HAMMER Utilities: Sync with 59A
[dragonfly.git] / contrib / cvs-1.12 / src / myndbm.c
blobd7ef885f7848ff18621b1c05a2124a4d8fd6776f
1 /*
2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
5 * and others.
7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (C) 1989-1992, Brian Berliner
9 *
10 * You may distribute under the terms of the GNU General Public License as
11 * specified in the README file that comes with the CVS source distribution.
13 * A simple ndbm-emulator for CVS. It parses a text file of the format:
15 * key value
17 * at dbm_open time, and loads the entire file into memory. As such, it is
18 * probably only good for fairly small modules files. Ours is about 30K in
19 * size, and this code works fine.
22 #include "cvs.h"
24 #include "getdelim.h"
25 #include "getline.h"
27 #ifdef MY_NDBM
28 # ifndef O_ACCMODE
29 # define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
30 # endif /* defined O_ACCMODE */
32 static void mydbm_load_file (FILE *, List *, char *);
34 /* Returns NULL on error in which case errno has been set to indicate
35 the error. Can also call error() itself. */
36 /* ARGSUSED */
37 DBM *
38 mydbm_open (char *file, int flags, int mode)
40 FILE *fp;
41 DBM *db;
43 fp = CVS_FOPEN (file, (flags & O_ACCMODE) != O_RDONLY
44 ? FOPEN_BINARY_READWRITE : FOPEN_BINARY_READ);
45 if (fp == NULL && !(existence_error (errno) && (flags & O_CREAT)))
46 return NULL;
48 db = xmalloc (sizeof (*db));
49 db->dbm_list = getlist ();
50 db->modified = 0;
51 db->name = xstrdup (file);
53 if (fp != NULL)
55 mydbm_load_file (fp, db->dbm_list, file);
56 if (fclose (fp) < 0)
57 error (0, errno, "cannot close %s",
58 primary_root_inverse_translate (file));
60 return db;
65 static int
66 write_item (Node *node, void *data)
68 FILE *fp = data;
69 fputs (node->key, fp);
70 fputs (" ", fp);
71 fputs (node->data, fp);
72 fputs ("\012", fp);
73 return 0;
78 void
79 mydbm_close (DBM *db)
81 if (db->modified)
83 FILE *fp;
84 fp = CVS_FOPEN (db->name, FOPEN_BINARY_WRITE);
85 if (fp == NULL)
86 error (1, errno, "cannot write %s", db->name);
87 walklist (db->dbm_list, write_item, fp);
88 if (fclose (fp) < 0)
89 error (0, errno, "cannot close %s", db->name);
91 free (db->name);
92 dellist (&db->dbm_list);
93 free (db);
98 datum
99 mydbm_fetch (DBM *db, datum key)
101 Node *p;
102 char *s;
103 datum val;
105 /* make sure it's null-terminated */
106 s = xmalloc (key.dsize + 1);
107 (void) strncpy (s, key.dptr, key.dsize);
108 s[key.dsize] = '\0';
110 p = findnode (db->dbm_list, s);
111 if (p)
113 val.dptr = p->data;
114 val.dsize = strlen (p->data);
116 else
118 val.dptr = NULL;
119 val.dsize = 0;
121 free (s);
122 return val;
127 datum
128 mydbm_firstkey (DBM *db)
130 Node *head, *p;
131 datum key;
133 head = db->dbm_list->list;
134 p = head->next;
135 if (p != head)
137 key.dptr = p->key;
138 key.dsize = strlen (p->key);
140 else
142 key.dptr = NULL;
143 key.dsize = 0;
145 db->dbm_next = p->next;
146 return key;
151 datum
152 mydbm_nextkey (DBM *db)
154 Node *head, *p;
155 datum key;
157 head = db->dbm_list->list;
158 p = db->dbm_next;
159 if (p != head)
161 key.dptr = p->key;
162 key.dsize = strlen (p->key);
164 else
166 key.dptr = NULL;
167 key.dsize = 0;
169 db->dbm_next = p->next;
170 return key;
175 /* Note: only updates the in-memory copy, which is written out at
176 mydbm_close time. Note: Also differs from DBM in that on duplication,
177 it gives a warning, rather than either DBM_INSERT or DBM_REPLACE
178 behavior. */
180 mydbm_store (DBM *db, datum key, datum value, int flags)
182 Node *node;
184 node = getnode ();
185 node->type = NDBMNODE;
187 node->key = xmalloc (key.dsize + 1);
188 *node->key = '\0';
189 strncat (node->key, key.dptr, key.dsize);
191 node->data = xmalloc (value.dsize + 1);
192 *(char *)node->data = '\0';
193 strncat (node->data, value.dptr, value.dsize);
195 db->modified = 1;
196 if (addnode (db->dbm_list, node) == -1)
198 error (0, 0, "attempt to insert duplicate key `%s'", node->key);
199 freenode (node);
200 return 0;
202 return 0;
207 /* Load a DBM file.
209 * INPUTS
210 * filename Used in error messages.
212 static void
213 mydbm_load_file (FILE *fp, List *list, char *filename)
215 char *line = NULL;
216 size_t line_size;
217 char *value;
218 size_t value_allocated;
219 char *cp, *vp;
220 int cont;
221 int line_length;
222 int line_num;
224 value_allocated = 1;
225 value = xmalloc (value_allocated);
227 cont = 0;
228 line_num=0;
229 while ((line_length = getdelim (&line, &line_size, '\012', fp)) >= 0)
231 line_num++;
232 if (line_length > 0 && line[line_length - 1] == '\012')
234 /* Strip the newline. */
235 --line_length;
236 line[line_length] = '\0';
238 if (line_length > 0 && line[line_length - 1] == '\015')
240 /* If the file (e.g. modules) was written on an NT box, it will
241 contain CRLF at the ends of lines. Strip them (we can't do
242 this by opening the file in text mode because we might be
243 running on unix). */
244 --line_length;
245 line[line_length] = '\0';
249 * Add the line to the value, at the end if this is a continuation
250 * line; otherwise at the beginning, but only after any trailing
251 * backslash is removed.
253 if (!cont)
254 value[0] = '\0';
257 * See if the line we read is a continuation line, and strip the
258 * backslash if so.
260 if (line_length > 0)
261 cp = &line[line_length - 1];
262 else
263 cp = line;
264 if (*cp == '\\')
266 cont = 1;
267 *cp = '\0';
268 --line_length;
270 else
272 cont = 0;
274 expand_string (&value,
275 &value_allocated,
276 strlen (value) + line_length + 5);
277 strcat (value, line);
279 if (value[0] == '#')
280 continue; /* comment line */
281 vp = value;
282 while (*vp && isspace ((unsigned char) *vp))
283 vp++;
284 if (*vp == '\0')
285 continue; /* empty line */
288 * If this was not a continuation line, add the entry to the database
290 if (!cont)
292 Node *p = getnode ();
293 char *kp;
295 kp = vp;
296 while (*vp && !isspace ((unsigned char) *vp))
297 vp++;
298 if (*vp)
299 *vp++ = '\0'; /* NULL terminate the key */
300 p->type = NDBMNODE;
301 p->key = xstrdup (kp);
302 while (*vp && isspace ((unsigned char) *vp))
303 vp++; /* skip whitespace to value */
304 if (*vp == '\0')
306 if (!really_quiet)
307 error (0, 0,
308 "warning: NULL value for key `%s' at line %d of `%s'",
309 p->key, line_num,
310 primary_root_inverse_translate (filename));
311 freenode (p);
312 continue;
314 p->data = xstrdup (vp);
315 if (addnode (list, p) == -1)
317 if (!really_quiet)
318 error (0, 0,
319 "duplicate key found for `%s' at line %d of `%s'",
320 p->key, line_num,
321 primary_root_inverse_translate (filename));
322 freenode (p);
326 if (line_length < 0 && !feof (fp))
327 error (0, errno, "cannot read file `%s' in mydbm_load_file",
328 primary_root_inverse_translate (filename));
330 free (line);
331 free (value);
334 #endif /* MY_NDBM */