X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2FSDCCmacro.c;h=73be7495cd6e2e6187c81d73f345aee22baf6330;hb=3bd25d75bcad68055bb616dcc29dde8a2965965e;hp=41bfddf5d12488b48640c181b98114784a4ae86a;hpb=1ad40983f38c7d999d35971f62626050e95746db;p=fw%2Fsdcc diff --git a/src/SDCCmacro.c b/src/SDCCmacro.c index 41bfddf5..73be7495 100644 --- a/src/SDCCmacro.c +++ b/src/SDCCmacro.c @@ -24,74 +24,128 @@ #include "common.h" -enum +enum { - MAX_STRING_LENGTH = 2048, + 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 * @@ -101,11 +155,28 @@ mvsprintf(hTab *pvals, const char *pformat, va_list ap) 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);