getNAME.c revision 1.24 1 /* $NetBSD: getNAME.c,v 1.24 2004/03/20 20:30:48 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1997, Christos Zoulas. All rights reserved.
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. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 #ifndef lint
35 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\
36 The Regents of the University of California. All rights reserved.\n");
37 #if 0
38 static char sccsid[] = "@(#)getNAME.c 8.1 (Berkeley) 6/30/93";
39 #else
40 __RCSID("$NetBSD: getNAME.c,v 1.24 2004/03/20 20:30:48 christos Exp $");
41 #endif
42 #endif /* not lint */
43
44 /*
45 * Get name sections from manual pages.
46 * -t for building toc
47 * -i for building intro entries
48 * -w for querying type of manual source
49 * -v verbose
50 * other apropos database
51 */
52 #include <err.h>
53 #include <ctype.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58
59 static int tocrc;
60 static int intro;
61 static int typeflag;
62 static int verbose;
63
64 #define SLOP 10 /* strlen(" () - ") < 10 */
65
66 static char *linebuf = NULL;
67 static size_t maxlen = 0;
68
69
70 static void doname(char *);
71 static void dorefname(char *);
72 static void getfrom(char *);
73 static void oldman(char *, char *);
74 static void newman(char *, char *);
75 static void remcomma(char *, size_t *);
76 static void remquote(char *, size_t *);
77 static void fixxref(char *, size_t *);
78 static void split(char *, char *);
79 static void usage(void);
80
81 int main(int, char *[]);
82
83 /* The .SH NAMEs that are allowed. */
84 static const char *names[] = { "name", "namn", 0 };
85
86 int
87 main(int argc, char *argv[])
88 {
89 int ch;
90
91 while ((ch = getopt(argc, argv, "itvw")) != -1)
92 switch (ch) {
93 case 'i':
94 intro = 1;
95 break;
96 case 't':
97 tocrc = 1;
98 break;
99 case 'v':
100 verbose = 1;
101 break;
102 case 'w':
103 typeflag = 1;
104 break;
105 case '?':
106 default:
107 usage();
108 }
109 argc -= optind;
110 argv += optind;
111
112 if (!*argv)
113 usage();
114
115 for (; *argv; ++argv)
116 getfrom(*argv);
117 return 0;
118 }
119
120 static void
121 getfrom(char *pathname)
122 {
123 char *name;
124 char *line;
125 size_t len;
126
127 if (freopen(pathname, "r", stdin) == 0) {
128 warn("Cannot open `%s'", pathname);
129 return;
130 }
131 if ((name = strrchr(pathname, '/')) != NULL)
132 name++;
133 else
134 name = pathname;
135 for (;;) {
136 if ((line = fgetln(stdin, &len)) == NULL) {
137 if (typeflag)
138 (void)printf("%-60s\tUNKNOWN\n", pathname);
139 if (verbose)
140 warnx("missing .TH or .Dt section in `%s'",
141 pathname);
142 return;
143 }
144 if (len < 3)
145 continue;
146 if (line[0] != '.')
147 continue;
148 if ((line[1] == 'T' && line[2] == 'H') ||
149 (line[1] == 't' && line[2] == 'h')) {
150 oldman(pathname, name);
151 return;
152 }
153 if (line[1] == 'D' && line[2] == 't') {
154 newman(pathname, name);
155 return;
156 }
157 }
158 }
159
160 static void
161 oldman(char *pathname, char *name)
162 {
163 char *line, *ext, *s, *newlinebuf;
164 size_t len, i, extlen;
165 size_t curlen = 0;
166 size_t newmaxlen;
167
168 if (typeflag) {
169 (void)printf("%-60s\tOLD\n", pathname);
170 return;
171 }
172 for (;;) {
173 if ((line = fgetln(stdin, &len)) == NULL) {
174 if (verbose)
175 warnx("missing .SH section in `%s'", pathname);
176 return;
177 }
178 if (len < 4)
179 continue;
180 if (line[0] != '.')
181 continue;
182 if (line[1] == 'S' && line[2] == 'H')
183 break;
184 if (line[1] == 's' && line[2] == 'h')
185 break;
186 }
187
188 for (s = &line[3]; s < &line[len] &&
189 (isspace((unsigned char) *s) || *s == '"' || *s == '\''); s++)
190 continue;
191 if (s == &line[len]) {
192 warnx("missing argument to .SH in `%s'", pathname);
193 return;
194 }
195 for (i = 0; names[i]; i++)
196 if (strncasecmp(s, names[i], strlen(names[i])) == 0)
197 break;
198 if (names[i] == NULL) {
199 warnx("first .SH section is not \"NAME\" in `%s'", pathname);
200 return;
201 }
202
203 if (tocrc)
204 doname(name);
205
206 for (i = 0;; i++) {
207 if ((line = fgetln(stdin, &len)) == NULL)
208 break;
209 if (line[0] == '.') {
210 if (line[1] == '\\' && line[2] == '"')
211 continue; /* [nt]roff comment */
212 if (line[1] == 'S' && line[2] == 'H')
213 break;
214 if (line[1] == 's' && line[2] == 'h')
215 break;
216 if (line[1] == 'P' && line[2] == 'P')
217 break;
218 }
219 if (line[len - 1] == '\n') {
220 line[len - 1] = '\0';
221 len--;
222 }
223 if ((ext = strrchr(name, '.')) != NULL) {
224 ext++;
225 extlen = strlen(ext);
226 }
227 else
228 extlen = 0;
229
230 if (maxlen + extlen < curlen + len + SLOP) {
231 newmaxlen = 2 * (curlen + len) + SLOP + extlen;
232 if ((newlinebuf = realloc(linebuf, newmaxlen)) == NULL)
233 err(1, NULL);
234 linebuf = newlinebuf;
235 maxlen = newmaxlen;
236 }
237 if (i != 0)
238 linebuf[curlen++] = ' ';
239 (void)memcpy(&linebuf[curlen], line, len);
240 curlen += len;
241 linebuf[curlen] = '\0';
242
243 if(!tocrc && !intro) {
244 /* change the \- into (N) - */
245 if ((s = strstr(linebuf, "\\-")) != NULL) {
246 (void)memmove(s + extlen + 3, s + 1,
247 curlen - (s + 1 - linebuf));
248 curlen--;
249 if (extlen) {
250 *s++ = '(';
251 while (*ext)
252 *s++ = *ext++;
253 *s++ = ')';
254 *s++ = ' ';
255 curlen += extlen + 3;
256 }
257 linebuf[curlen] = '\0';
258 }
259 }
260 }
261
262 if (intro)
263 split(linebuf, name);
264 else
265 (void)printf("%s\n", linebuf);
266 return;
267 }
268
269 static void
270 newman(char *pathname, char *name)
271 {
272 char *line, *ext, *s, *newlinebuf;
273 size_t len, i, extlen;
274 size_t curlen = 0;
275 size_t newmaxlen;
276
277 if (typeflag) {
278 (void)printf("%-60s\tNEW\n", pathname);
279 return;
280 }
281 for (;;) {
282 if ((line = fgetln(stdin, &len)) == NULL) {
283 if (verbose)
284 warnx("missing .Sh section in `%s'", pathname);
285 return;
286 }
287 if (line[0] != '.')
288 continue;
289 if (line[1] == 'S' && line[2] == 'h')
290 break;
291 }
292
293 for (s = &line[3]; s < &line[len] && isspace((unsigned char) *s); s++)
294 continue;
295 if (s == &line[len]) {
296 warnx("missing argument to .Sh in `%s'", pathname);
297 return;
298 }
299 for (i = 0; names[i]; i++)
300 if (strncasecmp(s, names[i], strlen(names[i])) == 0)
301 break;
302 if (names[i] == NULL) {
303 warnx("first .SH section is not \"NAME\" in `%s'", pathname);
304 return;
305 }
306
307 if (tocrc)
308 doname(name);
309
310 for (i = 0;; i++) {
311 if ((line = fgetln(stdin, &len)) == NULL)
312 break;
313
314 if (line[0] == '.') {
315 if (line[1] == '\\' && line[2] == '"')
316 continue; /* [nt]roff comment */
317 if (line[1] == 'S' && line[2] == 'h')
318 break;
319 }
320
321 if (line[len - 1] == '\n') {
322 line[len - 1] = '\0';
323 len--;
324 }
325
326 if ((ext = strrchr(name, '.')) != NULL) {
327 ext++;
328 extlen = strlen(ext);
329 }
330 else
331 extlen = 0;
332
333 if (maxlen + extlen < curlen + len + SLOP) {
334 newmaxlen = 2 * (curlen + len) + SLOP + extlen;
335 if ((newlinebuf = realloc(linebuf, newmaxlen)) == NULL)
336 err(1, NULL);
337 linebuf = newlinebuf;
338 maxlen = newmaxlen;
339 }
340
341 if (i != 0)
342 linebuf[curlen++] = ' ';
343
344 remcomma(line, &len);
345
346 if (line[0] != '.') {
347 (void)memcpy(&linebuf[curlen], line, len);
348 curlen += len;
349 }
350 else {
351 remquote(line, &len);
352 fixxref(line, &len);
353
354 /*
355 * Put section and dash between names and description.
356 */
357 if (line[1] == 'N' && line[2] == 'd') {
358 if(!tocrc && !intro) {
359 if (extlen) {
360 linebuf[curlen++] = '(';
361 while (*ext)
362 linebuf[curlen++] = *ext++;
363 linebuf[curlen++] = ')';
364 linebuf[curlen++] = ' ';
365 }
366 }
367 linebuf[curlen++] = '-';
368 linebuf[curlen++] = ' ';
369 }
370 /*
371 * Skip over macro names.
372 */
373 if (len <= 4)
374 continue;
375 (void)memcpy(&linebuf[curlen], &line[4], len - 4);
376 curlen += len - 4;
377 }
378 }
379 linebuf[curlen] = '\0';
380 if (intro)
381 split(linebuf, name);
382 else
383 (void)printf("%s\n", linebuf);
384 }
385
386 /*
387 * convert " ," -> " "
388 */
389 static void
390 remcomma(char *line, size_t *len)
391 {
392 char *pline = line, *loc;
393 size_t plen = *len;
394
395 while ((loc = memchr(pline, ' ', plen)) != NULL) {
396 plen -= loc - pline + 1;
397 pline = loc;
398 if (loc[1] == ',') {
399 (void)memcpy(loc, &loc[1], plen);
400 (*len)--;
401 }
402 else
403 pline++;
404 }
405 }
406
407 /*
408 * Get rid of quotes in macros.
409 */
410 static void
411 remquote(char *line, size_t *len)
412 {
413 char *loc;
414 char *pline = &line[4];
415 size_t plen = *len - 4;
416
417 if (*len < 4)
418 return;
419
420 while ((loc = memchr(pline, '"', plen)) != NULL) {
421 plen -= loc - pline + 1;
422 pline = loc;
423 (void)memcpy(loc, &loc[1], plen);
424 (*len)--;
425 }
426 }
427
428 /*
429 * Handle cross references
430 */
431 static void
432 fixxref(char *line, size_t *len)
433 {
434 char *loc;
435 char *pline = &line[4];
436 size_t plen = *len - 4;
437
438 if (*len < 4)
439 return;
440
441 if (line[1] == 'X' && line[2] == 'r') {
442 if ((loc = memchr(pline, ' ', plen)) != NULL) {
443 *loc++ = '(';
444 loc++;
445 *loc++ = ')';
446 *len = loc - line;
447 }
448 }
449 }
450
451 static void
452 doname(char *name)
453 {
454 char *dp = name, *ep;
455
456 again:
457 while (*dp && *dp != '.')
458 (void)putchar(*dp++);
459 if (*dp)
460 for (ep = dp+1; *ep; ep++)
461 if (*ep == '.') {
462 (void)putchar(*dp++);
463 goto again;
464 }
465 (void)putchar('(');
466 if (*dp)
467 dp++;
468 while (*dp)
469 (void)putchar(*dp++);
470 (void)putchar(')');
471 (void)putchar(' ');
472 }
473
474 static void
475 split(char *line, char *name)
476 {
477 char *cp, *dp;
478 char *sp;
479 const char *sep;
480
481 cp = strchr(line, '-');
482 if (cp == 0)
483 return;
484 sp = cp + 1;
485 for (--cp; *cp == ' ' || *cp == '\t' || *cp == '\\'; cp--)
486 ;
487 *++cp = '\0';
488 while (*sp && (*sp == ' ' || *sp == '\t'))
489 sp++;
490 for (sep = "", dp = line; dp && *dp; dp = cp, sep = "\n") {
491 cp = strchr(dp, ',');
492 if (cp) {
493 char *tp;
494
495 for (tp = cp - 1; *tp == ' ' || *tp == '\t'; tp--)
496 ;
497 *++tp = '\0';
498 for (++cp; *cp == ' ' || *cp == '\t'; cp++)
499 ;
500 }
501 (void)printf("%s%s\t", sep, dp);
502 dorefname(name);
503 (void)printf("\t- %s", sp);
504 }
505 (void)putchar('\n');
506 }
507
508 static void
509 dorefname(char *name)
510 {
511 char *dp = name, *ep;
512
513 again:
514 while (*dp && *dp != '.')
515 (void)putchar(*dp++);
516 if (*dp)
517 for (ep = dp+1; *ep; ep++)
518 if (*ep == '.') {
519 (void)putchar(*dp++);
520 goto again;
521 }
522 (void)putchar('.');
523 if (*dp)
524 dp++;
525 while (*dp)
526 (void)putchar(*dp++);
527 }
528
529 static void
530 usage(void)
531 {
532
533 (void)fprintf(stderr, "Usage: %s [-itw] file ...\n", getprogname());
534 exit(1);
535 }
536