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 # define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
23 # endif /* defined O_ACCMODE */
25 static void mydbm_load_file PROTO ((FILE *, List *, char *));
27 /* Returns NULL on error in which case errno has been set to indicate
28 the error. Can also call error() itself. */
31 mydbm_open (file, flags, mode)
39 fp = CVS_FOPEN (file, (flags & O_ACCMODE) != O_RDONLY ?
40 FOPEN_BINARY_READWRITE : FOPEN_BINARY_READ);
41 if (fp == NULL && !(existence_error (errno) && (flags & O_CREAT)))
44 db = (DBM *) xmalloc (sizeof (*db));
45 db->dbm_list = getlist ();
47 db->name = xstrdup (file);
51 mydbm_load_file (fp, db->dbm_list, file);
53 error (0, errno, "cannot close %s", file);
58 static int write_item PROTO ((Node *, void *));
61 write_item (node, data)
65 FILE *fp = (FILE *)data;
66 fputs (node->key, fp);
68 fputs (node->data, fp);
80 fp = CVS_FOPEN (db->name, FOPEN_BINARY_WRITE);
82 error (1, errno, "cannot write %s", db->name);
83 walklist (db->dbm_list, write_item, (void *)fp);
85 error (0, errno, "cannot close %s", db->name);
88 dellist (&db->dbm_list);
101 /* make sure it's null-terminated */
102 s = xmalloc (key.dsize + 1);
103 (void) strncpy (s, key.dptr, key.dsize);
106 p = findnode (db->dbm_list, s);
110 val.dsize = strlen (p->data);
114 val.dptr = (char *) NULL;
128 head = db->dbm_list->list;
133 key.dsize = strlen (p->key);
137 key.dptr = (char *) NULL;
140 db->dbm_next = p->next;
151 head = db->dbm_list->list;
156 key.dsize = strlen (p->key);
160 key.dptr = (char *) NULL;
163 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 (db, key, value, flags)
181 node->type = NDBMNODE;
183 node->key = xmalloc (key.dsize + 1);
185 strncat (node->key, key.dptr, key.dsize);
187 node->data = xmalloc (value.dsize + 1);
188 *(char *)node->data = '\0';
189 strncat (node->data, value.dptr, value.dsize);
192 if (addnode (db->dbm_list, node) == -1)
194 error (0, 0, "attempt to insert duplicate key `%s'", node->key);
202 mydbm_load_file (fp, list, filename)
205 char *filename; /* Used in error messages. */
210 size_t value_allocated;
217 value = xmalloc (value_allocated);
221 while ((line_length =
222 getstr (&line, &line_size, fp, '\012', 0, GETLINE_NO_LIMIT)) >= 0)
225 if (line_length > 0 && line[line_length - 1] == '\012')
227 /* Strip the newline. */
229 line[line_length] = '\0';
231 if (line_length > 0 && line[line_length - 1] == '\015')
233 /* If the file (e.g. modules) was written on an NT box, it will
234 contain CRLF at the ends of lines. Strip them (we can't do
235 this by opening the file in text mode because we might be
238 line[line_length] = '\0';
242 * Add the line to the value, at the end if this is a continuation
243 * line; otherwise at the beginning, but only after any trailing
244 * backslash is removed.
250 * See if the line we read is a continuation line, and strip the
254 cp = &line[line_length - 1];
267 expand_string (&value,
269 strlen (value) + line_length + 5);
270 strcat (value, line);
273 continue; /* comment line */
275 while (*vp && isspace ((unsigned char) *vp))
278 continue; /* empty line */
281 * If this was not a continuation line, add the entry to the database
285 Node *p = getnode ();
289 while (*vp && !isspace ((unsigned char) *vp))
292 *vp++ = '\0'; /* NULL terminate the key */
294 p->key = xstrdup (kp);
295 while (*vp && isspace ((unsigned char) *vp))
296 vp++; /* skip whitespace to value */
301 "warning: NULL value for key `%s' at line %d of `%s'",
302 p->key, line_num, filename);
306 p->data = xstrdup (vp);
307 if (addnode (list, p) == -1)
311 "duplicate key found for `%s' at line %d of `%s'",
312 p->key, line_num, filename);
317 if (line_length < 0 && !feof (fp))
318 /* FIXME: should give the name of the file. */
319 error (0, errno, "cannot read file in mydbm_load_file");