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