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