=================================================================== RCS file: /cvs/mandoc/roff.c,v retrieving revision 1.265 retrieving revision 1.268 diff -u -p -r1.265 -r1.268 --- mandoc/roff.c 2015/04/18 17:28:36 1.265 +++ mandoc/roff.c 2015/04/19 14:57:38 1.268 @@ -1,6 +1,6 @@ -/* $Id: roff.c,v 1.265 2015/04/18 17:28:36 schwarze Exp $ */ +/* $Id: roff.c,v 1.268 2015/04/19 14:57:38 schwarze Exp $ */ /* - * Copyright (c) 2009-2012, 2014 Kristaps Dzonsons + * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons * Copyright (c) 2010-2015 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any @@ -30,6 +30,7 @@ #include "mandoc_aux.h" #include "roff.h" #include "libmandoc.h" +#include "roff_int.h" #include "libroff.h" /* Maximum number of nested if-else conditionals. */ @@ -38,6 +39,8 @@ /* Maximum number of string expansions per line, to break infinite loops. */ #define EXPAND_LIMIT 1000 +/* --- data types --------------------------------------------------------- */ + enum rofft { ROFF_ab, ROFF_ad, @@ -374,6 +377,8 @@ struct predef { #define PREDEF(__name, __str) \ { (__name), (__str) }, +/* --- function prototypes ------------------------------------------------ */ + static enum rofft roffhash_find(const char *, size_t); static void roffhash_init(void); static void roffnode_cleanscope(struct roff *); @@ -438,6 +443,8 @@ static enum rofferr roff_T_(ROFF_ARGS); static enum rofferr roff_unsupp(ROFF_ARGS); static enum rofferr roff_userdef(ROFF_ARGS); +/* --- constant data ------------------------------------------------------ */ + /* See roffhash_find() */ #define ASCII_HI 126 @@ -734,6 +741,8 @@ static int roffit_lines; /* number of lines to delay static char *roffit_macro; /* nil-terminated macro line */ +/* --- request table ------------------------------------------------------ */ + static void roffhash_init(void) { @@ -786,6 +795,8 @@ roffhash_find(const char *p, size_t s) return(ROFF_MAX); } +/* --- stack of request blocks -------------------------------------------- */ + /* * Pop the current node off of the stack of roff instructions currently * pending. @@ -826,6 +837,8 @@ roffnode_push(struct roff *r, enum rofft tok, const ch r->last = p; } +/* --- roff parser state data management ---------------------------------- */ + static void roff_free1(struct roff *r) { @@ -901,16 +914,14 @@ roff_alloc(struct mparse *parse, const struct mchars * return(r); } +/* --- syntax tree state data management ---------------------------------- */ + static void roff_man_free1(struct roff_man *man) { - if (man->first != NULL) { - if (man->macroset == MACROSET_MDOC) - mdoc_node_delete(man, man->first); - else - man_node_delete(man, man->first); - } + if (man->first != NULL) + roff_node_delete(man, man->first); free(man->meta.msec); free(man->meta.vol); free(man->meta.os); @@ -966,6 +977,261 @@ roff_man_alloc(struct roff *roff, struct mparse *parse return(man); } +/* --- syntax tree handling ----------------------------------------------- */ + +struct roff_node * +roff_node_alloc(struct roff_man *man, int line, int pos, + enum roff_type type, int tok) +{ + struct roff_node *n; + + n = mandoc_calloc(1, sizeof(*n)); + n->line = line; + n->pos = pos; + n->tok = tok; + n->type = type; + n->sec = man->lastsec; + + if (man->flags & MDOC_SYNOPSIS) + n->flags |= MDOC_SYNPRETTY; + else + n->flags &= ~MDOC_SYNPRETTY; + if (man->flags & MDOC_NEWLINE) + n->flags |= MDOC_LINE; + man->flags &= ~MDOC_NEWLINE; + + return(n); +} + +void +roff_node_append(struct roff_man *man, struct roff_node *n) +{ + + switch (man->next) { + case ROFF_NEXT_SIBLING: + man->last->next = n; + n->prev = man->last; + n->parent = man->last->parent; + break; + case ROFF_NEXT_CHILD: + man->last->child = n; + n->parent = man->last; + break; + default: + abort(); + /* NOTREACHED */ + } + n->parent->nchild++; + + /* + * Copy over the normalised-data pointer of our parent. Not + * everybody has one, but copying a null pointer is fine. + */ + + switch (n->type) { + case ROFFT_BODY: + if (n->end != ENDBODY_NOT) + break; + /* FALLTHROUGH */ + case ROFFT_TAIL: + /* FALLTHROUGH */ + case ROFFT_HEAD: + n->norm = n->parent->norm; + break; + default: + break; + } + + if (man->macroset == MACROSET_MDOC) + mdoc_valid_pre(man, n); + + switch (n->type) { + case ROFFT_HEAD: + assert(n->parent->type == ROFFT_BLOCK); + n->parent->head = n; + break; + case ROFFT_BODY: + if (n->end) + break; + assert(n->parent->type == ROFFT_BLOCK); + n->parent->body = n; + break; + case ROFFT_TAIL: + assert(n->parent->type == ROFFT_BLOCK); + n->parent->tail = n; + break; + default: + break; + } + man->last = n; +} + +void +roff_word_alloc(struct roff_man *man, int line, int pos, const char *word) +{ + struct roff_node *n; + + n = roff_node_alloc(man, line, pos, ROFFT_TEXT, TOKEN_NONE); + n->string = roff_strdup(man->roff, word); + roff_node_append(man, n); + if (man->macroset == MACROSET_MDOC) + mdoc_valid_post(man); + else + man_valid_post(man); + man->next = ROFF_NEXT_SIBLING; +} + +void +roff_word_append(struct roff_man *man, const char *word) +{ + struct roff_node *n; + char *addstr, *newstr; + + n = man->last; + addstr = roff_strdup(man->roff, word); + mandoc_asprintf(&newstr, "%s %s", n->string, addstr); + free(addstr); + free(n->string); + n->string = newstr; + man->next = ROFF_NEXT_SIBLING; +} + +void +roff_elem_alloc(struct roff_man *man, int line, int pos, int tok) +{ + struct roff_node *n; + + n = roff_node_alloc(man, line, pos, ROFFT_ELEM, tok); + roff_node_append(man, n); + man->next = ROFF_NEXT_CHILD; +} + +struct roff_node * +roff_block_alloc(struct roff_man *man, int line, int pos, int tok) +{ + struct roff_node *n; + + n = roff_node_alloc(man, line, pos, ROFFT_BLOCK, tok); + roff_node_append(man, n); + man->next = ROFF_NEXT_CHILD; + return(n); +} + +struct roff_node * +roff_head_alloc(struct roff_man *man, int line, int pos, int tok) +{ + struct roff_node *n; + + n = roff_node_alloc(man, line, pos, ROFFT_HEAD, tok); + roff_node_append(man, n); + man->next = ROFF_NEXT_CHILD; + return(n); +} + +struct roff_node * +roff_body_alloc(struct roff_man *man, int line, int pos, int tok) +{ + struct roff_node *n; + + n = roff_node_alloc(man, line, pos, ROFFT_BODY, tok); + roff_node_append(man, n); + man->next = ROFF_NEXT_CHILD; + return(n); +} + +void +roff_addeqn(struct roff_man *man, const struct eqn *eqn) +{ + struct roff_node *n; + + n = roff_node_alloc(man, eqn->ln, eqn->pos, ROFFT_EQN, TOKEN_NONE); + n->eqn = eqn; + if (eqn->ln > man->last->line) + n->flags |= MDOC_LINE; + roff_node_append(man, n); + man->next = ROFF_NEXT_SIBLING; +} + +void +roff_addtbl(struct roff_man *man, const struct tbl_span *tbl) +{ + struct roff_node *n; + + if (man->macroset == MACROSET_MAN) + man_breakscope(man, TOKEN_NONE); + n = roff_node_alloc(man, tbl->line, 0, ROFFT_TBL, TOKEN_NONE); + n->span = tbl; + roff_node_append(man, n); + if (man->macroset == MACROSET_MDOC) + mdoc_valid_post(man); + else + man_valid_post(man); + man->next = ROFF_NEXT_SIBLING; +} + +void +roff_node_unlink(struct roff_man *man, struct roff_node *n) +{ + + /* Adjust siblings. */ + + if (n->prev) + n->prev->next = n->next; + if (n->next) + n->next->prev = n->prev; + + /* Adjust parent. */ + + if (n->parent != NULL) { + n->parent->nchild--; + if (n->parent->child == n) + n->parent->child = n->next; + if (n->parent->last == n) + n->parent->last = n->prev; + } + + /* Adjust parse point. */ + + if (man == NULL) + return; + if (man->last == n) { + if (n->prev == NULL) { + man->last = n->parent; + man->next = ROFF_NEXT_CHILD; + } else { + man->last = n->prev; + man->next = ROFF_NEXT_SIBLING; + } + } + if (man->first == n) + man->first = NULL; +} + +void +roff_node_free(struct roff_node *n) +{ + + if (n->args != NULL) + mdoc_argv_free(n->args); + if (n->type == ROFFT_BLOCK || n->type == ROFFT_ELEM) + free(n->norm); + free(n->string); + free(n); +} + +void +roff_node_delete(struct roff_man *man, struct roff_node *n) +{ + + while (n->child != NULL) + roff_node_delete(man, n->child); + assert(n->nchild == 0); + roff_node_unlink(man, n); + roff_node_free(n); +} + +/* --- main functions of the roff parser ---------------------------------- */ + /* * In the current line, expand escape sequences that tend to get * used in numerical expressions and conditional requests. @@ -1385,6 +1651,8 @@ roff_parse(struct roff *r, char *buf, int *pos, int ln return(t); } +/* --- handling of request blocks ----------------------------------------- */ + static enum rofferr roff_cblock(ROFF_ARGS) { @@ -1695,6 +1963,8 @@ roff_cond_text(ROFF_ARGS) return(rr ? ROFF_CONT : ROFF_IGN); } +/* --- handling of numeric and conditional expressions -------------------- */ + /* * Parse a single signed integer number. Stop at the first non-digit. * If there is at least one digit, return success and advance the @@ -2212,6 +2482,8 @@ roff_evalnum(struct roff *r, int ln, const char *v, return(1); } +/* --- register management ------------------------------------------------ */ + void roff_setreg(struct roff *r, const char *name, int val, char sign) { @@ -2376,6 +2648,8 @@ roff_rr(ROFF_ARGS) return(ROFF_IGN); } +/* --- handler functions for roff requests -------------------------------- */ + static enum rofferr roff_rm(ROFF_ARGS) { @@ -2720,6 +2994,8 @@ roff_so(ROFF_ARGS) return(ROFF_SO); } +/* --- user defined strings and macros ------------------------------------ */ + static enum rofferr roff_userdef(ROFF_ARGS) { @@ -2987,6 +3263,8 @@ roff_freestr(struct roffkv *r) free(n); } } + +/* --- accessors and utility functions ------------------------------------ */ const struct tbl_span * roff_span(const struct roff *r)