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