=================================================================== RCS file: /cvs/mandoc/roff.c,v retrieving revision 1.152 retrieving revision 1.163 diff -u -p -r1.152 -r1.163 --- mandoc/roff.c 2011/07/26 14:09:01 1.152 +++ mandoc/roff.c 2011/07/27 20:55:28 1.163 @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.152 2011/07/26 14:09:01 kristaps Exp $ */ +/* $Id: roff.c,v 1.163 2011/07/27 20:55:28 kristaps Exp $ */ /* * Copyright (c) 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010, 2011 Ingo Schwarze @@ -82,8 +82,10 @@ struct reg { }; struct roffstr { - char *name; /* key of symbol */ - char *string; /* current value */ + char *key; /* key of symbol */ + size_t keysz; + char *val; /* current value */ + size_t valsz; struct roffstr *next; /* next in list */ }; @@ -143,6 +145,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 +161,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 +185,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 +233,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 +262,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 +391,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,13 +399,13 @@ 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; @@ -413,8 +417,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++; @@ -426,17 +429,18 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int */ if ('\0' == *cp) - return(1); + return; if ('*' != *cp) { res = cp; esc = mandoc_escape(&cp, NULL, NULL); if (ESCAPE_ERROR != esc) continue; - mandoc_msg(MANDOCERR_BADESCAPE, - r->parse, ln, pos, NULL); cp = res; - continue; + mandoc_msg + (MANDOCERR_BADESCAPE, r->parse, + ln, (int)(stesc - *bufp), NULL); + return; } cp++; @@ -449,7 +453,7 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int switch (*cp) { case ('\0'): - return(1); + return; case ('('): cp++; maxl = 2; @@ -467,8 +471,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; } @@ -481,13 +490,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); @@ -499,13 +511,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) @@ -519,8 +576,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); @@ -545,13 +601,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)); @@ -631,7 +687,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; @@ -1210,14 +1266,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) { @@ -1409,20 +1467,23 @@ 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->keysz = strlen(name); + n->val = NULL; + n->valsz = 0; 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; + n->valsz = 0; } if (NULL == string) @@ -1433,17 +1494,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 = n->valsz; + 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) { @@ -1459,7 +1520,9 @@ roff_setstr(struct roff *r, const char *name, const ch /* Append terminating bytes. */ if (multiline) *c++ = '\n'; + *c = '\0'; + n->valsz = (int)(c - n->val); } static const char * @@ -1467,11 +1530,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 @@ -1480,8 +1544,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); }