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