char *ut_expand_envvars (const char *src0) { /* Expands ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms, but not $X */ const char *src = src0; size_t sz = strlen (src) + 1, pos = 0; char *dst = os_malloc (sz); while (*src) { if (*src == '$' && *(src + 1) == '{') { char *x, *xp; src++; x = expand_envbrace (&src, &ut_expand_envvars); if (x == NULL) { os_free(dst); return NULL; } xp = x; while (*xp) { expand_append (&dst, &sz, &pos, *xp++); } os_free (x); } else { expand_append (&dst, &sz, &pos, *src++); } } expand_append (&dst, &sz, &pos, 0); return dst; }
char *ut_expand_envvars_sh (const char *src0) { /* Expands $X, ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms; $ and \ can be escaped with \ */ const char *src = src0; size_t sz = strlen (src) + 1, pos = 0; char *dst = os_malloc (sz); while (*src) { if (*src == '\\') { src++; if (*src == 0) { OS_REPORT (OS_ERROR, "configuration parser", 0, "%s: incomplete escape at end of string\n", src0); os_free(dst); return NULL; } expand_append (&dst, &sz, &pos, *src++); } else if (*src == '$') { char *x, *xp; src++; if (*src == 0) { OS_REPORT (OS_ERROR, "configuration parser", 0, "%s: incomplete variable expansion at end of string\n", src0); os_free(dst); return NULL; } else if (*src == '{') { x = expand_envbrace (&src, &ut_expand_envvars_sh); } else if (isalnum (*src) || *src == '_') { x = expand_envsimple (&src, &ut_expand_envvars_sh); } else { x = expand_envchar (&src, &ut_expand_envvars_sh); } if (x == NULL) { os_free(dst); return NULL; } xp = x; while (*xp) { expand_append (&dst, &sz, &pos, *xp++); } os_free (x); } else { expand_append (&dst, &sz, &pos, *src++); } } expand_append (&dst, &sz, &pos, 0); return dst; }
static str_list_type brace_expand P1C(const_string *, text) { str_list_type result, partial, recurse; const_string p; result = str_list_init(); partial = str_list_init(); for (p = *text; *p && *p != '}'; ++p) { /* FIXME: Should be IS_ENV_SEP(*p) */ if (*p == ENV_SEP || *p == ',') { expand_append(&partial, *text, p); str_list_concat(&result, partial); str_list_free(&partial); *text = p+1; partial = str_list_init(); } else if (*p == '{') { expand_append(&partial, *text, p); ++p; recurse = brace_expand(&p); str_list_concat_elements(&partial, recurse); str_list_free(&recurse); /* Check for missing closing brace. */ if (*p != '}') { WARNING1 ("%s: Unmatched {", *text); } *text = p+1; } else if (*p == '$') { /* Skip ${VAR} */ if (*(p+1) == '{') for (p+=2; *p!='}';++p); } } expand_append(&partial, *text, p); str_list_concat(&result, partial); str_list_free(&partial); *text = p; return result; }