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
ParseComment(xpmData * data)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;
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 */
185 int
xpmNextString(xpmData * data)186 xpmNextString(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 */
240 unsigned int
xpmNextWord(xpmData * data,char * buf,unsigned int buflen)241 xpmNextWord(
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 */
277 int
xpmNextUI(xpmData * data,unsigned int * ui_return)278 xpmNextUI(
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 */
292 int
xpmGetString(xpmData * data,char ** sptr,unsigned int * l)293 xpmGetString(
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 */
376 int
xpmGetCmt(xpmData * data,char ** cmt)377 xpmGetCmt(
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
394 xpmDataType 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 */
405 int
xpmParseHeader(xpmData * data)406 xpmParseHeader(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 }
482