File: | src/usr.bin/mandoc/mdoc_macro.c |
Warning: | line 269, column 6 Access to field 'flags' results in a dereference of a null pointer (loaded from variable 'to') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: mdoc_macro.c,v 1.191 2020/01/19 17:59:01 schwarze Exp $ */ | |||
2 | /* | |||
3 | * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> | |||
4 | * Copyright (c) 2010, 2012-2020 Ingo Schwarze <schwarze@openbsd.org> | |||
5 | * | |||
6 | * Permission to use, copy, modify, and distribute this software for any | |||
7 | * purpose with or without fee is hereby granted, provided that the above | |||
8 | * copyright notice and this permission notice appear in all copies. | |||
9 | * | |||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES | |||
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR | |||
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
17 | */ | |||
18 | #include <sys/types.h> | |||
19 | ||||
20 | #include <assert.h> | |||
21 | #include <ctype.h> | |||
22 | #include <stdlib.h> | |||
23 | #include <stdio.h> | |||
24 | #include <string.h> | |||
25 | #include <time.h> | |||
26 | ||||
27 | #include "mandoc.h" | |||
28 | #include "roff.h" | |||
29 | #include "mdoc.h" | |||
30 | #include "libmandoc.h" | |||
31 | #include "roff_int.h" | |||
32 | #include "libmdoc.h" | |||
33 | ||||
34 | static void blk_full(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
35 | static void blk_exp_close(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
36 | static void blk_part_exp(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
37 | static void blk_part_imp(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
38 | static void ctx_synopsis(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
39 | static void in_line_eoln(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
40 | static void in_line_argn(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
41 | static void in_line(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
42 | static void phrase_ta(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf); | |||
43 | ||||
44 | static void append_delims(struct roff_man *, int, int *, char *); | |||
45 | static void dword(struct roff_man *, int, int, const char *, | |||
46 | enum mdelim, int); | |||
47 | static int find_pending(struct roff_man *, enum roff_tok, | |||
48 | int, int, struct roff_node *); | |||
49 | static int lookup(struct roff_man *, int, int, int, const char *); | |||
50 | static int macro_or_word(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf, char *, int); | |||
51 | static void break_intermediate(struct roff_node *, | |||
52 | struct roff_node *); | |||
53 | static int parse_rest(struct roff_man *, enum roff_tok, | |||
54 | int, int *, char *); | |||
55 | static enum roff_tok rew_alt(enum roff_tok); | |||
56 | static void rew_elem(struct roff_man *, enum roff_tok); | |||
57 | static void rew_last(struct roff_man *, const struct roff_node *); | |||
58 | static void rew_pending(struct roff_man *, | |||
59 | const struct roff_node *); | |||
60 | ||||
61 | static const struct mdoc_macro mdoc_macros[MDOC_MAX - MDOC_Dd] = { | |||
62 | { in_line_eoln, MDOC_PROLOGUE(1 << 3) | MDOC_JOIN(1 << 5) }, /* Dd */ | |||
63 | { in_line_eoln, MDOC_PROLOGUE(1 << 3) }, /* Dt */ | |||
64 | { in_line_eoln, MDOC_PROLOGUE(1 << 3) }, /* Os */ | |||
65 | { blk_full, MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Sh */ | |||
66 | { blk_full, MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Ss */ | |||
67 | { in_line_eoln, 0 }, /* Pp */ | |||
68 | { blk_part_imp, MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* D1 */ | |||
69 | { blk_part_imp, MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Dl */ | |||
70 | { blk_full, MDOC_EXPLICIT(1 << 2) }, /* Bd */ | |||
71 | { blk_exp_close, MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Ed */ | |||
72 | { blk_full, MDOC_EXPLICIT(1 << 2) }, /* Bl */ | |||
73 | { blk_exp_close, MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* El */ | |||
74 | { blk_full, MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* It */ | |||
75 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Ad */ | |||
76 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* An */ | |||
77 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
78 | MDOC_IGNDELIM(1 << 4) | MDOC_JOIN(1 << 5) }, /* Ap */ | |||
79 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Ar */ | |||
80 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Cd */ | |||
81 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Cm */ | |||
82 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Dv */ | |||
83 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Er */ | |||
84 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Ev */ | |||
85 | { in_line_eoln, 0 }, /* Ex */ | |||
86 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Fa */ | |||
87 | { in_line_eoln, 0 }, /* Fd */ | |||
88 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Fl */ | |||
89 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Fn */ | |||
90 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Ft */ | |||
91 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Ic */ | |||
92 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* In */ | |||
93 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Li */ | |||
94 | { blk_full, MDOC_JOIN(1 << 5) }, /* Nd */ | |||
95 | { ctx_synopsis, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Nm */ | |||
96 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Op */ | |||
97 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Ot */ | |||
98 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Pa */ | |||
99 | { in_line_eoln, 0 }, /* Rv */ | |||
100 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* St */ | |||
101 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Va */ | |||
102 | { ctx_synopsis, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Vt */ | |||
103 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Xr */ | |||
104 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %A */ | |||
105 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %B */ | |||
106 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %D */ | |||
107 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %I */ | |||
108 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %J */ | |||
109 | { in_line_eoln, 0 }, /* %N */ | |||
110 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %O */ | |||
111 | { in_line_eoln, 0 }, /* %P */ | |||
112 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %R */ | |||
113 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %T */ | |||
114 | { in_line_eoln, 0 }, /* %V */ | |||
115 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
116 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Ac */ | |||
117 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
118 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Ao */ | |||
119 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Aq */ | |||
120 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* At */ | |||
121 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
122 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Bc */ | |||
123 | { blk_full, MDOC_EXPLICIT(1 << 2) }, /* Bf */ | |||
124 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
125 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Bo */ | |||
126 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Bq */ | |||
127 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Bsx */ | |||
128 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Bx */ | |||
129 | { in_line_eoln, 0 }, /* Db */ | |||
130 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
131 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Dc */ | |||
132 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
133 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Do */ | |||
134 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Dq */ | |||
135 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_EXPLICIT(1 << 2) }, /* Ec */ | |||
136 | { blk_exp_close, MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Ef */ | |||
137 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Em */ | |||
138 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_EXPLICIT(1 << 2) }, /* Eo */ | |||
139 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Fx */ | |||
140 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Ms */ | |||
141 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* No */ | |||
142 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
143 | MDOC_IGNDELIM(1 << 4) | MDOC_JOIN(1 << 5) }, /* Ns */ | |||
144 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Nx */ | |||
145 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Ox */ | |||
146 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
147 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Pc */ | |||
148 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_IGNDELIM(1 << 4) }, /* Pf */ | |||
149 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
150 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Po */ | |||
151 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Pq */ | |||
152 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
153 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Qc */ | |||
154 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Ql */ | |||
155 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
156 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Qo */ | |||
157 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Qq */ | |||
158 | { blk_exp_close, MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Re */ | |||
159 | { blk_full, MDOC_EXPLICIT(1 << 2) }, /* Rs */ | |||
160 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
161 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Sc */ | |||
162 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
163 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* So */ | |||
164 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Sq */ | |||
165 | { in_line_argn, 0 }, /* Sm */ | |||
166 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Sx */ | |||
167 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Sy */ | |||
168 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Tn */ | |||
169 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Ux */ | |||
170 | { blk_exp_close, MDOC_EXPLICIT(1 << 2) | MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Xc */ | |||
171 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_EXPLICIT(1 << 2) }, /* Xo */ | |||
172 | { blk_full, MDOC_EXPLICIT(1 << 2) | MDOC_CALLABLE(1 << 0) }, /* Fo */ | |||
173 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
174 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Fc */ | |||
175 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
176 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Oo */ | |||
177 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
178 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Oc */ | |||
179 | { blk_full, MDOC_EXPLICIT(1 << 2) }, /* Bk */ | |||
180 | { blk_exp_close, MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Ek */ | |||
181 | { in_line_eoln, 0 }, /* Bt */ | |||
182 | { in_line_eoln, 0 }, /* Hf */ | |||
183 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Fr */ | |||
184 | { in_line_eoln, 0 }, /* Ud */ | |||
185 | { in_line, 0 }, /* Lb */ | |||
186 | { in_line_eoln, 0 }, /* Lp */ | |||
187 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Lk */ | |||
188 | { in_line, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Mt */ | |||
189 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Brq */ | |||
190 | { blk_part_exp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
191 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Bro */ | |||
192 | { blk_exp_close, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | | |||
193 | MDOC_EXPLICIT(1 << 2) | MDOC_JOIN(1 << 5) }, /* Brc */ | |||
194 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %C */ | |||
195 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Es */ | |||
196 | { blk_part_imp, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* En */ | |||
197 | { in_line_argn, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) }, /* Dx */ | |||
198 | { in_line_eoln, MDOC_JOIN(1 << 5) }, /* %Q */ | |||
199 | { in_line_eoln, 0 }, /* %U */ | |||
200 | { phrase_ta, MDOC_CALLABLE(1 << 0) | MDOC_PARSED(1 << 1) | MDOC_JOIN(1 << 5) }, /* Ta */ | |||
201 | { in_line_eoln, 0 }, /* Tg */ | |||
202 | }; | |||
203 | ||||
204 | ||||
205 | const struct mdoc_macro * | |||
206 | mdoc_macro(enum roff_tok tok) | |||
207 | { | |||
208 | assert(tok >= MDOC_Dd && tok < MDOC_MAX)((tok >= MDOC_Dd && tok < MDOC_MAX) ? (void)0 : __assert2("/usr/src/usr.bin/mandoc/mdoc_macro.c", 208, __func__ , "tok >= MDOC_Dd && tok < MDOC_MAX")); | |||
209 | return mdoc_macros + (tok - MDOC_Dd); | |||
210 | } | |||
211 | ||||
212 | /* | |||
213 | * This is called at the end of parsing. It must traverse up the tree, | |||
214 | * closing out open [implicit] scopes. Obviously, open explicit scopes | |||
215 | * are errors. | |||
216 | */ | |||
217 | void | |||
218 | mdoc_endparse(struct roff_man *mdoc) | |||
219 | { | |||
220 | struct roff_node *n; | |||
221 | ||||
222 | /* Scan for open explicit scopes. */ | |||
223 | ||||
224 | n = mdoc->last->flags & NODE_VALID(1 << 0) ? | |||
225 | mdoc->last->parent : mdoc->last; | |||
226 | ||||
227 | for ( ; n; n = n->parent) | |||
228 | if (n->type == ROFFT_BLOCK && | |||
229 | mdoc_macro(n->tok)->flags & MDOC_EXPLICIT(1 << 2)) | |||
230 | mandoc_msg(MANDOCERR_BLK_NOEND, | |||
231 | n->line, n->pos, "%s", roff_name[n->tok]); | |||
232 | ||||
233 | /* Rewind to the first. */ | |||
234 | ||||
235 | rew_last(mdoc, mdoc->meta.first); | |||
236 | } | |||
237 | ||||
238 | /* | |||
239 | * Look up the macro at *p called by "from", | |||
240 | * or as a line macro if from == TOKEN_NONE. | |||
241 | */ | |||
242 | static int | |||
243 | lookup(struct roff_man *mdoc, int from, int line, int ppos, const char *p) | |||
244 | { | |||
245 | enum roff_tok res; | |||
246 | ||||
247 | if (mdoc->flags & MDOC_PHRASEQF(1 << 13)) { | |||
248 | mdoc->flags &= ~MDOC_PHRASEQF(1 << 13); | |||
249 | return TOKEN_NONE; | |||
250 | } | |||
251 | if (from == TOKEN_NONE || mdoc_macro(from)->flags & MDOC_PARSED(1 << 1)) { | |||
252 | res = roffhash_find(mdoc->mdocmac, p, 0); | |||
253 | if (res != TOKEN_NONE) { | |||
254 | if (mdoc_macro(res)->flags & MDOC_CALLABLE(1 << 0)) | |||
255 | return res; | |||
256 | mandoc_msg(MANDOCERR_MACRO_CALL, line, ppos, "%s", p); | |||
257 | } | |||
258 | } | |||
259 | return TOKEN_NONE; | |||
260 | } | |||
261 | ||||
262 | /* | |||
263 | * Rewind up to and including a specific node. | |||
264 | */ | |||
265 | static void | |||
266 | rew_last(struct roff_man *mdoc, const struct roff_node *to) | |||
267 | { | |||
268 | ||||
269 | if (to->flags & NODE_VALID(1 << 0)) | |||
| ||||
270 | return; | |||
271 | ||||
272 | while (mdoc->last != to) { | |||
273 | mdoc_state(mdoc, mdoc->last); | |||
274 | mdoc->last->flags |= NODE_VALID(1 << 0) | NODE_ENDED(1 << 1); | |||
275 | mdoc->last = mdoc->last->parent; | |||
276 | } | |||
277 | mdoc_state(mdoc, mdoc->last); | |||
278 | mdoc->last->flags |= NODE_VALID(1 << 0) | NODE_ENDED(1 << 1); | |||
279 | mdoc->next = ROFF_NEXT_SIBLING; | |||
280 | } | |||
281 | ||||
282 | /* | |||
283 | * Rewind up to a specific block, including all blocks that broke it. | |||
284 | */ | |||
285 | static void | |||
286 | rew_pending(struct roff_man *mdoc, const struct roff_node *n) | |||
287 | { | |||
288 | ||||
289 | for (;;) { | |||
290 | rew_last(mdoc, n); | |||
291 | ||||
292 | if (mdoc->last == n) { | |||
293 | switch (n->type) { | |||
294 | case ROFFT_HEAD: | |||
295 | roff_body_alloc(mdoc, n->line, n->pos, | |||
296 | n->tok); | |||
297 | if (n->tok == MDOC_Ss) | |||
298 | mdoc->flags &= ~ROFF_NONOFILL(1 << 16); | |||
299 | break; | |||
300 | case ROFFT_BLOCK: | |||
301 | break; | |||
302 | default: | |||
303 | return; | |||
304 | } | |||
305 | if ( ! (n->flags & NODE_BROKEN(1 << 2))) | |||
306 | return; | |||
307 | } else | |||
308 | n = mdoc->last; | |||
309 | ||||
310 | for (;;) { | |||
311 | if ((n = n->parent) == NULL((void *)0)) | |||
312 | return; | |||
313 | ||||
314 | if (n->type == ROFFT_BLOCK || | |||
315 | n->type == ROFFT_HEAD) { | |||
316 | if (n->flags & NODE_ENDED(1 << 1)) | |||
317 | break; | |||
318 | else | |||
319 | return; | |||
320 | } | |||
321 | } | |||
322 | } | |||
323 | } | |||
324 | ||||
325 | /* | |||
326 | * For a block closing macro, return the corresponding opening one. | |||
327 | * Otherwise, return the macro itself. | |||
328 | */ | |||
329 | static enum roff_tok | |||
330 | rew_alt(enum roff_tok tok) | |||
331 | { | |||
332 | switch (tok) { | |||
333 | case MDOC_Ac: | |||
334 | return MDOC_Ao; | |||
335 | case MDOC_Bc: | |||
336 | return MDOC_Bo; | |||
337 | case MDOC_Brc: | |||
338 | return MDOC_Bro; | |||
339 | case MDOC_Dc: | |||
340 | return MDOC_Do; | |||
341 | case MDOC_Ec: | |||
342 | return MDOC_Eo; | |||
343 | case MDOC_Ed: | |||
344 | return MDOC_Bd; | |||
345 | case MDOC_Ef: | |||
346 | return MDOC_Bf; | |||
347 | case MDOC_Ek: | |||
348 | return MDOC_Bk; | |||
349 | case MDOC_El: | |||
350 | return MDOC_Bl; | |||
351 | case MDOC_Fc: | |||
352 | return MDOC_Fo; | |||
353 | case MDOC_Oc: | |||
354 | return MDOC_Oo; | |||
355 | case MDOC_Pc: | |||
356 | return MDOC_Po; | |||
357 | case MDOC_Qc: | |||
358 | return MDOC_Qo; | |||
359 | case MDOC_Re: | |||
360 | return MDOC_Rs; | |||
361 | case MDOC_Sc: | |||
362 | return MDOC_So; | |||
363 | case MDOC_Xc: | |||
364 | return MDOC_Xo; | |||
365 | default: | |||
366 | return tok; | |||
367 | } | |||
368 | } | |||
369 | ||||
370 | static void | |||
371 | rew_elem(struct roff_man *mdoc, enum roff_tok tok) | |||
372 | { | |||
373 | struct roff_node *n; | |||
374 | ||||
375 | n = mdoc->last; | |||
376 | if (n->type != ROFFT_ELEM) | |||
377 | n = n->parent; | |||
378 | assert(n->type == ROFFT_ELEM)((n->type == ROFFT_ELEM) ? (void)0 : __assert2("/usr/src/usr.bin/mandoc/mdoc_macro.c" , 378, __func__, "n->type == ROFFT_ELEM")); | |||
379 | assert(tok == n->tok)((tok == n->tok) ? (void)0 : __assert2("/usr/src/usr.bin/mandoc/mdoc_macro.c" , 379, __func__, "tok == n->tok")); | |||
380 | rew_last(mdoc, n); | |||
381 | } | |||
382 | ||||
383 | static void | |||
384 | break_intermediate(struct roff_node *n, struct roff_node *breaker) | |||
385 | { | |||
386 | if (n != breaker && | |||
387 | n->type != ROFFT_BLOCK && n->type != ROFFT_HEAD && | |||
388 | (n->type != ROFFT_BODY || n->end != ENDBODY_NOT)) | |||
389 | n = n->parent; | |||
390 | while (n != breaker) { | |||
391 | if ( ! (n->flags & NODE_VALID(1 << 0))) | |||
392 | n->flags |= NODE_BROKEN(1 << 2); | |||
393 | n = n->parent; | |||
394 | } | |||
395 | } | |||
396 | ||||
397 | /* | |||
398 | * If there is an open sub-block of the target requiring | |||
399 | * explicit close-out, postpone closing out the target until | |||
400 | * the rew_pending() call closing out the sub-block. | |||
401 | */ | |||
402 | static int | |||
403 | find_pending(struct roff_man *mdoc, enum roff_tok tok, int line, int ppos, | |||
404 | struct roff_node *target) | |||
405 | { | |||
406 | struct roff_node *n; | |||
407 | int irc; | |||
408 | ||||
409 | if (target->flags & NODE_VALID(1 << 0)) | |||
410 | return 0; | |||
411 | ||||
412 | irc = 0; | |||
413 | for (n = mdoc->last; n != NULL((void *)0) && n != target; n = n->parent) { | |||
414 | if (n->flags & NODE_ENDED(1 << 1)) | |||
415 | continue; | |||
416 | if (n->type == ROFFT_BLOCK && | |||
417 | mdoc_macro(n->tok)->flags & MDOC_EXPLICIT(1 << 2)) { | |||
418 | irc = 1; | |||
419 | break_intermediate(mdoc->last, target); | |||
420 | if (target->type == ROFFT_HEAD) | |||
421 | target->flags |= NODE_ENDED(1 << 1); | |||
422 | else if ( ! (target->flags & NODE_ENDED(1 << 1))) { | |||
423 | mandoc_msg(MANDOCERR_BLK_NEST, | |||
424 | line, ppos, "%s breaks %s", | |||
425 | roff_name[tok], roff_name[n->tok]); | |||
426 | mdoc_endbody_alloc(mdoc, line, ppos, | |||
427 | tok, target); | |||
428 | } | |||
429 | } | |||
430 | } | |||
431 | return irc; | |||
432 | } | |||
433 | ||||
434 | /* | |||
435 | * Allocate a word and check whether it's punctuation or not. | |||
436 | * Punctuation consists of those tokens found in mdoc_isdelim(). | |||
437 | */ | |||
438 | static void | |||
439 | dword(struct roff_man *mdoc, int line, int col, const char *p, | |||
440 | enum mdelim d, int may_append) | |||
441 | { | |||
442 | ||||
443 | if (d == DELIM_MAX) | |||
444 | d = mdoc_isdelim(p); | |||
445 | ||||
446 | if (may_append && | |||
447 | ! (mdoc->flags & (MDOC_SYNOPSIS(1 << 7) | MDOC_KEEP(1 << 8) | MDOC_SMOFF(1 << 9))) && | |||
448 | d == DELIM_NONE && mdoc->last->type == ROFFT_TEXT && | |||
449 | mdoc_isdelim(mdoc->last->string) == DELIM_NONE) { | |||
450 | roff_word_append(mdoc, p); | |||
451 | return; | |||
452 | } | |||
453 | ||||
454 | roff_word_alloc(mdoc, line, col, p); | |||
455 | ||||
456 | /* | |||
457 | * If the word consists of a bare delimiter, | |||
458 | * flag the new node accordingly, | |||
459 | * unless doing so was vetoed by the invoking macro. | |||
460 | * Always clear the veto, it is only valid for one word. | |||
461 | */ | |||
462 | ||||
463 | if (d == DELIM_OPEN) | |||
464 | mdoc->last->flags |= NODE_DELIMO(1 << 4); | |||
465 | else if (d == DELIM_CLOSE && | |||
466 | ! (mdoc->flags & MDOC_NODELIMC(1 << 10)) && | |||
467 | mdoc->last->parent->tok != MDOC_Fd) | |||
468 | mdoc->last->flags |= NODE_DELIMC(1 << 5); | |||
469 | mdoc->flags &= ~MDOC_NODELIMC(1 << 10); | |||
470 | } | |||
471 | ||||
472 | static void | |||
473 | append_delims(struct roff_man *mdoc, int line, int *pos, char *buf) | |||
474 | { | |||
475 | char *p; | |||
476 | int la; | |||
477 | enum margserr ac; | |||
478 | ||||
479 | if (buf[*pos] == '\0') | |||
480 | return; | |||
481 | ||||
482 | for (;;) { | |||
483 | la = *pos; | |||
484 | ac = mdoc_args(mdoc, line, pos, buf, TOKEN_NONE, &p); | |||
485 | if (ac == ARGS_EOLN) | |||
486 | break; | |||
487 | dword(mdoc, line, la, p, DELIM_MAX, 1); | |||
488 | ||||
489 | /* | |||
490 | * If we encounter end-of-sentence symbols, then trigger | |||
491 | * the double-space. | |||
492 | * | |||
493 | * XXX: it's easy to allow this to propagate outward to | |||
494 | * the last symbol, such that `. )' will cause the | |||
495 | * correct double-spacing. However, (1) groff isn't | |||
496 | * smart enough to do this and (2) it would require | |||
497 | * knowing which symbols break this behaviour, for | |||
498 | * example, `. ;' shouldn't propagate the double-space. | |||
499 | */ | |||
500 | ||||
501 | if (mandoc_eos(p, strlen(p))) | |||
502 | mdoc->last->flags |= NODE_EOS(1 << 6); | |||
503 | if (ac == ARGS_ALLOC) | |||
504 | free(p); | |||
505 | } | |||
506 | } | |||
507 | ||||
508 | /* | |||
509 | * Parse one word. | |||
510 | * If it is a macro, call it and return 1. | |||
511 | * Otherwise, allocate it and return 0. | |||
512 | */ | |||
513 | static int | |||
514 | macro_or_word(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf, char *p, int parsed) | |||
515 | { | |||
516 | int ntok; | |||
517 | ||||
518 | ntok = buf[ppos] == '"' || parsed == 0 || | |||
519 | mdoc->flags & MDOC_PHRASELIT(1 << 5) ? TOKEN_NONE : | |||
520 | lookup(mdoc, tok, line, ppos, p); | |||
521 | ||||
522 | if (ntok == TOKEN_NONE) { | |||
523 | dword(mdoc, line, ppos, p, DELIM_MAX, tok == TOKEN_NONE || | |||
524 | mdoc_macro(tok)->flags & MDOC_JOIN(1 << 5)); | |||
525 | return 0; | |||
526 | } else { | |||
527 | if (tok != TOKEN_NONE && | |||
528 | mdoc_macro(tok)->fp == in_line_eoln) | |||
529 | rew_elem(mdoc, tok); | |||
530 | (*mdoc_macro(ntok)->fp)(mdoc, ntok, line, ppos, pos, buf); | |||
531 | if (tok == TOKEN_NONE) | |||
532 | append_delims(mdoc, line, pos, buf); | |||
533 | return 1; | |||
534 | } | |||
535 | } | |||
536 | ||||
537 | /* | |||
538 | * Close out block partial/full explicit. | |||
539 | */ | |||
540 | static void | |||
541 | blk_exp_close(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
542 | { | |||
543 | struct roff_node *body; /* Our own body. */ | |||
544 | struct roff_node *endbody; /* Our own end marker. */ | |||
545 | struct roff_node *itblk; /* An It block starting later. */ | |||
546 | struct roff_node *later; /* A sub-block starting later. */ | |||
547 | struct roff_node *n; /* Search back to our block. */ | |||
548 | struct roff_node *target; /* For find_pending(). */ | |||
549 | ||||
550 | int j, lastarg, maxargs, nl, pending; | |||
551 | enum margserr ac; | |||
552 | enum roff_tok atok, ntok; | |||
553 | char *p; | |||
554 | ||||
555 | nl = MDOC_NEWLINE(1 << 3) & mdoc->flags; | |||
556 | ||||
557 | switch (tok) { | |||
558 | case MDOC_Ec: | |||
559 | maxargs = 1; | |||
560 | break; | |||
561 | case MDOC_Ek: | |||
562 | mdoc->flags &= ~MDOC_KEEP(1 << 8); | |||
563 | /* FALLTHROUGH */ | |||
564 | default: | |||
565 | maxargs = 0; | |||
566 | break; | |||
567 | } | |||
568 | ||||
569 | /* Search backwards for the beginning of our own body. */ | |||
570 | ||||
571 | atok = rew_alt(tok); | |||
572 | body = NULL((void *)0); | |||
573 | for (n = mdoc->last; n; n = n->parent) { | |||
574 | if (n->flags & NODE_ENDED(1 << 1) || n->tok != atok || | |||
575 | n->type != ROFFT_BODY || n->end != ENDBODY_NOT) | |||
576 | continue; | |||
577 | body = n; | |||
578 | break; | |||
579 | } | |||
580 | ||||
581 | /* | |||
582 | * Search backwards for beginnings of blocks, | |||
583 | * both of our own and of pending sub-blocks. | |||
584 | */ | |||
585 | ||||
586 | endbody = itblk = later = NULL((void *)0); | |||
587 | for (n = mdoc->last; n; n = n->parent) { | |||
588 | if (n->flags & NODE_ENDED(1 << 1)) | |||
589 | continue; | |||
590 | ||||
591 | /* | |||
592 | * Mismatching end macros can never break anything | |||
593 | * and we only care about the breaking of BLOCKs. | |||
594 | */ | |||
595 | ||||
596 | if (body == NULL((void *)0) || n->type != ROFFT_BLOCK) | |||
597 | continue; | |||
598 | ||||
599 | /* | |||
600 | * SYNOPSIS name blocks can not be broken themselves, | |||
601 | * but they do get broken together with a broken child. | |||
602 | */ | |||
603 | ||||
604 | if (n->tok == MDOC_Nm) { | |||
605 | if (later != NULL((void *)0)) | |||
606 | n->flags |= NODE_BROKEN(1 << 2) | NODE_ENDED(1 << 1); | |||
607 | continue; | |||
608 | } | |||
609 | ||||
610 | if (n->tok == MDOC_It) { | |||
611 | itblk = n; | |||
612 | continue; | |||
613 | } | |||
614 | ||||
615 | if (atok == n->tok) { | |||
616 | ||||
617 | /* | |||
618 | * Found the start of our own block. | |||
619 | * When there is no pending sub block, | |||
620 | * just proceed to closing out. | |||
621 | */ | |||
622 | ||||
623 | if (later == NULL((void *)0) || | |||
624 | (tok == MDOC_El && itblk == NULL((void *)0))) | |||
625 | break; | |||
626 | ||||
627 | /* | |||
628 | * When there is a pending sub block, postpone | |||
629 | * closing out the current block until the | |||
630 | * rew_pending() closing out the sub-block. | |||
631 | * Mark the place where the formatting - but not | |||
632 | * the scope - of the current block ends. | |||
633 | */ | |||
634 | ||||
635 | mandoc_msg(MANDOCERR_BLK_NEST, | |||
636 | line, ppos, "%s breaks %s", | |||
637 | roff_name[atok], roff_name[later->tok]); | |||
638 | ||||
639 | endbody = mdoc_endbody_alloc(mdoc, line, ppos, | |||
640 | atok, body); | |||
641 | ||||
642 | if (tok == MDOC_El) | |||
643 | itblk->flags |= NODE_ENDED(1 << 1) | NODE_BROKEN(1 << 2); | |||
644 | ||||
645 | /* | |||
646 | * If a block closing macro taking arguments | |||
647 | * breaks another block, put the arguments | |||
648 | * into the end marker. | |||
649 | */ | |||
650 | ||||
651 | if (maxargs) | |||
652 | mdoc->next = ROFF_NEXT_CHILD; | |||
653 | break; | |||
654 | } | |||
655 | ||||
656 | /* | |||
657 | * Explicit blocks close out description lines, but | |||
658 | * even those can get broken together with a child. | |||
659 | */ | |||
660 | ||||
661 | if (n->tok == MDOC_Nd) { | |||
662 | if (later != NULL((void *)0)) | |||
663 | n->flags |= NODE_BROKEN(1 << 2) | NODE_ENDED(1 << 1); | |||
664 | else | |||
665 | rew_last(mdoc, n); | |||
666 | continue; | |||
667 | } | |||
668 | ||||
669 | /* Breaking an open sub block. */ | |||
670 | ||||
671 | break_intermediate(mdoc->last, body); | |||
672 | n->flags |= NODE_BROKEN(1 << 2); | |||
673 | if (later == NULL((void *)0)) | |||
674 | later = n; | |||
675 | } | |||
676 | ||||
677 | if (body == NULL((void *)0)) { | |||
678 | mandoc_msg(MANDOCERR_BLK_NOTOPEN, line, ppos, | |||
679 | "%s", roff_name[tok]); | |||
680 | if (maxargs && endbody == NULL((void *)0)) { | |||
681 | /* | |||
682 | * Stray .Ec without previous .Eo: | |||
683 | * Break the output line, keep the arguments. | |||
684 | */ | |||
685 | roff_elem_alloc(mdoc, line, ppos, ROFF_br); | |||
686 | rew_elem(mdoc, ROFF_br); | |||
687 | } | |||
688 | } else if (endbody == NULL((void *)0)) { | |||
689 | rew_last(mdoc, body); | |||
690 | if (maxargs) | |||
691 | mdoc_tail_alloc(mdoc, line, ppos, atok); | |||
692 | } | |||
693 | ||||
694 | if ((mdoc_macro(tok)->flags & MDOC_PARSED(1 << 1)) == 0) { | |||
695 | if (buf[*pos] != '\0') | |||
696 | mandoc_msg(MANDOCERR_ARG_SKIP, line, ppos, | |||
697 | "%s %s", roff_name[tok], buf + *pos); | |||
698 | if (endbody == NULL((void *)0) && n != NULL((void *)0)) | |||
699 | rew_pending(mdoc, n); | |||
700 | ||||
701 | /* | |||
702 | * Restore the fill mode that was set before the display. | |||
703 | * This needs to be done here rather than during validation | |||
704 | * such that subsequent nodes get the right flags. | |||
705 | */ | |||
706 | ||||
707 | if (tok == MDOC_Ed && body != NULL((void *)0)) { | |||
708 | if (body->flags & NODE_NOFILL(1 << 8)) | |||
709 | mdoc->flags |= ROFF_NOFILL(1 << 1); | |||
710 | else | |||
711 | mdoc->flags &= ~ROFF_NOFILL(1 << 1); | |||
712 | } | |||
713 | return; | |||
714 | } | |||
715 | ||||
716 | if (endbody != NULL((void *)0)) | |||
717 | n = endbody; | |||
718 | ||||
719 | ntok = TOKEN_NONE; | |||
720 | for (j = 0; ; j++) { | |||
721 | lastarg = *pos; | |||
722 | ||||
723 | if (j == maxargs && n != NULL((void *)0)) | |||
724 | rew_last(mdoc, n); | |||
725 | ||||
726 | ac = mdoc_args(mdoc, line, pos, buf, tok, &p); | |||
727 | if (ac == ARGS_PUNCT || ac == ARGS_EOLN) | |||
728 | break; | |||
729 | ||||
730 | ntok = lookup(mdoc, tok, line, lastarg, p); | |||
731 | ||||
732 | if (ntok == TOKEN_NONE) { | |||
733 | dword(mdoc, line, lastarg, p, DELIM_MAX, | |||
734 | mdoc_macro(tok)->flags & MDOC_JOIN(1 << 5)); | |||
735 | if (ac == ARGS_ALLOC) | |||
736 | free(p); | |||
737 | continue; | |||
738 | } | |||
739 | if (ac == ARGS_ALLOC) | |||
740 | free(p); | |||
741 | ||||
742 | if (n != NULL((void *)0)) | |||
743 | rew_last(mdoc, n); | |||
744 | mdoc->flags &= ~MDOC_NEWLINE(1 << 3); | |||
745 | (*mdoc_macro(ntok)->fp)(mdoc, ntok, line, lastarg, pos, buf); | |||
746 | break; | |||
747 | } | |||
748 | ||||
749 | if (n != NULL((void *)0)) { | |||
750 | pending = 0; | |||
751 | if (ntok != TOKEN_NONE && n->flags & NODE_BROKEN(1 << 2)) { | |||
752 | target = n; | |||
753 | do | |||
754 | target = target->parent; | |||
755 | while ( ! (target->flags & NODE_ENDED(1 << 1))); | |||
756 | pending = find_pending(mdoc, ntok, line, ppos, target); | |||
757 | } | |||
758 | if ( ! pending) | |||
759 | rew_pending(mdoc, n); | |||
760 | } | |||
761 | if (nl) | |||
762 | append_delims(mdoc, line, pos, buf); | |||
763 | } | |||
764 | ||||
765 | static void | |||
766 | in_line(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
767 | { | |||
768 | int la, scope, cnt, firstarg, mayopen, nc, nl; | |||
769 | enum roff_tok ntok; | |||
770 | enum margserr ac; | |||
771 | enum mdelim d; | |||
772 | struct mdoc_arg *arg; | |||
773 | char *p; | |||
774 | ||||
775 | nl = MDOC_NEWLINE(1 << 3) & mdoc->flags; | |||
776 | ||||
777 | /* | |||
778 | * Whether we allow ignored elements (those without content, | |||
779 | * usually because of reserved words) to squeak by. | |||
780 | */ | |||
781 | ||||
782 | switch (tok) { | |||
783 | case MDOC_An: | |||
784 | case MDOC_Ar: | |||
785 | case MDOC_Fl: | |||
786 | case MDOC_Mt: | |||
787 | case MDOC_Nm: | |||
788 | case MDOC_Pa: | |||
789 | nc = 1; | |||
790 | break; | |||
791 | default: | |||
792 | nc = 0; | |||
793 | break; | |||
794 | } | |||
795 | ||||
796 | mdoc_argv(mdoc, line, tok, &arg, pos, buf); | |||
797 | ||||
798 | d = DELIM_NONE; | |||
799 | firstarg = 1; | |||
800 | mayopen = 1; | |||
801 | for (cnt = scope = 0;; ) { | |||
802 | la = *pos; | |||
803 | ac = mdoc_args(mdoc, line, pos, buf, tok, &p); | |||
804 | ||||
805 | /* | |||
806 | * At the end of a macro line, | |||
807 | * opening delimiters do not suppress spacing. | |||
808 | */ | |||
809 | ||||
810 | if (ac == ARGS_EOLN) { | |||
811 | if (d == DELIM_OPEN) | |||
812 | mdoc->last->flags &= ~NODE_DELIMO(1 << 4); | |||
813 | break; | |||
814 | } | |||
815 | ||||
816 | /* | |||
817 | * The rest of the macro line is only punctuation, | |||
818 | * to be handled by append_delims(). | |||
819 | * If there were no other arguments, | |||
820 | * do not allow the first one to suppress spacing, | |||
821 | * even if it turns out to be a closing one. | |||
822 | */ | |||
823 | ||||
824 | if (ac == ARGS_PUNCT) { | |||
825 | if (cnt == 0 && (nc == 0 || tok == MDOC_An)) | |||
826 | mdoc->flags |= MDOC_NODELIMC(1 << 10); | |||
827 | break; | |||
828 | } | |||
829 | ||||
830 | ntok = (tok == MDOC_Fn && !cnt) ? | |||
831 | TOKEN_NONE : lookup(mdoc, tok, line, la, p); | |||
832 | ||||
833 | /* | |||
834 | * In this case, we've located a submacro and must | |||
835 | * execute it. Close out scope, if open. If no | |||
836 | * elements have been generated, either create one (nc) | |||
837 | * or raise a warning. | |||
838 | */ | |||
839 | ||||
840 | if (ntok != TOKEN_NONE) { | |||
841 | if (scope) | |||
842 | rew_elem(mdoc, tok); | |||
843 | if (nc && ! cnt) { | |||
844 | mdoc_elem_alloc(mdoc, line, ppos, tok, arg); | |||
845 | rew_last(mdoc, mdoc->last); | |||
846 | } else if ( ! nc && ! cnt) { | |||
847 | mdoc_argv_free(arg); | |||
848 | mandoc_msg(MANDOCERR_MACRO_EMPTY, | |||
849 | line, ppos, "%s", roff_name[tok]); | |||
850 | } | |||
851 | (*mdoc_macro(ntok)->fp)(mdoc, ntok, | |||
852 | line, la, pos, buf); | |||
853 | if (nl) | |||
854 | append_delims(mdoc, line, pos, buf); | |||
855 | if (ac == ARGS_ALLOC) | |||
856 | free(p); | |||
857 | return; | |||
858 | } | |||
859 | ||||
860 | /* | |||
861 | * Handle punctuation. Set up our scope, if a word; | |||
862 | * rewind the scope, if a delimiter; then append the word. | |||
863 | */ | |||
864 | ||||
865 | if ((d = mdoc_isdelim(p)) != DELIM_NONE) { | |||
866 | /* | |||
867 | * If we encounter closing punctuation, no word | |||
868 | * has been emitted, no scope is open, and we're | |||
869 | * allowed to have an empty element, then start | |||
870 | * a new scope. | |||
871 | */ | |||
872 | if ((d == DELIM_CLOSE || | |||
873 | (d == DELIM_MIDDLE && tok == MDOC_Fl)) && | |||
874 | !cnt && !scope && nc && mayopen) { | |||
875 | mdoc_elem_alloc(mdoc, line, ppos, tok, arg); | |||
876 | scope = 1; | |||
877 | cnt++; | |||
878 | if (tok == MDOC_Nm) | |||
879 | mayopen = 0; | |||
880 | } | |||
881 | /* | |||
882 | * Close out our scope, if one is open, before | |||
883 | * any punctuation. | |||
884 | */ | |||
885 | if (scope && tok != MDOC_Lk) { | |||
886 | rew_elem(mdoc, tok); | |||
887 | scope = 0; | |||
888 | if (tok == MDOC_Fn) | |||
889 | mayopen = 0; | |||
890 | } | |||
891 | } else if (mayopen && !scope) { | |||
892 | mdoc_elem_alloc(mdoc, line, ppos, tok, arg); | |||
893 | scope = 1; | |||
894 | cnt++; | |||
895 | } | |||
896 | ||||
897 | dword(mdoc, line, la, p, d, | |||
898 | mdoc_macro(tok)->flags & MDOC_JOIN(1 << 5)); | |||
899 | ||||
900 | if (ac == ARGS_ALLOC) | |||
901 | free(p); | |||
902 | ||||
903 | /* | |||
904 | * If the first argument is a closing delimiter, | |||
905 | * do not suppress spacing before it. | |||
906 | */ | |||
907 | ||||
908 | if (firstarg && d == DELIM_CLOSE && !nc) | |||
909 | mdoc->last->flags &= ~NODE_DELIMC(1 << 5); | |||
910 | firstarg = 0; | |||
911 | ||||
912 | /* | |||
913 | * `Fl' macros have their scope re-opened with each new | |||
914 | * word so that the `-' can be added to each one without | |||
915 | * having to parse out spaces. | |||
916 | */ | |||
917 | if (scope && tok == MDOC_Fl) { | |||
918 | rew_elem(mdoc, tok); | |||
919 | scope = 0; | |||
920 | } | |||
921 | } | |||
922 | ||||
923 | if (scope && tok != MDOC_Lk) { | |||
924 | rew_elem(mdoc, tok); | |||
925 | scope = 0; | |||
926 | } | |||
927 | ||||
928 | /* | |||
929 | * If no elements have been collected and we're allowed to have | |||
930 | * empties (nc), open a scope and close it out. Otherwise, | |||
931 | * raise a warning. | |||
932 | */ | |||
933 | ||||
934 | if ( ! cnt) { | |||
935 | if (nc) { | |||
936 | mdoc_elem_alloc(mdoc, line, ppos, tok, arg); | |||
937 | rew_last(mdoc, mdoc->last); | |||
938 | } else { | |||
939 | mdoc_argv_free(arg); | |||
940 | mandoc_msg(MANDOCERR_MACRO_EMPTY, | |||
941 | line, ppos, "%s", roff_name[tok]); | |||
942 | } | |||
943 | } | |||
944 | if (nl) | |||
945 | append_delims(mdoc, line, pos, buf); | |||
946 | if (scope) | |||
947 | rew_elem(mdoc, tok); | |||
948 | } | |||
949 | ||||
950 | static void | |||
951 | blk_full(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
952 | { | |||
953 | struct mdoc_arg *arg; | |||
954 | struct roff_node *blk; /* Our own or a broken block. */ | |||
955 | struct roff_node *head; /* Our own head. */ | |||
956 | struct roff_node *body; /* Our own body. */ | |||
957 | struct roff_node *n; | |||
958 | char *p; | |||
959 | size_t iarg; | |||
960 | int done, la, nl, parsed; | |||
961 | enum margserr ac, lac; | |||
962 | ||||
963 | nl = MDOC_NEWLINE(1 << 3) & mdoc->flags; | |||
964 | ||||
965 | if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) { | |||
966 | mandoc_msg(MANDOCERR_MACRO_EMPTY, | |||
967 | line, ppos, "%s", roff_name[tok]); | |||
968 | return; | |||
969 | } | |||
970 | ||||
971 | if ((mdoc_macro(tok)->flags & MDOC_EXPLICIT(1 << 2)) == 0) { | |||
972 | ||||
973 | /* Here, tok is one of Sh Ss Nm Nd It. */ | |||
974 | ||||
975 | blk = NULL((void *)0); | |||
976 | for (n = mdoc->last; n != NULL((void *)0); n = n->parent) { | |||
977 | if (n->flags & NODE_ENDED(1 << 1)) { | |||
978 | if ( ! (n->flags & NODE_VALID(1 << 0))) | |||
979 | n->flags |= NODE_BROKEN(1 << 2); | |||
980 | continue; | |||
981 | } | |||
982 | if (n->type != ROFFT_BLOCK) | |||
983 | continue; | |||
984 | ||||
985 | if (tok == MDOC_It && n->tok == MDOC_Bl) { | |||
986 | if (blk != NULL((void *)0)) { | |||
987 | mandoc_msg(MANDOCERR_BLK_BROKEN, | |||
988 | line, ppos, "It breaks %s", | |||
989 | roff_name[blk->tok]); | |||
990 | rew_pending(mdoc, blk); | |||
991 | } | |||
992 | break; | |||
993 | } | |||
994 | ||||
995 | if (mdoc_macro(n->tok)->flags & MDOC_EXPLICIT(1 << 2)) { | |||
996 | switch (tok) { | |||
997 | case MDOC_Sh: | |||
998 | case MDOC_Ss: | |||
999 | mandoc_msg(MANDOCERR_BLK_BROKEN, | |||
1000 | line, ppos, | |||
1001 | "%s breaks %s", roff_name[tok], | |||
1002 | roff_name[n->tok]); | |||
1003 | rew_pending(mdoc, n); | |||
1004 | n = mdoc->last; | |||
1005 | continue; | |||
1006 | case MDOC_It: | |||
1007 | /* Delay in case it's astray. */ | |||
1008 | blk = n; | |||
1009 | continue; | |||
1010 | default: | |||
1011 | break; | |||
1012 | } | |||
1013 | break; | |||
1014 | } | |||
1015 | ||||
1016 | /* Here, n is one of Sh Ss Nm Nd It. */ | |||
1017 | ||||
1018 | if (tok != MDOC_Sh && (n->tok == MDOC_Sh || | |||
1019 | (tok != MDOC_Ss && (n->tok == MDOC_Ss || | |||
1020 | (tok != MDOC_It && n->tok == MDOC_It))))) | |||
1021 | break; | |||
1022 | ||||
1023 | /* Item breaking an explicit block. */ | |||
1024 | ||||
1025 | if (blk != NULL((void *)0)) { | |||
1026 | mandoc_msg(MANDOCERR_BLK_BROKEN, line, ppos, | |||
1027 | "It breaks %s", roff_name[blk->tok]); | |||
1028 | rew_pending(mdoc, blk); | |||
1029 | blk = NULL((void *)0); | |||
1030 | } | |||
1031 | ||||
1032 | /* Close out prior implicit scopes. */ | |||
1033 | ||||
1034 | rew_pending(mdoc, n); | |||
1035 | } | |||
1036 | ||||
1037 | /* Skip items outside lists. */ | |||
1038 | ||||
1039 | if (tok == MDOC_It && (n == NULL((void *)0) || n->tok != MDOC_Bl)) { | |||
1040 | mandoc_msg(MANDOCERR_IT_STRAY, | |||
1041 | line, ppos, "It %s", buf + *pos); | |||
1042 | roff_elem_alloc(mdoc, line, ppos, ROFF_br); | |||
1043 | rew_elem(mdoc, ROFF_br); | |||
1044 | return; | |||
1045 | } | |||
1046 | } | |||
1047 | ||||
1048 | /* | |||
1049 | * This routine accommodates implicitly- and explicitly-scoped | |||
1050 | * macro openings. Implicit ones first close out prior scope | |||
1051 | * (seen above). Delay opening the head until necessary to | |||
1052 | * allow leading punctuation to print. Special consideration | |||
1053 | * for `It -column', which has phrase-part syntax instead of | |||
1054 | * regular child nodes. | |||
1055 | */ | |||
1056 | ||||
1057 | switch (tok) { | |||
1058 | case MDOC_Sh: | |||
1059 | mdoc->flags &= ~ROFF_NOFILL(1 << 1); | |||
1060 | break; | |||
1061 | case MDOC_Ss: | |||
1062 | mdoc->flags |= ROFF_NONOFILL(1 << 16); | |||
1063 | break; | |||
1064 | default: | |||
1065 | break; | |||
1066 | } | |||
1067 | mdoc_argv(mdoc, line, tok, &arg, pos, buf); | |||
1068 | blk = mdoc_block_alloc(mdoc, line, ppos, tok, arg); | |||
1069 | head = body = NULL((void *)0); | |||
1070 | ||||
1071 | /* | |||
1072 | * Exception: Heads of `It' macros in `-diag' lists are not | |||
1073 | * parsed, even though `It' macros in general are parsed. | |||
1074 | */ | |||
1075 | ||||
1076 | parsed = tok != MDOC_It || | |||
1077 | mdoc->last->parent->tok != MDOC_Bl || | |||
1078 | mdoc->last->parent->norm->Bl.type != LIST_diag; | |||
1079 | ||||
1080 | /* | |||
1081 | * The `Nd' macro has all arguments in its body: it's a hybrid | |||
1082 | * of block partial-explicit and full-implicit. Stupid. | |||
1083 | */ | |||
1084 | ||||
1085 | if (tok == MDOC_Nd) { | |||
1086 | head = roff_head_alloc(mdoc, line, ppos, tok); | |||
1087 | rew_last(mdoc, head); | |||
1088 | body = roff_body_alloc(mdoc, line, ppos, tok); | |||
1089 | } | |||
1090 | ||||
1091 | if (tok == MDOC_Bk) | |||
1092 | mdoc->flags |= MDOC_KEEP(1 << 8); | |||
1093 | ||||
1094 | ac = ARGS_EOLN; | |||
1095 | for (;;) { | |||
1096 | ||||
1097 | /* | |||
1098 | * If we are right after a tab character, | |||
1099 | * do not parse the first word for macros. | |||
1100 | */ | |||
1101 | ||||
1102 | if (mdoc->flags & MDOC_PHRASEQN(1 << 15)) { | |||
1103 | mdoc->flags &= ~MDOC_PHRASEQN(1 << 15); | |||
1104 | mdoc->flags |= MDOC_PHRASEQF(1 << 13); | |||
1105 | } | |||
1106 | ||||
1107 | la = *pos; | |||
1108 | lac = ac; | |||
1109 | ac = mdoc_args(mdoc, line, pos, buf, tok, &p); | |||
1110 | if (ac == ARGS_EOLN) { | |||
1111 | if (lac != ARGS_PHRASE || | |||
1112 | ! (mdoc->flags & MDOC_PHRASEQF(1 << 13))) | |||
1113 | break; | |||
1114 | ||||
1115 | /* | |||
1116 | * This line ends in a tab; start the next | |||
1117 | * column now, with a leading blank. | |||
1118 | */ | |||
1119 | ||||
1120 | if (body != NULL((void *)0)) | |||
1121 | rew_last(mdoc, body); | |||
1122 | body = roff_body_alloc(mdoc, line, ppos, tok); | |||
1123 | roff_word_alloc(mdoc, line, ppos, "\\&"); | |||
1124 | break; | |||
1125 | } | |||
1126 | ||||
1127 | if (tok == MDOC_Bd || tok == MDOC_Bk) { | |||
1128 | mandoc_msg(MANDOCERR_ARG_EXCESS, line, la, | |||
1129 | "%s ... %s", roff_name[tok], buf + la); | |||
1130 | if (ac == ARGS_ALLOC) | |||
1131 | free(p); | |||
1132 | break; | |||
1133 | } | |||
1134 | if (tok == MDOC_Rs) { | |||
1135 | mandoc_msg(MANDOCERR_ARG_SKIP, | |||
1136 | line, la, "Rs %s", buf + la); | |||
1137 | if (ac == ARGS_ALLOC) | |||
1138 | free(p); | |||
1139 | break; | |||
1140 | } | |||
1141 | if (ac == ARGS_PUNCT) | |||
1142 | break; | |||
1143 | ||||
1144 | /* | |||
1145 | * Emit leading punctuation (i.e., punctuation before | |||
1146 | * the ROFFT_HEAD) for non-phrase types. | |||
1147 | */ | |||
1148 | ||||
1149 | if (head == NULL((void *)0) && | |||
1150 | ac != ARGS_PHRASE && | |||
1151 | mdoc_isdelim(p) == DELIM_OPEN) { | |||
1152 | dword(mdoc, line, la, p, DELIM_OPEN, 0); | |||
1153 | if (ac == ARGS_ALLOC) | |||
1154 | free(p); | |||
1155 | continue; | |||
1156 | } | |||
1157 | ||||
1158 | /* Open a head if one hasn't been opened. */ | |||
1159 | ||||
1160 | if (head == NULL((void *)0)) | |||
1161 | head = roff_head_alloc(mdoc, line, ppos, tok); | |||
1162 | ||||
1163 | if (ac == ARGS_PHRASE) { | |||
1164 | ||||
1165 | /* | |||
1166 | * If we haven't opened a body yet, rewind the | |||
1167 | * head; if we have, rewind that instead. | |||
1168 | */ | |||
1169 | ||||
1170 | rew_last(mdoc, body == NULL((void *)0) ? head : body); | |||
1171 | body = roff_body_alloc(mdoc, line, ppos, tok); | |||
1172 | ||||
1173 | /* Process to the tab or to the end of the line. */ | |||
1174 | ||||
1175 | mdoc->flags |= MDOC_PHRASE(1 << 4); | |||
1176 | parse_rest(mdoc, TOKEN_NONE, line, &la, buf); | |||
1177 | mdoc->flags &= ~MDOC_PHRASE(1 << 4); | |||
1178 | ||||
1179 | /* There may have been `Ta' macros. */ | |||
1180 | ||||
1181 | while (body->next != NULL((void *)0)) | |||
1182 | body = body->next; | |||
1183 | continue; | |||
1184 | } | |||
1185 | ||||
1186 | done = macro_or_word(mdoc, tok, line, la, pos, buf, p, parsed); | |||
1187 | if (ac == ARGS_ALLOC) | |||
1188 | free(p); | |||
1189 | if (done) | |||
1190 | break; | |||
1191 | } | |||
1192 | ||||
1193 | if (blk->flags & NODE_VALID(1 << 0)) | |||
1194 | return; | |||
1195 | if (head == NULL((void *)0)) | |||
1196 | head = roff_head_alloc(mdoc, line, ppos, tok); | |||
1197 | if (nl && tok != MDOC_Bd && tok != MDOC_Bl && tok != MDOC_Rs) | |||
1198 | append_delims(mdoc, line, pos, buf); | |||
1199 | if (body != NULL((void *)0)) | |||
1200 | goto out; | |||
1201 | if (find_pending(mdoc, tok, line, ppos, head)) | |||
1202 | return; | |||
1203 | ||||
1204 | /* Close out scopes to remain in a consistent state. */ | |||
1205 | ||||
1206 | rew_last(mdoc, head); | |||
1207 | body = roff_body_alloc(mdoc, line, ppos, tok); | |||
1208 | if (tok == MDOC_Ss) | |||
1209 | mdoc->flags &= ~ROFF_NONOFILL(1 << 16); | |||
1210 | ||||
1211 | /* | |||
1212 | * Set up fill mode for display blocks. | |||
1213 | * This needs to be done here up front rather than during | |||
1214 | * validation such that child nodes get the right flags. | |||
1215 | */ | |||
1216 | ||||
1217 | if (tok == MDOC_Bd && arg != NULL((void *)0)) { | |||
1218 | for (iarg = 0; iarg < arg->argc; iarg++) { | |||
1219 | switch (arg->argv[iarg].arg) { | |||
1220 | case MDOC_Unfilled: | |||
1221 | case MDOC_Literal: | |||
1222 | mdoc->flags |= ROFF_NOFILL(1 << 1); | |||
1223 | break; | |||
1224 | case MDOC_Filled: | |||
1225 | case MDOC_Ragged: | |||
1226 | case MDOC_Centred: | |||
1227 | mdoc->flags &= ~ROFF_NOFILL(1 << 1); | |||
1228 | break; | |||
1229 | default: | |||
1230 | continue; | |||
1231 | } | |||
1232 | break; | |||
1233 | } | |||
1234 | } | |||
1235 | out: | |||
1236 | if (mdoc->flags & MDOC_FREECOL(1 << 6)) { | |||
1237 | rew_last(mdoc, body); | |||
1238 | rew_last(mdoc, blk); | |||
1239 | mdoc->flags &= ~MDOC_FREECOL(1 << 6); | |||
1240 | } | |||
1241 | } | |||
1242 | ||||
1243 | static void | |||
1244 | blk_part_imp(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
1245 | { | |||
1246 | int done, la, nl; | |||
1247 | enum margserr ac; | |||
1248 | char *p; | |||
1249 | struct roff_node *blk; /* saved block context */ | |||
1250 | struct roff_node *body; /* saved body context */ | |||
1251 | struct roff_node *n; | |||
1252 | ||||
1253 | nl = MDOC_NEWLINE(1 << 3) & mdoc->flags; | |||
1254 | ||||
1255 | /* | |||
1256 | * A macro that spans to the end of the line. This is generally | |||
1257 | * (but not necessarily) called as the first macro. The block | |||
1258 | * has a head as the immediate child, which is always empty, | |||
1259 | * followed by zero or more opening punctuation nodes, then the | |||
1260 | * body (which may be empty, depending on the macro), then zero | |||
1261 | * or more closing punctuation nodes. | |||
1262 | */ | |||
1263 | ||||
1264 | blk = mdoc_block_alloc(mdoc, line, ppos, tok, NULL((void *)0)); | |||
1265 | rew_last(mdoc, roff_head_alloc(mdoc, line, ppos, tok)); | |||
1266 | ||||
1267 | /* | |||
1268 | * Open the body scope "on-demand", that is, after we've | |||
1269 | * processed all our the leading delimiters (open parenthesis, | |||
1270 | * etc.). | |||
1271 | */ | |||
1272 | ||||
1273 | for (body = NULL((void *)0); ; ) { | |||
1274 | la = *pos; | |||
1275 | ac = mdoc_args(mdoc, line, pos, buf, tok, &p); | |||
1276 | if (ac == ARGS_EOLN || ac == ARGS_PUNCT) | |||
1277 | break; | |||
1278 | ||||
1279 | if (body == NULL((void *)0) && mdoc_isdelim(p) == DELIM_OPEN) { | |||
1280 | dword(mdoc, line, la, p, DELIM_OPEN, 0); | |||
1281 | if (ac == ARGS_ALLOC) | |||
1282 | free(p); | |||
1283 | continue; | |||
1284 | } | |||
1285 | ||||
1286 | if (body == NULL((void *)0)) | |||
1287 | body = roff_body_alloc(mdoc, line, ppos, tok); | |||
1288 | ||||
1289 | done = macro_or_word(mdoc, tok, line, la, pos, buf, p, 1); | |||
1290 | if (ac == ARGS_ALLOC) | |||
1291 | free(p); | |||
1292 | if (done) | |||
1293 | break; | |||
1294 | } | |||
1295 | if (body == NULL((void *)0)) | |||
1296 | body = roff_body_alloc(mdoc, line, ppos, tok); | |||
1297 | ||||
1298 | if (find_pending(mdoc, tok, line, ppos, body)) | |||
1299 | return; | |||
1300 | ||||
1301 | rew_last(mdoc, body); | |||
1302 | if (nl) | |||
1303 | append_delims(mdoc, line, pos, buf); | |||
1304 | rew_pending(mdoc, blk); | |||
1305 | ||||
1306 | /* Move trailing .Ns out of scope. */ | |||
1307 | ||||
1308 | for (n = body->child; n && n->next; n = n->next) | |||
1309 | /* Do nothing. */ ; | |||
1310 | if (n && n->tok == MDOC_Ns) | |||
1311 | roff_node_relink(mdoc, n); | |||
1312 | } | |||
1313 | ||||
1314 | static void | |||
1315 | blk_part_exp(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
1316 | { | |||
1317 | int done, la, nl; | |||
1318 | enum margserr ac; | |||
1319 | struct roff_node *head; /* keep track of head */ | |||
1320 | char *p; | |||
1321 | ||||
1322 | nl = MDOC_NEWLINE(1 << 3) & mdoc->flags; | |||
1323 | ||||
1324 | /* | |||
1325 | * The opening of an explicit macro having zero or more leading | |||
1326 | * punctuation nodes; a head with optional single element (the | |||
1327 | * case of `Eo'); and a body that may be empty. | |||
1328 | */ | |||
1329 | ||||
1330 | roff_block_alloc(mdoc, line, ppos, tok); | |||
1331 | head = NULL((void *)0); | |||
1332 | for (;;) { | |||
1333 | la = *pos; | |||
1334 | ac = mdoc_args(mdoc, line, pos, buf, tok, &p); | |||
1335 | if (ac == ARGS_PUNCT || ac == ARGS_EOLN) | |||
1336 | break; | |||
1337 | ||||
1338 | /* Flush out leading punctuation. */ | |||
1339 | ||||
1340 | if (head == NULL((void *)0) && mdoc_isdelim(p) == DELIM_OPEN) { | |||
1341 | dword(mdoc, line, la, p, DELIM_OPEN, 0); | |||
1342 | if (ac == ARGS_ALLOC) | |||
1343 | free(p); | |||
1344 | continue; | |||
1345 | } | |||
1346 | ||||
1347 | if (head == NULL((void *)0)) { | |||
1348 | head = roff_head_alloc(mdoc, line, ppos, tok); | |||
1349 | if (tok == MDOC_Eo) /* Not parsed. */ | |||
1350 | dword(mdoc, line, la, p, DELIM_MAX, 0); | |||
1351 | rew_last(mdoc, head); | |||
1352 | roff_body_alloc(mdoc, line, ppos, tok); | |||
1353 | if (tok == MDOC_Eo) { | |||
1354 | if (ac == ARGS_ALLOC) | |||
1355 | free(p); | |||
1356 | continue; | |||
1357 | } | |||
1358 | } | |||
1359 | ||||
1360 | done = macro_or_word(mdoc, tok, line, la, pos, buf, p, 1); | |||
1361 | if (ac == ARGS_ALLOC) | |||
1362 | free(p); | |||
1363 | if (done) | |||
1364 | break; | |||
1365 | } | |||
1366 | ||||
1367 | /* Clean-up to leave in a consistent state. */ | |||
1368 | ||||
1369 | if (head == NULL((void *)0)) { | |||
1370 | rew_last(mdoc, roff_head_alloc(mdoc, line, ppos, tok)); | |||
1371 | roff_body_alloc(mdoc, line, ppos, tok); | |||
1372 | } | |||
1373 | if (nl) | |||
1374 | append_delims(mdoc, line, pos, buf); | |||
1375 | } | |||
1376 | ||||
1377 | static void | |||
1378 | in_line_argn(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
1379 | { | |||
1380 | struct mdoc_arg *arg; | |||
1381 | char *p; | |||
1382 | enum margserr ac; | |||
1383 | enum roff_tok ntok; | |||
1384 | int state; /* arg#; -1: not yet open; -2: closed */ | |||
1385 | int la, maxargs, nl; | |||
1386 | ||||
1387 | nl = mdoc->flags & MDOC_NEWLINE(1 << 3); | |||
1388 | ||||
1389 | /* | |||
1390 | * A line macro that has a fixed number of arguments (maxargs). | |||
1391 | * Only open the scope once the first non-leading-punctuation is | |||
1392 | * found (unless MDOC_IGNDELIM is noted, like in `Pf'), then | |||
1393 | * keep it open until the maximum number of arguments are | |||
1394 | * exhausted. | |||
1395 | */ | |||
1396 | ||||
1397 | switch (tok) { | |||
1398 | case MDOC_Ap: | |||
1399 | case MDOC_Ns: | |||
1400 | case MDOC_Ux: | |||
1401 | maxargs = 0; | |||
1402 | break; | |||
1403 | case MDOC_Bx: | |||
1404 | case MDOC_Es: | |||
1405 | case MDOC_Xr: | |||
1406 | maxargs = 2; | |||
1407 | break; | |||
1408 | default: | |||
1409 | maxargs = 1; | |||
1410 | break; | |||
1411 | } | |||
1412 | ||||
1413 | mdoc_argv(mdoc, line, tok, &arg, pos, buf); | |||
1414 | ||||
1415 | state = -1; | |||
1416 | p = NULL((void *)0); | |||
1417 | for (;;) { | |||
1418 | la = *pos; | |||
1419 | ac = mdoc_args(mdoc, line, pos, buf, tok, &p); | |||
1420 | ||||
1421 | if ((ac == ARGS_WORD || ac == ARGS_ALLOC) && state == -1 && | |||
1422 | (mdoc_macro(tok)->flags & MDOC_IGNDELIM(1 << 4)) == 0 && | |||
1423 | mdoc_isdelim(p) == DELIM_OPEN) { | |||
1424 | dword(mdoc, line, la, p, DELIM_OPEN, 0); | |||
1425 | if (ac == ARGS_ALLOC) | |||
1426 | free(p); | |||
1427 | continue; | |||
1428 | } | |||
1429 | ||||
1430 | if (state == -1 && tok != MDOC_In && | |||
1431 | tok != MDOC_St && tok != MDOC_Xr) { | |||
1432 | mdoc_elem_alloc(mdoc, line, ppos, tok, arg); | |||
1433 | state = 0; | |||
1434 | } | |||
1435 | ||||
1436 | if (ac == ARGS_PUNCT || ac == ARGS_EOLN) { | |||
1437 | if (abs(state) < 2 && tok == MDOC_Pf) | |||
1438 | mandoc_msg(MANDOCERR_PF_SKIP, | |||
1439 | line, ppos, "Pf %s", | |||
1440 | p == NULL((void *)0) ? "at eol" : p); | |||
1441 | break; | |||
1442 | } | |||
1443 | ||||
1444 | if (state == maxargs) { | |||
1445 | rew_elem(mdoc, tok); | |||
1446 | state = -2; | |||
1447 | } | |||
1448 | ||||
1449 | ntok = (tok == MDOC_Pf && state == 0) ? | |||
1450 | TOKEN_NONE : lookup(mdoc, tok, line, la, p); | |||
1451 | ||||
1452 | if (ntok != TOKEN_NONE) { | |||
1453 | if (state >= 0) { | |||
1454 | rew_elem(mdoc, tok); | |||
1455 | state = -2; | |||
1456 | } | |||
1457 | (*mdoc_macro(ntok)->fp)(mdoc, ntok, | |||
1458 | line, la, pos, buf); | |||
1459 | if (ac == ARGS_ALLOC) | |||
1460 | free(p); | |||
1461 | break; | |||
1462 | } | |||
1463 | ||||
1464 | if (mdoc_macro(tok)->flags & MDOC_IGNDELIM(1 << 4) || | |||
1465 | mdoc_isdelim(p) == DELIM_NONE) { | |||
1466 | if (state == -1) { | |||
1467 | mdoc_elem_alloc(mdoc, line, ppos, tok, arg); | |||
1468 | state = 1; | |||
1469 | } else if (state >= 0) | |||
1470 | state++; | |||
1471 | } else if (state >= 0) { | |||
1472 | rew_elem(mdoc, tok); | |||
1473 | state = -2; | |||
1474 | } | |||
1475 | ||||
1476 | dword(mdoc, line, la, p, DELIM_MAX, | |||
1477 | mdoc_macro(tok)->flags & MDOC_JOIN(1 << 5)); | |||
1478 | if (ac == ARGS_ALLOC) | |||
1479 | free(p); | |||
1480 | p = mdoc->last->string; | |||
1481 | } | |||
1482 | ||||
1483 | if (state == -1) { | |||
1484 | mandoc_msg(MANDOCERR_MACRO_EMPTY, | |||
1485 | line, ppos, "%s", roff_name[tok]); | |||
1486 | return; | |||
1487 | } | |||
1488 | ||||
1489 | if (state == 0 && tok == MDOC_Pf) | |||
1490 | append_delims(mdoc, line, pos, buf); | |||
1491 | if (state >= 0) | |||
1492 | rew_elem(mdoc, tok); | |||
1493 | if (nl) | |||
1494 | append_delims(mdoc, line, pos, buf); | |||
1495 | } | |||
1496 | ||||
1497 | static void | |||
1498 | in_line_eoln(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
1499 | { | |||
1500 | struct roff_node *n; | |||
1501 | struct mdoc_arg *arg; | |||
1502 | ||||
1503 | if ((tok == MDOC_Pp || tok == MDOC_Lp) && | |||
1504 | ! (mdoc->flags & MDOC_SYNOPSIS(1 << 7))) { | |||
1505 | n = mdoc->last; | |||
1506 | if (mdoc->next == ROFF_NEXT_SIBLING) | |||
1507 | n = n->parent; | |||
1508 | if (n->tok == MDOC_Nm) | |||
1509 | rew_last(mdoc, n->parent); | |||
1510 | } | |||
1511 | ||||
1512 | if (buf[*pos] == '\0' && | |||
1513 | (tok == MDOC_Fd || *roff_name[tok] == '%')) { | |||
1514 | mandoc_msg(MANDOCERR_MACRO_EMPTY, | |||
1515 | line, ppos, "%s", roff_name[tok]); | |||
1516 | return; | |||
1517 | } | |||
1518 | ||||
1519 | mdoc_argv(mdoc, line, tok, &arg, pos, buf); | |||
1520 | mdoc_elem_alloc(mdoc, line, ppos, tok, arg); | |||
1521 | if (parse_rest(mdoc, tok, line, pos, buf)) | |||
1522 | return; | |||
1523 | rew_elem(mdoc, tok); | |||
1524 | } | |||
1525 | ||||
1526 | /* | |||
1527 | * The simplest argument parser available: Parse the remaining | |||
1528 | * words until the end of the phrase or line and return 0 | |||
1529 | * or until the next macro, call that macro, and return 1. | |||
1530 | */ | |||
1531 | static int | |||
1532 | parse_rest(struct roff_man *mdoc, enum roff_tok tok, | |||
1533 | int line, int *pos, char *buf) | |||
1534 | { | |||
1535 | char *p; | |||
1536 | int done, la; | |||
1537 | enum margserr ac; | |||
1538 | ||||
1539 | for (;;) { | |||
1540 | la = *pos; | |||
1541 | ac = mdoc_args(mdoc, line, pos, buf, tok, &p); | |||
1542 | if (ac == ARGS_EOLN) | |||
1543 | return 0; | |||
1544 | done = macro_or_word(mdoc, tok, line, la, pos, buf, p, 1); | |||
1545 | if (ac == ARGS_ALLOC) | |||
1546 | free(p); | |||
1547 | if (done) | |||
1548 | return 1; | |||
1549 | } | |||
1550 | } | |||
1551 | ||||
1552 | static void | |||
1553 | ctx_synopsis(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
1554 | { | |||
1555 | ||||
1556 | if (~mdoc->flags & (MDOC_SYNOPSIS(1 << 7) | MDOC_NEWLINE(1 << 3))) | |||
1557 | in_line(mdoc, tok, line, ppos, pos, buf); | |||
1558 | else if (tok == MDOC_Nm) | |||
1559 | blk_full(mdoc, tok, line, ppos, pos, buf); | |||
1560 | else { | |||
1561 | assert(tok == MDOC_Vt)((tok == MDOC_Vt) ? (void)0 : __assert2("/usr/src/usr.bin/mandoc/mdoc_macro.c" , 1561, __func__, "tok == MDOC_Vt")); | |||
1562 | blk_part_imp(mdoc, tok, line, ppos, pos, buf); | |||
1563 | } | |||
1564 | } | |||
1565 | ||||
1566 | /* | |||
1567 | * Phrases occur within `Bl -column' entries, separated by `Ta' or tabs. | |||
1568 | * They're unusual because they're basically free-form text until a | |||
1569 | * macro is encountered. | |||
1570 | */ | |||
1571 | static void | |||
1572 | phrase_ta(MACRO_PROT_ARGSstruct roff_man *mdoc, enum roff_tok tok, int line, int ppos, int *pos, char *buf) | |||
1573 | { | |||
1574 | struct roff_node *body, *n; | |||
1575 | ||||
1576 | /* Make sure we are in a column list or ignore this macro. */ | |||
1577 | ||||
1578 | body = NULL((void *)0); | |||
| ||||
1579 | for (n = mdoc->last; n != NULL((void *)0); n = n->parent) { | |||
1580 | if (n->flags & NODE_ENDED(1 << 1)) | |||
1581 | continue; | |||
1582 | if (n->tok == MDOC_It && n->type == ROFFT_BODY) | |||
1583 | body = n; | |||
1584 | if (n->tok == MDOC_Bl && n->end == ENDBODY_NOT) | |||
1585 | break; | |||
1586 | } | |||
1587 | ||||
1588 | if (n
| |||
1589 | mandoc_msg(MANDOCERR_TA_STRAY, line, ppos, "Ta"); | |||
1590 | return; | |||
1591 | } | |||
1592 | ||||
1593 | /* Advance to the next column. */ | |||
1594 | ||||
1595 | rew_last(mdoc, body); | |||
1596 | roff_body_alloc(mdoc, line, ppos, MDOC_It); | |||
1597 | parse_rest(mdoc, TOKEN_NONE, line, pos, buf); | |||
1598 | } |