![]() ![]() | ![]() |
version 1.2, 2010/06/08 15:06:01 | version 1.31, 2014/08/16 19:00:01 | ||
---|---|---|---|
|
|
||
/* $Id$ */ | /* $Id$ */ | ||
/* | /* | ||
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> | * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> | ||
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org> | |||
* | * | ||
* Permission to use, copy, modify, and distribute this software for any | * Permission to use, copy, modify, and distribute this software for any | ||
* purpose with or without fee is hereby granted, provided that the above | * purpose with or without fee is hereby granted, provided that the above | ||
|
|
||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
*/ | */ | ||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | #include "config.h" | ||
#endif | |||
#include <sys/types.h> | #include <sys/types.h> | ||
#include <assert.h> | #if HAVE_WCHAR | ||
#include <locale.h> | |||
#endif | |||
#include <stdint.h> | #include <stdint.h> | ||
#include <stdio.h> | #include <stdio.h> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
#include <unistd.h> | #include <unistd.h> | ||
#if HAVE_WCHAR | |||
#include <wchar.h> | |||
#endif | |||
#include "mandoc.h" | |||
#include "mandoc_aux.h" | |||
#include "out.h" | #include "out.h" | ||
#include "term.h" | #include "term.h" | ||
#include "main.h" | #include "main.h" | ||
static void ascii_endline(struct termp *); | static struct termp *ascii_init(enum termenc, char *); | ||
static void ascii_letter(struct termp *, char); | static double ascii_hspan(const struct termp *, | ||
static void ascii_begin(struct termp *); | const struct roffsu *); | ||
static size_t ascii_width(const struct termp *, int); | |||
static void ascii_advance(struct termp *, size_t); | static void ascii_advance(struct termp *, size_t); | ||
static void ascii_begin(struct termp *); | |||
static void ascii_end(struct termp *); | static void ascii_end(struct termp *); | ||
static void ascii_endline(struct termp *); | |||
static void ascii_letter(struct termp *, int); | |||
static void ascii_setwidth(struct termp *, int, size_t); | |||
#if HAVE_WCHAR | |||
static void locale_advance(struct termp *, size_t); | |||
static void locale_endline(struct termp *); | |||
static void locale_letter(struct termp *, int); | |||
static size_t locale_width(const struct termp *, int); | |||
#endif | |||
void * | |||
ascii_alloc(char *outopts) | static struct termp * | ||
ascii_init(enum termenc enc, char *outopts) | |||
{ | { | ||
struct termp *p; | const char *toks[4]; | ||
const char *toks[2]; | |||
char *v; | char *v; | ||
struct termp *p; | |||
if (NULL == (p = term_alloc(TERMENC_ASCII))) | p = mandoc_calloc(1, sizeof(struct termp)); | ||
return(NULL); | |||
p->type = TERMTYPE_CHAR; | p->tabwidth = 5; | ||
p->letter = ascii_letter; | p->defrmargin = p->lastrmargin = 78; | ||
p->begin = ascii_begin; | p->begin = ascii_begin; | ||
p->end = ascii_end; | p->end = ascii_end; | ||
p->endline = ascii_endline; | p->hspan = ascii_hspan; | ||
p->type = TERMTYPE_CHAR; | |||
p->enc = TERMENC_ASCII; | |||
p->advance = ascii_advance; | p->advance = ascii_advance; | ||
p->endline = ascii_endline; | |||
p->letter = ascii_letter; | |||
p->setwidth = ascii_setwidth; | |||
p->width = ascii_width; | |||
toks[0] = "width"; | #if HAVE_WCHAR | ||
toks[1] = NULL; | if (TERMENC_ASCII != enc) { | ||
v = TERMENC_LOCALE == enc ? | |||
setlocale(LC_ALL, "") : | |||
setlocale(LC_CTYPE, "en_US.UTF-8"); | |||
if (NULL != v && MB_CUR_MAX > 1) { | |||
p->enc = enc; | |||
p->advance = locale_advance; | |||
p->endline = locale_endline; | |||
p->letter = locale_letter; | |||
p->width = locale_width; | |||
} | |||
} | |||
#endif | |||
toks[0] = "indent"; | |||
toks[1] = "width"; | |||
toks[2] = "mdoc"; | |||
toks[3] = NULL; | |||
while (outopts && *outopts) | while (outopts && *outopts) | ||
switch (getsubopt(&outopts, UNCONST(toks), &v)) { | switch (getsubopt(&outopts, UNCONST(toks), &v)) { | ||
case (0): | case 0: | ||
p->defindent = (size_t)atoi(v); | |||
break; | |||
case 1: | |||
p->defrmargin = (size_t)atoi(v); | p->defrmargin = (size_t)atoi(v); | ||
break; | break; | ||
case 2: | |||
/* | |||
* Temporary, undocumented mode | |||
* to imitate mdoc(7) output style. | |||
*/ | |||
p->mdocstyle = 1; | |||
p->defindent = 5; | |||
break; | |||
default: | default: | ||
break; | break; | ||
} | } | ||
|
|
||
return(p); | return(p); | ||
} | } | ||
void * | |||
ascii_alloc(char *outopts) | |||
{ | |||
return(ascii_init(TERMENC_ASCII, outopts)); | |||
} | |||
void * | |||
utf8_alloc(char *outopts) | |||
{ | |||
return(ascii_init(TERMENC_UTF8, outopts)); | |||
} | |||
void * | |||
locale_alloc(char *outopts) | |||
{ | |||
return(ascii_init(TERMENC_LOCALE, outopts)); | |||
} | |||
static void | |||
ascii_setwidth(struct termp *p, int iop, size_t width) | |||
{ | |||
p->rmargin = p->defrmargin; | |||
if (0 < iop) | |||
p->defrmargin += width; | |||
else if (0 > iop) | |||
p->defrmargin -= width; | |||
else | |||
p->defrmargin = width ? width : p->lastrmargin; | |||
p->lastrmargin = p->rmargin; | |||
p->rmargin = p->maxrmargin = p->defrmargin; | |||
} | |||
static size_t | |||
ascii_width(const struct termp *p, int c) | |||
{ | |||
return(1); | |||
} | |||
void | void | ||
ascii_free(void *arg) | ascii_free(void *arg) | ||
{ | { | ||
|
|
||
term_free((struct termp *)arg); | term_free((struct termp *)arg); | ||
} | } | ||
/* ARGSUSED */ | |||
static void | static void | ||
ascii_letter(struct termp *p, char c) | ascii_letter(struct termp *p, int c) | ||
{ | { | ||
/* Just push onto the screen. */ | |||
putchar(c); | putchar(c); | ||
} | } | ||
static void | static void | ||
ascii_begin(struct termp *p) | ascii_begin(struct termp *p) | ||
{ | { | ||
|
|
||
(*p->headf)(p, p->argf); | (*p->headf)(p, p->argf); | ||
} | } | ||
static void | static void | ||
ascii_end(struct termp *p) | ascii_end(struct termp *p) | ||
{ | { | ||
|
|
||
(*p->footf)(p, p->argf); | (*p->footf)(p, p->argf); | ||
} | } | ||
/* ARGSUSED */ | |||
static void | static void | ||
ascii_endline(struct termp *p) | ascii_endline(struct termp *p) | ||
{ | { | ||
|
|
||
putchar('\n'); | putchar('\n'); | ||
} | } | ||
/* ARGSUSED */ | |||
static void | static void | ||
ascii_advance(struct termp *p, size_t len) | ascii_advance(struct termp *p, size_t len) | ||
{ | { | ||
size_t i; | size_t i; | ||
/* Just print whitespace on the terminal. */ | |||
for (i = 0; i < len; i++) | for (i = 0; i < len; i++) | ||
putchar(' '); | putchar(' '); | ||
} | } | ||
static double | |||
ascii_hspan(const struct termp *p, const struct roffsu *su) | |||
{ | |||
double r; | |||
/* | |||
* Approximate based on character width. | |||
* None of these will be actually correct given that an inch on | |||
* the screen depends on character size, terminal, etc., etc. | |||
*/ | |||
switch (su->unit) { | |||
case SCALE_BU: | |||
r = su->scale * 10.0 / 240.0; | |||
break; | |||
case SCALE_CM: | |||
r = su->scale * 10.0 / 2.54; | |||
break; | |||
case SCALE_FS: | |||
r = su->scale * 2730.666; | |||
break; | |||
case SCALE_IN: | |||
r = su->scale * 10.0; | |||
break; | |||
case SCALE_MM: | |||
r = su->scale / 100.0; | |||
break; | |||
case SCALE_PC: | |||
r = su->scale * 10.0 / 6.0; | |||
break; | |||
case SCALE_PT: | |||
r = su->scale * 10.0 / 72.0; | |||
break; | |||
case SCALE_VS: | |||
r = su->scale * 2.0 - 1.0; | |||
break; | |||
case SCALE_EN: | |||
/* FALLTHROUGH */ | |||
case SCALE_EM: | |||
r = su->scale; | |||
break; | |||
case SCALE_MAX: | |||
abort(); | |||
/* NOTREACHED */ | |||
} | |||
return(r); | |||
} | |||
#if HAVE_WCHAR | |||
static size_t | |||
locale_width(const struct termp *p, int c) | |||
{ | |||
int rc; | |||
if (c == ASCII_NBRSP) | |||
c = ' '; | |||
rc = wcwidth(c); | |||
if (rc < 0) | |||
rc = 0; | |||
return(rc); | |||
} | |||
static void | |||
locale_advance(struct termp *p, size_t len) | |||
{ | |||
size_t i; | |||
for (i = 0; i < len; i++) | |||
putwchar(L' '); | |||
} | |||
static void | |||
locale_endline(struct termp *p) | |||
{ | |||
putwchar(L'\n'); | |||
} | |||
static void | |||
locale_letter(struct termp *p, int c) | |||
{ | |||
putwchar(c); | |||
} | |||
#endif |