1241675Suqs/* $Id: mdoc_validate.c,v 1.182 2012/03/23 05:50:25 kristaps Exp $ */ 2241675Suqs/* 3241675Suqs * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4241675Suqs * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> 5241675Suqs * 6241675Suqs * Permission to use, copy, modify, and distribute this software for any 7241675Suqs * purpose with or without fee is hereby granted, provided that the above 8241675Suqs * copyright notice and this permission notice appear in all copies. 9241675Suqs * 10241675Suqs * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11241675Suqs * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12241675Suqs * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13241675Suqs * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14241675Suqs * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15241675Suqs * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16241675Suqs * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17241675Suqs */ 18241675Suqs#ifdef HAVE_CONFIG_H 19241675Suqs#include "config.h" 20241675Suqs#endif 21241675Suqs 22241675Suqs#ifndef OSNAME 23241675Suqs#include <sys/utsname.h> 24241675Suqs#endif 25241675Suqs 26241675Suqs#include <sys/types.h> 27241675Suqs 28241675Suqs#include <assert.h> 29241675Suqs#include <ctype.h> 30241675Suqs#include <limits.h> 31241675Suqs#include <stdio.h> 32241675Suqs#include <stdlib.h> 33241675Suqs#include <string.h> 34241675Suqs#include <time.h> 35241675Suqs 36241675Suqs#include "mdoc.h" 37241675Suqs#include "mandoc.h" 38241675Suqs#include "libmdoc.h" 39241675Suqs#include "libmandoc.h" 40241675Suqs 41241675Suqs/* FIXME: .Bl -diag can't have non-text children in HEAD. */ 42241675Suqs 43241675Suqs#define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n 44241675Suqs#define POST_ARGS struct mdoc *mdoc 45241675Suqs 46241675Suqs#define NUMSIZ 32 47241675Suqs#define DATESIZE 32 48241675Suqs 49241675Suqsenum check_ineq { 50241675Suqs CHECK_LT, 51241675Suqs CHECK_GT, 52241675Suqs CHECK_EQ 53241675Suqs}; 54241675Suqs 55241675Suqsenum check_lvl { 56241675Suqs CHECK_WARN, 57241675Suqs CHECK_ERROR, 58241675Suqs}; 59241675Suqs 60241675Suqstypedef int (*v_pre)(PRE_ARGS); 61241675Suqstypedef int (*v_post)(POST_ARGS); 62241675Suqs 63241675Suqsstruct valids { 64241675Suqs v_pre *pre; 65241675Suqs v_post *post; 66241675Suqs}; 67241675Suqs 68241675Suqsstatic int check_count(struct mdoc *, enum mdoc_type, 69241675Suqs enum check_lvl, enum check_ineq, int); 70241675Suqsstatic int check_parent(PRE_ARGS, enum mdoct, enum mdoc_type); 71241675Suqsstatic void check_text(struct mdoc *, int, int, char *); 72241675Suqsstatic void check_argv(struct mdoc *, 73241675Suqs struct mdoc_node *, struct mdoc_argv *); 74241675Suqsstatic void check_args(struct mdoc *, struct mdoc_node *); 75241675Suqsstatic int concat(char *, const struct mdoc_node *, size_t); 76241675Suqsstatic enum mdoc_sec a2sec(const char *); 77241675Suqsstatic size_t macro2len(enum mdoct); 78241675Suqs 79241675Suqsstatic int ebool(POST_ARGS); 80241675Suqsstatic int berr_ge1(POST_ARGS); 81241675Suqsstatic int bwarn_ge1(POST_ARGS); 82241675Suqsstatic int ewarn_eq0(POST_ARGS); 83241675Suqsstatic int ewarn_eq1(POST_ARGS); 84241675Suqsstatic int ewarn_ge1(POST_ARGS); 85241675Suqsstatic int ewarn_le1(POST_ARGS); 86241675Suqsstatic int hwarn_eq0(POST_ARGS); 87241675Suqsstatic int hwarn_eq1(POST_ARGS); 88241675Suqsstatic int hwarn_ge1(POST_ARGS); 89241675Suqsstatic int hwarn_le1(POST_ARGS); 90241675Suqs 91241675Suqsstatic int post_an(POST_ARGS); 92241675Suqsstatic int post_at(POST_ARGS); 93241675Suqsstatic int post_bf(POST_ARGS); 94241675Suqsstatic int post_bl(POST_ARGS); 95241675Suqsstatic int post_bl_block(POST_ARGS); 96241675Suqsstatic int post_bl_block_width(POST_ARGS); 97241675Suqsstatic int post_bl_block_tag(POST_ARGS); 98241675Suqsstatic int post_bl_head(POST_ARGS); 99241675Suqsstatic int post_bx(POST_ARGS); 100241675Suqsstatic int post_dd(POST_ARGS); 101241675Suqsstatic int post_dt(POST_ARGS); 102241675Suqsstatic int post_defaults(POST_ARGS); 103241675Suqsstatic int post_literal(POST_ARGS); 104241675Suqsstatic int post_eoln(POST_ARGS); 105241675Suqsstatic int post_it(POST_ARGS); 106241675Suqsstatic int post_lb(POST_ARGS); 107241675Suqsstatic int post_nm(POST_ARGS); 108241675Suqsstatic int post_ns(POST_ARGS); 109241675Suqsstatic int post_os(POST_ARGS); 110241675Suqsstatic int post_ignpar(POST_ARGS); 111241675Suqsstatic int post_prol(POST_ARGS); 112241675Suqsstatic int post_root(POST_ARGS); 113241675Suqsstatic int post_rs(POST_ARGS); 114241675Suqsstatic int post_sh(POST_ARGS); 115241675Suqsstatic int post_sh_body(POST_ARGS); 116241675Suqsstatic int post_sh_head(POST_ARGS); 117241675Suqsstatic int post_st(POST_ARGS); 118241675Suqsstatic int post_std(POST_ARGS); 119241675Suqsstatic int post_vt(POST_ARGS); 120241675Suqsstatic int pre_an(PRE_ARGS); 121241675Suqsstatic int pre_bd(PRE_ARGS); 122241675Suqsstatic int pre_bl(PRE_ARGS); 123241675Suqsstatic int pre_dd(PRE_ARGS); 124241675Suqsstatic int pre_display(PRE_ARGS); 125241675Suqsstatic int pre_dt(PRE_ARGS); 126241675Suqsstatic int pre_it(PRE_ARGS); 127241675Suqsstatic int pre_literal(PRE_ARGS); 128241675Suqsstatic int pre_os(PRE_ARGS); 129241675Suqsstatic int pre_par(PRE_ARGS); 130241675Suqsstatic int pre_sh(PRE_ARGS); 131241675Suqsstatic int pre_ss(PRE_ARGS); 132241675Suqsstatic int pre_std(PRE_ARGS); 133241675Suqs 134241675Suqsstatic v_post posts_an[] = { post_an, NULL }; 135241675Suqsstatic v_post posts_at[] = { post_at, post_defaults, NULL }; 136241675Suqsstatic v_post posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL }; 137241675Suqsstatic v_post posts_bf[] = { hwarn_le1, post_bf, NULL }; 138241675Suqsstatic v_post posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL }; 139241675Suqsstatic v_post posts_bl[] = { bwarn_ge1, post_bl, NULL }; 140241675Suqsstatic v_post posts_bx[] = { post_bx, NULL }; 141241675Suqsstatic v_post posts_bool[] = { ebool, NULL }; 142241675Suqsstatic v_post posts_eoln[] = { post_eoln, NULL }; 143241675Suqsstatic v_post posts_defaults[] = { post_defaults, NULL }; 144241675Suqsstatic v_post posts_dd[] = { post_dd, post_prol, NULL }; 145241675Suqsstatic v_post posts_dl[] = { post_literal, bwarn_ge1, NULL }; 146241675Suqsstatic v_post posts_dt[] = { post_dt, post_prol, NULL }; 147241675Suqsstatic v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL }; 148241675Suqsstatic v_post posts_it[] = { post_it, NULL }; 149241675Suqsstatic v_post posts_lb[] = { post_lb, NULL }; 150241675Suqsstatic v_post posts_nd[] = { berr_ge1, NULL }; 151241675Suqsstatic v_post posts_nm[] = { post_nm, NULL }; 152241675Suqsstatic v_post posts_notext[] = { ewarn_eq0, NULL }; 153241675Suqsstatic v_post posts_ns[] = { post_ns, NULL }; 154241675Suqsstatic v_post posts_os[] = { post_os, post_prol, NULL }; 155241675Suqsstatic v_post posts_rs[] = { post_rs, NULL }; 156241675Suqsstatic v_post posts_sh[] = { post_ignpar, hwarn_ge1, post_sh, NULL }; 157241675Suqsstatic v_post posts_sp[] = { ewarn_le1, NULL }; 158241675Suqsstatic v_post posts_ss[] = { post_ignpar, hwarn_ge1, NULL }; 159241675Suqsstatic v_post posts_st[] = { post_st, NULL }; 160241675Suqsstatic v_post posts_std[] = { post_std, NULL }; 161241675Suqsstatic v_post posts_text[] = { ewarn_ge1, NULL }; 162241675Suqsstatic v_post posts_text1[] = { ewarn_eq1, NULL }; 163241675Suqsstatic v_post posts_vt[] = { post_vt, NULL }; 164241675Suqsstatic v_post posts_wline[] = { bwarn_ge1, NULL }; 165241675Suqsstatic v_pre pres_an[] = { pre_an, NULL }; 166241675Suqsstatic v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL }; 167241675Suqsstatic v_pre pres_bl[] = { pre_bl, pre_par, NULL }; 168241675Suqsstatic v_pre pres_d1[] = { pre_display, NULL }; 169241675Suqsstatic v_pre pres_dl[] = { pre_literal, pre_display, NULL }; 170241675Suqsstatic v_pre pres_dd[] = { pre_dd, NULL }; 171241675Suqsstatic v_pre pres_dt[] = { pre_dt, NULL }; 172241675Suqsstatic v_pre pres_er[] = { NULL, NULL }; 173241675Suqsstatic v_pre pres_fd[] = { NULL, NULL }; 174241675Suqsstatic v_pre pres_it[] = { pre_it, pre_par, NULL }; 175241675Suqsstatic v_pre pres_os[] = { pre_os, NULL }; 176241675Suqsstatic v_pre pres_pp[] = { pre_par, NULL }; 177241675Suqsstatic v_pre pres_sh[] = { pre_sh, NULL }; 178241675Suqsstatic v_pre pres_ss[] = { pre_ss, NULL }; 179241675Suqsstatic v_pre pres_std[] = { pre_std, NULL }; 180241675Suqs 181241675Suqsstatic const struct valids mdoc_valids[MDOC_MAX] = { 182241675Suqs { NULL, NULL }, /* Ap */ 183241675Suqs { pres_dd, posts_dd }, /* Dd */ 184241675Suqs { pres_dt, posts_dt }, /* Dt */ 185241675Suqs { pres_os, posts_os }, /* Os */ 186241675Suqs { pres_sh, posts_sh }, /* Sh */ 187241675Suqs { pres_ss, posts_ss }, /* Ss */ 188241675Suqs { pres_pp, posts_notext }, /* Pp */ 189241675Suqs { pres_d1, posts_wline }, /* D1 */ 190241675Suqs { pres_dl, posts_dl }, /* Dl */ 191241675Suqs { pres_bd, posts_bd }, /* Bd */ 192241675Suqs { NULL, NULL }, /* Ed */ 193241675Suqs { pres_bl, posts_bl }, /* Bl */ 194241675Suqs { NULL, NULL }, /* El */ 195241675Suqs { pres_it, posts_it }, /* It */ 196241675Suqs { NULL, NULL }, /* Ad */ 197241675Suqs { pres_an, posts_an }, /* An */ 198241675Suqs { NULL, posts_defaults }, /* Ar */ 199241675Suqs { NULL, NULL }, /* Cd */ 200241675Suqs { NULL, NULL }, /* Cm */ 201241675Suqs { NULL, NULL }, /* Dv */ 202241675Suqs { pres_er, NULL }, /* Er */ 203241675Suqs { NULL, NULL }, /* Ev */ 204241675Suqs { pres_std, posts_std }, /* Ex */ 205241675Suqs { NULL, NULL }, /* Fa */ 206241675Suqs { pres_fd, posts_text }, /* Fd */ 207241675Suqs { NULL, NULL }, /* Fl */ 208241675Suqs { NULL, NULL }, /* Fn */ 209241675Suqs { NULL, NULL }, /* Ft */ 210241675Suqs { NULL, NULL }, /* Ic */ 211241675Suqs { NULL, posts_text1 }, /* In */ 212241675Suqs { NULL, posts_defaults }, /* Li */ 213241675Suqs { NULL, posts_nd }, /* Nd */ 214241675Suqs { NULL, posts_nm }, /* Nm */ 215241675Suqs { NULL, NULL }, /* Op */ 216241675Suqs { NULL, NULL }, /* Ot */ 217241675Suqs { NULL, posts_defaults }, /* Pa */ 218241675Suqs { pres_std, posts_std }, /* Rv */ 219241675Suqs { NULL, posts_st }, /* St */ 220241675Suqs { NULL, NULL }, /* Va */ 221241675Suqs { NULL, posts_vt }, /* Vt */ 222241675Suqs { NULL, posts_text }, /* Xr */ 223241675Suqs { NULL, posts_text }, /* %A */ 224241675Suqs { NULL, posts_text }, /* %B */ /* FIXME: can be used outside Rs/Re. */ 225241675Suqs { NULL, posts_text }, /* %D */ 226241675Suqs { NULL, posts_text }, /* %I */ 227241675Suqs { NULL, posts_text }, /* %J */ 228241675Suqs { NULL, posts_text }, /* %N */ 229241675Suqs { NULL, posts_text }, /* %O */ 230241675Suqs { NULL, posts_text }, /* %P */ 231241675Suqs { NULL, posts_text }, /* %R */ 232241675Suqs { NULL, posts_text }, /* %T */ /* FIXME: can be used outside Rs/Re. */ 233241675Suqs { NULL, posts_text }, /* %V */ 234241675Suqs { NULL, NULL }, /* Ac */ 235241675Suqs { NULL, NULL }, /* Ao */ 236241675Suqs { NULL, NULL }, /* Aq */ 237241675Suqs { NULL, posts_at }, /* At */ 238241675Suqs { NULL, NULL }, /* Bc */ 239241675Suqs { NULL, posts_bf }, /* Bf */ 240241675Suqs { NULL, NULL }, /* Bo */ 241241675Suqs { NULL, NULL }, /* Bq */ 242241675Suqs { NULL, NULL }, /* Bsx */ 243241675Suqs { NULL, posts_bx }, /* Bx */ 244241675Suqs { NULL, posts_bool }, /* Db */ 245241675Suqs { NULL, NULL }, /* Dc */ 246241675Suqs { NULL, NULL }, /* Do */ 247241675Suqs { NULL, NULL }, /* Dq */ 248241675Suqs { NULL, NULL }, /* Ec */ 249241675Suqs { NULL, NULL }, /* Ef */ 250241675Suqs { NULL, NULL }, /* Em */ 251241675Suqs { NULL, NULL }, /* Eo */ 252241675Suqs { NULL, NULL }, /* Fx */ 253241675Suqs { NULL, NULL }, /* Ms */ 254241675Suqs { NULL, posts_notext }, /* No */ 255241675Suqs { NULL, posts_ns }, /* Ns */ 256241675Suqs { NULL, NULL }, /* Nx */ 257241675Suqs { NULL, NULL }, /* Ox */ 258241675Suqs { NULL, NULL }, /* Pc */ 259241675Suqs { NULL, posts_text1 }, /* Pf */ 260241675Suqs { NULL, NULL }, /* Po */ 261241675Suqs { NULL, NULL }, /* Pq */ 262241675Suqs { NULL, NULL }, /* Qc */ 263241675Suqs { NULL, NULL }, /* Ql */ 264241675Suqs { NULL, NULL }, /* Qo */ 265241675Suqs { NULL, NULL }, /* Qq */ 266241675Suqs { NULL, NULL }, /* Re */ 267241675Suqs { NULL, posts_rs }, /* Rs */ 268241675Suqs { NULL, NULL }, /* Sc */ 269241675Suqs { NULL, NULL }, /* So */ 270241675Suqs { NULL, NULL }, /* Sq */ 271241675Suqs { NULL, posts_bool }, /* Sm */ 272241675Suqs { NULL, NULL }, /* Sx */ 273241675Suqs { NULL, NULL }, /* Sy */ 274241675Suqs { NULL, NULL }, /* Tn */ 275241675Suqs { NULL, NULL }, /* Ux */ 276241675Suqs { NULL, NULL }, /* Xc */ 277241675Suqs { NULL, NULL }, /* Xo */ 278241675Suqs { NULL, posts_fo }, /* Fo */ 279241675Suqs { NULL, NULL }, /* Fc */ 280241675Suqs { NULL, NULL }, /* Oo */ 281241675Suqs { NULL, NULL }, /* Oc */ 282241675Suqs { NULL, posts_bk }, /* Bk */ 283241675Suqs { NULL, NULL }, /* Ek */ 284241675Suqs { NULL, posts_eoln }, /* Bt */ 285241675Suqs { NULL, NULL }, /* Hf */ 286241675Suqs { NULL, NULL }, /* Fr */ 287241675Suqs { NULL, posts_eoln }, /* Ud */ 288241675Suqs { NULL, posts_lb }, /* Lb */ 289241675Suqs { NULL, posts_notext }, /* Lp */ 290241675Suqs { NULL, NULL }, /* Lk */ 291241675Suqs { NULL, posts_defaults }, /* Mt */ 292241675Suqs { NULL, NULL }, /* Brq */ 293241675Suqs { NULL, NULL }, /* Bro */ 294241675Suqs { NULL, NULL }, /* Brc */ 295241675Suqs { NULL, posts_text }, /* %C */ 296241675Suqs { NULL, NULL }, /* Es */ 297241675Suqs { NULL, NULL }, /* En */ 298241675Suqs { NULL, NULL }, /* Dx */ 299241675Suqs { NULL, posts_text }, /* %Q */ 300241675Suqs { NULL, posts_notext }, /* br */ 301241675Suqs { pres_pp, posts_sp }, /* sp */ 302241675Suqs { NULL, posts_text1 }, /* %U */ 303241675Suqs { NULL, NULL }, /* Ta */ 304241675Suqs}; 305241675Suqs 306241675Suqs#define RSORD_MAX 14 /* Number of `Rs' blocks. */ 307241675Suqs 308241675Suqsstatic const enum mdoct rsord[RSORD_MAX] = { 309241675Suqs MDOC__A, 310241675Suqs MDOC__T, 311241675Suqs MDOC__B, 312241675Suqs MDOC__I, 313241675Suqs MDOC__J, 314241675Suqs MDOC__R, 315241675Suqs MDOC__N, 316241675Suqs MDOC__V, 317241675Suqs MDOC__P, 318241675Suqs MDOC__Q, 319241675Suqs MDOC__D, 320241675Suqs MDOC__O, 321241675Suqs MDOC__C, 322241675Suqs MDOC__U 323241675Suqs}; 324241675Suqs 325241675Suqsstatic const char * const secnames[SEC__MAX] = { 326241675Suqs NULL, 327241675Suqs "NAME", 328241675Suqs "LIBRARY", 329241675Suqs "SYNOPSIS", 330241675Suqs "DESCRIPTION", 331241675Suqs "IMPLEMENTATION NOTES", 332241675Suqs "RETURN VALUES", 333241675Suqs "ENVIRONMENT", 334241675Suqs "FILES", 335241675Suqs "EXIT STATUS", 336241675Suqs "EXAMPLES", 337241675Suqs "DIAGNOSTICS", 338241675Suqs "COMPATIBILITY", 339241675Suqs "ERRORS", 340241675Suqs "SEE ALSO", 341241675Suqs "STANDARDS", 342241675Suqs "HISTORY", 343241675Suqs "AUTHORS", 344241675Suqs "CAVEATS", 345241675Suqs "BUGS", 346241675Suqs "SECURITY CONSIDERATIONS", 347241675Suqs NULL 348241675Suqs}; 349241675Suqs 350241675Suqsint 351241675Suqsmdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) 352241675Suqs{ 353241675Suqs v_pre *p; 354241675Suqs int line, pos; 355241675Suqs char *tp; 356241675Suqs 357241675Suqs switch (n->type) { 358241675Suqs case (MDOC_TEXT): 359241675Suqs tp = n->string; 360241675Suqs line = n->line; 361241675Suqs pos = n->pos; 362241675Suqs check_text(mdoc, line, pos, tp); 363241675Suqs /* FALLTHROUGH */ 364241675Suqs case (MDOC_TBL): 365241675Suqs /* FALLTHROUGH */ 366241675Suqs case (MDOC_EQN): 367241675Suqs /* FALLTHROUGH */ 368241675Suqs case (MDOC_ROOT): 369241675Suqs return(1); 370241675Suqs default: 371241675Suqs break; 372241675Suqs } 373241675Suqs 374241675Suqs check_args(mdoc, n); 375241675Suqs 376241675Suqs if (NULL == mdoc_valids[n->tok].pre) 377241675Suqs return(1); 378241675Suqs for (p = mdoc_valids[n->tok].pre; *p; p++) 379241675Suqs if ( ! (*p)(mdoc, n)) 380241675Suqs return(0); 381241675Suqs return(1); 382241675Suqs} 383241675Suqs 384241675Suqs 385241675Suqsint 386241675Suqsmdoc_valid_post(struct mdoc *mdoc) 387241675Suqs{ 388241675Suqs v_post *p; 389241675Suqs 390241675Suqs if (MDOC_VALID & mdoc->last->flags) 391241675Suqs return(1); 392241675Suqs mdoc->last->flags |= MDOC_VALID; 393241675Suqs 394241675Suqs switch (mdoc->last->type) { 395241675Suqs case (MDOC_TEXT): 396241675Suqs /* FALLTHROUGH */ 397241675Suqs case (MDOC_EQN): 398241675Suqs /* FALLTHROUGH */ 399241675Suqs case (MDOC_TBL): 400241675Suqs return(1); 401241675Suqs case (MDOC_ROOT): 402241675Suqs return(post_root(mdoc)); 403241675Suqs default: 404241675Suqs break; 405241675Suqs } 406241675Suqs 407241675Suqs if (NULL == mdoc_valids[mdoc->last->tok].post) 408241675Suqs return(1); 409241675Suqs for (p = mdoc_valids[mdoc->last->tok].post; *p; p++) 410241675Suqs if ( ! (*p)(mdoc)) 411241675Suqs return(0); 412241675Suqs 413241675Suqs return(1); 414241675Suqs} 415241675Suqs 416241675Suqsstatic int 417241675Suqscheck_count(struct mdoc *m, enum mdoc_type type, 418241675Suqs enum check_lvl lvl, enum check_ineq ineq, int val) 419241675Suqs{ 420241675Suqs const char *p; 421241675Suqs enum mandocerr t; 422241675Suqs 423241675Suqs if (m->last->type != type) 424241675Suqs return(1); 425241675Suqs 426241675Suqs switch (ineq) { 427241675Suqs case (CHECK_LT): 428241675Suqs p = "less than "; 429241675Suqs if (m->last->nchild < val) 430241675Suqs return(1); 431241675Suqs break; 432241675Suqs case (CHECK_GT): 433241675Suqs p = "more than "; 434241675Suqs if (m->last->nchild > val) 435241675Suqs return(1); 436241675Suqs break; 437241675Suqs case (CHECK_EQ): 438241675Suqs p = ""; 439241675Suqs if (val == m->last->nchild) 440241675Suqs return(1); 441241675Suqs break; 442241675Suqs default: 443241675Suqs abort(); 444241675Suqs /* NOTREACHED */ 445241675Suqs } 446241675Suqs 447241675Suqs t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT; 448241675Suqs mandoc_vmsg(t, m->parse, m->last->line, m->last->pos, 449241675Suqs "want %s%d children (have %d)", 450241675Suqs p, val, m->last->nchild); 451241675Suqs return(1); 452241675Suqs} 453241675Suqs 454241675Suqsstatic int 455241675Suqsberr_ge1(POST_ARGS) 456241675Suqs{ 457241675Suqs 458241675Suqs return(check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0)); 459241675Suqs} 460241675Suqs 461241675Suqsstatic int 462241675Suqsbwarn_ge1(POST_ARGS) 463241675Suqs{ 464241675Suqs return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0)); 465241675Suqs} 466241675Suqs 467241675Suqsstatic int 468241675Suqsewarn_eq0(POST_ARGS) 469241675Suqs{ 470241675Suqs return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0)); 471241675Suqs} 472241675Suqs 473241675Suqsstatic int 474241675Suqsewarn_eq1(POST_ARGS) 475241675Suqs{ 476241675Suqs return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1)); 477241675Suqs} 478241675Suqs 479241675Suqsstatic int 480241675Suqsewarn_ge1(POST_ARGS) 481241675Suqs{ 482241675Suqs return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0)); 483241675Suqs} 484241675Suqs 485241675Suqsstatic int 486241675Suqsewarn_le1(POST_ARGS) 487241675Suqs{ 488241675Suqs return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2)); 489241675Suqs} 490241675Suqs 491241675Suqsstatic int 492241675Suqshwarn_eq0(POST_ARGS) 493241675Suqs{ 494241675Suqs return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0)); 495241675Suqs} 496241675Suqs 497241675Suqsstatic int 498241675Suqshwarn_eq1(POST_ARGS) 499241675Suqs{ 500241675Suqs return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1)); 501241675Suqs} 502241675Suqs 503241675Suqsstatic int 504241675Suqshwarn_ge1(POST_ARGS) 505241675Suqs{ 506241675Suqs return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0)); 507241675Suqs} 508241675Suqs 509241675Suqsstatic int 510241675Suqshwarn_le1(POST_ARGS) 511241675Suqs{ 512241675Suqs return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_LT, 2)); 513241675Suqs} 514241675Suqs 515241675Suqsstatic void 516241675Suqscheck_args(struct mdoc *m, struct mdoc_node *n) 517241675Suqs{ 518241675Suqs int i; 519241675Suqs 520241675Suqs if (NULL == n->args) 521241675Suqs return; 522241675Suqs 523241675Suqs assert(n->args->argc); 524241675Suqs for (i = 0; i < (int)n->args->argc; i++) 525241675Suqs check_argv(m, n, &n->args->argv[i]); 526241675Suqs} 527241675Suqs 528241675Suqsstatic void 529241675Suqscheck_argv(struct mdoc *m, struct mdoc_node *n, struct mdoc_argv *v) 530241675Suqs{ 531241675Suqs int i; 532241675Suqs 533241675Suqs for (i = 0; i < (int)v->sz; i++) 534241675Suqs check_text(m, v->line, v->pos, v->value[i]); 535241675Suqs 536241675Suqs /* FIXME: move to post_std(). */ 537241675Suqs 538241675Suqs if (MDOC_Std == v->arg) 539241675Suqs if ( ! (v->sz || m->meta.name)) 540241675Suqs mdoc_nmsg(m, n, MANDOCERR_NONAME); 541241675Suqs} 542241675Suqs 543241675Suqsstatic void 544241675Suqscheck_text(struct mdoc *m, int ln, int pos, char *p) 545241675Suqs{ 546241675Suqs char *cp; 547241675Suqs 548241675Suqs if (MDOC_LITERAL & m->flags) 549241675Suqs return; 550241675Suqs 551241675Suqs for (cp = p; NULL != (p = strchr(p, '\t')); p++) 552241675Suqs mdoc_pmsg(m, ln, pos + (int)(p - cp), MANDOCERR_BADTAB); 553241675Suqs} 554241675Suqs 555241675Suqsstatic int 556241675Suqscheck_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t) 557241675Suqs{ 558241675Suqs 559241675Suqs assert(n->parent); 560241675Suqs if ((MDOC_ROOT == t || tok == n->parent->tok) && 561241675Suqs (t == n->parent->type)) 562241675Suqs return(1); 563241675Suqs 564241675Suqs mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, n->line, 565241675Suqs n->pos, "want parent %s", MDOC_ROOT == t ? 566241675Suqs "<root>" : mdoc_macronames[tok]); 567241675Suqs return(0); 568241675Suqs} 569241675Suqs 570241675Suqs 571241675Suqsstatic int 572241675Suqspre_display(PRE_ARGS) 573241675Suqs{ 574241675Suqs struct mdoc_node *node; 575241675Suqs 576241675Suqs if (MDOC_BLOCK != n->type) 577241675Suqs return(1); 578241675Suqs 579241675Suqs for (node = mdoc->last->parent; node; node = node->parent) 580241675Suqs if (MDOC_BLOCK == node->type) 581241675Suqs if (MDOC_Bd == node->tok) 582241675Suqs break; 583241675Suqs 584241675Suqs if (node) 585241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_NESTEDDISP); 586241675Suqs 587241675Suqs return(1); 588241675Suqs} 589241675Suqs 590241675Suqs 591241675Suqsstatic int 592241675Suqspre_bl(PRE_ARGS) 593241675Suqs{ 594241675Suqs int i, comp, dup; 595241675Suqs const char *offs, *width; 596241675Suqs enum mdoc_list lt; 597241675Suqs struct mdoc_node *np; 598241675Suqs 599241675Suqs if (MDOC_BLOCK != n->type) { 600241675Suqs if (ENDBODY_NOT != n->end) { 601241675Suqs assert(n->pending); 602241675Suqs np = n->pending->parent; 603241675Suqs } else 604241675Suqs np = n->parent; 605241675Suqs 606241675Suqs assert(np); 607241675Suqs assert(MDOC_BLOCK == np->type); 608241675Suqs assert(MDOC_Bl == np->tok); 609241675Suqs return(1); 610241675Suqs } 611241675Suqs 612241675Suqs /* 613241675Suqs * First figure out which kind of list to use: bind ourselves to 614241675Suqs * the first mentioned list type and warn about any remaining 615241675Suqs * ones. If we find no list type, we default to LIST_item. 616241675Suqs */ 617241675Suqs 618241675Suqs /* LINTED */ 619241675Suqs for (i = 0; n->args && i < (int)n->args->argc; i++) { 620241675Suqs lt = LIST__NONE; 621241675Suqs dup = comp = 0; 622241675Suqs width = offs = NULL; 623241675Suqs switch (n->args->argv[i].arg) { 624241675Suqs /* Set list types. */ 625241675Suqs case (MDOC_Bullet): 626241675Suqs lt = LIST_bullet; 627241675Suqs break; 628241675Suqs case (MDOC_Dash): 629241675Suqs lt = LIST_dash; 630241675Suqs break; 631241675Suqs case (MDOC_Enum): 632241675Suqs lt = LIST_enum; 633241675Suqs break; 634241675Suqs case (MDOC_Hyphen): 635241675Suqs lt = LIST_hyphen; 636241675Suqs break; 637241675Suqs case (MDOC_Item): 638241675Suqs lt = LIST_item; 639241675Suqs break; 640241675Suqs case (MDOC_Tag): 641241675Suqs lt = LIST_tag; 642241675Suqs break; 643241675Suqs case (MDOC_Diag): 644241675Suqs lt = LIST_diag; 645241675Suqs break; 646241675Suqs case (MDOC_Hang): 647241675Suqs lt = LIST_hang; 648241675Suqs break; 649241675Suqs case (MDOC_Ohang): 650241675Suqs lt = LIST_ohang; 651241675Suqs break; 652241675Suqs case (MDOC_Inset): 653241675Suqs lt = LIST_inset; 654241675Suqs break; 655241675Suqs case (MDOC_Column): 656241675Suqs lt = LIST_column; 657241675Suqs break; 658241675Suqs /* Set list arguments. */ 659241675Suqs case (MDOC_Compact): 660241675Suqs dup = n->norm->Bl.comp; 661241675Suqs comp = 1; 662241675Suqs break; 663241675Suqs case (MDOC_Width): 664241675Suqs /* NB: this can be empty! */ 665241675Suqs if (n->args->argv[i].sz) { 666241675Suqs width = n->args->argv[i].value[0]; 667241675Suqs dup = (NULL != n->norm->Bl.width); 668241675Suqs break; 669241675Suqs } 670241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 671241675Suqs break; 672241675Suqs case (MDOC_Offset): 673241675Suqs /* NB: this can be empty! */ 674241675Suqs if (n->args->argv[i].sz) { 675241675Suqs offs = n->args->argv[i].value[0]; 676241675Suqs dup = (NULL != n->norm->Bl.offs); 677241675Suqs break; 678241675Suqs } 679241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 680241675Suqs break; 681241675Suqs default: 682241675Suqs continue; 683241675Suqs } 684241675Suqs 685241675Suqs /* Check: duplicate auxiliary arguments. */ 686241675Suqs 687241675Suqs if (dup) 688241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP); 689241675Suqs 690241675Suqs if (comp && ! dup) 691241675Suqs n->norm->Bl.comp = comp; 692241675Suqs if (offs && ! dup) 693241675Suqs n->norm->Bl.offs = offs; 694241675Suqs if (width && ! dup) 695241675Suqs n->norm->Bl.width = width; 696241675Suqs 697241675Suqs /* Check: multiple list types. */ 698241675Suqs 699241675Suqs if (LIST__NONE != lt && n->norm->Bl.type != LIST__NONE) 700241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP); 701241675Suqs 702241675Suqs /* Assign list type. */ 703241675Suqs 704241675Suqs if (LIST__NONE != lt && n->norm->Bl.type == LIST__NONE) { 705241675Suqs n->norm->Bl.type = lt; 706241675Suqs /* Set column information, too. */ 707241675Suqs if (LIST_column == lt) { 708241675Suqs n->norm->Bl.ncols = 709241675Suqs n->args->argv[i].sz; 710241675Suqs n->norm->Bl.cols = (void *) 711241675Suqs n->args->argv[i].value; 712241675Suqs } 713241675Suqs } 714241675Suqs 715241675Suqs /* The list type should come first. */ 716241675Suqs 717241675Suqs if (n->norm->Bl.type == LIST__NONE) 718241675Suqs if (n->norm->Bl.width || 719241675Suqs n->norm->Bl.offs || 720241675Suqs n->norm->Bl.comp) 721241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST); 722241675Suqs 723241675Suqs continue; 724241675Suqs } 725241675Suqs 726241675Suqs /* Allow lists to default to LIST_item. */ 727241675Suqs 728241675Suqs if (LIST__NONE == n->norm->Bl.type) { 729241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE); 730241675Suqs n->norm->Bl.type = LIST_item; 731241675Suqs } 732241675Suqs 733241675Suqs /* 734241675Suqs * Validate the width field. Some list types don't need width 735241675Suqs * types and should be warned about them. Others should have it 736241675Suqs * and must also be warned. 737241675Suqs */ 738241675Suqs 739241675Suqs switch (n->norm->Bl.type) { 740241675Suqs case (LIST_tag): 741241675Suqs if (n->norm->Bl.width) 742241675Suqs break; 743241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG); 744241675Suqs break; 745241675Suqs case (LIST_column): 746241675Suqs /* FALLTHROUGH */ 747241675Suqs case (LIST_diag): 748241675Suqs /* FALLTHROUGH */ 749241675Suqs case (LIST_ohang): 750241675Suqs /* FALLTHROUGH */ 751241675Suqs case (LIST_inset): 752241675Suqs /* FALLTHROUGH */ 753241675Suqs case (LIST_item): 754241675Suqs if (n->norm->Bl.width) 755241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 756241675Suqs break; 757241675Suqs default: 758241675Suqs break; 759241675Suqs } 760241675Suqs 761241675Suqs return(1); 762241675Suqs} 763241675Suqs 764241675Suqs 765241675Suqsstatic int 766241675Suqspre_bd(PRE_ARGS) 767241675Suqs{ 768241675Suqs int i, dup, comp; 769241675Suqs enum mdoc_disp dt; 770241675Suqs const char *offs; 771241675Suqs struct mdoc_node *np; 772241675Suqs 773241675Suqs if (MDOC_BLOCK != n->type) { 774241675Suqs if (ENDBODY_NOT != n->end) { 775241675Suqs assert(n->pending); 776241675Suqs np = n->pending->parent; 777241675Suqs } else 778241675Suqs np = n->parent; 779241675Suqs 780241675Suqs assert(np); 781241675Suqs assert(MDOC_BLOCK == np->type); 782241675Suqs assert(MDOC_Bd == np->tok); 783241675Suqs return(1); 784241675Suqs } 785241675Suqs 786241675Suqs /* LINTED */ 787241675Suqs for (i = 0; n->args && i < (int)n->args->argc; i++) { 788241675Suqs dt = DISP__NONE; 789241675Suqs dup = comp = 0; 790241675Suqs offs = NULL; 791241675Suqs 792241675Suqs switch (n->args->argv[i].arg) { 793241675Suqs case (MDOC_Centred): 794241675Suqs dt = DISP_centred; 795241675Suqs break; 796241675Suqs case (MDOC_Ragged): 797241675Suqs dt = DISP_ragged; 798241675Suqs break; 799241675Suqs case (MDOC_Unfilled): 800241675Suqs dt = DISP_unfilled; 801241675Suqs break; 802241675Suqs case (MDOC_Filled): 803241675Suqs dt = DISP_filled; 804241675Suqs break; 805241675Suqs case (MDOC_Literal): 806241675Suqs dt = DISP_literal; 807241675Suqs break; 808241675Suqs case (MDOC_File): 809241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_BADDISP); 810241675Suqs return(0); 811241675Suqs case (MDOC_Offset): 812241675Suqs /* NB: this can be empty! */ 813241675Suqs if (n->args->argv[i].sz) { 814241675Suqs offs = n->args->argv[i].value[0]; 815241675Suqs dup = (NULL != n->norm->Bd.offs); 816241675Suqs break; 817241675Suqs } 818241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); 819241675Suqs break; 820241675Suqs case (MDOC_Compact): 821241675Suqs comp = 1; 822241675Suqs dup = n->norm->Bd.comp; 823241675Suqs break; 824241675Suqs default: 825241675Suqs abort(); 826241675Suqs /* NOTREACHED */ 827241675Suqs } 828241675Suqs 829241675Suqs /* Check whether we have duplicates. */ 830241675Suqs 831241675Suqs if (dup) 832241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP); 833241675Suqs 834241675Suqs /* Make our auxiliary assignments. */ 835241675Suqs 836241675Suqs if (offs && ! dup) 837241675Suqs n->norm->Bd.offs = offs; 838241675Suqs if (comp && ! dup) 839241675Suqs n->norm->Bd.comp = comp; 840241675Suqs 841241675Suqs /* Check whether a type has already been assigned. */ 842241675Suqs 843241675Suqs if (DISP__NONE != dt && n->norm->Bd.type != DISP__NONE) 844241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP); 845241675Suqs 846241675Suqs /* Make our type assignment. */ 847241675Suqs 848241675Suqs if (DISP__NONE != dt && n->norm->Bd.type == DISP__NONE) 849241675Suqs n->norm->Bd.type = dt; 850241675Suqs } 851241675Suqs 852241675Suqs if (DISP__NONE == n->norm->Bd.type) { 853241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE); 854241675Suqs n->norm->Bd.type = DISP_ragged; 855241675Suqs } 856241675Suqs 857241675Suqs return(1); 858241675Suqs} 859241675Suqs 860241675Suqs 861241675Suqsstatic int 862241675Suqspre_ss(PRE_ARGS) 863241675Suqs{ 864241675Suqs 865241675Suqs if (MDOC_BLOCK != n->type) 866241675Suqs return(1); 867241675Suqs return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY)); 868241675Suqs} 869241675Suqs 870241675Suqs 871241675Suqsstatic int 872241675Suqspre_sh(PRE_ARGS) 873241675Suqs{ 874241675Suqs 875241675Suqs if (MDOC_BLOCK != n->type) 876241675Suqs return(1); 877241675Suqs 878241675Suqs roff_regunset(mdoc->roff, REG_nS); 879241675Suqs return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT)); 880241675Suqs} 881241675Suqs 882241675Suqs 883241675Suqsstatic int 884241675Suqspre_it(PRE_ARGS) 885241675Suqs{ 886241675Suqs 887241675Suqs if (MDOC_BLOCK != n->type) 888241675Suqs return(1); 889241675Suqs 890241675Suqs return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY)); 891241675Suqs} 892241675Suqs 893241675Suqs 894241675Suqsstatic int 895241675Suqspre_an(PRE_ARGS) 896241675Suqs{ 897241675Suqs int i; 898241675Suqs 899241675Suqs if (NULL == n->args) 900241675Suqs return(1); 901241675Suqs 902241675Suqs for (i = 1; i < (int)n->args->argc; i++) 903241675Suqs mdoc_pmsg(mdoc, n->args->argv[i].line, 904241675Suqs n->args->argv[i].pos, MANDOCERR_IGNARGV); 905241675Suqs 906241675Suqs if (MDOC_Split == n->args->argv[0].arg) 907241675Suqs n->norm->An.auth = AUTH_split; 908241675Suqs else if (MDOC_Nosplit == n->args->argv[0].arg) 909241675Suqs n->norm->An.auth = AUTH_nosplit; 910241675Suqs else 911241675Suqs abort(); 912241675Suqs 913241675Suqs return(1); 914241675Suqs} 915241675Suqs 916241675Suqsstatic int 917241675Suqspre_std(PRE_ARGS) 918241675Suqs{ 919241675Suqs 920241675Suqs if (n->args && 1 == n->args->argc) 921241675Suqs if (MDOC_Std == n->args->argv[0].arg) 922241675Suqs return(1); 923241675Suqs 924241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_NOARGV); 925241675Suqs return(1); 926241675Suqs} 927241675Suqs 928241675Suqsstatic int 929241675Suqspre_dt(PRE_ARGS) 930241675Suqs{ 931241675Suqs 932241675Suqs if (NULL == mdoc->meta.date || mdoc->meta.os) 933241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); 934241675Suqs 935241675Suqs if (mdoc->meta.title) 936241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP); 937241675Suqs 938241675Suqs return(1); 939241675Suqs} 940241675Suqs 941241675Suqsstatic int 942241675Suqspre_os(PRE_ARGS) 943241675Suqs{ 944241675Suqs 945241675Suqs if (NULL == mdoc->meta.title || NULL == mdoc->meta.date) 946241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); 947241675Suqs 948241675Suqs if (mdoc->meta.os) 949241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP); 950241675Suqs 951241675Suqs return(1); 952241675Suqs} 953241675Suqs 954241675Suqsstatic int 955241675Suqspre_dd(PRE_ARGS) 956241675Suqs{ 957241675Suqs 958241675Suqs if (mdoc->meta.title || mdoc->meta.os) 959241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); 960241675Suqs 961241675Suqs if (mdoc->meta.date) 962241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP); 963241675Suqs 964241675Suqs return(1); 965241675Suqs} 966241675Suqs 967241675Suqs 968241675Suqsstatic int 969241675Suqspost_bf(POST_ARGS) 970241675Suqs{ 971241675Suqs struct mdoc_node *np; 972241675Suqs enum mdocargt arg; 973241675Suqs 974241675Suqs /* 975241675Suqs * Unlike other data pointers, these are "housed" by the HEAD 976241675Suqs * element, which contains the goods. 977241675Suqs */ 978241675Suqs 979241675Suqs if (MDOC_HEAD != mdoc->last->type) { 980241675Suqs if (ENDBODY_NOT != mdoc->last->end) { 981241675Suqs assert(mdoc->last->pending); 982241675Suqs np = mdoc->last->pending->parent->head; 983241675Suqs } else if (MDOC_BLOCK != mdoc->last->type) { 984241675Suqs np = mdoc->last->parent->head; 985241675Suqs } else 986241675Suqs np = mdoc->last->head; 987241675Suqs 988241675Suqs assert(np); 989241675Suqs assert(MDOC_HEAD == np->type); 990241675Suqs assert(MDOC_Bf == np->tok); 991241675Suqs return(1); 992241675Suqs } 993241675Suqs 994241675Suqs np = mdoc->last; 995241675Suqs assert(MDOC_BLOCK == np->parent->type); 996241675Suqs assert(MDOC_Bf == np->parent->tok); 997241675Suqs 998241675Suqs /* 999241675Suqs * Cannot have both argument and parameter. 1000241675Suqs * If neither is specified, let it through with a warning. 1001241675Suqs */ 1002241675Suqs 1003241675Suqs if (np->parent->args && np->child) { 1004241675Suqs mdoc_nmsg(mdoc, np, MANDOCERR_SYNTARGVCOUNT); 1005241675Suqs return(0); 1006241675Suqs } else if (NULL == np->parent->args && NULL == np->child) { 1007241675Suqs mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE); 1008241675Suqs return(1); 1009241675Suqs } 1010241675Suqs 1011241675Suqs /* Extract argument into data. */ 1012241675Suqs 1013241675Suqs if (np->parent->args) { 1014241675Suqs arg = np->parent->args->argv[0].arg; 1015241675Suqs if (MDOC_Emphasis == arg) 1016241675Suqs np->norm->Bf.font = FONT_Em; 1017241675Suqs else if (MDOC_Literal == arg) 1018241675Suqs np->norm->Bf.font = FONT_Li; 1019241675Suqs else if (MDOC_Symbolic == arg) 1020241675Suqs np->norm->Bf.font = FONT_Sy; 1021241675Suqs else 1022241675Suqs abort(); 1023241675Suqs return(1); 1024241675Suqs } 1025241675Suqs 1026241675Suqs /* Extract parameter into data. */ 1027241675Suqs 1028241675Suqs if (0 == strcmp(np->child->string, "Em")) 1029241675Suqs np->norm->Bf.font = FONT_Em; 1030241675Suqs else if (0 == strcmp(np->child->string, "Li")) 1031241675Suqs np->norm->Bf.font = FONT_Li; 1032241675Suqs else if (0 == strcmp(np->child->string, "Sy")) 1033241675Suqs np->norm->Bf.font = FONT_Sy; 1034241675Suqs else 1035241675Suqs mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE); 1036241675Suqs 1037241675Suqs return(1); 1038241675Suqs} 1039241675Suqs 1040241675Suqsstatic int 1041241675Suqspost_lb(POST_ARGS) 1042241675Suqs{ 1043241675Suqs const char *p; 1044241675Suqs char *buf; 1045241675Suqs size_t sz; 1046241675Suqs 1047241675Suqs check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1); 1048241675Suqs 1049241675Suqs assert(mdoc->last->child); 1050241675Suqs assert(MDOC_TEXT == mdoc->last->child->type); 1051241675Suqs 1052241675Suqs p = mdoc_a2lib(mdoc->last->child->string); 1053241675Suqs 1054241675Suqs /* If lookup ok, replace with table value. */ 1055241675Suqs 1056241675Suqs if (p) { 1057241675Suqs free(mdoc->last->child->string); 1058241675Suqs mdoc->last->child->string = mandoc_strdup(p); 1059241675Suqs return(1); 1060241675Suqs } 1061241675Suqs 1062241675Suqs /* If not, use "library ``xxxx''. */ 1063241675Suqs 1064241675Suqs sz = strlen(mdoc->last->child->string) + 1065241675Suqs 2 + strlen("\\(lqlibrary\\(rq"); 1066241675Suqs buf = mandoc_malloc(sz); 1067241675Suqs snprintf(buf, sz, "library \\(lq%s\\(rq", 1068241675Suqs mdoc->last->child->string); 1069241675Suqs free(mdoc->last->child->string); 1070241675Suqs mdoc->last->child->string = buf; 1071241675Suqs return(1); 1072241675Suqs} 1073241675Suqs 1074241675Suqsstatic int 1075241675Suqspost_eoln(POST_ARGS) 1076241675Suqs{ 1077241675Suqs 1078241675Suqs if (mdoc->last->child) 1079241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST); 1080241675Suqs return(1); 1081241675Suqs} 1082241675Suqs 1083241675Suqs 1084241675Suqsstatic int 1085241675Suqspost_vt(POST_ARGS) 1086241675Suqs{ 1087241675Suqs const struct mdoc_node *n; 1088241675Suqs 1089241675Suqs /* 1090241675Suqs * The Vt macro comes in both ELEM and BLOCK form, both of which 1091241675Suqs * have different syntaxes (yet more context-sensitive 1092241675Suqs * behaviour). ELEM types must have a child, which is already 1093241675Suqs * guaranteed by the in_line parsing routine; BLOCK types, 1094241675Suqs * specifically the BODY, should only have TEXT children. 1095241675Suqs */ 1096241675Suqs 1097241675Suqs if (MDOC_BODY != mdoc->last->type) 1098241675Suqs return(1); 1099241675Suqs 1100241675Suqs for (n = mdoc->last->child; n; n = n->next) 1101241675Suqs if (MDOC_TEXT != n->type) 1102241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_CHILD); 1103241675Suqs 1104241675Suqs return(1); 1105241675Suqs} 1106241675Suqs 1107241675Suqs 1108241675Suqsstatic int 1109241675Suqspost_nm(POST_ARGS) 1110241675Suqs{ 1111241675Suqs char buf[BUFSIZ]; 1112241675Suqs int c; 1113241675Suqs 1114241675Suqs /* If no child specified, make sure we have the meta name. */ 1115241675Suqs 1116241675Suqs if (NULL == mdoc->last->child && NULL == mdoc->meta.name) { 1117241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME); 1118241675Suqs return(1); 1119241675Suqs } else if (mdoc->meta.name) 1120241675Suqs return(1); 1121241675Suqs 1122241675Suqs /* If no meta name, set it from the child. */ 1123241675Suqs 1124241675Suqs buf[0] = '\0'; 1125241675Suqs if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) { 1126241675Suqs mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM); 1127241675Suqs return(0); 1128241675Suqs } 1129241675Suqs 1130241675Suqs assert(c); 1131241675Suqs mdoc->meta.name = mandoc_strdup(buf); 1132241675Suqs return(1); 1133241675Suqs} 1134241675Suqs 1135241675Suqsstatic int 1136241675Suqspost_literal(POST_ARGS) 1137241675Suqs{ 1138241675Suqs 1139241675Suqs /* 1140241675Suqs * The `Dl' (note "el" not "one") and `Bd' macros unset the 1141241675Suqs * MDOC_LITERAL flag as they leave. Note that `Bd' only sets 1142241675Suqs * this in literal mode, but it doesn't hurt to just switch it 1143241675Suqs * off in general since displays can't be nested. 1144241675Suqs */ 1145241675Suqs 1146241675Suqs if (MDOC_BODY == mdoc->last->type) 1147241675Suqs mdoc->flags &= ~MDOC_LITERAL; 1148241675Suqs 1149241675Suqs return(1); 1150241675Suqs} 1151241675Suqs 1152241675Suqsstatic int 1153241675Suqspost_defaults(POST_ARGS) 1154241675Suqs{ 1155241675Suqs struct mdoc_node *nn; 1156241675Suqs 1157241675Suqs /* 1158241675Suqs * The `Ar' defaults to "file ..." if no value is provided as an 1159241675Suqs * argument; the `Mt' and `Pa' macros use "~"; the `Li' just 1160241675Suqs * gets an empty string. 1161241675Suqs */ 1162241675Suqs 1163241675Suqs if (mdoc->last->child) 1164241675Suqs return(1); 1165241675Suqs 1166241675Suqs nn = mdoc->last; 1167241675Suqs mdoc->next = MDOC_NEXT_CHILD; 1168241675Suqs 1169241675Suqs switch (nn->tok) { 1170241675Suqs case (MDOC_Ar): 1171241675Suqs if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file")) 1172241675Suqs return(0); 1173241675Suqs if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "...")) 1174241675Suqs return(0); 1175241675Suqs break; 1176241675Suqs case (MDOC_At): 1177241675Suqs if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "AT&T")) 1178241675Suqs return(0); 1179241675Suqs if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "UNIX")) 1180241675Suqs return(0); 1181241675Suqs break; 1182241675Suqs case (MDOC_Li): 1183241675Suqs if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "")) 1184241675Suqs return(0); 1185241675Suqs break; 1186241675Suqs case (MDOC_Pa): 1187241675Suqs /* FALLTHROUGH */ 1188241675Suqs case (MDOC_Mt): 1189241675Suqs if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~")) 1190241675Suqs return(0); 1191241675Suqs break; 1192241675Suqs default: 1193241675Suqs abort(); 1194241675Suqs /* NOTREACHED */ 1195241675Suqs } 1196241675Suqs 1197241675Suqs mdoc->last = nn; 1198241675Suqs return(1); 1199241675Suqs} 1200241675Suqs 1201241675Suqsstatic int 1202241675Suqspost_at(POST_ARGS) 1203241675Suqs{ 1204241675Suqs const char *p, *q; 1205241675Suqs char *buf; 1206241675Suqs size_t sz; 1207241675Suqs 1208241675Suqs /* 1209241675Suqs * If we have a child, look it up in the standard keys. If a 1210241675Suqs * key exist, use that instead of the child; if it doesn't, 1211241675Suqs * prefix "AT&T UNIX " to the existing data. 1212241675Suqs */ 1213241675Suqs 1214241675Suqs if (NULL == mdoc->last->child) 1215241675Suqs return(1); 1216241675Suqs 1217241675Suqs assert(MDOC_TEXT == mdoc->last->child->type); 1218241675Suqs p = mdoc_a2att(mdoc->last->child->string); 1219241675Suqs 1220241675Suqs if (p) { 1221241675Suqs free(mdoc->last->child->string); 1222241675Suqs mdoc->last->child->string = mandoc_strdup(p); 1223241675Suqs } else { 1224241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT); 1225241675Suqs p = "AT&T UNIX "; 1226241675Suqs q = mdoc->last->child->string; 1227241675Suqs sz = strlen(p) + strlen(q) + 1; 1228241675Suqs buf = mandoc_malloc(sz); 1229241675Suqs strlcpy(buf, p, sz); 1230241675Suqs strlcat(buf, q, sz); 1231241675Suqs free(mdoc->last->child->string); 1232241675Suqs mdoc->last->child->string = buf; 1233241675Suqs } 1234241675Suqs 1235241675Suqs return(1); 1236241675Suqs} 1237241675Suqs 1238241675Suqsstatic int 1239241675Suqspost_an(POST_ARGS) 1240241675Suqs{ 1241241675Suqs struct mdoc_node *np; 1242241675Suqs 1243241675Suqs np = mdoc->last; 1244241675Suqs if (AUTH__NONE == np->norm->An.auth) { 1245241675Suqs if (0 == np->child) 1246241675Suqs check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0); 1247241675Suqs } else if (np->child) 1248241675Suqs check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0); 1249241675Suqs 1250241675Suqs return(1); 1251241675Suqs} 1252241675Suqs 1253241675Suqs 1254241675Suqsstatic int 1255241675Suqspost_it(POST_ARGS) 1256241675Suqs{ 1257241675Suqs int i, cols; 1258241675Suqs enum mdoc_list lt; 1259241675Suqs struct mdoc_node *n, *c; 1260241675Suqs enum mandocerr er; 1261241675Suqs 1262241675Suqs if (MDOC_BLOCK != mdoc->last->type) 1263241675Suqs return(1); 1264241675Suqs 1265241675Suqs n = mdoc->last->parent->parent; 1266241675Suqs lt = n->norm->Bl.type; 1267241675Suqs 1268241675Suqs if (LIST__NONE == lt) { 1269241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE); 1270241675Suqs return(1); 1271241675Suqs } 1272241675Suqs 1273241675Suqs switch (lt) { 1274241675Suqs case (LIST_tag): 1275241675Suqs if (mdoc->last->head->child) 1276241675Suqs break; 1277241675Suqs /* FIXME: give this a dummy value. */ 1278241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS); 1279241675Suqs break; 1280241675Suqs case (LIST_hang): 1281241675Suqs /* FALLTHROUGH */ 1282241675Suqs case (LIST_ohang): 1283241675Suqs /* FALLTHROUGH */ 1284241675Suqs case (LIST_inset): 1285241675Suqs /* FALLTHROUGH */ 1286241675Suqs case (LIST_diag): 1287241675Suqs if (NULL == mdoc->last->head->child) 1288241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS); 1289241675Suqs break; 1290241675Suqs case (LIST_bullet): 1291241675Suqs /* FALLTHROUGH */ 1292241675Suqs case (LIST_dash): 1293241675Suqs /* FALLTHROUGH */ 1294241675Suqs case (LIST_enum): 1295241675Suqs /* FALLTHROUGH */ 1296241675Suqs case (LIST_hyphen): 1297241675Suqs if (NULL == mdoc->last->body->child) 1298241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY); 1299241675Suqs /* FALLTHROUGH */ 1300241675Suqs case (LIST_item): 1301241675Suqs if (mdoc->last->head->child) 1302241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST); 1303241675Suqs break; 1304241675Suqs case (LIST_column): 1305241675Suqs cols = (int)n->norm->Bl.ncols; 1306241675Suqs 1307241675Suqs assert(NULL == mdoc->last->head->child); 1308241675Suqs 1309241675Suqs if (NULL == mdoc->last->body->child) 1310241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY); 1311241675Suqs 1312241675Suqs for (i = 0, c = mdoc->last->child; c; c = c->next) 1313241675Suqs if (MDOC_BODY == c->type) 1314241675Suqs i++; 1315241675Suqs 1316241675Suqs if (i < cols) 1317241675Suqs er = MANDOCERR_ARGCOUNT; 1318241675Suqs else if (i == cols || i == cols + 1) 1319241675Suqs break; 1320241675Suqs else 1321241675Suqs er = MANDOCERR_SYNTARGCOUNT; 1322241675Suqs 1323241675Suqs mandoc_vmsg(er, mdoc->parse, mdoc->last->line, 1324241675Suqs mdoc->last->pos, 1325241675Suqs "columns == %d (have %d)", cols, i); 1326241675Suqs return(MANDOCERR_ARGCOUNT == er); 1327241675Suqs default: 1328241675Suqs break; 1329241675Suqs } 1330241675Suqs 1331241675Suqs return(1); 1332241675Suqs} 1333241675Suqs 1334241675Suqsstatic int 1335241675Suqspost_bl_block(POST_ARGS) 1336241675Suqs{ 1337241675Suqs struct mdoc_node *n; 1338241675Suqs 1339241675Suqs /* 1340241675Suqs * These are fairly complicated, so we've broken them into two 1341241675Suqs * functions. post_bl_block_tag() is called when a -tag is 1342241675Suqs * specified, but no -width (it must be guessed). The second 1343241675Suqs * when a -width is specified (macro indicators must be 1344241675Suqs * rewritten into real lengths). 1345241675Suqs */ 1346241675Suqs 1347241675Suqs n = mdoc->last; 1348241675Suqs 1349241675Suqs if (LIST_tag == n->norm->Bl.type && 1350241675Suqs NULL == n->norm->Bl.width) { 1351241675Suqs if ( ! post_bl_block_tag(mdoc)) 1352241675Suqs return(0); 1353241675Suqs } else if (NULL != n->norm->Bl.width) { 1354241675Suqs if ( ! post_bl_block_width(mdoc)) 1355241675Suqs return(0); 1356241675Suqs } else 1357241675Suqs return(1); 1358241675Suqs 1359241675Suqs assert(n->norm->Bl.width); 1360241675Suqs return(1); 1361241675Suqs} 1362241675Suqs 1363241675Suqsstatic int 1364241675Suqspost_bl_block_width(POST_ARGS) 1365241675Suqs{ 1366241675Suqs size_t width; 1367241675Suqs int i; 1368241675Suqs enum mdoct tok; 1369241675Suqs struct mdoc_node *n; 1370241675Suqs char buf[NUMSIZ]; 1371241675Suqs 1372241675Suqs n = mdoc->last; 1373241675Suqs 1374241675Suqs /* 1375241675Suqs * Calculate the real width of a list from the -width string, 1376241675Suqs * which may contain a macro (with a known default width), a 1377241675Suqs * literal string, or a scaling width. 1378241675Suqs * 1379241675Suqs * If the value to -width is a macro, then we re-write it to be 1380241675Suqs * the macro's width as set in share/tmac/mdoc/doc-common. 1381241675Suqs */ 1382241675Suqs 1383241675Suqs if (0 == strcmp(n->norm->Bl.width, "Ds")) 1384241675Suqs width = 6; 1385241675Suqs else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width))) 1386241675Suqs return(1); 1387241675Suqs else if (0 == (width = macro2len(tok))) { 1388241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH); 1389241675Suqs return(1); 1390241675Suqs } 1391241675Suqs 1392241675Suqs /* The value already exists: free and reallocate it. */ 1393241675Suqs 1394241675Suqs assert(n->args); 1395241675Suqs 1396241675Suqs for (i = 0; i < (int)n->args->argc; i++) 1397241675Suqs if (MDOC_Width == n->args->argv[i].arg) 1398241675Suqs break; 1399241675Suqs 1400241675Suqs assert(i < (int)n->args->argc); 1401241675Suqs 1402241675Suqs snprintf(buf, NUMSIZ, "%un", (unsigned int)width); 1403241675Suqs free(n->args->argv[i].value[0]); 1404241675Suqs n->args->argv[i].value[0] = mandoc_strdup(buf); 1405241675Suqs 1406241675Suqs /* Set our width! */ 1407241675Suqs n->norm->Bl.width = n->args->argv[i].value[0]; 1408241675Suqs return(1); 1409241675Suqs} 1410241675Suqs 1411241675Suqsstatic int 1412241675Suqspost_bl_block_tag(POST_ARGS) 1413241675Suqs{ 1414241675Suqs struct mdoc_node *n, *nn; 1415241675Suqs size_t sz, ssz; 1416241675Suqs int i; 1417241675Suqs char buf[NUMSIZ]; 1418241675Suqs 1419241675Suqs /* 1420241675Suqs * Calculate the -width for a `Bl -tag' list if it hasn't been 1421241675Suqs * provided. Uses the first head macro. NOTE AGAIN: this is 1422241675Suqs * ONLY if the -width argument has NOT been provided. See 1423241675Suqs * post_bl_block_width() for converting the -width string. 1424241675Suqs */ 1425241675Suqs 1426241675Suqs sz = 10; 1427241675Suqs n = mdoc->last; 1428241675Suqs 1429241675Suqs for (nn = n->body->child; nn; nn = nn->next) { 1430241675Suqs if (MDOC_It != nn->tok) 1431241675Suqs continue; 1432241675Suqs 1433241675Suqs assert(MDOC_BLOCK == nn->type); 1434241675Suqs nn = nn->head->child; 1435241675Suqs 1436241675Suqs if (nn == NULL) 1437241675Suqs break; 1438241675Suqs 1439241675Suqs if (MDOC_TEXT == nn->type) { 1440241675Suqs sz = strlen(nn->string) + 1; 1441241675Suqs break; 1442241675Suqs } 1443241675Suqs 1444241675Suqs if (0 != (ssz = macro2len(nn->tok))) 1445241675Suqs sz = ssz; 1446241675Suqs 1447241675Suqs break; 1448241675Suqs } 1449241675Suqs 1450241675Suqs /* Defaults to ten ens. */ 1451241675Suqs 1452241675Suqs snprintf(buf, NUMSIZ, "%un", (unsigned int)sz); 1453241675Suqs 1454241675Suqs /* 1455241675Suqs * We have to dynamically add this to the macro's argument list. 1456241675Suqs * We're guaranteed that a MDOC_Width doesn't already exist. 1457241675Suqs */ 1458241675Suqs 1459241675Suqs assert(n->args); 1460241675Suqs i = (int)(n->args->argc)++; 1461241675Suqs 1462241675Suqs n->args->argv = mandoc_realloc(n->args->argv, 1463241675Suqs n->args->argc * sizeof(struct mdoc_argv)); 1464241675Suqs 1465241675Suqs n->args->argv[i].arg = MDOC_Width; 1466241675Suqs n->args->argv[i].line = n->line; 1467241675Suqs n->args->argv[i].pos = n->pos; 1468241675Suqs n->args->argv[i].sz = 1; 1469241675Suqs n->args->argv[i].value = mandoc_malloc(sizeof(char *)); 1470241675Suqs n->args->argv[i].value[0] = mandoc_strdup(buf); 1471241675Suqs 1472241675Suqs /* Set our width! */ 1473241675Suqs n->norm->Bl.width = n->args->argv[i].value[0]; 1474241675Suqs return(1); 1475241675Suqs} 1476241675Suqs 1477241675Suqs 1478241675Suqsstatic int 1479241675Suqspost_bl_head(POST_ARGS) 1480241675Suqs{ 1481241675Suqs struct mdoc_node *np, *nn, *nnp; 1482241675Suqs int i, j; 1483241675Suqs 1484241675Suqs if (LIST_column != mdoc->last->norm->Bl.type) 1485241675Suqs /* FIXME: this should be ERROR class... */ 1486241675Suqs return(hwarn_eq0(mdoc)); 1487241675Suqs 1488241675Suqs /* 1489241675Suqs * Convert old-style lists, where the column width specifiers 1490241675Suqs * trail as macro parameters, to the new-style ("normal-form") 1491241675Suqs * lists where they're argument values following -column. 1492241675Suqs */ 1493241675Suqs 1494241675Suqs /* First, disallow both types and allow normal-form. */ 1495241675Suqs 1496241675Suqs /* 1497241675Suqs * TODO: technically, we can accept both and just merge the two 1498241675Suqs * lists, but I'll leave that for another day. 1499241675Suqs */ 1500241675Suqs 1501241675Suqs if (mdoc->last->norm->Bl.ncols && mdoc->last->nchild) { 1502241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_COLUMNS); 1503241675Suqs return(0); 1504241675Suqs } else if (NULL == mdoc->last->child) 1505241675Suqs return(1); 1506241675Suqs 1507241675Suqs np = mdoc->last->parent; 1508241675Suqs assert(np->args); 1509241675Suqs 1510241675Suqs for (j = 0; j < (int)np->args->argc; j++) 1511241675Suqs if (MDOC_Column == np->args->argv[j].arg) 1512241675Suqs break; 1513241675Suqs 1514241675Suqs assert(j < (int)np->args->argc); 1515241675Suqs assert(0 == np->args->argv[j].sz); 1516241675Suqs 1517241675Suqs /* 1518241675Suqs * Accommodate for new-style groff column syntax. Shuffle the 1519241675Suqs * child nodes, all of which must be TEXT, as arguments for the 1520241675Suqs * column field. Then, delete the head children. 1521241675Suqs */ 1522241675Suqs 1523241675Suqs np->args->argv[j].sz = (size_t)mdoc->last->nchild; 1524241675Suqs np->args->argv[j].value = mandoc_malloc 1525241675Suqs ((size_t)mdoc->last->nchild * sizeof(char *)); 1526241675Suqs 1527241675Suqs mdoc->last->norm->Bl.ncols = np->args->argv[j].sz; 1528241675Suqs mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value; 1529241675Suqs 1530241675Suqs for (i = 0, nn = mdoc->last->child; nn; i++) { 1531241675Suqs np->args->argv[j].value[i] = nn->string; 1532241675Suqs nn->string = NULL; 1533241675Suqs nnp = nn; 1534241675Suqs nn = nn->next; 1535241675Suqs mdoc_node_delete(NULL, nnp); 1536241675Suqs } 1537241675Suqs 1538241675Suqs mdoc->last->nchild = 0; 1539241675Suqs mdoc->last->child = NULL; 1540241675Suqs 1541241675Suqs return(1); 1542241675Suqs} 1543241675Suqs 1544241675Suqsstatic int 1545241675Suqspost_bl(POST_ARGS) 1546241675Suqs{ 1547241675Suqs struct mdoc_node *n; 1548241675Suqs 1549241675Suqs if (MDOC_HEAD == mdoc->last->type) 1550241675Suqs return(post_bl_head(mdoc)); 1551241675Suqs if (MDOC_BLOCK == mdoc->last->type) 1552241675Suqs return(post_bl_block(mdoc)); 1553241675Suqs if (MDOC_BODY != mdoc->last->type) 1554241675Suqs return(1); 1555241675Suqs 1556241675Suqs for (n = mdoc->last->child; n; n = n->next) { 1557241675Suqs switch (n->tok) { 1558241675Suqs case (MDOC_Lp): 1559241675Suqs /* FALLTHROUGH */ 1560241675Suqs case (MDOC_Pp): 1561241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_CHILD); 1562241675Suqs /* FALLTHROUGH */ 1563241675Suqs case (MDOC_It): 1564241675Suqs /* FALLTHROUGH */ 1565241675Suqs case (MDOC_Sm): 1566241675Suqs continue; 1567241675Suqs default: 1568241675Suqs break; 1569241675Suqs } 1570241675Suqs 1571241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_SYNTCHILD); 1572241675Suqs return(0); 1573241675Suqs } 1574241675Suqs 1575241675Suqs return(1); 1576241675Suqs} 1577241675Suqs 1578241675Suqsstatic int 1579241675Suqsebool(struct mdoc *mdoc) 1580241675Suqs{ 1581241675Suqs 1582241675Suqs if (NULL == mdoc->last->child) { 1583241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY); 1584241675Suqs mdoc_node_delete(mdoc, mdoc->last); 1585241675Suqs return(1); 1586241675Suqs } 1587241675Suqs check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1); 1588241675Suqs 1589241675Suqs assert(MDOC_TEXT == mdoc->last->child->type); 1590241675Suqs 1591241675Suqs if (0 == strcmp(mdoc->last->child->string, "on")) 1592241675Suqs return(1); 1593241675Suqs if (0 == strcmp(mdoc->last->child->string, "off")) 1594241675Suqs return(1); 1595241675Suqs 1596241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL); 1597241675Suqs return(1); 1598241675Suqs} 1599241675Suqs 1600241675Suqsstatic int 1601241675Suqspost_root(POST_ARGS) 1602241675Suqs{ 1603241675Suqs int erc; 1604241675Suqs struct mdoc_node *n; 1605241675Suqs 1606241675Suqs erc = 0; 1607241675Suqs 1608241675Suqs /* Check that we have a finished prologue. */ 1609241675Suqs 1610241675Suqs if ( ! (MDOC_PBODY & mdoc->flags)) { 1611241675Suqs erc++; 1612241675Suqs mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG); 1613241675Suqs } 1614241675Suqs 1615241675Suqs n = mdoc->first; 1616241675Suqs assert(n); 1617241675Suqs 1618241675Suqs /* Check that we begin with a proper `Sh'. */ 1619241675Suqs 1620241675Suqs if (NULL == n->child) { 1621241675Suqs erc++; 1622241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY); 1623241675Suqs } else if (MDOC_BLOCK != n->child->type || 1624241675Suqs MDOC_Sh != n->child->tok) { 1625241675Suqs erc++; 1626241675Suqs /* Can this be lifted? See rxdebug.1 for example. */ 1627241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY); 1628241675Suqs } 1629241675Suqs 1630241675Suqs return(erc ? 0 : 1); 1631241675Suqs} 1632241675Suqs 1633241675Suqsstatic int 1634241675Suqspost_st(POST_ARGS) 1635241675Suqs{ 1636241675Suqs struct mdoc_node *ch; 1637241675Suqs const char *p; 1638241675Suqs 1639241675Suqs if (NULL == (ch = mdoc->last->child)) { 1640241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY); 1641241675Suqs mdoc_node_delete(mdoc, mdoc->last); 1642241675Suqs return(1); 1643241675Suqs } 1644241675Suqs 1645241675Suqs assert(MDOC_TEXT == ch->type); 1646241675Suqs 1647241675Suqs if (NULL == (p = mdoc_a2st(ch->string))) { 1648241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD); 1649241675Suqs mdoc_node_delete(mdoc, mdoc->last); 1650241675Suqs } else { 1651241675Suqs free(ch->string); 1652241675Suqs ch->string = mandoc_strdup(p); 1653241675Suqs } 1654241675Suqs 1655241675Suqs return(1); 1656241675Suqs} 1657241675Suqs 1658241675Suqsstatic int 1659241675Suqspost_rs(POST_ARGS) 1660241675Suqs{ 1661241675Suqs struct mdoc_node *nn, *next, *prev; 1662241675Suqs int i, j; 1663241675Suqs 1664241675Suqs switch (mdoc->last->type) { 1665241675Suqs case (MDOC_HEAD): 1666241675Suqs check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0); 1667241675Suqs return(1); 1668241675Suqs case (MDOC_BODY): 1669241675Suqs if (mdoc->last->child) 1670241675Suqs break; 1671241675Suqs check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0); 1672241675Suqs return(1); 1673241675Suqs default: 1674241675Suqs return(1); 1675241675Suqs } 1676241675Suqs 1677241675Suqs /* 1678241675Suqs * Make sure only certain types of nodes are allowed within the 1679241675Suqs * the `Rs' body. Delete offending nodes and raise a warning. 1680241675Suqs * Do this before re-ordering for the sake of clarity. 1681241675Suqs */ 1682241675Suqs 1683241675Suqs next = NULL; 1684241675Suqs for (nn = mdoc->last->child; nn; nn = next) { 1685241675Suqs for (i = 0; i < RSORD_MAX; i++) 1686241675Suqs if (nn->tok == rsord[i]) 1687241675Suqs break; 1688241675Suqs 1689241675Suqs if (i < RSORD_MAX) { 1690241675Suqs if (MDOC__J == rsord[i] || MDOC__B == rsord[i]) 1691241675Suqs mdoc->last->norm->Rs.quote_T++; 1692241675Suqs next = nn->next; 1693241675Suqs continue; 1694241675Suqs } 1695241675Suqs 1696241675Suqs next = nn->next; 1697241675Suqs mdoc_nmsg(mdoc, nn, MANDOCERR_CHILD); 1698241675Suqs mdoc_node_delete(mdoc, nn); 1699241675Suqs } 1700241675Suqs 1701241675Suqs /* 1702241675Suqs * Nothing to sort if only invalid nodes were found 1703241675Suqs * inside the `Rs' body. 1704241675Suqs */ 1705241675Suqs 1706241675Suqs if (NULL == mdoc->last->child) 1707241675Suqs return(1); 1708241675Suqs 1709241675Suqs /* 1710241675Suqs * The full `Rs' block needs special handling to order the 1711241675Suqs * sub-elements according to `rsord'. Pick through each element 1712241675Suqs * and correctly order it. This is a insertion sort. 1713241675Suqs */ 1714241675Suqs 1715241675Suqs next = NULL; 1716241675Suqs for (nn = mdoc->last->child->next; nn; nn = next) { 1717241675Suqs /* Determine order of `nn'. */ 1718241675Suqs for (i = 0; i < RSORD_MAX; i++) 1719241675Suqs if (rsord[i] == nn->tok) 1720241675Suqs break; 1721241675Suqs 1722241675Suqs /* 1723241675Suqs * Remove `nn' from the chain. This somewhat 1724241675Suqs * repeats mdoc_node_unlink(), but since we're 1725241675Suqs * just re-ordering, there's no need for the 1726241675Suqs * full unlink process. 1727241675Suqs */ 1728241675Suqs 1729241675Suqs if (NULL != (next = nn->next)) 1730241675Suqs next->prev = nn->prev; 1731241675Suqs 1732241675Suqs if (NULL != (prev = nn->prev)) 1733241675Suqs prev->next = nn->next; 1734241675Suqs 1735241675Suqs nn->prev = nn->next = NULL; 1736241675Suqs 1737241675Suqs /* 1738241675Suqs * Scan back until we reach a node that's 1739241675Suqs * ordered before `nn'. 1740241675Suqs */ 1741241675Suqs 1742241675Suqs for ( ; prev ; prev = prev->prev) { 1743241675Suqs /* Determine order of `prev'. */ 1744241675Suqs for (j = 0; j < RSORD_MAX; j++) 1745241675Suqs if (rsord[j] == prev->tok) 1746241675Suqs break; 1747241675Suqs 1748241675Suqs if (j <= i) 1749241675Suqs break; 1750241675Suqs } 1751241675Suqs 1752241675Suqs /* 1753241675Suqs * Set `nn' back into its correct place in front 1754241675Suqs * of the `prev' node. 1755241675Suqs */ 1756241675Suqs 1757241675Suqs nn->prev = prev; 1758241675Suqs 1759241675Suqs if (prev) { 1760241675Suqs if (prev->next) 1761241675Suqs prev->next->prev = nn; 1762241675Suqs nn->next = prev->next; 1763241675Suqs prev->next = nn; 1764241675Suqs } else { 1765241675Suqs mdoc->last->child->prev = nn; 1766241675Suqs nn->next = mdoc->last->child; 1767241675Suqs mdoc->last->child = nn; 1768241675Suqs } 1769241675Suqs } 1770241675Suqs 1771241675Suqs return(1); 1772241675Suqs} 1773241675Suqs 1774241675Suqsstatic int 1775241675Suqspost_ns(POST_ARGS) 1776241675Suqs{ 1777241675Suqs 1778241675Suqs if (MDOC_LINE & mdoc->last->flags) 1779241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNNS); 1780241675Suqs return(1); 1781241675Suqs} 1782241675Suqs 1783241675Suqsstatic int 1784241675Suqspost_sh(POST_ARGS) 1785241675Suqs{ 1786241675Suqs 1787241675Suqs if (MDOC_HEAD == mdoc->last->type) 1788241675Suqs return(post_sh_head(mdoc)); 1789241675Suqs if (MDOC_BODY == mdoc->last->type) 1790241675Suqs return(post_sh_body(mdoc)); 1791241675Suqs 1792241675Suqs return(1); 1793241675Suqs} 1794241675Suqs 1795241675Suqsstatic int 1796241675Suqspost_sh_body(POST_ARGS) 1797241675Suqs{ 1798241675Suqs struct mdoc_node *n; 1799241675Suqs 1800241675Suqs if (SEC_NAME != mdoc->lastsec) 1801241675Suqs return(1); 1802241675Suqs 1803241675Suqs /* 1804241675Suqs * Warn if the NAME section doesn't contain the `Nm' and `Nd' 1805241675Suqs * macros (can have multiple `Nm' and one `Nd'). Note that the 1806241675Suqs * children of the BODY declaration can also be "text". 1807241675Suqs */ 1808241675Suqs 1809241675Suqs if (NULL == (n = mdoc->last->child)) { 1810241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC); 1811241675Suqs return(1); 1812241675Suqs } 1813241675Suqs 1814241675Suqs for ( ; n && n->next; n = n->next) { 1815241675Suqs if (MDOC_ELEM == n->type && MDOC_Nm == n->tok) 1816241675Suqs continue; 1817241675Suqs if (MDOC_TEXT == n->type) 1818241675Suqs continue; 1819241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC); 1820241675Suqs } 1821241675Suqs 1822241675Suqs assert(n); 1823241675Suqs if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok) 1824241675Suqs return(1); 1825241675Suqs 1826241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC); 1827241675Suqs return(1); 1828241675Suqs} 1829241675Suqs 1830241675Suqsstatic int 1831241675Suqspost_sh_head(POST_ARGS) 1832241675Suqs{ 1833241675Suqs char buf[BUFSIZ]; 1834241675Suqs struct mdoc_node *n; 1835241675Suqs enum mdoc_sec sec; 1836241675Suqs int c; 1837241675Suqs 1838241675Suqs /* 1839241675Suqs * Process a new section. Sections are either "named" or 1840241675Suqs * "custom". Custom sections are user-defined, while named ones 1841241675Suqs * follow a conventional order and may only appear in certain 1842241675Suqs * manual sections. 1843241675Suqs */ 1844241675Suqs 1845241675Suqs sec = SEC_CUSTOM; 1846241675Suqs buf[0] = '\0'; 1847241675Suqs if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) { 1848241675Suqs mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM); 1849241675Suqs return(0); 1850241675Suqs } else if (1 == c) 1851241675Suqs sec = a2sec(buf); 1852241675Suqs 1853241675Suqs /* The NAME should be first. */ 1854241675Suqs 1855241675Suqs if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed) 1856241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST); 1857241675Suqs 1858241675Suqs /* The SYNOPSIS gets special attention in other areas. */ 1859241675Suqs 1860241675Suqs if (SEC_SYNOPSIS == sec) 1861241675Suqs mdoc->flags |= MDOC_SYNOPSIS; 1862241675Suqs else 1863241675Suqs mdoc->flags &= ~MDOC_SYNOPSIS; 1864241675Suqs 1865241675Suqs /* Mark our last section. */ 1866241675Suqs 1867241675Suqs mdoc->lastsec = sec; 1868241675Suqs 1869241675Suqs /* 1870241675Suqs * Set the section attribute for the current HEAD, for its 1871241675Suqs * parent BLOCK, and for the HEAD children; the latter can 1872241675Suqs * only be TEXT nodes, so no recursion is needed. 1873241675Suqs * For other blocks and elements, including .Sh BODY, this is 1874241675Suqs * done when allocating the node data structures, but for .Sh 1875241675Suqs * BLOCK and HEAD, the section is still unknown at that time. 1876241675Suqs */ 1877241675Suqs 1878241675Suqs mdoc->last->parent->sec = sec; 1879241675Suqs mdoc->last->sec = sec; 1880241675Suqs for (n = mdoc->last->child; n; n = n->next) 1881241675Suqs n->sec = sec; 1882241675Suqs 1883241675Suqs /* We don't care about custom sections after this. */ 1884241675Suqs 1885241675Suqs if (SEC_CUSTOM == sec) 1886241675Suqs return(1); 1887241675Suqs 1888241675Suqs /* 1889241675Suqs * Check whether our non-custom section is being repeated or is 1890241675Suqs * out of order. 1891241675Suqs */ 1892241675Suqs 1893241675Suqs if (sec == mdoc->lastnamed) 1894241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECREP); 1895241675Suqs 1896241675Suqs if (sec < mdoc->lastnamed) 1897241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECOOO); 1898241675Suqs 1899241675Suqs /* Mark the last named section. */ 1900241675Suqs 1901241675Suqs mdoc->lastnamed = sec; 1902241675Suqs 1903241675Suqs /* Check particular section/manual conventions. */ 1904241675Suqs 1905241675Suqs assert(mdoc->meta.msec); 1906241675Suqs 1907241675Suqs switch (sec) { 1908241675Suqs case (SEC_RETURN_VALUES): 1909241675Suqs /* FALLTHROUGH */ 1910241675Suqs case (SEC_ERRORS): 1911241675Suqs /* FALLTHROUGH */ 1912241675Suqs case (SEC_LIBRARY): 1913241675Suqs if (*mdoc->meta.msec == '2') 1914241675Suqs break; 1915241675Suqs if (*mdoc->meta.msec == '3') 1916241675Suqs break; 1917241675Suqs if (*mdoc->meta.msec == '9') 1918241675Suqs break; 1919241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECMSEC); 1920241675Suqs break; 1921241675Suqs default: 1922241675Suqs break; 1923241675Suqs } 1924241675Suqs 1925241675Suqs return(1); 1926241675Suqs} 1927241675Suqs 1928241675Suqsstatic int 1929241675Suqspost_ignpar(POST_ARGS) 1930241675Suqs{ 1931241675Suqs struct mdoc_node *np; 1932241675Suqs 1933241675Suqs if (MDOC_BODY != mdoc->last->type) 1934241675Suqs return(1); 1935241675Suqs 1936241675Suqs if (NULL != (np = mdoc->last->child)) 1937241675Suqs if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 1938241675Suqs mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR); 1939241675Suqs mdoc_node_delete(mdoc, np); 1940241675Suqs } 1941241675Suqs 1942241675Suqs if (NULL != (np = mdoc->last->last)) 1943241675Suqs if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) { 1944241675Suqs mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR); 1945241675Suqs mdoc_node_delete(mdoc, np); 1946241675Suqs } 1947241675Suqs 1948241675Suqs return(1); 1949241675Suqs} 1950241675Suqs 1951241675Suqsstatic int 1952241675Suqspre_par(PRE_ARGS) 1953241675Suqs{ 1954241675Suqs 1955241675Suqs if (NULL == mdoc->last) 1956241675Suqs return(1); 1957241675Suqs if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type) 1958241675Suqs return(1); 1959241675Suqs 1960241675Suqs /* 1961241675Suqs * Don't allow prior `Lp' or `Pp' prior to a paragraph-type 1962241675Suqs * block: `Lp', `Pp', or non-compact `Bd' or `Bl'. 1963241675Suqs */ 1964241675Suqs 1965241675Suqs if (MDOC_Pp != mdoc->last->tok && MDOC_Lp != mdoc->last->tok) 1966241675Suqs return(1); 1967241675Suqs if (MDOC_Bl == n->tok && n->norm->Bl.comp) 1968241675Suqs return(1); 1969241675Suqs if (MDOC_Bd == n->tok && n->norm->Bd.comp) 1970241675Suqs return(1); 1971241675Suqs if (MDOC_It == n->tok && n->parent->norm->Bl.comp) 1972241675Suqs return(1); 1973241675Suqs 1974241675Suqs mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR); 1975241675Suqs mdoc_node_delete(mdoc, mdoc->last); 1976241675Suqs return(1); 1977241675Suqs} 1978241675Suqs 1979241675Suqsstatic int 1980241675Suqspre_literal(PRE_ARGS) 1981241675Suqs{ 1982241675Suqs 1983241675Suqs if (MDOC_BODY != n->type) 1984241675Suqs return(1); 1985241675Suqs 1986241675Suqs /* 1987241675Suqs * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd 1988241675Suqs * -unfilled' macros set MDOC_LITERAL on entrance to the body. 1989241675Suqs */ 1990241675Suqs 1991241675Suqs switch (n->tok) { 1992241675Suqs case (MDOC_Dl): 1993241675Suqs mdoc->flags |= MDOC_LITERAL; 1994241675Suqs break; 1995241675Suqs case (MDOC_Bd): 1996241675Suqs if (DISP_literal == n->norm->Bd.type) 1997241675Suqs mdoc->flags |= MDOC_LITERAL; 1998241675Suqs if (DISP_unfilled == n->norm->Bd.type) 1999241675Suqs mdoc->flags |= MDOC_LITERAL; 2000241675Suqs break; 2001241675Suqs default: 2002241675Suqs abort(); 2003241675Suqs /* NOTREACHED */ 2004241675Suqs } 2005241675Suqs 2006241675Suqs return(1); 2007241675Suqs} 2008241675Suqs 2009241675Suqsstatic int 2010241675Suqspost_dd(POST_ARGS) 2011241675Suqs{ 2012241675Suqs char buf[DATESIZE]; 2013241675Suqs struct mdoc_node *n; 2014241675Suqs int c; 2015241675Suqs 2016241675Suqs if (mdoc->meta.date) 2017241675Suqs free(mdoc->meta.date); 2018241675Suqs 2019241675Suqs n = mdoc->last; 2020241675Suqs if (NULL == n->child || '\0' == n->child->string[0]) { 2021241675Suqs mdoc->meta.date = mandoc_normdate 2022241675Suqs (mdoc->parse, NULL, n->line, n->pos); 2023241675Suqs return(1); 2024241675Suqs } 2025241675Suqs 2026241675Suqs buf[0] = '\0'; 2027241675Suqs if (-1 == (c = concat(buf, n->child, DATESIZE))) { 2028241675Suqs mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM); 2029241675Suqs return(0); 2030241675Suqs } 2031241675Suqs 2032241675Suqs assert(c); 2033241675Suqs mdoc->meta.date = mandoc_normdate 2034241675Suqs (mdoc->parse, buf, n->line, n->pos); 2035241675Suqs 2036241675Suqs return(1); 2037241675Suqs} 2038241675Suqs 2039241675Suqsstatic int 2040241675Suqspost_dt(POST_ARGS) 2041241675Suqs{ 2042241675Suqs struct mdoc_node *nn, *n; 2043241675Suqs const char *cp; 2044241675Suqs char *p; 2045241675Suqs 2046241675Suqs n = mdoc->last; 2047241675Suqs 2048241675Suqs if (mdoc->meta.title) 2049241675Suqs free(mdoc->meta.title); 2050241675Suqs if (mdoc->meta.vol) 2051241675Suqs free(mdoc->meta.vol); 2052241675Suqs if (mdoc->meta.arch) 2053241675Suqs free(mdoc->meta.arch); 2054241675Suqs 2055241675Suqs mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL; 2056241675Suqs 2057241675Suqs /* First make all characters uppercase. */ 2058241675Suqs 2059241675Suqs if (NULL != (nn = n->child)) 2060241675Suqs for (p = nn->string; *p; p++) { 2061241675Suqs if (toupper((unsigned char)*p) == *p) 2062241675Suqs continue; 2063241675Suqs 2064241675Suqs /* 2065241675Suqs * FIXME: don't be lazy: have this make all 2066241675Suqs * characters be uppercase and just warn once. 2067241675Suqs */ 2068241675Suqs mdoc_nmsg(mdoc, nn, MANDOCERR_UPPERCASE); 2069241675Suqs break; 2070241675Suqs } 2071241675Suqs 2072241675Suqs /* Handles: `.Dt' 2073241675Suqs * --> title = unknown, volume = local, msec = 0, arch = NULL 2074241675Suqs */ 2075241675Suqs 2076241675Suqs if (NULL == (nn = n->child)) { 2077241675Suqs /* XXX: make these macro values. */ 2078241675Suqs /* FIXME: warn about missing values. */ 2079241675Suqs mdoc->meta.title = mandoc_strdup("UNKNOWN"); 2080241675Suqs mdoc->meta.vol = mandoc_strdup("LOCAL"); 2081241675Suqs mdoc->meta.msec = mandoc_strdup("1"); 2082241675Suqs return(1); 2083241675Suqs } 2084241675Suqs 2085241675Suqs /* Handles: `.Dt TITLE' 2086241675Suqs * --> title = TITLE, volume = local, msec = 0, arch = NULL 2087241675Suqs */ 2088241675Suqs 2089241675Suqs mdoc->meta.title = mandoc_strdup 2090241675Suqs ('\0' == nn->string[0] ? "UNKNOWN" : nn->string); 2091241675Suqs 2092241675Suqs if (NULL == (nn = nn->next)) { 2093241675Suqs /* FIXME: warn about missing msec. */ 2094241675Suqs /* XXX: make this a macro value. */ 2095241675Suqs mdoc->meta.vol = mandoc_strdup("LOCAL"); 2096241675Suqs mdoc->meta.msec = mandoc_strdup("1"); 2097241675Suqs return(1); 2098241675Suqs } 2099241675Suqs 2100241675Suqs /* Handles: `.Dt TITLE SEC' 2101241675Suqs * --> title = TITLE, volume = SEC is msec ? 2102241675Suqs * format(msec) : SEC, 2103241675Suqs * msec = SEC is msec ? atoi(msec) : 0, 2104241675Suqs * arch = NULL 2105241675Suqs */ 2106241675Suqs 2107241675Suqs cp = mandoc_a2msec(nn->string); 2108241675Suqs if (cp) { 2109241675Suqs mdoc->meta.vol = mandoc_strdup(cp); 2110241675Suqs mdoc->meta.msec = mandoc_strdup(nn->string); 2111241675Suqs } else { 2112241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_BADMSEC); 2113241675Suqs mdoc->meta.vol = mandoc_strdup(nn->string); 2114241675Suqs mdoc->meta.msec = mandoc_strdup(nn->string); 2115241675Suqs } 2116241675Suqs 2117241675Suqs if (NULL == (nn = nn->next)) 2118241675Suqs return(1); 2119241675Suqs 2120241675Suqs /* Handles: `.Dt TITLE SEC VOL' 2121241675Suqs * --> title = TITLE, volume = VOL is vol ? 2122241675Suqs * format(VOL) : 2123241675Suqs * VOL is arch ? format(arch) : 2124241675Suqs * VOL 2125241675Suqs */ 2126241675Suqs 2127241675Suqs cp = mdoc_a2vol(nn->string); 2128241675Suqs if (cp) { 2129241675Suqs free(mdoc->meta.vol); 2130241675Suqs mdoc->meta.vol = mandoc_strdup(cp); 2131241675Suqs } else { 2132241675Suqs /* FIXME: warn about bad arch. */ 2133241675Suqs cp = mdoc_a2arch(nn->string); 2134241675Suqs if (NULL == cp) { 2135241675Suqs free(mdoc->meta.vol); 2136241675Suqs mdoc->meta.vol = mandoc_strdup(nn->string); 2137241675Suqs } else 2138241675Suqs mdoc->meta.arch = mandoc_strdup(cp); 2139241675Suqs } 2140241675Suqs 2141241675Suqs /* Ignore any subsequent parameters... */ 2142241675Suqs /* FIXME: warn about subsequent parameters. */ 2143241675Suqs 2144241675Suqs return(1); 2145241675Suqs} 2146241675Suqs 2147241675Suqsstatic int 2148241675Suqspost_prol(POST_ARGS) 2149241675Suqs{ 2150241675Suqs /* 2151241675Suqs * Remove prologue macros from the document after they're 2152241675Suqs * processed. The final document uses mdoc_meta for these 2153241675Suqs * values and discards the originals. 2154241675Suqs */ 2155241675Suqs 2156241675Suqs mdoc_node_delete(mdoc, mdoc->last); 2157241675Suqs if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os) 2158241675Suqs mdoc->flags |= MDOC_PBODY; 2159241675Suqs 2160241675Suqs return(1); 2161241675Suqs} 2162241675Suqs 2163241675Suqsstatic int 2164241675Suqspost_bx(POST_ARGS) 2165241675Suqs{ 2166241675Suqs struct mdoc_node *n; 2167241675Suqs 2168241675Suqs /* 2169241675Suqs * Make `Bx's second argument always start with an uppercase 2170241675Suqs * letter. Groff checks if it's an "accepted" term, but we just 2171241675Suqs * uppercase blindly. 2172241675Suqs */ 2173241675Suqs 2174241675Suqs n = mdoc->last->child; 2175241675Suqs if (n && NULL != (n = n->next)) 2176241675Suqs *n->string = (char)toupper 2177241675Suqs ((unsigned char)*n->string); 2178241675Suqs 2179241675Suqs return(1); 2180241675Suqs} 2181241675Suqs 2182241675Suqsstatic int 2183241675Suqspost_os(POST_ARGS) 2184241675Suqs{ 2185241675Suqs struct mdoc_node *n; 2186241675Suqs char buf[BUFSIZ]; 2187241675Suqs int c; 2188241675Suqs#ifndef OSNAME 2189241675Suqs struct utsname utsname; 2190241675Suqs#endif 2191241675Suqs 2192241675Suqs n = mdoc->last; 2193241675Suqs 2194241675Suqs /* 2195241675Suqs * Set the operating system by way of the `Os' macro. Note that 2196241675Suqs * if an argument isn't provided and -DOSNAME="\"foo\"" is 2197241675Suqs * provided during compilation, this value will be used instead 2198241675Suqs * of filling in "sysname release" from uname(). 2199241675Suqs */ 2200241675Suqs 2201241675Suqs if (mdoc->meta.os) 2202241675Suqs free(mdoc->meta.os); 2203241675Suqs 2204241675Suqs buf[0] = '\0'; 2205241675Suqs if (-1 == (c = concat(buf, n->child, BUFSIZ))) { 2206241675Suqs mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM); 2207241675Suqs return(0); 2208241675Suqs } 2209241675Suqs 2210241675Suqs assert(c); 2211241675Suqs 2212241675Suqs /* XXX: yes, these can all be dynamically-adjusted buffers, but 2213241675Suqs * it's really not worth the extra hackery. 2214241675Suqs */ 2215241675Suqs 2216241675Suqs if ('\0' == buf[0]) { 2217241675Suqs#ifdef OSNAME 2218241675Suqs if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) { 2219241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 2220241675Suqs return(0); 2221241675Suqs } 2222241675Suqs#else /*!OSNAME */ 2223241675Suqs if (-1 == uname(&utsname)) { 2224241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_UNAME); 2225241675Suqs mdoc->meta.os = mandoc_strdup("UNKNOWN"); 2226241675Suqs return(post_prol(mdoc)); 2227241675Suqs } 2228241675Suqs 2229241675Suqs if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) { 2230241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 2231241675Suqs return(0); 2232241675Suqs } 2233241675Suqs if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) { 2234241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 2235241675Suqs return(0); 2236241675Suqs } 2237241775Suqs if (0 == strcmp(utsname.sysname, "FreeBSD")) 2238241774Suqs strtok(utsname.release, "-"); 2239241675Suqs if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) { 2240241675Suqs mdoc_nmsg(mdoc, n, MANDOCERR_MEM); 2241241675Suqs return(0); 2242241675Suqs } 2243241675Suqs#endif /*!OSNAME*/ 2244241675Suqs } 2245241675Suqs 2246241675Suqs mdoc->meta.os = mandoc_strdup(buf); 2247241675Suqs return(1); 2248241675Suqs} 2249241675Suqs 2250241675Suqsstatic int 2251241675Suqspost_std(POST_ARGS) 2252241675Suqs{ 2253241675Suqs struct mdoc_node *nn, *n; 2254241675Suqs 2255241675Suqs n = mdoc->last; 2256241675Suqs 2257241675Suqs /* 2258241675Suqs * Macros accepting `-std' as an argument have the name of the 2259241675Suqs * current document (`Nm') filled in as the argument if it's not 2260241675Suqs * provided. 2261241675Suqs */ 2262241675Suqs 2263241675Suqs if (n->child) 2264241675Suqs return(1); 2265241675Suqs 2266241675Suqs if (NULL == mdoc->meta.name) 2267241675Suqs return(1); 2268241675Suqs 2269241675Suqs nn = n; 2270241675Suqs mdoc->next = MDOC_NEXT_CHILD; 2271241675Suqs 2272241675Suqs if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name)) 2273241675Suqs return(0); 2274241675Suqs 2275241675Suqs mdoc->last = nn; 2276241675Suqs return(1); 2277241675Suqs} 2278241675Suqs 2279241675Suqs/* 2280241675Suqs * Concatenate a node, stopping at the first non-text. 2281241675Suqs * Concatenation is separated by a single whitespace. 2282241675Suqs * Returns -1 on fatal (string overrun) error, 0 if child nodes were 2283241675Suqs * encountered, 1 otherwise. 2284241675Suqs */ 2285241675Suqsstatic int 2286241675Suqsconcat(char *p, const struct mdoc_node *n, size_t sz) 2287241675Suqs{ 2288241675Suqs 2289241675Suqs for ( ; NULL != n; n = n->next) { 2290241675Suqs if (MDOC_TEXT != n->type) 2291241675Suqs return(0); 2292241675Suqs if ('\0' != p[0] && strlcat(p, " ", sz) >= sz) 2293241675Suqs return(-1); 2294241675Suqs if (strlcat(p, n->string, sz) >= sz) 2295241675Suqs return(-1); 2296241675Suqs concat(p, n->child, sz); 2297241675Suqs } 2298241675Suqs 2299241675Suqs return(1); 2300241675Suqs} 2301241675Suqs 2302241675Suqsstatic enum mdoc_sec 2303241675Suqsa2sec(const char *p) 2304241675Suqs{ 2305241675Suqs int i; 2306241675Suqs 2307241675Suqs for (i = 0; i < (int)SEC__MAX; i++) 2308241675Suqs if (secnames[i] && 0 == strcmp(p, secnames[i])) 2309241675Suqs return((enum mdoc_sec)i); 2310241675Suqs 2311241675Suqs return(SEC_CUSTOM); 2312241675Suqs} 2313241675Suqs 2314241675Suqsstatic size_t 2315241675Suqsmacro2len(enum mdoct macro) 2316241675Suqs{ 2317241675Suqs 2318241675Suqs switch (macro) { 2319241675Suqs case(MDOC_Ad): 2320241675Suqs return(12); 2321241675Suqs case(MDOC_Ao): 2322241675Suqs return(12); 2323241675Suqs case(MDOC_An): 2324241675Suqs return(12); 2325241675Suqs case(MDOC_Aq): 2326241675Suqs return(12); 2327241675Suqs case(MDOC_Ar): 2328241675Suqs return(12); 2329241675Suqs case(MDOC_Bo): 2330241675Suqs return(12); 2331241675Suqs case(MDOC_Bq): 2332241675Suqs return(12); 2333241675Suqs case(MDOC_Cd): 2334241675Suqs return(12); 2335241675Suqs case(MDOC_Cm): 2336241675Suqs return(10); 2337241675Suqs case(MDOC_Do): 2338241675Suqs return(10); 2339241675Suqs case(MDOC_Dq): 2340241675Suqs return(12); 2341241675Suqs case(MDOC_Dv): 2342241675Suqs return(12); 2343241675Suqs case(MDOC_Eo): 2344241675Suqs return(12); 2345241675Suqs case(MDOC_Em): 2346241675Suqs return(10); 2347241675Suqs case(MDOC_Er): 2348241675Suqs return(17); 2349241675Suqs case(MDOC_Ev): 2350241675Suqs return(15); 2351241675Suqs case(MDOC_Fa): 2352241675Suqs return(12); 2353241675Suqs case(MDOC_Fl): 2354241675Suqs return(10); 2355241675Suqs case(MDOC_Fo): 2356241675Suqs return(16); 2357241675Suqs case(MDOC_Fn): 2358241675Suqs return(16); 2359241675Suqs case(MDOC_Ic): 2360241675Suqs return(10); 2361241675Suqs case(MDOC_Li): 2362241675Suqs return(16); 2363241675Suqs case(MDOC_Ms): 2364241675Suqs return(6); 2365241675Suqs case(MDOC_Nm): 2366241675Suqs return(10); 2367241675Suqs case(MDOC_No): 2368241675Suqs return(12); 2369241675Suqs case(MDOC_Oo): 2370241675Suqs return(10); 2371241675Suqs case(MDOC_Op): 2372241675Suqs return(14); 2373241675Suqs case(MDOC_Pa): 2374241675Suqs return(32); 2375241675Suqs case(MDOC_Pf): 2376241675Suqs return(12); 2377241675Suqs case(MDOC_Po): 2378241675Suqs return(12); 2379241675Suqs case(MDOC_Pq): 2380241675Suqs return(12); 2381241675Suqs case(MDOC_Ql): 2382241675Suqs return(16); 2383241675Suqs case(MDOC_Qo): 2384241675Suqs return(12); 2385241675Suqs case(MDOC_So): 2386241675Suqs return(12); 2387241675Suqs case(MDOC_Sq): 2388241675Suqs return(12); 2389241675Suqs case(MDOC_Sy): 2390241675Suqs return(6); 2391241675Suqs case(MDOC_Sx): 2392241675Suqs return(16); 2393241675Suqs case(MDOC_Tn): 2394241675Suqs return(10); 2395241675Suqs case(MDOC_Va): 2396241675Suqs return(12); 2397241675Suqs case(MDOC_Vt): 2398241675Suqs return(12); 2399241675Suqs case(MDOC_Xr): 2400241675Suqs return(10); 2401241675Suqs default: 2402241675Suqs break; 2403241675Suqs }; 2404241675Suqs return(0); 2405241675Suqs} 2406