]>
git.cameronkatri.com Git - mandoc.git/blob - roff.c
990475561b9ae075e77fa4283eee0ed897384d75
1 /* $Id: roff.c,v 1.58 2008/12/10 10:43:57 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 /* TODO: validate Dt macro arguments. */
42 /* FIXME: Bl -diag supposed to ignore callable children. */
45 int tok
; /* Token id. */
46 struct roffnode
*parent
; /* Parent (or NULL). */
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. */
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
;
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. */
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
*,
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 **);
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 *,
131 roff_free(struct rofftree
*tree
, int flush
)
143 if (ROFF_PRELUDE
& tree
->state
) {
144 (void)roff_err(tree
, NULL
, "prelude never finished");
146 } else if ( ! (ROFFSec_NAME
& tree
->asec
)) {
147 (void)roff_err(tree
, NULL
, "missing `NAME' section");
149 } else if ( ! (ROFFSec_NMASK
& tree
->asec
))
150 (void)roff_warn(tree
, NULL
, "missing suggested `NAME', "
151 "`SYNOPSIS', `DESCRIPTION' sections");
153 for (n
= tree
->last
; n
; n
= n
->parent
) {
154 if (0 != tokens
[n
->tok
].ctx
)
156 (void)roff_err(tree
, NULL
, "closing explicit scope "
157 "`%s'", toknames
[n
->tok
]);
163 if ( ! roffexit(tree
, t
))
167 if ( ! (*tree
->cb
.rofftail
)(tree
->arg
))
179 return(error
? 0 : 1);
184 roff_alloc(const struct roffcb
*cb
, void *args
)
186 struct rofftree
*tree
;
191 if (NULL
== (tree
= calloc(1, sizeof(struct rofftree
))))
194 tree
->state
= ROFF_PRELUDE
;
196 tree
->section
= ROFF_MSEC_MAX
;
198 (void)memcpy(&tree
->cb
, cb
, sizeof(struct roffcb
));
205 roff_engine(struct rofftree
*tree
, char *buf
)
212 return(roff_err(tree
, buf
, "blank line"));
213 else if ('.' != *buf
)
214 return(textparse(tree
, buf
));
216 return(roffparse(tree
, buf
));
221 textparse(struct rofftree
*tree
, char *buf
)
225 /* TODO: literal parsing. */
227 if ( ! (ROFF_BODY
& tree
->state
))
228 return(roff_err(tree
, buf
, "data not in body"));
232 while (*buf
&& isspace(*buf
))
240 while (*buf
&& ! isspace(*buf
))
245 if ( ! roffdata(tree
, 1, bufp
))
250 if ( ! roffdata(tree
, 1, bufp
))
260 roffargs(const struct rofftree
*tree
,
261 int tok
, char *buf
, char **argv
)
266 assert(tok
>= 0 && tok
< ROFF_MAX
);
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.
279 for (i
= 0; *buf
&& i
< ROFF_MAXLINEARG
; i
++) {
282 while (*buf
&& '\"' != *buf
)
285 return(roff_err(tree
, argv
[i
],
286 "unclosed quote in arg list"));
290 if ( ! isspace(*buf
)) {
294 if (*(buf
- 1) == '\\') {
304 while (*buf
&& isspace(*buf
))
309 if (ROFF_MAXLINEARG
== i
&& *buf
)
310 return(roff_err(tree
, p
, "too many args"));
318 roffscan(int tok
, const int *tokv
)
324 for ( ; ROFF_MAX
!= *tokv
; tokv
++)
333 roffparse(struct rofftree
*tree
, char *buf
)
337 char *argv
[ROFF_MAXLINEARG
];
340 if (0 != *buf
&& 0 != *(buf
+ 1) && 0 != *(buf
+ 2))
341 if (0 == strncmp(buf
, ".\\\"", 3))
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
))
349 argvp
= (char **)argv
;
352 * Prelude macros break some assumptions, so branch now.
355 if (ROFF_PRELUDE
& tree
->state
) {
356 assert(NULL
== tree
->last
);
357 return(roffcall(tree
, tok
, argvp
));
360 assert(ROFF_BODY
& tree
->state
);
363 * First check that our possible parents and parent's possible
364 * children are satisfied.
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
]));
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
]));
380 * Branch if we're not a layout token.
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
));
389 * First consider implicit-end tags, like as follows:
392 * In this, we want to close the scope of the NAME section. If
393 * there's an intermediary implicit-end tag, such as
397 * then it must be closed as well.
400 if (tok
== tokens
[tok
].ctx
) {
402 * First search up to the point where we must close.
403 * If one doesn't exist, then we can open a new scope.
406 for (n
= tree
->last
; n
; n
= n
->parent
) {
407 assert(0 == tokens
[n
->tok
].ctx
||
408 n
->tok
== tokens
[n
->tok
].ctx
);
411 if (ROFF_SHALLOW
& tokens
[tok
].flags
) {
415 if (tokens
[n
->tok
].ctx
== n
->tok
)
417 return(roff_err(tree
, *argv
, "`%s' breaks "
418 "scope of prior`%s'",
424 * Create a new scope, as no previous one exists to
429 return(roffcall(tree
, tok
, argvp
));
432 * Close out all intermediary scoped blocks, then hang
433 * the current scope from our predecessor's parent.
438 if ( ! roffexit(tree
, t
))
442 return(roffcall(tree
, tok
, argvp
));
446 * Now consider explicit-end tags, where we want to close back
447 * to a specific tag. Example:
451 * In this, the `El' tag closes out the scope of `Bl'.
454 assert(tok
!= tokens
[tok
].ctx
&& 0 != tokens
[tok
].ctx
);
457 for (n
= tree
->last
; n
; n
= n
->parent
)
458 if (n
->tok
!= tokens
[tok
].ctx
) {
459 if (n
->tok
== tokens
[n
->tok
].ctx
)
461 return(roff_err(tree
, *argv
, "`%s' breaks "
462 "scope of prior `%s'",
469 return(roff_err(tree
, *argv
, "`%s' has no starting "
470 "tag `%s'", toknames
[tok
],
471 toknames
[tokens
[tok
].ctx
]));
476 if ( ! roffexit(tree
, t
))
478 } while (t
!= tokens
[tok
].ctx
);
485 rofffindarg(const char *name
)
489 /* FIXME: use a table, this is slow but ok for now. */
492 for (i
= 0; i
< ROFF_ARGMAX
; i
++)
494 if (0 == strcmp(name
, tokargnames
[i
]))
502 rofffindtok(const char *buf
)
507 for (i
= 0; *buf
&& ! isspace(*buf
) && i
< 3; i
++, buf
++)
515 /* FIXME: use a table, this is slow but ok for now. */
518 for (i
= 0; i
< ROFF_MAX
; i
++)
520 if (0 == strcmp(toknames
[i
], token
))
528 roffchecksec(struct rofftree
*tree
, const char *start
, int sec
)
534 if ((prior
= ROFFSec_NAME
) & tree
->asec
)
538 if ((prior
= ROFFSec_SYNOP
) & tree
->asec
)
541 case(ROFFSec_RETVAL
):
542 if ((prior
= ROFFSec_DESC
) & tree
->asec
)
546 if ((prior
= ROFFSec_RETVAL
) & tree
->asec
)
550 if ((prior
= ROFFSec_ENV
) & tree
->asec
)
554 if ((prior
= ROFFSec_FILES
) & tree
->asec
)
558 if ((prior
= ROFFSec_EX
) & tree
->asec
)
562 if ((prior
= ROFFSec_DIAG
) & tree
->asec
)
565 case(ROFFSec_SEEALSO
):
566 if ((prior
= ROFFSec_ERRS
) & tree
->asec
)
570 if ((prior
= ROFFSec_SEEALSO
) & tree
->asec
)
574 if ((prior
= ROFFSec_STAND
) & tree
->asec
)
578 if ((prior
= ROFFSec_HIST
) & tree
->asec
)
581 case(ROFFSec_CAVEATS
):
582 if ((prior
= ROFFSec_AUTH
) & tree
->asec
)
586 if ((prior
= ROFFSec_CAVEATS
) & tree
->asec
)
593 return(roff_warnp(tree
, start
, ROFF_Sh
, WRN_SECORD
));
597 /* FIXME: move this into literals.c (or similar). */
599 roffispunct(const char *p
)
641 rofffindcallable(const char *name
)
645 if (ROFF_MAX
== (c
= rofffindtok(name
)))
647 assert(c
>= 0 && c
< ROFF_MAX
);
648 return(ROFF_CALLABLE
& tokens
[c
].flags
? c
: ROFF_MAX
);
652 static struct roffnode
*
653 roffnode_new(int tokid
, struct rofftree
*tree
)
657 if (NULL
== (p
= malloc(sizeof(struct roffnode
))))
661 p
->parent
= tree
->last
;
669 roffargok(int tokid
, int argid
)
673 if (NULL
== (c
= tokens
[tokid
].args
))
676 for ( ; ROFF_ARGMAX
!= *c
; c
++)
685 roffnode_free(struct rofftree
*tree
)
692 tree
->last
= tree
->last
->parent
;
698 roffspecial(struct rofftree
*tree
, int tok
, const char *start
,
699 const int *argc
, const char **argv
,
700 size_t sz
, char **ordp
)
707 if (ROFF_ATT_MAX
!= roff_att(*ordp
))
709 return(roff_errp(tree
, *ordp
, tok
, ERR_BADARG
));
714 if (ROFF_MSEC_MAX
!= roff_msec(ordp
[1]))
716 if ( ! roff_warn(tree
, start
, "invalid `%s' manual "
717 "section", toknames
[tok
]))
727 return(roff_errp(tree
, start
, tok
, ERR_ARGGE1
));
731 if (0 != tree
->name
[0]) {
732 ordp
[0] = tree
->name
;
736 return(roff_err(tree
, start
, "`Nm' not set"));
737 } else if ( ! roffsetname(tree
, ordp
))
746 return(roff_errp(tree
, start
, tok
, ERR_ARGEQ1
));
750 return(roff_errp(tree
, start
, tok
, ERR_ARGEQ1
));
751 else if (0 == strcmp(ordp
[0], "on") ||
752 0 == strcmp(ordp
[0], "off"))
754 return(roff_errp(tree
, *ordp
, tok
, ERR_BADARG
));
763 return(roff_errp(tree
, start
, tok
, ERR_ARGEQ0
));
768 return((*tree
->cb
.roffspecial
)(tree
->arg
, tok
, tree
->cur
,
769 argc
, argv
, (const char **)ordp
));
774 roffexit(struct rofftree
*tree
, int tok
)
777 assert(tokens
[tok
].cb
);
778 return((*tokens
[tok
].cb
)(tok
, tree
, NULL
, ROFF_EXIT
));
783 roffcall(struct rofftree
*tree
, int tok
, char **argv
)
788 if (NULL
== tokens
[tok
].cb
)
789 return(roff_errp(tree
, *argv
, tok
, ERR_NOTSUP
));
791 if (tokens
[tok
].sections
&& ROFF_MSEC_MAX
!= tree
->section
) {
793 while (ROFF_MSEC_MAX
!=
794 (c
= tokens
[tok
].sections
[i
++]))
795 if (c
== tree
->section
)
797 if (ROFF_MSEC_MAX
== c
) {
798 if ( ! roff_warn(tree
, *argv
, "`%s' is not a valid "
799 "macro in this manual section",
805 return((*tokens
[tok
].cb
)(tok
, tree
, argv
, ROFF_ENTER
));
810 roffnextopt(const struct rofftree
*tree
, int tok
,
811 char ***in
, char **val
)
820 if (NULL
== (arg
= *argv
))
825 if (ROFF_ARGMAX
== (v
= rofffindarg(arg
+ 1))) {
826 if ( ! roff_warn(tree
, arg
, "argument-like parameter `%s' to "
827 "`%s'", arg
, toknames
[tok
]))
832 if ( ! roffargok(tok
, v
)) {
833 if ( ! roff_warn(tree
, arg
, "invalid argument parameter `%s' to "
834 "`%s'", tokargnames
[v
], toknames
[tok
]))
839 if ( ! (ROFF_VALUE
& tokenargs
[v
]))
845 (void)roff_err(tree
, arg
, "empty value of `%s' for `%s'",
846 tokargnames
[v
], toknames
[tok
]);
855 roffpurgepunct(struct rofftree
*tree
, char **argv
)
863 if ( ! roffispunct(argv
[--i
]))
865 while (i
>= 0 && roffispunct(argv
[i
]))
871 if ( ! roffdata(tree
, 0, argv
[i
++]))
878 roffparseopts(struct rofftree
*tree
, int tok
,
879 char ***args
, int *argc
, char **argv
)
886 while (-1 != (c
= roffnextopt(tree
, tok
, args
, &v
))) {
887 if (ROFF_ARGMAX
== c
)
896 argc
[i
] = ROFF_ARGMAX
;
903 roffdata(struct rofftree
*tree
, int space
, char *buf
)
908 return((*tree
->cb
.roffdata
)(tree
->arg
,
909 space
!= 0, tree
->cur
, buf
));
915 roff_Dd(ROFFCALL_ARGS
)
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
));
927 assert(ROFF_PRELUDE
& tree
->state
);
928 assert( ! (ROFF_BODY
& tree
->state
));
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
));
935 assert(NULL
== tree
->last
);
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.
945 if (0 == strcmp(*argv
, "$Mdocdate: December 10 2008 $")) {
947 if (NULL
== localtime_r(&t
, &tree
->tm
))
948 err(1, "localtime_r");
949 tree
->state
|= ROFF_PRELUDE_Dd
;
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
)) {
964 tree
->state
|= ROFF_PRELUDE_Dd
;
967 return(roff_errp(tree
, p
, tok
, ERR_BADARG
));
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
));
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
));
984 tree
->state
|= ROFF_PRELUDE_Dd
;
991 roff_Dt(ROFFCALL_ARGS
)
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
));
1001 assert(ROFF_PRELUDE
& tree
->state
);
1002 assert( ! (ROFF_BODY
& tree
->state
));
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
));
1010 sz
= sizeof(tree
->title
);
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
));
1019 return(roff_errp(tree
, *argv
, tok
, ERR_ARGGE2
));
1021 if (ROFF_MSEC_MAX
== (tree
->section
= roff_msec(*argv
)))
1022 return(roff_errp(tree
, *argv
, tok
, ERR_BADARG
));
1026 if (NULL
== *argv
) {
1027 switch (tree
->section
) {
1033 tree
->volume
= ROFF_VOL_URM
;
1044 tree
->volume
= ROFF_VOL_PRM
;
1047 tree
->volume
= ROFF_VOL_PRM
;
1050 tree
->volume
= ROFF_VOL_KM
;
1052 case(ROFF_MSEC_UNASS
):
1054 case(ROFF_MSEC_DRAFT
):
1056 case(ROFF_MSEC_PAPER
):
1057 tree
->volume
= ROFF_VOL_NONE
;
1063 } else if (ROFF_VOL_MAX
== (tree
->volume
= roff_vol(*argv
)))
1064 return(roff_errp(tree
, *argv
, tok
, ERR_BADARG
));
1066 assert(NULL
== tree
->last
);
1067 tree
->state
|= ROFF_PRELUDE_Dt
;
1074 roffsetname(struct rofftree
*tree
, char **ordp
)
1080 /* FIXME: not all sections can set this. */
1082 if (NULL
!= *(ordp
+ 1))
1083 return(roff_errp(tree
, *ordp
, ROFF_Nm
, ERR_ARGMNY
));
1085 sz
= sizeof(tree
->name
);
1086 if (strlcpy(tree
->name
, *ordp
, sz
) >= sz
)
1087 return(roff_errp(tree
, *ordp
, ROFF_Nm
, ERR_ARGLEN
));
1095 roff_Ns(ROFFCALL_ARGS
)
1100 first
= (*argv
++ == tree
->cur
);
1103 if ( ! roffspecial(tree
, tok
, *argv
, NULL
, NULL
, 0, morep
))
1107 if (ROFF_MAX
!= (c
= rofffindcallable(*argv
))) {
1108 if ( ! roffcall(tree
, c
, argv
))
1113 if ( ! roffispunct(*argv
)) {
1114 if ( ! roffdata(tree
, 1, *argv
++))
1119 for (j
= 0; argv
[j
]; j
++)
1120 if ( ! roffispunct(argv
[j
]))
1124 if ( ! roffdata(tree
, 0, *argv
++))
1135 return(roffpurgepunct(tree
, argv
));
1141 roff_Os(ROFFCALL_ARGS
)
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
));
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
));
1160 sz
= sizeof(tree
->os
);
1163 if (strlcat(tree
->os
, *argv
++, sz
) >= sz
)
1164 return(roff_errp(tree
, p
, tok
, ERR_ARGLEN
));
1166 if (0 == tree
->os
[0])
1167 if (strlcpy(tree
->os
, "LOCAL", sz
) >= sz
)
1168 return(roff_errp(tree
, p
, tok
, ERR_ARGLEN
));
1170 tree
->state
|= ROFF_PRELUDE_Os
;
1171 tree
->state
&= ~ROFF_PRELUDE
;
1172 tree
->state
|= ROFF_BODY
;
1174 assert(ROFF_MSEC_MAX
!= tree
->section
);
1175 assert(0 != tree
->title
[0]);
1176 assert(0 != tree
->os
[0]);
1178 assert(NULL
== tree
->last
);
1180 return((*tree
->cb
.roffhead
)(tree
->arg
, &tree
->tm
,
1181 tree
->os
, tree
->title
,
1182 tree
->section
, tree
->volume
));
1188 roff_layout(ROFFCALL_ARGS
)
1190 int i
, c
, argcp
[ROFF_MAXLINEARG
];
1191 char *argvp
[ROFF_MAXLINEARG
];
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.
1205 assert( ! (ROFF_CALLABLE
& tokens
[tok
].flags
));
1207 if (ROFF_PRELUDE
& tree
->state
)
1208 return(roff_errp(tree
, *argv
, tok
, ERR_NOT_PR
));
1210 if (ROFF_EXIT
== type
) {
1211 roffnode_free(tree
);
1212 if ( ! (*tree
->cb
.roffblkbodyout
)(tree
->arg
, tok
))
1214 return((*tree
->cb
.roffblkout
)(tree
->arg
, tok
));
1218 assert( ! (ROFF_CALLABLE
& tokens
[tok
].flags
));
1220 if ( ! roffparseopts(tree
, tok
, &argv
, argcp
, argvp
))
1222 if (NULL
== roffnode_new(tok
, tree
))
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.
1247 if ( ! (*tree
->cb
.roffblkin
)(tree
->arg
, tok
, argcp
,
1248 (const char **)argvp
))
1251 /* +++ Begin run macro-specific hooks over argv. */
1255 if (NULL
== *argv
) {
1257 return(roff_errp(tree
, *argv
, tok
, ERR_ARGGE1
));
1260 tree
->csec
= roff_sec((const char **)argv
);
1262 if ( ! (ROFFSec_OTHER
& tree
->csec
) &&
1263 tree
->asec
& tree
->csec
)
1264 if ( ! roff_warn(tree
, *argv
, "section repeated"))
1267 if (0 == tree
->asec
&& ! (ROFFSec_NAME
& tree
->csec
))
1268 return(roff_err(tree
, *argv
, "`NAME' section "
1270 if ( ! roffchecksec(tree
, *argv
, tree
->csec
))
1273 tree
->asec
|= tree
->csec
;
1279 /* --- End run macro-specific hooks over argv. */
1282 return((*tree
->cb
.roffblkbodyin
)
1283 (tree
->arg
, tok
, argcp
,
1284 (const char **)argvp
));
1286 if ( ! (*tree
->cb
.roffblkheadin
)(tree
->arg
, tok
, argcp
,
1287 (const char **)argvp
))
1291 * If there are no parsable parts, then write remaining tokens
1292 * into the layout header and exit.
1295 if ( ! (ROFF_PARSED
& tokens
[tok
].flags
)) {
1298 if ( ! roffdata(tree
, i
++, *argv
++))
1301 if ( ! (*tree
->cb
.roffblkheadout
)(tree
->arg
, tok
))
1303 return((*tree
->cb
.roffblkbodyin
)(tree
->arg
, tok
, argcp
,
1304 (const char **)argvp
));
1308 * Parsable elements may be in the header (or be the header, for
1309 * that matter). Follow the regular parsing rules for these.
1314 if (ROFF_MAX
== (c
= rofffindcallable(*argv
))) {
1316 if ( ! roffdata(tree
, i
++, *argv
++))
1320 if ( ! roffcall(tree
, c
, argv
))
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
1331 if (NULL
== *argv
) {
1332 if ( ! (*tree
->cb
.roffblkheadout
)(tree
->arg
, tok
))
1334 return((*tree
->cb
.roffblkbodyin
)
1335 (tree
->arg
, tok
, argcp
,
1336 (const char **)argvp
));
1340 * Expensive. Scan to the end of line then work backwards until
1341 * a token isn't punctuation.
1344 if ( ! roffpurgepunct(tree
, argv
))
1346 if ( ! (*tree
->cb
.roffblkheadout
)(tree
->arg
, tok
))
1348 return((*tree
->cb
.roffblkbodyin
)(tree
->arg
,
1349 tok
, argcp
, (const char **)argvp
));
1355 roff_ordered(ROFFCALL_ARGS
)
1357 int i
, first
, c
, argcp
[ROFF_MAXLINEARG
];
1358 char *ordp
[ROFF_MAXLINEARG
], *p
,
1359 *argvp
[ROFF_MAXLINEARG
];
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:
1368 * .Xr arg1 arg2 punctuation
1371 if (ROFF_PRELUDE
& tree
->state
)
1372 return(roff_errp(tree
, *argv
, tok
, ERR_NOT_PR
));
1374 first
= (*argv
== tree
->cur
);
1378 if ( ! roffparseopts(tree
, tok
, &argv
, argcp
, argvp
))
1382 return(roffspecial(tree
, tok
, p
, argcp
,
1383 (const char **)argvp
, 0, ordp
));
1386 while (*argv
&& i
< ROFF_MAXLINEARG
) {
1387 c
= ROFF_PARSED
& tokens
[tok
].flags
?
1388 rofffindcallable(*argv
) : ROFF_MAX
;
1390 if (ROFF_MAX
== c
&& ! roffispunct(*argv
)) {
1391 ordp
[i
++] = *argv
++;
1399 if ( ! roffspecial(tree
, tok
, p
, argcp
,
1400 (const char **)argvp
,
1404 return(roffcall(tree
, c
, argv
));
1407 assert(i
!= ROFF_MAXLINEARG
);
1410 if ( ! roffspecial(tree
, tok
, p
, argcp
,
1411 (const char**)argvp
,
1415 /* FIXME: error if there's stuff after the punctuation. */
1417 if ( ! first
|| NULL
== *argv
)
1420 return(roffpurgepunct(tree
, argv
));
1426 roff_text(ROFFCALL_ARGS
)
1428 int i
, j
, first
, c
, argcp
[ROFF_MAXLINEARG
];
1429 char *argvp
[ROFF_MAXLINEARG
];
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:
1440 * <fl> v W f </fl> ;
1443 if (ROFF_PRELUDE
& tree
->state
)
1444 return(roff_errp(tree
, *argv
, tok
, ERR_NOT_PR
));
1446 first
= (*argv
== tree
->cur
);
1449 if ( ! roffparseopts(tree
, tok
, &argv
, argcp
, argvp
))
1451 if ( ! (*tree
->cb
.roffin
)(tree
->arg
, tok
, argcp
,
1452 (const char **)argvp
))
1455 return((*tree
->cb
.roffout
)(tree
->arg
, tok
));
1457 if ( ! (ROFF_PARSED
& tokens
[tok
].flags
)) {
1460 if ( ! roffdata(tree
, i
++, *argv
++))
1462 return((*tree
->cb
.roffout
)(tree
->arg
, tok
));
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.
1476 if (ROFF_MAX
!= (c
= rofffindcallable(*argv
))) {
1477 if ( ! (ROFF_LSCOPE
& tokens
[tok
].flags
))
1478 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1481 if ( ! roffcall(tree
, c
, argv
))
1483 if (ROFF_LSCOPE
& tokens
[tok
].flags
)
1484 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1489 if ( ! roffispunct(*argv
)) {
1490 if ( ! roffdata(tree
, i
++, *argv
++))
1496 for (j
= 0; argv
[j
]; j
++)
1497 if ( ! roffispunct(argv
[j
]))
1501 if (ROFF_LSCOPE
& tokens
[tok
].flags
) {
1502 if ( ! roffdata(tree
, 0, *argv
++))
1506 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1508 if ( ! roffdata(tree
, 0, *argv
++))
1510 if ( ! (*tree
->cb
.roffin
)(tree
->arg
, tok
,
1512 (const char **)argvp
))
1519 if ( ! (*tree
->cb
.roffout
)(tree
->arg
, tok
))
1525 return((*tree
->cb
.roffout
)(tree
->arg
, tok
));
1529 return(roffpurgepunct(tree
, argv
));
1535 roff_noop(ROFFCALL_ARGS
)
1544 roff_depr(ROFFCALL_ARGS
)
1547 return(roff_errp(tree
, *argv
, tok
, ERR_DEPREC
));
1552 roff_warnp(const struct rofftree
*tree
, const char *pos
,
1553 int tok
, enum rofferr type
)
1559 p
= "section at `%s' out of order";
1566 return(roff_warn(tree
, pos
, p
, toknames
[tok
]));
1571 roff_warn(const struct rofftree
*tree
, const char *pos
, char *fmt
, ...)
1577 (void)vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
1580 return((*tree
->cb
.roffmsg
)(tree
->arg
,
1581 ROFF_WARN
, tree
->cur
, pos
, buf
));
1586 roff_errp(const struct rofftree
*tree
, const char *pos
,
1587 int tok
, enum rofferr type
)
1593 p
= "`%s' expects exactly one argument";
1596 p
= "`%s' expects exactly zero arguments";
1599 p
= "`%s' expects one or more arguments";
1602 p
= "`%s' expects two or more arguments";
1605 p
= "invalid argument for `%s'";
1608 p
= "macro `%s' is not supported";
1611 p
= "prelude macro `%s' is out of order";
1614 p
= "prelude macro `%s' repeated";
1617 p
= "macro argument for `%s' is too long";
1620 p
= "macro `%s' is deprecated";
1623 p
= "macro `%s' disallowed in prelude";
1626 p
= "too many arguments for macro `%s'";
1633 return(roff_err(tree
, pos
, p
, toknames
[tok
]));
1638 roff_err(const struct rofftree
*tree
, const char *pos
, char *fmt
, ...)
1644 if (-1 == vsnprintf(buf
, sizeof(buf
), fmt
, ap
))
1645 err(1, "vsnprintf");
1648 return((*tree
->cb
.roffmsg
)
1649 (tree
->arg
, ROFF_ERROR
, tree
->cur
, pos
, buf
));