man_validate.c revision 1.1.1.15 1 1.1.1.15 joerg /* Id: man_validate.c,v 1.87 2013/12/31 18:07:42 schwarze Exp */
2 1.1 joerg /*
3 1.1.1.12 joerg * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps (at) bsd.lv>
4 1.1.1.15 joerg * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze (at) openbsd.org>
5 1.1 joerg *
6 1.1 joerg * Permission to use, copy, modify, and distribute this software for any
7 1.1 joerg * purpose with or without fee is hereby granted, provided that the above
8 1.1 joerg * copyright notice and this permission notice appear in all copies.
9 1.1 joerg *
10 1.1 joerg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 1.1 joerg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 1.1 joerg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 1.1 joerg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 1.1 joerg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 1.1 joerg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 1.1 joerg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 1.1 joerg */
18 1.1.1.4 joerg #ifdef HAVE_CONFIG_H
19 1.1.1.4 joerg #include "config.h"
20 1.1.1.4 joerg #endif
21 1.1.1.4 joerg
22 1.1 joerg #include <sys/types.h>
23 1.1 joerg
24 1.1 joerg #include <assert.h>
25 1.1 joerg #include <ctype.h>
26 1.1 joerg #include <errno.h>
27 1.1 joerg #include <limits.h>
28 1.1 joerg #include <stdarg.h>
29 1.1 joerg #include <stdlib.h>
30 1.1.1.10 joerg #include <string.h>
31 1.1.1.11 joerg #include <time.h>
32 1.1 joerg
33 1.1.1.12 joerg #include "man.h"
34 1.1.1.7 joerg #include "mandoc.h"
35 1.1 joerg #include "libman.h"
36 1.1 joerg #include "libmandoc.h"
37 1.1 joerg
38 1.1.1.15 joerg #define CHKARGS struct man *man, struct man_node *n
39 1.1 joerg
40 1.1 joerg typedef int (*v_check)(CHKARGS);
41 1.1 joerg
42 1.1 joerg struct man_valid {
43 1.1 joerg v_check *pres;
44 1.1 joerg v_check *posts;
45 1.1 joerg };
46 1.1 joerg
47 1.1 joerg static int check_eq0(CHKARGS);
48 1.1.1.14 joerg static int check_eq2(CHKARGS);
49 1.1 joerg static int check_le1(CHKARGS);
50 1.1 joerg static int check_ge2(CHKARGS);
51 1.1 joerg static int check_le5(CHKARGS);
52 1.1.1.15 joerg static int check_head1(CHKARGS);
53 1.1 joerg static int check_par(CHKARGS);
54 1.1 joerg static int check_part(CHKARGS);
55 1.1 joerg static int check_root(CHKARGS);
56 1.1.1.13 joerg static void check_text(CHKARGS);
57 1.1 joerg
58 1.1.1.11 joerg static int post_AT(CHKARGS);
59 1.1.1.15 joerg static int post_IP(CHKARGS);
60 1.1.1.13 joerg static int post_vs(CHKARGS);
61 1.1.1.11 joerg static int post_fi(CHKARGS);
62 1.1.1.13 joerg static int post_ft(CHKARGS);
63 1.1.1.11 joerg static int post_nf(CHKARGS);
64 1.1.1.13 joerg static int post_sec(CHKARGS);
65 1.1.1.11 joerg static int post_TH(CHKARGS);
66 1.1.1.11 joerg static int post_UC(CHKARGS);
67 1.1.1.13 joerg static int pre_sec(CHKARGS);
68 1.1.1.11 joerg
69 1.1.1.11 joerg static v_check posts_at[] = { post_AT, NULL };
70 1.1.1.13 joerg static v_check posts_br[] = { post_vs, check_eq0, NULL };
71 1.1 joerg static v_check posts_eq0[] = { check_eq0, NULL };
72 1.1.1.14 joerg static v_check posts_eq2[] = { check_eq2, NULL };
73 1.1.1.11 joerg static v_check posts_fi[] = { check_eq0, post_fi, NULL };
74 1.1.1.13 joerg static v_check posts_ft[] = { post_ft, NULL };
75 1.1.1.15 joerg static v_check posts_ip[] = { post_IP, NULL };
76 1.1.1.15 joerg static v_check posts_le1[] = { check_le1, NULL };
77 1.1.1.11 joerg static v_check posts_nf[] = { check_eq0, post_nf, NULL };
78 1.1 joerg static v_check posts_par[] = { check_par, NULL };
79 1.1 joerg static v_check posts_part[] = { check_part, NULL };
80 1.1.1.13 joerg static v_check posts_sec[] = { post_sec, NULL };
81 1.1.1.13 joerg static v_check posts_sp[] = { post_vs, check_le1, NULL };
82 1.1.1.12 joerg static v_check posts_th[] = { check_ge2, check_le5, post_TH, NULL };
83 1.1.1.11 joerg static v_check posts_uc[] = { post_UC, NULL };
84 1.1.1.15 joerg static v_check posts_ur[] = { check_head1, check_part, NULL };
85 1.1.1.14 joerg static v_check pres_sec[] = { pre_sec, NULL };
86 1.1.1.11 joerg
87 1.1 joerg static const struct man_valid man_valids[MAN_MAX] = {
88 1.1.1.13 joerg { NULL, posts_br }, /* br */
89 1.1.1.14 joerg { NULL, posts_th }, /* TH */
90 1.1.1.13 joerg { pres_sec, posts_sec }, /* SH */
91 1.1.1.13 joerg { pres_sec, posts_sec }, /* SS */
92 1.1.1.14 joerg { NULL, NULL }, /* TP */
93 1.1.1.14 joerg { NULL, posts_par }, /* LP */
94 1.1.1.14 joerg { NULL, posts_par }, /* PP */
95 1.1.1.14 joerg { NULL, posts_par }, /* P */
96 1.1.1.15 joerg { NULL, posts_ip }, /* IP */
97 1.1.1.14 joerg { NULL, NULL }, /* HP */
98 1.1 joerg { NULL, NULL }, /* SM */
99 1.1 joerg { NULL, NULL }, /* SB */
100 1.1 joerg { NULL, NULL }, /* BI */
101 1.1 joerg { NULL, NULL }, /* IB */
102 1.1 joerg { NULL, NULL }, /* BR */
103 1.1 joerg { NULL, NULL }, /* RB */
104 1.1 joerg { NULL, NULL }, /* R */
105 1.1 joerg { NULL, NULL }, /* B */
106 1.1 joerg { NULL, NULL }, /* I */
107 1.1 joerg { NULL, NULL }, /* IR */
108 1.1 joerg { NULL, NULL }, /* RI */
109 1.1.1.14 joerg { NULL, posts_eq0 }, /* na */
110 1.1.1.14 joerg { NULL, posts_sp }, /* sp */
111 1.1.1.14 joerg { NULL, posts_nf }, /* nf */
112 1.1.1.14 joerg { NULL, posts_fi }, /* fi */
113 1.1 joerg { NULL, NULL }, /* RE */
114 1.1 joerg { NULL, posts_part }, /* RS */
115 1.1 joerg { NULL, NULL }, /* DT */
116 1.1.1.11 joerg { NULL, posts_uc }, /* UC */
117 1.1.1.15 joerg { NULL, posts_le1 }, /* PD */
118 1.1.1.11 joerg { NULL, posts_at }, /* AT */
119 1.1.1.10 joerg { NULL, NULL }, /* in */
120 1.1.1.11 joerg { NULL, posts_ft }, /* ft */
121 1.1.1.14 joerg { NULL, posts_eq2 }, /* OP */
122 1.1.1.15 joerg { NULL, posts_nf }, /* EX */
123 1.1.1.15 joerg { NULL, posts_fi }, /* EE */
124 1.1.1.15 joerg { NULL, posts_ur }, /* UR */
125 1.1.1.15 joerg { NULL, NULL }, /* UE */
126 1.1 joerg };
127 1.1 joerg
128 1.1 joerg
129 1.1 joerg int
130 1.1.1.15 joerg man_valid_pre(struct man *man, struct man_node *n)
131 1.1 joerg {
132 1.1 joerg v_check *cp;
133 1.1 joerg
134 1.1.1.11 joerg switch (n->type) {
135 1.1.1.11 joerg case (MAN_TEXT):
136 1.1.1.11 joerg /* FALLTHROUGH */
137 1.1.1.11 joerg case (MAN_ROOT):
138 1.1.1.11 joerg /* FALLTHROUGH */
139 1.1.1.12 joerg case (MAN_EQN):
140 1.1.1.12 joerg /* FALLTHROUGH */
141 1.1.1.11 joerg case (MAN_TBL):
142 1.1 joerg return(1);
143 1.1.1.11 joerg default:
144 1.1.1.11 joerg break;
145 1.1.1.11 joerg }
146 1.1 joerg
147 1.1 joerg if (NULL == (cp = man_valids[n->tok].pres))
148 1.1 joerg return(1);
149 1.1 joerg for ( ; *cp; cp++)
150 1.1.1.15 joerg if ( ! (*cp)(man, n))
151 1.1 joerg return(0);
152 1.1 joerg return(1);
153 1.1 joerg }
154 1.1 joerg
155 1.1 joerg
156 1.1 joerg int
157 1.1.1.15 joerg man_valid_post(struct man *man)
158 1.1 joerg {
159 1.1 joerg v_check *cp;
160 1.1 joerg
161 1.1.1.15 joerg if (MAN_VALID & man->last->flags)
162 1.1 joerg return(1);
163 1.1.1.15 joerg man->last->flags |= MAN_VALID;
164 1.1 joerg
165 1.1.1.15 joerg switch (man->last->type) {
166 1.1 joerg case (MAN_TEXT):
167 1.1.1.15 joerg check_text(man, man->last);
168 1.1.1.13 joerg return(1);
169 1.1 joerg case (MAN_ROOT):
170 1.1.1.15 joerg return(check_root(man, man->last));
171 1.1.1.12 joerg case (MAN_EQN):
172 1.1.1.12 joerg /* FALLTHROUGH */
173 1.1.1.11 joerg case (MAN_TBL):
174 1.1.1.11 joerg return(1);
175 1.1 joerg default:
176 1.1 joerg break;
177 1.1 joerg }
178 1.1 joerg
179 1.1.1.15 joerg if (NULL == (cp = man_valids[man->last->tok].posts))
180 1.1 joerg return(1);
181 1.1 joerg for ( ; *cp; cp++)
182 1.1.1.15 joerg if ( ! (*cp)(man, man->last))
183 1.1 joerg return(0);
184 1.1 joerg
185 1.1 joerg return(1);
186 1.1 joerg }
187 1.1 joerg
188 1.1 joerg
189 1.1 joerg static int
190 1.1 joerg check_root(CHKARGS)
191 1.1 joerg {
192 1.1 joerg
193 1.1.1.15 joerg if (MAN_BLINE & man->flags)
194 1.1.1.15 joerg man_nmsg(man, n, MANDOCERR_SCOPEEXIT);
195 1.1.1.15 joerg else if (MAN_ELINE & man->flags)
196 1.1.1.15 joerg man_nmsg(man, n, MANDOCERR_SCOPEEXIT);
197 1.1 joerg
198 1.1.1.15 joerg man->flags &= ~MAN_BLINE;
199 1.1.1.15 joerg man->flags &= ~MAN_ELINE;
200 1.1 joerg
201 1.1.1.15 joerg if (NULL == man->first->child) {
202 1.1.1.15 joerg man_nmsg(man, n, MANDOCERR_NODOCBODY);
203 1.1.1.7 joerg return(0);
204 1.1.1.15 joerg } else if (NULL == man->meta.title) {
205 1.1.1.15 joerg man_nmsg(man, n, MANDOCERR_NOTITLE);
206 1.1.1.11 joerg
207 1.1.1.6 joerg /*
208 1.1.1.6 joerg * If a title hasn't been set, do so now (by
209 1.1.1.6 joerg * implication, date and section also aren't set).
210 1.1.1.6 joerg */
211 1.1.1.11 joerg
212 1.1.1.15 joerg man->meta.title = mandoc_strdup("unknown");
213 1.1.1.15 joerg man->meta.msec = mandoc_strdup("1");
214 1.1.1.15 joerg man->meta.date = mandoc_normdate
215 1.1.1.15 joerg (man->parse, NULL, n->line, n->pos);
216 1.1.1.6 joerg }
217 1.1 joerg
218 1.1 joerg return(1);
219 1.1 joerg }
220 1.1 joerg
221 1.1.1.13 joerg static void
222 1.1.1.13 joerg check_text(CHKARGS)
223 1.1 joerg {
224 1.1.1.13 joerg char *cp, *p;
225 1.1 joerg
226 1.1.1.15 joerg if (MAN_LITERAL & man->flags)
227 1.1.1.14 joerg return;
228 1.1.1.14 joerg
229 1.1.1.14 joerg cp = n->string;
230 1.1.1.14 joerg for (p = cp; NULL != (p = strchr(p, '\t')); p++)
231 1.1.1.15 joerg man_pmsg(man, n->line, (int)(p - cp), MANDOCERR_BADTAB);
232 1.1 joerg }
233 1.1 joerg
234 1.1 joerg #define INEQ_DEFINE(x, ineq, name) \
235 1.1 joerg static int \
236 1.1 joerg check_##name(CHKARGS) \
237 1.1 joerg { \
238 1.1 joerg if (n->nchild ineq (x)) \
239 1.1 joerg return(1); \
240 1.1.1.15 joerg mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line, n->pos, \
241 1.1.1.7 joerg "line arguments %s %d (have %d)", \
242 1.1.1.7 joerg #ineq, (x), n->nchild); \
243 1.1.1.12 joerg return(1); \
244 1.1 joerg }
245 1.1 joerg
246 1.1 joerg INEQ_DEFINE(0, ==, eq0)
247 1.1.1.14 joerg INEQ_DEFINE(2, ==, eq2)
248 1.1 joerg INEQ_DEFINE(1, <=, le1)
249 1.1 joerg INEQ_DEFINE(2, >=, ge2)
250 1.1 joerg INEQ_DEFINE(5, <=, le5)
251 1.1 joerg
252 1.1.1.11 joerg static int
253 1.1.1.15 joerg check_head1(CHKARGS)
254 1.1.1.15 joerg {
255 1.1.1.15 joerg
256 1.1.1.15 joerg if (MAN_HEAD == n->type && 1 != n->nchild)
257 1.1.1.15 joerg mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line,
258 1.1.1.15 joerg n->pos, "line arguments eq 1 (have %d)", n->nchild);
259 1.1.1.15 joerg
260 1.1.1.15 joerg return(1);
261 1.1.1.15 joerg }
262 1.1.1.15 joerg
263 1.1.1.15 joerg static int
264 1.1.1.13 joerg post_ft(CHKARGS)
265 1.1.1.11 joerg {
266 1.1.1.11 joerg char *cp;
267 1.1.1.11 joerg int ok;
268 1.1.1.11 joerg
269 1.1.1.11 joerg if (0 == n->nchild)
270 1.1.1.11 joerg return(1);
271 1.1.1.11 joerg
272 1.1.1.11 joerg ok = 0;
273 1.1.1.11 joerg cp = n->child->string;
274 1.1.1.11 joerg switch (*cp) {
275 1.1.1.11 joerg case ('1'):
276 1.1.1.11 joerg /* FALLTHROUGH */
277 1.1.1.11 joerg case ('2'):
278 1.1.1.11 joerg /* FALLTHROUGH */
279 1.1.1.11 joerg case ('3'):
280 1.1.1.11 joerg /* FALLTHROUGH */
281 1.1.1.11 joerg case ('4'):
282 1.1.1.11 joerg /* FALLTHROUGH */
283 1.1.1.11 joerg case ('I'):
284 1.1.1.11 joerg /* FALLTHROUGH */
285 1.1.1.11 joerg case ('P'):
286 1.1.1.11 joerg /* FALLTHROUGH */
287 1.1.1.11 joerg case ('R'):
288 1.1.1.11 joerg if ('\0' == cp[1])
289 1.1.1.11 joerg ok = 1;
290 1.1.1.11 joerg break;
291 1.1.1.11 joerg case ('B'):
292 1.1.1.11 joerg if ('\0' == cp[1] || ('I' == cp[1] && '\0' == cp[2]))
293 1.1.1.11 joerg ok = 1;
294 1.1.1.11 joerg break;
295 1.1.1.11 joerg case ('C'):
296 1.1.1.11 joerg if ('W' == cp[1] && '\0' == cp[2])
297 1.1.1.11 joerg ok = 1;
298 1.1.1.11 joerg break;
299 1.1.1.11 joerg default:
300 1.1.1.11 joerg break;
301 1.1.1.11 joerg }
302 1.1.1.11 joerg
303 1.1.1.11 joerg if (0 == ok) {
304 1.1.1.12 joerg mandoc_vmsg
305 1.1.1.15 joerg (MANDOCERR_BADFONT, man->parse,
306 1.1.1.12 joerg n->line, n->pos, "%s", cp);
307 1.1.1.11 joerg *cp = '\0';
308 1.1.1.11 joerg }
309 1.1.1.11 joerg
310 1.1.1.11 joerg if (1 < n->nchild)
311 1.1.1.12 joerg mandoc_vmsg
312 1.1.1.15 joerg (MANDOCERR_ARGCOUNT, man->parse, n->line,
313 1.1.1.12 joerg n->pos, "want one child (have %d)",
314 1.1.1.12 joerg n->nchild);
315 1.1.1.11 joerg
316 1.1.1.11 joerg return(1);
317 1.1.1.11 joerg }
318 1.1 joerg
319 1.1 joerg static int
320 1.1.1.13 joerg pre_sec(CHKARGS)
321 1.1 joerg {
322 1.1 joerg
323 1.1.1.13 joerg if (MAN_BLOCK == n->type)
324 1.1.1.15 joerg man->flags &= ~MAN_LITERAL;
325 1.1 joerg return(1);
326 1.1 joerg }
327 1.1 joerg
328 1.1.1.13 joerg static int
329 1.1.1.13 joerg post_sec(CHKARGS)
330 1.1.1.13 joerg {
331 1.1.1.13 joerg
332 1.1.1.13 joerg if ( ! (MAN_HEAD == n->type && 0 == n->nchild))
333 1.1.1.13 joerg return(1);
334 1.1.1.13 joerg
335 1.1.1.15 joerg man_nmsg(man, n, MANDOCERR_SYNTARGCOUNT);
336 1.1.1.13 joerg return(0);
337 1.1.1.13 joerg }
338 1.1 joerg
339 1.1 joerg static int
340 1.1 joerg check_part(CHKARGS)
341 1.1 joerg {
342 1.1 joerg
343 1.1 joerg if (MAN_BODY == n->type && 0 == n->nchild)
344 1.1.1.15 joerg mandoc_msg(MANDOCERR_ARGCWARN, man->parse, n->line,
345 1.1.1.12 joerg n->pos, "want children (have none)");
346 1.1.1.11 joerg
347 1.1 joerg return(1);
348 1.1 joerg }
349 1.1 joerg
350 1.1 joerg
351 1.1 joerg static int
352 1.1 joerg check_par(CHKARGS)
353 1.1 joerg {
354 1.1 joerg
355 1.1.1.12 joerg switch (n->type) {
356 1.1.1.12 joerg case (MAN_BLOCK):
357 1.1.1.12 joerg if (0 == n->body->nchild)
358 1.1.1.15 joerg man_node_delete(man, n);
359 1.1.1.12 joerg break;
360 1.1.1.12 joerg case (MAN_BODY):
361 1.1.1.12 joerg if (0 == n->nchild)
362 1.1.1.15 joerg man_nmsg(man, n, MANDOCERR_IGNPAR);
363 1.1.1.12 joerg break;
364 1.1.1.12 joerg case (MAN_HEAD):
365 1.1.1.12 joerg if (n->nchild)
366 1.1.1.15 joerg man_nmsg(man, n, MANDOCERR_ARGSLOST);
367 1.1.1.12 joerg break;
368 1.1.1.12 joerg default:
369 1.1.1.12 joerg break;
370 1.1.1.12 joerg }
371 1.1 joerg
372 1.1 joerg return(1);
373 1.1 joerg }
374 1.1 joerg
375 1.1.1.15 joerg static int
376 1.1.1.15 joerg post_IP(CHKARGS)
377 1.1.1.15 joerg {
378 1.1.1.15 joerg
379 1.1.1.15 joerg switch (n->type) {
380 1.1.1.15 joerg case (MAN_BLOCK):
381 1.1.1.15 joerg if (0 == n->head->nchild && 0 == n->body->nchild)
382 1.1.1.15 joerg man_node_delete(man, n);
383 1.1.1.15 joerg break;
384 1.1.1.15 joerg case (MAN_BODY):
385 1.1.1.15 joerg if (0 == n->parent->head->nchild && 0 == n->nchild)
386 1.1.1.15 joerg man_nmsg(man, n, MANDOCERR_IGNPAR);
387 1.1.1.15 joerg break;
388 1.1.1.15 joerg default:
389 1.1.1.15 joerg break;
390 1.1.1.15 joerg }
391 1.1.1.15 joerg return(1);
392 1.1.1.15 joerg }
393 1.1 joerg
394 1.1 joerg static int
395 1.1.1.11 joerg post_TH(CHKARGS)
396 1.1.1.11 joerg {
397 1.1.1.12 joerg const char *p;
398 1.1.1.11 joerg
399 1.1.1.15 joerg free(man->meta.title);
400 1.1.1.15 joerg free(man->meta.vol);
401 1.1.1.15 joerg free(man->meta.source);
402 1.1.1.15 joerg free(man->meta.msec);
403 1.1.1.15 joerg free(man->meta.date);
404 1.1.1.15 joerg
405 1.1.1.15 joerg man->meta.title = man->meta.vol = man->meta.date =
406 1.1.1.15 joerg man->meta.msec = man->meta.source = NULL;
407 1.1.1.11 joerg
408 1.1.1.11 joerg /* ->TITLE<- MSEC DATE SOURCE VOL */
409 1.1.1.11 joerg
410 1.1.1.11 joerg n = n->child;
411 1.1.1.12 joerg if (n && n->string) {
412 1.1.1.12 joerg for (p = n->string; '\0' != *p; p++) {
413 1.1.1.12 joerg /* Only warn about this once... */
414 1.1.1.13 joerg if (isalpha((unsigned char)*p) &&
415 1.1.1.13 joerg ! isupper((unsigned char)*p)) {
416 1.1.1.15 joerg man_nmsg(man, n, MANDOCERR_UPPERCASE);
417 1.1.1.12 joerg break;
418 1.1.1.12 joerg }
419 1.1.1.12 joerg }
420 1.1.1.15 joerg man->meta.title = mandoc_strdup(n->string);
421 1.1.1.12 joerg } else
422 1.1.1.15 joerg man->meta.title = mandoc_strdup("");
423 1.1.1.11 joerg
424 1.1.1.11 joerg /* TITLE ->MSEC<- DATE SOURCE VOL */
425 1.1.1.11 joerg
426 1.1.1.12 joerg if (n)
427 1.1.1.12 joerg n = n->next;
428 1.1.1.12 joerg if (n && n->string)
429 1.1.1.15 joerg man->meta.msec = mandoc_strdup(n->string);
430 1.1.1.12 joerg else
431 1.1.1.15 joerg man->meta.msec = mandoc_strdup("");
432 1.1.1.11 joerg
433 1.1.1.11 joerg /* TITLE MSEC ->DATE<- SOURCE VOL */
434 1.1.1.11 joerg
435 1.1.1.12 joerg if (n)
436 1.1.1.12 joerg n = n->next;
437 1.1.1.14 joerg if (n && n->string && '\0' != n->string[0]) {
438 1.1.1.15 joerg man->meta.date = mandoc_normdate
439 1.1.1.15 joerg (man->parse, n->string, n->line, n->pos);
440 1.1.1.14 joerg } else
441 1.1.1.15 joerg man->meta.date = mandoc_strdup("");
442 1.1.1.11 joerg
443 1.1.1.11 joerg /* TITLE MSEC DATE ->SOURCE<- VOL */
444 1.1.1.11 joerg
445 1.1.1.11 joerg if (n && (n = n->next))
446 1.1.1.15 joerg man->meta.source = mandoc_strdup(n->string);
447 1.1.1.11 joerg
448 1.1.1.11 joerg /* TITLE MSEC DATE SOURCE ->VOL<- */
449 1.1.1.14 joerg /* If missing, use the default VOL name for MSEC. */
450 1.1.1.11 joerg
451 1.1.1.11 joerg if (n && (n = n->next))
452 1.1.1.15 joerg man->meta.vol = mandoc_strdup(n->string);
453 1.1.1.15 joerg else if ('\0' != man->meta.msec[0] &&
454 1.1.1.15 joerg (NULL != (p = mandoc_a2msec(man->meta.msec))))
455 1.1.1.15 joerg man->meta.vol = mandoc_strdup(p);
456 1.1.1.11 joerg
457 1.1.1.11 joerg /*
458 1.1.1.11 joerg * Remove the `TH' node after we've processed it for our
459 1.1.1.11 joerg * meta-data.
460 1.1.1.11 joerg */
461 1.1.1.15 joerg man_node_delete(man, man->last);
462 1.1.1.11 joerg return(1);
463 1.1.1.11 joerg }
464 1.1.1.11 joerg
465 1.1.1.11 joerg static int
466 1.1.1.11 joerg post_nf(CHKARGS)
467 1.1.1.11 joerg {
468 1.1.1.11 joerg
469 1.1.1.15 joerg if (MAN_LITERAL & man->flags)
470 1.1.1.15 joerg man_nmsg(man, n, MANDOCERR_SCOPEREP);
471 1.1.1.11 joerg
472 1.1.1.15 joerg man->flags |= MAN_LITERAL;
473 1.1.1.11 joerg return(1);
474 1.1.1.11 joerg }
475 1.1.1.11 joerg
476 1.1.1.11 joerg static int
477 1.1.1.11 joerg post_fi(CHKARGS)
478 1.1.1.11 joerg {
479 1.1.1.11 joerg
480 1.1.1.15 joerg if ( ! (MAN_LITERAL & man->flags))
481 1.1.1.15 joerg man_nmsg(man, n, MANDOCERR_WNOSCOPE);
482 1.1.1.11 joerg
483 1.1.1.15 joerg man->flags &= ~MAN_LITERAL;
484 1.1.1.11 joerg return(1);
485 1.1.1.11 joerg }
486 1.1.1.11 joerg
487 1.1.1.11 joerg static int
488 1.1.1.11 joerg post_UC(CHKARGS)
489 1.1.1.11 joerg {
490 1.1.1.11 joerg static const char * const bsd_versions[] = {
491 1.1.1.11 joerg "3rd Berkeley Distribution",
492 1.1.1.11 joerg "4th Berkeley Distribution",
493 1.1.1.11 joerg "4.2 Berkeley Distribution",
494 1.1.1.11 joerg "4.3 Berkeley Distribution",
495 1.1.1.11 joerg "4.4 Berkeley Distribution",
496 1.1.1.11 joerg };
497 1.1.1.11 joerg
498 1.1.1.11 joerg const char *p, *s;
499 1.1.1.11 joerg
500 1.1.1.11 joerg n = n->child;
501 1.1.1.11 joerg
502 1.1.1.11 joerg if (NULL == n || MAN_TEXT != n->type)
503 1.1.1.11 joerg p = bsd_versions[0];
504 1.1.1.11 joerg else {
505 1.1.1.11 joerg s = n->string;
506 1.1.1.11 joerg if (0 == strcmp(s, "3"))
507 1.1.1.11 joerg p = bsd_versions[0];
508 1.1.1.11 joerg else if (0 == strcmp(s, "4"))
509 1.1.1.11 joerg p = bsd_versions[1];
510 1.1.1.11 joerg else if (0 == strcmp(s, "5"))
511 1.1.1.11 joerg p = bsd_versions[2];
512 1.1.1.11 joerg else if (0 == strcmp(s, "6"))
513 1.1.1.11 joerg p = bsd_versions[3];
514 1.1.1.11 joerg else if (0 == strcmp(s, "7"))
515 1.1.1.11 joerg p = bsd_versions[4];
516 1.1.1.11 joerg else
517 1.1.1.11 joerg p = bsd_versions[0];
518 1.1.1.11 joerg }
519 1.1.1.11 joerg
520 1.1.1.15 joerg free(man->meta.source);
521 1.1.1.15 joerg man->meta.source = mandoc_strdup(p);
522 1.1.1.11 joerg return(1);
523 1.1.1.11 joerg }
524 1.1.1.11 joerg
525 1.1.1.11 joerg static int
526 1.1.1.11 joerg post_AT(CHKARGS)
527 1.1.1.11 joerg {
528 1.1.1.11 joerg static const char * const unix_versions[] = {
529 1.1.1.11 joerg "7th Edition",
530 1.1.1.11 joerg "System III",
531 1.1.1.11 joerg "System V",
532 1.1.1.11 joerg "System V Release 2",
533 1.1.1.11 joerg };
534 1.1.1.11 joerg
535 1.1.1.11 joerg const char *p, *s;
536 1.1.1.11 joerg struct man_node *nn;
537 1.1.1.11 joerg
538 1.1.1.11 joerg n = n->child;
539 1.1.1.11 joerg
540 1.1.1.11 joerg if (NULL == n || MAN_TEXT != n->type)
541 1.1.1.11 joerg p = unix_versions[0];
542 1.1.1.11 joerg else {
543 1.1.1.11 joerg s = n->string;
544 1.1.1.11 joerg if (0 == strcmp(s, "3"))
545 1.1.1.11 joerg p = unix_versions[0];
546 1.1.1.11 joerg else if (0 == strcmp(s, "4"))
547 1.1.1.11 joerg p = unix_versions[1];
548 1.1.1.11 joerg else if (0 == strcmp(s, "5")) {
549 1.1.1.11 joerg nn = n->next;
550 1.1.1.11 joerg if (nn && MAN_TEXT == nn->type && nn->string[0])
551 1.1.1.11 joerg p = unix_versions[3];
552 1.1.1.11 joerg else
553 1.1.1.11 joerg p = unix_versions[2];
554 1.1.1.11 joerg } else
555 1.1.1.11 joerg p = unix_versions[0];
556 1.1.1.11 joerg }
557 1.1.1.11 joerg
558 1.1.1.15 joerg free(man->meta.source);
559 1.1.1.15 joerg man->meta.source = mandoc_strdup(p);
560 1.1.1.11 joerg return(1);
561 1.1.1.11 joerg }
562 1.1.1.13 joerg
563 1.1.1.13 joerg static int
564 1.1.1.13 joerg post_vs(CHKARGS)
565 1.1.1.13 joerg {
566 1.1.1.13 joerg
567 1.1.1.15 joerg if (NULL != n->prev)
568 1.1.1.15 joerg return(1);
569 1.1.1.15 joerg
570 1.1.1.15 joerg switch (n->parent->tok) {
571 1.1.1.15 joerg case (MAN_SH):
572 1.1.1.15 joerg /* FALLTHROUGH */
573 1.1.1.15 joerg case (MAN_SS):
574 1.1.1.15 joerg man_nmsg(man, n, MANDOCERR_IGNPAR);
575 1.1.1.15 joerg /* FALLTHROUGH */
576 1.1.1.15 joerg case (MAN_MAX):
577 1.1.1.15 joerg /*
578 1.1.1.15 joerg * Don't warn about this because it occurs in pod2man
579 1.1.1.15 joerg * and would cause considerable (unfixable) warnage.
580 1.1.1.15 joerg */
581 1.1.1.15 joerg man_node_delete(man, n);
582 1.1.1.15 joerg break;
583 1.1.1.15 joerg default:
584 1.1.1.15 joerg break;
585 1.1.1.15 joerg }
586 1.1.1.13 joerg
587 1.1.1.13 joerg return(1);
588 1.1.1.13 joerg }
589