Return to term_ascii.c CVS log | Up to [cvsweb.bsd.lv] / mandoc |
version 1.15, 2011/05/17 22:32:45 | version 1.37, 2014/10/28 02:43:59 | ||
---|---|---|---|
|
|
||
/* $Id$ */ | /* $Id$ */ | ||
/* | /* | ||
* Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> | * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> | ||
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org> | |||
* | * | ||
* Permission to use, copy, modify, and distribute this software for any | * Permission to use, copy, modify, and distribute this software for any | ||
* purpose with or without fee is hereby granted, provided that the above | * purpose with or without fee is hereby granted, provided that the above | ||
|
|
||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
*/ | */ | ||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | #include "config.h" | ||
#endif | |||
#include <sys/types.h> | #include <sys/types.h> | ||
#include <assert.h> | #if HAVE_WCHAR | ||
#ifdef USE_WCHAR | #include <locale.h> | ||
# include <locale.h> | |||
#endif | #endif | ||
#include <stdint.h> | #include <stdint.h> | ||
#include <stdio.h> | #include <stdio.h> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
#include <unistd.h> | #include <unistd.h> | ||
#ifdef USE_WCHAR | #if HAVE_WCHAR | ||
# include <wchar.h> | #include <wchar.h> | ||
#endif | #endif | ||
#include "mandoc.h" | #include "mandoc.h" | ||
#include "mandoc_aux.h" | |||
#include "out.h" | #include "out.h" | ||
#include "term.h" | #include "term.h" | ||
#include "main.h" | #include "main.h" | ||
#if ! defined(__STDC_ISO_10646__) | |||
# undef USE_WCHAR | |||
#endif | |||
static struct termp *ascii_init(enum termenc, char *); | static struct termp *ascii_init(enum termenc, char *); | ||
static double ascii_hspan(const struct termp *, | static double ascii_hspan(const struct termp *, | ||
const struct roffsu *); | const struct roffsu *); | ||
|
|
||
static void ascii_end(struct termp *); | static void ascii_end(struct termp *); | ||
static void ascii_endline(struct termp *); | static void ascii_endline(struct termp *); | ||
static void ascii_letter(struct termp *, int); | static void ascii_letter(struct termp *, int); | ||
static void ascii_setwidth(struct termp *, int, size_t); | |||
#ifdef USE_WCHAR | #if HAVE_WCHAR | ||
static void locale_advance(struct termp *, size_t); | static void locale_advance(struct termp *, size_t); | ||
static void locale_endline(struct termp *); | static void locale_endline(struct termp *); | ||
static void locale_letter(struct termp *, int); | static void locale_letter(struct termp *, int); | ||
static size_t locale_width(const struct termp *, int); | static size_t locale_width(const struct termp *, int); | ||
#endif | #endif | ||
static struct termp * | static struct termp * | ||
ascii_init(enum termenc enc, char *outopts) | ascii_init(enum termenc enc, char *outopts) | ||
{ | { | ||
const char *toks[2]; | const char *toks[5]; | ||
char *v; | char *v; | ||
struct termp *p; | struct termp *p; | ||
p = mandoc_calloc(1, sizeof(struct termp)); | p = mandoc_calloc(1, sizeof(struct termp)); | ||
p->enc = enc; | |||
p->tabwidth = 5; | p->tabwidth = 5; | ||
p->defrmargin = 78; | p->defrmargin = p->lastrmargin = 78; | ||
p->begin = ascii_begin; | p->begin = ascii_begin; | ||
p->end = ascii_end; | p->end = ascii_end; | ||
|
|
||
p->advance = ascii_advance; | p->advance = ascii_advance; | ||
p->endline = ascii_endline; | p->endline = ascii_endline; | ||
p->letter = ascii_letter; | p->letter = ascii_letter; | ||
p->setwidth = ascii_setwidth; | |||
p->width = ascii_width; | p->width = ascii_width; | ||
#if defined (USE_WCHAR) | #if HAVE_WCHAR | ||
if (TERMENC_LOCALE == enc) | if (TERMENC_ASCII != enc) { | ||
if (setlocale(LC_ALL, "") && MB_CUR_MAX > 1) { | v = TERMENC_LOCALE == enc ? | ||
setlocale(LC_ALL, "") : | |||
setlocale(LC_CTYPE, "en_US.UTF-8"); | |||
if (NULL != v && MB_CUR_MAX > 1) { | |||
p->enc = enc; | p->enc = enc; | ||
p->advance = locale_advance; | p->advance = locale_advance; | ||
p->endline = locale_endline; | p->endline = locale_endline; | ||
p->letter = locale_letter; | p->letter = locale_letter; | ||
p->width = locale_width; | p->width = locale_width; | ||
} | } | ||
} | |||
#endif | #endif | ||
toks[0] = "width"; | toks[0] = "indent"; | ||
toks[1] = NULL; | toks[1] = "width"; | ||
toks[2] = "mdoc"; | |||
toks[3] = "synopsis"; | |||
toks[4] = NULL; | |||
while (outopts && *outopts) | while (outopts && *outopts) | ||
switch (getsubopt(&outopts, UNCONST(toks), &v)) { | switch (getsubopt(&outopts, UNCONST(toks), &v)) { | ||
case (0): | case 0: | ||
p->defindent = (size_t)atoi(v); | |||
break; | |||
case 1: | |||
p->defrmargin = (size_t)atoi(v); | p->defrmargin = (size_t)atoi(v); | ||
break; | break; | ||
case 2: | |||
/* | |||
* Temporary, undocumented mode | |||
* to imitate mdoc(7) output style. | |||
*/ | |||
p->mdocstyle = 1; | |||
p->defindent = 5; | |||
break; | |||
case 3: | |||
p->synopsisonly = 1; | |||
break; | |||
default: | default: | ||
break; | break; | ||
} | } | ||
|
|
||
} | } | ||
void * | void * | ||
utf8_alloc(char *outopts) | |||
{ | |||
return(ascii_init(TERMENC_UTF8, outopts)); | |||
} | |||
void * | |||
locale_alloc(char *outopts) | locale_alloc(char *outopts) | ||
{ | { | ||
return(ascii_init(TERMENC_LOCALE, outopts)); | return(ascii_init(TERMENC_LOCALE, outopts)); | ||
} | } | ||
/* ARGSUSED */ | static void | ||
ascii_setwidth(struct termp *p, int iop, size_t width) | |||
{ | |||
p->rmargin = p->defrmargin; | |||
if (0 < iop) | |||
p->defrmargin += width; | |||
else if (0 > iop) | |||
p->defrmargin -= width; | |||
else | |||
p->defrmargin = width ? width : p->lastrmargin; | |||
p->lastrmargin = p->rmargin; | |||
p->rmargin = p->maxrmargin = p->defrmargin; | |||
} | |||
static size_t | static size_t | ||
ascii_width(const struct termp *p, int c) | ascii_width(const struct termp *p, int c) | ||
{ | { | ||
|
|
||
term_free((struct termp *)arg); | term_free((struct termp *)arg); | ||
} | } | ||
/* ARGSUSED */ | |||
static void | static void | ||
ascii_letter(struct termp *p, int c) | ascii_letter(struct termp *p, int c) | ||
{ | { | ||
putchar(c); | putchar(c); | ||
} | } | ||
|
|
||
(*p->footf)(p, p->argf); | (*p->footf)(p, p->argf); | ||
} | } | ||
/* ARGSUSED */ | |||
static void | static void | ||
ascii_endline(struct termp *p) | ascii_endline(struct termp *p) | ||
{ | { | ||
|
|
||
putchar('\n'); | putchar('\n'); | ||
} | } | ||
/* ARGSUSED */ | |||
static void | static void | ||
ascii_advance(struct termp *p, size_t len) | ascii_advance(struct termp *p, size_t len) | ||
{ | { | ||
size_t i; | size_t i; | ||
for (i = 0; i < len; i++) | for (i = 0; i < len; i++) | ||
putchar(' '); | putchar(' '); | ||
} | } | ||
/* ARGSUSED */ | |||
static double | static double | ||
ascii_hspan(const struct termp *p, const struct roffsu *su) | ascii_hspan(const struct termp *p, const struct roffsu *su) | ||
{ | { | ||
double r; | double r; | ||
/* | /* | ||
* Approximate based on character width. These are generated | * Approximate based on character width. | ||
* entirely by eyeballing the screen, but appear to be correct. | * None of these will be actually correct given that an inch on | ||
* the screen depends on character size, terminal, etc., etc. | |||
*/ | */ | ||
switch (su->unit) { | switch (su->unit) { | ||
case (SCALE_CM): | case SCALE_BU: | ||
r = 4 * su->scale; | r = su->scale * 10.0 / 240.0; | ||
break; | break; | ||
case (SCALE_IN): | case SCALE_CM: | ||
r = 10 * su->scale; | r = su->scale * 10.0 / 2.54; | ||
break; | break; | ||
case (SCALE_PC): | case SCALE_FS: | ||
r = (10 * su->scale) / 6; | r = su->scale * 2730.666; | ||
break; | break; | ||
case (SCALE_PT): | case SCALE_IN: | ||
r = (10 * su->scale) / 72; | r = su->scale * 10.0; | ||
break; | break; | ||
case (SCALE_MM): | case SCALE_MM: | ||
r = su->scale / 1000; | r = su->scale / 100.0; | ||
break; | break; | ||
case (SCALE_VS): | case SCALE_PC: | ||
r = su->scale * 2 - 1; | r = su->scale * 10.0 / 6.0; | ||
break; | break; | ||
default: | case SCALE_PT: | ||
r = su->scale * 10.0 / 72.0; | |||
break; | |||
case SCALE_VS: | |||
r = su->scale * 2.0 - 1.0; | |||
break; | |||
case SCALE_EN: | |||
/* FALLTHROUGH */ | |||
case SCALE_EM: | |||
r = su->scale; | r = su->scale; | ||
break; | break; | ||
default: | |||
abort(); | |||
/* NOTREACHED */ | |||
} | } | ||
return(r); | return(r); | ||
} | } | ||
#ifdef USE_WCHAR | const char * | ||
/* ARGSUSED */ | ascii_uc2str(int uc) | ||
{ | |||
static const char nbrsp[2] = { ASCII_NBRSP, '\0' }; | |||
static const char *tab[] = { | |||
"<NUL>","<SOH>","<STX>","<ETX>","<EOT>","<ENQ>","<ACK>","<BEL>", | |||
"<BS>", "\t", "<LF>", "<VT>", "<FF>", "<CR>", "<SO>", "<SI>", | |||
"<DLE>","<DC1>","<DC2>","<DC3>","<DC4>","<NAK>","<SYN>","<ETB>", | |||
"<CAN>","<EM>", "<SUB>","<ESC>","<FS>", "<GS>", "<RS>", "<US>", | |||
" ", "!", "\"", "#", "$", "%", "&", "'", | |||
"(", ")", "*", "+", ",", "-", ".", "/", | |||
"0", "1", "2", "3", "4", "5", "6", "7", | |||
"8", "9", ":", ";", "<", "=", ">", "?", | |||
"@", "A", "B", "C", "D", "E", "F", "G", | |||
"H", "I", "J", "K", "L", "M", "N", "O", | |||
"P", "Q", "R", "S", "T", "U", "V", "W", | |||
"X", "Y", "Z", "[", "\\", "]", "^", "_", | |||
"`", "a", "b", "c", "d", "e", "f", "g", | |||
"h", "i", "j", "k", "l", "m", "n", "o", | |||
"p", "q", "r", "s", "t", "u", "v", "w", | |||
"x", "y", "z", "{", "|", "}", "~", "<DEL>", | |||
"<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>", | |||
"\"", "(C)", "_\ba", "<<", "~", "", "(R)", "-", | |||
"<deg>","+-", "2", "3", "'", ",\bu", "<par>",".", | |||
",", "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", | |||
"/\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","-:-", | |||
"/\bo", "`\bu", "'\bu", "^\bu", "\"\bu","'\by", "th", "\"\by", | |||
"A", "a", "A", "a", "A", "a", "'\bC", "'\bc", | |||
"^\bC", "^\bc", "C", "c", "C", "c", "D", "d", | |||
"/\bD", "/\bd", "E", "e", "E", "e", "E", "e", | |||
"E", "e", "E", "e", "^\bG", "^\bg", "G", "g", | |||
"G", "g", ",\bG", ",\bg", "^\bH", "^\bh", "/\bH", "/\bh", | |||
"~\bI", "~\bi", "I", "i", "I", "i", "I", "i", | |||
"I", "i", "IJ", "ij", "^\bJ", "^\bj", ",\bK", ",\bk", | |||
"q", "'\bL", "'\bl", ",\bL", ",\bl", "L", "l", "L", | |||
"l", "/\bL", "/\bl", "'\bN", "'\bn", ",\bN", ",\bn", "N", | |||
"n", "'n", "Ng", "ng", "O", "o", "O", "o", | |||
"O", "o", "OE", "oe", "'\bR", "'\br", ",\bR", ",\br", | |||
"R", "r", "'\bS", "'\bs", "^\bS", "^\bs", ",\bS", ",\bs", | |||
"S", "s", ",\bT", ",\bt", "T", "t", "/\bT", "/\bt", | |||
"~\bU", "~\bu", "U", "u", "U", "u", "U", "u", | |||
"U", "u", "U", "u", "^\bW", "^\bw", "^\bY", "^\by", | |||
"\"\bY","'\bZ", "'\bz", "Z", "z", "Z", "z", "s", | |||
"b", "B", "B", "b", "6", "6", "O", "C", | |||
"c", "D", "D", "D", "d", "d", "3", "@", | |||
"E", "F", ",\bf", "G", "G", "hv", "I", "/\bI", | |||
"K", "k", "/\bl", "l", "W", "N", "n", "~\bO", | |||
"O", "o", "OI", "oi", "P", "p", "YR", "2", | |||
"2", "SH", "sh", "t", "T", "t", "T", "U", | |||
"u", "Y", "V", "Y", "y", "/\bZ", "/\bz", "ZH", | |||
"ZH", "zh", "zh", "/\b2", "5", "5", "ts", "w", | |||
"|", "||", "|=", "!", "DZ", "Dz", "dz", "LJ", | |||
"Lj", "lj", "NJ", "Nj", "nj", "A", "a", "I", | |||
"i", "O", "o", "U", "u", "U", "u", "U", | |||
"u", "U", "u", "U", "u", "@", "A", "a", | |||
"A", "a", "AE", "ae", "/\bG", "/\bg", "G", "g", | |||
"K", "k", "O", "o", "O", "o", "ZH", "zh", | |||
"j", "DZ", "Dz", "dz", "'\bG", "'\bg", "HV", "W", | |||
"`\bN", "`\bn", "A", "a", "'\bAE","'\bae","O", "o"}; | |||
if (uc < 0) | |||
return("<?>"); | |||
if ((size_t)uc < sizeof(tab)/sizeof(tab[0])) | |||
return(tab[uc]); | |||
return(mchars_uc2str(uc)); | |||
} | |||
#if HAVE_WCHAR | |||
static size_t | static size_t | ||
locale_width(const struct termp *p, int c) | locale_width(const struct termp *p, int c) | ||
{ | { | ||
int rc; | int rc; | ||
return((rc = wcwidth(c)) < 0 ? 0 : rc); | if (c == ASCII_NBRSP) | ||
c = ' '; | |||
rc = wcwidth(c); | |||
if (rc < 0) | |||
rc = 0; | |||
return(rc); | |||
} | } | ||
/* ARGSUSED */ | |||
static void | static void | ||
locale_advance(struct termp *p, size_t len) | locale_advance(struct termp *p, size_t len) | ||
{ | { | ||
size_t i; | size_t i; | ||
for (i = 0; i < len; i++) | for (i = 0; i < len; i++) | ||
putwchar(L' '); | putwchar(L' '); | ||
} | } | ||
/* ARGSUSED */ | |||
static void | static void | ||
locale_endline(struct termp *p) | locale_endline(struct termp *p) | ||
{ | { | ||
|
|
||
putwchar(L'\n'); | putwchar(L'\n'); | ||
} | } | ||
/* ARGSUSED */ | |||
static void | static void | ||
locale_letter(struct termp *p, int c) | locale_letter(struct termp *p, int c) | ||
{ | { | ||
putwchar(c); | putwchar(c); | ||
} | } | ||
#endif | #endif |