Add CVS 1.12.11.
[dragonfly.git] / contrib / cvs-1.12.11 / 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 "cvs.h"
17 #include "getline.h"
18
19 #ifdef MY_NDBM
20 # ifndef O_ACCMODE
21 #   define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
22 # endif /* defined O_ACCMODE */
23
24 static void mydbm_load_file (FILE *, List *, char *);
25
26 /* Returns NULL on error in which case errno has been set to indicate
27    the error.  Can also call error() itself.  */
28 /* ARGSUSED */
29 DBM *
30 mydbm_open (char *file, int flags, int mode)
31 {
32     FILE *fp;
33     DBM *db;
34
35     fp = CVS_FOPEN (file, (flags & O_ACCMODE) != O_RDONLY
36                           ?  FOPEN_BINARY_READWRITE : FOPEN_BINARY_READ);
37     if (fp == NULL && !(existence_error (errno) && (flags & O_CREAT)))
38         return NULL;
39
40     db = 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, file);
48         if (fclose (fp) < 0)
49             error (0, errno, "cannot close %s",
50                    primary_root_inverse_translate (file));
51     }
52     return db;
53 }
54
55
56
57 static int
58 write_item (Node *node, void *data)
59 {
60     FILE *fp = data;
61     fputs (node->key, fp);
62     fputs (" ", fp);
63     fputs (node->data, fp);
64     fputs ("\012", fp);
65     return 0;
66 }
67
68
69
70 void
71 mydbm_close (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, 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 (db);
86 }
87
88
89
90 datum
91 mydbm_fetch (DBM *db, 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 = NULL;
111         val.dsize = 0;
112     }
113     free (s);
114     return val;
115 }
116
117
118
119 datum
120 mydbm_firstkey (DBM *db)
121 {
122     Node *head, *p;
123     datum key;
124
125     head = db->dbm_list->list;
126     p = head->next;
127     if (p != head)
128     {
129         key.dptr = p->key;
130         key.dsize = strlen (p->key);
131     }
132     else
133     {
134         key.dptr = NULL;
135         key.dsize = 0;
136     }
137     db->dbm_next = p->next;
138     return key;
139 }
140
141
142
143 datum
144 mydbm_nextkey (DBM *db)
145 {
146     Node *head, *p;
147     datum key;
148
149     head = db->dbm_list->list;
150     p = db->dbm_next;
151     if (p != head)
152     {
153         key.dptr = p->key;
154         key.dsize = strlen (p->key);
155     }
156     else
157     {
158         key.dptr = (char *) NULL;
159         key.dsize = 0;
160     }
161     db->dbm_next = p->next;
162     return key;
163 }
164
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 (DBM *db, datum key, datum value, int flags)
173 {
174     Node *node;
175
176     node = getnode ();
177     node->type = NDBMNODE;
178
179     node->key = xmalloc (key.dsize + 1);
180     *node->key = '\0';
181     strncat (node->key, key.dptr, key.dsize);
182
183     node->data = xmalloc (value.dsize + 1);
184     *(char *)node->data = '\0';
185     strncat (node->data, value.dptr, value.dsize);
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
198
199 /* Load a DBM file.
200  *
201  * INPUTS
202  *   filename           Used in error messages.
203  */
204 static void
205 mydbm_load_file (FILE *fp, List *list, char *filename)
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 = getdelim (&line, &line_size, '\012', fp)) >= 0)
222     {
223         line_num++;
224         if (line_length > 0 && line[line_length - 1] == '\012')
225         {
226             /* Strip the newline.  */
227             --line_length;
228             line[line_length] = '\0';
229         }
230         if (line_length > 0 && line[line_length - 1] == '\015')
231         {
232             /* If the file (e.g. modules) was written on an NT box, it will
233                contain CRLF at the ends of lines.  Strip them (we can't do
234                this by opening the file in text mode because we might be
235                running on unix).  */
236             --line_length;
237             line[line_length] = '\0';
238         }
239
240         /*
241          * Add the line to the value, at the end if this is a continuation
242          * line; otherwise at the beginning, but only after any trailing
243          * backslash is removed.
244          */
245         if (!cont)
246             value[0] = '\0';
247
248         /*
249          * See if the line we read is a continuation line, and strip the
250          * backslash if so.
251          */
252         if (line_length > 0)
253             cp = &line[line_length - 1];
254         else
255             cp = line;
256         if (*cp == '\\')
257         {
258             cont = 1;
259             *cp = '\0';
260             --line_length;
261         }
262         else
263         {
264             cont = 0;
265         }
266         expand_string (&value,
267                        &value_allocated,
268                        strlen (value) + line_length + 5);
269         strcat (value, line);
270
271         if (value[0] == '#')
272             continue;                   /* comment line */
273         vp = value;
274         while (*vp && isspace ((unsigned char) *vp))
275             vp++;
276         if (*vp == '\0')
277             continue;                   /* empty line */
278
279         /*
280          * If this was not a continuation line, add the entry to the database
281          */
282         if (!cont)
283         {
284             Node *p = getnode ();
285             char *kp;
286
287             kp = vp;
288             while (*vp && !isspace ((unsigned char) *vp))
289                 vp++;
290             if (*vp)
291                 *vp++ = '\0';           /* NULL terminate the key */
292             p->type = NDBMNODE;
293             p->key = xstrdup (kp);
294             while (*vp && isspace ((unsigned char) *vp))
295                 vp++;                   /* skip whitespace to value */
296             if (*vp == '\0')
297             {
298                 if (!really_quiet)
299                     error (0, 0,
300                         "warning: NULL value for key `%s' at line %d of `%s'",
301                         p->key, line_num,
302                         primary_root_inverse_translate (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,
313                         primary_root_inverse_translate (filename));
314                 freenode (p);
315             }
316         }
317     }
318     if (line_length < 0 && !feof (fp))
319         error (0, errno, "cannot read file `%s' in mydbm_load_file",
320                primary_root_inverse_translate (filename));
321
322     free (line);
323     free (value);
324 }
325
326 #endif                          /* MY_NDBM */