1*c0a657b3Sschwarze /* $OpenBSD: term_ascii.c,v 1.33 2015/07/17 22:35:36 schwarze Exp $ */ 2f95d589eSschwarze /* 3a5e11edeSschwarze * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 42ccd0917Sschwarze * 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 * 102ccd0917Sschwarze * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 11f95d589eSschwarze * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 122ccd0917Sschwarze * 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" 322ccd0917Sschwarze #include "manconf.h" 33f95d589eSschwarze #include "main.h" 34f95d589eSschwarze 352ccd0917Sschwarze static struct termp *ascii_init(enum termenc, const struct mchars *, 362ccd0917Sschwarze const struct manoutput *); 3713a35416Sschwarze static int 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); 4513a35416Sschwarze static void ascii_setwidth(struct termp *, int, int); 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 * 542ccd0917Sschwarze ascii_init(enum termenc enc, const struct mchars *mchars, 552ccd0917Sschwarze 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; 63*c0a657b3Sschwarze p->line = 1; 643ebeb861Sschwarze p->tabwidth = 5; 655281506aSschwarze p->defrmargin = p->lastrmargin = 78; 66c48a0735Sschwarze p->fontq = mandoc_reallocarray(NULL, 67c48a0735Sschwarze (p->fontsz = 8), sizeof(enum termfont)); 68c48a0735Sschwarze p->fontq[0] = p->fontl = TERMFONT_NONE; 693ebeb861Sschwarze 70f95d589eSschwarze p->begin = ascii_begin; 71f95d589eSschwarze p->end = ascii_end; 72769ee804Sschwarze p->hspan = ascii_hspan; 73769ee804Sschwarze p->type = TERMTYPE_CHAR; 74a5e11edeSschwarze 75a5e11edeSschwarze p->enc = TERMENC_ASCII; 76a5e11edeSschwarze p->advance = ascii_advance; 77a5e11edeSschwarze p->endline = ascii_endline; 78a5e11edeSschwarze p->letter = ascii_letter; 795281506aSschwarze p->setwidth = ascii_setwidth; 803ebeb861Sschwarze p->width = ascii_width; 81f95d589eSschwarze 82a5e11edeSschwarze if (TERMENC_ASCII != enc) { 83a5e11edeSschwarze v = TERMENC_LOCALE == enc ? 84a5e11edeSschwarze setlocale(LC_ALL, "") : 8567b9506bSschwarze setlocale(LC_CTYPE, "en_US.UTF-8"); 86a5e11edeSschwarze if (NULL != v && MB_CUR_MAX > 1) { 87a5e11edeSschwarze p->enc = enc; 88a5e11edeSschwarze p->advance = locale_advance; 89a5e11edeSschwarze p->endline = locale_endline; 90a5e11edeSschwarze p->letter = locale_letter; 91a5e11edeSschwarze p->width = locale_width; 92a5e11edeSschwarze } 93a5e11edeSschwarze } 94a5e11edeSschwarze 952ccd0917Sschwarze if (outopts->mdoc) { 96b6695f6fSschwarze p->mdocstyle = 1; 97b6695f6fSschwarze p->defindent = 5; 98f95d589eSschwarze } 992ccd0917Sschwarze if (outopts->indent) 1002ccd0917Sschwarze p->defindent = outopts->indent; 1012ccd0917Sschwarze if (outopts->width) 1022ccd0917Sschwarze p->defrmargin = outopts->width; 1032ccd0917Sschwarze if (outopts->synopsisonly) 1042ccd0917Sschwarze p->synopsisonly = 1; 105f95d589eSschwarze 106f95d589eSschwarze return(p); 107f95d589eSschwarze } 108f95d589eSschwarze 109a5e11edeSschwarze void * 1102ccd0917Sschwarze ascii_alloc(const struct mchars *mchars, const struct manoutput *outopts) 111a5e11edeSschwarze { 112a5e11edeSschwarze 11372f211f7Sschwarze return(ascii_init(TERMENC_ASCII, mchars, outopts)); 114a5e11edeSschwarze } 115a5e11edeSschwarze 116a5e11edeSschwarze void * 1172ccd0917Sschwarze utf8_alloc(const struct mchars *mchars, const struct manoutput *outopts) 118a5e11edeSschwarze { 119a5e11edeSschwarze 12072f211f7Sschwarze return(ascii_init(TERMENC_UTF8, mchars, outopts)); 121a5e11edeSschwarze } 122a5e11edeSschwarze 123a5e11edeSschwarze void * 1242ccd0917Sschwarze locale_alloc(const struct mchars *mchars, const struct manoutput *outopts) 125a5e11edeSschwarze { 126a5e11edeSschwarze 12772f211f7Sschwarze return(ascii_init(TERMENC_LOCALE, mchars, outopts)); 128a5e11edeSschwarze } 129f95d589eSschwarze 1305281506aSschwarze static void 13113a35416Sschwarze ascii_setwidth(struct termp *p, int iop, int width) 1325281506aSschwarze { 1335281506aSschwarze 13413a35416Sschwarze width /= 24; 13510111bf6Sschwarze p->rmargin = p->defrmargin; 13699b0a561Sschwarze if (iop > 0) 13710111bf6Sschwarze p->defrmargin += width; 13899b0a561Sschwarze else if (iop == 0) 13913a35416Sschwarze p->defrmargin = width ? (size_t)width : p->lastrmargin; 14013a35416Sschwarze else if (p->defrmargin > (size_t)width) 14110111bf6Sschwarze p->defrmargin -= width; 14210111bf6Sschwarze else 14399b0a561Sschwarze p->defrmargin = 0; 14410111bf6Sschwarze p->lastrmargin = p->rmargin; 14510111bf6Sschwarze p->rmargin = p->maxrmargin = p->defrmargin; 1465281506aSschwarze } 1475281506aSschwarze 1482b036407Sschwarze void 1492b036407Sschwarze ascii_sepline(void *arg) 1502b036407Sschwarze { 1512b036407Sschwarze struct termp *p; 1522b036407Sschwarze size_t i; 1532b036407Sschwarze 1542b036407Sschwarze p = (struct termp *)arg; 155*c0a657b3Sschwarze p->line += 3; 1562b036407Sschwarze putchar('\n'); 1572b036407Sschwarze for (i = 0; i < p->defrmargin; i++) 1582b036407Sschwarze putchar('-'); 1592b036407Sschwarze putchar('\n'); 1602b036407Sschwarze putchar('\n'); 1612b036407Sschwarze } 1622b036407Sschwarze 1633ebeb861Sschwarze static size_t 164a5e11edeSschwarze ascii_width(const struct termp *p, int c) 1653ebeb861Sschwarze { 1663ebeb861Sschwarze 1673ebeb861Sschwarze return(1); 1683ebeb861Sschwarze } 1693ebeb861Sschwarze 170f95d589eSschwarze void 171f95d589eSschwarze ascii_free(void *arg) 172f95d589eSschwarze { 173f95d589eSschwarze 174f95d589eSschwarze term_free((struct termp *)arg); 175f95d589eSschwarze } 176f95d589eSschwarze 177f95d589eSschwarze static void 178a5e11edeSschwarze ascii_letter(struct termp *p, int c) 179f95d589eSschwarze { 180f95d589eSschwarze 181f95d589eSschwarze putchar(c); 182f95d589eSschwarze } 183f95d589eSschwarze 184f95d589eSschwarze static void 185f95d589eSschwarze ascii_begin(struct termp *p) 186f95d589eSschwarze { 187f95d589eSschwarze 188f95d589eSschwarze (*p->headf)(p, p->argf); 189f95d589eSschwarze } 190f95d589eSschwarze 191f95d589eSschwarze static void 192f95d589eSschwarze ascii_end(struct termp *p) 193f95d589eSschwarze { 194f95d589eSschwarze 195f95d589eSschwarze (*p->footf)(p, p->argf); 196f95d589eSschwarze } 197f95d589eSschwarze 198f95d589eSschwarze static void 199f95d589eSschwarze ascii_endline(struct termp *p) 200f95d589eSschwarze { 201f95d589eSschwarze 202*c0a657b3Sschwarze p->line++; 203f95d589eSschwarze putchar('\n'); 204f95d589eSschwarze } 205f95d589eSschwarze 206f95d589eSschwarze static void 207f95d589eSschwarze ascii_advance(struct termp *p, size_t len) 208f95d589eSschwarze { 209f95d589eSschwarze size_t i; 210f95d589eSschwarze 211f95d589eSschwarze for (i = 0; i < len; i++) 212f95d589eSschwarze putchar(' '); 213f95d589eSschwarze } 214769ee804Sschwarze 21513a35416Sschwarze static int 216769ee804Sschwarze ascii_hspan(const struct termp *p, const struct roffsu *su) 217769ee804Sschwarze { 218769ee804Sschwarze double r; 219769ee804Sschwarze 220769ee804Sschwarze switch (su->unit) { 221d5dc6f2eSschwarze case SCALE_BU: 22213a35416Sschwarze r = su->scale; 223d5dc6f2eSschwarze break; 22449aff9f8Sschwarze case SCALE_CM: 22513a35416Sschwarze r = su->scale * 240.0 / 2.54; 226d5dc6f2eSschwarze break; 227d5dc6f2eSschwarze case SCALE_FS: 22813a35416Sschwarze r = su->scale * 65536.0; 229769ee804Sschwarze break; 23049aff9f8Sschwarze case SCALE_IN: 23113a35416Sschwarze r = su->scale * 240.0; 232769ee804Sschwarze break; 233d5dc6f2eSschwarze case SCALE_MM: 23413a35416Sschwarze r = su->scale * 0.24; 235769ee804Sschwarze break; 23649aff9f8Sschwarze case SCALE_VS: 23713a35416Sschwarze /* FALLTHROUGH */ 23813a35416Sschwarze case SCALE_PC: 23913a35416Sschwarze r = su->scale * 40.0; 24013a35416Sschwarze break; 24113a35416Sschwarze case SCALE_PT: 24213a35416Sschwarze r = su->scale * 10.0 / 3.0; 243769ee804Sschwarze break; 244d5dc6f2eSschwarze case SCALE_EN: 24550825659Sschwarze /* FALLTHROUGH */ 246d5dc6f2eSschwarze case SCALE_EM: 24713a35416Sschwarze r = su->scale * 24.0; 248769ee804Sschwarze break; 2494ffbec5dSschwarze default: 250d5dc6f2eSschwarze abort(); 25150825659Sschwarze /* NOTREACHED */ 252769ee804Sschwarze } 25313a35416Sschwarze return(r > 0.0 ? r + 0.01 : r - 0.01); 254769ee804Sschwarze } 255769ee804Sschwarze 25655f79d48Sschwarze const char * 25755f79d48Sschwarze ascii_uc2str(int uc) 25855f79d48Sschwarze { 25955f79d48Sschwarze static const char nbrsp[2] = { ASCII_NBRSP, '\0' }; 26055f79d48Sschwarze static const char *tab[] = { 26155f79d48Sschwarze "<NUL>","<SOH>","<STX>","<ETX>","<EOT>","<ENQ>","<ACK>","<BEL>", 26255f79d48Sschwarze "<BS>", "\t", "<LF>", "<VT>", "<FF>", "<CR>", "<SO>", "<SI>", 26355f79d48Sschwarze "<DLE>","<DC1>","<DC2>","<DC3>","<DC4>","<NAK>","<SYN>","<ETB>", 26455f79d48Sschwarze "<CAN>","<EM>", "<SUB>","<ESC>","<FS>", "<GS>", "<RS>", "<US>", 26555f79d48Sschwarze " ", "!", "\"", "#", "$", "%", "&", "'", 26655f79d48Sschwarze "(", ")", "*", "+", ",", "-", ".", "/", 26755f79d48Sschwarze "0", "1", "2", "3", "4", "5", "6", "7", 26855f79d48Sschwarze "8", "9", ":", ";", "<", "=", ">", "?", 26955f79d48Sschwarze "@", "A", "B", "C", "D", "E", "F", "G", 27055f79d48Sschwarze "H", "I", "J", "K", "L", "M", "N", "O", 27155f79d48Sschwarze "P", "Q", "R", "S", "T", "U", "V", "W", 27255f79d48Sschwarze "X", "Y", "Z", "[", "\\", "]", "^", "_", 27355f79d48Sschwarze "`", "a", "b", "c", "d", "e", "f", "g", 27455f79d48Sschwarze "h", "i", "j", "k", "l", "m", "n", "o", 27555f79d48Sschwarze "p", "q", "r", "s", "t", "u", "v", "w", 27655f79d48Sschwarze "x", "y", "z", "{", "|", "}", "~", "<DEL>", 27755f79d48Sschwarze "<80>", "<81>", "<82>", "<83>", "<84>", "<85>", "<86>", "<87>", 27855f79d48Sschwarze "<88>", "<89>", "<8A>", "<8B>", "<8C>", "<8D>", "<8E>", "<8F>", 27955f79d48Sschwarze "<90>", "<91>", "<92>", "<93>", "<94>", "<95>", "<96>", "<97>", 28055f79d48Sschwarze "<99>", "<99>", "<9A>", "<9B>", "<9C>", "<9D>", "<9E>", "<9F>", 281d8d0d815Sschwarze nbrsp, "!", "/\bc", "GBP", "o\bx", "=\bY", "|", "<sec>", 282d8d0d815Sschwarze "\"", "(C)", "_\ba", "<<", "~", "", "(R)", "-", 283d8d0d815Sschwarze "<deg>","+-", "2", "3", "'", ",\bu", "<par>",".", 284d8d0d815Sschwarze ",", "1", "_\bo", ">>", "1/4", "1/2", "3/4", "?", 285d8d0d815Sschwarze "`\bA", "'\bA", "^\bA", "~\bA", "\"\bA","o\bA", "AE", ",\bC", 286d8d0d815Sschwarze "`\bE", "'\bE", "^\bE", "\"\bE","`\bI", "'\bI", "^\bI", "\"\bI", 287d8d0d815Sschwarze "-\bD", "~\bN", "`\bO", "'\bO", "^\bO", "~\bO", "\"\bO","x", 288d8d0d815Sschwarze "/\bO", "`\bU", "'\bU", "^\bU", "\"\bU","'\bY", "Th", "ss", 289d8d0d815Sschwarze "`\ba", "'\ba", "^\ba", "~\ba", "\"\ba","o\ba", "ae", ",\bc", 290d8d0d815Sschwarze "`\be", "'\be", "^\be", "\"\be","`\bi", "'\bi", "^\bi", "\"\bi", 291d8d0d815Sschwarze "d", "~\bn", "`\bo", "'\bo", "^\bo", "~\bo", "\"\bo","-:-", 292d8d0d815Sschwarze "/\bo", "`\bu", "'\bu", "^\bu", "\"\bu","'\by", "th", "\"\by", 293d8d0d815Sschwarze "A", "a", "A", "a", "A", "a", "'\bC", "'\bc", 294d8d0d815Sschwarze "^\bC", "^\bc", "C", "c", "C", "c", "D", "d", 295d8d0d815Sschwarze "/\bD", "/\bd", "E", "e", "E", "e", "E", "e", 296d8d0d815Sschwarze "E", "e", "E", "e", "^\bG", "^\bg", "G", "g", 297d8d0d815Sschwarze "G", "g", ",\bG", ",\bg", "^\bH", "^\bh", "/\bH", "/\bh", 298d8d0d815Sschwarze "~\bI", "~\bi", "I", "i", "I", "i", "I", "i", 299d8d0d815Sschwarze "I", "i", "IJ", "ij", "^\bJ", "^\bj", ",\bK", ",\bk", 300d8d0d815Sschwarze "q", "'\bL", "'\bl", ",\bL", ",\bl", "L", "l", "L", 301d8d0d815Sschwarze "l", "/\bL", "/\bl", "'\bN", "'\bn", ",\bN", ",\bn", "N", 30255f79d48Sschwarze "n", "'n", "Ng", "ng", "O", "o", "O", "o", 303d8d0d815Sschwarze "O", "o", "OE", "oe", "'\bR", "'\br", ",\bR", ",\br", 304d8d0d815Sschwarze "R", "r", "'\bS", "'\bs", "^\bS", "^\bs", ",\bS", ",\bs", 305d8d0d815Sschwarze "S", "s", ",\bT", ",\bt", "T", "t", "/\bT", "/\bt", 306d8d0d815Sschwarze "~\bU", "~\bu", "U", "u", "U", "u", "U", "u", 307d8d0d815Sschwarze "U", "u", "U", "u", "^\bW", "^\bw", "^\bY", "^\by", 308d8d0d815Sschwarze "\"\bY","'\bZ", "'\bz", "Z", "z", "Z", "z", "s", 30955f79d48Sschwarze "b", "B", "B", "b", "6", "6", "O", "C", 31055f79d48Sschwarze "c", "D", "D", "D", "d", "d", "3", "@", 311d8d0d815Sschwarze "E", "F", ",\bf", "G", "G", "hv", "I", "/\bI", 312d8d0d815Sschwarze "K", "k", "/\bl", "l", "W", "N", "n", "~\bO", 31355f79d48Sschwarze "O", "o", "OI", "oi", "P", "p", "YR", "2", 31455f79d48Sschwarze "2", "SH", "sh", "t", "T", "t", "T", "U", 315d8d0d815Sschwarze "u", "Y", "V", "Y", "y", "/\bZ", "/\bz", "ZH", 316d8d0d815Sschwarze "ZH", "zh", "zh", "/\b2", "5", "5", "ts", "w", 31755f79d48Sschwarze "|", "||", "|=", "!", "DZ", "Dz", "dz", "LJ", 31855f79d48Sschwarze "Lj", "lj", "NJ", "Nj", "nj", "A", "a", "I", 31955f79d48Sschwarze "i", "O", "o", "U", "u", "U", "u", "U", 32055f79d48Sschwarze "u", "U", "u", "U", "u", "@", "A", "a", 321d8d0d815Sschwarze "A", "a", "AE", "ae", "/\bG", "/\bg", "G", "g", 32255f79d48Sschwarze "K", "k", "O", "o", "O", "o", "ZH", "zh", 323d8d0d815Sschwarze "j", "DZ", "Dz", "dz", "'\bG", "'\bg", "HV", "W", 324d8d0d815Sschwarze "`\bN", "`\bn", "A", "a", "'\bAE","'\bae","O", "o"}; 32555f79d48Sschwarze 3266899db98Sschwarze assert(uc >= 0); 327ed5ebdbaSschwarze if ((size_t)uc < sizeof(tab)/sizeof(tab[0])) 32855f79d48Sschwarze return(tab[uc]); 329ed5ebdbaSschwarze return(mchars_uc2str(uc)); 33055f79d48Sschwarze } 33155f79d48Sschwarze 332a5e11edeSschwarze static size_t 333a5e11edeSschwarze locale_width(const struct termp *p, int c) 334a5e11edeSschwarze { 335a5e11edeSschwarze int rc; 336a5e11edeSschwarze 337c9fd5525Sschwarze if (c == ASCII_NBRSP) 338c9fd5525Sschwarze c = ' '; 339c9fd5525Sschwarze rc = wcwidth(c); 340c9fd5525Sschwarze if (rc < 0) 341c9fd5525Sschwarze rc = 0; 342c9fd5525Sschwarze return(rc); 343a5e11edeSschwarze } 344a5e11edeSschwarze 345a5e11edeSschwarze static void 346a5e11edeSschwarze locale_advance(struct termp *p, size_t len) 347a5e11edeSschwarze { 348a5e11edeSschwarze size_t i; 349a5e11edeSschwarze 350a5e11edeSschwarze for (i = 0; i < len; i++) 351a5e11edeSschwarze putwchar(L' '); 352a5e11edeSschwarze } 353a5e11edeSschwarze 354a5e11edeSschwarze static void 355a5e11edeSschwarze locale_endline(struct termp *p) 356a5e11edeSschwarze { 357a5e11edeSschwarze 358*c0a657b3Sschwarze p->line++; 359a5e11edeSschwarze putwchar(L'\n'); 360a5e11edeSschwarze } 361a5e11edeSschwarze 362a5e11edeSschwarze static void 363a5e11edeSschwarze locale_letter(struct termp *p, int c) 364a5e11edeSschwarze { 365a5e11edeSschwarze 366a5e11edeSschwarze putwchar(c); 367a5e11edeSschwarze } 368