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