man_validate.c revision 1.1.1.17.12.1 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.17.12.1 pgoyette * 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.17.12.1 pgoyette static void post_in(CHKARGS);
55 1.1.1.17.12.1 pgoyette static void post_vs(CHKARGS);
56 1.1.1.16 christos
57 1.1.1.17.12.1 pgoyette 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.17.12.1 pgoyette 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.17.12.1 pgoyette post_UR, /* MT */
93 1.1.1.17.12.1 pgoyette NULL, /* ME */
94 1.1 joerg };
95 1.1.1.17.12.1 pgoyette 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.17.12.1 pgoyette 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.17.12.1 pgoyette 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.17.12.1 pgoyette if (n->tok < ROFF_MAX) {
129 1.1.1.17.12.1 pgoyette switch (n->tok) {
130 1.1.1.17.12.1 pgoyette case ROFF_br:
131 1.1.1.17.12.1 pgoyette case ROFF_sp:
132 1.1.1.17.12.1 pgoyette post_vs(man, n);
133 1.1.1.17.12.1 pgoyette break;
134 1.1.1.17.12.1 pgoyette default:
135 1.1.1.17.12.1 pgoyette roff_validate(man);
136 1.1.1.17.12.1 pgoyette break;
137 1.1.1.17.12.1 pgoyette }
138 1.1.1.17.12.1 pgoyette break;
139 1.1.1.17.12.1 pgoyette }
140 1.1.1.17.12.1 pgoyette 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.17.12.1 pgoyette 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.17.12.1 pgoyette mandoc_normdate(man, NULL, n->line, n->pos);
174 1.1.1.6 joerg }
175 1.1.1.17.12.1 pgoyette
176 1.1.1.17.12.1 pgoyette if (man->meta.os_e &&
177 1.1.1.17.12.1 pgoyette (man->meta.rcsids & (1 << man->meta.os_e)) == 0)
178 1.1.1.17.12.1 pgoyette mandoc_msg(MANDOCERR_RCS_MISSING, man->parse, 0, 0,
179 1.1.1.17.12.1 pgoyette man->meta.os_e == MANDOC_OS_OPENBSD ?
180 1.1.1.17.12.1 pgoyette "(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.17.12.1 pgoyette mandoc_msg(MANDOCERR_UR_NOHEAD, man->parse,
216 1.1.1.17.12.1 pgoyette 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.17.12.1 pgoyette 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.17.12.1 pgoyette "%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.17.12.1 pgoyette man->parse, n->line, n->pos, "%s %s%s",
248 1.1.1.17.12.1 pgoyette 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.17.12.1 pgoyette "%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.17.12.1 pgoyette 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.17.12.1 pgoyette else if (man->os_s != NULL)
347 1.1.1.17.12.1 pgoyette man->meta.os = mandoc_strdup(man->os_s);
348 1.1.1.17.12.1 pgoyette if (man->meta.os_e == MANDOC_OS_OTHER && man->meta.os != NULL) {
349 1.1.1.17.12.1 pgoyette if (strstr(man->meta.os, "OpenBSD") != NULL)
350 1.1.1.17.12.1 pgoyette man->meta.os_e = MANDOC_OS_OPENBSD;
351 1.1.1.17.12.1 pgoyette else if (strstr(man->meta.os, "NetBSD") != NULL)
352 1.1.1.17.12.1 pgoyette man->meta.os_e = MANDOC_OS_NETBSD;
353 1.1.1.17.12.1 pgoyette }
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.17.12.1 pgoyette post_in(CHKARGS)
453 1.1.1.17.12.1 pgoyette {
454 1.1.1.17.12.1 pgoyette char *s;
455 1.1.1.17.12.1 pgoyette
456 1.1.1.17.12.1 pgoyette if (n->parent->tok != MAN_TP ||
457 1.1.1.17.12.1 pgoyette n->parent->type != ROFFT_HEAD ||
458 1.1.1.17.12.1 pgoyette n->child == NULL ||
459 1.1.1.17.12.1 pgoyette *n->child->string == '+' ||
460 1.1.1.17.12.1 pgoyette *n->child->string == '-')
461 1.1.1.17.12.1 pgoyette return;
462 1.1.1.17.12.1 pgoyette mandoc_asprintf(&s, "+%s", n->child->string);
463 1.1.1.17.12.1 pgoyette free(n->child->string);
464 1.1.1.17.12.1 pgoyette n->child->string = s;
465 1.1.1.17.12.1 pgoyette }
466 1.1.1.17.12.1 pgoyette
467 1.1.1.17.12.1 pgoyette 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.17.12.1 pgoyette case MAN_PP:
478 1.1.1.17.12.1 pgoyette case MAN_LP:
479 1.1.1.17.12.1 pgoyette case MAN_P:
480 1.1.1.16 christos mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos,
481 1.1.1.17.12.1 pgoyette "%s after %s", roff_name[n->tok],
482 1.1.1.17.12.1 pgoyette 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