makewhatis.c revision 1.22 1 /* $NetBSD: makewhatis.c,v 1.22 2002/03/07 20:37:14 jdolecek Exp $ */
2
3 /*-
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matthias Scheler.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 #if defined(__COPYRIGHT) && !defined(lint)
41 __COPYRIGHT("@(#) Copyright (c) 1999 The NetBSD Foundation, Inc.\n\
42 All rights reserved.\n");
43 #endif /* not lint */
44
45 #if defined(__RCSID) && !defined(lint)
46 __RCSID("$NetBSD: makewhatis.c,v 1.22 2002/03/07 20:37:14 jdolecek Exp $");
47 #endif /* not lint */
48
49 #if HAVE_CONFIG_H
50 #include "config.h"
51 #endif
52
53 #include <sys/types.h>
54 #include <sys/param.h>
55 #include <sys/stat.h>
56 #include <sys/wait.h>
57
58 #include <ctype.h>
59 #include <err.h>
60 #include <errno.h>
61 #include <fcntl.h>
62 #include <fts.h>
63 #include <locale.h>
64 #include <paths.h>
65 #include <signal.h>
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <string.h>
69 #include <unistd.h>
70 #include <zlib.h>
71
72 typedef struct manpagestruct manpage;
73 struct manpagestruct {
74 manpage *mp_left,*mp_right;
75 ino_t mp_inode;
76 size_t mp_sdoff;
77 size_t mp_sdlen;
78 char mp_name[1];
79 };
80
81 typedef struct whatisstruct whatis;
82 struct whatisstruct {
83 whatis *wi_left,*wi_right;
84 char *wi_data;
85 char wi_prefix[1];
86 };
87
88 int main(int, char * const *);
89 char *findwhitespace(char *);
90 char *strmove(char *,char *);
91 char *GetS(gzFile, char *, size_t);
92 int manpagesection(char *);
93 char *createsectionstring(char *);
94 void addmanpage(manpage **, ino_t, char *, size_t, size_t);
95 void addwhatis(whatis **, char *, char *);
96 char *replacestring(char *, char *, char *);
97 void catpreprocess(char *);
98 char *parsecatpage(gzFile *);
99 int manpreprocess(char *);
100 char *nroff(gzFile *);
101 char *parsemanpage(gzFile *, int);
102 char *getwhatisdata(char *);
103 void processmanpages(manpage **,whatis **);
104 void dumpwhatis(FILE *, whatis *);
105 void *emalloc(size_t);
106 char *estrdup(const char *);
107
108 char * const default_manpath[] = {
109 "/usr/share/man",
110 NULL
111 };
112
113 const char *sectionext = "0123456789ln";
114 const char *whatisdb = "whatis.db";
115
116 int
117 main(int argc, char *const *argv)
118 {
119 char * const *manpath;
120 FTS *fts;
121 FTSENT *fe;
122 manpage *source;
123 whatis *dest;
124 FILE *out;
125 size_t sdoff, sdlen;
126
127 (void)setlocale(LC_ALL, "");
128
129 manpath = (argc < 2) ? default_manpath : &argv[1];
130
131 if ((fts = fts_open(manpath, FTS_LOGICAL, NULL)) == NULL)
132 err(EXIT_FAILURE, "Cannot open `%s'", *manpath);
133
134 source = NULL;
135 while ((fe = fts_read(fts)) != NULL) {
136 switch (fe->fts_info) {
137 case FTS_F:
138 if (manpagesection(fe->fts_path) >= 0) {
139 /*
140 * Get manpage subdirectory prefix. Most
141 * commonly, this is arch-specific subdirectory.
142 */
143 if (fe->fts_level >= 3) {
144 int sl = fe->fts_level - 1;
145 const char *s, *lsl=NULL;
146
147 s = &fe->fts_path[fe->fts_pathlen-1];
148 for(; sl > 0; sl--) {
149 s--;
150 while(s[0] != '/') s--;
151 if (!lsl)
152 lsl = s;
153 }
154
155 /* Include trailing '/', so we get
156 * 'arch/'. */
157 sdoff = s + 1 - fe->fts_path;
158 sdlen = lsl - s + 1;
159 } else {
160 sdoff = 0;
161 sdlen = 0;
162 }
163
164 addmanpage(&source, fe->fts_statp->st_ino,
165 fe->fts_path, sdoff, sdlen);
166 }
167 /*FALLTHROUGH*/
168 case FTS_D:
169 case FTS_DC:
170 case FTS_DEFAULT:
171 case FTS_DP:
172 case FTS_SLNONE:
173 break;
174 default:
175 errno = fe->fts_errno;
176 err(EXIT_FAILURE, "Error reading `%s'", fe->fts_path);
177 }
178 }
179
180 (void)fts_close(fts);
181
182 dest = NULL;
183 processmanpages(&source, &dest);
184
185 if (chdir(manpath[0]) == -1)
186 err(EXIT_FAILURE, "Cannot change dir to `%s'", manpath[0]);
187
188 (void)unlink(whatisdb);
189 if ((out = fopen(whatisdb, "w")) == NULL)
190 err(EXIT_FAILURE, "Cannot open `%s'", whatisdb);
191
192 dumpwhatis(out, dest);
193 if (fchmod(fileno(out), S_IRUSR|S_IRGRP|S_IROTH) == -1)
194 err(EXIT_FAILURE, "Cannot chmod `%s'", whatisdb);
195 if (fclose(out) != 0)
196 err(EXIT_FAILURE, "Cannot close `%s'", whatisdb);
197
198 return EXIT_SUCCESS;
199 }
200
201 char *
202 findwhitespace(char *str)
203 {
204 while (!isspace((unsigned char)*str))
205 if (*str++ == '\0') {
206 str = NULL;
207 break;
208 }
209
210 return str;
211 }
212
213 char
214 *strmove(char *dest,char *src)
215 {
216 return memmove(dest, src, strlen(src) + 1);
217 }
218
219 char *
220 GetS(gzFile in, char *buffer, size_t length)
221 {
222 char *ptr;
223
224 if (((ptr = gzgets(in, buffer, (int)length)) != NULL) && (*ptr == '\0'))
225 ptr = NULL;
226
227 return ptr;
228 }
229
230 int
231 manpagesection(char *name)
232 {
233 char *ptr;
234
235 if ((ptr = strrchr(name, '/')) != NULL)
236 ptr++;
237 else
238 ptr = name;
239
240 while ((ptr = strchr(ptr, '.')) != NULL) {
241 int section;
242
243 ptr++;
244 section=0;
245 while (sectionext[section] != '\0')
246 if (sectionext[section] == *ptr)
247 return section;
248 else
249 section++;
250 }
251
252 return -1;
253 }
254
255 char *
256 createsectionstring(char *section_id)
257 {
258 char *section = emalloc(strlen(section_id) + 7);
259 section[0] = ' ';
260 section[1] = '(';
261 (void)strcat(strcpy(§ion[2], section_id), ") - ");
262 return section;
263 }
264
265 void
266 addmanpage(manpage **tree,ino_t inode,char *name, size_t sdoff, size_t sdlen)
267 {
268 manpage *mp;
269
270 while ((mp = *tree) != NULL) {
271 if (mp->mp_inode == inode)
272 return;
273 tree = inode < mp->mp_inode ? &mp->mp_left : &mp->mp_right;
274 }
275
276 mp = emalloc(sizeof(manpage) + strlen(name));
277 mp->mp_left = NULL;
278 mp->mp_right = NULL;
279 mp->mp_inode = inode;
280 mp->mp_sdoff = sdoff;
281 mp->mp_sdlen = sdlen;
282 (void)strcpy(mp->mp_name, name);
283 *tree = mp;
284 }
285
286 void
287 addwhatis(whatis **tree, char *data, char *prefix)
288 {
289 whatis *wi;
290 int result;
291
292 while (isspace((unsigned char)*data))
293 data++;
294
295 if (*data == '/') {
296 char *ptr;
297
298 ptr = ++data;
299 while ((*ptr != '\0') && !isspace((unsigned char)*ptr))
300 if (*ptr++ == '/')
301 data = ptr;
302 }
303
304 while ((wi = *tree) != NULL) {
305 result = strcmp(data, wi->wi_data);
306 if (result == 0) return;
307 tree = result < 0 ? &wi->wi_left : &wi->wi_right;
308 }
309
310 wi = emalloc(sizeof(whatis) + strlen(prefix));
311
312 wi->wi_left = NULL;
313 wi->wi_right = NULL;
314 wi->wi_data = data;
315 if (prefix[0] != '\0')
316 (void) strcpy(wi->wi_prefix, prefix);
317 else
318 wi->wi_prefix[0] = '\0';
319 *tree = wi;
320 }
321
322 void
323 catpreprocess(char *from)
324 {
325 char *to;
326
327 to = from;
328 while (isspace((unsigned char)*from)) from++;
329
330 while (*from != '\0')
331 if (isspace((unsigned char)*from)) {
332 while (isspace((unsigned char)*++from));
333 if (*from != '\0')
334 *to++ = ' ';
335 }
336 else if (*(from + 1) == '\10')
337 from += 2;
338 else
339 *to++ = *from++;
340
341 *to = '\0';
342 }
343
344 char *
345 replacestring(char *string, char *old, char *new)
346
347 {
348 char *ptr, *result;
349 size_t slength, olength, nlength, pos;
350
351 if (new == NULL)
352 return estrdup(string);
353
354 ptr = strstr(string, old);
355 if (ptr == NULL)
356 return estrdup(string);
357
358 slength = strlen(string);
359 olength = strlen(old);
360 nlength = strlen(new);
361 result = emalloc(slength - olength + nlength + 1);
362
363 pos = ptr - string;
364 (void)memcpy(result, string, pos);
365 (void)memcpy(&result[pos], new, nlength);
366 (void)strcpy(&result[pos + nlength], &string[pos + olength]);
367
368 return result;
369 }
370
371 char *
372 parsecatpage(gzFile *in)
373 {
374 char buffer[8192];
375 char *section, *ptr, *last;
376 size_t size;
377
378 do {
379 if (GetS(in, buffer, sizeof(buffer)) == NULL)
380 return NULL;
381 }
382 while (buffer[0] == '\n');
383
384 section = NULL;
385 if ((ptr = strchr(buffer, '(')) != NULL) {
386 if ((last = strchr(ptr + 1, ')')) !=NULL) {
387 size_t length;
388
389 length = last - ptr + 1;
390 section = emalloc(length + 5);
391 *section = ' ';
392 (void) memcpy(section + 1, ptr, length);
393 (void) strcpy(section + 1 + length, " - ");
394 }
395 }
396
397 for (;;) {
398 if (GetS(in, buffer, sizeof(buffer)) == NULL) {
399 free(section);
400 return NULL;
401 }
402 catpreprocess(buffer);
403 if (strncmp(buffer, "NAME", 4) == 0)
404 break;
405 }
406
407 ptr = last = buffer;
408 size = sizeof(buffer) - 1;
409 while ((size > 0) && (GetS(in, ptr, size) != NULL)) {
410 int length;
411
412 catpreprocess(ptr);
413
414 length = strlen(ptr);
415 if (length == 0) {
416 *last = '\0';
417
418 ptr = replacestring(buffer, " - ", section);
419 free(section);
420 return ptr;
421 }
422 if ((length > 1) && (ptr[length - 1] == '-') &&
423 isalpha(ptr[length - 2]))
424 last = &ptr[--length];
425 else {
426 last = &ptr[length++];
427 *last = ' ';
428 }
429
430 ptr += length;
431 size -= length;
432 }
433
434 free(section);
435
436 return NULL;
437 }
438
439 int
440 manpreprocess(char *line)
441 {
442 char *from, *to;
443
444 to = from = line;
445 while (isspace((unsigned char)*from)) from++;
446 if (strncmp(from, ".\\\"", 3) == 0)
447 return 1;
448
449 while (*from != '\0')
450 if (isspace((unsigned char)*from)) {
451 while (isspace((unsigned char)*++from));
452 if ((*from != '\0') && (*from != ','))
453 *to++ = ' ';
454 }
455 else if (*from == '\\')
456 switch (*++from) {
457 case '\0':
458 case '-':
459 break;
460 case 'f':
461 case 's':
462 from++;
463 if ((*from=='+') || (*from=='-'))
464 from++;
465 while (isdigit(*from))
466 from++;
467 break;
468 default:
469 from++;
470 }
471 else
472 if (*from == '"')
473 from++;
474 else
475 *to++ = *from++;
476
477 *to = '\0';
478
479 if (strncasecmp(line, ".Xr", 3) == 0) {
480 char *sect;
481
482 from = line + 3;
483 if (isspace((unsigned char)*from))
484 from++;
485
486 if ((sect = findwhitespace(from)) != NULL) {
487 size_t length;
488 char *trail;
489
490 *sect++ = '\0';
491 if ((trail = findwhitespace(sect)) != NULL)
492 *trail++ = '\0';
493 length = strlen(from);
494 (void) memmove(line, from, length);
495 line[length++] = '(';
496 to = &line[length];
497 length = strlen(sect);
498 (void) memmove(to, sect, length);
499 if (trail == NULL) {
500 (void) strcpy(&to[length], ")");
501 } else {
502 to += length;
503 *to++ = ')';
504 length = strlen(trail);
505 (void) memmove(to, trail, length + 1);
506 }
507 }
508 }
509
510 return 0;
511 }
512
513 char *
514 nroff(gzFile *in)
515 {
516 char tempname[MAXPATHLEN], buffer[65536], *data;
517 int tempfd, bytes, pipefd[2], status;
518 static int devnull = -1;
519 pid_t child;
520
521 if (gzrewind(in) < 0)
522 err(EXIT_FAILURE, "Cannot rewind pipe");
523
524 if ((devnull < 0) &&
525 ((devnull = open(_PATH_DEVNULL, O_WRONLY, 0)) < 0))
526 err(EXIT_FAILURE, "Cannot open `/dev/null'");
527
528 (void)strcpy(tempname, _PATH_TMP "makewhatis.XXXXXX");
529 if ((tempfd = mkstemp(tempname)) == -1)
530 err(EXIT_FAILURE, "Cannot create temp file");
531
532 while ((bytes = gzread(in, buffer, sizeof(buffer))) > 0)
533 if (write(tempfd, buffer, (size_t)bytes) != bytes) {
534 bytes = -1;
535 break;
536 }
537
538 if (bytes < 0) {
539 (void)close(tempfd);
540 (void)unlink(tempname);
541 err(EXIT_FAILURE, "Read from pipe failed");
542 }
543 if (lseek(tempfd, (off_t)0, SEEK_SET) == (off_t)-1) {
544 (void)close(tempfd);
545 (void)unlink(tempname);
546 err(EXIT_FAILURE, "Cannot rewind temp file");
547 }
548 if (pipe(pipefd) == -1) {
549 (void)close(tempfd);
550 (void)unlink(tempname);
551 err(EXIT_FAILURE, "Cannot create pipe");
552 }
553
554 switch (child = vfork()) {
555 case -1:
556 (void)close(pipefd[1]);
557 (void)close(pipefd[0]);
558 (void)close(tempfd);
559 (void)unlink(tempname);
560 err(EXIT_FAILURE, "Fork failed");
561 /* NOTREACHED */
562 case 0:
563 (void)close(pipefd[0]);
564 if (tempfd != STDIN_FILENO) {
565 (void)dup2(tempfd, STDIN_FILENO);
566 (void)close(tempfd);
567 }
568 if (pipefd[1] != STDOUT_FILENO) {
569 (void)dup2(pipefd[1], STDOUT_FILENO);
570 (void)close(pipefd[1]);
571 }
572 if (devnull != STDERR_FILENO) {
573 (void)dup2(devnull, STDERR_FILENO);
574 (void)close(devnull);
575 }
576 (void)execlp("nroff", "nroff", "-S", "-man", NULL);
577 _exit(EXIT_FAILURE);
578 /*NOTREACHED*/
579 default:
580 (void)close(pipefd[1]);
581 (void)close(tempfd);
582 break;
583 }
584
585 if ((in = gzdopen(pipefd[0], "r")) == NULL) {
586 if (errno == 0)
587 errno = ENOMEM;
588 (void)close(pipefd[0]);
589 (void)kill(child, SIGTERM);
590 while (waitpid(child, NULL, 0) != child);
591 (void)unlink(tempname);
592 err(EXIT_FAILURE, "Cannot read from pipe");
593 }
594
595 data = parsecatpage(in);
596 while (gzread(in, buffer, sizeof(buffer)) > 0);
597 (void)gzclose(in);
598
599 while (waitpid(child, &status, 0) != child);
600 if ((data != NULL) &&
601 !(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) {
602 free(data);
603 errx(EXIT_FAILURE, "nroff exited with %d status",
604 WEXITSTATUS(status));
605 }
606
607 (void)unlink(tempname);
608 return data;
609 }
610
611 char *
612 parsemanpage(gzFile *in, int defaultsection)
613 {
614 char *section, buffer[8192], *ptr;
615
616 section = NULL;
617 do {
618 if (GetS(in, buffer, sizeof(buffer) - 1) == NULL) {
619 free(section);
620 return NULL;
621 }
622 if (manpreprocess(buffer))
623 continue;
624 if (strncasecmp(buffer, ".Dt", 3) == 0) {
625 char *end;
626
627 ptr = &buffer[3];
628 if (isspace((unsigned char)*ptr))
629 ptr++;
630 if ((ptr = findwhitespace(ptr)) == NULL)
631 continue;
632
633 if ((end = findwhitespace(++ptr)) != NULL)
634 *end = '\0';
635
636 free(section);
637 section = createsectionstring(ptr);
638 }
639 else if (strncasecmp(buffer, ".TH", 3) == 0) {
640 ptr = &buffer[3];
641 while (isspace((unsigned char)*ptr))
642 ptr++;
643 if ((ptr = findwhitespace(ptr)) != NULL) {
644 char *next;
645
646 while (isspace((unsigned char)*ptr))
647 ptr++;
648 if ((next = findwhitespace(ptr)) != NULL)
649 *next = '\0';
650 free(section);
651 section = createsectionstring(ptr);
652 }
653 }
654 else if (strncasecmp(buffer, ".Ds", 3) == 0) {
655 free(section);
656 return NULL;
657 }
658 } while (strncasecmp(buffer, ".Sh NAME", 8) != 0);
659
660 do {
661 if (GetS(in, buffer, sizeof(buffer) - 1) == NULL) {
662 free(section);
663 return NULL;
664 }
665 } while (manpreprocess(buffer));
666
667 if (strncasecmp(buffer, ".Nm", 3) == 0) {
668 size_t length, offset;
669
670 ptr = &buffer[3];
671 while (isspace((unsigned char)*ptr))
672 ptr++;
673
674 length = strlen(ptr);
675 if ((length > 1) && (ptr[length - 1] == ',') &&
676 isspace((unsigned char)ptr[length - 2])) {
677 ptr[--length] = '\0';
678 ptr[length - 1] = ',';
679 }
680 (void) memmove(buffer, ptr, length + 1);
681
682 offset = length + 3;
683 ptr = &buffer[offset];
684 for (;;) {
685 size_t more;
686
687 if ((sizeof(buffer) == offset) ||
688 (GetS(in, ptr, sizeof(buffer) - offset)
689 == NULL)) {
690 free(section);
691 return NULL;
692 }
693 if (manpreprocess(ptr))
694 continue;
695
696 if (strncasecmp(ptr, ".Nm", 3) != 0) break;
697
698 ptr += 3;
699 if (isspace((unsigned char)*ptr))
700 ptr++;
701
702 buffer[length++] = ' ';
703 more = strlen(ptr);
704 if ((more > 1) && (ptr[more - 1] == ',') &&
705 isspace((unsigned char)ptr[more - 2])) {
706 ptr[--more] = '\0';
707 ptr[more - 1] = ',';
708 }
709
710 (void) memmove(&buffer[length], ptr, more + 1);
711 length += more;
712 offset = length + 3;
713
714 ptr = &buffer[offset];
715 }
716
717 if (strncasecmp(ptr, ".Nd", 3) == 0) {
718 (void) strcpy(&buffer[length], " -");
719
720 while (strncasecmp(ptr, ".Sh", 3) != 0) {
721 int more;
722
723 if (*ptr == '.') {
724 char *space;
725
726 if (strncasecmp(ptr, ".Nd", 3) != 0) {
727 free(section);
728 return NULL;
729 }
730 space = findwhitespace(ptr);
731 if (space == NULL)
732 ptr = "";
733 else {
734 space++;
735 (void) strmove(ptr, space);
736 }
737 }
738
739 if (*ptr != '\0') {
740 buffer[offset - 1] = ' ';
741 more = strlen(ptr) + 1;
742 offset += more;
743 }
744 ptr = &buffer[offset];
745 if ((sizeof(buffer) == offset) ||
746 (GetS(in, ptr, sizeof(buffer) - offset)
747 == NULL)) {
748 free(section);
749 return NULL;
750 }
751 if (manpreprocess(ptr))
752 *ptr = '\0';
753 }
754 }
755 }
756 else {
757 int offset;
758
759 if (*buffer == '.') {
760 char *space;
761
762 if ((space = findwhitespace(&buffer[1])) == NULL) {
763 free(section);
764 return NULL;
765 }
766 space++;
767 (void) strmove(buffer, space);
768 }
769
770 offset = strlen(buffer) + 1;
771 for (;;) {
772 int more;
773
774 ptr = &buffer[offset];
775 if ((sizeof(buffer) == offset) ||
776 (GetS(in, ptr, sizeof(buffer) - offset)
777 == NULL)) {
778 free(section);
779 return NULL;
780 }
781 if (manpreprocess(ptr) || (*ptr == '\0'))
782 continue;
783
784 if ((strncasecmp(ptr, ".Sh", 3) == 0) ||
785 (strncasecmp(ptr, ".Ss", 3) == 0))
786 break;
787
788 if (*ptr == '.') {
789 char *space;
790
791 if ((space = findwhitespace(ptr)) == NULL) {
792 continue;
793 }
794
795 space++;
796 (void) memmove(ptr, space, strlen(space) + 1);
797 }
798
799 buffer[offset - 1] = ' ';
800 more = strlen(ptr);
801 if ((more > 1) && (ptr[more - 1] == ',') &&
802 isspace((unsigned char)ptr[more - 2])) {
803 ptr[more - 1] = '\0';
804 ptr[more - 2] = ',';
805 }
806 else more++;
807 offset += more;
808 }
809 }
810
811 if (section == NULL) {
812 char sectionbuffer[24];
813
814 (void) sprintf(sectionbuffer, " (%c) - ",
815 sectionext[defaultsection]);
816 ptr = replacestring(buffer, " - ", sectionbuffer);
817 }
818 else {
819 ptr = replacestring(buffer, " - ", section);
820 free(section);
821 }
822 return ptr;
823 }
824
825 char *
826 getwhatisdata(char *name)
827 {
828 gzFile *in;
829 char *data;
830 int section;
831
832 if ((in = gzopen(name, "r")) == NULL) {
833 if (errno == 0)
834 errno = ENOMEM;
835 err(EXIT_FAILURE, "Cannot open `%s'", name);
836 /* NOTREACHED */
837 }
838
839 section = manpagesection(name);
840 if (section == 0)
841 data = parsecatpage(in);
842 else {
843 data = parsemanpage(in, section);
844 if (data == NULL)
845 data = nroff(in);
846 }
847
848 (void) gzclose(in);
849 return data;
850 }
851
852 void
853 processmanpages(manpage **source, whatis **dest)
854 {
855 manpage *mp;
856 char sd[128];
857
858 mp = *source;
859 *source = NULL;
860
861 while (mp != NULL) {
862 manpage *obsolete;
863 char *data;
864
865 if (mp->mp_left != NULL)
866 processmanpages(&mp->mp_left,dest);
867
868 if ((data = getwhatisdata(mp->mp_name)) != NULL) {
869 /* Pass eventual directory prefix to addwhatis() */
870 if (mp->mp_sdlen > 0 && mp->mp_sdlen < sizeof(sd)-1)
871 strlcpy(sd, &mp->mp_name[mp->mp_sdoff],
872 mp->mp_sdlen);
873 else
874 sd[0] = '\0';
875
876 addwhatis(dest, data, sd);
877 }
878
879 obsolete = mp;
880 mp = mp->mp_right;
881 free(obsolete);
882 }
883 }
884
885 void
886 dumpwhatis(FILE *out, whatis *tree)
887 {
888 while (tree != NULL) {
889 if (tree->wi_left)
890 dumpwhatis(out, tree->wi_left);
891
892 if ((tree->wi_data[0] && fputs(tree->wi_prefix, out) == EOF) ||
893 (fputs(tree->wi_data, out) == EOF) ||
894 (fputc('\n', out) == EOF))
895 err(EXIT_FAILURE, "Write failed");
896
897 tree = tree->wi_right;
898 }
899 }
900
901 void *
902 emalloc(size_t len)
903 {
904 void *ptr;
905 if ((ptr = malloc(len)) == NULL)
906 err(EXIT_FAILURE, "malloc %lu failed", (unsigned long)len);
907 return ptr;
908 }
909
910 char *
911 estrdup(const char *str)
912 {
913 char *ptr;
914 if ((ptr = strdup(str)) == NULL)
915 err(EXIT_FAILURE, "strdup failed");
916 return ptr;
917 }
918