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