Annotation of mandoc/macro.c, Revision 1.21
1.21 ! kristaps 1: /* $Id: macro.c,v 1.20 2009/01/05 12:23:17 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.19 kristaps 32: static int rewind_elem(struct mdoc *, int, int);
33: static int rewind_imp(struct mdoc *, int, int);
34: static int rewind_exp(struct mdoc *, int, int, int);
35: static int rewind_line(struct mdoc *, int, int);
36: static int append_delims(struct mdoc *, int, int *, char *);
37:
38:
39: static int
40: rewind_elem(struct mdoc *mdoc, int ppos, int tok)
41: {
42: struct mdoc_node *n;
1.2 kristaps 43:
1.19 kristaps 44: n = mdoc->last;
45: if (MDOC_ELEM != n->type)
46: n = n->parent;
47: assert(MDOC_ELEM == n->type);
48: assert(tok == n->data.elem.tok);
49:
50: mdoc->last = n;
51: mdoc->next = MDOC_NEXT_SIBLING;
1.21 ! kristaps 52: if ( ! mdoc_valid_post(mdoc, tok, ppos))
! 53: return(0);
! 54: return(mdoc_action(mdoc, tok, ppos));
1.19 kristaps 55: }
1.6 kristaps 56:
57:
58: static int
1.19 kristaps 59: rewind_line(struct mdoc *mdoc, int ppos, int tok)
1.6 kristaps 60: {
61: struct mdoc_node *n;
1.7 kristaps 62: int t;
63:
1.6 kristaps 64: /* LINTED */
1.16 kristaps 65: for (n = mdoc->last; n; n = n->parent) {
66: if (MDOC_HEAD != n->type)
1.6 kristaps 67: continue;
1.16 kristaps 68: if (tok == (t = n->data.head.tok))
1.6 kristaps 69: break;
1.7 kristaps 70: if ( ! (MDOC_EXPLICIT & mdoc_macros[t].flags))
71: continue;
1.6 kristaps 72: return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_BREAK));
73: }
74:
1.16 kristaps 75: mdoc->last = n ? n : mdoc->last;
76: mdoc->next = MDOC_NEXT_SIBLING;
1.21 ! kristaps 77: /* XXX - no validation, we do this only for blocks/elements. */
1.6 kristaps 78: return(1);
79: }
80:
81:
82: static int
1.19 kristaps 83: rewind_exp(struct mdoc *mdoc, int ppos, int tok, int tt)
1.6 kristaps 84: {
1.7 kristaps 85: struct mdoc_node *n;
1.6 kristaps 86:
1.7 kristaps 87: assert(mdoc->last);
1.6 kristaps 88:
1.7 kristaps 89: /* LINTED */
90: for (n = mdoc->last->parent; n; n = n->parent) {
91: if (MDOC_BLOCK != n->type)
92: continue;
1.16 kristaps 93: if (tt == n->data.block.tok)
94: break;
95: return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_BREAK));
96: }
97:
98: if (NULL == (mdoc->last = n))
99: return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_NOCTX));
100:
101: mdoc->next = MDOC_NEXT_SIBLING;
1.21 ! kristaps 102: if ( ! mdoc_valid_post(mdoc, tok, ppos))
! 103: return(0);
! 104: return(mdoc_action(mdoc, tok, ppos));
! 105: }
! 106:
! 107:
! 108: static int
! 109: rewind_imp(struct mdoc *mdoc, int ppos, int tok)
! 110: {
! 111: struct mdoc_node *n;
! 112: int t;
! 113:
! 114: n = mdoc->last ? mdoc->last->parent : NULL;
! 115:
! 116: /* LINTED */
! 117: for ( ; n; n = n->parent) {
! 118: if (MDOC_BLOCK != n->type)
! 119: continue;
! 120: if (tok == (t = n->data.block.tok))
! 121: break;
! 122: if ( ! (MDOC_EXPLICIT & mdoc_macros[t].flags))
! 123: continue;
! 124: return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_BREAK));
! 125: }
! 126:
! 127: mdoc->last = n ? n : mdoc->last;
! 128: mdoc->next = MDOC_NEXT_SIBLING;
! 129: if ( ! mdoc_valid_post(mdoc, tok, ppos))
! 130: return(0);
! 131: return(mdoc_action(mdoc, tok, ppos));
1.16 kristaps 132: }
133:
134:
1.19 kristaps 135: /* ARGSUSED */
136: int
137: macro_close_explicit(MACRO_PROT_ARGS)
138: {
139: int tt;
140:
141: switch (tok) {
142: case (MDOC_El):
143: tt = MDOC_Bl;
144: break;
145: case (MDOC_Ed):
146: tt = MDOC_Bd;
147: break;
148: case (MDOC_Re):
149: tt = MDOC_Rs;
150: break;
151: case (MDOC_Ef):
152: tt = MDOC_Bf;
153: break;
154: default:
155: abort();
156: /* NOTREACHED */
157: }
158:
159: if (0 != buf[*pos])
160: return(mdoc_err(mdoc, tok, ppos, ERR_ARGS_EQ0));
1.20 kristaps 161: return(rewind_exp(mdoc, ppos, tok, tt));
1.19 kristaps 162: }
163:
164:
1.16 kristaps 165: static int
1.15 kristaps 166: append_delims(struct mdoc *mdoc, int tok, int *pos, char *buf)
167: {
168: int c, lastarg;
169: char *p;
170:
171: if (0 == buf[*pos])
172: return(1);
173:
174: for (;;) {
175: lastarg = *pos;
176: c = mdoc_args(mdoc, tok, pos, buf, 0, &p);
177: if (ARGS_ERROR == c)
178: return(0);
179: else if (ARGS_EOLN == c)
180: break;
181: assert(mdoc_isdelim(p));
182: mdoc_word_alloc(mdoc, lastarg, p);
1.16 kristaps 183: mdoc->next = MDOC_NEXT_SIBLING;
1.15 kristaps 184: }
1.2 kristaps 185:
1.1 kristaps 186: return(1);
187: }
188:
1.2 kristaps 189:
1.19 kristaps 190: /*
191: * A general text domain macro. When invoked, this opens a scope that
192: * accepts words until either end-of-line, only-punctuation, or a
193: * callable macro. If the word is punctuation (not only-punctuation),
194: * then the scope is closed out, the punctuation appended, then the
195: * scope opened again. If any terminating conditions are met, the scope
196: * is closed out. If this is the first macro in the line and
197: * only-punctuation remains, this punctuation is flushed.
198: */
199: int
200: macro_text(MACRO_PROT_ARGS)
1.13 kristaps 201: {
1.19 kristaps 202: int lastarg, lastpunct, c, sz, fl, argc;
203: struct mdoc_arg argv[MDOC_LINEARG_MAX];
204: char *p;
1.13 kristaps 205:
1.19 kristaps 206: lastarg = ppos;
207: lastpunct = 0;
1.17 kristaps 208:
1.19 kristaps 209: for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
210: lastarg = *pos;
1.17 kristaps 211:
1.19 kristaps 212: c = mdoc_argv(mdoc, tok, &argv[argc], pos, buf);
213: if (ARGV_EOLN == c || ARGV_WORD == c)
214: break;
215: else if (ARGV_ARG == c)
216: continue;
217: mdoc_argv_free(argc, argv);
1.14 kristaps 218: return(0);
1.10 kristaps 219: }
220:
1.19 kristaps 221: if ( ! mdoc_valid_pre(mdoc, tok, ppos, argc, argv)) {
222: mdoc_argv_free(argc, argv);
223: return(0);
1.7 kristaps 224: }
225:
1.15 kristaps 226: fl = ARGS_DELIM;
227: if (MDOC_QUOTABLE & mdoc_macros[tok].flags)
228: fl |= ARGS_QUOTED;
1.7 kristaps 229:
1.19 kristaps 230: mdoc_elem_alloc(mdoc, lastarg, tok, argc, argv);
231: mdoc->next = MDOC_NEXT_CHILD;
1.7 kristaps 232:
1.19 kristaps 233: for (lastpunct = sz = 0; sz + argc < MDOC_LINEARG_MAX; sz++) {
234: lastarg = *pos;
1.7 kristaps 235:
1.19 kristaps 236: if (lastpunct) {
237: mdoc_elem_alloc(mdoc, lastarg, tok, argc, argv);
238: mdoc->next = MDOC_NEXT_CHILD;
239: lastpunct = 0;
240: }
1.2 kristaps 241:
1.19 kristaps 242: c = mdoc_args(mdoc, tok, pos, buf, fl, &p);
243: if (ARGS_ERROR == c) {
244: mdoc_argv_free(argc, argv);
1.7 kristaps 245: return(0);
1.19 kristaps 246: }
247:
248: if (ARGS_EOLN == c)
249: break;
250: if (ARGS_PUNCT == c)
251: break;
1.2 kristaps 252:
1.19 kristaps 253: if (MDOC_MAX != (c = mdoc_find(mdoc, p))) {
254: if ( ! rewind_elem(mdoc, ppos, tok)) {
255: mdoc_argv_free(argc, argv);
256: return(0);
257: }
258: mdoc_argv_free(argc, argv);
259: if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
260: return(0);
261: if (ppos > 1)
262: return(1);
263: return(append_delims(mdoc, tok, pos, buf));
264: }
1.2 kristaps 265:
1.19 kristaps 266: if (mdoc_isdelim(p)) {
267: if ( ! rewind_elem(mdoc, ppos, tok)) {
268: mdoc_argv_free(argc, argv);
269: return(0);
270: }
271: lastpunct = 1;
272: }
273: mdoc_word_alloc(mdoc, lastarg, p);
274: mdoc->next = MDOC_NEXT_SIBLING;
1.2 kristaps 275: }
276:
1.19 kristaps 277: mdoc_argv_free(argc, argv);
1.2 kristaps 278:
1.19 kristaps 279: if (sz == MDOC_LINEARG_MAX)
280: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
1.2 kristaps 281:
1.19 kristaps 282: if ( ! rewind_elem(mdoc, ppos, tok))
1.7 kristaps 283: return(0);
1.19 kristaps 284: if (ppos > 1)
285: return(1);
286: return(append_delims(mdoc, tok, pos, buf));
1.5 kristaps 287: }
288:
289:
1.19 kristaps 290: /*
291: * Multi-line-scoped macro.
292: */
1.5 kristaps 293: int
1.16 kristaps 294: macro_scoped(MACRO_PROT_ARGS)
1.6 kristaps 295: {
1.19 kristaps 296: int c, lastarg, argc;
1.6 kristaps 297: struct mdoc_arg argv[MDOC_LINEARG_MAX];
298:
1.16 kristaps 299: assert ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags));
1.6 kristaps 300:
1.19 kristaps 301: if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags))
302: if ( ! rewind_imp(mdoc, ppos, tok))
1.16 kristaps 303: return(0);
1.2 kristaps 304:
1.19 kristaps 305: lastarg = ppos;
1.8 kristaps 306:
1.16 kristaps 307: for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
308: lastarg = *pos;
309: c = mdoc_argv(mdoc, tok, &argv[argc], pos, buf);
310: if (ARGV_EOLN == c || ARGV_WORD == c)
311: break;
312: else if (ARGV_ARG == c)
313: continue;
314: mdoc_argv_free(argc, argv);
1.8 kristaps 315: return(0);
1.16 kristaps 316: }
1.2 kristaps 317:
1.19 kristaps 318: if ( ! mdoc_valid_pre(mdoc, tok, ppos, argc, argv)) {
1.16 kristaps 319: mdoc_argv_free(argc, argv);
320: return(0);
321: }
1.8 kristaps 322:
1.19 kristaps 323: mdoc_block_alloc(mdoc, ppos, tok, (size_t)argc, argv);
324: mdoc->next = MDOC_NEXT_CHILD;
325:
326: mdoc_argv_free(argc, argv);
327:
328: /* XXX - Assumes header isn't parsed! */
329:
330: if (0 != buf[*pos]) {
331: mdoc_head_alloc(mdoc, ppos, tok);
332: mdoc->next = MDOC_NEXT_CHILD;
333:
334: mdoc_word_alloc(mdoc, lastarg, &buf[*pos]);
335: mdoc->next = MDOC_NEXT_SIBLING;
1.7 kristaps 336:
1.19 kristaps 337: if ( ! rewind_line(mdoc, ppos, tok))
338: return(0);
1.2 kristaps 339:
1.19 kristaps 340: while (buf[*pos])
341: (*pos)++;
1.7 kristaps 342: }
1.1 kristaps 343:
1.19 kristaps 344: #if 0
345: /* Post-processing. */
1.8 kristaps 346: switch (tok) {
1.16 kristaps 347: case (MDOC_Sh):
348: sec = mdoc_atosec((size_t)sz, _CC(args));
349: if (SEC_CUSTOM != sec)
350: mdoc->sec_lastn = sec;
351: mdoc->sec_last = sec;
352: break;
1.8 kristaps 353: default:
354: break;
355: }
1.19 kristaps 356: #endif
1.8 kristaps 357:
1.16 kristaps 358: mdoc_body_alloc(mdoc, ppos, tok);
359: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 360:
1.16 kristaps 361: return(1);
1.1 kristaps 362: }
1.5 kristaps 363:
1.7 kristaps 364:
1.19 kristaps 365: /*
366: * When scoped to a line, a macro encompasses all of the contents. This
367: * differs from constants or text macros, where a new macro will
368: * terminate the existing context.
369: */
1.7 kristaps 370: int
1.16 kristaps 371: macro_scoped_line(MACRO_PROT_ARGS)
1.7 kristaps 372: {
1.8 kristaps 373: int lastarg, c, j;
374: char *p;
1.7 kristaps 375:
1.16 kristaps 376: mdoc_block_alloc(mdoc, ppos, tok, 0, NULL);
377: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 378:
1.16 kristaps 379: mdoc_head_alloc(mdoc, ppos, tok);
380: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 381:
1.19 kristaps 382: /* XXX - no known argument macros. */
383:
384: if ( ! mdoc_valid_pre(mdoc, tok, ppos, 0, NULL))
1.16 kristaps 385: return(0);
1.8 kristaps 386:
387: /* Process line parameters. */
388:
1.19 kristaps 389: for (lastarg = ppos, j = 0; j < MDOC_LINEARG_MAX; j++) {
390: lastarg = *pos;
391: c = mdoc_args(mdoc, tok, pos, buf, ARGS_DELIM, &p);
1.8 kristaps 392:
1.19 kristaps 393: if (ARGS_ERROR == c)
394: return(0);
395: if (ARGS_PUNCT == c)
396: break;
397: if (ARGS_EOLN == c)
398: break;
1.8 kristaps 399:
1.19 kristaps 400: if (MDOC_MAX == (c = mdoc_find(mdoc, p))) {
401: mdoc_word_alloc(mdoc, lastarg, p);
402: mdoc->next = MDOC_NEXT_SIBLING;
403: continue;
404: }
1.8 kristaps 405:
1.19 kristaps 406: if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
407: return(0);
1.8 kristaps 408: break;
409: }
410:
1.19 kristaps 411: if (j == MDOC_LINEARG_MAX)
412: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
413:
414: if (1 == ppos) {
415: if ( ! rewind_line(mdoc, ppos, tok))
1.16 kristaps 416: return(0);
417: if ( ! append_delims(mdoc, tok, pos, buf))
1.8 kristaps 418: return(0);
419: }
1.19 kristaps 420: return(rewind_imp(mdoc, ppos, tok));
1.7 kristaps 421: }
1.8 kristaps 422:
1.10 kristaps 423:
1.19 kristaps 424: /*
425: * Delimited macros are like text macros except that, should punctuation
426: * be encountered, the macro isn't re-started with remaining tokens
427: * (it's only emitted once). Delimited macros can have a maximum number
428: * of arguments.
1.17 kristaps 429: */
1.10 kristaps 430: int
431: macro_constant_delimited(MACRO_PROT_ARGS)
432: {
1.19 kristaps 433: int lastarg, flushed, j, c, maxargs;
1.13 kristaps 434: char *p;
1.10 kristaps 435:
436: lastarg = ppos;
437: flushed = 0;
438:
439: switch (tok) {
1.16 kristaps 440: case (MDOC_No):
441: /* FALLTHROUGH */
442: case (MDOC_Ns):
443: /* FALLTHROUGH */
1.10 kristaps 444: case (MDOC_Ux):
445: maxargs = 0;
446: break;
447: default:
448: maxargs = 1;
449: break;
450: }
451:
1.19 kristaps 452: mdoc_elem_alloc(mdoc, lastarg, tok, 0, NULL);
453: mdoc->next = MDOC_NEXT_CHILD;
1.10 kristaps 454:
1.19 kristaps 455: for (j = 0; j < MDOC_LINEARG_MAX; j++) {
456: lastarg = *pos;
1.10 kristaps 457:
1.19 kristaps 458: if (j == maxargs && ! flushed) {
459: if ( ! rewind_elem(mdoc, ppos, tok))
460: return(0);
461: flushed = 1;
462: }
1.11 kristaps 463:
1.19 kristaps 464: c = mdoc_args(mdoc, tok, pos, buf, ARGS_DELIM, &p);
465: if (ARGS_ERROR == c)
1.10 kristaps 466: return(0);
1.19 kristaps 467: if (ARGS_PUNCT == c)
468: break;
469: if (ARGS_EOLN == c)
470: break;
471:
472: if (MDOC_MAX != (c = mdoc_find(mdoc, p))) {
473: if ( ! flushed && ! rewind_elem(mdoc, ppos, tok))
474: return(0);
475: flushed = 1;
476: if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
477: return(0);
478: break;
479: }
1.10 kristaps 480:
1.19 kristaps 481: if (mdoc_isdelim(p)) {
482: if ( ! rewind_elem(mdoc, ppos, tok))
483: return(0);
484: flushed = 1;
485: }
486:
487: mdoc_word_alloc(mdoc, lastarg, p);
488: mdoc->next = MDOC_NEXT_SIBLING;
1.10 kristaps 489: }
490:
1.19 kristaps 491: if ( ! flushed && rewind_elem(mdoc, ppos, tok))
492: return(0);
1.11 kristaps 493:
1.19 kristaps 494: if (MDOC_LINEARG_MAX == j)
495: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
1.10 kristaps 496:
1.19 kristaps 497: if (ppos > 1)
498: return(1);
499: return(append_delims(mdoc, tok, pos, buf));
1.10 kristaps 500: }
1.11 kristaps 501:
502:
1.19 kristaps 503: /*
504: * Constant macros span an entire line: they constitute a macro and all
505: * of its arguments and child data.
506: */
1.11 kristaps 507: int
508: macro_constant(MACRO_PROT_ARGS)
509: {
1.19 kristaps 510: int c, lastarg, argc, sz, fl;
511: struct mdoc_arg argv[MDOC_LINEARG_MAX];
512: char *p;
1.11 kristaps 513:
1.16 kristaps 514: fl = 0;
1.15 kristaps 515: if (MDOC_QUOTABLE & mdoc_macros[tok].flags)
516: fl = ARGS_QUOTED;
1.11 kristaps 517:
1.16 kristaps 518: for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
519: lastarg = *pos;
520: c = mdoc_argv(mdoc, tok, &argv[argc], pos, buf);
521: if (ARGV_EOLN == c)
522: break;
523: else if (ARGV_ARG == c)
524: continue;
525: else if (ARGV_WORD == c)
526: break;
1.11 kristaps 527:
1.16 kristaps 528: mdoc_argv_free(argc, argv);
1.11 kristaps 529: return(0);
530: }
531:
1.16 kristaps 532: if (MDOC_LINEARG_MAX == argc) {
533: mdoc_argv_free(argc, argv);
534: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
535: }
1.11 kristaps 536:
1.19 kristaps 537: mdoc_elem_alloc(mdoc, ppos, tok, argc, argv);
538: mdoc->next = MDOC_NEXT_CHILD;
539:
540: mdoc_argv_free(argc, argv);
541:
1.16 kristaps 542: for (sz = 0; sz + argc < MDOC_LINEARG_MAX; sz++) {
1.13 kristaps 543: lastarg = *pos;
1.19 kristaps 544: c = mdoc_args(mdoc, tok, pos, buf, fl, &p);
1.16 kristaps 545: if (ARGS_ERROR == c)
546: return(0);
547: if (ARGS_EOLN == c)
1.13 kristaps 548: break;
1.19 kristaps 549:
550: mdoc_word_alloc(mdoc, lastarg, p);
1.21 ! kristaps 551: mdoc->next = MDOC_NEXT_SIBLING;
1.13 kristaps 552: }
553:
1.19 kristaps 554: if (MDOC_LINEARG_MAX == sz + argc)
1.13 kristaps 555: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
556:
1.19 kristaps 557: return(rewind_elem(mdoc, ppos, tok));
1.13 kristaps 558: }
1.15 kristaps 559:
560:
1.16 kristaps 561: /* ARGSUSED */
1.15 kristaps 562: int
563: macro_obsolete(MACRO_PROT_ARGS)
564: {
565:
566: return(mdoc_warn(mdoc, tok, ppos, WARN_IGN_OBSOLETE));
567: }
CVSweb