=================================================================== RCS file: /cvs/mandoc/tbl_layout.c,v retrieving revision 1.32 retrieving revision 1.50 diff -u -p -r1.32 -r1.50 --- mandoc/tbl_layout.c 2015/01/26 18:42:30 1.32 +++ mandoc/tbl_layout.c 2021/08/10 12:55:04 1.50 @@ -1,7 +1,8 @@ -/* $Id: tbl_layout.c,v 1.32 2015/01/26 18:42:30 schwarze Exp $ */ +/* $Id: tbl_layout.c,v 1.50 2021/08/10 12:55:04 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2012, 2014, 2015 Ingo Schwarze + * Copyright (c) 2012, 2014, 2015, 2017, 2020, 2021 + * Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,14 +21,17 @@ #include #include +#include +#include #include #include #include -#include "mandoc.h" #include "mandoc_aux.h" +#include "mandoc.h" +#include "tbl.h" #include "libmandoc.h" -#include "libroff.h" +#include "tbl_int.h" struct tbl_phrase { char name; @@ -54,7 +58,7 @@ static void mods(struct tbl_node *, struct tbl_cell static void cell(struct tbl_node *, struct tbl_row *, int, const char *, int *); static struct tbl_cell *cell_alloc(struct tbl_node *, struct tbl_row *, - enum tbl_cellt, int vert); + enum tbl_cellt); static void @@ -62,6 +66,10 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp, int ln, const char *p, int *pos) { char *endptr; + unsigned long spacing; + size_t sz; + int isz; + enum mandoc_esc fontesc; mod: while (p[*pos] == ' ' || p[*pos] == '\t') @@ -69,7 +77,7 @@ mod: /* Row delimiters and cell specifiers end modifier lists. */ - if (strchr(".,-=^_ACLNRSaclnrs|", p[*pos]) != NULL) + if (strchr(".,-=^_ACLNRSaclnrs", p[*pos]) != NULL) return; /* Throw away parenthesised expression. */ @@ -82,27 +90,26 @@ mod: (*pos)++; goto mod; } - mandoc_msg(MANDOCERR_TBLLAYOUT_PAR, tbl->parse, - ln, *pos, NULL); + mandoc_msg(MANDOCERR_TBLLAYOUT_PAR, ln, *pos, NULL); return; } /* Parse numerical spacing from modifier string. */ if (isdigit((unsigned char)p[*pos])) { - cp->spacing = strtoull(p + *pos, &endptr, 10); + if ((spacing = strtoul(p + *pos, &endptr, 10)) > 9) + mandoc_msg(MANDOCERR_TBLLAYOUT_SPC, ln, *pos, + "%lu", spacing); + else + cp->spacing = spacing; *pos = endptr - p; goto mod; } switch (tolower((unsigned char)p[(*pos)++])) { case 'b': - /* FALLTHROUGH */ - case 'i': - /* FALLTHROUGH */ - case 'r': - (*pos)--; - break; + cp->font = ESCAPE_FONTBOLD; + goto mod; case 'd': cp->flags |= TBL_CELL_BALIGN; goto mod; @@ -111,12 +118,13 @@ mod: goto mod; case 'f': break; + case 'i': + cp->font = ESCAPE_FONTITALIC; + goto mod; case 'm': - mandoc_msg(MANDOCERR_TBLLAYOUT_MOD, tbl->parse, - ln, *pos, "m"); + mandoc_msg(MANDOCERR_TBLLAYOUT_MOD, ln, *pos, "m"); goto mod; case 'p': - /* FALLTHROUGH */ case 'v': if (p[*pos] == '-' || p[*pos] == '+') (*pos)++; @@ -129,7 +137,22 @@ mod: case 'u': cp->flags |= TBL_CELL_UP; goto mod; - case 'w': /* XXX for now, ignore minimal column width */ + case 'w': + sz = 0; + if (p[*pos] == '(') { + (*pos)++; + while (p[*pos + sz] != '\0' && p[*pos + sz] != ')') + sz++; + } else + while (isdigit((unsigned char)p[*pos + sz])) + sz++; + if (sz) { + free(cp->wstr); + cp->wstr = mandoc_strndup(p + *pos, sz); + *pos += sz; + if (p[*pos] == ')') + (*pos)++; + } goto mod; case 'x': cp->flags |= TBL_CELL_WMAX; @@ -137,62 +160,75 @@ mod: case 'z': cp->flags |= TBL_CELL_WIGN; goto mod; + case '|': + if (cp->vert < 2) + cp->vert++; + else + mandoc_msg(MANDOCERR_TBLLAYOUT_VERT, + ln, *pos - 1, NULL); + goto mod; default: - mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse, + mandoc_msg(MANDOCERR_TBLLAYOUT_CHAR, ln, *pos - 1, "%c", p[*pos - 1]); goto mod; } - switch (tolower((unsigned char)p[(*pos)++])) { - case '3': - /* FALLTHROUGH */ - case 'b': - cp->flags |= TBL_CELL_BOLD; + while (p[*pos] == ' ' || p[*pos] == '\t') + (*pos)++; + + /* Ignore parenthised font names for now. */ + + if (p[*pos] == '(') goto mod; - case '2': - /* FALLTHROUGH */ - case 'i': - cp->flags |= TBL_CELL_ITALIC; - goto mod; - case '1': - /* FALLTHROUGH */ - case 'r': - goto mod; + + isz = 0; + if (p[*pos] != '\0') + isz++; + if (strchr(" \t.", p[*pos + isz]) == NULL) + isz++; + + fontesc = mandoc_font(p + *pos, isz); + + switch (fontesc) { + case ESCAPE_FONTPREV: + case ESCAPE_ERROR: + mandoc_msg(MANDOCERR_FT_BAD, + ln, *pos, "TS %s", p + *pos - 1); + break; default: - mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse, - ln, *pos - 1, "TS f%c", p[*pos - 1]); - goto mod; + cp->font = fontesc; + break; } + *pos += isz; + goto mod; } static void cell(struct tbl_node *tbl, struct tbl_row *rp, int ln, const char *p, int *pos) { - int vert, i; + int i; enum tbl_cellt c; - /* Handle vertical lines. */ + /* Handle leading vertical lines */ - vert = 0; -again: while (p[*pos] == ' ' || p[*pos] == '\t' || p[*pos] == '|') { if (p[*pos] == '|') { - if (vert < 2) - vert++; + if (rp->vert < 2) + rp->vert++; else mandoc_msg(MANDOCERR_TBLLAYOUT_VERT, - tbl->parse, ln, *pos, NULL); + ln, *pos, NULL); } (*pos)++; } - /* Handle trailing vertical lines */ +again: + while (p[*pos] == ' ' || p[*pos] == '\t') + (*pos)++; - if ('.' == p[*pos] || '\0' == p[*pos]) { - rp->vert = vert; + if (p[*pos] == '.' || p[*pos] == '\0') return; - } /* Parse the column position (`c', `l', `r', ...). */ @@ -201,7 +237,7 @@ again: break; if (i == KEYS_MAX) { - mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse, + mandoc_msg(MANDOCERR_TBLLAYOUT_CHAR, ln, *pos, "%c", p[*pos]); (*pos)++; goto again; @@ -212,31 +248,26 @@ again: if (c == TBL_CELL_SPAN) { if (rp->last == NULL) - mandoc_msg(MANDOCERR_TBLLAYOUT_SPAN, - tbl->parse, ln, *pos, NULL); + mandoc_msg(MANDOCERR_TBLLAYOUT_SPAN, ln, *pos, NULL); else if (rp->last->pos == TBL_CELL_HORIZ || rp->last->pos == TBL_CELL_DHORIZ) c = rp->last->pos; } else if (c == TBL_CELL_DOWN && rp == tbl->first_row) - mandoc_msg(MANDOCERR_TBLLAYOUT_DOWN, - tbl->parse, ln, *pos, NULL); + mandoc_msg(MANDOCERR_TBLLAYOUT_DOWN, ln, *pos, NULL); (*pos)++; /* Allocate cell then parse its modifiers. */ - mods(tbl, cell_alloc(tbl, rp, c, vert), ln, p, pos); + mods(tbl, cell_alloc(tbl, rp, c), ln, p, pos); } void -tbl_layout(struct tbl_node *tbl, int ln, const char *p) +tbl_layout(struct tbl_node *tbl, int ln, const char *p, int pos) { struct tbl_row *rp; - int pos; - pos = 0; rp = NULL; - for (;;) { /* Skip whitespace before and after each cell. */ @@ -253,69 +284,93 @@ tbl_layout(struct tbl_node *tbl, int ln, const char *p case '.': /* End of layout. */ pos++; tbl->part = TBL_PART_DATA; - if (tbl->first_row != NULL) + + /* + * When the layout is completely empty, + * default to one left-justified column. + */ + + if (tbl->first_row == NULL) { + tbl->first_row = tbl->last_row = + mandoc_calloc(1, sizeof(*rp)); + } + if (tbl->first_row->first == NULL) { + mandoc_msg(MANDOCERR_TBLLAYOUT_NONE, + ln, pos, NULL); + cell_alloc(tbl, tbl->first_row, + TBL_CELL_LEFT); + if (tbl->opts.lvert < tbl->first_row->vert) + tbl->opts.lvert = tbl->first_row->vert; return; - mandoc_msg(MANDOCERR_TBLLAYOUT_NONE, - tbl->parse, ln, pos, NULL); - rp = mandoc_calloc(1, sizeof(*rp)); - cell_alloc(tbl, rp, TBL_CELL_LEFT, 0); - tbl->first_row = tbl->last_row = rp; + } + + /* + * Search for the widest line + * along the left and right margins. + */ + + for (rp = tbl->first_row; rp; rp = rp->next) { + if (tbl->opts.lvert < rp->vert) + tbl->opts.lvert = rp->vert; + if (rp->last != NULL && + rp->last->col + 1 == tbl->opts.cols && + tbl->opts.rvert < rp->last->vert) + tbl->opts.rvert = rp->last->vert; + + /* If the last line is empty, drop it. */ + + if (rp->next != NULL && + rp->next->first == NULL) { + free(rp->next); + rp->next = NULL; + tbl->last_row = rp; + } + } return; default: /* Cell. */ break; } - if (rp == NULL) { /* First cell on this line. */ - rp = mandoc_calloc(1, sizeof(*rp)); - if (tbl->last_row) - tbl->last_row->next = rp; - else - tbl->first_row = rp; - tbl->last_row = rp; + /* + * If the last line had at least one cell, + * start a new one; otherwise, continue it. + */ + + if (rp == NULL) { + if (tbl->last_row == NULL || + tbl->last_row->first != NULL) { + rp = mandoc_calloc(1, sizeof(*rp)); + if (tbl->last_row) + tbl->last_row->next = rp; + else + tbl->first_row = rp; + tbl->last_row = rp; + } else + rp = tbl->last_row; } cell(tbl, rp, ln, p, &pos); } } static struct tbl_cell * -cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos, - int vert) +cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos) { struct tbl_cell *p, *pp; - struct tbl_head *h, *hp; - p = mandoc_calloc(1, sizeof(struct tbl_cell)); + p = mandoc_calloc(1, sizeof(*p)); + p->spacing = SIZE_MAX; + p->font = ESCAPE_FONTROMAN; + p->pos = pos; - if (NULL != (pp = rp->last)) { + if ((pp = rp->last) != NULL) { pp->next = p; - h = pp->head->next; - } else { + p->col = pp->col + 1; + } else rp->first = p; - h = tbl->first_head; - } rp->last = p; - p->pos = pos; - p->vert = vert; + if (tbl->opts.cols <= p->col) + tbl->opts.cols = p->col + 1; - /* Re-use header. */ - - if (h) { - p->head = h; - return(p); - } - - hp = mandoc_calloc(1, sizeof(struct tbl_head)); - hp->ident = tbl->opts.cols++; - hp->vert = vert; - - if (tbl->last_head) { - hp->prev = tbl->last_head; - tbl->last_head->next = hp; - } else - tbl->first_head = hp; - tbl->last_head = hp; - - p->head = hp; - return(p); + return p; }