1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
|
/*
* db_store.c: dbstore(), database storage routine.
*
* Copyright (C), 1994, 1995, Graeme W. Wilford. (Wilf.)
*
* You may distribute under the terms of the GNU Library General Public
* License as specified in the file COPYING.LIB that comes with this
* distribution.
*
* Mon Aug 8 20:35:30 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk)
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif /* HAVE_CONFIG_H */
#include <stdio.h>
#include <assert.h>
#if defined(STDC_HEADERS)
#include <string.h>
#include <stdlib.h>
#elif defined(HAVE_STRING_H)
#include <string.h>
#elif defined(HAVE_STRINGS_H)
#include <strings.h>
#else /* no string(s) header file */
extern char *strtok();
extern char *strsep();
#endif /* STDC_HEADERS */
#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#ifndef STDC_HEADERS
extern long atol();
extern char *strsep();
#endif /* not STDC_HEADERS */
#define NLS_SET db_storeSet
#include <libintl.h>
#define _(String) gettext (String)
#include "manconfig.h"
#include "lib/error.h"
#include "mydbm.h"
#include "db_storage.h"
/* deal with situation where we cannot insert an unused key */
static void gripe_insert_unused(char *data)
{
error (0, 0,
_( "cannot insert unused key %s"),
data);
gripe_corrupt_data();
}
/* The do_we_replace logic */
static int replace_if_necessary(struct mandata *in, struct mandata *info,
datum newkey, datum newcont)
{
#ifndef FAVOUR_STRAYCATS
if (in->id < info->id) {
#else /* FAVOUR_STRAYCATS */
if (in->id < info->id ||
(in->id == STRAY_CAT && info->id == WHATIS_MAN)) {
#endif /* !FAVOUR_STRAYCATS */
if (MYDBM_REPLACE(dbf, newkey, newcont))
gripe_replace_key(newkey.dptr);
} else if (in->id == info->id)
if (debug)
fprintf(stderr,
"ignoring identical multi key: %s\n",
newkey.dptr);
if (in->id == info->id &&
in->id == ULT_MAN) {
if (strcmp(in->comp ? in->comp : "-", info->comp) == 0) {
if (in->_st_mtime != info->_st_mtime) {
if (debug)
fprintf(stderr, "replace_if_necessary(): replace\n");
if (MYDBM_REPLACE(dbf, newkey, newcont))
gripe_replace_key(newkey.dptr);
}
return 0; /* same file */
} else
return 1; /* differing ext's */
}
return 0; /* not physical file anyway */
}
/*
Any one of three situations can occur when storing some data.
1) no simple key is found.
store as singular reference.
2) simple key already exists, content starts with a '\t'.
Already multiple reference. Add our new item in multiple format
and update the simple key content, to point to our new one also.
3) simple key already exists, content does not start with a '\t'.
First we have to reformat the simple key into a multi key for the
old item, and insert. Then we have to insert the new data as a
multi key. Lastly we must create the simple key and do a replace
on it.
Use precedence algorithm on inserts. If we already have a key assigned
to the new value, check priority of page using id. If new page is higher
(lower value), replace old with new, otherwise ignore new page.
If we have two ULT_MAN pages competing for the same key, we must have
more than one of foo.sec, foo.sec.comp1, foo.sec.comp2. OR we have a
replacement page. If the st_mtimes differ, throw out the old struct and
replace it with the new, if the comp exts differ, oops, this is bad,
keep one and return appropriate error code.
If we have two WHATIS_MAN pages or a WHATIS_MAN and a SO_MAN page
competing for the same key, don't worry. This will happen a lot and is
not a problem.
return errorcode or 0 on success.
*/
#ifndef FAST_BTREE
int dbstore(struct mandata *in, char *basename)
{
datum oldkey, oldcont;
/* create a simple key */
oldkey.dsize = strlen(basename) + 1;
if (oldkey.dsize == 1) {
if (debug)
dbprintf(in);
return 2;
}
oldkey.dptr = basename;
/* get the content for the simple key */
oldcont = MYDBM_FETCH(dbf, oldkey);
if (oldcont.dptr == NULL) { /* situation (1) */
oldcont = make_content(in);
if (MYDBM_INSERT(dbf, oldkey, oldcont))
gripe_insert_unused(oldkey.dptr);
free(oldcont.dptr);
} else if (*oldcont.dptr == '\t') { /* situation (2) */
datum newkey, newcont;
newkey = make_multi_key(oldkey.dptr, 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(oldcont.dptr);
cont = MYDBM_FETCH(dbf, newkey);
split_content(cont.dptr, &info);
ret = replace_if_necessary(in, &info, newkey, newcont);
/* MYDBM_FREE(cont.dptr); */
free(info.addr);
free(newkey.dptr);
free(newcont.dptr);
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
oldcont.dptr otherwise (for NDBM only!) */
free(newkey.dptr);
free(newcont.dptr);
newcont.dsize = oldcont.dsize + strlen(in->ext) + 1;
newcont.dptr = (char *) xmalloc(newcont.dsize);
sprintf(newcont.dptr, "%s\t%s", oldcont.dptr, in->ext);
MYDBM_FREE(oldcont.dptr);
/* Try to replace the old simple data with the new stuff */
if (MYDBM_REPLACE(dbf, oldkey, newcont))
gripe_replace_key(oldkey.dptr);
free(newcont.dptr);
} else { /* situation (3) */
datum newkey, newcont, lastkey, lastcont;
struct mandata old;
/* Extract the old singular reference */
split_content(oldcont.dptr, &old);
/* Create multi keys for both
and new items, create new content */
lastkey = make_multi_key(oldkey.dptr, old.ext);
newkey = make_multi_key(oldkey.dptr, in->ext);
newcont = make_content(in);
/* Check against identical multi keys before inserting
into db */
if (strcmp(lastkey.dptr, newkey.dptr) == 0) {
int ret;
ret = replace_if_necessary(in, &old, oldkey, newcont);
/* MYDBM_FREE(oldcont.dptr); */
free(old.addr);
free(newcont.dptr);
free(newkey.dptr);
free(lastkey.dptr);
return ret;
}
lastcont = make_content(&old);
if (MYDBM_INSERT(dbf, lastkey, lastcont))
gripe_insert_unused(lastkey.dptr);
free(lastkey.dptr);
free(lastcont.dptr);
if (MYDBM_INSERT(dbf, newkey, newcont))
gripe_insert_unused(newkey.dptr);
free(newkey.dptr);
free(newcont.dptr);
/* Now build a simple reference to the above two items */
newcont.dsize = strlen(old.ext) + strlen(in->ext) + 3;
newcont.dptr = (char *) xmalloc (newcont.dsize);
sprintf(newcont.dptr, "\t%s\t%s", old.ext, in->ext);
if (MYDBM_REPLACE(dbf, oldkey, newcont))
gripe_replace_key(oldkey.dptr);
/* MYDBM_FREE(oldcont.dptr); */
free(old.addr);
free(newcont.dptr);
}
return 0;
}
#endif /* !FAST_BTREE */
|