xref: /netbsd/usr.sbin/tpctl/data.c (revision c4a72b64)
1 /*	$NetBSD: data.c,v 1.1 2002/08/27 14:12:16 takemura Exp $	*/
2 
3 /*-
4  * Copyright (c) 2002 TAKEMRUA Shin
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of The NetBSD Foundation nor the names of its
16  *    contributors may be used to endorse or promote products derived
17  *    from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <stdio.h>
33 #include <strings.h>
34 #include <stdlib.h>
35 #include <time.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <sys/param.h>
39 
40 #include "tpctl.h"
41 
42 #ifndef lint
43 #include <sys/cdefs.h>
44 __RCSID("$NetBSD: data.c,v 1.1 2002/08/27 14:12:16 takemura Exp $");
45 #endif /* not lint */
46 
47 static void *
48 alloc(int size)
49 {
50 	void *res;
51 
52 	if ((res = malloc(size)) == NULL) {
53 		perror(getprogname());
54 		exit(EXIT_FAILURE);
55 	}
56 
57 	return (res);
58 }
59 
60 /*
61  * duplicate string
62  * trailing white space will be removed.
63  */
64 static char *
65 strdup_prune(char *s)
66 {
67 	char *res, *tail;
68 
69 	tail = &s[strlen(s) - 1];
70 	while (s <= tail && strchr(" \t", *tail) != NULL)
71 		tail--;
72 
73 	res = alloc(tail - s + 2);
74 	memcpy(res, s, tail - s + 1);
75 	res[tail - s + 1] = '\0';
76 
77 	return (res);
78 }
79 
80 int
81 init_data(struct tpctl_data *data)
82 {
83 	TAILQ_INIT(&data->list);
84 
85 	return (0);
86 }
87 
88 int
89 read_data(char *filename, struct tpctl_data *data)
90 {
91 	int res, len, n, i, t;
92 	char buf[MAXDATALEN + 2], *p, *p2;
93 	FILE *fp;
94 	struct tpctl_data_elem *elem;
95 
96 	data->lineno = 0;
97 
98 	if ((fp = fopen(filename, "r")) == NULL)
99 		return (ERR_NOFILE);
100 
101 	while (fgets(buf, sizeof(buf), fp) != NULL) {
102 		data->lineno++;
103 		buf[MAXDATALEN + 1] = '\0';
104 		len = strlen(buf);
105 		if (MAXDATALEN < len) {
106 			res = ERR_SYNTAX;
107 			goto exit_func;
108 		}
109 
110 		/* prune trailing space and newline */;
111 		p = &buf[len - 1];
112 		while (buf <= p && strchr(" \t\n\r", *p) != NULL)
113 			*p-- = '\0';
114 
115 		/* skip space */;
116 		p = buf;
117 		while (*p != '\0' && strchr(" \t", *p) != NULL)
118 			p++;
119 
120 		/* comment or empty line */
121 		if (*p == '#' || *p == '\0') {
122 			elem = alloc(sizeof(*elem));
123 			elem->type = TPCTL_COMMENT;
124 			elem->name = strdup_prune(buf);
125 			TAILQ_INSERT_TAIL(&data->list, elem, link);
126 			continue;
127 		}
128 
129 		/* calibration parameter */
130 		elem = alloc(sizeof(*elem));
131 		elem->type = TPCTL_CALIBCOORDS;
132 		p2 = p;
133 		while (*p2 != ',' && *p2 != '\0')
134 			p2++;
135 		if (*p2 != ',') {
136 			/* missing ',' */
137 			res = ERR_SYNTAX;
138 			free(elem);
139 			goto exit_func;
140 		}
141 		*p2 = '\0';
142 		elem->name = strdup_prune(p);
143 		if (search_data(data, elem->name) != NULL) {
144 			free(elem);
145 			res = ERR_DUPNAME;
146 			goto exit_func;
147 		}
148 		TAILQ_INSERT_TAIL(&data->list, elem, link);
149 		p = p2 + 1;
150 
151 		n = strtol(p, &p2, 0);
152 		if (p == p2) {
153 			res = ERR_SYNTAX;
154 			goto exit_func;
155 		}
156 		p = p2;
157 		while (*p != '\0' && strchr(" \t", *p) != NULL)
158 			p++;
159 
160 		if (WSMOUSE_CALIBCOORDS_MAX < n) {
161 			res = ERR_SYNTAX;
162 			goto exit_func;
163 		}
164 
165 		elem->calibcoords.samplelen = n;
166 		for (i = 0; i < n * 4; i++) {
167 			if (*p != ',') {
168 				res = ERR_SYNTAX;
169 				goto exit_func;
170 			}
171 			p++;
172 			t = strtol(p, &p2, 0);
173 			if (p == p2) {
174 				res = ERR_SYNTAX;
175 				goto exit_func;
176 			}
177 			p = p2;
178 			while (*p != '\0' && strchr(" \t", *p) != NULL)
179 				p++;
180 			switch (i % 4) {
181 			case 0:
182 				elem->calibcoords.samples[i / 4].rawx = t;
183 				break;
184 			case 1:
185 				elem->calibcoords.samples[i / 4].rawy = t;
186 				break;
187 			case 2:
188 				elem->calibcoords.samples[i / 4].x = t;
189 				break;
190 			case 3:
191 				elem->calibcoords.samples[i / 4].y = t;
192 				break;
193 			}
194 		}
195 		if (*p != '\0') {
196 			res = ERR_SYNTAX;
197 			goto exit_func;
198 		}
199 	}
200 
201 	if (ferror(fp))
202 		res = ERR_IO;
203 	else
204 		res = ERR_NONE;
205 
206  exit_func:
207 	fclose(fp);
208 	if (res != ERR_NONE) {
209 		free_data(data);
210 	}
211 
212 	return (res);
213 }
214 
215 int
216 write_data(char *filename, struct tpctl_data *data)
217 {
218 	int res, fd;
219 	FILE *fp;
220 	struct tpctl_data_elem *elem;
221 	char *p, tmpfile[MAXPATHLEN + 1];
222 
223 	if (filename == NULL) {
224 		fp = stdout;
225 	} else {
226 		strncpy(tmpfile, filename, MAXPATHLEN);
227 		tmpfile[MAXPATHLEN] = '\0';
228 		if ((p = strrchr(tmpfile, '/')) == NULL) {
229 			strcpy(tmpfile, TPCTL_TMP_FILENAME);
230 		} else {
231 			p++;
232 			if (MAXPATHLEN <
233 			    p - tmpfile + strlen(TPCTL_TMP_FILENAME))
234 				return (ERR_NOFILE);/* file name is too long */
235 			strcat(tmpfile, TPCTL_TMP_FILENAME);
236 		}
237 		if ((fd = open(tmpfile, O_RDWR|O_CREAT|O_EXCL, 0644)) < 0) {
238 			fprintf(stderr, "%s: can't create %s\n",
239 			    getprogname(), tmpfile);
240 			return (ERR_NOFILE);
241 		}
242 		if ((fp = fdopen(fd, "w")) == NULL) {
243 			perror("fdopen");
244 			exit(EXIT_FAILURE);
245 		}
246 	}
247 
248 	TAILQ_FOREACH(elem, &data->list, link) {
249 		switch (elem->type) {
250 		case TPCTL_CALIBCOORDS:
251 			write_coords(fp, elem->name, &elem->calibcoords);
252 			break;
253 		case TPCTL_COMMENT:
254 			fprintf(fp, "%s\n", elem->name);
255 			break;
256 		default:
257 			fprintf(stderr, "%s: internal error\n", getprogname());
258 			exit(EXIT_FAILURE);
259 			break;
260 		}
261 	}
262 
263 	if (filename != NULL) {
264 		fclose(fp);
265 		close(fd);
266 		if (rename(tmpfile, filename) < 0) {
267 			unlink(tmpfile);
268 			return (ERR_NOFILE);
269 		}
270 	}
271 	res = ERR_NONE;
272 
273 	return (res);
274 }
275 
276 void
277 write_coords(FILE *fp, char *name, struct wsmouse_calibcoords *coords)
278 {
279 	int i;
280 
281 	fprintf(fp, "%s,%d", name, coords->samplelen);
282 	for (i = 0; i < coords->samplelen; i++) {
283 		fprintf(fp, ",%d,%d,%d,%d",
284 		    coords->samples[i].rawx,
285 		    coords->samples[i].rawy,
286 		    coords->samples[i].x,
287 		    coords->samples[i].y);
288 	}
289 	fprintf(fp, "\n");
290 }
291 
292 void
293 free_data(struct tpctl_data *data)
294 {
295 	struct tpctl_data_elem *elem;
296 
297 	while (!TAILQ_EMPTY(&data->list)) {
298 		elem = TAILQ_FIRST(&data->list);
299 		TAILQ_REMOVE(&data->list, elem, link);
300 
301 		switch (elem->type) {
302 		case TPCTL_CALIBCOORDS:
303 		case TPCTL_COMMENT:
304 			free(elem->name);
305 			break;
306 		default:
307 			fprintf(stderr, "%s: internal error\n", getprogname());
308 			exit(EXIT_FAILURE);
309 			break;
310 		}
311 	}
312 }
313 
314 int
315 replace_data(struct tpctl_data *data, char *name, struct wsmouse_calibcoords *calibcoords)
316 {
317 	struct tpctl_data_elem *elem;
318 
319 	TAILQ_FOREACH(elem, &data->list, link) {
320 		if (elem->type == TPCTL_CALIBCOORDS &&
321 		    strcmp(name, elem->name) == 0) {
322 			elem->calibcoords = *calibcoords;
323 			return (0);
324 		}
325 	}
326 
327 	elem = alloc(sizeof(*elem));
328 	elem->type = TPCTL_CALIBCOORDS;
329 	elem->name = strdup(name);
330 	elem->calibcoords = *calibcoords;
331 	if (elem->name == NULL) {
332 		perror(getprogname());
333 		exit(EXIT_FAILURE);
334 	}
335 	TAILQ_INSERT_TAIL(&data->list, elem, link);
336 
337 	return (1);
338 }
339 
340 struct wsmouse_calibcoords *
341 search_data(struct tpctl_data *data, char *name)
342 {
343 	struct tpctl_data_elem *elem;
344 
345 	TAILQ_FOREACH(elem, &data->list, link) {
346 		if (elem->type == TPCTL_CALIBCOORDS &&
347 		    strcmp(name, elem->name) == 0) {
348 			return (&elem->calibcoords);
349 		}
350 	}
351 
352 	return (NULL);
353 }
354