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