1 /* $NetBSD: makewhatis.c,v 1.46 2008/11/16 06:26:12 dholland Exp $ */
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
36 #include <sys/cdefs.h>
38 __COPYRIGHT("@(#) Copyright (c) 1999\
39 The NetBSD Foundation, Inc. All rights reserved.");
40 __RCSID("$NetBSD: makewhatis.c,v 1.46 2008/11/16 06:26:12 dholland Exp $");
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <sys/queue.h>
65 #include <man/manconf.h>
66 #include <man/pathnames.h>
72 typedef struct manpagestruct manpage
;
73 struct manpagestruct
{
74 manpage
*mp_left
, *mp_right
;
81 typedef struct whatisstruct whatis
;
83 whatis
*wi_left
, *wi_right
;
88 int main(int, char * const *);
89 static char *findwhitespace(char *);
90 static char *strmove(char *, char *);
91 static char *GetS(gzFile
, char *, size_t);
92 static int pathnamesection(const char *, const char *);
93 static int manpagesection(char *);
94 static char *createsectionstring(char *);
95 static void addmanpage(manpage
**, ino_t
, char *, size_t, size_t);
96 static void addwhatis(whatis
**, char *, char *);
97 static char *makesection(int);
98 static char *makewhatisline(const char *, const char *, const char *);
99 static void catpreprocess(char *);
100 static char *parsecatpage(const char *, gzFile
*);
101 static int manpreprocess(char *);
102 static char *nroff(const char *, gzFile
*);
103 static char *parsemanpage(const char *, gzFile
*, int);
104 static char *getwhatisdata(char *);
105 static void processmanpages(manpage
**, whatis
**);
106 static void dumpwhatis(FILE *, whatis
*);
107 static int makewhatis(char * const *manpath
);
109 static char * const default_manpath
[] = {
114 static const char *sectionext
= "0123456789ln";
115 static const char *whatisdb
= _PATH_WHATIS
;
116 static const char *whatisdb_new
= _PATH_WHATIS
".new";
117 static int dowarn
= 0;
119 #define ISALPHA(c) isalpha((unsigned char)(c))
120 #define ISDIGIT(c) isdigit((unsigned char)(c))
121 #define ISSPACE(c) isspace((unsigned char)(c))
124 main(int argc
, char *const *argv
)
126 char * const *manpath
;
128 const char *conffile
;
131 int rv
, jobs
, status
;
133 char *paths
[2], **p
, *sl
;
139 retval
= EXIT_SUCCESS
;
141 (void)setlocale(LC_ALL
, "");
143 while ((c
= getopt(argc
, argv
, "C:fw")) != -1) {
149 /* run all processing on foreground */
156 fprintf(stderr
, "Usage: %s [-fw] [-C file] [manpath ...]\n",
168 return makewhatis(manpath
);
172 * Try read config file, fallback to default_manpath[]
173 * if man.conf not available.
176 if ((tp
= gettag("_whatdb", 0)) == NULL
) {
177 manpath
= default_manpath
;
181 /* Build individual databases */
183 TAILQ_FOREACH(ep
, &tp
->entrylist
, q
) {
184 if ((rv
= glob(ep
->s
,
185 GLOB_BRACE
| GLOB_NOSORT
| GLOB_ERR
| GLOB_NOCHECK
,
187 err(EXIT_FAILURE
, "glob('%s')", ep
->s
);
189 /* We always have something to work with here */
190 for (p
= pg
.gl_pathv
; *p
; p
++) {
191 sl
= strrchr(*p
, '/');
193 err(EXIT_FAILURE
, "glob: _whatdb entry '%s' "
194 "doesn't contain slash", ep
->s
);
198 * Cut the last component of path, leaving just
199 * the directory. We will use the result as root
200 * for manpage search.
201 * glob malloc()s space for the paths, so it's
202 * okay to change it in-place.
208 /* Do not fork child */
215 exit(makewhatis(paths
));
231 /* Wait for the childern to finish */
234 if (!WIFEXITED(status
) || WEXITSTATUS(status
) != EXIT_SUCCESS
)
235 retval
= EXIT_FAILURE
;
243 makewhatis(char * const * manpath
)
252 struct stat st_before
, st_after
;
254 if ((fts
= fts_open(manpath
, FTS_LOGICAL
, NULL
)) == NULL
)
255 err(EXIT_FAILURE
, "Cannot open `%s'", *manpath
);
258 while ((fe
= fts_read(fts
)) != NULL
) {
259 switch (fe
->fts_info
) {
261 if (manpagesection(fe
->fts_path
) >= 0) {
263 * Get manpage subdirectory prefix. Most
264 * commonly, this is arch-specific subdirectory.
266 if (fe
->fts_level
>= 3) {
271 s
= &fe
->fts_path
[fe
->fts_pathlen
- 1];
272 for(sl
= fe
->fts_level
- 1; sl
> 0;
282 * Include trailing '/', so we get
285 sdoff
= s
+ 1 - fe
->fts_path
;
292 addmanpage(&source
, fe
->fts_statp
->st_ino
,
293 fe
->fts_path
, sdoff
, sdlen
);
307 warnx("Symbolic link with no target: `%s'",
311 warnx("Unreadable directory: `%s'", fe
->fts_path
);
314 errno
= fe
->fts_errno
;
315 warn("Cannot stat `%s'", fe
->fts_path
);
318 errno
= fe
->fts_errno
;
319 warn("Error reading `%s'", fe
->fts_path
);
322 errx(EXIT_FAILURE
, "Unknown info %d returned from fts "
323 " for path: `%s'", fe
->fts_info
, fe
->fts_path
);
327 (void)fts_close(fts
);
330 processmanpages(&source
, &dest
);
332 if (chdir(manpath
[0]) == -1)
333 err(EXIT_FAILURE
, "Cannot change dir to `%s'", manpath
[0]);
336 * makewhatis runs unattended, so it needs to be able to
337 * recover if the last run crashed out. Therefore, if
338 * whatisdb_new exists and is more than (arbitrarily) sixteen
339 * hours old, nuke it. If it exists but is not so old, refuse
340 * to run until it's cleaned up, in case another makewhatis is
341 * already running. Also, open the output with O_EXCL to make
342 * sure we get our own, in case two copies start exactly at
343 * once. (Unlikely? Maybe, maybe not, if two copies of cron
346 * Similarly, before renaming the file after we finish writing
347 * to it, make sure it's still the same file we opened. This
348 * can't be completely race-free, but getting caught by it
349 * would require an unexplained sixteen-hour-or-more lag
350 * between the last mtime update when we wrote to it and when
351 * we get to the stat call *and* another makewhatis starting
352 * out to write at exactly the wrong moment. Not impossible,
353 * but not likely enough to worry about.
355 * This is maybe unnecessarily elaborate, but generating
356 * corrupted output isn't so good either.
359 if (stat(whatisdb_new
, &st_before
) == 0) {
360 if (st_before
.st_mtime
- time(NULL
) > 16*60*60) {
361 /* Don't complain if someone else just removed it. */
362 if (unlink(whatisdb_new
) == -1 && errno
!= ENOENT
) {
363 err(EXIT_FAILURE
, "Could not remove `%s'",
366 warnx("Removed stale `%s'", whatisdb_new
);
369 errx(EXIT_FAILURE
, "The file `%s' already exists "
370 "-- am I already running?", whatisdb_new
);
372 } else if (errno
!= ENOENT
) {
373 /* Something unexpected happened. */
374 err(EXIT_FAILURE
, "Cannot stat `%s'", whatisdb_new
);
377 outfd
= open(whatisdb_new
, O_WRONLY
|O_CREAT
|O_EXCL
,
378 S_IRUSR
|S_IRGRP
|S_IROTH
);
380 err(EXIT_FAILURE
, "Cannot open `%s'", whatisdb_new
);
382 if (fstat(outfd
, &st_before
) == -1)
383 err(EXIT_FAILURE
, "Cannot fstat `%s'", whatisdb_new
);
385 if ((out
= fdopen(outfd
, "w")) == NULL
)
386 err(EXIT_FAILURE
, "Cannot fdopen `%s'", whatisdb_new
);
388 dumpwhatis(out
, dest
);
389 if (fchmod(fileno(out
), S_IRUSR
|S_IRGRP
|S_IROTH
) == -1)
390 err(EXIT_FAILURE
, "Cannot chmod `%s'", whatisdb_new
);
391 if (fclose(out
) != 0)
392 err(EXIT_FAILURE
, "Cannot close `%s'", whatisdb_new
);
394 if (stat(whatisdb_new
, &st_after
) == -1)
395 err(EXIT_FAILURE
, "Cannot stat `%s' (after writing)",
398 if (st_before
.st_dev
!= st_after
.st_dev
||
399 st_before
.st_ino
!= st_after
.st_ino
) {
400 errx(EXIT_FAILURE
, "The file `%s' changed under me; giving up",
404 if (rename(whatisdb_new
, whatisdb
) == -1)
405 err(EXIT_FAILURE
, "Could not rename `%s' to `%s'",
406 whatisdb_new
, whatisdb
);
412 findwhitespace(char *str
)
414 while (!ISSPACE(*str
))
415 if (*str
++ == '\0') {
424 strmove(char *dest
, char *src
)
426 return memmove(dest
, src
, strlen(src
) + 1);
430 GetS(gzFile in
, char *buffer
, size_t length
)
434 if (((ptr
= gzgets(in
, buffer
, (int)length
)) != NULL
) && (*ptr
== '\0'))
443 char sectionbuffer
[24];
446 (void)snprintf(sectionbuffer
, sizeof(sectionbuffer
),
447 " (%c) - ", sectionext
[s
]);
448 return estrdup(sectionbuffer
);
452 pathnamesection(const char *pat
, const char *name
)
455 size_t len
= strlen(pat
);
458 while ((ptr
= strstr(name
, pat
)) != NULL
) {
459 if ((ext
= strchr(sectionext
, ptr
[len
])) != NULL
) {
460 return ext
- sectionext
;
469 manpagesection(char *name
)
473 if ((ptr
= strrchr(name
, '/')) != NULL
)
478 while ((ptr
= strchr(ptr
, '.')) != NULL
) {
483 while (sectionext
[section
] != '\0')
484 if (sectionext
[section
] == *ptr
)
493 createsectionstring(char *section_id
)
497 if (asprintf(§ion
, " (%s) - ", section_id
) < 0)
498 err(EXIT_FAILURE
, "malloc failed");
503 addmanpage(manpage
**tree
, ino_t inode
, char *name
, size_t sdoff
, size_t sdlen
)
507 while ((mp
= *tree
) != NULL
) {
508 if (mp
->mp_inode
== inode
)
510 tree
= inode
< mp
->mp_inode
? &mp
->mp_left
: &mp
->mp_right
;
513 mp
= emalloc(sizeof(manpage
) + strlen(name
));
516 mp
->mp_inode
= inode
;
517 mp
->mp_sdoff
= sdoff
;
518 mp
->mp_sdlen
= sdlen
;
519 (void)strcpy(mp
->mp_name
, name
);
524 addwhatis(whatis
**tree
, char *data
, char *prefix
)
529 while (ISSPACE(*data
))
536 while ((*ptr
!= '\0') && !ISSPACE(*ptr
))
541 while ((wi
= *tree
) != NULL
) {
542 result
= strcmp(data
, wi
->wi_data
);
543 if (result
== 0) result
= strcmp(prefix
, wi
->wi_prefix
);
544 if (result
== 0) return;
545 tree
= result
< 0 ? &wi
->wi_left
: &wi
->wi_right
;
548 wi
= emalloc(sizeof(whatis
) + strlen(prefix
));
553 if (prefix
[0] != '\0')
554 (void) strcpy(wi
->wi_prefix
, prefix
);
556 wi
->wi_prefix
[0] = '\0';
561 catpreprocess(char *from
)
566 while (ISSPACE(*from
)) from
++;
568 while (*from
!= '\0')
569 if (ISSPACE(*from
)) {
570 while (ISSPACE(*++from
));
574 else if (*(from
+ 1) == '\b')
583 makewhatisline(const char *file
, const char *line
, const char *section
)
585 static const char *del
[] = {
593 size_t llen
, slen
, dlen
;
597 if (section
== NULL
) {
599 warnx("%s: No section provided for `%s'", file
, line
);
600 return estrdup(line
);
603 for (i
= 0; del
[i
]; i
++)
604 if ((ptr
= strstr(line
, del
[i
])) != NULL
)
607 if (del
[i
] == NULL
) {
609 warnx("%s: Bad format line `%s'", file
, line
);
610 return estrdup(line
);
613 slen
= strlen(section
);
615 dlen
= strlen(del
[i
]);
617 result
= emalloc(llen
- dlen
+ slen
+ 1);
620 (void)memcpy(result
, line
, pos
);
621 (void)memcpy(&result
[pos
], section
, slen
);
622 (void)strcpy(&result
[pos
+ slen
], &line
[pos
+ dlen
]);
627 parsecatpage(const char *name
, gzFile
*in
)
630 char *section
, *ptr
, *last
;
634 if (GetS(in
, buffer
, sizeof(buffer
)) == NULL
)
637 while (buffer
[0] == '\n');
640 if ((ptr
= strchr(buffer
, '(')) != NULL
) {
641 if ((last
= strchr(ptr
+ 1, ')')) !=NULL
) {
644 length
= last
- ptr
+ 1;
645 section
= emalloc(length
+ 5);
647 (void) memcpy(section
+ 1, ptr
, length
);
648 (void) strcpy(section
+ 1 + length
, " - ");
653 if (GetS(in
, buffer
, sizeof(buffer
)) == NULL
) {
657 catpreprocess(buffer
);
658 if (strncmp(buffer
, "NAME", 4) == 0)
662 section
= makesection(pathnamesection("/cat", name
));
665 size
= sizeof(buffer
) - 1;
666 while ((size
> 0) && (GetS(in
, ptr
, size
) != NULL
)) {
671 length
= strlen(ptr
);
675 ptr
= makewhatisline(name
, buffer
, section
);
679 if ((length
> 1) && (ptr
[length
- 1] == '-') &&
680 ISALPHA(ptr
[length
- 2]))
681 last
= &ptr
[--length
];
683 last
= &ptr
[length
++];
697 manpreprocess(char *line
)
702 while (ISSPACE(*from
))
704 if (strncmp(from
, ".\\\"", 3) == 0)
707 while (*from
!= '\0')
708 if (ISSPACE(*from
)) {
709 while (ISSPACE(*++from
));
710 if ((*from
!= '\0') && (*from
!= ','))
712 } else if (*from
== '\\') {
720 if ((*from
=='+') || (*from
=='-'))
722 while (ISDIGIT(*from
))
737 if (strncasecmp(line
, ".Xr", 3) == 0) {
744 if ((sect
= findwhitespace(from
)) != NULL
) {
749 if ((trail
= findwhitespace(sect
)) != NULL
)
751 length
= strlen(from
);
752 (void) memmove(line
, from
, length
);
753 line
[length
++] = '(';
755 length
= strlen(sect
);
756 (void) memmove(to
, sect
, length
);
758 (void) strcpy(&to
[length
], ")");
762 length
= strlen(trail
);
763 (void) memmove(to
, trail
, length
+ 1);
772 nroff(const char *inname
, gzFile
*in
)
774 char tempname
[MAXPATHLEN
], buffer
[65536], *data
;
775 int tempfd
, bytes
, pipefd
[2], status
;
776 static int devnull
= -1;
779 if (gzrewind(in
) < 0)
780 err(EXIT_FAILURE
, "Cannot rewind pipe");
783 ((devnull
= open(_PATH_DEVNULL
, O_WRONLY
, 0)) < 0))
784 err(EXIT_FAILURE
, "Cannot open `/dev/null'");
786 (void)strlcpy(tempname
, _PATH_TMP
"makewhatis.XXXXXX",
788 if ((tempfd
= mkstemp(tempname
)) == -1)
789 err(EXIT_FAILURE
, "Cannot create temp file");
791 while ((bytes
= gzread(in
, buffer
, sizeof(buffer
))) > 0)
792 if (write(tempfd
, buffer
, (size_t)bytes
) != bytes
) {
799 (void)unlink(tempname
);
800 err(EXIT_FAILURE
, "Read from pipe failed");
802 if (lseek(tempfd
, (off_t
)0, SEEK_SET
) == (off_t
)-1) {
804 (void)unlink(tempname
);
805 err(EXIT_FAILURE
, "Cannot rewind temp file");
807 if (pipe(pipefd
) == -1) {
809 (void)unlink(tempname
);
810 err(EXIT_FAILURE
, "Cannot create pipe");
813 switch (child
= vfork()) {
815 (void)close(pipefd
[1]);
816 (void)close(pipefd
[0]);
818 (void)unlink(tempname
);
819 err(EXIT_FAILURE
, "Fork failed");
822 (void)close(pipefd
[0]);
823 if (tempfd
!= STDIN_FILENO
) {
824 (void)dup2(tempfd
, STDIN_FILENO
);
827 if (pipefd
[1] != STDOUT_FILENO
) {
828 (void)dup2(pipefd
[1], STDOUT_FILENO
);
829 (void)close(pipefd
[1]);
831 if (devnull
!= STDERR_FILENO
) {
832 (void)dup2(devnull
, STDERR_FILENO
);
833 (void)close(devnull
);
835 (void)execlp(NROFF
, NROFF
, "-S", "-man", NULL
);
839 (void)close(pipefd
[1]);
844 if ((in
= gzdopen(pipefd
[0], "r")) == NULL
) {
847 (void)close(pipefd
[0]);
848 (void)kill(child
, SIGTERM
);
849 while (waitpid(child
, NULL
, 0) != child
);
850 (void)unlink(tempname
);
851 err(EXIT_FAILURE
, "Cannot read from pipe");
854 data
= parsecatpage(inname
, in
);
855 while (gzread(in
, buffer
, sizeof(buffer
)) > 0);
858 while (waitpid(child
, &status
, 0) != child
);
859 if ((data
!= NULL
) &&
860 !(WIFEXITED(status
) && (WEXITSTATUS(status
) == 0))) {
862 errx(EXIT_FAILURE
, NROFF
" on `%s' exited with %d status",
863 inname
, WEXITSTATUS(status
));
866 (void)unlink(tempname
);
871 parsemanpage(const char *name
, gzFile
*in
, int defaultsection
)
873 char *section
, buffer
[8192], *ptr
;
877 if (GetS(in
, buffer
, sizeof(buffer
) - 1) == NULL
) {
881 if (manpreprocess(buffer
))
883 if (strncasecmp(buffer
, ".Dt", 3) == 0) {
889 if ((ptr
= findwhitespace(ptr
)) == NULL
)
892 if ((end
= findwhitespace(++ptr
)) != NULL
)
896 section
= createsectionstring(ptr
);
898 else if (strncasecmp(buffer
, ".TH", 3) == 0) {
900 while (ISSPACE(*ptr
))
902 if ((ptr
= findwhitespace(ptr
)) != NULL
) {
905 while (ISSPACE(*ptr
))
907 if ((next
= findwhitespace(ptr
)) != NULL
)
910 section
= createsectionstring(ptr
);
913 else if (strncasecmp(buffer
, ".Ds", 3) == 0) {
917 } while (strncasecmp(buffer
, ".Sh NAME", 8) != 0);
920 if (GetS(in
, buffer
, sizeof(buffer
) - 1) == NULL
) {
924 } while (manpreprocess(buffer
));
926 if (strncasecmp(buffer
, ".Nm", 3) == 0) {
927 size_t length
, offset
;
930 while (ISSPACE(*ptr
))
933 length
= strlen(ptr
);
934 if ((length
> 1) && (ptr
[length
- 1] == ',') &&
935 ISSPACE(ptr
[length
- 2])) {
936 ptr
[--length
] = '\0';
937 ptr
[length
- 1] = ',';
939 (void) memmove(buffer
, ptr
, length
+ 1);
942 ptr
= &buffer
[offset
];
946 if ((sizeof(buffer
) == offset
) ||
947 (GetS(in
, ptr
, sizeof(buffer
) - offset
)
952 if (manpreprocess(ptr
))
955 if (strncasecmp(ptr
, ".Nm", 3) != 0) break;
961 buffer
[length
++] = ' ';
963 if ((more
> 1) && (ptr
[more
- 1] == ',') &&
964 ISSPACE(ptr
[more
- 2])) {
969 (void) memmove(&buffer
[length
], ptr
, more
+ 1);
973 ptr
= &buffer
[offset
];
976 if (strncasecmp(ptr
, ".Nd", 3) == 0) {
977 (void) strlcpy(&buffer
[length
], " -",
978 sizeof(buffer
) - length
);
980 while (strncasecmp(ptr
, ".Sh", 3) != 0) {
986 if (strncasecmp(ptr
, ".Nd", 3) != 0 ||
987 strchr(ptr
, '[') != NULL
) {
991 space
= findwhitespace(ptr
);
996 (void) strmove(ptr
, space
);
1001 buffer
[offset
- 1] = ' ';
1002 more
= strlen(ptr
) + 1;
1005 ptr
= &buffer
[offset
];
1006 if ((sizeof(buffer
) == offset
) ||
1007 (GetS(in
, ptr
, sizeof(buffer
) - offset
)
1012 if (manpreprocess(ptr
))
1020 if (*buffer
== '.') {
1023 if ((space
= findwhitespace(&buffer
[1])) == NULL
) {
1028 (void) strmove(buffer
, space
);
1031 offset
= strlen(buffer
) + 1;
1035 ptr
= &buffer
[offset
];
1036 if ((sizeof(buffer
) == offset
) ||
1037 (GetS(in
, ptr
, sizeof(buffer
) - offset
)
1042 if (manpreprocess(ptr
) || (*ptr
== '\0'))
1045 if ((strncasecmp(ptr
, ".Sh", 3) == 0) ||
1046 (strncasecmp(ptr
, ".Ss", 3) == 0))
1052 if ((space
= findwhitespace(ptr
)) == NULL
) {
1057 (void) memmove(ptr
, space
, strlen(space
) + 1);
1060 buffer
[offset
- 1] = ' ';
1062 if ((more
> 1) && (ptr
[more
- 1] == ',') &&
1063 ISSPACE(ptr
[more
- 2])) {
1064 ptr
[more
- 1] = '\0';
1065 ptr
[more
- 2] = ',';
1072 if (section
== NULL
)
1073 section
= makesection(defaultsection
);
1075 ptr
= makewhatisline(name
, buffer
, section
);
1081 getwhatisdata(char *name
)
1087 if ((in
= gzopen(name
, "r")) == NULL
) {
1090 err(EXIT_FAILURE
, "Cannot open `%s'", name
);
1094 section
= manpagesection(name
);
1096 data
= parsecatpage(name
, in
);
1098 data
= parsemanpage(name
, in
, section
);
1100 data
= nroff(name
, in
);
1108 processmanpages(manpage
**source
, whatis
**dest
)
1116 while (mp
!= NULL
) {
1120 if (mp
->mp_left
!= NULL
)
1121 processmanpages(&mp
->mp_left
, dest
);
1123 if ((data
= getwhatisdata(mp
->mp_name
)) != NULL
) {
1124 /* Pass eventual directory prefix to addwhatis() */
1125 if (mp
->mp_sdlen
> 0 && mp
->mp_sdlen
< sizeof(sd
)-1)
1126 strlcpy(sd
, &mp
->mp_name
[mp
->mp_sdoff
],
1131 addwhatis(dest
, data
, sd
);
1141 dumpwhatis(FILE *out
, whatis
*tree
)
1143 while (tree
!= NULL
) {
1145 dumpwhatis(out
, tree
->wi_left
);
1147 if ((tree
->wi_data
[0] && fputs(tree
->wi_prefix
, out
) == EOF
) ||
1148 (fputs(tree
->wi_data
, out
) == EOF
) ||
1149 (fputc('\n', out
) == EOF
))
1150 err(EXIT_FAILURE
, "Write failed");
1152 tree
= tree
->wi_right
;