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