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