1 /* $Id: term_ascii.c,v 1.9 2011/12/05 00:28:12 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 #include <sys/types.h> 18 19 #include <assert.h> 20 #include <locale.h> 21 #include <stdint.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <unistd.h> 25 #include <wchar.h> 26 27 #include "mandoc.h" 28 #include "out.h" 29 #include "term.h" 30 #include "main.h" 31 32 static struct termp *ascii_init(enum termenc, char *); 33 static double ascii_hspan(const struct termp *, 34 const struct roffsu *); 35 static size_t ascii_width(const struct termp *, int); 36 static void ascii_advance(struct termp *, size_t); 37 static void ascii_begin(struct termp *); 38 static void ascii_end(struct termp *); 39 static void ascii_endline(struct termp *); 40 static void ascii_letter(struct termp *, int); 41 42 static void locale_advance(struct termp *, size_t); 43 static void locale_endline(struct termp *); 44 static void locale_letter(struct termp *, int); 45 static size_t locale_width(const struct termp *, int); 46 47 static struct termp * 48 ascii_init(enum termenc enc, char *outopts) 49 { 50 const char *toks[4]; 51 char *v; 52 struct termp *p; 53 54 p = mandoc_calloc(1, sizeof(struct termp)); 55 p->enc = enc; 56 57 p->tabwidth = 5; 58 p->defrmargin = 78; 59 60 p->begin = ascii_begin; 61 p->end = ascii_end; 62 p->hspan = ascii_hspan; 63 p->type = TERMTYPE_CHAR; 64 65 p->enc = TERMENC_ASCII; 66 p->advance = ascii_advance; 67 p->endline = ascii_endline; 68 p->letter = ascii_letter; 69 p->width = ascii_width; 70 71 if (TERMENC_ASCII != enc) { 72 v = TERMENC_LOCALE == enc ? 73 setlocale(LC_ALL, "") : 74 setlocale(LC_CTYPE, "UTF-8"); 75 if (NULL != v && MB_CUR_MAX > 1) { 76 p->enc = enc; 77 p->advance = locale_advance; 78 p->endline = locale_endline; 79 p->letter = locale_letter; 80 p->width = locale_width; 81 } 82 } 83 84 toks[0] = "indent"; 85 toks[1] = "width"; 86 toks[2] = "mdoc"; 87 toks[3] = NULL; 88 89 while (outopts && *outopts) 90 switch (getsubopt(&outopts, UNCONST(toks), &v)) { 91 case (0): 92 p->defindent = (size_t)atoi(v); 93 break; 94 case (1): 95 p->defrmargin = (size_t)atoi(v); 96 break; 97 case (2): 98 /* 99 * Temporary, undocumented mode 100 * to imitate mdoc(7) output style. 101 */ 102 p->mdocstyle = 1; 103 p->defindent = 5; 104 break; 105 default: 106 break; 107 } 108 109 /* Enforce a lower boundary. */ 110 if (p->defrmargin < 58) 111 p->defrmargin = 58; 112 113 return(p); 114 } 115 116 void * 117 ascii_alloc(char *outopts) 118 { 119 120 return(ascii_init(TERMENC_ASCII, outopts)); 121 } 122 123 void * 124 utf8_alloc(char *outopts) 125 { 126 127 return(ascii_init(TERMENC_UTF8, outopts)); 128 } 129 130 131 void * 132 locale_alloc(char *outopts) 133 { 134 135 return(ascii_init(TERMENC_LOCALE, outopts)); 136 } 137 138 /* ARGSUSED */ 139 static size_t 140 ascii_width(const struct termp *p, int c) 141 { 142 143 return(1); 144 } 145 146 void 147 ascii_free(void *arg) 148 { 149 150 term_free((struct termp *)arg); 151 } 152 153 /* ARGSUSED */ 154 static void 155 ascii_letter(struct termp *p, int c) 156 { 157 158 putchar(c); 159 } 160 161 static void 162 ascii_begin(struct termp *p) 163 { 164 165 (*p->headf)(p, p->argf); 166 } 167 168 static void 169 ascii_end(struct termp *p) 170 { 171 172 (*p->footf)(p, p->argf); 173 } 174 175 /* ARGSUSED */ 176 static void 177 ascii_endline(struct termp *p) 178 { 179 180 putchar('\n'); 181 } 182 183 /* ARGSUSED */ 184 static void 185 ascii_advance(struct termp *p, size_t len) 186 { 187 size_t i; 188 189 for (i = 0; i < len; i++) 190 putchar(' '); 191 } 192 193 /* ARGSUSED */ 194 static double 195 ascii_hspan(const struct termp *p, const struct roffsu *su) 196 { 197 double r; 198 199 /* 200 * Approximate based on character width. These are generated 201 * entirely by eyeballing the screen, but appear to be correct. 202 */ 203 204 switch (su->unit) { 205 case (SCALE_CM): 206 r = 4 * su->scale; 207 break; 208 case (SCALE_IN): 209 r = 10 * su->scale; 210 break; 211 case (SCALE_PC): 212 r = (10 * su->scale) / 6; 213 break; 214 case (SCALE_PT): 215 r = (10 * su->scale) / 72; 216 break; 217 case (SCALE_MM): 218 r = su->scale / 1000; 219 break; 220 case (SCALE_VS): 221 r = su->scale * 2 - 1; 222 break; 223 default: 224 r = su->scale; 225 break; 226 } 227 228 return(r); 229 } 230 231 /* ARGSUSED */ 232 static size_t 233 locale_width(const struct termp *p, int c) 234 { 235 int rc; 236 237 return((rc = wcwidth(c)) < 0 ? 0 : rc); 238 } 239 240 /* ARGSUSED */ 241 static void 242 locale_advance(struct termp *p, size_t len) 243 { 244 size_t i; 245 246 for (i = 0; i < len; i++) 247 putwchar(L' '); 248 } 249 250 /* ARGSUSED */ 251 static void 252 locale_endline(struct termp *p) 253 { 254 255 putwchar(L'\n'); 256 } 257 258 /* ARGSUSED */ 259 static void 260 locale_letter(struct termp *p, int c) 261 { 262 263 putwchar(c); 264 } 265