-static void
-stringa(struct termp *p, const char *s)
-{
-
- /* XXX - speed up if not passing to chara. */
- for ( ; *s; s++)
- chara(p, *s);
-}
-
-
-static void
-chara(struct termp *p, char c)
-{
-
- /*
- * Insert a single character into the line-buffer. If the
- * buffer's space is exceeded, then allocate more space.
- */
- if (p->col + 1 >= p->maxcols) {
- p->buf = realloc(p->buf, p->maxcols * 2);
- if (NULL == p->buf)
- err(1, "malloc");
- p->maxcols *= 2;
- }
- p->buf[(p->col)++] = c;
-}
-
-
-static void
-style(struct termp *p, enum termstyle esc)
-{
-
- if (p->col + 4 >= p->maxcols)
- errx(1, "line overrun");
-
- p->buf[(p->col)++] = 27;
- p->buf[(p->col)++] = '[';
- switch (esc) {
- case (STYLE_CLEAR):
- p->buf[(p->col)++] = '0';
- break;
- case (STYLE_BOLD):
- p->buf[(p->col)++] = '1';
- break;
- case (STYLE_UNDERLINE):
- p->buf[(p->col)++] = '4';
- break;
- default:
- abort();
- /* NOTREACHED */
- }
- p->buf[(p->col)++] = 'm';
-}
-
-
-static void
-nescape(struct termp *p, const char *word, size_t len)
-{
-
- switch (len) {
- case (1):
- if ('q' == word[0])
- stringa(p, TERMSYM_DQUOTE);
- break;
- case (2):
- if ('r' == word[0] && 'B' == word[1])
- stringa(p, TERMSYM_RBRACK);
- else if ('l' == word[0] && 'B' == word[1])
- stringa(p, TERMSYM_LBRACK);
- else if ('l' == word[0] && 'q' == word[1])
- stringa(p, TERMSYM_LDQUOTE);
- else if ('r' == word[0] && 'q' == word[1])
- stringa(p, TERMSYM_RDQUOTE);
- else if ('o' == word[0] && 'q' == word[1])
- stringa(p, TERMSYM_LSQUOTE);
- else if ('a' == word[0] && 'q' == word[1])
- stringa(p, TERMSYM_RSQUOTE);
- else if ('<' == word[0] && '-' == word[1])
- stringa(p, TERMSYM_LARROW);
- else if ('-' == word[0] && '>' == word[1])
- stringa(p, TERMSYM_RARROW);
- else if ('b' == word[0] && 'u' == word[1])
- stringa(p, TERMSYM_BULLET);
- else if ('<' == word[0] && '=' == word[1])
- stringa(p, TERMSYM_LE);
- else if ('>' == word[0] && '=' == word[1])
- stringa(p, TERMSYM_GE);
- else if ('=' == word[0] && '=' == word[1])
- stringa(p, TERMSYM_EQ);
- else if ('+' == word[0] && '-' == word[1])
- stringa(p, TERMSYM_PLUSMINUS);
- else if ('u' == word[0] && 'a' == word[1])
- stringa(p, TERMSYM_UARROW);
- else if ('d' == word[0] && 'a' == word[1])
- stringa(p, TERMSYM_DARROW);
- else if ('a' == word[0] && 'a' == word[1])
- stringa(p, TERMSYM_ACUTE);
- else if ('g' == word[0] && 'a' == word[1])
- stringa(p, TERMSYM_GRAVE);
- else if ('!' == word[0] && '=' == word[1])
- stringa(p, TERMSYM_NEQ);
- else if ('i' == word[0] && 'f' == word[1])
- stringa(p, TERMSYM_INF);
- else if ('n' == word[0] && 'a' == word[1])
- stringa(p, TERMSYM_NAN);
- else if ('b' == word[0] && 'a' == word[1])
- stringa(p, TERMSYM_BAR);
-
- /* Deprecated forms. */
- else if ('B' == word[0] && 'a' == word[1])
- stringa(p, TERMSYM_BAR);
- else if ('I' == word[0] && 'f' == word[1])
- stringa(p, TERMSYM_INF2);
- else if ('G' == word[0] && 'e' == word[1])
- stringa(p, TERMSYM_GE);
- else if ('G' == word[0] && 't' == word[1])
- stringa(p, TERMSYM_GT);
- else if ('L' == word[0] && 'e' == word[1])
- stringa(p, TERMSYM_LE);
- else if ('L' == word[0] && 'q' == word[1])
- stringa(p, TERMSYM_LDQUOTE);
- else if ('L' == word[0] && 't' == word[1])
- stringa(p, TERMSYM_LT);
- else if ('N' == word[0] && 'a' == word[1])
- stringa(p, TERMSYM_NAN);
- else if ('N' == word[0] && 'e' == word[1])
- stringa(p, TERMSYM_NEQ);
- else if ('P' == word[0] && 'i' == word[1])
- stringa(p, TERMSYM_PI);
- else if ('P' == word[0] && 'm' == word[1])
- stringa(p, TERMSYM_PLUSMINUS);
- else if ('R' == word[0] && 'q' == word[1])
- stringa(p, TERMSYM_RDQUOTE);
- break;
- default:
- break;
- }
-}
-
-
-static void
-pescape(struct termp *p, const char *word, size_t *i, size_t len)
-{
- size_t j;
-
- (*i)++;
- assert(*i < len);
-
- /*
- * Handle an escape sequence. This must manage both groff-style
- * escapes and mdoc-style escapes.
- */
-
- if ('(' == word[*i]) {
- /* Two-character escapes. */
- (*i)++;
- assert(*i + 1 < len);
- nescape(p, &word[*i], 2);
- (*i)++;
- return;
-
- } else if ('*' == word[*i]) {
- (*i)++;
- assert(*i < len);
- switch (word[*i]) {
- case ('('):
- (*i)++;
- assert(*i + 1 < len);
- nescape(p, &word[*i], 2);
- (*i)++;
- return;
- default:
- break;
- }
- nescape(p, &word[*i], 1);
- return;
-
- } else if ('[' != word[*i]) {
- /* One-character escapes. */
- switch (word[*i]) {
- case ('\\'):
- /* FALLTHROUGH */
- case ('\''):
- /* FALLTHROUGH */
- case ('`'):
- /* FALLTHROUGH */
- case ('-'):
- /* FALLTHROUGH */
- case (' '):
- /* FALLTHROUGH */
- case ('.'):
- chara(p, word[*i]);
- break;
- case ('e'):
- chara(p, '\\');
- break;
- default:
- break;
- }
- return;
- }
-
- (*i)++;
- for (j = 0; word[*i] && ']' != word[*i]; (*i)++, j++)
- /* Loop... */ ;
-
- nescape(p, &word[*i - j], j);
-}
-
-
-static void
-pword(struct termp *p, const char *word, size_t len)
-{
- size_t i;
-
- /*
- * Handle pwords, partial words, which may be either a single
- * word or a phrase that cannot be broken down (such as a
- * literal string). This handles word styling.
- */
-
- if ( ! (p->flags & TERMP_NOSPACE) &&
- ! (p->flags & TERMP_LITERAL))
- chara(p, ' ');
-
- if ( ! (p->flags & TERMP_NONOSPACE))
- p->flags &= ~TERMP_NOSPACE;
-
- /*
- * XXX - if literal and underlining, this will underline the
- * spaces between literal words.
- */
-
- if (p->flags & TERMP_BOLD)
- style(p, STYLE_BOLD);
- if (p->flags & TERMP_UNDERLINE)
- style(p, STYLE_UNDERLINE);
-
- for (i = 0; i < len; i++) {
- if ('\\' == word[i]) {
- pescape(p, word, &i, len);
- continue;
- }
- chara(p, word[i]);
- }
-
- if (p->flags & TERMP_BOLD ||
- p->flags & TERMP_UNDERLINE)
- style(p, STYLE_CLEAR);
-}
-
-