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