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