=================================================================== RCS file: /cvs/texi2mdoc/util.c,v retrieving revision 1.15 retrieving revision 1.18 diff -u -p -r1.15 -r1.18 --- texi2mdoc/util.c 2015/02/25 14:49:14 1.15 +++ texi2mdoc/util.c 2015/02/28 08:41:59 1.18 @@ -1,4 +1,4 @@ -/* $Id: util.c,v 1.15 2015/02/25 14:49:14 kristaps Exp $ */ +/* $Id: util.c,v 1.18 2015/02/28 08:41:59 kristaps Exp $ */ /* * Copyright (c) 2015 Kristaps Dzonsons * @@ -330,8 +330,11 @@ advance(struct texi *p, size_t *pos) f->col = 0; } else f->col++; - } else + } else { --f->insplice; + if (0 == f->insplice) + f->depth = 0; + } (*pos)++; } @@ -439,7 +442,7 @@ advanceto(struct texi *p, size_t *pos, size_t end) } static void -texiexecmacro(struct texi *p, struct teximacro *m, size_t *pos) +texiexecmacro(struct texi *p, struct teximacro *m, size_t sv, size_t *pos) { size_t valsz, realsz, aasz, asz, ssz, i, j, k, start, end; @@ -447,17 +450,31 @@ texiexecmacro(struct texi *p, struct teximacro *m, siz char **args; const char *cp; + /* Disregard empty macros. */ + if (0 == (valsz = realsz = strlen(m->value))) + return; + + /* + * This is important: it protect us from macros that invoke more + * macros, possibly going on infinitely. + * We use "sv" instead of the current position because we might + * be invoked at the end of the macro (i.e., insplice == 0). + * The "sv" value was initialised at the start of the macro. + */ + if (sv > 0) + if (++p->files[p->filepos].depth > 64) + texierr(p, "maximium recursive depth"); + args = argparse(p, pos, &asz, m->argsz); if (asz != m->argsz) texiwarn(p, "invalid macro argument length"); aasz = asz < m->argsz ? asz : m->argsz; if (0 == aasz) { - texisplice(p, m->value, strlen(m->value), pos); + texisplice(p, m->value, valsz, pos); return; } - valsz = realsz = strlen(m->value); val = strdup(m->value); for (i = j = 0; i < realsz; i++) { @@ -589,7 +606,7 @@ texicmd(struct texi *p, size_t pos, size_t *end, struc return(TEXICMD__MAX); /* Alphabetic commands are special. */ - if ( ! isalpha(BUF(p)[pos])) { + if ( ! isalpha((unsigned char)BUF(p)[pos])) { if ((*end = pos + 1) == BUFSZ(p)) return(TEXICMD__MAX); for (i = 0; i < TEXICMD__MAX; i++) { @@ -653,7 +670,7 @@ texicmd(struct texi *p, size_t pos, size_t *end, struc int parsearg(struct texi *p, size_t *pos, size_t num) { - size_t end; + size_t end, sv; enum texicmd cmd; struct teximacro *macro; @@ -684,10 +701,11 @@ parsearg(struct texi *p, size_t *pos, size_t num) continue; } + sv = p->files[p->filepos - 1].insplice; cmd = texicmd(p, *pos, &end, ¯o); advanceto(p, pos, end); if (NULL != macro) - texiexecmacro(p, macro, pos); + texiexecmacro(p, macro, sv, pos); if (TEXICMD__MAX == cmd) continue; if (NULL != texitoks[cmd].fp) @@ -701,9 +719,9 @@ parsearg(struct texi *p, size_t *pos, size_t num) * This will stop in the event of EOF or if we're not at a bracket. */ void -parsebracket(struct texi *p, size_t *pos) +parsebracket(struct texi *p, size_t *pos, int dostack) { - size_t end; + size_t end, sv, stack; enum texicmd cmd; struct teximacro *macro; @@ -714,12 +732,25 @@ parsebracket(struct texi *p, size_t *pos) return; advance(p, pos); + stack = 0; while ((*pos = advancenext(p, pos)) < BUFSZ(p)) { switch (BUF(p)[*pos]) { case ('}'): + if (stack > 0) { + stack--; + advance(p, pos); + texiputchar(p, '}'); + continue; + } advance(p, pos); return; case ('{'): + if (dostack) { + stack++; + advance(p, pos); + texiputchar(p, '{'); + continue; + } if (0 == p->ign) texiwarn(p, "unexpected \"{\""); advance(p, pos); @@ -731,10 +762,11 @@ parsebracket(struct texi *p, size_t *pos) continue; } + sv = p->files[p->filepos - 1].insplice; cmd = texicmd(p, *pos, &end, ¯o); advanceto(p, pos, end); if (NULL != macro) - texiexecmacro(p, macro, pos); + texiexecmacro(p, macro, sv, pos); if (TEXICMD__MAX == cmd) continue; if (NULL != texitoks[cmd].fp) @@ -750,7 +782,7 @@ parsebracket(struct texi *p, size_t *pos) void parseeoln(struct texi *p, size_t *pos) { - size_t end; + size_t end, sv; enum texicmd cmd; struct teximacro *macro; @@ -779,10 +811,11 @@ parseeoln(struct texi *p, size_t *pos) continue; } + sv = p->files[p->filepos - 1].insplice; cmd = texicmd(p, *pos, &end, ¯o); advanceto(p, pos, end); if (NULL != macro) - texiexecmacro(p, macro, pos); + texiexecmacro(p, macro, sv, pos); if (TEXICMD__MAX == cmd) continue; if (NULL != texitoks[cmd].fp) @@ -800,7 +833,7 @@ parseeoln(struct texi *p, size_t *pos) static void parsesingle(struct texi *p, size_t *pos) { - size_t end; + size_t end, sv; enum texicmd cmd; struct teximacro *macro; @@ -825,10 +858,11 @@ parsesingle(struct texi *p, size_t *pos) return; } + sv = p->files[p->filepos - 1].insplice; cmd = texicmd(p, *pos, &end, ¯o); advanceto(p, pos, end); if (NULL != macro) - texiexecmacro(p, macro, pos); + texiexecmacro(p, macro, sv, pos); if (TEXICMD__MAX == cmd) return; if (NULL != texitoks[cmd].fp) @@ -853,7 +887,7 @@ parselinearg(struct texi *p, size_t *pos) } if (*pos < BUFSZ(p) && '{' == BUF(p)[*pos]) - parsebracket(p, pos); + parsebracket(p, pos, 0); else if (*pos < BUFSZ(p) && '\n' != BUF(p)[*pos]) parsesingle(p, pos); else @@ -905,7 +939,7 @@ texisplice(struct texi *p, const char *buf, size_t sz, void parseto(struct texi *p, size_t *pos, const char *endtoken) { - size_t end; + size_t end, sv; enum texicmd cmd; size_t endtoksz; struct teximacro *macro; @@ -932,6 +966,7 @@ parseto(struct texi *p, size_t *pos, const char *endto continue; } + sv = p->files[p->filepos - 1].insplice; cmd = texicmd(p, *pos, &end, ¯o); advanceto(p, pos, end); if (TEXICMD_END == cmd) { @@ -952,7 +987,7 @@ parseto(struct texi *p, size_t *pos, const char *endto continue; } if (NULL != macro) - texiexecmacro(p, macro, pos); + texiexecmacro(p, macro, sv, pos); if (TEXICMD__MAX == cmd) continue; if (NULL != texitoks[cmd].fp) @@ -1209,6 +1244,9 @@ argparse(struct texi *p, size_t *pos, size_t *argsz, s args = NULL; *argsz = 0; + if (*pos == BUFSZ(p)) + return(args); + if ('{' != BUF(p)[*pos] && hint) { /* * Special case: if we encounter an unbracketed argument @@ -1234,6 +1272,8 @@ argparse(struct texi *p, size_t *pos, size_t *argsz, s return(args); } else if ('{' != BUF(p)[*pos]) return(args); + + assert('{' == BUF(p)[*pos]); /* Parse til the closing '}', putting into the array. */ advance(p, pos);