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