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.1 (Berkeley) 06/07/93";
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 NDBM
22 #include <ndbm.h>
23 #endif
24 
25 #ifdef NEWDB
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 NDBM
34 	datum	dbm;
35 #endif
36 #ifdef NEWDB
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 NDBM
69 		DBM	*dbm;
70 #endif
71 #ifdef NEWDB
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 NDBM
144 	  case T_DBM:
145 #endif
146 #ifndef NEWDB
147 	  case T_BTREE:
148 	  case T_HASH:
149 #endif
150 		fprintf(stderr, "%s: Type %s not supported in this version\n",
151 			progname, typename);
152 		exit(EX_UNAVAILABLE);
153 	}
154 
155 	/*
156 	**  Create the database.
157 	*/
158 
159 	mode = O_RDWR;
160 	if (!notrunc)
161 		mode |= O_CREAT|O_TRUNC;
162 	switch (type)
163 	{
164 #ifdef NDBM
165 	  case T_DBM:
166 		dbp.dbm = dbm_open(mapname, mode, 0644);
167 		break;
168 #endif
169 
170 #ifdef NEWDB
171 	  case T_HASH:
172 		dbp.db = dbopen(mapname, mode, 0644, DB_HASH, NULL);
173 		break;
174 
175 	  case T_BTREE:
176 		dbp.db = dbopen(mapname, mode, 0644, DB_BTREE, NULL);
177 		break;
178 #endif
179 
180 	  default:
181 		fprintf(stderr, "%s: internal error: type %d\n", progname, type);
182 		exit(EX_SOFTWARE);
183 	}
184 
185 	if (dbp.dbx == NULL)
186 	{
187 		fprintf(stderr, "%s: cannot create type %s map %s\n",
188 			progname, typename, mapname);
189 		exit(EX_CANTCREAT);
190 	}
191 
192 	/*
193 	**  Copy the data
194 	*/
195 
196 	lineno = 0;
197 	exitstat = EX_OK;
198 	while (fgets(ibuf, sizeof ibuf, stdin) != NULL)
199 	{
200 		register char *p;
201 
202 		lineno++;
203 
204 		/*
205 		**  Parse the line.
206 		*/
207 
208 		p = strchr(ibuf, '\n');
209 		if (*p != '\0')
210 			*p = '\0';
211 		if (ibuf[0] == '\0' || ibuf[0] == '#')
212 			continue;
213 		if (isspace(ibuf[0]))
214 		{
215 			fprintf(stderr, "%s: %s: line %d: syntax error (leading space)\n",
216 				progname, mapname, lineno);
217 			continue;
218 		}
219 		key.xx.data = ibuf;
220 		for (p = ibuf; *p != '\0' && !isspace(*p); p++)
221 		{
222 			if (foldcase && isupper(*p))
223 				*p = tolower(*p);
224 		}
225 		key.xx.size = p - key.xx.data;
226 		if (inclnull)
227 			key.xx.size++;
228 		if (*p != '\0')
229 			*p++ = '\0';
230 		while (isspace(*p))
231 			p++;
232 		if (*p == '\0')
233 		{
234 			fprintf(stderr, "%s: %s: line %d: no RHS for LHS %s\n",
235 				progname, mapname, lineno, key.xx.data);
236 			continue;
237 		}
238 		val.xx.data = p;
239 		val.xx.size = strlen(p);
240 		if (inclnull)
241 			val.xx.size++;
242 
243 		/*
244 		**  Do the database insert.
245 		*/
246 
247 		if (verbose)
248 		{
249 			printf("key=`%s', val=`%s'\n", key.xx.data, val.xx.data);
250 		}
251 
252 		switch (type)
253 		{
254 #ifdef NDBM
255 		  case T_DBM:
256 			st = dbm_store(dbp.dbm, key.dbm, val.dbm,
257 					allowreplace ? DBM_REPLACE : DBM_INSERT);
258 			break;
259 #endif
260 
261 #ifdef NEWDB
262 		  case T_BTREE:
263 		  case T_HASH:
264 			st = (*dbp.db->put)(dbp.db, &key.db, &val.db,
265 					allowreplace ? 0 : R_NOOVERWRITE);
266 			break;
267 #endif
268 		}
269 
270 		if (st < 0)
271 		{
272 			fprintf(stderr, "%s: %s: line %d: key %s: put error\n",
273 				progname, mapname, lineno, key.xx.data);
274 			perror(mapname);
275 			exitstat = EX_IOERR;
276 		}
277 		else if (st > 0)
278 		{
279 			fprintf(stderr, "%s: %s: line %d: key %s: duplicate key\n",
280 				progname, mapname, lineno, key.xx.data);
281 		}
282 	}
283 
284 	/*
285 	**  Now close the database.
286 	*/
287 
288 	switch (type)
289 	{
290 #ifdef NDBM
291 	  case T_DBM:
292 		dbm_close(dbp.dbm);
293 		break;
294 #endif
295 
296 #ifdef NEWDB
297 	  case T_HASH:
298 	  case T_BTREE:
299 		if ((*dbp.db->close)(dbp.db) < 0)
300 		{
301 			fprintf(stderr, "%s: %s: error on close\n",
302 				progname, mapname);
303 			perror(mapname);
304 			exitstat = EX_IOERR;
305 		}
306 #endif
307 	}
308 
309 	exit (exitstat);
310 }
311