=================================================================== RCS file: /cvs/mandoc/mdoc_validate.c,v retrieving revision 1.120 retrieving revision 1.123 diff -u -p -r1.120 -r1.123 --- mandoc/mdoc_validate.c 2010/10/11 13:24:33 1.120 +++ mandoc/mdoc_validate.c 2010/11/29 13:02:47 1.123 @@ -1,4 +1,4 @@ -/* $Id: mdoc_validate.c,v 1.120 2010/10/11 13:24:33 kristaps Exp $ */ +/* $Id: mdoc_validate.c,v 1.123 2010/11/29 13:02:47 kristaps Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons * @@ -85,6 +85,8 @@ static int post_at(POST_ARGS); static int post_bf(POST_ARGS); static int post_bl(POST_ARGS); static int post_bl_head(POST_ARGS); +static int post_defaults(POST_ARGS); +static int post_eoln(POST_ARGS); static int post_dt(POST_ARGS); static int post_it(POST_ARGS); static int post_lb(POST_ARGS); @@ -95,7 +97,6 @@ static int post_sh(POST_ARGS); static int post_sh_body(POST_ARGS); static int post_sh_head(POST_ARGS); static int post_st(POST_ARGS); -static int post_eoln(POST_ARGS); static int post_vt(POST_ARGS); static int pre_an(PRE_ARGS); static int pre_bd(PRE_ARGS); @@ -117,6 +118,7 @@ static v_post posts_bf[] = { hwarn_le1, post_bf, NULL static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL }; static v_post posts_bool[] = { eerr_eq1, ebool, NULL }; static v_post posts_eoln[] = { post_eoln, NULL }; +static v_post posts_defaults[] = { post_defaults, NULL }; static v_post posts_dt[] = { post_dt, NULL }; static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL }; static v_post posts_it[] = { post_it, NULL }; @@ -167,7 +169,7 @@ const struct valids mdoc_valids[MDOC_MAX] = { { pres_it, posts_it }, /* It */ { NULL, posts_text }, /* Ad */ { pres_an, posts_an }, /* An */ - { NULL, NULL }, /* Ar */ + { NULL, posts_defaults }, /* Ar */ { NULL, posts_text }, /* Cd */ { NULL, NULL }, /* Cm */ { NULL, NULL }, /* Dv */ @@ -181,7 +183,7 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, posts_wtext }, /* Ft */ { NULL, posts_text }, /* Ic */ { NULL, posts_text1 }, /* In */ - { NULL, NULL }, /* Li */ + { NULL, posts_defaults }, /* Li */ { NULL, posts_nd }, /* Nd */ { NULL, posts_nm }, /* Nm */ { NULL, posts_wline }, /* Op */ @@ -260,7 +262,7 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, posts_lb }, /* Lb */ { NULL, posts_notext }, /* Lp */ { NULL, posts_text }, /* Lk */ - { NULL, posts_text }, /* Mt */ + { NULL, posts_defaults }, /* Mt */ { NULL, posts_wline }, /* Brq */ { NULL, NULL }, /* Bro */ { NULL, NULL }, /* Brc */ @@ -275,7 +277,26 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Ta */ }; +#define RSORD_MAX 14 /* Number of `Rs' blocks. */ +static const enum mdoct rsord[RSORD_MAX] = { + MDOC__A, + MDOC__T, + MDOC__B, + MDOC__I, + MDOC__J, + MDOC__R, + MDOC__N, + MDOC__V, + MDOC__P, + MDOC__Q, + MDOC__D, + MDOC__O, + MDOC__C, + MDOC__U +}; + + int mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) { @@ -893,15 +914,16 @@ pre_it(PRE_ARGS) static int pre_an(PRE_ARGS) { + int i; if (NULL == n->args) return(1); - if (n->args->argc > 1) - if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_ARGCOUNT)) + + for (i = 1; i < (int)n->args->argc; i++) + if ( ! mdoc_pmsg(mdoc, n->args->argv[i].line, + n->args->argv[i].pos, MANDOCERR_IGNARGV)) return(0); - /* FIXME: this should use a different error message. */ - if (MDOC_Split == n->args->argv[0].arg) n->data.An.auth = AUTH_split; else if (MDOC_Nosplit == n->args->argv[0].arg) @@ -1113,7 +1135,47 @@ post_nm(POST_ARGS) return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME)); } +static int +post_defaults(POST_ARGS) +{ + struct mdoc_node *nn; + /* + * The `Ar' defaults to "file ..." if no value is provided as an + * argument; the `Mt' macro uses "~"; the `Li' just gets an + * empty string. + */ + + if (mdoc->last->child) + return(1); + + nn = mdoc->last; + mdoc->next = MDOC_NEXT_CHILD; + + switch (nn->tok) { + case (MDOC_Ar): + if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file")) + return(0); + if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "...")) + return(0); + break; + case (MDOC_Li): + if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "")) + return(0); + break; + case (MDOC_Mt): + if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~")) + return(0); + break; + default: + abort(); + /* NOTREACHED */ + } + + mdoc->last = nn; + return(1); +} + static int post_at(POST_ARGS) { @@ -1339,45 +1401,95 @@ post_st(POST_ARGS) static int post_rs(POST_ARGS) { - struct mdoc_node *nn; + struct mdoc_node *nn, *next, *prev; + int i, j; if (MDOC_BODY != mdoc->last->type) return(1); - for (nn = mdoc->last->child; nn; nn = nn->next) - switch (nn->tok) { - case(MDOC__U): - /* FALLTHROUGH */ - case(MDOC__Q): - /* FALLTHROUGH */ - case(MDOC__C): - /* FALLTHROUGH */ - case(MDOC__A): - /* FALLTHROUGH */ - case(MDOC__B): - /* FALLTHROUGH */ - case(MDOC__D): - /* FALLTHROUGH */ - case(MDOC__I): - /* FALLTHROUGH */ - case(MDOC__J): - /* FALLTHROUGH */ - case(MDOC__N): - /* FALLTHROUGH */ - case(MDOC__O): - /* FALLTHROUGH */ - case(MDOC__P): - /* FALLTHROUGH */ - case(MDOC__R): - /* FALLTHROUGH */ - case(MDOC__T): - /* FALLTHROUGH */ - case(MDOC__V): - break; - default: - mdoc_nmsg(mdoc, nn, MANDOCERR_SYNTCHILD); - return(0); + /* + * Make sure only certain types of nodes are allowed within the + * the `Rs' body. Delete offending nodes and raise a warning. + * Do this before re-ordering for the sake of clarity. + */ + + next = NULL; + for (nn = mdoc->last->child; nn; nn = next) { + for (i = 0; i < RSORD_MAX; i++) + if (nn->tok == rsord[i]) + break; + + if (i < RSORD_MAX) { + next = nn->next; + continue; } + + next = nn->next; + mdoc_nmsg(mdoc, nn, MANDOCERR_CHILD); + mdoc_node_delete(mdoc, nn); + } + + /* + * The full `Rs' block needs special handling to order the + * sub-elements according to `rsord'. Pick through each element + * and correctly order it. This is a insertion sort. + */ + + next = NULL; + for (nn = mdoc->last->child->next; nn; nn = next) { + /* Determine order of `nn'. */ + for (i = 0; i < RSORD_MAX; i++) + if (rsord[i] == nn->tok) + break; + + /* + * Remove `nn' from the chain. This somewhat + * repeats mdoc_node_unlink(), but since we're + * just re-ordering, there's no need for the + * full unlink process. + */ + + if (NULL != (next = nn->next)) + next->prev = nn->prev; + + if (NULL != (prev = nn->prev)) + prev->next = nn->next; + + nn->prev = nn->next = NULL; + + /* + * Scan back until we reach a node that's + * ordered before `nn'. + */ + + for ( ; prev ; prev = prev->prev) { + /* Determine order of `prev'. */ + for (j = 0; j < RSORD_MAX; j++) + if (rsord[j] == prev->tok) + break; + + if (j <= i) + break; + } + + /* + * Set `nn' back into its correct place in front + * of the `prev' node. + */ + + nn->prev = prev; + + if (prev) { + if (prev->next) + prev->next->prev = nn; + nn->next = prev->next; + prev->next = nn; + } else { + mdoc->last->child->prev = nn; + nn->next = mdoc->last->child; + mdoc->last->child = nn; + } + } return(1); }