=================================================================== RCS file: /cvs/mandoc/Attic/terminal.c,v retrieving revision 1.4 retrieving revision 1.12 diff -u -p -r1.4 -r1.12 --- mandoc/Attic/terminal.c 2009/03/20 22:01:07 1.4 +++ mandoc/Attic/terminal.c 2009/03/26 16:47:13 1.12 @@ -1,4 +1,4 @@ -/* $Id: terminal.c,v 1.4 2009/03/20 22:01:07 kristaps Exp $ */ +/* $Id: terminal.c,v 1.12 2009/03/26 16:47:13 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -23,58 +23,39 @@ #include #include "term.h" +#include "man.h" +#include "mdoc.h" -#ifdef __linux__ -extern size_t strlcpy(char *, const char *, size_t); -extern size_t strlcat(char *, const char *, size_t); -#endif +extern int man_run(struct termp *, + const struct man *); +extern int mdoc_run(struct termp *, + const struct mdoc *); -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 *, +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; @@ -83,9 +64,10 @@ terminal_run(void *arg, const struct mdoc *mdoc) if (NULL == p->symtab) 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); } @@ -95,12 +77,12 @@ 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) @@ -113,7 +95,7 @@ termp_free(struct termp *p) static struct termp * -termp_alloc(enum termenc enc) +term_alloc(enum termenc enc) { struct termp *p; @@ -126,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 @@ -327,16 +365,10 @@ term_word(struct termp *p, const char *word) len = (int)strlen(word); if (p->flags & TERMP_LITERAL) { - termp_pword(p, word, len); + term_pword(p, word, len); return; } - 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]) { @@ -353,215 +385,30 @@ term_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); } } -static void -termp_body(struct termp *p, struct termpair *ppair, - const struct mdoc_meta *meta, - const struct mdoc_node *node) -{ - - term_node(p, ppair, meta, node); - if (node->next) - termp_body(p, ppair, meta, node->next); -} - - /* - * 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. - */ -void -term_node(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 */ - term_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); -} - - -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 - */ - - term_vspace(p); - - p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; - p->rmargin = p->maxrmargin - strlen(buf); - p->offset = 0; - - term_word(p, os); - term_flushln(p); - - p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; - p->offset = p->rmargin; - p->rmargin = p->maxrmargin; - p->flags &= ~TERMP_NOBREAK; - - term_word(p, buf); - term_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; - - term_word(p, title); - term_flushln(p); - - p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; - p->offset = p->rmargin; - p->rmargin = p->maxrmargin - strlen(title); - - term_word(p, buf); - term_flushln(p); - - p->offset = p->rmargin; - p->rmargin = p->maxrmargin; - p->flags &= ~TERMP_NOBREAK; - p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; - - term_word(p, title); - term_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 = term_a2ascii(p->symtab, word, len, &sz))) return; - termp_stringa(p, rhs, sz); + term_stringa(p, rhs, sz); } @@ -571,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; @@ -583,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; @@ -598,18 +445,39 @@ 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 ('f' == word[*i]) { + (*i)++; + if (*i >= len) + return; + switch (word[*i]) { + case ('B'): + p->flags |= TERMP_BOLD; + break; + case ('I'): + p->flags |= TERMP_UNDER; + break; + case ('P'): + /* FALLTHROUGH */ + case ('R'): + p->flags &= ~TERMP_STYLE; + break; + default: + break; + } + return; } else if ('[' != word[*i]) { - termp_nescape(p, &word[*i], 1); + term_nescape(p, &word[*i], 1); return; } @@ -620,7 +488,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); } @@ -630,12 +498,16 @@ 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 (term_isclosedelim(word, len)) + if ( ! (TERMP_IGNDELIM & p->flags)) + p->flags |= TERMP_NOSPACE; + if ( ! (TERMP_NOSPACE & p->flags)) - termp_chara(p, ' '); + term_chara(p, ' '); if ( ! (p->flags & TERMP_NONOSPACE)) p->flags &= ~TERMP_NOSPACE; @@ -647,33 +519,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; @@ -702,7 +577,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; @@ -718,112 +593,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; - } -}