getNAME.c revision 1.23 1 /* $NetBSD: getNAME.c,v 1.23 2004/03/20 20:26:58 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\
35 The Regents of the University of California. All rights reserved.\n");
36 #if 0
37 static char sccsid[] = "@(#)getNAME.c 8.1 (Berkeley) 6/30/93";
38 #else
39 __RCSID("$NetBSD: getNAME.c,v 1.23 2004/03/20 20:26:58 christos Exp $");
40 #endif
41 #endif /* not lint */
42
43 /*
44 * Get name sections from manual pages.
45 * -t for building toc
46 * -i for building intro entries
47 * -w for querying type of manual source
48 * -v verbose
49 * other apropos database
50 */
51 #include <err.h>
52 #include <ctype.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57
58 static int tocrc;
59 static int intro;
60 static int typeflag;
61 static int verbose;
62
63 #define SLOP 10 /* strlen(" () - ") < 10 */
64
65 static char *linebuf = NULL;
66 static size_t maxlen = 0;
67
68
69 static void doname(char *);
70 static void dorefname(char *);
71 static void getfrom(char *);
72 static void oldman(char *, char *);
73 static void newman(char *, char *);
74 static void remcomma(char *, size_t *);
75 static void remquote(char *, size_t *);
76 static void fixxref(char *, size_t *);
77 static void split(char *, char *);
78 static void usage(void);
79
80 int main(int, char *[]);
81
82 /* The .SH NAMEs that are allowed. */
83 static const char *names[] = { "name", "namn", 0 };
84
85 int
86 main(int argc, char *argv[])
87 {
88 int ch;
89
90 while ((ch = getopt(argc, argv, "itvw")) != -1)
91 switch (ch) {
92 case 'i':
93 intro = 1;
94 break;
95 case 't':
96 tocrc = 1;
97 break;
98 case 'v':
99 verbose = 1;
100 break;
101 case 'w':
102 typeflag = 1;
103 break;
104 case '?':
105 default:
106 usage();
107 }
108 argc -= optind;
109 argv += optind;
110
111 if (!*argv)
112 usage();
113
114 for (; *argv; ++argv)
115 getfrom(*argv);
116 return 0;
117 }
118
119 static void
120 getfrom(char *pathname)
121 {
122 char *name;
123 char *line;
124 size_t len;
125
126 if (freopen(pathname, "r", stdin) == 0) {
127 warn("Cannot open `%s'", pathname);
128 return;
129 }
130 if ((name = strrchr(pathname, '/')) != NULL)
131 name++;
132 else
133 name = pathname;
134 for (;;) {
135 if ((line = fgetln(stdin, &len)) == NULL) {
136 if (typeflag)
137 (void)printf("%-60s\tUNKNOWN\n", pathname);
138 if (verbose)
139 warnx("missing .TH or .Dt section in `%s'",
140 pathname);
141 return;
142 }
143 if (len < 3)
144 continue;
145 if (line[0] != '.')
146 continue;
147 if ((line[1] == 'T' && line[2] == 'H') ||
148 (line[1] == 't' && line[2] == 'h')) {
149 oldman(pathname, name);
150 return;
151 }
152 if (line[1] == 'D' && line[2] == 't') {
153 newman(pathname, name);
154 return;
155 }
156 }
157 }
158
159 static void
160 oldman(char *pathname, char *name)
161 {
162 char *line, *ext, *s, *newlinebuf;
163 size_t len, i, extlen;
164 size_t curlen = 0;
165 size_t newmaxlen;
166
167 if (typeflag) {
168 (void)printf("%-60s\tOLD\n", pathname);
169 return;
170 }
171 for (;;) {
172 if ((line = fgetln(stdin, &len)) == NULL) {
173 if (verbose)
174 warnx("missing .SH section in `%s'", pathname);
175 return;
176 }
177 if (len < 4)
178 continue;
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 newmaxlen = 2 * (curlen + len) + SLOP + extlen;
231 if ((newlinebuf = realloc(linebuf, newmaxlen)) == NULL)
232 err(1, NULL);
233 linebuf = newlinebuf;
234 maxlen = newmaxlen;
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 (void)printf("%s\n", linebuf);
265 return;
266 }
267
268 static void
269 newman(char *pathname, char *name)
270 {
271 char *line, *ext, *s, *newlinebuf;
272 size_t len, i, extlen;
273 size_t curlen = 0;
274 size_t newmaxlen;
275
276 if (typeflag) {
277 (void)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 newmaxlen = 2 * (curlen + len) + SLOP + extlen;
334 if ((newlinebuf = realloc(linebuf, newmaxlen)) == NULL)
335 err(1, NULL);
336 linebuf = newlinebuf;
337 maxlen = newmaxlen;
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 (void)printf("%s\n", linebuf);
383 }
384
385 /*
386 * convert " ," -> " "
387 */
388 static void
389 remcomma(char *line, 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 void
410 remquote(char *line, 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(char *line, size_t *len)
432 {
433 char *loc;
434 char *pline = &line[4];
435 size_t plen = *len - 4;
436
437 if (*len < 4)
438 return;
439
440 if (line[1] == 'X' && line[2] == 'r') {
441 if ((loc = memchr(pline, ' ', plen)) != NULL) {
442 *loc++ = '(';
443 loc++;
444 *loc++ = ')';
445 *len = loc - line;
446 }
447 }
448 }
449
450 static void
451 doname(char *name)
452 {
453 char *dp = name, *ep;
454
455 again:
456 while (*dp && *dp != '.')
457 (void)putchar(*dp++);
458 if (*dp)
459 for (ep = dp+1; *ep; ep++)
460 if (*ep == '.') {
461 (void)putchar(*dp++);
462 goto again;
463 }
464 (void)putchar('(');
465 if (*dp)
466 dp++;
467 while (*dp)
468 (void)putchar(*dp++);
469 (void)putchar(')');
470 (void)putchar(' ');
471 }
472
473 static void
474 split(char *line, char *name)
475 {
476 char *cp, *dp;
477 char *sp;
478 const char *sep;
479
480 cp = strchr(line, '-');
481 if (cp == 0)
482 return;
483 sp = cp + 1;
484 for (--cp; *cp == ' ' || *cp == '\t' || *cp == '\\'; cp--)
485 ;
486 *++cp = '\0';
487 while (*sp && (*sp == ' ' || *sp == '\t'))
488 sp++;
489 for (sep = "", dp = line; dp && *dp; dp = cp, sep = "\n") {
490 cp = strchr(dp, ',');
491 if (cp) {
492 char *tp;
493
494 for (tp = cp - 1; *tp == ' ' || *tp == '\t'; tp--)
495 ;
496 *++tp = '\0';
497 for (++cp; *cp == ' ' || *cp == '\t'; cp++)
498 ;
499 }
500 (void)printf("%s%s\t", sep, dp);
501 dorefname(name);
502 (void)printf("\t- %s", sp);
503 }
504 (void)putchar('\n');
505 }
506
507 static void
508 dorefname(char *name)
509 {
510 char *dp = name, *ep;
511
512 again:
513 while (*dp && *dp != '.')
514 (void)putchar(*dp++);
515 if (*dp)
516 for (ep = dp+1; *ep; ep++)
517 if (*ep == '.') {
518 (void)putchar(*dp++);
519 goto again;
520 }
521 (void)putchar('.');
522 if (*dp)
523 dp++;
524 while (*dp)
525 (void)putchar(*dp++);
526 }
527
528 static void
529 usage(void)
530 {
531
532 (void)fprintf(stderr, "Usage: %s [-itw] file ...\n", getprogname());
533 exit(1);
534 }
535