1*61d06d6bSBaptiste Daroussin /* $Id: dba.c,v 1.10 2017/02/17 14:43:54 schwarze Exp $ */ 2*61d06d6bSBaptiste Daroussin /* 3*61d06d6bSBaptiste Daroussin * Copyright (c) 2016, 2017 Ingo Schwarze <schwarze@openbsd.org> 4*61d06d6bSBaptiste Daroussin * 5*61d06d6bSBaptiste Daroussin * Permission to use, copy, modify, and distribute this software for any 6*61d06d6bSBaptiste Daroussin * purpose with or without fee is hereby granted, provided that the above 7*61d06d6bSBaptiste Daroussin * copyright notice and this permission notice appear in all copies. 8*61d06d6bSBaptiste Daroussin * 9*61d06d6bSBaptiste Daroussin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10*61d06d6bSBaptiste Daroussin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11*61d06d6bSBaptiste Daroussin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12*61d06d6bSBaptiste Daroussin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13*61d06d6bSBaptiste Daroussin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14*61d06d6bSBaptiste Daroussin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15*61d06d6bSBaptiste Daroussin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16*61d06d6bSBaptiste Daroussin * 17*61d06d6bSBaptiste Daroussin * Allocation-based version of the mandoc database, for read-write access. 18*61d06d6bSBaptiste Daroussin * The interface is defined in "dba.h". 19*61d06d6bSBaptiste Daroussin */ 20*61d06d6bSBaptiste Daroussin #include "config.h" 21*61d06d6bSBaptiste Daroussin 22*61d06d6bSBaptiste Daroussin #include <sys/types.h> 23*61d06d6bSBaptiste Daroussin #if HAVE_ENDIAN 24*61d06d6bSBaptiste Daroussin #include <endian.h> 25*61d06d6bSBaptiste Daroussin #elif HAVE_SYS_ENDIAN 26*61d06d6bSBaptiste Daroussin #include <sys/endian.h> 27*61d06d6bSBaptiste Daroussin #elif HAVE_NTOHL 28*61d06d6bSBaptiste Daroussin #include <arpa/inet.h> 29*61d06d6bSBaptiste Daroussin #endif 30*61d06d6bSBaptiste Daroussin #include <errno.h> 31*61d06d6bSBaptiste Daroussin #include <stddef.h> 32*61d06d6bSBaptiste Daroussin #include <stdint.h> 33*61d06d6bSBaptiste Daroussin #include <stdlib.h> 34*61d06d6bSBaptiste Daroussin #include <string.h> 35*61d06d6bSBaptiste Daroussin #include <unistd.h> 36*61d06d6bSBaptiste Daroussin 37*61d06d6bSBaptiste Daroussin #include "mandoc_aux.h" 38*61d06d6bSBaptiste Daroussin #include "mandoc_ohash.h" 39*61d06d6bSBaptiste Daroussin #include "mansearch.h" 40*61d06d6bSBaptiste Daroussin #include "dba_write.h" 41*61d06d6bSBaptiste Daroussin #include "dba_array.h" 42*61d06d6bSBaptiste Daroussin #include "dba.h" 43*61d06d6bSBaptiste Daroussin 44*61d06d6bSBaptiste Daroussin struct macro_entry { 45*61d06d6bSBaptiste Daroussin struct dba_array *pages; 46*61d06d6bSBaptiste Daroussin char value[]; 47*61d06d6bSBaptiste Daroussin }; 48*61d06d6bSBaptiste Daroussin 49*61d06d6bSBaptiste Daroussin static void *prepend(const char *, char); 50*61d06d6bSBaptiste Daroussin static void dba_pages_write(struct dba_array *); 51*61d06d6bSBaptiste Daroussin static int compare_names(const void *, const void *); 52*61d06d6bSBaptiste Daroussin static int compare_strings(const void *, const void *); 53*61d06d6bSBaptiste Daroussin 54*61d06d6bSBaptiste Daroussin static struct macro_entry 55*61d06d6bSBaptiste Daroussin *get_macro_entry(struct ohash *, const char *, int32_t); 56*61d06d6bSBaptiste Daroussin static void dba_macros_write(struct dba_array *); 57*61d06d6bSBaptiste Daroussin static void dba_macro_write(struct ohash *); 58*61d06d6bSBaptiste Daroussin static int compare_entries(const void *, const void *); 59*61d06d6bSBaptiste Daroussin 60*61d06d6bSBaptiste Daroussin 61*61d06d6bSBaptiste Daroussin /*** top-level functions **********************************************/ 62*61d06d6bSBaptiste Daroussin 63*61d06d6bSBaptiste Daroussin struct dba * 64*61d06d6bSBaptiste Daroussin dba_new(int32_t npages) 65*61d06d6bSBaptiste Daroussin { 66*61d06d6bSBaptiste Daroussin struct dba *dba; 67*61d06d6bSBaptiste Daroussin struct ohash *macro; 68*61d06d6bSBaptiste Daroussin int32_t im; 69*61d06d6bSBaptiste Daroussin 70*61d06d6bSBaptiste Daroussin dba = mandoc_malloc(sizeof(*dba)); 71*61d06d6bSBaptiste Daroussin dba->pages = dba_array_new(npages, DBA_GROW); 72*61d06d6bSBaptiste Daroussin dba->macros = dba_array_new(MACRO_MAX, 0); 73*61d06d6bSBaptiste Daroussin for (im = 0; im < MACRO_MAX; im++) { 74*61d06d6bSBaptiste Daroussin macro = mandoc_malloc(sizeof(*macro)); 75*61d06d6bSBaptiste Daroussin mandoc_ohash_init(macro, 4, 76*61d06d6bSBaptiste Daroussin offsetof(struct macro_entry, value)); 77*61d06d6bSBaptiste Daroussin dba_array_set(dba->macros, im, macro); 78*61d06d6bSBaptiste Daroussin } 79*61d06d6bSBaptiste Daroussin return dba; 80*61d06d6bSBaptiste Daroussin } 81*61d06d6bSBaptiste Daroussin 82*61d06d6bSBaptiste Daroussin void 83*61d06d6bSBaptiste Daroussin dba_free(struct dba *dba) 84*61d06d6bSBaptiste Daroussin { 85*61d06d6bSBaptiste Daroussin struct dba_array *page; 86*61d06d6bSBaptiste Daroussin struct ohash *macro; 87*61d06d6bSBaptiste Daroussin struct macro_entry *entry; 88*61d06d6bSBaptiste Daroussin unsigned int slot; 89*61d06d6bSBaptiste Daroussin 90*61d06d6bSBaptiste Daroussin dba_array_FOREACH(dba->macros, macro) { 91*61d06d6bSBaptiste Daroussin for (entry = ohash_first(macro, &slot); entry != NULL; 92*61d06d6bSBaptiste Daroussin entry = ohash_next(macro, &slot)) { 93*61d06d6bSBaptiste Daroussin dba_array_free(entry->pages); 94*61d06d6bSBaptiste Daroussin free(entry); 95*61d06d6bSBaptiste Daroussin } 96*61d06d6bSBaptiste Daroussin ohash_delete(macro); 97*61d06d6bSBaptiste Daroussin free(macro); 98*61d06d6bSBaptiste Daroussin } 99*61d06d6bSBaptiste Daroussin dba_array_free(dba->macros); 100*61d06d6bSBaptiste Daroussin 101*61d06d6bSBaptiste Daroussin dba_array_undel(dba->pages); 102*61d06d6bSBaptiste Daroussin dba_array_FOREACH(dba->pages, page) { 103*61d06d6bSBaptiste Daroussin dba_array_free(dba_array_get(page, DBP_NAME)); 104*61d06d6bSBaptiste Daroussin dba_array_free(dba_array_get(page, DBP_SECT)); 105*61d06d6bSBaptiste Daroussin dba_array_free(dba_array_get(page, DBP_ARCH)); 106*61d06d6bSBaptiste Daroussin free(dba_array_get(page, DBP_DESC)); 107*61d06d6bSBaptiste Daroussin dba_array_free(dba_array_get(page, DBP_FILE)); 108*61d06d6bSBaptiste Daroussin dba_array_free(page); 109*61d06d6bSBaptiste Daroussin } 110*61d06d6bSBaptiste Daroussin dba_array_free(dba->pages); 111*61d06d6bSBaptiste Daroussin 112*61d06d6bSBaptiste Daroussin free(dba); 113*61d06d6bSBaptiste Daroussin } 114*61d06d6bSBaptiste Daroussin 115*61d06d6bSBaptiste Daroussin /* 116*61d06d6bSBaptiste Daroussin * Write the complete mandoc database to disk; the format is: 117*61d06d6bSBaptiste Daroussin * - One integer each for magic and version. 118*61d06d6bSBaptiste Daroussin * - One pointer each to the macros table and to the final magic. 119*61d06d6bSBaptiste Daroussin * - The pages table. 120*61d06d6bSBaptiste Daroussin * - The macros table. 121*61d06d6bSBaptiste Daroussin * - And at the very end, the magic integer again. 122*61d06d6bSBaptiste Daroussin */ 123*61d06d6bSBaptiste Daroussin int 124*61d06d6bSBaptiste Daroussin dba_write(const char *fname, struct dba *dba) 125*61d06d6bSBaptiste Daroussin { 126*61d06d6bSBaptiste Daroussin int save_errno; 127*61d06d6bSBaptiste Daroussin int32_t pos_end, pos_macros, pos_macros_ptr; 128*61d06d6bSBaptiste Daroussin 129*61d06d6bSBaptiste Daroussin if (dba_open(fname) == -1) 130*61d06d6bSBaptiste Daroussin return -1; 131*61d06d6bSBaptiste Daroussin dba_int_write(MANDOCDB_MAGIC); 132*61d06d6bSBaptiste Daroussin dba_int_write(MANDOCDB_VERSION); 133*61d06d6bSBaptiste Daroussin pos_macros_ptr = dba_skip(1, 2); 134*61d06d6bSBaptiste Daroussin dba_pages_write(dba->pages); 135*61d06d6bSBaptiste Daroussin pos_macros = dba_tell(); 136*61d06d6bSBaptiste Daroussin dba_macros_write(dba->macros); 137*61d06d6bSBaptiste Daroussin pos_end = dba_tell(); 138*61d06d6bSBaptiste Daroussin dba_int_write(MANDOCDB_MAGIC); 139*61d06d6bSBaptiste Daroussin dba_seek(pos_macros_ptr); 140*61d06d6bSBaptiste Daroussin dba_int_write(pos_macros); 141*61d06d6bSBaptiste Daroussin dba_int_write(pos_end); 142*61d06d6bSBaptiste Daroussin if (dba_close() == -1) { 143*61d06d6bSBaptiste Daroussin save_errno = errno; 144*61d06d6bSBaptiste Daroussin unlink(fname); 145*61d06d6bSBaptiste Daroussin errno = save_errno; 146*61d06d6bSBaptiste Daroussin return -1; 147*61d06d6bSBaptiste Daroussin } 148*61d06d6bSBaptiste Daroussin return 0; 149*61d06d6bSBaptiste Daroussin } 150*61d06d6bSBaptiste Daroussin 151*61d06d6bSBaptiste Daroussin 152*61d06d6bSBaptiste Daroussin /*** functions for handling pages *************************************/ 153*61d06d6bSBaptiste Daroussin 154*61d06d6bSBaptiste Daroussin /* 155*61d06d6bSBaptiste Daroussin * Create a new page and append it to the pages table. 156*61d06d6bSBaptiste Daroussin */ 157*61d06d6bSBaptiste Daroussin struct dba_array * 158*61d06d6bSBaptiste Daroussin dba_page_new(struct dba_array *pages, const char *arch, 159*61d06d6bSBaptiste Daroussin const char *desc, const char *file, enum form form) 160*61d06d6bSBaptiste Daroussin { 161*61d06d6bSBaptiste Daroussin struct dba_array *page, *entry; 162*61d06d6bSBaptiste Daroussin 163*61d06d6bSBaptiste Daroussin page = dba_array_new(DBP_MAX, 0); 164*61d06d6bSBaptiste Daroussin entry = dba_array_new(1, DBA_STR | DBA_GROW); 165*61d06d6bSBaptiste Daroussin dba_array_add(page, entry); 166*61d06d6bSBaptiste Daroussin entry = dba_array_new(1, DBA_STR | DBA_GROW); 167*61d06d6bSBaptiste Daroussin dba_array_add(page, entry); 168*61d06d6bSBaptiste Daroussin if (arch != NULL && *arch != '\0') { 169*61d06d6bSBaptiste Daroussin entry = dba_array_new(1, DBA_STR | DBA_GROW); 170*61d06d6bSBaptiste Daroussin dba_array_add(entry, (void *)arch); 171*61d06d6bSBaptiste Daroussin } else 172*61d06d6bSBaptiste Daroussin entry = NULL; 173*61d06d6bSBaptiste Daroussin dba_array_add(page, entry); 174*61d06d6bSBaptiste Daroussin dba_array_add(page, mandoc_strdup(desc)); 175*61d06d6bSBaptiste Daroussin entry = dba_array_new(1, DBA_STR | DBA_GROW); 176*61d06d6bSBaptiste Daroussin dba_array_add(entry, prepend(file, form)); 177*61d06d6bSBaptiste Daroussin dba_array_add(page, entry); 178*61d06d6bSBaptiste Daroussin dba_array_add(pages, page); 179*61d06d6bSBaptiste Daroussin return page; 180*61d06d6bSBaptiste Daroussin } 181*61d06d6bSBaptiste Daroussin 182*61d06d6bSBaptiste Daroussin /* 183*61d06d6bSBaptiste Daroussin * Add a section, architecture, or file name to an existing page. 184*61d06d6bSBaptiste Daroussin * Passing the NULL pointer for the architecture makes the page MI. 185*61d06d6bSBaptiste Daroussin * In that case, any earlier or later architectures are ignored. 186*61d06d6bSBaptiste Daroussin */ 187*61d06d6bSBaptiste Daroussin void 188*61d06d6bSBaptiste Daroussin dba_page_add(struct dba_array *page, int32_t ie, const char *str) 189*61d06d6bSBaptiste Daroussin { 190*61d06d6bSBaptiste Daroussin struct dba_array *entries; 191*61d06d6bSBaptiste Daroussin char *entry; 192*61d06d6bSBaptiste Daroussin 193*61d06d6bSBaptiste Daroussin entries = dba_array_get(page, ie); 194*61d06d6bSBaptiste Daroussin if (ie == DBP_ARCH) { 195*61d06d6bSBaptiste Daroussin if (entries == NULL) 196*61d06d6bSBaptiste Daroussin return; 197*61d06d6bSBaptiste Daroussin if (str == NULL || *str == '\0') { 198*61d06d6bSBaptiste Daroussin dba_array_free(entries); 199*61d06d6bSBaptiste Daroussin dba_array_set(page, DBP_ARCH, NULL); 200*61d06d6bSBaptiste Daroussin return; 201*61d06d6bSBaptiste Daroussin } 202*61d06d6bSBaptiste Daroussin } 203*61d06d6bSBaptiste Daroussin if (*str == '\0') 204*61d06d6bSBaptiste Daroussin return; 205*61d06d6bSBaptiste Daroussin dba_array_FOREACH(entries, entry) { 206*61d06d6bSBaptiste Daroussin if (ie == DBP_FILE && *entry < ' ') 207*61d06d6bSBaptiste Daroussin entry++; 208*61d06d6bSBaptiste Daroussin if (strcmp(entry, str) == 0) 209*61d06d6bSBaptiste Daroussin return; 210*61d06d6bSBaptiste Daroussin } 211*61d06d6bSBaptiste Daroussin dba_array_add(entries, (void *)str); 212*61d06d6bSBaptiste Daroussin } 213*61d06d6bSBaptiste Daroussin 214*61d06d6bSBaptiste Daroussin /* 215*61d06d6bSBaptiste Daroussin * Add an additional name to an existing page. 216*61d06d6bSBaptiste Daroussin */ 217*61d06d6bSBaptiste Daroussin void 218*61d06d6bSBaptiste Daroussin dba_page_alias(struct dba_array *page, const char *name, uint64_t mask) 219*61d06d6bSBaptiste Daroussin { 220*61d06d6bSBaptiste Daroussin struct dba_array *entries; 221*61d06d6bSBaptiste Daroussin char *entry; 222*61d06d6bSBaptiste Daroussin char maskbyte; 223*61d06d6bSBaptiste Daroussin 224*61d06d6bSBaptiste Daroussin if (*name == '\0') 225*61d06d6bSBaptiste Daroussin return; 226*61d06d6bSBaptiste Daroussin maskbyte = mask & NAME_MASK; 227*61d06d6bSBaptiste Daroussin entries = dba_array_get(page, DBP_NAME); 228*61d06d6bSBaptiste Daroussin dba_array_FOREACH(entries, entry) { 229*61d06d6bSBaptiste Daroussin if (strcmp(entry + 1, name) == 0) { 230*61d06d6bSBaptiste Daroussin *entry |= maskbyte; 231*61d06d6bSBaptiste Daroussin return; 232*61d06d6bSBaptiste Daroussin } 233*61d06d6bSBaptiste Daroussin } 234*61d06d6bSBaptiste Daroussin dba_array_add(entries, prepend(name, maskbyte)); 235*61d06d6bSBaptiste Daroussin } 236*61d06d6bSBaptiste Daroussin 237*61d06d6bSBaptiste Daroussin /* 238*61d06d6bSBaptiste Daroussin * Return a pointer to a temporary copy of instr with inbyte prepended. 239*61d06d6bSBaptiste Daroussin */ 240*61d06d6bSBaptiste Daroussin static void * 241*61d06d6bSBaptiste Daroussin prepend(const char *instr, char inbyte) 242*61d06d6bSBaptiste Daroussin { 243*61d06d6bSBaptiste Daroussin static char *outstr = NULL; 244*61d06d6bSBaptiste Daroussin static size_t outlen = 0; 245*61d06d6bSBaptiste Daroussin size_t newlen; 246*61d06d6bSBaptiste Daroussin 247*61d06d6bSBaptiste Daroussin newlen = strlen(instr) + 1; 248*61d06d6bSBaptiste Daroussin if (newlen > outlen) { 249*61d06d6bSBaptiste Daroussin outstr = mandoc_realloc(outstr, newlen + 1); 250*61d06d6bSBaptiste Daroussin outlen = newlen; 251*61d06d6bSBaptiste Daroussin } 252*61d06d6bSBaptiste Daroussin *outstr = inbyte; 253*61d06d6bSBaptiste Daroussin memcpy(outstr + 1, instr, newlen); 254*61d06d6bSBaptiste Daroussin return outstr; 255*61d06d6bSBaptiste Daroussin } 256*61d06d6bSBaptiste Daroussin 257*61d06d6bSBaptiste Daroussin /* 258*61d06d6bSBaptiste Daroussin * Write the pages table to disk; the format is: 259*61d06d6bSBaptiste Daroussin * - One integer containing the number of pages. 260*61d06d6bSBaptiste Daroussin * - For each page, five pointers to the names, sections, 261*61d06d6bSBaptiste Daroussin * architectures, description, and file names of the page. 262*61d06d6bSBaptiste Daroussin * MI pages write 0 instead of the architecture pointer. 263*61d06d6bSBaptiste Daroussin * - One list each for names, sections, architectures, descriptions and 264*61d06d6bSBaptiste Daroussin * file names. The description for each page ends with a NUL byte. 265*61d06d6bSBaptiste Daroussin * For all the other lists, each string ends with a NUL byte, 266*61d06d6bSBaptiste Daroussin * and the last string for a page ends with two NUL bytes. 267*61d06d6bSBaptiste Daroussin * - To assure alignment of following integers, 268*61d06d6bSBaptiste Daroussin * the end is padded with NUL bytes up to a multiple of four bytes. 269*61d06d6bSBaptiste Daroussin */ 270*61d06d6bSBaptiste Daroussin static void 271*61d06d6bSBaptiste Daroussin dba_pages_write(struct dba_array *pages) 272*61d06d6bSBaptiste Daroussin { 273*61d06d6bSBaptiste Daroussin struct dba_array *page, *entry; 274*61d06d6bSBaptiste Daroussin int32_t pos_pages, pos_end; 275*61d06d6bSBaptiste Daroussin 276*61d06d6bSBaptiste Daroussin pos_pages = dba_array_writelen(pages, 5); 277*61d06d6bSBaptiste Daroussin dba_array_FOREACH(pages, page) { 278*61d06d6bSBaptiste Daroussin dba_array_setpos(page, DBP_NAME, dba_tell()); 279*61d06d6bSBaptiste Daroussin entry = dba_array_get(page, DBP_NAME); 280*61d06d6bSBaptiste Daroussin dba_array_sort(entry, compare_names); 281*61d06d6bSBaptiste Daroussin dba_array_writelst(entry); 282*61d06d6bSBaptiste Daroussin } 283*61d06d6bSBaptiste Daroussin dba_array_FOREACH(pages, page) { 284*61d06d6bSBaptiste Daroussin dba_array_setpos(page, DBP_SECT, dba_tell()); 285*61d06d6bSBaptiste Daroussin entry = dba_array_get(page, DBP_SECT); 286*61d06d6bSBaptiste Daroussin dba_array_sort(entry, compare_strings); 287*61d06d6bSBaptiste Daroussin dba_array_writelst(entry); 288*61d06d6bSBaptiste Daroussin } 289*61d06d6bSBaptiste Daroussin dba_array_FOREACH(pages, page) { 290*61d06d6bSBaptiste Daroussin if ((entry = dba_array_get(page, DBP_ARCH)) != NULL) { 291*61d06d6bSBaptiste Daroussin dba_array_setpos(page, DBP_ARCH, dba_tell()); 292*61d06d6bSBaptiste Daroussin dba_array_sort(entry, compare_strings); 293*61d06d6bSBaptiste Daroussin dba_array_writelst(entry); 294*61d06d6bSBaptiste Daroussin } else 295*61d06d6bSBaptiste Daroussin dba_array_setpos(page, DBP_ARCH, 0); 296*61d06d6bSBaptiste Daroussin } 297*61d06d6bSBaptiste Daroussin dba_array_FOREACH(pages, page) { 298*61d06d6bSBaptiste Daroussin dba_array_setpos(page, DBP_DESC, dba_tell()); 299*61d06d6bSBaptiste Daroussin dba_str_write(dba_array_get(page, DBP_DESC)); 300*61d06d6bSBaptiste Daroussin } 301*61d06d6bSBaptiste Daroussin dba_array_FOREACH(pages, page) { 302*61d06d6bSBaptiste Daroussin dba_array_setpos(page, DBP_FILE, dba_tell()); 303*61d06d6bSBaptiste Daroussin dba_array_writelst(dba_array_get(page, DBP_FILE)); 304*61d06d6bSBaptiste Daroussin } 305*61d06d6bSBaptiste Daroussin pos_end = dba_align(); 306*61d06d6bSBaptiste Daroussin dba_seek(pos_pages); 307*61d06d6bSBaptiste Daroussin dba_array_FOREACH(pages, page) 308*61d06d6bSBaptiste Daroussin dba_array_writepos(page); 309*61d06d6bSBaptiste Daroussin dba_seek(pos_end); 310*61d06d6bSBaptiste Daroussin } 311*61d06d6bSBaptiste Daroussin 312*61d06d6bSBaptiste Daroussin static int 313*61d06d6bSBaptiste Daroussin compare_names(const void *vp1, const void *vp2) 314*61d06d6bSBaptiste Daroussin { 315*61d06d6bSBaptiste Daroussin const char *cp1, *cp2; 316*61d06d6bSBaptiste Daroussin int diff; 317*61d06d6bSBaptiste Daroussin 318*61d06d6bSBaptiste Daroussin cp1 = *(const char * const *)vp1; 319*61d06d6bSBaptiste Daroussin cp2 = *(const char * const *)vp2; 320*61d06d6bSBaptiste Daroussin return (diff = *cp2 - *cp1) ? diff : 321*61d06d6bSBaptiste Daroussin strcasecmp(cp1 + 1, cp2 + 1); 322*61d06d6bSBaptiste Daroussin } 323*61d06d6bSBaptiste Daroussin 324*61d06d6bSBaptiste Daroussin static int 325*61d06d6bSBaptiste Daroussin compare_strings(const void *vp1, const void *vp2) 326*61d06d6bSBaptiste Daroussin { 327*61d06d6bSBaptiste Daroussin const char *cp1, *cp2; 328*61d06d6bSBaptiste Daroussin 329*61d06d6bSBaptiste Daroussin cp1 = *(const char * const *)vp1; 330*61d06d6bSBaptiste Daroussin cp2 = *(const char * const *)vp2; 331*61d06d6bSBaptiste Daroussin return strcmp(cp1, cp2); 332*61d06d6bSBaptiste Daroussin } 333*61d06d6bSBaptiste Daroussin 334*61d06d6bSBaptiste Daroussin /*** functions for handling macros ************************************/ 335*61d06d6bSBaptiste Daroussin 336*61d06d6bSBaptiste Daroussin /* 337*61d06d6bSBaptiste Daroussin * In the hash table for a single macro, look up an entry by 338*61d06d6bSBaptiste Daroussin * the macro value or add an empty one if it doesn't exist yet. 339*61d06d6bSBaptiste Daroussin */ 340*61d06d6bSBaptiste Daroussin static struct macro_entry * 341*61d06d6bSBaptiste Daroussin get_macro_entry(struct ohash *macro, const char *value, int32_t np) 342*61d06d6bSBaptiste Daroussin { 343*61d06d6bSBaptiste Daroussin struct macro_entry *entry; 344*61d06d6bSBaptiste Daroussin size_t len; 345*61d06d6bSBaptiste Daroussin unsigned int slot; 346*61d06d6bSBaptiste Daroussin 347*61d06d6bSBaptiste Daroussin slot = ohash_qlookup(macro, value); 348*61d06d6bSBaptiste Daroussin if ((entry = ohash_find(macro, slot)) == NULL) { 349*61d06d6bSBaptiste Daroussin len = strlen(value) + 1; 350*61d06d6bSBaptiste Daroussin entry = mandoc_malloc(sizeof(*entry) + len); 351*61d06d6bSBaptiste Daroussin memcpy(&entry->value, value, len); 352*61d06d6bSBaptiste Daroussin entry->pages = dba_array_new(np, DBA_GROW); 353*61d06d6bSBaptiste Daroussin ohash_insert(macro, slot, entry); 354*61d06d6bSBaptiste Daroussin } 355*61d06d6bSBaptiste Daroussin return entry; 356*61d06d6bSBaptiste Daroussin } 357*61d06d6bSBaptiste Daroussin 358*61d06d6bSBaptiste Daroussin /* 359*61d06d6bSBaptiste Daroussin * In addition to get_macro_entry(), add multiple page references, 360*61d06d6bSBaptiste Daroussin * converting them from the on-disk format (byte offsets in the file) 361*61d06d6bSBaptiste Daroussin * to page pointers in memory. 362*61d06d6bSBaptiste Daroussin */ 363*61d06d6bSBaptiste Daroussin void 364*61d06d6bSBaptiste Daroussin dba_macro_new(struct dba *dba, int32_t im, const char *value, 365*61d06d6bSBaptiste Daroussin const int32_t *pp) 366*61d06d6bSBaptiste Daroussin { 367*61d06d6bSBaptiste Daroussin struct macro_entry *entry; 368*61d06d6bSBaptiste Daroussin const int32_t *ip; 369*61d06d6bSBaptiste Daroussin int32_t np; 370*61d06d6bSBaptiste Daroussin 371*61d06d6bSBaptiste Daroussin np = 0; 372*61d06d6bSBaptiste Daroussin for (ip = pp; *ip; ip++) 373*61d06d6bSBaptiste Daroussin np++; 374*61d06d6bSBaptiste Daroussin 375*61d06d6bSBaptiste Daroussin entry = get_macro_entry(dba_array_get(dba->macros, im), value, np); 376*61d06d6bSBaptiste Daroussin for (ip = pp; *ip; ip++) 377*61d06d6bSBaptiste Daroussin dba_array_add(entry->pages, dba_array_get(dba->pages, 378*61d06d6bSBaptiste Daroussin be32toh(*ip) / 5 / sizeof(*ip) - 1)); 379*61d06d6bSBaptiste Daroussin } 380*61d06d6bSBaptiste Daroussin 381*61d06d6bSBaptiste Daroussin /* 382*61d06d6bSBaptiste Daroussin * In addition to get_macro_entry(), add one page reference, 383*61d06d6bSBaptiste Daroussin * directly taking the in-memory page pointer as an argument. 384*61d06d6bSBaptiste Daroussin */ 385*61d06d6bSBaptiste Daroussin void 386*61d06d6bSBaptiste Daroussin dba_macro_add(struct dba_array *macros, int32_t im, const char *value, 387*61d06d6bSBaptiste Daroussin struct dba_array *page) 388*61d06d6bSBaptiste Daroussin { 389*61d06d6bSBaptiste Daroussin struct macro_entry *entry; 390*61d06d6bSBaptiste Daroussin 391*61d06d6bSBaptiste Daroussin if (*value == '\0') 392*61d06d6bSBaptiste Daroussin return; 393*61d06d6bSBaptiste Daroussin entry = get_macro_entry(dba_array_get(macros, im), value, 1); 394*61d06d6bSBaptiste Daroussin dba_array_add(entry->pages, page); 395*61d06d6bSBaptiste Daroussin } 396*61d06d6bSBaptiste Daroussin 397*61d06d6bSBaptiste Daroussin /* 398*61d06d6bSBaptiste Daroussin * Write the macros table to disk; the format is: 399*61d06d6bSBaptiste Daroussin * - The number of macro tables (actually, MACRO_MAX). 400*61d06d6bSBaptiste Daroussin * - That number of pointers to the individual macro tables. 401*61d06d6bSBaptiste Daroussin * - The individual macro tables. 402*61d06d6bSBaptiste Daroussin */ 403*61d06d6bSBaptiste Daroussin static void 404*61d06d6bSBaptiste Daroussin dba_macros_write(struct dba_array *macros) 405*61d06d6bSBaptiste Daroussin { 406*61d06d6bSBaptiste Daroussin struct ohash *macro; 407*61d06d6bSBaptiste Daroussin int32_t im, pos_macros, pos_end; 408*61d06d6bSBaptiste Daroussin 409*61d06d6bSBaptiste Daroussin pos_macros = dba_array_writelen(macros, 1); 410*61d06d6bSBaptiste Daroussin im = 0; 411*61d06d6bSBaptiste Daroussin dba_array_FOREACH(macros, macro) { 412*61d06d6bSBaptiste Daroussin dba_array_setpos(macros, im++, dba_tell()); 413*61d06d6bSBaptiste Daroussin dba_macro_write(macro); 414*61d06d6bSBaptiste Daroussin } 415*61d06d6bSBaptiste Daroussin pos_end = dba_tell(); 416*61d06d6bSBaptiste Daroussin dba_seek(pos_macros); 417*61d06d6bSBaptiste Daroussin dba_array_writepos(macros); 418*61d06d6bSBaptiste Daroussin dba_seek(pos_end); 419*61d06d6bSBaptiste Daroussin } 420*61d06d6bSBaptiste Daroussin 421*61d06d6bSBaptiste Daroussin /* 422*61d06d6bSBaptiste Daroussin * Write one individual macro table to disk; the format is: 423*61d06d6bSBaptiste Daroussin * - The number of entries in the table. 424*61d06d6bSBaptiste Daroussin * - For each entry, two pointers, the first one to the value 425*61d06d6bSBaptiste Daroussin * and the second one to the list of pages. 426*61d06d6bSBaptiste Daroussin * - A list of values, each ending in a NUL byte. 427*61d06d6bSBaptiste Daroussin * - To assure alignment of following integers, 428*61d06d6bSBaptiste Daroussin * padding with NUL bytes up to a multiple of four bytes. 429*61d06d6bSBaptiste Daroussin * - A list of pointers to pages, each list ending in a 0 integer. 430*61d06d6bSBaptiste Daroussin */ 431*61d06d6bSBaptiste Daroussin static void 432*61d06d6bSBaptiste Daroussin dba_macro_write(struct ohash *macro) 433*61d06d6bSBaptiste Daroussin { 434*61d06d6bSBaptiste Daroussin struct macro_entry **entries, *entry; 435*61d06d6bSBaptiste Daroussin struct dba_array *page; 436*61d06d6bSBaptiste Daroussin int32_t *kpos, *dpos; 437*61d06d6bSBaptiste Daroussin unsigned int ie, ne, slot; 438*61d06d6bSBaptiste Daroussin int use; 439*61d06d6bSBaptiste Daroussin int32_t addr, pos_macro, pos_end; 440*61d06d6bSBaptiste Daroussin 441*61d06d6bSBaptiste Daroussin /* Temporary storage for filtering and sorting. */ 442*61d06d6bSBaptiste Daroussin 443*61d06d6bSBaptiste Daroussin ne = ohash_entries(macro); 444*61d06d6bSBaptiste Daroussin entries = mandoc_reallocarray(NULL, ne, sizeof(*entries)); 445*61d06d6bSBaptiste Daroussin kpos = mandoc_reallocarray(NULL, ne, sizeof(*kpos)); 446*61d06d6bSBaptiste Daroussin dpos = mandoc_reallocarray(NULL, ne, sizeof(*dpos)); 447*61d06d6bSBaptiste Daroussin 448*61d06d6bSBaptiste Daroussin /* Build a list of non-empty entries and sort it. */ 449*61d06d6bSBaptiste Daroussin 450*61d06d6bSBaptiste Daroussin ne = 0; 451*61d06d6bSBaptiste Daroussin for (entry = ohash_first(macro, &slot); entry != NULL; 452*61d06d6bSBaptiste Daroussin entry = ohash_next(macro, &slot)) { 453*61d06d6bSBaptiste Daroussin use = 0; 454*61d06d6bSBaptiste Daroussin dba_array_FOREACH(entry->pages, page) 455*61d06d6bSBaptiste Daroussin if (dba_array_getpos(page)) 456*61d06d6bSBaptiste Daroussin use = 1; 457*61d06d6bSBaptiste Daroussin if (use) 458*61d06d6bSBaptiste Daroussin entries[ne++] = entry; 459*61d06d6bSBaptiste Daroussin } 460*61d06d6bSBaptiste Daroussin qsort(entries, ne, sizeof(*entries), compare_entries); 461*61d06d6bSBaptiste Daroussin 462*61d06d6bSBaptiste Daroussin /* Number of entries, and space for the pointer pairs. */ 463*61d06d6bSBaptiste Daroussin 464*61d06d6bSBaptiste Daroussin dba_int_write(ne); 465*61d06d6bSBaptiste Daroussin pos_macro = dba_skip(2, ne); 466*61d06d6bSBaptiste Daroussin 467*61d06d6bSBaptiste Daroussin /* String table. */ 468*61d06d6bSBaptiste Daroussin 469*61d06d6bSBaptiste Daroussin for (ie = 0; ie < ne; ie++) { 470*61d06d6bSBaptiste Daroussin kpos[ie] = dba_tell(); 471*61d06d6bSBaptiste Daroussin dba_str_write(entries[ie]->value); 472*61d06d6bSBaptiste Daroussin } 473*61d06d6bSBaptiste Daroussin dba_align(); 474*61d06d6bSBaptiste Daroussin 475*61d06d6bSBaptiste Daroussin /* Pages table. */ 476*61d06d6bSBaptiste Daroussin 477*61d06d6bSBaptiste Daroussin for (ie = 0; ie < ne; ie++) { 478*61d06d6bSBaptiste Daroussin dpos[ie] = dba_tell(); 479*61d06d6bSBaptiste Daroussin dba_array_FOREACH(entries[ie]->pages, page) 480*61d06d6bSBaptiste Daroussin if ((addr = dba_array_getpos(page))) 481*61d06d6bSBaptiste Daroussin dba_int_write(addr); 482*61d06d6bSBaptiste Daroussin dba_int_write(0); 483*61d06d6bSBaptiste Daroussin } 484*61d06d6bSBaptiste Daroussin pos_end = dba_tell(); 485*61d06d6bSBaptiste Daroussin 486*61d06d6bSBaptiste Daroussin /* Fill in the pointer pairs. */ 487*61d06d6bSBaptiste Daroussin 488*61d06d6bSBaptiste Daroussin dba_seek(pos_macro); 489*61d06d6bSBaptiste Daroussin for (ie = 0; ie < ne; ie++) { 490*61d06d6bSBaptiste Daroussin dba_int_write(kpos[ie]); 491*61d06d6bSBaptiste Daroussin dba_int_write(dpos[ie]); 492*61d06d6bSBaptiste Daroussin } 493*61d06d6bSBaptiste Daroussin dba_seek(pos_end); 494*61d06d6bSBaptiste Daroussin 495*61d06d6bSBaptiste Daroussin free(entries); 496*61d06d6bSBaptiste Daroussin free(kpos); 497*61d06d6bSBaptiste Daroussin free(dpos); 498*61d06d6bSBaptiste Daroussin } 499*61d06d6bSBaptiste Daroussin 500*61d06d6bSBaptiste Daroussin static int 501*61d06d6bSBaptiste Daroussin compare_entries(const void *vp1, const void *vp2) 502*61d06d6bSBaptiste Daroussin { 503*61d06d6bSBaptiste Daroussin const struct macro_entry *ep1, *ep2; 504*61d06d6bSBaptiste Daroussin 505*61d06d6bSBaptiste Daroussin ep1 = *(const struct macro_entry * const *)vp1; 506*61d06d6bSBaptiste Daroussin ep2 = *(const struct macro_entry * const *)vp2; 507*61d06d6bSBaptiste Daroussin return strcmp(ep1->value, ep2->value); 508*61d06d6bSBaptiste Daroussin } 509