#include "common.h"
-enum
+enum
{
- MAX_STRING_LENGTH = PATH_MAX,
+ MAX_STRING_LENGTH = 2048,
MAX_MACRO_NAME_LENGTH = 128
};
void
-_evalMacros(char *apinto, hTab *pvals, const char *pfrom)
+_evalMacros(char *apinto, hTab *pvals, const char *pfrom, size_t alen)
{
- bool fdidsomething = FALSE;
- char *pinto = apinto;
+ bool fdidsomething = FALSE;
+ char *pinto = apinto;
+ size_t plen = alen;
+ char quote = '\0';
assert(pinto);
assert(pvals);
assert(pfrom);
- while (*pfrom)
- {
- if (*pfrom == '{')
- {
- const char *pend = ++pfrom;
- char name[MAX_MACRO_NAME_LENGTH];
- const char *pval;
+ while (plen > 0 && *pfrom) {
+ switch (*pfrom) {
+ case '"':
+ case '\'':
+ if (quote != '\0') {
+ /* write previous quote */
+ *pinto++ = quote;
+ --plen;
+ }
+ quote = *pfrom++;
+ break;
+
+ case '{':
+ {
+ const char *pend = ++pfrom;
+ char name[MAX_MACRO_NAME_LENGTH];
+ const char *pval;
+
+ /* Find the end of macro */
+ while (*pend && '}' != *pend) {
+ pend++;
+ }
+ if ('}' != *pend) {
+ wassertl(0, "Unterminated macro expansion");
+ }
- while (*pend && *pend != '}')
- {
- pend++;
- }
- if (*pend != '}')
- {
- wassertl(0, "Unterminated macro expansion");
- }
- /* Pull out the macro name */
- strncpy(name, pfrom, pend-pfrom);
- name[pend-pfrom] = '\0';
-
- /* Look up the value in the hash table */
- pval = shash_find (pvals, name);
-
- if (pval == NULL)
- {
- fprintf (stderr, "Cant find macro \"%s\"\n", name);
- wassertl (0, "Invalid macro name");
- }
+ /* Pull out the macro name */
+ if (pend - pfrom >= MAX_MACRO_NAME_LENGTH) {
+ wassertl(0, "macro name too long");
+ }
+
+ strncpy(name, pfrom, pend - pfrom);
+ name[pend - pfrom] = '\0';
- /* Replace */
- strcpy(pinto, pval);
- pinto += strlen(pval);
- fdidsomething = TRUE;
+ /* Look up the value in the hash table */
+ pval = shash_find (pvals, name);
- pfrom = pend+1;
+ if (NULL == pval) {
+ /* Empty macro value */
+ if ('\0' != quote) {
+ /* It was a quote */
+ if (pend[1] == quote) {
+ /* Start quote equals end quote: skip both */
+ ++pend;
+ }
+ else {
+ /* Start quote not equals end quote: add both */
+ *pinto++ = quote;
+ --plen;
+ }
+ }
}
- else
- {
- /* Pass through */
- *pinto++ = *pfrom++;
+ else {
+ if ('\0' != quote) {
+ /* It was a quote, add it */
+ *pinto++ = quote;
+ --plen;
+ }
+ if (plen > 0) {
+ /* Replace macro */
+ strncpy(pinto, pval, plen);
+ pinto += strlen(pval);
+ plen -= plen > strlen(pval) ? strlen(pval) : plen;
+ fdidsomething = TRUE;
+ }
}
+
+ quote = '\0';
+ pfrom = pend + 1;
+ }
+ break;
+
+ default:
+ if ('\0' != quote) {
+ *pinto++ = quote;
+ --plen;
+ quote = '\0';
+ }
+
+ if (plen > 0) {
+ /* Pass through */
+ *pinto++ = *pfrom++;
+ --plen;
+ }
}
+ }
+
+ if (plen > 0 && '\0' != quote) {
+ *pinto++ = quote;
+ --plen;
+ }
+
+ if (plen <= 0) {
+ wassertl(0, "macro expansion too long");
+ }
*pinto = '\0';
/* If we did something then recursivly expand any expanded macros */
- if (fdidsomething)
- {
- char ainto[MAX_STRING_LENGTH];
- _evalMacros(ainto, pvals, apinto);
- strcpy(apinto, ainto);
- }
+ if (fdidsomething) {
+ char ainto[MAX_STRING_LENGTH];
+ _evalMacros(ainto, pvals, apinto, MAX_STRING_LENGTH);
+ strncpyz(apinto, ainto, alen);
+ }
}
char *
char atmp[MAX_STRING_LENGTH];
/* Recursivly evaluate all the macros in the string */
- _evalMacros(ainto, pvals, pformat);
+ _evalMacros(ainto, pvals, pformat, MAX_STRING_LENGTH);
/* Evaluate all the arguments */
- vsprintf(atmp, ainto, ap);
+#if defined(HAVE_VSNPRINTF)
+ if (vsnprintf(atmp, MAX_STRING_LENGTH, ainto, ap) >= MAX_STRING_LENGTH)
+ {
+ fprintf(stderr, "Internal error: mvsprintf output truncated.\n");
+ }
+#else
+ {
+ int wlen;
+
+ wlen = vsprintf(atmp, ainto, ap);
+
+ if (wlen < 0 || wlen >= MAX_STRING_LENGTH)
+ {
+ wassertl(0, "mvsprintf overflowed.");
+ }
+ }
+#endif
+
/* Recursivly evaluate any macros that were used as arguments */
- _evalMacros(ainto, pvals, atmp);
+ _evalMacros(ainto, pvals, atmp, MAX_STRING_LENGTH);
/* Return a copy of the evaluated string. */
return Safe_strdup(ainto);