Sun Nov 16 06:26:12 2008 UTC ()
Minor KNF and whitespace nits. No functional change.


(dholland)
diff -r1.45 -r1.46 src/libexec/makewhatis/makewhatis.c

cvs diff -r1.45 -r1.46 src/libexec/makewhatis/makewhatis.c (switch to unified diff)

--- src/libexec/makewhatis/makewhatis.c 2008/11/16 06:17:05 1.45
+++ src/libexec/makewhatis/makewhatis.c 2008/11/16 06:26:12 1.46
@@ -1,1151 +1,1153 @@ @@ -1,1151 +1,1153 @@
1/* $NetBSD: makewhatis.c,v 1.45 2008/11/16 06:17:05 dholland Exp $ */ 1/* $NetBSD: makewhatis.c,v 1.46 2008/11/16 06:26:12 dholland Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1999 The NetBSD Foundation, Inc. 4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matthias Scheler. 8 * by Matthias Scheler.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 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 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 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 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 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32#if HAVE_NBTOOL_CONFIG_H 32#if HAVE_NBTOOL_CONFIG_H
33#include "nbtool_config.h" 33#include "nbtool_config.h"
34#endif 34#endif
35 35
36#include <sys/cdefs.h> 36#include <sys/cdefs.h>
37#if !defined(lint) 37#if !defined(lint)
38__COPYRIGHT("@(#) Copyright (c) 1999\ 38__COPYRIGHT("@(#) Copyright (c) 1999\
39 The NetBSD Foundation, Inc. All rights reserved."); 39 The NetBSD Foundation, Inc. All rights reserved.");
40__RCSID("$NetBSD: makewhatis.c,v 1.45 2008/11/16 06:17:05 dholland Exp $"); 40__RCSID("$NetBSD: makewhatis.c,v 1.46 2008/11/16 06:26:12 dholland Exp $");
41#endif /* not lint */ 41#endif /* not lint */
42 42
43#include <sys/types.h> 43#include <sys/types.h>
44#include <sys/param.h> 44#include <sys/param.h>
45#include <sys/queue.h> 45#include <sys/queue.h>
46#include <sys/stat.h> 46#include <sys/stat.h>
47#include <sys/wait.h> 47#include <sys/wait.h>
48 48
49#include <ctype.h> 49#include <ctype.h>
50#include <err.h> 50#include <err.h>
51#include <errno.h> 51#include <errno.h>
52#include <fcntl.h> 52#include <fcntl.h>
53#include <fts.h> 53#include <fts.h>
54#include <glob.h> 54#include <glob.h>
55#include <locale.h> 55#include <locale.h>
56#include <paths.h> 56#include <paths.h>
57#include <signal.h> 57#include <signal.h>
58#include <stdio.h> 58#include <stdio.h>
59#include <stdlib.h> 59#include <stdlib.h>
60#include <string.h> 60#include <string.h>
61#include <unistd.h> 61#include <unistd.h>
62#include <zlib.h> 62#include <zlib.h>
63#include <util.h> 63#include <util.h>
64 64
65#include <man/manconf.h> 65#include <man/manconf.h>
66#include <man/pathnames.h> 66#include <man/pathnames.h>
67 67
68#ifndef NROFF 68#ifndef NROFF
69#define NROFF "nroff" 69#define NROFF "nroff"
70#endif 70#endif
71 71
72typedef struct manpagestruct manpage; 72typedef struct manpagestruct manpage;
73struct manpagestruct { 73struct manpagestruct {
74 manpage *mp_left,*mp_right; 74 manpage *mp_left, *mp_right;
75 ino_t mp_inode; 75 ino_t mp_inode;
76 size_t mp_sdoff; 76 size_t mp_sdoff;
77 size_t mp_sdlen; 77 size_t mp_sdlen;
78 char mp_name[1]; 78 char mp_name[1];
79}; 79};
80 80
81typedef struct whatisstruct whatis; 81typedef struct whatisstruct whatis;
82struct whatisstruct { 82struct whatisstruct {
83 whatis *wi_left,*wi_right; 83 whatis *wi_left, *wi_right;
84 char *wi_data; 84 char *wi_data;
85 char wi_prefix[1]; 85 char wi_prefix[1];
86}; 86};
87 87
88int main(int, char * const *); 88int main(int, char * const *);
89static char *findwhitespace(char *); 89static char *findwhitespace(char *);
90static char *strmove(char *,char *); 90static char *strmove(char *, char *);
91static char *GetS(gzFile, char *, size_t); 91static char *GetS(gzFile, char *, size_t);
92static int pathnamesection(const char *, const char *); 92static int pathnamesection(const char *, const char *);
93static int manpagesection(char *); 93static int manpagesection(char *);
94static char *createsectionstring(char *); 94static char *createsectionstring(char *);
95static void addmanpage(manpage **, ino_t, char *, size_t, size_t); 95static void addmanpage(manpage **, ino_t, char *, size_t, size_t);
96static void addwhatis(whatis **, char *, char *); 96static void addwhatis(whatis **, char *, char *);
97static char *makesection(int); 97static char *makesection(int);
98static char *makewhatisline(const char *, const char *, const char *); 98static char *makewhatisline(const char *, const char *, const char *);
99static void catpreprocess(char *); 99static void catpreprocess(char *);
100static char *parsecatpage(const char *, gzFile *); 100static char *parsecatpage(const char *, gzFile *);
101static int manpreprocess(char *); 101static int manpreprocess(char *);
102static char *nroff(const char *, gzFile *); 102static char *nroff(const char *, gzFile *);
103static char *parsemanpage(const char *, gzFile *, int); 103static char *parsemanpage(const char *, gzFile *, int);
104static char *getwhatisdata(char *); 104static char *getwhatisdata(char *);
105static void processmanpages(manpage **,whatis **); 105static void processmanpages(manpage **, whatis **);
106static void dumpwhatis(FILE *, whatis *); 106static void dumpwhatis(FILE *, whatis *);
107static int makewhatis(char * const *manpath); 107static int makewhatis(char * const *manpath);
108 108
109static char * const default_manpath[] = { 109static char * const default_manpath[] = {
110 "/usr/share/man", 110 "/usr/share/man",
111 NULL 111 NULL
112}; 112};
113 113
114static const char *sectionext = "0123456789ln"; 114static const char *sectionext = "0123456789ln";
115static const char *whatisdb = _PATH_WHATIS; 115static const char *whatisdb = _PATH_WHATIS;
116static const char *whatisdb_new = _PATH_WHATIS ".new"; 116static const char *whatisdb_new = _PATH_WHATIS ".new";
117static int dowarn = 0; 117static int dowarn = 0;
118 118
119#define ISALPHA(c) isalpha((unsigned char)(c)) 119#define ISALPHA(c) isalpha((unsigned char)(c))
120#define ISDIGIT(c) isdigit((unsigned char)(c)) 120#define ISDIGIT(c) isdigit((unsigned char)(c))
121#define ISSPACE(c) isspace((unsigned char)(c)) 121#define ISSPACE(c) isspace((unsigned char)(c))
122 122
123int 123int
124main(int argc, char *const *argv) 124main(int argc, char *const *argv)
125{ 125{
126 char * const *manpath; 126 char * const *manpath;
127 int c, dofork; 127 int c, dofork;
128 const char *conffile; 128 const char *conffile;
129 ENTRY *ep; 129 ENTRY *ep;
130 TAG *tp; 130 TAG *tp;
131 int rv, jobs, status; 131 int rv, jobs, status;
132 glob_t pg; 132 glob_t pg;
133 char *paths[2], **p, *sl; 133 char *paths[2], **p, *sl;
134 int retval; 134 int retval;
135 135
136 dofork = 1; 136 dofork = 1;
137 conffile = NULL; 137 conffile = NULL;
138 jobs = 0; 138 jobs = 0;
139 retval = EXIT_SUCCESS; 139 retval = EXIT_SUCCESS;
140 140
141 (void)setlocale(LC_ALL, ""); 141 (void)setlocale(LC_ALL, "");
142 142
143 while ((c = getopt(argc, argv, "C:fw")) != -1) { 143 while ((c = getopt(argc, argv, "C:fw")) != -1) {
144 switch (c) { 144 switch (c) {
145 case 'C': 145 case 'C':
146 conffile = optarg; 146 conffile = optarg;
147 break; 147 break;
148 case 'f': 148 case 'f':
149 /* run all processing on foreground */ 149 /* run all processing on foreground */
150 dofork = 0; 150 dofork = 0;
151 break; 151 break;
152 case 'w': 152 case 'w':
153 dowarn++; 153 dowarn++;
154 break; 154 break;
155 default: 155 default:
156 fprintf(stderr, "Usage: %s [-fw] [-C file] [manpath ...]\n", 156 fprintf(stderr, "Usage: %s [-fw] [-C file] [manpath ...]\n",
157 getprogname()); 157 getprogname());
158 exit(EXIT_FAILURE); 158 exit(EXIT_FAILURE);
159 } 159 }
160 } 160 }
161 argc -= optind; 161 argc -= optind;
162 argv += optind; 162 argv += optind;
163  163
164 if (argc >= 1) { 164 if (argc >= 1) {
165 manpath = &argv[0]; 165 manpath = &argv[0];
166  166
167 mkwhatis: 167 mkwhatis:
168 return makewhatis(manpath); 168 return makewhatis(manpath);
169 } 169 }
170 170
171 /* 171 /*
172 * Try read config file, fallback to default_manpath[] 172 * Try read config file, fallback to default_manpath[]
173 * if man.conf not available. 173 * if man.conf not available.
174 */ 174 */
175 config(conffile); 175 config(conffile);
176 if ((tp = gettag("_whatdb", 0)) == NULL) { 176 if ((tp = gettag("_whatdb", 0)) == NULL) {
177 manpath = default_manpath; 177 manpath = default_manpath;
178 goto mkwhatis; 178 goto mkwhatis;
179 } 179 }
180 180
181 /* Build individual databases */ 181 /* Build individual databases */
182 paths[1] = NULL; 182 paths[1] = NULL;
183 TAILQ_FOREACH(ep, &tp->entrylist, q) { 183 TAILQ_FOREACH(ep, &tp->entrylist, q) {
184 if ((rv = glob(ep->s, 184 if ((rv = glob(ep->s,
185 GLOB_BRACE | GLOB_NOSORT | GLOB_ERR | GLOB_NOCHECK, 185 GLOB_BRACE | GLOB_NOSORT | GLOB_ERR | GLOB_NOCHECK,
186 NULL, &pg)) != 0) 186 NULL, &pg)) != 0)
187 err(EXIT_FAILURE, "glob('%s')", ep->s); 187 err(EXIT_FAILURE, "glob('%s')", ep->s);
188 188
189 /* We always have something to work with here */ 189 /* We always have something to work with here */
190 for (p = pg.gl_pathv; *p; p++) { 190 for (p = pg.gl_pathv; *p; p++) {
191 sl = strrchr(*p, '/'); 191 sl = strrchr(*p, '/');
192 if (sl == NULL) { 192 if (sl == NULL) {
193 err(EXIT_FAILURE, "glob: _whatdb entry '%s' " 193 err(EXIT_FAILURE, "glob: _whatdb entry '%s' "
194 "doesn't contain slash", ep->s); 194 "doesn't contain slash", ep->s);
195 } 195 }
196 196
197 /* 197 /*
198 * Cut the last component of path, leaving just 198 * Cut the last component of path, leaving just
199 * the directory. We will use the result as root 199 * the directory. We will use the result as root
200 * for manpage search. 200 * for manpage search.
201 * glob malloc()s space for the paths, so it's 201 * glob malloc()s space for the paths, so it's
202 * okay to change it in-place. 202 * okay to change it in-place.
203 */ 203 */
204 *sl = '\0'; 204 *sl = '\0';
205 paths[0] = *p; 205 paths[0] = *p;
206 206
207 if (!dofork) { 207 if (!dofork) {
208 /* Do not fork child */ 208 /* Do not fork child */
209 makewhatis(paths); 209 makewhatis(paths);
210 continue; 210 continue;
211 } 211 }
212 212
213 switch (fork()) { 213 switch (fork()) {
214 case 0: 214 case 0:
215 exit(makewhatis(paths)); 215 exit(makewhatis(paths));
216 break; 216 break;
217 case -1: 217 case -1:
218 warn("fork"); 218 warn("fork");
219 makewhatis(paths); 219 makewhatis(paths);
220 break; 220 break;
221 default: 221 default:
222 jobs++; 222 jobs++;
223 break; 223 break;
224 } 224 }
225  225
226 } 226 }
227 227
228 globfree(&pg); 228 globfree(&pg);
229 } 229 }
230 230
231 /* Wait for the childern to finish */ 231 /* Wait for the childern to finish */
232 while (jobs > 0) { 232 while (jobs > 0) {
233 (void)wait(&status); 233 (void)wait(&status);
234 if (!WIFEXITED(status) || WEXITSTATUS(status) != EXIT_SUCCESS) 234 if (!WIFEXITED(status) || WEXITSTATUS(status) != EXIT_SUCCESS)
235 retval = EXIT_FAILURE; 235 retval = EXIT_FAILURE;
236 jobs--; 236 jobs--;
237 } 237 }
238  238
239 return retval; 239 return retval;
240} 240}
241 241
242static int 242static int
243makewhatis(char * const * manpath) 243makewhatis(char * const * manpath)
244{ 244{
245 FTS *fts; 245 FTS *fts;
246 FTSENT *fe; 246 FTSENT *fe;
247 manpage *source; 247 manpage *source;
248 whatis *dest; 248 whatis *dest;
249 FILE *out; 249 FILE *out;
250 size_t sdoff, sdlen; 250 size_t sdoff, sdlen;
251 int outfd; 251 int outfd;
252 struct stat st_before, st_after; 252 struct stat st_before, st_after;
253 253
254 if ((fts = fts_open(manpath, FTS_LOGICAL, NULL)) == NULL) 254 if ((fts = fts_open(manpath, FTS_LOGICAL, NULL)) == NULL)
255 err(EXIT_FAILURE, "Cannot open `%s'", *manpath); 255 err(EXIT_FAILURE, "Cannot open `%s'", *manpath);
256 256
257 source = NULL; 257 source = NULL;
258 while ((fe = fts_read(fts)) != NULL) { 258 while ((fe = fts_read(fts)) != NULL) {
259 switch (fe->fts_info) { 259 switch (fe->fts_info) {
260 case FTS_F: 260 case FTS_F:
261 if (manpagesection(fe->fts_path) >= 0) { 261 if (manpagesection(fe->fts_path) >= 0) {
262 /* 262 /*
263 * Get manpage subdirectory prefix. Most 263 * Get manpage subdirectory prefix. Most
264 * commonly, this is arch-specific subdirectory. 264 * commonly, this is arch-specific subdirectory.
265 */ 265 */
266 if (fe->fts_level >= 3) { 266 if (fe->fts_level >= 3) {
267 int sl; 267 int sl;
268 const char *s, *lsl; 268 const char *s, *lsl;
269 269
270 lsl = NULL; 270 lsl = NULL;
271 s = &fe->fts_path[fe->fts_pathlen - 1]; 271 s = &fe->fts_path[fe->fts_pathlen - 1];
272 for(sl = fe->fts_level - 1; sl > 0; 272 for(sl = fe->fts_level - 1; sl > 0;
273 sl--) { 273 sl--) {
274 s--; 274 s--;
275 while (s[0] != '/') 275 while (s[0] != '/')
276 s--; 276 s--;
277 if (lsl == NULL) 277 if (lsl == NULL)
278 lsl = s; 278 lsl = s;
279 } 279 }
280  280
281 /* Include trailing '/', so we get 281 /*
282 * 'arch/'. */ 282 * Include trailing '/', so we get
 283 * 'arch/'.
 284 */
283 sdoff = s + 1 - fe->fts_path; 285 sdoff = s + 1 - fe->fts_path;
284 sdlen = lsl - s + 1; 286 sdlen = lsl - s + 1;
285 } else { 287 } else {
286 sdoff = 0; 288 sdoff = 0;
287 sdlen = 0; 289 sdlen = 0;
288 } 290 }
289 291
290 addmanpage(&source, fe->fts_statp->st_ino, 292 addmanpage(&source, fe->fts_statp->st_ino,
291 fe->fts_path, sdoff, sdlen); 293 fe->fts_path, sdoff, sdlen);
292 } 294 }
293 /*FALLTHROUGH*/ 295 /*FALLTHROUGH*/
294 case FTS_D: 296 case FTS_D:
295 case FTS_DC: 297 case FTS_DC:
296 case FTS_DEFAULT: 298 case FTS_DEFAULT:
297 case FTS_DP: 299 case FTS_DP:
298 case FTS_SL: 300 case FTS_SL:
299 case FTS_DOT: 301 case FTS_DOT:
300 case FTS_W: 302 case FTS_W:
301 case FTS_NSOK: 303 case FTS_NSOK:
302 case FTS_INIT: 304 case FTS_INIT:
303 break; 305 break;
304 case FTS_SLNONE: 306 case FTS_SLNONE:
305 warnx("Symbolic link with no target: `%s'", 307 warnx("Symbolic link with no target: `%s'",
306 fe->fts_path); 308 fe->fts_path);
307 break; 309 break;
308 case FTS_DNR: 310 case FTS_DNR:
309 warnx("Unreadable directory: `%s'", fe->fts_path); 311 warnx("Unreadable directory: `%s'", fe->fts_path);
310 break; 312 break;
311 case FTS_NS: 313 case FTS_NS:
312 errno = fe->fts_errno; 314 errno = fe->fts_errno;
313 warn("Cannot stat `%s'", fe->fts_path); 315 warn("Cannot stat `%s'", fe->fts_path);
314 break; 316 break;
315 case FTS_ERR: 317 case FTS_ERR:
316 errno = fe->fts_errno; 318 errno = fe->fts_errno;
317 warn("Error reading `%s'", fe->fts_path); 319 warn("Error reading `%s'", fe->fts_path);
318 break; 320 break;
319 default: 321 default:
320 errx(EXIT_FAILURE, "Unknown info %d returned from fts " 322 errx(EXIT_FAILURE, "Unknown info %d returned from fts "
321 " for path: `%s'", fe->fts_info, fe->fts_path); 323 " for path: `%s'", fe->fts_info, fe->fts_path);
322 } 324 }
323 } 325 }
324 326
325 (void)fts_close(fts); 327 (void)fts_close(fts);
326 328
327 dest = NULL; 329 dest = NULL;
328 processmanpages(&source, &dest); 330 processmanpages(&source, &dest);
329 331
330 if (chdir(manpath[0]) == -1) 332 if (chdir(manpath[0]) == -1)
331 err(EXIT_FAILURE, "Cannot change dir to `%s'", manpath[0]); 333 err(EXIT_FAILURE, "Cannot change dir to `%s'", manpath[0]);
332 334
333 /* 335 /*
334 * makewhatis runs unattended, so it needs to be able to 336 * makewhatis runs unattended, so it needs to be able to
335 * recover if the last run crashed out. Therefore, if 337 * recover if the last run crashed out. Therefore, if
336 * whatisdb_new exists and is more than (arbitrarily) sixteen 338 * whatisdb_new exists and is more than (arbitrarily) sixteen
337 * hours old, nuke it. If it exists but is not so old, refuse 339 * hours old, nuke it. If it exists but is not so old, refuse
338 * to run until it's cleaned up, in case another makewhatis is 340 * to run until it's cleaned up, in case another makewhatis is
339 * already running. Also, open the output with O_EXCL to make 341 * already running. Also, open the output with O_EXCL to make
340 * sure we get our own, in case two copies start exactly at 342 * sure we get our own, in case two copies start exactly at
341 * once. (Unlikely? Maybe, maybe not, if two copies of cron 343 * once. (Unlikely? Maybe, maybe not, if two copies of cron
342 * end up running.) 344 * end up running.)
343 * 345 *
344 * Similarly, before renaming the file after we finish writing 346 * Similarly, before renaming the file after we finish writing
345 * to it, make sure it's still the same file we opened. This 347 * to it, make sure it's still the same file we opened. This
346 * can't be completely race-free, but getting caught by it 348 * can't be completely race-free, but getting caught by it
347 * would require an unexplained sixteen-hour-or-more lag 349 * would require an unexplained sixteen-hour-or-more lag
348 * between the last mtime update when we wrote to it and when 350 * between the last mtime update when we wrote to it and when
349 * we get to the stat call *and* another makewhatis starting 351 * we get to the stat call *and* another makewhatis starting
350 * out to write at exactly the wrong moment. Not impossible, 352 * out to write at exactly the wrong moment. Not impossible,
351 * but not likely enough to worry about. 353 * but not likely enough to worry about.
352 * 354 *
353 * This is maybe unnecessarily elaborate, but generating 355 * This is maybe unnecessarily elaborate, but generating
354 * corrupted output isn't so good either. 356 * corrupted output isn't so good either.
355 */ 357 */
356 358
357 if (stat(whatisdb_new, &st_before) == 0) { 359 if (stat(whatisdb_new, &st_before) == 0) {
358 if (st_before.st_mtime - time(NULL) > 16*60*60) { 360 if (st_before.st_mtime - time(NULL) > 16*60*60) {
359 /* Don't complain if someone else just removed it. */ 361 /* Don't complain if someone else just removed it. */
360 if (unlink(whatisdb_new) == -1 && errno != ENOENT) { 362 if (unlink(whatisdb_new) == -1 && errno != ENOENT) {
361 err(EXIT_FAILURE, "Could not remove `%s'", 363 err(EXIT_FAILURE, "Could not remove `%s'",
362 whatisdb_new); 364 whatisdb_new);
363 } else { 365 } else {
364 warnx("Removed stale `%s'", whatisdb_new); 366 warnx("Removed stale `%s'", whatisdb_new);
365 } 367 }
366 } else { 368 } else {
367 errx(EXIT_FAILURE, "The file `%s' already exists " 369 errx(EXIT_FAILURE, "The file `%s' already exists "
368 "-- am I already running?", whatisdb_new); 370 "-- am I already running?", whatisdb_new);
369 } 371 }
370 } else if (errno != ENOENT) { 372 } else if (errno != ENOENT) {
371 /* Something unexpected happened. */ 373 /* Something unexpected happened. */
372 err(EXIT_FAILURE, "Cannot stat `%s'", whatisdb_new); 374 err(EXIT_FAILURE, "Cannot stat `%s'", whatisdb_new);
373 } 375 }
374 376
375 outfd = open(whatisdb_new, O_WRONLY|O_CREAT|O_EXCL, 377 outfd = open(whatisdb_new, O_WRONLY|O_CREAT|O_EXCL,
376 S_IRUSR|S_IRGRP|S_IROTH); 378 S_IRUSR|S_IRGRP|S_IROTH);
377 if (outfd < 0) 379 if (outfd < 0)
378 err(EXIT_FAILURE, "Cannot open `%s'", whatisdb_new); 380 err(EXIT_FAILURE, "Cannot open `%s'", whatisdb_new);
379 381
380 if (fstat(outfd, &st_before) == -1) 382 if (fstat(outfd, &st_before) == -1)
381 err(EXIT_FAILURE, "Cannot fstat `%s'", whatisdb_new); 383 err(EXIT_FAILURE, "Cannot fstat `%s'", whatisdb_new);
382 384
383 if ((out = fdopen(outfd, "w")) == NULL) 385 if ((out = fdopen(outfd, "w")) == NULL)
384 err(EXIT_FAILURE, "Cannot fdopen `%s'", whatisdb_new); 386 err(EXIT_FAILURE, "Cannot fdopen `%s'", whatisdb_new);
385 387
386 dumpwhatis(out, dest); 388 dumpwhatis(out, dest);
387 if (fchmod(fileno(out), S_IRUSR|S_IRGRP|S_IROTH) == -1) 389 if (fchmod(fileno(out), S_IRUSR|S_IRGRP|S_IROTH) == -1)
388 err(EXIT_FAILURE, "Cannot chmod `%s'", whatisdb_new); 390 err(EXIT_FAILURE, "Cannot chmod `%s'", whatisdb_new);
389 if (fclose(out) != 0) 391 if (fclose(out) != 0)
390 err(EXIT_FAILURE, "Cannot close `%s'", whatisdb_new); 392 err(EXIT_FAILURE, "Cannot close `%s'", whatisdb_new);
391 393
392 if (stat(whatisdb_new, &st_after) == -1) 394 if (stat(whatisdb_new, &st_after) == -1)
393 err(EXIT_FAILURE, "Cannot stat `%s' (after writing)", 395 err(EXIT_FAILURE, "Cannot stat `%s' (after writing)",
394 whatisdb_new); 396 whatisdb_new);
395 397
396 if (st_before.st_dev != st_after.st_dev || 398 if (st_before.st_dev != st_after.st_dev ||
397 st_before.st_ino != st_after.st_ino) { 399 st_before.st_ino != st_after.st_ino) {
398 errx(EXIT_FAILURE, "The file `%s' changed under me; giving up", 400 errx(EXIT_FAILURE, "The file `%s' changed under me; giving up",
399 whatisdb_new); 401 whatisdb_new);
400 } 402 }
401 403
402 if (rename(whatisdb_new, whatisdb) == -1) 404 if (rename(whatisdb_new, whatisdb) == -1)
403 err(EXIT_FAILURE, "Could not rename `%s' to `%s'", 405 err(EXIT_FAILURE, "Could not rename `%s' to `%s'",
404 whatisdb_new, whatisdb); 406 whatisdb_new, whatisdb);
405 407
406 return EXIT_SUCCESS; 408 return EXIT_SUCCESS;
407} 409}
408 410
409static char * 411static char *
410findwhitespace(char *str) 412findwhitespace(char *str)
411{ 413{
412 while (!ISSPACE(*str)) 414 while (!ISSPACE(*str))
413 if (*str++ == '\0') { 415 if (*str++ == '\0') {
414 str = NULL; 416 str = NULL;
415 break; 417 break;
416 } 418 }
417 419
418 return str; 420 return str;
419} 421}
420 422
421static char 423static char *
422*strmove(char *dest,char *src) 424strmove(char *dest, char *src)
423{ 425{
424 return memmove(dest, src, strlen(src) + 1); 426 return memmove(dest, src, strlen(src) + 1);
425} 427}
426 428
427static char * 429static char *
428GetS(gzFile in, char *buffer, size_t length) 430GetS(gzFile in, char *buffer, size_t length)
429{ 431{
430 char *ptr; 432 char *ptr;
431 433
432 if (((ptr = gzgets(in, buffer, (int)length)) != NULL) && (*ptr == '\0')) 434 if (((ptr = gzgets(in, buffer, (int)length)) != NULL) && (*ptr == '\0'))
433 ptr = NULL; 435 ptr = NULL;
434 436
435 return ptr; 437 return ptr;
436} 438}
437 439
438static char * 440static char *
439makesection(int s) 441makesection(int s)
440{ 442{
441 char sectionbuffer[24]; 443 char sectionbuffer[24];
442 if (s == -1) 444 if (s == -1)
443 return NULL; 445 return NULL;
444 (void)snprintf(sectionbuffer, sizeof(sectionbuffer), 446 (void)snprintf(sectionbuffer, sizeof(sectionbuffer),
445 " (%c) - ", sectionext[s]); 447 " (%c) - ", sectionext[s]);
446 return estrdup(sectionbuffer); 448 return estrdup(sectionbuffer);
447} 449}
448 450
449static int 451static int
450pathnamesection(const char *pat, const char *name) 452pathnamesection(const char *pat, const char *name)
451{ 453{
452 char *ptr, *ext; 454 char *ptr, *ext;
453 size_t len = strlen(pat); 455 size_t len = strlen(pat);
454 456
455 457
456 while ((ptr = strstr(name, pat)) != NULL) { 458 while ((ptr = strstr(name, pat)) != NULL) {
457 if ((ext = strchr(sectionext, ptr[len])) != NULL) { 459 if ((ext = strchr(sectionext, ptr[len])) != NULL) {
458 return ext - sectionext; 460 return ext - sectionext;
459 } 461 }
460 name = ptr + 1; 462 name = ptr + 1;
461 } 463 }
462 return -1; 464 return -1;
463} 465}
464 466
465 467
466static int 468static int
467manpagesection(char *name) 469manpagesection(char *name)
468{ 470{
469 char *ptr; 471 char *ptr;
470 472
471 if ((ptr = strrchr(name, '/')) != NULL) 473 if ((ptr = strrchr(name, '/')) != NULL)
472 ptr++; 474 ptr++;
473 else 475 else
474 ptr = name; 476 ptr = name;
475 477
476 while ((ptr = strchr(ptr, '.')) != NULL) { 478 while ((ptr = strchr(ptr, '.')) != NULL) {
477 int section; 479 int section;
478 480
479 ptr++; 481 ptr++;
480 section = 0; 482 section = 0;
481 while (sectionext[section] != '\0') 483 while (sectionext[section] != '\0')
482 if (sectionext[section] == *ptr) 484 if (sectionext[section] == *ptr)
483 return section; 485 return section;
484 else 486 else
485 section++; 487 section++;
486 } 488 }
487 return -1; 489 return -1;
488} 490}
489 491
490static char * 492static char *
491createsectionstring(char *section_id) 493createsectionstring(char *section_id)
492{ 494{
493 char *section; 495 char *section;
494 496
495 if (asprintf(&section, " (%s) - ", section_id) < 0) 497 if (asprintf(&section, " (%s) - ", section_id) < 0)
496 err(EXIT_FAILURE, "malloc failed"); 498 err(EXIT_FAILURE, "malloc failed");
497 return section; 499 return section;
498} 500}
499 501
500static void 502static void
501addmanpage(manpage **tree,ino_t inode,char *name, size_t sdoff, size_t sdlen) 503addmanpage(manpage **tree, ino_t inode, char *name, size_t sdoff, size_t sdlen)
502{ 504{
503 manpage *mp; 505 manpage *mp;
504 506
505 while ((mp = *tree) != NULL) { 507 while ((mp = *tree) != NULL) {
506 if (mp->mp_inode == inode) 508 if (mp->mp_inode == inode)
507 return; 509 return;
508 tree = inode < mp->mp_inode ? &mp->mp_left : &mp->mp_right; 510 tree = inode < mp->mp_inode ? &mp->mp_left : &mp->mp_right;
509 } 511 }
510 512
511 mp = emalloc(sizeof(manpage) + strlen(name)); 513 mp = emalloc(sizeof(manpage) + strlen(name));
512 mp->mp_left = NULL; 514 mp->mp_left = NULL;
513 mp->mp_right = NULL; 515 mp->mp_right = NULL;
514 mp->mp_inode = inode; 516 mp->mp_inode = inode;
515 mp->mp_sdoff = sdoff; 517 mp->mp_sdoff = sdoff;
516 mp->mp_sdlen = sdlen; 518 mp->mp_sdlen = sdlen;
517 (void)strcpy(mp->mp_name, name); 519 (void)strcpy(mp->mp_name, name);
518 *tree = mp; 520 *tree = mp;
519} 521}
520 522
521static void 523static void
522addwhatis(whatis **tree, char *data, char *prefix) 524addwhatis(whatis **tree, char *data, char *prefix)
523{ 525{
524 whatis *wi; 526 whatis *wi;
525 int result; 527 int result;
526 528
527 while (ISSPACE(*data)) 529 while (ISSPACE(*data))
528 data++; 530 data++;
529 531
530 if (*data == '/') { 532 if (*data == '/') {
531 char *ptr; 533 char *ptr;
532 534
533 ptr = ++data; 535 ptr = ++data;
534 while ((*ptr != '\0') && !ISSPACE(*ptr)) 536 while ((*ptr != '\0') && !ISSPACE(*ptr))
535 if (*ptr++ == '/') 537 if (*ptr++ == '/')
536 data = ptr; 538 data = ptr;
537 } 539 }
538 540
539 while ((wi = *tree) != NULL) { 541 while ((wi = *tree) != NULL) {
540 result = strcmp(data, wi->wi_data); 542 result = strcmp(data, wi->wi_data);
541 if (result == 0) return; 543 if (result == 0) return;
542 tree = result < 0 ? &wi->wi_left : &wi->wi_right; 544 tree = result < 0 ? &wi->wi_left : &wi->wi_right;
543 } 545 }
544 546
545 wi = emalloc(sizeof(whatis) + strlen(prefix)); 547 wi = emalloc(sizeof(whatis) + strlen(prefix));
546 548
547 wi->wi_left = NULL; 549 wi->wi_left = NULL;
548 wi->wi_right = NULL; 550 wi->wi_right = NULL;
549 wi->wi_data = data; 551 wi->wi_data = data;
550 if (prefix[0] != '\0') 552 if (prefix[0] != '\0')
551 (void) strcpy(wi->wi_prefix, prefix); 553 (void) strcpy(wi->wi_prefix, prefix);
552 else 554 else
553 wi->wi_prefix[0] = '\0'; 555 wi->wi_prefix[0] = '\0';
554 *tree = wi; 556 *tree = wi;
555} 557}
556 558
557static void 559static void
558catpreprocess(char *from) 560catpreprocess(char *from)
559{ 561{
560 char *to; 562 char *to;
561 563
562 to = from; 564 to = from;
563 while (ISSPACE(*from)) from++; 565 while (ISSPACE(*from)) from++;
564 566
565 while (*from != '\0') 567 while (*from != '\0')
566 if (ISSPACE(*from)) { 568 if (ISSPACE(*from)) {
567 while (ISSPACE(*++from)); 569 while (ISSPACE(*++from));
568 if (*from != '\0') 570 if (*from != '\0')
569 *to++ = ' '; 571 *to++ = ' ';
570 } 572 }
571 else if (*(from + 1) == '\b') 573 else if (*(from + 1) == '\b')
572 from += 2; 574 from += 2;
573 else 575 else
574 *to++ = *from++; 576 *to++ = *from++;
575 577
576 *to = '\0'; 578 *to = '\0';
577} 579}
578 580
579static char * 581static char *
580makewhatisline(const char *file, const char *line, const char *section) 582makewhatisline(const char *file, const char *line, const char *section)
581{ 583{
582 static const char *del[] = { 584 static const char *del[] = {
583 " - ", 585 " - ",
584 " -- ", 586 " -- ",
585 "- ", 587 "- ",
586 " -", 588 " -",
587 NULL 589 NULL
588 }; 590 };
589 size_t i, pos; 591 size_t i, pos;
590 size_t llen, slen, dlen; 592 size_t llen, slen, dlen;
591 char *result, *ptr; 593 char *result, *ptr;
592 594
593 ptr = NULL; 595 ptr = NULL;
594 if (section == NULL) { 596 if (section == NULL) {
595 if (dowarn) 597 if (dowarn)
596 warnx("%s: No section provided for `%s'", file, line); 598 warnx("%s: No section provided for `%s'", file, line);
597 return estrdup(line); 599 return estrdup(line);
598 } 600 }
599 601
600 for (i = 0; del[i]; i++) 602 for (i = 0; del[i]; i++)
601 if ((ptr = strstr(line, del[i])) != NULL) 603 if ((ptr = strstr(line, del[i])) != NULL)
602 break; 604 break;
603 605
604 if (del[i] == NULL) { 606 if (del[i] == NULL) {
605 if (dowarn) 607 if (dowarn)
606 warnx("%s: Bad format line `%s'", file, line); 608 warnx("%s: Bad format line `%s'", file, line);
607 return estrdup(line); 609 return estrdup(line);
608 } 610 }
609 611
610 slen = strlen(section); 612 slen = strlen(section);
611 llen = strlen(line); 613 llen = strlen(line);
612 dlen = strlen(del[i]); 614 dlen = strlen(del[i]);
613 615
614 result = emalloc(llen - dlen + slen + 1); 616 result = emalloc(llen - dlen + slen + 1);
615 pos = ptr - line; 617 pos = ptr - line;
616 618
617 (void)memcpy(result, line, pos); 619 (void)memcpy(result, line, pos);
618 (void)memcpy(&result[pos], section, slen); 620 (void)memcpy(&result[pos], section, slen);
619 (void)strcpy(&result[pos + slen], &line[pos + dlen]); 621 (void)strcpy(&result[pos + slen], &line[pos + dlen]);
620 return result; 622 return result;
621} 623}
622 624
623static char * 625static char *
624parsecatpage(const char *name, gzFile *in) 626parsecatpage(const char *name, gzFile *in)
625{ 627{
626 char buffer[8192]; 628 char buffer[8192];
627 char *section, *ptr, *last; 629 char *section, *ptr, *last;
628 size_t size; 630 size_t size;
629 631
630 do { 632 do {
631 if (GetS(in, buffer, sizeof(buffer)) == NULL) 633 if (GetS(in, buffer, sizeof(buffer)) == NULL)
632 return NULL; 634 return NULL;
633 } 635 }
634 while (buffer[0] == '\n'); 636 while (buffer[0] == '\n');
635 637
636 section = NULL; 638 section = NULL;
637 if ((ptr = strchr(buffer, '(')) != NULL) { 639 if ((ptr = strchr(buffer, '(')) != NULL) {
638 if ((last = strchr(ptr + 1, ')')) !=NULL) { 640 if ((last = strchr(ptr + 1, ')')) !=NULL) {
639 size_t length; 641 size_t length;
640 642
641 length = last - ptr + 1; 643 length = last - ptr + 1;
642 section = emalloc(length + 5); 644 section = emalloc(length + 5);
643 *section = ' '; 645 *section = ' ';
644 (void) memcpy(section + 1, ptr, length); 646 (void) memcpy(section + 1, ptr, length);
645 (void) strcpy(section + 1 + length, " - "); 647 (void) strcpy(section + 1 + length, " - ");
646 } 648 }
647 } 649 }
648 650
649 for (;;) { 651 for (;;) {
650 if (GetS(in, buffer, sizeof(buffer)) == NULL) { 652 if (GetS(in, buffer, sizeof(buffer)) == NULL) {
651 free(section); 653 free(section);
652 return NULL; 654 return NULL;
653 } 655 }
654 catpreprocess(buffer); 656 catpreprocess(buffer);
655 if (strncmp(buffer, "NAME", 4) == 0) 657 if (strncmp(buffer, "NAME", 4) == 0)
656 break; 658 break;
657 } 659 }
658 if (section == NULL) 660 if (section == NULL)
659 section = makesection(pathnamesection("/cat", name)); 661 section = makesection(pathnamesection("/cat", name));
660 662
661 ptr = last = buffer; 663 ptr = last = buffer;
662 size = sizeof(buffer) - 1; 664 size = sizeof(buffer) - 1;
663 while ((size > 0) && (GetS(in, ptr, size) != NULL)) { 665 while ((size > 0) && (GetS(in, ptr, size) != NULL)) {
664 int length; 666 int length;
665 667
666 catpreprocess(ptr); 668 catpreprocess(ptr);
667 669
668 length = strlen(ptr); 670 length = strlen(ptr);
669 if (length == 0) { 671 if (length == 0) {
670 *last = '\0'; 672 *last = '\0';
671 673
672 ptr = makewhatisline(name, buffer, section); 674 ptr = makewhatisline(name, buffer, section);
673 free(section); 675 free(section);
674 return ptr; 676 return ptr;
675 } 677 }
676 if ((length > 1) && (ptr[length - 1] == '-') && 678 if ((length > 1) && (ptr[length - 1] == '-') &&
677 ISALPHA(ptr[length - 2])) 679 ISALPHA(ptr[length - 2]))
678 last = &ptr[--length]; 680 last = &ptr[--length];
679 else { 681 else {
680 last = &ptr[length++]; 682 last = &ptr[length++];
681 *last = ' '; 683 *last = ' ';
682 } 684 }
683 685
684 ptr += length; 686 ptr += length;
685 size -= length; 687 size -= length;
686 } 688 }
687 689
688 free(section); 690 free(section);
689 691
690 return NULL; 692 return NULL;
691} 693}
692 694
693static int 695static int
694manpreprocess(char *line) 696manpreprocess(char *line)
695{ 697{
696 char *from, *to; 698 char *from, *to;
697 699
698 to = from = line; 700 to = from = line;
699 while (ISSPACE(*from)) 701 while (ISSPACE(*from))
700 from++; 702 from++;
701 if (strncmp(from, ".\\\"", 3) == 0) 703 if (strncmp(from, ".\\\"", 3) == 0)
702 return 1; 704 return 1;
703 705
704 while (*from != '\0') 706 while (*from != '\0')
705 if (ISSPACE(*from)) { 707 if (ISSPACE(*from)) {
706 while (ISSPACE(*++from)); 708 while (ISSPACE(*++from));
707 if ((*from != '\0') && (*from != ',')) 709 if ((*from != '\0') && (*from != ','))
708 *to++ = ' '; 710 *to++ = ' ';
709 } else if (*from == '\\') { 711 } else if (*from == '\\') {
710 switch (*++from) { 712 switch (*++from) {
711 case '\0': 713 case '\0':
712 case '-': 714 case '-':
713 break; 715 break;
714 case 'f': 716 case 'f':
715 case 's': 717 case 's':
716 from++; 718 from++;
717 if ((*from=='+') || (*from=='-')) 719 if ((*from=='+') || (*from=='-'))
718 from++; 720 from++;
719 while (ISDIGIT(*from)) 721 while (ISDIGIT(*from))
720 from++; 722 from++;
721 break; 723 break;
722 default: 724 default:
723 from++; 725 from++;
724 } 726 }
725 } else { 727 } else {
726 if (*from == '"') 728 if (*from == '"')
727 from++; 729 from++;
728 else 730 else
729 *to++ = *from++; 731 *to++ = *from++;
730 } 732 }
731 733
732 *to = '\0'; 734 *to = '\0';
733 735
734 if (strncasecmp(line, ".Xr", 3) == 0) { 736 if (strncasecmp(line, ".Xr", 3) == 0) {
735 char *sect; 737 char *sect;
736 738
737 from = line + 3; 739 from = line + 3;
738 if (ISSPACE(*from)) 740 if (ISSPACE(*from))
739 from++; 741 from++;
740 742
741 if ((sect = findwhitespace(from)) != NULL) { 743 if ((sect = findwhitespace(from)) != NULL) {
742 size_t length; 744 size_t length;
743 char *trail; 745 char *trail;
744 746
745 *sect++ = '\0'; 747 *sect++ = '\0';
746 if ((trail = findwhitespace(sect)) != NULL) 748 if ((trail = findwhitespace(sect)) != NULL)
747 *trail++ = '\0'; 749 *trail++ = '\0';
748 length = strlen(from); 750 length = strlen(from);
749 (void) memmove(line, from, length); 751 (void) memmove(line, from, length);
750 line[length++] = '('; 752 line[length++] = '(';
751 to = &line[length]; 753 to = &line[length];
752 length = strlen(sect); 754 length = strlen(sect);
753 (void) memmove(to, sect, length); 755 (void) memmove(to, sect, length);
754 if (trail == NULL) { 756 if (trail == NULL) {
755 (void) strcpy(&to[length], ")"); 757 (void) strcpy(&to[length], ")");
756 } else { 758 } else {
757 to += length; 759 to += length;
758 *to++ = ')'; 760 *to++ = ')';
759 length = strlen(trail); 761 length = strlen(trail);
760 (void) memmove(to, trail, length + 1); 762 (void) memmove(to, trail, length + 1);
761 } 763 }
762 } 764 }
763 } 765 }
764 766
765 return 0; 767 return 0;
766} 768}
767 769
768static char * 770static char *
769nroff(const char *inname, gzFile *in) 771nroff(const char *inname, gzFile *in)
770{ 772{
771 char tempname[MAXPATHLEN], buffer[65536], *data; 773 char tempname[MAXPATHLEN], buffer[65536], *data;
772 int tempfd, bytes, pipefd[2], status; 774 int tempfd, bytes, pipefd[2], status;
773 static int devnull = -1; 775 static int devnull = -1;
774 pid_t child; 776 pid_t child;
775 777
776 if (gzrewind(in) < 0) 778 if (gzrewind(in) < 0)
777 err(EXIT_FAILURE, "Cannot rewind pipe"); 779 err(EXIT_FAILURE, "Cannot rewind pipe");
778 780
779 if ((devnull < 0) && 781 if ((devnull < 0) &&
780 ((devnull = open(_PATH_DEVNULL, O_WRONLY, 0)) < 0)) 782 ((devnull = open(_PATH_DEVNULL, O_WRONLY, 0)) < 0))
781 err(EXIT_FAILURE, "Cannot open `/dev/null'"); 783 err(EXIT_FAILURE, "Cannot open `/dev/null'");
782 784
783 (void)strlcpy(tempname, _PATH_TMP "makewhatis.XXXXXX", 785 (void)strlcpy(tempname, _PATH_TMP "makewhatis.XXXXXX",
784 sizeof(tempname)); 786 sizeof(tempname));
785 if ((tempfd = mkstemp(tempname)) == -1) 787 if ((tempfd = mkstemp(tempname)) == -1)
786 err(EXIT_FAILURE, "Cannot create temp file"); 788 err(EXIT_FAILURE, "Cannot create temp file");
787 789
788 while ((bytes = gzread(in, buffer, sizeof(buffer))) > 0) 790 while ((bytes = gzread(in, buffer, sizeof(buffer))) > 0)
789 if (write(tempfd, buffer, (size_t)bytes) != bytes) { 791 if (write(tempfd, buffer, (size_t)bytes) != bytes) {
790 bytes = -1; 792 bytes = -1;
791 break; 793 break;
792 } 794 }
793 795
794 if (bytes < 0) { 796 if (bytes < 0) {
795 (void)close(tempfd); 797 (void)close(tempfd);
796 (void)unlink(tempname); 798 (void)unlink(tempname);
797 err(EXIT_FAILURE, "Read from pipe failed"); 799 err(EXIT_FAILURE, "Read from pipe failed");
798 } 800 }
799 if (lseek(tempfd, (off_t)0, SEEK_SET) == (off_t)-1) { 801 if (lseek(tempfd, (off_t)0, SEEK_SET) == (off_t)-1) {
800 (void)close(tempfd); 802 (void)close(tempfd);
801 (void)unlink(tempname); 803 (void)unlink(tempname);
802 err(EXIT_FAILURE, "Cannot rewind temp file"); 804 err(EXIT_FAILURE, "Cannot rewind temp file");
803 } 805 }
804 if (pipe(pipefd) == -1) { 806 if (pipe(pipefd) == -1) {
805 (void)close(tempfd); 807 (void)close(tempfd);
806 (void)unlink(tempname); 808 (void)unlink(tempname);
807 err(EXIT_FAILURE, "Cannot create pipe"); 809 err(EXIT_FAILURE, "Cannot create pipe");
808 } 810 }
809 811
810 switch (child = vfork()) { 812 switch (child = vfork()) {
811 case -1: 813 case -1:
812 (void)close(pipefd[1]); 814 (void)close(pipefd[1]);
813 (void)close(pipefd[0]); 815 (void)close(pipefd[0]);
814 (void)close(tempfd); 816 (void)close(tempfd);
815 (void)unlink(tempname); 817 (void)unlink(tempname);
816 err(EXIT_FAILURE, "Fork failed"); 818 err(EXIT_FAILURE, "Fork failed");
817 /* NOTREACHED */ 819 /* NOTREACHED */
818 case 0: 820 case 0:
819 (void)close(pipefd[0]); 821 (void)close(pipefd[0]);
820 if (tempfd != STDIN_FILENO) { 822 if (tempfd != STDIN_FILENO) {
821 (void)dup2(tempfd, STDIN_FILENO); 823 (void)dup2(tempfd, STDIN_FILENO);
822 (void)close(tempfd); 824 (void)close(tempfd);
823 } 825 }
824 if (pipefd[1] != STDOUT_FILENO) { 826 if (pipefd[1] != STDOUT_FILENO) {
825 (void)dup2(pipefd[1], STDOUT_FILENO); 827 (void)dup2(pipefd[1], STDOUT_FILENO);
826 (void)close(pipefd[1]); 828 (void)close(pipefd[1]);
827 } 829 }
828 if (devnull != STDERR_FILENO) { 830 if (devnull != STDERR_FILENO) {
829 (void)dup2(devnull, STDERR_FILENO); 831 (void)dup2(devnull, STDERR_FILENO);
830 (void)close(devnull); 832 (void)close(devnull);
831 } 833 }
832 (void)execlp(NROFF, NROFF, "-S", "-man", NULL); 834 (void)execlp(NROFF, NROFF, "-S", "-man", NULL);
833 _exit(EXIT_FAILURE); 835 _exit(EXIT_FAILURE);
834 /*NOTREACHED*/ 836 /*NOTREACHED*/
835 default: 837 default:
836 (void)close(pipefd[1]); 838 (void)close(pipefd[1]);
837 (void)close(tempfd); 839 (void)close(tempfd);
838 break; 840 break;
839 } 841 }
840 842
841 if ((in = gzdopen(pipefd[0], "r")) == NULL) { 843 if ((in = gzdopen(pipefd[0], "r")) == NULL) {
842 if (errno == 0) 844 if (errno == 0)
843 errno = ENOMEM; 845 errno = ENOMEM;
844 (void)close(pipefd[0]); 846 (void)close(pipefd[0]);
845 (void)kill(child, SIGTERM); 847 (void)kill(child, SIGTERM);
846 while (waitpid(child, NULL, 0) != child); 848 while (waitpid(child, NULL, 0) != child);
847 (void)unlink(tempname); 849 (void)unlink(tempname);
848 err(EXIT_FAILURE, "Cannot read from pipe"); 850 err(EXIT_FAILURE, "Cannot read from pipe");
849 } 851 }
850 852
851 data = parsecatpage(inname, in); 853 data = parsecatpage(inname, in);
852 while (gzread(in, buffer, sizeof(buffer)) > 0); 854 while (gzread(in, buffer, sizeof(buffer)) > 0);
853 (void)gzclose(in); 855 (void)gzclose(in);
854 856
855 while (waitpid(child, &status, 0) != child); 857 while (waitpid(child, &status, 0) != child);
856 if ((data != NULL) && 858 if ((data != NULL) &&
857 !(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) { 859 !(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) {
858 free(data); 860 free(data);
859 errx(EXIT_FAILURE, NROFF " on `%s' exited with %d status", 861 errx(EXIT_FAILURE, NROFF " on `%s' exited with %d status",
860 inname, WEXITSTATUS(status)); 862 inname, WEXITSTATUS(status));
861 } 863 }
862 864
863 (void)unlink(tempname); 865 (void)unlink(tempname);
864 return data; 866 return data;
865} 867}
866 868
867static char * 869static char *
868parsemanpage(const char *name, gzFile *in, int defaultsection) 870parsemanpage(const char *name, gzFile *in, int defaultsection)
869{ 871{
870 char *section, buffer[8192], *ptr; 872 char *section, buffer[8192], *ptr;
871 873
872 section = NULL; 874 section = NULL;
873 do { 875 do {
874 if (GetS(in, buffer, sizeof(buffer) - 1) == NULL) { 876 if (GetS(in, buffer, sizeof(buffer) - 1) == NULL) {
875 free(section); 877 free(section);
876 return NULL; 878 return NULL;
877 } 879 }
878 if (manpreprocess(buffer)) 880 if (manpreprocess(buffer))
879 continue; 881 continue;
880 if (strncasecmp(buffer, ".Dt", 3) == 0) { 882 if (strncasecmp(buffer, ".Dt", 3) == 0) {
881 char *end; 883 char *end;
882 884
883 ptr = &buffer[3]; 885 ptr = &buffer[3];
884 if (ISSPACE(*ptr)) 886 if (ISSPACE(*ptr))
885 ptr++; 887 ptr++;
886 if ((ptr = findwhitespace(ptr)) == NULL) 888 if ((ptr = findwhitespace(ptr)) == NULL)
887 continue; 889 continue;
888 890
889 if ((end = findwhitespace(++ptr)) != NULL) 891 if ((end = findwhitespace(++ptr)) != NULL)
890 *end = '\0'; 892 *end = '\0';
891 893
892 free(section); 894 free(section);
893 section = createsectionstring(ptr); 895 section = createsectionstring(ptr);
894 } 896 }
895 else if (strncasecmp(buffer, ".TH", 3) == 0) { 897 else if (strncasecmp(buffer, ".TH", 3) == 0) {
896 ptr = &buffer[3]; 898 ptr = &buffer[3];
897 while (ISSPACE(*ptr)) 899 while (ISSPACE(*ptr))
898 ptr++; 900 ptr++;
899 if ((ptr = findwhitespace(ptr)) != NULL) { 901 if ((ptr = findwhitespace(ptr)) != NULL) {
900 char *next; 902 char *next;
901 903
902 while (ISSPACE(*ptr)) 904 while (ISSPACE(*ptr))
903 ptr++; 905 ptr++;
904 if ((next = findwhitespace(ptr)) != NULL) 906 if ((next = findwhitespace(ptr)) != NULL)
905 *next = '\0'; 907 *next = '\0';
906 free(section); 908 free(section);
907 section = createsectionstring(ptr); 909 section = createsectionstring(ptr);
908 } 910 }
909 } 911 }
910 else if (strncasecmp(buffer, ".Ds", 3) == 0) { 912 else if (strncasecmp(buffer, ".Ds", 3) == 0) {
911 free(section); 913 free(section);
912 return NULL; 914 return NULL;
913 } 915 }
914 } while (strncasecmp(buffer, ".Sh NAME", 8) != 0); 916 } while (strncasecmp(buffer, ".Sh NAME", 8) != 0);
915 917
916 do { 918 do {
917 if (GetS(in, buffer, sizeof(buffer) - 1) == NULL) { 919 if (GetS(in, buffer, sizeof(buffer) - 1) == NULL) {
918 free(section); 920 free(section);
919 return NULL; 921 return NULL;
920 } 922 }
921 } while (manpreprocess(buffer)); 923 } while (manpreprocess(buffer));
922 924
923 if (strncasecmp(buffer, ".Nm", 3) == 0) { 925 if (strncasecmp(buffer, ".Nm", 3) == 0) {
924 size_t length, offset; 926 size_t length, offset;
925 927
926 ptr = &buffer[3]; 928 ptr = &buffer[3];
927 while (ISSPACE(*ptr)) 929 while (ISSPACE(*ptr))
928 ptr++; 930 ptr++;
929 931
930 length = strlen(ptr); 932 length = strlen(ptr);
931 if ((length > 1) && (ptr[length - 1] == ',') && 933 if ((length > 1) && (ptr[length - 1] == ',') &&
932 ISSPACE(ptr[length - 2])) { 934 ISSPACE(ptr[length - 2])) {
933 ptr[--length] = '\0'; 935 ptr[--length] = '\0';
934 ptr[length - 1] = ','; 936 ptr[length - 1] = ',';
935 } 937 }
936 (void) memmove(buffer, ptr, length + 1); 938 (void) memmove(buffer, ptr, length + 1);
937 939
938 offset = length + 3; 940 offset = length + 3;
939 ptr = &buffer[offset]; 941 ptr = &buffer[offset];
940 for (;;) { 942 for (;;) {
941 size_t more; 943 size_t more;
942 944
943 if ((sizeof(buffer) == offset) || 945 if ((sizeof(buffer) == offset) ||
944 (GetS(in, ptr, sizeof(buffer) - offset) 946 (GetS(in, ptr, sizeof(buffer) - offset)
945 == NULL)) { 947 == NULL)) {
946 free(section); 948 free(section);
947 return NULL; 949 return NULL;
948 } 950 }
949 if (manpreprocess(ptr)) 951 if (manpreprocess(ptr))
950 continue; 952 continue;
951 953
952 if (strncasecmp(ptr, ".Nm", 3) != 0) break; 954 if (strncasecmp(ptr, ".Nm", 3) != 0) break;
953 955
954 ptr += 3; 956 ptr += 3;
955 if (ISSPACE(*ptr)) 957 if (ISSPACE(*ptr))
956 ptr++; 958 ptr++;
957 959
958 buffer[length++] = ' '; 960 buffer[length++] = ' ';
959 more = strlen(ptr); 961 more = strlen(ptr);
960 if ((more > 1) && (ptr[more - 1] == ',') && 962 if ((more > 1) && (ptr[more - 1] == ',') &&
961 ISSPACE(ptr[more - 2])) { 963 ISSPACE(ptr[more - 2])) {
962 ptr[--more] = '\0'; 964 ptr[--more] = '\0';
963 ptr[more - 1] = ','; 965 ptr[more - 1] = ',';
964 } 966 }
965 967
966 (void) memmove(&buffer[length], ptr, more + 1); 968 (void) memmove(&buffer[length], ptr, more + 1);
967 length += more; 969 length += more;
968 offset = length + 3; 970 offset = length + 3;
969 971
970 ptr = &buffer[offset]; 972 ptr = &buffer[offset];
971 } 973 }
972 974
973 if (strncasecmp(ptr, ".Nd", 3) == 0) { 975 if (strncasecmp(ptr, ".Nd", 3) == 0) {
974 (void) strlcpy(&buffer[length], " -", 976 (void) strlcpy(&buffer[length], " -",
975 sizeof(buffer) - length); 977 sizeof(buffer) - length);
976 978
977 while (strncasecmp(ptr, ".Sh", 3) != 0) { 979 while (strncasecmp(ptr, ".Sh", 3) != 0) {
978 int more; 980 int more;
979 981
980 if (*ptr == '.') { 982 if (*ptr == '.') {
981 char *space; 983 char *space;
982 984
983 if (strncasecmp(ptr, ".Nd", 3) != 0 || 985 if (strncasecmp(ptr, ".Nd", 3) != 0 ||
984 strchr(ptr, '[') != NULL) { 986 strchr(ptr, '[') != NULL) {
985 free(section); 987 free(section);
986 return NULL; 988 return NULL;
987 } 989 }
988 space = findwhitespace(ptr); 990 space = findwhitespace(ptr);
989 if (space == NULL) { 991 if (space == NULL) {
990 ptr = ""; 992 ptr = "";
991 } else { 993 } else {
992 space++; 994 space++;
993 (void) strmove(ptr, space); 995 (void) strmove(ptr, space);
994 } 996 }
995 } 997 }
996 998
997 if (*ptr != '\0') { 999 if (*ptr != '\0') {
998 buffer[offset - 1] = ' '; 1000 buffer[offset - 1] = ' ';
999 more = strlen(ptr) + 1; 1001 more = strlen(ptr) + 1;
1000 offset += more; 1002 offset += more;
1001 } 1003 }
1002 ptr = &buffer[offset]; 1004 ptr = &buffer[offset];
1003 if ((sizeof(buffer) == offset) || 1005 if ((sizeof(buffer) == offset) ||
1004 (GetS(in, ptr, sizeof(buffer) - offset) 1006 (GetS(in, ptr, sizeof(buffer) - offset)
1005 == NULL)) { 1007 == NULL)) {
1006 free(section); 1008 free(section);
1007 return NULL; 1009 return NULL;
1008 } 1010 }
1009 if (manpreprocess(ptr)) 1011 if (manpreprocess(ptr))
1010 *ptr = '\0'; 1012 *ptr = '\0';
1011 } 1013 }
1012 } 1014 }
1013 } 1015 }
1014 else { 1016 else {
1015 int offset; 1017 int offset;
1016 1018
1017 if (*buffer == '.') { 1019 if (*buffer == '.') {
1018 char *space; 1020 char *space;
1019 1021
1020 if ((space = findwhitespace(&buffer[1])) == NULL) { 1022 if ((space = findwhitespace(&buffer[1])) == NULL) {
1021 free(section); 1023 free(section);
1022 return NULL; 1024 return NULL;
1023 } 1025 }
1024 space++; 1026 space++;
1025 (void) strmove(buffer, space); 1027 (void) strmove(buffer, space);
1026 } 1028 }
1027 1029
1028 offset = strlen(buffer) + 1; 1030 offset = strlen(buffer) + 1;
1029 for (;;) { 1031 for (;;) {
1030 int more; 1032 int more;
1031 1033
1032 ptr = &buffer[offset]; 1034 ptr = &buffer[offset];
1033 if ((sizeof(buffer) == offset) || 1035 if ((sizeof(buffer) == offset) ||
1034 (GetS(in, ptr, sizeof(buffer) - offset) 1036 (GetS(in, ptr, sizeof(buffer) - offset)
1035 == NULL)) { 1037 == NULL)) {
1036 free(section); 1038 free(section);
1037 return NULL; 1039 return NULL;
1038 } 1040 }
1039 if (manpreprocess(ptr) || (*ptr == '\0')) 1041 if (manpreprocess(ptr) || (*ptr == '\0'))
1040 continue; 1042 continue;
1041 1043
1042 if ((strncasecmp(ptr, ".Sh", 3) == 0) || 1044 if ((strncasecmp(ptr, ".Sh", 3) == 0) ||
1043 (strncasecmp(ptr, ".Ss", 3) == 0)) 1045 (strncasecmp(ptr, ".Ss", 3) == 0))
1044 break; 1046 break;
1045 1047
1046 if (*ptr == '.') { 1048 if (*ptr == '.') {
1047 char *space; 1049 char *space;
1048 1050
1049 if ((space = findwhitespace(ptr)) == NULL) { 1051 if ((space = findwhitespace(ptr)) == NULL) {
1050 continue; 1052 continue;
1051 } 1053 }
1052 1054
1053 space++; 1055 space++;
1054 (void) memmove(ptr, space, strlen(space) + 1); 1056 (void) memmove(ptr, space, strlen(space) + 1);
1055 } 1057 }
1056 1058
1057 buffer[offset - 1] = ' '; 1059 buffer[offset - 1] = ' ';
1058 more = strlen(ptr); 1060 more = strlen(ptr);
1059 if ((more > 1) && (ptr[more - 1] == ',') && 1061 if ((more > 1) && (ptr[more - 1] == ',') &&
1060 ISSPACE(ptr[more - 2])) { 1062 ISSPACE(ptr[more - 2])) {
1061 ptr[more - 1] = '\0'; 1063 ptr[more - 1] = '\0';
1062 ptr[more - 2] = ','; 1064 ptr[more - 2] = ',';
1063 } 1065 }
1064 else more++; 1066 else more++;
1065 offset += more; 1067 offset += more;
1066 } 1068 }
1067 } 1069 }
1068 1070
1069 if (section == NULL) 1071 if (section == NULL)
1070 section = makesection(defaultsection); 1072 section = makesection(defaultsection);
1071 1073
1072 ptr = makewhatisline(name, buffer, section); 1074 ptr = makewhatisline(name, buffer, section);
1073 free(section); 1075 free(section);
1074 return ptr; 1076 return ptr;
1075} 1077}
1076 1078
1077static char * 1079static char *
1078getwhatisdata(char *name) 1080getwhatisdata(char *name)
1079{ 1081{
1080 gzFile *in; 1082 gzFile *in;
1081 char *data; 1083 char *data;
1082 int section; 1084 int section;
1083 1085
1084 if ((in = gzopen(name, "r")) == NULL) { 1086 if ((in = gzopen(name, "r")) == NULL) {
1085 if (errno == 0) 1087 if (errno == 0)
1086 errno = ENOMEM; 1088 errno = ENOMEM;
1087 err(EXIT_FAILURE, "Cannot open `%s'", name); 1089 err(EXIT_FAILURE, "Cannot open `%s'", name);
1088 /* NOTREACHED */ 1090 /* NOTREACHED */
1089 } 1091 }
1090 1092
1091 section = manpagesection(name); 1093 section = manpagesection(name);
1092 if (section == 0) { 1094 if (section == 0) {
1093 data = parsecatpage(name, in); 1095 data = parsecatpage(name, in);
1094 } else { 1096 } else {
1095 data = parsemanpage(name, in, section); 1097 data = parsemanpage(name, in, section);
1096 if (data == NULL) 1098 if (data == NULL)
1097 data = nroff(name, in); 1099 data = nroff(name, in);
1098 } 1100 }
1099 1101
1100 (void) gzclose(in); 1102 (void) gzclose(in);
1101 return data; 1103 return data;
1102} 1104}
1103 1105
1104static void 1106static void
1105processmanpages(manpage **source, whatis **dest) 1107processmanpages(manpage **source, whatis **dest)
1106{ 1108{
1107 manpage *mp; 1109 manpage *mp;
1108 char sd[128]; 1110 char sd[128];
1109 1111
1110 mp = *source; 1112 mp = *source;
1111 *source = NULL; 1113 *source = NULL;
1112 1114
1113 while (mp != NULL) { 1115 while (mp != NULL) {
1114 manpage *obsolete; 1116 manpage *obsolete;
1115 char *data; 1117 char *data;
1116 1118
1117 if (mp->mp_left != NULL) 1119 if (mp->mp_left != NULL)
1118 processmanpages(&mp->mp_left,dest); 1120 processmanpages(&mp->mp_left, dest);
1119 1121
1120 if ((data = getwhatisdata(mp->mp_name)) != NULL) { 1122 if ((data = getwhatisdata(mp->mp_name)) != NULL) {
1121 /* Pass eventual directory prefix to addwhatis() */ 1123 /* Pass eventual directory prefix to addwhatis() */
1122 if (mp->mp_sdlen > 0 && mp->mp_sdlen < sizeof(sd)-1) 1124 if (mp->mp_sdlen > 0 && mp->mp_sdlen < sizeof(sd)-1)
1123 strlcpy(sd, &mp->mp_name[mp->mp_sdoff], 1125 strlcpy(sd, &mp->mp_name[mp->mp_sdoff],
1124 mp->mp_sdlen); 1126 mp->mp_sdlen);
1125 else 1127 else
1126 sd[0] = '\0'; 1128 sd[0] = '\0';
1127 1129
1128 addwhatis(dest, data, sd); 1130 addwhatis(dest, data, sd);
1129 } 1131 }
1130 1132
1131 obsolete = mp; 1133 obsolete = mp;
1132 mp = mp->mp_right; 1134 mp = mp->mp_right;
1133 free(obsolete); 1135 free(obsolete);
1134 } 1136 }
1135} 1137}
1136 1138
1137static void 1139static void
1138dumpwhatis(FILE *out, whatis *tree) 1140dumpwhatis(FILE *out, whatis *tree)
1139{ 1141{
1140 while (tree != NULL) { 1142 while (tree != NULL) {
1141 if (tree->wi_left) 1143 if (tree->wi_left)
1142 dumpwhatis(out, tree->wi_left); 1144 dumpwhatis(out, tree->wi_left);
1143 1145
1144 if ((tree->wi_data[0] && fputs(tree->wi_prefix, out) == EOF) || 1146 if ((tree->wi_data[0] && fputs(tree->wi_prefix, out) == EOF) ||
1145 (fputs(tree->wi_data, out) == EOF) || 1147 (fputs(tree->wi_data, out) == EOF) ||
1146 (fputc('\n', out) == EOF)) 1148 (fputc('\n', out) == EOF))
1147 err(EXIT_FAILURE, "Write failed"); 1149 err(EXIT_FAILURE, "Write failed");
1148 1150
1149 tree = tree->wi_right; 1151 tree = tree->wi_right;
1150 } 1152 }
1151} 1153}