1 /*
2  * Copyright (c) 1992 Eric P. Allman.
3  * Copyright (c) 1992 Regents of the University of California.
4  * All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char sccsid[] = "@(#)makemap.c	5.1 (Berkeley) 11/15/92";
11 #endif /* not lint */
12 
13 #include <stdio.h>
14 #include <sysexits.h>
15 #include <sys/file.h>
16 #include <ctype.h>
17 #include <string.h>
18 #include "useful.h"
19 #include "conf.h"
20 
21 #ifdef DBM_MAP
22 #include <ndbm.h>
23 #endif
24 
25 #if defined(HASH_MAP) || defined(BTREE_MAP)
26 #include <db.h>
27 #endif
28 
29 enum type { T_DBM, T_BTREE, T_HASH, T_ERR, T_UNKNOWN };
30 
31 union dbent
32 {
33 #ifdef DBM_MAP
34 	datum	dbm;
35 #endif
36 #if defined(HASH_MAP) || defined(BTREE_MAP)
37 	DBT	db;
38 #endif
39 	struct
40 	{
41 		char	*data;
42 		int	size;
43 	} xx;
44 };
45 
46 #define BUFSIZE		1024
47 
48 main(argc, argv)
49 	int argc;
50 	char **argv;
51 {
52 	char *progname;
53 	bool inclnull = FALSE;
54 	bool notrunc = FALSE;
55 	bool allowreplace = FALSE;
56 	bool verbose = FALSE;
57 	int exitstat;
58 	int opt;
59 	char *typename;
60 	char *mapname;
61 	int lineno;
62 	int st;
63 	int mode;
64 	enum type type;
65 	union
66 	{
67 #ifdef DBM_MAP
68 		DBM	*dbm;
69 #endif
70 #if defined(HASH_MAP) || defined(BTREE_MAP)
71 		DB	*db;
72 #endif
73 		void	*dbx;
74 	} dbp;
75 	union dbent key, val;
76 	char ibuf[BUFSIZE];
77 	extern char *optarg;
78 	extern int optind;
79 
80 	progname = argv[0];
81 
82 	while ((opt = getopt(argc, argv, "Norv")) != EOF)
83 	{
84 		switch (opt)
85 		{
86 		  case 'N':
87 			inclnull = TRUE;
88 			break;
89 
90 		  case 'o':
91 			notrunc = TRUE;
92 			break;
93 
94 		  case 'r':
95 			allowreplace = TRUE;
96 			break;
97 
98 		  case 'v':
99 			verbose = TRUE;
100 			break;
101 
102 		  default:
103 			type = T_ERR;
104 			break;
105 		}
106 	}
107 
108 	argc -= optind;
109 	argv += optind;
110 	if (argc != 2)
111 		type = T_ERR;
112 	else
113 	{
114 		typename = argv[0];
115 		mapname = argv[1];
116 
117 		if (strcmp(typename, "dbm") == 0)
118 			type = T_DBM;
119 		else if (strcmp(typename, "btree") == 0)
120 			type = T_BTREE;
121 		else if (strcmp(typename, "hash") == 0)
122 			type = T_HASH;
123 		else
124 			type = T_UNKNOWN;
125 	}
126 
127 	switch (type)
128 	{
129 	  case T_ERR:
130 		fprintf(stderr, "Usage: %s [-N] [-o] [-v] type mapname\n", progname);
131 		exit(EX_USAGE);
132 
133 	  case T_UNKNOWN:
134 		fprintf(stderr, "%s: Unknown database type %s\n",
135 			progname, typename);
136 		exit(EX_USAGE);
137 
138 #ifndef DBM_MAP
139 	  case T_DBM:
140 #endif
141 #ifndef BTREE_MAP
142 	  case T_BTREE:
143 #endif
144 #ifndef HASH_MAP
145 	  case T_HASH:
146 #endif
147 		fprintf(stderr, "%s: Type %s not supported in this version\n",
148 			progname, typename);
149 		exit(EX_UNAVAILABLE);
150 	}
151 
152 	/*
153 	**  Create the database.
154 	*/
155 
156 	mode = O_RDWR;
157 	if (!notrunc)
158 		mode |= O_CREAT|O_TRUNC;
159 	switch (type)
160 	{
161 #ifdef DBM_MAP
162 	  case T_DBM:
163 		dbp.dbm = dbm_open(mapname, mode, 0644);
164 		break;
165 #endif
166 
167 #ifdef HASH_MAP
168 	  case T_HASH:
169 		dbp.db = dbopen(mapname, mode, 0644, DB_HASH, NULL);
170 		break;
171 #endif
172 
173 #ifdef BTREE_MAP
174 	  case T_BTREE:
175 		dbp.db = dbopen(mapname, mode, 0644, DB_BTREE, NULL);
176 		break;
177 #endif
178 
179 	  default:
180 		fprintf(stderr, "%s: internal error: type %d\n", progname, type);
181 		exit(EX_SOFTWARE);
182 	}
183 
184 	if (dbp.dbx == NULL)
185 	{
186 		fprintf(stderr, "%s: cannot create type %s map %s\n",
187 			progname, typename, mapname);
188 		exit(EX_CANTCREAT);
189 	}
190 
191 	/*
192 	**  Copy the data
193 	*/
194 
195 	lineno = 0;
196 	exitstat = EX_OK;
197 	while (fgets(ibuf, sizeof ibuf, stdin) != NULL)
198 	{
199 		register char *p;
200 
201 		lineno++;
202 
203 		/*
204 		**  Parse the line.
205 		*/
206 
207 		p = strchr(ibuf, '\n');
208 		if (*p != '\0')
209 			*p = '\0';
210 		if (ibuf[0] == '\0' || ibuf[0] == '#')
211 			continue;
212 		if (isspace(ibuf[0]))
213 		{
214 			fprintf(stderr, "%s: %s: line %d: syntax error (leading space)\n",
215 				progname, mapname, lineno);
216 			continue;
217 		}
218 		key.xx.data = ibuf;
219 		for (p = ibuf; *p != '\0' && !isspace(*p); p++)
220 			continue;
221 		key.xx.size = p - key.xx.data;
222 		if (inclnull)
223 			key.xx.size++;
224 		if (*p != '\0')
225 			*p++ = '\0';
226 		while (isspace(*p))
227 			p++;
228 		if (*p == '\0')
229 		{
230 			fprintf(stderr, "%s: %s: line %d: no RHS for LHS %s\n",
231 				progname, mapname, lineno, key.xx.data);
232 			continue;
233 		}
234 		val.xx.data = p;
235 		val.xx.size = strlen(p);
236 		if (inclnull)
237 			val.xx.size++;
238 
239 		/*
240 		**  Do the database insert.
241 		*/
242 
243 		if (verbose)
244 		{
245 			printf("key=`%s', val=`%s'\n", key.xx.data, val.xx.data);
246 		}
247 
248 		switch (type)
249 		{
250 #ifdef DBM_MAP
251 		  case T_DBM:
252 			st = dbm_store(dbp.dbm, key.dbm, val.dbm,
253 					allowreplace ? DBM_REPLACE : DBM_INSERT);
254 			break;
255 #endif
256 
257 #if defined(BTREE_MAP) || defined(HASH_MAP)
258 		  case T_BTREE:
259 		  case T_HASH:
260 			st = (*dbp.db->put)(dbp.db, &key.db, &val.db,
261 					allowreplace ? 0 : R_NOOVERWRITE);
262 			break;
263 #endif
264 		}
265 
266 		if (st < 0)
267 		{
268 			fprintf(stderr, "%s: %s: line %d: key %s: put error\n",
269 				progname, mapname, lineno, key.xx.data);
270 			perror(mapname);
271 			exitstat = EX_IOERR;
272 		}
273 		else if (st > 0)
274 		{
275 			fprintf(stderr, "%s: %s: line %d: key %s: duplicate key\n",
276 				progname, mapname, lineno, key.xx.data);
277 		}
278 	}
279 
280 	/*
281 	**  Now close the database.
282 	*/
283 
284 	switch (type)
285 	{
286 #ifdef DBM_MAP
287 	  case T_DBM:
288 		dbm_close(dbp.dbm);
289 		break;
290 #endif
291 
292 #if defined(HASH_MAP) || defined(BTREE_MAP)
293 	  case T_HASH:
294 	  case T_BTREE:
295 		if ((*dbp.db->close)(dbp.db) < 0)
296 		{
297 			fprintf(stderr, "%s: %s: error on close\n",
298 				progname, mapname);
299 			perror(mapname);
300 			exitstat = EX_IOERR;
301 		}
302 #endif
303 	}
304 
305 	exit (exitstat);
306 }
307