xref: /dflybsd-src/contrib/cvs-1.12/src/myndbm.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /*
286d7f5d3SJohn Marino  * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
386d7f5d3SJohn Marino  *
486d7f5d3SJohn Marino  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
586d7f5d3SJohn Marino  *                                  and others.
686d7f5d3SJohn Marino  *
786d7f5d3SJohn Marino  * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
886d7f5d3SJohn Marino  * Portions Copyright (C) 1989-1992, Brian Berliner
986d7f5d3SJohn Marino  *
1086d7f5d3SJohn Marino  * You may distribute under the terms of the GNU General Public License as
1186d7f5d3SJohn Marino  * specified in the README file that comes with the CVS source distribution.
1286d7f5d3SJohn Marino  *
1386d7f5d3SJohn Marino  * A simple ndbm-emulator for CVS.  It parses a text file of the format:
1486d7f5d3SJohn Marino  *
1586d7f5d3SJohn Marino  * key	value
1686d7f5d3SJohn Marino  *
1786d7f5d3SJohn Marino  * at dbm_open time, and loads the entire file into memory.  As such, it is
1886d7f5d3SJohn Marino  * probably only good for fairly small modules files.  Ours is about 30K in
1986d7f5d3SJohn Marino  * size, and this code works fine.
2086d7f5d3SJohn Marino  */
2186d7f5d3SJohn Marino 
2286d7f5d3SJohn Marino #include "cvs.h"
2386d7f5d3SJohn Marino 
2486d7f5d3SJohn Marino #include "getdelim.h"
2586d7f5d3SJohn Marino #include "getline.h"
2686d7f5d3SJohn Marino 
2786d7f5d3SJohn Marino #ifdef MY_NDBM
2886d7f5d3SJohn Marino # ifndef O_ACCMODE
2986d7f5d3SJohn Marino #   define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
3086d7f5d3SJohn Marino # endif /* defined O_ACCMODE */
3186d7f5d3SJohn Marino 
3286d7f5d3SJohn Marino static void mydbm_load_file (FILE *, List *, char *);
3386d7f5d3SJohn Marino 
3486d7f5d3SJohn Marino /* Returns NULL on error in which case errno has been set to indicate
3586d7f5d3SJohn Marino    the error.  Can also call error() itself.  */
3686d7f5d3SJohn Marino /* ARGSUSED */
3786d7f5d3SJohn Marino DBM *
mydbm_open(char * file,int flags,int mode)3886d7f5d3SJohn Marino mydbm_open (char *file, int flags, int mode)
3986d7f5d3SJohn Marino {
4086d7f5d3SJohn Marino     FILE *fp;
4186d7f5d3SJohn Marino     DBM *db;
4286d7f5d3SJohn Marino 
4386d7f5d3SJohn Marino     fp = CVS_FOPEN (file, (flags & O_ACCMODE) != O_RDONLY
4486d7f5d3SJohn Marino 			  ?  FOPEN_BINARY_READWRITE : FOPEN_BINARY_READ);
4586d7f5d3SJohn Marino     if (fp == NULL && !(existence_error (errno) && (flags & O_CREAT)))
4686d7f5d3SJohn Marino 	return NULL;
4786d7f5d3SJohn Marino 
4886d7f5d3SJohn Marino     db = xmalloc (sizeof (*db));
4986d7f5d3SJohn Marino     db->dbm_list = getlist ();
5086d7f5d3SJohn Marino     db->modified = 0;
5186d7f5d3SJohn Marino     db->name = xstrdup (file);
5286d7f5d3SJohn Marino 
5386d7f5d3SJohn Marino     if (fp != NULL)
5486d7f5d3SJohn Marino     {
5586d7f5d3SJohn Marino 	mydbm_load_file (fp, db->dbm_list, file);
5686d7f5d3SJohn Marino 	if (fclose (fp) < 0)
5786d7f5d3SJohn Marino 	    error (0, errno, "cannot close %s",
5886d7f5d3SJohn Marino 		   primary_root_inverse_translate (file));
5986d7f5d3SJohn Marino     }
6086d7f5d3SJohn Marino     return db;
6186d7f5d3SJohn Marino }
6286d7f5d3SJohn Marino 
6386d7f5d3SJohn Marino 
6486d7f5d3SJohn Marino 
6586d7f5d3SJohn Marino static int
write_item(Node * node,void * data)6686d7f5d3SJohn Marino write_item (Node *node, void *data)
6786d7f5d3SJohn Marino {
6886d7f5d3SJohn Marino     FILE *fp = data;
6986d7f5d3SJohn Marino     fputs (node->key, fp);
7086d7f5d3SJohn Marino     fputs (" ", fp);
7186d7f5d3SJohn Marino     fputs (node->data, fp);
7286d7f5d3SJohn Marino     fputs ("\012", fp);
7386d7f5d3SJohn Marino     return 0;
7486d7f5d3SJohn Marino }
7586d7f5d3SJohn Marino 
7686d7f5d3SJohn Marino 
7786d7f5d3SJohn Marino 
7886d7f5d3SJohn Marino void
mydbm_close(DBM * db)7986d7f5d3SJohn Marino mydbm_close (DBM *db)
8086d7f5d3SJohn Marino {
8186d7f5d3SJohn Marino     if (db->modified)
8286d7f5d3SJohn Marino     {
8386d7f5d3SJohn Marino 	FILE *fp;
8486d7f5d3SJohn Marino 	fp = CVS_FOPEN (db->name, FOPEN_BINARY_WRITE);
8586d7f5d3SJohn Marino 	if (fp == NULL)
8686d7f5d3SJohn Marino 	    error (1, errno, "cannot write %s", db->name);
8786d7f5d3SJohn Marino 	walklist (db->dbm_list, write_item, fp);
8886d7f5d3SJohn Marino 	if (fclose (fp) < 0)
8986d7f5d3SJohn Marino 	    error (0, errno, "cannot close %s", db->name);
9086d7f5d3SJohn Marino     }
9186d7f5d3SJohn Marino     free (db->name);
9286d7f5d3SJohn Marino     dellist (&db->dbm_list);
9386d7f5d3SJohn Marino     free (db);
9486d7f5d3SJohn Marino }
9586d7f5d3SJohn Marino 
9686d7f5d3SJohn Marino 
9786d7f5d3SJohn Marino 
9886d7f5d3SJohn Marino datum
mydbm_fetch(DBM * db,datum key)9986d7f5d3SJohn Marino mydbm_fetch (DBM *db, datum key)
10086d7f5d3SJohn Marino {
10186d7f5d3SJohn Marino     Node *p;
10286d7f5d3SJohn Marino     char *s;
10386d7f5d3SJohn Marino     datum val;
10486d7f5d3SJohn Marino 
10586d7f5d3SJohn Marino     /* make sure it's null-terminated */
10686d7f5d3SJohn Marino     s = xmalloc (key.dsize + 1);
10786d7f5d3SJohn Marino     (void) strncpy (s, key.dptr, key.dsize);
10886d7f5d3SJohn Marino     s[key.dsize] = '\0';
10986d7f5d3SJohn Marino 
11086d7f5d3SJohn Marino     p = findnode (db->dbm_list, s);
11186d7f5d3SJohn Marino     if (p)
11286d7f5d3SJohn Marino     {
11386d7f5d3SJohn Marino 	val.dptr = p->data;
11486d7f5d3SJohn Marino 	val.dsize = strlen (p->data);
11586d7f5d3SJohn Marino     }
11686d7f5d3SJohn Marino     else
11786d7f5d3SJohn Marino     {
11886d7f5d3SJohn Marino 	val.dptr = NULL;
11986d7f5d3SJohn Marino 	val.dsize = 0;
12086d7f5d3SJohn Marino     }
12186d7f5d3SJohn Marino     free (s);
12286d7f5d3SJohn Marino     return val;
12386d7f5d3SJohn Marino }
12486d7f5d3SJohn Marino 
12586d7f5d3SJohn Marino 
12686d7f5d3SJohn Marino 
12786d7f5d3SJohn Marino datum
mydbm_firstkey(DBM * db)12886d7f5d3SJohn Marino mydbm_firstkey (DBM *db)
12986d7f5d3SJohn Marino {
13086d7f5d3SJohn Marino     Node *head, *p;
13186d7f5d3SJohn Marino     datum key;
13286d7f5d3SJohn Marino 
13386d7f5d3SJohn Marino     head = db->dbm_list->list;
13486d7f5d3SJohn Marino     p = head->next;
13586d7f5d3SJohn Marino     if (p != head)
13686d7f5d3SJohn Marino     {
13786d7f5d3SJohn Marino 	key.dptr = p->key;
13886d7f5d3SJohn Marino 	key.dsize = strlen (p->key);
13986d7f5d3SJohn Marino     }
14086d7f5d3SJohn Marino     else
14186d7f5d3SJohn Marino     {
14286d7f5d3SJohn Marino 	key.dptr = NULL;
14386d7f5d3SJohn Marino 	key.dsize = 0;
14486d7f5d3SJohn Marino     }
14586d7f5d3SJohn Marino     db->dbm_next = p->next;
14686d7f5d3SJohn Marino     return key;
14786d7f5d3SJohn Marino }
14886d7f5d3SJohn Marino 
14986d7f5d3SJohn Marino 
15086d7f5d3SJohn Marino 
15186d7f5d3SJohn Marino datum
mydbm_nextkey(DBM * db)15286d7f5d3SJohn Marino mydbm_nextkey (DBM *db)
15386d7f5d3SJohn Marino {
15486d7f5d3SJohn Marino     Node *head, *p;
15586d7f5d3SJohn Marino     datum key;
15686d7f5d3SJohn Marino 
15786d7f5d3SJohn Marino     head = db->dbm_list->list;
15886d7f5d3SJohn Marino     p = db->dbm_next;
15986d7f5d3SJohn Marino     if (p != head)
16086d7f5d3SJohn Marino     {
16186d7f5d3SJohn Marino 	key.dptr = p->key;
16286d7f5d3SJohn Marino 	key.dsize = strlen (p->key);
16386d7f5d3SJohn Marino     }
16486d7f5d3SJohn Marino     else
16586d7f5d3SJohn Marino     {
16686d7f5d3SJohn Marino 	key.dptr = NULL;
16786d7f5d3SJohn Marino 	key.dsize = 0;
16886d7f5d3SJohn Marino     }
16986d7f5d3SJohn Marino     db->dbm_next = p->next;
17086d7f5d3SJohn Marino     return key;
17186d7f5d3SJohn Marino }
17286d7f5d3SJohn Marino 
17386d7f5d3SJohn Marino 
17486d7f5d3SJohn Marino 
17586d7f5d3SJohn Marino /* Note: only updates the in-memory copy, which is written out at
17686d7f5d3SJohn Marino    mydbm_close time.  Note: Also differs from DBM in that on duplication,
17786d7f5d3SJohn Marino    it gives a warning, rather than either DBM_INSERT or DBM_REPLACE
17886d7f5d3SJohn Marino    behavior.  */
17986d7f5d3SJohn Marino int
mydbm_store(DBM * db,datum key,datum value,int flags)18086d7f5d3SJohn Marino mydbm_store (DBM *db, datum key, datum value, int flags)
18186d7f5d3SJohn Marino {
18286d7f5d3SJohn Marino     Node *node;
18386d7f5d3SJohn Marino 
18486d7f5d3SJohn Marino     node = getnode ();
18586d7f5d3SJohn Marino     node->type = NDBMNODE;
18686d7f5d3SJohn Marino 
18786d7f5d3SJohn Marino     node->key = xmalloc (key.dsize + 1);
18886d7f5d3SJohn Marino     *node->key = '\0';
18986d7f5d3SJohn Marino     strncat (node->key, key.dptr, key.dsize);
19086d7f5d3SJohn Marino 
19186d7f5d3SJohn Marino     node->data = xmalloc (value.dsize + 1);
19286d7f5d3SJohn Marino     *(char *)node->data = '\0';
19386d7f5d3SJohn Marino     strncat (node->data, value.dptr, value.dsize);
19486d7f5d3SJohn Marino 
19586d7f5d3SJohn Marino     db->modified = 1;
19686d7f5d3SJohn Marino     if (addnode (db->dbm_list, node) == -1)
19786d7f5d3SJohn Marino     {
19886d7f5d3SJohn Marino 	error (0, 0, "attempt to insert duplicate key `%s'", node->key);
19986d7f5d3SJohn Marino 	freenode (node);
20086d7f5d3SJohn Marino 	return 0;
20186d7f5d3SJohn Marino     }
20286d7f5d3SJohn Marino     return 0;
20386d7f5d3SJohn Marino }
20486d7f5d3SJohn Marino 
20586d7f5d3SJohn Marino 
20686d7f5d3SJohn Marino 
20786d7f5d3SJohn Marino /* Load a DBM file.
20886d7f5d3SJohn Marino  *
20986d7f5d3SJohn Marino  * INPUTS
21086d7f5d3SJohn Marino  *   filename		Used in error messages.
21186d7f5d3SJohn Marino  */
21286d7f5d3SJohn Marino static void
mydbm_load_file(FILE * fp,List * list,char * filename)21386d7f5d3SJohn Marino mydbm_load_file (FILE *fp, List *list, char *filename)
21486d7f5d3SJohn Marino {
21586d7f5d3SJohn Marino     char *line = NULL;
21686d7f5d3SJohn Marino     size_t line_size;
21786d7f5d3SJohn Marino     char *value;
21886d7f5d3SJohn Marino     size_t value_allocated;
21986d7f5d3SJohn Marino     char *cp, *vp;
22086d7f5d3SJohn Marino     int cont;
22186d7f5d3SJohn Marino     int line_length;
22286d7f5d3SJohn Marino     int line_num;
22386d7f5d3SJohn Marino 
22486d7f5d3SJohn Marino     value_allocated = 1;
22586d7f5d3SJohn Marino     value = xmalloc (value_allocated);
22686d7f5d3SJohn Marino 
22786d7f5d3SJohn Marino     cont = 0;
22886d7f5d3SJohn Marino     line_num=0;
22986d7f5d3SJohn Marino     while ((line_length = getdelim (&line, &line_size, '\012', fp)) >= 0)
23086d7f5d3SJohn Marino     {
23186d7f5d3SJohn Marino 	line_num++;
23286d7f5d3SJohn Marino 	if (line_length > 0 && line[line_length - 1] == '\012')
23386d7f5d3SJohn Marino 	{
23486d7f5d3SJohn Marino 	    /* Strip the newline.  */
23586d7f5d3SJohn Marino 	    --line_length;
23686d7f5d3SJohn Marino 	    line[line_length] = '\0';
23786d7f5d3SJohn Marino 	}
23886d7f5d3SJohn Marino 	if (line_length > 0 && line[line_length - 1] == '\015')
23986d7f5d3SJohn Marino 	{
24086d7f5d3SJohn Marino 	    /* If the file (e.g. modules) was written on an NT box, it will
24186d7f5d3SJohn Marino 	       contain CRLF at the ends of lines.  Strip them (we can't do
24286d7f5d3SJohn Marino 	       this by opening the file in text mode because we might be
24386d7f5d3SJohn Marino 	       running on unix).  */
24486d7f5d3SJohn Marino 	    --line_length;
24586d7f5d3SJohn Marino 	    line[line_length] = '\0';
24686d7f5d3SJohn Marino 	}
24786d7f5d3SJohn Marino 
24886d7f5d3SJohn Marino 	/*
24986d7f5d3SJohn Marino 	 * Add the line to the value, at the end if this is a continuation
25086d7f5d3SJohn Marino 	 * line; otherwise at the beginning, but only after any trailing
25186d7f5d3SJohn Marino 	 * backslash is removed.
25286d7f5d3SJohn Marino 	 */
25386d7f5d3SJohn Marino 	if (!cont)
25486d7f5d3SJohn Marino 	    value[0] = '\0';
25586d7f5d3SJohn Marino 
25686d7f5d3SJohn Marino 	/*
25786d7f5d3SJohn Marino 	 * See if the line we read is a continuation line, and strip the
25886d7f5d3SJohn Marino 	 * backslash if so.
25986d7f5d3SJohn Marino 	 */
26086d7f5d3SJohn Marino 	if (line_length > 0)
26186d7f5d3SJohn Marino 	    cp = &line[line_length - 1];
26286d7f5d3SJohn Marino 	else
26386d7f5d3SJohn Marino 	    cp = line;
26486d7f5d3SJohn Marino 	if (*cp == '\\')
26586d7f5d3SJohn Marino 	{
26686d7f5d3SJohn Marino 	    cont = 1;
26786d7f5d3SJohn Marino 	    *cp = '\0';
26886d7f5d3SJohn Marino 	    --line_length;
26986d7f5d3SJohn Marino 	}
27086d7f5d3SJohn Marino 	else
27186d7f5d3SJohn Marino 	{
27286d7f5d3SJohn Marino 	    cont = 0;
27386d7f5d3SJohn Marino 	}
27486d7f5d3SJohn Marino 	expand_string (&value,
27586d7f5d3SJohn Marino 		       &value_allocated,
27686d7f5d3SJohn Marino 		       strlen (value) + line_length + 5);
27786d7f5d3SJohn Marino 	strcat (value, line);
27886d7f5d3SJohn Marino 
27986d7f5d3SJohn Marino 	if (value[0] == '#')
28086d7f5d3SJohn Marino 	    continue;			/* comment line */
28186d7f5d3SJohn Marino 	vp = value;
28286d7f5d3SJohn Marino 	while (*vp && isspace ((unsigned char) *vp))
28386d7f5d3SJohn Marino 	    vp++;
28486d7f5d3SJohn Marino 	if (*vp == '\0')
28586d7f5d3SJohn Marino 	    continue;			/* empty line */
28686d7f5d3SJohn Marino 
28786d7f5d3SJohn Marino 	/*
28886d7f5d3SJohn Marino 	 * If this was not a continuation line, add the entry to the database
28986d7f5d3SJohn Marino 	 */
29086d7f5d3SJohn Marino 	if (!cont)
29186d7f5d3SJohn Marino 	{
29286d7f5d3SJohn Marino 	    Node *p = getnode ();
29386d7f5d3SJohn Marino 	    char *kp;
29486d7f5d3SJohn Marino 
29586d7f5d3SJohn Marino 	    kp = vp;
29686d7f5d3SJohn Marino 	    while (*vp && !isspace ((unsigned char) *vp))
29786d7f5d3SJohn Marino 		vp++;
29886d7f5d3SJohn Marino 	    if (*vp)
29986d7f5d3SJohn Marino 		*vp++ = '\0';		/* NULL terminate the key */
30086d7f5d3SJohn Marino 	    p->type = NDBMNODE;
30186d7f5d3SJohn Marino 	    p->key = xstrdup (kp);
30286d7f5d3SJohn Marino 	    while (*vp && isspace ((unsigned char) *vp))
30386d7f5d3SJohn Marino 		vp++;			/* skip whitespace to value */
30486d7f5d3SJohn Marino 	    if (*vp == '\0')
30586d7f5d3SJohn Marino 	    {
30686d7f5d3SJohn Marino 		if (!really_quiet)
30786d7f5d3SJohn Marino 		    error (0, 0,
30886d7f5d3SJohn Marino 			"warning: NULL value for key `%s' at line %d of `%s'",
30986d7f5d3SJohn Marino 			p->key, line_num,
31086d7f5d3SJohn Marino 			primary_root_inverse_translate (filename));
31186d7f5d3SJohn Marino 		freenode (p);
31286d7f5d3SJohn Marino 		continue;
31386d7f5d3SJohn Marino 	    }
31486d7f5d3SJohn Marino 	    p->data = xstrdup (vp);
31586d7f5d3SJohn Marino 	    if (addnode (list, p) == -1)
31686d7f5d3SJohn Marino 	    {
31786d7f5d3SJohn Marino 		if (!really_quiet)
31886d7f5d3SJohn Marino 		    error (0, 0,
31986d7f5d3SJohn Marino 			"duplicate key found for `%s' at line %d of `%s'",
32086d7f5d3SJohn Marino 			p->key, line_num,
32186d7f5d3SJohn Marino 			primary_root_inverse_translate (filename));
32286d7f5d3SJohn Marino 		freenode (p);
32386d7f5d3SJohn Marino 	    }
32486d7f5d3SJohn Marino 	}
32586d7f5d3SJohn Marino     }
32686d7f5d3SJohn Marino     if (line_length < 0 && !feof (fp))
32786d7f5d3SJohn Marino 	error (0, errno, "cannot read file `%s' in mydbm_load_file",
32886d7f5d3SJohn Marino 	       primary_root_inverse_translate (filename));
32986d7f5d3SJohn Marino 
33086d7f5d3SJohn Marino     free (line);
33186d7f5d3SJohn Marino     free (value);
33286d7f5d3SJohn Marino }
33386d7f5d3SJohn Marino 
33486d7f5d3SJohn Marino #endif				/* MY_NDBM */
335