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