1*84dd50f0Sschwarze /* $Id: term_ascii.c,v 1.9 2011/12/05 00:28:12 schwarze Exp $ */ 2f95d589eSschwarze /* 3a5e11edeSschwarze * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4f95d589eSschwarze * 5f95d589eSschwarze * Permission to use, copy, modify, and distribute this software for any 6f95d589eSschwarze * purpose with or without fee is hereby granted, provided that the above 7f95d589eSschwarze * copyright notice and this permission notice appear in all copies. 8f95d589eSschwarze * 9f95d589eSschwarze * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10f95d589eSschwarze * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11f95d589eSschwarze * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12f95d589eSschwarze * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13f95d589eSschwarze * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14f95d589eSschwarze * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15f95d589eSschwarze * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16f95d589eSschwarze */ 17f95d589eSschwarze #include <sys/types.h> 18f95d589eSschwarze 19f95d589eSschwarze #include <assert.h> 20a5e11edeSschwarze #include <locale.h> 21f95d589eSschwarze #include <stdint.h> 22f95d589eSschwarze #include <stdio.h> 23f95d589eSschwarze #include <stdlib.h> 24f95d589eSschwarze #include <unistd.h> 25a5e11edeSschwarze #include <wchar.h> 26f95d589eSschwarze 272791bd1cSschwarze #include "mandoc.h" 28f95d589eSschwarze #include "out.h" 29f95d589eSschwarze #include "term.h" 30f95d589eSschwarze #include "main.h" 31f95d589eSschwarze 32a5e11edeSschwarze static struct termp *ascii_init(enum termenc, char *); 33769ee804Sschwarze static double ascii_hspan(const struct termp *, 34769ee804Sschwarze const struct roffsu *); 35a5e11edeSschwarze static size_t ascii_width(const struct termp *, int); 36769ee804Sschwarze static void ascii_advance(struct termp *, size_t); 37769ee804Sschwarze static void ascii_begin(struct termp *); 38769ee804Sschwarze static void ascii_end(struct termp *); 39f95d589eSschwarze static void ascii_endline(struct termp *); 40a5e11edeSschwarze static void ascii_letter(struct termp *, int); 41f95d589eSschwarze 42a5e11edeSschwarze static void locale_advance(struct termp *, size_t); 43a5e11edeSschwarze static void locale_endline(struct termp *); 44a5e11edeSschwarze static void locale_letter(struct termp *, int); 45a5e11edeSschwarze static size_t locale_width(const struct termp *, int); 46f95d589eSschwarze 47a5e11edeSschwarze static struct termp * 48a5e11edeSschwarze ascii_init(enum termenc enc, char *outopts) 49f95d589eSschwarze { 50b6695f6fSschwarze const char *toks[4]; 51f95d589eSschwarze char *v; 52a5e11edeSschwarze struct termp *p; 53f95d589eSschwarze 54a5e11edeSschwarze p = mandoc_calloc(1, sizeof(struct termp)); 55a5e11edeSschwarze p->enc = enc; 56f95d589eSschwarze 573ebeb861Sschwarze p->tabwidth = 5; 583ebeb861Sschwarze p->defrmargin = 78; 593ebeb861Sschwarze 60f95d589eSschwarze p->begin = ascii_begin; 61f95d589eSschwarze p->end = ascii_end; 62769ee804Sschwarze p->hspan = ascii_hspan; 63769ee804Sschwarze p->type = TERMTYPE_CHAR; 64a5e11edeSschwarze 65a5e11edeSschwarze p->enc = TERMENC_ASCII; 66a5e11edeSschwarze p->advance = ascii_advance; 67a5e11edeSschwarze p->endline = ascii_endline; 68a5e11edeSschwarze p->letter = ascii_letter; 693ebeb861Sschwarze p->width = ascii_width; 70f95d589eSschwarze 71a5e11edeSschwarze if (TERMENC_ASCII != enc) { 72a5e11edeSschwarze v = TERMENC_LOCALE == enc ? 73a5e11edeSschwarze setlocale(LC_ALL, "") : 74a5e11edeSschwarze setlocale(LC_CTYPE, "UTF-8"); 75a5e11edeSschwarze if (NULL != v && MB_CUR_MAX > 1) { 76a5e11edeSschwarze p->enc = enc; 77a5e11edeSschwarze p->advance = locale_advance; 78a5e11edeSschwarze p->endline = locale_endline; 79a5e11edeSschwarze p->letter = locale_letter; 80a5e11edeSschwarze p->width = locale_width; 81a5e11edeSschwarze } 82a5e11edeSschwarze } 83a5e11edeSschwarze 84e12fe158Sschwarze toks[0] = "indent"; 85e12fe158Sschwarze toks[1] = "width"; 86b6695f6fSschwarze toks[2] = "mdoc"; 87b6695f6fSschwarze toks[3] = NULL; 88f95d589eSschwarze 89f95d589eSschwarze while (outopts && *outopts) 90f95d589eSschwarze switch (getsubopt(&outopts, UNCONST(toks), &v)) { 91f95d589eSschwarze case (0): 92e12fe158Sschwarze p->defindent = (size_t)atoi(v); 93e12fe158Sschwarze break; 94e12fe158Sschwarze case (1): 95f95d589eSschwarze p->defrmargin = (size_t)atoi(v); 96f95d589eSschwarze break; 97b6695f6fSschwarze case (2): 98*84dd50f0Sschwarze /* 99*84dd50f0Sschwarze * Temporary, undocumented mode 100*84dd50f0Sschwarze * to imitate mdoc(7) output style. 101*84dd50f0Sschwarze */ 102b6695f6fSschwarze p->mdocstyle = 1; 103b6695f6fSschwarze p->defindent = 5; 104b6695f6fSschwarze break; 105f95d589eSschwarze default: 106f95d589eSschwarze break; 107f95d589eSschwarze } 108f95d589eSschwarze 109f95d589eSschwarze /* Enforce a lower boundary. */ 110f95d589eSschwarze if (p->defrmargin < 58) 111f95d589eSschwarze p->defrmargin = 58; 112f95d589eSschwarze 113f95d589eSschwarze return(p); 114f95d589eSschwarze } 115f95d589eSschwarze 116a5e11edeSschwarze void * 117a5e11edeSschwarze ascii_alloc(char *outopts) 118a5e11edeSschwarze { 119a5e11edeSschwarze 120a5e11edeSschwarze return(ascii_init(TERMENC_ASCII, outopts)); 121a5e11edeSschwarze } 122a5e11edeSschwarze 123a5e11edeSschwarze void * 124a5e11edeSschwarze utf8_alloc(char *outopts) 125a5e11edeSschwarze { 126a5e11edeSschwarze 127a5e11edeSschwarze return(ascii_init(TERMENC_UTF8, outopts)); 128a5e11edeSschwarze } 129a5e11edeSschwarze 130a5e11edeSschwarze 131a5e11edeSschwarze void * 132a5e11edeSschwarze locale_alloc(char *outopts) 133a5e11edeSschwarze { 134a5e11edeSschwarze 135a5e11edeSschwarze return(ascii_init(TERMENC_LOCALE, outopts)); 136a5e11edeSschwarze } 137f95d589eSschwarze 138769ee804Sschwarze /* ARGSUSED */ 1393ebeb861Sschwarze static size_t 140a5e11edeSschwarze ascii_width(const struct termp *p, int c) 1413ebeb861Sschwarze { 1423ebeb861Sschwarze 1433ebeb861Sschwarze return(1); 1443ebeb861Sschwarze } 1453ebeb861Sschwarze 146f95d589eSschwarze void 147f95d589eSschwarze ascii_free(void *arg) 148f95d589eSschwarze { 149f95d589eSschwarze 150f95d589eSschwarze term_free((struct termp *)arg); 151f95d589eSschwarze } 152f95d589eSschwarze 153f95d589eSschwarze /* ARGSUSED */ 154f95d589eSschwarze static void 155a5e11edeSschwarze ascii_letter(struct termp *p, int c) 156f95d589eSschwarze { 157f95d589eSschwarze 158f95d589eSschwarze putchar(c); 159f95d589eSschwarze } 160f95d589eSschwarze 161f95d589eSschwarze static void 162f95d589eSschwarze ascii_begin(struct termp *p) 163f95d589eSschwarze { 164f95d589eSschwarze 165f95d589eSschwarze (*p->headf)(p, p->argf); 166f95d589eSschwarze } 167f95d589eSschwarze 168f95d589eSschwarze static void 169f95d589eSschwarze ascii_end(struct termp *p) 170f95d589eSschwarze { 171f95d589eSschwarze 172f95d589eSschwarze (*p->footf)(p, p->argf); 173f95d589eSschwarze } 174f95d589eSschwarze 175f95d589eSschwarze /* ARGSUSED */ 176f95d589eSschwarze static void 177f95d589eSschwarze ascii_endline(struct termp *p) 178f95d589eSschwarze { 179f95d589eSschwarze 180f95d589eSschwarze putchar('\n'); 181f95d589eSschwarze } 182f95d589eSschwarze 183f95d589eSschwarze /* ARGSUSED */ 184f95d589eSschwarze static void 185f95d589eSschwarze ascii_advance(struct termp *p, size_t len) 186f95d589eSschwarze { 187f95d589eSschwarze size_t i; 188f95d589eSschwarze 189f95d589eSschwarze for (i = 0; i < len; i++) 190f95d589eSschwarze putchar(' '); 191f95d589eSschwarze } 192769ee804Sschwarze 193769ee804Sschwarze /* ARGSUSED */ 194769ee804Sschwarze static double 195769ee804Sschwarze ascii_hspan(const struct termp *p, const struct roffsu *su) 196769ee804Sschwarze { 197769ee804Sschwarze double r; 198769ee804Sschwarze 199769ee804Sschwarze /* 200769ee804Sschwarze * Approximate based on character width. These are generated 201769ee804Sschwarze * entirely by eyeballing the screen, but appear to be correct. 202769ee804Sschwarze */ 203769ee804Sschwarze 204769ee804Sschwarze switch (su->unit) { 205769ee804Sschwarze case (SCALE_CM): 206769ee804Sschwarze r = 4 * su->scale; 207769ee804Sschwarze break; 208769ee804Sschwarze case (SCALE_IN): 209769ee804Sschwarze r = 10 * su->scale; 210769ee804Sschwarze break; 211769ee804Sschwarze case (SCALE_PC): 212769ee804Sschwarze r = (10 * su->scale) / 6; 213769ee804Sschwarze break; 214769ee804Sschwarze case (SCALE_PT): 215769ee804Sschwarze r = (10 * su->scale) / 72; 216769ee804Sschwarze break; 217769ee804Sschwarze case (SCALE_MM): 218769ee804Sschwarze r = su->scale / 1000; 219769ee804Sschwarze break; 220769ee804Sschwarze case (SCALE_VS): 221769ee804Sschwarze r = su->scale * 2 - 1; 222769ee804Sschwarze break; 223769ee804Sschwarze default: 224769ee804Sschwarze r = su->scale; 225769ee804Sschwarze break; 226769ee804Sschwarze } 227769ee804Sschwarze 228769ee804Sschwarze return(r); 229769ee804Sschwarze } 230769ee804Sschwarze 231a5e11edeSschwarze /* ARGSUSED */ 232a5e11edeSschwarze static size_t 233a5e11edeSschwarze locale_width(const struct termp *p, int c) 234a5e11edeSschwarze { 235a5e11edeSschwarze int rc; 236a5e11edeSschwarze 237a5e11edeSschwarze return((rc = wcwidth(c)) < 0 ? 0 : rc); 238a5e11edeSschwarze } 239a5e11edeSschwarze 240a5e11edeSschwarze /* ARGSUSED */ 241a5e11edeSschwarze static void 242a5e11edeSschwarze locale_advance(struct termp *p, size_t len) 243a5e11edeSschwarze { 244a5e11edeSschwarze size_t i; 245a5e11edeSschwarze 246a5e11edeSschwarze for (i = 0; i < len; i++) 247a5e11edeSschwarze putwchar(L' '); 248a5e11edeSschwarze } 249a5e11edeSschwarze 250a5e11edeSschwarze /* ARGSUSED */ 251a5e11edeSschwarze static void 252a5e11edeSschwarze locale_endline(struct termp *p) 253a5e11edeSschwarze { 254a5e11edeSschwarze 255a5e11edeSschwarze putwchar(L'\n'); 256a5e11edeSschwarze } 257a5e11edeSschwarze 258a5e11edeSschwarze /* ARGSUSED */ 259a5e11edeSschwarze static void 260a5e11edeSschwarze locale_letter(struct termp *p, int c) 261a5e11edeSschwarze { 262a5e11edeSschwarze 263a5e11edeSschwarze putwchar(c); 264a5e11edeSschwarze } 265