=================================================================== RCS file: /cvs/mandoc/roff.c,v retrieving revision 1.93 retrieving revision 1.94 diff -u -p -r1.93 -r1.94 --- mandoc/roff.c 2010/07/04 22:04:04 1.93 +++ mandoc/roff.c 2010/07/07 15:04:54 1.94 @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.93 2010/07/04 22:04:04 schwarze Exp $ */ +/* $Id: roff.c,v 1.94 2010/07/07 15:04:54 kristaps Exp $ */ /* * Copyright (c) 2010 Kristaps Dzonsons * Copyright (c) 2010 Ingo Schwarze @@ -28,8 +28,8 @@ #include #include "mandoc.h" -#include "regs.h" #include "roff.h" +#include "libmandoc.h" #define RSTACK_MAX 128 @@ -69,6 +69,13 @@ enum roffrule { ROFFRULE_DENY }; + +struct roffstr { + char *name; /* key of symbol */ + char *string; /* current value */ + struct roffstr *next; /* next in list */ +}; + struct roff { struct roffnode *last; /* leaf of stack */ mandocmsg msg; /* err/warn/fatal messages */ @@ -76,6 +83,7 @@ struct roff { enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */ int rstackpos; /* position in rstack */ struct regset *regs; /* read/writable registers */ + struct roffstr *first_string; }; struct roffnode { @@ -109,12 +117,6 @@ struct roffmac { struct roffmac *next; }; -struct roffstr { - char *name; - char *string; - struct roffstr *next; -} *first_string; - static enum rofferr roff_block(ROFF_ARGS); static enum rofferr roff_block_text(ROFF_ARGS); static enum rofferr roff_block_sub(ROFF_ARGS); @@ -124,9 +126,16 @@ static enum rofferr roff_cond(ROFF_ARGS); static enum rofferr roff_cond_text(ROFF_ARGS); static enum rofferr roff_cond_sub(ROFF_ARGS); static enum rofferr roff_ds(ROFF_ARGS); +static enum roffrule roff_evalcond(const char *, int *); +static void roff_freestr(struct roff *); +static const char *roff_getstrn(const struct roff *, + const char *, size_t); static enum rofferr roff_line(ROFF_ARGS); static enum rofferr roff_nr(ROFF_ARGS); -static enum roffrule roff_evalcond(const char *, int *); +static int roff_res(struct roff *, int, + char **, size_t *, int, int *); +static void roff_setstr(struct roff *, + const char *, const char *); /* See roff_hash_find() */ @@ -276,7 +285,7 @@ roff_free1(struct roff *r) while (r->last) roffnode_pop(r); - roff_freestr(); + roff_freestr(r); } @@ -317,6 +326,74 @@ roff_alloc(struct regset *regs, const mandocmsg msg, v } +/* + * Pre-filter each and every line for reserved words (one beginning with + * `\*', e.g., `\*(ab'). These must be handled before the actual line + * is processed. + */ +static int +roff_res(struct roff *r, int ln, char **bufp, + size_t *szp, int pos, int *offs) +{ + const char *cp, *cpp, *st, *res; + int i, maxl; + size_t nsz; + char *n; + + for (cp = &(*bufp)[pos]; (cpp = strstr(cp, "\\*")); cp++) { + cp = cpp + 2; + switch (*cp) { + case ('('): + cp++; + maxl = 2; + break; + case ('['): + cp++; + maxl = 0; + break; + default: + maxl = 1; + break; + } + + st = cp; + + for (i = 0; 0 == maxl || i < maxl; i++, cp++) { + if ('\0' == *cp) + return(1); /* Error. */ + if (0 == maxl && ']' == *cp) + break; + } + + res = roff_getstrn(r, st, (size_t)i); + + if (NULL == res) { + cp -= maxl ? 1 : 0; + continue; + } + + ROFF_DEBUG("roff: splicing reserved: [%.*s]\n", i, st); + + nsz = *szp + strlen(res) + 1; + n = mandoc_malloc(nsz); + + *n = '\0'; + + strlcat(n, *bufp, (size_t)(cpp - *bufp + 1)); + strlcat(n, res, nsz); + strlcat(n, cp + (maxl ? 0 : 1), nsz); + + free(*bufp); + + *bufp = n; + *szp = nsz; + return(0); + } + + return(1); +} + + enum rofferr roff_parseln(struct roff *r, int ln, char **bufp, size_t *szp, int pos, int *offs) @@ -325,6 +402,14 @@ roff_parseln(struct roff *r, int ln, char **bufp, int ppos; /* + * Run the reserved-word filter only if we have some reserved + * words to fill in. + */ + + if (r->first_string && ! roff_res(r, ln, bufp, szp, pos, offs)) + return(ROFF_RERUN); + + /* * First, if a scope is open and we're not a macro, pass the * text through the macro's filter. If a scope isn't open and * we're not a macro, just let it through. @@ -338,11 +423,8 @@ roff_parseln(struct roff *r, int ln, char **bufp, return((*roffs[t].text) (r, t, bufp, szp, ln, pos, pos, offs)); - } else if ( ! ROFF_CTL((*bufp)[pos])) { - ROFF_DEBUG("roff: pass non-scoped text: [%s]\n", - &(*bufp)[pos]); + } else if ( ! ROFF_CTL((*bufp)[pos])) return(ROFF_CONT); - } /* * If a scope is open, go to the child handler for that macro, @@ -366,11 +448,8 @@ roff_parseln(struct roff *r, int ln, char **bufp, */ ppos = pos; - if (ROFF_MAX == (t = roff_parse(*bufp, &pos))) { - ROFF_DEBUG("roff: pass non-scoped non-macro: [%s]\n", - &(*bufp)[pos]); + if (ROFF_MAX == (t = roff_parse(*bufp, &pos))) return(ROFF_CONT); - } ROFF_DEBUG("roff: intercept new-scope: %s, [%s]\n", roffs[t].name, &(*bufp)[pos]); @@ -914,7 +993,7 @@ roff_ds(ROFF_ARGS) *end = '\0'; } - roff_setstr(name, string); + roff_setstr(r, name, string); return(ROFF_IGN); } @@ -962,73 +1041,53 @@ roff_nr(ROFF_ARGS) } -char * -roff_setstr(const char *name, const char *string) +static void +roff_setstr(struct roff *r, const char *name, const char *string) { struct roffstr *n; char *namecopy; - n = first_string; + n = r->first_string; while (n && strcmp(name, n->name)) n = n->next; - if (n) { - free(n->string); - } else { - if (NULL == (namecopy = strdup(name))) - return(NULL); - if (NULL == (n = malloc(sizeof(struct roffstr)))) { - free(n); - return(NULL); - } + + if (NULL == n) { + namecopy = mandoc_strdup(name); + n = mandoc_malloc(sizeof(struct roffstr)); n->name = namecopy; - n->next = first_string; - first_string = n; - } - if (string) - n->string = strdup(string); - else - n->string = NULL; - return(n->string); -} + n->next = r->first_string; + r->first_string = n; + } else + free(n->string); -char * -roff_getstr(const char *name) -{ - struct roffstr *n; - - n = first_string; - while (n && strcmp(name, n->name)) - n = n->next; - if (n) - return(n->string); - else - return(NULL); + n->string = string ? strdup(string) : NULL; } -char * -roff_getstrn(const char *name, size_t len) + +static const char * +roff_getstrn(const struct roff *r, const char *name, size_t len) { - struct roffstr *n; + const struct roffstr *n; - n = first_string; + n = r->first_string; while (n && (strncmp(name, n->name, len) || '\0' != n->name[len])) n = n->next; - if (n) - return(n->string); - else - return(NULL); + + return(n ? n->string : NULL); } -void -roff_freestr(void) + +static void +roff_freestr(struct roff *r) { struct roffstr *n, *nn; - for (n = first_string; n; n = nn) { + for (n = r->first_string; n; n = nn) { free(n->name); free(n->string); nn = n->next; free(n); } - first_string = NULL; + + r->first_string = NULL; }