1 /* $Id: term_ascii.c,v 1.21 2013/06/01 14:27:20 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 #ifdef HAVE_CONFIG_H 18 #include "config.h" 19 #endif 20 21 #include <sys/types.h> 22 23 #include <assert.h> 24 #ifdef USE_WCHAR 25 # include <locale.h> 26 #endif 27 #include <stdint.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #ifdef USE_WCHAR 32 # include <wchar.h> 33 #endif 34 35 #include "mandoc.h" 36 #include "out.h" 37 #include "term.h" 38 #include "main.h" 39 40 /* 41 * Sadly, this doesn't seem to be defined on systems even when they 42 * support it. For the time being, remove it and let those compiling 43 * the software decide for themselves what to use. 44 */ 45 #if 0 46 #if ! defined(__STDC_ISO_10646__) 47 # undef USE_WCHAR 48 #endif 49 #endif 50 51 static struct termp *ascii_init(enum termenc, char *); 52 static double ascii_hspan(const struct termp *, 53 const struct roffsu *); 54 static size_t ascii_width(const struct termp *, int); 55 static void ascii_advance(struct termp *, size_t); 56 static void ascii_begin(struct termp *); 57 static void ascii_end(struct termp *); 58 static void ascii_endline(struct termp *); 59 static void ascii_letter(struct termp *, int); 60 61 #ifdef USE_WCHAR 62 static void locale_advance(struct termp *, size_t); 63 static void locale_endline(struct termp *); 64 static void locale_letter(struct termp *, int); 65 static size_t locale_width(const struct termp *, int); 66 #endif 67 68 static struct termp * 69 ascii_init(enum termenc enc, char *outopts) 70 { 71 const char *toks[4]; 72 char *v; 73 struct termp *p; 74 75 p = mandoc_calloc(1, sizeof(struct termp)); 76 77 p->tabwidth = 5; 78 p->defrmargin = 78; 79 80 p->begin = ascii_begin; 81 p->end = ascii_end; 82 p->hspan = ascii_hspan; 83 p->type = TERMTYPE_CHAR; 84 85 p->enc = TERMENC_ASCII; 86 p->advance = ascii_advance; 87 p->endline = ascii_endline; 88 p->letter = ascii_letter; 89 p->width = ascii_width; 90 91 #ifdef USE_WCHAR 92 if (TERMENC_ASCII != enc) { 93 v = TERMENC_LOCALE == enc ? 94 setlocale(LC_ALL, "") : 95 setlocale(LC_CTYPE, "en_US.UTF-8"); 96 if (NULL != v && MB_CUR_MAX > 1) { 97 p->enc = enc; 98 p->advance = locale_advance; 99 p->endline = locale_endline; 100 p->letter = locale_letter; 101 p->width = locale_width; 102 } 103 } 104 #endif 105 106 toks[0] = "indent"; 107 toks[1] = "width"; 108 toks[2] = "mdoc"; 109 toks[3] = NULL; 110 111 while (outopts && *outopts) 112 switch (getsubopt(&outopts, UNCONST(toks), &v)) { 113 case (0): 114 p->defindent = (size_t)atoi(v); 115 break; 116 case (1): 117 p->defrmargin = (size_t)atoi(v); 118 break; 119 case (2): 120 /* 121 * Temporary, undocumented mode 122 * to imitate mdoc(7) output style. 123 */ 124 p->mdocstyle = 1; 125 p->defindent = 5; 126 break; 127 default: 128 break; 129 } 130 131 /* Enforce a lower boundary. */ 132 if (p->defrmargin < 58) 133 p->defrmargin = 58; 134 135 return(p); 136 } 137 138 void * 139 ascii_alloc(char *outopts) 140 { 141 142 return(ascii_init(TERMENC_ASCII, outopts)); 143 } 144 145 void * 146 utf8_alloc(char *outopts) 147 { 148 149 return(ascii_init(TERMENC_UTF8, outopts)); 150 } 151 152 153 void * 154 locale_alloc(char *outopts) 155 { 156 157 return(ascii_init(TERMENC_LOCALE, outopts)); 158 } 159 160 /* ARGSUSED */ 161 static size_t 162 ascii_width(const struct termp *p, int c) 163 { 164 165 return(1); 166 } 167 168 void 169 ascii_free(void *arg) 170 { 171 172 term_free((struct termp *)arg); 173 } 174 175 /* ARGSUSED */ 176 static void 177 ascii_letter(struct termp *p, int c) 178 { 179 180 putchar(c); 181 } 182 183 static void 184 ascii_begin(struct termp *p) 185 { 186 187 (*p->headf)(p, p->argf); 188 } 189 190 static void 191 ascii_end(struct termp *p) 192 { 193 194 (*p->footf)(p, p->argf); 195 } 196 197 /* ARGSUSED */ 198 static void 199 ascii_endline(struct termp *p) 200 { 201 202 putchar('\n'); 203 } 204 205 /* ARGSUSED */ 206 static void 207 ascii_advance(struct termp *p, size_t len) 208 { 209 size_t i; 210 211 for (i = 0; i < len; i++) 212 putchar(' '); 213 } 214 215 /* ARGSUSED */ 216 static double 217 ascii_hspan(const struct termp *p, const struct roffsu *su) 218 { 219 double r; 220 221 /* 222 * Approximate based on character width. These are generated 223 * entirely by eyeballing the screen, but appear to be correct. 224 */ 225 226 switch (su->unit) { 227 case (SCALE_CM): 228 r = 4 * su->scale; 229 break; 230 case (SCALE_IN): 231 r = 10 * su->scale; 232 break; 233 case (SCALE_PC): 234 r = (10 * su->scale) / 6; 235 break; 236 case (SCALE_PT): 237 r = (10 * su->scale) / 72; 238 break; 239 case (SCALE_MM): 240 r = su->scale / 1000; 241 break; 242 case (SCALE_VS): 243 r = su->scale * 2 - 1; 244 break; 245 default: 246 r = su->scale; 247 break; 248 } 249 250 return(r); 251 } 252 253 #ifdef USE_WCHAR 254 /* ARGSUSED */ 255 static size_t 256 locale_width(const struct termp *p, int c) 257 { 258 int rc; 259 260 return((rc = wcwidth(c)) < 0 ? 0 : rc); 261 } 262 263 /* ARGSUSED */ 264 static void 265 locale_advance(struct termp *p, size_t len) 266 { 267 size_t i; 268 269 for (i = 0; i < len; i++) 270 putwchar(L' '); 271 } 272 273 /* ARGSUSED */ 274 static void 275 locale_endline(struct termp *p) 276 { 277 278 putwchar(L'\n'); 279 } 280 281 /* ARGSUSED */ 282 static void 283 locale_letter(struct termp *p, int c) 284 { 285 286 putwchar(c); 287 } 288 #endif