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