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