]>
git.cameronkatri.com Git - mandoc.git/blob - mandocdb.c
1 /* $Id: mandocdb.c,v 1.49 2012/05/27 17:48:57 schwarze Exp $ */
3 * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2011, 2012 Ingo Schwarze <schwarze@openbsd.org>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 #include <sys/param.h>
23 #include <sys/types.h>
37 #if defined(__linux__)
40 #elif defined(__APPLE__)
41 # include <libkern/OSByteOrder.h>
53 #define MANDOC_BUFSZ BUFSIZ
54 #define MANDOC_SLOP 1024
56 #define MANDOC_SRC 0x1
57 #define MANDOC_FORM 0x2
59 #define WARNING(_f, _b, _fmt, _args...) \
61 fprintf(stderr, "%s: ", (_b)); \
62 fprintf(stderr, (_fmt), ##_args); \
64 fprintf(stderr, ": %s", (_f)); \
65 fprintf(stderr, "\n"); \
66 } while (/* CONSTCOND */ 0)
68 /* Access to the mandoc database on disk. */
71 char idxn
[MAXPATHLEN
]; /* index db filename */
72 char dbn
[MAXPATHLEN
]; /* keyword db filename */
73 DB
*idx
; /* index recno database */
74 DB
*db
; /* keyword btree database */
77 /* Stack of temporarily unused index records. */
80 recno_t
*stack
; /* pointer to a malloc'ed array */
81 size_t size
; /* number of allocated slots */
82 size_t cur
; /* current number of empty records */
83 recno_t last
; /* last record number in the index */
86 /* Tiny list for files. No need to bring in QUEUE. */
89 char *fname
; /* heap-allocated */
94 struct of
*next
; /* NULL for last one */
95 struct of
*first
; /* first in list */
98 /* Buffer for storing growable data. */
102 size_t len
; /* current length */
103 size_t size
; /* total buffer size */
106 /* Operation we're going to perform. */
109 OP_DEFAULT
= 0, /* new dbs from dir list or default config */
110 OP_CONFFILE
, /* new databases from custom config file */
111 OP_UPDATE
, /* delete/add entries in existing database */
112 OP_DELETE
, /* delete entries from existing database */
113 OP_TEST
/* change no databases, report potential problems */
116 #define MAN_ARGS DB *hash, \
119 const struct man_node *n
120 #define MDOC_ARGS DB *hash, \
123 const struct mdoc_node *n, \
124 const struct mdoc_meta *m
126 static void buf_appendmdoc(struct buf
*,
127 const struct mdoc_node
*, int);
128 static void buf_append(struct buf
*, const char *);
129 static void buf_appendb(struct buf
*,
130 const void *, size_t);
131 static void dbt_put(DB
*, const char *, DBT
*, DBT
*);
132 static void hash_put(DB
*, const struct buf
*, uint64_t);
133 static void hash_reset(DB
**);
134 static void index_merge(const struct of
*, struct mparse
*,
135 struct buf
*, struct buf
*, DB
*,
136 struct mdb
*, struct recs
*,
138 static void index_prune(const struct of
*, struct mdb
*,
139 struct recs
*, const char *);
140 static void ofile_argbuild(int, char *[],
141 struct of
**, const char *);
142 static void ofile_dirbuild(const char *, const char *,
143 const char *, int, struct of
**, char *);
144 static void ofile_free(struct of
*);
145 static void pformatted(DB
*, struct buf
*, struct buf
*,
146 const struct of
*, const char *);
147 static int pman_node(MAN_ARGS
);
148 static void pmdoc_node(MDOC_ARGS
);
149 static int pmdoc_head(MDOC_ARGS
);
150 static int pmdoc_body(MDOC_ARGS
);
151 static int pmdoc_Fd(MDOC_ARGS
);
152 static int pmdoc_In(MDOC_ARGS
);
153 static int pmdoc_Fn(MDOC_ARGS
);
154 static int pmdoc_Nd(MDOC_ARGS
);
155 static int pmdoc_Nm(MDOC_ARGS
);
156 static int pmdoc_Sh(MDOC_ARGS
);
157 static int pmdoc_St(MDOC_ARGS
);
158 static int pmdoc_Xr(MDOC_ARGS
);
160 #define MDOCF_CHILD 0x01 /* Automatically index child nodes. */
162 struct mdoc_handler
{
163 int (*fp
)(MDOC_ARGS
); /* Optional handler. */
164 uint64_t mask
; /* Set unless handler returns 0. */
165 int flags
; /* For use by pmdoc_node. */
168 static const struct mdoc_handler mdocs
[MDOC_MAX
] = {
169 { NULL
, 0, 0 }, /* Ap */
170 { NULL
, 0, 0 }, /* Dd */
171 { NULL
, 0, 0 }, /* Dt */
172 { NULL
, 0, 0 }, /* Os */
173 { pmdoc_Sh
, TYPE_Sh
, MDOCF_CHILD
}, /* Sh */
174 { pmdoc_head
, TYPE_Ss
, MDOCF_CHILD
}, /* Ss */
175 { NULL
, 0, 0 }, /* Pp */
176 { NULL
, 0, 0 }, /* D1 */
177 { NULL
, 0, 0 }, /* Dl */
178 { NULL
, 0, 0 }, /* Bd */
179 { NULL
, 0, 0 }, /* Ed */
180 { NULL
, 0, 0 }, /* Bl */
181 { NULL
, 0, 0 }, /* El */
182 { NULL
, 0, 0 }, /* It */
183 { NULL
, 0, 0 }, /* Ad */
184 { NULL
, TYPE_An
, MDOCF_CHILD
}, /* An */
185 { NULL
, TYPE_Ar
, MDOCF_CHILD
}, /* Ar */
186 { NULL
, TYPE_Cd
, MDOCF_CHILD
}, /* Cd */
187 { NULL
, TYPE_Cm
, MDOCF_CHILD
}, /* Cm */
188 { NULL
, TYPE_Dv
, MDOCF_CHILD
}, /* Dv */
189 { NULL
, TYPE_Er
, MDOCF_CHILD
}, /* Er */
190 { NULL
, TYPE_Ev
, MDOCF_CHILD
}, /* Ev */
191 { NULL
, 0, 0 }, /* Ex */
192 { NULL
, TYPE_Fa
, MDOCF_CHILD
}, /* Fa */
193 { pmdoc_Fd
, TYPE_In
, 0 }, /* Fd */
194 { NULL
, TYPE_Fl
, MDOCF_CHILD
}, /* Fl */
195 { pmdoc_Fn
, 0, 0 }, /* Fn */
196 { NULL
, TYPE_Ft
, MDOCF_CHILD
}, /* Ft */
197 { NULL
, TYPE_Ic
, MDOCF_CHILD
}, /* Ic */
198 { pmdoc_In
, TYPE_In
, 0 }, /* In */
199 { NULL
, TYPE_Li
, MDOCF_CHILD
}, /* Li */
200 { pmdoc_Nd
, TYPE_Nd
, MDOCF_CHILD
}, /* Nd */
201 { pmdoc_Nm
, TYPE_Nm
, MDOCF_CHILD
}, /* Nm */
202 { NULL
, 0, 0 }, /* Op */
203 { NULL
, 0, 0 }, /* Ot */
204 { NULL
, TYPE_Pa
, MDOCF_CHILD
}, /* Pa */
205 { NULL
, 0, 0 }, /* Rv */
206 { pmdoc_St
, TYPE_St
, 0 }, /* St */
207 { NULL
, TYPE_Va
, MDOCF_CHILD
}, /* Va */
208 { pmdoc_body
, TYPE_Va
, MDOCF_CHILD
}, /* Vt */
209 { pmdoc_Xr
, TYPE_Xr
, 0 }, /* Xr */
210 { NULL
, 0, 0 }, /* %A */
211 { NULL
, 0, 0 }, /* %B */
212 { NULL
, 0, 0 }, /* %D */
213 { NULL
, 0, 0 }, /* %I */
214 { NULL
, 0, 0 }, /* %J */
215 { NULL
, 0, 0 }, /* %N */
216 { NULL
, 0, 0 }, /* %O */
217 { NULL
, 0, 0 }, /* %P */
218 { NULL
, 0, 0 }, /* %R */
219 { NULL
, 0, 0 }, /* %T */
220 { NULL
, 0, 0 }, /* %V */
221 { NULL
, 0, 0 }, /* Ac */
222 { NULL
, 0, 0 }, /* Ao */
223 { NULL
, 0, 0 }, /* Aq */
224 { NULL
, TYPE_At
, MDOCF_CHILD
}, /* At */
225 { NULL
, 0, 0 }, /* Bc */
226 { NULL
, 0, 0 }, /* Bf */
227 { NULL
, 0, 0 }, /* Bo */
228 { NULL
, 0, 0 }, /* Bq */
229 { NULL
, TYPE_Bsx
, MDOCF_CHILD
}, /* Bsx */
230 { NULL
, TYPE_Bx
, MDOCF_CHILD
}, /* Bx */
231 { NULL
, 0, 0 }, /* Db */
232 { NULL
, 0, 0 }, /* Dc */
233 { NULL
, 0, 0 }, /* Do */
234 { NULL
, 0, 0 }, /* Dq */
235 { NULL
, 0, 0 }, /* Ec */
236 { NULL
, 0, 0 }, /* Ef */
237 { NULL
, TYPE_Em
, MDOCF_CHILD
}, /* Em */
238 { NULL
, 0, 0 }, /* Eo */
239 { NULL
, TYPE_Fx
, MDOCF_CHILD
}, /* Fx */
240 { NULL
, TYPE_Ms
, MDOCF_CHILD
}, /* Ms */
241 { NULL
, 0, 0 }, /* No */
242 { NULL
, 0, 0 }, /* Ns */
243 { NULL
, TYPE_Nx
, MDOCF_CHILD
}, /* Nx */
244 { NULL
, TYPE_Ox
, MDOCF_CHILD
}, /* Ox */
245 { NULL
, 0, 0 }, /* Pc */
246 { NULL
, 0, 0 }, /* Pf */
247 { NULL
, 0, 0 }, /* Po */
248 { NULL
, 0, 0 }, /* Pq */
249 { NULL
, 0, 0 }, /* Qc */
250 { NULL
, 0, 0 }, /* Ql */
251 { NULL
, 0, 0 }, /* Qo */
252 { NULL
, 0, 0 }, /* Qq */
253 { NULL
, 0, 0 }, /* Re */
254 { NULL
, 0, 0 }, /* Rs */
255 { NULL
, 0, 0 }, /* Sc */
256 { NULL
, 0, 0 }, /* So */
257 { NULL
, 0, 0 }, /* Sq */
258 { NULL
, 0, 0 }, /* Sm */
259 { NULL
, 0, 0 }, /* Sx */
260 { NULL
, TYPE_Sy
, MDOCF_CHILD
}, /* Sy */
261 { NULL
, TYPE_Tn
, MDOCF_CHILD
}, /* Tn */
262 { NULL
, 0, 0 }, /* Ux */
263 { NULL
, 0, 0 }, /* Xc */
264 { NULL
, 0, 0 }, /* Xo */
265 { pmdoc_head
, TYPE_Fn
, 0 }, /* Fo */
266 { NULL
, 0, 0 }, /* Fc */
267 { NULL
, 0, 0 }, /* Oo */
268 { NULL
, 0, 0 }, /* Oc */
269 { NULL
, 0, 0 }, /* Bk */
270 { NULL
, 0, 0 }, /* Ek */
271 { NULL
, 0, 0 }, /* Bt */
272 { NULL
, 0, 0 }, /* Hf */
273 { NULL
, 0, 0 }, /* Fr */
274 { NULL
, 0, 0 }, /* Ud */
275 { NULL
, TYPE_Lb
, MDOCF_CHILD
}, /* Lb */
276 { NULL
, 0, 0 }, /* Lp */
277 { NULL
, TYPE_Lk
, MDOCF_CHILD
}, /* Lk */
278 { NULL
, TYPE_Mt
, MDOCF_CHILD
}, /* Mt */
279 { NULL
, 0, 0 }, /* Brq */
280 { NULL
, 0, 0 }, /* Bro */
281 { NULL
, 0, 0 }, /* Brc */
282 { NULL
, 0, 0 }, /* %C */
283 { NULL
, 0, 0 }, /* Es */
284 { NULL
, 0, 0 }, /* En */
285 { NULL
, TYPE_Dx
, MDOCF_CHILD
}, /* Dx */
286 { NULL
, 0, 0 }, /* %Q */
287 { NULL
, 0, 0 }, /* br */
288 { NULL
, 0, 0 }, /* sp */
289 { NULL
, 0, 0 }, /* %U */
290 { NULL
, 0, 0 }, /* Ta */
293 static const char *progname
;
294 static int use_all
; /* Use all directories and files. */
295 static int verb
; /* Output verbosity level. */
296 static int warnings
; /* Potential problems in manuals. */
299 main(int argc
, char *argv
[])
301 struct mparse
*mp
; /* parse sequence */
302 struct manpaths dirs
;
305 enum op op
; /* current operation */
308 char dirbuf
[MAXPATHLEN
];
309 DB
*hash
; /* temporary keyword hashtable */
310 BTREEINFO info
; /* btree configuration */
312 struct buf buf
, /* keyword buffer */
313 dbuf
; /* description buffer */
314 struct of
*of
; /* list of files for processing */
318 progname
= strrchr(argv
[0], '/');
319 if (progname
== NULL
)
324 memset(&dirs
, 0, sizeof(struct manpaths
));
325 memset(&mdb
, 0, sizeof(struct mdb
));
326 memset(&recs
, 0, sizeof(struct recs
));
334 while (-1 != (ch
= getopt(argc
, argv
, "aC:d:tu:vW")))
342 "-C: conflicting options\n");
351 "-d: conflicting options\n");
358 dup2(STDOUT_FILENO
, STDERR_FILENO
);
361 "-t: conflicting options\n");
371 "-u: conflicting options\n");
390 if (OP_CONFFILE
== op
&& argc
> 0) {
391 fprintf(stderr
, "-C: too many arguments\n");
395 memset(&info
, 0, sizeof(BTREEINFO
));
399 mp
= mparse_alloc(MPARSE_AUTO
, MANDOCLEVEL_FATAL
, NULL
, NULL
, NULL
);
401 memset(&buf
, 0, sizeof(struct buf
));
402 memset(&dbuf
, 0, sizeof(struct buf
));
404 buf
.size
= dbuf
.size
= MANDOC_BUFSZ
;
406 buf
.cp
= mandoc_malloc(buf
.size
);
407 dbuf
.cp
= mandoc_malloc(dbuf
.size
);
410 ofile_argbuild(argc
, argv
, &of
, ".");
413 index_merge(of
, mp
, &dbuf
, &buf
,
414 hash
, &mdb
, &recs
, ".");
418 if (OP_UPDATE
== op
|| OP_DELETE
== op
) {
419 strlcat(mdb
.dbn
, dir
, MAXPATHLEN
);
420 strlcat(mdb
.dbn
, "/", MAXPATHLEN
);
421 sz1
= strlcat(mdb
.dbn
, MANDOC_DB
, MAXPATHLEN
);
423 strlcat(mdb
.idxn
, dir
, MAXPATHLEN
);
424 strlcat(mdb
.idxn
, "/", MAXPATHLEN
);
425 sz2
= strlcat(mdb
.idxn
, MANDOC_IDX
, MAXPATHLEN
);
427 if (sz1
>= MAXPATHLEN
|| sz2
>= MAXPATHLEN
) {
428 fprintf(stderr
, "%s: path too long\n", dir
);
429 exit((int)MANDOCLEVEL_BADARG
);
432 flags
= O_CREAT
| O_RDWR
;
433 mdb
.db
= dbopen(mdb
.dbn
, flags
, 0644, DB_BTREE
, &info
);
434 mdb
.idx
= dbopen(mdb
.idxn
, flags
, 0644, DB_RECNO
, NULL
);
436 if (NULL
== mdb
.db
) {
438 exit((int)MANDOCLEVEL_SYSERR
);
439 } else if (NULL
== mdb
.idx
) {
441 exit((int)MANDOCLEVEL_SYSERR
);
444 ofile_argbuild(argc
, argv
, &of
, dir
);
449 index_prune(of
, &mdb
, &recs
, dir
);
452 * Go to the root of the respective manual tree.
453 * This must work or no manuals may be found (they're
454 * indexed relative to the root).
457 if (OP_UPDATE
== op
) {
458 if (-1 == chdir(dir
)) {
460 exit((int)MANDOCLEVEL_SYSERR
);
462 index_merge(of
, mp
, &dbuf
, &buf
, hash
,
470 * Configure the directories we're going to scan.
471 * If we have command-line arguments, use them.
472 * If not, we use man(1)'s method (see mandocdb.8).
476 dirs
.paths
= mandoc_calloc(argc
, sizeof(char *));
478 for (i
= 0; i
< argc
; i
++)
479 dirs
.paths
[i
] = mandoc_strdup(argv
[i
]);
481 manpath_parse(&dirs
, dir
, NULL
, NULL
);
483 for (i
= 0; i
< dirs
.sz
; i
++) {
485 * Go to the root of the respective manual tree.
486 * This must work or no manuals may be found:
487 * They are indexed relative to the root.
490 if (-1 == chdir(dirs
.paths
[i
])) {
491 perror(dirs
.paths
[i
]);
492 exit((int)MANDOCLEVEL_SYSERR
);
495 strlcpy(mdb
.dbn
, MANDOC_DB
, MAXPATHLEN
);
496 strlcpy(mdb
.idxn
, MANDOC_IDX
, MAXPATHLEN
);
498 flags
= O_CREAT
| O_TRUNC
| O_RDWR
;
499 mdb
.db
= dbopen(mdb
.dbn
, flags
, 0644, DB_BTREE
, &info
);
500 mdb
.idx
= dbopen(mdb
.idxn
, flags
, 0644, DB_RECNO
, NULL
);
502 if (NULL
== mdb
.db
) {
504 exit((int)MANDOCLEVEL_SYSERR
);
505 } else if (NULL
== mdb
.idx
) {
507 exit((int)MANDOCLEVEL_SYSERR
);
511 * Search for manuals and fill the new database.
514 strlcpy(dirbuf
, dirs
.paths
[i
], MAXPATHLEN
);
515 ofile_dirbuild(".", "", "", 0, &of
, dirbuf
);
518 index_merge(of
, mp
, &dbuf
, &buf
, hash
,
519 &mdb
, &recs
, dirs
.paths
[i
]);
524 (*mdb
.db
->close
)(mdb
.db
);
525 (*mdb
.idx
->close
)(mdb
.idx
);
532 (*mdb
.db
->close
)(mdb
.db
);
534 (*mdb
.idx
->close
)(mdb
.idx
);
536 (*hash
->close
)(hash
);
546 return(MANDOCLEVEL_OK
);
550 "usage: %s [-av] [-C file] | dir ... | -t file ...\n"
551 " -d dir [file ...] | "
552 "-u dir [file ...]\n",
555 return((int)MANDOCLEVEL_BADARG
);
559 index_merge(const struct of
*of
, struct mparse
*mp
,
560 struct buf
*dbuf
, struct buf
*buf
, DB
*hash
,
561 struct mdb
*mdb
, struct recs
*recs
,
567 DB
*files
; /* temporary file name table */
568 char emptystring
[1] = {'\0'};
572 const char *fn
, *msec
, *march
, *mtitle
;
585 for (of
= of
->first
; of
; of
= of
->next
) {
589 * Try interpreting the file as mdoc(7) or man(7)
590 * source code, unless it is already known to be
591 * formatted. Fall back to formatted mode.
598 if ((MANDOC_SRC
& of
->src_form
||
599 ! (MANDOC_FORM
& of
->src_form
)) &&
600 MANDOCLEVEL_FATAL
> mparse_readfd(mp
, -1, fn
))
601 mparse_result(mp
, &mdoc
, &man
);
604 msec
= mdoc_meta(mdoc
)->msec
;
605 march
= mdoc_meta(mdoc
)->arch
;
608 mtitle
= mdoc_meta(mdoc
)->title
;
609 } else if (NULL
!= man
) {
610 msec
= man_meta(man
)->msec
;
612 mtitle
= man_meta(man
)->title
;
620 * Check whether the manual section given in a file
621 * agrees with the directory where the file is located.
622 * Some manuals have suffixes like (3p) on their
623 * section number either inside the file or in the
624 * directory name, some are linked into more than one
625 * section, like encrypt(1) = makekey(8). Do not skip
626 * manuals for such reasons.
632 if (strcasecmp(msec
, of
->sec
))
633 WARNING(fn
, basedir
, "Section \"%s\" manual "
634 "in \"%s\" directory", msec
, of
->sec
);
636 * Manual page directories exist for each kernel
637 * architecture as returned by machine(1).
638 * However, many manuals only depend on the
639 * application architecture as returned by arch(1).
640 * For example, some (2/ARM) manuals are shared
641 * across the "armish" and "zaurus" kernel
643 * A few manuals are even shared across completely
644 * different architectures, for example fdformat(1)
645 * on amd64, i386, sparc, and sparc64.
646 * Thus, warn about architecture mismatches,
647 * but don't skip manuals for this reason.
652 if (strcasecmp(march
, of
->arch
))
653 WARNING(fn
, basedir
, "Architecture \"%s\" "
654 "manual in \"%s\" directory",
658 * By default, skip a file if the title given
659 * in the file disagrees with the file name.
660 * Do not warn, this happens for all MLINKs.
665 if (strcasecmp(mtitle
, of
->title
))
669 * Build a title string for the file. If it matches
670 * the location of the file, remember the title as
671 * found; else, remember it as missing.
676 buf_appendb(buf
, mtitle
, strlen(mtitle
));
677 buf_appendb(buf
, "(", 1);
678 buf_appendb(buf
, msec
, strlen(msec
));
679 if ('\0' != *march
) {
680 buf_appendb(buf
, "/", 1);
681 buf_appendb(buf
, march
, strlen(march
));
683 buf_appendb(buf
, ")", 2);
684 for (p
= buf
->cp
; '\0' != *p
; p
++)
691 val
.data
= emptystring
;
693 ch
= (*files
->get
)(files
, &key
, &val
, 0);
696 exit((int)MANDOCLEVEL_SYSERR
);
698 val
.data
= (void *)fn
;
699 val
.size
= strlen(fn
) + 1;
703 if (NULL
!= val
.data
&&
704 (*files
->put
)(files
, &key
, &val
, 0) < 0) {
706 exit((int)MANDOCLEVEL_SYSERR
);
710 if (skip
&& !use_all
)
714 * The index record value consists of a nil-terminated
715 * filename, a nil-terminated manual section, and a
716 * nil-terminated description. Use the actual
717 * location of the file, such that the user can find
718 * it with man(1). Since the description may not be
719 * set, we set a sentinel to see if we're going to
720 * write a nil byte in its place.
724 type
= mdoc
? 'd' : (man
? 'a' : 'c');
725 buf_appendb(dbuf
, &type
, 1);
726 buf_appendb(dbuf
, fn
, strlen(fn
) + 1);
727 buf_appendb(dbuf
, of
->sec
, strlen(of
->sec
) + 1);
728 buf_appendb(dbuf
, of
->title
, strlen(of
->title
) + 1);
729 buf_appendb(dbuf
, of
->arch
, strlen(of
->arch
) + 1);
734 * Collect keyword/mask pairs.
735 * Each pair will become a new btree node.
740 pmdoc_node(hash
, buf
, dbuf
,
741 mdoc_node(mdoc
), mdoc_meta(mdoc
));
743 pman_node(hash
, buf
, dbuf
, man_node(man
));
745 pformatted(hash
, buf
, dbuf
, of
, basedir
);
747 /* Test mode, do not access any database. */
749 if (NULL
== mdb
->db
|| NULL
== mdb
->idx
)
753 * Make sure the file name is always registered
754 * as an .Nm search key.
757 buf_append(buf
, of
->title
);
758 hash_put(hash
, buf
, TYPE_Nm
);
761 * Reclaim an empty index record, if available.
762 * Use its record number for all new btree nodes.
767 rec
= recs
->stack
[(int)recs
->cur
];
768 } else if (recs
->last
> 0) {
773 vbuf
[1] = htobe64(rec
);
776 * Copy from the in-memory hashtable of pending
777 * keyword/mask pairs into the database.
781 while (0 == (ch
= (*hash
->seq
)(hash
, &key
, &val
, seq
))) {
783 assert(sizeof(uint64_t) == val
.size
);
784 memcpy(&mask
, val
.data
, val
.size
);
785 vbuf
[0] = htobe64(mask
);
786 val
.size
= sizeof(vbuf
);
788 dbt_put(mdb
->db
, mdb
->dbn
, &key
, &val
);
792 exit((int)MANDOCLEVEL_SYSERR
);
796 * Apply to the index. If we haven't had a description
797 * set, put an empty one in now.
801 buf_appendb(dbuf
, "", 1);
804 key
.size
= sizeof(recno_t
);
807 val
.size
= dbuf
->len
;
810 printf("%s: Adding to index: %s\n", basedir
, fn
);
812 dbt_put(mdb
->idx
, mdb
->idxn
, &key
, &val
);
816 * Iterate the remembered file titles and check that
817 * all files can be found by their main title.
822 while (0 == (*files
->seq
)(files
, &key
, &val
, seq
)) {
825 WARNING((char *)val
.data
, basedir
,
826 "Probably unreachable, title "
827 "is %s", (char *)key
.data
);
829 (*files
->close
)(files
);
834 * Scan through all entries in the index file `idx' and prune those
835 * entries in `ofile'.
836 * Pruning consists of removing from `db', then invalidating the entry
837 * in `idx' (zeroing its value size).
840 index_prune(const struct of
*ofile
, struct mdb
*mdb
,
841 struct recs
*recs
, const char *basedir
)
852 while (0 == (ch
= (*mdb
->idx
->seq
)(mdb
->idx
, &key
, &val
, seq
))) {
854 assert(sizeof(recno_t
) == key
.size
);
855 memcpy(&recs
->last
, key
.data
, key
.size
);
857 /* Deleted records are zero-sized. Skip them. */
863 * Make sure we're sane.
864 * Read past our mdoc/man/cat type to the next string,
865 * then make sure it's bounded by a NUL.
866 * Failing any of these, we go into our error handler.
869 fn
= (char *)val
.data
+ 1;
870 if (NULL
== memchr(fn
, '\0', val
.size
- 1))
874 * Search for the file in those we care about.
875 * XXX: build this into a tree. Too slow.
878 for (of
= ofile
->first
; of
; of
= of
->next
)
879 if (0 == strcmp(fn
, of
->fname
))
886 * Search through the keyword database, throwing out all
887 * references to our file.
891 while (0 == (ch
= (*mdb
->db
->seq
)(mdb
->db
,
892 &key
, &val
, sseq
))) {
894 if (sizeof(vbuf
) != val
.size
)
897 memcpy(vbuf
, val
.data
, val
.size
);
898 if (recs
->last
!= betoh64(vbuf
[1]))
901 if ((ch
= (*mdb
->db
->del
)(mdb
->db
,
902 &key
, R_CURSOR
)) < 0)
908 exit((int)MANDOCLEVEL_SYSERR
);
909 } else if (1 != ch
) {
910 fprintf(stderr
, "%s: corrupt database\n",
912 exit((int)MANDOCLEVEL_SYSERR
);
916 printf("%s: Deleting from index: %s\n",
920 ch
= (*mdb
->idx
->put
)(mdb
->idx
, &key
, &val
, R_CURSOR
);
925 if (recs
->cur
>= recs
->size
) {
926 recs
->size
+= MANDOC_SLOP
;
927 recs
->stack
= mandoc_realloc(recs
->stack
,
928 recs
->size
* sizeof(recno_t
));
931 recs
->stack
[(int)recs
->cur
] = recs
->last
;
937 exit((int)MANDOCLEVEL_SYSERR
);
938 } else if (1 != ch
) {
939 fprintf(stderr
, "%s: corrupt index\n", mdb
->idxn
);
940 exit((int)MANDOCLEVEL_SYSERR
);
947 * Grow the buffer (if necessary) and copy in a binary string.
950 buf_appendb(struct buf
*buf
, const void *cp
, size_t sz
)
953 /* Overshoot by MANDOC_BUFSZ. */
955 while (buf
->len
+ sz
>= buf
->size
) {
956 buf
->size
= buf
->len
+ sz
+ MANDOC_BUFSZ
;
957 buf
->cp
= mandoc_realloc(buf
->cp
, buf
->size
);
960 memcpy(buf
->cp
+ (int)buf
->len
, cp
, sz
);
965 * Append a nil-terminated string to the buffer.
966 * This can be invoked multiple times.
967 * The buffer string will be nil-terminated.
968 * If invoked multiple times, a space is put between strings.
971 buf_append(struct buf
*buf
, const char *cp
)
975 if (0 == (sz
= strlen(cp
)))
979 buf
->cp
[(int)buf
->len
- 1] = ' ';
981 buf_appendb(buf
, cp
, sz
+ 1);
985 * Recursively add all text from a given node.
986 * This is optimised for general mdoc nodes in this context, which do
987 * not consist of subexpressions and having a recursive call for n->next
989 * The "f" variable should be 0 unless called from pmdoc_Nd for the
990 * description buffer, which does not start at the beginning of the
994 buf_appendmdoc(struct buf
*buf
, const struct mdoc_node
*n
, int f
)
997 for ( ; n
; n
= n
->next
) {
999 buf_appendmdoc(buf
, n
->child
, f
);
1001 if (MDOC_TEXT
== n
->type
&& f
) {
1003 buf_appendb(buf
, n
->string
,
1004 strlen(n
->string
) + 1);
1005 } else if (MDOC_TEXT
== n
->type
)
1006 buf_append(buf
, n
->string
);
1016 if (NULL
!= (hash
= *db
))
1017 (*hash
->close
)(hash
);
1019 *db
= dbopen(NULL
, O_CREAT
|O_RDWR
, 0644, DB_HASH
, NULL
);
1022 exit((int)MANDOCLEVEL_SYSERR
);
1028 pmdoc_head(MDOC_ARGS
)
1031 return(MDOC_HEAD
== n
->type
);
1036 pmdoc_body(MDOC_ARGS
)
1039 return(MDOC_BODY
== n
->type
);
1046 const char *start
, *end
;
1049 if (SEC_SYNOPSIS
!= n
->sec
)
1051 if (NULL
== (n
= n
->child
) || MDOC_TEXT
!= n
->type
)
1055 * Only consider those `Fd' macro fields that begin with an
1056 * "inclusion" token (versus, e.g., #define).
1058 if (strcmp("#include", n
->string
))
1061 if (NULL
== (n
= n
->next
) || MDOC_TEXT
!= n
->type
)
1065 * Strip away the enclosing angle brackets and make sure we're
1070 if ('<' == *start
|| '"' == *start
)
1073 if (0 == (sz
= strlen(start
)))
1076 end
= &start
[(int)sz
- 1];
1077 if ('>' == *end
|| '"' == *end
)
1080 assert(end
>= start
);
1082 buf_appendb(buf
, start
, (size_t)(end
- start
+ 1));
1083 buf_appendb(buf
, "", 1);
1092 if (NULL
== n
->child
|| MDOC_TEXT
!= n
->child
->type
)
1095 buf_append(buf
, n
->child
->string
);
1103 struct mdoc_node
*nn
;
1108 if (NULL
== nn
|| MDOC_TEXT
!= nn
->type
)
1111 /* .Fn "struct type *name" "char *arg" */
1113 cp
= strrchr(nn
->string
, ' ');
1117 /* Strip away pointer symbol. */
1122 /* Store the function name. */
1124 buf_append(buf
, cp
);
1125 hash_put(hash
, buf
, TYPE_Fn
);
1127 /* Store the function type. */
1129 if (nn
->string
< cp
) {
1131 buf_appendb(buf
, nn
->string
, cp
- nn
->string
);
1132 buf_appendb(buf
, "", 1);
1133 hash_put(hash
, buf
, TYPE_Ft
);
1136 /* Store the arguments. */
1138 for (nn
= nn
->next
; nn
; nn
= nn
->next
) {
1139 if (MDOC_TEXT
!= nn
->type
)
1142 buf_append(buf
, nn
->string
);
1143 hash_put(hash
, buf
, TYPE_Fa
);
1154 if (NULL
== n
->child
|| MDOC_TEXT
!= n
->child
->type
)
1157 buf_append(buf
, n
->child
->string
);
1166 if (NULL
== (n
= n
->child
))
1169 buf_appendb(buf
, n
->string
, strlen(n
->string
));
1171 if (NULL
!= (n
= n
->next
)) {
1172 buf_appendb(buf
, ".", 1);
1173 buf_appendb(buf
, n
->string
, strlen(n
->string
) + 1);
1175 buf_appendb(buf
, ".", 2);
1185 if (MDOC_BODY
!= n
->type
)
1188 buf_appendmdoc(dbuf
, n
->child
, 1);
1197 if (SEC_NAME
== n
->sec
)
1199 else if (SEC_SYNOPSIS
!= n
->sec
|| MDOC_HEAD
!= n
->type
)
1202 if (NULL
== n
->child
)
1203 buf_append(buf
, m
->name
);
1213 return(SEC_CUSTOM
== n
->sec
&& MDOC_HEAD
== n
->type
);
1217 hash_put(DB
*db
, const struct buf
*buf
, uint64_t mask
)
1227 key
.size
= buf
->len
;
1229 if ((rc
= (*db
->get
)(db
, &key
, &val
, 0)) < 0) {
1231 exit((int)MANDOCLEVEL_SYSERR
);
1232 } else if (0 == rc
) {
1233 assert(sizeof(uint64_t) == val
.size
);
1234 memcpy(&oldmask
, val
.data
, val
.size
);
1239 val
.size
= sizeof(uint64_t);
1241 if ((rc
= (*db
->put
)(db
, &key
, &val
, 0)) < 0) {
1243 exit((int)MANDOCLEVEL_SYSERR
);
1248 dbt_put(DB
*db
, const char *dbn
, DBT
*key
, DBT
*val
)
1254 if (0 == (*db
->put
)(db
, key
, val
, 0))
1258 exit((int)MANDOCLEVEL_SYSERR
);
1263 * Call out to per-macro handlers after clearing the persistent database
1264 * key. If the macro sets the database key, flush it to the database.
1267 pmdoc_node(MDOC_ARGS
)
1286 * Both NULL handlers and handlers returning true
1287 * request using the data. Only skip the element
1288 * when the handler returns false.
1291 if (NULL
!= mdocs
[n
->tok
].fp
&&
1292 0 == (*mdocs
[n
->tok
].fp
)(hash
, buf
, dbuf
, n
, m
))
1296 * For many macros, use the text from all children.
1297 * Set zero flags for macros not needing this.
1298 * In that case, the handler must fill the buffer.
1301 if (MDOCF_CHILD
& mdocs
[n
->tok
].flags
)
1302 buf_appendmdoc(buf
, n
->child
, 0);
1305 * Cover the most common case:
1306 * Automatically stage one string per element.
1307 * Set a zero mask for macros not needing this.
1308 * Additional staging can be done in the handler.
1311 if (mdocs
[n
->tok
].mask
)
1312 hash_put(hash
, buf
, mdocs
[n
->tok
].mask
);
1318 pmdoc_node(hash
, buf
, dbuf
, n
->child
, m
);
1319 pmdoc_node(hash
, buf
, dbuf
, n
->next
, m
);
1325 const struct man_node
*head
, *body
;
1326 char *start
, *sv
, *title
;
1333 * We're only searching for one thing: the first text child in
1334 * the BODY of a NAME section. Since we don't keep track of
1335 * sections in -man, run some hoops to find out whether we're in
1336 * the correct section or not.
1339 if (MAN_BODY
== n
->type
&& MAN_SH
== n
->tok
) {
1341 assert(body
->parent
);
1342 if (NULL
!= (head
= body
->parent
->head
) &&
1343 1 == head
->nchild
&&
1344 NULL
!= (head
= (head
->child
)) &&
1345 MAN_TEXT
== head
->type
&&
1346 0 == strcmp(head
->string
, "NAME") &&
1347 NULL
!= (body
= body
->child
) &&
1348 MAN_TEXT
== body
->type
) {
1353 * Suck the entire NAME section into memory.
1354 * Yes, we might run away.
1355 * But too many manuals have big, spread-out
1356 * NAME sections over many lines.
1358 for ( ; NULL
!= body
; body
= body
->next
) {
1359 if (MAN_TEXT
!= body
->type
)
1361 if (0 == (sz
= strlen(body
->string
)))
1363 title
= mandoc_realloc
1364 (title
, titlesz
+ sz
+ 1);
1365 memcpy(title
+ titlesz
, body
->string
, sz
);
1367 title
[(int)titlesz
- 1] = ' ';
1372 title
= mandoc_realloc(title
, titlesz
+ 1);
1373 title
[(int)titlesz
] = '\0';
1375 /* Skip leading space. */
1378 while (isspace((unsigned char)*sv
))
1381 if (0 == (sz
= strlen(sv
))) {
1386 /* Erase trailing space. */
1388 start
= &sv
[sz
- 1];
1389 while (start
> sv
&& isspace((unsigned char)*start
))
1400 * Go through a special heuristic dance here.
1401 * This is why -man manuals are great!
1402 * (I'm being sarcastic: my eyes are bleeding.)
1403 * Conventionally, one or more manual names are
1404 * comma-specified prior to a whitespace, then a
1405 * dash, then a description. Try to puzzle out
1406 * the name parts here.
1410 sz
= strcspn(start
, " ,");
1411 if ('\0' == start
[(int)sz
])
1415 buf_appendb(buf
, start
, sz
);
1416 buf_appendb(buf
, "", 1);
1418 hash_put(hash
, buf
, TYPE_Nm
);
1420 if (' ' == start
[(int)sz
]) {
1421 start
+= (int)sz
+ 1;
1425 assert(',' == start
[(int)sz
]);
1426 start
+= (int)sz
+ 1;
1427 while (' ' == *start
)
1434 buf_append(buf
, start
);
1439 while (isspace((unsigned char)*start
))
1442 if (0 == strncmp(start
, "-", 1))
1444 else if (0 == strncmp(start
, "\\-\\-", 4))
1446 else if (0 == strncmp(start
, "\\-", 2))
1448 else if (0 == strncmp(start
, "\\(en", 4))
1450 else if (0 == strncmp(start
, "\\(em", 4))
1453 while (' ' == *start
)
1456 sz
= strlen(start
) + 1;
1457 buf_appendb(dbuf
, start
, sz
);
1458 buf_appendb(buf
, start
, sz
);
1460 hash_put(hash
, buf
, TYPE_Nd
);
1465 for (n
= n
->child
; n
; n
= n
->next
)
1466 if (pman_node(hash
, buf
, dbuf
, n
))
1473 * Parse a formatted manual page.
1474 * By necessity, this involves rather crude guesswork.
1477 pformatted(DB
*hash
, struct buf
*buf
, struct buf
*dbuf
,
1478 const struct of
*of
, const char *basedir
)
1481 char *line
, *p
, *title
;
1482 size_t len
, plen
, titlesz
;
1484 if (NULL
== (stream
= fopen(of
->fname
, "r"))) {
1485 WARNING(of
->fname
, basedir
, "%s", strerror(errno
));
1490 * Always use the title derived from the filename up front,
1491 * do not even try to find it in the file. This also makes
1492 * sure we don't end up with an orphan index record, even if
1493 * the file content turns out to be completely unintelligible.
1497 buf_append(buf
, of
->title
);
1498 hash_put(hash
, buf
, TYPE_Nm
);
1500 /* Skip to first blank line. */
1502 while (NULL
!= (line
= fgetln(stream
, &len
)))
1507 * Assume the first line that is not indented
1508 * is the first section header. Skip to it.
1511 while (NULL
!= (line
= fgetln(stream
, &len
)))
1512 if ('\n' != *line
&& ' ' != *line
)
1516 * Read up until the next section into a buffer.
1517 * Strip the leading and trailing newline from each read line,
1518 * appending a trailing space.
1519 * Ignore empty (whitespace-only) lines.
1525 while (NULL
!= (line
= fgetln(stream
, &len
))) {
1526 if (' ' != *line
|| '\n' != line
[(int)len
- 1])
1528 while (len
> 0 && isspace((unsigned char)*line
)) {
1534 title
= mandoc_realloc(title
, titlesz
+ len
);
1535 memcpy(title
+ titlesz
, line
, len
);
1537 title
[(int)titlesz
- 1] = ' ';
1541 * If no page content can be found, or the input line
1542 * is already the next section header, or there is no
1543 * trailing newline, reuse the page title as the page
1547 if (NULL
== title
|| '\0' == *title
) {
1548 WARNING(of
->fname
, basedir
,
1549 "Cannot find NAME section");
1550 buf_appendb(dbuf
, buf
->cp
, buf
->size
);
1551 hash_put(hash
, buf
, TYPE_Nd
);
1557 title
= mandoc_realloc(title
, titlesz
+ 1);
1558 title
[(int)titlesz
] = '\0';
1561 * Skip to the first dash.
1562 * Use the remaining line as the description (no more than 70
1566 if (NULL
!= (p
= strstr(title
, "- "))) {
1567 for (p
+= 2; ' ' == *p
|| '\b' == *p
; p
++)
1568 /* Skip to next word. */ ;
1570 WARNING(of
->fname
, basedir
,
1571 "No dash in title line");
1577 /* Strip backspace-encoding from line. */
1579 while (NULL
!= (line
= memchr(p
, '\b', plen
))) {
1582 memmove(line
, line
+ 1, plen
--);
1585 memmove(line
- 1, line
+ 1, plen
- len
);
1589 buf_appendb(dbuf
, p
, plen
+ 1);
1591 buf_appendb(buf
, p
, plen
+ 1);
1592 hash_put(hash
, buf
, TYPE_Nd
);
1598 ofile_argbuild(int argc
, char *argv
[],
1599 struct of
**of
, const char *basedir
)
1601 char buf
[MAXPATHLEN
];
1602 const char *sec
, *arch
, *title
;
1607 for (i
= 0; i
< argc
; i
++) {
1610 * Try to infer the manual section, architecture and
1611 * page title from the path, assuming it looks like
1612 * man*[/<arch>]/<title>.<section> or
1613 * cat<section>[/<arch>]/<title>.0
1616 if (strlcpy(buf
, argv
[i
], sizeof(buf
)) >= sizeof(buf
)) {
1617 fprintf(stderr
, "%s: Path too long\n", argv
[i
]);
1620 sec
= arch
= title
= "";
1622 p
= strrchr(buf
, '\0');
1624 if ('\0' == *sec
&& '.' == *p
) {
1628 src_form
|= MANDOC_FORM
;
1629 else if ('1' <= *sec
&& '9' >= *sec
)
1630 src_form
|= MANDOC_SRC
;
1635 if ('\0' == *title
) {
1640 if (0 == strncmp("man", p
+ 1, 3))
1641 src_form
|= MANDOC_SRC
;
1642 else if (0 == strncmp("cat", p
+ 1, 3))
1643 src_form
|= MANDOC_FORM
;
1648 if ('\0' == *title
) {
1649 WARNING(argv
[i
], basedir
,
1650 "Cannot deduce title from filename");
1655 * Build the file structure.
1658 nof
= mandoc_calloc(1, sizeof(struct of
));
1659 nof
->fname
= mandoc_strdup(argv
[i
]);
1660 nof
->sec
= mandoc_strdup(sec
);
1661 nof
->arch
= mandoc_strdup(arch
);
1662 nof
->title
= mandoc_strdup(title
);
1663 nof
->src_form
= src_form
;
1666 * Add the structure to the list.
1673 nof
->first
= (*of
)->first
;
1681 * Recursively build up a list of files to parse.
1682 * We use this instead of ftw() and so on because I don't want global
1683 * variables hanging around.
1684 * This ignores the mandocdb.db and mandocdb.index files, but assumes that
1685 * everything else is a manual.
1686 * Pass in a pointer to a NULL structure for the first invocation.
1689 ofile_dirbuild(const char *dir
, const char* psec
, const char *parch
,
1690 int p_src_form
, struct of
**of
, char *basedir
)
1692 char buf
[MAXPATHLEN
];
1695 const char *fn
, *sec
, *arch
;
1696 char *p
, *q
, *suffix
;
1701 if (NULL
== (d
= opendir(dir
))) {
1702 WARNING("", dir
, "%s", strerror(errno
));
1706 while (NULL
!= (dp
= readdir(d
))) {
1712 src_form
= p_src_form
;
1714 if (DT_DIR
== dp
->d_type
) {
1719 * By default, only use directories called:
1720 * man<section>/[<arch>/] or
1721 * cat<section>/[<arch>/]
1725 if(0 == strncmp("man", fn
, 3)) {
1726 src_form
|= MANDOC_SRC
;
1728 } else if (0 == strncmp("cat", fn
, 3)) {
1729 src_form
|= MANDOC_FORM
;
1732 WARNING(fn
, basedir
, "Bad section");
1738 } else if ('\0' == *arch
) {
1739 if (NULL
!= strchr(fn
, '.')) {
1740 WARNING(fn
, basedir
, "Bad architecture");
1746 WARNING(fn
, basedir
, "Excessive subdirectory");
1752 strlcat(buf
, dir
, MAXPATHLEN
);
1753 strlcat(buf
, "/", MAXPATHLEN
);
1754 strlcat(basedir
, "/", MAXPATHLEN
);
1755 strlcat(basedir
, fn
, MAXPATHLEN
);
1756 sz
= strlcat(buf
, fn
, MAXPATHLEN
);
1758 if (MAXPATHLEN
<= sz
) {
1759 WARNING(fn
, basedir
, "Path too long");
1763 ofile_dirbuild(buf
, sec
, arch
,
1764 src_form
, of
, basedir
);
1766 p
= strrchr(basedir
, '/');
1771 if (DT_REG
!= dp
->d_type
) {
1772 WARNING(fn
, basedir
, "Not a regular file");
1775 if (!strcmp(MANDOC_DB
, fn
) || !strcmp(MANDOC_IDX
, fn
))
1777 if ('\0' == *psec
) {
1778 WARNING(fn
, basedir
, "File outside section");
1784 * By default, skip files where the file name suffix
1785 * does not agree with the section directory
1786 * they are located in.
1789 suffix
= strrchr(fn
, '.');
1790 if (NULL
== suffix
) {
1791 WARNING(fn
, basedir
, "No filename suffix");
1794 } else if ((MANDOC_SRC
& src_form
&&
1795 strcmp(suffix
+ 1, psec
)) ||
1796 (MANDOC_FORM
& src_form
&&
1797 strcmp(suffix
+ 1, "0"))) {
1798 WARNING(fn
, basedir
, "Wrong filename suffix");
1801 if ('0' == suffix
[1])
1802 src_form
|= MANDOC_FORM
;
1803 else if ('1' <= suffix
[1] && '9' >= suffix
[1])
1804 src_form
|= MANDOC_SRC
;
1808 * Skip formatted manuals if a source version is
1809 * available. Ignore the age: it is very unlikely
1810 * that people install newer formatted base manuals
1811 * when they used to have source manuals before,
1812 * and in ports, old manuals get removed on update.
1814 if (0 == use_all
&& MANDOC_FORM
& src_form
&&
1817 strlcat(buf
, dir
, MAXPATHLEN
);
1818 p
= strrchr(buf
, '/');
1819 if ('\0' != *parch
&& NULL
!= p
)
1820 for (p
--; p
> buf
; p
--)
1827 if (0 == strncmp("cat", p
, 3))
1828 memcpy(p
, "man", 3);
1829 strlcat(buf
, "/", MAXPATHLEN
);
1830 sz
= strlcat(buf
, fn
, MAXPATHLEN
);
1831 if (sz
>= MAXPATHLEN
) {
1832 WARNING(fn
, basedir
, "Path too long");
1835 q
= strrchr(buf
, '.');
1836 if (NULL
!= q
&& p
< q
++) {
1838 sz
= strlcat(buf
, psec
, MAXPATHLEN
);
1839 if (sz
>= MAXPATHLEN
) {
1840 WARNING(fn
, basedir
, "Path too long");
1843 if (0 == access(buf
, R_OK
))
1849 assert('.' == dir
[0]);
1850 if ('/' == dir
[1]) {
1851 strlcat(buf
, dir
+ 2, MAXPATHLEN
);
1852 strlcat(buf
, "/", MAXPATHLEN
);
1854 sz
= strlcat(buf
, fn
, MAXPATHLEN
);
1855 if (sz
>= MAXPATHLEN
) {
1856 WARNING(fn
, basedir
, "Path too long");
1860 nof
= mandoc_calloc(1, sizeof(struct of
));
1861 nof
->fname
= mandoc_strdup(buf
);
1862 nof
->sec
= mandoc_strdup(psec
);
1863 nof
->arch
= mandoc_strdup(parch
);
1864 nof
->src_form
= src_form
;
1867 * Remember the file name without the extension,
1868 * to be used as the page title in the database.
1873 nof
->title
= mandoc_strdup(fn
);
1876 * Add the structure to the list.
1883 nof
->first
= (*of
)->first
;
1893 ofile_free(struct of
*of
)
1900 while (NULL
!= of
) {