Annotation of mandoc/macro.c, Revision 1.10
1.10 ! kristaps 1: /* $Id: macro.c,v 1.9 2008/12/28 23:07:04 kristaps Exp $ */
1.1 kristaps 2: /*
3: * Copyright (c) 2008 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
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: */
1.2 kristaps 19: #include <assert.h>
20: #include <ctype.h>
1.1 kristaps 21: #include <stdlib.h>
1.2 kristaps 22: #include <stdio.h>
1.5 kristaps 23: #include <string.h>
1.2 kristaps 24:
25: #include "private.h"
26:
1.10 ! kristaps 27: /* FIXME: maxlineargs should be per LINE, no per TOKEN. */
! 28:
1.3 kristaps 29: #define _CC(p) ((const char **)p)
1.2 kristaps 30:
1.6 kristaps 31: static int scope_rewind_exp(struct mdoc *, int, int, int);
1.7 kristaps 32: static int scope_rewind_imp(struct mdoc *, int, int);
1.3 kristaps 33: static int append_text(struct mdoc *, int,
34: int, int, char *[]);
1.10 ! kristaps 35: static int append_const(struct mdoc *, int, int, int, char *[]);
1.6 kristaps 36: static int append_scoped(struct mdoc *, int, int, int,
37: const char *[], int, const struct mdoc_arg *);
1.7 kristaps 38: static int append_delims(struct mdoc *, int, int *, char *);
1.6 kristaps 39:
40:
41: static int
1.7 kristaps 42: append_delims(struct mdoc *mdoc, int tok, int *pos, char *buf)
1.6 kristaps 43: {
1.7 kristaps 44: int c, lastarg;
45: char *p;
1.6 kristaps 46:
47: if (0 == buf[*pos])
1.7 kristaps 48: return(1);
1.6 kristaps 49:
1.8 kristaps 50: mdoc_msg(mdoc, *pos, "`%s' flushing punctuation",
51: mdoc_macronames[tok]);
1.6 kristaps 52:
1.7 kristaps 53: for (;;) {
54: lastarg = *pos;
55: c = mdoc_args(mdoc, tok, pos, buf, 0, &p);
56: if (ARGS_ERROR == c)
57: return(0);
58: else if (ARGS_EOLN == c)
59: break;
60: assert(mdoc_isdelim(p));
61: mdoc_word_alloc(mdoc, lastarg, p);
1.6 kristaps 62: }
63:
64: return(1);
65: }
66:
67:
68: static int
1.7 kristaps 69: scope_rewind_imp(struct mdoc *mdoc, int ppos, int tok)
1.6 kristaps 70: {
71: struct mdoc_node *n;
1.7 kristaps 72: int t;
73:
74: n = mdoc->last ? mdoc->last->parent : NULL;
1.6 kristaps 75:
76: /* LINTED */
1.7 kristaps 77: for ( ; n; n = n->parent) {
1.6 kristaps 78: if (MDOC_BLOCK != n->type)
79: continue;
1.7 kristaps 80: if (tok == (t = n->data.block.tok))
1.6 kristaps 81: break;
1.7 kristaps 82: if ( ! (MDOC_EXPLICIT & mdoc_macros[t].flags))
83: continue;
1.6 kristaps 84: return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_BREAK));
85: }
86:
1.7 kristaps 87: if (n) {
88: mdoc->last = n;
89: mdoc_msg(mdoc, ppos, "scope: rewound implicit `%s'",
90: mdoc_macronames[tok]);
91: return(1);
92: }
1.6 kristaps 93:
1.7 kristaps 94: mdoc_msg(mdoc, ppos, "scope: new implicit `%s'",
95: mdoc_macronames[tok]);
1.6 kristaps 96: return(1);
97: }
98:
99:
100: static int
1.7 kristaps 101: scope_rewind_exp(struct mdoc *mdoc, int ppos, int tok, int dst)
1.6 kristaps 102: {
1.7 kristaps 103: struct mdoc_node *n;
1.6 kristaps 104:
1.7 kristaps 105: assert(mdoc->last);
1.6 kristaps 106:
1.7 kristaps 107: /* LINTED */
108: for (n = mdoc->last->parent; n; n = n->parent) {
109: if (MDOC_BLOCK != n->type)
110: continue;
111: if (dst == n->data.block.tok)
112: break;
113: return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_BREAK));
1.6 kristaps 114: }
115:
1.7 kristaps 116: if (NULL == (mdoc->last = n))
117: return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_NOCTX));
1.6 kristaps 118:
1.7 kristaps 119: mdoc_msg(mdoc, ppos, "scope: rewound explicit `%s' to `%s'",
120: mdoc_macronames[tok], mdoc_macronames[dst]);
1.2 kristaps 121:
1.1 kristaps 122: return(1);
123: }
124:
1.2 kristaps 125:
126: static int
1.6 kristaps 127: append_scoped(struct mdoc *mdoc, int tok, int pos,
128: int sz, const char *args[],
129: int argc, const struct mdoc_arg *argv)
1.2 kristaps 130: {
1.7 kristaps 131: enum mdoc_sec sec;
132: struct mdoc_node *node;
1.5 kristaps 133:
1.4 kristaps 134: switch (tok) {
135: /* ======= ADD MORE MACRO CHECKS BELOW. ======= */
136: case (MDOC_Sh):
1.6 kristaps 137: if (0 == sz)
138: return(mdoc_err(mdoc, tok, pos, ERR_ARGS_GE1));
139:
1.5 kristaps 140: sec = mdoc_atosec((size_t)sz, _CC(args));
141: if (SEC_CUSTOM != sec && sec < mdoc->sec_lastn)
142: if ( ! mdoc_warn(mdoc, tok, pos, WARN_SEC_OO))
143: return(0);
144:
145: if (SEC_BODY == mdoc->sec_last && SEC_NAME != sec)
146: return(mdoc_err(mdoc, tok, pos, ERR_SEC_NAME));
147:
148: if (SEC_CUSTOM != sec)
149: mdoc->sec_lastn = sec;
150: mdoc->sec_last = sec;
1.4 kristaps 151: break;
1.6 kristaps 152:
1.4 kristaps 153: case (MDOC_Ss):
1.6 kristaps 154: if (0 == sz)
155: return(mdoc_err(mdoc, tok, pos, ERR_ARGS_GE1));
156: break;
1.7 kristaps 157:
158: case (MDOC_Bd):
159: assert(mdoc->last);
1.9 kristaps 160: node = mdoc->last->parent;
161: /* LINTED */
162: for ( ; node; node = node->parent) {
1.7 kristaps 163: if (node->type != MDOC_BLOCK)
164: continue;
165: if (node->data.block.tok != MDOC_Bd)
166: continue;
167: return(mdoc_err(mdoc, tok, pos, ERR_SCOPE_NONEST));
168: }
169: break;
1.6 kristaps 170:
171: case (MDOC_Bl):
1.4 kristaps 172: break;
1.6 kristaps 173:
1.4 kristaps 174: /* ======= ADD MORE MACRO CHECKS ABOVE. ======= */
175: default:
176: abort();
177: /* NOTREACHED */
178: }
179:
1.6 kristaps 180: mdoc_block_alloc(mdoc, pos, tok, (size_t)argc, argv);
1.3 kristaps 181: mdoc_head_alloc(mdoc, pos, tok, (size_t)sz, _CC(args));
1.2 kristaps 182: mdoc_body_alloc(mdoc, pos, tok);
183: return(1);
184: }
185:
186:
1.1 kristaps 187: static int
1.10 ! kristaps 188: append_const(struct mdoc *mdoc, int tok,
! 189: int pos, int sz, char *args[])
! 190: {
! 191:
! 192: assert(sz >= 0);
! 193: args[sz] = NULL;
! 194:
! 195: switch (tok) {
! 196: /* ======= ADD MORE MACRO CHECKS BELOW. ======= */
! 197: case (MDOC_Bx):
! 198: /* FALLTHROUGH */
! 199: case (MDOC_Bsx):
! 200: /* FALLTHROUGH */
! 201: case (MDOC_Os):
! 202: /* FALLTHROUGH */
! 203: case (MDOC_Fx):
! 204: /* FALLTHROUGH */
! 205: case (MDOC_Nx):
! 206: assert(sz <= 1);
! 207: break;
! 208:
! 209: case (MDOC_Ux):
! 210: assert(0 == sz);
! 211: break;
! 212:
! 213: /* ======= ADD MORE MACRO CHECKS ABOVE. ======= */
! 214: default:
! 215: abort();
! 216: /* NOTREACHED */
! 217: }
! 218:
! 219: mdoc_elem_alloc(mdoc, pos, tok, 0, NULL, (size_t)sz, _CC(args));
! 220: return(1);
! 221: }
! 222:
! 223:
! 224: static int
1.3 kristaps 225: append_text(struct mdoc *mdoc, int tok,
226: int pos, int sz, char *args[])
1.1 kristaps 227: {
228:
1.3 kristaps 229: assert(sz >= 0);
1.2 kristaps 230: args[sz] = NULL;
231:
232: switch (tok) {
1.4 kristaps 233: /* ======= ADD MORE MACRO CHECKS BELOW. ======= */
1.7 kristaps 234: case (MDOC_Pp):
235: if (0 == sz)
236: break;
237: if ( ! mdoc_warn(mdoc, tok, pos, WARN_ARGS_EQ0))
238: return(0);
239: break;
240:
1.2 kristaps 241: case (MDOC_Ft):
242: /* FALLTHROUGH */
243: case (MDOC_Li):
244: /* FALLTHROUGH */
245: case (MDOC_Ms):
246: /* FALLTHROUGH */
247: case (MDOC_Pa):
248: /* FALLTHROUGH */
249: case (MDOC_Tn):
1.4 kristaps 250: if (0 < sz)
251: break;
252: if ( ! mdoc_warn(mdoc, tok, pos, WARN_ARGS_GE1))
1.1 kristaps 253: return(0);
1.4 kristaps 254: break;
1.7 kristaps 255:
1.2 kristaps 256: case (MDOC_Ar):
257: /* FALLTHROUGH */
258: case (MDOC_Cm):
259: /* FALLTHROUGH */
260: case (MDOC_Fl):
1.7 kristaps 261: /* These can have no arguments. */
1.4 kristaps 262: break;
1.7 kristaps 263:
1.2 kristaps 264: case (MDOC_Ad):
265: /* FALLTHROUGH */
266: case (MDOC_Em):
267: /* FALLTHROUGH */
268: case (MDOC_Er):
269: /* FALLTHROUGH */
270: case (MDOC_Ev):
271: /* FALLTHROUGH */
272: case (MDOC_Fa):
273: /* FALLTHROUGH */
274: case (MDOC_Dv):
275: /* FALLTHROUGH */
276: case (MDOC_Ic):
277: /* FALLTHROUGH */
278: case (MDOC_Va):
279: /* FALLTHROUGH */
280: case (MDOC_Vt):
1.4 kristaps 281: if (0 < sz)
282: break;
283: return(mdoc_err(mdoc, tok, pos, ERR_ARGS_GE1));
284: /* ======= ADD MORE MACRO CHECKS ABOVE. ======= */
1.2 kristaps 285: default:
1.4 kristaps 286: abort();
287: /* NOTREACHED */
1.2 kristaps 288: }
289:
1.7 kristaps 290: mdoc_elem_alloc(mdoc, pos, tok, 0, NULL, (size_t)sz, _CC(args));
1.4 kristaps 291: return(1);
1.2 kristaps 292: }
293:
1.1 kristaps 294:
1.2 kristaps 295: int
1.5 kristaps 296: macro_text(MACRO_PROT_ARGS)
1.2 kristaps 297: {
1.7 kristaps 298: int lastarg, lastpunct, c, j;
1.2 kristaps 299: char *args[MDOC_LINEARG_MAX], *p;
1.1 kristaps 300:
1.5 kristaps 301: if (SEC_PROLOGUE == mdoc->sec_lastn)
302: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
303:
1.7 kristaps 304: /* Token pre-processing. */
305:
306: switch (tok) {
307: case (MDOC_Pp):
308: /* `.Pp' ignored when following `.Sh' or `.Ss'. */
309: assert(mdoc->last);
310: if (MDOC_BODY != mdoc->last->type)
311: break;
312: switch (mdoc->last->data.body.tok) {
313: case (MDOC_Ss):
314: /* FALLTHROUGH */
315: case (MDOC_Sh):
316: if ( ! mdoc_warn(mdoc, tok, ppos, WARN_IGN_AFTER_BLK))
317: return(0);
318: return(1);
319: default:
320: break;
321: }
322: break;
323: default:
324: break;
325: }
326:
327: /* Process line parameters. */
328:
329: j = 0;
330: lastarg = ppos;
331: lastpunct = 0;
332:
1.2 kristaps 333: again:
1.7 kristaps 334: if (j == MDOC_LINEARG_MAX)
335: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
336:
337: /*
338: * Parse out the next argument, unquoted and unescaped. If
339: * we're a word (which may be punctuation followed eventually by
340: * a real word), then fall into checking for callables. If
341: * only punctuation remains and we're the first, then flush
342: * arguments, punctuation and exit; else, return to the caller.
343: */
344:
1.6 kristaps 345: lastarg = *pos;
1.2 kristaps 346:
1.7 kristaps 347: switch (mdoc_args(mdoc, tok, pos, buf, ARGS_DELIM, &args[j])) {
348: case (ARGS_ERROR):
1.2 kristaps 349: return(0);
1.7 kristaps 350: case (ARGS_WORD):
351: break;
352: case (ARGS_PUNCT):
353: if ( ! lastpunct && ! append_text(mdoc, tok, ppos, j, args))
354: return(0);
1.8 kristaps 355: if (ppos > 1)
356: return(1);
1.7 kristaps 357: return(append_delims(mdoc, tok, pos, buf));
358: case (ARGS_EOLN):
1.8 kristaps 359: if (lastpunct)
360: return(1);
1.7 kristaps 361: return(append_text(mdoc, tok, ppos, j, args));
362: default:
363: abort();
364: /* NOTREACHED */
365: }
1.2 kristaps 366:
1.7 kristaps 367: /*
368: * Command found. First flush out arguments, then call the
369: * command. If we're the line macro when it exits, flush
370: * terminal punctuation.
371: */
1.2 kristaps 372:
373: if (MDOC_MAX != (c = mdoc_find(mdoc, args[j]))) {
1.7 kristaps 374: if ( ! lastpunct && ! append_text(mdoc, tok, ppos, j, args))
375: return(0);
376: if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
377: return(0);
378: if (ppos > 1)
379: return(1);
380: return(append_delims(mdoc, tok, pos, buf));
1.2 kristaps 381: }
382:
1.7 kristaps 383: /* Word/non-term-punctuation found. */
1.2 kristaps 384:
1.4 kristaps 385: if ( ! mdoc_isdelim(args[j])) {
1.7 kristaps 386: /* Words are appended to the array of arguments. */
1.2 kristaps 387: j++;
1.8 kristaps 388: lastpunct = 0;
1.2 kristaps 389: goto again;
390: }
391:
1.7 kristaps 392: /*
393: * For punctuation, flush all collected words, then flush
394: * punctuation, then start collecting again. Of course, this
395: * is non-terminal punctuation.
396: */
1.2 kristaps 397:
1.7 kristaps 398: p = args[j];
399: if ( ! lastpunct && ! append_text(mdoc, tok, ppos, j, args))
400: return(0);
1.2 kristaps 401:
1.7 kristaps 402: mdoc_word_alloc(mdoc, lastarg, p);
403: j = 0;
1.2 kristaps 404: lastpunct = 1;
405:
406: goto again;
407: /* NOTREACHED */
408: }
1.1 kristaps 409:
410:
1.2 kristaps 411: int
1.5 kristaps 412: macro_prologue_dtitle(MACRO_PROT_ARGS)
413: {
1.7 kristaps 414: int lastarg, j;
1.5 kristaps 415: char *args[MDOC_LINEARG_MAX];
416:
417: if (SEC_PROLOGUE != mdoc->sec_lastn)
418: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_NPROLOGUE));
419: if (0 == mdoc->meta.date)
420: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_OO));
421: if (mdoc->meta.title[0])
422: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_REP));
423:
424: j = -1;
1.7 kristaps 425: lastarg = ppos;
1.5 kristaps 426:
427: again:
1.6 kristaps 428: if (j == MDOC_LINEARG_MAX)
429: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
1.5 kristaps 430:
1.7 kristaps 431: lastarg = *pos;
432:
433: switch (mdoc_args(mdoc, tok, pos, buf, 0, &args[++j])) {
434: case (ARGS_EOLN):
1.5 kristaps 435: if (mdoc->meta.title)
436: return(1);
437: if ( ! mdoc_warn(mdoc, tok, ppos, WARN_ARGS_GE1))
438: return(0);
439: (void)xstrlcpy(mdoc->meta.title,
440: "UNTITLED", META_TITLE_SZ);
441: return(1);
1.7 kristaps 442: case (ARGS_ERROR):
1.5 kristaps 443: return(0);
1.7 kristaps 444: default:
445: break;
446: }
447:
1.5 kristaps 448: if (MDOC_MAX != mdoc_find(mdoc, args[j]) && ! mdoc_warn
449: (mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE))
450: return(0);
451:
452: if (0 == j) {
453: if (xstrlcpy(mdoc->meta.title, args[0], META_TITLE_SZ))
454: goto again;
1.7 kristaps 455: return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
1.5 kristaps 456:
457: } else if (1 == j) {
458: mdoc->meta.msec = mdoc_atomsec(args[1]);
459: if (MSEC_DEFAULT != mdoc->meta.msec)
460: goto again;
1.7 kristaps 461: return(mdoc_err(mdoc, tok, -1, ERR_SYNTAX_ARGFORM));
1.5 kristaps 462:
463: } else if (2 == j) {
464: mdoc->meta.vol = mdoc_atovol(args[2]);
465: if (VOL_DEFAULT != mdoc->meta.vol)
466: goto again;
467: mdoc->meta.arch = mdoc_atoarch(args[2]);
468: if (ARCH_DEFAULT != mdoc->meta.arch)
469: goto again;
1.7 kristaps 470: return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
1.5 kristaps 471: }
472:
473: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
474: }
475:
476:
477: int
1.6 kristaps 478: macro_prologue_os(MACRO_PROT_ARGS)
479: {
1.7 kristaps 480: int lastarg, j;
1.6 kristaps 481: char *args[MDOC_LINEARG_MAX];
482:
483: if (SEC_PROLOGUE != mdoc->sec_lastn)
484: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_NPROLOGUE));
485: if (0 == mdoc->meta.title[0])
486: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_OO));
487: if (mdoc->meta.os[0])
488: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_REP));
489:
490: j = -1;
1.7 kristaps 491: lastarg = ppos;
1.6 kristaps 492:
493: again:
494: if (j == MDOC_LINEARG_MAX)
495: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
496:
1.7 kristaps 497: lastarg = *pos;
498:
499: switch (mdoc_args(mdoc, tok, pos, buf,
500: ARGS_QUOTED, &args[++j])) {
501: case (ARGS_EOLN):
1.6 kristaps 502: mdoc->sec_lastn = mdoc->sec_last = SEC_BODY;
503: return(1);
1.7 kristaps 504: case (ARGS_ERROR):
1.6 kristaps 505: return(0);
1.7 kristaps 506: default:
507: break;
508: }
1.6 kristaps 509:
510: if ( ! xstrlcat(mdoc->meta.os, args[j], sizeof(mdoc->meta.os)))
1.7 kristaps 511: return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
1.6 kristaps 512: if ( ! xstrlcat(mdoc->meta.os, " ", sizeof(mdoc->meta.os)))
1.7 kristaps 513: return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
1.6 kristaps 514:
515: goto again;
516: /* NOTREACHED */
517: }
518:
519:
520: int
1.5 kristaps 521: macro_prologue_ddate(MACRO_PROT_ARGS)
522: {
1.7 kristaps 523: int lastarg, j;
1.5 kristaps 524: char *args[MDOC_LINEARG_MAX], date[64];
525:
526: if (SEC_PROLOGUE != mdoc->sec_lastn)
527: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_NPROLOGUE));
528: if (mdoc->meta.title[0])
529: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_OO));
530: if (mdoc->meta.date)
531: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_REP));
532:
533: j = -1;
534: date[0] = 0;
1.7 kristaps 535: lastarg = ppos;
1.5 kristaps 536:
537: again:
1.6 kristaps 538: if (j == MDOC_LINEARG_MAX)
539: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
540:
1.7 kristaps 541: lastarg = *pos;
542: switch (mdoc_args(mdoc, tok, pos, buf, 0, &args[++j])) {
543: case (ARGS_EOLN):
1.5 kristaps 544: if (mdoc->meta.date)
545: return(1);
546: mdoc->meta.date = mdoc_atotime(date);
547: if (mdoc->meta.date)
548: return(1);
1.7 kristaps 549: return(mdoc_err(mdoc, tok, ppos, ERR_SYNTAX_ARGFORM));
550: case (ARGS_ERROR):
1.5 kristaps 551: return(0);
1.7 kristaps 552: default:
553: break;
554: }
1.5 kristaps 555:
556: if (MDOC_MAX != mdoc_find(mdoc, args[j]) && ! mdoc_warn
557: (mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE))
558: return(0);
559:
560: if (0 == j) {
561: if (xstrcmp("$Mdocdate$", args[j])) {
562: mdoc->meta.date = time(NULL);
563: goto again;
564: } else if (xstrcmp("$Mdocdate:", args[j]))
565: goto again;
566: } else if (4 == j)
567: if ( ! xstrcmp("$", args[j]))
568: goto again;
569:
570: if ( ! xstrlcat(date, args[j], sizeof(date)))
1.7 kristaps 571: return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
1.5 kristaps 572: if ( ! xstrlcat(date, " ", sizeof(date)))
1.7 kristaps 573: return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
1.5 kristaps 574:
575: goto again;
576: /* NOTREACHED */
577: }
578:
579:
580: int
1.6 kristaps 581: macro_scoped_explicit(MACRO_PROT_ARGS)
582: {
583: int c, lastarg, j;
584: struct mdoc_arg argv[MDOC_LINEARG_MAX];
1.7 kristaps 585: struct mdoc_node *n;
1.6 kristaps 586:
587: if (SEC_PROLOGUE == mdoc->sec_lastn)
588: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
589:
590: /*
591: * First close out the explicit scope. The `end' tags (such as
592: * `.El' to `.Bl' don't cause anything to happen: we merely
593: * readjust our last parse point.
594: */
595:
596: switch (tok) {
597: case (MDOC_El):
598: return(scope_rewind_exp(mdoc, ppos, tok, MDOC_Bl));
1.7 kristaps 599: case (MDOC_Ed):
600: return(scope_rewind_exp(mdoc, ppos, tok, MDOC_Bd));
1.6 kristaps 601: default:
602: break;
603: }
604:
605: assert(MDOC_EXPLICIT & mdoc_macros[tok].flags);
606:
1.7 kristaps 607: /* Token pre-processing. */
608:
609: switch (tok) {
610: case (MDOC_Bl):
611: /* FALLTHROUGH */
612: case (MDOC_Bd):
613: /* `.Pp' ignored when preceding `.Bl' or `.Bd'. */
614: assert(mdoc->last);
615: if (MDOC_ELEM != mdoc->last->type)
616: break;
617: if (MDOC_Pp != mdoc->last->data.elem.tok)
618: break;
619: if ( ! mdoc_warn(mdoc, tok, ppos, WARN_IGN_BEFORE_BLK))
620: return(0);
621: assert(mdoc->last->prev);
622: n = mdoc->last;
623: mdoc->last = mdoc->last->prev;
624: mdoc->last->next = NULL;
625: mdoc_node_free(n);
626: break;
627: default:
628: break;
629: }
630:
1.6 kristaps 631: lastarg = *pos;
632:
633: for (j = 0; j < MDOC_LINEARG_MAX; j++) {
634: lastarg = *pos;
1.7 kristaps 635: c = mdoc_argv(mdoc, tok, &argv[j], pos, buf);
1.6 kristaps 636: if (0 == c)
637: break;
638: else if (1 == c)
639: continue;
640:
641: mdoc_argv_free(j, argv);
642: return(0);
643: }
644:
645: if (MDOC_LINEARG_MAX == j) {
646: mdoc_argv_free(j, argv);
647: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
648: }
649:
650: c = append_scoped(mdoc, tok, ppos, 0, NULL, j, argv);
651: mdoc_argv_free(j, argv);
652: return(c);
653: }
654:
655:
1.8 kristaps 656: /*
657: * Implicity-scoped macros, like `.Ss', have a scope that terminates
658: * with a subsequent call to the same macro. Implicit macros cannot
659: * break the scope of explicitly-scoped macros; however, they can break
660: * the scope of other implicit macros (so `.Sh' can break `.Ss'). This
661: * is ok with macros like `.It' because they exist only within an
662: * explicit context.
663: *
664: * These macros put line arguments (which it's allowed to have) into the
665: * HEAD section and open a BODY scope to be used until the macro scope
666: * closes.
667: */
1.6 kristaps 668: int
1.5 kristaps 669: macro_scoped_implicit(MACRO_PROT_ARGS)
1.2 kristaps 670: {
1.7 kristaps 671: int lastarg, j;
1.2 kristaps 672: char *args[MDOC_LINEARG_MAX];
673: struct mdoc_node *n;
674:
1.5 kristaps 675: assert( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags));
1.1 kristaps 676:
1.5 kristaps 677: if (SEC_PROLOGUE == mdoc->sec_lastn)
678: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
1.1 kristaps 679:
1.7 kristaps 680: /* Token pre-processing. */
1.6 kristaps 681:
1.7 kristaps 682: switch (tok) {
683: case (MDOC_Ss):
684: /* FALLTHROUGH */
685: case (MDOC_Sh):
686: /* `.Pp' ignored when preceding `.Ss' or `.Sh'. */
687: if (NULL == mdoc->last)
688: break;
689: if (MDOC_ELEM != mdoc->last->type)
690: break;
691: if (MDOC_Pp != mdoc->last->data.elem.tok)
1.1 kristaps 692: break;
1.7 kristaps 693: if ( ! mdoc_warn(mdoc, tok, ppos, WARN_IGN_BEFORE_BLK))
694: return(0);
695: assert(mdoc->last->prev);
696: n = mdoc->last;
1.8 kristaps 697: mdoc_msg(mdoc, ppos, "removing prior `Pp' macro");
1.7 kristaps 698: mdoc->last = mdoc->last->prev;
699: mdoc->last->next = NULL;
700: mdoc_node_free(n);
701: break;
702: default:
703: break;
1.2 kristaps 704: }
705:
1.8 kristaps 706: /* Rewind our scope. */
707:
708: if ( ! scope_rewind_imp(mdoc, ppos, tok))
709: return(0);
1.2 kristaps 710:
711: j = 0;
1.7 kristaps 712: lastarg = ppos;
1.2 kristaps 713:
1.8 kristaps 714: /*
715: * Process until we hit a line. Note that current implicit
716: * macros don't have any arguments, so we don't need to do any
717: * argument processing.
718: */
719:
1.2 kristaps 720: again:
1.7 kristaps 721: if (j == MDOC_LINEARG_MAX)
722: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
723:
1.6 kristaps 724: lastarg = *pos;
1.2 kristaps 725:
1.7 kristaps 726: switch (mdoc_args(mdoc, tok, pos, buf, 0, &args[j])) {
727: case (ARGS_ERROR):
1.2 kristaps 728: return(0);
1.7 kristaps 729: case (ARGS_EOLN):
730: return(append_scoped(mdoc, tok, ppos, j, _CC(args), 0, NULL));
731: default:
732: break;
733: }
1.1 kristaps 734:
1.7 kristaps 735: if (MDOC_MAX != mdoc_find(mdoc, args[j]))
1.3 kristaps 736: if ( ! mdoc_warn(mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE))
1.1 kristaps 737: return(0);
738:
1.2 kristaps 739: j++;
740: goto again;
1.8 kristaps 741: /* NOTREACHED */
742: }
743:
744:
745: /*
746: * A line-scoped macro opens a scope for the contents of its line, which
747: * are placed under the HEAD node. Punctuation trailing the line is put
748: * as a sibling to the HEAD node, under the BLOCK node.
749: */
750: int
751: macro_scoped_line(MACRO_PROT_ARGS)
752: {
753: int lastarg, c, j;
754: char *p;
755: struct mdoc_node *n;
756:
757: if (SEC_PROLOGUE == mdoc->sec_lastn)
758: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
759:
760: assert(1 == ppos);
761:
762: /* Token pre-processing. */
763:
764: switch (tok) {
765: case (MDOC_D1):
766: /* FALLTHROUGH */
767: case (MDOC_Dl):
768: /* These can't be nested in a display block. */
769: assert(mdoc->last);
770: for (n = mdoc->last->parent ; n; n = n->parent)
771: if (MDOC_BLOCK != n->type)
772: continue;
773: else if (MDOC_Bd == n->data.block.tok)
774: break;
775: if (NULL == n)
776: break;
777: return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_NONEST));
778: default:
779: break;
780: }
781:
782: /*
783: * All line-scoped macros have a HEAD and optionally a BODY
784: * section. We open our scope here; when we exit this function,
785: * we'll rewind our scope appropriately.
786: */
787:
788: mdoc_block_alloc(mdoc, ppos, tok, 0, NULL);
789: mdoc_head_alloc(mdoc, ppos, tok, 0, NULL);
790:
791: /* Process line parameters. */
792:
793: j = 0;
794: lastarg = ppos;
795:
796: again:
797: if (j == MDOC_LINEARG_MAX)
798: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
799:
800: lastarg = *pos;
801: c = mdoc_args(mdoc, tok, pos, buf, ARGS_DELIM, &p);
802:
803: switch (c) {
804: case (ARGS_ERROR):
805: return(0);
806: case (ARGS_WORD):
807: break;
808: case (ARGS_PUNCT):
809: if ( ! append_delims(mdoc, tok, pos, buf))
810: return(0);
811: return(scope_rewind_imp(mdoc, ppos, tok));
812: case (ARGS_EOLN):
813: return(scope_rewind_imp(mdoc, ppos, tok));
814: default:
815: abort();
816: /* NOTREACHED */
817: }
818:
819: if (MDOC_MAX != (c = mdoc_find(mdoc, p))) {
820: if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
821: return(0);
822: if ( ! append_delims(mdoc, tok, pos, buf))
823: return(0);
824: return(scope_rewind_imp(mdoc, ppos, tok));
825: }
1.1 kristaps 826:
1.8 kristaps 827: if (mdoc_isdelim(p))
828: j = 0;
829:
830: mdoc_word_alloc(mdoc, lastarg, p);
831: goto again;
1.2 kristaps 832: /* NOTREACHED */
1.1 kristaps 833: }
1.5 kristaps 834:
1.7 kristaps 835:
1.9 kristaps 836: /*
837: * Partial-line scope is identical to line scope (macro_scoped_line())
838: * except that trailing punctuation is appended to the BLOCK, instead of
839: * contained within the HEAD.
840: */
1.7 kristaps 841: int
1.8 kristaps 842: macro_scoped_pline(MACRO_PROT_ARGS)
1.7 kristaps 843: {
1.8 kristaps 844: int lastarg, c, j;
845: char *p;
1.7 kristaps 846:
1.8 kristaps 847: if (SEC_PROLOGUE == mdoc->sec_lastn)
848: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
849:
850: /* Token pre-processing. */
851:
852: switch (tok) {
1.9 kristaps 853: case (MDOC_Ql):
854: if ( ! mdoc_warn(mdoc, tok, ppos, WARN_COMPAT_TROFF))
855: return(0);
856: break;
1.8 kristaps 857: default:
858: break;
859: }
860:
861: mdoc_block_alloc(mdoc, ppos, tok, 0, NULL);
862: mdoc_head_alloc(mdoc, ppos, tok, 0, NULL);
863:
864: /* Process line parameters. */
865:
866: j = 0;
867: lastarg = ppos;
868:
869: again:
870: if (j == MDOC_LINEARG_MAX)
871: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
872:
873: lastarg = *pos;
874: c = mdoc_args(mdoc, tok, pos, buf, ARGS_DELIM, &p);
875:
876: switch (c) {
877: case (ARGS_ERROR):
878: return(0);
879: case (ARGS_WORD):
880: break;
881: case (ARGS_PUNCT):
882: if ( ! scope_rewind_imp(mdoc, ppos, tok))
883: return(0);
884: if (ppos > 1)
885: return(1);
886: return(append_delims(mdoc, tok, pos, buf));
887: case (ARGS_EOLN):
888: return(scope_rewind_imp(mdoc, ppos, tok));
889: default:
890: abort();
891: /* NOTREACHED */
892: }
893:
894: if (MDOC_MAX != (c = mdoc_find(mdoc, p))) {
895: if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
896: return(0);
897: if ( ! scope_rewind_imp(mdoc, ppos, tok))
898: return(0);
899: if (ppos > 1)
900: return(1);
901: return(append_delims(mdoc, tok, pos, buf));
902: }
903:
904: if (mdoc_isdelim(p))
905: j = 0;
906:
907: mdoc_word_alloc(mdoc, lastarg, p);
908: goto again;
909: /* NOTREACHED */
1.7 kristaps 910: }
1.8 kristaps 911:
1.10 ! kristaps 912:
! 913: /*
! 914: * A delimited-constant macro is similar to a general text macro: the
! 915: * macro is followed by a 0 or 1 arguments (possibly-unspecified) then
! 916: * terminating punctuation, other words, or another callable macro.
! 917: */
! 918: int
! 919: macro_constant_delimited(MACRO_PROT_ARGS)
! 920: {
! 921: int lastarg, flushed, c, maxargs;
! 922: char *p, *pp;
! 923:
! 924: if (SEC_PROLOGUE == mdoc->sec_lastn)
! 925: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
! 926:
! 927: /* Process line parameters. */
! 928:
! 929: lastarg = ppos;
! 930: flushed = 0;
! 931:
! 932: switch (tok) {
! 933: case (MDOC_Ux):
! 934: maxargs = 0;
! 935: break;
! 936: default:
! 937: maxargs = 1;
! 938: break;
! 939: }
! 940:
! 941: again:
! 942: lastarg = *pos;
! 943:
! 944: switch (mdoc_args(mdoc, tok, pos, buf, ARGS_DELIM, &p)) {
! 945: case (ARGS_ERROR):
! 946: return(0);
! 947: case (ARGS_WORD):
! 948: break;
! 949: case (ARGS_PUNCT):
! 950: if ( ! flushed && ! append_const(mdoc, tok, ppos, 0, &p))
! 951: return(0);
! 952: if (ppos > 1)
! 953: return(1);
! 954: return(append_delims(mdoc, tok, pos, buf));
! 955: case (ARGS_EOLN):
! 956: if (flushed)
! 957: return(1);
! 958: return(append_const(mdoc, tok, ppos, 0, &p));
! 959: default:
! 960: abort();
! 961: /* NOTREACHED */
! 962: }
! 963:
! 964: if (0 == maxargs) {
! 965: pp = p;
! 966: if ( ! append_const(mdoc, tok, ppos, 0, &p))
! 967: return(0);
! 968: p = pp;
! 969: flushed = 1;
! 970: }
! 971:
! 972: if (MDOC_MAX != (c = mdoc_find(mdoc, p))) {
! 973: if ( ! flushed && ! append_const(mdoc, tok, ppos, 0, &p))
! 974: return(0);
! 975: if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
! 976: return(0);
! 977: if (ppos > 1)
! 978: return(1);
! 979: return(append_delims(mdoc, tok, pos, buf));
! 980: }
! 981:
! 982: if ( ! flushed && ! mdoc_isdelim(p)) {
! 983: if ( ! append_const(mdoc, tok, ppos, 1, &p))
! 984: return(0);
! 985: flushed = 1;
! 986: goto again;
! 987: } else if ( ! flushed) {
! 988: pp = p;
! 989: if ( ! append_const(mdoc, tok, ppos, 0, &p))
! 990: return(0);
! 991: p = pp;
! 992: flushed = 1;
! 993: }
! 994:
! 995: mdoc_word_alloc(mdoc, lastarg, p);
! 996: goto again;
! 997: /* NOTREACHED */
! 998: }
CVSweb