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