diff --git a/src/mustach-dhcpd-pools.c b/src/mustach-dhcpd-pools.c index 8aa412a..00e1b8b 100644 --- a/src/mustach-dhcpd-pools.c +++ b/src/mustach-dhcpd-pools.c @@ -441,7 +441,7 @@ int mustach_dhcpd_pools(struct conf_t *state) case MUSTACH_ERROR_BAD_SEPARATORS: error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: bad separator"); break; - case MUSTACH_ERROR_TOO_DEPTH: + case MUSTACH_ERROR_TOO_DEEP: error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: too deep"); break; case MUSTACH_ERROR_CLOSING: diff --git a/src/mustach.c b/src/mustach.c index 9868cff..45eb7a4 100644 --- a/src/mustach.c +++ b/src/mustach.c @@ -30,6 +30,76 @@ #define NAME_LENGTH_MAX 1024 #define DEPTH_MAX 256 +#if !defined(NO_OPEN_MEMSTREAM) +static FILE *memfile_open(char **buffer, size_t *size) +{ + return open_memstream(buffer, size); +} +static void memfile_abort(FILE *file, char **buffer, size_t *size) +{ + fclose(file); + free(*buffer); + *buffer = NULL; + *size = 0; +} +static int memfile_close(FILE *file, char **buffer, size_t *size) +{ + int rc; + + /* adds terminating null */ + rc = fputc(0, file) ? MUSTACH_ERROR_SYSTEM : 0; + fclose(file); + if (rc == 0) + /* removes terminating null of the length */ + (*size)--; + else { + free(*buffer); + *buffer = NULL; + *size = 0; + } + return rc; +} +#else +static FILE *memfile_open(char **buffer, size_t *size) +{ + return tmpfile(); +} +static void memfile_abort(FILE *file, char **buffer, size_t *size) +{ + fclose(file); + *buffer = NULL; + *size = 0; +} +static int memfile_close(FILE *file, char **buffer, size_t *size) +{ + int rc; + size_t s; + char *b; + + s = (size_t)ftell(file); + b = malloc(s + 1); + if (b == NULL) { + rc = MUSTACH_ERROR_SYSTEM; + errno = ENOMEM; + s = 0; + } else { + rewind(file); + if (1 == fread(b, s, 1, file)) { + rc = 0; + b[s] = 0; + } else { + rc = MUSTACH_ERROR_SYSTEM; + free(b); + b = NULL; + s = 0; + } + } + *buffer = b; + *size = s; + return rc; +} +#endif + static int getpartial(struct mustach_itf *itf, void *closure, const char *name, char **result) { int rc; @@ -37,26 +107,22 @@ static int getpartial(struct mustach_itf *itf, void *closure, const char *name, size_t size; *result = NULL; - file = open_memstream(result, &size); + file = memfile_open(result, &size); if (file == NULL) rc = MUSTACH_ERROR_SYSTEM; else { rc = itf->put(closure, name, 0, file); - if (rc == 0) - /* adds terminating null */ - rc = fputc(0, file) ? MUSTACH_ERROR_SYSTEM : 0; - fclose(file); - if (rc < 0) { - free(*result); - *result = NULL; - } + if (rc < 0) + memfile_abort(file, result, &size); + else + rc = memfile_close(file, result, &size); } return rc; } static int process(const char *template, struct mustach_itf *itf, void *closure, FILE *file, const char *opstr, const char *clstr) { - char name[NAME_LENGTH_MAX + 1], *partial, c; + char name[NAME_LENGTH_MAX + 1], *partial, c, *tmp; const char *beg, *term; struct { const char *name, *again; size_t length; int emit, entered; } stack[DEPTH_MAX]; size_t oplen, cllen, len, l; @@ -112,8 +178,10 @@ static int process(const char *template, struct mustach_itf *itf, void *closure, default: while (len && isspace(beg[0])) { beg++; len--; } while (len && isspace(beg[len-1])) len--; +#if defined(NO_EXTENSION_FOR_MUSTACH) || defined(NO_ALLOW_EMPTY_TAG) if (len == 0) return MUSTACH_ERROR_EMPTY_TAG; +#endif if (len > NAME_LENGTH_MAX) return MUSTACH_ERROR_TAG_TOO_LONG; memcpy(name, beg, len); @@ -134,19 +202,25 @@ static int process(const char *template, struct mustach_itf *itf, void *closure, for (l = 0; l < len && !isspace(beg[l]) ; l++); if (l == len) return MUSTACH_ERROR_BAD_SEPARATORS; - opstr = strndupa(beg, l); + oplen = l; + tmp = alloca(oplen + 1); + memcpy(tmp, beg, oplen); + tmp[oplen] = 0; + opstr = tmp; while (l < len && isspace(beg[l])) l++; if (l == len) return MUSTACH_ERROR_BAD_SEPARATORS; - clstr = strndupa(beg + l, len - l); - oplen = strlen(opstr); - cllen = strlen(clstr); + cllen = len - l; + tmp = alloca(cllen + 1); + memcpy(tmp, beg + l, cllen); + tmp[cllen] = 0; + clstr = tmp; break; case '^': case '#': /* begin section */ if (depth == DEPTH_MAX) - return MUSTACH_ERROR_TOO_DEPTH; + return MUSTACH_ERROR_TOO_DEEP; rc = emit; if (rc) { rc = itf->enter(closure, name); @@ -234,24 +308,15 @@ int mustach(const char *template, struct mustach_itf *itf, void *closure, char * *result = NULL; if (size == NULL) size = &s; - file = open_memstream(result, size); - if (file == NULL) { + file = memfile_open(result, size); + if (file == NULL) rc = MUSTACH_ERROR_SYSTEM; - errno = ENOMEM; - } else { + else { rc = fmustach(template, itf, closure, file); - if (rc == 0) - /* adds terminating null */ - rc = fputc(0, file) ? MUSTACH_ERROR_SYSTEM : 0; - fclose(file); - if (rc >= 0) - /* removes terminating null of the length */ - (*size)--; - else { - free(*result); - *result = NULL; - *size = 0; - } + if (rc < 0) + memfile_abort(file, result, size); + else + rc = memfile_close(file, result, size); } return rc; } diff --git a/src/mustach.h b/src/mustach.h index 716d7e3..32288a1 100644 --- a/src/mustach.h +++ b/src/mustach.h @@ -29,12 +29,17 @@ * * The functions enter and next should return 0 or 1. * - * All other functions should normally return 0. + * All other functions should normally return 0. If it returns + * a negative value, it means an error that stop the process + * and that is reported to the caller. * * @start: Starts the mustach processing of the closure * 'start' is optional (can be NULL) * * @put: Writes the value of 'name' to 'file' with 'escape' or not + * As an extension (see NO_ALLOW_EMPTY_TAG), the 'name' can be + * the empty string. In that later case an implemntation can + * return MUSTACH_ERROR_EMPTY_TAG to refuse empty names. * * @enter: Enters the section of 'name' if possible. * Musts return 1 if entered or 0 if not entered. @@ -64,14 +69,17 @@ struct mustach_itf { #define MUSTACH_ERROR_EMPTY_TAG -3 #define MUSTACH_ERROR_TAG_TOO_LONG -4 #define MUSTACH_ERROR_BAD_SEPARATORS -5 -#define MUSTACH_ERROR_TOO_DEPTH -6 +#define MUSTACH_ERROR_TOO_DEEP -6 #define MUSTACH_ERROR_CLOSING -7 #define MUSTACH_ERROR_BAD_UNESCAPE_TAG -8 +/* compatibility with older bad name */ +#define MUSTACH_ERROR_TOO_DEPTH MUSTACH_ERROR_TOO_DEEP + /** * fmustach - Renders the mustache 'template' in 'file' for 'itf' and 'closure'. * - * @template: the template string to instantiate + * @template: the template string to instanciate * @itf: the interface to the functions that mustach calls * @closure: the closure to pass to functions called * @file: the file where to write the result @@ -84,7 +92,7 @@ extern int fmustach(const char *template, struct mustach_itf *itf, void *closure /** * fmustach - Renders the mustache 'template' in 'fd' for 'itf' and 'closure'. * - * @template: the template string to instantiate + * @template: the template string to instanciate * @itf: the interface to the functions that mustach calls * @closure: the closure to pass to functions called * @fd: the file descriptor number where to write the result @@ -97,7 +105,7 @@ extern int fdmustach(const char *template, struct mustach_itf *itf, void *closur /** * fmustach - Renders the mustache 'template' in 'result' for 'itf' and 'closure'. * - * @template: the template string to instantiate + * @template: the template string to instanciate * @itf: the interface to the functions that mustach calls * @closure: the closure to pass to functions called * @result: the pointer receiving the result when 0 is returned