1 /* $NetBSD: getNAME.c,v 1.26 2008/07/20 01:09:07 lukem 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\ 36 The Regents of the University of California. All rights reserved."); 37 #if 0 38 static char sccsid[] = "@(#)getNAME.c 8.1 (Berkeley) 6/30/93"; 39 #else 40 __RCSID("$NetBSD: getNAME.c,v 1.26 2008/07/20 01:09:07 lukem 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