int dbdelete (MYDBM_FILE dbf, const char *name, struct mandata *info) { datum key, cont; memset (&key, 0, sizeof key); memset (&cont, 0, sizeof cont); /* get entry for info */ debug ("Attempting delete of %s(%s) entry.\n", name, info->ext); MYDBM_SET (key, name_to_key (name)); cont = MYDBM_FETCH (dbf, key); if (!MYDBM_DPTR (cont)) { /* 0 entries */ MYDBM_FREE_DPTR (key); return NO_ENTRY; } else if (*MYDBM_DPTR (cont) != '\t') { /* 1 entry */ MYDBM_DELETE (dbf, key); MYDBM_FREE_DPTR (cont); } else { /* 2+ entries */ char **names, **ext; char *multi_content = NULL; datum multi_key; int refs, i, j; /* Extract all of the extensions associated with this key */ refs = list_extensions (MYDBM_DPTR (cont) + 1, &names, &ext); for (i = 0; i < refs; ++i) if (STREQ (names[i], name) && STREQ (ext[i], info->ext)) break; if (i >= refs) { free (names); free (ext); MYDBM_FREE_DPTR (cont); MYDBM_FREE_DPTR (key); return NO_ENTRY; } multi_key = make_multi_key (names[i], ext[i]); if (!MYDBM_EXISTS (dbf, multi_key)) { error (0, 0, _( "multi key %s does not exist"), MYDBM_DPTR (multi_key)); gripe_corrupt_data (); } MYDBM_DELETE (dbf, multi_key); MYDBM_FREE_DPTR (multi_key); /* refs *may* be 1 if all manual pages with this name have been deleted. In this case, we'll have to remove the key too */ if (refs == 1) { free (names); free (ext); MYDBM_FREE_DPTR (cont); MYDBM_DELETE (dbf, key); MYDBM_FREE_DPTR (key); return 0; } /* create our new multi content */ for (j = 0; j < refs; ++j) if (i != j) multi_content = appendstr (multi_content, "\t", names[j], "\t", ext[j], NULL); MYDBM_FREE_DPTR (cont); /* if refs = 2 do something else. Doesn't really matter as the gdbm db file does not shrink any after a deletion anyway */ MYDBM_SET (cont, multi_content); if (MYDBM_REPLACE (dbf, key, cont)) gripe_replace_key (MYDBM_DPTR (key)); free (names); free (ext); } MYDBM_FREE_DPTR (key); return 0; }
int dbstore (struct mandata *in, const char *base) { datum oldkey, oldcont; memset (&oldkey, 0, sizeof oldkey); memset (&oldcont, 0, sizeof oldcont); /* create a simple key */ MYDBM_SET (oldkey, name_to_key (base)); if (!*base) { dbprintf (in); return 2; } if (in->name) { error (0, 0, "in->name (%s) should not be set when calling " "dbstore()!\n", in->name); free (in->name); in->name = NULL; } /* get the content for the simple key */ oldcont = MYDBM_FETCH (dbf, oldkey); if (MYDBM_DPTR (oldcont) == NULL) { /* situation (1) */ if (!STREQ (base, MYDBM_DPTR (oldkey))) in->name = xstrdup (base); oldcont = make_content (in); if (MYDBM_REPLACE (dbf, oldkey, oldcont)) gripe_replace_key (MYDBM_DPTR (oldkey)); free (MYDBM_DPTR (oldcont)); free (in->name); in->name = NULL; } else if (*MYDBM_DPTR (oldcont) == '\t') { /* situation (2) */ datum newkey, newcont; memset (&newkey, 0, sizeof newkey); memset (&newcont, 0, sizeof newcont); newkey = make_multi_key (base, in->ext); newcont = make_content (in); /* Try to insert the new multi data */ if (MYDBM_INSERT (dbf, newkey, newcont)) { datum cont; struct mandata info; int ret; MYDBM_FREE (MYDBM_DPTR (oldcont)); cont = MYDBM_FETCH (dbf, newkey); split_content (MYDBM_DPTR (cont), &info); ret = replace_if_necessary (in, &info, newkey, newcont); /* MYDBM_FREE (MYDBM_DPTR (cont)); */ free_mandata_elements (&info); free (MYDBM_DPTR (newkey)); free (MYDBM_DPTR (newcont)); free (MYDBM_DPTR (oldkey)); return ret; } /* Now lets add some info to the simple key's cont. */ /* This next bit needs to be done first as we'll wipe out MYDBM_DPTR (oldcont) otherwise (for NDBM only!) */ free (MYDBM_DPTR (newkey)); free (MYDBM_DPTR (newcont)); MYDBM_SET (newcont, xasprintf ( "%s\t%s\t%s", MYDBM_DPTR (oldcont), base, in->ext)); MYDBM_FREE (MYDBM_DPTR (oldcont)); /* Try to replace the old simple data with the new stuff */ if (MYDBM_REPLACE (dbf, oldkey, newcont)) gripe_replace_key (MYDBM_DPTR (oldkey)); free (MYDBM_DPTR (newcont)); } else { /* situation (3) */ datum newkey, newcont, lastkey, lastcont; struct mandata old; char *old_name; memset (&newkey, 0, sizeof newkey); memset (&newcont, 0, sizeof newcont); memset (&lastkey, 0, sizeof lastkey); memset (&lastcont, 0, sizeof lastcont); /* Extract the old singular reference */ split_content (MYDBM_DPTR (oldcont), &old); /* Create multi keys for both old and new items, create new content */ if (old.name) old_name = xstrdup (old.name); else old_name = xstrdup (MYDBM_DPTR (oldkey)); lastkey = make_multi_key (old_name, old.ext); /* Check against identical multi keys before inserting into db */ if (STREQ (old_name, base) && STREQ (old.ext, in->ext)) { int ret; if (!STREQ (base, MYDBM_DPTR (oldkey))) in->name = xstrdup (base); newcont = make_content (in); ret = replace_if_necessary (in, &old, oldkey, newcont); /* MYDBM_FREE (MYDBM_DPTR (oldcont)); */ free_mandata_elements (&old); free (MYDBM_DPTR (newcont)); free (MYDBM_DPTR (lastkey)); free (MYDBM_DPTR (oldkey)); free (old_name); free (in->name); in->name = NULL; return ret; } /* Multi keys use the proper case, and so don't need a name * field. */ if (old.name) { free (old.name); old.name = NULL; } lastcont = make_content (&old); /* We always replace here; if the multi key already exists * in the database, then that indicates some kind of * database corruption, but our new multi key is almost * certainly better. */ if (MYDBM_REPLACE (dbf, lastkey, lastcont)) gripe_replace_key (MYDBM_DPTR (lastkey)); free (MYDBM_DPTR (lastkey)); free (MYDBM_DPTR (lastcont)); newkey = make_multi_key (base, in->ext); newcont = make_content (in); if (MYDBM_REPLACE (dbf, newkey, newcont)) gripe_replace_key (MYDBM_DPTR (newkey)); free (MYDBM_DPTR (newkey)); free (MYDBM_DPTR (newcont)); /* Now build a simple reference to the above two items */ MYDBM_SET (newcont, xasprintf ( "\t%s\t%s\t%s\t%s", old_name, old.ext, base, in->ext)); if (MYDBM_REPLACE (dbf, oldkey, newcont)) gripe_replace_key (MYDBM_DPTR (oldkey)); /* MYDBM_FREE (MYDBM_DPTR (oldcont)); */ free_mandata_elements (&old); free (MYDBM_DPTR (newcont)); free (old_name); } free (MYDBM_DPTR (oldkey)); return 0; }