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