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