Annotation of mandoc/macro.c, Revision 1.18
1.18 ! kristaps 1: /* $Id: macro.c,v 1.17 2009/01/02 14:06:16 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.16 kristaps 34: static int scope_rewind_imp(struct mdoc *, int, int);
1.6 kristaps 35: static int scope_rewind_exp(struct mdoc *, int, int, int);
1.16 kristaps 36: static int scope_rewind_line(struct mdoc *, int, int);
1.3 kristaps 37: static int append_text(struct mdoc *, int,
38: int, int, char *[]);
1.16 kristaps 39: static int append_text_argv(struct mdoc *, int, int,
40: int, 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.16 kristaps 45: scope_rewind_line(struct mdoc *mdoc, int ppos, int tok)
1.6 kristaps 46: {
47: struct mdoc_node *n;
1.7 kristaps 48: int t;
49:
1.6 kristaps 50: /* LINTED */
1.16 kristaps 51: for (n = mdoc->last; n; n = n->parent) {
52: if (MDOC_HEAD != n->type)
1.6 kristaps 53: continue;
1.16 kristaps 54: if (tok == (t = n->data.head.tok))
1.6 kristaps 55: break;
1.7 kristaps 56: if ( ! (MDOC_EXPLICIT & mdoc_macros[t].flags))
57: continue;
1.6 kristaps 58: return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_BREAK));
59: }
60:
1.16 kristaps 61: mdoc->last = n ? n : mdoc->last;
62: mdoc->next = MDOC_NEXT_SIBLING;
1.6 kristaps 63: return(1);
64: }
65:
66:
67: static int
1.16 kristaps 68: scope_rewind_exp(struct mdoc *mdoc, int ppos, int tok, int tt)
1.6 kristaps 69: {
1.7 kristaps 70: struct mdoc_node *n;
1.6 kristaps 71:
1.7 kristaps 72: assert(mdoc->last);
1.6 kristaps 73:
1.7 kristaps 74: /* LINTED */
75: for (n = mdoc->last->parent; n; n = n->parent) {
76: if (MDOC_BLOCK != n->type)
77: continue;
1.16 kristaps 78: if (tt == n->data.block.tok)
79: break;
80: return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_BREAK));
81: }
82:
83: if (NULL == (mdoc->last = n))
84: return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_NOCTX));
85:
86: mdoc->next = MDOC_NEXT_SIBLING;
87: return(mdoc_valid_post(mdoc, tok, ppos));
88: }
89:
90:
91: static int
92: scope_rewind_imp(struct mdoc *mdoc, int ppos, int tok)
93: {
94: struct mdoc_node *n;
95: int t;
96:
97: n = mdoc->last ? mdoc->last->parent : NULL;
98:
99: /* LINTED */
100: for ( ; n; n = n->parent) {
101: if (MDOC_BLOCK != n->type)
102: continue;
103: if (tok == (t = n->data.block.tok))
1.7 kristaps 104: break;
1.16 kristaps 105: if ( ! (MDOC_EXPLICIT & mdoc_macros[t].flags))
106: continue;
1.7 kristaps 107: return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_BREAK));
1.6 kristaps 108: }
109:
1.16 kristaps 110: mdoc->last = n ? n : mdoc->last;
111: mdoc->next = MDOC_NEXT_SIBLING;
112: return(mdoc_valid_post(mdoc, tok, ppos));
1.15 kristaps 113: }
1.6 kristaps 114:
1.15 kristaps 115:
116: static int
117: append_delims(struct mdoc *mdoc, int tok, int *pos, char *buf)
118: {
119: int c, lastarg;
120: char *p;
121:
122: if (0 == buf[*pos])
123: return(1);
124:
125: for (;;) {
126: lastarg = *pos;
127: c = mdoc_args(mdoc, tok, pos, buf, 0, &p);
128: if (ARGS_ERROR == c)
129: return(0);
130: else if (ARGS_EOLN == c)
131: break;
132: assert(mdoc_isdelim(p));
133: mdoc_word_alloc(mdoc, lastarg, p);
1.16 kristaps 134: mdoc->next = MDOC_NEXT_SIBLING;
1.15 kristaps 135: }
1.2 kristaps 136:
1.1 kristaps 137: return(1);
138: }
139:
1.2 kristaps 140:
141: static int
1.16 kristaps 142: append_text_argv(struct mdoc *mdoc, int tok, int pos,
143: int sz, char *args[],
1.13 kristaps 144: int argc, const struct mdoc_arg *argv)
145: {
146:
1.16 kristaps 147: if ( ! mdoc_valid_pre(mdoc, tok, pos, 0, NULL, argc, argv))
1.15 kristaps 148: return(0);
1.17 kristaps 149:
150: switch (tok) {
151: case (MDOC_Pf):
152: /* TODO: only use first two arguments in element. */
153: break;
154: default:
155: break;
156: }
157:
1.16 kristaps 158: mdoc_elem_alloc(mdoc, pos, tok, (size_t)argc,
159: argv, (size_t)sz, _CC(args));
160: mdoc->next = MDOC_NEXT_SIBLING;
1.13 kristaps 161: return(1);
162: }
163:
164:
165: static int
1.16 kristaps 166: append_text(struct mdoc *mdoc, int tok,
1.10 kristaps 167: int pos, int sz, char *args[])
168: {
169:
1.16 kristaps 170: if ( ! mdoc_valid_pre(mdoc, tok, pos, sz, _CC(args), 0, NULL))
1.14 kristaps 171: return(0);
172:
1.10 kristaps 173: switch (tok) {
1.18 ! kristaps 174: /*
! 175: * FIXME: deprecate this "feature" of mdoc(7).
! 176: */
1.11 kristaps 177: case (MDOC_At):
178: if (0 == sz)
179: break;
1.15 kristaps 180: if (ATT_DEFAULT == mdoc_atoatt(args[0])) {
1.11 kristaps 181: mdoc_elem_alloc(mdoc, pos, tok,
182: 0, NULL, 0, NULL);
1.16 kristaps 183: mdoc->next = MDOC_NEXT_SIBLING;
1.11 kristaps 184: mdoc_word_alloc(mdoc, pos, args[0]);
1.16 kristaps 185: mdoc->next = MDOC_NEXT_SIBLING;
186: } else {
1.15 kristaps 187: mdoc_elem_alloc(mdoc, pos, tok, 0,
188: NULL, 1, _CC(&args[0]));
1.16 kristaps 189: mdoc->next = MDOC_NEXT_SIBLING;
190: }
1.11 kristaps 191:
1.15 kristaps 192: if (sz > 1)
193: mdoc_word_alloc(mdoc, pos, args[1]);
1.16 kristaps 194: mdoc->next = MDOC_NEXT_SIBLING;
1.11 kristaps 195: return(1);
1.16 kristaps 196:
1.14 kristaps 197: default:
1.10 kristaps 198: break;
199: }
200:
201: mdoc_elem_alloc(mdoc, pos, tok, 0, NULL, (size_t)sz, _CC(args));
1.16 kristaps 202: mdoc->next = MDOC_NEXT_SIBLING;
1.4 kristaps 203: return(1);
1.2 kristaps 204: }
205:
1.1 kristaps 206:
1.2 kristaps 207: int
1.5 kristaps 208: macro_text(MACRO_PROT_ARGS)
1.2 kristaps 209: {
1.15 kristaps 210: int lastarg, lastpunct, c, j, fl;
1.13 kristaps 211: char *args[MDOC_LINEARG_MAX];
1.1 kristaps 212:
1.7 kristaps 213: /* Token pre-processing. */
214:
215: switch (tok) {
1.18 ! kristaps 216: /* FIXME: move to validate.c. */
1.7 kristaps 217: case (MDOC_Pp):
218: /* `.Pp' ignored when following `.Sh' or `.Ss'. */
219: assert(mdoc->last);
220: if (MDOC_BODY != mdoc->last->type)
221: break;
222: switch (mdoc->last->data.body.tok) {
223: case (MDOC_Ss):
224: /* FALLTHROUGH */
225: case (MDOC_Sh):
226: if ( ! mdoc_warn(mdoc, tok, ppos, WARN_IGN_AFTER_BLK))
227: return(0);
228: return(1);
229: default:
230: break;
231: }
232: break;
233: default:
234: break;
235: }
236:
237: /* Process line parameters. */
238:
239: j = 0;
240: lastarg = ppos;
241: lastpunct = 0;
1.15 kristaps 242: fl = ARGS_DELIM;
243:
244: if (MDOC_QUOTABLE & mdoc_macros[tok].flags)
245: fl |= ARGS_QUOTED;
1.7 kristaps 246:
1.2 kristaps 247: again:
1.7 kristaps 248: if (j == MDOC_LINEARG_MAX)
249: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
250:
251: /*
252: * Parse out the next argument, unquoted and unescaped. If
253: * we're a word (which may be punctuation followed eventually by
254: * a real word), then fall into checking for callables. If
255: * only punctuation remains and we're the first, then flush
256: * arguments, punctuation and exit; else, return to the caller.
257: */
258:
1.6 kristaps 259: lastarg = *pos;
1.2 kristaps 260:
1.15 kristaps 261: switch (mdoc_args(mdoc, tok, pos, buf, fl, &args[j])) {
1.7 kristaps 262: case (ARGS_ERROR):
1.2 kristaps 263: return(0);
1.7 kristaps 264: case (ARGS_WORD):
265: break;
266: case (ARGS_PUNCT):
267: if ( ! lastpunct && ! append_text(mdoc, tok, ppos, j, args))
268: return(0);
1.8 kristaps 269: if (ppos > 1)
270: return(1);
1.7 kristaps 271: return(append_delims(mdoc, tok, pos, buf));
272: case (ARGS_EOLN):
1.8 kristaps 273: if (lastpunct)
274: return(1);
1.7 kristaps 275: return(append_text(mdoc, tok, ppos, j, args));
276: default:
277: abort();
278: /* NOTREACHED */
279: }
1.2 kristaps 280:
1.7 kristaps 281: /*
282: * Command found. First flush out arguments, then call the
283: * command. If we're the line macro when it exits, flush
284: * terminal punctuation.
285: */
1.2 kristaps 286:
287: if (MDOC_MAX != (c = mdoc_find(mdoc, args[j]))) {
1.7 kristaps 288: if ( ! lastpunct && ! append_text(mdoc, tok, ppos, j, args))
289: return(0);
290: if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
291: return(0);
292: if (ppos > 1)
293: return(1);
294: return(append_delims(mdoc, tok, pos, buf));
1.2 kristaps 295: }
296:
1.7 kristaps 297: /* Word/non-term-punctuation found. */
1.2 kristaps 298:
1.4 kristaps 299: if ( ! mdoc_isdelim(args[j])) {
1.7 kristaps 300: /* Words are appended to the array of arguments. */
1.2 kristaps 301: j++;
1.8 kristaps 302: lastpunct = 0;
1.2 kristaps 303: goto again;
304: }
305:
1.7 kristaps 306: /*
307: * For punctuation, flush all collected words, then flush
308: * punctuation, then start collecting again. Of course, this
309: * is non-terminal punctuation.
310: */
1.2 kristaps 311:
1.7 kristaps 312: if ( ! lastpunct && ! append_text(mdoc, tok, ppos, j, args))
313: return(0);
1.2 kristaps 314:
1.13 kristaps 315: mdoc_word_alloc(mdoc, lastarg, args[j]);
1.16 kristaps 316: mdoc->next = MDOC_NEXT_SIBLING;
1.7 kristaps 317: j = 0;
1.2 kristaps 318: lastpunct = 1;
319:
320: goto again;
321: /* NOTREACHED */
322: }
1.1 kristaps 323:
324:
1.16 kristaps 325:
326: /* ARGSUSED */
1.2 kristaps 327: int
1.16 kristaps 328: macro_close_explicit(MACRO_PROT_ARGS)
1.5 kristaps 329: {
1.16 kristaps 330: int tt;
1.5 kristaps 331:
1.16 kristaps 332: /*
333: * First close out the explicit scope. The `end' tags (such as
334: * `.El' to `.Bl' don't cause anything to happen: we merely
335: * readjust our last parse point.
336: */
1.5 kristaps 337:
1.16 kristaps 338: switch (tok) {
339: case (MDOC_El):
340: tt = MDOC_Bl;
341: break;
342: case (MDOC_Ed):
343: tt = MDOC_Bd;
1.7 kristaps 344: break;
1.16 kristaps 345: case (MDOC_Re):
346: tt = MDOC_Rs;
1.7 kristaps 347: break;
1.17 kristaps 348: case (MDOC_Ef):
349: tt = MDOC_Bf;
350: break;
1.7 kristaps 351: default:
1.16 kristaps 352: abort();
353: /* NOTREACHED */
1.7 kristaps 354: }
1.5 kristaps 355:
1.18 ! kristaps 356: if (0 != buf[*pos])
! 357: return(mdoc_err(mdoc, tok, ppos, ERR_ARGS_EQ0));
1.16 kristaps 358: return(scope_rewind_exp(mdoc, ppos, tok, tt));
1.5 kristaps 359: }
360:
361:
362: int
1.16 kristaps 363: macro_scoped(MACRO_PROT_ARGS)
1.6 kristaps 364: {
1.16 kristaps 365: int i, c, lastarg, argc, sz;
366: char *args[MDOC_LINEARG_MAX];
1.6 kristaps 367: struct mdoc_arg argv[MDOC_LINEARG_MAX];
1.16 kristaps 368: enum mdoc_sec sec;
1.7 kristaps 369: struct mdoc_node *n;
1.6 kristaps 370:
1.16 kristaps 371: assert ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags));
1.6 kristaps 372:
1.7 kristaps 373: /* Token pre-processing. */
374:
375: switch (tok) {
376: case (MDOC_Bl):
377: /* FALLTHROUGH */
378: case (MDOC_Bd):
379: /* `.Pp' ignored when preceding `.Bl' or `.Bd'. */
380: assert(mdoc->last);
381: if (MDOC_ELEM != mdoc->last->type)
382: break;
383: if (MDOC_Pp != mdoc->last->data.elem.tok)
384: break;
385: if ( ! mdoc_warn(mdoc, tok, ppos, WARN_IGN_BEFORE_BLK))
386: return(0);
387: assert(mdoc->last->prev);
388: n = mdoc->last;
389: mdoc->last = mdoc->last->prev;
390: mdoc->last->next = NULL;
391: mdoc_node_free(n);
392: break;
1.16 kristaps 393: case (MDOC_Sh):
394: /* FALLTHROUGH */
1.7 kristaps 395: case (MDOC_Ss):
1.16 kristaps 396: if ( ! scope_rewind_imp(mdoc, ppos, tok))
397: return(0);
1.7 kristaps 398: /* `.Pp' ignored when preceding `.Ss' or `.Sh'. */
399: if (NULL == mdoc->last)
400: break;
401: if (MDOC_ELEM != mdoc->last->type)
402: break;
403: if (MDOC_Pp != mdoc->last->data.elem.tok)
1.1 kristaps 404: break;
1.7 kristaps 405: if ( ! mdoc_warn(mdoc, tok, ppos, WARN_IGN_BEFORE_BLK))
406: return(0);
407: assert(mdoc->last->prev);
408: n = mdoc->last;
1.8 kristaps 409: mdoc_msg(mdoc, ppos, "removing prior `Pp' macro");
1.7 kristaps 410: mdoc->last = mdoc->last->prev;
411: mdoc->last->next = NULL;
412: mdoc_node_free(n);
413: break;
414: default:
415: break;
1.2 kristaps 416: }
417:
1.16 kristaps 418: /* Argument processing. */
419:
420: lastarg = *pos;
1.8 kristaps 421:
1.16 kristaps 422: for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
423: lastarg = *pos;
424: c = mdoc_argv(mdoc, tok, &argv[argc], pos, buf);
425: if (ARGV_EOLN == c || ARGV_WORD == c)
426: break;
427: else if (ARGV_ARG == c)
428: continue;
429: mdoc_argv_free(argc, argv);
1.8 kristaps 430: return(0);
1.16 kristaps 431: }
1.2 kristaps 432:
1.16 kristaps 433: /* Parameter processing. */
1.2 kristaps 434:
1.16 kristaps 435: for (sz = 0; argc + sz < MDOC_LINEARG_MAX; sz++) {
436: lastarg = *pos;
437: c = mdoc_args(mdoc, tok, pos, buf, 0, &args[sz]);
438: if (ARGS_EOLN == c)
439: break;
440: if (ARGS_WORD == c)
441: continue;
442: mdoc_argv_free(argc, argv);
443: return(0);
444: }
1.8 kristaps 445:
1.16 kristaps 446: if (MDOC_LINEARG_MAX == (argc + sz)) {
447: mdoc_argv_free(argc, argv);
1.7 kristaps 448: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
1.16 kristaps 449: }
1.7 kristaps 450:
1.16 kristaps 451: /* Post-processing. */
1.2 kristaps 452:
1.16 kristaps 453: if ( ! mdoc_valid_pre(mdoc, tok, ppos, sz, _CC(args), argc, argv)) {
454: mdoc_argv_free(argc, argv);
1.2 kristaps 455: return(0);
1.7 kristaps 456: }
1.1 kristaps 457:
1.8 kristaps 458: switch (tok) {
1.16 kristaps 459: case (MDOC_Sh):
460: sec = mdoc_atosec((size_t)sz, _CC(args));
461: if (SEC_CUSTOM != sec)
462: mdoc->sec_lastn = sec;
463: mdoc->sec_last = sec;
464: break;
1.8 kristaps 465: default:
466: break;
467: }
468:
1.16 kristaps 469: mdoc_block_alloc(mdoc, ppos, tok, (size_t)argc, argv);
470: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 471:
1.16 kristaps 472: mdoc_argv_free(argc, argv);
1.8 kristaps 473:
1.18 ! kristaps 474: if (sz > 0) {
! 475: mdoc_head_alloc(mdoc, ppos, tok);
! 476: mdoc->next = MDOC_NEXT_CHILD;
! 477:
! 478: for (i = 0; i < sz; i++) {
! 479: mdoc_word_alloc(mdoc, ppos, args[i]);
! 480: mdoc->next = MDOC_NEXT_SIBLING;
! 481: }
! 482:
! 483: if ( ! scope_rewind_line(mdoc, ppos, tok))
! 484: return(0);
1.16 kristaps 485: }
1.8 kristaps 486:
1.16 kristaps 487: mdoc_body_alloc(mdoc, ppos, tok);
488: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 489:
1.16 kristaps 490: return(1);
1.1 kristaps 491: }
1.5 kristaps 492:
1.7 kristaps 493:
494: int
1.16 kristaps 495: macro_scoped_line(MACRO_PROT_ARGS)
1.7 kristaps 496: {
1.8 kristaps 497: int lastarg, c, j;
498: char *p;
1.7 kristaps 499:
1.16 kristaps 500: assert(1 == ppos);
501:
502: mdoc_block_alloc(mdoc, ppos, tok, 0, NULL);
503: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 504:
1.16 kristaps 505: mdoc_head_alloc(mdoc, ppos, tok);
506: mdoc->next = MDOC_NEXT_CHILD;
1.8 kristaps 507:
1.16 kristaps 508: if ( ! mdoc_valid_pre(mdoc, tok, ppos, 0, NULL, 0, NULL))
509: return(0);
1.8 kristaps 510:
511: /* Process line parameters. */
512:
513: j = 0;
514: lastarg = ppos;
515:
516: again:
517: if (j == MDOC_LINEARG_MAX)
518: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
519:
520: lastarg = *pos;
521: c = mdoc_args(mdoc, tok, pos, buf, ARGS_DELIM, &p);
522:
523: switch (c) {
524: case (ARGS_ERROR):
525: return(0);
526: case (ARGS_WORD):
527: break;
528: case (ARGS_PUNCT):
1.16 kristaps 529: if (ppos > 1)
530: return(scope_rewind_imp(mdoc, ppos, tok));
531: if ( ! scope_rewind_line(mdoc, ppos, tok))
532: return(0);
533: if ( ! append_delims(mdoc, tok, pos, buf))
1.8 kristaps 534: return(0);
1.16 kristaps 535: return(scope_rewind_imp(mdoc, ppos, tok));
1.8 kristaps 536: case (ARGS_EOLN):
537: return(scope_rewind_imp(mdoc, ppos, tok));
538: default:
539: abort();
540: /* NOTREACHED */
541: }
542:
543: if (MDOC_MAX != (c = mdoc_find(mdoc, p))) {
544: if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
545: return(0);
1.16 kristaps 546: if (ppos > 1)
547: return(scope_rewind_imp(mdoc, ppos, tok));
548: if ( ! scope_rewind_line(mdoc, ppos, tok))
549: return(0);
550: if ( ! append_delims(mdoc, tok, pos, buf))
1.8 kristaps 551: return(0);
1.16 kristaps 552: return(scope_rewind_imp(mdoc, ppos, tok));
1.8 kristaps 553: }
554:
555: if (mdoc_isdelim(p))
556: j = 0;
557:
558: mdoc_word_alloc(mdoc, lastarg, p);
1.16 kristaps 559: mdoc->next = MDOC_NEXT_SIBLING;
1.8 kristaps 560: goto again;
561: /* NOTREACHED */
1.7 kristaps 562: }
1.8 kristaps 563:
1.10 kristaps 564:
1.17 kristaps 565: /*
566: * FIXME: like in with macro_constant, have the append_ routine chop the
567: * number of requisite arguments (this is ugly when done in-line).
568: */
1.10 kristaps 569: int
570: macro_constant_delimited(MACRO_PROT_ARGS)
571: {
572: int lastarg, flushed, c, maxargs;
1.13 kristaps 573: char *p;
1.10 kristaps 574:
575: /* Process line parameters. */
576:
577: lastarg = ppos;
578: flushed = 0;
579:
1.11 kristaps 580: /* Token pre-processing. */
581:
1.10 kristaps 582: switch (tok) {
1.16 kristaps 583: case (MDOC_No):
584: /* FALLTHROUGH */
585: case (MDOC_Ns):
586: /* FALLTHROUGH */
1.10 kristaps 587: case (MDOC_Ux):
588: maxargs = 0;
589: break;
590: default:
591: maxargs = 1;
592: break;
593: }
594:
595: again:
596: lastarg = *pos;
597:
598: switch (mdoc_args(mdoc, tok, pos, buf, ARGS_DELIM, &p)) {
599: case (ARGS_ERROR):
600: return(0);
601: case (ARGS_WORD):
602: break;
603: case (ARGS_PUNCT):
1.16 kristaps 604: if ( ! flushed && ! append_text(mdoc, tok, ppos, 0, &p))
1.10 kristaps 605: return(0);
606: if (ppos > 1)
607: return(1);
608: return(append_delims(mdoc, tok, pos, buf));
609: case (ARGS_EOLN):
610: if (flushed)
611: return(1);
1.16 kristaps 612: return(append_text(mdoc, tok, ppos, 0, &p));
1.10 kristaps 613: default:
614: abort();
615: /* NOTREACHED */
616: }
617:
1.11 kristaps 618: /* Accepts no arguments: flush out symbol and continue. */
619:
1.16 kristaps 620: if ( ! flushed && 0 == maxargs) {
621: if ( ! append_text(mdoc, tok, ppos, 0, &p))
1.10 kristaps 622: return(0);
623: flushed = 1;
624: }
625:
626: if (MDOC_MAX != (c = mdoc_find(mdoc, p))) {
1.16 kristaps 627: if ( ! flushed && ! append_text(mdoc, tok, ppos, 0, &p))
1.10 kristaps 628: return(0);
629: if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
630: return(0);
631: if (ppos > 1)
632: return(1);
633: return(append_delims(mdoc, tok, pos, buf));
634: }
635:
1.11 kristaps 636: /*
637: * We only accept one argument; subsequent tokens are considered
638: * as literal words (until a macro).
639: */
640:
1.10 kristaps 641: if ( ! flushed && ! mdoc_isdelim(p)) {
1.16 kristaps 642: if ( ! append_text(mdoc, tok, ppos, 1, &p))
1.10 kristaps 643: return(0);
644: flushed = 1;
645: goto again;
646: } else if ( ! flushed) {
1.16 kristaps 647: if ( ! append_text(mdoc, tok, ppos, 0, &p))
1.10 kristaps 648: return(0);
649: flushed = 1;
650: }
651:
652: mdoc_word_alloc(mdoc, lastarg, p);
1.16 kristaps 653: mdoc->next = MDOC_NEXT_SIBLING;
1.10 kristaps 654: goto again;
655: /* NOTREACHED */
656: }
1.11 kristaps 657:
658:
659: int
660: macro_constant(MACRO_PROT_ARGS)
661: {
1.16 kristaps 662: int c, lastarg, argc, sz, fl;
1.11 kristaps 663: char *args[MDOC_LINEARG_MAX];
1.16 kristaps 664: struct mdoc_arg argv[MDOC_LINEARG_MAX];
1.11 kristaps 665:
1.16 kristaps 666: fl = 0;
1.15 kristaps 667: if (MDOC_QUOTABLE & mdoc_macros[tok].flags)
668: fl = ARGS_QUOTED;
1.11 kristaps 669:
1.16 kristaps 670: for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
671: lastarg = *pos;
672: c = mdoc_argv(mdoc, tok, &argv[argc], pos, buf);
673: if (ARGV_EOLN == c)
674: break;
675: else if (ARGV_ARG == c)
676: continue;
677: else if (ARGV_WORD == c)
678: break;
1.11 kristaps 679:
1.16 kristaps 680: mdoc_argv_free(argc, argv);
1.11 kristaps 681: return(0);
682: }
683:
1.16 kristaps 684: if (MDOC_LINEARG_MAX == argc) {
685: mdoc_argv_free(argc, argv);
686: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
687: }
1.11 kristaps 688:
1.16 kristaps 689: for (sz = 0; sz + argc < MDOC_LINEARG_MAX; sz++) {
1.13 kristaps 690: lastarg = *pos;
1.16 kristaps 691: c = mdoc_args(mdoc, tok, pos, buf, fl, &args[sz]);
692: if (ARGS_ERROR == c)
693: return(0);
694: if (ARGS_EOLN == c)
1.13 kristaps 695: break;
696: }
697:
1.16 kristaps 698: if (MDOC_LINEARG_MAX == sz + argc) {
699: mdoc_argv_free(argc, argv);
1.13 kristaps 700: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
701: }
702:
1.16 kristaps 703: c = append_text_argv(mdoc, tok, ppos, sz, args, argc, argv);
704: mdoc_argv_free(argc, argv);
1.13 kristaps 705: return(c);
706: }
1.15 kristaps 707:
708:
1.16 kristaps 709: /* ARGSUSED */
1.15 kristaps 710: int
711: macro_obsolete(MACRO_PROT_ARGS)
712: {
713:
714: return(mdoc_warn(mdoc, tok, ppos, WARN_IGN_OBSOLETE));
715: }
CVSweb