2 * Copyright (c) 1992, Brian Berliner
4 * You may distribute under the terms of the GNU General Public License as
5 * specified in the README file that comes with the CVS source distribution.
7 * A simple ndbm-emulator for CVS. It parses a text file of the format:
11 * at dbm_open time, and loads the entire file into memory. As such, it is
12 * probably only good for fairly small modules files. Ours is about 30K in
13 * size, and this code works fine.
22 static void mydbm_load_file PROTO ((FILE *, List *));
24 /* Returns NULL on error in which case errno has been set to indicate
25 the error. Can also call error() itself. */
28 mydbm_open (file, flags, mode)
36 fp = CVS_FOPEN (file, FOPEN_BINARY_READ);
37 if (fp == NULL && !(existence_error (errno) && (flags & O_CREAT)))
40 db = (DBM *) xmalloc (sizeof (*db));
41 db->dbm_list = getlist ();
43 db->name = xstrdup (file);
47 mydbm_load_file (fp, db->dbm_list);
49 error (0, errno, "cannot close %s", file);
54 static int write_item PROTO ((Node *, void *));
57 write_item (node, data)
61 FILE *fp = (FILE *)data;
62 fputs (node->key, fp);
64 fputs (node->data, fp);
76 fp = CVS_FOPEN (db->name, FOPEN_BINARY_WRITE);
78 error (1, errno, "cannot write %s", db->name);
79 walklist (db->dbm_list, write_item, (void *)fp);
81 error (0, errno, "cannot close %s", db->name);
84 dellist (&db->dbm_list);
97 /* make sure it's null-terminated */
98 s = xmalloc (key.dsize + 1);
99 (void) strncpy (s, key.dptr, key.dsize);
102 p = findnode (db->dbm_list, s);
106 val.dsize = strlen (p->data);
110 val.dptr = (char *) NULL;
124 head = db->dbm_list->list;
129 key.dsize = strlen (p->key);
133 key.dptr = (char *) NULL;
136 db->dbm_next = p->next;
147 head = db->dbm_list->list;
152 key.dsize = strlen (p->key);
156 key.dptr = (char *) NULL;
159 db->dbm_next = p->next;
163 /* Note: only updates the in-memory copy, which is written out at
164 mydbm_close time. Note: Also differs from DBM in that on duplication,
165 it gives a warning, rather than either DBM_INSERT or DBM_REPLACE
168 mydbm_store (db, key, value, flags)
177 node->type = NDBMNODE;
179 node->key = xmalloc (key.dsize + 1);
180 strncpy (node->key, key.dptr, key.dsize);
181 node->key[key.dsize] = '\0';
183 node->data = xmalloc (value.dsize + 1);
184 strncpy (node->data, value.dptr, value.dsize);
185 node->data[value.dsize] = '\0';
188 if (addnode (db->dbm_list, node) == -1)
190 error (0, 0, "attempt to insert duplicate key `%s'", node->key);
198 mydbm_load_file (fp, list)
205 size_t value_allocated;
211 value = xmalloc (value_allocated);
214 while ((line_length = getstr (&line, &line_size, fp, '\012', 0)) >= 0)
216 if (line_length > 0 && line[line_length - 1] == '\012')
218 /* Strip the newline. */
220 line[line_length] = '\0';
222 if (line_length > 0 && line[line_length - 1] == '\015')
224 /* If the file (e.g. modules) was written on an NT box, it will
225 contain CRLF at the ends of lines. Strip them (we can't do
226 this by opening the file in text mode because we might be
229 line[line_length] = '\0';
233 * Add the line to the value, at the end if this is a continuation
234 * line; otherwise at the beginning, but only after any trailing
235 * backslash is removed.
241 * See if the line we read is a continuation line, and strip the
245 cp = &line[line_length - 1];
258 expand_string (&value,
260 strlen (value) + line_length + 5);
261 strcat (value, line);
264 continue; /* comment line */
266 while (*vp && isspace (*vp))
269 continue; /* empty line */
272 * If this was not a continuation line, add the entry to the database
276 Node *p = getnode ();
280 while (*vp && !isspace (*vp))
282 *vp++ = '\0'; /* NULL terminate the key */
284 p->key = xstrdup (kp);
285 while (*vp && isspace (*vp))
286 vp++; /* skip whitespace to value */
289 error (0, 0, "warning: NULL value for key `%s'", p->key);
293 p->data = xstrdup (vp);
294 if (addnode (list, p) == -1)
296 error (0, 0, "duplicate key found for `%s'", p->key);
301 if (line_length < 0 && !feof (fp))
302 /* FIXME: should give the name of the file. */
303 error (0, errno, "cannot read file in mydbm_load_file");