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