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