]>
git.cameronkatri.com Git - mandoc.git/blob - roff.c
1 /* $Id: roff.c,v 1.64 2008/12/12 10:11:10 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. */
77 int literal
; /* Literal mode. */
80 static struct roffnode
*roffnode_new(int, struct rofftree
*);
81 static void roffnode_free(struct rofftree
*);
82 static int roff_warn(const struct rofftree
*,
83 const char *, char *, ...);
84 static int roff_warnp(const struct rofftree
*,
85 const char *, int, enum rofferr
);
86 static int roff_err(const struct rofftree
*,
87 const char *, char *, ...);
88 static int roff_errp(const struct rofftree
*,
89 const char *, int, enum rofferr
);
90 static int roffpurgepunct(struct rofftree
*, char **);
91 static int roffscan(int, const int *);
92 static int rofffindtok(const char *);
93 static int rofffindarg(const char *);
94 static int rofffindcallable(const char *);
95 static int roffispunct(const char *);
96 static int roffchecksec(struct rofftree
*,
97 const char *, int, int);
98 static int roffargs(const struct rofftree
*,
99 int, char *, char **);
100 static int roffargok(int, int);
101 static int roffnextopt(const struct rofftree
*,
102 int, char ***, char **);
103 static int roffparseopts(struct rofftree
*, int,
104 char ***, int *, char **);
105 static int roffcall(struct rofftree
*, int, char **);
106 static int roffexit(struct rofftree
*, int);
107 static int roffparse(struct rofftree
*, char *);
108 static int textparse(struct rofftree
*, char *);
109 static int roffdata(struct rofftree
*, int, char *);
110 static int roffspecial(struct rofftree
*, int,
111 const char *, const int *,
112 const char **, size_t, char **);
113 static int roffsetname(struct rofftree
*, char **);
116 extern size_t strlcat(char *, const char *, size_t);
117 extern size_t strlcpy(char *, const char *, size_t);
118 extern int vsnprintf(char *, size_t,
119 const char *, va_list);
120 extern char *strptime(const char *, const char *,
125 roff_free(struct rofftree
*tree
, int flush
)
137 if ( ! (ROFFSec_NAME
& tree
->asec
)) {
138 (void)roff_err(tree
, NULL
, "missing `NAME' section");
140 } else if ( ! (ROFFSec_NMASK
& tree
->asec
))
141 (void)roff_warn(tree
, NULL
, "missing suggested `NAME', "
142 "`SYNOPSIS', `DESCRIPTION' sections");
144 for (n
= tree
->last
; n
; n
= n
->parent
) {
145 if (0 != tokens
[n
->tok
].ctx
)
147 (void)roff_err(tree
, NULL
, "closing explicit scope "
148 "`%s'", toknames
[n
->tok
]);
154 if ( ! roffexit(tree
, t
))
158 if ( ! (*tree
->cb
.rofftail
)(tree
->arg
, &tree
->tm
,
159 tree
->os
, tree
->title
,
160 tree
->section
, tree
->volume
))
172 return(error
? 0 : 1);
177 roff_alloc(const struct roffcb
*cb
, void *args
)
179 struct rofftree
*tree
;
184 if (NULL
== (tree
= calloc(1, sizeof(struct rofftree
))))
188 tree
->section
= ROFF_MSEC_MAX
;
190 (void)memcpy(&tree
->cb
, cb
, sizeof(struct roffcb
));
197 roff_engine(struct rofftree
*tree
, char *buf
)
204 return(roff_err(tree
, buf
, "blank line"));
205 else if ('.' != *buf
)
206 return(textparse(tree
, buf
));
208 return(roffparse(tree
, buf
));
213 textparse(struct rofftree
*tree
, char *buf
)
217 /* TODO: literal parsing. */
219 if ( ! (ROFFSec_NAME
& tree
->asec
))
220 return(roff_err(tree
, buf
, "data before `NAME' section"));
223 return(roffdata(tree
, 0, buf
));
227 while (*buf
&& isspace(*buf
))
235 while (*buf
&& ! isspace(*buf
))
240 if ( ! roffdata(tree
, 1, bufp
))
245 if ( ! roffdata(tree
, 1, bufp
))
255 roffargs(const struct rofftree
*tree
,
256 int tok
, char *buf
, char **argv
)
261 assert(tok
>= 0 && tok
< ROFF_MAX
);
267 * This is an ugly little loop. It parses a line into
268 * space-delimited tokens. If a quote mark is encountered, a
269 * token is alloted the entire quoted text. If whitespace is
270 * escaped, it's included in the prior alloted token.
274 for (i
= 0; *buf
&& i
< ROFF_MAXLINEARG
; i
++) {
277 while (*buf
&& '\"' != *buf
)
280 return(roff_err(tree
, argv
[i
],
281 "unclosed quote in arg list"));
285 if ( ! isspace(*buf
)) {
289 if (*(buf
- 1) == '\\') {
299 while (*buf
&& isspace(*buf
))
304 if (ROFF_MAXLINEARG
== i
&& *buf
)
305 return(roff_err(tree
, p
, "too many args"));
313 roffscan(int tok
, const int *tokv
)
319 for ( ; ROFF_MAX
!= *tokv
; tokv
++)
328 roffparse(struct rofftree
*tree
, char *buf
)
332 char *argv
[ROFF_MAXLINEARG
];
335 if (0 != *buf
&& 0 != *(buf
+ 1) && 0 != *(buf
+ 2))
336 if (0 == strncmp(buf
, ".\\\"", 3))
339 if (ROFF_MAX
== (tok
= rofffindtok(buf
+ 1)))
340 return(roff_err(tree
, buf
, "bogus line macro"));
341 else if ( ! roffargs(tree
, tok
, buf
, argv
))
344 argvp
= (char **)argv
;
347 * Prelude macros break some assumptions, so branch now.
350 if ( ! (ROFFSec_PR_Dd
& tree
->asec
)) {
351 assert(NULL
== tree
->last
);
352 return(roffcall(tree
, tok
, argvp
));
356 * First check that our possible parents and parent's possible
357 * children are satisfied.
360 if (tree
->last
&& ! roffscan
361 (tree
->last
->tok
, tokens
[tok
].parents
))
362 return(roff_err(tree
, *argvp
, "`%s' has invalid "
363 "parent `%s'", toknames
[tok
],
364 toknames
[tree
->last
->tok
]));
366 if (tree
->last
&& ! roffscan
367 (tok
, tokens
[tree
->last
->tok
].children
))
368 return(roff_err(tree
, *argvp
, "`%s' has invalid "
369 "child `%s'", toknames
[tok
],
370 toknames
[tree
->last
->tok
]));
373 * Branch if we're not a layout token.
376 if (ROFF_LAYOUT
!= tokens
[tok
].type
)
377 return(roffcall(tree
, tok
, argvp
));
378 if (0 == tokens
[tok
].ctx
)
379 return(roffcall(tree
, tok
, argvp
));
382 * First consider implicit-end tags, like as follows:
385 * In this, we want to close the scope of the NAME section. If
386 * there's an intermediary implicit-end tag, such as
390 * then it must be closed as well.
393 if (tok
== tokens
[tok
].ctx
) {
395 * First search up to the point where we must close.
396 * If one doesn't exist, then we can open a new scope.
399 for (n
= tree
->last
; n
; n
= n
->parent
) {
400 assert(0 == tokens
[n
->tok
].ctx
||
401 n
->tok
== tokens
[n
->tok
].ctx
);
404 if (ROFF_SHALLOW
& tokens
[tok
].flags
) {
408 if (tokens
[n
->tok
].ctx
== n
->tok
)
410 return(roff_err(tree
, *argv
, "`%s' breaks "
411 "scope of prior`%s'",
417 * Create a new scope, as no previous one exists to
422 return(roffcall(tree
, tok
, argvp
));
425 * Close out all intermediary scoped blocks, then hang
426 * the current scope from our predecessor's parent.
431 if ( ! roffexit(tree
, t
))
435 return(roffcall(tree
, tok
, argvp
));
439 * Now consider explicit-end tags, where we want to close back
440 * to a specific tag. Example:
444 * In this, the `El' tag closes out the scope of `Bl'.
447 assert(tok
!= tokens
[tok
].ctx
&& 0 != tokens
[tok
].ctx
);
450 for (n
= tree
->last
; n
; n
= n
->parent
)
451 if (n
->tok
!= tokens
[tok
].ctx
) {
452 if (n
->tok
== tokens
[n
->tok
].ctx
)
454 return(roff_err(tree
, *argv
, "`%s' breaks "
455 "scope of prior `%s'",
462 return(roff_err(tree
, *argv
, "`%s' has no starting "
463 "tag `%s'", toknames
[tok
],
464 toknames
[tokens
[tok
].ctx
]));
469 if ( ! roffexit(tree
, t
))
471 } while (t
!= tokens
[tok
].ctx
);
478 rofffindarg(const char *name
)
482 /* FIXME: use a table, this is slow but ok for now. */
485 for (i
= 0; i
< ROFF_ARGMAX
; i
++)
487 if (0 == strcmp(name
, tokargnames
[i
]))
495 rofffindtok(const char *buf
)
500 for (i
= 0; *buf
&& ! isspace(*buf
) && i
< 3; i
++, buf
++)
508 /* FIXME: use a table, this is slow but ok for now. */
511 for (i
= 0; i
< ROFF_MAX
; i
++)
513 if (0 == strcmp(toknames
[i
], token
))
521 roffchecksec(struct rofftree
*tree
,
522 const char *start
, int sec
, int fail
)
529 if (ROFFSec_PR_Dd
& tree
->asec
)
533 if (ROFFSec_PR_Dt
& tree
->asec
)
537 if (ROFFSec_PR_Os
& tree
->asec
)
541 if (ROFFSec_NAME
& tree
->asec
)
545 if (ROFFSec_SYNOP
& tree
->asec
)
548 case(ROFFSec_RETVAL
):
549 if (ROFFSec_DESC
& tree
->asec
)
553 if (ROFFSec_RETVAL
& tree
->asec
)
557 if (ROFFSec_ENV
& tree
->asec
)
561 if (ROFFSec_FILES
& tree
->asec
)
565 if (ROFFSec_EX
& tree
->asec
)
569 if (ROFFSec_DIAG
& tree
->asec
)
572 case(ROFFSec_SEEALSO
):
573 if (ROFFSec_ERRS
& tree
->asec
)
577 if (ROFFSec_SEEALSO
& tree
->asec
)
581 if (ROFFSec_STAND
& tree
->asec
)
585 if (ROFFSec_HIST
& tree
->asec
)
588 case(ROFFSec_CAVEATS
):
589 if (ROFFSec_AUTH
& tree
->asec
)
593 if (ROFFSec_CAVEATS
& tree
->asec
)
602 return(roff_warnp(tree
, start
, ROFF_Sh
, WRN_SECORD
));
607 roffispunct(const char *p
)
649 rofffindcallable(const char *name
)
653 if (ROFF_MAX
== (c
= rofffindtok(name
)))
655 assert(c
>= 0 && c
< ROFF_MAX
);
656 return(ROFF_CALLABLE
& tokens
[c
].flags
? c
: ROFF_MAX
);
660 static struct roffnode
*
661 roffnode_new(int tokid
, struct rofftree
*tree
)
665 if (NULL
== (p
= malloc(sizeof(struct roffnode
))))
669 p
->parent
= tree
->last
;
677 roffargok(int tokid
, int argid
)
681 if (NULL
== (c
= tokens
[tokid
].args
))
684 for ( ; ROFF_ARGMAX
!= *c
; c
++)
693 roffnode_free(struct rofftree
*tree
)
700 tree
->last
= tree
->last
->parent
;
706 roffspecial(struct rofftree
*tree
, int tok
, const char *start
,
707 const int *argc
, const char **argv
,
708 size_t sz
, char **ordp
)
715 if (ROFF_ATT_MAX
!= roff_att(*ordp
))
717 return(roff_errp(tree
, *ordp
, tok
, ERR_BADARG
));
722 if (ROFF_MSEC_MAX
!= roff_msec(ordp
[1]))
724 if ( ! roff_warn(tree
, start
, "invalid `%s' manual "
725 "section", toknames
[tok
]))
735 return(roff_errp(tree
, start
, tok
, ERR_ARGGE1
));
739 if (0 != tree
->name
[0]) {
740 ordp
[0] = tree
->name
;
744 return(roff_err(tree
, start
, "`Nm' not set"));
745 } else if ( ! roffsetname(tree
, ordp
))
754 return(roff_errp(tree
, start
, tok
, ERR_ARGEQ1
));
758 return(roff_errp(tree
, start
, tok
, ERR_ARGEQ1
));
759 else if (0 == strcmp(ordp
[0], "on") ||
760 0 == strcmp(ordp
[0], "off"))
762 return(roff_errp(tree
, *ordp
, tok
, ERR_BADARG
));
771 return(roff_errp(tree
, start
, tok
, ERR_ARGEQ0
));
776 return((*tree
->cb
.roffspecial
)(tree
->arg
, tok
, tree
->cur
,
777 argc
, argv
, (const char **)ordp
));
782 roffexit(struct rofftree
*tree
, int tok
)
785 assert(tokens
[tok
].cb
);
786 return((*tokens
[tok
].cb
)(tok
, tree
, NULL
, ROFF_EXIT
));
791 roffcall(struct rofftree
*tree
, int tok
, char **argv
)
796 if (NULL
== tokens
[tok
].cb
)
797 return(roff_errp(tree
, *argv
, tok
, ERR_NOTSUP
));
799 if (tokens
[tok
].sections
&& ROFF_MSEC_MAX
!= tree
->section
) {
801 while (ROFF_MSEC_MAX
!=
802 (c
= tokens
[tok
].sections
[i
++]))
803 if (c
== tree
->section
)
805 if (ROFF_MSEC_MAX
== c
) {
806 if ( ! roff_warn(tree
, *argv
, "`%s' is not a valid "
807 "macro in this manual section",
813 return((*tokens
[tok
].cb
)(tok
, tree
, argv
, ROFF_ENTER
));
818 roffnextopt(const struct rofftree
*tree
, int tok
,
819 char ***in
, char **val
)
828 if (NULL
== (arg
= *argv
))
833 if (ROFF_ARGMAX
== (v
= rofffindarg(arg
+ 1))) {
834 if ( ! roff_warn(tree
, arg
, "argument-like parameter `%s' to "
835 "`%s'", arg
, toknames
[tok
]))
840 if ( ! roffargok(tok
, v
)) {
841 if ( ! roff_warn(tree
, arg
, "invalid argument parameter `%s' to "
842 "`%s'", tokargnames
[v
], toknames
[tok
]))
847 if ( ! (ROFF_VALUE
& tokenargs
[v
]))
853 (void)roff_err(tree
, arg
, "empty value of `%s' for `%s'",
854 tokargnames
[v
], toknames
[tok
]);
863 roffpurgepunct(struct rofftree
*tree
, char **argv
)
871 if ( ! roffispunct(argv
[--i
]))
873 while (i
>= 0 && roffispunct(argv
[i
]))
879 if ( ! roffdata(tree
, 0, argv
[i
++]))
886 roffparseopts(struct rofftree
*tree
, int tok
,
887 char ***args
, int *argc
, char **argv
)
894 while (-1 != (c
= roffnextopt(tree
, tok
, args
, &v
))) {
895 if (ROFF_ARGMAX
== c
)
904 argc
[i
] = ROFF_ARGMAX
;
911 roffdata(struct rofftree
*tree
, int space
, char *buf
)
916 return((*tree
->cb
.roffdata
)(tree
->arg
,
917 space
!= 0, tree
->cur
, buf
));
923 roff_Dd(ROFFCALL_ARGS
)
929 if (ROFFSec_PR_Os
& tree
->asec
)
930 return(roff_text(tok
, tree
, argv
, type
));
931 if (ROFFSec_PR_Dd
& tree
->asec
)
932 return(roff_errp(tree
, *argv
, tok
, ERR_PR_REP
));
933 if ( ! roffchecksec(tree
, *argv
, ROFFSec_PR_Dd
, 1))
934 return(roff_errp(tree
, *argv
, tok
, ERR_PR_OOO
));
936 assert(NULL
== tree
->last
);
938 tree
->asec
|= (tree
->csec
= ROFFSec_PR_Dd
);
941 * This is a bit complex because there are many forms the date
942 * can be in: it can be simply $Mdocdate: December 12 2008 $, $Mdocdate <date>$,
943 * or a raw date. Process accordingly.
946 if (0 == strcmp(*argv
, "$Mdocdate: December 12 2008 $")) {
948 if (NULL
== localtime_r(&t
, &tree
->tm
))
949 err(1, "localtime_r");
957 if (0 != strcmp(*argv
, "$Mdocdate:")) {
959 if (strlcat(buf
, *argv
++, sz
) < sz
)
961 return(roff_errp(tree
, p
, tok
, ERR_BADARG
));
963 if (strptime(buf
, "%b%d,%Y", &tree
->tm
))
965 return(roff_errp(tree
, p
, tok
, ERR_BADARG
));
970 while (*argv
&& **argv
!= '$') {
971 if (strlcat(buf
, *argv
++, sz
) >= sz
)
972 return(roff_errp(tree
, p
, tok
, ERR_BADARG
));
973 if (strlcat(buf
, " ", sz
) >= sz
)
974 return(roff_errp(tree
, p
, tok
, ERR_BADARG
));
978 return(roff_errp(tree
, p
, tok
, ERR_BADARG
));
979 if (NULL
== strptime(buf
, "%b %d %Y", &tree
->tm
))
980 return(roff_errp(tree
, p
, tok
, ERR_BADARG
));
988 roff_Dt(ROFFCALL_ARGS
)
992 if (ROFFSec_PR_Os
& tree
->asec
)
993 return(roff_text(tok
, tree
, argv
, type
));
994 if (ROFFSec_PR_Dt
& tree
->asec
)
995 return(roff_errp(tree
, *argv
, tok
, ERR_PR_REP
));
996 if ( ! roffchecksec(tree
, *argv
, ROFFSec_PR_Dt
, 1))
997 return(roff_errp(tree
, *argv
, tok
, ERR_PR_OOO
));
1000 tree
->asec
|= (tree
->csec
= ROFFSec_PR_Dt
);
1001 sz
= sizeof(tree
->title
);
1004 return(roff_errp(tree
, *argv
, tok
, ERR_ARGGE2
));
1005 if (strlcpy(tree
->title
, *argv
, sz
) >= sz
)
1006 return(roff_errp(tree
, *argv
, tok
, ERR_ARGLEN
));
1010 return(roff_errp(tree
, *argv
, tok
, ERR_ARGGE2
));
1012 if (ROFF_MSEC_MAX
== (tree
->section
= roff_msec(*argv
)))
1013 return(roff_errp(tree
, *argv
, tok
, ERR_BADARG
));
1017 if (NULL
== *argv
) {
1018 switch (tree
->section
) {
1024 tree
->volume
= ROFF_VOL_URM
;
1035 tree
->volume
= ROFF_VOL_PRM
;
1038 tree
->volume
= ROFF_VOL_PRM
;
1041 tree
->volume
= ROFF_VOL_KM
;
1043 case(ROFF_MSEC_UNASS
):
1045 case(ROFF_MSEC_DRAFT
):
1047 case(ROFF_MSEC_PAPER
):
1048 tree
->volume
= ROFF_VOL_NONE
;
1054 } else if (ROFF_VOL_MAX
== (tree
->volume
= roff_vol(*argv
)))
1055 return(roff_errp(tree
, *argv
, tok
, ERR_BADARG
));
1057 assert(NULL
== tree
->last
);
1064 roffsetname(struct rofftree
*tree
, char **ordp
)
1070 /* FIXME: not all sections can set this. */
1072 if (NULL
!= *(ordp
+ 1))
1073 return(roff_errp(tree
, *ordp
, ROFF_Nm
, ERR_ARGMNY
));
1075 sz
= sizeof(tree
->name
);
1076 if (strlcpy(tree
->name
, *ordp
, sz
) >= sz
)
1077 return(roff_errp(tree
, *ordp
, ROFF_Nm
, ERR_ARGLEN
));
1085 roff_Ns(ROFFCALL_ARGS
)
1090 first
= (*argv
++ == tree
->cur
);
1093 if ( ! roffspecial(tree
, tok
, *argv
, NULL
, NULL
, 0, morep
))
1097 if (ROFF_MAX
!= (c
= rofffindcallable(*argv
))) {
1098 if ( ! roffcall(tree
, c
, argv
))
1103 if ( ! roffispunct(*argv
)) {
1104 if ( ! roffdata(tree
, 1, *argv
++))
1109 for (j
= 0; argv
[j
]; j
++)
1110 if ( ! roffispunct(argv
[j
]))
1114 if ( ! roffdata(tree
, 0, *argv
++))
1125 return(roffpurgepunct(tree
, argv
));
1131 roff_Os(ROFFCALL_ARGS
)
1136 if (ROFFSec_PR_Os
& tree
->asec
)
1137 return(roff_text(tok
, tree
, argv
, type
));
1138 if ( ! roffchecksec(tree
, *argv
, ROFFSec_PR_Os
, 1))
1139 return(roff_errp(tree
, *argv
, tok
, ERR_PR_OOO
));
1142 sz
= sizeof(tree
->os
);
1143 tree
->asec
|= (tree
->csec
= ROFFSec_PR_Os
);
1148 if (strlcat(tree
->os
, *argv
++, sz
) >= sz
)
1149 return(roff_errp(tree
, p
, tok
, ERR_ARGLEN
));
1151 if (0 == tree
->os
[0])
1152 if (strlcpy(tree
->os
, "LOCAL", sz
) >= sz
)
1153 return(roff_errp(tree
, p
, tok
, ERR_ARGLEN
));
1155 assert(ROFF_MSEC_MAX
!= tree
->section
);
1156 assert(0 != tree
->title
[0]);
1157 assert(0 != tree
->os
[0]);
1159 assert(NULL
== tree
->last
);
1161 return((*tree
->cb
.roffhead
)(tree
->arg
, &tree
->tm
,
1162 tree
->os
, tree
->title
,
1163 tree
->section
, tree
->volume
));
1169 roff_layout(ROFFCALL_ARGS
)
1171 int i
, c
, argcp
[ROFF_MAXLINEARG
];
1172 char *argvp
[ROFF_MAXLINEARG
], *p
;
1175 * The roff_layout function is for multi-line macros. A layout
1176 * has a start and end point, which is either declared
1177 * explicitly or implicitly. An explicit start and end is
1178 * embodied by `.Bl' and `.El', with the former being the start
1179 * and the latter being an end. The `.Sh' and `.Ss' tags, on
1180 * the other hand, are implicit. The scope of a layout is the
1181 * space between start and end. Explicit layouts may not close
1182 * out implicit ones and vice versa; implicit layouts may close
1183 * out other implicit layouts.
1186 assert( ! (ROFF_CALLABLE
& tokens
[tok
].flags
));
1188 if ( ! (ROFFSec_PR_Os
& tree
->asec
))
1189 return(roff_errp(tree
, *argv
, tok
, ERR_NOT_PR
));
1191 if (ROFF_EXIT
== type
) {
1192 roffnode_free(tree
);
1193 if ( ! (*tree
->cb
.roffblkbodyout
)(tree
->arg
, tok
))
1195 return((*tree
->cb
.roffblkout
)(tree
->arg
, tok
));
1199 assert( ! (ROFF_CALLABLE
& tokens
[tok
].flags
));
1201 if ( ! roffparseopts(tree
, tok
, &argv
, argcp
, argvp
))
1203 if (NULL
== roffnode_new(tok
, tree
))
1207 * Layouts have two parts: the layout body and header. The
1208 * layout header is the trailing text of the line macro, while
1209 * the layout body is everything following until termination.
1228 if ( ! (*tree
->cb
.roffblkin
)(tree
->arg
, tok
, argcp
,
1229 (const char **)argvp
))
1232 /* +++ Begin run macro-specific hooks over argv. */
1240 if (NULL
== *argv
) {
1242 return(roff_errp(tree
, *argv
, tok
, ERR_ARGGE1
));
1245 tree
->csec
= roff_sec((const char **)argv
);
1247 if ( ! (ROFFSec_OTHER
& tree
->csec
) &&
1248 tree
->asec
& tree
->csec
)
1249 if ( ! roff_warn(tree
, *argv
, "section repeated"))
1252 if (0 == tree
->asec
&& ! (ROFFSec_NAME
& tree
->csec
))
1253 return(roff_err(tree
, *argv
, "`NAME' section "
1255 if ( ! roffchecksec(tree
, *argv
, tree
->csec
, 0))
1258 tree
->asec
|= tree
->csec
;
1260 if ( ! roffspecial(tree
, tok
, p
, argcp
,
1261 (const char **)argvp
, 0, argv
))
1268 /* --- End run macro-specific hooks over argv. */
1271 return((*tree
->cb
.roffblkbodyin
)
1272 (tree
->arg
, tok
, argcp
,
1273 (const char **)argvp
));
1275 if ( ! (*tree
->cb
.roffblkheadin
)(tree
->arg
, tok
, argcp
,
1276 (const char **)argvp
))
1280 * If there are no parsable parts, then write remaining tokens
1281 * into the layout header and exit.
1284 if ( ! (ROFF_PARSED
& tokens
[tok
].flags
)) {
1287 if ( ! roffdata(tree
, i
++, *argv
++))
1290 if ( ! (*tree
->cb
.roffblkheadout
)(tree
->arg
, tok
))
1292 return((*tree
->cb
.roffblkbodyin
)(tree
->arg
, tok
, argcp
,
1293 (const char **)argvp
));
1297 * Parsable elements may be in the header (or be the header, for
1298 * that matter). Follow the regular parsing rules for these.
1303 if (ROFF_MAX
== (c
= rofffindcallable(*argv
))) {
1305 if ( ! roffdata(tree
, i
++, *argv
++))
1309 if ( ! roffcall(tree
, c
, argv
))
1315 * If there's trailing punctuation in the header, then write it
1316 * out now. Here we mimic the behaviour of a line-dominant text
1320 if (NULL
== *argv
) {
1321 if ( ! (*tree
->cb
.roffblkheadout
)(tree
->arg
, tok
))
1323 return((*tree
->cb
.roffblkbodyin
)
1324 (tree
->arg
, tok
, argcp
,
1325 (const char **)argvp
));
1329 * Expensive. Scan to the end of line then work backwards until
1330 * a token isn't punctuation.
1333 if ( ! roffpurgepunct(tree
, argv
))
1335 if ( ! (*tree
->cb
.roffblkheadout
)(tree
->arg
, tok
))
1337 return((*tree
->cb
.roffblkbodyin
)(tree
->arg
,
1338 tok
, argcp
, (const char **)argvp
));
1344 roff_ordered(ROFFCALL_ARGS
)
1346 int i
, first
, c
, argcp
[ROFF_MAXLINEARG
];
1347 char *ordp
[ROFF_MAXLINEARG
], *p
,
1348 *argvp
[ROFF_MAXLINEARG
];
1351 * Ordered macros pass their arguments directly to handlers,
1352 * instead of considering it free-form text. Thus, the
1353 * following macro looks as follows:
1357 * .Xr arg1 arg2 punctuation
1360 if ( ! (ROFFSec_PR_Os
& tree
->asec
))
1361 return(roff_errp(tree
, *argv
, tok
, ERR_NOT_PR
));
1363 first
= (*argv
== tree
->cur
);
1367 if ( ! roffparseopts(tree
, tok
, &argv
, argcp
, argvp
))
1371 return(roffspecial(tree
, tok
, p
, argcp
,
1372 (const char **)argvp
, 0, ordp
));
1375 while (*argv
&& i
< ROFF_MAXLINEARG
) {
1376 c
= ROFF_PARSED
& tokens
[tok
].flags
?
1377 rofffindcallable(*argv
) : ROFF_MAX
;
1379 if (ROFF_MAX
== c
&& ! roffispunct(*argv
)) {
1380 ordp
[i
++] = *argv
++;
1388 if ( ! roffspecial(tree
, tok
, p
, argcp
,
1389 (const char **)argvp
,
1393 return(roffcall(tree
, c
, argv
));
1396 assert(i
!= ROFF_MAXLINEARG
);
1399 if ( ! roffspecial(tree
, tok
, p
, argcp
,
1400 (const char**)argvp
,
1404 /* FIXME: error if there's stuff after the punctuation. */
1406 if ( ! first
|| NULL
== *argv
)
1409 return(roffpurgepunct(tree
, argv
));
1414 macro_default(struct rofftree
*tree
, int tok
, char *args
[])
1417 char *argv
[ROFF_MAXLINEARG
];
1418 int i
, argc
[ROFF_MAXLINEARG
];
1420 if ( ! roffparseopts(tree
, tok
, &args
, argc
, argv
))
1423 if ( ! (ROFF_PARSED
& tokens
[tok
].flags
))
1424 return((*tree
->cb
.macro
)(tree
->arg
, tok
, argc
, argv
, 0, args
));
1429 c
= rofffindcallable(*args
);
1430 if (ROFF_MAX
== c
) {
1431 if (roffispunct(*args
)) {
1437 if (ROFF_MAX
!= (c
= rofffindcallable(*argv
))) {
1438 if ( ! (ROFF_LSCOPE
& tokens
[tok
].flags
))
1439 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1442 if ( ! roffcall(tree
, c
, argv
))
1444 if (ROFF_LSCOPE
& tokens
[tok
].flags
)
1445 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1450 if ( ! roffispunct(*argv
)) {
1451 if ( ! roffdata(tree
, i
++, *argv
++))
1457 for (j
= 0; argv
[j
]; j
++)
1458 if ( ! roffispunct(argv
[j
]))
1462 if (ROFF_LSCOPE
& tokens
[tok
].flags
) {
1463 if ( ! roffdata(tree
, 0, *argv
++))
1467 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1469 if ( ! roffdata(tree
, 0, *argv
++))
1471 if ( ! (*tree
->cb
.roffin
)(tree
->arg
, tok
,
1473 (const char **)argvp
))
1480 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1489 roff_text(ROFFCALL_ARGS
)
1491 int i
, j
, first
, c
, argcp
[ROFF_MAXLINEARG
];
1492 char *argvp
[ROFF_MAXLINEARG
];
1495 * Text macros are similar to special tokens, except that
1496 * arguments are instead flushed as pure data: we're only
1497 * concerned with the macro and its arguments. Example:
1503 * <fl> v W f </fl> ;
1506 if ( ! (ROFFSec_PR_Os
& tree
->asec
))
1507 return(roff_errp(tree
, *argv
, tok
, ERR_NOT_PR
));
1509 first
= (*argv
== tree
->cur
);
1512 if ( ! roffparseopts(tree
, tok
, &argv
, argcp
, argvp
))
1514 if ( ! (*tree
->cb
.roffin
)(tree
->arg
, tok
, argcp
,
1515 (const char **)argvp
))
1518 return((*tree
->cb
.roffout
)(tree
->arg
, tok
));
1520 if ( ! (ROFF_PARSED
& tokens
[tok
].flags
)) {
1523 if ( ! roffdata(tree
, i
++, *argv
++))
1525 return((*tree
->cb
.roffout
)(tree
->arg
, tok
));
1529 * Deal with punctuation. Ugly. Work ahead until we encounter
1530 * terminating punctuation. If we encounter it and all
1531 * subsequent tokens are punctuation, then stop processing (the
1532 * line-dominant macro will print these tokens after closure).
1533 * If the punctuation is followed by non-punctuation, then close
1534 * and re-open our scope, then continue.
1539 if (ROFF_MAX
!= (c
= rofffindcallable(*argv
))) {
1540 if ( ! (ROFF_LSCOPE
& tokens
[tok
].flags
))
1541 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1544 if ( ! roffcall(tree
, c
, argv
))
1546 if (ROFF_LSCOPE
& tokens
[tok
].flags
)
1547 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1552 if ( ! roffispunct(*argv
)) {
1553 if ( ! roffdata(tree
, i
++, *argv
++))
1559 for (j
= 0; argv
[j
]; j
++)
1560 if ( ! roffispunct(argv
[j
]))
1564 if (ROFF_LSCOPE
& tokens
[tok
].flags
) {
1565 if ( ! roffdata(tree
, 0, *argv
++))
1569 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1571 if ( ! roffdata(tree
, 0, *argv
++))
1573 if ( ! (*tree
->cb
.roffin
)(tree
->arg
, tok
,
1575 (const char **)argvp
))
1582 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1588 return((*tree
->cb
.roffout
)(tree
->arg
, tok
));
1592 return(roffpurgepunct(tree
, argv
));
1598 roff_noop(ROFFCALL_ARGS
)
1615 roff_depr(ROFFCALL_ARGS
)
1618 return(roff_errp(tree
, *argv
, tok
, ERR_DEPREC
));
1622 /* FIXME: push this into the filter. */
1624 roff_warnp(const struct rofftree
*tree
, const char *pos
,
1625 int tok
, enum rofferr type
)
1631 p
= "section at `%s' out of order";
1638 return(roff_warn(tree
, pos
, p
, toknames
[tok
]));
1643 roff_warn(const struct rofftree
*tree
, const char *pos
, char *fmt
, ...)
1649 (void)vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
1652 return((*tree
->cb
.roffmsg
)(tree
->arg
,
1653 ROFF_WARN
, tree
->cur
, pos
, buf
));
1657 /* FIXME: push this into the filter. */
1659 roff_errp(const struct rofftree
*tree
, const char *pos
,
1660 int tok
, enum rofferr type
)
1666 p
= "`%s' expects exactly one argument";
1669 p
= "`%s' expects exactly zero arguments";
1672 p
= "`%s' expects one or more arguments";
1675 p
= "`%s' expects two or more arguments";
1678 p
= "invalid argument for `%s'";
1681 p
= "macro `%s' is not supported";
1684 p
= "prelude macro `%s' is out of order";
1687 p
= "prelude macro `%s' repeated";
1690 p
= "macro argument for `%s' is too long";
1693 p
= "macro `%s' is deprecated";
1696 p
= "macro `%s' disallowed in prelude";
1699 p
= "too many arguments for macro `%s'";
1706 return(roff_err(tree
, pos
, p
, toknames
[tok
]));
1711 roff_err(const struct rofftree
*tree
, const char *pos
, char *fmt
, ...)
1717 if (-1 == vsnprintf(buf
, sizeof(buf
), fmt
, ap
))
1718 err(1, "vsnprintf");
1721 return((*tree
->cb
.roffmsg
)
1722 (tree
->arg
, ROFF_ERROR
, tree
->cur
, pos
, buf
));