]>
git.cameronkatri.com Git - mandoc.git/blob - mandocdb.c
1 /* $Id: mandocdb.c,v 1.10 2011/11/23 09:52:20 kristaps Exp $ */
3 * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include <sys/param.h>
44 #define MANDOC_BUFSZ BUFSIZ
45 #define MANDOC_SLOP 1024
47 /* Tiny list for files. No need to bring in QUEUE. */
50 char *fname
; /* heap-allocated */
51 struct of
*next
; /* NULL for last one */
52 struct of
*first
; /* first in list */
55 /* Buffer for storing growable data. */
59 size_t len
; /* current length */
60 size_t size
; /* total buffer size */
63 /* Operation we're going to perform. */
66 OP_NEW
= 0, /* new database */
67 OP_UPDATE
, /* delete/add entries in existing database */
68 OP_DELETE
/* delete entries from existing database */
71 #define MAN_ARGS DB *hash, \
74 const struct man_node *n
75 #define MDOC_ARGS DB *hash, \
78 const struct mdoc_node *n, \
79 const struct mdoc_meta *m
81 static void buf_appendmdoc(struct buf
*,
82 const struct mdoc_node
*, int);
83 static void buf_append(struct buf
*, const char *);
84 static void buf_appendb(struct buf
*,
85 const void *, size_t);
86 static void dbt_put(DB
*, const char *, DBT
*, DBT
*);
87 static void hash_put(DB
*, const struct buf
*, uint64_t);
88 static void hash_reset(DB
**);
89 static void index_merge(const struct of
*, struct mparse
*,
90 struct buf
*, struct buf
*,
91 DB
*, DB
*, const char *,
92 DB
*, const char *, int,
93 recno_t
, const recno_t
*, size_t);
94 static void index_prune(const struct of
*, DB
*,
95 const char *, DB
*, const char *,
96 int, recno_t
*, recno_t
**, size_t *);
97 static void ofile_argbuild(char *[], int, int, struct of
**);
98 static int ofile_dirbuild(const char *, int, struct of
**);
99 static void ofile_free(struct of
*);
100 static int pman_node(MAN_ARGS
);
101 static void pmdoc_node(MDOC_ARGS
);
102 static void pmdoc_An(MDOC_ARGS
);
103 static void pmdoc_Cd(MDOC_ARGS
);
104 static void pmdoc_Er(MDOC_ARGS
);
105 static void pmdoc_Ev(MDOC_ARGS
);
106 static void pmdoc_Fd(MDOC_ARGS
);
107 static void pmdoc_In(MDOC_ARGS
);
108 static void pmdoc_Fn(MDOC_ARGS
);
109 static void pmdoc_Fo(MDOC_ARGS
);
110 static void pmdoc_Nd(MDOC_ARGS
);
111 static void pmdoc_Nm(MDOC_ARGS
);
112 static void pmdoc_Pa(MDOC_ARGS
);
113 static void pmdoc_St(MDOC_ARGS
);
114 static void pmdoc_Vt(MDOC_ARGS
);
115 static void pmdoc_Xr(MDOC_ARGS
);
116 static void usage(void);
118 typedef void (*pmdoc_nf
)(MDOC_ARGS
);
120 static const pmdoc_nf mdocs
[MDOC_MAX
] = {
245 static const char *progname
;
248 main(int argc
, char *argv
[])
250 struct mparse
*mp
; /* parse sequence */
251 struct manpaths dirs
;
252 enum op op
; /* current operation */
254 char ibuf
[MAXPATHLEN
], /* index fname */
255 fbuf
[MAXPATHLEN
]; /* btree fname */
256 int verb
, /* output verbosity */
258 DB
*idx
, /* index database */
259 *db
, /* keyword database */
260 *hash
; /* temporary keyword hashtable */
261 BTREEINFO info
; /* btree configuration */
262 recno_t maxrec
; /* supremum of all records */
263 recno_t
*recs
; /* buffer of empty records */
265 recsz
, /* buffer size of recs */
266 reccur
; /* valid number of recs */
267 struct buf buf
, /* keyword buffer */
268 dbuf
; /* description buffer */
269 struct of
*of
; /* list of files for processing */
273 progname
= strrchr(argv
[0], '/');
274 if (progname
== NULL
)
279 memset(&dirs
, 0, sizeof(struct manpaths
));
292 while (-1 != (ch
= getopt(argc
, argv
, "d:u:v")))
307 return((int)MANDOCLEVEL_BADARG
);
313 memset(&info
, 0, sizeof(BTREEINFO
));
316 mp
= mparse_alloc(MPARSE_AUTO
, MANDOCLEVEL_FATAL
, NULL
, NULL
);
318 memset(&buf
, 0, sizeof(struct buf
));
319 memset(&dbuf
, 0, sizeof(struct buf
));
321 buf
.size
= dbuf
.size
= MANDOC_BUFSZ
;
323 buf
.cp
= mandoc_malloc(buf
.size
);
324 dbuf
.cp
= mandoc_malloc(dbuf
.size
);
326 flags
= OP_NEW
== op
? O_CREAT
|O_TRUNC
|O_RDWR
: O_CREAT
|O_RDWR
;
328 if (OP_UPDATE
== op
|| OP_DELETE
== op
) {
329 ibuf
[0] = fbuf
[0] = '\0';
331 strlcat(fbuf
, dir
, MAXPATHLEN
);
332 strlcat(fbuf
, "/", MAXPATHLEN
);
333 sz1
= strlcat(fbuf
, MANDOC_DB
, MAXPATHLEN
);
335 strlcat(ibuf
, dir
, MAXPATHLEN
);
336 strlcat(ibuf
, "/", MAXPATHLEN
);
337 sz2
= strlcat(ibuf
, MANDOC_IDX
, MAXPATHLEN
);
339 if (sz1
>= MAXPATHLEN
|| sz2
>= MAXPATHLEN
) {
340 fprintf(stderr
, "%s: Path too long\n", dir
);
341 exit((int)MANDOCLEVEL_BADARG
);
344 db
= dbopen(fbuf
, flags
, 0644, DB_BTREE
, &info
);
345 idx
= dbopen(ibuf
, flags
, 0644, DB_RECNO
, NULL
);
349 exit((int)MANDOCLEVEL_SYSERR
);
350 } else if (NULL
== db
) {
352 exit((int)MANDOCLEVEL_SYSERR
);
356 printf("%s: Opened\n", fbuf
);
357 printf("%s: Opened\n", ibuf
);
360 ofile_argbuild(argv
, argc
, verb
, &of
);
366 index_prune(of
, db
, fbuf
, idx
, ibuf
, verb
,
367 &maxrec
, &recs
, &recsz
);
370 index_merge(of
, mp
, &dbuf
, &buf
, hash
,
371 db
, fbuf
, idx
, ibuf
, verb
,
372 maxrec
, recs
, reccur
);
378 * Configure the directories we're going to scan.
379 * If we have command-line arguments, use them.
380 * If not, we use man(1)'s method (see mandocdb.8).
384 dirs
.paths
= mandoc_malloc(argc
* sizeof(char *));
386 for (i
= 0; i
< argc
; i
++)
387 dirs
.paths
[i
] = mandoc_strdup(argv
[i
]);
389 manpath_parseconf(&dirs
);
391 for (i
= 0; i
< dirs
.sz
; i
++) {
392 ibuf
[0] = fbuf
[0] = '\0';
394 strlcat(fbuf
, dirs
.paths
[i
], MAXPATHLEN
);
395 strlcat(fbuf
, "/", MAXPATHLEN
);
396 sz1
= strlcat(fbuf
, MANDOC_DB
, MAXPATHLEN
);
398 strlcat(ibuf
, dirs
.paths
[i
], MAXPATHLEN
);
399 strlcat(ibuf
, "/", MAXPATHLEN
);
400 sz2
= strlcat(ibuf
, MANDOC_IDX
, MAXPATHLEN
);
402 if (sz1
>= MAXPATHLEN
|| sz2
>= MAXPATHLEN
) {
403 fprintf(stderr
, "%s: Path too long\n",
405 exit((int)MANDOCLEVEL_BADARG
);
408 db
= dbopen(fbuf
, flags
, 0644, DB_BTREE
, &info
);
409 idx
= dbopen(ibuf
, flags
, 0644, DB_RECNO
, NULL
);
413 exit((int)MANDOCLEVEL_SYSERR
);
414 } else if (NULL
== db
) {
416 exit((int)MANDOCLEVEL_SYSERR
);
420 printf("%s: Truncated\n", fbuf
);
421 printf("%s: Truncated\n", ibuf
);
427 if ( ! ofile_dirbuild(dirs
.paths
[i
], verb
, &of
))
428 exit((int)MANDOCLEVEL_SYSERR
);
435 index_merge(of
, mp
, &dbuf
, &buf
, hash
, db
, fbuf
,
436 idx
, ibuf
, verb
, maxrec
, recs
, reccur
);
445 (*hash
->close
)(hash
);
455 return(MANDOCLEVEL_OK
);
459 index_merge(const struct of
*of
, struct mparse
*mp
,
460 struct buf
*dbuf
, struct buf
*buf
,
461 DB
*hash
, DB
*db
, const char *dbf
,
462 DB
*idx
, const char *idxf
, int verb
,
463 recno_t maxrec
, const recno_t
*recs
, size_t reccur
)
470 const char *fn
, *msec
, *mtitle
, *arch
;
475 for (rec
= 0; of
; of
= of
->next
) {
479 rec
= recs
[(int)reccur
];
480 } else if (maxrec
> 0) {
489 if (mparse_readfd(mp
, -1, fn
) >= MANDOCLEVEL_FATAL
) {
490 fprintf(stderr
, "%s: Parse failure\n", fn
);
494 mparse_result(mp
, &mdoc
, &man
);
495 if (NULL
== mdoc
&& NULL
== man
)
498 msec
= NULL
!= mdoc
?
499 mdoc_meta(mdoc
)->msec
: man_meta(man
)->msec
;
500 mtitle
= NULL
!= mdoc
?
501 mdoc_meta(mdoc
)->title
: man_meta(man
)->title
;
502 arch
= NULL
!= mdoc
?
503 mdoc_meta(mdoc
)->arch
: NULL
;
509 * The index record value consists of a nil-terminated
510 * filename, a nil-terminated manual section, and a
511 * nil-terminated description. Since the description
512 * may not be set, we set a sentinel to see if we're
513 * going to write a nil byte in its place.
517 buf_appendb(dbuf
, fn
, strlen(fn
) + 1);
518 buf_appendb(dbuf
, msec
, strlen(msec
) + 1);
519 buf_appendb(dbuf
, mtitle
, strlen(mtitle
) + 1);
520 buf_appendb(dbuf
, arch
, strlen(arch
) + 1);
524 /* Fix the record number in the btree value. */
527 pmdoc_node(hash
, buf
, dbuf
,
528 mdoc_node(mdoc
), mdoc_meta(mdoc
));
530 pman_node(hash
, buf
, dbuf
, man_node(man
));
533 * Copy from the in-memory hashtable of pending keywords
539 while (0 == (ch
= (*hash
->seq
)(hash
, &key
, &val
, seq
))) {
542 vbuf
.mask
= *(uint64_t *)val
.data
;
543 val
.size
= sizeof(struct db_val
);
547 printf("%s: Added keyword: %s\n",
548 fn
, (char *)key
.data
);
549 dbt_put(db
, dbf
, &key
, &val
);
553 exit((int)MANDOCLEVEL_SYSERR
);
557 * Apply to the index. If we haven't had a description
558 * set, put an empty one in now.
562 buf_appendb(dbuf
, "", 1);
565 key
.size
= sizeof(recno_t
);
568 val
.size
= dbuf
->len
;
571 printf("%s: Added index\n", fn
);
572 dbt_put(idx
, idxf
, &key
, &val
);
577 * Scan through all entries in the index file `idx' and prune those
578 * entries in `ofile'.
579 * Pruning consists of removing from `db', then invalidating the entry
580 * in `idx' (zeroing its value size).
583 index_prune(const struct of
*ofile
, DB
*db
, const char *dbf
,
584 DB
*idx
, const char *idxf
, int verb
,
585 recno_t
*maxrec
, recno_t
**recs
, size_t *recsz
)
597 while (0 == (ch
= (*idx
->seq
)(idx
, &key
, &val
, seq
))) {
599 *maxrec
= *(recno_t
*)key
.data
;
601 if (reccur
>= *recsz
) {
602 *recsz
+= MANDOC_SLOP
;
603 *recs
= mandoc_realloc(*recs
,
604 *recsz
* sizeof(recno_t
));
606 (*recs
)[(int)reccur
] = *maxrec
;
611 fn
= (char *)val
.data
;
612 for (of
= ofile
; of
; of
= of
->next
)
613 if (0 == strcmp(fn
, of
->fname
))
620 while (0 == (ch
= (*db
->seq
)(db
, &key
, &val
, sseq
))) {
622 assert(sizeof(struct db_val
) == val
.size
);
624 if (*maxrec
!= vbuf
->rec
)
627 printf("%s: Deleted keyword: %s\n",
628 fn
, (char *)key
.data
);
629 ch
= (*db
->del
)(db
, &key
, R_CURSOR
);
635 exit((int)MANDOCLEVEL_SYSERR
);
639 printf("%s: Deleted index\n", fn
);
642 ch
= (*idx
->put
)(idx
, &key
, &val
, R_CURSOR
);
645 exit((int)MANDOCLEVEL_SYSERR
);
648 if (reccur
>= *recsz
) {
649 *recsz
+= MANDOC_SLOP
;
650 *recs
= mandoc_realloc
651 (*recs
, *recsz
* sizeof(recno_t
));
654 (*recs
)[(int)reccur
] = *maxrec
;
661 * Grow the buffer (if necessary) and copy in a binary string.
664 buf_appendb(struct buf
*buf
, const void *cp
, size_t sz
)
667 /* Overshoot by MANDOC_BUFSZ. */
669 while (buf
->len
+ sz
>= buf
->size
) {
670 buf
->size
= buf
->len
+ sz
+ MANDOC_BUFSZ
;
671 buf
->cp
= mandoc_realloc(buf
->cp
, buf
->size
);
674 memcpy(buf
->cp
+ (int)buf
->len
, cp
, sz
);
679 * Append a nil-terminated string to the buffer.
680 * This can be invoked multiple times.
681 * The buffer string will be nil-terminated.
682 * If invoked multiple times, a space is put between strings.
685 buf_append(struct buf
*buf
, const char *cp
)
689 if (0 == (sz
= strlen(cp
)))
693 buf
->cp
[(int)buf
->len
- 1] = ' ';
695 buf_appendb(buf
, cp
, sz
+ 1);
699 * Recursively add all text from a given node.
700 * This is optimised for general mdoc nodes in this context, which do
701 * not consist of subexpressions and having a recursive call for n->next
703 * The "f" variable should be 0 unless called from pmdoc_Nd for the
704 * description buffer, which does not start at the beginning of the
708 buf_appendmdoc(struct buf
*buf
, const struct mdoc_node
*n
, int f
)
711 for ( ; n
; n
= n
->next
) {
713 buf_appendmdoc(buf
, n
->child
, f
);
715 if (MDOC_TEXT
== n
->type
&& f
) {
717 buf_appendb(buf
, n
->string
,
718 strlen(n
->string
) + 1);
719 } else if (MDOC_TEXT
== n
->type
)
720 buf_append(buf
, n
->string
);
730 if (SEC_AUTHORS
!= n
->sec
)
733 buf_appendmdoc(buf
, n
->child
, 0);
734 hash_put(hash
, buf
, TYPE_An
);
742 if (NULL
!= (hash
= *db
))
743 (*hash
->close
)(hash
);
745 *db
= dbopen(NULL
, O_CREAT
|O_RDWR
, 0644, DB_HASH
, NULL
);
748 exit((int)MANDOCLEVEL_SYSERR
);
756 const char *start
, *end
;
759 if (SEC_SYNOPSIS
!= n
->sec
)
761 if (NULL
== (n
= n
->child
) || MDOC_TEXT
!= n
->type
)
765 * Only consider those `Fd' macro fields that begin with an
766 * "inclusion" token (versus, e.g., #define).
768 if (strcmp("#include", n
->string
))
771 if (NULL
== (n
= n
->next
) || MDOC_TEXT
!= n
->type
)
775 * Strip away the enclosing angle brackets and make sure we're
780 if ('<' == *start
|| '"' == *start
)
783 if (0 == (sz
= strlen(start
)))
786 end
= &start
[(int)sz
- 1];
787 if ('>' == *end
|| '"' == *end
)
790 assert(end
>= start
);
792 buf_appendb(buf
, start
, (size_t)(end
- start
+ 1));
793 buf_appendb(buf
, "", 1);
795 hash_put(hash
, buf
, TYPE_In
);
803 if (SEC_SYNOPSIS
!= n
->sec
)
806 buf_appendmdoc(buf
, n
->child
, 0);
807 hash_put(hash
, buf
, TYPE_Cd
);
815 if (SEC_SYNOPSIS
!= n
->sec
)
817 if (NULL
== n
->child
|| MDOC_TEXT
!= n
->child
->type
)
820 buf_append(buf
, n
->child
->string
);
821 hash_put(hash
, buf
, TYPE_In
);
830 if (SEC_SYNOPSIS
!= n
->sec
)
832 if (NULL
== n
->child
|| MDOC_TEXT
!= n
->child
->type
)
835 /* .Fn "struct type *arg" "foo" */
837 cp
= strrchr(n
->child
->string
, ' ');
839 cp
= n
->child
->string
;
841 /* Strip away pointer symbol. */
847 hash_put(hash
, buf
, TYPE_Fn
);
855 if (SEC_STANDARDS
!= n
->sec
)
857 if (NULL
== n
->child
|| MDOC_TEXT
!= n
->child
->type
)
860 buf_append(buf
, n
->child
->string
);
861 hash_put(hash
, buf
, TYPE_St
);
869 if (NULL
== (n
= n
->child
))
872 buf_appendb(buf
, n
->string
, strlen(n
->string
));
874 if (NULL
!= (n
= n
->next
)) {
875 buf_appendb(buf
, ".", 1);
876 buf_appendb(buf
, n
->string
, strlen(n
->string
) + 1);
878 buf_appendb(buf
, ".", 2);
880 hash_put(hash
, buf
, TYPE_Xr
);
890 if (SEC_SYNOPSIS
!= n
->sec
)
892 if (MDOC_Vt
== n
->tok
&& MDOC_BODY
!= n
->type
)
894 if (NULL
== n
->last
|| MDOC_TEXT
!= n
->last
->type
)
898 * Strip away leading pointer symbol '*' and trailing ';'.
901 start
= n
->last
->string
;
903 while ('*' == *start
)
906 if (0 == (sz
= strlen(start
)))
909 if (';' == start
[(int)sz
- 1])
915 buf_appendb(buf
, start
, sz
);
916 buf_appendb(buf
, "", 1);
917 hash_put(hash
, buf
, TYPE_Va
);
925 if (SEC_SYNOPSIS
!= n
->sec
|| MDOC_HEAD
!= n
->type
)
927 if (NULL
== n
->child
|| MDOC_TEXT
!= n
->child
->type
)
930 buf_append(buf
, n
->child
->string
);
931 hash_put(hash
, buf
, TYPE_Fn
);
940 if (MDOC_BODY
!= n
->type
)
943 buf_appendmdoc(dbuf
, n
->child
, 1);
944 buf_appendmdoc(buf
, n
->child
, 0);
946 hash_put(hash
, buf
, TYPE_Nd
);
954 if (SEC_ERRORS
!= n
->sec
)
957 buf_appendmdoc(buf
, n
->child
, 0);
958 hash_put(hash
, buf
, TYPE_Er
);
966 if (SEC_ENVIRONMENT
!= n
->sec
)
969 buf_appendmdoc(buf
, n
->child
, 0);
970 hash_put(hash
, buf
, TYPE_Ev
);
978 if (SEC_FILES
!= n
->sec
)
981 buf_appendmdoc(buf
, n
->child
, 0);
982 hash_put(hash
, buf
, TYPE_Pa
);
990 if (SEC_NAME
== n
->sec
) {
991 buf_appendmdoc(buf
, n
->child
, 0);
992 hash_put(hash
, buf
, TYPE_Nm
);
994 } else if (SEC_SYNOPSIS
!= n
->sec
|| MDOC_HEAD
!= n
->type
)
997 if (NULL
== n
->child
)
998 buf_append(buf
, m
->name
);
1000 buf_appendmdoc(buf
, n
->child
, 0);
1001 hash_put(hash
, buf
, TYPE_Nm
);
1005 hash_put(DB
*db
, const struct buf
*buf
, uint64_t mask
)
1014 key
.size
= buf
->len
;
1016 if ((rc
= (*db
->get
)(db
, &key
, &val
, 0)) < 0) {
1018 exit((int)MANDOCLEVEL_SYSERR
);
1020 mask
|= *(uint64_t *)val
.data
;
1023 val
.size
= sizeof(uint64_t);
1025 if ((rc
= (*db
->put
)(db
, &key
, &val
, 0)) < 0) {
1027 exit((int)MANDOCLEVEL_SYSERR
);
1032 dbt_put(DB
*db
, const char *dbn
, DBT
*key
, DBT
*val
)
1038 if (0 == (*db
->put
)(db
, key
, val
, 0))
1042 exit((int)MANDOCLEVEL_SYSERR
);
1047 * Call out to per-macro handlers after clearing the persistent database
1048 * key. If the macro sets the database key, flush it to the database.
1051 pmdoc_node(MDOC_ARGS
)
1067 if (NULL
== mdocs
[n
->tok
])
1071 (*mdocs
[n
->tok
])(hash
, buf
, dbuf
, n
, m
);
1077 pmdoc_node(hash
, buf
, dbuf
, n
->child
, m
);
1078 pmdoc_node(hash
, buf
, dbuf
, n
->next
, m
);
1084 const struct man_node
*head
, *body
;
1085 const char *start
, *sv
;
1092 * We're only searching for one thing: the first text child in
1093 * the BODY of a NAME section. Since we don't keep track of
1094 * sections in -man, run some hoops to find out whether we're in
1095 * the correct section or not.
1098 if (MAN_BODY
== n
->type
&& MAN_SH
== n
->tok
) {
1100 assert(body
->parent
);
1101 if (NULL
!= (head
= body
->parent
->head
) &&
1102 1 == head
->nchild
&&
1103 NULL
!= (head
= (head
->child
)) &&
1104 MAN_TEXT
== head
->type
&&
1105 0 == strcmp(head
->string
, "NAME") &&
1106 NULL
!= (body
= body
->child
) &&
1107 MAN_TEXT
== body
->type
) {
1109 assert(body
->string
);
1110 start
= sv
= body
->string
;
1113 * Go through a special heuristic dance here.
1114 * This is why -man manuals are great!
1115 * (I'm being sarcastic: my eyes are bleeding.)
1116 * Conventionally, one or more manual names are
1117 * comma-specified prior to a whitespace, then a
1118 * dash, then a description. Try to puzzle out
1119 * the name parts here.
1123 sz
= strcspn(start
, " ,");
1124 if ('\0' == start
[(int)sz
])
1128 buf_appendb(buf
, start
, sz
);
1129 buf_appendb(buf
, "", 1);
1131 hash_put(hash
, buf
, TYPE_Nm
);
1133 if (' ' == start
[(int)sz
]) {
1134 start
+= (int)sz
+ 1;
1138 assert(',' == start
[(int)sz
]);
1139 start
+= (int)sz
+ 1;
1140 while (' ' == *start
)
1147 buf_append(buf
, start
);
1151 while (' ' == *start
)
1154 if (0 == strncmp(start
, "-", 1))
1156 else if (0 == strncmp(start
, "\\-", 2))
1158 else if (0 == strncmp(start
, "\\(en", 4))
1160 else if (0 == strncmp(start
, "\\(em", 4))
1163 while (' ' == *start
)
1166 sz
= strlen(start
) + 1;
1167 buf_appendb(dbuf
, start
, sz
);
1168 buf_appendb(buf
, start
, sz
);
1170 hash_put(hash
, buf
, TYPE_Nd
);
1174 for (n
= n
->child
; n
; n
= n
->next
)
1175 if (pman_node(hash
, buf
, dbuf
, n
))
1182 ofile_argbuild(char *argv
[], int argc
, int verb
, struct of
**of
)
1187 for (i
= 0; i
< argc
; i
++) {
1188 nof
= mandoc_calloc(1, sizeof(struct of
));
1189 nof
->fname
= strdup(argv
[i
]);
1191 printf("%s: Scheduling\n", argv
[i
]);
1196 nof
->first
= (*of
)->first
;
1204 * Recursively build up a list of files to parse.
1205 * We use this instead of ftw() and so on because I don't want global
1206 * variables hanging around.
1207 * This ignores the mandoc.db and mandoc.index files, but assumes that
1208 * everything else is a manual.
1209 * Pass in a pointer to a NULL structure for the first invocation.
1212 ofile_dirbuild(const char *dir
, int verb
, struct of
**of
)
1214 char buf
[MAXPATHLEN
];
1221 if (NULL
== (d
= opendir(dir
))) {
1226 while (NULL
!= (dp
= readdir(d
))) {
1228 if (DT_DIR
== dp
->d_type
) {
1229 if (0 == strcmp(".", fn
))
1231 if (0 == strcmp("..", fn
))
1235 strlcat(buf
, dir
, MAXPATHLEN
);
1236 strlcat(buf
, "/", MAXPATHLEN
);
1237 sz
= strlcat(buf
, fn
, MAXPATHLEN
);
1239 if (sz
< MAXPATHLEN
) {
1240 if ( ! ofile_dirbuild(buf
, verb
, of
))
1243 } else if (sz
< MAXPATHLEN
)
1246 fprintf(stderr
, "%s: Path too long\n", dir
);
1249 if (DT_REG
!= dp
->d_type
)
1252 if (0 == strcmp(MANDOC_DB
, fn
) ||
1253 0 == strcmp(MANDOC_IDX
, fn
))
1257 strlcat(buf
, dir
, MAXPATHLEN
);
1258 strlcat(buf
, "/", MAXPATHLEN
);
1259 sz
= strlcat(buf
, fn
, MAXPATHLEN
);
1260 if (sz
>= MAXPATHLEN
) {
1261 fprintf(stderr
, "%s: Path too long\n", dir
);
1265 nof
= mandoc_calloc(1, sizeof(struct of
));
1266 nof
->fname
= mandoc_strdup(buf
);
1269 printf("%s: Scheduling\n", buf
);
1275 nof
->first
= (*of
)->first
;
1286 ofile_free(struct of
*of
)
1302 fprintf(stderr
, "usage: %s [-v] "
1303 "[-d dir [files...] |"
1304 " -u dir [files...] |"
1305 " dir...]\n", progname
);