xref: /plan9-contrib/sys/src/libndb/ndbparse.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <ctype.h>
5 #include <ndb.h>
6 #include "ndbhf.h"
7 
8 /*
9  *  Parse a data base entry.  Entries may span multiple
10  *  lines.  An entry starts on a left margin.  All subsequent
11  *  lines must be indented by white space.  An entry consists
12  *  of tuples of the forms:
13  *	attribute-name
14  *	attribute-name=value
15  *	attribute-name="value with white space"
16  *
17  *  The parsing returns a 2-dimensional structure.  The first
18  *  dimension joins all tuples. All tuples on the same line
19  *  form a ring along the second dimension.
20  */
21 
22 /*
23  *  parse the next entry in the file
24  */
25 Ndbtuple*
26 ndbparse(Ndb *db)
27 {
28 	char *line;
29 	Ndbtuple *t;
30 	Ndbtuple *first, *last;
31 	int len;
32 
33 	first = last = 0;
34 	for(;;){
35 		if((line = Brdline(&db->b, '\n')) == 0)
36 			break;
37 		len = Blinelen(&db->b);
38 		if(line[len-1] != '\n')
39 			break;
40 		if(first && !ISWHITE(*line) && *line != '#'){
41 			Bseek(&db->b, -len, 1);
42 			return first;
43 		}
44 		t = _ndbparseline(line);
45 		if(t == 0)
46 			continue;
47 		if(first)
48 			last->entry = t;
49 		else
50 			first = t;
51 		last = t;
52 		while(last->entry)
53 			last = last->entry;
54 	}
55 	return first;
56 }
57 
58 
59 /*
60  *  free the hash files belonging to a db
61  */
62 static void
63 hffree(Ndb *db)
64 {
65 	Ndbhf *hf, *next;
66 
67 	for(hf = db->hf; hf; hf = next){
68 		next = hf->next;
69 		close(hf->fd);
70 		free(hf);
71 	}
72 	db->hf = 0;
73 }
74 
75 int
76 ndbreopen(Ndb *db)
77 {
78 	int fd;
79 	Dir d;
80 
81 	/* forget what we know about the open files */
82 	if(db->mtime){
83 		hffree(db);
84 		close(Bfildes(&db->b));
85 		Bterm(&db->b);
86 		db->mtime = 0;
87 	}
88 
89 	/* try the open again */
90 	fd = open(db->file, OREAD);
91 	if(fd < 0)
92 		return -1;
93 	if(dirfstat(fd, &d) < 0){
94 		close(fd);
95 		return -1;
96 	}
97 
98 	db->qid = d.qid;
99 	db->mtime = d.mtime;
100 	db->length = d.length;
101 	Binits(&db->b, fd, OREAD, db->buf, sizeof(db->buf));
102 	return 0;
103 }
104 
105 static char *deffile = "/lib/ndb/local";
106 
107 /*
108  *  lookup the list of files to use in the specified database file
109  */
110 static Ndb*
111 doopen(char *file)
112 {
113 	Ndb *db;
114 
115 	db = (Ndb*)malloc(sizeof(Ndb));
116 	if(db == 0)
117 		return 0;
118 	strncpy(db->file, file, sizeof(db->file)-1);
119 	db->next = 0;
120 	db->hf = 0;
121 	db->mtime = 0;
122 
123 	if(ndbreopen(db) < 0){
124 		free(db);
125 		return 0;
126 	}
127 
128 	return db;
129 }
130 Ndb*
131 ndbopen(char *file)
132 {
133 	Ndb *db, *first, *last;
134 	Ndbs s;
135 	Ndbtuple *t, *nt;
136 
137 	if(file == 0)
138 		file = deffile;
139 	db = doopen(file);
140 	if(db == 0)
141 		return 0;
142 	first = last = db;
143 	t = ndbsearch(db, &s, "database", "");
144 	Bseek(&db->b, 0, 0);
145 	if(t == 0)
146 		return db;
147 	for(nt = t; nt; nt = nt->entry){
148 		if(strcmp(nt->attr, "file") != 0)
149 			continue;
150 		if(strcmp(nt->val, file) == 0){
151 			/* default file can be reordered in the list */
152 			if(first->next == 0)
153 				continue;
154 			if(strcmp(first->file, file) == 0){
155 				db = first;
156 				first = first->next;
157 				last->next = db;
158 				db->next = 0;
159 				last = db;
160 			}
161 			continue;
162 		}
163 		db = doopen(nt->val);
164 		if(db == 0)
165 			continue;
166 		last->next = db;
167 		last = db;
168 	}
169 	return first;
170 }
171 
172 void
173 ndbclose(Ndb *db)
174 {
175 	Ndb *nextdb;
176 
177 	for(; db; db = nextdb){
178 		nextdb = db->next;
179 		hffree(db);
180 		close(Bfildes(&db->b));
181 		Bterm(&db->b);
182 		free(db);
183 	}
184 }
185