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