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