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.
21 # define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
22 # endif /* defined O_ACCMODE */
24 static void mydbm_load_file (FILE *, List *, char *);
26 /* Returns NULL on error in which case errno has been set to indicate
27 the error. Can also call error() itself. */
30 mydbm_open (char *file, int flags, int mode)
35 fp = CVS_FOPEN (file, (flags & O_ACCMODE) != O_RDONLY
36 ? FOPEN_BINARY_READWRITE : FOPEN_BINARY_READ);
37 if (fp == NULL && !(existence_error (errno) && (flags & O_CREAT)))
40 db = xmalloc (sizeof (*db));
41 db->dbm_list = getlist ();
43 db->name = xstrdup (file);
47 mydbm_load_file (fp, db->dbm_list, file);
49 error (0, errno, "cannot close %s",
50 primary_root_inverse_translate (file));
58 write_item (Node *node, void *data)
61 fputs (node->key, fp);
63 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, fp);
81 error (0, errno, "cannot close %s", db->name);
84 dellist (&db->dbm_list);
91 mydbm_fetch (DBM *db, datum key)
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);
120 mydbm_firstkey (DBM *db)
125 head = db->dbm_list->list;
130 key.dsize = strlen (p->key);
137 db->dbm_next = p->next;
144 mydbm_nextkey (DBM *db)
149 head = db->dbm_list->list;
154 key.dsize = strlen (p->key);
158 key.dptr = (char *) NULL;
161 db->dbm_next = p->next;
167 /* Note: only updates the in-memory copy, which is written out at
168 mydbm_close time. Note: Also differs from DBM in that on duplication,
169 it gives a warning, rather than either DBM_INSERT or DBM_REPLACE
172 mydbm_store (DBM *db, datum key, datum value, int flags)
177 node->type = NDBMNODE;
179 node->key = xmalloc (key.dsize + 1);
181 strncat (node->key, key.dptr, key.dsize);
183 node->data = xmalloc (value.dsize + 1);
184 *(char *)node->data = '\0';
185 strncat (node->data, value.dptr, value.dsize);
188 if (addnode (db->dbm_list, node) == -1)
190 error (0, 0, "attempt to insert duplicate key `%s'", node->key);
202 * filename Used in error messages.
205 mydbm_load_file (FILE *fp, List *list, char *filename)
210 size_t value_allocated;
217 value = xmalloc (value_allocated);
221 while ((line_length = getdelim (&line, &line_size, '\012', fp)) >= 0)
224 if (line_length > 0 && line[line_length - 1] == '\012')
226 /* Strip the newline. */
228 line[line_length] = '\0';
230 if (line_length > 0 && line[line_length - 1] == '\015')
232 /* If the file (e.g. modules) was written on an NT box, it will
233 contain CRLF at the ends of lines. Strip them (we can't do
234 this by opening the file in text mode because we might be
237 line[line_length] = '\0';
241 * Add the line to the value, at the end if this is a continuation
242 * line; otherwise at the beginning, but only after any trailing
243 * backslash is removed.
249 * See if the line we read is a continuation line, and strip the
253 cp = &line[line_length - 1];
266 expand_string (&value,
268 strlen (value) + line_length + 5);
269 strcat (value, line);
272 continue; /* comment line */
274 while (*vp && isspace ((unsigned char) *vp))
277 continue; /* empty line */
280 * If this was not a continuation line, add the entry to the database
284 Node *p = getnode ();
288 while (*vp && !isspace ((unsigned char) *vp))
291 *vp++ = '\0'; /* NULL terminate the key */
293 p->key = xstrdup (kp);
294 while (*vp && isspace ((unsigned char) *vp))
295 vp++; /* skip whitespace to value */
300 "warning: NULL value for key `%s' at line %d of `%s'",
302 primary_root_inverse_translate (filename));
306 p->data = xstrdup (vp);
307 if (addnode (list, p) == -1)
311 "duplicate key found for `%s' at line %d of `%s'",
313 primary_root_inverse_translate (filename));
318 if (line_length < 0 && !feof (fp))
319 error (0, errno, "cannot read file `%s' in mydbm_load_file",
320 primary_root_inverse_translate (filename));