Print this page
Various tweaks -- add our sections, etc.
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/mandoc/mdoc_validate.c
+++ new/usr/src/cmd/mandoc/mdoc_validate.c
1 1 /* $Id: mdoc_validate.c,v 1.182 2012/03/23 05:50:25 kristaps Exp $ */
2 2 /*
3 3 * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4 4 * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
5 5 *
6 6 * Permission to use, copy, modify, and distribute this software for any
7 7 * purpose with or without fee is hereby granted, provided that the above
8 8 * copyright notice and this permission notice appear in all copies.
9 9 *
10 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 17 */
18 18 #ifdef HAVE_CONFIG_H
19 19 #include "config.h"
20 20 #endif
21 21
22 22 #ifndef OSNAME
23 23 #include <sys/utsname.h>
24 24 #endif
25 25
26 26 #include <sys/types.h>
27 27
28 28 #include <assert.h>
29 29 #include <ctype.h>
30 30 #include <limits.h>
31 31 #include <stdio.h>
32 32 #include <stdlib.h>
33 33 #include <string.h>
34 34 #include <time.h>
35 35
36 36 #include "mdoc.h"
37 37 #include "mandoc.h"
38 38 #include "libmdoc.h"
39 39 #include "libmandoc.h"
40 40
41 41 /* FIXME: .Bl -diag can't have non-text children in HEAD. */
42 42
43 43 #define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n
44 44 #define POST_ARGS struct mdoc *mdoc
45 45
46 46 #define NUMSIZ 32
47 47 #define DATESIZE 32
48 48
49 49 enum check_ineq {
50 50 CHECK_LT,
51 51 CHECK_GT,
52 52 CHECK_EQ
53 53 };
54 54
55 55 enum check_lvl {
56 56 CHECK_WARN,
57 57 CHECK_ERROR,
58 58 };
59 59
60 60 typedef int (*v_pre)(PRE_ARGS);
61 61 typedef int (*v_post)(POST_ARGS);
62 62
63 63 struct valids {
64 64 v_pre *pre;
65 65 v_post *post;
66 66 };
67 67
68 68 static int check_count(struct mdoc *, enum mdoc_type,
69 69 enum check_lvl, enum check_ineq, int);
70 70 static int check_parent(PRE_ARGS, enum mdoct, enum mdoc_type);
71 71 static void check_text(struct mdoc *, int, int, char *);
72 72 static void check_argv(struct mdoc *,
73 73 struct mdoc_node *, struct mdoc_argv *);
74 74 static void check_args(struct mdoc *, struct mdoc_node *);
75 75 static int concat(char *, const struct mdoc_node *, size_t);
76 76 static enum mdoc_sec a2sec(const char *);
77 77 static size_t macro2len(enum mdoct);
78 78
79 79 static int ebool(POST_ARGS);
80 80 static int berr_ge1(POST_ARGS);
81 81 static int bwarn_ge1(POST_ARGS);
82 82 static int ewarn_eq0(POST_ARGS);
83 83 static int ewarn_eq1(POST_ARGS);
84 84 static int ewarn_ge1(POST_ARGS);
85 85 static int ewarn_le1(POST_ARGS);
86 86 static int hwarn_eq0(POST_ARGS);
87 87 static int hwarn_eq1(POST_ARGS);
88 88 static int hwarn_ge1(POST_ARGS);
89 89 static int hwarn_le1(POST_ARGS);
90 90
91 91 static int post_an(POST_ARGS);
92 92 static int post_at(POST_ARGS);
93 93 static int post_bf(POST_ARGS);
94 94 static int post_bl(POST_ARGS);
95 95 static int post_bl_block(POST_ARGS);
96 96 static int post_bl_block_width(POST_ARGS);
97 97 static int post_bl_block_tag(POST_ARGS);
98 98 static int post_bl_head(POST_ARGS);
99 99 static int post_bx(POST_ARGS);
100 100 static int post_dd(POST_ARGS);
101 101 static int post_dt(POST_ARGS);
102 102 static int post_defaults(POST_ARGS);
103 103 static int post_literal(POST_ARGS);
104 104 static int post_eoln(POST_ARGS);
105 105 static int post_it(POST_ARGS);
106 106 static int post_lb(POST_ARGS);
107 107 static int post_nm(POST_ARGS);
108 108 static int post_ns(POST_ARGS);
109 109 static int post_os(POST_ARGS);
110 110 static int post_ignpar(POST_ARGS);
111 111 static int post_prol(POST_ARGS);
112 112 static int post_root(POST_ARGS);
113 113 static int post_rs(POST_ARGS);
114 114 static int post_sh(POST_ARGS);
115 115 static int post_sh_body(POST_ARGS);
116 116 static int post_sh_head(POST_ARGS);
117 117 static int post_st(POST_ARGS);
118 118 static int post_std(POST_ARGS);
119 119 static int post_vt(POST_ARGS);
120 120 static int pre_an(PRE_ARGS);
121 121 static int pre_bd(PRE_ARGS);
122 122 static int pre_bl(PRE_ARGS);
123 123 static int pre_dd(PRE_ARGS);
124 124 static int pre_display(PRE_ARGS);
125 125 static int pre_dt(PRE_ARGS);
126 126 static int pre_it(PRE_ARGS);
127 127 static int pre_literal(PRE_ARGS);
128 128 static int pre_os(PRE_ARGS);
129 129 static int pre_par(PRE_ARGS);
130 130 static int pre_sh(PRE_ARGS);
131 131 static int pre_ss(PRE_ARGS);
132 132 static int pre_std(PRE_ARGS);
133 133
134 134 static v_post posts_an[] = { post_an, NULL };
135 135 static v_post posts_at[] = { post_at, post_defaults, NULL };
136 136 static v_post posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL };
137 137 static v_post posts_bf[] = { hwarn_le1, post_bf, NULL };
138 138 static v_post posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL };
139 139 static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL };
140 140 static v_post posts_bx[] = { post_bx, NULL };
141 141 static v_post posts_bool[] = { ebool, NULL };
142 142 static v_post posts_eoln[] = { post_eoln, NULL };
143 143 static v_post posts_defaults[] = { post_defaults, NULL };
144 144 static v_post posts_dd[] = { post_dd, post_prol, NULL };
145 145 static v_post posts_dl[] = { post_literal, bwarn_ge1, NULL };
146 146 static v_post posts_dt[] = { post_dt, post_prol, NULL };
147 147 static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };
148 148 static v_post posts_it[] = { post_it, NULL };
149 149 static v_post posts_lb[] = { post_lb, NULL };
150 150 static v_post posts_nd[] = { berr_ge1, NULL };
151 151 static v_post posts_nm[] = { post_nm, NULL };
152 152 static v_post posts_notext[] = { ewarn_eq0, NULL };
153 153 static v_post posts_ns[] = { post_ns, NULL };
154 154 static v_post posts_os[] = { post_os, post_prol, NULL };
155 155 static v_post posts_rs[] = { post_rs, NULL };
156 156 static v_post posts_sh[] = { post_ignpar, hwarn_ge1, post_sh, NULL };
157 157 static v_post posts_sp[] = { ewarn_le1, NULL };
158 158 static v_post posts_ss[] = { post_ignpar, hwarn_ge1, NULL };
159 159 static v_post posts_st[] = { post_st, NULL };
160 160 static v_post posts_std[] = { post_std, NULL };
161 161 static v_post posts_text[] = { ewarn_ge1, NULL };
162 162 static v_post posts_text1[] = { ewarn_eq1, NULL };
163 163 static v_post posts_vt[] = { post_vt, NULL };
164 164 static v_post posts_wline[] = { bwarn_ge1, NULL };
165 165 static v_pre pres_an[] = { pre_an, NULL };
166 166 static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL };
167 167 static v_pre pres_bl[] = { pre_bl, pre_par, NULL };
168 168 static v_pre pres_d1[] = { pre_display, NULL };
169 169 static v_pre pres_dl[] = { pre_literal, pre_display, NULL };
170 170 static v_pre pres_dd[] = { pre_dd, NULL };
171 171 static v_pre pres_dt[] = { pre_dt, NULL };
172 172 static v_pre pres_er[] = { NULL, NULL };
173 173 static v_pre pres_fd[] = { NULL, NULL };
174 174 static v_pre pres_it[] = { pre_it, pre_par, NULL };
175 175 static v_pre pres_os[] = { pre_os, NULL };
176 176 static v_pre pres_pp[] = { pre_par, NULL };
177 177 static v_pre pres_sh[] = { pre_sh, NULL };
178 178 static v_pre pres_ss[] = { pre_ss, NULL };
179 179 static v_pre pres_std[] = { pre_std, NULL };
180 180
181 181 static const struct valids mdoc_valids[MDOC_MAX] = {
182 182 { NULL, NULL }, /* Ap */
183 183 { pres_dd, posts_dd }, /* Dd */
184 184 { pres_dt, posts_dt }, /* Dt */
185 185 { pres_os, posts_os }, /* Os */
186 186 { pres_sh, posts_sh }, /* Sh */
187 187 { pres_ss, posts_ss }, /* Ss */
188 188 { pres_pp, posts_notext }, /* Pp */
189 189 { pres_d1, posts_wline }, /* D1 */
190 190 { pres_dl, posts_dl }, /* Dl */
191 191 { pres_bd, posts_bd }, /* Bd */
192 192 { NULL, NULL }, /* Ed */
193 193 { pres_bl, posts_bl }, /* Bl */
194 194 { NULL, NULL }, /* El */
195 195 { pres_it, posts_it }, /* It */
196 196 { NULL, NULL }, /* Ad */
197 197 { pres_an, posts_an }, /* An */
198 198 { NULL, posts_defaults }, /* Ar */
199 199 { NULL, NULL }, /* Cd */
200 200 { NULL, NULL }, /* Cm */
201 201 { NULL, NULL }, /* Dv */
202 202 { pres_er, NULL }, /* Er */
203 203 { NULL, NULL }, /* Ev */
204 204 { pres_std, posts_std }, /* Ex */
205 205 { NULL, NULL }, /* Fa */
206 206 { pres_fd, posts_text }, /* Fd */
207 207 { NULL, NULL }, /* Fl */
208 208 { NULL, NULL }, /* Fn */
209 209 { NULL, NULL }, /* Ft */
210 210 { NULL, NULL }, /* Ic */
211 211 { NULL, posts_text1 }, /* In */
212 212 { NULL, posts_defaults }, /* Li */
213 213 { NULL, posts_nd }, /* Nd */
214 214 { NULL, posts_nm }, /* Nm */
215 215 { NULL, NULL }, /* Op */
216 216 { NULL, NULL }, /* Ot */
217 217 { NULL, posts_defaults }, /* Pa */
218 218 { pres_std, posts_std }, /* Rv */
219 219 { NULL, posts_st }, /* St */
220 220 { NULL, NULL }, /* Va */
221 221 { NULL, posts_vt }, /* Vt */
222 222 { NULL, posts_text }, /* Xr */
223 223 { NULL, posts_text }, /* %A */
224 224 { NULL, posts_text }, /* %B */ /* FIXME: can be used outside Rs/Re. */
225 225 { NULL, posts_text }, /* %D */
226 226 { NULL, posts_text }, /* %I */
227 227 { NULL, posts_text }, /* %J */
228 228 { NULL, posts_text }, /* %N */
229 229 { NULL, posts_text }, /* %O */
230 230 { NULL, posts_text }, /* %P */
231 231 { NULL, posts_text }, /* %R */
232 232 { NULL, posts_text }, /* %T */ /* FIXME: can be used outside Rs/Re. */
233 233 { NULL, posts_text }, /* %V */
234 234 { NULL, NULL }, /* Ac */
235 235 { NULL, NULL }, /* Ao */
236 236 { NULL, NULL }, /* Aq */
237 237 { NULL, posts_at }, /* At */
238 238 { NULL, NULL }, /* Bc */
239 239 { NULL, posts_bf }, /* Bf */
240 240 { NULL, NULL }, /* Bo */
241 241 { NULL, NULL }, /* Bq */
242 242 { NULL, NULL }, /* Bsx */
243 243 { NULL, posts_bx }, /* Bx */
244 244 { NULL, posts_bool }, /* Db */
245 245 { NULL, NULL }, /* Dc */
246 246 { NULL, NULL }, /* Do */
247 247 { NULL, NULL }, /* Dq */
248 248 { NULL, NULL }, /* Ec */
249 249 { NULL, NULL }, /* Ef */
250 250 { NULL, NULL }, /* Em */
251 251 { NULL, NULL }, /* Eo */
252 252 { NULL, NULL }, /* Fx */
253 253 { NULL, NULL }, /* Ms */
254 254 { NULL, posts_notext }, /* No */
255 255 { NULL, posts_ns }, /* Ns */
256 256 { NULL, NULL }, /* Nx */
257 257 { NULL, NULL }, /* Ox */
258 258 { NULL, NULL }, /* Pc */
259 259 { NULL, posts_text1 }, /* Pf */
260 260 { NULL, NULL }, /* Po */
261 261 { NULL, NULL }, /* Pq */
262 262 { NULL, NULL }, /* Qc */
263 263 { NULL, NULL }, /* Ql */
264 264 { NULL, NULL }, /* Qo */
265 265 { NULL, NULL }, /* Qq */
266 266 { NULL, NULL }, /* Re */
267 267 { NULL, posts_rs }, /* Rs */
268 268 { NULL, NULL }, /* Sc */
269 269 { NULL, NULL }, /* So */
270 270 { NULL, NULL }, /* Sq */
271 271 { NULL, posts_bool }, /* Sm */
272 272 { NULL, NULL }, /* Sx */
273 273 { NULL, NULL }, /* Sy */
274 274 { NULL, NULL }, /* Tn */
275 275 { NULL, NULL }, /* Ux */
276 276 { NULL, NULL }, /* Xc */
277 277 { NULL, NULL }, /* Xo */
278 278 { NULL, posts_fo }, /* Fo */
279 279 { NULL, NULL }, /* Fc */
280 280 { NULL, NULL }, /* Oo */
281 281 { NULL, NULL }, /* Oc */
282 282 { NULL, posts_bk }, /* Bk */
283 283 { NULL, NULL }, /* Ek */
284 284 { NULL, posts_eoln }, /* Bt */
285 285 { NULL, NULL }, /* Hf */
286 286 { NULL, NULL }, /* Fr */
287 287 { NULL, posts_eoln }, /* Ud */
288 288 { NULL, posts_lb }, /* Lb */
289 289 { NULL, posts_notext }, /* Lp */
290 290 { NULL, NULL }, /* Lk */
291 291 { NULL, posts_defaults }, /* Mt */
292 292 { NULL, NULL }, /* Brq */
293 293 { NULL, NULL }, /* Bro */
294 294 { NULL, NULL }, /* Brc */
295 295 { NULL, posts_text }, /* %C */
296 296 { NULL, NULL }, /* Es */
297 297 { NULL, NULL }, /* En */
298 298 { NULL, NULL }, /* Dx */
299 299 { NULL, posts_text }, /* %Q */
300 300 { NULL, posts_notext }, /* br */
301 301 { pres_pp, posts_sp }, /* sp */
302 302 { NULL, posts_text1 }, /* %U */
303 303 { NULL, NULL }, /* Ta */
304 304 };
305 305
306 306 #define RSORD_MAX 14 /* Number of `Rs' blocks. */
307 307
308 308 static const enum mdoct rsord[RSORD_MAX] = {
309 309 MDOC__A,
310 310 MDOC__T,
311 311 MDOC__B,
312 312 MDOC__I,
313 313 MDOC__J,
314 314 MDOC__R,
315 315 MDOC__N,
316 316 MDOC__V,
317 317 MDOC__P,
318 318 MDOC__Q,
319 319 MDOC__D,
320 320 MDOC__O,
321 321 MDOC__C,
322 322 MDOC__U
323 323 };
324 324
325 325 static const char * const secnames[SEC__MAX] = {
326 326 NULL,
327 327 "NAME",
328 328 "LIBRARY",
329 329 "SYNOPSIS",
↓ open down ↓ |
329 lines elided |
↑ open up ↑ |
330 330 "DESCRIPTION",
331 331 "IMPLEMENTATION NOTES",
332 332 "RETURN VALUES",
333 333 "ENVIRONMENT",
334 334 "FILES",
335 335 "EXIT STATUS",
336 336 "EXAMPLES",
337 337 "DIAGNOSTICS",
338 338 "COMPATIBILITY",
339 339 "ERRORS",
340 + "ARCHITECTURE",
341 + "CODE SET INDEPENDENCE",
342 + "INTERFACE STABILITY",
343 + "MULTITHREADING LEVEL",
340 344 "SEE ALSO",
341 345 "STANDARDS",
342 346 "HISTORY",
343 347 "AUTHORS",
344 348 "CAVEATS",
345 349 "BUGS",
346 350 "SECURITY CONSIDERATIONS",
347 351 NULL
348 352 };
349 353
350 354 int
351 355 mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n)
352 356 {
353 357 v_pre *p;
354 358 int line, pos;
355 359 char *tp;
356 360
357 361 switch (n->type) {
358 362 case (MDOC_TEXT):
359 363 tp = n->string;
360 364 line = n->line;
361 365 pos = n->pos;
362 366 check_text(mdoc, line, pos, tp);
363 367 /* FALLTHROUGH */
364 368 case (MDOC_TBL):
365 369 /* FALLTHROUGH */
366 370 case (MDOC_EQN):
367 371 /* FALLTHROUGH */
368 372 case (MDOC_ROOT):
369 373 return(1);
370 374 default:
371 375 break;
372 376 }
373 377
374 378 check_args(mdoc, n);
375 379
376 380 if (NULL == mdoc_valids[n->tok].pre)
377 381 return(1);
378 382 for (p = mdoc_valids[n->tok].pre; *p; p++)
379 383 if ( ! (*p)(mdoc, n))
380 384 return(0);
381 385 return(1);
382 386 }
383 387
384 388
385 389 int
386 390 mdoc_valid_post(struct mdoc *mdoc)
387 391 {
388 392 v_post *p;
389 393
390 394 if (MDOC_VALID & mdoc->last->flags)
391 395 return(1);
392 396 mdoc->last->flags |= MDOC_VALID;
393 397
394 398 switch (mdoc->last->type) {
395 399 case (MDOC_TEXT):
396 400 /* FALLTHROUGH */
397 401 case (MDOC_EQN):
398 402 /* FALLTHROUGH */
399 403 case (MDOC_TBL):
400 404 return(1);
401 405 case (MDOC_ROOT):
402 406 return(post_root(mdoc));
403 407 default:
404 408 break;
405 409 }
406 410
407 411 if (NULL == mdoc_valids[mdoc->last->tok].post)
408 412 return(1);
409 413 for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
410 414 if ( ! (*p)(mdoc))
411 415 return(0);
412 416
413 417 return(1);
414 418 }
415 419
416 420 static int
417 421 check_count(struct mdoc *m, enum mdoc_type type,
418 422 enum check_lvl lvl, enum check_ineq ineq, int val)
419 423 {
420 424 const char *p;
421 425 enum mandocerr t;
422 426
423 427 if (m->last->type != type)
424 428 return(1);
425 429
426 430 switch (ineq) {
427 431 case (CHECK_LT):
428 432 p = "less than ";
429 433 if (m->last->nchild < val)
430 434 return(1);
431 435 break;
432 436 case (CHECK_GT):
433 437 p = "more than ";
434 438 if (m->last->nchild > val)
435 439 return(1);
436 440 break;
437 441 case (CHECK_EQ):
438 442 p = "";
439 443 if (val == m->last->nchild)
440 444 return(1);
441 445 break;
442 446 default:
443 447 abort();
444 448 /* NOTREACHED */
445 449 }
446 450
447 451 t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT;
448 452 mandoc_vmsg(t, m->parse, m->last->line, m->last->pos,
449 453 "want %s%d children (have %d)",
450 454 p, val, m->last->nchild);
451 455 return(1);
452 456 }
453 457
454 458 static int
455 459 berr_ge1(POST_ARGS)
456 460 {
457 461
458 462 return(check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0));
459 463 }
460 464
461 465 static int
462 466 bwarn_ge1(POST_ARGS)
463 467 {
464 468 return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0));
465 469 }
466 470
467 471 static int
468 472 ewarn_eq0(POST_ARGS)
469 473 {
470 474 return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0));
471 475 }
472 476
473 477 static int
474 478 ewarn_eq1(POST_ARGS)
475 479 {
476 480 return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1));
477 481 }
478 482
479 483 static int
480 484 ewarn_ge1(POST_ARGS)
481 485 {
482 486 return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0));
483 487 }
484 488
485 489 static int
486 490 ewarn_le1(POST_ARGS)
487 491 {
488 492 return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2));
489 493 }
490 494
491 495 static int
492 496 hwarn_eq0(POST_ARGS)
493 497 {
494 498 return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0));
495 499 }
496 500
497 501 static int
498 502 hwarn_eq1(POST_ARGS)
499 503 {
500 504 return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1));
501 505 }
502 506
503 507 static int
504 508 hwarn_ge1(POST_ARGS)
505 509 {
506 510 return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0));
507 511 }
508 512
509 513 static int
510 514 hwarn_le1(POST_ARGS)
511 515 {
512 516 return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_LT, 2));
513 517 }
514 518
515 519 static void
516 520 check_args(struct mdoc *m, struct mdoc_node *n)
517 521 {
518 522 int i;
519 523
520 524 if (NULL == n->args)
521 525 return;
522 526
523 527 assert(n->args->argc);
524 528 for (i = 0; i < (int)n->args->argc; i++)
525 529 check_argv(m, n, &n->args->argv[i]);
526 530 }
527 531
528 532 static void
529 533 check_argv(struct mdoc *m, struct mdoc_node *n, struct mdoc_argv *v)
530 534 {
531 535 int i;
532 536
533 537 for (i = 0; i < (int)v->sz; i++)
534 538 check_text(m, v->line, v->pos, v->value[i]);
535 539
536 540 /* FIXME: move to post_std(). */
537 541
538 542 if (MDOC_Std == v->arg)
539 543 if ( ! (v->sz || m->meta.name))
540 544 mdoc_nmsg(m, n, MANDOCERR_NONAME);
541 545 }
542 546
543 547 static void
544 548 check_text(struct mdoc *m, int ln, int pos, char *p)
545 549 {
546 550 char *cp;
547 551
548 552 if (MDOC_LITERAL & m->flags)
549 553 return;
550 554
551 555 for (cp = p; NULL != (p = strchr(p, '\t')); p++)
552 556 mdoc_pmsg(m, ln, pos + (int)(p - cp), MANDOCERR_BADTAB);
553 557 }
554 558
555 559 static int
556 560 check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t)
557 561 {
558 562
559 563 assert(n->parent);
560 564 if ((MDOC_ROOT == t || tok == n->parent->tok) &&
561 565 (t == n->parent->type))
562 566 return(1);
563 567
564 568 mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, n->line,
565 569 n->pos, "want parent %s", MDOC_ROOT == t ?
566 570 "<root>" : mdoc_macronames[tok]);
567 571 return(0);
568 572 }
569 573
570 574
571 575 static int
572 576 pre_display(PRE_ARGS)
573 577 {
574 578 struct mdoc_node *node;
575 579
576 580 if (MDOC_BLOCK != n->type)
577 581 return(1);
578 582
579 583 for (node = mdoc->last->parent; node; node = node->parent)
580 584 if (MDOC_BLOCK == node->type)
581 585 if (MDOC_Bd == node->tok)
582 586 break;
583 587
584 588 if (node)
585 589 mdoc_nmsg(mdoc, n, MANDOCERR_NESTEDDISP);
586 590
587 591 return(1);
588 592 }
589 593
590 594
591 595 static int
592 596 pre_bl(PRE_ARGS)
593 597 {
594 598 int i, comp, dup;
595 599 const char *offs, *width;
596 600 enum mdoc_list lt;
597 601 struct mdoc_node *np;
598 602
599 603 if (MDOC_BLOCK != n->type) {
600 604 if (ENDBODY_NOT != n->end) {
601 605 assert(n->pending);
602 606 np = n->pending->parent;
603 607 } else
604 608 np = n->parent;
605 609
606 610 assert(np);
607 611 assert(MDOC_BLOCK == np->type);
608 612 assert(MDOC_Bl == np->tok);
609 613 return(1);
610 614 }
611 615
612 616 /*
613 617 * First figure out which kind of list to use: bind ourselves to
614 618 * the first mentioned list type and warn about any remaining
615 619 * ones. If we find no list type, we default to LIST_item.
616 620 */
617 621
618 622 /* LINTED */
619 623 for (i = 0; n->args && i < (int)n->args->argc; i++) {
620 624 lt = LIST__NONE;
621 625 dup = comp = 0;
622 626 width = offs = NULL;
623 627 switch (n->args->argv[i].arg) {
624 628 /* Set list types. */
625 629 case (MDOC_Bullet):
626 630 lt = LIST_bullet;
627 631 break;
628 632 case (MDOC_Dash):
629 633 lt = LIST_dash;
630 634 break;
631 635 case (MDOC_Enum):
632 636 lt = LIST_enum;
633 637 break;
634 638 case (MDOC_Hyphen):
635 639 lt = LIST_hyphen;
636 640 break;
637 641 case (MDOC_Item):
638 642 lt = LIST_item;
639 643 break;
640 644 case (MDOC_Tag):
641 645 lt = LIST_tag;
642 646 break;
643 647 case (MDOC_Diag):
644 648 lt = LIST_diag;
645 649 break;
646 650 case (MDOC_Hang):
647 651 lt = LIST_hang;
648 652 break;
649 653 case (MDOC_Ohang):
650 654 lt = LIST_ohang;
651 655 break;
652 656 case (MDOC_Inset):
653 657 lt = LIST_inset;
654 658 break;
655 659 case (MDOC_Column):
656 660 lt = LIST_column;
657 661 break;
658 662 /* Set list arguments. */
659 663 case (MDOC_Compact):
660 664 dup = n->norm->Bl.comp;
661 665 comp = 1;
662 666 break;
663 667 case (MDOC_Width):
664 668 /* NB: this can be empty! */
665 669 if (n->args->argv[i].sz) {
666 670 width = n->args->argv[i].value[0];
667 671 dup = (NULL != n->norm->Bl.width);
668 672 break;
669 673 }
670 674 mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
671 675 break;
672 676 case (MDOC_Offset):
673 677 /* NB: this can be empty! */
674 678 if (n->args->argv[i].sz) {
675 679 offs = n->args->argv[i].value[0];
676 680 dup = (NULL != n->norm->Bl.offs);
677 681 break;
678 682 }
679 683 mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
680 684 break;
681 685 default:
682 686 continue;
683 687 }
684 688
685 689 /* Check: duplicate auxiliary arguments. */
686 690
687 691 if (dup)
688 692 mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP);
689 693
690 694 if (comp && ! dup)
691 695 n->norm->Bl.comp = comp;
692 696 if (offs && ! dup)
693 697 n->norm->Bl.offs = offs;
694 698 if (width && ! dup)
695 699 n->norm->Bl.width = width;
696 700
697 701 /* Check: multiple list types. */
698 702
699 703 if (LIST__NONE != lt && n->norm->Bl.type != LIST__NONE)
700 704 mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP);
701 705
702 706 /* Assign list type. */
703 707
704 708 if (LIST__NONE != lt && n->norm->Bl.type == LIST__NONE) {
705 709 n->norm->Bl.type = lt;
706 710 /* Set column information, too. */
707 711 if (LIST_column == lt) {
708 712 n->norm->Bl.ncols =
709 713 n->args->argv[i].sz;
710 714 n->norm->Bl.cols = (void *)
711 715 n->args->argv[i].value;
712 716 }
713 717 }
714 718
715 719 /* The list type should come first. */
716 720
717 721 if (n->norm->Bl.type == LIST__NONE)
718 722 if (n->norm->Bl.width ||
719 723 n->norm->Bl.offs ||
720 724 n->norm->Bl.comp)
721 725 mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST);
722 726
723 727 continue;
724 728 }
725 729
726 730 /* Allow lists to default to LIST_item. */
727 731
728 732 if (LIST__NONE == n->norm->Bl.type) {
729 733 mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE);
730 734 n->norm->Bl.type = LIST_item;
731 735 }
732 736
733 737 /*
734 738 * Validate the width field. Some list types don't need width
735 739 * types and should be warned about them. Others should have it
736 740 * and must also be warned.
737 741 */
738 742
739 743 switch (n->norm->Bl.type) {
740 744 case (LIST_tag):
741 745 if (n->norm->Bl.width)
742 746 break;
743 747 mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG);
744 748 break;
745 749 case (LIST_column):
746 750 /* FALLTHROUGH */
747 751 case (LIST_diag):
748 752 /* FALLTHROUGH */
749 753 case (LIST_ohang):
750 754 /* FALLTHROUGH */
751 755 case (LIST_inset):
752 756 /* FALLTHROUGH */
753 757 case (LIST_item):
754 758 if (n->norm->Bl.width)
755 759 mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
756 760 break;
757 761 default:
758 762 break;
759 763 }
760 764
761 765 return(1);
762 766 }
763 767
764 768
765 769 static int
766 770 pre_bd(PRE_ARGS)
767 771 {
768 772 int i, dup, comp;
769 773 enum mdoc_disp dt;
770 774 const char *offs;
771 775 struct mdoc_node *np;
772 776
773 777 if (MDOC_BLOCK != n->type) {
774 778 if (ENDBODY_NOT != n->end) {
775 779 assert(n->pending);
776 780 np = n->pending->parent;
777 781 } else
778 782 np = n->parent;
779 783
780 784 assert(np);
781 785 assert(MDOC_BLOCK == np->type);
782 786 assert(MDOC_Bd == np->tok);
783 787 return(1);
784 788 }
785 789
786 790 /* LINTED */
787 791 for (i = 0; n->args && i < (int)n->args->argc; i++) {
788 792 dt = DISP__NONE;
789 793 dup = comp = 0;
790 794 offs = NULL;
791 795
792 796 switch (n->args->argv[i].arg) {
793 797 case (MDOC_Centred):
794 798 dt = DISP_centred;
795 799 break;
796 800 case (MDOC_Ragged):
797 801 dt = DISP_ragged;
798 802 break;
799 803 case (MDOC_Unfilled):
800 804 dt = DISP_unfilled;
801 805 break;
802 806 case (MDOC_Filled):
803 807 dt = DISP_filled;
804 808 break;
805 809 case (MDOC_Literal):
806 810 dt = DISP_literal;
807 811 break;
808 812 case (MDOC_File):
809 813 mdoc_nmsg(mdoc, n, MANDOCERR_BADDISP);
810 814 return(0);
811 815 case (MDOC_Offset):
812 816 /* NB: this can be empty! */
813 817 if (n->args->argv[i].sz) {
814 818 offs = n->args->argv[i].value[0];
815 819 dup = (NULL != n->norm->Bd.offs);
816 820 break;
817 821 }
818 822 mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
819 823 break;
820 824 case (MDOC_Compact):
821 825 comp = 1;
822 826 dup = n->norm->Bd.comp;
823 827 break;
824 828 default:
825 829 abort();
826 830 /* NOTREACHED */
827 831 }
828 832
829 833 /* Check whether we have duplicates. */
830 834
831 835 if (dup)
832 836 mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP);
833 837
834 838 /* Make our auxiliary assignments. */
835 839
836 840 if (offs && ! dup)
837 841 n->norm->Bd.offs = offs;
838 842 if (comp && ! dup)
839 843 n->norm->Bd.comp = comp;
840 844
841 845 /* Check whether a type has already been assigned. */
842 846
843 847 if (DISP__NONE != dt && n->norm->Bd.type != DISP__NONE)
844 848 mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP);
845 849
846 850 /* Make our type assignment. */
847 851
848 852 if (DISP__NONE != dt && n->norm->Bd.type == DISP__NONE)
849 853 n->norm->Bd.type = dt;
850 854 }
851 855
852 856 if (DISP__NONE == n->norm->Bd.type) {
853 857 mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE);
854 858 n->norm->Bd.type = DISP_ragged;
855 859 }
856 860
857 861 return(1);
858 862 }
859 863
860 864
861 865 static int
862 866 pre_ss(PRE_ARGS)
863 867 {
864 868
865 869 if (MDOC_BLOCK != n->type)
866 870 return(1);
867 871 return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
868 872 }
869 873
870 874
871 875 static int
872 876 pre_sh(PRE_ARGS)
873 877 {
874 878
875 879 if (MDOC_BLOCK != n->type)
876 880 return(1);
877 881
878 882 roff_regunset(mdoc->roff, REG_nS);
879 883 return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT));
880 884 }
881 885
882 886
883 887 static int
884 888 pre_it(PRE_ARGS)
885 889 {
886 890
887 891 if (MDOC_BLOCK != n->type)
888 892 return(1);
889 893
890 894 return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
891 895 }
892 896
893 897
894 898 static int
895 899 pre_an(PRE_ARGS)
896 900 {
897 901 int i;
898 902
899 903 if (NULL == n->args)
900 904 return(1);
901 905
902 906 for (i = 1; i < (int)n->args->argc; i++)
903 907 mdoc_pmsg(mdoc, n->args->argv[i].line,
904 908 n->args->argv[i].pos, MANDOCERR_IGNARGV);
905 909
906 910 if (MDOC_Split == n->args->argv[0].arg)
907 911 n->norm->An.auth = AUTH_split;
908 912 else if (MDOC_Nosplit == n->args->argv[0].arg)
909 913 n->norm->An.auth = AUTH_nosplit;
910 914 else
911 915 abort();
912 916
913 917 return(1);
914 918 }
915 919
916 920 static int
917 921 pre_std(PRE_ARGS)
918 922 {
919 923
920 924 if (n->args && 1 == n->args->argc)
921 925 if (MDOC_Std == n->args->argv[0].arg)
922 926 return(1);
923 927
924 928 mdoc_nmsg(mdoc, n, MANDOCERR_NOARGV);
925 929 return(1);
926 930 }
927 931
928 932 static int
929 933 pre_dt(PRE_ARGS)
930 934 {
931 935
932 936 if (NULL == mdoc->meta.date || mdoc->meta.os)
933 937 mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
934 938
935 939 if (mdoc->meta.title)
936 940 mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
937 941
938 942 return(1);
939 943 }
940 944
941 945 static int
942 946 pre_os(PRE_ARGS)
943 947 {
944 948
945 949 if (NULL == mdoc->meta.title || NULL == mdoc->meta.date)
946 950 mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
947 951
948 952 if (mdoc->meta.os)
949 953 mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
950 954
951 955 return(1);
952 956 }
953 957
954 958 static int
955 959 pre_dd(PRE_ARGS)
956 960 {
957 961
958 962 if (mdoc->meta.title || mdoc->meta.os)
959 963 mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
960 964
961 965 if (mdoc->meta.date)
962 966 mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
963 967
964 968 return(1);
965 969 }
966 970
967 971
968 972 static int
969 973 post_bf(POST_ARGS)
970 974 {
971 975 struct mdoc_node *np;
972 976 enum mdocargt arg;
973 977
974 978 /*
975 979 * Unlike other data pointers, these are "housed" by the HEAD
976 980 * element, which contains the goods.
977 981 */
978 982
979 983 if (MDOC_HEAD != mdoc->last->type) {
980 984 if (ENDBODY_NOT != mdoc->last->end) {
981 985 assert(mdoc->last->pending);
982 986 np = mdoc->last->pending->parent->head;
983 987 } else if (MDOC_BLOCK != mdoc->last->type) {
984 988 np = mdoc->last->parent->head;
985 989 } else
986 990 np = mdoc->last->head;
987 991
988 992 assert(np);
989 993 assert(MDOC_HEAD == np->type);
990 994 assert(MDOC_Bf == np->tok);
991 995 return(1);
992 996 }
993 997
994 998 np = mdoc->last;
995 999 assert(MDOC_BLOCK == np->parent->type);
996 1000 assert(MDOC_Bf == np->parent->tok);
997 1001
998 1002 /*
999 1003 * Cannot have both argument and parameter.
1000 1004 * If neither is specified, let it through with a warning.
1001 1005 */
1002 1006
1003 1007 if (np->parent->args && np->child) {
1004 1008 mdoc_nmsg(mdoc, np, MANDOCERR_SYNTARGVCOUNT);
1005 1009 return(0);
1006 1010 } else if (NULL == np->parent->args && NULL == np->child) {
1007 1011 mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE);
1008 1012 return(1);
1009 1013 }
1010 1014
1011 1015 /* Extract argument into data. */
1012 1016
1013 1017 if (np->parent->args) {
1014 1018 arg = np->parent->args->argv[0].arg;
1015 1019 if (MDOC_Emphasis == arg)
1016 1020 np->norm->Bf.font = FONT_Em;
1017 1021 else if (MDOC_Literal == arg)
1018 1022 np->norm->Bf.font = FONT_Li;
1019 1023 else if (MDOC_Symbolic == arg)
1020 1024 np->norm->Bf.font = FONT_Sy;
1021 1025 else
1022 1026 abort();
1023 1027 return(1);
1024 1028 }
1025 1029
1026 1030 /* Extract parameter into data. */
1027 1031
1028 1032 if (0 == strcmp(np->child->string, "Em"))
1029 1033 np->norm->Bf.font = FONT_Em;
1030 1034 else if (0 == strcmp(np->child->string, "Li"))
1031 1035 np->norm->Bf.font = FONT_Li;
1032 1036 else if (0 == strcmp(np->child->string, "Sy"))
1033 1037 np->norm->Bf.font = FONT_Sy;
1034 1038 else
1035 1039 mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE);
1036 1040
1037 1041 return(1);
1038 1042 }
1039 1043
1040 1044 static int
1041 1045 post_lb(POST_ARGS)
1042 1046 {
1043 1047 const char *p;
1044 1048 char *buf;
1045 1049 size_t sz;
1046 1050
1047 1051 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
1048 1052
1049 1053 assert(mdoc->last->child);
1050 1054 assert(MDOC_TEXT == mdoc->last->child->type);
1051 1055
1052 1056 p = mdoc_a2lib(mdoc->last->child->string);
1053 1057
1054 1058 /* If lookup ok, replace with table value. */
1055 1059
1056 1060 if (p) {
1057 1061 free(mdoc->last->child->string);
1058 1062 mdoc->last->child->string = mandoc_strdup(p);
1059 1063 return(1);
1060 1064 }
1061 1065
1062 1066 /* If not, use "library ``xxxx''. */
1063 1067
1064 1068 sz = strlen(mdoc->last->child->string) +
1065 1069 2 + strlen("\\(lqlibrary\\(rq");
1066 1070 buf = mandoc_malloc(sz);
1067 1071 snprintf(buf, sz, "library \\(lq%s\\(rq",
1068 1072 mdoc->last->child->string);
1069 1073 free(mdoc->last->child->string);
1070 1074 mdoc->last->child->string = buf;
1071 1075 return(1);
1072 1076 }
1073 1077
1074 1078 static int
1075 1079 post_eoln(POST_ARGS)
1076 1080 {
1077 1081
1078 1082 if (mdoc->last->child)
1079 1083 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST);
1080 1084 return(1);
1081 1085 }
1082 1086
1083 1087
1084 1088 static int
1085 1089 post_vt(POST_ARGS)
1086 1090 {
1087 1091 const struct mdoc_node *n;
1088 1092
1089 1093 /*
1090 1094 * The Vt macro comes in both ELEM and BLOCK form, both of which
1091 1095 * have different syntaxes (yet more context-sensitive
1092 1096 * behaviour). ELEM types must have a child, which is already
1093 1097 * guaranteed by the in_line parsing routine; BLOCK types,
1094 1098 * specifically the BODY, should only have TEXT children.
1095 1099 */
1096 1100
1097 1101 if (MDOC_BODY != mdoc->last->type)
1098 1102 return(1);
1099 1103
1100 1104 for (n = mdoc->last->child; n; n = n->next)
1101 1105 if (MDOC_TEXT != n->type)
1102 1106 mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
1103 1107
1104 1108 return(1);
1105 1109 }
1106 1110
1107 1111
1108 1112 static int
1109 1113 post_nm(POST_ARGS)
1110 1114 {
1111 1115 char buf[BUFSIZ];
1112 1116 int c;
1113 1117
1114 1118 /* If no child specified, make sure we have the meta name. */
1115 1119
1116 1120 if (NULL == mdoc->last->child && NULL == mdoc->meta.name) {
1117 1121 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME);
1118 1122 return(1);
1119 1123 } else if (mdoc->meta.name)
1120 1124 return(1);
1121 1125
1122 1126 /* If no meta name, set it from the child. */
1123 1127
1124 1128 buf[0] = '\0';
1125 1129 if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) {
1126 1130 mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
1127 1131 return(0);
1128 1132 }
1129 1133
1130 1134 assert(c);
1131 1135 mdoc->meta.name = mandoc_strdup(buf);
1132 1136 return(1);
1133 1137 }
1134 1138
1135 1139 static int
1136 1140 post_literal(POST_ARGS)
1137 1141 {
1138 1142
1139 1143 /*
1140 1144 * The `Dl' (note "el" not "one") and `Bd' macros unset the
1141 1145 * MDOC_LITERAL flag as they leave. Note that `Bd' only sets
1142 1146 * this in literal mode, but it doesn't hurt to just switch it
1143 1147 * off in general since displays can't be nested.
1144 1148 */
1145 1149
1146 1150 if (MDOC_BODY == mdoc->last->type)
1147 1151 mdoc->flags &= ~MDOC_LITERAL;
1148 1152
1149 1153 return(1);
1150 1154 }
1151 1155
1152 1156 static int
1153 1157 post_defaults(POST_ARGS)
1154 1158 {
1155 1159 struct mdoc_node *nn;
1156 1160
1157 1161 /*
1158 1162 * The `Ar' defaults to "file ..." if no value is provided as an
1159 1163 * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
1160 1164 * gets an empty string.
1161 1165 */
1162 1166
1163 1167 if (mdoc->last->child)
1164 1168 return(1);
1165 1169
1166 1170 nn = mdoc->last;
1167 1171 mdoc->next = MDOC_NEXT_CHILD;
1168 1172
1169 1173 switch (nn->tok) {
1170 1174 case (MDOC_Ar):
1171 1175 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file"))
1172 1176 return(0);
1173 1177 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "..."))
1174 1178 return(0);
1175 1179 break;
1176 1180 case (MDOC_At):
1177 1181 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "AT&T"))
1178 1182 return(0);
1179 1183 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "UNIX"))
1180 1184 return(0);
1181 1185 break;
1182 1186 case (MDOC_Li):
1183 1187 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, ""))
1184 1188 return(0);
1185 1189 break;
1186 1190 case (MDOC_Pa):
1187 1191 /* FALLTHROUGH */
1188 1192 case (MDOC_Mt):
1189 1193 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~"))
1190 1194 return(0);
1191 1195 break;
1192 1196 default:
1193 1197 abort();
1194 1198 /* NOTREACHED */
1195 1199 }
1196 1200
1197 1201 mdoc->last = nn;
1198 1202 return(1);
1199 1203 }
1200 1204
1201 1205 static int
1202 1206 post_at(POST_ARGS)
1203 1207 {
1204 1208 const char *p, *q;
1205 1209 char *buf;
1206 1210 size_t sz;
1207 1211
1208 1212 /*
1209 1213 * If we have a child, look it up in the standard keys. If a
1210 1214 * key exist, use that instead of the child; if it doesn't,
1211 1215 * prefix "AT&T UNIX " to the existing data.
1212 1216 */
1213 1217
1214 1218 if (NULL == mdoc->last->child)
1215 1219 return(1);
1216 1220
1217 1221 assert(MDOC_TEXT == mdoc->last->child->type);
1218 1222 p = mdoc_a2att(mdoc->last->child->string);
1219 1223
1220 1224 if (p) {
1221 1225 free(mdoc->last->child->string);
1222 1226 mdoc->last->child->string = mandoc_strdup(p);
1223 1227 } else {
1224 1228 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT);
1225 1229 p = "AT&T UNIX ";
1226 1230 q = mdoc->last->child->string;
1227 1231 sz = strlen(p) + strlen(q) + 1;
1228 1232 buf = mandoc_malloc(sz);
1229 1233 strlcpy(buf, p, sz);
1230 1234 strlcat(buf, q, sz);
1231 1235 free(mdoc->last->child->string);
1232 1236 mdoc->last->child->string = buf;
1233 1237 }
1234 1238
1235 1239 return(1);
1236 1240 }
1237 1241
1238 1242 static int
1239 1243 post_an(POST_ARGS)
1240 1244 {
1241 1245 struct mdoc_node *np;
1242 1246
1243 1247 np = mdoc->last;
1244 1248 if (AUTH__NONE == np->norm->An.auth) {
1245 1249 if (0 == np->child)
1246 1250 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0);
1247 1251 } else if (np->child)
1248 1252 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0);
1249 1253
1250 1254 return(1);
1251 1255 }
1252 1256
1253 1257
1254 1258 static int
1255 1259 post_it(POST_ARGS)
1256 1260 {
1257 1261 int i, cols;
1258 1262 enum mdoc_list lt;
1259 1263 struct mdoc_node *n, *c;
1260 1264 enum mandocerr er;
1261 1265
1262 1266 if (MDOC_BLOCK != mdoc->last->type)
1263 1267 return(1);
1264 1268
1265 1269 n = mdoc->last->parent->parent;
1266 1270 lt = n->norm->Bl.type;
1267 1271
1268 1272 if (LIST__NONE == lt) {
1269 1273 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE);
1270 1274 return(1);
1271 1275 }
1272 1276
1273 1277 switch (lt) {
1274 1278 case (LIST_tag):
1275 1279 if (mdoc->last->head->child)
1276 1280 break;
1277 1281 /* FIXME: give this a dummy value. */
1278 1282 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS);
1279 1283 break;
1280 1284 case (LIST_hang):
1281 1285 /* FALLTHROUGH */
1282 1286 case (LIST_ohang):
1283 1287 /* FALLTHROUGH */
1284 1288 case (LIST_inset):
1285 1289 /* FALLTHROUGH */
1286 1290 case (LIST_diag):
1287 1291 if (NULL == mdoc->last->head->child)
1288 1292 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS);
1289 1293 break;
1290 1294 case (LIST_bullet):
1291 1295 /* FALLTHROUGH */
1292 1296 case (LIST_dash):
1293 1297 /* FALLTHROUGH */
1294 1298 case (LIST_enum):
1295 1299 /* FALLTHROUGH */
1296 1300 case (LIST_hyphen):
1297 1301 if (NULL == mdoc->last->body->child)
1298 1302 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY);
1299 1303 /* FALLTHROUGH */
1300 1304 case (LIST_item):
1301 1305 if (mdoc->last->head->child)
1302 1306 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST);
1303 1307 break;
1304 1308 case (LIST_column):
1305 1309 cols = (int)n->norm->Bl.ncols;
1306 1310
1307 1311 assert(NULL == mdoc->last->head->child);
1308 1312
1309 1313 if (NULL == mdoc->last->body->child)
1310 1314 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY);
1311 1315
1312 1316 for (i = 0, c = mdoc->last->child; c; c = c->next)
1313 1317 if (MDOC_BODY == c->type)
1314 1318 i++;
1315 1319
1316 1320 if (i < cols)
1317 1321 er = MANDOCERR_ARGCOUNT;
1318 1322 else if (i == cols || i == cols + 1)
1319 1323 break;
1320 1324 else
1321 1325 er = MANDOCERR_SYNTARGCOUNT;
1322 1326
1323 1327 mandoc_vmsg(er, mdoc->parse, mdoc->last->line,
1324 1328 mdoc->last->pos,
1325 1329 "columns == %d (have %d)", cols, i);
1326 1330 return(MANDOCERR_ARGCOUNT == er);
1327 1331 default:
1328 1332 break;
1329 1333 }
1330 1334
1331 1335 return(1);
1332 1336 }
1333 1337
1334 1338 static int
1335 1339 post_bl_block(POST_ARGS)
1336 1340 {
1337 1341 struct mdoc_node *n;
1338 1342
1339 1343 /*
1340 1344 * These are fairly complicated, so we've broken them into two
1341 1345 * functions. post_bl_block_tag() is called when a -tag is
1342 1346 * specified, but no -width (it must be guessed). The second
1343 1347 * when a -width is specified (macro indicators must be
1344 1348 * rewritten into real lengths).
1345 1349 */
1346 1350
1347 1351 n = mdoc->last;
1348 1352
1349 1353 if (LIST_tag == n->norm->Bl.type &&
1350 1354 NULL == n->norm->Bl.width) {
1351 1355 if ( ! post_bl_block_tag(mdoc))
1352 1356 return(0);
1353 1357 } else if (NULL != n->norm->Bl.width) {
1354 1358 if ( ! post_bl_block_width(mdoc))
1355 1359 return(0);
1356 1360 } else
1357 1361 return(1);
1358 1362
1359 1363 assert(n->norm->Bl.width);
1360 1364 return(1);
1361 1365 }
1362 1366
1363 1367 static int
1364 1368 post_bl_block_width(POST_ARGS)
1365 1369 {
1366 1370 size_t width;
1367 1371 int i;
1368 1372 enum mdoct tok;
1369 1373 struct mdoc_node *n;
1370 1374 char buf[NUMSIZ];
1371 1375
1372 1376 n = mdoc->last;
1373 1377
1374 1378 /*
1375 1379 * Calculate the real width of a list from the -width string,
1376 1380 * which may contain a macro (with a known default width), a
1377 1381 * literal string, or a scaling width.
1378 1382 *
1379 1383 * If the value to -width is a macro, then we re-write it to be
1380 1384 * the macro's width as set in share/tmac/mdoc/doc-common.
1381 1385 */
1382 1386
1383 1387 if (0 == strcmp(n->norm->Bl.width, "Ds"))
1384 1388 width = 6;
1385 1389 else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width)))
1386 1390 return(1);
1387 1391 else if (0 == (width = macro2len(tok))) {
1388 1392 mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH);
1389 1393 return(1);
1390 1394 }
1391 1395
1392 1396 /* The value already exists: free and reallocate it. */
1393 1397
1394 1398 assert(n->args);
1395 1399
1396 1400 for (i = 0; i < (int)n->args->argc; i++)
1397 1401 if (MDOC_Width == n->args->argv[i].arg)
1398 1402 break;
1399 1403
1400 1404 assert(i < (int)n->args->argc);
1401 1405
1402 1406 snprintf(buf, NUMSIZ, "%un", (unsigned int)width);
1403 1407 free(n->args->argv[i].value[0]);
1404 1408 n->args->argv[i].value[0] = mandoc_strdup(buf);
1405 1409
1406 1410 /* Set our width! */
1407 1411 n->norm->Bl.width = n->args->argv[i].value[0];
1408 1412 return(1);
1409 1413 }
1410 1414
1411 1415 static int
1412 1416 post_bl_block_tag(POST_ARGS)
1413 1417 {
1414 1418 struct mdoc_node *n, *nn;
1415 1419 size_t sz, ssz;
1416 1420 int i;
1417 1421 char buf[NUMSIZ];
1418 1422
1419 1423 /*
1420 1424 * Calculate the -width for a `Bl -tag' list if it hasn't been
1421 1425 * provided. Uses the first head macro. NOTE AGAIN: this is
1422 1426 * ONLY if the -width argument has NOT been provided. See
1423 1427 * post_bl_block_width() for converting the -width string.
1424 1428 */
1425 1429
1426 1430 sz = 10;
1427 1431 n = mdoc->last;
1428 1432
1429 1433 for (nn = n->body->child; nn; nn = nn->next) {
1430 1434 if (MDOC_It != nn->tok)
1431 1435 continue;
1432 1436
1433 1437 assert(MDOC_BLOCK == nn->type);
1434 1438 nn = nn->head->child;
1435 1439
1436 1440 if (nn == NULL)
1437 1441 break;
1438 1442
1439 1443 if (MDOC_TEXT == nn->type) {
1440 1444 sz = strlen(nn->string) + 1;
1441 1445 break;
1442 1446 }
1443 1447
1444 1448 if (0 != (ssz = macro2len(nn->tok)))
1445 1449 sz = ssz;
1446 1450
1447 1451 break;
1448 1452 }
1449 1453
1450 1454 /* Defaults to ten ens. */
1451 1455
1452 1456 snprintf(buf, NUMSIZ, "%un", (unsigned int)sz);
1453 1457
1454 1458 /*
1455 1459 * We have to dynamically add this to the macro's argument list.
1456 1460 * We're guaranteed that a MDOC_Width doesn't already exist.
1457 1461 */
1458 1462
1459 1463 assert(n->args);
1460 1464 i = (int)(n->args->argc)++;
1461 1465
1462 1466 n->args->argv = mandoc_realloc(n->args->argv,
1463 1467 n->args->argc * sizeof(struct mdoc_argv));
1464 1468
1465 1469 n->args->argv[i].arg = MDOC_Width;
1466 1470 n->args->argv[i].line = n->line;
1467 1471 n->args->argv[i].pos = n->pos;
1468 1472 n->args->argv[i].sz = 1;
1469 1473 n->args->argv[i].value = mandoc_malloc(sizeof(char *));
1470 1474 n->args->argv[i].value[0] = mandoc_strdup(buf);
1471 1475
1472 1476 /* Set our width! */
1473 1477 n->norm->Bl.width = n->args->argv[i].value[0];
1474 1478 return(1);
1475 1479 }
1476 1480
1477 1481
1478 1482 static int
1479 1483 post_bl_head(POST_ARGS)
1480 1484 {
1481 1485 struct mdoc_node *np, *nn, *nnp;
1482 1486 int i, j;
1483 1487
1484 1488 if (LIST_column != mdoc->last->norm->Bl.type)
1485 1489 /* FIXME: this should be ERROR class... */
1486 1490 return(hwarn_eq0(mdoc));
1487 1491
1488 1492 /*
1489 1493 * Convert old-style lists, where the column width specifiers
1490 1494 * trail as macro parameters, to the new-style ("normal-form")
1491 1495 * lists where they're argument values following -column.
1492 1496 */
1493 1497
1494 1498 /* First, disallow both types and allow normal-form. */
1495 1499
1496 1500 /*
1497 1501 * TODO: technically, we can accept both and just merge the two
1498 1502 * lists, but I'll leave that for another day.
1499 1503 */
1500 1504
1501 1505 if (mdoc->last->norm->Bl.ncols && mdoc->last->nchild) {
1502 1506 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_COLUMNS);
1503 1507 return(0);
1504 1508 } else if (NULL == mdoc->last->child)
1505 1509 return(1);
1506 1510
1507 1511 np = mdoc->last->parent;
1508 1512 assert(np->args);
1509 1513
1510 1514 for (j = 0; j < (int)np->args->argc; j++)
1511 1515 if (MDOC_Column == np->args->argv[j].arg)
1512 1516 break;
1513 1517
1514 1518 assert(j < (int)np->args->argc);
1515 1519 assert(0 == np->args->argv[j].sz);
1516 1520
1517 1521 /*
1518 1522 * Accommodate for new-style groff column syntax. Shuffle the
1519 1523 * child nodes, all of which must be TEXT, as arguments for the
1520 1524 * column field. Then, delete the head children.
1521 1525 */
1522 1526
1523 1527 np->args->argv[j].sz = (size_t)mdoc->last->nchild;
1524 1528 np->args->argv[j].value = mandoc_malloc
1525 1529 ((size_t)mdoc->last->nchild * sizeof(char *));
1526 1530
1527 1531 mdoc->last->norm->Bl.ncols = np->args->argv[j].sz;
1528 1532 mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value;
1529 1533
1530 1534 for (i = 0, nn = mdoc->last->child; nn; i++) {
1531 1535 np->args->argv[j].value[i] = nn->string;
1532 1536 nn->string = NULL;
1533 1537 nnp = nn;
1534 1538 nn = nn->next;
1535 1539 mdoc_node_delete(NULL, nnp);
1536 1540 }
1537 1541
1538 1542 mdoc->last->nchild = 0;
1539 1543 mdoc->last->child = NULL;
1540 1544
1541 1545 return(1);
1542 1546 }
1543 1547
1544 1548 static int
1545 1549 post_bl(POST_ARGS)
1546 1550 {
1547 1551 struct mdoc_node *n;
1548 1552
1549 1553 if (MDOC_HEAD == mdoc->last->type)
1550 1554 return(post_bl_head(mdoc));
1551 1555 if (MDOC_BLOCK == mdoc->last->type)
1552 1556 return(post_bl_block(mdoc));
1553 1557 if (MDOC_BODY != mdoc->last->type)
1554 1558 return(1);
1555 1559
1556 1560 for (n = mdoc->last->child; n; n = n->next) {
1557 1561 switch (n->tok) {
1558 1562 case (MDOC_Lp):
1559 1563 /* FALLTHROUGH */
1560 1564 case (MDOC_Pp):
1561 1565 mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
1562 1566 /* FALLTHROUGH */
1563 1567 case (MDOC_It):
1564 1568 /* FALLTHROUGH */
1565 1569 case (MDOC_Sm):
1566 1570 continue;
1567 1571 default:
1568 1572 break;
1569 1573 }
1570 1574
1571 1575 mdoc_nmsg(mdoc, n, MANDOCERR_SYNTCHILD);
1572 1576 return(0);
1573 1577 }
1574 1578
1575 1579 return(1);
1576 1580 }
1577 1581
1578 1582 static int
1579 1583 ebool(struct mdoc *mdoc)
1580 1584 {
1581 1585
1582 1586 if (NULL == mdoc->last->child) {
1583 1587 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
1584 1588 mdoc_node_delete(mdoc, mdoc->last);
1585 1589 return(1);
1586 1590 }
1587 1591 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
1588 1592
1589 1593 assert(MDOC_TEXT == mdoc->last->child->type);
1590 1594
1591 1595 if (0 == strcmp(mdoc->last->child->string, "on"))
1592 1596 return(1);
1593 1597 if (0 == strcmp(mdoc->last->child->string, "off"))
1594 1598 return(1);
1595 1599
1596 1600 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL);
1597 1601 return(1);
1598 1602 }
1599 1603
1600 1604 static int
1601 1605 post_root(POST_ARGS)
1602 1606 {
1603 1607 int erc;
1604 1608 struct mdoc_node *n;
1605 1609
1606 1610 erc = 0;
1607 1611
1608 1612 /* Check that we have a finished prologue. */
1609 1613
1610 1614 if ( ! (MDOC_PBODY & mdoc->flags)) {
1611 1615 erc++;
1612 1616 mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG);
1613 1617 }
1614 1618
1615 1619 n = mdoc->first;
1616 1620 assert(n);
1617 1621
1618 1622 /* Check that we begin with a proper `Sh'. */
1619 1623
1620 1624 if (NULL == n->child) {
1621 1625 erc++;
1622 1626 mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY);
1623 1627 } else if (MDOC_BLOCK != n->child->type ||
1624 1628 MDOC_Sh != n->child->tok) {
1625 1629 erc++;
1626 1630 /* Can this be lifted? See rxdebug.1 for example. */
1627 1631 mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY);
1628 1632 }
1629 1633
1630 1634 return(erc ? 0 : 1);
1631 1635 }
1632 1636
1633 1637 static int
1634 1638 post_st(POST_ARGS)
1635 1639 {
1636 1640 struct mdoc_node *ch;
1637 1641 const char *p;
1638 1642
1639 1643 if (NULL == (ch = mdoc->last->child)) {
1640 1644 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
1641 1645 mdoc_node_delete(mdoc, mdoc->last);
1642 1646 return(1);
1643 1647 }
1644 1648
1645 1649 assert(MDOC_TEXT == ch->type);
1646 1650
1647 1651 if (NULL == (p = mdoc_a2st(ch->string))) {
1648 1652 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD);
1649 1653 mdoc_node_delete(mdoc, mdoc->last);
1650 1654 } else {
1651 1655 free(ch->string);
1652 1656 ch->string = mandoc_strdup(p);
1653 1657 }
1654 1658
1655 1659 return(1);
1656 1660 }
1657 1661
1658 1662 static int
1659 1663 post_rs(POST_ARGS)
1660 1664 {
1661 1665 struct mdoc_node *nn, *next, *prev;
1662 1666 int i, j;
1663 1667
1664 1668 switch (mdoc->last->type) {
1665 1669 case (MDOC_HEAD):
1666 1670 check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0);
1667 1671 return(1);
1668 1672 case (MDOC_BODY):
1669 1673 if (mdoc->last->child)
1670 1674 break;
1671 1675 check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0);
1672 1676 return(1);
1673 1677 default:
1674 1678 return(1);
1675 1679 }
1676 1680
1677 1681 /*
1678 1682 * Make sure only certain types of nodes are allowed within the
1679 1683 * the `Rs' body. Delete offending nodes and raise a warning.
1680 1684 * Do this before re-ordering for the sake of clarity.
1681 1685 */
1682 1686
1683 1687 next = NULL;
1684 1688 for (nn = mdoc->last->child; nn; nn = next) {
1685 1689 for (i = 0; i < RSORD_MAX; i++)
1686 1690 if (nn->tok == rsord[i])
1687 1691 break;
1688 1692
1689 1693 if (i < RSORD_MAX) {
1690 1694 if (MDOC__J == rsord[i] || MDOC__B == rsord[i])
1691 1695 mdoc->last->norm->Rs.quote_T++;
1692 1696 next = nn->next;
1693 1697 continue;
1694 1698 }
1695 1699
1696 1700 next = nn->next;
1697 1701 mdoc_nmsg(mdoc, nn, MANDOCERR_CHILD);
1698 1702 mdoc_node_delete(mdoc, nn);
1699 1703 }
1700 1704
1701 1705 /*
1702 1706 * Nothing to sort if only invalid nodes were found
1703 1707 * inside the `Rs' body.
1704 1708 */
1705 1709
1706 1710 if (NULL == mdoc->last->child)
1707 1711 return(1);
1708 1712
1709 1713 /*
1710 1714 * The full `Rs' block needs special handling to order the
1711 1715 * sub-elements according to `rsord'. Pick through each element
1712 1716 * and correctly order it. This is a insertion sort.
1713 1717 */
1714 1718
1715 1719 next = NULL;
1716 1720 for (nn = mdoc->last->child->next; nn; nn = next) {
1717 1721 /* Determine order of `nn'. */
1718 1722 for (i = 0; i < RSORD_MAX; i++)
1719 1723 if (rsord[i] == nn->tok)
1720 1724 break;
1721 1725
1722 1726 /*
1723 1727 * Remove `nn' from the chain. This somewhat
1724 1728 * repeats mdoc_node_unlink(), but since we're
1725 1729 * just re-ordering, there's no need for the
1726 1730 * full unlink process.
1727 1731 */
1728 1732
1729 1733 if (NULL != (next = nn->next))
1730 1734 next->prev = nn->prev;
1731 1735
1732 1736 if (NULL != (prev = nn->prev))
1733 1737 prev->next = nn->next;
1734 1738
1735 1739 nn->prev = nn->next = NULL;
1736 1740
1737 1741 /*
1738 1742 * Scan back until we reach a node that's
1739 1743 * ordered before `nn'.
1740 1744 */
1741 1745
1742 1746 for ( ; prev ; prev = prev->prev) {
1743 1747 /* Determine order of `prev'. */
1744 1748 for (j = 0; j < RSORD_MAX; j++)
1745 1749 if (rsord[j] == prev->tok)
1746 1750 break;
1747 1751
1748 1752 if (j <= i)
1749 1753 break;
1750 1754 }
1751 1755
1752 1756 /*
1753 1757 * Set `nn' back into its correct place in front
1754 1758 * of the `prev' node.
1755 1759 */
1756 1760
1757 1761 nn->prev = prev;
1758 1762
1759 1763 if (prev) {
1760 1764 if (prev->next)
1761 1765 prev->next->prev = nn;
1762 1766 nn->next = prev->next;
1763 1767 prev->next = nn;
1764 1768 } else {
1765 1769 mdoc->last->child->prev = nn;
1766 1770 nn->next = mdoc->last->child;
1767 1771 mdoc->last->child = nn;
1768 1772 }
1769 1773 }
1770 1774
1771 1775 return(1);
1772 1776 }
1773 1777
1774 1778 static int
1775 1779 post_ns(POST_ARGS)
1776 1780 {
1777 1781
1778 1782 if (MDOC_LINE & mdoc->last->flags)
1779 1783 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNNS);
1780 1784 return(1);
1781 1785 }
1782 1786
1783 1787 static int
1784 1788 post_sh(POST_ARGS)
1785 1789 {
1786 1790
1787 1791 if (MDOC_HEAD == mdoc->last->type)
1788 1792 return(post_sh_head(mdoc));
1789 1793 if (MDOC_BODY == mdoc->last->type)
1790 1794 return(post_sh_body(mdoc));
1791 1795
1792 1796 return(1);
1793 1797 }
1794 1798
1795 1799 static int
1796 1800 post_sh_body(POST_ARGS)
1797 1801 {
1798 1802 struct mdoc_node *n;
1799 1803
1800 1804 if (SEC_NAME != mdoc->lastsec)
1801 1805 return(1);
1802 1806
1803 1807 /*
1804 1808 * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1805 1809 * macros (can have multiple `Nm' and one `Nd'). Note that the
1806 1810 * children of the BODY declaration can also be "text".
1807 1811 */
1808 1812
1809 1813 if (NULL == (n = mdoc->last->child)) {
1810 1814 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
1811 1815 return(1);
1812 1816 }
1813 1817
1814 1818 for ( ; n && n->next; n = n->next) {
1815 1819 if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
1816 1820 continue;
1817 1821 if (MDOC_TEXT == n->type)
1818 1822 continue;
1819 1823 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
1820 1824 }
1821 1825
1822 1826 assert(n);
1823 1827 if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
1824 1828 return(1);
1825 1829
1826 1830 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
1827 1831 return(1);
1828 1832 }
1829 1833
1830 1834 static int
1831 1835 post_sh_head(POST_ARGS)
1832 1836 {
1833 1837 char buf[BUFSIZ];
1834 1838 struct mdoc_node *n;
1835 1839 enum mdoc_sec sec;
1836 1840 int c;
1837 1841
1838 1842 /*
1839 1843 * Process a new section. Sections are either "named" or
1840 1844 * "custom". Custom sections are user-defined, while named ones
1841 1845 * follow a conventional order and may only appear in certain
1842 1846 * manual sections.
1843 1847 */
1844 1848
1845 1849 sec = SEC_CUSTOM;
1846 1850 buf[0] = '\0';
1847 1851 if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) {
1848 1852 mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
1849 1853 return(0);
1850 1854 } else if (1 == c)
1851 1855 sec = a2sec(buf);
1852 1856
1853 1857 /* The NAME should be first. */
1854 1858
1855 1859 if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1856 1860 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST);
1857 1861
1858 1862 /* The SYNOPSIS gets special attention in other areas. */
1859 1863
1860 1864 if (SEC_SYNOPSIS == sec)
1861 1865 mdoc->flags |= MDOC_SYNOPSIS;
1862 1866 else
1863 1867 mdoc->flags &= ~MDOC_SYNOPSIS;
1864 1868
1865 1869 /* Mark our last section. */
1866 1870
1867 1871 mdoc->lastsec = sec;
1868 1872
1869 1873 /*
1870 1874 * Set the section attribute for the current HEAD, for its
1871 1875 * parent BLOCK, and for the HEAD children; the latter can
1872 1876 * only be TEXT nodes, so no recursion is needed.
1873 1877 * For other blocks and elements, including .Sh BODY, this is
1874 1878 * done when allocating the node data structures, but for .Sh
1875 1879 * BLOCK and HEAD, the section is still unknown at that time.
1876 1880 */
1877 1881
1878 1882 mdoc->last->parent->sec = sec;
1879 1883 mdoc->last->sec = sec;
1880 1884 for (n = mdoc->last->child; n; n = n->next)
1881 1885 n->sec = sec;
1882 1886
1883 1887 /* We don't care about custom sections after this. */
1884 1888
1885 1889 if (SEC_CUSTOM == sec)
1886 1890 return(1);
1887 1891
1888 1892 /*
1889 1893 * Check whether our non-custom section is being repeated or is
1890 1894 * out of order.
1891 1895 */
1892 1896
1893 1897 if (sec == mdoc->lastnamed)
1894 1898 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECREP);
1895 1899
1896 1900 if (sec < mdoc->lastnamed)
1897 1901 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECOOO);
1898 1902
1899 1903 /* Mark the last named section. */
1900 1904
1901 1905 mdoc->lastnamed = sec;
1902 1906
1903 1907 /* Check particular section/manual conventions. */
1904 1908
1905 1909 assert(mdoc->meta.msec);
1906 1910
1907 1911 switch (sec) {
1908 1912 case (SEC_RETURN_VALUES):
1909 1913 /* FALLTHROUGH */
1910 1914 case (SEC_ERRORS):
1911 1915 /* FALLTHROUGH */
1912 1916 case (SEC_LIBRARY):
1913 1917 if (*mdoc->meta.msec == '2')
1914 1918 break;
1915 1919 if (*mdoc->meta.msec == '3')
1916 1920 break;
1917 1921 if (*mdoc->meta.msec == '9')
1918 1922 break;
1919 1923 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECMSEC);
1920 1924 break;
1921 1925 default:
1922 1926 break;
1923 1927 }
1924 1928
1925 1929 return(1);
1926 1930 }
1927 1931
1928 1932 static int
1929 1933 post_ignpar(POST_ARGS)
1930 1934 {
1931 1935 struct mdoc_node *np;
1932 1936
1933 1937 if (MDOC_BODY != mdoc->last->type)
1934 1938 return(1);
1935 1939
1936 1940 if (NULL != (np = mdoc->last->child))
1937 1941 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
1938 1942 mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
1939 1943 mdoc_node_delete(mdoc, np);
1940 1944 }
1941 1945
1942 1946 if (NULL != (np = mdoc->last->last))
1943 1947 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
1944 1948 mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
1945 1949 mdoc_node_delete(mdoc, np);
1946 1950 }
1947 1951
1948 1952 return(1);
1949 1953 }
1950 1954
1951 1955 static int
1952 1956 pre_par(PRE_ARGS)
1953 1957 {
1954 1958
1955 1959 if (NULL == mdoc->last)
1956 1960 return(1);
1957 1961 if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
1958 1962 return(1);
1959 1963
1960 1964 /*
1961 1965 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
1962 1966 * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
1963 1967 */
1964 1968
1965 1969 if (MDOC_Pp != mdoc->last->tok && MDOC_Lp != mdoc->last->tok)
1966 1970 return(1);
1967 1971 if (MDOC_Bl == n->tok && n->norm->Bl.comp)
1968 1972 return(1);
1969 1973 if (MDOC_Bd == n->tok && n->norm->Bd.comp)
1970 1974 return(1);
1971 1975 if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
1972 1976 return(1);
1973 1977
1974 1978 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
1975 1979 mdoc_node_delete(mdoc, mdoc->last);
1976 1980 return(1);
1977 1981 }
1978 1982
1979 1983 static int
1980 1984 pre_literal(PRE_ARGS)
1981 1985 {
1982 1986
1983 1987 if (MDOC_BODY != n->type)
1984 1988 return(1);
1985 1989
1986 1990 /*
1987 1991 * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
1988 1992 * -unfilled' macros set MDOC_LITERAL on entrance to the body.
1989 1993 */
1990 1994
1991 1995 switch (n->tok) {
1992 1996 case (MDOC_Dl):
1993 1997 mdoc->flags |= MDOC_LITERAL;
1994 1998 break;
1995 1999 case (MDOC_Bd):
1996 2000 if (DISP_literal == n->norm->Bd.type)
1997 2001 mdoc->flags |= MDOC_LITERAL;
1998 2002 if (DISP_unfilled == n->norm->Bd.type)
1999 2003 mdoc->flags |= MDOC_LITERAL;
2000 2004 break;
2001 2005 default:
2002 2006 abort();
2003 2007 /* NOTREACHED */
2004 2008 }
2005 2009
2006 2010 return(1);
2007 2011 }
2008 2012
2009 2013 static int
2010 2014 post_dd(POST_ARGS)
2011 2015 {
2012 2016 char buf[DATESIZE];
2013 2017 struct mdoc_node *n;
2014 2018 int c;
2015 2019
2016 2020 if (mdoc->meta.date)
2017 2021 free(mdoc->meta.date);
2018 2022
2019 2023 n = mdoc->last;
2020 2024 if (NULL == n->child || '\0' == n->child->string[0]) {
2021 2025 mdoc->meta.date = mandoc_normdate
2022 2026 (mdoc->parse, NULL, n->line, n->pos);
2023 2027 return(1);
2024 2028 }
2025 2029
2026 2030 buf[0] = '\0';
2027 2031 if (-1 == (c = concat(buf, n->child, DATESIZE))) {
2028 2032 mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
2029 2033 return(0);
2030 2034 }
2031 2035
2032 2036 assert(c);
2033 2037 mdoc->meta.date = mandoc_normdate
2034 2038 (mdoc->parse, buf, n->line, n->pos);
2035 2039
2036 2040 return(1);
2037 2041 }
2038 2042
2039 2043 static int
2040 2044 post_dt(POST_ARGS)
2041 2045 {
2042 2046 struct mdoc_node *nn, *n;
2043 2047 const char *cp;
2044 2048 char *p;
2045 2049
2046 2050 n = mdoc->last;
2047 2051
2048 2052 if (mdoc->meta.title)
2049 2053 free(mdoc->meta.title);
2050 2054 if (mdoc->meta.vol)
2051 2055 free(mdoc->meta.vol);
2052 2056 if (mdoc->meta.arch)
2053 2057 free(mdoc->meta.arch);
2054 2058
2055 2059 mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL;
2056 2060
2057 2061 /* First make all characters uppercase. */
2058 2062
2059 2063 if (NULL != (nn = n->child))
2060 2064 for (p = nn->string; *p; p++) {
2061 2065 if (toupper((unsigned char)*p) == *p)
2062 2066 continue;
2063 2067
2064 2068 /*
2065 2069 * FIXME: don't be lazy: have this make all
2066 2070 * characters be uppercase and just warn once.
2067 2071 */
2068 2072 mdoc_nmsg(mdoc, nn, MANDOCERR_UPPERCASE);
2069 2073 break;
2070 2074 }
2071 2075
2072 2076 /* Handles: `.Dt'
2073 2077 * --> title = unknown, volume = local, msec = 0, arch = NULL
2074 2078 */
2075 2079
2076 2080 if (NULL == (nn = n->child)) {
2077 2081 /* XXX: make these macro values. */
2078 2082 /* FIXME: warn about missing values. */
2079 2083 mdoc->meta.title = mandoc_strdup("UNKNOWN");
2080 2084 mdoc->meta.vol = mandoc_strdup("LOCAL");
2081 2085 mdoc->meta.msec = mandoc_strdup("1");
2082 2086 return(1);
2083 2087 }
2084 2088
2085 2089 /* Handles: `.Dt TITLE'
2086 2090 * --> title = TITLE, volume = local, msec = 0, arch = NULL
2087 2091 */
2088 2092
2089 2093 mdoc->meta.title = mandoc_strdup
2090 2094 ('\0' == nn->string[0] ? "UNKNOWN" : nn->string);
2091 2095
2092 2096 if (NULL == (nn = nn->next)) {
2093 2097 /* FIXME: warn about missing msec. */
2094 2098 /* XXX: make this a macro value. */
2095 2099 mdoc->meta.vol = mandoc_strdup("LOCAL");
2096 2100 mdoc->meta.msec = mandoc_strdup("1");
2097 2101 return(1);
2098 2102 }
2099 2103
2100 2104 /* Handles: `.Dt TITLE SEC'
2101 2105 * --> title = TITLE, volume = SEC is msec ?
2102 2106 * format(msec) : SEC,
2103 2107 * msec = SEC is msec ? atoi(msec) : 0,
2104 2108 * arch = NULL
2105 2109 */
2106 2110
2107 2111 cp = mandoc_a2msec(nn->string);
2108 2112 if (cp) {
2109 2113 mdoc->meta.vol = mandoc_strdup(cp);
2110 2114 mdoc->meta.msec = mandoc_strdup(nn->string);
2111 2115 } else {
2112 2116 mdoc_nmsg(mdoc, n, MANDOCERR_BADMSEC);
2113 2117 mdoc->meta.vol = mandoc_strdup(nn->string);
2114 2118 mdoc->meta.msec = mandoc_strdup(nn->string);
2115 2119 }
2116 2120
2117 2121 if (NULL == (nn = nn->next))
2118 2122 return(1);
2119 2123
2120 2124 /* Handles: `.Dt TITLE SEC VOL'
2121 2125 * --> title = TITLE, volume = VOL is vol ?
2122 2126 * format(VOL) :
2123 2127 * VOL is arch ? format(arch) :
2124 2128 * VOL
2125 2129 */
2126 2130
2127 2131 cp = mdoc_a2vol(nn->string);
2128 2132 if (cp) {
2129 2133 free(mdoc->meta.vol);
2130 2134 mdoc->meta.vol = mandoc_strdup(cp);
2131 2135 } else {
2132 2136 /* FIXME: warn about bad arch. */
2133 2137 cp = mdoc_a2arch(nn->string);
2134 2138 if (NULL == cp) {
2135 2139 free(mdoc->meta.vol);
2136 2140 mdoc->meta.vol = mandoc_strdup(nn->string);
2137 2141 } else
2138 2142 mdoc->meta.arch = mandoc_strdup(cp);
2139 2143 }
2140 2144
2141 2145 /* Ignore any subsequent parameters... */
2142 2146 /* FIXME: warn about subsequent parameters. */
2143 2147
2144 2148 return(1);
2145 2149 }
2146 2150
2147 2151 static int
2148 2152 post_prol(POST_ARGS)
2149 2153 {
2150 2154 /*
2151 2155 * Remove prologue macros from the document after they're
2152 2156 * processed. The final document uses mdoc_meta for these
2153 2157 * values and discards the originals.
2154 2158 */
2155 2159
2156 2160 mdoc_node_delete(mdoc, mdoc->last);
2157 2161 if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os)
2158 2162 mdoc->flags |= MDOC_PBODY;
2159 2163
2160 2164 return(1);
2161 2165 }
2162 2166
2163 2167 static int
2164 2168 post_bx(POST_ARGS)
2165 2169 {
2166 2170 struct mdoc_node *n;
2167 2171
2168 2172 /*
2169 2173 * Make `Bx's second argument always start with an uppercase
2170 2174 * letter. Groff checks if it's an "accepted" term, but we just
2171 2175 * uppercase blindly.
2172 2176 */
2173 2177
2174 2178 n = mdoc->last->child;
2175 2179 if (n && NULL != (n = n->next))
2176 2180 *n->string = (char)toupper
2177 2181 ((unsigned char)*n->string);
2178 2182
2179 2183 return(1);
2180 2184 }
2181 2185
2182 2186 static int
2183 2187 post_os(POST_ARGS)
2184 2188 {
2185 2189 struct mdoc_node *n;
2186 2190 char buf[BUFSIZ];
2187 2191 int c;
2188 2192 #ifndef OSNAME
2189 2193 struct utsname utsname;
2190 2194 #endif
2191 2195
2192 2196 n = mdoc->last;
2193 2197
2194 2198 /*
2195 2199 * Set the operating system by way of the `Os' macro. Note that
2196 2200 * if an argument isn't provided and -DOSNAME="\"foo\"" is
2197 2201 * provided during compilation, this value will be used instead
2198 2202 * of filling in "sysname release" from uname().
2199 2203 */
2200 2204
2201 2205 if (mdoc->meta.os)
2202 2206 free(mdoc->meta.os);
2203 2207
2204 2208 buf[0] = '\0';
2205 2209 if (-1 == (c = concat(buf, n->child, BUFSIZ))) {
2206 2210 mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
2207 2211 return(0);
2208 2212 }
2209 2213
2210 2214 assert(c);
2211 2215
2212 2216 /* XXX: yes, these can all be dynamically-adjusted buffers, but
2213 2217 * it's really not worth the extra hackery.
2214 2218 */
2215 2219
2216 2220 if ('\0' == buf[0]) {
2217 2221 #ifdef OSNAME
2218 2222 if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {
2219 2223 mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2220 2224 return(0);
2221 2225 }
2222 2226 #else /*!OSNAME */
2223 2227 if (-1 == uname(&utsname)) {
2224 2228 mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);
2225 2229 mdoc->meta.os = mandoc_strdup("UNKNOWN");
2226 2230 return(post_prol(mdoc));
2227 2231 }
2228 2232
2229 2233 if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) {
2230 2234 mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2231 2235 return(0);
2232 2236 }
2233 2237 if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) {
2234 2238 mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2235 2239 return(0);
2236 2240 }
2237 2241 if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) {
2238 2242 mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2239 2243 return(0);
2240 2244 }
2241 2245 #endif /*!OSNAME*/
2242 2246 }
2243 2247
2244 2248 mdoc->meta.os = mandoc_strdup(buf);
2245 2249 return(1);
2246 2250 }
2247 2251
2248 2252 static int
2249 2253 post_std(POST_ARGS)
2250 2254 {
2251 2255 struct mdoc_node *nn, *n;
2252 2256
2253 2257 n = mdoc->last;
2254 2258
2255 2259 /*
2256 2260 * Macros accepting `-std' as an argument have the name of the
2257 2261 * current document (`Nm') filled in as the argument if it's not
2258 2262 * provided.
2259 2263 */
2260 2264
2261 2265 if (n->child)
2262 2266 return(1);
2263 2267
2264 2268 if (NULL == mdoc->meta.name)
2265 2269 return(1);
2266 2270
2267 2271 nn = n;
2268 2272 mdoc->next = MDOC_NEXT_CHILD;
2269 2273
2270 2274 if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name))
2271 2275 return(0);
2272 2276
2273 2277 mdoc->last = nn;
2274 2278 return(1);
2275 2279 }
2276 2280
2277 2281 /*
2278 2282 * Concatenate a node, stopping at the first non-text.
2279 2283 * Concatenation is separated by a single whitespace.
2280 2284 * Returns -1 on fatal (string overrun) error, 0 if child nodes were
2281 2285 * encountered, 1 otherwise.
2282 2286 */
2283 2287 static int
2284 2288 concat(char *p, const struct mdoc_node *n, size_t sz)
2285 2289 {
2286 2290
2287 2291 for ( ; NULL != n; n = n->next) {
2288 2292 if (MDOC_TEXT != n->type)
2289 2293 return(0);
2290 2294 if ('\0' != p[0] && strlcat(p, " ", sz) >= sz)
2291 2295 return(-1);
2292 2296 if (strlcat(p, n->string, sz) >= sz)
2293 2297 return(-1);
2294 2298 concat(p, n->child, sz);
2295 2299 }
2296 2300
2297 2301 return(1);
2298 2302 }
2299 2303
2300 2304 static enum mdoc_sec
2301 2305 a2sec(const char *p)
2302 2306 {
2303 2307 int i;
2304 2308
2305 2309 for (i = 0; i < (int)SEC__MAX; i++)
2306 2310 if (secnames[i] && 0 == strcmp(p, secnames[i]))
2307 2311 return((enum mdoc_sec)i);
2308 2312
2309 2313 return(SEC_CUSTOM);
2310 2314 }
2311 2315
2312 2316 static size_t
2313 2317 macro2len(enum mdoct macro)
2314 2318 {
2315 2319
2316 2320 switch (macro) {
2317 2321 case(MDOC_Ad):
2318 2322 return(12);
2319 2323 case(MDOC_Ao):
2320 2324 return(12);
2321 2325 case(MDOC_An):
2322 2326 return(12);
2323 2327 case(MDOC_Aq):
2324 2328 return(12);
2325 2329 case(MDOC_Ar):
2326 2330 return(12);
2327 2331 case(MDOC_Bo):
2328 2332 return(12);
2329 2333 case(MDOC_Bq):
2330 2334 return(12);
2331 2335 case(MDOC_Cd):
2332 2336 return(12);
2333 2337 case(MDOC_Cm):
2334 2338 return(10);
2335 2339 case(MDOC_Do):
2336 2340 return(10);
2337 2341 case(MDOC_Dq):
2338 2342 return(12);
2339 2343 case(MDOC_Dv):
2340 2344 return(12);
2341 2345 case(MDOC_Eo):
2342 2346 return(12);
2343 2347 case(MDOC_Em):
2344 2348 return(10);
2345 2349 case(MDOC_Er):
2346 2350 return(17);
2347 2351 case(MDOC_Ev):
2348 2352 return(15);
2349 2353 case(MDOC_Fa):
2350 2354 return(12);
2351 2355 case(MDOC_Fl):
2352 2356 return(10);
2353 2357 case(MDOC_Fo):
2354 2358 return(16);
2355 2359 case(MDOC_Fn):
2356 2360 return(16);
2357 2361 case(MDOC_Ic):
2358 2362 return(10);
2359 2363 case(MDOC_Li):
2360 2364 return(16);
2361 2365 case(MDOC_Ms):
2362 2366 return(6);
2363 2367 case(MDOC_Nm):
2364 2368 return(10);
2365 2369 case(MDOC_No):
2366 2370 return(12);
2367 2371 case(MDOC_Oo):
2368 2372 return(10);
2369 2373 case(MDOC_Op):
2370 2374 return(14);
2371 2375 case(MDOC_Pa):
2372 2376 return(32);
2373 2377 case(MDOC_Pf):
2374 2378 return(12);
2375 2379 case(MDOC_Po):
2376 2380 return(12);
2377 2381 case(MDOC_Pq):
2378 2382 return(12);
2379 2383 case(MDOC_Ql):
2380 2384 return(16);
2381 2385 case(MDOC_Qo):
2382 2386 return(12);
2383 2387 case(MDOC_So):
2384 2388 return(12);
2385 2389 case(MDOC_Sq):
2386 2390 return(12);
2387 2391 case(MDOC_Sy):
2388 2392 return(6);
2389 2393 case(MDOC_Sx):
2390 2394 return(16);
2391 2395 case(MDOC_Tn):
2392 2396 return(10);
2393 2397 case(MDOC_Va):
2394 2398 return(12);
2395 2399 case(MDOC_Vt):
2396 2400 return(12);
2397 2401 case(MDOC_Xr):
2398 2402 return(10);
2399 2403 default:
2400 2404 break;
2401 2405 };
2402 2406 return(0);
2403 2407 }
↓ open down ↓ |
2054 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX