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