=================================================================== RCS file: /cvs/mandoc/Attic/terminal.c,v retrieving revision 1.1 retrieving revision 1.10 diff -u -p -r1.1 -r1.10 --- mandoc/Attic/terminal.c 2009/03/19 16:17:27 1.1 +++ mandoc/Attic/terminal.c 2009/03/26 14:44:41 1.10 @@ -1,4 +1,4 @@ -/* $Id: terminal.c,v 1.1 2009/03/19 16:17:27 kristaps Exp $ */ +/* $Id: terminal.c,v 1.10 2009/03/26 14:44:41 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -23,64 +23,51 @@ #include #include "term.h" +#include "man.h" +#include "mdoc.h" -static struct termp *termp_alloc(enum termenc); -static void termp_free(struct termp *); -static void termp_body(struct termp *, struct termpair *, - const struct mdoc_meta *, - const struct mdoc_node *); -static void termp_head(struct termp *, - const struct mdoc_meta *); -static void termp_foot(struct termp *, - const struct mdoc_meta *); -static void termp_pword(struct termp *, const char *, int); -static void termp_pescape(struct termp *, +extern int man_run(struct termp *, + const struct man *); +extern int mdoc_run(struct termp *, + const struct mdoc *); + +static struct termp *term_alloc(enum termenc); +static void term_free(struct termp *); +static void term_pword(struct termp *, const char *, int); +static void term_pescape(struct termp *, const char *, int *, int); -static void termp_nescape(struct termp *, +static void term_nescape(struct termp *, const char *, size_t); -static void termp_chara(struct termp *, char); -static void termp_stringa(struct termp *, +static void term_chara(struct termp *, char); +static void term_stringa(struct termp *, const char *, size_t); -static void sanity(const struct mdoc_node *); /* XXX */ +static int term_isopendelim(const char *, int); +static int term_isclosedelim(const char *, int); void * -latin1_alloc(void) -{ - - return(termp_alloc(TERMENC_LATIN1)); -} - - -void * -utf8_alloc(void) -{ - - return(termp_alloc(TERMENC_UTF8)); -} - - -void * ascii_alloc(void) { - return(termp_alloc(TERMENC_ASCII)); + return(term_alloc(TERMENC_ASCII)); } int -terminal_run(void *arg, const struct mdoc *mdoc) +terminal_run(void *arg, const struct man *man, + const struct mdoc *mdoc) { struct termp *p; p = (struct termp *)arg; if (NULL == p->symtab) - p->symtab = ascii2htab(); + p->symtab = term_ascii2htab(); - termp_head(p, mdoc_meta(mdoc)); - termp_body(p, NULL, mdoc_meta(mdoc), mdoc_node(mdoc)); - termp_foot(p, mdoc_meta(mdoc)); + if (man) + return(man_run(p, man)); + if (mdoc) + return(mdoc_run(p, mdoc)); return(1); } @@ -90,25 +77,25 @@ void terminal_free(void *arg) { - termp_free((struct termp *)arg); + term_free((struct termp *)arg); } static void -termp_free(struct termp *p) +term_free(struct termp *p) { if (p->buf) free(p->buf); if (TERMENC_ASCII == p->enc && p->symtab) - asciifree(p->symtab); + term_asciifree(p->symtab); free(p); } static struct termp * -termp_alloc(enum termenc enc) +term_alloc(enum termenc enc) { struct termp *p; @@ -121,6 +108,62 @@ termp_alloc(enum termenc enc) } +static int +term_isclosedelim(const char *p, int len) +{ + + if (1 != len) + return(0); + + switch (*p) { + case('.'): + /* FALLTHROUGH */ + case(','): + /* FALLTHROUGH */ + case(';'): + /* FALLTHROUGH */ + case(':'): + /* FALLTHROUGH */ + case('?'): + /* FALLTHROUGH */ + case('!'): + /* FALLTHROUGH */ + case(')'): + /* FALLTHROUGH */ + case(']'): + /* FALLTHROUGH */ + case('}'): + return(1); + default: + break; + } + + return(0); +} + + +static int +term_isopendelim(const char *p, int len) +{ + + if (1 != len) + return(0); + + switch (*p) { + case('('): + /* FALLTHROUGH */ + case('['): + /* FALLTHROUGH */ + case('{'): + return(1); + default: + break; + } + + return(0); +} + + /* * Flush a line of text. A "line" is loosely defined as being something * that should be followed by a newline, regardless of whether it's @@ -156,7 +199,7 @@ termp_alloc(enum termenc enc) * possible). */ void -flushln(struct termp *p) +term_flushln(struct termp *p) { int i, j; size_t vsz, vis, maxvis, mmax, bp; @@ -217,21 +260,12 @@ flushln(struct termp *p) for (j = 0; j < (int)p->offset; j++) putchar(' '); vis = 0; - } else if (vis + vsz > bp) - warnx("word breaks right margin"); - - /* TODO: hyphenate. */ - - } else { - if (vis && vis + vsz > bp) { - putchar('\n'); - for (j = 0; j < (int)p->rmargin; j++) - putchar(' '); - vis = p->rmargin - p->offset; - } else if (vis + vsz > bp) - warnx("word breaks right margin"); - - /* TODO: hyphenate. */ + } + } else if (vis && vis + vsz > bp) { + putchar('\n'); + for (j = 0; j < (int)p->rmargin; j++) + putchar(' '); + vis = p->rmargin - p->offset; } /* @@ -289,7 +323,7 @@ flushln(struct termp *p) * assertion. */ void -newln(struct termp *p) +term_newln(struct termp *p) { p->flags |= TERMP_NOSPACE; @@ -297,7 +331,7 @@ newln(struct termp *p) p->flags &= ~TERMP_NOLPAD; return; } - flushln(p); + term_flushln(p); p->flags &= ~TERMP_NOLPAD; } @@ -309,10 +343,10 @@ newln(struct termp *p) * assertion. */ void -vspace(struct termp *p) +term_vspace(struct termp *p) { - newln(p); + term_newln(p); putchar('\n'); } @@ -324,24 +358,17 @@ vspace(struct termp *p) * the word and put it verbatim into the output buffer. */ void -word(struct termp *p, const char *word) +term_word(struct termp *p, const char *word) { int i, j, len; + len = (int)strlen(word); + if (p->flags & TERMP_LITERAL) { - termp_pword(p, word, (int)strlen(word)); + term_pword(p, word, len); return; } - if (0 == (len = (int)strlen(word))) - errx(1, "blank line not in literal context"); - - if (mdoc_isdelim(word)) { - if ( ! (p->flags & TERMP_IGNDELIM)) - p->flags |= TERMP_NOSPACE; - p->flags &= ~TERMP_IGNDELIM; - } - /* LINTED */ for (j = i = 0; i < len; i++) { if (' ' != word[i]) { @@ -358,208 +385,30 @@ word(struct termp *p, const char *word) if (0 == j) continue; assert(i >= j); - termp_pword(p, &word[i - j], j); + term_pword(p, &word[i - j], j); j = 0; } if (j > 0) { assert(i >= j); - termp_pword(p, &word[i - j], j); + term_pword(p, &word[i - j], j); } } /* - * This is the main function for printing out nodes. It's constituted - * of PRE and POST functions, which correspond to prefix and infix - * processing. The termpair structure allows data to persist between - * prefix and postfix invocations. - */ -static void -termp_body(struct termp *p, struct termpair *ppair, - const struct mdoc_meta *meta, - const struct mdoc_node *node) -{ - int dochild; - struct termpair pair; - - /* Some quick sanity-checking. */ - - sanity(node); - - /* Pre-processing. */ - - dochild = 1; - pair.ppair = ppair; - pair.type = 0; - pair.offset = pair.rmargin = 0; - pair.flag = 0; - pair.count = 0; - - if (MDOC_TEXT != node->type) { - if (termacts[node->tok].pre) - if ( ! (*termacts[node->tok].pre)(p, &pair, meta, node)) - dochild = 0; - } else /* MDOC_TEXT == node->type */ - word(p, node->string); - - /* Children. */ - - if (TERMPAIR_FLAG & pair.type) - p->flags |= pair.flag; - - if (dochild && node->child) - termp_body(p, &pair, meta, node->child); - - if (TERMPAIR_FLAG & pair.type) - p->flags &= ~pair.flag; - - /* Post-processing. */ - - if (MDOC_TEXT != node->type) - if (termacts[node->tok].post) - (*termacts[node->tok].post)(p, &pair, meta, node); - - /* Siblings. */ - - if (node->next) - termp_body(p, ppair, meta, node->next); -} - - -static void -termp_foot(struct termp *p, const struct mdoc_meta *meta) -{ - struct tm *tm; - char *buf, *os; - - if (NULL == (buf = malloc(p->rmargin))) - err(1, "malloc"); - if (NULL == (os = malloc(p->rmargin))) - err(1, "malloc"); - - tm = localtime(&meta->date); - -#ifdef __OpenBSD__ - if (NULL == strftime(buf, p->rmargin, "%B %d, %Y", tm)) -#else - if (0 == strftime(buf, p->rmargin, "%B %d, %Y", tm)) -#endif - err(1, "strftime"); - - (void)strlcpy(os, meta->os, p->rmargin); - - /* - * This is /slightly/ different from regular groff output - * because we don't have page numbers. Print the following: - * - * OS MDOCDATE - */ - - vspace(p); - - p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; - p->rmargin = p->maxrmargin - strlen(buf); - p->offset = 0; - - word(p, os); - flushln(p); - - p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; - p->offset = p->rmargin; - p->rmargin = p->maxrmargin; - p->flags &= ~TERMP_NOBREAK; - - word(p, buf); - flushln(p); - - free(buf); - free(os); -} - - -static void -termp_head(struct termp *p, const struct mdoc_meta *meta) -{ - char *buf, *title; - - p->rmargin = p->maxrmargin; - p->offset = 0; - - if (NULL == (buf = malloc(p->rmargin))) - err(1, "malloc"); - if (NULL == (title = malloc(p->rmargin))) - err(1, "malloc"); - - /* - * The header is strange. It has three components, which are - * really two with the first duplicated. It goes like this: - * - * IDENTIFIER TITLE IDENTIFIER - * - * The IDENTIFIER is NAME(SECTION), which is the command-name - * (if given, or "unknown" if not) followed by the manual page - * section. These are given in `Dt'. The TITLE is a free-form - * string depending on the manual volume. If not specified, it - * switches on the manual section. - */ - - assert(meta->vol); - (void)strlcpy(buf, meta->vol, p->rmargin); - - if (meta->arch) { - (void)strlcat(buf, " (", p->rmargin); - (void)strlcat(buf, meta->arch, p->rmargin); - (void)strlcat(buf, ")", p->rmargin); - } - - (void)snprintf(title, p->rmargin, "%s(%d)", - meta->title, meta->msec); - - p->offset = 0; - p->rmargin = (p->maxrmargin - strlen(buf)) / 2; - p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; - - word(p, title); - flushln(p); - - p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; - p->offset = p->rmargin; - p->rmargin = p->maxrmargin - strlen(title); - - word(p, buf); - flushln(p); - - p->offset = p->rmargin; - p->rmargin = p->maxrmargin; - p->flags &= ~TERMP_NOBREAK; - p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; - - word(p, title); - flushln(p); - - p->rmargin = p->maxrmargin; - p->offset = 0; - p->flags &= ~TERMP_NOSPACE; - - free(title); - free(buf); -} - - -/* * Determine the symbol indicated by an escape sequences, that is, one * starting with a backslash. Once done, we pass this value into the * output buffer by way of the symbol table. */ static void -termp_nescape(struct termp *p, const char *word, size_t len) +term_nescape(struct termp *p, const char *word, size_t len) { const char *rhs; size_t sz; - if (NULL == (rhs = a2ascii(p->symtab, word, len, &sz))) + if (NULL == (rhs = term_a2ascii(p->symtab, word, len, &sz))) return; - termp_stringa(p, rhs, sz); + term_stringa(p, rhs, sz); } @@ -569,7 +418,7 @@ termp_nescape(struct termp *p, const char *word, size_ * the escape sequence (we assert upon badly-formed escape sequences). */ static void -termp_pescape(struct termp *p, const char *word, int *i, int len) +term_pescape(struct termp *p, const char *word, int *i, int len) { int j; @@ -581,7 +430,7 @@ termp_pescape(struct termp *p, const char *word, int * if (*i + 1 >= len) return; - termp_nescape(p, &word[*i], 2); + term_nescape(p, &word[*i], 2); (*i)++; return; @@ -596,18 +445,18 @@ termp_pescape(struct termp *p, const char *word, int * if (*i + 1 >= len) return; - termp_nescape(p, &word[*i], 2); + term_nescape(p, &word[*i], 2); (*i)++; return; case ('['): break; default: - termp_nescape(p, &word[*i], 1); + term_nescape(p, &word[*i], 1); return; } } else if ('[' != word[*i]) { - termp_nescape(p, &word[*i], 1); + term_nescape(p, &word[*i], 1); return; } @@ -618,7 +467,7 @@ termp_pescape(struct termp *p, const char *word, int * if (0 == word[*i]) return; - termp_nescape(p, &word[*i - j], (size_t)j); + term_nescape(p, &word[*i - j], (size_t)j); } @@ -628,14 +477,17 @@ termp_pescape(struct termp *p, const char *word, int * * handles word styling. */ static void -termp_pword(struct termp *p, const char *word, int len) +term_pword(struct termp *p, const char *word, int len) { int i; - if ( ! (TERMP_NOSPACE & p->flags) && - ! (TERMP_LITERAL & p->flags)) - termp_chara(p, ' '); + if (term_isclosedelim(word, len)) + if ( ! (TERMP_IGNDELIM & p->flags)) + p->flags |= TERMP_NOSPACE; + if ( ! (TERMP_NOSPACE & p->flags)) + term_chara(p, ' '); + if ( ! (p->flags & TERMP_NONOSPACE)) p->flags &= ~TERMP_NOSPACE; @@ -646,33 +498,36 @@ termp_pword(struct termp *p, const char *word, int len for (i = 0; i < len; i++) { if ('\\' == word[i]) { - termp_pescape(p, word, &i, len); + term_pescape(p, word, &i, len); continue; } if (TERMP_STYLE & p->flags) { if (TERMP_BOLD & p->flags) { - termp_chara(p, word[i]); - termp_chara(p, 8); + term_chara(p, word[i]); + term_chara(p, 8); } if (TERMP_UNDER & p->flags) { - termp_chara(p, '_'); - termp_chara(p, 8); + term_chara(p, '_'); + term_chara(p, 8); } } - termp_chara(p, word[i]); + term_chara(p, word[i]); } + + if (term_isopendelim(word, len)) + p->flags |= TERMP_NOSPACE; } /* - * Like termp_chara() but for arbitrary-length buffers. Resize the + * Like term_chara() but for arbitrary-length buffers. Resize the * buffer by a factor of two (if the buffer is less than that) or the * buffer's size. */ static void -termp_stringa(struct termp *p, const char *c, size_t sz) +term_stringa(struct termp *p, const char *c, size_t sz) { size_t s; @@ -701,7 +556,7 @@ termp_stringa(struct termp *p, const char *c, size_t s * size. */ static void -termp_chara(struct termp *p, char c) +term_chara(struct termp *p, char c) { size_t s; @@ -717,112 +572,3 @@ termp_chara(struct termp *p, char c) p->buf[(int)(p->col)++] = c; } - -static void -sanity(const struct mdoc_node *n) -{ - - switch (n->type) { - case (MDOC_TEXT): - if (n->child) - errx(1, "regular form violated (1)"); - if (NULL == n->parent) - errx(1, "regular form violated (2)"); - if (NULL == n->string) - errx(1, "regular form violated (3)"); - switch (n->parent->type) { - case (MDOC_TEXT): - /* FALLTHROUGH */ - case (MDOC_ROOT): - errx(1, "regular form violated (4)"); - /* NOTREACHED */ - default: - break; - } - break; - case (MDOC_ELEM): - if (NULL == n->parent) - errx(1, "regular form violated (5)"); - switch (n->parent->type) { - case (MDOC_TAIL): - /* FALLTHROUGH */ - case (MDOC_BODY): - /* FALLTHROUGH */ - case (MDOC_HEAD): - break; - default: - errx(1, "regular form violated (6)"); - /* NOTREACHED */ - } - if (n->child) switch (n->child->type) { - case (MDOC_TEXT): - break; - default: - errx(1, "regular form violated (7("); - /* NOTREACHED */ - } - break; - case (MDOC_HEAD): - /* FALLTHROUGH */ - case (MDOC_BODY): - /* FALLTHROUGH */ - case (MDOC_TAIL): - if (NULL == n->parent) - errx(1, "regular form violated (8)"); - if (MDOC_BLOCK != n->parent->type) - errx(1, "regular form violated (9)"); - if (n->child) switch (n->child->type) { - case (MDOC_BLOCK): - /* FALLTHROUGH */ - case (MDOC_ELEM): - /* FALLTHROUGH */ - case (MDOC_TEXT): - break; - default: - errx(1, "regular form violated (a)"); - /* NOTREACHED */ - } - break; - case (MDOC_BLOCK): - if (NULL == n->parent) - errx(1, "regular form violated (b)"); - if (NULL == n->child) - errx(1, "regular form violated (c)"); - switch (n->parent->type) { - case (MDOC_ROOT): - /* FALLTHROUGH */ - case (MDOC_HEAD): - /* FALLTHROUGH */ - case (MDOC_BODY): - /* FALLTHROUGH */ - case (MDOC_TAIL): - break; - default: - errx(1, "regular form violated (d)"); - /* NOTREACHED */ - } - switch (n->child->type) { - case (MDOC_ROOT): - /* FALLTHROUGH */ - case (MDOC_ELEM): - errx(1, "regular form violated (e)"); - /* NOTREACHED */ - default: - break; - } - break; - case (MDOC_ROOT): - if (n->parent) - errx(1, "regular form violated (f)"); - if (NULL == n->child) - errx(1, "regular form violated (10)"); - switch (n->child->type) { - case (MDOC_BLOCK): - break; - default: - errx(1, "regular form violated (11)"); - /* NOTREACHED */ - } - break; - } -}