1*4f4f7972Sschwarze /* $Id: term_ascii.c,v 1.11 2014/03/21 22:17:01 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 19a5e11edeSschwarze #include <locale.h> 20f95d589eSschwarze #include <stdint.h> 21f95d589eSschwarze #include <stdio.h> 22f95d589eSschwarze #include <stdlib.h> 23f95d589eSschwarze #include <unistd.h> 24a5e11edeSschwarze #include <wchar.h> 25f95d589eSschwarze 262791bd1cSschwarze #include "mandoc.h" 27*4f4f7972Sschwarze #include "mandoc_aux.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)); 55f95d589eSschwarze 563ebeb861Sschwarze p->tabwidth = 5; 573ebeb861Sschwarze p->defrmargin = 78; 583ebeb861Sschwarze 59f95d589eSschwarze p->begin = ascii_begin; 60f95d589eSschwarze p->end = ascii_end; 61769ee804Sschwarze p->hspan = ascii_hspan; 62769ee804Sschwarze p->type = TERMTYPE_CHAR; 63a5e11edeSschwarze 64a5e11edeSschwarze p->enc = TERMENC_ASCII; 65a5e11edeSschwarze p->advance = ascii_advance; 66a5e11edeSschwarze p->endline = ascii_endline; 67a5e11edeSschwarze p->letter = ascii_letter; 683ebeb861Sschwarze p->width = ascii_width; 69f95d589eSschwarze 70a5e11edeSschwarze if (TERMENC_ASCII != enc) { 71a5e11edeSschwarze v = TERMENC_LOCALE == enc ? 72a5e11edeSschwarze setlocale(LC_ALL, "") : 7367b9506bSschwarze setlocale(LC_CTYPE, "en_US.UTF-8"); 74a5e11edeSschwarze if (NULL != v && MB_CUR_MAX > 1) { 75a5e11edeSschwarze p->enc = enc; 76a5e11edeSschwarze p->advance = locale_advance; 77a5e11edeSschwarze p->endline = locale_endline; 78a5e11edeSschwarze p->letter = locale_letter; 79a5e11edeSschwarze p->width = locale_width; 80a5e11edeSschwarze } 81a5e11edeSschwarze } 82a5e11edeSschwarze 83e12fe158Sschwarze toks[0] = "indent"; 84e12fe158Sschwarze toks[1] = "width"; 85b6695f6fSschwarze toks[2] = "mdoc"; 86b6695f6fSschwarze toks[3] = NULL; 87f95d589eSschwarze 88f95d589eSschwarze while (outopts && *outopts) 89f95d589eSschwarze switch (getsubopt(&outopts, UNCONST(toks), &v)) { 90f95d589eSschwarze case (0): 91e12fe158Sschwarze p->defindent = (size_t)atoi(v); 92e12fe158Sschwarze break; 93e12fe158Sschwarze case (1): 94f95d589eSschwarze p->defrmargin = (size_t)atoi(v); 95f95d589eSschwarze break; 96b6695f6fSschwarze case (2): 9784dd50f0Sschwarze /* 9884dd50f0Sschwarze * Temporary, undocumented mode 9984dd50f0Sschwarze * to imitate mdoc(7) output style. 10084dd50f0Sschwarze */ 101b6695f6fSschwarze p->mdocstyle = 1; 102b6695f6fSschwarze p->defindent = 5; 103b6695f6fSschwarze break; 104f95d589eSschwarze default: 105f95d589eSschwarze break; 106f95d589eSschwarze } 107f95d589eSschwarze 108f95d589eSschwarze /* Enforce a lower boundary. */ 109f95d589eSschwarze if (p->defrmargin < 58) 110f95d589eSschwarze p->defrmargin = 58; 111f95d589eSschwarze 112f95d589eSschwarze return(p); 113f95d589eSschwarze } 114f95d589eSschwarze 115a5e11edeSschwarze void * 116a5e11edeSschwarze ascii_alloc(char *outopts) 117a5e11edeSschwarze { 118a5e11edeSschwarze 119a5e11edeSschwarze return(ascii_init(TERMENC_ASCII, outopts)); 120a5e11edeSschwarze } 121a5e11edeSschwarze 122a5e11edeSschwarze void * 123a5e11edeSschwarze utf8_alloc(char *outopts) 124a5e11edeSschwarze { 125a5e11edeSschwarze 126a5e11edeSschwarze return(ascii_init(TERMENC_UTF8, outopts)); 127a5e11edeSschwarze } 128a5e11edeSschwarze 129a5e11edeSschwarze 130a5e11edeSschwarze void * 131a5e11edeSschwarze locale_alloc(char *outopts) 132a5e11edeSschwarze { 133a5e11edeSschwarze 134a5e11edeSschwarze return(ascii_init(TERMENC_LOCALE, outopts)); 135a5e11edeSschwarze } 136f95d589eSschwarze 137769ee804Sschwarze /* ARGSUSED */ 1383ebeb861Sschwarze static size_t 139a5e11edeSschwarze ascii_width(const struct termp *p, int c) 1403ebeb861Sschwarze { 1413ebeb861Sschwarze 1423ebeb861Sschwarze return(1); 1433ebeb861Sschwarze } 1443ebeb861Sschwarze 145f95d589eSschwarze void 146f95d589eSschwarze ascii_free(void *arg) 147f95d589eSschwarze { 148f95d589eSschwarze 149f95d589eSschwarze term_free((struct termp *)arg); 150f95d589eSschwarze } 151f95d589eSschwarze 152f95d589eSschwarze /* ARGSUSED */ 153f95d589eSschwarze static void 154a5e11edeSschwarze ascii_letter(struct termp *p, int c) 155f95d589eSschwarze { 156f95d589eSschwarze 157f95d589eSschwarze putchar(c); 158f95d589eSschwarze } 159f95d589eSschwarze 160f95d589eSschwarze static void 161f95d589eSschwarze ascii_begin(struct termp *p) 162f95d589eSschwarze { 163f95d589eSschwarze 164f95d589eSschwarze (*p->headf)(p, p->argf); 165f95d589eSschwarze } 166f95d589eSschwarze 167f95d589eSschwarze static void 168f95d589eSschwarze ascii_end(struct termp *p) 169f95d589eSschwarze { 170f95d589eSschwarze 171f95d589eSschwarze (*p->footf)(p, p->argf); 172f95d589eSschwarze } 173f95d589eSschwarze 174f95d589eSschwarze /* ARGSUSED */ 175f95d589eSschwarze static void 176f95d589eSschwarze ascii_endline(struct termp *p) 177f95d589eSschwarze { 178f95d589eSschwarze 179f95d589eSschwarze putchar('\n'); 180f95d589eSschwarze } 181f95d589eSschwarze 182f95d589eSschwarze /* ARGSUSED */ 183f95d589eSschwarze static void 184f95d589eSschwarze ascii_advance(struct termp *p, size_t len) 185f95d589eSschwarze { 186f95d589eSschwarze size_t i; 187f95d589eSschwarze 188f95d589eSschwarze for (i = 0; i < len; i++) 189f95d589eSschwarze putchar(' '); 190f95d589eSschwarze } 191769ee804Sschwarze 192769ee804Sschwarze /* ARGSUSED */ 193769ee804Sschwarze static double 194769ee804Sschwarze ascii_hspan(const struct termp *p, const struct roffsu *su) 195769ee804Sschwarze { 196769ee804Sschwarze double r; 197769ee804Sschwarze 198769ee804Sschwarze /* 199769ee804Sschwarze * Approximate based on character width. These are generated 200769ee804Sschwarze * entirely by eyeballing the screen, but appear to be correct. 201769ee804Sschwarze */ 202769ee804Sschwarze 203769ee804Sschwarze switch (su->unit) { 204769ee804Sschwarze case (SCALE_CM): 205769ee804Sschwarze r = 4 * su->scale; 206769ee804Sschwarze break; 207769ee804Sschwarze case (SCALE_IN): 208769ee804Sschwarze r = 10 * su->scale; 209769ee804Sschwarze break; 210769ee804Sschwarze case (SCALE_PC): 211769ee804Sschwarze r = (10 * su->scale) / 6; 212769ee804Sschwarze break; 213769ee804Sschwarze case (SCALE_PT): 214769ee804Sschwarze r = (10 * su->scale) / 72; 215769ee804Sschwarze break; 216769ee804Sschwarze case (SCALE_MM): 217769ee804Sschwarze r = su->scale / 1000; 218769ee804Sschwarze break; 219769ee804Sschwarze case (SCALE_VS): 220769ee804Sschwarze r = su->scale * 2 - 1; 221769ee804Sschwarze break; 222769ee804Sschwarze default: 223769ee804Sschwarze r = su->scale; 224769ee804Sschwarze break; 225769ee804Sschwarze } 226769ee804Sschwarze 227769ee804Sschwarze return(r); 228769ee804Sschwarze } 229769ee804Sschwarze 230a5e11edeSschwarze /* ARGSUSED */ 231a5e11edeSschwarze static size_t 232a5e11edeSschwarze locale_width(const struct termp *p, int c) 233a5e11edeSschwarze { 234a5e11edeSschwarze int rc; 235a5e11edeSschwarze 236a5e11edeSschwarze return((rc = wcwidth(c)) < 0 ? 0 : rc); 237a5e11edeSschwarze } 238a5e11edeSschwarze 239a5e11edeSschwarze /* ARGSUSED */ 240a5e11edeSschwarze static void 241a5e11edeSschwarze locale_advance(struct termp *p, size_t len) 242a5e11edeSschwarze { 243a5e11edeSschwarze size_t i; 244a5e11edeSschwarze 245a5e11edeSschwarze for (i = 0; i < len; i++) 246a5e11edeSschwarze putwchar(L' '); 247a5e11edeSschwarze } 248a5e11edeSschwarze 249a5e11edeSschwarze /* ARGSUSED */ 250a5e11edeSschwarze static void 251a5e11edeSschwarze locale_endline(struct termp *p) 252a5e11edeSschwarze { 253a5e11edeSschwarze 254a5e11edeSschwarze putwchar(L'\n'); 255a5e11edeSschwarze } 256a5e11edeSschwarze 257a5e11edeSschwarze /* ARGSUSED */ 258a5e11edeSschwarze static void 259a5e11edeSschwarze locale_letter(struct termp *p, int c) 260a5e11edeSschwarze { 261a5e11edeSschwarze 262a5e11edeSschwarze putwchar(c); 263a5e11edeSschwarze } 264