1 /*
2  * Copyright (c) 1990 Jan-Simon Pendry
3  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
4  * Copyright (c) 1990 The Regents of the University of California.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Jan-Simon Pendry at Imperial College, London.
9  *
10  * %sccs.include.redist.c%
11  *
12  *	@(#)mk-amd-map.c	5.5 (Berkeley) 02/09/92
13  *
14  * $Id: mk-amd-map.c,v 5.2.2.1 1992/02/09 15:09:18 jsp beta $
15  */
16 
17 /*
18  * Convert a file map into an ndbm map
19  */
20 
21 #ifndef lint
22 char copyright[] = "\
23 @(#)Copyright (c) 1990 Jan-Simon Pendry\n\
24 @(#)Copyright (c) 1990 Imperial College of Science, Technology & Medicine\n\
25 @(#)Copyright (c) 1990 The Regents of the University of California.\n\
26 @(#)All rights reserved.\n";
27 #endif /* not lint */
28 
29 #ifndef lint
30 static char rcsid[] = "$Id: mk-amd-map.c,v 5.2.2.1 1992/02/09 15:09:18 jsp beta $";
31 static char sccsid[] = "@(#)mk-amd-map.c	5.5 (Berkeley) 02/09/92";
32 #endif /* not lint */
33 
34 #include "am.h"
35 
36 #ifndef SIGINT
37 #include <signal.h>
38 #endif
39 
40 #ifdef OS_HAS_NDBM
41 #define HAS_DATABASE
42 #include <ndbm.h>
43 
44 #define create_database(name) dbm_open(name, O_RDWR|O_CREAT, 0444)
45 
46 static int store_data(db, k, v)
47 voidp db;
48 char *k, *v;
49 {
50 	datum key, val;
51 
52 	key.dptr = k; val.dptr = v;
53 	key.dsize = strlen(k) + 1;
54 	val.dsize = strlen(v) + 1;
55 	return dbm_store((DBM *) db, key, val, DBM_INSERT);
56 }
57 
58 #endif /* OS_HAS_NDBM */
59 
60 #ifdef HAS_DATABASE
61 #include <fcntl.h>
62 #include <ctype.h>
63 
64 static int read_line(buf, size, fp)
65 char *buf;
66 int size;
67 FILE *fp;
68 {
69 	int done = 0;
70 
71 	do {
72 		while (fgets(buf, size, fp)) {
73 			int len = strlen(buf);
74 			done += len;
75 			if (len > 1 && buf[len-2] == '\\' &&
76 					buf[len-1] == '\n') {
77 				int ch;
78 				buf += len - 2;
79 				size -= len - 2;
80 				*buf = '\n'; buf[1] = '\0';
81 				/*
82 				 * Skip leading white space on next line
83 				 */
84 				while ((ch = getc(fp)) != EOF &&
85 					isascii(ch) && isspace(ch))
86 						;
87 				(void) ungetc(ch, fp);
88 			} else {
89 				return done;
90 			}
91 		}
92 	} while (size > 0 && !feof(fp));
93 
94 	return done;
95 }
96 
97 /*
98  * Read through a map
99  */
100 static int read_file(fp, map, db)
101 FILE *fp;
102 char *map;
103 voidp db;
104 {
105 	char key_val[2048];
106 	int chuck = 0;
107 	int line_no = 0;
108 	int errs = 0;
109 
110 	while (read_line(key_val, sizeof(key_val), fp)) {
111 		char *kp;
112 		char *cp;
113 		char *hash;
114 		int len = strlen(key_val);
115 		line_no++;
116 
117 		/*
118 		 * Make sure we got the whole line
119 		 */
120 		if (key_val[len-1] != '\n') {
121 			fprintf(stderr, "line %d in \"%s\" is too long", line_no, map);
122 			chuck = 1;
123 		} else {
124 			key_val[len-1] = '\0';
125 		}
126 
127 		/*
128 		 * Strip comments
129 		 */
130 		hash = strchr(key_val, '#');
131 		if (hash)
132 			*hash = '\0';
133 
134 		/*
135 		 * Find start of key
136 		 */
137 		for (kp = key_val; *kp && isascii(*kp) && isspace(*kp); kp++)
138 			;
139 
140 		/*
141 		 * Ignore blank lines
142 		 */
143 		if (!*kp)
144 			goto again;
145 
146 		/*
147 		 * Find end of key
148 		 */
149 		for (cp = kp; *cp&&(!isascii(*cp)||!isspace(*cp)); cp++)
150 			;
151 
152 		/*
153 		 * Check whether key matches, or whether
154 		 * the entry is a wildcard entry.
155 		 */
156 		if (*cp)
157 			*cp++ = '\0';
158 		while (*cp && isascii(*cp) && isspace(*cp))
159 			cp++;
160 		if (*kp == '+') {
161 			fprintf(stderr, "Can't interpolate %s\n", kp);
162 			errs++;
163 		} else if (*cp) {
164 			if (db) {
165 				if (store_data(db, kp, cp) < 0) {
166 					fprintf(stderr, "Could store %s -> %s\n", kp, cp);
167 					errs++;
168 				}
169 			} else {
170 				printf("%s\t%s\n", kp, cp);
171 			}
172 		} else {
173 			fprintf(stderr, "%s: line %d has no value field", map, line_no);
174 			errs++;
175 		}
176 
177 again:
178 		/*
179 		 * If the last read didn't get a whole line then
180 		 * throw away the remainder before continuing...
181 		 */
182 		if (chuck) {
183 			while (fgets(key_val, sizeof(key_val), fp) &&
184 				!strchr(key_val, '\n'))
185 					;
186 			chuck = 0;
187 		}
188 	}
189 	return errs;
190 }
191 
192 static int remove_file(f)
193 char *f;
194 {
195 	if (unlink(f) < 0 && errno != ENOENT)
196 		return -1;
197 	return 0;
198 }
199 
200 main(argc, argv)
201 int argc;
202 char *argv[];
203 {
204 	FILE *mapf;
205 	char *map;
206 	int rc = 0;
207 	DBM *mapd;
208 	static char maptmp[] = "dbmXXXXXX";
209 	char maptpag[16], maptdir[16];
210 	char *mappag, *mapdir;
211 	int len;
212 	char *sl;
213 	int printit = 0;
214 	int usage = 0;
215 	int ch;
216 	extern int optind;
217 
218 	while ((ch = getopt(argc, argv, "p")) != EOF)
219 	switch (ch) {
220 	case 'p':
221 		printit = 1;
222 		break;
223 	default:
224 		usage++;
225 		break;
226 	}
227 
228 	if (usage || optind != (argc - 1)) {
229 		fputs("Usage: mk-amd-map [-p] file-map\n", stderr);
230 		exit(1);
231 	}
232 
233 	map = argv[optind];
234 	sl = strrchr(map, '/');
235 	if (sl) {
236 		*sl = '\0';
237 		if (chdir(map) < 0) {
238 			fputs("Can't chdir to ", stderr);
239 			perror(map);
240 			exit(1);
241 		}
242 		map = sl + 1;
243 	}
244 
245 	if (!printit) {
246 		len = strlen(map);
247 		mappag = (char *) malloc(len + 5);
248 		mapdir = (char *) malloc(len + 5);
249 		if (!mappag || !mapdir) {
250 			perror("mk-amd-map: malloc");
251 			exit(1);
252 		}
253 		mktemp(maptmp);
254 		sprintf(maptpag, "%s.pag", maptmp);
255 		sprintf(maptdir, "%s.dir", maptmp);
256 		if (remove_file(maptpag) < 0 || remove_file(maptdir) < 0) {
257 			fprintf(stderr, "Can't remove existing temporary files; %s and", maptpag);
258 			perror(maptdir);
259 			exit(1);
260 		}
261 	}
262 
263 	mapf =  fopen(map, "r");
264 	if (mapf && !printit)
265 		mapd = create_database(maptmp);
266 	else
267 		mapd = 0;
268 
269 #ifndef DEBUG
270 	signal(SIGINT, SIG_IGN);
271 #endif
272 
273 	if (mapd || printit) {
274 		int error = read_file(mapf, map, mapd);
275 		(void) fclose(mapf);
276 		if (printit) {
277 			if (error) {
278 				fprintf(stderr, "Error creating ndbm map for %s\n", map);
279 				rc = 1;
280 			}
281 		} else {
282 			if (error) {
283 				fprintf(stderr, "Error reading source file  %s\n", map);
284 				rc = 1;
285 			} else {
286 				sprintf(mappag, "%s.pag", map);
287 				sprintf(mapdir, "%s.dir", map);
288 				if (rename(maptpag, mappag) < 0) {
289 					fprintf(stderr, "Couldn't rename %s to ", maptpag);
290 					perror(mappag);
291 					/* Throw away the temporary map */
292 					unlink(maptpag);
293 					unlink(maptdir);
294 					rc = 1;
295 				} else if (rename(maptdir, mapdir) < 0) {
296 					fprintf(stderr, "Couldn't rename %s to ", maptdir);
297 					perror(mapdir);
298 					/* Put the .pag file back */
299 					rename(mappag, maptpag);
300 					/* Throw away remaining part of original map */
301 					unlink(mapdir);
302 					fprintf(stderr,
303 						"WARNING: existing map \"%s.{dir,pag}\" destroyed\n",
304 						map);
305 					rc = 1;
306 				}
307 			}
308 		}
309 	} else {
310 		fprintf(stderr, "Can't open \"%s.{dir,pag}\" for ", map);
311 		perror("writing");
312 		rc = 1;
313 	}
314 	exit(rc);
315 }
316 #else
317 main()
318 {
319 	fputs("mk-amd-map: This system does not support hashed database files\n", stderr);
320 	exit(1);
321 }
322 #endif /* HAS_DATABASE */
323