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