1*2ccd0917Sschwarze /* $OpenBSD: term_ascii.c,v 1.31 2015/03/27 21:17:16 schwarze Exp $ */ 2f95d589eSschwarze /* 3a5e11edeSschwarze * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4*2ccd0917Sschwarze * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> 5f95d589eSschwarze * 6f95d589eSschwarze * Permission to use, copy, modify, and distribute this software for any 7f95d589eSschwarze * purpose with or without fee is hereby granted, provided that the above 8f95d589eSschwarze * copyright notice and this permission notice appear in all copies. 9f95d589eSschwarze * 10*2ccd0917Sschwarze * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 11f95d589eSschwarze * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*2ccd0917Sschwarze * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 13f95d589eSschwarze * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14f95d589eSschwarze * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15f95d589eSschwarze * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16f95d589eSschwarze * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17f95d589eSschwarze */ 18f95d589eSschwarze #include <sys/types.h> 19f95d589eSschwarze 206899db98Sschwarze #include <assert.h> 21a5e11edeSschwarze #include <locale.h> 22f95d589eSschwarze #include <stdint.h> 23f95d589eSschwarze #include <stdio.h> 24f95d589eSschwarze #include <stdlib.h> 25f95d589eSschwarze #include <unistd.h> 26a5e11edeSschwarze #include <wchar.h> 27f95d589eSschwarze 282791bd1cSschwarze #include "mandoc.h" 294f4f7972Sschwarze #include "mandoc_aux.h" 30f95d589eSschwarze #include "out.h" 31f95d589eSschwarze #include "term.h" 32*2ccd0917Sschwarze #include "manconf.h" 33f95d589eSschwarze #include "main.h" 34f95d589eSschwarze 35*2ccd0917Sschwarze static struct termp *ascii_init(enum termenc, const struct mchars *, 36*2ccd0917Sschwarze const struct manoutput *); 37769ee804Sschwarze static double ascii_hspan(const struct termp *, 38769ee804Sschwarze const struct roffsu *); 39a5e11edeSschwarze static size_t ascii_width(const struct termp *, int); 40769ee804Sschwarze static void ascii_advance(struct termp *, size_t); 41769ee804Sschwarze static void ascii_begin(struct termp *); 42769ee804Sschwarze static void ascii_end(struct termp *); 43f95d589eSschwarze static void ascii_endline(struct termp *); 44a5e11edeSschwarze static void ascii_letter(struct termp *, int); 4510111bf6Sschwarze static void ascii_setwidth(struct termp *, int, size_t); 46f95d589eSschwarze 47a5e11edeSschwarze static void locale_advance(struct termp *, size_t); 48a5e11edeSschwarze static void locale_endline(struct termp *); 49a5e11edeSschwarze static void locale_letter(struct termp *, int); 50a5e11edeSschwarze static size_t locale_width(const struct termp *, int); 51f95d589eSschwarze 5249aff9f8Sschwarze 53a5e11edeSschwarze static struct termp * 54*2ccd0917Sschwarze ascii_init(enum termenc enc, const struct mchars *mchars, 55*2ccd0917Sschwarze const struct manoutput *outopts) 56f95d589eSschwarze { 57f95d589eSschwarze char *v; 58a5e11edeSschwarze struct termp *p; 59f95d589eSschwarze 60a5e11edeSschwarze p = mandoc_calloc(1, sizeof(struct termp)); 61f95d589eSschwarze 6272f211f7Sschwarze p->symtab = mchars; 633ebeb861Sschwarze p->tabwidth = 5; 645281506aSschwarze p->defrmargin = p->lastrmargin = 78; 65c48a0735Sschwarze p->fontq = mandoc_reallocarray(NULL, 66c48a0735Sschwarze (p->fontsz = 8), sizeof(enum termfont)); 67c48a0735Sschwarze p->fontq[0] = p->fontl = TERMFONT_NONE; 683ebeb861Sschwarze 69f95d589eSschwarze p->begin = ascii_begin; 70f95d589eSschwarze p->end = ascii_end; 71769ee804Sschwarze p->hspan = ascii_hspan; 72769ee804Sschwarze p->type = TERMTYPE_CHAR; 73a5e11edeSschwarze 74a5e11edeSschwarze p->enc = TERMENC_ASCII; 75a5e11edeSschwarze p->advance = ascii_advance; 76a5e11edeSschwarze p->endline = ascii_endline; 77a5e11edeSschwarze p->letter = ascii_letter; 785281506aSschwarze p->setwidth = ascii_setwidth; 793ebeb861Sschwarze p->width = ascii_width; 80f95d589eSschwarze 81a5e11edeSschwarze if (TERMENC_ASCII != enc) { 82a5e11edeSschwarze v = TERMENC_LOCALE == enc ? 83a5e11edeSschwarze setlocale(LC_ALL, "") : 8467b9506bSschwarze setlocale(LC_CTYPE, "en_US.UTF-8"); 85a5e11edeSschwarze if (NULL != v && MB_CUR_MAX > 1) { 86a5e11edeSschwarze p->enc = enc; 87a5e11edeSschwarze p->advance = locale_advance; 88a5e11edeSschwarze p->endline = locale_endline; 89a5e11edeSschwarze p->letter = locale_letter; 90a5e11edeSschwarze p->width = locale_width; 91a5e11edeSschwarze } 92a5e11edeSschwarze } 93a5e11edeSschwarze 94*2ccd0917Sschwarze if (outopts->mdoc) { 95b6695f6fSschwarze p->mdocstyle = 1; 96b6695f6fSschwarze p->defindent = 5; 97f95d589eSschwarze } 98*2ccd0917Sschwarze if (outopts->indent) 99*2ccd0917Sschwarze p->defindent = outopts->indent; 100*2ccd0917Sschwarze if (outopts->width) 101*2ccd0917Sschwarze p->defrmargin = outopts->width; 102*2ccd0917Sschwarze if (outopts->synopsisonly) 103*2ccd0917Sschwarze p->synopsisonly = 1; 104f95d589eSschwarze 105f95d589eSschwarze return(p); 106f95d589eSschwarze } 107f95d589eSschwarze 108a5e11edeSschwarze void * 109*2ccd0917Sschwarze ascii_alloc(const struct mchars *mchars, const struct manoutput *outopts) 110a5e11edeSschwarze { 111a5e11edeSschwarze 11272f211f7Sschwarze return(ascii_init(TERMENC_ASCII, mchars, outopts)); 113a5e11edeSschwarze } 114a5e11edeSschwarze 115a5e11edeSschwarze void * 116*2ccd0917Sschwarze utf8_alloc(const struct mchars *mchars, const struct manoutput *outopts) 117a5e11edeSschwarze { 118a5e11edeSschwarze 11972f211f7Sschwarze return(ascii_init(TERMENC_UTF8, mchars, outopts)); 120a5e11edeSschwarze } 121a5e11edeSschwarze 122a5e11edeSschwarze void * 123*2ccd0917Sschwarze locale_alloc(const struct mchars *mchars, const struct manoutput *outopts) 124a5e11edeSschwarze { 125a5e11edeSschwarze 12672f211f7Sschwarze return(ascii_init(TERMENC_LOCALE, mchars, outopts)); 127a5e11edeSschwarze } 128f95d589eSschwarze 1295281506aSschwarze static void 13010111bf6Sschwarze ascii_setwidth(struct termp *p, int iop, size_t width) 1315281506aSschwarze { 1325281506aSschwarze 13310111bf6Sschwarze p->rmargin = p->defrmargin; 13499b0a561Sschwarze if (iop > 0) 13510111bf6Sschwarze p->defrmargin += width; 13699b0a561Sschwarze else if (iop == 0) 13799b0a561Sschwarze p->defrmargin = width ? width : p->lastrmargin; 13899b0a561Sschwarze else if (p->defrmargin > width) 13910111bf6Sschwarze p->defrmargin -= width; 14010111bf6Sschwarze else 14199b0a561Sschwarze p->defrmargin = 0; 14210111bf6Sschwarze p->lastrmargin = p->rmargin; 14310111bf6Sschwarze p->rmargin = p->maxrmargin = p->defrmargin; 1445281506aSschwarze } 1455281506aSschwarze 1462b036407Sschwarze void 1472b036407Sschwarze ascii_sepline(void *arg) 1482b036407Sschwarze { 1492b036407Sschwarze struct termp *p; 1502b036407Sschwarze size_t i; 1512b036407Sschwarze 1522b036407Sschwarze p = (struct termp *)arg; 1532b036407Sschwarze putchar('\n'); 1542b036407Sschwarze for (i = 0; i < p->defrmargin; i++) 1552b036407Sschwarze putchar('-'); 1562b036407Sschwarze putchar('\n'); 1572b036407Sschwarze putchar('\n'); 1582b036407Sschwarze } 1592b036407Sschwarze 1603ebeb861Sschwarze static size_t 161a5e11edeSschwarze ascii_width(const struct termp *p, int c) 1623ebeb861Sschwarze { 1633ebeb861Sschwarze 1643ebeb861Sschwarze return(1); 1653ebeb861Sschwarze } 1663ebeb861Sschwarze 167f95d589eSschwarze void 168f95d589eSschwarze ascii_free(void *arg) 169f95d589eSschwarze { 170f95d589eSschwarze 171f95d589eSschwarze term_free((struct termp *)arg); 172f95d589eSschwarze } 173f95d589eSschwarze 174f95d589eSschwarze static void 175a5e11edeSschwarze ascii_letter(struct termp *p, int c) 176f95d589eSschwarze { 177f95d589eSschwarze 178f95d589eSschwarze putchar(c); 179f95d589eSschwarze } 180f95d589eSschwarze 181f95d589eSschwarze static void 182f95d589eSschwarze ascii_begin(struct termp *p) 183f95d589eSschwarze { 184f95d589eSschwarze 185f95d589eSschwarze (*p->headf)(p, p->argf); 186f95d589eSschwarze } 187f95d589eSschwarze 188f95d589eSschwarze static void 189f95d589eSschwarze ascii_end(struct termp *p) 190f95d589eSschwarze { 191f95d589eSschwarze 192f95d589eSschwarze (*p->footf)(p, p->argf); 193f95d589eSschwarze } 194f95d589eSschwarze 195f95d589eSschwarze static void 196f95d589eSschwarze ascii_endline(struct termp *p) 197f95d589eSschwarze { 198f95d589eSschwarze 199f95d589eSschwarze putchar('\n'); 200f95d589eSschwarze } 201f95d589eSschwarze 202f95d589eSschwarze static void 203f95d589eSschwarze ascii_advance(struct termp *p, size_t len) 204f95d589eSschwarze { 205f95d589eSschwarze size_t i; 206f95d589eSschwarze 207f95d589eSschwarze for (i = 0; i < len; i++) 208f95d589eSschwarze putchar(' '); 209f95d589eSschwarze } 210769ee804Sschwarze 211769ee804Sschwarze static double 212769ee804Sschwarze ascii_hspan(const struct termp *p, const struct roffsu *su) 213769ee804Sschwarze { 214769ee804Sschwarze double r; 215769ee804Sschwarze 216769ee804Sschwarze /* 217d5dc6f2eSschwarze * Approximate based on character width. 218d5dc6f2eSschwarze * None of these will be actually correct given that an inch on 219d5dc6f2eSschwarze * the screen depends on character size, terminal, etc., etc. 220769ee804Sschwarze */ 221769ee804Sschwarze switch (su->unit) { 222d5dc6f2eSschwarze case SCALE_BU: 223d5dc6f2eSschwarze r = su->scale * 10.0 / 240.0; 224d5dc6f2eSschwarze break; 22549aff9f8Sschwarze case SCALE_CM: 226d5dc6f2eSschwarze r = su->scale * 10.0 / 2.54; 227d5dc6f2eSschwarze break; 228d5dc6f2eSschwarze case SCALE_FS: 229d5dc6f2eSschwarze r = su->scale * 2730.666; 230769ee804Sschwarze break; 23149aff9f8Sschwarze case SCALE_IN: 23253ab8734Sschwarze r = su->scale * 10.0; 233769ee804Sschwarze break; 234d5dc6f2eSschwarze case SCALE_MM: 235d5dc6f2eSschwarze r = su->scale / 100.0; 236d5dc6f2eSschwarze break; 23749aff9f8Sschwarze case SCALE_PC: 238d5dc6f2eSschwarze r = su->scale * 10.0 / 6.0; 239769ee804Sschwarze break; 24049aff9f8Sschwarze case SCALE_PT: 241d5dc6f2eSschwarze r = su->scale * 10.0 / 72.0; 242769ee804Sschwarze break; 24349aff9f8Sschwarze case SCALE_VS: 24453ab8734Sschwarze r = su->scale * 2.0 - 1.0; 245769ee804Sschwarze break; 246d5dc6f2eSschwarze case SCALE_EN: 24750825659Sschwarze /* FALLTHROUGH */ 248d5dc6f2eSschwarze case SCALE_EM: 249769ee804Sschwarze r = su->scale; 250769ee804Sschwarze break; 2514ffbec5dSschwarze default: 252d5dc6f2eSschwarze abort(); 25350825659Sschwarze /* NOTREACHED */ 254769ee804Sschwarze } 255769ee804Sschwarze 256769ee804Sschwarze return(r); 257769ee804Sschwarze } 258769ee804Sschwarze 25955f79d48Sschwarze const char * 26055f79d48Sschwarze ascii_uc2str(int uc) 26155f79d48Sschwarze { 26255f79d48Sschwarze static const char nbrsp[2] = { ASCII_NBRSP, '\0' }; 26355f79d48Sschwarze static const char *tab[] = { 26455f79d48Sschwarze "<NUL>","<SOH>","<STX>","<ETX>","<EOT>","<ENQ>","<ACK>","<BEL>", 26555f79d48Sschwarze "<BS>", "\t", "<LF>", "<VT>", "<FF>", "<CR>", "<SO>", "<SI>", 26655f79d48Sschwarze "<DLE>","<DC1>","<DC2>","<DC3>","<DC4>","<NAK>","<SYN>","<ETB>", 26755f79d48Sschwarze "<CAN>","<EM>", "<SUB>","<ESC>","<FS>", "<GS>", "<RS>", "<US>", 26855f79d48Sschwarze " ", "!", "\"", "#", "$", "%", "&", "'", 26955f79d48Sschwarze "(", ")", "*", "+", ",", "-", ".", "/", 27055f79d48Sschwarze "0", "1", "2", "3", "4", "5", "6", "7", 27155f79d48Sschwarze "8", "9", ":", ";", "<", "=", ">", "?", 27255f79d48Sschwarze "@", "A", "B", "C", "D", "E", "F", "G", 27355f79d48Sschwarze "H", "I", "J", "K", "L", "M", "N", "O", 27455f79d48Sschwarze "P", "Q", "R", "S", "T", "U", "V", "W", 27555f79d48Sschwarze "X", "Y", "Z", "[", "\\", "]", "^", "_", 27655f79d48Sschwarze "`", "a", "b", "c", "d", "e", "f", "g", 27755f79d48Sschwarze "h", "i", "j", "k", "l", "m", "n", "o", 27855f79d48Sschwarze "p", "q", "r", "s", "t", "u", "v", "w", 27955f79d48Sschwarze "x", "y", "z", "{", "|", "}", "~", "<DEL>", 28055f79d48Sschwarze "<80>", "<81>", "<82>", "<83>", "<84>", "<85>", "<86>", "<87>", 28155f79d48Sschwarze "<88>", "<89>", "<8A>", "<8B>", "<8C>", "<8D>", "<8E>", "<8F>", 28255f79d48Sschwarze "<90>", "<91>", "<92>", "<93>", "<94>", "<95>", "<96>", "<97>", 28355f79d48Sschwarze "<99>", "<99>", "<9A>", "<9B>", "<9C>", "<9D>", "<9E>", "<9F>", 284d8d0d815Sschwarze nbrsp, "!", "/\bc", "GBP", "o\bx", "=\bY", "|", "<sec>", 285d8d0d815Sschwarze "\"", "(C)", "_\ba", "<<", "~", "", "(R)", "-", 286d8d0d815Sschwarze "<deg>","+-", "2", "3", "'", ",\bu", "<par>",".", 287d8d0d815Sschwarze ",", "1", "_\bo", ">>", "1/4", "1/2", "3/4", "?", 288d8d0d815Sschwarze "`\bA", "'\bA", "^\bA", "~\bA", "\"\bA","o\bA", "AE", ",\bC", 289d8d0d815Sschwarze "`\bE", "'\bE", "^\bE", "\"\bE","`\bI", "'\bI", "^\bI", "\"\bI", 290d8d0d815Sschwarze "-\bD", "~\bN", "`\bO", "'\bO", "^\bO", "~\bO", "\"\bO","x", 291d8d0d815Sschwarze "/\bO", "`\bU", "'\bU", "^\bU", "\"\bU","'\bY", "Th", "ss", 292d8d0d815Sschwarze "`\ba", "'\ba", "^\ba", "~\ba", "\"\ba","o\ba", "ae", ",\bc", 293d8d0d815Sschwarze "`\be", "'\be", "^\be", "\"\be","`\bi", "'\bi", "^\bi", "\"\bi", 294d8d0d815Sschwarze "d", "~\bn", "`\bo", "'\bo", "^\bo", "~\bo", "\"\bo","-:-", 295d8d0d815Sschwarze "/\bo", "`\bu", "'\bu", "^\bu", "\"\bu","'\by", "th", "\"\by", 296d8d0d815Sschwarze "A", "a", "A", "a", "A", "a", "'\bC", "'\bc", 297d8d0d815Sschwarze "^\bC", "^\bc", "C", "c", "C", "c", "D", "d", 298d8d0d815Sschwarze "/\bD", "/\bd", "E", "e", "E", "e", "E", "e", 299d8d0d815Sschwarze "E", "e", "E", "e", "^\bG", "^\bg", "G", "g", 300d8d0d815Sschwarze "G", "g", ",\bG", ",\bg", "^\bH", "^\bh", "/\bH", "/\bh", 301d8d0d815Sschwarze "~\bI", "~\bi", "I", "i", "I", "i", "I", "i", 302d8d0d815Sschwarze "I", "i", "IJ", "ij", "^\bJ", "^\bj", ",\bK", ",\bk", 303d8d0d815Sschwarze "q", "'\bL", "'\bl", ",\bL", ",\bl", "L", "l", "L", 304d8d0d815Sschwarze "l", "/\bL", "/\bl", "'\bN", "'\bn", ",\bN", ",\bn", "N", 30555f79d48Sschwarze "n", "'n", "Ng", "ng", "O", "o", "O", "o", 306d8d0d815Sschwarze "O", "o", "OE", "oe", "'\bR", "'\br", ",\bR", ",\br", 307d8d0d815Sschwarze "R", "r", "'\bS", "'\bs", "^\bS", "^\bs", ",\bS", ",\bs", 308d8d0d815Sschwarze "S", "s", ",\bT", ",\bt", "T", "t", "/\bT", "/\bt", 309d8d0d815Sschwarze "~\bU", "~\bu", "U", "u", "U", "u", "U", "u", 310d8d0d815Sschwarze "U", "u", "U", "u", "^\bW", "^\bw", "^\bY", "^\by", 311d8d0d815Sschwarze "\"\bY","'\bZ", "'\bz", "Z", "z", "Z", "z", "s", 31255f79d48Sschwarze "b", "B", "B", "b", "6", "6", "O", "C", 31355f79d48Sschwarze "c", "D", "D", "D", "d", "d", "3", "@", 314d8d0d815Sschwarze "E", "F", ",\bf", "G", "G", "hv", "I", "/\bI", 315d8d0d815Sschwarze "K", "k", "/\bl", "l", "W", "N", "n", "~\bO", 31655f79d48Sschwarze "O", "o", "OI", "oi", "P", "p", "YR", "2", 31755f79d48Sschwarze "2", "SH", "sh", "t", "T", "t", "T", "U", 318d8d0d815Sschwarze "u", "Y", "V", "Y", "y", "/\bZ", "/\bz", "ZH", 319d8d0d815Sschwarze "ZH", "zh", "zh", "/\b2", "5", "5", "ts", "w", 32055f79d48Sschwarze "|", "||", "|=", "!", "DZ", "Dz", "dz", "LJ", 32155f79d48Sschwarze "Lj", "lj", "NJ", "Nj", "nj", "A", "a", "I", 32255f79d48Sschwarze "i", "O", "o", "U", "u", "U", "u", "U", 32355f79d48Sschwarze "u", "U", "u", "U", "u", "@", "A", "a", 324d8d0d815Sschwarze "A", "a", "AE", "ae", "/\bG", "/\bg", "G", "g", 32555f79d48Sschwarze "K", "k", "O", "o", "O", "o", "ZH", "zh", 326d8d0d815Sschwarze "j", "DZ", "Dz", "dz", "'\bG", "'\bg", "HV", "W", 327d8d0d815Sschwarze "`\bN", "`\bn", "A", "a", "'\bAE","'\bae","O", "o"}; 32855f79d48Sschwarze 3296899db98Sschwarze assert(uc >= 0); 330ed5ebdbaSschwarze if ((size_t)uc < sizeof(tab)/sizeof(tab[0])) 33155f79d48Sschwarze return(tab[uc]); 332ed5ebdbaSschwarze return(mchars_uc2str(uc)); 33355f79d48Sschwarze } 33455f79d48Sschwarze 335a5e11edeSschwarze static size_t 336a5e11edeSschwarze locale_width(const struct termp *p, int c) 337a5e11edeSschwarze { 338a5e11edeSschwarze int rc; 339a5e11edeSschwarze 340c9fd5525Sschwarze if (c == ASCII_NBRSP) 341c9fd5525Sschwarze c = ' '; 342c9fd5525Sschwarze rc = wcwidth(c); 343c9fd5525Sschwarze if (rc < 0) 344c9fd5525Sschwarze rc = 0; 345c9fd5525Sschwarze return(rc); 346a5e11edeSschwarze } 347a5e11edeSschwarze 348a5e11edeSschwarze static void 349a5e11edeSschwarze locale_advance(struct termp *p, size_t len) 350a5e11edeSschwarze { 351a5e11edeSschwarze size_t i; 352a5e11edeSschwarze 353a5e11edeSschwarze for (i = 0; i < len; i++) 354a5e11edeSschwarze putwchar(L' '); 355a5e11edeSschwarze } 356a5e11edeSschwarze 357a5e11edeSschwarze static void 358a5e11edeSschwarze locale_endline(struct termp *p) 359a5e11edeSschwarze { 360a5e11edeSschwarze 361a5e11edeSschwarze putwchar(L'\n'); 362a5e11edeSschwarze } 363a5e11edeSschwarze 364a5e11edeSschwarze static void 365a5e11edeSschwarze locale_letter(struct termp *p, int c) 366a5e11edeSschwarze { 367a5e11edeSschwarze 368a5e11edeSschwarze putwchar(c); 369a5e11edeSschwarze } 370