/* * Evaluate a clause with arguments. argc/argv are arguments from the upper * function call. * * Returned string must be freed when done
*/ staticchar *eval_clause(constchar *str, size_t len, int argc, char *argv[])
{ char *tmp, *name, *res, *endptr, *prev, *p; int new_argc = 0; char *new_argv[FUNCTION_MAX_ARGS]; int nest = 0; int i; unsignedlong n;
tmp = xstrndup(str, len);
/* * If variable name is '1', '2', etc. It is generally an argument * from a user-function call (i.e. local-scope variable). If not * available, then look-up global-scope variables.
*/
n = strtoul(tmp, &endptr, 10); if (!*endptr && n > 0 && n <= argc) {
res = xstrdup(argv[n - 1]); goto free_tmp;
}
prev = p = tmp;
/* * Split into tokens * The function name and arguments are separated by a comma. * For example, if the function call is like this: * $(foo,$(x),$(y)) * * The input string for this helper should be: * foo,$(x),$(y) * * and split into: * new_argv[0] = 'foo' * new_argv[1] = '$(x)' * new_argv[2] = '$(y)'
*/ while (*p) { if (nest == 0 && *p == ',') {
*p = 0; if (new_argc >= FUNCTION_MAX_ARGS)
pperror("too many function arguments");
new_argv[new_argc++] = prev;
prev = p + 1;
} elseif (*p == '(') {
nest++;
} elseif (*p == ')') {
nest--;
}
p++;
}
if (new_argc >= FUNCTION_MAX_ARGS)
pperror("too many function arguments");
new_argv[new_argc++] = prev;
/* * Shift arguments * new_argv[0] represents a function name or a variable name. Put it * into 'name', then shift the rest of the arguments. This simplifies * 'const' handling.
*/
name = expand_string_with_args(new_argv[0], argc, argv);
new_argc--; for (i = 0; i < new_argc; i++)
new_argv[i] = expand_string_with_args(new_argv[i + 1],
argc, argv);
/* Search for variables */
res = variable_expand(name, new_argc, new_argv); if (res) goto free;
/* Look for built-in functions */
res = function_expand(name, new_argc, new_argv); if (res) goto free;
/* Last, try environment variable */ if (new_argc == 0) {
res = env_expand(name); if (res) goto free;
}
res = xstrdup("");
free: for (i = 0; i < new_argc; i++)
free(new_argv[i]);
free(name);
free_tmp:
free(tmp);
return res;
}
/* * Expand a string that follows '$' * * For example, if the input string is * ($(FOO)$($(BAR)))$(BAZ) * this helper evaluates * $($(FOO)$($(BAR))) * and returns a new string containing the expansion (note that the string is * recursively expanded), also advancing 'str' to point to the next character * after the corresponding closing parenthesis, in this case, *str will be * $(BAR)
*/ staticchar *expand_dollar_with_args(constchar **str, int argc, char *argv[])
{ constchar *p = *str; constchar *q; int nest = 0;
/* * In Kconfig, variable/function references always start with "$(". * Neither single-letter variables as in $A nor curly braces as in ${CC} * are supported. '$' not followed by '(' loses its special meaning.
*/ if (*p != '(') {
*str = p; return xstrdup("$");
}
p++;
q = p; while (*q) { if (*q == '(') {
nest++;
} elseif (*q == ')') { if (nest-- == 0) break;
}
q++;
}
if (!*q)
pperror("unterminated reference to '%s': missing ')'", p);
/* Advance 'str' to after the expanded initial portion of the string */
*str = q + 1;
while (1) { if (*p == '$') {
in_len = p - in;
p++;
expansion = expand_dollar_with_args(&p, argc, argv);
out_len += in_len + strlen(expansion);
out = xrealloc(out, out_len);
strncat(out, in, in_len);
strcat(out, expansion);
free(expansion);
in = p; continue;
}
if (is_end(*p)) break;
p++;
}
in_len = p - in;
out_len += in_len;
out = xrealloc(out, out_len);
strncat(out, in, in_len);
/* Advance 'str' to the end character */
*str = p;
return out;
}
staticbool is_end_of_str(char c)
{ return !c;
}
/* * Expand variables and functions in the given string. Undefined variables * expand to an empty string. * The returned string must be freed when done.
*/ staticchar *expand_string_with_args(constchar *in, int argc, char *argv[])
{ return __expand_string(&in, is_end_of_str, argc, argv);
}
staticbool is_end_of_token(char c)
{ return !(isalnum(c) || c == '_' || c == '-');
}
/* * Expand variables in a token. The parsing stops when a token separater * (in most cases, it is a whitespace) is encountered. 'str' is updated to * point to the next character. * * The returned string must be freed when done.
*/ char *expand_one_token(constchar **str)
{ return __expand_string(str, is_end_of_token, 0, NULL);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.