diff options
author | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2011-01-04 22:28:18 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2011-01-04 22:28:18 +0000 |
commit | 3f808e58f9b1e56a31e679de60386c10cefbe115 (patch) | |
tree | bc87b62f89cfcead15638c92e75e667be76752d5 | |
parent | 520623cefde5dd43125b0e3bd121266079514407 (diff) |
Merge kristaps@' cleaner tbl integration, removing mine;
there are still a few bugs, but fixing these will be easier in tree.
37 files changed, 1859 insertions, 1829 deletions
diff --git a/usr.bin/mandoc/Makefile b/usr.bin/mandoc/Makefile index 4c469a34fe5..0df572bdefe 100644 --- a/usr.bin/mandoc/Makefile +++ b/usr.bin/mandoc/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.50 2010/12/25 13:23:03 schwarze Exp $ +# $OpenBSD: Makefile,v 1.51 2011/01/04 22:28:17 schwarze Exp $ .include <bsd.own.mk> @@ -10,15 +10,14 @@ CFLAGS+=-W -Wall -Wstrict-prototypes CFLAGS+=-Wno-unused-parameter .endif -SRCS= roff.c mandoc.c +SRCS= roff.c tbl.c tbl_opts.c tbl_layout.c tbl_data.c mandoc.c SRCS+= mdoc_macro.c mdoc.c mdoc_hash.c mdoc_strings.c \ mdoc_argv.c mdoc_validate.c lib.c att.c \ arch.c vol.c msec.c st.c SRCS+= man_macro.c man.c man_hash.c man_validate.c man_argv.c SRCS+= main.c mdoc_term.c chars.c term.c tree.c man_term.c SRCS+= html.c mdoc_html.c man_html.c out.c -SRCS+= term_ps.c term_ascii.c -SRCS+= tbl.c tbl_data.c tbl_layout.c tbl_option.c tbl_term.c tbl_tree.c +SRCS+= term_ps.c term_ascii.c tbl_term.c tbl_html.c PROG= mandoc diff --git a/usr.bin/mandoc/chars.c b/usr.bin/mandoc/chars.c index e3fe1a44d76..e3b192e6d70 100644 --- a/usr.bin/mandoc/chars.c +++ b/usr.bin/mandoc/chars.c @@ -1,4 +1,4 @@ -/* $Id: chars.c,v 1.14 2010/09/20 20:43:38 schwarze Exp $ */ +/* $Id: chars.c,v 1.15 2011/01/04 22:28:17 schwarze Exp $ */ /* * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -50,22 +50,22 @@ struct ln { #include "chars.in" -struct tbl { +struct ctab { enum chars type; struct ln **htab; }; static inline int match(const struct ln *, const char *, size_t, int); -static const struct ln *find(struct tbl *, const char *, size_t, int); +static const struct ln *find(struct ctab *, const char *, size_t, int); void chars_free(void *arg) { - struct tbl *tab; + struct ctab *tab; - tab = (struct tbl *)arg; + tab = (struct ctab *)arg; free(tab->htab); free(tab); @@ -75,7 +75,7 @@ chars_free(void *arg) void * chars_init(enum chars type) { - struct tbl *tab; + struct ctab *tab; struct ln **htab; struct ln *pp; int i, hash; @@ -87,7 +87,7 @@ chars_init(enum chars type) * (they're in-line re-ordered during lookup). */ - tab = malloc(sizeof(struct tbl)); + tab = malloc(sizeof(struct ctab)); if (NULL == tab) { perror(NULL); exit((int)MANDOCLEVEL_SYSERR); @@ -126,7 +126,7 @@ chars_spec2cp(void *arg, const char *p, size_t sz) { const struct ln *ln; - ln = find((struct tbl *)arg, p, sz, CHARS_CHAR); + ln = find((struct ctab *)arg, p, sz, CHARS_CHAR); if (NULL == ln) return(-1); return(ln->unicode); @@ -141,7 +141,7 @@ chars_res2cp(void *arg, const char *p, size_t sz) { const struct ln *ln; - ln = find((struct tbl *)arg, p, sz, CHARS_STRING); + ln = find((struct ctab *)arg, p, sz, CHARS_STRING); if (NULL == ln) return(-1); return(ln->unicode); @@ -156,7 +156,7 @@ chars_spec2str(void *arg, const char *p, size_t sz, size_t *rsz) { const struct ln *ln; - ln = find((struct tbl *)arg, p, sz, CHARS_CHAR); + ln = find((struct ctab *)arg, p, sz, CHARS_CHAR); if (NULL == ln) return(NULL); @@ -173,7 +173,7 @@ chars_res2str(void *arg, const char *p, size_t sz, size_t *rsz) { const struct ln *ln; - ln = find((struct tbl *)arg, p, sz, CHARS_STRING); + ln = find((struct ctab *)arg, p, sz, CHARS_STRING); if (NULL == ln) return(NULL); @@ -183,7 +183,7 @@ chars_res2str(void *arg, const char *p, size_t sz, size_t *rsz) static const struct ln * -find(struct tbl *tab, const char *p, size_t sz, int type) +find(struct ctab *tab, const char *p, size_t sz, int type) { struct ln *pp, *prev; struct ln **htab; diff --git a/usr.bin/mandoc/html.h b/usr.bin/mandoc/html.h index 61c66b7865e..8ae7bd7db92 100644 --- a/usr.bin/mandoc/html.h +++ b/usr.bin/mandoc/html.h @@ -1,4 +1,4 @@ -/* $Id: html.h,v 1.11 2010/12/25 13:23:03 schwarze Exp $ */ +/* $Id: html.h,v 1.12 2011/01/04 22:28:17 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -138,6 +138,7 @@ struct tag *print_otag(struct html *, enum htmltag, void print_tagq(struct html *, const struct tag *); void print_stagq(struct html *, const struct tag *); void print_text(struct html *, const char *); +void print_tbl(struct html *, const struct tbl_span *); void bufcat_su(struct html *, const char *, const struct roffsu *); diff --git a/usr.bin/mandoc/libroff.h b/usr.bin/mandoc/libroff.h new file mode 100644 index 00000000000..17e4f8fef69 --- /dev/null +++ b/usr.bin/mandoc/libroff.h @@ -0,0 +1,62 @@ +/* $Id: libroff.h,v 1.1 2011/01/04 22:28:17 schwarze Exp $ */ +/* + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef LIBROFF_H +#define LIBROFF_H + +__BEGIN_DECLS + +enum tbl_part { + TBL_PART_OPTS, /* in options (first line) */ + TBL_PART_LAYOUT, /* describing layout */ + TBL_PART_DATA, /* creating data rows */ + TBL_PART_CDATA /* continue previous row */ +}; + +struct tbl_node { + mandocmsg msg; /* status messages */ + void *data; /* privdata for messages */ + int pos; /* invocation column */ + int line; /* invocation line */ + enum tbl_part part; + struct tbl opts; + struct tbl_row *first_row; + struct tbl_row *last_row; + struct tbl_span *first_span; + struct tbl_span *last_span; + struct tbl_head *first_head; + struct tbl_head *last_head; + struct tbl_node *next; +}; + +#define TBL_MSG(tblp, type, line, col) \ + (*(tblp)->msg)((type), (tblp)->data, (line), (col), NULL) + +struct tbl_node *tbl_alloc(int, int, void *, mandocmsg); +void tbl_restart(int, int, struct tbl_node *); +void tbl_free(struct tbl_node *); +void tbl_reset(struct tbl_node *); +enum rofferr tbl_read(struct tbl_node *, int, const char *, int); +int tbl_option(struct tbl_node *, int, const char *); +int tbl_layout(struct tbl_node *, int, const char *); +int tbl_data(struct tbl_node *, int, const char *); +int tbl_cdata(struct tbl_node *, int, const char *); +const struct tbl_span *tbl_span(const struct tbl_node *); +void tbl_end(struct tbl_node *); + +__END_DECLS + +#endif /*LIBROFF_H*/ diff --git a/usr.bin/mandoc/main.c b/usr.bin/mandoc/main.c index 116d051262c..9715f047c89 100644 --- a/usr.bin/mandoc/main.c +++ b/usr.bin/mandoc/main.c @@ -1,6 +1,6 @@ -/* $Id: main.c,v 1.63 2011/01/03 23:39:27 schwarze Exp $ */ +/* $Id: main.c,v 1.64 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -162,9 +162,21 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "bad comment style", "unknown escape sequence", "unterminated quoted string", + + /* related to tables */ + "extra data cells", "generic error", + /* related to tables */ + "bad table syntax", + "bad table option", + "bad table layout", + "no table layout cells specified", + "no table data cells specified", + "ignore data in cell", + "data block still open", + "input stack limit exceeded, infinite loop?", "skipping bad character", "skipping text before the first section header", @@ -182,7 +194,6 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "missing list type", "line argument(s) will be lost", "body argument(s) will be lost", - "tbl(1) error", "generic fatal error", @@ -509,10 +520,7 @@ fdesc(struct curparse *curp) } assert(curp->roff); - if ( ! roff_endparse(curp->roff)) { - assert(MANDOCLEVEL_FATAL <= file_status); - goto cleanup; - } + roff_endparse(curp->roff); /* * With -Wstop and warnings or errors of at least @@ -781,7 +789,7 @@ rerun: continue; } else break; - case (ROFF_CONT): + default: break; } @@ -799,9 +807,20 @@ rerun: * Lastly, push down into the parsers themselves. One * of these will have already been set in the pset() * routine. + * If libroff returns ROFF_TBL, then add it to the + * currently open parse. Since we only get here if + * there does exist data (see tbl_data.c), we're + * guaranteed that something's been allocated. */ - if (curp->man || curp->mdoc) { + if (ROFF_TBL == rr) { + assert(curp->man || curp->mdoc); + if (curp->man) + man_addspan(curp->man, roff_span(curp->roff)); + else + mdoc_addspan(curp->mdoc, roff_span(curp->roff)); + + } else if (curp->man || curp->mdoc) { rc = curp->man ? man_parseln(curp->man, curp->line, ln.buf, of) : diff --git a/usr.bin/mandoc/man.3 b/usr.bin/mandoc/man.3 index aff3499eb12..a1a9ea08640 100644 --- a/usr.bin/mandoc/man.3 +++ b/usr.bin/mandoc/man.3 @@ -1,6 +1,6 @@ -.\" $Id: man.3,v 1.19 2010/12/22 00:33:25 schwarze Exp $ +.\" $Id: man.3,v 1.20 2011/01/04 22:28:17 schwarze Exp $ .\" -.\" Copyright (c) 2009-2010 Kristaps Dzonsons <kristaps@bsd.lv> +.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: December 22 2010 $ +.Dd $Mdocdate: January 4 2011 $ .Dt MAN 3 .Os .Sh NAME @@ -31,6 +31,11 @@ .In mandoc.h .In man.h .Vt extern const char * const * man_macronames; +.Ft int +.Fo man_addspan +.Fa "struct man *man" +.Fa "const struct tbl_span *span" +.Fc .Ft "struct man *" .Fo man_alloc .Fa "struct regset *regs" @@ -101,6 +106,9 @@ for details. .El .Ss Functions .Bl -ohang +.It Fn man_addspan +Add a table span to the parsing stream. +Returns 0 on failure, 1 on success. .It Fn man_alloc Allocates a parsing structure. The diff --git a/usr.bin/mandoc/man.c b/usr.bin/mandoc/man.c index c0c6e34d119..2f534e1d9d1 100644 --- a/usr.bin/mandoc/man.c +++ b/usr.bin/mandoc/man.c @@ -1,6 +1,6 @@ -/* $Id: man.c,v 1.51 2011/01/01 17:38:11 schwarze Exp $ */ +/* $Id: man.c,v 1.52 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -26,10 +26,6 @@ #include "libman.h" #include "libmandoc.h" -#include "out.h" -#include "term.h" -#include "tbl.h" - const char *const __man_macronames[MAN_MAX] = { "br", "TH", "SH", "SS", "TP", "LP", "PP", "P", @@ -39,7 +35,7 @@ const char *const __man_macronames[MAN_MAX] = { "RI", "na", "sp", "nf", "fi", "RE", "RS", "DT", "UC", "PD", "AT", "in", - "TS", "TE", "ft", + "ft" }; const char * const *man_macronames = __man_macronames; @@ -48,6 +44,8 @@ static struct man_node *man_node_alloc(int, int, enum man_type, enum mant); static int man_node_append(struct man *, struct man_node *); +static int man_span_alloc(struct man *, + const struct tbl_span *); static void man_node_free(struct man_node *); static void man_node_unlink(struct man *, struct man_node *); @@ -55,6 +53,7 @@ static int man_ptext(struct man *, int, char *, int); static int man_pmacro(struct man *, int, char *, int); static void man_free1(struct man *); static void man_alloc1(struct man *); +static int man_descope(struct man *, int, int); const struct man_node * @@ -124,22 +123,10 @@ man_endparse(struct man *m) int man_parseln(struct man *m, int ln, char *buf, int offs) { - struct man_node *n; if (MAN_HALT & m->flags) return(0); - n = m->last; - - if (n && MAN_TS == n->tok && MAN_BODY == n->type && - strncmp(buf+offs, ".TE", 3)) { - n = n->parent; - if ( ! tbl_read(n->data.TS, "man tbl parser", - ln, buf+offs, strlen(buf+offs))) - man_nmsg(m, n, MANDOCERR_TBL); - return(1); - } - return(('.' == buf[offs] || '\'' == buf[offs]) ? man_pmacro(m, ln, buf, offs) : man_ptext(m, ln, buf, offs)); @@ -224,6 +211,8 @@ man_node_append(struct man *man, struct man_node *p) man->last = p; switch (p->type) { + case (MAN_TBL): + /* FALLTHROUGH */ case (MAN_TEXT): if ( ! man_valid_post(man)) return(0); @@ -301,6 +290,21 @@ man_block_alloc(struct man *m, int line, int pos, enum mant tok) return(1); } +static int +man_span_alloc(struct man *m, const struct tbl_span *span) +{ + struct man_node *n; + + /* FIXME: grab from span */ + n = man_node_alloc(0, 0, MAN_TBL, MAN_MAX); + n->span = span; + + if ( ! man_node_append(m, n)) + return(0); + + m->next = MAN_NEXT_SIBLING; + return(1); +} int man_word_alloc(struct man *m, int line, int pos, const char *word) @@ -335,8 +339,6 @@ man_node_free(struct man_node *p) if (p->string) free(p->string); - if (p->data.TS) - tbl_free(p->data.TS); free(p); } @@ -353,6 +355,40 @@ man_node_delete(struct man *m, struct man_node *p) } +int +man_addspan(struct man *m, const struct tbl_span *sp) +{ + + if ( ! man_span_alloc(m, sp)) + return(0); + return(man_descope(m, 0, 0)); +} + +static int +man_descope(struct man *m, int line, int offs) +{ + /* + * Co-ordinate what happens with having a next-line scope open: + * first close out the element scope (if applicable), then close + * out the block scope (also if applicable). + */ + + if (MAN_ELINE & m->flags) { + m->flags &= ~MAN_ELINE; + if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX)) + return(0); + } + + if ( ! (MAN_BLINE & m->flags)) + return(1); + m->flags &= ~MAN_BLINE; + + if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX)) + return(0); + return(man_body_alloc(m, line, offs, m->last->tok)); +} + + static int man_ptext(struct man *m, int line, char *buf, int offs) { @@ -372,7 +408,7 @@ man_ptext(struct man *m, int line, char *buf, int offs) if (MAN_LITERAL & m->flags) { if ( ! man_word_alloc(m, line, offs, buf + offs)) return(0); - goto descope; + return(man_descope(m, line, offs)); } /* Pump blank lines directly into the backend. */ @@ -384,7 +420,7 @@ man_ptext(struct man *m, int line, char *buf, int offs) /* Allocate a blank entry. */ if ( ! man_word_alloc(m, line, offs, "")) return(0); - goto descope; + return(man_descope(m, line, offs)); } /* @@ -421,26 +457,7 @@ man_ptext(struct man *m, int line, char *buf, int offs) if (mandoc_eos(buf, (size_t)i, 0)) m->last->flags |= MAN_EOS; -descope: - /* - * Co-ordinate what happens with having a next-line scope open: - * first close out the element scope (if applicable), then close - * out the block scope (also if applicable). - */ - - if (MAN_ELINE & m->flags) { - m->flags &= ~MAN_ELINE; - if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX)) - return(0); - } - - if ( ! (MAN_BLINE & m->flags)) - return(1); - m->flags &= ~MAN_BLINE; - - if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX)) - return(0); - return(man_body_alloc(m, line, offs, m->last->tok)); + return(man_descope(m, line, offs)); } diff --git a/usr.bin/mandoc/man.h b/usr.bin/mandoc/man.h index 7daa88a4153..f459db294f3 100644 --- a/usr.bin/mandoc/man.h +++ b/usr.bin/mandoc/man.h @@ -1,6 +1,6 @@ -/* $Id: man.h,v 1.32 2010/12/27 23:57:13 schwarze Exp $ */ +/* $Id: man.h,v 1.33 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -53,8 +53,6 @@ enum mant { MAN_PD, MAN_AT, MAN_in, - MAN_TS, - MAN_TE, MAN_ft, MAN_MAX }; @@ -68,7 +66,8 @@ enum man_type { MAN_ROOT, MAN_BLOCK, MAN_HEAD, - MAN_BODY + MAN_BODY, + MAN_TBL }; /* @@ -83,10 +82,6 @@ struct man_meta { char *source; /* `TH' source (e.g., GNU) */ }; -union man_data { - struct tbl *TS; -}; - /* * Single node in tree-linked AST. */ @@ -106,7 +101,7 @@ struct man_node { char *string; /* TEXT node argument */ struct man_node *head; /* BLOCK node HEAD ptr */ struct man_node *body; /* BLOCK node BODY ptr */ - union man_data data; + const struct tbl_span *span; /* TBL */ }; /* @@ -124,6 +119,8 @@ struct man *man_alloc(struct regset *, void *, mandocmsg); void man_reset(struct man *); int man_parseln(struct man *, int, char *, int); int man_endparse(struct man *); +int man_addspan(struct man *, + const struct tbl_span *); const struct man_node *man_node(const struct man *); const struct man_meta *man_meta(const struct man *); diff --git a/usr.bin/mandoc/man_html.c b/usr.bin/mandoc/man_html.c index 919bda0d2a4..075f7ddd187 100644 --- a/usr.bin/mandoc/man_html.c +++ b/usr.bin/mandoc/man_html.c @@ -1,6 +1,6 @@ -/* $Id: man_html.c,v 1.28 2011/01/04 01:15:39 schwarze Exp $ */ +/* $Id: man_html.c,v 1.29 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -107,8 +107,6 @@ static const struct htmlman mans[MAN_MAX] = { { man_ign_pre, NULL }, /* PD */ { man_ign_pre, NULL }, /* AT */ { man_in_pre, NULL }, /* in */ - { NULL, NULL }, /* TS */ - { NULL, NULL }, /* TE */ { man_ign_pre, NULL }, /* ft */ }; @@ -196,11 +194,12 @@ print_man_node(MAN_ARGS) break; case (MAN_TEXT): print_text(h, n->string); - if (MANH_LITERAL & mh->fl) print_otag(h, TAG_BR, 0, NULL); - return; + case (MAN_TBL): + print_tbl(h, n->span); + break; default: /* * Close out scope of font prior to opening a macro @@ -228,7 +227,7 @@ print_man_node(MAN_ARGS) case (MAN_ROOT): man_root_post(m, n, mh, h); break; - case (MAN_TEXT): + case (MAN_TBL): break; default: if (mans[n->tok].post) diff --git a/usr.bin/mandoc/man_macro.c b/usr.bin/mandoc/man_macro.c index cb467dd6f2c..a30b585b91a 100644 --- a/usr.bin/mandoc/man_macro.c +++ b/usr.bin/mandoc/man_macro.c @@ -1,4 +1,4 @@ -/* $Id: man_macro.c,v 1.25 2010/12/19 07:53:12 schwarze Exp $ */ +/* $Id: man_macro.c,v 1.26 2011/01/04 22:28:17 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -75,8 +75,6 @@ const struct man_macro __man_macros[MAN_MAX] = { { in_line_eoln, 0 }, /* PD */ { in_line_eoln, 0 }, /* AT */ { in_line_eoln, 0 }, /* in */ - { blk_exp, MAN_EXPLICIT }, /* TS */ - { blk_close, 0 }, /* TE */ { in_line_eoln, 0 }, /* ft */ }; @@ -259,9 +257,6 @@ blk_close(MACRO_PROT_ARGS) case (MAN_RE): ntok = MAN_RS; break; - case (MAN_TE): - ntok = MAN_TS; - break; default: abort(); /* NOTREACHED */ diff --git a/usr.bin/mandoc/man_term.c b/usr.bin/mandoc/man_term.c index 49bac5b5943..27abd27c91b 100644 --- a/usr.bin/mandoc/man_term.c +++ b/usr.bin/mandoc/man_term.c @@ -1,6 +1,6 @@ -/* $Id: man_term.c,v 1.57 2011/01/04 01:15:39 schwarze Exp $ */ +/* $Id: man_term.c,v 1.58 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -29,7 +29,6 @@ #include "term.h" #include "chars.h" #include "main.h" -#include "tbl.h" #define INDENT 7 #define HALFINDENT 3 @@ -92,7 +91,6 @@ static int pre_ign(DECL_ARGS); static int pre_in(DECL_ARGS); static int pre_literal(DECL_ARGS); static int pre_sp(DECL_ARGS); -static int pre_TS(DECL_ARGS); static int pre_ft(DECL_ARGS); static void post_IP(DECL_ARGS); @@ -135,8 +133,6 @@ static const struct termact termacts[MAN_MAX] = { { pre_ign, NULL, 0 }, /* PD */ { pre_ign, NULL, 0 }, /* AT */ { pre_in, NULL, MAN_NOTEXT }, /* in */ - { pre_TS, NULL, 0 }, /* TS */ - { NULL, NULL, 0 }, /* TE */ { pre_ft, NULL, MAN_NOTEXT }, /* ft */ }; @@ -844,21 +840,6 @@ post_RS(DECL_ARGS) } -/* ARGSUSED */ -static int -pre_TS(DECL_ARGS) -{ - - if (MAN_BLOCK != n->type) - return(0); - - if (tbl_close(p, n->data.TS, "man tbl postprocess", n->line)) - tbl_write(p, n->data.TS); - - return(0); -} - - static void print_man_node(DECL_ARGS) { @@ -889,6 +870,11 @@ print_man_node(DECL_ARGS) p->maxrmargin = rmax; } break; + case (MAN_TBL): + if (TBL_SPAN_FIRST & n->span->flags) + term_newln(p); + term_tbl(p, n->span); + break; default: if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) term_fontrepl(p, TERMFONT_NONE); @@ -900,11 +886,17 @@ print_man_node(DECL_ARGS) if (c && n->child) print_man_nodelist(p, mt, n->child, m); - if (MAN_TEXT != n->type) { + switch (n->type) { + case (MAN_TEXT): + /* FALLTHROUGH */ + case (MAN_TBL): + break; + default: if (termacts[n->tok].post) (*termacts[n->tok].post)(p, mt, n, m); if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) term_fontrepl(p, TERMFONT_NONE); + break; } if (MAN_EOS & n->flags) diff --git a/usr.bin/mandoc/man_validate.c b/usr.bin/mandoc/man_validate.c index 776d1ac1d64..6da4350a1f0 100644 --- a/usr.bin/mandoc/man_validate.c +++ b/usr.bin/mandoc/man_validate.c @@ -1,6 +1,6 @@ -/* $Id: man_validate.c,v 1.37 2010/12/19 07:53:12 schwarze Exp $ */ +/* $Id: man_validate.c,v 1.38 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -30,10 +30,6 @@ #include "libman.h" #include "libmandoc.h" -#include "out.h" -#include "term.h" -#include "tbl.h" - #define CHKARGS struct man *m, struct man_node *n typedef int (*v_check)(CHKARGS); @@ -60,7 +56,6 @@ static int post_AT(CHKARGS); static int post_fi(CHKARGS); static int post_nf(CHKARGS); static int post_TH(CHKARGS); -static int post_TS(CHKARGS); static int post_UC(CHKARGS); static v_check posts_at[] = { post_AT, NULL }; @@ -73,7 +68,6 @@ static v_check posts_par[] = { check_par, NULL }; static v_check posts_part[] = { check_part, NULL }; static v_check posts_sec[] = { check_sec, NULL }; static v_check posts_th[] = { check_ge2, check_le5, check_title, post_TH, NULL }; -static v_check posts_ts[] = { post_TS, NULL }; static v_check posts_uc[] = { post_UC, NULL }; static v_check pres_bline[] = { check_bline, NULL }; @@ -111,8 +105,6 @@ static const struct man_valid man_valids[MAN_MAX] = { { NULL, NULL }, /* PD */ { NULL, posts_at }, /* AT */ { NULL, NULL }, /* in */ - { NULL, posts_ts }, /* TS */ - { NULL, NULL }, /* TE */ { NULL, posts_ft }, /* ft */ }; @@ -122,10 +114,16 @@ man_valid_pre(struct man *m, struct man_node *n) { v_check *cp; - if (MAN_TEXT == n->type) - return(1); - if (MAN_ROOT == n->type) + switch (n->type) { + case (MAN_TEXT): + /* FALLTHROUGH */ + case (MAN_ROOT): + /* FALLTHROUGH */ + case (MAN_TBL): return(1); + default: + break; + } if (NULL == (cp = man_valids[n->tok].pres)) return(1); @@ -150,6 +148,8 @@ man_valid_post(struct man *m) return(check_text(m, m->last)); case (MAN_ROOT): return(check_root(m, m->last)); + case (MAN_TBL): + return(1); default: break; } @@ -572,13 +572,3 @@ post_AT(CHKARGS) m->meta.source = mandoc_strdup(p); return(1); } - -static int -post_TS(CHKARGS) -{ - - if (MAN_HEAD == n->type) - n->parent->data.TS = tbl_alloc(); - - return(1); -} diff --git a/usr.bin/mandoc/mandoc.h b/usr.bin/mandoc/mandoc.h index e30929c9521..366614ef138 100644 --- a/usr.bin/mandoc/mandoc.h +++ b/usr.bin/mandoc/mandoc.h @@ -1,6 +1,6 @@ -/* $Id: mandoc.h,v 1.26 2011/01/03 23:39:27 schwarze Exp $ */ +/* $Id: mandoc.h,v 1.27 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -100,8 +100,20 @@ enum mandocerr { MANDOCERR_BADESCAPE, /* unknown escape sequence */ MANDOCERR_BADQUOTE, /* unterminated quoted string */ + /* related to tables */ + MANDOCERR_TBLEXTRADAT, /* extra data cells */ + MANDOCERR_ERROR, /* ===== start of errors ===== */ + /* related to tables */ + MANDOCERR_TBL, /* bad table syntax */ + MANDOCERR_TBLOPT, /* bad table option */ + MANDOCERR_TBLLAYOUT, /* bad table layout */ + MANDOCERR_TBLNOLAYOUT, /* no table layout cells specified */ + MANDOCERR_TBLNODATA, /* no table data cells specified */ + MANDOCERR_TBLIGNDATA, /* ignore data in cell */ + MANDOCERR_TBLBLOCK, /* data block still open */ + MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */ MANDOCERR_BADCHAR, /* skipping bad character */ MANDOCERR_NOTEXT, /* skipping text before the first section header */ @@ -120,7 +132,6 @@ enum mandocerr { MANDOCERR_LISTTYPE, /* missing list type */ MANDOCERR_ARGSLOST, /* line argument(s) will be lost */ MANDOCERR_BODYLOST, /* body argument(s) will be lost */ - MANDOCERR_TBL, /* tbl(1) error */ MANDOCERR_FATAL, /* ===== start of fatal errors ===== */ @@ -137,6 +148,124 @@ enum mandocerr { MANDOCERR_MAX }; +struct tbl { + char tab; /* cell-separator */ + char decimal; /* decimal point */ + int linesize; + char delims[2]; /* FIXME: deprecate */ + int opts; +#define TBL_OPT_CENTRE (1 << 0) +#define TBL_OPT_EXPAND (1 << 1) +#define TBL_OPT_BOX (1 << 2) +#define TBL_OPT_DBOX (1 << 3) +#define TBL_OPT_ALLBOX (1 << 4) +#define TBL_OPT_NOKEEP (1 << 5) +#define TBL_OPT_NOSPACE (1 << 6) + int cols; /* number of columns */ +}; + +enum tbl_headt { + TBL_HEAD_DATA, /* plug in data from tbl_dat */ + TBL_HEAD_VERT, /* vertical spacer */ + TBL_HEAD_DVERT /* double-vertical spacer */ +}; + +/* + * The head of a table specifies all of its columns. When formatting a + * tbl_span, iterate over these and plug in data from the tbl_span when + * appropriate, using tbl_cell as a guide to placement. + */ +struct tbl_head { + enum tbl_headt pos; + int ident; /* 0 <= unique id < cols */ + struct tbl_head *next; + struct tbl_head *prev; +}; + +enum tbl_cellt { + TBL_CELL_CENTRE, /* c, C */ + TBL_CELL_RIGHT, /* r, R */ + TBL_CELL_LEFT, /* l, L */ + TBL_CELL_NUMBER, /* n, N */ + TBL_CELL_SPAN, /* s, S */ + TBL_CELL_LONG, /* a, A */ + TBL_CELL_DOWN, /* ^ */ + TBL_CELL_HORIZ, /* _, - */ + TBL_CELL_DHORIZ, /* = */ + TBL_CELL_VERT, /* | */ + TBL_CELL_DVERT, /* || */ + TBL_CELL_MAX +}; + +/* + * A cell in a layout row. + */ +struct tbl_cell { + struct tbl_cell *next; + enum tbl_cellt pos; + int spacing; + int flags; +#define TBL_CELL_TALIGN (1 << 0) /* t, T */ +#define TBL_CELL_BALIGN (1 << 1) /* d, D */ +#define TBL_CELL_BOLD (1 << 2) /* fB, B, b */ +#define TBL_CELL_ITALIC (1 << 3) /* fI, I, i */ +#define TBL_CELL_EQUAL (1 << 4) /* e, E */ +#define TBL_CELL_UP (1 << 5) /* u, U */ +#define TBL_CELL_WIGN (1 << 6) /* z, Z */ + struct tbl_head *head; +}; + +/* + * A layout row. + */ +struct tbl_row { + struct tbl_row *next; + struct tbl_cell *first; + struct tbl_cell *last; +}; + +enum tbl_datt { + TBL_DATA_NONE, + TBL_DATA_DATA, + TBL_DATA_HORIZ, + TBL_DATA_DHORIZ, + TBL_DATA_NHORIZ, + TBL_DATA_NDHORIZ +}; + +/* + * A cell within a row of data. The "string" field contains the actual + * string value that's in the cell. The rest is layout. + */ +struct tbl_dat { + struct tbl_cell *layout; /* layout cell: CAN BE NULL */ + struct tbl_dat *next; + char *string; + enum tbl_datt pos; +}; + +enum tbl_spant { + TBL_SPAN_DATA, /* span consists of data */ + TBL_SPAN_HORIZ, /* span is horizontal line */ + TBL_SPAN_DHORIZ /* span is double horizontal line */ +}; + +/* + * A row of data in a table. + */ +struct tbl_span { + struct tbl *tbl; + struct tbl_head *head; + struct tbl_row *layout; /* layout row: CAN BE NULL */ + struct tbl_dat *first; + struct tbl_dat *last; + int flags; +#define TBL_SPAN_FIRST (1 << 0) +#define TBL_SPAN_LAST (1 << 1) + enum tbl_spant pos; + struct tbl_span *next; +}; + /* * Available registers (set in libroff, accessed elsewhere). */ diff --git a/usr.bin/mandoc/mdoc.3 b/usr.bin/mandoc/mdoc.3 index 58c2116cd21..556b5792546 100644 --- a/usr.bin/mandoc/mdoc.3 +++ b/usr.bin/mandoc/mdoc.3 @@ -1,6 +1,6 @@ -.\" $Id: mdoc.3,v 1.14 2010/12/22 00:33:25 schwarze Exp $ +.\" $Id: mdoc.3,v 1.15 2011/01/04 22:28:17 schwarze Exp $ .\" -.\" Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> +.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> .\" Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> .\" .\" Permission to use, copy, modify, and distribute this software for any @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: December 22 2010 $ +.Dd $Mdocdate: January 4 2011 $ .Dt MDOC 3 .Os .Sh NAME @@ -33,6 +33,11 @@ .In mdoc.h .Vt extern const char * const * mdoc_macronames; .Vt extern const char * const * mdoc_argnames; +.Ft int +.Fo mdoc_addspan +.Fa "struct mdoc *mdoc" +.Fa "const struct tbl_span *span" +.Fc .Ft "struct mdoc *" .Fo mdoc_alloc .Fa "struct regset *regs" @@ -92,6 +97,9 @@ for details. .El .Ss Functions .Bl -ohang +.It Fn mdoc_addspan +Add a table span to the parsing stream. +Returns 0 on failure, 1 on success. .It Fn mdoc_alloc Allocates a parsing structure. The diff --git a/usr.bin/mandoc/mdoc.c b/usr.bin/mandoc/mdoc.c index 1060aa53fc1..51386a989ab 100644 --- a/usr.bin/mandoc/mdoc.c +++ b/usr.bin/mandoc/mdoc.c @@ -1,6 +1,6 @@ -/* $Id: mdoc.c,v 1.76 2011/01/01 17:38:11 schwarze Exp $ */ +/* $Id: mdoc.c,v 1.77 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -28,10 +28,6 @@ #include "libmdoc.h" #include "libmandoc.h" -#include "out.h" -#include "term.h" -#include "tbl.h" - const char *const __mdoc_macronames[MDOC_MAX] = { "Ap", "Dd", "Dt", "Os", "Sh", "Ss", "Pp", "D1", @@ -69,7 +65,7 @@ const char *const __mdoc_macronames[MDOC_MAX] = { /* LINTED */ "Dx", "%Q", "br", "sp", /* LINTED */ - "%U", "Ta", "TS", "TE" + "%U", "Ta" }; const char *const __mdoc_argnames[MDOC_ARG_MAX] = { @@ -98,6 +94,8 @@ static int node_append(struct mdoc *, struct mdoc_node *); static int mdoc_ptext(struct mdoc *, int, char *, int); static int mdoc_pmacro(struct mdoc *, int, char *, int); +static int mdoc_span_alloc(struct mdoc *, + const struct tbl_span *); const struct mdoc_node * @@ -221,6 +219,24 @@ mdoc_endparse(struct mdoc *m) return(0); } +int +mdoc_addspan(struct mdoc *m, const struct tbl_span *sp) +{ + + if (MDOC_HALT & m->flags) + return(0); + + /* No text before an initial macro. */ + + if (SEC_NONE == m->lastnamed) { + /* FIXME: grab from span. */ + mdoc_pmsg(m, 0, 0, MANDOCERR_NOTEXT); + return(1); + } + + return(mdoc_span_alloc(m, sp)); +} + /* * Main parse routine. Parses a single line -- really just hands off to @@ -229,24 +245,12 @@ mdoc_endparse(struct mdoc *m) int mdoc_parseln(struct mdoc *m, int ln, char *buf, int offs) { - struct mdoc_node *n; if (MDOC_HALT & m->flags) return(0); m->flags |= MDOC_NEWLINE; - n = m->last; - - if (n && MDOC_TS == n->tok && MDOC_BODY == n->type && - strncmp(buf+offs, ".TE", 3)) { - n = n->parent; - if ( ! tbl_read(n->norm->TS, "mdoc tbl parser", - ln, buf+offs, strlen(buf+offs))) - mdoc_nmsg(m, n, MANDOCERR_TBL); - return(1); - } - /* * Let the roff nS register switch SYNOPSIS mode early, * such that the parser knows at all times @@ -383,6 +387,8 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p) mdoc->last = p; switch (p->type) { + case (MDOC_TBL): + /* FALLTHROUGH */ case (MDOC_TEXT): if ( ! mdoc_valid_post(mdoc)) return(0); @@ -499,8 +505,6 @@ mdoc_block_alloc(struct mdoc *m, int line, int pos, case (MDOC_Bl): /* FALLTHROUGH */ case (MDOC_Rs): - /* FALLTHROUGH */ - case (MDOC_TS): p->norm = mandoc_calloc(1, sizeof(union mdoc_data)); break; default: @@ -539,6 +543,22 @@ mdoc_elem_alloc(struct mdoc *m, int line, int pos, return(1); } +static int +mdoc_span_alloc(struct mdoc *m, const struct tbl_span *sp) +{ + struct mdoc_node *n; + + /* FIXME: grab from tbl_span. */ + n = node_alloc(m, 0, 0, MDOC_MAX, MDOC_TBL); + n->span = sp; + + if ( ! node_append(m, n)) + return(0); + + m->next = MDOC_NEXT_SIBLING; + return(1); +} + int mdoc_word_alloc(struct mdoc *m, int line, int pos, const char *p) @@ -567,10 +587,6 @@ static void mdoc_node_free(struct mdoc_node *p) { - if (MDOC_TS == p->tok && MDOC_BLOCK == p->type) - if (p->norm->TS) - tbl_free(p->norm->TS); - if (MDOC_BLOCK == p->type || MDOC_ELEM == p->type) free(p->norm); if (p->string) diff --git a/usr.bin/mandoc/mdoc.h b/usr.bin/mandoc/mdoc.h index a74b2ebc8d1..b24ac1a0b5e 100644 --- a/usr.bin/mandoc/mdoc.h +++ b/usr.bin/mandoc/mdoc.h @@ -1,6 +1,6 @@ -/* $Id: mdoc.h,v 1.41 2010/12/29 00:47:30 schwarze Exp $ */ +/* $Id: mdoc.h,v 1.42 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -143,8 +143,6 @@ enum mdoct { MDOC_sp, MDOC__U, MDOC_Ta, - MDOC_TS, - MDOC_TE, MDOC_MAX }; @@ -192,6 +190,7 @@ enum mdoc_type { MDOC_TAIL, MDOC_BODY, MDOC_BLOCK, + MDOC_TBL, MDOC_ROOT }; @@ -370,7 +369,6 @@ union mdoc_data { struct mdoc_bf Bf; struct mdoc_bl Bl; struct mdoc_rs Rs; - struct tbl *TS; }; /* @@ -402,6 +400,7 @@ struct mdoc_node { struct mdoc_node *body; /* BLOCK */ struct mdoc_node *tail; /* BLOCK */ char *string; /* TEXT */ + const struct tbl_span *span; /* TBL */ enum mdoc_endbody end; /* BODY */ }; @@ -429,6 +428,8 @@ int mdoc_parseln(struct mdoc *, int, char *, int); const struct mdoc_node *mdoc_node(const struct mdoc *); const struct mdoc_meta *mdoc_meta(const struct mdoc *); int mdoc_endparse(struct mdoc *); +int mdoc_addspan(struct mdoc *, + const struct tbl_span *); __END_DECLS diff --git a/usr.bin/mandoc/mdoc_html.c b/usr.bin/mandoc/mdoc_html.c index 26bda0d55fc..427583b9711 100644 --- a/usr.bin/mandoc/mdoc_html.c +++ b/usr.bin/mandoc/mdoc_html.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_html.c,v 1.44 2010/12/29 00:47:31 schwarze Exp $ */ +/* $Id: mdoc_html.c,v 1.45 2011/01/04 22:28:17 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -239,8 +239,6 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = { {mdoc_sp_pre, NULL}, /* sp */ {mdoc__x_pre, mdoc__x_post}, /* %U */ {NULL, NULL}, /* Ta */ - {NULL, NULL}, /* TS */ - {NULL, NULL}, /* TE */ }; static const char * const lists[LIST_MAX] = { @@ -420,6 +418,9 @@ print_mdoc_node(MDOC_ARGS) case (MDOC_TEXT): print_text(h, n->string); return; + case (MDOC_TBL): + print_tbl(h, n->span); + break; default: if (mdocs[n->tok].pre && ENDBODY_NOT == n->end) child = (*mdocs[n->tok].pre)(m, n, h); @@ -448,6 +449,8 @@ print_mdoc_node(MDOC_ARGS) case (MDOC_ROOT): mdoc_root_post(m, n, h); break; + case (MDOC_TBL): + break; default: if (mdocs[n->tok].post && ENDBODY_NOT == n->end) (*mdocs[n->tok].post)(m, n, h); diff --git a/usr.bin/mandoc/mdoc_macro.c b/usr.bin/mandoc/mdoc_macro.c index 77c4d3d25cf..699ebbb92f6 100644 --- a/usr.bin/mandoc/mdoc_macro.c +++ b/usr.bin/mandoc/mdoc_macro.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_macro.c,v 1.61 2010/12/21 23:46:18 schwarze Exp $ */ +/* $Id: mdoc_macro.c,v 1.62 2011/01/04 22:28:17 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> @@ -185,8 +185,6 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { in_line_eoln, 0 }, /* sp */ { in_line_eoln, 0 }, /* %U */ { phrase_ta, MDOC_CALLABLE | MDOC_PARSED }, /* Ta */ - { blk_part_exp, MDOC_EXPLICIT }, /* TS */ - { blk_exp_close, MDOC_EXPLICIT }, /* TE */ }; const struct mdoc_macro * const mdoc_macros = __mdoc_macros; @@ -309,8 +307,6 @@ rew_alt(enum mdoct tok) return(MDOC_So); case (MDOC_Xc): return(MDOC_Xo); - case (MDOC_TE): - return(MDOC_TS); default: return(tok); } diff --git a/usr.bin/mandoc/mdoc_term.c b/usr.bin/mandoc/mdoc_term.c index 4ee3ee6160f..b97de215fc6 100644 --- a/usr.bin/mandoc/mdoc_term.c +++ b/usr.bin/mandoc/mdoc_term.c @@ -1,6 +1,6 @@ -/* $Id: mdoc_term.c,v 1.121 2010/12/29 00:47:31 schwarze Exp $ */ +/* $Id: mdoc_term.c,v 1.122 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -30,7 +30,6 @@ #include "mdoc.h" #include "chars.h" #include "main.h" -#include "tbl.h" #define INDENT 5 #define HALFINDENT 3 @@ -116,7 +115,6 @@ static int termp_sh_pre(DECL_ARGS); static int termp_sm_pre(DECL_ARGS); static int termp_sp_pre(DECL_ARGS); static int termp_ss_pre(DECL_ARGS); -static int termp_ts_pre(DECL_ARGS); static int termp_under_pre(DECL_ARGS); static int termp_ud_pre(DECL_ARGS); static int termp_vt_pre(DECL_ARGS); @@ -246,8 +244,6 @@ static const struct termact termacts[MDOC_MAX] = { { termp_sp_pre, NULL }, /* sp */ { termp_under_pre, termp____post }, /* %U */ { NULL, NULL }, /* Ta */ - { termp_ts_pre, NULL }, /* TS */ - { NULL, NULL }, /* TE */ }; @@ -312,11 +308,20 @@ print_mdoc_node(DECL_ARGS) memset(&npair, 0, sizeof(struct termpair)); npair.ppair = pair; - - if (MDOC_TEXT == n->type) - term_word(p, n->string); - else if (termacts[n->tok].pre && ENDBODY_NOT == n->end) - chld = (*termacts[n->tok].pre)(p, &npair, m, n); + + switch (n->type) { + case (MDOC_TEXT): + term_word(p, n->string); + break; + case (MDOC_TBL): + term_tbl(p, n->span); + break; + default: + if (termacts[n->tok].pre && ENDBODY_NOT == n->end) + chld = (*termacts[n->tok].pre) + (p, &npair, m, n); + break; + } /* * Keeps only work until the end of a line. If a keep was @@ -353,8 +358,14 @@ print_mdoc_node(DECL_ARGS) term_fontpopq(p, font); - if (MDOC_TEXT != n->type && termacts[n->tok].post && - ! (MDOC_ENDED & n->flags)) { + switch (n->type) { + case (MDOC_TEXT): + break; + case (MDOC_TBL): + break; + default: + if ( ! termacts[n->tok].post || MDOC_ENDED & n->flags) + break; (void)(*termacts[n->tok].post)(p, &npair, m, n); /* @@ -372,6 +383,7 @@ print_mdoc_node(DECL_ARGS) */ if (ENDBODY_NOSPACE == n->end) p->flags |= TERMP_NOSPACE; + break; } if (MDOC_EOS & n->flags) @@ -2109,21 +2121,6 @@ termp_lk_pre(DECL_ARGS) /* ARGSUSED */ static int -termp_ts_pre(DECL_ARGS) -{ - - if (MDOC_BLOCK != n->type) - return(0); - - if (tbl_close(p, n->norm->TS, "mdoc tbl postprocess", n->line)) - tbl_write(p, n->norm->TS); - - return(0); -} - - -/* ARGSUSED */ -static int termp_bk_pre(DECL_ARGS) { diff --git a/usr.bin/mandoc/mdoc_validate.c b/usr.bin/mandoc/mdoc_validate.c index 6cab7c65ca7..b5556f1755b 100644 --- a/usr.bin/mandoc/mdoc_validate.c +++ b/usr.bin/mandoc/mdoc_validate.c @@ -1,6 +1,6 @@ -/* $Id: mdoc_validate.c,v 1.83 2011/01/03 23:39:27 schwarze Exp $ */ +/* $Id: mdoc_validate.c,v 1.84 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -32,10 +32,6 @@ #include "libmdoc.h" #include "libmandoc.h" -#include "out.h" -#include "term.h" -#include "tbl.h" - /* FIXME: .Bl -diag can't have non-text children in HEAD. */ #define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n @@ -127,7 +123,6 @@ static int pre_par(PRE_ARGS); static int pre_sh(PRE_ARGS); static int pre_ss(PRE_ARGS); static int pre_std(PRE_ARGS); -static int pre_ts(PRE_ARGS); static v_post posts_an[] = { post_an, NULL }; static v_post posts_at[] = { post_at, post_defaults, NULL }; @@ -174,7 +169,6 @@ static v_pre pres_pp[] = { pre_par, NULL }; static v_pre pres_sh[] = { pre_sh, NULL }; static v_pre pres_ss[] = { pre_ss, NULL }; static v_pre pres_std[] = { pre_std, NULL }; -static v_pre pres_ts[] = { pre_ts, NULL }; const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Ap */ @@ -299,8 +293,6 @@ const struct valids mdoc_valids[MDOC_MAX] = { { pres_pp, posts_sp }, /* sp */ { NULL, posts_text1 }, /* %U */ { NULL, NULL }, /* Ta */ - { pres_ts, NULL }, /* TS */ - { NULL, NULL }, /* TE */ }; #define RSORD_MAX 14 /* Number of `Rs' blocks. */ @@ -330,12 +322,19 @@ mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) int line, pos; char *tp; - if (MDOC_TEXT == n->type) { + switch (n->type) { + case (MDOC_TEXT): tp = n->string; line = n->line; pos = n->pos; check_text(mdoc, line, pos, tp); + /* FALLTHROUGH */ + case (MDOC_TBL): + /* FALLTHROUGH */ + case (MDOC_ROOT): return(1); + default: + break; } check_args(mdoc, n); @@ -358,10 +357,16 @@ mdoc_valid_post(struct mdoc *mdoc) return(1); mdoc->last->flags |= MDOC_VALID; - if (MDOC_TEXT == mdoc->last->type) + switch (mdoc->last->type) { + case (MDOC_TEXT): + /* FALLTHROUGH */ + case (MDOC_TBL): return(1); - if (MDOC_ROOT == mdoc->last->type) + case (MDOC_ROOT): return(post_root(mdoc)); + default: + break; + } if (NULL == mdoc_valids[mdoc->last->tok].post) return(1); @@ -1897,16 +1902,6 @@ post_ignpar(POST_ARGS) } static int -pre_ts(PRE_ARGS) -{ - - if (MDOC_BLOCK == mdoc->last->type) - mdoc->last->norm->TS = tbl_alloc(); - - return(1); -} - -static int pre_par(PRE_ARGS) { diff --git a/usr.bin/mandoc/roff.3 b/usr.bin/mandoc/roff.3 index f8cb1622c69..58843b605d0 100644 --- a/usr.bin/mandoc/roff.3 +++ b/usr.bin/mandoc/roff.3 @@ -1,6 +1,6 @@ -.\" $Id: roff.3,v 1.5 2010/08/20 00:53:35 schwarze Exp $ +.\" $Id: roff.3,v 1.6 2011/01/04 22:28:17 schwarze Exp $ .\" -.\" Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> +.\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: August 20 2010 $ +.Dd $Mdocdate: January 4 2011 $ .Dt ROFF 3 .Os .Sh NAME @@ -23,7 +23,8 @@ .Nm roff_endparse , .Nm roff_free , .Nm roff_parseln , -.Nm roff_reset +.Nm roff_reset , +.Nm roff_span .Nd roff macro compiler library .Sh SYNOPSIS .In mandoc.h @@ -34,7 +35,7 @@ .Fa "void *data" .Fa "mandocmsg msgs" .Fc -.Ft int +.Ft void .Fn roff_endparse "struct roff *roff" .Ft void .Fn roff_free "struct roff *roff" @@ -49,6 +50,8 @@ .Fc .Ft void .Fn roff_reset "struct roff *roff" +.Ft "const struct tbl_span *" +.Fn roff_span "const struct roff *roff" .Sh DESCRIPTION The .Nm @@ -138,7 +141,13 @@ This line should not contain the trailing newline. Returns 0 on failure, 1 on success. .It Fn roff_endparse Signals that the parse is complete. -Returns 0 on failure, 1 on success. +.It Fn roff_span +If +.Fn roff_parseln +returned +.Va ROFF_TBL , +return the last parsed table row. +Returns NULL otherwise. .El .Sh EXAMPLES See diff --git a/usr.bin/mandoc/roff.c b/usr.bin/mandoc/roff.c index d25041cb8df..f4bc46244b7 100644 --- a/usr.bin/mandoc/roff.c +++ b/usr.bin/mandoc/roff.c @@ -1,6 +1,6 @@ -/* $Id: roff.c,v 1.26 2011/01/03 23:19:33 schwarze Exp $ */ +/* $Id: roff.c,v 1.27 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -15,10 +15,6 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include <assert.h> #include <errno.h> #include <ctype.h> @@ -29,6 +25,7 @@ #include "mandoc.h" #include "roff.h" +#include "libroff.h" #include "libmandoc.h" #define RSTACK_MAX 128 @@ -56,6 +53,9 @@ enum rofft { ROFF_rm, ROFF_so, ROFF_tr, + ROFF_TS, + ROFF_TE, + ROFF_T_, ROFF_cblock, ROFF_ccond, /* FIXME: remove this. */ ROFF_USERDEF, @@ -67,7 +67,6 @@ enum roffrule { ROFFRULE_DENY }; - struct roffstr { char *name; /* key of symbol */ char *string; /* current value */ @@ -83,6 +82,9 @@ struct roff { struct regset *regs; /* read/writable registers */ struct roffstr *first_string; /* user-defined strings & macros */ const char *current_string; /* value of last called user macro */ + struct tbl_node *first_tbl; /* first table parsed */ + struct tbl_node *last_tbl; /* last table parsed */ + struct tbl_node *tbl; /* current table being parsed */ }; struct roffnode { @@ -138,6 +140,9 @@ static int roff_res(struct roff *, static void roff_setstr(struct roff *, const char *, const char *, int); static enum rofferr roff_so(ROFF_ARGS); +static enum rofferr roff_TE(ROFF_ARGS); +static enum rofferr roff_TS(ROFF_ARGS); +static enum rofferr roff_T_(ROFF_ARGS); static enum rofferr roff_userdef(ROFF_ARGS); /* See roff_hash_find() */ @@ -168,6 +173,9 @@ static struct roffmac roffs[ROFF_MAX] = { { "rm", roff_line_error, NULL, NULL, 0, NULL }, { "so", roff_so, NULL, NULL, 0, NULL }, { "tr", roff_line_ignore, NULL, NULL, 0, NULL }, + { "TS", roff_TS, NULL, NULL, 0, NULL }, + { "TE", roff_TE, NULL, NULL, 0, NULL }, + { "T&", roff_T_, NULL, NULL, 0, NULL }, { ".", roff_cblock, NULL, NULL, 0, NULL }, { "\\}", roff_ccond, NULL, NULL, 0, NULL }, { NULL, roff_userdef, NULL, NULL, 0, NULL }, @@ -289,9 +297,19 @@ roffnode_push(struct roff *r, enum rofft tok, const char *name, static void roff_free1(struct roff *r) { + struct tbl_node *t; + + while (r->first_tbl) { + t = r->first_tbl; + r->first_tbl = t->next; + tbl_free(t); + } + + r->first_tbl = r->last_tbl = r->tbl = NULL; while (r->last) roffnode_pop(r); + roff_freestr(r); } @@ -431,6 +449,7 @@ roff_parseln(struct roff *r, int ln, char **bufp, size_t *szp, int pos, int *offs) { enum rofft t; + enum rofferr e; int ppos; /* @@ -450,11 +469,17 @@ roff_parseln(struct roff *r, int ln, char **bufp, if (r->last && ! ROFF_CTL((*bufp)[pos])) { t = r->last->tok; assert(roffs[t].text); - return((*roffs[t].text) - (r, t, bufp, szp, - ln, pos, pos, offs)); - } else if ( ! ROFF_CTL((*bufp)[pos])) + e = (*roffs[t].text) + (r, t, bufp, szp, ln, pos, pos, offs); + assert(ROFF_IGN == e || ROFF_CONT == e); + if (ROFF_CONT == e && r->tbl) + return(tbl_read(r->tbl, ln, *bufp, *offs)); + return(e); + } else if ( ! ROFF_CTL((*bufp)[pos])) { + if (r->tbl) + return(tbl_read(r->tbl, ln, *bufp, *offs)); return(ROFF_CONT); + } /* * If a scope is open, go to the child handler for that macro, @@ -486,14 +511,20 @@ roff_parseln(struct roff *r, int ln, char **bufp, } -int +void roff_endparse(struct roff *r) { - if (NULL == r->last) - return(1); - return((*r->msg)(MANDOCERR_SCOPEEXIT, r->data, r->last->line, - r->last->col, NULL)); + if (r->last) + (*r->msg)(MANDOCERR_SCOPEEXIT, r->data, + r->last->line, r->last->col, NULL); + + if (r->tbl) { + (*r->msg)(MANDOCERR_SCOPEEXIT, r->data, + r->tbl->line, r->tbl->pos, NULL); + tbl_end(r->tbl); + r->tbl = NULL; + } } @@ -562,8 +593,7 @@ roff_cblock(ROFF_ARGS) */ if (NULL == r->last) { - if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL)) - return(ROFF_ERR); + (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); return(ROFF_IGN); } @@ -582,14 +612,12 @@ roff_cblock(ROFF_ARGS) case (ROFF_ig): break; default: - if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL)) - return(ROFF_ERR); + (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); return(ROFF_IGN); } if ((*bufp)[pos]) - if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL)) - return(ROFF_ERR); + (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL); roffnode_pop(r); roffnode_cleanscope(r); @@ -616,8 +644,7 @@ roff_ccond(ROFF_ARGS) { if (NULL == r->last) { - if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL)) - return(ROFF_ERR); + (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); return(ROFF_IGN); } @@ -629,20 +656,17 @@ roff_ccond(ROFF_ARGS) case (ROFF_if): break; default: - if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL)) - return(ROFF_ERR); + (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); return(ROFF_IGN); } if (r->last->endspan > -1) { - if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL)) - return(ROFF_ERR); + (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); return(ROFF_IGN); } if ((*bufp)[pos]) - if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL)) - return(ROFF_ERR); + (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL); roffnode_pop(r); roffnode_cleanscope(r); @@ -1095,6 +1119,55 @@ roff_nr(ROFF_ARGS) /* ARGSUSED */ static enum rofferr +roff_TE(ROFF_ARGS) +{ + + if (NULL == r->tbl) + (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); + else + tbl_end(r->tbl); + + r->tbl = NULL; + return(ROFF_IGN); +} + +/* ARGSUSED */ +static enum rofferr +roff_T_(ROFF_ARGS) +{ + + if (NULL == r->tbl) + (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); + else + tbl_restart(ppos, ln, r->tbl); + + return(ROFF_IGN); +} + +/* ARGSUSED */ +static enum rofferr +roff_TS(ROFF_ARGS) +{ + struct tbl_node *t; + + if (r->tbl) { + (*r->msg)(MANDOCERR_SCOPEBROKEN, r->data, ln, ppos, NULL); + tbl_end(r->tbl); + } + + t = tbl_alloc(ppos, ln, r->data, r->msg); + + if (r->last_tbl) + r->last_tbl->next = t; + else + r->first_tbl = r->last_tbl = t; + + r->tbl = r->last_tbl = t; + return(ROFF_IGN); +} + +/* ARGSUSED */ +static enum rofferr roff_so(ROFF_ARGS) { char *name; @@ -1270,3 +1343,10 @@ roff_freestr(struct roff *r) r->first_string = NULL; } + +const struct tbl_span * +roff_span(const struct roff *r) +{ + + return(r->tbl ? tbl_span(r->tbl) : NULL); +} diff --git a/usr.bin/mandoc/roff.h b/usr.bin/mandoc/roff.h index 938c300f32f..1e533701a50 100644 --- a/usr.bin/mandoc/roff.h +++ b/usr.bin/mandoc/roff.h @@ -1,4 +1,4 @@ -/* $Id: roff.h,v 1.6 2010/11/25 22:23:31 schwarze Exp $ */ +/* $Id: roff.h,v 1.7 2011/01/04 22:28:17 schwarze Exp $ */ /* * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -24,6 +24,7 @@ enum rofferr { ROFF_REPARSE, /* re-run main parser on the result */ ROFF_SO, /* include another file */ ROFF_IGN, /* ignore current line */ + ROFF_TBL, /* a table row was successfully parsed */ ROFF_ERR /* badness: puke and stop */ }; @@ -36,7 +37,8 @@ struct roff *roff_alloc(struct regset *, void *, mandocmsg); void roff_reset(struct roff *); enum rofferr roff_parseln(struct roff *, int, char **, size_t *, int, int *); -int roff_endparse(struct roff *); +void roff_endparse(struct roff *); +const struct tbl_span *roff_span(const struct roff *); __END_DECLS diff --git a/usr.bin/mandoc/tbl.c b/usr.bin/mandoc/tbl.c index 57d3da90880..56369368098 100644 --- a/usr.bin/mandoc/tbl.c +++ b/usr.bin/mandoc/tbl.c @@ -1,6 +1,6 @@ -/* $Id: tbl.c,v 1.3 2010/10/15 22:07:12 schwarze Exp $ */ +/* $Id: tbl.c,v 1.4 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,533 +14,146 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/queue.h> - #include <assert.h> -#include <errno.h> -#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> -#include "out.h" -#include "term.h" -#include "tbl.h" -#include "tbl_extern.h" - - -const char *const errnames[ERR_MAX] = { - "bad syntax", /* ERR_SYNTAX */ - "bad option" /* ERR_OPTION */ -}; - -static char buf[1024]; /* XXX */ - -static enum tbl_tok tbl_next_char(char); -static void tbl_init(struct tbl *); -static void tbl_clear(struct tbl *); -static struct tbl_head *tbl_head_alloc(struct tbl *); -static void tbl_span_free(struct tbl_span *); -static void tbl_data_free(struct tbl_data *); -static void tbl_row_free(struct tbl_row *); - -static void headadj(const struct tbl_cell *, - struct tbl_head *); +#include "mandoc.h" +#include "roff.h" +#include "libmandoc.h" +#include "libroff.h" -static void -tbl_init(struct tbl *tbl) +enum rofferr +tbl_read(struct tbl_node *tbl, int ln, const char *p, int offs) { + int len; + const char *cp; - bzero(tbl, sizeof(struct tbl)); - - tbl->part = TBL_PART_OPTS; - tbl->tab = '\t'; - tbl->linesize = 12; - tbl->decimal = '.'; - - TAILQ_INIT(&tbl->span); - TAILQ_INIT(&tbl->row); - TAILQ_INIT(&tbl->head); -} + cp = &p[offs]; + len = (int)strlen(cp); + /* + * If we're in the options section and we don't have a + * terminating semicolon, assume we've moved directly into the + * layout section. No need to report a warning: this is, + * apparently, standard behaviour. + */ -int -tbl_read(struct tbl *tbl, const char *f, int ln, const char *p, int len) -{ - - if (len && TBL_PART_OPTS == tbl->part) - if (';' != p[len - 1]) + if (TBL_PART_OPTS == tbl->part && len) + if (';' != cp[len - 1]) tbl->part = TBL_PART_LAYOUT; + /* Now process each logical section of the table. */ + switch (tbl->part) { case (TBL_PART_OPTS): - return(tbl_option(tbl, f, ln, p)); - case (TBL_PART_CLAYOUT): - /* FALLTHROUGH */ + return(tbl_option(tbl, ln, p) ? ROFF_IGN : ROFF_ERR); case (TBL_PART_LAYOUT): - return(tbl_layout(tbl, f, ln, p)); - case (TBL_PART_DATA): - return(tbl_data(tbl, f, ln, p)); - case (TBL_PART_ERROR): - break; - } - - return(0); -} - - -int -tbl_close(struct termp *p, struct tbl *tbl, const char *f, int ln) -{ - - if (TBL_PART_DATA != tbl->part) - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, 0)); - if ( ! tbl_data_close(tbl, f, ln)) - return(0); -#if 1 - return(tbl_calc_term(p, tbl)); -#else - return(tbl_calc_tree(tbl)); -#endif -} - - -int -tbl_write(struct termp *p, const struct tbl *tbl) -{ - -#if 1 - return(tbl_write_term(p, tbl)); -#else - return(tbl_write_tree(tbl)); -#endif -} - - -static enum tbl_tok -tbl_next_char(char c) -{ - - /* - * These are delimiting tokens. They separate out words in the - * token stream. - */ - - switch (c) { - case ('('): - return(TBL_TOK_OPENPAREN); - case (')'): - return(TBL_TOK_CLOSEPAREN); - case (' '): - return(TBL_TOK_SPACE); - case ('\t'): - return(TBL_TOK_TAB); - case (';'): - return(TBL_TOK_SEMICOLON); - case ('.'): - return(TBL_TOK_PERIOD); - case (','): - return(TBL_TOK_COMMA); - case (0): - return(TBL_TOK_NIL); + return(tbl_layout(tbl, ln, p) ? ROFF_IGN : ROFF_ERR); + case (TBL_PART_CDATA): + return(tbl_cdata(tbl, ln, p) ? ROFF_TBL : ROFF_IGN); default: break; } - return(TBL_TOK_WORD); -} - - -const char * -tbl_last(void) -{ - - return(buf); -} - - -int -tbl_last_uint(void) -{ - char *ep; - long lval; - - /* From OpenBSD's strtol(3). Gross. */ - - errno = 0; - lval = strtol(buf, &ep, 10); - if (buf[0] == 0 || *ep != 0) - return(-1); - if (errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) - return(-1); - if (lval < 0 || lval > INT_MAX) - return(-1); - - return((int)lval); -} - - -enum tbl_tok -tbl_next(const char *p, int *pos) -{ - int i; - enum tbl_tok c; - - buf[0] = 0; - - if (TBL_TOK_WORD != (c = tbl_next_char(p[*pos]))) { - if (TBL_TOK_NIL != c) { - buf[0] = p[*pos]; - buf[1] = 0; - (*pos)++; - } - return(c); - } - /* - * Copy words into a nil-terminated buffer. For now, we use a - * static buffer. Eventually this should be made into a dynamic - * one living in struct tbl. + * This only returns zero if the line is empty, so we ignore it + * and continue on. */ - - for (i = 0; i < 1023; i++, (*pos)++) - if (TBL_TOK_WORD == tbl_next_char(p[*pos])) - buf[i] = p[*pos]; - else - break; - - assert(i < 1023); - buf[i] = 0; - - return(TBL_TOK_WORD); -} - - -int -tbl_err(struct tbl *tbl) -{ - - (void)fprintf(stderr, "%s\n", strerror(errno)); - tbl->part = TBL_PART_ERROR; - return(0); + return(tbl_data(tbl, ln, p) ? ROFF_TBL : ROFF_IGN); } - -/* ARGSUSED */ -int -tbl_warnx(struct tbl *tbl, enum tbl_err tok, - const char *f, int line, int pos) +struct tbl_node * +tbl_alloc(int pos, int line, void *data, const mandocmsg msg) { + struct tbl_node *p; - (void)fprintf(stderr, "%s:%d:%d: %s\n", - f, line, pos + 1, errnames[tok]); - - /* TODO: -Werror */ - return(1); -} - - -int -tbl_errx(struct tbl *tbl, enum tbl_err tok, - const char *f, int line, int pos) -{ - - (void)fprintf(stderr, "%s:%d:%d: %s\n", - f, line, pos + 1, errnames[tok]); - - tbl->part = TBL_PART_ERROR; - return(0); -} - - -struct tbl * -tbl_alloc(void) -{ - struct tbl *p; - - if (NULL == (p = malloc(sizeof(struct tbl)))) - return(NULL); - - tbl_init(p); + p = mandoc_calloc(1, sizeof(struct tbl_node)); + p->line = line; + p->pos = pos; + p->data = data; + p->msg = msg; + p->part = TBL_PART_OPTS; + p->opts.tab = '\t'; + p->opts.linesize = 12; + p->opts.decimal = '.'; return(p); } - -void -tbl_free(struct tbl *p) -{ - - tbl_clear(p); - free(p); -} - - void -tbl_reset(struct tbl *tbl) -{ - - tbl_clear(tbl); - tbl_init(tbl); -} - - -struct tbl_span * -tbl_span_alloc(struct tbl *tbl) -{ - struct tbl_span *p, *pp; - struct tbl_row *row; - - if (NULL == (p = calloc(1, sizeof(struct tbl_span)))) { - (void)tbl_err(tbl); - return(NULL); - } - - TAILQ_INIT(&p->data); - TAILQ_INSERT_TAIL(&tbl->span, p, entries); - - /* LINTED */ - pp = TAILQ_PREV(p, tbl_spanh, entries); - - if (pp) { - row = TAILQ_NEXT(pp->row, entries); - if (NULL == row) - row = pp->row; - } else { - row = TAILQ_FIRST(&tbl->row); - } - - assert(row); - p->row = row; - p->tbl = tbl; - return(p); -} - - -struct tbl_row * -tbl_row_alloc(struct tbl *tbl) -{ - struct tbl_row *p; - - if (NULL == (p = calloc(1, sizeof(struct tbl_row)))) { - (void)tbl_err(tbl); - return(NULL); - } - - TAILQ_INIT(&p->cell); - TAILQ_INSERT_TAIL(&tbl->row, p, entries); - p->tbl = tbl; - return(p); -} - - -static void -headadj(const struct tbl_cell *cell, struct tbl_head *head) -{ - if (TBL_CELL_VERT != cell->pos && - TBL_CELL_DVERT != cell->pos) { - head->pos = TBL_HEAD_DATA; - return; - } - if (TBL_CELL_VERT == cell->pos) - if (TBL_HEAD_DVERT != head->pos) - head->pos = TBL_HEAD_VERT; - if (TBL_CELL_DVERT == cell->pos) - head->pos = TBL_HEAD_DVERT; -} - - -static struct tbl_head * -tbl_head_alloc(struct tbl *tbl) +tbl_free(struct tbl_node *p) { - struct tbl_head *p; - - if (NULL == (p = calloc(1, sizeof(struct tbl_head)))) { - (void)tbl_err(tbl); - return(NULL); - } - p->tbl = tbl; - return(p); -} - - -struct tbl_cell * -tbl_cell_alloc(struct tbl_row *rp, enum tbl_cellt pos) -{ - struct tbl_cell *p, *pp; - struct tbl_head *h, *hp; - - if (NULL == (p = calloc(1, sizeof(struct tbl_cell)))) { - (void)tbl_err(rp->tbl); - return(NULL); - } - - TAILQ_INSERT_TAIL(&rp->cell, p, entries); - p->pos = pos; - p->row = rp; - - /* - * This is a little bit complicated. Here we determine the - * header the corresponds to a cell. We add headers dynamically - * when need be or re-use them, otherwise. As an example, given - * the following: - * - * 1 c || l - * 2 | c | l - * 3 l l - * 3 || c | l |. - * - * We first add the new headers (as there are none) in (1); then - * in (2) we insert the first spanner (as it doesn't match up - * with the header); then we re-use the prior data headers, - * skipping over the spanners; then we re-use everything and add - * a last spanner. Note that VERT headers are made into DVERT - * ones. - */ - - /* LINTED */ - pp = TAILQ_PREV(p, tbl_cellh, entries); - - h = pp ? TAILQ_NEXT(pp->head, entries) : - TAILQ_FIRST(&rp->tbl->head); - - if (h) { - /* Re-use data header. */ - if (TBL_HEAD_DATA == h->pos && - (TBL_CELL_VERT != p->pos && - TBL_CELL_DVERT != p->pos)) { - p->head = h; - return(p); - } - - /* Re-use spanner header. */ - if (TBL_HEAD_DATA != h->pos && - (TBL_CELL_VERT == p->pos || - TBL_CELL_DVERT == p->pos)) { - headadj(p, h); - p->head = h; - return(p); - } - - /* Right-shift headers with a new spanner. */ - if (TBL_HEAD_DATA == h->pos && - (TBL_CELL_VERT == p->pos || - TBL_CELL_DVERT == p->pos)) { - if (NULL == (hp = tbl_head_alloc(rp->tbl))) - return(NULL); - TAILQ_INSERT_BEFORE(h, hp, entries); - headadj(p, hp); - p->head = hp; - return(p); + struct tbl_row *rp; + struct tbl_cell *cp; + struct tbl_span *sp; + struct tbl_dat *dp; + struct tbl_head *hp; + + while (NULL != (rp = p->first_row)) { + p->first_row = rp->next; + while (rp->first) { + cp = rp->first; + rp->first = cp->next; + free(cp); } + free(rp); + } - h = TAILQ_NEXT(h, entries); - if (h) { - headadj(p, h); - p->head = h; - return(p); + while (NULL != (sp = p->first_span)) { + p->first_span = sp->next; + while (sp->first) { + dp = sp->first; + sp->first = dp->next; + if (dp->string) + free(dp->string); + free(dp); } + free(sp); + } - /* Fall through to default case... */ + while (NULL != (hp = p->first_head)) { + p->first_head = hp->next; + free(hp); } - if (NULL == (hp = tbl_head_alloc(rp->tbl))) - return(NULL); - TAILQ_INSERT_TAIL(&rp->tbl->head, hp, entries); - headadj(p, hp); - p->head = hp; - return(p); + free(p); } - -struct tbl_data * -tbl_data_alloc(struct tbl_span *sp) +void +tbl_restart(int line, int pos, struct tbl_node *tbl) { - struct tbl_data *p; - struct tbl_cell *cp; - struct tbl_data *dp; - - if (NULL == (p = calloc(1, sizeof(struct tbl_data)))) { - (void)tbl_err(sp->row->tbl); - return(NULL); - } + if (TBL_PART_CDATA == tbl->part) + TBL_MSG(tbl, MANDOCERR_TBLBLOCK, tbl->line, tbl->pos); - cp = NULL; - /* LINTED */ - if (NULL == (dp = TAILQ_LAST(&sp->data, tbl_datah))) - cp = TAILQ_FIRST(&sp->row->cell); - else if (dp->cell) - cp = TAILQ_NEXT(dp->cell, entries); + tbl->part = TBL_PART_LAYOUT; + tbl->line = line; + tbl->pos = pos; - TAILQ_INSERT_TAIL(&sp->data, p, entries); - - if (cp && (TBL_CELL_VERT == cp->pos || - TBL_CELL_DVERT == cp->pos)) - cp = TAILQ_NEXT(cp, entries); - - p->span = sp; - p->cell = cp; - return(p); + if (NULL == tbl->first_span || NULL == tbl->first_span->first) + TBL_MSG(tbl, MANDOCERR_TBLNODATA, tbl->line, tbl->pos); } - -static void -tbl_clear(struct tbl *p) +const struct tbl_span * +tbl_span(const struct tbl_node *tbl) { - struct tbl_span *span; - struct tbl_head *head; - struct tbl_row *row; - /* LINTED */ - while ((span = TAILQ_FIRST(&p->span))) { - TAILQ_REMOVE(&p->span, span, entries); - tbl_span_free(span); - } - /* LINTED */ - while ((row = TAILQ_FIRST(&p->row))) { - TAILQ_REMOVE(&p->row, row, entries); - tbl_row_free(row); - } - /* LINTED */ - while ((head = TAILQ_FIRST(&p->head))) { - TAILQ_REMOVE(&p->head, head, entries); - free(head); - } + assert(tbl); + return(tbl->last_span); } - -static void -tbl_span_free(struct tbl_span *p) +void +tbl_end(struct tbl_node *tbl) { - struct tbl_data *data; - - /* LINTED */ - while ((data = TAILQ_FIRST(&p->data))) { - TAILQ_REMOVE(&p->data, data, entries); - tbl_data_free(data); - } - free(p); -} + if (NULL == tbl->first_span || NULL == tbl->first_span->first) + TBL_MSG(tbl, MANDOCERR_TBLNODATA, tbl->line, tbl->pos); -static void -tbl_data_free(struct tbl_data *p) -{ + if (tbl->last_span) + tbl->last_span->flags |= TBL_SPAN_LAST; - if (p->string) - free(p->string); - free(p); + if (TBL_PART_CDATA == tbl->part) + TBL_MSG(tbl, MANDOCERR_TBLBLOCK, tbl->line, tbl->pos); } - -static void -tbl_row_free(struct tbl_row *p) -{ - struct tbl_cell *cell; - - /* LINTED */ - while ((cell = TAILQ_FIRST(&p->cell))) { - TAILQ_REMOVE(&p->cell, cell, entries); - free(cell); - } - free(p); -} diff --git a/usr.bin/mandoc/tbl.h b/usr.bin/mandoc/tbl.h deleted file mode 100644 index 29ac777496f..00000000000 --- a/usr.bin/mandoc/tbl.h +++ /dev/null @@ -1,34 +0,0 @@ -/* $Id: tbl.h,v 1.3 2010/10/15 22:07:12 schwarze Exp $ */ -/* - * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef TBL_H -#define TBL_H - -__BEGIN_DECLS - -struct tbl; - -struct tbl *tbl_alloc(void); -void tbl_free(struct tbl *); -void tbl_reset(struct tbl *); - -int tbl_read(struct tbl *, const char *, int, const char *, int); -int tbl_close(struct termp *, struct tbl *, const char *, int); -int tbl_write(struct termp *, const struct tbl *); - -__END_DECLS - -#endif /*TBL_H*/ diff --git a/usr.bin/mandoc/tbl_data.c b/usr.bin/mandoc/tbl_data.c index 09bfbebcda5..a10404df38a 100644 --- a/usr.bin/mandoc/tbl_data.c +++ b/usr.bin/mandoc/tbl_data.c @@ -1,6 +1,6 @@ -/* $Id: tbl_data.c,v 1.3 2010/10/15 23:19:40 schwarze Exp $ */ +/* $Id: tbl_data.c,v 1.4 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,119 +14,178 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/queue.h> -#include <sys/types.h> - #include <assert.h> #include <ctype.h> #include <stdlib.h> #include <string.h> +#include <time.h> -#include "out.h" -#include "term.h" -#include "tbl_extern.h" - -/* FIXME: warn about losing data contents if cell is HORIZ. */ - -static int data(struct tbl *, struct tbl_span *, - const char *, int, int, - const char *, int, int); +#include "mandoc.h" +#include "libmandoc.h" +#include "libroff.h" +static int data(struct tbl_node *, struct tbl_span *, + int, const char *, int *); -int -data(struct tbl *tbl, struct tbl_span *dp, - const char *f, int ln, int pos, - const char *p, int start, int end) +static int +data(struct tbl_node *tbl, struct tbl_span *dp, + int ln, const char *p, int *pos) { - struct tbl_data *dat; - - if (NULL == (dat = tbl_data_alloc(dp))) + struct tbl_dat *dat; + struct tbl_cell *cp; + int sv; + + cp = NULL; + if (dp->last && dp->last->layout) + cp = dp->last->layout->next; + else if (NULL == dp->last) + cp = dp->layout->first; + + /* Skip over spanners to data formats. */ + + while (cp && (TBL_CELL_VERT == cp->pos || + TBL_CELL_DVERT == cp->pos)) + cp = cp->next; + + dat = mandoc_calloc(1, sizeof(struct tbl_dat)); + dat->layout = cp; + dat->pos = TBL_DATA_NONE; + + if (NULL == dat->layout) + TBL_MSG(tbl, MANDOCERR_TBLEXTRADAT, ln, *pos); + + if (dp->last) { + dp->last->next = dat; + dp->last = dat; + } else + dp->last = dp->first = dat; + + sv = *pos; + while (p[*pos] && p[*pos] != tbl->opts.tab) + (*pos)++; + + /* + * Check for a continued-data scope opening. This consists of a + * trailing `T{' at the end of the line. Subsequent lines, + * until a standalone `T}', are included in our cell. + */ + + if (*pos - sv == 2 && 'T' == p[sv] && '{' == p[sv + 1]) { + tbl->part = TBL_PART_CDATA; return(0); + } - if (NULL == dat->cell) - if ( ! tbl_warnx(tbl, ERR_SYNTAX, f, ln, pos)) - return(0); - - assert(end >= start); - if (NULL == (dat->string = malloc((size_t)(end - start + 1)))) - return(tbl_err(tbl)); - - (void)memcpy(dat->string, &p[start], (size_t)(end - start)); - dat->string[end - start] = 0; + dat->string = mandoc_malloc(*pos - sv + 1); + memcpy(dat->string, &p[sv], *pos - sv); + dat->string[*pos - sv] = '\0'; - /* XXX: do the strcmps, then malloc(). */ + if (p[*pos]) + (*pos)++; if ( ! strcmp(dat->string, "_")) - dat->flags |= TBL_DATA_HORIZ; + dat->pos = TBL_DATA_HORIZ; else if ( ! strcmp(dat->string, "=")) - dat->flags |= TBL_DATA_DHORIZ; + dat->pos = TBL_DATA_DHORIZ; else if ( ! strcmp(dat->string, "\\_")) - dat->flags |= TBL_DATA_NHORIZ; + dat->pos = TBL_DATA_NHORIZ; else if ( ! strcmp(dat->string, "\\=")) - dat->flags |= TBL_DATA_NDHORIZ; + dat->pos = TBL_DATA_NDHORIZ; else + dat->pos = TBL_DATA_DATA; + + if (NULL == dat->layout) return(1); - free(dat->string); - dat->string = NULL; + if (TBL_CELL_HORIZ == dat->layout->pos || + TBL_CELL_DHORIZ == dat->layout->pos) + if (TBL_DATA_DATA == dat->pos && '\0' != *dat->string) + TBL_MSG(tbl, MANDOCERR_TBLIGNDATA, ln, sv); + return(1); } +int +tbl_cdata(struct tbl_node *tbl, int ln, const char *p) +{ + struct tbl_dat *dat; + size_t sz; + + if (0 == strcmp(p, "T}")) { + tbl->part = TBL_PART_DATA; + return(1); + } + + dat = tbl->last_span->last; + dat->pos = TBL_DATA_DATA; + + if (dat->string) { + sz = strlen(p) + strlen(dat->string) + 2; + dat->string = mandoc_realloc(dat->string, sz); + strlcat(dat->string, " ", sz); + strlcat(dat->string, p, sz); + } else + dat->string = mandoc_strdup(p); + + return(0); +} int -tbl_data(struct tbl *tbl, const char *f, int ln, const char *p) +tbl_data(struct tbl_node *tbl, int ln, const char *p) { struct tbl_span *dp; - int i, j; - - if ('.' == p[0] && ! isdigit((u_char)p[1])) { - /* Comment lines end up here with just a dot. */ - if ('\0' == p[1]) - return(1); - /* - * XXX: departs from tbl convention in that we disallow - * macros in the data body. - */ - if (strncasecmp(p, ".T&", 3)) - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, 0)); - return(tbl_data_close(tbl, f, ln)); - } + struct tbl_row *rp; + int pos; - if (NULL == (dp = tbl_span_alloc(tbl))) + pos = 0; + + if ('\0' == p[pos]) { + TBL_MSG(tbl, MANDOCERR_TBL, ln, pos); return(0); + } + + /* + * Choose a layout row: take the one following the last parsed + * span's. If that doesn't exist, use the last parsed span's. + * If there's no last parsed span, use the first row. This can + * be NULL! + */ + + if (tbl->last_span) { + assert(tbl->last_span->layout); + rp = tbl->last_span->layout->next; + if (NULL == rp) + rp = tbl->last_span->layout; + } else + rp = tbl->first_row; + + dp = mandoc_calloc(1, sizeof(struct tbl_span)); + dp->tbl = &tbl->opts; + dp->layout = rp; + dp->head = tbl->first_head; + + if (tbl->last_span) { + tbl->last_span->next = dp; + tbl->last_span = dp; + } else { + tbl->last_span = tbl->first_span = dp; + dp->flags |= TBL_SPAN_FIRST; + } if ( ! strcmp(p, "_")) { - dp->flags |= TBL_SPAN_HORIZ; + dp->pos = TBL_SPAN_HORIZ; return(1); } else if ( ! strcmp(p, "=")) { - dp->flags |= TBL_SPAN_DHORIZ; + dp->pos = TBL_SPAN_DHORIZ; return(1); } - for (j = i = 0; p[i]; i++) { - if (p[i] != tbl->tab) - continue; - if ( ! data(tbl, dp, f, ln, i, p, j, i)) - return(0); - j = i + 1; - } - - return(data(tbl, dp, f, ln, i, p, j, i)); -} + dp->pos = TBL_SPAN_DATA; + /* This returns 0 when TBL_PART_CDATA is entered. */ -int -tbl_data_close(struct tbl *tbl, const char *f, int ln) -{ - struct tbl_span *span; - - /* LINTED */ - span = TAILQ_LAST(&tbl->span, tbl_spanh); - if (NULL == span) - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, 0)); - if (TAILQ_NEXT(span->row, entries)) - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, 0)); + while ('\0' != p[pos]) + if ( ! data(tbl, dp, ln, p, &pos)) + return(0); - tbl->part = TBL_PART_LAYOUT; return(1); } diff --git a/usr.bin/mandoc/tbl_extern.h b/usr.bin/mandoc/tbl_extern.h deleted file mode 100644 index 1c73041c92b..00000000000 --- a/usr.bin/mandoc/tbl_extern.h +++ /dev/null @@ -1,183 +0,0 @@ -/* $Id: tbl_extern.h,v 1.3 2010/10/15 22:07:12 schwarze Exp $ */ -/* - * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef TBL_EXTERN_H -#define TBL_EXTERN_H - -enum tbl_err { - ERR_SYNTAX, - ERR_OPTION, - ERR_MAX -}; - -enum tbl_tok { - TBL_TOK_WORD, - TBL_TOK_OPENPAREN, - TBL_TOK_CLOSEPAREN, - TBL_TOK_COMMA, - TBL_TOK_SEMICOLON, - TBL_TOK_PERIOD, - TBL_TOK_SPACE, - TBL_TOK_TAB, - TBL_TOK_NIL -}; - -enum tbl_part { - TBL_PART_OPTS, - TBL_PART_LAYOUT, - TBL_PART_CLAYOUT, - TBL_PART_DATA, - TBL_PART_ERROR -}; - -struct tbl; -struct tbl_head; -struct tbl_row; -struct tbl_cell; -struct tbl_span; -struct tbl_data; - -TAILQ_HEAD(tbl_rowh, tbl_row); -TAILQ_HEAD(tbl_cellh, tbl_cell); -TAILQ_HEAD(tbl_headh, tbl_head); -TAILQ_HEAD(tbl_spanh, tbl_span); -TAILQ_HEAD(tbl_datah, tbl_data); - -struct tbl { - enum tbl_part part; - int opts; -#define TBL_OPT_CENTRE (1 << 0) -#define TBL_OPT_EXPAND (1 << 1) -#define TBL_OPT_BOX (1 << 2) -#define TBL_OPT_DBOX (1 << 3) -#define TBL_OPT_ALLBOX (1 << 4) -#define TBL_OPT_NOKEEP (1 << 5) -#define TBL_OPT_NOSPACE (1 << 6) - char tab; - char decimal; - int linesize; - char delims[2]; - struct tbl_spanh span; - struct tbl_headh head; - struct tbl_rowh row; -}; - -enum tbl_headt { - TBL_HEAD_DATA, - TBL_HEAD_VERT, - TBL_HEAD_DVERT, - TBL_HEAD_MAX -}; - -struct tbl_head { - struct tbl *tbl; - enum tbl_headt pos; - int width; - int decimal; - TAILQ_ENTRY(tbl_head) entries; -}; - -struct tbl_row { - struct tbl *tbl; - struct tbl_cellh cell; - TAILQ_ENTRY(tbl_row) entries; -}; - -enum tbl_cellt { - TBL_CELL_CENTRE, /* c, C */ - TBL_CELL_RIGHT, /* r, R */ - TBL_CELL_LEFT, /* l, L */ - TBL_CELL_NUMBER, /* n, N */ - TBL_CELL_SPAN, /* s, S */ - TBL_CELL_LONG, /* a, A */ - TBL_CELL_DOWN, /* ^ */ - TBL_CELL_HORIZ, /* _, - */ - TBL_CELL_DHORIZ, /* = */ - TBL_CELL_VERT, /* | */ - TBL_CELL_DVERT, /* || */ - TBL_CELL_MAX -}; - -struct tbl_cell { - struct tbl_row *row; - struct tbl_head *head; - enum tbl_cellt pos; - int spacing; - int flags; -#define TBL_CELL_TALIGN (1 << 0) /* t, T */ -#define TBL_CELL_BALIGN (1 << 1) /* d, D */ -#define TBL_CELL_BOLD (1 << 2) /* fB, B, b */ -#define TBL_CELL_ITALIC (1 << 3) /* fI, I, i */ -#define TBL_CELL_EQUAL (1 << 4) /* e, E */ -#define TBL_CELL_UP (1 << 5) /* u, U */ -#define TBL_CELL_WIGN (1 << 6) /* z, Z */ - TAILQ_ENTRY(tbl_cell) entries; -}; - -struct tbl_data { - struct tbl_span *span; - struct tbl_cell *cell; - int flags; -#define TBL_DATA_HORIZ (1 << 0) -#define TBL_DATA_DHORIZ (1 << 1) -#define TBL_DATA_NHORIZ (1 << 2) -#define TBL_DATA_NDHORIZ (1 << 3) - char *string; - TAILQ_ENTRY(tbl_data) entries; -}; - -struct tbl_span { - struct tbl_row *row; - struct tbl *tbl; - int flags; -#define TBL_SPAN_HORIZ (1 << 0) -#define TBL_SPAN_DHORIZ (1 << 1) - struct tbl_datah data; - TAILQ_ENTRY(tbl_span) entries; -}; - -__BEGIN_DECLS - -int tbl_option(struct tbl *, - const char *, int, const char *); -int tbl_layout(struct tbl *, - const char *, int, const char *); -int tbl_data(struct tbl *, - const char *, int, const char *); -int tbl_data_close(struct tbl *, const char *, int); - -enum tbl_tok tbl_next(const char *, int *); -const char *tbl_last(void); -int tbl_last_uint(void); -int tbl_errx(struct tbl *, enum tbl_err, - const char *, int, int); -int tbl_warnx(struct tbl *, enum tbl_err, - const char *, int, int); -int tbl_err(struct tbl *); - -struct tbl_row *tbl_row_alloc(struct tbl *); -struct tbl_cell *tbl_cell_alloc(struct tbl_row *, enum tbl_cellt); -struct tbl_span *tbl_span_alloc(struct tbl *); -struct tbl_data *tbl_data_alloc(struct tbl_span *); - -int tbl_write_term(struct termp *, const struct tbl *); -int tbl_calc_term(struct termp *, struct tbl *); -int tbl_write_tree(const struct tbl *); -int tbl_calc_tree(struct tbl *); - -__END_DECLS - -#endif /*TBL_EXTERN_H*/ diff --git a/usr.bin/mandoc/tbl_html.c b/usr.bin/mandoc/tbl_html.c new file mode 100644 index 00000000000..b5ca990b274 --- /dev/null +++ b/usr.bin/mandoc/tbl_html.c @@ -0,0 +1,73 @@ +/* $Id: tbl_html.c,v 1.1 2011/01/04 22:28:17 schwarze Exp $ */ +/* + * Copyright (c) 2011 Kristaps Dzonsons <kristaps@kth.se> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "mandoc.h" +#include "out.h" +#include "html.h" + +void +print_tbl(struct html *h, const struct tbl_span *sp) +{ + const struct tbl_head *hp; + const struct tbl_dat *dp; + struct tag *tt; + + switch (sp->pos) { + case (TBL_SPAN_HORIZ): + /* FALLTHROUGH */ + case (TBL_SPAN_DHORIZ): + return; + default: + break; + } + + /* Inhibit printing of spaces: we do padding ourselves. */ + + h->flags |= HTML_NONOSPACE; + h->flags |= HTML_NOSPACE; + + print_otag(h, TAG_TABLE, 0, NULL); + print_otag(h, TAG_TR, 0, NULL); + + dp = sp->first; + for (hp = sp->head; hp; hp = hp->next) { + switch (hp->pos) { + case (TBL_HEAD_VERT): + /* FALLTHROUGH */ + case (TBL_HEAD_DVERT): + continue; + case (TBL_HEAD_DATA): + break; + } + tt = print_otag(h, TAG_TD, 0, NULL); + if (dp) { + if (dp->string) + print_text(h, dp->string); + dp = dp->next; + } + print_tagq(h, tt); + } + h->flags &= ~HTML_NONOSPACE; +} diff --git a/usr.bin/mandoc/tbl_layout.c b/usr.bin/mandoc/tbl_layout.c index 7fa9610e864..6b27e4873b0 100644 --- a/usr.bin/mandoc/tbl_layout.c +++ b/usr.bin/mandoc/tbl_layout.c @@ -1,6 +1,6 @@ -/* $Id: tbl_layout.c,v 1.3 2010/10/15 22:50:28 schwarze Exp $ */ +/* $Id: tbl_layout.c,v 1.4 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,38 +14,30 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/queue.h> -#include <sys/types.h> - #include <assert.h> #include <ctype.h> #include <stdlib.h> #include <string.h> +#include <time.h> -#include "out.h" -#include "term.h" -#include "tbl_extern.h" +#include "mandoc.h" +#include "libmandoc.h" +#include "libroff.h" struct tbl_phrase { char name; enum tbl_cellt key; }; -#define KEYS_MAX 17 +#define KEYS_MAX 11 static const struct tbl_phrase keys[KEYS_MAX] = { { 'c', TBL_CELL_CENTRE }, - { 'C', TBL_CELL_CENTRE }, { 'r', TBL_CELL_RIGHT }, - { 'R', TBL_CELL_RIGHT }, { 'l', TBL_CELL_LEFT }, - { 'L', TBL_CELL_LEFT }, { 'n', TBL_CELL_NUMBER }, - { 'N', TBL_CELL_NUMBER }, { 's', TBL_CELL_SPAN }, - { 'S', TBL_CELL_SPAN }, { 'a', TBL_CELL_LONG }, - { 'A', TBL_CELL_LONG }, { '^', TBL_CELL_DOWN }, { '-', TBL_CELL_HORIZ }, { '_', TBL_CELL_HORIZ }, @@ -53,191 +45,163 @@ static const struct tbl_phrase keys[KEYS_MAX] = { { '|', TBL_CELL_VERT } }; -static int mods(struct tbl *, struct tbl_cell *, - const char *, int, - const char *, int, int); -static int cell(struct tbl *, struct tbl_row *, - const char *, int, int); -static int row(struct tbl *, const char *, +static int mods(struct tbl_node *, struct tbl_cell *, int, const char *, int *); - +static int cell(struct tbl_node *, struct tbl_row *, + int, const char *, int *); +static void row(struct tbl_node *, int, const char *, int *); +static struct tbl_cell *cell_alloc(struct tbl_node *, + struct tbl_row *, enum tbl_cellt); +static void head_adjust(const struct tbl_cell *, + struct tbl_head *); static int -mods(struct tbl *tbl, struct tbl_cell *cp, const char *p, - int pp, const char *f, int ln, int pos) +mods(struct tbl_node *tbl, struct tbl_cell *cp, + int ln, const char *p, int *pos) { char buf[5]; int i; +mod: /* * XXX: since, at least for now, modifiers are non-conflicting * (are separable by value, regardless of position), we let * modifiers come in any order. The existing tbl doesn't let * this happen. */ - - if (0 == p[pp]) + switch (p[*pos]) { + case ('\0'): + /* FALLTHROUGH */ + case (' '): + /* FALLTHROUGH */ + case ('\t'): + /* FALLTHROUGH */ + case (','): + /* FALLTHROUGH */ + case ('.'): return(1); + default: + break; + } /* Parse numerical spacing from modifier string. */ - if (isdigit((u_char)p[pp])) { + if (isdigit((unsigned char)p[*pos])) { for (i = 0; i < 4; i++) { - if ( ! isdigit((u_char)p[pp + i])) + if ( ! isdigit((unsigned char)p[*pos + i])) break; - buf[i] = p[pp + i]; + buf[i] = p[*pos + i]; } - buf[i] = 0; + buf[i] = '\0'; /* No greater than 4 digits. */ - if (4 == i) - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, pos + pp)); - - /* - * We can't change the spacing in any subsequent layout - * definitions. FIXME: I don't think we can change the - * spacing for a column at all, after it's already been - * initialised. - */ - - if (TBL_PART_CLAYOUT != tbl->part) - cp->spacing = atoi(buf); - else if ( ! tbl_warnx(tbl, ERR_SYNTAX, f, ln, pos + pp)) + if (4 == i) { + TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos); return(0); - - /* Continue parsing modifiers. */ + } + + *pos += i; + cp->spacing = atoi(buf); - return(mods(tbl, cp, p, pp + i, f, ln, pos)); + goto mod; + /* NOTREACHED */ } /* TODO: GNU has many more extensions. */ - switch (p[pp]) { + switch (tolower(p[(*pos)++])) { case ('z'): - /* FALLTHROUGH */ - case ('Z'): cp->flags |= TBL_CELL_WIGN; - return(mods(tbl, cp, p, pp + 1, f, ln, pos)); - case ('w'): - /* FALLTHROUGH */ - case ('W'): /* XXX for now, ignore minimal column width */ - while (isdigit((u_char)p[++pp])); - return(mods(tbl, cp, p, pp, f, ln, pos)); + goto mod; case ('u'): - /* FALLTHROUGH */ - case ('U'): cp->flags |= TBL_CELL_UP; - return(mods(tbl, cp, p, pp + 1, f, ln, pos)); + goto mod; case ('e'): - /* FALLTHROUGH */ - case ('E'): cp->flags |= TBL_CELL_EQUAL; - return(mods(tbl, cp, p, pp + 1, f, ln, pos)); + goto mod; case ('t'): - /* FALLTHROUGH */ - case ('T'): cp->flags |= TBL_CELL_TALIGN; - return(mods(tbl, cp, p, pp + 1, f, ln, pos)); + goto mod; case ('d'): - /* FALLTHROUGH */ - case ('D'): cp->flags |= TBL_CELL_BALIGN; - return(mods(tbl, cp, p, pp + 1, f, ln, pos)); + goto mod; case ('f'): - pp++; - /* FALLTHROUGH */ - case ('B'): - /* FALLTHROUGH */ - case ('I'): - /* FALLTHROUGH */ + break; case ('b'): /* FALLTHROUGH */ case ('i'): + (*pos)--; break; default: - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, pos + pp)); + TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1); + return(0); } - switch (p[pp]) { + switch (tolower(p[(*pos)++])) { case ('b'): - /* FALLTHROUGH */ - case ('B'): cp->flags |= TBL_CELL_BOLD; - return(mods(tbl, cp, p, pp + 1, f, ln, pos)); + goto mod; case ('i'): - /* FALLTHROUGH */ - case ('I'): cp->flags |= TBL_CELL_ITALIC; - return(mods(tbl, cp, p, pp + 1, f, ln, pos)); + goto mod; default: break; } - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, pos + pp)); + TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1); + return(0); } - static int -cell(struct tbl *tbl, struct tbl_row *rp, - const char *f, int ln, int pos) +cell(struct tbl_node *tbl, struct tbl_row *rp, + int ln, const char *p, int *pos) { - struct tbl_cell *cp; - const char *p; - int j, i; + int i; enum tbl_cellt c; /* Parse the column position (`r', `R', `|', ...). */ - c = TBL_CELL_MAX; - for (p = tbl_last(), i = 0; i < KEYS_MAX; i++) { - if (keys[i].name != p[0]) - continue; - c = keys[i].key; - break; + for (i = 0; i < KEYS_MAX; i++) + if (tolower(p[*pos]) == keys[i].name) + break; + + if (KEYS_MAX == i) { + TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos); + return(0); } - if (i == KEYS_MAX) - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, pos)); + (*pos)++; + c = keys[i].key; /* Extra check for the double-vertical. */ - if (TBL_CELL_VERT == c && '|' == p[1]) { - j = 2; + if (TBL_CELL_VERT == c && '|' == p[*pos]) { + (*pos)++; c = TBL_CELL_DVERT; - } else - j = 1; + } - /* Disallow subsequent spacers. */ + /* Disallow adjacent spacers. */ - /* LINTED */ - cp = TAILQ_LAST(&rp->cell, tbl_cellh); - - if (cp && (TBL_CELL_VERT == c || TBL_CELL_DVERT == c) && - (TBL_CELL_VERT == cp->pos || - TBL_CELL_DVERT == cp->pos)) - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, pos)); + if (rp->last && (TBL_CELL_VERT == c || TBL_CELL_DVERT == c) && + (TBL_CELL_VERT == rp->last->pos || + TBL_CELL_DVERT == rp->last->pos)) { + TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1); + return(0); + } /* Allocate cell then parse its modifiers. */ - if (NULL == (cp = tbl_cell_alloc(rp, c))) - return(0); - return(mods(tbl, cp, p, j, f, ln, pos)); + return(mods(tbl, cell_alloc(tbl, rp, c), ln, p, pos)); } -static int -row(struct tbl *tbl, const char *f, int ln, - const char *p, int *pos) +static void +row(struct tbl_node *tbl, int ln, const char *p, int *pos) { struct tbl_row *rp; - int sv; - - rp = tbl_row_alloc(tbl); -again: - sv = *pos; - /* +row: /* * EBNF describing this section: * * row ::= row_list [:space:]* [.]?[\n] @@ -247,41 +211,165 @@ again: * row_elem ::= [\t\ ]*[:alpha:]+ */ - switch (tbl_next(p, pos)) { - case (TBL_TOK_TAB): - /* FALLTHROUGH */ - case (TBL_TOK_SPACE): - goto again; - case (TBL_TOK_WORD): - if ( ! cell(tbl, rp, f, ln, sv)) - return(0); - goto again; - case (TBL_TOK_COMMA): - if (NULL == TAILQ_FIRST(&rp->cell)) - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv)); - return(row(tbl, f, ln, p, pos)); - case (TBL_TOK_PERIOD): - if (NULL == TAILQ_FIRST(&rp->cell)) - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv)); + rp = mandoc_calloc(1, sizeof(struct tbl_row)); + if (tbl->last_row) { + tbl->last_row->next = rp; + tbl->last_row = rp; + } else + tbl->last_row = tbl->first_row = rp; + +cell: + while (isspace((unsigned char)p[*pos])) + (*pos)++; + + /* Safely exit layout context. */ + + if ('.' == p[*pos]) { tbl->part = TBL_PART_DATA; - break; - case (TBL_TOK_NIL): - if (NULL == TAILQ_FIRST(&rp->cell)) - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv)); - break; - default: - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv)); + if (NULL == tbl->first_row) + TBL_MSG(tbl, MANDOCERR_TBLNOLAYOUT, ln, *pos); + (*pos)++; + return; } - return(1); -} + /* End (and possibly restart) a row. */ + + if (',' == p[*pos]) { + (*pos)++; + goto row; + } else if ('\0' == p[*pos]) + return; + + if ( ! cell(tbl, rp, ln, p, pos)) + return; + goto cell; + /* NOTREACHED */ +} int -tbl_layout(struct tbl *tbl, const char *f, int ln, const char *p) +tbl_layout(struct tbl_node *tbl, int ln, const char *p) { int pos; pos = 0; - return(row(tbl, f, ln, p, &pos)); + row(tbl, ln, p, &pos); + + /* Always succeed. */ + return(1); +} + +static struct tbl_cell * +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)); + + if (NULL != (pp = rp->last)) { + rp->last->next = p; + rp->last = p; + } else + rp->last = rp->first = p; + + p->pos = pos; + + /* + * This is a little bit complicated. Here we determine the + * header the corresponds to a cell. We add headers dynamically + * when need be or re-use them, otherwise. As an example, given + * the following: + * + * 1 c || l + * 2 | c | l + * 3 l l + * 3 || c | l |. + * + * We first add the new headers (as there are none) in (1); then + * in (2) we insert the first spanner (as it doesn't match up + * with the header); then we re-use the prior data headers, + * skipping over the spanners; then we re-use everything and add + * a last spanner. Note that VERT headers are made into DVERT + * ones. + */ + + h = pp ? pp->head->next : tbl->first_head; + + if (h) { + /* Re-use data header. */ + if (TBL_HEAD_DATA == h->pos && + (TBL_CELL_VERT != p->pos && + TBL_CELL_DVERT != p->pos)) { + p->head = h; + return(p); + } + + /* Re-use spanner header. */ + if (TBL_HEAD_DATA != h->pos && + (TBL_CELL_VERT == p->pos || + TBL_CELL_DVERT == p->pos)) { + head_adjust(p, h); + p->head = h; + return(p); + } + + /* Right-shift headers with a new spanner. */ + if (TBL_HEAD_DATA == h->pos && + (TBL_CELL_VERT == p->pos || + TBL_CELL_DVERT == p->pos)) { + hp = mandoc_calloc(1, sizeof(struct tbl_head)); + hp->ident = tbl->opts.cols++; + hp->prev = h->prev; + if (h->prev) + h->prev->next = hp; + if (h == tbl->first_head) + tbl->first_head = hp; + h->prev = hp; + hp->next = h; + head_adjust(p, hp); + p->head = hp; + return(p); + } + + if (NULL != (h = h->next)) { + head_adjust(p, h); + p->head = h; + return(p); + } + + /* Fall through to default case... */ + } + + hp = mandoc_calloc(1, sizeof(struct tbl_head)); + hp->ident = tbl->opts.cols++; + + if (tbl->last_head) { + hp->prev = tbl->last_head; + tbl->last_head->next = hp; + tbl->last_head = hp; + } else + tbl->last_head = tbl->first_head = hp; + + head_adjust(p, hp); + p->head = hp; + return(p); } + +static void +head_adjust(const struct tbl_cell *cell, struct tbl_head *head) +{ + if (TBL_CELL_VERT != cell->pos && + TBL_CELL_DVERT != cell->pos) { + head->pos = TBL_HEAD_DATA; + return; + } + + if (TBL_CELL_VERT == cell->pos) + if (TBL_HEAD_DVERT != head->pos) + head->pos = TBL_HEAD_VERT; + + if (TBL_CELL_DVERT == cell->pos) + head->pos = TBL_HEAD_DVERT; +} + diff --git a/usr.bin/mandoc/tbl_option.c b/usr.bin/mandoc/tbl_option.c deleted file mode 100644 index 09cd3afd680..00000000000 --- a/usr.bin/mandoc/tbl_option.c +++ /dev/null @@ -1,197 +0,0 @@ -/* $Id: tbl_option.c,v 1.2 2010/10/15 21:33:47 schwarze Exp $ */ -/* - * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include <sys/queue.h> - -#include <stdlib.h> -#include <string.h> - -#include "out.h" -#include "term.h" -#include "tbl_extern.h" - -struct tbl_phrase { - char *name; - int key; - int ident; -#define KEY_CENTRE 0 -#define KEY_DELIM 1 -#define KEY_EXPAND 2 -#define KEY_BOX 3 -#define KEY_DBOX 4 -#define KEY_ALLBOX 5 -#define KEY_TAB 6 -#define KEY_LINESIZE 7 -#define KEY_NOKEEP 8 -#define KEY_DPOINT 9 -#define KEY_NOSPACE 10 -#define KEY_FRAME 11 -#define KEY_DFRAME 12 -}; - -#define KEY_MAXKEYS 14 - -static const struct tbl_phrase keys[KEY_MAXKEYS] = { - { "center", TBL_OPT_CENTRE, KEY_CENTRE}, - { "centre", TBL_OPT_CENTRE, KEY_CENTRE}, - { "delim", 0, KEY_DELIM}, - { "expand", TBL_OPT_EXPAND, KEY_EXPAND}, - { "box", TBL_OPT_BOX, KEY_BOX}, - { "doublebox", TBL_OPT_DBOX, KEY_DBOX}, - { "allbox", TBL_OPT_ALLBOX, KEY_ALLBOX}, - { "frame", TBL_OPT_BOX, KEY_FRAME}, - { "doubleframe", TBL_OPT_DBOX, KEY_DFRAME}, - { "tab", 0, KEY_TAB}, - { "linesize", 0, KEY_LINESIZE}, - { "nokeep", TBL_OPT_NOKEEP, KEY_NOKEEP}, - { "decimalpoint", 0, KEY_DPOINT}, - { "nospaces", TBL_OPT_NOSPACE, KEY_NOSPACE}, -}; - -static int arg(struct tbl *, const char *, - int, const char *, int *, int); -static int opt(struct tbl *, const char *, - int, const char *, int *); - -static int -arg(struct tbl *tbl, const char *f, int ln, - const char *p, int *pos, int key) -{ - const char *buf; - int sv; - -again: - sv = *pos; - - switch (tbl_next(p, pos)) { - case (TBL_TOK_OPENPAREN): - break; - case (TBL_TOK_SPACE): - /* FALLTHROUGH */ - case (TBL_TOK_TAB): - goto again; - default: - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv)); - } - - sv = *pos; - - switch (tbl_next(p, pos)) { - case (TBL_TOK_WORD): - break; - default: - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv)); - } - - buf = tbl_last(); - - switch (key) { - case (KEY_DELIM): - if (2 != strlen(buf)) - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv)); - tbl->delims[0] = buf[0]; - tbl->delims[1] = buf[1]; - break; - case (KEY_TAB): - if (1 != strlen(buf)) - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv)); - tbl->tab = buf[0]; - break; - case (KEY_LINESIZE): - if (-1 == (tbl->linesize = tbl_last_uint())) - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv)); - break; - case (KEY_DPOINT): - if (1 != strlen(buf)) - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv)); - tbl->decimal = buf[0]; - break; - default: - abort(); - } - - sv = *pos; - - switch (tbl_next(p, pos)) { - case (TBL_TOK_CLOSEPAREN): - break; - default: - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv)); - } - - return(1); -} - - -static int -opt(struct tbl *tbl, const char *f, int ln, const char *p, int *pos) -{ - int i, sv; - -again: - sv = *pos; - - /* - * EBNF describing this section: - * - * options ::= option_list [:space:]* [;][\n] - * option_list ::= option option_tail - * option_tail ::= [:space:]+ option_list | - * ::= epsilon - * option ::= [:alpha:]+ args - * args ::= [:space:]* [(] [:alpha:]+ [)] - */ - - switch (tbl_next(p, pos)) { - case (TBL_TOK_WORD): - break; - case (TBL_TOK_SPACE): - /* FALLTHROUGH */ - case (TBL_TOK_TAB): - goto again; - case (TBL_TOK_SEMICOLON): - tbl->part = TBL_PART_LAYOUT; - return(1); - default: - return(tbl_errx(tbl, ERR_SYNTAX, f, ln, sv)); - } - - for (i = 0; i < KEY_MAXKEYS; i++) { - if (strcasecmp(tbl_last(), keys[i].name)) - continue; - if (keys[i].key) - tbl->opts |= keys[i].key; - else if ( ! arg(tbl, f, ln, p, pos, keys[i].ident)) - return(0); - - break; - } - - if (KEY_MAXKEYS == i) - return(tbl_errx(tbl, ERR_OPTION, f, ln, sv)); - - return(opt(tbl, f, ln, p, pos)); -} - - -int -tbl_option(struct tbl *tbl, const char *f, int ln, const char *p) -{ - int pos; - - pos = 0; - return(opt(tbl, f, ln, p, &pos)); -} diff --git a/usr.bin/mandoc/tbl_opts.c b/usr.bin/mandoc/tbl_opts.c new file mode 100644 index 00000000000..9a8f0aba620 --- /dev/null +++ b/usr.bin/mandoc/tbl_opts.c @@ -0,0 +1,260 @@ +/* $Id: tbl_opts.c,v 1.1 2011/01/04 22:28:17 schwarze Exp $ */ +/* + * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "mandoc.h" +#include "libroff.h" + +enum tbl_ident { + KEY_CENTRE = 0, + KEY_DELIM, + KEY_EXPAND, + KEY_BOX, + KEY_DBOX, + KEY_ALLBOX, + KEY_TAB, + KEY_LINESIZE, + KEY_NOKEEP, + KEY_DPOINT, + KEY_NOSPACE, + KEY_FRAME, + KEY_DFRAME, + KEY_MAX +}; + +struct tbl_phrase { + const char *name; + int key; + enum tbl_ident ident; +}; + +/* Handle Commonwealth/American spellings. */ +#define KEY_MAXKEYS 14 + +/* Maximum length of key name string. */ +#define KEY_MAXNAME 13 + +/* Maximum length of key number size. */ +#define KEY_MAXNUMSZ 10 + +static const struct tbl_phrase keys[KEY_MAXKEYS] = { + { "center", TBL_OPT_CENTRE, KEY_CENTRE}, + { "centre", TBL_OPT_CENTRE, KEY_CENTRE}, + { "delim", 0, KEY_DELIM}, + { "expand", TBL_OPT_EXPAND, KEY_EXPAND}, + { "box", TBL_OPT_BOX, KEY_BOX}, + { "doublebox", TBL_OPT_DBOX, KEY_DBOX}, + { "allbox", TBL_OPT_ALLBOX, KEY_ALLBOX}, + { "frame", TBL_OPT_BOX, KEY_FRAME}, + { "doubleframe", TBL_OPT_DBOX, KEY_DFRAME}, + { "tab", 0, KEY_TAB}, + { "linesize", 0, KEY_LINESIZE}, + { "nokeep", TBL_OPT_NOKEEP, KEY_NOKEEP}, + { "decimalpoint", 0, KEY_DPOINT}, + { "nospaces", TBL_OPT_NOSPACE, KEY_NOSPACE}, +}; + +static int arg(struct tbl_node *, int, + const char *, int *, int); +static void opt(struct tbl_node *, int, + const char *, int *); + +static int +arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key) +{ + int i; + char buf[KEY_MAXNUMSZ]; + + while (isspace((unsigned char)p[*pos])) + (*pos)++; + + /* Arguments always begin with a parenthesis. */ + + if ('(' != p[*pos]) { + TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos); + return(0); + } + + (*pos)++; + + /* + * The arguments can be ANY value, so we can't just stop at the + * next close parenthesis (the argument can be a closed + * parenthesis itself). + */ + + switch (key) { + case (KEY_DELIM): + if ('\0' == (tbl->opts.delims[0] = p[(*pos)++])) { + TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1); + return(0); + } + + if ('\0' == (tbl->opts.delims[1] = p[(*pos)++])) { + TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1); + return(0); + } + break; + case (KEY_TAB): + if ('\0' != (tbl->opts.tab = p[(*pos)++])) + break; + + TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1); + return(0); + case (KEY_LINESIZE): + for (i = 0; i < KEY_MAXNUMSZ && p[*pos]; i++, (*pos)++) { + buf[i] = p[*pos]; + if ( ! isdigit((unsigned char)buf[i])) + break; + } + + if (i < KEY_MAXNUMSZ) { + buf[i] = '\0'; + tbl->opts.linesize = atoi(buf); + break; + } + + (*tbl->msg)(MANDOCERR_TBL, tbl->data, ln, *pos, NULL); + return(0); + case (KEY_DPOINT): + if ('\0' != (tbl->opts.decimal = p[(*pos)++])) + break; + + TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1); + return(0); + default: + abort(); + /* NOTREACHED */ + } + + /* End with a close parenthesis. */ + + if (')' == p[(*pos)++]) + return(1); + + TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1); + return(0); +} + +static void +opt(struct tbl_node *tbl, int ln, const char *p, int *pos) +{ + int i, sv; + char buf[KEY_MAXNAME]; + + /* + * Parse individual options from the stream as surrounded by + * this goto. Each pass through the routine parses out a single + * option and registers it. Option arguments are processed in + * the arg() function. + */ + +again: /* + * EBNF describing this section: + * + * options ::= option_list [:space:]* [;][\n] + * option_list ::= option option_tail + * option_tail ::= [:space:]+ option_list | + * ::= epsilon + * option ::= [:alpha:]+ args + * args ::= [:space:]* [(] [:alpha:]+ [)] + */ + + while (isspace((unsigned char)p[*pos])) + (*pos)++; + + /* Safe exit point. */ + + if (';' == p[*pos]) + return; + + /* Copy up to first non-alpha character. */ + + for (sv = *pos, i = 0; i < KEY_MAXNAME; i++, (*pos)++) { + buf[i] = tolower(p[*pos]); + if ( ! isalpha((unsigned char)buf[i])) + break; + } + + /* Exit if buffer is empty (or overrun). */ + + if (KEY_MAXNAME == i || 0 == i) { + TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos); + return; + } + + buf[i] = '\0'; + + while (isspace((unsigned char)p[*pos])) + (*pos)++; + + /* + * Look through all of the available keys to find one that + * matches the input. FIXME: hashtable this. + */ + + for (i = 0; i < KEY_MAXKEYS; i++) { + if (strcmp(buf, keys[i].name)) + continue; + + /* + * Note: this is more difficult to recover from, as we + * can be anywhere in the option sequence and it's + * harder to jump to the next. Meanwhile, just bail out + * of the sequence altogether. + */ + + if (keys[i].key) + tbl->opts.opts |= keys[i].key; + else if ( ! arg(tbl, ln, p, pos, keys[i].ident)) + return; + + break; + } + + /* + * Allow us to recover from bad options by continuing to another + * parse sequence. + */ + + if (KEY_MAXKEYS == i) + TBL_MSG(tbl, MANDOCERR_TBLOPT, ln, sv); + + goto again; + /* NOTREACHED */ +} + +int +tbl_option(struct tbl_node *tbl, int ln, const char *p) +{ + int pos; + + /* + * Table options are always on just one line, so automatically + * switch into the next input mode here. + */ + tbl->part = TBL_PART_LAYOUT; + + pos = 0; + opt(tbl, ln, p, &pos); + + /* Always succeed. */ + return(1); +} diff --git a/usr.bin/mandoc/tbl_term.c b/usr.bin/mandoc/tbl_term.c index af5d54557c3..7b7a056ea3c 100644 --- a/usr.bin/mandoc/tbl_term.c +++ b/usr.bin/mandoc/tbl_term.c @@ -1,7 +1,6 @@ -/* $Id: tbl_term.c,v 1.4 2010/10/15 22:16:51 schwarze Exp $ */ +/* $Id: tbl_term.c,v 1.5 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> - * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@kth.se> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,154 +14,152 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/queue.h> - #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include "mandoc.h" #include "out.h" #include "term.h" -#include "tbl_extern.h" /* FIXME: `n' modifier doesn't always do the right thing. */ /* FIXME: `n' modifier doesn't use the cell-spacing buffer. */ -static void calc_data(struct termp *, struct tbl_data *); -static void calc_data_literal(struct termp *, struct tbl_data *); -static void calc_data_number(struct termp *, struct tbl_data *); -static void calc_data_spanner(struct termp *, struct tbl_data *); -static inline void write_char(struct termp *, char, int); -static void write_data(struct termp *, - const struct tbl_data *, int); -static void write_data_literal(struct termp *, - const struct tbl_data *, int); -static void write_data_number(struct termp *, - const struct tbl_data *, int); -static void write_data_spanner(struct termp *, - const struct tbl_data *, int); -static void write_hframe(struct termp *, const struct tbl *); -static void write_hrule(struct termp *, const struct tbl_span *); -static void write_spanner(struct termp *, const struct tbl_head *); -static void write_vframe(struct termp *, const struct tbl *); - - -int -tbl_write_term(struct termp *p, const struct tbl *tbl) +static inline void tbl_char(struct termp *, char, int); +static void tbl_hframe(struct termp *, + const struct tbl_span *); +static void tbl_data_number(struct termp *, + const struct tbl *, + const struct tbl_dat *, + const struct termp_tbl *); +static void tbl_data_literal(struct termp *, + const struct tbl_dat *, + const struct termp_tbl *); +static void tbl_data(struct termp *, const struct tbl *, + const struct tbl_dat *, + const struct termp_tbl *); +static void tbl_spanner(struct termp *, + const struct tbl_head *); +static void tbl_hrule(struct termp *, + const struct tbl_span *); +static void tbl_vframe(struct termp *, + const struct tbl *); +static void tbl_calc(struct termp *, + const struct tbl_span *); +static void tbl_calc_data(struct termp *, + const struct tbl *, + const struct tbl_dat *, + struct termp_tbl *); +static void tbl_calc_data_literal(struct termp *, + const struct tbl_dat *, + struct termp_tbl *); +static void tbl_calc_data_number(struct termp *, + const struct tbl *, + const struct tbl_dat *, + struct termp_tbl *); + +void +term_tbl(struct termp *tp, const struct tbl_span *sp) { - const struct tbl_span *span; - const struct tbl_data *data; - const struct tbl_head *head; + const struct tbl_head *hp; + const struct tbl_dat *dp; + + /* Inhibit printing of spaces: we do padding ourselves. */ + + tp->flags |= TERMP_NONOSPACE; + tp->flags |= TERMP_NOSPACE; /* - * Note that the absolute widths and decimal places for headers - * were set when tbl_calc_term was called. + * The first time we're invoked for a given table block, create + * the termp_tbl structure. This contains the column + * configuration for the entire table, e.g., table-wide column + * width, decimal point, etc. */ - term_newln(p); - p->flags |= TERMP_NOSPACE | TERMP_NONOSPACE; + if (TBL_SPAN_FIRST & sp->flags) { + assert(NULL == tp->tbl); + tp->tbl = calloc + (sp->tbl->cols, sizeof(struct termp_tbl)); + if (NULL == tp->tbl) { + perror(NULL); + exit(EXIT_FAILURE); + } + tbl_calc(tp, sp); - /* First, write out our head horizontal frame. */ + /* Flush out any preceding data. */ + term_flushln(tp); + } - write_hframe(p, tbl); + /* Horizontal frame at the start of boxed tables. */ - /* - * Iterate through each span, and inside, through the global - * headers. If the global header's a spanner, print it - * directly; if it's data, use the corresponding data in the - * span as the object to print. - */ + if (TBL_SPAN_FIRST & sp->flags) + tbl_hframe(tp, sp); - TAILQ_FOREACH(span, &tbl->span, entries) { - write_vframe(p, tbl); + /* Vertical frame at the start of each row. */ - /* Accomodate for the horizontal rule. */ - if (TBL_DATA_DHORIZ & span->flags || - TBL_DATA_HORIZ & span->flags) { - write_hrule(p, span); - write_vframe(p, tbl); - term_flushln(p); - continue; - } + tbl_vframe(tp, sp->tbl); + + /* + * Now print the actual data itself depending on the span type. + * Spanner spans get a horizontal rule; data spanners have their + * data printed by matching data to header. + */ - data = TAILQ_FIRST(&span->data); - TAILQ_FOREACH(head, &tbl->head, entries) { - switch (head->pos) { + switch (sp->pos) { + case (TBL_SPAN_HORIZ): + /* FALLTHROUGH */ + case (TBL_SPAN_DHORIZ): + tbl_hrule(tp, sp); + break; + case (TBL_SPAN_DATA): + /* Iterate over template headers. */ + dp = sp->first; + for (hp = sp->head; hp; hp = hp->next) { + switch (hp->pos) { case (TBL_HEAD_VERT): /* FALLTHROUGH */ case (TBL_HEAD_DVERT): - write_spanner(p, head); - break; + tbl_spanner(tp, hp); + continue; case (TBL_HEAD_DATA): - write_data(p, data, head->width); - if (data) - data = TAILQ_NEXT(data, entries); break; - default: - abort(); - /* NOTREACHED */ } + tbl_data(tp, sp->tbl, dp, + &tp->tbl[hp->ident]); + + /* Go to the next data cell. */ + if (dp) + dp = dp->next; } - write_vframe(p, tbl); - term_flushln(p); + break; } - /* Last, write out our tail horizontal frame. */ + tbl_vframe(tp, sp->tbl); + term_flushln(tp); - write_hframe(p, tbl); - - p->flags &= ~TERMP_NONOSPACE; - - return(1); -} - - -int -tbl_calc_term(struct termp *p, struct tbl *tbl) -{ - struct tbl_span *span; - struct tbl_data *data; - struct tbl_head *head; - - /* Calculate width as the max of column cells' widths. */ + /* + * If we're the last row, clean up after ourselves: clear the + * existing table configuration and set it to NULL. + */ - TAILQ_FOREACH(span, &tbl->span, entries) { - if (TBL_DATA_HORIZ & span->flags) - continue; - if (TBL_DATA_DHORIZ & span->flags) - continue; - if (TBL_DATA_NHORIZ & span->flags) - continue; - if (TBL_DATA_NDHORIZ & span->flags) - continue; - TAILQ_FOREACH(data, &span->data, entries) - calc_data(p, data); + if (TBL_SPAN_LAST & sp->flags) { + tbl_hframe(tp, sp); + assert(tp->tbl); + free(tp->tbl); + tp->tbl = NULL; } - /* Calculate width as the simple spanner value. */ - - TAILQ_FOREACH(head, &tbl->head, entries) - switch (head->pos) { - case (TBL_HEAD_VERT): - head->width = term_len(p, 1); - break; - case (TBL_HEAD_DVERT): - head->width = term_len(p, 2); - break; - default: - break; - } + tp->flags &= ~TERMP_NONOSPACE; - return(1); } - static void -write_hrule(struct termp *p, const struct tbl_span *span) +tbl_hrule(struct termp *tp, const struct tbl_span *sp) { - const struct tbl_head *head; - char c; + const struct tbl_head *hp; + char c; + int width; /* * An hrule extends across the entire table and is demarked by a @@ -171,21 +168,22 @@ write_hrule(struct termp *p, const struct tbl_span *span) */ c = '-'; - if (TBL_SPAN_DHORIZ & span->flags) + if (TBL_SPAN_DHORIZ == sp->pos) c = '='; /* FIXME: don't use `+' between data and a spanner! */ - TAILQ_FOREACH(head, &span->tbl->head, entries) { - switch (head->pos) { + for (hp = sp->head; hp; hp = hp->next) { + width = tp->tbl[hp->ident].width; + switch (hp->pos) { case (TBL_HEAD_DATA): - write_char(p, c, head->width); + tbl_char(tp, c, width); break; case (TBL_HEAD_DVERT): - write_char(p, '+', head->width); + tbl_char(tp, '+', width); /* FALLTHROUGH */ case (TBL_HEAD_VERT): - write_char(p, '+', head->width); + tbl_char(tp, '+', width); break; default: abort(); @@ -194,13 +192,14 @@ write_hrule(struct termp *p, const struct tbl_span *span) } } - static void -write_hframe(struct termp *p, const struct tbl *tbl) +tbl_hframe(struct termp *tp, const struct tbl_span *sp) { - const struct tbl_head *head; + const struct tbl_head *hp; + int width; - if ( ! (TBL_OPT_BOX & tbl->opts || TBL_OPT_DBOX & tbl->opts)) + if ( ! (TBL_OPT_BOX & sp->tbl->opts || + TBL_OPT_DBOX & sp->tbl->opts)) return; /* @@ -211,135 +210,70 @@ write_hframe(struct termp *p, const struct tbl *tbl) * by `+' whenever a span is encountered. */ - if (TBL_OPT_DBOX & tbl->opts) { - term_word(p, "+"); - TAILQ_FOREACH(head, &tbl->head, entries) - write_char(p, '-', head->width); - term_word(p, "+"); - term_flushln(p); + if (TBL_OPT_DBOX & sp->tbl->opts) { + term_word(tp, "+"); + for (hp = sp->head; hp; hp = hp->next) { + width = tp->tbl[hp->ident].width; + tbl_char(tp, '-', width); + } + term_word(tp, "+"); + term_flushln(tp); } - term_word(p, "+"); - TAILQ_FOREACH(head, &tbl->head, entries) { - switch (head->pos) { + term_word(tp, "+"); + for (hp = sp->head; hp; hp = hp->next) { + width = tp->tbl[hp->ident].width; + switch (hp->pos) { case (TBL_HEAD_DATA): - write_char(p, '-', head->width); + tbl_char(tp, '-', width); break; default: - write_char(p, '+', head->width); + tbl_char(tp, '+', width); break; } } - term_word(p, "+"); - term_flushln(p); + term_word(tp, "+"); + term_flushln(tp); } - static void -write_vframe(struct termp *p, const struct tbl *tbl) +tbl_data(struct termp *tp, const struct tbl *tbl, + const struct tbl_dat *dp, + const struct termp_tbl *tbp) { - /* Always just a single vertical line. */ + enum tbl_cellt pos; - if ( ! (TBL_OPT_BOX & tbl->opts || TBL_OPT_DBOX & tbl->opts)) + if (NULL == dp) { + tbl_char(tp, ASCII_NBRSP, tbp->width); return; - term_word(p, "|"); -} - - -static void -calc_data_spanner(struct termp *p, struct tbl_data *data) -{ - - /* N.B., these are horiz spanners (not vert) so always 1. */ - data->cell->head->width = term_len(p, 1); -} - - -static void -calc_data_number(struct termp *p, struct tbl_data *data) -{ - int sz, d; - char *dp, pnt; - - /* - * First calculate number width and decimal place (last + 1 for - * no-decimal numbers). If the stored decimal is subsequent - * ours, make our size longer by that difference - * (right-"shifting"); similarly, if ours is subsequent the - * stored, then extend the stored size by the difference. - * Finally, re-assign the stored values. - */ - - /* TODO: use spacing modifier. */ - - assert(data->string); - sz = (int)term_strlen(p, data->string); - pnt = data->span->tbl->decimal; - - dp = strchr(data->string, pnt); - d = dp ? sz - (int)term_strlen(p, dp) : sz; - d += term_len(p, 1); - - sz += term_len(p, 2); - - if (data->cell->head->decimal > d) { - sz += data->cell->head->decimal - d; - d = data->cell->head->decimal; - } else - data->cell->head->width += - d - data->cell->head->decimal; - - if (sz > data->cell->head->width) - data->cell->head->width = sz; - if (d > data->cell->head->decimal) - data->cell->head->decimal = d; -} - - -static void -calc_data_literal(struct termp *p, struct tbl_data *data) -{ - int sz, bufsz; - - /* - * Calculate our width and use the spacing, with a minimum - * spacing dictated by position (centre, e.g,. gets a space on - * either side, while right/left get a single adjacent space). - */ - - assert(data->string); - sz = (int)term_strlen(p, data->string); + } - switch (data->cell->pos) { - case (TBL_CELL_LONG): + switch (dp->pos) { + case (TBL_DATA_NONE): + tbl_char(tp, ASCII_NBRSP, tbp->width); + return; + case (TBL_DATA_HORIZ): /* FALLTHROUGH */ - case (TBL_CELL_CENTRE): - bufsz = 2; - break; + case (TBL_DATA_NHORIZ): + tbl_char(tp, '-', tbp->width); + return; + case (TBL_DATA_NDHORIZ): + /* FALLTHROUGH */ + case (TBL_DATA_DHORIZ): + tbl_char(tp, '=', tbp->width); + return; default: - bufsz = 1; break; } + + pos = dp->layout ? dp->layout->pos : TBL_CELL_LEFT; - if (data->cell->spacing) - bufsz = bufsz > data->cell->spacing ? - bufsz : data->cell->spacing; - - sz += term_len(p, bufsz); - if (data->cell->head->width < sz) - data->cell->head->width = sz; -} - - -static void -calc_data(struct termp *p, struct tbl_data *data) -{ - - switch (data->cell->pos) { + switch (pos) { case (TBL_CELL_HORIZ): - /* FALLTHROUGH */ + tbl_char(tp, '-', tbp->width); + break; case (TBL_CELL_DHORIZ): - calc_data_spanner(p, data); + tbl_char(tp, '=', tbp->width); break; case (TBL_CELL_LONG): /* FALLTHROUGH */ @@ -348,126 +282,184 @@ calc_data(struct termp *p, struct tbl_data *data) case (TBL_CELL_LEFT): /* FALLTHROUGH */ case (TBL_CELL_RIGHT): - calc_data_literal(p, data); + tbl_data_literal(tp, dp, tbp); break; case (TBL_CELL_NUMBER): - calc_data_number(p, data); - break; - case (TBL_CELL_SPAN): - data->cell->head->width = 0; + tbl_data_number(tp, tbl, dp, tbp); break; default: abort(); /* NOTREACHED */ } } - - static void -write_data_spanner(struct termp *p, const struct tbl_data *data, int width) +tbl_spanner(struct termp *tp, const struct tbl_head *hp) { - /* - * Write spanners dictated by both our cell designation (in the - * layout) or as data. - */ - if (TBL_DATA_HORIZ & data->flags) - write_char(p, '-', width); - else if (TBL_DATA_DHORIZ & data->flags) - write_char(p, '=', width); - else if (TBL_CELL_HORIZ == data->cell->pos) - write_char(p, '-', width); - else if (TBL_CELL_DHORIZ == data->cell->pos) - write_char(p, '=', width); + switch (hp->pos) { + case (TBL_HEAD_VERT): + term_word(tp, "|"); + break; + case (TBL_HEAD_DVERT): + term_word(tp, "||"); + break; + default: + break; + } } - static void -write_data_number(struct termp *p, const struct tbl_data *data, int width) +tbl_vframe(struct termp *tp, const struct tbl *tbl) { - char *dp, pnt; - int d, padl, sz; - - /* - * See calc_data_number(). Left-pad by taking the offset of our - * and the maximum decimal; right-pad by the remaining amount. - */ + /* Always just a single vertical line. */ - sz = (int)term_strlen(p, data->string); - pnt = data->span->tbl->decimal; + if (TBL_OPT_BOX & tbl->opts || TBL_OPT_DBOX & tbl->opts) + term_word(tp, "|"); +} - if (NULL == (dp = strchr(data->string, pnt))) { - d = sz + 1; - } else { - d = (int)(dp - data->string) + 1; - } +static inline void +tbl_char(struct termp *tp, char c, int len) +{ + int i, sz; + char cp[2]; - assert(d <= data->cell->head->decimal); - assert(sz - d <= data->cell->head->width - - data->cell->head->decimal); + cp[0] = c; + cp[1] = '\0'; - padl = data->cell->head->decimal - d + 1; - assert(width - sz - padl); + sz = term_strlen(tp, cp); - write_char(p, ' ', padl); - term_word(p, data->string); - write_char(p, ' ', width - sz - padl); + for (i = 0; i < len; i += sz) + term_word(tp, cp); } - static void -write_data_literal(struct termp *p, const struct tbl_data *data, int width) +tbl_data_literal(struct termp *tp, + const struct tbl_dat *dp, + const struct termp_tbl *tblp) { - int padl, padr; + int padl, padr, ssz; + enum tbl_cellt pos; padl = padr = 0; - switch (data->cell->pos) { + pos = dp->layout ? dp->layout->pos : TBL_CELL_LEFT; + ssz = term_len(tp, 1); + + switch (pos) { case (TBL_CELL_LONG): - padl = 1; - padr = width - (int)term_strlen(p, data->string) - 1; + padl = ssz; + padr = tblp->width - term_strlen(tp, dp->string) - ssz; break; case (TBL_CELL_CENTRE): - padl = width - (int)term_strlen(p, data->string); + padl = tblp->width - term_strlen(tp, dp->string); if (padl % 2) padr++; padl /= 2; padr += padl; break; case (TBL_CELL_RIGHT): - padl = width - (int)term_strlen(p, data->string); + padl = tblp->width - term_strlen(tp, dp->string); break; default: - padr = width - (int)term_strlen(p, data->string); + padr = tblp->width - term_strlen(tp, dp->string); break; } - write_char(p, ' ', padl); - term_word(p, data->string); - write_char(p, ' ', padr); + tbl_char(tp, ASCII_NBRSP, padl); + term_word(tp, dp->string); + tbl_char(tp, ASCII_NBRSP, padr); } +static void +tbl_data_number(struct termp *tp, const struct tbl *tbl, + const struct tbl_dat *dp, + const struct termp_tbl *tblp) +{ + char *decp, buf[2]; + int d, padl, sz, psz, ssz, i; + + /* + * See calc_data_number(). Left-pad by taking the offset of our + * and the maximum decimal; right-pad by the remaining amount. + */ + + sz = term_strlen(tp, dp->string); + psz = term_strlen(tp, "."); + + if (NULL != (decp = strchr(dp->string, tbl->decimal))) { + buf[1] = '\0'; + for (ssz = i = 0; decp != &dp->string[i]; i++) { + buf[0] = dp->string[i]; + ssz += term_strlen(tp, buf); + } + d = ssz + psz; + } else + d = sz + psz; + + assert(d <= tblp->decimal); + assert(sz - d <= tblp->width - tblp->decimal); + + padl = tblp->decimal - d + term_len(tp, 1); + assert(tblp->width - sz - padl); + + tbl_char(tp, ASCII_NBRSP, padl); + term_word(tp, dp->string); + tbl_char(tp, ASCII_NBRSP, tblp->width - sz - padl); +} static void -write_data(struct termp *p, const struct tbl_data *data, int width) +tbl_calc(struct termp *tp, const struct tbl_span *sp) { + const struct tbl_dat *dp; + const struct tbl_head *hp; + struct termp_tbl *p; - if (NULL == data) { - write_char(p, ' ', width); - return; - } + /* Calculate width as the max of column cells' widths. */ - if (TBL_DATA_HORIZ & data->flags || - TBL_DATA_DHORIZ & data->flags) { - write_data_spanner(p, data, width); - return; + hp = sp->head; + + for ( ; sp; sp = sp->next) { + if (TBL_SPAN_DATA != sp->pos) + continue; + + for (dp = sp->first; dp; dp = dp->next) { + if (NULL == dp->layout) + continue; + p = &tp->tbl[dp->layout->head->ident]; + tbl_calc_data(tp, sp->tbl, dp, p); + } } - switch (data->cell->pos) { + /* Calculate width as the simple spanner value. */ + + for ( ; hp; hp = hp->next) + switch (hp->pos) { + case (TBL_HEAD_VERT): + tp->tbl[hp->ident].width = term_len(tp, 1); + break; + case (TBL_HEAD_DVERT): + tp->tbl[hp->ident].width = term_len(tp, 2); + break; + default: + break; + } +} + +static void +tbl_calc_data(struct termp *tp, const struct tbl *tbl, + const struct tbl_dat *dp, struct termp_tbl *tblp) +{ + int sz; + + /* Branch down into data sub-types. */ + + switch (dp->layout->pos) { case (TBL_CELL_HORIZ): /* FALLTHROUGH */ case (TBL_CELL_DHORIZ): - write_data_spanner(p, data, width); + sz = term_len(tp, 1); + if (tblp->width < sz) + tblp->width = sz; break; case (TBL_CELL_LONG): /* FALLTHROUGH */ @@ -476,12 +468,10 @@ write_data(struct termp *p, const struct tbl_data *data, int width) case (TBL_CELL_LEFT): /* FALLTHROUGH */ case (TBL_CELL_RIGHT): - write_data_literal(p, data, width); + tbl_calc_data_literal(tp, dp, tblp); break; case (TBL_CELL_NUMBER): - write_data_number(p, data, width); - break; - case (TBL_CELL_SPAN): + tbl_calc_data_number(tp, tbl, dp, tblp); break; default: abort(); @@ -489,36 +479,87 @@ write_data(struct termp *p, const struct tbl_data *data, int width) } } +static void +tbl_calc_data_number(struct termp *tp, const struct tbl *tbl, + const struct tbl_dat *dp, struct termp_tbl *tblp) +{ + int sz, d, psz, i, ssz; + char *cp, buf[2]; + + /* + * First calculate number width and decimal place (last + 1 for + * no-decimal numbers). If the stored decimal is subsequent + * ours, make our size longer by that difference + * (right-"shifting"); similarly, if ours is subsequent the + * stored, then extend the stored size by the difference. + * Finally, re-assign the stored values. + */ + + /* TODO: use spacing modifier. */ + + assert(dp->string); + sz = term_strlen(tp, dp->string); + psz = term_strlen(tp, "."); + + if (NULL != (cp = strchr(dp->string, tbl->decimal))) { + buf[1] = '\0'; + for (ssz = i = 0; cp != &dp->string[i]; i++) { + buf[0] = dp->string[i]; + ssz += term_strlen(tp, buf); + } + d = ssz + psz; + } else + d = sz + psz; + + sz += term_len(tp, 2); + + if (tblp->decimal > d) { + sz += tblp->decimal - d; + d = tblp->decimal; + } else + tblp->width += d - tblp->decimal; + + if (sz > tblp->width) + tblp->width = sz; + if (d > tblp->decimal) + tblp->decimal = d; +} static void -write_spanner(struct termp *p, const struct tbl_head *head) +tbl_calc_data_literal(struct termp *tp, + const struct tbl_dat *dp, + struct termp_tbl *tblp) { - char *w; + int sz, bufsz, spsz; - w = NULL; - switch (head->pos) { - case (TBL_HEAD_VERT): - w = "|"; - break; - case (TBL_HEAD_DVERT): - w = "||"; + /* + * Calculate our width and use the spacing, with a minimum + * spacing dictated by position (centre, e.g,. gets a space on + * either side, while right/left get a single adjacent space). + */ + + assert(dp->string); + sz = term_strlen(tp, dp->string); + + switch (dp->layout->pos) { + case (TBL_CELL_LONG): + /* FALLTHROUGH */ + case (TBL_CELL_CENTRE): + bufsz = term_len(tp, 2); break; default: + bufsz = term_len(tp, 1); break; } - assert(p); - term_word(p, w); -} - + spsz = 0; + if (dp->layout->spacing) + spsz = term_len(tp, dp->layout->spacing); -static inline void -write_char(struct termp *p, char c, int len) -{ - int i; - static char w[2]; + if (spsz) + bufsz = bufsz > spsz ? bufsz : spsz; - w[0] = c; - for (i = 0; i < len; i++) - term_word(p, w); + sz += bufsz; + if (tblp->width < sz) + tblp->width = sz; } diff --git a/usr.bin/mandoc/tbl_tree.c b/usr.bin/mandoc/tbl_tree.c deleted file mode 100644 index e073c66aa2f..00000000000 --- a/usr.bin/mandoc/tbl_tree.c +++ /dev/null @@ -1,88 +0,0 @@ -/* $Id: tbl_tree.c,v 1.2 2010/10/15 21:33:47 schwarze Exp $ */ -/* - * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include <sys/queue.h> - -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "out.h" -#include "term.h" -#include "tbl_extern.h" - -static const char * const htypes[TBL_HEAD_MAX] = { - "data", - "vert", - "dvert", -}; - -static const char * const ctypes[TBL_CELL_MAX] = { - "centre", - "right", - "left", - "number", - "span", - "long", - "down", - "horiz", - "dhoriz", - "vert", - "dvert", -}; - - -/* ARGSUSED */ -int -tbl_calc_tree(struct tbl *tbl) -{ - - return(1); -} - - -int -tbl_write_tree(const struct tbl *tbl) -{ - struct tbl_row *row; - struct tbl_cell *cell; - struct tbl_span *span; - struct tbl_data *data; - struct tbl_head *head; - - (void)printf("header\n"); - TAILQ_FOREACH(head, &tbl->head, entries) - (void)printf("\t%s (=%p)\n", htypes[head->pos], head); - - (void)printf("layout\n"); - TAILQ_FOREACH(row, &tbl->row, entries) { - (void)printf("\trow (=%p)\n", row); - TAILQ_FOREACH(cell, &row->cell, entries) - (void)printf("\t\t%s (=%p) >%p\n", - ctypes[cell->pos], - cell, cell->head); - } - - (void)printf("data\n"); - TAILQ_FOREACH(span, &tbl->span, entries) { - (void)printf("\tspan >%p\n", span->row); - TAILQ_FOREACH(data, &span->data, entries) - (void)printf("\t\tdata >%p\n", data->cell); - } - - return(1); -} diff --git a/usr.bin/mandoc/term.c b/usr.bin/mandoc/term.c index 8ecc5e5c774..e2d136a1cca 100644 --- a/usr.bin/mandoc/term.c +++ b/usr.bin/mandoc/term.c @@ -1,4 +1,4 @@ -/* $Id: term.c,v 1.54 2010/10/27 19:27:30 schwarze Exp $ */ +/* $Id: term.c,v 1.55 2011/01/04 22:28:17 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> @@ -673,6 +673,12 @@ term_strlen(const struct termp *p, const char *cp) if (rhs) for (i = 0; i < rsz; i++) sz += (*p->width)(p, *rhs++); + } else if (ASCII_NBRSP == *cp) { + sz += (*p->width)(p, ' '); + cp++; + } else if (ASCII_HYPH == *cp) { + sz += (*p->width)(p, '-'); + cp++; } else sz += (*p->width)(p, *cp++); diff --git a/usr.bin/mandoc/term.h b/usr.bin/mandoc/term.h index 102cb18fa22..dd22b426ec8 100644 --- a/usr.bin/mandoc/term.h +++ b/usr.bin/mandoc/term.h @@ -1,6 +1,6 @@ -/* $Id: term.h,v 1.27 2010/07/31 21:43:07 schwarze Exp $ */ +/* $Id: term.h,v 1.28 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -71,9 +71,15 @@ struct termp_ps { size_t pdfobjsz; /* size of pdfobjs */ }; +struct termp_tbl { + int width; /* width in fixed chars */ + int decimal; /* decimal point position */ +}; + struct termp { enum termtype type; - size_t defrmargin; /* Right margin of the device.. */ + struct termp_tbl *tbl; /* table configuration */ + size_t defrmargin; /* Right margin of the device. */ size_t rmargin; /* Current right margin. */ size_t maxrmargin; /* Max right margin. */ size_t maxcols; /* Max size of buf. */ @@ -120,6 +126,7 @@ struct termp { }; struct termp *term_alloc(enum termenc); +void term_tbl(struct termp *, const struct tbl_span *); void term_free(struct termp *); void term_newln(struct termp *); void term_vspace(struct termp *); diff --git a/usr.bin/mandoc/term_ascii.c b/usr.bin/mandoc/term_ascii.c index 21b1abbe226..a31e1327a96 100644 --- a/usr.bin/mandoc/term_ascii.c +++ b/usr.bin/mandoc/term_ascii.c @@ -1,4 +1,4 @@ -/* $Id: term_ascii.c,v 1.3 2010/07/13 01:09:13 schwarze Exp $ */ +/* $Id: term_ascii.c,v 1.4 2011/01/04 22:28:17 schwarze Exp $ */ /* * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -14,10 +14,6 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include <sys/types.h> #include <assert.h> @@ -26,6 +22,7 @@ #include <stdlib.h> #include <unistd.h> +#include "mandoc.h" #include "out.h" #include "term.h" #include "main.h" diff --git a/usr.bin/mandoc/tree.c b/usr.bin/mandoc/tree.c index b775ca1edc7..959b0a5b744 100644 --- a/usr.bin/mandoc/tree.c +++ b/usr.bin/mandoc/tree.c @@ -1,6 +1,6 @@ -/* $Id: tree.c,v 1.10 2010/07/13 01:09:13 schwarze Exp $ */ +/* $Id: tree.c,v 1.11 2011/01/04 22:28:17 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008, 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -26,6 +26,7 @@ static void print_mdoc(const struct mdoc_node *, int); static void print_man(const struct man_node *, int); +static void print_span(const struct tbl_span *, int); /* ARGSUSED */ @@ -84,11 +85,16 @@ print_mdoc(const struct mdoc_node *n, int indent) case (MDOC_TEXT): t = "text"; break; + case (MDOC_TBL): + t = "tbl"; + break; default: abort(); /* NOTREACHED */ } + p = NULL; + switch (n->type) { case (MDOC_TEXT): p = n->string; @@ -116,6 +122,8 @@ print_mdoc(const struct mdoc_node *n, int indent) argc = n->args->argc; } break; + case (MDOC_TBL): + break; case (MDOC_ROOT): p = "root"; break; @@ -124,24 +132,32 @@ print_mdoc(const struct mdoc_node *n, int indent) /* NOTREACHED */ } - for (i = 0; i < indent; i++) - (void)printf(" "); - (void)printf("%s (%s)", p, t); - - for (i = 0; i < (int)argc; i++) { - (void)printf(" -%s", mdoc_argnames[argv[i].arg]); - if (argv[i].sz > 0) - (void)printf(" ["); - for (j = 0; j < (int)argv[i].sz; j++) - (void)printf(" [%s]", argv[i].value[j]); - if (argv[i].sz > 0) - (void)printf(" ]"); - } + if (n->span) { + assert(NULL == p); + print_span(n->span, indent); + } else { + for (i = 0; i < indent; i++) + putchar('\t'); + + printf("%s (%s)", p, t); - for (i = 0; i < (int)sz; i++) - (void)printf(" [%s]", params[i]); + for (i = 0; i < (int)argc; i++) { + printf(" -%s", mdoc_argnames[argv[i].arg]); + if (argv[i].sz > 0) + printf(" ["); + for (j = 0; j < (int)argv[i].sz; j++) + printf(" [%s]", argv[i].value[j]); + if (argv[i].sz > 0) + printf(" ]"); + } + + for (i = 0; i < (int)sz; i++) + printf(" [%s]", params[i]); - (void)printf(" %d:%d\n", n->line, n->pos); + printf(" %d:%d", n->line, n->pos); + } + + putchar('\n'); if (n->child) print_mdoc(n->child, indent + 1); @@ -175,11 +191,16 @@ print_man(const struct man_node *n, int indent) case (MAN_BODY): t = "block-body"; break; + case (MAN_TBL): + t = "tbl"; + break; default: abort(); /* NOTREACHED */ } + p = NULL; + switch (n->type) { case (MAN_TEXT): p = n->string; @@ -196,17 +217,69 @@ print_man(const struct man_node *n, int indent) case (MAN_ROOT): p = "root"; break; + case (MAN_TBL): + break; default: abort(); /* NOTREACHED */ } - for (i = 0; i < indent; i++) - (void)printf(" "); - (void)printf("%s (%s) %d:%d\n", p, t, n->line, n->pos); + if (n->span) { + assert(NULL == p); + print_span(n->span, indent); + } else { + for (i = 0; i < indent; i++) + putchar('\t'); + printf("%s (%s) %d:%d", p, t, n->line, n->pos); + } + + putchar('\n'); if (n->child) print_man(n->child, indent + 1); if (n->next) print_man(n->next, indent); } + +static void +print_span(const struct tbl_span *sp, int indent) +{ + const struct tbl_dat *dp; + int i; + + for (i = 0; i < indent; i++) + putchar('\t'); + + printf("tbl: "); + + switch (sp->pos) { + case (TBL_SPAN_HORIZ): + putchar('-'); + return; + case (TBL_SPAN_DHORIZ): + putchar('='); + return; + default: + break; + } + + for (dp = sp->first; dp; dp = dp->next) { + switch (dp->pos) { + case (TBL_DATA_HORIZ): + /* FALLTHROUGH */ + case (TBL_DATA_NHORIZ): + putchar('-'); + continue; + case (TBL_DATA_DHORIZ): + /* FALLTHROUGH */ + case (TBL_DATA_NDHORIZ): + putchar('='); + continue; + default: + break; + } + printf("[%s%s]", dp->string, dp->layout ? "" : "*"); + if (dp->next) + putchar(' '); + } +} |