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.6.1.1 (Berkeley) 03/06/95";
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 		size_t	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 		if (dbp.db != NULL)
204 			(void) (*dbp.db->sync)(dbp.db, 0);
205 		break;
206 
207 	  case T_BTREE:
208 		dbp.db = dbopen(mapname, mode, 0644, DB_BTREE, NULL);
209 		if (dbp.db != NULL)
210 			(void) (*dbp.db->sync)(dbp.db, 0);
211 		break;
212 #endif
213 
214 	  default:
215 		fprintf(stderr, "%s: internal error: type %d\n", progname, type);
216 		exit(EX_SOFTWARE);
217 	}
218 
219 	if (dbp.dbx == NULL)
220 	{
221 		fprintf(stderr, "%s: cannot create type %s map %s\n",
222 			progname, typename, mapname);
223 		exit(EX_CANTCREAT);
224 	}
225 
226 	/*
227 	**  Copy the data
228 	*/
229 
230 	lineno = 0;
231 	exitstat = EX_OK;
232 	while (fgets(ibuf, sizeof ibuf, stdin) != NULL)
233 	{
234 		register char *p;
235 
236 		lineno++;
237 
238 		/*
239 		**  Parse the line.
240 		*/
241 
242 		p = strchr(ibuf, '\n');
243 		if (p != NULL)
244 			*p = '\0';
245 		else if (!feof(stdin))
246 		{
247 			fprintf(stderr, "%s: %s: line %d: line too long (%d bytes max)\n",
248 				progname, mapname, lineno, sizeof ibuf);
249 			continue;
250 		}
251 
252 		if (ibuf[0] == '\0' || ibuf[0] == '#')
253 			continue;
254 		if (isspace(ibuf[0]))
255 		{
256 			fprintf(stderr, "%s: %s: line %d: syntax error (leading space)\n",
257 				progname, mapname, lineno);
258 			continue;
259 		}
260 		key.xx.data = ibuf;
261 		for (p = ibuf; *p != '\0' && !isspace(*p); p++)
262 		{
263 			if (foldcase && isupper(*p))
264 				*p = tolower(*p);
265 		}
266 		key.xx.size = p - key.xx.data;
267 		if (inclnull)
268 			key.xx.size++;
269 		if (*p != '\0')
270 			*p++ = '\0';
271 		while (isspace(*p))
272 			p++;
273 		if (*p == '\0')
274 		{
275 			fprintf(stderr, "%s: %s: line %d: no RHS for LHS %s\n",
276 				progname, mapname, lineno, key.xx.data);
277 			continue;
278 		}
279 		val.xx.data = p;
280 		val.xx.size = strlen(p);
281 		if (inclnull)
282 			val.xx.size++;
283 
284 		/*
285 		**  Do the database insert.
286 		*/
287 
288 		if (verbose)
289 		{
290 			printf("key=`%s', val=`%s'\n", key.xx.data, val.xx.data);
291 		}
292 
293 		switch (type)
294 		{
295 #ifdef NDBM
296 		  case T_DBM:
297 			st = dbm_store(dbp.dbm, key.dbm, val.dbm,
298 					allowreplace ? DBM_REPLACE : DBM_INSERT);
299 			break;
300 #endif
301 
302 #ifdef NEWDB
303 		  case T_BTREE:
304 		  case T_HASH:
305 			st = (*dbp.db->put)(dbp.db, &key.db, &val.db,
306 					allowreplace ? 0 : R_NOOVERWRITE);
307 			break;
308 #endif
309 		}
310 
311 		if (st < 0)
312 		{
313 			fprintf(stderr, "%s: %s: line %d: key %s: put error\n",
314 				progname, mapname, lineno, key.xx.data);
315 			perror(mapname);
316 			exitstat = EX_IOERR;
317 		}
318 		else if (st > 0)
319 		{
320 			fprintf(stderr, "%s: %s: line %d: key %s: duplicate key\n",
321 				progname, mapname, lineno, key.xx.data);
322 		}
323 	}
324 
325 	/*
326 	**  Now close the database.
327 	*/
328 
329 	switch (type)
330 	{
331 #ifdef NDBM
332 	  case T_DBM:
333 		dbm_close(dbp.dbm);
334 		break;
335 #endif
336 
337 #ifdef NEWDB
338 	  case T_HASH:
339 	  case T_BTREE:
340 		if ((*dbp.db->close)(dbp.db) < 0)
341 		{
342 			fprintf(stderr, "%s: %s: error on close\n",
343 				progname, mapname);
344 			perror(mapname);
345 			exitstat = EX_IOERR;
346 		}
347 #endif
348 	}
349 
350 	exit (exitstat);
351 }
352