data.c revision 52dc082b
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' || c == '\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 else if (c == EOF) { 178 /* hit end of file before the end of the comment */ 179 return XpmFileInvalid; 180 } 181 } 182 return 0; 183 } 184} 185 186/* 187 * skip to the end of the current string and the beginning of the next one 188 */ 189int 190xpmNextString(xpmData *data) 191{ 192 if (!data->type) 193 data->cptr = (data->stream.data)[++data->line]; 194 else if (data->type == XPMBUFFER) { 195 register char c; 196 197 /* get to the end of the current string */ 198 if (data->Eos) { 199 while ((c = *data->cptr++) && c != data->Eos && c != '\0'); 200 201 if (c == '\0') 202 return XpmFileInvalid; 203 } 204 205 /* 206 * then get to the beginning of the next string looking for possible 207 * comment 208 */ 209 if (data->Bos) { 210 while ((c = *data->cptr++) && c != data->Bos && c != '\0') 211 if (data->Bcmt && c == data->Bcmt[0]) 212 ParseComment(data); 213 } else if (data->Bcmt) { /* XPM2 natural */ 214 while (((c = *data->cptr++) == data->Bcmt[0]) && c != '\0') 215 ParseComment(data); 216 data->cptr--; 217 } 218 } else { 219 register int c; 220 FILE *file = data->stream.file; 221 222 /* get to the end of the current string */ 223 if (data->Eos) { 224 while ((c = Getc(data, file)) != data->Eos && c != EOF); 225 226 if (c == EOF) 227 return XpmFileInvalid; 228 } 229 230 /* 231 * then get to the beginning of the next string looking for possible 232 * comment 233 */ 234 if (data->Bos) { 235 while ((c = Getc(data, file)) != data->Bos && c != EOF) 236 if (data->Bcmt && c == data->Bcmt[0]) 237 ParseComment(data); 238 239 } else if (data->Bcmt) { /* XPM2 natural */ 240 while ((c = Getc(data, file)) == data->Bcmt[0]) 241 ParseComment(data); 242 Ungetc(data, c, file); 243 } 244 } 245 return XpmSuccess; 246} 247 248 249/* 250 * skip whitespace and return the following word 251 */ 252unsigned int 253xpmNextWord( 254 xpmData *data, 255 char *buf, 256 unsigned int buflen) 257{ 258 register unsigned int n = 0; 259 int c; 260 261 if (!data->type || data->type == XPMBUFFER) { 262 while ((c = *data->cptr) && isspace(c) && (c != data->Eos)) 263 data->cptr++; 264 do { 265 c = *data->cptr++; 266 *buf++ = c; 267 n++; 268 } while (c && !isspace(c) && (c != data->Eos) && (n < buflen)); 269 n--; 270 data->cptr--; 271 } else { 272 FILE *file = data->stream.file; 273 274 while ((c = Getc(data, file)) != EOF && isspace(c) && c != data->Eos); 275 while (!isspace(c) && c != data->Eos && c != EOF && n < buflen) { 276 *buf++ = c; 277 n++; 278 c = Getc(data, file); 279 } 280 Ungetc(data, c, file); 281 } 282 return (n); /* this returns bytes read + 1 */ 283} 284 285/* 286 * skip whitespace and compute the following unsigned int, 287 * returns 1 if one is found and 0 if not 288 */ 289int 290xpmNextUI( 291 xpmData *data, 292 unsigned int *ui_return) 293{ 294 char buf[BUFSIZ]; 295 int l; 296 297 l = xpmNextWord(data, buf, BUFSIZ); 298 return xpmatoui(buf, l, ui_return); 299} 300 301/* 302 * return end of string - WARNING: malloc! 303 */ 304int 305xpmGetString( 306 xpmData *data, 307 char **sptr, 308 unsigned int *l) 309{ 310 unsigned int i, n = 0; 311 int c; 312 char *p = NULL, *q, buf[BUFSIZ]; 313 314 if (!data->type || data->type == XPMBUFFER) { 315 if (data->cptr) { 316 char *start = data->cptr; 317 while ((c = *data->cptr) && c != data->Eos) 318 data->cptr++; 319 n = data->cptr - start + 1; 320 p = (char *) XpmMalloc(n); 321 if (!p) 322 return (XpmNoMemory); 323 strncpy(p, start, n); 324 if (data->type) /* XPMBUFFER */ 325 p[n - 1] = '\0'; 326 } 327 } else { 328 FILE *file = data->stream.file; 329 330 if ((c = Getc(data, file)) == EOF) 331 return (XpmFileInvalid); 332 333 i = 0; 334 q = buf; 335 p = (char *) XpmMalloc(1); 336 while (c != data->Eos && c != EOF) { 337 if (i == BUFSIZ) { 338 /* get to the end of the buffer */ 339 /* malloc needed memory */ 340 q = (char *) XpmRealloc(p, n + i); 341 if (!q) { 342 XpmFree(p); 343 return (XpmNoMemory); 344 } 345 p = q; 346 q += n; 347 /* and copy what we already have */ 348 strncpy(q, buf, i); 349 n += i; 350 i = 0; 351 q = buf; 352 } 353 *q++ = c; 354 i++; 355 c = Getc(data, file); 356 } 357 if (c == EOF) { 358 XpmFree(p); 359 return (XpmFileInvalid); 360 } 361 if (n + i != 0) { 362 /* malloc needed memory */ 363 q = (char *) XpmRealloc(p, n + i + 1); 364 if (!q) { 365 XpmFree(p); 366 return (XpmNoMemory); 367 } 368 p = q; 369 q += n; 370 /* and copy the buffer */ 371 strncpy(q, buf, i); 372 n += i; 373 p[n++] = '\0'; 374 } else { 375 *p = '\0'; 376 n = 1; 377 } 378 Ungetc(data, c, file); 379 } 380 *sptr = p; 381 *l = n; 382 return (XpmSuccess); 383} 384 385/* 386 * get the current comment line 387 */ 388int 389xpmGetCmt( 390 xpmData *data, 391 char **cmt) 392{ 393 if (!data->type) 394 *cmt = NULL; 395 else if (data->CommentLength != 0 && data->CommentLength < UINT_MAX - 1) { 396 if( (*cmt = (char *) XpmMalloc(data->CommentLength + 1)) == NULL) 397 return XpmNoMemory; 398 strncpy(*cmt, data->Comment, data->CommentLength); 399 (*cmt)[data->CommentLength] = '\0'; 400 data->CommentLength = 0; 401 } else 402 *cmt = NULL; 403 return 0; 404} 405 406xpmDataType xpmDataTypes[] = 407{ 408 {"", "!", "\n", '\0', '\n', "", "", "", ""}, /* Natural type */ 409 {"C", "/*", "*/", '"', '"', ",\n", "static char *", "[] = {\n", "};\n"}, 410 {"Lisp", ";", "\n", '"', '"', "\n", "(setq ", " '(\n", "))\n"}, 411 {NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL} 412}; 413 414/* 415 * parse xpm header 416 */ 417int 418xpmParseHeader(xpmData *data) 419{ 420 char buf[BUFSIZ+1] = {0}; 421 int l, n = 0; 422 423 if (data->type) { 424 data->Bos = '\0'; 425 data->Eos = '\n'; 426 data->Bcmt = data->Ecmt = NULL; 427 l = xpmNextWord(data, buf, BUFSIZ); 428 if (l == 7 && !strncmp("#define", buf, 7)) { 429 /* this maybe an XPM 1 file */ 430 char *ptr; 431 432 l = xpmNextWord(data, buf, BUFSIZ); 433 if (!l) 434 return (XpmFileInvalid); 435 buf[l] = '\0'; 436 ptr = strrchr(buf, '_'); 437 if (!ptr || strncmp("_format", ptr, l - (ptr - buf))) 438 return XpmFileInvalid; 439 /* this is definitely an XPM 1 file */ 440 data->format = 1; 441 n = 1; /* handle XPM1 as mainly XPM2 C */ 442 } else { 443 444 /* 445 * skip the first word, get the second one, and see if this is 446 * XPM 2 or 3 447 */ 448 l = xpmNextWord(data, buf, BUFSIZ); 449 if ((l == 3 && !strncmp("XPM", buf, 3)) || 450 (l == 4 && !strncmp("XPM2", buf, 4))) { 451 if (l == 3) 452 n = 1; /* handle XPM as XPM2 C */ 453 else { 454 /* get the type key word */ 455 l = xpmNextWord(data, buf, BUFSIZ); 456 457 /* 458 * get infos about this type 459 */ 460 while (xpmDataTypes[n].type 461 && strncmp(xpmDataTypes[n].type, buf, l)) 462 n++; 463 } 464 data->format = 0; 465 } else 466 /* nope this is not an XPM file */ 467 return XpmFileInvalid; 468 } 469 if (xpmDataTypes[n].type) { 470 if (n == 0) { /* natural type */ 471 data->Bcmt = xpmDataTypes[n].Bcmt; 472 data->Ecmt = xpmDataTypes[n].Ecmt; 473 xpmNextString(data); /* skip the end of the headerline */ 474 data->Bos = xpmDataTypes[n].Bos; 475 data->Eos = xpmDataTypes[n].Eos; 476 } else { 477 data->Bcmt = xpmDataTypes[n].Bcmt; 478 data->Ecmt = xpmDataTypes[n].Ecmt; 479 if (!data->format) { /* XPM 2 or 3 */ 480 data->Bos = xpmDataTypes[n].Bos; 481 data->Eos = '\0'; 482 /* get to the beginning of the first string */ 483 xpmNextString(data); 484 data->Eos = xpmDataTypes[n].Eos; 485 } else /* XPM 1 skip end of line */ 486 xpmNextString(data); 487 } 488 } else 489 /* we don't know about that type of XPM file... */ 490 return XpmFileInvalid; 491 } 492 return XpmSuccess; 493} 494