aboutsummaryrefslogtreecommitdiff
path: root/unix/gdev
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
commitfa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch)
treebdda434976bc09c864f2e4fa6f16ba1952b1e555 /unix/gdev
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'unix/gdev')
-rw-r--r--unix/gdev/README126
-rw-r--r--unix/gdev/iism70/README18
-rw-r--r--unix/gdev/iism70/m70.h27
-rw-r--r--unix/gdev/iism70/mkpkg15
-rw-r--r--unix/gdev/iism70/zclm70.x12
-rw-r--r--unix/gdev/iism70/zopm70.x14
-rw-r--r--unix/gdev/iism70/zrdm70.x14
-rw-r--r--unix/gdev/iism70/zstm70.x28
-rw-r--r--unix/gdev/iism70/zwrm70.x14
-rw-r--r--unix/gdev/iism70/zwtm70.x13
-rw-r--r--unix/gdev/iism75/README24
-rw-r--r--unix/gdev/iism75/iis.h106
-rw-r--r--unix/gdev/iism75/m75.h28
-rw-r--r--unix/gdev/iism75/m75put.x160
-rw-r--r--unix/gdev/iism75/mkpkg18
-rw-r--r--unix/gdev/iism75/zclm75.x19
-rw-r--r--unix/gdev/iism75/zopm75.x32
-rw-r--r--unix/gdev/iism75/zrdm75.x163
-rw-r--r--unix/gdev/iism75/zstm75.x28
-rw-r--r--unix/gdev/iism75/zwrm75.x76
-rw-r--r--unix/gdev/iism75/zwtm75.x29
-rw-r--r--unix/gdev/iism75/zzrdii.x17
-rw-r--r--unix/gdev/iism75/zzwrii.x17
-rw-r--r--unix/gdev/m70vms/README68
-rw-r--r--unix/gdev/m70vms/fcbu.inc6
-rw-r--r--unix/gdev/m70vms/m70.h30
-rw-r--r--unix/gdev/m70vms/m70cls.f26
-rw-r--r--unix/gdev/m70vms/m70get.f43
-rw-r--r--unix/gdev/m70vms/m70io.f75
-rw-r--r--unix/gdev/m70vms/m70mcl.f35
-rw-r--r--unix/gdev/m70vms/m70opn.f41
-rw-r--r--unix/gdev/m70vms/m70rel.f19
-rw-r--r--unix/gdev/m70vms/m70wt.f44
-rw-r--r--unix/gdev/m70vms/m70wti.f46
-rw-r--r--unix/gdev/m70vms/mkpkg29
-rw-r--r--unix/gdev/m70vms/zclm70.x24
-rw-r--r--unix/gdev/m70vms/zopm70.x59
-rw-r--r--unix/gdev/m70vms/zrdm70.x36
-rw-r--r--unix/gdev/m70vms/zstm70.x28
-rw-r--r--unix/gdev/m70vms/zwrm70.x36
-rw-r--r--unix/gdev/m70vms/zwtm70.x44
-rw-r--r--unix/gdev/mkpkg12
-rw-r--r--unix/gdev/mkpkg.sh3
-rw-r--r--unix/gdev/sgidev/README24
-rw-r--r--unix/gdev/sgidev/README.gif438
-rw-r--r--unix/gdev/sgidev/mkpkg9
-rw-r--r--unix/gdev/sgidev/mkpkg.sh60
-rw-r--r--unix/gdev/sgidev/sgi2gif.c731
-rw-r--r--unix/gdev/sgidev/sgi2svg.c245
-rw-r--r--unix/gdev/sgidev/sgi2uapl.c545
-rw-r--r--unix/gdev/sgidev/sgi2ueps.c530
-rw-r--r--unix/gdev/sgidev/sgi2uhpgl.c160
-rw-r--r--unix/gdev/sgidev/sgi2uhplj.c223
-rw-r--r--unix/gdev/sgidev/sgi2uimp.c341
-rw-r--r--unix/gdev/sgidev/sgi2uptx.c61
-rw-r--r--unix/gdev/sgidev/sgi2uqms.c296
-rw-r--r--unix/gdev/sgidev/sgi2xbm.c135
-rw-r--r--unix/gdev/sgidev/sgiUtil.c132
-rw-r--r--unix/gdev/sgidev/sgiUtil.h10
-rw-r--r--unix/gdev/sgidev/sgidispatch.c70
-rw-r--r--unix/gdev/zfiogd.x420
61 files changed, 6132 insertions, 0 deletions
diff --git a/unix/gdev/README b/unix/gdev/README
new file mode 100644
index 00000000..235194cb
--- /dev/null
+++ b/unix/gdev/README
@@ -0,0 +1,126 @@
+ZFIOGD -- FIO device driver for binary graphics devices.
+ Note: this code is part of library LIBSYS.
+
+The purpose of this driver is to provide a low level i/o interface to the
+interactive binary graphics devices supported on a particular system. This
+includes devices such as image displays and bit mapped vector graphics devices
+(e.g., the Versatec plotters). The ZFIOGD driver is not intended for graphics
+devices with a text interface, e.g., the Tektronix compatible graphics
+terminals. A third interface, i.e., the ZFIOPL driver, is used for devices
+accessed via the NCAR system plot package.
+
+By using a ZFIO level driver to talk to the binary graphics devices we can
+isolate the system dependencies of the interface to a small amount of code.
+We gain the ability to access the device over the network, since the kernel
+server can be used once the i/o interface to the device is part of the kernel.
+
+The ZFIOGD driver is implemented in LIBSYS rather than LIBOS since the
+interface code, while system dependent, is generally written at least partially
+in SPP to access header files shared with the GIO graphics kernel for the
+device, as well as to gain access to the LIBSYS library functions for ease
+of coding. ZFIOGD is used only by the graphics kernels hence is not needed
+to bootstrap the system; it is added to LIBSYS after the system is up and
+running.
+
+The code is made as follows:
+
+ [1] In a bootstrap, the commands in the mkpkg.csh file are executed by
+ the root mkpkg.csh file in host$.
+
+ [2] In a sysgen, the mkpkg file in this directory is called by an entry
+ in sys$mkpkg to to update the libsys.a library.
+
+
+ARCHITECTURE
+
+ The single FIO device driver ZFIOGD is used to access all binary graphics
+devices. This simplifies the KI and VOS interfaces and maximally isolates
+knowledge of the devices supported on a particular system. New devices can
+be added to ZFIOGD without any changes to the kernel interface or the VOS.
+When a device is opened via the ZFIOGD driver the name of the device is
+specified as follows:
+
+ node!device:hostdevname
+e.g.,
+ lyra!iis,/dev/iis
+ vela!iis,iia0
+
+where
+ device identifies the bottom level driver to be used
+
+ hostdevname is the host system name for the particular
+ device to be accessed (there may be
+ multiple copies of a device on a single
+ system)
+
+The task of ZOPNGD is to look up device name in an internal table and call
+the appropriate lower level device open procedure to physically open the
+device. If the device resides on a remote node the kernel interface will
+have have spawned a remote kernel server which will call ZOPNGD on the host
+which actually owns the device.
+
+
+ ZFIOGD
+
+
+ iism7X deanza peritek versatec (etc.)
+
+
+The ZFIOGD interface is a data driven interface, i.e., all control and status
+readback functions are performed by ZARDGD and ZAWRGD calls to read and write
+binary packets of data. This is ideal for a device such as the IIS which is
+also data driven, but is less convenient for devices which have a control
+type interface (in a control type interface, a subroutine is called to do
+something to the device, rather than writing to the device). Even when the
+device is control driven at the host system level, a data driven interface is
+desirable to isolate the system dependence of the OS device driver, as well
+as to provide network access.
+
+
+PROTOCOLS
+
+ When building a ZFIOGD sub-driver for a control driven device, it is
+suggested that a control packet be defined for the device which is capable
+of encoding all control functions. The high level code (GIO graphics device
+driver) will encode control functions in this packet (which should have a
+machine independent external representation), and send it along via ZAWRGD
+to the sub-kernel, which will decode the packet and poke the host system device
+driver as necessary to perform the indicated function.
+
+There is no predefined protocol for encoding control packets for binary
+graphics devices. Conceivably such an interface could be defined, but our
+goal with the ZFIOGD interface is to isolate the host system dependence of
+the interface and provide network access capabilities; we are NOT trying to
+address the problems of device independence in this interface. That is the
+function of the GIO device driver, which should be machine independent and
+portable, but addresses the problems of providing a device independent
+interface.
+
+A control packet and communications protocol should therefore be defined
+separately for each device. One possibility is to use the OFFSET argument
+in the ZAWRGD call as a function code, rather than placing the function code
+in a generic packet header. This is possible since the OFFSET argument is not
+used for streaming devices. The only disadvantage to using the OFFSET field
+in this way is that doing so would prevent use of FIO to buffer i/o to the
+device, since FIO always sets OFFSET to zero when calling ZAWRGD for a
+streaming device. The alternative is the generic packet approach, wherein
+each i/o or control operation is preceded by a packet defining the operation
+to be performed (this can simplify the interface, since a single set of
+subroutines can be used to encode/transmit and receive/decode packet headers).
+Yet another possibilty is to combine the two approaches, using a generic
+packet header for most operations, but a special "offset" or function code
+for special operations such as master clear or device reset (as well as to
+reset the communications protocol).
+
+See the send/receive procedures in the KI (kernel interface) for an example
+of how to encode packets in a machine independent form for transmission over
+the network.
+
+
+ADDING NEW DEVICES
+
+ To add a new device to ZFIOGD, create a subdirectory with the name of the
+device and implement the six driver subroutines therein. Add an entry to the
+mkpkg to compile the new subdirectory. Add a new entry to the device table
+and to each switch-case statement in zfiogd.x. Relink all affected graphics
+executables, and relink the kernel server executable.
diff --git a/unix/gdev/iism70/README b/unix/gdev/iism70/README
new file mode 100644
index 00000000..8023068b
--- /dev/null
+++ b/unix/gdev/iism70/README
@@ -0,0 +1,18 @@
+UNIX IRAF/FIO device driver for the IIS Model 70
+(will probably also work for the model 75). 11/85 dct
+----------------------------------------------------------------------
+
+This directory contains the IRAF/FIO driver subroutines for the IIS Model 70
+image display on UNIX. On a UNIX system the ZIFOBF (binary file) driver is
+used to access the display, hence the subroutines herein merely map the calls
+into the corresponding BF procedures.
+
+
+Driver Procedures:
+
+ zopm70 -- open + allocate
+ zclm70 -- close + deallocate
+ zrdm70 -- asynchronous binary read
+ zwrm70 -- asynchronous binary write
+ zwtm70 -- wait for i/o completion, return status
+ zstm70 -- get device status
diff --git a/unix/gdev/iism70/m70.h b/unix/gdev/iism70/m70.h
new file mode 100644
index 00000000..6a1a7d28
--- /dev/null
+++ b/unix/gdev/iism70/m70.h
@@ -0,0 +1,27 @@
+# Definitions for the VMS/IIS device driver.
+
+define IIS_READ 1 # read function code
+define IIS_WRITE 0 # write function code
+define IIS_INACTIVE -1 # no i/o in progress
+
+define EFN EFN2 # EFN to use for i/o
+define EFN1W 0 # efn #1, wait for completion
+define EFN2 1 # efn #2, no wait for completion
+define EFN3 2 # efn #3, no wait for completion
+
+# Function control block structure for IIS. The first part of the structure
+# is filled in by VMS at open time; all we need to know is the offset of the
+# device name. We use the latter part of the buffer
+
+define LEN_FCB 30
+define FCB_U_NAME (P2S($1)+16+($2)-1)
+define FCB_STATUS Memi[$1+20] # channel status (r, w, err)
+define FCB_NBYTES Memi[$1+21] # nbytes last transfer
+define FCB_EFN Memi[$1+22] # event flag used for transfer
+
+# IIS device status words.
+
+define IIS_FILSIZE (512 * 512 * SZB_CHAR)
+define IIS_BLKSIZE 1024
+define IIS_OPTBUFSIZE (512 * SZB_CHAR)
+define IIS_MAXBUFSIZE 32768
diff --git a/unix/gdev/iism70/mkpkg b/unix/gdev/iism70/mkpkg
new file mode 100644
index 00000000..57b920c5
--- /dev/null
+++ b/unix/gdev/iism70/mkpkg
@@ -0,0 +1,15 @@
+# Make the UNIX version of the IIS driver.
+
+$checkout libsys.a lib$
+$update libsys.a
+$checkin libsys.a lib$
+$exit
+
+libsys.a:
+ zclm70.x
+ zopm70.x
+ zrdm70.x
+ zstm70.x m70.h <fio.h> <mach.h>
+ zwrm70.x
+ zwtm70.x
+ ;
diff --git a/unix/gdev/iism70/zclm70.x b/unix/gdev/iism70/zclm70.x
new file mode 100644
index 00000000..719bc727
--- /dev/null
+++ b/unix/gdev/iism70/zclm70.x
@@ -0,0 +1,12 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# ZCLM70 -- Close and deallocate the IIS.
+
+procedure zclm70 (chan, status)
+
+int chan
+int status
+
+begin
+ call zclsbf (chan, status)
+end
diff --git a/unix/gdev/iism70/zopm70.x b/unix/gdev/iism70/zopm70.x
new file mode 100644
index 00000000..5c49d506
--- /dev/null
+++ b/unix/gdev/iism70/zopm70.x
@@ -0,0 +1,14 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# ZOPM70 -- Open the IIS for binary file i/o. The device will be automatically
+# allocated if necessary.
+
+procedure zopm70 (device, mode, chan)
+
+char device[ARB] # packed UNIX device name
+int mode # access mode
+int chan # receives device channel
+
+begin
+ call zopnbf (device, mode, chan)
+end
diff --git a/unix/gdev/iism70/zrdm70.x b/unix/gdev/iism70/zrdm70.x
new file mode 100644
index 00000000..f3ef3f2a
--- /dev/null
+++ b/unix/gdev/iism70/zrdm70.x
@@ -0,0 +1,14 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# ZRDM70 -- Initiate an asynchronous read from the IIS.
+
+procedure zrdm70 (chan, buf, nbytes, offset)
+
+int chan # FCB pointer for device
+char buf[ARB] # output buffer
+int nbytes # number of bytes to read
+long offset # not used for this device
+
+begin
+ call zardbf (chan, buf, nbytes, offset)
+end
diff --git a/unix/gdev/iism70/zstm70.x b/unix/gdev/iism70/zstm70.x
new file mode 100644
index 00000000..2b790dfa
--- /dev/null
+++ b/unix/gdev/iism70/zstm70.x
@@ -0,0 +1,28 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <fio.h>
+include "m70.h"
+
+# ZSTM70 -- Return device status for the IIS.
+
+procedure zstm70 (chan, what, lvalue)
+
+int chan # FCB pointer for device
+int what # status parameter
+long lvalue
+
+begin
+ switch (what) {
+ case FSTT_FILSIZE:
+ lvalue = IIS_FILSIZE
+ case FSTT_BLKSIZE:
+ lvalue = IIS_BLKSIZE
+ case FSTT_OPTBUFSIZE:
+ lvalue = IIS_OPTBUFSIZE
+ case FSTT_MAXBUFSIZE:
+ lvalue = IIS_MAXBUFSIZE
+ default:
+ lvalue = ERR
+ }
+end
diff --git a/unix/gdev/iism70/zwrm70.x b/unix/gdev/iism70/zwrm70.x
new file mode 100644
index 00000000..10545f99
--- /dev/null
+++ b/unix/gdev/iism70/zwrm70.x
@@ -0,0 +1,14 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# ZWRM70 -- Initiate an asynchronous write to the IIS.
+
+procedure zwrm70 (chan, buf, nbytes, offset)
+
+int chan # FCB pointer for device
+char buf[ARB] # input buffer
+int nbytes # number of bytes to write
+long offset # not used for this device
+
+begin
+ call zawrbf (chan, buf, nbytes, offset)
+end
diff --git a/unix/gdev/iism70/zwtm70.x b/unix/gdev/iism70/zwtm70.x
new file mode 100644
index 00000000..b2523c31
--- /dev/null
+++ b/unix/gdev/iism70/zwtm70.x
@@ -0,0 +1,13 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# ZWTM70 -- Wait for i/o completion and return the number of bytes read or
+# written or ERR. Repetitive calls return the same value.
+
+procedure zwtm70 (chan, status)
+
+int chan # FCB pointer for device
+int status # nbytes transferred or ERR
+
+begin
+ call zawtbf (chan, status)
+end
diff --git a/unix/gdev/iism75/README b/unix/gdev/iism75/README
new file mode 100644
index 00000000..60433d4d
--- /dev/null
+++ b/unix/gdev/iism75/README
@@ -0,0 +1,24 @@
+UNIX IRAF/FIO device driver for the IIS Model 75
+2 Feb 1896 Dct.; ported to UNIX from VMS 10 Mar 1987 SRo.
+----------------------------------------------------------------------
+
+This directory contains the IRAF/FIO driver subroutines for the IIS Model 75
+image display. This directory is self contained.
+
+The model 75 interface is implemented as a transformation on the data stream
+for the model 70. The high level code thinks that it is talking to a model
+70; we translate the headers as necessary for the model 75 before passing
+them on to the device. This approach does not provide full access to the
+capabilities of the model 75, however the existing high level code is all
+written for the model 70 and we are not at present interested in the advanced
+features of either display.
+
+
+Driver Procedures:
+
+ zopm75 -- open + allocate
+ zclm75 -- close + deallocate
+ zrdm75 -- asynchronous binary read
+ zwrm75 -- asynchronous binary write
+ zwtm75 -- wait for i/o completion, return status
+ zstm75 -- get device status
diff --git a/unix/gdev/iism75/iis.h b/unix/gdev/iism75/iis.h
new file mode 100644
index 00000000..515c0def
--- /dev/null
+++ b/unix/gdev/iism75/iis.h
@@ -0,0 +1,106 @@
+# IIS.H -- Hardware definitions for the IIS models 70 and 75.
+
+# Define header
+define LEN_IISHDR 8 # Length of IIS header
+
+define XFERID $1[1] # transfer id
+define THINGCT $1[2] # thing count
+define SUBUNIT $1[3] # subuint select
+define CHECKSUM $1[4] # check sum
+define XREG $1[5] # x register
+define YREG $1[6] # y register
+define ZREG $1[7] # z register
+define TREG $1[8] # t register
+
+# Transfer ID definitions
+define BYTEORDER 20B
+define PMA 40B
+define ACCELERATE 100B
+define REPEAT 200B
+define IREAD 100000B
+define IWRITE 000000B
+define PACKED 40000B
+define BYPASSIFM 20000B
+define PAGEMODE 10000B
+define ADDWRITE 4000B
+define ACCUM 2000B
+define BLOCKXFER 1000B
+define VRETRACE 400B
+
+define M70_BYTE 10000B
+define M70_MUX32 200B
+
+# Subunits
+define REFRESH 1
+define LUT 2
+define OFM 3
+define IFM 4
+define FEEDBACK 5
+define SCROLLZOOM 6
+define VIDEOM 7
+define SUMPROC 8
+define GRAPHICS 9
+define CURSOR 10
+define ALU 11
+
+define M70_SCROLL 6
+define M70_ZOOM 12
+
+# Command definitions
+define COMMAND 100000B
+define ERASE 100000B # Erase
+
+define SCROLL 1B
+define ZOOM 10000B
+define WRAP 1000B
+
+define M70_ADVXONTC 100000B # Advance x on thing count
+define M70_ADVXONYOV 40000B # Advance x on y overflow
+define M70_ADVYONXOV 100000B # Advance y on x overflow
+define M70_ADVYONTC 40000B # Advance y on thing count
+
+define M75_ADVXONTC 400B # Advance x on thing count
+define M75_ADVXONYOV 200B # Advance x on y overflow
+define M75_ADVYONXOV 2000B # Advance y on x overflow
+define M75_ADVYONTC 4000B # Advance y on thing count
+
+# 4 - Button Trackball
+define PUSH 40000B
+define BUTTONA 400B
+define BUTTONB 1000B
+define BUTTONC 2000B
+define BUTTOND 4000B
+
+# Display channels
+define CHAN1 1B
+define CHAN2 2B
+define CHAN3 4B
+define CHAN4 10B
+define GRCHAN 100000B
+
+define LEN_IISFRAMES 4
+define IISFRAMES CHAN1, CHAN2, CHAN3, CHAN4
+
+# Colors
+define BLUE 1B
+define GREEN 2B
+define RED 4B
+define MONO 7B
+
+# Bit plane selections
+define BITPL0 1B
+define BITPL1 2B
+define BITPL2 4B
+define BITPL3 10B
+define BITPL4 20B
+define BITPL5 40B
+define BITPL6 100B
+define BITPL7 200B
+define ALLBITPL 377B
+
+# IIS Sizes
+define MCXSCALE 64 # Metacode x scale
+define MCYSCALE 64 # Metacode y scale
+define IIS_XDIM 512
+define IIS_YDIM 512
+define SZB_IISHDR 16 # Size of IIS header in bytes
diff --git a/unix/gdev/iism75/m75.h b/unix/gdev/iism75/m75.h
new file mode 100644
index 00000000..832aa423
--- /dev/null
+++ b/unix/gdev/iism75/m75.h
@@ -0,0 +1,28 @@
+# Definitions for the Model 75 UNIX/IIS device driver.
+
+define IIS_READ 1 # read function code
+define IIS_WRITE 0 # write function code
+define IIS_INACTIVE 2 # no i/o in progress
+
+# Function control block structure containing only our own internal variables.
+
+define LEN_FCB 20
+define FCB_CHAN Memi[($1)] # os channel
+define FCB_STATUS Mems[P2S(($1)+1)] # channel status (r, w, err)
+define FCB_NBYTES Mems[P2S(($1)+2)] # nbytes last transfer
+define FCB_STATE Mems[P2S(($1)+3)] # instruction processing state
+define FCB_IISHDR Mems[P2S(($1)+4)] # m70 header of current instr.
+ # (extra space)
+
+# Instruction processing states
+
+define READY 0 # ready for new instruction
+define DATA_READ 1 # read data to complete instruction
+define DATA_WRITE 2 # write data to complete instruction
+
+# IIS device status words.
+
+define IIS_FILSIZE (512 * 512 * SZB_CHAR)
+define IIS_BLKSIZE 1024
+define IIS_OPTBUFSIZE (512 * SZB_CHAR)
+define IIS_MAXBUFSIZE 16384
diff --git a/unix/gdev/iism75/m75put.x b/unix/gdev/iism75/m75put.x
new file mode 100644
index 00000000..01ca6511
--- /dev/null
+++ b/unix/gdev/iism75/m75put.x
@@ -0,0 +1,160 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "m75.h"
+include "iis.h"
+
+# M75PUT -- Translate an M70 instruction+data into an M75 instruction+data and
+# output it to the display device. We are called after both the instruction
+# header and the data (if any) have been received. The M70 header has been
+# saved in the the channel descriptor and the data, if any, is in BUF.
+
+procedure m75put (fcb, buf, nbytes_buf, offset)
+
+pointer fcb # pointer to channel descriptor
+short buf[ARB] # data array
+int nbytes_buf # nbytes of data in buffer
+long offset # not used
+
+int ifcb
+bool use_altbuf
+short altbuf[128]
+short m70[LEN_IISHDR]
+short m75[LEN_IISHDR]
+int nbytes, status, sum, i
+int xferid, subunit, xreg, yreg
+int and(), or(), not()
+
+begin
+ ifcb = fcb
+ use_altbuf = false
+
+ # Retrieve the M70 header from the channel descriptor.
+ call amovs (FCB_IISHDR(fcb), m70, LEN_IISHDR)
+
+ xferid = XFERID(m70)
+ subunit = SUBUNIT(m70)
+ xreg = XREG(m70)
+ yreg = YREG(m70)
+
+ if (THINGCT(m70) == 0)
+ nbytes = 0
+ else
+ nbytes = nbytes_buf
+
+ # Start with a copy of the header for the M75, but turn off those bits
+ # in the transfer id which the M70 knows nothing about and hence could
+ # not have set.
+
+ call amovs (m70, m75, LEN_IISHDR)
+ XFERID(m75) = and (xferid,
+ not (BYTEORDER+PMA+ACCELERATE+REPEAT+PAGEMODE))
+
+ # Translate the remaining fields of the header as necessary for each
+ # subunit.
+
+ switch (and (subunit, 77B)) {
+ case REFRESH:
+ if (and (xreg, M70_ADVXONTC) != 0)
+ subunit = or (subunit, M75_ADVXONTC)
+ if (and (xreg, M70_ADVXONYOV) != 0)
+ subunit = or (subunit, M75_ADVXONYOV)
+ if (and (yreg, M70_ADVYONTC) != 0)
+ subunit = or (subunit, M75_ADVYONTC)
+ if (and (yreg, M70_ADVYONXOV) != 0)
+ subunit = or (subunit, M75_ADVYONXOV)
+
+ SUBUNIT(m75) = subunit
+ XREG(m75) = and (xreg, IIS_XDIM-1)
+ YREG(m75) = and (yreg, IIS_YDIM-1)
+
+ case LUT:
+ XREG(m75) = and (xreg, 1777B)
+ YREG(m75) = 0
+
+ case OFM:
+ XREG(m75) = and (xreg, 1777B)
+ YREG(m75) = 0
+
+ # The M70 feeds a 10 bit output DAC while the M75 DAC is 8 bits.
+ do i = 1, nbytes_buf / (SZB_CHAR * SZ_SHORT)
+ buf[i] = buf[i] / 4
+
+ case FEEDBACK:
+ subunit = COMMAND + FEEDBACK
+ SUBUNIT(m75) = subunit
+ XREG(m75) = 0
+ YREG(m75) = 0
+
+ case GRAPHICS:
+ XREG(m75) = and (xreg, 777B)
+
+ # In a command mode transfer, the status register value is passed
+ # as data for the M70, but in the T register for the M75.
+
+ if (and (subunit, COMMAND) != 0) {
+ TREG(m75) = buf[1]
+ THINGCT(m75) = 0
+ nbytes = 0
+ }
+
+ case CURSOR:
+ XREG(m75) = and (xreg, 7777B)
+ YREG(m75) = 0
+
+ case M70_SCROLL:
+ SUBUNIT(m75) = SCROLLZOOM
+ XREG(m75) = and (xreg, 3B)
+ YREG(m75) = 0
+ ZREG(m75) = ALLBITPL
+ TREG(m75) = SCROLL + WRAP
+
+ case M70_ZOOM:
+ SUBUNIT(m75) = SCROLLZOOM
+ THINGCT(m75) = 2
+ XREG(m75) = and (xreg, 3B)
+ YREG(m75) = 0
+ ZREG(m75) = ALLBITPL
+ TREG(m75) = ZOOM + SCROLL + WRAP
+
+ # There are up to 3 words of data for the M70: zoom factor,
+ # x center, y center. For the M75 the zoom is specified
+ # separately for each axis in the high bits of the word which
+ # contains the axis center. For simplicity we require that
+ # all 3 words always be given.
+
+ altbuf[1] = buf[1] * 10000B + buf[2]
+ altbuf[2] = buf[1] * 10000B + buf[3]
+ use_altbuf = true
+ nbytes = 2 * (SZ_SHORT * SZB_CHAR)
+ }
+
+ # Compute the checksum for the new header.
+
+ CHECKSUM(m75) = 1
+ if (THINGCT(m75) > 0)
+ THINGCT(m75) = -THINGCT(m75)
+
+ sum = 0
+ do i = 1, LEN_IISHDR
+ sum = sum + m75[i]
+
+ CHECKSUM(m75) = -sum
+
+ # Output the header.
+
+ call zzwrii (fcb, m75, SZB_IISHDR, offset)
+ call zwtm75 (ifcb, status)
+ if (status == ERR) {
+ FCB_STATUS(fcb) = ERR
+ return
+ }
+
+ # Output the data block, if any.
+
+ if (nbytes > 0)
+ if (use_altbuf)
+ call zzwrii (fcb, altbuf, nbytes, offset)
+ else
+ call zzwrii (fcb, buf, nbytes, offset)
+end
diff --git a/unix/gdev/iism75/mkpkg b/unix/gdev/iism75/mkpkg
new file mode 100644
index 00000000..97387aec
--- /dev/null
+++ b/unix/gdev/iism75/mkpkg
@@ -0,0 +1,18 @@
+# Mkpkg for the UNIX version of the IIS driver.
+
+$checkout libsys.a lib$
+$update libsys.a
+$checkin libsys.a lib$
+$exit
+
+libsys.a:
+ m75put.x iis.h m75.h <mach.h>
+ zclm75.x m75.h <mach.h>
+ zopm75.x m75.h <mach.h>
+ zrdm75.x iis.h m75.h <mach.h>
+ zstm75.x m75.h <fio.h> <mach.h>
+ zwrm75.x iis.h m75.h <mach.h>
+ zwtm75.x m75.h <mach.h>
+ zzrdii.x m75.h <mach.h>
+ zzwrii.x m75.h <mach.h>
+ ;
diff --git a/unix/gdev/iism75/zclm75.x b/unix/gdev/iism75/zclm75.x
new file mode 100644
index 00000000..989358d9
--- /dev/null
+++ b/unix/gdev/iism75/zclm75.x
@@ -0,0 +1,19 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "m75.h"
+
+# ZCLM75 -- Close and deallocate the IIS.
+
+procedure zclm75 (ifcb, status)
+
+int ifcb # pointer to channel descriptor passed as int
+int status
+pointer fcb
+
+begin
+ fcb = ifcb
+ call zclsbf (FCB_CHAN(fcb), status)
+
+ call mfree (fcb, TY_STRUCT)
+end
diff --git a/unix/gdev/iism75/zopm75.x b/unix/gdev/iism75/zopm75.x
new file mode 100644
index 00000000..33a9acf8
--- /dev/null
+++ b/unix/gdev/iism75/zopm75.x
@@ -0,0 +1,32 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "m75.h"
+
+# ZOPM75 -- Open the IIS for binary file i/o.
+
+procedure zopm75 (device, mode, ifcb)
+
+char device[ARB] # packed UNIX device name
+int mode # access mode
+int ifcb # pointer to channel descriptor passed as int
+
+pointer fcb
+int chan
+
+begin
+ call calloc (fcb, LEN_FCB, TY_STRUCT)
+ ifcb = fcb
+
+ FCB_STATUS(fcb) = IIS_INACTIVE
+ FCB_NBYTES(fcb) = 0
+ FCB_STATE(fcb) = READY
+
+ call zopnbf (device, mode, chan)
+
+ if (chan < 0) {
+ call mfree (fcb, TY_STRUCT)
+ ifcb = ERR
+ } else
+ FCB_CHAN(fcb) = chan
+end
diff --git a/unix/gdev/iism75/zrdm75.x b/unix/gdev/iism75/zrdm75.x
new file mode 100644
index 00000000..9cc2498d
--- /dev/null
+++ b/unix/gdev/iism75/zrdm75.x
@@ -0,0 +1,163 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "m75.h"
+include "iis.h"
+
+# ZRDM75 -- Initiate an asynchronous read of data from the IIS. Note that
+# the zwrm75 procedure is called to write the header for data reads, as well
+# as writes. Hence we should be called only after the header has been saved
+# in the channel descriptor by ZWRM75, leaving the channel in state DATA_READ.
+# Our task is to translate and output the header, read the M75 data block, and
+# return the data block to the user after performing any transformations
+# necessary to make it look like M70fdata.
+
+procedure zrdm75 (ifcb, buf, nbytes_buf, offset)
+
+int ifcb # pointer to channel descriptor passed as int
+short buf[ARB] # data array
+int nbytes_buf # nbytes of data in buffer
+long offset # not used
+
+pointer fcb
+short m70[LEN_IISHDR]
+short m75[LEN_IISHDR]
+int nbytes, status, sum, i
+int xferid, subunit, xreg, yreg
+int and(), or(), not()
+
+begin
+ fcb = ifcb
+ nbytes = nbytes_buf
+
+ if (FCB_STATE(fcb) != DATA_READ) {
+ FCB_STATUS(fcb) = ERR
+ return
+ }
+
+ # Retrieve the M70 header from the channel descriptor.
+ call amovs (FCB_IISHDR(fcb), m70, LEN_IISHDR)
+
+ xferid = XFERID(m70)
+ subunit = SUBUNIT(m70)
+ xreg = XREG(m70)
+ yreg = YREG(m70)
+
+ # Start with a copy of the header for the M75, but turn off those bits
+ # in the transfer id which the M70 knows nothing about and hence could
+ # not have set.
+
+ call amovs (m70, m75, LEN_IISHDR)
+ XFERID(m75) = and (xferid,
+ not (BYTEORDER+PMA+ACCELERATE+REPEAT+PAGEMODE))
+
+ # Translate the remaining fields of the header as necessary for each
+ # subunit.
+
+ switch (and (subunit, 77B)) {
+ case REFRESH:
+ if (and (xreg, M70_ADVXONTC) != 0)
+ subunit = or (subunit, M75_ADVXONTC)
+ if (and (xreg, M70_ADVXONYOV) != 0)
+ subunit = or (subunit, M75_ADVXONYOV)
+ if (and (yreg, M70_ADVYONTC) != 0)
+ subunit = or (subunit, M75_ADVYONTC)
+ if (and (yreg, M70_ADVYONXOV) != 0)
+ subunit = or (subunit, M75_ADVYONXOV)
+
+ SUBUNIT(m75) = subunit
+ XREG(m75) = and (xreg, IIS_XDIM-1)
+ YREG(m75) = and (yreg, IIS_YDIM-1)
+
+ case LUT:
+ XREG(m75) = and (xreg, 1777B)
+ YREG(m75) = 0
+
+ case OFM:
+ XREG(m75) = and (xreg, 1777B)
+ YREG(m75) = 0
+
+ # The M70 OFM lookup table is 10 bits deep, whereas the M75 table
+ # is only 8 bits deep, so scale the 8 bit M75 values up to 10 bits.
+
+ do i = 1, nbytes_buf / (SZB_CHAR * SZ_SHORT)
+ buf[i] = buf[i] * 4
+
+ case FEEDBACK:
+ subunit = COMMAND + FEEDBACK
+ SUBUNIT(m75) = subunit
+ XREG(m75) = 0
+ YREG(m75) = 0
+
+ case GRAPHICS:
+ XREG(m75) = and (xreg, 777B)
+ TREG(m75) = 0 # ??
+
+ case CURSOR:
+ XREG(m75) = and (xreg, 7777B)
+ YREG(m75) = 0
+
+ case M70_SCROLL:
+ SUBUNIT(m75) = SCROLLZOOM
+ XREG(m75) = and (xreg, 3B)
+ YREG(m75) = 0
+ ZREG(m75) = ALLBITPL
+ TREG(m75) = SCROLL + WRAP
+
+ case M70_ZOOM:
+ SUBUNIT(m75) = SCROLLZOOM
+ THINGCT(m75) = 2
+ nbytes = 2 * (SZ_SHORT * SZB_CHAR)
+ XREG(m75) = and (xreg, 3B)
+ YREG(m75) = 0
+ ZREG(m75) = ALLBITPL
+ TREG(m75) = ZOOM
+ }
+
+ # Compute the checksum for the new header.
+
+ CHECKSUM(m75) = 1
+ if (THINGCT(m75) > 0)
+ THINGCT(m75) = -THINGCT(m75)
+
+ sum = 0
+ do i = 1, LEN_IISHDR
+ sum = sum + m75[i]
+
+ CHECKSUM(m75) = -sum
+
+ # Output the header.
+
+ call zzwrii (fcb, m75, SZB_IISHDR, offset)
+ call zwtm75 (ifcb, status)
+ if (status == ERR) {
+ FCB_STATUS(fcb) = ERR
+ return
+ }
+
+ # Read the data block.
+
+ if (nbytes > 0) {
+ call zzrdii (fcb, buf, nbytes, offset)
+ call zwtm75 (ifcb, status)
+ if (status <= 0) {
+ FCB_STATUS(fcb) = ERR
+ return
+ }
+ }
+
+ # Perform any transformations on the data just read necessary to
+ # convert it into M70 format. If the number of bytes read is
+ # different than that expected by the M70, be sure to set the
+ # expected count in the channel descriptor for the next ZWTM75.
+
+ if (and (subunit, 77B) == ZOOM) {
+ FCB_NBYTES(fcb) = 3 * (SZ_SHORT * SZB_CHAR)
+ FCB_STATUS(fcb) = IIS_INACTIVE
+ buf[3] = mod (int(buf[2]), 10000B)
+ buf[2] = mod (int(buf[1]), 10000B)
+ buf[1] = buf[1] / 10000B
+ }
+
+ FCB_STATE(fcb) = READY
+end
diff --git a/unix/gdev/iism75/zstm75.x b/unix/gdev/iism75/zstm75.x
new file mode 100644
index 00000000..b1e9923c
--- /dev/null
+++ b/unix/gdev/iism75/zstm75.x
@@ -0,0 +1,28 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <fio.h>
+include "m75.h"
+
+# ZSTM75 -- Return device status for the IIS.
+
+procedure zstm75 (ifcb, what, lvalue)
+
+int ifcb # pointer to channel descriptor passed as int
+int what # status parameter
+long lvalue
+
+begin
+ switch (what) {
+ case FSTT_FILSIZE:
+ lvalue = IIS_FILSIZE
+ case FSTT_BLKSIZE:
+ lvalue = IIS_BLKSIZE
+ case FSTT_OPTBUFSIZE:
+ lvalue = IIS_OPTBUFSIZE
+ case FSTT_MAXBUFSIZE:
+ lvalue = IIS_MAXBUFSIZE
+ default:
+ lvalue = ERR
+ }
+end
diff --git a/unix/gdev/iism75/zwrm75.x b/unix/gdev/iism75/zwrm75.x
new file mode 100644
index 00000000..38bb0f3c
--- /dev/null
+++ b/unix/gdev/iism75/zwrm75.x
@@ -0,0 +1,76 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "m75.h"
+include "iis.h"
+
+# ZWRM75 -- Initiate an asynchronous write to the IIS. We are called to
+# output the header of all instructions sent to the IIS. There are 3 types
+# of instructions; those which consist only of a header write, those which
+# consist of a header write followed by a data write, and those which
+# consist of a header write followed by a data read. Translation of an M70
+# instruction into an M75 instruction may involve moving information between
+# the header and data block, hence we must save the headers of the read and
+# write instructions until the data has been read or written. The STATE
+# variable in the channel descriptor is used to keep track of the instruction
+# processing state.
+
+procedure zwrm75 (ifcb, buf, nbytes, offset)
+
+int ifcb # pointer to channel descriptor passed as int
+char buf[ARB] # input buffer
+int nbytes # number of bytes to write
+long offset # not used for this device
+
+pointer fcb
+int xferid, and()
+
+begin
+ fcb = ifcb
+
+ if (FCB_STATE(fcb) == READY) {
+ # Start a new instruction.
+
+ if (nbytes != SZB_IISHDR) {
+ FCB_STATUS(fcb) = ERR
+ return
+ }
+
+ # Save the M70 header in the descriptor.
+ call amovs (buf, FCB_IISHDR(fcb), LEN_IISHDR)
+ xferid = XFERID(buf)
+
+ # Determine the state for the new instruction.
+
+ if (THINGCT(buf) == 0)
+ FCB_STATE(fcb) = READY
+ else if (and (xferid, IREAD) != 0)
+ FCB_STATE(fcb) = DATA_READ
+ else
+ FCB_STATE(fcb) = DATA_WRITE
+
+ # If the new state is READY, no data read or write is needed,
+ # so just translate and output the header.
+
+ if (FCB_STATE(fcb) == READY)
+ call m75put (fcb, buf, nbytes, offset)
+ else {
+ # Set up a channel status as if we had just written the new
+ # header, so that the next ZWTM75 will not return an error.
+
+ FCB_STATUS(fcb) = IIS_INACTIVE
+ FCB_NBYTES(fcb) = SZB_IISHDR
+ }
+
+ } else if (FCB_STATE(fcb) == DATA_WRITE) {
+ # This is the second zwrm75 call for a hdr+data output
+ # instruction.
+
+ call m75put (fcb, buf, nbytes, offset)
+ FCB_STATE(fcb) = READY
+
+ } else {
+ # ZRDM75 should have been called, set error on the channel.
+ FCB_STATUS(fcb) = ERR
+ }
+end
diff --git a/unix/gdev/iism75/zwtm75.x b/unix/gdev/iism75/zwtm75.x
new file mode 100644
index 00000000..491b0f50
--- /dev/null
+++ b/unix/gdev/iism75/zwtm75.x
@@ -0,0 +1,29 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "m75.h"
+
+# ZWTM75 -- Wait for i/o completion and return the number of bytes read or
+# written or ERR. Repetitive calls return the same value.
+
+procedure zwtm75 (ifcb, status)
+
+int ifcb # pointer to channel descriptor passed as int
+int status # nbytes transferred or ERR
+
+pointer fcb
+
+begin
+ fcb = ifcb
+
+ switch (FCB_STATUS(fcb)) {
+ case ERR:
+ status = ERR
+ case IIS_INACTIVE:
+ status = FCB_NBYTES(fcb)
+
+ default:
+ call zawtbf (FCB_CHAN(fcb), status)
+ FCB_STATUS(fcb) = IIS_INACTIVE
+ }
+end
diff --git a/unix/gdev/iism75/zzrdii.x b/unix/gdev/iism75/zzrdii.x
new file mode 100644
index 00000000..f72058c3
--- /dev/null
+++ b/unix/gdev/iism75/zzrdii.x
@@ -0,0 +1,17 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "m75.h"
+
+# ZZRDII -- Initiate an asynchronous read from the IIS.
+
+procedure zzrdii (fcb, buf, nbytes, offset)
+
+pointer fcb # pointer to channel descriptor
+char buf[ARB] # output buffer
+int nbytes # number of bytes to read
+long offset # not used for this device
+
+begin
+ call zardbf (FCB_CHAN(fcb), buf, nbytes, offset)
+end
diff --git a/unix/gdev/iism75/zzwrii.x b/unix/gdev/iism75/zzwrii.x
new file mode 100644
index 00000000..8515cc64
--- /dev/null
+++ b/unix/gdev/iism75/zzwrii.x
@@ -0,0 +1,17 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "m75.h"
+
+# ZZWRII -- Initiate an asynchronous write to the IIS.
+
+procedure zzwrii (fcb, buf, nbytes, offset)
+
+pointer fcb # pointer to channel descriptor
+char buf[ARB] # input buffer
+int nbytes # number of bytes to write
+long offset # not used for this device
+
+begin
+ call zawrbf (FCB_CHAN(fcb), buf, nbytes, offset)
+end
diff --git a/unix/gdev/m70vms/README b/unix/gdev/m70vms/README
new file mode 100644
index 00000000..23a06824
--- /dev/null
+++ b/unix/gdev/m70vms/README
@@ -0,0 +1,68 @@
+VMS IRAF/FIO device driver for the IIS Model 70
+(will probably also work for the model 75). 11/85 dct
+----------------------------------------------------------------------
+
+This directory contains the IRAF/FIO driver subroutines for the IIS Model 70
+image display on VMS. This directory is self contained; no external code is
+required other than the VMS/IIS device driver itself. The code should be
+portable to any VMS system.
+
+
+Driver Procedures:
+
+ zopm70 -- open + allocate
+ zclm70 -- close + deallocate
+ zrdm70 -- asynchronous binary read
+ zwrm70 -- asynchronous binary write
+ zwtm70 -- wait for i/o completion, return status
+ zstm70 -- get device status
+
+
+On a UNIX system the ordinary binary file driver (ZFIOBF) may be used for these
+functions. This might work on VMS too, but the IRAF/VMS binary file driver is
+complicated and uses RMS, so I did not bother to try. This driver uses a
+modified version local KPNO IIS library, which I suppose came originally from
+IIS corp. The interface procedures are written in VMS Fortran and make direct
+calls to the VMS system services. The original library has been modified to
+convert all the names to the prefix "m70", and to remove all Fortran i/o.
+
+
+VMS/IIS Interface Procedures:
+
+ m70get (fcb, error) # open+allocate+mclear
+ m70rel (fcb) # close+deallocate
+ m70opn (fcb, error) # open
+ m70cls (fcb) # close
+ m70mcl (fcb, error) # master clear
+
+ m70io (fcb, data, count, read, opcd, iosb, error)
+ m70wt (fcb, bfnum, bfcnt, iosb, error)
+ m70wti (fcb, func, time, button, x, y)
+
+
+M70IO: I/O between M70 and a VAX.
+
+ fcb function communications block.
+ data input/output buffer.
+ count number of words to read/write.
+ read 0 -> write, 1 -> read.
+ opcd :: 0 -> qio with efn = 1 and wait for completion
+ 1 -> qio with efn = 2
+ 2 -> qio with efn = 3
+ iosb I/O status quadword
+ error :: -1 => display not available
+ 0 => success
+ 1 => time/out
+ 2 => invalid or non-responding device
+ 1000 > machine dependent error code
+
+
+M70WT: Wait for i/o.
+
+ fcb function communication block.
+ bfnum used to determine event flag to wait for
+ bfcnt number of words in buffer. should be -1 indicating
+ i/o pending. reset to zero when i/o completed.
+ iosb i/o status block
+ error 0 success, -1 not acquired, 1 timeout,
+ 2 invalid device, 1000+n system dep. error
diff --git a/unix/gdev/m70vms/fcbu.inc b/unix/gdev/m70vms/fcbu.inc
new file mode 100644
index 00000000..54f23244
--- /dev/null
+++ b/unix/gdev/m70vms/fcbu.inc
@@ -0,0 +1,6 @@
+c
+c vax offsets for display.for and termio.for
+c
+ parameter fcb_u_spool = 21
+ parameter fcb_u_m70_chan = 19
+ parameter fcb_u_m70_name = 17
diff --git a/unix/gdev/m70vms/m70.h b/unix/gdev/m70vms/m70.h
new file mode 100644
index 00000000..16b4c938
--- /dev/null
+++ b/unix/gdev/m70vms/m70.h
@@ -0,0 +1,30 @@
+# Definitions for the VMS/IIS device driver.
+
+define IIS_READ 1 # read function code
+define IIS_WRITE 0 # write function code
+define IIS_INACTIVE 2 # no i/o in progress
+
+define EFN EFN2 # EFN to use for i/o
+define EFN1W 0 # efn #1, wait for completion
+define EFN2 1 # efn #2, no wait for completion
+define EFN3 2 # efn #3, no wait for completion
+
+# Function control block structure for IIS. The first part of the structure
+# is filled in by VMS at open time; all we need to know is the offset of the
+# device name. We use the latter part of the buffer for our own internal
+# variables.
+
+define LEN_FCB 28
+define FCB_U_NAME Mems[($1)+16+($2)-1]
+define FCB_IOSB Mems[($1)+20+($2)-1]
+define FCB_KCHAN Mems[($1)+24] # NULL if on local node, else remote
+define FCB_STATUS Mems[($1)+25] # channel status (r, w, err)
+define FCB_NBYTES Mems[($1)+26] # nbytes last transfer
+define FCB_EFN Mems[($1)+27] # event flag used for transfer
+
+# IIS device status words.
+
+define IIS_FILSIZE (512 * 512 * SZB_CHAR)
+define IIS_BLKSIZE 1024
+define IIS_OPTBUFSIZE (512 * SZB_CHAR)
+define IIS_MAXBUFSIZE 32768
diff --git a/unix/gdev/m70vms/m70cls.f b/unix/gdev/m70vms/m70cls.f
new file mode 100644
index 00000000..9eb2fcd3
--- /dev/null
+++ b/unix/gdev/m70vms/m70cls.f
@@ -0,0 +1,26 @@
+ subroutine m70cls (fcb)
+c
+c Routine to close model 70 display
+c
+ integer fcb(*)
+ include 'fcbu.inc'
+c
+ integer*4 sys$dassgn, chan, junk
+ integer*2 chan2(2)
+ equivalence (chan, chan2)
+c
+c call wtexec (fcb)
+c
+ chan2(1) = fcb(fcb_u_m70_chan)
+ chan2(2) = fcb(fcb_u_m70_chan+1)
+c
+c if (chan.ne.0) call lib$signal (%val(sys$dassgn (%val(chan))))
+ if (chan.ne.0) then
+ junk = sys$dassgn (%val(chan))
+ endif
+c
+ fcb(fcb_u_m70_chan) = 0
+ fcb(fcb_u_m70_chan+1) = 0
+c
+ return
+ end
diff --git a/unix/gdev/m70vms/m70get.f b/unix/gdev/m70vms/m70get.f
new file mode 100644
index 00000000..c9d0b1c2
--- /dev/null
+++ b/unix/gdev/m70vms/m70get.f
@@ -0,0 +1,43 @@
+ subroutine m70get (fcb, error)
+c
+c Routine to get (allocate) the model 70
+c
+c arguments:
+c
+c fcb function communications block
+c
+c error -2 => device already allocated
+c -1 => m70 not acquired
+c 0 => success
+c 1 => timeout
+c 2 => invalid device or powerfail
+c >=1000 machine dependent error number
+c
+ integer fcb(*), error
+c
+ include 'fcbu.inc'
+ external ss$_normal, ss$_devalloc
+ integer*4 len,status, sys$alloc
+ integer*2 nam2(2), stat
+ byte nam(4)
+ character name*4, result*8
+ equivalence (nam2, nam), (name, nam), (status, stat)
+c
+ nam2(1) = fcb(fcb_u_m70_name)
+ nam2(2) = fcb(fcb_u_m70_name+1)
+c
+ status = sys$alloc (name, len, result,)
+ if (status.ne.%loc(ss$_normal)) then
+ if (status .eq. %loc(ss$_devalloc)) then
+ error = -2
+ else
+ error = 1000 + stat
+ endif
+ else
+ call m70opn (fcb, error)
+ if (error .ne. 0) return
+ call m70mcl (fcb, error)
+ endif
+c
+ return
+ end
diff --git a/unix/gdev/m70vms/m70io.f b/unix/gdev/m70vms/m70io.f
new file mode 100644
index 00000000..cbe0418e
--- /dev/null
+++ b/unix/gdev/m70vms/m70io.f
@@ -0,0 +1,75 @@
+ subroutine m70io (fcb, data, count, read, opcd, iosb, error)
+c
+c Routine does io between M70 and a VAX
+c
+c Parameters:
+c
+c fcb function communications block.
+c
+c data input/output buffer.
+c
+c count number of words to read/write.
+c
+c read 0 -> write, 1 -> read.
+c
+c opcd 0 -> qio with efn = 1 and wait for completion
+c 1 -> qio with efn = 2
+c 2 -> qio with efn = 3
+c
+c iosb I/O status quadword
+c
+c error -1 => display not available
+c 0 => success
+c 1 => time/out
+c 2 => invalid or non-responding device
+c 1000 > machine dependent error code
+c
+ integer fcb(*), data(1), count, read, opcd, error
+ integer*4 iosb(2)
+c
+ include 'fcbu.inc'
+ external io$_writevblk, io$_readvblk, ss$_timeout, ss$_powerfail
+ integer*4 chan, sys$qio, sys$waitfr, func, status, l_iosb(2)
+ integer*2 chan2(2), stat(2)
+ equivalence (chan, chan2), (status, stat(1))
+c
+ chan2(1) = fcb(fcb_u_m70_chan)
+ chan2(2) = fcb(fcb_u_m70_chan+1)
+c
+ if (read.eq.1) then
+ func = %loc(io$_readvblk)
+ else
+ func = %loc(io$_writevblk)
+ endif
+c
+ if (opcd.eq.0) then
+ status = sys$qio (%val(opcd+1), %val(chan), %val(func),
+ 1 l_iosb,,, data, %val(2*count),,,,)
+ if (status) then
+ status = sys$waitfr (%val(1))
+ if (l_iosb(1)) then
+ error = 0
+ else
+ stat(1) = lib$match_cond
+ 1 (iosb, ss$_timeout, ss$_powerfail)
+ if (stat(1) .eq. 0) then
+ error = 1000 + iosb(1)
+ else
+ error = stat(1)
+ endif
+ endif
+ else
+ error = 1000 + stat(1)
+ endif
+ else
+ status = sys$qio (%val(opcd+1), %val(chan), %val(func),
+ 1 iosb,,, data, %val(2*count),,,,)
+ if (status) then
+ error = 0
+ else
+ error = 1000 + stat(1)
+ endif
+ endif
+c
+ return
+ end
diff --git a/unix/gdev/m70vms/m70mcl.f b/unix/gdev/m70vms/m70mcl.f
new file mode 100644
index 00000000..c9fb5c98
--- /dev/null
+++ b/unix/gdev/m70vms/m70mcl.f
@@ -0,0 +1,35 @@
+ subroutine m70mcl (fcb, error)
+c
+c master clear model 70
+c
+ integer fcb(*), error
+c
+ include 'fcbu.inc'
+ external io$_rewind, ss$_normal
+ integer*4 status, iosb(2), chan, sys$qiow
+ integer*2 chan2(2), iostat, stat
+ equivalence (chan, chan2), (iosb, iostat)
+ equivalence (status, stat)
+ external ss$_timeout, ss$_powerfail
+c
+ chan2(1) = fcb(fcb_u_m70_chan)
+ chan2(2) = fcb(fcb_u_m70_chan+1)
+c
+ status = sys$qiow (, %val(chan), io$_rewind, iosb,,,,,,,,)
+ if (status) then
+ if (iosb(1)) then
+ error = 0
+ else
+ status = lib$match_cond (iosb, ss$_timeout, ss$_powerfail)
+ if (status .eq. 0) then
+ error = 1000 + iostat
+ else
+ error = status
+ endif
+ endif
+ else
+ error = 1000 + stat
+ endif
+c
+ return
+ end
diff --git a/unix/gdev/m70vms/m70opn.f b/unix/gdev/m70vms/m70opn.f
new file mode 100644
index 00000000..4bb91b3a
--- /dev/null
+++ b/unix/gdev/m70vms/m70opn.f
@@ -0,0 +1,41 @@
+ subroutine m70opn (FCB, error)
+C
+c Routine to open model 70
+c
+c Error is returned as:
+c -1 = display open
+c 0 = OK
+c 1 = timeout
+c 2 = invalid or non-responding device
+c >= 1000 : machine dependent error number
+c
+ integer fcb(*), error
+ include 'fcbu.inc'
+C
+ integer*4 sys$assign, chan, status
+ integer*2 chan2(2), name2(2), stat(2)
+ byte name1(4)
+ character*4 m70
+ equivalence (chan, chan2), (status, stat(1))
+ equivalence (name1, name2), (name1, m70)
+C
+ name2(1) = fcb(fcb_u_m70_name)
+ name2(2) = fcb(fcb_u_m70_name+1)
+ chan2(1) = fcb(fcb_u_m70_chan)
+ chan2(2) = fcb(fcb_u_m70_chan+1)
+c
+ if (chan.eq.0) then
+ status = sys$assign ('_'//m70//':', chan,,)
+ if (status) then
+ fcb(fcb_u_m70_chan) = chan2(1)
+ fcb(fcb_u_m70_chan+1) = chan2(2)
+ error = 0
+ else
+ error = 1000 + stat(1)
+ endif
+ else
+ error = -1
+ endif
+c
+ return
+ end
diff --git a/unix/gdev/m70vms/m70rel.f b/unix/gdev/m70vms/m70rel.f
new file mode 100644
index 00000000..7b686d10
--- /dev/null
+++ b/unix/gdev/m70vms/m70rel.f
@@ -0,0 +1,19 @@
+ subroutine m70rel (fcb)
+c
+c routine to release(DEALLOCATE) the model 70
+c
+ integer fcb(*)
+c
+ include 'fcbu.inc'
+ integer*2 dev2(2)
+ byte dev(4)
+ character*4 m70
+ equivalence (dev2,dev), (m70,dev)
+c
+ call m70cls (fcb)
+ dev2(1) = fcb(fcb_u_m70_name)
+ dev2(2) = fcb(fcb_u_m70_name+1)
+ call sys$dalloc ('_'//m70//':',)
+c
+ return
+ end
diff --git a/unix/gdev/m70vms/m70wt.f b/unix/gdev/m70vms/m70wt.f
new file mode 100644
index 00000000..715a1c68
--- /dev/null
+++ b/unix/gdev/m70vms/m70wt.f
@@ -0,0 +1,44 @@
+ subroutine m70wt (fcb, bfnum, bfcnt, iosb, error)
+c
+c routine to wait for completion of buffer write on pdp-11's
+c
+c fcb function communication block.
+c bfnum used to determine event flag to wait for
+c bfcnt number of words in buffer. should be -1 indicating
+c i/o pending. reset to zero when i/o completed.
+c iosb i/o status block
+c error 0 success, -1 not acquired, 1 timeout,
+c 2 invalid device, 1000+n system dep. error
+c
+ integer fcb(*)
+ integer bfnum, bfcnt, error
+ integer*4 iosb(2), status
+ integer*2 stat(2)
+c
+ integer*4 sys$waitfr
+ equivalence (status, stat(1))
+ external ss$_timeout, ss$_powerfail
+c
+c is this wait required?
+c
+ error = 0
+ if (bfcnt .ge. 0) return
+c
+ status = sys$waitfr (%val(bfnum+1))
+ if (status) then
+ bfcnt = 0
+ if (.not. iosb(1)) then
+ stat(1) = lib$match_cond
+ 1 (iosb, ss$_timeout, ss$_powerfail)
+ if (stat(1) .eq. 0) then
+ error = 1000 + iosb(1)
+ else
+ error = stat(1)
+ endif
+ endif
+ else
+ error = 1000 + stat(1)
+ endif
+c
+ return
+ end
diff --git a/unix/gdev/m70vms/m70wti.f b/unix/gdev/m70vms/m70wti.f
new file mode 100644
index 00000000..0aabd1fd
--- /dev/null
+++ b/unix/gdev/m70vms/m70wti.f
@@ -0,0 +1,46 @@
+ subroutine m70wti (fcb, func, time, button, x, y)
+c
+c This routine waits for the appropriate interupt from the
+c Unibus M70 interface card, then returns button and cursor
+c information.
+c
+c
+c parameter descriptions:
+c
+c fcb is a system info. array.
+c
+c func is interpreted:
+c 0 ==> wait for button push.
+c 1 ==> wait for cursor move.
+c 2 ==> wait for button push or cursor move.
+c
+ integer fcb(*), func, time, button, x, y
+c
+ include 'fcbu.inc'
+ external io$_rewindoff
+ integer*4 sys$qiow, mask, chan, iosb(2)
+ integer*2 chan2(2)
+ equivalence (chan, chan2)
+c
+ chan2(1) = fcb(fcb_u_m70_chan) ! get M70 channel
+ chan2(2) = fcb(fcb_u_m70_chan+1)
+c
+ if (func.eq.0) then
+ mask = '0400'x ! wait for button
+ elseif (func.eq.1) then
+ mask = '0800'x ! wait for trackball
+ elseif (func.eq.2) then
+ mask = '0C00'x ! wait for button or trackball
+ else
+ mask = '0C00'x
+ endif
+c
+ status = sys$qiow (, %val(chan), io$_rewindoff,
+ 1 iosb,,,%val(mask),,,,,)
+c
+c Get button word and X-Y position of cursor
+c
+ call rbutn (fcb, button, x, y)
+c
+ return
+ end
diff --git a/unix/gdev/m70vms/mkpkg b/unix/gdev/m70vms/mkpkg
new file mode 100644
index 00000000..976cc1e4
--- /dev/null
+++ b/unix/gdev/m70vms/mkpkg
@@ -0,0 +1,29 @@
+# Makelib for the VMS version of the IIS driver.
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ @(i2)
+ zclm70.x m70.h <mach.h> <knet.h>
+ zopm70.x m70.h <mach.h> <knet.h>
+ zrdm70.x m70.h <mach.h> <knet.h>
+ zstm70.x m70.h <mach.h> <fio.h>
+ zwrm70.x m70.h <mach.h> <knet.h>
+ zwtm70.x m70.h <mach.h> <knet.h>
+ ;
+
+i2: # Compile the VMS/Fortran IIS i/o routines with the VMS /NOI4 option.
+ $set XFLAGS = "-c -O -i2"
+
+ m70cls.f fcbu.inc
+ m70get.f fcbu.inc
+ m70io.f fcbu.inc
+ m70mcl.f fcbu.inc
+ m70opn.f fcbu.inc
+ m70rel.f fcbu.inc
+ m70wt.f
+ m70wti.f fcbu.inc
+ ;
diff --git a/unix/gdev/m70vms/zclm70.x b/unix/gdev/m70vms/zclm70.x
new file mode 100644
index 00000000..a7ebb8f7
--- /dev/null
+++ b/unix/gdev/m70vms/zclm70.x
@@ -0,0 +1,24 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <knet.h>
+include "m70.h"
+
+# ZCLM70 -- Close and deallocate the IIS.
+
+procedure zclm70 (chan, status)
+
+int chan # FCB pointer for device
+int status
+pointer fcb
+
+begin
+ fcb = chan
+ if (FCB_KCHAN(fcb) == NULL) {
+ call zwtm70 (chan, status)
+ call m70rel (Mems[fcb])
+ } else
+ call zclsbf (FCB_KCHAN(fcb), status)
+
+ call mfree (fcb, TY_SHORT)
+end
diff --git a/unix/gdev/m70vms/zopm70.x b/unix/gdev/m70vms/zopm70.x
new file mode 100644
index 00000000..f338dbe7
--- /dev/null
+++ b/unix/gdev/m70vms/zopm70.x
@@ -0,0 +1,59 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <knet.h>
+include "m70.h"
+
+# ZOPM70 -- Open the IIS for binary file i/o. The device will be automatically
+# allocated if necessary.
+
+procedure zopm70 (device, mode, chan)
+
+char device[ARB] # packed VMS device name
+int mode # access mode
+int chan # receives device channel
+
+pointer fcb
+int kchan
+char upkdev[SZ_FNAME]
+int ki_connect()
+
+short ier
+% character m70*4
+% integer*2 namw(2)
+% equivalence (m70, namw)
+
+begin
+ call calloc (fcb, LEN_FCB, TY_SHORT)
+
+ # Use the binary file driver if the device resides on a remote node.
+ # This precludes remote access to a VMS hosted IIS at present.
+
+ if (ki_connect (device) != NULL) {
+ call zopnbf (device, mode, kchan)
+ if (kchan != ERR)
+ FCB_KCHAN(fcb) = kchan
+ } else {
+ # Load string descriptor for device name into FCB.
+ call strupk (device, upkdev, SZ_FNAME)
+% call f77pak (upkdev, m70, 4)
+
+ FCB_U_NAME(fcb,1) = namw[1]
+ FCB_U_NAME(fcb,2) = namw[2]
+ FCB_KCHAN(fcb) = NULL
+ FCB_STATUS(fcb) = IIS_INACTIVE
+ FCB_NBYTES(fcb) = 0
+
+ # Allocate and open the device.
+ call m70get (Mems[fcb], ier)
+ kchan = ier
+ if (kchan != 0)
+ kchan = ERR
+ }
+
+ if (kchan < 0) {
+ call mfree (fcb, TY_SHORT)
+ chan = ERR
+ } else
+ chan = fcb
+end
diff --git a/unix/gdev/m70vms/zrdm70.x b/unix/gdev/m70vms/zrdm70.x
new file mode 100644
index 00000000..2bf726ab
--- /dev/null
+++ b/unix/gdev/m70vms/zrdm70.x
@@ -0,0 +1,36 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <knet.h>
+include "m70.h"
+
+# ZRDM70 -- Initiate an asynchronous read from the IIS.
+
+procedure zrdm70 (chan, buf, nbytes, offset)
+
+int chan # FCB pointer for device
+char buf[ARB] # output buffer
+int nbytes # number of bytes to read
+long offset # not used for this device
+
+pointer fcb
+short rwflag, opcd, nwords, ier
+data rwflag /IIS_READ/, opcd /EFN/
+
+begin
+ fcb = chan
+ if (FCB_KCHAN(fcb) == NULL) {
+ nwords = nbytes / (SZ_SHORT * SZB_CHAR)
+ call m70io (Mems[fcb], buf, nwords, rwflag, opcd, FCB_IOSB(fcb,1),
+ ier)
+
+ FCB_NBYTES(fcb) = nbytes
+ FCB_EFN(fcb) = opcd
+
+ if (ier != 0)
+ FCB_STATUS(fcb) = ERR
+ else
+ FCB_STATUS(fcb) = IIS_READ
+ } else
+ call zardbf (FCB_KCHAN(fcb), buf, nbytes, offset)
+end
diff --git a/unix/gdev/m70vms/zstm70.x b/unix/gdev/m70vms/zstm70.x
new file mode 100644
index 00000000..2b790dfa
--- /dev/null
+++ b/unix/gdev/m70vms/zstm70.x
@@ -0,0 +1,28 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <fio.h>
+include "m70.h"
+
+# ZSTM70 -- Return device status for the IIS.
+
+procedure zstm70 (chan, what, lvalue)
+
+int chan # FCB pointer for device
+int what # status parameter
+long lvalue
+
+begin
+ switch (what) {
+ case FSTT_FILSIZE:
+ lvalue = IIS_FILSIZE
+ case FSTT_BLKSIZE:
+ lvalue = IIS_BLKSIZE
+ case FSTT_OPTBUFSIZE:
+ lvalue = IIS_OPTBUFSIZE
+ case FSTT_MAXBUFSIZE:
+ lvalue = IIS_MAXBUFSIZE
+ default:
+ lvalue = ERR
+ }
+end
diff --git a/unix/gdev/m70vms/zwrm70.x b/unix/gdev/m70vms/zwrm70.x
new file mode 100644
index 00000000..7cc1ef8a
--- /dev/null
+++ b/unix/gdev/m70vms/zwrm70.x
@@ -0,0 +1,36 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <knet.h>
+include "m70.h"
+
+# ZWRM70 -- Initiate an asynchronous write to the IIS.
+
+procedure zwrm70 (chan, buf, nbytes, offset)
+
+int chan # FCB pointer for device
+char buf[ARB] # input buffer
+int nbytes # number of bytes to write
+long offset # not used for this device
+
+pointer fcb
+short rwflag, opcd, nwords, ier
+data rwflag /IIS_WRITE/, opcd /EFN/
+
+begin
+ fcb = chan
+ if (FCB_KCHAN(fcb) == NULL) {
+ nwords = nbytes / (SZ_SHORT * SZB_CHAR)
+ call m70io (Mems[fcb], buf, nwords, rwflag, opcd, FCB_IOSB(fcb,1),
+ ier)
+
+ FCB_NBYTES(fcb) = nbytes
+ FCB_EFN(fcb) = opcd
+
+ if (ier != 0)
+ FCB_STATUS(fcb) = ERR
+ else
+ FCB_STATUS(fcb) = IIS_WRITE
+ } else
+ call zawrbf (FCB_KCHAN(fcb), buf, nbytes, offset)
+end
diff --git a/unix/gdev/m70vms/zwtm70.x b/unix/gdev/m70vms/zwtm70.x
new file mode 100644
index 00000000..69ab39da
--- /dev/null
+++ b/unix/gdev/m70vms/zwtm70.x
@@ -0,0 +1,44 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <knet.h>
+include "m70.h"
+
+# ZWTM70 -- Wait for i/o completion and return the number of bytes read or
+# written or ERR. Repetitive calls return the same value.
+
+procedure zwtm70 (chan, status)
+
+int chan # FCB pointer for device
+int status # nbytes transferred or ERR
+
+pointer fcb
+short bfnum, bufcnt, ier
+
+begin
+ fcb = chan
+
+ if (FCB_KCHAN(fcb) == NULL) {
+ switch (FCB_STATUS(fcb)) {
+ case ERR:
+ status = ERR
+ case IIS_INACTIVE:
+ status = FCB_NBYTES(fcb)
+
+ default:
+ bfcnt = -1 # m70wt is a nop if we don't do this
+ bfnum = FCB_EFN(fcb)
+
+ call m70wt (Mems[fcb], bfnum, bfcnt, FCB_IOSB(fcb,1), ier)
+
+ if (ier != 0)
+ status = ERR
+ else
+ status = FCB_NBYTES(fcb)
+
+ FCB_STATUS(fcb) = IIS_INACTIVE
+ }
+
+ } else
+ call zawtbf (FCB_KCHAN(fcb), status)
+end
diff --git a/unix/gdev/mkpkg b/unix/gdev/mkpkg
new file mode 100644
index 00000000..800c7e9c
--- /dev/null
+++ b/unix/gdev/mkpkg
@@ -0,0 +1,12 @@
+# Make the ZFIOGD (binary graphics) device driver and install it in libsys.
+
+$checkout libsys.a lib$
+$update libsys.a
+$checkin libsys.a lib$
+$exit
+
+libsys.a:
+ zfiogd.x <fio.h> <mach.h>
+ @iism70
+ @iism75
+ ;
diff --git a/unix/gdev/mkpkg.sh b/unix/gdev/mkpkg.sh
new file mode 100644
index 00000000..3984d71f
--- /dev/null
+++ b/unix/gdev/mkpkg.sh
@@ -0,0 +1,3 @@
+# GDEV -- Host dependent graphics device drivers.
+
+(cd sgidev; sh -x mkpkg.sh)
diff --git a/unix/gdev/sgidev/README b/unix/gdev/sgidev/README
new file mode 100644
index 00000000..363b490f
--- /dev/null
+++ b/unix/gdev/sgidev/README
@@ -0,0 +1,24 @@
+SGIDEV -- This directory contains the UNIX dependent sources for the metacode
+or bitmap translation programs for all devices supported by the SGI graphics
+kernel. See gio$sgikern or `help sgikern' for further information on SGI.
+
+To add a new SGI device:
+
+ [1] Add source file for translator to this directory.
+ [2] Add references to mkpkg.csh and mkpkg.
+ [3] Run `mkpkg update' in this directory to install new translator.
+
+ [4] Add entry to graphcap file, including DD command string
+ containing host command to dispose of the output.
+
+ [5] Test new device interface.
+
+Alternatively, you might wish to install the source for the translator in
+local somewhere, to avoid a merge operation when a new version of the VMS
+host system interface is installed.
+
+Note that some example graphcap entries for SGI devices might require non-
+standard tasks residing outside of IRAF, for example the `impress300'
+command to ship Impress output from a UNIX node to a VMS node running
+Eunice in order to execute the VMS IMPRINT command. These are considered
+so unusual that support is not included in the standard system.
diff --git a/unix/gdev/sgidev/README.gif b/unix/gdev/sgidev/README.gif
new file mode 100644
index 00000000..85833d3f
--- /dev/null
+++ b/unix/gdev/sgidev/README.gif
@@ -0,0 +1,438 @@
+
+Announcement for adass.iraf.system:
+
+ An SGI translator which converts IRAF graphics directly to GIF
+images is now available from our anonymous ftp archive as
+
+ ftp://iraf.noao.edu/pub/sgi2gif.c
+ ftp://iraf.noao.edu/pub/sgi2gif.readme
+
+The associated readme file describes how to install the translator and
+configure a variety of graphcap entries for it.
+ SGI translators are used to convert IRAF graphics to some other
+format, usually Postscript, for disposal to a printer or some other
+hardcopy device. The SGI2GIF translator now allows users to generate
+GIF images (suitable for web page presentation) directly from IRAF using
+the familiar ":.snap" command or non-interactively. See the readme file
+for a full discussion of the capabilities and configuration options, or
+contact site support (iraf@noao.edu) with questions or problems.
+
+--------------------------------------------------------------------------------
+
+README:
+
+1. Introduction
+---------------
+
+ IRAF hardcopy graphics are generated by converting the graphics
+metacode through the SGI (Simple Graphics Interface) kernel which
+translates the numerous graphics commands to a minimal set of move/draw
+instructions or a bitmap raster of the plot. In the case of
+hardcopy/output graphics (i.e. the SGI kernel), the dev$graphcap file
+defines parameters for this conversion which include the plot size, SGI
+kernel options, and most especially a "device dispose" (DD) string which
+specifies the SGI translator to be used and what to do with the resulting
+translator output. The SGI kernel is not a full graphics kernel so
+information such as line color and fill areas are lost, below we will
+discuss how to retain this when producing a GIF images using other
+translators and graphcap file trickery.
+
+ For most printer devices the "sgi2uapl" Postscript translator is
+used to convert the SGI kernel metacode from a series of move/draw
+instructions to equivalent postscript commands, other translators are
+available to convert to other printer languages. The SGI kernel can also
+be used, with the proper graphcap entries, to generate a bitmap raster of
+the plot which can be easily converted to various image formats. The SGI2GIF
+translator takes advantage of this latter feature to produce GIF images
+directly from the IRAF graphics metacode.
+
+ The translator has options for specifying the image size,
+foreground and background colors, GIF transparency, and can be used to
+convert multiple input bitmap files or a single file containing multiple
+graphics frames. It allows users to easily generate images suitable for
+presentation on the web, either manually or automatically.
+
+
+2. Installation
+---------------
+
+ The SGI translator is distributed in source form and to be used
+must be compiled and installed in the system hbin$ directory. To install
+the new SGI translator follow these steps while logged in through the iraf
+user account:
+
+ [1] Download the translator from the IRAF anonymous FTP archive or
+ one of it's mirror sites using:
+
+ % ftp iraf.noao.edu (140.252.1.1)
+ login: anonymous
+ password: [your email address]
+ ftp> cd /pub
+ ftp> mget sgi2gif.c
+ ftp> quit
+
+ [2] Compile the source using
+
+ % cc -o sgi2gif.e sgi2gif.c # compile the source
+ % mv sgi2gif.e $hbin # move to the $hbin
+
+ "$hbin" is defined in the iraf environment to be something like
+ $iraf/unix/bin.<arch>, where <arch> would be 'ssol' for Solaris,
+ 'sparc' for SunOS and so on.
+
+ [3] Optionally place the source in the directory $iraf/unix/gdev/sgidev.
+
+ [4] Edit the dev$graphcap file and add the following default entries
+ for the device near the top of the file:
+
+ g-gif|UNIX generic interface to multi-frame GIF file generator:\
+ :DD=ugif,tmp$sgk,!{ sgidispatch sgi2gif -w $(PX) -h $(PY) \
+ -bg 0 0 0 -fg 255 255 255 -root sgigif $F.[1-8] ; \
+ rm $F.[1-8]; }&:MF#8:NF:tc=sgi_image_format:
+
+ sgi_image_format|Generic raster file format specification:\
+ :kf=bin$x_sgikern.e:tn=sgikern:ar#.75:\
+ :xr#640:yr#480 :PX#640:PY#480 :XW#640:YW#480:\
+ :BI:MF#1:YF:NB#8:LO#1:LS#0:XO#0:YO#0:
+
+ The 'g-gif' entry takes one or more graphics file input and converts
+ each input frame to a redirected file on output called 'sgigifXXX.gif'
+ where the 'XXX' is frame number. See below for details one
+ configuring other graphcap entries.
+
+
+2. Translator Options
+---------------------
+ The SGI2GIF translator allows the following options:
+
+ -w N Set the width of input bitmap and output image. The
+ argument must be derived from the graphcap value since
+ that is what the SGI kernel will use when generating the
+ bitmap, e.g. "-w $(PX)" instead of "-w 640".
+
+ -h N Set the height of input bitmap and output image. The
+ argument must be derived from the graphcap value since
+ that is what the SGI kernel will use when generating the
+ bitmap, e.g. "-h $(PY)" instead of "-h 640".
+
+ -i Invert the bitmap before conversion. By default the
+ graphics are drawn using the foreground color, this
+ option inverts the bitmap before conversion meaning the
+ graphics are drawn using the background color.
+
+ -t Set background color as transparent. If enabled the
+ translator will produce a GIF89 format image with the
+ background color set as "transparent". When this image
+ is used with an HTML document the background color is
+ the HTML page color.
+
+ -root Set the root rame for output file. If defined this
+ root name will be combined with the frame number and
+ a ".gif" extension to form the output name. If not
+ defined and only one input image is present the default
+ action is to send the output to STDOUT.
+
+ -fg R G B Specify foreground color (default 'black'). Set the
+ foreground color as a triplet of RGB values in the
+ range 0-255. The -fg flag must have three arguments.
+
+ -bg R G B Specify background color (default 'white'). Set the
+ foreground color as a triplet of RGB values in the
+ range 0-255. The -bg flag must have three arguments.
+
+
+3. Configuring Alternate Graphcap Entries
+-----------------------------------------
+
+ Most of the work in a graphcap entry is done by the 'device
+dispose' (i.e. "DD") string. This string is composed of three comma
+delimited parts: a node/device name (which is normally ignored), a
+temporary filename, and a host dispose command. To configure a new entry
+it is only this last field that normally needs to be modified, perhaps in
+conjunction with another graphcap parameter. As an example let's look at
+the DD string used in the example graphcap above:
+
+ :DD=ugif,tmp$sgk,!{ sgidispatch sgi2gif -w $(PX) -h $(PY) \
+ -bg 0 0 0 -fg 255 255 255 -root sgigif $F.[1-8] ; rm $F.[1-8]; }&:
+
+where 'ugif' is the unused node/device name, 'tmp$sgk' is the temporary
+filename, and the remainder is a host dispose command. The 'sgidispatch'
+command is an iraf binary that launches the specified translator
+('sgi2gif' here) with any required arguments. Note that everything within
+the "!{...}&" curly braces is executed (as a background Bourne shell
+command) so any string of valid unix command separate by a semicolon will
+be executed. In this case the sgidispatch command launches the sgi2gif
+translator with all of it's arguments, it then deletes the input metacode
+file symbolized by the "$F".
+ You may notice that some arguments are specified as e.g. "-w
+$(PX)". When the DD string is executed any macro values beginning with a
+'$' such as '$(PX)' are replaced with values from the rest of the graphcap
+entry. In this case '$(PX)' is replaced by the value contained in the
+graphcap :PX (physical X size) field, the "$F.[1-8]" is expanded to
+include the unique root filename along with any extension 1 thru 8 which may
+be generated because of multiple plots in the input. In
+most cases all you may need to change in the DD string itself is the
+output file, or e.g. whether it gets piped to some other command.
+
+
+3.1 Changing Image Size
+-----------------------
+
+ Changing the image size is simply a matter of changing the graphcap
+parameters
+
+ :xr#640:yr#480: sets X,Y device resolution
+ :PX#640:PY#480: sets X,Y physical size of bitmap
+ :XW#640:YW#480: sets X,Y width of plotting window
+
+These are defined in the 'sgi_image_format' entry given above. Graphics
+are drawn using Normalized Device Coordinates ('NDC', values in the range
+0.0 to 1.0) and will be scaled appropriately for any specified output
+dimensions allowing users to configure graphcap entries for images which are
+larger/smaller than the default, or have square or elongated aspect ratios.
+
+3.2 Preserving Color Information
+--------------------------------
+
+ Colors such as those used for the axis labels and frame, and colors
+used in the plot itself for different line/marker types cannot be preserved
+by the SGI kernel directly. To do this you must use a full graphics kernel
+such as the PSIKERN postscript kernel found in STSDAS. The V2.11
+distribution contains graphcap entries suitable for this kernel but assumes
+you have STSDAS available. See the online help for more information about
+this kernel.
+ Using the '-fg' and '-bg' flags will allow you to specify foreground
+and background colors to be used for the plot as a whole. Note that these
+flags require three arguments to specify the RGB color components. The '-t'
+flag may be used to mark the background color as 'transparent' so only the
+foreground color is shown when the image is used in an HTML document.
+
+3.3 Generating Other Image Formats
+----------------------------------
+
+ GIF may be used as an intermediate format which can be converted to
+something else as part of the graphcap DD string. For example, to use the
+ImageMagick CONVERT task to produce a JPEG image the graphcap DD string
+could be written as
+
+ g-jpeg|UNIX generic interface to JPEG file generator:\
+ :DD=ugif,tmp$sgk,!{ sgidispatch sgi2gif -w $(PX) -h $(PY) \
+ -bg 0 0 0 -fg 255 255 255 -root sgi $F | \
+ convert sgi$$.gif sgi$$.jpg ; rm $F; }&: \
+ :MF#1:NF:tc=sgi_image_format:
+
+The DD string first uses the SGI2GIF translator to produce a 'sgi.gif'
+image, then calls the convert task (which is assumed to be in the user's
+path) to convert this to JPEG as a separate step. The :MF field is
+set to one meaning each frame will generate a new file. The '$$' used in
+the filenames (e.g. 'sgi$$.gif') is the process id created for the shell
+running the DD command meaning multiple filenames of the form 'sgi12345.gif'
+will be created, each with a unique id number so the images aren't over-
+written. In the past this form of DD string could be used with the standard
+sgi2uapl postscript translator and a host task such as 'gs' to convert
+postscript to some other format.
+
+4. Interfacing to Web CGI Scripts
+----------------------------------
+
+ It would be impossible to give complete details about interfacing
+IRAF programs to CGI scripts due to the variety of languages and tasks
+that may be used. To begin lets look at how to execute a task from the
+host level, which is essentially what we'll be doing from within a CGI
+script.
+ In principle this can be done in one of two ways: Either invoke
+the executable directly with the correct command line arguments, or run
+the CL with the input redirected to execute the task. In the first case
+you must know in which executable the task resides, core IRAF system tasks
+(e.g. things in the PLOT and IMAGES packages) have their executables in
+the main $iraf/bin.<arch> directory, NOAO package tasks have the
+executables in the $iraf/noao/bin.<arch> directory. There is usually a
+separate executable for each package and you can probably figure out which
+one goes for each package otherwise just look at the package cl file to
+find out, for example the PLOT package defines the task in the
+$iraf/pkg/plot/plot.cl file, if you look in their you'll see that is
+defines the tasks as (part of the file reads)
+
+task contour,
+ surface, hafton, velvect = "plot$x_ncar.e"
+
+which means that the CONTOUR, SURFACE, etc tasks are in the "x_ncar.e"
+executable.
+ Once you find the correct binary, you need to create a file with
+the task parameters: usually it's easiest to set the parameters and then
+dump the parameter file with 'dpar', e.g.
+
+ cl> dpar listpix > listpix.par
+
+It's likely that CGI scripts will need to set certain parameters itself so
+thought must be given to how to edit this list of default parameters with
+values given in the CGI script.
+
+To run the task you would then do something like:
+
+ % $iraf/bin.sparc/x_images.e listpix @listpix.par
+
+In this case you must be careful that ALL of the task parameters are
+defined, this is done by 'dpar' but empty string parameters will always
+be prompted for. On a host command line simply respond to the parameter
+prompts by hitting the return key, from with a CGI script these must
+be supplied automatically in some way (e.g. via redirection).
+ In the second case you create a command file and input it to the
+cl, for example
+
+ % cl < cl.input >& some_logfile
+
+where cl.input contains CL commands such as
+
+ wfits.scale=no # set a parameter wfits image*.imh
+ mta # call a task
+ logout # logout of the CL
+
+You must be careful about making sure you are in the right directory and
+that parameters are given explicitly if they're like to change, but with
+this approach you can call any iraf task.
+
+4.1 Graphics Tasks
+-------------------
+
+ Regardless of the method chosen, you need to be careful about
+redirecting any required input or text/graphics output. Graphics output
+can be redirected either by setting the "device" parameter to e.g. 'vdm'
+to create a file called 'vdm' in the uparm directory, or using the '>G' CL
+syntax as in
+
+ cl> surface dev$pix >G surf.plot # redirect metacode to a file
+ cl> surface dev$pix dev="vdm" # save metacode to uparm dir
+ cl> surface dev$pix dev="stdplot" # to print it out
+ cl> gflush # flush graphics buffer
+
+Which of these approaches works best for depends depends on the tasks you
+need and the method of execution chosen above. Note that the ">G" syntax
+will only work for tasks executed within the CL, setting a device
+parameter to something that creates a file will work with either method.
+ For non-interactive tasks like SURFACE or CONTOUR this file is
+created automatically, interactive tasks however may need to create
+metacode files explicitly or else the CGI script must take care to extract
+only those plots of interest from the metacode file (e.g. with a separate
+call to GKIEXTRACT).
+ Interactive tasks must also satisfy requests for cursor commands,
+including the usual 'q' keystroke needed to exit the task. Since cursor
+commands are in reality queries to the CL any binary run as a host task
+will generate a cursor prompt on the standard output the same as for any
+other parameter query. The response to a cursor query however is usually
+of the form
+ x y wcs key strval
+
+where 'x' and 'y' are the cursor position, 'wcs' is the WCS of those coords
+(usually not important), 'key' is the keystroke you would normally enter,
+and if 'key' is a color the 'strval' is the remainder of that color command.
+See section 3.7 of the "help cursors" help page for more details on alternate
+graphics input. Note however, that your CGI script must know in advance the
+order in which the prompts will occur to be able to satisfy them correctly,
+e.g. any parameter prompts generated by empty string values should be met
+with a newline, and cursor prompts with something as above. Since the tasks
+will be very narrowly defined as to how they are run this usually isn't
+difficult to set up.
+
+4.2 Example
+-----------
+
+ As an example let create a CGI script to execute the PCOL task
+from a web interface. All that we need to do this is the PLOT package
+binary to execute the task, a 'graphcap' file, and the SGIKERN binary in
+order to convert our graphics metacode to a GIF format using the specified
+graphcap entries and the newly installed SGI2GIF translator. In the
+following we detail the steps involved in creating this script on a system
+with IRAF installed, your application may vary somewhat. We use a
+C-shell script here but the same principles apply to all scripting
+languages, users should contact site support with questions.
+
+-----------------------------------------------------------------------------
+
+#!/bin/csh -f
+#
+# Sample CGI script demonstrating the using the PCOL graphics task to
+# produce an 'sgigif.gif' file of the resulting plot which can be shown
+# as an image of the output web page. The script does not show how to
+# parse arguments or format the resulting HTML page. All that is required
+# for IRAF execution is the binary for the task to be run, the SGIKERN
+# binary, and a graphcap file to produce the GIF (given below). The CGI
+# script can define the task parameters itself or use a predefined 'dpar'
+# dump to set defaults as we do below.
+
+# The REMOTE_ADDR variable is defined in the environment of the CGI
+# script automatically, we specify it here for demonstration purposes.
+set REMOTE_ADDR = 140.252.30.95
+
+# This would be defined as the graphcap file installed for the local web
+# server.
+
+# The only graphcap entries needed to output graphics to a GIF file using
+# the SGI translator is as follows:
+#
+# vdm|stdvdm|Virtual Device Metafile:\
+# :co#80:li#35:xr#1024:yr#1024:zr#256:ar#.77:ch#.0294:cw#.0125:\
+# :X1#0:X2#1023:Y1#0:Y2#1023:
+#
+# g-gif|UNIX generic interface to multi-frame GIF file generator:\
+# :DD=ugif,tmp$sgk,!{ /<path>/sgi2gif.e -w $(PX) -h $(PY) \
+# -bg 0 0 0 -fg 255 255 255 -root sgigif $F.[1-8] ; \
+# rm $F.[1-8]; }&:MF#8:NF:tc=sgi_image_format:
+#
+# sgi_image_format|Generic raster file format specification:\
+# :kf=bin$x_sgikern.e:tn=sgikern:ar#.75:\
+# :xr#640:yr#480:PX#640:PY#480:XW#640:YW#480:\
+# :BI:MF#1:YF:NB#8:LO#1:LS#0:XO#0:YO#0:
+#
+# Note that the path to the sgigif.e binary is specified explicitly, this
+# must be replaced by the path to the actual binary.
+#
+# On the web server this file would normally be installed in the cgi-bin
+# or some other directory, the cgi script itself needs to define this location
+# with the following variable:
+
+set graphcap = /tmp/graphcap
+
+# A uparm directory needs to be defined for saving the VDM file. This is
+# defined based on the REMOTE_ADDR so we can have multiple connections
+# running at the same time without concurrency problems.
+
+set uparm = /tmp/uparm-$REMOTE_ADDR/
+
+# Create the uparm directory we'll be using...
+mkdir $uparm
+
+# Execute the graphics task desired. In this example we're running the PCOL
+# task and assume we've saved the parameters to a 'pcol.dpar' file in the
+# current directory. In practice the parameters can be specified using a
+# dpar file in the cgi-bin dir or explicitly on the command line. To execute
+# the task we call the binary directly, direct output to /dev/null and
+# redirect input blank lines to respond to params that take no value. We
+# must set the uparm and graphcap values set above to handle the graphics.
+# The CGI script can insert values such as 'image' based on arguments, the
+# defaults come from a predefined dpar file.
+
+/iraf/iraf/bin.ssun/x_plot.e >>& /dev/null << EOF
+set uparm = $uparm
+set graphcap = $graphcap
+pcol @pcol.dpar pcol.device="vdm"
+
+EOF
+
+# At this point the GKI metacode is saved in the uparm$vdm file, where
+# 'uparm' is set above and is created by the custom graphcap file we're
+# using. To convert GKI metacode to the final GIF file we call the SGIKERN
+# directly and specify the device as 'g-gif' which produces an 'sgigif.gif'
+# file in the current directory. Graphcap entries can be created to name
+# the file anything desired, that filename is then used as a URL for the
+# web page returned.
+
+/iraf/iraf/bin.ssun/x_sgikern.e >>& /dev/null << EOF
+set uparm = $uparm
+set graphcap = $graphcap
+sgikern input=uparm\$vdm device=g-gif generic=yes
+EOF
+
+# Finally, clean up the temp files we've created.
+/bin/rm -rf $uparm
+
diff --git a/unix/gdev/sgidev/mkpkg b/unix/gdev/sgidev/mkpkg
new file mode 100644
index 00000000..e9dac3df
--- /dev/null
+++ b/unix/gdev/sgidev/mkpkg
@@ -0,0 +1,9 @@
+# Make the SGI device host level translation programs [MACHDEP].
+
+$call update
+$exit
+
+update:
+ ! sh -x mkpkg.sh
+ ! mv $hlib/sgi*.e $hbin
+ ;
diff --git a/unix/gdev/sgidev/mkpkg.sh b/unix/gdev/sgidev/mkpkg.sh
new file mode 100644
index 00000000..85d6c83a
--- /dev/null
+++ b/unix/gdev/sgidev/mkpkg.sh
@@ -0,0 +1,60 @@
+# Make the SGI translators and install them in hlib.
+
+$CC -c $HSI_CF sgiUtil.c
+
+$CC -c $HSI_CF sgidispatch.c
+$CC $HSI_LF sgidispatch.o ../../hlib/libos.a $HSI_LIBS -o sgidispatch.e
+mv -f sgidispatch.e ../../hlib
+rm sgidispatch.o
+
+$CC -c $HSI_CF sgi2uimp.c
+$CC $HSI_LF sgi2uimp.o sgiUtil.o $HSI_LIBS -o sgi2uimp.e
+mv -f sgi2uimp.e ../../hlib
+rm sgi2uimp.o
+
+$CC -c $HSI_CF sgi2uapl.c
+$CC $HSI_LF sgi2uapl.o sgiUtil.o $HSI_LIBS -o sgi2uapl.e
+mv -f sgi2uapl.e ../../hlib
+rm sgi2uapl.o
+
+$CC -c $HSI_CF sgi2uqms.c
+$CC $HSI_LF sgi2uqms.o sgiUtil.o $HSI_LIBS -o sgi2uqms.e
+mv -f sgi2uqms.e ../../hlib
+rm sgi2uqms.o
+
+$CC -c $HSI_CF sgi2uptx.c
+$CC $HSI_LF sgi2uptx.o sgiUtil.o $HSI_LIBS -o sgi2uptx.e
+mv -f sgi2uptx.e ../../hlib
+rm sgi2uptx.o
+
+$CC -c $HSI_CF sgi2uhplj.c
+$CC $HSI_LF sgi2uhplj.o sgiUtil.o $HSI_LIBS -o sgi2uhplj.e
+mv -f sgi2uhplj.e ../../hlib
+rm sgi2uhplj.o
+
+$CC -c $HSI_CF sgi2uhpgl.c
+$CC $HSI_LF sgi2uhpgl.o sgiUtil.o $HSI_LIBS -o sgi2uhpgl.e
+mv -f sgi2uhpgl.e ../../hlib
+rm sgi2uhpgl.o
+
+$CC -c $HSI_CF sgi2ueps.c
+$CC $HSI_LF sgi2ueps.o sgiUtil.o $HSI_LIBS -o sgi2ueps.e
+mv -f sgi2ueps.e ../../hlib
+rm sgi2ueps.o
+
+$CC -c $HSI_CF sgi2gif.c
+$CC $HSI_LF sgi2gif.o sgiUtil.o $HSI_LIBS -o sgi2gif.e
+mv -f sgi2gif.e ../../hlib
+rm sgi2gif.o
+
+$CC -c $HSI_CF sgi2xbm.c
+$CC $HSI_LF sgi2xbm.o sgiUtil.o $HSI_LIBS -o sgi2xbm.e
+mv -f sgi2xbm.e ../../hlib
+rm sgi2xbm.o
+
+$CC -c $HSI_CF sgi2svg.c
+$CC $HSI_LF sgi2svg.o sgiUtil.o $HSI_LIBS -o sgi2svg.e
+mv -f sgi2svg.e ../../hlib
+rm sgi2svg.o
+
+rm sgiUtil.o
diff --git a/unix/gdev/sgidev/sgi2gif.c b/unix/gdev/sgidev/sgi2gif.c
new file mode 100644
index 00000000..e46d4d28
--- /dev/null
+++ b/unix/gdev/sgidev/sgi2gif.c
@@ -0,0 +1,731 @@
+/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "sgiUtil.h"
+
+
+/*
+ * SGI2GIF.C -- Read an IRAF SGI bitmap file on standard input and convert
+ * to a GIF format image on standard outout.
+ *
+ * Usage:
+ * sgi2gif.e [-params] [ [sgi_bitmap] [sgi_bitmap] ... ]
+ *
+ * -w N width of input bitmap and output image
+ * -h N height of input bitmap and output image
+ * -i invert the bitmap values before conversion
+ * -t set background color as transparent
+ * -root set the root rame for output file (default stdout)
+ * -fg R G B specify foreground color
+ * -bg R G B specify background color
+ *
+ * The input file name and the switches may occur in any order. The
+ * foreground/background flags require three arguments giving the values
+ * of the RGB components of the color as a decimal number in the range 0-255.
+ * Enabling the transparency flag will cause a GIF 89 image to be written,
+ * otherwise the default will be a GIF 87 format image. The transparent
+ * color will always be the backgrund color. The bitmap may be inverted
+ * here using the -i flag.
+ *
+ * Sample graphcaps for this translator might look like:
+ *
+ * g-gif|UNIX generic interface to multi-frame GIF file generator:\
+ * :DD=ugif,tmp$sgk,!{ sgidispatch sgi2gif -w $(PX) -h $(PY) \
+ * -bg 0 0 0 -fg 255 255 255 -root sgigif $F.[1-8] ; \
+ * rm $F.[1-8]; }&:MF#8:NF:tc=sgi_image_format:
+ *
+ * sgi_image_format|Generic raster file format specification:\
+ * :kf=bin$x_sgikern.e:tn=sgikern:ar#.75:\
+ * :xr#640:yr#480:PX#640:PY#480:XW#640:YW#480:\
+ * :BI:MF#1:YF:NB#8:LO#1:LS#0:XO#0:YO#0:
+ *
+ * The 'g-gif' entry takes one or more graphics file input and converts
+ * each input frame to a redirected file on output called 'sgigifXXX.gif'
+ * where the 'XXX' is frame number.
+ *
+ * To change the image size the graphcap :xr, :PX, :XW (X-dimension) and
+ * :yr, :PY, :XY (Y-dimension) fields all need to be changed. The -i
+ * or -t flags must be specified in the graphcap DD string along with the
+ * -fg/bg flags and their arguments.
+ */
+
+
+#define NBITS_CHAR 8 /* number of bits in a char */
+#define DEF_WIDTH 640 /* default image width */
+#define DEF_HEIGHT 480 /* default image height */
+#define DEF_BG 255 /* default background RGB */
+#define DEF_FG 0 /* default foreground RGB */
+#define MAX_INFILES 16 /* max number of input bitmaps */
+#define SZ_FNAME 64 /* size of a filename */
+
+typedef int code_int;
+typedef long int count_int;
+typedef unsigned char byte;
+
+static byte *pixels;
+
+static int px = DEF_WIDTH;
+static int py = DEF_HEIGHT;
+static int nrows = DEF_HEIGHT;
+static int ncols = DEF_WIDTH;
+static int transparent = 0;
+static int invert = 0;
+static int red[] = { DEF_BG, DEF_FG } ;
+static int green[] = { DEF_BG, DEF_FG } ;
+static int blue[] = { DEF_BG, DEF_FG } ;
+static char *infile[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static char *s_root = "sgigif_";
+
+static int GIFNextPixel();
+static void BumpPixel(), GIFEncode(), Putword(), compress();
+static void output(), cl_block(), cl_hash(), char_init();
+static void char_out(), flush_char(), unpack1to8();
+
+
+
+/* MAIN -- Main entry point for the task.
+ */
+int
+main (int argc, char *argv[])
+{
+ FILE *fdi, *fdo;
+ char fname[SZ_FNAME];
+ char *root = s_root;
+ byte *buffer, *ip;
+ int i, index, numin=0, len_buf;
+ int interlace, background, bpp;
+
+
+ /* Process the command line.
+ */
+ for (i=1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ if (strcmp (argv[i], "-w") == 0) {
+ ncols = px = atoi (argv[++i]);
+ } else if (strcmp (argv[i], "-h") == 0) {
+ nrows = py = atoi (argv[++i]);
+ } else if (strcmp (argv[i], "-i") == 0) {
+ invert++;
+ } else if (strcmp (argv[i], "-root") == 0) {
+ root = argv[++i];
+ } else if (strcmp (argv[i], "-t") == 0) {
+ transparent++;
+ } else if (strcmp (argv[i], "-bg") == 0) {
+ if (isdigit(argv[++i][0]))
+ red[0] = atoi (argv[i]);
+ else
+ fprintf (stderr,
+ "sgi2gif: invalid -bg arg '%s'\n", argv[i]);
+ if (isdigit(argv[++i][0]))
+ green[0] = atoi (argv[i]);
+ else
+ fprintf (stderr,
+ "sgi2gif: invalid -bg arg '%s'\n", argv[i]);
+ if (isdigit(argv[++i][0]))
+ blue[0] = atoi (argv[i]);
+ else
+ fprintf (stderr,
+ "sgi2gif: invalid -bg arg '%s'\n", argv[i]);
+ } else if (strcmp (argv[i], "-fg") == 0) {
+ if (isdigit(argv[++i][0]))
+ red[1] = atoi (argv[i]);
+ else
+ fprintf (stderr,
+ "sgi2gif: invalid -bg arg '%s'\n", argv[i]);
+ if (isdigit(argv[++i][0]))
+ green[1] = atoi (argv[i]);
+ else
+ fprintf (stderr,
+ "sgi2gif: invalid -bg arg '%s'\n", argv[i]);
+ if (isdigit(argv[++i][0]))
+ blue[1] = atoi (argv[i]);
+ else
+ fprintf (stderr,
+ "sgi2gif: invalid -bg arg '%s'\n", argv[i]);
+ } else {
+ fprintf (stderr, "sgi2gif: unknown switch '%s'\n", argv[i]);
+ }
+ } else {
+ /* input sgi-bitmap file specification */
+ if (numin < MAX_INFILES)
+ infile[numin++] = argv[i];
+ }
+ }
+
+ /* Allocate space for the images. */
+ len_buf = px / NBITS_CHAR;
+ buffer = (byte *) malloc (len_buf);
+ ip = pixels = (byte *) malloc (px * (py + 1));
+
+ /* Loop over the input bitmaps, writing the converted output to
+ * either stdout or a filename.
+ */
+ for (index = 0; index == 0 || index < numin; index++) {
+
+ /* Open the input file. */
+ fdi = (infile[index] ? fopen (infile[index], "r") : stdin);
+
+ /* Open the output file. For multiple input files force each
+ * output to a new image, when reading from stdin or only one
+ * bitmap write to stdout if we didn't set the rootname.
+ */
+ if (numin <= 1 && strcmp (root, s_root) == 0) {
+ fdo = stdout;
+ } else {
+ if (numin > 1)
+ sprintf (fname, "%s%d.gif", root, index);
+ else
+ sprintf (fname, "%s.gif", root);
+ fdo = fopen (fname, "w+");
+ }
+
+ /* Now unpack this bitmap to the output image as byte data. */
+ ip = pixels;
+ while (fread (buffer, len_buf, 1, fdi)) {
+ /* If we're on a MSB ordered machine wordswap the bitmap so
+ * it's in the correct order for unpacking to be interpreted
+ * as an LSB-ordered image.
+ */
+ if ( ! isSwapped ())
+ bswap4 (buffer, buffer, len_buf);
+
+ unpack1to8 ((ip+=px), buffer, px);
+ }
+
+ /* All set, write it out. */
+ GIFEncode (fdo, px, py, (interlace=0), (background=0), (bpp=1),
+ red, green, blue);
+
+ fflush (fdi);
+ fflush (fdo);
+ if (fdi != stdin)
+ fclose (fdi);
+ if (fdo != stdout)
+ fclose (fdo);
+ }
+
+ /* Clean up. */
+ free (buffer);
+ free (pixels);
+
+ return (0);
+}
+
+
+/* UNPACK1TO8 -- Unpack each bit in the bitmap to a byte on output.
+ */
+
+static void
+unpack1to8 (byte *dest, byte *src, int len)
+{
+ register int i, b;
+ byte c = 0;
+
+ for (i = 0, b = 0; i < len; i++) {
+ if (b > 7) {
+ b = 0;
+ c = (invert ? ~(*src++) : (*src++) );
+ }
+ *dest++ = (byte) ((c >> (b++)) & 1);
+ }
+}
+
+
+/* GIF Writing Procedures.
+ *
+ * Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>. A
+ * Lempel-Zim compression based on "compress". Original Copyright 1990,
+ * David Koblas, heavily modified since then....
+ */
+
+#define GIFBITS 12
+
+static int Width, Height;
+static int curx, cury;
+static long CountDown;
+static int Interlace;
+
+
+/* GIFENCODE -- GIF Image compression interface.
+ */
+
+static void
+GIFEncode (fp, GWidth, GHeight, GInterlace, Background, Bpp, Red, Green, Blue)
+FILE *fp;
+int GWidth, GHeight;
+int GInterlace;
+int Background;
+int Bpp;
+int Red[], Green[], Blue[];
+{
+ int B;
+ int RWidth, RHeight;
+ int LeftOfs, TopOfs;
+ int Resolution;
+ int ColorMapSize;
+ int InitCodeSize;
+ int i;
+
+ Interlace = GInterlace;
+
+ ColorMapSize = 1 << Bpp;
+
+ RWidth = Width = GWidth;
+ RHeight = Height = GHeight;
+ LeftOfs = TopOfs = 0;
+
+ Resolution = Bpp;
+
+ /* Calculate number of bits we are expecting */
+ CountDown = (long)Width * (long)Height;
+
+ /* The initial code size */
+ if (Bpp <= 1)
+ InitCodeSize = 2;
+ else
+ InitCodeSize = Bpp;
+
+ /* Set up the current x and y position */
+ curx = cury = 0;
+
+ /* Write the Magic header */
+ fwrite ((transparent ? "GIF89a" : "GIF87a"), 1, 6, fp);
+
+ /* Write out the screen width and height */
+ Putword (RWidth, fp);
+ Putword (RHeight, fp);
+
+ /* Indicate that there is a global colour map */
+ B = 0x80; /* Yes, there is a color map */
+
+ /* OR in the resolution */
+ B |= (Resolution - 1) << 5;
+
+ /* OR in the Bits per Pixel */
+ B |= (Bpp - 1);
+
+ /* Write it out */
+ fputc (B, fp);
+
+ /* Write out the Background colour */
+ fputc (Background, fp);
+
+ /* Byte of 0's (future expansion) */
+ fputc (0, fp);
+
+ /* Write out the Global Colour Map */
+ for (i = 0; i < ColorMapSize; ++i) {
+ fputc (Red[i], fp);
+ fputc (Green[i], fp);
+ fputc (Blue[i], fp);
+ }
+
+ /* If doing transparency, write the extension. */
+ if (transparent) {
+ fputc (0x21, fp); /* graphics extension... */
+ fputc (0xf9, fp); /* transparency... */
+ fputc (0x4, fp);
+ fputc (0x1, fp);
+ fputc (0x0, fp);
+ fputc (0x0, fp);
+ fputc ((char) 0, fp); /* background color index */
+ fputc (0x0, fp);
+ }
+
+ /* Write an Image separator */
+ fputc (',', fp);
+
+ /* Write the Image header */
+ Putword (LeftOfs, fp);
+ Putword (TopOfs, fp);
+ Putword (Width, fp);
+ Putword (Height, fp);
+
+ /* Write out whether or not the image is interlaced */
+ if (Interlace)
+ fputc (0x40, fp);
+ else
+ fputc (0x00, fp);
+
+ /* Write out the initial code size */
+ fputc (InitCodeSize, fp);
+
+ /* Go and actually compress the data */
+ compress (InitCodeSize + 1, fp);
+
+ /* Write out a Zero-length packet (to end the series) */
+ fputc (0, fp);
+
+ /* Write the GIF file terminator */
+ fputc (';', fp);
+}
+
+
+/* Bump the 'curx' and 'cury' to point to the next pixel
+ */
+static void
+BumpPixel()
+{
+ /* Bump the current X position */
+ ++curx;
+
+ /* If at the end of a scan line, set curx back to the beginning. */
+ if (curx == Width) {
+ curx = 0;
+ ++cury;
+ }
+}
+
+
+/* Return the next pixel from the image
+ */
+static int
+GIFNextPixel ()
+{
+ int r;
+
+ if (CountDown == 0)
+ return EOF;
+
+ --CountDown;
+ r = (int) pixels[ cury * ncols + curx ] ;
+ BumpPixel();
+ return r;
+}
+
+
+/* Write out a word to the GIF file
+ */
+static void
+Putword (w, fp)
+int w;
+FILE*fp;
+{
+ unsigned short val = w;
+
+ fputc (val & 0xff, fp);
+ fputc ((val / 256) & 0xff, fp);
+}
+
+
+/*
+ * GIF Image compression - modified 'compress'
+ *
+ * Based on: compress.c - File compression ala IEEE Computer, June 1984.
+ *
+ * By Authors: Spencer W. Thomas, Jim McKie, Steve Davies, Ken Turkowski,
+ * James A. Woods, Joe Orost
+ *
+ * Lempel-Ziv compression based on 'compress'. GIF modifications by
+ * David Rowley (mgardi@watdcsu.waterloo.edu)
+ */
+
+#define HSIZE 5003 /* 80% occupancy */
+
+static int n_bits; /* number of bits/code */
+static int maxbits = GIFBITS; /* user settable max # bits/code */
+static code_int maxcode; /* maximum code, given n_bits */
+ /* should NEVER generate this code */
+static code_int maxmaxcode = (code_int) 1 << GIFBITS;
+#define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1)
+
+static count_int htab[HSIZE];
+static unsigned short codetab [HSIZE];
+#define HashTabOf(i) htab[i]
+#define CodeTabOf(i) codetab[i]
+
+/* To save much memory, we overlay the table used by compress() with those
+ * used by decompress(). The tab_prefix table is the same size and type
+ * as the codetab. The tab_suffix table needs 2**GIFBITS characters. We
+ * get this from the beginning of htab. The output stack uses the rest
+ * of htab, and contains characters. There is plenty of room for any
+ * possible stack (stack used to be 8000 characters).
+ */
+
+#define tab_prefixof(i) CodeTabOf(i)
+#define tab_suffixof(i) ((unsigned char *)(htab))[i]
+
+static code_int free_ent = 0; /* first unused entry */
+static code_int hsize = HSIZE; /* for dynamic table sizing */
+
+
+/* block compression parameters -- after all codes are used up,
+ * and compression rate changes, start over.
+ */
+static int clear_flg = 0;
+
+/*
+ * compress stdin to stdout
+ *
+ * Algorithm: use open addressing double hashing (no chaining) on the
+ * prefix code / next character combination. We do a variant of Knuth's
+ * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
+ * secondary probe. Here, the modular division first probe is gives way
+ * to a faster exclusive-or manipulation. Also do block compression with
+ * an adaptive reset, whereby the code table is cleared when the compression
+ * ratio decreases, but after the table fills. The variable-length output
+ * codes are re-sized at this point, and a special CLEAR code is generated
+ * for the decompressor. Late addition: construct the table according to
+ * file size for noticeable speed improvement on small files. Please direct
+ * questions about this implementation to ames!jaw.
+ */
+
+static FILE *g_outfile;
+static int g_init_bits;
+static int ClearCode;
+static int EOFCode;
+static int cur_bits = 0;
+
+static unsigned long cur_accum = 0;
+static unsigned long masks[] = {
+ 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
+ 0x001F, 0x003F, 0x007F, 0x00FF,
+ 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
+ 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
+
+static int a_count; /* Number of characters so far in this 'packet' */
+static char accum[256]; /* Define the storage for the packet accumulator */
+
+static void
+compress (init_bits, outfile)
+int init_bits;
+FILE *outfile;
+{
+ register long fcode;
+ register code_int i /* = 0 */;
+ register int c;
+ register code_int ent;
+ register code_int disp;
+ register code_int hsize_reg;
+ register int hshift;
+
+ /* Set up the globals: g_init_bits - initial number of bits
+ * g_outfile - pointer to output file
+ */
+ g_init_bits = init_bits;
+ g_outfile = outfile;
+
+ /* Set up the necessary values */
+ clear_flg = 0;
+ cur_accum = 0;
+ cur_bits = 0;
+ maxbits = GIFBITS;
+ maxcode = MAXCODE(n_bits = g_init_bits);
+
+ ClearCode = (1 << (init_bits - 1));
+ EOFCode = ClearCode + 1;
+ free_ent = ClearCode + 2;
+
+ char_init();
+ for (i=0; i<HSIZE; i++) {
+ htab[i] = 0;
+ codetab[i] = 0;
+ }
+
+ ent = GIFNextPixel ();
+
+ hshift = 0;
+ for (fcode = (long) hsize; fcode < 65536L; fcode *= 2L)
+ ++hshift;
+ hshift = 8 - hshift; /* set hash code range bound */
+
+ hsize_reg = hsize;
+ cl_hash ((count_int) hsize_reg); /* clear hash table */
+
+ output ((code_int)ClearCode);
+
+ while ((c = GIFNextPixel ()) != EOF) {
+
+ fcode = (long) (((long) c << maxbits) + ent);
+ i = (((code_int)c << hshift) ^ ent); /* xor hashing */
+
+ if (HashTabOf (i) == fcode) {
+ ent = CodeTabOf (i);
+ continue;
+ } else if ((long)HashTabOf (i) < 0) /* empty slot */
+ goto nomatch;
+ disp = hsize_reg - i; /* secondary hash (after G. Knott) */
+ if (i == 0)
+ disp = 1;
+probe:
+ if ((i -= disp) < 0)
+ i += hsize_reg;
+
+ if (HashTabOf (i) == fcode) {
+ ent = CodeTabOf (i);
+ continue;
+ }
+ if ((long)HashTabOf (i) > 0)
+ goto probe;
+nomatch:
+ output ((code_int) ent);
+ ent = c;
+ if (free_ent < maxmaxcode) { /* } */
+ CodeTabOf (i) = free_ent++; /* code -> hashtable */
+ HashTabOf (i) = fcode;
+ } else
+ cl_block();
+ }
+
+ /*
+ * Put out the final code.
+ */
+ output ((code_int)ent);
+ output ((code_int) EOFCode);
+}
+
+/*
+ * Output the given code.
+ * Inputs:
+ * code: A n_bits-bit integer. If == -1, then EOF. This assumes
+ * that n_bits =< (long)wordsize - 1.
+ * Outputs:
+ * Outputs code to the file.
+ * Assumptions:
+ * Chars are 8 bits long.
+ * Algorithm:
+ * Maintain a GIFBITS character long buffer (so that 8 codes will
+ * fit in it exactly). Use the VAX insv instruction to insert each
+ * code in turn. When the buffer fills up empty it and start over.
+ */
+
+static void
+output (code)
+code_int code;
+{
+ cur_accum &= masks[ cur_bits ];
+
+ if (cur_bits > 0)
+ cur_accum |= ((long)code << cur_bits);
+ else
+ cur_accum = code;
+
+ cur_bits += n_bits;
+
+ while (cur_bits >= 8) {
+ char_out ((unsigned int)(cur_accum & 0xff));
+ cur_accum >>= 8;
+ cur_bits -= 8;
+ }
+
+ /*
+ * If the next entry is going to be too big for the code size,
+ * then increase it, if possible.
+ */
+ if (free_ent > maxcode || clear_flg) {
+
+ if (clear_flg) {
+ maxcode = MAXCODE (n_bits = g_init_bits);
+ clear_flg = 0;
+ } else {
+ ++n_bits;
+ if (n_bits == maxbits)
+ maxcode = maxmaxcode;
+ else
+ maxcode = MAXCODE(n_bits);
+ }
+ }
+
+ if (code == EOFCode) {
+ /* At EOF, write the rest of the buffer. */
+ while (cur_bits > 0) {
+ char_out ((unsigned int)(cur_accum & 0xff));
+ cur_accum >>= 8;
+ cur_bits -= 8;
+ }
+ flush_char();
+ fflush (g_outfile);
+ if (ferror (g_outfile))
+ perror ("error writing output file");
+ }
+}
+
+/*
+ * Clear out the hash table
+ */
+static void
+cl_block () /* table clear for block compress */
+{
+
+ cl_hash ((count_int) hsize);
+ free_ent = ClearCode + 2;
+ clear_flg = 1;
+
+ output ((code_int)ClearCode);
+}
+
+static void
+cl_hash(hsize) /* reset code table */
+register count_int hsize;
+{
+
+ register count_int *htab_p = htab + hsize;
+
+ register long i;
+ register long m1 = -1;
+
+ i = hsize - 16;
+ do { /* might use Sys V memset(3) here */
+ *(htab_p - 16) = m1;
+ *(htab_p - 15) = m1;
+ *(htab_p - 14) = m1;
+ *(htab_p - 13) = m1;
+ *(htab_p - 12) = m1;
+ *(htab_p - 11) = m1;
+ *(htab_p - 10) = m1;
+ *(htab_p - 9) = m1;
+ *(htab_p - 8) = m1;
+ *(htab_p - 7) = m1;
+ *(htab_p - 6) = m1;
+ *(htab_p - 5) = m1;
+ *(htab_p - 4) = m1;
+ *(htab_p - 3) = m1;
+ *(htab_p - 2) = m1;
+ *(htab_p - 1) = m1;
+ htab_p -= 16;
+ } while ((i -= 16) >= 0);
+
+ for (i += 16; i > 0; --i)
+ *--htab_p = m1;
+}
+
+/* Set up the 'byte output' routine
+ */
+static void
+char_init()
+{
+ register int i;
+
+ a_count = 0;
+ for (i=0; i<256; i++)
+ accum[i] = 0;
+}
+
+/* Add a character to the end of the current packet, and if it is 254
+ * characters, flush the packet to disk.
+ */
+static void
+char_out (c)
+int c;
+{
+ accum[ a_count++ ] = c;
+ if (a_count >= 254)
+ flush_char();
+}
+
+/* Flush the packet to disk, and reset the accumulator */
+static void
+flush_char()
+{
+ if (a_count > 0) {
+ fputc (a_count, g_outfile);
+ fwrite (accum, 1, a_count, g_outfile);
+ a_count = 0;
+ }
+}
diff --git a/unix/gdev/sgidev/sgi2svg.c b/unix/gdev/sgidev/sgi2svg.c
new file mode 100644
index 00000000..be25a704
--- /dev/null
+++ b/unix/gdev/sgidev/sgi2svg.c
@@ -0,0 +1,245 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#define import_spp
+#define import_error
+#include <iraf.h>
+
+#include "sgiUtil.h"
+
+
+/*
+** SGI2SVG.C -- Read IRAF SGI metacode from standard input, translate into
+** Scalable Vector Graphics (SVG) format.
+**
+** Usage
+** sgi2svg.e [-params] [sgi_metacode] [| lpr -Papple]
+**
+** -fg <N> FG color specified as RGB triplet (e.g. 'F00' is red)
+** -bg <N> BG color specified as RGB triplet (e.g. '0F0' is green)
+** -fill <N> fill color specified as RGB triplet (e.g. '00F' is blue)
+** -w <N> width of plot, device pixels starting from l
+** -h <N> height of plot, device pixels starting from b
+** -p <N> pen width
+**
+** Option values must be separated from their flags by a space; the input
+** file name and the switches may occur in any order.
+**
+** Sample Graphcap:
+**
+** g-svg|UNIX generic interface to SVG file generator:\
+** :DD=usvg,tmp$sgk,!{ sgidispatch sgi2svg -w $(PX) -h $(PY) \
+** -bg FFF -fg 000 -fill FFF $F > sgi$$.svg ; }&:PX#640:PY#480:\
+** :kf=bin$x_sgikern.e:tn=sgikern:tc=sgi_apl:
+*/
+
+#define OSOK 0 /* normal successful completion */
+#define LEN_MCBUF 1024 /* number of SGK instrs in buffer */
+#define SGK_FRAME 1 /* new frame instruction */
+#define SGK_MOVE 2 /* move pen */
+#define SGK_DRAW 3 /* draw pen */
+#define SGK_SETLW 4 /* set line width */
+#define GKI_MAXNDC 32767. /* SGK units */
+
+
+/* Device opcodes and parameters.
+ */
+#define DEF_LEFT 0 /* origin in device pixels in x */
+#define DEF_BOTTOM 0 /* origin in device pixels in y */
+#define DEF_WIDTH 640 /* width in x (240d/i, 11" paper) */
+#define DEF_HEIGHT 480 /* height in y (240d/i, 8.5" paper)*/
+#define DEF_PENWIDTH 1 /* origin in device pixels in x */
+
+
+/* Commands to setup SVG environment.
+*/
+static char *svg_prolog[] = {
+ "<?xml version=\"1.0\" standalone=\"no\"?>\n",
+ "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
+ " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
+ NULL
+};
+
+/* Opcode instruction.
+*/
+struct sgi_inst {
+ short opcode;
+ short x, y;
+};
+
+
+int pen_width = DEF_PENWIDTH; /* initial line width */
+int width = DEF_WIDTH; /* margins */
+int height = DEF_HEIGHT;
+char *bg = "#FFF"; /* BG/FG colors */
+char *fg = "#000";
+char *fill = "#FFF"; /* vector fill color */
+
+
+static void translate (FILE *in, FILE *out);
+
+
+
+/* MAIN -- Main entry point for SGI2UHPGL. Optional arguments are device
+** window parameters and name of input file.
+*/
+int
+main (int argc, char *argv[])
+{
+ FILE *in;
+ char *infile = "stdin", *argp;
+ int argno;
+ register char **lp;
+
+
+ /* Process the command line.
+ */
+ for (argno=1; (argp = argv[argno]) != NULL; argno++) {
+ if (argp[0] == '-') {
+ /* A window-control or pen width switch.
+ */
+ switch (argp[1]) {
+ case 'f':
+ if (argp[2] == 'g')
+ fg = argv[++argno];
+ else
+ fill = argv[++argno];
+ break;
+ case 'b':
+ bg = argv[++argno];
+ break;
+ case 'w': width = atoi (argv[++argno]); break;
+ case 'h': height = atoi (argv[++argno]); break;
+ case 'p': pen_width = atoi (argv[++argno]); break;
+ default:
+ break;
+ }
+
+ } else {
+ /* Input sgi-metacode file specification.
+ */
+ infile = argp;
+ }
+ }
+
+
+ /* Open the input file. */
+ if (strcmp (infile, "stdin") == 0)
+ in = stdin;
+ else
+ in = fopen (infile, "r");
+ if (in == NULL) {
+ fprintf (stderr, "Fatal error (sgi2svg): Cannot open `%s'\n",
+ infile);
+ fflush (stderr);
+ exit (OSOK+1);
+ }
+
+
+ /* Output the standard prolog.
+ */
+ for (lp=svg_prolog; *lp; lp++)
+ fputs (*lp, stdout);
+
+ fprintf (stdout,"<svg width=\"%dpx\" height=\"%dpx\" version=\"1.1\"\n",
+ width, height);
+ fprintf (stdout," xmlns=\"http://www.w3.org/2000/svg\">");
+ fprintf (stdout,
+ "<g id=\"g0\" fill=\"#%s\" stroke=\"#%s\" stroke-width=\"1\">\n",
+ bg, fg);
+ fprintf (stdout,
+ "<rect x=\"1\" y=\"1\" width=\"%d\" height=\"%d\"\n",
+ width, height);
+ fprintf (stdout,
+ " fill=\"#%s\" stroke=\"#%s\" stroke-width=\"1\"/>\n", fill, bg);
+
+
+
+ /* Process the metacode.
+ */
+ translate (in, stdout);
+
+
+ /* Clean up.
+ */
+ fprintf (stdout, "</g></svg>"); /* output the end of file */
+ if (in != stdin)
+ fclose (in);
+
+ return (0);
+}
+
+
+/* TRANSLATE -- Interpret input SGI metacode instructions into device
+** instructions and write to stdout.
+*/
+static void
+translate (FILE *in, FILE *out)
+{
+ register struct sgi_inst *sgip;
+ struct sgi_inst inbuf[LEN_MCBUF], *buftop;
+ int n, in_stroke=0, swap_bytes = isSwapped();
+ int x, y, gnum=1;
+
+
+ /* Process the metacode:
+ */
+ while ((n = fread ((char *)inbuf, sizeof(*sgip), LEN_MCBUF, in)) > 0) {
+ if (swap_bytes)
+ bswap2 ((unsigned char *)inbuf, (unsigned char *)inbuf,
+ sizeof(*sgip) * n);
+
+ buftop = inbuf + n;
+
+ for (sgip = inbuf; sgip < buftop; sgip++) {
+ switch (sgip->opcode) {
+ case SGK_FRAME:
+ fprintf (out, "\n");
+ break;
+
+ case SGK_MOVE:
+ x = (int) (((float)sgip->x / GKI_MAXNDC) * width);
+ y = (int) (((float)sgip->y / GKI_MAXNDC) * height);
+ y = height - y + 1;
+ if (in_stroke) /* end current stroke */
+ fprintf (out, "\"/>");
+
+ /* Begin a new output stroke.
+ */
+ fprintf (out, "<polyline points=\"%d,%d", x, y);
+ in_stroke = 1;
+ break;
+
+ case SGK_DRAW:
+ x = (int) (((float)sgip->x / GKI_MAXNDC) * width);
+ y = (int) (((float)sgip->y / GKI_MAXNDC) * height);
+ y = height - y + 1;
+ fprintf (out, " %d,%d", x, y);
+ in_stroke = 1;
+ break;
+
+ case SGK_SETLW:
+ /* Set pen width.
+ */
+ pen_width = sgip->x + 1;
+ if (in_stroke) /* end current stroke */
+ fprintf (out, "\"/></g>");
+ fprintf (out, "<g id=\"g%d\" stroke-width=\"%d\">",
+ gnum++, pen_width);
+ in_stroke = 0;
+ break;
+
+ default:
+ fprintf (stderr, "sgi2svg: unrecognized sgi opcode %d\n",
+ sgip->opcode);
+ break;
+ }
+ }
+ }
+
+ /* Terminate plotting and exit.
+ */
+ fprintf (out, " \"/></g>\n");
+}
diff --git a/unix/gdev/sgidev/sgi2uapl.c b/unix/gdev/sgidev/sgi2uapl.c
new file mode 100644
index 00000000..3c59d284
--- /dev/null
+++ b/unix/gdev/sgidev/sgi2uapl.c
@@ -0,0 +1,545 @@
+/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <pwd.h>
+
+#ifdef SOLARIS
+#include <sys/systeminfo.h>
+#endif
+
+#define import_spp
+#define import_error
+#include <iraf.h>
+
+#include "sgiUtil.h"
+
+
+/*
+ * SGI2UAPL.C -- Read IRAF SGI metacode from standard input, translate into
+ * Postscript for the Apple Laserwriter and write to standard output.
+ *
+ * Usage:
+ *
+ * sgi2uapl.e [-params] [sgi_metacode] [| lpr -Plw]
+ *
+ * -4 use 4 byte point encoding scheme (default is 7 byte)
+ * -t omit the timestamp/logo normally written to corner of plot
+ * -l N left edge; x plot origin in device pixels
+ * -b N bottom edge; y plot origin in device pixels
+ * -w N width of plot, device pixels starting from l
+ * -h N height of plot, device pixels starting from b
+ * -p O.S pen width `origin' and `slope'
+ *
+ * Numeric values may be appended directly to their flags or separated by a
+ * space; the input file name and the switches may occur in any order.
+ * Note that you can arrange for the Postscript output to be saved in a file
+ * as well as directed to the printer by calling the translator as
+ *
+ * sgi2uapl.e [params] | tee -a file | lpr -Plw
+ */
+
+#define OSOK 0 /* normal successful completion */
+#define LEN_MCBUF 1024 /* number of SGK instrs in buffer */
+#define SGK_FRAME 1 /* new frame instruction */
+#define SGK_MOVE 2 /* move pen */
+#define SGK_DRAW 3 /* draw pen */
+#define SGK_SETLW 4 /* set line width */
+#define SGK_MAXNDC 32767 /* SGK units */
+
+/* Device opcodes and parameters. The default edge and width parameters (DEF_)
+ * are given in Apple Laserwriter pixels, at 300 dots/inch. Although bypassing
+ * the device-independence of Postscript, this achieves greater efficiency
+ * both in translator performance and in transmission rate to the plotter.
+ * The device y-origin is at the lower left corner of the page, but we take
+ * care of this with a Postscript coordinate transformation. Thus the maximum
+ * page `width' is 11*300 pixels, `height' is 8.5*300 pixels.
+ */
+#define DEV_FRAME "showpage setcoords setjoins\n" /* newframe */
+#define DEV_SETLW "setlinewidth\n" /* linewidth */
+
+#define MAX_POINTS 512 /* maximum points on stack before a STROKE */
+#define DEF_LEFT 30 /* origin in device pixels in x */
+#define DEF_WIDTH 3180 /* width in x (300d/i, 11" paper) */
+#define DEF_BOTTOM 60 /* origin in device pixels in y */
+#define DEF_HEIGHT 2415 /* height in y (300d/i, 8.5" paper) */
+#define DEF_PENBASE 3 /* base pen width (LW 1->2) */
+#define DEF_PENSLOPE 4 /* pen width slope (LW 2->4, 3->6 etc.) */
+#define SZ_PENCMD 16 /* total no. of chars in penwidth instruction */
+#define SZ_PENVAL 2 /* no. of chars in penwidth value */
+#define SZ_VCODE 7 /* no. of chars in MOVE or DRAW opcode */
+#define SZ_VECT 17 /* total no. chars in a MOVE or DRAW inst. */
+#define SZ_COORD 4 /* no. of chars in device coordinate */
+#define XY_MOVE 0
+#define XY_DRAW 1
+
+struct sgi_inst {
+ short opcode;
+ short x;
+ short y;
+};
+
+/* Commands to setup Postscript environment.
+ */
+static char *ps_init[] = {
+ "%!PS-Adobe-2.0",
+ "/devppi 300 def",
+ "/userppi 72 def",
+ "/pagewidth 8.5 def",
+ "/devpixtouser { userppi mul devppi div } def",
+ "/pagetolandscape 90 def",
+ "/setcoords { pagewidth userppi mul 0 translate",
+ " pagetolandscape rotate 1 devpixtouser 1 devpixtouser scale } def",
+ "/setjoins { 1 setlinejoin 1 setlinecap } def",
+ "erasepage initgraphics setcoords setjoins",
+ NULL };
+
+/* 7BYTE -- Postscript procedures to move or draw, with the X,Y coordinates
+ * encoded as a 4 byte sequence (7 bytes including the command name and spaces)
+ * following the command name. This is the fastest encoding, since it
+ * minimizes the Postscript interpreter execution time.
+ *
+ * bit 76543210
+ * ------------------------------------------
+ * 0 01XXXXXX hi 6 X bits
+ * 1 01XXXXXX li 6 X bits
+ * 2 01YYYYYY hi 6 Y bits
+ * 3 01YYYYYY lo 6 Y bits
+ */
+static char *ps_7byte[] = {
+ "/getpoint {",
+ " currentfile read pop 8#77 and 6 bitshift",
+ " currentfile read pop 8#77 and or",
+ " currentfile read pop 8#77 and 6 bitshift",
+ " currentfile read pop 8#77 and or",
+ " } def",
+ "/m { getpoint moveto } def",
+ "/d { getpoint lineto } def",
+ NULL };
+
+/* 4BYTE -- Postscript procedure to draw an arbitrary series of vectors,
+ * encoded 4 bytes per point. This is the most space efficient encoding,
+ * but the runtime may be somewhat longer than for the 7byte encoding,
+ * due to the Postscript interpreter overhead.
+ *
+ * Optional Flag byte:
+ * > move instruction
+ * + draw instruction
+ * $ terminate plotting
+ * other ignored (e.g., whitespace)
+ *
+ * Point Encoding:
+ * bit 76543210
+ * ------------------------------------------
+ * 1 01XXXXXX hi 6 X bits
+ * 2 01XXXXXX lo 6 X bits
+ * 3 01YYYYYY hi 6 Y bits
+ * 4 01YYYYYY lo 6 Y bits
+ *
+ * Data points are encoded 12 bits (0-4095) per X,Y coordinate. The flag byte
+ * is used as the terminator, to toggle the move/draw state, and to permit
+ * whitespace to be ignored. A high bit is set in each byte to ensure a
+ * printable character, as control codes would interfere with the operation of
+ * the Postscript interpreter.
+ */
+#define CH_MOVE '>'
+#define CH_DRAW '+'
+#define CH_EXITPLOT '$'
+
+static char *ps_4byte[] = {
+ "/plot { /movepen { moveto } def",
+ " { currentfile read not { exit } if",
+ " { dup 8#100 ge",
+ " { exit }",
+ " { dup 8#076 eq",
+ " { pop /movepen { moveto } def",
+ " currentfile read not { exit } if }",
+ " { dup 8#053 eq",
+ " { pop /movepen { lineto } def",
+ " currentfile read not { exit } if }",
+ " { dup 8#044 eq",
+ " { exit }",
+ " { pop currentfile read not { exit } if }",
+ " ifelse }",
+ " ifelse }",
+ " ifelse }",
+ " ifelse",
+ " } loop",
+ " dup 8#044 eq { pop exit } { 8#77 and 6 bitshift } ifelse",
+ " currentfile read pop 8#77 and or",
+ " currentfile read pop 8#77 and 6 bitshift",
+ " currentfile read pop 8#77 and or",
+ " movepen",
+ " } loop",
+ " } def",
+ NULL };
+
+static int fourbyte = 0;
+static int penmode = -1;
+static int omit_logo = 0;
+static int dev_left;
+static int dev_bottom;
+static int dev_width;
+static int dev_height;
+static int dev_penbase = DEF_PENBASE;
+static int dev_penslope = DEF_PENSLOPE;
+static int npts = 0;
+
+
+static void translate (FILE *in, FILE *out);
+static char *make_label (void);
+static void textout (FILE *out, char *text[]);
+static char *penencode (int val, char *code);
+static void xy_flush (FILE *out);
+static void xy_point (FILE *out, register int x, register int y, int flag);
+
+
+
+/* MAIN -- Main entry point for SGI2UAPL. Optional arguments are device
+ * window parameters and name of input file.
+ */
+int
+main (int argc, char *argv[])
+{
+ FILE *in;
+ char *infile;
+ char *argp;
+ int argno;
+ int np;
+ char penparam[SZ_PENCMD];
+
+
+ infile = "stdin";
+
+ /* Process the command line.
+ */
+ for (argno=1; (argp = argv[argno]) != NULL; argno++) {
+ if (argp[0] == '-') {
+ /* A window-control or pen width switch.
+ */
+ switch (argp[1]) {
+ case '4':
+ fourbyte++;
+ break;
+ case 't':
+ omit_logo++;
+ break;
+ case 'l':
+ dev_left = get_iarg (argp[2], argv, argno, DEF_LEFT);
+ break;
+ case 'b':
+ dev_bottom = get_iarg (argp[2], argv, argno, DEF_BOTTOM);
+ break;
+ case 'w':
+ dev_width = get_iarg (argp[2], argv, argno, DEF_WIDTH);
+ break;
+ case 'h':
+ dev_height = get_iarg (argp[2], argv, argno, DEF_HEIGHT);
+ break;
+ case 'p':
+ if (argp[2] == (char) 0)
+ if (argv[argno+1] == NULL) {
+ fprintf (stderr, "missing arg to switch `%s';",
+ argp);
+ fprintf (stderr, " reset to %d.%d\n", dev_penbase,
+ dev_penslope);
+ } else
+ strcpy (penparam, argv[++argno]);
+ else
+ strcpy (penparam, argv[argno]+2);
+
+ np = sscanf (penparam, "%d . %d", &dev_penbase,
+ &dev_penslope);
+ if (np == 1) {
+ dev_penslope = dev_penbase;
+ } else if (np < 1) {
+ dev_penbase = DEF_PENBASE;
+ dev_penslope = DEF_PENSLOPE;
+ }
+
+ break;
+ default:
+ fprintf (stderr, "sgi2uapl: unknown switch '%s'\n", argp);
+ }
+
+ } else {
+ /* Input sgi-metacode file specification.
+ */
+ infile = argp;
+ }
+ }
+
+ if (strcmp (infile, "stdin") == 0)
+ in = stdin;
+ else
+ in = fopen (infile, "r");
+
+ if (in == NULL) {
+ fprintf (stderr, "Fatal error (sgi2uapl): Cannot open `%s'\n",
+ infile);
+ fflush (stderr);
+ exit (OSOK+1);
+ }
+
+ /* Process the metacode.
+ */
+ translate (in, stdout);
+
+ if (in != stdin)
+ fclose (in);
+
+ return (0);
+}
+
+
+/* TRANSLATE -- Interpret input SGI metacode instructions into device
+ * instructions and write to stdout.
+ */
+static void
+translate (FILE *in, FILE *out)
+{
+ register struct sgi_inst *sgip;
+ struct sgi_inst inbuf[LEN_MCBUF], *buftop;
+ int n, x, y, curpoints = 0, swap_bytes;
+ float xscale, yscale;
+
+
+ swap_bytes = isSwapped();
+
+ xscale = (float) dev_width / (float) SGK_MAXNDC;
+ yscale = (float) dev_height / (float) SGK_MAXNDC;
+
+ /* Output device initialization. */
+ textout (out, ps_init);
+
+ /* Define the Postscript plotting procedures. */
+ if (fourbyte)
+ textout (out, ps_4byte);
+ else
+ textout (out, ps_7byte);
+
+ /* Initialize pen width. */
+ fwrite (penencode (dev_penbase, DEV_SETLW), SZ_PENCMD, 1, out);
+
+ /* Process the metacode:
+ */
+ while ((n = fread ((char *)inbuf, sizeof(*sgip), LEN_MCBUF, in)) > 0) {
+ if (swap_bytes)
+ bswap2 ((unsigned char *)inbuf, (unsigned char *)inbuf,
+ sizeof(*sgip) * n);
+
+ buftop = inbuf + n;
+
+ for (sgip = inbuf; sgip < buftop; sgip++) {
+ switch (sgip->opcode) {
+ case SGK_FRAME:
+ xy_flush (out);
+ fprintf (out, DEV_FRAME);
+ break;
+
+ case SGK_MOVE:
+ x = dev_left + sgip->x * xscale;
+ y = dev_bottom + sgip->y * yscale;
+ xy_point (out, x, y, XY_MOVE);
+ break;
+
+ case SGK_DRAW:
+ x = dev_left + sgip->x * xscale;
+ y = dev_bottom + sgip->y * yscale;
+ xy_point (out, x, y, XY_DRAW);
+
+ /* Limit number of points passed to Postscript between
+ * 'stroke' commands to draw the buffered points.
+ */
+ curpoints = curpoints + 1;
+ if (curpoints > MAX_POINTS) {
+ xy_flush (out);
+ xy_point (out, x, y, XY_MOVE);
+ curpoints = 0;
+ }
+ break;
+
+ case SGK_SETLW: {
+ /* Set pen width.
+ */
+ int x = max (0, sgip->x - 1);
+
+ xy_flush (out);
+ curpoints = 0;
+ fwrite (penencode (
+ max (1, dev_penbase + x * dev_penslope), DEV_SETLW),
+ SZ_PENCMD, 1, out);
+ }
+ break;
+
+ default:
+ fprintf (stderr, "sgi2uapl: unrecognized sgi opcode %d\n",
+ sgip->opcode);
+ break;
+ }
+ }
+ }
+
+ /* Terminate plotting and exit.
+ */
+ xy_flush (out);
+
+ /* Add the NOAO logo and timestamp at the bottom of the page and
+ * output the page.
+ */
+ if (!omit_logo) {
+ fprintf (out, "/Times-Roman findfont 24 scalefont setfont\n");
+
+ /* fprintf (out, "[-1 0 0 -1 2350 3180] setmatrix\n"); */
+ fprintf (out, "initmatrix\n");
+ fprintf (out, "-1 72 mul 300 div 1 72 mul 300 div scale\n");
+ fprintf (out, "-2409 88 translate\n");
+
+ fprintf (out, "%d %d moveto\n", 1600, 3150);
+ fprintf (out, "[1 0 0 -1 0 0] concat\n");
+ fprintf (out, "(%s) show\n", make_label());
+ }
+
+ fprintf (out, "showpage\n");
+}
+
+
+/* XY_POINT -- Output a move or draw instruction, using either the 4 byte or
+ * 7 byte encoding scheme.
+ */
+static void
+xy_point (
+ FILE *out, /* output file */
+ register int x, /* coords to move to */
+ register int y, /* coords to move to */
+ int flag /* move or draw? */
+)
+{
+ static char o[] = "m XXXX";
+ register char *op = o;
+ register int n;
+
+ if (fourbyte) {
+ if (npts == 0) {
+ fputs ("plot\n", out);
+ penmode = XY_MOVE;
+ }
+
+ if (flag != penmode)
+ *op++ = ((penmode = flag) == XY_MOVE) ? CH_MOVE : CH_DRAW;
+
+ *op++ = ((n = ((x >> 6) & 077)) == 077) ? n : (0100 | n);
+ *op++ = ((n = (x & 077)) == 077) ? n : (0100 | n);
+ *op++ = ((n = ((y >> 6) & 077)) == 077) ? n : (0100 | n);
+ *op++ = ((n = (y & 077)) == 077) ? n : (0100 | n);
+
+ fwrite (o, op-o, 1, out);
+ if (!(++npts % 15))
+ fputc ('\n', out);
+
+ } else {
+ o[0] = (flag == XY_MOVE) ? 'm' : 'd';
+ o[2] = ((n = ((x >> 6) & 077)) == 077) ? n : (0100 | n);
+ o[3] = ((n = (x & 077)) == 077) ? n : (0100 | n);
+ o[4] = ((n = ((y >> 6) & 077)) == 077) ? n : (0100 | n);
+ o[5] = ((n = (y & 077)) == 077) ? n : (0100 | n);
+
+ fwrite (o, 6, 1, out);
+ if (!(++npts % 10))
+ fputc ('\n', out);
+ else
+ fputc (' ', out);
+ }
+}
+
+
+/* XY_FLUSH -- Terminate the current drawing sequence, if any, and issue the
+ * stroke command to Postscript to draw the buffered points.
+ */
+static void
+xy_flush (FILE *out)
+{
+ if (npts > 0) {
+ if (fourbyte)
+ fputs ("$\n", out);
+ else if (npts % 10)
+ fputc ('\n', out);
+ fputs ("stroke\n", out);
+ npts = 0;
+ }
+}
+
+
+/* PENENCODE -- Encode base, slope into a character string formatted for the
+ * device set-pen command.
+ */
+static char *
+penencode (
+ int val, /* device line width */
+ char *code /* device set-linewidth command */
+)
+{
+ static char obuf[SZ_PENCMD+1];
+ register int digit, n;
+ register char *op, *ip;
+
+ for (op = &obuf[SZ_PENVAL-1], digit = SZ_PENVAL, n=val; --digit >= 0;
+ n = n / 10)
+ *op-- = n % 10 + '0';
+ obuf[SZ_PENVAL] = ' ';
+ for (op = &obuf[SZ_PENVAL+1], ip = code, n = SZ_PENCMD; --n >= 0; )
+ *op++ = *ip++;
+
+ return (obuf);
+}
+
+
+/* TEXTOUT -- Output lines of text to a file.
+ */
+static void
+textout (
+ FILE *out, /* output file */
+ char *text[] /* array of lines of text */
+)
+{
+ register char **lp;
+
+ for (lp=text; *lp; lp++) {
+ fputs (*lp, out);
+ fputc ('\n', out);
+ }
+}
+
+
+/* MAKE_LABEL -- Generate the label for the output printer page.
+ */
+static char *
+make_label (void)
+{
+ static char buf[128];
+ char hostname[32];
+ char username[32];
+ struct passwd *pw;
+ time_t clock;
+
+#ifdef SOLARIS
+ sysinfo (SI_HOSTNAME, hostname, 32);
+#else
+ gethostname (hostname, 32);
+#endif
+
+ clock = time(0);
+ pw = getpwuid (getuid());
+ strcpy (username, pw->pw_name);
+ endpwent();
+
+ sprintf (buf, "NOAO/IRAF %s@%s %s",
+ username, hostname, asctime(localtime(&clock)));
+
+ return (buf);
+}
diff --git a/unix/gdev/sgidev/sgi2ueps.c b/unix/gdev/sgidev/sgi2ueps.c
new file mode 100644
index 00000000..345eb702
--- /dev/null
+++ b/unix/gdev/sgidev/sgi2ueps.c
@@ -0,0 +1,530 @@
+/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <time.h>
+#include <pwd.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define import_spp
+#define import_error
+#include <iraf.h>
+
+#include "sgiUtil.h"
+
+
+/*
+ * SGI2UEPS.C -- Read IRAF SGI metacode from standard input, translate into
+ * Encapsulated Postscript and write to standard output.
+ *
+ * Usage:
+ *
+ * sgi2ueps.e [-params] [sgi_metacode] [| lpr -Plw]
+ *
+ * -4 use 4 byte point encoding scheme (default is 7 byte)
+ * -l N left edge; x plot origin in device pixels
+ * -b N bottom edge; y plot origin in device pixels
+ * -w N width of plot, device pixels starting from l
+ * -h N height of plot, device pixels starting from b
+ * -p O.S pen width `origin' and `slope'
+ *
+ * Numeric values may be appended directly to their flags or separated by a
+ * space; the input file name and the switches may occur in any order.
+ * Note that you can arrange for the Postscript output to be saved in a file
+ * as well as directed to the printer by calling the translator as
+ *
+ * sgi2ueps.e [params] | tee -a file | lpr -Plw
+ */
+
+#define OSOK 0 /* normal successful completion */
+#define LEN_MCBUF 1024 /* number of SGK instrs in buffer */
+#define SGK_FRAME 1 /* new frame instruction */
+#define SGK_MOVE 2 /* move pen */
+#define SGK_DRAW 3 /* draw pen */
+#define SGK_SETLW 4 /* set line width */
+#define SGK_MAXNDC 32767 /* SGK units */
+
+/* Device opcodes and parameters. The default edge and width parameters (DEF_)
+ * are given in pixels at 300 dots/inch. Although bypassing the
+ * device-independence of Postscript, this achieves greater efficiency
+ * both in translator performance and in transmission rate to the plotter.
+ * The device y-origin is at the lower left corner of the page, but we take
+ * care of this with a Postscript coordinate transformation. Thus the maximum
+ * page `width' is 11*300 pixels, `height' is 8.5*300 pixels.
+ */
+#define DEV_FRAME "showpage setcoords setjoins\n" /* newframe */
+#define DEV_SETLW "setlinewidth\n" /* linewidth */
+
+#define MAX_POINTS 512 /* maximum points on stack before a STROKE */
+#define DEF_LEFT 30 /* origin in device pixels in x */
+#define DEF_WIDTH 3180 /* width in x (300d/i, 11" paper) */
+#define DEF_BOTTOM 60 /* origin in device pixels in y */
+#define DEF_HEIGHT 2415 /* height in y (300d/i, 8.5" paper) */
+#define DEV_UNITS 300 /* EPS translator units: N per inch */
+#define EPS_UNITS 72 /* PostScript units (points) */
+#define DEF_PENBASE 3 /* base pen width (LW 1->2) */
+#define DEF_PENSLOPE 4 /* pen width slope (LW 2->4, 3->6 etc.) */
+#define SZ_PENCMD 16 /* total no. of chars in penwidth instruction */
+#define SZ_PENVAL 2 /* no. of chars in penwidth value */
+#define SZ_VCODE 7 /* no. of chars in MOVE or DRAW opcode */
+#define SZ_VECT 17 /* total no. chars in a MOVE or DRAW inst. */
+#define SZ_COORD 4 /* no. of chars in device coordinate */
+#define XY_MOVE 0
+#define XY_DRAW 1
+
+struct sgi_inst {
+ short opcode;
+ short x;
+ short y;
+};
+
+/* Commands to setup Postscript environment.
+ */
+static char *ps_init[] = {
+ "/devppi 300 def",
+ "/userppi 72 def",
+ "/pagewidth 8.5 def",
+ "/devpixtouser { userppi mul devppi div } def",
+ "/setscale { 1 devpixtouser 1 devpixtouser scale } def",
+ "/pagetolandscape 90 def",
+ "/setcoords { pagewidth userppi mul 0 translate",
+ " pagetolandscape rotate setscale } def",
+ "/setjoins { 1 setlinejoin 1 setlinecap } def",
+ NULL };
+
+static char *ps_endprolog[] = {
+ "%%EndProlog",
+ "%%Page: 1 1",
+ "gsave setscale setjoins",
+ NULL };
+
+/* 7BYTE -- Postscript procedures to move or draw, with the X,Y coordinates
+ * encoded as a 4 byte sequence (7 bytes including the command name and spaces)
+ * following the command name. This is the fastest encoding, since it
+ * minimizes the Postscript interpreter execution time.
+ *
+ * bit 76543210
+ * ------------------------------------------
+ * 0 01XXXXXX hi 6 X bits
+ * 1 01XXXXXX li 6 X bits
+ * 2 01YYYYYY hi 6 Y bits
+ * 3 01YYYYYY lo 6 Y bits
+ */
+static char *ps_7byte[] = {
+ "/getpoint {",
+ " currentfile read pop 8#77 and 6 bitshift",
+ " currentfile read pop 8#77 and or",
+ " currentfile read pop 8#77 and 6 bitshift",
+ " currentfile read pop 8#77 and or",
+ " } def",
+ "/m { getpoint moveto } def",
+ "/d { getpoint lineto } def",
+ NULL };
+
+/* 4BYTE -- Postscript procedure to draw an arbitrary series of vectors,
+ * encoded 4 bytes per point. This is the most space efficient encoding,
+ * but the runtime may be somewhat longer than for the 7byte encoding,
+ * due to the Postscript interpreter overhead.
+ *
+ * Optional Flag byte:
+ * > move instruction
+ * + draw instruction
+ * $ terminate plotting
+ * other ignored (e.g., whitespace)
+ *
+ * Point Encoding:
+ * bit 76543210
+ * ------------------------------------------
+ * 1 01XXXXXX hi 6 X bits
+ * 2 01XXXXXX lo 6 X bits
+ * 3 01YYYYYY hi 6 Y bits
+ * 4 01YYYYYY lo 6 Y bits
+ *
+ * Data points are encoded 12 bits (0-4095) per X,Y coordinate. The flag byte
+ * is used as the terminator, to toggle the move/draw state, and to permit
+ * whitespace to be ignored. A high bit is set in each byte to ensure a
+ * printable character, as control codes would interfere with the operation of
+ * the Postscript interpreter.
+ */
+#define CH_MOVE '>'
+#define CH_DRAW '+'
+#define CH_EXITPLOT '$'
+
+static char *ps_4byte[] = {
+ "/plot { /movepen { moveto } def",
+ " { currentfile read not { exit } if",
+ " { dup 8#100 ge",
+ " { exit }",
+ " { dup 8#076 eq",
+ " { pop /movepen { moveto } def",
+ " currentfile read not { exit } if }",
+ " { dup 8#053 eq",
+ " { pop /movepen { lineto } def",
+ " currentfile read not { exit } if }",
+ " { dup 8#044 eq",
+ " { exit }",
+ " { pop currentfile read not { exit } if }",
+ " ifelse }",
+ " ifelse }",
+ " ifelse }",
+ " ifelse",
+ " } loop",
+ " dup 8#044 eq { pop exit } { 8#77 and 6 bitshift } ifelse",
+ " currentfile read pop 8#77 and or",
+ " currentfile read pop 8#77 and 6 bitshift",
+ " currentfile read pop 8#77 and or",
+ " movepen",
+ " } loop",
+ " } def",
+ NULL };
+
+static int npts = 0;
+static int fourbyte = 0;
+static int penmode = -1;
+static int dev_left;
+static int dev_bottom;
+static int dev_width;
+static int dev_height;
+static int dev_penbase = DEF_PENBASE;
+static int dev_penslope = DEF_PENSLOPE;
+static char progname[SZ_LINE+1];
+
+static void translate (FILE *in, FILE *out);
+static void xy_point (FILE *out, register int x, register int y, int flag);
+static void xy_flush (FILE *out);
+static char *penencode (int val, char *code);
+static void textout (FILE *out, char *text[]);
+static void eps_comments (FILE *out);
+
+
+
+/* MAIN -- Main entry point for SGI2UAPL. Optional arguments are device
+ * window parameters and name of input file.
+ */
+int
+main (int argc, char *argv[])
+{
+ FILE *in;
+ char *infile;
+ char *argp;
+ int argno;
+ int np;
+ char penparam[SZ_PENCMD];
+
+
+ strcpy (progname, argv[0]);
+ infile = "stdin";
+
+ /* Process the command line.
+ */
+ for (argno=1; (argp = argv[argno]) != NULL; argno++) {
+ if (argp[0] == '-') {
+ /* A window-control or pen width switch.
+ */
+ switch (argp[1]) {
+ case '4':
+ fourbyte++;
+ break;
+ case 'l':
+ dev_left = get_iarg (argp[2], argv, argno, DEF_LEFT);
+ break;
+ case 'b':
+ dev_bottom = get_iarg (argp[2], argv, argno, DEF_BOTTOM);
+ break;
+ case 'w':
+ dev_width = get_iarg (argp[2], argv, argno, DEF_WIDTH);
+ break;
+ case 'h':
+ dev_height = get_iarg (argp[2], argv, argno, DEF_HEIGHT);
+ break;
+ case 'p':
+ if (argp[2] == (char) 0)
+ if (argv[argno+1] == NULL) {
+ fprintf (stderr, "missing arg to switch `%s';",
+ argp);
+ fprintf (stderr, " reset to %d.%d\n", dev_penbase,
+ dev_penslope);
+ } else
+ strcpy (penparam, argv[++argno]);
+ else
+ strcpy (penparam, argv[argno]+2);
+
+ np = sscanf (penparam, "%d . %d", &dev_penbase,
+ &dev_penslope);
+ if (np == 1) {
+ dev_penslope = dev_penbase;
+ } else if (np < 1) {
+ dev_penbase = DEF_PENBASE;
+ dev_penslope = DEF_PENSLOPE;
+ }
+
+ break;
+ default:
+ fprintf (stderr, "sgi2ueps: unknown switch '%s'\n", argp);
+ }
+
+ } else {
+ /* Input sgi-metacode file specification.
+ */
+ infile = argp;
+ }
+ }
+
+ if (strcmp (infile, "stdin") == 0)
+ in = stdin;
+ else
+ in = fopen (infile, "r");
+
+ if (in == NULL) {
+ fprintf (stderr, "Fatal error (sgi2ueps): Cannot open `%s'\n",
+ infile);
+ fflush (stderr);
+ exit (OSOK+1);
+ }
+
+ /* Process the metacode.
+ */
+ translate (in, stdout);
+
+ if (in != stdin)
+ fclose (in);
+
+ return (0);
+}
+
+
+/* TRANSLATE -- Interpret input SGI metacode instructions into device
+ * instructions and write to stdout.
+ */
+static void
+translate (FILE *in, FILE *out)
+{
+ register struct sgi_inst *sgip;
+ struct sgi_inst inbuf[LEN_MCBUF], *buftop;
+ int n, x, y, curpoints = 0, swap_bytes;
+ float xscale, yscale;
+
+
+ swap_bytes = isSwapped();
+
+ xscale = (float) dev_width / (float) SGK_MAXNDC;
+ yscale = (float) dev_height / (float) SGK_MAXNDC;
+
+ /* Output device initialization. */
+ eps_comments (out);
+ textout (out, ps_init);
+
+ /* Define the Postscript plotting procedures. */
+ if (fourbyte)
+ textout (out, ps_4byte);
+ else
+ textout (out, ps_7byte);
+
+ textout (out, ps_endprolog);
+
+ /* Initialize pen width. */
+ fwrite (penencode (dev_penbase, DEV_SETLW), SZ_PENCMD, 1, out);
+
+ /* Process the metacode:
+ */
+ while ((n = fread ((char *)inbuf, sizeof(*sgip), LEN_MCBUF, in)) > 0) {
+ if (swap_bytes)
+ bswap2 ((unsigned char *)inbuf, (unsigned char *)inbuf,
+ sizeof(*sgip) * n);
+
+ buftop = inbuf + n;
+
+ for (sgip = inbuf; sgip < buftop; sgip++) {
+ switch (sgip->opcode) {
+ case SGK_FRAME:
+ xy_flush (out);
+ fprintf (out, DEV_FRAME);
+ break;
+
+ case SGK_MOVE:
+ x = dev_left + sgip->x * xscale;
+ y = dev_bottom + sgip->y * yscale;
+ xy_point (out, x, y, XY_MOVE);
+ break;
+
+ case SGK_DRAW:
+ x = dev_left + sgip->x * xscale;
+ y = dev_bottom + sgip->y * yscale;
+ xy_point (out, x, y, XY_DRAW);
+
+ /* Limit number of points passed to Postscript between
+ * 'stroke' commands to draw the buffered points.
+ */
+ curpoints = curpoints + 1;
+ if (curpoints > MAX_POINTS) {
+ xy_flush (out);
+ xy_point (out, x, y, XY_MOVE);
+ curpoints = 0;
+ }
+ break;
+
+ case SGK_SETLW: {
+ /* Set pen width.
+ */
+ int x = max (0, sgip->x - 1);
+
+ xy_flush (out);
+ curpoints = 0;
+ fwrite (penencode (
+ max (1, dev_penbase + x * dev_penslope), DEV_SETLW),
+ SZ_PENCMD, 1, out);
+ }
+ break;
+
+ default:
+ fprintf (stderr, "sgi2ueps: unrecognized sgi opcode %d\n",
+ sgip->opcode);
+ break;
+ }
+ }
+ }
+
+ /* Terminate plotting and exit.
+ */
+ xy_flush (out);
+
+ fprintf (out, "grestore showpage\n");
+}
+
+
+/* XY_POINT -- Output a move or draw instruction, using either the 4 byte or
+ * 7 byte encoding scheme.
+ */
+static void
+xy_point (
+ FILE *out, /* output file */
+ register int x, /* coords to move to */
+ register int y, /* coords to move to */
+ int flag /* move or draw? */
+)
+{
+ static char o[] = "m XXXX";
+ register char *op = o;
+ register int n;
+
+ if (fourbyte) {
+ if (npts == 0) {
+ fputs ("plot\n", out);
+ penmode = XY_MOVE;
+ }
+
+ if (flag != penmode)
+ *op++ = ((penmode = flag) == XY_MOVE) ? CH_MOVE : CH_DRAW;
+
+ *op++ = ((n = ((x >> 6) & 077)) == 077) ? n : (0100 | n);
+ *op++ = ((n = (x & 077)) == 077) ? n : (0100 | n);
+ *op++ = ((n = ((y >> 6) & 077)) == 077) ? n : (0100 | n);
+ *op++ = ((n = (y & 077)) == 077) ? n : (0100 | n);
+
+ fwrite (o, op-o, 1, out);
+ if (!(++npts % 15))
+ fputc ('\n', out);
+
+ } else {
+ o[0] = (flag == XY_MOVE) ? 'm' : 'd';
+ o[2] = ((n = ((x >> 6) & 077)) == 077) ? n : (0100 | n);
+ o[3] = ((n = (x & 077)) == 077) ? n : (0100 | n);
+ o[4] = ((n = ((y >> 6) & 077)) == 077) ? n : (0100 | n);
+ o[5] = ((n = (y & 077)) == 077) ? n : (0100 | n);
+
+ fwrite (o, 6, 1, out);
+ if (!(++npts % 10))
+ fputc ('\n', out);
+ else
+ fputc (' ', out);
+ }
+}
+
+
+/* XY_FLUSH -- Terminate the current drawing sequence, if any, and issue the
+ * stroke command to Postscript to draw the buffered points.
+ */
+static void
+xy_flush (FILE *out)
+{
+ if (npts > 0) {
+ if (fourbyte)
+ fputs ("$\n", out);
+ else if (npts % 10)
+ fputc ('\n', out);
+ fputs ("stroke\n", out);
+ npts = 0;
+ }
+}
+
+
+/* PENENCODE -- Encode base, slope into a character string formatted for the
+ * device set-pen command.
+ */
+static char *
+penencode (
+ int val, /* device line width */
+ char *code /* device set-linewidth command */
+)
+{
+ static char obuf[SZ_PENCMD+1];
+ register int digit, n;
+ register char *op, *ip;
+
+ for (op = &obuf[SZ_PENVAL-1], digit = SZ_PENVAL, n=val; --digit >= 0;
+ n = n / 10)
+ *op-- = n % 10 + '0';
+ obuf[SZ_PENVAL] = ' ';
+ for (op = &obuf[SZ_PENVAL+1], ip = code, n = SZ_PENCMD; --n >= 0; )
+ *op++ = *ip++;
+
+ return (obuf);
+}
+
+
+/* TEXTOUT -- Output lines of text to a file.
+ */
+static void
+textout (
+ FILE *out, /* output file */
+ char *text[] /* array of lines of text */
+)
+{
+ register char **lp;
+
+ for (lp=text; *lp; lp++) {
+ fputs (*lp, out);
+ fputc ('\n', out);
+ }
+}
+
+
+/* EPS_COMMENTS -- Set identifying comments for EPS conformance.
+ */
+static void
+eps_comments (FILE *out)
+{
+ time_t clock;
+ int llx, lly, urx, ury;
+
+ clock = time(0);
+
+ fprintf (out, "%%!PS-Adobe-3.0 EPSF-3.0\n");
+ fprintf (out, "%%%%Title: IRAF SGI plot\n");
+ fprintf (out, "%%%%Creator: %s\n", progname);
+ fprintf (out, "%%%%CreationDate: %s", asctime(localtime(&clock)));
+
+ /* Compute bounding box in PostScript coordinates. */
+ llx = ((float) dev_left / (float) DEV_UNITS) * (float) EPS_UNITS;
+ lly = ((float) dev_bottom / (float) DEV_UNITS) * (float) EPS_UNITS;
+ urx = ((float) (dev_left + dev_width) / (float) DEV_UNITS)
+ * (float) EPS_UNITS;
+ ury = ((float) (dev_bottom + dev_height) / (float) DEV_UNITS)
+ * (float) EPS_UNITS;
+
+ fprintf (out, "%%%%BoundingBox: %d %d %d %d\n", llx, lly, urx, ury);
+ fprintf (out, "%%%%Pages: 1\n");
+ fprintf (out, "%%%%EndComments\n");
+}
diff --git a/unix/gdev/sgidev/sgi2uhpgl.c b/unix/gdev/sgidev/sgi2uhpgl.c
new file mode 100644
index 00000000..2e952446
--- /dev/null
+++ b/unix/gdev/sgidev/sgi2uhpgl.c
@@ -0,0 +1,160 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define import_spp
+#define import_error
+#include <iraf.h>
+
+#include "sgiUtil.h"
+
+
+/*
+ * SGI2UHPGL.C -- Read IRAF SGI metacode from standard input, translate into
+ * HP graphics language call for HP 7550A plotter
+ *
+ * Usage
+ * sgi2uhpgl.e [sgi_metacode] [| lpr -Papple]
+ *
+ */
+
+#define OSOK 0 /* normal successful completion */
+#define LEN_MCBUF 1024 /* number of SGK instrs in buffer */
+#define SGK_FRAME 1 /* new frame instruction */
+#define SGK_MOVE 2 /* move pen */
+#define SGK_DRAW 3 /* draw pen */
+#define SGK_SETLW 4 /* set line width */
+#define GKI_MAXNDC 32767 /* SGK units */
+
+/* Device opcodes and parameters.
+ */
+#define DEV_INIT "IN;DF;SP1;" /* initialize */
+#define DEV_END "SP0;PG:" /* terminate */
+#define DEV_FRAME "PG;" /* newframe */
+#define DEV_MOVE "PU" /* move */
+#define DEV_DRAW "PD" /* draw */
+#define PRES 1016 /* plotter resolution per inch */
+#define XLEN_INCHES 10.0 /* width of plot (x) in inches */
+#define YLEN_INCHES 8.0 /* height of plot (y) in inches */
+#define XSCALE PRES * XLEN_INCHES / GKI_MAXNDC
+#define YSCALE PRES * YLEN_INCHES / GKI_MAXNDC
+
+
+#define SZ_COORD 4 /* no. of chars in device coordinate */
+
+struct sgi_inst {
+ short opcode;
+ short x;
+ short y;
+};
+
+static void translate (FILE *in, FILE *out);
+
+
+/* MAIN -- Main entry point for SGI2UHPGL. Optional arguments are device
+ * window parameters and name of input file.
+ */
+int
+main (int argc, char *argv[])
+{
+ FILE *in;
+ char *infile;
+
+
+ infile = "stdin";
+
+ /* Process the command line.
+ */
+ infile = argv[1];
+
+ if (strcmp (infile, "stdin") == 0)
+ in = stdin;
+ else
+ in = fopen (infile, "r");
+
+ if (in == NULL) {
+ fprintf (stderr, "Fatal error (sgi2uhpp): Cannot open `%s'\n",
+ infile);
+ fflush (stderr);
+ exit (OSOK+1);
+ }
+
+ /* Process the metacode.
+ */
+ translate (in, stdout);
+
+ if (in != stdin)
+ fclose (in);
+
+ return (0);
+}
+
+
+/* TRANSLATE -- Interpret input SGI metacode instructions into device
+ * instructions and write to stdout.
+ */
+static void
+translate (FILE *in, FILE *out)
+{
+ register struct sgi_inst *sgip;
+ struct sgi_inst inbuf[LEN_MCBUF], *buftop;
+ int n, swap_bytes;
+ float x, y;
+
+
+ swap_bytes = isSwapped();
+
+ /* Output device initialization.
+ */
+ fprintf (out, "%s\n", DEV_INIT);
+
+ /* Initialize pen width. Not implemented.
+ */
+
+ /* Process the metacode:
+ */
+ while ((n = fread ((char *)inbuf, sizeof(*sgip), LEN_MCBUF, in)) > 0) {
+ if (swap_bytes)
+ bswap2 ((unsigned char *)inbuf, (unsigned char *)inbuf,
+ sizeof(*sgip) * n);
+
+ buftop = inbuf + n;
+
+ for (sgip = inbuf; sgip < buftop; sgip++) {
+ switch (sgip->opcode) {
+ case SGK_FRAME:
+ fprintf (out, "%s\n", DEV_FRAME);
+ break;
+
+ case SGK_MOVE:
+ x = sgip->x * XSCALE;
+ y = sgip->y * YSCALE;
+ fprintf (out,
+ "%s%06.0f%s%06.0f%s\n", DEV_MOVE, x, ",", y, ";");
+ break;
+
+ case SGK_DRAW:
+ x = sgip->x * XSCALE;
+ y = sgip->y * YSCALE;
+ fprintf (out,
+ "%s%06.0f%s%06.0f%s\n", DEV_DRAW, x, ",", y, ";");
+ break;
+
+ case SGK_SETLW:
+ /* Set pen width.
+ */
+ break;
+ default:
+ fprintf (stderr, "sgi2uhpp: unrecognized sgi opcode %d\n",
+ sgip->opcode);
+ break;
+ }
+ }
+ }
+
+ /* Terminate plotting and exit.
+ */
+ fwrite (DEV_END, strlen(DEV_END), 1, out);
+ fprintf (out, "\n");
+}
diff --git a/unix/gdev/sgidev/sgi2uhplj.c b/unix/gdev/sgidev/sgi2uhplj.c
new file mode 100644
index 00000000..7c8956ce
--- /dev/null
+++ b/unix/gdev/sgidev/sgi2uhplj.c
@@ -0,0 +1,223 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define import_spp
+#define import_error
+#include <iraf.h>
+
+#include "sgiUtil.h"
+
+
+/*
+ * SGI2UHPLJ.C -- Read IRAF SGI rasterfile from standard input, translate into
+ * the Hewlett Packard Printer Command Language (HP Laserjet Series) and
+ * write to standard output.
+ *
+ * Warning
+ * The output of this is for 150 dpi. At this resolution it will take
+ * some 200 seconds to plot an simple "prow".
+ *
+ * Usage
+ * sgi2uhplj.e [-params] [sgi_] [| lpr -Phpraw]
+ *
+ * -l N left edge; x plot origin in device pixels def DEF_LEFT
+ * -b N bottom edge; y plot origin in device pixels def DEF_BOTTOM
+ * -w N width of plot, device pixels starting from l def DEF_WIDTH
+ * -h N height of plot, device pixels starting from b def DEF_HEIGHT
+ *
+ * Numeric values may be appended directly to their flags or separated by a
+ * space; the input file name and the switches may occur in any order.
+ */
+
+#define OSOK 0 /* normal successful completion */
+#define NBITS_CHAR 8 /* number of bits in a char */
+
+/* Device opcodes and parameters. The default edge and width parameters (DEF_)
+ * are given in HP pixels, at 150 dots/inch. The HP plots in portrait mode
+ * by default so RO must be set in GRAPHCAP. Thus the maximum page `width' is
+ * 11*150pixels, `height' is 8.5*150 pixels.
+ */
+
+#define DEV_INIT "\033*t150R\033*r1A" /* Enter graph. */
+#define DEV_END "\033*rB\014" /* Exit graph. */
+#define DEV_VECT "\033*p%03dX\033*p%03dY"/* x,y cursor posn in dots */
+#define DEV_RAST "\033*b%03dW" /* transfer raster graphics */
+
+#define DEF_LEFT 15 /* origin in device pixels in x */
+#define DEF_WIDTH 1216 /* width in x (150d/i, 8.5" paper) */
+#define DEF_BOTTOM 30 /* origin in device pixels in y */
+#define DEF_HEIGHT 1590 /* height in y (150d/i, 11" paper) */
+
+#define SZ_VECT 14 /* total chars in cursor position command */
+#define SZ_RAST 7 /* total chars in transfer graphics command */
+
+/* graphcap entry for uhplj and sgi_hplaserjet. one problem with current
+ * entry is that graph comes out slightly to the right of center on the page
+ * The printer used, "hpraw", is site dependent.
+ *
+ * uhplj|UNIX generic interface to Hewlett-Packard LaserJet II:\
+ * :BF:WS:XO#0:YO#0:LO#2:LS#2:\
+ * :DD=plnode!hpii,tmp$sgk,!{ sgidispatch sgi2uhpii $F \
+ * -l$(XO) -b$(YO) -w$(PX) -h$(PY) $F | lpr -Phpraw; rm $F; }&:\
+ * :tc=sgi_hplaserjet:
+ *
+ * sgi_hplaserjet|Hewlett Packard LaserJet Plus at 150 dpi:\
+ * :kf=bin$x_sgikern.e:tn=sgikern:cw#.0125:ch#.0294:\
+ * :ar#1.325:xs#.2032:ys#.2692:xr#1200:yr#1590:\
+ * :XO#8:YO#0:XW#1200:YW#1590:PX#1216:PY#1590:LO#1:LS#0:\
+ * :BI:MF#8:RO:NB#8:
+ */
+
+int dev_left;
+int dev_bottom;
+int dev_width;
+int dev_height;
+
+static void translate (FILE *in, FILE *out);
+static char *xyencode (int x, int y);
+
+
+/* MAIN -- Main entry point for SGI2UHPII. Optional arguments are device
+ * window parameters and name of input file.
+ */
+int
+main (int argc, char *argv[])
+{
+ FILE *in;
+ char *infile;
+ char *argp;
+ int argno;
+
+
+ infile = "stdin";
+
+ /* Process the command line.
+ */
+ for (argno=1; (argp = argv[argno]) != NULL; argno++) {
+ if (argp[0] == '-') {
+ /* A window-control or pen width switch.
+ */
+ switch (argp[1]) {
+ case 'l':
+ dev_left = get_iarg (argp[2], argv, argno, DEF_LEFT);
+ break;
+ case 'b':
+ dev_bottom = get_iarg (argp[2], argv, argno, DEF_BOTTOM);
+ break;
+ case 'w':
+ dev_width = get_iarg (argp[2], argv, argno, DEF_WIDTH);
+ break;
+ case 'h':
+ dev_height = get_iarg (argp[2], argv, argno, DEF_HEIGHT);
+ break;
+ default:
+ break;
+ }
+
+ } else {
+ /* Input sgi-raster file specification.
+ */
+ infile = argp;
+ }
+ }
+
+ if (strcmp (infile, "stdin") == 0)
+ in = stdin;
+ else
+ in = fopen (infile, "r");
+
+ if (in == NULL) {
+ fprintf (stderr, "Fatal error (sgi2uhpii): Cannot open `%s'\n",
+ infile);
+ fflush (stderr);
+ exit (OSOK+1);
+ }
+
+ /* Process the rasterfile.
+ */
+ translate (in, stdout);
+
+ if (in != stdin)
+ fclose (in);
+
+ return (0);
+}
+
+
+/* TRANSLATE -- Interpret input SGI Raster File format into Hewlett Packard
+ * Raster graphics instructions and write to stdout.
+ */
+static void
+translate (FILE *in, FILE *out)
+{
+ int n1, swap_bytes;
+ int n, nlines, length, len_buf;
+ register unsigned char *bp1, *buffer1;
+ char buf_rast [SZ_RAST];
+
+
+ swap_bytes = isSwapped ();
+
+ len_buf = dev_width / NBITS_CHAR;
+ buffer1 = (unsigned char *)malloc (len_buf);
+
+ /* Output device initialization.
+ */
+ fwrite (xyencode (dev_left, dev_bottom), SZ_VECT, 1, out);
+ fwrite (DEV_INIT, strlen(DEV_INIT), 1, out);
+
+ /* Process the raster file
+ */
+ nlines = dev_height;
+ while ((n = fread (buffer1, len_buf, 1, in)) > 0) {
+
+ if (swap_bytes)
+ bswap2 (buffer1, buffer1, len_buf);
+
+ /* Keep track of number of lines left on the page.
+ */
+ if (!(nlines--)) {
+ nlines += dev_height;
+ fwrite (DEV_END, strlen (DEV_END), 1, out);
+ fwrite (xyencode (dev_left, dev_bottom), SZ_VECT, 1, out);
+ fwrite (DEV_INIT, strlen (DEV_INIT), 1, out);
+ }
+
+ /* Search for trailing null bytes to trim them off.
+ */
+ length = len_buf;
+ for (bp1 = buffer1+length; length && *(--bp1) == 0; length--)
+ ;
+
+ n1 = length;
+ if (n1 == 0) {
+ n1 = 1;
+ *buffer1 = 0;
+ }
+
+ /* Now copy out this line and prefix it with the control codes.
+ */
+ sprintf (buf_rast, DEV_RAST, n1);
+ fwrite (buf_rast, SZ_RAST, 1, out);
+ fwrite (buffer1, n1, 1, out);
+ }
+
+ /* Terminate plotting and exit.
+ */
+ fwrite (DEV_END, strlen(DEV_END), 1, out);
+}
+
+
+/* XYENCODE -- Encode x, y into a character string formatted for the device.
+ */
+static char *
+xyencode (int x, int y)
+{
+ static char obuf [SZ_VECT];
+
+ memset (obuf, 0, SZ_VECT);
+ sprintf (obuf, DEV_VECT, x, y);
+ return (obuf);
+}
diff --git a/unix/gdev/sgidev/sgi2uimp.c b/unix/gdev/sgidev/sgi2uimp.c
new file mode 100644
index 00000000..a8f566ed
--- /dev/null
+++ b/unix/gdev/sgidev/sgi2uimp.c
@@ -0,0 +1,341 @@
+/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define import_spp
+#define import_error
+#include <iraf.h>
+
+#include "sgiUtil.h"
+
+
+/*
+ * SGI2UIMP.C -- Read IRAF SGI metacode from standard input, translate into
+ * the Impress language and write to standard output.
+ *
+ * Usage
+ * sgi2uimp.e [-params] [sgi_metacode] [| lpr -v -Pimagen]
+ *
+ * -l N left edge; x plot origin in device pixels def DEF_LEFT
+ * -b N bottom edge; y plot origin in device pixels def DEF_BOTTOM
+ * -w N width of plot, device pixels starting from l def DEF_WIDTH
+ * -h N height of plot, device pixels starting from b def DEF_HEIGHT
+ * -p O.S pen width `origin' and `slope' def DEF_PENBASE
+ * .DEF_PENSLOPE
+ *
+ * Numeric values may be appended directly to their flags or separated by a
+ * space; the input file name and the switches may occur in any order.
+ * The windowing parameters are specified explicitly rather than using the
+ * plotter resolution and paper size due to differences in exactly where
+ * each different Imagen begins and ends plotting within the paper window.
+ *
+ */
+
+#define OSOK 0 /* normal successful completion */
+#define LEN_MCBUF 1024 /* number of SGK instrs in buffer */
+#define SGK_FRAME 1 /* new frame instruction */
+#define SGK_MOVE 2 /* move pen */
+#define SGK_DRAW 3 /* draw pen */
+#define SGK_SETLW 4 /* set line width */
+#define GKI_MAXNDC 32767 /* SGK units */
+
+/* Device opcodes and parameters. The default edge and width parameters
+ * (DEF_), given in device pixels for a 240 dot/inch Imagen with 8 1/2" x 11"
+ * paper, should be modified to fit the local plotter.
+ */
+#define DEF_LEFT 85 /* origin in device pixels in x */
+#define DEF_WIDTH 2490 /* width in x (240d/i, 11" paper) */
+#define DEF_BOTTOM 50 /* origin in device pixels in y */
+#define DEF_HEIGHT 1905 /* height in y (240d/i, 8.5" paper)*/
+#define DEF_PENBASE 2 /* base pen width */
+#define DEF_PENSLOPE 2 /* pen slope (b.s=3.2 ==> 3,5,7,9) */
+#define SZ_PENPARAM 5 /* max chars in penwidth parameter */
+#define BLACK_LINE 15 /* draw solid line */
+#define CREATE_PATH 230 /* set up set of vertices */
+#define DRAW_PATH 234 /* draw that set of vertices */
+#define END_DOCUMENT 255 /* end of document */
+#define END_PAGE 219 /* formfeed */
+#define HV_VALUE 125 /* 0 11 11 101 (orig, axes, orient)*/
+#define SET_ABS_H 135 /* move absolute in h */
+#define SET_ABS_V 137 /* move absolute in v */
+#define SET_HV_SYSTEM 205 /* establish coordinate system */
+#define SET_PEN 232 /* set pen width */
+#define SZ_HEAD 3 /* # header opcode bytes in obuf */
+#define SZ_TAIL 2 /* # trailing opcode bytes in obuf */
+#define COUNT_OFFSET 1 /* byte offset to npoints in obuf */
+
+/* Output macros -- watch out for SZ_OBUF; some Imagens have a limited amount
+ * of memory for the DRAW buffer:
+ */
+#define SZ_OBUF (1024)
+#define DECL_OBUF register char *op; char *np; char obuf[SZ_OBUF+1];
+#define o_clear (op=obuf)
+#define o_flush(o) fwrite(obuf,op-obuf,1,o)
+#define putbyte(v) (*op++ = (v))
+#define putword(v) ((*op++ = (v)/256), (*op++ = (v)%256))
+#define setcount(b,v) ((np = obuf+b), (*np++ = (v)/256), (*np = (v)%256))
+#define npoints ((op-obuf - SZ_HEAD)/4)
+#define obuf_full ((op-obuf + SZ_TAIL) >= SZ_OBUF)
+
+struct sgi_inst {
+ short opcode;
+ short x;
+ short y;
+};
+
+int imp_left;
+int imp_bottom;
+int imp_width;
+int imp_height;
+int imp_penbase = DEF_PENBASE;
+int imp_penslope = DEF_PENSLOPE;
+
+static void translate (FILE *in, FILE *out);
+
+
+/* MAIN -- Main entry point for SGI2UIMP. Optional arguments are device
+ * window parameters and name of input file.
+ */
+int
+main (int argc, char *argv[])
+{
+ FILE *in;
+ char *infile;
+ char *argp;
+ int argno;
+ int np;
+ char penparam[SZ_PENPARAM];
+
+
+ infile = "stdin";
+
+ /* Process the command line.
+ */
+ for (argno=1; (argp = argv[argno]) != NULL; argno++) {
+ if (argp[0] == '-') {
+ /* A window-control or pen width switch.
+ */
+ switch (argp[1]) {
+ case 'l':
+ imp_left = get_iarg (argp[2], argv, argno, DEF_LEFT);
+ break;
+ case 'b':
+ imp_bottom = get_iarg (argp[2], argv, argno, DEF_BOTTOM);
+ break;
+ case 'w':
+ imp_width = get_iarg (argp[2], argv, argno, DEF_WIDTH);
+ break;
+ case 'h':
+ imp_height = get_iarg (argp[2], argv, argno, DEF_HEIGHT);
+ break;
+ case 'p':
+ if (argp[2] == (char) 0)
+ if (argv[argno+1] == NULL) {
+ fprintf (stderr, "missing arg to switch `%s';",
+ argp);
+ fprintf (stderr, " reset to %d.%d\n", imp_penbase,
+ imp_penslope);
+ } else
+ strcpy (penparam, argv[++argno]);
+ else
+ strcpy (penparam, argv[argno]+2);
+
+ np = sscanf (penparam, "%d . %d", &imp_penbase,
+ &imp_penslope);
+ if (np == 1) {
+ imp_penslope = imp_penbase;
+ } else if (np < 1) {
+ imp_penbase = DEF_PENBASE;
+ imp_penslope = DEF_PENSLOPE;
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ } else {
+ /* Input sgi-metacode file specification.
+ */
+ infile = argp;
+ }
+ }
+
+ if (strcmp (infile, "stdin") == 0)
+ in = stdin;
+ else
+ in = fopen (infile, "r");
+
+ if (in == NULL) {
+ fprintf (stderr, "Fatal error (sgi2uimp): Cannot open `%s'\n",
+ infile);
+ fflush (stderr);
+ exit (OSOK+1);
+ }
+
+ /* Process the metacode.
+ */
+ translate (in, stdout);
+
+ if (in != stdin)
+ fclose (in);
+
+ return (0);
+}
+
+
+/* TRANSLATE -- Interpret input SGI metacode instructions into the device
+ * language and write to stdout.
+ */
+static void
+translate (FILE *in, FILE *out)
+{
+ int n, x, y, swap_bytes;
+ float xscale, yscale;
+ register struct sgi_inst *sgip;
+ struct sgi_inst inbuf[LEN_MCBUF], *buftop;
+ DECL_OBUF;
+
+ swap_bytes = isSwapped();
+
+ xscale = (float) imp_width / (float) GKI_MAXNDC;
+ yscale = (float) imp_height / (float) GKI_MAXNDC;
+
+ /* Output device header instructions.
+ */
+ fprintf (out, "@Document(%s, %s, %s, %s, %s, %s)",
+ "language impress", "pagecollation on", "jamresistance on",
+ "name \"IRAF SGI plot\"", "prerasterization on", "jobheader off");
+
+ /* Output page orientation and coordinate system initialization.
+ */
+ putc (SET_HV_SYSTEM, out);
+ putc (HV_VALUE, out);
+
+ /* Initialize pen width.
+ */
+ putc (SET_PEN, out);
+ putc (1 * imp_penbase, out);
+
+ o_clear;
+
+ /* Process the metacode:
+ */
+ while ((n = fread ((char *)inbuf, sizeof(*sgip), LEN_MCBUF, in)) > 0) {
+
+ if (swap_bytes)
+ bswap2 ((unsigned char *)inbuf, (unsigned char *)inbuf,
+ sizeof(*sgip) * n);
+
+ buftop = inbuf + n;
+
+ for (sgip = inbuf; sgip < buftop; sgip++) {
+ switch (sgip->opcode) {
+ case SGK_FRAME:
+ /* Terminate and output any DRAW buffer contents.
+ */
+ if (npoints > 1) {
+ setcount (COUNT_OFFSET, npoints);
+ putbyte (DRAW_PATH);
+ putbyte (BLACK_LINE);
+ o_flush (out);
+ }
+
+ o_clear;
+ putbyte (END_PAGE);
+ putbyte (SET_ABS_H);
+ putword (0);
+ putbyte (SET_ABS_V);
+ putword (0);
+ o_flush (out);
+ break;
+
+ case SGK_MOVE:
+ /* Terminate and output any DRAW buffer contents.
+ */
+ if (npoints > 1) {
+ setcount (COUNT_OFFSET, npoints);
+ putbyte (DRAW_PATH);
+ putbyte (BLACK_LINE);
+ o_flush (out);
+ }
+
+ x = imp_left + sgip->x * xscale;
+ y = imp_bottom + sgip->y * yscale;
+
+ /* Initialize output buffer for start of draw instruction.
+ */
+ o_clear;
+ putbyte (CREATE_PATH);
+ putword (1);
+ putword (x); putword (y);
+
+ break;
+
+ case SGK_DRAW:
+ x = imp_left + sgip->x * xscale;
+ y = imp_bottom + sgip->y * yscale;
+ putword (x); putword (y);
+
+ /* If we are about to exceed output buffer, flush and re-
+ * initialize starting with current point.
+ */
+ if (obuf_full) {
+ setcount (COUNT_OFFSET, npoints);
+ putbyte (DRAW_PATH);
+ putbyte (BLACK_LINE);
+ o_flush (out);
+
+ /* Reinitialize DRAW buffer.
+ */
+ o_clear;
+ putbyte (CREATE_PATH);
+ putword (1);
+ putword (x); putword (y);
+ }
+
+ break;
+
+ case SGK_SETLW:
+ /* Terminate and output any DRAW buffer contents.
+ */
+ if (npoints > 1) {
+ setcount (COUNT_OFFSET, npoints);
+ putbyte (DRAW_PATH);
+ putbyte (BLACK_LINE);
+ o_flush (out);
+ o_clear;
+ }
+
+ /* Set pen width.
+ */
+ putc (SET_PEN, out);
+ putc ((imp_penbase + ((sgip->x) - 1) * imp_penslope), out);
+ break;
+
+ default:
+ fprintf (stderr, "sgi2uimp: unrecognized sgi opcode %d\n",
+ sgip->opcode);
+ break;
+ }
+ }
+ }
+
+ /* Flush any remaining buffered points.
+ */
+ if (npoints > 1) {
+ setcount (COUNT_OFFSET, npoints);
+ putbyte (DRAW_PATH);
+ putbyte (BLACK_LINE);
+ o_flush (out);
+ }
+
+ /* Signal end of page and end of document.
+ */
+ putc (END_PAGE, out);
+ putc (END_DOCUMENT, out);
+}
diff --git a/unix/gdev/sgidev/sgi2uptx.c b/unix/gdev/sgidev/sgi2uptx.c
new file mode 100644
index 00000000..6c44f334
--- /dev/null
+++ b/unix/gdev/sgidev/sgi2uptx.c
@@ -0,0 +1,61 @@
+/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define NBITS_CHAR 8 /* number of bits in a char */
+#define MASK 64 /* printronix raster flag */
+#define START_LINE "\005" /* start of raster line control code */
+#define END_LINE "\012" /* end of raster line control code */
+#define START_PAGE "\014" /* form feed */
+
+/* PRINTRONIX translator from the SGI bitmap file to the STDOUT */
+
+int
+main (int argc, char *argv[])
+{
+
+ FILE *fpi;
+ char *buffer;
+ int n, len_buf, nlines;
+ int index; /* goes through all 8 files */
+ int px, py;
+
+ px = atoi (argv[1]);
+ py = atoi (argv[2]);
+ len_buf = px/NBITS_CHAR;
+ buffer = (char *) malloc (len_buf);
+
+ for (index=3; index<argc; index++) {
+
+ if (index != 3) fwrite (START_PAGE, 1, 1, stdout);
+ fpi = fopen (argv[index], "r");
+ nlines = py;
+
+ while (fread (buffer, len_buf, 1, fpi)) {
+
+ /* Keep track of number of lines left on the page. */
+ if (!(nlines--)) {
+ nlines += py;
+ fwrite (START_PAGE, 1, 1, stdout);
+ }
+
+ /* Turn on the raster flag on every data byte */
+ for (n = 0; n < len_buf; n++) buffer[n] |= MASK;
+
+ /* Now copy out this line and bracket it with the control codes. */
+ fwrite (START_LINE, 1, 1, stdout);
+ fwrite (buffer, len_buf, 1, stdout);
+ fwrite (END_LINE, 1, 1, stdout);
+
+ }
+
+ fclose (fpi);
+
+ }
+
+ return (0);
+}
diff --git a/unix/gdev/sgidev/sgi2uqms.c b/unix/gdev/sgidev/sgi2uqms.c
new file mode 100644
index 00000000..e91d7e38
--- /dev/null
+++ b/unix/gdev/sgidev/sgi2uqms.c
@@ -0,0 +1,296 @@
+/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define import_spp
+#define import_error
+#include <iraf.h>
+
+#include "sgiUtil.h"
+
+
+/*
+ * SGI2UQMS.C -- Read IRAF SGI metacode from standard input, translate into
+ * the QMS Vector Graphics Mode (Talaris Lasergrafix, QUIC Command Mode) and
+ * write to standard output.
+ *
+ * Usage
+ * sgi2uqms.e [-params] [sgi_metacode] [| lpr -Pqms]
+ *
+ * -l N left edge; x plot origin in device pixels def DEF_LEFT
+ * -b N bottom edge; y plot origin in device pixels def DEF_BOTTOM
+ * -w N width of plot, device pixels starting from l def DEF_WIDTH
+ * -h N height of plot, device pixels starting from b def DEF_HEIGHT
+ * -p O.S pen width `origin' and `slope' def DEF_PENBASE
+ * .DEF_PENSLOPE
+ *
+ * Numeric values may be appended directly to their flags or separated by a
+ * space; the input file name and the switches may occur in any order.
+ */
+
+#define OSOK 0 /* normal successful completion */
+#define LEN_MCBUF 1024 /* number of SGK instrs in buffer */
+#define SGK_FRAME 1 /* new frame instruction */
+#define SGK_MOVE 2 /* move pen */
+#define SGK_DRAW 3 /* draw pen */
+#define SGK_SETLW 4 /* set line width */
+#define GKI_MAXNDC 32767 /* SGK units */
+
+/* Device opcodes and parameters. The default edge and width parameters (DEF_)
+ * are given in QMS pixels, at 300 dots/inch. The QMS y-origin is at the
+ * top of the page, so in GRAPHCAP, YF must be set, and Landscape Orientation
+ * used in the QMS. Thus the maximum page `width' is 11*300 pixels, `height'
+ * is 8.5*300 pixels.
+ */
+#define DEV_INIT "\012^PY^-\012^ISYNTAX00010^IOL^F^IGV" /* Enter graph.*/
+#define DEV_END "^IGE^ISYNTAX00000^IOP^O\012^PN^-\012" /* Exit graph. */
+#define DEV_FRAME "^," /* QMS Vector Graphics Mode form feed instr */
+#define DEV_MOVE "^U" /* QMS (VGM) pen-up instruction */
+#define DEV_DRAW "^D" /* QMS (VGM) pen-down instruction */
+#define DEV_SETLW "^PW" /* QMS (VGM) Set Line Width (follow w/ nn) */
+
+#define DEF_LEFT 30 /* origin in device pixels in x */
+#define DEF_WIDTH 3180 /* width in x (300d/i, 11" paper) */
+#define DEF_BOTTOM 60 /* origin in device pixels in y */
+#define DEF_HEIGHT 2415 /* height in y (300d/i, 8.5" paper) */
+#define DEF_PENBASE 3 /* base pen width (LW 1->2) */
+#define DEF_PENSLOPE 4 /* pen width slope (LW 2->4, 3->6 etc.) */
+#define SZ_PENCMD 5 /* total no. of chars in penwidth instruction */
+#define SZ_PENVAL 2 /* no. of chars in penwidth value */
+#define SZ_VECT 11 /* total no. chars in a MOVE or DRAW inst. */
+#define SZ_COORD 4 /* no. of chars in device coordinate */
+
+struct sgi_inst {
+ short opcode;
+ short x;
+ short y;
+};
+
+int dev_left;
+int dev_bottom;
+int dev_width;
+int dev_height;
+int dev_penbase = DEF_PENBASE;
+int dev_penslope = DEF_PENSLOPE;
+
+static void translate (FILE *in, FILE *out);
+static char *xyencode (int opcode, int x, int y);
+static char *penencode (char *opcode, int val);
+
+
+
+/* MAIN -- Main entry point for SGI2UQMS. Optional arguments are device
+ * window parameters and name of input file.
+ */
+int
+main (int argc, char *argv[])
+{
+ FILE *in;
+ char *infile;
+ char *argp;
+ int argno;
+ int np;
+ char penparam[SZ_PENCMD];
+
+
+ infile = "stdin";
+
+ /* Process the command line.
+ */
+ for (argno=1; (argp = argv[argno]) != NULL; argno++) {
+ if (argp[0] == '-') {
+ /* A window-control or pen width switch.
+ */
+ switch (argp[1]) {
+ case 'l':
+ dev_left = get_iarg (argp[2], argv, argno, DEF_LEFT);
+ break;
+ case 'b':
+ dev_bottom = get_iarg (argp[2], argv, argno, DEF_BOTTOM);
+ break;
+ case 'w':
+ dev_width = get_iarg (argp[2], argv, argno, DEF_WIDTH);
+ break;
+ case 'h':
+ dev_height = get_iarg (argp[2], argv, argno, DEF_HEIGHT);
+ break;
+ case 'p':
+ if (argp[2] == (char) 0)
+ if (argv[argno+1] == NULL) {
+ fprintf (stderr, "missing arg to switch `%s';",
+ argp);
+ fprintf (stderr, " reset to %d.%d\n", dev_penbase,
+ dev_penslope);
+ } else
+ strcpy (penparam, argv[++argno]);
+ else
+ strcpy (penparam, argv[argno]+2);
+
+ np = sscanf (penparam, "%d . %d", &dev_penbase,
+ &dev_penslope);
+ if (np == 1) {
+ dev_penslope = dev_penbase;
+ } else if (np < 1) {
+ dev_penbase = DEF_PENBASE;
+ dev_penslope = DEF_PENSLOPE;
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ } else {
+ /* Input sgi-metacode file specification.
+ */
+ infile = argp;
+ }
+ }
+
+ if (strcmp (infile, "stdin") == 0)
+ in = stdin;
+ else
+ in = fopen (infile, "r");
+
+ if (in == NULL) {
+ fprintf (stderr, "Fatal error (sgi2uqms): Cannot open `%s'\n",
+ infile);
+ fflush (stderr);
+ exit (OSOK+1);
+ }
+
+ /* Process the metacode.
+ */
+ translate (in, stdout);
+
+ if (in != stdin)
+ fclose (in);
+
+ return (0);
+}
+
+
+/* TRANSLATE -- Interpret input SGI metacode instructions into device
+ * instructions and write to stdout.
+ */
+static void
+translate (FILE *in, FILE *out)
+{
+ int n, x, y, swap_bytes;
+ float xscale, yscale;
+ register struct sgi_inst *sgip;
+ struct sgi_inst inbuf[LEN_MCBUF], *buftop;
+
+
+ swap_bytes = isSwapped();
+
+ xscale = (float) dev_width / (float) GKI_MAXNDC;
+ yscale = (float) dev_height / (float) GKI_MAXNDC;
+
+ /* Output device initialization.
+ */
+ fwrite (DEV_INIT, strlen(DEV_INIT), 1, out);
+
+ /* Initialize pen width.
+ */
+ fwrite (penencode (DEV_SETLW, dev_penbase), SZ_PENCMD, 1, out);
+
+ /* Process the metacode:
+ */
+ while ((n = fread ((char *)inbuf, sizeof(*sgip), LEN_MCBUF, in)) > 0) {
+
+ if (swap_bytes)
+ bswap2 ((unsigned char *)inbuf, (unsigned char *)inbuf,
+ sizeof(*sgip) * n);
+
+ buftop = inbuf + n;
+
+ for (sgip = inbuf; sgip < buftop; sgip++) {
+ switch (sgip->opcode) {
+ case SGK_FRAME:
+ fwrite (DEV_FRAME, strlen(DEV_FRAME), 1, out);
+ break;
+
+ case SGK_MOVE:
+ x = dev_left + sgip->x * xscale;
+ y = dev_bottom + sgip->y * yscale;
+ fwrite (xyencode ('U', x, y), SZ_VECT, 1, out);
+ break;
+
+ case SGK_DRAW:
+ x = dev_left + sgip->x * xscale;
+ y = dev_bottom + sgip->y * yscale;
+ fwrite (xyencode ('D', x, y), SZ_VECT, 1, out);
+ break;
+
+ case SGK_SETLW:
+ /* Set pen width.
+ */
+ fwrite (penencode (DEV_SETLW, dev_penbase +
+ ((sgip->x) - 1) * dev_penslope), SZ_PENCMD, 1, out);
+ break;
+
+ default:
+ fprintf (stderr, "sgi2uqms: unrecognized sgi opcode %d\n",
+ sgip->opcode);
+ break;
+ }
+ }
+ }
+
+ /* Terminate plotting and exit.
+ */
+ fwrite (DEV_END, strlen(DEV_END), 1, out);
+}
+
+
+/* XYENCODE -- Encode x, y into a character string formatted for the device.
+ */
+static char *
+xyencode (
+ int opcode, /* draw or move */
+ int x, /* must be positive */
+ int y /* must be positive */
+)
+{
+ static char obuf[] = "^X0000:0000";
+ register int digit, n;
+ register char *op;
+ int i;
+
+ obuf[1] = opcode;
+ i = SZ_VECT - 1 - SZ_COORD - 1;
+ for (op = &obuf[i], digit = SZ_COORD, n=x; --digit >= 0; n = n / 10)
+ *op-- = n % 10 + '0';
+ i = SZ_VECT - 1;
+ for (op = &obuf[i], digit = SZ_COORD, n=y; --digit >= 0; n = n / 10)
+ *op-- = n % 10 + '0';
+
+ return (obuf);
+}
+
+
+/* PENENCODE -- Encode base, slope into a character string formatted for the
+ * device set-pen command.
+ */
+static char *
+penencode (
+ char *opcode, /* device set-linewidth command */
+ int val /* device line width */
+)
+{
+ static char obuf[SZ_PENCMD+1];
+ register int digit, n;
+ register char *op;
+
+ strcpy (obuf, opcode);
+ for (op = &obuf[SZ_PENCMD-1], digit = SZ_PENVAL, n=val; --digit >= 0;
+ n = n / 10)
+ *op-- = n % 10 + '0';
+
+ return (obuf);
+}
diff --git a/unix/gdev/sgidev/sgi2xbm.c b/unix/gdev/sgidev/sgi2xbm.c
new file mode 100644
index 00000000..6d4c230a
--- /dev/null
+++ b/unix/gdev/sgidev/sgi2xbm.c
@@ -0,0 +1,135 @@
+/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "sgiUtil.h"
+
+
+/* SGI2XBM.C -- Read an IRAF SGI bitmap file on standard input and convert
+ * to a GIF format image on standard outout.
+ *
+ * Usage:
+ * sgi2xbm.e [-w N] [-h NY] [-i] [ [sgi_bitmap] [sgi_bitmap] ... ]
+ *
+ * -w N width of input bitmap and output image
+ * -h N height of input bitmap and output image
+ * -i invert the bitmap values before conversion
+ *
+ * The input file name and the switches may occur in any order. The bitmap
+ * may be inverted here using the -i flag.
+ *
+ * Sample graphcaps for this translator might look like:
+ *
+ * g-xbm|UNIX generic interface to multi-frame XBM file generator:\
+ * :DD=ugif,tmp$sgk,!{ sgidispatch sgi2xbm -w $(PX) -h $(PY) \
+ * $F.[1-8] > sgixbm$$; rm $F.[1-8]; }&:\
+ * :MF#8:NF:tc=sgi_image_format:
+ *
+ * sgi_image_format|Generic raster file format specification:\
+ * :kf=bin$x_sgikern.e:tn=sgikern:ar#.75:\
+ * :xr#640:yr#480:PX#640:PY#480:XW#640:YW#480:\
+ * :BI:MF#1:YF:NB#8:LO#1:LS#0:XO#0:YO#0:
+ *
+ * All bitmaps will be dumped to the file 'sgixbmXXX' in the local directory
+ * where XXX is a pid.
+ *
+ * To change the image size the graphcap :xr, :PX, :XW (X-dimension) and
+ * :yr, :PY, :XY (Y-dimension) fields all need to be changed. The -i
+ * flag must be specified in the graphcap DD string.
+ *
+ */
+
+#define NBITS_CHAR 8 /* number of bits in a char */
+#define DEF_WIDTH 640 /* default image width */
+#define DEF_HEIGHT 480 /* default image height */
+#define MAX_INFILES 16 /* max number of input bitmaps */
+#define SZ_FNAME 64 /* size of a filename */
+
+typedef unsigned char byte;
+
+static int px = DEF_WIDTH;
+static int py = DEF_HEIGHT;
+static int invert = 0;
+static char *infile[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+
+int
+main (int argc, char *argv[])
+{
+ FILE *fd;
+ byte *buffer;
+ int i, n, len_buf, numin = 0, cnt = 0;
+ int index; /* goes through all files */
+
+
+ /* Process the command line.
+ */
+ for (i=1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ if (strcmp (argv[i], "-w") == 0)
+ px = atoi (argv[++i]);
+ else if (strcmp (argv[i], "-h") == 0)
+ py = atoi (argv[++i]);
+ else if (strcmp (argv[i], "-i") == 0)
+ invert++;
+ } else {
+ /* input sgi-bitmap file specification */
+ if (numin < MAX_INFILES)
+ infile[numin++] = argv[i];
+ }
+
+ }
+
+ /* Allocate some space for the working buffer. */
+ len_buf = px / NBITS_CHAR;
+ buffer = (byte *) malloc (len_buf);
+
+ /* Loop over the input bitmaps, writing the converted output to
+ * the stdout.
+ */
+ for (index = 0; index == 0 || index < numin; index++) {
+
+ /* Open the input file. */
+ fd = (infile[index] ? fopen (infile[index], "r") : stdin);
+
+ if (index > 0) printf ("\n");
+
+ printf ("#define xbm%03d_width %d\n", index, px);
+ printf ("#define xbm%03d_height %d\n", index, py);
+ printf ("static char xbm%03d_bits[] = {\n ", index);
+
+ n = 0;
+ cnt = 0;
+ while (fread (buffer, len_buf, 1, fd)) {
+ /* If we're on a MSB ordered machine wordswap the bitmap so
+ * it's in the correct order for unpacking to be interpreted
+ * as an LSB-ordered image.
+ */
+ if (!isSwapped ())
+ bswap4 (buffer, buffer, len_buf);
+
+ /* Write out the pixels. */
+ for (i=0; i < len_buf; i++, cnt++) {
+ printf ("0x%.2x",
+ (byte) (invert ? ~buffer[i]: buffer[i])), n += 4;
+ if (cnt < (len_buf * py - 1))
+ printf (","), n++;
+ else
+ printf ("};\n");
+ if (n > 70)
+ printf ("\n "), n=0;
+ }
+ }
+
+ if (fd != stdin)
+ fclose (fd);
+ fflush (fd);
+ }
+ free (buffer);
+
+ return (0);
+}
diff --git a/unix/gdev/sgidev/sgiUtil.c b/unix/gdev/sgidev/sgiUtil.c
new file mode 100644
index 00000000..25214450
--- /dev/null
+++ b/unix/gdev/sgidev/sgiUtil.c
@@ -0,0 +1,132 @@
+/**
+ * SGIUTIL.C -- Shared utility procedures for the SGI translators.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#define import_spp
+#define import_error
+#include <iraf.h>
+
+
+/**
+ * BSWAP2 -- Move bytes from array "a" to array "b", swapping successive
+ * pairs of bytes. The two arrays may be the same but may not be offset
+ * and overlapping.
+ */
+void
+bswap2 (
+ unsigned char *a, /* input array */
+ unsigned char *b, /* output array */
+ int nbytes /* number of bytes to swap */
+)
+{
+ register unsigned char *ip, *op, *otop;
+ register unsigned int temp;
+
+ ip = a;
+ op = b;
+ otop = op + (nbytes & ~1);
+
+ /* Swap successive pairs of bytes.
+ */
+ while (op < otop) {
+ temp = *ip++;
+ *op++ = *ip++;
+ *op++ = temp;
+ }
+
+ /* If there is an odd byte left, move it to the output array.
+ */
+ if (nbytes & 1)
+ *op = *ip;
+}
+
+
+/* BSWAP4 - Move bytes from array "a" to array "b", swapping the four bytes
+ * in each successive 4 byte group, i.e., 12345678 becomes 43218765.
+ * The input and output arrays may be the same but may not partially overlap.
+*/
+void
+bswap4 (
+ unsigned char *a, /* input array */
+ unsigned char *b, /* output array */
+ int nbytes /* number of bytes to swap */
+)
+{
+ register int n;
+ register unsigned char *ip, *op, *tp;
+ static unsigned char temp[4];
+
+ tp = temp;
+ ip = (unsigned char *)a;
+ op = (unsigned char *)b;
+
+ /* Swap successive four byte groups.
+ */
+ for (n = nbytes >> 2; --n >= 0; ) {
+ *tp++ = *ip++;
+ *tp++ = *ip++;
+ *tp++ = *ip++;
+ *tp++ = *ip++;
+ *op++ = *--tp;
+ *op++ = *--tp;
+ *op++ = *--tp;
+ *op++ = *--tp;
+ }
+
+ /* If there are any odd bytes left, move them to the output array.
+ * Do not bother to swap as it is unclear how to swap a partial
+ * group, and really incorrect if the data is not modulus 4.
+ */
+ for (n = nbytes & 03; --n >= 0; )
+ *op++ = *ip++;
+}
+
+
+/**
+ * ISSWAPPED -- Test whether we are running on a byte-swapped machine.
+ */
+int
+isSwapped (void)
+{
+ union {
+ short tswap;
+ char b[2];
+ } test;
+
+ test.tswap = 1;
+ return ((int) test.b[0]);
+}
+
+
+/**
+ * GET_IARG -- Get an integer argument, whether appended directly to flag
+ * or separated by a whitespace character; if error, report and assign
+ * default.
+ */
+int
+get_iarg (
+ char argp,
+ char **argv,
+ int argno,
+ int def_val
+)
+{
+ int temp_val;
+
+ if (argp == (char) 0) {
+ if (argv[argno+1] == NULL) {
+ fprintf (stderr, "missing arg to switch `%c';", argp);
+ fprintf (stderr, " reset to %d\n", def_val);
+ temp_val = def_val;
+ } else
+ temp_val = atoi (argv[++argno]);
+ } else
+ temp_val = atoi (argv[argno]+2);
+
+ return (temp_val);
+}
diff --git a/unix/gdev/sgidev/sgiUtil.h b/unix/gdev/sgidev/sgiUtil.h
new file mode 100644
index 00000000..9630a03e
--- /dev/null
+++ b/unix/gdev/sgidev/sgiUtil.h
@@ -0,0 +1,10 @@
+/**
+ * SGIUTIL.H -- Declarations for the SGI utility routines.
+ */
+
+void bswap2 (unsigned char *a, unsigned char *b, int nbytes);
+void bswap4 (unsigned char *a, unsigned char *b, int nbytes);
+
+int isSwapped (void);
+
+int get_iarg (char argp, char **argv, int argno, int def_val);
diff --git a/unix/gdev/sgidev/sgidispatch.c b/unix/gdev/sgidev/sgidispatch.c
new file mode 100644
index 00000000..90201460
--- /dev/null
+++ b/unix/gdev/sgidev/sgidispatch.c
@@ -0,0 +1,70 @@
+/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define import_spp
+#define import_error
+#define import_kernel
+#define import_knames
+#include <iraf.h>
+
+
+/*
+ * SGIDISPATCH.C -- Determine pathname to the executable for the named SGI
+ * translator, and execute the translator. Pass all command line arguments
+ * to the child, which also inherits stdin, stdout, and stderr.
+ *
+ * Usage: sgidispatch translator [args]
+ */
+
+#define DEF_HOST "unix" /* default host system */
+#define F_OK 0 /* access mode `file exists' */
+#ifndef X_OK
+#define X_OK 1 /* access mode `executable' */
+#endif
+
+char *irafpath();
+
+
+/* MAIN -- Main entry point for SGIDISPATCH.
+ */
+int
+main (int argc, char *argv[])
+{
+ char tpath[SZ_PATHNAME+1];
+ char translator[SZ_PATHNAME+1];
+ int ip;
+
+ /* Do nothing if called with no arguments.
+ */
+ if (argc < 2)
+ exit (OSOK);
+
+ /* Construct pathname to translator.
+ */
+ strcpy (translator, argv[1]);
+ ip = strlen (translator);
+ if (strcmp (&translator[ip], ".e") != 0)
+ strcat (translator, ".e");
+ sprintf (tpath, "%s", irafpath(translator));
+
+ if (access (tpath, X_OK) == ERR) {
+ fprintf (stderr, "Fatal (sgidispatch): unable to access SGI");
+ fprintf (stderr, " translator `%s'\n", tpath);
+ fflush (stderr);
+ exit (OSOK+1);
+ }
+
+ /* Set up i/o for translator and attempt to fork.
+ */
+ argv[argc] = 0;
+ execv (tpath, &argv[1]);
+ fprintf (stderr, "Fatal (sgidispatch): unable to execv(%s, ...)\n",
+ tpath);
+ fflush (stderr);
+ exit (OSOK+1);
+}
diff --git a/unix/gdev/zfiogd.x b/unix/gdev/zfiogd.x
new file mode 100644
index 00000000..a401f9ff
--- /dev/null
+++ b/unix/gdev/zfiogd.x
@@ -0,0 +1,420 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <fio.h>
+
+# ZFIOGD -- FIO device driver for the interactive binary graphics devices.
+# This code is host system dependent (at least in part) as well as node
+# dependent, since the set of graphics devices available on a particular node
+# can vary greatly. The devices for which driver subroutines are linked
+# into this particular version of ZFIOGD are listed below. The individual
+# driver subroutines must be named explicitly in the case statements in
+# each generic driver subroutine.
+
+define DEVICES "|iism70|iism75|imtool|"
+define DEF_OSDEV_1 "unix:/tmp/.IMT%d"
+define DEF_OSDEV_2 "fifo:/dev/imt1i:/dev/imt1o"
+define IMTDEV "IMTDEV"
+define DELIMCH ','
+
+define SZ_OSDEV 512 # device specification string
+define MAXDEV 8
+define MAXBYTES 4000 # fifo transfer size, bytes
+define MAXTRYS 50 # fifo timeout
+define DELAY 10 # fifo i/o interval, msec
+
+define IISM70 1 # IIS Model 70 image display
+define IISM75 2 # IIS Model 75 image display
+define IMTOOL 3 # IMTOOL-type display server
+define NDEVICES 3
+
+
+# ZOPNGD -- Open a binary graphics device. The format of the DEVINFO string
+# is "devname:osdev" (the KI will have already taken care of any network
+# node prefix by the time we are called).
+
+procedure zopngd (devinfo, mode, chan)
+
+char devinfo[ARB] #I PACKED device info string
+int mode #I access mode
+int chan #O receives assigned channel
+
+bool first_time
+pointer devname, envname
+pointer sp, info, imtdev, osdev, pkfname, ip, op
+int nchars, dev, oschan, arg1, arg2, i
+int strdic(), ctoi()
+data first_time /true/
+define err_ 91
+
+int gd_dev[MAXDEV], gd_oschan[MAXDEV]
+int gd_status[MAXDEV], gd_arg1[MAXDEV], gd_arg2[MAXDEV]
+common /zgdcom/ gd_dev, gd_oschan, gd_status, gd_arg1, gd_arg2
+
+begin
+ call smark (sp)
+ call salloc (info, SZ_OSDEV, TY_CHAR)
+ call salloc (osdev, SZ_OSDEV, TY_CHAR)
+ call salloc (imtdev, SZ_OSDEV, TY_CHAR)
+ call salloc (pkfname, SZ_OSDEV, TY_CHAR)
+ call salloc (devname, SZ_FNAME, TY_CHAR)
+ call salloc (envname, SZ_FNAME, TY_CHAR)
+
+ if (first_time) {
+ do i = 1, MAXDEV
+ gd_dev[i] = NULL
+ first_time = false
+ }
+
+ # Parse device specification.
+ # -----------------------------
+ call strupk (devinfo, Memc[info], SZ_OSDEV)
+
+ # Extract generic device name.
+ op = devname
+ for (ip=info; Memc[ip] != EOS && Memc[ip] != DELIMCH; ip=ip+1) {
+ Memc[op] = Memc[ip]
+ op = op + 1
+ }
+ Memc[op] = EOS
+ if (Memc[ip] == DELIMCH)
+ ip = ip + 1
+ else
+ goto err_
+
+ # Look up the generic device name in the device table.
+ dev = strdic (Memc[devname], Memc[osdev], 0, DEVICES)
+ if (dev <= 0)
+ goto err_
+
+ # Get the OS device name.
+ op = osdev
+ for (; Memc[ip] != EOS && Memc[ip] != DELIMCH; ip=ip+1) {
+ Memc[op] = Memc[ip]
+ op = op + 1
+ }
+ Memc[op] = EOS
+ if (Memc[ip] == DELIMCH)
+ ip = ip + 1
+
+ # Get any optional integer arguments.
+ if (ctoi (Memc, ip, arg1) <= 0)
+ arg1 = 0
+ if (Memc[ip] == DELIMCH)
+ ip = ip + 1
+ if (ctoi (Memc, ip, arg2) <= 0)
+ arg2 = 0
+
+ # Edit device specification as necessary.
+ # ------------------------------------------
+
+ # If the generic device is IMTOOL and we have an old style OS device
+ # name, convert it to the format required by the ND driver. If the
+ # OS device name is null supply the default value. If the user has
+ # "IMTDEV" defined in their host environment this overrides the value
+ # passed in the argument list.
+
+ if (dev == IMTOOL) {
+ call strpak (IMTDEV, Memc[envname], SZ_FNAME)
+ call zgtenv (Memc[envname], Memc[imtdev], SZ_OSDEV, nchars)
+
+ if (nchars > 0) {
+ # Environment override.
+ call strupk (Memc[imtdev], Memc[osdev], SZ_OSDEV)
+
+ } else if (Memc[osdev] == '/') {
+ # Old style device name. Convert to the form "fifo:in:out".
+ call strcpy ("fifo:", Memc[imtdev], SZ_OSDEV)
+ call strcat (Memc[osdev], Memc[imtdev], SZ_OSDEV)
+ call strcat ("i:", Memc[imtdev], SZ_OSDEV)
+ call strcat (Memc[osdev], Memc[imtdev], SZ_OSDEV)
+ call strcat ("o", Memc[imtdev], SZ_OSDEV)
+ call strcpy (Memc[imtdev], Memc[osdev], SZ_OSDEV)
+ }
+ }
+
+ # Allocate a slot in the GD device table for the device. We need this
+ # to vector to the correct sub-driver when an i/o function is called.
+
+ for (chan=1; chan <= MAXDEV; chan=chan+1)
+ if (gd_dev[chan] == NULL)
+ break
+ if (chan > MAXDEV)
+ goto err_
+
+ # Try to physically open the device. [ADD NEW DEVICES HERE].
+ switch (dev) {
+ case IISM70:
+ call strpak (Memc[osdev], Memc[pkfname], SZ_OSDEV)
+ call zopm70 (Memc[pkfname], mode, oschan)
+ case IISM75:
+ call strpak (Memc[osdev], Memc[pkfname], SZ_OSDEV)
+ call zopm75 (Memc[pkfname], mode, oschan)
+
+ case IMTOOL:
+ if (Memc[osdev] == EOS) {
+ # Supply default value.
+ call strpak (DEF_OSDEV_1, Memc[pkfname], SZ_OSDEV)
+ call zopnnd (Memc[pkfname], mode, oschan)
+ if (oschan == ERR) {
+ call strpak (DEF_OSDEV_2, Memc[pkfname], SZ_OSDEV)
+ call zopnnd (Memc[pkfname], mode, oschan)
+ }
+ } else {
+ call strpak (Memc[osdev], Memc[pkfname], SZ_OSDEV)
+ call zopnnd (Memc[pkfname], mode, oschan)
+ }
+
+ default:
+ oschan = ERR
+ }
+
+ if (oschan == ERR)
+ goto err_
+
+ gd_dev[chan] = dev
+ gd_oschan[chan] = oschan
+ gd_status[chan] = OK
+ gd_arg1[chan] = arg1
+ gd_arg2[chan] = arg2
+
+ call sfree (sp)
+ return
+err_
+ chan = ERR
+ call sfree (sp)
+end
+
+
+# ZCLSGD -- Close a binary graphics device.
+
+procedure zclsgd (chan, status)
+
+int chan #I channel assigned device
+int status #O receives status of close
+
+int gd_dev[MAXDEV], gd_oschan[MAXDEV]
+int gd_status[MAXDEV], gd_arg1[MAXDEV], gd_arg2[MAXDEV]
+common /zgdcom/ gd_dev, gd_oschan, gd_status, gd_arg1, gd_arg2
+
+begin
+ # [ADD NEW DEVICES HERE].
+
+ if (chan < 1 || chan > MAXDEV) {
+ status = ERR
+ return
+ }
+
+ switch (gd_dev[chan]) {
+ case IISM70:
+ call zclm70 (gd_oschan[chan], status)
+ case IISM75:
+ call zclm75 (gd_oschan[chan], status)
+ case IMTOOL:
+ call zclsnd (gd_oschan[chan], status)
+ default:
+ status = ERR
+ }
+
+ gd_dev[chan] = NULL
+end
+
+
+# ZARDGD -- Read from a binary graphics device.
+
+procedure zardgd (chan, buf, maxbytes, offset)
+
+int chan # channel assigned device
+char buf[ARB] # buffer to be filled
+int maxbytes # max bytes to read
+long offset # file offset (function code else zero)
+
+int nread, nleft, ntries, n, op
+int gd_dev[MAXDEV], gd_oschan[MAXDEV]
+int gd_status[MAXDEV], gd_arg1[MAXDEV], gd_arg2[MAXDEV]
+common /zgdcom/ gd_dev, gd_oschan, gd_status, gd_arg1, gd_arg2
+
+begin
+ gd_status[chan] = OK
+
+ # [ADD NEW DEVICES HERE].
+
+ switch (gd_dev[chan]) {
+ case IISM70:
+ call zrdm70 (gd_oschan[chan], buf, maxbytes, offset)
+ case IISM75:
+ call zrdm75 (gd_oschan[chan], buf, maxbytes, offset)
+
+ case IMTOOL:
+ # Nothing special here, except that we can only move 4096 bytes at
+ # a time through the pipe to the display server. Some provision
+ # for timeout is necessary in the event that the sender dies during
+ # the transfer.
+ #
+ # [we don't need all this for the ND driver, but there is still
+ # a 4096 byte limit for fifo's, so leave this in for now.]
+
+ nread = 0
+ ntries = 0
+ op = 1
+
+ for (nleft=maxbytes; nleft > 0; ) {
+ n = min (nleft, MAXBYTES)
+ call zardnd (gd_oschan[chan], buf[op], n, offset)
+ call zawtnd (gd_oschan[chan], n)
+ if (n < 0) {
+ nread = ERR
+ break
+ }
+
+ nread = nread + n
+ op = op + n / SZB_CHAR
+ nleft = nleft - n
+ if (n == 0)
+ call zwmsec (DELAY)
+
+ ntries = ntries + 1
+ if (ntries > MAXTRYS) {
+ nread = ERR
+ break
+ }
+ }
+
+ gd_status[chan] = nread
+
+ default:
+ gd_status[chan] = ERR
+ }
+end
+
+
+# ZAWRGD -- Write to a binary graphics device.
+
+procedure zawrgd (chan, buf, nbytes, offset)
+
+int chan # channel assigned device
+char buf[ARB] # buffer containing the data
+int nbytes # nbytes to be written
+long offset # file offset (function code else zero)
+
+int nwrote, nleft, ntries, n, ip
+int gd_dev[MAXDEV], gd_oschan[MAXDEV]
+int gd_status[MAXDEV], gd_arg1[MAXDEV], gd_arg2[MAXDEV]
+common /zgdcom/ gd_dev, gd_oschan, gd_status, gd_arg1, gd_arg2
+
+begin
+ gd_status[chan] = OK
+
+ # [ADD NEW DEVICES HERE].
+
+ switch (gd_dev[chan]) {
+ case IISM70:
+ call zwrm70 (gd_oschan[chan], buf, nbytes, offset)
+ case IISM75:
+ call zwrm75 (gd_oschan[chan], buf, nbytes, offset)
+
+ case IMTOOL:
+ nwrote = 0
+ ntries = 0
+ ip = 1
+
+ for (nleft=nbytes; nleft > 0; ) {
+ n = min (nleft, MAXBYTES)
+ call zawrnd (gd_oschan[chan], buf[ip], n, offset)
+ call zawtnd (gd_oschan[chan], n)
+ if (n < 0) {
+ nwrote = ERR
+ break
+ }
+
+ ip = ip + n / SZB_CHAR
+ nwrote = nwrote + n
+ nleft = nleft - n
+ if (n == 0)
+ call zwmsec (DELAY)
+
+ ntries = ntries + 1
+ if (ntries > MAXTRYS) {
+ nwrote = ERR
+ break
+ }
+ }
+
+ gd_status[chan] = nwrote
+
+ default:
+ gd_status[chan] = ERR
+ }
+end
+
+
+# ZAWTGD -- Wait for i/o to a binary graphics device.
+
+procedure zawtgd (chan, status)
+
+int chan # channel assigned device
+int status # receives nbytes transferred or ERR
+
+int gd_dev[MAXDEV], gd_oschan[MAXDEV]
+int gd_status[MAXDEV], gd_arg1[MAXDEV], gd_arg2[MAXDEV]
+common /zgdcom/ gd_dev, gd_oschan, gd_status, gd_arg1, gd_arg2
+
+begin
+ if (gd_status[chan] == ERR) {
+ status = ERR
+ return
+ }
+
+ # [ADD NEW DEVICES HERE].
+
+ switch (gd_dev[chan]) {
+ case IISM70:
+ call zwtm70 (gd_oschan[chan], status)
+ case IISM75:
+ call zwtm75 (gd_oschan[chan], status)
+ case IMTOOL:
+ status = gd_status[chan]
+ default:
+ status = ERR
+ }
+end
+
+
+# ZSTTGD -- Get the file status of a binary graphics device.
+
+procedure zsttgd (chan, what, lvalue)
+
+int chan # channel assigned device
+int what # status parameter being queried
+long lvalue # receives value of parameter
+
+int gd_dev[MAXDEV], gd_oschan[MAXDEV]
+int gd_status[MAXDEV], gd_arg1[MAXDEV], gd_arg2[MAXDEV]
+common /zgdcom/ gd_dev, gd_oschan, gd_status, gd_arg1, gd_arg2
+
+begin
+ # [ADD NEW DEVICES HERE].
+
+ switch (gd_dev[chan]) {
+ case IISM70:
+ call zstm70 (gd_oschan[chan], what, lvalue)
+ case IISM75:
+ call zstm75 (gd_oschan[chan], what, lvalue)
+
+ case IMTOOL:
+ switch (what) {
+ case FSTT_FILSIZE:
+ lvalue = gd_arg1[chan] * gd_arg2[chan] * SZB_CHAR
+ case FSTT_BLKSIZE:
+ lvalue = gd_arg1[chan] * SZB_CHAR
+ case FSTT_OPTBUFSIZE:
+ lvalue = gd_arg1[chan] * SZB_CHAR
+ case FSTT_MAXBUFSIZE:
+ lvalue = 32768
+ default:
+ lvalue = ERR
+ }
+ default:
+ lvalue = ERR
+ }
+end