diff options
author | Joe Hunkeler <jhunkeler@gmail.com> | 2015-08-11 16:51:37 -0400 |
---|---|---|
committer | Joe Hunkeler <jhunkeler@gmail.com> | 2015-08-11 16:51:37 -0400 |
commit | 40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch) | |
tree | 4464880c571602d54f6ae114729bf62a89518057 /vendor/x11iraf/ximtool/iis.c | |
download | iraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz |
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'vendor/x11iraf/ximtool/iis.c')
-rw-r--r-- | vendor/x11iraf/ximtool/iis.c | 1698 |
1 files changed, 1698 insertions, 0 deletions
diff --git a/vendor/x11iraf/ximtool/iis.c b/vendor/x11iraf/ximtool/iis.c new file mode 100644 index 00000000..8217feca --- /dev/null +++ b/vendor/x11iraf/ximtool/iis.c @@ -0,0 +1,1698 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/un.h> +#include <fcntl.h> + +#include <X11/Intrinsic.h> +#include <X11/StringDefs.h> +#include "ximtool.h" +#include "iis.h" + +/* + * IIS.C -- IRAF/IIS "imtool" protocol module. This code is responsible for + * accepting connections from remote network clients and communicating with + * them via the imtool/iis image display server communications prototcol. + * + * fd = xim_iisOpen (xim) + * xim_iisClose (xim) + * xim_iisio (xim, &fd, &id) + * + * xim_frameLabel (xim) + * xim_encodewcs (xim, sx, sy, sz, obuf) + * xim_retCursorVal (xim, sx, sy, frame, wcs, key, strval) + * + * xim_iisiomap (w, iomap, &iomap_len) + * xim_iiscolormap (w, r, g, b, &first, &ngray, &rgb_len) + * + * xim_iisio is a callback procedure called by Xt when there is input to be + * processed on the stream used to communicate with the remote client. + */ + +#define MEMORY 01 /* frame buffer i/o */ +#define LUT 02 /* lut i/o */ +#define FEEDBACK 05 /* used for frame clears */ +#define IMCURSOR 020 /* logical image cursor */ +#define WCS 021 /* used to set WCS */ +#define SZ_IOBUF 65536 /* max size data transfer */ +#define IO_TIMEOUT 30 /* i/o not getting anywhere */ +#define MAXCONN 5 + + +#define IIS_VERSION 11 /* version 10 => 1.0 */ + /* v1.1 => fast subraster write */ +#define IIS_DEBUG 0 /* local debug flag */ + +#define SZ_IMCURVAL 160 +#define PACKED 0040000 +#define COMMAND 0100000 +#define IIS_READ 0100000 +#define IMC_SAMPLE 0040000 +#define IMT_FBCONFIG 077 +#define XYMASK 077777 +#define ALLBITPL 255 + +struct iism70 { + short tid; + short thingct; + short subunit; + short checksum; + short x, y, z; + short t; +}; + +/* Running id for frame mappings. We keep a separate id for each of the + * currently allowed MAX_FRAMES since the object id is used in the WCS + * code for the image along with the (frame_num * 100). + */ +int objid[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; +static int *wcspix_enabled = NULL; + +static int iis_debug = -1; /* protocol debug */ + +static void set_fbconfig(), add_mapping(); +static void xim_connectClient(), xim_disconnectClient(); +static int chan_read(), chan_write(), decode_frameno(); + +static CtranPtr wcs_update(); +static IoChanPtr open_fifo(), open_inet(), open_unix(); +static IoChanPtr get_iochan(); +static MappingPtr xim_getMapping(); + +extern int errno; + + +/* XIM_IISOPEN -- Initialize the IIS protocol module and ready the module to + * accept client connections and begin processing client requests. Clients + * may connect to the server using a fifo connection or an internet or + * UNIX domain socket connection. All three types of server ports are + * simultaneously ready to receive client connections. + */ +xim_iisOpen (xim) +register XimDataPtr xim; +{ + int i, port, last_port = (xim->port + xim->nports - 1); + int nopen = 0; + + + if (open_unix (xim)) + nopen++; + if (open_fifo (xim)) + nopen++; + + for (port=xim->port; port > 0 && port <= last_port; port++) { + if (open_inet (xim, port)) + nopen++; + } + + return (nopen); +} + + +/* XIM_IISCLOSE -- Close down the IIS protocol module. + */ +void +xim_iisClose (xim) +register XimDataPtr xim; +{ + register IoChanPtr chan; + register int i; + + for (i=0, chan=NULL; i < XtNumber(xim->chan); i++) { + chan = &xim->chan[i]; + if (chan->id) { + xim_removeInput (xim, chan->id); + chan->id = NULL; + } + + switch (chan->type) { + case IO_FIFO: + if (chan->keepalive >= 0) + close (chan->keepalive); + if (chan->datain >= 0) + close (chan->datain); + if (chan->dataout >= 0) + close (chan->dataout); + chan->type = 0; + break; + + case IO_INET: + close (chan->datain); + chan->type = 0; + break; + + case IO_UNIX: + close (chan->datain); + unlink (chan->path); + chan->type = 0; + break; + } + } +} + + +/* OPEN_FIFO -- Open the imtool fifo port and make ready to accept client + * connections and begin processing client requests. There is no client + * yet at this stage. + */ +static IoChanPtr +open_fifo (xim) +register XimDataPtr xim; +{ + register IoChanPtr chan; + int datain, dataout; + int keepalive; + + +#if defined (__DARWIN__) || defined(__CYGWIN__) + /* On OS X we don't use fifos. */ + xim->input_fifo = "none"; + return (NULL); +#endif + + /* Setting the input fifo to "none" or the null string disables + * fifo support. + */ + if (!xim->input_fifo[0] || strcmp(xim->input_fifo,"none")==0) + return (NULL); + + datain = dataout = -1; + + if (IIS_DEBUG) + printf ("Opening fifo: '%s'\n", xim->input_fifo); + + /* Open the output fifo (which is the client's input fifo). We have + * to open it ourselves first as a client to get around the fifo + * open-no-client error. + */ + if ((datain = open (xim->input_fifo, O_RDONLY|O_NDELAY)) != -1) { + if ((dataout = open (xim->input_fifo, O_WRONLY|O_NDELAY)) != -1) + fcntl (dataout, F_SETFL, O_WRONLY); + else + goto done; + close (datain); + } else + goto done; + + /* Open the input stream, a FIFO pseudodevice file used by + * applications to send us commands and data. + */ + if ((datain = open (xim->output_fifo, O_RDONLY|O_NDELAY)) == -1) + goto done; + else { + /* Clear O_NDELAY for reading. */ + fcntl (datain, F_SETFL, O_RDONLY); + + /* Open the client's output fifo as a pseudo-client to make it + * appear that a client is connected. + */ + keepalive = open (xim->output_fifo, O_WRONLY); + } +done: + /* Allocate and fill in i/o channel descriptor. */ + if (datain > 0 && dataout > 0 && (chan = get_iochan(xim))) { + chan->xim = (XtPointer) xim; + chan->type = IO_FIFO; + chan->datain = datain; + chan->dataout = dataout; + chan->keepalive = keepalive; + chan->reference_frame = 1; + chan->version = 0; + chan->rf_p = &xim->frames[0]; + } else { + fprintf (stderr, "Warning: cannot open %s\n", xim->output_fifo); + xim->input_fifo = "none"; + return (NULL); + } + + /* Register input callback. */ + if (chan) { + chan->id = xim_addInput (xim, chan->datain, xim_iisio, + (XtPointer)chan); + } else { + if (datain > 0) + close (datain); + if (dataout > 0) + close (dataout); + } + + return (chan); +} + + +/* OPEN_INET -- Set up a port to be used for incoming client connections + * using internet domain sockets. + */ +static IoChanPtr +open_inet (xim, portnum) +register XimDataPtr xim; +int portnum; +{ + register int s = 0; + register IoChanPtr chan; + struct sockaddr_in sockaddr; + int reuse = 1; + + /* Setting the port to zero disables inet socket support. */ + if (portnum <= 0) + return (NULL); + + + if (IIS_DEBUG) + printf ("Opening inet port: %d\n", portnum); + + if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) + goto err; + + memset ((void *)&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons((short)portnum); + sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, + sizeof(reuse)) < 0) + goto err; + + if (bind (s, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) + goto err; + + if (listen (s, MAXCONN) < 0) + goto err; + + /* Allocate and fill in i/o channel descriptor. */ + if (chan = get_iochan(xim)) { + chan->xim = (XtPointer) xim; + chan->type = IO_INET; + chan->datain = s; + chan->dataout = s; + chan->reference_frame = 1; + chan->version = 0; + chan->rf_p = &xim->frames[0]; + + /* Register connectClient callback. */ + chan->id = xim_addInput (xim,s,xim_connectClient,(XtPointer)chan); + return (chan); + } + + +err: + if (errno == EADDRINUSE) { + fprintf (stderr,"ximtool: inet port %d already in use - disabled\n", + portnum); + } else { + fprintf (stderr, "ximtool: can't open inet socket %d, errno=%d\n", + portnum, errno); + } + xim->port = 0; + if (s) + close (s); + return (NULL); +} + + +/* OPEN_UNIX -- Set up a port to be used for incoming client connections + * using unix domain sockets. + */ +static IoChanPtr +open_unix (xim) +register XimDataPtr xim; +{ + register int s = 0; + register IoChanPtr chan; + struct sockaddr_un sockaddr; + int addrlen; + char path[256]; + + /* Setting the addr to "none" or the null string disables unix + * socket support. + */ + if (!xim->unixaddr[0] || strcmp(xim->unixaddr,"none")==0) + return (NULL); + + + if (IIS_DEBUG) + printf ("Opening unix socket: '%s'\n", xim->unixaddr); + + /* Get path to be used for the unix domain socket. */ + sprintf (path, xim->unixaddr, getuid()); + unlink (path); + + if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) + goto err; + + memset ((void *)&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sun_family = AF_UNIX; + strcpy (sockaddr.sun_path, path); + addrlen = sizeof(sockaddr) - sizeof(sockaddr.sun_path) + strlen(path); + if (bind (s, (struct sockaddr *)&sockaddr, addrlen) < 0) + goto err; + + if (listen (s, MAXCONN) < 0) + goto err; + + /* Allocate and fill in i/o channel descriptor. */ + if (chan = get_iochan(xim)) { + chan->xim = (XtPointer) xim; + chan->type = IO_UNIX; + chan->datain = s; + chan->dataout = s; + chan->reference_frame = 1; + chan->version = 0; + chan->rf_p = &xim->frames[0]; + strncpy (chan->path, path, SZ_FNAME); + + /* Register connectClient callback. */ + chan->id = xim_addInput (xim,s,xim_connectClient,(XtPointer)chan); + return (chan); + } +err: + if (errno == EADDRINUSE) { + fprintf (stderr,"ximtool: unix addr %s already in use - disabled\n", + path); + } else { + fprintf (stderr,"ximtool: cannot open unix socket '%s', errno=%d\n", + path, errno); + } + strcpy (xim->unixaddr, "none"); + if (s) + close (s); + return (NULL); +} + + +/* XIM_CONNECTCLIENT -- Called when a client has attempted a connection on + * a socket port. Accept the connection and set up a new i/o channel to + * communicate with the new client. + */ +static void +xim_connectClient (chan_port, source, id) +IoChanPtr chan_port; +int *source; +XtPointer id; +{ + register XimDataPtr xim = (XimDataPtr) chan_port->xim; + register IoChanPtr chan; + register int s; + + /* Accept connection. */ + if ((s = accept ((int)*source, (struct sockaddr *)0, (int *)0)) < 0) + return; +/* + if (fcntl (s, F_SETFL, O_RDWR|O_NDELAY) < 0) { + close (s); + return; + } +*/ + + /* Allocate and fill in i/o channel descriptor. */ + if (chan = get_iochan(xim)) { + chan->xim = (XtPointer) xim; + chan->type = chan_port->type; + chan->datain = s; + chan->dataout = s; + chan->reference_frame = 1; + chan->version = 0; + chan->rf_p = &xim->frames[0]; + chan->id = xim_addInput (xim, s, xim_iisio, (XtPointer)chan); + } +} + + +/* XIM_DISCONNECTCLIENT -- Called to close a client connection when EOF is + * seen on the input port. Close the connection and free the channel + * descriptor. + */ +static void +xim_disconnectClient (chan) +register IoChanPtr chan; +{ + switch (chan->type) { + case IO_INET: + case IO_UNIX: + close (chan->datain); + if (chan->id) { + xim_removeInput (chan->xim, chan->id); + chan->id = NULL; + } + chan->type = 0; + break; + default: + break; + } +} + + +/* GET_IOCHAN --- Get an i/o channel descriptor. + */ +static IoChanPtr +get_iochan (xim) +register XimDataPtr xim; +{ + register IoChanPtr chan; + register int i; + + for (i=0; i < XtNumber(xim->chan); i++) + if (!xim->chan[i].type) + return (&xim->chan[i]); + + return (NULL); +} + + +/* XIM_IISIO -- Xt file i/o callback procedure, called when there is input + * pending on the data stream to the ximtool client. + */ +void +xim_iisio (chan, fd_addr, id_addr) +IoChanPtr chan; +int *fd_addr; +XtInputId *id_addr; +{ + register XimDataPtr xim = (XimDataPtr) chan->xim; + register MappingPtr mp = (MappingPtr) NULL; + register FrameBufPtr fb; + register int sum, i; + register short *p; + int datain = *fd_addr; + int dataout = chan->dataout; + int ndatabytes, nbytes, n, newframe, ntrys=0; + struct iism70 iis; + char buf[SZ_FIFOBUF]; + static int errmsg=0, bswap=0; + + + /* Initialize the debug output. */ + if (iis_debug == -1) + iis_debug = (getenv("DEBUG_IIS") != (char *)NULL); + + /* Get the IIS header. */ + if ((n = chan_read (datain, (char *)&iis, sizeof(iis))) < sizeof(iis)) { + if (n != 0) + fprintf (stderr, + "ximtool: command input read error, n=%d of %d, errno=%d\n", + n, sizeof(iis), errno); + if (n <= 0) + xim_disconnectClient (chan); + return; + } else if (bswap) + bswap2 ((char *)&iis, (char *)&iis, sizeof(iis)); + + /* Verify the checksum. If it fails swap the bytes and try again. + */ + for (;;) { + for (i=0, sum=0, p=(short *)&iis; i < 8; i++) + sum += *p++; + if ((sum & 0177777) == 0177777) + break; + + if (ntrys++) { + if (!errmsg++) { + fprintf (stderr, "ximtool: bad data header checksum\n"); + if (bswap) + bswap2 ((char *)&iis, (char *)&iis, sizeof(iis)); + fprintf (stderr, "noswap:"); + for (i=0, p=(short *)&iis; i < 8; i++) + fprintf (stderr, " %6o", p[i]); + fprintf (stderr, "\n"); + + bswap2 ((char *)&iis, (char *)&iis, sizeof(iis)); + fprintf (stderr, " swap:"); + for (i=0, p=(short *)&iis; i < 8; i++) + fprintf (stderr, " %6o", p[i]); + fprintf (stderr, "\n"); + } + break; + + } else { + bswap2 ((char *)&iis, (char *)&iis, sizeof(iis)); + bswap = !bswap; + } + } + + ndatabytes = -iis.thingct; + if (!(iis.tid & PACKED)) + ndatabytes *= 2; + + if (iis_debug) { + fprintf (stderr, + "subunit=%06o tid=%06o nbytes=%7d x=%06o y=%06o z=%06o t=%06o\n", + iis.subunit & 077, + iis.tid, + ndatabytes, + iis.x & 0177777, + iis.y & 0177777, + iis.z & 0177777, + iis.t & 0177777); + fflush (stderr); + } + + + switch (iis.subunit & 077) { + case FEEDBACK: + /* The feedback unit is used only to clear a frame. The + * xim_eraseFrame() procedure takes care of uncaching the + * mappings associated with this frame. + */ + newframe = decode_frameno (iis.z & 0177777); + xim_setReferenceFrame (chan, newframe); + if (newframe == chan->reference_frame) + xim_eraseFrame (xim, chan->reference_frame); + + /* ISM: Uncache all mappings associated with this frame. */ + fb = &xim->frames[newframe-1]; + for (i=0; i < fb->nmaps; i++) { + mp = &fb->mapping[i]; + if (mp->id) { + sprintf (buf, "uncache %d", mp->id); + ism_message (xim, "wcspix", buf); + wcspix_message (xim, buf); + mp->id = 0; + } + } + + /* Reset various counters for the new frame and release the + * mappings. + */ + fb->nmaps = 0; + fb->ctran.valid = 0; + objid[newframe-1] = 0; + fb->nmaps = 0; + + if (iis_debug) + fprintf (stderr, "erase frame %d - ref = %d\n", + newframe, chan->reference_frame); + break; + + case LUT: + /* Data mode writes to the frame lookup tables are not implemented. + * A command mode write to the LUT subunit is used to connect + * image memories up to the RGB channels, i.e., to select the frame + * to be displayed. We ignore any attempt to assign multiple + * frames to multiple color channels, and just do a simple frame + * select. + */ + if (iis.subunit & COMMAND) { + int frame, z, n; + short x[17]; + + if (chan_read (datain, (char *)x, ndatabytes) == ndatabytes) { + if (bswap) + bswap2 ((char *)x, (char *)x, ndatabytes); + + z = x[0]; + if (!z) z = 1; + for (n=0; !(z & 1); z >>= 1) + n++; + + frame = max (1, n + 1); + if (frame > xim->nframes) { + if (frame <= MAX_FRAMES) { + set_fbconfig (chan, xim->fb_configno, frame); + if (iis_debug) + fprintf (stderr, "set_fbconfig (%d, %d)\n", + xim->fb_configno, frame); + } else { + fprintf (stderr, "ximtool warning: "); + fprintf (stderr, + "attempt to display nonexistent frame %d\n", + frame); + return; + } + } + + xim_setDisplayFrame (xim, frame); + if (iis_debug) + fprintf (stderr, "set_frame (%d)\n", frame); + return; + } + } + + case MEMORY: + /* Load data into the frame buffer. Data is assumed to be byte + * packed. + */ + if (iis.tid & IIS_READ) { + /* Read from the display. + */ + unsigned char *ip, iobuf[SZ_IOBUF]; + int nbytes, nleft, n, x, y; + long starttime; + + /* Get the frame to read from. */ + xim_setReferenceFrame (chan, decode_frameno (iis.z & 0177777)); + + nbytes = ndatabytes; + x = iis.x & XYMASK; + y = iis.y & XYMASK; + + if (x < 0 || x >= xim->width || y < 0 || y >= xim->height) { + fprintf (stderr, + "ximtool: attempted read out of bounds on framebuf\n"); + fprintf (stderr, + "read %d bytes at [%d,%d]\n", nbytes, x, y); + memset ((void *)iobuf, 0, nbytes); + } else { + int nx, ny; + + /********** OLD CODE ********* + GtReadPixels (xim->gt, chan->rf_p->raster, iobuf, 8, x, y, + min(xim->width-x,nbytes), max(1,nbytes/xim->width)); + ********** OLD CODE **********/ + + /* If the iis.t element is set, it will contain the width + ** of the subraster being read. In the old scheme we + ** assumed we were reading the entire width of the FB. + */ + if (iis.t > 0 && iis.t != ALLBITPL) { + nx = min (xim->width-x, iis.t); + ny = max (1, nbytes/iis.t); + } else { + nx = min (xim->width-x, nbytes); + ny = max (1, nbytes/xim->width); + } + GtReadPixels (xim->gt, chan->rf_p->raster, iobuf, 8, x, y, + nx, ny); + + if (iis_debug) + fprintf (stderr, + "read %d bytes at [%d,%d]\n", nbytes, x, y); + } + + /* Return the data from the frame buffer. */ + starttime = time(0); + for (nleft=nbytes, ip=iobuf; nleft > 0; nleft -= n) { + n = (nleft < SZ_FIFOBUF) ? nleft : SZ_FIFOBUF; + if ((n = chan_write (dataout, ip, n)) <= 0) { + if (n < 0 || (time(0) - starttime > IO_TIMEOUT)) { + fprintf (stderr, "XIMTOOL: timeout on write\n"); + break; + } + } else + ip += n; + } + + return; + + } else { + /* Write to the display. + */ + unsigned char *op, iobuf[SZ_IOBUF]; + int nbytes, nleft, n, x, y; + long starttime; + + /* Get the frame to be written into (encoded with a bit for + * each frame, 01 is frame 1, 02 is frame 2, 04 is frame 3, + * and so on). + */ + xim_setReferenceFrame (chan, decode_frameno (iis.z & 0177777)); + + nbytes = ndatabytes; + x = iis.x & XYMASK; + y = iis.y & XYMASK; + + /* Read the data into the frame buffer. + */ + starttime = time(0); + for (nleft=nbytes, op=iobuf; nleft > 0; nleft -= n) { + n = (nleft < SZ_FIFOBUF) ? nleft : SZ_FIFOBUF; + if ((n = chan_read (datain, op, n)) <= 0) { + if (n < 0 || (time(0) - starttime > IO_TIMEOUT)) { + fprintf (stderr, "XIMTOOL: timeout on read\n"); + break; + } + } else + op += n; + } + + if (x < 0 || x >= xim->width || y < 0 || y >= xim->height) { + fprintf (stderr, + "ximtool: attempted write out of bounds on framebuf\n"); + fprintf (stderr, + "write %d bytes at [%d,%d]\n", nbytes, x, y); + memset ((void *)iobuf, 0, nbytes); + } else { + int nx, ny; + + /********** OLD CODE ********* + GtWritePixels (xim->gt, chan->rf_p->raster, iobuf, 8, x, y, + min(xim->width-x,nbytes), max(1,nbytes/xim->width)); + ********** OLD CODE **********/ + + /* If the iis.t element is set, it will contain the width + ** of the subraster being written. In the old scheme we + ** assumed we were writing the entire width of the FB. + */ + if (iis.t > 0 && iis.t != ALLBITPL) { + nx = min (xim->width-x, iis.t); + ny = max (1, nbytes/iis.t); + } else { + nx = min (xim->width-x, nbytes); + ny = max (1, nbytes/xim->width); + } + GtWritePixels (xim->gt, chan->rf_p->raster, iobuf, 8, + x, y, nx, ny); + + if (iis_debug) + fprintf (stderr, "write %d bytes at x=%d, y=%d\n", + nbytes, x, y, nx, ny); + } + + return; + } + break; + + case WCS: + /* Read or write the WCS for a frame. The frame number to + * which the WCS applies is passed in Z and the frame buffer + * configuration in T. The client changes the frame buffer + * configuration in a WCS set. The WCS text follows the header + * as byte packed ASCII data. + */ + if (iis.tid & IIS_READ) { + /* Return the WCS for the referenced frame. + */ + char emsg[SZ_WCSBUF]; + char *text; + int frame, wcsnum; + + memset ((char *)emsg, 0, SZ_WCSBUF); + + if ((iis.x & 017777) && (iis.y & 017777)) { + /* This is a check by the client on our capabilities. + * Return with a version number which can be used by the + * client. However we write back using the old WCS + * buffer size for compatability. + */ + sprintf (text=emsg, "version=%d", IIS_VERSION); + chan->version = IIS_VERSION; + + chan_write (dataout, text, SZ_OLD_WCSBUF); + if (iis_debug) + fprintf (stderr, "version query wcs: %s\n",text); + + } else if ((iis.x & 017777) && (iis.t & 017777)) { + /* Return the buffer for a specified WCS number. + */ + CtranPtr ct = (CtranPtr) NULL; + FrameBufPtr fr = (FrameBufPtr) NULL; + int wcsnum = (iis.t & 017777); + register int i, j; + + + /* Decode the requested wcs number. */ + frame = decode_frameno (iis.z & 0177777); + + /* Search for the requested WCS number. */ + mp = (MappingPtr) NULL; + for (j=0; j < xim->nframes; j++) { + fr = &xim->frames[j]; + if (fr->frameno != frame) + continue; + for (i=0; i < fr->nmaps; i++) { + mp = &fr->mapping[i]; + if (mp->id == wcsnum) { + /* found the mapping */ + ct = &(mp->ctran); + goto map_found; + } + } + } + + /* Encode the WCS and mapping information. */ +map_found: if (ct) { + char wcs[SZ_WCSBUF], mapping[SZ_WCSBUF]; + + sprintf (wcs, "%s\n%f %f %f %f %f %f %f %f %d\n", + ct->imtitle, ct->a, ct->b, ct->c, ct->d, + ct->tx, ct->ty, ct->z1, ct->z2, ct->zt); + sprintf (mapping, "%s %f %f %d %d %d %d %d %d\n%s\n", + mp->region, mp->sx, mp->sy, mp->snx, mp->sny, + mp->dx, mp->dy, mp->dnx, mp->dny, mp->ref); + + strcpy (text=emsg, wcs); + strcat (text, mapping); + } else + strcpy (text=emsg, "[NOSUCHWCS]\n"); + + chan_write (dataout, text, SZ_WCSBUF); + + if (iis_debug) { + fprintf (stderr, "query specified wcs=%d frame=%d\n", + wcsnum, frame); + write (2, text, strlen (text)); + } + + } else { + frame = decode_frameno (iis.z & 0177777); + xim_setReferenceFrame (chan, frame); + + if (chan->rf_p->frameno <= 0) + strcpy (text=emsg, "[NOSUCHFRAME]\n"); + else + text = chan->rf_p->wcsbuf; + + if ((iis.x & 0777)) + chan_write (dataout, text, SZ_WCSBUF); + else + chan_write (dataout, text, SZ_OLD_WCSBUF); + + if (iis_debug) { + fprintf (stderr, "query wcs: frame = %d\n", frame); + write (2, text, strlen(text)); + } + } + + } else { + /* Set the WCS for the referenced frame. + */ + register CtranPtr ct; + int fb_config, frame, new_wcs = 0; + + frame = decode_frameno (iis.z & 0177777); + fb_config = (iis.t & 0777) + 1; + new_wcs = (iis.x & 0777); + + /* See if we need to change the frame buffer configuration, + * or allocate a new frame. + */ + if (fb_config != xim->fb_configno) + set_fbconfig (chan, fb_config, frame); + else if (frame > xim->nframes && frame <= MAX_FRAMES) + set_fbconfig (chan, xim->fb_configno, frame); + + /* Read in and set up the WCS. */ + xim_setReferenceFrame (chan, frame); + memset ((char *)buf, 0, SZ_WCSBUF); + if (chan_read (datain, buf, ndatabytes) == ndatabytes) + strncpy (chan->rf_p->wcsbuf, buf, + (new_wcs ? SZ_WCSBUF : SZ_OLD_WCSBUF)); + + if (iis_debug) { + fprintf (stderr, "set wcs:\n"); + write (2, buf, ndatabytes); + } + + strcpy (chan->rf_p->ctran.format, W_DEFFORMAT); + chan->rf_p->ctran.imtitle[0] = '\0'; + chan->rf_p->ctran.valid = 0; + ct = wcs_update (xim, chan->rf_p); + + /* If we're connected to an old-style client, disable the + * WCSPIX ISM, otherwise just let the GUI know it capable. + */ + wcspix_message (xim, (new_wcs ? "capable" : "disable")); + + /* Add the mapping information. */ + add_mapping (xim, ct, chan->rf_p->wcsbuf, + &xim->frames[chan->reference_frame-1]); + + xim_message (xim, "frameTitle", ct->imtitle); + } + return; + + case IMCURSOR: + /* Read or write the logical image cursor. This is an extension + * added to provide a high level cursor read facility; this is + * not the same as a low level access to the IIS cursor subunit. + * Cursor reads may be either nonblocking (immediate) or blocking, + * using the keyboard or mouse to terminate the read, and + * coordinates may be returned in either image (world) or frame + * buffer pixel coordinates. + */ + if (iis.tid & IIS_READ) { + /* Read the logical image cursor. In the case of a blocking + * read all we do is initiate a cursor read; completion occurs + * when the user hits a key or button. + */ + if (iis_debug) + fprintf (stderr, "read cursor position\n"); + if (iis.tid & IMC_SAMPLE) { + /* Sample the cursor position and return the cursor value + * on the output datastream encoded in a fixed size + * ascii buffer. + */ + int wcs = iis.z; + int raster, frame; + float sx, sy; + IoChanPtr sv_chan; + + /* Save the cursor channel so that sampled cursor reads + * can occur on one channel without affecting any + * interactive cursor reads in progress on another + * channel. + */ + sv_chan = xim->cursor_chan; + xim->cursor_chan = chan; + xim_getCursorPos (xim, &sx, &sy, &raster, &frame); + xim_retCursorVal (xim, sx, sy, frame, wcs, 0, ""); + xim->cursor_chan = sv_chan; + + } else { + /* Initiate a user triggered cursor read. */ + if (xim->cursor_chan) { + int frame = xim->cursor_chan->reference_frame; + xim_retCursorVal (xim, 0., 0., frame, 0, EOF, ""); + } + xim->cursor_chan = chan; + xim_cursorMode (xim, 1); + } + + } else { + /* Write (set) the logical image cursor position. */ + register CtranPtr ct; + int sx = iis.x, sy = iis.y; + float wx = sx, wy = sy; + int wcs = iis.z; + + if (iis_debug) + fprintf(stderr, "write cursor position: [%d,%d]\n", sx, sy); + if (wcs) { + ct = wcs_update (xim, xim->df_p); + if (ct->valid) { + if (abs(ct->a) > .001) + sx = (wx - ct->tx) / ct->a; + if (abs(ct->d) > .001) + sy = (wy - ct->ty) / ct->d; + } + } + + xim_setCursorPos (xim, sx, sy); + } + return; + + default: + /* Ignore unsupported command input. + */ + break; + } + + /* Discard any data following the header. */ + if (!(iis.tid & IIS_READ)) + for (nbytes = ndatabytes; nbytes > 0; nbytes -= n) { + n = (nbytes < SZ_FIFOBUF) ? nbytes : SZ_FIFOBUF; + if ((n = chan_read (datain, buf, n)) <= 0) { + if (iis_debug) + fprintf (stderr, + "discarding %d bytes following header:\n", n); + break; + } + } +} + + +/* XIM_IISIOMAP, XIM_IISCOLORMAP -- Set the iomap and colormap for a Gterm + * widget to emulate the color allocation scheme assumed by the imtool + * protocol. + * + * The nominal pixel mappings are as follows. + * + * Imtool Gterm Description + * + * 0 0 background + * 1 - 200 10-209 image data + * 201 210 cursor (white) + * 202 0 background (black) + * 203 1 white + * 204 2 red + * 205 3 green + * 206 4 blue + * 207 6 yellow + * 208 5 cyan + * 209 7 magenta + * 210 211 coral + * 211 212 maroon + * 212 213 orange + * 213 214 khaki + * 214 215 orchid + * 215 216 turquoise + * 216 217 violet + * 217 218 wheat + * + * The Gterm color allocation is the standard 10 static colors, followed by + * 200 dynamically allocated colors used to display image data, followed by + * a few additional colors. Only the block of 200 colors are subject to + * modification when the display is windowed or a new colortable is loaded. + * + * If the gterm widget is permitted a sufficient number of dynamic colors then + * pixels will be allocated as in the figure above. If there are too few + * colormap cells available to allocate all the colors then the image data + * region of gterm colormap space will be shrunk to make up the difference. + * The full set of static colors (imtool:201-217) are always allocated; it + * is the range 1-200 which is reduced if there are too few colors. The + * iomap always makes it appear to the client that the full range of 200 + * image levels and 17 static colors are available, even if the actual number + * of color cells available is less. + * + * The input arrays should be dimension of length 256. The number of + * iomap entries and number of RGB entries set is returned in the output + * variables iomap_len and rgb_len. + */ +xim_iisiomap (w, iomap, iomap_len) +register XtPointer w; +unsigned short *iomap; +int *iomap_len; +{ + register int i; + int first, nelem, maxelem; + int delta; + + GtQueryColormap (w, 0, &first, &nelem, &maxelem); + delta = min(maxelem,209) - 209; + + /* Set the iomap. */ + iomap[0] = 0; + for (i=1; i < 201; i++) + iomap[i] = (200 + delta) * (i-1) / 200 + first; + iomap[201] = first + 200 + delta; + for (i=0; i < 8; i++) + iomap[202+i] = i; + iomap[207] = 6; + iomap[208] = 5; + for (i=0; i < 8; i++) + iomap[210+i] = first + 201 + i + delta; + *iomap_len = 218; +} + + +/* xim_iiscolormap -- This is the gterm colormap for the IIS emulation, set + * before the IIS iomap is defined. The first colormap cell corresponds to + * first = gterm color 10. + */ +xim_iiscolormap (w, r, g, b, first, ngray, rgb_len) +register XtPointer w; +unsigned short *r, *g, *b; +int *first, *ngray, *rgb_len; +{ + register int i, j; + int nelem, maxelem; + int delta; + + GtQueryColormap (w, 0, first, &nelem, &maxelem); + delta = min(maxelem,209) - 209; + + /* Set the colormap. */ + for (i=0; i < 256; i++) + r[i] = g[i] = b[i] = 0; + for (i=0; i < 200 + delta; i++) + r[i] = g[i] = b[i] = (i * 255 / (200 + delta)); + + r[i] = 255; g[i] = 255; b[i] = 255; i++; /* 210=cursor */ + r[i] = 255; g[i] = 127; b[i] = 0; i++; /* 211=coral */ + r[i] = 142; g[i] = 35; b[i] = 107; i++; /* 212=maroon */ + r[i] = 204; g[i] = 50; b[i] = 50; i++; /* 213=orange */ + r[i] = 159; g[i] = 159; b[i] = 95; i++; /* 214=khaki */ + r[i] = 219; g[i] = 112; b[i] = 219; i++; /* 215=orchid */ + r[i] = 112; g[i] = 219; b[i] = 219; i++; /* 216=turquoise */ + r[i] = 159; g[i] = 95; b[i] = 159; i++; /* 217=violet */ + r[i] = 216; g[i] = 216; b[i] = 191; i++; /* 218=wheat */ + + /* Scale colormap values to 16 bits. */ + for (j=0; j < i; j++) { + r[j] <<= 8; + g[j] <<= 8; + b[j] <<= 8; + } + + *ngray = 200 + delta; + *rgb_len = i; +} + + +/* SET_FBCONFIG -- Set the frame buffer configuration, or add additional + * frames to the current configuration. + */ +static void +set_fbconfig (chan, config, frame) +IoChanPtr chan; +int config; +int frame; +{ + register XimDataPtr xim = (XimDataPtr) chan->xim; + register FrameBufPtr fb = &xim->frames[frame-1]; + register int i; + + if (config != xim->fb_configno) { + /* Change the frame buffer configuration. */ + xim_initialize (xim, config, + max (xim->fb_config[config-1].nframes, frame), 1); + + /* Reinitialize the tile framing if enabled. */ + if (xim->tileFrames) + xim_tileFrames (xim, xim->tileFramesList); + + /* Initialize the ISM to uncache all images when we change + * frame buffer configs. + */ + ism_message (xim, "wcspix", "initialize"); + + } else if (frame > xim->nframes) { + /* Add additional frames. */ + for (i=1; i <= frame; i++) { + fb = &xim->frames[i-1]; + if (fb->frameno != i) { + xim_initFrame (xim, i, frame, + &xim->fb_config[config-1], xim->memModel); + + /* If we're in tile mode, add the frame to the tile list + * and if needed resize the tile frames. + */ + if (xim->tileFrames) { + xim->tileFramesList |= (1 << (i-1)); + xim->nTileFrames++; + xim_tileFrames (xim, xim->tileFramesList); + } + } + } + } + + xim_setReferenceFrame (chan, frame); + if (frame != xim->display_frame) + xim_setDisplayFrame (xim, frame); +} + + +/* DECODE_FRAMENO -- Decode encoded IIS register frame number. + */ +static +decode_frameno (z) +register int z; +{ + register int n; + + /* Get the frame number, encoded with a bit for each frame, 01 is + * frame 1, 02 is frame 2, 04 is frame 3, and so on. + */ + if (!z) z = 1; + for (n=0; !(z & 1); z >>= 1) + n++; + + return (max (1, n + 1)); +} + + +/* XIM_RETCURSORVAL -- Return the cursor value on the output datastream to + * the client which requested the cursor read. + */ +xim_retCursorVal (xim, sx, sy, frame, wcs, key, strval) +register XimDataPtr xim; +float sx, sy; /* cursor screen coordinates */ +int frame; /* frame number */ +int wcs; /* nonzero if WCS coords desired */ +int key; /* keystroke used as trigger */ +char *strval; /* optional string value */ +{ + register CtranPtr ct; + register MappingPtr mp = (MappingPtr) NULL; + int dataout, wcscode; + char curval[SZ_IMCURVAL]; + char keystr[20]; + float wx, wy; + + if (xim->cursor_chan) + dataout = xim->cursor_chan->dataout; + else + return; + + /* Compute cursor coordinates. */ + if (wcs) { + ct = wcs_update (xim, xim->df_p); + if (ct->valid) { + /* The imtool WCS assumes that the center of the first display + * pixel is at (0,0) but actually it is at (0.5,0.5). + */ + sx -= 0.5; + sy -= 0.5; + + if (abs(ct->a) > .001) + wx = ct->a * sx + ct->c * sy + ct->tx; + if (abs(ct->d) > .001) + wy = ct->b * sx + ct->d * sy + ct->ty; + } + } else { + wx = sx; + wy = sy; + } + + /* Compute WCS code. */ + wcscode = frame * 100 + wcs; + if (wcspix_enabled != NULL && *wcspix_enabled) { + if ((mp = xim_getMapping (xim, sx, sy, frame))) { + wcscode = mp->id; + + /* Return the coordinates in terms of the mapping. */ + ct = &(mp->ctran); + wx = ct->a * sx + ct->c * sy + ct->tx; + wy = ct->b * sx + ct->d * sy + ct->ty; + } + } + + /* Encode the cursor value. */ + if (key == EOF) + sprintf (curval, "EOF\n"); + else { + if (isprint (key) && !isspace(key)) { + keystr[0] = key; + keystr[1] = '\0'; + } else + sprintf (keystr, "\\%03o", key); + + sprintf (curval, "%10.3f %10.3f %d %s %s\n", + wx, wy, wcscode, keystr, strval); + } + + + if (iis_debug) fprintf (stderr, "curval: %s", curval); + + /* Send it to the client program and terminate cursor mode. */ + chan_write (dataout, curval, sizeof(curval)); + xim_cursorMode (xim, 0); + xim->cursor_chan = NULL; +} + + +/* XIM_ENCODEWCS -- Transform the input screen (raster) coordinates and + * pixel value and return a string giving X, Y, and the pixel intensity in + * world units. + */ +xim_encodewcs (xim, sx, sy, sz, obuf) +register XimDataPtr xim; +float sx, sy; /* screen (raster) pixel coordinates */ +int sz; /* screen pixel value */ +char *obuf; /* receives encoded string */ +{ + register CtranPtr ct; + MappingPtr mp = (MappingPtr) NULL; + float wx, wy, wz; + float y = xim->height - sy; + register int j=0, i=0, ch, map_found = 0; + char buf[SZ_LINE]; + + + /* The first time we're called get the address of the wcspix + * connected flag so we can check whether to get screen pixel + * or real-image values. + */ + if (wcspix_enabled == NULL) { + register IsmModule ism; + extern ismModule ism_modules[]; + extern int ism_nmodules; + + for (i=0; i < ism_nmodules; i++) { + ism = &ism_modules[i]; + if (strcmp ("wcspix", ism->name) == 0) + wcspix_enabled = &(ism->connected); + } + } + + + /* Now lookup the coordinate mapping and update the WCS and real + * pixel value if the ISM is running. + */ + if (wcspix_enabled != NULL && *wcspix_enabled) { + if ((mp = xim_getMapping (xim, sx+1.0, sy, xim->display_frame))) { + ct = &(mp->ctran); + sx -= 0.5; + sy -= 0.5; + wx = ct->a * sx + ct->c * sy + ct->tx; + wy = ct->b * sx + ct->d * sy + ct->ty; + +/* +printf ("sx: %f sy: %f\n", sx, sy); +printf ("ct: %s\n%f %f %f %f %f %f %f %f %d\n", + ct->imtitle, ct->a, ct->b, ct->c, ct->d, + ct->tx, ct->ty, ct->z1, ct->z2, ct->zt); +printf ("mp: %s %f %f %d %d %d %d %d %d\n%s\n\n", + mp->region, mp->sx, mp->sy, mp->snx, mp->sny, + mp->dx, mp->dy, mp->dnx, mp->dny, mp->ref); +printf ("wx: %f wy: %f\n", wx, wy); +*/ + + /* Found the image mapping so request the WCS + * and pixel information from the WPIX ISM. + */ + if (mp->ref != NULL) { + sprintf (buf, "wcstran %d %g %g\n", mp->id, wx, wy); + ism_message (xim, "wcspix", buf); + } + map_found++; + } + } + + ct = wcs_update (xim, xim->df_p); + if (ct->valid) { + /* The imtool WCS assumes that the center of the first display + * pixel is at (0,0) but actually it is at (0.5,0.5). + */ + + wx = ct->a * sx + ct->c * sy + ct->tx; + wy = ct->b * sx + ct->d * sy + ct->ty; + + if (sz == 0) + wz = 0.0; + else { + switch (ct->zt) { + case W_LINEAR: + wz = ((sz - CMS_DATASTART) * (ct->z2 - ct->z1) / + (CMS_DATARANGE-1)) + ct->z1; + break; + default: + wz = sz; + break; + } + } + } else { + wx = sx; + wy = sy; + wz = sz; + } + + ch = ' '; + if (sz && ct->valid) { + if (ct->z1 < ct->z2) { + if (wz < (ct->z1 + 0.01)) + ch = '-'; + else if (wz > (ct->z2 - 0.01)) + ch = '+'; + } else if (ct->z1 > ct->z2) { + if (wz < (ct->z2 + 0.01)) + ch = '-'; + else if (wz > (ct->z1 - 0.01)) + ch = '+'; + } + } + sprintf (obuf, ct->format, wx + 0.005, wy + 0.005, wz, ch); +} + + +/* XIM_GETMAPPING -- Return the mapping struct for the given screen coords. + */ +static MappingPtr +xim_getMapping (xim, sx, sy, frame) +register XimDataPtr xim; +float sx, sy; /* screen (raster) pixel coordinates */ +int frame; +{ + FrameBufPtr fb = (FrameBufPtr) NULL; + MappingPtr mp = (MappingPtr) NULL; + register int j=0, i=0; + float y = xim->height - sy; + char buf[SZ_LINE]; + register map_debug = 0; + + + /* Loop through the frame buffers until we find the current one. + * The mappings aren't stored in the display fb so we need to + * search. + */ + for (j=0; j < xim->nframes; j++) { + fb = &xim->frames[j]; + + if (frame == fb->frameno) { + /* Got the right frame, now search for mappings on this + * frame which intersect the screen coords. We assume there + * are no overlapping image mappings. + */ + for (i=0; i < fb->nmaps; i++) { + mp = &fb->mapping[i]; + if (map_debug) { + printf ("%d: sx=%.2f sy=%.2f / %.2f --> ",i,sx,sy,y); + printf ("mp->dx=%d+%d=%d mp->dy=%d+%d=%d", + mp->dx, mp->dnx, mp->dx+mp->dnx, + mp->dy, mp->dny, mp->dy+mp->dny); + } + if ((sx >= mp->dx && sx <= (mp->dx + mp->dnx)) && + ( y >= mp->dy && y <= (mp->dy + mp->dny))) { + if (map_debug) printf (" YES\n"); + return (mp); + } + if (map_debug) printf (" NO\n"); + } + } + } + + return ((MappingPtr) NULL); +} + + +/* XIM_FRAMELABEL -- Return a pointer to the frame label string for the current + * frame. + */ +char * +xim_frameLabel (xim) +register XimDataPtr xim; +{ + register FrameBufPtr df_p = xim->df_p; + + sprintf (df_p->label, "[%d] %s", df_p->frameno, df_p->ctran.imtitle); + return (df_p->label); +} + + +/* WCS_UPDATE -- Load the screen WCS, if not yet validated, from the user + * wcs file, if any. + * + * File format (two lines): + * + * image title (imtool header label string)\n + * a b c d tx ty z1 z2 zt + * + * The WCS text is passed in via the data stream as a write to the subunit + * WCS and left in the buffer "wcsbuf". Mapping information is parsed + * elsewhere if needed, our only purpose here is to extract the frame WCS. + */ +static CtranPtr +wcs_update (xim, fr) +register XimDataPtr xim; +FrameBufPtr fr; +{ + register CtranPtr ct = &fr->ctran; + char buf[1024], *format; + + + /* Get the new WCS. */ + if (!ct->valid) { + fr->label[0] = '\0'; + ct->zt = W_UNITARY; + + /* Attempt to read the WCS and set up a unitary transformation + * if the information cannot be read. + */ + if (sscanf (fr->wcsbuf, "%[^\n]\n%f%f%f%f%f%f%f%f%d", + buf, &ct->a, &ct->b, &ct->c, &ct->d, &ct->tx, &ct->ty, + &ct->z1, &ct->z2, &ct->zt) < 7) { + + if (fr->wcsbuf[0]) + fprintf (stderr, "ximtool: error decoding WCS\n"); + + strncpy (ct->imtitle, "[NO WCS]\n", SZ_IMTITLE); + ct->a = ct->d = 1; + ct->b = ct->c = 0; + ct->tx = ct->ty = 0; + ct->zt = W_UNITARY; + + } else + strncpy (ct->imtitle, buf, SZ_IMTITLE); + + ct->valid++; + } + + /* Determine best format for wcs output. */ + if (ct->valid && ct->zt == W_LINEAR) { + float z1, z2, zrange; + z1 = ct->z1; + z2 = ct->z2; + zrange = (z1 > z2) ? z1 - z2 : z2 - z1; + if (zrange < 0.01 || (abs(z1) + abs(z2)) / 2.0 < 0.01) + format = " %7.2f %7.2f %9.3g%c"; + else if (zrange < 100.0 && (abs(z1) + abs(z2)) / 2.0 < 200.0) + format = " %7.2f %7.2f %7.3f%c"; + else if (zrange > 99999.0 || (abs(z1) + abs(z2)) / 2.0 > 99999.0) + format = " %7.2f %7.2f %9.3g%c"; + else + format = W_DEFFORMAT; + } else + format = " %7.2f %7.2f %7.0f%c"; + + strcpy (ct->format, format); + return (ct); +} + + +/* ADD_MAPPING -- Add a mapping for the current frame. + * + * File format (two lines): + * + * image title (imtool header label string)\n + * a b c d tx ty z1 z2 zt \n + * region_name sx sy snx sny dx dy dnx dny\n + * object_ref + * + * The WCS text is passed in via the data stream as a write to the subunit + * WCS and left in the buffer "wcsbuf". Mapping information is parsed + * elsewhere if needed, our only purpose here is to extract the frame WCS. + */ + +static void +add_mapping (xim, ctran, wcsbuf, fr) +register XimDataPtr xim; +CtranPtr ctran; +char *wcsbuf; +FrameBufPtr fr; +{ + register MappingPtr mp = &fr->mapping[fr->nmaps]; + register CtranPtr ct = &mp->ctran; + register int i, j, frame = fr->frameno; + char buf[SZ_WCSBUF], *format; + + /* Attempt to read the WCS and set up a unitary transformation + * if the information cannot be read. + */ + if (sscanf (wcsbuf, "%[^\n]\n%f%f%f%f%f%f%f%f%d", + buf, &ct->a, &ct->b, &ct->c, &ct->d, &ct->tx, &ct->ty, + &ct->z1, &ct->z2, &ct->zt) < 7) { + + if (wcsbuf[0]) + fprintf (stderr, "ximtool: error decoding WCS\n"); + + strncpy (ct->imtitle, "[NO WCS]\n", SZ_IMTITLE); + ct->a = ct->d = 1; + ct->b = ct->c = 0; + ct->tx = ct->ty = 0; + ct->zt = W_UNITARY; + } else + strncpy (ct->imtitle, buf, SZ_IMTITLE); + + ct->valid = 1; + + + /* Skip over the first two lines of WCS data. + */ + strcpy (buf, wcsbuf); + for (i=0, j=0; j < 2 && buf[i]; i++) + if (buf[i] == '\n') + j++; + + /* Attempt to read the mapping. + */ + mp->regid = (++objid[frame-1]) + (frame * 100); + mp->id = mp->regid; + mp->ref[0] = '\0'; + mp->region[0] = '\0'; + + if (sscanf (&buf[i], "%s%f%f%d%d%d%d%d%d\n%s\n", + mp->region, &mp->sx, &mp->sy, &mp->snx, &mp->sny, + &mp->dx, &mp->dy, &mp->dnx, &mp->dny, mp->ref) < 10) { + + if (!wcsbuf[0]) + fprintf (stderr, "ximtool: error decoding WCS mapping\n"); + strncpy (mp->region, "none", SZ_IMTITLE); + strncpy (mp->ref, "none", SZ_IMTITLE); + + mp->sx = 1.0; + mp->sy = 1.0; + mp->snx = xim->width; + mp->sny = xim->height; + mp->dx = 1; + mp->dy = 1; + mp->dnx = xim->width; + mp->dny = xim->height; + } + memmove (ctran, &mp->ctran, sizeof (Ctran)); + + + /* Tell the ISM to cache this mapping if we have an object ref. */ + sprintf (buf, "cache %s %d", mp->ref, mp->id); + ism_message (xim, "wcspix", buf); + sprintf (buf, "wcslist %d", mp->id); + ism_message (xim, "wcspix", buf); + + /* Send the object ref to the GUI. */ + sprintf (buf, "cache %s %d %d", mp->ref, fr->frameno, mp->id); + wcspix_message (xim, buf); + sprintf (buf, "orient %d %d %d %d", + mp->id, fr->frameno, (int)ctran->a, (int)(-1 * ctran->d)); + wcspix_message (xim, buf); + + fr->nmaps++; + + + /* Debug the mappings. */ + if (getenv("DEBUG_MAPPINGS") != NULL) print_mappings (fr); +} + + +/* PRINT_MAPPINGS -- Debug routine to print all mappings on a frame. + */ +print_mappings (fr) +FrameBufPtr fr; +{ + MappingPtr mp; + register int i; + + if (fr->nmaps == 0) printf ("No mappings for frame %d\n", fr->frameno); + for (i=0; i < fr->nmaps; i++) { + mp = &fr->mapping[i]; + printf ("Mapping %d of %d: id=%d frame=%d:\n", + i+1, fr->nmaps, mp->id, fr->frameno); + printf ("\t%s %f %f %d %d %d %d %d %d\n\t%s\n", + mp->region, mp->sx, mp->sy, mp->snx, mp->sny, + mp->dx, mp->dy, mp->dnx, mp->dny, mp->ref); + } +} + + +/* CHAN_READ -- Read exactly "n" bytes from a descriptor. + */ + +static int +chan_read (fd, vptr, nbytes) +int fd; +void *vptr; +int nbytes; +{ + char *ptr = vptr; + int nread = 0, nleft = nbytes, nb = 0; + + while (nleft > 0) { + if ( (nb = read(fd, ptr, nleft)) < 0) { + if (errno == EINTR) + nb = 0; /* and call read() again */ + else + return(-1); + } else if (nb == 0) + break; /* EOF */ + nleft -= nb; + ptr += nb; + nread += nb; + } + return (nread); /* return no. of bytes read */ +} + + +/* CHAN_WRITE -- Write exactly "n" bytes to a descriptor. + */ + +static int +chan_write (fd, vptr, nbytes) +int fd; +void *vptr; +int nbytes; +{ + char *ptr = vptr; + int nwritten = 0, nleft = nbytes, nb = 0; + + while (nleft > 0) { + if ( (nb = write(fd, ptr, nleft)) <= 0) { + if (errno == EINTR) + nb = 0; /* and call write() again */ + else + return(-1); /* error */ + } + nleft -= nb; + ptr += nb; + nwritten += nb; + } + return (nwritten); +} |