getNAME.c revision 1.15 1 /* $NetBSD: getNAME.c,v 1.15 1998/10/10 02:53:12 hubertf Exp $ */
2
3 /*-
4 * Copyright (c) 1997, Christos Zoulas
5 * Copyright (c) 1980, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
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. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * This product includes software developed by Christos Zoulas.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38 #include <sys/cdefs.h>
39 #ifndef lint
40 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\
41 The Regents of the University of California. All rights reserved.\n");
42 #if 0
43 static char sccsid[] = "@(#)getNAME.c 8.1 (Berkeley) 6/30/93";
44 #else
45 __RCSID("$NetBSD: getNAME.c,v 1.15 1998/10/10 02:53:12 hubertf Exp $");
46 #endif
47 #endif /* not lint */
48
49 /*
50 * Get name sections from manual pages.
51 * -t for building toc
52 * -i for building intro entries
53 * -w for querying type of manual source
54 * -v verbose
55 * other apropos database
56 */
57 #include <err.h>
58 #include <ctype.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
63
64 static int tocrc;
65 static int intro;
66 static int typeflag;
67 static int verbose;
68
69 #define SLOP 10 /* strlen(" () - ") < 10 */
70
71 static char *linebuf = NULL;
72 static size_t maxlen = 0;
73
74
75 static void doname __P((char *));
76 static void dorefname __P((char *));
77 static void getfrom __P((char *));
78 static void oldman __P((char *, char *));
79 static void newman __P((char *, char *));
80 static void remcomma __P((char *, size_t *));
81 static void remquote __P((char *, size_t *));
82 static void fixxref __P((char *, size_t *));
83 static void split __P((char *, char *));
84 static void usage __P((void));
85
86 int main __P((int, char *[]));
87
88 int
89 main(argc, argv)
90 int argc;
91 char *argv[];
92 {
93 int ch;
94
95 while ((ch = getopt(argc, argv, "itvw")) != -1)
96 switch (ch) {
97 case 'i':
98 intro = 1;
99 break;
100 case 't':
101 tocrc = 1;
102 break;
103 case 'v':
104 verbose = 1;
105 break;
106 case 'w':
107 typeflag = 1;
108 break;
109 case '?':
110 default:
111 usage();
112 }
113 argc -= optind;
114 argv += optind;
115
116 if (!*argv)
117 usage();
118
119 for (; *argv; ++argv)
120 getfrom(*argv);
121 exit(0);
122 }
123
124 void
125 getfrom(pathname)
126 char *pathname;
127 {
128 char *name;
129 char *line;
130 size_t len;
131
132 if (freopen(pathname, "r", stdin) == 0) {
133 warn("Cannot open `%s'", pathname);
134 return;
135 }
136 if ((name = strrchr(pathname, '/')) != NULL)
137 name++;
138 else
139 name = pathname;
140 for (;;) {
141 if ((line = fgetln(stdin, &len)) == NULL) {
142 if (typeflag)
143 printf("%-60s\tUNKNOWN\n", pathname);
144 return;
145 }
146 if (line[0] != '.')
147 continue;
148 if ((line[1] == 'T' && line[2] == 'H') ||
149 (line[1] == 't' && line[2] == 'h'))
150 return oldman(pathname, name);
151 if (line[1] == 'D' && line[2] == 't')
152 return newman(pathname, name);
153 }
154 if (verbose)
155 warnx("missing .TH or .Dt section in `%s'", pathname);
156 }
157
158 static void
159 oldman(pathname, name)
160 char *pathname, *name;
161 {
162 char *line, *ext, *s;
163 size_t len, i, extlen;
164 size_t curlen = 0;
165
166 if (typeflag) {
167 printf("%-60s\tOLD\n", pathname);
168 return;
169 }
170 for (;;) {
171 if ((line = fgetln(stdin, &len)) == NULL) {
172 if (verbose)
173 warnx("missing .SH section in `%s'", pathname);
174 return;
175 }
176 if (line[0] != '.')
177 continue;
178 if (line[1] == 'S' && line[2] == 'H')
179 break;
180 if (line[1] == 's' && line[2] == 'h')
181 break;
182 }
183
184 for (s = &line[3]; s < &line[len] &&
185 (isspace((unsigned char) *s) || *s == '"' || *s == '\''); s++)
186 continue;
187 if (s == &line[len]) {
188 warnx("missing argument to .SH in `%s'", pathname);
189 return;
190 }
191 if (strncasecmp(s, "name", 4) != 0) {
192 warnx("first .SH section is not \"NAME\" in `%s'", pathname);
193 return;
194 }
195
196 if (tocrc)
197 doname(name);
198
199 for (i = 0;; i++) {
200 if ((line = fgetln(stdin, &len)) == NULL)
201 break;
202 if (line[0] == '.') {
203 if (line[1] == '\\' && line[2] == '"')
204 continue; /* [nt]roff comment */
205 if (line[1] == 'S' && line[2] == 'H')
206 break;
207 if (line[1] == 's' && line[2] == 'h')
208 break;
209 if (line[1] == 'P' && line[2] == 'P')
210 break;
211 }
212 if (line[len - 1] == '\n') {
213 line[len - 1] = '\0';
214 len--;
215 }
216 if ((ext = strrchr(name, '.')) != NULL) {
217 ext++;
218 extlen = strlen(ext);
219 }
220 else
221 extlen = 0;
222
223 if (maxlen + extlen < curlen + len + SLOP) {
224 maxlen = 2 * (curlen + len) + SLOP + extlen;
225 if ((linebuf = realloc(linebuf, maxlen)) == NULL)
226 err(1, "%s", "");
227 }
228 if (i != 0)
229 linebuf[curlen++] = ' ';
230 (void)memcpy(&linebuf[curlen], line, len);
231 curlen += len;
232 linebuf[curlen] = '\0';
233
234 if(!tocrc && !intro) {
235 /* change the \- into (N) - */
236 if ((s = strstr(linebuf, "\\-")) != NULL) {
237 (void)memmove(s + extlen + 3, s + 1,
238 curlen - (s + 1 - linebuf));
239 curlen--;
240 if (extlen) {
241 *s++ = '(';
242 while (*ext)
243 *s++ = *ext++;
244 *s++ = ')';
245 *s++ = ' ';
246 curlen += extlen + 3;
247 }
248 linebuf[curlen] = '\0';
249 }
250 }
251 }
252
253 if (intro)
254 split(linebuf, name);
255 else
256 printf("%s\n", linebuf);
257 return;
258 }
259
260 static void
261 newman(pathname, name)
262 char *pathname, *name;
263 {
264 char *line, *ext, *s;
265 size_t len, i, extlen;
266 size_t curlen = 0;
267
268 if (typeflag) {
269 printf("%-60s\tNEW\n", pathname);
270 return;
271 }
272 for (;;) {
273 if ((line = fgetln(stdin, &len)) == NULL) {
274 if (verbose)
275 warnx("missing .Sh section in `%s'", pathname);
276 return;
277 }
278 if (line[0] != '.')
279 continue;
280 if (line[1] == 'S' && line[2] == 'h')
281 break;
282 }
283
284 for (s = &line[3]; s < &line[len] && isspace((unsigned char) *s); s++)
285 continue;
286 if (s == &line[len]) {
287 warnx("missing argument to .Sh in `%s'", pathname);
288 return;
289 }
290 if (strncasecmp(s, "name", 4) != 0) {
291 warnx("first .Sh section is not \"NAME\" in `%s'", pathname);
292 return;
293 }
294
295 if (tocrc)
296 doname(name);
297
298 for (i = 0;; i++) {
299 if ((line = fgetln(stdin, &len)) == NULL)
300 break;
301
302 if (line[0] == '.') {
303 if (line[1] == '\\' && line[2] == '"')
304 continue; /* [nt]roff comment */
305 if (line[1] == 'S' && line[2] == 'h')
306 break;
307 }
308
309 if (line[len - 1] == '\n') {
310 line[len - 1] = '\0';
311 len--;
312 }
313
314 if ((ext = strrchr(name, '.')) != NULL) {
315 ext++;
316 extlen = strlen(ext);
317 }
318 else
319 extlen = 0;
320
321 if (maxlen + extlen < curlen + len + SLOP) {
322 maxlen = 2 * (curlen + len) + SLOP + extlen;
323 if ((linebuf = realloc(linebuf, maxlen)) == NULL)
324 err(1, "%s", "");
325 }
326
327 if (i != 0)
328 linebuf[curlen++] = ' ';
329
330 remcomma(line, &len);
331
332 if (line[0] != '.') {
333 (void)memcpy(&linebuf[curlen], line, len);
334 curlen += len;
335 }
336 else {
337 remquote(line, &len);
338 fixxref(line, &len);
339
340 /*
341 * Put section and dash between names and description.
342 */
343 if (line[1] == 'N' && line[2] == 'd') {
344 if(!tocrc && !intro) {
345 if (extlen) {
346 linebuf[curlen++] = '(';
347 while (*ext)
348 linebuf[curlen++] = *ext++;
349 linebuf[curlen++] = ')';
350 linebuf[curlen++] = ' ';
351 }
352 }
353 linebuf[curlen++] = '-';
354 linebuf[curlen++] = ' ';
355 }
356 /*
357 * Skip over macro names.
358 */
359 if (len <= 4)
360 continue;
361 (void)memcpy(&linebuf[curlen], &line[4], len - 4);
362 curlen += len - 4;
363 }
364 }
365 linebuf[curlen] = '\0';
366 if (intro)
367 split(linebuf, name);
368 else
369 printf("%s\n", linebuf);
370 }
371
372 /*
373 * convert " ," -> " "
374 */
375 static void
376 remcomma(line, len)
377 char *line;
378 size_t *len;
379 {
380 char *pline = line, *loc;
381 size_t plen = *len;
382
383 while ((loc = memchr(pline, ' ', plen)) != NULL) {
384 plen -= loc - pline + 1;
385 pline = loc;
386 if (loc[1] == ',') {
387 (void)memcpy(loc, &loc[1], plen);
388 (*len)--;
389 }
390 else
391 pline++;
392 }
393 }
394
395 /*
396 * Get rid of quotes in macros.
397 */
398 static
399 void remquote(line, len)
400 char *line;
401 size_t *len;
402 {
403 char *loc;
404 char *pline = &line[4];
405 size_t plen = *len - 4;
406
407 if (*len < 4)
408 return;
409
410 while ((loc = memchr(pline, '"', plen)) != NULL) {
411 plen -= loc - pline + 1;
412 pline = loc;
413 (void)memcpy(loc, &loc[1], plen);
414 (*len)--;
415 }
416 }
417
418 /*
419 * Handle cross references
420 */
421 static void
422 fixxref(line, len)
423 char *line;
424 size_t *len;
425 {
426 char *loc;
427 char *pline = &line[4];
428 size_t plen = *len - 4;
429
430 if (*len < 4)
431 return;
432
433 if (line[1] == 'X' && line[2] == 'r') {
434 if ((loc = memchr(pline, ' ', plen)) != NULL) {
435 *loc++ = '(';
436 loc++;
437 *loc++ = ')';
438 *len = loc - line;
439 }
440 }
441 }
442
443 static void
444 doname(name)
445 char *name;
446 {
447 char *dp = name, *ep;
448
449 again:
450 while (*dp && *dp != '.')
451 putchar(*dp++);
452 if (*dp)
453 for (ep = dp+1; *ep; ep++)
454 if (*ep == '.') {
455 putchar(*dp++);
456 goto again;
457 }
458 putchar('(');
459 if (*dp)
460 dp++;
461 while (*dp)
462 putchar (*dp++);
463 putchar(')');
464 putchar(' ');
465 }
466
467 static void
468 split(line, name)
469 char *line, *name;
470 {
471 char *cp, *dp;
472 char *sp, *sep;
473
474 cp = strchr(line, '-');
475 if (cp == 0)
476 return;
477 sp = cp + 1;
478 for (--cp; *cp == ' ' || *cp == '\t' || *cp == '\\'; cp--)
479 ;
480 *++cp = '\0';
481 while (*sp && (*sp == ' ' || *sp == '\t'))
482 sp++;
483 for (sep = "", dp = line; dp && *dp; dp = cp, sep = "\n") {
484 cp = strchr(dp, ',');
485 if (cp) {
486 char *tp;
487
488 for (tp = cp - 1; *tp == ' ' || *tp == '\t'; tp--)
489 ;
490 *++tp = '\0';
491 for (++cp; *cp == ' ' || *cp == '\t'; cp++)
492 ;
493 }
494 printf("%s%s\t", sep, dp);
495 dorefname(name);
496 printf("\t- %s", sp);
497 }
498 putchar('\n');
499 }
500
501 static void
502 dorefname(name)
503 char *name;
504 {
505 char *dp = name, *ep;
506
507 again:
508 while (*dp && *dp != '.')
509 putchar(*dp++);
510 if (*dp)
511 for (ep = dp+1; *ep; ep++)
512 if (*ep == '.') {
513 putchar(*dp++);
514 goto again;
515 }
516 putchar('.');
517 if (*dp)
518 dp++;
519 while (*dp)
520 putchar (*dp++);
521 }
522
523 static void
524 usage()
525 {
526 extern char *__progname;
527 (void)fprintf(stderr, "Usage: %s [-itw] file ...\n", __progname);
528 exit(1);
529 }
530