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