Update changes file
[profile/ivi/libXpm.git] / src / data.c
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 */
40 static char *RCS_Version = "$XpmVersion: 3.4k $";
41
42 /* Internal version number */
43 static 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
57 static int
58 ParseComment(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, *s2;
65
66         s = data->Comment;
67         *s = data->Bcmt[0];
68
69         /* skip the string beginning comment */
70         s2 = data->Bcmt;
71         do {
72             c = *data->cptr++;
73             *++s = c;
74             n++;
75             s2++;
76         } while (c == *s2 && *s2 != '\0' && c);
77
78         if (*s2 != '\0') {
79             /* this wasn't the beginning of a comment */
80             data->cptr -= n;
81             return 0;
82         }
83         /* store comment */
84         data->Comment[0] = *s;
85         s = data->Comment;
86         notend = 1;
87         n = 0;
88         while (notend) {
89             s2 = data->Ecmt;
90             while (*s != *s2 && c) {
91                 c = *data->cptr++;
92                 if (n == XPMMAXCMTLEN - 1)  { /* forget it */
93                     s = data->Comment;
94                     n = 0;
95                 }
96                 *++s = c;
97                 n++;
98             }
99             data->CommentLength = n;
100             do {
101                 c = *data->cptr++;
102                 if (n == XPMMAXCMTLEN - 1)  { /* forget it */
103                     s = data->Comment;
104                     n = 0;
105                 }
106                 *++s = c;
107                 n++;
108                 s2++;
109             } while (c == *s2 && *s2 != '\0' && c);
110             if (*s2 == '\0') {
111                 /* this is the end of the comment */
112                 notend = 0;
113                 data->cptr--;
114             }
115         }
116         return 0;
117     } else {
118         FILE *file = data->stream.file;
119         register int c;
120         register unsigned int n = 0, a;
121         unsigned int notend;
122         char *s, *s2;
123
124         s = data->Comment;
125         *s = data->Bcmt[0];
126
127         /* skip the string beginning comment */
128         s2 = data->Bcmt;
129         do {
130             c = Getc(data, file);
131             *++s = c;
132             n++;
133             s2++;
134         } while (c == *s2 && *s2 != '\0' && c != EOF);
135
136         if (*s2 != '\0') {
137             /* this wasn't the beginning of a comment */
138             /* put characters back in the order that we got them */
139             for (a = n; a > 0; a--, s--)
140                 Ungetc(data, *s, file);
141             return 0;
142         }
143         /* store comment */
144         data->Comment[0] = *s;
145         s = data->Comment;
146         notend = 1;
147         n = 0;
148         while (notend) {
149             s2 = data->Ecmt;
150             while (*s != *s2 && c != EOF) {
151                 c = Getc(data, file);
152                 if (n == XPMMAXCMTLEN - 1)  { /* forget it */
153                     s = data->Comment;
154                     n = 0;
155                 }
156                 *++s = c;
157                 n++;
158             }
159             data->CommentLength = n;
160             do {
161                 c = Getc(data, file);
162                 if (n == XPMMAXCMTLEN - 1)  { /* forget it */
163                     s = data->Comment;
164                     n = 0;
165                 }
166                 *++s = c;
167                 n++;
168                 s2++;
169             } while (c == *s2 && *s2 != '\0' && c != EOF);
170             if (*s2 == '\0') {
171                 /* this is the end of the comment */
172                 notend = 0;
173                 Ungetc(data, *s, file);
174             }
175         }
176         return 0;
177     }
178 }
179
180 /*
181  * skip to the end of the current string and the beginning of the next one
182  */
183 int
184 xpmNextString(xpmData *data)
185 {
186     if (!data->type)
187         data->cptr = (data->stream.data)[++data->line];
188     else if (data->type == XPMBUFFER) {
189         register char c;
190
191         /* get to the end of the current string */
192         if (data->Eos)
193             while ((c = *data->cptr++) && c != data->Eos);
194
195         /*
196          * then get to the beginning of the next string looking for possible
197          * comment
198          */
199         if (data->Bos) {
200             while ((c = *data->cptr++) && c != data->Bos)
201                 if (data->Bcmt && c == data->Bcmt[0])
202                     ParseComment(data);
203         } else if (data->Bcmt) {        /* XPM2 natural */
204             while ((c = *data->cptr++) == data->Bcmt[0])
205                 ParseComment(data);
206             data->cptr--;
207         }
208     } else {
209         register int c;
210         FILE *file = data->stream.file;
211
212         /* get to the end of the current string */
213         if (data->Eos)
214             while ((c = Getc(data, file)) != data->Eos && c != EOF);
215
216         /*
217          * then get to the beginning of the next string looking for possible
218          * comment
219          */
220         if (data->Bos) {
221             while ((c = Getc(data, file)) != data->Bos && c != EOF)
222                 if (data->Bcmt && c == data->Bcmt[0])
223                     ParseComment(data);
224
225         } else if (data->Bcmt) {        /* XPM2 natural */
226             while ((c = Getc(data, file)) == data->Bcmt[0])
227                 ParseComment(data);
228             Ungetc(data, c, file);
229         }
230     }
231     return 0;
232 }
233
234
235 /*
236  * skip whitespace and return the following word
237  */
238 unsigned int
239 xpmNextWord(
240     xpmData             *data,
241     char                *buf,
242     unsigned int         buflen)
243 {
244     register unsigned int n = 0;
245     int c;
246
247     if (!data->type || data->type == XPMBUFFER) {
248         while (isspace(c = *data->cptr) && c != data->Eos)
249             data->cptr++;
250         do {
251             c = *data->cptr++;
252             *buf++ = c;
253             n++;
254         } while (!isspace(c) && c != data->Eos && n < buflen);
255         n--;
256         data->cptr--;
257     } else {
258         FILE *file = data->stream.file;
259
260         while ((c = Getc(data, file)) != EOF && isspace(c) && c != data->Eos);
261         while (!isspace(c) && c != data->Eos && c != EOF && n < buflen) {
262             *buf++ = c;
263             n++;
264             c = Getc(data, file);
265         }
266         Ungetc(data, c, file);
267     }
268     return (n); /* this returns bytes read + 1 */
269 }
270
271 /*
272  * skip whitespace and compute the following unsigned int,
273  * returns 1 if one is found and 0 if not
274  */
275 int
276 xpmNextUI(
277     xpmData             *data,
278     unsigned int        *ui_return)
279 {
280     char buf[BUFSIZ];
281     int l;
282
283     l = xpmNextWord(data, buf, BUFSIZ);
284     return xpmatoui(buf, l, ui_return);
285 }
286
287 /*
288  * return end of string - WARNING: malloc!
289  */
290 int
291 xpmGetString(
292     xpmData              *data,
293     char                **sptr,
294     unsigned int         *l)
295 {
296     unsigned int i, n = 0;
297     int c;
298     char *p = NULL, *q, buf[BUFSIZ];
299
300     if (!data->type || data->type == XPMBUFFER) {
301         if (data->cptr) {
302             char *start = data->cptr;
303             while ((c = *data->cptr) && c != data->Eos)
304                 data->cptr++;
305             n = data->cptr - start + 1;
306             p = (char *) XpmMalloc(n);
307             if (!p)
308                 return (XpmNoMemory);
309             strncpy(p, start, n);
310             if (data->type)             /* XPMBUFFER */
311                 p[n - 1] = '\0';
312         }
313     } else {
314         FILE *file = data->stream.file;
315
316         if ((c = Getc(data, file)) == EOF)
317             return (XpmFileInvalid);
318
319         i = 0;
320         q = buf;
321         p = (char *) XpmMalloc(1);
322         while (c != data->Eos && c != EOF) {
323             if (i == BUFSIZ) {
324                 /* get to the end of the buffer */
325                 /* malloc needed memory */
326                 q = (char *) XpmRealloc(p, n + i);
327                 if (!q) {
328                     XpmFree(p);
329                     return (XpmNoMemory);
330                 }
331                 p = q;
332                 q += n;
333                 /* and copy what we already have */
334                 strncpy(q, buf, i);
335                 n += i;
336                 i = 0;
337                 q = buf;
338             }
339             *q++ = c;
340             i++;
341             c = Getc(data, file);
342         }
343         if (c == EOF) {
344             XpmFree(p);
345             return (XpmFileInvalid);
346         }
347         if (n + i != 0) {
348             /* malloc needed memory */
349             q = (char *) XpmRealloc(p, n + i + 1);
350             if (!q) {
351                 XpmFree(p);
352                 return (XpmNoMemory);
353             }
354             p = q;
355             q += n;
356             /* and copy the buffer */
357             strncpy(q, buf, i);
358             n += i;
359             p[n++] = '\0';
360         } else {
361             *p = '\0';
362             n = 1;
363         }
364         Ungetc(data, c, file);
365     }
366     *sptr = p;
367     *l = n;
368     return (XpmSuccess);
369 }
370
371 /*
372  * get the current comment line
373  */
374 int
375 xpmGetCmt(
376     xpmData      *data,
377     char        **cmt)
378 {
379     if (!data->type)
380         *cmt = NULL;
381     else if (data->CommentLength != 0 && data->CommentLength < UINT_MAX - 1) {
382         if( (*cmt = (char *) XpmMalloc(data->CommentLength + 1)) == NULL)
383                 return XpmNoMemory;
384         strncpy(*cmt, data->Comment, data->CommentLength);
385         (*cmt)[data->CommentLength] = '\0';
386         data->CommentLength = 0;
387     } else
388         *cmt = NULL;
389     return 0;
390 }
391
392 xpmDataType xpmDataTypes[] =
393 {
394     {"", "!", "\n", '\0', '\n', "", "", "", ""},        /* Natural type */
395     {"C", "/*", "*/", '"', '"', ",\n", "static char *", "[] = {\n", "};\n"},
396     {"Lisp", ";", "\n", '"', '"', "\n", "(setq ", " '(\n", "))\n"},
397     {NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL}
398 };
399
400 /*
401  * parse xpm header
402  */
403 int
404 xpmParseHeader(xpmData *data)
405 {
406     char buf[BUFSIZ+1] = {0};
407     int l, n = 0;
408
409     if (data->type) {
410         data->Bos = '\0';
411         data->Eos = '\n';
412         data->Bcmt = data->Ecmt = NULL;
413         l = xpmNextWord(data, buf, BUFSIZ);
414         if (l == 7 && !strncmp("#define", buf, 7)) {
415             /* this maybe an XPM 1 file */
416             char *ptr;
417
418             l = xpmNextWord(data, buf, BUFSIZ);
419             if (!l)
420                 return (XpmFileInvalid);
421             buf[l] = '\0';
422             ptr = strrchr(buf, '_');
423             if (!ptr || strncmp("_format", ptr, l - (ptr - buf)))
424                 return XpmFileInvalid;
425             /* this is definitely an XPM 1 file */
426             data->format = 1;
427             n = 1;                      /* handle XPM1 as mainly XPM2 C */
428         } else {
429
430             /*
431              * skip the first word, get the second one, and see if this is
432              * XPM 2 or 3
433              */
434             l = xpmNextWord(data, buf, BUFSIZ);
435             if ((l == 3 && !strncmp("XPM", buf, 3)) ||
436                 (l == 4 && !strncmp("XPM2", buf, 4))) {
437                 if (l == 3)
438                     n = 1;              /* handle XPM as XPM2 C */
439                 else {
440                     /* get the type key word */
441                     l = xpmNextWord(data, buf, BUFSIZ);
442
443                     /*
444                      * get infos about this type
445                      */
446                     while (xpmDataTypes[n].type
447                            && strncmp(xpmDataTypes[n].type, buf, l))
448                         n++;
449                 }
450                 data->format = 0;
451             } else
452                 /* nope this is not an XPM file */
453                 return XpmFileInvalid;
454         }
455         if (xpmDataTypes[n].type) {
456             if (n == 0) {               /* natural type */
457                 data->Bcmt = xpmDataTypes[n].Bcmt;
458                 data->Ecmt = xpmDataTypes[n].Ecmt;
459                 xpmNextString(data);    /* skip the end of the headerline */
460                 data->Bos = xpmDataTypes[n].Bos;
461                 data->Eos = xpmDataTypes[n].Eos;
462             } else {
463                 data->Bcmt = xpmDataTypes[n].Bcmt;
464                 data->Ecmt = xpmDataTypes[n].Ecmt;
465                 if (!data->format) {    /* XPM 2 or 3 */
466                     data->Bos = xpmDataTypes[n].Bos;
467                     data->Eos = '\0';
468                     /* get to the beginning of the first string */
469                     xpmNextString(data);
470                     data->Eos = xpmDataTypes[n].Eos;
471                 } else                  /* XPM 1 skip end of line */
472                     xpmNextString(data);
473             }
474         } else
475             /* we don't know about that type of XPM file... */
476             return XpmFileInvalid;
477     }
478     return XpmSuccess;
479 }