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