/* * 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); }
size_t term_tab_next(size_t prev) { size_t i, j; for (i = 0;; i++) { if (i == tabs.a.n) { if (tabs.p.n == 0) return prev; /* return i ? prev : (prev / tabs.d + 1) * tabs.d; */ tabs.a.n += tabs.p.n; if (tabs.a.s < tabs.a.n) { tabs.a.s = tabs.a.n; tabs.a.t = mandoc_reallocarray(tabs.a.t, tabs.a.s, sizeof(*tabs.a.t)); } for (j = 0; j < tabs.p.n; j++) tabs.a.t[i + j] = tabs.p.t[j] + (i ? tabs.a.t[i - 1] : 0); } if (prev < tabs.a.t[i] / 24) return tabs.a.t[i] / 24; } }
static void adjbuf(struct termp *p, size_t sz) { if (0 == p->maxcols) p->maxcols = 1024; while (sz >= p->maxcols) p->maxcols <<= 2; p->buf = mandoc_reallocarray(p->buf, p->maxcols, sizeof(int)); }
/* Set font, save previous. */ void term_fontpush(struct termp *p, enum termfont f) { p->fontl = p->fontq[p->fonti]; if (++p->fonti == p->fontsz) { p->fontsz += 8; p->fontq = mandoc_reallocarray(p->fontq, p->fontsz, sizeof(*p->fontq)); } p->fontq[p->fonti] = f; }
void term_tab_set(const struct termp *p, const char *arg) { static int recording_period; struct roffsu su; struct tablist *tl; size_t pos; int add; /* Special arguments: clear all tabs or switch lists. */ if (arg == NULL) { tabs.a.n = tabs.p.n = 0; recording_period = 0; if (tabs.d == 0) { a2roffsu(".8i", &su, SCALE_IN); tabs.d = term_hspan(p, &su) / 24; } return; } if (arg[0] == 'T' && arg[1] == '\0') { recording_period = 1; return; } /* Parse the sign, the number, and the unit. */ if (*arg == '+') { add = 1; arg++; } else add = 0; if (a2roffsu(arg, &su, SCALE_EM) == NULL) return; /* Select the list, and extend it if it is full. */ tl = recording_period ? &tabs.p : &tabs.a; if (tl->n >= tl->s) { tl->s += 8; tl->t = mandoc_reallocarray(tl->t, tl->s, sizeof(*tl->t)); } /* Append the new position. */ pos = term_hspan(p, &su); tl->t[tl->n] = pos; if (add && tl->n) tl->t[tl->n] += tl->t[tl->n - 1]; tl->n++; }
static void eqn_def(struct eqn_node *ep) { const char *start; size_t sz; struct eqn_def *def; int i; if ((start = eqn_nextrawtok(ep, &sz)) == NULL) { mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, ep->eqn.ln, ep->eqn.pos, "define"); return; } /* * Search for a key that already exists. * Create a new key if none is found. */ if (NULL == (def = eqn_def_find(ep, start, sz))) { /* Find holes in string array. */ for (i = 0; i < (int)ep->defsz; i++) if (0 == ep->defs[i].keysz) break; if (i == (int)ep->defsz) { ep->defsz++; ep->defs = mandoc_reallocarray(ep->defs, ep->defsz, sizeof(struct eqn_def)); ep->defs[i].key = ep->defs[i].val = NULL; } def = ep->defs + i; free(def->key); def->key = mandoc_strndup(start, sz); def->keysz = sz; } start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0); if (start == NULL) { mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse, ep->eqn.ln, ep->eqn.pos, "define %s", def->key); free(def->key); free(def->val); def->key = def->val = NULL; def->keysz = def->valsz = 0; return; } free(def->val); def->val = mandoc_strndup(start, sz); def->valsz = sz; }
static void pdf_obj(struct termp *p, size_t obj) { assert(obj > 0); if ((obj - 1) >= p->ps->pdfobjsz) { p->ps->pdfobjsz = obj + 128; p->ps->pdfobjs = mandoc_reallocarray(p->ps->pdfobjs, p->ps->pdfobjsz, sizeof(size_t)); } p->ps->pdfobjs[(int)obj - 1] = p->ps->pdfbytes; ps_printf(p, "%zu 0 obj\n", obj); }
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); } }
/* * Parse flags and their arguments from the input line. * These come in the form -flag [argument ...]. * Some flags take no argument, some one, some multiple. */ void mdoc_argv(struct mdoc *mdoc, int line, enum mdoct tok, struct mdoc_arg **reta, int *pos, char *buf) { struct mdoc_argv tmpv; struct mdoc_argv **retv; const enum mdocargt *argtable; char *argname; int ipos, retc; char savechar; *reta = NULL; /* Which flags does this macro support? */ argtable = mdocargs[tok].argvs; if (argtable == NULL) return; /* Loop over the flags on the input line. */ ipos = *pos; while (buf[ipos] == '-') { /* Seek to the first unescaped space. */ for (argname = buf + ++ipos; buf[ipos] != '\0'; ipos++) if (buf[ipos] == ' ' && buf[ipos - 1] != '\\') break; /* * We want to nil-terminate the word to look it up. * But we may not have a flag, in which case we need * to restore the line as-is. So keep around the * stray byte, which we'll reset upon exiting. */ if ((savechar = buf[ipos]) != '\0') buf[ipos++] = '\0'; /* * Now look up the word as a flag. Use temporary * storage that we'll copy into the node's flags. */ while ((tmpv.arg = *argtable++) != MDOC_ARG_MAX) if ( ! strcmp(argname, mdoc_argnames[tmpv.arg])) break; /* If it isn't a flag, restore the saved byte. */ if (tmpv.arg == MDOC_ARG_MAX) { if (savechar != '\0') buf[ipos - 1] = savechar; break; } /* Read to the next word (the first argument). */ while (buf[ipos] == ' ') ipos++; /* Parse the arguments of the flag. */ tmpv.line = line; tmpv.pos = ipos; tmpv.sz = 0; tmpv.value = NULL; switch (argvflags[tmpv.arg]) { case ARGV_SINGLE: argv_single(mdoc, line, &tmpv, &ipos, buf); break; case ARGV_MULTI: argv_multi(mdoc, line, &tmpv, &ipos, buf); break; case ARGV_NONE: break; } /* Append to the return values. */ if (*reta == NULL) *reta = mandoc_calloc(1, sizeof(**reta)); retc = ++(*reta)->argc; retv = &(*reta)->argv; *retv = mandoc_reallocarray(*retv, retc, sizeof(**retv)); memcpy(*retv + retc - 1, &tmpv, sizeof(**retv)); /* Prepare for parsing the next flag. */ *pos = ipos; argtable = mdocargs[tok].argvs; } }
static void pg_search(const struct req *req) { struct mansearch search; struct manpaths paths; struct manpage *res; char **argv; char *query, *rp, *wp; size_t ressz; int argc; /* * Begin by chdir()ing into the root of the manpath. * This way we can pick up the database files, which are * relative to the manpath root. */ if (-1 == (chdir(req->q.manpath))) { fprintf(stderr, "chdir %s: %s\n", req->q.manpath, strerror(errno)); pg_error_internal(); return; } search.arch = req->q.arch; search.sec = req->q.sec; search.outkey = "Nd"; search.argmode = req->q.equal ? ARG_NAME : ARG_EXPR; search.firstmatch = 1; paths.sz = 1; paths.paths = mandoc_malloc(sizeof(char *)); paths.paths[0] = mandoc_strdup("."); /* * Break apart at spaces with backslash-escaping. */ argc = 0; argv = NULL; rp = query = mandoc_strdup(req->q.query); for (;;) { while (isspace((unsigned char)*rp)) rp++; if (*rp == '\0') break; argv = mandoc_reallocarray(argv, argc + 1, sizeof(char *)); argv[argc++] = wp = rp; for (;;) { if (isspace((unsigned char)*rp)) { *wp = '\0'; rp++; break; } if (rp[0] == '\\' && rp[1] != '\0') rp++; if (wp != rp) *wp = *rp; if (*rp == '\0') break; wp++; rp++; } } if (0 == mansearch(&search, &paths, argc, argv, &res, &ressz)) pg_noresult(req, "You entered an invalid query."); else if (0 == ressz) pg_noresult(req, "No results found."); else pg_searchres(req, res, ressz); free(query); mansearch_free(res, ressz); free(paths.paths[0]); free(paths.paths); }
static struct termp * pspdf_alloc(const struct manoutput *outopts) { struct termp *p; unsigned int pagex, pagey; size_t marginx, marginy, lineheight; const char *pp; p = mandoc_calloc(1, sizeof(struct termp)); p->enc = TERMENC_ASCII; p->fontq = mandoc_reallocarray(NULL, (p->fontsz = 8), sizeof(enum termfont)); p->fontq[0] = p->fontl = TERMFONT_NONE; p->ps = mandoc_calloc(1, sizeof(struct termp_ps)); p->advance = ps_advance; p->begin = ps_begin; p->end = ps_end; p->endline = ps_endline; p->hspan = ps_hspan; p->letter = ps_letter; p->setwidth = ps_setwidth; p->width = ps_width; /* Default to US letter (millimetres). */ pagex = 216; pagey = 279; /* * The ISO-269 paper sizes can be calculated automatically, but * it would require bringing in -lm for pow() and I'd rather not * do that. So just do it the easy way for now. Since this * only happens once, I'm not terribly concerned. */ pp = outopts->paper; if (pp && strcasecmp(pp, "letter")) { if (0 == strcasecmp(pp, "a3")) { pagex = 297; pagey = 420; } else if (0 == strcasecmp(pp, "a4")) { pagex = 210; pagey = 297; } else if (0 == strcasecmp(pp, "a5")) { pagex = 148; pagey = 210; } else if (0 == strcasecmp(pp, "legal")) { pagex = 216; pagey = 356; } else if (2 != sscanf(pp, "%ux%u", &pagex, &pagey)) warnx("%s: Unknown paper", pp); } /* * This MUST be defined before any PNT2AFM or AFM2PNT * calculations occur. */ p->ps->scale = 11; /* Remember millimetres -> AFM units. */ pagex = PNT2AFM(p, ((double)pagex * 2.834)); pagey = PNT2AFM(p, ((double)pagey * 2.834)); /* Margins are 1/9 the page x and y. */ marginx = (size_t)((double)pagex / 9.0); marginy = (size_t)((double)pagey / 9.0); /* Line-height is 1.4em. */ lineheight = PNT2AFM(p, ((double)p->ps->scale * 1.4)); p->ps->width = p->ps->lastwidth = (size_t)pagex; p->ps->height = (size_t)pagey; p->ps->header = pagey - (marginy / 2) - (lineheight / 2); p->ps->top = pagey - marginy; p->ps->footer = (marginy / 2) - (lineheight / 2); p->ps->bottom = marginy; p->ps->left = marginx; p->ps->lineheight = lineheight; p->defrmargin = pagex - (marginx * 2); return p; }
int mansearch(const struct mansearch *search, const struct manpaths *paths, int argc, char *argv[], struct manpage **res, size_t *sz) { int fd, rc, c, indexbit; int64_t pageid; uint64_t outbit, iterbit; char buf[PATH_MAX]; char *sql; struct manpage *mpage; struct expr *e, *ep; sqlite3 *db; sqlite3_stmt *s, *s2; struct match *mp; struct ohash_info info; struct ohash htab; unsigned int idx; size_t i, j, cur, maxres; info.calloc = hash_calloc; info.alloc = hash_alloc; info.free = hash_free; info.key_offset = offsetof(struct match, pageid); *sz = cur = maxres = 0; sql = NULL; *res = NULL; fd = -1; e = NULL; rc = 0; if (0 == argc) goto out; if (NULL == (e = exprcomp(search, argc, argv))) goto out; outbit = 0; if (NULL != search->outkey) { for (indexbit = 0, iterbit = 1; indexbit < mansearch_keymax; indexbit++, iterbit <<= 1) { if (0 == strcasecmp(search->outkey, mansearch_keynames[indexbit])) { outbit = iterbit; break; } } } /* * Save a descriptor to the current working directory. * Since pathnames in the "paths" variable might be relative, * and we'll be chdir()ing into them, we need to keep a handle * on our current directory from which to start the chdir(). */ if (NULL == getcwd(buf, PATH_MAX)) { perror("getcwd"); goto out; } else if (-1 == (fd = open(buf, O_RDONLY, 0))) { perror(buf); goto out; } sql = sql_statement(e); /* * Loop over the directories (containing databases) for us to * search. * Don't let missing/bad databases/directories phase us. * In each, try to open the resident database and, if it opens, * scan it for our match expression. */ for (i = 0; i < paths->sz; i++) { if (-1 == fchdir(fd)) { perror(buf); free(*res); break; } else if (-1 == chdir(paths->paths[i])) { perror(paths->paths[i]); continue; } c = sqlite3_open_v2(MANDOC_DB, &db, SQLITE_OPEN_READONLY, NULL); if (SQLITE_OK != c) { fprintf(stderr, "%s/%s: %s\n", paths->paths[i], MANDOC_DB, strerror(errno)); sqlite3_close(db); continue; } /* * Define the SQL functions for substring * and regular expression matching. */ c = sqlite3_create_function(db, "match", 2, SQLITE_UTF8 | SQLITE_DETERMINISTIC, NULL, sql_match, NULL, NULL); assert(SQLITE_OK == c); c = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8 | SQLITE_DETERMINISTIC, NULL, sql_regexp, NULL, NULL); assert(SQLITE_OK == c); j = 1; c = sqlite3_prepare_v2(db, sql, -1, &s, NULL); if (SQLITE_OK != c) fprintf(stderr, "%s\n", sqlite3_errmsg(db)); for (ep = e; NULL != ep; ep = ep->next) { if (NULL == ep->substr) { SQL_BIND_BLOB(db, s, j, ep->regexp); } else SQL_BIND_TEXT(db, s, j, ep->substr); if (0 == ((TYPE_Nd | TYPE_Nm) & ep->bits)) SQL_BIND_INT64(db, s, j, ep->bits); } memset(&htab, 0, sizeof(struct ohash)); ohash_init(&htab, 4, &info); /* * Hash each entry on its [unique] document identifier. * This is a uint64_t. * Instead of using a hash function, simply convert the * uint64_t to a uint32_t, the hash value's type. * This gives good performance and preserves the * distribution of buckets in the table. */ while (SQLITE_ROW == (c = sqlite3_step(s))) { pageid = sqlite3_column_int64(s, 2); idx = ohash_lookup_memory(&htab, (char *)&pageid, sizeof(uint64_t), (uint32_t)pageid); if (NULL != ohash_find(&htab, idx)) continue; mp = mandoc_calloc(1, sizeof(struct match)); mp->pageid = pageid; mp->form = sqlite3_column_int(s, 1); mp->bits = sqlite3_column_int64(s, 3); if (TYPE_Nd == outbit) mp->desc = mandoc_strdup((const char *) sqlite3_column_text(s, 0)); ohash_insert(&htab, idx, mp); } if (SQLITE_DONE != c) fprintf(stderr, "%s\n", sqlite3_errmsg(db)); sqlite3_finalize(s); c = sqlite3_prepare_v2(db, "SELECT sec, arch, name, pageid FROM mlinks " "WHERE pageid=? ORDER BY sec, arch, name", -1, &s, NULL); if (SQLITE_OK != c) fprintf(stderr, "%s\n", sqlite3_errmsg(db)); c = sqlite3_prepare_v2(db, "SELECT bits, key, pageid FROM keys " "WHERE pageid=? AND bits & ?", -1, &s2, NULL); if (SQLITE_OK != c) fprintf(stderr, "%s\n", sqlite3_errmsg(db)); for (mp = ohash_first(&htab, &idx); NULL != mp; mp = ohash_next(&htab, &idx)) { if (cur + 1 > maxres) { maxres += 1024; *res = mandoc_reallocarray(*res, maxres, sizeof(struct manpage)); } mpage = *res + cur; mpage->ipath = i; mpage->bits = mp->bits; mpage->sec = 10; mpage->form = mp->form; buildnames(mpage, db, s, mp->pageid, paths->paths[i], mp->form); mpage->output = TYPE_Nd & outbit ? mp->desc : outbit ? buildoutput(db, s2, mp->pageid, outbit) : NULL; free(mp); cur++; } sqlite3_finalize(s); sqlite3_finalize(s2); sqlite3_close(db); ohash_delete(&htab); /* * In man(1) mode, prefer matches in earlier trees * over matches in later trees. */ if (cur && search->firstmatch) break; } qsort(*res, cur, sizeof(struct manpage), manpage_compare); rc = 1; out: if (-1 != fd) { if (-1 == fchdir(fd)) perror(buf); close(fd); } exprfree(e); free(sql); *sz = cur; return(rc); }