]> git.cameronkatri.com Git - mandoc.git/blob - macro.c
9c15e863c5854931c93f0b4ea6143a95da0d3c7b
[mandoc.git] / macro.c
1 /* $Id: macro.c,v 1.74 2009/03/21 09:20:15 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19 #include <assert.h>
20 #include <ctype.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24
25 #include "private.h"
26
27 /*
28 * This has scanning/parsing routines, each of which extract a macro and
29 * its arguments and parameters, then know how to progress to the next
30 * macro.
31 */
32
33 /* FIXME: .Fl, .Ar, .Cd handling of `|'. */
34
35 enum mwarn {
36 WMACPARM,
37 WOBS
38 };
39
40 enum merr {
41 EOPEN,
42 EQUOT,
43 ENOCTX,
44 ENOPARMS
45 };
46
47 #define REWIND_REWIND (1 << 0)
48 #define REWIND_NOHALT (1 << 1)
49 #define REWIND_HALT (1 << 2)
50
51 static int obsolete(MACRO_PROT_ARGS);
52 static int blk_part_exp(MACRO_PROT_ARGS);
53 static int in_line_eoln(MACRO_PROT_ARGS);
54 static int in_line_argn(MACRO_PROT_ARGS);
55 static int in_line(MACRO_PROT_ARGS);
56 static int blk_full(MACRO_PROT_ARGS);
57 static int blk_exp_close(MACRO_PROT_ARGS);
58 static int blk_part_imp(MACRO_PROT_ARGS);
59
60 static int phrase(struct mdoc *, int, int, char *);
61 static int rew_dohalt(int, enum mdoc_type,
62 const struct mdoc_node *);
63 static int rew_alt(int);
64 static int rew_dobreak(int, const struct mdoc_node *);
65 static int rew_elem(struct mdoc *, int);
66 static int rew_impblock(struct mdoc *, int, int, int);
67 static int rew_expblock(struct mdoc *, int, int, int);
68 static int rew_subblock(enum mdoc_type,
69 struct mdoc *, int, int, int);
70 static int rew_last(struct mdoc *, struct mdoc_node *);
71 static int append_delims(struct mdoc *, int, int *, char *);
72 static int lookup(struct mdoc *, int, int, int, const char *);
73 static int pwarn(struct mdoc *, int, int, enum mwarn);
74 static int perr(struct mdoc *, int, int, enum merr);
75 static int swarn(struct mdoc *, enum mdoc_type, int, int,
76 const struct mdoc_node *);
77
78 #define nerr(m, n, t) perr((m), (n)->line, (n)->pos, (t))
79
80 /* Central table of library: who gets parsed how. */
81
82 const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
83 { NULL, 0 }, /* \" */
84 { in_line_eoln, MDOC_PROLOGUE }, /* Dd */
85 { in_line_eoln, MDOC_PROLOGUE }, /* Dt */
86 { in_line_eoln, MDOC_PROLOGUE }, /* Os */
87 { blk_full, 0 }, /* Sh */
88 { blk_full, 0 }, /* Ss */
89 { in_line, 0 }, /* Pp */
90 { blk_part_imp, MDOC_PARSED }, /* D1 */
91 { blk_part_imp, MDOC_PARSED }, /* Dl */
92 { blk_full, MDOC_EXPLICIT }, /* Bd */
93 { blk_exp_close, MDOC_EXPLICIT }, /* Ed */
94 { blk_full, MDOC_EXPLICIT }, /* Bl */
95 { blk_exp_close, MDOC_EXPLICIT }, /* El */
96 { blk_full, MDOC_PARSED }, /* It */
97 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
98 { in_line, MDOC_PARSED }, /* An */
99 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */
100 { in_line_eoln, MDOC_CALLABLE }, /* Cd */
101 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */
102 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */
103 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */
104 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */
105 { in_line_eoln, 0 }, /* Ex */
106 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */
107 { in_line_eoln, 0 }, /* Fd */
108 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */
109 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */
110 { in_line, MDOC_PARSED }, /* Ft */
111 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */
112 { in_line_eoln, 0 }, /* In */
113 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Li */
114 { in_line_eoln, 0 }, /* Nd */
115 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */
116 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */
117 { obsolete, 0 }, /* Ot */
118 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */
119 { in_line_eoln, 0 }, /* Rv */
120 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */
121 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Va */
122 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */
123 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */
124 { in_line_eoln, 0 }, /* %A */
125 { in_line_eoln, 0 }, /* %B */
126 { in_line_eoln, 0 }, /* %D */
127 { in_line_eoln, 0 }, /* %I */
128 { in_line_eoln, 0 }, /* %J */
129 { in_line_eoln, 0 }, /* %N */
130 { in_line_eoln, 0 }, /* %O */
131 { in_line_eoln, 0 }, /* %P */
132 { in_line_eoln, 0 }, /* %R */
133 { in_line_eoln, 0 }, /* %T */
134 { in_line_eoln, 0 }, /* %V */
135 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ac */
136 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ao */
137 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Aq */
138 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* At */
139 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Bc */
140 { blk_full, MDOC_EXPLICIT }, /* Bf */
141 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bo */
142 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Bq */
143 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bsx */
144 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bx */
145 { in_line_eoln, 0 }, /* Db */
146 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Dc */
147 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Do */
148 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Dq */
149 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ec */
150 { blk_exp_close, MDOC_EXPLICIT }, /* Ef */
151 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Em */
152 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */
153 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */
154 { in_line, MDOC_PARSED }, /* Ms */
155 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* No */
156 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ns */
157 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */
158 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ox */
159 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Pc */
160 { in_line_argn, MDOC_PARSED | MDOC_IGNDELIM }, /* Pf */
161 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Po */
162 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Pq */
163 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Qc */
164 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Ql */
165 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Qo */
166 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Qq */
167 { blk_exp_close, MDOC_EXPLICIT }, /* Re */
168 { blk_full, MDOC_EXPLICIT }, /* Rs */
169 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Sc */
170 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* So */
171 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Sq */
172 { in_line_eoln, 0 }, /* Sm */
173 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sx */
174 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sy */
175 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */
176 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ux */
177 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */
178 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */
179 { blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */
180 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Fc */
181 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Oo */
182 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Oc */
183 { blk_full, MDOC_EXPLICIT }, /* Bk */
184 { blk_exp_close, MDOC_EXPLICIT }, /* Ek */
185 { in_line_eoln, 0 }, /* Bt */
186 { in_line_eoln, 0 }, /* Hf */
187 { obsolete, 0 }, /* Fr */
188 { in_line_eoln, 0 }, /* Ud */
189 { in_line_eoln, 0 }, /* Lb */
190 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ap */
191 { in_line, 0 }, /* Lp */
192 { in_line, MDOC_PARSED }, /* Lk */
193 { in_line, MDOC_PARSED }, /* Mt */
194 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Brq */
195 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bro */
196 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Brc */
197 { in_line_eoln, 0 }, /* %C */
198 { obsolete, 0 }, /* Es */
199 { obsolete, 0 }, /* En */
200 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */
201 };
202
203 const struct mdoc_macro * const mdoc_macros = __mdoc_macros;
204
205
206 static int
207 perr(struct mdoc *mdoc, int line, int pos, enum merr type)
208 {
209 char *p;
210
211 p = NULL;
212 switch (type) {
213 case (EOPEN):
214 p = "explicit scope still open on exit";
215 break;
216 case (EQUOT):
217 p = "unterminated quotation";
218 break;
219 case (ENOCTX):
220 p = "closure has no prior context";
221 break;
222 case (ENOPARMS):
223 p = "unexpect line arguments";
224 break;
225 }
226 assert(p);
227 return(mdoc_perr(mdoc, line, pos, p));
228 }
229
230
231 static int
232 pwarn(struct mdoc *mdoc, int line, int pos, enum mwarn type)
233 {
234 char *p;
235
236 p = NULL;
237 switch (type) {
238 case (WMACPARM):
239 p = "macro-like parameter";
240 break;
241 case (WOBS):
242 p = "macro marked obsolete";
243 break;
244 }
245 assert(p);
246 return(mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX, p));
247 }
248
249
250 static int
251 swarn(struct mdoc *mdoc, enum mdoc_type type,
252 int line, int pos, const struct mdoc_node *p)
253 {
254 const char *n, *t, *tt;
255
256 n = t = "<root>";
257 tt = "block";
258
259 switch (type) {
260 case (MDOC_BODY):
261 tt = "multi-line";
262 break;
263 case (MDOC_HEAD):
264 tt = "line";
265 break;
266 default:
267 break;
268 }
269
270 switch (p->type) {
271 case (MDOC_BLOCK):
272 n = mdoc_macronames[p->tok];
273 t = "block";
274 break;
275 case (MDOC_BODY):
276 n = mdoc_macronames[p->tok];
277 t = "multi-line";
278 break;
279 case (MDOC_HEAD):
280 n = mdoc_macronames[p->tok];
281 t = "line";
282 break;
283 default:
284 break;
285 }
286
287 if ( ! (MDOC_IGN_SCOPE & mdoc->pflags))
288 return(mdoc_perr(mdoc, line, pos,
289 "%s scope breaks %s scope of %s",
290 tt, t, n));
291 return(mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX,
292 "%s scope breaks %s scope of %s",
293 tt, t, n));
294 }
295
296
297 /*
298 * This is called at the end of parsing. It must traverse up the tree,
299 * closing out open [implicit] scopes. Obviously, open explicit scopes
300 * are errors.
301 */
302 int
303 macro_end(struct mdoc *mdoc)
304 {
305 struct mdoc_node *n;
306
307 assert(mdoc->first);
308 assert(mdoc->last);
309
310 /* Scan for open explicit scopes. */
311
312 n = MDOC_VALID & mdoc->last->flags ?
313 mdoc->last->parent : mdoc->last;
314
315 for ( ; n; n = n->parent) {
316 if (MDOC_BLOCK != n->type)
317 continue;
318 if ( ! (MDOC_EXPLICIT & mdoc_macros[n->tok].flags))
319 continue;
320 return(nerr(mdoc, n, EOPEN));
321 }
322
323 return(rew_last(mdoc, mdoc->first));
324 }
325
326 static int
327 lookup(struct mdoc *mdoc, int line, int pos, int from, const char *p)
328 {
329 int res;
330
331 res = mdoc_tokhash_find(mdoc->htab, p);
332 if (MDOC_PARSED & mdoc_macros[from].flags)
333 return(res);
334 if (MDOC_MAX == res)
335 return(res);
336 if ( ! pwarn(mdoc, line, pos, WMACPARM))
337 return(-1);
338 return(MDOC_MAX);
339 }
340
341
342 static int
343 rew_last(struct mdoc *mdoc, struct mdoc_node *to)
344 {
345
346 assert(to);
347 mdoc->next = MDOC_NEXT_SIBLING;
348
349 /* LINTED */
350 while (mdoc->last != to) {
351 if ( ! mdoc_valid_post(mdoc))
352 return(0);
353 if ( ! mdoc_action_post(mdoc))
354 return(0);
355 mdoc->last = mdoc->last->parent;
356 assert(mdoc->last);
357 }
358
359 if ( ! mdoc_valid_post(mdoc))
360 return(0);
361 return(mdoc_action_post(mdoc));
362 }
363
364
365 static int
366 rew_alt(int tok)
367 {
368 switch (tok) {
369 case (MDOC_Ac):
370 return(MDOC_Ao);
371 case (MDOC_Bc):
372 return(MDOC_Bo);
373 case (MDOC_Brc):
374 return(MDOC_Bro);
375 case (MDOC_Dc):
376 return(MDOC_Do);
377 case (MDOC_Ec):
378 return(MDOC_Eo);
379 case (MDOC_Ed):
380 return(MDOC_Bd);
381 case (MDOC_Ef):
382 return(MDOC_Bf);
383 case (MDOC_Ek):
384 return(MDOC_Bk);
385 case (MDOC_El):
386 return(MDOC_Bl);
387 case (MDOC_Fc):
388 return(MDOC_Fo);
389 case (MDOC_Oc):
390 return(MDOC_Oo);
391 case (MDOC_Pc):
392 return(MDOC_Po);
393 case (MDOC_Qc):
394 return(MDOC_Qo);
395 case (MDOC_Re):
396 return(MDOC_Rs);
397 case (MDOC_Sc):
398 return(MDOC_So);
399 case (MDOC_Xc):
400 return(MDOC_Xo);
401 default:
402 break;
403 }
404 abort();
405 /* NOTREACHED */
406 }
407
408
409 /*
410 * Rewind rules. This indicates whether to stop rewinding
411 * (REWIND_HALT) without touching our current scope, stop rewinding and
412 * close our current scope (REWIND_REWIND), or continue (REWIND_NOHALT).
413 * The scope-closing and so on occurs in the various rew_* routines.
414 */
415 static int
416 rew_dohalt(int tok, enum mdoc_type type, const struct mdoc_node *p)
417 {
418
419 if (MDOC_ROOT == p->type)
420 return(REWIND_HALT);
421 if (MDOC_VALID & p->flags)
422 return(REWIND_NOHALT);
423
424 switch (tok) {
425 case (MDOC_Aq):
426 /* FALLTHROUGH */
427 case (MDOC_Bq):
428 /* FALLTHROUGH */
429 case (MDOC_Brq):
430 /* FALLTHROUGH */
431 case (MDOC_D1):
432 /* FALLTHROUGH */
433 case (MDOC_Dl):
434 /* FALLTHROUGH */
435 case (MDOC_Dq):
436 /* FALLTHROUGH */
437 case (MDOC_Op):
438 /* FALLTHROUGH */
439 case (MDOC_Pq):
440 /* FALLTHROUGH */
441 case (MDOC_Ql):
442 /* FALLTHROUGH */
443 case (MDOC_Qq):
444 /* FALLTHROUGH */
445 case (MDOC_Sq):
446 assert(MDOC_HEAD != type);
447 assert(MDOC_TAIL != type);
448 if (type == p->type && tok == p->tok)
449 return(REWIND_REWIND);
450 break;
451 case (MDOC_It):
452 assert(MDOC_TAIL != type);
453 if (type == p->type && tok == p->tok)
454 return(REWIND_REWIND);
455 if (MDOC_BODY == p->type && MDOC_Bl == p->tok)
456 return(REWIND_HALT);
457 break;
458 case (MDOC_Sh):
459 if (type == p->type && tok == p->tok)
460 return(REWIND_REWIND);
461 break;
462 case (MDOC_Ss):
463 assert(MDOC_TAIL != type);
464 if (type == p->type && tok == p->tok)
465 return(REWIND_REWIND);
466 if (MDOC_BODY == p->type && MDOC_Sh == p->tok)
467 return(REWIND_HALT);
468 break;
469 case (MDOC_Ao):
470 /* FALLTHROUGH */
471 case (MDOC_Bd):
472 /* FALLTHROUGH */
473 case (MDOC_Bf):
474 /* FALLTHROUGH */
475 case (MDOC_Bk):
476 /* FALLTHROUGH */
477 case (MDOC_Bl):
478 /* FALLTHROUGH */
479 case (MDOC_Bo):
480 /* FALLTHROUGH */
481 case (MDOC_Bro):
482 /* FALLTHROUGH */
483 case (MDOC_Do):
484 /* FALLTHROUGH */
485 case (MDOC_Eo):
486 /* FALLTHROUGH */
487 case (MDOC_Fo):
488 /* FALLTHROUGH */
489 case (MDOC_Oo):
490 /* FALLTHROUGH */
491 case (MDOC_Po):
492 /* FALLTHROUGH */
493 case (MDOC_Qo):
494 /* FALLTHROUGH */
495 case (MDOC_Rs):
496 /* FALLTHROUGH */
497 case (MDOC_So):
498 /* FALLTHROUGH */
499 case (MDOC_Xo):
500 if (type == p->type && tok == p->tok)
501 return(REWIND_REWIND);
502 break;
503
504 /* Multi-line explicit scope close. */
505 case (MDOC_Ac):
506 /* FALLTHROUGH */
507 case (MDOC_Bc):
508 /* FALLTHROUGH */
509 case (MDOC_Brc):
510 /* FALLTHROUGH */
511 case (MDOC_Dc):
512 /* FALLTHROUGH */
513 case (MDOC_Ec):
514 /* FALLTHROUGH */
515 case (MDOC_Ed):
516 /* FALLTHROUGH */
517 case (MDOC_Ek):
518 /* FALLTHROUGH */
519 case (MDOC_El):
520 /* FALLTHROUGH */
521 case (MDOC_Fc):
522 /* FALLTHROUGH */
523 case (MDOC_Ef):
524 /* FALLTHROUGH */
525 case (MDOC_Oc):
526 /* FALLTHROUGH */
527 case (MDOC_Pc):
528 /* FALLTHROUGH */
529 case (MDOC_Qc):
530 /* FALLTHROUGH */
531 case (MDOC_Re):
532 /* FALLTHROUGH */
533 case (MDOC_Sc):
534 /* FALLTHROUGH */
535 case (MDOC_Xc):
536 if (type == p->type && rew_alt(tok) == p->tok)
537 return(REWIND_REWIND);
538 break;
539 default:
540 abort();
541 /* NOTREACHED */
542 }
543
544 return(REWIND_NOHALT);
545 }
546
547
548 /*
549 * See if we can break an encountered scope (the rew_dohalt has returned
550 * REWIND_NOHALT).
551 */
552 static int
553 rew_dobreak(int tok, const struct mdoc_node *p)
554 {
555
556 assert(MDOC_ROOT != p->type);
557 if (MDOC_ELEM == p->type)
558 return(1);
559 if (MDOC_TEXT == p->type)
560 return(1);
561 if (MDOC_VALID & p->flags)
562 return(1);
563
564 switch (tok) {
565 case (MDOC_It):
566 return(MDOC_It == p->tok);
567 case (MDOC_Ss):
568 return(MDOC_Ss == p->tok);
569 case (MDOC_Sh):
570 if (MDOC_Ss == p->tok)
571 return(1);
572 return(MDOC_Sh == p->tok);
573 case (MDOC_El):
574 if (MDOC_It == p->tok)
575 return(1);
576 break;
577 case (MDOC_Oc):
578 /* XXX - experimental! */
579 if (MDOC_Op == p->tok)
580 return(1);
581 break;
582 default:
583 break;
584 }
585
586 if (MDOC_EXPLICIT & mdoc_macros[tok].flags)
587 return(p->tok == rew_alt(tok));
588 else if (MDOC_BLOCK == p->type)
589 return(1);
590
591 return(tok == p->tok);
592 }
593
594
595 static int
596 rew_elem(struct mdoc *mdoc, int tok)
597 {
598 struct mdoc_node *n;
599
600 n = mdoc->last;
601 if (MDOC_ELEM != n->type)
602 n = n->parent;
603 assert(MDOC_ELEM == n->type);
604 assert(tok == n->tok);
605
606 return(rew_last(mdoc, n));
607 }
608
609
610 static int
611 rew_subblock(enum mdoc_type type, struct mdoc *mdoc,
612 int tok, int line, int ppos)
613 {
614 struct mdoc_node *n;
615 int c;
616
617 /* LINTED */
618 for (n = mdoc->last; n; n = n->parent) {
619 c = rew_dohalt(tok, type, n);
620 if (REWIND_HALT == c)
621 return(1);
622 if (REWIND_REWIND == c)
623 break;
624 else if (rew_dobreak(tok, n))
625 continue;
626 if ( ! swarn(mdoc, type, line, ppos, n))
627 return(0);
628 }
629
630 assert(n);
631 return(rew_last(mdoc, n));
632 }
633
634
635 static int
636 rew_expblock(struct mdoc *mdoc, int tok, int line, int ppos)
637 {
638 struct mdoc_node *n;
639 int c;
640
641 /* LINTED */
642 for (n = mdoc->last; n; n = n->parent) {
643 c = rew_dohalt(tok, MDOC_BLOCK, n);
644 if (REWIND_HALT == c)
645 return(perr(mdoc, line, ppos, ENOCTX));
646 if (REWIND_REWIND == c)
647 break;
648 else if (rew_dobreak(tok, n))
649 continue;
650 if ( ! swarn(mdoc, MDOC_BLOCK, line, ppos, n))
651 return(0);
652 }
653
654 assert(n);
655 return(rew_last(mdoc, n));
656 }
657
658
659 static int
660 rew_impblock(struct mdoc *mdoc, int tok, int line, int ppos)
661 {
662 struct mdoc_node *n;
663 int c;
664
665 /* LINTED */
666 for (n = mdoc->last; n; n = n->parent) {
667 c = rew_dohalt(tok, MDOC_BLOCK, n);
668 if (REWIND_HALT == c)
669 return(1);
670 else if (REWIND_REWIND == c)
671 break;
672 else if (rew_dobreak(tok, n))
673 continue;
674 if ( ! swarn(mdoc, MDOC_BLOCK, line, ppos, n))
675 return(0);
676 }
677
678 assert(n);
679 return(rew_last(mdoc, n));
680 }
681
682
683 static int
684 append_delims(struct mdoc *mdoc, int line, int *pos, char *buf)
685 {
686 int c, lastarg;
687 char *p;
688
689 if (0 == buf[*pos])
690 return(1);
691
692 for (;;) {
693 lastarg = *pos;
694 c = mdoc_args(mdoc, line, pos, buf, 0, &p);
695 assert(ARGS_PHRASE != c);
696
697 if (ARGS_ERROR == c)
698 return(0);
699 else if (ARGS_EOLN == c)
700 break;
701 assert(mdoc_isdelim(p));
702 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
703 return(0);
704 mdoc->next = MDOC_NEXT_SIBLING;
705 }
706
707 return(1);
708 }
709
710
711 /*
712 * Close out block partial/full explicit.
713 */
714 static int
715 blk_exp_close(MACRO_PROT_ARGS)
716 {
717 int j, c, lastarg, maxargs, flushed;
718 char *p;
719
720 switch (tok) {
721 case (MDOC_Ec):
722 maxargs = 1;
723 break;
724 default:
725 maxargs = 0;
726 break;
727 }
728
729 if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
730 if (0 == buf[*pos]) {
731 if ( ! rew_subblock(MDOC_BODY, mdoc,
732 tok, line, ppos))
733 return(0);
734 return(rew_expblock(mdoc, tok, line, ppos));
735 }
736 return(perr(mdoc, line, ppos, ENOPARMS));
737 }
738
739 if ( ! rew_subblock(MDOC_BODY, mdoc, tok, line, ppos))
740 return(0);
741
742 if (maxargs > 0) {
743 if ( ! mdoc_tail_alloc(mdoc, line,
744 ppos, rew_alt(tok)))
745 return(0);
746 mdoc->next = MDOC_NEXT_CHILD;
747 }
748
749 for (lastarg = ppos, flushed = j = 0; ; j++) {
750 lastarg = *pos;
751
752 if (j == maxargs && ! flushed) {
753 if ( ! rew_expblock(mdoc, tok, line, ppos))
754 return(0);
755 flushed = 1;
756 }
757
758 c = mdoc_args(mdoc, line, pos, buf, tok, &p);
759
760 if (ARGS_ERROR == c)
761 return(0);
762 if (ARGS_PUNCT == c)
763 break;
764 if (ARGS_EOLN == c)
765 break;
766
767 if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
768 return(0);
769 else if (MDOC_MAX != c) {
770 if ( ! flushed) {
771 if ( ! rew_expblock(mdoc, tok,
772 line, ppos))
773 return(0);
774 flushed = 1;
775 }
776 if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
777 return(0);
778 break;
779 }
780
781 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
782 return(0);
783 mdoc->next = MDOC_NEXT_SIBLING;
784 }
785
786 if ( ! flushed && ! rew_expblock(mdoc, tok, line, ppos))
787 return(0);
788
789 if (ppos > 1)
790 return(1);
791 return(append_delims(mdoc, line, pos, buf));
792 }
793
794
795 /*
796 * In-line macros where reserved words cause scope close-reopen.
797 */
798 static int
799 in_line(MACRO_PROT_ARGS)
800 {
801 int la, lastpunct, c, w;
802 struct mdoc_arg *arg;
803 char *p;
804
805 for (la = ppos, arg = NULL;; ) {
806 la = *pos;
807 c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
808
809 if (ARGV_WORD == c) {
810 *pos = la;
811 break;
812 }
813
814 if (ARGV_EOLN == c)
815 break;
816 if (ARGV_ARG == c)
817 continue;
818
819 mdoc_argv_free(arg);
820 return(0);
821 }
822
823 if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
824 return(0);
825 mdoc->next = MDOC_NEXT_CHILD;
826
827 for (lastpunct = 0;; ) {
828 la = *pos;
829 w = mdoc_args(mdoc, line, pos, buf, tok, &p);
830
831 if (ARGS_ERROR == w)
832 return(0);
833 if (ARGS_EOLN == w)
834 break;
835 if (ARGS_PUNCT == w)
836 break;
837
838 /* Quoted words shouldn't be looked-up. */
839
840 c = ARGS_QWORD == w ? MDOC_MAX :
841 lookup(mdoc, line, la, tok, p);
842
843 /* MDOC_MAX (not a macro) or -1 (error). */
844
845 if (MDOC_MAX != c && -1 != c) {
846 if (0 == lastpunct && ! rew_elem(mdoc, tok))
847 return(0);
848 c = mdoc_macro(mdoc, c, line, la, pos, buf);
849 if (0 == c)
850 return(0);
851 if (ppos > 1)
852 return(1);
853 return(append_delims(mdoc, line, pos, buf));
854 } else if (-1 == c)
855 return(0);
856
857 /* Non-quote-enclosed punctuation. */
858
859 if (ARGS_QWORD != w && mdoc_isdelim(p)) {
860 if (0 == lastpunct && ! rew_elem(mdoc, tok))
861 return(0);
862 lastpunct = 1;
863 } else if (lastpunct) {
864 c = mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
865
866 if (0 == c)
867 return(0);
868
869 mdoc->next = MDOC_NEXT_CHILD;
870 lastpunct = 0;
871 }
872
873 if ( ! mdoc_word_alloc(mdoc, line, la, p))
874 return(0);
875 mdoc->next = MDOC_NEXT_SIBLING;
876 }
877
878 if (0 == lastpunct && ! rew_elem(mdoc, tok))
879 return(0);
880 if (ppos > 1)
881 return(1);
882 return(append_delims(mdoc, line, pos, buf));
883 }
884
885
886 /*
887 * Block full-explicit and full-implicit.
888 */
889 static int
890 blk_full(MACRO_PROT_ARGS)
891 {
892 int c, lastarg, reopen;
893 struct mdoc_arg *arg;
894 char *p;
895
896 if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
897 if ( ! rew_subblock(MDOC_BODY, mdoc,
898 tok, line, ppos))
899 return(0);
900 if ( ! rew_impblock(mdoc, tok, line, ppos))
901 return(0);
902 }
903
904 for (arg = NULL;; ) {
905 lastarg = *pos;
906 c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
907
908 if (ARGV_WORD == c) {
909 *pos = lastarg;
910 break;
911 }
912
913 if (ARGV_EOLN == c)
914 break;
915 if (ARGV_ARG == c)
916 continue;
917
918 mdoc_argv_free(arg);
919 return(0);
920 }
921
922 if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, arg))
923 return(0);
924 mdoc->next = MDOC_NEXT_CHILD;
925
926 if (0 == buf[*pos]) {
927 if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
928 return(0);
929 if ( ! rew_subblock(MDOC_HEAD, mdoc,
930 tok, line, ppos))
931 return(0);
932 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
933 return(0);
934 mdoc->next = MDOC_NEXT_CHILD;
935 return(1);
936 }
937
938 if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
939 return(0);
940 mdoc->next = MDOC_NEXT_CHILD;
941
942 for (reopen = 0;; ) {
943 lastarg = *pos;
944 c = mdoc_args(mdoc, line, pos, buf, tok, &p);
945
946 if (ARGS_ERROR == c)
947 return(0);
948 if (ARGS_EOLN == c)
949 break;
950 if (ARGS_PHRASE == c) {
951 if (reopen && ! mdoc_head_alloc
952 (mdoc, line, ppos, tok))
953 return(0);
954 mdoc->next = MDOC_NEXT_CHILD;
955 /*
956 * Phrases are self-contained macro phrases used
957 * in the columnar output of a macro. They need
958 * special handling.
959 */
960 if ( ! phrase(mdoc, line, lastarg, buf))
961 return(0);
962 if ( ! rew_subblock(MDOC_HEAD, mdoc,
963 tok, line, ppos))
964 return(0);
965
966 reopen = 1;
967 continue;
968 }
969
970 if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
971 return(0);
972
973 if (MDOC_MAX == c) {
974 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
975 return(0);
976 mdoc->next = MDOC_NEXT_SIBLING;
977 continue;
978 }
979
980 if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
981 return(0);
982 break;
983 }
984
985 if (1 == ppos && ! append_delims(mdoc, line, pos, buf))
986 return(0);
987 if ( ! rew_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
988 return(0);
989
990 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
991 return(0);
992 mdoc->next = MDOC_NEXT_CHILD;
993
994 return(1);
995 }
996
997
998 /*
999 * Block partial-imnplicit scope.
1000 */
1001 static int
1002 blk_part_imp(MACRO_PROT_ARGS)
1003 {
1004 int lastarg, c;
1005 char *p;
1006 struct mdoc_node *blk, *body, *n;
1007
1008 if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL))
1009 return(0);
1010 mdoc->next = MDOC_NEXT_CHILD;
1011 blk = mdoc->last;
1012
1013 if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1014 return(0);
1015 mdoc->next = MDOC_NEXT_SIBLING;
1016
1017 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1018 return(0);
1019 mdoc->next = MDOC_NEXT_CHILD;
1020 body = mdoc->last;
1021
1022 /* XXX - no known argument macros. */
1023
1024 for (lastarg = ppos;; ) {
1025 lastarg = *pos;
1026 c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1027 assert(ARGS_PHRASE != c);
1028
1029 if (ARGS_ERROR == c)
1030 return(0);
1031 if (ARGS_PUNCT == c)
1032 break;
1033 if (ARGS_EOLN == c)
1034 break;
1035
1036 if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1037 return(0);
1038 else if (MDOC_MAX == c) {
1039 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1040 return(0);
1041 mdoc->next = MDOC_NEXT_SIBLING;
1042 continue;
1043 }
1044
1045 if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1046 return(0);
1047 break;
1048 }
1049
1050 /*
1051 * Since we know what our context is, we can rewind directly to
1052 * it. This allows us to accomodate for our scope being
1053 * violated by another token.
1054 */
1055
1056 for (n = mdoc->last; n; n = n->parent)
1057 if (body == n)
1058 break;
1059
1060 if (n) {
1061 mdoc->last = body;
1062 mdoc->next = MDOC_NEXT_SIBLING;
1063 }
1064
1065 if (1 == ppos && ! append_delims(mdoc, line, pos, buf))
1066 return(0);
1067
1068 if (n) {
1069 mdoc->last = mdoc->last->parent;
1070 assert(mdoc->last == blk);
1071 mdoc->next = MDOC_NEXT_SIBLING;
1072 }
1073 return(1);
1074 }
1075
1076
1077 /*
1078 * Block partial-explicit macros.
1079 */
1080 static int
1081 blk_part_exp(MACRO_PROT_ARGS)
1082 {
1083 int lastarg, flushed, j, c, maxargs;
1084 char *p;
1085
1086 lastarg = ppos;
1087 flushed = 0;
1088
1089 /*
1090 * Number of arguments (head arguments). Only `Eo' has these,
1091 */
1092
1093 switch (tok) {
1094 case (MDOC_Eo):
1095 maxargs = 1;
1096 break;
1097 default:
1098 maxargs = 0;
1099 break;
1100 }
1101
1102 if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL))
1103 return(0);
1104 mdoc->next = MDOC_NEXT_CHILD;
1105
1106 if (0 == maxargs) {
1107 if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1108 return(0);
1109 if ( ! rew_subblock(MDOC_HEAD, mdoc,
1110 tok, line, ppos))
1111 return(0);
1112 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1113 return(0);
1114 flushed = 1;
1115 } else if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
1116 return(0);
1117
1118 mdoc->next = MDOC_NEXT_CHILD;
1119
1120 for (j = 0; ; j++) {
1121 lastarg = *pos;
1122 if (j == maxargs && ! flushed) {
1123 if ( ! rew_subblock(MDOC_HEAD, mdoc,
1124 tok, line, ppos))
1125 return(0);
1126 flushed = 1;
1127 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1128 return(0);
1129 mdoc->next = MDOC_NEXT_CHILD;
1130 }
1131
1132 c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1133 assert(ARGS_PHRASE != c);
1134
1135 if (ARGS_ERROR == c)
1136 return(0);
1137 if (ARGS_PUNCT == c)
1138 break;
1139 if (ARGS_EOLN == c)
1140 break;
1141
1142 if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1143 return(0);
1144 else if (MDOC_MAX != c) {
1145 if ( ! flushed) {
1146 if ( ! rew_subblock(MDOC_HEAD, mdoc,
1147 tok, line, ppos))
1148 return(0);
1149 flushed = 1;
1150 if ( ! mdoc_body_alloc(mdoc, line,
1151 ppos, tok))
1152 return(0);
1153 mdoc->next = MDOC_NEXT_CHILD;
1154 }
1155 if ( ! mdoc_macro(mdoc, c, line, lastarg,
1156 pos, buf))
1157 return(0);
1158 break;
1159 }
1160
1161 if ( ! flushed && mdoc_isdelim(p)) {
1162 if ( ! rew_subblock(MDOC_HEAD, mdoc,
1163 tok, line, ppos))
1164 return(0);
1165 flushed = 1;
1166 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1167 return(0);
1168 mdoc->next = MDOC_NEXT_CHILD;
1169 }
1170
1171 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1172 return(0);
1173 mdoc->next = MDOC_NEXT_SIBLING;
1174 }
1175
1176 if ( ! flushed) {
1177 if ( ! rew_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1178 return(0);
1179 if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1180 return(0);
1181 mdoc->next = MDOC_NEXT_CHILD;
1182 }
1183
1184 if (ppos > 1)
1185 return(1);
1186 return(append_delims(mdoc, line, pos, buf));
1187 }
1188
1189
1190 /*
1191 * In-line macros where reserved words signal closure of the macro.
1192 * Macros also have a fixed number of arguments.
1193 */
1194 static int
1195 in_line_argn(MACRO_PROT_ARGS)
1196 {
1197 int lastarg, flushed, j, c, maxargs;
1198 struct mdoc_arg *arg;
1199 char *p;
1200
1201
1202 /*
1203 * Fixed maximum arguments per macro. Some of these have none
1204 * and close as soon as the invocation is parsed.
1205 */
1206
1207 switch (tok) {
1208 case (MDOC_Ap):
1209 /* FALLTHROUGH */
1210 case (MDOC_No):
1211 /* FALLTHROUGH */
1212 case (MDOC_Ns):
1213 /* FALLTHROUGH */
1214 case (MDOC_Ux):
1215 maxargs = 0;
1216 break;
1217 default:
1218 maxargs = 1;
1219 break;
1220 }
1221
1222 for (lastarg = ppos, arg = NULL;; ) {
1223 lastarg = *pos;
1224 c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
1225
1226 if (ARGV_WORD == c) {
1227 *pos = lastarg;
1228 break;
1229 }
1230
1231 if (ARGV_EOLN == c)
1232 break;
1233 if (ARGV_ARG == c)
1234 continue;
1235
1236 mdoc_argv_free(arg);
1237 return(0);
1238 }
1239
1240 if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
1241 return(0);
1242 mdoc->next = MDOC_NEXT_CHILD;
1243
1244 for (flushed = j = 0; ; j++) {
1245 lastarg = *pos;
1246
1247 if (j == maxargs && ! flushed) {
1248 if ( ! rew_elem(mdoc, tok))
1249 return(0);
1250 flushed = 1;
1251 }
1252
1253 c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1254
1255 if (ARGS_ERROR == c)
1256 return(0);
1257 if (ARGS_PUNCT == c)
1258 break;
1259 if (ARGS_EOLN == c)
1260 break;
1261
1262 if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
1263 return(0);
1264 else if (MDOC_MAX != c) {
1265 if ( ! flushed && ! rew_elem(mdoc, tok))
1266 return(0);
1267 flushed = 1;
1268 if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1269 return(0);
1270 break;
1271 }
1272
1273 if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
1274 ! flushed && mdoc_isdelim(p)) {
1275 if ( ! rew_elem(mdoc, tok))
1276 return(0);
1277 flushed = 1;
1278 }
1279
1280 if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
1281 return(0);
1282 mdoc->next = MDOC_NEXT_SIBLING;
1283 }
1284
1285 if ( ! flushed && ! rew_elem(mdoc, tok))
1286 return(0);
1287
1288 if (ppos > 1)
1289 return(1);
1290 return(append_delims(mdoc, line, pos, buf));
1291 }
1292
1293
1294 /*
1295 * In-line macro that spans an entire line. May be callable, but has no
1296 * subsequent parsed arguments.
1297 */
1298 static int
1299 in_line_eoln(MACRO_PROT_ARGS)
1300 {
1301 int c, w, la;
1302 struct mdoc_arg *arg;
1303 char *p;
1304
1305 assert( ! (MDOC_PARSED & mdoc_macros[tok].flags));
1306
1307 arg = NULL;
1308
1309 for (;;) {
1310 la = *pos;
1311 c = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
1312
1313 if (ARGV_WORD == c) {
1314 *pos = la;
1315 break;
1316 }
1317 if (ARGV_EOLN == c)
1318 break;
1319 if (ARGV_ARG == c)
1320 continue;
1321
1322 mdoc_argv_free(arg);
1323 return(0);
1324 }
1325
1326 if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
1327 return(0);
1328
1329 mdoc->next = MDOC_NEXT_CHILD;
1330
1331 for (;;) {
1332 la = *pos;
1333 w = mdoc_args(mdoc, line, pos, buf, tok, &p);
1334
1335 if (ARGS_ERROR == w)
1336 return(0);
1337 if (ARGS_EOLN == w)
1338 break;
1339
1340 c = ARGS_QWORD == w ? MDOC_MAX :
1341 lookup(mdoc, line, la, tok, p);
1342
1343 if (MDOC_MAX != c && -1 != c) {
1344 if ( ! rew_elem(mdoc, tok))
1345 return(0);
1346 return(mdoc_macro(mdoc, c, line, la, pos, buf));
1347 } else if (-1 == c)
1348 return(0);
1349
1350 if ( ! mdoc_word_alloc(mdoc, line, la, p))
1351 return(0);
1352 mdoc->next = MDOC_NEXT_SIBLING;
1353 }
1354
1355 return(rew_elem(mdoc, tok));
1356 }
1357
1358
1359 /* ARGSUSED */
1360 static int
1361 obsolete(MACRO_PROT_ARGS)
1362 {
1363
1364 return(pwarn(mdoc, line, ppos, WOBS));
1365 }
1366
1367
1368 static int
1369 phrase(struct mdoc *mdoc, int line, int ppos, char *buf)
1370 {
1371 int i, la, c, quoted;
1372
1373 /*
1374 * Parse over words in a phrase. We have to handle this
1375 * specially because we assume no calling context -- in normal
1376 * circumstances, we switch argument parsing based on whether
1377 * the parent macro accepts quotes, tabs, etc. Here, anything
1378 * goes.
1379 */
1380
1381 for (i = ppos; buf[i]; ) {
1382 assert(' ' != buf[i]);
1383 la = i;
1384 quoted = 0;
1385
1386 /*
1387 * Read to next token. If quoted (check not escaped),
1388 * scan ahead to next unescaped quote. If not quoted or
1389 * escape-quoted, then scan ahead to next space.
1390 */
1391
1392 if ((i && '\"' == buf[i] && '\\' != buf[i - 1]) ||
1393 (0 == i && '\"' == buf[i])) {
1394 for (la = ++i; buf[i]; i++)
1395 if ('\"' != buf[i])
1396 continue;
1397 else if ('\\' != buf[i - 1])
1398 break;
1399 if (0 == buf[i])
1400 return(perr(mdoc, line, la, EQUOT));
1401 quoted = 1;
1402 } else
1403 for ( ; buf[i]; i++)
1404 if (i && ' ' == buf[i]) {
1405 if ('\\' != buf[i - 1])
1406 break;
1407 } else if (' ' == buf[i])
1408 break;
1409
1410 /* If not end-of-line, terminate argument. */
1411
1412 if (buf[i])
1413 buf[i++] = 0;
1414
1415 /* Read to next argument. */
1416
1417 for ( ; buf[i] && ' ' == buf[i]; i++)
1418 /* Spin. */ ;
1419
1420 /*
1421 * If we're a non-quoted string, try to look up the
1422 * value as a macro and execute it, if found.
1423 */
1424
1425 c = quoted ? MDOC_MAX :
1426 mdoc_tokhash_find(mdoc->htab, &buf[la]);
1427
1428 if (MDOC_MAX != c) {
1429 if ( ! mdoc_macro(mdoc, c, line, la, &i, buf))
1430 return(0);
1431 return(append_delims(mdoc, line, &i, buf));
1432 }
1433
1434 /* A regular word or quoted string. */
1435
1436 if ( ! mdoc_word_alloc(mdoc, line, la, &buf[la]))
1437 return(0);
1438 mdoc->next = MDOC_NEXT_SIBLING;
1439 }
1440
1441 return(1);
1442 }