/* Try to interpret LINE (a null-terminated string) as a variable definition. * If LINE was recognized as a variable definition, a pointer to its `struct * variable' is returned. If LINE is not a variable definition, NULL is returned. */ public static variable assign_variable_definition(ref variable v, string line) { string beg = ""; variable_flavor flavor = new variable_flavor(); string name = ""; beg = Utils.next_token(line); line = parse_variable_definition(beg, ref flavor); if (line == null) { return(null); } int endindex = 0; if (flavor == variable_flavor.f_append) { endindex = beg.IndexOf("+="); } else { if (flavor == variable_flavor.f_recursive) { endindex = beg.IndexOf("="); } else { endindex = beg.IndexOf(":="); if (endindex < 0) { endindex = beg.IndexOf("?="); } } } name = beg.Substring(0, endindex).Trim(); line = line.Trim(); v.value = line; v.flavor = flavor; // Expand the name, so "$(foo)bar = baz" works. v.name = ExpandString(name); if (v.name.Length == 0) { MessageBox.Show("Empty variable name - (" + (new StackFrame()).GetFileName() + " - " + (new StackFrame()).GetFileLineNumber() + ")"); } return(v); }
// Given a variable, a value, and a flavor, define the variable. See the try_variable_definition() function for details on the parameters. public static variable do_variable_definition(string varname, string value, variable_origin origin, variable_flavor flavor, int target_var) { string p = ""; string alloc_value = ""; variable v; bool append = false; bool conditional = false; // Calculate the variable's new value in VALUE. switch (flavor) { default: case variable_flavor.f_bogus: //Should not be possible. MessageBox.Show("Abort!"); break; case variable_flavor.f_simple: /* A simple variable definition "var := value". Expand the value. We have to allocate memory since otherwise it'll clobber the * variable buffer, and we may still need that if we're looking at a target-specific variable. */ p = alloc_value = ExpandString(value); break; case variable_flavor.f_conditional: // A conditional variable definition "var ?= value". The value is set IFF the variable is not defined yet. v = lookup_variable(varname); if (v != null) { return(v.special? set_special_var(v) : v); } conditional = true; flavor = variable_flavor.f_recursive; p = value; break; case variable_flavor.f_recursive: // A recursive variable definition "var = value". The value is used verbatim. p = value; break; case variable_flavor.f_append: { // If we have += but we're in a target variable context, we want to append only with other variables in the context of this target. if (target_var == 1) { append = true; v = lookup_variable_in_set(varname, varname.Length, current_variable_set_list); // Don't append from the global set if a previous non-appending target-specific variable definition exists. if (v != null && !v.append) { append = false; } } else { v = lookup_variable(varname); } if (v == null) { // There was no old value. This becomes a normal recursive definition. p = value; flavor = variable_flavor.f_recursive; } else { // Paste the old and new values together in VALUE. string val = ""; string tp = ""; val = value; if (v.recursive) { // The previous definition of the variable was recursive. The new value is the unexpanded old and new values. flavor = variable_flavor.f_recursive; } else { /* The previous definition of the variable was simple. The new value comes from the old value, which was expanded * when it was set; and from the expanded new value. Allocate memory for the expansion as we may still need the rest of the * buffer if we're looking at a target-specific variable. */ val = tp = ExpandString(val); } p = alloc_value = v.value + " " + val; } break; } } /* If we are defining variables inside an $(eval ...), we might have a * different variable context pushed, not the global context (maybe we're inside a $(call ...) or something. Since this function is only ever * invoked in places where we want to define globally visible variables, make sure we define this variable in the global set. */ v = define_variable_in_set(varname, p, origin, (flavor == variable_flavor.f_recursive), (target_var == 1 ? current_variable_set_list : null)); v.append = append; v.conditional = conditional; return(v.special ? set_special_var(v) : v); }
/* Parse P (a null-terminated string) as a variable definition. If it is not a variable definition, return NULL. * If it is a variable definition, return a pointer to the char after the assignment token and set *FLAVOR to the type of variable assignment. */ public static string parse_variable_definition(string p, ref variable_flavor flavor) { bool wspace = false; int i; for (i = 0; i < p.Length; i++) { if (p[i] == '$') { char closeparen; char openparen = p[i + 1]; if (openparen == '(') { closeparen = ')'; } else if (openparen == '{') { closeparen = '}'; } else { // '$$' or '$X'. Either way, nothing special to do here. continue; } int count = 0; for (; i < p.Length; i++) { if (p[i] == openparen) { ++count; } else if (p[i] == closeparen) { if (--count < 0) { i++; break; } } } continue; } if (Utils.isblank(p[i])) { wspace = true; continue; } if (p[i] == '=') { flavor = variable_flavor.f_recursive; return(p.Substring(i + 1)); } // Match assignment variants (:=, +=, ?=) if ((i + 1) < p.Length && p[i + 1] == '=') { switch (p[i]) { case ':': flavor = variable_flavor.f_simple; break; case '+': flavor = variable_flavor.f_append; break; case '?': flavor = variable_flavor.f_conditional; break; default: // If we skipped whitespace, non-assignments means no var. if (wspace) { return(null); } // Might be assignment, or might be $= or #=. Check. continue; } return(p.Substring(i + 2)); } else if (p[i] == ':') { return(null); } // If we skipped whitespace, non-assignments means no var. if (wspace) { return(null); } } if (i >= p.Length) { return(null); } return(p.Substring(i)); }