]> git.cameronkatri.com Git - mandoc.git/blob - roff.c
990475561b9ae075e77fa4283eee0ed897384d75
[mandoc.git] / roff.c
1 /* $Id: roff.c,v 1.58 2008/12/10 10:43:57 kristaps Exp $ */
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 */
19 #include <sys/param.h>
20 #include <sys/types.h>
21
22 #include <assert.h>
23 #include <ctype.h>
24 #include <err.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <time.h>
30
31 #include "private.h"
32 #include "roff.h"
33
34 /* FIXME: First letters of quoted-text interpreted in rofffindtok. */
35 /* FIXME: `No' not implemented. */
36 /* TODO: warn if Pp occurs before/after Sh etc. (see mdoc.samples). */
37 /* TODO: warn about empty lists. */
38 /* TODO: (warn) some sections need specific elements. */
39 /* TODO: (warn) NAME section has particular order. */
40 /* TODO: macros with a set number of arguments? */
41 /* TODO: validate Dt macro arguments. */
42 /* FIXME: Bl -diag supposed to ignore callable children. */
43
44 struct roffnode {
45 int tok; /* Token id. */
46 struct roffnode *parent; /* Parent (or NULL). */
47 };
48
49 enum rofferr {
50 ERR_ARGEQ1, /* Macro requires arg == 1. */
51 ERR_ARGEQ0, /* Macro requires arg == 0. */
52 ERR_ARGGE1, /* Macro requires arg >= 1. */
53 ERR_ARGGE2, /* Macro requires arg >= 2. */
54 ERR_ARGLEN, /* Macro argument too long. */
55 ERR_BADARG, /* Macro has bad arg. */
56 ERR_ARGMNY, /* Too many macro arguments. */
57 ERR_NOTSUP, /* Macro not supported. */
58 ERR_DEPREC, /* Macro deprecated. */
59 ERR_PR_OOO, /* Prelude macro bad order. */
60 ERR_PR_REP, /* Prelude macro repeated. */
61 ERR_NOT_PR, /* Not allowed in prelude. */
62 WRN_SECORD, /* Sections out-of-order. */
63 };
64
65 struct rofftree {
66 struct roffnode *last; /* Last parsed node. */
67 char *cur; /* Line start. */
68 struct tm tm; /* `Dd' results. */
69 char name[64]; /* `Nm' results. */
70 char os[64]; /* `Os' results. */
71 char title[64]; /* `Dt' results. */
72 enum roffmsec section;
73 enum roffvol volume;
74 int state;
75 #define ROFF_PRELUDE (1 << 1) /* In roff prelude. */ /* FIXME: put into asec. */
76 #define ROFF_PRELUDE_Os (1 << 2) /* `Os' is parsed. */
77 #define ROFF_PRELUDE_Dt (1 << 3) /* `Dt' is parsed. */
78 #define ROFF_PRELUDE_Dd (1 << 4) /* `Dd' is parsed. */
79 #define ROFF_BODY (1 << 5) /* In roff body. */
80 struct roffcb cb; /* Callbacks. */
81 void *arg; /* Callbacks' arg. */
82 int csec; /* Current section. */
83 int asec; /* Thus-far sections. */
84 };
85
86 static struct roffnode *roffnode_new(int, struct rofftree *);
87 static void roffnode_free(struct rofftree *);
88 static int roff_warn(const struct rofftree *,
89 const char *, char *, ...);
90 static int roff_warnp(const struct rofftree *,
91 const char *, int, enum rofferr);
92 static int roff_err(const struct rofftree *,
93 const char *, char *, ...);
94 static int roff_errp(const struct rofftree *,
95 const char *, int, enum rofferr);
96 static int roffpurgepunct(struct rofftree *, char **);
97 static int roffscan(int, const int *);
98 static int rofffindtok(const char *);
99 static int rofffindarg(const char *);
100 static int rofffindcallable(const char *);
101 static int roffispunct(const char *);
102 static int roffchecksec(struct rofftree *,
103 const char *, int);
104 static int roffargs(const struct rofftree *,
105 int, char *, char **);
106 static int roffargok(int, int);
107 static int roffnextopt(const struct rofftree *,
108 int, char ***, char **);
109 static int roffparseopts(struct rofftree *, int,
110 char ***, int *, char **);
111 static int roffcall(struct rofftree *, int, char **);
112 static int roffexit(struct rofftree *, int);
113 static int roffparse(struct rofftree *, char *);
114 static int textparse(struct rofftree *, char *);
115 static int roffdata(struct rofftree *, int, char *);
116 static int roffspecial(struct rofftree *, int,
117 const char *, const int *,
118 const char **, size_t, char **);
119 static int roffsetname(struct rofftree *, char **);
120
121 #ifdef __linux__
122 extern size_t strlcat(char *, const char *, size_t);
123 extern size_t strlcpy(char *, const char *, size_t);
124 extern int vsnprintf(char *, size_t,
125 const char *, va_list);
126 extern char *strptime(const char *, const char *,
127 struct tm *);
128 #endif
129
130 int
131 roff_free(struct rofftree *tree, int flush)
132 {
133 int error, t;
134 struct roffnode *n;
135
136 error = 0;
137
138 if ( ! flush)
139 goto end;
140
141 error = 1;
142
143 if (ROFF_PRELUDE & tree->state) {
144 (void)roff_err(tree, NULL, "prelude never finished");
145 goto end;
146 } else if ( ! (ROFFSec_NAME & tree->asec)) {
147 (void)roff_err(tree, NULL, "missing `NAME' section");
148 goto end;
149 } else if ( ! (ROFFSec_NMASK & tree->asec))
150 (void)roff_warn(tree, NULL, "missing suggested `NAME', "
151 "`SYNOPSIS', `DESCRIPTION' sections");
152
153 for (n = tree->last; n; n = n->parent) {
154 if (0 != tokens[n->tok].ctx)
155 continue;
156 (void)roff_err(tree, NULL, "closing explicit scope "
157 "`%s'", toknames[n->tok]);
158 goto end;
159 }
160
161 while (tree->last) {
162 t = tree->last->tok;
163 if ( ! roffexit(tree, t))
164 goto end;
165 }
166
167 if ( ! (*tree->cb.rofftail)(tree->arg))
168 goto end;
169
170 error = 0;
171
172 end:
173
174 while (tree->last)
175 roffnode_free(tree);
176
177 free(tree);
178
179 return(error ? 0 : 1);
180 }
181
182
183 struct rofftree *
184 roff_alloc(const struct roffcb *cb, void *args)
185 {
186 struct rofftree *tree;
187
188 assert(args);
189 assert(cb);
190
191 if (NULL == (tree = calloc(1, sizeof(struct rofftree))))
192 err(1, "calloc");
193
194 tree->state = ROFF_PRELUDE;
195 tree->arg = args;
196 tree->section = ROFF_MSEC_MAX;
197
198 (void)memcpy(&tree->cb, cb, sizeof(struct roffcb));
199
200 return(tree);
201 }
202
203
204 int
205 roff_engine(struct rofftree *tree, char *buf)
206 {
207
208 tree->cur = buf;
209 assert(buf);
210
211 if (0 == *buf)
212 return(roff_err(tree, buf, "blank line"));
213 else if ('.' != *buf)
214 return(textparse(tree, buf));
215
216 return(roffparse(tree, buf));
217 }
218
219
220 static int
221 textparse(struct rofftree *tree, char *buf)
222 {
223 char *bufp;
224
225 /* TODO: literal parsing. */
226
227 if ( ! (ROFF_BODY & tree->state))
228 return(roff_err(tree, buf, "data not in body"));
229
230 /* LINTED */
231 while (*buf) {
232 while (*buf && isspace(*buf))
233 buf++;
234
235 if (0 == *buf)
236 break;
237
238 bufp = buf++;
239
240 while (*buf && ! isspace(*buf))
241 buf++;
242
243 if (0 != *buf) {
244 *buf++ = 0;
245 if ( ! roffdata(tree, 1, bufp))
246 return(0);
247 continue;
248 }
249
250 if ( ! roffdata(tree, 1, bufp))
251 return(0);
252 break;
253 }
254
255 return(1);
256 }
257
258
259 static int
260 roffargs(const struct rofftree *tree,
261 int tok, char *buf, char **argv)
262 {
263 int i;
264 char *p;
265
266 assert(tok >= 0 && tok < ROFF_MAX);
267 assert('.' == *buf);
268
269 p = buf;
270
271 /*
272 * This is an ugly little loop. It parses a line into
273 * space-delimited tokens. If a quote mark is encountered, a
274 * token is alloted the entire quoted text. If whitespace is
275 * escaped, it's included in the prior alloted token.
276 */
277
278 /* LINTED */
279 for (i = 0; *buf && i < ROFF_MAXLINEARG; i++) {
280 if ('\"' == *buf) {
281 argv[i] = ++buf;
282 while (*buf && '\"' != *buf)
283 buf++;
284 if (0 == *buf)
285 return(roff_err(tree, argv[i],
286 "unclosed quote in arg list"));
287 } else {
288 argv[i] = buf++;
289 while (*buf) {
290 if ( ! isspace(*buf)) {
291 buf++;
292 continue;
293 }
294 if (*(buf - 1) == '\\') {
295 buf++;
296 continue;
297 }
298 break;
299 }
300 if (0 == *buf)
301 continue;
302 }
303 *buf++ = 0;
304 while (*buf && isspace(*buf))
305 buf++;
306 }
307
308 assert(i > 0);
309 if (ROFF_MAXLINEARG == i && *buf)
310 return(roff_err(tree, p, "too many args"));
311
312 argv[i] = NULL;
313 return(1);
314 }
315
316
317 static int
318 roffscan(int tok, const int *tokv)
319 {
320
321 if (NULL == tokv)
322 return(1);
323
324 for ( ; ROFF_MAX != *tokv; tokv++)
325 if (tok == *tokv)
326 return(1);
327
328 return(0);
329 }
330
331
332 static int
333 roffparse(struct rofftree *tree, char *buf)
334 {
335 int tok, t;
336 struct roffnode *n;
337 char *argv[ROFF_MAXLINEARG];
338 char **argvp;
339
340 if (0 != *buf && 0 != *(buf + 1) && 0 != *(buf + 2))
341 if (0 == strncmp(buf, ".\\\"", 3))
342 return(1);
343
344 if (ROFF_MAX == (tok = rofffindtok(buf + 1)))
345 return(roff_err(tree, buf, "bogus line macro"));
346 else if ( ! roffargs(tree, tok, buf, argv))
347 return(0);
348
349 argvp = (char **)argv;
350
351 /*
352 * Prelude macros break some assumptions, so branch now.
353 */
354
355 if (ROFF_PRELUDE & tree->state) {
356 assert(NULL == tree->last);
357 return(roffcall(tree, tok, argvp));
358 }
359
360 assert(ROFF_BODY & tree->state);
361
362 /*
363 * First check that our possible parents and parent's possible
364 * children are satisfied.
365 */
366
367 if (tree->last && ! roffscan
368 (tree->last->tok, tokens[tok].parents))
369 return(roff_err(tree, *argvp, "`%s' has invalid "
370 "parent `%s'", toknames[tok],
371 toknames[tree->last->tok]));
372
373 if (tree->last && ! roffscan
374 (tok, tokens[tree->last->tok].children))
375 return(roff_err(tree, *argvp, "`%s' has invalid "
376 "child `%s'", toknames[tok],
377 toknames[tree->last->tok]));
378
379 /*
380 * Branch if we're not a layout token.
381 */
382
383 if (ROFF_LAYOUT != tokens[tok].type)
384 return(roffcall(tree, tok, argvp));
385 if (0 == tokens[tok].ctx)
386 return(roffcall(tree, tok, argvp));
387
388 /*
389 * First consider implicit-end tags, like as follows:
390 * .Sh SECTION 1
391 * .Sh SECTION 2
392 * In this, we want to close the scope of the NAME section. If
393 * there's an intermediary implicit-end tag, such as
394 * .Sh SECTION 1
395 * .Ss Subsection 1
396 * .Sh SECTION 2
397 * then it must be closed as well.
398 */
399
400 if (tok == tokens[tok].ctx) {
401 /*
402 * First search up to the point where we must close.
403 * If one doesn't exist, then we can open a new scope.
404 */
405
406 for (n = tree->last; n; n = n->parent) {
407 assert(0 == tokens[n->tok].ctx ||
408 n->tok == tokens[n->tok].ctx);
409 if (n->tok == tok)
410 break;
411 if (ROFF_SHALLOW & tokens[tok].flags) {
412 n = NULL;
413 break;
414 }
415 if (tokens[n->tok].ctx == n->tok)
416 continue;
417 return(roff_err(tree, *argv, "`%s' breaks "
418 "scope of prior`%s'",
419 toknames[tok],
420 toknames[n->tok]));
421 }
422
423 /*
424 * Create a new scope, as no previous one exists to
425 * close out.
426 */
427
428 if (NULL == n)
429 return(roffcall(tree, tok, argvp));
430
431 /*
432 * Close out all intermediary scoped blocks, then hang
433 * the current scope from our predecessor's parent.
434 */
435
436 do {
437 t = tree->last->tok;
438 if ( ! roffexit(tree, t))
439 return(0);
440 } while (t != tok);
441
442 return(roffcall(tree, tok, argvp));
443 }
444
445 /*
446 * Now consider explicit-end tags, where we want to close back
447 * to a specific tag. Example:
448 * .Bl
449 * .It Item.
450 * .El
451 * In this, the `El' tag closes out the scope of `Bl'.
452 */
453
454 assert(tok != tokens[tok].ctx && 0 != tokens[tok].ctx);
455
456 /* LINTED */
457 for (n = tree->last; n; n = n->parent)
458 if (n->tok != tokens[tok].ctx) {
459 if (n->tok == tokens[n->tok].ctx)
460 continue;
461 return(roff_err(tree, *argv, "`%s' breaks "
462 "scope of prior `%s'",
463 toknames[tok],
464 toknames[n->tok]));
465 } else
466 break;
467
468 if (NULL == n)
469 return(roff_err(tree, *argv, "`%s' has no starting "
470 "tag `%s'", toknames[tok],
471 toknames[tokens[tok].ctx]));
472
473 /* LINTED */
474 do {
475 t = tree->last->tok;
476 if ( ! roffexit(tree, t))
477 return(0);
478 } while (t != tokens[tok].ctx);
479
480 return(1);
481 }
482
483
484 static int
485 rofffindarg(const char *name)
486 {
487 size_t i;
488
489 /* FIXME: use a table, this is slow but ok for now. */
490
491 /* LINTED */
492 for (i = 0; i < ROFF_ARGMAX; i++)
493 /* LINTED */
494 if (0 == strcmp(name, tokargnames[i]))
495 return((int)i);
496
497 return(ROFF_ARGMAX);
498 }
499
500
501 static int
502 rofffindtok(const char *buf)
503 {
504 char token[4];
505 int i;
506
507 for (i = 0; *buf && ! isspace(*buf) && i < 3; i++, buf++)
508 token[i] = *buf;
509
510 if (i == 3)
511 return(ROFF_MAX);
512
513 token[i] = 0;
514
515 /* FIXME: use a table, this is slow but ok for now. */
516
517 /* LINTED */
518 for (i = 0; i < ROFF_MAX; i++)
519 /* LINTED */
520 if (0 == strcmp(toknames[i], token))
521 return((int)i);
522
523 return(ROFF_MAX);
524 }
525
526
527 static int
528 roffchecksec(struct rofftree *tree, const char *start, int sec)
529 {
530 int prior;
531
532 switch (sec) {
533 case(ROFFSec_SYNOP):
534 if ((prior = ROFFSec_NAME) & tree->asec)
535 return(1);
536 break;
537 case(ROFFSec_DESC):
538 if ((prior = ROFFSec_SYNOP) & tree->asec)
539 return(1);
540 break;
541 case(ROFFSec_RETVAL):
542 if ((prior = ROFFSec_DESC) & tree->asec)
543 return(1);
544 break;
545 case(ROFFSec_ENV):
546 if ((prior = ROFFSec_RETVAL) & tree->asec)
547 return(1);
548 break;
549 case(ROFFSec_FILES):
550 if ((prior = ROFFSec_ENV) & tree->asec)
551 return(1);
552 break;
553 case(ROFFSec_EX):
554 if ((prior = ROFFSec_FILES) & tree->asec)
555 return(1);
556 break;
557 case(ROFFSec_DIAG):
558 if ((prior = ROFFSec_EX) & tree->asec)
559 return(1);
560 break;
561 case(ROFFSec_ERRS):
562 if ((prior = ROFFSec_DIAG) & tree->asec)
563 return(1);
564 break;
565 case(ROFFSec_SEEALSO):
566 if ((prior = ROFFSec_ERRS) & tree->asec)
567 return(1);
568 break;
569 case(ROFFSec_STAND):
570 if ((prior = ROFFSec_SEEALSO) & tree->asec)
571 return(1);
572 break;
573 case(ROFFSec_HIST):
574 if ((prior = ROFFSec_STAND) & tree->asec)
575 return(1);
576 break;
577 case(ROFFSec_AUTH):
578 if ((prior = ROFFSec_HIST) & tree->asec)
579 return(1);
580 break;
581 case(ROFFSec_CAVEATS):
582 if ((prior = ROFFSec_AUTH) & tree->asec)
583 return(1);
584 break;
585 case(ROFFSec_BUGS):
586 if ((prior = ROFFSec_CAVEATS) & tree->asec)
587 return(1);
588 break;
589 default:
590 return(1);
591 }
592
593 return(roff_warnp(tree, start, ROFF_Sh, WRN_SECORD));
594 }
595
596
597 /* FIXME: move this into literals.c (or similar). */
598 static int
599 roffispunct(const char *p)
600 {
601
602 if (0 == *p)
603 return(0);
604 if (0 != *(p + 1))
605 return(0);
606
607 switch (*p) {
608 case('{'):
609 /* FALLTHROUGH */
610 case('.'):
611 /* FALLTHROUGH */
612 case(','):
613 /* FALLTHROUGH */
614 case(';'):
615 /* FALLTHROUGH */
616 case(':'):
617 /* FALLTHROUGH */
618 case('?'):
619 /* FALLTHROUGH */
620 case('!'):
621 /* FALLTHROUGH */
622 case('('):
623 /* FALLTHROUGH */
624 case(')'):
625 /* FALLTHROUGH */
626 case('['):
627 /* FALLTHROUGH */
628 case(']'):
629 /* FALLTHROUGH */
630 case('}'):
631 return(1);
632 default:
633 break;
634 }
635
636 return(0);
637 }
638
639
640 static int
641 rofffindcallable(const char *name)
642 {
643 int c;
644
645 if (ROFF_MAX == (c = rofffindtok(name)))
646 return(ROFF_MAX);
647 assert(c >= 0 && c < ROFF_MAX);
648 return(ROFF_CALLABLE & tokens[c].flags ? c : ROFF_MAX);
649 }
650
651
652 static struct roffnode *
653 roffnode_new(int tokid, struct rofftree *tree)
654 {
655 struct roffnode *p;
656
657 if (NULL == (p = malloc(sizeof(struct roffnode))))
658 err(1, "malloc");
659
660 p->tok = tokid;
661 p->parent = tree->last;
662 tree->last = p;
663
664 return(p);
665 }
666
667
668 static int
669 roffargok(int tokid, int argid)
670 {
671 const int *c;
672
673 if (NULL == (c = tokens[tokid].args))
674 return(0);
675
676 for ( ; ROFF_ARGMAX != *c; c++)
677 if (argid == *c)
678 return(1);
679
680 return(0);
681 }
682
683
684 static void
685 roffnode_free(struct rofftree *tree)
686 {
687 struct roffnode *p;
688
689 assert(tree->last);
690
691 p = tree->last;
692 tree->last = tree->last->parent;
693 free(p);
694 }
695
696
697 static int
698 roffspecial(struct rofftree *tree, int tok, const char *start,
699 const int *argc, const char **argv,
700 size_t sz, char **ordp)
701 {
702
703 switch (tok) {
704 case (ROFF_At):
705 if (0 == sz)
706 break;
707 if (ROFF_ATT_MAX != roff_att(*ordp))
708 break;
709 return(roff_errp(tree, *ordp, tok, ERR_BADARG));
710
711 case (ROFF_Xr):
712 if (2 == sz) {
713 assert(ordp[1]);
714 if (ROFF_MSEC_MAX != roff_msec(ordp[1]))
715 break;
716 if ( ! roff_warn(tree, start, "invalid `%s' manual "
717 "section", toknames[tok]))
718 return(0);
719 }
720 /* FALLTHROUGH */
721
722 case (ROFF_Sx):
723 /* FALLTHROUGH*/
724 case (ROFF_Fn):
725 if (0 != sz)
726 break;
727 return(roff_errp(tree, start, tok, ERR_ARGGE1));
728
729 case (ROFF_Nm):
730 if (0 == sz) {
731 if (0 != tree->name[0]) {
732 ordp[0] = tree->name;
733 ordp[1] = NULL;
734 break;
735 }
736 return(roff_err(tree, start, "`Nm' not set"));
737 } else if ( ! roffsetname(tree, ordp))
738 return(0);
739 break;
740
741 case (ROFF_Rv):
742 /* FALLTHROUGH*/
743 case (ROFF_Ex):
744 if (1 == sz)
745 break;
746 return(roff_errp(tree, start, tok, ERR_ARGEQ1));
747
748 case (ROFF_Sm):
749 if (1 != sz)
750 return(roff_errp(tree, start, tok, ERR_ARGEQ1));
751 else if (0 == strcmp(ordp[0], "on") ||
752 0 == strcmp(ordp[0], "off"))
753 break;
754 return(roff_errp(tree, *ordp, tok, ERR_BADARG));
755
756 case (ROFF_Ud):
757 /* FALLTHROUGH */
758 case (ROFF_Ux):
759 /* FALLTHROUGH */
760 case (ROFF_Bt):
761 if (0 == sz)
762 break;
763 return(roff_errp(tree, start, tok, ERR_ARGEQ0));
764 default:
765 break;
766 }
767
768 return((*tree->cb.roffspecial)(tree->arg, tok, tree->cur,
769 argc, argv, (const char **)ordp));
770 }
771
772
773 static int
774 roffexit(struct rofftree *tree, int tok)
775 {
776
777 assert(tokens[tok].cb);
778 return((*tokens[tok].cb)(tok, tree, NULL, ROFF_EXIT));
779 }
780
781
782 static int
783 roffcall(struct rofftree *tree, int tok, char **argv)
784 {
785 int i;
786 enum roffmsec c;
787
788 if (NULL == tokens[tok].cb)
789 return(roff_errp(tree, *argv, tok, ERR_NOTSUP));
790
791 if (tokens[tok].sections && ROFF_MSEC_MAX != tree->section) {
792 i = 0;
793 while (ROFF_MSEC_MAX !=
794 (c = tokens[tok].sections[i++]))
795 if (c == tree->section)
796 break;
797 if (ROFF_MSEC_MAX == c) {
798 if ( ! roff_warn(tree, *argv, "`%s' is not a valid "
799 "macro in this manual section",
800 toknames[tok]))
801 return(0);
802 }
803 }
804
805 return((*tokens[tok].cb)(tok, tree, argv, ROFF_ENTER));
806 }
807
808
809 static int
810 roffnextopt(const struct rofftree *tree, int tok,
811 char ***in, char **val)
812 {
813 char *arg, **argv;
814 int v;
815
816 *val = NULL;
817 argv = *in;
818 assert(argv);
819
820 if (NULL == (arg = *argv))
821 return(-1);
822 if ('-' != *arg)
823 return(-1);
824
825 if (ROFF_ARGMAX == (v = rofffindarg(arg + 1))) {
826 if ( ! roff_warn(tree, arg, "argument-like parameter `%s' to "
827 "`%s'", arg, toknames[tok]))
828 return(ROFF_ARGMAX);
829 return(-1);
830 }
831
832 if ( ! roffargok(tok, v)) {
833 if ( ! roff_warn(tree, arg, "invalid argument parameter `%s' to "
834 "`%s'", tokargnames[v], toknames[tok]))
835 return(ROFF_ARGMAX);
836 return(-1);
837 }
838
839 if ( ! (ROFF_VALUE & tokenargs[v]))
840 return(v);
841
842 *in = ++argv;
843
844 if (NULL == *argv) {
845 (void)roff_err(tree, arg, "empty value of `%s' for `%s'",
846 tokargnames[v], toknames[tok]);
847 return(ROFF_ARGMAX);
848 }
849
850 return(v);
851 }
852
853
854 static int
855 roffpurgepunct(struct rofftree *tree, char **argv)
856 {
857 int i;
858
859 i = 0;
860 while (argv[i])
861 i++;
862 assert(i > 0);
863 if ( ! roffispunct(argv[--i]))
864 return(1);
865 while (i >= 0 && roffispunct(argv[i]))
866 i--;
867 i++;
868
869 /* LINTED */
870 while (argv[i])
871 if ( ! roffdata(tree, 0, argv[i++]))
872 return(0);
873 return(1);
874 }
875
876
877 static int
878 roffparseopts(struct rofftree *tree, int tok,
879 char ***args, int *argc, char **argv)
880 {
881 int i, c;
882 char *v;
883
884 i = 0;
885
886 while (-1 != (c = roffnextopt(tree, tok, args, &v))) {
887 if (ROFF_ARGMAX == c)
888 return(0);
889
890 argc[i] = c;
891 argv[i] = v;
892 i++;
893 *args = *args + 1;
894 }
895
896 argc[i] = ROFF_ARGMAX;
897 argv[i] = NULL;
898 return(1);
899 }
900
901
902 static int
903 roffdata(struct rofftree *tree, int space, char *buf)
904 {
905
906 if (0 == *buf)
907 return(1);
908 return((*tree->cb.roffdata)(tree->arg,
909 space != 0, tree->cur, buf));
910 }
911
912
913 /* ARGSUSED */
914 static int
915 roff_Dd(ROFFCALL_ARGS)
916 {
917 time_t t;
918 char *p, buf[32];
919 size_t sz;
920
921 if (ROFF_BODY & tree->state) {
922 assert( ! (ROFF_PRELUDE & tree->state));
923 assert(ROFF_PRELUDE_Dd & tree->state);
924 return(roff_text(tok, tree, argv, type));
925 }
926
927 assert(ROFF_PRELUDE & tree->state);
928 assert( ! (ROFF_BODY & tree->state));
929
930 if (ROFF_PRELUDE_Dd & tree->state)
931 return(roff_errp(tree, *argv, tok, ERR_PR_REP));
932 if (ROFF_PRELUDE_Dt & tree->state)
933 return(roff_errp(tree, *argv, tok, ERR_PR_OOO));
934
935 assert(NULL == tree->last);
936
937 argv++;
938
939 /*
940 * This is a bit complex because there are many forms the date
941 * can be in: it can be simply $Mdocdate: December 10 2008 $, $Mdocdate <date>$,
942 * or a raw date. Process accordingly.
943 */
944
945 if (0 == strcmp(*argv, "$Mdocdate: December 10 2008 $")) {
946 t = time(NULL);
947 if (NULL == localtime_r(&t, &tree->tm))
948 err(1, "localtime_r");
949 tree->state |= ROFF_PRELUDE_Dd;
950 return(1);
951 }
952
953 buf[0] = 0;
954 p = *argv;
955 sz = sizeof(buf);
956
957 if (0 != strcmp(*argv, "$Mdocdate:")) {
958 while (*argv) {
959 if (strlcat(buf, *argv++, sz) < sz)
960 continue;
961 return(roff_errp(tree, p, tok, ERR_BADARG));
962 }
963 if (strptime(buf, "%b%d,%Y", &tree->tm)) {
964 tree->state |= ROFF_PRELUDE_Dd;
965 return(1);
966 }
967 return(roff_errp(tree, p, tok, ERR_BADARG));
968 }
969
970 argv++;
971
972 while (*argv && **argv != '$') {
973 if (strlcat(buf, *argv++, sz) >= sz)
974 return(roff_errp(tree, p, tok, ERR_BADARG));
975 if (strlcat(buf, " ", sz) >= sz)
976 return(roff_errp(tree, p, tok, ERR_BADARG));
977 }
978
979 if (NULL == *argv)
980 return(roff_errp(tree, p, tok, ERR_BADARG));
981 if (NULL == strptime(buf, "%b %d %Y", &tree->tm))
982 return(roff_errp(tree, p, tok, ERR_BADARG));
983
984 tree->state |= ROFF_PRELUDE_Dd;
985 return(1);
986 }
987
988
989 /* ARGSUSED */
990 static int
991 roff_Dt(ROFFCALL_ARGS)
992 {
993 size_t sz;
994
995 if (ROFF_BODY & tree->state) {
996 assert( ! (ROFF_PRELUDE & tree->state));
997 assert(ROFF_PRELUDE_Dt & tree->state);
998 return(roff_text(tok, tree, argv, type));
999 }
1000
1001 assert(ROFF_PRELUDE & tree->state);
1002 assert( ! (ROFF_BODY & tree->state));
1003
1004 if ( ! (ROFF_PRELUDE_Dd & tree->state))
1005 return(roff_errp(tree, *argv, tok, ERR_PR_OOO));
1006 if (ROFF_PRELUDE_Dt & tree->state)
1007 return(roff_errp(tree, *argv, tok, ERR_PR_REP));
1008
1009 argv++;
1010 sz = sizeof(tree->title);
1011
1012 if (NULL == *argv)
1013 return(roff_errp(tree, *argv, tok, ERR_ARGGE2));
1014 if (strlcpy(tree->title, *argv, sz) >= sz)
1015 return(roff_errp(tree, *argv, tok, ERR_ARGLEN));
1016
1017 argv++;
1018 if (NULL == *argv)
1019 return(roff_errp(tree, *argv, tok, ERR_ARGGE2));
1020
1021 if (ROFF_MSEC_MAX == (tree->section = roff_msec(*argv)))
1022 return(roff_errp(tree, *argv, tok, ERR_BADARG));
1023
1024 argv++;
1025
1026 if (NULL == *argv) {
1027 switch (tree->section) {
1028 case(ROFF_MSEC_1):
1029 /* FALLTHROUGH */
1030 case(ROFF_MSEC_6):
1031 /* FALLTHROUGH */
1032 case(ROFF_MSEC_7):
1033 tree->volume = ROFF_VOL_URM;
1034 break;
1035 case(ROFF_MSEC_2):
1036 /* FALLTHROUGH */
1037 case(ROFF_MSEC_3):
1038 /* FALLTHROUGH */
1039 case(ROFF_MSEC_3p):
1040 /* FALLTHROUGH */
1041 case(ROFF_MSEC_4):
1042 /* FALLTHROUGH */
1043 case(ROFF_MSEC_5):
1044 tree->volume = ROFF_VOL_PRM;
1045 break;
1046 case(ROFF_MSEC_8):
1047 tree->volume = ROFF_VOL_PRM;
1048 break;
1049 case(ROFF_MSEC_9):
1050 tree->volume = ROFF_VOL_KM;
1051 break;
1052 case(ROFF_MSEC_UNASS):
1053 /* FALLTHROUGH */
1054 case(ROFF_MSEC_DRAFT):
1055 /* FALLTHROUGH */
1056 case(ROFF_MSEC_PAPER):
1057 tree->volume = ROFF_VOL_NONE;
1058 break;
1059 default:
1060 abort();
1061 /* NOTREACHED */
1062 }
1063 } else if (ROFF_VOL_MAX == (tree->volume = roff_vol(*argv)))
1064 return(roff_errp(tree, *argv, tok, ERR_BADARG));
1065
1066 assert(NULL == tree->last);
1067 tree->state |= ROFF_PRELUDE_Dt;
1068
1069 return(1);
1070 }
1071
1072
1073 static int
1074 roffsetname(struct rofftree *tree, char **ordp)
1075 {
1076 size_t sz;
1077
1078 assert(*ordp);
1079
1080 /* FIXME: not all sections can set this. */
1081
1082 if (NULL != *(ordp + 1))
1083 return(roff_errp(tree, *ordp, ROFF_Nm, ERR_ARGMNY));
1084
1085 sz = sizeof(tree->name);
1086 if (strlcpy(tree->name, *ordp, sz) >= sz)
1087 return(roff_errp(tree, *ordp, ROFF_Nm, ERR_ARGLEN));
1088
1089 return(1);
1090 }
1091
1092
1093 /* ARGSUSED */
1094 static int
1095 roff_Ns(ROFFCALL_ARGS)
1096 {
1097 int j, c, first;
1098 char *morep[1];
1099
1100 first = (*argv++ == tree->cur);
1101 morep[0] = NULL;
1102
1103 if ( ! roffspecial(tree, tok, *argv, NULL, NULL, 0, morep))
1104 return(0);
1105
1106 while (*argv) {
1107 if (ROFF_MAX != (c = rofffindcallable(*argv))) {
1108 if ( ! roffcall(tree, c, argv))
1109 return(0);
1110 break;
1111 }
1112
1113 if ( ! roffispunct(*argv)) {
1114 if ( ! roffdata(tree, 1, *argv++))
1115 return(0);
1116 continue;
1117 }
1118
1119 for (j = 0; argv[j]; j++)
1120 if ( ! roffispunct(argv[j]))
1121 break;
1122
1123 if (argv[j]) {
1124 if ( ! roffdata(tree, 0, *argv++))
1125 return(0);
1126 continue;
1127 }
1128
1129 break;
1130 }
1131
1132 if ( ! first)
1133 return(1);
1134
1135 return(roffpurgepunct(tree, argv));
1136 }
1137
1138
1139 /* ARGSUSED */
1140 static int
1141 roff_Os(ROFFCALL_ARGS)
1142 {
1143 char *p;
1144 size_t sz;
1145
1146 if (ROFF_BODY & tree->state) {
1147 assert( ! (ROFF_PRELUDE & tree->state));
1148 assert(ROFF_PRELUDE_Os & tree->state);
1149 return(roff_text(tok, tree, argv, type));
1150 }
1151
1152 assert(ROFF_PRELUDE & tree->state);
1153 if ( ! (ROFF_PRELUDE_Dt & tree->state) ||
1154 ! (ROFF_PRELUDE_Dd & tree->state))
1155 return(roff_errp(tree, *argv, tok, ERR_PR_OOO));
1156
1157 tree->os[0] = 0;
1158
1159 p = *++argv;
1160 sz = sizeof(tree->os);
1161
1162 while (*argv)
1163 if (strlcat(tree->os, *argv++, sz) >= sz)
1164 return(roff_errp(tree, p, tok, ERR_ARGLEN));
1165
1166 if (0 == tree->os[0])
1167 if (strlcpy(tree->os, "LOCAL", sz) >= sz)
1168 return(roff_errp(tree, p, tok, ERR_ARGLEN));
1169
1170 tree->state |= ROFF_PRELUDE_Os;
1171 tree->state &= ~ROFF_PRELUDE;
1172 tree->state |= ROFF_BODY;
1173
1174 assert(ROFF_MSEC_MAX != tree->section);
1175 assert(0 != tree->title[0]);
1176 assert(0 != tree->os[0]);
1177
1178 assert(NULL == tree->last);
1179
1180 return((*tree->cb.roffhead)(tree->arg, &tree->tm,
1181 tree->os, tree->title,
1182 tree->section, tree->volume));
1183 }
1184
1185
1186 /* ARGSUSED */
1187 static int
1188 roff_layout(ROFFCALL_ARGS)
1189 {
1190 int i, c, argcp[ROFF_MAXLINEARG];
1191 char *argvp[ROFF_MAXLINEARG];
1192
1193 /*
1194 * The roff_layout function is for multi-line macros. A layout
1195 * has a start and end point, which is either declared
1196 * explicitly or implicitly. An explicit start and end is
1197 * embodied by `.Bl' and `.El', with the former being the start
1198 * and the latter being an end. The `.Sh' and `.Ss' tags, on
1199 * the other hand, are implicit. The scope of a layout is the
1200 * space between start and end. Explicit layouts may not close
1201 * out implicit ones and vice versa; implicit layouts may close
1202 * out other implicit layouts.
1203 */
1204
1205 assert( ! (ROFF_CALLABLE & tokens[tok].flags));
1206
1207 if (ROFF_PRELUDE & tree->state)
1208 return(roff_errp(tree, *argv, tok, ERR_NOT_PR));
1209
1210 if (ROFF_EXIT == type) {
1211 roffnode_free(tree);
1212 if ( ! (*tree->cb.roffblkbodyout)(tree->arg, tok))
1213 return(0);
1214 return((*tree->cb.roffblkout)(tree->arg, tok));
1215 }
1216
1217 argv++;
1218 assert( ! (ROFF_CALLABLE & tokens[tok].flags));
1219
1220 if ( ! roffparseopts(tree, tok, &argv, argcp, argvp))
1221 return(0);
1222 if (NULL == roffnode_new(tok, tree))
1223 return(0);
1224
1225 /*
1226 * Layouts have two parts: the layout body and header. The
1227 * layout header is the trailing text of the line macro, while
1228 * the layout body is everything following until termination.
1229 * Example:
1230 *
1231 * .It Fl f ) ;
1232 * Bar.
1233 *
1234 * ...Produces...
1235 *
1236 * <block>
1237 * <head>
1238 * <!Fl f!> ;
1239 * </head>
1240 *
1241 * <body>
1242 * Bar.
1243 * </body>
1244 * </block>
1245 */
1246
1247 if ( ! (*tree->cb.roffblkin)(tree->arg, tok, argcp,
1248 (const char **)argvp))
1249 return(0);
1250
1251 /* +++ Begin run macro-specific hooks over argv. */
1252
1253 switch (tok) {
1254 case (ROFF_Sh):
1255 if (NULL == *argv) {
1256 argv--;
1257 return(roff_errp(tree, *argv, tok, ERR_ARGGE1));
1258 }
1259
1260 tree->csec = roff_sec((const char **)argv);
1261
1262 if ( ! (ROFFSec_OTHER & tree->csec) &&
1263 tree->asec & tree->csec)
1264 if ( ! roff_warn(tree, *argv, "section repeated"))
1265 return(0);
1266
1267 if (0 == tree->asec && ! (ROFFSec_NAME & tree->csec))
1268 return(roff_err(tree, *argv, "`NAME' section "
1269 "must be first"));
1270 if ( ! roffchecksec(tree, *argv, tree->csec))
1271 return(0);
1272
1273 tree->asec |= tree->csec;
1274 break;
1275 default:
1276 break;
1277 }
1278
1279 /* --- End run macro-specific hooks over argv. */
1280
1281 if (NULL == *argv)
1282 return((*tree->cb.roffblkbodyin)
1283 (tree->arg, tok, argcp,
1284 (const char **)argvp));
1285
1286 if ( ! (*tree->cb.roffblkheadin)(tree->arg, tok, argcp,
1287 (const char **)argvp))
1288 return(0);
1289
1290 /*
1291 * If there are no parsable parts, then write remaining tokens
1292 * into the layout header and exit.
1293 */
1294
1295 if ( ! (ROFF_PARSED & tokens[tok].flags)) {
1296 i = 0;
1297 while (*argv)
1298 if ( ! roffdata(tree, i++, *argv++))
1299 return(0);
1300
1301 if ( ! (*tree->cb.roffblkheadout)(tree->arg, tok))
1302 return(0);
1303 return((*tree->cb.roffblkbodyin)(tree->arg, tok, argcp,
1304 (const char **)argvp));
1305 }
1306
1307 /*
1308 * Parsable elements may be in the header (or be the header, for
1309 * that matter). Follow the regular parsing rules for these.
1310 */
1311
1312 i = 0;
1313 while (*argv) {
1314 if (ROFF_MAX == (c = rofffindcallable(*argv))) {
1315 assert(tree->arg);
1316 if ( ! roffdata(tree, i++, *argv++))
1317 return(0);
1318 continue;
1319 }
1320 if ( ! roffcall(tree, c, argv))
1321 return(0);
1322 break;
1323 }
1324
1325 /*
1326 * If there's trailing punctuation in the header, then write it
1327 * out now. Here we mimic the behaviour of a line-dominant text
1328 * macro.
1329 */
1330
1331 if (NULL == *argv) {
1332 if ( ! (*tree->cb.roffblkheadout)(tree->arg, tok))
1333 return(0);
1334 return((*tree->cb.roffblkbodyin)
1335 (tree->arg, tok, argcp,
1336 (const char **)argvp));
1337 }
1338
1339 /*
1340 * Expensive. Scan to the end of line then work backwards until
1341 * a token isn't punctuation.
1342 */
1343
1344 if ( ! roffpurgepunct(tree, argv))
1345 return(0);
1346 if ( ! (*tree->cb.roffblkheadout)(tree->arg, tok))
1347 return(0);
1348 return((*tree->cb.roffblkbodyin)(tree->arg,
1349 tok, argcp, (const char **)argvp));
1350 }
1351
1352
1353 /* ARGSUSED */
1354 static int
1355 roff_ordered(ROFFCALL_ARGS)
1356 {
1357 int i, first, c, argcp[ROFF_MAXLINEARG];
1358 char *ordp[ROFF_MAXLINEARG], *p,
1359 *argvp[ROFF_MAXLINEARG];
1360
1361 /*
1362 * Ordered macros pass their arguments directly to handlers,
1363 * instead of considering it free-form text. Thus, the
1364 * following macro looks as follows:
1365 *
1366 * .Xr foo 1 ) ,
1367 *
1368 * .Xr arg1 arg2 punctuation
1369 */
1370
1371 if (ROFF_PRELUDE & tree->state)
1372 return(roff_errp(tree, *argv, tok, ERR_NOT_PR));
1373
1374 first = (*argv == tree->cur);
1375 p = *argv++;
1376 ordp[0] = NULL;
1377
1378 if ( ! roffparseopts(tree, tok, &argv, argcp, argvp))
1379 return(0);
1380
1381 if (NULL == *argv)
1382 return(roffspecial(tree, tok, p, argcp,
1383 (const char **)argvp, 0, ordp));
1384
1385 i = 0;
1386 while (*argv && i < ROFF_MAXLINEARG) {
1387 c = ROFF_PARSED & tokens[tok].flags ?
1388 rofffindcallable(*argv) : ROFF_MAX;
1389
1390 if (ROFF_MAX == c && ! roffispunct(*argv)) {
1391 ordp[i++] = *argv++;
1392 continue;
1393 }
1394 ordp[i] = NULL;
1395
1396 if (ROFF_MAX == c)
1397 break;
1398
1399 if ( ! roffspecial(tree, tok, p, argcp,
1400 (const char **)argvp,
1401 (size_t)i, ordp))
1402 return(0);
1403
1404 return(roffcall(tree, c, argv));
1405 }
1406
1407 assert(i != ROFF_MAXLINEARG);
1408 ordp[i] = NULL;
1409
1410 if ( ! roffspecial(tree, tok, p, argcp,
1411 (const char**)argvp,
1412 (size_t)i, ordp))
1413 return(0);
1414
1415 /* FIXME: error if there's stuff after the punctuation. */
1416
1417 if ( ! first || NULL == *argv)
1418 return(1);
1419
1420 return(roffpurgepunct(tree, argv));
1421 }
1422
1423
1424 /* ARGSUSED */
1425 static int
1426 roff_text(ROFFCALL_ARGS)
1427 {
1428 int i, j, first, c, argcp[ROFF_MAXLINEARG];
1429 char *argvp[ROFF_MAXLINEARG];
1430
1431 /*
1432 * Text macros are similar to special tokens, except that
1433 * arguments are instead flushed as pure data: we're only
1434 * concerned with the macro and its arguments. Example:
1435 *
1436 * .Fl v W f ;
1437 *
1438 * ...Produces...
1439 *
1440 * <fl> v W f </fl> ;
1441 */
1442
1443 if (ROFF_PRELUDE & tree->state)
1444 return(roff_errp(tree, *argv, tok, ERR_NOT_PR));
1445
1446 first = (*argv == tree->cur);
1447 argv++;
1448
1449 if ( ! roffparseopts(tree, tok, &argv, argcp, argvp))
1450 return(0);
1451 if ( ! (*tree->cb.roffin)(tree->arg, tok, argcp,
1452 (const char **)argvp))
1453 return(0);
1454 if (NULL == *argv)
1455 return((*tree->cb.roffout)(tree->arg, tok));
1456
1457 if ( ! (ROFF_PARSED & tokens[tok].flags)) {
1458 i = 0;
1459 while (*argv)
1460 if ( ! roffdata(tree, i++, *argv++))
1461 return(0);
1462 return((*tree->cb.roffout)(tree->arg, tok));
1463 }
1464
1465 /*
1466 * Deal with punctuation. Ugly. Work ahead until we encounter
1467 * terminating punctuation. If we encounter it and all
1468 * subsequent tokens are punctuation, then stop processing (the
1469 * line-dominant macro will print these tokens after closure).
1470 * If the punctuation is followed by non-punctuation, then close
1471 * and re-open our scope, then continue.
1472 */
1473
1474 i = 0;
1475 while (*argv) {
1476 if (ROFF_MAX != (c = rofffindcallable(*argv))) {
1477 if ( ! (ROFF_LSCOPE & tokens[tok].flags))
1478 if ( ! (*tree->cb.roffout)(tree->arg, tok))
1479 return(0);
1480
1481 if ( ! roffcall(tree, c, argv))
1482 return(0);
1483 if (ROFF_LSCOPE & tokens[tok].flags)
1484 if ( ! (*tree->cb.roffout)(tree->arg, tok))
1485 return(0);
1486 break;
1487 }
1488
1489 if ( ! roffispunct(*argv)) {
1490 if ( ! roffdata(tree, i++, *argv++))
1491 return(0);
1492 continue;
1493 }
1494
1495 i = 1;
1496 for (j = 0; argv[j]; j++)
1497 if ( ! roffispunct(argv[j]))
1498 break;
1499
1500 if (argv[j]) {
1501 if (ROFF_LSCOPE & tokens[tok].flags) {
1502 if ( ! roffdata(tree, 0, *argv++))
1503 return(0);
1504 continue;
1505 }
1506 if ( ! (*tree->cb.roffout)(tree->arg, tok))
1507 return(0);
1508 if ( ! roffdata(tree, 0, *argv++))
1509 return(0);
1510 if ( ! (*tree->cb.roffin)(tree->arg, tok,
1511 argcp,
1512 (const char **)argvp))
1513 return(0);
1514
1515 i = 0;
1516 continue;
1517 }
1518
1519 if ( ! (*tree->cb.roffout)(tree->arg, tok))
1520 return(0);
1521 break;
1522 }
1523
1524 if (NULL == *argv)
1525 return((*tree->cb.roffout)(tree->arg, tok));
1526 if ( ! first)
1527 return(1);
1528
1529 return(roffpurgepunct(tree, argv));
1530 }
1531
1532
1533 /* ARGSUSED */
1534 static int
1535 roff_noop(ROFFCALL_ARGS)
1536 {
1537
1538 return(1);
1539 }
1540
1541
1542 /* ARGSUSED */
1543 static int
1544 roff_depr(ROFFCALL_ARGS)
1545 {
1546
1547 return(roff_errp(tree, *argv, tok, ERR_DEPREC));
1548 }
1549
1550
1551 static int
1552 roff_warnp(const struct rofftree *tree, const char *pos,
1553 int tok, enum rofferr type)
1554 {
1555 char *p;
1556
1557 switch (type) {
1558 case (WRN_SECORD):
1559 p = "section at `%s' out of order";
1560 break;
1561 default:
1562 abort();
1563 /* NOTREACHED */
1564 }
1565
1566 return(roff_warn(tree, pos, p, toknames[tok]));
1567 }
1568
1569
1570 static int
1571 roff_warn(const struct rofftree *tree, const char *pos, char *fmt, ...)
1572 {
1573 va_list ap;
1574 char buf[128];
1575
1576 va_start(ap, fmt);
1577 (void)vsnprintf(buf, sizeof(buf), fmt, ap);
1578 va_end(ap);
1579
1580 return((*tree->cb.roffmsg)(tree->arg,
1581 ROFF_WARN, tree->cur, pos, buf));
1582 }
1583
1584
1585 static int
1586 roff_errp(const struct rofftree *tree, const char *pos,
1587 int tok, enum rofferr type)
1588 {
1589 char *p;
1590
1591 switch (type) {
1592 case (ERR_ARGEQ1):
1593 p = "`%s' expects exactly one argument";
1594 break;
1595 case (ERR_ARGEQ0):
1596 p = "`%s' expects exactly zero arguments";
1597 break;
1598 case (ERR_ARGGE1):
1599 p = "`%s' expects one or more arguments";
1600 break;
1601 case (ERR_ARGGE2):
1602 p = "`%s' expects two or more arguments";
1603 break;
1604 case (ERR_BADARG):
1605 p = "invalid argument for `%s'";
1606 break;
1607 case (ERR_NOTSUP):
1608 p = "macro `%s' is not supported";
1609 break;
1610 case(ERR_PR_OOO):
1611 p = "prelude macro `%s' is out of order";
1612 break;
1613 case(ERR_PR_REP):
1614 p = "prelude macro `%s' repeated";
1615 break;
1616 case(ERR_ARGLEN):
1617 p = "macro argument for `%s' is too long";
1618 break;
1619 case(ERR_DEPREC):
1620 p = "macro `%s' is deprecated";
1621 break;
1622 case(ERR_NOT_PR):
1623 p = "macro `%s' disallowed in prelude";
1624 break;
1625 case(ERR_ARGMNY):
1626 p = "too many arguments for macro `%s'";
1627 break;
1628 default:
1629 abort();
1630 /* NOTREACHED */
1631 }
1632
1633 return(roff_err(tree, pos, p, toknames[tok]));
1634 }
1635
1636
1637 static int
1638 roff_err(const struct rofftree *tree, const char *pos, char *fmt, ...)
1639 {
1640 va_list ap;
1641 char buf[128];
1642
1643 va_start(ap, fmt);
1644 if (-1 == vsnprintf(buf, sizeof(buf), fmt, ap))
1645 err(1, "vsnprintf");
1646 va_end(ap);
1647
1648 return((*tree->cb.roffmsg)
1649 (tree->arg, ROFF_ERROR, tree->cur, pos, buf));
1650 }
1651