]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Add subst_env_in_string function
authorJoel Rosdahl <joel@rosdahl.net>
Sun, 3 Apr 2011 19:51:10 +0000 (21:51 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Mon, 30 May 2011 19:35:53 +0000 (21:35 +0200)
ccache.h
test/test_util.c
util.c

index 64baf7348a8e94678d1f630ed2b057add3843b29..59c05f7bbfd697ad77781eec3553389b8b8265d0 100644 (file)
--- a/ccache.h
+++ b/ccache.h
@@ -152,6 +152,7 @@ char *x_readlink(const char *path);
 #endif
 bool read_file(const char *path, size_t size_hint, char **data, size_t *size);
 char *read_text_file(const char *path, size_t size_hint);
+char *subst_env_in_string(const char *str, char **errmsg);
 
 /* ------------------------------------------------------------------------- */
 /* stats.c */
index a92d55c2c2b77908b1404b7bcc3ce3101a79e325..4357205583af958d8c2c1343a04abf53a13ebb57 100644 (file)
@@ -56,4 +56,42 @@ TEST(format_hash_as_string)
                           format_hash_as_string(hash, 12345));
 }
 
+TEST(subst_env_in_string)
+{
+       char *errmsg;
+       const char *shell = getenv("SHELL");
+
+       errmsg = "";
+       CHECK_STR_EQ_FREE2(shell,
+                          subst_env_in_string("$SHELL", &errmsg));
+       CHECK(!errmsg);
+
+       errmsg = "";
+       CHECK_STR_EQ_FREE2("$",
+                          subst_env_in_string("$", &errmsg));
+       CHECK(!errmsg);
+
+       errmsg = "";
+       CHECK_STR_EQ_FREE12(format("%s %s:%s", shell, shell, shell),
+                           subst_env_in_string("$SHELL $SHELL:$SHELL", &errmsg));
+       CHECK(!errmsg);
+
+       errmsg = "";
+       CHECK_STR_EQ_FREE12(format("x%s", shell),
+                           subst_env_in_string("x$SHELL", &errmsg));
+       CHECK(!errmsg);
+
+       errmsg = "";
+       CHECK_STR_EQ_FREE12(format("%sx", shell),
+                           subst_env_in_string("${SHELL}x", &errmsg));
+       CHECK(!errmsg);
+
+       CHECK(!subst_env_in_string("$surelydoesntexist", &errmsg));
+       CHECK_STR_EQ_FREE2("environment variable \"surelydoesntexist\" not set",
+                          errmsg);
+
+       CHECK(!subst_env_in_string("${SHELL", &errmsg));
+       CHECK_STR_EQ_FREE2("syntax error: missing '}' after \"SHELL\"", errmsg);
+}
+
 TEST_SUITE_END
diff --git a/util.c b/util.c
index d64cd23205dd916d656e49876c117f8b80986fb0..1b7c950ce95ed6cead9bac8b5a1ed8412fd30c58 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1270,3 +1270,83 @@ read_text_file(const char *path, size_t size_hint)
                return NULL;
        }
 }
+
+static bool
+expand_variable(const char **str, char **result, char **errmsg)
+{
+       bool curly;
+       const char *p, *q;
+       char *name;
+       const char *value;
+
+       assert(**str == '$');
+       p = *str + 1;
+       if (*p == '{') {
+               curly = true;
+               ++p;
+       } else {
+               curly = false;
+       }
+       q = p;
+       while (isalnum(*q) || *q == '_') {
+               ++q;
+       }
+       if (curly) {
+               if (*q != '}') {
+                       *errmsg = format("syntax error: missing '}' after \"%s\"", p);
+                       return NULL;
+               }
+       }
+
+       if (q == p) {
+               /* Special case: don't consider a single $ the start of a variable. */
+               x_asprintf2(result, "%s$", *result);
+               return true;
+       }
+
+       name = x_strndup(p, q - p);
+       value = getenv(name);
+       if (!value) {
+               *errmsg = format("environment variable \"%s\" not set", name);
+               return false;
+       }
+       x_asprintf2(result, "%s%s", *result, value);
+       if (!curly) {
+               --q;
+       }
+       *str = q;
+       return true;
+}
+
+/*
+ * Substitute all instances of $VAR or ${VAR}, where VAR is an environment
+ * variable, in a string. Caller frees. If one of the environment variables
+ * doesn't exist, NULL will be returned and *errmsg will be an appropriate
+ * error message (caller frees).
+ */
+char *
+subst_env_in_string(const char *str, char **errmsg)
+{
+       const char *p; /* Interval start. */
+       const char *q; /* Interval end. */
+       char *result;
+
+       assert(errmsg);
+       *errmsg = NULL;
+
+       result = x_strdup("");
+       p = str;
+       q = str;
+       for (q = str; *q; ++q) {
+               if (*q == '$') {
+                       x_asprintf2(&result, "%s%.*s", result, (int)(q - p), p);
+                       if (!expand_variable(&q, &result, errmsg)) {
+                               free(result);
+                               return NULL;
+                       }
+                       p = q + 1;
+               }
+       }
+       x_asprintf2(&result, "%s%.*s", result, (int)(q - p), p);
+       return result;
+}