PageRenderTime 69ms CodeModel.GetById 19ms app.highlight 45ms RepoModel.GetById 1ms app.codeStats 1ms

/contrib/cvs/src/myndbm.c

https://bitbucket.org/freebsd/freebsd-head/
C | 331 lines | 253 code | 32 blank | 46 comment | 50 complexity | 0cd538fd9e1d312abf0fe6e1e2a493ca MD5 | raw file
  1/*
  2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
  3 *
  4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  5 *                                  and others.
  6 *
  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.
 12 * 
 13 * A simple ndbm-emulator for CVS.  It parses a text file of the format:
 14 * 
 15 * key	value
 16 * 
 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.
 20 */
 21
 22#include <assert.h>
 23#include "cvs.h"
 24#include "getline.h"
 25
 26#ifdef MY_NDBM
 27# ifndef O_ACCMODE
 28#   define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
 29# endif /* defined O_ACCMODE */
 30
 31static void mydbm_load_file PROTO ((FILE *, List *, char *));
 32
 33/* Returns NULL on error in which case errno has been set to indicate
 34   the error.  Can also call error() itself.  */
 35/* ARGSUSED */
 36DBM *
 37mydbm_open (file, flags, mode)
 38    char *file;
 39    int flags;
 40    int mode;
 41{
 42    FILE *fp;
 43    DBM *db;
 44
 45    fp = CVS_FOPEN (file, (flags & O_ACCMODE) != O_RDONLY ?
 46                                 FOPEN_BINARY_READWRITE : FOPEN_BINARY_READ);
 47    if (fp == NULL && !(existence_error (errno) && (flags & O_CREAT)))
 48	return ((DBM *) 0);
 49
 50    db = (DBM *) xmalloc (sizeof (*db));
 51    db->dbm_list = getlist ();
 52    db->modified = 0;
 53    db->name = xstrdup (file);
 54
 55    if (fp != NULL)
 56    {
 57	mydbm_load_file (fp, db->dbm_list, file);
 58	if (fclose (fp) < 0)
 59	    error (0, errno, "cannot close %s", file);
 60    }
 61    return (db);
 62}
 63
 64static int write_item PROTO ((Node *, void *));
 65
 66static int
 67write_item (node, data)
 68    Node *node;
 69    void *data;
 70{
 71    FILE *fp = (FILE *)data;
 72    fputs (node->key, fp);
 73    fputs (" ", fp);
 74    fputs (node->data, fp);
 75    fputs ("\012", fp);
 76    return 0;
 77}
 78
 79void
 80mydbm_close (db)
 81    DBM *db;
 82{
 83    if (db->modified)
 84    {
 85	FILE *fp;
 86	fp = CVS_FOPEN (db->name, FOPEN_BINARY_WRITE);
 87	if (fp == NULL)
 88	    error (1, errno, "cannot write %s", db->name);
 89	walklist (db->dbm_list, write_item, (void *)fp);
 90	if (fclose (fp) < 0)
 91	    error (0, errno, "cannot close %s", db->name);
 92    }
 93    free (db->name);
 94    dellist (&db->dbm_list);
 95    free ((char *) db);
 96}
 97
 98datum
 99mydbm_fetch (db, key)
100    DBM *db;
101    datum key;
102{
103    Node *p;
104    char *s;
105    datum val;
106
107    /* make sure it's null-terminated */
108    s = xmalloc (key.dsize + 1);
109    (void) strncpy (s, key.dptr, key.dsize);
110    s[key.dsize] = '\0';
111
112    p = findnode (db->dbm_list, s);
113    if (p)
114    {
115	val.dptr = p->data;
116	val.dsize = strlen (p->data);
117    }
118    else
119    {
120	val.dptr = (char *) NULL;
121	val.dsize = 0;
122    }
123    free (s);
124    return (val);
125}
126
127datum
128mydbm_firstkey (db)
129    DBM *db;
130{
131    Node *head, *p;
132    datum key;
133
134    head = db->dbm_list->list;
135    p = head->next;
136    if (p != head)
137    {
138	key.dptr = p->key;
139	key.dsize = strlen (p->key);
140    }
141    else
142    {
143	key.dptr = (char *) NULL;
144	key.dsize = 0;
145    }
146    db->dbm_next = p->next;
147    return (key);
148}
149
150datum
151mydbm_nextkey (db)
152    DBM *db;
153{
154    Node *head, *p;
155    datum key;
156
157    head = db->dbm_list->list;
158    p = db->dbm_next;
159    if (p != head)
160    {
161	key.dptr = p->key;
162	key.dsize = strlen (p->key);
163    }
164    else
165    {
166	key.dptr = (char *) NULL;
167	key.dsize = 0;
168    }
169    db->dbm_next = p->next;
170    return (key);
171}
172
173/* Note: only updates the in-memory copy, which is written out at
174   mydbm_close time.  Note: Also differs from DBM in that on duplication,
175   it gives a warning, rather than either DBM_INSERT or DBM_REPLACE
176   behavior.  */
177int
178mydbm_store (db, key, value, flags)
179    DBM *db;
180    datum key;
181    datum value;
182    int flags;
183{
184    Node *node;
185
186    node = getnode ();
187    node->type = NDBMNODE;
188
189    node->key = xmalloc (key.dsize + 1);
190    *node->key = '\0';
191    strncat (node->key, key.dptr, key.dsize);
192
193    node->data = xmalloc (value.dsize + 1);
194    *(char *)node->data = '\0';
195    strncat (node->data, value.dptr, value.dsize);
196
197    db->modified = 1;
198    if (addnode (db->dbm_list, node) == -1)
199    {
200	error (0, 0, "attempt to insert duplicate key `%s'", node->key);
201	freenode (node);
202	return 0;
203    }
204    return 0;
205}
206
207static void
208mydbm_load_file (fp, list, filename)
209    FILE *fp;
210    List *list;
211    char *filename;	/* Used in error messages. */
212{
213    char *line = NULL;
214    size_t line_size;
215    char *value;
216    size_t value_allocated;
217    char *cp, *vp;
218    int cont;
219    int line_length;
220    int line_num;
221
222    value_allocated = 1;
223    value = xmalloc (value_allocated);
224
225    cont = 0;
226    line_num=0;
227    while ((line_length = 
228            getstr (&line, &line_size, fp, '\012', 0, GETLINE_NO_LIMIT)) >= 0)
229    {
230	line_num++;
231	if (line_length > 0 && line[line_length - 1] == '\012')
232	{
233	    /* Strip the newline.  */
234	    --line_length;
235	    line[line_length] = '\0';
236	}
237	if (line_length > 0 && line[line_length - 1] == '\015')
238	{
239	    /* If the file (e.g. modules) was written on an NT box, it will
240	       contain CRLF at the ends of lines.  Strip them (we can't do
241	       this by opening the file in text mode because we might be
242	       running on unix).  */
243	    --line_length;
244	    line[line_length] = '\0';
245	}
246
247	/*
248	 * Add the line to the value, at the end if this is a continuation
249	 * line; otherwise at the beginning, but only after any trailing
250	 * backslash is removed.
251	 */
252	if (!cont)
253	    value[0] = '\0';
254
255	/*
256	 * See if the line we read is a continuation line, and strip the
257	 * backslash if so.
258	 */
259	if (line_length > 0)
260	    cp = &line[line_length - 1];
261	else
262	    cp = line;
263	if (*cp == '\\')
264	{
265	    cont = 1;
266	    *cp = '\0';
267	    --line_length;
268	}
269	else
270	{
271	    cont = 0;
272	}
273	expand_string (&value,
274		       &value_allocated,
275		       strlen (value) + line_length + 5);
276	strcat (value, line);
277
278	if (value[0] == '#')
279	    continue;			/* comment line */
280	vp = value;
281	while (*vp && isspace ((unsigned char) *vp))
282	    vp++;
283	if (*vp == '\0')
284	    continue;			/* empty line */
285
286	/*
287	 * If this was not a continuation line, add the entry to the database
288	 */
289	if (!cont)
290	{
291	    Node *p = getnode ();
292	    char *kp;
293
294	    kp = vp;
295	    while (*vp && !isspace ((unsigned char) *vp))
296		vp++;
297	    if (*vp)
298		*vp++ = '\0';		/* NULL terminate the key */
299	    p->type = NDBMNODE;
300	    p->key = xstrdup (kp);
301	    while (*vp && isspace ((unsigned char) *vp))
302		vp++;			/* skip whitespace to value */
303	    if (*vp == '\0')
304	    {
305		if (!really_quiet)
306		    error (0, 0,
307			"warning: NULL value for key `%s' at line %d of `%s'",
308			p->key, line_num, filename);
309		freenode (p);
310		continue;
311	    }
312	    p->data = xstrdup (vp);
313	    if (addnode (list, p) == -1)
314	    {
315		if (!really_quiet)
316		    error (0, 0,
317			"duplicate key found for `%s' at line %d of `%s'",
318			p->key, line_num, filename);
319		freenode (p);
320	    }
321	}
322    }
323    if (line_length < 0 && !feof (fp))
324	/* FIXME: should give the name of the file.  */
325	error (0, errno, "cannot read file in mydbm_load_file");
326
327    free (line);
328    free (value);
329}
330
331#endif				/* MY_NDBM */