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