man_validate.c revision 1.1.1.12 1 1.1.1.12 joerg /* $Vendor-Id: man_validate.c,v 1.67 2011/03/22 15:30:30 kristaps 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.12 joerg * Copyright (c) 2010 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.8 joerg #define CHKARGS struct man *m, 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_bline(CHKARGS);
48 1.1 joerg static int check_eq0(CHKARGS);
49 1.1.1.11 joerg static int check_ft(CHKARGS);
50 1.1 joerg static int check_le1(CHKARGS);
51 1.1 joerg static int check_ge2(CHKARGS);
52 1.1 joerg static int check_le5(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 joerg static int check_sec(CHKARGS);
57 1.1 joerg static int check_text(CHKARGS);
58 1.1 joerg
59 1.1.1.11 joerg static int post_AT(CHKARGS);
60 1.1.1.11 joerg static int post_fi(CHKARGS);
61 1.1.1.11 joerg static int post_nf(CHKARGS);
62 1.1.1.11 joerg static int post_TH(CHKARGS);
63 1.1.1.11 joerg static int post_UC(CHKARGS);
64 1.1.1.11 joerg
65 1.1.1.11 joerg static v_check posts_at[] = { post_AT, NULL };
66 1.1 joerg static v_check posts_eq0[] = { check_eq0, NULL };
67 1.1.1.11 joerg static v_check posts_fi[] = { check_eq0, post_fi, NULL };
68 1.1.1.11 joerg static v_check posts_le1[] = { check_le1, NULL };
69 1.1.1.11 joerg static v_check posts_ft[] = { check_ft, NULL };
70 1.1.1.11 joerg static v_check posts_nf[] = { check_eq0, post_nf, NULL };
71 1.1 joerg static v_check posts_par[] = { check_par, NULL };
72 1.1 joerg static v_check posts_part[] = { check_part, NULL };
73 1.1 joerg static v_check posts_sec[] = { check_sec, NULL };
74 1.1.1.12 joerg static v_check posts_th[] = { check_ge2, check_le5, post_TH, NULL };
75 1.1.1.11 joerg static v_check posts_uc[] = { post_UC, NULL };
76 1.1 joerg static v_check pres_bline[] = { check_bline, NULL };
77 1.1 joerg
78 1.1.1.11 joerg
79 1.1 joerg static const struct man_valid man_valids[MAN_MAX] = {
80 1.1.1.5 joerg { NULL, posts_eq0 }, /* br */
81 1.1.1.5 joerg { pres_bline, posts_th }, /* TH */
82 1.1 joerg { pres_bline, posts_sec }, /* SH */
83 1.1 joerg { pres_bline, posts_sec }, /* SS */
84 1.1.1.12 joerg { pres_bline, NULL }, /* TP */
85 1.1 joerg { pres_bline, posts_par }, /* LP */
86 1.1 joerg { pres_bline, posts_par }, /* PP */
87 1.1 joerg { pres_bline, posts_par }, /* P */
88 1.1.1.12 joerg { pres_bline, NULL }, /* IP */
89 1.1.1.12 joerg { pres_bline, NULL }, /* HP */
90 1.1 joerg { NULL, NULL }, /* SM */
91 1.1 joerg { NULL, NULL }, /* SB */
92 1.1 joerg { NULL, NULL }, /* BI */
93 1.1 joerg { NULL, NULL }, /* IB */
94 1.1 joerg { NULL, NULL }, /* BR */
95 1.1 joerg { NULL, NULL }, /* RB */
96 1.1 joerg { NULL, NULL }, /* R */
97 1.1 joerg { NULL, NULL }, /* B */
98 1.1 joerg { NULL, NULL }, /* I */
99 1.1 joerg { NULL, NULL }, /* IR */
100 1.1 joerg { NULL, NULL }, /* RI */
101 1.1.1.10 joerg { NULL, posts_eq0 }, /* na */ /* FIXME: should warn only. */
102 1.1.1.10 joerg { NULL, posts_le1 }, /* sp */ /* FIXME: should warn only. */
103 1.1.1.11 joerg { pres_bline, posts_nf }, /* nf */
104 1.1.1.11 joerg { pres_bline, posts_fi }, /* fi */
105 1.1 joerg { NULL, NULL }, /* RE */
106 1.1 joerg { NULL, posts_part }, /* RS */
107 1.1 joerg { NULL, NULL }, /* DT */
108 1.1.1.11 joerg { NULL, posts_uc }, /* UC */
109 1.1.1.2 joerg { NULL, NULL }, /* PD */
110 1.1.1.11 joerg { NULL, posts_at }, /* AT */
111 1.1.1.10 joerg { NULL, NULL }, /* in */
112 1.1.1.11 joerg { NULL, posts_ft }, /* ft */
113 1.1 joerg };
114 1.1 joerg
115 1.1 joerg
116 1.1 joerg int
117 1.1.1.8 joerg man_valid_pre(struct man *m, struct man_node *n)
118 1.1 joerg {
119 1.1 joerg v_check *cp;
120 1.1 joerg
121 1.1.1.11 joerg switch (n->type) {
122 1.1.1.11 joerg case (MAN_TEXT):
123 1.1.1.11 joerg /* FALLTHROUGH */
124 1.1.1.11 joerg case (MAN_ROOT):
125 1.1.1.11 joerg /* FALLTHROUGH */
126 1.1.1.12 joerg case (MAN_EQN):
127 1.1.1.12 joerg /* FALLTHROUGH */
128 1.1.1.11 joerg case (MAN_TBL):
129 1.1 joerg return(1);
130 1.1.1.11 joerg default:
131 1.1.1.11 joerg break;
132 1.1.1.11 joerg }
133 1.1 joerg
134 1.1 joerg if (NULL == (cp = man_valids[n->tok].pres))
135 1.1 joerg return(1);
136 1.1 joerg for ( ; *cp; cp++)
137 1.1 joerg if ( ! (*cp)(m, n))
138 1.1 joerg return(0);
139 1.1 joerg return(1);
140 1.1 joerg }
141 1.1 joerg
142 1.1 joerg
143 1.1 joerg int
144 1.1 joerg man_valid_post(struct man *m)
145 1.1 joerg {
146 1.1 joerg v_check *cp;
147 1.1 joerg
148 1.1 joerg if (MAN_VALID & m->last->flags)
149 1.1 joerg return(1);
150 1.1 joerg m->last->flags |= MAN_VALID;
151 1.1 joerg
152 1.1 joerg switch (m->last->type) {
153 1.1 joerg case (MAN_TEXT):
154 1.1 joerg return(check_text(m, m->last));
155 1.1 joerg case (MAN_ROOT):
156 1.1 joerg return(check_root(m, m->last));
157 1.1.1.12 joerg case (MAN_EQN):
158 1.1.1.12 joerg /* FALLTHROUGH */
159 1.1.1.11 joerg case (MAN_TBL):
160 1.1.1.11 joerg return(1);
161 1.1 joerg default:
162 1.1 joerg break;
163 1.1 joerg }
164 1.1 joerg
165 1.1 joerg if (NULL == (cp = man_valids[m->last->tok].posts))
166 1.1 joerg return(1);
167 1.1 joerg for ( ; *cp; cp++)
168 1.1 joerg if ( ! (*cp)(m, m->last))
169 1.1 joerg return(0);
170 1.1 joerg
171 1.1 joerg return(1);
172 1.1 joerg }
173 1.1 joerg
174 1.1 joerg
175 1.1 joerg static int
176 1.1 joerg check_root(CHKARGS)
177 1.1 joerg {
178 1.1 joerg
179 1.1 joerg if (MAN_BLINE & m->flags)
180 1.1.1.11 joerg man_nmsg(m, n, MANDOCERR_SCOPEEXIT);
181 1.1.1.11 joerg else if (MAN_ELINE & m->flags)
182 1.1.1.11 joerg man_nmsg(m, n, MANDOCERR_SCOPEEXIT);
183 1.1 joerg
184 1.1 joerg m->flags &= ~MAN_BLINE;
185 1.1 joerg m->flags &= ~MAN_ELINE;
186 1.1 joerg
187 1.1.1.7 joerg if (NULL == m->first->child) {
188 1.1.1.7 joerg man_nmsg(m, n, MANDOCERR_NODOCBODY);
189 1.1.1.7 joerg return(0);
190 1.1.1.7 joerg } else if (NULL == m->meta.title) {
191 1.1.1.11 joerg man_nmsg(m, n, MANDOCERR_NOTITLE);
192 1.1.1.11 joerg
193 1.1.1.6 joerg /*
194 1.1.1.6 joerg * If a title hasn't been set, do so now (by
195 1.1.1.6 joerg * implication, date and section also aren't set).
196 1.1.1.6 joerg */
197 1.1.1.11 joerg
198 1.1.1.6 joerg m->meta.title = mandoc_strdup("unknown");
199 1.1.1.7 joerg m->meta.msec = mandoc_strdup("1");
200 1.1.1.12 joerg m->meta.date = mandoc_normdate
201 1.1.1.12 joerg (m->parse, NULL, n->line, n->pos);
202 1.1.1.6 joerg }
203 1.1 joerg
204 1.1 joerg return(1);
205 1.1 joerg }
206 1.1 joerg
207 1.1 joerg
208 1.1 joerg static int
209 1.1 joerg check_text(CHKARGS)
210 1.1 joerg {
211 1.1.1.8 joerg char *p;
212 1.1 joerg int pos, c;
213 1.1.1.10 joerg size_t sz;
214 1.1 joerg
215 1.1 joerg for (p = n->string, pos = n->pos + 1; *p; p++, pos++) {
216 1.1.1.10 joerg sz = strcspn(p, "\t\\");
217 1.1.1.10 joerg p += (int)sz;
218 1.1.1.10 joerg
219 1.1.1.10 joerg if ('\0' == *p)
220 1.1.1.10 joerg break;
221 1.1.1.10 joerg
222 1.1.1.10 joerg pos += (int)sz;
223 1.1.1.7 joerg
224 1.1.1.10 joerg if ('\t' == *p) {
225 1.1.1.10 joerg if (MAN_LITERAL & m->flags)
226 1.1.1.10 joerg continue;
227 1.1.1.12 joerg man_pmsg(m, n->line, pos, MANDOCERR_BADTAB);
228 1.1.1.12 joerg continue;
229 1.1 joerg }
230 1.1 joerg
231 1.1.1.10 joerg /* Check the special character. */
232 1.1.1.9 joerg
233 1.1.1.10 joerg c = mandoc_special(p);
234 1.1.1.10 joerg if (c) {
235 1.1.1.10 joerg p += c - 1;
236 1.1.1.10 joerg pos += c - 1;
237 1.1.1.11 joerg } else
238 1.1.1.11 joerg man_pmsg(m, n->line, pos, MANDOCERR_BADESCAPE);
239 1.1 joerg }
240 1.1 joerg
241 1.1 joerg return(1);
242 1.1 joerg }
243 1.1 joerg
244 1.1 joerg
245 1.1 joerg #define INEQ_DEFINE(x, ineq, name) \
246 1.1 joerg static int \
247 1.1 joerg check_##name(CHKARGS) \
248 1.1 joerg { \
249 1.1 joerg if (n->nchild ineq (x)) \
250 1.1 joerg return(1); \
251 1.1.1.12 joerg mandoc_vmsg(MANDOCERR_ARGCOUNT, m->parse, n->line, n->pos, \
252 1.1.1.7 joerg "line arguments %s %d (have %d)", \
253 1.1.1.7 joerg #ineq, (x), n->nchild); \
254 1.1.1.12 joerg return(1); \
255 1.1 joerg }
256 1.1 joerg
257 1.1 joerg INEQ_DEFINE(0, ==, eq0)
258 1.1 joerg INEQ_DEFINE(1, <=, le1)
259 1.1 joerg INEQ_DEFINE(2, >=, ge2)
260 1.1 joerg INEQ_DEFINE(5, <=, le5)
261 1.1 joerg
262 1.1.1.11 joerg static int
263 1.1.1.11 joerg check_ft(CHKARGS)
264 1.1.1.11 joerg {
265 1.1.1.11 joerg char *cp;
266 1.1.1.11 joerg int ok;
267 1.1.1.11 joerg
268 1.1.1.11 joerg if (0 == n->nchild)
269 1.1.1.11 joerg return(1);
270 1.1.1.11 joerg
271 1.1.1.11 joerg ok = 0;
272 1.1.1.11 joerg cp = n->child->string;
273 1.1.1.11 joerg switch (*cp) {
274 1.1.1.11 joerg case ('1'):
275 1.1.1.11 joerg /* FALLTHROUGH */
276 1.1.1.11 joerg case ('2'):
277 1.1.1.11 joerg /* FALLTHROUGH */
278 1.1.1.11 joerg case ('3'):
279 1.1.1.11 joerg /* FALLTHROUGH */
280 1.1.1.11 joerg case ('4'):
281 1.1.1.11 joerg /* FALLTHROUGH */
282 1.1.1.11 joerg case ('I'):
283 1.1.1.11 joerg /* FALLTHROUGH */
284 1.1.1.11 joerg case ('P'):
285 1.1.1.11 joerg /* FALLTHROUGH */
286 1.1.1.11 joerg case ('R'):
287 1.1.1.11 joerg if ('\0' == cp[1])
288 1.1.1.11 joerg ok = 1;
289 1.1.1.11 joerg break;
290 1.1.1.11 joerg case ('B'):
291 1.1.1.11 joerg if ('\0' == cp[1] || ('I' == cp[1] && '\0' == cp[2]))
292 1.1.1.11 joerg ok = 1;
293 1.1.1.11 joerg break;
294 1.1.1.11 joerg case ('C'):
295 1.1.1.11 joerg if ('W' == cp[1] && '\0' == cp[2])
296 1.1.1.11 joerg ok = 1;
297 1.1.1.11 joerg break;
298 1.1.1.11 joerg default:
299 1.1.1.11 joerg break;
300 1.1.1.11 joerg }
301 1.1.1.11 joerg
302 1.1.1.11 joerg if (0 == ok) {
303 1.1.1.12 joerg mandoc_vmsg
304 1.1.1.12 joerg (MANDOCERR_BADFONT, m->parse,
305 1.1.1.12 joerg n->line, n->pos, "%s", cp);
306 1.1.1.11 joerg *cp = '\0';
307 1.1.1.11 joerg }
308 1.1.1.11 joerg
309 1.1.1.11 joerg if (1 < n->nchild)
310 1.1.1.12 joerg mandoc_vmsg
311 1.1.1.12 joerg (MANDOCERR_ARGCOUNT, m->parse, n->line,
312 1.1.1.12 joerg n->pos, "want one child (have %d)",
313 1.1.1.12 joerg n->nchild);
314 1.1.1.11 joerg
315 1.1.1.11 joerg return(1);
316 1.1.1.11 joerg }
317 1.1 joerg
318 1.1 joerg static int
319 1.1 joerg check_sec(CHKARGS)
320 1.1 joerg {
321 1.1 joerg
322 1.1.1.7 joerg if (MAN_HEAD == n->type && 0 == n->nchild) {
323 1.1.1.7 joerg man_nmsg(m, n, MANDOCERR_SYNTARGCOUNT);
324 1.1.1.7 joerg return(0);
325 1.1.1.7 joerg } else if (MAN_BODY == n->type && 0 == n->nchild)
326 1.1.1.12 joerg mandoc_msg(MANDOCERR_ARGCWARN, m->parse, n->line,
327 1.1.1.12 joerg n->pos, "want children (have none)");
328 1.1.1.7 joerg
329 1.1 joerg return(1);
330 1.1 joerg }
331 1.1 joerg
332 1.1 joerg
333 1.1 joerg static int
334 1.1 joerg check_part(CHKARGS)
335 1.1 joerg {
336 1.1 joerg
337 1.1 joerg if (MAN_BODY == n->type && 0 == n->nchild)
338 1.1.1.12 joerg mandoc_msg(MANDOCERR_ARGCWARN, m->parse, n->line,
339 1.1.1.12 joerg n->pos, "want children (have none)");
340 1.1.1.11 joerg
341 1.1 joerg return(1);
342 1.1 joerg }
343 1.1 joerg
344 1.1 joerg
345 1.1 joerg static int
346 1.1 joerg check_par(CHKARGS)
347 1.1 joerg {
348 1.1 joerg
349 1.1.1.12 joerg switch (n->type) {
350 1.1.1.12 joerg case (MAN_BLOCK):
351 1.1.1.12 joerg if (0 == n->body->nchild)
352 1.1.1.12 joerg man_node_delete(m, n);
353 1.1.1.12 joerg break;
354 1.1.1.12 joerg case (MAN_BODY):
355 1.1.1.12 joerg if (0 == n->nchild)
356 1.1.1.12 joerg man_nmsg(m, n, MANDOCERR_IGNPAR);
357 1.1.1.12 joerg break;
358 1.1.1.12 joerg case (MAN_HEAD):
359 1.1.1.12 joerg if (n->nchild)
360 1.1.1.12 joerg man_nmsg(m, n, MANDOCERR_ARGSLOST);
361 1.1.1.12 joerg break;
362 1.1.1.12 joerg default:
363 1.1.1.12 joerg break;
364 1.1.1.12 joerg }
365 1.1 joerg
366 1.1 joerg return(1);
367 1.1 joerg }
368 1.1 joerg
369 1.1 joerg
370 1.1 joerg static int
371 1.1 joerg check_bline(CHKARGS)
372 1.1 joerg {
373 1.1 joerg
374 1.1 joerg assert( ! (MAN_ELINE & m->flags));
375 1.1.1.7 joerg if (MAN_BLINE & m->flags) {
376 1.1.1.7 joerg man_nmsg(m, n, MANDOCERR_SYNTLINESCOPE);
377 1.1.1.7 joerg return(0);
378 1.1.1.7 joerg }
379 1.1.1.5 joerg
380 1.1 joerg return(1);
381 1.1 joerg }
382 1.1 joerg
383 1.1.1.11 joerg static int
384 1.1.1.11 joerg post_TH(CHKARGS)
385 1.1.1.11 joerg {
386 1.1.1.12 joerg const char *p;
387 1.1.1.12 joerg int line, pos;
388 1.1.1.11 joerg
389 1.1.1.11 joerg if (m->meta.title)
390 1.1.1.11 joerg free(m->meta.title);
391 1.1.1.11 joerg if (m->meta.vol)
392 1.1.1.11 joerg free(m->meta.vol);
393 1.1.1.11 joerg if (m->meta.source)
394 1.1.1.11 joerg free(m->meta.source);
395 1.1.1.11 joerg if (m->meta.msec)
396 1.1.1.11 joerg free(m->meta.msec);
397 1.1.1.12 joerg if (m->meta.date)
398 1.1.1.12 joerg free(m->meta.date);
399 1.1.1.11 joerg
400 1.1.1.12 joerg line = n->line;
401 1.1.1.12 joerg pos = n->pos;
402 1.1.1.12 joerg m->meta.title = m->meta.vol = m->meta.date =
403 1.1.1.11 joerg m->meta.msec = m->meta.source = NULL;
404 1.1.1.11 joerg
405 1.1.1.11 joerg /* ->TITLE<- MSEC DATE SOURCE VOL */
406 1.1.1.11 joerg
407 1.1.1.11 joerg n = n->child;
408 1.1.1.12 joerg if (n && n->string) {
409 1.1.1.12 joerg for (p = n->string; '\0' != *p; p++) {
410 1.1.1.12 joerg /* Only warn about this once... */
411 1.1.1.12 joerg if (isalpha((u_char)*p) && ! isupper((u_char)*p)) {
412 1.1.1.12 joerg man_nmsg(m, n, MANDOCERR_UPPERCASE);
413 1.1.1.12 joerg break;
414 1.1.1.12 joerg }
415 1.1.1.12 joerg }
416 1.1.1.12 joerg m->meta.title = mandoc_strdup(n->string);
417 1.1.1.12 joerg } else
418 1.1.1.12 joerg m->meta.title = mandoc_strdup("");
419 1.1.1.11 joerg
420 1.1.1.11 joerg /* TITLE ->MSEC<- DATE SOURCE VOL */
421 1.1.1.11 joerg
422 1.1.1.12 joerg if (n)
423 1.1.1.12 joerg n = n->next;
424 1.1.1.12 joerg if (n && n->string)
425 1.1.1.12 joerg m->meta.msec = mandoc_strdup(n->string);
426 1.1.1.12 joerg else
427 1.1.1.12 joerg m->meta.msec = mandoc_strdup("");
428 1.1.1.11 joerg
429 1.1.1.11 joerg /* TITLE MSEC ->DATE<- SOURCE VOL */
430 1.1.1.11 joerg
431 1.1.1.12 joerg if (n)
432 1.1.1.12 joerg n = n->next;
433 1.1.1.12 joerg if (n)
434 1.1.1.12 joerg pos = n->pos;
435 1.1.1.12 joerg m->meta.date = mandoc_normdate
436 1.1.1.12 joerg (m->parse, n ? n->string : NULL, line, pos);
437 1.1.1.11 joerg
438 1.1.1.11 joerg /* TITLE MSEC DATE ->SOURCE<- VOL */
439 1.1.1.11 joerg
440 1.1.1.11 joerg if (n && (n = n->next))
441 1.1.1.11 joerg m->meta.source = mandoc_strdup(n->string);
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.11 joerg m->meta.vol = mandoc_strdup(n->string);
447 1.1.1.11 joerg
448 1.1.1.11 joerg /*
449 1.1.1.11 joerg * Remove the `TH' node after we've processed it for our
450 1.1.1.11 joerg * meta-data.
451 1.1.1.11 joerg */
452 1.1.1.11 joerg man_node_delete(m, m->last);
453 1.1.1.11 joerg return(1);
454 1.1.1.11 joerg }
455 1.1.1.11 joerg
456 1.1.1.11 joerg static int
457 1.1.1.11 joerg post_nf(CHKARGS)
458 1.1.1.11 joerg {
459 1.1.1.11 joerg
460 1.1.1.11 joerg if (MAN_LITERAL & m->flags)
461 1.1.1.11 joerg man_nmsg(m, n, MANDOCERR_SCOPEREP);
462 1.1.1.11 joerg
463 1.1.1.11 joerg m->flags |= MAN_LITERAL;
464 1.1.1.11 joerg return(1);
465 1.1.1.11 joerg }
466 1.1.1.11 joerg
467 1.1.1.11 joerg static int
468 1.1.1.11 joerg post_fi(CHKARGS)
469 1.1.1.11 joerg {
470 1.1.1.11 joerg
471 1.1.1.11 joerg if ( ! (MAN_LITERAL & m->flags))
472 1.1.1.12 joerg man_nmsg(m, n, MANDOCERR_WNOSCOPE);
473 1.1.1.11 joerg
474 1.1.1.11 joerg m->flags &= ~MAN_LITERAL;
475 1.1.1.11 joerg return(1);
476 1.1.1.11 joerg }
477 1.1.1.11 joerg
478 1.1.1.11 joerg static int
479 1.1.1.11 joerg post_UC(CHKARGS)
480 1.1.1.11 joerg {
481 1.1.1.11 joerg static const char * const bsd_versions[] = {
482 1.1.1.11 joerg "3rd Berkeley Distribution",
483 1.1.1.11 joerg "4th Berkeley Distribution",
484 1.1.1.11 joerg "4.2 Berkeley Distribution",
485 1.1.1.11 joerg "4.3 Berkeley Distribution",
486 1.1.1.11 joerg "4.4 Berkeley Distribution",
487 1.1.1.11 joerg };
488 1.1.1.11 joerg
489 1.1.1.11 joerg const char *p, *s;
490 1.1.1.11 joerg
491 1.1.1.11 joerg n = n->child;
492 1.1.1.11 joerg n = m->last->child;
493 1.1.1.11 joerg
494 1.1.1.11 joerg if (NULL == n || MAN_TEXT != n->type)
495 1.1.1.11 joerg p = bsd_versions[0];
496 1.1.1.11 joerg else {
497 1.1.1.11 joerg s = n->string;
498 1.1.1.11 joerg if (0 == strcmp(s, "3"))
499 1.1.1.11 joerg p = bsd_versions[0];
500 1.1.1.11 joerg else if (0 == strcmp(s, "4"))
501 1.1.1.11 joerg p = bsd_versions[1];
502 1.1.1.11 joerg else if (0 == strcmp(s, "5"))
503 1.1.1.11 joerg p = bsd_versions[2];
504 1.1.1.11 joerg else if (0 == strcmp(s, "6"))
505 1.1.1.11 joerg p = bsd_versions[3];
506 1.1.1.11 joerg else if (0 == strcmp(s, "7"))
507 1.1.1.11 joerg p = bsd_versions[4];
508 1.1.1.11 joerg else
509 1.1.1.11 joerg p = bsd_versions[0];
510 1.1.1.11 joerg }
511 1.1.1.11 joerg
512 1.1.1.11 joerg if (m->meta.source)
513 1.1.1.11 joerg free(m->meta.source);
514 1.1.1.11 joerg
515 1.1.1.11 joerg m->meta.source = mandoc_strdup(p);
516 1.1.1.11 joerg return(1);
517 1.1.1.11 joerg }
518 1.1.1.11 joerg
519 1.1.1.11 joerg static int
520 1.1.1.11 joerg post_AT(CHKARGS)
521 1.1.1.11 joerg {
522 1.1.1.11 joerg static const char * const unix_versions[] = {
523 1.1.1.11 joerg "7th Edition",
524 1.1.1.11 joerg "System III",
525 1.1.1.11 joerg "System V",
526 1.1.1.11 joerg "System V Release 2",
527 1.1.1.11 joerg };
528 1.1.1.11 joerg
529 1.1.1.11 joerg const char *p, *s;
530 1.1.1.11 joerg struct man_node *nn;
531 1.1.1.11 joerg
532 1.1.1.11 joerg n = n->child;
533 1.1.1.11 joerg
534 1.1.1.11 joerg if (NULL == n || MAN_TEXT != n->type)
535 1.1.1.11 joerg p = unix_versions[0];
536 1.1.1.11 joerg else {
537 1.1.1.11 joerg s = n->string;
538 1.1.1.11 joerg if (0 == strcmp(s, "3"))
539 1.1.1.11 joerg p = unix_versions[0];
540 1.1.1.11 joerg else if (0 == strcmp(s, "4"))
541 1.1.1.11 joerg p = unix_versions[1];
542 1.1.1.11 joerg else if (0 == strcmp(s, "5")) {
543 1.1.1.11 joerg nn = n->next;
544 1.1.1.11 joerg if (nn && MAN_TEXT == nn->type && nn->string[0])
545 1.1.1.11 joerg p = unix_versions[3];
546 1.1.1.11 joerg else
547 1.1.1.11 joerg p = unix_versions[2];
548 1.1.1.11 joerg } else
549 1.1.1.11 joerg p = unix_versions[0];
550 1.1.1.11 joerg }
551 1.1.1.11 joerg
552 1.1.1.11 joerg if (m->meta.source)
553 1.1.1.11 joerg free(m->meta.source);
554 1.1.1.11 joerg
555 1.1.1.11 joerg m->meta.source = mandoc_strdup(p);
556 1.1.1.11 joerg return(1);
557 1.1.1.11 joerg }
558