version 1.188, 2013/12/25 00:50:05 |
version 1.194, 2014/02/14 23:24:26 |
|
|
/* $Id$ */ |
/* $Id$ */ |
/* |
/* |
* Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> |
* Copyright (c) 2010-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 |
|
|
ROFF_am, |
ROFF_am, |
ROFF_ami, |
ROFF_ami, |
ROFF_am1, |
ROFF_am1, |
|
ROFF_as, |
ROFF_cc, |
ROFF_cc, |
|
ROFF_ce, |
ROFF_de, |
ROFF_de, |
ROFF_dei, |
ROFF_dei, |
ROFF_de1, |
ROFF_de1, |
Line 109 struct roffreg { |
|
Line 111 struct roffreg { |
|
struct roff { |
struct roff { |
enum mparset parsetype; /* requested parse type */ |
enum mparset parsetype; /* requested parse type */ |
struct mparse *parse; /* parse point */ |
struct mparse *parse; /* parse point */ |
|
int quick; /* skip standard macro deletion */ |
struct roffnode *last; /* leaf of stack */ |
struct roffnode *last; /* leaf of stack */ |
enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */ |
enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */ |
char control; /* control character */ |
char control; /* control character */ |
Line 191 static int roff_getnum(const char *, int *, int *); |
|
Line 194 static int roff_getnum(const char *, int *, int *); |
|
static int roff_getop(const char *, int *, char *); |
static int roff_getop(const char *, int *, char *); |
static int roff_getregn(const struct roff *, |
static int roff_getregn(const struct roff *, |
const char *, size_t); |
const char *, size_t); |
|
static int roff_getregro(const char *name); |
static const char *roff_getstrn(const struct roff *, |
static const char *roff_getstrn(const struct roff *, |
const char *, size_t); |
const char *, size_t); |
static enum rofferr roff_it(ROFF_ARGS); |
static enum rofferr roff_it(ROFF_ARGS); |
Line 231 static struct roffmac roffs[ROFF_MAX] = { |
|
Line 235 static struct roffmac roffs[ROFF_MAX] = { |
|
{ "am", roff_block, roff_block_text, roff_block_sub, 0, NULL }, |
{ "am", roff_block, roff_block_text, roff_block_sub, 0, NULL }, |
{ "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL }, |
{ "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL }, |
{ "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL }, |
{ "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL }, |
|
{ "as", roff_ds, NULL, NULL, 0, NULL }, |
{ "cc", roff_cc, NULL, NULL, 0, NULL }, |
{ "cc", roff_cc, NULL, NULL, 0, NULL }, |
|
{ "ce", roff_line_ignore, NULL, NULL, 0, NULL }, |
{ "de", roff_block, roff_block_text, roff_block_sub, 0, NULL }, |
{ "de", roff_block, roff_block_text, roff_block_sub, 0, NULL }, |
{ "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL }, |
{ "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL }, |
{ "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL }, |
{ "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL }, |
Line 447 roff_free1(struct roff *r) |
|
Line 453 roff_free1(struct roff *r) |
|
void |
void |
roff_reset(struct roff *r) |
roff_reset(struct roff *r) |
{ |
{ |
int i; |
|
|
|
roff_free1(r); |
roff_free1(r); |
|
|
r->control = 0; |
r->control = 0; |
|
|
for (i = 0; i < PREDEFS_MAX; i++) |
|
roff_setstr(r, predefs[i].name, predefs[i].str, 0); |
|
} |
} |
|
|
|
|
Line 468 roff_free(struct roff *r) |
|
Line 469 roff_free(struct roff *r) |
|
|
|
|
|
struct roff * |
struct roff * |
roff_alloc(enum mparset type, struct mparse *parse) |
roff_alloc(enum mparset type, struct mparse *parse, int quick) |
{ |
{ |
struct roff *r; |
struct roff *r; |
int i; |
|
|
|
r = mandoc_calloc(1, sizeof(struct roff)); |
r = mandoc_calloc(1, sizeof(struct roff)); |
r->parsetype = type; |
r->parsetype = type; |
r->parse = parse; |
r->parse = parse; |
|
r->quick = quick; |
r->rstackpos = -1; |
r->rstackpos = -1; |
|
|
roffhash_init(); |
roffhash_init(); |
|
|
for (i = 0; i < PREDEFS_MAX; i++) |
|
roff_setstr(r, predefs[i].name, predefs[i].str, 0); |
|
|
|
return(r); |
return(r); |
} |
} |
|
|
Line 646 roff_parsetext(char **bufp, size_t *szp, int pos, int |
|
Line 644 roff_parsetext(char **bufp, size_t *szp, int pos, int |
|
if ('\\' == *p) { |
if ('\\' == *p) { |
/* Skip over escapes. */ |
/* Skip over escapes. */ |
p++; |
p++; |
esc = mandoc_escape |
esc = mandoc_escape((const char **)&p, NULL, NULL); |
((const char const **)&p, NULL, NULL); |
|
if (ESCAPE_ERROR == esc) |
if (ESCAPE_ERROR == esc) |
break; |
break; |
continue; |
continue; |
Line 946 roff_block(ROFF_ARGS) |
|
Line 943 roff_block(ROFF_ARGS) |
|
/* |
/* |
* At the beginning of a `de' macro, clear the existing string |
* At the beginning of a `de' macro, clear the existing string |
* with the same name, if there is one. New content will be |
* with the same name, if there is one. New content will be |
* added from roff_block_text() in multiline mode. |
* appended from roff_block_text() in multiline mode. |
*/ |
*/ |
|
|
if (ROFF_de == tok) |
if (ROFF_de == tok) |
Line 1036 roff_block_sub(ROFF_ARGS) |
|
Line 1033 roff_block_sub(ROFF_ARGS) |
|
*/ |
*/ |
if (ROFF_cblock != t) { |
if (ROFF_cblock != t) { |
if (ROFF_de == tok) |
if (ROFF_de == tok) |
roff_setstr(r, r->last->name, *bufp + ppos, 1); |
roff_setstr(r, r->last->name, *bufp + ppos, 2); |
return(ROFF_IGN); |
return(ROFF_IGN); |
} |
} |
|
|
Line 1052 roff_block_text(ROFF_ARGS) |
|
Line 1049 roff_block_text(ROFF_ARGS) |
|
{ |
{ |
|
|
if (ROFF_de == tok) |
if (ROFF_de == tok) |
roff_setstr(r, r->last->name, *bufp + pos, 1); |
roff_setstr(r, r->last->name, *bufp + pos, 2); |
|
|
return(ROFF_IGN); |
return(ROFF_IGN); |
} |
} |
Line 1355 roff_ds(ROFF_ARGS) |
|
Line 1352 roff_ds(ROFF_ARGS) |
|
string++; |
string++; |
|
|
/* The rest is the value. */ |
/* The rest is the value. */ |
roff_setstr(r, name, string, 0); |
roff_setstr(r, name, string, ROFF_as == tok); |
return(ROFF_IGN); |
return(ROFF_IGN); |
} |
} |
|
|
Line 1388 roff_setreg(struct roff *r, const char *name, int val, |
|
Line 1385 roff_setreg(struct roff *r, const char *name, int val, |
|
reg->val = val; |
reg->val = val; |
} |
} |
|
|
|
/* |
|
* Handle some predefined read-only number registers. |
|
* For now, return -1 if the requested register is not predefined; |
|
* in case a predefined read-only register having the value -1 |
|
* were to turn up, another special value would have to be chosen. |
|
*/ |
|
static int |
|
roff_getregro(const char *name) |
|
{ |
|
|
|
switch (*name) { |
|
case ('A'): /* ASCII approximation mode is always off. */ |
|
return(0); |
|
case ('g'): /* Groff compatibility mode is always on. */ |
|
return(1); |
|
case ('H'): /* Fixed horizontal resolution. */ |
|
return (24); |
|
case ('j'): /* Always adjust left margin only. */ |
|
return(0); |
|
case ('T'): /* Some output device is always defined. */ |
|
return(1); |
|
case ('V'): /* Fixed vertical resolution. */ |
|
return (40); |
|
default: |
|
return (-1); |
|
} |
|
} |
|
|
int |
int |
roff_getreg(const struct roff *r, const char *name) |
roff_getreg(const struct roff *r, const char *name) |
{ |
{ |
struct roffreg *reg; |
struct roffreg *reg; |
|
int val; |
|
|
|
if ('.' == name[0] && '\0' != name[1] && '\0' == name[2]) { |
|
val = roff_getregro(name + 1); |
|
if (-1 != val) |
|
return (val); |
|
} |
|
|
for (reg = r->regtab; reg; reg = reg->next) |
for (reg = r->regtab; reg; reg = reg->next) |
if (0 == strcmp(name, reg->key.p)) |
if (0 == strcmp(name, reg->key.p)) |
return(reg->val); |
return(reg->val); |
|
|
roff_getregn(const struct roff *r, const char *name, size_t len) |
roff_getregn(const struct roff *r, const char *name, size_t len) |
{ |
{ |
struct roffreg *reg; |
struct roffreg *reg; |
|
int val; |
|
|
|
if ('.' == name[0] && 2 == len) { |
|
val = roff_getregro(name + 1); |
|
if (-1 != val) |
|
return (val); |
|
} |
|
|
for (reg = r->regtab; reg; reg = reg->next) |
for (reg = r->regtab; reg; reg = reg->next) |
if (len == reg->key.sz && |
if (len == reg->key.sz && |
0 == strncmp(name, reg->key.p, len)) |
0 == strncmp(name, reg->key.p, len)) |
Line 1498 roff_Dd(ROFF_ARGS) |
|
Line 1537 roff_Dd(ROFF_ARGS) |
|
{ |
{ |
const char *const *cp; |
const char *const *cp; |
|
|
if (MPARSE_MDOC != r->parsetype) |
if (0 == r->quick && MPARSE_MDOC != r->parsetype) |
for (cp = __mdoc_reserved; *cp; cp++) |
for (cp = __mdoc_reserved; *cp; cp++) |
roff_setstr(r, *cp, NULL, 0); |
roff_setstr(r, *cp, NULL, 0); |
|
|
Line 1511 roff_TH(ROFF_ARGS) |
|
Line 1550 roff_TH(ROFF_ARGS) |
|
{ |
{ |
const char *const *cp; |
const char *const *cp; |
|
|
if (MPARSE_MDOC != r->parsetype) |
if (0 == r->quick && MPARSE_MDOC != r->parsetype) |
for (cp = __man_reserved; *cp; cp++) |
for (cp = __man_reserved; *cp; cp++) |
roff_setstr(r, *cp, NULL, 0); |
roff_setstr(r, *cp, NULL, 0); |
|
|
Line 1813 roff_getname(struct roff *r, char **cpp, int ln, int p |
|
Line 1852 roff_getname(struct roff *r, char **cpp, int ln, int p |
|
|
|
/* |
/* |
* Store *string into the user-defined string called *name. |
* Store *string into the user-defined string called *name. |
* In multiline mode, append to an existing entry and append '\n'; |
|
* else replace the existing entry, if there is one. |
|
* To clear an existing entry, call with (*r, *name, NULL, 0). |
* To clear an existing entry, call with (*r, *name, NULL, 0). |
|
* append == 0: replace mode |
|
* append == 1: single-line append mode |
|
* append == 2: multiline append mode, append '\n' after each call |
*/ |
*/ |
static void |
static void |
roff_setstr(struct roff *r, const char *name, const char *string, |
roff_setstr(struct roff *r, const char *name, const char *string, |
int multiline) |
int append) |
{ |
{ |
|
|
roff_setstrn(&r->strtab, name, strlen(name), string, |
roff_setstrn(&r->strtab, name, strlen(name), string, |
string ? strlen(string) : 0, multiline); |
string ? strlen(string) : 0, append); |
} |
} |
|
|
static void |
static void |
roff_setstrn(struct roffkv **r, const char *name, size_t namesz, |
roff_setstrn(struct roffkv **r, const char *name, size_t namesz, |
const char *string, size_t stringsz, int multiline) |
const char *string, size_t stringsz, int append) |
{ |
{ |
struct roffkv *n; |
struct roffkv *n; |
char *c; |
char *c; |
Line 1850 roff_setstrn(struct roffkv **r, const char *name, size |
|
Line 1890 roff_setstrn(struct roffkv **r, const char *name, size |
|
n->val.sz = 0; |
n->val.sz = 0; |
n->next = *r; |
n->next = *r; |
*r = n; |
*r = n; |
} else if (0 == multiline) { |
} else if (0 == append) { |
/* In multiline mode, append; else replace. */ |
|
free(n->val.p); |
free(n->val.p); |
n->val.p = NULL; |
n->val.p = NULL; |
n->val.sz = 0; |
n->val.sz = 0; |
Line 1864 roff_setstrn(struct roffkv **r, const char *name, size |
|
Line 1903 roff_setstrn(struct roffkv **r, const char *name, size |
|
* One additional byte for the '\n' in multiline mode, |
* One additional byte for the '\n' in multiline mode, |
* and one for the terminating '\0'. |
* and one for the terminating '\0'. |
*/ |
*/ |
newch = stringsz + (multiline ? 2u : 1u); |
newch = stringsz + (1 < append ? 2u : 1u); |
|
|
if (NULL == n->val.p) { |
if (NULL == n->val.p) { |
n->val.p = mandoc_malloc(newch); |
n->val.p = mandoc_malloc(newch); |
Line 1891 roff_setstrn(struct roffkv **r, const char *name, size |
|
Line 1930 roff_setstrn(struct roffkv **r, const char *name, size |
|
} |
} |
|
|
/* Append terminating bytes. */ |
/* Append terminating bytes. */ |
if (multiline) |
if (1 < append) |
*c++ = '\n'; |
*c++ = '\n'; |
|
|
*c = '\0'; |
*c = '\0'; |
Line 1902 static const char * |
|
Line 1941 static const char * |
|
roff_getstrn(const struct roff *r, const char *name, size_t len) |
roff_getstrn(const struct roff *r, const char *name, size_t len) |
{ |
{ |
const struct roffkv *n; |
const struct roffkv *n; |
|
int i; |
|
|
for (n = r->strtab; n; n = n->next) |
for (n = r->strtab; n; n = n->next) |
if (0 == strncmp(name, n->key.p, len) && |
if (0 == strncmp(name, n->key.p, len) && |
'\0' == n->key.p[(int)len]) |
'\0' == n->key.p[(int)len]) |
return(n->val.p); |
return(n->val.p); |
|
|
|
for (i = 0; i < PREDEFS_MAX; i++) |
|
if (0 == strncmp(name, predefs[i].name, len) && |
|
'\0' == predefs[i].name[(int)len]) |
|
return(predefs[i].str); |
|
|
return(NULL); |
return(NULL); |
} |
} |