char * wildcard_expansion (char *wc, char *o) { # define PATH_SIZE 1024 struct AnchorPath * apath; if ( (apath = AllocMem (sizeof (struct AnchorPath) + PATH_SIZE, MEMF_CLEAR)) ) { apath->ap_Strlen = PATH_SIZE; if (MatchFirst (wc, apath) == 0) { do { o = variable_buffer_output (o, apath->ap_Buf, strlen (apath->ap_Buf)); o = variable_buffer_output (o, " ",1); } while (MatchNext (apath) == 0); } MatchEnd (apath); FreeMem (apath, sizeof (struct AnchorPath) + PATH_SIZE); } return o; }
static char * variable_append (const char *name, unsigned int length, const struct variable_set_list *set) { const struct variable *v; char *buf = 0; /* If there's nothing left to check, return the empty buffer. */ if (!set) return initialize_variable_output (); /* Try to find the variable in this variable set. */ v = lookup_variable_in_set (name, length, set->set); /* If there isn't one, look to see if there's one in a set above us. */ if (!v) return variable_append (name, length, set->next); /* If this variable type is append, first get any upper values. If not, initialize the buffer. */ if (v->append) buf = variable_append (name, length, set->next); else buf = initialize_variable_output (); /* Append this value to the buffer, and return it. If we already have a value, first add a space. */ if (buf > variable_buffer) buf = variable_buffer_output (buf, " ", 1); #ifdef CONFIG_WITH_VALUE_LENGTH assert (v->value_length == strlen (v->value)); #endif /* Either expand it or copy it, depending. */ if (! v->recursive) #ifdef CONFIG_WITH_VALUE_LENGTH return variable_buffer_output (buf, v->value, v->value_length); #else return variable_buffer_output (buf, v->value, strlen (v->value)); #endif #ifdef CONFIG_WITH_VALUE_LENGTH variable_expand_string_2 (buf, v->value, v->value_length, &buf); return buf; #else buf = variable_expand_string (buf, v->value, strlen (v->value)); return (buf + strlen (buf)); #endif }
__inline #endif static char * reference_variable (char *o, const char *name, unsigned int length) { struct variable *v; char *value; v = lookup_variable (name, length); if (v == 0) warn_undefined (name, length); /* If there's no variable by that name or it has no value, stop now. */ if (v == 0 || (*v->value == '\0' && !v->append)) return o; value = (v->recursive ? recursively_expand (v) : v->value); o = variable_buffer_output (o, value, strlen (value)); if (v->recursive) free (value); return o; }
/* Static worker for reference_variable() that expands the recursive variable V. The main difference between this and recursively_expand[_for_file] is that this worker avoids the temporary buffer and outputs directly into the current variable buffer (O). */ static char * reference_recursive_variable (char *o, struct variable *v) { const struct floc *this_var; const struct floc **saved_varp; int set_reading = 0; /* Don't install a new location if this location is empty. This can happen for command-line variables, builtin variables, etc. */ saved_varp = expanding_var; if (v->fileinfo.filenm) { this_var = &v->fileinfo; expanding_var = &this_var; } /* If we have no other file-reading context, use the variable's context. */ if (!reading_file) { set_reading = 1; reading_file = &v->fileinfo; } if (v->expanding) { if (!v->exp_count) /* Expanding V causes infinite recursion. Lose. */ fatal (*expanding_var, _("Recursive variable `%s' references itself (eventually)"), v->name); --v->exp_count; } v->expanding = 1; if (!v->append) /* Expand directly into the variable buffer. */ variable_expand_string_2 (o, v->value, v->value_length, &o); else { /* XXX: Feel free to optimize appending target variables as well. */ char *value = allocated_variable_append (v); unsigned int value_len = strlen (value); o = variable_buffer_output (o, value, value_len); free (value); } v->expanding = 0; if (set_reading) reading_file = 0; expanding_var = saved_varp; return o; }
/* Expands the specified string, appending it to the specified variable value. */ void append_expanded_string_to_variable (struct variable *v, const char *value, unsigned int value_len, int append) { char *p = (char *) memchr (value, '$', value_len); if (!p) /* fast path */ append_string_to_variable (v,value, value_len, append); else if (value_len) { unsigned int off_dollar = p - (char *)value; /* Install a fresh variable buffer. */ char *saved_buffer; unsigned int saved_buffer_length; install_variable_buffer (&saved_buffer, &saved_buffer_length); p = variable_buffer; if (append || !v->value_length) { /* Copy the current value into it and append a space. */ if (v->value_length) { p = variable_buffer_output (p, v->value, v->value_length); p = variable_buffer_output (p, " ", 1); } /* Append the assignment value. */ p = variable_buffer_output (p, value, off_dollar); variable_expand_string_2 (p, value + off_dollar, value_len - off_dollar, &p); } else { /* Expand the assignemnt value. */ p = variable_buffer_output (p, value, off_dollar); variable_expand_string_2 (p, value + off_dollar, value_len - off_dollar, &p); /* Append a space followed by the old value. */ p = variable_buffer_output (p, " ", 1); p = variable_buffer_output (p, v->value, v->value_length + 1) - 1; } /* Replace the variable with the variable buffer. */ #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE if (v->rdonly_val) v->rdonly_val = 0; else #endif free (v->value); v->value = variable_buffer; v->value_length = p - v->value; v->value_alloc_len = variable_buffer_length; /* Restore the variable buffer, but without freeing the current. */ variable_buffer = NULL; restore_variable_buffer (saved_buffer, saved_buffer_length); } /* else: Drop empty strings. Use $(NO_SUCH_VARIABLE) if a space is wanted. */ }
static char * variable_append (const char *name, unsigned int length, const struct variable_set_list *set, int local) { const struct variable *v; char *buf = 0; /* If this set is local and the next is not a parent, then next is local. */ int nextlocal = local && set->next_is_parent == 0; /* If there's nothing left to check, return the empty buffer. */ if (!set) return initialize_variable_output (); /* Try to find the variable in this variable set. */ v = lookup_variable_in_set (name, length, set->set); /* If there isn't one, or this one is private, try the set above us. */ if (!v || (!local && v->private_var)) return variable_append (name, length, set->next, nextlocal); /* If this variable type is append, first get any upper values. If not, initialize the buffer. */ if (v->append) buf = variable_append (name, length, set->next, nextlocal); else buf = initialize_variable_output (); /* Append this value to the buffer, and return it. If we already have a value, first add a space. */ if (buf > variable_buffer) buf = variable_buffer_output (buf, " ", 1); /* Either expand it or copy it, depending. */ if (! v->recursive) return variable_buffer_output (buf, v->value, strlen (v->value)); buf = variable_expand_string (buf, v->value, strlen (v->value)); return (buf + strlen (buf)); }
__inline #endif static char * #endif reference_variable (char *o, const char *name, unsigned int length) { struct variable *v; #ifndef CONFIG_WITH_VALUE_LENGTH char *value; #endif v = lookup_variable (name, length); if (v == 0) warn_undefined (name, length); /* If there's no variable by that name or it has no value, stop now. */ if (v == 0 || (*v->value == '\0' && !v->append)) return o; #ifdef CONFIG_WITH_VALUE_LENGTH assert (v->value_length == strlen (v->value)); if (!v->recursive) o = variable_buffer_output (o, v->value, v->value_length); else o = reference_recursive_variable (o, v); #else /* !CONFIG_WITH_VALUE_LENGTH */ value = (v->recursive ? recursively_expand (v) : v->value); o = variable_buffer_output (o, value, strlen (value)); if (v->recursive) free (value); #endif /* !CONFIG_WITH_VALUE_LENGTH */ return o; }
char * variable_expand (const char *line) { #ifndef CONFIG_WITH_VALUE_LENGTH return variable_expand_string(NULL, line, (long)-1); #else /* CONFIG_WITH_VALUE_LENGTH */ char *s; /* this function is abused a lot like this: variable_expand(""). */ if (!*line) { s = variable_buffer_output (initialize_variable_output (), "\0", 2); return s - 2; } return variable_expand_string_2 (NULL, line, (long)-1, &s); #endif /* CONFIG_WITH_VALUE_LENGTH */ }
static char * reference_variable (char *o, const char *name, unsigned int length) { // fprintf(stderr, "reference variable for name=%s, length=%d, o=%s\n", name, length, o); struct variable *v; char *value; v = lookup_variable (name, length); if (v == 0) warn_undefined (name, length); /* If there's no variable by that name or it has no value, stop now. */ if (v == 0 || (*v->value == '\0' && !v->append)) { // Vizmake if (!v) { char buf[BSIZE]; if (length > BSIZE) length = BSIZE - 1; strncpy(buf, name, length); buf[length] = '\0'; vprint("VAR REF END---UNDEFINED---%s", buf); } else vprint_var(v, ""); return o; } value = (v->recursive ? recursively_expand (v) : v->value); // Wenbin vprint_var(v, value); o = variable_buffer_output (o, value, strlen (value)); // fprintf(stderr, "wenbin: %s: %s=%s => %s\n", name, v->name, v->value, o); if (v->recursive) free (value); return o; }
static char * allocated_variable_append (const struct variable *v) { char *val; /* Construct the appended variable value. */ char *obuf = variable_buffer; unsigned int olen = variable_buffer_length; variable_buffer = 0; val = variable_append (v->name, strlen (v->name), current_variable_set_list); variable_buffer_output (val, "", 1); val = variable_buffer; variable_buffer = obuf; variable_buffer_length = olen; return val; }
/* Scan STRING for variable references and expansion-function calls. Only LENGTH bytes of STRING are actually scanned. If LENGTH is -1, scan until a null byte is found. Write the results to LINE, which must point into `variable_buffer'. If LINE is NULL, start at the beginning of the buffer. Return a pointer to LINE, or to the beginning of the buffer if LINE is NULL. */ char * variable_expand_string (char *line, const char *string, long length) { struct variable *v; const char *p, *p1; char *abuf = NULL; char *o; unsigned int line_offset; if (!line) line = initialize_variable_output(); o = line; line_offset = line - variable_buffer; if (length == 0) { variable_buffer_output (o, "", 1); return (variable_buffer); } /* If we want a subset of the string, allocate a temporary buffer for it. Most of the functions we use here don't work with length limits. */ if (length > 0 && string[length] != '\0') { abuf = xmalloc(length+1); memcpy(abuf, string, length); abuf[length] = '\0'; string = abuf; } p = string; while (1) { /* Copy all following uninteresting chars all at once to the variable output buffer, and skip them. Uninteresting chars end at the next $ or the end of the input. */ p1 = strchr (p, '$'); o = variable_buffer_output (o, p, p1 != 0 ? (unsigned int)(p1 - p) : strlen (p) + 1); if (p1 == 0) break; p = p1 + 1; /* Dispatch on the char that follows the $. */ switch (*p) { case '$': /* $$ seen means output one $ to the variable output buffer. */ o = variable_buffer_output (o, p, 1); break; case '(': case '{': /* $(...) or ${...} is the general case of substitution. */ { char openparen = *p; char closeparen = (openparen == '(') ? ')' : '}'; const char *begp; const char *beg = p + 1; char *op; char *abeg = NULL; const char *end, *colon; op = o; begp = p; if (handle_function (&op, &begp)) { o = op; p = begp; break; } /* Is there a variable reference inside the parens or braces? If so, expand it before expanding the entire reference. */ end = strchr (beg, closeparen); if (end == 0) /* Unterminated variable reference. */ fatal (*expanding_var, _("unterminated variable reference")); p1 = lindex (beg, end, '$'); if (p1 != 0) { /* BEG now points past the opening paren or brace. Count parens or braces until it is matched. */ int count = 0; for (p = beg; *p != '\0'; ++p) { if (*p == openparen) ++count; else if (*p == closeparen && --count < 0) break; } /* If COUNT is >= 0, there were unmatched opening parens or braces, so we go to the simple case of a variable name such as `$($(a)'. */ if (count < 0) { abeg = expand_argument (beg, p); /* Expand the name. */ beg = abeg; end = strchr (beg, '\0'); } } else /* Advance P to the end of this reference. After we are finished expanding this one, P will be incremented to continue the scan. */ p = end; /* This is not a reference to a built-in function and any variable references inside are now expanded. Is the resultant text a substitution reference? */ colon = lindex (beg, end, ':'); if (colon) { /* This looks like a substitution reference: $(FOO:A=B). */ const char *subst_beg, *subst_end, *replace_beg, *replace_end; subst_beg = colon + 1; subst_end = lindex (subst_beg, end, '='); if (subst_end == 0) /* There is no = in sight. Punt on the substitution reference and treat this as a variable name containing a colon, in the code below. */ colon = 0; else { replace_beg = subst_end + 1; replace_end = end; /* Extract the variable name before the colon and look up that variable. */ v = lookup_variable (beg, colon - beg); if (v == 0) warn_undefined (beg, colon - beg); /* If the variable is not empty, perform the substitution. */ if (v != 0 && *v->value != '\0') { char *pattern, *replace, *ppercent, *rpercent; char *value = (v->recursive ? recursively_expand (v) : v->value); /* Copy the pattern and the replacement. Add in an extra % at the beginning to use in case there isn't one in the pattern. */ pattern = alloca (subst_end - subst_beg + 2); *(pattern++) = '%'; memcpy (pattern, subst_beg, subst_end - subst_beg); pattern[subst_end - subst_beg] = '\0'; replace = alloca (replace_end - replace_beg + 2); *(replace++) = '%'; memcpy (replace, replace_beg, replace_end - replace_beg); replace[replace_end - replace_beg] = '\0'; /* Look for %. Set the percent pointers properly based on whether we find one or not. */ ppercent = find_percent (pattern); if (ppercent) { ++ppercent; rpercent = find_percent (replace); if (rpercent) ++rpercent; } else { ppercent = pattern; rpercent = replace; --pattern; --replace; } o = patsubst_expand_pat (o, value, pattern, replace, ppercent, rpercent); if (v->recursive) free (value); } } } if (colon == 0) /* This is an ordinary variable reference. Look up the value of the variable. */ o = reference_variable (o, beg, end - beg); if (abeg) free (abeg); } break; case '\0': break; default: if (isblank ((unsigned char)p[-1])) break; /* A $ followed by a random char is a variable reference: $a is equivalent to $(a). */ o = reference_variable (o, p, 1); break; } if (*p == '\0') break; ++p; } if (abuf) free (abuf); variable_buffer_output (o, "", 1); return (variable_buffer + line_offset); }
/*============================================================================================================== * * NAME * wake_builtin_date - Formats a date. * * PROTOTYPE * $(<date> [ format [, time] ] ) * $(<gmdate> [ format [, time] ] ) * * DESCRIPTION * Formats a time value. * * PARAMETERS * format - * A format string, that accepts the same specifiers than the PHP date() function. * If not specified, the default format is 'Y-m-d H:i:s'. * * time - * A time value. If not specified, the current Unix time is used. * *==============================================================================================================*/ static char * __wake_builtin_date ( char * output, char * format, time_t time_value, int is_localtime ) { struct tm * tm = ( is_localtime ) ? localtime ( & time_value ) : gmtime ( & time_value ) ; char * p = format ; int ap_hour ; char buffer [128] ; char * buffer_p ; int iso_year, iso_week ; int iso_values_set = 0, tz_set = 0 ; tm -> tm_year += 1900 ; ap_hour = ( tm -> tm_hour % 12 ) ? tm -> tm_hour % 12 : 12 ; while ( * p ) { buffer_p = NULL ; * buffer = 0 ; switch ( * p ) { // 'a' : lowercase "am" or "pm" case 'a' : buffer_p = ( tm -> tm_hour >= 12 ) ? "pm" : "am" ; break ; // 'A' : uppercase "AM" or "PM" case 'A' : buffer_p = ( tm -> tm_hour >= 12 ) ? "PM" : "AM" ; break ; // 'B' : internet Swatch hour case 'B' : { int result = ( ( ( time_value - ( time_value - ( ( time_value % 86400 ) + 3600 ) ) ) * 10 ) / 864 ) ; while ( result < 0 ) result += 1000 ; result %= 1000 ; sprintf ( buffer, "%03d", result ) ; break ; } // 'c' : Full date, in ISO8601 format case 'c' : sprintf ( buffer, "%04d-%02d-%02dT%02d:%02d:%02d%s", tm -> tm_year, tm -> tm_mon + 1, tm -> tm_mday, tm -> tm_hour, tm -> tm_min, tm -> tm_sec, gmtoffset ( is_localtime, tm -> tm_gmtoff, 1 ) ) ; break ; // 'd' : day of month, as a two-digits number case 'd' : sprintf ( buffer, "%02d", tm -> tm_mday ) ; break ; // 'D' : short day name case 'D' : buffer_p = short_day_names [ tm -> tm_wday ] ; break ; // 'e' : Timezone name case 'e' : if ( ! tz_set ) tzset ( ) ; buffer_p = tzname [0] ; break ; // 'F' : Long month name case 'F' : buffer_p = long_month_names [ tm -> tm_mon ] ; break ; // 'g' : Hour without leading zero (1..12) case 'g' : sprintf ( buffer, "%d", ap_hour ) ; break ; // 'G' : Hour without leading zero (0..23) case 'G' : sprintf ( buffer, "%d", tm -> tm_hour ) ; break ; // 'h' : Hour with leading zero (01..12) case 'h' : sprintf ( buffer, "%02d", ap_hour ) ; break ; // 'H' : Hour with leading zero (00..23) case 'H' : sprintf ( buffer, "%02d", tm -> tm_hour ) ; break ; // 'i' : Minute, with leading zero (00..59) case 'i' : sprintf ( buffer, "%02d", tm -> tm_min ) ; break ; // 'I' : 1 if daylight savings time is active, 0 otherwise case 'I' : sprintf ( buffer, "%d", tm -> tm_isdst ) ; break ; // 'j' : day of month, without the leading zero case 'j' : sprintf ( buffer, "%d", tm -> tm_mday ) ; break ; // 'l' : Long day name case 'l' : buffer_p = long_day_names [ tm -> tm_wday ] ; break ; // 'L' : 1 is the year is leap, 0 otherwise case 'L' : sprintf ( buffer, "%d", IS_LEAP ( tm -> tm_year ) ) ; break ; // 'M' : short month name case 'M' : buffer_p = short_month_names [ tm -> tm_mon ] ; break ; // 'm' : month of year, as a two-digits number case 'm' : sprintf ( buffer, "%02d", tm -> tm_mon + 1 ) ; break ; // 'n' : month of year, without the leading zero case 'n' : sprintf ( buffer, "%d", tm -> tm_mon + 1 ) ; break ; // 'N' : day of week, from 1 (monday) to 7 (sunday) case 'N' : sprintf ( buffer, "%d", ( tm -> tm_wday ) ? tm -> tm_wday : 7 ) ; break ; // 'o' : ISO8601 year case 'o' : if ( ! iso_values_set ) { isoweek_from_date ( tm -> tm_year, tm -> tm_mon, tm -> tm_mday, & iso_week, & iso_year ) ; iso_values_set = 1 ; } sprintf ( buffer, "%d", iso_year ) ; break ; // 'O' : GMT offset in ISO8601 format (+0200) case 'O' : buffer_p = gmtoffset ( is_localtime, tm -> tm_gmtoff, 0 ) ; break ; // 'P' : GMT offset in RFC822 format (+02:00) case 'P' : buffer_p = gmtoffset ( is_localtime, tm -> tm_gmtoff, 1 ) ; break ; // 'r' : RFC822 date case 'r' : sprintf ( buffer, "%3s %02d %3s %04d %02d:%02d:%02d %s", short_day_names [ tm -> tm_wday ], tm -> tm_mday, short_month_names [ tm -> tm_mon ], tm -> tm_year, tm -> tm_hour, tm -> tm_min, tm -> tm_sec, gmtoffset ( is_localtime, tm -> tm_gmtoff, 0 ) ) ; break ; // 's' : Seconds, with leading zero (00..59) case 's' : sprintf ( buffer, "%02d", tm -> tm_sec ) ; break ; // 'S' : 2-letters english suffix for a day of month case 'S' : buffer_p = english_suffix ( tm -> tm_mday ) ; break ; // 't' : month length case 't' : sprintf ( buffer, "%d", MONTH_LENGTH ( tm -> tm_year, tm -> tm_mon ) ) ; break ; // 'T' : Timezone abbreviation case 'T' : if ( ! tz_set ) tzset ( ) ; buffer_p = tzname [1] ; break ; // 'u' : microsecond time. Always return '000000' since we accept an integer value as time case 'u' : buffer_p = "000000" ; break ; // 'U' : Unix time case 'U' : sprintf ( buffer, "%d", ( int ) time_value ) ; break ; // 'w' : day of week, from 0 (sunday) to 6 (saturday) case 'w' : sprintf ( buffer, "%d", tm -> tm_wday ) ; break ; // 'W' : ISO8601 week number (were weeks start on monday) case 'W' : if ( ! iso_values_set ) { isoweek_from_date ( tm -> tm_year, tm -> tm_mon, tm -> tm_mday, & iso_week, & iso_year ) ; iso_values_set = 1 ; } sprintf ( buffer, "%d", iso_week ) ; break ; // 'y' : 2-digits year case 'y' : sprintf ( buffer, "%02d", ( tm -> tm_year % 100 ) ) ; break ; // 'Y' : 4-digits year case 'Y' : sprintf ( buffer, "%04d", tm -> tm_year ) ; break ; // 'z' : day of year, from 0 to 365 case 'z' : sprintf ( buffer, "%d", tm -> tm_yday ) ; break ; // 'Z' : GMT offset in seconds case 'Z' : sprintf ( buffer, "%d", ( int ) tm -> tm_gmtoff ) ; break ; // Escape character : copy the next one without interpretation unless this is the last one case '\\' : if ( * ( p + 1 ) ) p ++ ; /* Intentionally fall through the default case */ // Other characters : copy as is default : buffer [0] = * p ; buffer [1] = 0 ; break ; } if ( buffer_p == NULL ) buffer_p = buffer ; output = variable_buffer_output ( output, buffer_p, strlen ( buffer_p ) ) ; p ++ ; } return ( output ) ; }
static const char * library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr) { static char *dirs[] = { #ifndef _AMIGA "/lib", "/usr/lib", #endif #if defined(WINDOWS32) && !defined(LIBDIR) /* * This is completely up to the user at product install time. Just define * a placeholder. */ #define LIBDIR "." #endif LIBDIR, /* Defined by configuration. */ 0 }; const char *file = 0; char *libpatterns; FILE_TIMESTAMP mtime; /* Loop variables for the libpatterns value. */ char *p; const char *p2; unsigned int len; unsigned int liblen; /* Information about the earliest (in the vpath sequence) match. */ unsigned int best_vpath = 0, best_path = 0; char **dp; libpatterns = xstrdup (variable_expand ("$(.LIBPATTERNS)")); /* Skip the '-l'. */ lib += 2; liblen = strlen (lib); /* Loop through all the patterns in .LIBPATTERNS, and search on each one. To implement the linker-compatible behavior we have to search through all entries in .LIBPATTERNS and choose the "earliest" one. */ p2 = libpatterns; while ((p = find_next_token (&p2, &len)) != 0) { static char *buf = NULL; static unsigned int buflen = 0; static int libdir_maxlen = -1; static unsigned int std_dirs = 0; char *libbuf = variable_expand (""); /* Expand the pattern using LIB as a replacement. */ { char c = p[len]; char *p3, *p4; p[len] = '\0'; p3 = find_percent (p); if (!p3) { /* Give a warning if there is no pattern. */ error (NILF, _(".LIBPATTERNS element '%s' is not a pattern"), p); p[len] = c; continue; } p4 = variable_buffer_output (libbuf, p, p3-p); p4 = variable_buffer_output (p4, lib, liblen); p4 = variable_buffer_output (p4, p3+1, len - (p3-p)); p[len] = c; } /* Look first for 'libNAME.a' in the current directory. */ mtime = name_mtime (libbuf); if (mtime != NONEXISTENT_MTIME) { if (mtime_ptr != 0) *mtime_ptr = mtime; file = strcache_add (libbuf); /* This by definition will have the best index, so stop now. */ break; } /* Now try VPATH search on that. */ { unsigned int vpath_index, path_index; const char* f = vpath_search (libbuf, mtime_ptr ? &mtime : NULL, &vpath_index, &path_index); if (f) { /* If we have a better match, record it. */ if (file == 0 || vpath_index < best_vpath || (vpath_index == best_vpath && path_index < best_path)) { file = f; best_vpath = vpath_index; best_path = path_index; if (mtime_ptr != 0) *mtime_ptr = mtime; } } } /* Now try the standard set of directories. */ if (!buflen) { for (dp = dirs; *dp != 0; ++dp) { int l = strlen (*dp); if (l > libdir_maxlen) libdir_maxlen = l; std_dirs++; } buflen = strlen (libbuf); buf = xmalloc(libdir_maxlen + buflen + 2); } else if (buflen < strlen (libbuf)) { buflen = strlen (libbuf); buf = xrealloc (buf, libdir_maxlen + buflen + 2); } { /* Use the last std_dirs index for standard directories. This was it will always be greater than the VPATH index. */ unsigned int vpath_index = ~((unsigned int)0) - std_dirs; for (dp = dirs; *dp != 0; ++dp) { sprintf (buf, "%s/%s", *dp, libbuf); mtime = name_mtime (buf); if (mtime != NONEXISTENT_MTIME) { if (file == 0 || vpath_index < best_vpath) { file = strcache_add (buf); best_vpath = vpath_index; if (mtime_ptr != 0) *mtime_ptr = mtime; } } vpath_index++; } } } free (libpatterns); return file; }
/* Scan STRING for variable references and expansion-function calls. Only LENGTH bytes of STRING are actually scanned. If LENGTH is -1, scan until a null byte is found. Write the results to LINE, which must point into `variable_buffer'. If LINE is NULL, start at the beginning of the buffer. Return a pointer to LINE, or to the beginning of the buffer if LINE is NULL. Set EOLP to point to the string terminator. */ char * variable_expand_string_2 (char *line, const char *string, long length, char **eolp) { struct variable *v; const char *p, *p1, *eos; char *o; unsigned int line_offset; if (!line) line = initialize_variable_output(); o = line; line_offset = line - variable_buffer; if (length < 0) length = strlen (string); else MY_ASSERT_MSG (string + length == (p1 = memchr (string, '\0', length)) || !p1, ("len=%ld p1=%p %s\n", length, p1, line)); /* Simple 1: Emptry string. */ if (length == 0) { o = variable_buffer_output (o, "\0", 2); *eolp = o - 2; return (variable_buffer + line_offset); } /* Simple 2: Nothing to expand. ~50% if the kBuild calls. */ p1 = (const char *)memchr (string, '$', length); if (p1 == 0) { o = variable_buffer_output (o, string, length); o = variable_buffer_output (o, "\0", 2); *eolp = o - 2; assert (strchr (variable_buffer + line_offset, '\0') == *eolp); return (variable_buffer + line_offset); } p = string; eos = p + length; while (1) { /* Copy all following uninteresting chars all at once to the variable output buffer, and skip them. Uninteresting chars end at the next $ or the end of the input. */ o = variable_buffer_output (o, p, p1 != 0 ? (p1 - p) : (eos - p)); if (p1 == 0) break; p = p1 + 1; /* Dispatch on the char that follows the $. */ switch (*p) { case '$': /* $$ seen means output one $ to the variable output buffer. */ o = variable_buffer_output (o, p, 1); break; case '(': case '{': /* $(...) or ${...} is the general case of substitution. */ { char openparen = *p; char closeparen = (openparen == '(') ? ')' : '}'; const char *begp; const char *beg = p + 1; char *op; char *abeg = NULL; unsigned int alen = 0; const char *end, *colon; op = o; begp = p; end = may_be_function_name (p + 1, eos); if ( end && handle_function (&op, &begp, end, eos)) { o = op; p = begp; MY_ASSERT_MSG (!(p1 = memchr (variable_buffer + line_offset, '\0', o - (variable_buffer + line_offset))), ("line=%p o/exp_end=%p act_end=%p\n", variable_buffer + line_offset, o, p1)); break; } /* Is there a variable reference inside the parens or braces? If so, expand it before expanding the entire reference. */ end = memchr (beg, closeparen, eos - beg); if (end == 0) /* Unterminated variable reference. */ fatal (*expanding_var, _("unterminated variable reference")); p1 = lindex (beg, end, '$'); if (p1 != 0) { /* BEG now points past the opening paren or brace. Count parens or braces until it is matched. */ int count = 0; for (p = beg; p < eos; ++p) { if (*p == openparen) ++count; else if (*p == closeparen && --count < 0) break; } /* If COUNT is >= 0, there were unmatched opening parens or braces, so we go to the simple case of a variable name such as `$($(a)'. */ if (count < 0) { unsigned int len; char saved; /* Expand the name. */ saved = *p; *(char *)p = '\0'; /* XXX: proove that this is safe! XXX2: shouldn't be necessary any longer! */ abeg = allocated_variable_expand_3 (beg, p - beg, &len, &alen); beg = abeg; end = beg + len; *(char *)p = saved; } } else /* Advance P to the end of this reference. After we are finished expanding this one, P will be incremented to continue the scan. */ p = end; /* This is not a reference to a built-in function and any variable references inside are now expanded. Is the resultant text a substitution reference? */ colon = lindex (beg, end, ':'); if (colon) { /* This looks like a substitution reference: $(FOO:A=B). */ const char *subst_beg, *subst_end, *replace_beg, *replace_end; subst_beg = colon + 1; subst_end = lindex (subst_beg, end, '='); if (subst_end == 0) /* There is no = in sight. Punt on the substitution reference and treat this as a variable name containing a colon, in the code below. */ colon = 0; else { replace_beg = subst_end + 1; replace_end = end; /* Extract the variable name before the colon and look up that variable. */ v = lookup_variable (beg, colon - beg); if (v == 0) warn_undefined (beg, colon - beg); /* If the variable is not empty, perform the substitution. */ if (v != 0 && *v->value != '\0') { char *pattern, *replace, *ppercent, *rpercent; char *value = (v->recursive ? recursively_expand (v) : v->value); /* Copy the pattern and the replacement. Add in an extra % at the beginning to use in case there isn't one in the pattern. */ pattern = alloca (subst_end - subst_beg + 2); *(pattern++) = '%'; memcpy (pattern, subst_beg, subst_end - subst_beg); pattern[subst_end - subst_beg] = '\0'; replace = alloca (replace_end - replace_beg + 2); *(replace++) = '%'; memcpy (replace, replace_beg, replace_end - replace_beg); replace[replace_end - replace_beg] = '\0'; /* Look for %. Set the percent pointers properly based on whether we find one or not. */ ppercent = find_percent (pattern); if (ppercent) { ++ppercent; rpercent = find_percent (replace); if (rpercent) ++rpercent; } else { ppercent = pattern; rpercent = replace; --pattern; --replace; } o = patsubst_expand_pat (o, value, pattern, replace, ppercent, rpercent); if (v->recursive) free (value); } } } if (colon == 0) /* This is an ordinary variable reference. Look up the value of the variable. */ o = reference_variable (o, beg, end - beg); if (abeg) recycle_variable_buffer (abeg, alen); } break; case '\0': assert (p == eos); break; default: if (isblank ((unsigned char)p[-1])) /* XXX: This looks incorrect, previous is '$' */ break; /* A $ followed by a random char is a variable reference: $a is equivalent to $(a). */ o = reference_variable (o, p, 1); break; } if (++p >= eos) break; p1 = memchr (p, '$', eos - p); } o = variable_buffer_output (o, "\0", 2); /* KMK: compensate for the strlen + 1 that was removed above. */ *eolp = o - 2; MY_ASSERT_MSG (strchr (variable_buffer + line_offset, '\0') == *eolp, ("expected=%d actual=%d\nlength=%ld string=%.*s\n", (int)(*eolp - variable_buffer + line_offset), (int)strlen(variable_buffer + line_offset), length, (int)length, string)); return (variable_buffer + line_offset); }