Annotation of src/usr.bin/mandoc/term_ascii.c, Revision 1.20
1.20 ! schwarze 1: /* $Id: term_ascii.c,v 1.19 2014/08/17 22:06:49 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.8 schwarze 53: const char *toks[4];
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";
90: toks[3] = NULL;
1.1 schwarze 91:
92: while (outopts && *outopts)
93: switch (getsubopt(&outopts, UNCONST(toks), &v)) {
1.14 schwarze 94: case 0:
1.7 schwarze 95: p->defindent = (size_t)atoi(v);
96: break;
1.14 schwarze 97: case 1:
1.1 schwarze 98: p->defrmargin = (size_t)atoi(v);
1.8 schwarze 99: break;
1.14 schwarze 100: case 2:
1.9 schwarze 101: /*
102: * Temporary, undocumented mode
103: * to imitate mdoc(7) output style.
104: */
1.8 schwarze 105: p->mdocstyle = 1;
106: p->defindent = 5;
1.1 schwarze 107: break;
108: default:
109: break;
110: }
111:
112: /* Enforce a lower boundary. */
113: if (p->defrmargin < 58)
114: p->defrmargin = 58;
115:
116: return(p);
1.2 schwarze 117: }
118:
1.6 schwarze 119: void *
120: ascii_alloc(char *outopts)
121: {
122:
123: return(ascii_init(TERMENC_ASCII, outopts));
124: }
125:
126: void *
127: utf8_alloc(char *outopts)
128: {
129:
130: return(ascii_init(TERMENC_UTF8, outopts));
131: }
132:
133: void *
134: locale_alloc(char *outopts)
135: {
136:
137: return(ascii_init(TERMENC_LOCALE, outopts));
1.12 schwarze 138: }
139:
140: static void
1.13 schwarze 141: ascii_setwidth(struct termp *p, int iop, size_t width)
1.12 schwarze 142: {
143:
1.13 schwarze 144: p->rmargin = p->defrmargin;
145: if (0 < iop)
146: p->defrmargin += width;
147: else if (0 > iop)
148: p->defrmargin -= width;
149: else
150: p->defrmargin = width ? width : p->lastrmargin;
151: p->lastrmargin = p->rmargin;
152: p->rmargin = p->maxrmargin = p->defrmargin;
1.6 schwarze 153: }
1.2 schwarze 154:
155: static size_t
1.6 schwarze 156: ascii_width(const struct termp *p, int c)
1.2 schwarze 157: {
158:
159: return(1);
1.1 schwarze 160: }
161:
162: void
163: ascii_free(void *arg)
164: {
165:
166: term_free((struct termp *)arg);
167: }
168:
169: static void
1.6 schwarze 170: ascii_letter(struct termp *p, int c)
1.1 schwarze 171: {
1.14 schwarze 172:
1.1 schwarze 173: putchar(c);
174: }
175:
176: static void
177: ascii_begin(struct termp *p)
178: {
179:
180: (*p->headf)(p, p->argf);
181: }
182:
183: static void
184: ascii_end(struct termp *p)
185: {
186:
187: (*p->footf)(p, p->argf);
188: }
189:
190: static void
191: ascii_endline(struct termp *p)
192: {
193:
194: putchar('\n');
195: }
196:
197: static void
198: ascii_advance(struct termp *p, size_t len)
199: {
1.14 schwarze 200: size_t i;
1.1 schwarze 201:
202: for (i = 0; i < len; i++)
203: putchar(' ');
204: }
1.3 schwarze 205:
206: static double
207: ascii_hspan(const struct termp *p, const struct roffsu *su)
208: {
209: double r;
210:
211: /*
1.17 schwarze 212: * Approximate based on character width.
213: * None of these will be actually correct given that an inch on
214: * the screen depends on character size, terminal, etc., etc.
1.3 schwarze 215: */
216: switch (su->unit) {
1.17 schwarze 217: case SCALE_BU:
218: r = su->scale * 10.0 / 240.0;
219: break;
1.14 schwarze 220: case SCALE_CM:
1.17 schwarze 221: r = su->scale * 10.0 / 2.54;
222: break;
223: case SCALE_FS:
224: r = su->scale * 2730.666;
1.3 schwarze 225: break;
1.14 schwarze 226: case SCALE_IN:
1.16 schwarze 227: r = su->scale * 10.0;
1.3 schwarze 228: break;
1.17 schwarze 229: case SCALE_MM:
230: r = su->scale / 100.0;
231: break;
1.14 schwarze 232: case SCALE_PC:
1.17 schwarze 233: r = su->scale * 10.0 / 6.0;
1.3 schwarze 234: break;
1.14 schwarze 235: case SCALE_PT:
1.17 schwarze 236: r = su->scale * 10.0 / 72.0;
1.3 schwarze 237: break;
1.14 schwarze 238: case SCALE_VS:
1.16 schwarze 239: r = su->scale * 2.0 - 1.0;
1.3 schwarze 240: break;
1.17 schwarze 241: case SCALE_EN:
1.18 schwarze 242: /* FALLTHROUGH */
1.17 schwarze 243: case SCALE_EM:
1.3 schwarze 244: r = su->scale;
1.17 schwarze 245: break;
1.20 ! schwarze 246: default:
1.17 schwarze 247: abort();
1.18 schwarze 248: /* NOTREACHED */
1.3 schwarze 249: }
250:
251: return(r);
252: }
253:
1.6 schwarze 254: static size_t
255: locale_width(const struct termp *p, int c)
256: {
257: int rc;
258:
1.15 schwarze 259: if (c == ASCII_NBRSP)
260: c = ' ';
261: rc = wcwidth(c);
262: if (rc < 0)
263: rc = 0;
264: return(rc);
1.6 schwarze 265: }
266:
267: static void
268: locale_advance(struct termp *p, size_t len)
269: {
1.14 schwarze 270: size_t i;
1.6 schwarze 271:
272: for (i = 0; i < len; i++)
273: putwchar(L' ');
274: }
275:
276: static void
277: locale_endline(struct termp *p)
278: {
279:
280: putwchar(L'\n');
281: }
282:
283: static void
284: locale_letter(struct termp *p, int c)
285: {
1.14 schwarze 286:
1.6 schwarze 287: putwchar(c);
288: }