1/* $NetBSD: data.c,v 1.5 2008/05/10 15:31:05 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 * 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.5 2008/05/10 15:31:05 martin Exp $"); 45#endif /* not lint */ 46 47static void * 48alloc(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 */ 64static char * 65strdup_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 80int 81init_data(struct tpctl_data *data) 82{ 83 TAILQ_INIT(&data->list); 84 85 return (0); 86} 87 88int 89read_data(const 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 254int 255write_data(const char *filename, struct tpctl_data *data) 256{ 257 int res, fd; 258 FILE *fp; 259 struct tpctl_data_elem *elem; 260 char *p, tempfile[MAXPATHLEN + 1]; 261 262 fd = 0; /* XXXGCC -Wuninitialized [hpcarm] */ 263 264 if (filename == NULL) { 265 fp = stdout; 266 } else { 267 strncpy(tempfile, filename, MAXPATHLEN); 268 tempfile[MAXPATHLEN] = '\0'; 269 if ((p = strrchr(tempfile, '/')) == NULL) { 270 strcpy(tempfile, TPCTL_TMP_FILENAME); 271 } else { 272 p++; 273 if (MAXPATHLEN < 274 p - tempfile + strlen(TPCTL_TMP_FILENAME)) 275 return (ERR_NOFILE);/* file name is too long */ 276 strcat(tempfile, TPCTL_TMP_FILENAME); 277 } 278 if ((fd = open(tempfile, O_RDWR|O_CREAT|O_EXCL, 0644)) < 0) { 279 fprintf(stderr, "%s: can't create %s\n", 280 getprogname(), tempfile); 281 return (ERR_NOFILE); 282 } 283 if ((fp = fdopen(fd, "w")) == NULL) { 284 perror("fdopen"); 285 exit(EXIT_FAILURE); 286 } 287 } 288 289 TAILQ_FOREACH(elem, &data->list, link) { 290 switch (elem->type) { 291 case TPCTL_CALIBCOORDS: 292 write_coords(fp, elem->name, &elem->calibcoords); 293 break; 294 case TPCTL_COMMENT: 295 fprintf(fp, "%s\n", elem->name); 296 break; 297 default: 298 fprintf(stderr, "%s: internal error\n", getprogname()); 299 exit(EXIT_FAILURE); 300 break; 301 } 302 } 303 304 if (filename != NULL) { 305 fclose(fp); 306 close(fd); 307 if (rename(tempfile, filename) < 0) { 308 unlink(tempfile); 309 return (ERR_NOFILE); 310 } 311 } 312 res = ERR_NONE; 313 314 return (res); 315} 316 317void 318write_coords(FILE *fp, char *name, struct wsmouse_calibcoords *coords) 319{ 320 int i; 321 322 fprintf(fp, "%s,%d,%d,%d,%d,%d", name, 323 coords->minx, coords->miny, 324 coords->maxx, coords->maxy, 325 coords->samplelen); 326 for (i = 0; i < coords->samplelen; i++) { 327 fprintf(fp, ",%d,%d,%d,%d", 328 coords->samples[i].rawx, 329 coords->samples[i].rawy, 330 coords->samples[i].x, 331 coords->samples[i].y); 332 } 333 fprintf(fp, "\n"); 334} 335 336void 337free_data(struct tpctl_data *data) 338{ 339 struct tpctl_data_elem *elem; 340 341 while (!TAILQ_EMPTY(&data->list)) { 342 elem = TAILQ_FIRST(&data->list); 343 TAILQ_REMOVE(&data->list, elem, link); 344 345 switch (elem->type) { 346 case TPCTL_CALIBCOORDS: 347 case TPCTL_COMMENT: 348 free(elem->name); 349 break; 350 default: 351 fprintf(stderr, "%s: internal error\n", getprogname()); 352 exit(EXIT_FAILURE); 353 break; 354 } 355 } 356} 357 358int 359replace_data(struct tpctl_data *data, char *name, struct wsmouse_calibcoords *calibcoords) 360{ 361 struct tpctl_data_elem *elem; 362 363 TAILQ_FOREACH(elem, &data->list, link) { 364 if (elem->type == TPCTL_CALIBCOORDS && 365 strcmp(name, elem->name) == 0) { 366 elem->calibcoords = *calibcoords; 367 return (0); 368 } 369 } 370 371 elem = alloc(sizeof(*elem)); 372 elem->type = TPCTL_CALIBCOORDS; 373 elem->name = strdup(name); 374 elem->calibcoords = *calibcoords; 375 if (elem->name == NULL) { 376 perror(getprogname()); 377 exit(EXIT_FAILURE); 378 } 379 TAILQ_INSERT_TAIL(&data->list, elem, link); 380 381 return (1); 382} 383 384struct wsmouse_calibcoords * 385search_data(struct tpctl_data *data, char *name) 386{ 387 struct tpctl_data_elem *elem; 388 389 TAILQ_FOREACH(elem, &data->list, link) { 390 if (elem->type == TPCTL_CALIBCOORDS && 391 strcmp(name, elem->name) == 0) { 392 return (&elem->calibcoords); 393 } 394 } 395 396 return (NULL); 397} 398