1 /* $NetBSD: data.c,v 1.2 2002/12/15 09:13:21 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.2 2002/12/15 09:13:21 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 /* 152 * minX, maxX, minY, maxY 153 */ 154 for (i = 0; i < 4; i++) { 155 t = strtol(p, &p2, 0); 156 if (p == p2) { 157 res = ERR_SYNTAX; 158 goto exit_func; 159 } 160 p = p2; 161 while (*p != '\0' && strchr(" \t", *p) != NULL) 162 p++; 163 if (*p != ',') { 164 res = ERR_SYNTAX; 165 goto exit_func; 166 } 167 p++; 168 switch (i % 4) { 169 case 0: 170 elem->calibcoords.minx = t; 171 break; 172 case 1: 173 elem->calibcoords.miny = t; 174 break; 175 case 2: 176 elem->calibcoords.maxx = t; 177 break; 178 case 3: 179 elem->calibcoords.maxy = t; 180 break; 181 } 182 } 183 184 /* 185 * number of samples 186 */ 187 n = strtol(p, &p2, 0); 188 if (p == p2) { 189 res = ERR_SYNTAX; 190 goto exit_func; 191 } 192 p = p2; 193 while (*p != '\0' && strchr(" \t", *p) != NULL) 194 p++; 195 196 if (WSMOUSE_CALIBCOORDS_MAX < n) { 197 res = ERR_SYNTAX; 198 goto exit_func; 199 } 200 elem->calibcoords.samplelen = n; 201 202 /* 203 * samples 204 */ 205 for (i = 0; i < n * 4; i++) { 206 if (*p != ',') { 207 res = ERR_SYNTAX; 208 goto exit_func; 209 } 210 p++; 211 t = strtol(p, &p2, 0); 212 if (p == p2) { 213 res = ERR_SYNTAX; 214 goto exit_func; 215 } 216 p = p2; 217 while (*p != '\0' && strchr(" \t", *p) != NULL) 218 p++; 219 switch (i % 4) { 220 case 0: 221 elem->calibcoords.samples[i / 4].rawx = t; 222 break; 223 case 1: 224 elem->calibcoords.samples[i / 4].rawy = t; 225 break; 226 case 2: 227 elem->calibcoords.samples[i / 4].x = t; 228 break; 229 case 3: 230 elem->calibcoords.samples[i / 4].y = t; 231 break; 232 } 233 } 234 if (*p != '\0') { 235 res = ERR_SYNTAX; 236 goto exit_func; 237 } 238 } 239 240 if (ferror(fp)) 241 res = ERR_IO; 242 else 243 res = ERR_NONE; 244 245 exit_func: 246 fclose(fp); 247 if (res != ERR_NONE) { 248 free_data(data); 249 } 250 251 return (res); 252 } 253 254 int 255 write_data(char *filename, struct tpctl_data *data) 256 { 257 int res, fd; 258 FILE *fp; 259 struct tpctl_data_elem *elem; 260 char *p, tmpfile[MAXPATHLEN + 1]; 261 262 if (filename == NULL) { 263 fp = stdout; 264 } else { 265 strncpy(tmpfile, filename, MAXPATHLEN); 266 tmpfile[MAXPATHLEN] = '\0'; 267 if ((p = strrchr(tmpfile, '/')) == NULL) { 268 strcpy(tmpfile, TPCTL_TMP_FILENAME); 269 } else { 270 p++; 271 if (MAXPATHLEN < 272 p - tmpfile + strlen(TPCTL_TMP_FILENAME)) 273 return (ERR_NOFILE);/* file name is too long */ 274 strcat(tmpfile, TPCTL_TMP_FILENAME); 275 } 276 if ((fd = open(tmpfile, O_RDWR|O_CREAT|O_EXCL, 0644)) < 0) { 277 fprintf(stderr, "%s: can't create %s\n", 278 getprogname(), tmpfile); 279 return (ERR_NOFILE); 280 } 281 if ((fp = fdopen(fd, "w")) == NULL) { 282 perror("fdopen"); 283 exit(EXIT_FAILURE); 284 } 285 } 286 287 TAILQ_FOREACH(elem, &data->list, link) { 288 switch (elem->type) { 289 case TPCTL_CALIBCOORDS: 290 write_coords(fp, elem->name, &elem->calibcoords); 291 break; 292 case TPCTL_COMMENT: 293 fprintf(fp, "%s\n", elem->name); 294 break; 295 default: 296 fprintf(stderr, "%s: internal error\n", getprogname()); 297 exit(EXIT_FAILURE); 298 break; 299 } 300 } 301 302 if (filename != NULL) { 303 fclose(fp); 304 close(fd); 305 if (rename(tmpfile, filename) < 0) { 306 unlink(tmpfile); 307 return (ERR_NOFILE); 308 } 309 } 310 res = ERR_NONE; 311 312 return (res); 313 } 314 315 void 316 write_coords(FILE *fp, char *name, struct wsmouse_calibcoords *coords) 317 { 318 int i; 319 320 fprintf(fp, "%s,%d,%d,%d,%d,%d", name, 321 coords->minx, coords->miny, 322 coords->maxx, coords->maxy, 323 coords->samplelen); 324 for (i = 0; i < coords->samplelen; i++) { 325 fprintf(fp, ",%d,%d,%d,%d", 326 coords->samples[i].rawx, 327 coords->samples[i].rawy, 328 coords->samples[i].x, 329 coords->samples[i].y); 330 } 331 fprintf(fp, "\n"); 332 } 333 334 void 335 free_data(struct tpctl_data *data) 336 { 337 struct tpctl_data_elem *elem; 338 339 while (!TAILQ_EMPTY(&data->list)) { 340 elem = TAILQ_FIRST(&data->list); 341 TAILQ_REMOVE(&data->list, elem, link); 342 343 switch (elem->type) { 344 case TPCTL_CALIBCOORDS: 345 case TPCTL_COMMENT: 346 free(elem->name); 347 break; 348 default: 349 fprintf(stderr, "%s: internal error\n", getprogname()); 350 exit(EXIT_FAILURE); 351 break; 352 } 353 } 354 } 355 356 int 357 replace_data(struct tpctl_data *data, char *name, struct wsmouse_calibcoords *calibcoords) 358 { 359 struct tpctl_data_elem *elem; 360 361 TAILQ_FOREACH(elem, &data->list, link) { 362 if (elem->type == TPCTL_CALIBCOORDS && 363 strcmp(name, elem->name) == 0) { 364 elem->calibcoords = *calibcoords; 365 return (0); 366 } 367 } 368 369 elem = alloc(sizeof(*elem)); 370 elem->type = TPCTL_CALIBCOORDS; 371 elem->name = strdup(name); 372 elem->calibcoords = *calibcoords; 373 if (elem->name == NULL) { 374 perror(getprogname()); 375 exit(EXIT_FAILURE); 376 } 377 TAILQ_INSERT_TAIL(&data->list, elem, link); 378 379 return (1); 380 } 381 382 struct wsmouse_calibcoords * 383 search_data(struct tpctl_data *data, char *name) 384 { 385 struct tpctl_data_elem *elem; 386 387 TAILQ_FOREACH(elem, &data->list, link) { 388 if (elem->type == TPCTL_CALIBCOORDS && 389 strcmp(name, elem->name) == 0) { 390 return (&elem->calibcoords); 391 } 392 } 393 394 return (NULL); 395 } 396