#ifndef lint                                                                  
static  char    *sccsid = "@(#)xmgndisp.c   MgnAlt 1.13 (MIT/CSR) 5/13/93";   
#endif  lint                                                                  
                                                                              
/*                                                                            
        Function:       Display MIDR or GxDR image in X window                
        System:         Magellan Altimetry Data Reduction                     
        Phase:          UTIL                                                  
        Module:         xmgndisp.c                                            
        Revision:       1.13                                                  
        Date:           5/13/93                                               
        Author:         <pgf@space.mit.edu>                                   
        Created:        Mon Dec  9 11:44:07 EST 1991                          
        Control:        SCCS                                                  
*/                                                                            
                                                                              
#include <stdio.h>                                                            
#include <math.h>                                                             
#include <ctype.h>                                                            
#include <strings.h>                                                          
#include <X11/Xlib.h>                                                         
#include <X11/Xutil.h>                                                        
#include <X11/Xresource.h>                                                    
#include <X11/keysym.h>                                                       
                                                                              
#define APP_CLASS       "/usr/lib/X11/app-defaults/Xmgndisp"                  
#define UNINIT          (1.e20)                                               
#define OK(d)           ((d)<(UNINIT/2))                                      
#define MIN(x,y)        ((x)<(y)?(x):(y))                                     
#define MAX(x,y)        ((x)>(y)?(x):(y))                                     
#define VENUS_RADIUS    6051000                                               
                                                                              
        /*                                                                    
        **      Default resource values                                       
        */                                                                    
                                                                              
#define DFT_BORDER      2                                                     
#define DFT_CMAPDIR     "/usr/gips/lib/cmap"                                  
#define DFT_EXPAND      1                                                     
#define DFT_FONT        "fixed"                                               
#define DFT_INSERT      0                                                     
#define DFT_NZOOM       4                                                     
#define DFT_ZOOM        1                                                     
                                                                              
#define R_BOOL          0       /* boolean resource value */                  
#define R_INUM          1       /* int resource value */                      
#define R_DNUM          2       /* double resource value */                   
#define R_STR           3       /* string resource value */                   
                                                                              
        /*                                                                    
        **      XrmParseCommand stuff                                         
        */                                                                    
                                                                              
XrmOptionDescRec opTable[] = {                                                
        { "-Cmapdir",   "*colormapdir", XrmoptionSepArg, (caddr_t) NULL },    
        { "-borderwidth","*borderwidth",XrmoptionSepArg, (caddr_t) NULL },    
        { "-browse",    "*browse",      XrmoptionNoArg,  (caddr_t) "True" },  
        { "-colormap",  "*colormap",    XrmoptionSepArg, (caddr_t) NULL },    
        { "-display",   "*display",     XrmoptionSepArg, (caddr_t) NULL },    
        { "-expand",    "*expand",      XrmoptionSepArg, (caddr_t) NULL },    
        { "-fn",        "*font",        XrmoptionSepArg, (caddr_t) NULL },    
        { "-font",      "*font",        XrmoptionSepArg, (caddr_t) NULL },    
        { "-geometry",  "*geometry",    XrmoptionSepArg, (caddr_t) NULL },    
        { "-help",      "*help",        XrmoptionNoArg,  (caddr_t) "True" },  
        { "-highvalue", "*highvalue",   XrmoptionSepArg, (caddr_t) NULL },    
        { "-insertloc", "*insertloc",   XrmoptionSepArg, (caddr_t) NULL },    
        { "-lowvalue",  "*lowvalue",    XrmoptionSepArg, (caddr_t) NULL },    
        { "-match",     "*match",       XrmoptionNoArg,  (caddr_t) "True" },  
        { "-nzoom",     "*zoomfact",    XrmoptionResArg, (caddr_t) NULL },    
        { "-palette",   "*palette",     XrmoptionSepArg, (caddr_t) NULL },    
        { "-shift",     "*shift",       XrmoptionSepArg, (caddr_t) NULL },    
        { "-swap",      "*swap",        XrmoptionNoArg,  (caddr_t) "True" },  
        { "-verbose",   "*verbose",     XrmoptionNoArg,  (caddr_t) "True" },  
        { "-xrm",       NULL,           XrmoptionResArg, (caddr_t) NULL },    
        { "-zoomloc",   "*zoomloc",     XrmoptionResArg, (caddr_t) NULL },    
};                                                                            
                                                                              
        /*                                                                    
        **      Command-line parameters                                       
        */                                                                    
                                                                              
Usage(cmd)                                                                    
        char    *cmd;                                                         
{                                                                             
        printf("Usage:\t%s [-browse] [-match] [-verbose]\n", cmd);            
        printf("\t[-borderwidth <width>] [-colormap <colormap>]\n");          
        printf("\t[-Cmapdir <directory>] [-display <host:display>]\n");       
        printf("\t[-expand <factor>] [-fn <font>] [-font <font>]\n");         
        printf("\t[-geometry <WxH+X+Y>] [-help] [-highvalue <value>]\n");     
        printf("\t[-insertloc <location>] [-lowvalue <value>]\n");            
        printf("\t[-nzoom <zoomsize>] [-palette <file>] [-shift <bits>]\n");  
        printf("\t[-swap] [-xrm <resources>] [-zoomloc <location>]\n");       
        printf("\t[vicar-file]\n");                                           
        exit(0);                                                              
}                                                                             
                                                                              
        /*                                                                    
        **      Resource values                                               
        */                                                                    
                                                                              
char            *inFile;                /* name of input file */              
char            *inShortFile;           /* short input file name */           
char            *pCmdName;              /* argv[0] value */                   
int             bFlag;                  /* -browse: browse image */           
int             nBorder = DFT_BORDER;   /* -borderwidth: all borders */       
double          fExpand = DFT_EXPAND;   /* -expand: expansion factor */       
double          maxValue = UNINIT;      /* -highvalue: high DN value */       
double          minValue = UNINIT;      /* -lowvalue: low DN value */         
int             nFlag;                  /* -match: exact colors */            
int             nStrip;                 /* -shift: pixel shift factor */      
int             sFlag;                  /* -swap: swap pixel bytes */         
int             vFlag;                  /* -verbose: verbose mode */          
int             nZoom   = DFT_NZOOM;    /* zoom insert factor */              
int             butType = DFT_INSERT;   /* button insert location */          
int             zoomType = DFT_ZOOM;    /* zoom insert location */            
                                                                              
        /*                                                                    
        **      General X11 stuff                                             
        */                                                                    
                                                                              
Display         *theDisp;               /* display device */                  
int             theScreen;              /* display screen */                  
Visual          *theVisual;             /* display visual */                  
GC              theGC;                  /* graphic object */                  
Window          rootWin;                /* root window */                     
XFontStruct     *mfInfo;                /* text font */                       
XrmDatabase     resDB;                  /* merged resources */                
                                                                              
        /*                                                                    
        **      Main image window                                             
        */                                                                    
                                                                              
Window          imWin;                  /* xmgndisp image window */           
XImage          *retImage;              /* original image */                  
char            *pRetImage;             /* image pixels */                    
int             iWidth;                 /* retained image width */            
int             iHeight;                /* retained image height */           
int             inType;                 /* image type from VICAR */           
XImage          *expImage;              /* displayed image */                 
int             eWidth;                 /* displayed image width */           
int             eHeight;                /* displayed image height */          
int             noExpose;               /* don't expose after resize */       
                                                                              
        /*                                                                    
        **      Colormap                                                      
        */                                                                    
                                                                              
unsigned long   fColor;                 /* foreground color */                
unsigned long   bColor;                 /* background color */                
Colormap        theCmap;                /* display colormap */                
XColor          defColor[256];          /* Xcolor entries used */             
unsigned long   indxColor[256];         /* color lookup table */              
char            usedColor[256];         /* pixels used */                     
int             nColors;                /* displayed colors */                
int             nCells;                 /* number of color cells */           
unsigned int    rgbIndex[3][256];       /* colormap intensities */            
                                                                              
        /*                                                                    
        **      Sub-window parameters                                         
        */                                                                    
                                                                              
Window          butWin;                 /* button output window */            
int             bWidth;                 /* button text offsets */             
int             bHeight;                /* button text height */              
char            bText[3][80];           /* button text strings */             
int             curLoc[2];              /* cursor loc in retImage */          
Window          zoomWin;                /* zoom insert window */              
XImage          *zoomImage;             /* zoom insert image */               
                                                                              
char            cBuf[4096];             /* conversion buffer */               
extern  char    *getenv();              /* C library */                       
extern  char    *malloc();              /* C library */                       
                                                                              
        /*                                                                    
        **      Start here                                                    
        */                                                                    
                                                                              
main(argc, argv)                                                              
        char    *argv[];                                                      
{                                                                             
        XEvent  theEvent;                                                     
                                                                              
        parseArgs(argc, argv);                                                
        readColormap();                                                       
        openDisplay();                                                        
        loadVicarFile(&inType);                                               
        if (nFlag)                                                            
                setExactColors();                                             
        else                                                                  
                setShiftedColors();                                           
        setDisplay();                                                         
                                                                              
        while (1) {                                                           
                XNextEvent(theDisp, &theEvent);                               
                handleEvent(&theEvent);                                       
        }                                                                     
}                                                                             
                                                                              
        /*                                                                    
        **      parse command-line arguments                                  
        */                                                                    
                                                                              
parseArgs(argc, argv)                                                         
        int             argc;                                                 
        char            *argv[];                                              
{                                                                             
        char            *c;                                                   
        XrmDatabase     cmdDB;                                                
                                                                              
        /* parse command arguments */                                         
        XrmInitialize();                                                      
        XrmParseCommand(&resDB, opTable, sizeof(opTable)/sizeof(opTable[0]),  
                pCmdName = argv[0], &argc, argv);                             
                                                                              
        /* get input file pathname */                                         
        if (argc < 2)                                                         
                inFile = "'stdin'";                                           
        else if (argc == 2 && argv[1][0] != '-')                              
                inFile = argv[1];                                             
        else                                                                  
                Usage(pCmdName);                                              
                                                                              
        /* user asking for help? */                                           
        if (getRsrc(&argc, R_BOOL, "xmgndisp.help", "Xmgndisp.Help"))         
                Usage(pCmdName);                                              
                                                                              
        /* try to open the display */                                         
        if (!getRsrc(&c, R_STR, "xmgndisp.display", "Xmgndisp.Display"))      
                c = NULL;                                                     
        if (! (theDisp = XOpenDisplay(c)))                                    
                error("Can't open display: %s", XDisplayName(c));             
                                                                              
        /* merge other resources */                                           
        cmdDB = resDB;                                                        
        resDB = XrmGetFileDatabase(APP_CLASS);                                
        if (c = XResourceManagerString(theDisp))                              
                XrmMergeDatabases(XrmGetStringDatabase(c), &resDB);           
        else {                                                                
                sprintf(cBuf, "%s/%s", getenv("HOME"), "./Xdefaults");        
                XrmMergeDatabases(XrmGetFileDatabase(cBuf), &resDB);          
        }                                                                     
        c = getenv("XENVIRONMENT");                                           
        sprintf(cBuf, "%s/.Xdefaults-", c ? c : getenv("HOME"));              
        gethostname(cBuf+strlen(cBuf), sizeof(cBuf)-strlen(cBuf));            
        XrmMergeDatabases(XrmGetFileDatabase(cBuf), &resDB);                  
        XrmMergeDatabases(cmdDB, &resDB);                                     
                                                                              
        /* get numeric and flag resource values */                            
        (void)getRsrc(&bFlag, R_BOOL,                                         
                "xmgndisp.browse", "Xmgndisp.Browse");                        
        (void)getRsrc(&fExpand, R_DNUM,                                       
                "xmgndisp.expand", "Xmgndisp.Expand");                        
        (void)getRsrc(&maxValue, R_DNUM,                                      
                "xmgndisp.highvalue", "Xmgndisp.HighValue");                  
        (void)getRsrc(&minValue, R_DNUM,                                      
                "xmgndisp.lowvalue", "Xmgndisp.LowValue");                    
        (void)getRsrc(&nFlag,                                                 
                R_BOOL, "xmgndisp.match", "Xmgndisp.Match");                  
        (void)getRsrc(&nStrip,                                                
                R_INUM, "xmgndisp.shift", "Xmgndisp.Shift");                  
        (void)getRsrc(&sFlag,                                                 
                R_BOOL, "xmgndisp.swap", "Xmgndisp.Swap");                    
        (void)getRsrc(&vFlag,                                                 
                R_BOOL, "xmgndisp.verbose", "Xmgndisp.Verbose");              
        (void)getRsrc(&nZoom,                                                 
                R_INUM, "xmgndisp.zoomfact", "Xmgndisp.ZoomFact");            
        getInsertType(&butType,                                               
                "xmgndisp.insertloc", "Xmgndisp.Insertloc");                  
        getInsertType(&zoomType,                                              
                "xmgndisp.zoomloc", "Xmgndisp.Zoomloc");                      
                                                                              
        /* verify numerics */                                                 
        if (fExpand <= 0 || fExpand > 16)                                     
                error("bad -expand value", "");                               
        if (nStrip < 0 || nStrip > 7)                                         
                error("bad -strip value: %d", (char *)nStrip);                
                                                                              
        /* get name of input file */                                          
        inShortFile = (c = rindex(inFile, '/')) ? c+1 : inFile;               
}                                                                             
                                                                              
        /*                                                                    
        **      Copy colormap file entries to rgbIndex[][]                    
        */                                                                    
                                                                              
readColormap()                                                                
{                                                                             
        char    *cFile;                 /* colormap file */                   
        char    *cmapDir;               /* colormap directory */              
        char    aName[256];             /* colormap file name */              
        FILE    *pAfile;                /* colormap file stream */            
        int     nColor = 0;             /* color index */                     
        int     pFlag = 0;              /* =1 if palette format */            
        char    aFileBuf[256];          /* colormap line buffer */            
        char    *mapFmt = " %d %d %d";  /* file line format */                
        char    *pBuf;                  /* line buffer pointer */             
        int     i;                      /* scratch */                         
                                                                              
        /* initialize colors to grey */                                       
        for (i = 0; i < 256; i++)                                             
                rgbIndex[0][i] = rgbIndex[1][i] = rgbIndex[2][i] = i;         
                                                                              
        /* get palette or colormap file name and open it */                   
        if (getRsrc(&cFile, R_STR, "xmgndisp.palette", "Xmgndisp.Palette")    
                        && (pAfile = fopen(strcpy(aName, cFile), "r")))       
                pFlag++;                                                      
        else if (!getRsrc(&cFile, R_STR,                                      
                "xmgndisp.colormap", "Xmgndisp.Colormap"))                    
                return;                                                       
        else if ((pAfile = fopen(strcpy(aName, cFile), "r")) == NULL) {       
                if (!getRsrc(&cmapDir, R_STR, "xmgndisp.colormapdir",         
                        "Xmgndisp.Colormapdir"))                              
                        cmapDir = DFT_CMAPDIR;                                
                sprintf(aName, "%s/%s", cmapDir, cFile);                      
                pAfile = fopen(aName, "r");                                   
        }                                                                     
        if (!pAfile)                                                          
                perror(aName), exit(1);                                       
                                                                              
        /* read colormap file lines */                                        
        while (fgets(pBuf = aFileBuf, sizeof(aFileBuf)-1, pAfile)) {          
                while (isspace(*pBuf))                                        
                        pBuf++;                                               
                if (! pFlag) {                                                
                        /* ignore comments */                                 
                        if (! *pBuf || *pBuf == '#')                          
                                continue;                                     
                        mapFmt = " %d %d %d";                                 
                        i = nColor;                                           
                } else if (sscanf(pBuf, " %d", &i) != 1 || i < 0 || i > 255)  
                        error("bad palette index: %s", pBuf);                 
                else                                                          
                        mapFmt = " %*d %d %d %d";                             
                /* line should contail 0 <= red, green, blue <= 255 */        
                if (sscanf(pBuf, mapFmt, &rgbIndex[0][i],                     
                        &rgbIndex[1][i], &rgbIndex[2][i]) != 3)               
                        error("bad colormap entry: %s", pBuf);                
                nColor++;                                                     
        }                                                                     
        (void)fclose(pAfile);                                                 
        if (!pFlag && nColor < 256)                                           
                error("%s: insufficient colormap entries", aName);            
}                                                                             
                                                                              
        /*                                                                    
        **      Save generic display variables                                
        */                                                                    
                                                                              
openDisplay()                                                                 
{                                                                             
        theScreen = DefaultScreen(theDisp);                                   
        theCmap   = DefaultColormap(theDisp, theScreen);                      
        rootWin   = RootWindow(theDisp, theScreen);                           
        theGC     = DefaultGC(theDisp, theScreen);                            
        bColor    = WhitePixel(theDisp, theScreen);                           
        fColor    = BlackPixel(theDisp, theScreen);                           
        theVisual = DefaultVisual(theDisp, theScreen);                        
        nCells    = DisplayCells(theDisp, theScreen);                         
                                                                              
        if (nCells <= 2)                                                      
                error("program requires color display", "");                  
}                                                                             
                                                                              
        /*                                                                    
        **      Try to allocate all colors used by full-size image.           
        **      If any cannot be allocated, use nearest values.               
        */                                                                    
                                                                              
setExactColors()                                                              
{                                                                             
        XColor  cTable[256];            /* default color table */             
        int     nDefColors;             /* colors to find */                  
        int     nDist;                  /* color difference metric */         
        int     minDist;                /* minimum color difference */        
        int     minColor;               /* closest color index */             
        int     i, j;                   /* scratch */                         
                                                                              
        if (! (i = defineColors(0xff, 0)))                                    
                return;                                                       
                                                                              
        if (vFlag) /* failed to pull it off */                                
                fprintf(stderr, "can't allocate %d colors out of %d.\n",      
                        i, nColors);                                          
                                                                              
        nDefColors = MIN(nCells, 256);                                        
                                                                              
        /* read in the default color table */                                 
        for (i = 0; i < nDefColors; i++)                                      
                cTable[i].pixel = i;                                          
        XQueryColors(theDisp, theCmap, cTable, nDefColors);                   
                                                                              
        for (i = 0; i < 256; i++) {                                           
                if (! usedColor[i] || indxColor[i] != 0xffff)                 
                        continue;                                             
                minDist = 100000;                                             
                minColor = -1;                                                
                for (j = 0; j < nDefColors; j++) {                            
                        nDist = abs(rgbIndex[0][i]-(cTable[j].red >> 8)) +    
                                abs(rgbIndex[1][i]-(cTable[j].green >> 8)) +  
                                abs(rgbIndex[2][i]-(cTable[j].blue >> 8));    
                        if (nDist < minDist) /* locate nearest color */       
                                minDist = nDist, minColor = j;                
                }                                                             
                if (minColor < 0)                                             
                        error("cannot allocate colors", "");                  
                defColor[i] = defColor[minColor];                             
                indxColor[i] = cTable[minColor].pixel;                        
        }                                                                     
}                                                                             
                                                                              
        /*                                                                    
        **      Try to allocate all colors. If not successful,                
        **      mask least significant bit and try again.                     
        */                                                                    
                                                                              
setShiftedColors()                                                            
{                                                                             
        int     i;              /* scratch */                                 
        int     iStrip;         /* bit shift index */                         
                                                                              
        for (iStrip = nStrip; iStrip < 8; iStrip++) {                         
                /* try to allocate subset of all colors */                    
                if (! (i = defineColors((0xff << iStrip) & 0xff, 1)))         
                        break;                                                
                while (--i >= 0) /* free all colors allocated above */        
                        if (usedColor[i])                                     
                                XFreeColors(theDisp, theCmap,                 
                                        &indxColor[i], 1, 0L);                
        }                                                                     
        if (iStrip == 8) {                                                    
                if (vFlag) /* give up and use default color table */          
                        fprintf(stderr, "can't allocate desired colors.\n");  
                for (i = 0; i < 256; i++)                                     
                        indxColor[i] = i;                                     
        } else if (vFlag && iStrip != nStrip)                                 
                fprintf(stderr, "%s: stripped %d bits\n",                     
                        inShortFile,iStrip);                                  
}                                                                             
                                                                              
        /*                                                                    
        **      Initialize the main image window                              
        */                                                                    
                                                                              
setDisplay()                                                                  
{                                                                             
        XSetWindowAttributes    xSwa;           /* window attributes */       
        unsigned int            xSwaMask;       /* mask for xSwa */           
        XSizeHints              sHints;         /* window sizes */            
        char                    *geomStr;       /* geometry variable */       
        char                    *drawFont;      /* drawing font */            
        char                    iBuf[9];        /* icon title */              
        char                    *pChar;         /* text pointer */            
        int                     geomMask;       /* -geometry flags */         
        int                     xWin = 0;       /* -geometry field */         
        int                     yWin = 0;       /* -geometry field */         
        int                     wWin = 1;       /* -geometry field */         
        int                     hWin = 1;       /* -geometry field */         
        register char           *pPixel;        /* image pixel */             
        register int            i;              /* scratch */                 
                                                                              
        /* translate retained image pixels to allocated color values */       
        for (pPixel = pRetImage, i = iHeight * iWidth; --i >= 0; pPixel++)    
                *pPixel = indxColor[*pPixel & 0xff];                          
                                                                              
        /* load up the retained image */                                      
        retImage = XCreateImage(theDisp, theVisual, 8, ZPixmap, 0,            
                pRetImage, iWidth, iHeight, 8, iWidth);                       
        if (!retImage)                                                        
                error("unable to create XImage", "");                         
                                                                              
        /* determine dimension of retained and displayed images */            
        eWidth = iWidth * fExpand;                                            
        eHeight = iHeight * fExpand;                                          
        if (eWidth > DisplayWidth(theDisp, theScreen))                        
                eWidth = DisplayWidth(theDisp, theScreen);                    
        if (eHeight > DisplayHeight(theDisp, theScreen))                      
                eHeight = DisplayHeight(theDisp, theScreen);                  
                                                                              
        /* get a drawing font */                                              
        if (!getRsrc(&drawFont, R_STR, "xmgndisp.font", "Xmgndisp.Font"))     
                drawFont = DFT_FONT;                                          
        if (! (mfInfo = XLoadQueryFont(theDisp, drawFont)))                   
                error("couldn't open '%s' font", drawFont);                   
        XSetFont(theDisp, theGC, mfInfo->fid);                                
        XSetForeground(theDisp, theGC, fColor);                               
        XSetBackground(theDisp, theGC, bColor);                               
                                                                              
        /* parse the -geometry argument */                                    
        if (!getRsrc(&geomStr,R_STR,                                          
                "xmgndisp.geometry","Xmgndisp.Geometry"))                     
                geomMask = 0;                                                 
        else                                                                  
                geomMask = XParseGeometry(geomStr,                            
                        &xWin, &yWin, &wWin, &hWin);                          
        if (geomMask & WidthValue)                                            
                eWidth = wWin;                                                
        if (geomMask & HeightValue)                                           
                eHeight = hWin;                                               
                                                                              
        /* adjust to retain correct aspect ratio */                           
        if (eHeight * iWidth > eWidth * iHeight)                              
                eHeight = (eWidth * iHeight + iWidth/2) / iWidth;             
        else if (eHeight * iWidth < eWidth * iHeight)                         
                eWidth = (eHeight * iWidth + iHeight/2) / iHeight;            
                                                                              
        /* adjust window origin to keep it within screen area */              
        if ((geomMask & XValue) && (geomMask & XNegative))                    
                xWin = XDisplayWidth(theDisp, theScreen)                      
                        - eWidth - abs(xWin);                                 
        if ((geomMask & YValue) && (geomMask & YNegative))                    
                yWin = XDisplayHeight(theDisp,theScreen)                      
                        - eHeight - abs(yWin);                                
                                                                              
        /* create the image window */                                         
        xSwa.background_pixel = bColor;                                       
        xSwa.border_pixel     = fColor;                                       
        xSwa.bit_gravity      = ForgetGravity;                                
        xSwaMask = CWBackPixel | CWBorderPixel | CWBitGravity;                
        imWin = XCreateWindow(theDisp, rootWin, xWin, yWin, eWidth, eHeight,  
                2, 0, CopyFromParent, CopyFromParent, xSwaMask, &xSwa);       
        if (! imWin)                                                          
                error("Can't open main window", "");                          
                                                                              
        /* specify window size hints */                                       
        sHints.x = xWin;                                                      
        sHints.y = yWin;                                                      
        sHints.width = eWidth;                                                
        sHints.height = eHeight;                                              
        sHints.max_width = DisplayWidth(theDisp, theScreen);                  
        sHints.max_height = DisplayHeight(theDisp, theScreen);                
        if ((geomMask & XValue) || (geomMask & YValue))                       
                sHints.flags = USPosition | USSize | PMaxSize;                
        else                                                                  
                sHints.flags = PPosition | USSize | PMaxSize;                 
                                                                              
        /* construct window and icon titles */                                
        sprintf(cBuf, "File: %s; Type: %s", inFile, inType);                  
        strncpy(iBuf, inShortFile, 8);                                        
        iBuf[8] = 0;                                                          
        if (pChar = index(iBuf, '.'))                                         
                *pChar = 0;                                                   
                                                                              
        /* send hints to a window manager */                                  
#ifdef X11R3                                                                  
        XSetStandardProperties(theDisp, imWin, cBuf, iBuf, None,              
                &pCmdName, 1, &sHints);                                       
#else   /* R4 and later */                                                    
        {                                                                     
        XWMHints                wHints;         /* window manager mode */     
        XClassHint              cHints;         /* window class mode */       
        XTextProperty           winName;        /* name for window border */  
        XTextProperty           iconName;       /* name for window icon */    
                                                                              
        /* specify window-manager hints */                                    
        wHints.initial_state = NormalState;                                   
        wHints.input = True;                                                  
        wHints.flags = StateHint | InputHint;                                 
                                                                              
        /* specify window class hints */                                      
        cHints.res_name = "xdisp";                                            
        cHints.res_class = "Basicwin";                                        
                                                                              
        /* construct TextProperty structures for window & icon labels */      
        pChar = cBuf;                                                         
        XStringListToTextProperty(&pChar, 1, &winName);                       
        pChar = iBuf;                                                         
        XStringListToTextProperty(&pChar, 1, &iconName);                      
                                                                              
        /* tell the window manager about it */                                
        XSetWMProperties(theDisp, imWin, &winName, &iconName,                 
                &pCmdName, 1, &sHints, &wHints, &cHints);                     
        }                                                                     
#endif  X11R3                                                                 
                                                                              
        /* if necessary, zoom the display image */                            
        reSize(eWidth, eHeight);                                              
                                                                              
        /* specify which interrupts we want */                                
        XSelectInput(theDisp, imWin,                                          
                FocusChangeMask | EnterWindowMask | LeaveWindowMask |         
                ButtonPressMask | ButtonReleaseMask | Button1MotionMask |     
                ExposureMask | KeyPressMask | StructureNotifyMask);           
                                                                              
        /* display the image window */                                        
        XMapWindow(theDisp, imWin);                                           
}                                                                             
                                                                              
        /*                                                                    
        **      Write message to stderr, then quit                            
        */                                                                    
                                                                              
error(cMsg, cInsert)                                                          
        char    *cMsg, *cInsert;                                              
{                                                                             
        fprintf(stderr, "%s: ", pCmdName);                                    
        fprintf(stderr, cMsg, cInsert);                                       
        fprintf(stderr, "\n");                                                
        exit(-1);                                                             
}                                                                             
                                                                              
        /*                                                                    
        **      Retrieve a resource value from the database                   
        */                                                                    
                                                                              
getRsrc(var, vtype, arg1, arg2)                                               
        caddr_t         var;                                                  
        int             vtype;                                                
        char            *arg1, *arg2;                                         
{                                                                             
        XrmValue        val;                                                  
        char            *type[20], ch, *c;                                    
                                                                              
        if (XrmGetResource(resDB, arg1, arg2, type, &val) != True)            
                return 0;                                                     
        ch = *(c = val.addr+val.size);                                        
        *c = 0;                                                               
        switch(vtype) {                                                       
        case R_BOOL:                                                          
                *(int *)var = strcmp(val.addr, "False") ? 1 : 0;              
                break;                                                        
        case R_INUM:                                                          
                *(int *)var = atoi(val.addr);                                 
                break;                                                        
        case R_DNUM:                                                          
                *(double *)var = atof(val.addr);                              
                break;                                                        
        case R_STR:                                                           
                *(char **)var = strcpy(malloc(val.size+1), val.addr);         
                break;                                                        
        }                                                                     
        *c = ch;                                                              
        return 1;                                                             
}                                                                             
                                                                              
        /*                                                                    
        **      translate location to index                                   
        */                                                                    
                                                                              
getInsertType(val, arg1, arg2)                                                
        int     *val;                                                         
        char    *arg1, *arg2;                                                 
{                                                                             
        char    *c, *d;                                                       
                                                                              
        if (! getRsrc(&c, R_STR, arg1, arg2))                                 
                return;                                                       
        for (d = c; *d; d++)                                                  
                if (isupper(*d))                                              
                        *d = tolower(*d);                                     
        if (!strcmp(c, "topleft"))                                            
                *val = 0;                                                     
        else if (!strcmp(c, "topright"))                                      
                *val = 1;                                                     
        else if (!strcmp(c, "bottomright"))                                   
                *val = 2;                                                     
        else if (!strcmp(c, "bottomleft"))                                    
                *val = 3;                                                     
        else                                                                  
                error("bad location: %s", c);                                 
}                                                                             
                                                                              
        /*                                                                    
        **      Try to allocate nColors from rgbIndex[][].                    
        **      If sw==1, immediately XAllocColor fails return                
        **      (1 + the index of the failing rgbIndex[][i]);                 
        **      otherwise, keep going and return number allocated.            
        */                                                                    
                                                                              
defineColors(mask, sw)                                                        
{                                                                             
        int     nRetCode = 0;           /* return code */                     
        int     iColor;                 /* color index */                     
                                                                              
        for (iColor = 0; iColor < 256; iColor++) {                            
                if (! usedColor[iColor])                                      
                        continue;                                             
                defColor[iColor].red   = (rgbIndex[0][iColor] & mask) << 8;   
                defColor[iColor].green = (rgbIndex[1][iColor] & mask) << 8;   
                defColor[iColor].blue  = (rgbIndex[2][iColor] & mask) << 8;   
                defColor[iColor].flags = DoRed | DoGreen | DoBlue;            
                if (! XAllocColor(theDisp, theCmap, &defColor[iColor])) {     
                        defColor[iColor].pixel = 0xffff;                      
                        if (sw)                                               
                                return iColor+1;                              
                        else                                                  
                                nRetCode++;                                   
                }                                                             
                indxColor[iColor] = defColor[iColor].pixel;                   
        }                                                                     
        return nRetCode;                                                      
}                                                                             
                                                                              
        /*                                                                    
        **      If necessary, resize the image window                         
        */                                                                    
                                                                              
reSize(w, h)                                                                  
{                                                                             
        register char   *pInImage;      /* pointer to input XImage data */    
        register char   *pExpImage;     /* pointer to output XImage data */   
        register char   *pLine;         /* pointer to output raster */        
        register int    *pIndex, *pIn;  /* line expand lookup buffer */       
        register int    x, y;           /* scratch */                         
                                                                              
        /* if the size is same as retained image, use that */                 
        if (w == iWidth && h == iHeight) {                                    
                if (expImage != retImage) { /* remove previous image */       
                        if (expImage)                                         
                                XDestroyImage(expImage);                      
                        expImage = retImage;                                  
                        eWidth = iWidth;                                      
                        eHeight = iHeight;                                    
                }                                                             
                return;                                                       
        }                                                                     
                                                                              
        /* remove any insert windows (before possible XResizeWindow) */       
        XUnmapSubwindows(theDisp, imWin);                                     
                                                                              
        /* preserve aspect ratio */                                           
        if (noExpose = (w * iHeight != iWidth * h)) {                         
                if (w * iHeight > iWidth * h)                                 
                        w = (iWidth * h + w/2)/iHeight;                       
                else                                                          
                        h = (w * iHeight + h/2)/iWidth;                       
                if (expImage && w == eWidth && h == eHeight)                  
                        return;                                               
                XResizeWindow(theDisp, imWin, w, h);                          
        }                                                                     
                                                                              
        if (w * h > 500 * 500) { /* if large image, tell the user */          
                pLine = "Resizing Image.  Please wait...";                    
                XDrawImageString(theDisp, imWin, theGC,                       
                        (w - XTextWidth(mfInfo, pLine, strlen(pLine)))/2,     
                        (h + mfInfo->ascent - mfInfo->descent)/2,             
                        pLine, strlen(pLine));                                
                XFlush(theDisp);                                              
        }                                                                     
                                                                              
        /* kill any old expImage */                                           
        if (expImage && expImage != retImage) {                               
                free(expImage->data);                                         
                expImage->data = NULL;                                        
                XDestroyImage(expImage);                                      
        }                                                                     
                                                                              
        if (vFlag)                                                            
                fprintf(stderr, "resize to %dx%d\n", w, h);                   
                                                                              
        /* create new expImage and pixel array */                             
        expImage = XCreateImage(theDisp, theVisual, 8, ZPixmap, 0,            
                pExpImage = malloc(w * h), eWidth = w, eHeight = h, 8, w);    
        if (!expImage || !pExpImage)                                          
                error("can't create a %d byte image", eWidth * eHeight);      
                                                                              
        /* create index lookup table to speed line expansion */               
        pIn = pIndex = (int *)malloc(eWidth*sizeof(int));                     
        for (x = 0; x < eWidth; x++)                                          
                *pIn++ = (iWidth * x + eWidth/2) / eWidth;                    
                                                                              
        /* expand the retained image */                                       
        pInImage = (char *)retImage->data;                                    
        for (y = 0;  y < eHeight;  y++) {                                     
                pLine  = pInImage +                                           
                        iWidth * ((iHeight * y + eHeight/2) / eHeight);       
                for (pIn = pIndex, x = 0;  x < eWidth;  x++)                  
                        *pExpImage++ = *(pLine + *pIn++);                     
        }                                                                     
        free(pIndex);                                                         
}                                                                             
                                                                              
        /*                                                                    
        **      General event handler                                         
        */                                                                    
                                                                              
handleEvent(event)                                                            
        XEvent          *event;         /* generic event */                   
{                                                                             
        XComposeStatus  cStatus;        /* keyboard status */                 
        XButtonEvent    *bEvent;        /* button event */                    
        XExposeEvent    *eEvent;        /* exposure event */                  
        XKeyEvent       *kEvent;        /* keystroke event */                 
        XConfigureEvent *cEvent;        /* configuration event */             
        XPointerMovedEvent *pEvent;     /* pointer motion event */            
        char            kBuf[128];      /* cooked keyboard buffer */          
        KeySym          kSym;           /* raw keystroke code */              
        static  char    fActive;        /* =1 if window is active */          
        static  char    fFocus;         /* =1 if window has focus */          
        static  char    buttonFlag;     /* =1 if Button1 is down */           
        register int    x, y;           /* scratch */                         
                                                                              
        switch (event->type) {                                                
        case Expose:                                                          
                eEvent = (XExposeEvent *) event;                              
                if (eEvent->window == imWin)                                  
                        if (noExpose && (eEvent->width != eWidth ||           
                                        eEvent->height != eHeight))           
                                ;                                             
                        else XPutImage(theDisp, imWin, theGC, expImage,       
                                eEvent->x, eEvent->y, eEvent->x, eEvent->y,   
                                eEvent->width, eEvent->height);               
                else if (eEvent->window == butWin)                            
                        exposeButtonWindow();                                 
                else if (eEvent->window == zoomWin)                           
                        exposeZoomWindow();                                   
                noExpose = 0;                                                 
                break;                                                        
        case KeyPress:                                                        
                if (! fActive)                                                
                        break;                                                
                kEvent = (XKeyEvent *) event;                                 
                XLookupString(kEvent, kBuf, 128, &kSym, &cStatus);            
                switch (kSym) {                                               
                case 'q':       /* q/Q - quit xmgndisp */                     
                case 'Q':                                                     
                        XDestroyWindow(theDisp, imWin);                       
                        XUnloadFont(theDisp, mfInfo->fid);                    
                        XCloseDisplay(theDisp);                               
                        exit(0);                                              
                case '<':       /* < - reduce zoom factor */                  
                        if (nZoom <= 2) {                                     
                                XBell(theDisp, 100);                          
                                break;                                        
                        }                                                     
                        nZoom--;                                              
                        showZoomWindow();                                     
                        break;                                                
                case '>':       /* < - increase zoom factor */                
                        if (nZoom >= 16) {                                    
                                XBell(theDisp, 100);                          
                                break;                                        
                        }                                                     
                        nZoom++;                                              
                        showZoomWindow();                                     
                        break;                                                
                case 'v':                                                     
                case 'V':       /* v,V - cycle pointer value insert */        
                        butType = (butType + 1) % 4;                          
                        showButtonWindow();                                   
                        break;                                                
                case 'z':                                                     
                case 'Z':       /* z,Z - cycle zoom insert */                 
                        zoomType = (zoomType + 1) % 4;                        
                        showButtonWindow();                                   
                        break;                                                
                case XK_Return: /* ^M - remove insert windows */              
                        XUnmapSubwindows(theDisp, imWin);                     
                        break;                                                
                case XK_Left:   /* arrow-keys - move pointer */               
                case XK_Up:                                                   
                case XK_Right:                                                
                case XK_Down:                                                 
                case 'h':                                                     
                case 'j':                                                     
                case 'k':                                                     
                case 'l':                                                     
                        if (kEvent->window != imWin)                          
                                break;                                        
                        /* adjust index in retained image */                  
                        switch (kSym) {                                       
                        case XK_Left:                                         
                        case 'h':                                             
                                curLoc[0]--;                                  
                                break;                                        
                        case XK_Up:                                           
                        case 'k':                                             
                                curLoc[1]--;                                  
                                break;                                        
                        case XK_Right:                                        
                        case 'l':                                             
                                curLoc[0]++;                                  
                                break;                                        
                        case XK_Down:                                         
                        case 'j':                                             
                                curLoc[1]++;                                  
                                break;                                        
                        }                                                     
                        /* change the insert values */                        
                        showButtonWindow();                                   
                                                                              
                        /* translate to offsets in displayed image */         
                        x = (curLoc[0] * eWidth + iWidth/2) / iWidth;         
                        y = (curLoc[1] * eHeight + iHeight/2) / iHeight;      
                        if (x < 0 || x >= eWidth || y < 0 || y >= eHeight)    
                                break;                                        
                                                                              
                        /* if necessary, move the pointer */                  
                        if (kEvent->x != x || kEvent->y != y)                 
                                XWarpPointer(theDisp, None, imWin,            
                                        0, 0, 0, 0, x, y);                    
                        break;                                                
                }                                                             
                break;                                                        
        case ConfigureNotify: /* resize image window */                       
                cEvent = (XConfigureEvent *) event;                           
                if (cEvent->window != imWin)                                  
                        break;                                                
                noExpose = 0;                                                 
                if (cEvent->width != eWidth || cEvent->height != eHeight)     
                        reSize(cEvent->width, cEvent->height);                
                break;                                                        
        case EnterNotify: /* pointer entering image window */                 
                fActive = event->xcrossing.focus;                             
                break;                                                        
        case LeaveNotify: /* pointer leaving image window */                  
                fActive = fFocus;                                             
                break;                                                        
        case FocusIn: /* image window getting the keyboard focus */           
                fFocus = fActive = 1;                                         
                break;                                                        
        case FocusOut: /* image window losing the keyboard focus */           
                fFocus = fActive = 0;                                         
                break;                                                        
        case ButtonPress:                                                     
                bEvent = (XButtonEvent *) event;                              
                if (bEvent->window != imWin)                                  
                        break;                                                
                if (bEvent->button != Button1)                                
                        break;                                                
                /* convert location to retained image */                      
                curLoc[0] = (bEvent->x * iWidth + eWidth/2) / eWidth;         
                curLoc[1] = (bEvent->y * iHeight + eHeight/2) / eHeight;      
                showButtonWindow();                                           
                /* remember button pressed */                                 
                buttonFlag = 1;                                               
                break;                                                        
        case ButtonRelease:                                                   
                bEvent = (XButtonEvent *) event;                              
                if (bEvent->window != imWin)                                  
                        break;                                                
                if (bEvent->button != Button1)                                
                        break;                                                
                /* remember button released */                                
                buttonFlag = 0;                                               
                break;                                                        
        case MotionNotify:                                                    
                if (! buttonFlag || !fActive)                                 
                        break;                                                
                pEvent = (XPointerMovedEvent *) event;                        
                if (pEvent->window != imWin)                                  
                        break;                                                
                /* pointer dragged -- update inserts */                       
                curLoc[0] = (pEvent->x * iWidth + eWidth/2) / eWidth;         
                curLoc[1] = (pEvent->y * iHeight + eHeight/2) / eHeight;      
                showButtonWindow();                                           
                break;                                                        
        default:                                                              
                break;                                                        
        }                                                                     
}                                                                             
                                                                              
        /*                                                                    
        **      Left button draws pixel coordinates and value                 
        */                                                                    
                                                                              
showButtonWindow()                                                            
{                                                                             
        static  int     wSave, hSave;   /* saved subwindow size */            
        static  int     xSave, ySave;   /* saved subwindow origin */          
        float           lon, lat;       /* pointer location */                
        float           fVal;           /* pointer data value */              
        int             dn;             /* pointer pixel */                   
        int             xOrg, yOrg;     /* new subwindow origin */            
        int             i, x, y;        /* scratch */                         
        char            cDelim;         /* data value delimiter */            
        char            *fUnits;        /* data unit type */                  
                                                                              
        /* clip pointer to retained image */                                  
        x = curLoc[0] = MIN(MAX(curLoc[0], 0), iWidth-1);                     
        y = curLoc[1] = MIN(MAX(curLoc[1], 0), iHeight-1);                    
                                                                              
        /* display the zoomed insert */                                       
        showZoomWindow();                                                     
                                                                              
        /* get map coordinates */                                             
        cDelim = getVicarValue(x, y, &i, &lon, &lat, &fVal, &fUnits);         
                                                                              
        /* construct text strings */                                          
        sprintf(bText[0], OK(lon) ?                                           
                "x=%04d  PIXEL LONGITUDE = %.3f" : "x=%04d", x, lon);         
        sprintf(bText[1], OK(lat) ?                                           
                "y=%04d   PIXEL LATITUDE = %.3f" : "y=%04d", y, lat);         
        sprintf(bText[2], OK(fVal) ?                                          
                "d=%04d      PIXEL VALUE %c %.7g" : "d=%04d", i,              
                cDelim, fVal);                                                
        if (fUnits && OK(fVal))                                               
                sprintf(bText[2]+strlen(bText[2]), " <%s>", fUnits);          
                                                                              
        /* determine maximum width of strings */                              
        for (bWidth = i = 0; i < 3; i++)                                      
                bWidth = MAX(bWidth, XTextWidth(mfInfo,                       
                                bText[i], strlen(bText[i])));                 
        bHeight = mfInfo->ascent + mfInfo->descent;                           
        x = bWidth += 2*nBorder;                                              
        y = 4*nBorder+3*bHeight;                                              
                                                                              
        /* determine subwindow origin */                                      
        switch (butType) {                                                    
        case 0:                                                               
                xOrg = yOrg = 0;                                              
                break;                                                        
        case 1:                                                               
                xOrg = eWidth - x - 2*nBorder;                                
                yOrg = 0;                                                     
                break;                                                        
        case 2:                                                               
                xOrg = eWidth - x - 2*nBorder;                                
                yOrg = eHeight - y - 2*nBorder;                               
                break;                                                        
        case 3:                                                               
                xOrg = 0;                                                     
                yOrg = eHeight - y - 2*nBorder;                               
                break;                                                        
        }                                                                     
                                                                              
        if (butWin && (x != wSave || y != hSave ||                            
                        xOrg != xSave || yOrg != ySave)) {                    
                /* subwindow size or origin change */                         
                XDestroyWindow(theDisp, butWin);                              
                butWin = 0;                                                   
        }                                                                     
        if (butWin) {                                                         
                /* same subwindow size and origin */                          
                XClearWindow(theDisp, butWin);                                
                exposeButtonWindow();                                         
        } else {                                                              
                /* create or recreate the subwindow */                        
                butWin = XCreateSimpleWindow(theDisp, imWin,                  
                        xSave = xOrg, ySave = yOrg,                           
                        wSave = x, hSave = y,                                 
                        nBorder, fColor, bColor);                             
                XSelectInput(theDisp, butWin, ExposureMask);                  
        }                                                                     
        XMapWindow(theDisp, butWin);                                          
}                                                                             
                                                                              
        /*                                                                    
        **      redraw the insert subwindow                                   
        */                                                                    
                                                                              
exposeButtonWindow()                                                          
{                                                                             
        int     i;                                                            
                                                                              
        for (i = 0; i < 3; i++)                                               
                XDrawImageString(theDisp, butWin, theGC, nBorder,             
                        nBorder+bHeight*(i+1), bText[i], strlen(bText[i]));   
}                                                                             
                                                                              
        /*                                                                    
        **      Create zoom insert subwindow and zoomed image                 
        */                                                                    
                                                                              
showZoomWindow()                                                              
{                                                                             
        static  int     xSave, ySave;   /* saved subwindow origin */          
        static  int     lenSave;        /* saved subwindow width/height */    
        int             xOrg, yOrg;     /* new subwindow origin */            
        register char   *pIn;           /* retained image array */            
        register char   *pOut;          /* zoomed image array */              
        register int    lenIn;          /* number of pixels to zoom */        
        register int    lenOut;         /* new zoomed window width */         
        register int    w, x, y, z;     /* scratch */                         
        register int    dx, dy;         /* scratch */                         
                                                                              
        /* compute unzoomed and zoomed line lengths */                        
        lenIn = MIN(eHeight, eWidth)/(8*nZoom);                               
        if (lenIn <= 1)                                                       
                lenIn = 1;                                                    
        lenOut = (2 * lenIn + 1) * nZoom;                                     
                                                                              
        /* determine subwindow origin */                                      
        switch (zoomType) {                                                   
        case 0:                                                               
                xOrg = yOrg = 0;                                              
                break;                                                        
        case 1:                                                               
                xOrg = eWidth - lenOut - 2*nBorder;                           
                yOrg = 0;                                                     
                break;                                                        
        case 2:                                                               
                xOrg = eWidth - lenOut - 2*nBorder;                           
                yOrg = eHeight - lenOut - 2*nBorder;                          
                break;                                                        
        case 3:                                                               
                xOrg = 0;                                                     
                yOrg = eHeight - lenOut - 2*nBorder;                          
                break;                                                        
        }                                                                     
                                                                              
        if (zoomWin && (lenSave != lenOut ||                                  
                        xOrg != xSave || yOrg != ySave)) {                    
                /* remove subwindow on size or origin change */               
                free(zoomImage->data);                                        
                XDestroyImage(zoomImage);                                     
                XDestroyWindow(theDisp, zoomWin);                             
                zoomWin = 0;                                                  
        }                                                                     
                                                                              
        if (! zoomWin) {                                                      
                /* create or recreate subwindow and zoomed image */           
                zoomWin = XCreateSimpleWindow(theDisp, imWin, xOrg, yOrg,     
                        lenOut, lenOut, nBorder, fColor, bColor);             
                zoomImage = XCreateImage(theDisp, theVisual, 8, ZPixmap, 0,   
                        malloc(lenOut * lenOut), lenOut, lenOut, 8, lenOut);  
                XSelectInput(theDisp, zoomWin, ExposureMask);                 
        }                                                                     
                                                                              
        pIn = (char *)retImage->data;                                         
        pOut = (char *)zoomImage->data;                                       
                                                                              
        /* zoom about curLoc in retained image */                             
        for (y = -lenIn; y <= lenIn; y++) {                                   
                dy = ((dy = curLoc[1]+y) >= iHeight) ? -1 : dy*iWidth;        
                for (x = -lenIn; x <= lenIn; x++) {                           
                        w = (dy < 0 || (dx = curLoc[0]+x) < 0 ||              
                                        dx >= iWidth)                         
                                ? 0 : *(pIn + dy + dx);                       
                        for (z = nZoom; --z >= 0; *pOut++ = w)                
                                ;                                             
                }                                                             
                /* after zooming a line, replicate it nZoom-1 times */        
                for (z = nZoom; --z > 0; pOut += lenOut)                      
                        bcopy(pOut-lenOut, pOut, lenOut);                     
        }                                                                     
                                                                              
        /* if subwindow size/origin unchanged, it must be exposed */          
        if (lenSave == lenOut && xOrg == xSave && yOrg == ySave)              
                exposeZoomWindow();                                           
                                                                              
        /* save sub-window size and origin */                                 
        lenSave = lenOut;                                                     
        xSave = xOrg;                                                         
        ySave = yOrg;                                                         
        XMapWindow(theDisp, zoomWin);                                         
}                                                                             
                                                                              
        /*                                                                    
        **      repaint the zoomed subwindow                                  
        */                                                                    
                                                                              
exposeZoomWindow()                                                            
{                                                                             
        register int    i;              /* scratch */                         
                                                                              
        /* paint the zoomed image */                                          
        XPutImage(theDisp, zoomWin, theGC, zoomImage,                         
                0, 0, 0, 0, zoomImage->width, zoomImage->height);             
                                                                              
        /* insert zoom size */                                                
        sprintf(cBuf, "x%d", nZoom);                                          
        XDrawImageString(theDisp, zoomWin, theGC,                             
                (zoomImage->width-XTextWidth(mfInfo, cBuf, strlen(cBuf)))/2,  
                nBorder+mfInfo->ascent+mfInfo->descent, cBuf, strlen(cBuf));  
                                                                              
        /* draw cross-hairs to indicate central pixel */                      
        i = (zoomImage->width - nZoom)/2;                                     
        XDrawLine(theDisp, zoomWin, theGC, i, i, i-nZoom, i-nZoom);           
        XDrawLine(theDisp, zoomWin, theGC, i+nZoom, i, i+2*nZoom, i-nZoom);   
        i += nZoom;                                                           
        XDrawLine(theDisp, zoomWin, theGC, i, i, i+nZoom, i+nZoom);           
        XDrawLine(theDisp, zoomWin, theGC, i-nZoom, i, i-2*nZoom, i+nZoom);   
}                                                                             
                                                                              
        /*                                                                    
        **      Applicable VICAR keywords                                     
        */                                                                    
                                                                              
int     DIM;                    /* image dimension */                         
int     EOL;                    /* end-of-file label flag */                  
int     LBLSIZE;                /* label length in bytes */                   
int     NB;                     /* number of image bands */                   
int     NBB;                    /* line prefix bytes */                       
int     NL;                     /* number of lines */                         
int     NLB;                    /* number of prefix lines */                  
int     NS;                     /* number of samples per line */              
char    *DN_UNITS;              /* data units */                              
char    *FORMAT;                /* pixel format */                            
char    *IMAGE = "unknown";     /* image description */                       
char    *INTFMT;                /* integer pixel format */                    
char    *MAP_PROJ;              /* map projection type */                     
char    *ORG;                   /* image structure type */                    
char    *REALFMT;               /* float pixel format */                      
double  HI_DN   = UNINIT;       /* largest assigned pixel value */            
double  HI_REP  = UNINIT;       /* real value of HI_DN */                     
double  LAT_LC  = UNINIT;       /* latitude of lower center */                
double  LAT_LL  = UNINIT;       /* latitude of lower left */                  
double  LAT_LR  = UNINIT;       /* latitude of lower right */                 
double  LAT_UC  = UNINIT;       /* latitude of upper center */                
double  LAT_UL  = UNINIT;       /* latitude of upper left */                  
double  LAT_UR  = UNINIT;       /* latitude of upper right */                 
double  LON_CL  = UNINIT;       /* longitude of center left */                
double  LON_CR  = UNINIT;       /* longitude of center right */               
double  LON_LL  = UNINIT;       /* longitude of lower left */                 
double  LON_LR  = UNINIT;       /* longitude of lower right */                
double  LON_UL  = UNINIT;       /* longitude of upper left */                 
double  LON_UR  = UNINIT;       /* longitude of upper right */                
double  LOW_DN  = UNINIT;       /* smallest assigned pixel value */           
double  LOW_REP = UNINIT;       /* real value of LOW_DN */                    
double  PIXSIZ  = UNINIT;       /* pixel size in DN_UNITS units */            
double  PROJSAMP = UNINIT;      /* sample index of PROJ_LON */                
double  PROJ_LON = UNINIT;      /* standard projection longitude */           
double  SPECLINE = UNINIT;      /* line index of PROJ_LON */                  
double  SPECSAMP = UNINIT;      /* sample index of prime meridian */          
                                                                              
#define K_NORTH         01      /* latitude is northern */                    
#define K_SOUTH         02      /* latitude is southern */                    
                                                                              
int     nsFlag;                 /* =1,2 if all LATs northern,southern */      
                                                                              
        /*                                                                    
        **      Values of k_flg, below                                        
        */                                                                    
                                                                              
#define K_REQD          01      /* keyword must be present */                 
#define K_FOUND         02      /* keyword is present */                      
#define K_CHAR          04      /* keyword value is character string */       
#define K_INT           010     /* keyword value is integer */                
#define K_DOUBLE        020     /* keyword value is integer or double */      
#define K_LAT           040     /* keyword value is a latitude */             
                                                                              
        /*                                                                    
        **      Table of VICAR keyword names and attributes                   
        **      NOTE: LBLSIZE must be first.                                  
        */                                                                    
                                                                              
struct  keyTab  {                                                             
        char    *k_name;        /* header keyword */                          
        char    *k_ptr;         /* where to copy the value */                 
        int     k_flg;          /* flag fields */                             
} KeyTable[] = {                                                              
        "LBLSIZE",      (char *) &LBLSIZE,      K_INT | K_REQD,               
        "DIM",          (char *) &DIM,          K_INT,                        
        "DN_UNITS",     (char *) &DN_UNITS,     K_CHAR,                       
        "EOL",          (char *) &EOL,          K_INT,                        
        "FORMAT",       (char *) &FORMAT,       K_CHAR | K_REQD,              
        "HI_DN",        (char *) &HI_DN,        K_DOUBLE,                     
        "HI_REP",       (char *) &HI_REP,       K_DOUBLE,                     
        "IMAGE",        (char *) &IMAGE,        K_CHAR,                       
        "INTFMT",       (char *) &INTFMT,       K_CHAR,                       
        "LAT_LC",       (char *) &LAT_LC,       K_DOUBLE | K_LAT,             
        "LAT_LL",       (char *) &LAT_LL,       K_DOUBLE | K_LAT,             
        "LAT_LR",       (char *) &LAT_LR,       K_DOUBLE | K_LAT,             
        "LAT_UC",       (char *) &LAT_UC,       K_DOUBLE | K_LAT,             
        "LAT_UL",       (char *) &LAT_UL,       K_DOUBLE | K_LAT,             
        "LAT_UR",       (char *) &LAT_UR,       K_DOUBLE | K_LAT,             
        "LON_CL",       (char *) &LON_CL,       K_DOUBLE,                     
        "LON_CR",       (char *) &LON_CR,       K_DOUBLE,                     
        "LON_LL",       (char *) &LON_LL,       K_DOUBLE,                     
        "LON_LR",       (char *) &LON_LR,       K_DOUBLE,                     
        "LON_UL",       (char *) &LON_UL,       K_DOUBLE,                     
        "LON_UR",       (char *) &LON_UR,       K_DOUBLE,                     
        "LOW_DN",       (char *) &LOW_DN,       K_DOUBLE,                     
        "LOW_REP",      (char *) &LOW_REP,      K_DOUBLE,                     
        "MAP_PROJ",     (char *) &MAP_PROJ,     K_CHAR,                       
        "NB",           (char *) &NB,           K_INT,                        
        "NBB",          (char *) &NBB,          K_INT,                        
        "NL",           (char *) &NL,           K_INT | K_REQD,               
        "NLB",          (char *) &NLB,          K_INT,                        
        "NS",           (char *) &NS,           K_INT | K_REQD,               
        "ORG",          (char *) &ORG,          K_CHAR,                       
        "PIXSIZ",       (char *) &PIXSIZ,       K_DOUBLE,                     
        "PROJSAMP",     (char *) &PROJSAMP,     K_DOUBLE,                     
        "PROJ_LON",     (char *) &PROJ_LON,     K_DOUBLE,                     
        "REALFMT",      (char *) &REALFMT,      K_CHAR,                       
        "SPECLINE",     (char *) &SPECLINE,     K_DOUBLE,                     
        "SPECSAMP",     (char *) &SPECSAMP,     K_DOUBLE,                     
        NULL                                                                  
};                                                                            
                                                                              
        /*                                                                    
        **      Read the input VICAR file into an XImage                      
        */                                                                    
                                                                              
loadVicarFile(ppType)                                                         
        char            **ppType;       /* returned image type */             
{                                                                             
        float           fVal;           /* scratch */                         
        double          fFact;          /* convert from DN to real */         
        double          dFact;          /* convert from real to image */      
        register FILE   *pFile;         /* input stream pointer */            
        register char   *pPix;          /* pointer to pRetImage */            
        register char   dType;          /* input byte type */                 
        register char   *pixTable;      /* input translation table */         
        register int    tabSize;        /* size of pixTable */                
        register int    inPix;          /* input pixel value */               
        register int    x, y;           /* scratch */                         
        register char   *c;             /* scratch */                         
                                                                              
        /* open the VICAR file */                                             
        if (inFile == NULL)                                                   
                inFile = "'stdin'";                                           
        if (strcmp(inFile, "'stdin'") == 0)                                   
                pFile = stdin;                                                
        else if ((pFile = fopen(inFile, "r")) == NULL)                        
                perror(inFile), exit(1);                                      
                                                                              
        /* scan the header */                                                 
        readVicarHeader(pFile);                                               
                                                                              
        /* verify image structure keywords */                                 
        if (ORG && strcmp(ORG, "BSQ"))                                        
                error("unsupported ORG value: %s", ORG);                      
        if (DIM && (DIM < 2 || DIM > 3))                                      
                error("unsupported DIM value: %d", (char *)DIM);              
        if (!DN_UNITS || ! strcmp(DN_UNITS, "NONE") ||                        
                        ! strcmp(DN_UNITS, "N/A"))                            
                DN_UNITS = 0;                                                 
        if (EOL)                                                              
                (void)fprintf(stderr, "%s: EOF labels ignored\n", inFile);    
                                                                              
        /* construct fancy IMAGE string */                                    
        for (c = *ppType = IMAGE; *c; c++)                                    
                if (islower(*c) && (c == IMAGE || c[-1] == ' '))              
                        *c = toupper(*c);                                     
                else if (isupper(*c) && c != IMAGE && c[-1] != ' ')           
                        *c = tolower(*c);                                     
                                                                              
        /* fix-up bugs in Magellan browse image headers */                    
        if (!strcmp(inShortFile, "browse.img") ||                             
                        !strcmp(inShortFile, "BROWSE.IMG"))                   
                bFlag = 1;                                                    
        if (bFlag && OK(PIXSIZ+SPECLINE+PROJSAMP)) {                          
                if ((x = PIXSIZ / 75) == 1 || x == 3 || x == 9 || x == 27) {  
                        PIXSIZ *= 8;                                          
                        SPECLINE /= 8;                                        
                        PROJSAMP /= 8;                                        
                }                                                             
                if (vFlag)                                                    
                        fprintf(stderr, "%s: %s -> %g,%g,%g\n",               
                                inShortFile, "PIXSIZ,SPECLINE,PROJSAMP",      
                                PIXSIZ, SPECLINE, PROJSAMP);                  
        }                                                                     
                                                                              
        /* determine pixel format type */                                     
        if (!strcmp(FORMAT, "BYTE")) {                                        
                dType = 'b';                                                  
                tabSize = 256;                                                
        } else if (!strcmp(FORMAT, "HALF")) {                                 
                dType = ((INTFMT && strcmp(INTFMT, "LOW")) ^ sFlag) ?         
                        'h' : 's';                                            
                tabSize = 65536;                                              
        } else if (!strcmp(FORMAT, "REAL")) {                                 
                dType = ((REALFMT && strcmp(REALFMT, "VAX")) ^ sFlag) ?       
                        'v' : 'f';                                            
                /* float pixels require user-supplied display range */        
                if (! OK(minValue) || ! OK(maxValue) ||                       
                                minValue >= maxValue)                         
                        error("%s: missing -lowvalue or -highvalue value",    
                                inFile);                                      
                dFact = 255.0/(maxValue - minValue);                          
                tabSize = 0;                                                  
        } else                                                                
                error("unsupported FORMAT value: %s", FORMAT);                
                                                                              
        if (tabSize) {                                                        
                /* for BYTE or HALF pixels, determine image stretch */        
                if (! OK(LOW_DN))                                             
                        LOW_DN = 0;                                           
                if (! OK(LOW_REP))                                            
                        LOW_REP = LOW_DN;                                     
                if (! OK(minValue))                                           
                        minValue = LOW_REP;                                   
                if (! OK(HI_DN))                                              
                        HI_DN = tabSize - 1;                                  
                if (! OK(HI_REP))                                             
                        HI_REP = HI_DN;                                       
                if (! OK(maxValue))                                           
                        maxValue = HI_REP;                                    
                if (LOW_DN >= HI_DN)                                          
                        error("%s: inconsistent LOW_DN, HI_DN values",        
                                inFile);                                      
                if (minValue >= maxValue)                                     
                        error(                                                
                        "%s: inconsistent -highvalue, -lowvalue values",      
                                inFile);                                      
                fFact = (HI_REP - LOW_REP) / (HI_DN - LOW_DN);                
                dFact = 255.0/(maxValue - minValue);                          
                                                                              
                /* construct a lookup table */                                
                pixTable = malloc(tabSize);                                   
                for (x = 0; x < tabSize; x++) {                               
                        fVal = LOW_REP + (x - LOW_DN) * fFact;                
                        inPix = LOW_DN + (fVal - minValue) * dFact;           
                        if (inPix < 0)                                        
                                inPix = 0;                                    
                        else if (inPix > 255)                                 
                                inPix = 255;                                  
                        pixTable[x] = inPix;                                  
                }                                                             
        }                                                                     
                                                                              
        /* allocate the retained image array */                               
        iWidth = NS;                                                          
        iHeight = NL;                                                         
        if ((pRetImage = pPix = malloc(NL * NS)) == NULL)                     
                error("%s: insufficient memory", inShortFile);                
                                                                              
        for (y = 0; y < NL+NLB; y++) {                                        
                for (x = 0; x < NS+NBB; x++) {                                
                        inPix = getc(pFile) & 0xff;                           
                        if (x < NBB) /* ignore line-prefix bytes */           
                                continue;                                     
                        /*                                                    
                         * NOTE: pixels are loaded one-byte-at-a-time         
                         * into inPix so whether the CPU is LSB-first         
                         * or MSB-first is unimportant.                       
                         */                                                   
                        switch (dType) {                                      
                        case 'b': /* byte */                                  
                                break;                                        
                        case 'h': /* short - HSB first */                     
                                inPix = (inPix << 8) | (getc(pFile) & 0xff);  
                                break;                                        
                        case 's': /* short - LSB first */                     
                                inPix |= (getc(pFile) & 0xff) << 8;           
                                break;                                        
                        /*                                                    
                         * Conversion into local float format is              
                         * CPU-dependent, but note that Sun and               
                         * DecStation (mips) obey same rules.                 
                         */                                                   
#ifdef vax                                                                    
                        case 'f': /* IEEE float -> VAX */                     
                                if (inPix && inPix != 0xff)                   
                                        inPix++;                              
                                inPix = (inPix << 8) | (getc(pFile) & 0xff);  
                                inPix |= (getc(pFile) & 0xff) << 24;          
                                inPix |= (getc(pFile) & 0xff) << 16;          
                                break;                                        
                        case 'v': /* VAX float -> VAX */                      
                                inPix |= (getc(pFile) & 0xff) << 8;           
                                inPix |= (getc(pFile) & 0xff) << 16;          
                                inPix |= (getc(pFile) & 0xff) << 24;          
                                break;                                        
#else                                                                         
                        case 'f': /* IEEE float -> IEEE CPU */                
                                inPix = (inPix << 8) | (getc(pFile) & 0xff);  
                                inPix = (inPix << 8) | (getc(pFile) & 0xff);  
                                inPix = (inPix << 8) | (getc(pFile) & 0xff);  
                                break;                                        
                        case 'v': /* VAX float -> IEEE CPU */                 
                                inPix |= (getc(pFile) & 0xff) << 8;           
                                if (inPix & 0xff00)                           
                                        inPix -= 0x100;                       
                                inPix = (inPix << 16) | getc(pFile) & 0xff;   
                                inPix |= (getc(pFile) & 0xff) << 8;           
                                break;                                        
#endif vax                                                                    
                        }                                                     
                        if (y < NLB) /* ignore image prefix lines */          
                                continue;                                     
                        if (tabSize)                                          
                                /* translate via lookup table */              
                                inPix = *(pixTable + inPix) & 0xff;           
                        else {                                                
                                /* cast long int to float */                  
                                *((int *)&fVal) = inPix;                      
                                /* load as float and normalize */             
                                inPix = (fVal - minValue) * dFact;            
                                /* clip */                                    
                                if (inPix < 0)                                
                                        inPix = 0;                            
                                else if (inPix > 255)                         
                                        inPix = 255;                          
                        }                                                     
                        /* store retained pixel value */                      
                        *pPix++ = inPix;                                      
                        /* count number of discrete pixel values */           
                        if (! usedColor[inPix])                               
                                usedColor[inPix] = 1, nColors++;              
                }                                                             
        }                                                                     
        (void)fclose(pFile);                                                  
        if (vFlag)                                                            
                fprintf(stderr, "%s: %d colors in %dx%d image\n",             
                        inShortFile, nColors, iWidth, iHeight);               
}                                                                             
                                                                              
        /*                                                                    
        **      VICAR header state table                                      
        */                                                                    
                                                                              
int     stateTable[][4] = {                                                   
        /*      blank   equals  quote   other           state */              
        {        0,     -1,     -1,      1      }, /* 0 blank */              
        {       -1,      2,     -1,      1      }, /* 1 keyword */            
        {        7,     -1,      3,      6      }, /* 2 assignment */         
        {        4,      4,      5,      4      }, /* 3 starting quote */     
        {        4,      4,      5,      4      }, /* 4 string value */       
        {        0,     -1,     -1,     -1      }, /* 5 ending quote */       
        {        7,     -1,     -1,      6      }, /* 6 numeric value */      
        {        0,     -1,     -1,      1      }  /* 7 end numeric */        
};                                                                            
                                                                              
        /*                                                                    
        **      Read the VICAR header, fill "KeyTable" structure              
        */                                                                    
                                                                              
readVicarHeader(pFile)                                                        
        FILE    *pFile;                 /* input file stream */               
{                                                                             
        struct  keyTab  *pKey;          /* pointer to KeyTable[] */           
        int     nByte   = 0;            /* input byte count */                
        int     cChar   = 0;            /* current character */               
        int     cType   = 0;            /* character type code */             
        int     fNull   = 0;            /* =1 if NUL read */                  
        int     nState  = 0;            /* state code */                      
        char    *pBuf   = cBuf;         /* pointer to buf */                  
        int     ch;                     /* scratch */                         
                                                                              
        /*                                                                    
        **      This code implements a finite-state automaton                 
        */                                                                    
                                                                              
        for ( ; cChar != EOF; nByte++) {                                      
                /* stop if length of label exceded */                         
                if ((KeyTable[0].k_flg & K_FOUND) && nByte >= LBLSIZE) {      
                        cType = 0;                                            
                        cChar = EOF;                                          
                } else if (fNull) { /* gobble after NUL encountered */        
                        (void)getc(pFile);                                    
                        continue;                                             
                } else switch (cChar = getc(pFile)) {                         
                /* get input byte type */                                     
                case EOF:                                                     
                        error("%s: unexpected EOF", inFile);                  
                case 0:                                                       
                        fNull++;                                              
                case '\r':                                                    
                case '\n':                                                    
                        continue;                                             
                case ' ':                                                     
                        cType = 0;                                            
                        break;                                                
                case '=':                                                     
                        cType = 1;                                            
                        break;                                                
                case '\'':                                                    
                        cType = 2;                                            
                        break;                                                
                default:                                                      
                        cType = 3;                                            
                        break;                                                
                }                                                             
                /* branch on new state */                                     
                switch (nState = stateTable[nState][cType]) {                 
                case -1: /* unexpected state */                               
                        error("VICAR label error in byte %d",                 
                                (char *)nByte);                               
                case 0: /* blank before keyword */                            
                        break;                                                
                case 1: /* keyword */                                         
                case 4: /* string value */                                    
                        *pBuf++ = cChar;                                      
                        break;                                                
                case 2: /* assignment = */                                    
                        *pBuf = 0;                                            
                        for (pKey = KeyTable; pKey->k_name &&                 
                                        strcmp(cBuf, pKey->k_name); pKey++)   
                                ;                                             
                        if (! pKey->k_name)                                   
                                pKey = NULL;                                  
                        pBuf = cBuf;                                          
                        break;                                                
                case 3: /* starting quote */                                  
                        if (pKey && ! (pKey->k_flg & K_CHAR))                 
                                error("non-numeric %s value", pKey->k_name);  
                        break;                                                
                case 6: /* numeric value */                                   
                        if (pKey && (pKey->k_flg & K_CHAR))                   
                                error("non-string %s value", pKey->k_name);   
                        *pBuf++ = cChar;                                      
                        break;                                                
                case 5: /* ending (or doubled) quote */                       
                        if ((cChar = getc(pFile)) == '\'') {                  
                                *pBuf++ = cChar;                              
                                nState = 4;                                   
                                nByte++;                                      
                                break;                                        
                        }                                                     
                        (void)ungetc(cChar, pFile);                           
                case 7: /* end numeric */                                     
                        if (! pKey) { /* skip unimportant keyword */          
                                pBuf = cBuf;                                  
                                break;                                        
                        }                                                     
                        *pBuf++ = 0;                                          
                        if (vFlag)                                            
                                fprintf(stderr, "%-8.8s = %s\n",              
                                        pKey->k_name, cBuf);                  
                        if (nState == 5)                                      
                                *(char **)(pKey->k_ptr) =                     
                                        strcpy(malloc(pBuf-cBuf), cBuf);      
                        else if (sscanf(cBuf[0] ? cBuf : "0",                 
                                (pKey->k_flg & K_DOUBLE) ? "%lf" : "%d",      
                                        pKey->k_ptr) != 1)                    
                                error("bad %s value", pKey->k_name);          
                        pKey->k_flg |= K_FOUND;                               
                        if (pKey->k_flg & K_LAT)                              
                                nsFlag |= (cBuf[0] == '-') ?                  
                                        K_SOUTH : K_NORTH;                    
                        pBuf = cBuf;                                          
                        break;                                                
                }                                                             
        }                                                                     
                                                                              
        /* Check for required parameters */                                   
        for (pKey = KeyTable; pKey->k_name; pKey++)                           
                if ((pKey->k_flg & (K_REQD | K_FOUND)) == K_REQD)             
                        error("keyword not in header: %s", pKey->k_name);     
}                                                                             
                                                                              
getVicarValue(x, y, dn, lon, lat, val, units)                                 
        float   *lon, *lat, *val;       /* returned coordinates */            
        int     *dn;                    /* returned pixel value */            
        char    **units;                /* unit type string */                
{                                                                             
        static  float   fScale;         /* projection scale factor */         
        static  float   fConv;          /* radians per degree */              
        float           dx, dy;         /* scratch */                         
        int             i;              /* scratch */                         
                                                                              
        /* initialize projection parameters */                                
        if (! fConv && OK(PIXSIZ)) {                                          
                fConv = 45/atan(1.0);                                         
                fScale = PIXSIZ/VENUS_RADIUS;                                 
        }                                                                     
                                                                              
        /* if information exists, derive longitude and latitude */            
        *dn = pRetImage[x + y * iWidth] & 0xff;                               
        dx = fScale*(x+0.5-PROJSAMP);                                         
        dy = fScale*(SPECLINE-0.5-y);                                         
        if (! MAP_PROJ || !OK(SPECLINE+PROJSAMP+PROJ_LON+PIXSIZ))             
                *lat = *lon = UNINIT;                                         
        else if (!strcmp(MAP_PROJ, "SINUSOIDAL")) {                           
                *lat = dy*fConv;                                              
                *lon = dx/cos(dy);                                            
        } else if (!strcmp(MAP_PROJ, "STEREOGRAPHIC")) {                      
                *lon = atan2(dx,(nsFlag == K_SOUTH) ? dy : -dy);              
                *lat = 2*fConv*atan(0.5*hypot(dx,dy));                        
                *lat = (nsFlag == K_SOUTH) ? *lat-90 : 90-*lat;               
        } else if (!strcmp(MAP_PROJ, "MERCATOR")) {                           
                *lon = dx;                                                    
                *lat = 2*fConv*atan(exp(dy))-90;                              
        }                                                                     
        *lon *= fConv;                                                        
        if (fabs(*lon) > 180)                                                 
                *lat = *lon = UNINIT;                                         
        else if ((*lon = PROJ_LON + *lon) < 0)                                
                *lon += 360;                                                  
                                                                              
        *units = DN_UNITS;                                                    
                                                                              
        /* get pixel DN value */                                              
        for (i = 0; i < 256 && *dn != indxColor[i]; i++)                      
                ;                                                             
        if (i == 256) {                                                       
                *val = UNINIT;                                                
                return '?';                                                   
        } else if ((*dn = i) == 0) {                                          
                *val = minValue;                                              
                return '<';                                                   
        } else if (i == 255) {                                                
                *val = maxValue;                                              
                return '>';                                                   
        } else {                                                              
                *val = minValue + (i*(maxValue-minValue))/255.0;              
                return '=';                                                   
        }                                                                     
}                                                                             
