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