-/* $Id: term_ascii.c,v 1.50 2015/10/12 00:08:16 schwarze Exp $ */
+/* $Id: term_ascii.c,v 1.66 2020/09/09 13:45:05 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014,2015,2017,2018,2020 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#include <assert.h>
#if HAVE_WCHAR
+#include <langinfo.h>
#include <locale.h>
#endif
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#if HAVE_WCHAR
#include <wchar.h>
#include "manconf.h"
#include "main.h"
-static struct termp *ascii_init(enum termenc, const struct mchars *,
- const struct manoutput *);
+static struct termp *ascii_init(enum termenc, const struct manoutput *);
static int ascii_hspan(const struct termp *,
const struct roffsu *);
static size_t ascii_width(const struct termp *, int);
static struct termp *
-ascii_init(enum termenc enc, const struct mchars *mchars,
- const struct manoutput *outopts)
+ascii_init(enum termenc enc, const struct manoutput *outopts)
{
#if HAVE_WCHAR
char *v;
#endif
struct termp *p;
- p = mandoc_calloc(1, sizeof(struct termp));
+ p = mandoc_calloc(1, sizeof(*p));
+ p->tcol = p->tcols = mandoc_calloc(1, sizeof(*p->tcol));
+ p->maxtcol = 1;
- p->symtab = mchars;
p->line = 1;
- p->tabwidth = 5;
p->defrmargin = p->lastrmargin = 78;
p->fontq = mandoc_reallocarray(NULL,
- (p->fontsz = 8), sizeof(enum termfont));
+ (p->fontsz = 8), sizeof(*p->fontq));
p->fontq[0] = p->fontl = TERMFONT_NONE;
p->begin = ascii_begin;
p->width = ascii_width;
#if HAVE_WCHAR
- if (TERMENC_ASCII != enc) {
- v = TERMENC_LOCALE == enc ?
- setlocale(LC_ALL, "") :
- setlocale(LC_CTYPE, "en_US.UTF-8");
- if (NULL != v && MB_CUR_MAX > 1) {
- p->enc = enc;
+ if (enc != TERMENC_ASCII) {
+
+ /*
+ * Do not change any of this to LC_ALL. It might break
+ * the formatting by subtly changing the behaviour of
+ * various functions, for example strftime(3). As a
+ * worst case, it might even cause buffer overflows.
+ */
+
+ v = enc == TERMENC_LOCALE ?
+ setlocale(LC_CTYPE, "") :
+ setlocale(LC_CTYPE, UTF8_LOCALE);
+
+ /*
+ * We only support UTF-8,
+ * so revert to ASCII for anything else.
+ */
+
+ if (v != NULL &&
+ strcmp(nl_langinfo(CODESET), "UTF-8") != 0)
+ v = setlocale(LC_CTYPE, "C");
+
+ if (v != NULL && MB_CUR_MAX > 1) {
+ p->enc = TERMENC_UTF8;
p->advance = locale_advance;
p->endline = locale_endline;
p->letter = locale_letter;
if (outopts->synopsisonly)
p->synopsisonly = 1;
+ assert(p->defindent < UINT16_MAX);
+ assert(p->defrmargin < UINT16_MAX);
return p;
}
void *
-ascii_alloc(const struct mchars *mchars, const struct manoutput *outopts)
+ascii_alloc(const struct manoutput *outopts)
{
- return ascii_init(TERMENC_ASCII, mchars, outopts);
+ return ascii_init(TERMENC_ASCII, outopts);
}
void *
-utf8_alloc(const struct mchars *mchars, const struct manoutput *outopts)
+utf8_alloc(const struct manoutput *outopts)
{
- return ascii_init(TERMENC_UTF8, mchars, outopts);
+ return ascii_init(TERMENC_UTF8, outopts);
}
void *
-locale_alloc(const struct mchars *mchars, const struct manoutput *outopts)
+locale_alloc(const struct manoutput *outopts)
{
- return ascii_init(TERMENC_LOCALE, mchars, outopts);
+ return ascii_init(TERMENC_LOCALE, outopts);
}
static void
{
width /= 24;
- p->rmargin = p->defrmargin;
+ p->tcol->rmargin = p->defrmargin;
if (iop > 0)
p->defrmargin += width;
else if (iop == 0)
p->defrmargin -= width;
else
p->defrmargin = 0;
- p->lastrmargin = p->rmargin;
- p->rmargin = p->maxrmargin = p->defrmargin;
+ if (p->defrmargin > 1000)
+ p->defrmargin = 1000;
+ p->lastrmargin = p->tcol->rmargin;
+ p->tcol->rmargin = p->maxrmargin = p->defrmargin;
}
void
-ascii_sepline(void *arg)
+terminal_sepline(void *arg)
{
struct termp *p;
size_t i;
p = (struct termp *)arg;
- p->line += 3;
- putchar('\n');
+ (*p->endline)(p);
for (i = 0; i < p->defrmargin; i++)
- putchar('-');
- putchar('\n');
- putchar('\n');
+ (*p->letter)(p, '-');
+ (*p->endline)(p);
+ (*p->endline)(p);
}
static size_t
ascii_width(const struct termp *p, int c)
{
-
- return 1;
+ return c != ASCII_BREAK;
}
void
{
p->line++;
+ if ((int)p->tcol->offset > p->ti)
+ p->tcol->offset -= p->ti;
+ else
+ p->tcol->offset = 0;
+ p->ti = 0;
putchar('\n');
}
{
size_t i;
+ /*
+ * XXX We used to have "assert(len < UINT16_MAX)" here.
+ * that is not quite right because the input document
+ * can trigger that by merely providing large input.
+ * For now, simply truncate.
+ */
+ if (len > 256)
+ len = 256;
for (i = 0; i < len; i++)
putchar(' ');
}
"<80>", "<81>", "<82>", "<83>", "<84>", "<85>", "<86>", "<87>",
"<88>", "<89>", "<8A>", "<8B>", "<8C>", "<8D>", "<8E>", "<8F>",
"<90>", "<91>", "<92>", "<93>", "<94>", "<95>", "<96>", "<97>",
- "<99>", "<99>", "<9A>", "<9B>", "<9C>", "<9D>", "<9E>", "<9F>",
- nbrsp, "!", "/\bc", "GBP", "o\bx", "=\bY", "|", "<sec>",
+ "<98>", "<99>", "<9A>", "<9B>", "<9C>", "<9D>", "<9E>", "<9F>",
+ nbrsp, "!", "/\bc", "-\bL", "o\bx", "=\bY", "|", "<section>",
"\"", "(C)", "_\ba", "<<", "~", "", "(R)", "-",
- "<deg>","+-", "2", "3", "'", ",\bu", "<par>",".",
- ",", "1", "_\bo", ">>", "1/4", "1/2", "3/4", "?",
+ "<degree>","+-","^2", "^3", "'","<micro>","<paragraph>",".",
+ ",", "^1", "_\bo", ">>", "1/4", "1/2", "3/4", "?",
"`\bA", "'\bA", "^\bA", "~\bA", "\"\bA","o\bA", "AE", ",\bC",
"`\bE", "'\bE", "^\bE", "\"\bE","`\bI", "'\bI", "^\bI", "\"\bI",
- "-\bD", "~\bN", "`\bO", "'\bO", "^\bO", "~\bO", "\"\bO","x",
+ "Dh", "~\bN", "`\bO", "'\bO", "^\bO", "~\bO", "\"\bO","x",
"/\bO", "`\bU", "'\bU", "^\bU", "\"\bU","'\bY", "Th", "ss",
"`\ba", "'\ba", "^\ba", "~\ba", "\"\ba","o\ba", "ae", ",\bc",
"`\be", "'\be", "^\be", "\"\be","`\bi", "'\bi", "^\bi", "\"\bi",
- "d", "~\bn", "`\bo", "'\bo", "^\bo", "~\bo", "\"\bo","-:-",
+ "dh", "~\bn", "`\bo", "'\bo", "^\bo", "~\bo", "\"\bo","/",
"/\bo", "`\bu", "'\bu", "^\bu", "\"\bu","'\by", "th", "\"\by",
"A", "a", "A", "a", "A", "a", "'\bC", "'\bc",
"^\bC", "^\bc", "C", "c", "C", "c", "D", "d",
{
size_t i;
+ /*
+ * XXX We used to have "assert(len < UINT16_MAX)" here.
+ * that is not quite right because the input document
+ * can trigger that by merely providing large input.
+ * For now, simply truncate.
+ */
+ if (len > 256)
+ len = 256;
for (i = 0; i < len; i++)
putwchar(L' ');
}
{
p->line++;
+ if ((int)p->tcol->offset > p->ti)
+ p->tcol->offset -= p->ti;
+ else
+ p->tcol->offset = 0;
+ p->ti = 0;
putwchar(L'\n');
}