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* sxpm.c:                                                                     *
28*                                                                             *
29*  Show XPM File program                                                      *
30*                                                                             *
31*  Developed by Arnaud Le Hors                                                *
32\*****************************************************************************/
33
34#ifdef HAVE_CONFIG_H
35#include <config.h>
36#endif
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <X11/StringDefs.h>
41#include <X11/Intrinsic.h>
42#include <X11/IntrinsicP.h>
43#include <X11/Shell.h>
44
45#ifdef VMS
46#include <X11/shape.h>
47#else
48#include <X11/extensions/shape.h>
49#endif
50
51#include <X11/xpm.h>
52
53#ifdef USE_GETTEXT
54#include <locale.h>
55#include <libintl.h>
56#else
57#define gettext(a) (a)
58#endif
59
60/* XPM */
61/* plaid pixmap */
62static char *plaid[] = {
63    /* width height ncolors chars_per_pixel */
64    "22 22 4 2 XPMEXT",
65    /* colors */
66    "   c red 	m white  s light_color",
67    "Y  c green	m black  s lines_in_mix",
68    "+  c yellow	m white  s lines_in_dark",
69    "x 		m black  s dark_color",
70    /* pixels */
71    "x   x   x x x   x   x x x x x x + x x x x x ",
72    "  x   x   x   x   x   x x x x x x x x x x x ",
73    "x   x   x x x   x   x x x x x x + x x x x x ",
74    "  x   x   x   x   x   x x x x x x x x x x x ",
75    "x   x   x x x   x   x x x x x x + x x x x x ",
76    "Y Y Y Y Y x Y Y Y Y Y + x + x + x + x + x + ",
77    "x   x   x x x   x   x x x x x x + x x x x x ",
78    "  x   x   x   x   x   x x x x x x x x x x x ",
79    "x   x   x x x   x   x x x x x x + x x x x x ",
80    "  x   x   x   x   x   x x x x x x x x x x x ",
81    "x   x   x x x   x   x x x x x x + x x x x x ",
82    "          x           x   x   x Y x   x   x ",
83    "          x             x   x   Y   x   x   ",
84    "          x           x   x   x Y x   x   x ",
85    "          x             x   x   Y   x   x   ",
86    "          x           x   x   x Y x   x   x ",
87    "x x x x x x x x x x x x x x x x x x x x x x ",
88    "          x           x   x   x Y x   x   x ",
89    "          x             x   x   Y   x   x   ",
90    "          x           x   x   x Y x   x   x ",
91    "          x             x   x   Y   x   x   ",
92    "          x           x   x   x Y x   x   x ",
93    "bullshit",
94    "XPMEXT ext1 data1",
95    "XPMEXT ext2",
96    "data2_1",
97    "data2_2",
98    "XPMEXT",
99    "foo",
100    "",
101    "XPMEXT ext3",
102    "data3",
103    "XPMENDEXT"
104};
105
106#define win XtWindow(topw)
107#define dpy XtDisplay(topw)
108#define root XRootWindowOfScreen(XtScreen(topw))
109#define xrdb XtDatabase(dpy)
110static Colormap colormap;
111
112void Usage(void) _X_NORETURN;
113void ErrorMessage(int ErrorStatus, const char *tag);
114void Punt(int i) _X_NORETURN;
115void VersionInfo(void);
116void kinput(Widget widget, char *tag, XEvent *xe, Boolean *b);
117void GetNumbers(int num, int *format_return,
118		int *libmajor_return,
119		char *libminor_return);
120
121#define IWIDTH      50
122#define IHEIGHT     50
123
124typedef struct _XpmIcon {
125    Pixmap pixmap;
126    Pixmap mask;
127    XpmAttributes attributes;
128}        XpmIcon;
129
130static char **command;
131static Widget topw;
132static XpmIcon view, icon;
133static XrmOptionDescRec options[] = {
134    {"-hints", ".hints", XrmoptionNoArg, (XtPointer) "True"},
135    {"-icon", ".icon", XrmoptionSepArg, (XtPointer) NULL},
136};
137
138int
139main(
140    int		  argc,
141    char	**argv)
142{
143    int ErrorStatus;
144    unsigned int verbose = 0;		/* performs verbose output */
145    unsigned int stdinf = 1;		/* read from stdin */
146    unsigned int stdoutf = 0;		/* write to stdout */
147    unsigned int nod = 0;		/* no display */
148    unsigned int nom = 0;		/* no mask display */
149    unsigned int incResize = 0;
150    unsigned int resize = 0;
151    unsigned int w_rtn;
152    unsigned int h_rtn;
153    char *input = NULL;
154    char *output = NULL;
155    char *iconFile = NULL;
156    unsigned int numsymbols = 0;
157    XpmColorSymbol symbols[10];
158    char *stype;
159    XrmValue val;
160    unsigned long valuemask = 0;
161    int n;
162    Arg args[4];
163
164#ifdef Debug
165    char **data;
166    char *buffer;
167#endif
168
169#ifdef USE_GETTEXT
170    XtSetLanguageProc(NULL,NULL,NULL);
171    bindtextdomain("sxpm",LOCALEDIR);
172    textdomain("sxpm");
173#endif
174
175    topw = XtInitialize(argv[0], "Sxpm",
176			options, XtNumber(options), &argc, argv);
177
178    if (!topw) {
179	/* L10N_Comments : Error if no $DISPLAY or $DISPLAY can't be opened.
180	   Not normally reached as Xt exits before we get here. */
181	fprintf(stderr, gettext("Sxpm Error... [ Undefined DISPLAY ]\n"));
182	exit(1);
183    }
184    colormap = XDefaultColormapOfScreen(XtScreen(topw));
185
186    /*
187     * geometry management
188     */
189
190    if (XrmGetResource(xrdb, NULL, "sxpm.geometry", &stype, &val)
191	|| XrmGetResource(xrdb, NULL, "Sxpm.geometry", &stype, &val)) {
192
193	int flags;
194	int x_rtn;
195	int y_rtn;
196	char *geo = NULL;
197
198	geo = (char *) val.addr;
199	flags = XParseGeometry(geo, &x_rtn, &y_rtn,
200			       (unsigned int *) &w_rtn,
201			       (unsigned int *) &h_rtn);
202
203	if (!((WidthValue & flags) && (HeightValue & flags)))
204	    resize = 1;
205
206    } else
207	resize = 1;
208
209    n = 0;
210    if (resize) {
211	w_rtn = 0;
212	h_rtn = 0;
213	XtSetArg(args[n], XtNwidth, 1);
214	n++;
215	XtSetArg(args[n], XtNheight, 1);
216	n++;
217    }
218    XtSetArg(args[n], XtNmappedWhenManaged, False);
219    n++;
220    XtSetArg(args[n], XtNinput, True);
221    n++;
222    XtSetValues(topw, args, n);
223
224    if ((XrmGetResource(xrdb, "sxpm.hints", "", &stype, &val)
225	 || XrmGetResource(xrdb, "Sxpm.hints", "", &stype, &val))
226	&& !strcmp((char *) val.addr, "True")) {
227	/* gotcha */
228	incResize = 1;
229	resize = 1;
230    }
231
232    /*
233     * icon management
234     */
235
236    if (XrmGetResource(xrdb, "sxpm.icon", "", &stype, &val)
237	|| XrmGetResource(xrdb, "Sxpm.icon", "", &stype, &val)) {
238	iconFile = (char *) val.addr;
239    }
240    if (iconFile) {
241
242	XColor color, junk;
243	Pixel bpix;
244	Window iconW;
245
246	if (XAllocNamedColor(dpy, colormap, "black", &color, &junk))
247	    bpix = color.pixel;
248	else
249	    bpix = XBlackPixelOfScreen(XtScreen(topw));
250
251	iconW = XCreateSimpleWindow(dpy, root, 0, 0,
252				    IWIDTH, IHEIGHT, 1, bpix, bpix);
253
254	icon.attributes.valuemask = XpmReturnAllocPixels;
255	ErrorStatus = XpmReadFileToPixmap(dpy, root, iconFile, &icon.pixmap,
256					  &icon.mask, &icon.attributes);
257	ErrorMessage(ErrorStatus, "Icon");
258
259	XSetWindowBackgroundPixmap(dpy, iconW, icon.pixmap);
260
261	n = 0;
262	XtSetArg(args[n], XtNbackground, bpix);
263	n++;
264	XtSetArg(args[n], XtNiconWindow, iconW);
265	n++;
266	XtSetValues(topw, args, n);
267    }
268
269    /*
270     * arguments parsing
271     */
272
273    command = argv;
274    for (n = 1; n < argc; n++) {
275	if (strcmp(argv[n], "-plaid") == 0) {
276	    stdinf = 0;
277	    continue;
278	}
279	if (argv[n][0] != '-') {
280	    stdinf = 0;
281	    input = argv[n];
282	    continue;
283	}
284	if ((strlen(argv[n]) == 1) && (argv[n][0] == '-'))
285	    /* stdin */
286	    continue;
287	if (strcmp(argv[n], "-o") == 0) {
288	    if (n < argc - 1) {
289		if ((strlen(argv[n + 1]) == 1) && (argv[n + 1][0] == '-'))
290		    stdoutf = 1;
291		else
292		    output = argv[n + 1];
293		n++;
294		continue;
295	    } else
296		Usage();
297	}
298	if (strcmp(argv[n], "-nod") == 0) {
299	    nod = 1;
300	    continue;
301	}
302	if (strcmp(argv[n], "-nom") == 0) {
303	    nom = 1;
304	    continue;
305	}
306	if (strcmp(argv[n], "-sc") == 0) {
307	    if (n < argc - 2) {
308		valuemask |= XpmColorSymbols;
309		symbols[numsymbols].name = argv[++n];
310		symbols[numsymbols++].value = argv[++n];
311		continue;
312	    } else
313		Usage();
314	}
315	if (strcmp(argv[n], "-sp") == 0) {
316	    if (n < argc - 2) {
317		valuemask |= XpmColorSymbols;
318		symbols[numsymbols].name = argv[++n];
319		symbols[numsymbols].value = NULL;
320		symbols[numsymbols++].pixel = atol(argv[++n]);
321		continue;
322	    }
323	}
324	if (strcmp(argv[n], "-cp") == 0) {
325	    if (n < argc - 2) {
326		valuemask |= XpmColorSymbols;
327		symbols[numsymbols].name = NULL;
328		symbols[numsymbols].value = argv[++n];
329		symbols[numsymbols++].pixel = atol(argv[++n]);
330		continue;
331	    }
332	}
333	if (strcmp(argv[n], "-mono") == 0) {
334	    valuemask |= XpmColorKey;
335	    view.attributes.color_key = XPM_MONO;
336	    continue;
337	}
338	if (strcmp(argv[n], "-gray4") == 0 || strcmp(argv[n], "-grey4") == 0) {
339	    valuemask |= XpmColorKey;
340	    view.attributes.color_key = XPM_GRAY4;
341	    continue;
342	}
343	if (strcmp(argv[n], "-gray") == 0 || strcmp(argv[n], "-grey") == 0) {
344	    valuemask |= XpmColorKey;
345	    view.attributes.color_key = XPM_GRAY;
346	    continue;
347	}
348	if (strcmp(argv[n], "-color") == 0) {
349	    valuemask |= XpmColorKey;
350	    view.attributes.color_key = XPM_COLOR;
351	    continue;
352	}
353	if (strncmp(argv[n], "-closecolors", 6) == 0) {
354	    valuemask |= XpmCloseness;
355	    view.attributes.closeness = 40000;
356	    continue;
357	}
358	if (strcmp(argv[n], "-rgb") == 0) {
359	    if (n < argc - 1) {
360		valuemask |= XpmRgbFilename;
361		view.attributes.rgb_fname = argv[++n];
362		continue;
363	    } else
364		Usage();
365
366	}
367	if (strncmp(argv[n], "-version", 4) == 0) {
368	    VersionInfo();
369	    exit(0);
370	}
371	if (strcmp(argv[n], "-v") == 0) {
372	    verbose = 1;
373	    continue;
374	}
375	if (strcmp(argv[n], "-pcmap") == 0) {
376	    valuemask |= XpmColormap;
377	    continue;
378	}
379	Usage();
380    }
381
382    XtRealizeWidget(topw);
383    if (valuemask & XpmColormap) {
384	colormap = XCreateColormap(dpy, win,
385				   DefaultVisual(dpy, DefaultScreen(dpy)),
386				   AllocNone);
387	view.attributes.colormap = colormap;
388	XSetWindowColormap(dpy, win, colormap);
389    }
390    view.attributes.colorsymbols = symbols;
391    view.attributes.numsymbols = numsymbols;
392    view.attributes.valuemask = valuemask;
393
394#ifdef Debug
395    /* this is just to test the XpmCreateDataFromPixmap function */
396
397    view.attributes.valuemask |= XpmReturnAllocPixels;
398    view.attributes.valuemask |= XpmReturnExtensions;
399    ErrorStatus = XpmCreatePixmapFromData(dpy, win, plaid,
400					  &view.pixmap, &view.mask,
401					  &view.attributes);
402    ErrorMessage(ErrorStatus, "Plaid");
403
404    ErrorStatus = XpmCreateDataFromPixmap(dpy, &data, view.pixmap, view.mask,
405					  &view.attributes);
406    ErrorMessage(ErrorStatus, "Data");
407    if (verbose && view.attributes.nextensions) {
408	unsigned int i, j;
409
410	for (i = 0; i < view.attributes.nextensions; i++) {
411	    fprintf(stderr, "Xpm extension : %s\n",
412		    view.attributes.extensions[i].name);
413	    for (j = 0; j < view.attributes.extensions[i].nlines; j++)
414		fprintf(stderr, "\t\t%s\n",
415			view.attributes.extensions[i].lines[j]);
416	}
417    }
418    XFreePixmap(dpy, view.pixmap);
419    if (view.mask)
420	XFreePixmap(dpy, view.mask);
421
422    XFreeColors(dpy, colormap,
423		view.attributes.alloc_pixels,
424		view.attributes.nalloc_pixels, 0);
425
426    XpmFreeAttributes(&view.attributes);
427    view.attributes.valuemask = valuemask;
428#endif
429
430    if (input || stdinf) {
431	view.attributes.valuemask |= XpmReturnInfos;
432	view.attributes.valuemask |= XpmReturnAllocPixels;
433	view.attributes.valuemask |= XpmReturnExtensions;
434
435#ifdef Debug
436	XpmFree(data);
437
438	/*
439	 * this is just to test the XpmCreatePixmapFromBuffer and
440	 * XpmCreateBufferFromPixmap functions
441	 */
442	ErrorStatus = XpmReadFileToBuffer(input, &buffer);
443	ErrorMessage(ErrorStatus, "CreateBufferFromFile");
444
445	ErrorStatus = XpmCreatePixmapFromBuffer(dpy, win, buffer,
446						&view.pixmap, &view.mask,
447						&view.attributes);
448	ErrorMessage(ErrorStatus, "CreatePixmapFromBuffer");
449	XpmFree(buffer);
450	ErrorStatus = XpmCreateBufferFromPixmap(dpy, &buffer,
451						view.pixmap, view.mask,
452						&view.attributes);
453	ErrorMessage(ErrorStatus, "CreateBufferFromPixmap");
454	ErrorStatus = XpmWriteFileFromBuffer("buffer_output", buffer);
455	ErrorMessage(ErrorStatus, "WriteFileFromBuffer");
456	XpmFree(buffer);
457	if (view.pixmap) {
458	    XFreePixmap(dpy, view.pixmap);
459	    if (view.mask)
460		XFreePixmap(dpy, view.mask);
461
462	    XFreeColors(dpy, colormap, view.attributes.alloc_pixels,
463			view.attributes.nalloc_pixels, 0);
464
465	    XpmFreeAttributes(&view.attributes);
466	}
467	ErrorStatus = XpmReadFileToData(input, &data);
468	ErrorMessage(ErrorStatus, "ReadFileToData");
469	ErrorStatus = XpmCreatePixmapFromData(dpy, win, data,
470					      &view.pixmap, &view.mask,
471					      &view.attributes);
472	ErrorMessage(ErrorStatus, "CreatePixmapFromData");
473	ErrorStatus = XpmWriteFileFromData("sxpmout.xpm", data);
474	ErrorMessage(ErrorStatus, "WriteFileFromData");
475	XpmFree(data);
476	XpmFreeAttributes(&view.attributes);
477#endif
478	ErrorStatus = XpmReadFileToPixmap(dpy, win, input,
479					  &view.pixmap, &view.mask,
480					  &view.attributes);
481	ErrorMessage(ErrorStatus, "Read");
482	if (verbose && view.attributes.nextensions) {
483	    unsigned int i, j;
484
485	    for (i = 0; i < view.attributes.nextensions; i++) {
486		/* L10N_Comments : Output when -v & file has extensions
487		   %s is replaced by extension name */
488		fprintf(stderr, gettext("Xpm extension : %s\n"),
489			view.attributes.extensions[i].name);
490		for (j = 0; j < view.attributes.extensions[i].nlines; j++)
491		    fprintf(stderr, "\t\t%s\n",
492			    view.attributes.extensions[i].lines[j]);
493	    }
494	}
495    } else {
496#ifdef Debug
497	ErrorStatus = XpmCreatePixmapFromData(dpy, win, data,
498					      &view.pixmap, &view.mask,
499					      &view.attributes);
500	XpmFree(data);
501#else
502	ErrorStatus = XpmCreatePixmapFromData(dpy, win, plaid,
503					      &view.pixmap, &view.mask,
504					      &view.attributes);
505#endif
506	ErrorMessage(ErrorStatus, "Plaid");
507    }
508    if (output || stdoutf) {
509	ErrorStatus = XpmWriteFileFromPixmap(dpy, output, view.pixmap,
510					     view.mask, &view.attributes);
511	ErrorMessage(ErrorStatus, "Write");
512    }
513    if (!nod) {
514
515	/*
516	 * manage display if requested
517	 */
518
519	XSizeHints size_hints;
520	char *xString = NULL;
521
522	if (w_rtn && h_rtn
523	    && ((w_rtn < view.attributes.width)
524		|| h_rtn < view.attributes.height)) {
525	    resize = 1;
526	}
527	if (resize) {
528	    XtResizeWidget(topw,
529			   view.attributes.width, view.attributes.height, 1);
530	}
531	if (incResize) {
532	    size_hints.flags = USSize | PMinSize | PResizeInc;
533	    size_hints.height = view.attributes.height;
534	    size_hints.width = view.attributes.width;
535	    size_hints.height_inc = view.attributes.height;
536	    size_hints.width_inc = view.attributes.width;
537	} else
538	    size_hints.flags = PMinSize;
539
540	size_hints.min_height = view.attributes.height;
541	size_hints.min_width = view.attributes.width;
542	XSetWMNormalHints(dpy, win, &size_hints);
543
544	if (input) {
545	    xString = (char *) XtMalloc((sizeof(char) * strlen(input)) + 20);
546	    sprintf(xString, "Sxpm: %s", input);
547	    XStoreName(dpy, win, xString);
548	    XSetIconName(dpy, win, xString);
549	} else if (stdinf) {
550	    XStoreName(dpy, win, "Sxpm: stdin");
551	    XSetIconName(dpy, win, "Sxpm: stdin");
552	} else {
553	    XStoreName(dpy, win, "Sxpm");
554	    XSetIconName(dpy, win, "Sxpm");
555	}
556
557	XtAddEventHandler(topw, KeyPressMask, False,
558			  (XtEventHandler) kinput, NULL);
559	XSetWindowBackgroundPixmap(dpy, win, view.pixmap);
560
561	if (view.mask && !nom)
562	    XShapeCombineMask(dpy, win, ShapeBounding, 0, 0,
563			      view.mask, ShapeSet);
564
565	XClearWindow(dpy, win);
566	XtMapWidget(topw);
567	if (xString)
568	    XtFree(xString);
569	XtMainLoop();
570    }
571    Punt(0);
572}
573
574void
575Usage(void)
576{
577    /* L10N_Comments : Usage message (sxpm -h) in two parts.
578       In the first part %s is replaced by the command name. */
579    fprintf(stderr, gettext("\nUsage:  %s [options...]\n"), command[0]);
580    fprintf(stderr, gettext("Where options are:\n\
581\n\
582[-d host:display]            Display to connect to.\n\
583[-g geom]                    Geometry of window.\n\
584[-hints]                     Set ResizeInc for window.\n\
585[-icon filename]             Set pixmap for iconWindow.\n\
586[-plaid]                     Read the included plaid pixmap.\n\
587[filename]                   Read from file 'filename', and from standard\n\
588                             input if 'filename' is '-'.\n\
589[-o filename]                Write to file 'filename', and to standard\n\
590                             output if 'filename' is '-'.\n\
591[-pcmap]                     Use a private colormap.\n\
592[-closecolors]               Try to use `close' colors.\n\
593[-nod]                       Don't display in window.\n\
594[-nom]                       Don't use clip mask if any.\n\
595[-mono]                      Use the colors specified for a monochrome visual.\n\
596[-grey4]                     Use the colors specified for a 4 greyscale visual.\n\
597[-grey]                      Use the colors specified for a greyscale visual.\n\
598[-color]                     Use the colors specified for a color visual.\n\
599[-sc symbol color]           Override color defaults.\n\
600[-sp symbol pixel]           Override color defaults.\n\
601[-cp color pixel]            Override color defaults.\n\
602[-rgb filename]              Search color names in the rgb text file 'filename'.\n\
603[-v]                         Verbose - print out extensions.\n\
604[-version]                   Print out program's version number\n\
605                             and library's version number if different.\n\
606if no input is specified sxpm reads from standard input.\n\
607\n"));
608    exit(0);
609}
610
611
612void
613ErrorMessage(
614    int		 ErrorStatus,
615    const char	*tag)
616{
617    char *error = NULL;
618    char *warning = NULL;
619
620    switch (ErrorStatus) {
621    case XpmSuccess:
622	return;
623    case XpmColorError:
624/* L10N_Comments : The following set of messages are classified as
625   either errors or warnings.  Based on the class of message, different
626   wrappers are selected at the end to state the message source & class.
627
628	   L10N_Comments : WARNING produced when filename can be read, but
629	   contains an invalid color specification (need to create test case)*/
630	warning = gettext("Could not parse or alloc requested color");
631	break;
632    case XpmOpenFailed:
633	/* L10N_Comments : ERROR produced when filename does not exist
634	   or insufficient permissions to open (i.e. sxpm /no/such/file ) */
635	error = gettext("Cannot open file");
636	break;
637    case XpmFileInvalid:
638	/* L10N_Comments : ERROR produced when filename can be read, but
639	   is not an XPM file (i.e. sxpm /dev/null ) */
640	error = gettext("Invalid XPM file");
641	break;
642    case XpmNoMemory:
643	/* L10N_Comments : ERROR produced when filename can be read, but
644	   is too big for memory
645	   (i.e. limit datasize 32 ; sxpm /usr/dt/backdrops/Crochet.pm ) */
646	error = gettext("Not enough memory");
647	break;
648    case XpmColorFailed:
649	/* L10N_Comments : ERROR produced when filename can be read, but
650	   contains an invalid color specification (need to create test case)*/
651	error = gettext("Failed to parse or alloc some color");
652	break;
653    }
654
655    if (warning)
656	/* L10N_Comments : Wrapper around above WARNING messages.
657	   First %s is the tag for the operation that produced the warning.
658	   Second %s is the message selected from the above set. */
659	fprintf(stderr, gettext("%s Xpm Warning: %s.\n"), tag, warning);
660
661    if (error) {
662	/* L10N_Comments : Wrapper around above ERROR messages.
663	   First %s is the tag for the operation that produced the error.
664	   Second %s is the message selected from the above set */
665	fprintf(stderr, gettext("%s Xpm Error: %s.\n"), tag, error);
666	Punt(1);
667    }
668}
669
670void
671Punt(int i)
672{
673    if (icon.pixmap) {
674	XFreePixmap(dpy, icon.pixmap);
675	if (icon.mask)
676	    XFreePixmap(dpy, icon.mask);
677
678	XFreeColors(dpy, colormap,
679		    icon.attributes.alloc_pixels,
680		    icon.attributes.nalloc_pixels, 0);
681
682	XpmFreeAttributes(&icon.attributes);
683    }
684    if (view.pixmap) {
685	XFreePixmap(dpy, view.pixmap);
686	if (view.mask)
687	    XFreePixmap(dpy, view.mask);
688
689	XFreeColors(dpy, colormap,
690		    view.attributes.alloc_pixels,
691		    view.attributes.nalloc_pixels, 0);
692
693	XpmFreeAttributes(&view.attributes);
694    }
695    exit(i);
696}
697
698void
699kinput(
700    Widget	 widget,
701    char	*tag,
702    XEvent	*xe,
703    Boolean	*b)
704{
705    char c = '\0';
706
707    XLookupString(&(xe->xkey), &c, 1, NULL, NULL);
708    if (c == 'q' || c == 'Q')
709	Punt(0);
710}
711
712/*
713 * small function to extract various version numbers from the given global
714 * number (following the rule described in xpm.h).
715 */
716void
717GetNumbers(
718    int		 num,
719    int		*format_return,
720    int		*libmajor_return,
721    char	*libminor_return)
722{
723    *format_return = num / 10000;
724    *libmajor_return = (num % 10000) / 100;
725    *libminor_return = 'a' + (num % 10000) % 100 - 1;
726}
727
728void
729VersionInfo(void)
730{
731    int format, libmajor;
732    char libminor;
733
734    GetNumbers(XpmIncludeVersion, &format, &libmajor, &libminor);
735    /* L10N_Comments : sxpm -version output */
736    fprintf(stderr, gettext("sxpm version: %d.%d%c\n"),
737	    format, libmajor, libminor);
738    /* L10N_Comments :
739     * if we are linked to an XPM library different from the one we've been
740     * compiled with, print its own number too when sxpm -version is called.
741     */
742    if (XpmIncludeVersion != XpmLibraryVersion()) {
743	GetNumbers(XpmLibraryVersion(), &format, &libmajor, &libminor);
744	fprintf(stderr, gettext("using the XPM library version: %d.%d%c\n"),
745		format, libmajor, libminor);
746    }
747}
748