]> git.saurik.com Git - wxWidgets.git/blob - src/xpm/data.c
Added various licence files
[wxWidgets.git] / src / xpm / data.c
1 /*
2 * Copyright (C) 1989-94 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 /* Official version number */
36 static char *RCS_Version = "$XpmVersion: 3.4b $";
37
38 /* Internal version number */
39 static char *RCS_Id = "$Id$";
40
41 #include "xpm34p.h"
42 #ifdef VMS
43 #include "sys$library:stat.h"
44 #include "sys$library:ctype.h"
45 #else
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <ctype.h>
49 #endif
50
51 #include <string.h>
52
53 LFUNC(ParseComment, int, (xpmData * mdata));
54
55 static int
56 ParseComment(xpmData *mdata)
57 {
58 if (mdata->type == XPMBUFFER) {
59 register char c;
60 register unsigned int n = 0;
61 unsigned int notend;
62 char *s, *s2;
63
64 s = mdata->Comment;
65 *s = mdata->Bcmt[0];
66
67 /* skip the string beginning comment */
68 s2 = mdata->Bcmt;
69 do {
70 c = *mdata->cptr++;
71 *++s = c;
72 n++;
73 s2++;
74 } while (c == *s2 && *s2 != '\0' && c && c != mdata->Bos);
75
76 if (*s2 != '\0') {
77 /* this wasn't the beginning of a comment */
78 mdata->cptr -= n;
79 return 0;
80 }
81 /* store comment */
82 mdata->Comment[0] = *s;
83 s = mdata->Comment;
84 notend = 1;
85 n = 0;
86 while (notend) {
87 s2 = mdata->Ecmt;
88 while (*s != *s2 && c && c != mdata->Bos) {
89 c = *mdata->cptr++;
90 *++s = c;
91 n++;
92 }
93 mdata->CommentLength = n;
94 do {
95 c = *mdata->cptr++;
96 n++;
97 *++s = c;
98 s2++;
99 } while (c == *s2 && *s2 != '\0' && c && c != mdata->Bos);
100 if (*s2 == '\0') {
101 /* this is the end of the comment */
102 notend = 0;
103 mdata->cptr--;
104 }
105 }
106 return 0;
107 } else {
108 FILE *file = mdata->stream.file;
109 register int c;
110 register unsigned int n = 0, a;
111 unsigned int notend;
112 char *s, *s2;
113
114 s = mdata->Comment;
115 *s = mdata->Bcmt[0];
116
117 /* skip the string beginning comment */
118 s2 = mdata->Bcmt;
119 do {
120 c = getc(file);
121 *++s = c;
122 n++;
123 s2++;
124 } while (c == *s2 && *s2 != '\0'
125 && c != EOF && c != mdata->Bos);
126
127 if (*s2 != '\0') {
128 /* this wasn't the beginning of a comment */
129 /* put characters back in the order that we got them */
130 for (a = n; a > 0; a--, s--)
131 ungetc(*s, file);
132 return 0;
133 }
134 /* store comment */
135 mdata->Comment[0] = *s;
136 s = mdata->Comment;
137 notend = 1;
138 n = 0;
139 while (notend) {
140 s2 = mdata->Ecmt;
141 while (*s != *s2 && c != EOF && c != mdata->Bos) {
142 c = getc(file);
143 *++s = c;
144 n++;
145 }
146 mdata->CommentLength = n;
147 do {
148 c = getc(file);
149 n++;
150 *++s = c;
151 s2++;
152 } while (c == *s2 && *s2 != '\0'
153 && c != EOF && c != mdata->Bos);
154 if (*s2 == '\0') {
155 /* this is the end of the comment */
156 notend = 0;
157 ungetc(*s, file);
158 }
159 }
160 return 0;
161 }
162 }
163
164 /*
165 * skip to the end of the current string and the beginning of the next one
166 */
167 int
168 xpmNextString(xpmData *mdata)
169 {
170 if (!mdata->type)
171 mdata->cptr = (mdata->stream.data)[++mdata->line];
172 else if (mdata->type == XPMBUFFER) {
173 register char c;
174
175 /* get to the end of the current string */
176 if (mdata->Eos)
177 while ((c = *mdata->cptr++) && c != mdata->Eos);
178
179 /*
180 * then get to the beginning of the next string looking for possible
181 * comment
182 */
183 if (mdata->Bos) {
184 while ((c = *mdata->cptr++) && c != mdata->Bos)
185 if (mdata->Bcmt && c == mdata->Bcmt[0])
186 ParseComment(mdata);
187 } else if (mdata->Bcmt) { /* XPM2 natural */
188 while ((c = *mdata->cptr++) == mdata->Bcmt[0])
189 ParseComment(mdata);
190 mdata->cptr--;
191 }
192 } else {
193 register int c;
194 FILE *file = mdata->stream.file;
195
196 /* get to the end of the current string */
197 if (mdata->Eos)
198 while ((c = getc(file)) != mdata->Eos && c != EOF);
199
200 /*
201 * then get to the beginning of the next string looking for possible
202 * comment
203 */
204 if (mdata->Bos) {
205 while ((c = getc(file)) != mdata->Bos && c != EOF)
206 if (mdata->Bcmt && c == mdata->Bcmt[0])
207 ParseComment(mdata);
208
209 } else if (mdata->Bcmt) { /* XPM2 natural */
210 while ((c = getc(file)) == mdata->Bcmt[0])
211 ParseComment(mdata);
212 ungetc(c, file);
213 }
214 }
215 return 0;
216 }
217
218
219 /*
220 * skip whitespace and compute the following unsigned int,
221 * returns 1 if one is found and 0 if not
222 */
223 int
224 xpmNextUI(xpmData *mdata, unsigned int *ui_return)
225 {
226 char buf[BUFSIZ];
227 int l;
228
229 l = xpmNextWord(mdata, buf, BUFSIZ);
230 return atoui(buf, l, ui_return);
231 }
232
233 /*
234 * skip whitespace and return the following word
235 */
236 unsigned int
237 xpmNextWord(xpmData *mdata, char *buf, unsigned int buflen)
238 {
239 register unsigned int n = 0;
240 int c;
241
242 if (!mdata->type || mdata->type == XPMBUFFER) {
243 while (isspace(c = *mdata->cptr) && c != mdata->Eos)
244 mdata->cptr++;
245 do {
246 c = *mdata->cptr++;
247 *buf++ = c;
248 n++;
249 } while (!isspace(c) && c != mdata->Eos && n < buflen);
250 n--;
251 mdata->cptr--;
252 } else {
253 FILE *file = mdata->stream.file;
254
255 while ((c = getc(file)) != EOF && isspace(c) && c != mdata->Eos);
256 while (!isspace(c) && c != mdata->Eos && c != EOF && n < buflen) {
257 *buf++ = c;
258 n++;
259 c = getc(file);
260 }
261 ungetc(c, file);
262 }
263 return (n);
264 }
265
266 /*
267 * return end of string - WARNING: malloc!
268 */
269 int
270 xpmGetString(xpmData *mdata, char **sptr, unsigned int *l)
271 {
272 unsigned int i, n = 0;
273 int c;
274 char *p, *q, buf[BUFSIZ];
275
276 if (!mdata->type || mdata->type == XPMBUFFER) {
277 if (mdata->cptr) {
278 char *start;
279
280 while (isspace(c = *mdata->cptr) && c != mdata->Eos)
281 mdata->cptr++;
282 start = mdata->cptr;
283 while ((c = *mdata->cptr) && c != mdata->Eos)
284 mdata->cptr++;
285 n = mdata->cptr - start + 1;
286 p = (char *) XpmMalloc(n);
287 if (!p)
288 return (XpmNoMemory);
289 strncpy(p, start, n);
290 if (mdata->type) /* XPMBUFFER */
291 p[n - 1] = '\0';
292 }
293 } else {
294 FILE *file = mdata->stream.file;
295
296 while ((c = getc(file)) != EOF && isspace(c) && c != mdata->Eos);
297 if (c == EOF)
298 return (XpmFileInvalid);
299 p = NULL;
300 i = 0;
301 q = buf;
302 p = (char *) XpmMalloc(1);
303 while (c != mdata->Eos && c != EOF) {
304 if (i == BUFSIZ) {
305 /* get to the end of the buffer */
306 /* malloc needed memory */
307 q = (char *) XpmRealloc(p, n + i);
308 if (!q) {
309 XpmFree(p);
310 return (XpmNoMemory);
311 }
312 p = q;
313 q += n;
314 /* and copy what we already have */
315 strncpy(q, buf, i);
316 n += i;
317 i = 0;
318 q = buf;
319 }
320 *q++ = c;
321 i++;
322 c = getc(file);
323 }
324 if (c == EOF) {
325 XpmFree(p);
326 return (XpmFileInvalid);
327 }
328 if (n + i != 0) {
329 /* malloc needed memory */
330 q = (char *) XpmRealloc(p, n + i + 1);
331 if (!q) {
332 XpmFree(p);
333 return (XpmNoMemory);
334 }
335 p = q;
336 q += n;
337 /* and copy the buffer */
338 strncpy(q, buf, i);
339 n += i;
340 p[n++] = '\0';
341 } else {
342 *p = '\0';
343 n = 1;
344 }
345 ungetc(c, file);
346 }
347 *sptr = p;
348 *l = n;
349 return (XpmSuccess);
350 }
351
352 /*
353 * get the current comment line
354 */
355 int
356 xpmGetCmt(xpmData *mdata, char **cmt)
357 {
358 if (!mdata->type)
359 *cmt = NULL;
360 else if (mdata->CommentLength) {
361 *cmt = (char *) XpmMalloc(mdata->CommentLength + 1);
362 strncpy(*cmt, mdata->Comment, mdata->CommentLength);
363 (*cmt)[mdata->CommentLength] = '\0';
364 mdata->CommentLength = 0;
365 } else
366 *cmt = NULL;
367 return 0;
368 }
369
370 /*
371 * open the given file to be read as an xpmData which is returned.
372 */
373 int
374 xpmReadFile(char *filename, xpmData *mdata)
375 {
376 #ifdef ZPIPE
377 char *compressfile, buf[BUFSIZ];
378 struct stat status;
379
380 #endif
381
382 if (!filename) {
383 mdata->stream.file = (stdin);
384 mdata->type = XPMFILE;
385 } else {
386 #ifdef ZPIPE
387 if (((int) strlen(filename) > 2) &&
388 !strcmp(".Z", filename + (strlen(filename) - 2))) {
389 mdata->type = XPMPIPE;
390 sprintf(buf, "uncompress -c %s", filename);
391 if (!(mdata->stream.file = popen(buf, "r")))
392 return (XpmOpenFailed);
393
394 } else if (((int) strlen(filename) > 3) &&
395 !strcmp(".gz", filename + (strlen(filename) - 3))) {
396 mdata->type = XPMPIPE;
397 sprintf(buf, "gunzip -qc %s", filename);
398 if (!(mdata->stream.file = popen(buf, "r")))
399 return (XpmOpenFailed);
400
401 } else {
402 if (!(compressfile = (char *) XpmMalloc(strlen(filename) + 4)))
403 return (XpmNoMemory);
404
405 strcpy(compressfile, filename);
406 strcat(compressfile, ".Z");
407 if (!stat(compressfile, &status)) {
408 sprintf(buf, "uncompress -c %s", compressfile);
409 if (!(mdata->stream.file = popen(buf, "r"))) {
410 XpmFree(compressfile);
411 return (XpmOpenFailed);
412 }
413 mdata->type = XPMPIPE;
414 } else {
415 strcpy(compressfile, filename);
416 strcat(compressfile, ".gz");
417 if (!stat(compressfile, &status)) {
418 sprintf(buf, "gunzip -c %s", compressfile);
419 if (!(mdata->stream.file = popen(buf, "r"))) {
420 XpmFree(compressfile);
421 return (XpmOpenFailed);
422 }
423 mdata->type = XPMPIPE;
424 } else {
425 #endif
426 if (!(mdata->stream.file = fopen(filename, "r"))) {
427 #ifdef ZPIPE
428 XpmFree(compressfile);
429 #endif
430 return (XpmOpenFailed);
431 }
432 mdata->type = XPMFILE;
433 #ifdef ZPIPE
434 }
435 }
436 XpmFree(compressfile);
437 }
438 #endif
439 }
440 mdata->CommentLength = 0;
441 return (XpmSuccess);
442 }
443
444 /*
445 * open the given file to be written as an xpmData which is returned
446 */
447 int
448 xpmWriteFile(char *filename, xpmData *mdata)
449 {
450 #ifdef ZPIPE
451 char buf[BUFSIZ];
452
453 #endif
454
455 if (!filename) {
456 mdata->stream.file = (stdout);
457 mdata->type = XPMFILE;
458 } else {
459 #ifdef ZPIPE
460 if ((int) strlen(filename) > 2
461 && !strcmp(".Z", filename + (strlen(filename) - 2))) {
462 sprintf(buf, "compress > %s", filename);
463 if (!(mdata->stream.file = popen(buf, "w")))
464 return (XpmOpenFailed);
465
466 mdata->type = XPMPIPE;
467 } else if ((int) strlen(filename) > 3
468 && !strcmp(".gz", filename + (strlen(filename) - 3))) {
469 sprintf(buf, "gzip -q > %s", filename);
470 if (!(mdata->stream.file = popen(buf, "w")))
471 return (XpmOpenFailed);
472
473 mdata->type = XPMPIPE;
474 } else {
475 #endif
476 if (!(mdata->stream.file = fopen(filename, "w")))
477 return (XpmOpenFailed);
478
479 mdata->type = XPMFILE;
480 #ifdef ZPIPE
481 }
482 #endif
483 }
484 return (XpmSuccess);
485 }
486
487 /*
488 * open the given array to be read or written as an xpmData which is returned
489 */
490 void
491 xpmOpenArray(char **data, xpmData *mdata)
492 {
493 mdata->type = XPMARRAY;
494 mdata->stream.data = data;
495 mdata->cptr = *data;
496 mdata->line = 0;
497 mdata->CommentLength = 0;
498 mdata->Bcmt = mdata->Ecmt = NULL;
499 mdata->Bos = mdata->Eos = '\0';
500 mdata->format = 0; /* this can only be Xpm 2 or 3 */
501 }
502
503 /*
504 * open the given buffer to be read or written as an xpmData which is returned
505 */
506 void
507 xpmOpenBuffer(char *buffer, xpmData *mdata)
508 {
509 mdata->type = XPMBUFFER;
510 mdata->cptr = buffer;
511 mdata->CommentLength = 0;
512 }
513
514 /*
515 * close the file related to the xpmData if any
516 */
517 int
518 xpmDataClose(xpmData *mdata)
519 {
520 switch (mdata->type) {
521 case XPMARRAY:
522 case XPMBUFFER:
523 break;
524 case XPMFILE:
525 if (mdata->stream.file != (stdout) && mdata->stream.file != (stdin))
526 fclose(mdata->stream.file);
527 break;
528 #ifdef ZPIPE
529 case XPMPIPE:
530 pclose(mdata->stream.file);
531 break;
532 #endif
533 }
534 return 0;
535 }
536
537 xpmDataType xpmDataTypes[] =
538 {
539 "", "!", "\n", '\0', '\n', "", "", "", "", /* Natural type */
540 "C", "/*", "*/", '"', '"', ",\n", "static char *", "[] = {\n", "};\n",
541 "Lisp", ";", "\n", '"', '"', "\n", "(setq ", " '(\n", "))\n",
542 #ifdef VMS
543 NULL
544 #else
545 NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL
546 #endif
547 };
548
549 /*
550 * parse xpm header
551 */
552 int
553 xpmParseHeader(xpmData *mdata)
554 {
555 char buf[BUFSIZ];
556 int l, n = 0;
557
558 if (mdata->type) {
559 mdata->Bos = '\0';
560 mdata->Eos = '\n';
561 mdata->Bcmt = mdata->Ecmt = NULL;
562 l = xpmNextWord(mdata, buf, BUFSIZ);
563 if (l == 7 && !strncmp("#define", buf, 7)) {
564 /* this maybe an XPM 1 file */
565 char *ptr;
566
567 l = xpmNextWord(mdata, buf, BUFSIZ);
568 if (!l)
569 return (XpmFileInvalid);
570 ptr = strchr(buf, '_');
571 if (!ptr || strncmp("_format", ptr, l - (ptr - buf)))
572 return XpmFileInvalid;
573 /* this is definitely an XPM 1 file */
574 mdata->format = 1;
575 n = 1; /* handle XPM1 as mainly XPM2 C */
576 } else {
577
578 /*
579 * skip the first word, get the second one, and see if this is
580 * XPM 2 or 3
581 */
582 l = xpmNextWord(mdata, buf, BUFSIZ);
583 if ((l == 3 && !strncmp("XPM", buf, 3)) ||
584 (l == 4 && !strncmp("XPM2", buf, 4))) {
585 if (l == 3)
586 n = 1; /* handle XPM as XPM2 C */
587 else {
588 /* get the type key word */
589 l = xpmNextWord(mdata, buf, BUFSIZ);
590
591 /*
592 * get infos about this type
593 */
594 while (xpmDataTypes[n].type
595 && strncmp(xpmDataTypes[n].type, buf, l))
596 n++;
597 }
598 mdata->format = 0;
599 } else
600 /* nope this is not an XPM file */
601 return XpmFileInvalid;
602 }
603 if (xpmDataTypes[n].type) {
604 if (n == 0) { /* natural type */
605 mdata->Bcmt = xpmDataTypes[n].Bcmt;
606 mdata->Ecmt = xpmDataTypes[n].Ecmt;
607 xpmNextString(mdata); /* skip the end of the headerline */
608 mdata->Bos = xpmDataTypes[n].Bos;
609 mdata->Eos = xpmDataTypes[n].Eos;
610 } else {
611 mdata->Bcmt = xpmDataTypes[n].Bcmt;
612 mdata->Ecmt = xpmDataTypes[n].Ecmt;
613 if (!mdata->format) { /* XPM 2 or 3 */
614 mdata->Bos = xpmDataTypes[n].Bos;
615 mdata->Eos = '\0';
616 /* get to the beginning of the first string */
617 xpmNextString(mdata);
618 mdata->Eos = xpmDataTypes[n].Eos;
619 } else /* XPM 1 skip end of line */
620 xpmNextString(mdata);
621 }
622 } else
623 /* we don't know about that type of XPM file... */
624 return XpmFileInvalid;
625 }
626 return XpmSuccess;
627 }