Annotation of mandoc/roff.c, Revision 1.190
1.190 ! schwarze 1: /* $Id: roff.c,v 1.189 2013/12/30 18:44:06 schwarze Exp $ */
1.1 kristaps 2: /*
1.175 schwarze 3: * Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
1.190 ! schwarze 4: * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
1.1 kristaps 5: *
6: * Permission to use, copy, modify, and distribute this software for any
1.66 kristaps 7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 9: *
1.106 kristaps 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
1.66 kristaps 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1.106 kristaps 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
1.66 kristaps 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 17: */
1.66 kristaps 18: #ifdef HAVE_CONFIG_H
19: #include "config.h"
20: #endif
1.30 kristaps 21:
1.67 kristaps 22: #include <assert.h>
1.85 kristaps 23: #include <ctype.h>
1.178 schwarze 24: #include <stdio.h>
1.1 kristaps 25: #include <stdlib.h>
1.67 kristaps 26: #include <string.h>
1.1 kristaps 27:
1.67 kristaps 28: #include "mandoc.h"
1.109 kristaps 29: #include "libroff.h"
1.94 kristaps 30: #include "libmandoc.h"
1.33 kristaps 31:
1.141 kristaps 32: /* Maximum number of nested if-else conditionals. */
1.82 kristaps 33: #define RSTACK_MAX 128
34:
1.170 schwarze 35: /* Maximum number of string expansions per line, to break infinite loops. */
36: #define EXPAND_LIMIT 1000
37:
1.67 kristaps 38: enum rofft {
1.103 kristaps 39: ROFF_ad,
1.80 kristaps 40: ROFF_am,
41: ROFF_ami,
42: ROFF_am1,
1.174 kristaps 43: ROFF_cc,
1.80 kristaps 44: ROFF_de,
45: ROFF_dei,
46: ROFF_de1,
1.83 schwarze 47: ROFF_ds,
1.82 kristaps 48: ROFF_el,
1.185 schwarze 49: ROFF_fam,
1.186 schwarze 50: ROFF_hw,
1.103 kristaps 51: ROFF_hy,
1.82 kristaps 52: ROFF_ie,
1.75 kristaps 53: ROFF_if,
1.76 kristaps 54: ROFF_ig,
1.123 schwarze 55: ROFF_it,
1.103 kristaps 56: ROFF_ne,
57: ROFF_nh,
1.104 kristaps 58: ROFF_nr,
1.124 schwarze 59: ROFF_ns,
60: ROFF_ps,
1.83 schwarze 61: ROFF_rm,
1.105 kristaps 62: ROFF_so,
1.124 schwarze 63: ROFF_ta,
1.83 schwarze 64: ROFF_tr,
1.175 schwarze 65: ROFF_Dd,
66: ROFF_TH,
1.109 kristaps 67: ROFF_TS,
68: ROFF_TE,
1.112 kristaps 69: ROFF_T_,
1.125 kristaps 70: ROFF_EQ,
71: ROFF_EN,
1.76 kristaps 72: ROFF_cblock,
1.141 kristaps 73: ROFF_ccond,
1.106 kristaps 74: ROFF_USERDEF,
1.67 kristaps 75: ROFF_MAX
76: };
77:
1.82 kristaps 78: enum roffrule {
1.183 schwarze 79: ROFFRULE_DENY,
80: ROFFRULE_ALLOW
1.82 kristaps 81: };
82:
1.147 kristaps 83: /*
1.167 kristaps 84: * An incredibly-simple string buffer.
85: */
1.94 kristaps 86: struct roffstr {
1.167 kristaps 87: char *p; /* nil-terminated buffer */
88: size_t sz; /* saved strlen(p) */
1.166 kristaps 89: };
90:
91: /*
1.167 kristaps 92: * A key-value roffstr pair as part of a singly-linked list.
1.166 kristaps 93: */
94: struct roffkv {
95: struct roffstr key;
96: struct roffstr val;
97: struct roffkv *next; /* next in list */
1.94 kristaps 98: };
99:
1.180 schwarze 100: /*
101: * A single number register as part of a singly-linked list.
102: */
103: struct roffreg {
104: struct roffstr key;
1.181 schwarze 105: int val;
1.180 schwarze 106: struct roffreg *next;
107: };
108:
1.67 kristaps 109: struct roff {
1.175 schwarze 110: enum mparset parsetype; /* requested parse type */
1.128 kristaps 111: struct mparse *parse; /* parse point */
1.190 ! schwarze 112: int quick; /* skip standard macro deletion */
1.67 kristaps 113: struct roffnode *last; /* leaf of stack */
1.82 kristaps 114: enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */
1.174 kristaps 115: char control; /* control character */
1.82 kristaps 116: int rstackpos; /* position in rstack */
1.180 schwarze 117: struct roffreg *regtab; /* number registers */
1.166 kristaps 118: struct roffkv *strtab; /* user-defined strings & macros */
1.167 kristaps 119: struct roffkv *xmbtab; /* multi-byte trans table (`tr') */
120: struct roffstr *xtab; /* single-byte trans table (`tr') */
1.106 kristaps 121: const char *current_string; /* value of last called user macro */
1.118 kristaps 122: struct tbl_node *first_tbl; /* first table parsed */
123: struct tbl_node *last_tbl; /* last table parsed */
124: struct tbl_node *tbl; /* current table being parsed */
1.125 kristaps 125: struct eqn_node *last_eqn; /* last equation parsed */
126: struct eqn_node *first_eqn; /* first equation parsed */
127: struct eqn_node *eqn; /* current equation being parsed */
1.79 kristaps 128: };
129:
1.67 kristaps 130: struct roffnode {
131: enum rofft tok; /* type of node */
132: struct roffnode *parent; /* up one in stack */
133: int line; /* parse line */
134: int col; /* parse col */
1.106 kristaps 135: char *name; /* node name, e.g. macro name */
1.79 kristaps 136: char *end; /* end-rules: custom token */
137: int endspan; /* end-rules: next-line or infty */
1.82 kristaps 138: enum roffrule rule; /* current evaluation rule */
1.67 kristaps 139: };
140:
141: #define ROFF_ARGS struct roff *r, /* parse ctx */ \
1.72 kristaps 142: enum rofft tok, /* tok of macro */ \
1.67 kristaps 143: char **bufp, /* input buffer */ \
144: size_t *szp, /* size of input buffer */ \
145: int ln, /* parse line */ \
1.75 kristaps 146: int ppos, /* original pos in buffer */ \
147: int pos, /* current pos in buffer */ \
1.74 kristaps 148: int *offs /* reset offset of buffer data */
1.67 kristaps 149:
150: typedef enum rofferr (*roffproc)(ROFF_ARGS);
151:
152: struct roffmac {
153: const char *name; /* macro name */
1.79 kristaps 154: roffproc proc; /* process new macro */
155: roffproc text; /* process as child text of macro */
156: roffproc sub; /* process as child of macro */
157: int flags;
158: #define ROFFMAC_STRUCT (1 << 0) /* always interpret */
1.85 kristaps 159: struct roffmac *next;
1.67 kristaps 160: };
161:
1.141 kristaps 162: struct predef {
163: const char *name; /* predefined input name */
164: const char *str; /* replacement symbol */
165: };
166:
167: #define PREDEF(__name, __str) \
168: { (__name), (__str) },
169:
1.155 kristaps 170: static enum rofft roffhash_find(const char *, size_t);
171: static void roffhash_init(void);
172: static void roffnode_cleanscope(struct roff *);
173: static void roffnode_pop(struct roff *);
174: static void roffnode_push(struct roff *, enum rofft,
175: const char *, int, int);
1.80 kristaps 176: static enum rofferr roff_block(ROFF_ARGS);
177: static enum rofferr roff_block_text(ROFF_ARGS);
178: static enum rofferr roff_block_sub(ROFF_ARGS);
179: static enum rofferr roff_cblock(ROFF_ARGS);
1.174 kristaps 180: static enum rofferr roff_cc(ROFF_ARGS);
1.80 kristaps 181: static enum rofferr roff_ccond(ROFF_ARGS);
1.82 kristaps 182: static enum rofferr roff_cond(ROFF_ARGS);
183: static enum rofferr roff_cond_text(ROFF_ARGS);
184: static enum rofferr roff_cond_sub(ROFF_ARGS);
1.92 schwarze 185: static enum rofferr roff_ds(ROFF_ARGS);
1.94 kristaps 186: static enum roffrule roff_evalcond(const char *, int *);
1.155 kristaps 187: static void roff_free1(struct roff *);
1.180 schwarze 188: static void roff_freereg(struct roffreg *);
1.167 kristaps 189: static void roff_freestr(struct roffkv *);
1.121 schwarze 190: static char *roff_getname(struct roff *, char **, int, int);
1.184 schwarze 191: static int roff_getnum(const char *, int *, int *);
192: static int roff_getop(const char *, int *, char *);
1.181 schwarze 193: static int roff_getregn(const struct roff *,
194: const char *, size_t);
1.94 kristaps 195: static const char *roff_getstrn(const struct roff *,
196: const char *, size_t);
1.178 schwarze 197: static enum rofferr roff_it(ROFF_ARGS);
1.103 kristaps 198: static enum rofferr roff_line_ignore(ROFF_ARGS);
1.89 kristaps 199: static enum rofferr roff_nr(ROFF_ARGS);
1.169 schwarze 200: static void roff_openeqn(struct roff *, const char *,
1.156 kristaps 201: int, int, const char *);
1.155 kristaps 202: static enum rofft roff_parse(struct roff *, const char *, int *);
1.178 schwarze 203: static enum rofferr roff_parsetext(char **, size_t *, int, int *);
1.172 schwarze 204: static enum rofferr roff_res(struct roff *,
1.142 kristaps 205: char **, size_t *, int, int);
1.122 schwarze 206: static enum rofferr roff_rm(ROFF_ARGS);
1.94 kristaps 207: static void roff_setstr(struct roff *,
1.106 kristaps 208: const char *, const char *, int);
1.166 kristaps 209: static void roff_setstrn(struct roffkv **, const char *,
1.164 kristaps 210: size_t, const char *, size_t, int);
1.105 kristaps 211: static enum rofferr roff_so(ROFF_ARGS);
1.164 kristaps 212: static enum rofferr roff_tr(ROFF_ARGS);
1.175 schwarze 213: static enum rofferr roff_Dd(ROFF_ARGS);
214: static enum rofferr roff_TH(ROFF_ARGS);
1.109 kristaps 215: static enum rofferr roff_TE(ROFF_ARGS);
216: static enum rofferr roff_TS(ROFF_ARGS);
1.125 kristaps 217: static enum rofferr roff_EQ(ROFF_ARGS);
218: static enum rofferr roff_EN(ROFF_ARGS);
1.112 kristaps 219: static enum rofferr roff_T_(ROFF_ARGS);
1.106 kristaps 220: static enum rofferr roff_userdef(ROFF_ARGS);
1.67 kristaps 221:
1.155 kristaps 222: /* See roffhash_find() */
1.85 kristaps 223:
224: #define ASCII_HI 126
225: #define ASCII_LO 33
226: #define HASHWIDTH (ASCII_HI - ASCII_LO + 1)
227:
228: static struct roffmac *hash[HASHWIDTH];
229:
230: static struct roffmac roffs[ROFF_MAX] = {
1.103 kristaps 231: { "ad", roff_line_ignore, NULL, NULL, 0, NULL },
1.85 kristaps 232: { "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
233: { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
234: { "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
1.174 kristaps 235: { "cc", roff_cc, NULL, NULL, 0, NULL },
1.85 kristaps 236: { "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
237: { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
238: { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
1.92 schwarze 239: { "ds", roff_ds, NULL, NULL, 0, NULL },
1.85 kristaps 240: { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
1.185 schwarze 241: { "fam", roff_line_ignore, NULL, NULL, 0, NULL },
1.186 schwarze 242: { "hw", roff_line_ignore, NULL, NULL, 0, NULL },
1.103 kristaps 243: { "hy", roff_line_ignore, NULL, NULL, 0, NULL },
1.85 kristaps 244: { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
245: { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
246: { "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL },
1.178 schwarze 247: { "it", roff_it, NULL, NULL, 0, NULL },
1.103 kristaps 248: { "ne", roff_line_ignore, NULL, NULL, 0, NULL },
249: { "nh", roff_line_ignore, NULL, NULL, 0, NULL },
1.104 kristaps 250: { "nr", roff_nr, NULL, NULL, 0, NULL },
1.124 schwarze 251: { "ns", roff_line_ignore, NULL, NULL, 0, NULL },
252: { "ps", roff_line_ignore, NULL, NULL, 0, NULL },
1.122 schwarze 253: { "rm", roff_rm, NULL, NULL, 0, NULL },
1.105 kristaps 254: { "so", roff_so, NULL, NULL, 0, NULL },
1.124 schwarze 255: { "ta", roff_line_ignore, NULL, NULL, 0, NULL },
1.164 kristaps 256: { "tr", roff_tr, NULL, NULL, 0, NULL },
1.175 schwarze 257: { "Dd", roff_Dd, NULL, NULL, 0, NULL },
258: { "TH", roff_TH, NULL, NULL, 0, NULL },
1.109 kristaps 259: { "TS", roff_TS, NULL, NULL, 0, NULL },
260: { "TE", roff_TE, NULL, NULL, 0, NULL },
1.112 kristaps 261: { "T&", roff_T_, NULL, NULL, 0, NULL },
1.125 kristaps 262: { "EQ", roff_EQ, NULL, NULL, 0, NULL },
263: { "EN", roff_EN, NULL, NULL, 0, NULL },
1.85 kristaps 264: { ".", roff_cblock, NULL, NULL, 0, NULL },
265: { "\\}", roff_ccond, NULL, NULL, 0, NULL },
1.106 kristaps 266: { NULL, roff_userdef, NULL, NULL, 0, NULL },
1.67 kristaps 267: };
268:
1.175 schwarze 269: const char *const __mdoc_reserved[] = {
270: "Ac", "Ad", "An", "Ao", "Ap", "Aq", "Ar", "At",
271: "Bc", "Bd", "Bf", "Bk", "Bl", "Bo", "Bq",
272: "Brc", "Bro", "Brq", "Bsx", "Bt", "Bx",
273: "Cd", "Cm", "Db", "Dc", "Dd", "Dl", "Do", "Dq",
274: "Ds", "Dt", "Dv", "Dx", "D1",
275: "Ec", "Ed", "Ef", "Ek", "El", "Em", "em",
276: "En", "Eo", "Eq", "Er", "Es", "Ev", "Ex",
277: "Fa", "Fc", "Fd", "Fl", "Fn", "Fo", "Fr", "Ft", "Fx",
278: "Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp", "LP",
279: "Me", "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx",
280: "Oc", "Oo", "Op", "Os", "Ot", "Ox",
281: "Pa", "Pc", "Pf", "Po", "Pp", "PP", "pp", "Pq",
282: "Qc", "Ql", "Qo", "Qq", "Or", "Rd", "Re", "Rs", "Rv",
283: "Sc", "Sf", "Sh", "SH", "Sm", "So", "Sq",
284: "Ss", "St", "Sx", "Sy",
285: "Ta", "Tn", "Ud", "Ux", "Va", "Vt", "Xc", "Xo", "Xr",
286: "%A", "%B", "%D", "%I", "%J", "%N", "%O",
287: "%P", "%Q", "%R", "%T", "%U", "%V",
288: NULL
289: };
290:
291: const char *const __man_reserved[] = {
292: "AT", "B", "BI", "BR", "BT", "DE", "DS", "DT",
293: "EE", "EN", "EQ", "EX", "HF", "HP", "I", "IB", "IP", "IR",
294: "LP", "ME", "MT", "OP", "P", "PD", "PP", "PT",
295: "R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS", "SY",
296: "TE", "TH", "TP", "TQ", "TS", "T&", "UC", "UE", "UR", "YS",
297: NULL
298: };
299:
1.141 kristaps 300: /* Array of injected predefined strings. */
301: #define PREDEFS_MAX 38
302: static const struct predef predefs[PREDEFS_MAX] = {
303: #include "predefs.in"
304: };
305:
1.155 kristaps 306: /* See roffhash_find() */
1.85 kristaps 307: #define ROFF_HASH(p) (p[0] - ASCII_LO)
308:
1.178 schwarze 309: static int roffit_lines; /* number of lines to delay */
310: static char *roffit_macro; /* nil-terminated macro line */
311:
1.85 kristaps 312: static void
1.155 kristaps 313: roffhash_init(void)
1.85 kristaps 314: {
315: struct roffmac *n;
316: int buc, i;
317:
1.106 kristaps 318: for (i = 0; i < (int)ROFF_USERDEF; i++) {
1.85 kristaps 319: assert(roffs[i].name[0] >= ASCII_LO);
320: assert(roffs[i].name[0] <= ASCII_HI);
321:
322: buc = ROFF_HASH(roffs[i].name);
323:
324: if (NULL != (n = hash[buc])) {
325: for ( ; n->next; n = n->next)
326: /* Do nothing. */ ;
327: n->next = &roffs[i];
328: } else
329: hash[buc] = &roffs[i];
330: }
331: }
332:
1.67 kristaps 333: /*
334: * Look up a roff token by its name. Returns ROFF_MAX if no macro by
335: * the nil-terminated string name could be found.
336: */
337: static enum rofft
1.155 kristaps 338: roffhash_find(const char *p, size_t s)
1.67 kristaps 339: {
1.85 kristaps 340: int buc;
341: struct roffmac *n;
1.67 kristaps 342:
1.85 kristaps 343: /*
344: * libroff has an extremely simple hashtable, for the time
345: * being, which simply keys on the first character, which must
346: * be printable, then walks a chain. It works well enough until
347: * optimised.
348: */
349:
350: if (p[0] < ASCII_LO || p[0] > ASCII_HI)
351: return(ROFF_MAX);
352:
353: buc = ROFF_HASH(p);
354:
355: if (NULL == (n = hash[buc]))
356: return(ROFF_MAX);
357: for ( ; n; n = n->next)
1.106 kristaps 358: if (0 == strncmp(n->name, p, s) && '\0' == n->name[(int)s])
1.85 kristaps 359: return((enum rofft)(n - roffs));
1.67 kristaps 360:
361: return(ROFF_MAX);
362: }
363:
364:
365: /*
366: * Pop the current node off of the stack of roff instructions currently
367: * pending.
368: */
369: static void
370: roffnode_pop(struct roff *r)
371: {
372: struct roffnode *p;
373:
1.75 kristaps 374: assert(r->last);
375: p = r->last;
1.82 kristaps 376:
1.75 kristaps 377: r->last = r->last->parent;
1.106 kristaps 378: free(p->name);
379: free(p->end);
1.67 kristaps 380: free(p);
381: }
382:
383:
384: /*
385: * Push a roff node onto the instruction stack. This must later be
386: * removed with roffnode_pop().
387: */
1.98 schwarze 388: static void
1.106 kristaps 389: roffnode_push(struct roff *r, enum rofft tok, const char *name,
390: int line, int col)
1.67 kristaps 391: {
392: struct roffnode *p;
393:
1.98 schwarze 394: p = mandoc_calloc(1, sizeof(struct roffnode));
1.67 kristaps 395: p->tok = tok;
1.106 kristaps 396: if (name)
397: p->name = mandoc_strdup(name);
1.67 kristaps 398: p->parent = r->last;
399: p->line = line;
400: p->col = col;
1.79 kristaps 401: p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY;
1.67 kristaps 402:
403: r->last = p;
404: }
405:
406:
407: static void
408: roff_free1(struct roff *r)
409: {
1.176 schwarze 410: struct tbl_node *tbl;
1.125 kristaps 411: struct eqn_node *e;
1.167 kristaps 412: int i;
1.67 kristaps 413:
1.176 schwarze 414: while (NULL != (tbl = r->first_tbl)) {
415: r->first_tbl = tbl->next;
416: tbl_free(tbl);
1.109 kristaps 417: }
418:
1.113 kristaps 419: r->first_tbl = r->last_tbl = r->tbl = NULL;
420:
1.125 kristaps 421: while (NULL != (e = r->first_eqn)) {
422: r->first_eqn = e->next;
423: eqn_free(e);
424: }
425:
426: r->first_eqn = r->last_eqn = r->eqn = NULL;
427:
1.67 kristaps 428: while (r->last)
429: roffnode_pop(r);
1.109 kristaps 430:
1.167 kristaps 431: roff_freestr(r->strtab);
432: roff_freestr(r->xmbtab);
433:
434: r->strtab = r->xmbtab = NULL;
435:
1.180 schwarze 436: roff_freereg(r->regtab);
437:
438: r->regtab = NULL;
439:
1.167 kristaps 440: if (r->xtab)
441: for (i = 0; i < 128; i++)
442: free(r->xtab[i].p);
443:
444: free(r->xtab);
445: r->xtab = NULL;
1.67 kristaps 446: }
447:
448: void
449: roff_reset(struct roff *r)
450: {
1.143 kristaps 451: int i;
1.67 kristaps 452:
453: roff_free1(r);
1.143 kristaps 454:
1.174 kristaps 455: r->control = 0;
1.147 kristaps 456:
1.143 kristaps 457: for (i = 0; i < PREDEFS_MAX; i++)
458: roff_setstr(r, predefs[i].name, predefs[i].str, 0);
1.67 kristaps 459: }
460:
461:
462: void
463: roff_free(struct roff *r)
464: {
465:
466: roff_free1(r);
467: free(r);
468: }
469:
470:
471: struct roff *
1.190 ! schwarze 472: roff_alloc(enum mparset type, struct mparse *parse, int quick)
1.67 kristaps 473: {
474: struct roff *r;
1.141 kristaps 475: int i;
1.67 kristaps 476:
1.98 schwarze 477: r = mandoc_calloc(1, sizeof(struct roff));
1.175 schwarze 478: r->parsetype = type;
1.128 kristaps 479: r->parse = parse;
1.190 ! schwarze 480: r->quick = quick;
1.82 kristaps 481: r->rstackpos = -1;
1.85 kristaps 482:
1.155 kristaps 483: roffhash_init();
1.141 kristaps 484:
485: for (i = 0; i < PREDEFS_MAX; i++)
486: roff_setstr(r, predefs[i].name, predefs[i].str, 0);
487:
1.67 kristaps 488: return(r);
489: }
490:
1.94 kristaps 491: /*
1.181 schwarze 492: * In the current line, expand user-defined strings ("\*")
493: * and references to number registers ("\n").
494: * Also check the syntax of other escape sequences.
1.154 kristaps 495: */
1.172 schwarze 496: static enum rofferr
1.142 kristaps 497: roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
1.94 kristaps 498: {
1.181 schwarze 499: char ubuf[12]; /* buffer to print the number */
1.108 schwarze 500: const char *stesc; /* start of an escape sequence ('\\') */
501: const char *stnam; /* start of the name, after "[(*" */
502: const char *cp; /* end of the name, e.g. before ']' */
503: const char *res; /* the string to be substituted */
1.181 schwarze 504: char *nbuf; /* new buffer to copy bufp to */
505: size_t nsz; /* size of the new buffer */
506: size_t maxl; /* expected length of the escape name */
507: size_t naml; /* actual length of the escape name */
508: int expand_count; /* to avoid infinite loops */
1.94 kristaps 509:
1.170 schwarze 510: expand_count = 0;
511:
1.154 kristaps 512: again:
1.108 schwarze 513: cp = *bufp + pos;
514: while (NULL != (cp = strchr(cp, '\\'))) {
515: stesc = cp++;
516:
517: /*
1.181 schwarze 518: * The second character must be an asterisk or an n.
1.108 schwarze 519: * If it isn't, skip it anyway: It is escaped,
520: * so it can't start another escape sequence.
521: */
522:
523: if ('\0' == *cp)
1.172 schwarze 524: return(ROFF_CONT);
1.152 kristaps 525:
1.181 schwarze 526: switch (*cp) {
527: case ('*'):
528: res = NULL;
529: break;
530: case ('n'):
531: res = ubuf;
532: break;
533: default:
534: if (ESCAPE_ERROR != mandoc_escape(&cp, NULL, NULL))
1.152 kristaps 535: continue;
1.153 kristaps 536: mandoc_msg
537: (MANDOCERR_BADESCAPE, r->parse,
538: ln, (int)(stesc - *bufp), NULL);
1.172 schwarze 539: return(ROFF_CONT);
1.152 kristaps 540: }
541:
542: cp++;
1.108 schwarze 543:
544: /*
545: * The third character decides the length
1.181 schwarze 546: * of the name of the string or register.
1.108 schwarze 547: * Save a pointer to the name.
548: */
549:
1.94 kristaps 550: switch (*cp) {
1.108 schwarze 551: case ('\0'):
1.172 schwarze 552: return(ROFF_CONT);
1.94 kristaps 553: case ('('):
554: cp++;
555: maxl = 2;
556: break;
557: case ('['):
558: cp++;
559: maxl = 0;
560: break;
561: default:
562: maxl = 1;
563: break;
564: }
1.108 schwarze 565: stnam = cp;
1.94 kristaps 566:
1.108 schwarze 567: /* Advance to the end of the name. */
1.94 kristaps 568:
1.181 schwarze 569: for (naml = 0; 0 == maxl || naml < maxl; naml++, cp++) {
1.153 kristaps 570: if ('\0' == *cp) {
571: mandoc_msg
572: (MANDOCERR_BADESCAPE,
573: r->parse, ln,
574: (int)(stesc - *bufp), NULL);
1.172 schwarze 575: return(ROFF_CONT);
1.153 kristaps 576: }
1.94 kristaps 577: if (0 == maxl && ']' == *cp)
578: break;
579: }
580:
1.108 schwarze 581: /*
582: * Retrieve the replacement string; if it is
583: * undefined, resume searching for escapes.
584: */
585:
1.181 schwarze 586: if (NULL == res)
587: res = roff_getstrn(r, stnam, naml);
588: else
589: snprintf(ubuf, sizeof(ubuf), "%d",
590: roff_getregn(r, stnam, naml));
1.94 kristaps 591:
592: if (NULL == res) {
1.153 kristaps 593: mandoc_msg
594: (MANDOCERR_BADESCAPE, r->parse,
595: ln, (int)(stesc - *bufp), NULL);
1.142 kristaps 596: res = "";
1.94 kristaps 597: }
598:
1.108 schwarze 599: /* Replace the escape sequence by the string. */
600:
1.161 kristaps 601: pos = stesc - *bufp;
1.154 kristaps 602:
1.94 kristaps 603: nsz = *szp + strlen(res) + 1;
1.181 schwarze 604: nbuf = mandoc_malloc(nsz);
1.94 kristaps 605:
1.181 schwarze 606: strlcpy(nbuf, *bufp, (size_t)(stesc - *bufp + 1));
607: strlcat(nbuf, res, nsz);
608: strlcat(nbuf, cp + (maxl ? 0 : 1), nsz);
1.94 kristaps 609:
610: free(*bufp);
611:
1.181 schwarze 612: *bufp = nbuf;
1.94 kristaps 613: *szp = nsz;
1.170 schwarze 614:
615: if (EXPAND_LIMIT >= ++expand_count)
616: goto again;
617:
618: /* Just leave the string unexpanded. */
619: mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, ln, pos, NULL);
1.172 schwarze 620: return(ROFF_IGN);
1.154 kristaps 621: }
1.172 schwarze 622: return(ROFF_CONT);
1.154 kristaps 623: }
624:
625: /*
1.178 schwarze 626: * Process text streams:
627: * Convert all breakable hyphens into ASCII_HYPH.
628: * Decrement and spring input line trap.
1.154 kristaps 629: */
630: static enum rofferr
1.178 schwarze 631: roff_parsetext(char **bufp, size_t *szp, int pos, int *offs)
1.154 kristaps 632: {
633: size_t sz;
634: const char *start;
1.178 schwarze 635: char *p;
636: int isz;
1.154 kristaps 637: enum mandoc_esc esc;
638:
1.178 schwarze 639: start = p = *bufp + pos;
1.154 kristaps 640:
641: while ('\0' != *p) {
642: sz = strcspn(p, "-\\");
643: p += sz;
644:
1.159 kristaps 645: if ('\0' == *p)
646: break;
647:
1.154 kristaps 648: if ('\\' == *p) {
649: /* Skip over escapes. */
650: p++;
1.189 schwarze 651: esc = mandoc_escape((const char **)&p, NULL, NULL);
1.154 kristaps 652: if (ESCAPE_ERROR == esc)
653: break;
1.155 kristaps 654: continue;
1.159 kristaps 655: } else if (p == start) {
1.158 kristaps 656: p++;
1.155 kristaps 657: continue;
1.158 kristaps 658: }
1.155 kristaps 659:
1.171 schwarze 660: if (isalpha((unsigned char)p[-1]) &&
661: isalpha((unsigned char)p[1]))
1.155 kristaps 662: *p = ASCII_HYPH;
663: p++;
1.94 kristaps 664: }
665:
1.178 schwarze 666: /* Spring the input line trap. */
667: if (1 == roffit_lines) {
668: isz = asprintf(&p, "%s\n.%s", *bufp, roffit_macro);
669: if (-1 == isz) {
670: perror(NULL);
671: exit((int)MANDOCLEVEL_SYSERR);
672: }
673: free(*bufp);
674: *bufp = p;
675: *szp = isz + 1;
676: *offs = 0;
677: free(roffit_macro);
678: roffit_lines = 0;
679: return(ROFF_REPARSE);
680: } else if (1 < roffit_lines)
681: --roffit_lines;
1.154 kristaps 682: return(ROFF_CONT);
1.94 kristaps 683: }
684:
1.67 kristaps 685: enum rofferr
1.90 kristaps 686: roff_parseln(struct roff *r, int ln, char **bufp,
687: size_t *szp, int pos, int *offs)
1.67 kristaps 688: {
689: enum rofft t;
1.109 kristaps 690: enum rofferr e;
1.130 kristaps 691: int ppos, ctl;
1.79 kristaps 692:
693: /*
1.94 kristaps 694: * Run the reserved-word filter only if we have some reserved
695: * words to fill in.
696: */
697:
1.172 schwarze 698: e = roff_res(r, bufp, szp, ln, pos);
699: if (ROFF_IGN == e)
700: return(e);
701: assert(ROFF_CONT == e);
1.94 kristaps 702:
1.130 kristaps 703: ppos = pos;
1.174 kristaps 704: ctl = roff_getcontrol(r, *bufp, &pos);
1.130 kristaps 705:
1.94 kristaps 706: /*
1.79 kristaps 707: * First, if a scope is open and we're not a macro, pass the
708: * text through the macro's filter. If a scope isn't open and
709: * we're not a macro, just let it through.
1.125 kristaps 710: * Finally, if there's an equation scope open, divert it into it
711: * no matter our state.
1.79 kristaps 712: */
1.74 kristaps 713:
1.130 kristaps 714: if (r->last && ! ctl) {
1.78 kristaps 715: t = r->last->tok;
716: assert(roffs[t].text);
1.109 kristaps 717: e = (*roffs[t].text)
718: (r, t, bufp, szp, ln, pos, pos, offs);
719: assert(ROFF_IGN == e || ROFF_CONT == e);
1.125 kristaps 720: if (ROFF_CONT != e)
721: return(e);
1.182 schwarze 722: }
723: if (r->eqn)
724: return(eqn_read(&r->eqn, ln, *bufp, ppos, offs));
725: if ( ! ctl) {
1.125 kristaps 726: if (r->tbl)
1.130 kristaps 727: return(tbl_read(r->tbl, ln, *bufp, pos));
1.178 schwarze 728: return(roff_parsetext(bufp, szp, pos, offs));
1.182 schwarze 729: }
1.67 kristaps 730:
1.79 kristaps 731: /*
732: * If a scope is open, go to the child handler for that macro,
733: * as it may want to preprocess before doing anything with it.
1.125 kristaps 734: * Don't do so if an equation is open.
1.79 kristaps 735: */
1.78 kristaps 736:
1.79 kristaps 737: if (r->last) {
738: t = r->last->tok;
739: assert(roffs[t].sub);
740: return((*roffs[t].sub)
1.90 kristaps 741: (r, t, bufp, szp,
1.130 kristaps 742: ln, ppos, pos, offs));
1.79 kristaps 743: }
1.78 kristaps 744:
1.79 kristaps 745: /*
746: * Lastly, as we've no scope open, try to look up and execute
747: * the new macro. If no macro is found, simply return and let
748: * the compilers handle it.
749: */
1.67 kristaps 750:
1.106 kristaps 751: if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos)))
1.79 kristaps 752: return(ROFF_CONT);
1.67 kristaps 753:
1.75 kristaps 754: assert(roffs[t].proc);
1.78 kristaps 755: return((*roffs[t].proc)
1.90 kristaps 756: (r, t, bufp, szp,
757: ln, ppos, pos, offs));
1.74 kristaps 758: }
759:
760:
1.117 kristaps 761: void
1.74 kristaps 762: roff_endparse(struct roff *r)
763: {
764:
1.110 kristaps 765: if (r->last)
1.128 kristaps 766: mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
1.109 kristaps 767: r->last->line, r->last->col, NULL);
1.117 kristaps 768:
1.125 kristaps 769: if (r->eqn) {
1.128 kristaps 770: mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
1.148 kristaps 771: r->eqn->eqn.ln, r->eqn->eqn.pos, NULL);
1.151 kristaps 772: eqn_end(&r->eqn);
1.125 kristaps 773: }
774:
1.117 kristaps 775: if (r->tbl) {
1.128 kristaps 776: mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
1.117 kristaps 777: r->tbl->line, r->tbl->pos, NULL);
1.151 kristaps 778: tbl_end(&r->tbl);
1.117 kristaps 779: }
1.67 kristaps 780: }
781:
782: /*
783: * Parse a roff node's type from the input buffer. This must be in the
784: * form of ".foo xxx" in the usual way.
785: */
786: static enum rofft
1.106 kristaps 787: roff_parse(struct roff *r, const char *buf, int *pos)
1.67 kristaps 788: {
1.106 kristaps 789: const char *mac;
790: size_t maclen;
1.67 kristaps 791: enum rofft t;
792:
1.144 kristaps 793: if ('\0' == buf[*pos] || '"' == buf[*pos] ||
794: '\t' == buf[*pos] || ' ' == buf[*pos])
1.67 kristaps 795: return(ROFF_MAX);
796:
1.144 kristaps 797: /*
798: * We stop the macro parse at an escape, tab, space, or nil.
799: * However, `\}' is also a valid macro, so make sure we don't
800: * clobber it by seeing the `\' as the end of token.
801: */
802:
1.106 kristaps 803: mac = buf + *pos;
1.144 kristaps 804: maclen = strcspn(mac + 1, " \\\t\0") + 1;
1.67 kristaps 805:
1.106 kristaps 806: t = (r->current_string = roff_getstrn(r, mac, maclen))
1.155 kristaps 807: ? ROFF_USERDEF : roffhash_find(mac, maclen);
1.67 kristaps 808:
1.127 kristaps 809: *pos += (int)maclen;
1.130 kristaps 810:
1.67 kristaps 811: while (buf[*pos] && ' ' == buf[*pos])
812: (*pos)++;
813:
814: return(t);
815: }
816:
817: /* ARGSUSED */
818: static enum rofferr
1.76 kristaps 819: roff_cblock(ROFF_ARGS)
1.67 kristaps 820: {
821:
1.79 kristaps 822: /*
823: * A block-close `..' should only be invoked as a child of an
824: * ignore macro, otherwise raise a warning and just ignore it.
825: */
826:
1.76 kristaps 827: if (NULL == r->last) {
1.128 kristaps 828: mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1.76 kristaps 829: return(ROFF_IGN);
830: }
1.67 kristaps 831:
1.81 kristaps 832: switch (r->last->tok) {
833: case (ROFF_am):
834: /* FALLTHROUGH */
835: case (ROFF_ami):
836: /* FALLTHROUGH */
837: case (ROFF_am1):
838: /* FALLTHROUGH */
839: case (ROFF_de):
1.108 schwarze 840: /* ROFF_de1 is remapped to ROFF_de in roff_block(). */
1.81 kristaps 841: /* FALLTHROUGH */
842: case (ROFF_dei):
843: /* FALLTHROUGH */
844: case (ROFF_ig):
845: break;
846: default:
1.128 kristaps 847: mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1.67 kristaps 848: return(ROFF_IGN);
1.76 kristaps 849: }
1.67 kristaps 850:
1.76 kristaps 851: if ((*bufp)[pos])
1.128 kristaps 852: mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
1.71 kristaps 853:
854: roffnode_pop(r);
1.76 kristaps 855: roffnode_cleanscope(r);
856: return(ROFF_IGN);
1.71 kristaps 857:
1.67 kristaps 858: }
859:
860:
1.76 kristaps 861: static void
862: roffnode_cleanscope(struct roff *r)
1.67 kristaps 863: {
864:
1.76 kristaps 865: while (r->last) {
1.173 schwarze 866: if (--r->last->endspan != 0)
1.76 kristaps 867: break;
868: roffnode_pop(r);
869: }
1.67 kristaps 870: }
871:
872:
1.75 kristaps 873: /* ARGSUSED */
1.74 kristaps 874: static enum rofferr
1.75 kristaps 875: roff_ccond(ROFF_ARGS)
1.74 kristaps 876: {
877:
1.76 kristaps 878: if (NULL == r->last) {
1.128 kristaps 879: mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1.76 kristaps 880: return(ROFF_IGN);
881: }
882:
1.82 kristaps 883: switch (r->last->tok) {
884: case (ROFF_el):
885: /* FALLTHROUGH */
886: case (ROFF_ie):
887: /* FALLTHROUGH */
888: case (ROFF_if):
889: break;
890: default:
1.128 kristaps 891: mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1.75 kristaps 892: return(ROFF_IGN);
893: }
894:
1.76 kristaps 895: if (r->last->endspan > -1) {
1.128 kristaps 896: mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1.76 kristaps 897: return(ROFF_IGN);
898: }
899:
900: if ((*bufp)[pos])
1.128 kristaps 901: mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
1.76 kristaps 902:
1.75 kristaps 903: roffnode_pop(r);
1.76 kristaps 904: roffnode_cleanscope(r);
905: return(ROFF_IGN);
906: }
907:
1.75 kristaps 908:
1.76 kristaps 909: /* ARGSUSED */
910: static enum rofferr
1.80 kristaps 911: roff_block(ROFF_ARGS)
1.76 kristaps 912: {
1.78 kristaps 913: int sv;
914: size_t sz;
1.106 kristaps 915: char *name;
916:
917: name = NULL;
1.76 kristaps 918:
1.106 kristaps 919: if (ROFF_ig != tok) {
920: if ('\0' == (*bufp)[pos]) {
1.128 kristaps 921: mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
1.106 kristaps 922: return(ROFF_IGN);
923: }
1.107 kristaps 924:
925: /*
926: * Re-write `de1', since we don't really care about
927: * groff's strange compatibility mode, into `de'.
928: */
929:
1.106 kristaps 930: if (ROFF_de1 == tok)
931: tok = ROFF_de;
932: if (ROFF_de == tok)
933: name = *bufp + pos;
934: else
1.128 kristaps 935: mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos,
1.106 kristaps 936: roffs[tok].name);
1.107 kristaps 937:
1.131 schwarze 938: while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos]))
1.80 kristaps 939: pos++;
1.107 kristaps 940:
1.131 schwarze 941: while (isspace((unsigned char)(*bufp)[pos]))
1.106 kristaps 942: (*bufp)[pos++] = '\0';
1.80 kristaps 943: }
944:
1.106 kristaps 945: roffnode_push(r, tok, name, ln, ppos);
946:
947: /*
948: * At the beginning of a `de' macro, clear the existing string
949: * with the same name, if there is one. New content will be
950: * added from roff_block_text() in multiline mode.
951: */
1.107 kristaps 952:
1.106 kristaps 953: if (ROFF_de == tok)
1.108 schwarze 954: roff_setstr(r, name, "", 0);
1.76 kristaps 955:
1.79 kristaps 956: if ('\0' == (*bufp)[pos])
1.78 kristaps 957: return(ROFF_IGN);
958:
1.107 kristaps 959: /* If present, process the custom end-of-line marker. */
960:
1.78 kristaps 961: sv = pos;
1.131 schwarze 962: while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos]))
1.78 kristaps 963: pos++;
964:
965: /*
966: * Note: groff does NOT like escape characters in the input.
967: * Instead of detecting this, we're just going to let it fly and
968: * to hell with it.
969: */
970:
971: assert(pos > sv);
972: sz = (size_t)(pos - sv);
973:
1.79 kristaps 974: if (1 == sz && '.' == (*bufp)[sv])
975: return(ROFF_IGN);
976:
1.98 schwarze 977: r->last->end = mandoc_malloc(sz + 1);
1.78 kristaps 978:
979: memcpy(r->last->end, *bufp + sv, sz);
980: r->last->end[(int)sz] = '\0';
981:
1.77 kristaps 982: if ((*bufp)[pos])
1.128 kristaps 983: mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
1.74 kristaps 984:
1.78 kristaps 985: return(ROFF_IGN);
986: }
987:
988:
989: /* ARGSUSED */
990: static enum rofferr
1.80 kristaps 991: roff_block_sub(ROFF_ARGS)
1.79 kristaps 992: {
993: enum rofft t;
994: int i, j;
995:
996: /*
997: * First check whether a custom macro exists at this level. If
998: * it does, then check against it. This is some of groff's
999: * stranger behaviours. If we encountered a custom end-scope
1000: * tag and that tag also happens to be a "real" macro, then we
1001: * need to try interpreting it again as a real macro. If it's
1002: * not, then return ignore. Else continue.
1003: */
1004:
1005: if (r->last->end) {
1.130 kristaps 1006: for (i = pos, j = 0; r->last->end[j]; j++, i++)
1.79 kristaps 1007: if ((*bufp)[i] != r->last->end[j])
1008: break;
1009:
1010: if ('\0' == r->last->end[j] &&
1011: ('\0' == (*bufp)[i] ||
1012: ' ' == (*bufp)[i] ||
1013: '\t' == (*bufp)[i])) {
1014: roffnode_pop(r);
1015: roffnode_cleanscope(r);
1016:
1.130 kristaps 1017: while (' ' == (*bufp)[i] || '\t' == (*bufp)[i])
1018: i++;
1019:
1020: pos = i;
1.106 kristaps 1021: if (ROFF_MAX != roff_parse(r, *bufp, &pos))
1.79 kristaps 1022: return(ROFF_RERUN);
1023: return(ROFF_IGN);
1024: }
1025: }
1026:
1027: /*
1028: * If we have no custom end-query or lookup failed, then try
1029: * pulling it out of the hashtable.
1030: */
1031:
1.137 schwarze 1032: t = roff_parse(r, *bufp, &pos);
1.79 kristaps 1033:
1.106 kristaps 1034: /*
1035: * Macros other than block-end are only significant
1036: * in `de' blocks; elsewhere, simply throw them away.
1037: */
1038: if (ROFF_cblock != t) {
1039: if (ROFF_de == tok)
1040: roff_setstr(r, r->last->name, *bufp + ppos, 1);
1.79 kristaps 1041: return(ROFF_IGN);
1.106 kristaps 1042: }
1.79 kristaps 1043:
1044: assert(roffs[t].proc);
1.90 kristaps 1045: return((*roffs[t].proc)(r, t, bufp, szp,
1046: ln, ppos, pos, offs));
1.79 kristaps 1047: }
1048:
1049:
1050: /* ARGSUSED */
1051: static enum rofferr
1.80 kristaps 1052: roff_block_text(ROFF_ARGS)
1.78 kristaps 1053: {
1054:
1.106 kristaps 1055: if (ROFF_de == tok)
1056: roff_setstr(r, r->last->name, *bufp + pos, 1);
1057:
1.78 kristaps 1058: return(ROFF_IGN);
1059: }
1060:
1061:
1062: /* ARGSUSED */
1063: static enum rofferr
1.82 kristaps 1064: roff_cond_sub(ROFF_ARGS)
1065: {
1066: enum rofft t;
1067: enum roffrule rr;
1.139 kristaps 1068: char *ep;
1.82 kristaps 1069:
1070: rr = r->last->rule;
1.139 kristaps 1071: roffnode_cleanscope(r);
1.177 schwarze 1072: t = roff_parse(r, *bufp, &pos);
1.82 kristaps 1073:
1.139 kristaps 1074: /*
1.177 schwarze 1075: * Fully handle known macros when they are structurally
1076: * required or when the conditional evaluated to true.
1.87 kristaps 1077: */
1078:
1.177 schwarze 1079: if ((ROFF_MAX != t) &&
1080: (ROFF_ccond == t || ROFFRULE_ALLOW == rr ||
1081: ROFFMAC_STRUCT & roffs[t].flags)) {
1082: assert(roffs[t].proc);
1083: return((*roffs[t].proc)(r, t, bufp, szp,
1084: ln, ppos, pos, offs));
1085: }
1.144 kristaps 1086:
1.177 schwarze 1087: /* Always check for the closing delimiter `\}'. */
1.144 kristaps 1088:
1.177 schwarze 1089: ep = &(*bufp)[pos];
1090: while (NULL != (ep = strchr(ep, '\\'))) {
1091: if ('}' != *(++ep))
1092: continue;
1.82 kristaps 1093:
1.177 schwarze 1094: /*
1095: * If we're at the end of line, then just chop
1096: * off the \} and resize the buffer.
1097: * If we aren't, then convert it to spaces.
1098: */
1.139 kristaps 1099:
1.177 schwarze 1100: if ('\0' == *(ep + 1)) {
1101: *--ep = '\0';
1102: *szp -= 2;
1103: } else
1104: *(ep - 1) = *ep = ' ';
1.82 kristaps 1105:
1.177 schwarze 1106: roff_ccond(r, ROFF_ccond, bufp, szp,
1107: ln, pos, pos + 2, offs);
1108: break;
1109: }
1110: return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
1.82 kristaps 1111: }
1112:
1113: /* ARGSUSED */
1114: static enum rofferr
1115: roff_cond_text(ROFF_ARGS)
1.78 kristaps 1116: {
1.140 kristaps 1117: char *ep;
1.82 kristaps 1118: enum roffrule rr;
1119:
1120: rr = r->last->rule;
1.140 kristaps 1121: roffnode_cleanscope(r);
1.82 kristaps 1122:
1.140 kristaps 1123: ep = &(*bufp)[pos];
1124: for ( ; NULL != (ep = strchr(ep, '\\')); ep++) {
1125: ep++;
1126: if ('}' != *ep)
1127: continue;
1128: *ep = '&';
1129: roff_ccond(r, ROFF_ccond, bufp, szp,
1130: ln, pos, pos + 2, offs);
1.78 kristaps 1131: }
1.82 kristaps 1132: return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
1.74 kristaps 1133: }
1134:
1.184 schwarze 1135: static int
1136: roff_getnum(const char *v, int *pos, int *res)
1137: {
1138: int p, n;
1139:
1140: p = *pos;
1141: n = v[p] == '-';
1142: if (n)
1143: p++;
1144:
1145: for (*res = 0; isdigit((unsigned char)v[p]); p++)
1146: *res += 10 * *res + v[p] - '0';
1147: if (p == *pos + n)
1148: return 0;
1149:
1150: if (n)
1151: *res = -*res;
1152:
1153: *pos = p;
1154: return 1;
1155: }
1156:
1157: static int
1158: roff_getop(const char *v, int *pos, char *res)
1159: {
1160: int e;
1161:
1162: *res = v[*pos];
1163: e = v[*pos + 1] == '=';
1164:
1165: switch (*res) {
1166: case '=':
1167: break;
1168: case '>':
1169: if (e)
1170: *res = 'g';
1171: break;
1172: case '<':
1173: if (e)
1174: *res = 'l';
1175: break;
1176: default:
1177: return(0);
1178: }
1179:
1180: *pos += 1 + e;
1181:
1182: return(*res);
1183: }
1184:
1.88 kristaps 1185: static enum roffrule
1186: roff_evalcond(const char *v, int *pos)
1187: {
1.184 schwarze 1188: int not, lh, rh;
1189: char op;
1.88 kristaps 1190:
1191: switch (v[*pos]) {
1192: case ('n'):
1193: (*pos)++;
1194: return(ROFFRULE_ALLOW);
1195: case ('e'):
1196: /* FALLTHROUGH */
1197: case ('o'):
1198: /* FALLTHROUGH */
1199: case ('t'):
1200: (*pos)++;
1201: return(ROFFRULE_DENY);
1.184 schwarze 1202: case ('!'):
1203: (*pos)++;
1204: not = 1;
1205: break;
1.88 kristaps 1206: default:
1.184 schwarze 1207: not = 0;
1.88 kristaps 1208: break;
1209: }
1210:
1.184 schwarze 1211: if (!roff_getnum(v, pos, &lh))
1212: return ROFFRULE_DENY;
1213: if (!roff_getop(v, pos, &op)) {
1214: if (lh < 0)
1215: lh = 0;
1216: goto out;
1217: }
1218: if (!roff_getnum(v, pos, &rh))
1219: return ROFFRULE_DENY;
1220: switch (op) {
1221: case 'g':
1222: lh = lh >= rh;
1223: break;
1224: case 'l':
1225: lh = lh <= rh;
1226: break;
1227: case '=':
1228: lh = lh == rh;
1229: break;
1230: case '>':
1231: lh = lh > rh;
1232: break;
1233: case '<':
1234: lh = lh < rh;
1235: break;
1236: default:
1237: return ROFFRULE_DENY;
1238: }
1239: out:
1240: if (not)
1241: lh = !lh;
1242: return lh ? ROFFRULE_ALLOW : ROFFRULE_DENY;
1.88 kristaps 1243: }
1244:
1.75 kristaps 1245: /* ARGSUSED */
1.74 kristaps 1246: static enum rofferr
1.103 kristaps 1247: roff_line_ignore(ROFF_ARGS)
1.89 kristaps 1248: {
1.123 schwarze 1249:
1.89 kristaps 1250: return(ROFF_IGN);
1251: }
1252:
1.104 kristaps 1253: /* ARGSUSED */
1254: static enum rofferr
1.82 kristaps 1255: roff_cond(ROFF_ARGS)
1.74 kristaps 1256: {
1.173 schwarze 1257:
1258: roffnode_push(r, tok, NULL, ln, ppos);
1.74 kristaps 1259:
1.134 kristaps 1260: /*
1261: * An `.el' has no conditional body: it will consume the value
1262: * of the current rstack entry set in prior `ie' calls or
1263: * defaults to DENY.
1264: *
1265: * If we're not an `el', however, then evaluate the conditional.
1266: */
1.133 kristaps 1267:
1.173 schwarze 1268: r->last->rule = ROFF_el == tok ?
1.134 kristaps 1269: (r->rstackpos < 0 ?
1270: ROFFRULE_DENY : r->rstack[r->rstackpos--]) :
1271: roff_evalcond(*bufp, &pos);
1.77 kristaps 1272:
1.134 kristaps 1273: /*
1274: * An if-else will put the NEGATION of the current evaluated
1275: * conditional into the stack of rules.
1276: */
1277:
1.84 schwarze 1278: if (ROFF_ie == tok) {
1.134 kristaps 1279: if (r->rstackpos == RSTACK_MAX - 1) {
1280: mandoc_msg(MANDOCERR_MEM,
1281: r->parse, ln, ppos, NULL);
1282: return(ROFF_ERR);
1283: }
1284: r->rstack[++r->rstackpos] =
1285: ROFFRULE_DENY == r->last->rule ?
1286: ROFFRULE_ALLOW : ROFFRULE_DENY;
1.82 kristaps 1287: }
1.88 kristaps 1288:
1289: /* If the parent has false as its rule, then so do we. */
1290:
1.109 kristaps 1291: if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule)
1.84 schwarze 1292: r->last->rule = ROFFRULE_DENY;
1.88 kristaps 1293:
1294: /*
1.173 schwarze 1295: * Determine scope.
1296: * If there is nothing on the line after the conditional,
1297: * not even whitespace, use next-line scope.
1.88 kristaps 1298: */
1.74 kristaps 1299:
1.173 schwarze 1300: if ('\0' == (*bufp)[pos]) {
1301: r->last->endspan = 2;
1302: goto out;
1303: }
1304:
1305: while (' ' == (*bufp)[pos])
1306: pos++;
1307:
1308: /* An opening brace requests multiline scope. */
1.75 kristaps 1309:
1310: if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) {
1311: r->last->endspan = -1;
1312: pos += 2;
1.173 schwarze 1313: goto out;
1.109 kristaps 1314: }
1.74 kristaps 1315:
1.77 kristaps 1316: /*
1.173 schwarze 1317: * Anything else following the conditional causes
1318: * single-line scope. Warn if the scope contains
1319: * nothing but trailing whitespace.
1.77 kristaps 1320: */
1321:
1.75 kristaps 1322: if ('\0' == (*bufp)[pos])
1.173 schwarze 1323: mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
1.77 kristaps 1324:
1.173 schwarze 1325: r->last->endspan = 1;
1.74 kristaps 1326:
1.173 schwarze 1327: out:
1.75 kristaps 1328: *offs = pos;
1329: return(ROFF_RERUN);
1.83 schwarze 1330: }
1331:
1332:
1333: /* ARGSUSED */
1334: static enum rofferr
1.92 schwarze 1335: roff_ds(ROFF_ARGS)
1336: {
1.96 kristaps 1337: char *name, *string;
1338:
1339: /*
1340: * A symbol is named by the first word following the macro
1341: * invocation up to a space. Its value is anything after the
1342: * name's trailing whitespace and optional double-quote. Thus,
1343: *
1344: * [.ds foo "bar " ]
1345: *
1346: * will have `bar " ' as its value.
1347: */
1.92 schwarze 1348:
1.121 schwarze 1349: string = *bufp + pos;
1350: name = roff_getname(r, &string, ln, pos);
1.92 schwarze 1351: if ('\0' == *name)
1352: return(ROFF_IGN);
1353:
1.121 schwarze 1354: /* Read past initial double-quote. */
1355: if ('"' == *string)
1.92 schwarze 1356: string++;
1357:
1.96 kristaps 1358: /* The rest is the value. */
1.106 kristaps 1359: roff_setstr(r, name, string, 0);
1.92 schwarze 1360: return(ROFF_IGN);
1361: }
1362:
1.180 schwarze 1363: void
1.187 schwarze 1364: roff_setreg(struct roff *r, const char *name, int val, char sign)
1.147 kristaps 1365: {
1.180 schwarze 1366: struct roffreg *reg;
1367:
1368: /* Search for an existing register with the same name. */
1369: reg = r->regtab;
1370:
1371: while (reg && strcmp(name, reg->key.p))
1372: reg = reg->next;
1.147 kristaps 1373:
1.180 schwarze 1374: if (NULL == reg) {
1375: /* Create a new register. */
1376: reg = mandoc_malloc(sizeof(struct roffreg));
1377: reg->key.p = mandoc_strdup(name);
1378: reg->key.sz = strlen(name);
1.187 schwarze 1379: reg->val = 0;
1.180 schwarze 1380: reg->next = r->regtab;
1381: r->regtab = reg;
1382: }
1383:
1.187 schwarze 1384: if ('+' == sign)
1385: reg->val += val;
1386: else if ('-' == sign)
1387: reg->val -= val;
1388: else
1389: reg->val = val;
1.147 kristaps 1390: }
1391:
1.181 schwarze 1392: int
1.180 schwarze 1393: roff_getreg(const struct roff *r, const char *name)
1.147 kristaps 1394: {
1.180 schwarze 1395: struct roffreg *reg;
1396:
1397: for (reg = r->regtab; reg; reg = reg->next)
1398: if (0 == strcmp(name, reg->key.p))
1.181 schwarze 1399: return(reg->val);
1400:
1401: return(0);
1402: }
1403:
1404: static int
1405: roff_getregn(const struct roff *r, const char *name, size_t len)
1406: {
1407: struct roffreg *reg;
1408:
1409: for (reg = r->regtab; reg; reg = reg->next)
1410: if (len == reg->key.sz &&
1411: 0 == strncmp(name, reg->key.p, len))
1412: return(reg->val);
1.147 kristaps 1413:
1.180 schwarze 1414: return(0);
1.147 kristaps 1415: }
1416:
1.180 schwarze 1417: static void
1418: roff_freereg(struct roffreg *reg)
1.147 kristaps 1419: {
1.180 schwarze 1420: struct roffreg *old_reg;
1.147 kristaps 1421:
1.180 schwarze 1422: while (NULL != reg) {
1423: free(reg->key.p);
1424: old_reg = reg;
1425: reg = reg->next;
1426: free(old_reg);
1427: }
1.147 kristaps 1428: }
1.92 schwarze 1429:
1430: /* ARGSUSED */
1431: static enum rofferr
1.89 kristaps 1432: roff_nr(ROFF_ARGS)
1.83 schwarze 1433: {
1.121 schwarze 1434: const char *key;
1435: char *val;
1.187 schwarze 1436: size_t sz;
1.138 kristaps 1437: int iv;
1.187 schwarze 1438: char sign;
1.89 kristaps 1439:
1.121 schwarze 1440: val = *bufp + pos;
1441: key = roff_getname(r, &val, ln, pos);
1.89 kristaps 1442:
1.187 schwarze 1443: sign = *val;
1444: if ('+' == sign || '-' == sign)
1445: val++;
1446:
1447: sz = strspn(val, "0123456789");
1448: iv = sz ? mandoc_strntoi(val, sz, 10) : 0;
1.180 schwarze 1449:
1.187 schwarze 1450: roff_setreg(r, key, iv, sign);
1.109 kristaps 1451:
1.122 schwarze 1452: return(ROFF_IGN);
1453: }
1454:
1455: /* ARGSUSED */
1456: static enum rofferr
1457: roff_rm(ROFF_ARGS)
1458: {
1459: const char *name;
1460: char *cp;
1461:
1462: cp = *bufp + pos;
1463: while ('\0' != *cp) {
1.127 kristaps 1464: name = roff_getname(r, &cp, ln, (int)(cp - *bufp));
1.122 schwarze 1465: if ('\0' != *name)
1466: roff_setstr(r, name, NULL, 0);
1467: }
1.178 schwarze 1468: return(ROFF_IGN);
1469: }
1470:
1471: /* ARGSUSED */
1472: static enum rofferr
1473: roff_it(ROFF_ARGS)
1474: {
1475: char *cp;
1476: size_t len;
1477: int iv;
1478:
1479: /* Parse the number of lines. */
1480: cp = *bufp + pos;
1481: len = strcspn(cp, " \t");
1482: cp[len] = '\0';
1483: if ((iv = mandoc_strntoi(cp, len, 10)) <= 0) {
1484: mandoc_msg(MANDOCERR_NUMERIC, r->parse,
1485: ln, ppos, *bufp + 1);
1486: return(ROFF_IGN);
1487: }
1488: cp += len + 1;
1489:
1490: /* Arm the input line trap. */
1491: roffit_lines = iv;
1492: roffit_macro = mandoc_strdup(cp);
1.109 kristaps 1493: return(ROFF_IGN);
1.175 schwarze 1494: }
1495:
1496: /* ARGSUSED */
1497: static enum rofferr
1498: roff_Dd(ROFF_ARGS)
1499: {
1500: const char *const *cp;
1501:
1.190 ! schwarze 1502: if (0 == r->quick && MPARSE_MDOC != r->parsetype)
1.175 schwarze 1503: for (cp = __mdoc_reserved; *cp; cp++)
1504: roff_setstr(r, *cp, NULL, 0);
1505:
1506: return(ROFF_CONT);
1507: }
1508:
1509: /* ARGSUSED */
1510: static enum rofferr
1511: roff_TH(ROFF_ARGS)
1512: {
1513: const char *const *cp;
1514:
1.190 ! schwarze 1515: if (0 == r->quick && MPARSE_MDOC != r->parsetype)
1.175 schwarze 1516: for (cp = __man_reserved; *cp; cp++)
1517: roff_setstr(r, *cp, NULL, 0);
1518:
1519: return(ROFF_CONT);
1.109 kristaps 1520: }
1521:
1522: /* ARGSUSED */
1523: static enum rofferr
1524: roff_TE(ROFF_ARGS)
1525: {
1526:
1527: if (NULL == r->tbl)
1.128 kristaps 1528: mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1.115 kristaps 1529: else
1.151 kristaps 1530: tbl_end(&r->tbl);
1.109 kristaps 1531:
1.112 kristaps 1532: return(ROFF_IGN);
1533: }
1534:
1535: /* ARGSUSED */
1536: static enum rofferr
1537: roff_T_(ROFF_ARGS)
1538: {
1539:
1540: if (NULL == r->tbl)
1.128 kristaps 1541: mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1.112 kristaps 1542: else
1.116 kristaps 1543: tbl_restart(ppos, ln, r->tbl);
1.112 kristaps 1544:
1.109 kristaps 1545: return(ROFF_IGN);
1546: }
1547:
1.156 kristaps 1548: #if 0
1549: static int
1.151 kristaps 1550: roff_closeeqn(struct roff *r)
1551: {
1552:
1553: return(r->eqn && ROFF_EQN == eqn_end(&r->eqn) ? 1 : 0);
1554: }
1.156 kristaps 1555: #endif
1.151 kristaps 1556:
1.156 kristaps 1557: static void
1.151 kristaps 1558: roff_openeqn(struct roff *r, const char *name, int line,
1559: int offs, const char *buf)
1.125 kristaps 1560: {
1.151 kristaps 1561: struct eqn_node *e;
1562: int poff;
1.125 kristaps 1563:
1564: assert(NULL == r->eqn);
1.151 kristaps 1565: e = eqn_alloc(name, offs, line, r->parse);
1.125 kristaps 1566:
1567: if (r->last_eqn)
1568: r->last_eqn->next = e;
1569: else
1570: r->first_eqn = r->last_eqn = e;
1571:
1572: r->eqn = r->last_eqn = e;
1.151 kristaps 1573:
1574: if (buf) {
1575: poff = 0;
1576: eqn_read(&r->eqn, line, buf, offs, &poff);
1577: }
1578: }
1579:
1580: /* ARGSUSED */
1581: static enum rofferr
1582: roff_EQ(ROFF_ARGS)
1583: {
1584:
1585: roff_openeqn(r, *bufp + pos, ln, ppos, NULL);
1.125 kristaps 1586: return(ROFF_IGN);
1587: }
1588:
1589: /* ARGSUSED */
1590: static enum rofferr
1591: roff_EN(ROFF_ARGS)
1592: {
1593:
1.128 kristaps 1594: mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
1.125 kristaps 1595: return(ROFF_IGN);
1596: }
1597:
1598: /* ARGSUSED */
1599: static enum rofferr
1.109 kristaps 1600: roff_TS(ROFF_ARGS)
1601: {
1.176 schwarze 1602: struct tbl_node *tbl;
1.89 kristaps 1603:
1.115 kristaps 1604: if (r->tbl) {
1.128 kristaps 1605: mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL);
1.151 kristaps 1606: tbl_end(&r->tbl);
1.115 kristaps 1607: }
1.83 schwarze 1608:
1.176 schwarze 1609: tbl = tbl_alloc(ppos, ln, r->parse);
1.113 kristaps 1610:
1611: if (r->last_tbl)
1.176 schwarze 1612: r->last_tbl->next = tbl;
1.113 kristaps 1613: else
1.176 schwarze 1614: r->first_tbl = r->last_tbl = tbl;
1.113 kristaps 1615:
1.176 schwarze 1616: r->tbl = r->last_tbl = tbl;
1.83 schwarze 1617: return(ROFF_IGN);
1.92 schwarze 1618: }
1619:
1.105 kristaps 1620: /* ARGSUSED */
1621: static enum rofferr
1.174 kristaps 1622: roff_cc(ROFF_ARGS)
1623: {
1624: const char *p;
1625:
1626: p = *bufp + pos;
1627:
1628: if ('\0' == *p || '.' == (r->control = *p++))
1629: r->control = 0;
1630:
1631: if ('\0' != *p)
1632: mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
1633:
1634: return(ROFF_IGN);
1635: }
1636:
1637: /* ARGSUSED */
1638: static enum rofferr
1.164 kristaps 1639: roff_tr(ROFF_ARGS)
1640: {
1641: const char *p, *first, *second;
1642: size_t fsz, ssz;
1643: enum mandoc_esc esc;
1644:
1645: p = *bufp + pos;
1646:
1647: if ('\0' == *p) {
1648: mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
1649: return(ROFF_IGN);
1650: }
1651:
1652: while ('\0' != *p) {
1653: fsz = ssz = 1;
1654:
1655: first = p++;
1656: if ('\\' == *first) {
1657: esc = mandoc_escape(&p, NULL, NULL);
1658: if (ESCAPE_ERROR == esc) {
1659: mandoc_msg
1660: (MANDOCERR_BADESCAPE, r->parse,
1661: ln, (int)(p - *bufp), NULL);
1662: return(ROFF_IGN);
1663: }
1664: fsz = (size_t)(p - first);
1665: }
1666:
1667: second = p++;
1668: if ('\\' == *second) {
1669: esc = mandoc_escape(&p, NULL, NULL);
1670: if (ESCAPE_ERROR == esc) {
1671: mandoc_msg
1672: (MANDOCERR_BADESCAPE, r->parse,
1673: ln, (int)(p - *bufp), NULL);
1674: return(ROFF_IGN);
1675: }
1676: ssz = (size_t)(p - second);
1.165 kristaps 1677: } else if ('\0' == *second) {
1.164 kristaps 1678: mandoc_msg(MANDOCERR_ARGCOUNT, r->parse,
1679: ln, (int)(p - *bufp), NULL);
1680: second = " ";
1.165 kristaps 1681: p--;
1.164 kristaps 1682: }
1683:
1.167 kristaps 1684: if (fsz > 1) {
1685: roff_setstrn(&r->xmbtab, first,
1686: fsz, second, ssz, 0);
1687: continue;
1688: }
1689:
1690: if (NULL == r->xtab)
1691: r->xtab = mandoc_calloc
1692: (128, sizeof(struct roffstr));
1693:
1694: free(r->xtab[(int)*first].p);
1695: r->xtab[(int)*first].p = mandoc_strndup(second, ssz);
1696: r->xtab[(int)*first].sz = ssz;
1.164 kristaps 1697: }
1698:
1699: return(ROFF_IGN);
1700: }
1701:
1702: /* ARGSUSED */
1703: static enum rofferr
1.105 kristaps 1704: roff_so(ROFF_ARGS)
1705: {
1706: char *name;
1707:
1.128 kristaps 1708: mandoc_msg(MANDOCERR_SO, r->parse, ln, ppos, NULL);
1.105 kristaps 1709:
1710: /*
1711: * Handle `so'. Be EXTREMELY careful, as we shouldn't be
1712: * opening anything that's not in our cwd or anything beneath
1713: * it. Thus, explicitly disallow traversing up the file-system
1714: * or using absolute paths.
1715: */
1716:
1717: name = *bufp + pos;
1718: if ('/' == *name || strstr(name, "../") || strstr(name, "/..")) {
1.128 kristaps 1719: mandoc_msg(MANDOCERR_SOPATH, r->parse, ln, pos, NULL);
1.105 kristaps 1720: return(ROFF_ERR);
1721: }
1722:
1723: *offs = pos;
1724: return(ROFF_SO);
1725: }
1.92 schwarze 1726:
1.106 kristaps 1727: /* ARGSUSED */
1728: static enum rofferr
1729: roff_userdef(ROFF_ARGS)
1.99 kristaps 1730: {
1.106 kristaps 1731: const char *arg[9];
1732: char *cp, *n1, *n2;
1.119 schwarze 1733: int i;
1.106 kristaps 1734:
1735: /*
1736: * Collect pointers to macro argument strings
1.188 schwarze 1737: * and NUL-terminate them.
1.106 kristaps 1738: */
1739: cp = *bufp + pos;
1.119 schwarze 1740: for (i = 0; i < 9; i++)
1.120 schwarze 1741: arg[i] = '\0' == *cp ? "" :
1.136 kristaps 1742: mandoc_getarg(r->parse, &cp, ln, &pos);
1.99 kristaps 1743:
1.106 kristaps 1744: /*
1745: * Expand macro arguments.
1.99 kristaps 1746: */
1.106 kristaps 1747: *szp = 0;
1748: n1 = cp = mandoc_strdup(r->current_string);
1749: while (NULL != (cp = strstr(cp, "\\$"))) {
1750: i = cp[2] - '1';
1751: if (0 > i || 8 < i) {
1752: /* Not an argument invocation. */
1753: cp += 2;
1754: continue;
1755: }
1756:
1757: *szp = strlen(n1) - 3 + strlen(arg[i]) + 1;
1758: n2 = mandoc_malloc(*szp);
1759:
1760: strlcpy(n2, n1, (size_t)(cp - n1 + 1));
1761: strlcat(n2, arg[i], *szp);
1762: strlcat(n2, cp + 3, *szp);
1763:
1764: cp = n2 + (cp - n1);
1765: free(n1);
1766: n1 = n2;
1.99 kristaps 1767: }
1768:
1.106 kristaps 1769: /*
1770: * Replace the macro invocation
1771: * by the expanded macro.
1772: */
1773: free(*bufp);
1774: *bufp = n1;
1775: if (0 == *szp)
1776: *szp = strlen(*bufp) + 1;
1777:
1778: return(*szp > 1 && '\n' == (*bufp)[(int)*szp - 2] ?
1779: ROFF_REPARSE : ROFF_APPEND);
1.99 kristaps 1780: }
1.121 schwarze 1781:
1782: static char *
1783: roff_getname(struct roff *r, char **cpp, int ln, int pos)
1784: {
1785: char *name, *cp;
1786:
1787: name = *cpp;
1788: if ('\0' == *name)
1789: return(name);
1790:
1791: /* Read until end of name. */
1792: for (cp = name; '\0' != *cp && ' ' != *cp; cp++) {
1793: if ('\\' != *cp)
1794: continue;
1795: cp++;
1796: if ('\\' == *cp)
1797: continue;
1.128 kristaps 1798: mandoc_msg(MANDOCERR_NAMESC, r->parse, ln, pos, NULL);
1.121 schwarze 1799: *cp = '\0';
1800: name = cp;
1801: }
1802:
1803: /* Nil-terminate name. */
1804: if ('\0' != *cp)
1805: *(cp++) = '\0';
1806:
1807: /* Read past spaces. */
1808: while (' ' == *cp)
1809: cp++;
1810:
1811: *cpp = cp;
1812: return(name);
1813: }
1814:
1.106 kristaps 1815: /*
1816: * Store *string into the user-defined string called *name.
1817: * In multiline mode, append to an existing entry and append '\n';
1818: * else replace the existing entry, if there is one.
1819: * To clear an existing entry, call with (*r, *name, NULL, 0).
1820: */
1.94 kristaps 1821: static void
1.106 kristaps 1822: roff_setstr(struct roff *r, const char *name, const char *string,
1823: int multiline)
1.92 schwarze 1824: {
1.164 kristaps 1825:
1826: roff_setstrn(&r->strtab, name, strlen(name), string,
1827: string ? strlen(string) : 0, multiline);
1828: }
1829:
1830: static void
1.166 kristaps 1831: roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
1.164 kristaps 1832: const char *string, size_t stringsz, int multiline)
1833: {
1.166 kristaps 1834: struct roffkv *n;
1.164 kristaps 1835: char *c;
1836: int i;
1837: size_t oldch, newch;
1.92 schwarze 1838:
1.106 kristaps 1839: /* Search for an existing string with the same name. */
1.164 kristaps 1840: n = *r;
1841:
1.166 kristaps 1842: while (n && strcmp(name, n->key.p))
1.92 schwarze 1843: n = n->next;
1.94 kristaps 1844:
1845: if (NULL == n) {
1.106 kristaps 1846: /* Create a new string table entry. */
1.166 kristaps 1847: n = mandoc_malloc(sizeof(struct roffkv));
1848: n->key.p = mandoc_strndup(name, namesz);
1849: n->key.sz = namesz;
1850: n->val.p = NULL;
1851: n->val.sz = 0;
1.164 kristaps 1852: n->next = *r;
1853: *r = n;
1.106 kristaps 1854: } else if (0 == multiline) {
1855: /* In multiline mode, append; else replace. */
1.166 kristaps 1856: free(n->val.p);
1857: n->val.p = NULL;
1858: n->val.sz = 0;
1.106 kristaps 1859: }
1860:
1861: if (NULL == string)
1862: return;
1863:
1864: /*
1865: * One additional byte for the '\n' in multiline mode,
1866: * and one for the terminating '\0'.
1867: */
1.164 kristaps 1868: newch = stringsz + (multiline ? 2u : 1u);
1869:
1.166 kristaps 1870: if (NULL == n->val.p) {
1871: n->val.p = mandoc_malloc(newch);
1872: *n->val.p = '\0';
1.106 kristaps 1873: oldch = 0;
1874: } else {
1.166 kristaps 1875: oldch = n->val.sz;
1876: n->val.p = mandoc_realloc(n->val.p, oldch + newch);
1.106 kristaps 1877: }
1878:
1879: /* Skip existing content in the destination buffer. */
1.166 kristaps 1880: c = n->val.p + (int)oldch;
1.106 kristaps 1881:
1882: /* Append new content to the destination buffer. */
1.164 kristaps 1883: i = 0;
1884: while (i < (int)stringsz) {
1.106 kristaps 1885: /*
1886: * Rudimentary roff copy mode:
1887: * Handle escaped backslashes.
1888: */
1.164 kristaps 1889: if ('\\' == string[i] && '\\' == string[i + 1])
1890: i++;
1891: *c++ = string[i++];
1.106 kristaps 1892: }
1.94 kristaps 1893:
1.106 kristaps 1894: /* Append terminating bytes. */
1895: if (multiline)
1896: *c++ = '\n';
1.163 kristaps 1897:
1.106 kristaps 1898: *c = '\0';
1.166 kristaps 1899: n->val.sz = (int)(c - n->val.p);
1.92 schwarze 1900: }
1901:
1.94 kristaps 1902: static const char *
1903: roff_getstrn(const struct roff *r, const char *name, size_t len)
1.92 schwarze 1904: {
1.166 kristaps 1905: const struct roffkv *n;
1.92 schwarze 1906:
1.164 kristaps 1907: for (n = r->strtab; n; n = n->next)
1.166 kristaps 1908: if (0 == strncmp(name, n->key.p, len) &&
1909: '\0' == n->key.p[(int)len])
1910: return(n->val.p);
1.94 kristaps 1911:
1.157 kristaps 1912: return(NULL);
1.92 schwarze 1913: }
1914:
1.94 kristaps 1915: static void
1.167 kristaps 1916: roff_freestr(struct roffkv *r)
1.92 schwarze 1917: {
1.166 kristaps 1918: struct roffkv *n, *nn;
1.92 schwarze 1919:
1.167 kristaps 1920: for (n = r; n; n = nn) {
1.166 kristaps 1921: free(n->key.p);
1922: free(n->val.p);
1.92 schwarze 1923: nn = n->next;
1924: free(n);
1925: }
1.114 kristaps 1926: }
1927:
1928: const struct tbl_span *
1929: roff_span(const struct roff *r)
1930: {
1931:
1932: return(r->tbl ? tbl_span(r->tbl) : NULL);
1.125 kristaps 1933: }
1934:
1935: const struct eqn *
1936: roff_eqn(const struct roff *r)
1937: {
1938:
1939: return(r->last_eqn ? &r->last_eqn->eqn : NULL);
1.164 kristaps 1940: }
1941:
1942: /*
1943: * Duplicate an input string, making the appropriate character
1944: * conversations (as stipulated by `tr') along the way.
1945: * Returns a heap-allocated string with all the replacements made.
1946: */
1947: char *
1948: roff_strdup(const struct roff *r, const char *p)
1949: {
1.166 kristaps 1950: const struct roffkv *cp;
1.164 kristaps 1951: char *res;
1952: const char *pp;
1953: size_t ssz, sz;
1954: enum mandoc_esc esc;
1955:
1.167 kristaps 1956: if (NULL == r->xmbtab && NULL == r->xtab)
1.164 kristaps 1957: return(mandoc_strdup(p));
1958: else if ('\0' == *p)
1959: return(mandoc_strdup(""));
1960:
1961: /*
1962: * Step through each character looking for term matches
1963: * (remember that a `tr' can be invoked with an escape, which is
1964: * a glyph but the escape is multi-character).
1965: * We only do this if the character hash has been initialised
1966: * and the string is >0 length.
1967: */
1968:
1969: res = NULL;
1970: ssz = 0;
1971:
1972: while ('\0' != *p) {
1.167 kristaps 1973: if ('\\' != *p && r->xtab && r->xtab[(int)*p].p) {
1974: sz = r->xtab[(int)*p].sz;
1975: res = mandoc_realloc(res, ssz + sz + 1);
1976: memcpy(res + ssz, r->xtab[(int)*p].p, sz);
1977: ssz += sz;
1978: p++;
1979: continue;
1980: } else if ('\\' != *p) {
1981: res = mandoc_realloc(res, ssz + 2);
1982: res[ssz++] = *p++;
1983: continue;
1984: }
1985:
1.164 kristaps 1986: /* Search for term matches. */
1.167 kristaps 1987: for (cp = r->xmbtab; cp; cp = cp->next)
1.166 kristaps 1988: if (0 == strncmp(p, cp->key.p, cp->key.sz))
1.164 kristaps 1989: break;
1990:
1991: if (NULL != cp) {
1992: /*
1993: * A match has been found.
1994: * Append the match to the array and move
1995: * forward by its keysize.
1996: */
1.166 kristaps 1997: res = mandoc_realloc
1998: (res, ssz + cp->val.sz + 1);
1999: memcpy(res + ssz, cp->val.p, cp->val.sz);
2000: ssz += cp->val.sz;
2001: p += (int)cp->key.sz;
1.164 kristaps 2002: continue;
2003: }
2004:
1.167 kristaps 2005: /*
2006: * Handle escapes carefully: we need to copy
2007: * over just the escape itself, or else we might
2008: * do replacements within the escape itself.
2009: * Make sure to pass along the bogus string.
2010: */
2011: pp = p++;
2012: esc = mandoc_escape(&p, NULL, NULL);
2013: if (ESCAPE_ERROR == esc) {
2014: sz = strlen(pp);
1.164 kristaps 2015: res = mandoc_realloc(res, ssz + sz + 1);
2016: memcpy(res + ssz, pp, sz);
1.167 kristaps 2017: break;
1.164 kristaps 2018: }
1.167 kristaps 2019: /*
2020: * We bail out on bad escapes.
2021: * No need to warn: we already did so when
2022: * roff_res() was called.
2023: */
2024: sz = (int)(p - pp);
2025: res = mandoc_realloc(res, ssz + sz + 1);
2026: memcpy(res + ssz, pp, sz);
2027: ssz += sz;
1.164 kristaps 2028: }
2029:
2030: res[(int)ssz] = '\0';
2031: return(res);
1.174 kristaps 2032: }
2033:
2034: /*
2035: * Find out whether a line is a macro line or not.
2036: * If it is, adjust the current position and return one; if it isn't,
2037: * return zero and don't change the current position.
2038: * If the control character has been set with `.cc', then let that grain
2039: * precedence.
2040: * This is slighly contrary to groff, where using the non-breaking
2041: * control character when `cc' has been invoked will cause the
2042: * non-breaking macro contents to be printed verbatim.
2043: */
2044: int
2045: roff_getcontrol(const struct roff *r, const char *cp, int *ppos)
2046: {
2047: int pos;
2048:
2049: pos = *ppos;
2050:
2051: if (0 != r->control && cp[pos] == r->control)
2052: pos++;
2053: else if (0 != r->control)
2054: return(0);
2055: else if ('\\' == cp[pos] && '.' == cp[pos + 1])
2056: pos += 2;
2057: else if ('.' == cp[pos] || '\'' == cp[pos])
2058: pos++;
2059: else
2060: return(0);
2061:
2062: while (' ' == cp[pos] || '\t' == cp[pos])
2063: pos++;
2064:
2065: *ppos = pos;
2066: return(1);
1.74 kristaps 2067: }
CVSweb