diff options
-rw-r--r-- | regs.h | 5 | ||||
-rw-r--r-- | roff.3 | 67 | ||||
-rw-r--r-- | roff.c | 115 | ||||
-rw-r--r-- | term.c | 6 |
4 files changed, 192 insertions, 1 deletions
@@ -41,6 +41,11 @@ struct regset { struct reg regs[REG__MAX]; }; +char *roff_setstr(const char *, const char *); +char *roff_getstr(const char *); +char *roff_getstrn(const char *, size_t); +void roff_freestr(void); + __END_DECLS #endif /*!REGS_H*/ @@ -50,6 +50,15 @@ .Fc .Ft void .Fn roff_reset "struct roff *roff" +.In regs.h +.Ft "char *" +.Fn roff_setstr "const char *name" "const char *string" +.Ft "char *" +.Fn roff_getstr "const char *name" +.Ft "char *" +.Fn roff_getstrn "const char *name" "size_t len" +.Ft void +.Fn roff_freestr void .Sh DESCRIPTION The .Nm @@ -145,6 +154,52 @@ Returns 0 on failure, 1 on success. Signals that the parse is complete. Returns 0 on failure, 1 on success. .El +.Sh USER-DEFINED STRINGS +Strings defined by the +.Xr roff 7 +.Sx \&ds +instruction are saved using the +.Fn roff_setstr +function and retrieved using the +.Fn roff_getstr +and +.Fn roff_getstrn +functions. +.Pp +These functions take the name of the string to be accessed +as their first argument. +While +.Fn roff_getstr +requires the name to be null-terminated, +.Fn roff_getstrn +accepts non-terminated strings, but requires the length of the name +to be specified. +.Pp +The second argument to +.Fn roff_setstr +is the new value of the string. +It will be copied to internal storage, so both pointers to constant +strings and pointers to volatile storage are acceptable. +.Pp +All of these functions return a pointer to the new value of the string +in internal storage, which should be considered read-only, so use +.Xr strdup 3 +on it as appropriate. +The read functions return NULL when a string of the specified name +is not available or empty, and +.Fn roff_setstr +returns NULL when memory allocation fails. +In the latter case, the string will remain unset. +.Pp +The function +.Fn roff_freestr +clears all user-defined strings. +It always succeeds. +Both +.Fn roff_reset +and +.Fn roff_free +call it. .Sh EXAMPLES See .Pa main.c @@ -159,3 +214,15 @@ The .Nm library was written by .An Kristaps Dzonsons Aq kristaps@bsd.lv . +.Sh BUGS +The implementation of user-defined strings needs improvement: +.Bl -dash +.It +String values are taken literally and are not interpreted. +.It +Parsing of quoted strings is incomplete. +.It +The stings are stored internally using a singly linked list, +which is fine for small numbers of strings, +but ineffient when handling many strings. +.El @@ -108,6 +108,12 @@ struct roffmac { struct roffmac *next; }; +struct roffstr { + char *name; + char *string; + struct roffstr *next; +} *first_string; + static enum rofferr roff_block(ROFF_ARGS); static enum rofferr roff_block_text(ROFF_ARGS); static enum rofferr roff_block_sub(ROFF_ARGS); @@ -116,6 +122,7 @@ static enum rofferr roff_ccond(ROFF_ARGS); static enum rofferr roff_cond(ROFF_ARGS); static enum rofferr roff_cond_text(ROFF_ARGS); static enum rofferr roff_cond_sub(ROFF_ARGS); +static enum rofferr roff_ds(ROFF_ARGS); static enum rofferr roff_line(ROFF_ARGS); static enum rofferr roff_nr(ROFF_ARGS); static enum roffrule roff_evalcond(const char *, int *); @@ -135,7 +142,7 @@ static struct roffmac roffs[ROFF_MAX] = { { "de", 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 }, - { "ds", roff_line, NULL, NULL, 0, NULL }, + { "ds", roff_ds, NULL, NULL, 0, NULL }, { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, @@ -268,6 +275,7 @@ roff_free1(struct roff *r) while (r->last) roffnode_pop(r); + roff_freestr(); } @@ -879,6 +887,39 @@ roff_cond(ROFF_ARGS) /* ARGSUSED */ static enum rofferr +roff_ds(ROFF_ARGS) +{ + char *name, *string, *end; + + name = *bufp + pos; + if ('\0' == *name) + return(ROFF_IGN); + + string = name; + while (*string && ' ' != *string) + string++; + if (*string) + *(string++) = NULL; + if (*string && '"' == *string) + string++; + while (*string && ' ' == *string) + string++; + end = string; + while (*end) + end++; + if (string < end) { + end--; + if (*end == '"') + *end = '\0'; + } + + roff_setstr(name, string); + return(ROFF_IGN); +} + + +/* ARGSUSED */ +static enum rofferr roff_nr(ROFF_ARGS) { const char *key, *val; @@ -918,3 +959,75 @@ roff_nr(ROFF_ARGS) return(ROFF_IGN); } + + +char * +roff_setstr(const char *name, const char *string) +{ + struct roffstr *n; + char *namecopy; + + n = first_string; + while (n && strcmp(name, n->name)) + n = n->next; + if (n) { + free(n->string); + } else { + if (NULL == (namecopy = strdup(name))) + return(NULL); + if (NULL == (n = malloc(sizeof(struct roffstr)))) { + free(n); + return(NULL); + } + n->name = namecopy; + n->next = first_string; + first_string = n; + } + if (string) + n->string = strdup(string); + else + n->string = NULL; + return(n->string); +} + +char * +roff_getstr(const char *name) +{ + struct roffstr *n; + + n = first_string; + while (n && strcmp(name, n->name)) + n = n->next; + if (n) + return(n->string); + else + return(NULL); +} + +char * +roff_getstrn(const char *name, size_t len) +{ + struct roffstr *n; + + n = first_string; + while (n && (strncmp(name, n->name, len) || '\0' != n->name[len])) + n = n->next; + if (n) + return(n->string); + else + return(NULL); +} + +void +roff_freestr(void) +{ + struct roffstr *n, *nn; + + for (n = first_string; n; n = nn) { + free(n->name); + free(n->string); + nn = n->next; + free(n); + } + first_string = NULL; +} @@ -30,6 +30,7 @@ #include "mandoc.h" #include "chars.h" #include "out.h" +#include "regs.h" #include "term.h" #include "main.h" @@ -377,6 +378,11 @@ res(struct termp *p, const char *word, size_t len) size_t sz; rhs = chars_a2res(p->symtab, word, len, &sz); + if (NULL == rhs) { + rhs = roff_getstrn(word, len); + if (rhs) + sz = strlen(rhs); + } if (rhs) encode(p, rhs, sz); } |