getNAME.c revision 1.22 1 /* $NetBSD: getNAME.c,v 1.22 2003/09/19 05:41:33 itojun 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.22 2003/09/19 05:41:33 itojun 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, *newlinebuf;
195 size_t len, i, extlen;
196 size_t curlen = 0;
197 size_t newmaxlen;
198
199 if (typeflag) {
200 printf("%-60s\tOLD\n", pathname);
201 return;
202 }
203 for (;;) {
204 if ((line = fgetln(stdin, &len)) == NULL) {
205 if (verbose)
206 warnx("missing .SH section in `%s'", pathname);
207 return;
208 }
209 if (len < 4)
210 continue;
211 if (line[0] != '.')
212 continue;
213 if (line[1] == 'S' && line[2] == 'H')
214 break;
215 if (line[1] == 's' && line[2] == 'h')
216 break;
217 }
218
219 for (s = &line[3]; s < &line[len] &&
220 (isspace((unsigned char) *s) || *s == '"' || *s == '\''); s++)
221 continue;
222 if (s == &line[len]) {
223 warnx("missing argument to .SH in `%s'", pathname);
224 return;
225 }
226 for (i = 0; names[i]; i++)
227 if (strncasecmp(s, names[i], strlen(names[i])) == 0)
228 break;
229 if (names[i] == NULL) {
230 warnx("first .SH section is not \"NAME\" in `%s'", pathname);
231 return;
232 }
233
234 if (tocrc)
235 doname(name);
236
237 for (i = 0;; i++) {
238 if ((line = fgetln(stdin, &len)) == NULL)
239 break;
240 if (line[0] == '.') {
241 if (line[1] == '\\' && line[2] == '"')
242 continue; /* [nt]roff comment */
243 if (line[1] == 'S' && line[2] == 'H')
244 break;
245 if (line[1] == 's' && line[2] == 'h')
246 break;
247 if (line[1] == 'P' && line[2] == 'P')
248 break;
249 }
250 if (line[len - 1] == '\n') {
251 line[len - 1] = '\0';
252 len--;
253 }
254 if ((ext = strrchr(name, '.')) != NULL) {
255 ext++;
256 extlen = strlen(ext);
257 }
258 else
259 extlen = 0;
260
261 if (maxlen + extlen < curlen + len + SLOP) {
262 newmaxlen = 2 * (curlen + len) + SLOP + extlen;
263 if ((newlinebuf = realloc(linebuf, newmaxlen)) == NULL)
264 err(1, NULL);
265 linebuf = newlinebuf;
266 maxlen = newmaxlen;
267 }
268 if (i != 0)
269 linebuf[curlen++] = ' ';
270 (void)memcpy(&linebuf[curlen], line, len);
271 curlen += len;
272 linebuf[curlen] = '\0';
273
274 if(!tocrc && !intro) {
275 /* change the \- into (N) - */
276 if ((s = strstr(linebuf, "\\-")) != NULL) {
277 (void)memmove(s + extlen + 3, s + 1,
278 curlen - (s + 1 - linebuf));
279 curlen--;
280 if (extlen) {
281 *s++ = '(';
282 while (*ext)
283 *s++ = *ext++;
284 *s++ = ')';
285 *s++ = ' ';
286 curlen += extlen + 3;
287 }
288 linebuf[curlen] = '\0';
289 }
290 }
291 }
292
293 if (intro)
294 split(linebuf, name);
295 else
296 printf("%s\n", linebuf);
297 return;
298 }
299
300 static void
301 newman(pathname, name)
302 char *pathname, *name;
303 {
304 char *line, *ext, *s, *newlinebuf;
305 size_t len, i, extlen;
306 size_t curlen = 0;
307 size_t newmaxlen;
308
309 if (typeflag) {
310 printf("%-60s\tNEW\n", pathname);
311 return;
312 }
313 for (;;) {
314 if ((line = fgetln(stdin, &len)) == NULL) {
315 if (verbose)
316 warnx("missing .Sh section in `%s'", pathname);
317 return;
318 }
319 if (line[0] != '.')
320 continue;
321 if (line[1] == 'S' && line[2] == 'h')
322 break;
323 }
324
325 for (s = &line[3]; s < &line[len] && isspace((unsigned char) *s); s++)
326 continue;
327 if (s == &line[len]) {
328 warnx("missing argument to .Sh in `%s'", pathname);
329 return;
330 }
331 for (i = 0; names[i]; i++)
332 if (strncasecmp(s, names[i], strlen(names[i])) == 0)
333 break;
334 if (names[i] == NULL) {
335 warnx("first .SH section is not \"NAME\" in `%s'", pathname);
336 return;
337 }
338
339 if (tocrc)
340 doname(name);
341
342 for (i = 0;; i++) {
343 if ((line = fgetln(stdin, &len)) == NULL)
344 break;
345
346 if (line[0] == '.') {
347 if (line[1] == '\\' && line[2] == '"')
348 continue; /* [nt]roff comment */
349 if (line[1] == 'S' && line[2] == 'h')
350 break;
351 }
352
353 if (line[len - 1] == '\n') {
354 line[len - 1] = '\0';
355 len--;
356 }
357
358 if ((ext = strrchr(name, '.')) != NULL) {
359 ext++;
360 extlen = strlen(ext);
361 }
362 else
363 extlen = 0;
364
365 if (maxlen + extlen < curlen + len + SLOP) {
366 newmaxlen = 2 * (curlen + len) + SLOP + extlen;
367 if ((newlinebuf = realloc(linebuf, newmaxlen)) == NULL)
368 err(1, NULL);
369 linebuf = newlinebuf;
370 maxlen = newmaxlen;
371 }
372
373 if (i != 0)
374 linebuf[curlen++] = ' ';
375
376 remcomma(line, &len);
377
378 if (line[0] != '.') {
379 (void)memcpy(&linebuf[curlen], line, len);
380 curlen += len;
381 }
382 else {
383 remquote(line, &len);
384 fixxref(line, &len);
385
386 /*
387 * Put section and dash between names and description.
388 */
389 if (line[1] == 'N' && line[2] == 'd') {
390 if(!tocrc && !intro) {
391 if (extlen) {
392 linebuf[curlen++] = '(';
393 while (*ext)
394 linebuf[curlen++] = *ext++;
395 linebuf[curlen++] = ')';
396 linebuf[curlen++] = ' ';
397 }
398 }
399 linebuf[curlen++] = '-';
400 linebuf[curlen++] = ' ';
401 }
402 /*
403 * Skip over macro names.
404 */
405 if (len <= 4)
406 continue;
407 (void)memcpy(&linebuf[curlen], &line[4], len - 4);
408 curlen += len - 4;
409 }
410 }
411 linebuf[curlen] = '\0';
412 if (intro)
413 split(linebuf, name);
414 else
415 printf("%s\n", linebuf);
416 }
417
418 /*
419 * convert " ," -> " "
420 */
421 static void
422 remcomma(line, len)
423 char *line;
424 size_t *len;
425 {
426 char *pline = line, *loc;
427 size_t plen = *len;
428
429 while ((loc = memchr(pline, ' ', plen)) != NULL) {
430 plen -= loc - pline + 1;
431 pline = loc;
432 if (loc[1] == ',') {
433 (void)memcpy(loc, &loc[1], plen);
434 (*len)--;
435 }
436 else
437 pline++;
438 }
439 }
440
441 /*
442 * Get rid of quotes in macros.
443 */
444 static
445 void remquote(line, len)
446 char *line;
447 size_t *len;
448 {
449 char *loc;
450 char *pline = &line[4];
451 size_t plen = *len - 4;
452
453 if (*len < 4)
454 return;
455
456 while ((loc = memchr(pline, '"', plen)) != NULL) {
457 plen -= loc - pline + 1;
458 pline = loc;
459 (void)memcpy(loc, &loc[1], plen);
460 (*len)--;
461 }
462 }
463
464 /*
465 * Handle cross references
466 */
467 static void
468 fixxref(line, len)
469 char *line;
470 size_t *len;
471 {
472 char *loc;
473 char *pline = &line[4];
474 size_t plen = *len - 4;
475
476 if (*len < 4)
477 return;
478
479 if (line[1] == 'X' && line[2] == 'r') {
480 if ((loc = memchr(pline, ' ', plen)) != NULL) {
481 *loc++ = '(';
482 loc++;
483 *loc++ = ')';
484 *len = loc - line;
485 }
486 }
487 }
488
489 static void
490 doname(name)
491 char *name;
492 {
493 char *dp = name, *ep;
494
495 again:
496 while (*dp && *dp != '.')
497 putchar(*dp++);
498 if (*dp)
499 for (ep = dp+1; *ep; ep++)
500 if (*ep == '.') {
501 putchar(*dp++);
502 goto again;
503 }
504 putchar('(');
505 if (*dp)
506 dp++;
507 while (*dp)
508 putchar (*dp++);
509 putchar(')');
510 putchar(' ');
511 }
512
513 static void
514 split(line, name)
515 char *line, *name;
516 {
517 char *cp, *dp;
518 char *sp, *sep;
519
520 cp = strchr(line, '-');
521 if (cp == 0)
522 return;
523 sp = cp + 1;
524 for (--cp; *cp == ' ' || *cp == '\t' || *cp == '\\'; cp--)
525 ;
526 *++cp = '\0';
527 while (*sp && (*sp == ' ' || *sp == '\t'))
528 sp++;
529 for (sep = "", dp = line; dp && *dp; dp = cp, sep = "\n") {
530 cp = strchr(dp, ',');
531 if (cp) {
532 char *tp;
533
534 for (tp = cp - 1; *tp == ' ' || *tp == '\t'; tp--)
535 ;
536 *++tp = '\0';
537 for (++cp; *cp == ' ' || *cp == '\t'; cp++)
538 ;
539 }
540 printf("%s%s\t", sep, dp);
541 dorefname(name);
542 printf("\t- %s", sp);
543 }
544 putchar('\n');
545 }
546
547 static void
548 dorefname(name)
549 char *name;
550 {
551 char *dp = name, *ep;
552
553 again:
554 while (*dp && *dp != '.')
555 putchar(*dp++);
556 if (*dp)
557 for (ep = dp+1; *ep; ep++)
558 if (*ep == '.') {
559 putchar(*dp++);
560 goto again;
561 }
562 putchar('.');
563 if (*dp)
564 dp++;
565 while (*dp)
566 putchar (*dp++);
567 }
568
569 static void
570 usage()
571 {
572
573 (void)fprintf(stderr, "Usage: %s [-itw] file ...\n", getprogname());
574 exit(1);
575 }
576