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