Home | History | Annotate | Line # | Download | only in getNAME
getNAME.c revision 1.25
      1 /*	$NetBSD: getNAME.c,v 1.25 2006/09/12 21:56:43 hubertf 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.25 2006/09/12 21:56:43 hubertf 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 	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
    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
    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
    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
    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
    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
    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
    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
    541 usage(void)
    542 {
    543 
    544 	(void)fprintf(stderr, "Usage: %s [-itw] file ...\n", getprogname());
    545 	exit(1);
    546 }
    547