term_ascii.c revision 294113
1294113Sbapt/* $Id: term_ascii.c,v 1.52 2015/11/12 21:50:03 schwarze Exp $ */ 2241675Suqs/* 3241675Suqs * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4294113Sbapt * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> 5241675Suqs * 6241675Suqs * Permission to use, copy, modify, and distribute this software for any 7241675Suqs * purpose with or without fee is hereby granted, provided that the above 8241675Suqs * copyright notice and this permission notice appear in all copies. 9241675Suqs * 10294113Sbapt * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 11241675Suqs * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12294113Sbapt * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 13241675Suqs * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14241675Suqs * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15241675Suqs * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16241675Suqs * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17241675Suqs */ 18241675Suqs#include "config.h" 19241675Suqs 20241675Suqs#include <sys/types.h> 21241675Suqs 22275432Sbapt#include <assert.h> 23275432Sbapt#if HAVE_WCHAR 24275432Sbapt#include <locale.h> 25241675Suqs#endif 26241675Suqs#include <stdint.h> 27241675Suqs#include <stdio.h> 28241675Suqs#include <stdlib.h> 29241675Suqs#include <unistd.h> 30275432Sbapt#if HAVE_WCHAR 31275432Sbapt#include <wchar.h> 32241675Suqs#endif 33241675Suqs 34241675Suqs#include "mandoc.h" 35274880Sbapt#include "mandoc_aux.h" 36241675Suqs#include "out.h" 37241675Suqs#include "term.h" 38294113Sbapt#include "manconf.h" 39241675Suqs#include "main.h" 40241675Suqs 41294113Sbaptstatic struct termp *ascii_init(enum termenc, const struct manoutput *); 42294113Sbaptstatic int ascii_hspan(const struct termp *, 43241675Suqs const struct roffsu *); 44241675Suqsstatic size_t ascii_width(const struct termp *, int); 45241675Suqsstatic void ascii_advance(struct termp *, size_t); 46241675Suqsstatic void ascii_begin(struct termp *); 47241675Suqsstatic void ascii_end(struct termp *); 48241675Suqsstatic void ascii_endline(struct termp *); 49241675Suqsstatic void ascii_letter(struct termp *, int); 50294113Sbaptstatic void ascii_setwidth(struct termp *, int, int); 51241675Suqs 52275432Sbapt#if HAVE_WCHAR 53241675Suqsstatic void locale_advance(struct termp *, size_t); 54241675Suqsstatic void locale_endline(struct termp *); 55241675Suqsstatic void locale_letter(struct termp *, int); 56241675Suqsstatic size_t locale_width(const struct termp *, int); 57241675Suqs#endif 58241675Suqs 59274880Sbapt 60241675Suqsstatic struct termp * 61294113Sbaptascii_init(enum termenc enc, const struct manoutput *outopts) 62241675Suqs{ 63294113Sbapt#if HAVE_WCHAR 64241675Suqs char *v; 65294113Sbapt#endif 66241675Suqs struct termp *p; 67241675Suqs 68241675Suqs p = mandoc_calloc(1, sizeof(struct termp)); 69241675Suqs 70294113Sbapt p->line = 1; 71241675Suqs p->tabwidth = 5; 72274880Sbapt p->defrmargin = p->lastrmargin = 78; 73279527Sbapt p->fontq = mandoc_reallocarray(NULL, 74279527Sbapt (p->fontsz = 8), sizeof(enum termfont)); 75279527Sbapt p->fontq[0] = p->fontl = TERMFONT_NONE; 76241675Suqs 77241675Suqs p->begin = ascii_begin; 78241675Suqs p->end = ascii_end; 79241675Suqs p->hspan = ascii_hspan; 80241675Suqs p->type = TERMTYPE_CHAR; 81241675Suqs 82241675Suqs p->enc = TERMENC_ASCII; 83241675Suqs p->advance = ascii_advance; 84241675Suqs p->endline = ascii_endline; 85241675Suqs p->letter = ascii_letter; 86274880Sbapt p->setwidth = ascii_setwidth; 87241675Suqs p->width = ascii_width; 88241675Suqs 89275432Sbapt#if HAVE_WCHAR 90241675Suqs if (TERMENC_ASCII != enc) { 91294113Sbapt 92294113Sbapt /* 93294113Sbapt * Do not change any of this to LC_ALL. It might break 94294113Sbapt * the formatting by subtly changing the behaviour of 95294113Sbapt * various functions, for example strftime(3). As a 96294113Sbapt * worst case, it might even cause buffer overflows. 97294113Sbapt */ 98294113Sbapt 99241675Suqs v = TERMENC_LOCALE == enc ? 100294113Sbapt setlocale(LC_CTYPE, "") : 101274880Sbapt setlocale(LC_CTYPE, "en_US.UTF-8"); 102241675Suqs if (NULL != v && MB_CUR_MAX > 1) { 103241675Suqs p->enc = enc; 104241675Suqs p->advance = locale_advance; 105241675Suqs p->endline = locale_endline; 106241675Suqs p->letter = locale_letter; 107241675Suqs p->width = locale_width; 108241675Suqs } 109241675Suqs } 110241675Suqs#endif 111241675Suqs 112294113Sbapt if (outopts->mdoc) { 113294113Sbapt p->mdocstyle = 1; 114294113Sbapt p->defindent = 5; 115294113Sbapt } 116294113Sbapt if (outopts->indent) 117294113Sbapt p->defindent = outopts->indent; 118294113Sbapt if (outopts->width) 119294113Sbapt p->defrmargin = outopts->width; 120294113Sbapt if (outopts->synopsisonly) 121294113Sbapt p->synopsisonly = 1; 122241675Suqs 123294113Sbapt return p; 124241675Suqs} 125241675Suqs 126241675Suqsvoid * 127294113Sbaptascii_alloc(const struct manoutput *outopts) 128241675Suqs{ 129241675Suqs 130294113Sbapt return ascii_init(TERMENC_ASCII, outopts); 131241675Suqs} 132241675Suqs 133241675Suqsvoid * 134294113Sbaptutf8_alloc(const struct manoutput *outopts) 135241675Suqs{ 136241675Suqs 137294113Sbapt return ascii_init(TERMENC_UTF8, outopts); 138241675Suqs} 139241675Suqs 140241675Suqsvoid * 141294113Sbaptlocale_alloc(const struct manoutput *outopts) 142241675Suqs{ 143241675Suqs 144294113Sbapt return ascii_init(TERMENC_LOCALE, outopts); 145241675Suqs} 146241675Suqs 147274880Sbaptstatic void 148294113Sbaptascii_setwidth(struct termp *p, int iop, int width) 149274880Sbapt{ 150274880Sbapt 151294113Sbapt width /= 24; 152274880Sbapt p->rmargin = p->defrmargin; 153275432Sbapt if (iop > 0) 154274880Sbapt p->defrmargin += width; 155275432Sbapt else if (iop == 0) 156294113Sbapt p->defrmargin = width ? (size_t)width : p->lastrmargin; 157294113Sbapt else if (p->defrmargin > (size_t)width) 158274880Sbapt p->defrmargin -= width; 159274880Sbapt else 160275432Sbapt p->defrmargin = 0; 161274880Sbapt p->lastrmargin = p->rmargin; 162274880Sbapt p->rmargin = p->maxrmargin = p->defrmargin; 163274880Sbapt} 164274880Sbapt 165279527Sbaptvoid 166279527Sbaptascii_sepline(void *arg) 167279527Sbapt{ 168279527Sbapt struct termp *p; 169279527Sbapt size_t i; 170279527Sbapt 171279527Sbapt p = (struct termp *)arg; 172294113Sbapt p->line += 3; 173279527Sbapt putchar('\n'); 174279527Sbapt for (i = 0; i < p->defrmargin; i++) 175279527Sbapt putchar('-'); 176279527Sbapt putchar('\n'); 177279527Sbapt putchar('\n'); 178279527Sbapt} 179279527Sbapt 180241675Suqsstatic size_t 181241675Suqsascii_width(const struct termp *p, int c) 182241675Suqs{ 183241675Suqs 184294113Sbapt return 1; 185241675Suqs} 186241675Suqs 187241675Suqsvoid 188241675Suqsascii_free(void *arg) 189241675Suqs{ 190241675Suqs 191241675Suqs term_free((struct termp *)arg); 192241675Suqs} 193241675Suqs 194241675Suqsstatic void 195241675Suqsascii_letter(struct termp *p, int c) 196241675Suqs{ 197274880Sbapt 198241675Suqs putchar(c); 199241675Suqs} 200241675Suqs 201241675Suqsstatic void 202241675Suqsascii_begin(struct termp *p) 203241675Suqs{ 204241675Suqs 205241675Suqs (*p->headf)(p, p->argf); 206241675Suqs} 207241675Suqs 208241675Suqsstatic void 209241675Suqsascii_end(struct termp *p) 210241675Suqs{ 211241675Suqs 212241675Suqs (*p->footf)(p, p->argf); 213241675Suqs} 214241675Suqs 215241675Suqsstatic void 216241675Suqsascii_endline(struct termp *p) 217241675Suqs{ 218241675Suqs 219294113Sbapt p->line++; 220241675Suqs putchar('\n'); 221241675Suqs} 222241675Suqs 223241675Suqsstatic void 224241675Suqsascii_advance(struct termp *p, size_t len) 225241675Suqs{ 226274880Sbapt size_t i; 227241675Suqs 228241675Suqs for (i = 0; i < len; i++) 229241675Suqs putchar(' '); 230241675Suqs} 231241675Suqs 232294113Sbaptstatic int 233241675Suqsascii_hspan(const struct termp *p, const struct roffsu *su) 234241675Suqs{ 235241675Suqs double r; 236241675Suqs 237241675Suqs switch (su->unit) { 238275432Sbapt case SCALE_BU: 239294113Sbapt r = su->scale; 240275432Sbapt break; 241274880Sbapt case SCALE_CM: 242294113Sbapt r = su->scale * 240.0 / 2.54; 243241675Suqs break; 244275432Sbapt case SCALE_FS: 245294113Sbapt r = su->scale * 65536.0; 246275432Sbapt break; 247274880Sbapt case SCALE_IN: 248294113Sbapt r = su->scale * 240.0; 249241675Suqs break; 250275432Sbapt case SCALE_MM: 251294113Sbapt r = su->scale * 0.24; 252275432Sbapt break; 253294113Sbapt case SCALE_VS: 254274880Sbapt case SCALE_PC: 255294113Sbapt r = su->scale * 40.0; 256241675Suqs break; 257274880Sbapt case SCALE_PT: 258294113Sbapt r = su->scale * 10.0 / 3.0; 259241675Suqs break; 260275432Sbapt case SCALE_EN: 261275432Sbapt case SCALE_EM: 262294113Sbapt r = su->scale * 24.0; 263241675Suqs break; 264275432Sbapt default: 265275432Sbapt abort(); 266241675Suqs } 267294113Sbapt return r > 0.0 ? r + 0.01 : r - 0.01; 268241675Suqs} 269241675Suqs 270275432Sbaptconst char * 271275432Sbaptascii_uc2str(int uc) 272275432Sbapt{ 273275432Sbapt static const char nbrsp[2] = { ASCII_NBRSP, '\0' }; 274275432Sbapt static const char *tab[] = { 275275432Sbapt "<NUL>","<SOH>","<STX>","<ETX>","<EOT>","<ENQ>","<ACK>","<BEL>", 276275432Sbapt "<BS>", "\t", "<LF>", "<VT>", "<FF>", "<CR>", "<SO>", "<SI>", 277275432Sbapt "<DLE>","<DC1>","<DC2>","<DC3>","<DC4>","<NAK>","<SYN>","<ETB>", 278275432Sbapt "<CAN>","<EM>", "<SUB>","<ESC>","<FS>", "<GS>", "<RS>", "<US>", 279275432Sbapt " ", "!", "\"", "#", "$", "%", "&", "'", 280275432Sbapt "(", ")", "*", "+", ",", "-", ".", "/", 281275432Sbapt "0", "1", "2", "3", "4", "5", "6", "7", 282275432Sbapt "8", "9", ":", ";", "<", "=", ">", "?", 283275432Sbapt "@", "A", "B", "C", "D", "E", "F", "G", 284275432Sbapt "H", "I", "J", "K", "L", "M", "N", "O", 285275432Sbapt "P", "Q", "R", "S", "T", "U", "V", "W", 286275432Sbapt "X", "Y", "Z", "[", "\\", "]", "^", "_", 287275432Sbapt "`", "a", "b", "c", "d", "e", "f", "g", 288275432Sbapt "h", "i", "j", "k", "l", "m", "n", "o", 289275432Sbapt "p", "q", "r", "s", "t", "u", "v", "w", 290275432Sbapt "x", "y", "z", "{", "|", "}", "~", "<DEL>", 291275432Sbapt "<80>", "<81>", "<82>", "<83>", "<84>", "<85>", "<86>", "<87>", 292275432Sbapt "<88>", "<89>", "<8A>", "<8B>", "<8C>", "<8D>", "<8E>", "<8F>", 293275432Sbapt "<90>", "<91>", "<92>", "<93>", "<94>", "<95>", "<96>", "<97>", 294275432Sbapt "<99>", "<99>", "<9A>", "<9B>", "<9C>", "<9D>", "<9E>", "<9F>", 295275432Sbapt nbrsp, "!", "/\bc", "GBP", "o\bx", "=\bY", "|", "<sec>", 296275432Sbapt "\"", "(C)", "_\ba", "<<", "~", "", "(R)", "-", 297275432Sbapt "<deg>","+-", "2", "3", "'", ",\bu", "<par>",".", 298275432Sbapt ",", "1", "_\bo", ">>", "1/4", "1/2", "3/4", "?", 299275432Sbapt "`\bA", "'\bA", "^\bA", "~\bA", "\"\bA","o\bA", "AE", ",\bC", 300275432Sbapt "`\bE", "'\bE", "^\bE", "\"\bE","`\bI", "'\bI", "^\bI", "\"\bI", 301275432Sbapt "-\bD", "~\bN", "`\bO", "'\bO", "^\bO", "~\bO", "\"\bO","x", 302275432Sbapt "/\bO", "`\bU", "'\bU", "^\bU", "\"\bU","'\bY", "Th", "ss", 303275432Sbapt "`\ba", "'\ba", "^\ba", "~\ba", "\"\ba","o\ba", "ae", ",\bc", 304275432Sbapt "`\be", "'\be", "^\be", "\"\be","`\bi", "'\bi", "^\bi", "\"\bi", 305275432Sbapt "d", "~\bn", "`\bo", "'\bo", "^\bo", "~\bo", "\"\bo","-:-", 306275432Sbapt "/\bo", "`\bu", "'\bu", "^\bu", "\"\bu","'\by", "th", "\"\by", 307275432Sbapt "A", "a", "A", "a", "A", "a", "'\bC", "'\bc", 308275432Sbapt "^\bC", "^\bc", "C", "c", "C", "c", "D", "d", 309275432Sbapt "/\bD", "/\bd", "E", "e", "E", "e", "E", "e", 310275432Sbapt "E", "e", "E", "e", "^\bG", "^\bg", "G", "g", 311275432Sbapt "G", "g", ",\bG", ",\bg", "^\bH", "^\bh", "/\bH", "/\bh", 312275432Sbapt "~\bI", "~\bi", "I", "i", "I", "i", "I", "i", 313275432Sbapt "I", "i", "IJ", "ij", "^\bJ", "^\bj", ",\bK", ",\bk", 314275432Sbapt "q", "'\bL", "'\bl", ",\bL", ",\bl", "L", "l", "L", 315275432Sbapt "l", "/\bL", "/\bl", "'\bN", "'\bn", ",\bN", ",\bn", "N", 316275432Sbapt "n", "'n", "Ng", "ng", "O", "o", "O", "o", 317275432Sbapt "O", "o", "OE", "oe", "'\bR", "'\br", ",\bR", ",\br", 318275432Sbapt "R", "r", "'\bS", "'\bs", "^\bS", "^\bs", ",\bS", ",\bs", 319275432Sbapt "S", "s", ",\bT", ",\bt", "T", "t", "/\bT", "/\bt", 320275432Sbapt "~\bU", "~\bu", "U", "u", "U", "u", "U", "u", 321275432Sbapt "U", "u", "U", "u", "^\bW", "^\bw", "^\bY", "^\by", 322275432Sbapt "\"\bY","'\bZ", "'\bz", "Z", "z", "Z", "z", "s", 323275432Sbapt "b", "B", "B", "b", "6", "6", "O", "C", 324275432Sbapt "c", "D", "D", "D", "d", "d", "3", "@", 325275432Sbapt "E", "F", ",\bf", "G", "G", "hv", "I", "/\bI", 326275432Sbapt "K", "k", "/\bl", "l", "W", "N", "n", "~\bO", 327275432Sbapt "O", "o", "OI", "oi", "P", "p", "YR", "2", 328275432Sbapt "2", "SH", "sh", "t", "T", "t", "T", "U", 329275432Sbapt "u", "Y", "V", "Y", "y", "/\bZ", "/\bz", "ZH", 330275432Sbapt "ZH", "zh", "zh", "/\b2", "5", "5", "ts", "w", 331275432Sbapt "|", "||", "|=", "!", "DZ", "Dz", "dz", "LJ", 332275432Sbapt "Lj", "lj", "NJ", "Nj", "nj", "A", "a", "I", 333275432Sbapt "i", "O", "o", "U", "u", "U", "u", "U", 334275432Sbapt "u", "U", "u", "U", "u", "@", "A", "a", 335275432Sbapt "A", "a", "AE", "ae", "/\bG", "/\bg", "G", "g", 336275432Sbapt "K", "k", "O", "o", "O", "o", "ZH", "zh", 337275432Sbapt "j", "DZ", "Dz", "dz", "'\bG", "'\bg", "HV", "W", 338275432Sbapt "`\bN", "`\bn", "A", "a", "'\bAE","'\bae","O", "o"}; 339275432Sbapt 340275432Sbapt assert(uc >= 0); 341275432Sbapt if ((size_t)uc < sizeof(tab)/sizeof(tab[0])) 342294113Sbapt return tab[uc]; 343294113Sbapt return mchars_uc2str(uc); 344275432Sbapt} 345275432Sbapt 346275432Sbapt#if HAVE_WCHAR 347241675Suqsstatic size_t 348241675Suqslocale_width(const struct termp *p, int c) 349241675Suqs{ 350241675Suqs int rc; 351241675Suqs 352274880Sbapt if (c == ASCII_NBRSP) 353274880Sbapt c = ' '; 354274880Sbapt rc = wcwidth(c); 355274880Sbapt if (rc < 0) 356274880Sbapt rc = 0; 357294113Sbapt return rc; 358241675Suqs} 359241675Suqs 360241675Suqsstatic void 361241675Suqslocale_advance(struct termp *p, size_t len) 362241675Suqs{ 363274880Sbapt size_t i; 364241675Suqs 365241675Suqs for (i = 0; i < len; i++) 366241675Suqs putwchar(L' '); 367241675Suqs} 368241675Suqs 369241675Suqsstatic void 370241675Suqslocale_endline(struct termp *p) 371241675Suqs{ 372241675Suqs 373294113Sbapt p->line++; 374241675Suqs putwchar(L'\n'); 375241675Suqs} 376241675Suqs 377241675Suqsstatic void 378241675Suqslocale_letter(struct termp *p, int c) 379241675Suqs{ 380274880Sbapt 381241675Suqs putwchar(c); 382241675Suqs} 383241675Suqs#endif 384