=================================================================== RCS file: /cvs/mandoc/mandocdb.c,v retrieving revision 1.225 retrieving revision 1.232 diff -u -p -r1.225 -r1.232 --- mandoc/mandocdb.c 2016/08/01 20:53:13 1.225 +++ mandoc/mandocdb.c 2016/10/18 16:06:44 1.232 @@ -1,7 +1,8 @@ -/* $Id: mandocdb.c,v 1.225 2016/08/01 20:53:13 schwarze Exp $ */ +/* $Id: mandocdb.c,v 1.232 2016/10/18 16:06:44 schwarze Exp $ */ /* * Copyright (c) 2011, 2012 Kristaps Dzonsons * Copyright (c) 2011-2016 Ingo Schwarze + * Copyright (c) 2016 Ed Maste * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -84,6 +85,7 @@ struct mpage { char *arch; /* architecture from file content */ char *title; /* title from file content */ char *desc; /* description from file content */ + struct mpage *next; /* singly linked list */ struct mlink *mlinks; /* singly linked list */ int name_head_done; enum form form; /* format from file content */ @@ -118,11 +120,15 @@ static void dbadd_mlink(const struct mlink *mlink); static void dbprune(struct dba *); static void dbwrite(struct dba *); static void filescan(const char *); +#if HAVE_FTS_COMPARE_CONST +static int fts_compare(const FTSENT *const *, const FTSENT *const *); +#else +static int fts_compare(const FTSENT **, const FTSENT **); +#endif static void mlink_add(struct mlink *, const struct stat *); static void mlink_check(struct mpage *, struct mlink *); static void mlink_free(struct mlink *); static void mlinks_undupe(struct mpage *); -int mpages_compare(const void *, const void *); static void mpages_free(void); static void mpages_merge(struct dba *, struct mparse *); static void parse_cat(struct mpage *, int); @@ -169,6 +175,7 @@ static int write_utf8; /* write UTF-8 output; else A static int exitcode; /* to be returned by main */ static enum op op; /* operational mode */ static char basedir[PATH_MAX]; /* current base directory */ +static struct mpage *mpage_head; /* list of distinct manual pages */ static struct ohash mpages; /* table of distinct manual pages */ static struct ohash mlinks; /* table of directory entries */ static struct ohash names; /* table of all names */ @@ -448,10 +455,10 @@ mandocdb(int argc, char *argv[]) if (nodb == 0) dbprune(dba); } else { - /* - * Database missing or corrupt. - * Recreate from scratch. - */ + /* Database missing or corrupt. */ + if (op != OP_UPDATE || errno != ENOENT) + say(MANDOC_DB, "%s: Automatically recreating" + " from scratch", strerror(errno)); exitcode = (int)MANDOCLEVEL_OK; op = OP_DEFAULT; if (0 == treescan()) @@ -540,6 +547,20 @@ usage: } /* + * To get a singly linked list in alpha order while inserting entries + * at the beginning, process directory entries in reverse alpha order. + */ +static int +#if HAVE_FTS_COMPARE_CONST +fts_compare(const FTSENT *const *a, const FTSENT *const *b) +#else +fts_compare(const FTSENT **a, const FTSENT **b) +#endif +{ + return -strcmp((*a)->fts_name, (*b)->fts_name); +} + +/* * Scan a directory tree rooted at "basedir" for manpages. * We use fts(), scanning directory parts along the way for clues to our * section and architecture. @@ -569,8 +590,8 @@ treescan(void) argv[0] = "."; argv[1] = (char *)NULL; - f = fts_open((char * const *)argv, - FTS_PHYSICAL | FTS_NOCHDIR, NULL); + f = fts_open((char * const *)argv, FTS_PHYSICAL | FTS_NOCHDIR, + fts_compare); if (f == NULL) { exitcode = (int)MANDOCLEVEL_SYSERR; say("", "&fts_open"); @@ -936,6 +957,8 @@ mlink_add(struct mlink *mlink, const struct stat *st) mpage->inodev.st_ino = inodev.st_ino; mpage->inodev.st_dev = inodev.st_dev; mpage->form = FORM_NONE; + mpage->next = mpage_head; + mpage_head = mpage; ohash_insert(&mpages, slot, mpage); } else mlink->next = mpage->mlinks; @@ -959,20 +982,18 @@ mpages_free(void) { struct mpage *mpage; struct mlink *mlink; - unsigned int slot; - mpage = ohash_first(&mpages, &slot); - while (NULL != mpage) { - while (NULL != (mlink = mpage->mlinks)) { + while ((mpage = mpage_head) != NULL) { + while ((mlink = mpage->mlinks) != NULL) { mpage->mlinks = mlink->next; mlink_free(mlink); } + mpage_head = mpage->next; free(mpage->sec); free(mpage->arch); free(mpage->title); free(mpage->desc); free(mpage); - mpage = ohash_next(&mpages, &slot); } } @@ -1049,7 +1070,7 @@ mlink_check(struct mpage *mpage, struct mlink *mlink) * architectures. * A few manuals are even shared across completely * different architectures, for example fdformat(1) - * on amd64, i386, sparc, and sparc64. + * on amd64, i386, and sparc64. */ if (strcasecmp(mpage->arch, mlink->arch)) @@ -1086,30 +1107,18 @@ mlink_check(struct mpage *mpage, struct mlink *mlink) static void mpages_merge(struct dba *dba, struct mparse *mp) { - struct mpage **mplist, *mpage, *mpage_dest; + struct mpage *mpage, *mpage_dest; struct mlink *mlink, *mlink_dest; struct roff_man *man; char *sodest; char *cp; int fd; - unsigned int ip, npages, pslot; - npages = ohash_entries(&mpages); - mplist = mandoc_reallocarray(NULL, npages, sizeof(*mplist)); - ip = 0; - mpage = ohash_first(&mpages, &pslot); - while (mpage != NULL) { + for (mpage = mpage_head; mpage != NULL; mpage = mpage->next) { mlinks_undupe(mpage); - if (mpage->mlinks != NULL) - mplist[ip++] = mpage; - mpage = ohash_next(&mpages, &pslot); - } - npages = ip; - qsort(mplist, npages, sizeof(*mplist), mpages_compare); + if ((mlink = mpage->mlinks) == NULL) + continue; - for (ip = 0; ip < npages; ip++) { - mpage = mplist[ip]; - mlink = mpage->mlinks; name_mask = NAME_MASK; mandoc_ohash_init(&names, 4, offsetof(struct str, key)); mandoc_ohash_init(&strings, 6, offsetof(struct str, key)); @@ -1218,19 +1227,8 @@ nextpage: ohash_delete(&strings); ohash_delete(&names); } - free(mplist); } -int -mpages_compare(const void *vp1, const void *vp2) -{ - const struct mpage *mp1, *mp2; - - mp1 = *(const struct mpage **)vp1; - mp2 = *(const struct mpage **)vp2; - return strcmp(mp1->mlinks->file, mp2->mlinks->file); -} - static void parse_cat(struct mpage *mpage, int fd) { @@ -1693,7 +1691,7 @@ parse_mdoc_Nm(struct mpage *mpage, const struct roff_m if ( ! (mpage->name_head_done || n->child == NULL || n->child->string == NULL || strcasecmp(n->child->string, meta->title))) { - putkey(mpage, n->child->string, ROFFT_HEAD); + putkey(mpage, n->child->string, NAME_HEAD); mpage->name_head_done = 1; } return 0; @@ -2013,11 +2011,12 @@ dbadd(struct dba *dba, struct mpage *mpage) cp = mpage->desc; i = strlen(cp); mustfree = render_string(&cp, &i); - mpage->dba = dba_page_new(dba->pages, mlink->name, mpage->sec, + mpage->dba = dba_page_new(dba->pages, *mpage->arch == '\0' ? mlink->arch : mpage->arch, cp, mlink->file, mpage->form); if (mustfree) free(cp); + dba_page_add(mpage->dba, DBP_SECT, mpage->sec); while (mlink != NULL) { dbadd_mlink(mlink);