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