=================================================================== RCS file: /cvs/mandoc/roff.c,v retrieving revision 1.151 retrieving revision 1.161 diff -u -p -r1.151 -r1.161 --- mandoc/roff.c 2011/07/25 15:37:00 1.151 +++ mandoc/roff.c 2011/07/27 14:58:28 1.161 @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.151 2011/07/25 15:37:00 kristaps Exp $ */ +/* $Id: roff.c,v 1.161 2011/07/27 14:58:28 kristaps Exp $ */ /* * Copyright (c) 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010, 2011 Ingo Schwarze @@ -82,8 +82,8 @@ struct reg { }; struct roffstr { - char *name; /* key of symbol */ - char *string; /* current value */ + char *key; /* key of symbol */ + char *val; /* current value */ struct roffstr *next; /* next in list */ }; @@ -143,6 +143,12 @@ struct predef { #define PREDEF(__name, __str) \ { (__name), (__str) }, +static enum rofft roffhash_find(const char *, size_t); +static void roffhash_init(void); +static void roffnode_cleanscope(struct roff *); +static void roffnode_pop(struct roff *); +static void roffnode_push(struct roff *, enum rofft, + const char *, int, int); static enum rofferr roff_block(ROFF_ARGS); static enum rofferr roff_block_text(ROFF_ARGS); static enum rofferr roff_block_sub(ROFF_ARGS); @@ -153,13 +159,18 @@ 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_free1(struct roff *); static void roff_freestr(struct roff *); static char *roff_getname(struct roff *, char **, int, int); static const char *roff_getstrn(const struct roff *, const char *, size_t); static enum rofferr roff_line_ignore(ROFF_ARGS); static enum rofferr roff_nr(ROFF_ARGS); -static int roff_res(struct roff *, +static void roff_openeqn(struct roff *, const char *, + int, int, const char *); +static enum rofft roff_parse(struct roff *, const char *, int *); +static enum rofferr roff_parsetext(char *); +static void roff_res(struct roff *, char **, size_t *, int, int); static enum rofferr roff_rm(ROFF_ARGS); static void roff_setstr(struct roff *, @@ -172,7 +183,7 @@ static enum rofferr roff_EN(ROFF_ARGS); static enum rofferr roff_T_(ROFF_ARGS); static enum rofferr roff_userdef(ROFF_ARGS); -/* See roff_hash_find() */ +/* See roffhash_find() */ #define ASCII_HI 126 #define ASCII_LO 33 @@ -220,20 +231,11 @@ static const struct predef predefs[PREDEFS_MAX] = { #include "predefs.in" }; -static void roff_free1(struct roff *); -static enum rofft roff_hash_find(const char *, size_t); -static void roff_hash_init(void); -static void roffnode_cleanscope(struct roff *); -static void roffnode_push(struct roff *, enum rofft, - const char *, int, int); -static void roffnode_pop(struct roff *); -static enum rofft roff_parse(struct roff *, const char *, int *); - -/* See roff_hash_find() */ +/* See roffhash_find() */ #define ROFF_HASH(p) (p[0] - ASCII_LO) static void -roff_hash_init(void) +roffhash_init(void) { struct roffmac *n; int buc, i; @@ -258,7 +260,7 @@ roff_hash_init(void) * the nil-terminated string name could be found. */ static enum rofft -roff_hash_find(const char *p, size_t s) +roffhash_find(const char *p, size_t s) { int buc; struct roffmac *n; @@ -387,7 +389,7 @@ roff_alloc(struct mparse *parse) r->parse = parse; r->rstackpos = -1; - roff_hash_init(); + roffhash_init(); for (i = 0; i < PREDEFS_MAX; i++) roff_setstr(r, predefs[i].name, predefs[i].str, 0); @@ -395,15 +397,16 @@ roff_alloc(struct mparse *parse) return(r); } - /* * 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. + * This also checks the syntax of regular escapes. */ -static int +static void roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos) { + enum mandoc_esc esc; const char *stesc; /* start of an escape sequence ('\\') */ const char *stnam; /* start of the name, after "[(*" */ const char *cp; /* end of the name, e.g. before ']' */ @@ -412,8 +415,7 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int size_t nsz; char *n; - /* Search for a leading backslash and save a pointer to it. */ - +again: cp = *bufp + pos; while (NULL != (cp = strchr(cp, '\\'))) { stesc = cp++; @@ -425,10 +427,22 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int */ if ('\0' == *cp) - return(1); - if ('*' != *cp++) - continue; + return; + if ('*' != *cp) { + res = cp; + esc = mandoc_escape(&cp, NULL, NULL); + if (ESCAPE_ERROR != esc) + continue; + cp = res; + mandoc_msg + (MANDOCERR_BADESCAPE, r->parse, + ln, (int)(stesc - *bufp), NULL); + return; + } + + cp++; + /* * The third character decides the length * of the name of the string. @@ -437,7 +451,7 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int switch (*cp) { case ('\0'): - return(1); + return; case ('('): cp++; maxl = 2; @@ -455,8 +469,13 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int /* Advance to the end of the name. */ for (i = 0; 0 == maxl || i < maxl; i++, cp++) { - if ('\0' == *cp) - return(1); /* Error. */ + if ('\0' == *cp) { + mandoc_msg + (MANDOCERR_BADESCAPE, + r->parse, ln, + (int)(stesc - *bufp), NULL); + return; + } if (0 == maxl && ']' == *cp) break; } @@ -469,13 +488,16 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int res = roff_getstrn(r, stnam, (size_t)i); if (NULL == res) { - /* TODO: keep track of the correct position. */ - mandoc_msg(MANDOCERR_BADESCAPE, r->parse, ln, pos, NULL); + mandoc_msg + (MANDOCERR_BADESCAPE, r->parse, + ln, (int)(stesc - *bufp), NULL); res = ""; } /* Replace the escape sequence by the string. */ + pos = stesc - *bufp; + nsz = *szp + strlen(res) + 1; n = mandoc_malloc(nsz); @@ -487,13 +509,58 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int *bufp = n; *szp = nsz; - return(0); + goto again; } - - return(1); } +/* + * Process text streams: convert all breakable hyphens into ASCII_HYPH. + */ +static enum rofferr +roff_parsetext(char *p) +{ + char l, r; + size_t sz; + const char *start; + enum mandoc_esc esc; + start = p; + + while ('\0' != *p) { + sz = strcspn(p, "-\\"); + p += sz; + + if ('\0' == *p) + break; + + if ('\\' == *p) { + /* Skip over escapes. */ + p++; + esc = mandoc_escape + ((const char **)&p, NULL, NULL); + if (ESCAPE_ERROR == esc) + break; + continue; + } else if (p == start) { + p++; + continue; + } + + l = *(p - 1); + r = *(p + 1); + if ('\\' != l && + '\t' != r && '\t' != l && + ' ' != r && ' ' != l && + '-' != r && '-' != l && + ! isdigit((unsigned char)l) && + ! isdigit((unsigned char)r)) + *p = ASCII_HYPH; + p++; + } + + return(ROFF_CONT); +} + enum rofferr roff_parseln(struct roff *r, int ln, char **bufp, size_t *szp, int pos, int *offs) @@ -507,8 +574,7 @@ roff_parseln(struct roff *r, int ln, char **bufp, * words to fill in. */ - if (r->first_string && ! roff_res(r, bufp, szp, ln, pos)) - return(ROFF_REPARSE); + roff_res(r, bufp, szp, ln, pos); ppos = pos; ctl = mandoc_getcontrol(*bufp, &pos); @@ -533,13 +599,13 @@ roff_parseln(struct roff *r, int ln, char **bufp, return(eqn_read(&r->eqn, ln, *bufp, pos, offs)); if (r->tbl) return(tbl_read(r->tbl, ln, *bufp, pos)); - return(ROFF_CONT); + return(roff_parsetext(*bufp + pos)); } else if ( ! ctl) { if (r->eqn) return(eqn_read(&r->eqn, ln, *bufp, pos, offs)); if (r->tbl) return(tbl_read(r->tbl, ln, *bufp, pos)); - return(ROFF_CONT); + return(roff_parsetext(*bufp + pos)); } else if (r->eqn) return(eqn_read(&r->eqn, ln, *bufp, ppos, offs)); @@ -619,7 +685,7 @@ roff_parse(struct roff *r, const char *buf, int *pos) maclen = strcspn(mac + 1, " \\\t\0") + 1; t = (r->current_string = roff_getstrn(r, mac, maclen)) - ? ROFF_USERDEF : roff_hash_find(mac, maclen); + ? ROFF_USERDEF : roffhash_find(mac, maclen); *pos += (int)maclen; @@ -1198,14 +1264,16 @@ roff_T_(ROFF_ARGS) return(ROFF_IGN); } -int +#if 0 +static int roff_closeeqn(struct roff *r) { return(r->eqn && ROFF_EQN == eqn_end(&r->eqn) ? 1 : 0); } +#endif -void +static void roff_openeqn(struct roff *r, const char *name, int line, int offs, const char *buf) { @@ -1397,20 +1465,20 @@ roff_setstr(struct roff *r, const char *name, const ch /* Search for an existing string with the same name. */ n = r->first_string; - while (n && strcmp(name, n->name)) + while (n && strcmp(name, n->key)) n = n->next; if (NULL == n) { /* Create a new string table entry. */ n = mandoc_malloc(sizeof(struct roffstr)); - n->name = mandoc_strdup(name); - n->string = NULL; + n->key = mandoc_strdup(name); + n->val = NULL; n->next = r->first_string; r->first_string = n; } else if (0 == multiline) { /* In multiline mode, append; else replace. */ - free(n->string); - n->string = NULL; + free(n->val); + n->val = NULL; } if (NULL == string) @@ -1421,17 +1489,17 @@ roff_setstr(struct roff *r, const char *name, const ch * and one for the terminating '\0'. */ newch = strlen(string) + (multiline ? 2u : 1u); - if (NULL == n->string) { - n->string = mandoc_malloc(newch); - *n->string = '\0'; + if (NULL == n->val) { + n->val = mandoc_malloc(newch); + *n->val = '\0'; oldch = 0; } else { - oldch = strlen(n->string); - n->string = mandoc_realloc(n->string, oldch + newch); + oldch = strlen(n->val); + n->val = mandoc_realloc(n->val, oldch + newch); } /* Skip existing content in the destination buffer. */ - c = n->string + (int)oldch; + c = n->val + (int)oldch; /* Append new content to the destination buffer. */ while (*string) { @@ -1455,11 +1523,12 @@ roff_getstrn(const struct roff *r, const char *name, s { const struct roffstr *n; - n = r->first_string; - while (n && (strncmp(name, n->name, len) || '\0' != n->name[(int)len])) - n = n->next; + for (n = r->first_string; n; n = n->next) + if (0 == strncmp(name, n->key, len) && + '\0' == n->key[(int)len]) + return(n->val); - return(n ? n->string : NULL); + return(NULL); } static void @@ -1468,8 +1537,8 @@ roff_freestr(struct roff *r) struct roffstr *n, *nn; for (n = r->first_string; n; n = nn) { - free(n->name); - free(n->string); + free(n->key); + free(n->val); nn = n->next; free(n); }