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