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