1 /* $NetBSD: makewhatis.c,v 1.49 2013/06/24 20:57:47 christos 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.49 2013/06/24 20:57:47 christos 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
[] = {
112 #endif /* defined(__minix) */
117 static const char *sectionext
= "0123456789ln";
118 static const char *whatisdb
= _PATH_WHATIS
;
119 static const char *whatisdb_new
= _PATH_WHATIS
".new";
120 static int dowarn
= 0;
122 #define ISALPHA(c) isalpha((unsigned char)(c))
123 #define ISDIGIT(c) isdigit((unsigned char)(c))
124 #define ISSPACE(c) isspace((unsigned char)(c))
127 main(int argc
, char *const *argv
)
129 char * const *manpath
;
131 const char *conffile
;
134 int rv
, jobs
, status
;
136 char *paths
[2], **p
, *sl
;
142 retval
= EXIT_SUCCESS
;
144 (void)setlocale(LC_ALL
, "");
146 while ((c
= getopt(argc
, argv
, "C:fw")) != -1) {
152 /* run all processing on foreground */
159 fprintf(stderr
, "Usage: %s [-fw] [-C file] [manpath ...]\n",
171 return makewhatis(manpath
);
175 * Try read config file, fallback to default_manpath[]
176 * if man.conf not available.
179 if ((tp
= gettag("_whatdb", 0)) == NULL
) {
180 manpath
= default_manpath
;
184 /* Build individual databases */
186 TAILQ_FOREACH(ep
, &tp
->entrylist
, q
) {
187 if ((rv
= glob(ep
->s
,
188 GLOB_BRACE
| GLOB_NOSORT
| GLOB_ERR
| GLOB_NOCHECK
,
190 err(EXIT_FAILURE
, "glob('%s')", ep
->s
);
192 /* We always have something to work with here */
193 for (p
= pg
.gl_pathv
; *p
; p
++) {
194 sl
= strrchr(*p
, '/');
196 err(EXIT_FAILURE
, "glob: _whatdb entry '%s' "
197 "doesn't contain slash", ep
->s
);
201 * Cut the last component of path, leaving just
202 * the directory. We will use the result as root
203 * for manpage search.
204 * glob malloc()s space for the paths, so it's
205 * okay to change it in-place.
211 /* Do not fork child */
218 exit(makewhatis(paths
));
234 /* Wait for the childern to finish */
237 if (!WIFEXITED(status
) || WEXITSTATUS(status
) != EXIT_SUCCESS
)
238 retval
= EXIT_FAILURE
;
246 makewhatis(char * const * manpath
)
255 struct stat st_before
, st_after
;
257 if ((fts
= fts_open(manpath
, FTS_LOGICAL
, NULL
)) == NULL
)
258 err(EXIT_FAILURE
, "Cannot open `%s'", *manpath
);
261 while ((fe
= fts_read(fts
)) != NULL
) {
262 switch (fe
->fts_info
) {
264 if (manpagesection(fe
->fts_path
) >= 0) {
266 * Get manpage subdirectory prefix. Most
267 * commonly, this is arch-specific subdirectory.
269 if (fe
->fts_level
>= 3) {
274 s
= &fe
->fts_path
[fe
->fts_pathlen
- 1];
275 for(sl
= fe
->fts_level
- 1; sl
> 0;
285 * Include trailing '/', so we get
288 sdoff
= s
+ 1 - fe
->fts_path
;
295 addmanpage(&source
, fe
->fts_statp
->st_ino
,
296 fe
->fts_path
, sdoff
, sdlen
);
310 warnx("Symbolic link with no target: `%s'",
314 warnx("Unreadable directory: `%s'", fe
->fts_path
);
317 errno
= fe
->fts_errno
;
318 warn("Cannot stat `%s'", fe
->fts_path
);
321 errno
= fe
->fts_errno
;
322 warn("Error reading `%s'", fe
->fts_path
);
325 errx(EXIT_FAILURE
, "Unknown info %d returned from fts "
326 " for path: `%s'", fe
->fts_info
, fe
->fts_path
);
330 (void)fts_close(fts
);
333 processmanpages(&source
, &dest
);
335 if (chdir(manpath
[0]) == -1)
336 err(EXIT_FAILURE
, "Cannot change dir to `%s'", manpath
[0]);
339 * makewhatis runs unattended, so it needs to be able to
340 * recover if the last run crashed out. Therefore, if
341 * whatisdb_new exists and is more than (arbitrarily) sixteen
342 * hours old, nuke it. If it exists but is not so old, refuse
343 * to run until it's cleaned up, in case another makewhatis is
344 * already running. Also, open the output with O_EXCL to make
345 * sure we get our own, in case two copies start exactly at
346 * once. (Unlikely? Maybe, maybe not, if two copies of cron
349 * Similarly, before renaming the file after we finish writing
350 * to it, make sure it's still the same file we opened. This
351 * can't be completely race-free, but getting caught by it
352 * would require an unexplained sixteen-hour-or-more lag
353 * between the last mtime update when we wrote to it and when
354 * we get to the stat call *and* another makewhatis starting
355 * out to write at exactly the wrong moment. Not impossible,
356 * but not likely enough to worry about.
358 * This is maybe unnecessarily elaborate, but generating
359 * corrupted output isn't so good either.
362 if (stat(whatisdb_new
, &st_before
) == 0) {
363 if (st_before
.st_mtime
- time(NULL
) > 16*60*60) {
364 /* Don't complain if someone else just removed it. */
365 if (unlink(whatisdb_new
) == -1 && errno
!= ENOENT
) {
366 err(EXIT_FAILURE
, "Could not remove `%s'",
369 warnx("Removed stale `%s'", whatisdb_new
);
372 errx(EXIT_FAILURE
, "The file `%s' already exists "
373 "-- am I already running?", whatisdb_new
);
375 } else if (errno
!= ENOENT
) {
376 /* Something unexpected happened. */
377 err(EXIT_FAILURE
, "Cannot stat `%s'", whatisdb_new
);
380 outfd
= open(whatisdb_new
, O_WRONLY
|O_CREAT
|O_EXCL
,
381 S_IRUSR
|S_IRGRP
|S_IROTH
);
383 err(EXIT_FAILURE
, "Cannot open `%s'", whatisdb_new
);
385 if (fstat(outfd
, &st_before
) == -1)
386 err(EXIT_FAILURE
, "Cannot fstat `%s'", whatisdb_new
);
388 if ((out
= fdopen(outfd
, "w")) == NULL
)
389 err(EXIT_FAILURE
, "Cannot fdopen `%s'", whatisdb_new
);
391 dumpwhatis(out
, dest
);
392 if (fchmod(fileno(out
), S_IRUSR
|S_IRGRP
|S_IROTH
) == -1)
393 err(EXIT_FAILURE
, "Cannot chmod `%s'", whatisdb_new
);
394 if (fclose(out
) != 0)
395 err(EXIT_FAILURE
, "Cannot close `%s'", whatisdb_new
);
397 if (stat(whatisdb_new
, &st_after
) == -1)
398 err(EXIT_FAILURE
, "Cannot stat `%s' (after writing)",
401 if (st_before
.st_dev
!= st_after
.st_dev
||
402 st_before
.st_ino
!= st_after
.st_ino
) {
403 errx(EXIT_FAILURE
, "The file `%s' changed under me; giving up",
407 if (rename(whatisdb_new
, whatisdb
) == -1)
408 err(EXIT_FAILURE
, "Could not rename `%s' to `%s'",
409 whatisdb_new
, whatisdb
);
415 findwhitespace(char *str
)
417 while (!ISSPACE(*str
))
418 if (*str
++ == '\0') {
427 strmove(char *dest
, char *src
)
429 return memmove(dest
, src
, strlen(src
) + 1);
433 GetS(gzFile in
, char *buffer
, size_t length
)
437 if (((ptr
= gzgets(in
, buffer
, (int)length
)) != NULL
) && (*ptr
== '\0'))
446 char sectionbuffer
[24];
449 (void)snprintf(sectionbuffer
, sizeof(sectionbuffer
),
450 " (%c) - ", sectionext
[s
]);
451 return estrdup(sectionbuffer
);
455 pathnamesection(const char *pat
, const char *name
)
458 size_t len
= strlen(pat
);
461 while ((ptr
= strstr(name
, pat
)) != NULL
) {
462 if ((ext
= strchr(sectionext
, ptr
[len
])) != NULL
) {
463 return ext
- sectionext
;
472 manpagesection(char *name
)
476 if ((ptr
= strrchr(name
, '/')) != NULL
)
481 while ((ptr
= strchr(ptr
, '.')) != NULL
) {
486 while (sectionext
[section
] != '\0')
487 if (sectionext
[section
] == *ptr
)
496 createsectionstring(char *section_id
)
500 if (asprintf(§ion
, " (%s) - ", section_id
) < 0)
501 err(EXIT_FAILURE
, "malloc failed");
506 addmanpage(manpage
**tree
, ino_t inode
, char *name
, size_t sdoff
, size_t sdlen
)
510 while ((mp
= *tree
) != NULL
) {
511 if (mp
->mp_inode
== inode
)
513 tree
= inode
< mp
->mp_inode
? &mp
->mp_left
: &mp
->mp_right
;
516 mp
= emalloc(sizeof(manpage
) + strlen(name
));
519 mp
->mp_inode
= inode
;
520 mp
->mp_sdoff
= sdoff
;
521 mp
->mp_sdlen
= sdlen
;
522 (void)strcpy(mp
->mp_name
, name
);
527 addwhatis(whatis
**tree
, char *data
, char *prefix
)
532 while (ISSPACE(*data
))
539 while ((*ptr
!= '\0') && !ISSPACE(*ptr
))
544 while ((wi
= *tree
) != NULL
) {
545 result
= strcmp(data
, wi
->wi_data
);
546 if (result
== 0) result
= strcmp(prefix
, wi
->wi_prefix
);
547 if (result
== 0) return;
548 tree
= result
< 0 ? &wi
->wi_left
: &wi
->wi_right
;
551 wi
= emalloc(sizeof(whatis
) + strlen(prefix
));
556 if (prefix
[0] != '\0')
557 (void) strcpy(wi
->wi_prefix
, prefix
);
559 wi
->wi_prefix
[0] = '\0';
564 catpreprocess(char *from
)
569 while (ISSPACE(*from
)) from
++;
571 while (*from
!= '\0')
572 if (ISSPACE(*from
)) {
573 while (ISSPACE(*++from
));
577 else if (*(from
+ 1) == '\b')
586 makewhatisline(const char *file
, const char *line
, const char *section
)
588 static const char *del
[] = {
596 size_t llen
, slen
, dlen
;
600 if (section
== NULL
) {
602 warnx("%s: No section provided for `%s'", file
, line
);
603 return estrdup(line
);
606 for (i
= 0; del
[i
]; i
++)
607 if ((ptr
= strstr(line
, del
[i
])) != NULL
)
610 if (del
[i
] == NULL
) {
612 warnx("%s: Bad format line `%s'", file
, line
);
613 return estrdup(line
);
616 slen
= strlen(section
);
618 dlen
= strlen(del
[i
]);
620 result
= emalloc(llen
- dlen
+ slen
+ 1);
623 (void)memcpy(result
, line
, pos
);
624 (void)memcpy(&result
[pos
], section
, slen
);
625 (void)strcpy(&result
[pos
+ slen
], &line
[pos
+ dlen
]);
630 parsecatpage(const char *name
, gzFile
*in
)
633 char *section
, *ptr
, *last
;
637 if (GetS(in
, buffer
, sizeof(buffer
)) == NULL
)
640 while (buffer
[0] == '\n');
643 if ((ptr
= strchr(buffer
, '(')) != NULL
) {
644 if ((last
= strchr(ptr
+ 1, ')')) !=NULL
) {
647 length
= last
- ptr
+ 1;
648 section
= emalloc(length
+ 5);
650 (void) memcpy(section
+ 1, ptr
, length
);
651 (void) strcpy(section
+ 1 + length
, " - ");
656 if (GetS(in
, buffer
, sizeof(buffer
)) == NULL
) {
660 catpreprocess(buffer
);
661 if (strncmp(buffer
, "NAME", 4) == 0)
665 section
= makesection(pathnamesection("/cat", name
));
668 size
= sizeof(buffer
) - 1;
669 while ((size
> 0) && (GetS(in
, ptr
, size
) != NULL
)) {
674 length
= strlen(ptr
);
678 ptr
= makewhatisline(name
, buffer
, section
);
682 if ((length
> 1) && (ptr
[length
- 1] == '-') &&
683 ISALPHA(ptr
[length
- 2]))
684 last
= &ptr
[--length
];
686 last
= &ptr
[length
++];
700 manpreprocess(char *line
)
705 while (ISSPACE(*from
))
707 if (strncmp(from
, ".\\\"", 3) == 0)
710 while (*from
!= '\0')
711 if (ISSPACE(*from
)) {
712 while (ISSPACE(*++from
));
713 if ((*from
!= '\0') && (*from
!= ','))
715 } else if (*from
== '\\') {
723 if ((*from
=='+') || (*from
=='-'))
725 while (ISDIGIT(*from
))
740 if (strncasecmp(line
, ".Xr", 3) == 0) {
747 if ((sect
= findwhitespace(from
)) != NULL
) {
752 if ((trail
= findwhitespace(sect
)) != NULL
)
754 length
= strlen(from
);
755 (void) memmove(line
, from
, length
);
756 line
[length
++] = '(';
758 length
= strlen(sect
);
759 (void) memmove(to
, sect
, length
);
761 (void) strcpy(&to
[length
], ")");
765 length
= strlen(trail
);
766 (void) memmove(to
, trail
, length
+ 1);
775 nroff(const char *inname
, gzFile
*in
)
777 char tempname
[MAXPATHLEN
], buffer
[65536], *data
;
778 int tempfd
, bytes
, pipefd
[2], status
;
779 static int devnull
= -1;
782 if (gzrewind(in
) < 0)
783 err(EXIT_FAILURE
, "Cannot rewind pipe");
786 ((devnull
= open(_PATH_DEVNULL
, O_WRONLY
, 0)) < 0))
787 err(EXIT_FAILURE
, "Cannot open `/dev/null'");
789 (void)strlcpy(tempname
, _PATH_TMP
"makewhatis.XXXXXX",
791 if ((tempfd
= mkstemp(tempname
)) == -1)
792 err(EXIT_FAILURE
, "Cannot create temp file");
794 while ((bytes
= gzread(in
, buffer
, sizeof(buffer
))) > 0)
795 if (write(tempfd
, buffer
, (size_t)bytes
) != bytes
) {
802 (void)unlink(tempname
);
803 err(EXIT_FAILURE
, "Read from pipe failed");
805 if (lseek(tempfd
, (off_t
)0, SEEK_SET
) == (off_t
)-1) {
807 (void)unlink(tempname
);
808 err(EXIT_FAILURE
, "Cannot rewind temp file");
810 if (pipe(pipefd
) == -1) {
812 (void)unlink(tempname
);
813 err(EXIT_FAILURE
, "Cannot create pipe");
816 switch (child
= vfork()) {
818 (void)close(pipefd
[1]);
819 (void)close(pipefd
[0]);
821 (void)unlink(tempname
);
822 err(EXIT_FAILURE
, "Fork failed");
825 (void)close(pipefd
[0]);
826 if (tempfd
!= STDIN_FILENO
) {
827 (void)dup2(tempfd
, STDIN_FILENO
);
830 if (pipefd
[1] != STDOUT_FILENO
) {
831 (void)dup2(pipefd
[1], STDOUT_FILENO
);
832 (void)close(pipefd
[1]);
834 if (devnull
!= STDERR_FILENO
) {
835 (void)dup2(devnull
, STDERR_FILENO
);
836 (void)close(devnull
);
838 (void)execlp(NROFF
, NROFF
, "-S", "-man", NULL
);
842 (void)close(pipefd
[1]);
847 if ((in
= gzdopen(pipefd
[0], "r")) == NULL
) {
850 (void)close(pipefd
[0]);
851 (void)kill(child
, SIGTERM
);
852 while (waitpid(child
, NULL
, 0) != child
);
853 (void)unlink(tempname
);
854 err(EXIT_FAILURE
, "Cannot read from pipe");
857 data
= parsecatpage(inname
, in
);
858 while (gzread(in
, buffer
, sizeof(buffer
)) > 0);
861 while (waitpid(child
, &status
, 0) != child
);
862 if ((data
!= NULL
) &&
863 !(WIFEXITED(status
) && (WEXITSTATUS(status
) == 0))) {
865 errx(EXIT_FAILURE
, NROFF
" on `%s' exited with %d status",
866 inname
, WEXITSTATUS(status
));
869 (void)unlink(tempname
);
874 parsemanpage(const char *name
, gzFile
*in
, int defaultsection
)
876 char *section
, buffer
[8192], *ptr
;
877 static const char POD
[] = ".\\\" Automatically generated by Pod";
878 static const char IX
[] = ".IX TITLE";
882 if (GetS(in
, buffer
, sizeof(buffer
) - 1) == NULL
) {
888 * Skip over lines in man pages that have been generated
889 * by Pod, until we find the TITLE.
891 if (strncasecmp(buffer
, POD
, sizeof(POD
) - 1) == 0) {
893 if (GetS(in
, buffer
, sizeof(buffer
) - 1)
898 } while (strncasecmp(buffer
, IX
, sizeof(IX
) - 1) != 0);
901 if (manpreprocess(buffer
))
903 if (strncasecmp(buffer
, ".Dt", 3) == 0) {
909 if ((ptr
= findwhitespace(ptr
)) == NULL
)
912 if ((end
= findwhitespace(++ptr
)) != NULL
)
916 section
= createsectionstring(ptr
);
918 else if (strncasecmp(buffer
, ".TH", 3) == 0) {
920 while (ISSPACE(*ptr
))
922 if ((ptr
= findwhitespace(ptr
)) != NULL
) {
925 while (ISSPACE(*ptr
))
927 if ((next
= findwhitespace(ptr
)) != NULL
)
930 section
= createsectionstring(ptr
);
933 else if (strncasecmp(buffer
, ".Ds", 3) == 0) {
937 } while (strncasecmp(buffer
, ".Sh NAME", 8) != 0);
940 if (GetS(in
, buffer
, sizeof(buffer
) - 1) == NULL
) {
944 } while (manpreprocess(buffer
));
946 if (strncasecmp(buffer
, ".Nm", 3) == 0) {
947 size_t length
, offset
;
950 while (ISSPACE(*ptr
))
953 length
= strlen(ptr
);
954 if ((length
> 1) && (ptr
[length
- 1] == ',') &&
955 ISSPACE(ptr
[length
- 2])) {
956 ptr
[--length
] = '\0';
957 ptr
[length
- 1] = ',';
959 (void) memmove(buffer
, ptr
, length
+ 1);
962 ptr
= &buffer
[offset
];
966 if ((sizeof(buffer
) == offset
) ||
967 (GetS(in
, ptr
, sizeof(buffer
) - offset
)
972 if (manpreprocess(ptr
))
975 if (strncasecmp(ptr
, ".Nm", 3) != 0) break;
981 buffer
[length
++] = ' ';
983 if ((more
> 1) && (ptr
[more
- 1] == ',') &&
984 ISSPACE(ptr
[more
- 2])) {
989 (void) memmove(&buffer
[length
], ptr
, more
+ 1);
993 ptr
= &buffer
[offset
];
996 if (strncasecmp(ptr
, ".Nd", 3) == 0) {
997 (void) strlcpy(&buffer
[length
], " -",
998 sizeof(buffer
) - length
);
1000 while (strncasecmp(ptr
, ".Sh", 3) != 0) {
1006 if (strncasecmp(ptr
, ".Nd", 3) != 0 ||
1007 strchr(ptr
, '[') != NULL
) {
1011 space
= findwhitespace(ptr
);
1012 if (space
== NULL
) {
1016 (void) strmove(ptr
, space
);
1021 buffer
[offset
- 1] = ' ';
1022 more
= strlen(ptr
) + 1;
1025 ptr
= &buffer
[offset
];
1026 if ((sizeof(buffer
) == offset
) ||
1027 (GetS(in
, ptr
, sizeof(buffer
) - offset
)
1032 if (manpreprocess(ptr
))
1040 if (*buffer
== '.') {
1043 if ((space
= findwhitespace(&buffer
[1])) == NULL
) {
1048 (void) strmove(buffer
, space
);
1051 offset
= strlen(buffer
) + 1;
1055 ptr
= &buffer
[offset
];
1056 if ((sizeof(buffer
) == offset
) ||
1057 (GetS(in
, ptr
, sizeof(buffer
) - offset
)
1062 if (manpreprocess(ptr
) || (*ptr
== '\0'))
1065 if ((strncasecmp(ptr
, ".Sh", 3) == 0) ||
1066 (strncasecmp(ptr
, ".Ss", 3) == 0))
1072 if ((space
= findwhitespace(ptr
)) == NULL
) {
1077 (void) memmove(ptr
, space
, strlen(space
) + 1);
1080 buffer
[offset
- 1] = ' ';
1082 if ((more
> 1) && (ptr
[more
- 1] == ',') &&
1083 ISSPACE(ptr
[more
- 2])) {
1084 ptr
[more
- 1] = '\0';
1085 ptr
[more
- 2] = ',';
1092 if (section
== NULL
)
1093 section
= makesection(defaultsection
);
1095 ptr
= makewhatisline(name
, buffer
, section
);
1101 getwhatisdata(char *name
)
1107 if ((in
= gzopen(name
, "r")) == NULL
) {
1110 err(EXIT_FAILURE
, "Cannot open `%s'", name
);
1114 section
= manpagesection(name
);
1116 data
= parsecatpage(name
, in
);
1118 data
= parsemanpage(name
, in
, section
);
1120 data
= nroff(name
, in
);
1128 processmanpages(manpage
**source
, whatis
**dest
)
1136 while (mp
!= NULL
) {
1140 if (mp
->mp_left
!= NULL
)
1141 processmanpages(&mp
->mp_left
, dest
);
1143 if ((data
= getwhatisdata(mp
->mp_name
)) != NULL
) {
1144 /* Pass eventual directory prefix to addwhatis() */
1145 if (mp
->mp_sdlen
> 0 && mp
->mp_sdlen
< sizeof(sd
)-1)
1146 strlcpy(sd
, &mp
->mp_name
[mp
->mp_sdoff
],
1151 addwhatis(dest
, data
, sd
);
1161 dumpwhatis(FILE *out
, whatis
*tree
)
1163 while (tree
!= NULL
) {
1165 dumpwhatis(out
, tree
->wi_left
);
1167 if ((tree
->wi_data
[0] && fputs(tree
->wi_prefix
, out
) == EOF
) ||
1168 (fputs(tree
->wi_data
, out
) == EOF
) ||
1169 (fputc('\n', out
) == EOF
))
1170 err(EXIT_FAILURE
, "Write failed");
1172 tree
= tree
->wi_right
;