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