]>
git.cameronkatri.com Git - mandoc.git/blob - mandocdb.c
1 /* $Id: mandocdb.c,v 1.8 2011/11/13 10:49:57 schwarze 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>
43 #define MANDOC_BUFSZ BUFSIZ
44 #define MANDOC_SLOP 1024
46 /* Tiny list for files. No need to bring in QUEUE. */
49 char *fname
; /* heap-allocated */
50 struct of
*next
; /* NULL for last one */
51 struct of
*first
; /* first in list */
54 /* Buffer for storing growable data. */
58 size_t len
; /* current length */
59 size_t size
; /* total buffer size */
62 /* Operation we're going to perform. */
65 OP_NEW
= 0, /* new database */
66 OP_UPDATE
, /* delete/add entries in existing database */
67 OP_DELETE
/* delete entries from existing database */
70 #define MAN_ARGS DB *hash, \
73 const struct man_node *n
74 #define MDOC_ARGS DB *hash, \
77 const struct mdoc_node *n, \
78 const struct mdoc_meta *m
80 static void buf_appendmdoc(struct buf
*,
81 const struct mdoc_node
*, int);
82 static void buf_append(struct buf
*, const char *);
83 static void buf_appendb(struct buf
*,
84 const void *, size_t);
85 static void dbt_put(DB
*, const char *, DBT
*, DBT
*);
86 static void hash_put(DB
*, const struct buf
*, int);
87 static void hash_reset(DB
**);
88 static void index_merge(const struct of
*, struct mparse
*,
89 struct buf
*, struct buf
*,
90 DB
*, DB
*, const char *,
91 DB
*, const char *, int,
92 recno_t
, const recno_t
*, size_t);
93 static void index_prune(const struct of
*, DB
*,
94 const char *, DB
*, const char *,
95 int, recno_t
*, recno_t
**, size_t *);
96 static void ofile_argbuild(char *[], int, int, struct of
**);
97 static int ofile_dirbuild(const char *, int, struct of
**);
98 static void ofile_free(struct of
*);
99 static int pman_node(MAN_ARGS
);
100 static void pmdoc_node(MDOC_ARGS
);
101 static void pmdoc_An(MDOC_ARGS
);
102 static void pmdoc_Cd(MDOC_ARGS
);
103 static void pmdoc_Er(MDOC_ARGS
);
104 static void pmdoc_Ev(MDOC_ARGS
);
105 static void pmdoc_Fd(MDOC_ARGS
);
106 static void pmdoc_In(MDOC_ARGS
);
107 static void pmdoc_Fn(MDOC_ARGS
);
108 static void pmdoc_Fo(MDOC_ARGS
);
109 static void pmdoc_Nd(MDOC_ARGS
);
110 static void pmdoc_Nm(MDOC_ARGS
);
111 static void pmdoc_Pa(MDOC_ARGS
);
112 static void pmdoc_St(MDOC_ARGS
);
113 static void pmdoc_Vt(MDOC_ARGS
);
114 static void pmdoc_Xr(MDOC_ARGS
);
115 static void usage(void);
117 typedef void (*pmdoc_nf
)(MDOC_ARGS
);
119 static const pmdoc_nf mdocs
[MDOC_MAX
] = {
244 static const char *progname
;
247 main(int argc
, char *argv
[])
249 struct mparse
*mp
; /* parse sequence */
250 enum op op
; /* current operation */
252 char ibuf
[MAXPATHLEN
], /* index fname */
253 fbuf
[MAXPATHLEN
]; /* btree fname */
254 int verb
, /* output verbosity */
256 DB
*idx
, /* index database */
257 *db
, /* keyword database */
258 *hash
; /* temporary keyword hashtable */
259 BTREEINFO info
; /* btree configuration */
260 recno_t maxrec
; /* supremum of all records */
261 recno_t
*recs
; /* buffer of empty records */
263 recsz
, /* buffer size of recs */
264 reccur
; /* valid number of recs */
265 struct buf buf
, /* keyword buffer */
266 dbuf
; /* description buffer */
267 struct of
*of
; /* list of files for processing */
271 progname
= strrchr(argv
[0], '/');
272 if (progname
== NULL
)
288 while (-1 != (ch
= getopt(argc
, argv
, "d:u:v")))
303 return((int)MANDOCLEVEL_BADARG
);
309 memset(&info
, 0, sizeof(BTREEINFO
));
312 mp
= mparse_alloc(MPARSE_AUTO
, MANDOCLEVEL_FATAL
, NULL
, NULL
);
314 memset(&buf
, 0, sizeof(struct buf
));
315 memset(&dbuf
, 0, sizeof(struct buf
));
317 buf
.size
= dbuf
.size
= MANDOC_BUFSZ
;
319 buf
.cp
= mandoc_malloc(buf
.size
);
320 dbuf
.cp
= mandoc_malloc(dbuf
.size
);
322 flags
= OP_NEW
== op
? O_CREAT
|O_TRUNC
|O_RDWR
: O_CREAT
|O_RDWR
;
324 if (OP_UPDATE
== op
|| OP_DELETE
== op
) {
325 ibuf
[0] = fbuf
[0] = '\0';
327 strlcat(fbuf
, dir
, MAXPATHLEN
);
328 strlcat(fbuf
, "/", MAXPATHLEN
);
329 sz1
= strlcat(fbuf
, MANDOC_DB
, MAXPATHLEN
);
331 strlcat(ibuf
, dir
, MAXPATHLEN
);
332 strlcat(ibuf
, "/", MAXPATHLEN
);
333 sz2
= strlcat(ibuf
, MANDOC_IDX
, MAXPATHLEN
);
335 if (sz1
>= MAXPATHLEN
|| sz2
>= MAXPATHLEN
) {
336 fprintf(stderr
, "%s: Path too long\n", dir
);
337 exit((int)MANDOCLEVEL_BADARG
);
340 db
= dbopen(fbuf
, flags
, 0644, DB_BTREE
, &info
);
341 idx
= dbopen(ibuf
, flags
, 0644, DB_RECNO
, NULL
);
345 exit((int)MANDOCLEVEL_SYSERR
);
346 } else if (NULL
== db
) {
348 exit((int)MANDOCLEVEL_SYSERR
);
352 printf("%s: Opened\n", fbuf
);
353 printf("%s: Opened\n", ibuf
);
356 ofile_argbuild(argv
, argc
, verb
, &of
);
362 index_prune(of
, db
, fbuf
, idx
, ibuf
, verb
,
363 &maxrec
, &recs
, &recsz
);
366 index_merge(of
, mp
, &dbuf
, &buf
, hash
,
367 db
, fbuf
, idx
, ibuf
, verb
,
368 maxrec
, recs
, reccur
);
373 for (i
= 0; i
< argc
; i
++) {
374 ibuf
[0] = fbuf
[0] = '\0';
376 strlcat(fbuf
, argv
[i
], MAXPATHLEN
);
377 strlcat(fbuf
, "/", MAXPATHLEN
);
378 sz1
= strlcat(fbuf
, MANDOC_DB
, MAXPATHLEN
);
380 strlcat(ibuf
, argv
[i
], MAXPATHLEN
);
381 strlcat(ibuf
, "/", MAXPATHLEN
);
382 sz2
= strlcat(ibuf
, MANDOC_IDX
, MAXPATHLEN
);
384 if (sz1
>= MAXPATHLEN
|| sz2
>= MAXPATHLEN
) {
385 fprintf(stderr
, "%s: Path too long\n", argv
[i
]);
386 exit((int)MANDOCLEVEL_BADARG
);
389 db
= dbopen(fbuf
, flags
, 0644, DB_BTREE
, &info
);
390 idx
= dbopen(ibuf
, flags
, 0644, DB_RECNO
, NULL
);
394 exit((int)MANDOCLEVEL_SYSERR
);
395 } else if (NULL
== db
) {
397 exit((int)MANDOCLEVEL_SYSERR
);
401 printf("%s: Truncated\n", fbuf
);
402 printf("%s: Truncated\n", ibuf
);
408 if ( ! ofile_dirbuild(argv
[i
], verb
, &of
))
409 exit((int)MANDOCLEVEL_SYSERR
);
416 index_merge(of
, mp
, &dbuf
, &buf
, hash
, db
, fbuf
,
417 idx
, ibuf
, verb
, maxrec
, recs
, reccur
);
426 (*hash
->close
)(hash
);
435 return(MANDOCLEVEL_OK
);
439 index_merge(const struct of
*of
, struct mparse
*mp
,
440 struct buf
*dbuf
, struct buf
*buf
,
441 DB
*hash
, DB
*db
, const char *dbf
,
442 DB
*idx
, const char *idxf
, int verb
,
443 recno_t maxrec
, const recno_t
*recs
, size_t reccur
)
450 const char *fn
, *msec
, *mtitle
, *arch
;
455 for (rec
= 0; of
; of
= of
->next
) {
459 rec
= recs
[(int)reccur
];
460 } else if (maxrec
> 0) {
469 if (mparse_readfd(mp
, -1, fn
) >= MANDOCLEVEL_FATAL
) {
470 fprintf(stderr
, "%s: Parse failure\n", fn
);
474 mparse_result(mp
, &mdoc
, &man
);
475 if (NULL
== mdoc
&& NULL
== man
)
478 msec
= NULL
!= mdoc
?
479 mdoc_meta(mdoc
)->msec
: man_meta(man
)->msec
;
480 mtitle
= NULL
!= mdoc
?
481 mdoc_meta(mdoc
)->title
: man_meta(man
)->title
;
482 arch
= NULL
!= mdoc
?
483 mdoc_meta(mdoc
)->arch
: NULL
;
489 * The index record value consists of a nil-terminated
490 * filename, a nil-terminated manual section, and a
491 * nil-terminated description. Since the description
492 * may not be set, we set a sentinel to see if we're
493 * going to write a nil byte in its place.
497 buf_appendb(dbuf
, fn
, strlen(fn
) + 1);
498 buf_appendb(dbuf
, msec
, strlen(msec
) + 1);
499 buf_appendb(dbuf
, mtitle
, strlen(mtitle
) + 1);
500 buf_appendb(dbuf
, arch
, strlen(arch
) + 1);
504 /* Fix the record number in the btree value. */
507 pmdoc_node(hash
, buf
, dbuf
,
508 mdoc_node(mdoc
), mdoc_meta(mdoc
));
510 pman_node(hash
, buf
, dbuf
, man_node(man
));
513 * Copy from the in-memory hashtable of pending keywords
517 memset(vbuf
, 0, sizeof(uint32_t));
518 memcpy(vbuf
+ 4, &rec
, sizeof(uint32_t));
521 while (0 == (ch
= (*hash
->seq
)(hash
, &key
, &val
, seq
))) {
524 memcpy(vbuf
, val
.data
, sizeof(uint32_t));
525 val
.size
= sizeof(vbuf
);
529 printf("%s: Added keyword: %s\n",
530 fn
, (char *)key
.data
);
531 dbt_put(db
, dbf
, &key
, &val
);
535 exit((int)MANDOCLEVEL_SYSERR
);
539 * Apply to the index. If we haven't had a description
540 * set, put an empty one in now.
544 buf_appendb(dbuf
, "", 1);
547 key
.size
= sizeof(recno_t
);
550 val
.size
= dbuf
->len
;
553 printf("%s: Added index\n", fn
);
554 dbt_put(idx
, idxf
, &key
, &val
);
559 * Scan through all entries in the index file `idx' and prune those
560 * entries in `ofile'.
561 * Pruning consists of removing from `db', then invalidating the entry
562 * in `idx' (zeroing its value size).
565 index_prune(const struct of
*ofile
, DB
*db
, const char *dbf
,
566 DB
*idx
, const char *idxf
, int verb
,
567 recno_t
*maxrec
, recno_t
**recs
, size_t *recsz
)
578 while (0 == (ch
= (*idx
->seq
)(idx
, &key
, &val
, seq
))) {
580 *maxrec
= *(recno_t
*)key
.data
;
582 if (reccur
>= *recsz
) {
583 *recsz
+= MANDOC_SLOP
;
584 *recs
= mandoc_realloc(*recs
,
585 *recsz
* sizeof(recno_t
));
587 (*recs
)[(int)reccur
] = *maxrec
;
592 fn
= (char *)val
.data
;
593 for (of
= ofile
; of
; of
= of
->next
)
594 if (0 == strcmp(fn
, of
->fname
))
601 while (0 == (ch
= (*db
->seq
)(db
, &key
, &val
, sseq
))) {
603 assert(8 == val
.size
);
604 if (*maxrec
!= *(recno_t
*)(val
.data
+ 4))
607 printf("%s: Deleted keyword: %s\n",
608 fn
, (char *)key
.data
);
609 ch
= (*db
->del
)(db
, &key
, R_CURSOR
);
615 exit((int)MANDOCLEVEL_SYSERR
);
619 printf("%s: Deleted index\n", fn
);
622 ch
= (*idx
->put
)(idx
, &key
, &val
, R_CURSOR
);
625 exit((int)MANDOCLEVEL_SYSERR
);
628 if (reccur
>= *recsz
) {
629 *recsz
+= MANDOC_SLOP
;
630 *recs
= mandoc_realloc
631 (*recs
, *recsz
* sizeof(recno_t
));
634 (*recs
)[(int)reccur
] = *maxrec
;
641 * Grow the buffer (if necessary) and copy in a binary string.
644 buf_appendb(struct buf
*buf
, const void *cp
, size_t sz
)
647 /* Overshoot by MANDOC_BUFSZ. */
649 while (buf
->len
+ sz
>= buf
->size
) {
650 buf
->size
= buf
->len
+ sz
+ MANDOC_BUFSZ
;
651 buf
->cp
= mandoc_realloc(buf
->cp
, buf
->size
);
654 memcpy(buf
->cp
+ (int)buf
->len
, cp
, sz
);
659 * Append a nil-terminated string to the buffer.
660 * This can be invoked multiple times.
661 * The buffer string will be nil-terminated.
662 * If invoked multiple times, a space is put between strings.
665 buf_append(struct buf
*buf
, const char *cp
)
669 if (0 == (sz
= strlen(cp
)))
673 buf
->cp
[(int)buf
->len
- 1] = ' ';
675 buf_appendb(buf
, cp
, sz
+ 1);
679 * Recursively add all text from a given node.
680 * This is optimised for general mdoc nodes in this context, which do
681 * not consist of subexpressions and having a recursive call for n->next
683 * The "f" variable should be 0 unless called from pmdoc_Nd for the
684 * description buffer, which does not start at the beginning of the
688 buf_appendmdoc(struct buf
*buf
, const struct mdoc_node
*n
, int f
)
691 for ( ; n
; n
= n
->next
) {
693 buf_appendmdoc(buf
, n
->child
, f
);
695 if (MDOC_TEXT
== n
->type
&& f
) {
697 buf_appendb(buf
, n
->string
,
698 strlen(n
->string
) + 1);
699 } else if (MDOC_TEXT
== n
->type
)
700 buf_append(buf
, n
->string
);
710 if (SEC_AUTHORS
!= n
->sec
)
713 buf_appendmdoc(buf
, n
->child
, 0);
714 hash_put(hash
, buf
, TYPE_An
);
722 if (NULL
!= (hash
= *db
))
723 (*hash
->close
)(hash
);
725 *db
= dbopen(NULL
, O_CREAT
|O_RDWR
, 0644, DB_HASH
, NULL
);
728 exit((int)MANDOCLEVEL_SYSERR
);
736 const char *start
, *end
;
739 if (SEC_SYNOPSIS
!= n
->sec
)
741 if (NULL
== (n
= n
->child
) || MDOC_TEXT
!= n
->type
)
745 * Only consider those `Fd' macro fields that begin with an
746 * "inclusion" token (versus, e.g., #define).
748 if (strcmp("#include", n
->string
))
751 if (NULL
== (n
= n
->next
) || MDOC_TEXT
!= n
->type
)
755 * Strip away the enclosing angle brackets and make sure we're
760 if ('<' == *start
|| '"' == *start
)
763 if (0 == (sz
= strlen(start
)))
766 end
= &start
[(int)sz
- 1];
767 if ('>' == *end
|| '"' == *end
)
770 assert(end
>= start
);
772 buf_appendb(buf
, start
, (size_t)(end
- start
+ 1));
773 buf_appendb(buf
, "", 1);
775 hash_put(hash
, buf
, TYPE_In
);
783 if (SEC_SYNOPSIS
!= n
->sec
)
786 buf_appendmdoc(buf
, n
->child
, 0);
787 hash_put(hash
, buf
, TYPE_Cd
);
795 if (SEC_SYNOPSIS
!= n
->sec
)
797 if (NULL
== n
->child
|| MDOC_TEXT
!= n
->child
->type
)
800 buf_append(buf
, n
->child
->string
);
801 hash_put(hash
, buf
, TYPE_In
);
810 if (SEC_SYNOPSIS
!= n
->sec
)
812 if (NULL
== n
->child
|| MDOC_TEXT
!= n
->child
->type
)
815 /* .Fn "struct type *arg" "foo" */
817 cp
= strrchr(n
->child
->string
, ' ');
819 cp
= n
->child
->string
;
821 /* Strip away pointer symbol. */
827 hash_put(hash
, buf
, TYPE_Fn
);
835 if (SEC_STANDARDS
!= n
->sec
)
837 if (NULL
== n
->child
|| MDOC_TEXT
!= n
->child
->type
)
840 buf_append(buf
, n
->child
->string
);
841 hash_put(hash
, buf
, TYPE_St
);
849 if (NULL
== (n
= n
->child
))
852 buf_appendb(buf
, n
->string
, strlen(n
->string
));
854 if (NULL
!= (n
= n
->next
)) {
855 buf_appendb(buf
, ".", 1);
856 buf_appendb(buf
, n
->string
, strlen(n
->string
) + 1);
858 buf_appendb(buf
, ".", 2);
860 hash_put(hash
, buf
, TYPE_Xr
);
870 if (SEC_SYNOPSIS
!= n
->sec
)
872 if (MDOC_Vt
== n
->tok
&& MDOC_BODY
!= n
->type
)
874 if (NULL
== n
->last
|| MDOC_TEXT
!= n
->last
->type
)
878 * Strip away leading pointer symbol '*' and trailing ';'.
881 start
= n
->last
->string
;
883 while ('*' == *start
)
886 if (0 == (sz
= strlen(start
)))
889 if (';' == start
[(int)sz
- 1])
895 buf_appendb(buf
, start
, sz
);
896 buf_appendb(buf
, "", 1);
897 hash_put(hash
, buf
, TYPE_Va
);
905 if (SEC_SYNOPSIS
!= n
->sec
|| MDOC_HEAD
!= n
->type
)
907 if (NULL
== n
->child
|| MDOC_TEXT
!= n
->child
->type
)
910 buf_append(buf
, n
->child
->string
);
911 hash_put(hash
, buf
, TYPE_Fn
);
920 if (MDOC_BODY
!= n
->type
)
923 buf_appendmdoc(dbuf
, n
->child
, 1);
924 buf_appendmdoc(buf
, n
->child
, 0);
926 hash_put(hash
, buf
, TYPE_Nd
);
934 if (SEC_ERRORS
!= n
->sec
)
937 buf_appendmdoc(buf
, n
->child
, 0);
938 hash_put(hash
, buf
, TYPE_Er
);
946 if (SEC_ENVIRONMENT
!= n
->sec
)
949 buf_appendmdoc(buf
, n
->child
, 0);
950 hash_put(hash
, buf
, TYPE_Ev
);
958 if (SEC_FILES
!= n
->sec
)
961 buf_appendmdoc(buf
, n
->child
, 0);
962 hash_put(hash
, buf
, TYPE_Pa
);
970 if (SEC_NAME
== n
->sec
) {
971 buf_appendmdoc(buf
, n
->child
, 0);
972 hash_put(hash
, buf
, TYPE_Nm
);
974 } else if (SEC_SYNOPSIS
!= n
->sec
|| MDOC_HEAD
!= n
->type
)
977 if (NULL
== n
->child
)
978 buf_append(buf
, m
->name
);
980 buf_appendmdoc(buf
, n
->child
, 0);
981 hash_put(hash
, buf
, TYPE_Nm
);
985 hash_put(DB
*db
, const struct buf
*buf
, int mask
)
996 if ((rc
= (*db
->get
)(db
, &key
, &val
, 0)) < 0) {
998 exit((int)MANDOCLEVEL_SYSERR
);
1000 mask
|= *(int *)val
.data
;
1003 val
.size
= sizeof(int);
1005 if ((rc
= (*db
->put
)(db
, &key
, &val
, 0)) < 0) {
1007 exit((int)MANDOCLEVEL_SYSERR
);
1012 dbt_put(DB
*db
, const char *dbn
, DBT
*key
, DBT
*val
)
1018 if (0 == (*db
->put
)(db
, key
, val
, 0))
1022 exit((int)MANDOCLEVEL_SYSERR
);
1027 * Call out to per-macro handlers after clearing the persistent database
1028 * key. If the macro sets the database key, flush it to the database.
1031 pmdoc_node(MDOC_ARGS
)
1047 if (NULL
== mdocs
[n
->tok
])
1051 (*mdocs
[n
->tok
])(hash
, buf
, dbuf
, n
, m
);
1057 pmdoc_node(hash
, buf
, dbuf
, n
->child
, m
);
1058 pmdoc_node(hash
, buf
, dbuf
, n
->next
, m
);
1064 const struct man_node
*head
, *body
;
1065 const char *start
, *sv
;
1072 * We're only searching for one thing: the first text child in
1073 * the BODY of a NAME section. Since we don't keep track of
1074 * sections in -man, run some hoops to find out whether we're in
1075 * the correct section or not.
1078 if (MAN_BODY
== n
->type
&& MAN_SH
== n
->tok
) {
1080 assert(body
->parent
);
1081 if (NULL
!= (head
= body
->parent
->head
) &&
1082 1 == head
->nchild
&&
1083 NULL
!= (head
= (head
->child
)) &&
1084 MAN_TEXT
== head
->type
&&
1085 0 == strcmp(head
->string
, "NAME") &&
1086 NULL
!= (body
= body
->child
) &&
1087 MAN_TEXT
== body
->type
) {
1089 assert(body
->string
);
1090 start
= sv
= body
->string
;
1093 * Go through a special heuristic dance here.
1094 * This is why -man manuals are great!
1095 * (I'm being sarcastic: my eyes are bleeding.)
1096 * Conventionally, one or more manual names are
1097 * comma-specified prior to a whitespace, then a
1098 * dash, then a description. Try to puzzle out
1099 * the name parts here.
1103 sz
= strcspn(start
, " ,");
1104 if ('\0' == start
[(int)sz
])
1108 buf_appendb(buf
, start
, sz
);
1109 buf_appendb(buf
, "", 1);
1111 hash_put(hash
, buf
, TYPE_Nm
);
1113 if (' ' == start
[(int)sz
]) {
1114 start
+= (int)sz
+ 1;
1118 assert(',' == start
[(int)sz
]);
1119 start
+= (int)sz
+ 1;
1120 while (' ' == *start
)
1127 buf_append(buf
, start
);
1131 while (' ' == *start
)
1134 if (0 == strncmp(start
, "-", 1))
1136 else if (0 == strncmp(start
, "\\-", 2))
1138 else if (0 == strncmp(start
, "\\(en", 4))
1140 else if (0 == strncmp(start
, "\\(em", 4))
1143 while (' ' == *start
)
1146 sz
= strlen(start
) + 1;
1147 buf_appendb(dbuf
, start
, sz
);
1148 buf_appendb(buf
, start
, sz
);
1150 hash_put(hash
, buf
, TYPE_Nd
);
1154 for (n
= n
->child
; n
; n
= n
->next
)
1155 if (pman_node(hash
, buf
, dbuf
, n
))
1162 ofile_argbuild(char *argv
[], int argc
, int verb
, struct of
**of
)
1167 for (i
= 0; i
< argc
; i
++) {
1168 nof
= mandoc_calloc(1, sizeof(struct of
));
1169 nof
->fname
= strdup(argv
[i
]);
1171 printf("%s: Scheduling\n", argv
[i
]);
1176 nof
->first
= (*of
)->first
;
1184 * Recursively build up a list of files to parse.
1185 * We use this instead of ftw() and so on because I don't want global
1186 * variables hanging around.
1187 * This ignores the mandoc.db and mandoc.index files, but assumes that
1188 * everything else is a manual.
1189 * Pass in a pointer to a NULL structure for the first invocation.
1192 ofile_dirbuild(const char *dir
, int verb
, struct of
**of
)
1194 char buf
[MAXPATHLEN
];
1201 if (NULL
== (d
= opendir(dir
))) {
1206 while (NULL
!= (dp
= readdir(d
))) {
1208 if (DT_DIR
== dp
->d_type
) {
1209 if (0 == strcmp(".", fn
))
1211 if (0 == strcmp("..", fn
))
1215 strlcat(buf
, dir
, MAXPATHLEN
);
1216 strlcat(buf
, "/", MAXPATHLEN
);
1217 sz
= strlcat(buf
, fn
, MAXPATHLEN
);
1219 if (sz
< MAXPATHLEN
) {
1220 if ( ! ofile_dirbuild(buf
, verb
, of
))
1223 } else if (sz
< MAXPATHLEN
)
1226 fprintf(stderr
, "%s: Path too long\n", dir
);
1229 if (DT_REG
!= dp
->d_type
)
1232 if (0 == strcmp(MANDOC_DB
, fn
) ||
1233 0 == strcmp(MANDOC_IDX
, fn
))
1237 strlcat(buf
, dir
, MAXPATHLEN
);
1238 strlcat(buf
, "/", MAXPATHLEN
);
1239 sz
= strlcat(buf
, fn
, MAXPATHLEN
);
1240 if (sz
>= MAXPATHLEN
) {
1241 fprintf(stderr
, "%s: Path too long\n", dir
);
1245 nof
= mandoc_calloc(1, sizeof(struct of
));
1246 nof
->fname
= mandoc_strdup(buf
);
1249 printf("%s: Scheduling\n", buf
);
1255 nof
->first
= (*of
)->first
;
1266 ofile_free(struct of
*of
)
1282 fprintf(stderr
, "usage: %s [-v] "
1283 "[-d dir [files...] |"
1284 " -u dir [files...] |"
1285 " dir...]\n", progname
);