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	6.1 (Berkeley) 12/21/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 	bool foldcase = FALSE;
58 	int exitstat;
59 	int opt;
60 	char *typename;
61 	char *mapname;
62 	int lineno;
63 	int st;
64 	int mode;
65 	enum type type;
66 	union
67 	{
68 #ifdef DBM_MAP
69 		DBM	*dbm;
70 #endif
71 #if defined(HASH_MAP) || defined(BTREE_MAP)
72 		DB	*db;
73 #endif
74 		void	*dbx;
75 	} dbp;
76 	union dbent key, val;
77 	char ibuf[BUFSIZE];
78 	extern char *optarg;
79 	extern int optind;
80 
81 	progname = argv[0];
82 
83 	while ((opt = getopt(argc, argv, "Nforv")) != EOF)
84 	{
85 		switch (opt)
86 		{
87 		  case 'N':
88 			inclnull = TRUE;
89 			break;
90 
91 		  case 'f':
92 			foldcase = TRUE;
93 			break;
94 
95 		  case 'o':
96 			notrunc = TRUE;
97 			break;
98 
99 		  case 'r':
100 			allowreplace = TRUE;
101 			break;
102 
103 		  case 'v':
104 			verbose = TRUE;
105 			break;
106 
107 		  default:
108 			type = T_ERR;
109 			break;
110 		}
111 	}
112 
113 	argc -= optind;
114 	argv += optind;
115 	if (argc != 2)
116 		type = T_ERR;
117 	else
118 	{
119 		typename = argv[0];
120 		mapname = argv[1];
121 
122 		if (strcmp(typename, "dbm") == 0)
123 			type = T_DBM;
124 		else if (strcmp(typename, "btree") == 0)
125 			type = T_BTREE;
126 		else if (strcmp(typename, "hash") == 0)
127 			type = T_HASH;
128 		else
129 			type = T_UNKNOWN;
130 	}
131 
132 	switch (type)
133 	{
134 	  case T_ERR:
135 		fprintf(stderr, "Usage: %s [-N] [-o] [-v] type mapname\n", progname);
136 		exit(EX_USAGE);
137 
138 	  case T_UNKNOWN:
139 		fprintf(stderr, "%s: Unknown database type %s\n",
140 			progname, typename);
141 		exit(EX_USAGE);
142 
143 #ifndef DBM_MAP
144 	  case T_DBM:
145 #endif
146 #ifndef BTREE_MAP
147 	  case T_BTREE:
148 #endif
149 #ifndef HASH_MAP
150 	  case T_HASH:
151 #endif
152 		fprintf(stderr, "%s: Type %s not supported in this version\n",
153 			progname, typename);
154 		exit(EX_UNAVAILABLE);
155 	}
156 
157 	/*
158 	**  Create the database.
159 	*/
160 
161 	mode = O_RDWR;
162 	if (!notrunc)
163 		mode |= O_CREAT|O_TRUNC;
164 	switch (type)
165 	{
166 #ifdef DBM_MAP
167 	  case T_DBM:
168 		dbp.dbm = dbm_open(mapname, mode, 0644);
169 		break;
170 #endif
171 
172 #ifdef HASH_MAP
173 	  case T_HASH:
174 		dbp.db = dbopen(mapname, mode, 0644, DB_HASH, NULL);
175 		break;
176 #endif
177 
178 #ifdef BTREE_MAP
179 	  case T_BTREE:
180 		dbp.db = dbopen(mapname, mode, 0644, DB_BTREE, NULL);
181 		break;
182 #endif
183 
184 	  default:
185 		fprintf(stderr, "%s: internal error: type %d\n", progname, type);
186 		exit(EX_SOFTWARE);
187 	}
188 
189 	if (dbp.dbx == NULL)
190 	{
191 		fprintf(stderr, "%s: cannot create type %s map %s\n",
192 			progname, typename, mapname);
193 		exit(EX_CANTCREAT);
194 	}
195 
196 	/*
197 	**  Copy the data
198 	*/
199 
200 	lineno = 0;
201 	exitstat = EX_OK;
202 	while (fgets(ibuf, sizeof ibuf, stdin) != NULL)
203 	{
204 		register char *p;
205 
206 		lineno++;
207 
208 		/*
209 		**  Parse the line.
210 		*/
211 
212 		p = strchr(ibuf, '\n');
213 		if (*p != '\0')
214 			*p = '\0';
215 		if (ibuf[0] == '\0' || ibuf[0] == '#')
216 			continue;
217 		if (isspace(ibuf[0]))
218 		{
219 			fprintf(stderr, "%s: %s: line %d: syntax error (leading space)\n",
220 				progname, mapname, lineno);
221 			continue;
222 		}
223 		key.xx.data = ibuf;
224 		for (p = ibuf; *p != '\0' && !isspace(*p); p++)
225 		{
226 			if (foldcase && isupper(*p))
227 				*p = tolower(*p);
228 		}
229 		key.xx.size = p - key.xx.data;
230 		if (inclnull)
231 			key.xx.size++;
232 		if (*p != '\0')
233 			*p++ = '\0';
234 		while (isspace(*p))
235 			p++;
236 		if (*p == '\0')
237 		{
238 			fprintf(stderr, "%s: %s: line %d: no RHS for LHS %s\n",
239 				progname, mapname, lineno, key.xx.data);
240 			continue;
241 		}
242 		val.xx.data = p;
243 		val.xx.size = strlen(p);
244 		if (inclnull)
245 			val.xx.size++;
246 
247 		/*
248 		**  Do the database insert.
249 		*/
250 
251 		if (verbose)
252 		{
253 			printf("key=`%s', val=`%s'\n", key.xx.data, val.xx.data);
254 		}
255 
256 		switch (type)
257 		{
258 #ifdef DBM_MAP
259 		  case T_DBM:
260 			st = dbm_store(dbp.dbm, key.dbm, val.dbm,
261 					allowreplace ? DBM_REPLACE : DBM_INSERT);
262 			break;
263 #endif
264 
265 #if defined(BTREE_MAP) || defined(HASH_MAP)
266 		  case T_BTREE:
267 		  case T_HASH:
268 			st = (*dbp.db->put)(dbp.db, &key.db, &val.db,
269 					allowreplace ? 0 : R_NOOVERWRITE);
270 			break;
271 #endif
272 		}
273 
274 		if (st < 0)
275 		{
276 			fprintf(stderr, "%s: %s: line %d: key %s: put error\n",
277 				progname, mapname, lineno, key.xx.data);
278 			perror(mapname);
279 			exitstat = EX_IOERR;
280 		}
281 		else if (st > 0)
282 		{
283 			fprintf(stderr, "%s: %s: line %d: key %s: duplicate key\n",
284 				progname, mapname, lineno, key.xx.data);
285 		}
286 	}
287 
288 	/*
289 	**  Now close the database.
290 	*/
291 
292 	switch (type)
293 	{
294 #ifdef DBM_MAP
295 	  case T_DBM:
296 		dbm_close(dbp.dbm);
297 		break;
298 #endif
299 
300 #if defined(HASH_MAP) || defined(BTREE_MAP)
301 	  case T_HASH:
302 	  case T_BTREE:
303 		if ((*dbp.db->close)(dbp.db) < 0)
304 		{
305 			fprintf(stderr, "%s: %s: error on close\n",
306 				progname, mapname);
307 			perror(mapname);
308 			exitstat = EX_IOERR;
309 		}
310 #endif
311 	}
312 
313 	exit (exitstat);
314 }
315