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