getNAME.c revision 1.14 1 /* $NetBSD: getNAME.c,v 1.14 1998/05/21 23:21:48 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.14 1998/05/21 23:21:48 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 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 /* change the \- into (N) - */
235 if ((s = strstr(linebuf, "\\-")) != NULL) {
236 (void)memmove(s + extlen + 3, s + 1,
237 curlen - (s + 1 - linebuf));
238 curlen--;
239 if (extlen) {
240 *s++ = '(';
241 while (*ext)
242 *s++ = *ext++;
243 *s++ = ')';
244 *s++ = ' ';
245 curlen += extlen + 3;
246 }
247 linebuf[curlen] = '\0';
248 }
249 }
250
251 if (intro)
252 split(linebuf, name);
253 else
254 printf("%s\n", linebuf);
255 return;
256 }
257
258 static void
259 newman(pathname, name)
260 char *pathname, *name;
261 {
262 char *line, *ext, *s;
263 size_t len, i, extlen;
264 size_t curlen = 0;
265
266 if (typeflag) {
267 printf("%-60s\tNEW\n", pathname);
268 return;
269 }
270 for (;;) {
271 if ((line = fgetln(stdin, &len)) == NULL) {
272 if (verbose)
273 warnx("missing .Sh section in `%s'", pathname);
274 return;
275 }
276 if (line[0] != '.')
277 continue;
278 if (line[1] == 'S' && line[2] == 'h')
279 break;
280 }
281
282 for (s = &line[3]; s < &line[len] && isspace((unsigned char) *s); s++)
283 continue;
284 if (s == &line[len]) {
285 warnx("missing argument to .Sh in `%s'", pathname);
286 return;
287 }
288 if (strncasecmp(s, "name", 4) != 0) {
289 warnx("first .Sh section is not \"NAME\" in `%s'", pathname);
290 return;
291 }
292
293 if (tocrc)
294 doname(name);
295
296 for (i = 0;; i++) {
297 if ((line = fgetln(stdin, &len)) == NULL)
298 break;
299
300 if (line[0] == '.') {
301 if (line[1] == '\\' && line[2] == '"')
302 continue; /* [nt]roff comment */
303 if (line[1] == 'S' && line[2] == 'h')
304 break;
305 }
306
307 if (line[len - 1] == '\n') {
308 line[len - 1] = '\0';
309 len--;
310 }
311
312 if ((ext = strrchr(name, '.')) != NULL) {
313 ext++;
314 extlen = strlen(ext);
315 }
316 else
317 extlen = 0;
318
319 if (maxlen + extlen < curlen + len + SLOP) {
320 maxlen = 2 * (curlen + len) + SLOP + extlen;
321 if ((linebuf = realloc(linebuf, maxlen)) == NULL)
322 err(1, "%s", "");
323 }
324
325 if (i != 0)
326 linebuf[curlen++] = ' ';
327
328 remcomma(line, &len);
329
330 if (line[0] != '.') {
331 (void)memcpy(&linebuf[curlen], line, len);
332 curlen += len;
333 }
334 else {
335 remquote(line, &len);
336 fixxref(line, &len);
337
338 /*
339 * Put section and dash between names and description.
340 */
341 if (line[1] == 'N' && line[2] == 'd') {
342 if (extlen) {
343 linebuf[curlen++] = '(';
344 while (*ext)
345 linebuf[curlen++] = *ext++;
346 linebuf[curlen++] = ')';
347 linebuf[curlen++] = ' ';
348 }
349 linebuf[curlen++] = '-';
350 linebuf[curlen++] = ' ';
351 }
352 /*
353 * Skip over macro names.
354 */
355 if (len <= 4)
356 continue;
357 (void)memcpy(&linebuf[curlen], &line[4], len - 4);
358 curlen += len - 4;
359 }
360 }
361 linebuf[curlen] = '\0';
362 if (intro)
363 split(linebuf, name);
364 else
365 printf("%s\n", linebuf);
366 }
367
368 /*
369 * convert " ," -> " "
370 */
371 static void
372 remcomma(line, len)
373 char *line;
374 size_t *len;
375 {
376 char *pline = line, *loc;
377 size_t plen = *len;
378
379 while ((loc = memchr(pline, ' ', plen)) != NULL) {
380 plen -= loc - pline + 1;
381 pline = loc;
382 if (loc[1] == ',') {
383 (void)memcpy(loc, &loc[1], plen);
384 (*len)--;
385 }
386 else
387 pline++;
388 }
389 }
390
391 /*
392 * Get rid of quotes in macros.
393 */
394 static
395 void remquote(line, len)
396 char *line;
397 size_t *len;
398 {
399 char *loc;
400 char *pline = &line[4];
401 size_t plen = *len - 4;
402
403 if (*len < 4)
404 return;
405
406 while ((loc = memchr(pline, '"', plen)) != NULL) {
407 plen -= loc - pline + 1;
408 pline = loc;
409 (void)memcpy(loc, &loc[1], plen);
410 (*len)--;
411 }
412 }
413
414 /*
415 * Handle cross references
416 */
417 static void
418 fixxref(line, len)
419 char *line;
420 size_t *len;
421 {
422 char *loc;
423 char *pline = &line[4];
424 size_t plen = *len - 4;
425
426 if (*len < 4)
427 return;
428
429 if (line[1] == 'X' && line[2] == 'r') {
430 if ((loc = memchr(pline, ' ', plen)) != NULL) {
431 *loc++ = '(';
432 loc++;
433 *loc++ = ')';
434 *len = loc - line;
435 }
436 }
437 }
438
439 static void
440 doname(name)
441 char *name;
442 {
443 char *dp = name, *ep;
444
445 again:
446 while (*dp && *dp != '.')
447 putchar(*dp++);
448 if (*dp)
449 for (ep = dp+1; *ep; ep++)
450 if (*ep == '.') {
451 putchar(*dp++);
452 goto again;
453 }
454 putchar('(');
455 if (*dp)
456 dp++;
457 while (*dp)
458 putchar (*dp++);
459 putchar(')');
460 putchar(' ');
461 }
462
463 static void
464 split(line, name)
465 char *line, *name;
466 {
467 char *cp, *dp;
468 char *sp, *sep;
469
470 cp = strchr(line, '-');
471 if (cp == 0)
472 return;
473 sp = cp + 1;
474 for (--cp; *cp == ' ' || *cp == '\t' || *cp == '\\'; cp--)
475 ;
476 *++cp = '\0';
477 while (*sp && (*sp == ' ' || *sp == '\t'))
478 sp++;
479 for (sep = "", dp = line; dp && *dp; dp = cp, sep = "\n") {
480 cp = strchr(dp, ',');
481 if (cp) {
482 char *tp;
483
484 for (tp = cp - 1; *tp == ' ' || *tp == '\t'; tp--)
485 ;
486 *++tp = '\0';
487 for (++cp; *cp == ' ' || *cp == '\t'; cp++)
488 ;
489 }
490 printf("%s%s\t", sep, dp);
491 dorefname(name);
492 printf("\t%s", sp);
493 }
494 }
495
496 static void
497 dorefname(name)
498 char *name;
499 {
500 char *dp = name, *ep;
501
502 again:
503 while (*dp && *dp != '.')
504 putchar(*dp++);
505 if (*dp)
506 for (ep = dp+1; *ep; ep++)
507 if (*ep == '.') {
508 putchar(*dp++);
509 goto again;
510 }
511 putchar('.');
512 if (*dp)
513 dp++;
514 while (*dp)
515 putchar (*dp++);
516 }
517
518 static void
519 usage()
520 {
521 extern char *__progname;
522 (void)fprintf(stderr, "Usage: %s [-itw] file ...\n", __progname);
523 exit(1);
524 }
525