Annotation of mandoc/makewhatis.c, Revision 1.1
1.1 ! kristaps 1: /* $Id: mandoc-db.c,v 1.21 2011/05/12 23:44:51 kristaps Exp $ */
! 2: /*
! 3: * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
! 8: *
! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 16: */
! 17: #ifdef HAVE_CONFIG_H
! 18: #include "config.h"
! 19: #endif
! 20:
! 21: #include <sys/param.h>
! 22:
! 23: #include <assert.h>
! 24: #ifdef __linux__
! 25: # include <db_185.h>
! 26: #else
! 27: # include <db.h>
! 28: #endif
! 29: #include <fcntl.h>
! 30: #include <getopt.h>
! 31: #include <stdio.h>
! 32: #include <stdint.h>
! 33: #include <stdlib.h>
! 34: #include <string.h>
! 35:
! 36: #include "man.h"
! 37: #include "mdoc.h"
! 38: #include "mandoc.h"
! 39:
! 40: #define MANDOC_DB "mandoc.db"
! 41: #define MANDOC_IDX "mandoc.index"
! 42: #define MANDOC_BUFSZ BUFSIZ
! 43: #define MANDOC_FLAGS O_CREAT|O_TRUNC|O_RDWR
! 44:
! 45: enum type {
! 46: MANDOC_NONE = 0,
! 47: MANDOC_NAME,
! 48: MANDOC_FUNCTION,
! 49: MANDOC_UTILITY,
! 50: MANDOC_INCLUDES,
! 51: MANDOC_VARIABLE,
! 52: MANDOC_STANDARD,
! 53: MANDOC_AUTHOR,
! 54: MANDOC_CONFIG
! 55: };
! 56:
! 57: #define MAN_ARGS DB *db, \
! 58: const char *dbn, \
! 59: DBT *key, size_t *ksz, \
! 60: DBT *val, \
! 61: DBT *rval, size_t *rsz, \
! 62: const struct man_node *n
! 63: #define MDOC_ARGS DB *db, \
! 64: const char *dbn, \
! 65: DBT *key, size_t *ksz, \
! 66: DBT *val, \
! 67: DBT *rval, size_t *rsz, \
! 68: const struct mdoc_node *n
! 69:
! 70: static void dbt_append(DBT *, size_t *, const char *);
! 71: static void dbt_appendb(DBT *, size_t *,
! 72: const void *, size_t);
! 73: static void dbt_init(DBT *, size_t *);
! 74: static void dbt_put(DB *, const char *, DBT *, DBT *);
! 75: static void usage(void);
! 76: static void pman(DB *, const char *, DBT *, size_t *,
! 77: DBT *, DBT *, size_t *, struct man *);
! 78: static int pman_node(MAN_ARGS);
! 79: static void pmdoc(DB *, const char *, DBT *, size_t *,
! 80: DBT *, DBT *, size_t *, struct mdoc *);
! 81: static void pmdoc_node(MDOC_ARGS);
! 82: static void pmdoc_An(MDOC_ARGS);
! 83: static void pmdoc_Cd(MDOC_ARGS);
! 84: static void pmdoc_Fd(MDOC_ARGS);
! 85: static void pmdoc_In(MDOC_ARGS);
! 86: static void pmdoc_Fn(MDOC_ARGS);
! 87: static void pmdoc_Fo(MDOC_ARGS);
! 88: static void pmdoc_Nd(MDOC_ARGS);
! 89: static void pmdoc_Nm(MDOC_ARGS);
! 90: static void pmdoc_St(MDOC_ARGS);
! 91: static void pmdoc_Vt(MDOC_ARGS);
! 92:
! 93: typedef void (*pmdoc_nf)(MDOC_ARGS);
! 94:
! 95: static const char *progname;
! 96:
! 97: static const pmdoc_nf mdocs[MDOC_MAX] = {
! 98: NULL, /* Ap */
! 99: NULL, /* Dd */
! 100: NULL, /* Dt */
! 101: NULL, /* Os */
! 102: NULL, /* Sh */
! 103: NULL, /* Ss */
! 104: NULL, /* Pp */
! 105: NULL, /* D1 */
! 106: NULL, /* Dl */
! 107: NULL, /* Bd */
! 108: NULL, /* Ed */
! 109: NULL, /* Bl */
! 110: NULL, /* El */
! 111: NULL, /* It */
! 112: NULL, /* Ad */
! 113: pmdoc_An, /* An */
! 114: NULL, /* Ar */
! 115: pmdoc_Cd, /* Cd */
! 116: NULL, /* Cm */
! 117: NULL, /* Dv */
! 118: NULL, /* Er */
! 119: NULL, /* Ev */
! 120: NULL, /* Ex */
! 121: NULL, /* Fa */
! 122: pmdoc_Fd, /* Fd */
! 123: NULL, /* Fl */
! 124: pmdoc_Fn, /* Fn */
! 125: NULL, /* Ft */
! 126: NULL, /* Ic */
! 127: pmdoc_In, /* In */
! 128: NULL, /* Li */
! 129: pmdoc_Nd, /* Nd */
! 130: pmdoc_Nm, /* Nm */
! 131: NULL, /* Op */
! 132: NULL, /* Ot */
! 133: NULL, /* Pa */
! 134: NULL, /* Rv */
! 135: pmdoc_St, /* St */
! 136: pmdoc_Vt, /* Va */
! 137: pmdoc_Vt, /* Vt */
! 138: NULL, /* Xr */
! 139: NULL, /* %A */
! 140: NULL, /* %B */
! 141: NULL, /* %D */
! 142: NULL, /* %I */
! 143: NULL, /* %J */
! 144: NULL, /* %N */
! 145: NULL, /* %O */
! 146: NULL, /* %P */
! 147: NULL, /* %R */
! 148: NULL, /* %T */
! 149: NULL, /* %V */
! 150: NULL, /* Ac */
! 151: NULL, /* Ao */
! 152: NULL, /* Aq */
! 153: NULL, /* At */
! 154: NULL, /* Bc */
! 155: NULL, /* Bf */
! 156: NULL, /* Bo */
! 157: NULL, /* Bq */
! 158: NULL, /* Bsx */
! 159: NULL, /* Bx */
! 160: NULL, /* Db */
! 161: NULL, /* Dc */
! 162: NULL, /* Do */
! 163: NULL, /* Dq */
! 164: NULL, /* Ec */
! 165: NULL, /* Ef */
! 166: NULL, /* Em */
! 167: NULL, /* Eo */
! 168: NULL, /* Fx */
! 169: NULL, /* Ms */
! 170: NULL, /* No */
! 171: NULL, /* Ns */
! 172: NULL, /* Nx */
! 173: NULL, /* Ox */
! 174: NULL, /* Pc */
! 175: NULL, /* Pf */
! 176: NULL, /* Po */
! 177: NULL, /* Pq */
! 178: NULL, /* Qc */
! 179: NULL, /* Ql */
! 180: NULL, /* Qo */
! 181: NULL, /* Qq */
! 182: NULL, /* Re */
! 183: NULL, /* Rs */
! 184: NULL, /* Sc */
! 185: NULL, /* So */
! 186: NULL, /* Sq */
! 187: NULL, /* Sm */
! 188: NULL, /* Sx */
! 189: NULL, /* Sy */
! 190: NULL, /* Tn */
! 191: NULL, /* Ux */
! 192: NULL, /* Xc */
! 193: NULL, /* Xo */
! 194: pmdoc_Fo, /* Fo */
! 195: NULL, /* Fc */
! 196: NULL, /* Oo */
! 197: NULL, /* Oc */
! 198: NULL, /* Bk */
! 199: NULL, /* Ek */
! 200: NULL, /* Bt */
! 201: NULL, /* Hf */
! 202: NULL, /* Fr */
! 203: NULL, /* Ud */
! 204: NULL, /* Lb */
! 205: NULL, /* Lp */
! 206: NULL, /* Lk */
! 207: NULL, /* Mt */
! 208: NULL, /* Brq */
! 209: NULL, /* Bro */
! 210: NULL, /* Brc */
! 211: NULL, /* %C */
! 212: NULL, /* Es */
! 213: NULL, /* En */
! 214: NULL, /* Dx */
! 215: NULL, /* %Q */
! 216: NULL, /* br */
! 217: NULL, /* sp */
! 218: NULL, /* %U */
! 219: NULL, /* Ta */
! 220: };
! 221:
! 222: int
! 223: main(int argc, char *argv[])
! 224: {
! 225: struct mparse *mp; /* parse sequence */
! 226: struct mdoc *mdoc; /* resulting mdoc */
! 227: struct man *man; /* resulting man */
! 228: char *fn; /* current file being parsed */
! 229: const char *msec, /* manual section */
! 230: *mtitle, /* manual title */
! 231: *arch, /* manual architecture */
! 232: *dir; /* result dir (default: cwd) */
! 233: char ibuf[MAXPATHLEN], /* index fname */
! 234: ibbuf[MAXPATHLEN], /* index backup fname */
! 235: fbuf[MAXPATHLEN], /* btree fname */
! 236: fbbuf[MAXPATHLEN]; /* btree backup fname */
! 237: int ch;
! 238: DB *idx, /* index database */
! 239: *db; /* keyword database */
! 240: DBT rkey, rval, /* recno entries */
! 241: key, val; /* persistent keyword entries */
! 242: size_t sv,
! 243: ksz, rsz; /* entry buffer size */
! 244: char vbuf[8]; /* stringified record number */
! 245: BTREEINFO info; /* btree configuration */
! 246: recno_t rec; /* current record number */
! 247: extern int optind;
! 248: extern char *optarg;
! 249:
! 250: progname = strrchr(argv[0], '/');
! 251: if (progname == NULL)
! 252: progname = argv[0];
! 253: else
! 254: ++progname;
! 255:
! 256: dir = "";
! 257:
! 258: while (-1 != (ch = getopt(argc, argv, "d:")))
! 259: switch (ch) {
! 260: case ('d'):
! 261: dir = optarg;
! 262: break;
! 263: default:
! 264: usage();
! 265: return((int)MANDOCLEVEL_BADARG);
! 266: }
! 267:
! 268: argc -= optind;
! 269: argv += optind;
! 270:
! 271: /*
! 272: * Set up temporary file-names into which we're going to write
! 273: * all of our data (both for the index and database). These
! 274: * will be securely renamed to the real file-names after we've
! 275: * written all of our data.
! 276: */
! 277:
! 278: ibuf[0] = ibuf[MAXPATHLEN - 2] =
! 279: ibbuf[0] = ibbuf[MAXPATHLEN - 2] =
! 280: fbuf[0] = fbuf[MAXPATHLEN - 2] =
! 281: fbbuf[0] = fbbuf[MAXPATHLEN - 2] = '\0';
! 282:
! 283: strlcat(fbuf, dir, MAXPATHLEN);
! 284: strlcat(fbuf, MANDOC_DB, MAXPATHLEN);
! 285:
! 286: strlcat(fbbuf, fbuf, MAXPATHLEN);
! 287: strlcat(fbbuf, "~", MAXPATHLEN);
! 288:
! 289: strlcat(ibuf, dir, MAXPATHLEN);
! 290: strlcat(ibuf, MANDOC_IDX, MAXPATHLEN);
! 291:
! 292: strlcat(ibbuf, ibuf, MAXPATHLEN);
! 293: strlcat(ibbuf, "~", MAXPATHLEN);
! 294:
! 295: if ('\0' != fbuf[MAXPATHLEN - 2] ||
! 296: '\0' != fbbuf[MAXPATHLEN - 2] ||
! 297: '\0' != ibuf[MAXPATHLEN - 2] ||
! 298: '\0' != ibbuf[MAXPATHLEN - 2]) {
! 299: fprintf(stderr, "%s: Path too long\n", progname);
! 300: exit((int)MANDOCLEVEL_SYSERR);
! 301: }
! 302:
! 303: /*
! 304: * For the keyword database, open a BTREE database that allows
! 305: * duplicates. For the index database, use a standard RECNO
! 306: * database type.
! 307: */
! 308:
! 309: memset(&info, 0, sizeof(BTREEINFO));
! 310: info.flags = R_DUP;
! 311: db = dbopen(fbbuf, MANDOC_FLAGS, 0644, DB_BTREE, &info);
! 312:
! 313: if (NULL == db) {
! 314: perror(fbbuf);
! 315: exit((int)MANDOCLEVEL_SYSERR);
! 316: }
! 317:
! 318: idx = dbopen(ibbuf, MANDOC_FLAGS, 0644, DB_RECNO, NULL);
! 319:
! 320: if (NULL == db) {
! 321: perror(ibbuf);
! 322: (*db->close)(db);
! 323: exit((int)MANDOCLEVEL_SYSERR);
! 324: }
! 325:
! 326: /*
! 327: * Try parsing the manuals given on the command line. If we
! 328: * totally fail, then just keep on going. Take resulting trees
! 329: * and push them down into the database code.
! 330: * Use the auto-parser and don't report any errors.
! 331: */
! 332:
! 333: mp = mparse_alloc(MPARSE_AUTO, MANDOCLEVEL_FATAL, NULL, NULL);
! 334:
! 335: memset(&key, 0, sizeof(DBT));
! 336: memset(&val, 0, sizeof(DBT));
! 337: memset(&rkey, 0, sizeof(DBT));
! 338: memset(&rval, 0, sizeof(DBT));
! 339:
! 340: val.size = sizeof(vbuf);
! 341: val.data = vbuf;
! 342: rkey.size = sizeof(recno_t);
! 343:
! 344: rec = 1;
! 345: ksz = rsz = 0;
! 346:
! 347: while (NULL != (fn = *argv++)) {
! 348: mparse_reset(mp);
! 349:
! 350: /* Parse and get (non-empty) AST. */
! 351:
! 352: if (mparse_readfd(mp, -1, fn) >= MANDOCLEVEL_FATAL) {
! 353: fprintf(stderr, "%s: Parse failure\n", fn);
! 354: continue;
! 355: }
! 356: mparse_result(mp, &mdoc, &man);
! 357: if (NULL == mdoc && NULL == man)
! 358: continue;
! 359:
! 360: /* Manual section: can be empty string. */
! 361:
! 362: msec = NULL != mdoc ?
! 363: mdoc_meta(mdoc)->msec :
! 364: man_meta(man)->msec;
! 365: mtitle = NULL != mdoc ?
! 366: mdoc_meta(mdoc)->title :
! 367: man_meta(man)->title;
! 368: arch = NULL != mdoc ? mdoc_meta(mdoc)->arch : NULL;
! 369:
! 370: assert(msec);
! 371: assert(mtitle);
! 372:
! 373: /*
! 374: * The index record value consists of a nil-terminated
! 375: * filename, a nil-terminated manual section, and a
! 376: * nil-terminated description. Since the description
! 377: * may not be set, we set a sentinel to see if we're
! 378: * going to write a nil byte in its place.
! 379: */
! 380:
! 381: dbt_init(&rval, &rsz);
! 382: dbt_appendb(&rval, &rsz, fn, strlen(fn) + 1);
! 383: dbt_appendb(&rval, &rsz, msec, strlen(msec) + 1);
! 384: dbt_appendb(&rval, &rsz, mtitle, strlen(mtitle) + 1);
! 385: dbt_appendb(&rval, &rsz, arch ? arch : "",
! 386: arch ? strlen(arch) + 1 : 1);
! 387:
! 388: sv = rval.size;
! 389:
! 390: /* Fix the record number in the btree value. */
! 391:
! 392: memset(val.data, 0, sizeof(uint32_t));
! 393: memcpy(val.data + 4, &rec, sizeof(uint32_t));
! 394:
! 395: if (mdoc)
! 396: pmdoc(db, fbbuf, &key, &ksz,
! 397: &val, &rval, &rsz, mdoc);
! 398: else
! 399: pman(db, fbbuf, &key, &ksz,
! 400: &val, &rval, &rsz, man);
! 401:
! 402: /*
! 403: * Apply this to the index. If we haven't had a
! 404: * description set, put an empty one in now.
! 405: */
! 406:
! 407: if (rval.size == sv)
! 408: dbt_appendb(&rval, &rsz, "", 1);
! 409:
! 410: rkey.data = &rec;
! 411: dbt_put(idx, ibbuf, &rkey, &rval);
! 412:
! 413: printf("Indexed: %s\n", fn);
! 414: rec++;
! 415: }
! 416:
! 417: (*db->close)(db);
! 418: (*idx->close)(idx);
! 419:
! 420: mparse_free(mp);
! 421:
! 422: free(key.data);
! 423: free(rval.data);
! 424:
! 425: /* Atomically replace the file with our temporary one. */
! 426:
! 427: if (-1 == rename(fbbuf, fbuf))
! 428: perror(fbuf);
! 429: if (-1 == rename(ibbuf, ibuf))
! 430: perror(fbuf);
! 431:
! 432: return((int)MANDOCLEVEL_OK);
! 433: }
! 434:
! 435: /*
! 436: * Initialise the stored database key whose data buffer is shared
! 437: * between uses (as the key must sometimes be constructed from an array
! 438: * of
! 439: */
! 440: static void
! 441: dbt_init(DBT *key, size_t *ksz)
! 442: {
! 443:
! 444: if (0 == *ksz) {
! 445: assert(0 == key->size);
! 446: assert(NULL == key->data);
! 447: key->data = mandoc_malloc(MANDOC_BUFSZ);
! 448: *ksz = MANDOC_BUFSZ;
! 449: }
! 450:
! 451: key->size = 0;
! 452: }
! 453:
! 454: /*
! 455: * Append a binary value to a database entry. This can be invoked
! 456: * multiple times; the buffer is automatically resized.
! 457: */
! 458: static void
! 459: dbt_appendb(DBT *key, size_t *ksz, const void *cp, size_t sz)
! 460: {
! 461:
! 462: assert(key->data);
! 463:
! 464: /* Overshoot by MANDOC_BUFSZ. */
! 465:
! 466: while (key->size + sz >= *ksz) {
! 467: *ksz = key->size + sz + MANDOC_BUFSZ;
! 468: key->data = mandoc_realloc(key->data, *ksz);
! 469: }
! 470:
! 471: #if 0
! 472: dstp = key->data + (int)key->size;
! 473:
! 474: while (NULL != (endp = memchr(cp, '\\', sz))) {
! 475: ssz = endp - cp;
! 476: memcpy(dstp, cp, ssz);
! 477:
! 478: dstp += ssz;
! 479: key->size += ssz;
! 480: sz -= ssz;
! 481:
! 482: cp = endp++;
! 483: /* FIXME: expects nil-terminated string! */
! 484: esc = mandoc_escape((const char **)&endp, NULL, NULL);
! 485:
! 486: switch (esc) {
! 487: case (ESCAPE_ERROR):
! 488: /* Nil-terminate this point. */
! 489: memcpy(dstp, "", 1);
! 490: key->size++;
! 491: return;
! 492: case (ESCAPE_PREDEF):
! 493: /* FALLTHROUGH */
! 494: case (ESCAPE_SPECIAL):
! 495: break;
! 496: default:
! 497: sz -= endp - cp;
! 498: cp = endp;
! 499: continue;
! 500: }
! 501:
! 502: ssz = endp - cp;
! 503: memcpy(dstp, cp, ssz);
! 504:
! 505: dstp += ssz;
! 506: key->size += ssz;
! 507: sz -= ssz;
! 508:
! 509: cp = endp;
! 510: }
! 511: #endif
! 512:
! 513: memcpy(key->data + (int)key->size, cp, sz);
! 514: key->size += sz;
! 515: }
! 516:
! 517: /*
! 518: * Append a nil-terminated string to the database entry. This can be
! 519: * invoked multiple times. The database entry will be nil-terminated as
! 520: * well; if invoked multiple times, a space is put between strings.
! 521: */
! 522: static void
! 523: dbt_append(DBT *key, size_t *ksz, const char *cp)
! 524: {
! 525: size_t sz;
! 526:
! 527: if (0 == (sz = strlen(cp)))
! 528: return;
! 529:
! 530: assert(key->data);
! 531:
! 532: if (key->size)
! 533: ((char *)key->data)[(int)key->size - 1] = ' ';
! 534:
! 535: dbt_appendb(key, ksz, cp, sz + 1);
! 536: }
! 537:
! 538: /* ARGSUSED */
! 539: static void
! 540: pmdoc_An(MDOC_ARGS)
! 541: {
! 542: uint32_t fl;
! 543:
! 544: if (SEC_AUTHORS != n->sec)
! 545: return;
! 546:
! 547: for (n = n->child; n; n = n->next)
! 548: if (MDOC_TEXT == n->type)
! 549: dbt_append(key, ksz, n->string);
! 550:
! 551: fl = (uint32_t)MANDOC_AUTHOR;
! 552: memcpy(val->data, &fl, 4);
! 553: }
! 554:
! 555: /* ARGSUSED */
! 556: static void
! 557: pmdoc_Fd(MDOC_ARGS)
! 558: {
! 559: uint32_t fl;
! 560: const char *start, *end;
! 561: size_t sz;
! 562:
! 563: if (SEC_SYNOPSIS != n->sec)
! 564: return;
! 565: if (NULL == (n = n->child) || MDOC_TEXT != n->type)
! 566: return;
! 567:
! 568: /*
! 569: * Only consider those `Fd' macro fields that begin with an
! 570: * "inclusion" token (versus, e.g., #define).
! 571: */
! 572: if (strcmp("#include", n->string))
! 573: return;
! 574:
! 575: if (NULL == (n = n->next) || MDOC_TEXT != n->type)
! 576: return;
! 577:
! 578: /*
! 579: * Strip away the enclosing angle brackets and make sure we're
! 580: * not zero-length.
! 581: */
! 582:
! 583: start = n->string;
! 584: if ('<' == *start || '"' == *start)
! 585: start++;
! 586:
! 587: if (0 == (sz = strlen(start)))
! 588: return;
! 589:
! 590: end = &start[(int)sz - 1];
! 591: if ('>' == *end || '"' == *end)
! 592: end--;
! 593:
! 594: assert(end >= start);
! 595: dbt_appendb(key, ksz, start, (size_t)(end - start + 1));
! 596: dbt_appendb(key, ksz, "", 1);
! 597:
! 598: fl = (uint32_t)MANDOC_INCLUDES;
! 599: memcpy(val->data, &fl, 4);
! 600: }
! 601:
! 602: /* ARGSUSED */
! 603: static void
! 604: pmdoc_Cd(MDOC_ARGS)
! 605: {
! 606: uint32_t fl;
! 607:
! 608: if (SEC_SYNOPSIS != n->sec)
! 609: return;
! 610:
! 611: for (n = n->child; n; n = n->next)
! 612: if (MDOC_TEXT == n->type)
! 613: dbt_append(key, ksz, n->string);
! 614:
! 615: fl = (uint32_t)MANDOC_CONFIG;
! 616: memcpy(val->data, &fl, 4);
! 617: }
! 618:
! 619: /* ARGSUSED */
! 620: static void
! 621: pmdoc_In(MDOC_ARGS)
! 622: {
! 623: uint32_t fl;
! 624:
! 625: if (SEC_SYNOPSIS != n->sec)
! 626: return;
! 627: if (NULL == n->child || MDOC_TEXT != n->child->type)
! 628: return;
! 629:
! 630: dbt_append(key, ksz, n->child->string);
! 631: fl = (uint32_t)MANDOC_INCLUDES;
! 632: memcpy(val->data, &fl, 4);
! 633: }
! 634:
! 635: /* ARGSUSED */
! 636: static void
! 637: pmdoc_Fn(MDOC_ARGS)
! 638: {
! 639: uint32_t fl;
! 640: const char *cp;
! 641:
! 642: if (SEC_SYNOPSIS != n->sec)
! 643: return;
! 644: if (NULL == n->child || MDOC_TEXT != n->child->type)
! 645: return;
! 646:
! 647: /* .Fn "struct type *arg" "foo" */
! 648:
! 649: cp = strrchr(n->child->string, ' ');
! 650: if (NULL == cp)
! 651: cp = n->child->string;
! 652:
! 653: /* Strip away pointer symbol. */
! 654:
! 655: while ('*' == *cp)
! 656: cp++;
! 657:
! 658: dbt_append(key, ksz, cp);
! 659: fl = (uint32_t)MANDOC_FUNCTION;
! 660: memcpy(val->data, &fl, 4);
! 661: }
! 662:
! 663: /* ARGSUSED */
! 664: static void
! 665: pmdoc_St(MDOC_ARGS)
! 666: {
! 667: uint32_t fl;
! 668:
! 669: if (SEC_STANDARDS != n->sec)
! 670: return;
! 671: if (NULL == n->child || MDOC_TEXT != n->child->type)
! 672: return;
! 673:
! 674: dbt_append(key, ksz, n->child->string);
! 675: fl = (uint32_t)MANDOC_STANDARD;
! 676: memcpy(val->data, &fl, 4);
! 677: }
! 678:
! 679: /* ARGSUSED */
! 680: static void
! 681: pmdoc_Vt(MDOC_ARGS)
! 682: {
! 683: uint32_t fl;
! 684: const char *start;
! 685: size_t sz;
! 686:
! 687: if (SEC_SYNOPSIS != n->sec)
! 688: return;
! 689: if (MDOC_Vt == n->tok && MDOC_BODY != n->type)
! 690: return;
! 691: if (NULL == n->last || MDOC_TEXT != n->last->type)
! 692: return;
! 693:
! 694: /*
! 695: * Strip away leading pointer symbol '*' and trailing ';'.
! 696: */
! 697:
! 698: start = n->last->string;
! 699:
! 700: while ('*' == *start)
! 701: start++;
! 702:
! 703: if (0 == (sz = strlen(start)))
! 704: return;
! 705:
! 706: if (';' == start[(int)sz - 1])
! 707: sz--;
! 708:
! 709: if (0 == sz)
! 710: return;
! 711:
! 712: dbt_appendb(key, ksz, start, sz);
! 713: dbt_appendb(key, ksz, "", 1);
! 714:
! 715: fl = (uint32_t)MANDOC_VARIABLE;
! 716: memcpy(val->data, &fl, 4);
! 717: }
! 718:
! 719: /* ARGSUSED */
! 720: static void
! 721: pmdoc_Fo(MDOC_ARGS)
! 722: {
! 723: uint32_t fl;
! 724:
! 725: if (SEC_SYNOPSIS != n->sec || MDOC_HEAD != n->type)
! 726: return;
! 727: if (NULL == n->child || MDOC_TEXT != n->child->type)
! 728: return;
! 729:
! 730: dbt_append(key, ksz, n->child->string);
! 731: fl = (uint32_t)MANDOC_FUNCTION;
! 732: memcpy(val->data, &fl, 4);
! 733: }
! 734:
! 735:
! 736: /* ARGSUSED */
! 737: static void
! 738: pmdoc_Nd(MDOC_ARGS)
! 739: {
! 740: int first;
! 741:
! 742: for (first = 1, n = n->child; n; n = n->next) {
! 743: if (MDOC_TEXT != n->type)
! 744: continue;
! 745: if (first)
! 746: dbt_appendb(rval, rsz, n->string, strlen(n->string) + 1);
! 747: else
! 748: dbt_append(rval, rsz, n->string);
! 749: first = 0;
! 750: }
! 751: }
! 752:
! 753: /* ARGSUSED */
! 754: static void
! 755: pmdoc_Nm(MDOC_ARGS)
! 756: {
! 757: uint32_t fl;
! 758:
! 759: if (SEC_NAME == n->sec) {
! 760: for (n = n->child; n; n = n->next) {
! 761: if (MDOC_TEXT != n->type)
! 762: continue;
! 763: dbt_append(key, ksz, n->string);
! 764: }
! 765: fl = (uint32_t)MANDOC_NAME;
! 766: memcpy(val->data, &fl, 4);
! 767: return;
! 768: } else if (SEC_SYNOPSIS != n->sec || MDOC_HEAD != n->type)
! 769: return;
! 770:
! 771: for (n = n->child; n; n = n->next) {
! 772: if (MDOC_TEXT != n->type)
! 773: continue;
! 774: dbt_append(key, ksz, n->string);
! 775: }
! 776:
! 777: fl = (uint32_t)MANDOC_UTILITY;
! 778: memcpy(val->data, &fl, 4);
! 779: }
! 780:
! 781: static void
! 782: dbt_put(DB *db, const char *dbn, DBT *key, DBT *val)
! 783: {
! 784:
! 785: if (0 == key->size)
! 786: return;
! 787:
! 788: assert(key->data);
! 789: assert(val->size);
! 790: assert(val->data);
! 791:
! 792: if (0 == (*db->put)(db, key, val, 0))
! 793: return;
! 794:
! 795: perror(dbn);
! 796: exit((int)MANDOCLEVEL_SYSERR);
! 797: /* NOTREACHED */
! 798: }
! 799:
! 800: /*
! 801: * Call out to per-macro handlers after clearing the persistent database
! 802: * key. If the macro sets the database key, flush it to the database.
! 803: */
! 804: static void
! 805: pmdoc_node(MDOC_ARGS)
! 806: {
! 807:
! 808: if (NULL == n)
! 809: return;
! 810:
! 811: switch (n->type) {
! 812: case (MDOC_HEAD):
! 813: /* FALLTHROUGH */
! 814: case (MDOC_BODY):
! 815: /* FALLTHROUGH */
! 816: case (MDOC_TAIL):
! 817: /* FALLTHROUGH */
! 818: case (MDOC_BLOCK):
! 819: /* FALLTHROUGH */
! 820: case (MDOC_ELEM):
! 821: if (NULL == mdocs[n->tok])
! 822: break;
! 823:
! 824: dbt_init(key, ksz);
! 825:
! 826: (*mdocs[n->tok])(db, dbn, key, ksz, val, rval, rsz, n);
! 827: dbt_put(db, dbn, key, val);
! 828: break;
! 829: default:
! 830: break;
! 831: }
! 832:
! 833: pmdoc_node(db, dbn, key, ksz, val, rval, rsz, n->child);
! 834: pmdoc_node(db, dbn, key, ksz, val, rval, rsz, n->next);
! 835: }
! 836:
! 837: static int
! 838: pman_node(MAN_ARGS)
! 839: {
! 840: const struct man_node *head, *body;
! 841: const char *start, *sv;
! 842: size_t sz;
! 843: uint32_t fl;
! 844:
! 845: if (NULL == n)
! 846: return(0);
! 847:
! 848: /*
! 849: * We're only searching for one thing: the first text child in
! 850: * the BODY of a NAME section. Since we don't keep track of
! 851: * sections in -man, run some hoops to find out whether we're in
! 852: * the correct section or not.
! 853: */
! 854:
! 855: if (MAN_BODY == n->type && MAN_SH == n->tok) {
! 856: body = n;
! 857: assert(body->parent);
! 858: if (NULL != (head = body->parent->head) &&
! 859: 1 == head->nchild &&
! 860: NULL != (head = (head->child)) &&
! 861: MAN_TEXT == head->type &&
! 862: 0 == strcmp(head->string, "NAME") &&
! 863: NULL != (body = body->child) &&
! 864: MAN_TEXT == body->type) {
! 865:
! 866: fl = (uint32_t)MANDOC_NAME;
! 867: memcpy(val->data, &fl, 4);
! 868:
! 869: assert(body->string);
! 870: start = sv = body->string;
! 871:
! 872: /*
! 873: * Go through a special heuristic dance here.
! 874: * This is why -man manuals are great!
! 875: * (I'm being sarcastic: my eyes are bleeding.)
! 876: * Conventionally, one or more manual names are
! 877: * comma-specified prior to a whitespace, then a
! 878: * dash, then a description. Try to puzzle out
! 879: * the name parts here.
! 880: */
! 881:
! 882: for ( ;; ) {
! 883: sz = strcspn(start, " ,");
! 884: if ('\0' == start[(int)sz])
! 885: break;
! 886:
! 887: dbt_init(key, ksz);
! 888: dbt_appendb(key, ksz, start, sz);
! 889: dbt_appendb(key, ksz, "", 1);
! 890:
! 891: dbt_put(db, dbn, key, val);
! 892:
! 893: if (' ' == start[(int)sz]) {
! 894: start += (int)sz + 1;
! 895: break;
! 896: }
! 897:
! 898: assert(',' == start[(int)sz]);
! 899: start += (int)sz + 1;
! 900: while (' ' == *start)
! 901: start++;
! 902: }
! 903:
! 904: if (sv == start) {
! 905: dbt_init(key, ksz);
! 906: dbt_append(key, ksz, start);
! 907: return(1);
! 908: }
! 909:
! 910: while (' ' == *start)
! 911: start++;
! 912:
! 913: if (0 == strncmp(start, "-", 1))
! 914: start += 1;
! 915: else if (0 == strncmp(start, "\\-", 2))
! 916: start += 2;
! 917: else if (0 == strncmp(start, "\\(en", 4))
! 918: start += 4;
! 919: else if (0 == strncmp(start, "\\(em", 4))
! 920: start += 4;
! 921:
! 922: while (' ' == *start)
! 923: start++;
! 924:
! 925: dbt_appendb(rval, rsz, start, strlen(start) + 1);
! 926: }
! 927: }
! 928:
! 929: if (pman_node(db, dbn, key, ksz, val, rval, rsz, n->child))
! 930: return(1);
! 931: if (pman_node(db, dbn, key, ksz, val, rval, rsz, n->next))
! 932: return(1);
! 933:
! 934: return(0);
! 935: }
! 936:
! 937: static void
! 938: pman(DB *db, const char *dbn, DBT *key, size_t *ksz,
! 939: DBT *val, DBT *rval, size_t *rsz, struct man *m)
! 940: {
! 941:
! 942: pman_node(db, dbn, key, ksz, val, rval, rsz, man_node(m));
! 943: }
! 944:
! 945:
! 946: static void
! 947: pmdoc(DB *db, const char *dbn, DBT *key, size_t *ksz,
! 948: DBT *val, DBT *rval, size_t *rsz, struct mdoc *m)
! 949: {
! 950:
! 951: pmdoc_node(db, dbn, key, ksz, val, rval, rsz, mdoc_node(m));
! 952: }
! 953:
! 954: static void
! 955: usage(void)
! 956: {
! 957:
! 958: fprintf(stderr, "usage: %s "
! 959: "[-d path] "
! 960: "[file...]\n",
! 961: progname);
! 962: }
CVSweb