/* Expands the specified string, appending it to the specified variable value. */ void append_expanded_string_to_variable (struct variable *v, const char *value, unsigned int value_len, int append) { char *p = (char *) memchr (value, '$', value_len); if (!p) /* fast path */ append_string_to_variable (v,value, value_len, append); else if (value_len) { unsigned int off_dollar = p - (char *)value; /* Install a fresh variable buffer. */ char *saved_buffer; unsigned int saved_buffer_length; install_variable_buffer (&saved_buffer, &saved_buffer_length); p = variable_buffer; if (append || !v->value_length) { /* Copy the current value into it and append a space. */ if (v->value_length) { p = variable_buffer_output (p, v->value, v->value_length); p = variable_buffer_output (p, " ", 1); } /* Append the assignment value. */ p = variable_buffer_output (p, value, off_dollar); variable_expand_string_2 (p, value + off_dollar, value_len - off_dollar, &p); } else { /* Expand the assignemnt value. */ p = variable_buffer_output (p, value, off_dollar); variable_expand_string_2 (p, value + off_dollar, value_len - off_dollar, &p); /* Append a space followed by the old value. */ p = variable_buffer_output (p, " ", 1); p = variable_buffer_output (p, v->value, v->value_length + 1) - 1; } /* Replace the variable with the variable buffer. */ #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE if (v->rdonly_val) v->rdonly_val = 0; else #endif free (v->value); v->value = variable_buffer; v->value_length = p - v->value; v->value_alloc_len = variable_buffer_length; /* Restore the variable buffer, but without freeing the current. */ variable_buffer = NULL; restore_variable_buffer (saved_buffer, saved_buffer_length); } /* else: Drop empty strings. Use $(NO_SUCH_VARIABLE) if a space is wanted. */ }
/* Evaluate a buffer as make syntax. Ideally eval_buffer() will take const char *, but not yet. */ void gmk_eval (const char *buffer, const gmk_floc *floc) { /* Preserve existing variable buffer context. */ char *pbuf; unsigned int plen; char *s; install_variable_buffer (&pbuf, &plen); s = xstrdup (buffer); eval_buffer (s, floc); free (s); restore_variable_buffer (pbuf, plen); }
/** * Appends text to a textfile, creating the textfile if necessary. */ int kmk_builtin_append(int argc, char **argv, char **envp) { int i; int fFirst; int iFile; FILE *pFile; int fNewline = 0; int fNoTrailingNewline = 0; int fTruncate = 0; int fDefine = 0; int fVariables = 0; int fCommands = 0; g_progname = argv[0]; /* * Parse options. */ i = 1; while (i < argc && argv[i][0] == '-' && argv[i][1] != '\0' /* '-' is a file */ && strchr("-cdnNtv", argv[i][1]) /* valid option char */ ) { char *psz = &argv[i][1]; if (*psz != '-') { do { switch (*psz) { case 'c': if (fVariables) { errx(1, "Option '-c' clashes with '-v'."); return usage(stderr); } #ifndef kmk_builtin_append fCommands = 1; break; #else errx(1, "Option '-c' isn't supported in external mode."); return usage(stderr); #endif case 'd': if (fVariables) { errx(1, "Option '-d' must come before '-v'!"); return usage(stderr); } fDefine = 1; break; case 'n': fNewline = 1; break; case 'N': fNoTrailingNewline = 1; break; case 't': fTruncate = 1; break; case 'v': if (fCommands) { errx(1, "Option '-v' clashes with '-c'."); return usage(stderr); } #ifndef kmk_builtin_append fVariables = 1; break; #else errx(1, "Option '-v' isn't supported in external mode."); return usage(stderr); #endif default: errx(1, "Invalid option '%c'! (%s)", *psz, argv[i]); return usage(stderr); } } while (*++psz); } else if (!strcmp(psz, "-help")) { usage(stdout); return 0; } else if (!strcmp(psz, "-version")) return kbuild_version(argv[0]); else break; i++; } if (i + fDefine >= argc) { if (i <= argc) errx(1, "missing filename!"); else errx(1, "missing define name!"); return usage(stderr); } /* * Open the output file. */ iFile = i; pFile = fopen(argv[i], fTruncate ? "w" : "a"); if (!pFile) return err(1, "failed to open '%s'", argv[i]); /* * Start define? */ if (fDefine) { i++; fprintf(pFile, "define %s\n", argv[i]); } /* * Append the argument strings to the file */ fFirst = 1; for (i++; i < argc; i++) { const char *psz = argv[i]; size_t cch = strlen(psz); if (!fFirst) fputc(fNewline ? '\n' : ' ', pFile); #ifndef kmk_builtin_append if (fCommands) { char *pszOldBuf; unsigned cchOldBuf; char *pchEnd; install_variable_buffer(&pszOldBuf, &cchOldBuf); pchEnd = func_commands(variable_buffer, &argv[i], "commands"); fwrite(variable_buffer, 1, pchEnd - variable_buffer, pFile); restore_variable_buffer(pszOldBuf, cchOldBuf); } else if (fVariables) { struct variable *pVar = lookup_variable(psz, cch); if (!pVar) continue; if ( !pVar->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar)) fwrite(pVar->value, 1, pVar->value_length, pFile); else { char *pszExpanded = allocated_variable_expand(pVar->value); fwrite(pszExpanded, 1, strlen(pszExpanded), pFile); free(pszExpanded); } } else #endif fwrite(psz, 1, cch, pFile); fFirst = 0; } /* * End the define? */ if (fDefine) { if (fFirst) fwrite("\nendef", 1, sizeof("\nendef") - 1, pFile); else fwrite("endef", 1, sizeof("endef") - 1, pFile); } /* * Add the final newline (unless supressed) and close the file. */ if ( ( !fNoTrailingNewline && fputc('\n', pFile) == EOF) || ferror(pFile)) { fclose(pFile); return errx(1, "error writing to '%s'!", argv[iFile]); } if (fclose(pFile)) return err(1, "failed to fclose '%s'!", argv[iFile]); return 0; }