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