SHOW:
|
|
- or go back to the newest paste.
| 1 | ### Eclipse Workspace Patch 1.0 | |
| 2 | #P make-patched | |
| 3 | Index: expand.c | |
| 4 | =================================================================== | |
| 5 | RCS file: /sources/make/make/expand.c,v | |
| 6 | retrieving revision 1.62 | |
| 7 | diff -u -r1.62 expand.c | |
| 8 | --- expand.c 5 Mar 2012 14:10:43 -0000 1.62 | |
| 9 | - | +++ expand.c 9 Apr 2012 09:50:04 -0000 |
| 9 | + | +++ expand.c 9 Apr 2012 13:34:41 -0000 |
| 10 | @@ -16,8 +16,6 @@ | |
| 11 | ||
| 12 | #include "make.h" | |
| 13 | ||
| 14 | -#include <assert.h> | |
| 15 | - | |
| 16 | #include "filedef.h" | |
| 17 | #include "job.h" | |
| 18 | #include "commands.h" | |
| 19 | @@ -30,125 +28,121 @@ | |
| 20 | ||
| 21 | /* The next two describe the variable output buffer. | |
| 22 | This buffer is used to hold the variable-expansion of a line of the | |
| 23 | - makefile. It is made bigger with realloc whenever it is too small. | |
| 24 | - variable_buffer_length is the size currently allocated. | |
| 25 | - variable_buffer is the address of the buffer. | |
| 26 | + makefile. It is made bigger with realloc whenever it is too small. */ | |
| 27 | + | |
| 28 | +static struct vbuffer *expansion_vbuf; | |
| 29 | ||
| 30 | - For efficiency, it's guaranteed that the buffer will always have | |
| 31 | +/* For efficiency, it's guaranteed that the buffer will always have | |
| 32 | VARIABLE_BUFFER_ZONE extra bytes allocated. This allows you to add a few | |
| 33 | extra chars without having to call a function. Note you should never use | |
| 34 | these bytes unless you're _sure_ you have room (you know when the buffer | |
| 35 | length was last checked. */ | |
| 36 | +#define VARIABLE_BUFFER_ZONE (2 * sizeof (char *)) | |
| 37 | ||
| 38 | -#define VARIABLE_BUFFER_ZONE 5 | |
| 39 | +struct vbuffer * | |
| 40 | +vbuffer_init (struct vbuffer *vbuf) | |
| 41 | +{
| |
| 42 | + vbuf->size = 100; | |
| 43 | + vbuf->ptr = vbuf->buffer = xmalloc (vbuf->size); | |
| 44 | ||
| 45 | -static unsigned int variable_buffer_length; | |
| 46 | -char *variable_buffer; | |
| 47 | + *vbuf->ptr = '\0'; | |
| 48 | ||
| 49 | -/* Subroutine of variable_expand and friends: | |
| 50 | - The text to add is LENGTH chars starting at STRING to the variable_buffer. | |
| 51 | - The text is added to the buffer at PTR, and the updated pointer into | |
| 52 | - the buffer is returned as the value. Thus, the value returned by | |
| 53 | - each call to variable_buffer_output should be the first argument to | |
| 54 | - the following call. */ | |
| 55 | + return vbuf; | |
| 56 | +} | |
| 57 | ||
| 58 | -char * | |
| 59 | -variable_buffer_output (char *ptr, const char *string, unsigned int length) | |
| 60 | +struct vbuffer * | |
| 61 | +vbuffer_reset (struct vbuffer *vbuf) | |
| 62 | {
| |
| 63 | - register unsigned int newlen = length + (ptr - variable_buffer); | |
| 64 | + vbuf->ptr = vbuf->buffer; | |
| 65 | ||
| 66 | - if ((newlen + VARIABLE_BUFFER_ZONE) > variable_buffer_length) | |
| 67 | - {
| |
| 68 | - unsigned int offset = ptr - variable_buffer; | |
| 69 | - variable_buffer_length = (newlen + 100 > 2 * variable_buffer_length | |
| 70 | - ? newlen + 100 | |
| 71 | - : 2 * variable_buffer_length); | |
| 72 | - variable_buffer = xrealloc (variable_buffer, variable_buffer_length); | |
| 73 | - ptr = variable_buffer + offset; | |
| 74 | - } | |
| 75 | + *vbuf->ptr = '\0'; | |
| 76 | ||
| 77 | - memcpy (ptr, string, length); | |
| 78 | - return ptr + length; | |
| 79 | + return vbuf; | |
| 80 | } | |
| 81 | ||
| 82 | -/* Return a pointer to the beginning of the variable buffer. */ | |
| 83 | +#ifdef __GNUC__ | |
| 84 | +__inline | |
| 85 | +#endif | |
| 86 | +static void | |
| 87 | +vbuffer_grow (struct vbuffer *vbuf, size_t newlen) | |
| 88 | +{
| |
| 89 | + size_t oldlen = vbuf->size; | |
| 90 | + size_t offset = vbuf->ptr - vbuf->buffer; | |
| 91 | + | |
| 92 | + newlen = newlen + 100 > 2 * oldlen | |
| 93 | + ? newlen + 100 : 2 * oldlen; | |
| 94 | + | |
| 95 | + vbuf->buffer = xrealloc (vbuf->buffer, newlen); | |
| 96 | + vbuf->ptr = vbuf->buffer + offset; | |
| 97 | + vbuf->size = newlen; | |
| 98 | +} | |
| 99 | ||
| 100 | -static char * | |
| 101 | -initialize_variable_output (void) | |
| 102 | +#ifdef __GNUC__ | |
| 103 | +__inline | |
| 104 | +#endif | |
| 105 | +size_t | |
| 106 | +vbuffer_reserve (struct vbuffer *o, size_t length) | |
| 107 | {
| |
| 108 | - /* If we don't have a variable output buffer yet, get one. */ | |
| 109 | + size_t newoff = (o->ptr - o->buffer) + length; | |
| 110 | ||
| 111 | - if (variable_buffer == 0) | |
| 112 | - {
| |
| 113 | - variable_buffer_length = 200; | |
| 114 | - variable_buffer = xmalloc (variable_buffer_length); | |
| 115 | - variable_buffer[0] = '\0'; | |
| 116 | - } | |
| 117 | + if ((newoff + VARIABLE_BUFFER_ZONE) > o->size) | |
| 118 | + vbuffer_grow (o, newoff); | |
| 119 | ||
| 120 | - return variable_buffer; | |
| 121 | + return o->size - newoff; | |
| 122 | } | |
| 123 | - | |
| 124 | -/* Recursively expand V. The returned string is malloc'd. */ | |
| 125 | ||
| 126 | -static char *allocated_variable_append (const struct variable *v); | |
| 127 | +/* Writes byte stream pointed by STR into VBUF. | |
| 128 | + The optional LEN argument can be used to limit the amount of bytes to copy. | |
| 129 | + Otherwise (if LEN is a negative number) STR is treated as a null-terminated | |
| 130 | + string and copied accordingly. | |
| 131 | ||
| 132 | -char * | |
| 133 | -recursively_expand_for_file (struct variable *v, struct file *file) | |
| 134 | + Returns the actual number of bytes copied, | |
| 135 | + that is LEN argument if it is non-negative and strlen (STR) otherwise. | |
| 136 | + | |
| 137 | + As like all the other vbuffer methods it leaves the internal buffer | |
| 138 | + of the VBUF null-terminated. */ | |
| 139 | + | |
| 140 | +#ifdef __GNUC__ | |
| 141 | +__inline | |
| 142 | +#endif | |
| 143 | +size_t | |
| 144 | +vbuffer_write (struct vbuffer *o, const char *str, ssize_t len) | |
| 145 | {
| |
| 146 | - char *value; | |
| 147 | - const struct floc *this_var; | |
| 148 | - const struct floc **saved_varp; | |
| 149 | - struct variable_set_list *save = 0; | |
| 150 | - int set_reading = 0; | |
| 151 | + size_t length = len < 0 ? strlen (str) : (size_t) len; | |
| 152 | ||
| 153 | - /* Don't install a new location if this location is empty. | |
| 154 | - This can happen for command-line variables, builtin variables, etc. */ | |
| 155 | - saved_varp = expanding_var; | |
| 156 | - if (v->fileinfo.filenm) | |
| 157 | - {
| |
| 158 | - this_var = &v->fileinfo; | |
| 159 | - expanding_var = &this_var; | |
| 160 | - } | |
| 161 | + if (length == 0) | |
| 162 | + return 0; | |
| 163 | ||
| 164 | - /* If we have no other file-reading context, use the variable's context. */ | |
| 165 | - if (!reading_file) | |
| 166 | - {
| |
| 167 | - set_reading = 1; | |
| 168 | - reading_file = &v->fileinfo; | |
| 169 | - } | |
| 170 | + vbuffer_reserve (o, length); | |
| 171 | ||
| 172 | - if (v->expanding) | |
| 173 | - {
| |
| 174 | - if (!v->exp_count) | |
| 175 | - /* Expanding V causes infinite recursion. Lose. */ | |
| 176 | - fatal (*expanding_var, | |
| 177 | - _("Recursive variable '%s' references itself (eventually)"),
| |
| 178 | - v->name); | |
| 179 | - --v->exp_count; | |
| 180 | - } | |
| 181 | + memcpy (o->ptr, str, length); | |
| 182 | + o->ptr += length; | |
| 183 | ||
| 184 | - if (file) | |
| 185 | - {
| |
| 186 | - save = current_variable_set_list; | |
| 187 | - current_variable_set_list = file->variables; | |
| 188 | - } | |
| 189 | + *o->ptr = '\0'; | |
| 190 | ||
| 191 | - v->expanding = 1; | |
| 192 | - if (v->append) | |
| 193 | - value = allocated_variable_append (v); | |
| 194 | - else | |
| 195 | - value = allocated_variable_expand (v->value); | |
| 196 | - v->expanding = 0; | |
| 197 | + return length; | |
| 198 | +} | |
| 199 | ||
| 200 | - if (set_reading) | |
| 201 | - reading_file = 0; | |
| 202 | +/* Moves the pointer of the VBUF back on the LEN bytes. | |
| 203 | + If LEN is negative, or if moving the pointer would lead to an underflow, | |
| 204 | + then sets the pointer to the start of the buffer. | |
| 205 | ||
| 206 | - if (file) | |
| 207 | - current_variable_set_list = save; | |
| 208 | + Returns the actual number of discarded bytes. */ | |
| 209 | ||
| 210 | - expanding_var = saved_varp; | |
| 211 | +size_t | |
| 212 | +vbuffer_unwrite (struct vbuffer *o, ssize_t len) | |
| 213 | +{
| |
| 214 | + size_t oldoff = o->ptr - o->buffer; | |
| 215 | + size_t length = len < 0 ? oldoff : (size_t) len; | |
| 216 | ||
| 217 | - return value; | |
| 218 | + if (length > oldoff) | |
| 219 | + length = oldoff; | |
| 220 | + | |
| 221 | + o->ptr -= length; | |
| 222 | + | |
| 223 | + *o->ptr = '\0'; | |
| 224 | + | |
| 225 | + return length; | |
| 226 | } | |
| 227 | ||
| 228 | /* Expand a simple reference to variable NAME, which is LENGTH chars long. */ | |
| 229 | @@ -156,11 +150,10 @@ | |
| 230 | #ifdef __GNUC__ | |
| 231 | __inline | |
| 232 | #endif | |
| 233 | -static char * | |
| 234 | -reference_variable (char *o, const char *name, unsigned int length) | |
| 235 | +static size_t | |
| 236 | +expand_variable_reference (struct vbuffer *o, const char *name, size_t length) | |
| 237 | {
| |
| 238 | struct variable *v; | |
| 239 | - char *value; | |
| 240 | ||
| 241 | v = lookup_variable (name, length); | |
| 242 | ||
| 243 | @@ -169,62 +162,117 @@ | |
| 244 | ||
| 245 | /* If there's no variable by that name or it has no value, stop now. */ | |
| 246 | if (v == 0 || (*v->value == '\0' && !v->append)) | |
| 247 | - return o; | |
| 248 | - | |
| 249 | - value = (v->recursive ? recursively_expand (v) : v->value); | |
| 250 | - | |
| 251 | - o = variable_buffer_output (o, value, strlen (value)); | |
| 252 | + return 0; | |
| 253 | ||
| 254 | if (v->recursive) | |
| 255 | - free (value); | |
| 256 | - | |
| 257 | - return o; | |
| 258 | + return vbuffer_expand_variable (o, v); | |
| 259 | + else | |
| 260 | + return vbuffer_write (o, v->value, -1); | |
| 261 | } | |
| 262 | - | |
| 263 | -/* Scan STRING for variable references and expansion-function calls. Only | |
| 264 | - LENGTH bytes of STRING are actually scanned. If LENGTH is -1, scan until | |
| 265 | - a null byte is found. | |
| 266 | - | |
| 267 | - Write the results to LINE, which must point into 'variable_buffer'. If | |
| 268 | - LINE is NULL, start at the beginning of the buffer. | |
| 269 | - Return a pointer to LINE, or to the beginning of the buffer if LINE is | |
| 270 | - NULL. | |
| 271 | - */ | |
| 272 | -char * | |
| 273 | -variable_expand_string (char *line, const char *string, long length) | |
| 274 | + | |
| 275 | + | |
| 276 | +#ifdef __GNUC__ | |
| 277 | +__inline | |
| 278 | +#endif | |
| 279 | +static int | |
| 280 | +handle_subst_reference (struct vbuffer *o, char *beg, char *end) | |
| 281 | {
| |
| 282 | + size_t result = 0; | |
| 283 | struct variable *v; | |
| 284 | - const char *p, *p1; | |
| 285 | - char *save; | |
| 286 | - char *o; | |
| 287 | - unsigned int line_offset; | |
| 288 | - | |
| 289 | - if (!line) | |
| 290 | - line = initialize_variable_output(); | |
| 291 | - o = line; | |
| 292 | - line_offset = line - variable_buffer; | |
| 293 | + const char *subst_beg, *subst_end, *replace_beg, *replace_end; | |
| 294 | + char *colon = lindex (beg, end, ':'); | |
| 295 | ||
| 296 | - if (length == 0) | |
| 297 | + if (colon == 0) | |
| 298 | + return -1; | |
| 299 | + | |
| 300 | + subst_beg = colon + 1; | |
| 301 | + subst_end = lindex (subst_beg, end, '='); | |
| 302 | + if (subst_end == 0) | |
| 303 | + /* There is no = in sight. Punt on the substitution reference and treat | |
| 304 | + this as a variable name containing a colon. */ | |
| 305 | + return -1; | |
| 306 | + | |
| 307 | + /* This looks like a valid substitution reference: $(FOO:A=B). */ | |
| 308 | + replace_beg = subst_end + 1; | |
| 309 | + replace_end = end; | |
| 310 | + | |
| 311 | + /* Extract the variable name before the colon and look up that variable. */ | |
| 312 | + v = lookup_variable (beg, colon - beg); | |
| 313 | + if (v == 0) | |
| 314 | + warn_undefined (beg, colon - beg); | |
| 315 | + | |
| 316 | + /* If the variable is not empty, perform the substitution. */ | |
| 317 | + if (v != 0 && *v->value != '\0') | |
| 318 | {
| |
| 319 | - variable_buffer_output (o, "", 1); | |
| 320 | - return (variable_buffer); | |
| 321 | + char *pattern, *replace, *ppercent, *rpercent; | |
| 322 | + char *value = (v->recursive | |
| 323 | + ? recursively_expand(v) | |
| 324 | + : v->value); | |
| 325 | + | |
| 326 | + /* Copy the pattern and the replacement. Add in an extra % at the | |
| 327 | + beginning to use in case there isn't one in the pattern. */ | |
| 328 | + pattern = alloca (subst_end - subst_beg + 2); | |
| 329 | + *(pattern++) = '%'; | |
| 330 | + memcpy (pattern, subst_beg, subst_end - subst_beg); | |
| 331 | + pattern[subst_end - subst_beg] = '\0'; | |
| 332 | + | |
| 333 | + replace = alloca (replace_end - replace_beg + 2); | |
| 334 | + *(replace++) = '%'; | |
| 335 | + memcpy (replace, replace_beg, replace_end - replace_beg); | |
| 336 | + replace[replace_end - replace_beg] = '\0'; | |
| 337 | + | |
| 338 | + /* Look for %. Set the percent pointers properly | |
| 339 | + based on whether we find one or not. */ | |
| 340 | + ppercent = find_percent (pattern); | |
| 341 | + if (ppercent) | |
| 342 | + {
| |
| 343 | + ++ppercent; | |
| 344 | + rpercent = find_percent (replace); | |
| 345 | + if (rpercent) | |
| 346 | + ++rpercent; | |
| 347 | + } | |
| 348 | + else | |
| 349 | + {
| |
| 350 | + ppercent = pattern--; | |
| 351 | + rpercent = replace--; | |
| 352 | + } | |
| 353 | + | |
| 354 | + *o->ptr = '\0'; | |
| 355 | + | |
| 356 | + result = patsubst_expand_pat (o, value, | |
| 357 | + pattern, replace, ppercent, rpercent); | |
| 358 | + | |
| 359 | + if (v->recursive) | |
| 360 | + free (value); | |
| 361 | } | |
| 362 | ||
| 363 | - /* We need a copy of STRING: due to eval, it's possible that it will get | |
| 364 | - freed as we process it (it might be the value of a variable that's reset | |
| 365 | - for example). Also having a nil-terminated string is handy. */ | |
| 366 | - save = length < 0 ? xstrdup (string) : xstrndup (string, length); | |
| 367 | - p = save; | |
| 368 | + return result; | |
| 369 | +} | |
| 370 | ||
| 371 | +size_t | |
| 372 | +vbuffer_expand (struct vbuffer *o, char *str, ssize_t len) | |
| 373 | +{
| |
| 374 | + size_t result = 0; | |
| 375 | + char *p, *p1; | |
| 376 | + | |
| 377 | + if (len == 0) | |
| 378 | + return 0; | |
| 379 | + | |
| 380 | + if (len > 0) | |
| 381 | + str[len] = '\0'; | |
| 382 | + | |
| 383 | + p = str; | |
| 384 | while (1) | |
| 385 | {
| |
| 386 | /* Copy all following uninteresting chars all at once to the | |
| 387 | - variable output buffer, and skip them. Uninteresting chars end | |
| 388 | + variable output buffer, and skip them. Uninteresting chars end | |
| 389 | at the next $ or the end of the input. */ | |
| 390 | ||
| 391 | p1 = strchr (p, '$'); | |
| 392 | ||
| 393 | - o = variable_buffer_output (o, p, p1 != 0 ? (unsigned int)(p1 - p) : strlen (p) + 1); | |
| 394 | + /* In case when P1 is nil, | |
| 395 | + 'vbuffer_write' writes the whole string pointed by P. */ | |
| 396 | + result += vbuffer_write (o, p, p1 ? p1 - p : -1); | |
| 397 | ||
| 398 | if (p1 == 0) | |
| 399 | break; | |
| 400 | @@ -236,27 +284,23 @@ | |
| 401 | {
| |
| 402 | case '$': | |
| 403 | /* $$ seen means output one $ to the variable output buffer. */ | |
| 404 | - o = variable_buffer_output (o, p, 1); | |
| 405 | + result += vbuffer_write (o, p, 1); | |
| 406 | break; | |
| 407 | ||
| 408 | case '(':
| |
| 409 | case '{':
| |
| 410 | /* $(...) or ${...} is the general case of substitution. */
| |
| 411 | {
| |
| 412 | + int handle_ret; | |
| 413 | char openparen = *p; | |
| 414 | char closeparen = (openparen == '(') ? ')' : '}';
| |
| 415 | - const char *begp; | |
| 416 | - const char *beg = p + 1; | |
| 417 | - char *op; | |
| 418 | - char *abeg = NULL; | |
| 419 | - const char *end, *colon; | |
| 420 | - | |
| 421 | - op = o; | |
| 422 | - begp = p; | |
| 423 | - if (handle_function (&op, &begp)) | |
| 424 | + char *beg = p + 1; | |
| 425 | + char *end; | |
| 426 | + | |
| 427 | + handle_ret = handle_function (o, &p); | |
| 428 | + if (handle_ret >= 0) | |
| 429 | {
| |
| 430 | - o = op; | |
| 431 | - p = begp; | |
| 432 | + result += handle_ret; | |
| 433 | break; | |
| 434 | } | |
| 435 | ||
| 436 | @@ -265,8 +309,8 @@ | |
| 437 | ||
| 438 | end = strchr (beg, closeparen); | |
| 439 | if (end == 0) | |
| 440 | - /* Unterminated variable reference. */ | |
| 441 | - fatal (*expanding_var, _("unterminated variable reference"));
| |
| 442 | + fatal (*expanding_var, _("unterminated variable reference"));
| |
| 443 | + | |
| 444 | p1 = lindex (beg, end, '$'); | |
| 445 | if (p1 != 0) | |
| 446 | {
| |
| 447 | @@ -285,102 +329,41 @@ | |
| 448 | such as '$($(a)'. */ | |
| 449 | if (count < 0) | |
| 450 | {
| |
| 451 | - abeg = expand_argument (beg, p); /* Expand the name. */ | |
| 452 | - beg = abeg; | |
| 453 | - end = strchr (beg, '\0'); | |
| 454 | + /* Expand the name. | |
| 455 | + As a little optimization we reuse the same vbuffer. */ | |
| 456 | + size_t name_len = vbuffer_expand (o, beg, p - beg); | |
| 457 | + *p = closeparen; | |
| 458 | + | |
| 459 | + /* We don't use 'vbuffer_unwrite' here because it would | |
| 460 | + reset the first byte of the computed name to nil. */ | |
| 461 | + o->ptr -= name_len; | |
| 462 | + | |
| 463 | + beg = o->ptr; | |
| 464 | + end = beg + name_len; | |
| 465 | + | |
| 466 | } | |
| 467 | } | |
| 468 | else | |
| 469 | /* Advance P to the end of this reference. After we are | |
| 470 | - finished expanding this one, P will be incremented to | |
| 471 | - continue the scan. */ | |
| 472 | + finished expanding this one, P will be incremented to | |
| 473 | + continue the scan. */ | |
| 474 | p = end; | |
| 475 | ||
| 476 | /* This is not a reference to a built-in function and | |
| 477 | any variable references inside are now expanded. | |
| 478 | Is the resultant text a substitution reference? */ | |
| 479 | ||
| 480 | - colon = lindex (beg, end, ':'); | |
| 481 | - if (colon) | |
| 482 | + handle_ret = handle_subst_reference (o, beg, end); | |
| 483 | + if (handle_ret >= 0) | |
| 484 | {
| |
| 485 | - /* This looks like a substitution reference: $(FOO:A=B). */ | |
| 486 | - const char *subst_beg, *subst_end, *replace_beg, *replace_end; | |
| 487 | - | |
| 488 | - subst_beg = colon + 1; | |
| 489 | - subst_end = lindex (subst_beg, end, '='); | |
| 490 | - if (subst_end == 0) | |
| 491 | - /* There is no = in sight. Punt on the substitution | |
| 492 | - reference and treat this as a variable name containing | |
| 493 | - a colon, in the code below. */ | |
| 494 | - colon = 0; | |
| 495 | - else | |
| 496 | - {
| |
| 497 | - replace_beg = subst_end + 1; | |
| 498 | - replace_end = end; | |
| 499 | - | |
| 500 | - /* Extract the variable name before the colon | |
| 501 | - and look up that variable. */ | |
| 502 | - v = lookup_variable (beg, colon - beg); | |
| 503 | - if (v == 0) | |
| 504 | - warn_undefined (beg, colon - beg); | |
| 505 | - | |
| 506 | - /* If the variable is not empty, perform the | |
| 507 | - substitution. */ | |
| 508 | - if (v != 0 && *v->value != '\0') | |
| 509 | - {
| |
| 510 | - char *pattern, *replace, *ppercent, *rpercent; | |
| 511 | - char *value = (v->recursive | |
| 512 | - ? recursively_expand (v) | |
| 513 | - : v->value); | |
| 514 | - | |
| 515 | - /* Copy the pattern and the replacement. Add in an | |
| 516 | - extra % at the beginning to use in case there | |
| 517 | - isn't one in the pattern. */ | |
| 518 | - pattern = alloca (subst_end - subst_beg + 2); | |
| 519 | - *(pattern++) = '%'; | |
| 520 | - memcpy (pattern, subst_beg, subst_end - subst_beg); | |
| 521 | - pattern[subst_end - subst_beg] = '\0'; | |
| 522 | - | |
| 523 | - replace = alloca (replace_end - replace_beg + 2); | |
| 524 | - *(replace++) = '%'; | |
| 525 | - memcpy (replace, replace_beg, | |
| 526 | - replace_end - replace_beg); | |
| 527 | - replace[replace_end - replace_beg] = '\0'; | |
| 528 | - | |
| 529 | - /* Look for %. Set the percent pointers properly | |
| 530 | - based on whether we find one or not. */ | |
| 531 | - ppercent = find_percent (pattern); | |
| 532 | - if (ppercent) | |
| 533 | - {
| |
| 534 | - ++ppercent; | |
| 535 | - rpercent = find_percent (replace); | |
| 536 | - if (rpercent) | |
| 537 | - ++rpercent; | |
| 538 | - } | |
| 539 | - else | |
| 540 | - {
| |
| 541 | - ppercent = pattern; | |
| 542 | - rpercent = replace; | |
| 543 | - --pattern; | |
| 544 | - --replace; | |
| 545 | - } | |
| 546 | - | |
| 547 | - o = patsubst_expand_pat (o, value, pattern, replace, | |
| 548 | - ppercent, rpercent); | |
| 549 | - | |
| 550 | - if (v->recursive) | |
| 551 | - free (value); | |
| 552 | - } | |
| 553 | - } | |
| 554 | + result += handle_ret; | |
| 555 | + break; | |
| 556 | } | |
| 557 | ||
| 558 | - if (colon == 0) | |
| 559 | - /* This is an ordinary variable reference. | |
| 560 | - Look up the value of the variable. */ | |
| 561 | - o = reference_variable (o, beg, end - beg); | |
| 562 | - | |
| 563 | - if (abeg) | |
| 564 | - free (abeg); | |
| 565 | + /* This is an ordinary variable reference. | |
| 566 | + Look up the value of the variable. */ | |
| 567 | + result += expand_variable_reference (o, beg, end - beg); | |
| 568 | + *o->ptr = '\0'; | |
| 569 | } | |
| 570 | break; | |
| 571 | ||
| 572 | @@ -393,7 +376,7 @@ | |
| 573 | ||
| 574 | /* A $ followed by a random char is a variable reference: | |
| 575 | $a is equivalent to $(a). */ | |
| 576 | - o = reference_variable (o, p, 1); | |
| 577 | + result += expand_variable_reference (o, p, 1); | |
| 578 | ||
| 579 | break; | |
| 580 | } | |
| 581 | @@ -404,69 +387,19 @@ | |
| 582 | ++p; | |
| 583 | } | |
| 584 | ||
| 585 | - free (save); | |
| 586 | - | |
| 587 | - variable_buffer_output (o, "", 1); | |
| 588 | - return (variable_buffer + line_offset); | |
| 589 | -} | |
| 590 | - | |
| 591 | -/* Scan LINE for variable references and expansion-function calls. | |
| 592 | - Build in 'variable_buffer' the result of expanding the references and calls. | |
| 593 | - Return the address of the resulting string, which is null-terminated | |
| 594 | - and is valid only until the next time this function is called. */ | |
| 595 | - | |
| 596 | -char * | |
| 597 | -variable_expand (const char *line) | |
| 598 | -{
| |
| 599 | - return variable_expand_string(NULL, line, (long)-1); | |
| 600 | -} | |
| 601 | - | |
| 602 | -/* Expand an argument for an expansion function. | |
| 603 | - The text starting at STR and ending at END is variable-expanded | |
| 604 | - into a null-terminated string that is returned as the value. | |
| 605 | - This is done without clobbering 'variable_buffer' or the current | |
| 606 | - variable-expansion that is in progress. */ | |
| 607 | - | |
| 608 | -char * | |
| 609 | -expand_argument (const char *str, const char *end) | |
| 610 | -{
| |
| 611 | - char *tmp, *alloc = NULL; | |
| 612 | - char *r; | |
| 613 | - | |
| 614 | - if (str == end) | |
| 615 | - return xstrdup("");
| |
| 616 | - | |
| 617 | - if (!end || *end == '\0') | |
| 618 | - return allocated_variable_expand (str); | |
| 619 | - | |
| 620 | - if (end - str + 1 > 1000) | |
| 621 | - tmp = alloc = xmalloc (end - str + 1); | |
| 622 | - else | |
| 623 | - tmp = alloca (end - str + 1); | |
| 624 | - | |
| 625 | - memcpy (tmp, str, end - str); | |
| 626 | - tmp[end - str] = '\0'; | |
| 627 | - | |
| 628 | - r = allocated_variable_expand (tmp); | |
| 629 | - | |
| 630 | - if (alloc) | |
| 631 | - free (alloc); | |
| 632 | + return result; | |
| 633 | ||
| 634 | - return r; | |
| 635 | } | |
| 636 | - | |
| 637 | -/* Expand LINE for FILE. Error messages refer to the file and line where | |
| 638 | - FILE's commands were found. Expansion uses FILE's variable set list. */ | |
| 639 | ||
| 640 | -char * | |
| 641 | -variable_expand_for_file (const char *line, struct file *file) | |
| 642 | -{
| |
| 643 | - char *result; | |
| 644 | +size_t | |
| 645 | +vbuffer_expand_for_file (struct vbuffer *o, char *str, ssize_t len, | |
| 646 | + struct file *file) {
| |
| 647 | + size_t result = 0; | |
| 648 | struct variable_set_list *savev; | |
| 649 | const struct floc *savef; | |
| 650 | ||
| 651 | if (file == 0) | |
| 652 | - return variable_expand (line); | |
| 653 | + return vbuffer_expand (o, str, len); | |
| 654 | ||
| 655 | savev = current_variable_set_list; | |
| 656 | current_variable_set_list = file->variables; | |
| 657 | @@ -477,124 +410,251 @@ | |
| 658 | else | |
| 659 | reading_file = 0; | |
| 660 | ||
| 661 | - result = variable_expand (line); | |
| 662 | + result = vbuffer_expand (o, str, len); | |
| 663 | ||
| 664 | current_variable_set_list = savev; | |
| 665 | reading_file = savef; | |
| 666 | ||
| 667 | return result; | |
| 668 | } | |
| 669 | - | |
| 670 | + | |
| 671 | /* Like allocated_variable_expand, but for += target-specific variables. | |
| 672 | First recursively construct the variable value from its appended parts in | |
| 673 | any upper variable sets. Then expand the resulting value. */ | |
| 674 | ||
| 675 | -static char * | |
| 676 | -variable_append (const char *name, unsigned int length, | |
| 677 | - const struct variable_set_list *set, int local) | |
| 678 | +static size_t | |
| 679 | +expand_variable_append (struct vbuffer *o, | |
| 680 | + const char *name, unsigned int length, | |
| 681 | + const struct variable_set_list *set_list, | |
| 682 | + int local) | |
| 683 | {
| |
| 684 | + size_t ret = 0; | |
| 685 | const struct variable *v; | |
| 686 | - char *buf = 0; | |
| 687 | - /* If this set is local and the next is not a parent, then next is local. */ | |
| 688 | - int nextlocal = local && set->next_is_parent == 0; | |
| 689 | + int nextlocal; | |
| 690 | ||
| 691 | /* If there's nothing left to check, return the empty buffer. */ | |
| 692 | - if (!set) | |
| 693 | - return initialize_variable_output (); | |
| 694 | + if (!set_list) | |
| 695 | + return 0; | |
| 696 | + | |
| 697 | + /* If this set is local and the next is not a parent, then next is local. */ | |
| 698 | + nextlocal = local && set_list->next_is_parent == 0; | |
| 699 | ||
| 700 | /* Try to find the variable in this variable set. */ | |
| 701 | - v = lookup_variable_in_set (name, length, set->set); | |
| 702 | + v = lookup_variable_in_set (name, length, set_list->set); | |
| 703 | ||
| 704 | /* If there isn't one, or this one is private, try the set above us. */ | |
| 705 | if (!v || (!local && v->private_var)) | |
| 706 | - return variable_append (name, length, set->next, nextlocal); | |
| 707 | + return expand_variable_append (o, name, length, | |
| 708 | + set_list->next, nextlocal); | |
| 709 | ||
| 710 | /* If this variable type is append, first get any upper values. | |
| 711 | If not, initialize the buffer. */ | |
| 712 | if (v->append) | |
| 713 | - buf = variable_append (name, length, set->next, nextlocal); | |
| 714 | - else | |
| 715 | - buf = initialize_variable_output (); | |
| 716 | + ret += expand_variable_append (o, name, length, | |
| 717 | + set_list->next, nextlocal); | |
| 718 | ||
| 719 | /* Append this value to the buffer, and return it. | |
| 720 | If we already have a value, first add a space. */ | |
| 721 | - if (buf > variable_buffer) | |
| 722 | - buf = variable_buffer_output (buf, " ", 1); | |
| 723 | + if (ret != 0) | |
| 724 | + ret += vbuffer_write (o, " ", 1); | |
| 725 | ||
| 726 | /* Either expand it or copy it, depending. */ | |
| 727 | - if (! v->recursive) | |
| 728 | - return variable_buffer_output (buf, v->value, strlen (v->value)); | |
| 729 | + if (v->recursive) | |
| 730 | + ret += vbuffer_expand_ro (o, v->value, -1); | |
| 731 | + else | |
| 732 | + ret += vbuffer_write (o, v->value, -1); | |
| 733 | ||
| 734 | - buf = variable_expand_string (buf, v->value, strlen (v->value)); | |
| 735 | - return (buf + strlen (buf)); | |
| 736 | + return ret; | |
| 737 | } | |
| 738 | ||
| 739 | +size_t | |
| 740 | +vbuffer_expand_variable_for_file (struct vbuffer *o, struct variable *v, | |
| 741 | + struct file *file) | |
| 742 | +{
| |
| 743 | + size_t ret = 0; | |
| 744 | + const struct floc *this_var; | |
| 745 | + const struct floc **saved_varp; | |
| 746 | + struct variable_set_list *save = 0; | |
| 747 | + int set_reading = 0; | |
| 748 | + | |
| 749 | + /* Don't install a new location if this location is empty. | |
| 750 | + This can happen for command-line variables, builtin variables, etc. */ | |
| 751 | + saved_varp = expanding_var; | |
| 752 | + if (v->fileinfo.filenm) | |
| 753 | + {
| |
| 754 | + this_var = &v->fileinfo; | |
| 755 | + expanding_var = &this_var; | |
| 756 | + } | |
| 757 | + | |
| 758 | + /* If we have no other file-reading context, use the variable's context. */ | |
| 759 | + if (!reading_file) | |
| 760 | + {
| |
| 761 | + set_reading = 1; | |
| 762 | + reading_file = &v->fileinfo; | |
| 763 | + } | |
| 764 | + | |
| 765 | + if (v->expanding) | |
| 766 | + {
| |
| 767 | + if (!v->exp_count) | |
| 768 | + /* Expanding V causes infinite recursion. Lose. */ | |
| 769 | + fatal (*expanding_var, | |
| 770 | + _("Recursive variable '%s' references itself (eventually)"),
| |
| 771 | + v->name); | |
| 772 | + --v->exp_count; | |
| 773 | + } | |
| 774 | + | |
| 775 | + if (file) | |
| 776 | + {
| |
| 777 | + save = current_variable_set_list; | |
| 778 | + current_variable_set_list = file->variables; | |
| 779 | + } | |
| 780 | + | |
| 781 | + v->expanding = 1; | |
| 782 | + | |
| 783 | + if (v->append) | |
| 784 | + ret += expand_variable_append (o, v->name, strlen (v->name), | |
| 785 | + current_variable_set_list, 1); | |
| 786 | + else | |
| 787 | + /* We need a copy of STRING: due to eval, it's possible that it will get | |
| 788 | + freed as we process it (it might be the value of a variable that's | |
| 789 | + reset, for example). Also having a nil-terminated string is handy. */ | |
| 790 | + ret += vbuffer_expand_ro (o, v->value, -1); | |
| 791 | ||
| 792 | -static char * | |
| 793 | -allocated_variable_append (const struct variable *v) | |
| 794 | + v->expanding = 0; | |
| 795 | + | |
| 796 | + if (set_reading) | |
| 797 | + reading_file = 0; | |
| 798 | + | |
| 799 | + if (file) | |
| 800 | + current_variable_set_list = save; | |
| 801 | + | |
| 802 | + expanding_var = saved_varp; | |
| 803 | + | |
| 804 | + return ret; | |
| 805 | +} | |
| 806 | + | |
| 807 | +size_t | |
| 808 | +vbuffer_expand_ro (struct vbuffer *o, const char *str, ssize_t len) | |
| 809 | +{
| |
| 810 | + size_t ret; | |
| 811 | + size_t length = len < 0 ? strlen (str) : (size_t) len; | |
| 812 | + | |
| 813 | + char *alloc = 0; | |
| 814 | + char *value = length > MAX_ALLOCA_SIZE | |
| 815 | + ? (alloc = xmalloc (length + 1)) | |
| 816 | + : alloca (length + 1); | |
| 817 | + | |
| 818 | + ret = vbuffer_expand (o, memcpy (value, str, length + 1), length); | |
| 819 | + | |
| 820 | + if (alloc) | |
| 821 | + free (alloc); | |
| 822 | + | |
| 823 | + return ret; | |
| 824 | +} | |
| 825 | + | |
| 826 | +size_t | |
| 827 | +vbuffer_expand_ro_for_file (struct vbuffer *o, const char *str, ssize_t len, | |
| 828 | + struct file *file) | |
| 829 | {
| |
| 830 | - char *val; | |
| 831 | + size_t ret; | |
| 832 | + char *string = len < 0 ? xstrdup (str) : xstrndup (str, len); | |
| 833 | + ret = vbuffer_expand_for_file (o, string, -1, file); | |
| 834 | + free (string); | |
| 835 | + return ret; | |
| 836 | +} | |
| 837 | ||
| 838 | - /* Construct the appended variable value. */ | |
| 839 | +/* Install a new expansion vbuffer, returning the current one. */ | |
| 840 | + | |
| 841 | +struct vbuffer * | |
| 842 | +install_new_expansion_vbuffer (void) | |
| 843 | +{
| |
| 844 | + struct vbuffer *old_vbuf = expansion_vbuf; | |
| 845 | ||
| 846 | - char *obuf = variable_buffer; | |
| 847 | - unsigned int olen = variable_buffer_length; | |
| 848 | + expansion_vbuf = xmalloc(sizeof(struct vbuffer)); | |
| 849 | + vbuffer_init(expansion_vbuf); | |
| 850 | ||
| 851 | - variable_buffer = 0; | |
| 852 | + return old_vbuf; | |
| 853 | +} | |
| 854 | ||
| 855 | - val = variable_append (v->name, strlen (v->name), | |
| 856 | - current_variable_set_list, 1); | |
| 857 | - variable_buffer_output (val, "", 1); | |
| 858 | - val = variable_buffer; | |
| 859 | +/* Restore a previously-saved vbuffer setting freeing the current one. */ | |
| 860 | ||
| 861 | - variable_buffer = obuf; | |
| 862 | - variable_buffer_length = olen; | |
| 863 | +void | |
| 864 | +restore_expansion_vbuffer (struct vbuffer *old_vbuf) | |
| 865 | +{
| |
| 866 | + vbuffer_free(expansion_vbuf); | |
| 867 | + free(expansion_vbuf); | |
| 868 | ||
| 869 | - return val; | |
| 870 | + expansion_vbuf = old_vbuf; | |
| 871 | } | |
| 872 | ||
| 873 | -/* Like variable_expand_for_file, but the returned string is malloc'd. | |
| 874 | - This function is called a lot. It wants to be efficient. */ | |
| 875 | +/* Expand an argument for an expansion function. | |
| 876 | + The text starting at STR and ending at END is variable-expanded | |
| 877 | + into a null-terminated string that is returned as the value. | |
| 878 | + This is done without clobbering 'variable_buffer' or the current | |
| 879 | + variable-expansion that is in progress. */ | |
| 880 | ||
| 881 | char * | |
| 882 | -allocated_variable_expand_for_file (const char *line, struct file *file) | |
| 883 | +expand_argument (const char *str, const char *end) | |
| 884 | {
| |
| 885 | - char *value; | |
| 886 | + struct vbuffer vbuf; | |
| 887 | ||
| 888 | - char *obuf = variable_buffer; | |
| 889 | - unsigned int olen = variable_buffer_length; | |
| 890 | + vbuffer_expand_ro (vbuffer_init(&vbuf), str, end - str); | |
| 891 | ||
| 892 | - variable_buffer = 0; | |
| 893 | + return vbuf.buffer; | |
| 894 | +} | |
| 895 | ||
| 896 | - value = variable_expand_for_file (line, file); | |
| 897 | +/* Scan LINE for variable references and expansion-function calls. | |
| 898 | + Build in 'variable_buffer' the result of expanding the references and calls. | |
| 899 | + Return the address of the resulting string, which is null-terminated | |
| 900 | + and is valid only until the next time this function is called. */ | |
| 901 | ||
| 902 | - variable_buffer = obuf; | |
| 903 | - variable_buffer_length = olen; | |
| 904 | +char * | |
| 905 | +variable_expand (const char *line) | |
| 906 | +{
| |
| 907 | + vbuffer_expand_ro (vbuffer_reset(expansion_vbuf), line, -1); | |
| 908 | ||
| 909 | - return value; | |
| 910 | + return expansion_vbuf->buffer; | |
| 911 | } | |
| 912 | ||
| 913 | -/* Install a new variable_buffer context, returning the current one for | |
| 914 | - safe-keeping. */ | |
| 915 | +/* Expand LINE for FILE. Error messages refer to the file and line where | |
| 916 | + FILE's commands were found. Expansion uses FILE's variable set list. */ | |
| 917 | ||
| 918 | -void | |
| 919 | -install_variable_buffer (char **bufp, unsigned int *lenp) | |
| 920 | +char * | |
| 921 | +variable_expand_for_file (const char *line, struct file *file) | |
| 922 | +{
| |
| 923 | + vbuffer_expand_ro_for_file (vbuffer_reset(expansion_vbuf), line, -1, file); | |
| 924 | + | |
| 925 | + return expansion_vbuf->buffer; | |
| 926 | +} | |
| 927 | + | |
| 928 | +char * | |
| 929 | +allocated_variable_expand (const char *line) | |
| 930 | {
| |
| 931 | - *bufp = variable_buffer; | |
| 932 | - *lenp = variable_buffer_length; | |
| 933 | + struct vbuffer vbuf; | |
| 934 | ||
| 935 | - variable_buffer = 0; | |
| 936 | - initialize_variable_output (); | |
| 937 | + vbuffer_expand_ro (vbuffer_init(&vbuf), line, -1); | |
| 938 | + | |
| 939 | + return vbuf.buffer; | |
| 940 | } | |
| 941 | ||
| 942 | -/* Restore a previously-saved variable_buffer setting (free the current one). | |
| 943 | - */ | |
| 944 | +/* Like variable_expand_for_file, but the returned string is malloc'd. */ | |
| 945 | ||
| 946 | -void | |
| 947 | -restore_variable_buffer (char *buf, unsigned int len) | |
| 948 | +char * | |
| 949 | +allocated_variable_expand_for_file (const char *line, struct file *file) | |
| 950 | {
| |
| 951 | - free (variable_buffer); | |
| 952 | + struct vbuffer vbuf; | |
| 953 | + | |
| 954 | + vbuffer_expand_ro_for_file (vbuffer_init(&vbuf), line, -1, file); | |
| 955 | + | |
| 956 | + return vbuf.buffer; | |
| 957 | +} | |
| 958 | + | |
| 959 | +char * | |
| 960 | +recursively_expand_for_file (struct variable *v, struct file *file) | |
| 961 | +{
| |
| 962 | + struct vbuffer vbuf; | |
| 963 | + | |
| 964 | + vbuffer_expand_variable_for_file (vbuffer_init(&vbuf), v, file); | |
| 965 | ||
| 966 | - variable_buffer = buf; | |
| 967 | - variable_buffer_length = len; | |
| 968 | + return vbuf.buffer; | |
| 969 | } | |
| 970 | Index: file.c | |
| 971 | =================================================================== | |
| 972 | RCS file: /sources/make/make/file.c,v | |
| 973 | retrieving revision 1.105 | |
| 974 | diff -u -r1.105 file.c | |
| 975 | --- file.c 5 Mar 2012 14:10:43 -0000 1.105 | |
| 976 | - | +++ file.c 9 Apr 2012 09:50:04 -0000 |
| 976 | + | +++ file.c 9 Apr 2012 13:34:41 -0000 |
| 977 | @@ -467,9 +467,11 @@ | |
| 978 | if (stem) | |
| 979 | {
| |
| 980 | const char *pattern = "%"; | |
| 981 | - char *buffer = variable_expand ("");
| |
| 982 | + struct vbuffer vbuf; | |
| 983 | struct dep *dp = deps, *dl = 0; | |
| 984 | ||
| 985 | + vbuffer_init (&vbuf); | |
| 986 | + | |
| 987 | while (dp != 0) | |
| 988 | {
| |
| 989 | char *percent; | |
| 990 | @@ -479,22 +481,23 @@ | |
| 991 | percent = find_percent (nm); | |
| 992 | if (percent) | |
| 993 | {
| |
| 994 | - char *o; | |
| 995 | + size_t len; | |
| 996 | ||
| 997 | /* We have to handle empty stems specially, because that | |
| 998 | would be equivalent to $(patsubst %,dp->name,) which | |
| 999 | will always be empty. */ | |
| 1000 | - if (stem[0] == '\0') | |
| 1001 | + if (*stem == '\0') | |
| 1002 | {
| |
| 1003 | memmove (percent, percent+1, strlen (percent)); | |
| 1004 | - o = variable_buffer_output (buffer, nm, strlen (nm) + 1); | |
| 1005 | + len = vbuffer_write (vbuffer_reset (&vbuf), nm, -1); | |
| 1006 | } | |
| 1007 | else | |
| 1008 | - o = patsubst_expand_pat (buffer, stem, pattern, nm, | |
| 1009 | - pattern+1, percent+1); | |
| 1010 | + len = patsubst_expand_pat (vbuffer_reset (&vbuf), stem, | |
| 1011 | + pattern, nm, | |
| 1012 | + pattern+1, percent+1); | |
| 1013 | ||
| 1014 | /* If the name expanded to the empty string, ignore it. */ | |
| 1015 | - if (buffer[0] == '\0') | |
| 1016 | + if (len == 0) | |
| 1017 | {
| |
| 1018 | struct dep *df = dp; | |
| 1019 | if (dp == deps) | |
| 1020 | @@ -506,24 +509,26 @@ | |
| 1021 | } | |
| 1022 | ||
| 1023 | /* Save the name. */ | |
| 1024 | - dp->name = strcache_add_len (buffer, o - buffer); | |
| 1025 | + dp->name = strcache_add_len (vbuf.buffer, len); | |
| 1026 | } | |
| 1027 | dp->stem = stem; | |
| 1028 | dp->staticpattern = 1; | |
| 1029 | dl = dp; | |
| 1030 | dp = dp->next; | |
| 1031 | } | |
| 1032 | + | |
| 1033 | + vbuffer_free (&vbuf); | |
| 1034 | } | |
| 1035 | ||
| 1036 | /* Enter them as files, unless they need a 2nd expansion. */ | |
| 1037 | for (d1 = deps; d1 != 0; d1 = d1->next) | |
| 1038 | {
| |
| 1039 | if (d1->need_2nd_expansion) | |
| 1040 | - continue; | |
| 1041 | + continue; | |
| 1042 | ||
| 1043 | d1->file = lookup_file (d1->name); | |
| 1044 | if (d1->file == 0) | |
| 1045 | - d1->file = enter_file (d1->name); | |
| 1046 | + d1->file = enter_file (d1->name); | |
| 1047 | d1->staticpattern = 0; | |
| 1048 | d1->name = 0; | |
| 1049 | } | |
| 1050 | @@ -573,12 +578,10 @@ | |
| 1051 | "$*" so they'll expand properly. */ | |
| 1052 | if (d->staticpattern) | |
| 1053 | {
| |
| 1054 | - char *o; | |
| 1055 | - d->name = o = variable_expand ("");
| |
| 1056 | - o = subst_expand (o, name, "%", "$*", 1, 2, 0); | |
| 1057 | - *o = '\0'; | |
| 1058 | + struct vbuffer vbuf; | |
| 1059 | + subst_expand (vbuffer_init(&vbuf), name, "%", "$*", 1, 2, 0); | |
| 1060 | free (name); | |
| 1061 | - d->name = name = xstrdup (d->name); | |
| 1062 | + d->name = name = xstrdup (vbuf.buffer); | |
| 1063 | d->staticpattern = 0; | |
| 1064 | } | |
| 1065 | ||
| 1066 | Index: function.c | |
| 1067 | =================================================================== | |
| 1068 | RCS file: /sources/make/make/function.c,v | |
| 1069 | retrieving revision 1.133 | |
| 1070 | diff -u -r1.133 function.c | |
| 1071 | --- function.c 5 Mar 2012 14:10:43 -0000 1.133 | |
| 1072 | - | +++ function.c 9 Apr 2012 09:50:04 -0000 |
| 1072 | + | +++ function.c 9 Apr 2012 13:34:41 -0000 |
| 1073 | @@ -15,6 +15,9 @@ | |
| 1074 | this program. If not, see <http://www.gnu.org/licenses/>. */ | |
| 1075 | ||
| 1076 | #include "make.h" | |
| 1077 | + | |
| 1078 | +#include <assert.h> | |
| 1079 | + | |
| 1080 | #include "filedef.h" | |
| 1081 | #include "variable.h" | |
| 1082 | #include "dep.h" | |
| 1083 | @@ -34,7 +37,7 @@ | |
| 1084 | unsigned char minimum_args; | |
| 1085 | unsigned char maximum_args; | |
| 1086 | char expand_args; | |
| 1087 | - char *(*func_ptr) (char *output, char **argv, const char *fname); | |
| 1088 | + size_t (*func_ptr) (struct vbuffer *output, char **argv, const char *fname); | |
| 1089 | }; | |
| 1090 | ||
| 1091 | static unsigned long | |
| 1092 | @@ -65,26 +68,29 @@ | |
| 1093 | static struct hash_table function_table; | |
| 1094 | ||
| 1095 | ||
| 1096 | -/* Store into VARIABLE_BUFFER at O the result of scanning TEXT and replacing | |
| 1097 | +/* Store into VBUFFER at O the result of scanning TEXT and replacing | |
| 1098 | each occurrence of SUBST with REPLACE. TEXT is null-terminated. SLEN is | |
| 1099 | the length of SUBST and RLEN is the length of REPLACE. If BY_WORD is | |
| 1100 | nonzero, substitutions are done only on matches which are complete | |
| 1101 | whitespace-delimited words. */ | |
| 1102 | ||
| 1103 | -char * | |
| 1104 | -subst_expand (char *o, const char *text, const char *subst, const char *replace, | |
| 1105 | - unsigned int slen, unsigned int rlen, int by_word) | |
| 1106 | +size_t | |
| 1107 | +subst_expand (struct vbuffer *o, const char *text, const char *subst, | |
| 1108 | + const char *replace, unsigned int slen, unsigned int rlen, | |
| 1109 | + int by_word) | |
| 1110 | {
| |
| 1111 | + size_t result = 0; | |
| 1112 | + | |
| 1113 | const char *t = text; | |
| 1114 | const char *p; | |
| 1115 | ||
| 1116 | if (slen == 0 && !by_word) | |
| 1117 | {
| |
| 1118 | /* The first occurrence of "" in any string is its end. */ | |
| 1119 | - o = variable_buffer_output (o, t, strlen (t)); | |
| 1120 | + result += vbuffer_write (o, t, -1); | |
| 1121 | if (rlen > 0) | |
| 1122 | - o = variable_buffer_output (o, replace, rlen); | |
| 1123 | - return o; | |
| 1124 | + result += vbuffer_write (o, replace, rlen); | |
| 1125 | + return result; | |
| 1126 | } | |
| 1127 | ||
| 1128 | do | |
| 1129 | @@ -99,14 +105,14 @@ | |
| 1130 | if (p == 0) | |
| 1131 | {
| |
| 1132 | /* No more matches. Output everything left on the end. */ | |
| 1133 | - o = variable_buffer_output (o, t, strlen (t)); | |
| 1134 | - return o; | |
| 1135 | + result += vbuffer_write (o, t, -1); | |
| 1136 | + return result; | |
| 1137 | } | |
| 1138 | } | |
| 1139 | ||
| 1140 | /* Output everything before this occurrence of the string to replace. */ | |
| 1141 | if (p > t) | |
| 1142 | - o = variable_buffer_output (o, t, p - t); | |
| 1143 | + result += vbuffer_write (o, t, p - t); | |
| 1144 | ||
| 1145 | /* If we're substituting only by fully matched words, | |
| 1146 | or only at the ends of words, check that this case qualifies. */ | |
| 1147 | @@ -115,20 +121,21 @@ | |
| 1148 | || (p[slen] != '\0' && !isblank ((unsigned char)p[slen])))) | |
| 1149 | /* Struck out. Output the rest of the string that is | |
| 1150 | no longer to be replaced. */ | |
| 1151 | - o = variable_buffer_output (o, subst, slen); | |
| 1152 | + result += vbuffer_write (o, subst, slen); | |
| 1153 | else if (rlen > 0) | |
| 1154 | /* Output the replacement string. */ | |
| 1155 | - o = variable_buffer_output (o, replace, rlen); | |
| 1156 | + result += vbuffer_write (o, replace, rlen); | |
| 1157 | ||
| 1158 | /* Advance T past the string to be replaced. */ | |
| 1159 | t = p + slen; | |
| 1160 | - } while (*t != '\0'); | |
| 1161 | + } | |
| 1162 | + while (*t != '\0'); | |
| 1163 | ||
| 1164 | - return o; | |
| 1165 | + return result; | |
| 1166 | } | |
| 1167 | ||
| 1168 | ||
| 1169 | -/* Store into VARIABLE_BUFFER at O the result of scanning TEXT | |
| 1170 | +/* Store into VBUFFER at O the result of scanning TEXT | |
| 1171 | and replacing strings matching PATTERN with REPLACE. | |
| 1172 | If PATTERN_PERCENT is not nil, PATTERN has already been | |
| 1173 | run through find_percent, and PATTERN_PERCENT is the result. | |
| 1174 | @@ -138,16 +145,17 @@ | |
| 1175 | character _AFTER_ the %, not to the % itself. | |
| 1176 | */ | |
| 1177 | ||
| 1178 | -char * | |
| 1179 | -patsubst_expand_pat (char *o, const char *text, | |
| 1180 | +size_t | |
| 1181 | +patsubst_expand_pat (struct vbuffer *o, const char *text, | |
| 1182 | const char *pattern, const char *replace, | |
| 1183 | const char *pattern_percent, const char *replace_percent) | |
| 1184 | {
| |
| 1185 | + size_t ret = 0; | |
| 1186 | + | |
| 1187 | unsigned int pattern_prepercent_len, pattern_postpercent_len; | |
| 1188 | unsigned int replace_prepercent_len, replace_postpercent_len; | |
| 1189 | const char *t; | |
| 1190 | unsigned int len; | |
| 1191 | - int doneany = 0; | |
| 1192 | ||
| 1193 | /* Record the length of REPLACE before and after the % so we don't have to | |
| 1194 | compute these lengths more than once. */ | |
| 1195 | @@ -197,43 +205,37 @@ | |
| 1196 | ||
| 1197 | if (fail) | |
| 1198 | /* It didn't match. Output the string. */ | |
| 1199 | - o = variable_buffer_output (o, t, len); | |
| 1200 | + ret += vbuffer_write (o, t, len); | |
| 1201 | else | |
| 1202 | {
| |
| 1203 | /* It matched. Output the replacement. */ | |
| 1204 | ||
| 1205 | /* Output the part of the replacement before the %. */ | |
| 1206 | - o = variable_buffer_output (o, replace, replace_prepercent_len); | |
| 1207 | + ret += vbuffer_write (o, replace, replace_prepercent_len); | |
| 1208 | ||
| 1209 | if (replace_percent != 0) | |
| 1210 | {
| |
| 1211 | /* Output the part of the matched string that | |
| 1212 | matched the % in the pattern. */ | |
| 1213 | - o = variable_buffer_output (o, t + pattern_prepercent_len, | |
| 1214 | - len - (pattern_prepercent_len | |
| 1215 | + ret += vbuffer_write (o, t + pattern_prepercent_len, | |
| 1216 | + len - (pattern_prepercent_len | |
| 1217 | + pattern_postpercent_len)); | |
| 1218 | /* Output the part of the replacement after the %. */ | |
| 1219 | - o = variable_buffer_output (o, replace_percent, | |
| 1220 | - replace_postpercent_len); | |
| 1221 | + ret += vbuffer_write (o, replace_percent, | |
| 1222 | + replace_postpercent_len); | |
| 1223 | } | |
| 1224 | } | |
| 1225 | ||
| 1226 | /* Output a space, but not if the replacement is "". */ | |
| 1227 | if (fail || replace_prepercent_len > 0 | |
| 1228 | || (replace_percent != 0 && len + replace_postpercent_len > 0)) | |
| 1229 | - {
| |
| 1230 | - o = variable_buffer_output (o, " ", 1); | |
| 1231 | - doneany = 1; | |
| 1232 | - } | |
| 1233 | + ret += vbuffer_write (o, " ", 1); | |
| 1234 | } | |
| 1235 | - if (doneany) | |
| 1236 | - /* Kill the last space. */ | |
| 1237 | - --o; | |
| 1238 | ||
| 1239 | - return o; | |
| 1240 | + return ret - vbuffer_unwrite (o, !!ret); | |
| 1241 | } | |
| 1242 | ||
| 1243 | -/* Store into VARIABLE_BUFFER at O the result of scanning TEXT | |
| 1244 | +/* Store into VBUFFER at O the result of scanning TEXT | |
| 1245 | and replacing strings matching PATTERN with REPLACE. | |
| 1246 | If PATTERN_PERCENT is not nil, PATTERN has already been | |
| 1247 | run through find_percent, and PATTERN_PERCENT is the result. | |
| 1248 | @@ -243,8 +245,9 @@ | |
| 1249 | character _AFTER_ the %, not to the % itself. | |
| 1250 | */ | |
| 1251 | ||
| 1252 | -char * | |
| 1253 | -patsubst_expand (char *o, const char *text, char *pattern, char *replace) | |
| 1254 | +size_t | |
| 1255 | +patsubst_expand (struct vbuffer *o, const char *text, char *pattern, | |
| 1256 | + char *replace) | |
| 1257 | {
| |
| 1258 | const char *pattern_percent = find_percent (pattern); | |
| 1259 | const char *replace_percent = find_percent (replace); | |
| 1260 | @@ -256,28 +259,7 @@ | |
| 1261 | ++pattern_percent; | |
| 1262 | ||
| 1263 | return patsubst_expand_pat (o, text, pattern, replace, | |
| 1264 | - pattern_percent, replace_percent); | |
| 1265 | -} | |
| 1266 | - | |
| 1267 | - | |
| 1268 | -/* Look up a function by name. */ | |
| 1269 | - | |
| 1270 | -static const struct function_table_entry * | |
| 1271 | -lookup_function (const char *s) | |
| 1272 | -{
| |
| 1273 | - const char *e = s; | |
| 1274 | - | |
| 1275 | - while (*e && ( (*e >= 'a' && *e <= 'z') || *e == '-')) | |
| 1276 | - e++; | |
| 1277 | - if (*e == '\0' || isblank ((unsigned char) *e)) | |
| 1278 | - {
| |
| 1279 | - struct function_table_entry function_table_entry_key; | |
| 1280 | - function_table_entry_key.name = s; | |
| 1281 | - function_table_entry_key.len = e - s; | |
| 1282 | - | |
| 1283 | - return hash_find_item (&function_table, &function_table_entry_key); | |
| 1284 | - } | |
| 1285 | - return 0; | |
| 1286 | + pattern_percent, replace_percent); | |
| 1287 | } | |
| 1288 | ||
| 1289 | ||
| 1290 | @@ -310,48 +292,16 @@ | |
| 1291 | } | |
| 1292 | ||
| 1293 | ||
| 1294 | -/* Find the next comma or ENDPAREN (counting nested STARTPAREN and | |
| 1295 | - ENDPARENtheses), starting at PTR before END. Return a pointer to | |
| 1296 | - next character. | |
| 1297 | - | |
| 1298 | - If no next argument is found, return NULL. | |
| 1299 | -*/ | |
| 1300 | - | |
| 1301 | -static char * | |
| 1302 | -find_next_argument (char startparen, char endparen, | |
| 1303 | - const char *ptr, const char *end) | |
| 1304 | -{
| |
| 1305 | - int count = 0; | |
| 1306 | - | |
| 1307 | - for (; ptr < end; ++ptr) | |
| 1308 | - if (*ptr == startparen) | |
| 1309 | - ++count; | |
| 1310 | - | |
| 1311 | - else if (*ptr == endparen) | |
| 1312 | - {
| |
| 1313 | - --count; | |
| 1314 | - if (count < 0) | |
| 1315 | - return NULL; | |
| 1316 | - } | |
| 1317 | - | |
| 1318 | - else if (*ptr == ',' && !count) | |
| 1319 | - return (char *)ptr; | |
| 1320 | - | |
| 1321 | - /* We didn't find anything. */ | |
| 1322 | - return NULL; | |
| 1323 | -} | |
| 1324 | - | |
| 1325 | - | |
| 1326 | -/* Glob-expand LINE. The returned pointer is | |
| 1327 | - only good until the next call to string_glob. */ | |
| 1328 | +/* Glob-expand the LINE writing the result into O. */ | |
| 1329 | ||
| 1330 | -static char * | |
| 1331 | -string_glob (char *line) | |
| 1332 | +#ifdef __GNUC__ | |
| 1333 | +__inline | |
| 1334 | +#endif | |
| 1335 | +static size_t | |
| 1336 | +string_glob (struct vbuffer *o, char *line) | |
| 1337 | {
| |
| 1338 | - static char *result = 0; | |
| 1339 | - static unsigned int length; | |
| 1340 | + size_t ret = 0; | |
| 1341 | struct nameseq *chain; | |
| 1342 | - unsigned int idx; | |
| 1343 | ||
| 1344 | chain = PARSE_FILE_SEQ (&line, struct nameseq, '\0', NULL, | |
| 1345 | /* We do not want parse_file_seq to strip './'s. | |
| 1346 | @@ -359,58 +309,53 @@ | |
| 1347 | $(patsubst ./%.c,obj/%.o,$(wildcard ./?*.c)). */ | |
| 1348 | PARSEFS_NOSTRIP|PARSEFS_NOCACHE|PARSEFS_EXISTS); | |
| 1349 | ||
| 1350 | - if (result == 0) | |
| 1351 | - {
| |
| 1352 | - length = 100; | |
| 1353 | - result = xmalloc (100); | |
| 1354 | - } | |
| 1355 | - | |
| 1356 | - idx = 0; | |
| 1357 | while (chain != 0) | |
| 1358 | {
| |
| 1359 | struct nameseq *next = chain->next; | |
| 1360 | - unsigned int len = strlen (chain->name); | |
| 1361 | ||
| 1362 | - if (idx + len + 1 > length) | |
| 1363 | - {
| |
| 1364 | - length += (len + 1) * 2; | |
| 1365 | - result = xrealloc (result, length); | |
| 1366 | - } | |
| 1367 | - memcpy (&result[idx], chain->name, len); | |
| 1368 | - idx += len; | |
| 1369 | - result[idx++] = ' '; | |
| 1370 | + ret += vbuffer_write (o, chain->name, -1); | |
| 1371 | + ret += vbuffer_write (o, " ", 1); | |
| 1372 | ||
| 1373 | /* Because we used PARSEFS_NOCACHE above, we have to free() NAME. */ | |
| 1374 | free ((char *)chain->name); | |
| 1375 | free (chain); | |
| 1376 | + | |
| 1377 | chain = next; | |
| 1378 | } | |
| 1379 | ||
| 1380 | - /* Kill the last space and terminate the string. */ | |
| 1381 | - if (idx == 0) | |
| 1382 | - result[0] = '\0'; | |
| 1383 | - else | |
| 1384 | - result[idx - 1] = '\0'; | |
| 1385 | + return ret - vbuffer_unwrite (o, !!ret); | |
| 1386 | +} | |
| 1387 | ||
| 1388 | - return result; | |
| 1389 | +static size_t | |
| 1390 | +func_wildcard (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 1391 | +{
| |
| 1392 | + size_t ret = 0; | |
| 1393 | + | |
| 1394 | +#ifdef _AMIGA | |
| 1395 | + o = wildcard_expansion (argv[0], o); | |
| 1396 | +#else | |
| 1397 | + ret += string_glob (o, argv[0]); | |
| 1398 | +#endif | |
| 1399 | + | |
| 1400 | + return ret; | |
| 1401 | } | |
| 1402 | + | |
| 1403 | ||
| 1404 | /* | |
| 1405 | Builtin functions | |
| 1406 | */ | |
| 1407 | ||
| 1408 | -static char * | |
| 1409 | -func_patsubst (char *o, char **argv, const char *funcname UNUSED) | |
| 1410 | +static size_t | |
| 1411 | +func_patsubst (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 1412 | {
| |
| 1413 | - o = patsubst_expand (o, argv[2], argv[0], argv[1]); | |
| 1414 | - return o; | |
| 1415 | + return patsubst_expand (o, argv[2], argv[0], argv[1]); | |
| 1416 | } | |
| 1417 | ||
| 1418 | ||
| 1419 | -static char * | |
| 1420 | -func_join (char *o, char **argv, const char *funcname UNUSED) | |
| 1421 | +static size_t | |
| 1422 | +func_join (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 1423 | {
| |
| 1424 | - int doneany = 0; | |
| 1425 | + size_t ret = 0; | |
| 1426 | ||
| 1427 | /* Write each word of the first argument directly followed | |
| 1428 | by the corresponding word of the second argument. | |
| 1429 | @@ -420,87 +365,84 @@ | |
| 1430 | const char *pp; | |
| 1431 | const char *list1_iterator = argv[0]; | |
| 1432 | const char *list2_iterator = argv[1]; | |
| 1433 | + | |
| 1434 | do | |
| 1435 | {
| |
| 1436 | unsigned int len1, len2; | |
| 1437 | ||
| 1438 | tp = find_next_token (&list1_iterator, &len1); | |
| 1439 | if (tp != 0) | |
| 1440 | - o = variable_buffer_output (o, tp, len1); | |
| 1441 | + ret += vbuffer_write (o, tp, len1); | |
| 1442 | ||
| 1443 | pp = find_next_token (&list2_iterator, &len2); | |
| 1444 | if (pp != 0) | |
| 1445 | - o = variable_buffer_output (o, pp, len2); | |
| 1446 | + ret += vbuffer_write (o, pp, len2); | |
| 1447 | ||
| 1448 | if (tp != 0 || pp != 0) | |
| 1449 | - {
| |
| 1450 | - o = variable_buffer_output (o, " ", 1); | |
| 1451 | - doneany = 1; | |
| 1452 | - } | |
| 1453 | + ret += vbuffer_write (o, " ", 1); | |
| 1454 | } | |
| 1455 | while (tp != 0 || pp != 0); | |
| 1456 | - if (doneany) | |
| 1457 | - /* Kill the last blank. */ | |
| 1458 | - --o; | |
| 1459 | ||
| 1460 | - return o; | |
| 1461 | + return ret - vbuffer_unwrite (o, !!ret); | |
| 1462 | } | |
| 1463 | ||
| 1464 | ||
| 1465 | -static char * | |
| 1466 | -func_origin (char *o, char **argv, const char *funcname UNUSED) | |
| 1467 | +static size_t | |
| 1468 | +func_origin (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 1469 | {
| |
| 1470 | - /* Expand the argument. */ | |
| 1471 | + size_t ret = 0; | |
| 1472 | struct variable *v = lookup_variable (argv[0], strlen (argv[0])); | |
| 1473 | + | |
| 1474 | if (v == 0) | |
| 1475 | - o = variable_buffer_output (o, "undefined", 9); | |
| 1476 | + ret += vbuffer_write (o, STRING_SIZE_TUPLE("undefined"));
| |
| 1477 | else | |
| 1478 | switch (v->origin) | |
| 1479 | {
| |
| 1480 | - default: | |
| 1481 | - case o_invalid: | |
| 1482 | - abort (); | |
| 1483 | - break; | |
| 1484 | case o_default: | |
| 1485 | - o = variable_buffer_output (o, "default", 7); | |
| 1486 | + ret += vbuffer_write (o, STRING_SIZE_TUPLE("default"));
| |
| 1487 | break; | |
| 1488 | case o_env: | |
| 1489 | - o = variable_buffer_output (o, "environment", 11); | |
| 1490 | + ret += vbuffer_write (o, STRING_SIZE_TUPLE("environment"));
| |
| 1491 | break; | |
| 1492 | case o_file: | |
| 1493 | - o = variable_buffer_output (o, "file", 4); | |
| 1494 | + ret += vbuffer_write (o, STRING_SIZE_TUPLE("file"));
| |
| 1495 | break; | |
| 1496 | case o_env_override: | |
| 1497 | - o = variable_buffer_output (o, "environment override", 20); | |
| 1498 | + ret += vbuffer_write (o, STRING_SIZE_TUPLE("environment override"));
| |
| 1499 | break; | |
| 1500 | case o_command: | |
| 1501 | - o = variable_buffer_output (o, "command line", 12); | |
| 1502 | + ret += vbuffer_write (o, STRING_SIZE_TUPLE("command line"));
| |
| 1503 | break; | |
| 1504 | case o_override: | |
| 1505 | - o = variable_buffer_output (o, "override", 8); | |
| 1506 | + ret += vbuffer_write (o, STRING_SIZE_TUPLE("override"));
| |
| 1507 | break; | |
| 1508 | case o_automatic: | |
| 1509 | - o = variable_buffer_output (o, "automatic", 9); | |
| 1510 | + ret += vbuffer_write (o, STRING_SIZE_TUPLE("automatic"));
| |
| 1511 | + break; | |
| 1512 | + case o_invalid: | |
| 1513 | + default: | |
| 1514 | + abort (); | |
| 1515 | break; | |
| 1516 | } | |
| 1517 | ||
| 1518 | - return o; | |
| 1519 | + return ret; | |
| 1520 | } | |
| 1521 | ||
| 1522 | -static char * | |
| 1523 | -func_flavor (char *o, char **argv, const char *funcname UNUSED) | |
| 1524 | +static size_t | |
| 1525 | +func_flavor (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 1526 | {
| |
| 1527 | + size_t ret = 0; | |
| 1528 | struct variable *v = lookup_variable (argv[0], strlen (argv[0])); | |
| 1529 | ||
| 1530 | if (v == 0) | |
| 1531 | - o = variable_buffer_output (o, "undefined", 9); | |
| 1532 | + ret += vbuffer_write (o, STRING_SIZE_TUPLE("undefined"));
| |
| 1533 | else | |
| 1534 | if (v->recursive) | |
| 1535 | - o = variable_buffer_output (o, "recursive", 9); | |
| 1536 | + ret += vbuffer_write (o, STRING_SIZE_TUPLE("recursive"));
| |
| 1537 | else | |
| 1538 | - o = variable_buffer_output (o, "simple", 6); | |
| 1539 | + ret += vbuffer_write (o, STRING_SIZE_TUPLE("simple"));
| |
| 1540 | ||
| 1541 | - return o; | |
| 1542 | + return ret; | |
| 1543 | } | |
| 1544 | ||
| 1545 | #ifdef VMS | |
| 1546 | @@ -514,14 +456,15 @@ | |
| 1547 | #endif | |
| 1548 | ||
| 1549 | ||
| 1550 | -static char * | |
| 1551 | -func_notdir_suffix (char *o, char **argv, const char *funcname) | |
| 1552 | +static size_t | |
| 1553 | +func_notdir_suffix (struct vbuffer *o, char **argv, const char *funcname) | |
| 1554 | {
| |
| 1555 | + size_t ret = 0; | |
| 1556 | + | |
| 1557 | /* Expand the argument. */ | |
| 1558 | const char *list_iterator = argv[0]; | |
| 1559 | const char *p2; | |
| 1560 | - int doneany =0; | |
| 1561 | - unsigned int len=0; | |
| 1562 | + unsigned int len = 0; | |
| 1563 | ||
| 1564 | int is_suffix = funcname[0] == 's'; | |
| 1565 | int is_notdir = !is_suffix; | |
| 1566 | @@ -529,7 +472,6 @@ | |
| 1567 | {
| |
| 1568 | const char *p = p2 + len; | |
| 1569 | ||
| 1570 | - | |
| 1571 | while (p >= p2 && (!is_suffix || *p != '.')) | |
| 1572 | {
| |
| 1573 | if (IS_PATHSEP (*p)) | |
| 1574 | @@ -543,41 +485,35 @@ | |
| 1575 | ++p; | |
| 1576 | else if (*p != '.') | |
| 1577 | continue; | |
| 1578 | - o = variable_buffer_output (o, p, len - (p - p2)); | |
| 1579 | + ret += vbuffer_write (o, p, len - (p - p2)); | |
| 1580 | } | |
| 1581 | #ifdef HAVE_DOS_PATHS | |
| 1582 | /* Handle the case of "d:foo/bar". */ | |
| 1583 | else if (is_notdir && p2[0] && p2[1] == ':') | |
| 1584 | {
| |
| 1585 | p = p2 + 2; | |
| 1586 | - o = variable_buffer_output (o, p, len - (p - p2)); | |
| 1587 | + ret += vbuffer_write (o, p, len - (p - p2)); | |
| 1588 | } | |
| 1589 | #endif | |
| 1590 | else if (is_notdir) | |
| 1591 | - o = variable_buffer_output (o, p2, len); | |
| 1592 | + ret += vbuffer_write (o, p2, len); | |
| 1593 | ||
| 1594 | if (is_notdir || p >= p2) | |
| 1595 | - {
| |
| 1596 | - o = variable_buffer_output (o, " ", 1); | |
| 1597 | - doneany = 1; | |
| 1598 | - } | |
| 1599 | + ret += vbuffer_write (o, " ", 1); | |
| 1600 | } | |
| 1601 | ||
| 1602 | - if (doneany) | |
| 1603 | - /* Kill last space. */ | |
| 1604 | - --o; | |
| 1605 | - | |
| 1606 | - return o; | |
| 1607 | + return ret - vbuffer_unwrite (o, !!ret); | |
| 1608 | } | |
| 1609 | ||
| 1610 | ||
| 1611 | -static char * | |
| 1612 | -func_basename_dir (char *o, char **argv, const char *funcname) | |
| 1613 | +static size_t | |
| 1614 | +func_basename_dir (struct vbuffer *o, char **argv, const char *funcname) | |
| 1615 | {
| |
| 1616 | + size_t ret = 0; | |
| 1617 | + | |
| 1618 | /* Expand the argument. */ | |
| 1619 | const char *p3 = argv[0]; | |
| 1620 | const char *p2; | |
| 1621 | - int doneany = 0; | |
| 1622 | unsigned int len = 0; | |
| 1623 | ||
| 1624 | int is_basename = funcname[0] == 'b'; | |
| 1625 | @@ -594,111 +530,105 @@ | |
| 1626 | } | |
| 1627 | ||
| 1628 | if (p >= p2 && (is_dir)) | |
| 1629 | - o = variable_buffer_output (o, p2, ++p - p2); | |
| 1630 | + ret += vbuffer_write (o, p2, ++p - p2); | |
| 1631 | else if (p >= p2 && (*p == '.')) | |
| 1632 | - o = variable_buffer_output (o, p2, p - p2); | |
| 1633 | + ret += vbuffer_write (o, p2, p - p2); | |
| 1634 | #ifdef HAVE_DOS_PATHS | |
| 1635 | /* Handle the "d:foobar" case */ | |
| 1636 | else if (p2[0] && p2[1] == ':' && is_dir) | |
| 1637 | - o = variable_buffer_output (o, p2, 2); | |
| 1638 | + ret += vbuffer_write (o, p2, 2); | |
| 1639 | #endif | |
| 1640 | else if (is_dir) | |
| 1641 | #ifdef VMS | |
| 1642 | - o = variable_buffer_output (o, "[]", 2); | |
| 1643 | + ret += vbuffer_write (o, "[]", 2); | |
| 1644 | #else | |
| 1645 | #ifndef _AMIGA | |
| 1646 | - o = variable_buffer_output (o, "./", 2); | |
| 1647 | + ret += vbuffer_write (o, "./", 2); | |
| 1648 | #else | |
| 1649 | ; /* Just a nop... */ | |
| 1650 | #endif /* AMIGA */ | |
| 1651 | #endif /* !VMS */ | |
| 1652 | else | |
| 1653 | /* The entire name is the basename. */ | |
| 1654 | - o = variable_buffer_output (o, p2, len); | |
| 1655 | + ret += vbuffer_write (o, p2, len); | |
| 1656 | ||
| 1657 | - o = variable_buffer_output (o, " ", 1); | |
| 1658 | - doneany = 1; | |
| 1659 | + ret += vbuffer_write (o, " ", 1); | |
| 1660 | } | |
| 1661 | ||
| 1662 | - if (doneany) | |
| 1663 | - /* Kill last space. */ | |
| 1664 | - --o; | |
| 1665 | - | |
| 1666 | - return o; | |
| 1667 | + return ret - vbuffer_unwrite (o, !!ret); | |
| 1668 | } | |
| 1669 | ||
| 1670 | -static char * | |
| 1671 | -func_addsuffix_addprefix (char *o, char **argv, const char *funcname) | |
| 1672 | +static size_t | |
| 1673 | +func_addsuffix_addprefix (struct vbuffer *o, char **argv, const char *funcname) | |
| 1674 | {
| |
| 1675 | + size_t ret = 0; | |
| 1676 | + | |
| 1677 | int fixlen = strlen (argv[0]); | |
| 1678 | const char *list_iterator = argv[1]; | |
| 1679 | - int is_addprefix = funcname[3] == 'p'; | |
| 1680 | + int is_addprefix = funcname[CSTRLEN("add")] == 'p';
| |
| 1681 | int is_addsuffix = !is_addprefix; | |
| 1682 | ||
| 1683 | - int doneany = 0; | |
| 1684 | const char *p; | |
| 1685 | unsigned int len; | |
| 1686 | ||
| 1687 | while ((p = find_next_token (&list_iterator, &len)) != 0) | |
| 1688 | {
| |
| 1689 | if (is_addprefix) | |
| 1690 | - o = variable_buffer_output (o, argv[0], fixlen); | |
| 1691 | - o = variable_buffer_output (o, p, len); | |
| 1692 | + ret += vbuffer_write (o, argv[0], fixlen); | |
| 1693 | + ret += vbuffer_write (o, p, len); | |
| 1694 | if (is_addsuffix) | |
| 1695 | - o = variable_buffer_output (o, argv[0], fixlen); | |
| 1696 | - o = variable_buffer_output (o, " ", 1); | |
| 1697 | - doneany = 1; | |
| 1698 | + ret += vbuffer_write (o, argv[0], fixlen); | |
| 1699 | + ret += vbuffer_write (o, " ", 1); | |
| 1700 | } | |
| 1701 | ||
| 1702 | - if (doneany) | |
| 1703 | - /* Kill last space. */ | |
| 1704 | - --o; | |
| 1705 | - | |
| 1706 | - return o; | |
| 1707 | + return ret - vbuffer_unwrite (o, !!ret); | |
| 1708 | } | |
| 1709 | ||
| 1710 | -static char * | |
| 1711 | -func_subst (char *o, char **argv, const char *funcname UNUSED) | |
| 1712 | -{
| |
| 1713 | - o = subst_expand (o, argv[2], argv[0], argv[1], strlen (argv[0]), | |
| 1714 | - strlen (argv[1]), 0); | |
| 1715 | ||
| 1716 | - return o; | |
| 1717 | +static size_t | |
| 1718 | +func_subst (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 1719 | +{
| |
| 1720 | + return subst_expand (o, argv[2], argv[0], argv[1], strlen (argv[0]), | |
| 1721 | + strlen (argv[1]), 0); | |
| 1722 | } | |
| 1723 | ||
| 1724 | ||
| 1725 | -static char * | |
| 1726 | -func_firstword (char *o, char **argv, const char *funcname UNUSED) | |
| 1727 | +static size_t | |
| 1728 | +func_firstword (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 1729 | {
| |
| 1730 | - unsigned int i; | |
| 1731 | + size_t ret = 0; | |
| 1732 | + | |
| 1733 | + unsigned int len; | |
| 1734 | const char *words = argv[0]; /* Use a temp variable for find_next_token */ | |
| 1735 | - const char *p = find_next_token (&words, &i); | |
| 1736 | + const char *p = find_next_token (&words, &len); | |
| 1737 | ||
| 1738 | if (p != 0) | |
| 1739 | - o = variable_buffer_output (o, p, i); | |
| 1740 | + ret += vbuffer_write (o, p, len); | |
| 1741 | ||
| 1742 | - return o; | |
| 1743 | + return ret; | |
| 1744 | } | |
| 1745 | ||
| 1746 | -static char * | |
| 1747 | -func_lastword (char *o, char **argv, const char *funcname UNUSED) | |
| 1748 | +static size_t | |
| 1749 | +func_lastword (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 1750 | {
| |
| 1751 | - unsigned int i; | |
| 1752 | + size_t ret = 0; | |
| 1753 | + | |
| 1754 | + unsigned int len; | |
| 1755 | const char *words = argv[0]; /* Use a temp variable for find_next_token */ | |
| 1756 | const char *p = NULL; | |
| 1757 | const char *t; | |
| 1758 | ||
| 1759 | - while ((t = find_next_token (&words, &i))) | |
| 1760 | + while ((t = find_next_token (&words, &len))) | |
| 1761 | p = t; | |
| 1762 | ||
| 1763 | if (p != 0) | |
| 1764 | - o = variable_buffer_output (o, p, i); | |
| 1765 | + ret += vbuffer_write (o, p, len); | |
| 1766 | ||
| 1767 | - return o; | |
| 1768 | + return ret; | |
| 1769 | } | |
| 1770 | ||
| 1771 | -static char * | |
| 1772 | -func_words (char *o, char **argv, const char *funcname UNUSED) | |
| 1773 | +static size_t | |
| 1774 | +func_words (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 1775 | {
| |
| 1776 | int i = 0; | |
| 1777 | const char *word_iterator = argv[0]; | |
| 1778 | @@ -708,9 +638,8 @@ | |
| 1779 | ++i; | |
| 1780 | ||
| 1781 | sprintf (buf, "%d", i); | |
| 1782 | - o = variable_buffer_output (o, buf, strlen (buf)); | |
| 1783 | ||
| 1784 | - return o; | |
| 1785 | + return vbuffer_write (o, buf, -1); | |
| 1786 | } | |
| 1787 | ||
| 1788 | /* Set begpp to point to the first non-whitespace character of the string, | |
| 1789 | @@ -744,10 +673,11 @@ | |
| 1790 | } | |
| 1791 | ||
| 1792 | ||
| 1793 | - | |
| 1794 | -static char * | |
| 1795 | -func_word (char *o, char **argv, const char *funcname UNUSED) | |
| 1796 | +static size_t | |
| 1797 | +func_word (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 1798 | {
| |
| 1799 | + size_t ret = 0; | |
| 1800 | + | |
| 1801 | const char *end_p; | |
| 1802 | const char *p; | |
| 1803 | int i; | |
| 1804 | @@ -766,14 +696,17 @@ | |
| 1805 | break; | |
| 1806 | ||
| 1807 | if (i == 0) | |
| 1808 | - o = variable_buffer_output (o, p, end_p - p); | |
| 1809 | + ret += vbuffer_write (o, p, end_p - p); | |
| 1810 | ||
| 1811 | - return o; | |
| 1812 | + return ret; | |
| 1813 | } | |
| 1814 | ||
| 1815 | -static char * | |
| 1816 | -func_wordlist (char *o, char **argv, const char *funcname UNUSED) | |
| 1817 | + | |
| 1818 | +static size_t | |
| 1819 | +func_wordlist (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 1820 | {
| |
| 1821 | + size_t ret = 0; | |
| 1822 | + | |
| 1823 | int start, count; | |
| 1824 | ||
| 1825 | /* Check the arguments. */ | |
| 1826 | @@ -805,67 +738,102 @@ | |
| 1827 | ; | |
| 1828 | ||
| 1829 | /* Return the stuff in the middle. */ | |
| 1830 | - o = variable_buffer_output (o, p, end_p - p); | |
| 1831 | + ret += vbuffer_write (o, p, end_p - p); | |
| 1832 | } | |
| 1833 | } | |
| 1834 | ||
| 1835 | - return o; | |
| 1836 | + return ret; | |
| 1837 | } | |
| 1838 | ||
| 1839 | -static char * | |
| 1840 | -func_findstring (char *o, char **argv, const char *funcname UNUSED) | |
| 1841 | +static size_t | |
| 1842 | +func_findstring (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 1843 | {
| |
| 1844 | + size_t ret = 0; | |
| 1845 | + | |
| 1846 | /* Find the first occurrence of the first string in the second. */ | |
| 1847 | if (strstr (argv[1], argv[0]) != 0) | |
| 1848 | - o = variable_buffer_output (o, argv[0], strlen (argv[0])); | |
| 1849 | + ret += vbuffer_write (o, argv[0], -1); | |
| 1850 | ||
| 1851 | - return o; | |
| 1852 | + return ret; | |
| 1853 | } | |
| 1854 | ||
| 1855 | -static char * | |
| 1856 | -func_foreach (char *o, char **argv, const char *funcname UNUSED) | |
| 1857 | +static size_t | |
| 1858 | +func_foreach (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 1859 | {
| |
| 1860 | - /* expand only the first two. */ | |
| 1861 | - char *varname = expand_argument (argv[0], NULL); | |
| 1862 | - char *list = expand_argument (argv[1], NULL); | |
| 1863 | - const char *body = argv[2]; | |
| 1864 | + size_t ret = 0; | |
| 1865 | ||
| 1866 | - int doneany = 0; | |
| 1867 | - const char *list_iterator = list; | |
| 1868 | - const char *p; | |
| 1869 | + char *p; | |
| 1870 | unsigned int len; | |
| 1871 | - struct variable *var; | |
| 1872 | + char *varname; | |
| 1873 | + char *list; | |
| 1874 | + char *body; | |
| 1875 | + size_t varname_len; | |
| 1876 | + size_t list_len; | |
| 1877 | + size_t body_len = strlen (argv[2]); | |
| 1878 | + struct vbuffer argbuf; | |
| 1879 | ||
| 1880 | - push_new_variable_scope (); | |
| 1881 | - var = define_variable (varname, strlen (varname), "", o_automatic, 0); | |
| 1882 | + /* Expand the list and the variable name into a dedicated vbuffer. */ | |
| 1883 | ||
| 1884 | - /* loop through LIST, put the value in VAR and expand BODY */ | |
| 1885 | - while ((p = find_next_token (&list_iterator, &len)) != 0) | |
| 1886 | + vbuffer_init (&argbuf); | |
| 1887 | + | |
| 1888 | + list_len = vbuffer_expand (&argbuf, argv[1], -1); | |
| 1889 | + *(++argbuf.ptr) = '\0'; | |
| 1890 | + /* Add an extra nil to iterate over the list more efficiently. */ | |
| 1891 | + *(++argbuf.ptr) = '\0'; | |
| 1892 | + | |
| 1893 | + varname_len = vbuffer_expand (&argbuf, argv[0], -1); | |
| 1894 | + *(++argbuf.ptr) = '\0'; | |
| 1895 | + | |
| 1896 | + /* Also get a room for an unexpanded body. */ | |
| 1897 | + | |
| 1898 | + vbuffer_reserve (&argbuf, body_len + 1); | |
| 1899 | + | |
| 1900 | + list = argbuf.buffer; | |
| 1901 | + varname = list + list_len + 2; | |
| 1902 | + body = varname + varname_len + 1; | |
| 1903 | + body[body_len] = ' '; | |
| 1904 | + | |
| 1905 | + if ((p = find_next_token ((const char **) &list, &len)) != 0) | |
| 1906 | {
| |
| 1907 | - char *result = 0; | |
| 1908 | + struct variable var; | |
| 1909 | + struct variable *saved_var; | |
| 1910 | + char **argp; | |
| 1911 | + char *saved_arg = NULL; | |
| 1912 | ||
| 1913 | - free (var->value); | |
| 1914 | - var->value = xstrndup (p, len); | |
| 1915 | + argp = lookup_call_argument_value (varname, varname_len); | |
| 1916 | + if (argp && *argp) | |
| 1917 | + {
| |
| 1918 | + /* Variable name is a numeric value and there is a call argument | |
| 1919 | + that would hide a pushed variable. | |
| 1920 | + Make a "hole" in the current call frame so that the new variable | |
| 1921 | + becomes visible. */ | |
| 1922 | + saved_arg = *argp; | |
| 1923 | + *argp = NULL; | |
| 1924 | + } | |
| 1925 | + saved_var = push_scoped_variable (&var, varname, varname_len); | |
| 1926 | ||
| 1927 | - result = allocated_variable_expand (body); | |
| 1928 | + /* loop through LIST, put the value in VAR and expand BODY */ | |
| 1929 | + do | |
| 1930 | + {
| |
| 1931 | + p[len] = '\0'; | |
| 1932 | + var.value = p; | |
| 1933 | + ret += vbuffer_expand (o, memcpy (body, argv[2], body_len), | |
| 1934 | + body_len + 1); | |
| 1935 | + ++list; | |
| 1936 | + } | |
| 1937 | + while ((p = find_next_token ((const char **) &list, &len)) != 0); | |
| 1938 | ||
| 1939 | - o = variable_buffer_output (o, result, strlen (result)); | |
| 1940 | - o = variable_buffer_output (o, " ", 1); | |
| 1941 | - doneany = 1; | |
| 1942 | - free (result); | |
| 1943 | + pop_scoped_variable (&var, saved_var); | |
| 1944 | + if (saved_arg) | |
| 1945 | + *argp = saved_arg; | |
| 1946 | } | |
| 1947 | ||
| 1948 | - if (doneany) | |
| 1949 | - /* Kill the last space. */ | |
| 1950 | - --o; | |
| 1951 | - | |
| 1952 | - pop_variable_scope (); | |
| 1953 | - free (varname); | |
| 1954 | - free (list); | |
| 1955 | + vbuffer_free (&argbuf); | |
| 1956 | ||
| 1957 | - return o; | |
| 1958 | + return ret - vbuffer_unwrite (o, !!ret); | |
| 1959 | } | |
| 1960 | ||
| 1961 | + | |
| 1962 | struct a_word | |
| 1963 | {
| |
| 1964 | struct a_word *next; | |
| 1965 | @@ -905,9 +873,11 @@ | |
| 1966 | int length; | |
| 1967 | }; | |
| 1968 | ||
| 1969 | -static char * | |
| 1970 | -func_filter_filterout (char *o, char **argv, const char *funcname) | |
| 1971 | +static size_t | |
| 1972 | +func_filter_filterout (struct vbuffer *o, char **argv, const char *funcname) | |
| 1973 | {
| |
| 1974 | + size_t ret = 0; | |
| 1975 | + | |
| 1976 | struct a_word *wordhead; | |
| 1977 | struct a_word **wordtail; | |
| 1978 | struct a_word *wp; | |
| 1979 | @@ -989,8 +959,6 @@ | |
| 1980 | ||
| 1981 | if (words) | |
| 1982 | {
| |
| 1983 | - int doneany = 0; | |
| 1984 | - | |
| 1985 | /* Run each pattern through the words, killing words. */ | |
| 1986 | for (pp = pathead; pp != 0; pp = pp->next) | |
| 1987 | {
| |
| 1988 | @@ -1019,58 +987,42 @@ | |
| 1989 | for (wp = wordhead; wp != 0; wp = wp->next) | |
| 1990 | if (is_filter ? wp->matched : !wp->matched) | |
| 1991 | {
| |
| 1992 | - o = variable_buffer_output (o, wp->str, strlen (wp->str)); | |
| 1993 | - o = variable_buffer_output (o, " ", 1); | |
| 1994 | - doneany = 1; | |
| 1995 | + ret += vbuffer_write (o, wp->str, -1); | |
| 1996 | + ret += vbuffer_write (o, " ", 1); | |
| 1997 | } | |
| 1998 | ||
| 1999 | - if (doneany) | |
| 2000 | - /* Kill the last space. */ | |
| 2001 | - --o; | |
| 2002 | } | |
| 2003 | ||
| 2004 | if (hashing) | |
| 2005 | hash_free (&a_word_table, 0); | |
| 2006 | ||
| 2007 | - return o; | |
| 2008 | + return ret - vbuffer_unwrite (o, !!ret); | |
| 2009 | } | |
| 2010 | ||
| 2011 | ||
| 2012 | -static char * | |
| 2013 | -func_strip (char *o, char **argv, const char *funcname UNUSED) | |
| 2014 | +static size_t | |
| 2015 | +func_strip (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 2016 | {
| |
| 2017 | - const char *p = argv[0]; | |
| 2018 | - int doneany = 0; | |
| 2019 | + size_t result = 0; | |
| 2020 | ||
| 2021 | - while (*p != '\0') | |
| 2022 | - {
| |
| 2023 | - int i=0; | |
| 2024 | - const char *word_start; | |
| 2025 | + unsigned int len; | |
| 2026 | + const char *words = argv[0]; /* Use a temp variable for find_next_token */ | |
| 2027 | + const char *p; | |
| 2028 | ||
| 2029 | - while (isspace ((unsigned char)*p)) | |
| 2030 | - ++p; | |
| 2031 | - word_start = p; | |
| 2032 | - for (i=0; *p != '\0' && !isspace ((unsigned char)*p); ++p, ++i) | |
| 2033 | - {}
| |
| 2034 | - if (!i) | |
| 2035 | - break; | |
| 2036 | - o = variable_buffer_output (o, word_start, i); | |
| 2037 | - o = variable_buffer_output (o, " ", 1); | |
| 2038 | - doneany = 1; | |
| 2039 | + while ((p = find_next_token (&words, &len)) != 0) | |
| 2040 | + {
| |
| 2041 | + result += vbuffer_write (o, p, len + 1); | |
| 2042 | + o->ptr[-1] = ' '; | |
| 2043 | } | |
| 2044 | ||
| 2045 | - if (doneany) | |
| 2046 | - /* Kill the last space. */ | |
| 2047 | - --o; | |
| 2048 | - | |
| 2049 | - return o; | |
| 2050 | + return result - vbuffer_unwrite (o, !!result); | |
| 2051 | } | |
| 2052 | ||
| 2053 | /* | |
| 2054 | Print a warning or fatal message. | |
| 2055 | */ | |
| 2056 | -static char * | |
| 2057 | -func_error (char *o, char **argv, const char *funcname) | |
| 2058 | +size_t | |
| 2059 | +func_error (struct vbuffer *o UNUSED, char **argv, const char *funcname) | |
| 2060 | {
| |
| 2061 | char **argvp; | |
| 2062 | char *msg, *p; | |
| 2063 | @@ -1111,16 +1063,18 @@ | |
| 2064 | } | |
| 2065 | ||
| 2066 | /* The warning function expands to the empty string. */ | |
| 2067 | - return o; | |
| 2068 | + return 0; | |
| 2069 | } | |
| 2070 | ||
| 2071 | ||
| 2072 | /* | |
| 2073 | chop argv[0] into words, and sort them. | |
| 2074 | */ | |
| 2075 | -static char * | |
| 2076 | -func_sort (char *o, char **argv, const char *funcname UNUSED) | |
| 2077 | +static size_t | |
| 2078 | +func_sort (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 2079 | {
| |
| 2080 | + size_t result = 0; | |
| 2081 | + | |
| 2082 | const char *t; | |
| 2083 | char **words; | |
| 2084 | int wordi; | |
| 2085 | @@ -1133,7 +1087,8 @@ | |
| 2086 | wordi = 0; | |
| 2087 | while ((p = find_next_token (&t, NULL)) != 0) | |
| 2088 | {
| |
| 2089 | - ++t; | |
| 2090 | + if (*t != '\0') | |
| 2091 | + ++t; | |
| 2092 | ++wordi; | |
| 2093 | } | |
| 2094 | ||
| 2095 | @@ -1144,7 +1099,8 @@ | |
| 2096 | wordi = 0; | |
| 2097 | while ((p = find_next_token (&t, &len)) != 0) | |
| 2098 | {
| |
| 2099 | - ++t; | |
| 2100 | + if (*t != '\0') | |
| 2101 | + ++t; | |
| 2102 | p[len] = '\0'; | |
| 2103 | words[wordi++] = p; | |
| 2104 | } | |
| 2105 | @@ -1161,18 +1117,18 @@ | |
| 2106 | if (i == wordi - 1 || strlen (words[i + 1]) != len | |
| 2107 | || strcmp (words[i], words[i + 1])) | |
| 2108 | {
| |
| 2109 | - o = variable_buffer_output (o, words[i], len); | |
| 2110 | - o = variable_buffer_output (o, " ", 1); | |
| 2111 | + result += vbuffer_write (o, words[i], len); | |
| 2112 | + result += vbuffer_write (o, " ", 1); | |
| 2113 | } | |
| 2114 | } | |
| 2115 | ||
| 2116 | /* Kill the last space. */ | |
| 2117 | - --o; | |
| 2118 | + result -= vbuffer_unwrite (o, 1); | |
| 2119 | } | |
| 2120 | ||
| 2121 | free (words); | |
| 2122 | ||
| 2123 | - return o; | |
| 2124 | + return result; | |
| 2125 | } | |
| 2126 | ||
| 2127 | /* | |
| 2128 | @@ -1187,9 +1143,11 @@ | |
| 2129 | example). | |
| 2130 | */ | |
| 2131 | ||
| 2132 | -static char * | |
| 2133 | -func_if (char *o, char **argv, const char *funcname UNUSED) | |
| 2134 | +static size_t | |
| 2135 | +func_if (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 2136 | {
| |
| 2137 | + size_t ret = 0; | |
| 2138 | + | |
| 2139 | const char *begp = argv[0]; | |
| 2140 | const char *endp = begp + strlen (argv[0]) - 1; | |
| 2141 | int result = 0; | |
| 2142 | @@ -1201,12 +1159,9 @@ | |
| 2143 | strip_whitespace (&begp, &endp); | |
| 2144 | ||
| 2145 | if (begp <= endp) | |
| 2146 | - {
| |
| 2147 | - char *expansion = expand_argument (begp, endp+1); | |
| 2148 | + result = vbuffer_expand (o, (char *) begp, endp+1 - begp); | |
| 2149 | ||
| 2150 | - result = strlen (expansion); | |
| 2151 | - free (expansion); | |
| 2152 | - } | |
| 2153 | + vbuffer_unwrite (o, result); | |
| 2154 | ||
| 2155 | /* If the result is true (1) we want to eval the first argument, and if | |
| 2156 | it's false (0) we want to eval the second. If the argument doesn't | |
| 2157 | @@ -1215,15 +1170,9 @@ | |
| 2158 | argv += 1 + !result; | |
| 2159 | ||
| 2160 | if (*argv) | |
| 2161 | - {
| |
| 2162 | - char *expansion = expand_argument (*argv, NULL); | |
| 2163 | + ret += vbuffer_expand (o, *argv, -1); | |
| 2164 | ||
| 2165 | - o = variable_buffer_output (o, expansion, strlen (expansion)); | |
| 2166 | - | |
| 2167 | - free (expansion); | |
| 2168 | - } | |
| 2169 | - | |
| 2170 | - return o; | |
| 2171 | + return ret; | |
| 2172 | } | |
| 2173 | ||
| 2174 | /* | |
| 2175 | @@ -1240,15 +1189,15 @@ | |
| 2176 | (short-circuiting). | |
| 2177 | */ | |
| 2178 | ||
| 2179 | -static char * | |
| 2180 | -func_or (char *o, char **argv, const char *funcname UNUSED) | |
| 2181 | +static size_t | |
| 2182 | +func_or (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 2183 | {
| |
| 2184 | for ( ; *argv ; ++argv) | |
| 2185 | {
| |
| 2186 | + size_t result; | |
| 2187 | + | |
| 2188 | const char *begp = *argv; | |
| 2189 | const char *endp = begp + strlen (*argv) - 1; | |
| 2190 | - char *expansion; | |
| 2191 | - int result = 0; | |
| 2192 | ||
| 2193 | /* Find the result of the condition: if it's false keep going. */ | |
| 2194 | ||
| 2195 | @@ -1257,23 +1206,14 @@ | |
| 2196 | if (begp > endp) | |
| 2197 | continue; | |
| 2198 | ||
| 2199 | - expansion = expand_argument (begp, endp+1); | |
| 2200 | - result = strlen (expansion); | |
| 2201 | + result = vbuffer_expand (o, (char *) begp, endp+1 - begp); | |
| 2202 | ||
| 2203 | /* If the result is false keep going. */ | |
| 2204 | - if (!result) | |
| 2205 | - {
| |
| 2206 | - free (expansion); | |
| 2207 | - continue; | |
| 2208 | - } | |
| 2209 | - | |
| 2210 | - /* It's true! Keep this result and return. */ | |
| 2211 | - o = variable_buffer_output (o, expansion, result); | |
| 2212 | - free (expansion); | |
| 2213 | - break; | |
| 2214 | + if (result) | |
| 2215 | + return result; | |
| 2216 | } | |
| 2217 | ||
| 2218 | - return o; | |
| 2219 | + return 0; | |
| 2220 | } | |
| 2221 | ||
| 2222 | /* | |
| 2223 | @@ -1290,56 +1230,37 @@ | |
| 2224 | (short-circuiting). | |
| 2225 | */ | |
| 2226 | ||
| 2227 | -static char * | |
| 2228 | -func_and (char *o, char **argv, const char *funcname UNUSED) | |
| 2229 | +static size_t | |
| 2230 | +func_and (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 2231 | {
| |
| 2232 | - char *expansion; | |
| 2233 | - int result; | |
| 2234 | - | |
| 2235 | while (1) | |
| 2236 | {
| |
| 2237 | + size_t result; | |
| 2238 | + | |
| 2239 | const char *begp = *argv; | |
| 2240 | const char *endp = begp + strlen (*argv) - 1; | |
| 2241 | ||
| 2242 | /* An empty condition is always false. */ | |
| 2243 | strip_whitespace (&begp, &endp); | |
| 2244 | if (begp > endp) | |
| 2245 | - return o; | |
| 2246 | + return 0; | |
| 2247 | ||
| 2248 | - expansion = expand_argument (begp, endp+1); | |
| 2249 | - result = strlen (expansion); | |
| 2250 | + result = vbuffer_expand (o, (char *) begp, endp+1 - begp); | |
| 2251 | ||
| 2252 | /* If the result is false, stop here: we're done. */ | |
| 2253 | if (!result) | |
| 2254 | - break; | |
| 2255 | + return 0; | |
| 2256 | ||
| 2257 | /* Otherwise the result is true. If this is the last one, keep this | |
| 2258 | result and quit. Otherwise go on to the next one! */ | |
| 2259 | ||
| 2260 | if (*(++argv)) | |
| 2261 | - free (expansion); | |
| 2262 | + vbuffer_unwrite (o, result); | |
| 2263 | else | |
| 2264 | - {
| |
| 2265 | - o = variable_buffer_output (o, expansion, result); | |
| 2266 | - break; | |
| 2267 | - } | |
| 2268 | + return result; | |
| 2269 | } | |
| 2270 | ||
| 2271 | - free (expansion); | |
| 2272 | - | |
| 2273 | - return o; | |
| 2274 | -} | |
| 2275 | - | |
| 2276 | -static char * | |
| 2277 | -func_wildcard (char *o, char **argv, const char *funcname UNUSED) | |
| 2278 | -{
| |
| 2279 | -#ifdef _AMIGA | |
| 2280 | - o = wildcard_expansion (argv[0], o); | |
| 2281 | -#else | |
| 2282 | - char *p = string_glob (argv[0]); | |
| 2283 | - o = variable_buffer_output (o, p, strlen (p)); | |
| 2284 | -#endif | |
| 2285 | - return o; | |
| 2286 | + return 0; | |
| 2287 | } | |
| 2288 | ||
| 2289 | /* | |
| 2290 | @@ -1350,36 +1271,38 @@ | |
| 2291 | Treat the arguments as a segment of makefile, and parse them. | |
| 2292 | */ | |
| 2293 | ||
| 2294 | -static char * | |
| 2295 | -func_eval (char *o, char **argv, const char *funcname UNUSED) | |
| 2296 | +static size_t | |
| 2297 | +func_eval (struct vbuffer *o UNUSED, char **argv, const char *funcname UNUSED) | |
| 2298 | {
| |
| 2299 | - char *buf; | |
| 2300 | - unsigned int len; | |
| 2301 | + struct vbuffer *vbuf; | |
| 2302 | ||
| 2303 | /* Eval the buffer. Pop the current variable buffer setting so that the | |
| 2304 | eval'd code can use its own without conflicting. */ | |
| 2305 | ||
| 2306 | - install_variable_buffer (&buf, &len); | |
| 2307 | + vbuf = install_new_expansion_vbuffer (); | |
| 2308 | ||
| 2309 | eval_buffer (argv[0]); | |
| 2310 | ||
| 2311 | - restore_variable_buffer (buf, len); | |
| 2312 | + restore_expansion_vbuffer (vbuf); | |
| 2313 | ||
| 2314 | - return o; | |
| 2315 | + /* Eval always expands to nothing. */ | |
| 2316 | + return 0; | |
| 2317 | } | |
| 2318 | ||
| 2319 | ||
| 2320 | -static char * | |
| 2321 | -func_value (char *o, char **argv, const char *funcname UNUSED) | |
| 2322 | +static size_t | |
| 2323 | +func_value (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 2324 | {
| |
| 2325 | + size_t result = 0; | |
| 2326 | + | |
| 2327 | /* Look up the variable. */ | |
| 2328 | struct variable *v = lookup_variable (argv[0], strlen (argv[0])); | |
| 2329 | ||
| 2330 | /* Copy its value into the output buffer without expanding it. */ | |
| 2331 | if (v) | |
| 2332 | - o = variable_buffer_output (o, v->value, strlen(v->value)); | |
| 2333 | + result += vbuffer_write (o, v->value, -1); | |
| 2334 | ||
| 2335 | - return o; | |
| 2336 | + return result; | |
| 2337 | } | |
| 2338 | ||
| 2339 | /* | |
| 2340 | @@ -1619,9 +1542,10 @@ | |
| 2341 | ||
| 2342 | #else | |
| 2343 | #ifndef _AMIGA | |
| 2344 | -char * | |
| 2345 | -func_shell_base (char *o, char **argv, int trim_newlines) | |
| 2346 | +size_t | |
| 2347 | +func_shell_base (struct vbuffer *o, char **argv, int trim_newlines) | |
| 2348 | {
| |
| 2349 | + size_t result = 0; | |
| 2350 | char *batch_filename = NULL; | |
| 2351 | ||
| 2352 | #ifdef __MSDOS__ | |
| 2353 | @@ -1650,7 +1574,7 @@ | |
| 2354 | #ifdef WINDOWS32 | |
| 2355 | just_print_flag = j_p_f; | |
| 2356 | #endif | |
| 2357 | - return o; | |
| 2358 | + return 0; | |
| 2359 | } | |
| 2360 | #endif | |
| 2361 | ||
| 2362 | @@ -1683,7 +1607,7 @@ | |
| 2363 | if (pipedes[0] < 0) | |
| 2364 | {
| |
| 2365 | perror_with_name (error_prefix, "pipe"); | |
| 2366 | - return o; | |
| 2367 | + return 0; | |
| 2368 | } | |
| 2369 | #elif defined(WINDOWS32) | |
| 2370 | windows32_openpipe (pipedes, &pid, command_argv, envp); | |
| 2371 | @@ -1694,14 +1618,14 @@ | |
| 2372 | {
| |
| 2373 | /* Open of the pipe failed, mark as failed execution. */ | |
| 2374 | shell_function_completed = -1; | |
| 2375 | - return o; | |
| 2376 | + return 0; | |
| 2377 | } | |
| 2378 | else | |
| 2379 | #else | |
| 2380 | if (pipe (pipedes) < 0) | |
| 2381 | {
| |
| 2382 | perror_with_name (error_prefix, "pipe"); | |
| 2383 | - return o; | |
| 2384 | + return 0; | |
| 2385 | } | |
| 2386 | ||
| 2387 | # ifdef __EMX__ | |
| 2388 | @@ -1800,13 +1724,13 @@ | |
| 2389 | /* The child finished normally. Replace all newlines in its output | |
| 2390 | with spaces, and put that in the variable output buffer. */ | |
| 2391 | fold_newlines (buffer, &i, trim_newlines); | |
| 2392 | - o = variable_buffer_output (o, buffer, i); | |
| 2393 | + result += vbuffer_write (o, buffer, i); | |
| 2394 | } | |
| 2395 | ||
| 2396 | free (buffer); | |
| 2397 | } | |
| 2398 | ||
| 2399 | - return o; | |
| 2400 | + return result; | |
| 2401 | } | |
| 2402 | ||
| 2403 | #else /* _AMIGA */ | |
| 2404 | @@ -1892,14 +1816,14 @@ | |
| 2405 | Close (child_stdout); | |
| 2406 | ||
| 2407 | fold_newlines (buffer, &i, trim_newlines); | |
| 2408 | - o = variable_buffer_output (o, buffer, i); | |
| 2409 | + result += vbuffer_write (o, buffer, i); | |
| 2410 | free (buffer); | |
| 2411 | return o; | |
| 2412 | } | |
| 2413 | #endif /* _AMIGA */ | |
| 2414 | ||
| 2415 | -char * | |
| 2416 | -func_shell (char *o, char **argv, const char *funcname UNUSED) | |
| 2417 | +size_t | |
| 2418 | +func_shell (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 2419 | {
| |
| 2420 | return func_shell_base (o, argv, 1); | |
| 2421 | } | |
| 2422 | @@ -1914,8 +1838,7 @@ | |
| 2423 | func_eq (char *o, char **argv, char *funcname UNUSED) | |
| 2424 | {
| |
| 2425 | int result = ! strcmp (argv[0], argv[1]); | |
| 2426 | - o = variable_buffer_output (o, result ? "1" : "", result); | |
| 2427 | - return o; | |
| 2428 | + return vbuffer_write (o, result ? "1" : "", result); | |
| 2429 | } | |
| 2430 | ||
| 2431 | ||
| 2432 | @@ -1930,8 +1853,7 @@ | |
| 2433 | while (isspace ((unsigned char)*s)) | |
| 2434 | s++; | |
| 2435 | result = ! (*s); | |
| 2436 | - o = variable_buffer_output (o, result ? "1" : "", result); | |
| 2437 | - return o; | |
| 2438 | + return vbuffer_write (o, result ? "1" : "", result); | |
| 2439 | } | |
| 2440 | #endif | |
| 2441 | ||
| 2442 | @@ -2058,13 +1980,14 @@ | |
| 2443 | } | |
| 2444 | ||
| 2445 | ||
| 2446 | -static char * | |
| 2447 | -func_realpath (char *o, char **argv, const char *funcname UNUSED) | |
| 2448 | +static size_t | |
| 2449 | +func_realpath (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 2450 | {
| |
| 2451 | + size_t result = 0; | |
| 2452 | + | |
| 2453 | /* Expand the argument. */ | |
| 2454 | const char *p = argv[0]; | |
| 2455 | const char *path = 0; | |
| 2456 | - int doneany = 0; | |
| 2457 | unsigned int len = 0; | |
| 2458 | #ifndef HAVE_REALPATH | |
| 2459 | struct stat st; | |
| 2460 | @@ -2087,22 +2010,17 @@ | |
| 2461 | #endif | |
| 2462 | ) | |
| 2463 | {
| |
| 2464 | - o = variable_buffer_output (o, out, strlen (out)); | |
| 2465 | - o = variable_buffer_output (o, " ", 1); | |
| 2466 | - doneany = 1; | |
| 2467 | + result += vbuffer_write (o, out, -1); | |
| 2468 | + result += vbuffer_write (o, " ", 1); | |
| 2469 | } | |
| 2470 | } | |
| 2471 | } | |
| 2472 | ||
| 2473 | - /* Kill last space. */ | |
| 2474 | - if (doneany) | |
| 2475 | - --o; | |
| 2476 | - | |
| 2477 | - return o; | |
| 2478 | + return result - vbuffer_unwrite (o, !!result); | |
| 2479 | } | |
| 2480 | ||
| 2481 | -static char * | |
| 2482 | -func_file (char *o, char **argv, const char *funcname UNUSED) | |
| 2483 | +static size_t | |
| 2484 | +func_file (struct vbuffer *o UNUSED, char **argv, const char *funcname UNUSED) | |
| 2485 | {
| |
| 2486 | char *fn = argv[0]; | |
| 2487 | ||
| 2488 | @@ -2137,16 +2055,17 @@ | |
| 2489 | else | |
| 2490 | fatal (reading_file, _("Invalid file operation: %s"), fn);
| |
| 2491 | ||
| 2492 | - return o; | |
| 2493 | + return 0; | |
| 2494 | } | |
| 2495 | ||
| 2496 | -static char * | |
| 2497 | -func_abspath (char *o, char **argv, const char *funcname UNUSED) | |
| 2498 | +static size_t | |
| 2499 | +func_abspath (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 2500 | {
| |
| 2501 | + size_t result = 0; | |
| 2502 | + | |
| 2503 | /* Expand the argument. */ | |
| 2504 | const char *p = argv[0]; | |
| 2505 | const char *path = 0; | |
| 2506 | - int doneany = 0; | |
| 2507 | unsigned int len = 0; | |
| 2508 | PATH_VAR (in); | |
| 2509 | PATH_VAR (out); | |
| 2510 | @@ -2160,25 +2079,18 @@ | |
| 2511 | ||
| 2512 | if (abspath (in, out)) | |
| 2513 | {
| |
| 2514 | - o = variable_buffer_output (o, out, strlen (out)); | |
| 2515 | - o = variable_buffer_output (o, " ", 1); | |
| 2516 | - doneany = 1; | |
| 2517 | + result += vbuffer_write (o, out, strlen (out)); | |
| 2518 | + result += vbuffer_write (o, " ", 1); | |
| 2519 | } | |
| 2520 | } | |
| 2521 | } | |
| 2522 | ||
| 2523 | - /* Kill last space. */ | |
| 2524 | - if (doneany) | |
| 2525 | - --o; | |
| 2526 | - | |
| 2527 | - return o; | |
| 2528 | + return result - vbuffer_unwrite (o, !!result); | |
| 2529 | } | |
| 2530 | ||
| 2531 | /* Lookup table for builtin functions. | |
| 2532 | ||
| 2533 | - This doesn't have to be sorted; we use a straight lookup. We might gain | |
| 2534 | - some efficiency by moving most often used functions to the start of the | |
| 2535 | - table. | |
| 2536 | + This doesn't have to be sorted; we use hash table to perform a lookup. | |
| 2537 | ||
| 2538 | If MAXIMUM_ARGS is 0, that means there is no maximum and all | |
| 2539 | comma-separated values are treated as arguments. | |
| 2540 | @@ -2186,7 +2098,7 @@ | |
| 2541 | EXPAND_ARGS means that all arguments should be expanded before invocation. | |
| 2542 | Functions that do namespace tricks (foreach) don't automatically expand. */ | |
| 2543 | ||
| 2544 | -static char *func_call (char *o, char **argv, const char *funcname); | |
| 2545 | +static size_t func_call (struct vbuffer *o, char **argv, const char *funcname); | |
| 2546 | ||
| 2547 | ||
| 2548 | static struct function_table_entry function_table_init[] = | |
| 2549 | @@ -2237,10 +2149,26 @@ | |
| 2550 | #define FUNCTION_TABLE_ENTRIES (sizeof (function_table_init) / sizeof (struct function_table_entry)) | |
| 2551 | ||
| 2552 | ||
| 2553 | +/* Look up a function by name. */ | |
| 2554 | + | |
| 2555 | +#ifdef __GNUC__ | |
| 2556 | +__inline | |
| 2557 | +#endif | |
| 2558 | +static const struct function_table_entry * | |
| 2559 | +lookup_function (const char *name, unsigned int length) | |
| 2560 | +{
| |
| 2561 | + struct function_table_entry function_table_entry_key; | |
| 2562 | + function_table_entry_key.name = name; | |
| 2563 | + function_table_entry_key.len = length; | |
| 2564 | + | |
| 2565 | + return hash_find_item (&function_table, &function_table_entry_key); | |
| 2566 | +} | |
| 2567 | + | |
| 2568 | + | |
| 2569 | /* These must come after the definition of function_table. */ | |
| 2570 | ||
| 2571 | -static char * | |
| 2572 | -expand_builtin_function (char *o, int argc, char **argv, | |
| 2573 | +static size_t | |
| 2574 | +expand_builtin_function (struct vbuffer *o, int argc, char **argv, | |
| 2575 | const struct function_table_entry *entry_p) | |
| 2576 | {
| |
| 2577 | if (argc < (int)entry_p->minimum_args) | |
| 2578 | @@ -2253,7 +2181,7 @@ | |
| 2579 | rather than in each one. We can change it later if necessary. */ | |
| 2580 | ||
| 2581 | if (!argc) | |
| 2582 | - return o; | |
| 2583 | + return 0; | |
| 2584 | ||
| 2585 | if (!entry_p->func_ptr) | |
| 2586 | fatal (*expanding_var, | |
| 2587 | @@ -2264,120 +2192,134 @@ | |
| 2588 | ||
| 2589 | /* Check for a function invocation in *STRINGP. *STRINGP points at the | |
| 2590 | opening ( or { and is not null-terminated. If a function invocation
| |
| 2591 | - is found, expand it into the buffer at *OP, updating *OP, incrementing | |
| 2592 | - *STRINGP past the reference and returning nonzero. If not, return zero. */ | |
| 2593 | + is found, expand it into the buffer O, incrementing *STRINGP past the | |
| 2594 | + reference and returning the amount of bytes written. | |
| 2595 | + Note, that in this case the string between the parens is destroyed. | |
| 2596 | + | |
| 2597 | + If no function call is recognized, return -1. */ | |
| 2598 | ||
| 2599 | int | |
| 2600 | -handle_function (char **op, const char **stringp) | |
| 2601 | +handle_function (struct vbuffer *o, char **stringp) | |
| 2602 | {
| |
| 2603 | + size_t ret = 0; | |
| 2604 | + | |
| 2605 | const struct function_table_entry *entry_p; | |
| 2606 | char openparen = (*stringp)[0]; | |
| 2607 | char closeparen = openparen == '(' ? ')' : '}';
| |
| 2608 | - const char *beg; | |
| 2609 | - const char *end; | |
| 2610 | - int count = 0; | |
| 2611 | - char *abeg = NULL; | |
| 2612 | + char *beg; | |
| 2613 | + char *end; | |
| 2614 | + int count; | |
| 2615 | char **argv, **argvp; | |
| 2616 | - int nargs; | |
| 2617 | + int nargs, maxargs; | |
| 2618 | + struct vbuffer argbuf; | |
| 2619 | + size_t reserved; | |
| 2620 | ||
| 2621 | beg = *stringp + 1; | |
| 2622 | ||
| 2623 | - entry_p = lookup_function (beg); | |
| 2624 | + end = beg; | |
| 2625 | + while ((*end >= 'a' && *end <= 'z') || *end == '-') | |
| 2626 | + end++; | |
| 2627 | + if (*end != ' ' && *end != '\t') | |
| 2628 | + return -1; | |
| 2629 | ||
| 2630 | + entry_p = lookup_function (beg, end - beg); | |
| 2631 | if (!entry_p) | |
| 2632 | - return 0; | |
| 2633 | + return -1; | |
| 2634 | ||
| 2635 | /* We found a builtin function. Find the beginning of its arguments (skip | |
| 2636 | whitespace after the name). */ | |
| 2637 | ||
| 2638 | - beg = next_token (beg + entry_p->len); | |
| 2639 | + beg = next_token (end); | |
| 2640 | + maxargs = entry_p->maximum_args; | |
| 2641 | ||
| 2642 | /* Find the end of the function invocation, counting nested use of | |
| 2643 | - whichever kind of parens we use. Since we're looking, count commas | |
| 2644 | - to get a rough estimate of how many arguments we might have. The | |
| 2645 | - count might be high, but it'll never be low. */ | |
| 2646 | - | |
| 2647 | - for (nargs=1, end=beg; *end != '\0'; ++end) | |
| 2648 | - if (*end == ',') | |
| 2649 | - ++nargs; | |
| 2650 | - else if (*end == openparen) | |
| 2651 | + whichever kind of parens we use and isolating arguments. | |
| 2652 | + As soon as we hit up to MAXARGS (if it is positive) assume the rest of | |
| 2653 | + the string is part of the last argument. For each argument, we save | |
| 2654 | + a pointer into the ARGBUF and NULL-terminate the argument value. */ | |
| 2655 | +#define VBUFFER_WRITE_PTR(o, value) \ | |
| 2656 | + *((char **) (((o)->ptr += sizeof (char *)) - sizeof (char *))) = (value) | |
| 2657 | + | |
| 2658 | + vbuffer_init (&argbuf); | |
| 2659 | - | + reserved = argbuf.size; |
| 2659 | + | + reserved = argbuf.size - sizeof (char *); |
| 2660 | + | |
| 2661 | + VBUFFER_WRITE_PTR (&argbuf, beg); | |
| 2662 | - | + VBUFFER_WRITE_PTR(&argbuf, beg); |
| 2662 | + | |
| 2663 | + nargs=1; | |
| 2664 | + count = 0; | |
| 2665 | + for (end=beg; *end != '\0'; ++end) | |
| 2666 | + if (*end == openparen) | |
| 2667 | ++count; | |
| 2668 | else if (*end == closeparen && --count < 0) | |
| 2669 | break; | |
| 2670 | + else if (count == 0 && *end == ',' && nargs != maxargs) | |
| 2671 | + {
| |
| 2672 | + *end = '\0'; | |
| 2673 | + nargs++; | |
| 2674 | + | |
| 2675 | - | + if (reserved < 2 * sizeof (char *)) |
| 2675 | + | + if (reserved <= 2 * sizeof (char *)) |
| 2676 | + reserved = vbuffer_reserve (&argbuf, 2 * sizeof (char *)); | |
| 2677 | + else | |
| 2678 | + reserved -= sizeof (char *); | |
| 2679 | + | |
| 2680 | - | + VBUFFER_WRITE_PTR(&argbuf, end+1); |
| 2680 | + | + VBUFFER_WRITE_PTR (&argbuf, end+1); |
| 2681 | + } | |
| 2682 | ||
| 2683 | if (count >= 0) | |
| 2684 | fatal (*expanding_var, | |
| 2685 | _("unterminated call to function '%s': missing '%c'"),
| |
| 2686 | entry_p->name, closeparen); | |
| 2687 | ||
| 2688 | - *stringp = end; | |
| 2689 | + /* NULL-terminate the last argument. */ | |
| 2690 | + *end = '\0'; | |
| 2691 | ||
| 2692 | - /* Get some memory to store the arg pointers. */ | |
| 2693 | - argvp = argv = alloca (sizeof (char *) * (nargs + 2)); | |
| 2694 | + /* NULL-terminate the arg vector (assume there was enough room reserved). */ | |
| 2695 | - | + VBUFFER_WRITE_PTR(&argbuf, NULL); |
| 2695 | + | + VBUFFER_WRITE_PTR (&argbuf, NULL); |
| 2696 | ||
| 2697 | - /* Chop the string into arguments, then a nul. As soon as we hit | |
| 2698 | - MAXIMUM_ARGS (if it's >0) assume the rest of the string is part of the | |
| 2699 | - last argument. | |
| 2700 | - | |
| 2701 | - If we're expanding, store pointers to the expansion of each one. If | |
| 2702 | - not, make a duplicate of the string and point into that, nul-terminating | |
| 2703 | - each argument. */ | |
| 2704 | + argv = (char **) argbuf.buffer; | |
| 2705 | ||
| 2706 | - if (entry_p->expand_args) | |
| 2707 | - {
| |
| 2708 | - const char *p; | |
| 2709 | - for (p=beg, nargs=0; p <= end; ++argvp) | |
| 2710 | - {
| |
| 2711 | - const char *next; | |
| 2712 | + /* If the function requires argument to be expanded, expand them into the | |
| 2713 | + same buffer as we used to for the arg vector, but store pointers to the | |
| 2714 | + expansion of each one into a new stack-allocated vector. | |
| 2715 | ||
| 2716 | - ++nargs; | |
| 2717 | + This, in turn, is performed in two steps: | |
| 2718 | + - First, we save position-independent offsets into a special buffer. | |
| 2719 | + - Next, build the final arg vector from the offsets buffer. | |
| 2720 | ||
| 2721 | - if (nargs == entry_p->maximum_args | |
| 2722 | - || (! (next = find_next_argument (openparen, closeparen, p, end)))) | |
| 2723 | - next = end; | |
| 2724 | + Involving an intermediate buffer for the offsets is necessary because | |
| 2725 | + ARGBUF may grow while expanding an argument thus invalidating any | |
| 2726 | + previously stored pointers. */ | |
| 2727 | ||
| 2728 | - *argvp = expand_argument (p, next); | |
| 2729 | - p = next + 1; | |
| 2730 | - } | |
| 2731 | - } | |
| 2732 | - else | |
| 2733 | + if (entry_p->expand_args) | |
| 2734 | {
| |
| 2735 | - int len = end - beg; | |
| 2736 | - char *p, *aend; | |
| 2737 | - | |
| 2738 | - abeg = xmalloc (len+1); | |
| 2739 | - memcpy (abeg, beg, len); | |
| 2740 | - abeg[len] = '\0'; | |
| 2741 | - aend = abeg + len; | |
| 2742 | - | |
| 2743 | - for (p=abeg, nargs=0; p <= aend; ++argvp) | |
| 2744 | - {
| |
| 2745 | - char *next; | |
| 2746 | - | |
| 2747 | - ++nargs; | |
| 2748 | - | |
| 2749 | - if (nargs == entry_p->maximum_args | |
| 2750 | - || (! (next = find_next_argument (openparen, closeparen, p, aend)))) | |
| 2751 | - next = aend; | |
| 2752 | - | |
| 2753 | - *argvp = p; | |
| 2754 | - *next = '\0'; | |
| 2755 | - p = next + 1; | |
| 2756 | - } | |
| 2757 | + int i; | |
| 2758 | + size_t *offs = alloca ((nargs + 1) * sizeof (size_t)); | |
| 2759 | + argv = memcpy (alloca ((nargs + 1) * sizeof (char *)), | |
| 2760 | + argv, (nargs + 1) * sizeof (char *)); | |
| 2761 | + | |
| 2762 | + vbuffer_reset (&argbuf); | |
| 2763 | + offs[0] = 0; | |
| 2764 | + for (i=0, argvp=argv; *argvp != 0; ++argvp, ++i) | |
| 2765 | + {
| |
| 2766 | + offs[i + 1] = offs[i] + vbuffer_expand (&argbuf, *argvp, -1) + 1; | |
| 2767 | + *(++argbuf.ptr) = '\0'; | |
| 2768 | + } | |
| 2769 | + for (i=0, argvp=argv; *argvp != 0; ++argvp, ++i) | |
| 2770 | + *argvp = argbuf.buffer + offs[i]; | |
| 2771 | } | |
| 2772 | - *argvp = NULL; | |
| 2773 | ||
| 2774 | /* Finally! Run the function... */ | |
| 2775 | - *op = expand_builtin_function (*op, nargs, argv, entry_p); | |
| 2776 | + ret += expand_builtin_function (o, nargs, argv, entry_p); | |
| 2777 | ||
| 2778 | - /* Free memory. */ | |
| 2779 | - if (entry_p->expand_args) | |
| 2780 | - for (argvp=argv; *argvp != 0; ++argvp) | |
| 2781 | - free (*argvp); | |
| 2782 | - else if (abeg) | |
| 2783 | - free (abeg); | |
| 2784 | + /* Restore a paren after the last argument and advance the STRINGP. */ | |
| 2785 | + *end = closeparen; | |
| 2786 | + *stringp = end; | |
| 2787 | + | |
| 2788 | + vbuffer_free (&argbuf); | |
| 2789 | + | |
| 2790 | +#undef VBUFFER_WRITE_PTR | |
| 2791 | ||
| 2792 | - return 1; | |
| 2793 | + return ret; | |
| 2794 | } | |
| 2795 | ||
| 2796 | ||
| 2797 | @@ -2385,37 +2327,41 @@ | |
| 2798 | function or a make variable, in the context of the rest of the arguments | |
| 2799 | assigned to $1, $2, ... $N. $0 is the name of the function. */ | |
| 2800 | ||
| 2801 | -static char * | |
| 2802 | -func_call (char *o, char **argv, const char *funcname UNUSED) | |
| 2803 | +static size_t | |
| 2804 | +func_call (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 2805 | {
| |
| 2806 | - static int max_args = 0; | |
| 2807 | + size_t ret = 0; | |
| 2808 | + | |
| 2809 | char *fname; | |
| 2810 | char *cp; | |
| 2811 | - char *body; | |
| 2812 | int flen; | |
| 2813 | int i; | |
| 2814 | - int saved_args; | |
| 2815 | + int argc; | |
| 2816 | const struct function_table_entry *entry_p; | |
| 2817 | struct variable *v; | |
| 2818 | ||
| 2819 | /* There is no way to define a variable with a space in the name, so strip | |
| 2820 | - leading and trailing whitespace as a favor to the user. */ | |
| 2821 | + trailing whitespace as a favor to the user. */ | |
| 2822 | fname = argv[0]; | |
| 2823 | while (*fname != '\0' && isspace ((unsigned char)*fname)) | |
| 2824 | ++fname; | |
| 2825 | ||
| 2826 | - cp = fname + strlen (fname) - 1; | |
| 2827 | + flen = strlen (fname); | |
| 2828 | + | |
| 2829 | + cp = fname + flen - 1; | |
| 2830 | while (cp > fname && isspace ((unsigned char)*cp)) | |
| 2831 | --cp; | |
| 2832 | cp[1] = '\0'; | |
| 2833 | ||
| 2834 | /* Calling nothing is a no-op */ | |
| 2835 | if (*fname == '\0') | |
| 2836 | - return o; | |
| 2837 | + return 0; | |
| 2838 | ||
| 2839 | - /* Are we invoking a builtin function? */ | |
| 2840 | + /* Fix up the length after stripping a trailing whitespace. */ | |
| 2841 | + flen = cp - fname + 1; | |
| 2842 | ||
| 2843 | - entry_p = lookup_function (fname); | |
| 2844 | + /* Are we invoking a builtin function? */ | |
| 2845 | + entry_p = lookup_function (fname, flen); | |
| 2846 | if (entry_p) | |
| 2847 | {
| |
| 2848 | /* How many arguments do we have? */ | |
| 2849 | @@ -2426,7 +2372,6 @@ | |
| 2850 | ||
| 2851 | /* Not a builtin, so the first argument is the name of a variable to be | |
| 2852 | expanded and interpreted as a function. Find it. */ | |
| 2853 | - flen = strlen (fname); | |
| 2854 | ||
| 2855 | v = lookup_variable (fname, flen); | |
| 2856 | ||
| 2857 | @@ -2434,61 +2379,42 @@ | |
| 2858 | warn_undefined (fname, flen); | |
| 2859 | ||
| 2860 | if (v == 0 || *v->value == '\0') | |
| 2861 | - return o; | |
| 2862 | - | |
| 2863 | - body = alloca (flen + 4); | |
| 2864 | - body[0] = '$'; | |
| 2865 | - body[1] = '(';
| |
| 2866 | - memcpy (body + 2, fname, flen); | |
| 2867 | - body[flen+2] = ')'; | |
| 2868 | - body[flen+3] = '\0'; | |
| 2869 | - | |
| 2870 | - /* Set up arguments $(1) .. $(N). $(0) is the function name. */ | |
| 2871 | - | |
| 2872 | - push_new_variable_scope (); | |
| 2873 | - | |
| 2874 | - for (i=0; *argv; ++i, ++argv) | |
| 2875 | - {
| |
| 2876 | - char num[11]; | |
| 2877 | - | |
| 2878 | - sprintf (num, "%d", i); | |
| 2879 | - define_variable (num, strlen (num), *argv, o_automatic, 0); | |
| 2880 | - } | |
| 2881 | - | |
| 2882 | - /* If the number of arguments we have is < max_args, it means we're inside | |
| 2883 | - a recursive invocation of $(call ...). Fill in the remaining arguments | |
| 2884 | - in the new scope with the empty value, to hide them from this | |
| 2885 | - invocation. */ | |
| 2886 | - | |
| 2887 | - for (; i < max_args; ++i) | |
| 2888 | - {
| |
| 2889 | - char num[11]; | |
| 2890 | - | |
| 2891 | - sprintf (num, "%d", i); | |
| 2892 | - define_variable (num, strlen (num), "", o_automatic, 0); | |
| 2893 | - } | |
| 2894 | + return 0; | |
| 2895 | ||
| 2896 | - /* Expand the body in the context of the arguments, adding the result to | |
| 2897 | - the variable buffer. */ | |
| 2898 | + if (!v->recursive) | |
| 2899 | + return vbuffer_write(o, v->value, -1); | |
| 2900 | ||
| 2901 | - v->exp_count = EXP_COUNT_MAX; | |
| 2902 | + /* Count the arguments. */ | |
| 2903 | + argc = 0; | |
| 2904 | + while (argv[++argc]) | |
| 2905 | + ; | |
| 2906 | ||
| 2907 | - saved_args = max_args; | |
| 2908 | - max_args = i; | |
| 2909 | - o = variable_expand_string (o, body, flen+3); | |
| 2910 | - max_args = saved_args; | |
| 2911 | + {
| |
| 2912 | + struct call_frame new_frame; | |
| 2913 | + struct call_frame *saved_frame = current_call_frame; | |
| 2914 | ||
| 2915 | - v->exp_count = 0; | |
| 2916 | + /* Replace the current call frame with a new one. */ | |
| 2917 | + new_frame.argc = argc; | |
| 2918 | + new_frame.argv = argv; | |
| 2919 | + current_call_frame = &new_frame; | |
| 2920 | + | |
| 2921 | + /* Expand the variable in the context of the arguments, | |
| 2922 | + writing the result into the variable buffer. */ | |
| 2923 | + v->exp_count = EXP_COUNT_MAX; | |
| 2924 | + ret += vbuffer_expand_variable (o, v); | |
| 2925 | + v->exp_count = 0; | |
| 2926 | ||
| 2927 | - pop_variable_scope (); | |
| 2928 | + current_call_frame = saved_frame; | |
| 2929 | + } | |
| 2930 | ||
| 2931 | - return o + strlen (o); | |
| 2932 | + return ret; | |
| 2933 | } | |
| 2934 | ||
| 2935 | + | |
| 2936 | void | |
| 2937 | define_new_function(const struct floc *flocp, | |
| 2938 | const char *name, int min, int max, int expand, | |
| 2939 | - char *(*func)(char *, char **, const char *)) | |
| 2940 | + size_t (*func)(struct vbuffer *, char **, const char *)) | |
| 2941 | {
| |
| 2942 | size_t len = strlen (name); | |
| 2943 | struct function_table_entry *ent = xmalloc (sizeof (struct function_table_entry)); | |
| 2944 | Index: guile.c | |
| 2945 | =================================================================== | |
| 2946 | RCS file: /sources/make/make/guile.c,v | |
| 2947 | retrieving revision 2.5 | |
| 2948 | diff -u -r2.5 guile.c | |
| 2949 | --- guile.c 5 Mar 2012 14:10:44 -0000 2.5 | |
| 2950 | - | +++ guile.c 9 Apr 2012 09:50:04 -0000 |
| 2950 | + | +++ guile.c 9 Apr 2012 13:34:41 -0000 |
| 2951 | @@ -86,20 +86,22 @@ | |
| 2952 | } | |
| 2953 | ||
| 2954 | /* This is the function registered with make */ | |
| 2955 | -static char * | |
| 2956 | -func_guile (char *o, char **argv, const char *funcname UNUSED) | |
| 2957 | +static size_t | |
| 2958 | +func_guile (struct vbuffer *o, char **argv, const char *funcname UNUSED) | |
| 2959 | {
| |
| 2960 | + size_t result = 0; | |
| 2961 | + | |
| 2962 | if (argv[0] && argv[0][0] != '\0') | |
| 2963 | {
| |
| 2964 | char *str = scm_with_guile (internal_guile_eval, argv[0]); | |
| 2965 | if (str) | |
| 2966 | {
| |
| 2967 | - o = variable_buffer_output (o, str, strlen (str)); | |
| 2968 | + result += vbuffer_write (o, str, -1); | |
| 2969 | free (str); | |
| 2970 | } | |
| 2971 | } | |
| 2972 | ||
| 2973 | - return o; | |
| 2974 | + return result; | |
| 2975 | } | |
| 2976 | ||
| 2977 | /* ----- Public interface ----- */ | |
| 2978 | Index: main.c | |
| 2979 | =================================================================== | |
| 2980 | RCS file: /sources/make/make/main.c,v | |
| 2981 | retrieving revision 1.256 | |
| 2982 | diff -u -r1.256 main.c | |
| 2983 | --- main.c 5 Mar 2012 14:10:44 -0000 1.256 | |
| 2984 | - | +++ main.c 9 Apr 2012 09:50:05 -0000 |
| 2984 | + | +++ main.c 9 Apr 2012 13:34:42 -0000 |
| 2985 | @@ -1104,6 +1104,8 @@ | |
| 2986 | ||
| 2987 | initialize_global_hash_tables (); | |
| 2988 | ||
| 2989 | + install_new_expansion_vbuffer(); | |
| 2990 | + | |
| 2991 | /* Figure out where we are. */ | |
| 2992 | ||
| 2993 | #ifdef WINDOWS32 | |
| 2994 | @@ -2277,12 +2279,7 @@ | |
| 2995 | if (default_goal_var->recursive) | |
| 2996 | p = variable_expand (default_goal_var->value); | |
| 2997 | else | |
| 2998 | - {
| |
| 2999 | - p = variable_buffer_output (variable_buffer, default_goal_var->value, | |
| 3000 | - strlen (default_goal_var->value)); | |
| 3001 | - *p = '\0'; | |
| 3002 | - p = variable_buffer; | |
| 3003 | - } | |
| 3004 | + p = default_goal_var->value; | |
| 3005 | ||
| 3006 | if (*p != '\0') | |
| 3007 | {
| |
| 3008 | @@ -2359,6 +2356,16 @@ | |
| 3009 | if (clock_skew_detected) | |
| 3010 | error (NILF, | |
| 3011 | _("warning: Clock skew detected. Your build may be incomplete."));
| |
| 3012 | +// error (NILF, | |
| 3013 | +// "memory_usage: %10d total: %8d mallocs, %8d reallocs, %8d strdups", | |
| 3014 | +// nr_mallocs + nr_reallocs + nr_strdups, | |
| 3015 | +// nr_mallocs, nr_reallocs, nr_strdups); | |
| 3016 | +// error (NILF, | |
| 3017 | +// "hash: %10d cmps, %8d hash1, %8d hash2", | |
| 3018 | +// nr_cmps, nr_hash1, nr_hash2); | |
| 3019 | +// error (NILF, | |
| 3020 | +// "max_lookup_depth: %10d, miss: %10d", | |
| 3021 | +// max_lookup_depth, lookup_miss); | |
| 3022 | ||
| 3023 | /* Exit. */ | |
| 3024 | die (status); | |
| 3025 | Index: make.h | |
| 3026 | =================================================================== | |
| 3027 | RCS file: /sources/make/make/make.h,v | |
| 3028 | retrieving revision 1.157 | |
| 3029 | diff -u -r1.157 make.h | |
| 3030 | --- make.h 5 Mar 2012 14:10:44 -0000 1.157 | |
| 3031 | - | +++ make.h 9 Apr 2012 09:50:05 -0000 |
| 3031 | + | +++ make.h 9 Apr 2012 13:34:42 -0000 |
| 3032 | @@ -21,6 +21,9 @@ | |
| 3033 | #undef HAVE_CONFIG_H | |
| 3034 | #define HAVE_CONFIG_H 1 | |
| 3035 | ||
| 3036 | +extern int nr_mallocs, nr_reallocs, nr_strdups, nr_cmps, nr_hash1, nr_hash2; | |
| 3037 | +extern int max_lookup_depth, lookup_miss; | |
| 3038 | + | |
| 3039 | /* Specify we want GNU source code. This must be defined before any | |
| 3040 | system headers are included. */ | |
| 3041 | ||
| 3042 | @@ -406,11 +409,32 @@ | |
| 3043 | void *xrealloc (void *, unsigned int); | |
| 3044 | char *xstrdup (const char *); | |
| 3045 | char *xstrndup (const char *, unsigned int); | |
| 3046 | + | |
| 3047 | char *find_next_token (const char **, unsigned int *); | |
| 3048 | -char *next_token (const char *); | |
| 3049 | -char *end_of_token (const char *); | |
| 3050 | + | |
| 3051 | +/* The following three functions are used extremely frequently, | |
| 3052 | + so we try to inline them where possible. */ | |
| 3053 | +#ifdef __GNUC__ | |
| 3054 | + | |
| 3055 | +static __inline char * | |
| 3056 | +next_token (const char *s) | |
| 3057 | + { return (char *) s + strspn (s, " \t"); }
| |
| 3058 | + | |
| 3059 | +static __inline char * | |
| 3060 | +end_of_token (const char *s) | |
| 3061 | + { return (char *) s + strcspn (s, " \t"); }
| |
| 3062 | + | |
| 3063 | +static __inline char * | |
| 3064 | +lindex (const char *s, const char *limit, int c) | |
| 3065 | + { return memchr (s, c, limit - s); }
| |
| 3066 | + | |
| 3067 | +#else | |
| 3068 | +char *next_token (const char *s); | |
| 3069 | +char *end_of_token (const char *s); | |
| 3070 | +char *lindex (const char *s, const char *limit, int c); | |
| 3071 | +#endif /* __GNUC__ */ | |
| 3072 | + | |
| 3073 | void collapse_continuations (char *); | |
| 3074 | -char *lindex (const char *, const char *, int); | |
| 3075 | int alpha_compare (const void *, const void *); | |
| 3076 | void print_spaces (unsigned int); | |
| 3077 | char *find_percent (char *); | |
| 3078 | Index: misc.c | |
| 3079 | =================================================================== | |
| 3080 | RCS file: /sources/make/make/misc.c,v | |
| 3081 | retrieving revision 1.89 | |
| 3082 | diff -u -r1.89 misc.c | |
| 3083 | --- misc.c 5 Mar 2012 14:10:44 -0000 1.89 | |
| 3084 | - | +++ misc.c 9 Apr 2012 09:50:05 -0000 |
| 3084 | + | +++ misc.c 9 Apr 2012 13:34:42 -0000 |
| 3085 | @@ -360,6 +360,8 @@ | |
| 3086 | /* Like malloc but get fatal error if memory is exhausted. */ | |
| 3087 | /* Don't bother if we're using dmalloc; it provides these for us. */ | |
| 3088 | ||
| 3089 | +int nr_mallocs, nr_reallocs, nr_strdups, nr_cmps, nr_hash1, nr_hash2; | |
| 3090 | + | |
| 3091 | #ifndef HAVE_DMALLOC_H | |
| 3092 | ||
| 3093 | #undef xmalloc | |
| 3094 | @@ -372,6 +374,7 @@ | |
| 3095 | {
| |
| 3096 | /* Make sure we don't allocate 0, for pre-ISO implementations. */ | |
| 3097 | void *result = malloc (size ? size : 1); | |
| 3098 | +// ++nr_mallocs; | |
| 3099 | if (result == 0) | |
| 3100 | fatal (NILF, _("virtual memory exhausted"));
| |
| 3101 | return result; | |
| 3102 | @@ -383,6 +386,7 @@ | |
| 3103 | {
| |
| 3104 | /* Make sure we don't allocate 0, for pre-ISO implementations. */ | |
| 3105 | void *result = calloc (size ? size : 1, 1); | |
| 3106 | +// ++nr_mallocs; | |
| 3107 | if (result == 0) | |
| 3108 | fatal (NILF, _("virtual memory exhausted"));
| |
| 3109 | return result; | |
| 3110 | @@ -393,6 +397,7 @@ | |
| 3111 | xrealloc (void *ptr, unsigned int size) | |
| 3112 | {
| |
| 3113 | void *result; | |
| 3114 | +// ++nr_reallocs; | |
| 3115 | ||
| 3116 | /* Some older implementations of realloc() don't conform to ISO. */ | |
| 3117 | if (! size) | |
| 3118 | @@ -408,6 +413,7 @@ | |
| 3119 | xstrdup (const char *ptr) | |
| 3120 | {
| |
| 3121 | char *result; | |
| 3122 | +// ++nr_strdups; | |
| 3123 | ||
| 3124 | #ifdef HAVE_STRDUP | |
| 3125 | result = strdup (ptr); | |
| 3126 | @@ -431,6 +437,7 @@ | |
| 3127 | xstrndup (const char *str, unsigned int length) | |
| 3128 | {
| |
| 3129 | char *result; | |
| 3130 | +// ++nr_strdups; | |
| 3131 | ||
| 3132 | #ifdef HAVE_STRNDUP | |
| 3133 | result = strndup (str, length); | |
| 3134 | @@ -447,6 +454,7 @@ | |
| 3135 | } | |
| 3136 | ||
| 3137 | ||
| 3138 | +#ifndef __GNUC__ | |
| 3139 | /* Limited INDEX: | |
| 3140 | Search through the string STRING, which ends at LIMIT, for the character C. | |
| 3141 | Returns a pointer to the first occurrence, or nil if none is found. | |
| 3142 | @@ -456,11 +464,7 @@ | |
| 3143 | char * | |
| 3144 | lindex (const char *s, const char *limit, int c) | |
| 3145 | {
| |
| 3146 | - while (s < limit) | |
| 3147 | - if (*s++ == c) | |
| 3148 | - return (char *)(s - 1); | |
| 3149 | - | |
| 3150 | - return 0; | |
| 3151 | + return memchr (s, c, limit - s); | |
| 3152 | } | |
| 3153 | ||
| 3154 | /* Return the address of the first whitespace or null in the string S. */ | |
| 3155 | @@ -468,10 +472,9 @@ | |
| 3156 | char * | |
| 3157 | end_of_token (const char *s) | |
| 3158 | {
| |
| 3159 | - while (*s != '\0' && !isblank ((unsigned char)*s)) | |
| 3160 | - ++s; | |
| 3161 | - return (char *)s; | |
| 3162 | + return (char *) s + strcspn (s, " \t"); | |
| 3163 | } | |
| 3164 | +#endif /* !__GNUC__ */ | |
| 3165 | ||
| 3166 | #ifdef WINDOWS32 | |
| 3167 | /* | |
| 3168 | @@ -503,15 +506,15 @@ | |
| 3169 | } | |
| 3170 | #endif | |
| 3171 | ||
| 3172 | +#ifndef __GNUC__ | |
| 3173 | /* Return the address of the first nonwhitespace or null in the string S. */ | |
| 3174 | ||
| 3175 | char * | |
| 3176 | next_token (const char *s) | |
| 3177 | {
| |
| 3178 | - while (isblank ((unsigned char)*s)) | |
| 3179 | - ++s; | |
| 3180 | - return (char *)s; | |
| 3181 | + return (char *) s + strspn (s, " \t"); | |
| 3182 | } | |
| 3183 | +#endif /* !__GNUC__ */ | |
| 3184 | ||
| 3185 | /* Find the next token in PTR; return the address of it, and store the length | |
| 3186 | of the token into *LENGTHPTR if LENGTHPTR is not nil. Set *PTR to the end | |
| 3187 | Index: read.c | |
| 3188 | =================================================================== | |
| 3189 | RCS file: /sources/make/make/read.c,v | |
| 3190 | retrieving revision 1.210 | |
| 3191 | diff -u -r1.210 read.c | |
| 3192 | --- read.c 5 Mar 2012 14:10:44 -0000 1.210 | |
| 3193 | - | +++ read.c 9 Apr 2012 09:50:05 -0000 |
| 3193 | + | +++ read.c 9 Apr 2012 13:34:42 -0000 |
| 3194 | @@ -566,6 +566,7 @@ | |
| 3195 | const char *pattern_percent; | |
| 3196 | struct floc *fstart; | |
| 3197 | struct floc fi; | |
| 3198 | + struct vbuffer vbuf; | |
| 3199 | ||
| 3200 | #define record_waiting_files() \ | |
| 3201 | do \ | |
| 3202 | @@ -583,6 +584,8 @@ | |
| 3203 | pattern = 0; \ | |
| 3204 | } while (0) | |
| 3205 | ||
| 3206 | + vbuffer_init(&vbuf); | |
| 3207 | + | |
| 3208 | pattern_percent = 0; | |
| 3209 | cmds_started = tgts_started = 1; | |
| 3210 | ||
| 3211 | @@ -893,6 +896,7 @@ | |
| 3212 | {
| |
| 3213 | enum make_word_type wtype; | |
| 3214 | char *cmdleft, *semip, *lb_next; | |
| 3215 | + unsigned int llen = 0; | |
| 3216 | unsigned int plen = 0; | |
| 3217 | char *colonp; | |
| 3218 | const char *end, *beg; /* Helpers for whitespace stripping. */ | |
| 3219 | @@ -943,7 +947,8 @@ | |
| 3220 | break; | |
| 3221 | } | |
| 3222 | ||
| 3223 | - p2 = variable_expand_string(NULL, lb_next, wlen); | |
| 3224 | + vbuffer_expand_ro (vbuffer_reset(&vbuf), lb_next, wlen); | |
| 3225 | + p2 = vbuf.buffer; | |
| 3226 | ||
| 3227 | while (1) | |
| 3228 | {
| |
| 3229 | @@ -955,9 +960,8 @@ | |
| 3230 | ||
| 3231 | if (cmdleft != 0) | |
| 3232 | {
| |
| 3233 | - unsigned long p2_off = p2 - variable_buffer; | |
| 3234 | - unsigned long cmd_off = cmdleft - variable_buffer; | |
| 3235 | - char *pend = p2 + strlen(p2); | |
| 3236 | + unsigned long p2_off = p2 - vbuf.buffer; | |
| 3237 | + unsigned long cmd_off = cmdleft - vbuf.buffer; | |
| 3238 | ||
| 3239 | /* Append any remnants of lb, then cut the line short | |
| 3240 | at the semicolon. */ | |
| 3241 | @@ -967,14 +971,16 @@ | |
| 3242 | here, but merely copy, since now you're beyond a ";" | |
| 3243 | and into a command script. However, the old parser | |
| 3244 | expanded the whole line, so we continue that for | |
| 3245 | - backwards-compatiblity. Also, it wouldn't be | |
| 3246 | + backwards-compatibility. Also, it wouldn't be | |
| 3247 | entirely consistent, since we do an unconditional | |
| 3248 | expand below once we know we don't have a | |
| 3249 | target-specific variable. */ | |
| 3250 | - (void)variable_expand_string(pend, lb_next, (long)-1); | |
| 3251 | + vbuffer_expand_ro (&vbuf, lb_next, -1); | |
| 3252 | + | |
| 3253 | + p2 = vbuf.buffer + p2_off; | |
| 3254 | + cmdleft = vbuf.buffer + cmd_off + 1; | |
| 3255 | + | |
| 3256 | lb_next += strlen(lb_next); | |
| 3257 | - p2 = variable_buffer + p2_off; | |
| 3258 | - cmdleft = variable_buffer + cmd_off + 1; | |
| 3259 | } | |
| 3260 | } | |
| 3261 | ||
| 3262 | @@ -996,15 +1002,16 @@ | |
| 3263 | if (wtype == w_eol) | |
| 3264 | break; | |
| 3265 | ||
| 3266 | - p2 += strlen(p2); | |
| 3267 | - *(p2++) = ' '; | |
| 3268 | - p2 = variable_expand_string(p2, lb_next, wlen); | |
| 3269 | + vbuffer_write(&vbuf, " ", 1); | |
| 3270 | + plen = vbuffer_expand_ro (&vbuf, lb_next, wlen); | |
| 3271 | + p2 = vbuf.ptr - plen; | |
| 3272 | + | |
| 3273 | /* We don't need to worry about cmdleft here, because if it was | |
| 3274 | found in the variable_buffer the entire buffer has already | |
| 3275 | been expanded... we'll never get here. */ | |
| 3276 | } | |
| 3277 | ||
| 3278 | - p2 = next_token (variable_buffer); | |
| 3279 | + p2 = next_token (vbuf.buffer); | |
| 3280 | ||
| 3281 | /* If the word we're looking at is EOL, see if there's _anything_ | |
| 3282 | on the line. If not, a variable expanded to nothing, so ignore | |
| 3283 | @@ -1045,14 +1052,13 @@ | |
| 3284 | ||
| 3285 | /* Test to see if it's a target-specific variable. Copy the rest | |
| 3286 | of the buffer over, possibly temporarily (we'll expand it later | |
| 3287 | - if it's not a target-specific variable). PLEN saves the length | |
| 3288 | - of the unparsed section of p2, for later. */ | |
| 3289 | + if it's not a target-specific variable). LLEN saves the length | |
| 3290 | + of the copied string, to know how many bytes to discard later. */ | |
| 3291 | if (*lb_next != '\0') | |
| 3292 | {
| |
| 3293 | - unsigned int l = p2 - variable_buffer; | |
| 3294 | - plen = strlen (p2); | |
| 3295 | - variable_buffer_output (p2+plen, lb_next, strlen (lb_next)+1); | |
| 3296 | - p2 = variable_buffer + l; | |
| 3297 | + unsigned long p2_off = p2 - vbuf.buffer; | |
| 3298 | + llen = vbuffer_write (&vbuf, lb_next, -1); | |
| 3299 | + p2 = vbuf.buffer + p2_off; | |
| 3300 | } | |
| 3301 | ||
| 3302 | p2 = parse_var_assignment (p2, &vmod); | |
| 3303 | @@ -1062,12 +1068,11 @@ | |
| 3304 | after it. */ | |
| 3305 | if (semip) | |
| 3306 | {
| |
| 3307 | - unsigned int l = p - variable_buffer; | |
| 3308 | + unsigned long p2_off = p2 - vbuf.buffer; | |
| 3309 | *(--semip) = ';'; | |
| 3310 | collapse_continuations (semip); | |
| 3311 | - variable_buffer_output (p2 + strlen (p2), | |
| 3312 | - semip, strlen (semip)+1); | |
| 3313 | - p = variable_buffer + l; | |
| 3314 | + vbuffer_write (&vbuf, semip, -1); | |
| 3315 | + p2 = vbuf.buffer + p2_off; | |
| 3316 | } | |
| 3317 | record_target_var (filenames, p2, | |
| 3318 | vmod.override_v ? o_override : o_file, | |
| 3319 | @@ -1086,12 +1091,14 @@ | |
| 3320 | /* We have some targets, so don't ignore the following commands. */ | |
| 3321 | no_targets = 0; | |
| 3322 | ||
| 3323 | - /* Expand the dependencies, etc. */ | |
| 3324 | + /* Expand the dependencies, etc. | |
| 3325 | + P2 still point past the colon. */ | |
| 3326 | if (*lb_next != '\0') | |
| 3327 | {
| |
| 3328 | - unsigned int l = p2 - variable_buffer; | |
| 3329 | - (void) variable_expand_string (p2 + plen, lb_next, (long)-1); | |
| 3330 | - p2 = variable_buffer + l; | |
| 3331 | + unsigned long p2_off = p2 - vbuf.buffer; | |
| 3332 | + vbuffer_unwrite (&vbuf, llen); | |
| 3333 | + vbuffer_expand_ro (&vbuf, lb_next, -1); | |
| 3334 | + p2 = vbuf.buffer + p2_off; | |
| 3335 | ||
| 3336 | /* Look for a semicolon in the expanded line. */ | |
| 3337 | if (cmdleft == 0) | |
| 3338 | @@ -1281,8 +1288,6 @@ | |
| 3339 | record_waiting_files (); | |
| 3340 | } | |
| 3341 | ||
| 3342 | -#undef word1eq | |
| 3343 | - | |
| 3344 | if (conditionals->if_cmds) | |
| 3345 | fatal (fstart, _("missing 'endif'"));
| |
| 3346 | ||
| 3347 | @@ -1292,7 +1297,13 @@ | |
| 3348 | if (collapsed) | |
| 3349 | free (collapsed); | |
| 3350 | free (commands); | |
| 3351 | + | |
| 3352 | + vbuffer_free(&vbuf); | |
| 3353 | + | |
| 3354 | +#undef record_waiting_files | |
| 3355 | } | |
| 3356 | + | |
| 3357 | +#undef word1eq | |
| 3358 | ||
| 3359 | ||
| 3360 | /* Remove comments from LINE. | |
| 3361 | @@ -1842,6 +1853,7 @@ | |
| 3362 | struct dep *deps; | |
| 3363 | const char *implicit_percent; | |
| 3364 | const char *name; | |
| 3365 | + struct vbuffer patbuf; | |
| 3366 | ||
| 3367 | /* If we've already snapped deps, that means we're in an eval being | |
| 3368 | resolved after the makefiles have been read in. We can't add more rules | |
| 3369 | @@ -1945,6 +1957,7 @@ | |
| 3370 | return; | |
| 3371 | } | |
| 3372 | ||
| 3373 | + vbuffer_init (&patbuf); | |
| 3374 | ||
| 3375 | /* Walk through each target and create it in the database. | |
| 3376 | We already set up the first target, above. */ | |
| 3377 | @@ -2057,10 +2070,12 @@ | |
| 3378 | if (pattern) | |
| 3379 | {
| |
| 3380 | static const char *percent = "%"; | |
| 3381 | - char *buffer = variable_expand ("");
| |
| 3382 | - char *o = patsubst_expand_pat (buffer, name, pattern, percent, | |
| 3383 | - pattern_percent+1, percent+1); | |
| 3384 | - f->stem = strcache_add_len (buffer, o - buffer); | |
| 3385 | + size_t len; | |
| 3386 | + | |
| 3387 | + len = patsubst_expand_pat (vbuffer_reset(&patbuf), name, | |
| 3388 | + pattern, percent, | |
| 3389 | + pattern_percent+1, percent+1); | |
| 3390 | + f->stem = strcache_add_len (patbuf.buffer, len); | |
| 3391 | if (this) | |
| 3392 | {
| |
| 3393 | if (! this->need_2nd_expansion) | |
| 3394 | @@ -2112,6 +2127,8 @@ | |
| 3395 | if (find_percent_cached (&name)) | |
| 3396 | fatal (flocp, _("mixed implicit and normal rules"));
| |
| 3397 | } | |
| 3398 | + | |
| 3399 | + vbuffer_free (&patbuf); | |
| 3400 | } | |
| 3401 | ||
| 3402 | /* Search STRING for an unquoted STOPCHAR or blank (if BLANK is nonzero). | |
| 3403 | Index: remake.c | |
| 3404 | =================================================================== | |
| 3405 | RCS file: /sources/make/make/remake.c,v | |
| 3406 | retrieving revision 1.153 | |
| 3407 | diff -u -r1.153 remake.c | |
| 3408 | --- remake.c 5 Mar 2012 14:10:45 -0000 1.153 | |
| 3409 | - | +++ remake.c 9 Apr 2012 09:50:05 -0000 |
| 3409 | + | +++ remake.c 9 Apr 2012 13:34:42 -0000 |
| 3410 | @@ -1534,12 +1534,14 @@ | |
| 3411 | const char *p2; | |
| 3412 | unsigned int len; | |
| 3413 | unsigned int liblen; | |
| 3414 | + struct vbuffer vbuf; | |
| 3415 | ||
| 3416 | /* Information about the earliest (in the vpath sequence) match. */ | |
| 3417 | unsigned int best_vpath = 0, best_path = 0; | |
| 3418 | ||
| 3419 | char **dp; | |
| 3420 | ||
| 3421 | + vbuffer_init(&vbuf); | |
| 3422 | libpatterns = xstrdup (variable_expand ("$(.LIBPATTERNS)"));
| |
| 3423 | ||
| 3424 | /* Skip the '-l'. */ | |
| 3425 | @@ -1556,28 +1558,30 @@ | |
| 3426 | static unsigned int buflen = 0; | |
| 3427 | static int libdir_maxlen = -1; | |
| 3428 | static unsigned int std_dirs = 0; | |
| 3429 | - char *libbuf = variable_expand ("");
| |
| 3430 | + char *libbuf; | |
| 3431 | ||
| 3432 | /* Expand the pattern using LIB as a replacement. */ | |
| 3433 | {
| |
| 3434 | char c = p[len]; | |
| 3435 | - char *p3, *p4; | |
| 3436 | + char *percent; | |
| 3437 | ||
| 3438 | p[len] = '\0'; | |
| 3439 | - p3 = find_percent (p); | |
| 3440 | - if (!p3) | |
| 3441 | + percent = find_percent (p); | |
| 3442 | + if (!percent) | |
| 3443 | {
| |
| 3444 | /* Give a warning if there is no pattern. */ | |
| 3445 | error (NILF, _(".LIBPATTERNS element '%s' is not a pattern"), p);
| |
| 3446 | p[len] = c; | |
| 3447 | continue; | |
| 3448 | } | |
| 3449 | - p4 = variable_buffer_output (libbuf, p, p3-p); | |
| 3450 | - p4 = variable_buffer_output (p4, lib, liblen); | |
| 3451 | - p4 = variable_buffer_output (p4, p3+1, len - (p3-p)); | |
| 3452 | + vbuffer_write (&vbuf, p, percent-p); | |
| 3453 | + vbuffer_write (&vbuf, lib, liblen); | |
| 3454 | + vbuffer_write (&vbuf, percent+1, len - (percent-p)); | |
| 3455 | p[len] = c; | |
| 3456 | } | |
| 3457 | ||
| 3458 | + libbuf = vbuf.buffer; | |
| 3459 | + | |
| 3460 | /* Look first for 'libNAME.a' in the current directory. */ | |
| 3461 | mtime = name_mtime (libbuf); | |
| 3462 | if (mtime != NONEXISTENT_MTIME) | |
| 3463 | @@ -1660,5 +1664,7 @@ | |
| 3464 | } | |
| 3465 | ||
| 3466 | free (libpatterns); | |
| 3467 | + vbuffer_free(&vbuf); | |
| 3468 | + | |
| 3469 | return file; | |
| 3470 | } | |
| 3471 | Index: variable.c | |
| 3472 | =================================================================== | |
| 3473 | RCS file: /sources/make/make/variable.c,v | |
| 3474 | retrieving revision 1.112 | |
| 3475 | diff -u -r1.112 variable.c | |
| 3476 | --- variable.c 5 Mar 2012 14:10:45 -0000 1.112 | |
| 3477 | - | +++ variable.c 9 Apr 2012 09:50:05 -0000 |
| 3477 | + | +++ variable.c 9 Apr 2012 13:34:42 -0000 |
| 3478 | @@ -172,6 +172,7 @@ | |
| 3479 | static struct variable_set_list global_setlist | |
| 3480 | = { 0, &global_variable_set, 0 };
| |
| 3481 | struct variable_set_list *current_variable_set_list = &global_setlist; | |
| 3482 | + | |
| 3483 | ||
| 3484 | /* Implement variables. */ | |
| 3485 | ||
| 3486 | @@ -182,18 +183,19 @@ | |
| 3487 | variable_hash_1, variable_hash_2, variable_hash_cmp); | |
| 3488 | } | |
| 3489 | ||
| 3490 | -/* Define variable named NAME with value VALUE in SET. VALUE is copied. | |
| 3491 | +/* Define variable named NAME with value VALUE in SET. VALUE is NOT copied, | |
| 3492 | + and after a call client must check whether the VALUE is assigned or not. | |
| 3493 | LENGTH is the length of NAME, which does not need to be null-terminated. | |
| 3494 | ORIGIN specifies the origin of the variable (makefile, command line | |
| 3495 | or environment). | |
| 3496 | If RECURSIVE is nonzero a flag is set in the variable saying | |
| 3497 | that it should be recursively re-expanded. */ | |
| 3498 | ||
| 3499 | -struct variable * | |
| 3500 | -define_variable_in_set (const char *name, unsigned int length, | |
| 3501 | - const char *value, enum variable_origin origin, | |
| 3502 | - int recursive, struct variable_set *set, | |
| 3503 | - const struct floc *flocp) | |
| 3504 | +static struct variable * | |
| 3505 | +define_variable_in_set_allocated (const char *name, unsigned int length, | |
| 3506 | + const char *value, enum variable_origin origin, | |
| 3507 | + int recursive, struct variable_set *set, | |
| 3508 | + const struct floc *flocp) | |
| 3509 | {
| |
| 3510 | struct variable *v; | |
| 3511 | struct variable **var_slot; | |
| 3512 | @@ -224,7 +226,7 @@ | |
| 3513 | {
| |
| 3514 | if (v->value != 0) | |
| 3515 | free (v->value); | |
| 3516 | - v->value = xstrdup (value); | |
| 3517 | + v->value = (char *) value; | |
| 3518 | if (flocp != 0) | |
| 3519 | v->fileinfo = *flocp; | |
| 3520 | else | |
| 3521 | @@ -241,7 +243,7 @@ | |
| 3522 | v->name = xstrndup (name, length); | |
| 3523 | v->length = length; | |
| 3524 | hash_insert_at (&set->table, v, var_slot); | |
| 3525 | - v->value = xstrdup (value); | |
| 3526 | + v->value = (char *) value; | |
| 3527 | if (flocp != 0) | |
| 3528 | v->fileinfo = *flocp; | |
| 3529 | else | |
| 3530 | @@ -254,6 +256,8 @@ | |
| 3531 | v->per_target = 0; | |
| 3532 | v->append = 0; | |
| 3533 | v->private_var = 0; | |
| 3534 | + v->volatile_var = 0; | |
| 3535 | + v->global = set == &global_variable_set; | |
| 3536 | v->export = v_default; | |
| 3537 | ||
| 3538 | v->exportable = 1; | |
| 3539 | @@ -275,6 +279,71 @@ | |
| 3540 | } | |
| 3541 | ||
| 3542 | ||
| 3543 | +struct variable * | |
| 3544 | +define_variable_in_set (const char *name, unsigned int length, | |
| 3545 | + const char *value, enum variable_origin origin, | |
| 3546 | + int recursive, struct variable_set *set, | |
| 3547 | + const struct floc *flocp) | |
| 3548 | +{
| |
| 3549 | + struct variable *v = define_variable_in_set_allocated (name, length, value, | |
| 3550 | + origin, recursive, | |
| 3551 | + set, flocp); | |
| 3552 | + /* Check if the new value was really assigned. */ | |
| 3553 | + if (v->value == value) | |
| 3554 | + v->value = xstrdup (value); | |
| 3555 | + | |
| 3556 | + return v; | |
| 3557 | +} | |
| 3558 | + | |
| 3559 | +struct variable * | |
| 3560 | +push_scoped_variable (struct variable *v, char *name, unsigned int length) | |
| 3561 | +{
| |
| 3562 | + struct variable_set *set = current_variable_set_list->set; | |
| 3563 | + struct variable *old_var; | |
| 3564 | + struct variable **var_slot; | |
| 3565 | + | |
| 3566 | + v->name = name; | |
| 3567 | + v->length = length; | |
| 3568 | + var_slot = (struct variable **) hash_find_slot (&set->table, v); | |
| 3569 | + | |
| 3570 | + old_var = *var_slot; | |
| 3571 | + if (HASH_VACANT (old_var)) | |
| 3572 | + old_var = NULL; | |
| 3573 | + | |
| 3574 | + hash_insert_at (&set->table, v, var_slot); | |
| 3575 | + | |
| 3576 | + v->fileinfo.filenm = NULL; | |
| 3577 | + v->origin = o_automatic; | |
| 3578 | + v->recursive = 0; | |
| 3579 | + v->special = 0; | |
| 3580 | + v->expanding = 0; | |
| 3581 | + v->exp_count = 0; | |
| 3582 | + v->per_target = 0; | |
| 3583 | + v->append = 0; | |
| 3584 | + v->private_var = 0; | |
| 3585 | + v->volatile_var = 0; | |
| 3586 | + v->exportable = 0; | |
| 3587 | + v->export = v_default; | |
| 3588 | + | |
| 3589 | + v->global = old_var ? old_var->global : 0; | |
| 3590 | + | |
| 3591 | + return old_var; | |
| 3592 | +} | |
| 3593 | + | |
| 3594 | +void | |
| 3595 | +pop_scoped_variable (struct variable *v, struct variable *old_var) | |
| 3596 | +{
| |
| 3597 | + struct variable_set *set = current_variable_set_list->set; | |
| 3598 | + struct variable **var_slot; | |
| 3599 | + | |
| 3600 | + var_slot = (struct variable **) hash_find_slot (&set->table, v); | |
| 3601 | + | |
| 3602 | + if (old_var) | |
| 3603 | + hash_insert_at (&set->table, old_var, var_slot); | |
| 3604 | + else | |
| 3605 | + hash_delete_at (&set->table, var_slot); | |
| 3606 | +} | |
| 3607 | + | |
| 3608 | /* Undefine variable named NAME in SET. LENGTH is the length of NAME, which | |
| 3609 | does not need to be null-terminated. ORIGIN specifies the origin of the | |
| 3610 | variable (makefile, command line or environment). */ | |
| 3611 | @@ -361,7 +430,8 @@ | |
| 3612 | */ | |
| 3613 | ||
| 3614 | if (streq (var->name, ".VARIABLES") | |
| 3615 | - && global_variable_set.table.ht_fill != last_var_count) | |
| 3616 | +// && global_variable_set.table.ht_fill != last_var_count | |
| 3617 | + ) | |
| 3618 | {
| |
| 3619 | unsigned long max = EXPANSION_INCREMENT (strlen (var->value)); | |
| 3620 | unsigned long len; | |
| 3621 | @@ -381,6 +451,9 @@ | |
| 3622 | struct variable *v = *vp; | |
| 3623 | int l = v->length; | |
| 3624 | ||
| 3625 | + if (!v->global) | |
| 3626 | + continue; | |
| 3627 | + | |
| 3628 | len += l + 1; | |
| 3629 | if (len > max) | |
| 3630 | {
| |
| 3631 | @@ -408,26 +481,89 @@ | |
| 3632 | } | |
| 3633 | ||
| 3634 | ||
| 3635 | +static struct call_frame empty_call_frame; | |
| 3636 | +struct call_frame *current_call_frame = &empty_call_frame; | |
| 3637 | + | |
| 3638 | +#ifdef __GNUC__ | |
| 3639 | +__inline | |
| 3640 | +#endif | |
| 3641 | +char ** | |
| 3642 | +lookup_call_argument_value (const char *name, unsigned int length) | |
| 3643 | +{
| |
| 3644 | + int num = 0; | |
| 3645 | + const char *p; | |
| 3646 | + | |
| 3647 | + /* Hot path: a single digit. */ | |
| 3648 | + if (length == 1 | |
| 3649 | + && (unsigned) *name - '0' < (unsigned) current_call_frame->argc) | |
| 3650 | + return current_call_frame->argv + (*name - '0'); | |
| 3651 | + | |
| 3652 | + /* Empty name or name with leading zeroes is not numeric. */ | |
| 3653 | + if (length == 0 || *name == '0') | |
| 3654 | + return NULL; | |
| 3655 | + | |
| 3656 | + for (p=name; length != 0 && ISDIGIT(*p); --length, ++p) | |
| 3657 | + {
| |
| 3658 | + num *= 10; | |
| 3659 | + num += *p - '0'; | |
| 3660 | + } | |
| 3661 | + | |
| 3662 | + if (length != 0 || num >= current_call_frame->argc) | |
| 3663 | + return NULL; | |
| 3664 | + | |
| 3665 | + return current_call_frame->argv + num; | |
| 3666 | +} | |
| 3667 | + | |
| 3668 | +#define CALL_ARGUMENT_INIT \ | |
| 3669 | + { \
| |
| 3670 | + /* name */ "", /* value */ "", \ | |
| 3671 | + /* file */ { NULL, 0}, /* length */ 0, \
| |
| 3672 | + /* recursive */ 0, /* append */ 0, \ | |
| 3673 | + /* conditional */ 0, /* per_target */ 0, \ | |
| 3674 | + /* special */ 0, /* exportable */ 0, \ | |
| 3675 | + /* expanding */ 0, /* private */ 0, \ | |
| 3676 | + /* volatile */ 1, /* global */ 0, \ | |
| 3677 | + /* exp_count */ 0, \ | |
| 3678 | + f_simple, o_automatic, v_default, \ | |
| 3679 | + } | |
| 3680 | + | |
| 3681 | /* Lookup a variable whose name is a string starting at NAME | |
| 3682 | and with LENGTH chars. NAME need not be null-terminated. | |
| 3683 | Returns address of the 'struct variable' containing all info | |
| 3684 | - on the variable, or nil if no such variable is defined. */ | |
| 3685 | + on the variable, or nil if no such variable is defined. | |
| 3686 | + In case when the variable is an argument of the current call frame, | |
| 3687 | + the 'struct variable' refers to the shared statically allocated instance, | |
| 3688 | + and its 'volatile_var' field is set to 1. */ | |
| 3689 | ||
| 3690 | struct variable * | |
| 3691 | lookup_variable (const char *name, unsigned int length) | |
| 3692 | {
| |
| 3693 | + static struct variable call_argument = CALL_ARGUMENT_INIT; | |
| 3694 | const struct variable_set_list *setlist; | |
| 3695 | + struct variable *v = NULL; | |
| 3696 | struct variable var_key; | |
| 3697 | int is_parent = 0; | |
| 3698 | ||
| 3699 | var_key.name = (char *) name; | |
| 3700 | var_key.length = length; | |
| 3701 | ||
| 3702 | + if (ISDIGIT(*name)) | |
| 3703 | + {
| |
| 3704 | + char **argp = lookup_call_argument_value (name, length); | |
| 3705 | + if (argp && *argp) | |
| 3706 | + {
| |
| 3707 | + v = &call_argument; | |
| 3708 | + v->value = *argp; | |
| 3709 | + v->name = (char *) name; | |
| 3710 | + v->length = length; | |
| 3711 | + return v; | |
| 3712 | + } | |
| 3713 | + } | |
| 3714 | + | |
| 3715 | for (setlist = current_variable_set_list; | |
| 3716 | setlist != 0; setlist = setlist->next) | |
| 3717 | {
| |
| 3718 | const struct variable_set *set = setlist->set; | |
| 3719 | - struct variable *v; | |
| 3720 | ||
| 3721 | v = (struct variable *) hash_find_item ((struct hash_table *) &set->table, &var_key); | |
| 3722 | if (v && (!is_parent || !v->private_var)) | |
| 3723 | @@ -494,6 +630,7 @@ | |
| 3724 | ||
| 3725 | return 0; | |
| 3726 | } | |
| 3727 | + | |
| 3728 | ||
| 3729 | /* Lookup a variable whose name is a string starting at NAME | |
| 3730 | and with LENGTH chars in set SET. NAME need not be null-terminated. | |
| 3731 | @@ -512,6 +649,7 @@ | |
| 3732 | return (struct variable *) hash_find_item ((struct hash_table *) &set->table, &var_key); | |
| 3733 | } | |
| 3734 | ||
| 3735 | + | |
| 3736 | /* Initialize FILE's variable set list. If FILE already has a variable set | |
| 3737 | list, the topmost variable set is left intact, but the the rest of the | |
| 3738 | chain is replaced with FILE->parent's setlist. If FILE is a double-colon | |
| 3739 | @@ -621,8 +759,6 @@ | |
| 3740 | } | |
| 3741 | } | |
| 3742 | ||
| 3743 | -/* Pop the top set off the current variable set list, | |
| 3744 | - and free all its storage. */ | |
| 3745 | ||
| 3746 | struct variable_set_list * | |
| 3747 | create_new_variable_set (void) | |
| 3748 | @@ -660,66 +796,6 @@ | |
| 3749 | free (list); | |
| 3750 | } | |
| 3751 | ||
| 3752 | -/* Create a new variable set and push it on the current setlist. | |
| 3753 | - If we're pushing a global scope (that is, the current scope is the global | |
| 3754 | - scope) then we need to "push" it the other way: file variable sets point | |
| 3755 | - directly to the global_setlist so we need to replace that with the new one. | |
| 3756 | - */ | |
| 3757 | - | |
| 3758 | -struct variable_set_list * | |
| 3759 | -push_new_variable_scope (void) | |
| 3760 | -{
| |
| 3761 | - current_variable_set_list = create_new_variable_set(); | |
| 3762 | - if (current_variable_set_list->next == &global_setlist) | |
| 3763 | - {
| |
| 3764 | - /* It was the global, so instead of new -> &global we want to replace | |
| 3765 | - &global with the new one and have &global -> new, with current still | |
| 3766 | - pointing to &global */ | |
| 3767 | - struct variable_set *set = current_variable_set_list->set; | |
| 3768 | - current_variable_set_list->set = global_setlist.set; | |
| 3769 | - global_setlist.set = set; | |
| 3770 | - current_variable_set_list->next = global_setlist.next; | |
| 3771 | - global_setlist.next = current_variable_set_list; | |
| 3772 | - current_variable_set_list = &global_setlist; | |
| 3773 | - } | |
| 3774 | - return (current_variable_set_list); | |
| 3775 | -} | |
| 3776 | - | |
| 3777 | -void | |
| 3778 | -pop_variable_scope (void) | |
| 3779 | -{
| |
| 3780 | - struct variable_set_list *setlist; | |
| 3781 | - struct variable_set *set; | |
| 3782 | - | |
| 3783 | - /* Can't call this if there's no scope to pop! */ | |
| 3784 | - assert(current_variable_set_list->next != NULL); | |
| 3785 | - | |
| 3786 | - if (current_variable_set_list != &global_setlist) | |
| 3787 | - {
| |
| 3788 | - /* We're not pointing to the global setlist, so pop this one. */ | |
| 3789 | - setlist = current_variable_set_list; | |
| 3790 | - set = setlist->set; | |
| 3791 | - current_variable_set_list = setlist->next; | |
| 3792 | - } | |
| 3793 | - else | |
| 3794 | - {
| |
| 3795 | - /* This set is the one in the global_setlist, but there is another global | |
| 3796 | - set beyond that. We want to copy that set to global_setlist, then | |
| 3797 | - delete what used to be in global_setlist. */ | |
| 3798 | - setlist = global_setlist.next; | |
| 3799 | - set = global_setlist.set; | |
| 3800 | - global_setlist.set = setlist->set; | |
| 3801 | - global_setlist.next = setlist->next; | |
| 3802 | - global_setlist.next_is_parent = setlist->next_is_parent; | |
| 3803 | - } | |
| 3804 | - | |
| 3805 | - /* Free the one we no longer need. */ | |
| 3806 | - free (setlist); | |
| 3807 | - hash_map (&set->table, free_variable_name_and_value); | |
| 3808 | - hash_free (&set->table, 1); | |
| 3809 | - free (set); | |
| 3810 | -} | |
| 3811 | - | |
| 3812 | /* Merge FROM_SET into TO_SET, freeing unused storage in FROM_SET. */ | |
| 3813 | ||
| 3814 | static void | |
| 3815 | @@ -966,6 +1042,7 @@ | |
| 3816 | struct variable makelevel_key; | |
| 3817 | char **result_0; | |
| 3818 | char **result; | |
| 3819 | + struct vbuffer vbuf; | |
| 3820 | ||
| 3821 | if (file == 0) | |
| 3822 | set_list = current_variable_set_list; | |
| 3823 | @@ -1053,6 +1130,8 @@ | |
| 3824 | ||
| 3825 | result = result_0 = xmalloc ((table.ht_fill + 2) * sizeof (char *)); | |
| 3826 | ||
| 3827 | + vbuffer_init (&vbuf); | |
| 3828 | + | |
| 3829 | v_slot = (struct variable **) table.ht_vec; | |
| 3830 | v_end = v_slot + table.ht_size; | |
| 3831 | for ( ; v_slot < v_end; v_slot++) | |
| 3832 | @@ -1060,32 +1139,30 @@ | |
| 3833 | {
| |
| 3834 | struct variable *v = *v_slot; | |
| 3835 | ||
| 3836 | + vbuffer_reset (&vbuf); | |
| 3837 | + | |
| 3838 | + vbuffer_write (&vbuf, v->name, -1); | |
| 3839 | + vbuffer_write (&vbuf, "=", 1); | |
| 3840 | + | |
| 3841 | /* If V is recursively expanded and didn't come from the environment, | |
| 3842 | expand its value. If it came from the environment, it should | |
| 3843 | go back into the environment unchanged. */ | |
| 3844 | if (v->recursive | |
| 3845 | && v->origin != o_env && v->origin != o_env_override) | |
| 3846 | - {
| |
| 3847 | - char *value = recursively_expand_for_file (v, file); | |
| 3848 | -#ifdef WINDOWS32 | |
| 3849 | - if (strcmp(v->name, "Path") == 0 || | |
| 3850 | - strcmp(v->name, "PATH") == 0) | |
| 3851 | - convert_Path_to_windows32(value, ';'); | |
| 3852 | -#endif | |
| 3853 | - *result++ = xstrdup (concat (3, v->name, "=", value)); | |
| 3854 | - free (value); | |
| 3855 | - } | |
| 3856 | + vbuffer_expand_variable_for_file (&vbuf, v, file); | |
| 3857 | else | |
| 3858 | - {
| |
| 3859 | + vbuffer_write (&vbuf, v->value, -1); | |
| 3860 | + | |
| 3861 | #ifdef WINDOWS32 | |
| 3862 | - if (strcmp(v->name, "Path") == 0 || | |
| 3863 | - strcmp(v->name, "PATH") == 0) | |
| 3864 | - convert_Path_to_windows32(v->value, ';'); | |
| 3865 | + if (strcmp(v->name, "Path") == 0 || | |
| 3866 | + strcmp(v->name, "PATH") == 0) | |
| 3867 | + convert_Path_to_windows32(value, ';'); | |
| 3868 | #endif | |
| 3869 | - *result++ = xstrdup (concat (3, v->name, "=", v->value)); | |
| 3870 | - } | |
| 3871 | + *result++ = xstrdup (vbuf.buffer); | |
| 3872 | } | |
| 3873 | ||
| 3874 | + vbuffer_free (&vbuf); | |
| 3875 | + | |
| 3876 | *result = xmalloc (100); | |
| 3877 | sprintf (*result, "%s=%u", MAKELEVEL_NAME, makelevel + 1); | |
| 3878 | *++result = 0; | |
| 3879 | @@ -1116,20 +1193,14 @@ | |
| 3880 | char * | |
| 3881 | shell_result (const char *p) | |
| 3882 | {
| |
| 3883 | - char *buf; | |
| 3884 | - unsigned int len; | |
| 3885 | + struct vbuffer vbuf; | |
| 3886 | char *args[2]; | |
| 3887 | - char *result; | |
| 3888 | - | |
| 3889 | - install_variable_buffer (&buf, &len); | |
| 3890 | ||
| 3891 | args[0] = (char *) p; | |
| 3892 | args[1] = NULL; | |
| 3893 | - variable_buffer_output (func_shell_base (variable_buffer, args, 0), "\0", 1); | |
| 3894 | - result = strdup (variable_buffer); | |
| 3895 | + func_shell_base (vbuffer_init(&vbuf), args, 0); | |
| 3896 | ||
| 3897 | - restore_variable_buffer (buf, len); | |
| 3898 | - return result; | |
| 3899 | + return vbuf.buffer; | |
| 3900 | } | |
| 3901 | ||
| 3902 | /* Given a variable, a value, and a flavor, define the variable. | |
| 3903 | @@ -1145,6 +1216,7 @@ | |
| 3904 | struct variable *v; | |
| 3905 | int append = 0; | |
| 3906 | int conditional = 0; | |
| 3907 | + unsigned int varlen = strlen (varname); | |
| 3908 | ||
| 3909 | /* Calculate the variable's new value in VALUE. */ | |
| 3910 | ||
| 3911 | @@ -1174,7 +1246,7 @@ | |
| 3912 | case f_conditional: | |
| 3913 | /* A conditional variable definition "var ?= value". | |
| 3914 | The value is set IFF the variable is not defined yet. */ | |
| 3915 | - v = lookup_variable (varname, strlen (varname)); | |
| 3916 | + v = lookup_variable (varname, varlen); | |
| 3917 | if (v) | |
| 3918 | return v->special ? set_special_var (v) : v; | |
| 3919 | ||
| 3920 | @@ -1193,7 +1265,7 @@ | |
| 3921 | if (target_var) | |
| 3922 | {
| |
| 3923 | append = 1; | |
| 3924 | - v = lookup_variable_in_set (varname, strlen (varname), | |
| 3925 | + v = lookup_variable_in_set (varname, varlen, | |
| 3926 | current_variable_set_list->set); | |
| 3927 | ||
| 3928 | /* Don't append from the global set if a previous non-appending | |
| 3929 | @@ -1202,7 +1274,7 @@ | |
| 3930 | append = 0; | |
| 3931 | } | |
| 3932 | else | |
| 3933 | - v = lookup_variable (varname, strlen (varname)); | |
| 3934 | + v = lookup_variable (varname, varlen); | |
| 3935 | ||
| 3936 | if (v == 0) | |
| 3937 | {
| |
| 3938 | @@ -1274,7 +1346,7 @@ | |
| 3939 | if (*tp == '\\') | |
| 3940 | *tp = '/'; | |
| 3941 | ||
| 3942 | - v = define_variable_loc (varname, strlen (varname), | |
| 3943 | + v = define_variable_loc (varname, varlen, | |
| 3944 | shellpath, origin, flavor == f_recursive, | |
| 3945 | flocp); | |
| 3946 | } | |
| 3947 | @@ -1314,12 +1386,12 @@ | |
| 3948 | if (*tp == '\\') | |
| 3949 | *tp = '/'; | |
| 3950 | ||
| 3951 | - v = define_variable_loc (varname, strlen (varname), | |
| 3952 | + v = define_variable_loc (varname, varlen, | |
| 3953 | shellpath, origin, | |
| 3954 | flavor == f_recursive, flocp); | |
| 3955 | } | |
| 3956 | else | |
| 3957 | - v = lookup_variable (varname, strlen (varname)); | |
| 3958 | + v = lookup_variable (varname, varlen); | |
| 3959 | ||
| 3960 | free (path_string); | |
| 3961 | } | |
| 3962 | @@ -1338,7 +1410,7 @@ | |
| 3963 | ||
| 3964 | if (find_and_set_default_shell (p)) | |
| 3965 | {
| |
| 3966 | - v = define_variable_in_set (varname, strlen (varname), default_shell, | |
| 3967 | + v = define_variable_in_set (varname, varlen, default_shell, | |
| 3968 | origin, flavor == f_recursive, | |
| 3969 | (target_var | |
| 3970 | ? current_variable_set_list->set | |
| 3971 | @@ -1354,7 +1426,7 @@ | |
| 3972 | ||
| 3973 | if (find_and_set_default_shell (alloc_value)) | |
| 3974 | {
| |
| 3975 | - v = define_variable_in_set (varname, strlen (varname), p, | |
| 3976 | + v = define_variable_in_set (varname, varlen, p, | |
| 3977 | origin, flavor == f_recursive, | |
| 3978 | (target_var | |
| 3979 | ? current_variable_set_list->set | |
| 3980 | @@ -1363,7 +1435,7 @@ | |
| 3981 | no_default_sh_exe = 0; | |
| 3982 | } | |
| 3983 | else | |
| 3984 | - v = lookup_variable (varname, strlen (varname)); | |
| 3985 | + v = lookup_variable (varname, varlen); | |
| 3986 | ||
| 3987 | if (tp) | |
| 3988 | free (tp); | |
| 3989 | @@ -1372,17 +1444,29 @@ | |
| 3990 | else | |
| 3991 | #endif | |
| 3992 | ||
| 3993 | - /* If we are defining variables inside an $(eval ...), we might have a | |
| 3994 | - different variable context pushed, not the global context (maybe we're | |
| 3995 | - inside a $(call ...) or something. Since this function is only ever | |
| 3996 | - invoked in places where we want to define globally visible variables, | |
| 3997 | - make sure we define this variable in the global set. */ | |
| 3998 | - | |
| 3999 | - v = define_variable_in_set (varname, strlen (varname), p, | |
| 4000 | - origin, flavor == f_recursive, | |
| 4001 | - (target_var | |
| 4002 | - ? current_variable_set_list->set : NULL), | |
| 4003 | - flocp); | |
| 4004 | + {
| |
| 4005 | + /* If we are defining variables inside an $(eval ...), we might have a | |
| 4006 | + different variable context pushed, not the global context (maybe we're | |
| 4007 | + inside a $(call ...) or something. Since this function is only ever | |
| 4008 | + invoked in places where we want to define globally visible variables, | |
| 4009 | + make sure we define this variable in the global set. */ | |
| 4010 | + | |
| 4011 | + v = define_variable_in_set_allocated (varname, varlen, alloc_value, | |
| 4012 | + origin, flavor == f_recursive, | |
| 4013 | + (target_var | |
| 4014 | + ? current_variable_set_list->set | |
| 4015 | + : NULL), | |
| 4016 | + flocp); | |
| 4017 | + | |
| 4018 | + if (v->value == alloc_value) | |
| 4019 | + {
| |
| 4020 | + if (!alloc_value) | |
| 4021 | + v->value = xstrdup (p); | |
| 4022 | + else | |
| 4023 | + alloc_value = NULL; | |
| 4024 | + } | |
| 4025 | + } | |
| 4026 | + | |
| 4027 | v->append = append; | |
| 4028 | v->conditional = conditional; | |
| 4029 | ||
| 4030 | Index: variable.h | |
| 4031 | =================================================================== | |
| 4032 | RCS file: /sources/make/make/variable.h,v | |
| 4033 | retrieving revision 1.51 | |
| 4034 | diff -u -r1.51 variable.h | |
| 4035 | --- variable.h 5 Mar 2012 14:10:45 -0000 1.51 | |
| 4036 | - | +++ variable.h 9 Apr 2012 09:50:05 -0000 |
| 4036 | + | +++ variable.h 9 Apr 2012 13:34:42 -0000 |
| 4037 | @@ -44,9 +44,11 @@ | |
| 4038 | Each bucket of the hash table is a chain of these, | |
| 4039 | chained through 'next'. */ | |
| 4040 | ||
| 4041 | -#define EXP_COUNT_BITS 15 /* This gets all the bitfields into 32 bits */ | |
| 4042 | +#define EXP_COUNT_BITS 14 /* This gets all the bitfields into 32 bits */ | |
| 4043 | #define EXP_COUNT_MAX ((1<<EXP_COUNT_BITS)-1) | |
| 4044 | ||
| 4045 | +#define MAX_ALLOCA_SIZE 1024 | |
| 4046 | + | |
| 4047 | struct variable | |
| 4048 | {
| |
| 4049 | char *name; /* Variable name. */ | |
| 4050 | @@ -64,6 +66,10 @@ | |
| 4051 | unsigned int expanding:1; /* Nonzero if currently being expanded. */ | |
| 4052 | unsigned int private_var:1; /* Nonzero avoids inheritance of this | |
| 4053 | target-specific variable. */ | |
| 4054 | + unsigned int volatile_var:1;/* Nonzero if the state can change across | |
| 4055 | + certain function calls. */ | |
| 4056 | + unsigned int global:1; /* Nonzero if this should be included in | |
| 4057 | + $(.VARIABLES) list. */ | |
| 4058 | unsigned int exp_count:EXP_COUNT_BITS; | |
| 4059 | /* If >1, allow this many self-referential | |
| 4060 | expansions. */ | |
| 4061 | @@ -107,44 +113,80 @@ | |
| 4062 | struct variable variable; | |
| 4063 | }; | |
| 4064 | ||
| 4065 | -extern char *variable_buffer; | |
| 4066 | +/* Structure used to hold the result of variable expansion. */ | |
| 4067 | + | |
| 4068 | +struct vbuffer | |
| 4069 | + {
| |
| 4070 | + char *ptr; /* Current position pointing inside the buffer. */ | |
| 4071 | + char *buffer; /* Start of the entire buffer. */ | |
| 4072 | + size_t size; /* Size of the allocated buffer. */ | |
| 4073 | + }; | |
| 4074 | + | |
| 4075 | +struct call_frame | |
| 4076 | + {
| |
| 4077 | + int argc; | |
| 4078 | + char **argv; | |
| 4079 | + }; | |
| 4080 | + | |
| 4081 | extern struct variable_set_list *current_variable_set_list; | |
| 4082 | extern struct variable *default_goal_var; | |
| 4083 | ||
| 4084 | +extern struct call_frame *current_call_frame; | |
| 4085 | + | |
| 4086 | +struct vbuffer *vbuffer_init (struct vbuffer *vbuf); | |
| 4087 | +struct vbuffer *vbuffer_reset (struct vbuffer *vbuf); | |
| 4088 | + | |
| 4089 | +#define vbuffer_free(vbuf) \ | |
| 4090 | + free ((vbuf)->buffer) | |
| 4091 | + | |
| 4092 | +size_t vbuffer_reserve (struct vbuffer *o, size_t len); | |
| 4093 | + | |
| 4094 | +size_t vbuffer_write (struct vbuffer *o, const char *str, ssize_t len); | |
| 4095 | +size_t vbuffer_unwrite (struct vbuffer *o, ssize_t len); | |
| 4096 | + | |
| 4097 | +size_t vbuffer_expand (struct vbuffer *o, char *str, ssize_t len); | |
| 4098 | +size_t vbuffer_expand_for_file (struct vbuffer *o, char *str, ssize_t len, | |
| 4099 | + struct file *file); | |
| 4100 | + | |
| 4101 | +size_t vbuffer_expand_ro (struct vbuffer *o, const char *str, ssize_t len); | |
| 4102 | +size_t vbuffer_expand_ro_for_file (struct vbuffer *o, const char *str, | |
| 4103 | + ssize_t len, struct file *file); | |
| 4104 | + | |
| 4105 | +#define vbuffer_expand_variable(o, v) \ | |
| 4106 | + vbuffer_expand_variable_for_file (o, v, NULL) | |
| 4107 | +size_t vbuffer_expand_variable_for_file (struct vbuffer *o, | |
| 4108 | + struct variable *v, | |
| 4109 | + struct file *file); | |
| 4110 | + | |
| 4111 | +struct vbuffer *install_new_expansion_vbuffer (void); | |
| 4112 | +void restore_expansion_vbuffer (struct vbuffer *old_vbuf); | |
| 4113 | + | |
| 4114 | /* expand.c */ | |
| 4115 | -char *variable_buffer_output (char *ptr, const char *string, unsigned int length); | |
| 4116 | +char *expand_argument (const char *str, const char *end); | |
| 4117 | char *variable_expand (const char *line); | |
| 4118 | char *variable_expand_for_file (const char *line, struct file *file); | |
| 4119 | +char *allocated_variable_expand (const char *line); | |
| 4120 | char *allocated_variable_expand_for_file (const char *line, struct file *file); | |
| 4121 | -#define allocated_variable_expand(line) \ | |
| 4122 | - allocated_variable_expand_for_file (line, (struct file *) 0) | |
| 4123 | -char *expand_argument (const char *str, const char *end); | |
| 4124 | -char *variable_expand_string (char *line, const char *string, long length); | |
| 4125 | -void install_variable_buffer (char **bufp, unsigned int *lenp); | |
| 4126 | -void restore_variable_buffer (char *buf, unsigned int len); | |
| 4127 | +#define recursively_expand(v) recursively_expand_for_file (v, NULL) | |
| 4128 | +char *recursively_expand_for_file (struct variable *v, struct file *file); | |
| 4129 | ||
| 4130 | /* function.c */ | |
| 4131 | -int handle_function (char **op, const char **stringp); | |
| 4132 | +int handle_function (struct vbuffer *vbuf, char **stringp); | |
| 4133 | int pattern_matches (const char *pattern, const char *percent, const char *str); | |
| 4134 | -char *subst_expand (char *o, const char *text, const char *subst, | |
| 4135 | - const char *replace, unsigned int slen, unsigned int rlen, | |
| 4136 | - int by_word); | |
| 4137 | -char *patsubst_expand_pat (char *o, const char *text, const char *pattern, | |
| 4138 | - const char *replace, const char *pattern_percent, | |
| 4139 | - const char *replace_percent); | |
| 4140 | -char *patsubst_expand (char *o, const char *text, char *pattern, char *replace); | |
| 4141 | -char *func_shell_base (char *o, char **argv, int trim_newlines); | |
| 4142 | - | |
| 4143 | - | |
| 4144 | -/* expand.c */ | |
| 4145 | -char *recursively_expand_for_file (struct variable *v, struct file *file); | |
| 4146 | -#define recursively_expand(v) recursively_expand_for_file (v, NULL) | |
| 4147 | +size_t subst_expand (struct vbuffer *vbuf, const char *text, const char *subst, | |
| 4148 | + const char *replace, unsigned int slen, unsigned int rlen, | |
| 4149 | + int by_word); | |
| 4150 | +size_t patsubst_expand_pat (struct vbuffer *vbuf, const char *text, | |
| 4151 | + const char *pattern, const char *replace, | |
| 4152 | + const char *pattern_percent, | |
| 4153 | + const char *replace_percent); | |
| 4154 | +size_t patsubst_expand (struct vbuffer *vbuf, const char *text, char *pattern, | |
| 4155 | + char *replace); | |
| 4156 | +size_t func_shell_base (struct vbuffer *vbuf, char **argv, int trim_newlines); | |
| 4157 | ||
| 4158 | /* variable.c */ | |
| 4159 | struct variable_set_list *create_new_variable_set (void); | |
| 4160 | void free_variable_set (struct variable_set_list *); | |
| 4161 | -struct variable_set_list *push_new_variable_scope (void); | |
| 4162 | -void pop_variable_scope (void); | |
| 4163 | void define_automatic_variables (void); | |
| 4164 | void initialize_file_variables (struct file *file, int reading); | |
| 4165 | void print_file_variables (const struct file *file); | |
| 4166 | @@ -167,10 +209,11 @@ | |
| 4167 | void hash_init_function_table (void); | |
| 4168 | void define_new_function(const struct floc *flocp, | |
| 4169 | const char *name, int min, int max, int expand, | |
| 4170 | - char *(*func)(char *, char **, const char *)); | |
| 4171 | + size_t (*func)(struct vbuffer *, char **, const char *)); | |
| 4172 | struct variable *lookup_variable (const char *name, unsigned int length); | |
| 4173 | struct variable *lookup_variable_in_set (const char *name, unsigned int length, | |
| 4174 | const struct variable_set *set); | |
| 4175 | +char **lookup_call_argument_value (const char *name, unsigned int length); | |
| 4176 | ||
| 4177 | struct variable *define_variable_in_set (const char *name, unsigned int length, | |
| 4178 | const char *value, | |
| 4179 | @@ -207,6 +250,10 @@ | |
| 4180 | #define define_variable_for_file(n,l,v,o,r,f) \ | |
| 4181 | define_variable_in_set((n),(l),(v),(o),(r),(f)->variables->set,NILF) | |
| 4182 | ||
| 4183 | +struct variable *push_scoped_variable (struct variable *v, | |
| 4184 | + char *name, unsigned int length); | |
| 4185 | +void pop_scoped_variable (struct variable *v, struct variable *old_var); | |
| 4186 | + | |
| 4187 | void undefine_variable_in_set (const char *name, unsigned int length, | |
| 4188 | enum variable_origin origin, | |
| 4189 | struct variable_set *set); |