=================================================================== RCS file: /cvs/mandoc/roff.c,v retrieving revision 1.262 retrieving revision 1.265 diff -u -p -r1.262 -r1.265 --- mandoc/roff.c 2015/02/17 18:09:14 1.262 +++ mandoc/roff.c 2015/04/18 17:28:36 1.265 @@ -1,6 +1,6 @@ -/* $Id: roff.c,v 1.262 2015/02/17 18:09:14 schwarze Exp $ */ +/* $Id: roff.c,v 1.265 2015/04/18 17:28:36 schwarze Exp $ */ /* - * Copyright (c) 2010, 2011, 2012, 2014 Kristaps Dzonsons + * Copyright (c) 2009-2012, 2014 Kristaps Dzonsons * Copyright (c) 2010-2015 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any @@ -28,6 +28,7 @@ #include "mandoc.h" #include "mandoc_aux.h" +#include "roff.h" #include "libmandoc.h" #include "libroff.h" @@ -412,6 +413,8 @@ static const char *roff_getstrn(const struct roff *, static enum rofferr roff_insec(ROFF_ARGS); static enum rofferr roff_it(ROFF_ARGS); static enum rofferr roff_line_ignore(ROFF_ARGS); +static void roff_man_alloc1(struct roff_man *); +static void roff_man_free1(struct roff_man *); static enum rofferr roff_nr(ROFF_ARGS); static enum rofft roff_parse(struct roff *, char *, int *, int, int); @@ -898,6 +901,71 @@ roff_alloc(struct mparse *parse, const struct mchars * return(r); } +static void +roff_man_free1(struct roff_man *man) +{ + + if (man->first != NULL) { + if (man->macroset == MACROSET_MDOC) + mdoc_node_delete(man, man->first); + else + man_node_delete(man, man->first); + } + free(man->meta.msec); + free(man->meta.vol); + free(man->meta.os); + free(man->meta.arch); + free(man->meta.title); + free(man->meta.name); + free(man->meta.date); +} + +static void +roff_man_alloc1(struct roff_man *man) +{ + + memset(&man->meta, 0, sizeof(man->meta)); + man->first = mandoc_calloc(1, sizeof(*man->first)); + man->first->type = ROFFT_ROOT; + man->last = man->first; + man->last_es = NULL; + man->flags = 0; + man->macroset = MACROSET_NONE; + man->lastsec = man->lastnamed = SEC_NONE; + man->next = ROFF_NEXT_CHILD; +} + +void +roff_man_reset(struct roff_man *man) +{ + + roff_man_free1(man); + roff_man_alloc1(man); +} + +void +roff_man_free(struct roff_man *man) +{ + + roff_man_free1(man); + free(man); +} + +struct roff_man * +roff_man_alloc(struct roff *roff, struct mparse *parse, + const char *defos, int quick) +{ + struct roff_man *man; + + man = mandoc_calloc(1, sizeof(*man)); + man->parse = parse; + man->roff = roff; + man->defos = defos; + man->quick = quick; + roff_man_alloc1(man); + return(man); +} + /* * In the current line, expand escape sequences that tend to get * used in numerical expressions and conditional requests. @@ -1128,6 +1196,8 @@ roff_parsetext(struct buf *buf, int pos, int *offs) esc = mandoc_escape((const char **)&p, NULL, NULL); if (esc == ESCAPE_ERROR) break; + while (*p == '-') + p++; continue; } else if (p == start) { p++; @@ -2653,14 +2723,16 @@ roff_so(ROFF_ARGS) static enum rofferr roff_userdef(ROFF_ARGS) { - const char *arg[9]; + const char *arg[9], *ap; char *cp, *n1, *n2; int i; + size_t asz, rsz; /* * Collect pointers to macro argument strings * and NUL-terminate them. */ + cp = buf->buf + pos; for (i = 0; i < 9; i++) arg[i] = *cp == '\0' ? "" : @@ -2669,31 +2741,89 @@ roff_userdef(ROFF_ARGS) /* * Expand macro arguments. */ - buf->sz = 0; - n1 = cp = mandoc_strdup(r->current_string); - while ((cp = strstr(cp, "\\$")) != NULL) { - i = cp[2] - '1'; - if (0 > i || 8 < i) { - /* Not an argument invocation. */ - cp += 2; + + buf->sz = strlen(r->current_string) + 1; + n1 = cp = mandoc_malloc(buf->sz); + memcpy(n1, r->current_string, buf->sz); + while (*cp != '\0') { + + /* Scan ahead for the next argument invocation. */ + + if (*cp++ != '\\') continue; + if (*cp++ != '$') + continue; + i = *cp - '1'; + if (0 > i || 8 < i) + continue; + cp -= 2; + + /* + * Determine the size of the expanded argument, + * taking escaping of quotes into account. + */ + + asz = 0; + for (ap = arg[i]; *ap != '\0'; ap++) { + asz++; + if (*ap == '"') + asz += 3; } - *cp = '\0'; - buf->sz = mandoc_asprintf(&n2, "%s%s%s", - n1, arg[i], cp + 3) + 1; - cp = n2 + (cp - n1); - free(n1); - n1 = n2; + if (asz != 3) { + + /* + * Determine the size of the rest of the + * unexpanded macro, including the NUL. + */ + + rsz = buf->sz - (cp - n1) - 3; + + /* + * When shrinking, move before + * releasing the storage. + */ + + if (asz < 3) + memmove(cp + asz, cp + 3, rsz); + + /* + * Resize the storage for the macro + * and readjust the parse pointer. + */ + + buf->sz += asz - 3; + n2 = mandoc_realloc(n1, buf->sz); + cp = n2 + (cp - n1); + n1 = n2; + + /* + * When growing, make room + * for the expanded argument. + */ + + if (asz > 3) + memmove(cp + asz, cp + 3, rsz); + } + + /* Copy the expanded argument, escaping quotes. */ + + n2 = cp; + for (ap = arg[i]; *ap != '\0'; ap++) { + if (*ap == '"') { + memcpy(n2, "\\(dq", 4); + n2 += 4; + } else + *n2++ = *ap; + } } /* * Replace the macro invocation * by the expanded macro. */ + free(buf->buf); buf->buf = n1; - if (buf->sz == 0) - buf->sz = strlen(buf->buf) + 1; *offs = 0; return(buf->sz > 1 && buf->buf[buf->sz - 2] == '\n' ?