man_validate.c revision 1.1.1.16 1 1.1.1.16 christos /* $OpenBSD$ */
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.16 christos * Copyright (c) 2010, 2012-2015 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 #include "config.h"
19 1.1.1.4 joerg
20 1.1 joerg #include <sys/types.h>
21 1.1 joerg
22 1.1 joerg #include <assert.h>
23 1.1 joerg #include <ctype.h>
24 1.1 joerg #include <errno.h>
25 1.1 joerg #include <limits.h>
26 1.1 joerg #include <stdarg.h>
27 1.1 joerg #include <stdlib.h>
28 1.1.1.10 joerg #include <string.h>
29 1.1.1.11 joerg #include <time.h>
30 1.1 joerg
31 1.1.1.12 joerg #include "man.h"
32 1.1.1.7 joerg #include "mandoc.h"
33 1.1.1.16 christos #include "mandoc_aux.h"
34 1.1 joerg #include "libman.h"
35 1.1 joerg #include "libmandoc.h"
36 1.1 joerg
37 1.1.1.15 joerg #define CHKARGS struct man *man, struct man_node *n
38 1.1 joerg
39 1.1.1.16 christos typedef void (*v_check)(CHKARGS);
40 1.1 joerg
41 1.1.1.16 christos static void check_par(CHKARGS);
42 1.1.1.16 christos static void check_part(CHKARGS);
43 1.1.1.16 christos static void check_root(CHKARGS);
44 1.1.1.13 joerg static void check_text(CHKARGS);
45 1.1 joerg
46 1.1.1.16 christos static void post_AT(CHKARGS);
47 1.1.1.16 christos static void post_IP(CHKARGS);
48 1.1.1.16 christos static void post_vs(CHKARGS);
49 1.1.1.16 christos static void post_fi(CHKARGS);
50 1.1.1.16 christos static void post_ft(CHKARGS);
51 1.1.1.16 christos static void post_nf(CHKARGS);
52 1.1.1.16 christos static void post_OP(CHKARGS);
53 1.1.1.16 christos static void post_TH(CHKARGS);
54 1.1.1.16 christos static void post_UC(CHKARGS);
55 1.1.1.16 christos static void post_UR(CHKARGS);
56 1.1.1.16 christos
57 1.1.1.16 christos static v_check man_valids[MAN_MAX] = {
58 1.1.1.16 christos post_vs, /* br */
59 1.1.1.16 christos post_TH, /* TH */
60 1.1.1.16 christos NULL, /* SH */
61 1.1.1.16 christos NULL, /* SS */
62 1.1.1.16 christos NULL, /* TP */
63 1.1.1.16 christos check_par, /* LP */
64 1.1.1.16 christos check_par, /* PP */
65 1.1.1.16 christos check_par, /* P */
66 1.1.1.16 christos post_IP, /* IP */
67 1.1.1.16 christos NULL, /* HP */
68 1.1.1.16 christos NULL, /* SM */
69 1.1.1.16 christos NULL, /* SB */
70 1.1.1.16 christos NULL, /* BI */
71 1.1.1.16 christos NULL, /* IB */
72 1.1.1.16 christos NULL, /* BR */
73 1.1.1.16 christos NULL, /* RB */
74 1.1.1.16 christos NULL, /* R */
75 1.1.1.16 christos NULL, /* B */
76 1.1.1.16 christos NULL, /* I */
77 1.1.1.16 christos NULL, /* IR */
78 1.1.1.16 christos NULL, /* RI */
79 1.1.1.16 christos post_vs, /* sp */
80 1.1.1.16 christos post_nf, /* nf */
81 1.1.1.16 christos post_fi, /* fi */
82 1.1.1.16 christos NULL, /* RE */
83 1.1.1.16 christos check_part, /* RS */
84 1.1.1.16 christos NULL, /* DT */
85 1.1.1.16 christos post_UC, /* UC */
86 1.1.1.16 christos NULL, /* PD */
87 1.1.1.16 christos post_AT, /* AT */
88 1.1.1.16 christos NULL, /* in */
89 1.1.1.16 christos post_ft, /* ft */
90 1.1.1.16 christos post_OP, /* OP */
91 1.1.1.16 christos post_nf, /* EX */
92 1.1.1.16 christos post_fi, /* EE */
93 1.1.1.16 christos post_UR, /* UR */
94 1.1.1.16 christos NULL, /* UE */
95 1.1.1.16 christos NULL, /* ll */
96 1.1 joerg };
97 1.1 joerg
98 1.1 joerg
99 1.1.1.16 christos void
100 1.1.1.16 christos man_valid_post(struct man *man)
101 1.1 joerg {
102 1.1.1.16 christos struct man_node *n;
103 1.1 joerg v_check *cp;
104 1.1 joerg
105 1.1.1.16 christos n = man->last;
106 1.1.1.16 christos if (n->flags & MAN_VALID)
107 1.1.1.16 christos return;
108 1.1.1.16 christos n->flags |= MAN_VALID;
109 1.1.1.16 christos
110 1.1.1.11 joerg switch (n->type) {
111 1.1.1.16 christos case MAN_TEXT:
112 1.1.1.16 christos check_text(man, n);
113 1.1.1.11 joerg break;
114 1.1.1.16 christos case MAN_ROOT:
115 1.1.1.16 christos check_root(man, n);
116 1.1.1.16 christos break;
117 1.1.1.16 christos case MAN_EQN:
118 1.1.1.12 joerg /* FALLTHROUGH */
119 1.1.1.16 christos case MAN_TBL:
120 1.1.1.16 christos break;
121 1.1 joerg default:
122 1.1.1.16 christos cp = man_valids + n->tok;
123 1.1.1.16 christos if (*cp)
124 1.1.1.16 christos (*cp)(man, n);
125 1.1 joerg break;
126 1.1 joerg }
127 1.1 joerg }
128 1.1 joerg
129 1.1.1.16 christos static void
130 1.1.1.16 christos check_root(CHKARGS)
131 1.1 joerg {
132 1.1 joerg
133 1.1.1.16 christos assert((man->flags & (MAN_BLINE | MAN_ELINE)) == 0);
134 1.1 joerg
135 1.1.1.16 christos if (NULL == man->first->child)
136 1.1.1.16 christos mandoc_msg(MANDOCERR_DOC_EMPTY, man->parse,
137 1.1.1.16 christos n->line, n->pos, NULL);
138 1.1.1.16 christos else
139 1.1.1.16 christos man->meta.hasbody = 1;
140 1.1 joerg
141 1.1.1.16 christos if (NULL == man->meta.title) {
142 1.1.1.16 christos mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse,
143 1.1.1.16 christos n->line, n->pos, NULL);
144 1.1.1.11 joerg
145 1.1.1.6 joerg /*
146 1.1.1.6 joerg * If a title hasn't been set, do so now (by
147 1.1.1.6 joerg * implication, date and section also aren't set).
148 1.1.1.6 joerg */
149 1.1.1.11 joerg
150 1.1.1.16 christos man->meta.title = mandoc_strdup("");
151 1.1.1.16 christos man->meta.msec = mandoc_strdup("");
152 1.1.1.16 christos man->meta.date = man->quick ? mandoc_strdup("") :
153 1.1.1.16 christos mandoc_normdate(man->parse, NULL, n->line, n->pos);
154 1.1.1.6 joerg }
155 1.1 joerg }
156 1.1 joerg
157 1.1.1.13 joerg static void
158 1.1.1.13 joerg check_text(CHKARGS)
159 1.1 joerg {
160 1.1.1.13 joerg char *cp, *p;
161 1.1 joerg
162 1.1.1.15 joerg if (MAN_LITERAL & man->flags)
163 1.1.1.14 joerg return;
164 1.1.1.14 joerg
165 1.1.1.14 joerg cp = n->string;
166 1.1.1.14 joerg for (p = cp; NULL != (p = strchr(p, '\t')); p++)
167 1.1.1.16 christos mandoc_msg(MANDOCERR_FI_TAB, man->parse,
168 1.1.1.16 christos n->line, n->pos + (p - cp), NULL);
169 1.1 joerg }
170 1.1 joerg
171 1.1.1.16 christos static void
172 1.1.1.16 christos post_OP(CHKARGS)
173 1.1.1.16 christos {
174 1.1 joerg
175 1.1.1.16 christos if (n->nchild == 0)
176 1.1.1.16 christos mandoc_msg(MANDOCERR_OP_EMPTY, man->parse,
177 1.1.1.16 christos n->line, n->pos, "OP");
178 1.1.1.16 christos else if (n->nchild > 2) {
179 1.1.1.16 christos n = n->child->next->next;
180 1.1.1.16 christos mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
181 1.1.1.16 christos n->line, n->pos, "OP ... %s", n->string);
182 1.1.1.16 christos }
183 1.1.1.16 christos }
184 1.1 joerg
185 1.1.1.16 christos static void
186 1.1.1.16 christos post_UR(CHKARGS)
187 1.1.1.15 joerg {
188 1.1.1.15 joerg
189 1.1.1.16 christos if (n->type == MAN_HEAD && n->child == NULL)
190 1.1.1.16 christos mandoc_vmsg(MANDOCERR_UR_NOHEAD, man->parse,
191 1.1.1.16 christos n->line, n->pos, "UR");
192 1.1.1.16 christos check_part(man, n);
193 1.1.1.15 joerg }
194 1.1.1.15 joerg
195 1.1.1.16 christos static void
196 1.1.1.13 joerg post_ft(CHKARGS)
197 1.1.1.11 joerg {
198 1.1.1.11 joerg char *cp;
199 1.1.1.11 joerg int ok;
200 1.1.1.11 joerg
201 1.1.1.11 joerg if (0 == n->nchild)
202 1.1.1.16 christos return;
203 1.1.1.11 joerg
204 1.1.1.11 joerg ok = 0;
205 1.1.1.11 joerg cp = n->child->string;
206 1.1.1.11 joerg switch (*cp) {
207 1.1.1.16 christos case '1':
208 1.1.1.11 joerg /* FALLTHROUGH */
209 1.1.1.16 christos case '2':
210 1.1.1.11 joerg /* FALLTHROUGH */
211 1.1.1.16 christos case '3':
212 1.1.1.11 joerg /* FALLTHROUGH */
213 1.1.1.16 christos case '4':
214 1.1.1.11 joerg /* FALLTHROUGH */
215 1.1.1.16 christos case 'I':
216 1.1.1.11 joerg /* FALLTHROUGH */
217 1.1.1.16 christos case 'P':
218 1.1.1.11 joerg /* FALLTHROUGH */
219 1.1.1.16 christos case 'R':
220 1.1.1.11 joerg if ('\0' == cp[1])
221 1.1.1.11 joerg ok = 1;
222 1.1.1.11 joerg break;
223 1.1.1.16 christos case 'B':
224 1.1.1.11 joerg if ('\0' == cp[1] || ('I' == cp[1] && '\0' == cp[2]))
225 1.1.1.11 joerg ok = 1;
226 1.1.1.11 joerg break;
227 1.1.1.16 christos case 'C':
228 1.1.1.11 joerg if ('W' == cp[1] && '\0' == cp[2])
229 1.1.1.11 joerg ok = 1;
230 1.1.1.11 joerg break;
231 1.1.1.11 joerg default:
232 1.1.1.11 joerg break;
233 1.1.1.11 joerg }
234 1.1.1.11 joerg
235 1.1.1.11 joerg if (0 == ok) {
236 1.1.1.16 christos mandoc_vmsg(MANDOCERR_FT_BAD, man->parse,
237 1.1.1.16 christos n->line, n->pos, "ft %s", cp);
238 1.1.1.11 joerg *cp = '\0';
239 1.1.1.11 joerg }
240 1.1.1.13 joerg }
241 1.1 joerg
242 1.1.1.16 christos static void
243 1.1 joerg check_part(CHKARGS)
244 1.1 joerg {
245 1.1 joerg
246 1.1.1.16 christos if (n->type == MAN_BODY && n->child == NULL)
247 1.1.1.16 christos mandoc_msg(MANDOCERR_BLK_EMPTY, man->parse,
248 1.1.1.16 christos n->line, n->pos, man_macronames[n->tok]);
249 1.1 joerg }
250 1.1 joerg
251 1.1.1.16 christos static void
252 1.1 joerg check_par(CHKARGS)
253 1.1 joerg {
254 1.1 joerg
255 1.1.1.12 joerg switch (n->type) {
256 1.1.1.16 christos case MAN_BLOCK:
257 1.1.1.12 joerg if (0 == n->body->nchild)
258 1.1.1.15 joerg man_node_delete(man, n);
259 1.1.1.12 joerg break;
260 1.1.1.16 christos case MAN_BODY:
261 1.1.1.12 joerg if (0 == n->nchild)
262 1.1.1.16 christos mandoc_vmsg(MANDOCERR_PAR_SKIP,
263 1.1.1.16 christos man->parse, n->line, n->pos,
264 1.1.1.16 christos "%s empty", man_macronames[n->tok]);
265 1.1.1.12 joerg break;
266 1.1.1.16 christos case MAN_HEAD:
267 1.1.1.12 joerg if (n->nchild)
268 1.1.1.16 christos mandoc_vmsg(MANDOCERR_ARG_SKIP,
269 1.1.1.16 christos man->parse, n->line, n->pos,
270 1.1.1.16 christos "%s %s%s", man_macronames[n->tok],
271 1.1.1.16 christos n->child->string,
272 1.1.1.16 christos n->nchild > 1 ? " ..." : "");
273 1.1.1.12 joerg break;
274 1.1.1.12 joerg default:
275 1.1.1.12 joerg break;
276 1.1.1.12 joerg }
277 1.1 joerg }
278 1.1 joerg
279 1.1.1.16 christos static void
280 1.1.1.15 joerg post_IP(CHKARGS)
281 1.1.1.15 joerg {
282 1.1.1.15 joerg
283 1.1.1.15 joerg switch (n->type) {
284 1.1.1.16 christos case MAN_BLOCK:
285 1.1.1.15 joerg if (0 == n->head->nchild && 0 == n->body->nchild)
286 1.1.1.15 joerg man_node_delete(man, n);
287 1.1.1.15 joerg break;
288 1.1.1.16 christos case MAN_BODY:
289 1.1.1.15 joerg if (0 == n->parent->head->nchild && 0 == n->nchild)
290 1.1.1.16 christos mandoc_vmsg(MANDOCERR_PAR_SKIP,
291 1.1.1.16 christos man->parse, n->line, n->pos,
292 1.1.1.16 christos "%s empty", man_macronames[n->tok]);
293 1.1.1.15 joerg break;
294 1.1.1.15 joerg default:
295 1.1.1.15 joerg break;
296 1.1.1.15 joerg }
297 1.1.1.15 joerg }
298 1.1 joerg
299 1.1.1.16 christos static void
300 1.1.1.11 joerg post_TH(CHKARGS)
301 1.1.1.11 joerg {
302 1.1.1.16 christos struct man_node *nb;
303 1.1.1.12 joerg const char *p;
304 1.1.1.11 joerg
305 1.1.1.15 joerg free(man->meta.title);
306 1.1.1.15 joerg free(man->meta.vol);
307 1.1.1.15 joerg free(man->meta.source);
308 1.1.1.15 joerg free(man->meta.msec);
309 1.1.1.15 joerg free(man->meta.date);
310 1.1.1.15 joerg
311 1.1.1.15 joerg man->meta.title = man->meta.vol = man->meta.date =
312 1.1.1.16 christos man->meta.msec = man->meta.source = NULL;
313 1.1.1.16 christos
314 1.1.1.16 christos nb = n;
315 1.1.1.11 joerg
316 1.1.1.11 joerg /* ->TITLE<- MSEC DATE SOURCE VOL */
317 1.1.1.11 joerg
318 1.1.1.11 joerg n = n->child;
319 1.1.1.12 joerg if (n && n->string) {
320 1.1.1.12 joerg for (p = n->string; '\0' != *p; p++) {
321 1.1.1.12 joerg /* Only warn about this once... */
322 1.1.1.16 christos if (isalpha((unsigned char)*p) &&
323 1.1.1.16 christos ! isupper((unsigned char)*p)) {
324 1.1.1.16 christos mandoc_vmsg(MANDOCERR_TITLE_CASE,
325 1.1.1.16 christos man->parse, n->line,
326 1.1.1.16 christos n->pos + (p - n->string),
327 1.1.1.16 christos "TH %s", n->string);
328 1.1.1.12 joerg break;
329 1.1.1.12 joerg }
330 1.1.1.12 joerg }
331 1.1.1.15 joerg man->meta.title = mandoc_strdup(n->string);
332 1.1.1.16 christos } else {
333 1.1.1.15 joerg man->meta.title = mandoc_strdup("");
334 1.1.1.16 christos mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse,
335 1.1.1.16 christos nb->line, nb->pos, "TH");
336 1.1.1.16 christos }
337 1.1.1.11 joerg
338 1.1.1.11 joerg /* TITLE ->MSEC<- DATE SOURCE VOL */
339 1.1.1.11 joerg
340 1.1.1.12 joerg if (n)
341 1.1.1.12 joerg n = n->next;
342 1.1.1.12 joerg if (n && n->string)
343 1.1.1.15 joerg man->meta.msec = mandoc_strdup(n->string);
344 1.1.1.16 christos else {
345 1.1.1.15 joerg man->meta.msec = mandoc_strdup("");
346 1.1.1.16 christos mandoc_vmsg(MANDOCERR_MSEC_MISSING, man->parse,
347 1.1.1.16 christos nb->line, nb->pos, "TH %s", man->meta.title);
348 1.1.1.16 christos }
349 1.1.1.11 joerg
350 1.1.1.11 joerg /* TITLE MSEC ->DATE<- SOURCE VOL */
351 1.1.1.11 joerg
352 1.1.1.12 joerg if (n)
353 1.1.1.12 joerg n = n->next;
354 1.1.1.14 joerg if (n && n->string && '\0' != n->string[0]) {
355 1.1.1.16 christos man->meta.date = man->quick ?
356 1.1.1.16 christos mandoc_strdup(n->string) :
357 1.1.1.16 christos mandoc_normdate(man->parse, n->string,
358 1.1.1.16 christos n->line, n->pos);
359 1.1.1.16 christos } else {
360 1.1.1.15 joerg man->meta.date = mandoc_strdup("");
361 1.1.1.16 christos mandoc_msg(MANDOCERR_DATE_MISSING, man->parse,
362 1.1.1.16 christos n ? n->line : nb->line,
363 1.1.1.16 christos n ? n->pos : nb->pos, "TH");
364 1.1.1.16 christos }
365 1.1.1.11 joerg
366 1.1.1.11 joerg /* TITLE MSEC DATE ->SOURCE<- VOL */
367 1.1.1.11 joerg
368 1.1.1.11 joerg if (n && (n = n->next))
369 1.1.1.15 joerg man->meta.source = mandoc_strdup(n->string);
370 1.1.1.16 christos else if (man->defos != NULL)
371 1.1.1.16 christos man->meta.source = mandoc_strdup(man->defos);
372 1.1.1.11 joerg
373 1.1.1.11 joerg /* TITLE MSEC DATE SOURCE ->VOL<- */
374 1.1.1.14 joerg /* If missing, use the default VOL name for MSEC. */
375 1.1.1.11 joerg
376 1.1.1.11 joerg if (n && (n = n->next))
377 1.1.1.15 joerg man->meta.vol = mandoc_strdup(n->string);
378 1.1.1.15 joerg else if ('\0' != man->meta.msec[0] &&
379 1.1.1.15 joerg (NULL != (p = mandoc_a2msec(man->meta.msec))))
380 1.1.1.15 joerg man->meta.vol = mandoc_strdup(p);
381 1.1.1.11 joerg
382 1.1.1.16 christos if (n != NULL && (n = n->next) != NULL)
383 1.1.1.16 christos mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
384 1.1.1.16 christos n->line, n->pos, "TH ... %s", n->string);
385 1.1.1.16 christos
386 1.1.1.11 joerg /*
387 1.1.1.11 joerg * Remove the `TH' node after we've processed it for our
388 1.1.1.11 joerg * meta-data.
389 1.1.1.11 joerg */
390 1.1.1.15 joerg man_node_delete(man, man->last);
391 1.1.1.11 joerg }
392 1.1.1.11 joerg
393 1.1.1.16 christos static void
394 1.1.1.11 joerg post_nf(CHKARGS)
395 1.1.1.11 joerg {
396 1.1.1.11 joerg
397 1.1.1.16 christos if (man->flags & MAN_LITERAL)
398 1.1.1.16 christos mandoc_msg(MANDOCERR_NF_SKIP, man->parse,
399 1.1.1.16 christos n->line, n->pos, "nf");
400 1.1.1.11 joerg
401 1.1.1.15 joerg man->flags |= MAN_LITERAL;
402 1.1.1.11 joerg }
403 1.1.1.11 joerg
404 1.1.1.16 christos static void
405 1.1.1.11 joerg post_fi(CHKARGS)
406 1.1.1.11 joerg {
407 1.1.1.11 joerg
408 1.1.1.15 joerg if ( ! (MAN_LITERAL & man->flags))
409 1.1.1.16 christos mandoc_msg(MANDOCERR_FI_SKIP, man->parse,
410 1.1.1.16 christos n->line, n->pos, "fi");
411 1.1.1.11 joerg
412 1.1.1.15 joerg man->flags &= ~MAN_LITERAL;
413 1.1.1.11 joerg }
414 1.1.1.11 joerg
415 1.1.1.16 christos static void
416 1.1.1.11 joerg post_UC(CHKARGS)
417 1.1.1.11 joerg {
418 1.1.1.11 joerg static const char * const bsd_versions[] = {
419 1.1.1.11 joerg "3rd Berkeley Distribution",
420 1.1.1.11 joerg "4th Berkeley Distribution",
421 1.1.1.11 joerg "4.2 Berkeley Distribution",
422 1.1.1.11 joerg "4.3 Berkeley Distribution",
423 1.1.1.11 joerg "4.4 Berkeley Distribution",
424 1.1.1.11 joerg };
425 1.1.1.11 joerg
426 1.1.1.11 joerg const char *p, *s;
427 1.1.1.11 joerg
428 1.1.1.11 joerg n = n->child;
429 1.1.1.11 joerg
430 1.1.1.11 joerg if (NULL == n || MAN_TEXT != n->type)
431 1.1.1.11 joerg p = bsd_versions[0];
432 1.1.1.11 joerg else {
433 1.1.1.11 joerg s = n->string;
434 1.1.1.11 joerg if (0 == strcmp(s, "3"))
435 1.1.1.11 joerg p = bsd_versions[0];
436 1.1.1.11 joerg else if (0 == strcmp(s, "4"))
437 1.1.1.11 joerg p = bsd_versions[1];
438 1.1.1.11 joerg else if (0 == strcmp(s, "5"))
439 1.1.1.11 joerg p = bsd_versions[2];
440 1.1.1.11 joerg else if (0 == strcmp(s, "6"))
441 1.1.1.11 joerg p = bsd_versions[3];
442 1.1.1.11 joerg else if (0 == strcmp(s, "7"))
443 1.1.1.11 joerg p = bsd_versions[4];
444 1.1.1.11 joerg else
445 1.1.1.11 joerg p = bsd_versions[0];
446 1.1.1.11 joerg }
447 1.1.1.11 joerg
448 1.1.1.15 joerg free(man->meta.source);
449 1.1.1.15 joerg man->meta.source = mandoc_strdup(p);
450 1.1.1.11 joerg }
451 1.1.1.11 joerg
452 1.1.1.16 christos static void
453 1.1.1.11 joerg post_AT(CHKARGS)
454 1.1.1.11 joerg {
455 1.1.1.11 joerg static const char * const unix_versions[] = {
456 1.1.1.11 joerg "7th Edition",
457 1.1.1.11 joerg "System III",
458 1.1.1.11 joerg "System V",
459 1.1.1.11 joerg "System V Release 2",
460 1.1.1.11 joerg };
461 1.1.1.11 joerg
462 1.1.1.11 joerg const char *p, *s;
463 1.1.1.11 joerg struct man_node *nn;
464 1.1.1.11 joerg
465 1.1.1.11 joerg n = n->child;
466 1.1.1.11 joerg
467 1.1.1.11 joerg if (NULL == n || MAN_TEXT != n->type)
468 1.1.1.11 joerg p = unix_versions[0];
469 1.1.1.11 joerg else {
470 1.1.1.11 joerg s = n->string;
471 1.1.1.11 joerg if (0 == strcmp(s, "3"))
472 1.1.1.11 joerg p = unix_versions[0];
473 1.1.1.11 joerg else if (0 == strcmp(s, "4"))
474 1.1.1.11 joerg p = unix_versions[1];
475 1.1.1.11 joerg else if (0 == strcmp(s, "5")) {
476 1.1.1.11 joerg nn = n->next;
477 1.1.1.11 joerg if (nn && MAN_TEXT == nn->type && nn->string[0])
478 1.1.1.11 joerg p = unix_versions[3];
479 1.1.1.11 joerg else
480 1.1.1.11 joerg p = unix_versions[2];
481 1.1.1.11 joerg } else
482 1.1.1.11 joerg p = unix_versions[0];
483 1.1.1.11 joerg }
484 1.1.1.11 joerg
485 1.1.1.15 joerg free(man->meta.source);
486 1.1.1.15 joerg man->meta.source = mandoc_strdup(p);
487 1.1.1.11 joerg }
488 1.1.1.13 joerg
489 1.1.1.16 christos static void
490 1.1.1.13 joerg post_vs(CHKARGS)
491 1.1.1.13 joerg {
492 1.1.1.13 joerg
493 1.1.1.15 joerg if (NULL != n->prev)
494 1.1.1.16 christos return;
495 1.1.1.15 joerg
496 1.1.1.15 joerg switch (n->parent->tok) {
497 1.1.1.16 christos case MAN_SH:
498 1.1.1.15 joerg /* FALLTHROUGH */
499 1.1.1.16 christos case MAN_SS:
500 1.1.1.16 christos mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos,
501 1.1.1.16 christos "%s after %s", man_macronames[n->tok],
502 1.1.1.16 christos man_macronames[n->parent->tok]);
503 1.1.1.15 joerg /* FALLTHROUGH */
504 1.1.1.16 christos case MAN_MAX:
505 1.1.1.16 christos /*
506 1.1.1.15 joerg * Don't warn about this because it occurs in pod2man
507 1.1.1.15 joerg * and would cause considerable (unfixable) warnage.
508 1.1.1.15 joerg */
509 1.1.1.15 joerg man_node_delete(man, n);
510 1.1.1.15 joerg break;
511 1.1.1.15 joerg default:
512 1.1.1.15 joerg break;
513 1.1.1.15 joerg }
514 1.1.1.13 joerg }
515