/src/data.c
C | 481 lines | 355 code | 35 blank | 91 comment | 165 complexity | e5988abe18451e480135a6b247be6c07 MD5 | raw file
1/* 2 * Copyright (C) 1989-95 GROUPE BULL 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to 6 * deal in the Software without restriction, including without limitation the 7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 * sell copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 * 21 * Except as contained in this notice, the name of GROUPE BULL shall not be 22 * used in advertising or otherwise to promote the sale, use or other dealings 23 * in this Software without prior written authorization from GROUPE BULL. 24 */ 25 26/*****************************************************************************\ 27* data.c: * 28* * 29* XPM library * 30* IO utilities * 31* * 32* Developed by Arnaud Le Hors * 33\*****************************************************************************/ 34 35/* October 2004, source code review by Thomas Biege <thomas@suse.de> */ 36 37#ifndef CXPMPROG 38#if 0 39/* Official version number */ 40static char *RCS_Version = "$XpmVersion: 3.4k $"; 41 42/* Internal version number */ 43static char *RCS_Id = "Id: xpm.shar,v 3.71 1998/03/19 19:47:14 lehors Exp $"; 44#endif 45#ifdef HAVE_CONFIG_H 46#include <config.h> 47#endif 48#include "XpmI.h" 49#endif 50#include <ctype.h> 51 52#ifndef CXPMPROG 53#define Getc(data, file) getc(file) 54#define Ungetc(data, c, file) ungetc(c, file) 55#endif 56 57static int 58ParseComment(xpmData *data) 59{ 60 if (data->type == XPMBUFFER) { 61 register char c; 62 register unsigned int n = 0; 63 unsigned int notend; 64 char *s; 65 const char *s2; 66 67 s = data->Comment; 68 *s = data->Bcmt[0]; 69 70 /* skip the string beginning comment */ 71 s2 = data->Bcmt; 72 do { 73 c = *data->cptr++; 74 *++s = c; 75 n++; 76 s2++; 77 } while (c == *s2 && *s2 != '\0' && c); 78 79 if (*s2 != '\0') { 80 /* this wasn't the beginning of a comment */ 81 data->cptr -= n; 82 return 0; 83 } 84 /* store comment */ 85 data->Comment[0] = *s; 86 s = data->Comment; 87 notend = 1; 88 n = 0; 89 while (notend) { 90 s2 = data->Ecmt; 91 while (*s != *s2 && c) { 92 c = *data->cptr++; 93 if (n == XPMMAXCMTLEN - 1) { /* forget it */ 94 s = data->Comment; 95 n = 0; 96 } 97 *++s = c; 98 n++; 99 } 100 data->CommentLength = n; 101 do { 102 c = *data->cptr++; 103 if (n == XPMMAXCMTLEN - 1) { /* forget it */ 104 s = data->Comment; 105 n = 0; 106 } 107 *++s = c; 108 n++; 109 s2++; 110 } while (c == *s2 && *s2 != '\0' && c); 111 if (*s2 == '\0') { 112 /* this is the end of the comment */ 113 notend = 0; 114 data->cptr--; 115 } 116 } 117 return 0; 118 } else { 119 FILE *file = data->stream.file; 120 register int c; 121 register unsigned int n = 0, a; 122 unsigned int notend; 123 char *s; 124 const char *s2; 125 126 s = data->Comment; 127 *s = data->Bcmt[0]; 128 129 /* skip the string beginning comment */ 130 s2 = data->Bcmt; 131 do { 132 c = Getc(data, file); 133 *++s = c; 134 n++; 135 s2++; 136 } while (c == *s2 && *s2 != '\0' && c != EOF); 137 138 if (*s2 != '\0') { 139 /* this wasn't the beginning of a comment */ 140 /* put characters back in the order that we got them */ 141 for (a = n; a > 0; a--, s--) 142 Ungetc(data, *s, file); 143 return 0; 144 } 145 /* store comment */ 146 data->Comment[0] = *s; 147 s = data->Comment; 148 notend = 1; 149 n = 0; 150 while (notend) { 151 s2 = data->Ecmt; 152 while (*s != *s2 && c != EOF) { 153 c = Getc(data, file); 154 if (n == XPMMAXCMTLEN - 1) { /* forget it */ 155 s = data->Comment; 156 n = 0; 157 } 158 *++s = c; 159 n++; 160 } 161 data->CommentLength = n; 162 do { 163 c = Getc(data, file); 164 if (n == XPMMAXCMTLEN - 1) { /* forget it */ 165 s = data->Comment; 166 n = 0; 167 } 168 *++s = c; 169 n++; 170 s2++; 171 } while (c == *s2 && *s2 != '\0' && c != EOF); 172 if (*s2 == '\0') { 173 /* this is the end of the comment */ 174 notend = 0; 175 Ungetc(data, *s, file); 176 } 177 } 178 return 0; 179 } 180} 181 182/* 183 * skip to the end of the current string and the beginning of the next one 184 */ 185int 186xpmNextString(xpmData *data) 187{ 188 if (!data->type) 189 data->cptr = (data->stream.data)[++data->line]; 190 else if (data->type == XPMBUFFER) { 191 register char c; 192 193 /* get to the end of the current string */ 194 if (data->Eos) 195 while ((c = *data->cptr++) && c != data->Eos); 196 197 /* 198 * then get to the beginning of the next string looking for possible 199 * comment 200 */ 201 if (data->Bos) { 202 while ((c = *data->cptr++) && c != data->Bos) 203 if (data->Bcmt && c == data->Bcmt[0]) 204 ParseComment(data); 205 } else if (data->Bcmt) { /* XPM2 natural */ 206 while ((c = *data->cptr++) == data->Bcmt[0]) 207 ParseComment(data); 208 data->cptr--; 209 } 210 } else { 211 register int c; 212 FILE *file = data->stream.file; 213 214 /* get to the end of the current string */ 215 if (data->Eos) 216 while ((c = Getc(data, file)) != data->Eos && c != EOF); 217 218 /* 219 * then get to the beginning of the next string looking for possible 220 * comment 221 */ 222 if (data->Bos) { 223 while ((c = Getc(data, file)) != data->Bos && c != EOF) 224 if (data->Bcmt && c == data->Bcmt[0]) 225 ParseComment(data); 226 227 } else if (data->Bcmt) { /* XPM2 natural */ 228 while ((c = Getc(data, file)) == data->Bcmt[0]) 229 ParseComment(data); 230 Ungetc(data, c, file); 231 } 232 } 233 return 0; 234} 235 236 237/* 238 * skip whitespace and return the following word 239 */ 240unsigned int 241xpmNextWord( 242 xpmData *data, 243 char *buf, 244 unsigned int buflen) 245{ 246 register unsigned int n = 0; 247 int c; 248 249 if (!data->type || data->type == XPMBUFFER) { 250 while (isspace(c = *data->cptr) && c != data->Eos) 251 data->cptr++; 252 do { 253 c = *data->cptr++; 254 *buf++ = c; 255 n++; 256 } while (!isspace(c) && c != data->Eos && n < buflen); 257 n--; 258 data->cptr--; 259 } else { 260 FILE *file = data->stream.file; 261 262 while ((c = Getc(data, file)) != EOF && isspace(c) && c != data->Eos); 263 while (!isspace(c) && c != data->Eos && c != EOF && n < buflen) { 264 *buf++ = c; 265 n++; 266 c = Getc(data, file); 267 } 268 Ungetc(data, c, file); 269 } 270 return (n); /* this returns bytes read + 1 */ 271} 272 273/* 274 * skip whitespace and compute the following unsigned int, 275 * returns 1 if one is found and 0 if not 276 */ 277int 278xpmNextUI( 279 xpmData *data, 280 unsigned int *ui_return) 281{ 282 char buf[BUFSIZ]; 283 int l; 284 285 l = xpmNextWord(data, buf, BUFSIZ); 286 return xpmatoui(buf, l, ui_return); 287} 288 289/* 290 * return end of string - WARNING: malloc! 291 */ 292int 293xpmGetString( 294 xpmData *data, 295 char **sptr, 296 unsigned int *l) 297{ 298 unsigned int i, n = 0; 299 int c; 300 char *p = NULL, *q, buf[BUFSIZ]; 301 302 if (!data->type || data->type == XPMBUFFER) { 303 if (data->cptr) { 304 char *start = data->cptr; 305 while ((c = *data->cptr) && c != data->Eos) 306 data->cptr++; 307 n = data->cptr - start + 1; 308 p = (char *) XpmMalloc(n); 309 if (!p) 310 return (XpmNoMemory); 311 strncpy(p, start, n); 312 if (data->type) /* XPMBUFFER */ 313 p[n - 1] = '\0'; 314 } 315 } else { 316 FILE *file = data->stream.file; 317 318 if ((c = Getc(data, file)) == EOF) 319 return (XpmFileInvalid); 320 321 i = 0; 322 q = buf; 323 p = (char *) XpmMalloc(1); 324 while (c != data->Eos && c != EOF) { 325 if (i == BUFSIZ) { 326 /* get to the end of the buffer */ 327 /* malloc needed memory */ 328 q = (char *) XpmRealloc(p, n + i); 329 if (!q) { 330 XpmFree(p); 331 return (XpmNoMemory); 332 } 333 p = q; 334 q += n; 335 /* and copy what we already have */ 336 strncpy(q, buf, i); 337 n += i; 338 i = 0; 339 q = buf; 340 } 341 *q++ = c; 342 i++; 343 c = Getc(data, file); 344 } 345 if (c == EOF) { 346 XpmFree(p); 347 return (XpmFileInvalid); 348 } 349 if (n + i != 0) { 350 /* malloc needed memory */ 351 q = (char *) XpmRealloc(p, n + i + 1); 352 if (!q) { 353 XpmFree(p); 354 return (XpmNoMemory); 355 } 356 p = q; 357 q += n; 358 /* and copy the buffer */ 359 strncpy(q, buf, i); 360 n += i; 361 p[n++] = '\0'; 362 } else { 363 *p = '\0'; 364 n = 1; 365 } 366 Ungetc(data, c, file); 367 } 368 *sptr = p; 369 *l = n; 370 return (XpmSuccess); 371} 372 373/* 374 * get the current comment line 375 */ 376int 377xpmGetCmt( 378 xpmData *data, 379 char **cmt) 380{ 381 if (!data->type) 382 *cmt = NULL; 383 else if (data->CommentLength != 0 && data->CommentLength < UINT_MAX - 1) { 384 if( (*cmt = (char *) XpmMalloc(data->CommentLength + 1)) == NULL) 385 return XpmNoMemory; 386 strncpy(*cmt, data->Comment, data->CommentLength); 387 (*cmt)[data->CommentLength] = '\0'; 388 data->CommentLength = 0; 389 } else 390 *cmt = NULL; 391 return 0; 392} 393 394xpmDataType xpmDataTypes[] = 395{ 396 {"", "!", "\n", '\0', '\n', "", "", "", ""}, /* Natural type */ 397 {"C", "/*", "*/", '"', '"', ",\n", "static char *", "[] = {\n", "};\n"}, 398 {"Lisp", ";", "\n", '"', '"', "\n", "(setq ", " '(\n", "))\n"}, 399 {NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL} 400}; 401 402/* 403 * parse xpm header 404 */ 405int 406xpmParseHeader(xpmData *data) 407{ 408 char buf[BUFSIZ+1] = {0}; 409 int l, n = 0; 410 411 if (data->type) { 412 data->Bos = '\0'; 413 data->Eos = '\n'; 414 data->Bcmt = data->Ecmt = NULL; 415 l = xpmNextWord(data, buf, BUFSIZ); 416 if (l == 7 && !strncmp("#define", buf, 7)) { 417 /* this maybe an XPM 1 file */ 418 char *ptr; 419 420 l = xpmNextWord(data, buf, BUFSIZ); 421 if (!l) 422 return (XpmFileInvalid); 423 buf[l] = '\0'; 424 ptr = strrchr(buf, '_'); 425 if (!ptr || strncmp("_format", ptr, l - (ptr - buf))) 426 return XpmFileInvalid; 427 /* this is definitely an XPM 1 file */ 428 data->format = 1; 429 n = 1; /* handle XPM1 as mainly XPM2 C */ 430 } else { 431 432 /* 433 * skip the first word, get the second one, and see if this is 434 * XPM 2 or 3 435 */ 436 l = xpmNextWord(data, buf, BUFSIZ); 437 if ((l == 3 && !strncmp("XPM", buf, 3)) || 438 (l == 4 && !strncmp("XPM2", buf, 4))) { 439 if (l == 3) 440 n = 1; /* handle XPM as XPM2 C */ 441 else { 442 /* get the type key word */ 443 l = xpmNextWord(data, buf, BUFSIZ); 444 445 /* 446 * get infos about this type 447 */ 448 while (xpmDataTypes[n].type 449 && strncmp(xpmDataTypes[n].type, buf, l)) 450 n++; 451 } 452 data->format = 0; 453 } else 454 /* nope this is not an XPM file */ 455 return XpmFileInvalid; 456 } 457 if (xpmDataTypes[n].type) { 458 if (n == 0) { /* natural type */ 459 data->Bcmt = xpmDataTypes[n].Bcmt; 460 data->Ecmt = xpmDataTypes[n].Ecmt; 461 xpmNextString(data); /* skip the end of the headerline */ 462 data->Bos = xpmDataTypes[n].Bos; 463 data->Eos = xpmDataTypes[n].Eos; 464 } else { 465 data->Bcmt = xpmDataTypes[n].Bcmt; 466 data->Ecmt = xpmDataTypes[n].Ecmt; 467 if (!data->format) { /* XPM 2 or 3 */ 468 data->Bos = xpmDataTypes[n].Bos; 469 data->Eos = '\0'; 470 /* get to the beginning of the first string */ 471 xpmNextString(data); 472 data->Eos = xpmDataTypes[n].Eos; 473 } else /* XPM 1 skip end of line */ 474 xpmNextString(data); 475 } 476 } else 477 /* we don't know about that type of XPM file... */ 478 return XpmFileInvalid; 479 } 480 return XpmSuccess; 481}