Annotation of src/usr.bin/mandoc/term_ascii.c, Revision 1.22
1.22 ! schwarze 1: /* $OpenBSD: term_ascii.c,v 1.21 2014/09/03 05:17:08 schwarze Exp $ */
1.1 schwarze 2: /*
1.6 schwarze 3: * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
1.12 schwarze 4: * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
1.1 schwarze 5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18: #include <sys/types.h>
19:
1.6 schwarze 20: #include <locale.h>
1.1 schwarze 21: #include <stdint.h>
22: #include <stdio.h>
23: #include <stdlib.h>
24: #include <unistd.h>
1.6 schwarze 25: #include <wchar.h>
1.1 schwarze 26:
1.4 schwarze 27: #include "mandoc.h"
1.11 schwarze 28: #include "mandoc_aux.h"
1.1 schwarze 29: #include "out.h"
30: #include "term.h"
31: #include "main.h"
32:
1.6 schwarze 33: static struct termp *ascii_init(enum termenc, char *);
1.3 schwarze 34: static double ascii_hspan(const struct termp *,
35: const struct roffsu *);
1.6 schwarze 36: static size_t ascii_width(const struct termp *, int);
1.3 schwarze 37: static void ascii_advance(struct termp *, size_t);
38: static void ascii_begin(struct termp *);
39: static void ascii_end(struct termp *);
1.1 schwarze 40: static void ascii_endline(struct termp *);
1.6 schwarze 41: static void ascii_letter(struct termp *, int);
1.13 schwarze 42: static void ascii_setwidth(struct termp *, int, size_t);
1.1 schwarze 43:
1.6 schwarze 44: static void locale_advance(struct termp *, size_t);
45: static void locale_endline(struct termp *);
46: static void locale_letter(struct termp *, int);
47: static size_t locale_width(const struct termp *, int);
1.1 schwarze 48:
1.14 schwarze 49:
1.6 schwarze 50: static struct termp *
51: ascii_init(enum termenc enc, char *outopts)
1.1 schwarze 52: {
1.21 schwarze 53: const char *toks[5];
1.1 schwarze 54: char *v;
1.6 schwarze 55: struct termp *p;
1.1 schwarze 56:
1.6 schwarze 57: p = mandoc_calloc(1, sizeof(struct termp));
1.1 schwarze 58:
1.2 schwarze 59: p->tabwidth = 5;
1.12 schwarze 60: p->defrmargin = p->lastrmargin = 78;
1.2 schwarze 61:
1.1 schwarze 62: p->begin = ascii_begin;
63: p->end = ascii_end;
1.6 schwarze 64: p->hspan = ascii_hspan;
65: p->type = TERMTYPE_CHAR;
66:
67: p->enc = TERMENC_ASCII;
68: p->advance = ascii_advance;
1.1 schwarze 69: p->endline = ascii_endline;
1.3 schwarze 70: p->letter = ascii_letter;
1.12 schwarze 71: p->setwidth = ascii_setwidth;
1.2 schwarze 72: p->width = ascii_width;
1.1 schwarze 73:
1.6 schwarze 74: if (TERMENC_ASCII != enc) {
75: v = TERMENC_LOCALE == enc ?
1.14 schwarze 76: setlocale(LC_ALL, "") :
77: setlocale(LC_CTYPE, "en_US.UTF-8");
1.6 schwarze 78: if (NULL != v && MB_CUR_MAX > 1) {
79: p->enc = enc;
80: p->advance = locale_advance;
81: p->endline = locale_endline;
82: p->letter = locale_letter;
83: p->width = locale_width;
84: }
85: }
86:
1.7 schwarze 87: toks[0] = "indent";
88: toks[1] = "width";
1.8 schwarze 89: toks[2] = "mdoc";
1.21 schwarze 90: toks[3] = "synopsis";
91: toks[4] = NULL;
1.1 schwarze 92:
93: while (outopts && *outopts)
94: switch (getsubopt(&outopts, UNCONST(toks), &v)) {
1.14 schwarze 95: case 0:
1.7 schwarze 96: p->defindent = (size_t)atoi(v);
97: break;
1.14 schwarze 98: case 1:
1.1 schwarze 99: p->defrmargin = (size_t)atoi(v);
1.8 schwarze 100: break;
1.14 schwarze 101: case 2:
1.9 schwarze 102: /*
103: * Temporary, undocumented mode
104: * to imitate mdoc(7) output style.
105: */
1.8 schwarze 106: p->mdocstyle = 1;
107: p->defindent = 5;
1.21 schwarze 108: break;
109: case 3:
110: p->synopsisonly = 1;
1.1 schwarze 111: break;
112: default:
113: break;
114: }
115:
116: /* Enforce a lower boundary. */
117: if (p->defrmargin < 58)
118: p->defrmargin = 58;
119:
120: return(p);
1.2 schwarze 121: }
122:
1.6 schwarze 123: void *
124: ascii_alloc(char *outopts)
125: {
126:
127: return(ascii_init(TERMENC_ASCII, outopts));
128: }
129:
130: void *
131: utf8_alloc(char *outopts)
132: {
133:
134: return(ascii_init(TERMENC_UTF8, outopts));
135: }
136:
137: void *
138: locale_alloc(char *outopts)
139: {
140:
141: return(ascii_init(TERMENC_LOCALE, outopts));
1.12 schwarze 142: }
143:
144: static void
1.13 schwarze 145: ascii_setwidth(struct termp *p, int iop, size_t width)
1.12 schwarze 146: {
147:
1.13 schwarze 148: p->rmargin = p->defrmargin;
149: if (0 < iop)
150: p->defrmargin += width;
151: else if (0 > iop)
152: p->defrmargin -= width;
153: else
154: p->defrmargin = width ? width : p->lastrmargin;
155: p->lastrmargin = p->rmargin;
156: p->rmargin = p->maxrmargin = p->defrmargin;
1.6 schwarze 157: }
1.2 schwarze 158:
159: static size_t
1.6 schwarze 160: ascii_width(const struct termp *p, int c)
1.2 schwarze 161: {
162:
163: return(1);
1.1 schwarze 164: }
165:
166: void
167: ascii_free(void *arg)
168: {
169:
170: term_free((struct termp *)arg);
171: }
172:
173: static void
1.6 schwarze 174: ascii_letter(struct termp *p, int c)
1.1 schwarze 175: {
1.14 schwarze 176:
1.1 schwarze 177: putchar(c);
178: }
179:
180: static void
181: ascii_begin(struct termp *p)
182: {
183:
184: (*p->headf)(p, p->argf);
185: }
186:
187: static void
188: ascii_end(struct termp *p)
189: {
190:
191: (*p->footf)(p, p->argf);
192: }
193:
194: static void
195: ascii_endline(struct termp *p)
196: {
197:
198: putchar('\n');
199: }
200:
201: static void
202: ascii_advance(struct termp *p, size_t len)
203: {
1.14 schwarze 204: size_t i;
1.1 schwarze 205:
206: for (i = 0; i < len; i++)
207: putchar(' ');
208: }
1.3 schwarze 209:
210: static double
211: ascii_hspan(const struct termp *p, const struct roffsu *su)
212: {
213: double r;
214:
215: /*
1.17 schwarze 216: * Approximate based on character width.
217: * None of these will be actually correct given that an inch on
218: * the screen depends on character size, terminal, etc., etc.
1.3 schwarze 219: */
220: switch (su->unit) {
1.17 schwarze 221: case SCALE_BU:
222: r = su->scale * 10.0 / 240.0;
223: break;
1.14 schwarze 224: case SCALE_CM:
1.17 schwarze 225: r = su->scale * 10.0 / 2.54;
226: break;
227: case SCALE_FS:
228: r = su->scale * 2730.666;
1.3 schwarze 229: break;
1.14 schwarze 230: case SCALE_IN:
1.16 schwarze 231: r = su->scale * 10.0;
1.3 schwarze 232: break;
1.17 schwarze 233: case SCALE_MM:
234: r = su->scale / 100.0;
235: break;
1.14 schwarze 236: case SCALE_PC:
1.17 schwarze 237: r = su->scale * 10.0 / 6.0;
1.3 schwarze 238: break;
1.14 schwarze 239: case SCALE_PT:
1.17 schwarze 240: r = su->scale * 10.0 / 72.0;
1.3 schwarze 241: break;
1.14 schwarze 242: case SCALE_VS:
1.16 schwarze 243: r = su->scale * 2.0 - 1.0;
1.3 schwarze 244: break;
1.17 schwarze 245: case SCALE_EN:
1.18 schwarze 246: /* FALLTHROUGH */
1.17 schwarze 247: case SCALE_EM:
1.3 schwarze 248: r = su->scale;
1.17 schwarze 249: break;
1.20 schwarze 250: default:
1.17 schwarze 251: abort();
1.18 schwarze 252: /* NOTREACHED */
1.3 schwarze 253: }
254:
255: return(r);
1.22 ! schwarze 256: }
! 257:
! 258: const char *
! 259: ascii_uc2str(int uc)
! 260: {
! 261: static const char nbrsp[2] = { ASCII_NBRSP, '\0' };
! 262: static const char *tab[] = {
! 263: "<NUL>","<SOH>","<STX>","<ETX>","<EOT>","<ENQ>","<ACK>","<BEL>",
! 264: "<BS>", "\t", "<LF>", "<VT>", "<FF>", "<CR>", "<SO>", "<SI>",
! 265: "<DLE>","<DC1>","<DC2>","<DC3>","<DC4>","<NAK>","<SYN>","<ETB>",
! 266: "<CAN>","<EM>", "<SUB>","<ESC>","<FS>", "<GS>", "<RS>", "<US>",
! 267: " ", "!", "\"", "#", "$", "%", "&", "'",
! 268: "(", ")", "*", "+", ",", "-", ".", "/",
! 269: "0", "1", "2", "3", "4", "5", "6", "7",
! 270: "8", "9", ":", ";", "<", "=", ">", "?",
! 271: "@", "A", "B", "C", "D", "E", "F", "G",
! 272: "H", "I", "J", "K", "L", "M", "N", "O",
! 273: "P", "Q", "R", "S", "T", "U", "V", "W",
! 274: "X", "Y", "Z", "[", "\\", "]", "^", "_",
! 275: "`", "a", "b", "c", "d", "e", "f", "g",
! 276: "h", "i", "j", "k", "l", "m", "n", "o",
! 277: "p", "q", "r", "s", "t", "u", "v", "w",
! 278: "x", "y", "z", "{", "|", "}", "~", "<DEL>",
! 279: "<80>", "<81>", "<82>", "<83>", "<84>", "<85>", "<86>", "<87>",
! 280: "<88>", "<89>", "<8A>", "<8B>", "<8C>", "<8D>", "<8E>", "<8F>",
! 281: "<90>", "<91>", "<92>", "<93>", "<94>", "<95>", "<96>", "<97>",
! 282: "<99>", "<99>", "<9A>", "<9B>", "<9C>", "<9D>", "<9E>", "<9F>",
! 283: nbrsp, "!", "c", "GBP", "$?", "Y=", "|", "<sec>",
! 284: "\"", "(C)", "a.", "<<", "<not>","", "(R)", "-",
! 285: "<deg>","+-", "^2", "^3", "'", "<my>", "<par>","*",
! 286: ",", "^1", "o.", ">>", "1/4", "1/2", "3/4", "?",
! 287: "A", "A", "A", "A", "Ae", "Aa", "AE", "C",
! 288: "E", "E", "E", "E", "I", "I", "I", "I",
! 289: "D", "N", "O", "O", "O", "O", "Oe", "*",
! 290: "Oe", "U", "U", "U", "Ue", "Y", "Th", "ss",
! 291: "a", "a", "a", "a", "ae", "aa", "ae", "c",
! 292: "e", "e", "e", "e", "i", "i", "i", "i",
! 293: "d", "n", "o", "o", "o", "o", "oe", "/",
! 294: "oe", "u", "u", "u", "ue", "y", "th", "y",
! 295: "A", "a", "A", "a", "A", "a", "C", "c",
! 296: "C", "c", "C", "c", "C", "c", "D", "d",
! 297: "D", "d", "E", "e", "E", "e", "E", "e",
! 298: "E", "e", "E", "e", "G", "g", "G", "g",
! 299: "G", "g", "G", "g", "H", "h", "H", "h",
! 300: "I", "i", "I", "i", "I", "i", "I", "i",
! 301: "I", "i", "IJ", "ij", "J", "j", "K", "k",
! 302: "q", "L", "l", "L", "l", "L", "l", "L",
! 303: "l", "L", "l", "N", "n", "N", "n", "N",
! 304: "n", "'n", "Ng", "ng", "O", "o", "O", "o",
! 305: "O", "o", "OE", "oe", "R", "r", "R", "r",
! 306: "R", "r", "S", "s", "S", "s", "S", "s",
! 307: "S", "s", "T", "t", "T", "t", "T", "t",
! 308: "U", "u", "U", "u", "U", "u", "U", "u",
! 309: "U", "u", "U", "u", "W", "w", "Y", "y",
! 310: "Y", "Z", "z", "Z", "z", "Z", "z", "s",
! 311: "b", "B", "B", "b", "6", "6", "O", "C",
! 312: "c", "D", "D", "D", "d", "d", "3", "@",
! 313: "E", "F", "f", "G", "G", "hv", "I", "I",
! 314: "K", "k", "l", "l", "W", "N", "n", "O",
! 315: "O", "o", "OI", "oi", "P", "p", "YR", "2",
! 316: "2", "SH", "sh", "t", "T", "t", "T", "U",
! 317: "u", "Y", "V", "Y", "y", "Z", "z", "ZH",
! 318: "ZH", "zh", "zh", "2", "5", "5", "ts", "w",
! 319: "|", "||", "|=", "!", "DZ", "Dz", "dz", "LJ",
! 320: "Lj", "lj", "NJ", "Nj", "nj", "A", "a", "I",
! 321: "i", "O", "o", "U", "u", "U", "u", "U",
! 322: "u", "U", "u", "U", "u", "@", "A", "a",
! 323: "A", "a", "AE", "ae", "G", "g", "G", "g",
! 324: "K", "k", "O", "o", "O", "o", "ZH", "zh",
! 325: "j", "DZ", "D", "dz", "G", "g", "HV", "W",
! 326: "N", "n", "A", "a", "AE", "ae", "O", "o"};
! 327:
! 328: if (uc < 0 || (size_t)uc >= sizeof(tab)/sizeof(tab[0]))
! 329: return("<?>");
! 330: return(tab[uc]);
1.3 schwarze 331: }
332:
1.6 schwarze 333: static size_t
334: locale_width(const struct termp *p, int c)
335: {
336: int rc;
337:
1.15 schwarze 338: if (c == ASCII_NBRSP)
339: c = ' ';
340: rc = wcwidth(c);
341: if (rc < 0)
342: rc = 0;
343: return(rc);
1.6 schwarze 344: }
345:
346: static void
347: locale_advance(struct termp *p, size_t len)
348: {
1.14 schwarze 349: size_t i;
1.6 schwarze 350:
351: for (i = 0; i < len; i++)
352: putwchar(L' ');
353: }
354:
355: static void
356: locale_endline(struct termp *p)
357: {
358:
359: putwchar(L'\n');
360: }
361:
362: static void
363: locale_letter(struct termp *p, int c)
364: {
1.14 schwarze 365:
1.6 schwarze 366: putwchar(c);
367: }