]> git.cameronkatri.com Git - mandoc.git/blob - mdoc_macro.c
Add -Owidth=width option to mandoc -Tascii. Asked for by joerg@ about a
[mandoc.git] / mdoc_macro.c
1 /* $Id: mdoc_macro.c,v 1.79 2010/05/31 23:49:16 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
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 above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include <assert.h>
22 #include <ctype.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <time.h>
27
28 #include "mandoc.h"
29 #include "libmdoc.h"
30 #include "libmandoc.h"
31
32 enum rew {
33 REWIND_REWIND,
34 REWIND_NOHALT,
35 REWIND_HALT
36 };
37
38 static int blk_full(MACRO_PROT_ARGS);
39 static int blk_exp_close(MACRO_PROT_ARGS);
40 static int blk_part_exp(MACRO_PROT_ARGS);
41 static int blk_part_imp(MACRO_PROT_ARGS);
42 static int ctx_synopsis(MACRO_PROT_ARGS);
43 static int in_line_eoln(MACRO_PROT_ARGS);
44 static int in_line_argn(MACRO_PROT_ARGS);
45 static int in_line(MACRO_PROT_ARGS);
46 static int obsolete(MACRO_PROT_ARGS);
47 static int phrase_ta(MACRO_PROT_ARGS);
48
49 static int append_delims(struct mdoc *,
50 int, int *, char *);
51 static enum mdoct lookup(enum mdoct, const char *);
52 static enum mdoct lookup_raw(const char *);
53 static int phrase(struct mdoc *, int, int, char *);
54 static enum mdoct rew_alt(enum mdoct);
55 static int rew_dobreak(enum mdoct,
56 const struct mdoc_node *);
57 static enum rew rew_dohalt(enum mdoct, enum mdoc_type,
58 const struct mdoc_node *);
59 static int rew_elem(struct mdoc *, enum mdoct);
60 static int rew_last(struct mdoc *,
61 const struct mdoc_node *);
62 static int rew_sub(enum mdoc_type, struct mdoc *,
63 enum mdoct, int, int);
64 static int swarn(struct mdoc *, enum mdoc_type, int,
65 int, const struct mdoc_node *);
66
67 const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
68 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ap */
69 { in_line_eoln, MDOC_PROLOGUE }, /* Dd */
70 { in_line_eoln, MDOC_PROLOGUE }, /* Dt */
71 { in_line_eoln, MDOC_PROLOGUE }, /* Os */
72 { blk_full, 0 }, /* Sh */
73 { blk_full, 0 }, /* Ss */
74 { in_line_eoln, 0 }, /* Pp */
75 { blk_part_imp, MDOC_PARSED }, /* D1 */
76 { blk_part_imp, MDOC_PARSED }, /* Dl */
77 { blk_full, MDOC_EXPLICIT }, /* Bd */
78 { blk_exp_close, MDOC_EXPLICIT }, /* Ed */
79 { blk_full, MDOC_EXPLICIT }, /* Bl */
80 { blk_exp_close, MDOC_EXPLICIT }, /* El */
81 { blk_full, MDOC_PARSED }, /* It */
82 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
83 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* An */
84 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */
85 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cd */
86 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */
87 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */
88 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */
89 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */
90 { in_line_eoln, 0 }, /* Ex */
91 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */
92 { in_line_eoln, 0 }, /* Fd */
93 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */
94 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */
95 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */
96 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */
97 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */
98 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Li */
99 { blk_full, 0 }, /* Nd */
100 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */
101 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */
102 { obsolete, 0 }, /* Ot */
103 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */
104 { in_line_eoln, 0 }, /* Rv */
105 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */
106 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Va */
107 { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */
108 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */
109 { in_line_eoln, 0 }, /* %A */
110 { in_line_eoln, 0 }, /* %B */
111 { in_line_eoln, 0 }, /* %D */
112 { in_line_eoln, 0 }, /* %I */
113 { in_line_eoln, 0 }, /* %J */
114 { in_line_eoln, 0 }, /* %N */
115 { in_line_eoln, 0 }, /* %O */
116 { in_line_eoln, 0 }, /* %P */
117 { in_line_eoln, 0 }, /* %R */
118 { in_line_eoln, 0 }, /* %T */
119 { in_line_eoln, 0 }, /* %V */
120 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ac */
121 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ao */
122 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Aq */
123 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* At */
124 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Bc */
125 { blk_full, MDOC_EXPLICIT }, /* Bf */
126 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bo */
127 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Bq */
128 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bsx */
129 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bx */
130 { in_line_eoln, 0 }, /* Db */
131 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Dc */
132 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Do */
133 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Dq */
134 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ec */
135 { blk_exp_close, MDOC_EXPLICIT }, /* Ef */
136 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Em */
137 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */
138 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */
139 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ms */
140 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* No */
141 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ns */
142 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */
143 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ox */
144 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Pc */
145 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Pf */
146 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Po */
147 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Pq */
148 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Qc */
149 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Ql */
150 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Qo */
151 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Qq */
152 { blk_exp_close, MDOC_EXPLICIT }, /* Re */
153 { blk_full, MDOC_EXPLICIT }, /* Rs */
154 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Sc */
155 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* So */
156 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Sq */
157 { in_line_eoln, 0 }, /* Sm */
158 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sx */
159 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sy */
160 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */
161 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ux */
162 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */
163 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */
164 { blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */
165 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Fc */
166 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Oo */
167 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Oc */
168 { blk_full, MDOC_EXPLICIT }, /* Bk */
169 { blk_exp_close, MDOC_EXPLICIT }, /* Ek */
170 { in_line_eoln, 0 }, /* Bt */
171 { in_line_eoln, 0 }, /* Hf */
172 { obsolete, 0 }, /* Fr */
173 { in_line_eoln, 0 }, /* Ud */
174 { in_line, 0 }, /* Lb */
175 { in_line_eoln, 0 }, /* Lp */
176 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */
177 { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */
178 { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Brq */
179 { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bro */
180 { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Brc */
181 { in_line_eoln, 0 }, /* %C */
182 { obsolete, 0 }, /* Es */
183 { obsolete, 0 }, /* En */
184 { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */
185 { in_line_eoln, 0 }, /* %Q */
186 { in_line_eoln, 0 }, /* br */
187 { in_line_eoln, 0 }, /* sp */
188 { in_line_eoln, 0 }, /* %U */
189 { phrase_ta, MDOC_CALLABLE | MDOC_PARSED }, /* Ta */
190 };
191
192 const struct mdoc_macro * const mdoc_macros = __mdoc_macros;
193
194
195 static int
196 swarn(struct mdoc *mdoc, enum mdoc_type type,
197 int line, int pos, const struct mdoc_node *p)
198 {
199 const char *n, *t, *tt;
200 enum mandocerr ec;
201
202 n = t = "<root>";
203 tt = "block";
204
205 switch (type) {
206 case (MDOC_BODY):
207 tt = "multi-line";
208 break;
209 case (MDOC_HEAD):
210 tt = "line";
211 break;
212 default:
213 break;
214 }
215
216 switch (p->type) {
217 case (MDOC_BLOCK):
218 n = mdoc_macronames[p->tok];
219 t = "block";
220 break;
221 case (MDOC_BODY):
222 n = mdoc_macronames[p->tok];
223 t = "multi-line";
224 break;
225 case (MDOC_HEAD):
226 n = mdoc_macronames[p->tok];
227 t = "line";
228 break;
229 default:
230 break;
231 }
232
233 ec = (MDOC_IGN_SCOPE & mdoc->pflags) ?
234 MANDOCERR_SCOPE : MANDOCERR_SYNTSCOPE;
235
236 return(mdoc_vmsg(mdoc, ec, line, pos,
237 "%s scope breaks %s of %s",
238 tt, t, n));
239 }
240
241
242 /*
243 * This is called at the end of parsing. It must traverse up the tree,
244 * closing out open [implicit] scopes. Obviously, open explicit scopes
245 * are errors.
246 */
247 int
248 mdoc_macroend(struct mdoc *m)
249 {
250 struct mdoc_node *n;
251
252 /* Scan for open explicit scopes. */
253
254 n = MDOC_VALID & m->last->flags ? m->last->parent : m->last;
255
256 for ( ; n; n = n->parent) {
257 if (MDOC_BLOCK != n->type)
258 continue;
259 if ( ! (MDOC_EXPLICIT & mdoc_macros[n->tok].flags))
260 continue;
261 mdoc_nmsg(m, n, MANDOCERR_SYNTSCOPE);
262 return(0);
263 }
264
265 /* Rewind to the first. */
266
267 return(rew_last(m, m->first));
268 }
269
270
271 /*
272 * Look up a macro from within a subsequent context.
273 */
274 static enum mdoct
275 lookup(enum mdoct from, const char *p)
276 {
277 /* FIXME: make -diag lists be un-PARSED. */
278
279 if ( ! (MDOC_PARSED & mdoc_macros[from].flags))
280 return(MDOC_MAX);
281 return(lookup_raw(p));
282 }
283
284
285 /*
286 * Lookup a macro following the initial line macro.
287 */
288 static enum mdoct
289 lookup_raw(const char *p)
290 {
291 enum mdoct res;
292
293 if (MDOC_MAX == (res = mdoc_hash_find(p)))
294 return(MDOC_MAX);
295 if (MDOC_CALLABLE & mdoc_macros[res].flags)
296 return(res);
297 return(MDOC_MAX);
298 }
299
300
301 static int
302 rew_last(struct mdoc *mdoc, const struct mdoc_node *to)
303 {
304
305 assert(to);
306 mdoc->next = MDOC_NEXT_SIBLING;
307
308 /* LINTED */
309 while (mdoc->last != to) {
310 if ( ! mdoc_valid_post(mdoc))
311 return(0);
312 if ( ! mdoc_action_post(mdoc))
313 return(0);
314 mdoc->last = mdoc->last->parent;
315 assert(mdoc->last);
316 }
317
318 if ( ! mdoc_valid_post(mdoc))
319 return(0);
320 return(mdoc_action_post(mdoc));
321 }
322
323
324 /*
325 * Return the opening macro of a closing one, e.g., `Ec' has `Eo' as its
326 * matching pair.
327 */
328 static enum mdoct
329 rew_alt(enum mdoct tok)
330 {
331 switch (tok) {
332 case (MDOC_Ac):
333 return(MDOC_Ao);
334 case (MDOC_Bc):
335 return(MDOC_Bo);
336 case (MDOC_Brc):
337 return(MDOC_Bro);
338 case (MDOC_Dc):
339 return(MDOC_Do);
340 case (MDOC_Ec):
341 return(MDOC_Eo);
342 case (MDOC_Ed):
343 return(MDOC_Bd);
344 case (MDOC_Ef):
345 return(MDOC_Bf);
346 case (MDOC_Ek):
347 return(MDOC_Bk);
348 case (MDOC_El):
349 return(MDOC_Bl);
350 case (MDOC_Fc):
351 return(MDOC_Fo);
352 case (MDOC_Oc):
353 return(MDOC_Oo);
354 case (MDOC_Pc):
355 return(MDOC_Po);
356 case (MDOC_Qc):
357 return(MDOC_Qo);
358 case (MDOC_Re):
359 return(MDOC_Rs);
360 case (MDOC_Sc):
361 return(MDOC_So);
362 case (MDOC_Xc):
363 return(MDOC_Xo);
364 default:
365 break;
366 }
367 abort();
368 /* NOTREACHED */
369 }
370
371
372 /*
373 * Rewind rules. This indicates whether to stop rewinding
374 * (REWIND_HALT) without touching our current scope, stop rewinding and
375 * close our current scope (REWIND_REWIND), or continue (REWIND_NOHALT).
376 * The scope-closing and so on occurs in the various rew_* routines.
377 */
378 static enum rew
379 rew_dohalt(enum mdoct tok, enum mdoc_type type,
380 const struct mdoc_node *p)
381 {
382
383 if (MDOC_ROOT == p->type)
384 return(REWIND_HALT);
385 if (MDOC_VALID & p->flags)
386 return(REWIND_NOHALT);
387
388 switch (tok) {
389 case (MDOC_Aq):
390 /* FALLTHROUGH */
391 case (MDOC_Bq):
392 /* FALLTHROUGH */
393 case (MDOC_Brq):
394 /* FALLTHROUGH */
395 case (MDOC_D1):
396 /* FALLTHROUGH */
397 case (MDOC_Dl):
398 /* FALLTHROUGH */
399 case (MDOC_Dq):
400 /* FALLTHROUGH */
401 case (MDOC_Op):
402 /* FALLTHROUGH */
403 case (MDOC_Pq):
404 /* FALLTHROUGH */
405 case (MDOC_Ql):
406 /* FALLTHROUGH */
407 case (MDOC_Qq):
408 /* FALLTHROUGH */
409 case (MDOC_Sq):
410 /* FALLTHROUGH */
411 case (MDOC_Vt):
412 assert(MDOC_TAIL != type);
413 if (type == p->type && tok == p->tok)
414 return(REWIND_REWIND);
415 break;
416 case (MDOC_It):
417 assert(MDOC_TAIL != type);
418 if (type == p->type && tok == p->tok)
419 return(REWIND_REWIND);
420 if (MDOC_BODY == p->type && MDOC_Bl == p->tok)
421 return(REWIND_HALT);
422 break;
423 case (MDOC_Sh):
424 if (type == p->type && tok == p->tok)
425 return(REWIND_REWIND);
426 break;
427 case (MDOC_Nd):
428 /* FALLTHROUGH */
429 case (MDOC_Ss):
430 assert(MDOC_TAIL != type);
431 if (type == p->type && tok == p->tok)
432 return(REWIND_REWIND);
433 if (MDOC_BODY == p->type && MDOC_Sh == p->tok)
434 return(REWIND_HALT);
435 break;
436 case (MDOC_Ao):
437 /* FALLTHROUGH */
438 case (MDOC_Bd):
439 /* FALLTHROUGH */
440 case (MDOC_Bf):
441 /* FALLTHROUGH */
442 case (MDOC_Bk):
443 /* FALLTHROUGH */
444 case (MDOC_Bl):
445 /* FALLTHROUGH */
446 case (MDOC_Bo):
447 /* FALLTHROUGH */
448 case (MDOC_Bro):
449 /* FALLTHROUGH */
450 case (MDOC_Do):
451 /* FALLTHROUGH */
452 case (MDOC_Eo):
453 /* FALLTHROUGH */
454 case (MDOC_Fo):
455 /* FALLTHROUGH */
456 case (MDOC_Oo):
457 /* FALLTHROUGH */
458 case (MDOC_Po):
459 /* FALLTHROUGH */
460 case (MDOC_Qo):
461 /* FALLTHROUGH */
462 case (MDOC_Rs):
463 /* FALLTHROUGH */
464 case (MDOC_So):
465 /* FALLTHROUGH */
466 case (MDOC_Xo):
467 if (type == p->type && tok == p->tok)
468 return(REWIND_REWIND);
469 break;
470 /* Multi-line explicit scope close. */
471 case (MDOC_Ac):
472 /* FALLTHROUGH */
473 case (MDOC_Bc):
474 /* FALLTHROUGH */
475 case (MDOC_Brc):
476 /* FALLTHROUGH */
477 case (MDOC_Dc):
478 /* FALLTHROUGH */
479 case (MDOC_Ec):
480 /* FALLTHROUGH */
481 case (MDOC_Ed):
482 /* FALLTHROUGH */
483 case (MDOC_Ek):
484 /* FALLTHROUGH */
485 case (MDOC_El):
486 /* FALLTHROUGH */
487 case (MDOC_Fc):
488 /* FALLTHROUGH */
489 case (MDOC_Ef):
490 /* FALLTHROUGH */
491 case (MDOC_Oc):
492 /* FALLTHROUGH */
493 case (MDOC_Pc):
494 /* FALLTHROUGH */
495 case (MDOC_Qc):
496 /* FALLTHROUGH */
497 case (MDOC_Re):
498 /* FALLTHROUGH */
499 case (MDOC_Sc):
500 /* FALLTHROUGH */
501 case (MDOC_Xc):
502 if (type == p->type && rew_alt(tok) == p->tok)
503 return(REWIND_REWIND);
504 break;
505 default:
506 abort();
507 /* NOTREACHED */
508 }
509
510 return(REWIND_NOHALT);
511 }
512
513
514 /*
515 * See if we can break an encountered scope (the rew_dohalt has returned
516 * REWIND_NOHALT).
517 */
518 static int
519 rew_dobreak(enum mdoct tok, const struct mdoc_node *p)
520 {
521
522 assert(MDOC_ROOT != p->type);
523 if (MDOC_ELEM == p->type)
524 return(1);
525 if (MDOC_TEXT == p->type)
526 return(1);
527 if (MDOC_VALID & p->flags)
528 return(1);
529
530 switch (tok) {
531 case (MDOC_It):
532 return(MDOC_It == p->tok);
533 case (MDOC_Nd):
534 return(MDOC_Nd == p->tok);
535 case (MDOC_Ss):
536 return(MDOC_Ss == p->tok);
537 case (MDOC_Sh):
538 if (MDOC_Nd == p->tok)
539 return(1);
540 if (MDOC_Ss == p->tok)
541 return(1);
542 return(MDOC_Sh == p->tok);
543 case (MDOC_El):
544 if (MDOC_It == p->tok)
545 return(1);
546 break;
547 case (MDOC_Oc):
548 if (MDOC_Op == p->tok)
549 return(1);
550 break;
551 default:
552 break;
553 }
554
555 if (MDOC_EXPLICIT & mdoc_macros[tok].flags)
556 return(p->tok == rew_alt(tok));
557 else if (MDOC_BLOCK == p->type)
558 return(1);
559
560 return(tok == p->tok);
561 }
562
563
564 static int
565 rew_elem(struct mdoc *mdoc, enum mdoct tok)
566 {
567 struct mdoc_node *n;
568
569 n = mdoc->last;
570 if (MDOC_ELEM != n->type)
571 n = n->parent;
572 assert(MDOC_ELEM == n->type);
573 assert(tok == n->tok);
574
575 return(rew_last(mdoc, n));
576 }
577
578
579 static int
580 rew_sub(enum mdoc_type t, struct mdoc *m,
581 enum mdoct tok, int line, int ppos)
582 {
583 struct mdoc_node *n;
584 enum rew c;
585
586 /* LINTED */
587 for (n = m->last; n; n = n->parent) {
588 c = rew_dohalt(tok, t, n);
589 if (REWIND_HALT == c) {
590 if (MDOC_BLOCK != t)
591 return(1);
592 if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags))
593 return(1);
594 /* FIXME: shouldn't raise an error */
595 mdoc_pmsg(m, line, ppos, MANDOCERR_SYNTNOSCOPE);
596 return(0);
597 }
598 if (REWIND_REWIND == c)
599 break;
600 else if (rew_dobreak(tok, n))
601 continue;
602 if ( ! swarn(m, t, line, ppos, n))
603 return(0);
604 }
605
606 assert(n);
607 if ( ! rew_last(m, n))
608 return(0);
609
610 #ifdef UGLY
611 /*
612 * The current block extends an enclosing block beyond a line
613 * break. Now that the current block ends, close the enclosing
614 * block, too.
615 */
616 if (NULL != (n = n->pending)) {
617 assert(MDOC_HEAD == n->type);
618 if ( ! rew_last(m, n))
619 return(0);
620 if ( ! mdoc_body_alloc(m, n->line, n->pos, n->tok))
621 return(0);
622 }
623 #endif
624
625 return(1);
626 }
627
628
629 static int
630 append_delims(struct mdoc *m, int line, int *pos, char *buf)
631 {
632 int la;
633 enum margserr ac;
634 char *p;
635
636 if ('\0' == buf[*pos])
637 return(1);
638
639 for (;;) {
640 la = *pos;
641 ac = mdoc_zargs(m, line, pos, buf, ARGS_NOWARN, &p);
642
643 if (ARGS_ERROR == ac)
644 return(0);
645 else if (ARGS_EOLN == ac)
646 break;
647
648 assert(DELIM_NONE != mdoc_isdelim(p));
649 if ( ! mdoc_word_alloc(m, line, la, p))
650 return(0);
651
652 /*
653 * If we encounter end-of-sentence symbols, then trigger
654 * the double-space.
655 *
656 * XXX: it's easy to allow this to propogate outward to
657 * the last symbol, such that `. )' will cause the
658 * correct double-spacing. However, (1) groff isn't
659 * smart enough to do this and (2) it would require
660 * knowing which symbols break this behaviour, for
661 * example, `. ;' shouldn't propogate the double-space.
662 */
663 if (mandoc_eos(p, strlen(p)))
664 m->last->flags |= MDOC_EOS;
665 }
666
667 return(1);
668 }
669
670
671 /*
672 * Close out block partial/full explicit.
673 */
674 static int
675 blk_exp_close(MACRO_PROT_ARGS)
676 {
677 int j, lastarg, maxargs, flushed, nl;
678 enum margserr ac;
679 enum mdoct ntok;
680 char *p;
681
682 nl = MDOC_NEWLINE & m->flags;
683
684 switch (tok) {
685 case (MDOC_Ec):
686 maxargs = 1;
687 break;
688 default:
689 maxargs = 0;
690 break;
691 }
692
693 if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
694 /* FIXME: do this in validate */
695 if (buf[*pos])
696 if ( ! mdoc_pmsg(m, line, ppos, MANDOCERR_ARGSLOST))
697 return(0);
698
699 if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
700 return(0);
701 return(rew_sub(MDOC_BLOCK, m, tok, line, ppos));
702 }
703
704 if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
705 return(0);
706
707 if (maxargs > 0)
708 if ( ! mdoc_tail_alloc(m, line, ppos, rew_alt(tok)))
709 return(0);
710
711 for (flushed = j = 0; ; j++) {
712 lastarg = *pos;
713
714 if (j == maxargs && ! flushed) {
715 if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
716 return(0);
717 flushed = 1;
718 }
719
720 ac = mdoc_args(m, line, pos, buf, tok, &p);
721
722 if (ARGS_ERROR == ac)
723 return(0);
724 if (ARGS_PUNCT == ac)
725 break;
726 if (ARGS_EOLN == ac)
727 break;
728
729 ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
730
731 if (MDOC_MAX == ntok) {
732 if ( ! mdoc_word_alloc(m, line, lastarg, p))
733 return(0);
734 continue;
735 }
736
737 if ( ! flushed) {
738 if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
739 return(0);
740 flushed = 1;
741 }
742 if ( ! mdoc_macro(m, ntok, line, lastarg, pos, buf))
743 return(0);
744 break;
745 }
746
747 if ( ! flushed && ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
748 return(0);
749
750 if ( ! nl)
751 return(1);
752 return(append_delims(m, line, pos, buf));
753 }
754
755
756 static int
757 in_line(MACRO_PROT_ARGS)
758 {
759 int la, scope, cnt, nc, nl;
760 enum margverr av;
761 enum mdoct ntok;
762 enum margserr ac;
763 enum mdelim d;
764 struct mdoc_arg *arg;
765 char *p;
766
767 nl = MDOC_NEWLINE & m->flags;
768
769 /*
770 * Whether we allow ignored elements (those without content,
771 * usually because of reserved words) to squeak by.
772 */
773
774 switch (tok) {
775 case (MDOC_An):
776 /* FALLTHROUGH */
777 case (MDOC_Ar):
778 /* FALLTHROUGH */
779 case (MDOC_Fl):
780 /* FALLTHROUGH */
781 case (MDOC_Lk):
782 /* FALLTHROUGH */
783 case (MDOC_Nm):
784 /* FALLTHROUGH */
785 case (MDOC_Pa):
786 nc = 1;
787 break;
788 default:
789 nc = 0;
790 break;
791 }
792
793 for (arg = NULL;; ) {
794 la = *pos;
795 av = mdoc_argv(m, line, tok, &arg, pos, buf);
796
797 if (ARGV_WORD == av) {
798 *pos = la;
799 break;
800 }
801 if (ARGV_EOLN == av)
802 break;
803 if (ARGV_ARG == av)
804 continue;
805
806 mdoc_argv_free(arg);
807 return(0);
808 }
809
810 for (cnt = scope = 0;; ) {
811 la = *pos;
812 ac = mdoc_args(m, line, pos, buf, tok, &p);
813
814 if (ARGS_ERROR == ac)
815 return(0);
816 if (ARGS_EOLN == ac)
817 break;
818 if (ARGS_PUNCT == ac)
819 break;
820
821 ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
822
823 /*
824 * In this case, we've located a submacro and must
825 * execute it. Close out scope, if open. If no
826 * elements have been generated, either create one (nc)
827 * or raise a warning.
828 */
829
830 if (MDOC_MAX != ntok) {
831 if (scope && ! rew_elem(m, tok))
832 return(0);
833 if (nc && 0 == cnt) {
834 if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
835 return(0);
836 if ( ! rew_last(m, m->last))
837 return(0);
838 } else if ( ! nc && 0 == cnt) {
839 mdoc_argv_free(arg);
840 if ( ! mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY))
841 return(0);
842 }
843 if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
844 return(0);
845 if ( ! nl)
846 return(1);
847 return(append_delims(m, line, pos, buf));
848 }
849
850 /*
851 * Non-quote-enclosed punctuation. Set up our scope, if
852 * a word; rewind the scope, if a delimiter; then append
853 * the word.
854 */
855
856 d = ARGS_QWORD == ac ? DELIM_NONE : mdoc_isdelim(p);
857
858 if (DELIM_NONE != d) {
859 /*
860 * If we encounter closing punctuation, no word
861 * has been omitted, no scope is open, and we're
862 * allowed to have an empty element, then start
863 * a new scope. `Ar', `Fl', and `Li', only do
864 * this once per invocation. There may be more
865 * of these (all of them?).
866 */
867 if (0 == cnt && (nc || MDOC_Li == tok) &&
868 DELIM_CLOSE == d && ! scope) {
869 if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
870 return(0);
871 if (MDOC_Ar == tok || MDOC_Li == tok ||
872 MDOC_Fl == tok)
873 cnt++;
874 scope = 1;
875 }
876 /*
877 * Close out our scope, if one is open, before
878 * any punctuation.
879 */
880 if (scope && ! rew_elem(m, tok))
881 return(0);
882 scope = 0;
883 } else if ( ! scope) {
884 if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
885 return(0);
886 scope = 1;
887 }
888
889 if (DELIM_NONE == d)
890 cnt++;
891 if ( ! mdoc_word_alloc(m, line, la, p))
892 return(0);
893
894 /*
895 * `Fl' macros have their scope re-opened with each new
896 * word so that the `-' can be added to each one without
897 * having to parse out spaces.
898 */
899 if (scope && MDOC_Fl == tok) {
900 if ( ! rew_elem(m, tok))
901 return(0);
902 scope = 0;
903 }
904 }
905
906 if (scope && ! rew_elem(m, tok))
907 return(0);
908
909 /*
910 * If no elements have been collected and we're allowed to have
911 * empties (nc), open a scope and close it out. Otherwise,
912 * raise a warning.
913 */
914
915 if (nc && 0 == cnt) {
916 if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
917 return(0);
918 if ( ! rew_last(m, m->last))
919 return(0);
920 } else if ( ! nc && 0 == cnt) {
921 mdoc_argv_free(arg);
922 if ( ! mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY))
923 return(0);
924 }
925
926 if ( ! nl)
927 return(1);
928 return(append_delims(m, line, pos, buf));
929 }
930
931
932 static int
933 blk_full(MACRO_PROT_ARGS)
934 {
935 int la, nl;
936 struct mdoc_arg *arg;
937 struct mdoc_node *head; /* save of head macro */
938 struct mdoc_node *body; /* save of body macro */
939 #ifdef UGLY
940 struct mdoc_node *n;
941 #endif
942 enum mdoc_type mtt;
943 enum mdoct ntok;
944 enum margserr ac, lac;
945 enum margverr av;
946 char *p;
947
948 nl = MDOC_NEWLINE & m->flags;
949
950 /* Close out prior implicit scope. */
951
952 if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
953 if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
954 return(0);
955 if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
956 return(0);
957 }
958
959 /*
960 * This routine accomodates implicitly- and explicitly-scoped
961 * macro openings. Implicit ones first close out prior scope
962 * (seen above). Delay opening the head until necessary to
963 * allow leading punctuation to print. Special consideration
964 * for `It -column', which has phrase-part syntax instead of
965 * regular child nodes.
966 */
967
968 for (arg = NULL;; ) {
969 la = *pos;
970 av = mdoc_argv(m, line, tok, &arg, pos, buf);
971
972 if (ARGV_WORD == av) {
973 *pos = la;
974 break;
975 }
976
977 if (ARGV_EOLN == av)
978 break;
979 if (ARGV_ARG == av)
980 continue;
981
982 mdoc_argv_free(arg);
983 return(0);
984 }
985
986 if ( ! mdoc_block_alloc(m, line, ppos, tok, arg))
987 return(0);
988
989 head = body = NULL;
990
991 /*
992 * The `Nd' macro has all arguments in its body: it's a hybrid
993 * of block partial-explicit and full-implicit. Stupid.
994 */
995
996 if (MDOC_Nd == tok) {
997 if ( ! mdoc_head_alloc(m, line, ppos, tok))
998 return(0);
999 head = m->last;
1000 if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1001 return(0);
1002 if ( ! mdoc_body_alloc(m, line, ppos, tok))
1003 return(0);
1004 body = m->last;
1005 }
1006
1007 ac = ARGS_ERROR;
1008
1009 for ( ; ; ) {
1010 la = *pos;
1011 /* Initialise last-phrase-type with ARGS_PEND. */
1012 lac = ARGS_ERROR == ac ? ARGS_PEND : ac;
1013 ac = mdoc_args(m, line, pos, buf, tok, &p);
1014
1015 if (ARGS_ERROR == ac)
1016 return(0);
1017
1018 if (ARGS_EOLN == ac) {
1019 if (ARGS_PPHRASE != lac && ARGS_PHRASE != lac)
1020 break;
1021 /*
1022 * This is necessary: if the last token on a
1023 * line is a `Ta' or tab, then we'll get
1024 * ARGS_EOLN, so we must be smart enough to
1025 * reopen our scope if the last parse was a
1026 * phrase or partial phrase.
1027 */
1028 if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
1029 return(0);
1030 if ( ! mdoc_body_alloc(m, line, ppos, tok))
1031 return(0);
1032 body = m->last;
1033 break;
1034 }
1035
1036 /*
1037 * Emit leading punctuation (i.e., punctuation before
1038 * the MDOC_HEAD) for non-phrase types.
1039 */
1040
1041 if (NULL == head &&
1042 ARGS_PEND != ac &&
1043 ARGS_PHRASE != ac &&
1044 ARGS_PPHRASE != ac &&
1045 ARGS_QWORD != ac &&
1046 DELIM_OPEN == mdoc_isdelim(p)) {
1047 if ( ! mdoc_word_alloc(m, line, la, p))
1048 return(0);
1049 continue;
1050 }
1051
1052 /* Open a head if one hasn't been opened. */
1053
1054 if (NULL == head) {
1055 if ( ! mdoc_head_alloc(m, line, ppos, tok))
1056 return(0);
1057 head = m->last;
1058 }
1059
1060 if (ARGS_PHRASE == ac ||
1061 ARGS_PEND == ac ||
1062 ARGS_PPHRASE == ac) {
1063 /*
1064 * If we haven't opened a body yet, rewind the
1065 * head; if we have, rewind that instead.
1066 */
1067
1068 mtt = body ? MDOC_BODY : MDOC_HEAD;
1069 if ( ! rew_sub(mtt, m, tok, line, ppos))
1070 return(0);
1071
1072 /* Then allocate our body context. */
1073
1074 if ( ! mdoc_body_alloc(m, line, ppos, tok))
1075 return(0);
1076 body = m->last;
1077
1078 /*
1079 * Process phrases: set whether we're in a
1080 * partial-phrase (this effects line handling)
1081 * then call down into the phrase parser.
1082 */
1083
1084 if (ARGS_PPHRASE == ac)
1085 m->flags |= MDOC_PPHRASE;
1086 if (ARGS_PEND == ac && ARGS_PPHRASE == lac)
1087 m->flags |= MDOC_PPHRASE;
1088
1089 if ( ! phrase(m, line, la, buf))
1090 return(0);
1091
1092 m->flags &= ~MDOC_PPHRASE;
1093 continue;
1094 }
1095
1096 ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
1097
1098 if (MDOC_MAX == ntok) {
1099 if ( ! mdoc_word_alloc(m, line, la, p))
1100 return(0);
1101 continue;
1102 }
1103
1104 if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
1105 return(0);
1106 break;
1107 }
1108
1109 if (NULL == head) {
1110 if ( ! mdoc_head_alloc(m, line, ppos, tok))
1111 return(0);
1112 head = m->last;
1113 }
1114
1115 if (nl && ! append_delims(m, line, pos, buf))
1116 return(0);
1117
1118 /* If we've already opened our body, exit now. */
1119
1120 if (NULL != body)
1121 goto out;
1122
1123 #ifdef UGLY
1124 /*
1125 * If there is an open (i.e., unvalidated) sub-block requiring
1126 * explicit close-out, postpone switching the current block from
1127 * head to body until the rew_sub() call closing out that
1128 * sub-block.
1129 */
1130 for (n = m->last; n && n != head; n = n->parent) {
1131 if (MDOC_BLOCK == n->type &&
1132 MDOC_EXPLICIT & mdoc_macros[n->tok].flags &&
1133 ! (MDOC_VALID & n->flags)) {
1134 assert( ! (MDOC_ACTED & n->flags));
1135 n->pending = head;
1136 return(1);
1137 }
1138 }
1139 #endif
1140
1141 /* Close out scopes to remain in a consistent state. */
1142
1143 if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1144 return(0);
1145 if ( ! mdoc_body_alloc(m, line, ppos, tok))
1146 return(0);
1147
1148 out:
1149 if ( ! (MDOC_FREECOL & m->flags))
1150 return(1);
1151
1152 if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
1153 return(0);
1154 if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
1155 return(0);
1156
1157 m->flags &= ~MDOC_FREECOL;
1158 return(1);
1159 }
1160
1161
1162 static int
1163 blk_part_imp(MACRO_PROT_ARGS)
1164 {
1165 int la, nl;
1166 enum mdoct ntok;
1167 enum margserr ac;
1168 char *p;
1169 struct mdoc_node *blk; /* saved block context */
1170 struct mdoc_node *body; /* saved body context */
1171 struct mdoc_node *n;
1172
1173 nl = MDOC_NEWLINE & m->flags;
1174
1175 /*
1176 * A macro that spans to the end of the line. This is generally
1177 * (but not necessarily) called as the first macro. The block
1178 * has a head as the immediate child, which is always empty,
1179 * followed by zero or more opening punctuation nodes, then the
1180 * body (which may be empty, depending on the macro), then zero
1181 * or more closing punctuation nodes.
1182 */
1183
1184 if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL))
1185 return(0);
1186
1187 blk = m->last;
1188
1189 if ( ! mdoc_head_alloc(m, line, ppos, tok))
1190 return(0);
1191 if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1192 return(0);
1193
1194 /*
1195 * Open the body scope "on-demand", that is, after we've
1196 * processed all our the leading delimiters (open parenthesis,
1197 * etc.).
1198 */
1199
1200 for (body = NULL; ; ) {
1201 la = *pos;
1202 ac = mdoc_args(m, line, pos, buf, tok, &p);
1203
1204 if (ARGS_ERROR == ac)
1205 return(0);
1206 if (ARGS_EOLN == ac)
1207 break;
1208 if (ARGS_PUNCT == ac)
1209 break;
1210
1211 if (NULL == body && ARGS_QWORD != ac &&
1212 DELIM_OPEN == mdoc_isdelim(p)) {
1213 if ( ! mdoc_word_alloc(m, line, la, p))
1214 return(0);
1215 continue;
1216 }
1217
1218 if (NULL == body) {
1219 if ( ! mdoc_body_alloc(m, line, ppos, tok))
1220 return(0);
1221 body = m->last;
1222 }
1223
1224 ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
1225
1226 if (MDOC_MAX == ntok) {
1227 if ( ! mdoc_word_alloc(m, line, la, p))
1228 return(0);
1229 continue;
1230 }
1231
1232 if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
1233 return(0);
1234 break;
1235 }
1236
1237 /* Clean-ups to leave in a consistent state. */
1238
1239 if (NULL == body) {
1240 if ( ! mdoc_body_alloc(m, line, ppos, tok))
1241 return(0);
1242 body = m->last;
1243 }
1244
1245 for (n = body->child; n && n->next; n = n->next)
1246 /* Do nothing. */ ;
1247
1248 /*
1249 * End of sentence spacing: if the last node is a text node and
1250 * has a trailing period, then mark it as being end-of-sentence.
1251 */
1252
1253 if (n && MDOC_TEXT == n->type && n->string)
1254 if (mandoc_eos(n->string, strlen(n->string)))
1255 n->flags |= MDOC_EOS;
1256
1257 /* Up-propogate the end-of-space flag. */
1258
1259 if (n && (MDOC_EOS & n->flags)) {
1260 body->flags |= MDOC_EOS;
1261 body->parent->flags |= MDOC_EOS;
1262 }
1263
1264 /*
1265 * If we can't rewind to our body, then our scope has already
1266 * been closed by another macro (like `Oc' closing `Op'). This
1267 * is ugly behaviour nodding its head to OpenBSD's overwhelming
1268 * crufty use of `Op' breakage.
1269 *
1270 * FIXME - this should be ifdef'd OpenBSD?
1271 */
1272 for (n = m->last; n; n = n->parent)
1273 if (body == n)
1274 break;
1275
1276 if (NULL == n && ! mdoc_nmsg(m, body, MANDOCERR_SCOPE))
1277 return(0);
1278
1279 if (n && ! rew_last(m, body))
1280 return(0);
1281
1282 /* Standard appending of delimiters. */
1283
1284 if (nl && ! append_delims(m, line, pos, buf))
1285 return(0);
1286
1287 /* Rewind scope, if applicable. */
1288
1289 if (n && ! rew_last(m, blk))
1290 return(0);
1291
1292 return(1);
1293 }
1294
1295
1296 static int
1297 blk_part_exp(MACRO_PROT_ARGS)
1298 {
1299 int la, nl;
1300 enum margserr ac;
1301 struct mdoc_node *head; /* keep track of head */
1302 struct mdoc_node *body; /* keep track of body */
1303 char *p;
1304 enum mdoct ntok;
1305
1306 nl = MDOC_NEWLINE & m->flags;
1307
1308 /*
1309 * The opening of an explicit macro having zero or more leading
1310 * punctuation nodes; a head with optional single element (the
1311 * case of `Eo'); and a body that may be empty.
1312 */
1313
1314 if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL))
1315 return(0);
1316
1317 for (head = body = NULL; ; ) {
1318 la = *pos;
1319 ac = mdoc_args(m, line, pos, buf, tok, &p);
1320
1321 if (ARGS_ERROR == ac)
1322 return(0);
1323 if (ARGS_PUNCT == ac)
1324 break;
1325 if (ARGS_EOLN == ac)
1326 break;
1327
1328 /* Flush out leading punctuation. */
1329
1330 if (NULL == head && ARGS_QWORD != ac &&
1331 DELIM_OPEN == mdoc_isdelim(p)) {
1332 assert(NULL == body);
1333 if ( ! mdoc_word_alloc(m, line, la, p))
1334 return(0);
1335 continue;
1336 }
1337
1338 if (NULL == head) {
1339 assert(NULL == body);
1340 if ( ! mdoc_head_alloc(m, line, ppos, tok))
1341 return(0);
1342 head = m->last;
1343 }
1344
1345 /*
1346 * `Eo' gobbles any data into the head, but most other
1347 * macros just immediately close out and begin the body.
1348 */
1349
1350 if (NULL == body) {
1351 assert(head);
1352 /* No check whether it's a macro! */
1353 if (MDOC_Eo == tok)
1354 if ( ! mdoc_word_alloc(m, line, la, p))
1355 return(0);
1356
1357 if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1358 return(0);
1359 if ( ! mdoc_body_alloc(m, line, ppos, tok))
1360 return(0);
1361 body = m->last;
1362
1363 if (MDOC_Eo == tok)
1364 continue;
1365 }
1366
1367 assert(NULL != head && NULL != body);
1368
1369 ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
1370
1371 if (MDOC_MAX == ntok) {
1372 if ( ! mdoc_word_alloc(m, line, la, p))
1373 return(0);
1374 continue;
1375 }
1376
1377 if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
1378 return(0);
1379 break;
1380 }
1381
1382 /* Clean-up to leave in a consistent state. */
1383
1384 if (NULL == head) {
1385 if ( ! mdoc_head_alloc(m, line, ppos, tok))
1386 return(0);
1387 head = m->last;
1388 }
1389
1390 if (NULL == body) {
1391 if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
1392 return(0);
1393 if ( ! mdoc_body_alloc(m, line, ppos, tok))
1394 return(0);
1395 body = m->last;
1396 }
1397
1398 /* Standard appending of delimiters. */
1399
1400 if ( ! nl)
1401 return(1);
1402 return(append_delims(m, line, pos, buf));
1403 }
1404
1405
1406 /* ARGSUSED */
1407 static int
1408 in_line_argn(MACRO_PROT_ARGS)
1409 {
1410 int la, flushed, j, maxargs, nl;
1411 enum margserr ac;
1412 enum margverr av;
1413 struct mdoc_arg *arg;
1414 char *p;
1415 enum mdoct ntok;
1416
1417 nl = MDOC_NEWLINE & m->flags;
1418
1419 /*
1420 * A line macro that has a fixed number of arguments (maxargs).
1421 * Only open the scope once the first non-leading-punctuation is
1422 * found (unless MDOC_IGNDELIM is noted, like in `Pf'), then
1423 * keep it open until the maximum number of arguments are
1424 * exhausted.
1425 */
1426
1427 switch (tok) {
1428 case (MDOC_Ap):
1429 /* FALLTHROUGH */
1430 case (MDOC_No):
1431 /* FALLTHROUGH */
1432 case (MDOC_Ns):
1433 /* FALLTHROUGH */
1434 case (MDOC_Ux):
1435 maxargs = 0;
1436 break;
1437 case (MDOC_Xr):
1438 maxargs = 2;
1439 break;
1440 default:
1441 maxargs = 1;
1442 break;
1443 }
1444
1445 for (arg = NULL; ; ) {
1446 la = *pos;
1447 av = mdoc_argv(m, line, tok, &arg, pos, buf);
1448
1449 if (ARGV_WORD == av) {
1450 *pos = la;
1451 break;
1452 }
1453
1454 if (ARGV_EOLN == av)
1455 break;
1456 if (ARGV_ARG == av)
1457 continue;
1458
1459 mdoc_argv_free(arg);
1460 return(0);
1461 }
1462
1463 for (flushed = j = 0; ; ) {
1464 la = *pos;
1465 ac = mdoc_args(m, line, pos, buf, tok, &p);
1466
1467 if (ARGS_ERROR == ac)
1468 return(0);
1469 if (ARGS_PUNCT == ac)
1470 break;
1471 if (ARGS_EOLN == ac)
1472 break;
1473
1474 if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
1475 ARGS_QWORD != ac &&
1476 0 == j && DELIM_OPEN == mdoc_isdelim(p)) {
1477 if ( ! mdoc_word_alloc(m, line, la, p))
1478 return(0);
1479 continue;
1480 } else if (0 == j)
1481 if ( ! mdoc_elem_alloc(m, line, la, tok, arg))
1482 return(0);
1483
1484 if (j == maxargs && ! flushed) {
1485 if ( ! rew_elem(m, tok))
1486 return(0);
1487 flushed = 1;
1488 }
1489
1490 ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
1491
1492 if (MDOC_MAX != ntok) {
1493 if ( ! flushed && ! rew_elem(m, tok))
1494 return(0);
1495 flushed = 1;
1496 if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
1497 return(0);
1498 j++;
1499 break;
1500 }
1501
1502 if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
1503 ARGS_QWORD != ac &&
1504 ! flushed &&
1505 DELIM_NONE != mdoc_isdelim(p)) {
1506 if ( ! rew_elem(m, tok))
1507 return(0);
1508 flushed = 1;
1509 }
1510
1511 /*
1512 * XXX: this is a hack to work around groff's ugliness
1513 * as regards `Xr' and extraneous arguments. It should
1514 * ideally be deprecated behaviour, but because this is
1515 * code is no here, it's unlikely to be removed.
1516 */
1517
1518 #ifdef __OpenBSD__
1519 if (MDOC_Xr == tok && j == maxargs) {
1520 if ( ! mdoc_elem_alloc(m, line, la, MDOC_Ns, NULL))
1521 return(0);
1522 if ( ! rew_elem(m, MDOC_Ns))
1523 return(0);
1524 }
1525 #endif
1526
1527 if ( ! mdoc_word_alloc(m, line, la, p))
1528 return(0);
1529 j++;
1530 }
1531
1532 if (0 == j && ! mdoc_elem_alloc(m, line, la, tok, arg))
1533 return(0);
1534
1535 /* Close out in a consistent state. */
1536
1537 if ( ! flushed && ! rew_elem(m, tok))
1538 return(0);
1539 if ( ! nl)
1540 return(1);
1541 return(append_delims(m, line, pos, buf));
1542 }
1543
1544
1545 static int
1546 in_line_eoln(MACRO_PROT_ARGS)
1547 {
1548 int la;
1549 enum margserr ac;
1550 enum margverr av;
1551 struct mdoc_arg *arg;
1552 char *p;
1553 enum mdoct ntok;
1554
1555 assert( ! (MDOC_PARSED & mdoc_macros[tok].flags));
1556
1557 /* Parse macro arguments. */
1558
1559 for (arg = NULL; ; ) {
1560 la = *pos;
1561 av = mdoc_argv(m, line, tok, &arg, pos, buf);
1562
1563 if (ARGV_WORD == av) {
1564 *pos = la;
1565 break;
1566 }
1567 if (ARGV_EOLN == av)
1568 break;
1569 if (ARGV_ARG == av)
1570 continue;
1571
1572 mdoc_argv_free(arg);
1573 return(0);
1574 }
1575
1576 /* Open element scope. */
1577
1578 if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
1579 return(0);
1580
1581 /* Parse argument terms. */
1582
1583 for (;;) {
1584 la = *pos;
1585 ac = mdoc_args(m, line, pos, buf, tok, &p);
1586
1587 if (ARGS_ERROR == ac)
1588 return(0);
1589 if (ARGS_EOLN == ac)
1590 break;
1591
1592 ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
1593
1594 if (MDOC_MAX == ntok) {
1595 if ( ! mdoc_word_alloc(m, line, la, p))
1596 return(0);
1597 continue;
1598 }
1599
1600 if ( ! rew_elem(m, tok))
1601 return(0);
1602 return(mdoc_macro(m, ntok, line, la, pos, buf));
1603 }
1604
1605 /* Close out (no delimiters). */
1606
1607 return(rew_elem(m, tok));
1608 }
1609
1610
1611 /* ARGSUSED */
1612 static int
1613 ctx_synopsis(MACRO_PROT_ARGS)
1614 {
1615 int nl;
1616
1617 nl = MDOC_NEWLINE & m->flags;
1618
1619 /* If we're not in the SYNOPSIS, go straight to in-line. */
1620 if (SEC_SYNOPSIS != m->lastsec)
1621 return(in_line(m, tok, line, ppos, pos, buf));
1622
1623 /* If we're a nested call, same place. */
1624 if ( ! nl)
1625 return(in_line(m, tok, line, ppos, pos, buf));
1626
1627 /*
1628 * XXX: this will open a block scope; however, if later we end
1629 * up formatting the block scope, then child nodes will inherit
1630 * the formatting. Be careful.
1631 */
1632
1633 return(blk_part_imp(m, tok, line, ppos, pos, buf));
1634 }
1635
1636
1637 /* ARGSUSED */
1638 static int
1639 obsolete(MACRO_PROT_ARGS)
1640 {
1641
1642 return(mdoc_pmsg(m, line, ppos, MANDOCERR_MACROOBS));
1643 }
1644
1645
1646 /*
1647 * Phrases occur within `Bl -column' entries, separated by `Ta' or tabs.
1648 * They're unusual because they're basically free-form text until a
1649 * macro is encountered.
1650 */
1651 static int
1652 phrase(struct mdoc *m, int line, int ppos, char *buf)
1653 {
1654 int la, pos;
1655 enum margserr ac;
1656 enum mdoct ntok;
1657 char *p;
1658
1659 for (pos = ppos; ; ) {
1660 la = pos;
1661
1662 ac = mdoc_zargs(m, line, &pos, buf, 0, &p);
1663
1664 if (ARGS_ERROR == ac)
1665 return(0);
1666 if (ARGS_EOLN == ac)
1667 break;
1668
1669 ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p);
1670
1671 if (MDOC_MAX == ntok) {
1672 if ( ! mdoc_word_alloc(m, line, la, p))
1673 return(0);
1674 continue;
1675 }
1676
1677 if ( ! mdoc_macro(m, ntok, line, la, &pos, buf))
1678 return(0);
1679 return(append_delims(m, line, &pos, buf));
1680 }
1681
1682 return(1);
1683 }
1684
1685
1686 /* ARGSUSED */
1687 static int
1688 phrase_ta(MACRO_PROT_ARGS)
1689 {
1690 int la;
1691 enum mdoct ntok;
1692 enum margserr ac;
1693 char *p;
1694
1695 /*
1696 * FIXME: this is overly restrictive: if the `Ta' is unexpected,
1697 * it should simply error out with ARGSLOST.
1698 */
1699
1700 if ( ! rew_sub(MDOC_BODY, m, MDOC_It, line, ppos))
1701 return(0);
1702 if ( ! mdoc_body_alloc(m, line, ppos, MDOC_It))
1703 return(0);
1704
1705 for (;;) {
1706 la = *pos;
1707 ac = mdoc_zargs(m, line, pos, buf, 0, &p);
1708
1709 if (ARGS_ERROR == ac)
1710 return(0);
1711 if (ARGS_EOLN == ac)
1712 break;
1713
1714 ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p);
1715
1716 if (MDOC_MAX == ntok) {
1717 if ( ! mdoc_word_alloc(m, line, la, p))
1718 return(0);
1719 continue;
1720 }
1721
1722 if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
1723 return(0);
1724 return(append_delims(m, line, pos, buf));
1725 }
1726
1727 return(1);
1728 }