getNAME.c revision 1.17 1 /* $NetBSD: getNAME.c,v 1.17 1999/11/09 15:06:33 drochner 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.17 1999/11/09 15:06:33 drochner 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 /* The .SH NAMEs that are allowed. */
89 char *names[] = { "name", "namn", 0 };
90
91 int
92 main(argc, argv)
93 int argc;
94 char *argv[];
95 {
96 int ch;
97
98 while ((ch = getopt(argc, argv, "itvw")) != -1)
99 switch (ch) {
100 case 'i':
101 intro = 1;
102 break;
103 case 't':
104 tocrc = 1;
105 break;
106 case 'v':
107 verbose = 1;
108 break;
109 case 'w':
110 typeflag = 1;
111 break;
112 case '?':
113 default:
114 usage();
115 }
116 argc -= optind;
117 argv += optind;
118
119 if (!*argv)
120 usage();
121
122 for (; *argv; ++argv)
123 getfrom(*argv);
124 exit(0);
125 }
126
127 void
128 getfrom(pathname)
129 char *pathname;
130 {
131 char *name;
132 char *line;
133 size_t len;
134
135 if (freopen(pathname, "r", stdin) == 0) {
136 warn("Cannot open `%s'", pathname);
137 return;
138 }
139 if ((name = strrchr(pathname, '/')) != NULL)
140 name++;
141 else
142 name = pathname;
143 for (;;) {
144 if ((line = fgetln(stdin, &len)) == NULL) {
145 if (typeflag)
146 printf("%-60s\tUNKNOWN\n", pathname);
147 return;
148 }
149 if (line[0] != '.')
150 continue;
151 if ((line[1] == 'T' && line[2] == 'H') ||
152 (line[1] == 't' && line[2] == 'h'))
153 return oldman(pathname, name);
154 if (line[1] == 'D' && line[2] == 't')
155 return newman(pathname, name);
156 }
157 if (verbose)
158 warnx("missing .TH or .Dt section in `%s'", pathname);
159 }
160
161 static void
162 oldman(pathname, name)
163 char *pathname, *name;
164 {
165 char *line, *ext, *s;
166 size_t len, i, extlen;
167 size_t curlen = 0;
168
169 if (typeflag) {
170 printf("%-60s\tOLD\n", pathname);
171 return;
172 }
173 for (;;) {
174 if ((line = fgetln(stdin, &len)) == NULL) {
175 if (verbose)
176 warnx("missing .SH section in `%s'", pathname);
177 return;
178 }
179 if (line[0] != '.')
180 continue;
181 if (line[1] == 'S' && line[2] == 'H')
182 break;
183 if (line[1] == 's' && line[2] == 'h')
184 break;
185 }
186
187 for (s = &line[3]; s < &line[len] &&
188 (isspace((unsigned char) *s) || *s == '"' || *s == '\''); s++)
189 continue;
190 if (s == &line[len]) {
191 warnx("missing argument to .SH in `%s'", pathname);
192 return;
193 }
194 for (i = 0; names[i]; i++)
195 if (strncasecmp(s, names[i], strlen(names[i])) == 0)
196 break;
197 if (names[i] == NULL) {
198 warnx("first .SH section is not \"NAME\" in `%s'", pathname);
199 return;
200 }
201
202 if (tocrc)
203 doname(name);
204
205 for (i = 0;; i++) {
206 if ((line = fgetln(stdin, &len)) == NULL)
207 break;
208 if (line[0] == '.') {
209 if (line[1] == '\\' && line[2] == '"')
210 continue; /* [nt]roff comment */
211 if (line[1] == 'S' && line[2] == 'H')
212 break;
213 if (line[1] == 's' && line[2] == 'h')
214 break;
215 if (line[1] == 'P' && line[2] == 'P')
216 break;
217 }
218 if (line[len - 1] == '\n') {
219 line[len - 1] = '\0';
220 len--;
221 }
222 if ((ext = strrchr(name, '.')) != NULL) {
223 ext++;
224 extlen = strlen(ext);
225 }
226 else
227 extlen = 0;
228
229 if (maxlen + extlen < curlen + len + SLOP) {
230 maxlen = 2 * (curlen + len) + SLOP + extlen;
231 if ((linebuf = realloc(linebuf, maxlen)) == NULL)
232 err(1, NULL);
233 }
234 if (i != 0)
235 linebuf[curlen++] = ' ';
236 (void)memcpy(&linebuf[curlen], line, len);
237 curlen += len;
238 linebuf[curlen] = '\0';
239
240 if(!tocrc && !intro) {
241 /* change the \- into (N) - */
242 if ((s = strstr(linebuf, "\\-")) != NULL) {
243 (void)memmove(s + extlen + 3, s + 1,
244 curlen - (s + 1 - linebuf));
245 curlen--;
246 if (extlen) {
247 *s++ = '(';
248 while (*ext)
249 *s++ = *ext++;
250 *s++ = ')';
251 *s++ = ' ';
252 curlen += extlen + 3;
253 }
254 linebuf[curlen] = '\0';
255 }
256 }
257 }
258
259 if (intro)
260 split(linebuf, name);
261 else
262 printf("%s\n", linebuf);
263 return;
264 }
265
266 static void
267 newman(pathname, name)
268 char *pathname, *name;
269 {
270 char *line, *ext, *s;
271 size_t len, i, extlen;
272 size_t curlen = 0;
273
274 if (typeflag) {
275 printf("%-60s\tNEW\n", pathname);
276 return;
277 }
278 for (;;) {
279 if ((line = fgetln(stdin, &len)) == NULL) {
280 if (verbose)
281 warnx("missing .Sh section in `%s'", pathname);
282 return;
283 }
284 if (line[0] != '.')
285 continue;
286 if (line[1] == 'S' && line[2] == 'h')
287 break;
288 }
289
290 for (s = &line[3]; s < &line[len] && isspace((unsigned char) *s); s++)
291 continue;
292 if (s == &line[len]) {
293 warnx("missing argument to .Sh in `%s'", pathname);
294 return;
295 }
296 for (i = 0; names[i]; i++)
297 if (strncasecmp(s, names[i], strlen(names[i])) == 0)
298 break;
299 if (names[i] == NULL) {
300 warnx("first .SH section is not \"NAME\" in `%s'", pathname);
301 return;
302 }
303
304 if (tocrc)
305 doname(name);
306
307 for (i = 0;; i++) {
308 if ((line = fgetln(stdin, &len)) == NULL)
309 break;
310
311 if (line[0] == '.') {
312 if (line[1] == '\\' && line[2] == '"')
313 continue; /* [nt]roff comment */
314 if (line[1] == 'S' && line[2] == 'h')
315 break;
316 }
317
318 if (line[len - 1] == '\n') {
319 line[len - 1] = '\0';
320 len--;
321 }
322
323 if ((ext = strrchr(name, '.')) != NULL) {
324 ext++;
325 extlen = strlen(ext);
326 }
327 else
328 extlen = 0;
329
330 if (maxlen + extlen < curlen + len + SLOP) {
331 maxlen = 2 * (curlen + len) + SLOP + extlen;
332 if ((linebuf = realloc(linebuf, maxlen)) == NULL)
333 err(1, NULL);
334 }
335
336 if (i != 0)
337 linebuf[curlen++] = ' ';
338
339 remcomma(line, &len);
340
341 if (line[0] != '.') {
342 (void)memcpy(&linebuf[curlen], line, len);
343 curlen += len;
344 }
345 else {
346 remquote(line, &len);
347 fixxref(line, &len);
348
349 /*
350 * Put section and dash between names and description.
351 */
352 if (line[1] == 'N' && line[2] == 'd') {
353 if(!tocrc && !intro) {
354 if (extlen) {
355 linebuf[curlen++] = '(';
356 while (*ext)
357 linebuf[curlen++] = *ext++;
358 linebuf[curlen++] = ')';
359 linebuf[curlen++] = ' ';
360 }
361 }
362 linebuf[curlen++] = '-';
363 linebuf[curlen++] = ' ';
364 }
365 /*
366 * Skip over macro names.
367 */
368 if (len <= 4)
369 continue;
370 (void)memcpy(&linebuf[curlen], &line[4], len - 4);
371 curlen += len - 4;
372 }
373 }
374 linebuf[curlen] = '\0';
375 if (intro)
376 split(linebuf, name);
377 else
378 printf("%s\n", linebuf);
379 }
380
381 /*
382 * convert " ," -> " "
383 */
384 static void
385 remcomma(line, len)
386 char *line;
387 size_t *len;
388 {
389 char *pline = line, *loc;
390 size_t plen = *len;
391
392 while ((loc = memchr(pline, ' ', plen)) != NULL) {
393 plen -= loc - pline + 1;
394 pline = loc;
395 if (loc[1] == ',') {
396 (void)memcpy(loc, &loc[1], plen);
397 (*len)--;
398 }
399 else
400 pline++;
401 }
402 }
403
404 /*
405 * Get rid of quotes in macros.
406 */
407 static
408 void remquote(line, len)
409 char *line;
410 size_t *len;
411 {
412 char *loc;
413 char *pline = &line[4];
414 size_t plen = *len - 4;
415
416 if (*len < 4)
417 return;
418
419 while ((loc = memchr(pline, '"', plen)) != NULL) {
420 plen -= loc - pline + 1;
421 pline = loc;
422 (void)memcpy(loc, &loc[1], plen);
423 (*len)--;
424 }
425 }
426
427 /*
428 * Handle cross references
429 */
430 static void
431 fixxref(line, len)
432 char *line;
433 size_t *len;
434 {
435 char *loc;
436 char *pline = &line[4];
437 size_t plen = *len - 4;
438
439 if (*len < 4)
440 return;
441
442 if (line[1] == 'X' && line[2] == 'r') {
443 if ((loc = memchr(pline, ' ', plen)) != NULL) {
444 *loc++ = '(';
445 loc++;
446 *loc++ = ')';
447 *len = loc - line;
448 }
449 }
450 }
451
452 static void
453 doname(name)
454 char *name;
455 {
456 char *dp = name, *ep;
457
458 again:
459 while (*dp && *dp != '.')
460 putchar(*dp++);
461 if (*dp)
462 for (ep = dp+1; *ep; ep++)
463 if (*ep == '.') {
464 putchar(*dp++);
465 goto again;
466 }
467 putchar('(');
468 if (*dp)
469 dp++;
470 while (*dp)
471 putchar (*dp++);
472 putchar(')');
473 putchar(' ');
474 }
475
476 static void
477 split(line, name)
478 char *line, *name;
479 {
480 char *cp, *dp;
481 char *sp, *sep;
482
483 cp = strchr(line, '-');
484 if (cp == 0)
485 return;
486 sp = cp + 1;
487 for (--cp; *cp == ' ' || *cp == '\t' || *cp == '\\'; cp--)
488 ;
489 *++cp = '\0';
490 while (*sp && (*sp == ' ' || *sp == '\t'))
491 sp++;
492 for (sep = "", dp = line; dp && *dp; dp = cp, sep = "\n") {
493 cp = strchr(dp, ',');
494 if (cp) {
495 char *tp;
496
497 for (tp = cp - 1; *tp == ' ' || *tp == '\t'; tp--)
498 ;
499 *++tp = '\0';
500 for (++cp; *cp == ' ' || *cp == '\t'; cp++)
501 ;
502 }
503 printf("%s%s\t", sep, dp);
504 dorefname(name);
505 printf("\t- %s", sp);
506 }
507 putchar('\n');
508 }
509
510 static void
511 dorefname(name)
512 char *name;
513 {
514 char *dp = name, *ep;
515
516 again:
517 while (*dp && *dp != '.')
518 putchar(*dp++);
519 if (*dp)
520 for (ep = dp+1; *ep; ep++)
521 if (*ep == '.') {
522 putchar(*dp++);
523 goto again;
524 }
525 putchar('.');
526 if (*dp)
527 dp++;
528 while (*dp)
529 putchar (*dp++);
530 }
531
532 static void
533 usage()
534 {
535 extern char *__progname;
536 (void)fprintf(stderr, "Usage: %s [-itw] file ...\n", __progname);
537 exit(1);
538 }
539