1*50010e74Snonaka /* $NetBSD: data.c,v 1.6 2009/04/28 10:57:24 nonaka Exp $ */
2b8ce6e82Stakemura
3b8ce6e82Stakemura /*-
4b8ce6e82Stakemura * Copyright (c) 2002 TAKEMRUA Shin
5b8ce6e82Stakemura * All rights reserved.
6b8ce6e82Stakemura *
7b8ce6e82Stakemura * Redistribution and use in source and binary forms, with or without
8b8ce6e82Stakemura * modification, are permitted provided that the following conditions
9b8ce6e82Stakemura * are met:
10b8ce6e82Stakemura * 1. Redistributions of source code must retain the above copyright
11b8ce6e82Stakemura * notice, this list of conditions and the following disclaimer.
12b8ce6e82Stakemura * 2. Redistributions in binary form must reproduce the above copyright
13b8ce6e82Stakemura * notice, this list of conditions and the following disclaimer in the
14b8ce6e82Stakemura * documentation and/or other materials provided with the distribution.
155d1469bdSmartin * 3. Neither the name of The NetBSD Foundation nor the names of its
165d1469bdSmartin * contributors may be used to endorse or promote products derived
175d1469bdSmartin * from this software without specific prior written permission.
18b8ce6e82Stakemura *
19b8ce6e82Stakemura * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20b8ce6e82Stakemura * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21b8ce6e82Stakemura * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22b8ce6e82Stakemura * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23b8ce6e82Stakemura * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24b8ce6e82Stakemura * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25b8ce6e82Stakemura * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26b8ce6e82Stakemura * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27b8ce6e82Stakemura * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28b8ce6e82Stakemura * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29b8ce6e82Stakemura * POSSIBILITY OF SUCH DAMAGE.
30b8ce6e82Stakemura */
31b8ce6e82Stakemura
32b8ce6e82Stakemura #include <stdio.h>
33b8ce6e82Stakemura #include <strings.h>
34b8ce6e82Stakemura #include <stdlib.h>
35b8ce6e82Stakemura #include <time.h>
36b8ce6e82Stakemura #include <fcntl.h>
37b8ce6e82Stakemura #include <unistd.h>
38b8ce6e82Stakemura #include <sys/param.h>
39b8ce6e82Stakemura
40b8ce6e82Stakemura #include "tpctl.h"
41b8ce6e82Stakemura
42b8ce6e82Stakemura #ifndef lint
43b8ce6e82Stakemura #include <sys/cdefs.h>
44*50010e74Snonaka __RCSID("$NetBSD: data.c,v 1.6 2009/04/28 10:57:24 nonaka Exp $");
45b8ce6e82Stakemura #endif /* not lint */
46b8ce6e82Stakemura
47b8ce6e82Stakemura static void *
alloc(int size)48b8ce6e82Stakemura alloc(int size)
49b8ce6e82Stakemura {
50b8ce6e82Stakemura void *res;
51b8ce6e82Stakemura
52b8ce6e82Stakemura if ((res = malloc(size)) == NULL) {
53b8ce6e82Stakemura perror(getprogname());
54b8ce6e82Stakemura exit(EXIT_FAILURE);
55b8ce6e82Stakemura }
56b8ce6e82Stakemura
57b8ce6e82Stakemura return (res);
58b8ce6e82Stakemura }
59b8ce6e82Stakemura
60b8ce6e82Stakemura /*
61b8ce6e82Stakemura * duplicate string
62b8ce6e82Stakemura * trailing white space will be removed.
63b8ce6e82Stakemura */
64b8ce6e82Stakemura static char *
strdup_prune(char * s)65b8ce6e82Stakemura strdup_prune(char *s)
66b8ce6e82Stakemura {
67b8ce6e82Stakemura char *res, *tail;
68b8ce6e82Stakemura
69b8ce6e82Stakemura tail = &s[strlen(s) - 1];
70b8ce6e82Stakemura while (s <= tail && strchr(" \t", *tail) != NULL)
71b8ce6e82Stakemura tail--;
72b8ce6e82Stakemura
73b8ce6e82Stakemura res = alloc(tail - s + 2);
74b8ce6e82Stakemura memcpy(res, s, tail - s + 1);
75b8ce6e82Stakemura res[tail - s + 1] = '\0';
76b8ce6e82Stakemura
77b8ce6e82Stakemura return (res);
78b8ce6e82Stakemura }
79b8ce6e82Stakemura
80b8ce6e82Stakemura int
init_data(struct tpctl_data * data)81b8ce6e82Stakemura init_data(struct tpctl_data *data)
82b8ce6e82Stakemura {
83b8ce6e82Stakemura TAILQ_INIT(&data->list);
84b8ce6e82Stakemura
85b8ce6e82Stakemura return (0);
86b8ce6e82Stakemura }
87b8ce6e82Stakemura
88b8ce6e82Stakemura int
read_data(const char * filename,struct tpctl_data * data)89*50010e74Snonaka read_data(const char *filename, struct tpctl_data *data)
90b8ce6e82Stakemura {
91b8ce6e82Stakemura int res, len, n, i, t;
92b8ce6e82Stakemura char buf[MAXDATALEN + 2], *p, *p2;
93b8ce6e82Stakemura FILE *fp;
94b8ce6e82Stakemura struct tpctl_data_elem *elem;
95b8ce6e82Stakemura
96b8ce6e82Stakemura data->lineno = 0;
97b8ce6e82Stakemura
98b8ce6e82Stakemura if ((fp = fopen(filename, "r")) == NULL)
99b8ce6e82Stakemura return (ERR_NOFILE);
100b8ce6e82Stakemura
101b8ce6e82Stakemura while (fgets(buf, sizeof(buf), fp) != NULL) {
102b8ce6e82Stakemura data->lineno++;
103b8ce6e82Stakemura buf[MAXDATALEN + 1] = '\0';
104b8ce6e82Stakemura len = strlen(buf);
105b8ce6e82Stakemura if (MAXDATALEN < len) {
106b8ce6e82Stakemura res = ERR_SYNTAX;
107b8ce6e82Stakemura goto exit_func;
108b8ce6e82Stakemura }
109b8ce6e82Stakemura
110b8ce6e82Stakemura /* prune trailing space and newline */;
111b8ce6e82Stakemura p = &buf[len - 1];
112b8ce6e82Stakemura while (buf <= p && strchr(" \t\n\r", *p) != NULL)
113b8ce6e82Stakemura *p-- = '\0';
114b8ce6e82Stakemura
115b8ce6e82Stakemura /* skip space */;
116b8ce6e82Stakemura p = buf;
117b8ce6e82Stakemura while (*p != '\0' && strchr(" \t", *p) != NULL)
118b8ce6e82Stakemura p++;
119b8ce6e82Stakemura
120b8ce6e82Stakemura /* comment or empty line */
121b8ce6e82Stakemura if (*p == '#' || *p == '\0') {
122b8ce6e82Stakemura elem = alloc(sizeof(*elem));
123b8ce6e82Stakemura elem->type = TPCTL_COMMENT;
124b8ce6e82Stakemura elem->name = strdup_prune(buf);
125b8ce6e82Stakemura TAILQ_INSERT_TAIL(&data->list, elem, link);
126b8ce6e82Stakemura continue;
127b8ce6e82Stakemura }
128b8ce6e82Stakemura
129b8ce6e82Stakemura /* calibration parameter */
130b8ce6e82Stakemura elem = alloc(sizeof(*elem));
131b8ce6e82Stakemura elem->type = TPCTL_CALIBCOORDS;
132b8ce6e82Stakemura p2 = p;
133b8ce6e82Stakemura while (*p2 != ',' && *p2 != '\0')
134b8ce6e82Stakemura p2++;
135b8ce6e82Stakemura if (*p2 != ',') {
136b8ce6e82Stakemura /* missing ',' */
137b8ce6e82Stakemura res = ERR_SYNTAX;
138b8ce6e82Stakemura free(elem);
139b8ce6e82Stakemura goto exit_func;
140b8ce6e82Stakemura }
141b8ce6e82Stakemura *p2 = '\0';
142b8ce6e82Stakemura elem->name = strdup_prune(p);
143b8ce6e82Stakemura if (search_data(data, elem->name) != NULL) {
144b8ce6e82Stakemura free(elem);
145b8ce6e82Stakemura res = ERR_DUPNAME;
146b8ce6e82Stakemura goto exit_func;
147b8ce6e82Stakemura }
148b8ce6e82Stakemura TAILQ_INSERT_TAIL(&data->list, elem, link);
149b8ce6e82Stakemura p = p2 + 1;
150b8ce6e82Stakemura
15156d35e34Stakemura /*
15256d35e34Stakemura * minX, maxX, minY, maxY
15356d35e34Stakemura */
15456d35e34Stakemura for (i = 0; i < 4; i++) {
15556d35e34Stakemura t = strtol(p, &p2, 0);
15656d35e34Stakemura if (p == p2) {
15756d35e34Stakemura res = ERR_SYNTAX;
15856d35e34Stakemura goto exit_func;
15956d35e34Stakemura }
16056d35e34Stakemura p = p2;
16156d35e34Stakemura while (*p != '\0' && strchr(" \t", *p) != NULL)
16256d35e34Stakemura p++;
16356d35e34Stakemura if (*p != ',') {
16456d35e34Stakemura res = ERR_SYNTAX;
16556d35e34Stakemura goto exit_func;
16656d35e34Stakemura }
16756d35e34Stakemura p++;
16856d35e34Stakemura switch (i % 4) {
16956d35e34Stakemura case 0:
17056d35e34Stakemura elem->calibcoords.minx = t;
17156d35e34Stakemura break;
17256d35e34Stakemura case 1:
17356d35e34Stakemura elem->calibcoords.miny = t;
17456d35e34Stakemura break;
17556d35e34Stakemura case 2:
17656d35e34Stakemura elem->calibcoords.maxx = t;
17756d35e34Stakemura break;
17856d35e34Stakemura case 3:
17956d35e34Stakemura elem->calibcoords.maxy = t;
18056d35e34Stakemura break;
18156d35e34Stakemura }
18256d35e34Stakemura }
18356d35e34Stakemura
18456d35e34Stakemura /*
18556d35e34Stakemura * number of samples
18656d35e34Stakemura */
187b8ce6e82Stakemura n = strtol(p, &p2, 0);
188b8ce6e82Stakemura if (p == p2) {
189b8ce6e82Stakemura res = ERR_SYNTAX;
190b8ce6e82Stakemura goto exit_func;
191b8ce6e82Stakemura }
192b8ce6e82Stakemura p = p2;
193b8ce6e82Stakemura while (*p != '\0' && strchr(" \t", *p) != NULL)
194b8ce6e82Stakemura p++;
195b8ce6e82Stakemura
196b8ce6e82Stakemura if (WSMOUSE_CALIBCOORDS_MAX < n) {
197b8ce6e82Stakemura res = ERR_SYNTAX;
198b8ce6e82Stakemura goto exit_func;
199b8ce6e82Stakemura }
200b8ce6e82Stakemura elem->calibcoords.samplelen = n;
20156d35e34Stakemura
20256d35e34Stakemura /*
20356d35e34Stakemura * samples
20456d35e34Stakemura */
205b8ce6e82Stakemura for (i = 0; i < n * 4; i++) {
206b8ce6e82Stakemura if (*p != ',') {
207b8ce6e82Stakemura res = ERR_SYNTAX;
208b8ce6e82Stakemura goto exit_func;
209b8ce6e82Stakemura }
210b8ce6e82Stakemura p++;
211b8ce6e82Stakemura t = strtol(p, &p2, 0);
212b8ce6e82Stakemura if (p == p2) {
213b8ce6e82Stakemura res = ERR_SYNTAX;
214b8ce6e82Stakemura goto exit_func;
215b8ce6e82Stakemura }
216b8ce6e82Stakemura p = p2;
217b8ce6e82Stakemura while (*p != '\0' && strchr(" \t", *p) != NULL)
218b8ce6e82Stakemura p++;
219b8ce6e82Stakemura switch (i % 4) {
220b8ce6e82Stakemura case 0:
221b8ce6e82Stakemura elem->calibcoords.samples[i / 4].rawx = t;
222b8ce6e82Stakemura break;
223b8ce6e82Stakemura case 1:
224b8ce6e82Stakemura elem->calibcoords.samples[i / 4].rawy = t;
225b8ce6e82Stakemura break;
226b8ce6e82Stakemura case 2:
227b8ce6e82Stakemura elem->calibcoords.samples[i / 4].x = t;
228b8ce6e82Stakemura break;
229b8ce6e82Stakemura case 3:
230b8ce6e82Stakemura elem->calibcoords.samples[i / 4].y = t;
231b8ce6e82Stakemura break;
232b8ce6e82Stakemura }
233b8ce6e82Stakemura }
234b8ce6e82Stakemura if (*p != '\0') {
235b8ce6e82Stakemura res = ERR_SYNTAX;
236b8ce6e82Stakemura goto exit_func;
237b8ce6e82Stakemura }
238b8ce6e82Stakemura }
239b8ce6e82Stakemura
240b8ce6e82Stakemura if (ferror(fp))
241b8ce6e82Stakemura res = ERR_IO;
242b8ce6e82Stakemura else
243b8ce6e82Stakemura res = ERR_NONE;
244b8ce6e82Stakemura
245b8ce6e82Stakemura exit_func:
246b8ce6e82Stakemura fclose(fp);
247b8ce6e82Stakemura if (res != ERR_NONE) {
248b8ce6e82Stakemura free_data(data);
249b8ce6e82Stakemura }
250b8ce6e82Stakemura
251b8ce6e82Stakemura return (res);
252b8ce6e82Stakemura }
253b8ce6e82Stakemura
254b8ce6e82Stakemura int
write_data(const char * filename,struct tpctl_data * data)255*50010e74Snonaka write_data(const char *filename, struct tpctl_data *data)
256b8ce6e82Stakemura {
257b8ce6e82Stakemura int res, fd;
258b8ce6e82Stakemura FILE *fp;
259b8ce6e82Stakemura struct tpctl_data_elem *elem;
260*50010e74Snonaka char *p, tempfile[MAXPATHLEN + 1];
261b8ce6e82Stakemura
26207950b9fShe fd = 0; /* XXXGCC -Wuninitialized [hpcarm] */
26307950b9fShe
264b8ce6e82Stakemura if (filename == NULL) {
265b8ce6e82Stakemura fp = stdout;
266b8ce6e82Stakemura } else {
267*50010e74Snonaka strncpy(tempfile, filename, MAXPATHLEN);
268*50010e74Snonaka tempfile[MAXPATHLEN] = '\0';
269*50010e74Snonaka if ((p = strrchr(tempfile, '/')) == NULL) {
270*50010e74Snonaka strcpy(tempfile, TPCTL_TMP_FILENAME);
271b8ce6e82Stakemura } else {
272b8ce6e82Stakemura p++;
273b8ce6e82Stakemura if (MAXPATHLEN <
274*50010e74Snonaka p - tempfile + strlen(TPCTL_TMP_FILENAME))
275b8ce6e82Stakemura return (ERR_NOFILE);/* file name is too long */
276*50010e74Snonaka strcat(tempfile, TPCTL_TMP_FILENAME);
277b8ce6e82Stakemura }
278*50010e74Snonaka if ((fd = open(tempfile, O_RDWR|O_CREAT|O_EXCL, 0644)) < 0) {
279b8ce6e82Stakemura fprintf(stderr, "%s: can't create %s\n",
280*50010e74Snonaka getprogname(), tempfile);
281b8ce6e82Stakemura return (ERR_NOFILE);
282b8ce6e82Stakemura }
283b8ce6e82Stakemura if ((fp = fdopen(fd, "w")) == NULL) {
284b8ce6e82Stakemura perror("fdopen");
285b8ce6e82Stakemura exit(EXIT_FAILURE);
286b8ce6e82Stakemura }
287b8ce6e82Stakemura }
288b8ce6e82Stakemura
289b8ce6e82Stakemura TAILQ_FOREACH(elem, &data->list, link) {
290b8ce6e82Stakemura switch (elem->type) {
291b8ce6e82Stakemura case TPCTL_CALIBCOORDS:
292b8ce6e82Stakemura write_coords(fp, elem->name, &elem->calibcoords);
293b8ce6e82Stakemura break;
294b8ce6e82Stakemura case TPCTL_COMMENT:
295b8ce6e82Stakemura fprintf(fp, "%s\n", elem->name);
296b8ce6e82Stakemura break;
297b8ce6e82Stakemura default:
298b8ce6e82Stakemura fprintf(stderr, "%s: internal error\n", getprogname());
299b8ce6e82Stakemura exit(EXIT_FAILURE);
300b8ce6e82Stakemura break;
301b8ce6e82Stakemura }
302b8ce6e82Stakemura }
303b8ce6e82Stakemura
304b8ce6e82Stakemura if (filename != NULL) {
305b8ce6e82Stakemura fclose(fp);
306b8ce6e82Stakemura close(fd);
307*50010e74Snonaka if (rename(tempfile, filename) < 0) {
308*50010e74Snonaka unlink(tempfile);
309b8ce6e82Stakemura return (ERR_NOFILE);
310b8ce6e82Stakemura }
311b8ce6e82Stakemura }
312b8ce6e82Stakemura res = ERR_NONE;
313b8ce6e82Stakemura
314b8ce6e82Stakemura return (res);
315b8ce6e82Stakemura }
316b8ce6e82Stakemura
317b8ce6e82Stakemura void
write_coords(FILE * fp,char * name,struct wsmouse_calibcoords * coords)318b8ce6e82Stakemura write_coords(FILE *fp, char *name, struct wsmouse_calibcoords *coords)
319b8ce6e82Stakemura {
320b8ce6e82Stakemura int i;
321b8ce6e82Stakemura
32256d35e34Stakemura fprintf(fp, "%s,%d,%d,%d,%d,%d", name,
32356d35e34Stakemura coords->minx, coords->miny,
32456d35e34Stakemura coords->maxx, coords->maxy,
32556d35e34Stakemura coords->samplelen);
326b8ce6e82Stakemura for (i = 0; i < coords->samplelen; i++) {
327b8ce6e82Stakemura fprintf(fp, ",%d,%d,%d,%d",
328b8ce6e82Stakemura coords->samples[i].rawx,
329b8ce6e82Stakemura coords->samples[i].rawy,
330b8ce6e82Stakemura coords->samples[i].x,
331b8ce6e82Stakemura coords->samples[i].y);
332b8ce6e82Stakemura }
333b8ce6e82Stakemura fprintf(fp, "\n");
334b8ce6e82Stakemura }
335b8ce6e82Stakemura
336b8ce6e82Stakemura void
free_data(struct tpctl_data * data)337b8ce6e82Stakemura free_data(struct tpctl_data *data)
338b8ce6e82Stakemura {
339b8ce6e82Stakemura struct tpctl_data_elem *elem;
340b8ce6e82Stakemura
341b8ce6e82Stakemura while (!TAILQ_EMPTY(&data->list)) {
342b8ce6e82Stakemura elem = TAILQ_FIRST(&data->list);
343b8ce6e82Stakemura TAILQ_REMOVE(&data->list, elem, link);
344b8ce6e82Stakemura
345b8ce6e82Stakemura switch (elem->type) {
346b8ce6e82Stakemura case TPCTL_CALIBCOORDS:
347b8ce6e82Stakemura case TPCTL_COMMENT:
348b8ce6e82Stakemura free(elem->name);
349b8ce6e82Stakemura break;
350b8ce6e82Stakemura default:
351b8ce6e82Stakemura fprintf(stderr, "%s: internal error\n", getprogname());
352b8ce6e82Stakemura exit(EXIT_FAILURE);
353b8ce6e82Stakemura break;
354b8ce6e82Stakemura }
355b8ce6e82Stakemura }
356b8ce6e82Stakemura }
357b8ce6e82Stakemura
358b8ce6e82Stakemura int
replace_data(struct tpctl_data * data,char * name,struct wsmouse_calibcoords * calibcoords)359b8ce6e82Stakemura replace_data(struct tpctl_data *data, char *name, struct wsmouse_calibcoords *calibcoords)
360b8ce6e82Stakemura {
361b8ce6e82Stakemura struct tpctl_data_elem *elem;
362b8ce6e82Stakemura
363b8ce6e82Stakemura TAILQ_FOREACH(elem, &data->list, link) {
364b8ce6e82Stakemura if (elem->type == TPCTL_CALIBCOORDS &&
365b8ce6e82Stakemura strcmp(name, elem->name) == 0) {
366b8ce6e82Stakemura elem->calibcoords = *calibcoords;
367b8ce6e82Stakemura return (0);
368b8ce6e82Stakemura }
369b8ce6e82Stakemura }
370b8ce6e82Stakemura
371b8ce6e82Stakemura elem = alloc(sizeof(*elem));
372b8ce6e82Stakemura elem->type = TPCTL_CALIBCOORDS;
373b8ce6e82Stakemura elem->name = strdup(name);
374b8ce6e82Stakemura elem->calibcoords = *calibcoords;
375b8ce6e82Stakemura if (elem->name == NULL) {
376b8ce6e82Stakemura perror(getprogname());
377b8ce6e82Stakemura exit(EXIT_FAILURE);
378b8ce6e82Stakemura }
379b8ce6e82Stakemura TAILQ_INSERT_TAIL(&data->list, elem, link);
380b8ce6e82Stakemura
381b8ce6e82Stakemura return (1);
382b8ce6e82Stakemura }
383b8ce6e82Stakemura
384b8ce6e82Stakemura struct wsmouse_calibcoords *
search_data(struct tpctl_data * data,char * name)385b8ce6e82Stakemura search_data(struct tpctl_data *data, char *name)
386b8ce6e82Stakemura {
387b8ce6e82Stakemura struct tpctl_data_elem *elem;
388b8ce6e82Stakemura
389b8ce6e82Stakemura TAILQ_FOREACH(elem, &data->list, link) {
390b8ce6e82Stakemura if (elem->type == TPCTL_CALIBCOORDS &&
391b8ce6e82Stakemura strcmp(name, elem->name) == 0) {
392b8ce6e82Stakemura return (&elem->calibcoords);
393b8ce6e82Stakemura }
394b8ce6e82Stakemura }
395b8ce6e82Stakemura
396b8ce6e82Stakemura return (NULL);
397b8ce6e82Stakemura }
398