=================================================================== RCS file: /cvs/mandoc/roff.c,v retrieving revision 1.196 retrieving revision 1.200 diff -u -p -r1.196 -r1.200 --- mandoc/roff.c 2014/03/07 18:30:11 1.196 +++ mandoc/roff.c 2014/03/20 02:57:28 1.200 @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.196 2014/03/07 18:30:11 schwarze Exp $ */ +/* $Id: roff.c,v 1.200 2014/03/20 02:57:28 schwarze Exp $ */ /* * Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons * Copyright (c) 2010-2014 Ingo Schwarze @@ -76,11 +76,6 @@ enum rofft { ROFF_MAX }; -enum roffrule { - ROFFRULE_DENY, - ROFFRULE_ALLOW -}; - /* * An incredibly-simple string buffer. */ @@ -108,11 +103,10 @@ struct roffreg { }; struct roff { - enum mparset parsetype; /* requested parse type */ struct mparse *parse; /* parse point */ - int quick; /* skip standard macro deletion */ + int options; /* parse options */ struct roffnode *last; /* leaf of stack */ - enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */ + int rstack[RSTACK_MAX]; /* stack of !`ie' rules */ char control; /* control character */ int rstackpos; /* position in rstack */ struct roffreg *regtab; /* number registers */ @@ -136,7 +130,7 @@ struct roffnode { char *name; /* node name, e.g. macro name */ char *end; /* end-rules: custom token */ int endspan; /* end-rules: next-line or infty */ - enum roffrule rule; /* current evaluation rule */ + int rule; /* current evaluation rule */ }; #define ROFF_ARGS struct roff *r, /* parse ctx */ \ @@ -184,7 +178,8 @@ 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 int roff_evalcond(const char *, int *); +static int roff_evalstrcond(const char *, int *); static void roff_free1(struct roff *); static void roff_freereg(struct roffreg *); static void roff_freestr(struct roffkv *); @@ -269,34 +264,36 @@ static struct roffmac roffs[ROFF_MAX] = { { NULL, roff_userdef, NULL, NULL, 0, NULL }, }; +/* not currently implemented: Ds em Eq LP Me PP pp Or Rd Sf SH */ const char *const __mdoc_reserved[] = { "Ac", "Ad", "An", "Ao", "Ap", "Aq", "Ar", "At", "Bc", "Bd", "Bf", "Bk", "Bl", "Bo", "Bq", "Brc", "Bro", "Brq", "Bsx", "Bt", "Bx", "Cd", "Cm", "Db", "Dc", "Dd", "Dl", "Do", "Dq", - "Ds", "Dt", "Dv", "Dx", "D1", - "Ec", "Ed", "Ef", "Ek", "El", "Em", "em", - "En", "Eo", "Eq", "Er", "Es", "Ev", "Ex", + "Dt", "Dv", "Dx", "D1", + "Ec", "Ed", "Ef", "Ek", "El", "Em", + "En", "Eo", "Er", "Es", "Ev", "Ex", "Fa", "Fc", "Fd", "Fl", "Fn", "Fo", "Fr", "Ft", "Fx", - "Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp", "LP", - "Me", "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx", + "Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp", + "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx", "Oc", "Oo", "Op", "Os", "Ot", "Ox", - "Pa", "Pc", "Pf", "Po", "Pp", "PP", "pp", "Pq", - "Qc", "Ql", "Qo", "Qq", "Or", "Rd", "Re", "Rs", "Rv", - "Sc", "Sf", "Sh", "SH", "Sm", "So", "Sq", + "Pa", "Pc", "Pf", "Po", "Pp", "Pq", + "Qc", "Ql", "Qo", "Qq", "Re", "Rs", "Rv", + "Sc", "Sh", "Sm", "So", "Sq", "Ss", "St", "Sx", "Sy", "Ta", "Tn", "Ud", "Ux", "Va", "Vt", "Xc", "Xo", "Xr", - "%A", "%B", "%D", "%I", "%J", "%N", "%O", + "%A", "%B", "%C", "%D", "%I", "%J", "%N", "%O", "%P", "%Q", "%R", "%T", "%U", "%V", NULL }; +/* not currently implemented: BT DE DS ME MT PT SY TQ YS */ const char *const __man_reserved[] = { - "AT", "B", "BI", "BR", "BT", "DE", "DS", "DT", - "EE", "EN", "EQ", "EX", "HF", "HP", "I", "IB", "IP", "IR", - "LP", "ME", "MT", "OP", "P", "PD", "PP", "PT", - "R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS", "SY", - "TE", "TH", "TP", "TQ", "TS", "T&", "UC", "UE", "UR", "YS", + "AT", "B", "BI", "BR", "DT", + "EE", "EN", "EQ", "EX", "HP", "I", "IB", "IP", "IR", + "LP", "OP", "P", "PD", "PP", + "R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS", + "TE", "TH", "TP", "TS", "T&", "UC", "UE", "UR", NULL }; @@ -401,7 +398,7 @@ roffnode_push(struct roff *r, enum rofft tok, const ch p->parent = r->last; p->line = line; p->col = col; - p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY; + p->rule = p->parent ? p->parent->rule : 0; r->last = p; } @@ -467,14 +464,13 @@ roff_free(struct roff *r) struct roff * -roff_alloc(enum mparset type, struct mparse *parse, int quick) +roff_alloc(struct mparse *parse, int options) { struct roff *r; r = mandoc_calloc(1, sizeof(struct roff)); - r->parsetype = type; r->parse = parse; - r->quick = quick; + r->options = options; r->rstackpos = -1; roffhash_init(); @@ -1050,8 +1046,8 @@ static enum rofferr roff_cond_sub(ROFF_ARGS) { enum rofft t; - enum roffrule rr; char *ep; + int rr; rr = r->last->rule; roffnode_cleanscope(r); @@ -1063,8 +1059,7 @@ roff_cond_sub(ROFF_ARGS) */ if ((ROFF_MAX != t) && - (ROFFRULE_ALLOW == rr || - ROFFMAC_STRUCT & roffs[t].flags)) { + (rr || ROFFMAC_STRUCT & roffs[t].flags)) { assert(roffs[t].proc); return((*roffs[t].proc)(r, t, bufp, szp, ln, ppos, pos, offs)); @@ -1077,17 +1072,18 @@ roff_cond_sub(ROFF_ARGS) ep = *bufp + pos; if ('\\' == ep[0] && '}' == ep[1]) - rr = ROFFRULE_DENY; + rr = 0; /* Always check for the closing delimiter `\}'. */ while (NULL != (ep = strchr(ep, '\\'))) { - if ('}' != *(++ep)) - continue; - *ep = '&'; - roff_ccond(r, ln, pos); + if ('}' == *(++ep)) { + *ep = '&'; + roff_ccond(r, ln, ep - *bufp - 1); + } + ++ep; } - return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); + return(rr ? ROFF_CONT : ROFF_IGN); } /* ARGSUSED */ @@ -1095,20 +1091,20 @@ static enum rofferr roff_cond_text(ROFF_ARGS) { char *ep; - enum roffrule rr; + int rr; rr = r->last->rule; roffnode_cleanscope(r); - ep = &(*bufp)[pos]; - for ( ; NULL != (ep = strchr(ep, '\\')); ep++) { - ep++; - if ('}' != *ep) - continue; - *ep = '&'; - roff_ccond(r, ln, pos); + ep = *bufp + pos; + while (NULL != (ep = strchr(ep, '\\'))) { + if ('}' == *(++ep)) { + *ep = '&'; + roff_ccond(r, ln, ep - *bufp - 1); + } + ++ep; } - return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); + return(rr ? ROFF_CONT : ROFF_IGN); } static int @@ -1161,64 +1157,103 @@ roff_getop(const char *v, int *pos, char *res) return(*res); } -static enum roffrule +/* + * Evaluate a string comparison condition. + * The first character is the delimiter. + * Succeed if the string up to its second occurrence + * matches the string up to its third occurence. + * Advance the cursor after the third occurrence + * or lacking that, to the end of the line. + */ +static int +roff_evalstrcond(const char *v, int *pos) +{ + const char *s1, *s2, *s3; + int match; + + match = 0; + s1 = v + *pos; /* initial delimiter */ + s2 = s1 + 1; /* for scanning the first string */ + s3 = strchr(s2, *s1); /* for scanning the second string */ + + if (NULL == s3) /* found no middle delimiter */ + goto out; + + while ('\0' != *++s3) { + if (*s2 != *s3) { /* mismatch */ + s3 = strchr(s3, *s1); + break; + } + if (*s3 == *s1) { /* found the final delimiter */ + match = 1; + break; + } + s2++; + } + +out: + if (NULL == s3) + s3 = strchr(s2, '\0'); + else + s3++; + *pos = s3 - v; + return(match); +} + +static int roff_evalcond(const char *v, int *pos) { - int not, lh, rh; + int wanttrue, lh, rh; char op; + if ('!' == v[*pos]) { + wanttrue = 0; + (*pos)++; + } else + wanttrue = 1; + switch (v[*pos]) { case ('n'): + /* FALLTHROUGH */ + case ('o'): (*pos)++; - return(ROFFRULE_ALLOW); + return(wanttrue); + case ('c'): + /* FALLTHROUGH */ + case ('d'): + /* FALLTHROUGH */ case ('e'): /* FALLTHROUGH */ - case ('o'): + case ('r'): /* FALLTHROUGH */ case ('t'): (*pos)++; - return(ROFFRULE_DENY); - case ('!'): - (*pos)++; - not = 1; - break; + return(!wanttrue); default: - not = 0; break; } if (!roff_getnum(v, pos, &lh)) - return ROFFRULE_DENY; - if (!roff_getop(v, pos, &op)) { - if (lh < 0) - lh = 0; - goto out; - } + return(roff_evalstrcond(v, pos) == wanttrue); + if (!roff_getop(v, pos, &op)) + return((lh > 0) == wanttrue); if (!roff_getnum(v, pos, &rh)) - return ROFFRULE_DENY; + return(0); + switch (op) { case 'g': - lh = lh >= rh; - break; + return((lh >= rh) == wanttrue); case 'l': - lh = lh <= rh; - break; + return((lh <= rh) == wanttrue); case '=': - lh = lh == rh; - break; + return((lh == rh) == wanttrue); case '>': - lh = lh > rh; - break; + return((lh > rh) == wanttrue); case '<': - lh = lh < rh; - break; + return((lh < rh) == wanttrue); default: - return ROFFRULE_DENY; + return(0); } -out: - if (not) - lh = !lh; - return lh ? ROFFRULE_ALLOW : ROFFRULE_DENY; } /* ARGSUSED */ @@ -1245,8 +1280,7 @@ roff_cond(ROFF_ARGS) */ r->last->rule = ROFF_el == tok ? - (r->rstackpos < 0 ? - ROFFRULE_DENY : r->rstack[r->rstackpos--]) : + (r->rstackpos < 0 ? 0 : r->rstack[r->rstackpos--]) : roff_evalcond(*bufp, &pos); /* @@ -1260,15 +1294,13 @@ roff_cond(ROFF_ARGS) r->parse, ln, ppos, NULL); return(ROFF_ERR); } - r->rstack[++r->rstackpos] = - ROFFRULE_DENY == r->last->rule ? - ROFFRULE_ALLOW : ROFFRULE_DENY; + r->rstack[++r->rstackpos] = !r->last->rule; } /* If the parent has false as its rule, then so do we. */ - if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule) - r->last->rule = ROFFRULE_DENY; + if (r->last->parent && !r->last->parent->rule) + r->last->rule = 0; /* * Determine scope. @@ -1520,7 +1552,7 @@ roff_Dd(ROFF_ARGS) { const char *const *cp; - if (0 == r->quick && MPARSE_MDOC != r->parsetype) + if (0 == ((MPARSE_MDOC | MPARSE_QUICK) & r->options)) for (cp = __mdoc_reserved; *cp; cp++) roff_setstr(r, *cp, NULL, 0); @@ -1533,7 +1565,7 @@ roff_TH(ROFF_ARGS) { const char *const *cp; - if (0 == r->quick && MPARSE_MDOC != r->parsetype) + if (0 == (MPARSE_QUICK & r->options)) for (cp = __man_reserved; *cp; cp++) roff_setstr(r, *cp, NULL, 0);