1 /***********************************************************************
2 *
3 * Blox
4 *
5 * Standardized, Tk-based GUI widgets available for various window
6 * systems - Interface to Tcl
7 *
8 ***********************************************************************/
9
10 /***********************************************************************
11 *
12 * Copyright 1992, 1994, 1995, 1999, 2000, 2001, 2002, 2006, 2009
13 * Free Software Foundation, Inc.
14 * Written by Paolo Bonzini.
15 *
16 * This file is part of GNU Smalltalk.
17 *
18 * GNU Smalltalk is free software; you can redistribute it and/or modify it
19 * under the terms of the GNU General Public License as published by the Free
20 * Software Foundation; either version 2, or (at your option) any later
21 * version.
22 *
23 * Linking GNU Smalltalk statically or dynamically with other modules is
24 * making a combined work based on GNU Smalltalk. Thus, the terms and
25 * conditions of the GNU General Public License cover the whole
26 * combination.
27 *
28 * In addition, as a special exception, the Free Software Foundation
29 * give you permission to combine GNU Smalltalk with free software
30 * programs or libraries that are released under the GNU LGPL and with
31 * independent programs running under the GNU Smalltalk virtual machine.
32 *
33 * You may copy and distribute such a system following the terms of the
34 * GNU GPL for GNU Smalltalk and the licenses of the other code
35 * concerned, provided that you include the source code of that other
36 * code when and as the GNU GPL requires distribution of source code.
37 *
38 * Note that people who make modified versions of GNU Smalltalk are not
39 * obligated to grant this special exception for their modified
40 * versions; it is their choice whether to do so. The GNU General
41 * Public License gives permission to release a modified version without
42 * this exception; this exception also makes it possible to release a
43 * modified version which carries forward this exception.
44 *
45 * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
46 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
47 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
48 * more details.
49 *
50 * You should have received a copy of the GNU General Public License along with
51 * GNU Smalltalk; see the file COPYING. If not, write to the Free Software
52 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
53 *
54 * Here is the copyright notice for the XPM code:
55 * Copyright (C) 1989-94 GROUPE BULL
56 *
57 * Permission is hereby granted, free of charge, to any person obtaining a copy
58 * of this software and associated documentation files (the "Software"), to
59 * deal in the Software without restriction, including without limitation the
60 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
61 * sell copies of the Software, and to permit persons to whom the Software is
62 * furnished to do so, subject to the following conditions:
63 *
64 * The above copyright notice and this permission notice shall be included in
65 * all copies or substantial portions of the Software.
66 *
67 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
68 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
69 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
70 * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
71 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
72 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
73 *
74 * Except as contained in this notice, the name of GROUPE BULL shall not be
75 * used in advertising or otherwise to promote the sale, use or other dealings
76 * in this Software without prior written authorization from GROUPE BULL.
77
78 ***********************************************************************/
79
80 #include "config.h"
81 #include "gstpub.h"
82 #include <stdlib.h>
83
84 #ifndef HAVE_TCLTK
85 #error Tcl/Tk 8.0 needed to install the GNU Smalltalk GUI
86 #endif
87
88 #include <stdio.h>
89 #include <ctype.h>
90 #include <errno.h>
91 #include <tcl.h>
92 #define USE_COMPOSITELESS_PHOTO_PUT_BLOCK
93 #define USE_OLD_IMAGE
94 #include <tk.h>
95
96 /* Hack for API changes in Tcl 8.4.0 */
97 #ifndef CONST84
98 #define CONST84
99 #endif
100
101 #ifdef STDC_HEADERS
102 #include <stdlib.h>
103 #include <string.h>
104 #endif
105
106 /* Smalltalk call-ins */
107 static Tcl_Interp *tclInit (void);
108 static void bloxIdle (void);
109
110 /* TCL callbacks */
111 static int doCallback (ClientData clientData, Tcl_Interp * interp, int argc,
112 CONST84 char **argv);
113 static int xpmFileMatch (Tcl_Channel channel, char *fileName,
114 char *formatString, int *widthPtr, int *heightPtr);
115 static int xpmStringMatch (char *string, char *formatString, int *widthPtr,
116 int *heightPtr);
117 static int xpmFileRead (Tcl_Interp * interp, Tcl_Channel channel,
118 char *fileName, char *formatString,
119 Tk_PhotoHandle imageHandle, int destX, int destY,
120 int width, int height, int srcX, int srcY);
121 static int xpmStringRead (Tcl_Interp * interp, char *string,
122 char *formatString, Tk_PhotoHandle imageHandle,
123 int destX, int destY, int width, int height,
124 int srcX, int srcY);
125
126 /* Globals */
127
128 static void xpmInit (void);
129 static VMProxy *vmProxy;
130
131 void
bloxIdle(void)132 bloxIdle (void)
133 {
134 while (Tcl_DoOneEvent (TCL_ALL_EVENTS | TCL_DONT_WAIT));
135 }
136
137
138 int
doCallback(ClientData clientData,Tcl_Interp * interp,int argc,CONST84 char ** argv)139 doCallback (ClientData clientData, Tcl_Interp * interp, int argc, CONST84 char **argv)
140 {
141 OOP oop, *args;
142 int i;
143 char result[2] = "0";
144
145 /* argv[0] is "callback", the command name */
146 args = alloca (sizeof (OOP) * (argc - 2));
147 oop = vmProxy->idToOOP (atoi (argv[1]));
148 for (i = 0; i < argc - 3; i++)
149 args[i] = vmProxy->stringToOOP (argv[i + 3]);
150
151 args[argc - 3] = NULL;
152 if (vmProxy->vmsgSend (oop, vmProxy->symbolToOOP (argv[2]), args)
153 == vmProxy->trueOOP)
154 result[0]++;
155
156 Tcl_SetResult (interp, result, TCL_VOLATILE);
157 return TCL_OK;
158 }
159
160
161 Tcl_Interp *
tclInit(void)162 tclInit (void)
163 {
164 static Tcl_Interp *interp;
165 char *tclLibrary;
166 if (interp)
167 return (NULL);
168
169 interp = Tcl_CreateInterp ();
170 tclLibrary = getenv ("TCL_LIBRARY");
171 if (tclLibrary)
172 Tcl_SetVar (interp, "tcl_library", tclLibrary, TCL_GLOBAL_ONLY);
173
174 if (Tcl_Init (interp) == TCL_ERROR)
175 {
176 fprintf (stderr, "Tcl_Init failed: %s\n", interp->result);
177 exit (1);
178 }
179 if (Tk_Init (interp) == TCL_ERROR)
180 {
181 fprintf (stderr, "Tk_Init failed: %s\n", interp->result);
182 exit (1);
183 }
184 Tcl_CreateCommand (interp, "callback", doCallback, NULL, NULL);
185 xpmInit ();
186
187 return (interp);
188 }
189
190 void
gst_initModule(VMProxy * proxy)191 gst_initModule (VMProxy * proxy)
192 {
193 Tcl_FindExecutable ("");
194
195 vmProxy = proxy;
196 vmProxy->defineCFunc ("Tcl_Eval", Tcl_Eval);
197 vmProxy->defineCFunc ("Tcl_GetStringResult", Tcl_GetStringResult);
198 vmProxy->defineCFunc ("tclInit", tclInit);
199 vmProxy->defineCFunc ("bloxIdle", bloxIdle);
200 }
201
202 /******************* BEGINNING OF XPM CODE ***********************/
203
204 typedef struct
205 {
206 const char *cptr;
207 const char *Bcmt;
208 const char *Ecmt;
209 char Bos, Eos;
210 mst_Boolean xpm1; /* 1 if XPM1, 0 otherwise */
211 }
212 XpmData;
213
214 #include "rgbtab.h"
215
216 /* number of xpmColorKeys */
217 #define NKEYS 5
218
219 const char *xpmColorKeys[] = {
220 "s", /* key #1: symbol */
221 "m", /* key #2: mono visual */
222 "g4", /* key #3: 4 grays visual */
223 "g", /* key #4: gray visual */
224 "c", /* key #5: color visual */
225 };
226
227 typedef struct
228 {
229 const char *type; /* key word */
230 const char *Bcmt; /* string beginning comments */
231 const char *Ecmt; /* string ending comments */
232 char Bos; /* character beginning strings */
233 char Eos; /* character ending strings */
234 }
235 XpmDataType;
236
237 typedef struct
238 {
239 char *string; /* characters string */
240 char *symbolic; /* symbolic name */
241 char *m_color; /* monochrom default */
242 char *g4_color; /* 4 level grayscale default */
243 char *g_color; /* other level grayscale default */
244 char *c_color; /* color default */
245 int rgb;
246 }
247 XpmColor;
248
249 typedef struct
250 {
251 unsigned int width; /* image width */
252 unsigned int height; /* image height */
253 unsigned int *data; /* image data */
254 }
255 XpmImage;
256
257
258 static XpmDataType xpmDataTypes[] = {
259 {"", "!", "\n", '\0', '\n'}, /* Natural type */
260 {"C", "/*", "*/", '"', '"'},
261 {"Lisp", ";", "\n", '"', '"'},
262 {NULL, NULL, NULL, 0, 0,}
263 };
264
265 static int xpmParseHeader (XpmData * mdata);
266 static int xpmParseValues (XpmData * data,
267 unsigned int *width,
268 unsigned int *height,
269 unsigned int *ncolors,
270 unsigned int *cpp);
271 static int xpmParseColors (XpmData * data,
272 unsigned int ncolors,
273 unsigned int cpp,
274 XpmColor ** colorTablePtr);
275 static int xpmParsePixels (XpmData * data,
276 unsigned int width,
277 unsigned int height,
278 unsigned int ncolors,
279 unsigned int cpp,
280 XpmColor *colorTable,
281 unsigned int **pixels);
282 static int xpmParseData (char *buffer,
283 XpmImage * image,
284 mst_Boolean readPixels);
285
286 static mst_Boolean xpmNextUI (XpmData * mdata,
287 unsigned int *ui_return);
288
289 static mst_Boolean atoui (char *buf,
290 int l,
291 unsigned int *ui_return);
292
293 static void xpmNextString (XpmData * mdata);
294
295 static void xpmParseComment (XpmData * mdata);
296
297 static void xpmFreeColorTable (XpmColor * colorTable,
298 int ncolors);
299
300 static unsigned int xpmNextWord (XpmData * mdata, char *buf,
301 unsigned int buflen);
302
303 static void ParseNumericColor (char *str,
304 int *prgb);
305
306 static void ParseXColor (Tk_Uid uid,
307 int *prgb);
308
309 void
ParseNumericColor(char * str,int * prgb)310 ParseNumericColor (char *str, int *prgb)
311 {
312 #define HEX(ch, shift) \
313 ( ((unsigned int) (((ch) - ((ch) < 'A' ? 48 : 55)) & 15)) << (shift))
314
315 switch (strlen (str))
316 {
317 case 4:
318 *prgb = HEX (str[1], 20) | HEX (str[2], 12) | HEX (str[1], 4);
319 return;
320
321 case 7:
322 *prgb = HEX (str[1], 20) | HEX (str[3], 12) | HEX (str[5], 4)
323 | HEX (str[2], 16) | HEX (str[4], 8) | HEX (str[6], 0);
324 return;
325
326 case 10:
327 *prgb = HEX (str[1], 20) | HEX (str[4], 12) | HEX (str[7], 4)
328 | HEX (str[2], 16) | HEX (str[5], 8) | HEX (str[8], 0);
329 return;
330
331 case 13:
332 *prgb = HEX (str[1], 20) | HEX (str[5], 12) | HEX (str[9], 4)
333 | HEX (str[2], 16) | HEX (str[6], 8) | HEX (str[10], 0);
334 return;
335 }
336 }
337
338 void
ParseXColor(Tk_Uid uid,int * prgb)339 ParseXColor (Tk_Uid uid, int *prgb)
340 {
341 xpmColorEntry *ce;
342
343 for (ce = xColors; ce->color; ce++)
344 {
345 if ((char *) ce->color == uid)
346 {
347 *prgb = ce->rgb;
348 return;
349 }
350 }
351 }
352
353 void
xpmParseComment(XpmData * mdata)354 xpmParseComment (XpmData * mdata)
355 {
356 register char c;
357 register unsigned int n = 0;
358 const char *s2;
359
360 /* skip the string beginning comment */
361 s2 = mdata->Bcmt;
362 do
363 {
364 c = *mdata->cptr++;
365 n++;
366 s2++;
367 }
368 while (c == *s2 && *s2 != '\0' && c && c != mdata->Bos);
369
370 if (*s2 != '\0')
371 {
372 /* this wasn't the beginning of a comment */
373 mdata->cptr -= n;
374 return;
375 }
376 /* skip comment */
377 do
378 {
379 s2 = mdata->Ecmt;
380 while (c && c != *s2 && c != mdata->Bos)
381 {
382 c = *mdata->cptr++;
383 }
384 do
385 {
386 c = *mdata->cptr++;
387 s2++;
388 }
389 while (c == *s2 && *s2 != '\0' && c && c != mdata->Bos);
390 }
391 while (*s2 != '\0');
392
393 /* this is the end of the comment */
394 mdata->cptr--;
395 return;
396 }
397
398 /*
399 * skip to the end of the current string and the beginning of the next one
400 */
401 void
xpmNextString(XpmData * mdata)402 xpmNextString (XpmData * mdata)
403 {
404 register char c;
405
406 /* get to the end of the current string */
407 if (mdata->Eos)
408 while ((c = *mdata->cptr++) && c != mdata->Eos);
409
410 /*
411 * then get to the beginning of the next string looking for possible
412 * comment
413 */
414 if (mdata->Bos)
415 {
416 while ((c = *mdata->cptr++) && c != mdata->Bos)
417 if (mdata->Bcmt && c == mdata->Bcmt[0])
418 xpmParseComment (mdata);
419 }
420 else if (mdata->Bcmt)
421 { /* XPM2 natural */
422 while ((c = *mdata->cptr++) == mdata->Bcmt[0])
423 xpmParseComment (mdata);
424 mdata->cptr--;
425 }
426 return;
427 }
428
429
430 /*
431 * skip whitespace and return the following word
432 */
433 unsigned int
xpmNextWord(XpmData * mdata,char * buf,unsigned int buflen)434 xpmNextWord (XpmData * mdata, char *buf, unsigned int buflen)
435 {
436 register unsigned int n = 0;
437 int c;
438
439 while (isspace (c = *mdata->cptr) && c != mdata->Eos)
440 mdata->cptr++;
441 do
442 {
443 c = *mdata->cptr++;
444 *buf++ = c;
445 n++;
446 }
447 while (!isspace (c) && c != mdata->Eos && n < buflen);
448 n--;
449 mdata->cptr--;
450
451 return (n);
452 }
453
454 /*
455 * skip whitespace and compute the following unsigned int,
456 * returns true if one is found and false if not
457 */
458 mst_Boolean
atoui(char * buf,int l,unsigned int * ui_return)459 atoui (char *buf, int l, unsigned int *ui_return)
460 {
461 unsigned long int result;
462
463 buf[l] = 0;
464 errno = 0;
465 *ui_return = strtoul (buf, NULL, 0);
466 result = !errno;
467 errno = 0;
468 return (unsigned int) result;
469 }
470
471 mst_Boolean
xpmNextUI(XpmData * mdata,unsigned int * ui_return)472 xpmNextUI (XpmData * mdata, unsigned int *ui_return)
473 {
474 long int l;
475 char buf[BUFSIZ + 1];
476
477 l = xpmNextWord (mdata, buf, BUFSIZ);
478 return atoui (buf, l, ui_return);
479 }
480
481 /*
482 * parse xpm header
483 */
484 int
xpmParseHeader(XpmData * mdata)485 xpmParseHeader (XpmData * mdata)
486 {
487 char buf[BUFSIZ + 1];
488 int l, n = 0;
489
490 mdata->Bos = '\0';
491 mdata->Eos = '\n';
492 mdata->Bcmt = mdata->Ecmt = NULL;
493 l = xpmNextWord (mdata, buf, BUFSIZ);
494 if (l == 7 && !strncmp ("#define", buf, 7))
495 {
496 /* this maybe an XPM 1 file */
497 char *ptr;
498
499 l = xpmNextWord (mdata, buf, BUFSIZ);
500 if (!l)
501 return (TCL_ERROR); /* File Invalid */
502 ptr = strchr (buf, '_');
503 if (!ptr || strncmp ("_format", ptr, l - (ptr - buf)))
504 return (TCL_ERROR); /* File Invalid */
505 /* this is definitely an XPM 1 file */
506 mdata->xpm1 = true;
507 n = 1; /* handle XPM1 as mainly XPM2 C */
508 }
509 else
510 {
511
512 /*
513 * skip the first word, get the second one, and see if this is
514 * XPM 2 or 3
515 */
516 l = xpmNextWord (mdata, buf, BUFSIZ);
517 if ((l == 3 && !strncmp ("XPM", buf, 3)) ||
518 (l == 4 && !strncmp ("XPM2", buf, 4)))
519 {
520 if (l == 3)
521 n = 1; /* handle XPM as XPM2 C */
522 else
523 {
524 /* get the type key word */
525 l = xpmNextWord (mdata, buf, BUFSIZ);
526
527 /*
528 * get infos about this type
529 */
530 while (xpmDataTypes[n].type
531 && strncmp (xpmDataTypes[n].type, buf, l))
532 n++;
533 }
534 mdata->xpm1 = false;
535 }
536 else
537 /* nope this is not an XPM file */
538 return (TCL_ERROR); /* File Invalid */
539 }
540 if (xpmDataTypes[n].type)
541 {
542 if (n == 0)
543 { /* natural type */
544 mdata->Bcmt = xpmDataTypes[n].Bcmt;
545 mdata->Ecmt = xpmDataTypes[n].Ecmt;
546 xpmNextString (mdata); /* skip the end of the headerline */
547 mdata->Bos = xpmDataTypes[n].Bos;
548 mdata->Eos = xpmDataTypes[n].Eos;
549 }
550 else
551 {
552 mdata->Bcmt = xpmDataTypes[n].Bcmt;
553 mdata->Ecmt = xpmDataTypes[n].Ecmt;
554 if (!mdata->xpm1)
555 { /* XPM 2 or 3 */
556 mdata->Bos = xpmDataTypes[n].Bos;
557 mdata->Eos = '\0';
558 /* get to the beginning of the first string */
559 xpmNextString (mdata);
560 mdata->Eos = xpmDataTypes[n].Eos;
561 }
562 else /* XPM 1 skip end of line */
563 xpmNextString (mdata);
564 }
565 }
566 else
567 /* we don't know about that type of XPM file... */
568 return (TCL_ERROR); /* File Invalid */
569
570 return (TCL_OK);
571 }
572
573 int
xpmParseValues(XpmData * data,unsigned int * width,unsigned int * height,unsigned int * ncolors,unsigned int * cpp)574 xpmParseValues (XpmData * data, unsigned int *width, unsigned int *height,
575 unsigned int *ncolors, unsigned int *cpp)
576 {
577 unsigned int l;
578 unsigned int x_hotspot, y_hotspot, hotspot;
579 unsigned int extensions;
580 char buf[BUFSIZ + 1];
581
582 if (!data->xpm1)
583 { /* XPM 2 or 3 */
584
585 /*
586 * read values: width, height, ncolors, chars_per_pixel
587 */
588 if (!(xpmNextUI (data, width) && xpmNextUI (data, height)
589 && xpmNextUI (data, ncolors) && xpmNextUI (data, cpp)))
590 return (TCL_ERROR); /* File invalid */
591
592 /*
593 * read optional information (hotspot and/or XPMEXT) if any
594 */
595 l = xpmNextWord (data, buf, BUFSIZ);
596 if (l)
597 {
598 extensions = (l == 6 && !strncmp ("XPMEXT", buf, 6));
599 if (extensions)
600 hotspot = (xpmNextUI (data, &x_hotspot)
601 && xpmNextUI (data, &y_hotspot));
602 else
603 {
604 hotspot = (atoui (buf, l, &x_hotspot)
605 && xpmNextUI (data, &y_hotspot));
606 l = xpmNextWord (data, buf, BUFSIZ);
607 }
608 }
609 }
610 else
611 {
612
613 /*
614 * XPM 1 file read values: width, height, ncolors, chars_per_pixel
615 */
616 int i;
617 char *ptr;
618
619 for (i = 0; i < 4; i++)
620 {
621 l = xpmNextWord (data, buf, BUFSIZ);
622 if (l != 7 || strncmp ("#define", buf, 7))
623 return (TCL_ERROR); /* File invalid */
624 l = xpmNextWord (data, buf, BUFSIZ);
625 if (!l)
626 return (TCL_ERROR); /* File invalid */
627 ptr = strchr (buf, '_');
628 if (!ptr)
629 return (TCL_ERROR); /* File invalid */
630 switch (l - (ptr - buf))
631 {
632 case 6:
633 if (!strncmp ("_width", ptr, 6) && !xpmNextUI (data, width))
634 return (TCL_ERROR); /* File invalid */
635 break;
636 case 7:
637 if (!strncmp ("_height", ptr, 7) && !xpmNextUI (data, height))
638 return (TCL_ERROR); /* File invalid */
639 break;
640 case 8:
641 if (!strncmp ("_ncolors", ptr, 8) && !xpmNextUI (data, ncolors))
642 return (TCL_ERROR); /* File invalid */
643 break;
644 case 16:
645 if (!strncmp ("_chars_per_pixel", ptr, 16)
646 && !xpmNextUI (data, cpp))
647 return (TCL_ERROR); /* File invalid */
648 break;
649 default:
650 return (TCL_ERROR); /* File invalid */
651 }
652 /* skip the end of line */
653 xpmNextString (data);
654 }
655 }
656 return (TCL_OK);
657 }
658
659 int
xpmParseColors(XpmData * data,unsigned int ncolors,unsigned int cpp,XpmColor ** colorTablePtr)660 xpmParseColors (XpmData * data, unsigned int ncolors, unsigned int cpp,
661 XpmColor ** colorTablePtr)
662 {
663 unsigned int key, l, a, b;
664 unsigned int curkey; /* current color key */
665 unsigned int lastwaskey; /* key read */
666 char buf[BUFSIZ + 1];
667 char curbuf[BUFSIZ + 1]; /* current buffer */
668 const char **sptr;
669 char *s;
670 XpmColor *color;
671 XpmColor *colorTable;
672 char **defaults;
673
674 colorTable = (XpmColor *) malloc (ncolors * sizeof (XpmColor));
675 if (!colorTable)
676 return (TCL_ERROR); /* No memory */
677
678 memset (colorTable, 0, ncolors * sizeof (XpmColor));
679 if (!data->xpm1)
680 { /* XPM 2 or 3 */
681 for (a = 0, color = colorTable; a < ncolors; a++, color++)
682 {
683 xpmNextString (data); /* skip the line */
684
685 /*
686 * read pixel value
687 */
688 color->string = (char *) malloc (cpp + 1);
689 if (!color->string)
690 {
691 xpmFreeColorTable (colorTable, ncolors);
692 return (TCL_ERROR); /* No memory */
693 }
694 for (b = 0, s = color->string; b < cpp; b++, s++)
695 *s = *data->cptr++;
696 *s = '\0';
697
698 /*
699 * read color keys and values
700 */
701 defaults = (char **) color;
702 key = NKEYS;
703 curkey = 0;
704 lastwaskey = 0;
705 *curbuf = '\0'; /* init curbuf */
706 while ((l = xpmNextWord (data, buf, BUFSIZ)) != 0)
707 {
708 if (!lastwaskey)
709 {
710 for (key = 0, sptr = xpmColorKeys; key < NKEYS;
711 key++, sptr++)
712 if ((strlen (*sptr) == l) && (!strncmp (*sptr, buf, l)))
713 break;
714 }
715 if (!lastwaskey && key < NKEYS)
716 { /* open new key */
717 if (curkey)
718 { /* flush string */
719 s = (char *) malloc (strlen (curbuf) + 1);
720 if (!s)
721 {
722 xpmFreeColorTable (colorTable, ncolors);
723 return (TCL_ERROR); /* No memory */
724 }
725 defaults[curkey] = s;
726 strcpy (s, curbuf);
727 }
728 curkey = key + 1; /* set new key */
729 *curbuf = '\0'; /* reset curbuf */
730 lastwaskey = 1;
731 }
732 else
733 {
734 if (!curkey)
735 { /* key without value */
736 xpmFreeColorTable (colorTable, ncolors);
737 return (TCL_ERROR); /* File invalid */
738 }
739 if (!lastwaskey)
740 strcat (curbuf, " "); /* append space */
741 buf[l] = '\0';
742 strcat (curbuf, buf); /* append buf */
743 lastwaskey = 0;
744 }
745 }
746 if (!curkey)
747 { /* key without value */
748 xpmFreeColorTable (colorTable, ncolors);
749 return (TCL_ERROR); /* File invalid */
750 }
751 s = defaults[curkey] = (char *) malloc (strlen (curbuf) + 1);
752 if (!s)
753 {
754 xpmFreeColorTable (colorTable, ncolors);
755 return (TCL_ERROR); /* No memory */
756 }
757 strcpy (s, curbuf);
758 }
759 }
760 else
761 { /* XPM 1 */
762 /* get to the beginning of the first string */
763 data->Bos = '"';
764 data->Eos = '\0';
765 xpmNextString (data);
766 data->Eos = '"';
767 for (a = 0, color = colorTable; a < ncolors; a++, color++)
768 {
769
770 /*
771 * read pixel value
772 */
773 color->string = (char *) malloc (cpp + 1);
774 if (!color->string)
775 {
776 xpmFreeColorTable (colorTable, ncolors);
777 return (TCL_ERROR); /* No memory */
778 }
779 for (b = 0, s = color->string; b < cpp; b++, s++)
780 *s = *data->cptr++;
781 *s = '\0';
782
783 /*
784 * read color values
785 */
786 xpmNextString (data); /* get to the next string */
787 *curbuf = '\0'; /* init curbuf */
788 while ((l = xpmNextWord (data, buf, BUFSIZ)) != 0)
789 {
790 if (*curbuf != '\0')
791 strcat (curbuf, " "); /* append space */
792 buf[l] = '\0';
793 strcat (curbuf, buf); /* append buf */
794 }
795 s = (char *) malloc (strlen (curbuf) + 1);
796 if (!s)
797 {
798 xpmFreeColorTable (colorTable, ncolors);
799 return (TCL_ERROR); /* No memory */
800 }
801 strcpy (s, curbuf);
802 color->c_color = s;
803 *curbuf = '\0'; /* reset curbuf */
804 if (a < ncolors - 1)
805 xpmNextString (data); /* get to the next string */
806 }
807 }
808
809 for (a = 0, color = colorTable; a < ncolors; a++, color++)
810 {
811 Tk_Uid noneUid = Tk_GetUid ("None");
812
813 for (curkey = NKEYS, color->rgb = -2, defaults = (char **) color;
814 color->rgb == -2 && curkey; curkey--)
815 {
816
817 Tk_Uid colorUid;
818 if (!defaults[curkey])
819 continue;
820
821 if (defaults[curkey][0] == '#')
822 {
823 ParseNumericColor (defaults[curkey], &color->rgb);
824 continue;
825 }
826 if (!strncmp (defaults[curkey], "grey", 4))
827 {
828 /* Recognize `greys' too, not just `grays'... */
829 defaults[curkey][2] = 'a';
830 }
831
832 /* Make black the transparent color -- black becomes a very dark gray */
833 colorUid = Tk_GetUid (defaults[curkey]);
834 if (colorUid == noneUid)
835 {
836 color->rgb = 0;
837 continue;
838 }
839 ParseXColor (colorUid, &color->rgb);
840 if (!color->rgb)
841 color->rgb = 0x30303; /* This is gray1 */
842 }
843 }
844
845 *colorTablePtr = colorTable;
846 return (TCL_OK);
847 }
848
849 int
xpmParsePixels(XpmData * data,unsigned int width,unsigned int height,unsigned int ncolors,unsigned int cpp,XpmColor * colorTable,unsigned int ** pixels)850 xpmParsePixels (XpmData * data, unsigned int width, unsigned int height,
851 unsigned int ncolors, unsigned int cpp, XpmColor * colorTable,
852 unsigned int **pixels)
853 {
854 unsigned int *iptr, *iptr2;
855 unsigned int a, x, y;
856
857 iptr2 = (unsigned int *) malloc (sizeof (unsigned int) * width * height);
858 if (!iptr2)
859 return (TCL_ERROR); /* No memory */
860
861 iptr = iptr2;
862
863 switch (cpp)
864 {
865
866 case (1): /* Optimize for single character colors */
867 {
868 unsigned int colrgb[256];
869
870 memset (colrgb, 0, 256 * sizeof (int));
871 for (a = 0; a < 256; a++)
872 colrgb[a] = -1;
873 for (a = 0; a < ncolors; a++)
874 colrgb[(unsigned int) colorTable[a].string[0]] = colorTable[a].rgb;
875
876 for (y = 0; y < height; y++)
877 {
878 xpmNextString (data);
879 for (x = 0; x < width; x++, iptr++)
880 {
881 int rgb = colrgb[(unsigned int) *data->cptr++];
882
883 if (rgb != -1)
884 *iptr = rgb;
885 else
886 {
887 free (iptr2);
888 return (TCL_ERROR); /* File invalid */
889 }
890 }
891 }
892 }
893 break;
894
895 case (2): /* Optimize for double character scolors */
896 {
897
898 /* free all allocated pointers at all exits */
899 #define FREE_CRGB {int f; for (f = 0; f < 256; f++) \
900 if (crgb[f]) free(crgb[f]);}
901
902 /* array of pointers malloced by need */
903 unsigned int *crgb[256];
904 int char1, a2;
905
906 memset (crgb, 0, 256 * sizeof (unsigned int *)); /* init */
907 for (a = 0; a < ncolors; a++)
908 {
909 char1 = colorTable[a].string[0];
910 if (crgb[char1] == NULL)
911 { /* get new memory */
912 crgb[char1] = (unsigned int *)
913 malloc (256 * sizeof (unsigned int));
914 if (crgb[char1] == NULL)
915 { /* new block failed */
916 FREE_CRGB;
917 free (iptr2);
918 return (TCL_ERROR); /* No memory */
919 }
920 for (a2 = 0; a2 < 256; a2++)
921 crgb[char1][a2] = -1;
922 }
923 crgb[char1][(unsigned int) colorTable[a].string[1]] =
924 colorTable[a].rgb;
925 }
926
927 for (y = 0; y < height; y++)
928 {
929 xpmNextString (data);
930 for (x = 0; x < width; x++, iptr++)
931 {
932 int cc1 = *data->cptr++;
933 int rgb = crgb[cc1][(unsigned int) *data->cptr++];
934
935 if (rgb != -1)
936 *iptr = rgb - 1;
937 else
938 {
939 FREE_CRGB;
940 free (iptr2);
941 return (TCL_ERROR); /* File invalid */
942 }
943 }
944 }
945 FREE_CRGB;
946 }
947 break;
948
949 default: /* Long color names */
950 return (TCL_ERROR); /* Not supported */
951 }
952 *pixels = iptr2;
953 return (TCL_OK);
954 }
955
956 /*
957 * This function parses an xpm file or data and store the found informations
958 * in an an XpmImage structure which is returned.
959 */
960 int
xpmParseData(char * buffer,XpmImage * image,mst_Boolean readPixels)961 xpmParseData (char *buffer, XpmImage * image, mst_Boolean readPixels)
962 {
963 /* variables to return */
964 unsigned int width, height, ncolors, cpp;
965 XpmColor *colorTable = NULL;
966 unsigned int *pixelindex = NULL;
967
968 int ErrorStatus;
969 XpmData data;
970
971 /*
972 * parse the header
973 */
974 memset (image, 0, sizeof (XpmImage));
975 data.cptr = buffer;
976 ErrorStatus = xpmParseHeader (&data);
977 if (ErrorStatus != TCL_OK)
978 return (ErrorStatus);
979
980 /*
981 * read values
982 */
983 ErrorStatus = xpmParseValues (&data, &width, &height, &ncolors, &cpp);
984 if (ErrorStatus != TCL_OK)
985 return (ErrorStatus);
986
987 /*
988 * store found informations in the XpmImage structure
989 */
990 image->width = width;
991 image->height = height;
992 if (!readPixels)
993 return (TCL_OK);
994
995 /*
996 * read colors
997 */
998 ErrorStatus = xpmParseColors (&data, ncolors, cpp, &colorTable);
999 if (ErrorStatus != TCL_OK)
1000 return (ErrorStatus);
1001
1002 /*
1003 * read pixels and index them on color number
1004 */
1005 ErrorStatus =
1006 xpmParsePixels (&data, width, height, ncolors, cpp, colorTable,
1007 &pixelindex);
1008
1009 xpmFreeColorTable (colorTable, ncolors);
1010 if (ErrorStatus != TCL_OK)
1011 return (ErrorStatus);
1012
1013 image->data = pixelindex;
1014 return (TCL_OK);
1015 }
1016
1017 /*
1018 * Free the computed color table
1019 */
1020 void
xpmFreeColorTable(XpmColor * colorTable,int ncolors)1021 xpmFreeColorTable (XpmColor * colorTable, int ncolors)
1022 {
1023 int a, b;
1024 XpmColor *color;
1025 char **sptr;
1026
1027 for (a = 0, color = colorTable; a < ncolors; a++, color++)
1028 {
1029 for (b = 0, sptr = (char **) color; b <= NKEYS; b++, sptr++)
1030 if (*sptr)
1031 free (*sptr);
1032 }
1033 free (colorTable);
1034 }
1035
1036
1037 /******************************* TCL INTERFACE FOR XPM **************/
1038
1039 int
xpmStringMatch(char * string,char * formatString,int * widthPtr,int * heightPtr)1040 xpmStringMatch (char *string, char *formatString, int *widthPtr,
1041 int *heightPtr)
1042 {
1043 XpmImage img;
1044 int result;
1045
1046 result = xpmParseData (string, &img, false);
1047 if (result != TCL_OK)
1048 {
1049 return (0);
1050 }
1051 *widthPtr = img.width;
1052 *heightPtr = img.height;
1053 return (1);
1054 }
1055
1056 int
xpmStringRead(Tcl_Interp * interp,char * string,char * formatString,Tk_PhotoHandle imageHandle,int destX,int destY,int width,int height,int srcX,int srcY)1057 xpmStringRead (Tcl_Interp * interp, char *string, char *formatString,
1058 Tk_PhotoHandle imageHandle, int destX, int destY, int width,
1059 int height, int srcX, int srcY)
1060 {
1061 XpmImage img;
1062 int result;
1063 unsigned int *block;
1064
1065 #ifdef WORDS_BIG_ENDIAN
1066 #define BYTEOFS(i) (sizeof(int)-i)
1067 #else
1068 #define BYTEOFS(i) (i)
1069 #endif
1070
1071 static Tk_PhotoImageBlock blk = {
1072 NULL, /* unsigned char *pixelPtr; */
1073 0, /* int width; */
1074 1, /* int height; */
1075 0, /* int pitch; */
1076 sizeof (int), /* int pixelSize; */
1077 {BYTEOFS (2), BYTEOFS (1), BYTEOFS (0)}, /* int offset[3]; */
1078 };
1079
1080 #undef BYTEOFS
1081
1082 result = xpmParseData (string, &img, true);
1083 if (result != TCL_OK)
1084 return (result);
1085
1086 for (block = img.data + img.width * srcY + srcX; img.height;
1087 img.height--, destY++)
1088 {
1089 int todo;
1090 unsigned int last;
1091
1092 for (blk.pixelPtr = (PTR) block, blk.width = 0, last = *block,
1093 destX = 0, todo = img.width; todo--; last = *block, block++)
1094 {
1095
1096 if ((*block == 0) ^ (last == 0))
1097 {
1098 if (last)
1099 Tk_PhotoPutBlock (imageHandle, &blk, destX, destY,
1100 blk.width, 1);
1101 destX += blk.width;
1102 blk.width = 1;
1103 blk.pixelPtr = (PTR) block;
1104 }
1105 else
1106 blk.width++;
1107 }
1108
1109 if (last)
1110 Tk_PhotoPutBlock (imageHandle, &blk, destX, destY, blk.width, 1);
1111 }
1112
1113 free (img.data);
1114 return (result);
1115 }
1116
1117 int
xpmFileMatch(Tcl_Channel channel,char * fileName,char * formatString,int * widthPtr,int * heightPtr)1118 xpmFileMatch (Tcl_Channel channel, char *fileName, char *formatString,
1119 int *widthPtr, int *heightPtr)
1120 {
1121 int fileSize, bytesRead, result;
1122 char *buf;
1123 fileSize = Tcl_Seek (channel, 0, SEEK_END);
1124 if (fileSize < 0 || Tcl_Seek (channel, 0, SEEK_SET) < 0)
1125 return (0);
1126
1127 buf = malloc (fileSize + 1);
1128 if (!buf)
1129 return (0);
1130
1131 bytesRead = Tcl_Read (channel, buf, fileSize);
1132 if (bytesRead < 0)
1133 {
1134 free (buf);
1135 return (0);
1136 }
1137
1138 buf[bytesRead] = '\0';
1139 result = xpmStringMatch (buf, formatString, widthPtr, heightPtr);
1140 free (buf);
1141 return (result);
1142 }
1143
1144 int
xpmFileRead(Tcl_Interp * interp,Tcl_Channel channel,char * fileName,char * formatString,Tk_PhotoHandle imageHandle,int destX,int destY,int width,int height,int srcX,int srcY)1145 xpmFileRead (Tcl_Interp * interp, Tcl_Channel channel, char *fileName,
1146 char *formatString, Tk_PhotoHandle imageHandle, int destX,
1147 int destY, int width, int height, int srcX, int srcY)
1148 {
1149 int fileSize, bytesRead, result;
1150 char *buf;
1151 fileSize = Tcl_Seek (channel, 0, SEEK_END);
1152 if (fileSize < 0 || Tcl_Seek (channel, 0, SEEK_SET) < 0)
1153 return (TCL_ERROR);
1154
1155 buf = malloc (fileSize + 1);
1156 if (!buf)
1157 return (TCL_ERROR);
1158
1159 bytesRead = Tcl_Read (channel, buf, fileSize);
1160 if (bytesRead < 0)
1161 {
1162 free (buf);
1163 return (TCL_ERROR);
1164 }
1165
1166 buf[bytesRead] = '\0';
1167 result = xpmStringRead (interp, fileName, formatString, imageHandle,
1168 destX, destY, width, height, srcX, srcY);
1169 free (buf);
1170 return (result);
1171 }
1172
1173 void
xpmInit(void)1174 xpmInit (void)
1175 {
1176 static Tk_PhotoImageFormat xpmFormat = {
1177 (char *) "XPM",
1178 xpmFileMatch,
1179 xpmStringMatch,
1180 xpmFileRead,
1181 xpmStringRead,
1182 NULL,
1183 NULL,
1184 NULL
1185 };
1186 xpmColorEntry *ce;
1187
1188 Tk_CreatePhotoImageFormat (&xpmFormat);
1189
1190 for (ce = xColors; ce->color; ce++)
1191 ce->color = (char *) Tk_GetUid (ce->color);
1192 }
1193