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