static int check_root(CHKARGS) { if (MAN_BLINE & man->flags) man_nmsg(man, n, MANDOCERR_SCOPEEXIT); else if (MAN_ELINE & man->flags) man_nmsg(man, n, MANDOCERR_SCOPEEXIT); man->flags &= ~MAN_BLINE; man->flags &= ~MAN_ELINE; if (NULL == man->first->child) { man_nmsg(man, n, MANDOCERR_NODOCBODY); return(0); } else if (NULL == man->meta.title) { man_nmsg(man, n, MANDOCERR_NOTITLE); /* * If a title hasn't been set, do so now (by * implication, date and section also aren't set). */ man->meta.title = mandoc_strdup("unknown"); man->meta.msec = mandoc_strdup("1"); man->meta.date = mandoc_normdate (man->parse, NULL, n->line, n->pos); } return(1); }
static void check_root(CHKARGS) { assert((man->flags & (MAN_BLINE | MAN_ELINE)) == 0); if (n->last == NULL || n->last->type == ROFFT_COMMENT) mandoc_msg(MANDOCERR_DOC_EMPTY, n->line, n->pos, NULL); else man->meta.hasbody = 1; if (NULL == man->meta.title) { mandoc_msg(MANDOCERR_TH_NOTITLE, n->line, n->pos, NULL); /* * If a title hasn't been set, do so now (by * implication, date and section also aren't set). */ man->meta.title = mandoc_strdup(""); man->meta.msec = mandoc_strdup(""); man->meta.date = man->quick ? mandoc_strdup("") : mandoc_normdate(man, NULL, n->line, n->pos); } if (man->meta.os_e && (man->meta.rcsids & (1 << man->meta.os_e)) == 0) mandoc_msg(MANDOCERR_RCS_MISSING, 0, 0, man->meta.os_e == MANDOC_OS_OPENBSD ? "(OpenBSD)" : "(NetBSD)"); }
static void check_root(CHKARGS) { assert((man->flags & (MAN_BLINE | MAN_ELINE)) == 0); if (NULL == man->first->child) mandoc_msg(MANDOCERR_DOC_EMPTY, man->parse, n->line, n->pos, NULL); else man->meta.hasbody = 1; if (NULL == man->meta.title) { mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse, n->line, n->pos, NULL); /* * If a title hasn't been set, do so now (by * implication, date and section also aren't set). */ man->meta.title = mandoc_strdup(""); man->meta.msec = mandoc_strdup(""); man->meta.date = man->quick ? mandoc_strdup("") : mandoc_normdate(man->parse, NULL, n->line, n->pos); } }
int mdoc_macro(MACRO_PROT_ARGS) { assert(tok < MDOC_MAX); /* If we're in the body, deny prologue calls. */ if (MDOC_PROLOGUE & mdoc_macros[tok].flags && MDOC_PBODY & m->flags) { mdoc_pmsg(m, line, ppos, MANDOCERR_BADBODY); return(1); } /* If we're in the prologue, deny "body" macros. */ if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) && ! (MDOC_PBODY & m->flags)) { mdoc_pmsg(m, line, ppos, MANDOCERR_BADPROLOG); if (NULL == m->meta.msec) m->meta.msec = mandoc_strdup("1"); if (NULL == m->meta.title) m->meta.title = mandoc_strdup("UNKNOWN"); if (NULL == m->meta.vol) m->meta.vol = mandoc_strdup("LOCAL"); if (NULL == m->meta.os) m->meta.os = mandoc_strdup("LOCAL"); if (0 == m->meta.date) m->meta.date = time(NULL); m->flags |= MDOC_PBODY; } return((*mdoc_macros[tok].fp)(m, tok, line, ppos, pos, buf)); }
void mdoc_macro(MACRO_PROT_ARGS) { assert(tok < MDOC_MAX); if (mdoc->flags & MDOC_PBODY) { if (tok == MDOC_Dt) { mandoc_vmsg(MANDOCERR_DT_LATE, mdoc->parse, line, ppos, "Dt %s", buf + *pos); return; } } else if ( ! (mdoc_macros[tok].flags & MDOC_PROLOGUE)) { if (mdoc->meta.title == NULL) { mandoc_vmsg(MANDOCERR_DT_NOTITLE, mdoc->parse, line, ppos, "%s %s", mdoc_macronames[tok], buf + *pos); mdoc->meta.title = mandoc_strdup("UNTITLED"); } if (NULL == mdoc->meta.vol) mdoc->meta.vol = mandoc_strdup("LOCAL"); mdoc->flags |= MDOC_PBODY; } (*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf); }
static int post_os(POST_ARGS) { struct mdoc_node *n; char buf[BUFSIZ]; #ifndef OSNAME struct utsname utsname; #endif n = mdoc->last; /* * Set the operating system by way of the `Os' macro. Note that * if an argument isn't provided and -DOSNAME="\"foo\"" is * provided during compilation, this value will be used instead * of filling in "sysname release" from uname(). */ if (mdoc->meta.os) free(mdoc->meta.os); if ( ! concat(mdoc, buf, n->child, BUFSIZ)) return(0); /* XXX: yes, these can all be dynamically-adjusted buffers, but * it's really not worth the extra hackery. */ if ('\0' == buf[0]) { #ifdef OSNAME if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) { mdoc_nmsg(mdoc, n, MANDOCERR_MEM); return(0); } #else /*!OSNAME */ if (uname(&utsname)) { mdoc_nmsg(mdoc, n, MANDOCERR_UNAME); mdoc->meta.os = mandoc_strdup("UNKNOWN"); return(post_prol(mdoc)); } if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) { mdoc_nmsg(mdoc, n, MANDOCERR_MEM); return(0); } if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) { mdoc_nmsg(mdoc, n, MANDOCERR_MEM); return(0); } if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) { mdoc_nmsg(mdoc, n, MANDOCERR_MEM); return(0); } #endif /*!OSNAME*/ } mdoc->meta.os = mandoc_strdup(buf); return(1); }
void roff_setreg(struct roff *r, const char *name, int val, char sign) { struct roffreg *reg; /* Search for an existing register with the same name. */ reg = r->regtab; while (reg && strcmp(name, reg->key.p)) reg = reg->next; if (NULL == reg) { /* Create a new register. */ reg = mandoc_malloc(sizeof(struct roffreg)); reg->key.p = mandoc_strdup(name); reg->key.sz = strlen(name); reg->val = 0; reg->next = r->regtab; r->regtab = reg; } if ('+' == sign) reg->val += val; else if ('-' == sign) reg->val -= val; else reg->val = val; }
static int post_lb(POST_ARGS) { const char *p; char *buf; size_t sz; check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1); assert(mdoc->last->child); assert(MDOC_TEXT == mdoc->last->child->type); p = mdoc_a2lib(mdoc->last->child->string); /* If lookup ok, replace with table value. */ if (p) { free(mdoc->last->child->string); mdoc->last->child->string = mandoc_strdup(p); return(1); } /* If not, use "library ``xxxx''. */ sz = strlen(mdoc->last->child->string) + 2 + strlen("\\(lqlibrary\\(rq"); buf = mandoc_malloc(sz); snprintf(buf, sz, "library \\(lq%s\\(rq", mdoc->last->child->string); free(mdoc->last->child->string); mdoc->last->child->string = buf; return(1); }
/* * Add a directory to the array, ignoring bad directories. * Grow the array one-by-one for simplicity's sake. */ static void manpath_add(struct manpaths *dirs, const char *dir, int complain) { char buf[PATH_MAX]; struct stat sb; char *cp; size_t i; if (NULL == (cp = realpath(dir, buf))) { if (complain) warn("manpath: %s", dir); return; } for (i = 0; i < dirs->sz; i++) if (0 == strcmp(dirs->paths[i], dir)) return; if (stat(cp, &sb) == -1) { if (complain) warn("manpath: %s", dir); return; } dirs->paths = mandoc_reallocarray(dirs->paths, dirs->sz + 1, sizeof(char *)); dirs->paths[dirs->sz++] = mandoc_strdup(cp); }
static int argv_multi(struct mdoc *mdoc, int line, struct mdoc_argv *v, int *pos, char *buf) { enum margserr ac; char *p; for (v->sz = 0; ; v->sz++) { if ('-' == buf[*pos]) break; ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p); if (ARGS_ERROR == ac) return(0); else if (ARGS_EOLN == ac) break; if (0 == v->sz % MULTI_STEP) v->value = mandoc_realloc(v->value, (v->sz + MULTI_STEP) * sizeof(char *)); v->value[(int)v->sz] = mandoc_strdup(p); } return(1); }
static int mdoc_root_pre(MDOC_ARGS) { struct htmlpair tag; struct tag *t, *tt; char *volume, *title; if (NULL == meta->arch) volume = mandoc_strdup(meta->vol); else mandoc_asprintf(&volume, "%s (%s)", meta->vol, meta->arch); if (NULL == meta->msec) title = mandoc_strdup(meta->title); else mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec); PAIR_CLASS_INIT(&tag, "head"); t = print_otag(h, TAG_TABLE, 1, &tag); print_otag(h, TAG_TBODY, 0, NULL); tt = print_otag(h, TAG_TR, 0, NULL); PAIR_CLASS_INIT(&tag, "head-ltitle"); print_otag(h, TAG_TD, 1, &tag); print_text(h, title); print_stagq(h, tt); PAIR_CLASS_INIT(&tag, "head-vol"); print_otag(h, TAG_TD, 1, &tag); print_text(h, volume); print_stagq(h, tt); PAIR_CLASS_INIT(&tag, "head-rtitle"); print_otag(h, TAG_TD, 1, &tag); print_text(h, title); print_tagq(h, t); free(title); free(volume); return(1); }
/* ARGSUSED */ static enum rofferr roff_userdef(ROFF_ARGS) { const char *arg[9]; char *cp, *n1, *n2; int i; /* * Collect pointers to macro argument strings * and null-terminate them. */ cp = *bufp + pos; for (i = 0; i < 9; i++) arg[i] = '\0' == *cp ? "" : mandoc_getarg(r->parse, &cp, ln, &pos); /* * Expand macro arguments. */ *szp = 0; n1 = cp = mandoc_strdup(r->current_string); while (NULL != (cp = strstr(cp, "\\$"))) { i = cp[2] - '1'; if (0 > i || 8 < i) { /* Not an argument invocation. */ cp += 2; continue; } *szp = strlen(n1) - 3 + strlen(arg[i]) + 1; n2 = mandoc_malloc(*szp); strlcpy(n2, n1, (size_t)(cp - n1 + 1)); strlcat(n2, arg[i], *szp); strlcat(n2, cp + 3, *szp); cp = n2 + (cp - n1); free(n1); n1 = n2; } /* * Replace the macro invocation * by the expanded macro. */ free(*bufp); *bufp = n1; if (0 == *szp) *szp = strlen(*bufp) + 1; return(*szp > 1 && '\n' == (*bufp)[(int)*szp - 2] ? ROFF_REPARSE : ROFF_APPEND); }
static int mdoc_fd_pre(MDOC_ARGS) { struct tag *t; char *buf, *cp; synopsis_pre(h, n); if (NULL == (n = n->child)) return 0; assert(n->type == ROFFT_TEXT); if (strcmp(n->string, "#include")) { print_otag(h, TAG_CODE, "cT", "Fd"); return 1; } print_otag(h, TAG_CODE, "cT", "In"); print_text(h, n->string); if (NULL != (n = n->next)) { assert(n->type == ROFFT_TEXT); if (h->base_includes) { cp = n->string; if (*cp == '<' || *cp == '"') cp++; buf = mandoc_strdup(cp); cp = strchr(buf, '\0') - 1; if (cp >= buf && (*cp == '>' || *cp == '"')) *cp = '\0'; t = print_otag(h, TAG_A, "cThI", "In", buf); free(buf); } else t = print_otag(h, TAG_A, "cT", "In"); print_text(h, n->string); print_tagq(h, t); n = n->next; } for ( ; n; n = n->next) { assert(n->type == ROFFT_TEXT); print_text(h, n->string); } return 0; }
static int mdoc_root_pre(const struct roff_meta *meta, struct html *h) { struct tag *t, *tt; char *volume, *title; if (NULL == meta->arch) volume = mandoc_strdup(meta->vol); else mandoc_asprintf(&volume, "%s (%s)", meta->vol, meta->arch); if (NULL == meta->msec) title = mandoc_strdup(meta->title); else mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec); t = print_otag(h, TAG_TABLE, "c", "head"); tt = print_otag(h, TAG_TR, ""); print_otag(h, TAG_TD, "c", "head-ltitle"); print_text(h, title); print_stagq(h, tt); print_otag(h, TAG_TD, "c", "head-vol"); print_text(h, volume); print_stagq(h, tt); print_otag(h, TAG_TD, "c", "head-rtitle"); print_text(h, title); print_tagq(h, t); free(title); free(volume); return 1; }
static void argv_single(struct mdoc *mdoc, int line, struct mdoc_argv *v, int *pos, char *buf) { enum margserr ac; char *p; ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p); if (ac == ARGS_EOLN) return; v->sz = 1; v->value = mandoc_malloc(sizeof(char *)); v->value[0] = mandoc_strdup(p); }
static int post_bl_block_width(POST_ARGS) { size_t width; int i; enum mdoct tok; struct mdoc_node *n; char buf[NUMSIZ]; n = mdoc->last; /* * Calculate the real width of a list from the -width string, * which may contain a macro (with a known default width), a * literal string, or a scaling width. * * If the value to -width is a macro, then we re-write it to be * the macro's width as set in share/tmac/mdoc/doc-common. */ if (0 == strcmp(n->norm->Bl.width, "Ds")) width = 6; else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width))) return(1); else if (0 == (width = mdoc_macro2len(tok))) { mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH); return(1); } /* The value already exists: free and reallocate it. */ assert(n->args); for (i = 0; i < (int)n->args->argc; i++) if (MDOC_Width == n->args->argv[i].arg) break; assert(i < (int)n->args->argc); snprintf(buf, NUMSIZ, "%zun", width); free(n->args->argv[i].value[0]); n->args->argv[i].value[0] = mandoc_strdup(buf); /* Set our width! */ n->norm->Bl.width = n->args->argv[i].value[0]; return(1); }
/* * Push a roff node onto the instruction stack. This must later be * removed with roffnode_pop(). */ static void roffnode_push(struct roff *r, enum rofft tok, const char *name, int line, int col) { struct roffnode *p; p = mandoc_calloc(1, sizeof(struct roffnode)); p->tok = tok; if (name) p->name = mandoc_strdup(name); p->parent = r->last; p->line = line; p->col = col; p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY; r->last = p; }
/* * Prepare the search SQL statement. */ static char * sql_statement(const struct expr *e) { char *sql; size_t sz; int needop; sql = mandoc_strdup(e->equal ? "SELECT desc, form, pageid, bits " "FROM mpages NATURAL JOIN names WHERE " : "SELECT desc, form, pageid, 0 FROM mpages WHERE "); sz = strlen(sql); for (needop = 0; NULL != e; e = e->next) { if (e->and) sql_append(&sql, &sz, " AND ", 1); else if (needop) sql_append(&sql, &sz, " OR ", 1); if (e->open) sql_append(&sql, &sz, "(", e->open); sql_append(&sql, &sz, TYPE_Nd & e->bits ? (NULL == e->substr ? "desc REGEXP ?" : "desc MATCH ?") : TYPE_Nm == e->bits ? (NULL == e->substr ? "pageid IN (SELECT pageid FROM names " "WHERE name REGEXP ?)" : e->equal ? "name = ? " : "pageid IN (SELECT pageid FROM names " "WHERE name MATCH ?)") : (NULL == e->substr ? "pageid IN (SELECT pageid FROM keys " "WHERE key REGEXP ? AND bits & ?)" : "pageid IN (SELECT pageid FROM keys " "WHERE key MATCH ? AND bits & ?)"), 1); if (e->close) sql_append(&sql, &sz, ")", e->close); needop = 1; } return(sql); }
/* * Add a directory to the array, ignoring bad directories. * Grow the array one-by-one for simplicity's sake. */ static void manpath_add(struct manpaths *dirs, const char *dir) { char buf[PATH_MAX]; char *cp; int i; if (NULL == (cp = realpath(dir, buf))) return; for (i = 0; i < dirs->sz; i++) if (0 == strcmp(dirs->paths[i], dir)) return; dirs->paths = mandoc_realloc (dirs->paths, ((size_t)dirs->sz + 1) * sizeof(char *)); dirs->paths[dirs->sz++] = mandoc_strdup(cp); }
char * mandoc_normdate(struct mparse *parse, char *in, int ln, int pos) { char *out; time_t t; if (NULL == in || '\0' == *in || 0 == strcmp(in, "$" "Mdocdate$")) { mandoc_msg(MANDOCERR_NODATE, parse, ln, pos, NULL); time(&t); } else if (!a2time(&t, "$" "Mdocdate: %b %d %Y $", in) && !a2time(&t, "%b %d, %Y", in) && !a2time(&t, "%Y-%m-%d", in)) { mandoc_msg(MANDOCERR_BADDATE, parse, ln, pos, NULL); t = 0; } out = t ? time2a(t) : NULL; return(out ? out : mandoc_strdup(in)); }
/* ARGSUSED */ int tbl_cdata(struct tbl_node *tbl, int ln, const char *p) { struct tbl_dat *dat; size_t sz; int pos; pos = 0; dat = tbl->last_span->last; if (p[pos] == 'T' && p[pos + 1] == '}') { pos += 2; if (p[pos] == tbl->opts.tab) { tbl->part = TBL_PART_DATA; pos++; return(data(tbl, tbl->last_span, ln, p, &pos)); } else if ('\0' == p[pos]) { tbl->part = TBL_PART_DATA; return(1); } /* Fallthrough: T} is part of a word. */ } dat->pos = TBL_DATA_DATA; if (dat->string) { sz = strlen(p) + strlen(dat->string) + 2; dat->string = mandoc_realloc(dat->string, sz); strlcat(dat->string, " ", sz); strlcat(dat->string, p, sz); } else dat->string = mandoc_strdup(p); if (TBL_CELL_DOWN == dat->layout->pos) mandoc_msg(MANDOCERR_TBLIGNDATA, tbl->parse, ln, pos, NULL); return(0); }
int tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos) { struct tbl_dat *dat; size_t sz; dat = tbl->last_span->last; if (p[pos] == 'T' && p[pos + 1] == '}') { pos += 2; if (p[pos] == tbl->opts.tab) { tbl->part = TBL_PART_DATA; pos++; while (p[pos] != '\0') getdata(tbl, tbl->last_span, ln, p, &pos); return 1; } else if (p[pos] == '\0') { tbl->part = TBL_PART_DATA; return 1; } /* Fallthrough: T} is part of a word. */ } dat->pos = TBL_DATA_DATA; dat->block = 1; if (dat->string != NULL) { sz = strlen(p + pos) + strlen(dat->string) + 2; dat->string = mandoc_realloc(dat->string, sz); (void)strlcat(dat->string, " ", sz); (void)strlcat(dat->string, p + pos, sz); } else dat->string = mandoc_strdup(p + pos); if (dat->layout->pos == TBL_CELL_DOWN) mandoc_msg(MANDOCERR_TBLDATA_SPAN, tbl->parse, ln, pos, dat->string); return 0; }
static void print_mdoc_head(const struct roff_meta *meta, struct html *h) { char *cp; print_gen_head(h); if (meta->arch != NULL && meta->msec != NULL) mandoc_asprintf(&cp, "%s(%s) (%s)", meta->title, meta->msec, meta->arch); else if (meta->msec != NULL) mandoc_asprintf(&cp, "%s(%s)", meta->title, meta->msec); else if (meta->arch != NULL) mandoc_asprintf(&cp, "%s (%s)", meta->title, meta->arch); else cp = mandoc_strdup(meta->title); print_otag(h, TAG_TITLE, ""); print_text(h, cp); free(cp); }
static void argv_multi(struct mdoc *mdoc, int line, struct mdoc_argv *v, int *pos, char *buf) { enum margserr ac; char *p; for (v->sz = 0; ; v->sz++) { if (buf[*pos] == '-') break; ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p); if (ac == ARGS_EOLN) break; if (v->sz % MULTI_STEP == 0) v->value = mandoc_reallocarray(v->value, v->sz + MULTI_STEP, sizeof(char *)); v->value[(int)v->sz] = mandoc_strdup(p); } }
static int post_nm(POST_ARGS) { char buf[BUFSIZ]; /* If no child specified, make sure we have the meta name. */ if (NULL == mdoc->last->child && NULL == mdoc->meta.name) { mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME); return(1); } else if (mdoc->meta.name) return(1); /* If no meta name, set it from the child. */ if ( ! concat(mdoc, buf, mdoc->last->child, BUFSIZ)) return(0); mdoc->meta.name = mandoc_strdup(buf); return(1); }
static int argv_opt_single(struct mdoc *m, int line, struct mdoc_argv *v, int *pos, char *buf) { enum margserr ac; char *p; if ('-' == buf[*pos]) return(1); ac = args(m, line, pos, buf, ARGSFL_NONE, &p); if (ARGS_ERROR == ac) return(0); if (ARGS_EOLN == ac) return(1); v->sz = 1; v->value = mandoc_malloc(sizeof(char *)); v->value[0] = mandoc_strdup(p); return(1); }
static void post_AT(CHKARGS) { static const char * const unix_versions[] = { "7th Edition", "System III", "System V", "System V Release 2", }; struct roff_node *nn; const char *p, *s; n = n->child; if (n == NULL || n->type != ROFFT_TEXT) p = unix_versions[0]; else { s = n->string; if (0 == strcmp(s, "3")) p = unix_versions[0]; else if (0 == strcmp(s, "4")) p = unix_versions[1]; else if (0 == strcmp(s, "5")) { nn = n->next; if (nn != NULL && nn->type == ROFFT_TEXT && nn->string[0] != '\0') p = unix_versions[3]; else p = unix_versions[2]; } else p = unix_versions[0]; } free(man->meta.os); man->meta.os = mandoc_strdup(p); }
static int argv_single(struct mdoc *m, int line, struct mdoc_argv *v, int *pos, char *buf) { int ppos; enum margserr ac; char *p; ppos = *pos; ac = args(m, line, pos, buf, ARGSFL_NONE, &p); if (ARGS_EOLN == ac) { mdoc_pmsg(m, line, ppos, MANDOCERR_SYNTARGVCOUNT); return(0); } else if (ARGS_ERROR == ac) return(0); v->sz = 1; v->value = mandoc_malloc(sizeof(char *)); v->value[0] = mandoc_strdup(p); return(1); }
/* ARGSUSED */ static enum rofferr roff_it(ROFF_ARGS) { char *cp; size_t len; int iv; /* Parse the number of lines. */ cp = *bufp + pos; len = strcspn(cp, " \t"); cp[len] = '\0'; if ((iv = mandoc_strntoi(cp, len, 10)) <= 0) { mandoc_msg(MANDOCERR_NUMERIC, r->parse, ln, ppos, *bufp + 1); return(ROFF_IGN); } cp += len + 1; /* Arm the input line trap. */ roffit_lines = iv; roffit_macro = mandoc_strdup(cp); return(ROFF_IGN); }
static int post_AT(CHKARGS) { static const char * const unix_versions[] = { "7th Edition", "System III", "System V", "System V Release 2", }; const char *p, *s; struct man_node *nn; n = n->child; if (NULL == n || MAN_TEXT != n->type) p = unix_versions[0]; else { s = n->string; if (0 == strcmp(s, "3")) p = unix_versions[0]; else if (0 == strcmp(s, "4")) p = unix_versions[1]; else if (0 == strcmp(s, "5")) { nn = n->next; if (nn && MAN_TEXT == nn->type && nn->string[0]) p = unix_versions[3]; else p = unix_versions[2]; } else p = unix_versions[0]; } free(man->meta.source); man->meta.source = mandoc_strdup(p); return(1); }