Allow setting an empty base directory. FTP server like tnftpd do not
[netbsd-mini2440.git] / libexec / getNAME / getNAME.c
blob6cfad4970df7a87a6c3828ce66d3a0d2658510b6
1 /* $NetBSD: getNAME.c,v 1.25 2006/09/12 21:56:43 hubertf Exp $ */
3 /*-
4 * Copyright (c) 1997, Christos Zoulas. All rights reserved.
5 * Copyright (c) 1980, 1993
6 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 #ifndef lint
35 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\
36 The Regents of the University of California. All rights reserved.");
37 #if 0
38 static char sccsid[] = "@(#)getNAME.c 8.1 (Berkeley) 6/30/93";
39 #else
40 __RCSID("$NetBSD: getNAME.c,v 1.25 2006/09/12 21:56:43 hubertf Exp $");
41 #endif
42 #endif /* not lint */
45 * Get name sections from manual pages.
46 * -t for building toc
47 * -i for building intro entries
48 * -w for querying type of manual source
49 * -v verbose
50 * other apropos database
52 #include <err.h>
53 #include <ctype.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
59 static int tocrc;
60 static int intro;
61 static int typeflag;
62 static int verbose;
64 #define SLOP 10 /* strlen(" () - ") < 10 */
66 static char *linebuf = NULL;
67 static size_t maxlen = 0;
70 static void doname(char *);
71 static void dorefname(char *);
72 static void getfrom(char *);
73 static void oldman(char *, char *);
74 static void newman(char *, char *);
75 static void remcomma(char *, size_t *);
76 static void remquote(char *, size_t *);
77 static void fixxref(char *, size_t *);
78 static void split(char *, char *);
79 static void usage(void);
81 int main(int, char *[]);
83 /* The .SH NAMEs that are allowed. */
84 static const char *names[] = { "name", "namn", 0 };
86 int
87 main(int argc, char *argv[])
89 int ch;
91 while ((ch = getopt(argc, argv, "itvw")) != -1)
92 switch (ch) {
93 case 'i':
94 intro = 1;
95 break;
96 case 't':
97 tocrc = 1;
98 break;
99 case 'v':
100 verbose = 1;
101 break;
102 case 'w':
103 typeflag = 1;
104 break;
105 case '?':
106 default:
107 usage();
109 argc -= optind;
110 argv += optind;
112 if (!*argv)
113 usage();
115 for (; *argv; ++argv)
116 getfrom(*argv);
117 return 0;
120 static void
121 getfrom(char *pathname)
123 char *name;
124 char *line;
125 size_t len;
127 if (freopen(pathname, "r", stdin) == 0) {
128 warn("Cannot open `%s'", pathname);
129 return;
131 if ((name = strrchr(pathname, '/')) != NULL)
132 name++;
133 else
134 name = pathname;
135 for (;;) {
136 if ((line = fgetln(stdin, &len)) == NULL) {
137 if (typeflag)
138 (void)printf("%-60s\tUNKNOWN\n", pathname);
139 if (verbose)
140 warnx("missing .TH or .Dt section in `%s'",
141 pathname);
142 return;
144 if (len < 3)
145 continue;
146 if (line[0] != '.')
147 continue;
148 if ((line[1] == 'T' && line[2] == 'H') ||
149 (line[1] == 't' && line[2] == 'h')) {
150 oldman(pathname, name);
151 return;
153 if (line[1] == 'D' && line[2] == 't') {
154 newman(pathname, name);
155 return;
160 static void
161 oldman(char *pathname, char *name)
163 char *line, *ext, *s, *newlinebuf;
164 size_t len, i, extlen;
165 size_t curlen = 0;
166 size_t newmaxlen;
167 size_t ocurlen = -1;
169 if (typeflag) {
170 (void)printf("%-60s\tOLD\n", pathname);
171 return;
173 for (;;) {
174 if ((line = fgetln(stdin, &len)) == NULL) {
175 if (verbose)
176 warnx("missing .SH section in `%s'", pathname);
177 return;
179 if (len < 4)
180 continue;
181 if (line[0] != '.')
182 continue;
183 if (line[1] == 'S' && line[2] == 'H')
184 break;
185 if (line[1] == 's' && line[2] == 'h')
186 break;
189 for (s = &line[3]; s < &line[len] &&
190 (isspace((unsigned char) *s) || *s == '"' || *s == '\''); s++)
191 continue;
192 if (s == &line[len]) {
193 warnx("missing argument to .SH in `%s'", pathname);
194 return;
196 for (i = 0; names[i]; i++)
197 if (strncasecmp(s, names[i], strlen(names[i])) == 0)
198 break;
199 if (names[i] == NULL) {
200 warnx("first .SH section is not \"NAME\" in `%s'", pathname);
201 return;
204 again:
205 if (tocrc)
206 doname(name);
208 for (i = 0;; i++) {
209 if ((line = fgetln(stdin, &len)) == NULL)
210 break;
211 if (line[0] == '.') {
212 if (line[1] == '\\' && line[2] == '"')
213 continue; /* [nt]roff comment */
214 if (line[1] == 'S' && line[2] == 'H')
215 break;
216 if (line[1] == 's' && line[2] == 'h')
217 break;
218 if (line[1] == 'P' && line[2] == 'P')
219 break;
220 if (line[1] == 'b' && line[2] == 'r') {
221 if (intro)
222 split(linebuf, name);
223 else
224 (void)printf("%s\n", linebuf);
225 curlen = ocurlen;
226 goto again;
229 if (line[len - 1] == '\n') {
230 line[len - 1] = '\0';
231 len--;
233 if ((ext = strrchr(name, '.')) != NULL) {
234 ext++;
235 extlen = strlen(ext);
237 else
238 extlen = 0;
240 if (maxlen + extlen < curlen + len + SLOP) {
241 newmaxlen = 2 * (curlen + len) + SLOP + extlen;
242 if ((newlinebuf = realloc(linebuf, newmaxlen)) == NULL)
243 err(1, NULL);
244 linebuf = newlinebuf;
245 maxlen = newmaxlen;
247 if (i != 0)
248 linebuf[curlen++] = ' ';
249 (void)memcpy(&linebuf[curlen], line, len);
250 ocurlen = curlen;
251 curlen += len;
252 linebuf[curlen] = '\0';
254 if(!tocrc && !intro) {
255 /* change the \- into (N) - */
256 if ((s = strstr(linebuf, "\\-")) != NULL) {
257 (void)memmove(s + extlen + 3, s + 1,
258 curlen - (s + 1 - linebuf));
259 curlen--;
260 if (extlen) {
261 *s++ = '(';
262 while (*ext)
263 *s++ = *ext++;
264 *s++ = ')';
265 *s++ = ' ';
266 curlen += extlen + 3;
268 linebuf[curlen] = '\0';
273 if (intro)
274 split(linebuf, name);
275 else
276 (void)printf("%s\n", linebuf);
277 return;
280 static void
281 newman(char *pathname, char *name)
283 char *line, *ext, *s, *newlinebuf;
284 size_t len, i, extlen;
285 size_t curlen = 0;
286 size_t newmaxlen;
288 if (typeflag) {
289 (void)printf("%-60s\tNEW\n", pathname);
290 return;
292 for (;;) {
293 if ((line = fgetln(stdin, &len)) == NULL) {
294 if (verbose)
295 warnx("missing .Sh section in `%s'", pathname);
296 return;
298 if (line[0] != '.')
299 continue;
300 if (line[1] == 'S' && line[2] == 'h')
301 break;
304 for (s = &line[3]; s < &line[len] && isspace((unsigned char) *s); s++)
305 continue;
306 if (s == &line[len]) {
307 warnx("missing argument to .Sh in `%s'", pathname);
308 return;
310 for (i = 0; names[i]; i++)
311 if (strncasecmp(s, names[i], strlen(names[i])) == 0)
312 break;
313 if (names[i] == NULL) {
314 warnx("first .SH section is not \"NAME\" in `%s'", pathname);
315 return;
318 if (tocrc)
319 doname(name);
321 for (i = 0;; i++) {
322 if ((line = fgetln(stdin, &len)) == NULL)
323 break;
325 if (line[0] == '.') {
326 if (line[1] == '\\' && line[2] == '"')
327 continue; /* [nt]roff comment */
328 if (line[1] == 'S' && line[2] == 'h')
329 break;
332 if (line[len - 1] == '\n') {
333 line[len - 1] = '\0';
334 len--;
337 if ((ext = strrchr(name, '.')) != NULL) {
338 ext++;
339 extlen = strlen(ext);
341 else
342 extlen = 0;
344 if (maxlen + extlen < curlen + len + SLOP) {
345 newmaxlen = 2 * (curlen + len) + SLOP + extlen;
346 if ((newlinebuf = realloc(linebuf, newmaxlen)) == NULL)
347 err(1, NULL);
348 linebuf = newlinebuf;
349 maxlen = newmaxlen;
352 if (i != 0)
353 linebuf[curlen++] = ' ';
355 remcomma(line, &len);
357 if (line[0] != '.') {
358 (void)memcpy(&linebuf[curlen], line, len);
359 curlen += len;
361 else {
362 remquote(line, &len);
363 fixxref(line, &len);
366 * Put section and dash between names and description.
368 if (line[1] == 'N' && line[2] == 'd') {
369 if(!tocrc && !intro) {
370 if (extlen) {
371 linebuf[curlen++] = '(';
372 while (*ext)
373 linebuf[curlen++] = *ext++;
374 linebuf[curlen++] = ')';
375 linebuf[curlen++] = ' ';
378 linebuf[curlen++] = '-';
379 linebuf[curlen++] = ' ';
382 * Skip over macro names.
384 if (len <= 4)
385 continue;
386 (void)memcpy(&linebuf[curlen], &line[4], len - 4);
387 curlen += len - 4;
390 linebuf[curlen] = '\0';
391 if (intro)
392 split(linebuf, name);
393 else
394 (void)printf("%s\n", linebuf);
398 * convert " ," -> " "
400 static void
401 remcomma(char *line, size_t *len)
403 char *pline = line, *loc;
404 size_t plen = *len;
406 while ((loc = memchr(pline, ' ', plen)) != NULL) {
407 plen -= loc - pline + 1;
408 pline = loc;
409 if (loc[1] == ',') {
410 (void)memcpy(loc, &loc[1], plen);
411 (*len)--;
413 else
414 pline++;
419 * Get rid of quotes in macros.
421 static void
422 remquote(char *line, size_t *len)
424 char *loc;
425 char *pline = &line[4];
426 size_t plen = *len - 4;
428 if (*len < 4)
429 return;
431 while ((loc = memchr(pline, '"', plen)) != NULL) {
432 plen -= loc - pline + 1;
433 pline = loc;
434 (void)memcpy(loc, &loc[1], plen);
435 (*len)--;
440 * Handle cross references
442 static void
443 fixxref(char *line, size_t *len)
445 char *loc;
446 char *pline = &line[4];
447 size_t plen = *len - 4;
449 if (*len < 4)
450 return;
452 if (line[1] == 'X' && line[2] == 'r') {
453 if ((loc = memchr(pline, ' ', plen)) != NULL) {
454 *loc++ = '(';
455 loc++;
456 *loc++ = ')';
457 *len = loc - line;
462 static void
463 doname(char *name)
465 char *dp = name, *ep;
467 again:
468 while (*dp && *dp != '.')
469 (void)putchar(*dp++);
470 if (*dp)
471 for (ep = dp+1; *ep; ep++)
472 if (*ep == '.') {
473 (void)putchar(*dp++);
474 goto again;
476 (void)putchar('(');
477 if (*dp)
478 dp++;
479 while (*dp)
480 (void)putchar(*dp++);
481 (void)putchar(')');
482 (void)putchar(' ');
485 static void
486 split(char *line, char *name)
488 char *cp, *dp;
489 char *sp;
490 const char *sep;
492 cp = strchr(line, '-');
493 if (cp == 0)
494 return;
495 sp = cp + 1;
496 for (--cp; *cp == ' ' || *cp == '\t' || *cp == '\\'; cp--)
498 *++cp = '\0';
499 while (*sp && (*sp == ' ' || *sp == '\t'))
500 sp++;
501 for (sep = "", dp = line; dp && *dp; dp = cp, sep = "\n") {
502 cp = strchr(dp, ',');
503 if (cp) {
504 char *tp;
506 for (tp = cp - 1; *tp == ' ' || *tp == '\t'; tp--)
508 *++tp = '\0';
509 for (++cp; *cp == ' ' || *cp == '\t'; cp++)
512 (void)printf("%s%s\t", sep, dp);
513 dorefname(name);
514 (void)printf("\t- %s", sp);
516 (void)putchar('\n');
519 static void
520 dorefname(char *name)
522 char *dp = name, *ep;
524 again:
525 while (*dp && *dp != '.')
526 (void)putchar(*dp++);
527 if (*dp)
528 for (ep = dp+1; *ep; ep++)
529 if (*ep == '.') {
530 (void)putchar(*dp++);
531 goto again;
533 (void)putchar('.');
534 if (*dp)
535 dp++;
536 while (*dp)
537 (void)putchar(*dp++);
540 static void
541 usage(void)
544 (void)fprintf(stderr, "Usage: %s [-itw] file ...\n", getprogname());
545 exit(1);