]>
git.cameronkatri.com Git - mandoc.git/blob - roff.c
1 /* $Id: roff.c,v 1.62 2008/12/10 13:41:59 kristaps Exp $ */
3 * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
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
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.
19 #include <sys/param.h>
20 #include <sys/types.h>
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 /* FIXME: Bl -diag supposed to ignore callable children. */
44 int tok
; /* Token id. */
45 struct roffnode
*parent
; /* Parent (or NULL). */
49 ERR_ARGEQ1
, /* Macro requires arg == 1. */
50 ERR_ARGEQ0
, /* Macro requires arg == 0. */
51 ERR_ARGGE1
, /* Macro requires arg >= 1. */
52 ERR_ARGGE2
, /* Macro requires arg >= 2. */
53 ERR_ARGLEN
, /* Macro argument too long. */
54 ERR_BADARG
, /* Macro has bad arg. */
55 ERR_ARGMNY
, /* Too many macro arguments. */
56 ERR_NOTSUP
, /* Macro not supported. */
57 ERR_DEPREC
, /* Macro deprecated. */
58 ERR_PR_OOO
, /* Prelude macro bad order. */
59 ERR_PR_REP
, /* Prelude macro repeated. */
60 ERR_NOT_PR
, /* Not allowed in prelude. */
61 WRN_SECORD
/* Sections out-of-order. */
65 struct roffnode
*last
; /* Last parsed node. */
66 char *cur
; /* Line start. */
67 struct tm tm
; /* `Dd' results. */
68 char name
[64]; /* `Nm' results. */
69 char os
[64]; /* `Os' results. */
70 char title
[64]; /* `Dt' results. */
71 enum roffmsec section
;
73 struct roffcb cb
; /* Callbacks. */
74 void *arg
; /* Callbacks' arg. */
75 int csec
; /* Current section. */
76 int asec
; /* Thus-far sections. */
79 static struct roffnode
*roffnode_new(int, struct rofftree
*);
80 static void roffnode_free(struct rofftree
*);
81 static int roff_warn(const struct rofftree
*,
82 const char *, char *, ...);
83 static int roff_warnp(const struct rofftree
*,
84 const char *, int, enum rofferr
);
85 static int roff_err(const struct rofftree
*,
86 const char *, char *, ...);
87 static int roff_errp(const struct rofftree
*,
88 const char *, int, enum rofferr
);
89 static int roffpurgepunct(struct rofftree
*, char **);
90 static int roffscan(int, const int *);
91 static int rofffindtok(const char *);
92 static int rofffindarg(const char *);
93 static int rofffindcallable(const char *);
94 static int roffispunct(const char *);
95 static int roffchecksec(struct rofftree
*,
96 const char *, int, int);
97 static int roffargs(const struct rofftree
*,
98 int, char *, char **);
99 static int roffargok(int, int);
100 static int roffnextopt(const struct rofftree
*,
101 int, char ***, char **);
102 static int roffparseopts(struct rofftree
*, int,
103 char ***, int *, char **);
104 static int roffcall(struct rofftree
*, int, char **);
105 static int roffexit(struct rofftree
*, int);
106 static int roffparse(struct rofftree
*, char *);
107 static int textparse(struct rofftree
*, char *);
108 static int roffdata(struct rofftree
*, int, char *);
109 static int roffspecial(struct rofftree
*, int,
110 const char *, const int *,
111 const char **, size_t, char **);
112 static int roffsetname(struct rofftree
*, char **);
115 extern size_t strlcat(char *, const char *, size_t);
116 extern size_t strlcpy(char *, const char *, size_t);
117 extern int vsnprintf(char *, size_t,
118 const char *, va_list);
119 extern char *strptime(const char *, const char *,
124 roff_free(struct rofftree
*tree
, int flush
)
136 if ( ! (ROFFSec_NAME
& tree
->asec
)) {
137 (void)roff_err(tree
, NULL
, "missing `NAME' section");
139 } else if ( ! (ROFFSec_NMASK
& tree
->asec
))
140 (void)roff_warn(tree
, NULL
, "missing suggested `NAME', "
141 "`SYNOPSIS', `DESCRIPTION' sections");
143 for (n
= tree
->last
; n
; n
= n
->parent
) {
144 if (0 != tokens
[n
->tok
].ctx
)
146 (void)roff_err(tree
, NULL
, "closing explicit scope "
147 "`%s'", toknames
[n
->tok
]);
153 if ( ! roffexit(tree
, t
))
157 if ( ! (*tree
->cb
.rofftail
)(tree
->arg
, &tree
->tm
,
158 tree
->os
, tree
->title
,
159 tree
->section
, tree
->volume
))
171 return(error
? 0 : 1);
176 roff_alloc(const struct roffcb
*cb
, void *args
)
178 struct rofftree
*tree
;
183 if (NULL
== (tree
= calloc(1, sizeof(struct rofftree
))))
187 tree
->section
= ROFF_MSEC_MAX
;
189 (void)memcpy(&tree
->cb
, cb
, sizeof(struct roffcb
));
196 roff_engine(struct rofftree
*tree
, char *buf
)
203 return(roff_err(tree
, buf
, "blank line"));
204 else if ('.' != *buf
)
205 return(textparse(tree
, buf
));
207 return(roffparse(tree
, buf
));
212 textparse(struct rofftree
*tree
, char *buf
)
216 /* TODO: literal parsing. */
218 if ( ! (ROFFSec_NAME
& tree
->asec
))
219 return(roff_err(tree
, buf
, "data before `NAME' section"));
223 while (*buf
&& isspace(*buf
))
231 while (*buf
&& ! isspace(*buf
))
236 if ( ! roffdata(tree
, 1, bufp
))
241 if ( ! roffdata(tree
, 1, bufp
))
251 roffargs(const struct rofftree
*tree
,
252 int tok
, char *buf
, char **argv
)
257 assert(tok
>= 0 && tok
< ROFF_MAX
);
263 * This is an ugly little loop. It parses a line into
264 * space-delimited tokens. If a quote mark is encountered, a
265 * token is alloted the entire quoted text. If whitespace is
266 * escaped, it's included in the prior alloted token.
270 for (i
= 0; *buf
&& i
< ROFF_MAXLINEARG
; i
++) {
273 while (*buf
&& '\"' != *buf
)
276 return(roff_err(tree
, argv
[i
],
277 "unclosed quote in arg list"));
281 if ( ! isspace(*buf
)) {
285 if (*(buf
- 1) == '\\') {
295 while (*buf
&& isspace(*buf
))
300 if (ROFF_MAXLINEARG
== i
&& *buf
)
301 return(roff_err(tree
, p
, "too many args"));
309 roffscan(int tok
, const int *tokv
)
315 for ( ; ROFF_MAX
!= *tokv
; tokv
++)
324 roffparse(struct rofftree
*tree
, char *buf
)
328 char *argv
[ROFF_MAXLINEARG
];
331 if (0 != *buf
&& 0 != *(buf
+ 1) && 0 != *(buf
+ 2))
332 if (0 == strncmp(buf
, ".\\\"", 3))
335 if (ROFF_MAX
== (tok
= rofffindtok(buf
+ 1)))
336 return(roff_err(tree
, buf
, "bogus line macro"));
337 else if ( ! roffargs(tree
, tok
, buf
, argv
))
340 argvp
= (char **)argv
;
343 * Prelude macros break some assumptions, so branch now.
346 if ( ! (ROFFSec_PR_Dd
& tree
->asec
)) {
347 assert(NULL
== tree
->last
);
348 return(roffcall(tree
, tok
, argvp
));
352 * First check that our possible parents and parent's possible
353 * children are satisfied.
356 if (tree
->last
&& ! roffscan
357 (tree
->last
->tok
, tokens
[tok
].parents
))
358 return(roff_err(tree
, *argvp
, "`%s' has invalid "
359 "parent `%s'", toknames
[tok
],
360 toknames
[tree
->last
->tok
]));
362 if (tree
->last
&& ! roffscan
363 (tok
, tokens
[tree
->last
->tok
].children
))
364 return(roff_err(tree
, *argvp
, "`%s' has invalid "
365 "child `%s'", toknames
[tok
],
366 toknames
[tree
->last
->tok
]));
369 * Branch if we're not a layout token.
372 if (ROFF_LAYOUT
!= tokens
[tok
].type
)
373 return(roffcall(tree
, tok
, argvp
));
374 if (0 == tokens
[tok
].ctx
)
375 return(roffcall(tree
, tok
, argvp
));
378 * First consider implicit-end tags, like as follows:
381 * In this, we want to close the scope of the NAME section. If
382 * there's an intermediary implicit-end tag, such as
386 * then it must be closed as well.
389 if (tok
== tokens
[tok
].ctx
) {
391 * First search up to the point where we must close.
392 * If one doesn't exist, then we can open a new scope.
395 for (n
= tree
->last
; n
; n
= n
->parent
) {
396 assert(0 == tokens
[n
->tok
].ctx
||
397 n
->tok
== tokens
[n
->tok
].ctx
);
400 if (ROFF_SHALLOW
& tokens
[tok
].flags
) {
404 if (tokens
[n
->tok
].ctx
== n
->tok
)
406 return(roff_err(tree
, *argv
, "`%s' breaks "
407 "scope of prior`%s'",
413 * Create a new scope, as no previous one exists to
418 return(roffcall(tree
, tok
, argvp
));
421 * Close out all intermediary scoped blocks, then hang
422 * the current scope from our predecessor's parent.
427 if ( ! roffexit(tree
, t
))
431 return(roffcall(tree
, tok
, argvp
));
435 * Now consider explicit-end tags, where we want to close back
436 * to a specific tag. Example:
440 * In this, the `El' tag closes out the scope of `Bl'.
443 assert(tok
!= tokens
[tok
].ctx
&& 0 != tokens
[tok
].ctx
);
446 for (n
= tree
->last
; n
; n
= n
->parent
)
447 if (n
->tok
!= tokens
[tok
].ctx
) {
448 if (n
->tok
== tokens
[n
->tok
].ctx
)
450 return(roff_err(tree
, *argv
, "`%s' breaks "
451 "scope of prior `%s'",
458 return(roff_err(tree
, *argv
, "`%s' has no starting "
459 "tag `%s'", toknames
[tok
],
460 toknames
[tokens
[tok
].ctx
]));
465 if ( ! roffexit(tree
, t
))
467 } while (t
!= tokens
[tok
].ctx
);
474 rofffindarg(const char *name
)
478 /* FIXME: use a table, this is slow but ok for now. */
481 for (i
= 0; i
< ROFF_ARGMAX
; i
++)
483 if (0 == strcmp(name
, tokargnames
[i
]))
491 rofffindtok(const char *buf
)
496 for (i
= 0; *buf
&& ! isspace(*buf
) && i
< 3; i
++, buf
++)
504 /* FIXME: use a table, this is slow but ok for now. */
507 for (i
= 0; i
< ROFF_MAX
; i
++)
509 if (0 == strcmp(toknames
[i
], token
))
517 roffchecksec(struct rofftree
*tree
,
518 const char *start
, int sec
, int fail
)
525 if (ROFFSec_PR_Dd
& tree
->asec
)
529 if (ROFFSec_PR_Dt
& tree
->asec
)
533 if (ROFFSec_PR_Os
& tree
->asec
)
537 if (ROFFSec_NAME
& tree
->asec
)
541 if (ROFFSec_SYNOP
& tree
->asec
)
544 case(ROFFSec_RETVAL
):
545 if (ROFFSec_DESC
& tree
->asec
)
549 if (ROFFSec_RETVAL
& tree
->asec
)
553 if (ROFFSec_ENV
& tree
->asec
)
557 if (ROFFSec_FILES
& tree
->asec
)
561 if (ROFFSec_EX
& tree
->asec
)
565 if (ROFFSec_DIAG
& tree
->asec
)
568 case(ROFFSec_SEEALSO
):
569 if (ROFFSec_ERRS
& tree
->asec
)
573 if (ROFFSec_SEEALSO
& tree
->asec
)
577 if (ROFFSec_STAND
& tree
->asec
)
581 if (ROFFSec_HIST
& tree
->asec
)
584 case(ROFFSec_CAVEATS
):
585 if (ROFFSec_AUTH
& tree
->asec
)
589 if (ROFFSec_CAVEATS
& tree
->asec
)
598 return(roff_warnp(tree
, start
, ROFF_Sh
, WRN_SECORD
));
603 roffispunct(const char *p
)
645 rofffindcallable(const char *name
)
649 if (ROFF_MAX
== (c
= rofffindtok(name
)))
651 assert(c
>= 0 && c
< ROFF_MAX
);
652 return(ROFF_CALLABLE
& tokens
[c
].flags
? c
: ROFF_MAX
);
656 static struct roffnode
*
657 roffnode_new(int tokid
, struct rofftree
*tree
)
661 if (NULL
== (p
= malloc(sizeof(struct roffnode
))))
665 p
->parent
= tree
->last
;
673 roffargok(int tokid
, int argid
)
677 if (NULL
== (c
= tokens
[tokid
].args
))
680 for ( ; ROFF_ARGMAX
!= *c
; c
++)
689 roffnode_free(struct rofftree
*tree
)
696 tree
->last
= tree
->last
->parent
;
702 roffspecial(struct rofftree
*tree
, int tok
, const char *start
,
703 const int *argc
, const char **argv
,
704 size_t sz
, char **ordp
)
711 if (ROFF_ATT_MAX
!= roff_att(*ordp
))
713 return(roff_errp(tree
, *ordp
, tok
, ERR_BADARG
));
718 if (ROFF_MSEC_MAX
!= roff_msec(ordp
[1]))
720 if ( ! roff_warn(tree
, start
, "invalid `%s' manual "
721 "section", toknames
[tok
]))
731 return(roff_errp(tree
, start
, tok
, ERR_ARGGE1
));
735 if (0 != tree
->name
[0]) {
736 ordp
[0] = tree
->name
;
740 return(roff_err(tree
, start
, "`Nm' not set"));
741 } else if ( ! roffsetname(tree
, ordp
))
750 return(roff_errp(tree
, start
, tok
, ERR_ARGEQ1
));
754 return(roff_errp(tree
, start
, tok
, ERR_ARGEQ1
));
755 else if (0 == strcmp(ordp
[0], "on") ||
756 0 == strcmp(ordp
[0], "off"))
758 return(roff_errp(tree
, *ordp
, tok
, ERR_BADARG
));
767 return(roff_errp(tree
, start
, tok
, ERR_ARGEQ0
));
772 return((*tree
->cb
.roffspecial
)(tree
->arg
, tok
, tree
->cur
,
773 argc
, argv
, (const char **)ordp
));
778 roffexit(struct rofftree
*tree
, int tok
)
781 assert(tokens
[tok
].cb
);
782 return((*tokens
[tok
].cb
)(tok
, tree
, NULL
, ROFF_EXIT
));
787 roffcall(struct rofftree
*tree
, int tok
, char **argv
)
792 if (NULL
== tokens
[tok
].cb
)
793 return(roff_errp(tree
, *argv
, tok
, ERR_NOTSUP
));
795 if (tokens
[tok
].sections
&& ROFF_MSEC_MAX
!= tree
->section
) {
797 while (ROFF_MSEC_MAX
!=
798 (c
= tokens
[tok
].sections
[i
++]))
799 if (c
== tree
->section
)
801 if (ROFF_MSEC_MAX
== c
) {
802 if ( ! roff_warn(tree
, *argv
, "`%s' is not a valid "
803 "macro in this manual section",
809 return((*tokens
[tok
].cb
)(tok
, tree
, argv
, ROFF_ENTER
));
814 roffnextopt(const struct rofftree
*tree
, int tok
,
815 char ***in
, char **val
)
824 if (NULL
== (arg
= *argv
))
829 if (ROFF_ARGMAX
== (v
= rofffindarg(arg
+ 1))) {
830 if ( ! roff_warn(tree
, arg
, "argument-like parameter `%s' to "
831 "`%s'", arg
, toknames
[tok
]))
836 if ( ! roffargok(tok
, v
)) {
837 if ( ! roff_warn(tree
, arg
, "invalid argument parameter `%s' to "
838 "`%s'", tokargnames
[v
], toknames
[tok
]))
843 if ( ! (ROFF_VALUE
& tokenargs
[v
]))
849 (void)roff_err(tree
, arg
, "empty value of `%s' for `%s'",
850 tokargnames
[v
], toknames
[tok
]);
859 roffpurgepunct(struct rofftree
*tree
, char **argv
)
867 if ( ! roffispunct(argv
[--i
]))
869 while (i
>= 0 && roffispunct(argv
[i
]))
875 if ( ! roffdata(tree
, 0, argv
[i
++]))
882 roffparseopts(struct rofftree
*tree
, int tok
,
883 char ***args
, int *argc
, char **argv
)
890 while (-1 != (c
= roffnextopt(tree
, tok
, args
, &v
))) {
891 if (ROFF_ARGMAX
== c
)
900 argc
[i
] = ROFF_ARGMAX
;
907 roffdata(struct rofftree
*tree
, int space
, char *buf
)
912 return((*tree
->cb
.roffdata
)(tree
->arg
,
913 space
!= 0, tree
->cur
, buf
));
919 roff_Dd(ROFFCALL_ARGS
)
925 if (ROFFSec_PR_Os
& tree
->asec
)
926 return(roff_text(tok
, tree
, argv
, type
));
927 if (ROFFSec_PR_Dd
& tree
->asec
)
928 return(roff_errp(tree
, *argv
, tok
, ERR_PR_REP
));
929 if ( ! roffchecksec(tree
, *argv
, ROFFSec_PR_Dd
, 1))
930 return(roff_errp(tree
, *argv
, tok
, ERR_PR_OOO
));
932 assert(NULL
== tree
->last
);
934 tree
->asec
|= (tree
->csec
= ROFFSec_PR_Dd
);
937 * This is a bit complex because there are many forms the date
938 * can be in: it can be simply $Mdocdate: December 10 2008 $, $Mdocdate <date>$,
939 * or a raw date. Process accordingly.
942 if (0 == strcmp(*argv
, "$Mdocdate: December 10 2008 $")) {
944 if (NULL
== localtime_r(&t
, &tree
->tm
))
945 err(1, "localtime_r");
953 if (0 != strcmp(*argv
, "$Mdocdate:")) {
955 if (strlcat(buf
, *argv
++, sz
) < sz
)
957 return(roff_errp(tree
, p
, tok
, ERR_BADARG
));
959 if (strptime(buf
, "%b%d,%Y", &tree
->tm
))
961 return(roff_errp(tree
, p
, tok
, ERR_BADARG
));
966 while (*argv
&& **argv
!= '$') {
967 if (strlcat(buf
, *argv
++, sz
) >= sz
)
968 return(roff_errp(tree
, p
, tok
, ERR_BADARG
));
969 if (strlcat(buf
, " ", sz
) >= sz
)
970 return(roff_errp(tree
, p
, tok
, ERR_BADARG
));
974 return(roff_errp(tree
, p
, tok
, ERR_BADARG
));
975 if (NULL
== strptime(buf
, "%b %d %Y", &tree
->tm
))
976 return(roff_errp(tree
, p
, tok
, ERR_BADARG
));
984 roff_Dt(ROFFCALL_ARGS
)
988 if (ROFFSec_PR_Os
& tree
->asec
)
989 return(roff_text(tok
, tree
, argv
, type
));
990 if (ROFFSec_PR_Dt
& tree
->asec
)
991 return(roff_errp(tree
, *argv
, tok
, ERR_PR_REP
));
992 if ( ! roffchecksec(tree
, *argv
, ROFFSec_PR_Dt
, 1))
993 return(roff_errp(tree
, *argv
, tok
, ERR_PR_OOO
));
996 tree
->asec
|= (tree
->csec
= ROFFSec_PR_Dt
);
997 sz
= sizeof(tree
->title
);
1000 return(roff_errp(tree
, *argv
, tok
, ERR_ARGGE2
));
1001 if (strlcpy(tree
->title
, *argv
, sz
) >= sz
)
1002 return(roff_errp(tree
, *argv
, tok
, ERR_ARGLEN
));
1006 return(roff_errp(tree
, *argv
, tok
, ERR_ARGGE2
));
1008 if (ROFF_MSEC_MAX
== (tree
->section
= roff_msec(*argv
)))
1009 return(roff_errp(tree
, *argv
, tok
, ERR_BADARG
));
1013 if (NULL
== *argv
) {
1014 switch (tree
->section
) {
1020 tree
->volume
= ROFF_VOL_URM
;
1031 tree
->volume
= ROFF_VOL_PRM
;
1034 tree
->volume
= ROFF_VOL_PRM
;
1037 tree
->volume
= ROFF_VOL_KM
;
1039 case(ROFF_MSEC_UNASS
):
1041 case(ROFF_MSEC_DRAFT
):
1043 case(ROFF_MSEC_PAPER
):
1044 tree
->volume
= ROFF_VOL_NONE
;
1050 } else if (ROFF_VOL_MAX
== (tree
->volume
= roff_vol(*argv
)))
1051 return(roff_errp(tree
, *argv
, tok
, ERR_BADARG
));
1053 assert(NULL
== tree
->last
);
1060 roffsetname(struct rofftree
*tree
, char **ordp
)
1066 /* FIXME: not all sections can set this. */
1068 if (NULL
!= *(ordp
+ 1))
1069 return(roff_errp(tree
, *ordp
, ROFF_Nm
, ERR_ARGMNY
));
1071 sz
= sizeof(tree
->name
);
1072 if (strlcpy(tree
->name
, *ordp
, sz
) >= sz
)
1073 return(roff_errp(tree
, *ordp
, ROFF_Nm
, ERR_ARGLEN
));
1081 roff_Ns(ROFFCALL_ARGS
)
1086 first
= (*argv
++ == tree
->cur
);
1089 if ( ! roffspecial(tree
, tok
, *argv
, NULL
, NULL
, 0, morep
))
1093 if (ROFF_MAX
!= (c
= rofffindcallable(*argv
))) {
1094 if ( ! roffcall(tree
, c
, argv
))
1099 if ( ! roffispunct(*argv
)) {
1100 if ( ! roffdata(tree
, 1, *argv
++))
1105 for (j
= 0; argv
[j
]; j
++)
1106 if ( ! roffispunct(argv
[j
]))
1110 if ( ! roffdata(tree
, 0, *argv
++))
1121 return(roffpurgepunct(tree
, argv
));
1127 roff_Os(ROFFCALL_ARGS
)
1132 if (ROFFSec_PR_Os
& tree
->asec
)
1133 return(roff_text(tok
, tree
, argv
, type
));
1134 if ( ! roffchecksec(tree
, *argv
, ROFFSec_PR_Os
, 1))
1135 return(roff_errp(tree
, *argv
, tok
, ERR_PR_OOO
));
1138 sz
= sizeof(tree
->os
);
1139 tree
->asec
|= (tree
->csec
= ROFFSec_PR_Os
);
1144 if (strlcat(tree
->os
, *argv
++, sz
) >= sz
)
1145 return(roff_errp(tree
, p
, tok
, ERR_ARGLEN
));
1147 if (0 == tree
->os
[0])
1148 if (strlcpy(tree
->os
, "LOCAL", sz
) >= sz
)
1149 return(roff_errp(tree
, p
, tok
, ERR_ARGLEN
));
1151 assert(ROFF_MSEC_MAX
!= tree
->section
);
1152 assert(0 != tree
->title
[0]);
1153 assert(0 != tree
->os
[0]);
1155 assert(NULL
== tree
->last
);
1157 return((*tree
->cb
.roffhead
)(tree
->arg
, &tree
->tm
,
1158 tree
->os
, tree
->title
,
1159 tree
->section
, tree
->volume
));
1165 roff_layout(ROFFCALL_ARGS
)
1167 int i
, c
, argcp
[ROFF_MAXLINEARG
];
1168 char *argvp
[ROFF_MAXLINEARG
], *p
;
1171 * The roff_layout function is for multi-line macros. A layout
1172 * has a start and end point, which is either declared
1173 * explicitly or implicitly. An explicit start and end is
1174 * embodied by `.Bl' and `.El', with the former being the start
1175 * and the latter being an end. The `.Sh' and `.Ss' tags, on
1176 * the other hand, are implicit. The scope of a layout is the
1177 * space between start and end. Explicit layouts may not close
1178 * out implicit ones and vice versa; implicit layouts may close
1179 * out other implicit layouts.
1182 assert( ! (ROFF_CALLABLE
& tokens
[tok
].flags
));
1184 if ( ! ROFFSec_NAME
& tree
->asec
)
1185 return(roff_errp(tree
, *argv
, tok
, ERR_NOT_PR
));
1187 if (ROFF_EXIT
== type
) {
1188 roffnode_free(tree
);
1189 if ( ! (*tree
->cb
.roffblkbodyout
)(tree
->arg
, tok
))
1191 return((*tree
->cb
.roffblkout
)(tree
->arg
, tok
));
1195 assert( ! (ROFF_CALLABLE
& tokens
[tok
].flags
));
1197 if ( ! roffparseopts(tree
, tok
, &argv
, argcp
, argvp
))
1199 if (NULL
== roffnode_new(tok
, tree
))
1203 * Layouts have two parts: the layout body and header. The
1204 * layout header is the trailing text of the line macro, while
1205 * the layout body is everything following until termination.
1224 if ( ! (*tree
->cb
.roffblkin
)(tree
->arg
, tok
, argcp
,
1225 (const char **)argvp
))
1228 /* +++ Begin run macro-specific hooks over argv. */
1232 if (NULL
== *argv
) {
1234 return(roff_errp(tree
, *argv
, tok
, ERR_ARGGE1
));
1237 tree
->csec
= roff_sec((const char **)argv
);
1239 if ( ! (ROFFSec_OTHER
& tree
->csec
) &&
1240 tree
->asec
& tree
->csec
)
1241 if ( ! roff_warn(tree
, *argv
, "section repeated"))
1244 if (0 == tree
->asec
&& ! (ROFFSec_NAME
& tree
->csec
))
1245 return(roff_err(tree
, *argv
, "`NAME' section "
1247 if ( ! roffchecksec(tree
, *argv
, tree
->csec
, 0))
1250 tree
->asec
|= tree
->csec
;
1252 if ( ! roffspecial(tree
, tok
, p
, argcp
,
1253 (const char **)argvp
, 0, argv
))
1260 /* --- End run macro-specific hooks over argv. */
1263 return((*tree
->cb
.roffblkbodyin
)
1264 (tree
->arg
, tok
, argcp
,
1265 (const char **)argvp
));
1267 if ( ! (*tree
->cb
.roffblkheadin
)(tree
->arg
, tok
, argcp
,
1268 (const char **)argvp
))
1272 * If there are no parsable parts, then write remaining tokens
1273 * into the layout header and exit.
1276 if ( ! (ROFF_PARSED
& tokens
[tok
].flags
)) {
1279 if ( ! roffdata(tree
, i
++, *argv
++))
1282 if ( ! (*tree
->cb
.roffblkheadout
)(tree
->arg
, tok
))
1284 return((*tree
->cb
.roffblkbodyin
)(tree
->arg
, tok
, argcp
,
1285 (const char **)argvp
));
1289 * Parsable elements may be in the header (or be the header, for
1290 * that matter). Follow the regular parsing rules for these.
1295 if (ROFF_MAX
== (c
= rofffindcallable(*argv
))) {
1297 if ( ! roffdata(tree
, i
++, *argv
++))
1301 if ( ! roffcall(tree
, c
, argv
))
1307 * If there's trailing punctuation in the header, then write it
1308 * out now. Here we mimic the behaviour of a line-dominant text
1312 if (NULL
== *argv
) {
1313 if ( ! (*tree
->cb
.roffblkheadout
)(tree
->arg
, tok
))
1315 return((*tree
->cb
.roffblkbodyin
)
1316 (tree
->arg
, tok
, argcp
,
1317 (const char **)argvp
));
1321 * Expensive. Scan to the end of line then work backwards until
1322 * a token isn't punctuation.
1325 if ( ! roffpurgepunct(tree
, argv
))
1327 if ( ! (*tree
->cb
.roffblkheadout
)(tree
->arg
, tok
))
1329 return((*tree
->cb
.roffblkbodyin
)(tree
->arg
,
1330 tok
, argcp
, (const char **)argvp
));
1336 roff_ordered(ROFFCALL_ARGS
)
1338 int i
, first
, c
, argcp
[ROFF_MAXLINEARG
];
1339 char *ordp
[ROFF_MAXLINEARG
], *p
,
1340 *argvp
[ROFF_MAXLINEARG
];
1343 * Ordered macros pass their arguments directly to handlers,
1344 * instead of considering it free-form text. Thus, the
1345 * following macro looks as follows:
1349 * .Xr arg1 arg2 punctuation
1352 if ( ! ROFFSec_NAME
& tree
->asec
)
1353 return(roff_errp(tree
, *argv
, tok
, ERR_NOT_PR
));
1355 first
= (*argv
== tree
->cur
);
1359 if ( ! roffparseopts(tree
, tok
, &argv
, argcp
, argvp
))
1363 return(roffspecial(tree
, tok
, p
, argcp
,
1364 (const char **)argvp
, 0, ordp
));
1367 while (*argv
&& i
< ROFF_MAXLINEARG
) {
1368 c
= ROFF_PARSED
& tokens
[tok
].flags
?
1369 rofffindcallable(*argv
) : ROFF_MAX
;
1371 if (ROFF_MAX
== c
&& ! roffispunct(*argv
)) {
1372 ordp
[i
++] = *argv
++;
1380 if ( ! roffspecial(tree
, tok
, p
, argcp
,
1381 (const char **)argvp
,
1385 return(roffcall(tree
, c
, argv
));
1388 assert(i
!= ROFF_MAXLINEARG
);
1391 if ( ! roffspecial(tree
, tok
, p
, argcp
,
1392 (const char**)argvp
,
1396 /* FIXME: error if there's stuff after the punctuation. */
1398 if ( ! first
|| NULL
== *argv
)
1401 return(roffpurgepunct(tree
, argv
));
1407 roff_text(ROFFCALL_ARGS
)
1409 int i
, j
, first
, c
, argcp
[ROFF_MAXLINEARG
];
1410 char *argvp
[ROFF_MAXLINEARG
];
1413 * Text macros are similar to special tokens, except that
1414 * arguments are instead flushed as pure data: we're only
1415 * concerned with the macro and its arguments. Example:
1421 * <fl> v W f </fl> ;
1424 if ( ! ROFFSec_NAME
& tree
->asec
)
1425 return(roff_errp(tree
, *argv
, tok
, ERR_NOT_PR
));
1427 first
= (*argv
== tree
->cur
);
1430 if ( ! roffparseopts(tree
, tok
, &argv
, argcp
, argvp
))
1432 if ( ! (*tree
->cb
.roffin
)(tree
->arg
, tok
, argcp
,
1433 (const char **)argvp
))
1436 return((*tree
->cb
.roffout
)(tree
->arg
, tok
));
1438 if ( ! (ROFF_PARSED
& tokens
[tok
].flags
)) {
1441 if ( ! roffdata(tree
, i
++, *argv
++))
1443 return((*tree
->cb
.roffout
)(tree
->arg
, tok
));
1447 * Deal with punctuation. Ugly. Work ahead until we encounter
1448 * terminating punctuation. If we encounter it and all
1449 * subsequent tokens are punctuation, then stop processing (the
1450 * line-dominant macro will print these tokens after closure).
1451 * If the punctuation is followed by non-punctuation, then close
1452 * and re-open our scope, then continue.
1457 if (ROFF_MAX
!= (c
= rofffindcallable(*argv
))) {
1458 if ( ! (ROFF_LSCOPE
& tokens
[tok
].flags
))
1459 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1462 if ( ! roffcall(tree
, c
, argv
))
1464 if (ROFF_LSCOPE
& tokens
[tok
].flags
)
1465 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1470 if ( ! roffispunct(*argv
)) {
1471 if ( ! roffdata(tree
, i
++, *argv
++))
1477 for (j
= 0; argv
[j
]; j
++)
1478 if ( ! roffispunct(argv
[j
]))
1482 if (ROFF_LSCOPE
& tokens
[tok
].flags
) {
1483 if ( ! roffdata(tree
, 0, *argv
++))
1487 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1489 if ( ! roffdata(tree
, 0, *argv
++))
1491 if ( ! (*tree
->cb
.roffin
)(tree
->arg
, tok
,
1493 (const char **)argvp
))
1500 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1506 return((*tree
->cb
.roffout
)(tree
->arg
, tok
));
1510 return(roffpurgepunct(tree
, argv
));
1516 roff_noop(ROFFCALL_ARGS
)
1525 roff_depr(ROFFCALL_ARGS
)
1528 return(roff_errp(tree
, *argv
, tok
, ERR_DEPREC
));
1533 roff_warnp(const struct rofftree
*tree
, const char *pos
,
1534 int tok
, enum rofferr type
)
1540 p
= "section at `%s' out of order";
1547 return(roff_warn(tree
, pos
, p
, toknames
[tok
]));
1552 roff_warn(const struct rofftree
*tree
, const char *pos
, char *fmt
, ...)
1558 (void)vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
1561 return((*tree
->cb
.roffmsg
)(tree
->arg
,
1562 ROFF_WARN
, tree
->cur
, pos
, buf
));
1567 roff_errp(const struct rofftree
*tree
, const char *pos
,
1568 int tok
, enum rofferr type
)
1574 p
= "`%s' expects exactly one argument";
1577 p
= "`%s' expects exactly zero arguments";
1580 p
= "`%s' expects one or more arguments";
1583 p
= "`%s' expects two or more arguments";
1586 p
= "invalid argument for `%s'";
1589 p
= "macro `%s' is not supported";
1592 p
= "prelude macro `%s' is out of order";
1595 p
= "prelude macro `%s' repeated";
1598 p
= "macro argument for `%s' is too long";
1601 p
= "macro `%s' is deprecated";
1604 p
= "macro `%s' disallowed in prelude";
1607 p
= "too many arguments for macro `%s'";
1614 return(roff_err(tree
, pos
, p
, toknames
[tok
]));
1619 roff_err(const struct rofftree
*tree
, const char *pos
, char *fmt
, ...)
1625 if (-1 == vsnprintf(buf
, sizeof(buf
), fmt
, ap
))
1626 err(1, "vsnprintf");
1629 return((*tree
->cb
.roffmsg
)
1630 (tree
->arg
, ROFF_ERROR
, tree
->cur
, pos
, buf
));