aboutsummaryrefslogtreecommitdiff
path: root/pkg/dataio
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 /pkg/dataio
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'pkg/dataio')
-rw-r--r--pkg/dataio/Revisions887
-rw-r--r--pkg/dataio/bintext/mkpkg11
-rw-r--r--pkg/dataio/bintext/t_bintxt.x65
-rw-r--r--pkg/dataio/bintext/t_txtbin.x65
-rw-r--r--pkg/dataio/bintxt.par4
-rw-r--r--pkg/dataio/cardimage/conversion.x221
-rw-r--r--pkg/dataio/cardimage/mkpkg13
-rw-r--r--pkg/dataio/cardimage/rcardimage.com10
-rw-r--r--pkg/dataio/cardimage/structure.hlp139
-rw-r--r--pkg/dataio/cardimage/t_rcardimage.x271
-rw-r--r--pkg/dataio/cardimage/t_wcardimage.x256
-rw-r--r--pkg/dataio/cardimage/tabs.x67
-rw-r--r--pkg/dataio/cardimage/wcardimage.com8
-rw-r--r--pkg/dataio/dataio.cl19
-rw-r--r--pkg/dataio/dataio.hd27
-rw-r--r--pkg/dataio/dataio.men13
-rw-r--r--pkg/dataio/dataio.par4
-rw-r--r--pkg/dataio/doc/Mtio_notes12
-rw-r--r--pkg/dataio/doc/Rfits_notes85
-rw-r--r--pkg/dataio/doc/bintxt.hlp28
-rw-r--r--pkg/dataio/doc/export.hlp1066
-rw-r--r--pkg/dataio/doc/import.hlp631
-rw-r--r--pkg/dataio/doc/mtexamine.hlp84
-rw-r--r--pkg/dataio/doc/rcardimage.hlp120
-rw-r--r--pkg/dataio/doc/reblock.hlp177
-rw-r--r--pkg/dataio/doc/rfits.hlp228
-rw-r--r--pkg/dataio/doc/rtextimage.hlp84
-rw-r--r--pkg/dataio/doc/t2d.hlp70
-rw-r--r--pkg/dataio/doc/txtbin.hlp28
-rw-r--r--pkg/dataio/doc/wcardimage.hlp74
-rw-r--r--pkg/dataio/doc/wfits.hlp237
-rw-r--r--pkg/dataio/doc/wtextimage.hlp100
-rw-r--r--pkg/dataio/export.par13
-rw-r--r--pkg/dataio/export/Notes37
-rw-r--r--pkg/dataio/export/bltins/exeps.x537
-rw-r--r--pkg/dataio/export/bltins/exgif.x557
-rw-r--r--pkg/dataio/export/bltins/exiraf.x110
-rw-r--r--pkg/dataio/export/bltins/exmiff.x81
-rw-r--r--pkg/dataio/export/bltins/expgm.x47
-rw-r--r--pkg/dataio/export/bltins/exppm.x49
-rw-r--r--pkg/dataio/export/bltins/exras.x117
-rw-r--r--pkg/dataio/export/bltins/exrgb.x74
-rw-r--r--pkg/dataio/export/bltins/exvicar.x111
-rw-r--r--pkg/dataio/export/bltins/exxwd.x253
-rw-r--r--pkg/dataio/export/bltins/mkpkg20
-rw-r--r--pkg/dataio/export/cmaps.inc534
-rw-r--r--pkg/dataio/export/exbltins.h28
-rw-r--r--pkg/dataio/export/exbltins.x243
-rw-r--r--pkg/dataio/export/excmap.x258
-rw-r--r--pkg/dataio/export/exfcn.h25
-rw-r--r--pkg/dataio/export/exhdr.x207
-rw-r--r--pkg/dataio/export/exobands.gx390
-rw-r--r--pkg/dataio/export/export.h155
-rw-r--r--pkg/dataio/export/expreproc.x352
-rw-r--r--pkg/dataio/export/exraster.gx621
-rw-r--r--pkg/dataio/export/exrgb8.x994
-rw-r--r--pkg/dataio/export/exzscale.x755
-rw-r--r--pkg/dataio/export/generic/exobands.x489
-rw-r--r--pkg/dataio/export/generic/exraster.x709
-rw-r--r--pkg/dataio/export/generic/mkpkg12
-rw-r--r--pkg/dataio/export/mkpkg36
-rw-r--r--pkg/dataio/export/t_export.x1160
-rw-r--r--pkg/dataio/export/zzedbg.x157
-rw-r--r--pkg/dataio/fits/fits_cards.x292
-rw-r--r--pkg/dataio/fits/fits_files.x374
-rw-r--r--pkg/dataio/fits/fits_params.x248
-rw-r--r--pkg/dataio/fits/fits_read.x469
-rw-r--r--pkg/dataio/fits/fits_rheader.x888
-rw-r--r--pkg/dataio/fits/fits_rimage.x557
-rw-r--r--pkg/dataio/fits/fits_rpixels.x154
-rw-r--r--pkg/dataio/fits/fits_wheader.x469
-rw-r--r--pkg/dataio/fits/fits_wimage.x497
-rw-r--r--pkg/dataio/fits/fits_wpixels.x162
-rw-r--r--pkg/dataio/fits/fits_write.x246
-rw-r--r--pkg/dataio/fits/mkpkg24
-rw-r--r--pkg/dataio/fits/rfits.com18
-rw-r--r--pkg/dataio/fits/rfits.h96
-rw-r--r--pkg/dataio/fits/t_rfits.x216
-rw-r--r--pkg/dataio/fits/t_wfits.x253
-rw-r--r--pkg/dataio/fits/wfits.com17
-rw-r--r--pkg/dataio/fits/wfits.h128
-rw-r--r--pkg/dataio/import.par30
-rw-r--r--pkg/dataio/import/README2
-rw-r--r--pkg/dataio/import/bltins/README13
-rw-r--r--pkg/dataio/import/bltins/ipcmap.x76
-rw-r--r--pkg/dataio/import/bltins/ipgif.x883
-rw-r--r--pkg/dataio/import/bltins/ipras.x504
-rw-r--r--pkg/dataio/import/bltins/ipxwd.x188
-rw-r--r--pkg/dataio/import/bltins/mkpkg13
-rw-r--r--pkg/dataio/import/fmtdb.x610
-rw-r--r--pkg/dataio/import/generic/ipdb.x813
-rw-r--r--pkg/dataio/import/generic/ipfio.x569
-rw-r--r--pkg/dataio/import/generic/ipobands.x375
-rw-r--r--pkg/dataio/import/generic/ipproc.x921
-rw-r--r--pkg/dataio/import/generic/mkpkg15
-rw-r--r--pkg/dataio/import/images.dat433
-rw-r--r--pkg/dataio/import/import.h132
-rw-r--r--pkg/dataio/import/ipbuiltin.x91
-rw-r--r--pkg/dataio/import/ipdb.gx766
-rw-r--r--pkg/dataio/import/ipfcn.h57
-rw-r--r--pkg/dataio/import/ipfio.gx443
-rw-r--r--pkg/dataio/import/ipinfo.x256
-rw-r--r--pkg/dataio/import/iplistpix.x137
-rw-r--r--pkg/dataio/import/ipmkhdr.x63
-rw-r--r--pkg/dataio/import/ipobands.gx306
-rw-r--r--pkg/dataio/import/ipproc.gx804
-rw-r--r--pkg/dataio/import/mkpkg37
-rw-r--r--pkg/dataio/import/t_import.x768
-rw-r--r--pkg/dataio/import/zzidbg.x145
-rw-r--r--pkg/dataio/imtext/imtext.h21
-rw-r--r--pkg/dataio/imtext/mkpkg19
-rw-r--r--pkg/dataio/imtext/putcplx.x88
-rw-r--r--pkg/dataio/imtext/putint.x160
-rw-r--r--pkg/dataio/imtext/putreal.x88
-rw-r--r--pkg/dataio/imtext/rt_cvtpix.x115
-rw-r--r--pkg/dataio/imtext/rt_rheader.x170
-rw-r--r--pkg/dataio/imtext/rt_rwpix.x271
-rw-r--r--pkg/dataio/imtext/t_rtextimage.x109
-rw-r--r--pkg/dataio/imtext/t_wtextimage.x261
-rw-r--r--pkg/dataio/imtext/wtextimage.semi91
-rw-r--r--pkg/dataio/imtext/wti_wheader.x152
-rw-r--r--pkg/dataio/lib/addcards.x140
-rw-r--r--pkg/dataio/lib/getdatatype.x57
-rw-r--r--pkg/dataio/lib/mkpkg12
-rw-r--r--pkg/dataio/lib/ranges.x234
-rw-r--r--pkg/dataio/mkpkg33
-rw-r--r--pkg/dataio/mtexamine.par8
-rw-r--r--pkg/dataio/mtexamine/mkpkg10
-rw-r--r--pkg/dataio/mtexamine/mtexamine.com6
-rw-r--r--pkg/dataio/mtexamine/t_mtexamine.x376
-rw-r--r--pkg/dataio/rcardimage.par14
-rw-r--r--pkg/dataio/reblock.par16
-rw-r--r--pkg/dataio/reblock/mkpkg12
-rw-r--r--pkg/dataio/reblock/reblock.com21
-rw-r--r--pkg/dataio/reblock/reblock.h7
-rw-r--r--pkg/dataio/reblock/reblock.hlp154
-rw-r--r--pkg/dataio/reblock/reblock_file.x416
-rw-r--r--pkg/dataio/reblock/structure.hlp50
-rw-r--r--pkg/dataio/reblock/t_reblock.x214
-rw-r--r--pkg/dataio/rfits.par12
-rw-r--r--pkg/dataio/rtextimage.par9
-rw-r--r--pkg/dataio/t2d.par5
-rw-r--r--pkg/dataio/t2d/mkpkg10
-rw-r--r--pkg/dataio/t2d/t_t2d.x280
-rw-r--r--pkg/dataio/txtbin.par4
-rw-r--r--pkg/dataio/wcardimage.par11
-rw-r--r--pkg/dataio/wfits.par18
-rw-r--r--pkg/dataio/wtextimage.par8
-rw-r--r--pkg/dataio/x_dataio.x17
149 files changed, 32492 insertions, 0 deletions
diff --git a/pkg/dataio/Revisions b/pkg/dataio/Revisions
new file mode 100644
index 00000000..2c83227f
--- /dev/null
+++ b/pkg/dataio/Revisions
@@ -0,0 +1,887 @@
+.help revisions Jun88 pkg.dataio
+.nf
+
+dataio$lib/mkpkg
+ The getdatatype.x and ranges.x files were duplicates of those in the
+ XTOOLS library which is linked in dataio. These files should be the
+ versions actually linked in the binary, making XTOOLS unnecessary, but
+ I think the intent was to use XTOOLS. The getdatatype.x is identical
+ but there are slight changes in ranges.x. These files were left in
+ place in case there are problems found but the binary should now be
+ using the XTOOLS versions. (12/5/08, MJF)
+
+dataio$import/ipproc.gx
+ Fixed a type flag being used to determine byte-swapping. (12/5/08, MJF)
+
+dataio$import/t_import.x
+ Fixed a type declaration (1/21/08, MJF)
+
+dataio$export/exraster.gx
+ Fixed a bug in computing the number of output pixels (1/5/04, MJF)
+
+dataio$import/ipproc.gx
+ An operand point was possibly being freed twice, once in the ip_wrline()
+ procedure and again in the evvfree() call when processing completed.
+ This could cause a segfault on some system (9/27/02, MJF)
+
+dataio$export/exraster.gx
+dataio$export/bltins/exppm.x
+ There was a bug in the generation of PPM files when using images with
+ and odd number of columns causing the line to be too long by one byte.
+ The output image will now truncate the last column to avoid this since
+ we cannot write byte data. (8/9/02, MJF)
+
+dataio$export/export.h
+ Changed the zscale sampling parameters to use more points spread out
+ over more of the image. The old values would sometimes find an
+ innappropriate z1/z2 range causing problems when doing many images in
+ batch mode. (3/20/02, MJF)
+
+dataio$fits/t_rfits.x
+dataio$imtext/t_rtextimage.x
+ Changed the clgetc calls to to clgstr calls for the datatype parameter
+ in rfits and the otype parameter in rtextimage. This change is required
+ to avoid an "ERROR: Parameter not a legal character constant (parname)"
+ error introduced by recent changes to the CL. Basically "" is no longer
+ a legal argument for clgetc. (6/15/01 LED)
+
+dataio$fits/fits_rheader.x
+ Fixed a bug in the MEF file reading error recovery code that can cause
+ a segvio due to a too many open file descriptors condition. (5/1/01 LED)
+
+dataio$export/bltins/expgm.x
+dataio$export/bltins/exppm.x
+ Fixed a bug in writing the header for these formats on PCIX. (6/23/00 MJF)
+
+dataio$export.par
+ Made the 'format' parameter automatic mode (5/16/00 MJF)
+
+dataio$export/expreproc.x
+ Modified so that the 'overlay' colors are not scaled. (5/16/00 MJF)
+
+dataio$reblock/t_reblock.x
+dataio$reblock/reblock_file.x
+ Fixed a bug in the output block writing code caused by a failure to
+ check the status return of the awaitb call. At the same time worked
+ around a longstanding problem in tape to tape copies caused by
+ trying to open and close a magtape file for writing when there is
+ no data and fixed an initialization bug in the record trimming and
+ padding code that has been there a long time. (2/9/00 LED)
+
+dataio$import/ipdb.gx
+ Fixed a string overflow bug causing segvios on PCs (12/13/99 MJF)
+
+dataio$import.par
+dataio$export.par
+ Changed query param modes to auto to avoid prompt from epar :go
+ command. (11/4/99 MJF)
+
+dataio$export/bltins/exeps.x
+ Fixed an array overrun when writing EPS trailer comments. (10/25/99 MJF)
+
+dataio$export/mkpkg
+dataio$export/*/mkpkg
+dataio$import/mkpkg
+dataio$import/*/mkpkg
+ Fixed missing/extra file dependencies (9/20/99, MJF)
+
+dataio$export/exrgb8.x
+ Fixed a bug causing the cmap() function to write a garbage line at the
+ top or bottom of the output image. (8/20/99 MJF)
+
+dataio$export/exzscale.x
+dataio$import/t_import.x
+dataio$import/bltins/ipgif.x
+ Cleaned up some missing sfree() calls. (7/28/99 MJF)
+
+dataio$fits/wfits.h
+dataio$fits/fits_cards.x
+dataio$fits/fits_params.x
+ Modified wfits to write the DATE keyword value in the new format (including
+ a time field) and in units of GMT. (5/8/99 LED)
+
+dataio$export/bltins/exhdr.x
+ Changed the binary file header to use a 4-digit year (5/5/99, er..1999 MJF))
+
+dataio$export/bltins/exras.x
+dataio$export/bltins/exxwd.x
+ Fixed a bug in which rasterfiles and XWD file aren't swapped on LSB
+ machines when requested by the user. (12/14/98 MJF)
+
+dataio$import/t_import.x
+dataio$import/ipproc.gx
+ Fixed a bug preventing 1-D data from being converted. (12/10/98 MJF))
+
+dataio$import/t_import.x
+ Modified to initialize the 'use_cmap' flag to on by default so 8-bit
+ colormap images will be converted correctly. (7/14/98 MJF)
+
+dataio$fits/fits_cards.x
+ Added a check for pre-existing IRAFNAME keywords to the wfits task
+ (6/18/98 LED)
+
+dataio$export/exzscale.x
+dataio$export/t_export.x
+dataio$export/exobands.gx
+dataio$export/bltins/exeps.x
+dataio$export/bltins/exgif.x
+dataio$export/bltins/exrgb.x
+dataio$export/bltins/exxwd.x
+ Removed some unused variable and fixed type clashes (3/28/98 MJF)
+
+dataio$export/expreproc.x
+ Fixed a bug where the setcmap function was finding the colormap name
+ incorrectly when '@' params were used in a zscale function (2/2/98 MJF)
+
+dataio$import/t_import.x
+dataio$import/ipobands.gx
+ Fixed a bug in which use of the red()/green()/blue() functions caused
+ the size of the output image to be computed incorrectly. (12/12/97 MJF)
+
+dataio$fits/fits_read.x
+ Fixed a bug in the header listing code which resulted in rfits reading
+ through the whole image after listing the data when EXTENSION = N.
+ (11/3/97 LED)
+
+dataio$fits/fits_read.x
+ Fixed a bug in the global header handling code that could result a
+ the global image header being left in the tmp$ directory.
+ (8/6/97 LED)
+
+dataio$wfits.par
+dataio$fits/t_wfits.x
+dataio$doc/wfits.hlp
+ Added a new parameter call fextn whose default value is "fits" to the
+ wfits task. A ".fextn" suffix is appended to the output disk file names
+ to ensure that they are compatable with the fits kernel.
+ (6/20/97 LED)
+
+dataio$rfits.par
+dataio$wfits.par
+dataio$doc/rfits.hlp
+dataio$doc/wfits.hlp
+dataio$fits/fits_cards.x
+dataio$fits/fits_files.x
+dataio$fits/fits_params.x
+dataio$fits/fits_read.x
+dataio$fits/fits_rheader.x
+dataio$fits/fits_rimage.x
+dataio$fits/fits_rpixels.x
+dataio$fits/fits_wheader.x
+dataio$fits/fits_wimage.x
+dataio$fits/fits_wpixels.x
+dataio$fits/fits_write.x
+dataio$fits/mkpkg
+dataio$fits/rfits.com
+dataio$fits/rfits.h
+dataio$fits/t_rfits.x
+dataio$fits/t_wfits.x
+dataio$fits/wfits.com
+dataio$fits/wfits.h
+ Installed new versions of rfits and wfits. The new rfits and wfits
+ include support for: 1) reading and writing multi-extension fits files,
+ 2) reading and writing global header, 3) reading and writing ushort
+ images by default when appropriate.
+ (6/9/97 LED)
+
+
+dataio$doc/export.hlp
+dataio$export/excmap.x
+dataio$export/cmaps.inc
+ Added the 'overlay' cmap as a builtin cmap. (6/6/97)
+
+dataio$export/expreproc.x
+ Removed a call to scale the colormaps when using the default values.
+ Cmaps are now only scaled when a brightness/contrast value is set in
+ the setcmap() function. (6/6/97 MJF)
+
+dataio$export/bltins/exgif.x
+ Fixed a small error in the output of GIF files causing some display
+ programs to complain. GIF images which would now be an odd number of
+ bytes have an extra trailing ';' delimiter. This should be harmless
+ as all processing is supposed to stop once that char is found. (6/6/97 MJF)
+
+dataio$mkpkg
+dataio$dataio.cl
+dataio$dataio.hd
+dataio$dataio.men
+dataio$x_dataio.x
+dataio$import/ +
+dataio$import.par +
+dataio$export/ +
+dataio$export.par +
+dataio$doc/import.hlp +
+dataio$doc/export.hlp +
+ Installed the IMPORT/EXPORT task for general use. The images database
+ used by the IMPORT task is currently defined to be dataio$import/images.dat.
+ (3/31/97 MJF)
+
+
+dataio$fits/fits_rheader.x
+ Explictly set SIMPLE(fits) to YES the first time this card is encountered
+ so that duplicate fits SIMPLE cards are properly filtered out. Duplicate
+ SIMPLE cards are illegal fits so this should never happen but ...
+ (6/28/96 Davis).
+
+dataio$fits/fits_cards.x
+ Added some wfits code to filter any "END " keywords out of the image
+ header userarea.
+ (3/17/95 Davis)
+
+dataio$fits/t_wfits.x
+ Wfits was using the name of the @file instead of the first file as the
+ root output fits file name if the number of output files was 1.
+ (1/18/95 Davis)
+
+dataio$fits/fits_wheader.x
+ The autoscaling code was failing in the case bitpix=16 and pixtype=ushort.
+ Bscale and bzero values were being set to 1.0 and 0.0 respectively,
+ resulting in truncation of data values. The code has been modified to
+ set bscale and bzero to 1.0 and 32768 instead.(10/18/94 Davis)
+
+dataio$imtext/t_rtextimage.x
+dataio$imtext/t_wtextimage.x
+dataio$imtext/rt_cvtpix.x
+dataio$rtextimage.par
+dataio$wtextimage.par
+dataio$doc/rtextimage.hlp
+dataio$doc/wtextimage.hlp
+ A parameter "pixels" was added to select whether to read or write
+ the pixel values. This is complementary to rfits/wfits and allows
+ use of these tasks to store and restore image headers. (10/22/93, Valdes)
+
+dataio$reblock/t_reblock.x: Davis, Jan 20, 1993
+ Added support for multiple disk file input and output to the reblock
+ task.
+
+dataio$fits/fits_read: Davis, Apr 27, 1992
+ Modified rfits to use the fe parameter to skip to EOF for devices
+ e.g. cartridge tapes which seem to be having problems with file
+ skips.
+
+dataio$fits/t_rfits.x: Davis, Mar 25, 1992
+ Rfits was using the name of the @file instead of the first file as the
+ root output image name if the number of output files was 1.
+
+dataio$fits/fits_read: Davis, Feb 27, 1992
+ Changed the interpreation of the fe parameter as read from dev$tapecap
+ from MB to KB.
+
+dataio$fits/fits_write: Davis, Feb 18, 1992
+ Replaced a call to imgimage with one to imgcluster to extract the root
+ image name minus cluster and section.
+
+dataio$fits/t_rfits.x: Davis, Feb 18, 1992
+dataio$fits/t_wfits.x: Davis, Feb 18, 1992
+ Changed the maximum sequence number that can be appended to an output
+ root image of fits file name from 999 to 9999.
+
+dataio$fits/rfits.com: Davis, Feb 18, 1992
+dataio$fits/t_rfits.x: Davis, Feb 18, 1992
+dataio$fits/fits_read.x: Davis, Feb 18, 1992
+ Implemented a scan mode in rfits so that devices which have a slow
+ single-file file skip function (e.g. dat drives) can be used more
+ efficiently with the rfits make_image=no option.
+
+dataio$fits/fits_params.x: Davis, Feb 17, 1992
+ Modified wfits so that string parameters that are 1) written explictly
+ by wfits, and 2) <= 20 characters long including quotes, will have the /
+ in column 33 instead of 2 spaces past the end of the string. The
+ affected keywords are OBJECT, ORIGIN, DATE, IRAFNAME, IRAF-BPX, and
+ IRAFTYPE.
+
+dataio$fits/fits_wheader.x: Davis, Feb 17, 1992
+ Modified the short_header=yes option in wfits so that the image pixel
+ type, fits bitpix, and the scaling parameters are printed on the
+ standard output.
+
+dataio$fits/fits_rimage.x: Davis, Feb 17, 1992
+dataio$fits/fits_wimage.x: Davis, Feb 17, 1992
+ Modified rfits so that the ieee +/-NaNs, and +/-Infs are correctly
+ mapped to a user specified native floating point number. Underflow values
+ are automatically converted to 0.0. A warning message is printed on
+ the terminal if any bad pixels were replaced. A warning message is
+ also printed if valid floating point pixel values > MAX_REAL or <
+ -MAX_REAL were detected. Imreplace can be used to replace these
+ explicitly.
+
+dataio$fits/fits_rheader.x: Davis, Feb 14, 1992
+ Modified rfits to replace control characters decimal 0 (00X) to
+ 31 (1FX) and decimal 127 (7FX) with the blank character. The
+ new fits standard now explicitly defines these illegal in fits
+ headers.
+
+dataio$wfits.par: From, Davis, Feb 13, 1992
+dataio$doc/wfits.hlp: From, Davis, Feb 13, 1992
+dataio$fits/wfits.h: From, Davis, Feb 13, 1992
+dataio$fits/t_wfits.x: From, Davis, Feb 13, 1992
+dataio$fits/fits_write.x: From, Davis, Feb 13, 1992
+dataio$fits/fits_wheader.x: From, Davis, Feb 13, 1992
+dataio$fits/fits_wimage.x: From, Davis, Feb 13, 1992
+dataio$fits/fits_wpixels.x: From, Davis, Feb 13, 1992
+ 1. Modified wfits to fetch the default fits blocking factor for a device
+ from the dev$tapecap file. The user can still overrride this value
+ (which is usually set to 10) for variable blocked devices, but is no
+ longer required to know or set the block size for fixed block devices
+ like cartridge tapes.
+
+dataio$mtexamine/t_mtexamine.x: From, Davis, Jan 6, 1992
+dataio$cardimage/t_rcardimage.x: From, Davis, Jan 6, 1992
+dataio$cardimage/t_wcardimage.x: From, Davis, Jan 6, 1992
+dataio$reblock/t_reblock.x: From, Davis, Jan 6, 1992
+dataio$fits/t_rfits.x: From, Davis, Jan 6, 1992
+dataio$fits/t_wfits.x: From, Davis, Jan 6, 1992
+ 1. Modified the mtexamine, rcardimage, wcardimage, reblock, rfits, and
+ wfits tasks to accept the new magtape file name syntax.
+
+dataio$reblock/t_reblock.x: From, Davis, Dec 11, 1991
+ 1. Modified reblock so that character constants like '\n' can be
+ used as record padding characters.
+
+dataio$t2d/mkpkg: From Davis, Dec 3, 1991
+ 1. Removed the printf.h file dependency from the mkpkg.
+
+dataio$imtext/mkpkg: From Davis, Dec 3, 1991
+ 1. Added missing files dependencies for the files rt_rheader.x
+ (imio.h) and wti_wheader.x (imio.h).
+
+dataio$fits/mkpkg: From Davis, Dec 3, 1991
+dataio$fits/fits_read.x
+ 1. Added missing files dependencies for the files fits_rheader.x
+ (ctype.h) and fits_wimage.x (error.h).
+ 2. Removed unused "include <imset.h>" statement from fits_read.x
+
+dataio$cardimage/mkpkg: From Davis, Dec 3, 1991
+ 1. The entries for t_rcardimage.x and t_wcardimage.x were missing
+ several file dependencies.
+
+dataio$fits/fits_cards.x: From Davis, Oct 15, 1991
+ 1. Changed the name of the IRAF-B/P keyword to IRAF-BPX to conform to the
+ new FITS standard.
+
+dataio$fits/fits_rpixels.x: From Davis, Oct 9, 1991
+ 1. The rfits task has been modified to permit a short last record, i.e.
+ a last record that has not been padded out to 2880 bytes, without
+ generating any warning messages.
+
+dataio$fits/wfits.h: From Davis, Jun 11, 1991
+dataio$fits/t_wfits.x: From Davis, Jun 11, 1991
+dataio$fits/fits_write.x: From Davis, Jun 11, 1991
+dataio$fits/fits_wheader.x: From Davis, Jun 11, 1991
+ 1. The wfits task has been modified to write IEEE format FITS files
+ (fits bitpix = -32 and -64), instead of scaled integers if the input
+ image pixel type is real or double respectively and if the wfits parameter
+ bitpix is left at the default. If the user overrides the default and
+ elects to scale the data, a warning message with an estimate of the
+ precision loss is provided.
+
+dataio$fits/fits_write.x: From Davis, Jun 10, 1991
+dataio$fits/fits_read.x: From Davis, Jun 10, 1991
+ 1. Modified the fits writer and reader so that the IRAFNAME parameter
+ can deal with image sections. The fits writer will now record image
+ sections in the IRAFNAME parameter instead of inserting a blank.
+ The directory specification is still stripped. The fits reader will
+ now strip off any section notation before attempting to rename
+ the output image.
+
+dataio$fits/fits_rimage.x: From Davis, Jan 17, 1991
+dataio$fits/fits_wimage.x: From Davis, Jan 17, 1991
+ 1. Modified the scaling routines in rfits and wfits to minimize
+ the precision lost when converting from real pixels to fits integers
+ and vice versa.
+
+dataio$cardimage/t_rcardimage.x: From Davis, Jan 3, 1991
+dataio$doc/rcardimage.hlp: From Davis, Jan 3, 1991
+ 1. Modified rcardimage so that the error message encountered
+ when an odd-blocked rcardimage tape is encountered is less obscure.
+ 2. Modified the rcardimage help page to include an example of how to
+ reformat and odd-blocked cardimage tape with reblock.
+
+dataio$fits/t_rfits.x: From Davis, Dec 6, 1990
+ 1. Modified rfits so that it will supply a temporary root output file
+ name if old_irafname="yes" and quit with a clear error message if
+ old_irafname="no", in the case where the user sets the output file
+ to the null string "".
+
+dataio$fits/fits_rheader.x: From Davis, Sept 11, 1990
+ 1. Changed rfits so that history cards know go into the user area
+ instead of the history area where they get truncated.
+
+dataio$fits/wfits.h: From Davis, August 15, 1990
+dataio$fits/t_wfits.x: From Davis, August 15, 1990
+dataio$fits/fits_write.x: From Davis, August 15, 1990
+dataio$fits/fits_wimage.x: From Davis, August 15, 1990
+dataio$fits/fits_wpixels.x: From Davis, August 15, 1990
+dataio$fits/fits_rpixels.x: From Davis, August 15, 1990
+ 1. Wfits will now permit FITS blocking factors up to and including
+ 22 although a warning message will be issued if a blocking factor
+ > 10 is requested.
+
+ 2. Wfits occasionally crashed with a segmentation violation if a
+ non-standard fits blocking factor was selected. This error was
+ triggered if the unused portion of the output block to be blank
+ filled was greater than 2880 bytes. This bug has been fixed in
+ 2.10
+
+ 3. Rfits was not reading FITS data with a block size < 2880 on
+ the 9-track drives correctly. This bug has been fixed in 2.10.
+
+ 4. Wfits.rfits now sets the length of the user area to the maximum of
+ the default of 28800 chars and the value of the environment variable
+ "min_lenuserarea".
+
+dataio$fits/fits_wheader.x: From Davis, July 3, 1990
+dataio$fits/fits_cards.x: From Davis, July 3, 1990
+dataio$fits/fits_rheader.x: From Davis, July 3, 1990
+ Fixed a problem in the way bscale and bzero were computed that was
+ causing floating point errors for some double precision images,
+ basically because the precision was worse than I thought.
+ The really problem is that the min and max of a double precision
+ image are stored as reals in the image header do they do not
+ quite correspond to what is in the image. The solution was to extend
+ the values of the min and max to slightly lower and higher values
+ respectively. These problems will go away when ieee becomes more
+ accepted. (See messages below for history of this problem)
+
+ Wfits now checks for the presence of the FITS keywords SIMPLE, BITPIX,
+ NAXIS and NAXISn in the user area and filters them out before writing
+ the FITS header.
+
+ Rfits will now ignore FITS keywords that are duplicates of SIMPLE,
+ BITPIX, NAXIS and NAXISn. A warning message is issued if any of
+ these keywords are duplicated.
+
+dataio$fits/fits_wheader.x: From Davis, April 21
+dataio$fits/fits_write.x: From Davis, April 21
+dataio$fits/fits_read.x: From Davis, April 21
+ The original scaling algorithm was restored due to problems encountered
+ with the new one. This will be looked into more fully in version 2.10.
+ These means that a problem with double precision images may remain.
+
+ Since I had to make the above change at the last minute I added some
+ code to flush the STDOUT after in input and output file names
+ are computed and written to STDOUT. This avoids a problem with
+ output not being flushed when an error condition occurs and output
+ is being redirected causing confusion for the user who may not be able
+ to tell where the error occured in that case.
+
+dataio$fits/fits_wheader.x: From Davis, Mar 24, 1990
+ Fixed a problem with the scaling routines in wfits. Images with a
+ minimum which was negative and distant from the majority of the
+ data values could cause a problem in the scaling.
+
+dataio$fits/fits_rimage.x: From Davis, Mar 10, 1990
+ Recoded the routine that computes the mins and maxs of an image
+ slightly to remove a problem with the STF kernel. The mins and maxs
+ of the image were being reset to 0 when the first data was written
+ over-riding the program initialization of MAX_REAL and -MAX_REAL
+ and defeating the minimum calculation for all positive data.
+
+dataio$fits/fits_wheader.x: From Davis, Mar 9, 1990
+ Fixed a problem in the way bscale and bzero were computed that was
+ causing floating point errors for some double precision images,
+ basically because the precision was worse than I thought.
+ The really problem is that the min and max of a double precision
+ image are stored as reals in the image header do they do not
+ quite correspond to what is in the image. The solution was to extend
+ the values of the min and max to slightly lower and higher values
+ respectively. These problems will go away when ieee becomes more
+ accepted.
+
+dataio$fits/fits_cards: From Davis, Jan 20, 1990
+ Added a filter to remove duplicate IRAF-MIN, IRAF-MAX, IRAFTYPE,
+ and IRAF-B/P keywords from the user area.
+
+dataio$fits: From Davis, Jan 19, 1990
+ 1. Support was added for the IEEE floating point format to both
+ the rfits and wfits tasks. Rfits now recognizes -32 and -64 to
+ be legal values of bitpix representing respectively real and
+ double IEEE floating point format. Values of bscale and bzero
+ are applied if present in the header. By default wfits still
+ writes integer format FITS tapes with autoscaling. However if
+ the users selects a bitpix of -32 or -64 the appropriate floating
+ point format is written. In this case scaling is disabled.
+
+ 2. Rfits was modified to take a list of output images names or
+ an output image root name.
+
+ 3. Wfits was modified to take a list of output fits file names
+ or an output fits file root name.
+
+dataio$fits/fits_wheader.x: From Davis, Nov 20, 1989
+ 1. Fixed wfits so it would write out type "ushort" images correctly
+ with the default parameters. The chosen bitpix is 32 instead of
+ 16.
+
+dataio$fits/t_rfits.x,t_wfits.x: From Davis, May 29, 1989
+ 1. Changed both these tasks so the STDOUT is only flushed on a newline
+ if has not been redirected. Changed the remaining eprintf statements
+ to printf statements.
+
+dataio$fits/fits_rheader.x: From Davis, May 9, 1989
+ 1. Fixed abug in the code which decodes hms format numbers. The
+ problem was caused by leading blanks and the fact that the ctoi
+ routine does not recognize the plus character.
+
+dataio$fits/t_wfits.x: From Davis, Mar 31, 1989
+dataio$fits/wft_wimage.x: From Davis, Mar 31, 1989
+dataio$fits/wft_wpixels.x: From Davis, Mar 31, 1989
+ 1. Changed wfits so that a warning message is printed if the fits
+ long blocks option is used. The previous version only warned the
+ user if an illegal fits block size was used.
+ 2. Changed wfits so that the record structure written is printed
+ out on the standard output if short_header = yes as well as if
+ long_header = yes.
+ 3. Changed the error trapping code so that the number of records
+ actually written is printed out when wfits terminates prematurely
+ with an error condition.
+
+
+dataio$fits/t_wfits.x: From Davis, Mar 14, 1989
+dataio$fits/fits_rpixels: From Davis, Mar 14, 1989
+ 1. Changed wfits so that warning messages are printed if the user
+ overrides the default value of bitpix or turns of autoscaling.
+ These messages will be printed to the standard output along with
+ the output log.
+ 2. I have fixed a problem in the error checking code in rfits.
+ Too many reads were being done after an error recovery resulting
+ in the data in the output image being skewed. This needs to be
+ rechecked on DRACO where the original error recovery was done.
+
+dataio$reblock: From Davis, Jan 27, 1989
+ 1. Fixed a problem in reblock for tape to tape copies. The copyn parameter
+ was being ignored if no reblocking was occurring. This problem has been
+ fixed. A minor problem with the record counter was also fixed.
+
+dataio$fits: From Davis, Apr 14, 1988
+ 1. Added an option in wfits to write a non-standard physical block size
+ of blocking_factor > 10. This permits users with restricted block
+ size devices to read and write fits tapes.
+
+ 2. Changed the cl file name template commands inside wfits to images
+ name template commands.
+
+dataio$fits: From Davis, Mar23, 1988
+ 1. Fixed a bug in the fits string parameter trimming routine in which
+ the newline was being overwritten if the string was exactly 80
+ characters long.
+
+dataio$rfits: From Davis, December 11, 1987
+ 1. Fixed a small bug in the rfits disk handling code. If a user
+ successfully read a fits disk file, for example fitsdat, and then
+ tried to read a list of files using a template which did not match
+ any of the disk files, rfits would try to reread fitsdat. Rfits was
+ not handling the 0 length disk file list condition correctly.
+
+dataio$rfits: From Davis, December 3, 1987
+ 1. Rfits now checks for valid bscale and bzero values. If it cannot
+ decode bscale or bzero it sets them to 1.0 and 0.0 respectively.
+ 2. Rfits and wfits no longer flushes STDOUT on a newline if the output
+ has been redirected to a file. This greatly improves the speed of rfits
+ and wfits when the long_header parameter is set to yes especially for
+ VMS systems.
+
+dataio$rfits: From Davis, September 3, 1987
+ Rfits will now print out the ol irafname if short_header = yes, make_image
+ = no and old_name = yes. This makes it easier for users to list their
+ IRAF fits tapes.
+
+dataio$reblock/t_reblock.x: From Davis, August 12, 1987
+ The offset parameter in reblock was not being queried for by
+ the code.
+
+dataio$imtext/rt_rheader.x,wti_wheader.x: From SJacoby, June 10, 1987:
+ Tasks RTEXTIMAGE and WTEXTIMAGE no longer limit the image user area
+ being written to or read from to 2880 chars. The size of the
+ user area to be created or accessed by these tasks is controlled
+ by the IRAF environment variable `min_lenuserarea', and is not
+ limited by the code.
+
+dataio$fits/fits_rheader.x: From Davis, June 4, 1987:
+ The code for reading fits cards into the user area has been changed.
+ Rfits opens a new image with the default min_lenuserarea and
+ reads cards into it until it is filled. If the user area is
+ completely filled rfits issues a warning message along with the
+ number of fits parameters it was not able to completely store.
+
+dataio$fits/fits_write.x,fits_read.x,fits_rpixels.x: From Davis, May 15, 1987:
+ 1. I changed the error checking code so that it would work correctly
+ with the fits long blocks option. Wfits now does a call to fstat
+ to find out the number of bytes in the last read and uses this number
+ to validate the buffer if a read error occurs. There is no way to
+ recover from a read error in the tape record containing the header info.
+ 2. I added a check for the maximum permitted buffer size in wfits.
+ The program will abort if the device cannot suuport the length of
+ the output record requested.
+
+dataio$mtexamine/t_mtexamine.x: From Davis, May 15, 1987:
+ Error checking code has been added to MTEXAMINE. The task will now
+ print out a warning message for each bad record encountered and
+ continue reading the file instead of skipping to the next file.
+ The correct record count is preserved.
+
+dataio$imtext/wti_wheader.x, dataio$imtext/rt_rheader.x: Hammond, Mar 24, l987.
+ The FITS format header written by task WTEXTIMAGE has been changed. It
+ no longer contains the keywords SIMPLE=T and NAXIS=0. The output of
+ WTEXTIMAGE is a simple text file which makes no attempt to conform to
+ FITS standards. Task RTEXTIMAGE was modified to read both the old and
+ new format headers.
+
+dataio$t2d/t_t2d.x: From Lytle, Mar 20, 1987:
+ 1. T2D now deletes the zero length file left over when the program
+ encounters the end-of-tape and opens and closes an empty file.
+ 2. I also changed the verbose output format somewhat to make it
+ more logical.
+
+dataio$t_wcardimage: From Davis, Mar 19, 1987:
+ 1. WCARDIMAGE now checks that the input files are not binary
+ files before trying to write them to tape.
+
+dataio$fits: From Davis, Mar 19, 1987:
+ 1. More extensive error checking has been added to the FITS code.
+ Rfits attempts to recover from a read error in the data matrix.
+ Instead of terminating with a partially written image RFITS will
+ try to skip over the bad data. The resulting output image will
+ have the correct number of rows and columns but may contain one
+ or more records of bad data. The results of the error checking
+ may be tape drive dependent.
+ 2. RFITS now prints a warning message if no pixel file is
+ written (NAXIS = 0).
+ 3. RFITS now checks the first 6 characters of the first header record
+ to see if they are equal to SIMPLE.
+
+dataio$fits_wheader.x: From Davis, Jan 28, 1987:
+ 1. The scaling routine for determining bscale and bzero
+ introduced by Skip for the MV10000 was found to have problems
+ with some low dynamic range data. The symptom was that
+ the min value of an image restored from a FITS data would
+ have larger than expected roundoff errors. I have changed it back
+ to my original scaling algorithm.
+
+dataio$cardimage/: From Davis, Jan 20, 1987:
+ 1. Rcardimage has been modified to accept a list of disk files as
+ input as well as a list of tape files.
+
+dataio$fits/: From Davis, Jan 20, 1987
+ 1. The FITS longblocks option has been added to the FITS readers and
+ writers. RFITS will read long-blocked FITS data. The redundant
+ len_record parameter has been removed. IRAF mtio handles the tape
+ record buffering transparently.
+ 2. The len_record parameter has been removed from WFITS and
+ replaced with a blocking parameter factor, which specifies the number
+ of 2880 byte FITS records can be written in a single tape block.
+ The maximum legal FITS blocking factor is 10.
+ 3. RFITS has been modified to accept a list of disk files as well as
+ a list of tape files. This should facilitate file transfers over
+ the ethernet.
+
+dataio$reblock/reb_reblock_file.x: From Davis, Dec 12, 1986
+ 1. A bug in the seek option on disk binary files has been fixed.
+ This bug would cause the number of bytes read to be incorrectly
+ computed.
+
+dataio$lib/addcards.x: From Hammond, Oct 27, 1986
+ Header cards containing real values are now written with a %g rather
+ than %f format. This change affects task wtextimage.
+
+dataio$fits/fits_wheader.x: From Davis, Oct2
+ 1. The way the scaling routine wft_set_scale computes the data range
+ has been changed. Instead of adjusting maxdata and mindata individually
+ for machine precision; the data range is first computed and then adjusted
+ for the machine precision. This change was made in response to precision
+ problems encountered on the MV10000.
+
+dataio$fits/wfits.h: From Davis, Sep12, 1986
+ 1. The integer constants BYTE_MIN, BYTE_MAX, BYTE_BLANK etc have been
+ changed to type double to avoid compiler generated integer overflows.
+ The data type of TAPEMIN and TAPEMAX in the WFITS structure has also
+ been changed to double. This change was made in response to compiler
+ errors encountered on the MV10000 and should be transparent to the users.
+
+dataio$imtext/rt_cvtpix.x: From Hammond, Sep2, 1986
+ A typographical error was corrected in a call to patmake. The
+ pattern "[DdEd]" has been replaced with the correct pattern "[DdEe]".
+ This means numbers written with a lower case 'e' in the exponent field
+ are recognized as floating point numbers when read from the text file.
+ This procedure is called by task RTEXTIMAGE.
+
+dataio$mtexamine/t_mtexamine.x: From Davis, Aug20, 1986
+ 1. MTEXAMINE on the SUN was outputting an array of zeroes when asked to
+ dump records with output_type = c. The problem was that a long integer
+ was being passed to the routine ctocc instead of a char. This error
+ was not being detected on the VAXES.
+
+dataio$fits/fits_params.x: From Davis, Aug20, 1986
+ 1. The boolean parameter param in routine wft_encodeb was changed to type
+ integer. Wft_encodeb was being called with param = YES which caused
+ portability problems on the MV10000.
+
+From Davis July 16, 1986:
+
+1. RFITS has been modified so that imbedded blanks in the UT, ZD, ST, RA and
+DEC keywords are replaced by zeros. For example the mountain fits writers
+produce hms numbers of the form 20: 6: 3. RFITS will convert this to 20:06:03.
+
+-----------------------------------------------------------------------------
+
+From Davis June 13, 1986:
+
+1. TXTBIN and BINTXT have been modified so that the file number is
+appended to the output file name. Previous versions appended the extensions
+".txt" and ".bin" to the input file name.
+
+------------------------------------------------------------------------------
+
+From Davis June 12, 1986:
+
+1. WCARDIMAGE and WFITS now append a file number to the output file name
+if multiple disk files are being written. In the old writers a suffix
+was appended to the input file name (.fit for WFITS and .crd for
+WCARDIMAGE) and the output images were being copied to the input
+directory.
+
+------------------------------------------------------------------------------
+
+From Davis June 8, 1986:
+
+1. WFITS has been modified to store only the root of the image name. All
+pathname information has been stripped off.
+
+------------------------------------------------------------------------------
+
+From Davis May 28, 1986:
+
+1. The output of WFITS has been changed to print the file number, input file
+name, output file name, title and dimensions if long_header = no and
+short_header = yes.
+
+-------------------------------------------------------------------------------
+
+From Davis May 22, 1986:
+
+1. RFITS now writes 80 character records into the user area instead of
+trimming trailing whitespace from each record. This was changed to facilitate
+the image database interface. This change was also made to WTEXTIMAGE.
+
+-------------------------------------------------------------------------------
+
+From Davis May 21, 1986:
+
+A bug in the record trimming code of REBLOCK has been fixed. REBLOCK was
+computing the offset in the input block of data incorrectly.
+
+--------------------------------------------------------------------------------
+
+From Davis May 13, 1986:
+
+A bug in the error checking code in MTEXAMINE has been fixed. If there is an
+error on mtopen the program will abort instead of trying to open the next file.
+
+--------------------------------------------------------------------------------
+
+From Davis May 1, 1986:
+
+A problem with the autoscaling option in WFITS has been fixed. In order
+to avoid wrap around problems WFITS now assumes that the number of digits
+of machine precision is 1 less than the number in mach.h. In the case of
+the Vax the number is actually 6.? not 7 as quoted.
+
+-----------------------------------------------------------------------------
+
+From Davis Apr 17, 1986:
+
+Changed boolean == false constructs in files t_wcardimage.x and t_reblock.x
+to ! boolean.
+
+----------------------------------------------------------------------------
+
+From Davis Apr 4, 1986:
+
+The format of the RCAMERA DATE-OBS parameter has been changed form
+dd-mm-yyyy to dd/mm/yyyy to bring it into conformity with FITS standard.
+
+---------------------------------------------------------------------------
+
+From Hammond Mar 25, 1986:
+
+Task RTEXTIMAGE has been fixed so it properly skips over non standard fits
+headers, the number of lines being specified by the parameter nskip.
+
+___________________________________________________________________________
+
+From Davis Mar 9, 1986:
+
+The order of the REBLOCK parameters outfiles and file_list has been switched
+in order to preserve the correct command line sequence
+
+----------------------------------------------------------------------------
+
+From Davis Mar 3, 1986:
+
+The error checking in WFITS has been corrected so that WFITS terminates if
+it encounters a file write error instead of continuing to the next file
+as done previously.
+
+----------------------------------------------------------------------------
+
+From Davis Feb 19, 1986:
+
+1. Rfits and rpds have been fixed so that attempting to delete the last
+empty image does not generate a cannot delete protected file message.
+
+----------------------------------------------------------------------------
+
+From Davis Feb 3, 1986:
+
+1. A mysterious bug in which the date of observation card would sometimes
+not appear in the header has been fixed. A newline was missing from the
+proceeding header card.
+
+----------------------------------------------------------------------------
+
+From Davis Jan 16, 1986:
+
+1. Wfits no longer needs write permission to work. However as a consequence
+wfits no longer updates the image min and max.
+
+2. The scaling routines in rfits and wfits fits have been replaced by
+appropriate vector operators.
+
+3. The coordinate transformation parameters are now stored in the user
+area and are available to hedit, imgets etc.
+
+4. Scaled data is now read into real images regardless of the value of
+bitpix.
+
+-----------------------------------------------------------------------------
+
+From Davis Jan. 5, 1986:
+
+1. Rfits, rpds and rcamera now open dev$null instead of a temporary disk
+file for option make_image = no. This eliminates a lot od disk access overhead
+and should speed up these readers considerably.
+
+2. The default parameter options are now long_header=no and short_header=yes.
+Setting the long_header parameter to yes will over-ride the short header
+parameter.
+
+---------------------------------------------------------------------------
+
+From Davis Dec. 3, 1985:
+
+1. Rcamera will now print and store the header parameters ccdpicno and airmass
+if defined.
+
+2. A bug in the fringe scaling parameter calculation in rcamera was fixed.
+Currently the mountain programs store this number in floating point format.
+This will be changed in future necessitating a corresponding change in
+rcamera.
+
+-----------------------------------------------------------------------
+From Valdes Oct. 10, 1985:
+
+1. Defined widstape from ONEDSPEC package in the DATAIO package. The
+source and executable, however, still reside in ONEDSPEC (x_onedutil.e).
+Widstape and widsout should be combined and the source put in DATAIO
+at some point.
+.endhelp
diff --git a/pkg/dataio/bintext/mkpkg b/pkg/dataio/bintext/mkpkg
new file mode 100644
index 00000000..ff3db34f
--- /dev/null
+++ b/pkg/dataio/bintext/mkpkg
@@ -0,0 +1,11 @@
+# Bintext library
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ t_bintxt.x
+ t_txtbin.x
+ ;
diff --git a/pkg/dataio/bintext/t_bintxt.x b/pkg/dataio/bintext/t_bintxt.x
new file mode 100644
index 00000000..13b1e328
--- /dev/null
+++ b/pkg/dataio/bintext/t_bintxt.x
@@ -0,0 +1,65 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+define MAX_RANGES 100
+
+# T_BINTXT -- Procedure to convert binary files containing only text to text
+# files.
+
+procedure t_bintxt()
+
+bool verbose
+char outfile[SZ_FNAME]
+
+char infile[SZ_FNAME], out_fname[SZ_FNAME]
+int list, len_list, in, out, file_number
+
+bool clgetb()
+int strlen(), open(), clpopni(), clplen(), clgfil()
+
+begin
+ # Get input files
+ list = clpopni ("binary_file")
+ len_list = clplen (list)
+
+ # Get output files
+ call clgstr ("text_file", outfile, SZ_FNAME)
+
+ verbose = clgetb ("verbose")
+
+ file_number = 1
+ while (clgfil (list, infile, SZ_FNAME) != EOF) {
+
+ if (len_list > 1) {
+ call strcpy (outfile, out_fname, SZ_FNAME)
+ call sprintf (out_fname[strlen(out_fname) + 1], SZ_FNAME,
+ "%03d")
+ call pargi (file_number)
+ } else
+ call strcpy (outfile, out_fname, SZ_FNAME)
+
+ iferr {
+
+ if (verbose) {
+ call printf ("File: %s -> %s\n")
+ call pargstr (infile)
+ call pargstr (out_fname)
+ }
+
+ # Open input and output files, copy and close files
+ in = open (infile, READ_ONLY, BINARY_FILE)
+ out = open (out_fname, NEW_FILE, TEXT_FILE)
+ call fcopyo (in, out)
+ call close (in)
+ call close (out)
+
+ } then {
+ if (verbose) {
+ call eprintf ("Cannot read file %s\n")
+ call pargstr (infile)
+ }
+ } else
+ file_number = file_number + 1
+ }
+
+ call clpcls (list)
+end
diff --git a/pkg/dataio/bintext/t_txtbin.x b/pkg/dataio/bintext/t_txtbin.x
new file mode 100644
index 00000000..038a71ec
--- /dev/null
+++ b/pkg/dataio/bintext/t_txtbin.x
@@ -0,0 +1,65 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# T_TXTBIN -- Procedure to convert text files to binary files.
+
+procedure t_txtbin ()
+
+bool verbose
+char outfile[SZ_FNAME]
+
+char infile[SZ_FNAME], out_fname[SZ_FNAME]
+int list, len_list, in, out, file_number
+
+bool clgetb()
+int clpopni(), clplen(), clgfil(), strlen(), open()
+
+begin
+ # Get list of input files
+ list = clpopni ("text_file")
+ len_list = clplen (list)
+
+ # Get output file name
+ call clgstr ("binary_file", outfile, SZ_FNAME)
+
+ verbose = clgetb ("verbose")
+
+ # Loop over the files
+ file_number = 1
+ while (clgfil (list, infile, SZ_FNAME) != EOF) {
+
+ if (len_list > 1 ) {
+ call strcpy (outfile, out_fname, SZ_FNAME)
+ call sprintf (out_fname[strlen(out_fname) + 1], SZ_FNAME,
+ "%03d")
+ call pargi (file_number)
+ } else
+ call strcpy (outfile, out_fname, SZ_FNAME)
+
+ iferr {
+
+ if (verbose) {
+ call printf ("File: %s -> %s\n")
+ call pargstr (infile)
+ call pargstr (out_fname)
+ call flush (STDERR)
+ }
+
+ # Open input and output files, copy and close input and
+ # output files.
+ in = open (infile, READ_ONLY, TEXT_FILE)
+ out = open (out_fname, NEW_FILE, BINARY_FILE)
+ call fcopyo (in, out)
+ call close (in)
+ call close (out)
+
+ } then {
+ call eprintf ("Cannot read file: %s\n")
+ call pargstr (infile)
+ } else
+ file_number = file_number + 1
+ }
+ call clpcls (list)
+end
+
+
+
diff --git a/pkg/dataio/bintxt.par b/pkg/dataio/bintxt.par
new file mode 100644
index 00000000..359f9931
--- /dev/null
+++ b/pkg/dataio/bintxt.par
@@ -0,0 +1,4 @@
+mode,s,h,"ql",,,
+binary_file,s,a,,,,Input file name(s)
+text_file,s,a,,,,Output file name
+verbose,b,h,yes,,,Print messages?
diff --git a/pkg/dataio/cardimage/conversion.x b/pkg/dataio/cardimage/conversion.x
new file mode 100644
index 00000000..0d6f78af
--- /dev/null
+++ b/pkg/dataio/cardimage/conversion.x
@@ -0,0 +1,221 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+define MAX_CHARS 256
+
+
+# ASCII_TO_EBCDIC -- Vector procedure to convert ASCII characters to EBCDIC
+# characters using the lookup table atoe.
+
+procedure ascii_to_ebcdic (inbuffer, outbuffer, nchars)
+
+char inbuffer[ARB]
+short outbuffer[ARB], atoe[MAX_CHARS]
+int l, nchars
+
+data (atoe[l], l = 1, 8) / 0b, 1b, 2b, 3b, '7' , '-' , '.' , '/' /
+data (atoe[l], l = 9, 16) /26b, 5b, '%' , 13b, 14b, 15b, 16b, 17b /
+data (atoe[l], l = 17, 24) /20b, 21b, 22b, 23b, '<' , '=' , '2' , '&' /
+data (atoe[l], l = 25, 32) /30b, 31b, '?' , '\'', 34b, 35b, 36b, 37b /
+data (atoe[l], l = 33, 40) /'@' , 'O' , 177b, '{' , '[' , 'l' , 'P' , '}' /
+data (atoe[l], l = 41, 48) /'M' , ']' , '\\' , 'N' , 'k' , '`' , 'K' , 'a'/
+data (atoe[l], l = 49, 56) /360b, 361b, 362b, 363b, 364b, 365b, 366b, 367b/
+data (atoe[l], l = 57, 64) /370b, 371b, 'z' , '^' , 'L' , '~' , 'n' , 'o' /
+data (atoe[l], l = 65, 72) /'|' , 301b, 302b, 303b, 304b, 305b, 306b, 307b/
+data (atoe[l], l = 73, 80) /310b, 311b, 321b, 322b, 323b, 324b, 325b, 326b/
+data (atoe[l], l = 81, 88) /327b, 330b, 331b, 342b, 343b, 344b, 345b, 346b/
+data (atoe[l], l = 89, 96) /347b, 350b, 351b, 'J' , 340b, 'Z' , '_' , 'm' /
+data (atoe[l], l = 97, 104) /'y' , 201b, 202b, 203b, 204b, 205b, 206b, 207b/
+data (atoe[l], l = 105, 112) /210b, 211b, 221b, 222b, 223b, 224b, 225b, 226b/
+data (atoe[l], l = 113, 120) /227b, 230b, 231b, 242b, 243b, 244b, 245b, 246b/
+data (atoe[l], l = 121, 128) /247b, 250b, 251b, 300b, 'j' , 320b, 241b, 7b/
+data (atoe[l], l = 129, 136) /' ' , '!' , '"' , '#' , '$' , 25b, 6b, 27b/
+data (atoe[l], l = 137, 144) /'(' , ')' , '*' , '+' , ',' , 11b, 12b, 33b/
+data (atoe[l], l = 145, 152) /'0' , '1' , 32b, '3' , '4' , '5' , '6' , 10b/
+data (atoe[l], l = 153, 160) /'8' , '9' , ':' , ';' , 4b, 24b, '>' , 341b/
+data (atoe[l], l = 161, 168) /'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' , 'H' /
+data (atoe[l], l = 169, 176) /'I' , 'Q' , 'R' , 'S' , 'T' , 'U' , 'V' , 'W' /
+data (atoe[l], l = 177, 184) /'X' , 'Y' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' /
+data (atoe[l], l = 185, 192) /'h' , 'i' , 'p' , 'q' , 'r' , 's' , 't' , 'u' /
+data (atoe[l], l = 193, 200) /'v' , 'w' , 'x' , 200b, 212b, 213b, 214b, 215b/
+data (atoe[l], l = 201, 208) /216b, 217b, 220b, 232b, 233b, 234b, 235b, 236b/
+data (atoe[l], l = 209, 216) /237b, 240b, 252b, 253b, 254b, 255b, 256b, 257b/
+data (atoe[l], l = 217, 224) /260b, 261b, 262b, 263b, 264b, 265b, 266b, 267b/
+data (atoe[l], l = 225, 232) /270b, 271b, 272b, 273b, 274b, 275b, 276b, 277b/
+data (atoe[l], l = 233, 240) /312b, 313b, 314b, 315b, 316b, 317b, 332b, 333b/
+data (atoe[l], l = 241, 248) /334b, 335b, 336b, 337b, 352b, 353b, 354b, 355b/
+data (atoe[l], l = 249, 256) /356b, 357b, 372b, 373b, 374b, 375b, 376b, 377b/
+
+begin
+ call alutcs (inbuffer, outbuffer, nchars, atoe)
+end
+
+
+# EBCDIC_TO_ASCII -- Vector procedure to convert EBCDIC characters to ASCII
+# characters.
+
+procedure ebcdic_to_ascii (inbuffer, outbuffer, nchars)
+
+char outbuffer[ARB]
+short inbuffer[ARB], etoa[MAX_CHARS]
+int l, nchars
+
+data (etoa[l], l = 1, 8) / 0b, 1b, 2b, 3b, 234b, 11b, 206b, 177b /
+data (etoa[l], l = 9, 16) /227b, 215b, 216b, 13b, 14b, 15b, 16b, 17b/
+data (etoa[l], l = 17, 24) /20b, 21b, 22b, 23b, 235b, 205b, 10b, 207b /
+data (etoa[l], l = 25, 32) /30b, 31b, 222b, 217b, 34b, 35b, 36b, 37b /
+data (etoa[l], l = 33, 40) /200b, 201b, 202b, 203b, 204b, 12b, 27b, 33b/
+data (etoa[l], l = 41, 48) /210b, 211b, 212b, 213b, 214b, 5b, 6b, 7b/
+data (etoa[l], l = 49, 56) /220b, 221b, 26b, 223b, 224b, 225b, 226b, 4b/
+data (etoa[l], l = 57, 64) /230b, 231b, 232b, 233b, 24b, 25b, 236b, 32b/
+data (etoa[l], l = 65, 72) /' ' , 240b, 241b, 242b, 243b, 244b, 245b, 246b/
+data (etoa[l], l = 73, 80) /247b, 250b, '[' , '.' , '<' , '(' , '+' , '!' /
+data (etoa[l], l = 81, 88) /'&' , 251b, 252b, 253b, 254b, 255b, 256b, 257b/
+data (etoa[l], l = 89, 96) /260b, 261b, ']' , '$' , '*' , ')' , ';' , '^' /
+data (etoa[l], l = 97, 104) /'-' , '/' , 262b, 263b, 264b, 265b, 266b, 267b/
+data (etoa[l], l = 105, 112) /270b, 271b, '|' , ',' , '%' , '_' , '>' , '?' /
+data (etoa[l], l = 113, 120) /272b, 273b, 274b, 275b, 276b, 277b, 300b, 301b/
+data (etoa[l], l = 121, 128) /302b, '`' , ':' , '#' , '@' , '\'' , '=' , '"'/
+data (etoa[l], l = 129, 136) /303b, 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' /
+data (etoa[l], l = 137, 144) /'h' , 'i' , 304b, 305b, 306b, 307b, 310b, 311b/
+data (etoa[l], l = 145, 152) /312b, 'j' , 'k' , 'l' , 'm' , 'n' , 'o' , 'p' /
+data (etoa[l], l = 153, 160) /'q' , 'r' , 313b, 314b, 315b, 316b, 317b, 320b/
+data (etoa[l], l = 161, 168) /321b, '~' , 's' , 't' , 'u' , 'v' , 'w' , 'x' /
+data (etoa[l], l = 169, 176) /'y' , 'z' , 322b, 323b, 324b, 325b, 326b, 327b/
+data (etoa[l], l = 177, 184) /330b, 331b, 332b, 333b, 334b, 335b, 336b, 337b/
+data (etoa[l], l = 185, 192) /340b, 341b, 342b, 343b, 344b, 345b, 346b, 347b/
+data (etoa[l], l = 193, 200) /'{' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' /
+data (etoa[l], l = 201, 208) /'H' , 'I' , 350b, 351b, 352b, 353b, 354b, 355b/
+data (etoa[l], l = 209, 216) /'}' , 'J' , 'K' , 'L' , 'M' , 'N' , 'O' , 'P' /
+data (etoa[l], l = 217, 224) /'Q' , 'R' , 356b, 357b, 360b, 361b, 362b, 363b/
+data (etoa[l], l = 225, 232) /'\\', 237b, 'S' , 'T' , 'U' , 'V' , 'W' , 'X' /
+data (etoa[l], l = 233, 240) /'Y' , 'Z' , 364b, 365b, 366b, 367b, 370b, 371b/
+data (etoa[l], l = 241, 248) /'0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' /
+data (etoa[l], l = 249, 256) /'8' , '9' , 372b, 373b, 374b, 375b, 376b, 377b/
+
+begin
+ call alutsc (inbuffer, outbuffer, nchars, etoa)
+end
+
+
+# IBM_TO_ASCII -- Vector procedure for converting IBM characters to ASCII
+# characters.
+
+procedure ibm_to_ascii (inbuffer, outbuffer, nchars)
+
+char outbuffer[ARB]
+short inbuffer[ARB], ibmtoa[MAX_CHARS]
+int l, nchars
+
+data (ibmtoa[l], l = 1, 8) /0b, 1b, 2b, 3b, 234b, 11b, 206b, 177b /
+data (ibmtoa[l], l = 9, 16) /1227b, 215b, 216b, 13b, 14b, 15b, 16b, 17b/
+data (ibmtoa[l], l = 17, 24) /20b, 21b, 22b, 23b, 235b, 205b, 10b, 207b /
+data (ibmtoa[l], l = 25, 32) /30b, 31b, 222b, 217b, 34b, 35b, 36b, 37b /
+data (ibmtoa[l], l = 33, 40) /200b, 201b, 202b, 203b, 204b, 12b, 27b, 33b/
+data (ibmtoa[l], l = 41, 48) /210b, 211b, 212b, 213b, 214b, 5b, 6b, 7b/
+data (ibmtoa[l], l = 49, 56) /220b, 221b, 26b, 223b, 224b, 225b, 226b, 4b/
+data (ibmtoa[l], l = 57, 64) /230b, 231b, 232b, 233b, 24b, 25b, 236b, 32b/
+data (ibmtoa[l], l = 65, 72) /' ' , 240b, 241b, 242b, 243b, 244b, 245b, 246b/
+data (ibmtoa[l], l = 73, 80) /247b, 250b, 0b, '.' , '<' , '(' , '+' , '|' /
+data (ibmtoa[l], l = 81, 88) /'&' , 251b, 252b, 253b, 254b, 255b, 256b, 257b/
+data (ibmtoa[l], l = 89, 96) /260b, 261b, '!' , '$' , '*' , ')' , ';' , '^' /
+data (ibmtoa[l], l = 97, 104) /'-' , '/' , 262b, 263b, 264b, 265b, 266b, 267b/
+data (ibmtoa[l], l = 105,112) /270b, 271b, 0b, ',' , '%' , '_' , '>' , '?' /
+data (ibmtoa[l], l = 113, 120) /272b, 273b, 274b, 275b, 276b, 277b, 300b, 301b/
+data (ibmtoa[l], l = 121, 128) /302b, '`' , ':' , '#' , '@' , '\'' , '=' , '"'/
+data (ibmtoa[l], l = 129, 136) /303b, 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' /
+data (ibmtoa[l], l = 137, 144) /'h' , 'i' , 304b, 305b, 306b, 307b, 310b, 311b/
+data (ibmtoa[l], l = 145, 152) /312b, 'j' , 'k' , 'l' , 'm' , 'n' , 'o' , 'p' /
+data (ibmtoa[l], l = 153, 160) /'q' , 'r' , 313b, 314b, 315b, 316b, 317b, 320b/
+data (ibmtoa[l], l = 161, 168) /321b, '~' , 's' , 't' , 'u' , 'v' , 'w' , 'x' /
+data (ibmtoa[l], l = 169, 176) /'y' , 'z' , 322b, 323b, 324b, 325b, 326b, 327b/
+data (ibmtoa[l], l = 177, 184) /330b, 331b, 332b, 333b, 334b, 335b, 336b, 337b/
+data (ibmtoa[l], l = 185, 192) /340b, 341b, 342b, 343b, 344b, 345b, 346b, 347b/
+data (ibmtoa[l], l = 193, 200) /'{' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' /
+data (ibmtoa[l], l = 201, 208) /'H' , 'I' , 350b, 351b, 352b, 353b, 354b, 355b/
+data (ibmtoa[l], l = 209, 216) /'}' , 'J' , 'K' , 'L' , 'M' , 'N' , 'O' , 'P' /
+data (ibmtoa[l], l = 217, 224) /'Q' , 'R' , 356b, 357b, 360b, 361b, 362b, 363b/
+data (ibmtoa[l], l = 225, 232) /'\\', 237b, 'S' , 'T' , 'U' , 'V' , 'W' , 'X' /
+data (ibmtoa[l], l = 233, 240) /'Y' , 'Z' , 364b, 365b, 366b, 367b, 370b, 371b/
+data (ibmtoa[l], l = 241, 248) /'0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' /
+data (ibmtoa[l], l = 249, 256) /'8' , '9' , 372b, 373b, 374b, 375b, 376b, 377b /
+
+begin
+ call alutsc (inbuffer, outbuffer, nchars, ibmtoa)
+end
+
+
+# ASCII_TO_IBM -- Vector procedure to convert ASCII characters to IBM
+# characters.
+
+procedure ascii_to_ibm (inbuffer, outbuffer, nchars)
+
+char inbuffer[ARB]
+short outbuffer[ARB], atoibm[MAX_CHARS]
+int l, nchars
+
+data (atoibm[l], l = 1, 8) /0b, 1b, 2b, 3b, '7' , '-' , '.' , '/' /
+data (atoibm[l], l = 9, 16) /26b, 5b, '%' , 13b, 14b, 15b, 16b, 17b /
+data (atoibm[l], l = 17, 24) /20b, 21b, 22b, 23b, '<' , '=' , '2' , '&' /
+data (atoibm[l], l = 25, 32) /30b, 31b, '?' , '\'', 34b, 35b, 36b, 37b /
+data (atoibm[l], l = 33, 40) /'@' , 'Z' , 177b, '{' , '[' , 'l' , 'P' , '}' /
+data (atoibm[l], l = 41, 48) /'M' , ']' , '\\', 'N' , 'k' , '`' , 'K' , 'a' /
+data (atoibm[l], l = 49, 56) /360b, 361b, 362b, 363b, 364b, 365b, 366b, 367b/
+data (atoibm[l], l = 57, 64) /370b, 371b, 'z' , '^' , 'L' , '~' , 'n' , 'o' /
+data (atoibm[l], l = 65, 72) /'|' , 301b, 302b, 303b, 304b, 305b, 306b, 307b/
+data (atoibm[l], l = 73, 80) /310b, 311b, 321b, 322b, 323b, 324b, 325b, 326b/
+data (atoibm[l], l = 81, 88) /327b, 330b, 331b, 342b, 343b, 344b, 345b, 346b/
+data (atoibm[l], l = 89, 96) /347b, 350b, 351b, 255b, 340b, 275b, '_' , 'm' /
+data (atoibm[l], l = 97, 104) /'y' , 201b, 202b, 203b, 204b, 205b, 206b, 207b/
+data (atoibm[l], l = 105, 112) /210b, 211b, 221b, 222b, 223b, 224b, 225b, 226b/
+data (atoibm[l], l = 113, 120) /227b, 230b, 231b, 242b, 243b, 244b, 245b, 246b/
+data (atoibm[l], l = 121, 128) /247b, 250b, 251b, 300b, 'O' , 320b, 241b, 7b/
+data (atoibm[l], l = 129, 136) /' ' , '!' , '"' , '#' , '$' , 25b, 6b, 27b/
+data (atoibm[l], l = 137, 144) /'(' , ')' , '*' , '+' , ',' , 11b, 12b, 33b/
+data (atoibm[l], l = 145, 152) /'0' , '1' , 32b, '3' , '4' , '5' , '6' , 10b/
+data (atoibm[l], l = 153, 160) /'8' , '9' , ':' , ';' , 4b, 24b, '>' , 341b/
+data (atoibm[l], l = 161, 168) /'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' , 'H' /
+data (atoibm[l], l = 169, 176) /'I' , 'Q' , 'R' , 'S' , 'T' , 'U' , 'V' , 'W' /
+data (atoibm[l], l = 177, 184) /'X' , 'Y' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' /
+data (atoibm[l], l = 185, 192) /'h' , 'i' , 'p' , 'q' , 'r' , 's' , 't' , 'u' /
+data (atoibm[l], l = 193, 200) /'v' , 'w' , 'x' , 200b, 212b, 213b, 214b, 215b/
+data (atoibm[l], l = 201, 208) /216b, 217b, 220b, 232b, 233b, 234b, 235b, 236b/
+data (atoibm[l], l = 209, 216) /237b, 240b, 252b, 253b, 254b, 255b, 256b, 257b/
+data (atoibm[l], l = 217, 224) /260b, 261b, 262b, 263b, 264b, 265b, 266b, 267b/
+data (atoibm[l], l = 225, 232) /270b, 271b, 272b, 273b, 274b, 275b, 276b, 277b/
+data (atoibm[l], l = 233, 240) /312b, 313b, 314b, 315b, 316b, 317b, 332b, 333b/
+data (atoibm[l], l = 241, 248) /334b, 335b, 336b, 337b, 352b, 353b, 354b, 355b/
+data (atoibm[l], l = 249, 256) /356b, 357b, 372b, 373b, 374b, 375b, 376b, 377b/
+
+begin
+ call alutcs (inbuffer, outbuffer, nchars, atoibm)
+end
+
+
+# ALUTSC -- Vector operator to map one set of characters to another using a
+# lookup table.
+
+procedure alutsc (a, b, nchars, lut)
+
+char b[nchars]
+int nchars, i
+short a[nchars], lut[ARB]
+
+begin
+ do i = 1, nchars, 1
+ b[i] = lut[a[i] + 1]
+end
+
+
+# ALUTCS -- Vector operator to map one set of characters to another using
+# a lookup table.
+
+procedure alutcs (a, b, nchars, lut)
+
+char a[nchars]
+int nchars, i
+short b[nchars], lut[ARB]
+
+begin
+ do i = nchars, 1, -1
+ b[i] = lut[a[i] + 1]
+end
diff --git a/pkg/dataio/cardimage/mkpkg b/pkg/dataio/cardimage/mkpkg
new file mode 100644
index 00000000..63e23fc4
--- /dev/null
+++ b/pkg/dataio/cardimage/mkpkg
@@ -0,0 +1,13 @@
+# Cardimage library
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ t_rcardimage.x rcardimage.com <error.h> <ctype.h> <mach.h> <fset.h>
+ t_wcardimage.x wcardimage.com <fset.h> <error.h> <mach.h>
+ conversion.x
+ tabs.x
+ ;
diff --git a/pkg/dataio/cardimage/rcardimage.com b/pkg/dataio/cardimage/rcardimage.com
new file mode 100644
index 00000000..064f1af3
--- /dev/null
+++ b/pkg/dataio/cardimage/rcardimage.com
@@ -0,0 +1,10 @@
+int card_length
+int max_line_length
+int trim
+int entab
+int ebcdic
+int ibm
+char contn_string[SZ_LINE]
+
+common /rcardcom/ card_length, max_line_length, trim, entab, ebcdic, ibm,
+ contn_string
diff --git a/pkg/dataio/cardimage/structure.hlp b/pkg/dataio/cardimage/structure.hlp
new file mode 100644
index 00000000..4a8b5622
--- /dev/null
+++ b/pkg/dataio/cardimage/structure.hlp
@@ -0,0 +1,139 @@
+.help cardimage Jan85 dataio
+.sh
+RCARDIMAGE Structure Chart
+
+.nf
+t_rcardimage()
+# Returns when file list is satisfied or EOT is encountered.
+
+ cardfile_to_textfile (in_fname, out_fname, nlines, ncards)
+
+ fetchcard (fd, outline, ncards)
+ # Returns number of chars read or EOF
+
+ card_to_text (fd, instring)
+ # Returns number of chars or EOF
+
+ conversion routines
+.fi
+
+.sh
+WCARDIMAGE Structure Chart
+
+.nf
+t_wcardimage()
+# Returns when file list is satisfied.
+
+ textfile_to_cardfile (in_file, out_fname, ncards, nlines)
+
+ fetchline (fd, linebuf, nlines)
+ # Returns EOF or number of chars read
+
+ text_to_card (line, nchars, card)
+
+ conversion routines
+.fi
+.sh
+RCARDIMAGE Structure Summary
+
+.ls t_rcardimage
+The main procedure reads the control parameters.
+The files to be read and converted are calculated from the specified source
+and file list. A loop trough the files determines the specific input
+and output filenames and calls CARDFILE_TO_TEXTFILE for each conversion.
+.ls cardfile_to_textfile
+The input and output files are opened. Successive card images are fetched and
+converted to text lines by FETCHCARD. If the ENTAB switch is enabled
+blanks are replaced by tabs and blanks.
+.ls fetchcard
+This procedure reads individual card images, optionally joining those
+images prefixed by an indentifying continuation string with the previous
+card image(s). If trim is enabled white space is removed. Newline and
+EOS are added.
+.ls card_to_text
+Converts a packed card image to a text image. Call the CONVERSION routines
+to convert from EBCDIC to ASCII if the ebcdic switch is set.
+.le
+.le
+.le
+.le
+.sh
+WCARDIMAGE Structure Summary
+
+.ls t_wcardimage
+The main procedure read the control parameters.
+The files to be read and converted are calculated from the specified
+source and file list. A loop through the files determines the specific
+input source names and output filenames and calls TEXTFILE_TO_CARDFILE
+for each conversion.
+.ls textfile_to_cardfile
+The input and output source files are opened. Successive text lines are
+read and converted to one or more lines card_length + 1 long by
+calls to FETCHLINE.
+.ls fetchline
+FETCHLINE fetches lines of text and splits them into pieces <=
+maxch characters long optionally prefixing the remainders with
+an identifying continuation string. If the detab switch is set
+tabs in the lines are replaced with blanks.
+.ls text_to_card
+Converts a text string into a packed card image removing the newline
+character if necessary and padding with blanks if required.
+Call the conversion routines to convert from ASCII to EBCDIC if the
+ebcdic switch is set.
+.le
+.le
+.le
+.le
+.sh
+MTEXAMINE Structure Chart
+
+.nf
+t_mtexamine ()
+# Returns when file list is satisfied
+
+ mtexamine (tape_file, dump_range, byte_chunk, field_len,
+ vals_per_lines, output_format)
+ # Returns number of records read
+
+ bytupkl (a, b, nbytes, byte_chunk, byteswap)
+
+ dump (ptr, byte_chunk, nelems, field_len, vals_per_line,
+ output_format, max_plusint, twice_max_plusint)
+
+ sign_convert (a, nelems, max_plusint, twice_max_plusint)
+.fi
+.sh
+MTEXAMINE Structure Summary
+.ls t_mtexamine
+T_MTEXAMINE fetches the program parameters and calculates the
+input file list. If dump_records is yes, T_MTEXAMINE
+calculates the record list to be dumped, calculates the field length
+and number of values which can be printed on a line and checks to see that the
+data_type and output_format parameters are permitted types. For each
+file in the input list T_MTEXAMINE calls MTEXAMINE.
+.ls mtexamine
+If dump_records is no, MTEXAMINE prints the record structure of the specified
+files on the standard output. Otherwise MTEXAMINE loops through the tape
+records until it reaches a record number in the record list
+and calls dump to output the record to
+the standard output.
+.ls bytupkl
+BYTUPKL unpacks unsigned bytes into and integer array, optionally swaps
+the bytes, and assembles byte_chunk bytes into a long integer.
+.le
+.ls dump
+DUMP prints the record on the standard output using the specified
+output format and data type. If byte_chunk is 1 the output is unsigned.
+If byte_chunk is equal to the size in bytes of a long integer, then
+the data will be printed as signed. If byte_chunk is greater than one
+and less then the length of a long the data will be signed if the
+output format is decimal and unsigned otherwise. DUMP calls twos_comp
+to do the sign conversion.
+.ls sign_convert
+SIGN_CONVERT does a twos complement sign conversion if the output format is
+decimal and byte_chunk is greater than one and less than the size of a
+long integer.
+.le
+.le
+.le
+.le
diff --git a/pkg/dataio/cardimage/t_rcardimage.x b/pkg/dataio/cardimage/t_rcardimage.x
new file mode 100644
index 00000000..a2dad404
--- /dev/null
+++ b/pkg/dataio/cardimage/t_rcardimage.x
@@ -0,0 +1,271 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <ctype.h>
+include <mach.h>
+include <fset.h>
+
+define MAX_RANGES 100
+define TABSIZE 8
+
+# T_RCARDIMAGE -- Procedure to read cardimages tapes. Documentation in
+# rcardimage.hlp.
+
+procedure t_rcardimage()
+
+char infile[SZ_FNAME] # the input file name list
+char outfile[SZ_FNAME] # the output file name list
+char file_list[SZ_LINE] # the file number list
+int offset # the file number offset
+bool join # join long lines ?
+bool verbose # verbose output ?
+
+char in_fname[SZ_FNAME], out_fname[SZ_FNAME]
+int nlines, file_number, ncards, range[MAX_RANGES*2+1], nfiles
+int lenlist, junk
+pointer list
+
+bool clgetb()
+int btoi(), clgeti(), mtfile(), mtneedfileno(), strlen(), decode_ranges()
+int get_next_number(), fntlenb(), fntgfnb(), fstati()
+pointer fntopnb()
+include "rcardimage.com"
+
+begin
+ if (fstati (STDOUT, F_REDIR) == NO)
+ call fseti (STDOUT, F_FLUSHNL, YES)
+
+ # Get parameters.
+ call clgstr ("cardfile", infile, SZ_FNAME)
+ call clgstr ("textfile", outfile, SZ_FNAME)
+
+ # Make up a file list.
+ if (mtfile (infile) == YES) {
+ list = NULL
+ if (mtneedfileno (infile) == YES)
+ call clgstr ("file_list", file_list, SZ_LINE)
+ else
+ call strcpy ("1", file_list, SZ_LINE)
+ } else {
+ list = fntopnb (infile, YES)
+ lenlist = fntlenb (list)
+ call sprintf (file_list, SZ_LINE, "1-%d")
+ call pargi (lenlist)
+ }
+
+ # Decode the ranges.
+ if (decode_ranges (file_list, range, MAX_RANGES, nfiles) == ERR)
+ call error (1, "Illegal file number list")
+
+ # Set up the formatting parameters.
+ card_length = min (SZ_LINE, clgeti ("card_length"))
+ if (mod (card_length, SZB_CHAR) != 0)
+ call error (2, "A card must contain an even number of characters")
+ max_line_length = min (SZ_LINE, clgeti ("max_line_length"))
+ join = clgetb ("join")
+ if (join)
+ call clgstr ("contn_string", contn_string, SZ_LINE)
+ else
+ contn_string[1] = EOS
+ entab = btoi (clgetb ("entab"))
+ trim = btoi (clgetb ("trim"))
+ ebcdic = btoi (clgetb ("ebcdic"))
+ ibm = btoi (clgetb ("ibm"))
+ if (ibm == YES && ebcdic == YES)
+ call error (3, "Ibm and ebcdic cannot both be true.")
+
+ offset = clgeti ("offset")
+ verbose = clgetb ("verbose")
+
+ # Read successive cardimage files, convert and write into a numbered
+ # succession of output textfiles.
+
+ file_number = 0
+ while (get_next_number (range, file_number) != EOF) {
+
+ # Get the input file name.
+ if (list != NULL)
+ junk = fntgfnb (list, in_fname, SZ_FNAME)
+ else {
+ if (mtneedfileno (infile) == YES)
+ call mtfname (infile, file_number, in_fname, SZ_FNAME)
+ else
+ call strcpy (infile, in_fname, SZ_FNAME)
+
+ }
+
+ # Get the output file name.
+ call strcpy (outfile, out_fname, SZ_FNAME)
+ if (nfiles > 1) {
+ call sprintf (out_fname[strlen(out_fname)+1], SZ_FNAME, "%03d")
+ call pargi (file_number + offset)
+ }
+
+ # Copy the cardimage file to the output text file. If a read
+ # error occurs, try next file. If a zero length file is read,
+ # meaning that EOT was reached prematurely, merely exit, deleting
+ # the zero length output file.
+
+ iferr {
+ if (verbose) {
+ call printf ("File: %s -> %s: ")
+ call pargstr (in_fname)
+ call pargstr (out_fname)
+ }
+
+ call rc_cardfile_to_textfile (in_fname, out_fname, nlines,
+ ncards)
+
+ if (verbose) {
+ call printf ("%d card images -> %d text lines\n")
+ call pargi (ncards)
+ call pargi (nlines)
+ }
+
+ } then {
+ call flush (STDOUT)
+ call erract (EA_FATAL)
+ } else if (nlines == 0) { # EOT reached
+ if (verbose) {
+ call printf ("EOT encountered at file %s\n")
+ call pargi (file_number + offset)
+ }
+ call delete (out_fname)
+ break
+ }
+ }
+
+ if (list != NULL)
+ call fntclsb (list)
+end
+
+
+# RC_CARDFILE_TO_TEXTFILE -- Copy a cardfile to a new textfile.
+# Outputs the number of cards read and lines written.
+
+procedure rc_cardfile_to_textfile (in_fname, out_fname, nlines, ncards)
+
+char in_fname[ARB] # the input file name
+char out_fname[ARB] # the output file name
+int nlines # the number of lines
+int ncards # the number of cards
+
+char lbuf[SZ_LINE], tempbuf[SZ_LINE]
+int in, out, nchars
+int mtopen(), open(), rc_fetchcard()
+errchk mtopen, open, rc_fetchcard, putline, strentab, close
+include "rcardimage.com"
+
+begin
+ in = mtopen (in_fname, READ_ONLY, 0)
+ out = open (out_fname, NEW_FILE, TEXT_FILE)
+
+ ncards = 0
+ iferr {
+ nchars = rc_fetchcard (in, lbuf, ncards)
+ for (nlines = 0; nchars != EOF; nlines = nlines + 1) {
+ if (entab == YES) {
+ call strentab (lbuf, tempbuf, max_line_length, TABSIZE)
+ call putline (out, tempbuf)
+ } else
+ call putline (out, lbuf)
+ nchars = rc_fetchcard (in, lbuf, ncards)
+ }
+ } then
+ call erract (EA_WARN)
+
+ call close (in)
+ call close (out)
+end
+
+
+# RC_FETCHCARD -- Procedure to read card images and join those images prefixed
+# by an identifying continuation string with the previous image(s).
+# Returns number of characters in line or EOF.
+
+int procedure rc_fetchcard (fd, outline, cp)
+
+int fd # the input file descriptor
+char outline[ARB] # the output line
+int cp # the card counter
+
+bool newfile
+char instring[SZ_LINE * SZ_SHORT]
+int ip, op, npacked_chars, strsize
+int rc_card_to_text(), strlen(), strncmp()
+errchk rc_card_to_text
+data newfile/true/
+include "rcardimage.com"
+
+begin
+ ip = 1
+ op = 1
+ strsize = strlen (contn_string)
+
+ # Get first line of file.
+ if (newfile) {
+ npacked_chars = rc_card_to_text (fd, instring)
+ newfile = false
+ }
+
+ while (npacked_chars != EOF) {
+ # Count cards and file output buffer.
+ while (instring[ip] != EOS && op < max_line_length) {
+ outline[op] = instring[ip]
+ ip = ip + 1
+ op = op + 1
+ }
+ cp = cp + 1
+
+ # Check for continuation string in next line, move pointer if yes.
+ npacked_chars = rc_card_to_text (fd, instring)
+
+ if ((strsize != 0) &&
+ (strncmp (instring, contn_string, strsize) == 0) &&
+ (npacked_chars != EOF)) {
+ ip = strsize + 1
+ } else {
+ # Output line, remove whitespace, add newline and delimit string
+ if (trim == YES)
+ while (op >= 2 && IS_WHITE (outline[op-1]))
+ op = op -1
+ outline[op] = '\n'
+ outline[op+1] = EOS
+ return (op)
+ }
+ }
+
+ # Initialize for new file.
+ newfile = true
+ return (EOF)
+end
+
+
+# RC_CARD_TO_TEXT -- Procedure to transform a packed card image to a text image.
+
+int procedure rc_card_to_text (fd, card)
+
+int fd # input file descriptor
+char card[ARB] # the packed/unpacked cardimage image
+
+int npacked_chars, nchars
+int read()
+errchk read, ebcdic_to_ascii, ibm_to_ascii
+include "rcardimage.com"
+
+begin
+ npacked_chars = read (fd, card, card_length/SZB_CHAR)
+ if (npacked_chars == EOF)
+ return (EOF)
+ nchars = npacked_chars * SZB_CHAR
+ if (ebcdic == YES) {
+ call achtbs (card, card, nchars)
+ call ebcdic_to_ascii (card, card, nchars)
+ } else if (ibm == YES) {
+ call achtbs (card, card, nchars)
+ call ibm_to_ascii (card, card, nchars)
+ } else
+ call chrupk (card, 1, card, 1, nchars)
+ card[nchars+1] = EOS
+ return (nchars)
+end
diff --git a/pkg/dataio/cardimage/t_wcardimage.x b/pkg/dataio/cardimage/t_wcardimage.x
new file mode 100644
index 00000000..0a85bb55
--- /dev/null
+++ b/pkg/dataio/cardimage/t_wcardimage.x
@@ -0,0 +1,256 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <fset.h>
+include <error.h>
+include <mach.h>
+
+define TABSIZE 8
+
+# Procedure to write cardimage files. See wcardimage.hlp for documentation.
+
+procedure t_wcardimage()
+
+char out_file[SZ_FNAME] # input file name list
+char in_file[SZ_FNAME] # output file name list
+bool verbose # verbose mode ?
+
+char out_fname[SZ_FNAME]
+int ncards, file_number, nlines, list, len_list
+
+bool clgetb()
+int fstati(), clpopni(), clplen(), mtfile(), mtneedfileno()
+int clgeti(), clgfil(), strlen(), btoi()
+include "wcardimage.com"
+
+begin
+ # Flush standard output on newline
+ if (fstati (STDOUT, F_REDIR) == NO)
+ call fseti (STDOUT, F_FLUSHNL, YES)
+
+ # Get the parameters.
+ list = clpopni ("textfile")
+ len_list = clplen (list)
+
+ # Get name of output file.
+ # If no tape file number is given tape output then the program
+ # asks whether the tape is blank or contains data.
+ # If it is blank the tape begins writing at file 1 otherwise at EOT.
+ # Note that at some point this code needs to be modified to
+ # accept an output file name template.
+
+ call clgstr ( "cardfile", out_file, SZ_FNAME)
+ if (mtfile (out_file) == YES) {
+ if (mtneedfileno (out_file) == YES) {
+ if (! clgetb("new_tape"))
+ call mtfname (out_file, EOT, out_fname, SZ_FNAME)
+ else
+ call mtfname (out_file, 1, out_fname, SZ_FNAME)
+ } else
+ call strcpy (out_file, out_fname, SZ_FNAME)
+ }
+
+ # Get card_length and determine whether it fits in an integral number
+ # of characters.
+
+ card_length = min (SZ_LINE, clgeti ("card_length"))
+ if (mod (card_length, SZB_CHAR) != 0)
+ call error (1, "A card must fit in an integral number of chars.")
+
+ # Get number of cards per physical block and convert to packed chars.
+ cards_per_blk = clgeti ("cards_per_blk")
+
+ # Get the formatting parameters.
+ call clgstr ("contn_string", contn_string, SZ_LINE)
+ if (strlen (contn_string) > card_length)
+ call error (2,
+ "Continuation string cannot be > card_length chars.")
+ detab = btoi (clgetb ("detab"))
+
+ # Get the character type parameters.
+ ebcdic = btoi (clgetb ("ebcdic"))
+ ibm = btoi (clgetb ("ibm"))
+ if (ibm == YES && ebcdic == YES)
+ call error (3, "Ibm and ebcdic cannot both be true.")
+
+ verbose = clgetb ("verbose")
+
+ file_number = 1
+ while (clgfil (list, in_file, SZ_FNAME) != EOF) {
+ if (mtfile (out_file) == NO) {
+ if (len_list > 1) {
+ call sprintf (out_fname[1], SZ_FNAME, "%s%03d")
+ call pargstr (out_file)
+ call pargi (file_number)
+ } else
+ call strcpy (out_file, out_fname, SZ_FNAME)
+ } else {
+ if (file_number == 2)
+ call mtfname (out_fname, EOT, out_fname, SZ_FNAME)
+ }
+
+ # Copy text file to cardimage file.
+
+ iferr {
+ if (verbose) {
+ call printf ("File: %s -> %s: ")
+ call pargstr (in_file)
+ call pargstr (out_fname)
+ }
+
+ call wc_textfile_to_cardfile (in_file, out_fname, ncards,
+ nlines)
+
+ if (verbose) {
+ call printf ("%d lines read -> %d cards written\n")
+ call pargi (nlines)
+ call pargi (ncards)
+ }
+ } then {
+ call flush (STDOUT)
+ call erract (EA_FATAL)
+ } else if (ncards == 0) {
+ if (verbose)
+ call printf ("\tInput file is binary or empty\n")
+ }
+
+ file_number = file_number + 1
+ }
+end
+
+
+# WC_TEXTFILE_TO_CARDFILE -- Reads a textfile from disk and outputs a card
+# image file to tape or disk.
+
+procedure wc_textfile_to_cardfile (in_file, out_fname, ncards, nlines)
+
+char in_file[ARB] # input file name
+char out_fname[ARB] # output file name
+int ncards # number of card images
+int nlines # number of text lines
+
+char linebuf[SZ_LINE]
+int in, out, nchars, chars_per_blk
+int mtopen(), open(), access(), wc_fetchline(), mtfile()
+errchk mtopen, open, access, wc_fetchline, write, close, wc_text_to_card
+include "wcardimage.com"
+
+begin
+ nlines = 0
+ ncards = 0
+
+ if (access (in_file, READ_ONLY, TEXT_FILE) != YES)
+ return
+
+ # Open the file.
+ in = open (in_file, READ_ONLY, TEXT_FILE)
+ if (mtfile (out_fname) == YES) {
+ chars_per_blk = cards_per_blk * card_length / SZB_CHAR
+ out = mtopen (out_fname, WRITE_ONLY, chars_per_blk)
+ } else
+ out = open (out_fname, NEW_FILE, BINARY_FILE)
+
+ # Write file.
+ nchars = wc_fetchline (in, linebuf, nlines, card_length+1)
+ while (nchars != EOF) {
+ call wc_text_to_card (linebuf, nchars, linebuf)
+ call write (out, linebuf, card_length/SZB_CHAR)
+ ncards = ncards + 1
+ nchars = wc_fetchline (in, linebuf, nlines, card_length+1)
+ }
+
+ call close (in)
+ call close (out)
+end
+
+
+# WC_TEXT_TO_CARD -- Convert text string into a packed cardimage string
+# removing the newline character if necessary, padding with blanks
+# if required and optionally translating from ascii to ebcdic or ibm
+# ebcdic.
+
+procedure wc_text_to_card (line, nchars, card)
+
+char line[ARB] # input text line
+int nchars # number of chars in line
+char card[ARB] # output packed card image
+
+int init, ip
+errchk ascii_to_ebcdic, ascii_to_ibm, achtsb, chrpak
+include "wcardimage.com"
+
+begin
+ # Pad with blanks.
+ init = nchars
+ if (line[init] != '\n')
+ init = init + 1
+ for (ip=init; ip <= card_length; ip=ip+1)
+ line[ip] = ' '
+
+ # Pack the line.
+ if (ebcdic == YES) {
+ call ascii_to_ebcdic (line, card, card_length)
+ call achtsb (card, card, card_length)
+ } else if (ibm == YES) {
+ call ascii_to_ibm (line, card, card_length)
+ call achtsb (card, card, card_length)
+ } else
+ call chrpak (line, 1, card, 1, card_length)
+end
+
+
+# WC_FETCHLINE -- Procedure to fetch a line of text and split it into pieces
+# <= maxch characters long, optionally prefixing the remainders of lines
+# with a character string.
+
+int procedure wc_fetchline (fd, linebuf, lp, maxch)
+
+int fd # input file descriptor
+char linebuf[ARB] # output chunk of text
+int lp # number of lines read
+int maxch # maximum size of chunk of text
+
+char line[SZ_LINE], inline[SZ_LINE]
+int nchars, ip, op, offset, strsize
+int getline(), gstrcpy(), strlen(), strncmp()
+errchk getline(), strdetab()
+include "wcardimage.com"
+data ip /1/
+
+begin
+ # Get new line and detab if requested.
+ if (ip == 1) {
+ if (detab == YES) {
+ nchars = getline (fd, inline)
+ call strdetab (inline, line, SZ_LINE, TABSIZE)
+ } else
+ nchars = getline (fd, line)
+ if (nchars == EOF)
+ return (EOF)
+
+ lp = lp + 1
+ offset = 0
+ strsize = strlen (contn_string)
+ if (strsize != 0 && strncmp (line, contn_string, strsize) == 0)
+ call eprintf ("Warning: Line matches continuation string\n")
+
+ } else {
+ # Otherwise determine length of continuation string.
+ offset = gstrcpy (contn_string, linebuf, SZ_LINE)
+ }
+
+ # Copy maxch characters to the output buffer.
+ op = offset + 1
+ while (line[ip] != EOS && op < maxch && line[ip] != '\n') {
+ linebuf[op] = line[ip]
+ ip = ip + 1
+ op = op + 1
+ }
+
+ # Add newline and EOS reset pointer.
+ linebuf[op] = '\n'
+ linebuf[op+1] = EOS
+ if (line[ip] == EOS || line[ip] == '\n')
+ ip = 1
+
+ return (op)
+end
diff --git a/pkg/dataio/cardimage/tabs.x b/pkg/dataio/cardimage/tabs.x
new file mode 100644
index 00000000..ccb722a2
--- /dev/null
+++ b/pkg/dataio/cardimage/tabs.x
@@ -0,0 +1,67 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# STRDETAB -- Procedure to remove tabs from a line of text and replace with
+# blanks.
+
+procedure strdetab (line, outline, maxch, tabsize)
+
+int ip, op, maxch, tabsize
+char line[ARB], outline [ARB]
+
+begin
+ op=1
+ ip=1
+
+ while (line[ip] != EOS && op <= maxch) {
+ if (line[ip] == '\t') {
+ repeat {
+ outline[op] = ' '
+ op = op + 1
+ } until ((mod (op, tabsize) == 1) || (op > maxch))
+ ip = ip + 1
+ } else {
+ outline[op] = line[ip]
+ op = op + 1
+ ip = ip + 1
+ }
+ }
+
+ outline[op] = EOS
+end
+
+
+# STRENTAB -- Procedure to replace blanks with tabs and blanks.
+
+procedure strentab (line, outline, maxch, tabsize)
+
+int maxch, tabsize
+char line[ARB], outline[ARB]
+int ip, op, ltab
+
+begin
+ op = 1
+ ip = 1
+
+ repeat {
+ ltab = ip
+ while (line[ltab] == ' ' && op <= maxch) {
+ ltab = ltab + 1
+ if (mod(ltab, tabsize) == 1) {
+ outline[op] = '\t'
+ ip = ltab
+ op = op + 1
+ }
+ }
+ for (; ip < ltab && op <= maxch; ip = ip + 1) {
+ outline[op] = ' '
+ op = op + 1
+ }
+ if (line[ip] == EOS || op >= maxch+1)
+ break
+ outline[op] = line[ip]
+ op = op + 1
+ ip = ip + 1
+ } until (line[ip] == EOS || op >= maxch+1)
+
+ outline[op] = EOS
+end
diff --git a/pkg/dataio/cardimage/wcardimage.com b/pkg/dataio/cardimage/wcardimage.com
new file mode 100644
index 00000000..4d80adb1
--- /dev/null
+++ b/pkg/dataio/cardimage/wcardimage.com
@@ -0,0 +1,8 @@
+int card_length
+int cards_per_blk
+int detab
+int ebcdic
+int ibm
+char contn_string[SZ_LINE]
+
+common /wcardcom/ card_length, cards_per_blk, detab, ebcdic, ibm, contn_string
diff --git a/pkg/dataio/dataio.cl b/pkg/dataio/dataio.cl
new file mode 100644
index 00000000..2120892e
--- /dev/null
+++ b/pkg/dataio/dataio.cl
@@ -0,0 +1,19 @@
+#{ The DATAIO data input/output conversion package.
+
+package dataio
+
+task rcardimage,
+ wcardimage,
+ mtexamine,
+ txtbin,
+ bintxt,
+ rfits,
+ wfits,
+ reblock,
+ rtextimage,
+ t2d,
+ wtextimage,
+ import,
+ export = dataio$x_dataio.e
+
+clbye()
diff --git a/pkg/dataio/dataio.hd b/pkg/dataio/dataio.hd
new file mode 100644
index 00000000..93949ffd
--- /dev/null
+++ b/pkg/dataio/dataio.hd
@@ -0,0 +1,27 @@
+# Help directory for the DATAIO package.
+
+$doc = "pkg$dataio/doc/"
+$fits = "pkg$dataio/fits/"
+$reblock = "pkg$dataio/reblock/"
+$imtext = "pkg$dataio/imtext/"
+$mtexamine = "pkg$dataio/mtexamine/"
+$cardimage = "pkg$dataio/cardimage/"
+$bintext = "pkg$dataio/bintext/"
+$t2d = "pkg$dataio/t2d/"
+$import = "pkg$dataio/import/"
+$export = "pkg$dataio/export/"
+
+bintxt hlp=doc$bintxt.hlp, src=bintext$t_bintxt.x
+mtexamine hlp=doc$mtexamine.hlp, src=mtexamine$t_mtexamine.x
+rcardimage hlp=doc$rcardimage.hlp, src=cardimage$t_rcardimage.x
+reblock hlp=doc$reblock.hlp, src=reblock$t_reblock.x
+rfits hlp=doc$rfits.hlp, src=fits$t_rfits.x
+rtextimage hlp=doc$rtextimage.hlp, src=imtext$t_rtextimage.x
+txtbin hlp=doc$txtbin.hlp, src=bintext$t_txtbin.x
+wcardimage hlp=doc$wcardimage.hlp, src=cardimage$t_wcardimage.x
+wfits hlp=doc$wfits.hlp, src=fits$t_wfits.x
+wtextimage hlp=doc$wtextimage.hlp, src=imtext$t_wtextimage.x
+t2d hlp=doc$t2d.hlp, src=t2d$t_t2d.x
+import hlp=doc$import.hlp, src=import$t_import.x
+export hlp=doc$export.hlp, src=export$t_export.x
+revisions sys=Revisions
diff --git a/pkg/dataio/dataio.men b/pkg/dataio/dataio.men
new file mode 100644
index 00000000..3d83ce6b
--- /dev/null
+++ b/pkg/dataio/dataio.men
@@ -0,0 +1,13 @@
+ bintxt - Convert a binary file to an IRAF text file
+ export - Convert IRAF images to some other format
+ import - Convert some other format to an IRAF image
+ mtexamine - Examine the structure of a magnetic tape
+ rcardimage - Convert a cardimage file into a text file
+ reblock - Copy a binary file, optionally reblocking
+ rfits - Convert FITS image data into a list of IRAF images
+ rtextimage - Convert text files to IRAF images
+ t2d - Fast tape to disk copy
+ txtbin - Convert an IRAF text file to a binary file
+ wcardimage - Convert text files to cardimage files
+ wfits - Convert a list of IRAF images into FITS image data
+ wtextimage - Convert an IRAF image to a text file
diff --git a/pkg/dataio/dataio.par b/pkg/dataio/dataio.par
new file mode 100644
index 00000000..ff362077
--- /dev/null
+++ b/pkg/dataio/dataio.par
@@ -0,0 +1,4 @@
+# Dummy package parameter file.
+
+version,s,h,"26Apr86"
+mode,s,h,ql
diff --git a/pkg/dataio/doc/Mtio_notes b/pkg/dataio/doc/Mtio_notes
new file mode 100644
index 00000000..c5fb2fe5
--- /dev/null
+++ b/pkg/dataio/doc/Mtio_notes
@@ -0,0 +1,12 @@
+
+MTIO mods:
+
+ (1) Install error checking in MTOPEN ("errchk open").
+
+ (2) Attempt to position to a file beyond EOT for reading should not
+ cause an error, rather EOF should be returned at the first read,
+ indicating a zero length file (i.e., EOT).
+
+ (3) ZARDMT should zero-fill to an integral number of chars, provided
+ space is available at end of buffer (see ZARDBF, which I had to
+ modify to provide zero-fill).
diff --git a/pkg/dataio/doc/Rfits_notes b/pkg/dataio/doc/Rfits_notes
new file mode 100644
index 00000000..7df78ca5
--- /dev/null
+++ b/pkg/dataio/doc/Rfits_notes
@@ -0,0 +1,85 @@
+
+Notes on RFITS program.
+
+General Comments --
+ The code is well structured, modular, and the identifiers are well
+ chosen for the most part, with some exceptions. I liked the file list
+ technique, and have incorporated it into the card image reader I wrote
+ to test MTIO.
+
+ On the critical side, the code is not sufficiently well commented.
+ A few comments explaining the general approach are needed; the use
+ of the record buffer, the placement of unrecognized keywords in the
+ image header, and so on are important things that can only be derived
+ at present by a very detailed analysis of the code. Functionally the
+ program has some serious limitations as noted below.
+
+
+Detailed Comments --
+
+On functionality:
+
+ (1) Keywords BUNIT, BLANK, DATE, DATE_OBS, ORIGIN, CRVALn, CRPIXn,
+ etc., etc. should all be recognized. Many of these have direct
+ complements in the image header and it is merely a matter of
+ mapping the value directly. Without doing so we cannot save
+ and restore IRAF images in FITS tape form without serious loss
+ of information.
+
+ Our intention is eventually to map nonstandard FITS keywords
+ by name into the user fields. A similar table driven mapping
+ of the standard fields might therefore be desirable. This
+ would also make the reader more robust and easier to modify to
+ read nonstandard or future (extended) formats.
+
+ (2) Something should be done about indefinite pixels. It is easy to
+ check for FITS BLANK value and map into the appropriate INDEF.
+ This function should be encapsulated in a separate procedure,
+ because it will have to be modified when we add bad pixel lists
+ to IMIO.
+
+ (3) BITPIX=32 is not really implemented. Eight bits of precision lost
+ is too much. Also, SIMPLE='F' should not result in an irrecoverable
+ abort; a subsequent program may be able to recover the data if it
+ can at least be read into an imagefile. For similar reasons, it
+ would be best if it were possible to move pixels to disk without
+ conversion. Doing everything in real forces binary conversion of
+ the pixels, as well as causing the loss of precision for type long.
+
+
+On coding:
+
+ (1) Error checking is only partially implemented. As a rule, low level
+ procedures should "errchk" all subprocedures which perform i/o, so
+ that the higher level procedures can decide whether or not they want
+ to catch errors (makes code easier to modify, i.e., to add an error
+ handler in the future).
+
+ (2) The stack should be unchanged upon exit from a procedure. SALLOC is
+ used improperly in several places (noted on listing).
+
+ (3) The constants defining the FITS standard should be parameterized in
+ an include file with comments, or in an external lookup table. I do
+ not know what GROUPS, PCOUNT, GCOUNT are, and I had to think a bit to
+ figure out what the 11, 29, etc. were. The exact version of the
+ standard implemented by the program should be defined all in one
+ place, so that others can see what version of the standard is
+ implemented without having to read and understand the whole program,
+ and to make it easier to modify the program to read future and
+ nonstandard "FITS" files. Also numbers like "11", "29" etc. are
+ inherently hard to understand. Even "80" may have to be changed
+ to read a nonstandard or improperly written format.
+
+ (4) Defined expressions should be enclosed in parenthesis to guarantee
+ that they are evaluated properly. The definitions of SZB_BIT,
+ SZ_UBYTE, etc. do not work if enclosed in parenthesis. This is
+ very tricky; if I were to inherit the program, I would have "fixed"
+ those definitions at first sight by adding parens, just to be safe,
+ and then the code would no longer work. Use of integer division
+ in expressions where the operands of unknown size is bad.
+
+ (5) The "8" in the definition of SZB_BIT is machine dependent. I have
+ added an NBITS_BYTE definition to iraf.h. Do not let machine
+ dependence creep into code!!
+
+ (6) I have added WRDSWP and ACHTB_ to the system libraries.
diff --git a/pkg/dataio/doc/bintxt.hlp b/pkg/dataio/doc/bintxt.hlp
new file mode 100644
index 00000000..5d758ee5
--- /dev/null
+++ b/pkg/dataio/doc/bintxt.hlp
@@ -0,0 +1,28 @@
+.help bintxt Jun86 dataio
+.ih
+NAME
+bintxt -- Convert binary files containing only text to text files
+.ih
+USAGE
+bintxt binary_file text_file
+.ih
+PARAMETERS
+.ls binary_file
+Input file name or template, e.g. "file1" or "file*".
+.le
+.ls text_file
+The output file name. If multiple input files the filenumber will
+be concatenated onto the output file name.
+.le
+.ls verbose = yes
+Print messages of actions performed?
+.le
+.ih
+EXAMPLES
+1. Convert a binary file on disk to a text file on disk.
+
+ cl> bintxt binary_file text_file
+.ih
+SEE ALSO
+txtbin
+.endhelp
diff --git a/pkg/dataio/doc/export.hlp b/pkg/dataio/doc/export.hlp
new file mode 100644
index 00000000..4ef4a492
--- /dev/null
+++ b/pkg/dataio/doc/export.hlp
@@ -0,0 +1,1066 @@
+.help export Oct94 dataio
+.ih
+NAME
+export -- create a binary image file from one or more IRAF images
+
+.ih
+USAGE
+export images binfiles
+
+.ih
+PARAMETERS
+
+.ls images
+The list of input IRAF images to be converted. The list may contain
+either 2-D images or 3-D images.
+Any number of 2-D images may be combined to a single output file, only
+one 3-D image (or section) at a time may be converted. See the \fIBuiltin
+Formats\fR section for notes about the number of image expressions required
+for each builtin format and the handling of 3-D image data. Images greater
+than three dimensions should be converted using image sections.
+.le
+.ls binfiles
+The list of output binary files to create. If any of the builtin formats
+is selected for conversion the filename will have an extension added
+reflecting the format (if it is not already given).
+.le
+
+.ce
+OUTPUT PARAMETERS
+.ls format = "raw"
+The type of binary file to write. If the value is "raw" then the input
+images are converted directly to a raw binary raster using the task
+parameters. If the value is "list" the pixel values will be written
+to the standard output after evaluation of the \fIoutbands\fR parameter in
+the same format as would appear from the \fILISTPIX\fR task. Finally,
+the value may include any of the currently supported specific builtin formats:
+
+.nf
+ eps - Encapsulated PostScript
+ gif - Compuserve's GIF format
+ imh - IRAF OIF image
+ miff - ImageMagick MIFF format image
+ pgm - PBMPlus PGM format image
+ ppm - PBMPlus PPM format image
+ ras - Sun rasterfile format
+ rgb - SGI RGB format image
+ xwd - X11 Window dump file
+.fi
+
+If any of these builtin formats is selected one or more of the following
+parameters may be ignored. See the \fIBuiltin Formats\fR section for notes
+about the formats supported by this task.
+.le
+.ls outbands = ""
+Output image band expressions to write. This is a comma-delimited list of
+expressions or an @-file containing the expressions. Evaluated expressions
+do not all need to be the same length since the output image will be padded
+to the maximum size. See below for more information.
+.le
+.ls verbose = no
+Print verbose output to the screen during conversion?
+.le
+
+.ce
+RAW BINARY OUTPUT PARAMETERS
+.ls header = yes
+For raw binary file output only, prepend a header describing how the data
+are stored? If set to "no" then no header will be written. If set to "yes",
+a standard text header describing how the data were written will be
+prepended to the output file. Setting the \fIheader\fR parameter to the
+reserved string "long" will write the image headers from the IRAF images
+making up the output file in the standard header. The parameter may also
+be set to a filename that will be prepended to the output file. This
+parameter is ignored for builtin format output. See below for a description
+of the header layout.
+.le
+.ls outtype = ""
+Output pixel type if \fIformat\fR is set to "raw" or "list". This is a
+string giving the type and size of each pixel, the syntax for the outtype
+entry is
+.nf
+
+ <type>[<nbytes>]
+where
+ type = b # byte
+ u # unsigned (short) integer
+ i # signed integer
+ r # ieee floating point
+ n # native floating point
+
+ nbytes = 1, 2, 4, or 8
+
+.fi
+If no value for \fInbytes\fR is given the smallest size for the given type
+(i.e. 1 byte for 'b', 2 bytes for ints, 4 bytes for floating point) will
+be used. If no value is entered at all the type of the input image is used,
+for multiple images used to create a single binary file the type of the first
+image is used. This parameter is ignored for builtin format output options.
+.le
+.ls interleave = 0
+Pixel interleave type. If the \fIoutbands\fR parameter is composite
+(i.e. a comma-delimited list of expressions) the output file is pixel
+interleaved and the \fIinterleave\fR parameter is ignored. If the
+\fIoutbands\fR parameter is a single expression the file is line-interleaved
+when the \fIinterleave\fR value is a positive integer. If the \fIoutbands\fR
+is an empty string or a single expression the binary file is band interleaved
+if this parameter is zero. This parameter is ignored for builtin formats
+where the pixel storage is predefined.
+.le
+.ls bswap = "no"
+Type of byte-swapping to perform on output. The default is bswap=no which
+may be abbreviated "bswap-" (similarly a value of 'yes' can be abbreviated
+"bswap+"). If disabled no byte-swapping is performed, if set all integers
+are swapped on output relative to the current machine's byte ordering.
+Values of 'i2' or 'i4' will swap only two or four byte integers respectively,
+floating point values remain unswapped. This parameter may be used by some
+builtin formats that don't have a specified byte order.
+.le
+
+.ih
+DESCRIPTION
+ The \fIexport\fR task will convert one or more images in an
+input list to a binary raster file, a text listing of pixels values,
+or one of several specific file formats. For general binary
+rasters, various pixel types, data interleaving, and the byte order can be
+specified. An optional header may be added to the output file.
+Arbitrary arithmetic expressions, using both standard and custom
+functions, may be applied to the images in the
+input list before conversion allowing the user to scale intensity values,
+change image orientation, compute colormaps, or compute output pixel
+values.
+
+ The \fIformat\fR parameter controls the type of output generated:
+if set to \fIraw\fR a binary file described by the \fIouttype\fR,
+\fIinterleave\fR, and \fIbswap\fR parameters is written with pixel values
+determined from the expressions in the
+\fIoutbands\fR parameter. The value of \fIouttype\fR
+defines the output pixel size and type (long or short ints, native or IEEE
+reals, see parameter description for details). The
+\fIbswap\fR parameter can be used to set the byte order (relative to the
+current machine) of integer values, this
+parameter is ignored for floating point pixels or builtin
+formats with a specified byte order. The \fIoutbands\fR and \fIinterleave\fR
+parameters define the pixel storage in the binary file. For multiple
+\fIoutbands\fR
+expressions the data are assumed to be pixel interleaved (e.g. written
+as { {RGB}, {RGB} ...} triplets). For single expressions, a positive value
+of \fIinterleave\fR indicates that the data are written in a line-interleaved
+manner (e.g. a line of R, a line of G, ...). If \fIinterleave\fR is
+zero and \fIoutbands\fR is a single expression
+then no interleaving is done and the image bands are written sequentially.
+If \fIoutbands\fR is the null string, all pixels in a single input image
+will be written to a single output file.
+Error checking is done to make sure the combination of these
+parameters is correct. If the \fIheader\fR parameter is "yes" a text header
+describing how the data were written will be prepended to the file, setting
+the \fIheader\fR parameter to the reserved string "long"
+will cause the image header for each input image
+to be saved in the standard header. The \fIheader\fR parameter may also
+be the name of a user-defined file to prepend to the output instead of the
+standard header.
+
+ If the \fIformat\fR parameter is set to "list" the pixels values
+will be written to the screen as an ascii list of pixel coordinates
+followed by the pixel value. Pixel coordinates are determined using the
+same interleaving scheme as above, values are determined by evaluating
+each \fIoutbands\fR expression.
+
+ Lastly, the \fIformat\fR parameter may be any of the currently
+supported builtin formats. See the section on \fIBuiltin Formats\fR for
+more information and the restrictions or requirements of each format.
+
+.ih
+MORE ON OUTBANDS EXPRESSIONS
+ The simplest specification for \fIoutbands\fR is a null string,
+in which case the image is converted directly (i.e. band storage,
+pixels converted to output type). Arbitrary interpreted arithmetic
+expressions using standard and custom functions and operators are also
+supported. If the \fIimages\fR parameter is a list of 3-D images the
+operand names are the predefined tags b1, b2, ... bN for the bands in each
+image, the \fIbinfiles\fR parameter must contain an equal number of
+output files. To convert multiple 3-D images they must either be sliced
+to individual 2-D images (or specified as image sections) or stacked into
+a single image. If the \fIimages\fR parameter is a list of 2-D images
+(or sections) the operand names are the predefined tags i1, i2, ... iN for
+the each image in the input list, the b1, b2, etc names are also recognized.
+For more complex or
+lengthy expressions the \fIoutbands\fR parameter may alternatively be an
+@-file containing the expressions. Within this @-file whitespace and
+newline characters are ignored to allow expressions to be indented in a
+readable manner.
+
+ The image operands determine which input images in the list are
+converted to which output files. For 3-D input images one IRAF image is
+converted for each output file in the list, for 2-D images multiple images
+may be converted to a single output file. In the latter case the list
+pointers are updated automatically to keep track of the images. For example,
+to convert six images to two output files, the \fIoutbands\fR expression
+should contain three images operands. The first three images in the list
+will be used in evaluating the expressions for the first output file,
+the last three for the second file.
+
+ The image tags may be reordered in the expression but still refer to
+e.g. band-1, band-2 and so on. For example (where rgbim is a 512x512x3 image,
+and rim, gim, and bim are 512x512 images),
+
+.nf
+cl> export rgbim file outtype="u2" header- (1)
+cl> export rgbim file outtype="u2" header- outbands="b3,b2,b1" (2)
+cl> export rim,gim,bim file outty="u2" outbands="i3,i2,i1" (3)
+cl> export rim,gim,bim file outty="b" outbands="gray(i1,i2,i3)" (4)
+.fi
+
+Example (1) converts the input image pixels to a raw binary file of
+unsigned short integers with no header written as one image band following
+another. In example (2) the order of the bands is reversed and the binary
+file is stored as pixel interleaved BGR triplets of short ints.
+Example (3) is the same as (2) except that the input images in the list
+are reordered instead of bands within a single image. When using the image
+tags the input list is updated to account for this, so it is allowed to have
+more input images than output binary files.
+In example (4) the three images are converted to a single grayscale image
+before being written as byte data to the binary file.
+More complex and detailed examples are given below.
+
+Individual \fIoutbands\fR expressions are composed of operators and operands
+in general interpreted arithmetic expressions as follows:
+
+\fBOperands\fR
+.nf
+
+ iN # image list item
+ iN.param # image parameter
+ @"param" # parameter of 3-D image
+ bN # band within 3-D image
+
+ func() # function
+ constant # numeric constant
+.fi
+
+ The 'iN.param' and '@"param"' syntax allows an image header parameter
+to be accessed. For example 'i2.otime' refers to the 'otime' image
+header parameter in the second image of a list and '@"otime"' refers to the
+current image if the input list contains 3-D images. They may
+be used in an outbands expression such as
+.nf
+
+ (i1*(i1.otime/i2.otime)),i2,(i3*(i3.otime/i2.otime)) (1)
+ (b1/@"otime")),(b2/@"otime"),(b3/@"otime") (2)
+
+.fi
+to normalize the output bands by the exposure time value in the second image
+in the first example, or to normalize by the 'otime' keyword of a 3-D image
+in the second example.
+
+ In cases where a constant value is used as an outbands expression an
+alpha channel (an extra 8-bits of constant intensity) will be created
+consisting of that value. For example, writing a 32-bit RGB image with an
+alpha channel of 255 could be written using
+
+ cl> export rgbim file outtype="b1" outbands="b1,b2,b3,255"
+
+
+\fBOperators\fR
+
+The expression syntax implemented by \fIexport\fR provides the following
+set of operators:
+
+.nf
+
+ ( expr ) - grouping
+ + - * / - arithmetic
+ ** - exponentiation
+ // - concatenate
+ expr ? expr1 : expr2 - conditional expression
+
+ && - logical and
+ || - logical or
+ ! - logical not
+ < - less than
+ <= - less than or equal
+ > - greater than
+ >= - greater than or equal
+ == - equals
+ != - not equals
+ ?= - substring equals
+.fi
+
+The conditional expression has the value \fIexpr1\fR if \fIexpr\fR is true,
+and \fIexpr2\fR otherwise. Since the expression is evaluated at every pixel
+this permits pixel-dependent operations such as checking for special pixel
+values, or selection of elements from either of two vectors. For example,
+the command
+
+ (i1 <= 0) ? 0 : 1
+
+has the constant value zero if "i1" is less than or equal to zero,
+and one otherwise, effectively creating a pixel mask of positive pixels.
+Conditional expressions are general expressions and may be nested or used
+anywhere an expression is permitted.
+
+The concatenation operator applies to all types of data, not just
+strings. Concatenating two vectors results in a vector the
+combined length of the two input vectors. An example use of this would
+be to concatenate images side-by-side on output.
+
+
+\fBSpecial Functions\fR
+
+ In addition to the intrinsic functions already provided (see the help
+page for the \fIimexpr\fR task for a list of standard, mathematical and type
+conversion functions) there are a number of custom functions for this task:
+
+.ce
+\fBOutput Functions:\fR
+
+.nf
+ band (args) - force band interleaved storage
+ line (args) - force line interleaved storage
+ flipx (args) - flip image in X dimension
+ flipy (args) - flip image in Y dimension
+
+ block (val,width,height) - block fill area with a constant
+.fi
+
+ These functions define how the output data are written. For builtin
+formats whose normal orientation and storage format is known these functions
+are ignored (except where noted). These functions may not be used as arguments to other functions (except where noted) or as single operands
+within expressions (e.g. "255 + flipx(i1)"), however their arguments may
+be expressions or (perhaps output) functions themselves.
+
+.ls band (args)
+Force band storage in the output file regardless of the value of the
+\fIinterleave\fR parameter. This may be used to specify multiple
+expressions for each band while still forcing band storage (the default
+for multiple expressions is pixel-interleaved storage). This function
+may be used with some builtin formats to write multiple images to the output
+file as if they were a column of images in the original. This function
+is ignored by builtin formats that do not support this scheme (i.e RGB
+format) and may be used as an argument to the \fIsetcmap()\fR, \fIpsdpi()\fR,
+and \fIpsscale()\fR functions only.
+.le
+.ls line (args)
+Force line storage in the output file regardless of the value of the
+\fIinterleave\fR parameter. This may be used to specify multiple
+expressions for each band while still forcing line storage (the default
+for multiple expressions is pixel-interleaved storage). This function
+is ignored by builtin formats that do not support this scheme.
+.le
+.ls flipx (args)
+Flip the image left-to-right on output. This function may be used as an
+argument to the \fIband()\fR, \fIsetcmap()\fR, \fIpsdpi()\fR, or
+\fIpsscale()\fR functions only.
+.le
+.ls flipy (args)
+Flip the image top-to-bottom on output. Certain builtin formats (such as
+GIF, PGM, PPM, RAS and XWD) have their normal orientation already flipped wrt
+to IRAF and these will automatically be flipped on output. Using this
+function with those formats cancels the flip action, writing the image in the
+normal IRAF orientation and not the normal format orientation.
+This function may be used as an argument to the \fIband()\fR, \fIsetcmap()\fR,
+\fIpsdpi()\fR, or \fIpsscale()\fR functions only.
+.le
+.ls block (value, width, height)
+Fill an area with a constant value. This function can be used to fill a
+vertical area between images to provide padding of a constant value. It
+is similar to the "repl()" intrinsic function which replicates a data element
+a given number of times.
+.le
+
+
+.ce
+\fBScaling Functions:\fR
+.nf
+
+ zscale (arg [,z1, z2 [, nbins]]) - scale to a fixed number of bins
+ zscalem (arg1, arg2) - automatic scaling with filtering
+ gr[ea]y (arg1,arg2,arg3) - RGB to grayscale conversion
+ bscale (arg, zero, scale) - linearly transform intensity scale
+ gamma (arg, gamma [, scale]) - apply a gamma correction
+.fi
+
+ These functions may be used to scale the intensity values of the
+image before output in order to map image datatypes to a specified range.
+The 'args' value may be a list of image operands or expressions. These
+functions may be used as arguments to the output functions above
+or as operands within more complex expressions.
+
+.ls zscale (arg [,z1,z2 [,nbins]])
+Scale the pixels in a given range to a specified number of bins. This
+function will map the input pixels within the range z1 to z2 to one of
+'nbins' values. Pixels less than z1 are mapped to the lowest output
+intensity value, pixels greater than z2 are mapped to the highest value.
+If no \fIz1\fR and \fIz2\fR arguments are given appropriate values will
+be computed using the same algorithm and default parameters used by
+the \fIDISPLAY\fR task (see the help page for more information).
+If no \fInbins\fR value is given 256 bins are assumed.
+
+If the given value of z1 is greater than z2 the mappings will be inverted,
+i.e. larger pixel values will map to the lower bin numbers, smaller pixel
+values will map to larger bin numbers. For example, to map the dev$pix
+test image to 200 colors such that there are "black" stars on a "white"
+background one could use
+.nf
+
+ zscale (b1, @"i_maxpixval", @"i_minpixval", 200)
+.fi
+.le
+.ls zscalem (arg1, arg2)
+This is a variant of the zscale operand with automatic scale calculation;
+i.e. zscale (arg). The first argument is the same as for zscale to select
+the pixel values. The second argument is a boolean (true or false)
+expression selecting whether a value in the first argument is to be used in
+the calculation. This allows limiting the automatic scale calculation to
+pixels specified in a mask or to a certain range to exclude extreme or bad
+values that would otherwise perturb the result. Typical usages might be
+.nf
+
+ zscalem (i1, i2==0)
+ zscalem (i1, i1>0&&i1<10000)
+.fi
+where i1 are the image pixels and i2 would be pixels from the second
+input argument which defines a mask. Note that you can't just say i2
+for a mask but must use it in an expression resulting in a true or false
+value. Also note that the result is always in the range 0 to 255.
+.le
+.ls grey (arg1,arg2,arg3) or gray (arg1,arg2,arg3)
+Convert three image operands or expressions to a single grayscale image
+using the standard NTSC equation:
+.nf
+
+ Gray = 0.3 * arg1 + 0.59 * arg2 + 0.11 * arg3
+.fi
+.le
+.ls bscale (arg, zero, scale)
+Linearly transform the intensity scale of the image using the equation
+.nf
+
+ new[i] = (arg[i] - zero) / scale
+
+.fi
+Pixels are scaled in their input datatype prior to converting to the output
+datatype.
+.le
+.ls gamma (arg, gamma [, scale])
+Apply a gamma correction to the pixels. Pixel values are scaled according to
+the equation
+.nf
+
+ new = scale * [ (old/scale) ** (1.0/gamma) ]
+
+.fi
+If no scale argument is given a value of 255 will be assumed.
+.le
+
+
+ \fIAdditional functions\fR are supported for specific formats:
+
+.nf
+ Function Description Formats
+ -------- ----------- -------
+ cmap (r,g,b [,ncols]) create 8-bit colormap GIF,RAS,XWD,EPS
+ setcmap (args, [opts]) define a colormap GIF,RAS,XWD,EPS
+ psdpi (args, dpi) set dpi for output EPS
+ psscale (args, scale) set scale of output EPS
+.fi
+
+ These functions may take as arguments some of the output functions
+named above. For example, one can specify the dpi resolution of EPS output
+and band storage of images using something like
+.nf
+
+ psdpi(band(args), dpi)
+
+.fi
+
+.ls cmap (arg1,arg2,arg3 [, ncolors])
+Compute an 8-bit colormap from three image operands or expressions using a
+Median-Cut Algorithm and Floyd-Steinberg dithering. The computed colormap
+is written to the header of the output file. The resultant image
+is an 8-bit color index into the computed colormap. The \fIncolors\fR argument
+specifies the number of desired colors, a default value of 256 will be used
+if not provided. This function is only
+allowed for builtin formats supporting color lookup tables and may not be
+used within another expression or function.
+.le
+.ls setcmap (args, cmap [, brightness, contrast])
+Define the colormap to be used on output. This function is only supported
+for formats that support colormaps, the \fIargs\fR expressions are used to
+compute the color index values. The \fIcmap\fR argument may either be the
+filename of a normalized colormap table (such as is used by \fIXImtool\fR)
+or one of the builtin values:
+.nf
+ aips0 - and RGB false color mapping
+ blue - various shades of blue
+ color - standard B/W and RGB colormap
+ grayscale - standard grayscale
+ greyscale - (alias for above)
+ green - various shades of green
+ halley - standard halley mission colormap
+ heat - temperatures as colors
+ rainbow - rainbow colors
+ red - various shades of red
+ staircase - RGB staircase
+ standard - RGB ramps
+ overlay - grayscale with IMDKERN overlay colors
+.fi
+
+Colormap names must be quoted with either single or double quote characters.
+The optional \fIbrightness\fR and \fIcontrast\fR arguments have default
+values of 0.5 and 1.0 respectively corresponding to the default
+brightness/contrast scaling of the \fIXImtool\fR display server.
+If the cmap argument is an empty string the default Grayscale LUT will
+be used, IRAF logical paths may be used in the filename specification.
+.le
+.ls psdpi (args, dpi)
+Specify the dots-per-inch resolution of the output image. The default
+resolution is 300dpi, this may need to be reset for some printers or if
+the raster rendering produces "bands" in the output. This function may
+only be used as an argument to the \fIpsscale()\fR function.
+.le
+.ls psscale (args, scale)
+Specify the scale of the output image. The default value is 1.0 which
+means that image printed on a 300dpi device is roughly the same size
+as displayed on a typical 72dpi screen. Scale values less than one reduce
+the image size on the page, values greater than one increase the size. The
+scale value will automatically be adjusted if it creates an image that will
+not fit on a 8.5 inch by 11 inch page. A scale value of 0.25 prints one
+image pixel per 300dpi printer pixel. This function may
+only be used as an argument to the \fIpsdpi()\fR function.
+.le
+
+.ih
+EXPORT HEADER FORMAT
+ The header prepended to the binary data is ascii text consisting of
+keyword-value pairs, one per line, terminated with a newline after the
+value, beginning with the magic string
+"format = EXPORT". Using an ascii header allows the file format to be
+easily determined by the user with a file pager or any program reading
+the file.
+
+Defined keywords are:
+
+.nf
+ date - date file was written (dd/mm/yy)
+ hdrsize - size of header (bytes)
+ ncols - no. of image columns
+ nrows - no. of image rows
+ nbands - no. of image bands
+ datatype - pixel type (as <type><nbytes>)
+ outbands - outband expression list
+ interleave - interleave value (same as above)
+ bswap - are ints swapped relative to MII format?
+ image1 - image names used in creating file
+ :
+ imageN
+ header1 '{' <header> '}' - image headers of above
+ :
+ headerN '{' <header> '}'
+ end - terminate header
+.fi
+
+If the \fIheader\fR parameter is set to "long" the image headers for
+each image used in creating the file is included in the output header,
+otherwise only the image names are included.
+
+A sample (verbose) header might look like:
+
+.nf
+ format = EXPORT
+ date = '19/06/94'
+ hdrsize = 2084
+ nrows = 512
+ ncols = 512
+ nbands = 1
+ datatype = 'i2'
+ outbands = ''
+ interleave = 0
+ bswap = no
+ image1 = "dev$pix"
+ header1 = {
+ IRAF-BPX= 16 / DATA BITS/PIXEL
+ IRAFTYPE= 'SHORT ' / PIXEL TYPE
+ CCDPICNO= 53 / ORIGINAL CCD PICTURE NUM
+ ITIME = 600 / INTEGRATION TIME (SECS)
+ : : : :
+ }
+ end
+.fi
+
+.ih
+BUILTIN FORMATS
+ While the task provides a way of writing general binary raster
+files there is still a need for converting to specific formats.
+Implementing most formats is trivial since they usually follow the
+data model and the only "builtin" knowledge of the format is the minimal
+header required. More complex formats such as GIF and EPS are implemented
+as special cases. Note that all of the builtin formats require 8-bit color
+index or 8-bits per color in RGB or RGBA files, users should be careful
+in how the datatype conversion from IRAF image types is handled. In most
+cases this can be handled with the \fIzscale()\fR or \fIzscalem\fR functions.
+
+ For each of the formats listed below the table shows the number
+of \fIoutbands\fR expressions required and the type of output file that
+can be written. Complete examples for the most common cases are shown in
+the \fIExamples\fR section below. The columns in the table are defined as
+.nf
+
+ #expr - number of required \fIoutbands\fR expressions
+ Type - RGB or 8-bit colormap (index) file
+ bitpix - number of bits-per-pixel
+ CLT? - does the file have a colormap?
+ Alpha? - does the file have an alpha channel?
+ Interleaving - type of pixel interleaving
+ Notes - see explanation below each table
+
+.fi
+A general description and specific restrictions or requirements are given for
+each format. An error is generated of the input parameters do not meet the
+requirements of the requested format. Unless otherwise noted the values of
+the \fIheader\fR, \fIbswap\fR and \fIinterleave\fR parameters will be ignored.
+The value of \fIouttype\fR will be set internally and is also ignored.
+
+ If the input image is 3-D and no \fIoutbands\fR expressions are
+given, then where supported each band will be written to the output file as
+a complete image or RGB color component. For example, a 512x512x3 image
+will be written as a 512x1536 image with each band comprising one third
+the height of the output image. If the output format requires 24-bit pixels
+then each band of the image will be written as a color component.
+
+ The currently supported builtin formats include:
+
+.ls EPS - Encapsulated PostScript
+.nf
+
+ #expr Type bitpix CLT? Alpha? Interleaving Notes
+ ----- ----- ------ ---- ------ ------------ -----
+ 1 index 8 no no none
+
+.fi
+ The output 8-bit Encapsulated PostScript image
+centered on the page at a default scale of 1.0 at 300dpi (i.e. the image will
+appear on a 300dpi printer about the same size as displayed on a 72dpi
+screen). The output scale may be adjusted using
+the \fIpsscale()\fR function, e.g. to set the output for one image pixel
+per 300 dpi printer pixel use "psscale(b1,0.25)" (one quarter the normal size
+on the page). The output dpi resolution may be set explicitly with
+the \fIpsdpi()\fR function, this is sometimes necessary if "bands" appear
+in the final output image. Color EPS files may be written as either RGB
+postscript or with a colormap applied to the data (using either the
+\fIcmap()\fR or \fIsetcmap()\fR functions).
+.le
+.ls GIF - Compuserve's GIF format
+.nf
+
+ #expr Type bitpix CLT? Alpha? Interleaving Notes
+ ----- ----- ------ ---- ------ ------------ -----
+ 1 index 8 yes no none 1
+ 3 index 8 yes no none 2
+
+ Notes:
+ 1) Colormap generation enabled using \fIsetcmap()\fR or else
+ default grayscale colormap will be used
+ 2) use of \fIcmap()\fR required to generate colormap
+
+.fi
+ The output file is a GIF '87 image. A linear colormap of 256 entries
+will automatically be generated if only one image or expression is given for
+conversion and no colormap is specified.
+If three images or expressions are specified a 24-to-8 bit
+conversion can be done using a Median Cut Algorithm and Floyd-Steinberg
+dithering with the required \fIcmap()\fR function. Since the colormap
+sizes are limited to 256 entries the maximum pixel value is assumed to
+be 255, i.e. the output pixel size will be forced to 8-bits or less.
+.le
+.ls IMH - IRAF image file
+ The output file is an IRAF OIF format image of the specified datatype.
+Writing the image out as another IRAF image may be used to scale or composite
+several images into a new image that can be annotated with the \fITVMARK\fR
+task before writing out the final format.
+.le
+.ls MIFF - ImageMagick MIFF format image
+.nf
+
+ #expr Type bitpix CLT? Alpha? Interleaving Notes
+ ----- ----- ------ ---- ------ ------------ -----
+ 1 index 8 no no none
+ 1 index 8 yes no none 1,2
+ 3 rgb 24 no no pixel
+
+ Notes:
+ 1) Colormap generation enabled using \fIsetcmap()\fR
+ 2) Colormap generation enabled using \fIcmap()\fR
+
+.fi
+ The output file is a Machine Independent File Format image, with or
+without a colormap or as a 24-bit RGB image. Although MIFF permits 64K
+colors in a colormap the task only supports 256 colors, no compression is
+used in the image. The maximum pixel value per color is assumed to be 255.
+.le
+.ls PGM - PBMPlus PGM format image
+.nf
+
+ #expr Type bitpix CLT? Alpha? Interleaving Notes
+ ----- ----- ------ ---- ------ ------------ -----
+ 1 index 8 no no none
+ 3 index 8 no no none 1
+
+ Notes:
+ 1) Grayscale may be produce with \fIgray()\fR function
+
+.fi
+ The output file is an 8-bit raw (i.e. binary pixels) PGM image.
+The maximum pixel value is assumed to be 255.
+.le
+.ls PPM - PBMPlus PPM format image
+.nf
+
+ #expr Type bitpix CLT? Alpha? Interleaving Notes
+ ----- ----- ------ ---- ------ ------------ -----
+ 3 rgb 24 no no pixel
+
+.fi
+ The output file is an 24-bit raw (i.e. binary pixels) PPM image.
+The maximum pixel value per color is assumed to be 255.
+.le
+.ls RAS - Sun rasterfile format
+.nf
+
+ #expr Type bitpix CLT? Alpha? Interleaving Notes
+ ----- ----- ------ ---- ------ ------------ -----
+ 1 index 8 no no none
+ 1 index 8 yes no none 1,2
+ 3 rgb 24 no no pixel
+ 4 rgb 32 no yes pixel
+
+ Notes:
+ 1) Colormap generation enabled using \fIsetcmap()\fR
+ 2) Colormap generation enabled using \fIcmap()\fR
+
+.fi
+ The output file will be a Sun rasterfile. The header values
+(long integers) may be byte swapped by setting the \fIbswap\fR parameter
+to "yes" or "i4". For 32-bit true-color rasterfiles the
+alpha channel should be specified as the first expression. The maximum
+pixel value is assumed to be 255.
+.le
+.ls RGB - SGI RGB format image
+.nf
+
+ #expr Type bitpix CLT? Alpha? Interleaving Notes
+ ----- ----- ------ ---- ------ ------------ -----
+ 1 index 8 no no none
+ 3 rgb 24 no no scanline
+
+.fi
+ The output file will be an SGI RGB (IRIS) format image. Although
+this format supports colormaps they are not supported by this task.
+The maximum pixel value is assumed to be 255.
+.le
+.ls XWD - X11 Window dump file
+.nf
+
+ #expr Type bitpix CLT? Alpha? Interleaving Notes
+ ----- ----- ------ ---- ------ ------------ -----
+ 1 index 8 yes no none 1,2,3
+ 3 rgb 24 no no none
+
+ Notes:
+ 1) Linear grayscale colormap automatically generated
+ 2) Colormap generation enabled using \fIsetcmap()\fR
+ 3) Colormap generation enabled using \fIcmap()\fR
+
+.fi
+ The output file will be an X11 window dump file.
+A linear colormap of 256 entries will automatically be generated if only
+one image or expression is given for conversion, the \fIsetcmap()\fR function
+may be used to create an alternate colormap. If three images or expressions
+are specified a 24-to-8 bit conversion can be done using a Median Cut
+Algorithm and Floyd-Steinberg dithering if the \fIcmap()\fR function is
+specified. Header values (long integers) may be byte swapped by setting the
+task \fIbswap\fR parameter to "yes" or "i4". The maximum pixel value is
+assumed to be 255.
+.le
+
+.ih
+COLOR OUTPUT IMAGES
+ In theory the colormaps generated by the \fIcmap()\fR and
+\fIsetcmap()\fR functions could be written in the header for raw binary
+output and the pixel written out as color indices, but since we also
+support color index formats which are recognized widely by other packages
+there is no need to do this. Therefore we limit the use of colormaps to
+the builtin formats which already support it.
+
+ The simplest type of "color" image is the familiar grayscale image.
+Pixel values represent the display gray level, although for some formats a CLT
+(color lookup table) is required (e.g. GIF) and these pixel values are
+actually indices into a grayscale colormap. Most of the conversion done
+with this task will produce a grayscale image of some sort. For "color
+index" images the pixel values are indices into a colormap containing the
+RGB components of the color for a pixel with that value. Colormaps
+usually permit at most 256 possible colors implying 8-bit pixels.
+In this task the colormap may be computed either with the \fIcmap()\fR (which
+does a 24-to-8 bit mapping of the colors) or the \fIsetcmap()\fR function
+(which computes the colormap from a display lookup table of colors).
+"True color" images are those which have 24-bits of color (8-bit for each
+component) for each pixel, some true color images also contain an alpha
+channel (an extra 8-bits of constant intensity) which may or may not be
+used by the software displaying the image.
+
+ The \fIcmap()\fR function takes three images and computes a colormap
+using Paul Heckbert's Median Cut Algorithm ("Color Image Quantization for
+Frame Buffer Display", SIGGRAPH '82 Proceedings, pg 297) and Floyd-Steinberg
+dithering technique. The computed colormap is written to the file header
+and pixel values are converted to color indices. By default 256 colors are
+computed but fewer colors may be requested. This function is most useful
+for generating pseudo-color images from three input images taken in different
+filter bands (which is required for some formats like GIF that do not
+support 24-bit RGB).
+
+ The \fIsetcmap()\fR function, on the other hand, can be used to
+generate a color image from a single input image and a lookup table such as
+the ones used by displays servers like XImtool. In this case the pixel
+values are indices into a pre-defined colormap which is normalized between
+zero and one (so that it may be scaled to the desired number of colors).
+The \fIbrightness\fR argument defines the center of the transfer function, the
+default is 0.5 because it in the middle of the normalized range. The
+\fIcontrast\fR arguments sets the contrast of the transfer function. For
+example, the normalized pixel values and default brightness/contrast settings
+will map the pixel values to the corresponding color in the LUT. Changing
+the brightness to a lower value means that pixel intensities will map to lower
+values in the LUT, doubling the contrast for instance means that the LUT
+will increment two colors for every unit pixel change. This is what happens
+when changing a displayed image in IRAF with the mouse by moving the cursor
+left-right (changing the brightness) or up-down (changing the contrast).
+
+ An example use of this function would be if one wanted to convert an
+IRAF image to a color rasterfile with the same colormap and intensity
+scaling as was displayed in XImtool. After adjusting the display the
+brightness/contrast values could be read from the control panel and the
+rasterfile generated using
+.nf
+
+ setcmap (b1, "aips0", 0.36, 1.2)
+
+.fi
+where the "aips0" is one of the builtin colormaps and the brightness and
+contrast arguments are those from the ximtool display. Similarly, the
+expression
+.nf
+
+ setcmap (zscale(i1),"idl15.lut")
+
+.fi
+will save the image with the same intensity scaling and color as would be see
+by displaying it to ximtool using the default DISPLAY task settings,
+normalized XImtool brightness/contrast values and the "idl15.lut" LUT in the
+current directory.
+
+
+.ih
+EXAMPLES
+ The examples below are divided into several categories showing
+typical usage when creating various raw and builtin output files. Note
+that the output file will have a filename extension added indicating the
+format when converting to a builtin format.
+
+\fICreating Raw Binary Files\fR
+.nf
+
+List the pixels being one the standard output, apply a linear scale
+function first:
+
+ cl> export dev$pix "" list outbands="bscale(b1,1.0,3.2)"
+
+Convert the dev$pix test image to an 8-bit binary file with a gamma
+correction, write the standard header:
+
+ cl> export dev$pix bfil raw header+ outty="u1" outbands="gamma(b1,1.8)"
+
+Write the three bands of an IRAF image to a pixel interleaved binary
+file of short integers, prepend a user-defined header:
+
+ cl> export rgbim bfil raw header="hdr.txt" outty="i2" outban="b1,b2,b3"
+
+Convert three images representing RGB to a 4-color line-interleaved
+file, the IRAF images don't require scaling, create alpha channel:
+
+ cl> export rim,gim,bim bfil raw outty="u1" outban="line(i1,i2,i3,0)"
+
+Write the three bands of an IRAF image to a line-interleaved binary
+file of short integers:
+
+ cl> export rgbim binfil raw outtype="i2" outbands="line(b1,b2,b3)"
+ cl> export rgbim binfil raw outtype="i2" outbands="" interleave=3
+
+Write the three bands of an IRAF image to a grayscale binary file using
+a custom conversion formula. Pixel values are truncated to 8-bits:
+
+ cl> export rgbim grey raw outty="u1" outban="(.2*b1)+(.5*b2)+(.3*b3)"
+
+.fi
+
+\fICreating Specific Formats\fR
+.nf
+
+Convert dev$pix to an 8-bit Sun rasterfile with no colormap, scale the
+image to 8-bits using the default \fIzscale()\fR intensity mapping:
+
+ cl> export dev$pix dpix ras outbands="zscale(i1)"
+
+Apply various functions to the data before doing the same conversion:
+
+ cl> export dev$pix dpix ras outbands="zscale(log(i1))"
+ cl> export dev$pix dpix ras outbands="zscale(sqrt(i1))"
+
+Convert dev$pix to an 8-bit Sun rasterfile with no colormap, image pixel
+values are truncated to 8-bits:
+
+ cl> export dev$pix dpix ras
+
+Convert three images representing RGB to a 24-bit Sun rasterfile, assume
+the IRAF images don't require intensity scaling:
+
+ cl> export rim,gim,bim rgb ras outbands="i1,i2,i3"
+
+Create a Silicon Graphics RGB format image from a 3-D image:
+
+ cl> export rgbim bdata rgb outbands="b1,b2,b3"
+
+Convert dev$pix to an 8-bit GIF grayscale image, scale the image to map
+only pixel values between 0 and 320:
+
+ cl> export dev$pix dpix gif outbands="zscale(i1,0.0,320.0)"
+
+Combine three images representing RGB into an 8-bit X11 window dump
+grayscale image:
+
+ cl> export rim,gim,bim gray xwd outbands="gray(i1,i2,i3)"
+
+Convert dev$pix to an Encapsulated PostScript file at half the normal scale
+and apply a linear transformation to scale the pixel values:
+
+ cl> export dev$pix dpix eps \
+ >>> outbands="psscale(bscale(i1,0.,0.32), 0.5)"
+
+Convert three images representing RGB to an 8-bit GIF color image with
+a computed colormap:
+
+ cl> export rim,gim,bim rgb gif outbands="cmap(i1,i2,i3)"
+
+Convert dev$pix to a color rasterfile using the builtin "heat" colormap
+and default intensity mapping:
+
+ cl> export dev$pix dpix ras outban='setcmap(zscale(i1),"heat")'
+
+Convert dev$pix to a color rasterfile using the XImtool "idl15.lut"
+LUT file in the current directory and default intensity mapping:
+
+ cl> copy /usr/local/lib/imtoolcmap/idl15.lut .
+ cl> export dev$pix dpix ras outbands="setcmap(zscale(i1),'idl15.lut')"
+
+
+\fIAdvanced Usage\fR
+
+Given a set of DISPLAY task z1/z2 values of 10 and 320 respectively, and
+brightness/contrast values from XImtool of 0.6 and 1.2 respectively,
+convert an image to an EPS file with the same appearance:
+
+ im> type expr
+ setcmap ( zscale (i1, 10.0, 320.0), "greyscale", 0.6, 1.2 )
+ im> export dev$pix dpix eps outbands="@expr"
+
+Concatenate two images side-by-side to a PGM file, normalize each image
+by it's exposure time and apply a default intensity mapping:
+
+ cl> export im1,im2 two pgm \
+ >>> outbands='(zscale(i1/i1.otime)) // (zscale(i2/i2.otime))'
+
+Convert dev$pix to a color GIF using the XImtool "idl15" LUT with a spec-
+ified brightness/contrast scale. Map only pixel values between 5 and 300
+to 201 output intensity values. This should produce and image identical
+to what one would get by displaying dev$pix to imtool, setting the same
+brightness/contrast scale, and selecting the idl15 LUT:
+
+ cl> copy /usr/local/lib/imtoolcmap/idl15.lut .
+ cl> type expr.dat
+ setcmap (
+ zscale(i1, 5.0, 320.0, 201),
+ "idl15.lut",
+ 0.41,
+ 1.35)
+ cl> export dev$pix dpix gif outbands="@expr.dat"
+
+Combine three images representing RGB to an 8-bit Sun rasterfile with a
+computed colormap. Scale the intensity value of each image differently.
+
+ cl> type expr.dat
+ cmap (
+ zscale (i1),
+ zscale (i2, 0.0, 1200.0),
+ zscale (i3, -1.0, 320.0) )
+ cl> export im1,im2,im3 rgb ras outbands="@expr.dat"
+
+Do the same example but apply a gamma correction to the images:
+
+ cl> type expr.dat
+ cmap (
+ gamma (zscale(i1), 2.2),
+ gamma (zscale(i2,0,1200), 2.2),
+ gamma (zscale(i3,-1,320), 2.2) )
+
+Write four images to a grayscale GIF file such that they are tiled in a
+2x2 grid:
+
+ cl> export im1,im2,im3,im4 quad gif \
+ >>> outbands="band( (i1//i2), (i3//i4) )"
+
+Do the same example but create a border of 2 gray pixels around each
+of the images and apply the AIPS0 LUT with brightness/contrast values
+to create a color image:
+
+ cl> copy /usr/local/lib/imtoolcmap/aips0.lut .
+ cl> type expr.dat
+ setcmap (
+ band(
+ 128, 128,
+ (repl (128,2) // i1// repl (128,2) // i2 // repl (128,2)),
+ 128, 128,
+ (repl (128,2) // i3// repl (128,2) // i4 // repl (128,2)),
+ 128, 128 ),
+ "aips0.lut",
+ 0.54,
+ 1.03)
+ cl> export im1,im2,im3,im4 cquad gif outbands="@expr.dat"
+
+.fi
+
+Automatically scale an image ignoring data in a bad pixel mask (bpm), map the
+result to the greyscale part of the "overlay" color map, and apply a
+overlay pattern given by another mask (pattern).
+
+ cl> export dev$pix,bpm,pattern foo gif \
+ >>> outbands = "setcmap(i3==0?(zscalem(i1,i2==0)*200/255.):i3+203,'overlay')"
+
+
+The pattern has values of 1 and 203 is added to get it into the color map
+values of the overlay colors. The factor of 200/255 is to scale the result
+of zscalem from the range 0-255 to the range 0-200.
+
+.ih
+NOTES
+ This task is new with V2.11.
+
+ (long int headers in RAS and XWD may cause problems on 64-bit
+machines like the Alpha where host software expects 64-bit values. Need to
+see if IRAF on the alpha produces 32 or 64-bit longs, either way exchanging
+images may be a problem)
+
+.ih
+BUGS
+ Output of bitmap images is currently not supported.
+.ih
+SEE ALSO
+import, tvmark, imexpr
+.endhelp
diff --git a/pkg/dataio/doc/import.hlp b/pkg/dataio/doc/import.hlp
new file mode 100644
index 00000000..da8047b7
--- /dev/null
+++ b/pkg/dataio/doc/import.hlp
@@ -0,0 +1,631 @@
+.help import Oct94 dataio
+.ih
+NAME
+import -- create an IRAF image from an arbitrary binary file
+.ih
+USAGE
+import binfiles images
+.ih
+PARAMETERS
+.ls binfiles
+The list of input binary files to be read.
+.le
+.ls images
+The list of output IRAF images to be written. This parameter only needs to
+be specified when generating an output image (see the \fIoutput\fR parameter
+description).
+.le
+.ls format = "sense"
+The type of format to be processed. In default mode, i.e. \fIsense\fR,
+the format database is searched for a format identifier that evaluates
+truly for the current binary file, the input file parameters are then
+derived from the database entry. A specific format name in the database may
+alternatively be given in which case the input params are derived from that
+entry in the database. If \fIformat\fR=\fInone\fR the task parameters
+are used to describe the input file.
+.le
+
+.ce
+INPUT PARAMETERS
+.ls dims = ""
+The input file dimension string. This is a space or comma delimited string
+containing the length of the file in each dimension, e.g. "512,512,3".
+.le
+.ls pixtype = ""
+Input pixel type. This is a comma delimited string giving the type and size
+of each pixel, and an optional tag name to be used in the \fIoutbands\fR
+expressions. The syntax for the pixtype entry is
+.ls <type><nbytes>[:tag],<type><nbytes>[:tag],[....]
+
+where
+.nf
+ type = b # byte (no conversions)
+ u # unsigned integer
+ i # signed integer
+ r # ieee floating point
+ n # native floating point
+ x # ignore (skip)
+
+ nbytes = 1, 2, 4, or 8
+
+ tag is something like 'r','g','b' (color triplets), 'r',
+ 'i' (complex data), etc. If no tags are given one will
+ automatically be assigned of the form 'b1', 'b2', etc.
+
+.fi
+.le
+.le
+.ls interleave = 0
+Pixel interleave type. If the \fIpixtype\fR parameter is a composite then
+the input pixel are pixel-interleaved (i.e. each pixel in a band is stored
+together, as with RGB triplets) and this parameter is ignored. If
+the \fIpixtype\fR is an atomic value and \fIinterleave\fR is a positive
+number the image is line interleaved (e.g. a line of 'R', followed by a
+line of 'G', and so on). If the \fIpixtype\fR is atomic and \fIinterleave\fR
+is zero, the no data interleaving is assumed and each band in the file
+is stored sequentially.
+.le
+.ls bswap = "no"
+Type of byte-swapping to perform. By default no byte swapping is done,
+if \fIbswap\fR is "yes" then all input values are byte swapped, if \fIbswap\fR
+is "i2" then only short integers are byte swapped, if \fIbswap\fR is "i4" then
+only long integers are swapped. A combination of "i2,i4" can be used to
+swap only integer values, floating point numbers will not be swapped.
+.le
+.ls hskip = 0
+Number of bytes preceding pixel data to skip.
+.le
+.ls tskip = 0
+Number of bytes to skip at end of file.
+.le
+.ls bskip = 0
+Number of bytes between image bands to skip.
+.le
+.ls lskip = 0
+Number of bytes to skip at font of each line.
+.le
+.ls lpad = 0
+Number of bytes to skip at end of each line.
+.le
+
+.ce
+OUTPUT PARAMETERS
+.ls output = "image"
+Type of output to generate. Possible values include "none" process the files
+but not generate an output image (e.g. to check the parameter values for
+correctness), "image" to generate an output image, "list" to generate a
+pixel listing of the file as would be produced by the \fILISTPIX\fR task
+on the image if were converted (no image is created with this option),
+or "info" to print information about the file. The \fIimages\fR parameter
+is only used for \fIoutput\fR=image.
+.le
+.ls outtype = ""
+The data type of the output image. May be one of 's' for a short image, 'i'
+for an integer image, 'l' for a long image, 'r' for a real image, and 'd'
+for a double precision image. If no \fIouttype\fR is specified then the
+datatype of the \fIoutbands\fR expression is used. This parameter is only
+used when \fIoutput\fR is set to "image".
+.le
+.ls outbands = ""
+Output image band expressions. If no expressions are given then all of the
+input pixels will be converted. The number of output bands may be more or
+less than the number of input bands. See the \fIOUTBANDS EXPRESSIONS\fR
+section for a more complete description of this parameter.
+.le
+.ls imheader = ""
+Image or header keyword data file. If an image is given then the image header
+is copied. If a file is given then the FITS format cards are copied.
+This only applies to new images. The data file consists of lines
+in FITS format with leading whitespace ignored. A FITS card must begin
+with an uppercase/numeric keyword. Lines not beginning with a FITS
+keyword such as comments or lower case are ignored. The user keyword
+output of \fBimheader\fR is an acceptable data file. See \fBmkheader\fR
+for further information.
+.le
+
+.ls database = "imcnv$lib/images.dat"
+The format database. This may also be a list of files to be searched (e.g.
+so that user-defined databases may be included), which will be treated as
+a single database.
+.le
+.ls verbose = yes
+Print verbose output during the conversion?
+.le
+.ls buffer_size = 64
+Number of image lines \fIper band\fR to buffer in memory before writing to
+disk. Image buffering can increase task performance by as much as a factor
+of 30 for some formats but requires more memory.
+.le
+
+.ih
+DESCRIPTION
+
+ The \fIimport\fR task is used to convert arbitrary raster binary
+files to IRAF format images. The input format may be specified either
+through the task parameters (\fIformat\fR set to 'none'), or as an entry
+in a database of known formats (\fIformat\fR set to the name of the entry).
+If the format of the image is not known a priori, the database can be
+searched and each record will be evaluated for an expression which
+identifies the format (\fIformat\fR set to "sense"). The task will
+output either an IRAF image, a list of pixel values
+in a manner similar to the \fILISTPIX\fR task, or information about the
+file format if it is supported in the database.
+
+.ih
+Input File Specification
+ The input raster is assumed to be at most three dimensional, with
+pixels of various sizes that can be interleaved in a variety of ways.
+No compression schemes are yet supported, except in the case of builtin
+formats where special code has been written to handle to format.
+Byte-swapping and floating point conversion of pixels (from IEEE to
+native) is also supported.
+
+ The \fIpixtype\fR and \fIinterleave\fR parameters define the pixel
+storage in the binary file. \fIPixtype\fR is a comma delimited string,
+the elements of which define the type and size of each pixel. An optional
+'tag' name may be given to each pixel for use in the \fIoutbands\fR
+expressions. If no tag is given one will automatically be assigned.
+For composite pixtypes (i.e. when more than one element is listed), the
+data are assumed to be pixel interleaved (e.g. stored as { {RGB}, {RGB} ...}
+triplets). For atomic (i.e. single) pixtypes, a positive value of
+\fIinterleave\fR indicates that the data are stored in a line-interleaved
+manner (e.g. a line of R, a line of G, ...). If \fIinterleave\fR is
+zero and \fIpixtype\fR is atomic, then no interleaving is done and the
+image bands are thought to be stored sequentially. Minimal error
+checking is done to make sure the
+combination of these parameters is correct.
+
+ The file may contain arbitrary padding around the pixels as
+defined by the \fItskip\fR, \fIbskip\fR, \fIlskip\fR, and \fIlpad\fR
+parameters, header information may be skipped by setting the \fIhskip\fR
+parameter. Additionally, pixels may be ignored on input while still
+specifying the full format.
+.ih
+Output Parameters
+ Once a format has been found, the task may output an IRAF image
+by setting \fIoutput\fR to "image", a list of the pixels in the file
+can be written to STDOUT by setting \fIoutput\fR to "list", or information
+about the input file can be printed by setting \fIoutput\fR to "info".
+If \fIoutput\fR is set to "none" then no output will be generated, this
+can be used to check for read errors on the input file to verify task
+parameters. The datatype of the output image can be set by specifying
+the \fIouttype\fR parameter.
+
+ The \fIoutbands\fR parameter is a list of expressions which are
+evaluated to compute the pixels in each band of the output image. Operands
+in these expressions consist of numeric constants and the pixtype tags
+(either user-supplied tags or the automatic tags), general arithmetic
+expressions are supported, which can include any of the special functions
+listed below. The simplest expression is the name of a tag itself.
+Regardless of the storage of pixels in the input file, each image band is
+separated on output unless an expression is given which combines them.
+See below for more details on \fIoutbands\fR.
+
+ Header information may be added to an output image by naming
+either a keyword file or an existing image header listing in the
+\fIimheader\fR parameter. A header keyword data file consists of lines
+of FITS format cards. Leading whitespace is ignored. Lines not recognized
+as FITS cards are ignored. A valid FITS card is defined as beginning with
+a keyword of up to 8 uppercase, digit, hyphen, or underscore characters. If
+less than 8 characters the remaining characters are blanks. The
+ninth character may be an equal sign but must be immediately followed
+by a blank. Such value cards should be in FITS format though no
+attempt is made to enforce this. Any other ninth character is also
+acceptable and the line will be treated as a comment. Note that this
+way of recognizing FITS parameters excludes the case of comments
+in which the first 8 characters are blank. The reason for allowing
+leading whitespace and eliminating the blank keyword case is so that
+the long output of \fBimheader\fR may be used directly as input.
+
+.ih
+OUTBANDS EXPRESSIONS
+
+ The outbands parameter is a comma delimited list of expressions, the
+simplest of which is the name of a tag itself (or the default names of the
+tags if none are provided in the \fIpixtype\fR param).
+The input pixels, regardless of how they are stored in the binary file,
+are always stored as separate bands in the output IRAF image.
+The outbands expressions will be evaluated to compute the pixels in each
+band of the output image. This means that e.g. RGB triplets in an input
+file will be separated into different bands in the output image, unless a
+single expression is given that combines them. The components named
+in \fIpixtype\fR may be eliminated or re-ordered in \fIoutbands\fR to
+exclude certain input bands, or to change the channel order. For example
+the commands:
+
+.nf
+cl> import file img pixtype="u1:a,u1:r,u1:g,u1:b" outbands="g,r,a"
+cl> import file img pixtype="u1,u1,u1,u1" outbands="b3,b2,b1"
+.fi
+
+both convert an input 32-bit image with ARGB components. In the first case
+the output image is an IRAF image where the B component has been eliminated
+and the channel order reversed. The second case is the same as the first but
+uses the automatic tag names. A combination of user-supplied tags and
+defaults could also be used.
+
+ General interpreted arithmetic expressions are supported and can
+contain any of the standard expression evaluator functions (see
+the \fIimexpr\fR help page for more details). Special functions in
+expressions also include:
+.nf
+
+ flipx (arg) - flip image in X
+ flipy (arg) - flip image in Y
+ gr[ea]y (r,g,b) - RGB to grayscale using the NTSC Y formula
+ red (arg) - get the red component of a colormap image
+ green (arg) - get the green component of a colormap image
+ blue (arg) - get the blue component of a colormap image
+ gamma (arg, gamma) - apply a gamma correction to the image
+
+.fi
+The two flip functions can change the image orientation by reversing the order
+of pixels within a line (a flipx() call), or it can flip an image from top-
+to-bottom (a flipy() call). The flipping will apply to all bands of the out-
+put image even if it was only used in one expression. To reverse the channel
+order simply change the order of the tags in the outbands parameter. RGB
+images may be converted to a single grayscale image using the NTSC formula:
+.nf
+
+ gray = (0.289 * r) + (0.587 * G) + (0.114 * B)
+
+.fi
+Note that a similar grayscale conversion can be done by explicitly defining
+a similar equation in \fIoutbands\fR and supplying different coefficients.
+
+ The \fIred()\fR, \fIgreen()\fR, or \fIblue()\fR functions can be used
+to get a single color component from a colormap image rather than the
+grayscale equivalent of the colormap. For example, to separate an 8-bit
+GIF color image into it's RGB components one could specify an outbands
+parameter such as
+.nf
+
+cl> import foo.gif bar format=gif outbands="red(b1),green(b1),blue(b1)"
+
+.fi
+
+ Functions may also be nested in complex expressions such as:
+
+.nf
+ flipy (gray(r,g,b)) - convert to grayscale, flip in Y
+ flipx (flipy (gray (r,g,b))) - convert to grayscale, flip in X & Y
+ gray (r,g,255) - use constant 255 as the B band
+ gray (r,g+100,-b) - add constant to G, negate B
+.fi
+
+.ih
+FORMAT DATABASE
+
+ The format database is a text file named as a task parameter.
+Each record of a database entry is of the form:
+
+.nf
+ <format_name>:
+ <alias>:
+ keyword = <expr>
+ keyword = <expr>
+ ...and so on
+.fi
+
+A database record begins with the format name at the beginning of a line.
+Whitespace at the beginning of a line is considered the continuation of a
+previous line. Comments may be inserted in the database using the normal '#'
+character, the remainder of the line is considered a comment. Blank lines
+and comments are ignored, a record ends at the next line with a format name
+at the beginning of the line. The task \fIdatabase\fR parameter
+defines the text files to be
+scanned as the database. If the parameter is a list of files then each file
+in the list will be concatenated to a single database file used by the task.
+
+ The format_name field is a string identifying each entry in the
+database, any number of aliases may also be given to identify the same
+format possibly known by another name. Supported keywords include:
+
+.nf
+ image_id - A boolean expression identifying the image type
+ id_string - Verbose name of file format
+ bswap - is file byte-swapped? (See Below)
+ dims - a whitespace/comma delimited string of dimensions
+ pixtype - pixel type, size [and tag], may be a composite
+ interleave - describes how pixels are stored
+ hskip - # of bytes of header info to skip
+ tskip - # of bytes of trailing info to skip at end of file
+ bskip - # of bytes of info to skip between image bands
+ lskip - # of bytes of info to skip at front of each line
+ lpad - # of bytes of info to skip at end of each line
+ error - A condition that would cause a file read error,
+ returns a string with the error message, otherwise
+ returns the string "okay"
+.fi
+
+The 'image_id' string is an expression to be evaluated which, if true,
+uniquely identifies the file format (such as a comparison to a "magic number").
+The 'id_string' is a verbose name of the format.
+The 'error' keywords use the "? :" conditional syntax to
+define a boolean expression which, when true, returns an error message and is
+used to indicate a condition in a format which isn't supported. The remaining
+keywords have the same meaning as the task parameters. Keywords not present
+in the database record will take the default parameter value.
+
+ Expressions consist of any valid string that may be evaluated with the
+standard system expression evaluator evvexpr(). (See the documentation for this
+procedure or the \fIIMEXPR\fR task help page for details of builtin functions
+and operators.) Operators within expressions may be boolean, arithmetic,
+or the string operators '?=' (substring equality) and '//' (concatenation).
+Operands may be the special functions named below, previously defined
+keywords, constants (numeric or strings), and the special operands
+
+.ls $FSIZE
+The size of the binary file in bytes. In expressions this operand has an
+integer datatype. For formats with variable header sizes this can be used
+to determine the size of the header, since the size of the data can be
+derived from the image dimensions and subtracted from the total size of the
+file.
+.le
+.ls $FNAME
+The name of the binary file. In expressions this operand has a character
+datatype. As a last resort for images without any identifying features the
+file name may possibly be used to determine the format from a file name
+extension.
+.le
+
+
+.ih
+Special Functions:
+
+ In addition to the intrinsic functions already provided there are a
+number of input and utility functions for the database. These are:
+.nf
+
+ \fIINPUT FUNCTIONS\fR
+
+ ctocc ([offset]) - convert byte to printable char constant
+ ctod ([offset]) - convert string to double precision real
+ ctoi ([offset]) - convert string to integer
+ ctol ([offset]) - convert string to long
+ ctor ([offset]) - convert string to single precision real
+ ctowrd ([offset]) - get 1st white-space delimited word from str
+
+ getstr ([offset,] len) - get a string at offset
+ getb ([offset]) - get a byte at offset
+ getu ([offset]) - get an unsigned short int at offset
+geti[24] ([offset]) - get a signed int at offset
+getr[48] ([offset]) - get an IEEE fp number at offset
+getn[48] ([offset]) - get a native fp number at offset
+
+ locate ([offset,] pat) - find an offset to a pattern
+ line (n) - offset of line N
+
+ \fIUTILITY FUNCTIONS\fR
+
+ skip (nbytes) - move offset by N-bytes
+ bswap (arg) - byte swap the argument
+ substr (str, c1, c2) - extract a substring from argument
+ stridx (test, str) - get 1st occurrence of 'test' w/in 'str'
+
+parameter (param) - return the current task parameter
+ default (param) - return the default task parameter
+ lsb_host () - returns true if host is little-endian
+ msb_host () - returns true if host is big-endian
+.fi
+
+.ls ctocc ([offset]) [string]
+Convert byte at the given offset to printable char constant.
+If no offset argument is given the current offset is used.
+.le
+.ls ctod ([offset]) [double]
+Convert string to double precision real.
+The function reads a string from
+the file and converts it up to the first unrecognized character.
+If no offset argument is given the current offset is used.
+.le
+.ls ctoi ([offset]) [int]
+Convert string to integer.
+The function reads a string from
+the file and converts it up to the first unrecognized character.
+If no offset argument is given the current offset is used.
+.le
+.ls ctol ([offset]) [long]
+Convert string to long.
+The function reads a string from
+the file and converts it up to the first unrecognized character.
+If no offset argument is given the current offset is used.
+.le
+.ls ctor ([offset]) [real]
+Convert string to single precision real.
+The function reads a string from
+the file and converts it up to the first unrecognized character.
+If no offset argument is given the current offset is used.
+.le
+.ls ctowrd ([offset]) [string]
+Get 1st white-space delimited word from str, leading whitespace is skipped.
+If no offset argument is given the current offset is used.
+.le
+.ls getstr ([offset,] len) [string]
+Get a string at offset.
+If no offset argument is given the current offset is used, the length of
+the string must be specified.
+.le
+.ls getb ([offset]) [int]
+Get a byte at offset.
+If no offset argument is given the current offset is used.
+.le
+.ls getu ([offset]) [int]
+Get an unsigned short integer at offset.
+If no offset argument is given the current offset is used.
+.le
+.ls geti[24] ([offset]) [int]
+Get a signed int at offset.
+If no offset argument is given the current offset is used.
+Long integers values can be read by specifying the function as geti4(),
+the names geti() and geti2() return short integers.
+.le
+.ls getr[48] ([offset]) [real/double]
+Get an IEEE floating point number at an optional offset.
+If no offset argument is given the current offset is used.
+Double precision values can be read by specifying the function as getr8(),
+the names getr() and getr4() return single precision real.
+.le
+.ls getn[48] ([offset]) [real/double]
+Get a native floating point number at an optional offset.
+If no offset argument is given the current offset is used.
+Double precision values can be read by specifying the function as getn8(),
+the names getn() and getn4() return single precision real.
+.le
+.ls locate ([offset,] pat) [int]
+Compute an offset.
+If no offset argument is given the current offset is used.
+.le
+.ls line (N) [int]
+Offset of line N in bytes. The database is rewound and the offset of the
+requested line number is returned, line are delimited by the '\n' character.
+.le
+.ls skip (nbytes) [int]
+Move current offset by N-bytes. The number of bytes skipped is returned as
+the function value.
+.le
+.ls bswap (arg) [type of arg]
+Byte swap the argument.
+.le
+.ls substr (str, first, last) [string]
+Extracts a substring from string \fIstr\fR. The first character in
+the string is at index 1.
+.le
+.ls stridx (test, str) [int]
+Finds the position of the first occurrence of any character found
+in \fItest\fR in the string \fIstr\fR, returning 0 if the match fails.
+.le
+.ls parameter (param) [param type]
+Return the current task parameter. The parameter is specified as a string
+containing the name of a task parameter, the type of the returned value is
+the parameter type
+.le
+.ls default (param) [param type]
+Return the default task parameter. The parameter is specified as a string
+containing the name of a task parameter, the type of the returned value is
+the parameter type
+.le
+.ls lsb_host () [bool]
+Returns true if host is little-endian.
+This function can be used as the \fIbswap\fR keyword expression for formats
+with a specified byte order.
+.le
+.ls msb_host () [bool]
+Returns true if host is big-endian.
+This function can be used as the \fIbswap\fR keyword expression for formats
+with a specified byte order.
+.le
+
+.ih
+BYTE SWAPPING
+
+ The 'bswap' database entry is similar to the task parameter, it may
+be used to set byte swapping for the whole file, or for only certain data
+types. The value is a string parameter that may be "yes" to byteswap the
+whole file, "no" to not swap anything, or a comma delimited string of types
+described below to enable swapping for only those values.
+.nf
+
+ bswap = { no | yes | i2 i4 }
+
+ no # no swapping (default)
+ yes # byte swap whole file
+ i2 # byte swap short ints only
+ i4 # byte swap long ints only
+.fi
+
+ The \fIbswap\fR task parameter applies only to the pixel data,
+but the bswap keyword in a database record sets byte-swapping
+for the header information: arguments to the input and conversion functions
+will be byteswapped prior to being evaluated by the function. The bswap()
+special function can be used to negate byteswapping for a particular
+argument if it is or is not set by the keyword (the default is no byte
+swapping).
+
+.ih
+EXAMPLES
+.nf
+
+Get a list of known input formats:
+
+ cl> import "" "" output=info
+
+Get a list of known input formats, including those defined by the user:
+
+ cl> import "" "" output=info database="dev$images.dat,mydb.dat"
+
+Get a list of the file formats of each image in the directory:
+
+ cl> import file* "" format="sense" output=info verbose-
+ file1.ras Sun rasterfile
+ file1.eps unknown format
+ file1.pgm 8-bit PGM file
+ : :
+
+Get a list of the file formats of each image in the directory and
+print out some information about each file:
+
+ cl> import file* "" format="sense" output=info verbose+
+ file1.ras: Sun Rasterfile
+ Resolution: 320 x 200
+ Pixel type: 8-bit unsigned integer
+ Pixel storage: non-interleaved
+ Header length: 137 bytes
+ Byte swapped: no
+ ... :
+
+Read a raw 8-bit file of pixels into an unsigned short IRAF image:
+
+ cl> import file img format="none" dims="512,512" pixtype="b1" \
+ >>> outtype="u" outbands="b1"
+
+Read a JPL VICAR image or 8-bit Sun rasterfile:
+
+ cl> import file img format="vicar"
+ cl> import file img format="sunras"
+
+Concatenate three separate red, blue, and green images and convert
+ to a single grayscale image:
+
+ cl> concat pic.[rgb] > rgb
+ cl> import rgb img format=none dims="640,480,3" \
+ >>> pixtype="u1" interleave=0 outbands="gray(b1,b2,b3)"
+
+Read an 8-bit colormap GIF image and separate the RGB colors into
+ separate bands in the output image:
+
+ cl> import file.gif img outbands="red(b1),green(b1),blue(b1)"
+
+Read three 8-bit rasterfiles with 200 byte-headers as if they were
+ a single image, and combine the images to a single output band:
+
+ cl> concat pix.* > rfiles
+ cl> import rfiles img dims="512,512,3" pixtype="b1" \
+ >>> hskip=200 bskip=200 interleave=0 outbands="gray(b1,b2,b3)"
+
+Read a FITS image with one header record in which the data bytes
+ are incorrectly swapped, but the header info is in the right order:
+
+ cl> rfits nite1.fits "" nite1
+ File: nite1 1866-A Size = 640x480
+ cl> imheader nite1 l+ > imheader.dat # Save the header info
+ cl> imdel nite1.imh
+ cl> import nite1.fits nite1 format="none" dims="640,480" \
+ >>> bswap+ hskip=2880 pixtype="i2" outtype="s" imheader="imheader.dat"
+
+.fi
+
+.ih
+BUGS
+Bitmap images are not yet supported. Their most logical use would be as
+pixel masks but there hasn't been much call for these formats so they may
+be implemented at a later time.
+.ih
+REVISIONS
+.ls IMPORT V2.11
+This is a new task in this version.
+.le
+.ih
+SEE ALSO
+export. imexpr, hedit, default image database imcnv$lib/images.dat
+.endhelp
diff --git a/pkg/dataio/doc/mtexamine.hlp b/pkg/dataio/doc/mtexamine.hlp
new file mode 100644
index 00000000..15504254
--- /dev/null
+++ b/pkg/dataio/doc/mtexamine.hlp
@@ -0,0 +1,84 @@
+.help mtexamine Apr84 dataio
+.ih
+NAME
+mtexamine -- examine the structure of magtape or a single disk file
+.ih
+USAGE
+mtexamine tape_file
+.ih
+PARAMETERS
+.ls tape_file
+Tape or disk file, e.g. "mta1600[2]", "mta1600" or "data".
+.le
+.ls file_list = "1-999"
+List of tape file numbers or ranges delimited by commas, e.g. "1-3,5-8".
+File_list is used only if no file number is given in tape_file.
+Files will be read in ascending order, regardless of the order of the list.
+Reading will terminate if EOT is reached, thus a list such as "1-999"
+may be used to read all the files on the tape. File_list is ignored is input
+is a single disk file.
+.le
+.ls dump_records = no
+Dump selected records?
+.le
+.ls rec_list = "1-999"
+List of tape record numbers or ranges to be dumped delimited by whitespace
+or commas e.g "1-3,4".
+.le
+.ls swapbytes = no
+Swap bytes?
+.le
+.ls byte_chunk = 1
+The number of bytes which are considered as one output element.
+The maximum number of bytes permitted in byte_chunk is the number of
+bytes in a long integer on the host machine.
+.le
+.ls output_format = "o"
+Permitted types are character(c), octal(o), hexadecimal (x), decimal (d)
+or unsigned decimal (u). Character dumps are only permitted for byte_chunk = 1.
+Unless decimal format is specified, the data are dumped as
+unsigned integers.
+.le
+.ih
+DESCRIPTION
+By default mtexamine determines the record structure of all files
+on a magnetic tape or a single disk file.
+Selected files can be dumped by setting the file_list parameter.
+Selected records can be dumped by setting the dump_record switch
+and entering a record list. The user can select the byte chunk
+and the output format for the dump.
+
+Mtexamine can also be used to dump a single disk file. However the concept
+of a block is not well defined for disk files. Mtexamine defines a block
+to be one IRAF file io block which is usually some multiple of the machine
+block size.
+.ih
+EXAMPLES
+1. Determine the record structure of a magnetic tape and send the result to
+the file tapedump.
+
+.nf
+ cl> mtexamine mtb1600 > tapedump
+.fi
+
+2. Dump the third tape file in octal bytes on the standard output.
+
+.nf
+ cl> mtexamine mtb1600[3] du+
+.fi
+
+3. Dump the contents of the fifth record of the third tape file in ASCII
+characters on the standard output.
+
+.nf
+ cl> mtexamine mtb1600[3] du+ re=5 ou=c
+.fi
+.ih
+BUGS
+The IRAF magtape i/o routines do not permit data beyond a double EOF
+to be accessed. Therefore mtexamine cannot be used to examine tapes with
+embedded double EOFs.
+.ih
+SEE ALSO
+rewind, allocate
+.endhelp
diff --git a/pkg/dataio/doc/rcardimage.hlp b/pkg/dataio/doc/rcardimage.hlp
new file mode 100644
index 00000000..910cfc72
--- /dev/null
+++ b/pkg/dataio/doc/rcardimage.hlp
@@ -0,0 +1,120 @@
+.help rcardimage Jan87 dataio
+.ih
+NAME
+rcardimage -- Convert a card image file into an IRAF text file
+.ih
+USAGE
+rcardimage cardfile file_list textfile
+.ih
+PARAMETERS
+.ls cardfile
+The cardimage source file. Cardfile may be either a template specifying a
+list of disk files, e.g. card* or a mag tape file specification of the
+form mtl*[n], where mt stands for mag tape, l stands for a specific drive,
+* stands for the density and [n] is the tape file number. If no tape file
+number is specified then the tape file numbers are taken from the
+file_list parameter.
+.le
+.ls file_list
+A list of tape file
+numbers or ranges delimited by commas, for example
+"1,3,5-8", which is used only if the magtape device is specified.
+Files will be read in ascending order, regardless of
+the ordering of the list. Reading will terminate silently if EOT
+is reached, thus a list such as "1-999" may be used to read all
+files on a tape.
+.le
+.ls textfile
+Name of the output file. If multiple input files, multiple output
+files will be generated by concatenating the tape file number or
+disk sequence number onto the textfile string.
+.le
+.ls card_length = 80
+The number of columns per card in the input card image file.
+Must be divisible by the number of bytes per "IRAF character" (2 on most
+machines). The task reblock can be used to pad files with odd-sized
+cards.
+.le
+.ls max_line_length = 161
+The maximum line length to be generated. Default is maximum size
+of a line permitted by IRAF.
+Useful for stripping columns 73-80 from Fortran card image files.
+.le
+.ls entab = yes
+Replace blanks with tabs and blanks. Tabsize is 8.
+.le
+.ls join = no
+Rejoin oversize lines.
+.le
+.ls contn_string = ">>"
+Marker to enable program to recognize oversize lines.
+.le
+.ls trim = yes
+Trim trailing whitespace from each line.
+.le
+.ls verbose = yes
+Output messages listing files created, number of cards
+processed, etc.
+.le
+.ls ebcdic = no
+Translate from ebcdic to ascii.
+.le
+.ls ibm = no
+Translate from ibm ebcdic to ascii.
+.le
+.ls offset = 0
+Integer parameter specifying the tape file number offset. For example if
+offset = 100, card_file = "card" and file_list = "1-3", the output file
+names will be "card101", "card102" and "card103" respectively, instead of
+"card001", "card002" and "card003".
+.le
+
+.ih
+DESCRIPTION
+Multiple cardimage files are read from disk or tape.
+If only the magtape device is specified,
+a list of file numbers is requested. In the latter case, output files
+have the form root_filename // tape(disk)_file_number. By default, trailing
+whitespace is trimmed from each line.
+
+.ih
+EXAMPLES
+1. Convert a set of ASCII cardimage files on magnetic tape to IRAF text files,
+replacing blanks with tabs and blanks, and trimming whitespace from
+the ends of lines.
+
+ cl> rcardimage mtb1600 1-999 textfiles
+
+2. Convert a set of ASCII cardimage files on disk to IRAF test files.
+
+ cl> rcard card* 1 textfiles
+
+3. Convert a set of EBCDIC cardimage files on magnetic tape to IRAF text files,
+trimming whitespace from the ends of lines but leaving embedded blanks
+unchanged.
+
+ cl> rcardimage mtb1600 1-999 textfile en- ebc+
+
+4. Convert an odd-blocked (81 bytes per card) rcardimage file on tape to an
+IRAF text file by using reblock to write the file to disk and pad the cards
+with blanks, followed by rcardimage to convert the file to an IRAF textfile.
+
+ cl> reblock mta[1] cardimage inrecord=81 outrecord=82 \
+ padchar=" "
+
+ cl> rcardimage cardimage 1 textfile card_length=82
+
+.ih
+BUGS
+Due to portability considerations The card length in bytes must fill an
+integral number of IRAF characters. On most machines this means that the
+length of the card must be an even number of bytes . The task should be
+generalized to require only that the tape record length be specified
+to read odd blocked card image files.
+
+The size of the output text file lines is currently restricted to 161
+or fewer characters.
+.ih
+SEE ALSO
+wcardimage
+.endhelp
diff --git a/pkg/dataio/doc/reblock.hlp b/pkg/dataio/doc/reblock.hlp
new file mode 100644
index 00000000..dd3a506a
--- /dev/null
+++ b/pkg/dataio/doc/reblock.hlp
@@ -0,0 +1,177 @@
+.help reblock Jan93 dataio
+.ih
+NAME
+reblock -- copy a file to tape or disk with optional reblocking
+.ih
+USAGE
+reblock infiles outfiles file_list
+.ih
+PARAMETERS
+.ls infiles
+The input file list or device name, e.g. "mta1600[2]" or "mta800", "file1",
+"file1,file2", or "@infiles".
+.le
+.ls outfiles
+The list of output files or device name, e.g. "gemini!mtb", "out1",
+"out1,out2", or "@outfiles".
+If multiple file output to disk is requested, and the specified number
+of output files is 1, the output file names will be generated
+by concatenating the tape file number (the input files are on tape) or
+a sequence number (the input files are on disk) onto the output file
+name.
+.le
+.ls file_list
+List of tape file numbers or ranges delimited by commas,
+e.g. "1-3,5_8".
+File_list is requested only if the magtape input device is specified.
+Files will be read in ascending order regardless of the ordering of the list.
+Reading will terminate silently if EOT is reached, thus a list such as
+"1-999" may be used to read all files on the tape.
+.le
+.ls newtape
+If the output device is magtape, newtape specifies whether the tape is
+blank or contains data.
+Newtape is requested only if no tape file number is specified, e.g. "mta1600".
+.le
+.ls outblock = INDEF
+Size of the output block bytes.
+In the default case and for disk output, the output block size is set to the
+file i/o disk default buffer size.
+.le
+.ls inrecord = INDEF, outrecord = INDEF
+The sizes of the input and output logical records in bytes.
+The default input and output record sizes are set equal to
+the input and output block sizes respectively. If inrecord > outrecord,
+records are trimmed; if inrecord < outrecord, records are padded; if
+inrecord = outrecord, records are simply counted. If only one of inrecord or
+outrecord is set, the undefined parameter defaults to the value of the
+other.
+.le
+.ls skipn = 0
+The number of input blocks (tape input) or records (disk input, size inrecord)
+to be skipped.
+.le
+.ls copyn = INDEF
+The number of input blocks (tape input) or records
+(disk input, size inrecord) to be copied. Copyn defaults to a very large number.
+.le
+.ls byteswap = no
+Swap every other byte. For example if byteswap is enabled, bytes 1 2 3 4 5 6
+would become bytes 2 1 4 3 6 5 on output.
+.le
+.ls wordswap = no
+Swap every 4 bytes. For example if byteswap is enabled, bytes 1 2 3 4 5 6 7 8
+would become 4 3 2 1 8 7 6 5 on output.
+.le
+.ls pad_block = no
+If pad_block is set, reblock pads trailing blocks until they are outblock
+bytes long, otherwise trailing blocks may be short.
+.le
+.ls padchar = 0
+Single character used to pad blocks or records.
+Padchar is only requested if pad_record or pad_block
+is set. If padchar equals one of the digits 0 through nine, records and
+blocks are padded with the face value of the character, otherwise the
+ASCII value is used.
+.le
+.ls offset = 0
+The number which added to the tape file number is appended to \fIoutfiles\fR
+to produce the output file name. For example if file_list = "1-3", outfiles =
+"out" and offset = 100, the three files out101, out102, out103 would
+be produced rather than out001, out002 and out003.
+.le
+.ls verbose = yes
+Print messages about files, blocks copied etc.
+.le
+.ih
+DESCRIPTION
+REBLOCK is a procedure to copy disk or tape resident files to
+disk or tape. Multiple input tape or disk files may be specified.
+If multiple files are output to disk, and only one output file name is
+specified, the output file names will be
+generated by concatenating the tape file number (the input files are on tape)
+or a sequence number (the input files are on disk) onto the output file name.
+The user may request magnetic tape output to begin at a specific file on
+tape, e.g. mta1600[5] in which case file five will be overwritten if it
+exists, or at BOT or EOT. If no file number is specified REBLOCK asks
+whether the tape is new or old and begin writing at BOT or EOT as
+appropriate.
+
+Before beginning the copy, the user may request reblock to skip
+n (default 0) blocks (tape input) or logical records (disk input).
+The user can also specify that
+only n (default all) blocks (tape input) or records (disk input)
+are to be copied. Before the copy the data may be optionally word-swapped
+(default no) and/or byte-swapped (default no). If verbose is specified
+(default yes) reblock prints the input and output file names,
+the number of blocks read and written and the number of records read and
+written.
+
+Reblock
+uses the default buffer sizes supplied by mtio and file i/o to determine the
+maximum number of bytes which can be read in a single read call. For tapes
+this corresponds to the maximum number of bytes per block permitted by the
+device. Mtio will not read more than one block per read call. Therefore the
+actual number of bytes read will be less than or equal to the mtio buffer size.
+For disk files the default buffer size set by IRAF is a multiple of the
+disk block size. If the disk file is smaller than one block
+or the last block is partially full, the number of bytes read
+will be less than the default buffer size. All magtape and disk reads are
+done with the file i/o read procedure and a call to fstati determines the number
+of bytes actually read.
+
+If all the defaults are set, a binary copy is performed.
+In tape to tape copies the block and record sizes are preserved,
+but the density may
+be changed by specifying the appropriate output file name e.g. mta800 or
+mta1600.
+Reblocking occurs in tape to disk transfers, if records, are trimmed,
+padded or counted, or if blocks are padded.
+If a disk to tape transfer is requested
+the output block size will be the default file i/o buffer size.
+The last block in a file may be short. If uniform sized blocks are
+desired, pad_block must be set, in which case trailing partially filled
+blocks will be padded with padchar.
+
+Logical records are distinguished from blocks (physical records).
+The input and output record sizes default to
+the size of the input and output blocks respectively.
+Logical records may be shorter or longer than the block sizes.
+
+.ih
+EXAMPLES
+1. Copy a magnetic tape preserving the record sizes but changing
+the density from 800 bpi to 1600 bpi.
+
+.nf
+ cl> reblock mtb800 mta1600[1] 1-999
+.fi
+
+2. Reblock a magnetic tape changing the block size from 4000 bytes to 8000
+bytes and padding the last block.
+
+.nf
+ cl> reblock mtb1600 mta1600[1] 1-999 outb=8000 padb+
+.fi
+
+3. Copy a series of disk fits files to tape
+
+.nf
+ cl> reblock @fitsfiles mta[1] outb=28800
+.fi
+
+4. Trim the records of a disk file.
+
+.nf
+ cl> reblock infile outfile inrec=80 outrec=72
+.fi
+
+5. Pad the records of a disk file with blanks.
+
+.nf
+ cl> reblock input output inrec=81 outrec=82 padchar=" "
+.fi
+.ih
+SEE ALSO
+t2d
+.endhelp
diff --git a/pkg/dataio/doc/rfits.hlp b/pkg/dataio/doc/rfits.hlp
new file mode 100644
index 00000000..d28690c1
--- /dev/null
+++ b/pkg/dataio/doc/rfits.hlp
@@ -0,0 +1,228 @@
+.help rfits May97 dataio
+.ih
+NAME
+rfits -- convert image data in FITS files to individual IRAF images
+.ih
+USAGE
+rfits fits_file file_list iraf_file
+.ih
+PARAMETERS
+.ls fits_file
+The FITS data source. Fits_file is either a list of disk files or a tape
+device specification of the form mt[*][n], where mt is the mag tape
+device (e.g. mta), * is an optional density (e.g. 1600), and [n] is an
+optional tape file number. If n is specified then only image data in the
+nth tape file is read.
+.le
+.ls file_list
+The list of FITS extensions to be read from each disk file or from a single
+tape file, or the list of tape files AND FITS extensions to be read from
+an entire tape. FITS extensions are numbered from 0 to n, tape files are
+numbered from 1 to n. If file_list is "", only the 0th extension is read
+from each disk file or from a single tape file, but all the files and
+extensions are read from an entire tape. Legal file lists are composed
+of a series of file numbers and / or file ranges separated by commas
+or whitespace. For example the string
+
+ "1-3,4-8"
+
+will convert ALL the FITS extensions in files 1 through 8 on tape,
+but only FITS extensions 1 through 8 from a disk file or a single tape file.
+For the case of disk input, the same FITS extensions must be read from
+each input file. For the case of tape input the FITS extensions to be
+read from each file must be specified separately. For example the following
+string
+
+ "1-10[2-4],15-21[1-10]"
+
+tells rfits to convert extensions 2 through 4 in tape files 1 through 10
+and extensions 1 through 10 in tape files 15 through 21. Rfits will only
+convert extensions which contain image data. Other types of fits data
+such as tables will not be converted.
+.le
+.ls iraf_file
+The IRAF file which will receive the FITS image data if the make_image parameter
+switch is set. Iraf_file may be a template of output image names or
+a single root output image name. In the former case one output image name
+must be specified for every input file. In the latter case iraf_file is
+a root output image name to which the input file sequence number or tape
+file number is appended if the number of input files > 1. For example
+reading files 1 and 3 from a FITS tape with a value of iraf_file of "data"
+will produce the files data0001 and data0003, whereas reading the same
+two files with a value of iraf_file of "data1,data2" will produce the files
+data1 and data2. Extension numbers will be appended to the root output
+names if appropriate.
+.le
+.ls make_image = yes
+If make_images is "yes" convert the FITS image data to IRAF image data,
+otherwise simply print the header information using the long_header or
+short_header switches.
+.le
+.ls long_header = no
+If long_header is "yes" the full FITS header is printed on the standard output.
+.le
+.ls short_header = yes
+If short_header is "yes" and long_header is "no", only the output filename,
+the title string, and the image dimensions are printed on the standard output.
+.le
+.ls datatype
+The output image data type. Datatype may be s (short integer), i (integer),
+u (unsigned integer), l (long integer), r (real), or d (double). Data
+truncation may occur if an inappropriate data type is specified. If an
+unsupported data type or a null string is supplied then a default data
+type is selected based on the value of the fits bitpix, bscale, and bzero
+parameters. If the bscale and bzero parameters in the FITS header are
+undefined or equal to 1.0 and 0.0 respectively, rfits selects datatype
+s or l depending on bitpix. If bscale and bzero are set to 1.0 and 32768.0,
+rfits selects datatype, otherwise rfits selects datatype r.
+.le
+.ls blank = 0.
+The IRAF image value assigned to a FITS blank pixel.
+.le
+.ls scale = yes
+If scale is "no" then the data values are read directly from the FITS image
+without conversion. Otherwise rfits scales the data before output using
+the values of bscale and bzero.
+.le
+.ls oldirafname = no
+If the oldirafname switch is set rfits will attempt to restore the image to
+disk with the filename defined by the IRAFNAME parameter in the FITS header.
+.le
+.ls offset = 0
+An integer parameter specifying the offset to the current tape file
+number. For example if offset = 100, iraf_file = "fits" and file_list = "1-3"
+then the output file names will be "fits0101", "fits0102" and "fits0103"
+respectively rather than "fits0001", "fits0002" and "fits0003".
+.le
+.ih
+DESCRIPTION
+FITS data is read from the specified source; either disk or
+magnetic tape. The FITS header may optionally be printed on the standard
+output as either a full listing or a short description.
+The FITS long blocks option is supported.
+
+At present non-standard FITS files (SIMPLE = F) and files containing
+group data are skipped and a warning message is issued.
+Image stored in the FITS standard extension IMAGE can be read.
+Other standard extensions such as TABLE and BINTABLE are currently ignored.
+
+A warning message will be issued if the default user area allocated in
+memory is too small
+to hold all the FITS parameter cards being read in by RFITS.
+Since the default user area is 64000
+characters and a single card image is 81 characters long, the normal
+user area will hold ~800 complete card images. RFITS will not permit
+partial cards to be written. The user can override the default user area
+length by setting the environment variable min_lenuserarea (see example
+below).
+.ih
+EXAMPLES
+1. Convert all the image data on a mag tape to individual IRAF
+images. Allow rfits to select the output datatype and set blanks
+to zero.
+
+.nf
+ cl> rfits mtb1600 "" images
+
+ or alternatively
+
+ cl> rfits mtb1600 * images
+.fi
+
+2. Convert FITS files on disk to IRAF images. In the first example case the
+files specified by fits* are written to images images0001, images0002, etc.
+In the second example the fits disk files listed one per line in the text
+file fitslist are written to the output images listed one per line in
+the file imlist. Note that by using 0 or "" for the file_list parameter
+the user has told rfits to read only the primary fits data unit.
+
+.nf
+ cl> rfits fits* "" images
+
+ or alternatively
+
+ cl> rfits fits* 0 images
+
+
+ cl> rfits @fitslist "" @imlist
+
+ or alternatively
+
+ cl> rfits @fitslist 0 @imlist
+.fi
+
+3. List the contents of a FITS tape on the standard output without creating
+any image files.
+
+.nf
+ cl> rfits mtb1600 "" images ma-
+.fi
+
+4. Convert FITS files on tape directly to IRAF images without scaling.
+
+.nf
+ cl> rfits mtb1600 "" images scal-
+.fi
+
+5. Convert the first three FITS files on tape to IRAF image converting FITS
+blank values to -1 in the process. Note that the user will not get what
+he or she expects if the output data type is ushort.
+
+.nf
+ cl> rfits mta 1-3 images blank=-1
+.fi
+
+6. Read in a disk FITS file with a header roughly twice the usual IRAF length
+of 64000 characters.
+
+.nf
+ cl> set min_lenuserarea = 128000
+ cl> rfits fitsimage "" image
+.fi
+
+7. Read a FITS tape which has 5 normal fits records (2880 bytes) to a tape
+record. Notice that no hidden rfits parameters are required to do this.
+
+.nf
+ cl> rfits mta * images
+.fi
+
+8. Convert only the zeroth FITS extension in each of the first 100 files on a
+magnetic tape and try to restore the original IRAF image name in the process.
+
+.nf
+ cl> rfits mta 1-100[0] images old+
+.fi
+
+9. Convert the second, third, and fourth FITS extensions in the first 100
+files of a FITS tape and try to restore the original IRAF name in the process.
+
+.nf
+ cl> rfits mta "1-100[2-4]" images old+
+.fi
+
+10. Convert the second, third, and fourth FITS extensions in each of a list of
+disk files and restore the original IRAF name in the process.
+
+.nf
+ cl> rfits @fitslist "2-4" images old+
+.fi
+
+11. Convert the second, third, and fourth FITS extensions in the fifth
+mag tape file and try to restore the original IRAF name in the process.
+
+.nf
+ cl> rfits mta[5] "2-4" images old+
+.fi
+
+.ih
+BUGS
+Blank pixels are counted and set to a user determined value, but they are not
+records in the output image header.
+
+Rfits can read image data only. Other FITS data types such as ASCII and
+binary tables are skipped.
+.ih
+SEE ALSO
+wfits, reblock, t2d, fits kernel
+.endhelp
diff --git a/pkg/dataio/doc/rtextimage.hlp b/pkg/dataio/doc/rtextimage.hlp
new file mode 100644
index 00000000..f6b8f037
--- /dev/null
+++ b/pkg/dataio/doc/rtextimage.hlp
@@ -0,0 +1,84 @@
+.help rtextimage Oct93 dataio
+.ih
+NAME
+rtextimage -- convert a text file to an IRAF image
+.ih
+USAGE
+rtextimage input output
+.ih
+PARAMETERS
+.ls input
+A list of text files containing image pixels and optional header. Most likely
+the output from \fIrcardimage\fR, see examples below.
+.le
+.ls output
+The output IRAF image name. If more than one text file is being
+read, the ordinal of the text file in \fBinput\fR
+is appended to \fIoutput\fR to generate a unique image name.
+.le
+.ls otype = ""
+The data type of the output IRAF image pixels. If left unset and the IRAFTYPE
+keyword is found in the FITS header, output pixels will be of type IRAFTYPE.
+If IRAFTYPE appears more than once in the FITS header, the last value of
+IRAFTYPE is used. If left unset and the IRAFTYPE keyword is not provided in
+the FITS header, the output data type is determined from the pixels themselves.
+.le
+.ls header = yes
+If \fBheader\fR = yes, \fIrtextimage\fR will attempt to read a FITS
+header at the beginning of each text file.
+.le
+.ls pixels = yes
+Read the pixel values from the input text file. If no then the
+output image is initialized to zero pixel values.
+.le
+.ls nskip = 0
+The number of lines to skip before reading pixels. This is used to
+skip over a non-standard header and is important only when \fBheader\fR = no.
+.le
+.ls dim = ""
+A string listing the dimension of each axis. The number of dimensions listed
+equals the number of image dimensions. This information must be entered unless
+it can be read from a FITS header.
+.le
+.ih
+DESCRIPTION
+Text files are converted to IRAF images files with procedure
+\fBrtextimage\fR. The text file consists of an optional header optionally
+followed by the pixel values. If no pixel values are read the image is
+initialized to all zero pixel values. If pixel values a given they are
+read in FITS order, that is, the leftmost subscript varies most rapidly.
+The number of image dimensions and the length of each dimension must either
+be read from a FITS header or supplied by the user. Internally,
+\fBrtextimage\fR determines the format (integer or floating point) of the
+pixels in the text file by reading the first one and assuming all others
+are the same.
+.ih
+EXAMPLES
+1. Read a file written by \fIwtextimage\fR from the magtape file "mta[1]" into
+the IRAF image "picture".
+
+ cl> rcard mta[1] | rtext out=picture
+
+2. Read a series of text files with no headers preceding the pixels. The
+text files were previously read from tape with task \fBrcardimage\fR.
+The two dimensional images are 512 by 320 pixels, and will be named
+crab001, crab002, crab003, etc.
+
+ cl> rtext text.* crab header- dim=512,320
+
+
+3. Read a file with a non-standard header. The header is 5 cardimages long.
+
+ cl> rcard mta[5] | rtext out=spect.1 head- nskip=5 dim=1024
+.ih
+TIME REQUIREMENTS
+Task \fIrtextimage\fR requires about 145 cpu seconds to write a 512 square
+image (integer or real) from a text file.
+.ih
+BUGS
+The text file being read cannot have lines longer than SZ_LINE characters
+(see hlib$iraf.h).
+.ih
+SEE ALSO
+rcardimage, wtextimage
+.endhelp
diff --git a/pkg/dataio/doc/t2d.hlp b/pkg/dataio/doc/t2d.hlp
new file mode 100644
index 00000000..5d36334c
--- /dev/null
+++ b/pkg/dataio/doc/t2d.hlp
@@ -0,0 +1,70 @@
+.help t2d May89 dataio
+.ih
+NAME
+t2d -- copy files from tape to disk quickly
+.ih
+USAGE
+t2d input ofroot
+.ih
+PARAMETERS
+.ls input
+Tape file or device name, e.g. "mta1600[1]" or "mta"
+.le
+.ls files
+List of tape file numbers or ranges delimited by commas, e.g. "1-3,5-8".
+`Files' is requested only if no file number is given in `input'.
+Files will be read in ascending order, regardless of the order of the list.
+Reading will terminate if EOT is reached, thus a list such as "1-999"
+may be used to read all the files on the tape.
+.le
+.ls ofroot
+Root name to give output files. A three digit sequence number will be appended
+to this root name for each file written if a file list is used. If the file
+number is specifically given in the 'input' parameter, the output file will
+be named this root without an appended sequence number.
+.le
+.ls verbose = yes
+Flag to signal program that it should produce verbose output. This means
+progress reports.
+.le
+.ls errignore = yes
+Flag to signal program that tape records that give read errors should be
+considered to have zero length. If set to 'no', error records are considered
+to be the same length as all the other records on the tape.
+.le
+.ih
+DESCRIPTION
+T2d reads files from tape and puts them into disk files. No formatting is
+performed so the bits and bytes are in the same order on disk as they were
+on tape. The program uses double buffering and asynchronous i/o to speed
+things up as much as possible.
+
+When read errors are encountered one of two things can happen. Depending
+on the value of the parameter 'errignore', the error record is either
+thrown out or considered valid data. If 'errignore' is 'no' when an error
+is found, the input buffer is validated to the most recent 'good record'
+length and written to disk. If 'errignore' is 'yes' when an error is
+found, the input buffer is disposed of for that record.
+.ih
+EXAMPLES
+1. To read the second image from mta at 1600 bpi, store the image into
+"image" and see verbose output the command would be:
+
+.nf
+ cl> t2d mta1600[2] image
+.fi
+
+2. To read all the files on mtb at the default speed of 1600 bpi and put
+the disk files in root001, root002, root003, etc. and turn off verbose
+output, the command would be:
+
+.nf
+ cl> t2d mtb root v-
+.fi
+
+The program will prompt the user and ask for the list of files to be read
+to which the response would be "1-999".
+.ih
+SEE ALSO
+reblock
+.endhelp
diff --git a/pkg/dataio/doc/txtbin.hlp b/pkg/dataio/doc/txtbin.hlp
new file mode 100644
index 00000000..c519125f
--- /dev/null
+++ b/pkg/dataio/doc/txtbin.hlp
@@ -0,0 +1,28 @@
+.help txtbin Jun86 dataio
+.ih
+NAME
+txtbin -- convert text files to binary files
+.ih
+USAGE
+txtbin text_file binary_file
+.ih
+PARAMETERS
+.ls text_file
+Input file name or template, e.g. "abc" or "abc.*".
+.le
+.ls binary_file
+Output file name. If multiple input files the file_number will be
+added to the output file name.
+.le
+.ls verbose = "yes"
+Print messages about files processed?
+.le
+.ih
+EXAMPLES
+1. Convert a text file on disk to a binary file on disk.
+
+ cl> txtbin text_file binary_file
+.ih
+SEE ALSO
+bintxt
+.endhelp
diff --git a/pkg/dataio/doc/wcardimage.hlp b/pkg/dataio/doc/wcardimage.hlp
new file mode 100644
index 00000000..650f78ed
--- /dev/null
+++ b/pkg/dataio/doc/wcardimage.hlp
@@ -0,0 +1,74 @@
+.help wcardimage Jun86 dataio
+.ih
+NAME
+wcardimage -- convert IRAF text files to card image files
+.ih
+USAGE
+wcardimage infiles outfiles
+.ih
+PARAMETERS
+.ls textfile
+A character string identifying the file (s) on disk to be processed.
+The string acts as a "template" so that multiple files can be pro-
+cessed.
+.le
+.ls cardfile
+Name of the output tape device of the form "mta800" or "mta800[#]"
+or name of disk file (s). EOT and BOT are acceptable tape file numbers.
+The file number will be appended to
+the output file name in the case of multiple file disk output.
+.le
+.ls new_tape
+Specifies whether the output tape is blank or contains data.
+.le
+.ls contn_string = ">>"
+Character string which will be inserted at the beginning of
+card image lines which have been split from a single text line.
+.le
+.ls verbose = yes
+Print messages of actions performed?
+.le
+.ls detab = yes
+Remove tabs?
+.le
+.ls card_length = 80
+Number of columns per card.
+.le
+.ls cards_per_blk = 50
+Number of card images per physical record.
+.le
+.ls ebcdic = no
+Translate ascii characters to ebcdic?
+.le
+.ls ibm = no
+Translate ascii characters to ibm ebcdic?
+.le
+.ih
+DESCRIPTION
+If multiple file disk output is requested, ".crd" is appended to the input
+file name. Oversize lines are split and prefixed by the string ">>".
+.ih
+EXAMPLES
+1. Convert a set of IRAF text files to a set of blocked ASCII cardimage files
+on tape, replacing tabs with blanks and prefixing the leftover portions
+of oversize lines with ">>".
+
+.nf
+
+ cl> wcardimage files* mtb1600[1]
+.fi
+
+2. Convert a set of IRAF text files to a set of blocked EBCDIC cardimage files
+on tape, replacing tabs with blanks and prefixing the leftover portions
+of oversize lines with ">>".
+
+ cl> wcardimage files* mtb1600[1] eb+
+.ih
+BUGS
+The card_length in bytes must be an integral number of chars.
+At present WCARDIMAGE can only handle lines with less than or equal to
+161 characters.
+.ih
+SEE ALSO
+rcardimage
+.endhelp
diff --git a/pkg/dataio/doc/wfits.hlp b/pkg/dataio/doc/wfits.hlp
new file mode 100644
index 00000000..67d6f3c3
--- /dev/null
+++ b/pkg/dataio/doc/wfits.hlp
@@ -0,0 +1,237 @@
+.help wfits May97 dataio
+.ih
+NAME
+wfits -- convert individual IRAF image files to FITS image data
+.ih
+USAGE
+wfits iraf_files fits_files
+.ih
+PARAMETERS
+.ls iraf_files
+The input IRAF image file(s), e.g. "image.imh" or "*.imh".
+.le
+.ls fits_files
+The output FITS files.
+Magnetic tape output is assumed if the first two characters of fits_files
+are "mt", otherwise the disk output is assumed. Tape output will begin
+at the file number specified in fits_files, e.g. file 5 if fits_files =
+"mtb1600[5]", and the data in file 5 and succeeding files will be overwritten.
+If no tape file number is specified in fits_files, the newtape parameter
+is queried, and tape output will begin at BOT (beginning of tape) if
+newtape = yes, otherwise at EOT (end of tape, after the double EOF).
+Requesting a tape write at EOT on a blank tape may cause tape runaway.
+In the case of disk output, fits_files may be either a file name template
+or a root filename. In the former case there must be one output FITS file
+name for every input image. In the latter case fits_files is a root name
+and a sequence number will be appended to fits_files if the number of
+input images > 1.
+.le
+.ls newtape
+Boolean parameter specifying whether an output tape is blank or already
+contains data. Newtape is requested only if no tape file number is specified in
+fits_files, e.g. fits_files = "mtb1600".
+.le
+.ls bscale
+The FITS bscale parameter, defined as p = i * bscale + bzero, where
+p and i are the physical and tape data values respectively.
+The bscale parameter is only requested if the scale switch is on
+and the autoscale switch is off.
+.le
+.ls bzero
+The FITS bzero parameter (see bscale for a definition).
+Bzero is only requested if the scale switch is on and the autoscale
+switch is off.
+.le
+.ls fextn = "fits"
+The output fits file extension. If fextn is defined, an extension of
+the form ".fextn", e.g. ".fits" is added to the output fits file name.
+Fextn should be chosen to be compatible with one of the permitted fits
+kernel extensions.
+.le
+.ls extensions = no
+By default wfits writes each input image to a separate disk or tape FITS
+file. If \fIextensions\fR is "yes", then wfits will write all the images in
+the input image list to a single disk or tape FITS file using the FITS
+standard IMAGE extension to write images other than the first. Extension
+numbering is 0 indexed. The first image will be written to extension 1 if
+\fIglobal_header\fR is "yes", or to extension 0 if \fIglobal_hdr\fR is "no".
+.le
+.ls global_hdr = yes
+Write a short global header to the 0th extension of the output FITS file
+if \fIextensions\fR is "yes".
+.le
+.ls make_image = yes
+By default wfits writes the FITS image(s) to the output destination.
+If the make_image switch is turned off, wfits prints the FITS headers
+on the standard output and no output file is created. In this way the
+output FITS headers can be examined before actually writing a FITS tape.
+.le
+.ls long_header = no
+If this switch is set the full FITS header will be printed on the standard
+output for each IRAF image converted.
+.le
+.ls short_header = yes
+If this switch is set only a short header, listing the files processed and
+their dimensions will be printed on the standard output.
+The long_header switch must be turned off.
+.le
+.ls bitpix = 0
+A bitpix of 8, 16, or 32 will produce either an unsigned byte,
+twos-complement 16 bit integer, or twos-complement 32 bit integer FITS
+image. If bitpix is -32 or
+-64 IEEE real or double precision floating point FITS images are produced.
+If bitpix is set to 0 (the default), wfits will choose one of 8,
+16, 32, -32 or -64 based on the data type of the IRAF image.
+For example a short integer and real image will default to bitpix 16 and
+-32 respectively.
+Users should be wary or overriding the default value of bitpix as loss
+of precision in their data may result. In this case wfits will issue a
+warning message and an estimate of the maximum loss of precision to be
+expected.
+.le
+.ls blocking_factor = 0
+The tape blocking factor for FITS.
+Wfits normally writes \fIblocking_factor\fR * 2880 byte records,
+where \fIblocking_factor\fR is an integer from 1 to 10.
+If \fIblocking_factor\fR = 0, wfits uses the default FITS blocking
+factor specified for the device by the "fb" parameter in the
+file dev$tapecap, or 1 if the "fb" parameter is not present. For
+devices which support variable block sizes, e.g. 9-track tapes, exabytes
+and dats, "fb" is normally set to 10.
+The user may override this value by setting \fIblocking_factor\fR
+>= 1 or <= 10. If the device does not support variable block sizes, e.g.
+various types of cartridge drives, blocks of the size defined for the
+device by the "bs" parameter in the dev$tapecap file are written
+and \fIblocking_factor\fR is ignored.
+.le
+.ls scale = yes
+If the scale switch is set, the IRAF image will be scaled before output.
+Two types of scaling are available. The scaling parameters bscale and
+bzero may be entered by the user (autoscale = no), or the program can
+calculate the appropriate bscale and bzero factors (autoscale = yes).
+If the scale switch is turned off, the IRAF image data is converted
+directly to integers of the specified bitpix with possible loss of
+precision.
+.le
+.ls autoscale = yes
+If the autoscale switch is set, wfits calculates the appropriate bscale and
+bzero factors based on the IRAF image data type, and the maximum and minimum
+values of the data.
+.le
+.ih
+DESCRIPTION
+IRAF data is read from disk and written to the specified destination,
+either disk or magnetic tape. The FITS header may optionally be printed
+on the standard output as either a full listing or a short description,
+with or without creating an output image file. If a the default value
+of bitpix (default = 0) is entered, wfits will select the appropriate
+bitpix value based on the precision of the IRAF data. Otherwise the
+user value is used and loss of precision is possible. Two data scaling
+options are available. In autoscale mode wfits calculates the appropriate
+scaling factors based on the maximum and minimum data values in the
+IRAF image and the FITS bits per pixel. Alternatively the scaling factors
+can be entered directly. If no scaling is requested the IRAF data values
+will be converted directly to FITS integers or floating point values
+with possible loss of precision.
+.ih
+EXAMPLES
+1. Convert a list of IRAF image files to a list of FITS image files on a blank
+magnetic tape, allowing wfits to select the appropriate bitpix
+and scaling parameters.
+
+.nf
+ cl> wfits iraf_file* mtb1600[1]
+.fi
+
+2. Convert a list of IRAF image files to FITS image files on disk,
+allowing wfits to select the appropriate bitpix and scaling parameters.
+In the first example below the images specified by the template are written
+to files fits001, fits002, etc. In the second the list of input images
+specified one per line in the text file imlist are written to the
+files specified one per line in the text file fitslist.
+
+.nf
+ cl> wfits iraf_file* fits
+
+ cl> wfits @imlist @fitslist
+.fi
+
+3. Convert an IRAF image file to a 32 bits per pixel FITS file with no
+scaling and append to a tape already containing data.
+
+.nf
+ cl> wfits iraf_file mtb1600[EOT] bi=32 sc-
+.fi
+
+4. Convert an IRAF image to a 16 bit FITS image on disk, and specify
+bscale and bzero explicitly in the process.
+
+.nf
+ cl> wfits iraf_file fits_file bi=16 au- bs=4.0 bz=0.0
+.fi
+
+5. Print the FITS headers on the standard output.
+
+.nf
+ cl> wfits iraf_file* ma-
+.fi
+
+6. Create a disk file called headers containing the FITS headers for a list
+of IRAF image files.
+
+.nf
+ cl> wfits iraf_file* ma- > headers
+.fi
+
+7. Write a FITS tape with 14400 bytes per record (5 2880 FITS records per
+tape block) on a 9-track tape.
+
+.nf
+ cl> wfits images* mtb[1] block=5
+.fi
+
+8. Write a FITS Exabyte tape with a blocking factor of 1 (1 2880 FITS record
+per block). Note that wfits will normally by default write a 28000 (
+10 2880 FITS logical records per block) byte record.
+
+.nf
+ cl> wfits images* mtb[1] block=1
+.fi
+
+9. Write a list of images to a single tape file using the FITS standard
+extension IMAGE. Users who are planning on reading their data with
+local FITS readers should check that those local readers support the
+FITS IMAGE extension before selecting this option.
+
+.nf
+ cl> wfits *.imh mtb[1] block=1 extensions+
+.fi
+
+10. Repeat the previous example but do not write a global header.
+
+.nf
+ cl> wfits *.imh mtb[1] block=1 extensions+ global-
+.fi
+
+.ih
+BUGS
+WFITS does not attempt to recover from write errors. When an error is
+detected, WFITS issues an error message and attempts to write a double
+EOF at the end of the last good record. In this case the last file on
+the tape will be a partial file. IF WFITS is not successful in writing
+the double EOF, the message "Cannot close magtape file (name)" will be
+issued. Problems occur as some drives permit the double EOF to be
+written after the physical end of tape and some do not. Similarly
+some drives can read a double EOF after end of tape and some cannot. Depending
+on operating system and device driver, an attempt to read or write past
+end of tape may or may not be distinguishable from a normal write error.
+
+Blank pixel values are not correctly handled.
+
+Attempting to write at EOT on a blank tape will at best result in numerous
+error messages being issued and at worst result in tape runaway depending
+on the driver.
+.ih
+SEE ALSO
+rfits, reblock, fits kernel
+.endhelp
diff --git a/pkg/dataio/doc/wtextimage.hlp b/pkg/dataio/doc/wtextimage.hlp
new file mode 100644
index 00000000..6dd67ff8
--- /dev/null
+++ b/pkg/dataio/doc/wtextimage.hlp
@@ -0,0 +1,100 @@
+.help wtextimage Oct93 dataio
+.ih
+NAME
+wtextimage -- convert an IRAF image to a text file
+.ih
+USAGE
+wtextimage input output
+.ih
+PARAMETERS
+.ls input
+An IRAF image file name or template of file names to be converted.
+.le
+.ls output
+Name or root_name of output text file. If more than one IRAF image
+is being converted, the ordinal of the file in the input file list
+is appended to \fIoutput\fR to generate a unique output file name.
+.le
+.ls header = yes
+This parameter determines whether or not a descriptive header precedes
+the pixels written to the text file. When \fIheader = no\fR, only
+pixels values are converted; no header information is included in the
+output.
+.le
+.ls pixels = yes
+This parameter determines whether or not to write the pixels to the
+text file. This can be set to no to only write out the header.
+.le
+.ls format = ""
+Output format for each pixel. If not set by the user, the appropriate output
+pixel format is determined by the image data type.
+Acceptable formats are chosen from "W.D[defgz]" where w is the field width and
+d specifies the precision. Fortran formats of the form [iefgz]W.D are also
+acceptable. If a field width of 0 is specified, (e.g., 0.6g),
+output will be free format with each output line containing as many pixels as
+will fit on the line. This is the most space efficient format but requires
+that the reader program be able to handle free format (list directed) input.
+.le
+.ls maxlinelen = 80
+The maximum number of characters output per line of text; \fBmaxlinelen\fR
+must not exceed 322 characters. (Note that tasks \fIrtextimage\fR and
+\fIwcardimage\fR cannot read lines of text greater than 161 characters.)
+.le
+.ih
+DESCRIPTION
+IRAF images are converted to text files with procedure \fBwtextimage\fR.
+The text file written consists of an optional header optionally followed by
+the pixel values. The pixels are output in FITS order, that is, the
+leftmost subscript varies most rapidly. The image header is written in the
+"keyword = value / comment" format of FITS.
+.ih
+EXAMPLES
+1. Write a text file from an image section of dev$pix. The default maximum
+linelength of 80 is used; an output format is specified. The header portion
+of the output text is as follows:
+.ls
+.nf
+BITPIX = 8 / 8-bit ASCII characters
+NAXIS = 2 / Number of Image Dimensions
+NAXIS1 = 10 / Length of axis
+NAXIS2 = 10 / Length of axis
+ORIGIN = 'NOAO-IRAF: WTEXTIMAGE' /
+IRAF-MAX= 31431. / Max image pixel (out of date)
+IRAF-MIN= 33. / Min image pixel (out of date)
+IRAF-B/P= 16 / Image bits per pixel
+IRAFTYPE= 'SHORT INTEGER ' / Image datatype
+OBJECT = 'NGC 4147 B 1800 ' /
+FILENAME= 'DEV$PIX[1:10,1:10]' / IRAF filename
+FORMAT = '11I7 ' / Text line format
+DATA-TYP= ' object ( 0 )' / object,dark,comp,etc.
+ITIME = 1800 / integration time secs
+UT = '11:23:13' / universal time
+ZD = '24: 5: 0' / zenith distance
+DATE-OBS= '15/02/1985' / dd/mm/yy observation
+ST = '13:38:31' / sidereal time
+RA = '12: 9:20' / right ascension
+DEC = '18:35:35' / declination
+EPOCH = .0 / epoch of RA and DEC
+CAM-TEMP= -104.95 / camera temperature, deg C
+DEW-TEMP= -192.96 / dewar temp, deg C
+HISTORY1= 'bt= 590 bp= 0 cr= 0 dk= 0 '
+HISTORY2= 'ff= 55 fg= 0 sc= .000 bi= 51 '
+COMMENT = 'ngc 4147 b 1800'
+F1POS = 2 / filter bolt I position
+F2POS = 0 / filter bolt II position
+END
+.fi
+.le
+
+2. Write a series of text files from the IRAF images having root name
+"reduced". One text file is written for each image.
+
+ cl> wtext reduced.* txt
+.ih
+TIME REQUIREMENTS
+It takes almost 10 cpu minutes to convert a 512 square image of real pixels.
+A 512 square image of integer pixels takes about 3 cpu minutes.
+.ih
+SEE ALSO
+wcardimage, rtextimage, noao.onedspec.wspectext
+.endhelp
diff --git a/pkg/dataio/export.par b/pkg/dataio/export.par
new file mode 100644
index 00000000..d39690f2
--- /dev/null
+++ b/pkg/dataio/export.par
@@ -0,0 +1,13 @@
+# EXPORT Task Parameter File
+images,s,a,"",,,"The list of input iraf images"
+binfiles,s,a,"",,,"The list of output binary files"
+format,s,a,"raw",,,"The type of binary file to write { raw|list|<format> }"
+header,s,h,"yes",,,"Prepend a header describing how the data are stored?"
+outtype,s,h,"",,,"Output pixel type"
+outbands,s,h,"",,,"Output expressions"
+interleave,i,h,0,,,"Pixel interleave type"
+bswap,s,h,"no",,,"Type of byte-swapping to perform on output"
+verbose,b,h,no,,,"Verbose output during conversion?"
+
+# Mode parameter
+mode,s,h,"ql",,,"mode parameter"
diff --git a/pkg/dataio/export/Notes b/pkg/dataio/export/Notes
new file mode 100644
index 00000000..5e60b65a
--- /dev/null
+++ b/pkg/dataio/export/Notes
@@ -0,0 +1,37 @@
+Things to Do:
+-------------
+
+ Help Page:
+done - examples showing image operand usage
+done - examples of zscale/grey/bscale/gamma funcs in complex exprs
+
+done - clean up output header description
+done - verbose is used as terminal output and raw header flag - change
+done - define 'composite' in interleave description
+ - format=raw for >3-D images, more detail
+done? - clean up description of image list handling for large groups of
+ images - perhaps multiple params for operands
+done - format should be a query param
+??? - should 'outbands' be 'outexpr'
+??? - should there be an 'append' param to append existing files
+done - what happens if 3-D image passes in for builtin conversion
+done - Dave's typos/comments
+ - note that grouping exprs in function may affect the number of
+ perceived expressions, e.g. "psdpi ( (b1, b2, b3), 150.0)"
+done - add block() function to help page
+done - add setcmap() function - this is what's currently defined as the
+ setlut() function.
+??? - Clear up confusion about LUT and colormaps in the help page
+
+ Source:
+done - block() function fills full height of expression, not just that
+ height specified
+done - remove constraint on image sizes all being equal
+done - @param and tag.param operators need to be implemented
+done - text output still needs work
+done - remove xvv_initop() calls - interface violation
+done - finish header output
+done - is zscale() mapping the pixels NOT in the range 0-255 for gif???
+done - need to implement XWD
+ - need to patch xwd expr for RGB to add alpha channel
+ - optimize image reads from 3D images
diff --git a/pkg/dataio/export/bltins/exeps.x b/pkg/dataio/export/bltins/exeps.x
new file mode 100644
index 00000000..b7189896
--- /dev/null
+++ b/pkg/dataio/export/bltins/exeps.x
@@ -0,0 +1,537 @@
+include <evvexpr.h>
+include <imhdr.h>
+include <mach.h>
+include <fset.h>
+include "../export.h"
+include "../exbltins.h"
+
+
+define SZ_EPSSTRUCT 5
+define EPS_ITEMSPERLINE Memi[$1] # no. of items per line
+define EPS_HPTR Memi[$1+1] # ptr to hex digit string
+define EPS_BPTR Memi[$1+2] # ptr to output buffer
+define EPS_BCNT Memi[$1+3] # index into output buffer
+define HEXSTR Memc[EPS_HPTR($1)+$2]
+define BUF Memc[EPS_BPTR($1)+$2-1]
+
+define LINEWID 36 # hexstr pixels per line
+define HEXITS "0123456789abcdef" # hex digits
+define MARGIN 0.95 # defaults for 300 dpi
+define PAGEWID 612
+define PAGEHGT 762
+define SZ_EPSBUF 8192
+define SZ_TRAILER 31
+
+
+# EX_EPS - Write the output image to an Encasulated PostScript file.
+
+procedure ex_eps (ex)
+
+pointer ex #i task struct pointer
+
+pointer eps
+pointer bptr
+int fd, len, flags
+
+int strlen()
+bool streq()
+
+begin
+ # Check to see that we have the correct number of expressions to
+ # write this format.
+ flags = EX_OUTFLAGS(ex)
+ if ((EX_NEXPR(ex) != 1 && !bitset(flags, OF_BAND)) && EX_NEXPR(ex) != 3)
+ call error (7, "Invalid number of expressions for EPS file.")
+
+ # Set some of the output parameters.
+ call ex_do_outtype (ex, "b1")
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), OF_FLIPY)
+
+ # Allocate the EPS structure.
+ iferr (call calloc (eps, SZ_EPSSTRUCT, TY_STRUCT))
+ call error (0, "Error allocating eps structure.")
+ call calloc (EPS_HPTR(eps), 17, TY_CHAR)
+ call calloc (EPS_BPTR(eps), SZ_EPSBUF+SZ_TRAILER, TY_CHAR)
+ call strcpy (HEXITS, Memc[EPS_HPTR(eps)], 17)
+ EPS_BCNT(eps) = 1
+
+ # Now write out the header and image data.
+ fd = EX_FD(ex)
+ call fseti (fd, F_ADVICE, SEQUENTIAL)
+ if (bitset (flags, OF_CMAP)) {
+ if (streq (CMAPFILE(ex),"grayscale") ||
+ streq (CMAPFILE(ex),"greyscale")) {
+ call eps_header (ex, eps, NO)
+ call eps_gray (ex, eps, fd, false, true)
+ } else {
+ call eps_header (ex, eps, YES)
+ call eps_gray (ex, eps, fd, true, false)
+ }
+
+ } else if (EX_NEXPR(ex) == 1 || bitset (flags, OF_BAND)) {
+ call eps_header (ex, eps, NO)
+ call eps_gray (ex, eps, fd, false, false)
+
+ } else if (EX_NEXPR(ex) == 3) {
+ call eps_header (ex, eps, YES)
+ call eps_rgb (ex, eps, fd)
+ }
+
+ # Flush the remaining pixels in the buffer.
+ call calloc (bptr, SZ_EPSBUF, TY_CHAR)
+
+ if (mod (EPS_BCNT(eps),2) == 0) {
+ call amovc ("\ngrestore showpage\n%%Trailer\n\0",
+ BUF(eps,EPS_BCNT(eps)), SZ_TRAILER)
+ } else {
+ call amovc ("\ngrestore showpage\n%%Trailer\n",
+ BUF(eps,EPS_BCNT(eps)), SZ_TRAILER)
+ }
+ len = strlen (BUF(eps,1))
+ call strpak (BUF(eps,1), Memc[bptr], len)
+ call write (fd, Memc[bptr], len / SZB_CHAR)
+ call flush (fd)
+
+ # Write the EPS trailer and clean up the pointers.
+ call mfree (EPS_HPTR(eps), TY_CHAR)
+ call mfree (EPS_BPTR(eps), TY_CHAR)
+ call mfree (eps, TY_STRUCT)
+ call mfree (bptr, TY_CHAR)
+end
+
+
+# EPS_GRAY - Write a grayscale EPS file.
+
+procedure eps_gray (ex, eps, fd, use_cmap, is_gray)
+
+pointer ex #i task struct pointer
+pointer eps #i postscript struct pointer
+int fd #i output file descriptor
+bool use_cmap #i write a false color image?
+bool is_gray #i is this a grayscale cmap?
+
+pointer op, bop, out, cm
+int i, j, k, line, percent
+int len, orow, type
+
+pointer ex_evaluate(), ex_chtype()
+
+begin
+ # Now process the expressions and write the image.
+ type = EX_OUTTYPE(ex)
+ percent = 0
+ orow = 0
+ cm = EX_CMAP(ex)
+ call malloc (out, EX_OCOLS(ex)+2, TY_SHORT)
+ do i = 1, EX_NEXPR(ex) {
+
+ # Process each line in the image.
+ do j = 1, O_HEIGHT(ex,i) {
+
+ # See if we're flipping the image.
+ if (bitset (EX_OUTFLAGS(ex), OF_FLIPY))
+ line = EX_NLINES(ex) - j + 1
+ else
+ line = j
+
+ # Get pixels from image(s).
+ call ex_getpix (ex, line)
+
+ # Evaluate expression.
+ op = ex_evaluate (ex, O_EXPR(ex,i))
+
+ # Convert to the output pixel type.
+ bop = ex_chtype (ex, op, type)
+
+ # Write evaluated pixels.
+ call achtbs (Memc[bop], Mems[out], O_LEN(op))
+ len = O_LEN(op) - 1
+ if (is_gray) {
+ # Write a single color index as the grayscale value.
+ do k = 0, len
+ call eps_putval (eps, fd, CMAP(cm,EX_RED,Mems[out+k]+1))
+ } else if (use_cmap) {
+ # Write index values as RGB triplets.
+ do k = 0, len {
+ call eps_putval (eps, fd,
+ CMAP(cm,EX_RED, Mems[out+k]+1))
+ call eps_putval (eps, fd,
+ CMAP(cm,EX_GREEN,Mems[out+k]+1))
+ call eps_putval (eps, fd,
+ CMAP(cm,EX_BLUE, Mems[out+k]+1))
+ }
+ } else {
+ do k = 0, len
+ call eps_putval (eps, fd, Mems[out+k])
+ }
+
+ # Clean up the pointers.
+ call mfree (bop, TY_CHAR)
+ call evvfree (op)
+
+ # Print percent done if being verbose
+ orow = orow + 1
+ #if (EX_VERBOSE(ex) == YES)
+ call ex_pstat (ex, orow, percent)
+ }
+ }
+ call mfree (out, TY_SHORT)
+end
+
+
+# EPS_RGB - Write a RGB true color EPS file.
+
+procedure eps_rgb (ex, eps, fd)
+
+pointer ex #i task struct pointer
+pointer eps #i postscript struct pointer
+int fd #i output file descriptor
+
+pointer op, bop, out
+int i, j, k, line, percent, orow, type
+
+pointer ex_evaluate(), ex_chtype()
+
+begin
+ # Now process the expressions and write the image.
+ type = EX_OUTTYPE(ex)
+ percent = 0
+ orow = 0
+ call malloc (out, EX_OCOLS(ex)+2, TY_SHORT)
+ do j = 1, EX_NLINES(ex) {
+
+ # See if we're flipping the image.
+ if (bitset (EX_OUTFLAGS(ex), OF_FLIPY))
+ line = EX_NLINES(ex) - j + 1
+ else
+ line = j
+
+ # Get pixels from image(s).
+ call ex_getpix (ex, line)
+
+ # Process each line in the image.
+ do i = 1, EX_NEXPR(ex) {
+
+ # Evaluate expression.
+ op = ex_evaluate (ex, O_EXPR(ex,i))
+
+ # Convert to the output pixel type.
+ bop = ex_chtype (ex, op, type)
+
+ # Write evaluated pixels.
+ call achtbs (Memc[bop], Mems[out], O_LEN(op))
+ do k = 1, O_LEN(op)
+ call eps_putval (eps, fd, Mems[out+k-1])
+
+ # Clean up the pointers.
+ call mfree (bop, TY_CHAR)
+ call evvfree (op)
+ }
+
+ # Print percent done if being verbose
+ orow = orow + 1
+ #if (EX_VERBOSE(ex) == YES)
+ call ex_pstat (ex, orow, percent)
+ }
+ call mfree (out, TY_SHORT)
+end
+
+
+# EPS_HEADER - Write the EPS header block.
+
+procedure eps_header (ex, eps, color)
+
+pointer ex #i task struct pointer
+pointer eps #i EPS struct pointer
+int color #i is this a color image?
+
+int bp, fd, cols, rows, dpi, len
+int icols, irows, devpix, turnflag
+real scale, pixfac, scols, srows, llx, lly
+
+int strlen(), stropen()
+
+begin
+ fd = EX_FD(ex)
+ turnflag = NO
+ dpi = EX_PSDPI(ex)
+ scale = EX_PSSCALE(ex)
+ cols = EX_OCOLS(ex)
+ rows = EX_OROWS(ex)
+
+ # Open the buffer as a string file and print to it.
+ bp = stropen (BUF(eps,1), SZ_EPSBUF, TEXT_FILE)
+
+ # See if we need to rotate the image to fit on the page.
+ icols = cols
+ irows = rows
+ if (cols > rows && (scale * cols) > int (PAGEWID * MARGIN)) {
+ turnflag = YES
+ cols = irows
+ rows = icols
+ }
+
+ # Figure out size.
+ devpix = dpi / 72.0 + 0.5 # device pixels per unit, approx
+ pixfac = 72.0 / dpi * devpix # 1, approx.
+ scols = scale * cols * pixfac
+ srows = scale * rows * pixfac
+
+ if ( scols > PAGEWID * MARGIN || srows > PAGEHGT * MARGIN ) {
+ if ( scols > PAGEWID * MARGIN ) {
+ scale = scale * PAGEWID / scols * MARGIN
+ scols = scale * cols * pixfac
+ srows = scale * rows * pixfac
+ }
+ if ( srows > PAGEHGT * MARGIN ) {
+ scale = scale * PAGEHGT / srows * MARGIN
+ scols = scale * cols * pixfac
+ srows = scale * rows * pixfac
+ }
+ if (EX_VERBOSE(ex) == YES) {
+ call printf ("\tImage too large for page, rescaled to %g\n")
+ call pargr (scale)
+ call flush (STDOUT)
+ }
+ }
+
+ # Center it on the page.
+ llx = (PAGEWID - scols) / 2
+ lly = (PAGEHGT - srows) / 2
+
+ call fprintf (bp, "%%!PS-Adobe-2.0 EPSF-2.0\n")
+ call fprintf (bp, "%%%%Creator: IRAF EXPORT task\n")
+ call fprintf (bp, "%%%%Title: %s\n")
+ call pargstr (BFNAME(ex))
+ call fprintf (bp, "%%%%Pages: 1\n")
+ call fprintf (bp, "%%%%BoundingBox: %d %d %d %d\n")
+ call pargi (int (llx + 0.5))
+ call pargi (int (lly + 0.5))
+ call pargi (int (llx + scols))
+ call pargi (int (lly + srows))
+ call fprintf (bp, "%%%%EndComments\n")
+
+ call fprintf (bp, "/readstring {\n") # s -- s
+ call fprintf (bp, " currentfile exch readhexstring pop\n")
+ call fprintf (bp, "} bind def\n")
+
+ if (color == YES && !bitset (EX_OUTFLAGS(ex),OF_CMAP)) {
+ call eps_defcol (bp, icols)
+
+ call fprintf (bp, "/rpicstr %d string def\n")
+ call pargi (icols)
+ call fprintf (bp, "/gpicstr %d string def\n")
+ call pargi (icols)
+ call fprintf (bp, "/bpicstr %d string def\n")
+ call pargi (icols)
+
+ } else if (color == YES && bitset (EX_OUTFLAGS(ex),OF_CMAP)) {
+ call eps_defcol (bp, icols)
+
+ } else {
+ call fprintf (bp, "/picstr %d string def\n")
+ call pargi (icols)
+ }
+
+ call fprintf (bp, "%%%%EndProlog\n")
+ call fprintf (bp, "%%%%Page: 1 1\n")
+ call fprintf (bp, "gsave\n")
+ call fprintf (bp, "%g %g translate\n")
+ call pargr (llx)
+ call pargr (lly)
+ call fprintf (bp, "%g %g scale\n")
+ call pargr (scols)
+ call pargr (srows)
+
+ if (turnflag == YES) {
+ call fprintf (bp,
+ "0.5 0.5 translate 90 rotate -0.5 -0.5 translate\n")
+ }
+
+ call fprintf (bp, "%d %d 8\n")
+ call pargi (icols)
+ call pargi (irows)
+ call fprintf (bp, "[ %d 0 0 -%d 0 %d ]\n")
+ call pargi (icols)
+ call pargi (irows)
+ call pargi (irows)
+ if (color == YES) {
+ if (bitset (EX_OUTFLAGS(ex), OF_CMAP)) {
+ call fprintf (bp, "{currentfile pix readhexstring pop}\n")
+ call fprintf (bp, "false 3 colorimage")
+ } else {
+ call fprintf (bp, "{ rpicstr readstring }\n")
+ call fprintf (bp, "{ gpicstr readstring }\n")
+ call fprintf (bp, "{ bpicstr readstring }\n")
+ call fprintf (bp, "true 3 colorimage")
+ }
+ } else {
+ call fprintf (bp, "{ picstr readstring }\n")
+ call fprintf (bp, "image")
+ }
+ call flush (bp)
+ call strclose (bp)
+
+ # See if we need to pad the string to write it out correctly.
+ len = strlen(BUF(eps,1))
+ if (mod(len,2) == 1) {
+ BUF(eps,len+1) = '\n'
+ } else {
+ BUF(eps,len+1) = ' '
+ BUF(eps,len+2) = '\n'
+ }
+
+ # Now write the contents of the string buffer to the output file.
+ len = strlen(BUF(eps,1))
+ call strpak (BUF(eps,1), BUF(eps,1), len)
+ call write (fd, BUF(eps,1), len / SZB_CHAR)
+ call aclrc (BUF(eps,1), SZ_EPSBUF)
+ EPS_ITEMSPERLINE(eps) = 0
+end
+
+
+# EPS_DEFCOL - Write out code that checks if the PostScript device in question
+# knows about the 'colorimage' operator. If it doesn't, it defines
+# 'colorimage' in terms of image (ie, generates a greyscale image from
+# RGB data).
+
+procedure eps_defcol (fd, len)
+
+int fd #i output file descriptor
+int len #i length of a scanline
+
+begin
+ call fprintf (fd, "%% build a temporary dictionary\n")
+ call fprintf (fd, "20 dict begin\n\n")
+ call fprintf (fd,
+ "%% define string to hold a scanline's worth of data\n")
+ call fprintf (fd, "/pix %d string def\n\n")
+ call pargi (len)
+
+ call fprintf (fd, "\n")
+ call fprintf (fd, "%% define 'colorimage' if it isn't defined\n")
+ call fprintf (fd,
+ "/colorimage where %% do we know about 'colorimage'?\n")
+ call fprintf (fd,
+ " { pop } %% yes: pop off the 'dict' returned\n")
+ call fprintf (fd, " { %% no: define one\n")
+ call fprintf (fd, " /colortogray { %% define an RGB->I function\n")
+ call fprintf (fd,
+ " /rgbdata exch store %% call input 'rgbdata'\n")
+ call fprintf (fd, " rgbdata length 3 idiv\n")
+ call fprintf (fd, " /npixls exch store\n")
+ call fprintf (fd, " /rgbindx 0 store\n")
+ call fprintf (fd,
+ " /grays npixls string store %% str to hold the result\n")
+ call fprintf (fd, " 0 1 npixls 1 sub {\n")
+ call fprintf (fd, " grays exch\n")
+ call fprintf (fd,
+ " rgbdata rgbindx get 20 mul %% Red\n")
+ call fprintf (fd,
+ " rgbdata rgbindx 1 add get 32 mul %% Green\n")
+ call fprintf (fd,
+ " rgbdata rgbindx 2 add get 12 mul %% Blue\n")
+ call fprintf (fd,
+ " add add 64 idiv %% I = .5G + .31R + .18B\n")
+ call fprintf (fd, " put\n")
+ call fprintf (fd, " /rgbindx rgbindx 3 add store\n")
+ call fprintf (fd, " } for\n")
+ call fprintf (fd, " grays\n")
+ call fprintf (fd, " } bind def\n\n")
+
+ call fprintf (fd, " %% Utility procedure for colorimage operator.\n")
+ call fprintf (fd,
+ " %% This procedure takes two procedures off the\n")
+ call fprintf (fd,
+ " %% stack and merges them into a single procedure.\n\n")
+
+ call fprintf (fd, " /mergeprocs { %% def\n")
+ call fprintf (fd, " dup length\n")
+ call fprintf (fd, " 3 -1 roll\n")
+ call fprintf (fd, " dup\n")
+ call fprintf (fd, " length\n")
+ call fprintf (fd, " dup\n")
+ call fprintf (fd, " 5 1 roll\n")
+ call fprintf (fd, " 3 -1 roll\n")
+ call fprintf (fd, " add\n")
+ call fprintf (fd, " array cvx\n")
+ call fprintf (fd, " dup\n")
+ call fprintf (fd, " 3 -1 roll\n")
+ call fprintf (fd, " 0 exch\n")
+ call fprintf (fd, " putinterval\n")
+ call fprintf (fd, " dup\n")
+ call fprintf (fd, " 4 2 roll\n")
+ call fprintf (fd, " putinterval\n")
+ call fprintf (fd, " } bind def\n\n")
+
+ call fprintf (fd, " /colorimage { %% def\n")
+ call fprintf (fd, " pop pop %% remove 'false 3' operands\n")
+ call fprintf (fd, " {colortogray} mergeprocs\n")
+ call fprintf (fd, " image\n")
+ call fprintf (fd, " } bind def\n")
+ call fprintf (fd, " } ifelse %% end of 'false' case\n")
+ call fprintf (fd, "\n\n")
+ call flush (fd)
+end
+
+
+# EPS_PUTVAL - Put a pixel value to the output file.
+
+procedure eps_putval (eps, fd, sval)
+
+pointer eps #i EPS struct pointer
+int fd #i output file descriptor
+short sval #i value to write
+
+int val, index
+char ch, nl, sp
+int shifti()
+
+begin
+ # Force value to 8-bit range.
+ #val = max (0, min (255, sval))
+ val = sval
+
+ if (EPS_ITEMSPERLINE(eps) >= LINEWID) {
+ sp = ' '
+ call eps_putc (eps, fd, sp)
+ nl = '\n'
+ call eps_putc (eps, fd, nl)
+ EPS_ITEMSPERLINE(eps) = 0
+ }
+
+ # Get the hex string equivalent of the byte.
+ index = shifti (val, -4) # get left 4 bits
+ ch = HEXSTR(eps,index)
+ call eps_putc (eps, fd, ch)
+
+ index = and (val, 0FX) # get right 4 bits
+ ch = HEXSTR(eps,index)
+ call eps_putc (eps, fd, ch)
+
+ EPS_ITEMSPERLINE(eps) = EPS_ITEMSPERLINE(eps) + 1
+end
+
+
+# EPS_PUTC - Put a character to the buffer. This routine also flushes the
+# accumulated buffer to disk once it fills.
+
+procedure eps_putc (eps, fd, ch)
+
+pointer eps #i EPS struct pointer
+int fd #i file descriptor
+char ch #i character to 'write'
+
+begin
+ BUF(eps,EPS_BCNT(eps)) = ch
+ EPS_BCNT(eps) = EPS_BCNT(eps) + 1
+
+ # If we're getting close to a full buffer, write it out.
+ # Leave some space at the end for the epilogue.
+ if (EPS_BCNT(eps) > SZ_EPSBUF-64) {
+ call strpak (BUF(eps,1), BUF(eps,1), EPS_BCNT(eps))
+ call write (fd, BUF(eps,1), EPS_BCNT(eps) / SZB_CHAR)
+ #call aclrc (BUF(eps,1), SZ_EPSBUF)
+ EPS_BCNT(eps) = 1
+ }
+end
diff --git a/pkg/dataio/export/bltins/exgif.x b/pkg/dataio/export/bltins/exgif.x
new file mode 100644
index 00000000..462b70e4
--- /dev/null
+++ b/pkg/dataio/export/bltins/exgif.x
@@ -0,0 +1,557 @@
+include <mach.h>
+include <fset.h>
+include <evvexpr.h>
+include "../export.h"
+include "../exbltins.h"
+
+
+define SZ_GIFSTRUCT 30
+
+define GIF_INIT_BITS Memi[$1] # initial number of bits
+define GIF_MAXCODE Memi[$1+1] # max output code
+define GIF_FREE_ENT Memi[$1+2] # first unused entry
+define GIF_OFFSET Memi[$1+3] # offset into output buffer
+define GIF_IN_COUNT Memi[$1+4] # length of input
+define GIF_CUR_BITS Memi[$1+5] # current no. bits in code
+define GIF_N_BITS Memi[$1+6] # no. of max bits
+define GIF_CUR_ACCUM Memi[$1+7] # current accumulator
+define GIF_A_COUNT Memi[$1+8] # no. of chars in 'packet'
+define GIF_CLEAR_CODE Memi[$1+9] # clear hash table code
+define GIF_EOF_CODE Memi[$1+10] # EOF code
+define GIF_CLEAR_FLAG Memi[$1+11] # hash table has been cleared?
+define GIF_CURX Memi[$1+12] # current 'x' position in image
+define GIF_CURY Memi[$1+13] # current 'y' position in image
+define GIF_PASS Memi[$1+14] # interlacing pass number
+define GIF_WIDTH Memi[$1+15] # width of output image
+define GIF_HEIGHT Memi[$1+16] # height of output image
+define GIF_EXPNUM Memi[$1+17] # expression we're evaluating
+define GIF_LNUM Memi[$1+18] # line w/in that expression
+define GIF_NPIX Memi[$1+19] # no. of pixels to process
+define GIF_PERCENT Memi[$1+20] # percent of file completed
+
+define GIF_CDPTR Memi[$1+25] # compressed data (ptr)
+define GIF_HPTR Memi[$1+26] # hash table (ptr)
+define GIF_APTR Memi[$1+27] # packet accumulator (ptr)
+define GIF_DPTR Memi[$1+28] # expression data (ptr)
+define GIF_CPTR Memi[$1+29] # code table (ptr)
+
+define ACCUM Mems[GIF_APTR($1)+$2]
+define HTAB Memi[GIF_HPTR($1)+$2]
+define CODETAB Memi[GIF_CPTR($1)+$2]
+define DATA Mems[GIF_DPTR($1)+$2-1]
+define CDATA Mems[GIF_CDPTR($1)+$2]
+
+define HSIZE 5003 # 80% occupancy
+define USE_INTERLACE true # Write interlaced GIF files?
+
+#----------------------------------------------------------------------------
+define INTERLACE 040X # Image descriptor flags
+define GLOBAL_COLORMAP 080X
+define LOCAL_COLORMAP 080X # (currently unused)
+
+# Define the flags for the GIF89a extension blocks (currently unused).
+define GE_PLAINTEXT 001X # Plain Text Extension
+define GE_APPLICATION 0FFX # Application Extension
+define GE_COMMENT 0FEX # Comment Extension
+define GE_GCONTROL 0F9X # Graphics Control Extension
+
+
+# EX_GIF - Write the output image to a GIF 87a file.
+
+procedure ex_gif (ex)
+
+pointer ex #i task struct pointer
+
+pointer gif
+int nbytes, flags
+
+char ch[2]
+int or()
+
+begin
+ # Check to see that we have the correct number of expressions to
+ # write this format.
+ flags = EX_OUTFLAGS(ex)
+ if (EX_NEXPR(ex) != 1 && !bitset(flags, OF_BAND))
+ call error (7, "Invalid number of expressions for GIF file.")
+ if (bitset(flags, OF_LINE) || bitset (flags, LINE_STORAGE))
+ call error (7, "Line storage illegal for GIF file.")
+
+ # Fix the output pixel type to single bytes.
+ call ex_do_outtype (ex, "b1")
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), OF_FLIPY)
+
+ # Allocate the gif structure.
+ iferr {
+ call calloc (gif, SZ_GIFSTRUCT, TY_STRUCT)
+ call calloc (GIF_APTR(gif), 257, TY_SHORT)
+ call calloc (GIF_HPTR(gif), HSIZE, TY_INT)
+ call calloc (GIF_CPTR(gif), HSIZE, TY_INT)
+ call calloc (GIF_DPTR(gif), max(256,EX_OCOLS(ex)), TY_SHORT)
+ call calloc (GIF_CDPTR(gif), (2*EX_OROWS(ex)*EX_OCOLS(ex)),TY_SHORT)
+ } then
+ call error (0, "Error allocating gif structure.")
+
+ GIF_WIDTH(gif) = EX_OCOLS(ex)
+ GIF_HEIGHT(gif) = EX_OROWS(ex)
+ GIF_NPIX(gif) = EX_OROWS(ex) * EX_OCOLS(ex)
+ GIF_CURX(gif) = 1
+ GIF_CURY(gif) = 0
+ GIF_PASS(gif) = 1
+ GIF_EXPNUM(gif) = EX_NEXPR(ex)
+ GIF_LNUM(gif) = GIF_HEIGHT(gif)
+
+ # Write the header information.
+ call gif_wheader (ex, EX_FD(ex))
+
+ # Start processing the expressions and write compressed image data.
+ call gif_compress (ex, gif, EX_FD(ex))
+
+ # Write the GIF file terminator and dump the whole thing to disk.
+ if (mod(GIF_OFFSET(gif),2) == 1) {
+ CDATA(gif,GIF_OFFSET(gif)) = '\0'
+ GIF_OFFSET(gif) = GIF_OFFSET(gif) + 1
+ ch[1] = ';'
+ ch[2] = ';'
+ nbytes = (GIF_OFFSET(gif) + 1) / SZB_CHAR
+ } else {
+ ch[1] = '\0'
+ ch[2] = ';'
+ nbytes = GIF_OFFSET(gif) / SZB_CHAR
+ }
+ call achtsb (CDATA(gif,0), CDATA(gif,0), GIF_OFFSET(gif))
+ call write (EX_FD(ex), CDATA(gif,0), nbytes)
+ call achtsb (ch, ch, 2)
+ call write (EX_FD(ex), ch, 1)
+
+ # Clean up the pointers.
+ call mfree (GIF_APTR(gif), TY_SHORT)
+ call mfree (GIF_DPTR(gif), TY_SHORT)
+ call mfree (GIF_CDPTR(gif), TY_SHORT)
+ call mfree (GIF_HPTR(gif), TY_INT)
+ call mfree (GIF_CPTR(gif), TY_INT)
+ call mfree (gif, TY_STRUCT)
+end
+
+
+# GIF_WHEADER - Write the GIF header information. This covers not only the
+# global file header but all the preliminary stuff up until the actual image
+# data
+
+procedure gif_wheader (ex, fd)
+
+pointer ex #i tast struct pointer
+int fd #i output file descriptor
+
+char sig[7] # GIF signature
+char lsd[772] # Screen and Color Map information
+short SWidth, SHeight # Screen width and height
+
+short stmp
+int i, j
+
+int shifti(), ori()
+
+define GIF_SIGNATURE "GIF87a"
+
+begin
+ fd = EX_FD(ex)
+
+ # Write the GIF signature. This is technically the "header", following
+ # this are the scene/color/image descriptors.
+ call strcpy (GIF_SIGNATURE, sig, 7)
+ call strpak (sig, sig, 7)
+ call write (fd, sig, 7/SZB_CHAR)
+
+ # Logical Screen Descriptor.
+ SWidth = EX_OCOLS(ex)
+ SHeight = EX_OROWS(ex)
+ call gif_putword (fd, SWidth)
+ call gif_putword (fd, SHeight)
+
+ # Set the 'packed' flags and write it out
+ i = 0
+ i = ori (i, GLOBAL_COLORMAP) # indicate a colormap
+ i = ori (i, (shifti(7, 4))) # color resolution
+ i = ori (i, (8-1)) # bits per pixel
+ lsd[1] = i # packed flags
+ lsd[2] = 0 # background color
+ lsd[3] = 0 # aspect ratio
+ lsd[4] = 0 # filler expansion byte
+
+ # Write out the colormap.
+ if (EX_CMAP(ex) != NULL) {
+ j = 1
+ for (i=4 ; i <= 772; i=i+3) {
+ lsd[i ] = CMAP(EX_CMAP(ex), EX_RED, j)
+ lsd[i+1] = CMAP(EX_CMAP(ex), EX_GREEN, j)
+ lsd[i+2] = CMAP(EX_CMAP(ex), EX_BLUE, j)
+ j = j + 1
+ }
+ } else {
+ j = 0
+ for (i=4 ; i <= 772; i=i+3) {
+ lsd[i ] = j
+ lsd[i+1] = j
+ lsd[i+2] = j
+ j = j + 1
+ }
+ }
+ lsd[772] = ','
+ call achtcb (lsd, lsd, 772)
+ call write (fd, lsd, 772/SZB_CHAR)
+
+ # Write the image header.
+ stmp = 0
+ call gif_putword (fd, stmp)
+ call gif_putword (fd, stmp)
+ call gif_putword (fd, SWidth)
+ call gif_putword (fd, SHeight)
+
+ # Next set the interlace flag and the initial code size in the next
+ # two bytes.
+ if (USE_INTERLACE)
+ stmp = ori (shifti(INTERLACE,8), 8)
+ else
+ stmp = 8
+ if (BYTE_SWAP2 == YES)
+ call bswap2 (stmp, 1, stmp, 1, 2)
+ call write (fd, stmp, 1)
+end
+
+
+# GIF_COMPRESS - Compress the image data using a modified LZW.
+
+procedure gif_compress (ex, gif, fd)
+
+pointer ex #i tast struct pointer
+pointer gif #i gif struct pointer
+int fd #i output file descriptor
+
+long fcode
+int i, c, ent, disp
+int hsize_reg, hshift
+
+short gif_next_pixel()
+int xori(), shifti()
+
+define probe_ 99
+define nomatch_ 98
+
+begin
+ GIF_INIT_BITS(gif) = 9 # initialize
+ GIF_N_BITS(gif) = 9
+ GIF_OFFSET(gif) = 0
+ GIF_CLEAR_FLAG(gif) = NO
+ GIF_IN_COUNT(gif) = 1
+ GIF_MAXCODE(gif) = 511
+ GIF_CLEAR_CODE(gif) = 256
+ GIF_EOF_CODE(gif) = GIF_CLEAR_CODE(gif) + 1
+ GIF_FREE_ENT(gif) = GIF_CLEAR_CODE(gif) + 2
+ GIF_A_COUNT(gif) = 0
+
+ ent = gif_next_pixel (ex, gif)
+ hshift = 0
+ for (fcode = HSIZE; fcode < 65536 ; fcode = fcode * 2)
+ hshift = hshift + 1
+ hshift = 8-hshift # set hash code range bound
+
+ hsize_reg = HSIZE # clear the hash table
+ call amovki (-1, HTAB(gif,0), HSIZE)
+
+ call gif_output (fd, gif, GIF_CLEAR_CODE(gif))
+
+ # Now loop over the pixels.
+ repeat {
+ c = gif_next_pixel (ex, gif)
+ if (c == EOF)
+ break
+ GIF_IN_COUNT(gif) = GIF_IN_COUNT(gif) + 1
+
+ fcode = shifti (c, 12) + ent
+ i = xori (shifti (c, hshift), ent)
+
+ if (HTAB(gif,i) == fcode) {
+ ent = CODETAB(gif,i)
+ next
+ } else if (HTAB(gif,i) < 0) # empty slot
+ goto nomatch_
+ disp = hsize_reg - i # secondary hash (after G. Knott)
+ if (i == 0)
+ disp = 1
+
+probe_ i = i - disp
+ if (i < 0)
+ i = i + hsize_reg
+
+ if (HTAB(gif,i) == fcode) {
+ ent = CODETAB(gif,i)
+ next
+ }
+ if (HTAB(gif,i) >= 0)
+ goto probe_
+
+nomatch_ call gif_output (fd, gif, ent)
+ ent = c
+ if (GIF_FREE_ENT(gif) < 4096) {
+ CODETAB(gif,i) = GIF_FREE_ENT(gif)
+ GIF_FREE_ENT(gif) = GIF_FREE_ENT(gif) + 1
+ HTAB(gif,i) = fcode
+ } else {
+ # Clear out the hash table.
+ call amovki (-1, HTAB(gif,0), HSIZE)
+ GIF_FREE_ENT(gif) = GIF_CLEAR_CODE(gif) + 2
+ GIF_CLEAR_FLAG(gif) = YES
+ call gif_output (fd, gif, GIF_CLEAR_CODE(gif))
+ }
+ }
+
+ # Write out the final code.
+ call gif_output (fd, gif, ent)
+ call gif_output (fd, gif, GIF_EOF_CODE(gif))
+end
+
+
+# GIF_NEXT_PIXEL - Writes a 16-bit integer in GIF order (LSB first).
+
+short procedure gif_next_pixel (ex, gif)
+
+pointer ex #i tast struct pointer
+pointer gif #i gif struct pointer
+
+short pix
+pointer op, out
+pointer ex_chtype(), ex_evaluate()
+
+begin
+ if (GIF_NPIX(gif) == 0)
+ return (EOF)
+
+ # If the current X position is at the start of a line get the new
+ # data, otherwise just return what we already know.
+ pix = 1
+ if (GIF_CURX(gif) == 1) {
+ call ex_getpix (ex, GIF_LNUM(gif))
+ op = ex_evaluate (ex, O_EXPR(ex,GIF_EXPNUM(gif)))
+ out = ex_chtype (ex, op, TY_UBYTE)
+ call aclrs (DATA(gif,1), O_LEN(op))
+ call achtbu (Memc[out], DATA(gif,1), O_LEN(op))
+ call mfree (out, TY_CHAR)
+ call evvfree (op)
+ }
+ pix = DATA(gif,GIF_CURX(gif))
+
+ # Increment the position.
+ if (GIF_CURY(gif) == EX_OROWS(ex)) {
+ GIF_CURX(gif) = min (EX_OCOLS(ex), GIF_CURX(gif) + 1)
+ } else
+ call gif_bump_pixel (ex, gif)
+
+ GIF_NPIX(gif) = GIF_NPIX(gif) - 1
+ return (pix)
+end
+
+
+# GIF_BUMP_PIXEL - Update the current x and y values for interlacing.
+
+procedure gif_bump_pixel (ex, gif)
+
+pointer ex #i tast struct pointer
+pointer gif #i gif struct pointer
+
+int i, row, sum
+
+begin
+ GIF_CURX(gif) = GIF_CURX(gif) + 1
+
+ # If we are at the end of a scan line, set curx back to the beginning
+ # Since we are interlaced, bump the cury to the appropriate spot.
+
+ if (GIF_CURX(gif) > GIF_WIDTH(gif)) {
+ GIF_CURX(gif) = 1
+
+ if (USE_INTERLACE) {
+ switch (GIF_PASS(gif)) {
+ case 1:
+ GIF_CURY(gif) = GIF_CURY(gif) + 8
+ if (GIF_CURY(gif) >= GIF_HEIGHT(gif)) {
+ GIF_PASS(gif) = GIF_PASS(gif) + 1
+ GIF_CURY(gif) = 4
+ }
+ case 2:
+ GIF_CURY(gif) = GIF_CURY(gif) + 8
+ if (GIF_CURY(gif) >= GIF_HEIGHT(gif)) {
+ GIF_PASS(gif) = GIF_PASS(gif) + 1
+ GIF_CURY(gif) = 2
+ }
+ case 3:
+ GIF_CURY(gif) = GIF_CURY(gif) + 4
+ if (GIF_CURY(gif) >= GIF_HEIGHT(gif)) {
+ GIF_PASS(gif) = GIF_PASS(gif) + 1
+ GIF_CURY(gif) = 1
+ }
+ case 4:
+ GIF_CURY(gif) = GIF_CURY(gif) + 2
+ if (GIF_CURY(gif) >= GIF_HEIGHT(gif)) {
+ GIF_EXPNUM(gif) = EX_NEXPR(ex)
+ GIF_LNUM(gif) = EX_OROWS(ex)
+ GIF_CURY(gif) = GIF_HEIGHT(gif)
+ return
+ }
+ }
+
+ # Now figure out where we are in the expressions.
+ i = EX_NEXPR(ex)
+ sum = GIF_HEIGHT(gif)
+ while (sum >= GIF_CURY(gif)) {
+ sum = sum - O_HEIGHT(ex,i)
+ i = i - 1
+ }
+ GIF_EXPNUM(gif) = i + 1
+ GIF_LNUM(gif) = (sum + O_HEIGHT(ex,i+1)) - GIF_CURY(gif) + 1
+
+ row = ((EX_OROWS(ex) * EX_OCOLS(ex)) - GIF_NPIX(gif)) /
+ EX_OCOLS(ex)
+ #if (EX_VERBOSE(ex) == YES)
+ call ex_pstat (ex, row, GIF_PERCENT(gif))
+
+ } else {
+ GIF_CURY(gif) = GIF_CURY(gif) + 1
+
+ # Now figure out where we are in the expressions.
+ i = EX_NEXPR(ex)
+ sum = GIF_HEIGHT(gif)
+ while (sum >= GIF_CURY(gif)) {
+ sum = sum - O_HEIGHT(ex,i)
+ i = i - 1
+ }
+
+ if ((i+1) == GIF_EXPNUM(gif)) {
+ GIF_LNUM(gif) = GIF_LNUM(gif) - 1
+ } else {
+ GIF_EXPNUM(gif) = i + 1
+ GIF_LNUM(gif) = O_HEIGHT(ex,i+1)
+ }
+
+ #if (EX_VERBOSE(ex) == YES)
+ call ex_pstat (ex, GIF_CURY(gif), GIF_PERCENT(gif))
+ }
+ }
+end
+
+
+# GIF_OUTPUT - Output the given code.
+
+procedure gif_output (fd, gif, code)
+
+int fd #i output file descriptor
+pointer gif #i gif struct pointer
+int code #i code to output
+
+long masks[17]
+int i
+
+int ori(), andi(), shifti()
+
+data (masks(i), i=1,5) /00000X, 00001X, 00003X, 00007X, 0000FX/
+data (masks(i), i=6,9) /0001FX, 0003FX, 0007FX, 000FFX/
+data (masks(i), i=10,13) /001FFX, 003FFX, 007FFX, 00FFFX/
+data (masks(i), i=14,17) /01FFFX, 03FFFX, 07FFFX, 0FFFFX/
+
+begin
+ GIF_CUR_ACCUM(gif) = andi(GIF_CUR_ACCUM(gif),masks[GIF_CUR_BITS(gif)+1])
+
+ if (GIF_CUR_BITS(gif) > 0)
+ GIF_CUR_ACCUM(gif) = ori (GIF_CUR_ACCUM(gif),
+ shifti (code, GIF_CUR_BITS(gif)))
+ else
+ GIF_CUR_ACCUM(gif) = code
+ GIF_CUR_BITS(gif) = GIF_CUR_BITS(gif) + GIF_N_BITS(gif)
+
+ while (GIF_CUR_BITS(gif) >= 8) {
+ call char_out (fd, gif, andi (GIF_CUR_ACCUM(gif), 0FFX))
+ GIF_CUR_ACCUM(gif) = shifti (GIF_CUR_ACCUM(gif), -8)
+ GIF_CUR_BITS(gif) = GIF_CUR_BITS(gif) - 8
+ }
+
+ # If the next entry is going to be too big for the code size then
+ # increase it if possible.
+ if (GIF_FREE_ENT(gif) > GIF_MAXCODE(gif) || GIF_CLEAR_FLAG(gif)==YES) {
+ if (GIF_CLEAR_FLAG(gif) == YES) {
+ GIF_MAXCODE(gif) = 511
+ GIF_N_BITS(gif) = 9
+ GIF_CLEAR_FLAG(gif) = NO
+ } else {
+ GIF_N_BITS(gif) = GIF_N_BITS(gif) + 1
+ if (GIF_N_BITS(gif) == 12)
+ GIF_MAXCODE(gif) = 4096
+ else
+ GIF_MAXCODE(gif) = shifti (1, GIF_N_BITS(gif)) - 1
+ }
+ }
+
+ if (code == GIF_EOF_CODE(gif)) {
+ # At EOF, write the rest of the buffer.
+ while (GIF_CUR_BITS(gif) >= 8) {
+ call char_out (fd, gif, andi (GIF_CUR_ACCUM(gif), 0FFX))
+ GIF_CUR_ACCUM(gif) = shifti (GIF_CUR_ACCUM(gif), -8)
+ GIF_CUR_BITS(gif) = GIF_CUR_BITS(gif) - 8
+ }
+
+ call flush_char (gif)
+ call flush (fd)
+ }
+end
+
+
+# GIF_PUTWORD - Writes a 16-bit integer in GIF order (LSB first).
+
+procedure gif_putword (fd, w)
+
+int fd
+short w
+
+short val
+int tmp, shifti()
+
+begin
+ # If this is a MSB-first machine swap the bytes before output.
+ if (BYTE_SWAP2 == NO) {
+ call bitpak (int(w), tmp, 9, 8)
+ call bitpak (shifti(int(w),-8), tmp, 1, 8)
+ val = tmp
+ } else
+ val = w
+
+ call write (fd, val, SZ_SHORT/SZ_CHAR)
+end
+
+
+procedure char_out (fd, gif, c)
+
+int fd #i output file descriptor
+pointer gif #i gif struct pointer
+int c #i char to output
+
+begin
+ ACCUM(gif,GIF_A_COUNT(gif)) = c
+ GIF_A_COUNT(gif) = GIF_A_COUNT(gif) + 1
+ if (GIF_A_COUNT(gif) >= 254)
+ call flush_char (gif)
+end
+
+
+procedure flush_char (gif)
+
+pointer gif #i gif struct pointer
+
+begin
+ if (GIF_A_COUNT(gif) > 0) {
+ CDATA(gif,GIF_OFFSET(gif)) = GIF_A_COUNT(gif)
+ GIF_OFFSET(gif) = GIF_OFFSET(gif) + 1
+ call amovs (ACCUM(gif,0), CDATA(gif,GIF_OFFSET(gif)),
+ GIF_A_COUNT(gif))
+ GIF_OFFSET(gif) = GIF_OFFSET(gif) + GIF_A_COUNT(gif)
+ GIF_A_COUNT(gif) = 0
+ }
+end
diff --git a/pkg/dataio/export/bltins/exiraf.x b/pkg/dataio/export/bltins/exiraf.x
new file mode 100644
index 00000000..282cf383
--- /dev/null
+++ b/pkg/dataio/export/bltins/exiraf.x
@@ -0,0 +1,110 @@
+include <imhdr.h>
+include <mach.h>
+include <evvexpr.h>
+include "../export.h"
+
+
+# EX_IRAF - Write the evaluated expressions back out as an IRAF image.
+
+procedure ex_iraf (ex)
+
+pointer ex #i task struct pointer
+
+pointer sp, imname
+pointer im, op, out
+int i, j, flags
+int line, percent, orow, type
+
+pointer ex_evaluate(), ex_chtype()
+pointer immap()
+pointer impl2s(), impl2i(), impl2l(), impl2r(), impl2d()
+int fnroot()
+
+errchk immap
+
+begin
+ # Check to see that we have the correct number of expressions.
+ flags = EX_OUTFLAGS(ex)
+ if (EX_NEXPR(ex) != 1 && !bitset(flags, OF_BAND))
+ call error (7, "Invalid number of expressions for IRAF image.")
+ if (bitset(flags, OF_LINE) || bitset (flags, LINE_STORAGE))
+ call error (7, "Line storage illegal for IRAF image.")
+ if (EX_OUTTYPE(ex) == TY_UBYTE)
+ call ex_do_outtype (ex, "u2")
+
+ call smark (sp)
+ call salloc (imname, SZ_FNAME, TY_CHAR)
+ call aclrc (Memc[imname], SZ_FNAME)
+
+ # Since we're writing an image, close the output file descriptor
+ # and instead use an image pointer.
+ call close (EX_FD(ex))
+ call delete (BFNAME(ex))
+ EX_FD(ex) = NULL
+
+ # Generate the image name and map it for processing.
+ if (fnroot (BFNAME(ex), Memc[imname], SZ_FNAME) == 0)
+ call error (0, "Error making image name.")
+ iferr (im = immap (Memc[imname], NEW_IMAGE, 0))
+ call error (0, "Error mapping output image.")
+
+ # Set the minimal header values.
+ IM_LEN(im,1) = EX_OCOLS(ex)
+ IM_LEN(im,2) = EX_OROWS(ex)
+ IM_NDIM(im) = 2
+ IM_PIXTYPE(im) = EX_OUTTYPE(ex)
+
+ # Finally, evaluate the expressions and write the image.
+ type = EX_OUTTYPE(ex)
+ percent = 0
+ orow = 1
+ do i = 1, EX_NEXPR(ex) {
+
+ # Process each line in the image.
+ do j = 1, O_HEIGHT(ex,i) {
+
+ # See if we're flipping the image.
+ if (bitset (EX_OUTFLAGS(ex), OF_FLIPY))
+ line = EX_NLINES(ex) - j + 1
+ else
+ line = j
+
+ # Get pixels from image(s).
+ call ex_getpix (ex, line)
+
+ # Evaluate expression.
+ op = ex_evaluate (ex, O_EXPR(ex,i))
+
+ # Convert to the output pixel type.
+ out = ex_chtype (ex, op, type)
+
+ # Write evaluated pixels.
+ switch (type) {
+ case TY_USHORT, TY_SHORT:
+ call amovs (Mems[out], Mems[impl2s(im,orow)], O_LEN(op))
+ case TY_INT:
+ call amovi (Memi[out], Memi[impl2i(im,orow)], O_LEN(op))
+ case TY_LONG:
+ call amovl (Meml[out], Meml[impl2l(im,orow)], O_LEN(op))
+ case TY_REAL:
+ call amovr (Memr[out], Memr[impl2r(im,orow)], O_LEN(op))
+ case TY_DOUBLE:
+ call amovd (Memd[out], Memd[impl2d(im,orow)], O_LEN(op))
+ default:
+ call error (0, "Illegal output image type.")
+ }
+
+ # Clean up the pointers.
+ call mfree (out, type)
+ call evvfree (op)
+
+ # Print percent done if being verbose
+ orow = orow + 1
+ #if (EX_VERBOSE(ex) == YES)
+ call ex_pstat (ex, orow, percent)
+ }
+ }
+
+ call imunmap (im)
+ call sfree (sp)
+end
diff --git a/pkg/dataio/export/bltins/exmiff.x b/pkg/dataio/export/bltins/exmiff.x
new file mode 100644
index 00000000..9e5756e5
--- /dev/null
+++ b/pkg/dataio/export/bltins/exmiff.x
@@ -0,0 +1,81 @@
+include <mach.h>
+include "../export.h"
+
+
+# EX_MIFF - Write the evaluated expressions as an ImageMagick MIFF format file.
+
+procedure ex_miff (ex)
+
+pointer ex #i task struct pointer
+
+pointer sp, hdr, cmap
+int i, j, flags
+char ncols[6]
+
+int strlen()
+
+begin
+ # Check to see that we have the correct number of expressions to
+ # write this format.
+ flags = EX_OUTFLAGS(ex)
+ if (EX_NEXPR(ex) != 3 && EX_NEXPR(ex) != 1)
+ call error (7, "Invalid number of expressions for MIFF file.")
+ if (bitset(flags, OF_LINE) || bitset (flags, LINE_STORAGE))
+ call error (7, "Line storage illegal for MIFF file.")
+
+ # Write the header to the file.
+ call smark (sp)
+ call salloc (hdr, SZ_COMMAND, TY_CHAR)
+ call aclrc (Memc[hdr], SZ_COMMAND)
+
+ call sprintf (ncols, 6, "%d")
+ call pargi (EX_NCOLORS(ex))
+ call sprintf (Memc[hdr], SZ_COMMAND,
+ "{\nCreated by IRAF EXPORT Task\n}\nid=ImageMagick\nclass=%s %s%s\ncolumns=%-5d rows=%-5d\n\f\n:\n")
+
+ if (EX_NEXPR(ex) == 3) {
+ call pargstr ("DirectClass")
+ call pargstr ("")
+ call pargstr ("")
+ } else {
+ call pargstr ("PseudoClass")
+ if (bitset (flags,OF_CMAP)) {
+ call pargstr ("colors=")
+ call pargstr (ncols)
+ } else {
+ call pargstr ("")
+ call pargstr ("")
+ }
+ }
+ call pargi (EX_OCOLS(ex))
+ call pargi (EX_OROWS(ex))
+
+ if (mod(strlen(Memc[hdr]),2) == 1)
+ call strcat ("\n", Memc[hdr], SZ_COMMAND)
+ call strpak (Memc[hdr], Memc[hdr], SZ_COMMAND)
+ call write (EX_FD(ex), Memc[hdr], strlen(Memc[hdr])/SZB_CHAR)
+
+ # Finally, evaluate the expressions and write the image.
+ call ex_do_outtype (ex, "b1")
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), OF_FLIPY)
+
+ if (bitset (flags,OF_CMAP)) {
+ # Write out the colormap.
+ call salloc (cmap, 3*CMAP_SIZE, TY_CHAR)
+ j = 1
+ do i = 0, (3*CMAP_SIZE-1), 3 {
+ Memc[cmap+i+0] = CMAP(EX_CMAP(ex), EX_RED, j)
+ Memc[cmap+i+1] = CMAP(EX_CMAP(ex), EX_GREEN, j)
+ Memc[cmap+i+2] = CMAP(EX_CMAP(ex), EX_BLUE, j)
+ j = j + 1
+ }
+ call achtcb (Memc[cmap], Memc[cmap], (3 * CMAP_SIZE))
+ call write (EX_FD(ex), Memc[cmap], ((3 * CMAP_SIZE) / SZB_CHAR))
+
+ call ex_no_interleave (ex) # write the pixels
+
+ } else
+ call ex_px_interleave (ex)
+
+ call sfree (sp)
+end
diff --git a/pkg/dataio/export/bltins/expgm.x b/pkg/dataio/export/bltins/expgm.x
new file mode 100644
index 00000000..c8a7a1d7
--- /dev/null
+++ b/pkg/dataio/export/bltins/expgm.x
@@ -0,0 +1,47 @@
+include <mach.h>
+include "../export.h"
+
+
+# EX_PGM - Write the evaluated expressions as a PGM format file.
+
+procedure ex_pgm (ex)
+
+pointer ex #i task struct pointer
+
+pointer sp, hdr
+int len, flags
+
+int strlen()
+
+begin
+ # Check to see that we have the correct number of expressions to
+ # write this format.
+ flags = EX_OUTFLAGS(ex)
+ if (EX_NEXPR(ex) != 1 && !bitset(flags, OF_BAND))
+ call error (7, "Invalid number of expressions for PGM file.")
+ if (bitset(flags, OF_LINE) || bitset (flags, LINE_STORAGE))
+ call error (7, "Line storage illegal for PGM file.")
+
+ # Write the header to the file.
+ call smark (sp)
+ call salloc (hdr, SZ_LINE, TY_CHAR)
+ call aclrc (Memc[hdr], SZ_LINE)
+
+ call sprintf (Memc[hdr], SZ_LINE, "P5\n%-6d %-6d\n255\n")
+ call pargi (EX_OCOLS(ex) - mod (EX_OCOLS(ex),2))
+ call pargi (EX_OROWS(ex))
+ len = strlen (Memc[hdr])
+ call strpak (Memc[hdr], Memc[hdr], SZ_LINE)
+ call write (EX_FD(ex), Memc[hdr], len/SZB_CHAR)
+ call sfree (sp)
+
+ # Fix the output pixel type to single bytes.
+ call ex_do_outtype (ex, "b1")
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), OF_FLIPY)
+
+ # Finally, evaluate the expressions and write the image.
+ if (EX_NEXPR(ex) == 1 || bitset (flags, OF_BAND))
+ call ex_no_interleave (ex)
+ else
+ call error (7, "Shouldn't be here.")
+end
diff --git a/pkg/dataio/export/bltins/exppm.x b/pkg/dataio/export/bltins/exppm.x
new file mode 100644
index 00000000..4dab4727
--- /dev/null
+++ b/pkg/dataio/export/bltins/exppm.x
@@ -0,0 +1,49 @@
+include <mach.h>
+include "../export.h"
+
+
+# EX_PPM - Write the evaluated expressions as a PPM format file.
+
+procedure ex_ppm (ex)
+
+pointer ex #i task struct pointer
+
+pointer sp, hdr
+int len, flags
+
+int strlen()
+
+begin
+ # Check to see that we have the correct number of expressions to
+ # write this format.
+ flags = EX_OUTFLAGS(ex)
+ if (EX_NEXPR(ex) != 3)
+ call error (7, "Invalid number of expressions for PPM file.")
+ if (bitset(flags, OF_LINE) || bitset (flags, LINE_STORAGE))
+ call error (7, "Line storage illegal for PPM file.")
+
+ # Write the header to the file.
+ call smark (sp)
+ call salloc (hdr, SZ_LINE, TY_CHAR)
+ call aclrc (Memc[hdr], SZ_LINE)
+
+ # If we have an odd number of pixels we can't correctly write the
+ # last column to the file, so truncate the column in the output image.
+ if (mod (EX_NCOLS(ex),2) == 1)
+ EX_OCOLS(ex) = EX_OCOLS(ex) - 1
+
+ call sprintf (Memc[hdr], SZ_LINE, "P6\n%-6d %-6d\n255\n")
+ call pargi (EX_OCOLS(ex))
+ call pargi (EX_OROWS(ex))
+ len = strlen (Memc[hdr])
+ call strpak (Memc[hdr], Memc[hdr], SZ_LINE)
+ call write (EX_FD(ex), Memc[hdr], len/SZB_CHAR)
+ call sfree (sp)
+
+ # Fix the output pixel type to single bytes.
+ call ex_do_outtype (ex, "b1")
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), OF_FLIPY)
+
+ # Finally, evaluate the expressions and write the image.
+ call ex_px_interleave (ex)
+end
diff --git a/pkg/dataio/export/bltins/exras.x b/pkg/dataio/export/bltins/exras.x
new file mode 100644
index 00000000..f24209c6
--- /dev/null
+++ b/pkg/dataio/export/bltins/exras.x
@@ -0,0 +1,117 @@
+include <mach.h>
+include "../export.h"
+
+
+# EXRAS.X - Source file for the EXPORT task rasterfile builtin format.
+
+define SZ_RASHDR 8
+define RAS_MAGIC 1 # Magic number
+define RAS_WIDTH 2 # Image width (pixels per line)
+define RAS_HEIGHT 3 # Image height (number of lines)
+define RAS_DEPTH 4 # Image depth (bits per pixel)
+define RAS_LENGTH 5 # Image length (bytes)
+define RAS_TYPE 6 # File type
+define RAS_MAPTYPE 7 # Colormap type
+define RAS_MAPLENGTH 8 # Colormap length (bytes)
+
+# Rasterfile magic number
+define RAS_MAGIC_NUM 59A66A95X
+define RAS_RLE 80X
+
+# Sun supported ras_types
+define RT_OLD 0 # Raw pixrect image in 68000 byte order
+define RT_STANDARD 1 # Raw pixrect image in 68000 byte order
+define RT_BYTE_ENCODED 2 # Run-length compression of bytes
+define RT_FORMAT_RGB 3 # XRGB or RGB instead of XBGR or BGR
+define RT_FORMAT_TIFF 4 # tiff <-> standard rasterfile
+define RT_FORMAT_IFF 5 # iff (TAAC format) <-> standard rasterfile
+define RT_EXPERIMENTAL 65535 # Reserved for testing
+
+# Sun supported ras_maptypes
+define RMT_NONE 0 # ras_maplength is expected to be 0
+define RMT_EQUAL_RGB 1 # red[ras_maplength/3],green[],blue[]
+define RMT_RAW 2
+
+
+
+# EX_RAS - Write the evaluated expressions as a Sun Rasterfile.
+
+procedure ex_ras (ex)
+
+pointer ex #i task struct pointer
+
+pointer sp, cmap
+long header[SZ_RASHDR]
+int i, flags
+
+begin
+ # Check to see that we have the correct number of expressions to
+ # write this format.
+ flags = EX_OUTFLAGS(ex)
+ if (EX_NEXPR(ex) != 1 && EX_NEXPR(ex) != 3 && EX_NEXPR(ex) != 4) {
+ if (!bitset(flags, OF_BAND))
+ call error (7, "Invalid number of expressions for rasterfile.")
+ }
+ if (bitset(flags, OF_LINE) || bitset (flags, LINE_STORAGE))
+ call error (7, "Line storage illegal for rasterfile.")
+
+ # Fix the output pixel type to single bytes.
+ call ex_do_outtype (ex, "b1")
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), OF_FLIPY)
+
+ # Make sure the output is padded to the nearest 16-bits.
+ if (mod (O_WIDTH(ex,1),2) != 0) {
+ do i = 1, EX_NEXPR(ex) {
+ call strcat ("//repl(0,1)", O_EXPR(ex,i), SZ_EXPSTR)
+ O_WIDTH(ex,i) = O_WIDTH(ex,i) + 1
+ }
+ EX_OCOLS(ex) = EX_OCOLS(ex) + 1
+ }
+
+ # Set the header values.
+ header[RAS_MAGIC] = RAS_MAGIC_NUM
+ header[RAS_WIDTH] = EX_OCOLS(ex)
+ header[RAS_HEIGHT] = EX_OROWS(ex)
+ header[RAS_TYPE] = RT_STANDARD
+ if (EX_NEXPR(ex) == 1 || bitset (flags, OF_BAND)) {
+ header[RAS_LENGTH] = header[RAS_WIDTH] * header[RAS_HEIGHT]
+ header[RAS_DEPTH] = long (8)
+ } else {
+ header[RAS_LENGTH] = header[RAS_WIDTH] * header[RAS_HEIGHT] * 3
+ header[RAS_DEPTH] = long (24)
+ header[RAS_TYPE] = RT_FORMAT_RGB
+ }
+ if (bitset(flags, OF_CMAP)) {
+ header[RAS_MAPTYPE] = RMT_EQUAL_RGB
+ header[RAS_MAPLENGTH] = long (3*CMAP_SIZE)
+ } else {
+ header[RAS_MAPTYPE] = RMT_NONE
+ header[RAS_MAPLENGTH] = long (0)
+ }
+
+ # Write the header to the file. First swap it to Sun byte order if
+ # needed (although the format doesn't require this), then swap it
+ # if requested by the user.
+ if (BYTE_SWAP4 == YES)
+ call bswap4 (header, 1, header, 1, (SZ_RASHDR * SZ_LONG * SZB_CHAR))
+ if (EX_BSWAP(ex) == S_I4)
+ call bswap4 (header, 1, header, 1, (SZ_RASHDR * SZ_LONG * SZB_CHAR))
+ call write (EX_FD(ex), header, (SZ_RASHDR * SZ_LONG))
+
+ # If we have a colormap write that out now.
+ if (bitset(flags, OF_CMAP)) {
+ call smark (sp)
+ call salloc (cmap, 3*CMAP_SIZE, TY_CHAR)
+
+ call achtcb (Memc[EX_CMAP(ex)], Memc[cmap], (3 * CMAP_SIZE))
+ call write (EX_FD(ex), Memc[cmap], ((3 * CMAP_SIZE) / SZB_CHAR))
+
+ call sfree (sp)
+ }
+
+ # Finally, evaluate the expressions and write the image.
+ if (EX_NEXPR(ex) == 1 || bitset (flags, OF_BAND))
+ call ex_no_interleave (ex)
+ else if (EX_NEXPR(ex) == 3 || EX_NEXPR(ex) == 4)
+ call ex_px_interleave (ex)
+end
diff --git a/pkg/dataio/export/bltins/exrgb.x b/pkg/dataio/export/bltins/exrgb.x
new file mode 100644
index 00000000..119168e6
--- /dev/null
+++ b/pkg/dataio/export/bltins/exrgb.x
@@ -0,0 +1,74 @@
+include <mach.h>
+include "../export.h"
+include "../exbltins.h"
+
+
+define IMAGIC 0732B # SGI magic number
+define BPPMASK 00FFX
+define ITYPE_VERBATIM 0001X
+define ITYPE_RLE 0100X
+
+
+# EX_RGB - Write the output image to an SGI RGB format file.
+
+procedure ex_rgb (ex)
+
+pointer ex #i task struct pointer
+
+int i, fd
+short imagic, type, dim # stuff saved on disk
+short xsize, ysize, zsize, pad
+long min, max
+char name[80]
+
+begin
+ # Check to see that we have the correct number of expressions to
+ # write this format.
+ if (EX_NEXPR(ex) != 3)
+ call error (7, "Invalid number of expressions for SGI RGB.")
+
+ # Fix up the number of output rows.
+ EX_OROWS(ex) = EX_NLINES(ex) * EX_NEXPR(ex)
+
+ # Load the image header values
+ imagic = IMAGIC
+ type = ITYPE_VERBATIM
+ if (EX_NEXPR(ex) >= 3 && !bitset (EX_OUTFLAGS(ex),OF_BAND)) {
+ dim = 3
+ zsize = 3
+ } else {
+ dim = 2
+ zsize = 1
+ }
+ xsize = EX_OCOLS(ex)
+ ysize = EX_NLINES(ex)
+ min = 0
+ max = 255
+ call aclrc (name, 80)
+ call strcpy ("no name", name, 80)
+ call achtcb (name, name, 80)
+
+ # Write the header values to the output file.
+ fd = EX_FD(ex)
+ call write (fd, imagic, SZ_SHORT / SZ_CHAR)
+ call write (fd, type, SZ_SHORT / SZ_CHAR)
+ call write (fd, dim, SZ_SHORT / SZ_CHAR)
+ call write (fd, xsize, SZ_SHORT / SZ_CHAR)
+ call write (fd, ysize, SZ_SHORT / SZ_CHAR)
+ call write (fd, zsize, SZ_SHORT / SZ_CHAR)
+ call write (fd, min, SZ_LONG / SZ_CHAR)
+ call write (fd, max, SZ_LONG / SZ_CHAR)
+ call write (fd, 0, SZ_LONG / SZ_CHAR)
+ call write (fd, name, 8 / SZB_CHAR)
+
+ # Pad to a 512 byte header.
+ pad = 0
+ do i = 1, 240
+ call write (fd, pad, SZ_SHORT / SZ_CHAR)
+
+ # Fix the output parameters.
+ call ex_do_outtype (ex, "b1")
+
+ # Write it out.
+ call ex_no_interleave (ex)
+end
diff --git a/pkg/dataio/export/bltins/exvicar.x b/pkg/dataio/export/bltins/exvicar.x
new file mode 100644
index 00000000..31c8360f
--- /dev/null
+++ b/pkg/dataio/export/bltins/exvicar.x
@@ -0,0 +1,111 @@
+include <mach.h>
+include "../export.h"
+
+
+define SZ_VICHDR 1024
+
+
+# EX_VICAR - Write the evaluated expressions as a VICAR2 format file.
+
+procedure ex_vicar (ex)
+
+pointer ex #i task struct pointer
+
+pointer sp, hdr, user, date, arch
+int i, flags
+char space
+
+int envfind(), strncmp(), strlen()
+long clktime()
+
+begin
+ # Check to see that we have the correct number of expressions to
+ # write this format.
+ flags = EX_OUTFLAGS(ex)
+ if (EX_NEXPR(ex) != 1 && !bitset(flags, OF_BAND))
+ call error (7, "Invalid number of expressions for VICAR file.")
+ if (bitset(flags, OF_LINE) || bitset (flags, LINE_STORAGE))
+ call error (7, "Line storage illegal for VICAR file.")
+
+ # Write the header to the file.
+ call smark (sp)
+ call salloc (hdr, SZ_VICHDR, TY_CHAR)
+ call salloc (user, SZ_FNAME, TY_CHAR)
+ call salloc (date, SZ_FNAME, TY_CHAR)
+ call salloc (arch, SZ_FNAME, TY_CHAR)
+
+ space = ' '
+ call amovkc (space, Memc[hdr], SZ_VICHDR)
+ call aclrc (Memc[user], SZ_FNAME)
+ call aclrc (Memc[date], SZ_FNAME)
+ call aclrc (Memc[arch], SZ_FNAME)
+
+ # Header keywords:
+ call getuid (Memc[user], SZ_FNAME)
+ call cnvtime (clktime(long(0)), Memc[date], SZ_FNAME)
+ call sprintf (Memc[hdr], SZ_VICHDR,
+ "LBLSIZE=%d FORMAT='%s' TYPE='IMAGE' BUFSIZ=20480 DIM=3 EOL=0 RECSIZE=%d ORG='%s' NL=%d NS=%d NB=%d N1=%d N2=%d N3=%d N4=0 NBB=0 NLB=0 INTFMT='%s' REALFMT='%s' TASK='EXPORT' USER='%s' DAT_TIM='%s' ")
+
+ call pargi (SZ_VICHDR) # LBLSIZE
+ switch (EX_OUTTYPE(ex)) { # FORMAT
+ case TY_UBYTE: call pargstr ("BYTE")
+ case TY_SHORT: call pargstr ("HALF")
+ case TY_INT: call pargstr ("FULL")
+ case TY_LONG: call pargstr ("FULL")
+ case TY_REAL: call pargstr ("REAL")
+ case TY_DOUBLE: call pargstr ("DOUB")
+ }
+ call pargi (EX_OCOLS(ex)) # RECSIZE
+ if (bitset(flags, OF_LINE) || bitset (flags, LINE_STORAGE))
+ call pargstr ("BIL") # ORG
+ else
+ call pargstr ("BSQ")
+ call pargi (EX_OROWS(ex)) # NL
+ call pargi (EX_OCOLS(ex)) # NS
+ call pargi (EX_NEXPR(ex)) # NB
+ call pargi (EX_OCOLS(ex)) # N1
+ call pargi (EX_OROWS(ex)) # N2
+ call pargi (EX_NEXPR(ex)) # N3
+ if (BYTE_SWAP2 == NO)
+ call pargstr ("HIGH") # INTFMT
+ else
+ call pargstr ("LOW")
+ if (IEEE_USED == YES) { # REALFMT
+ if (envfind ("arch", Memc[arch], SZ_FNAME) != ERR) {
+ # If this is a DECstation we have a different IEEE.
+ if (strncmp(Memc[arch], ".d", 2) == 0)
+ call pargstr ("RIEEE")
+ else
+ call pargstr ("IEEE")
+ }
+ } else {
+ # Assume it's a VAX.
+ call pargstr ("VAX")
+ }
+ call pargstr (Memc[user]) # USER
+ call pargstr (Memc[date]) # DAT_TIM
+
+ i = SZ_VICHDR
+ while (Memc[hdr+i-1] != EOS && i > 0)
+ i = i - 1
+ Memc[hdr+i-1] = ' '
+
+ call strpak (Memc[hdr], Memc[hdr], SZ_VICHDR)
+ call write (EX_FD(ex), Memc[hdr], strlen(Memc[hdr])/SZB_CHAR)
+ call sfree (sp)
+
+ # Fix the output pixel type to single bytes.
+ switch (EX_OUTTYPE(ex)) {
+ case TY_UBYTE: call ex_do_outtype (ex, "b1")
+ case TY_SHORT: call ex_do_outtype (ex, "i2")
+ case TY_INT: call ex_do_outtype (ex, "i4")
+ case TY_LONG: call ex_do_outtype (ex, "i4")
+ case TY_REAL: call ex_do_outtype (ex, "n4")
+ case TY_DOUBLE: call ex_do_outtype (ex, "n8")
+ }
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), OF_FLIPY)
+
+ # Finally, evaluate the expressions and write the image.
+ if (EX_NEXPR(ex) == 1 || bitset (flags, OF_BAND))
+ call ex_no_interleave (ex)
+end
diff --git a/pkg/dataio/export/bltins/exxwd.x b/pkg/dataio/export/bltins/exxwd.x
new file mode 100644
index 00000000..08c4609a
--- /dev/null
+++ b/pkg/dataio/export/bltins/exxwd.x
@@ -0,0 +1,253 @@
+include <mach.h>
+include "../export.h"
+include "../exbltins.h"
+
+
+define X11WD_FILE_VERSION 7 # XWD version
+define SZ_XWD 25 # number of header elements
+define SZ_XWDHEADER 100 # size of header record (bytes)
+
+# Define the header structure.
+define X_HEADER_SIZE Meml[$1] # Size of the header (bytes)
+define X_FILE_VERSION Meml[$1+1] # XWD_FILE_VERSION
+define X_PIXMAP_FORMAT Meml[$1+2] # Pixmap format
+define X_PIXMAP_DEPTH Meml[$1+3] # Pixmap depth
+define X_PIXMAP_WIDTH Meml[$1+4] # Pixmap width
+define X_PIXMAP_HEIGHT Meml[$1+5] # Pixmap height
+define X_XOFFSET Meml[$1+6] # Bitmap x offset
+define X_BYTE_ORDER Meml[$1+7] # MSBFirst, LSBFirst
+define X_BITMAP_UNIT Meml[$1+8] # Bitmap unit
+define X_BITMAP_BIT_ORDER Meml[$1+9] # MSBFirst, LSBFirst
+define X_BITMAP_PAD Meml[$1+10] # Bitmap scanline pad
+define X_BITS_PER_PIXEL Meml[$1+11] # Bits per pixel
+define X_BYTES_PER_LINE Meml[$1+12] # Bytes per scanline
+define X_VISUAL_CLASS Meml[$1+13] # Class of colormap
+define X_RED_MASK Meml[$1+14] # Z red mask
+define X_GREEN_MASK Meml[$1+15] # Z green mask
+define X_BLUE_MASK Meml[$1+16] # Z blue mask
+define X_BITS_PER_RGB Meml[$1+17] # Log2 of distinct color values
+define X_COLORMAP_ENTRIES Meml[$1+18] # Number of entries in colormap
+define X_NCOLORS Meml[$1+19] # Number of Color structures
+define X_WINDOW_WIDTH Meml[$1+20] # Window width
+define X_WINDOW_HEIGHT Meml[$1+21] # Window height
+define X_WINDOW_X Meml[$1+22] # Window upper left X coordinate
+define X_WINDOW_Y Meml[$1+23] # Window upper left Y coordinate
+define X_WINDOW_BDRWIDTH Meml[$1+24] # Window border width
+
+define LSBFirst 0 # Byte order flags
+define MSBFirst 1
+
+define XYBitmap 0 # Pixmap types
+define XYPixmap 1
+define ZPixmap 2
+
+define StaticGray 0 # Recognized visuals
+define GrayScale 1
+define StaticColor 2
+define PseudoColor 3
+define TrueColor 4
+define DirectColor 5
+
+define DEBUG false
+
+
+# EX_XWD - Write the output image to an X11 Window Dump file.
+
+procedure ex_xwd (ex)
+
+pointer ex #i task struct pointer
+
+pointer xwd, cmap
+char cflags, fname[SZ_FNAME]
+int i, fd, flags
+long pixel
+short r, g, b, val
+
+int strlen()
+
+begin
+ # Check to see that we have the correct number of expressions to
+ # write this format.
+ flags = EX_OUTFLAGS(ex)
+ fd = EX_FD(ex)
+ if (EX_NEXPR(ex) != 1 && EX_NEXPR(ex) != 3 && EX_NEXPR(ex) != 4) {
+ if (!bitset(flags, OF_BAND))
+ call error (7, "Invalid number of expressions for XWD.")
+ }
+ if (bitset(flags, OF_LINE) || bitset (flags, LINE_STORAGE))
+ call error (7, "Line storage illegal for XWD.")
+
+ # Fix the output pixel type to single bytes.
+ call ex_do_outtype (ex, "b1")
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), OF_FLIPY)
+
+ # Allocate space for the header.
+ iferr (call calloc (xwd, SZ_XWD, TY_STRUCT))
+ call error (0, "Error allocate XWD structure.")
+
+ # Set up the header values.
+ flags = EX_OUTFLAGS(ex)
+ X_HEADER_SIZE(xwd) = SZ_XWDHEADER + strlen ("xwddump") + 1
+ X_FILE_VERSION(xwd) = X11WD_FILE_VERSION
+ X_PIXMAP_FORMAT(xwd) = ZPixmap
+ X_PIXMAP_WIDTH(xwd) = EX_OCOLS(ex)
+ X_PIXMAP_HEIGHT(xwd) = EX_OROWS(ex)
+ X_XOFFSET(xwd) = 0
+ X_BYTE_ORDER(xwd) = MSBFirst
+ X_BITMAP_BIT_ORDER(xwd) = MSBFirst
+ X_WINDOW_WIDTH(xwd) = EX_OCOLS(ex)
+ X_WINDOW_HEIGHT(xwd) = EX_OROWS(ex)
+ X_WINDOW_X(xwd) = 0
+ X_WINDOW_Y(xwd) = 0
+ X_WINDOW_BDRWIDTH(xwd) = 0
+
+ if (EX_NEXPR(ex) >= 3) {
+ if (DEBUG) call eprintf ("We think this is a DirectColor image.\n")
+ X_PIXMAP_DEPTH(xwd) = 24
+ X_BITMAP_UNIT(xwd) = 32
+ X_BITMAP_PAD(xwd) = 32
+ X_BITS_PER_PIXEL(xwd) = 32
+ X_VISUAL_CLASS(xwd) = DirectColor
+ X_COLORMAP_ENTRIES(xwd) = 256
+ X_NCOLORS(xwd) = 0
+ X_RED_MASK(xwd) = 0FF0000X
+ X_GREEN_MASK(xwd) = 0FF00X
+ X_BLUE_MASK(xwd) = 0FFX
+ X_BYTES_PER_LINE(xwd) = EX_OCOLS(ex) * 4
+ } else if (bitset (flags, OF_CMAP)) {
+ if (DEBUG) call eprintf ("We think this has a colormap.\n")
+ X_PIXMAP_DEPTH(xwd) = 8
+ X_BITS_PER_PIXEL(xwd) = 8
+ X_COLORMAP_ENTRIES(xwd) = EX_NCOLORS(ex)
+ X_NCOLORS(xwd) = EX_NCOLORS(ex)
+ X_BYTES_PER_LINE(xwd) = EX_OCOLS(ex)
+
+ X_BITMAP_UNIT(xwd) = 8
+ X_BITMAP_PAD(xwd) = 8
+ X_VISUAL_CLASS(xwd) = StaticGray
+ X_RED_MASK(xwd) = 0
+ X_GREEN_MASK(xwd) = 0
+ X_BLUE_MASK(xwd) = 0
+ } else {
+ if (DEBUG) call eprintf ("Pseudocolor.\n")
+ X_PIXMAP_DEPTH(xwd) = 8
+ X_BITS_PER_PIXEL(xwd) = 8
+ X_VISUAL_CLASS(xwd) = PseudoColor
+ X_COLORMAP_ENTRIES(xwd) = 255 + 1
+ X_NCOLORS(xwd) = EX_NCOLORS(ex)
+ X_RED_MASK(xwd) = 0
+ X_GREEN_MASK(xwd) = 0
+ X_BLUE_MASK(xwd) = 0
+ X_BYTES_PER_LINE(xwd) = EX_OCOLS(ex)
+ X_BITMAP_UNIT(xwd) = 8
+ X_BITMAP_PAD(xwd) = 8
+ }
+ X_BITS_PER_RGB(xwd) = X_PIXMAP_DEPTH(xwd)
+
+ # See if we need to byte swap in order to get MSB byte ordering.
+ if (BYTE_SWAP4 == YES)
+ call bswap4 (Meml[xwd], 1, Meml[xwd], 1, SZ_XWDHEADER)
+ if (EX_BSWAP(ex) == S_I4)
+ call bswap4 (Meml[xwd], 1, Meml[xwd], 1, SZ_XWDHEADER)
+ call write (fd, Meml[xwd], SZ_XWDHEADER/SZB_CHAR)
+ call strpak ("xwddump\0", fname, 8)
+ call write (fd, fname, 4)
+
+ # If we have a colormap set up the structure and write it out.
+ if (bitset (flags, OF_CMAP)) {
+ cmap = EX_CMAP(ex)
+ cflags = 0
+ do i = 1, EX_NCOLORS(ex) {
+ pixel = i - 1
+ r = CMAP(cmap,EX_RED,i) * 65535 / 256
+ g = CMAP(cmap,EX_GREEN,i) * 65535 / 256
+ b = CMAP(cmap,EX_BLUE,i) * 65535 / 256
+
+ call xwd_putlong (ex, fd, pixel)
+ call xwd_putword (ex, fd, r)
+ call xwd_putword (ex, fd, g)
+ call xwd_putword (ex, fd, b)
+ call xwd_putword (ex, fd, cflags)
+ }
+ } else if (EX_NEXPR(ex) < 3) {
+ do i = 0, 255 {
+ val = i * 65535 / 256
+ call xwd_putlong (ex, fd, long(i))
+ call xwd_putword (ex, fd, val)
+ call xwd_putword (ex, fd, val)
+ call xwd_putword (ex, fd, val)
+ val = 0 #shifti (7, 8)
+ call xwd_putword (ex, fd, val)
+ }
+ }
+
+ # Finally, evaluate the expressions and write the image.
+ if (EX_NEXPR(ex) == 1 || bitset (flags, OF_BAND))
+ call ex_no_interleave (ex)
+ else if (EX_NEXPR(ex) == 3) {
+ # If all they gave were the RGB values we need to patch the
+ # outbands expressions to stick in an alpha channel. Patch it
+ # up here.
+
+ call ex_alloc_outbands (OBANDS(ex,4))
+ do i = 4, 2, -1 {
+ call strcpy (O_EXPR(ex,i-1), O_EXPR(ex,i), SZ_EXPSTR)
+ O_WIDTH(ex,i) = O_WIDTH(ex,i-1)
+ O_HEIGHT(ex,i) = O_HEIGHT(ex,i-1)
+ }
+ call strcpy ("0", O_EXPR(ex,1), SZ_EXPSTR)
+ EX_NEXPR(ex) = 4
+ call ex_px_interleave (ex)
+
+ } else if (EX_NEXPR(ex) >= 3)
+ call ex_px_interleave (ex)
+
+ # Clean up.
+ call mfree (xwd, TY_STRUCT)
+end
+
+
+# XWD_PUTWORD - Writes a 16-bit integer in XWD order (MSB first).
+
+procedure xwd_putword (ex, fd, w)
+
+pointer ex #i task struct pointer
+int fd
+short w
+
+short val
+
+begin
+ # If this is a MSB-first machine swap the bytes before output.
+ if (BYTE_SWAP2 == YES)
+ call bswap2 (w, 1, val, 1, (SZ_SHORT * SZB_CHAR))
+ else
+ val = w
+ if (EX_BSWAP(ex) == S_I2)
+ call bswap2 (val, 1, val, 1, (SZ_SHORT * SZB_CHAR))
+
+ call write (fd, val, SZ_SHORT/SZ_CHAR)
+end
+
+
+# XWD_PUTLONG - Writes a 32-bit integer in XWD order (MSB first).
+
+procedure xwd_putlong (ex, fd, w)
+
+pointer ex #i task struct pointer
+int fd
+long w
+
+long val
+
+begin
+ # If this is a MSB-first machine swap the bytes before output.
+ if (BYTE_SWAP4 == YES)
+ call bswap4 (w, 1, val, 1, (SZ_LONG * SZB_CHAR))
+ else
+ val = w
+ if (EX_BSWAP(ex) == S_I4)
+ call bswap4 (val, 1, val, 1, (SZ_LONG * SZB_CHAR))
+
+ call write (fd, val, SZ_LONG/SZ_CHAR)
+end
diff --git a/pkg/dataio/export/bltins/mkpkg b/pkg/dataio/export/bltins/mkpkg
new file mode 100644
index 00000000..14e6b8d4
--- /dev/null
+++ b/pkg/dataio/export/bltins/mkpkg
@@ -0,0 +1,20 @@
+# Mkpkg file for building the EXPORT task builtin formats.
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ exeps.x ../exbltins.h ../export.h \
+ <evvexpr.h> <fset.h> <imhdr.h> <mach.h>
+ exgif.x ../exbltins.h ../export.h <evvexpr.h> <fset.h> <mach.h>
+ exiraf.x ../export.h <evvexpr.h> <imhdr.h> <mach.h>
+ exmiff.x ../export.h <mach.h>
+ expgm.x ../export.h <mach.h>
+ exppm.x ../export.h <mach.h>
+ exras.x ../export.h <mach.h>
+ exrgb.x ../exbltins.h ../export.h <mach.h>
+ exvicar.x ../export.h <mach.h>
+ exxwd.x ../exbltins.h ../export.h <mach.h>
+ ;
diff --git a/pkg/dataio/export/cmaps.inc b/pkg/dataio/export/cmaps.inc
new file mode 100644
index 00000000..91707e68
--- /dev/null
+++ b/pkg/dataio/export/cmaps.inc
@@ -0,0 +1,534 @@
+short aips0[768]
+data (aips0(i),i= 1, 12) / 0, 0, 0, 50, 50, 50, 50, 50, 50, 50, 50, 50/
+data (aips0(i),i= 13, 24) / 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50/
+data (aips0(i),i= 25, 36) / 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50/
+data (aips0(i),i= 37, 48) / 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50/
+data (aips0(i),i= 49, 60) / 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50/
+data (aips0(i),i= 61, 72) / 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50/
+data (aips0(i),i= 73, 84) / 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50/
+data (aips0(i),i= 85, 96) / 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50/
+data (aips0(i),i= 97,108) /121, 0,154,121, 0,154,121, 0,154,121, 0,154/
+data (aips0(i),i=109,120) /121, 0,154,121, 0,154,121, 0,154,121, 0,154/
+data (aips0(i),i=121,132) /121, 0,154,121, 0,154,121, 0,154,121, 0,154/
+data (aips0(i),i=133,144) /121, 0,154,121, 0,154,121, 0,154,121, 0,154/
+data (aips0(i),i=145,156) /121, 0,154,121, 0,154,121, 0,154,121, 0,154/
+data (aips0(i),i=157,168) /121, 0,154,121, 0,154,121, 0,154,121, 0,154/
+data (aips0(i),i=169,180) /121, 0,154,121, 0,154,121, 0,154,121, 0,154/
+data (aips0(i),i=181,192) / 0, 0,199, 0, 0,199, 0, 0,199, 0, 0,199/
+data (aips0(i),i=193,204) / 0, 0,199, 0, 0,199, 0, 0,199, 0, 0,199/
+data (aips0(i),i=205,216) / 0, 0,199, 0, 0,199, 0, 0,199, 0, 0,199/
+data (aips0(i),i=217,228) / 0, 0,199, 0, 0,199, 0, 0,199, 0, 0,199/
+data (aips0(i),i=229,240) / 0, 0,199, 0, 0,199, 0, 0,199, 0, 0,199/
+data (aips0(i),i=241,252) / 0, 0,199, 0, 0,199, 0, 0,199, 0, 0,199/
+data (aips0(i),i=253,264) / 0, 0,199, 0, 0,199, 0, 0,199, 0, 0,199/
+data (aips0(i),i=265,276) / 95,166,235, 95,166,235, 95,166,235, 95,166,235/
+data (aips0(i),i=277,288) / 95,166,235, 95,166,235, 95,166,235, 95,166,235/
+data (aips0(i),i=289,300) / 95,166,235, 95,166,235, 95,166,235, 95,166,235/
+data (aips0(i),i=301,312) / 95,166,235, 95,166,235, 95,166,235, 95,166,235/
+data (aips0(i),i=313,324) / 95,166,235, 95,166,235, 95,166,235, 95,166,235/
+data (aips0(i),i=325,336) / 95,166,235, 95,166,235, 95,166,235, 95,166,235/
+data (aips0(i),i=337,348) / 95,166,235, 95,166,235, 95,166,235, 95,166,235/
+data (aips0(i),i=349,360) / 0,145, 0, 0,145, 0, 0,145, 0, 0,145, 0/
+data (aips0(i),i=361,372) / 0,145, 0, 0,145, 0, 0,145, 0, 0,145, 0/
+data (aips0(i),i=373,384) / 0,145, 0, 0,145, 0, 0,145, 0, 0,145, 0/
+data (aips0(i),i=385,396) / 0,145, 0, 0,145, 0, 0,145, 0, 0,145, 0/
+data (aips0(i),i=397,408) / 0,145, 0, 0,145, 0, 0,145, 0, 0,145, 0/
+data (aips0(i),i=409,420) / 0,145, 0, 0,145, 0, 0,145, 0, 0,145, 0/
+data (aips0(i),i=421,432) / 0,145, 0, 0,145, 0, 0,145, 0, 0,145, 0/
+data (aips0(i),i=433,444) / 0,246, 0, 0,246, 0, 0,246, 0, 0,246, 0/
+data (aips0(i),i=445,456) / 0,246, 0, 0,246, 0, 0,246, 0, 0,246, 0/
+data (aips0(i),i=457,468) / 0,246, 0, 0,246, 0, 0,246, 0, 0,246, 0/
+data (aips0(i),i=469,480) / 0,246, 0, 0,246, 0, 0,246, 0, 0,246, 0/
+data (aips0(i),i=481,492) / 0,246, 0, 0,246, 0, 0,246, 0, 0,246, 0/
+data (aips0(i),i=493,504) / 0,246, 0, 0,246, 0, 0,246, 0, 0,246, 0/
+data (aips0(i),i=505,516) / 0,246, 0, 0,246, 0, 0,246, 0, 0,246, 0/
+data (aips0(i),i=517,528) /255,255, 0,255,255, 0,255,255, 0,255,255, 0/
+data (aips0(i),i=529,540) /255,255, 0,255,255, 0,255,255, 0,255,255, 0/
+data (aips0(i),i=541,552) /255,255, 0,255,255, 0,255,255, 0,255,255, 0/
+data (aips0(i),i=553,564) /255,255, 0,255,255, 0,255,255, 0,255,255, 0/
+data (aips0(i),i=565,576) /255,255, 0,255,255, 0,255,255, 0,255,255, 0/
+data (aips0(i),i=577,588) /255,255, 0,255,255, 0,255,255, 0,255,255, 0/
+data (aips0(i),i=589,600) /255,255, 0,255,255, 0,255,255, 0,255,255, 0/
+data (aips0(i),i=601,612) /255,177, 0,255,177, 0,255,177, 0,255,177, 0/
+data (aips0(i),i=613,624) /255,177, 0,255,177, 0,255,177, 0,255,177, 0/
+data (aips0(i),i=625,636) /255,177, 0,255,177, 0,255,177, 0,255,177, 0/
+data (aips0(i),i=637,648) /255,177, 0,255,177, 0,255,177, 0,255,177, 0/
+data (aips0(i),i=649,660) /255,177, 0,255,177, 0,255,177, 0,255,177, 0/
+data (aips0(i),i=661,672) /255,177, 0,255,177, 0,255,177, 0,255,177, 0/
+data (aips0(i),i=673,684) /255,177, 0,255,177, 0,255,177, 0,255,177, 0/
+data (aips0(i),i=685,696) /255, 0, 0,255, 0, 0,255, 0, 0,255, 0, 0/
+data (aips0(i),i=697,708) /255, 0, 0,255, 0, 0,255, 0, 0,255, 0, 0/
+data (aips0(i),i=709,720) /255, 0, 0,255, 0, 0,255, 0, 0,255, 0, 0/
+data (aips0(i),i=721,732) /255, 0, 0,255, 0, 0,255, 0, 0,255, 0, 0/
+data (aips0(i),i=733,744) /255, 0, 0,255, 0, 0,255, 0, 0,255, 0, 0/
+data (aips0(i),i=745,756) /255, 0, 0,255, 0, 0,255, 0, 0,255, 0, 0/
+data (aips0(i),i=757,768) /255, 0, 0,255, 0, 0,255, 0, 0,255, 0, 0/
+
+
+short color[768]
+data (color(i),i= 1, 12) / 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0/
+data (color(i),i= 13, 24) / 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0/
+data (color(i),i= 25, 36) / 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0/
+data (color(i),i= 37, 48) / 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0/
+data (color(i),i= 49, 60) / 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46/
+data (color(i),i= 61, 72) / 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46/
+data (color(i),i= 73, 84) / 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46/
+data (color(i),i= 85, 96) / 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46/
+data (color(i),i= 97,108) / 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95/
+data (color(i),i=109,120) / 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95/
+data (color(i),i=121,132) / 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95/
+data (color(i),i=133,144) / 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95/
+data (color(i),i=145,156) /142,142,142,142,142,142,142,142,142,142,142,142/
+data (color(i),i=157,168) /142,142,142,142,142,142,142,142,142,142,142,142/
+data (color(i),i=169,180) /142,142,142,142,142,142,142,142,142,142,142,142/
+data (color(i),i=181,192) /142,142,142,142,142,142,142,142,142,142,142,142/
+data (color(i),i=193,204) /191,191,191,191,191,191,191,191,191,191,191,191/
+data (color(i),i=205,216) /191,191,191,191,191,191,191,191,191,191,191,191/
+data (color(i),i=217,228) /191,191,191,191,191,191,191,191,191,191,191,191/
+data (color(i),i=229,240) /191,191,191,191,191,191,191,191,191,191,191,191/
+data (color(i),i=241,252) /238,238,238,238,238,238,238,238,238,238,238,238/
+data (color(i),i=253,264) /238,238,238,238,238,238,238,238,238,238,238,238/
+data (color(i),i=265,276) /238,238,238,238,238,238,238,238,238,238,238,238/
+data (color(i),i=277,288) /238,238,238,238,238,238,238,238,238,238,238,238/
+data (color(i),i=289,300) / 0, 46,238, 0, 46,238, 0, 46,238, 0, 46,238/
+data (color(i),i=301,312) / 0, 46,238, 0, 46,238, 0, 46,238, 0, 46,238/
+data (color(i),i=313,324) / 0, 46,238, 0, 46,238, 0, 46,238, 0, 46,238/
+data (color(i),i=325,336) / 0, 46,238, 0, 46,238, 0, 46,238, 0, 46,238/
+data (color(i),i=337,348) / 0, 95,191, 0, 95,191, 0, 95,191, 0, 95,191/
+data (color(i),i=349,360) / 0, 95,191, 0, 95,191, 0, 95,191, 0, 95,191/
+data (color(i),i=361,372) / 0, 95,191, 0, 95,191, 0, 95,191, 0, 95,191/
+data (color(i),i=373,384) / 0, 95,191, 0, 95,191, 0, 95,191, 0, 95,191/
+data (color(i),i=385,396) / 0,127,127, 0,127,127, 0,127,127, 0,127,127/
+data (color(i),i=397,408) / 0,127,127, 0,127,127, 0,127,127, 0,127,127/
+data (color(i),i=409,420) / 0,127,127, 0,127,127, 0,127,127, 0,127,127/
+data (color(i),i=421,432) / 0,127,127, 0,127,127, 0,127,127, 0,127,127/
+data (color(i),i=433,444) / 0,191, 78, 0,191, 78, 0,191, 78, 0,191, 78/
+data (color(i),i=445,456) / 0,191, 78, 0,191, 78, 0,191, 78, 0,191, 78/
+data (color(i),i=457,468) / 0,191, 78, 0,191, 78, 0,191, 78, 0,191, 78/
+data (color(i),i=469,480) / 0,191, 78, 0,191, 78, 0,191, 78, 0,191, 78/
+data (color(i),i=481,492) / 0,238, 0, 0,238, 0, 0,238, 0, 0,238, 0/
+data (color(i),i=493,504) / 0,238, 0, 0,238, 0, 0,238, 0, 0,238, 0/
+data (color(i),i=505,516) / 0,238, 0, 0,238, 0, 0,238, 0, 0,238, 0/
+data (color(i),i=517,528) / 0,238, 0, 0,238, 0, 0,238, 0, 0,238, 0/
+data (color(i),i=529,540) / 78,159, 0, 78,159, 0, 78,159, 0, 78,159, 0/
+data (color(i),i=541,552) / 78,159, 0, 78,159, 0, 78,159, 0, 78,159, 0/
+data (color(i),i=553,564) / 78,159, 0, 78,159, 0, 78,159, 0, 78,159, 0/
+data (color(i),i=565,576) / 78,159, 0, 78,159, 0, 78,159, 0, 78,159, 0/
+data (color(i),i=577,588) /127,127, 0,127,127, 0,127,127, 0,127,127, 0/
+data (color(i),i=589,600) /127,127, 0,127,127, 0,127,127, 0,127,127, 0/
+data (color(i),i=601,612) /127,127, 0,127,127, 0,127,127, 0,127,127, 0/
+data (color(i),i=613,624) /127,127, 0,127,127, 0,127,127, 0,127,127, 0/
+data (color(i),i=625,636) /159, 78, 0,159, 78, 0,159, 78, 0,159, 78, 0/
+data (color(i),i=637,648) /159, 78, 0,159, 78, 0,159, 78, 0,159, 78, 0/
+data (color(i),i=649,660) /159, 78, 0,159, 78, 0,159, 78, 0,159, 78, 0/
+data (color(i),i=661,672) /159, 78, 0,159, 78, 0,159, 78, 0,159, 78, 0/
+data (color(i),i=673,684) /238, 0, 0,238, 0, 0,238, 0, 0,238, 0, 0/
+data (color(i),i=685,696) /238, 0, 0,238, 0, 0,238, 0, 0,238, 0, 0/
+data (color(i),i=697,708) /238, 0, 0,238, 0, 0,238, 0, 0,238, 0, 0/
+data (color(i),i=709,720) /238, 0, 0,238, 0, 0,238, 0, 0,238, 0, 0/
+data (color(i),i=721,732) /191, 0, 78,191, 0, 78,191, 0, 78,191, 0, 78/
+data (color(i),i=733,744) /191, 0, 78,191, 0, 78,191, 0, 78,191, 0, 78/
+data (color(i),i=745,756) /191, 0, 78,191, 0, 78,191, 0, 78,191, 0, 78/
+data (color(i),i=757,768) /191, 0, 78,191, 0, 78,191, 0, 78,191, 0, 78/
+
+
+short halley[768]
+data (halley(i),i= 1, 12) / 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,179/
+data (halley(i),i= 13, 24) / 0, 0,179, 0, 0,220, 0, 0,220,120, 0,220/
+data (halley(i),i= 25, 36) /120, 0,220,120, 0,220,179, 0,229,179, 0,229/
+data (halley(i),i= 37, 48) /255, 0,255,255, 0,255,255, 0,179,255, 0,179/
+data (halley(i),i= 49, 60) /255, 0,132,255, 0, 0,255, 0, 0,255,120, 0/
+data (halley(i),i= 61, 72) /255,120, 0,252,184, 0,252,184, 0,250,206, 0/
+data (halley(i),i= 73, 84) /250,216, 0,250,216, 0,255,255, 0,255,255, 0/
+data (halley(i),i= 85, 96) /179,255, 0,179,255, 0, 0,255, 0, 0,255, 0/
+data (halley(i),i= 97,108) / 0,255, 0, 0,255,179, 0,255,179, 0,255,255/
+data (halley(i),i=109,120) / 0,255,255,120,199,255,120,199,255,120,199,255/
+data (halley(i),i=121,132) /159,159,255,159,159,255,199,120,255,199,120,255/
+data (halley(i),i=133,144) /255,179,255,255,179,255,255,196,255,255,220,255/
+data (halley(i),i=145,156) /255,220,255,255,255,255,255,255,255,255,255,255/
+data (halley(i),i=157,168) /255,255,255,255,229,255,255,220,255,255,220,255/
+data (halley(i),i=169,180) /255,220,255, 0,255, 0, 0,255, 0, 0,255, 0/
+data (halley(i),i=181,192) / 0,255, 0, 0,255, 0, 0,255, 0, 0,255, 0/
+data (halley(i),i=193,204) / 0,255, 0, 0,255, 0, 0,255, 0, 0,255, 0/
+data (halley(i),i=205,216) / 0,255, 0, 0,255, 0, 0,255, 0, 0,255, 0/
+data (halley(i),i=217,228) /235,158,255,199,120,255,199,120,255,199,120,255/
+data (halley(i),i=229,240) /199,120,255,199,120,255,199,120,255,199,120,255/
+data (halley(i),i=241,252) /199,120,255,199,120,255,167,152,255,159,159,255/
+data (halley(i),i=253,264) /159,159,255, 0, 0,255, 0, 0,255, 0, 0,255/
+data (halley(i),i=265,276) / 0, 0,255, 0, 0,255, 0, 0,255, 0, 0,255/
+data (halley(i),i=277,288) / 0, 0,255, 0, 0,255,255, 0, 0,255, 0, 0/
+data (halley(i),i=289,300) /255, 0, 0,255, 0, 0,255, 0, 0,255, 0, 0/
+data (halley(i),i=301,312) /255, 0, 0,255, 0, 0,255, 0, 0,255, 0, 0/
+data (halley(i),i=313,324) /255, 0, 0,255, 0, 0,255, 0, 0,255, 0, 0/
+data (halley(i),i=325,336) /255, 0, 0,255, 0, 0,255, 0, 0,255, 0, 0/
+data (halley(i),i=337,348) /255, 0, 0,255, 0, 0, 0,255,179, 0,255,179/
+data (halley(i),i=349,360) / 0,255,179, 0,255,179, 0,255,179, 0,255,179/
+data (halley(i),i=361,372) / 0,255,166, 0,255, 0, 0,255, 0, 0,255, 0/
+data (halley(i),i=373,384) / 0,255, 0, 0,255, 0, 0,255, 0, 0,255, 0/
+data (halley(i),i=385,396) / 0,255, 0, 0,255, 0, 91,255, 0,179,255, 0/
+data (halley(i),i=397,408) /179,255, 0,179,255, 0,179,255, 0,179,255, 0/
+data (halley(i),i=409,420) /179,255, 0,179,255, 0,179,255, 0,179,255, 0/
+data (halley(i),i=421,432) /250,255, 0,255,255, 0,255,255, 0,255,255, 0/
+data (halley(i),i=433,444) /255,255, 0,255,255, 0,255,255, 0,255,255, 0/
+data (halley(i),i=445,456) /255,255, 0,254,248, 0,250,216, 0,250,216, 0/
+data (halley(i),i=457,468) /250,216, 0,250,216, 0,250,216, 0,250,216, 0/
+data (halley(i),i=469,480) /250,216, 0,250,216, 0,250,216, 0,252,197, 0/
+data (halley(i),i=481,492) /252,184, 0,252,184, 0,252,184, 0,252,184, 0/
+data (halley(i),i=493,504) /252,184, 0,252,184, 0,252,184, 0,252,184, 0/
+data (halley(i),i=505,516) /252,184, 0,255,120, 0,255,120, 0,255,120, 0/
+data (halley(i),i=517,528) /255,120, 0,255,120, 0,255,120, 0,255,120, 0/
+data (halley(i),i=529,540) /255,120, 0,255,120, 0,255, 94, 0,255, 0, 0/
+data (halley(i),i=541,552) /255, 0, 0,255, 0, 0,255, 0, 0,255, 0, 0/
+data (halley(i),i=553,564) /255, 0, 0,255, 0, 0,255, 0, 0,255, 0, 0/
+data (halley(i),i=565,576) /255, 0,119,255, 0,179,255, 0,179,255, 0,179/
+data (halley(i),i=577,588) /255, 0,179,255, 0,179,255, 0,179,255, 0,179/
+data (halley(i),i=589,600) /255, 0,179,255, 0,179,255, 0,255,255, 0,255/
+data (halley(i),i=601,612) /255, 0,255,255, 0,255,255, 0,255,255, 0,255/
+data (halley(i),i=613,624) /255, 0,255,255, 0,255,255, 0,255,233, 0,248/
+data (halley(i),i=625,636) /179, 0,229,179, 0,229,179, 0,229,179, 0,229/
+data (halley(i),i=637,648) /179, 0,229,179, 0,229,179, 0,229,179, 0,229/
+data (halley(i),i=649,660) /179, 0,229,135, 0,223,120, 0,220,120, 0,220/
+data (halley(i),i=661,672) /120, 0,220,120, 0,220,120, 0,220,120, 0,220/
+data (halley(i),i=673,684) /120, 0,220,120, 0,220,120, 0,220,255,255,255/
+data (halley(i),i=685,696) /255,255,255,255,255,255,255,255,255,255,255,255/
+data (halley(i),i=697,708) / 0, 0,220, 0, 0,220, 0, 0,220, 0, 0,220/
+data (halley(i),i=709,720) / 0, 0,204, 0, 0,179, 0, 0,179, 0, 0,179/
+data (halley(i),i=721,732) / 0, 0,179, 0, 0,179, 0, 0,179, 0, 0,179/
+data (halley(i),i=733,744) / 0, 0,179, 0, 0,179, 0, 0, 34, 0, 0, 0/
+data (halley(i),i=745,756) / 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0/
+data (halley(i),i=757,768) / 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0/
+
+
+short heat[768]
+data (heat(i),i= 1, 12) / 0, 0, 0, 2, 0, 0, 6, 1, 0, 8, 2, 0/
+data (heat(i),i= 13, 24) / 12, 4, 0, 14, 5, 0, 18, 6, 0, 20, 6, 0/
+data (heat(i),i= 25, 36) / 24, 7, 0, 26, 8, 0, 30, 10, 0, 32, 11, 0/
+data (heat(i),i= 37, 48) / 36, 12, 0, 38, 12, 0, 42, 13, 0, 44, 14, 0/
+data (heat(i),i= 49, 60) / 48, 16, 0, 51, 17, 0, 53, 18, 0, 57, 19, 0/
+data (heat(i),i= 61, 72) / 59, 19, 0, 63, 20, 0, 65, 21, 0, 69, 23, 0/
+data (heat(i),i= 73, 84) / 71, 24, 0, 75, 25, 0, 77, 25, 0, 81, 26, 0/
+data (heat(i),i= 85, 96) / 83, 27, 0, 87, 29, 0, 89, 30, 0, 93, 31, 0/
+data (heat(i),i= 97,108) / 95, 31, 0, 99, 32, 0,102, 33, 0,104, 34, 0/
+data (heat(i),i=109,120) /108, 36, 0,110, 37, 0,114, 38, 0,116, 38, 0/
+data (heat(i),i=121,132) /120, 39, 0,122, 40, 0,126, 42, 0,128, 43, 0/
+data (heat(i),i=133,144) /132, 44, 0,134, 44, 0,138, 45, 0,140, 46, 0/
+data (heat(i),i=145,156) /144, 48, 0,146, 49, 0,150, 50, 0,153, 51, 0/
+data (heat(i),i=157,168) /155, 51, 0,159, 52, 0,161, 53, 0,165, 55, 0/
+data (heat(i),i=169,180) /167, 56, 0,171, 57, 0,173, 57, 0,177, 58, 0/
+data (heat(i),i=181,192) /179, 59, 0,183, 61, 0,185, 62, 0,189, 63, 0/
+data (heat(i),i=193,204) /191, 63, 0,195, 64, 0,197, 65, 0,201, 67, 0/
+data (heat(i),i=205,216) /204, 68, 0,206, 69, 0,210, 70, 0,212, 70, 0/
+data (heat(i),i=217,228) /216, 71, 0,218, 72, 0,222, 74, 0,224, 75, 0/
+data (heat(i),i=229,240) /228, 76, 0,230, 76, 0,234, 77, 0,236, 78, 0/
+data (heat(i),i=241,252) /240, 80, 0,242, 81, 0,246, 82, 0,248, 82, 0/
+data (heat(i),i=253,264) /252, 83, 0,255, 84, 0,255, 85, 0,255, 87, 0/
+data (heat(i),i=265,276) /255, 88, 0,255, 89, 0,255, 89, 0,255, 90, 0/
+data (heat(i),i=277,288) /255, 91, 0,255, 93, 0,255, 94, 0,255, 95, 0/
+data (heat(i),i=289,300) /255, 95, 0,255, 96, 0,255, 97, 0,255, 99, 0/
+data (heat(i),i=301,312) /255,100, 0,255,101, 0,255,102, 0,255,102, 0/
+data (heat(i),i=313,324) /255,103, 0,255,104, 0,255,106, 0,255,107, 0/
+data (heat(i),i=325,336) /255,108, 0,255,108, 0,255,109, 0,255,110, 0/
+data (heat(i),i=337,348) /255,112, 0,255,113, 0,255,114, 0,255,114, 0/
+data (heat(i),i=349,360) /255,115, 0,255,116, 0,255,118, 0,255,119, 0/
+data (heat(i),i=361,372) /255,120, 0,255,121, 0,255,121, 0,255,122, 0/
+data (heat(i),i=373,384) /255,123, 0,255,125, 0,255,126, 0,255,127, 0/
+data (heat(i),i=385,396) /255,127, 0,255,128, 0,255,129, 0,255,131, 0/
+data (heat(i),i=397,408) /255,132, 0,255,133, 0,255,133, 0,255,134, 0/
+data (heat(i),i=409,420) /255,135, 0,255,136, 0,255,138, 0,255,139, 0/
+data (heat(i),i=421,432) /255,140, 0,255,140, 0,255,141, 0,255,142, 0/
+data (heat(i),i=433,444) /255,144, 0,255,145, 0,255,146, 0,255,146, 0/
+data (heat(i),i=445,456) /255,147, 0,255,148, 0,255,150, 0,255,151, 0/
+data (heat(i),i=457,468) /255,152, 0,255,153, 0,255,153, 0,255,154, 0/
+data (heat(i),i=469,480) /255,155, 0,255,157, 0,255,158, 0,255,159, 0/
+data (heat(i),i=481,492) /255,159, 0,255,160, 0,255,161, 0,255,163, 0/
+data (heat(i),i=493,504) /255,164, 0,255,165, 0,255,165, 2,255,166, 6/
+data (heat(i),i=505,516) /255,167, 8,255,169, 12,255,170, 14,255,171, 18/
+data (heat(i),i=517,528) /255,172, 20,255,172, 24,255,173, 26,255,174, 30/
+data (heat(i),i=529,540) /255,176, 32,255,177, 36,255,178, 38,255,178, 42/
+data (heat(i),i=541,552) /255,179, 44,255,180, 48,255,182, 51,255,183, 53/
+data (heat(i),i=553,564) /255,184, 57,255,184, 59,255,185, 63,255,186, 65/
+data (heat(i),i=565,576) /255,187, 69,255,189, 71,255,190, 75,255,191, 77/
+data (heat(i),i=577,588) /255,191, 81,255,192, 83,255,193, 87,255,195, 89/
+data (heat(i),i=589,600) /255,196, 93,255,197, 95,255,197, 99,255,198,102/
+data (heat(i),i=601,612) /255,199,104,255,201,108,255,202,110,255,203,114/
+data (heat(i),i=613,624) /255,204,116,255,204,120,255,205,122,255,206,126/
+data (heat(i),i=625,636) /255,208,128,255,209,132,255,210,134,255,210,138/
+data (heat(i),i=637,648) /255,211,140,255,212,144,255,214,146,255,215,150/
+data (heat(i),i=649,660) /255,216,153,255,216,155,255,217,159,255,218,161/
+data (heat(i),i=661,672) /255,220,165,255,221,167,255,222,171,255,223,173/
+data (heat(i),i=673,684) /255,223,177,255,224,179,255,225,183,255,227,185/
+data (heat(i),i=685,696) /255,228,189,255,229,191,255,229,195,255,230,197/
+data (heat(i),i=697,708) /255,231,201,255,233,204,255,234,206,255,235,210/
+data (heat(i),i=709,720) /255,235,212,255,236,216,255,237,218,255,238,222/
+data (heat(i),i=721,732) /255,240,224,255,241,228,255,242,230,255,242,234/
+data (heat(i),i=733,744) /255,243,236,255,244,240,255,246,242,255,247,246/
+data (heat(i),i=745,756) /255,248,248,255,248,252,255,249,255,255,250,255/
+data (heat(i),i=757,768) /255,252,255,255,253,255,255,254,255,255,255,255/
+
+
+short rainbow[768]
+data (rainbow(i),i= 1, 12) / 0, 0, 42, 6, 0, 46, 14, 0, 51, 21, 0, 56/
+data (rainbow(i),i= 13, 24) / 29, 0, 61, 37, 0, 65, 44, 0, 70, 51, 0, 76/
+data (rainbow(i),i= 25, 36) / 58, 0, 81, 67, 0, 85, 75, 0, 90, 82, 0, 95/
+data (rainbow(i),i= 37, 48) / 89, 0,101, 96, 0,106,104, 0,110,112, 0,115/
+data (rainbow(i),i= 49, 60) /120, 0,121,127, 0,126,134, 0,131,141, 0,136/
+data (rainbow(i),i= 61, 72) /150, 0,141,141, 0,146,134, 0,152,127, 0,157/
+data (rainbow(i),i= 73, 84) /120, 0,163,112, 0,167,104, 0,172, 96, 0,178/
+data (rainbow(i),i= 85, 96) / 89, 0,184, 82, 0,189, 75, 0,195, 67, 0,199/
+data (rainbow(i),i= 97,108) / 58, 0,204, 51, 0,210, 44, 0,216, 37, 0,222/
+data (rainbow(i),i=109,120) / 29, 0,227, 21, 0,233, 14, 0,237, 6, 0,243/
+data (rainbow(i),i=121,132) / 0, 0,248, 0, 0,255, 0, 6,248, 0, 12,243/
+data (rainbow(i),i=133,144) / 0, 16,237, 0, 20,233, 0, 25,227, 0, 29,222/
+data (rainbow(i),i=145,156) / 0, 32,216, 0, 36,210, 0, 39,204, 0, 43,199/
+data (rainbow(i),i=157,168) / 0, 46,195, 0, 50,189, 0, 53,184, 0, 57,178/
+data (rainbow(i),i=169,180) / 0, 59,172, 0, 63,167, 0, 67,163, 0, 70,157/
+data (rainbow(i),i=181,192) / 0, 72,152, 0, 76,146, 0, 78,141, 0, 82,136/
+data (rainbow(i),i=193,204) / 0, 84,131, 0, 88,126, 0, 90,121, 0, 94,115/
+data (rainbow(i),i=205,216) / 0, 96,110, 0,100,106, 0,102,101, 0,104, 95/
+data (rainbow(i),i=217,228) / 0,108, 90, 0,110, 85, 0,114, 81, 0,116, 76/
+data (rainbow(i),i=229,240) / 0,119, 70, 0,121, 65, 0,125, 61, 0,127, 56/
+data (rainbow(i),i=241,252) / 0,129, 51, 0,133, 46, 0,134, 42, 0,138, 37/
+data (rainbow(i),i=253,264) / 0,140, 32, 0,142, 27, 0,146, 24, 0,148, 19/
+data (rainbow(i),i=265,276) / 0,151, 14, 0,153, 11, 0,155, 6, 0,159, 2/
+data (rainbow(i),i=277,288) / 0,160, 0, 0,164, 0, 0,165, 0, 0,169, 0/
+data (rainbow(i),i=289,300) / 0,171, 0, 0,173, 0, 0,176, 0, 0,178, 0/
+data (rainbow(i),i=301,312) / 0,180, 0, 0,184, 0, 0,185, 0, 0,189, 0/
+data (rainbow(i),i=313,324) / 0,191, 0, 0,193, 0, 0,196, 0, 0,197, 0/
+data (rainbow(i),i=325,336) / 0,201, 0, 0,203, 0, 0,205, 0, 0,208, 0/
+data (rainbow(i),i=337,348) / 0,210, 0, 0,212, 0, 0,215, 0, 0,217, 0/
+data (rainbow(i),i=349,360) / 0,220, 0, 0,222, 0, 0,224, 0, 0,227, 0/
+data (rainbow(i),i=361,372) / 0,229, 0, 0,231, 0, 0,234, 0, 0,235, 0/
+data (rainbow(i),i=373,384) / 0,238, 0, 0,241, 0, 0,242, 0, 0,244, 0/
+data (rainbow(i),i=385,396) / 0,248, 0, 0,249, 0, 0,252, 0, 0,255, 0/
+data (rainbow(i),i=397,408) / 0,252, 0, 0,249, 0, 0,248, 0, 0,244, 0/
+data (rainbow(i),i=409,420) / 0,242, 0, 0,241, 0, 0,238, 0, 0,235, 0/
+data (rainbow(i),i=421,432) / 0,234, 0, 0,231, 0, 0,229, 0, 0,227, 0/
+data (rainbow(i),i=433,444) / 0,224, 0, 0,222, 0, 0,220, 0, 0,217, 0/
+data (rainbow(i),i=445,456) / 0,215, 0, 0,212, 0, 0,210, 0, 0,208, 0/
+data (rainbow(i),i=457,468) / 0,205, 0, 0,203, 0, 0,201, 0, 0,197, 0/
+data (rainbow(i),i=469,480) / 1,196, 0, 8,197, 0, 17,201, 0, 25,204, 0/
+data (rainbow(i),i=481,492) / 32,206, 0, 42,210, 0, 51,215, 0, 59,218, 0/
+data (rainbow(i),i=493,504) / 68,222, 0, 77,227, 0, 87,229, 0, 95,235, 0/
+data (rainbow(i),i=505,516) /104,237, 0,114,242, 0,123,247, 0,133,252, 0/
+data (rainbow(i),i=517,528) /142,255, 0,152,255, 0,161,255, 0,171,255, 0/
+data (rainbow(i),i=529,540) /180,255, 0,191,255, 0,199,255, 0,210,255, 0/
+data (rainbow(i),i=541,552) /218,255, 0,229,255, 0,237,255, 0,248,255, 0/
+data (rainbow(i),i=553,564) /255,255, 0,255,255, 0,255,255, 0,255,255, 0/
+data (rainbow(i),i=565,576) /255,255, 0,255,255, 0,255,255, 0,254,255, 0/
+data (rainbow(i),i=577,588) /249,255, 0,244,248, 0,241,238, 0,235,229, 0/
+data (rainbow(i),i=589,600) /231,218, 0,228,209, 0,223,198, 0,218,189, 0/
+data (rainbow(i),i=601,612) /214,178, 0,210,169, 0,204,159, 0,201,148, 0/
+data (rainbow(i),i=613,624) /196,139, 0,192,129, 0,189,119, 0,184,109, 0/
+data (rainbow(i),i=625,636) /180,100, 0,177, 89, 0,173, 81, 0,169, 70, 0/
+data (rainbow(i),i=637,648) /165, 61, 0,161, 51, 0,159, 43, 0,157, 32, 0/
+data (rainbow(i),i=649,660) /154, 25, 0,158, 20, 0,159, 16, 0,163, 12, 0/
+data (rainbow(i),i=661,672) /165, 6, 0,167, 0, 0,170, 0, 0,172, 0, 0/
+data (rainbow(i),i=673,684) /174, 0, 0,178, 0, 0,180, 0, 0,183, 0, 0/
+data (rainbow(i),i=685,696) /185, 0, 0,187, 0, 0,191, 0, 0,192, 0, 0/
+data (rainbow(i),i=697,708) /196, 0, 0,197, 0, 0,201, 0, 0,204, 1, 1/
+data (rainbow(i),i=709,720) /205, 6, 6,209, 12, 12,210, 20, 20,214, 29, 29/
+data (rainbow(i),i=721,732) /216, 38, 38,218, 49, 49,221, 58, 58,223, 70, 70/
+data (rainbow(i),i=733,744) /225, 82, 82,229, 95, 95,231,109,109,234,123,123/
+data (rainbow(i),i=745,756) /236,138,138,238,153,153,242,169,169,243,184,184/
+data (rainbow(i),i=757,768) /247,202,202,248,218,218,252,236,236,255,255,255/
+
+
+short staircase[768]
+data (staircase(i),i= 1, 12) / 0, 0, 80, 1, 1, 80, 2, 2, 80, 4, 4, 80/
+data (staircase(i),i= 13, 24) / 5, 5, 80, 6, 6, 80, 6, 6, 80, 7, 7, 80/
+data (staircase(i),i= 25, 36) / 8, 8, 80, 10, 10, 80, 11, 11, 80, 12, 12, 80/
+data (staircase(i),i= 37, 48) / 12, 12, 80, 13, 13, 80, 14, 14, 80, 16, 16, 80/
+data (staircase(i),i= 49, 60) / 17, 17,120, 18, 18,120, 19, 19,120, 19, 19,120/
+data (staircase(i),i= 61, 72) / 20, 20,120, 21, 21,120, 23, 23,120, 24, 24,120/
+data (staircase(i),i= 73, 84) / 25, 25,120, 25, 25,120, 26, 26,120, 27, 27,120/
+data (staircase(i),i= 85, 96) / 29, 29,120, 30, 30,120, 31, 31,120, 31, 31,120/
+data (staircase(i),i= 97,108) / 32, 32,159, 33, 33,159, 34, 34,159, 36, 36,159/
+data (staircase(i),i=109,120) / 37, 37,159, 38, 38,159, 38, 38,159, 39, 39,159/
+data (staircase(i),i=121,132) / 40, 40,159, 42, 42,159, 43, 43,159, 44, 44,159/
+data (staircase(i),i=133,144) / 44, 44,159, 45, 45,159, 46, 46,159, 48, 48,159/
+data (staircase(i),i=145,156) / 49, 49,199, 50, 50,199, 51, 51,199, 51, 51,199/
+data (staircase(i),i=157,168) / 52, 52,199, 53, 53,199, 55, 55,199, 56, 56,199/
+data (staircase(i),i=169,180) / 57, 57,199, 57, 57,199, 58, 58,199, 59, 59,199/
+data (staircase(i),i=181,192) / 61, 61,199, 62, 62,199, 63, 63,199, 63, 63,199/
+data (staircase(i),i=193,204) / 64, 64,240, 65, 65,240, 67, 67,240, 68, 68,240/
+data (staircase(i),i=205,216) / 69, 69,240, 70, 70,240, 70, 70,240, 71, 71,240/
+data (staircase(i),i=217,228) / 72, 72,240, 74, 74,240, 75, 75,240, 76, 76,240/
+data (staircase(i),i=229,240) / 76, 76,240, 77, 77,240, 78, 78,240, 80, 80,240/
+data (staircase(i),i=241,252) / 81, 81,242, 82, 82,246, 82, 82,248, 83, 83,252/
+data (staircase(i),i=253,264) / 84, 84,255, 0, 80, 0, 1, 80, 1, 2, 80, 2/
+data (staircase(i),i=265,276) / 4, 80, 4, 5, 80, 5, 6, 80, 6, 6, 80, 6/
+data (staircase(i),i=277,288) / 7, 80, 7, 8, 80, 8, 10, 80, 10, 11, 80, 11/
+data (staircase(i),i=289,300) / 12, 80, 12, 12, 80, 12, 13, 80, 13, 14, 80, 14/
+data (staircase(i),i=301,312) / 16, 80, 16, 17,120, 17, 18,120, 18, 19,120, 19/
+data (staircase(i),i=313,324) / 19,120, 19, 20,120, 20, 21,120, 21, 23,120, 23/
+data (staircase(i),i=325,336) / 24,120, 24, 25,120, 25, 25,120, 25, 26,120, 26/
+data (staircase(i),i=337,348) / 27,120, 27, 29,120, 29, 30,120, 30, 31,120, 31/
+data (staircase(i),i=349,360) / 31,120, 31, 32,159, 32, 33,159, 33, 34,159, 34/
+data (staircase(i),i=361,372) / 36,159, 36, 37,159, 37, 38,159, 38, 38,159, 38/
+data (staircase(i),i=373,384) / 39,159, 39, 40,159, 40, 42,159, 42, 43,159, 43/
+data (staircase(i),i=385,396) / 44,159, 44, 44,159, 44, 45,159, 45, 46,159, 46/
+data (staircase(i),i=397,408) / 48,159, 48, 49,199, 49, 50,199, 50, 51,199, 51/
+data (staircase(i),i=409,420) / 51,199, 51, 52,199, 52, 53,199, 53, 55,199, 55/
+data (staircase(i),i=421,432) / 56,199, 56, 57,199, 57, 57,199, 57, 58,199, 58/
+data (staircase(i),i=433,444) / 59,199, 59, 61,199, 61, 62,199, 62, 63,199, 63/
+data (staircase(i),i=445,456) / 63,199, 63, 64,240, 64, 65,240, 65, 67,240, 67/
+data (staircase(i),i=457,468) / 68,240, 68, 69,240, 69, 70,240, 70, 70,240, 70/
+data (staircase(i),i=469,480) / 71,240, 71, 72,240, 72, 74,240, 74, 75,240, 75/
+data (staircase(i),i=481,492) / 76,240, 76, 76,240, 76, 77,240, 77, 78,240, 78/
+data (staircase(i),i=493,504) / 80,240, 80, 81,242, 81, 82,246, 82, 82,248, 82/
+data (staircase(i),i=505,516) / 83,252, 83, 84,255, 84, 80, 0, 0, 80, 1, 1/
+data (staircase(i),i=517,528) / 80, 2, 2, 80, 4, 4, 80, 5, 5, 80, 6, 6/
+data (staircase(i),i=529,540) / 80, 6, 6, 80, 7, 7, 80, 8, 8, 80, 10, 10/
+data (staircase(i),i=541,552) / 80, 11, 11, 80, 12, 12, 80, 12, 12, 80, 13, 13/
+data (staircase(i),i=553,564) / 80, 14, 14, 80, 16, 16,120, 17, 17,120, 18, 18/
+data (staircase(i),i=565,576) /120, 19, 19,120, 19, 19,120, 20, 20,120, 21, 21/
+data (staircase(i),i=577,588) /120, 23, 23,120, 24, 24,120, 25, 25,120, 25, 25/
+data (staircase(i),i=589,600) /120, 26, 26,120, 27, 27,120, 29, 29,120, 30, 30/
+data (staircase(i),i=601,612) /120, 31, 31,120, 31, 31,159, 32, 32,159, 33, 33/
+data (staircase(i),i=613,624) /159, 34, 34,159, 36, 36,159, 37, 37,159, 38, 38/
+data (staircase(i),i=625,636) /159, 38, 38,159, 39, 39,159, 40, 40,159, 42, 42/
+data (staircase(i),i=637,648) /159, 43, 43,159, 44, 44,159, 44, 44,159, 45, 45/
+data (staircase(i),i=649,660) /159, 46, 46,159, 48, 48,199, 49, 49,199, 50, 50/
+data (staircase(i),i=661,672) /199, 51, 51,199, 51, 51,199, 52, 52,199, 53, 53/
+data (staircase(i),i=673,684) /199, 55, 55,199, 56, 56,199, 57, 57,199, 57, 57/
+data (staircase(i),i=685,696) /199, 58, 58,199, 59, 59,199, 61, 61,199, 62, 62/
+data (staircase(i),i=697,708) /199, 63, 63,199, 63, 63,240, 64, 64,240, 65, 65/
+data (staircase(i),i=709,720) /240, 67, 67,240, 68, 68,240, 69, 69,240, 70, 70/
+data (staircase(i),i=721,732) /240, 70, 70,240, 71, 71,240, 72, 72,240, 74, 74/
+data (staircase(i),i=733,744) /240, 75, 75,240, 76, 76,240, 76, 76,240, 77, 77/
+data (staircase(i),i=745,756) /240, 78, 78,240, 80, 80,242,100,100,244,134,134/
+data (staircase(i),i=757,768) /248,170,170,250,204,204,253,204,204,255,255,255/
+
+
+short standard[768]
+data (standard(i),i= 1, 12) / 0, 0, 84, 1, 1, 87, 2, 2, 89, 4, 4, 90/
+data (standard(i),i= 13, 24) / 5, 5, 93, 6, 6, 95, 6, 6, 96, 7, 7, 99/
+data (standard(i),i= 25, 36) / 8, 8,101, 10, 10,102, 11, 11,104, 12, 12,107/
+data (standard(i),i= 37, 48) / 12, 12,108, 13, 13,110, 14, 14,113, 16, 16,114/
+data (standard(i),i= 49, 60) / 17, 17,116, 18, 18,119, 19, 19,121, 19, 19,122/
+data (standard(i),i= 61, 72) / 20, 20,125, 21, 21,127, 23, 23,128, 24, 24,131/
+data (standard(i),i= 73, 84) / 25, 25,133, 25, 25,134, 26, 26,136, 27, 27,139/
+data (standard(i),i= 85, 96) / 29, 29,140, 30, 30,142, 31, 31,145, 31, 31,146/
+data (standard(i),i= 97,108) / 32, 32,148, 33, 33,150, 34, 34,153, 36, 36,154/
+data (standard(i),i=109,120) / 37, 37,157, 38, 38,159, 38, 38,160, 39, 39,163/
+data (standard(i),i=121,132) / 40, 40,165, 42, 42,166, 43, 43,169, 44, 44,171/
+data (standard(i),i=133,144) / 44, 44,172, 45, 45,174, 46, 46,177, 48, 48,178/
+data (standard(i),i=145,156) / 49, 49,180, 50, 50,183, 51, 51,184, 51, 51,186/
+data (standard(i),i=157,168) / 52, 52,189, 53, 53,191, 55, 55,192, 56, 56,195/
+data (standard(i),i=169,180) / 57, 57,197, 57, 57,198, 58, 58,201, 59, 59,203/
+data (standard(i),i=181,192) / 61, 61,204, 62, 62,206, 63, 63,209, 63, 63,210/
+data (standard(i),i=193,204) / 64, 64,212, 65, 65,215, 67, 67,216, 68, 68,218/
+data (standard(i),i=205,216) / 69, 69,221, 70, 70,223, 70, 70,224, 71, 71,227/
+data (standard(i),i=217,228) / 72, 72,229, 74, 74,230, 75, 75,233, 76, 76,235/
+data (standard(i),i=229,240) / 76, 76,236, 77, 77,238, 78, 78,241, 80, 80,242/
+data (standard(i),i=241,252) / 81, 81,244, 82, 82,247, 82, 82,248, 83, 83,250/
+data (standard(i),i=253,264) / 84, 84,253, 0, 84, 0, 1, 87, 1, 2, 89, 2/
+data (standard(i),i=265,276) / 4, 90, 4, 5, 93, 5, 6, 95, 6, 6, 96, 6/
+data (standard(i),i=277,288) / 7, 99, 7, 8,101, 8, 10,102, 10, 11,104, 11/
+data (standard(i),i=289,300) / 12,107, 12, 12,108, 12, 13,110, 13, 14,113, 14/
+data (standard(i),i=301,312) / 16,114, 16, 17,116, 17, 18,119, 18, 19,121, 19/
+data (standard(i),i=313,324) / 19,122, 19, 20,125, 20, 21,127, 21, 23,128, 23/
+data (standard(i),i=325,336) / 24,131, 24, 25,133, 25, 25,134, 25, 26,136, 26/
+data (standard(i),i=337,348) / 27,139, 27, 29,140, 29, 30,142, 30, 31,145, 31/
+data (standard(i),i=349,360) / 31,146, 31, 32,148, 32, 33,150, 33, 34,153, 34/
+data (standard(i),i=361,372) / 36,154, 36, 37,157, 37, 38,159, 38, 38,160, 38/
+data (standard(i),i=373,384) / 39,163, 39, 40,165, 40, 42,166, 42, 43,169, 43/
+data (standard(i),i=385,396) / 44,171, 44, 44,172, 44, 45,174, 45, 46,177, 46/
+data (standard(i),i=397,408) / 48,178, 48, 49,180, 49, 50,183, 50, 51,184, 51/
+data (standard(i),i=409,420) / 51,186, 51, 52,189, 52, 53,191, 53, 55,192, 55/
+data (standard(i),i=421,432) / 56,195, 56, 57,197, 57, 57,198, 57, 58,201, 58/
+data (standard(i),i=433,444) / 59,203, 59, 61,204, 61, 62,206, 62, 63,209, 63/
+data (standard(i),i=445,456) / 63,210, 63, 64,212, 64, 65,215, 65, 67,216, 67/
+data (standard(i),i=457,468) / 68,218, 68, 69,221, 69, 70,223, 70, 70,224, 70/
+data (standard(i),i=469,480) / 71,227, 71, 72,229, 72, 74,230, 74, 75,233, 75/
+data (standard(i),i=481,492) / 76,235, 76, 76,236, 76, 77,238, 77, 78,241, 78/
+data (standard(i),i=493,504) / 80,242, 80, 81,244, 81, 82,247, 82, 82,248, 82/
+data (standard(i),i=505,516) / 83,250, 83, 84,253, 84, 84, 0, 0, 87, 1, 1/
+data (standard(i),i=517,528) / 89, 2, 2, 90, 4, 4, 93, 5, 5, 95, 6, 6/
+data (standard(i),i=529,540) / 96, 6, 6, 99, 7, 7,101, 8, 8,102, 10, 10/
+data (standard(i),i=541,552) /104, 11, 11,107, 12, 12,108, 12, 12,110, 13, 13/
+data (standard(i),i=553,564) /113, 14, 14,114, 16, 16,116, 17, 17,119, 18, 18/
+data (standard(i),i=565,576) /121, 19, 19,122, 19, 19,125, 20, 20,127, 21, 21/
+data (standard(i),i=577,588) /128, 23, 23,131, 24, 24,133, 25, 25,134, 25, 25/
+data (standard(i),i=589,600) /136, 26, 26,139, 27, 27,140, 29, 29,142, 30, 30/
+data (standard(i),i=601,612) /145, 31, 31,146, 31, 31,148, 32, 32,150, 33, 33/
+data (standard(i),i=613,624) /153, 34, 34,154, 36, 36,157, 37, 37,159, 38, 38/
+data (standard(i),i=625,636) /160, 38, 38,163, 39, 39,165, 40, 40,166, 42, 42/
+data (standard(i),i=637,648) /169, 43, 43,171, 44, 44,172, 44, 44,174, 45, 45/
+data (standard(i),i=649,660) /177, 46, 46,178, 48, 48,180, 49, 49,183, 50, 50/
+data (standard(i),i=661,672) /184, 51, 51,186, 51, 51,189, 52, 52,191, 53, 53/
+data (standard(i),i=673,684) /192, 55, 55,195, 56, 56,197, 57, 57,198, 57, 57/
+data (standard(i),i=685,696) /201, 58, 58,203, 59, 59,204, 61, 61,206, 62, 62/
+data (standard(i),i=697,708) /209, 63, 63,210, 63, 63,212, 64, 64,215, 65, 65/
+data (standard(i),i=709,720) /216, 67, 67,218, 68, 68,221, 69, 69,223, 70, 70/
+data (standard(i),i=721,732) /224, 70, 70,227, 71, 71,229, 72, 72,230, 74, 74/
+data (standard(i),i=733,744) /233, 75, 75,235, 76, 76,236, 76, 76,238, 77, 77/
+data (standard(i),i=745,756) /241, 78, 78,242, 80, 80,244, 81, 81,247, 82, 82/
+data (standard(i),i=757,768) /248, 82, 82,250, 83, 83,253, 84, 84,255, 85, 85/
+
+
+short overlay[768]
+data (overlay(i),i= 1, 12) / 0, 0, 0, 1, 1, 1, 3, 3, 3, 4, 4, 4/
+data (overlay(i),i= 13, 24) / 5, 5, 5, 6, 6, 6, 8, 8, 8, 9, 9, 9/
+data (overlay(i),i= 25, 36) / 10, 10, 10, 11, 11, 11, 13, 13, 13, 14, 14, 14/
+data (overlay(i),i= 37, 48) / 15, 15, 15, 17, 17, 17, 18, 18, 18, 19, 19, 19/
+data (overlay(i),i= 49, 60) / 20, 20, 20, 22, 22, 22, 23, 23, 23, 24, 24, 24/
+data (overlay(i),i= 61, 72) / 26, 26, 26, 27, 27, 27, 28, 28, 28, 29, 29, 29/
+data (overlay(i),i= 73, 84) / 31, 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, 34/
+data (overlay(i),i= 85, 96) / 36, 36, 36, 37, 37, 37, 38, 38, 38, 40, 40, 40/
+data (overlay(i),i= 97,108) / 41, 41, 41, 42, 42, 42, 43, 43, 43, 45, 45, 45/
+data (overlay(i),i=109,120) / 46, 46, 46, 47, 47, 47, 48, 48, 48, 50, 50, 50/
+data (overlay(i),i=121,132) / 51, 51, 51, 52, 52, 52, 54, 54, 54, 55, 55, 55/
+data (overlay(i),i=133,144) / 56, 56, 56, 57, 57, 57, 59, 59, 59, 60, 60, 60/
+data (overlay(i),i=145,156) / 61, 61, 61, 62, 62, 62, 64, 64, 64, 65, 65, 65/
+data (overlay(i),i=157,168) / 66, 66, 66, 68, 68, 68, 69, 69, 69, 70, 70, 70/
+data (overlay(i),i=169,180) / 71, 71, 71, 73, 73, 73, 74, 74, 74, 75, 75, 75/
+data (overlay(i),i=181,192) / 77, 77, 77, 78, 78, 78, 79, 79, 79, 80, 80, 80/
+data (overlay(i),i=193,204) / 82, 82, 82, 83, 83, 83, 84, 84, 84, 85, 85, 85/
+data (overlay(i),i=205,216) / 87, 87, 87, 88, 88, 88, 89, 89, 89, 91, 91, 91/
+data (overlay(i),i=217,228) / 92, 92, 92, 93, 93, 93, 94, 94, 94, 96, 96, 96/
+data (overlay(i),i=229,240) / 97, 97, 97, 98, 98, 98, 99, 99, 99,101,101,101/
+data (overlay(i),i=241,252) /102,102,102,103,103,103,105,105,105,106,106,106/
+data (overlay(i),i=253,264) /107,107,107,108,108,108,110,110,110,111,111,111/
+data (overlay(i),i=265,276) /112,112,112,113,113,113,115,115,115,116,116,116/
+data (overlay(i),i=277,288) /117,117,117,119,119,119,120,120,120,121,121,121/
+data (overlay(i),i=289,300) /122,122,122,124,124,124,125,125,125,126,126,126/
+data (overlay(i),i=301,312) /128,128,128,129,129,129,130,130,130,131,131,131/
+data (overlay(i),i=313,324) /133,133,133,134,134,134,135,135,135,136,136,136/
+data (overlay(i),i=325,336) /138,138,138,139,139,139,140,140,140,142,142,142/
+data (overlay(i),i=337,348) /143,143,143,144,144,144,145,145,145,147,147,147/
+data (overlay(i),i=349,360) /148,148,148,149,149,149,150,150,150,152,152,152/
+data (overlay(i),i=361,372) /153,153,153,154,154,154,156,156,156,157,157,157/
+data (overlay(i),i=373,384) /158,158,158,159,159,159,161,161,161,162,162,162/
+data (overlay(i),i=385,396) /163,163,163,164,164,164,166,166,166,167,167,167/
+data (overlay(i),i=397,408) /168,168,168,170,170,170,171,171,171,172,172,172/
+data (overlay(i),i=409,420) /173,173,173,175,175,175,176,176,176,177,177,177/
+data (overlay(i),i=421,432) /179,179,179,180,180,180,181,181,181,182,182,182/
+data (overlay(i),i=433,444) /184,184,184,185,185,185,186,186,186,187,187,187/
+data (overlay(i),i=445,456) /189,189,189,190,190,190,191,191,191,193,193,193/
+data (overlay(i),i=457,468) /194,194,194,195,195,195,196,196,196,198,198,198/
+data (overlay(i),i=469,480) /199,199,199,200,200,200,201,201,201,203,203,203/
+data (overlay(i),i=481,492) /204,204,204,205,205,205,207,207,207,208,208,208/
+data (overlay(i),i=493,504) /209,209,209,210,210,210,212,212,212,213,213,213/
+data (overlay(i),i=505,516) /214,214,214,215,215,215,217,217,217,218,218,218/
+data (overlay(i),i=517,528) /219,219,219,221,221,221,222,222,222,223,223,223/
+data (overlay(i),i=529,540) /224,224,224,226,226,226,227,227,227,228,228,228/
+data (overlay(i),i=541,552) /230,230,230,231,231,231,232,232,232,233,233,233/
+data (overlay(i),i=553,564) /235,235,235,236,236,236,237,237,237,238,238,238/
+data (overlay(i),i=565,576) /240,240,240,241,241,241,242,242,242,244,244,244/
+data (overlay(i),i=577,588) /245,245,245,246,246,246,247,247,247,249,249,249/
+data (overlay(i),i=589,600) /250,250,250,251,251,251,252,252,252,254,254,254/
+data (overlay(i),i=601,612) /255,255,255, 0, 0, 0,255,255,255,255, 0, 0/
+data (overlay(i),i=613,624) / 0,255, 0, 0, 0,255,255,255, 0, 0,255,255/
+data (overlay(i),i=625,636) /255, 0,255,255,127, 80,176, 48, 96,255,165, 0/
+data (overlay(i),i=637,648) /255,246,143,218,112,214, 0,245,255,238,130,238/
+data (overlay(i),i=649,660) /255,231,186, 0, 0, 0, 0, 0, 0, 0, 0, 0/
+data (overlay(i),i=661,672) / 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0/
+data (overlay(i),i=673,684) / 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0/
+data (overlay(i),i=685,696) / 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0/
+data (overlay(i),i=697,708) / 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0/
+data (overlay(i),i=709,720) / 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0/
+data (overlay(i),i=721,732) / 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0/
+data (overlay(i),i=733,744) / 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0/
+data (overlay(i),i=745,756) / 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0/
+data (overlay(i),i=757,768) / 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0/
diff --git a/pkg/dataio/export/exbltins.h b/pkg/dataio/export/exbltins.h
new file mode 100644
index 00000000..0723cdb2
--- /dev/null
+++ b/pkg/dataio/export/exbltins.h
@@ -0,0 +1,28 @@
+# EXBLTINS.H -- Macro definitions for builtin formats.
+
+define EX_FORMATS "|eps|epsi|epi|epsf|gif|giff|iraf|imh|miff|pgm|ppm|\
+ |ps|ras|sun|sunras|rgb|sgi|irix|xwd|x11|vicar2|"
+
+define EPS 1 # Encapsulated PostScript
+define EPSI 2 # Encapsulated PostScript (alias)
+define EPI 3 # Encapsulated PostScript (alias)
+define EPSF 4 # Encapsulated PostScript (alias)
+define GIF 5 # Compuserve GIF format
+define GIFF 6 # Compuserve GIF format (alias)
+define IRAF 7 # IRAF OIF format (hidden)
+define IMH 8 # IRAF OIF format (alias)
+define MIFF 9 # ImageMagick MIFF format
+define PGM 10 # PBMplus PGM grayscale format
+define PPM 11 # PBMplus PPM color format
+#newline
+define PS 13 # Sun rasterfile format
+define RAS 14 # Sun rasterfile format
+define SUN 15 # Sun rasterfile format (alias)
+define SUNRAS 16 # Sun rasterfile format (alias)
+define RGB 17 # Silicon Graphics RGB format
+define SGI 18 # Silicon Graphics RGB format (alias)
+define IRIS 19 # Silicon Graphics RGB format (alias)
+define XWD 20 # X11 Window dump
+define X11 21 # X11 Window dump (alias)
+define VICAR 22 # VICAR2 format
+
diff --git a/pkg/dataio/export/exbltins.x b/pkg/dataio/export/exbltins.x
new file mode 100644
index 00000000..bb0152dd
--- /dev/null
+++ b/pkg/dataio/export/exbltins.x
@@ -0,0 +1,243 @@
+include <mach.h>
+include "export.h"
+include "exbltins.h"
+
+
+# EXb_BUILTIN - Process a builtin format.
+
+procedure exb_process_image (ex)
+
+pointer ex #i task struct pointer
+
+begin
+ # Branch to the appropriate procedure for processing.
+ switch (EX_BLTIN(ex)) {
+ case EPS: # Encapsulated PostScript
+ call ex_eps (ex)
+ case GIF: # GIF
+ call ex_gif (ex)
+ case IMH: # IRAF OIF
+ call ex_iraf (ex)
+ case MIFF: # ImageMagick MIFF file
+ call ex_miff (ex)
+ case PGM: # PBMplus PGM (grayscale) file
+ call ex_pgm (ex)
+ case PPM: # PBMplus PPM (RGB) file
+ call ex_ppm (ex)
+ case RAS: # Sun rasterfile
+ call ex_ras (ex)
+ case RGB: # SGI RGB format file
+ call ex_rgb (ex)
+ case XWD: # X11 Window Dump
+ call ex_xwd (ex)
+ case VICAR: # JPL VICAR2 format image
+ call ex_vicar (ex)
+ default:
+ call error (0, "Unrecognized format")
+ }
+end
+
+
+# EXB_CHKPARS - Check the parameters for the builtin parameters.
+
+int procedure exb_chkpars (ex)
+
+pointer ex #i task struct pointer
+
+int legal, fmt
+
+begin
+ # Do a quick check that the number of expressions is valid for
+ # the requested format.
+ legal = NO
+ fmt = EX_BLTIN(ex)
+ switch (EX_NEXPR(ex)) {
+ case 1:
+ # PPM is the only format required to have 3 expressions.
+ if (fmt != PPM)
+ legal = YES
+ case 3:
+ if (fmt == PPM || fmt == RAS || fmt == RGB ||
+ fmt == XWD || fmt == EPS || fmt == MIFF)
+ legal = YES
+ case 4:
+ if (fmt == RAS || fmt == XWD)
+ legal = YES
+ case EX_UNDEFINED: # let it slide for now....
+ legal = YES
+ default:
+ if (bitset (EX_OUTFLAGS(ex), OF_BAND))
+ legal = YES
+ }
+ if (legal == NO) {
+ call error (1, "Wrong no. of expressions for requested format")
+ return (ERR)
+ }
+
+ # Check the bswap param. If it's set but ignored by a given format
+ # warn the user.
+ if (EX_BSWAP(ex) != S_NONE && (fmt != RAS && fmt != XWD)) {
+ call eprintf ("Warning: `bswap' parameter will be ignored")
+ return (ERR)
+ }
+
+ return (OK)
+end
+
+
+# EXB_DO_FORMAT - Process a builtin task format parameter and set appropriate
+# flags.
+
+procedure exb_do_format (ex, format)
+
+pointer ex #i task struct pointer
+char format[ARB] #i format parameter value
+
+char fmt[SZ_FNAME]
+int strdic()
+
+begin
+ switch (strdic (format, fmt, SZ_FNAME, EX_FORMATS)) {
+ case EPS, EPSI, EPI, EPSF, PS:
+ EX_BLTIN(ex) = EPS
+ EX_COLOR(ex) = YES
+ case GIF, GIFF:
+ EX_BLTIN(ex) = GIF
+ EX_COLOR(ex) = YES
+ case IMH, IRAF:
+ EX_BLTIN(ex) = IMH
+ EX_COLOR(ex) = NO
+ case MIFF:
+ EX_BLTIN(ex) = MIFF
+ EX_COLOR(ex) = YES
+ case PGM:
+ EX_BLTIN(ex) = PGM
+ EX_COLOR(ex) = NO
+ case PPM:
+ EX_BLTIN(ex) = PPM
+ EX_COLOR(ex) = NO
+ case RAS, SUN, SUNRAS:
+ EX_BLTIN(ex) = RAS
+ EX_COLOR(ex) = YES
+ case RGB, SGI, IRIS:
+ EX_BLTIN(ex) = RGB
+ EX_COLOR(ex) = NO
+ case XWD, X11:
+ EX_BLTIN(ex) = XWD
+ EX_COLOR(ex) = YES
+ case VICAR:
+ EX_BLTIN(ex) = VICAR
+ EX_COLOR(ex) = NO
+ default:
+ call error (2, "Unknown format.")
+ }
+end
+
+
+# EXB_PNAME - Print verbose name of the format.
+
+procedure exb_pname (ex)
+
+pointer ex #i task struct pointer
+
+begin
+ switch (EX_BLTIN(ex)) {
+ case EPS:
+ call pargstr ("Encapsulated PostScript")
+ case GIF:
+ call pargstr ("GIF")
+ case MIFF:
+ call pargstr ("ImageMagick MIFF")
+ case PGM:
+ call pargstr ("PGM")
+ case PPM:
+ call pargstr ("PPM")
+ case RAS:
+ call pargstr ("Sun Rasterfile")
+ case RGB:
+ call pargstr ("SGI RGB")
+ case XWD:
+ call pargstr ("X11 Window Dump")
+ case VICAR:
+ call pargstr ("JPL VICAR2 Image")
+ default:
+ call pargstr ("")
+ }
+end
+
+
+# EXB_PENDIAN - Print byte order of the format.
+
+procedure exb_pendian (ex)
+
+pointer ex #i task struct pointer
+
+begin
+ switch (EX_BLTIN(ex)) {
+ case GIF:
+ call pargstr ("Least Significant Byte First")
+ default:
+ if (EX_BSWAP(ex) == 0 && (BYTE_SWAP2==NO || BYTE_SWAP4==NO))
+ call pargstr ("Most Significant Byte First")
+ else
+ call pargstr ("Least Significant Byte First")
+ }
+end
+
+
+# EXB_PSTORAGE - Print pixel storage type of the format.
+
+procedure exb_pstorage (ex)
+
+pointer ex #i task struct pointer
+
+int flags
+
+begin
+ switch (EX_BLTIN(ex)) {
+ case GIF:
+ call pargstr ("LZW compressed bytes")
+ case RGB:
+ call pargstr ("Band interleaved")
+ default:
+ flags = EX_OUTFLAGS(ex)
+ if (bitset(flags, OF_BAND) || bitset(flags,BAND_STORAGE))
+ call pargstr ("Band Interleaved")
+ else if (bitset(flags, OF_LINE) || bitset(flags,LINE_STORAGE))
+ call pargstr ("Line Interleaved")
+ else if (bitset(flags,PIXEL_STORAGE))
+ call pargstr ("Pixel Interleaved")
+ else
+ call pargstr ("Unknown")
+ }
+end
+
+
+# EXB_FMT_EXT - Print the name of the builtin format. The returned pointer
+# must be freed by the calling procedure.
+
+pointer procedure exb_fmt_ext (ex)
+
+pointer ex #i task struct pointer
+
+pointer suf
+
+begin
+ call malloc (suf, SZ_FNAME, TY_CHAR)
+
+ switch (EX_BLTIN(ex)) {
+ case EPS: call strcpy (".eps", Memc[suf], SZ_FNAME)
+ case GIF: call strcpy (".gif", Memc[suf], SZ_FNAME)
+ case IMH: call strcpy (".imh", Memc[suf], SZ_FNAME)
+ case MIFF: call strcpy (".miff", Memc[suf], SZ_FNAME)
+ case PGM: call strcpy (".pgm", Memc[suf], SZ_FNAME)
+ case PPM: call strcpy (".ppm", Memc[suf], SZ_FNAME)
+ case RAS: call strcpy (".ras", Memc[suf], SZ_FNAME)
+ case RGB: call strcpy (".rgb", Memc[suf], SZ_FNAME)
+ case XWD: call strcpy (".xwd", Memc[suf], SZ_FNAME)
+ case VICAR: call strcpy (".vic", Memc[suf], SZ_FNAME)
+ default: Memc[suf] = EOS
+ }
+
+ return (suf)
+end
diff --git a/pkg/dataio/export/excmap.x b/pkg/dataio/export/excmap.x
new file mode 100644
index 00000000..486813ef
--- /dev/null
+++ b/pkg/dataio/export/excmap.x
@@ -0,0 +1,258 @@
+include <lexnum.h>
+include "export.h"
+
+
+define EX_COLORMAPS "|aips0|blue|color|grayscale|greyscale|green|halley\
+ |heat|rainbow|red|staircase|standard|overlay|"
+
+define AIPS0 1 # builtin colormaps
+define BLUE 2
+define COLOR 3
+define GRAYSCALE 4
+define GREYSCALE 5
+define GREEN 6
+define HALLEY 7
+define HEAT 8
+define RAINBOW 9
+define RED 10
+define STAIRCASE 11
+define STANDARD 12
+define OVERLAY 13
+
+
+# EX_READ_CMAP - Read a colormap into the colormap structure. We assume the
+# colormap is either a normalized CLT of RGB values between zero and one, or
+# RGB integer values between 0 and 255. The format of the file is three
+# values per line given as a red, green, and blue color. If the first line
+# contains a single number assume it's the number of colors. A maximum of
+# 256 colors will be read, if fewer values are read the remaining colors will
+# be filled with zeros.
+
+procedure ex_read_cmap (ex, cmname)
+
+pointer ex #i colormap pointer
+char cmname[ARB] #i colormap file name
+
+pointer cmap
+pointer sp, line
+real r, g, b, scale
+int i, stat, fd, type, ncolors
+
+int open(), fscan(), nscan()
+int getline(), lexnum(), strdic()
+errchk open
+
+define rdmap_ 99
+
+begin
+ # See if this is a builtin colormap request.
+ if (strdic(cmname,cmname,SZ_LINE,EX_COLORMAPS) > 0) {
+ call ex_bltin_cmap (ex, cmname)
+ return
+ }
+
+ # Open the colormap filename.
+ iferr (fd = open (cmname, READ_ONLY, TEXT_FILE))
+ call error (0, "Cannot open requested colormap file.")
+
+ # Check the first line to see if it's the number of colors or a
+ # CLT entry.
+ stat = fscan (fd)
+ call gargr (r)
+ call gargr (g)
+ call gargr (b)
+ if (nscan() == 1) {
+ ncolors = r
+ goto rdmap_
+ } else if (nscan() == 3) {
+ call seek (fd, BOF)
+rdmap_ call smark (sp)
+ call salloc (line, SZ_LINE, TY_CHAR)
+ stat = getline (fd, Memc[line])
+ i = 1
+ ncolors = 256
+ type = lexnum (Memc[line], i, stat)
+
+ if (type == LEX_REAL)
+ scale = 255.0
+ else if (type == LEX_DECIMAL)
+ scale = 1.0
+ else
+ call error (0, "Colormap file has an unknown format.")
+
+ call sfree (sp)
+ } else
+ call error (1, "Colormap file has an unknown format.")
+
+ # Read in a normalize colormap file.
+ cmap = EX_CMAP(ex)
+ for (i=1; fscan(fd) != EOF && i <= ncolors; i=i+1) {
+ call gargr (r)
+ call gargr (g)
+ call gargr (b)
+
+ CMAP(cmap,EX_RED,i) = max (0, min (255, int (r * scale + 0.5)))
+ CMAP(cmap,EX_GREEN,i) = max (0, min (255, int (g * scale + 0.5)))
+ CMAP(cmap,EX_BLUE,i) = max (0, min (255, int (b * scale + 0.5)))
+ }
+ ncolors = i
+ EX_NCOLORS(ex) = ncolors
+
+ # Close the file.
+ call close (fd)
+end
+
+
+# EX_SCALE_CMAP - Scale the colormap with the requested brightness and
+# contrast values.
+
+procedure ex_scale_cmap (cmap, ncolors, brightness, contrast)
+
+pointer cmap #i colormap pointer
+int ncolors #i number of colors in map
+real brightness #i brightness offset
+real contrast #i contrast scale
+
+pointer sp, ctmp
+int i, c1, c2
+short r, g, b
+real x, y, z, frac, slope, offset
+
+begin
+ call smark (sp)
+ call salloc (ctmp, 3*CMAP_SIZE, TY_CHAR)
+ call aclrc (Memc[ctmp], 3*CMAP_SIZE)
+
+ slope = max (-7.0, min (7.0, contrast))
+ offset = max (0.0, min (1.0, brightness))
+
+ # Compute the scaled colormap.
+ do i = 1, ncolors {
+ x = real (i) / real (ncolors)
+ y = (x - offset) * slope + 0.5
+
+ if (y <= 0.0) {
+ r = CMAP(cmap,EX_RED, 1)
+ g = CMAP(cmap,EX_GREEN,1)
+ b = CMAP(cmap,EX_BLUE, 1)
+ } else if (y >= 1.0) {
+ r = CMAP(cmap,EX_RED, ncolors)
+ g = CMAP(cmap,EX_GREEN,ncolors)
+ b = CMAP(cmap,EX_BLUE, ncolors)
+ } else {
+ z = y * (ncolors - 1)
+ c1 = max (1, int (z))
+ c2 = min (ncolors-1, c1 + 1)
+ frac = z - c1
+ r = CMAP(cmap,EX_RED,c1) * (1.0 - frac) +
+ CMAP(cmap,EX_RED,c2) * frac
+ g = CMAP(cmap,EX_GREEN,c1) * (1.0 - frac) +
+ CMAP(cmap,EX_GREEN,c2) * frac
+ b = CMAP(cmap,EX_BLUE,c1) * (1.0 - frac) +
+ CMAP(cmap,EX_BLUE,c2) * frac
+ }
+
+ CMAP(ctmp,EX_RED, i) = r
+ CMAP(ctmp,EX_GREEN,i) = g
+ CMAP(ctmp,EX_BLUE, i) = b
+ }
+ call amovc (Memc[ctmp], Memc[cmap], 3*CMAP_SIZE)
+
+ call sfree (sp)
+end
+
+
+# EX_BLTIN_CMAP - Load a predefined colormap.
+
+procedure ex_bltin_cmap (ex, cmname)
+
+pointer ex #i task struct pointer
+char cmname[ARB] #i colormap name
+
+pointer cmap
+int i, j, strdic()
+
+include "cmaps.inc"
+
+begin
+ j = 1
+ cmap = EX_CMAP(ex)
+ EX_NCOLORS(ex) = CMAP_SIZE
+
+ switch (strdic (cmname, cmname, SZ_LINE, EX_COLORMAPS)) {
+ case AIPS0:
+ do i = 1, 256 {
+ CMAP(cmap,EX_RED,i) = aips0[j]
+ CMAP(cmap,EX_GREEN,i) = aips0[j+1]
+ CMAP(cmap,EX_BLUE,i) = aips0[j+2]
+ j = j + 3
+ }
+ case BLUE:
+ call aclrs (Mems[cmap], 3*CMAP_SIZE)
+ do i = 1, 256
+ CMAP(cmap,EX_BLUE,i) = i - 1
+ case COLOR:
+ do i = 1, 256 {
+ CMAP(cmap,EX_RED,i) = color[j]
+ CMAP(cmap,EX_GREEN,i) = color[j+1]
+ CMAP(cmap,EX_BLUE,i) = color[j+2]
+ j = j + 3
+ }
+ case GRAYSCALE, GREYSCALE:
+ do i = 1, 256 {
+ CMAP(cmap,EX_RED,i) = i - 1
+ CMAP(cmap,EX_GREEN,i) = i - 1
+ CMAP(cmap,EX_BLUE,i) = i - 1
+ }
+ case GREEN:
+ call aclrs (Mems[cmap], 3*CMAP_SIZE)
+ do i = 1, 256
+ CMAP(cmap,EX_GREEN,i) = i - 1
+ case HALLEY:
+ do i = 1, 256 {
+ CMAP(cmap,EX_RED,i) = halley[j]
+ CMAP(cmap,EX_GREEN,i) = halley[j+1]
+ CMAP(cmap,EX_BLUE,i) = halley[j+2]
+ j = j + 3
+ }
+ case HEAT:
+ do i = 1, 256 {
+ CMAP(cmap,EX_RED,i) = heat[j]
+ CMAP(cmap,EX_GREEN,i) = heat[j+1]
+ CMAP(cmap,EX_BLUE,i) = heat[j+2]
+ j = j + 3
+ }
+ case RAINBOW:
+ do i = 1, 256 {
+ CMAP(cmap,EX_RED,i) = rainbow[j]
+ CMAP(cmap,EX_GREEN,i) = rainbow[j+1]
+ CMAP(cmap,EX_BLUE,i) = rainbow[j+2]
+ j = j + 3
+ }
+ case RED:
+ call aclrs (Mems[cmap], 3*CMAP_SIZE)
+ do i = 1, 256
+ CMAP(cmap,EX_RED,i) = i - 1
+ case STAIRCASE:
+ do i = 1, 256 {
+ CMAP(cmap,EX_RED,i) = staircase[j]
+ CMAP(cmap,EX_GREEN,i) = staircase[j+1]
+ CMAP(cmap,EX_BLUE,i) = staircase[j+2]
+ j = j + 3
+ }
+ case STANDARD:
+ do i = 1, 256 {
+ CMAP(cmap,EX_RED,i) = standard[j]
+ CMAP(cmap,EX_GREEN,i) = standard[j+1]
+ CMAP(cmap,EX_BLUE,i) = standard[j+2]
+ j = j + 3
+ }
+ case OVERLAY:
+ do i = 1, 256 {
+ CMAP(cmap,EX_RED,i) = overlay[j]
+ CMAP(cmap,EX_GREEN,i) = overlay[j+1]
+ CMAP(cmap,EX_BLUE,i) = overlay[j+2]
+ j = j + 3
+ }
+ }
+end
diff --git a/pkg/dataio/export/exfcn.h b/pkg/dataio/export/exfcn.h
new file mode 100644
index 00000000..7a9c61b3
--- /dev/null
+++ b/pkg/dataio/export/exfcn.h
@@ -0,0 +1,25 @@
+# EXFCN.H - Include file for the special functions supported by the EXPORT task.
+
+# Outbands expressions functions.
+define OB_FUNCTIONS "|band|line|flipx|flipy|\
+ |cmap|setcmap|psdpi|psscale|\
+ |zscale|grey|gray|bscale|gamma|\
+ |block|"
+
+define BAND 1 # force band-interleaved storage
+define LINE 2 # force line-interleaved storage
+define FLIPX 3 # flip image left-to-right
+define FLIPY 4 # flip image top-to-bottom
+#newline
+define CMAP 6 # create 8-bit colormap
+define SETCMAP 7 # apply a colormap
+define PSDPI 8 # set dpi for output
+define PSSCALE 9 # set scale of PS output
+#newline
+define ZSCALE 11 # scale to a fixed number of bins
+define GREY 12 # RGB to greyscale conversion
+define GRAY 13 # " " " "
+define BSCALE 14 # linearly transform intensity scale
+define GAMMA 15 # apply a gamma correction
+#newline
+define BLOCK 17 # floodfill a block w/ a constant
diff --git a/pkg/dataio/export/exhdr.x b/pkg/dataio/export/exhdr.x
new file mode 100644
index 00000000..9ba56a99
--- /dev/null
+++ b/pkg/dataio/export/exhdr.x
@@ -0,0 +1,207 @@
+include <error.h>
+include <fset.h>
+include <imhdr.h>
+include <imio.h>
+include <time.h>
+include <mach.h>
+include "export.h"
+
+
+# EX_WHEADER - Write the output file header information.
+
+procedure ex_wheader (ex, outfile)
+
+pointer ex #i task struct pointer
+char outfile[ARB] #i output file name
+
+pointer sp, tfile, buf, cbuf
+int file_type, nchars
+
+int fd, open(), access(), strlen()
+long fsize, fstatl()
+
+errchk open, access
+
+begin
+ if (EX_HEADER(ex) == HDR_SHORT || EX_HEADER(ex) == HDR_LONG) {
+
+ call smark (sp)
+ call salloc (tfile, SZ_PATHNAME, TY_CHAR)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+ call salloc (cbuf, SZ_LINE, TY_CHAR)
+ call aclrc (Memc[buf], SZ_LINE)
+ call aclrc (Memc[cbuf], SZ_LINE)
+
+ # Write the generic header.
+ call mktemp ("tmp$ex", Memc[tfile], SZ_PATHNAME)
+ fd = open (Memc[tfile], NEW_FILE, TEXT_FILE)
+ call ex_mkheader (ex, fd)
+ call close (fd)
+
+ if (EX_FORMAT(ex) != FMT_LIST)
+ fd = open (Memc[tfile], READ_ONLY, BINARY_FILE)
+ else
+ fd = open (Memc[tfile], READ_ONLY, TEXT_FILE)
+ fsize = fstatl (fd, F_FILESIZE) * SZB_CHAR
+ nchars = fsize + 27 #+ fsize/10
+ call sprintf (Memc[buf], SZ_LINE, "format = EXPORT\nhdrsize = %d\n")
+ call pargi (nchars)
+ nchars = strlen (Memc[buf])
+ if (EX_FD(ex) != STDOUT && EX_FORMAT(ex) != FMT_LIST) {
+ call strpak (Memc[buf], Memc[cbuf], nchars)
+ call write (EX_FD(ex), Memc[cbuf], nchars/SZB_CHAR)
+ call fcopyo (fd, EX_FD(ex))
+ call close (fd)
+ } else {
+ call fprintf (EX_FD(ex), "%s")
+ call pargstr (Memc[buf])
+ if (EX_FORMAT(ex) == FMT_LIST)
+ call fcopyo (fd, EX_FD(ex))
+ else
+ call fcopy (Memc[tfile], "STDOUT")
+
+ call close (fd)
+ }
+
+ call delete (Memc[tfile])
+ call sfree (sp)
+
+ } else if (EX_HEADER(ex) == HDR_USER) {
+ # Copy user file to output.
+ iferr {
+ # If the user header is a text file we need to reopen the
+ # output file so the copy is done correctly. Afterwards
+ # we'll reopen it as a binary file.
+ if (access (HDRFILE(ex), 0, TEXT_FILE) == YES) {
+ file_type = TEXT_FILE
+ call close (EX_FD(ex))
+ EX_FD(ex) = open (outfile, APPEND, file_type)
+ } else
+ file_type = BINARY_FILE
+
+ fd = open (HDRFILE(ex), READ_ONLY, file_type)
+ call fcopyo (fd, EX_FD(ex))
+ if (EX_FD(ex) != STDOUT)
+ call close (fd)
+
+ if (file_type == TEXT_FILE) {
+ if (EX_FD(ex) != STDOUT)
+ call close (EX_FD(ex))
+ if (EX_FORMAT(ex) != FMT_LIST)
+ EX_FD(ex) = open (outfile, APPEND, BINARY_FILE)
+ }
+ } then
+ call error (2, "Error writing user header.")
+ }
+end
+
+
+# EX_MKHEADER - Write the generic binary file header. Since we need to
+# output the size we'll write out just the trailer part to the temp file
+# and copy it to the real output file later.
+
+procedure ex_mkheader (ex, fd)
+
+pointer ex #i task struct pointer
+int fd #i temp file descriptor
+
+long clktime() # seconds since 00:00:00 10-Jan-80
+int tm[LEN_TMSTRUCT] # broken down time structure
+
+begin
+ # Write the time stamp string.
+ call brktime (clktime(0), tm)
+ call fprintf (fd, "date = '%d/%d/%d'\n")
+ call pargi (TM_MDAY(tm))
+ call pargi (TM_MONTH(tm))
+ call pargi (TM_YEAR(tm))
+
+ # ... and the rest of the header
+ call fprintf (fd, "ncols = %d\n") # image dimensions
+ call pargi (EX_OCOLS(ex))
+ call fprintf (fd, "nrows = %d\n")
+ call pargi (EX_OROWS(ex))
+ call fprintf (fd, "nbands = %d\n")
+ call pargi (EX_NEXPR(ex))
+
+ call fprintf (fd, "datatype = '%s'\n") # pixel type
+ call pargstr (Memc[EX_OTPTR(ex)])
+
+ call fprintf (fd, "outbands = '%s'\n") # outbands expressions
+ call pargstr (Memc[EX_OBPTR(ex)])
+
+ call fprintf (fd, "interleave = %d\n") # pixel interleave type
+ call pargi (EX_INTERLEAVE(ex))
+
+ call fprintf (fd, "bswap = %s\n") # byte swapping flag
+ switch (EX_BSWAP(ex)) {
+ case S_NONE: call pargstr ("none")
+ case S_ALL: call pargstr ("all")
+ case S_I2: call pargstr ("i2")
+ case S_I4: call pargstr ("i4")
+ }
+
+ if (EX_HEADER(ex) == HDR_LONG)
+ call ex_wimhdr (ex, fd) # write image headers
+
+ # Terminate header.
+ call fprintf (fd, "end\n")
+end
+
+
+# EX_WIMHDR - Write the image header information. Include the headers if this
+# is a verbose output.
+
+procedure ex_wimhdr (ex, fd)
+
+pointer ex #i task struct pointer
+int fd #i temp file descriptor
+
+pointer sp, lbuf, ip, im
+int i, in, ncols, min_lenuserarea
+int stropen(), getline(), envgeti()
+
+define USER_AREA Memc[($1+IMU-1)*SZ_STRUCT + 1]
+define LMARGIN 4
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+
+ do i = 1, EX_NIMAGES(ex) {
+
+ im = IO_IMPTR(IMOP(ex,i))
+ call fprintf (fd, "image%d = '%s'\n")
+ call pargi (i)
+ call pargstr (IM_HDRFILE(im))
+ call fprintf (fd, "header%d {\n")
+ call pargi (i)
+
+ # Open user area in header.
+ min_lenuserarea = (LEN_IMDES+IM_LENHDRMEM(im)-IMU) * SZ_STRUCT - 1
+ in = stropen (USER_AREA(im), min_lenuserarea, READ_ONLY)
+ ncols = envgeti ("ttyncols") - LMARGIN
+
+ # Copy header records to the output, stripping any trailing
+ # whitespace and clipping at the right margin.
+
+ while (getline (in, Memc[lbuf]) != EOF) {
+ for (ip=lbuf; Memc[ip] != EOS && Memc[ip] != '\n'; ip=ip+1)
+ ;
+ while (ip > lbuf && Memc[ip-1] == ' ')
+ ip = ip - 1
+ if (ip - lbuf > ncols)
+ ip = lbuf + ncols
+ Memc[ip] = '\n'
+ Memc[ip+1] = EOS
+
+ call putline (fd, " ")
+ call putline (fd, Memc[lbuf])
+ }
+
+ call fprintf (fd, "}\n")
+ }
+
+ call close (in)
+ call sfree (sp)
+end
diff --git a/pkg/dataio/export/exobands.gx b/pkg/dataio/export/exobands.gx
new file mode 100644
index 00000000..cd7313a3
--- /dev/null
+++ b/pkg/dataio/export/exobands.gx
@@ -0,0 +1,390 @@
+include <error.h>
+include <mach.h>
+include <evvexpr.h>
+include <fset.h>
+include <ctype.h>
+include "../export.h"
+include "../exfcn.h"
+
+define DEBUG false
+define VDEBUG false
+
+
+# EX_EVALUATE -- Evaluate the outbands expression.
+
+pointer procedure ex_evaluate (ex, expr)
+
+pointer ex #i task struct pointer
+char expr[ARB] #i expression to be evaluated
+
+pointer o # operand pointer to result
+
+int locpr()
+pointer evvexpr()
+extern ex_getop(), ex_obfcn()
+errchk evvexpr
+
+begin
+ if (DEBUG) { call eprintf("ex_eval: expr='%s'\n") ; call pargstr(expr) }
+
+ # Evaluate the expression.
+ iferr {
+ o = evvexpr (expr, locpr(ex_getop), ex, locpr(ex_obfcn), ex,
+ EV_RNGCHK)
+ } then
+ call erract (EA_FATAL)
+
+ return (o)
+end
+
+
+# EX_GETOP -- Called by evvexpr to get an operand.
+
+procedure ex_getop (ex, opname, o)
+
+pointer ex #i task struct pointer
+char opname[ARB] #i operand name to retrieve
+pointer o #o output operand pointer
+
+int i, nops, found, optype, imnum
+pointer sp, buf
+pointer op, param, emsg
+pointer im
+
+#int ex_ptype()
+int imgeti(), imgftype(), btoi(), ctoi()
+bool streq(), imgetb()
+double imgetd()
+
+define getpar_ 99
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+ call salloc (param, SZ_FNAME, TY_CHAR)
+ call salloc (emsg, SZ_LINE, TY_CHAR)
+ call aclrc (Memc[buf], SZ_LINE)
+ call aclrc (Memc[param], SZ_FNAME)
+ call aclrc (Memc[emsg], SZ_LINE)
+
+ if (VDEBUG) { call eprintf ("getop: opname=%s ");call pargstr(opname)}
+
+ # First see if it's one of the special image operands that was
+ # referenced in an "@param" call.
+
+ if (((opname[1] != 'i' && opname[1] != 'b') && !IS_DIGIT(opname[2])) ||
+ (opname[1] == 'i' && opname[2] == '_')) {
+ call strcpy (opname, Memc[param], SZ_FNAME)
+ im = IO_IMPTR(IMOP(ex,1))
+getpar_ O_LEN(o) = 0
+ switch (imgftype (im, Memc[param])) {
+ case TY_BOOL:
+ O_TYPE(o) = TY_BOOL
+ O_VALI(o) = btoi (imgetb (im, Memc[param]))
+ case TY_CHAR:
+ O_TYPE(o) = TY_CHAR
+ O_LEN(o) = SZ_LINE
+ call malloc (O_VALP(o), SZ_LINE, TY_CHAR)
+ call imgstr (im, Memc[param], O_VALC(o), SZ_LINE)
+ case TY_INT:
+ O_TYPE(o) = TY_INT
+ O_VALI(o) = imgeti (im, Memc[param])
+ case TY_REAL:
+ O_TYPE(o) = TY_DOUBLE
+ O_VALD(o) = imgetd (im, Memc[param])
+ default:
+ call sprintf (Memc[emsg], SZ_LINE, "param %s not found\n")
+ call pargstr (Memc[param])
+ call error (6, Memc[emsg])
+ }
+
+ call sfree (sp)
+ return
+
+ } else if (IS_LOWER(opname[1]) && opname[3] == '.') {
+ # This is a tag.param operand. Break out the image tag name and
+ # get the image pointer for it, then get the parameter
+ if (opname[1] == 'b') { # band of 3-D image, only 1 ptr
+ imnum = 1
+ } else if (opname[1] == 'i') { # image descriptor
+ i = 2
+ if (ctoi (opname, i, imnum) == 0)
+ call error (6, "can't parse operand")
+ } else {
+ call sprintf (Memc[buf], SZ_LINE,
+ "Unknown outbands operand `%s'\n")
+ call pargstr(opname)
+ call error (1, Memc[buf])
+ }
+
+ # Get the parameter value.
+ im = IO_IMPTR(IMOP(ex,imnum))
+ call strcpy (opname[4], Memc[param], SZ_FNAME)
+ goto getpar_
+ }
+
+ nops = EX_NIMOPS(ex)
+ found = NO
+ do i = 1, nops {
+ # Search for operand name which matches requested value.
+ op = IMOP(ex,i)
+ if (streq (Memc[IO_TAG(op)],opname)) {
+ found = YES
+ break
+ }
+ }
+
+ if (VDEBUG && found == YES) {
+ call eprintf (" tag=%s found=%d ")
+ call pargstr(Memc[IO_TAG(op)]) ; call pargi(found)
+ call zze_prop (op)
+ }
+
+ if (found == YES) {
+ # Copy operand descriptor to 'o'
+ #optype = ex_ptype (IO_TYPE(op), IO_NBYTES(op))
+ optype = IO_TYPE(op)
+ switch (optype) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ O_LEN(o) = IO_NPIX(op)
+ O_TYPE(o) = TY_SHORT
+ call malloc (O_VALP(o), IO_NPIX(op), TY_SHORT)
+ call amovs (Mems[IO_DATA(op)], Mems[O_VALP(o)], IO_NPIX(op))
+ $for (ilrd)
+ case TY_PIXEL:
+ O_LEN(o) = IO_NPIX(op)
+ O_TYPE(o) = TY_PIXEL
+ call malloc (O_VALP(o), IO_NPIX(op), TY_PIXEL)
+ call amov$t (Mem$t[IO_DATA(op)], Mem$t[O_VALP(o)], IO_NPIX(op))
+ $endfor
+ }
+
+ } else {
+ call sprintf (Memc[buf], SZ_LINE, "Unknown outbands operand `%s'\n")
+ call pargstr(opname)
+ call error (1, Memc[buf])
+ }
+
+ call sfree (sp)
+end
+
+
+# EX_OBFCN -- Called by evvexpr to execute import outbands special functions.
+
+procedure ex_obfcn (ex, fcn, args, nargs, o)
+
+pointer ex #i package pointer
+char fcn[ARB] #i function to be executed
+pointer args[ARB] #i argument list
+int nargs #i number of arguments
+pointer o #o operand pointer
+
+pointer sp, buf
+pointer r, g, b, gray
+pointer scaled, data
+int i, len, v_nargs, func, nbins
+short sz1, sz2, sb1, sb2, zero
+real gamma, bscale, bzero, scale, pix
+real z1, z2
+
+int strdic()
+bool fp_equalr(), strne()
+
+define setop_ 99
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_FNAME, TY_CHAR)
+
+ # Lookup function in dictionary.
+ func = strdic (fcn, Memc[buf], SZ_LINE, OB_FUNCTIONS)
+ if (func > 0 && strne(fcn,Memc[buf]))
+ func = 0
+
+ # Abort if the function is not known.
+ if (func <= 0)
+ call xev_error1 ("unknown function `%s' called", fcn)
+
+ # Verify the correct number of arguments, negative value means a
+ # variable number of args, handle it in the evaluation.
+ switch (func) {
+ case GRAY, GREY:
+ v_nargs = 3
+ case ZSCALE:
+ v_nargs = -1
+ case BSCALE:
+ v_nargs = 3
+ case GAMMA:
+ v_nargs = -1
+ case BLOCK:
+ v_nargs = 3
+ }
+ if (v_nargs > 0 && nargs != v_nargs)
+ call xev_error2 ("function `%s' requires %d arguments",
+ fcn, v_nargs)
+ else if (v_nargs < 0 && nargs < abs(v_nargs))
+ call xev_error2 ("function `%s' requires at least %d arguments",
+ fcn, abs(v_nargs))
+
+ if (DEBUG) {
+ call eprintf ("obfcn: nargs=%d func=%d\n")
+ call pargi (nargs) ; call pargi (func)
+ do i = 1, nargs { call eprintf ("\t") ; call zze_pevop (args[i]) }
+ call flush (STDERR)
+ }
+
+ # Evaluate the function.
+ zero = 0
+ switch (func) {
+ case GRAY, GREY:
+ # evaluate expression for NTSC grayscale.
+ r = O_VALP(args[1])
+ g = O_VALP(args[2])
+ b = O_VALP(args[3])
+ len = O_LEN(args[1]) - 1
+ O_LEN(o) = len + 1
+ O_TYPE(o) = TY_REAL
+ call malloc (O_VALP(o), len+1, TY_REAL)
+ gray = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ do i = 0, len {
+ Memr[gray+i] = R_COEFF * Mems[r+i] +
+ G_COEFF * Mems[g+i] +
+ B_COEFF * Mems[b+i]
+ }
+ $for (ilrd)
+ case TY_PIXEL:
+ do i = 0, len {
+ Memr[gray+i] = R_COEFF * Mem$t[r+i] +
+ G_COEFF * Mem$t[g+i] +
+ B_COEFF * Mem$t[b+i]
+ }
+ $endfor
+ }
+
+ case ZSCALE:
+ data = O_VALP(args[1])
+ switch (O_TYPE(args[2])) {
+ case TY_SHORT: z1 = O_VALS(args[2])
+ case TY_INT: z1 = O_VALI(args[2])
+ case TY_LONG: z1 = O_VALL(args[2])
+ case TY_REAL: z1 = O_VALR(args[2])
+ case TY_DOUBLE: z1 = O_VALD(args[2])
+ }
+ switch (O_TYPE(args[3])) {
+ case TY_SHORT: z2 = O_VALS(args[3])
+ case TY_INT: z2 = O_VALI(args[3])
+ case TY_LONG: z2 = O_VALL(args[3])
+ case TY_REAL: z2 = O_VALR(args[3])
+ case TY_DOUBLE: z2 = O_VALD(args[3])
+ }
+ if (nargs < 4)
+ nbins = 256
+ else
+ nbins = O_VALI(args[4])
+ len = O_LEN(args[1])
+ O_LEN(o) = len
+ O_TYPE(o) = O_TYPE(args[1])
+ call malloc (O_VALP(o), len, O_TYPE(args[1]))
+ scaled = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ sz1 = z1
+ sz2 = z2
+ sb1 = 0
+ sb2 = nbins - 1
+ if (abs(sz2-sz1) > 1.0e-5)
+ call amaps (Mems[data], Mems[scaled], len, sz1, sz2,
+ sb1, sb2)
+ else
+ call amovks (0, Mems[scaled], len)
+ $for (ilrd)
+ case TY_PIXEL:
+ if (abs(z2-z1) > 1.0e-5)
+ call amap$t (Mem$t[data], Mem$t[scaled], len, PIXEL (z1),
+ PIXEL(z2), PIXEL (0), PIXEL (nbins-1))
+ else
+ call amovk$t (PIXEL (0), Mem$t[scaled], len)
+ $endfor
+ }
+
+ case BSCALE:
+ data = O_VALP(args[1])
+ bzero = O_VALR(args[2])
+ bscale = O_VALR(args[3])
+ len = O_LEN(args[1]) - 1
+ O_LEN(o) = len + 1
+ O_TYPE(o) = TY_REAL
+ call malloc (O_VALP(o), len+1, TY_REAL)
+ scaled = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ if (!fp_equalr (0.0, bscale)) {
+ do i = 0, len
+ Memr[scaled+i] = (Mems[data+i] - bzero) / bscale
+ } else
+ call amovks (zero, Mems[scaled], len)
+ $for (ilrd)
+ case TY_PIXEL:
+ if (!fp_equalr (0.0, bscale)) {
+ do i = 0, len
+ Memr[scaled+i] = (Mem$t[data+i] - bzero) / bscale
+ } else
+ call amovk$t (PIXEL(0), Mem$t[scaled], len)
+ $endfor
+ }
+
+ case GAMMA:
+ data = O_VALP(args[1])
+ gamma = 1.0 / O_VALR(args[2])
+ if (nargs == 3)
+ scale = max (1.0, O_VALR(args[3]))
+ else
+ scale = 255.0
+ len = O_LEN(args[1]) - 1
+ O_LEN(o) = len + 1
+ O_TYPE(o) = TY_REAL
+ call malloc (O_VALP(o), len+1, TY_REAL)
+ scaled = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ do i = 0, len {
+ pix = max (zero, Mems[data+i])
+ Memr[scaled+i] = scale * ((pix/scale) ** gamma)
+ }
+ $for (ilrd)
+ case TY_PIXEL:
+ do i = 0, len {
+ pix = max (PIXEL(0), Mem$t[data+i])
+ Memr[scaled+i] = scale * ((pix/scale) ** gamma)
+ }
+ $endfor
+ }
+
+ case BLOCK:
+ len = O_VALI(args[2])
+ O_LEN(o) = len
+ O_TYPE(o) = O_TYPE(args[1])
+ call malloc (O_VALP(o), len, O_TYPE(args[1]))
+ scaled = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ call amovks (O_VALS(args[1]), Mems[scaled], len)
+ case TY_INT:
+ call amovki (O_VALI(args[1]), Memi[scaled], len)
+ case TY_LONG:
+ call amovkl (O_VALL(args[1]), Meml[scaled], len)
+ case TY_REAL:
+ call amovkr (O_VALR(args[1]), Memr[scaled], len)
+ case TY_DOUBLE:
+ call amovkd (O_VALD(args[1]), Memd[scaled], len)
+ }
+
+
+ }
+
+ if (DEBUG) { call zze_pevop (o) }
+
+ call sfree (sp)
+end
diff --git a/pkg/dataio/export/export.h b/pkg/dataio/export/export.h
new file mode 100644
index 00000000..279e4378
--- /dev/null
+++ b/pkg/dataio/export/export.h
@@ -0,0 +1,155 @@
+# EXPORT.H -- Main include file for the task structure.
+
+# Main task structure.
+define SZ_EXPSTRUCT 40
+define SZ_EXPSTR (20*SZ_LINE)
+define EX_UNDEFINED -999
+define MAX_OBEXPR 250
+define MAX_OPERANDS 50
+
+
+define EX_FD Memi[$1] # output binary file descriptor
+define EX_HEADER Memi[$1+1] # write an output header?
+define EX_OUTTYPE Memi[$1+2] # outtype parameter value
+define EX_INTERLEAVE Memi[$1+3] # interleave parameter value
+define EX_BSWAP Memi[$1+4] # bswap parameter value
+define EX_VERBOSE Memi[$1+5] # verbose parameter value
+
+define EX_FORMAT Memi[$1+6] # format parameter code
+define EX_BLTIN Memi[$1+7] # buitlin format code
+define EX_COLOR Memi[$1+8] # does format support color?
+define EX_OROWS Memi[$1+9] # no. rows in output image
+define EX_OCOLS Memi[$1+10] # no. cols in output image
+
+define EX_IMDIM Memi[$1+11] # input image list dimensionality
+define EX_IMTYPE Memi[$1+12] # input image list type
+define EX_NIMAGES Memi[$1+13] # number of images to convert
+define EX_NCOLS Memi[$1+14] # number of columns in image
+define EX_NLINES Memi[$1+15] # number of lines in image
+define EX_NEXPR Memi[$1+16] # number of outbands expressions
+define EX_NIMOPS Memi[$1+17] # image operand array (ptr)
+define EX_IMOPS Memi[$1+18] # image operand array (ptr)
+
+define EX_OUTFLAGS Memi[$1+20] # output format flags
+define EX_BFNPTR Memi[$1+21] # binary file name (ptr)
+define EX_HDRPTR Memi[$1+22] # user-defined head file (ptr)
+define EX_OTPTR Memi[$1+23] # output type string (ptr)
+define EX_OBPTR Memi[$1+24] # outbands expression string (ptr)
+define EX_CMPTR Memi[$1+25] # colormap filename (ptr)
+define EX_LUTPTR Memi[$1+26] # LUT filename (ptr)
+define EX_TIMPTR Memi[$1+27] # temp image name (ptr)
+define EX_PSDPI Memr[P2R($1+28)] # EPS dpi resolution
+define EX_PSSCALE Memr[P2R($1+29)] # EPS scale
+define EX_BRIGHTNESS Memr[P2R($1+30)] # display brightness value
+define EX_CONTRAST Memr[P2R($1+31)] # display contrast value
+
+define EX_CMAP Memi[$1+32] # colormap struct (ptr)
+define EX_NCOLORS Memi[$1+33] # no. of colors in colormap
+define EX_LUT Memi[$1+34] # LUT struct (ptr)
+define EX_NLUTEL Memi[$1+35] # no. of indices in lut
+define EX_OBANDS Memi[$1+36] # outbands array (ptr)
+
+
+# Handy macros.
+define HDRFILE Memc[EX_HDRPTR($1)]
+define LUTFILE Memc[EX_LUTPTR($1)]
+define CMAPFILE Memc[EX_CMPTR($1)]
+define BFNAME Memc[EX_BFNPTR($1)]
+define TIMNAME Memc[EX_TIMPTR($1)]
+define OBANDS Memi[EX_OBANDS($1)+$2-1]
+define IMOP Memi[EX_IMOPS($1)+$2-1]
+
+
+# Define the outbands struct.
+define LEN_OUTBANDS 5
+define OB_EXPSTR Memi[$1] # expression string (ptr)
+define OB_WIDTH Memi[$1+1] # expression width
+define OB_HEIGHT Memi[$1+2] # expression height
+
+define O_EXPR Memc[OB_EXPSTR(OBANDS($1,$2))]
+define O_WIDTH OB_WIDTH(OBANDS($1,$2))
+define O_HEIGHT OB_HEIGHT(OBANDS($1,$2))
+
+
+# Operand structure.
+define LEN_OPERAND 10
+define IO_IMPTR Memi[$1] # image descriptor
+define IO_BAND Memi[$1+1] # image band
+define IO_LINE Memi[$1+2] # image line
+
+define IO_TAG Memi[$1+3] # operand tag name
+define IO_TYPE Memi[$1+4] # operand type
+define IO_NBYTES Memi[$1+5] # number of bytes
+define IO_NPIX Memi[$1+6] # number of pixels
+define IO_DATA Memi[$1+7] # pixel ptr
+define IO_ISIM Memi[$1+8] # is data an image ptr?
+
+define OP_TAG Memc[IO_TAG($1)]
+
+#-----------------------------------------------------------------------------
+# Useful Macro Definitions.
+
+define bitset (and($1,$2)==($2))
+
+# Format flags.
+define FMT_RAW 1 # write a generic binary raster
+define FMT_LIST 2 # list pixels values to the screen
+define FMT_BUILTIN 3 # write a builtin format
+
+# OUTPUT FLAGS:
+# Byte swapping flags.
+define S_NONE 0000B # swap nothing
+define S_ALL 0001B # swap everything
+define S_I2 0002B # swap short ints
+define S_I4 0004B # swap long ints
+define SWAP_STR "|no|none|yes|i2|i4|"
+
+# Pixel storage flags.
+define PIXEL_STORAGE 0001B # { {RGB} {RGB} ... {RGB} ... }
+define LINE_STORAGE 0002B # { {RRRR} {GGG} {BBB} .... {RRR} ... }
+define BAND_STORAGE 0004B # { {RR..RRR} {GG...GGG} {BB..BBB} }
+
+# Output flags.
+define OF_CMAP 00010B # a colormap was defined
+define OF_MKCMAP 00020B # compute a colormap
+define OF_BAND 00040B # force band storage
+define OF_LINE 00100B # force line storage
+define OF_FLIPX 00200B # flip image in X
+define OF_FLIPY 00400B # flip image in Y
+define OF_IEEE 01000B # write IEEE floating point
+
+# Header flags.
+define HDR_NONE 1 # no output header
+define HDR_SHORT 2 # write a short header
+define HDR_LONG 3 # write a verbose header
+define HDR_USER 4 # user defined a file
+
+# Pixtype pixel types.
+define PT_BYTE 1 # byte data (no conversion)
+define PT_UINT 2 # unsigned integer
+define PT_INT 3 # signed integer
+define PT_IEEE 4 # ieee floating point
+define PT_NATIVE 5 # native floating point
+define PT_SKIP 6 # skip
+
+# EPS output params.
+define EPS_DPI 72 # dpi resolution
+define EPS_SCALE 1.0 # output scale
+
+# Define colormap/grayscale macros and parameters.
+define CMAP_SIZE 256 # Output colormap length
+define CMAP_MAX 255 # Maximum map value
+define CMAP Memc[$1+($2*CMAP_SIZE)+$3-1]
+
+define R_COEFF 0.299 # NTSC grayscale coefficients
+define G_COEFF 0.587
+define B_COEFF 0.114
+
+define EX_RED 0 # color flags
+define EX_GREEN 1
+define EX_BLUE 2
+
+define SAMPLE_SIZE 10000 # default zscale() sample size
+define CONTRAST 0.25 # default zscale() contrast
+define SAMP_LEN 40 # default zscale() sample length
+
diff --git a/pkg/dataio/export/expreproc.x b/pkg/dataio/export/expreproc.x
new file mode 100644
index 00000000..579f1fde
--- /dev/null
+++ b/pkg/dataio/export/expreproc.x
@@ -0,0 +1,352 @@
+include <error.h>
+include <ctype.h>
+include "export.h"
+include "exfcn.h"
+
+define DEBUG false
+
+
+# EX_PREPROCESS - Some of the output functions aren't really applied to
+# each line in the image (which is how the expressions are evaluated) but
+# just define some feature of the whole output image. We'll strip out
+# those functions here and set a flag so that the expression evaluation
+# code doesn't have to see them.
+
+procedure ex_preprocess (ex, expr)
+
+pointer ex #i task struct pointer
+char expr[ARB] #i input expression strings
+
+char expstr[SZ_EXPSTR]
+int ip, pp, last_ip, explen
+char func[SZ_FNAME]
+bool saw_output_func
+
+int strlen(), strdic(), nowhite()
+
+errchk ex_pp_setcmap, ex_pp_psdpi
+errchk ex_cnt_parens, ex_pp_psscale
+
+begin
+ # Strip out any whitespace chars.
+ call aclrc (expstr, SZ_EXPSTR)
+ ip = nowhite (expr, expstr, SZ_EXPSTR)
+
+ # Do a quick syntax check.
+ iferr (call ex_cnt_parens (expstr))
+ call erract (EA_FATAL)
+
+ # Only some functions may be nested, loop until we're forced to break.
+ # The functions have a precedence such that "special functions"
+ # may have as arguments "output functions". Below that are "scaling
+ # functions" and "builtin functions" that are evaluated for each image
+ # line. Functions w/in the same class may/may not call each other
+ # where it makes sense, we check for that here.
+ #
+ # The precedence order is:
+ #
+ # CMAP, SETCMAP, PSDPI, PSSCALE
+ # BAND, LINE, FLIPX, FLIPY
+ # ZSCALE, GRAY, BSCALE, GAMMA
+ # builtin functions
+
+ if (DEBUG) { call eprintf("preproc: str=`%s'\n");call pargstr(expstr) }
+
+ saw_output_func = false
+ for (ip = 1 ; expstr[ip] == '(' ; ip = ip + 1)
+ ;
+
+ last_ip = 1
+ explen = strlen (expstr)
+ repeat {
+ # Get the function name.
+ pp = 1
+ call aclrc (func, SZ_FNAME)
+ while (expstr[ip] != '(' && expstr[ip] != EOS) {
+ func[pp] = expstr[ip]
+ ip = ip + 1
+ pp = pp + 1
+ }
+ func[pp+1] = EOS
+ if (expstr[ip] == EOS) {
+ call strcpy (expstr[last_ip], expr, SZ_EXPSTR)
+ return
+ }
+ if (DEBUG) { call eprintf("\tfunc=`%s'\n");call pargstr(func) }
+
+ # Update pointer into string past '('.
+ ip = ip + 1
+
+ switch (strdic (func, func, SZ_FNAME, OB_FUNCTIONS)) {
+
+ case CMAP:
+ if (EX_NEXPR(ex) > 1)
+ call error (4,
+ "cmap() func allowed only in single expression")
+ if (saw_output_func)
+ call error (5,
+ "Function cmap() may not be nested in output func.")
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), OF_MKCMAP)
+
+ case SETCMAP:
+ if (EX_NEXPR(ex) > 1)
+ call error (4,
+ "setcmap() func allowed only in single expression")
+ if (saw_output_func)
+ call error (5,
+ "Function setcmap(0 may not be nested in output func.")
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), OF_CMAP)
+ iferr (call ex_pp_setcmap (ex, expstr[ip]))
+ call erract (EA_FATAL)
+ last_ip = ip
+ explen = strlen (expstr)
+ next
+
+ case PSDPI:
+ if (EX_NEXPR(ex) > 1)
+ call error (4,
+ "psdpi() func allowed only in single expression")
+ if (saw_output_func)
+ call error (5,
+ "Function psdpi() may not be nested in output func.")
+ iferr (call ex_pp_psdpi (ex, expstr[ip]))
+ call erract (EA_FATAL)
+ last_ip = ip
+ explen = strlen (expstr)
+ next
+
+ case PSSCALE:
+ if (EX_NEXPR(ex) > 1)
+ call error (4,
+ "psscale() func allowed only in single expression")
+ if (saw_output_func)
+ call error (5,
+ "Function psscale() may not be nested in output func.")
+ iferr (call ex_pp_psscale (ex, expstr[ip]))
+ call erract (EA_FATAL)
+ last_ip = ip
+ explen = strlen (expstr)
+ next
+
+
+ case BAND:
+ saw_output_func = true
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), OF_BAND)
+ case LINE:
+ saw_output_func = true
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), OF_LINE)
+ case FLIPX:
+ saw_output_func = true
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), OF_FLIPX)
+ case FLIPY:
+ saw_output_func = true
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), OF_FLIPY)
+
+ default:
+ # No special function seen so just punt.
+ break
+ }
+
+ last_ip = ip # update string ptr
+ if (expstr[explen] != ')')
+ call error (5,
+ "Malformed expression, expecting ')' as last char")
+ expstr[explen] = EOS # remove trailing right paren
+ }
+
+ # Copy expression from current ip to begining of buffer.
+ call strcpy (expstr[last_ip], expr, SZ_EXPSTR)
+
+ if (DEBUG) { call eprintf("\tfixed exp =`%s'\n");call pargstr(expr) }
+end
+
+
+# EX_PP_SETCMAP - Process the SETCMAP special function.
+
+procedure ex_pp_setcmap (ex, expstr)
+
+pointer ex #i task struct pointer
+char expstr[ARB] #i expression string
+
+pointer sp, cm, cmap
+int ip, lp # string pointers
+int tp, i # where to trim the string
+
+int ctor()
+bool streq()
+include "cmaps.inc"
+
+begin
+ call smark (sp)
+ call salloc (cm, SZ_FNAME, TY_CHAR)
+ call aclrc (Memc[cm], SZ_FNAME)
+
+ if (DEBUG) { call eprintf("\t\texp=`%s'\n");call pargstr(expstr)}
+
+ # Skip ahead to a quote char single or double) indicating colormap
+ # name, we also stop at another non-blank char incase they didn't
+ # use quotes. If we find a comma, back up one so it's handled below.
+ ip = 1
+ while (expstr[ip] != EOS &&
+ expstr[ip] != '"' &&
+ expstr[ip] != '\'') {
+ if (expstr[ip] == '@')
+ for (ip=ip+2; expstr[ip] != '"'; ip=ip+1)
+ ;
+ ip = ip + 1
+ }
+ tp = ip - 1
+
+ if (expstr[ip+1] == '"' || (expstr[ip+1]==' ' && expstr[ip+2]=='"') ||
+ expstr[ip+1] == '\'' || (expstr[ip+1]==' ' && expstr[ip+2]=='\'')) {
+ # No colormap file specified, assume it's a greyscale.
+ call strcpy ("greyscale", CMAPFILE(ex), SZ_FNAME)
+ ip = ip + 1
+
+ } else {
+ # Get colormap name and put it in the task struct.
+ ip = ip + 1
+ lp = 0
+ repeat {
+ Memc[cm+lp] = expstr[ip]
+ lp = lp + 1
+ ip = ip + 1
+ } until (expstr[ip] == EOS || expstr[ip] == '"' ||
+ expstr[ip] == '\'')
+ call strcpy (Memc[cm], CMAPFILE(ex), SZ_FNAME)
+ }
+
+ # Allocate the colormap pointer and read the colormap.
+ iferr (call calloc (EX_CMAP(ex), 3*CMAP_SIZE, TY_CHAR))
+ call error (0, "Error allocating colormap pointer.")
+ call ex_read_cmap (ex, CMAPFILE(ex))
+
+ # Get optional brightness and contrast values.
+ ip = ip + 1
+ if (expstr[ip] == ',') {
+ ip = ip + 1
+ if (ctor (expstr, ip, EX_BRIGHTNESS(ex)) == 0)
+ call error (5, "cannot interpret brightness value")
+ ip = ip + 1
+ if (ctor (expstr, ip, EX_CONTRAST(ex)) == 0)
+ call error (5, "cannot interpret contrast value")
+
+ # Don't scale the overlay colors in colormap.
+ if (streq(CMAPFILE(ex), "overlay")) {
+ cmap = EX_CMAP(ex)
+ call ex_scale_cmap (cmap, 200,
+ EX_BRIGHTNESS(ex), EX_CONTRAST(ex))
+
+ # Patch up the static overlay colors.
+ do i = 201, 255 {
+ Memc[cmap+(EX_RED*CMAP_SIZE)+i] = overlay[i*3+1]
+ Memc[cmap+(EX_GREEN*CMAP_SIZE)+i] = overlay[i*3+2]
+ Memc[cmap+(EX_BLUE*CMAP_SIZE)+i] = overlay[i*3+3]
+ }
+ } else {
+ call ex_scale_cmap (EX_CMAP(ex), EX_NCOLORS(ex),
+ EX_BRIGHTNESS(ex), EX_CONTRAST(ex))
+ }
+ }
+
+ # We should be at the end of the string now.
+ if (expstr[ip] != ')')
+ call error (5, "Malformed expression, expecting ')' as last char")
+
+ if (DEBUG) {
+ call eprintf("\t\tcmfile=`%s' brightness=%g contrast=%g\n")
+ call pargstr(CMAPFILE(ex));call pargr(EX_BRIGHTNESS(ex))
+ call pargr(EX_CONTRAST(ex))
+ }
+
+ # Now trim the expression string.
+ expstr[tp] = EOS
+ call sfree (sp)
+end
+
+
+# EX_PP_PSDPI - Process the PSDPI special function.
+
+procedure ex_pp_psdpi (ex, expstr)
+
+pointer ex #i task struct pointer
+char expstr[ARB] #i expression string
+
+int ip, tp
+int ctor(), strlen()
+
+begin
+ if (DEBUG) { call eprintf("\t\texp=`%s'\n");call pargstr(expstr)}
+
+ # The last argument is required to be the dpi resolution so pull
+ # it out.
+ ip = strlen (expstr)
+ while (expstr[ip] != ',') {
+ ip = ip - 1
+ if (expstr[ip] == ')' || IS_ALPHA(expstr[ip]))
+ call error (6, "syntax error")
+ }
+
+ tp = ip
+ ip = ip + 1
+ if (ctor(expstr,ip,EX_PSDPI(ex)) == 0)
+ call error (5, "cannot interpret EPS dpi value")
+
+ # Now trim the expression string.
+ expstr[tp] = EOS
+end
+
+
+# EX_PP_PSSCALE - Process the PSSCALE special function.
+
+procedure ex_pp_psscale (ex, expstr)
+
+pointer ex #i task struct pointer
+char expstr[ARB] #i expression string
+
+int ip, tp
+int ctor(), strlen()
+
+begin
+ if (DEBUG) { call eprintf("\t\texp=`%s'\n");call pargstr(expstr)}
+
+ # The last argument is required to be the dpi resolution so pull
+ # it out.
+ ip = strlen (expstr)
+ while (expstr[ip] != ',') {
+ ip = ip - 1
+ if (expstr[ip] == ')' || IS_ALPHA(expstr[ip]))
+ call error (6, "syntax error")
+ }
+
+ tp = ip
+ ip = ip + 1
+ if (ctor(expstr,ip,EX_PSSCALE(ex)) == 0)
+ call error (5, "cannot interpret EPS scale value")
+
+ # Now trim the expression string.
+ expstr[tp] = EOS
+end
+
+
+# EX_CNT_PARENS - Count the number of parentheses in the expression string.
+
+procedure ex_cnt_parens (expr)
+
+char expr[ARB] #i outbands expression strinf
+
+int ip, plev
+
+begin
+ ip = 1
+ plev = 0
+ while (expr[ip] != EOS) {
+ if (expr[ip] == '(') plev = plev + 1
+ if (expr[ip] == ')') plev = plev - 1
+ ip = ip + 1
+ }
+ if (plev > 0)
+ call error (5, "Missing right paren in `outbands' expression.")
+ if (plev < 0)
+ call error (5, "Missing left paren in `outbands' expression.")
+end
diff --git a/pkg/dataio/export/exraster.gx b/pkg/dataio/export/exraster.gx
new file mode 100644
index 00000000..a4c08710
--- /dev/null
+++ b/pkg/dataio/export/exraster.gx
@@ -0,0 +1,621 @@
+include <imhdr.h>
+include <mach.h>
+include <evvexpr.h>
+include "../export.h"
+
+define DEBUG false
+
+
+# EX_NO_INTERLEAVE - Write out the image with no interleaving.
+
+procedure ex_no_interleave (ex)
+
+pointer ex #i task struct pointer
+
+pointer op, out
+int i, j, k, line, percent, orow
+int fd, outtype
+
+pointer ex_evaluate(), ex_chtype()
+
+begin
+ if (DEBUG) { call eprintf ("ex_no_interleave:\n")
+ call eprintf ("NEXPR = %d OCOLS = %d OROWS = %d\n")
+ call pargi(EX_NEXPR(ex));call pargi(EX_OCOLS(ex))
+ call pargi(EX_OROWS(ex))
+ }
+
+ # Loop over the number of image expressions.
+ fd = EX_FD(ex)
+ outtype = EX_OUTTYPE(ex)
+ percent = 0
+ orow = 0
+ do i = 1, EX_NEXPR(ex) {
+
+ # Process each line in the image.
+ do j = 1, O_HEIGHT(ex,i) {
+
+ # See if we're flipping the image.
+ if (bitset (EX_OUTFLAGS(ex), OF_FLIPY))
+ #line = EX_NLINES(ex) - j + 1
+ line = O_HEIGHT(ex,i) - j + 1
+ else
+ line = j
+
+ # Get pixels from image(s).
+ call ex_getpix (ex, line)
+
+ # Evaluate expression.
+ op = ex_evaluate (ex, O_EXPR(ex,i))
+
+ # Convert to the output pixel type.
+ out = ex_chtype (ex, op, outtype)
+
+ # Write evaluated pixels.
+ if (EX_FORMAT(ex) != FMT_LIST)
+ call ex_wpixels (fd, outtype, out, O_LEN(op))
+ else {
+ call ex_listpix (fd, outtype, out, O_LEN(op), j, i,
+ EX_NEXPR(ex), NO)
+ }
+
+ # Clean up the pointers.
+ if (outtype == TY_UBYTE || outtype == TY_CHAR)
+ call mfree (out, TY_CHAR)
+ else
+ call mfree (out, outtype)
+ call evvfree (op)
+ do k = 1, EX_NIMOPS(ex) {
+ op = IMOP(ex,k)
+# if (IO_ISIM(op) == NO)
+ call mfree (IO_DATA(op), IM_PIXTYPE(IO_IMPTR(op)))
+ }
+
+ # Print percent done if being verbose
+ orow = orow + 1
+ #if (EX_VERBOSE(ex) == YES)
+ call ex_pstat (ex, orow, percent)
+ }
+ }
+
+ if (DEBUG) { call zze_prstruct ("Finished processing", ex) }
+end
+
+
+# EX_LN_INTERLEAVE - Write out the image with line interleaving.
+
+procedure ex_ln_interleave (ex)
+
+pointer ex #i task struct pointer
+
+pointer op, out
+int i, j, line, percent, orow
+int fd, outtype
+
+pointer ex_evaluate(), ex_chtype()
+
+begin
+ if (DEBUG) { call eprintf ("ex_ln_interleave:\n")
+ call eprintf ("NEXPR = %d OCOLS = %d OROWS = %d\n")
+ call pargi(EX_NEXPR(ex));call pargi(EX_OCOLS(ex))
+ call pargi(EX_OROWS(ex))
+ }
+
+ # Process each line in the image.
+ fd = EX_FD(ex)
+ outtype = EX_OUTTYPE(ex)
+ percent = 0
+ orow = 0
+ do i = 1, EX_NLINES(ex) {
+
+ # See if we're flipping the image.
+ if (bitset (EX_OUTFLAGS(ex), OF_FLIPY))
+ line = EX_NLINES(ex) - i + 1
+ else
+ line = i
+
+ # Get pixels from image(s).
+ call ex_getpix (ex, line)
+
+ # Loop over the number of image expressions.
+ do j = 1, EX_NEXPR(ex) {
+
+ # Evaluate expression.
+ op = ex_evaluate (ex, O_EXPR(ex,j))
+
+ # Convert to the output pixel type.
+ out = ex_chtype (ex, op, outtype)
+
+ # Write evaluated pixels.
+ if (EX_FORMAT(ex) != FMT_LIST)
+ call ex_wpixels (fd, outtype, out, O_LEN(op))
+ else {
+ call ex_listpix (fd, outtype, out, O_LEN(op), i, j,
+ EX_NEXPR(ex), NO)
+ }
+
+ # Clean up the pointers.
+ if (outtype == TY_UBYTE || outtype == TY_CHAR)
+ call mfree (out, TY_CHAR)
+ else
+ call mfree (out, outtype)
+ call evvfree (op)
+
+ # Print percent done if being verbose
+ orow = orow + 1
+ #if (EX_VERBOSE(ex) == YES)
+ call ex_pstat (ex, orow, percent)
+ }
+
+ do j = 1, EX_NIMOPS(ex) {
+ op = IMOP(ex,j)
+# if (IO_ISIM(op) == NO)
+ call mfree (IO_DATA(op), IM_PIXTYPE(IO_IMPTR(op)))
+ }
+ }
+
+ if (DEBUG) { call zze_prstruct ("Finished processing", ex) }
+end
+
+
+# EX_PX_INTERLEAVE - Write out the image with pixel interleaving.
+
+procedure ex_px_interleave (ex)
+
+pointer ex #i task struct pointer
+
+pointer sp, pp, op
+pointer o, outptr
+int i, j, line, npix, outtype
+long totpix
+int fd, percent, orow
+
+pointer ex_evaluate(), ex_chtype()
+
+begin
+ if (DEBUG) { call eprintf ("ex_px_interleave:\n")
+ call eprintf ("NEXPR = %d OCOLS = %d OROWS = %d\n")
+ call pargi(EX_NEXPR(ex));call pargi(EX_OCOLS(ex))
+ call pargi(EX_OROWS(ex))
+ }
+
+ call smark (sp)
+ call salloc (pp, EX_NEXPR(ex), TY_POINTER)
+
+ # Process each line in the image.
+ fd = EX_FD(ex)
+ outptr = NULL
+ outtype = EX_OUTTYPE(ex)
+ percent = 0
+ orow = 0
+ do i = 1, EX_NLINES(ex) {
+
+ # See if we're flipping the image.
+ if (bitset (EX_OUTFLAGS(ex), OF_FLIPY))
+ line = EX_NLINES(ex) - i + 1
+ else
+ line = i
+
+ # Get pixels from image(s).
+ call ex_getpix (ex, line)
+
+ # Loop over the number of image expressions.
+ totpix = 0
+ do j = 1, EX_NEXPR(ex) {
+
+ # Evaluate expression.
+ op = ex_evaluate (ex, O_EXPR(ex,j))
+
+ # Convert to the output pixel type.
+ o = ex_chtype (ex, op, outtype)
+ Memi[pp+j-1] = o
+
+ npix = O_LEN(op)
+ #npix = EX_OCOLS(op)
+ call evvfree (op)
+ }
+
+ # Merge pixels into a single vector.
+ call ex_merge_pixels (Memi[pp], EX_NEXPR(ex), npix, outtype,
+ outptr, totpix)
+
+ # Write vector of merged pixels.
+ if (outtype == TY_UBYTE)
+ call achtsb (Memc[outptr], Memc[outptr], totpix)
+ if (EX_FORMAT(ex) != FMT_LIST)
+ call ex_wpixels (fd, outtype, outptr, totpix)
+ else {
+ call ex_listpix (fd, outtype, outptr, totpix,
+ i, EX_NEXPR(ex), EX_NEXPR(ex), YES)
+ }
+
+ if (outtype != TY_CHAR && outtype != TY_UBYTE)
+ call mfree (outptr, outtype)
+ else
+ call mfree (outptr, TY_CHAR)
+ do j = 1, EX_NIMOPS(ex) {
+ op = IMOP(ex,j)
+# if (IO_ISIM(op) == NO)
+ call mfree (IO_DATA(op), IM_PIXTYPE(IO_IMPTR(op)))
+ }
+ do j = 1, EX_NEXPR(ex) {
+ if (outtype != TY_CHAR && outtype != TY_UBYTE)
+ call mfree (Memi[pp+j-1], outtype)
+ else
+ call mfree (Memi[pp+j-1], TY_CHAR)
+ }
+
+ # Print percent done if being verbose
+ orow = orow + 1
+ #if (EX_VERBOSE(ex) == YES)
+ call ex_pstat (ex, orow, percent)
+ }
+
+ call sfree (sp)
+
+ if (DEBUG) { call zze_prstruct ("Finished processing", ex) }
+end
+
+
+# EX_GETPIX - Get the pixels from the image and load each operand.
+
+procedure ex_getpix (ex, line)
+
+pointer ex #i task struct pointer
+int line #i current line number
+
+pointer im, op, data
+int nptrs, i, band
+
+pointer imgl3s(), imgl3i(), imgl3l()
+pointer imgl3r(), imgl3d()
+
+begin
+ # Loop over each of the image operands.
+ nptrs = EX_NIMOPS(ex)
+ do i = 1, nptrs {
+ op = IMOP(ex,i)
+ im = IO_IMPTR(op)
+ band = max (1, IO_BAND(op))
+
+ if (line > IM_LEN(im,2)) {
+ call calloc (IO_DATA(op), IM_LEN(im,1), IM_PIXTYPE(im))
+ IO_ISIM(op) = NO
+ IO_NPIX(op) = IM_LEN(im,1)
+ next
+ } else if (IO_DATA(op) == NULL)
+ call malloc (IO_DATA(op), IM_LEN(im,1), IM_PIXTYPE(im))
+
+ switch (IM_PIXTYPE(im)) {
+ case TY_USHORT:
+ data = imgl3s (im, line, band)
+ call amovs (Mems[data], Mems[IO_DATA(op)], IM_LEN(im,1))
+ IO_TYPE(op) = TY_SHORT
+ IO_NBYTES(op) = SZ_SHORT * SZB_CHAR
+ IO_ISIM(op) = YES
+ $for (silrd)
+ case TY_PIXEL:
+ data = imgl3$t (im, line, band)
+ call amov$t (Mem$t[data], Mem$t[IO_DATA(op)], IM_LEN(im,1))
+ IO_TYPE(op) = TY_PIXEL
+ $if (datatype == i)
+ IO_NBYTES(op) = SZ_INT32 * SZB_CHAR
+ $else
+ IO_NBYTES(op) = SZ_PIXEL * SZB_CHAR
+ $endif
+ IO_ISIM(op) = YES
+ $endfor
+ }
+ IO_NPIX(op) = IM_LEN(im,1)
+ }
+end
+
+
+# EX_WPIXELS - Write the pixels to the current file.
+
+procedure ex_wpixels (fd, otype, pix, npix)
+
+int fd #i output file descriptor
+int otype #i output data type
+pointer pix #i pointer to pixel data
+int npix #i number of pixels to write
+
+begin
+ # Write binary output.
+ switch (otype) {
+ case TY_UBYTE:
+ call write (fd, Mems[pix], npix / SZB_CHAR)
+ case TY_USHORT:
+ call write (fd, Mems[pix], npix * SZ_SHORT/SZ_CHAR)
+ $for (silrd)
+ case TY_PIXEL:
+ $if (datatype == i)
+ if (SZ_INT != SZ_INT32)
+ call ipak32 (Memi[pix], Memi[pix], npix)
+ call write (fd, Memi[pix], npix * SZ_INT32/SZ_CHAR)
+ $else
+ call write (fd, Mem$t[pix], npix * SZ_PIXEL/SZ_CHAR)
+ $endif
+ $endfor
+ }
+end
+
+
+# EX_LISTPIX - Write the pixels to the current file as ASCII text.
+
+procedure ex_listpix (fd, type, data, npix, line, band, nbands, merged)
+
+int fd #i output file descriptor
+int type #i output data type
+pointer data #i pointer to pixel data
+int npix #i number of pixels to write
+int line #i current output line number
+int band #i current output band number
+int nbands #i no. of output bands
+int merged #i are pixels interleaved?
+
+int i, j, k
+int val, pix, shifti(), andi()
+
+begin
+ if (merged == YES && nbands > 1) {
+ do i = 1, npix {
+ k = 0
+ do j = 1, nbands {
+ call fprintf (fd, "%4d %4d %4d ")
+ call pargi (i)
+ call pargi (line)
+ call pargi (j)
+
+ switch (type) {
+ case TY_UBYTE:
+ val = Memc[data+k]
+ if (mod(i,2) == 1) {
+ pix = shifti (val, -8)
+ } else {
+ pix = andi (val, 000FFX)
+ k = k + 1
+ }
+ if (pix < 0) pix = pix + 256
+ call fprintf (fd, "%d\n")
+ call pargi (pix)
+ case TY_CHAR, TY_SHORT, TY_USHORT:
+ call fprintf (fd, "%d\n")
+ call pargs (Mems[data+((j-1)*npix+i)-1])
+ case TY_INT:
+ call fprintf (fd, "%d\n")
+ call pargi (Memi[data+((j-1)*npix+i)-1])
+ case TY_LONG:
+ call fprintf (fd, "%d\n")
+ call pargl (Meml[data+((j-1)*npix+i)-1])
+ case TY_REAL:
+ call fprintf (fd, "%g\n")
+ call pargr (Memr[data+((j-1)*npix+i)-1])
+ case TY_DOUBLE:
+ call fprintf (fd, "%g\n")
+ call pargd (Memd[data+((j-1)*npix+i)-1])
+ }
+ }
+ }
+ } else {
+ j = 0
+ do i = 1, npix {
+ if (nbands > 1) {
+ call fprintf (fd, "%4d %4d %4d ")
+ call pargi (i)
+ call pargi (line)
+ call pargi (band)
+ } else {
+ call fprintf (fd, "%4d %4d ")
+ call pargi (i)
+ call pargi (line)
+ }
+
+ switch (type) {
+ case TY_UBYTE:
+ val = Memc[data+j]
+ if (mod(i,2) == 1) {
+ pix = shifti (val, -8)
+ } else {
+ pix = andi (val, 000FFX)
+ j = j + 1
+ }
+ if (pix < 0) pix = pix + 256
+ call fprintf (fd, "%d\n")
+ call pargi (pix)
+ case TY_CHAR, TY_SHORT, TY_USHORT:
+ call fprintf (fd, "%d\n")
+ call pargs (Mems[data+i-1])
+ case TY_INT:
+ call fprintf (fd, "%d\n")
+ call pargi (Memi[data+i-1])
+ case TY_LONG:
+ call fprintf (fd, "%d\n")
+ call pargl (Meml[data+i-1])
+ case TY_REAL:
+ call fprintf (fd, "%g\n")
+ call pargr (Memr[data+i-1])
+ case TY_DOUBLE:
+ call fprintf (fd, "%g\n")
+ call pargd (Memd[data+i-1])
+ }
+ }
+ }
+end
+
+
+# EX_MERGE_PIXELS - Merge a group of pixels arrays into one array by combining
+# the elements. Returns an allocated pointer which must be later freed and
+# the total number of pixels.
+
+procedure ex_merge_pixels (ptrs, nptrs, npix, dtype, pix, totpix)
+
+pointer ptrs[ARB] #i array of pixel ptrs
+int nptrs #i number of ptrs
+int npix #i no. of pixels in each array
+int dtype #i type of pointer to alloc
+pointer pix #o output pixel array ptr
+int totpix #o total no. of output pixels
+
+int i, j, ip
+
+begin
+ # Calculate the number of output pixels and allocate the pointer.
+ totpix = nptrs * npix
+ if (dtype != TY_CHAR && dtype != TY_UBYTE)
+ call realloc (pix, totpix, dtype)
+ else {
+ call realloc (pix, totpix, TY_CHAR)
+ do i = 1, nptrs
+ call achtbs (Mems[ptrs[i]], Mems[ptrs[i]], npix)
+ }
+
+ # Fill the output array
+ ip = 0
+ for (i = 1; i<=npix; i=i+1) {
+ do j = 1, nptrs {
+ switch (dtype) {
+ case TY_UBYTE:
+ Mems[pix+ip] = Mems[ptrs[j]+i-1]
+ case TY_USHORT:
+ Mems[pix+ip] = Mems[ptrs[j]+i-1]
+ $for (silrd)
+ case TY_PIXEL:
+ Mem$t[pix+ip] = Mem$t[ptrs[j]+i-1]
+ $endfor
+ }
+
+ ip = ip + 1
+ }
+ }
+end
+
+
+# EX_CHTYPE - Change the expression operand vector to the output datatype.
+# We allocate and return a pointer to the correct type to the converted
+# pixels, this pointer must be freed later on. Any IEEE or byte-swapping
+# requests are also handled here.
+
+pointer procedure ex_chtype (ex, op, type)
+
+pointer ex #i task struct pointer
+pointer op #i evvexpr operand pointer
+int type #i new type of pointer
+
+pointer out, coerce()
+int swap, flags
+
+begin
+ # Allocate the pointer and coerce it so the routine works.
+ if (type == TY_UBYTE || type == TY_CHAR)
+ call calloc (out, O_LEN(op), TY_CHAR)
+ else {
+ call calloc (out, O_LEN(op), type)
+ out = coerce (out, type, TY_CHAR)
+ }
+
+ # If this is a color index image subtract one from the pixel value
+ # to get the index.
+ if (bitset (flags, OF_CMAP))
+ call ex_pix_to_index (O_VALP(op), O_TYPE(op), O_LEN(op))
+
+ # Change the pixel type.
+ flags = EX_OUTFLAGS(ex)
+ swap = EX_BSWAP(ex)
+ switch (O_TYPE(op)) {
+ case TY_CHAR:
+ call achtc (Memc[O_VALP(op)], Memc[out], O_LEN(op), type)
+
+ case TY_SHORT:
+ call achts (Mems[O_VALP(op)], Memc[out], O_LEN(op), type)
+
+ # Do any requested byte swapping.
+ if (bitset (swap, S_I2) || bitset (swap, S_ALL))
+ call bswap4 (Mems[out], 1, Mems[out], 1, O_LEN(op))
+
+ case TY_INT:
+ call achti (Memi[O_VALP(op)], Memc[out], O_LEN(op), type)
+
+ # Do any requested byte swapping.
+ if (bitset (swap, S_I4) || bitset (swap, S_ALL))
+ call bswap4 (Memi[out], 1, Memi[out], 1, O_LEN(op))
+
+ case TY_LONG:
+ call achtl (Meml[O_VALP(op)], Memc[out], O_LEN(op), type)
+
+ # Do any requested byte swapping.
+ if (bitset (swap, S_I4) || bitset (swap, S_ALL))
+ call bswap4 (Meml[out], 1, Meml[out], 1, O_LEN(op))
+
+ case TY_REAL:
+ call achtr (Memr[O_VALP(op)], Memc[out], O_LEN(op), type)
+
+ # See if we need to convert to IEEE
+ if (bitset (flags, OF_IEEE) && IEEE_USED == NO)
+ call ieevpakr (Memr[out], Memr[out], O_LEN(op))
+
+ case TY_DOUBLE:
+ call achtd (Memd[O_VALP(op)], Memc[out], O_LEN(op), type)
+
+ # See if we need to convert to IEEE
+ if (bitset (flags, OF_IEEE) && IEEE_USED == NO)
+ call ieevpakd (Memd[P2D(out)], Memd[P2D(out)], O_LEN(op))
+
+ default:
+ call error (0, "Invalid output type requested.")
+ }
+
+ if (type != TY_UBYTE && type != TY_CHAR)
+ out = coerce (out, TY_CHAR, type)
+ return (out)
+end
+
+
+# EX_PIX_TO_INDEX - Convert pixel values to color index values. We assume
+# the colormap has at most 256 entries.
+
+procedure ex_pix_to_index (ptr, type, len)
+
+pointer ptr #i data ptr
+int type #i data type of array
+int len #i length of array
+
+$for (silrd)
+PIXEL $tindx, $tmin, $tmax
+$endfor
+
+begin
+ $for (silrd)
+ $tindx = PIXEL (1)
+ $tmin = PIXEL (0)
+ $tmax = PIXEL (255)
+ $endfor
+
+ switch (type) {
+ $for (silrd)
+ case TY_PIXEL:
+ call asubk$t (Mem$t[ptr], $tindx, Mem$t[ptr], len)
+ call amaxk$t (Mem$t[ptr], $tmin, Mem$t[ptr], len)
+ call amink$t (Mem$t[ptr], $tmax, Mem$t[ptr], len)
+ $endfor
+ }
+end
+
+
+# EX_PSTAT - Print information about the progress we're making.
+
+procedure ex_pstat (ex, row, percent)
+
+pointer ex #i task struct pointer
+int row #u current row
+int percent #u percent completed
+
+begin
+ # Print percent done if being verbose
+ if (row * 100 / EX_OROWS(ex) >= percent + 10) {
+ percent = percent + 10
+ call eprintf (" Status: %2d%% complete\r")
+ call pargi (percent)
+ call flush (STDERR)
+ }
+end
diff --git a/pkg/dataio/export/exrgb8.x b/pkg/dataio/export/exrgb8.x
new file mode 100644
index 00000000..9eac4705
--- /dev/null
+++ b/pkg/dataio/export/exrgb8.x
@@ -0,0 +1,994 @@
+include <imhdr.h>
+include "export.h"
+
+
+# Size definitions
+define A_BITS 8 # Number of bits of color
+define B_BITS 5 # Number of bits/pixel to use
+define C_BITS 3 # Number of cells/color to use
+define A_LEN 256 # 2 ** A_BITS
+define B_LEN 32 # 2 ** B_BITS
+define C_LEN 8 # 2 ** C_BITS
+define AB_SHIFT 8 # 2 ** (A_BITS - B_BITS)
+define BC_SHIFT 4 # 2 ** (B_BITS - C_BITS)
+define AC_SHIFT 32 # 2 ** (A_BITS - C_BITS)
+
+# Color metric definitions
+define R2FACT 20 # .300 * .300 * 256 = 23
+define G2FACT 39 # .586 * .586 * 256 = 88
+define B2FACT 8 # .114 * .114 * 256 = 3
+
+define RED 1
+define GREEN 2
+define BLUE 3
+
+# Colorbox structure
+define CBOX_LEN 9
+define CBOX_NEXT Memi[$1] # pointer to next colorbox structure
+define CBOX_PREV Memi[$1+1] # pointer to previous colorbox structure
+define CBOX_RMIN Memi[$1+2]
+define CBOX_RMAX Memi[$1+3]
+define CBOX_GMIN Memi[$1+4]
+define CBOX_GMAX Memi[$1+5]
+define CBOX_BMIN Memi[$1+6]
+define CBOX_BMAX Memi[$1+7]
+define CBOX_TOTAL Memi[$1+8]
+
+# Color cell structure
+define CCELL_LEN (A_LEN*2+1)
+define CCELL_NUM_ENTS Memi[$1]
+define CCELL_ENTRIES Memi[$1+2*($2)+$3+1]
+
+# Output number of colors
+define NCOLORS 256
+
+
+# EX_MKCMAP -- Generate an 8-bit colormap from three input image expressions
+# using Heckbert's Median Cut algorithm. The implementation of this algorithm
+# was modeled, with permission, on that in the program XV written by John
+# Bradley.
+
+procedure ex_mkcmap (ex)
+
+pointer ex #i task struct pointer
+
+pointer oim # Output image
+real z1[3], dz[3] # Display ranges
+
+int i, ncolors
+pointer sp, cmap, box_list, histogram, ColorCells
+pointer freeboxes, usedboxes, ptr, im
+
+pointer immap(), cm_largest_box()
+errchk open, immap
+
+begin
+ # Since we're creating a colormap we force the output pixel size
+ # to be 8-bits.
+ call ex_do_outtype (ex, "b1")
+
+ # Create a temporary image of the processed expressions. We'll
+ # evaluate the expressions only once an save the results, later
+ # we'll path up the operand and expressions structs to it copies
+ # this out to the requested format.
+
+ if (EX_TIMPTR(ex) == NULL)
+ call calloc (EX_TIMPTR(ex), SZ_FNAME, TY_CHAR)
+ else
+ call aclrc (TIMNAME(ex), SZ_FNAME)
+ call mktemp ("tmp$ex", TIMNAME(ex), SZ_FNAME)
+ oim = immap (TIMNAME(ex), NEW_IMAGE, 0)
+ IM_PIXTYPE(oim) = TY_SHORT
+ IM_LEN(oim,1) = EX_OCOLS(ex)
+ IM_LEN(oim,2) = EX_OROWS(ex)
+ IM_NDIM(oim) = 2
+
+ # Set input image intensity scaling.
+ z1[1] = 0.0
+ dz[1] = 1.0
+ z1[2] = 0.0
+ dz[2] = 1.0
+ z1[3] = 0.0
+ dz[3] = 1.0
+
+ # Allocate color map.
+ ncolors = NCOLORS
+ call smark (sp)
+ call salloc (cmap, 3 * ncolors, TY_SHORT)
+
+ # Allocate and initialize color boxes.
+ call salloc (box_list, ncolors * CBOX_LEN, TY_STRUCT)
+
+ freeboxes = box_list
+ usedboxes = NULL
+ ptr = freeboxes
+ CBOX_PREV(ptr) = NULL
+ CBOX_NEXT(ptr) = ptr + CBOX_LEN
+ for (i=2; i<ncolors; i=i+1) {
+ ptr = ptr + CBOX_LEN
+ CBOX_PREV(ptr) = ptr - CBOX_LEN
+ CBOX_NEXT(ptr) = ptr + CBOX_LEN
+ }
+ ptr = ptr + CBOX_LEN
+ CBOX_PREV(ptr) = ptr - CBOX_LEN
+ CBOX_NEXT(ptr) = NULL
+
+ ptr = freeboxes
+ freeboxes = CBOX_NEXT(ptr)
+ if (freeboxes != NULL)
+ CBOX_PREV(freeboxes) = NULL
+
+ CBOX_NEXT(ptr) = usedboxes
+ usedboxes = ptr
+ if (CBOX_NEXT(ptr) != NULL)
+ CBOX_PREV(CBOX_NEXT(ptr)) = ptr
+
+ # Allocate and get histogram.
+ if (EX_VERBOSE(ex) == YES) {
+ call printf ("Computing colormap....\n")
+ call flush (STDOUT)
+ }
+ call salloc (histogram, B_LEN*B_LEN*B_LEN, TY_INT)
+ call aclri (Memi[histogram], B_LEN*B_LEN*B_LEN)
+ call cm_get_histogram(ex, z1, dz, ptr, Memi[histogram])
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), OF_CMAP)
+
+ # Subdivide boxes until no more free boxes remain
+ while (freeboxes != NULL) {
+ ptr = cm_largest_box (usedboxes)
+ if (ptr != NULL)
+ call cm_splitbox (ptr, usedboxes, freeboxes, Memi[histogram])
+ else
+ break
+ }
+
+ # Set color map and write it out.
+ ptr = usedboxes
+ for (i=0; i<ncolors && ptr!=NULL; i=i+1) {
+ call cm_assign_color (ptr, Mems[cmap+3*i])
+ ptr = CBOX_NEXT(ptr)
+ }
+ ncolors = i
+
+ # Copy the colormap to the main task array.
+ call cm_save_cmap (ex, Mems[cmap], ncolors)
+
+ # Scan histogram and map all values to closest color.
+ # First create cell list as described in Heckbert[2] and then
+ # create mapping from truncated pixel space to color table entries
+
+ call salloc (ColorCells, C_LEN*C_LEN*C_LEN, TY_POINTER)
+ call aclri (Memi[ColorCells], C_LEN*C_LEN*C_LEN)
+ call cm_map_colortable (Memi[histogram], Mems[cmap], ncolors,
+ Memi[ColorCells])
+
+ # Scan image and match input values to table entries.
+ # Apply Floyd-Steinberg dithering.
+
+ if (EX_VERBOSE(ex) == YES) {
+ call printf ("Computing color indices....\n")
+ call flush (STDOUT)
+ }
+ call cm_quant_fsdither (ex, z1, dz, Memi[histogram],
+ Memi[ColorCells], Mems[cmap], ncolors, oim)
+
+ # Unmap the current image pointer(s).
+ do i = 1, EX_NIMAGES(ex) {
+ im = IO_IMPTR(IMOP(ex,i))
+ if (im != NULL)
+ call imunmap (im)
+ }
+
+ # Free the current operand and outbands pointers and fake up a new
+ # one that processes the temporary image.
+ for (i=1; i < EX_NEXPR(ex); i=i+1)
+ call ex_free_outbands (OBANDS(ex,i))
+ for (i=1; i < EX_NIMOPS(ex); i=i+1)
+ call ex_free_operand (IMOP(ex,i))
+ call ex_do_outbands (ex, "b1")
+ O_HEIGHT(ex,1) = EX_OROWS(ex)
+ O_WIDTH(ex,1) = EX_OCOLS(ex)
+
+ # Set the temp image as the only valid image and fudge the operands.
+ EX_NIMAGES(ex) = 1
+ EX_NEXPR(ex) = 1
+ EX_NLINES(ex) = EX_OROWS(ex)
+ IO_IMPTR(IMOP(ex,1)) = oim
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), OF_BAND)
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), BAND_STORAGE)
+
+ for (i=0; i < C_LEN*C_LEN*C_LEN; i=i+1) {
+ if (Memi[ColorCells+i] != NULL)
+ call mfree (Memi[ColorCells+i], TY_STRUCT)
+ }
+
+ call sfree (sp)
+end
+
+
+# CM_SAVE_CMAP -- Save color map for to main structure.
+
+procedure cm_save_cmap (ex, map, ncolors)
+
+pointer ex #i task struct pointer
+short map[3,ncolors] #i Color map
+int ncolors #i Number of colors
+
+int i
+pointer cmap
+
+begin
+ # Allocate the colormap pointer and read the colormap.
+ iferr (call calloc (EX_CMAP(ex), 3*CMAP_SIZE, TY_CHAR))
+ call error (0, "Error allocating colormap pointer.")
+ cmap = EX_CMAP(ex)
+
+ for (i=1; i<=min(ncolors,256); i=i+1) {
+ CMAP(cmap,EX_RED,i) = (map[1,i] + 0.5)
+ CMAP(cmap,EX_GREEN,i) = (map[2,i] + 0.5)
+ CMAP(cmap,EX_BLUE,i) = (map[3,i] + 0.5)
+ }
+ for (; i<=256; i=i+1) {
+ CMAP(cmap,EX_RED,i) = 0
+ CMAP(cmap,EX_GREEN,i) = 0
+ CMAP(cmap,EX_BLUE,i) = 0
+ }
+end
+
+
+# CM_GETLINE -- Get a line of intensity mapped input data.
+
+procedure cm_getline (ex, z1, dz, line, data)
+
+pointer ex #I task struct pointer
+real z1[3] #I Intensity mapping origins
+real dz[3] #I Intensity mapping ranges
+int line #I Line to be obtained
+pointer data #O Intensity mapped data
+
+int i, j, nc, lnum
+pointer iptr, optr, bptr, op
+
+pointer ex_evaluate(), ex_chtype()
+
+begin
+ # See if we're flipping the image.
+ if (bitset (EX_OUTFLAGS(ex), OF_FLIPY))
+ lnum = EX_NLINES(ex) - line + 1
+ else
+ lnum = line
+
+ # Get the pixels.
+ call ex_getpix (ex, lnum)
+
+ nc = EX_OCOLS(ex)
+ call malloc (iptr, nc, TY_SHORT)
+ do i = 1, 3 {
+ op = ex_evaluate (ex, O_EXPR(ex,i))
+ bptr = ex_chtype (ex, op, EX_OUTTYPE(ex))
+ call achtbs (Memc[bptr], Mems[iptr], nc)
+ call evvfree (op)
+
+ optr = data + i - 1
+ do j = 1, nc {
+ Memi[optr] = max (0, min (255, int (Mems[iptr+j-1])))
+ optr = optr + 3
+ }
+
+ call mfree (bptr, TY_CHAR)
+ }
+ call mfree (iptr, TY_SHORT)
+end
+
+
+# CM_GET_HISTOGRAM -- Compute color histogram
+
+procedure cm_get_histogram (ex, z1, dz, box, histogram)
+
+pointer ex #I task struct pointer
+real z1[3] #I Intensity mapping origins
+real dz[3] #I Intensity mapping ranges
+pointer box #O Initial box
+int histogram[B_LEN,B_LEN,B_LEN] #O Histogram
+
+int i, j, nc, nl, r, g, b, rmin, gmin, bmin, rmax, gmax, bmax
+pointer sp, data, ptr
+
+begin
+ nc = EX_OCOLS(ex)
+ nl = EX_OROWS(ex)
+
+ call smark (sp)
+ call salloc (data, 3 * nc, TY_INT)
+
+ rmin = A_LEN; rmax = -1
+ gmin = A_LEN; gmax = -1
+ bmin = A_LEN; bmax = -1
+
+ # calculate histogram
+ do j = 1, nl {
+ call cm_getline (ex, z1, dz, j, data)
+ ptr = data
+ do i = 1, nc {
+ r = Memi[ptr] / AB_SHIFT + 1
+ g = Memi[ptr+1] / AB_SHIFT + 1
+ b = Memi[ptr+2] / AB_SHIFT + 1
+ ptr = ptr + 3
+
+ histogram[r,g,b] = histogram[r,g,b] + 1
+
+ rmin = min (rmin, r)
+ rmax = max (rmax, r)
+ gmin = min (gmin, g)
+ gmax = max (gmax, g)
+ bmin = min (bmin, b)
+ bmax = max (bmax, b)
+ }
+ }
+
+ CBOX_RMIN(box) = rmin
+ CBOX_GMIN(box) = gmin
+ CBOX_BMIN(box) = bmin
+ CBOX_RMAX(box) = rmax
+ CBOX_GMAX(box) = gmax
+ CBOX_BMAX(box) = bmax
+ CBOX_TOTAL(box) = nc * nl
+
+ call sfree (sp)
+end
+
+
+
+# CM_LARGEST_BOX -- Return pointer to largest box
+
+pointer procedure cm_largest_box (usedboxes)
+
+pointer usedboxes #I Pointer to used boxes
+
+pointer tmp, ptr
+int size
+
+begin
+ size = -1
+ ptr = NULL
+
+ for (tmp=usedboxes; tmp!=NULL; tmp=CBOX_NEXT(tmp)) {
+ if ((CBOX_RMAX(tmp) > CBOX_RMIN(tmp) ||
+ CBOX_GMAX(tmp) > CBOX_GMIN(tmp) ||
+ CBOX_BMAX(tmp) > CBOX_BMIN(tmp)) &&
+ CBOX_TOTAL(tmp) > size) {
+ ptr = tmp
+ size = CBOX_TOTAL(tmp)
+ }
+ }
+ return(ptr)
+end
+
+
+# CM_SPLITBOX -- Split a box along largest dimension
+
+procedure cm_splitbox (box, usedboxes, freeboxes, histogram)
+
+pointer box #U Box to split
+pointer usedboxes #U Used boxes
+pointer freeboxes #U Free boxes
+int histogram[B_LEN, B_LEN, B_LEN] #I Histogram
+
+int first, last, i, j, rdel, gdel, bdel, sum1, sum2
+pointer sp, hist, new
+int ir, ig, ib
+int rmin, rmax, gmin, gmax, bmin, bmax
+int which
+
+begin
+ call smark (sp)
+ call salloc (hist, B_LEN, TY_INT)
+
+ # see which axis is the largest, do a histogram along that
+ # axis. Split at median point. Contract both new boxes to
+ # fit points and return
+
+ first = 1; last = 1
+ rmin = CBOX_RMIN(box); rmax = CBOX_RMAX(box)
+ gmin = CBOX_GMIN(box); gmax = CBOX_GMAX(box)
+ bmin = CBOX_BMIN(box); bmax = CBOX_BMAX(box)
+
+ rdel = rmax - rmin
+ gdel = gmax - gmin
+ bdel = bmax - bmin
+
+ if (rdel>=gdel && rdel>=bdel)
+ which = RED
+ else if (gdel>=bdel)
+ which = GREEN
+ else
+ which = BLUE
+
+ # get histogram along longest axis
+ switch (which) {
+ case RED:
+ for (ir=rmin; ir<=rmax; ir=ir+1) {
+ sum1 = 0
+ for (ig=gmin; ig<=gmax; ig=ig+1) {
+ for (ib=bmin; ib<=bmax; ib=ib+1) {
+ sum1 = sum1 + histogram[ir,ig,ib]
+ }
+ }
+ Memi[hist+ir-1] = sum1
+ }
+ first = rmin; last = rmax
+
+ case GREEN:
+ for (ig=gmin; ig<=gmax; ig=ig+1) {
+ sum1 = 0
+ for (ir=rmin; ir<=rmax; ir=ir+1) {
+ for (ib=bmin; ib<=bmax; ib=ib+1) {
+ sum1 = sum1 + histogram[ir,ig,ib]
+ }
+ }
+ Memi[hist+ig-1] = sum1
+ }
+ first = gmin; last = gmax
+
+ case BLUE:
+ for (ib=bmin; ib<=bmax; ib=ib+1) {
+ sum1 = 0
+ for (ir=rmin; ir<=rmax; ir=ir+1) {
+ for (ig=gmin; ig<=gmax; ig=ig+1) {
+ sum1 = sum1 + histogram[ir,ig,ib]
+ }
+ }
+ Memi[hist+ib-1] = sum1
+ }
+ first = bmin; last = bmax
+ }
+
+
+ # find median point
+ sum1 = 0
+ sum2 = CBOX_TOTAL(box) / 2
+ for (i=first; i<=last; i=i+1) {
+ sum1 = sum1 + Memi[hist+i-1]
+ if (sum1 >= sum2)
+ break
+ }
+ if (i == first)
+ i = i + 1
+
+
+ # Create new box, re-allocate points
+
+ new = freeboxes
+ freeboxes = CBOX_NEXT(new)
+ if (freeboxes != NULL)
+ CBOX_PREV(freeboxes) = NULL
+ if (usedboxes != NULL)
+ CBOX_PREV(usedboxes) = new
+ CBOX_NEXT(new) = usedboxes
+ usedboxes = new
+
+ sum1 = 0
+ sum2 = 0
+ for (j = first; j < i; j=j+1)
+ sum1 = sum1 + Memi[hist+j-1]
+ for (; j <= last; j=j+1)
+ sum2 = sum2 + Memi[hist+j-1]
+ CBOX_TOTAL(new) = sum1
+ CBOX_TOTAL(box) = sum2
+
+ CBOX_RMIN(new) = rmin; CBOX_RMAX(new) = rmax
+ CBOX_GMIN(new) = gmin; CBOX_GMAX(new) = gmax
+ CBOX_BMIN(new) = bmin; CBOX_BMAX(new) = bmax
+
+ switch (which) {
+ case RED:
+ CBOX_RMAX(new) = i-1; CBOX_RMIN(box) = i
+ case GREEN:
+ CBOX_GMAX(new) = i-1; CBOX_GMIN(box) = i
+ case BLUE:
+ CBOX_BMAX(new) = i-1; CBOX_BMIN(box) = i
+ }
+
+ call cm_shrinkbox (new, histogram)
+ call cm_shrinkbox (box, histogram)
+ call sfree (sp)
+end
+
+
+# CM_SHRINKBOX -- Shrink box
+
+procedure cm_shrinkbox (box, histogram)
+
+pointer box #U Box
+int histogram[B_LEN,B_LEN,B_LEN] #I Histogram
+
+int ir, ig, ib
+int rmin, rmax, gmin, gmax, bmin, bmax
+
+define have_rmin 11
+define have_rmax 12
+define have_gmin 13
+define have_gmax 14
+define have_bmin 15
+define have_bmax 16
+
+begin
+
+ rmin = CBOX_RMIN(box); rmax = CBOX_RMAX(box)
+ gmin = CBOX_GMIN(box); gmax = CBOX_GMAX(box)
+ bmin = CBOX_BMIN(box); bmax = CBOX_BMAX(box)
+
+ if (rmax > rmin) {
+ for (ir=rmin; ir<=rmax; ir=ir+1) {
+ for (ig=gmin; ig<=gmax; ig=ig+1) {
+ for (ib=bmin; ib<=bmax; ib=ib+1) {
+ if (histogram[ir,ig,ib] != 0) {
+ rmin = ir
+ CBOX_RMIN(box) = rmin
+ goto have_rmin
+ }
+ }
+ }
+ }
+
+have_rmin
+ if (rmax > rmin) {
+ for (ir=rmax; ir>=rmin; ir=ir-1) {
+ for (ig=gmin; ig<=gmax; ig=ig+1) {
+ for (ib=bmin; ib<=bmax; ib=ib+1) {
+ if (histogram[ir,ig,ib] != 0) {
+ rmax = ir
+ CBOX_RMAX(box) = rmax
+ goto have_rmax
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+have_rmax
+ if (gmax > gmin) {
+ for (ig=gmin; ig<=gmax; ig=ig+1) {
+ for (ir=rmin; ir<=rmax; ir=ir+1) {
+ for (ib=bmin; ib<=bmax; ib=ib+1) {
+ if (histogram[ir,ig,ib] != 0) {
+ gmin = ig
+ CBOX_GMIN(box) = gmin
+ goto have_gmin
+ }
+ }
+ }
+ }
+
+have_gmin
+ if (gmax > gmin) {
+ for (ig=gmax; ig>=gmin; ig=ig-1) {
+ for (ir=rmin; ir<=rmax; ir=ir+1) {
+ for (ib=bmin; ib<=bmax; ib=ib+1) {
+ if (histogram[ir,ig,ib] != 0) {
+ gmax = ig
+ CBOX_GMAX(box) = gmax
+ goto have_gmax
+ }
+ }
+ }
+ }
+ }
+ }
+
+have_gmax
+ if (bmax > bmin) {
+ for (ib=bmin; ib<=bmax; ib=ib+1) {
+ for (ir=rmin; ir<=rmax; ir=ir+1) {
+ for (ig=gmin; ig<=gmax; ig=ig+1) {
+ if (histogram[ir,ig,ib] != 0) {
+ bmin = ib
+ CBOX_BMIN(box) = bmin
+ goto have_bmin
+ }
+ }
+ }
+ }
+
+have_bmin
+ if (bmax > bmin) {
+ for (ib=bmax; ib>=bmin; ib=ib-1) {
+ for (ir=rmin; ir<=rmax; ir=ir+1) {
+ for (ig=gmin; ig<=gmax; ig=ig+1) {
+ if (histogram[ir,ig,ib] != 0) {
+ bmax = ib
+ CBOX_BMAX(box) = bmax
+ goto have_bmax
+ }
+ }
+ }
+ }
+ }
+ }
+
+have_bmax
+ return
+end
+
+
+
+# CM_ASSIGN_COLOR -- Assign colors
+
+procedure cm_assign_color (box, cmap)
+
+pointer box #I Box
+short cmap[3] #O Color map entry
+
+begin
+ # +1 ensures that color represents the middle of the box
+
+ cmap[1] = ((CBOX_RMIN(box) + CBOX_RMAX(box) - 2) * AB_SHIFT) / 2
+ cmap[2] = ((CBOX_GMIN(box) + CBOX_GMAX(box) - 2) * AB_SHIFT) / 2
+ cmap[3] = ((CBOX_BMIN(box) + CBOX_BMAX(box) - 2) * AB_SHIFT) / 2
+end
+
+
+
+# CM_MAP_COLORTABLE -- Map the color table
+
+procedure cm_map_colortable (histogram, cmap, ncolor, ColorCells)
+
+int histogram[B_LEN,B_LEN,B_LEN] #U Histogram
+short cmap[3,ncolor] #I Color map
+int ncolor #I Number of colors
+pointer ColorCells[C_LEN,C_LEN,C_LEN] #O Color cells
+
+int i, j, ir, ig, ib, rcell, bcell, gcell
+long dist, d2, tmp
+pointer cell, cm_create_colorcell()
+
+begin
+ for (ir=0; ir<B_LEN; ir=ir+1) {
+ rcell = 1 + ir / BC_SHIFT
+ for (ig=0; ig<B_LEN; ig=ig+1) {
+ gcell = 1 + ig / BC_SHIFT
+ for (ib=0; ib<B_LEN; ib=ib+1) {
+ bcell = 1 + ib / BC_SHIFT
+ if (histogram[1+ir,1+ig,1+ib]==0)
+ histogram[1+ir,1+ig,1+ib] = -1
+ else {
+ cell = ColorCells[rcell, gcell, bcell]
+
+ if (cell == NULL)
+ cell = cm_create_colorcell (ColorCells,
+ ir*AB_SHIFT, ig*AB_SHIFT, ib*AB_SHIFT,
+ cmap, ncolor)
+
+ dist = 2000000000
+ for (i=0; i<CCELL_NUM_ENTS(cell) &&
+ dist>CCELL_ENTRIES(cell,i,1); i=i+1) {
+ j = CCELL_ENTRIES(cell,i,0)
+ d2 = cmap[1,1+j] - (ir * BC_SHIFT)
+ d2 = (d2 * d2 * R2FACT)
+ tmp = cmap[2,1+j] - (ig * BC_SHIFT)
+ d2 = d2 + (tmp*tmp * G2FACT)
+ tmp = cmap[3,1+j] - (ib * BC_SHIFT)
+ d2 = d2 + (tmp*tmp * B2FACT)
+ if (d2 < dist) {
+ dist = d2
+ histogram[1+ir,1+ig,1+ib] = j
+ }
+ }
+ }
+ }
+ }
+ }
+end
+
+
+
+# CM_CREATE_COLORCELL -- Create a color cell structure
+
+pointer procedure cm_create_colorcell (ColorCells, ra, ga, ba, cmap, ncolor)
+
+pointer ColorCells[C_LEN,C_LEN,C_LEN] #U Color cells
+int ra, ga, ba #I Color to create cell for
+short cmap[3,ncolor] #I Color map
+int ncolor #I Number of colors
+
+int i, n, next_n, ir,ig,ib, r1,g1,b1
+long dist, mindist, tmp
+pointer ptr
+
+begin
+ ir = ra / AC_SHIFT
+ ig = ga / AC_SHIFT
+ ib = ba / AC_SHIFT
+
+ r1 = ir * AC_SHIFT
+ g1 = ig * AC_SHIFT
+ b1 = ib * AC_SHIFT
+
+ call malloc (ptr, CCELL_LEN, TY_STRUCT)
+ ColorCells[1+ir,1+ig,1+ib] = ptr
+ CCELL_NUM_ENTS(ptr) = 0
+
+ # step 1: find all colors inside this cell, while we're at
+ # it, find distance of centermost point to furthest corner
+
+ mindist = 2000000000
+
+ for (i=1; i<=ncolor; i=i+1) {
+ if (cmap[1,i]/AC_SHIFT == ir &&
+ cmap[2,i]/AC_SHIFT == ig &&
+ cmap[3,i]/AC_SHIFT == ib) {
+ CCELL_ENTRIES(ptr,CCELL_NUM_ENTS(ptr),0) = i - 1
+ CCELL_ENTRIES(ptr,CCELL_NUM_ENTS(ptr),1) = 0
+ CCELL_NUM_ENTS(ptr) = CCELL_NUM_ENTS(ptr) + 1
+
+ tmp = cmap[1,i] - r1
+ if (tmp < (A_LEN/C_LEN/2))
+ tmp = A_LEN/C_LEN-1 - tmp
+ dist = (tmp*tmp * R2FACT)
+
+ tmp = cmap[2,i] - g1
+ if (tmp < (A_LEN/C_LEN/2))
+ tmp = A_LEN/C_LEN-1 - tmp
+ dist = dist + (tmp*tmp * G2FACT)
+
+ tmp = cmap[3,i] - b1
+ if (tmp < (A_LEN/C_LEN/2))
+ tmp = A_LEN/C_LEN-1 - tmp
+ dist = dist + (tmp*tmp * B2FACT)
+
+ mindist = min (mindist, dist)
+ }
+ }
+
+
+ # step 3: find all points within that distance to box
+
+ for (i=1; i<=ncolor; i=i+1) {
+ if (cmap[1,i]/AC_SHIFT != ir ||
+ cmap[2,i]/AC_SHIFT != ig ||
+ cmap[3,i]/AC_SHIFT != ib) {
+ dist = 0
+ tmp = r1 - cmap[1,i]
+ if (tmp>0) {
+ dist = dist + (tmp*tmp * R2FACT)
+ } else {
+ tmp = cmap[1,i] - (r1 + A_LEN/C_LEN-1)
+ if (tmp > 0)
+ dist = dist + (tmp*tmp * R2FACT)
+ }
+
+ tmp = g1 - cmap[2,i]
+ if (tmp>0) {
+ dist = dist + (tmp*tmp * G2FACT)
+ } else {
+ tmp = cmap[2,i] - (g1 + A_LEN/C_LEN-1)
+ if (tmp > 0)
+ dist = dist + (tmp*tmp * G2FACT)
+ }
+
+ tmp = b1 - cmap[3,i]
+ if (tmp>0) {
+ dist = dist + (tmp*tmp * B2FACT)
+ } else {
+ tmp = cmap[3,i] - (b1 + A_LEN/C_LEN-1)
+ if (tmp > 0)
+ dist = dist + (tmp*tmp * B2FACT)
+ }
+
+ if (dist < mindist) {
+ CCELL_ENTRIES(ptr,CCELL_NUM_ENTS(ptr),0) = i - 1
+ CCELL_ENTRIES(ptr,CCELL_NUM_ENTS(ptr),1) = dist
+ CCELL_NUM_ENTS(ptr) = CCELL_NUM_ENTS(ptr) + 1
+ }
+ }
+ }
+
+
+ # sort color cells by distance, use cheap exchange sort
+ n = CCELL_NUM_ENTS(ptr) - 1
+ while (n > 0) {
+ next_n = 0
+ for (i=0; i<n; i=i+1) {
+ if (CCELL_ENTRIES(ptr,i,1) > CCELL_ENTRIES(ptr,i+1,1)) {
+ tmp = CCELL_ENTRIES(ptr,i,0)
+ CCELL_ENTRIES(ptr,i,0) = CCELL_ENTRIES(ptr,i+1,0)
+ CCELL_ENTRIES(ptr,i+1,0) = tmp
+ tmp = CCELL_ENTRIES(ptr,i,1)
+ CCELL_ENTRIES(ptr,i,1) = CCELL_ENTRIES(ptr,i+1,1)
+ CCELL_ENTRIES(ptr,i+1,1) = tmp
+ next_n = i
+ }
+ }
+ n = next_n
+ }
+
+ return (ptr)
+end
+
+
+
+# CM_QUANT_FSDITHER -- Quantized Floyd-Steinberg Dither
+
+procedure cm_quant_fsdither (ex, z1, dz, histogram,
+ ColorCells, cmap, ncolor, oim)
+
+pointer ex #I task struct pointer
+real z1[3] #I Intensity mapping origins
+real dz[3] #I Intensity mapping ranges
+int histogram[B_LEN,B_LEN,B_LEN] #U Histogram
+pointer ColorCells[C_LEN,C_LEN,C_LEN] #U Color cell data
+short cmap[3,ncolor] #I Color map
+int ncolor #I Number of colors
+pointer oim #O Output IMIO pointer
+
+pointer thisptr, nextptr, optr, impl2s()
+pointer sp, thisline, nextline, tmpptr
+int ir, ig, ib, r1, g1, b1, rcell, bcell, gcell
+int i, j, nc, nl, oval
+
+int ci, cj
+long dist, d2, tmp
+pointer cell
+
+pointer cm_create_colorcell()
+
+begin
+ nc = EX_OCOLS(ex)
+ nl = EX_OROWS(ex)
+
+ call smark (sp)
+ call salloc (thisline, nc * 3, TY_INT)
+ call salloc (nextline, nc * 3, TY_INT)
+
+ # get first line of picture
+ call cm_getline (ex, z1, dz, 1, nextline)
+
+ for (i=1; i<=nl; i=i+1) {
+ # swap thisline and nextline
+ tmpptr = thisline
+ thisline = nextline
+ nextline = tmpptr
+
+ # read in next line
+ if (i < nl)
+ #call cm_getline (ex, z1, dz, i, nextline, nc)
+ call cm_getline (ex, z1, dz, i, nextline)
+
+ # dither this line and put it into the output picture
+ thisptr = thisline
+ nextptr = nextline
+ optr = impl2s (oim, i)
+
+ for (j=1; j<=nc; j=j+1) {
+ r1 = Memi[thisptr]
+ g1 = Memi[thisptr+1]
+ b1 = Memi[thisptr+2]
+ thisptr = thisptr + 3
+
+ r1 = max (0, min (A_LEN-1, r1))
+ g1 = max (0, min (A_LEN-1, g1))
+ b1 = max (0, min (A_LEN-1, b1))
+
+ ir = r1 / AB_SHIFT
+ ig = g1 / AB_SHIFT
+ ib = b1 / AB_SHIFT
+
+ oval = histogram[1+ir,1+ig,1+ib]
+ if (oval == -1) {
+ rcell = 1 + ir / BC_SHIFT
+ gcell = 1 + ig / BC_SHIFT
+ bcell = 1 + ib / BC_SHIFT
+ cell = ColorCells[rcell, gcell, bcell]
+ if (cell == NULL)
+ cell = cm_create_colorcell (ColorCells, r1, g1, b1,
+ cmap, ncolor)
+
+ dist = 2000000000
+ for (ci=0; ci<CCELL_NUM_ENTS(cell) &&
+ dist>CCELL_ENTRIES(cell,ci,1); ci=ci+1) {
+ cj = CCELL_ENTRIES(cell,ci,0)
+ d2 = (cmap[1,1+cj]/AB_SHIFT) - ir
+ d2 = (d2*d2 * R2FACT)
+ tmp = (cmap[2,1+cj]/AB_SHIFT) - ig
+ d2 = d2 + (tmp*tmp * G2FACT)
+ tmp = (cmap[3,1+cj]/AB_SHIFT) - ib
+ d2 = d2 + (tmp*tmp * B2FACT)
+ if (d2<dist) {
+ dist = d2
+ oval = cj
+ }
+ }
+ histogram[1+ir,1+ig,1+ib] = oval
+ }
+
+ Mems[optr] = 1 + oval
+ optr = optr + 1
+
+ r1 = r1 - cmap[1,1+oval]
+ g1 = g1 - cmap[2,1+oval]
+ b1 = b1 - cmap[3,1+oval]
+
+ # don't use tables, because r1,g1,b1 could go negative
+ if (j < nc) {
+ tmpptr = thisptr
+ if (r1 < 0)
+ Memi[tmpptr] = Memi[tmpptr] + (r1*7-8)/16
+ else
+ Memi[tmpptr] = Memi[tmpptr] + (r1*7+8)/16
+ tmpptr = tmpptr + 1
+ if (g1 < 0)
+ Memi[tmpptr] = Memi[tmpptr] + (g1*7-8)/16
+ else
+ Memi[tmpptr] = Memi[tmpptr] + (g1*7+8)/16
+ tmpptr = tmpptr + 1
+ if (b1 < 0)
+ Memi[tmpptr] = Memi[tmpptr] + (b1*7-8)/16
+ else
+ Memi[tmpptr] = Memi[tmpptr] + (b1*7+8)/16
+ }
+
+ if (i < nl) {
+ if (j > 1) {
+ tmpptr = nextptr - 3
+ if (r1 < 0)
+ Memi[tmpptr] = Memi[tmpptr] + (r1*3-8)/16
+ else
+ Memi[tmpptr] = Memi[tmpptr] + (r1*3+8)/16
+ tmpptr = tmpptr + 1
+ if (g1 < 0)
+ Memi[tmpptr] = Memi[tmpptr] + (g1*3-8)/16
+ else
+ Memi[tmpptr] = Memi[tmpptr] + (g1*3+8)/16
+ tmpptr = tmpptr + 1
+ if (b1 < 0)
+ Memi[tmpptr] = Memi[tmpptr] + (b1*3-8)/16
+ else
+ Memi[tmpptr] = Memi[tmpptr] + (b1*3+8)/16
+ }
+
+ tmpptr = nextptr
+ if (r1 < 0)
+ Memi[tmpptr] = Memi[tmpptr] + (r1*5-8)/16
+ else
+ Memi[tmpptr] = Memi[tmpptr] + (r1*5+8)/16
+ tmpptr = tmpptr + 1
+ if (g1 < 0)
+ Memi[tmpptr] = Memi[tmpptr] + (g1*5-8)/16
+ else
+ Memi[tmpptr] = Memi[tmpptr] + (g1*5+8)/16
+ tmpptr = tmpptr + 1
+ if (b1 < 0)
+ Memi[tmpptr] = Memi[tmpptr] + (b1*5-8)/16
+ else
+ Memi[tmpptr] = Memi[tmpptr] + (b1*5+8)/16
+
+ if (j < nc) {
+ tmpptr = nextptr + 3
+ if (r1 < 0)
+ Memi[tmpptr] = Memi[tmpptr] + (r1-8)/16
+ else
+ Memi[tmpptr] = Memi[tmpptr] + (r1+8)/16
+ tmpptr = tmpptr + 1
+ if (g1 < 0)
+ Memi[tmpptr] = Memi[tmpptr] + (g1-8)/16
+ else
+ Memi[tmpptr] = Memi[tmpptr] + (g1+8)/16
+ tmpptr = tmpptr + 1
+ if (b1 < 0)
+ Memi[tmpptr] = Memi[tmpptr] + (b1-8)/16
+ else
+ Memi[tmpptr] = Memi[tmpptr] + (b1+8)/16
+ }
+ nextptr = nextptr + 3
+ }
+ }
+ }
+
+ # Flush the pixels to the output image, otherwise we end up with an
+ # odd line which may or may not be actual pixels.
+ call imflush (oim)
+
+ call sfree (sp)
+end
diff --git a/pkg/dataio/export/exzscale.x b/pkg/dataio/export/exzscale.x
new file mode 100644
index 00000000..f0a4b506
--- /dev/null
+++ b/pkg/dataio/export/exzscale.x
@@ -0,0 +1,755 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <evvexpr.h>
+include "export.h"
+
+define DEBUG false
+
+
+.help ex_zscale
+.nf ___________________________________________________________________________
+EX_ZSCALE -- Compute the optimal Z1, Z2 (range of greyscale values to be
+displayed) of an expression. For efficiency a statistical subsample of the
+expression is used. The pixel sample evenly subsamples the expression in x
+and y. The entire expression is used if the number of pixels in the expression
+is smaller than the desired sample.
+
+The sample is accumulated in a buffer and sorted by greyscale value.
+The median value is the central value of the sorted array. The slope of a
+straight line fitted to the sorted sample is a measure of the standard
+deviation of the sample about the median value. Our algorithm is to sort
+the sample and perform an iterative fit of a straight line to the sample,
+using pixel rejection to omit gross deviants near the endpoints. The fitted
+straight line is the transfer function used to map image Z into display Z.
+If more than half the pixels are rejected the full range is used. The slope
+of the fitted line is divided by the user-supplied contrast factor and the
+final Z1 and Z2 are computed, taking the origin of the fitted line at the
+median value.
+.endhelp ______________________________________________________________________
+
+define MIN_NPIXELS 5 # smallest permissible sample
+define MAX_REJECT 0.5 # max frac. of pixels to be rejected
+define GOOD_PIXEL 0 # use pixel in fit
+define BAD_PIXEL 1 # ignore pixel in all computations
+define REJECT_PIXEL 2 # reject pixel after a bit
+define KREJ 2.5 # k-sigma pixel rejection factor
+define MAX_ITERATIONS 5 # maximum number of fitline iterations
+
+
+# EX_PATCH_ZSCALE - Rather than compute the optimal zscale values for each
+# line in the expression we'll go through the expression string and compute
+# the values here. The expression string is modified with the values so that
+# when evaluated they are seen as arguments to the function.
+
+procedure ex_patch_zscale (ex, expnum)
+
+pointer ex #i task struct pointer
+int expnum #i expression number to fix
+
+pointer sp, exp, func
+int ip, pp
+
+bool streq()
+
+begin
+ call smark (sp)
+ call salloc (exp, SZ_EXPSTR, TY_CHAR)
+ call salloc (func, SZ_FNAME, TY_CHAR)
+ call aclrc(Memc[exp], SZ_EXPSTR)
+ call aclrc(Memc[func], SZ_FNAME)
+
+ # Copy the final expression string to the output buffer.
+ call strcpy (O_EXPR(ex,expnum), Memc[exp], SZ_EXPSTR)
+
+ # Now fix up any zscale functions calls embedded in the expression.
+ ip = 0
+ repeat {
+ # Skip ahead to a possible zscale()/mzscale() call.
+ while (Memc[exp+ip] != 'z' && Memc[exp+ip] != EOS)
+ ip = ip + 1
+ if (Memc[exp+ip] == EOS)
+ break
+
+ # Get the function name.
+ pp = 0
+ call aclrc (Memc[func], SZ_FNAME)
+ while (Memc[exp+ip] != '(' && Memc[exp+ip] != EOS) {
+ Memc[func+pp] = Memc[exp+ip]
+ ip = ip + 1
+ pp = pp + 1
+ }
+ Memc[func+pp+1] = EOS
+ if (Memc[exp+ip] == EOS)
+ break
+
+ if (DEBUG) { call eprintf("\tfunc=`%s'\n");call pargstr(Memc[func])}
+
+ # Update pointer into string past '('.
+ ip = ip + 1
+
+ if (streq(Memc[func],"zscale") || streq(Memc[func],"zscalem")) {
+ iferr (call ex_edit_zscale (ex, Memc[exp], ip+1))
+ call erract (EA_FATAL)
+ ip = ip + 1
+ }
+ }
+
+ # Copy the final expression string to the output buffer.
+ call strcpy (Memc[exp], O_EXPR(ex,expnum), SZ_EXPSTR)
+
+ call sfree (sp)
+end
+
+
+# EX_EDIT_ZSCALE - Process the ZSCALE special function. This function requires
+# preprocessing in the event the user didn't supply a z1/z2 value. What
+# we'll do here is pre-compute those values and patch up the expression
+# string. Otherwise we'll make sure the rest of the arguments are legal.
+
+procedure ex_edit_zscale (ex, expstr, pp)
+
+pointer ex #i task struct pointer
+char expstr[ARB] #i expression string
+int pp #i position pointer
+
+pointer sp, arg, arg2, exp, buf
+pointer exptr, exptr2, ep
+char ch
+int ip, op, tp, tp2, plev
+real z1, z2
+
+pointer ex_evaluate()
+
+begin
+ call smark (sp)
+ call salloc (arg, SZ_EXPSTR, TY_CHAR); call aclrc (Memc[arg], SZ_EXPSTR)
+ call salloc (arg2, SZ_EXPSTR,TY_CHAR); call aclrc (Memc[arg2],SZ_EXPSTR)
+ call salloc (exp, SZ_EXPSTR, TY_CHAR); call aclrc (Memc[exp], SZ_EXPSTR)
+ call salloc (buf, SZ_EXPSTR, TY_CHAR); call aclrc (Memc[buf], SZ_EXPSTR)
+
+ if (DEBUG) { call eprintf("\t\texp=`%s'\n");call pargstr(expstr)}
+
+ # Gather the expression argument.
+ ip = pp
+ op = 0
+ plev = 0
+ repeat {
+ ch = expstr[ip]
+ if (ch == '(') plev = plev + 1
+ if (ch == ')') plev = plev - 1
+ Memc[arg+op] = ch
+ if ((ch == ',' && plev == 0) || (ch == ')' && plev < 0))
+ break
+ ip = ip + 1
+ op = op + 1
+ }
+ Memc[arg+op] = EOS
+ tp = ip - 1
+ tp2 = tp
+ if (DEBUG) {call eprintf("\t\targ = `%s'\n");call pargstr(Memc[arg])}
+
+ # Gather the mask argument.
+ if (expstr[pp-2] == 'm' && ch == ',') {
+ ip = ip + 1
+ op = 0
+ plev = 0
+ repeat {
+ ch = expstr[ip]
+ if (ch == '(') plev = plev + 1
+ if (ch == ')') plev = plev - 1
+ Memc[arg2+op] = ch
+ if ((ch == ',' && plev == 0) || (ch == ')' && plev < 0))
+ break
+ ip = ip + 1
+ op = op + 1
+ }
+ Memc[arg2+op] = EOS
+ tp2 = ip - 1
+ if (DEBUG) {
+ call eprintf("\t\targ2 = `%s'\n")
+ call pargstr(Memc[arg2])
+ }
+ }
+
+ if (ch == ',') {
+ # We have more arguments, assume they're okay and return.
+ call sfree (sp)
+ return
+
+ } else if (ch == ')') {
+ # This is the end of the zscale function, so compute the optimal
+ # z1/z2 values for the given expression. First, dummy up an out-
+ # bands pointer.
+
+ call ex_alloc_outbands (exptr)
+ call strcpy (Memc[arg], Memc[OB_EXPSTR(exptr)], SZ_EXPSTR)
+
+ # Get the size of the expression.
+ call ex_getpix (ex, 1)
+ ep = ex_evaluate (ex, Memc[OB_EXPSTR(exptr)])
+ OB_WIDTH(exptr) = O_LEN(ep)
+ call evvfree (ep)
+ if (OB_WIDTH(exptr) == 0)
+ OB_HEIGHT(exptr) = 1
+ else
+ OB_HEIGHT(exptr) = EX_NLINES(ex)
+
+ # Setup the mask expression if needed.
+ if (Memc[arg2] != EOS) {
+ call ex_alloc_outbands (exptr2)
+ call strcpy (Memc[arg2], Memc[OB_EXPSTR(exptr2)], SZ_EXPSTR)
+
+ # Get the size of the expression.
+ ep = ex_evaluate (ex, Memc[OB_EXPSTR(exptr2)])
+ OB_WIDTH(exptr2) = O_LEN(ep)
+ call evvfree (ep)
+ if (OB_WIDTH(exptr2) == 0)
+ OB_HEIGHT(exptr2) = 1
+ else
+ OB_HEIGHT(exptr2) = EX_NLINES(ex)
+ if (OB_WIDTH(exptr2) != OB_WIDTH(exptr) ||
+ OB_WIDTH(exptr2) != OB_WIDTH(exptr))
+ call error (1, "Sizes of zscalem arguments not the same.")
+ } else
+ exptr2 = NULL
+
+ if (EX_VERBOSE(ex) == YES) {
+ call printf ("Computing zscale values...")
+ call flush (STDOUT)
+ }
+
+ call ex_zscale (ex, exptr, exptr2, z1, z2,
+ CONTRAST, SAMPLE_SIZE, SAMP_LEN)
+ call ex_free_outbands (exptr)
+ if (exptr2 != NULL)
+ call ex_free_outbands (exptr2)
+
+ if (DEBUG) {call eprintf("\t\t\tz1=%g z2=%g\n")
+ call pargr(z1) ; call pargr (z2) }
+
+ # Now patch up the expression string to insert the computed values.
+ if (expstr[pp-2] == 'm') {
+ call strcpy (expstr, Memc[exp], pp-3)
+ call strcat (expstr[pp-1], Memc[exp], tp-1)
+ } else
+ call strcpy (expstr, Memc[exp], tp)
+ call sprintf (Memc[buf], SZ_EXPSTR, ",%g,%g,256")
+ call pargr (z1)
+ call pargr (z2)
+ call strcat (Memc[buf], Memc[exp], SZ_EXPSTR)
+ call strcat (expstr[tp2+1], Memc[exp], SZ_EXPSTR)
+
+ # Print the computed values to the screen.
+ if (EX_VERBOSE(ex) == YES) {
+ call printf ("z1=%g z2=%g\n")
+ call pargr (z1)
+ call pargr (z2)
+ }
+ }
+
+ # Copy fixed-up expression to input buffer.
+ call aclrc (expstr, SZ_EXPSTR)
+ call strcpy (Memc[exp], expstr, SZ_EXPSTR)
+
+ if (DEBUG){call eprintf("\t\tnew expr=`%s'\n");call pargstr(expstr)}
+
+ call sfree (sp)
+end
+
+
+# EX_ZSCALE -- Sample the expression and compute Z1 and Z2.
+
+procedure ex_zscale (ex, exptr, exptr2, z1, z2, contrast, optimal_sample_size,
+ len_stdline)
+
+pointer ex # task struct pointer
+pointer exptr # expression struct pointer
+pointer exptr2 # expression struct pointer (mask)
+real z1, z2 # output min and max greyscale values
+real contrast # adj. to slope of transfer function
+int optimal_sample_size # desired number of pixels in sample
+int len_stdline # optimal number of pixels per line
+
+int npix, minpix, ngoodpix, center_pixel, ngrow
+real zmin, zmax, median
+real zstart, zslope
+pointer sample, left
+int ex_sample_expr(), ex_fit_line()
+
+begin
+ # Subsample the expression.
+ npix = ex_sample_expr (ex, exptr, exptr2, sample, optimal_sample_size,
+ len_stdline)
+ center_pixel = max (1, (npix + 1) / 2)
+
+ # Sort the sample, compute the minimum, maximum, and median pixel
+ # values.
+
+ call asrtr (Memr[sample], Memr[sample], npix)
+ zmin = Memr[sample]
+ zmax = Memr[sample+npix-1]
+
+ # The median value is the average of the two central values if there
+ # are an even number of pixels in the sample.
+
+ left = sample + center_pixel - 1
+ if (mod (npix, 2) == 1 || center_pixel >= npix)
+ median = Memr[left]
+ else
+ median = (Memr[left] + Memr[left+1]) / 2
+
+ # Fit a line to the sorted sample vector. If more than half of the
+ # pixels in the sample are rejected give up and return the full range.
+ # If the user-supplied contrast factor is not 1.0 adjust the scale
+ # accordingly and compute Z1 and Z2, the y intercepts at indices 1 and
+ # npix.
+
+ minpix = max (MIN_NPIXELS, int (npix * MAX_REJECT))
+ ngrow = max (1, nint (npix * .01))
+ ngoodpix = ex_fit_line (Memr[sample], npix, zstart, zslope,
+ KREJ, ngrow, MAX_ITERATIONS)
+
+ if (ngoodpix < minpix) {
+ z1 = zmin
+ z2 = zmax
+ } else {
+ if (contrast > 0)
+ zslope = zslope / contrast
+ z1 = max (zmin, median - (center_pixel - 1) * zslope)
+ z2 = min (zmax, median + (npix - center_pixel) * zslope)
+ }
+
+ call mfree (sample, TY_REAL)
+end
+
+
+# EX_SAMPLE_EXPR -- Extract an evenly gridded subsample of the pixels from
+# a possibly two-dimensional expression into a one-dimensional vector.
+
+int procedure ex_sample_expr (ex, exptr, exptr2, sample, optimal_sample_size,
+ len_stdline)
+
+pointer ex # task struct pointer
+pointer exptr # expression struct pointer
+pointer exptr2 # expression struct pointer (mask)
+pointer sample # output vector containing the sample
+int optimal_sample_size # desired number of pixels in sample
+int len_stdline # optimal number of pixels per line
+
+pointer op, ep, out, bpm
+int ncols, nlines, col_step, line_step, maxpix, line
+int opt_npix_per_line, npix_per_line, nsubsample
+int opt_nlines_in_sample, min_nlines_in_sample, max_nlines_in_sample
+
+pointer ex_evaluate()
+
+begin
+ ncols = OB_WIDTH(exptr)
+ nlines = OB_HEIGHT(exptr)
+
+ # Compute the number of pixels each line will contribute to the sample,
+ # and the subsampling step size for a line. The sampling grid must
+ # span the whole line on a uniform grid.
+
+ opt_npix_per_line = max (1, min (ncols, len_stdline))
+ col_step = max (1, (ncols + opt_npix_per_line-1) / opt_npix_per_line)
+ npix_per_line = max (1, (ncols + col_step-1) / col_step)
+
+ # Compute the number of lines to sample and the spacing between lines.
+ # We must ensure that the image is adequately sampled despite its
+ # size, hence there is a lower limit on the number of lines in the
+ # sample. We also want to minimize the number of lines accessed when
+ # accessing a large image, because each disk seek and read is expensive.
+ # The number of lines extracted will be roughly the sample size divided
+ # by len_stdline, possibly more if the lines are very short.
+
+ min_nlines_in_sample = max (1, optimal_sample_size / len_stdline)
+ opt_nlines_in_sample = max(min_nlines_in_sample, min(nlines,
+ (optimal_sample_size + npix_per_line-1) / npix_per_line))
+ line_step = max (1, nlines / (opt_nlines_in_sample))
+ max_nlines_in_sample = (nlines + line_step-1) / line_step
+
+ # Allocate space for the output vector. Buffer must be freed by our
+ # caller.
+
+ maxpix = npix_per_line * max_nlines_in_sample
+ call malloc (sample, maxpix, TY_REAL)
+
+ # Extract the vector.
+ op = sample
+ call malloc (out, ncols, TY_REAL)
+ if (exptr2 != NULL)
+ call malloc (bpm, ncols, TY_INT)
+ do line = (line_step + 1) / 2, nlines, line_step {
+
+ # Evaluate the expression at the current line.
+ call ex_getpix (ex, line)
+ ep = ex_evaluate (ex, Memc[OB_EXPSTR(exptr)])
+ switch (O_TYPE(ep)) {
+ case TY_CHAR:
+ call achtcr (Memc[O_VALP(ep)], Memr[out], O_LEN(ep))
+ case TY_SHORT:
+ call achtsr (Mems[O_VALP(ep)], Memr[out], O_LEN(ep))
+ case TY_INT:
+ call achtir (Memi[O_VALP(ep)], Memr[out], O_LEN(ep))
+ case TY_LONG:
+ call achtlr (Meml[O_VALP(ep)], Memr[out], O_LEN(ep))
+ case TY_REAL:
+ call amovr (Memr[O_VALP(ep)], Memr[out], O_LEN(ep))
+ case TY_DOUBLE:
+ call achtdr (Memd[O_VALP(ep)], Memr[out], O_LEN(ep))
+ default:
+ call error (0, "Unknown expression type in zscale/zscalem().")
+ }
+ call evvfree (ep)
+ if (exptr2 != NULL) {
+ ep = ex_evaluate (ex, Memc[OB_EXPSTR(exptr2)])
+ switch (O_TYPE(ep)) {
+ case TY_BOOL:
+ call amovi (Memi[O_VALP(ep)], Memi[bpm], O_LEN(ep))
+ default:
+ call error (0,
+ "Selection expression must be boolean in zscalem().")
+ }
+ call ex_subsample1 (Memr[out], Memi[bpm], Memr[op], O_LEN(ep),
+ npix_per_line, col_step, nsubsample)
+ call evvfree (ep)
+ } else
+ call ex_subsample (Memr[out], Memr[op], O_LEN(ep),
+ npix_per_line, col_step, nsubsample)
+
+ op = op + nsubsample
+ if (op - sample + npix_per_line > maxpix)
+ break
+ }
+ call mfree (out, TY_REAL)
+
+ return (op - sample)
+end
+
+
+# EX_SUBSAMPLE -- Subsample an image line. Extract the first pixel and
+# every "step"th pixel thereafter for a total of npix pixels.
+
+procedure ex_subsample (a, b, n, npix, step, nsubsample)
+
+real a[n]
+real b[npix]
+int n
+int npix, step, nsubsample
+int ip, i
+
+begin
+ nsubsample = npix
+ if (step <= 1)
+ call amovr (a, b, npix)
+ else {
+ ip = 1
+ do i = 1, npix {
+ b[i] = a[ip]
+ ip = ip + step
+ }
+ }
+end
+
+
+# EX_SUBSAMPLE1 -- Subsample an image line. Extract the first pixel and
+# every "step"th pixel thereafter for a total of npix pixels.
+#
+# Check for mask values and exclude them from the sample. In case a
+# subsampled line has fewer than 75% good pixels then increment the starting
+# pixel and step through again. Return the number of good pixels.
+
+procedure ex_subsample1 (a, c, b, n, npix, step, nsubsample)
+
+real a[ARB]
+int c[ARB]
+real b[npix]
+int n
+int npix, step, nsubsample
+int i, j
+
+begin
+ nsubsample = 0
+ if (step <= 1) {
+ do i = 1, n {
+ if (c[i] == 0)
+ next
+ nsubsample = nsubsample + 1
+ b[nsubsample] = a[i]
+ if (nsubsample == npix)
+ break
+ }
+ } else {
+ do j = 1, step-1 {
+ do i = j, n, step {
+ if (c[i] == 0)
+ next
+ nsubsample = nsubsample + 1
+ b[nsubsample] = a[i]
+ if (nsubsample == npix)
+ break
+ }
+ if (nsubsample >= 0.75 * npix)
+ break
+ }
+ }
+end
+
+
+# EX_FIT_LINE -- Fit a straight line to a data array of type real. This is
+# an iterative fitting algorithm, wherein points further than ksigma from the
+# current fit are excluded from the next fit. Convergence occurs when the
+# next iteration does not decrease the number of pixels in the fit, or when
+# there are no pixels left. The number of pixels left after pixel rejection
+# is returned as the function value.
+
+int procedure ex_fit_line (data, npix, zstart, zslope, krej, ngrow, maxiter)
+
+real data[npix] #i data to be fitted
+int npix #i number of pixels before rejection
+real zstart #o Z-value of pixel data[1]
+real zslope #o dz/pixel
+real krej #i k-sigma pixel rejection factor
+int ngrow #i number of pixels of growing
+int maxiter #i max iterations
+
+int i, ngoodpix, last_ngoodpix, minpix, niter
+real xscale, z0, dz, x, z, mean, sigma, threshold
+double sumxsqr, sumxz, sumz, sumx, rowrat
+pointer sp, flat, badpix, normx
+int ex_reject_pixels(), ex_compute_sigma()
+
+begin
+ if (npix <= 0)
+ return (0)
+ else if (npix == 1) {
+ zstart = data[1]
+ zslope = 0.0
+ return (1)
+ } else
+ xscale = 2.0 / (npix - 1)
+
+ # Allocate a buffer for data minus fitted curve, another for the
+ # normalized X values, and another to flag rejected pixels.
+
+ call smark (sp)
+ call salloc (flat, npix, TY_REAL)
+ call salloc (normx, npix, TY_REAL)
+ call salloc (badpix, npix, TY_SHORT)
+ call aclrs (Mems[badpix], npix)
+
+ # Compute normalized X vector. The data X values [1:npix] are
+ # normalized to the range [-1:1]. This diagonalizes the lsq matrix
+ # and reduces its condition number.
+
+ do i = 0, npix - 1
+ Memr[normx+i] = i * xscale - 1.0
+
+ # Fit a line with no pixel rejection. Accumulate the elements of the
+ # matrix and data vector. The matrix M is diagonal with
+ # M[1,1] = sum x**2 and M[2,2] = ngoodpix. The data vector is
+ # DV[1] = sum (data[i] * x[i]) and DV[2] = sum (data[i]).
+
+ sumxsqr = 0
+ sumxz = 0
+ sumx = 0
+ sumz = 0
+
+ do i = 1, npix {
+ x = Memr[normx+i-1]
+ z = data[i]
+ sumxsqr = sumxsqr + (x ** 2)
+ sumxz = sumxz + z * x
+ sumz = sumz + z
+ }
+
+ # Solve for the coefficients of the fitted line.
+ z0 = sumz / npix
+ dz = sumxz / sumxsqr
+
+ # Iterate, fitting a new line in each iteration. Compute the flattened
+ # data vector and the sigma of the flat vector. Compute the lower and
+ # upper k-sigma pixel rejection thresholds. Run down the flat array
+ # and detect pixels to be rejected from the fit. Reject pixels from
+ # the fit by subtracting their contributions from the matrix sums and
+ # marking the pixel as rejected.
+
+ ngoodpix = npix
+ minpix = max (MIN_NPIXELS, int (npix * MAX_REJECT))
+
+ for (niter=1; niter <= maxiter; niter=niter+1) {
+ last_ngoodpix = ngoodpix
+
+ # Subtract the fitted line from the data array.
+ call ex_flatten_data (data, Memr[flat], Memr[normx], npix, z0, dz)
+
+ # Compute the k-sigma rejection threshold. In principle this
+ # could be more efficiently computed using the matrix sums
+ # accumulated when the line was fitted, but there are problems with
+ # numerical stability with that approach.
+
+ ngoodpix = ex_compute_sigma (Memr[flat], Mems[badpix], npix,
+ mean, sigma)
+ threshold = sigma * krej
+
+ # Detect and reject pixels further than ksigma from the fitted
+ # line.
+ ngoodpix = ex_reject_pixels (data, Memr[flat], Memr[normx],
+ Mems[badpix], npix, sumxsqr, sumxz, sumx, sumz, threshold,
+ ngrow)
+
+ # Solve for the coefficients of the fitted line. Note that after
+ # pixel rejection the sum of the X values need no longer be zero.
+
+ if (ngoodpix > 0) {
+ rowrat = sumx / sumxsqr
+ z0 = (sumz - rowrat * sumxz) / (ngoodpix - rowrat * sumx)
+ dz = (sumxz - z0 * sumx) / sumxsqr
+ }
+
+ if (ngoodpix >= last_ngoodpix || ngoodpix < minpix)
+ break
+ }
+
+ # Transform the line coefficients back to the X range [1:npix].
+ zstart = z0 - dz
+ zslope = dz * xscale
+
+ call sfree (sp)
+ return (ngoodpix)
+end
+
+
+# EX_FLATTEN_DATA -- Compute and subtract the fitted line from the data array,
+# returned the flattened data in FLAT.
+
+procedure ex_flatten_data (data, flat, x, npix, z0, dz)
+
+real data[npix] # raw data array
+real flat[npix] # flattened data (output)
+real x[npix] # x value of each pixel
+int npix # number of pixels
+real z0, dz # z-intercept, dz/dx of fitted line
+int i
+
+begin
+ do i = 1, npix
+ flat[i] = data[i] - (x[i] * dz + z0)
+end
+
+
+# EX_COMPUTE_SIGMA -- Compute the root mean square deviation from the
+# mean of a flattened array. Ignore rejected pixels.
+
+int procedure ex_compute_sigma (a, badpix, npix, mean, sigma)
+
+real a[npix] # flattened data array
+short badpix[npix] # bad pixel flags (!= 0 if bad pixel)
+int npix
+real mean, sigma # (output)
+
+real pixval
+int i, ngoodpix
+double sum, sumsq, temp
+
+begin
+ sum = 0
+ sumsq = 0
+ ngoodpix = 0
+
+ # Accumulate sum and sum of squares.
+ do i = 1, npix
+ if (badpix[i] == GOOD_PIXEL) {
+ pixval = a[i]
+ ngoodpix = ngoodpix + 1
+ sum = sum + pixval
+ sumsq = sumsq + pixval ** 2
+ }
+
+ # Compute mean and sigma.
+ switch (ngoodpix) {
+ case 0:
+ mean = INDEF
+ sigma = INDEF
+ case 1:
+ mean = sum
+ sigma = INDEF
+ default:
+ mean = sum / ngoodpix
+ temp = sumsq / (ngoodpix - 1) - sum**2 / (ngoodpix * (ngoodpix - 1))
+ if (temp < 0) # possible with roundoff error
+ sigma = 0.0
+ else
+ sigma = sqrt (temp)
+ }
+
+ return (ngoodpix)
+end
+
+
+# EX_REJECT_PIXELS -- Detect and reject pixels more than "threshold" greyscale
+# units from the fitted line. The residuals about the fitted line are given
+# by the "flat" array, while the raw data is in "data". Each time a pixel
+# is rejected subtract its contributions from the matrix sums and flag the
+# pixel as rejected. When a pixel is rejected reject its neighbors out to
+# a specified radius as well. This speeds up convergence considerably and
+# produces a more stringent rejection criteria which takes advantage of the
+# fact that bad pixels tend to be clumped. The number of pixels left in the
+# fit is returned as the function value.
+
+int procedure ex_reject_pixels (data, flat, normx, badpix, npix,
+ sumxsqr, sumxz, sumx, sumz, threshold, ngrow)
+
+real data[npix] # raw data array
+real flat[npix] # flattened data array
+real normx[npix] # normalized x values of pixels
+short badpix[npix] # bad pixel flags (!= 0 if bad pixel)
+int npix
+double sumxsqr,sumxz,sumx,sumz # matrix sums
+real threshold # threshold for pixel rejection
+int ngrow # number of pixels of growing
+
+int ngoodpix, i, j
+real residual, lcut, hcut
+double x, z
+
+begin
+ ngoodpix = npix
+ lcut = -threshold
+ hcut = threshold
+
+ do i = 1, npix
+ if (badpix[i] == BAD_PIXEL)
+ ngoodpix = ngoodpix - 1
+ else {
+ residual = flat[i]
+ if (residual < lcut || residual > hcut) {
+ # Reject the pixel and its neighbors out to the growing
+ # radius. We must be careful how we do this to avoid
+ # directional effects. Do not turn off thresholding on
+ # pixels in the forward direction; mark them for rejection
+ # but do not reject until they have been thresholded.
+ # If this is not done growing will not be symmetric.
+
+ do j = max(1,i-ngrow), min(npix,i+ngrow) {
+ if (badpix[j] != BAD_PIXEL) {
+ if (j <= i) {
+ x = normx[j]
+ z = data[j]
+ sumxsqr = sumxsqr - (x ** 2)
+ sumxz = sumxz - z * x
+ sumx = sumx - x
+ sumz = sumz - z
+ badpix[j] = BAD_PIXEL
+ ngoodpix = ngoodpix - 1
+ } else
+ badpix[j] = REJECT_PIXEL
+ }
+ }
+ }
+ }
+
+ return (ngoodpix)
+end
diff --git a/pkg/dataio/export/generic/exobands.x b/pkg/dataio/export/generic/exobands.x
new file mode 100644
index 00000000..d8a7d636
--- /dev/null
+++ b/pkg/dataio/export/generic/exobands.x
@@ -0,0 +1,489 @@
+include <error.h>
+include <mach.h>
+include <evvexpr.h>
+include <fset.h>
+include <ctype.h>
+include "../export.h"
+include "../exfcn.h"
+
+define DEBUG false
+define VDEBUG false
+
+
+# EX_EVALUATE -- Evaluate the outbands expression.
+
+pointer procedure ex_evaluate (ex, expr)
+
+pointer ex #i task struct pointer
+char expr[ARB] #i expression to be evaluated
+
+pointer o # operand pointer to result
+
+int locpr()
+pointer evvexpr()
+extern ex_getop(), ex_obfcn()
+errchk evvexpr
+
+begin
+ if (DEBUG) { call eprintf("ex_eval: expr='%s'\n") ; call pargstr(expr) }
+
+ # Evaluate the expression.
+ iferr {
+ o = evvexpr (expr, locpr(ex_getop), ex, locpr(ex_obfcn), ex,
+ EV_RNGCHK)
+ } then
+ call erract (EA_FATAL)
+
+ return (o)
+end
+
+
+# EX_GETOP -- Called by evvexpr to get an operand.
+
+procedure ex_getop (ex, opname, o)
+
+pointer ex #i task struct pointer
+char opname[ARB] #i operand name to retrieve
+pointer o #o output operand pointer
+
+int i, nops, found, optype, imnum
+pointer sp, buf
+pointer op, param, emsg
+pointer im
+
+#int ex_ptype()
+int imgeti(), imgftype(), btoi(), ctoi()
+bool streq(), imgetb()
+double imgetd()
+
+define getpar_ 99
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+ call salloc (param, SZ_FNAME, TY_CHAR)
+ call salloc (emsg, SZ_LINE, TY_CHAR)
+ call aclrc (Memc[buf], SZ_LINE)
+ call aclrc (Memc[param], SZ_FNAME)
+ call aclrc (Memc[emsg], SZ_LINE)
+
+ if (VDEBUG) { call eprintf ("getop: opname=%s ");call pargstr(opname)}
+
+ # First see if it's one of the special image operands that was
+ # referenced in an "@param" call.
+
+ if (((opname[1] != 'i' && opname[1] != 'b') && !IS_DIGIT(opname[2])) ||
+ (opname[1] == 'i' && opname[2] == '_')) {
+ call strcpy (opname, Memc[param], SZ_FNAME)
+ im = IO_IMPTR(IMOP(ex,1))
+getpar_ O_LEN(o) = 0
+ switch (imgftype (im, Memc[param])) {
+ case TY_BOOL:
+ O_TYPE(o) = TY_BOOL
+ O_VALI(o) = btoi (imgetb (im, Memc[param]))
+ case TY_CHAR:
+ O_TYPE(o) = TY_CHAR
+ O_LEN(o) = SZ_LINE
+ call malloc (O_VALP(o), SZ_LINE, TY_CHAR)
+ call imgstr (im, Memc[param], O_VALC(o), SZ_LINE)
+ case TY_INT:
+ O_TYPE(o) = TY_INT
+ O_VALI(o) = imgeti (im, Memc[param])
+ case TY_REAL:
+ O_TYPE(o) = TY_DOUBLE
+ O_VALD(o) = imgetd (im, Memc[param])
+ default:
+ call sprintf (Memc[emsg], SZ_LINE, "param %s not found\n")
+ call pargstr (Memc[param])
+ call error (6, Memc[emsg])
+ }
+
+ call sfree (sp)
+ return
+
+ } else if (IS_LOWER(opname[1]) && opname[3] == '.') {
+ # This is a tag.param operand. Break out the image tag name and
+ # get the image pointer for it, then get the parameter
+ if (opname[1] == 'b') { # band of 3-D image, only 1 ptr
+ imnum = 1
+ } else if (opname[1] == 'i') { # image descriptor
+ i = 2
+ if (ctoi (opname, i, imnum) == 0)
+ call error (6, "can't parse operand")
+ } else {
+ call sprintf (Memc[buf], SZ_LINE,
+ "Unknown outbands operand `%s'\n")
+ call pargstr(opname)
+ call error (1, Memc[buf])
+ }
+
+ # Get the parameter value.
+ im = IO_IMPTR(IMOP(ex,imnum))
+ call strcpy (opname[4], Memc[param], SZ_FNAME)
+ goto getpar_
+ }
+
+ nops = EX_NIMOPS(ex)
+ found = NO
+ do i = 1, nops {
+ # Search for operand name which matches requested value.
+ op = IMOP(ex,i)
+ if (streq (Memc[IO_TAG(op)],opname)) {
+ found = YES
+ break
+ }
+ }
+
+ if (VDEBUG && found == YES) {
+ call eprintf (" tag=%s found=%d ")
+ call pargstr(Memc[IO_TAG(op)]) ; call pargi(found)
+ call zze_prop (op)
+ }
+
+ if (found == YES) {
+ # Copy operand descriptor to 'o'
+ #optype = ex_ptype (IO_TYPE(op), IO_NBYTES(op))
+ optype = IO_TYPE(op)
+ switch (optype) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ O_LEN(o) = IO_NPIX(op)
+ O_TYPE(o) = TY_SHORT
+ call malloc (O_VALP(o), IO_NPIX(op), TY_SHORT)
+ call amovs (Mems[IO_DATA(op)], Mems[O_VALP(o)], IO_NPIX(op))
+
+ case TY_INT:
+ O_LEN(o) = IO_NPIX(op)
+ O_TYPE(o) = TY_INT
+ call malloc (O_VALP(o), IO_NPIX(op), TY_INT)
+ call amovi (Memi[IO_DATA(op)], Memi[O_VALP(o)], IO_NPIX(op))
+
+ case TY_LONG:
+ O_LEN(o) = IO_NPIX(op)
+ O_TYPE(o) = TY_LONG
+ call malloc (O_VALP(o), IO_NPIX(op), TY_LONG)
+ call amovl (Meml[IO_DATA(op)], Meml[O_VALP(o)], IO_NPIX(op))
+
+ case TY_REAL:
+ O_LEN(o) = IO_NPIX(op)
+ O_TYPE(o) = TY_REAL
+ call malloc (O_VALP(o), IO_NPIX(op), TY_REAL)
+ call amovr (Memr[IO_DATA(op)], Memr[O_VALP(o)], IO_NPIX(op))
+
+ case TY_DOUBLE:
+ O_LEN(o) = IO_NPIX(op)
+ O_TYPE(o) = TY_DOUBLE
+ call malloc (O_VALP(o), IO_NPIX(op), TY_DOUBLE)
+ call amovd (Memd[IO_DATA(op)], Memd[O_VALP(o)], IO_NPIX(op))
+
+ }
+
+ } else {
+ call sprintf (Memc[buf], SZ_LINE, "Unknown outbands operand `%s'\n")
+ call pargstr(opname)
+ call error (1, Memc[buf])
+ }
+
+ call sfree (sp)
+end
+
+
+# EX_OBFCN -- Called by evvexpr to execute import outbands special functions.
+
+procedure ex_obfcn (ex, fcn, args, nargs, o)
+
+pointer ex #i package pointer
+char fcn[ARB] #i function to be executed
+pointer args[ARB] #i argument list
+int nargs #i number of arguments
+pointer o #o operand pointer
+
+pointer sp, buf
+pointer r, g, b, gray
+pointer scaled, data
+int i, len, v_nargs, func, nbins
+short sz1, sz2, sb1, sb2, zero
+real gamma, bscale, bzero, scale, pix
+real z1, z2
+
+int strdic()
+bool fp_equalr(), strne()
+
+define setop_ 99
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_FNAME, TY_CHAR)
+
+ # Lookup function in dictionary.
+ func = strdic (fcn, Memc[buf], SZ_LINE, OB_FUNCTIONS)
+ if (func > 0 && strne(fcn,Memc[buf]))
+ func = 0
+
+ # Abort if the function is not known.
+ if (func <= 0)
+ call xev_error1 ("unknown function `%s' called", fcn)
+
+ # Verify the correct number of arguments, negative value means a
+ # variable number of args, handle it in the evaluation.
+ switch (func) {
+ case GRAY, GREY:
+ v_nargs = 3
+ case ZSCALE:
+ v_nargs = -1
+ case BSCALE:
+ v_nargs = 3
+ case GAMMA:
+ v_nargs = -1
+ case BLOCK:
+ v_nargs = 3
+ }
+ if (v_nargs > 0 && nargs != v_nargs)
+ call xev_error2 ("function `%s' requires %d arguments",
+ fcn, v_nargs)
+ else if (v_nargs < 0 && nargs < abs(v_nargs))
+ call xev_error2 ("function `%s' requires at least %d arguments",
+ fcn, abs(v_nargs))
+
+ if (DEBUG) {
+ call eprintf ("obfcn: nargs=%d func=%d\n")
+ call pargi (nargs) ; call pargi (func)
+ do i = 1, nargs { call eprintf ("\t") ; call zze_pevop (args[i]) }
+ call flush (STDERR)
+ }
+
+ # Evaluate the function.
+ zero = 0
+ switch (func) {
+ case GRAY, GREY:
+ # evaluate expression for NTSC grayscale.
+ r = O_VALP(args[1])
+ g = O_VALP(args[2])
+ b = O_VALP(args[3])
+ len = O_LEN(args[1]) - 1
+ O_LEN(o) = len + 1
+ O_TYPE(o) = TY_REAL
+ call malloc (O_VALP(o), len+1, TY_REAL)
+ gray = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ do i = 0, len {
+ Memr[gray+i] = R_COEFF * Mems[r+i] +
+ G_COEFF * Mems[g+i] +
+ B_COEFF * Mems[b+i]
+ }
+
+ case TY_INT:
+ do i = 0, len {
+ Memr[gray+i] = R_COEFF * Memi[r+i] +
+ G_COEFF * Memi[g+i] +
+ B_COEFF * Memi[b+i]
+ }
+
+ case TY_LONG:
+ do i = 0, len {
+ Memr[gray+i] = R_COEFF * Meml[r+i] +
+ G_COEFF * Meml[g+i] +
+ B_COEFF * Meml[b+i]
+ }
+
+ case TY_REAL:
+ do i = 0, len {
+ Memr[gray+i] = R_COEFF * Memr[r+i] +
+ G_COEFF * Memr[g+i] +
+ B_COEFF * Memr[b+i]
+ }
+
+ case TY_DOUBLE:
+ do i = 0, len {
+ Memr[gray+i] = R_COEFF * Memd[r+i] +
+ G_COEFF * Memd[g+i] +
+ B_COEFF * Memd[b+i]
+ }
+
+ }
+
+ case ZSCALE:
+ data = O_VALP(args[1])
+ switch (O_TYPE(args[2])) {
+ case TY_SHORT: z1 = O_VALS(args[2])
+ case TY_INT: z1 = O_VALI(args[2])
+ case TY_LONG: z1 = O_VALL(args[2])
+ case TY_REAL: z1 = O_VALR(args[2])
+ case TY_DOUBLE: z1 = O_VALD(args[2])
+ }
+ switch (O_TYPE(args[3])) {
+ case TY_SHORT: z2 = O_VALS(args[3])
+ case TY_INT: z2 = O_VALI(args[3])
+ case TY_LONG: z2 = O_VALL(args[3])
+ case TY_REAL: z2 = O_VALR(args[3])
+ case TY_DOUBLE: z2 = O_VALD(args[3])
+ }
+ if (nargs < 4)
+ nbins = 256
+ else
+ nbins = O_VALI(args[4])
+ len = O_LEN(args[1])
+ O_LEN(o) = len
+ O_TYPE(o) = O_TYPE(args[1])
+ call malloc (O_VALP(o), len, O_TYPE(args[1]))
+ scaled = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ sz1 = z1
+ sz2 = z2
+ sb1 = 0
+ sb2 = nbins - 1
+ if (abs(sz2-sz1) > 1.0e-5)
+ call amaps (Mems[data], Mems[scaled], len, sz1, sz2,
+ sb1, sb2)
+ else
+ call amovks (0, Mems[scaled], len)
+
+ case TY_INT:
+ if (abs(z2-z1) > 1.0e-5)
+ call amapi (Memi[data], Memi[scaled], len, int (z1),
+ int(z2), int (0), int (nbins-1))
+ else
+ call amovki (int (0), Memi[scaled], len)
+
+ case TY_LONG:
+ if (abs(z2-z1) > 1.0e-5)
+ call amapl (Meml[data], Meml[scaled], len, long (z1),
+ long(z2), long (0), long (nbins-1))
+ else
+ call amovkl (long (0), Meml[scaled], len)
+
+ case TY_REAL:
+ if (abs(z2-z1) > 1.0e-5)
+ call amapr (Memr[data], Memr[scaled], len, real (z1),
+ real(z2), real (0), real (nbins-1))
+ else
+ call amovkr (real (0), Memr[scaled], len)
+
+ case TY_DOUBLE:
+ if (abs(z2-z1) > 1.0e-5)
+ call amapd (Memd[data], Memd[scaled], len, double (z1),
+ double(z2), double (0), double (nbins-1))
+ else
+ call amovkd (double (0), Memd[scaled], len)
+
+ }
+
+ case BSCALE:
+ data = O_VALP(args[1])
+ bzero = O_VALR(args[2])
+ bscale = O_VALR(args[3])
+ len = O_LEN(args[1]) - 1
+ O_LEN(o) = len + 1
+ O_TYPE(o) = TY_REAL
+ call malloc (O_VALP(o), len+1, TY_REAL)
+ scaled = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ if (!fp_equalr (0.0, bscale)) {
+ do i = 0, len
+ Memr[scaled+i] = (Mems[data+i] - bzero) / bscale
+ } else
+ call amovks (zero, Mems[scaled], len)
+
+ case TY_INT:
+ if (!fp_equalr (0.0, bscale)) {
+ do i = 0, len
+ Memr[scaled+i] = (Memi[data+i] - bzero) / bscale
+ } else
+ call amovki (int(0), Memi[scaled], len)
+
+ case TY_LONG:
+ if (!fp_equalr (0.0, bscale)) {
+ do i = 0, len
+ Memr[scaled+i] = (Meml[data+i] - bzero) / bscale
+ } else
+ call amovkl (long(0), Meml[scaled], len)
+
+ case TY_REAL:
+ if (!fp_equalr (0.0, bscale)) {
+ do i = 0, len
+ Memr[scaled+i] = (Memr[data+i] - bzero) / bscale
+ } else
+ call amovkr (real(0), Memr[scaled], len)
+
+ case TY_DOUBLE:
+ if (!fp_equalr (0.0, bscale)) {
+ do i = 0, len
+ Memr[scaled+i] = (Memd[data+i] - bzero) / bscale
+ } else
+ call amovkd (double(0), Memd[scaled], len)
+
+ }
+
+ case GAMMA:
+ data = O_VALP(args[1])
+ gamma = 1.0 / O_VALR(args[2])
+ if (nargs == 3)
+ scale = max (1.0, O_VALR(args[3]))
+ else
+ scale = 255.0
+ len = O_LEN(args[1]) - 1
+ O_LEN(o) = len + 1
+ O_TYPE(o) = TY_REAL
+ call malloc (O_VALP(o), len+1, TY_REAL)
+ scaled = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ do i = 0, len {
+ pix = max (zero, Mems[data+i])
+ Memr[scaled+i] = scale * ((pix/scale) ** gamma)
+ }
+
+ case TY_INT:
+ do i = 0, len {
+ pix = max (int(0), Memi[data+i])
+ Memr[scaled+i] = scale * ((pix/scale) ** gamma)
+ }
+
+ case TY_LONG:
+ do i = 0, len {
+ pix = max (long(0), Meml[data+i])
+ Memr[scaled+i] = scale * ((pix/scale) ** gamma)
+ }
+
+ case TY_REAL:
+ do i = 0, len {
+ pix = max (real(0), Memr[data+i])
+ Memr[scaled+i] = scale * ((pix/scale) ** gamma)
+ }
+
+ case TY_DOUBLE:
+ do i = 0, len {
+ pix = max (double(0), Memd[data+i])
+ Memr[scaled+i] = scale * ((pix/scale) ** gamma)
+ }
+
+ }
+
+ case BLOCK:
+ len = O_VALI(args[2])
+ O_LEN(o) = len
+ O_TYPE(o) = O_TYPE(args[1])
+ call malloc (O_VALP(o), len, O_TYPE(args[1]))
+ scaled = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ call amovks (O_VALS(args[1]), Mems[scaled], len)
+ case TY_INT:
+ call amovki (O_VALI(args[1]), Memi[scaled], len)
+ case TY_LONG:
+ call amovkl (O_VALL(args[1]), Meml[scaled], len)
+ case TY_REAL:
+ call amovkr (O_VALR(args[1]), Memr[scaled], len)
+ case TY_DOUBLE:
+ call amovkd (O_VALD(args[1]), Memd[scaled], len)
+ }
+
+
+ }
+
+ if (DEBUG) { call zze_pevop (o) }
+
+ call sfree (sp)
+end
diff --git a/pkg/dataio/export/generic/exraster.x b/pkg/dataio/export/generic/exraster.x
new file mode 100644
index 00000000..9838894f
--- /dev/null
+++ b/pkg/dataio/export/generic/exraster.x
@@ -0,0 +1,709 @@
+include <imhdr.h>
+include <mach.h>
+include <evvexpr.h>
+include "../export.h"
+
+define DEBUG false
+
+
+# EX_NO_INTERLEAVE - Write out the image with no interleaving.
+
+procedure ex_no_interleave (ex)
+
+pointer ex #i task struct pointer
+
+pointer op, out
+int i, j, k, line, percent, orow
+int fd, outtype
+
+pointer ex_evaluate(), ex_chtype()
+
+begin
+ if (DEBUG) { call eprintf ("ex_no_interleave:\n")
+ call eprintf ("NEXPR = %d OCOLS = %d OROWS = %d\n")
+ call pargi(EX_NEXPR(ex));call pargi(EX_OCOLS(ex))
+ call pargi(EX_OROWS(ex))
+ }
+
+ # Loop over the number of image expressions.
+ fd = EX_FD(ex)
+ outtype = EX_OUTTYPE(ex)
+ percent = 0
+ orow = 0
+ do i = 1, EX_NEXPR(ex) {
+
+ # Process each line in the image.
+ do j = 1, O_HEIGHT(ex,i) {
+
+ # See if we're flipping the image.
+ if (bitset (EX_OUTFLAGS(ex), OF_FLIPY))
+ #line = EX_NLINES(ex) - j + 1
+ line = O_HEIGHT(ex,i) - j + 1
+ else
+ line = j
+
+ # Get pixels from image(s).
+ call ex_getpix (ex, line)
+
+ # Evaluate expression.
+ op = ex_evaluate (ex, O_EXPR(ex,i))
+
+ # Convert to the output pixel type.
+ out = ex_chtype (ex, op, outtype)
+
+ # Write evaluated pixels.
+ if (EX_FORMAT(ex) != FMT_LIST)
+ call ex_wpixels (fd, outtype, out, O_LEN(op))
+ else {
+ call ex_listpix (fd, outtype, out, O_LEN(op), j, i,
+ EX_NEXPR(ex), NO)
+ }
+
+ # Clean up the pointers.
+ if (outtype == TY_UBYTE || outtype == TY_CHAR)
+ call mfree (out, TY_CHAR)
+ else
+ call mfree (out, outtype)
+ call evvfree (op)
+ do k = 1, EX_NIMOPS(ex) {
+ op = IMOP(ex,k)
+# if (IO_ISIM(op) == NO)
+ call mfree (IO_DATA(op), IM_PIXTYPE(IO_IMPTR(op)))
+ }
+
+ # Print percent done if being verbose
+ orow = orow + 1
+ #if (EX_VERBOSE(ex) == YES)
+ call ex_pstat (ex, orow, percent)
+ }
+ }
+
+ if (DEBUG) { call zze_prstruct ("Finished processing", ex) }
+end
+
+
+# EX_LN_INTERLEAVE - Write out the image with line interleaving.
+
+procedure ex_ln_interleave (ex)
+
+pointer ex #i task struct pointer
+
+pointer op, out
+int i, j, line, percent, orow
+int fd, outtype
+
+pointer ex_evaluate(), ex_chtype()
+
+begin
+ if (DEBUG) { call eprintf ("ex_ln_interleave:\n")
+ call eprintf ("NEXPR = %d OCOLS = %d OROWS = %d\n")
+ call pargi(EX_NEXPR(ex));call pargi(EX_OCOLS(ex))
+ call pargi(EX_OROWS(ex))
+ }
+
+ # Process each line in the image.
+ fd = EX_FD(ex)
+ outtype = EX_OUTTYPE(ex)
+ percent = 0
+ orow = 0
+ do i = 1, EX_NLINES(ex) {
+
+ # See if we're flipping the image.
+ if (bitset (EX_OUTFLAGS(ex), OF_FLIPY))
+ line = EX_NLINES(ex) - i + 1
+ else
+ line = i
+
+ # Get pixels from image(s).
+ call ex_getpix (ex, line)
+
+ # Loop over the number of image expressions.
+ do j = 1, EX_NEXPR(ex) {
+
+ # Evaluate expression.
+ op = ex_evaluate (ex, O_EXPR(ex,j))
+
+ # Convert to the output pixel type.
+ out = ex_chtype (ex, op, outtype)
+
+ # Write evaluated pixels.
+ if (EX_FORMAT(ex) != FMT_LIST)
+ call ex_wpixels (fd, outtype, out, O_LEN(op))
+ else {
+ call ex_listpix (fd, outtype, out, O_LEN(op), i, j,
+ EX_NEXPR(ex), NO)
+ }
+
+ # Clean up the pointers.
+ if (outtype == TY_UBYTE || outtype == TY_CHAR)
+ call mfree (out, TY_CHAR)
+ else
+ call mfree (out, outtype)
+ call evvfree (op)
+
+ # Print percent done if being verbose
+ orow = orow + 1
+ #if (EX_VERBOSE(ex) == YES)
+ call ex_pstat (ex, orow, percent)
+ }
+
+ do j = 1, EX_NIMOPS(ex) {
+ op = IMOP(ex,j)
+# if (IO_ISIM(op) == NO)
+ call mfree (IO_DATA(op), IM_PIXTYPE(IO_IMPTR(op)))
+ }
+ }
+
+ if (DEBUG) { call zze_prstruct ("Finished processing", ex) }
+end
+
+
+# EX_PX_INTERLEAVE - Write out the image with pixel interleaving.
+
+procedure ex_px_interleave (ex)
+
+pointer ex #i task struct pointer
+
+pointer sp, pp, op
+pointer o, outptr
+int i, j, line, npix, outtype
+long totpix
+int fd, percent, orow
+
+pointer ex_evaluate(), ex_chtype()
+
+begin
+ if (DEBUG) { call eprintf ("ex_px_interleave:\n")
+ call eprintf ("NEXPR = %d OCOLS = %d OROWS = %d\n")
+ call pargi(EX_NEXPR(ex));call pargi(EX_OCOLS(ex))
+ call pargi(EX_OROWS(ex))
+ }
+
+ call smark (sp)
+ call salloc (pp, EX_NEXPR(ex), TY_POINTER)
+
+ # Process each line in the image.
+ fd = EX_FD(ex)
+ outptr = NULL
+ outtype = EX_OUTTYPE(ex)
+ percent = 0
+ orow = 0
+ do i = 1, EX_NLINES(ex) {
+
+ # See if we're flipping the image.
+ if (bitset (EX_OUTFLAGS(ex), OF_FLIPY))
+ line = EX_NLINES(ex) - i + 1
+ else
+ line = i
+
+ # Get pixels from image(s).
+ call ex_getpix (ex, line)
+
+ # Loop over the number of image expressions.
+ totpix = 0
+ do j = 1, EX_NEXPR(ex) {
+
+ # Evaluate expression.
+ op = ex_evaluate (ex, O_EXPR(ex,j))
+
+ # Convert to the output pixel type.
+ o = ex_chtype (ex, op, outtype)
+ Memi[pp+j-1] = o
+
+ npix = O_LEN(op)
+ #npix = EX_OCOLS(op)
+ call evvfree (op)
+ }
+
+ # Merge pixels into a single vector.
+ call ex_merge_pixels (Memi[pp], EX_NEXPR(ex), npix, outtype,
+ outptr, totpix)
+
+ # Write vector of merged pixels.
+ if (outtype == TY_UBYTE)
+ call achtsb (Memc[outptr], Memc[outptr], totpix)
+ if (EX_FORMAT(ex) != FMT_LIST)
+ call ex_wpixels (fd, outtype, outptr, totpix)
+ else {
+ call ex_listpix (fd, outtype, outptr, totpix,
+ i, EX_NEXPR(ex), EX_NEXPR(ex), YES)
+ }
+
+ if (outtype != TY_CHAR && outtype != TY_UBYTE)
+ call mfree (outptr, outtype)
+ else
+ call mfree (outptr, TY_CHAR)
+ do j = 1, EX_NIMOPS(ex) {
+ op = IMOP(ex,j)
+# if (IO_ISIM(op) == NO)
+ call mfree (IO_DATA(op), IM_PIXTYPE(IO_IMPTR(op)))
+ }
+ do j = 1, EX_NEXPR(ex) {
+ if (outtype != TY_CHAR && outtype != TY_UBYTE)
+ call mfree (Memi[pp+j-1], outtype)
+ else
+ call mfree (Memi[pp+j-1], TY_CHAR)
+ }
+
+ # Print percent done if being verbose
+ orow = orow + 1
+ #if (EX_VERBOSE(ex) == YES)
+ call ex_pstat (ex, orow, percent)
+ }
+
+ call sfree (sp)
+
+ if (DEBUG) { call zze_prstruct ("Finished processing", ex) }
+end
+
+
+# EX_GETPIX - Get the pixels from the image and load each operand.
+
+procedure ex_getpix (ex, line)
+
+pointer ex #i task struct pointer
+int line #i current line number
+
+pointer im, op, data
+int nptrs, i, band
+
+pointer imgl3s(), imgl3i(), imgl3l()
+pointer imgl3r(), imgl3d()
+
+begin
+ # Loop over each of the image operands.
+ nptrs = EX_NIMOPS(ex)
+ do i = 1, nptrs {
+ op = IMOP(ex,i)
+ im = IO_IMPTR(op)
+ band = max (1, IO_BAND(op))
+
+ if (line > IM_LEN(im,2)) {
+ call calloc (IO_DATA(op), IM_LEN(im,1), IM_PIXTYPE(im))
+ IO_ISIM(op) = NO
+ IO_NPIX(op) = IM_LEN(im,1)
+ next
+ } else if (IO_DATA(op) == NULL)
+ call malloc (IO_DATA(op), IM_LEN(im,1), IM_PIXTYPE(im))
+
+ switch (IM_PIXTYPE(im)) {
+ case TY_USHORT:
+ data = imgl3s (im, line, band)
+ call amovs (Mems[data], Mems[IO_DATA(op)], IM_LEN(im,1))
+ IO_TYPE(op) = TY_SHORT
+ IO_NBYTES(op) = SZ_SHORT * SZB_CHAR
+ IO_ISIM(op) = YES
+
+ case TY_SHORT:
+ data = imgl3s (im, line, band)
+ call amovs (Mems[data], Mems[IO_DATA(op)], IM_LEN(im,1))
+ IO_TYPE(op) = TY_SHORT
+ IO_NBYTES(op) = SZ_SHORT * SZB_CHAR
+ IO_ISIM(op) = YES
+
+ case TY_INT:
+ data = imgl3i (im, line, band)
+ call amovi (Memi[data], Memi[IO_DATA(op)], IM_LEN(im,1))
+ IO_TYPE(op) = TY_INT
+ IO_NBYTES(op) = SZ_INT32 * SZB_CHAR
+ IO_ISIM(op) = YES
+
+ case TY_LONG:
+ data = imgl3l (im, line, band)
+ call amovl (Meml[data], Meml[IO_DATA(op)], IM_LEN(im,1))
+ IO_TYPE(op) = TY_LONG
+ IO_NBYTES(op) = SZ_LONG * SZB_CHAR
+ IO_ISIM(op) = YES
+
+ case TY_REAL:
+ data = imgl3r (im, line, band)
+ call amovr (Memr[data], Memr[IO_DATA(op)], IM_LEN(im,1))
+ IO_TYPE(op) = TY_REAL
+ IO_NBYTES(op) = SZ_REAL * SZB_CHAR
+ IO_ISIM(op) = YES
+
+ case TY_DOUBLE:
+ data = imgl3d (im, line, band)
+ call amovd (Memd[data], Memd[IO_DATA(op)], IM_LEN(im,1))
+ IO_TYPE(op) = TY_DOUBLE
+ IO_NBYTES(op) = SZ_DOUBLE * SZB_CHAR
+ IO_ISIM(op) = YES
+
+ }
+ IO_NPIX(op) = IM_LEN(im,1)
+ }
+end
+
+
+# EX_WPIXELS - Write the pixels to the current file.
+
+procedure ex_wpixels (fd, otype, pix, npix)
+
+int fd #i output file descriptor
+int otype #i output data type
+pointer pix #i pointer to pixel data
+int npix #i number of pixels to write
+
+begin
+ # Write binary output.
+ switch (otype) {
+ case TY_UBYTE:
+ call write (fd, Mems[pix], npix / SZB_CHAR)
+ case TY_USHORT:
+ call write (fd, Mems[pix], npix * SZ_SHORT/SZ_CHAR)
+
+ case TY_SHORT:
+ call write (fd, Mems[pix], npix * SZ_SHORT/SZ_CHAR)
+
+ case TY_INT:
+ if (SZ_INT != SZ_INT32)
+ call ipak32 (Memi[pix], Memi[pix], npix)
+ call write (fd, Memi[pix], npix * SZ_INT32/SZ_CHAR)
+
+ case TY_LONG:
+ call write (fd, Meml[pix], npix * SZ_LONG/SZ_CHAR)
+
+ case TY_REAL:
+ call write (fd, Memr[pix], npix * SZ_REAL/SZ_CHAR)
+
+ case TY_DOUBLE:
+ call write (fd, Memd[pix], npix * SZ_DOUBLE/SZ_CHAR)
+
+ }
+end
+
+
+# EX_LISTPIX - Write the pixels to the current file as ASCII text.
+
+procedure ex_listpix (fd, type, data, npix, line, band, nbands, merged)
+
+int fd #i output file descriptor
+int type #i output data type
+pointer data #i pointer to pixel data
+int npix #i number of pixels to write
+int line #i current output line number
+int band #i current output band number
+int nbands #i no. of output bands
+int merged #i are pixels interleaved?
+
+int i, j, k
+int val, pix, shifti(), andi()
+
+begin
+ if (merged == YES && nbands > 1) {
+ do i = 1, npix {
+ k = 0
+ do j = 1, nbands {
+ call fprintf (fd, "%4d %4d %4d ")
+ call pargi (i)
+ call pargi (line)
+ call pargi (j)
+
+ switch (type) {
+ case TY_UBYTE:
+ val = Memc[data+k]
+ if (mod(i,2) == 1) {
+ pix = shifti (val, -8)
+ } else {
+ pix = andi (val, 000FFX)
+ k = k + 1
+ }
+ if (pix < 0) pix = pix + 256
+ call fprintf (fd, "%d\n")
+ call pargi (pix)
+ case TY_CHAR, TY_SHORT, TY_USHORT:
+ call fprintf (fd, "%d\n")
+ call pargs (Mems[data+((j-1)*npix+i)-1])
+ case TY_INT:
+ call fprintf (fd, "%d\n")
+ call pargi (Memi[data+((j-1)*npix+i)-1])
+ case TY_LONG:
+ call fprintf (fd, "%d\n")
+ call pargl (Meml[data+((j-1)*npix+i)-1])
+ case TY_REAL:
+ call fprintf (fd, "%g\n")
+ call pargr (Memr[data+((j-1)*npix+i)-1])
+ case TY_DOUBLE:
+ call fprintf (fd, "%g\n")
+ call pargd (Memd[data+((j-1)*npix+i)-1])
+ }
+ }
+ }
+ } else {
+ j = 0
+ do i = 1, npix {
+ if (nbands > 1) {
+ call fprintf (fd, "%4d %4d %4d ")
+ call pargi (i)
+ call pargi (line)
+ call pargi (band)
+ } else {
+ call fprintf (fd, "%4d %4d ")
+ call pargi (i)
+ call pargi (line)
+ }
+
+ switch (type) {
+ case TY_UBYTE:
+ val = Memc[data+j]
+ if (mod(i,2) == 1) {
+ pix = shifti (val, -8)
+ } else {
+ pix = andi (val, 000FFX)
+ j = j + 1
+ }
+ if (pix < 0) pix = pix + 256
+ call fprintf (fd, "%d\n")
+ call pargi (pix)
+ case TY_CHAR, TY_SHORT, TY_USHORT:
+ call fprintf (fd, "%d\n")
+ call pargs (Mems[data+i-1])
+ case TY_INT:
+ call fprintf (fd, "%d\n")
+ call pargi (Memi[data+i-1])
+ case TY_LONG:
+ call fprintf (fd, "%d\n")
+ call pargl (Meml[data+i-1])
+ case TY_REAL:
+ call fprintf (fd, "%g\n")
+ call pargr (Memr[data+i-1])
+ case TY_DOUBLE:
+ call fprintf (fd, "%g\n")
+ call pargd (Memd[data+i-1])
+ }
+ }
+ }
+end
+
+
+# EX_MERGE_PIXELS - Merge a group of pixels arrays into one array by combining
+# the elements. Returns an allocated pointer which must be later freed and
+# the total number of pixels.
+
+procedure ex_merge_pixels (ptrs, nptrs, npix, dtype, pix, totpix)
+
+pointer ptrs[ARB] #i array of pixel ptrs
+int nptrs #i number of ptrs
+int npix #i no. of pixels in each array
+int dtype #i type of pointer to alloc
+pointer pix #o output pixel array ptr
+int totpix #o total no. of output pixels
+
+int i, j, ip
+
+begin
+ # Calculate the number of output pixels and allocate the pointer.
+ totpix = nptrs * npix
+ if (dtype != TY_CHAR && dtype != TY_UBYTE)
+ call realloc (pix, totpix, dtype)
+ else {
+ call realloc (pix, totpix, TY_CHAR)
+ do i = 1, nptrs
+ call achtbs (Mems[ptrs[i]], Mems[ptrs[i]], npix)
+ }
+
+ # Fill the output array
+ ip = 0
+ for (i = 1; i<=npix; i=i+1) {
+ do j = 1, nptrs {
+ switch (dtype) {
+ case TY_UBYTE:
+ Mems[pix+ip] = Mems[ptrs[j]+i-1]
+ case TY_USHORT:
+ Mems[pix+ip] = Mems[ptrs[j]+i-1]
+
+ case TY_SHORT:
+ Mems[pix+ip] = Mems[ptrs[j]+i-1]
+
+ case TY_INT:
+ Memi[pix+ip] = Memi[ptrs[j]+i-1]
+
+ case TY_LONG:
+ Meml[pix+ip] = Meml[ptrs[j]+i-1]
+
+ case TY_REAL:
+ Memr[pix+ip] = Memr[ptrs[j]+i-1]
+
+ case TY_DOUBLE:
+ Memd[pix+ip] = Memd[ptrs[j]+i-1]
+
+ }
+
+ ip = ip + 1
+ }
+ }
+end
+
+
+# EX_CHTYPE - Change the expression operand vector to the output datatype.
+# We allocate and return a pointer to the correct type to the converted
+# pixels, this pointer must be freed later on. Any IEEE or byte-swapping
+# requests are also handled here.
+
+pointer procedure ex_chtype (ex, op, type)
+
+pointer ex #i task struct pointer
+pointer op #i evvexpr operand pointer
+int type #i new type of pointer
+
+pointer out, coerce()
+int swap, flags
+
+begin
+ # Allocate the pointer and coerce it so the routine works.
+ if (type == TY_UBYTE || type == TY_CHAR)
+ call calloc (out, O_LEN(op), TY_CHAR)
+ else {
+ call calloc (out, O_LEN(op), type)
+ out = coerce (out, type, TY_CHAR)
+ }
+
+ # If this is a color index image subtract one from the pixel value
+ # to get the index.
+ if (bitset (flags, OF_CMAP))
+ call ex_pix_to_index (O_VALP(op), O_TYPE(op), O_LEN(op))
+
+ # Change the pixel type.
+ flags = EX_OUTFLAGS(ex)
+ swap = EX_BSWAP(ex)
+ switch (O_TYPE(op)) {
+ case TY_CHAR:
+ call achtc (Memc[O_VALP(op)], Memc[out], O_LEN(op), type)
+
+ case TY_SHORT:
+ call achts (Mems[O_VALP(op)], Memc[out], O_LEN(op), type)
+
+ # Do any requested byte swapping.
+ if (bitset (swap, S_I2) || bitset (swap, S_ALL))
+ call bswap4 (Mems[out], 1, Mems[out], 1, O_LEN(op))
+
+ case TY_INT:
+ call achti (Memi[O_VALP(op)], Memc[out], O_LEN(op), type)
+
+ # Do any requested byte swapping.
+ if (bitset (swap, S_I4) || bitset (swap, S_ALL))
+ call bswap4 (Memi[out], 1, Memi[out], 1, O_LEN(op))
+
+ case TY_LONG:
+ call achtl (Meml[O_VALP(op)], Memc[out], O_LEN(op), type)
+
+ # Do any requested byte swapping.
+ if (bitset (swap, S_I4) || bitset (swap, S_ALL))
+ call bswap4 (Meml[out], 1, Meml[out], 1, O_LEN(op))
+
+ case TY_REAL:
+ call achtr (Memr[O_VALP(op)], Memc[out], O_LEN(op), type)
+
+ # See if we need to convert to IEEE
+ if (bitset (flags, OF_IEEE) && IEEE_USED == NO)
+ call ieevpakr (Memr[out], Memr[out], O_LEN(op))
+
+ case TY_DOUBLE:
+ call achtd (Memd[O_VALP(op)], Memc[out], O_LEN(op), type)
+
+ # See if we need to convert to IEEE
+ if (bitset (flags, OF_IEEE) && IEEE_USED == NO)
+ call ieevpakd (Memd[P2D(out)], Memd[P2D(out)], O_LEN(op))
+
+ default:
+ call error (0, "Invalid output type requested.")
+ }
+
+ if (type != TY_UBYTE && type != TY_CHAR)
+ out = coerce (out, TY_CHAR, type)
+ return (out)
+end
+
+
+# EX_PIX_TO_INDEX - Convert pixel values to color index values. We assume
+# the colormap has at most 256 entries.
+
+procedure ex_pix_to_index (ptr, type, len)
+
+pointer ptr #i data ptr
+int type #i data type of array
+int len #i length of array
+
+
+short sindx, smin, smax
+
+int iindx, imin, imax
+
+long lindx, lmin, lmax
+
+real rindx, rmin, rmax
+
+double dindx, dmin, dmax
+
+
+begin
+
+ sindx = short (1)
+ smin = short (0)
+ smax = short (255)
+
+ iindx = int (1)
+ imin = int (0)
+ imax = int (255)
+
+ lindx = long (1)
+ lmin = long (0)
+ lmax = long (255)
+
+ rindx = real (1)
+ rmin = real (0)
+ rmax = real (255)
+
+ dindx = double (1)
+ dmin = double (0)
+ dmax = double (255)
+
+
+ switch (type) {
+
+ case TY_SHORT:
+ call asubks (Mems[ptr], sindx, Mems[ptr], len)
+ call amaxks (Mems[ptr], smin, Mems[ptr], len)
+ call aminks (Mems[ptr], smax, Mems[ptr], len)
+
+ case TY_INT:
+ call asubki (Memi[ptr], iindx, Memi[ptr], len)
+ call amaxki (Memi[ptr], imin, Memi[ptr], len)
+ call aminki (Memi[ptr], imax, Memi[ptr], len)
+
+ case TY_LONG:
+ call asubkl (Meml[ptr], lindx, Meml[ptr], len)
+ call amaxkl (Meml[ptr], lmin, Meml[ptr], len)
+ call aminkl (Meml[ptr], lmax, Meml[ptr], len)
+
+ case TY_REAL:
+ call asubkr (Memr[ptr], rindx, Memr[ptr], len)
+ call amaxkr (Memr[ptr], rmin, Memr[ptr], len)
+ call aminkr (Memr[ptr], rmax, Memr[ptr], len)
+
+ case TY_DOUBLE:
+ call asubkd (Memd[ptr], dindx, Memd[ptr], len)
+ call amaxkd (Memd[ptr], dmin, Memd[ptr], len)
+ call aminkd (Memd[ptr], dmax, Memd[ptr], len)
+
+ }
+end
+
+
+# EX_PSTAT - Print information about the progress we're making.
+
+procedure ex_pstat (ex, row, percent)
+
+pointer ex #i task struct pointer
+int row #u current row
+int percent #u percent completed
+
+begin
+ # Print percent done if being verbose
+ if (row * 100 / EX_OROWS(ex) >= percent + 10) {
+ percent = percent + 10
+ call eprintf (" Status: %2d%% complete\r")
+ call pargi (percent)
+ call flush (STDERR)
+ }
+end
diff --git a/pkg/dataio/export/generic/mkpkg b/pkg/dataio/export/generic/mkpkg
new file mode 100644
index 00000000..4902710d
--- /dev/null
+++ b/pkg/dataio/export/generic/mkpkg
@@ -0,0 +1,12 @@
+# Compile the generic sources.
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ exobands.x ../exfcn.h ../export.h <error.h> <evvexpr.h> \
+ <fset.h> <mach.h> <ctype.h>
+ exraster.x ../export.h <evvexpr.h> <imhdr.h> <mach.h>
+ ;
diff --git a/pkg/dataio/export/mkpkg b/pkg/dataio/export/mkpkg
new file mode 100644
index 00000000..986450a7
--- /dev/null
+++ b/pkg/dataio/export/mkpkg
@@ -0,0 +1,36 @@
+# MKPKG file for the EXPORT task
+
+$call update
+$exit
+
+update:
+ $checkout libpkg.a ../
+ $update libpkg.a
+ $checkin libpkg.a ../
+ ;
+
+generic:
+ $set GEN = "$$generic -k"
+ $ifolder (generic/exobands.x, exobands.gx)
+ $(GEN) exobands.gx -o generic/exobands.x $endif
+ $ifolder (generic/exraster.x, exraster.gx)
+ $(GEN) exraster.gx -o generic/exraster.x $endif
+ ;
+
+libpkg.a:
+ $ifeq (USE_GENERIC, yes) $call generic $endif
+
+ @generic # compile the generic format code
+ @bltins # compile the builtin format code
+
+ exbltins.x exbltins.h export.h <mach.h>
+ excmap.x cmaps.inc export.h <lexnum.h>
+ exhdr.x export.h <error.h> <fset.h> <imhdr.h> \
+ <imio.h> <mach.h> <time.h>
+ expreproc.x exfcn.h cmaps.inc export.h <ctype.h> <error.h>
+ exrgb8.x export.h <imhdr.h>
+ exzscale.x export.h <error.h> <evvexpr.h>
+ t_export.x export.h <ctype.h> <error.h> <evvexpr.h> \
+ <fset.h> <imhdr.h> <mach.h>
+ zzedbg.x exbltins.h export.h <evvexpr.h>
+ ;
diff --git a/pkg/dataio/export/t_export.x b/pkg/dataio/export/t_export.x
new file mode 100644
index 00000000..6516ed11
--- /dev/null
+++ b/pkg/dataio/export/t_export.x
@@ -0,0 +1,1160 @@
+include <error.h>
+include <ctype.h>
+include <evvexpr.h>
+include <mach.h>
+include <fset.h>
+include <imhdr.h>
+include "export.h"
+
+define DEBUG false
+
+
+# T_EXPORT -- Task entry. Convert one or more IRAF image to an output binary
+# file. Output may be a raw binary raster, with or without header information,
+# a pixel listing, or a specified (supported) format. Arbitrary expressions
+# may be applied to the input images before conversion.
+
+procedure t_export ()
+
+pointer ex # task struct pointer
+pointer sp, blist, bfname # stack pointers
+pointer imname[MAX_OPERANDS]
+pointer imlist # image list pointer
+pointer im # image descriptor
+int binlist # binary file list pointer
+int imdim # dimensionality of images
+int imtype # datatype of images
+int i
+
+pointer ex_init(), immap()
+int ex_getpars()
+int clgfil(), access(), fntopnb()
+int imtlen(), imtopenp(), open(), imtgetim()
+bool streq()
+
+errchk open, immap, ex_chkimlist
+
+define quit_ 99
+
+begin
+ # Allocate local stack storage.
+ call smark (sp)
+ call salloc (bfname, SZ_FNAME, TY_CHAR)
+ call salloc (blist, SZ_FNAME, TY_CHAR)
+ call aclrc (Memc[blist], SZ_FNAME)
+ call aclrc (Memc[bfname], SZ_FNAME)
+ do i = 1, MAX_OPERANDS {
+ call salloc (imname[i], SZ_FNAME, TY_CHAR)
+ call aclrc (Memc[imname[i]], SZ_FNAME)
+ }
+
+ # Get the image and file lists.
+ imlist = imtopenp ("images")
+ call clgstr ("binfiles", Memc[blist], SZ_FNAME)
+ if (!streq("", Memc[blist]) && !streq(" ", Memc[blist])) {
+ binlist = fntopnb (Memc[blist], YES)
+ iferr (call ex_chkimlist (imlist, binlist, imdim, imtype)) {
+ call imtclose (imlist)
+ call clpcls (binlist)
+ call sfree (sp)
+ call erract (EA_FATAL)
+ }
+ call clprew (binlist)
+ } else {
+ binlist = -1
+ iferr (call ex_chkimlist (imlist, binlist, imdim, imtype)) {
+ call imtclose (imlist)
+ call sfree (sp)
+ call erract (EA_FATAL)
+ }
+ }
+ call imtrew (imlist) # rewind the list ptrs
+
+ # Allocate structure and get the task parameters.
+ ex = ex_init ()
+ EX_IMDIM(ex) = imdim
+ EX_IMTYPE(ex) = imtype
+ if (ex_getpars (ex) != OK)
+ goto quit_
+
+ # Do some last minute error checking.
+ if (imtlen(imlist) < EX_NIMAGES(ex))
+ call error (0, "Too many image operands in expression list")
+
+ # Start processing the files.
+ repeat {
+
+ # Open the output binary file.
+ if (binlist > 0) {
+ if (clgfil(binlist, Memc[bfname], SZ_FNAME) == EOF)
+ break
+
+ # If this is a builtin format append the format suffix if it's
+ # not already there and then open the file.
+ call ex_mkfname (ex, Memc[bfname])
+ if (access (BFNAME(ex), 0, 0) == YES) {
+ call eprintf ("Output file `%s' already exists.\n")
+ call pargstr (BFNAME(ex))
+ goto quit_
+ }
+ if (EX_FORMAT(ex) != FMT_LIST)
+ EX_FD(ex) = open (BFNAME(ex), NEW_FILE, BINARY_FILE)
+ else
+ EX_FD(ex) = open (BFNAME(ex), NEW_FILE, TEXT_FILE)
+ } else {
+ call strcpy ("STDOUT", Memc[bfname], SZ_FNAME)
+ call strcpy ("STDOUT", BFNAME(ex), SZ_FNAME)
+ EX_FD(ex) = STDOUT
+ }
+
+ # Open the image pointers. If no outbands expressions were given
+ # we're converting only one image, but we need to fake up the
+ # image operands.
+ if (EX_NIMAGES(ex) == EX_UNDEFINED) {
+ i = imtgetim(imlist, Memc[imname[1]], SZ_FNAME)
+ im = immap (Memc[imname[1]], READ_ONLY, 0)
+ EX_NIMAGES(ex) = 1
+ EX_NEXPR(ex) = max (1, IM_LEN(im,3))
+ EX_NCOLS(ex) = IM_LEN(im,1)
+ EX_NLINES(ex) = IM_LEN(im,2)
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), BAND_STORAGE)
+ if (EX_IMDIM(ex) == 0)
+ EX_IMDIM(ex) = IM_NDIM(im)
+ if (EX_IMTYPE(ex) == 0) {
+ EX_IMTYPE(ex) = IM_PIXTYPE(im)
+ EX_OUTTYPE(ex) = IM_PIXTYPE(im)
+ }
+
+ # Fake the expressions and break out the operands.
+ do i = 1, EX_NEXPR(ex) {
+ call ex_alloc_outbands (OBANDS(ex,i))
+ call sprintf (O_EXPR(ex,i), SZ_LINE, "b%d")
+ call pargi (i)
+ }
+ call ex_parse_operands (ex)
+ if (EX_NEXPR(ex) > 1) {
+ EX_OUTFLAGS(ex) = and (EX_OUTFLAGS(ex), not(BAND_STORAGE))
+ EX_OUTFLAGS(ex) = and (EX_OUTFLAGS(ex), not(LINE_STORAGE))
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), PIXEL_STORAGE)
+ }
+ IO_IMPTR(IMOP(ex,1)) = im
+
+ # Print some status stuff so we know what's being converted.
+ call eprintf ("%s -> %s\n")
+ call pargstr (Memc[imname[1]])
+ call pargstr (BFNAME(ex))
+ } else {
+ EX_NLINES(ex) = 0
+ do i = 1, EX_NIMAGES(ex) {
+ if (imtgetim(imlist, Memc[imname[i]], SZ_FNAME) == EOF)
+ call error (1, "Short image list")
+ im = immap (Memc[imname[i]], READ_ONLY, 0)
+ EX_NCOLS(ex) = IM_LEN(im,1)
+ EX_NLINES(ex) = max (EX_NLINES(ex), IM_LEN(im,2))
+ IO_IMPTR(IMOP(ex,i)) = im
+ if (EX_IMDIM(ex) == 0)
+ EX_IMDIM(ex) = IM_NDIM(im)
+ if (EX_IMTYPE(ex) == 0) {
+ EX_IMTYPE(ex) = IM_PIXTYPE(im)
+ EX_OUTTYPE(ex) = IM_PIXTYPE(im)
+ }
+
+ # Print some status stuff so we know what's being converted.
+ call eprintf ("%s")
+ call pargstr (Memc[imname[i]])
+ if (i < EX_NIMAGES(ex))
+ call eprintf (",")
+ else {
+ call eprintf (" -> %s\n")
+ call pargstr (BFNAME(ex))
+ }
+ call flush (STDERR)
+ }
+ }
+
+ # For 3-D data we only have one image, but we may have multiple
+ # image operands (bands) within the image. If this is the case
+ # then copy the image pointer to the remaining operand structs.
+ if (EX_NIMAGES(ex) == 1 && EX_NIMOPS(ex) > 1) {
+ do i = 2, EX_NIMOPS(ex)
+ IO_IMPTR(IMOP(ex,i)) = IO_IMPTR(IMOP(ex,1))
+ }
+
+ # Now patch up any zscale calls in the expression string.
+ do i = 1, EX_NEXPR(ex)
+ call ex_patch_zscale (ex, i)
+
+ # Now that we have all the image information and things are going
+ # well, compute the size of the output image.
+ call ex_outsize (ex)
+
+ # If we're being verbose the print some more information on the
+ # input images and output file.
+ if (EX_VERBOSE(ex) == YES)
+ call ex_prinfo (ex, imname)
+
+ # Write the header now if this is a generic raster.
+ if (EX_HEADER(ex) != HDR_NONE && EX_FORMAT(ex) != FMT_BUILTIN)
+ call ex_wheader (ex, Memc[bfname])
+
+ # Process the image.
+ call ex_process_image (ex)
+
+ # Unmap the image pointer(s).
+ do i = 1, EX_NIMAGES(ex) {
+ im = IO_IMPTR(IMOP(ex,i))
+ if (im != NULL)
+ call imunmap (im)
+ }
+
+ # Close the output file descriptor.
+ if (EX_FD(ex) != NULL)
+ call close (EX_FD(ex))
+
+ # If we created a temp image then delete that now.
+ if (EX_TIMPTR(ex) != NULL)
+ call imdelete (TIMNAME(ex))
+
+ if (binlist < 0)
+ break
+ }
+
+ # Clean up.
+quit_ call imtclose (imlist)
+ if (binlist > 0)
+ call clpcls (binlist)
+ call sfree (sp)
+end
+
+
+# EX_INIT - Initialize the export task structure.
+
+pointer procedure ex_init ()
+
+pointer ex
+
+begin
+ # Allocate the task structure pointer.
+ iferr (call calloc (ex, SZ_EXPSTRUCT, TY_STRUCT))
+ call error (0, "Error allocating EXPORT task structure.")
+
+ # Allocate internal pointers.
+ call calloc (EX_HDRPTR(ex), SZ_FNAME, TY_CHAR)
+ call calloc (EX_CMPTR(ex), SZ_FNAME, TY_CHAR)
+ call calloc (EX_LUTPTR(ex), SZ_FNAME, TY_CHAR)
+ call calloc (EX_BFNPTR(ex), SZ_FNAME, TY_CHAR)
+ call calloc (EX_OBANDS(ex), MAX_OBEXPR, TY_STRUCT)
+ call calloc (EX_IMOPS(ex), MAX_OPERANDS, TY_STRUCT)
+ call calloc (EX_OTPTR(ex), SZ_LINE, TY_CHAR)
+ call calloc (EX_OBPTR(ex), SZ_EXPSTR, TY_CHAR)
+
+ # Initialize some parameters.
+ EX_OUTFLAGS(ex) = NULL
+ EX_NLUTEL(ex) = INDEFI
+ EX_NCOLORS(ex) = CMAP_SIZE
+ EX_PSDPI(ex) = EPS_DPI
+ EX_PSSCALE(ex) = EPS_SCALE
+ EX_BRIGHTNESS(ex) = 0.5
+ EX_CONTRAST(ex) = 1.0
+
+ return (ex)
+end
+
+
+# EX_FREE - Free the export task structure.
+
+procedure ex_free (ex)
+
+pointer ex #i task struct pointer
+
+int i
+
+begin
+ # Free internal pointers.
+ call mfree (EX_HDRPTR(ex), TY_CHAR)
+ call mfree (EX_CMPTR(ex), TY_CHAR)
+ call mfree (EX_LUTPTR(ex), TY_CHAR)
+ call mfree (EX_BFNPTR(ex), TY_CHAR)
+ call mfree (EX_TIMPTR(ex), TY_CHAR)
+ call mfree (EX_OTPTR(ex), TY_CHAR)
+ call mfree (EX_OBPTR(ex), TY_CHAR)
+
+ # Free outbands pointers.
+ for (i=1; i < MAX_OBEXPR; i=i+1)
+ call ex_free_outbands (OBANDS(ex,i))
+ call mfree (EX_OBANDS(ex), TY_POINTER)
+
+ # Free operand pointers.
+ for (i=1; i < MAX_OPERANDS; i=i+1)
+ call ex_free_operand (IMOP(ex,i))
+ call mfree (EX_IMOPS(ex), TY_POINTER)
+
+ # Free the colormap.
+ if (EX_CMAP(ex) != NULL)
+ call mfree (EX_CMAP(ex), TY_CHAR)
+
+ call mfree (ex, TY_STRUCT)
+end
+
+
+# EX_GETPARS - Get the task parameters.
+
+int procedure ex_getpars (ex)
+
+pointer ex #i task struct pointer
+
+pointer sp, format, header, bswap
+pointer outtype, outbands
+
+int ex_chkpars(), clgeti(), btoi()
+bool clgetb()
+
+errchk ex_do_format, ex_do_header, ex_do_bswap
+errchk ex_do_outtype, ex_do_outbands
+
+begin
+ call smark (sp)
+ call salloc (format, SZ_FNAME, TY_CHAR)
+ call salloc (header, SZ_FNAME, TY_CHAR)
+ call salloc (bswap, SZ_FNAME, TY_CHAR)
+ call salloc (outtype, SZ_LINE, TY_CHAR)
+ call salloc (outbands, SZ_EXPSTR, TY_CHAR)
+
+ call aclrc (Memc[format], SZ_FNAME)
+ call aclrc (Memc[header], SZ_FNAME)
+ call aclrc (Memc[bswap], SZ_FNAME)
+ call aclrc (Memc[outtype], SZ_FNAME)
+ call aclrc (Memc[outbands], SZ_EXPSTR)
+
+ # Get the string valued parameters.
+ call clgstr ("format", Memc[format], SZ_FNAME)
+ call clgstr ("header", Memc[header], SZ_FNAME)
+ call clgstr ("bswap", Memc[bswap], SZ_FNAME)
+ call clgstr ("outtype", Memc[outtype], SZ_LINE)
+ call strcpy (Memc[outtype], Memc[EX_OTPTR(ex)], SZ_LINE)
+ call clgstr ("outbands", Memc[outbands], SZ_EXPSTR)
+ call strcpy (Memc[outbands], Memc[EX_OBPTR(ex)], SZ_EXPSTR)
+
+ # Get the simple params.
+ EX_INTERLEAVE(ex) = clgeti ("interleave")
+ EX_VERBOSE(ex) = btoi (clgetb ("verbose"))
+
+ # Process the parameter values, due error checking
+ iferr {
+ call ex_do_format (ex, Memc[format])
+ call ex_do_header (ex, Memc[header])
+ call ex_do_bswap (ex, Memc[bswap])
+ call ex_do_outtype (ex, Memc[outtype])
+ call ex_do_outbands(ex, Memc[outbands])
+ } then {
+ call sfree (sp)
+ call erract (EA_FATAL)
+ }
+
+ call sfree (sp)
+
+ if (DEBUG) {
+ call eprintf("ex_format=%d\n"); call pargi (EX_FORMAT(ex))
+ call eprintf("ex_bswap=%d\n"); call pargi (EX_BSWAP(ex))
+ call eprintf("ex_outtype=%d\n"); call pargi (EX_OUTTYPE(ex))
+ call eprintf("ex_header=%d\n"); call pargi (EX_HEADER(ex))
+ }
+
+ # Do a sanity check on the params so we can exit now if needed.
+ return (ex_chkpars (ex))
+end
+
+
+# EX_CHKPARS - Check task parameters to be sure we have a valid conversion.
+
+int procedure ex_chkpars (ex)
+
+pointer ex #i task struct pointer
+
+int flags, exb_chkpars()
+
+begin
+ flags = EX_OUTFLAGS(ex)
+ if (EX_FORMAT(ex) == FMT_BUILTIN && !bitset(EX_OUTFLAGS(ex),OF_MKCMAP)){
+ return (exb_chkpars(ex))
+ } else {
+ if (bitset (flags, OF_CMAP)) {
+ call error (1, "Colormap creation not supported for raw output")
+ return (ERR)
+ }
+ }
+
+ return (OK)
+end
+
+
+# EX_CHKIMLIST - Check the image list to be sure it's valid.
+
+procedure ex_chkimlist (images, files, ndim, type)
+
+int images #i image list pointer
+int files #i binary files list pointer
+int ndim #o dimensionality of images
+int type #o datatype of images
+
+pointer im, sp, imname
+int dim
+
+pointer immap()
+int imtlen(), imtgetim(), clplen()
+
+errchk immap
+
+begin
+ call smark (sp)
+ call salloc (imname, SZ_FNAME, TY_CHAR)
+ call aclrc (Memc[imname], SZ_FNAME)
+
+ # Get dimension of first image.
+ if (imtgetim (images, Memc[imname], SZ_FNAME) != EOF) {
+ im = immap (Memc[imname], READ_ONLY, 0)
+ ndim = IM_NDIM(im)
+ type = IM_PIXTYPE(im)
+ call imunmap (im)
+ } else
+ call error (0, "Unexpected EOF in image list.\n")
+
+ # Loop over remaining images in the list.
+ while (imtgetim (images, Memc[imname], SZ_FNAME) != EOF) {
+ im = immap (Memc[imname], READ_ONLY, 0)
+ dim = IM_NDIM(im)
+ call imunmap (im)
+ if (dim != ndim)
+ call error (0, "Images must all be the same dimension.\n")
+ }
+
+ if (files > 0) {
+ if (ndim == 3 && (imtlen (images) != clplen (files)))
+ call error (0, "No. of images must equal no. of output files\n")
+ }
+
+ call sfree (sp)
+end
+
+
+# EX_OUTSIZE - Compute the output file dimensions. We don't require that
+# the expressions all evaluate to same length so we'll patch up the expr
+# string to pad with zeroes to the maximum width.
+
+procedure ex_outsize (ex)
+
+pointer ex #i task struct pointer
+
+pointer sp, expr
+int i, ip, imnum, plev
+int height, maxlen, maxhgt
+char ch
+
+pointer op, ex_evaluate()
+int ctoi(), strncmp()
+
+begin
+ call smark (sp)
+ call salloc (expr, SZ_EXPSTR, TY_CHAR)
+ call aclrc (Memc[expr], SZ_EXPSTR)
+
+ call ex_getpix (ex, 1)
+ maxlen = 0
+ do i = 1, EX_NEXPR(ex) { # get length of each expr
+ op = ex_evaluate (ex, O_EXPR(ex,i))
+ O_WIDTH(ex,i) = O_LEN(op)
+ maxlen = max (maxlen, O_WIDTH(ex,i))
+ call evvfree (op)
+ }
+
+ do i = 1, EX_NEXPR(ex) { # patch expressions
+
+ if (O_WIDTH(ex,i) <= 1) {
+ # If the width is 1 we have a constant, meaning we only want
+ # one line on output and need to pad the constant.
+ O_HEIGHT(ex,i) = 1
+ O_WIDTH(ex,i) = maxlen
+ call aclrc (Memc[expr], SZ_EXPSTR)
+ call sprintf (Memc[expr], SZ_EXPSTR, "repl(%s,%d)")
+ call pargstr (O_EXPR(ex,i))
+ call pargi (maxlen)
+ call strcpy (Memc[expr], O_EXPR(ex,i), SZ_EXPSTR)
+
+ } else if (O_WIDTH(ex,i) <= maxlen) {
+ # If this is a vector expression then look for image operands.
+ # The 'height' of the expression will be the largest height
+ # of the found operands.
+
+ ip = 1
+ maxhgt = 1
+ call strcpy (O_EXPR(ex,i), Memc[expr], SZ_EXPSTR)
+ repeat {
+ while (Memc[expr+ip-1] != 'i' && Memc[expr+ip-1] != 'b' &&
+ Memc[expr+ip-1] != EOS)
+ ip = ip + 1
+ if (Memc[expr+ip-1] == EOS)
+ break
+ if (IS_DIGIT(Memc[expr+ip])) {
+ ip = ip + 1
+ if (ctoi (Memc[expr], ip, imnum) == 0)
+ call error (4, "ex_outsize: can't parse operand")
+ maxhgt = max (maxhgt,IM_LEN(IO_IMPTR(IMOP(ex,imnum)),2))
+
+ } else if (strncmp(Memc[expr+ip-1], "block", 5) == 0) {
+ ip = ip + 1
+
+ # This is a "block" function call to fill a vertical
+ # area. The syntax is "block(constant, width, height)"
+ # so get the height argument.
+ while (Memc[expr+ip] != '(')
+ ip = ip + 1
+ plev = 0
+ repeat { # skip over 1st arg
+ ip = ip + 1
+ ch = Memc[expr+ip]
+ if (ch == '(') plev = plev + 1
+ if (ch == ')') plev = plev - 1
+ if (ch == ',' && plev == 0)
+ break
+ }
+ # Should be the start of arg2.
+ ip = ip + 2 # should be the width
+ if (ctoi (Memc[expr], ip, height) == 0)
+ call error (4, "ex_outsize: block() syntax error")
+ ip = ip + 1 # should be the height
+ if (ctoi (Memc[expr], ip, height) == 0)
+ call error (4, "ex_outsize: block() syntax error")
+
+ maxhgt = max (maxhgt, height)
+ } else
+ ip = ip + 1
+ }
+ O_HEIGHT(ex,i) = maxhgt
+
+ if (O_WIDTH(ex,i) < maxlen) {
+ call aclrc (Memc[expr], SZ_EXPSTR)
+ call sprintf (Memc[expr], SZ_EXPSTR, "%s//repl(0,%d)")
+ call pargstr (O_EXPR(ex,i))
+ call pargi (maxlen - O_WIDTH(ex,i))
+ call strcpy (Memc[expr], O_EXPR(ex,i), SZ_EXPSTR)
+ O_WIDTH(ex,i) = maxlen
+ }
+ }
+
+ if (DEBUG) { call eprintf ("%d: len=%d maxlen=%d height=%d\n")
+ call pargi(i) ; call pargi(O_WIDTH(ex,i))
+ call pargi(maxlen) ; call pargi (O_HEIGHT(ex,i)) }
+
+ }
+ EX_OCOLS(ex) = maxlen
+
+ # Now compute the total number of rows.
+ if (EX_IMDIM(ex) == 3) {
+ if (!bitset (EX_OUTFLAGS(ex), PIXEL_STORAGE)) {
+ if (EX_NEXPR(ex) > 1 && bitset (EX_OUTFLAGS(ex), OF_BAND))
+ EX_OROWS(ex) = IM_LEN(IO_IMPTR(IMOP(ex,1)),3)*EX_NLINES(ex)
+ else
+ EX_OROWS(ex) = EX_NLINES(ex)
+ } else
+ EX_OROWS(ex) = EX_NLINES(ex)
+ } else if (bitset (EX_OUTFLAGS(ex), OF_BAND)) {
+ EX_OROWS(ex) = 0
+ do i = 1, EX_NEXPR(ex)
+ EX_OROWS(ex) = EX_OROWS(ex) + O_HEIGHT(ex,i)
+ } else
+ EX_OROWS(ex) = EX_NLINES(ex)
+
+ call sfree (sp)
+end
+
+
+# EX_DO_FORMAT - Get the task format parameter and set appropriate flags.
+
+procedure ex_do_format (ex, format)
+
+pointer ex #i task struct pointer
+char format[ARB] #i format parameter value
+
+bool streq()
+
+begin
+ if (DEBUG) { call eprintf("format='%s'\n");call pargstr (format) }
+
+ EX_COLOR(ex) = NO
+ if (streq(format,"raw"))
+ EX_FORMAT(ex) = FMT_RAW
+ else if (streq(format,"list"))
+ EX_FORMAT(ex) = FMT_LIST
+ else {
+ EX_FORMAT(ex) = FMT_BUILTIN
+ call exb_do_format (ex, format)
+ }
+end
+
+
+# EX_DO_HEADER - Process the header parameter.
+
+procedure ex_do_header (ex, header)
+
+pointer ex #i task struct pointer
+char header[ARB] #i header parameter string
+
+bool streq()
+int access()
+
+begin
+ if (DEBUG) { call eprintf("header='%s'\n") ; call pargstr (header) }
+
+ if (streq(header,"no"))
+ EX_HEADER(ex) = HDR_NONE
+ else if (streq(header,"yes"))
+ EX_HEADER(ex) = HDR_SHORT
+ else if (streq(header,"long"))
+ EX_HEADER(ex) = HDR_LONG
+ else {
+ EX_HEADER(ex) = HDR_USER
+ if (access (header, 0, 0) == NO)
+ call error (2, "User-defined header file does not exist.")
+ else
+ call strcpy (header, HDRFILE(ex), SZ_FNAME)
+ }
+end
+
+
+# EX_DO_OUTTYPE - Process the output pixel type parameter.
+
+procedure ex_do_outtype (ex, outtype)
+
+pointer ex #i task struct pointer
+char outtype[ARB] #i outtype parameter string
+
+int pixtype, nbytes
+
+int ex_ptype(), stridx()
+
+begin
+ if (DEBUG) { call eprintf("outtype='%s'\n");call pargstr (outtype) }
+
+ if (outtype[1] == EOS) {
+ EX_OUTTYPE(ex) = EX_IMTYPE(ex) # use type of input image
+ return
+ }
+
+ pixtype = stridx(outtype[1],"buirn")
+ if (pixtype == 0)
+ call error (2, "Invalid 'outtype' value specified\n")
+
+ if (outtype[2] == EOS) {
+ if (outtype[1] == 'b') # set minimal sizes
+ nbytes = 1
+ else if (outtype[1] == 'u')
+ nbytes = 2
+ else
+ nbytes = 4
+ } else
+ nbytes = outtype[2] - '1' + 1
+
+ # Set struct param.
+ EX_OUTTYPE(ex) = ex_ptype (pixtype, nbytes)
+ call sprintf (Memc[EX_OTPTR(ex)], SZ_FNAME, "%c%d")
+ call pargc (Memc[EX_OTPTR(ex)])
+ call pargi (nbytes)
+end
+
+
+# EX_DO_BSWAP -- Read the byte-swap string an load the ip structure.
+
+procedure ex_do_bswap (ex, bswap)
+
+pointer ex #i task struct pointer
+char bswap[ARB] #i byte swap string
+
+char ch, flag[SZ_FNAME]
+int sp, i
+
+int strdic()
+
+begin
+ if (DEBUG) { call eprintf("swap='%s'\n");call pargstr (bswap) }
+
+ sp = 1
+ EX_BSWAP(ex) = NULL
+ while (bswap[sp] != EOS) {
+ i = 1
+ for (ch=bswap[sp]; ch != EOS && ch != ','; ch=bswap[sp]) {
+ flag[i] = ch
+ i = i + 1
+ sp = sp + 1
+ }
+ flag[i] = EOS
+
+ switch (strdic (flag, flag, SZ_FNAME, SWAP_STR)) {
+ case 1, 2:
+ EX_BSWAP(ex) = or (EX_BSWAP(ex), S_NONE)
+ case 3:
+ EX_BSWAP(ex) = or (EX_BSWAP(ex), S_ALL)
+ case 4:
+ EX_BSWAP(ex) = or (EX_BSWAP(ex), S_I2)
+ case 5:
+ EX_BSWAP(ex) = or (EX_BSWAP(ex), S_I4)
+ default:
+ break
+ }
+ }
+end
+
+
+# EX_DO_OUTBANDS - Parse the 'outbands' expressions. The operand tags are
+# caught and space allocated.
+
+procedure ex_do_outbands (ex, outbands)
+
+pointer ex #i task struct pointer
+char outbands[ARB] #i outbands expression string
+
+pointer sp, exp, expr
+int fd, nchars, nexpr
+int j, ip, plevel
+
+int open(), fstatl(), strlen()
+char getc()
+
+errchk open
+
+begin
+ if (DEBUG) { call eprintf("outbands='%s'\n");call pargstr (outbands) }
+
+ if (outbands[1] == EOS) {
+ EX_NIMAGES(ex) = EX_UNDEFINED # convert the whole image
+ EX_NEXPR(ex) = EX_UNDEFINED
+ return
+ }
+
+ call smark (sp)
+ call salloc (exp, SZ_EXPSTR, TY_CHAR)
+ call aclrc (Memc[exp], SZ_EXPSTR)
+
+ # If the outbands parameter is an @-file read in the expression from
+ # the file, otherwise just copy the param to the working buffer.
+ if (outbands[1] == '@') {
+ fd = open (outbands[2], READ_ONLY, TEXT_FILE)
+ nchars = fstatl (fd, F_FILESIZE) + 1
+ call calloc (expr, max(SZ_EXPSTR,nchars), TY_CHAR)
+ ip = 0
+ for (j=0; j<nchars && ip != EOF; j=j+1)
+ ip = getc (fd, Memc[expr+j])
+ Memc[expr+nchars-1] = EOS
+ call close (fd)
+ } else {
+ nchars = strlen (outbands) + 1
+ call calloc (expr, max(SZ_EXPSTR,nchars), TY_CHAR)
+ call strcpy (outbands, Memc[expr], nchars)
+ }
+
+ nexpr = 0 # initialize variables
+
+ # Preprocess the expression string to strip out functions that aren't
+ # really evaluated for each line in the image. The processing is
+ # done in-place and the returned string should contain only processing
+ # functions.
+ call ex_preprocess (ex, Memc[expr])
+ if (DEBUG) { call eprintf("\texpr1='%s'\n");call pargstr(Memc[expr]) }
+
+ ip = 0
+ while (Memc[expr+ip] != EOS) {
+ # Parse each expression into an outbands struct buffer.
+ plevel = 0
+ for (j=0; j<SZ_LINE && Memc[expr+ip] != EOS; j=j+1) {
+ Memc[exp+j] = Memc[expr+ip]
+ if (Memc[expr+ip] == '(')
+ plevel = plevel + 1
+ else if (Memc[expr+ip] == ')')
+ plevel = plevel - 1
+ else if (Memc[expr+ip] == ',' && plevel == 0)
+ break
+ else if (Memc[expr+ip] == EOS)
+ break
+
+ ip = ip + 1
+ }
+ if (Memc[expr+ip] != EOS)
+ ip = ip + 1
+ Memc[exp+j] = '\0'
+ nexpr = nexpr + 1
+
+ if (DEBUG) {
+ call eprintf ("\texpr[%d] = `%s'\n")
+ call pargi(nexpr);call pargstr(Memc[exp])
+ }
+
+ # Save expression in outbands struct.
+ call ex_alloc_outbands (OBANDS(ex,nexpr))
+ call strcpy (Memc[exp], O_EXPR(ex,nexpr), SZ_EXPSTR)
+ }
+ EX_NEXPR(ex) = nexpr
+
+ # Now that we have the expressions break out the operands.
+ call ex_parse_operands (ex)
+
+ # Set the output type flag if not already defined in preprocessing.
+ if (EX_OUTFLAGS(ex) == 0) {
+ if (EX_INTERLEAVE(ex) == 0 && EX_NEXPR(ex) > 1)
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), PIXEL_STORAGE)
+ else if (EX_INTERLEAVE(ex) > 0 && EX_NEXPR(ex) > 1)
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), LINE_STORAGE)
+ else
+ EX_OUTFLAGS(ex) = or (EX_OUTFLAGS(ex), BAND_STORAGE)
+ }
+
+ call mfree (expr, TY_CHAR)
+ call sfree (sp)
+end
+
+
+# EX_PARSE_OPERANDS - Parse each expression string to break out the image
+# operands. If the input image list is 2-D data we'll be generous and
+# allow either 'b1' or 'i1', otherwise require the bands number.
+
+define SZ_TAG 7
+
+procedure ex_parse_operands (ex)
+
+pointer ex #i task struct pointer
+
+pointer sp, expr
+int i, ip, opnum
+char ch, tag[SZ_TAG]
+
+int ctoi()
+
+begin
+ call smark (sp)
+ call salloc (expr, SZ_EXPSTR, TY_CHAR)
+
+ EX_NIMOPS(ex) = 0
+ EX_NIMAGES(ex) = 0
+ do i = 1, EX_NEXPR(ex) {
+ call aclrc (Memc[expr], SZ_EXPSTR)
+ call strcpy (O_EXPR(ex,i), Memc[expr], SZ_EXPSTR)
+
+ ip = 1
+ while (Memc[expr+ip] != EOS) {
+ ch = Memc[expr+ip-1]
+
+ # See if we have an operand descriptor.
+ if ((ch == 'b' || ch == 'i') && IS_DIGIT(Memc[expr+ip])) {
+ ip = ip + 1
+ if (ctoi (Memc[expr], ip, opnum) == 0)
+ call error (4, "can't parse operand")
+ call sprintf (tag, SZ_TAG, "%c%d")
+ call pargc (ch)
+ call pargi (opnum)
+
+ # Allocate the operand structure
+ if (IMOP(ex,opnum) == NULL) {
+ call ex_alloc_operand (IMOP(ex,opnum))
+ call strcpy (tag, OP_TAG(IMOP(ex,opnum)), SZ_TAG)
+ EX_NIMOPS(ex) = EX_NIMOPS(ex) + 1
+ }
+
+ # For 2-D images allow either name interchangeably. Here
+ # we set the struct image band, we'll load the image de-
+ # scriptor later.
+ if (EX_IMDIM(ex) == 2) {
+ IO_BAND(IMOP(ex,opnum)) = 1
+ EX_NIMAGES(ex) = EX_NIMOPS(ex)
+ } else if (EX_IMDIM(ex) == 3) {
+ if (ch == 'i')
+ call error (4, "Image operand illegal w/ 3-D lists")
+ IO_BAND(IMOP(ex,opnum)) = opnum
+ EX_NIMAGES(ex) = 1
+ }
+ if (DEBUG) call zze_prop (IMOP(ex,opnum))
+ }
+ ip = ip + 1
+ }
+ }
+
+ call sfree (sp)
+end
+
+
+# EX_PROCESS_IMAGE - Process the image pixels.
+
+procedure ex_process_image (ex)
+
+pointer ex #i task struct pointer
+
+int flags
+
+begin
+ flags = EX_OUTFLAGS(ex)
+
+ # Create the (if any) requested colormap first.
+ if (bitset (flags, OF_MKCMAP))
+ call ex_mkcmap (ex)
+
+ # Process the images.
+ if (EX_FORMAT(ex) == FMT_BUILTIN) {
+ # Write the builtin format.
+ call exb_process_image (ex)
+
+ } else {
+ if (bitset (flags, OF_BAND) || bitset (flags, BAND_STORAGE))
+ call ex_no_interleave (ex)
+ else if (bitset (flags, OF_LINE) || bitset (flags, LINE_STORAGE))
+ call ex_ln_interleave (ex)
+ else if (bitset (flags, PIXEL_STORAGE))
+ call ex_px_interleave (ex)
+ else
+ call error (0, "Unknown processing param.")
+ }
+
+ #if (EX_VERBOSE(ex) == YES) {
+ call eprintf (" Status: Done. \n")
+ call flush (STDERR)
+ #}
+end
+
+
+# EX_PRINFO - Print verbose information about the conversion.
+
+procedure ex_prinfo (ex, np)
+
+pointer ex #i task struct pointer
+pointer np[ARB] #i ptr to image names
+
+pointer im
+int i, j, flags
+
+begin
+ # Print information about the input images.
+ call eprintf (" Input images:\n")
+ do i = 1, EX_NIMAGES(ex) {
+ im = IO_IMPTR(IMOP(ex,i))
+ call eprintf ("\t%s: %s %40t")
+ call pargstr (OP_TAG(IMOP(ex,i)))
+ call pargstr (Memc[np[i]])
+ do j = 1, IM_NDIM(im) {
+ call eprintf ("%d ")
+ call pargi (IM_LEN(im,j))
+ if (j < IM_NDIM(im))
+ call eprintf ("x ")
+ }
+ call eprintf (" `%s'\n")
+ call pargstr (IM_TITLE(im))
+ }
+
+ # Print information about the output file.
+ flags = EX_OUTFLAGS(ex)
+ call eprintf (" Output file:\n")
+ call eprintf ("\tName: %30t%s\n")
+ call pargstr (BFNAME(ex))
+ call eprintf ("\tFormat: %30t%s\n")
+ switch (EX_FORMAT(ex)) {
+ case FMT_RAW: call pargstr ("Raw")
+ case FMT_LIST: call pargstr ("List")
+ case FMT_BUILTIN:
+ call exb_pname (ex)
+ }
+
+ if (EX_FORMAT(ex) == FMT_RAW) {
+ call eprintf ("\tHeader: %30t%s%s\n")
+ switch(EX_HEADER(ex)) {
+ case HDR_NONE: call pargstr ("None") ; call pargstr ("")
+ case HDR_SHORT: call pargstr ("Short") ; call pargstr ("")
+ case HDR_LONG: call pargstr ("Long") ; call pargstr ("")
+ case HDR_USER: call pargstr ("User: ")
+ call pargstr (HDRFILE(ex))
+ }
+ }
+
+ call eprintf ("\tByte Order: %30t%s\n")
+ if (EX_FORMAT(ex) == FMT_BUILTIN)
+ call exb_pendian (ex)
+ else if (EX_BSWAP(ex) == 0 && (BYTE_SWAP2==NO || BYTE_SWAP4==NO))
+ call pargstr ("Most Significant Byte First")
+ else
+ call pargstr ("Least Significant Byte First")
+
+ call eprintf ("\tResolution: %30t%d x %d\n")
+ call pargi (EX_OCOLS(ex))
+ call pargi (EX_OROWS(ex))
+
+ call eprintf ("\tPixel Storage: %30t%s\n")
+ if (EX_FORMAT(ex) == FMT_BUILTIN)
+ call exb_pstorage (ex)
+ else if (bitset(flags, OF_BAND) || bitset(flags,BAND_STORAGE))
+ call pargstr ("Band Interleaved")
+ else if (bitset(flags, OF_LINE) || bitset(flags,LINE_STORAGE))
+ call pargstr ("Line Interleaved")
+ else if (bitset(flags,PIXEL_STORAGE))
+ call pargstr ("Pixel Interleaved")
+ else
+ call pargstr ("Unknown")
+
+ if (bitset(flags, OF_CMAP) || bitset(flags, OF_MKCMAP))
+ call eprintf ("\tType: %30t8-bit Color Indexed\n")
+ else {
+ if (bitset(flags, OF_BAND) && EX_NEXPR(ex) > 1)
+ call eprintf ("\tType: %30tGrayscale\n")
+ else
+ call eprintf ("\tType: %30tRGB\n")
+ }
+
+ if (bitset(flags, OF_CMAP) || bitset(flags, OF_MKCMAP)) {
+ call eprintf ("\tColor Table: %30t%d entries\n")
+ call pargi (EX_NCOLORS(ex))
+ } else
+ call eprintf ("\tColor Table: %30tnone\n")
+
+ if (DEBUG && EX_NEXPR(ex) != 0) {
+ call eprintf ("\tEvaluated Expressions:\n")
+ do i = 1, EX_NEXPR(ex) {
+ call eprintf ("\t %d) %s\n")
+ call pargi (i)
+ call pargstr (O_EXPR(ex,i))
+ }
+ }
+end
+
+
+# EX_PTYPE -- For a given outtype parameter return the corresponding IRAF
+# data type.
+
+define NTYPES 6
+define NBITPIX 4
+
+int procedure ex_ptype (type, nbytes)
+
+int type #i pixel type
+int nbytes #i number of bytes
+
+int i, pt, pb, ptype
+int tindex[NTYPES], bindex[NBITPIX], ttbl[NTYPES*NBITPIX]
+
+data tindex /PT_BYTE, PT_UINT, PT_INT, PT_IEEE, PT_NATIVE, PT_SKIP/
+data bindex /1, 2, 4, 8/
+
+data (ttbl(i), i= 1, 4) /TY_UBYTE, TY_USHORT, TY_INT, 0/ # B
+data (ttbl(i), i= 5, 8) /TY_UBYTE, TY_USHORT, 0, 0/ # U
+data (ttbl(i), i= 9,12) /TY_UBYTE, TY_SHORT, TY_INT, 0/ # I
+data (ttbl(i), i=13,16) / 0, 0, TY_REAL, TY_DOUBLE/ # R
+data (ttbl(i), i=17,20) / 0, 0, TY_REAL, TY_DOUBLE/ # N
+data (ttbl(i), i=21,24) /TY_UBYTE, TY_USHORT, TY_REAL, TY_DOUBLE/ # X
+
+begin
+ if (type == 0 || nbytes == 0) # uninitialized values
+ return (0)
+
+ pt = NTYPES
+ do i = 1, NTYPES {
+ if (tindex[i] == type)
+ pt = i
+ }
+ pb = NBITPIX
+ do i = 1, NBITPIX {
+ if (bindex[i] == nbytes)
+ pb = i
+ }
+
+ ptype = ttbl[(pt-1)*NBITPIX+pb]
+
+ if (DEBUG) { call eprintf("pt=%d pb=%d -> ptype=%d\n")
+ call pargi (pt) ; call pargi (pb) ; call pargi (ptype) }
+
+ if (ptype == 0)
+ call error (0, "Invalid outtype specified.")
+ else
+ return (ptype)
+end
+
+
+# EX_MKFNAME - Create an output filename based on the requested format.
+
+procedure ex_mkfname (ex, fname)
+
+pointer ex #i task struct pointer
+char fname[ARB] # generate the output filename
+
+pointer sp, suffix, test
+int fnextn()
+bool streq()
+pointer exb_fmt_ext()
+
+begin
+ call smark (sp)
+ call salloc (test, SZ_FNAME, TY_CHAR)
+
+ if (EX_FORMAT(ex) == FMT_BUILTIN)
+ suffix = exb_fmt_ext (ex)
+ else if (EX_FORMAT(ex) == FMT_RAW || EX_FORMAT(ex) == FMT_LIST) {
+ call strcpy (fname, BFNAME(ex), SZ_FNAME)
+ call sfree (sp)
+ return
+ }
+
+ # If the current extension is not the same as the format extn add it.
+ if (fnextn (fname, Memc[test], SZ_FNAME) > 0) {
+ if (streq(Memc[test], Memc[suffix+1])) {
+ call strcpy (fname, BFNAME(ex), SZ_FNAME)
+ call sfree (sp)
+ return
+ }
+ }
+
+ call sprintf (BFNAME(ex), SZ_FNAME, "%s%s")
+ call pargstr (fname)
+ call pargstr (Memc[suffix])
+
+ call mfree (suffix, TY_CHAR)
+ call sfree (sp)
+end
+
+
+# EX_ALLOC_OUTBANDS -- Allocate an outbands structure.
+
+procedure ex_alloc_outbands (op)
+
+pointer op #i outbands struct pointer
+
+begin
+ call calloc (op, LEN_OUTBANDS, TY_STRUCT)
+ call calloc (OB_EXPSTR(op), SZ_EXPSTR, TY_CHAR)
+end
+
+
+# EX_FREE_OUTBANDS -- Free an outbands structure.
+
+procedure ex_free_outbands (op)
+
+pointer op #i outbands struct pointer
+
+begin
+ call mfree (OB_EXPSTR(op), TY_CHAR)
+ call mfree (op, TY_STRUCT)
+end
+
+
+# EX_ALLOC_OPERAND -- Allocate an operand structure.
+
+procedure ex_alloc_operand (op)
+
+pointer op #i operand struct pointer
+
+begin
+ call calloc (op, LEN_OPERAND, TY_STRUCT)
+ call calloc (IO_TAG(op), SZ_FNAME, TY_CHAR)
+end
+
+
+# EX_FREE_OPERAND -- Free an operand structure.
+
+procedure ex_free_operand (op)
+
+pointer op #i operand struct pointer
+
+begin
+ call mfree (IO_TAG(op), TY_CHAR)
+ call mfree (op, TY_STRUCT)
+end
diff --git a/pkg/dataio/export/zzedbg.x b/pkg/dataio/export/zzedbg.x
new file mode 100644
index 00000000..d1eba755
--- /dev/null
+++ b/pkg/dataio/export/zzedbg.x
@@ -0,0 +1,157 @@
+include <evvexpr.h>
+include "exbltins.h"
+include "export.h"
+
+procedure zze_prstruct (whence, ex)
+
+char whence[SZ_FNAME]
+pointer ex
+int i
+
+begin
+ call eprintf ("%s:\n") ; call pargstr (whence)
+ call eprintf ("\tformat=%s %s outflags=%d interleave=%d bswap=%s\n")
+ switch (EX_FORMAT(ex)) {
+ case FMT_RAW: call pargstr ("FMT_RAW")
+ case FMT_LIST: call pargstr ("FMT_LIST")
+ case FMT_BUILTIN: call pargstr ("FMT_BUILTIN")
+ default: call pargstr ("ERR")
+ }
+ switch (EX_BLTIN(ex)) {
+ case EPS: call pargstr ("(eps)")
+ case GIF: call pargstr ("(gif)")
+ case PGM: call pargstr ("(pgm)")
+ case PPM: call pargstr ("(ppm)")
+ case RAS: call pargstr ("(ras)")
+ case RGB: call pargstr ("(rgb)")
+ case XWD: call pargstr ("(xwd)")
+ default: call pargstr ("")
+ }
+ call pargi (EX_OUTFLAGS(ex))
+ call pargi (EX_INTERLEAVE(ex))
+ switch(EX_BSWAP(ex)) {
+ case S_NONE: call pargstr ("S_NONE")
+ case S_ALL: call pargstr ("S_ALL")
+ case S_I2: call pargstr ("S_I2")
+ case S_I4: call pargstr ("S_I4")
+ default: call pargstr ("ERR")
+ }
+ call eprintf ("\touttype=%s header='%s' verbose=%d\n")
+ switch(EX_OUTTYPE(ex)) {
+ case TY_SHORT: call pargstr ("TY_SHORT")
+ case TY_INT: call pargstr ("TY_INT")
+ case TY_LONG: call pargstr ("TY_LONG")
+ case TY_REAL: call pargstr ("TY_REAL")
+ case TY_DOUBLE: call pargstr ("TY_DOUBLE")
+ default: call pargstr ("ERR")
+ }
+ switch(EX_HEADER(ex)) {
+ case HDR_NONE: call pargstr ("HDR_NONE")
+ case HDR_SHORT: call pargstr ("HDR_SHORT")
+ case HDR_LONG: call pargstr ("HDR_LONG")
+ case HDR_USER: call pargstr ("HDR_USER")
+ default: call pargstr ("ERR")
+ }
+ call pargi (EX_VERBOSE(ex))
+ call eprintf ("\toutbands (%d):\n") ; call pargi (EX_NEXPR(ex))
+ do i = 1, EX_NEXPR(ex)
+ call zze_proband (ex, i)
+ call eprintf ("\tocols=%d orows=%d:\n")
+ call pargi (EX_OCOLS(ex)) ; call pargi (EX_OROWS(ex))
+ call eprintf ("\tnimages=%d nimops=%d ncols=%d nlines=%d:\n")
+ call pargi (EX_NIMAGES(ex))
+ call pargi (EX_NIMOPS(ex))
+ call pargi (EX_NCOLS(ex))
+ call pargi (EX_NLINES(ex))
+ do i = 1, MAX_OPERANDS {
+ if (IMOP(ex,i) != NULL) {
+ call eprintf ("\t ") ; call zze_prop (IMOP(ex,i))
+ }
+ }
+
+ call eprintf ("\tuser header = '%s' LUT file = '%s'\n")
+ call pargstr (HDRFILE(ex))
+ call pargstr (LUTFILE(ex))
+ call eprintf ("\tEPS dpi = %g scale = %g ncolors = %d\n")
+ call pargr (EX_PSDPI(ex))
+ call pargr (EX_PSSCALE(ex))
+ call pargi (EX_NCOLORS(ex))
+ call eprintf ("\tbrightness = %g contrast = %g\n")
+ call pargr (EX_BRIGHTNESS(ex))
+ call pargr (EX_CONTRAST(ex))
+ call flush (STDERR)
+end
+
+
+procedure zze_proband (ex, band)
+
+pointer ex
+int band
+
+begin
+ call eprintf ("\t ob=%d w=%d h=%d expr='%s'\n")
+ call pargi (OBANDS(ex,band))
+ call pargi (OB_WIDTH(OBANDS(ex,band)))
+ call pargi (OB_HEIGHT(OBANDS(ex,band)))
+ call pargstr (O_EXPR(ex,band))
+end
+
+
+procedure zze_prop (o)
+
+pointer o
+char buf[8]
+int type, ex_ptype()
+
+begin
+ if (o == NULL)
+ return
+
+ call sprintf (buf, 8, " buirnx")
+ type = ex_ptype(IO_TYPE(o), IO_NBYTES(o))
+ call eprintf("(o=%d im=%d band=%d tag=%s (t='%c' N=%d=>%s) Np=%d %d)\n")
+ call pargi (o)
+ call pargi (IO_IMPTR(o))
+ call pargi (IO_BAND(o))
+ if (IO_TAG(o) == NULL) call pargstr ("")
+ else call pargstr (OP_TAG(o))
+ #call pargc (buf[IO_TYPE(o)+1])
+ call pargc (IO_TYPE(o))
+ call pargi (IO_NBYTES(o))
+ switch (type) {
+ case TY_UBYTE: call pargstr ("TY_UBYTE")
+ case TY_USHORT: call pargstr ("TY_USHORT")
+ case TY_SHORT: call pargstr ("TY_SHORT")
+ case TY_INT: call pargstr ("TY_INT")
+ case TY_LONG: call pargstr ("TY_LONG")
+ case TY_REAL: call pargstr ("TY_REAL")
+ case TY_DOUBLE: call pargstr ("TY_DOUBLE")
+ default: call pargstr ("ERR")
+ }
+ call pargi (IO_NPIX(o))
+ call pargi (IO_DATA(o))
+ call flush (STDERR)
+end
+
+
+procedure zze_pevop (o)
+
+pointer o
+
+begin
+ call eprintf ("o=%d type=%d len=%d flags=%d ")
+ call pargi (o)
+ call pargi (O_TYPE(o))
+ call pargi (O_LEN(o))
+ call pargi (O_FLAGS(o))
+ switch (O_TYPE(o)) {
+ case TY_CHAR: call eprintf ("val='%s'\n") ; call pargstr (O_VALC(o))
+ case TY_SHORT: call eprintf ("val=%d\n") ; call pargs (O_VALS(o))
+ case TY_INT: call eprintf ("val=%d\n") ; call pargi (O_VALI(o))
+ case TY_LONG: call eprintf ("val=%d\n") ; call pargl (O_VALL(o))
+ case TY_REAL: call eprintf ("val=%g\n") ; call pargr (O_VALR(o))
+ case TY_DOUBLE: call eprintf ("val=%g\n") ; call pargd (O_VALD(o))
+ default: call eprintf ("ptr=%d\n") ; call pargi (O_VALP(o))
+ }
+ call flush (STDERR)
+end
diff --git a/pkg/dataio/fits/fits_cards.x b/pkg/dataio/fits/fits_cards.x
new file mode 100644
index 00000000..0ddfa230
--- /dev/null
+++ b/pkg/dataio/fits/fits_cards.x
@@ -0,0 +1,292 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include "wfits.h"
+
+# WFT_STANDARD_CARD -- Procedure for fetching the minimum header
+# parameters required by fits. The end card is encoded separately.
+
+int procedure wft_standard_card (cardno, im, fits, axisno, card)
+
+int cardno # number of FITS standard card
+pointer im # pointer to the IRAF image
+pointer fits # pointer to the FITS structure
+int axisno # axis number
+char card[ARB] # FITS card image
+
+char keyword[LEN_KEYWORD]
+int len_object
+int strlen()
+errchk wft_encodeb, wft_encodei, wft_encodel, wft_encode_axis
+
+begin
+ # Get mandatory keywords.
+ switch (cardno) {
+ case FIRST_CARD:
+ if (XTENSION(fits) == EXT_PRIMARY) {
+ call wft_encodeb ("SIMPLE", YES, card, "FITS STANDARD")
+ } else {
+ len_object = max (min (LEN_OBJECT, strlen ("IMAGE")),
+ LEN_STRING)
+ call wft_encodec ("XTENSION", "IMAGE", len_object, card,
+ "IMAGE EXTENSION")
+ }
+ case SECOND_CARD:
+ call wft_encodei ("BITPIX", FITS_BITPIX(fits), card,
+ "FITS BITS/PIXEL")
+ case THIRD_CARD:
+ call wft_encodei ("NAXIS", NAXIS(im), card, "NUMBER OF AXES")
+ default:
+ call wft_encode_axis ("NAXIS", keyword, axisno)
+ call wft_encodel (keyword, NAXISN(im, axisno), card, "")
+ axisno = axisno + 1
+ }
+
+ return (YES)
+end
+
+
+# WFT_OPTION_CARD -- Procedure for fetching optional FITS header parameters.
+# At present these are bscale, bzero, bunit, blank, object, origin, date,
+# irafmax, irafmin, iraf type and iraf bits per pixel. Blank is only encoded
+# if there are a nonzero number of blanks in the IRAF image. Bunit and object
+# are only encoded if the appropriate IRAF strings are defined. Bzero, bscale,
+# irafmax, irafmin, iraf type and iraf bits per pixel are only encoded if
+# there is a pixel file.
+
+int procedure wft_option_card (im, fits, optiono, card)
+
+pointer im # pointer to the IRAF image
+pointer fits # pointer to FITS structure
+int optiono # number of the option card
+char card[ARB] # FITS card image
+
+char datestr[LEN_DATE]
+int len_object, stat
+int strlen()
+errchk wft_encoded, wft_encodec, wft_encode_blank, wft_encoder, wft_encodei
+errchk wft_encode_date
+include "wfits.com"
+
+begin
+ stat = YES
+
+ # get optional keywords
+ switch (optiono) {
+ case KEY_EXTEND:
+ if (XTENSION(fits) == EXT_IMAGE || wextensions == NO)
+ stat = NO
+ else
+ call wft_encodeb ("EXTEND", YES, card,
+ "STANDARD EXTENSIONS MAY BE PRESENT")
+ case KEY_PCOUNT:
+ if (XTENSION(fits) == EXT_PRIMARY)
+ stat = NO
+ else
+ call wft_encodei ("PCOUNT", 0, card, "NO RANDOM PARAMETERS")
+ case KEY_GCOUNT:
+ if (XTENSION(fits) == EXT_PRIMARY)
+ stat = NO
+ else
+ call wft_encodei ("GCOUNT", 1, card, "ONLY ONE GROUP")
+ case KEY_BSCALE:
+ if ((NAXIS(im) <= 0) || (FITS_BITPIX(fits) < 0))
+ stat = NO
+ else {
+ call wft_encoded ("BSCALE", BSCALE(fits), card,
+ "REAL = TAPE*BSCALE + BZERO", NDEC_DOUBLE)
+ }
+ case KEY_BZERO:
+ if ((NAXIS(im) <= 0) || (FITS_BITPIX(fits) < 0))
+ stat = NO
+ else
+ call wft_encoded ("BZERO", BZERO(fits), card, "", NDEC_DOUBLE)
+ case KEY_BUNIT:
+ stat = NO
+ case KEY_BLANK:
+ stat = NO
+ #if (NBPIX(im) == 0)
+ #stat = NO
+ #else
+ #call wft_encode_blank ("BLANK", BLANK_STRING(fits), card,
+ #"TAPE VALUE OF BLANK PIXEL")
+ case KEY_OBJECT:
+ if (OBJECT(im) == EOS)
+ stat = NO
+ else {
+ len_object = max (min (LEN_OBJECT, strlen (OBJECT(im))),
+ LEN_STRING)
+ call wft_encodec ("OBJECT", OBJECT(im), len_object, card, "")
+ }
+ case KEY_ORIGIN:
+ call wft_encodec ("ORIGIN", "KPNO-IRAF", LEN_ORIGIN, card, "")
+ case KEY_DATE:
+ call wft_encode_date (datestr, LEN_DATE)
+ len_object = max (min (LEN_OBJECT, strlen (datestr)), LEN_STRING)
+ call wft_encodec ("DATE", datestr, len_object, card, "")
+ case KEY_IRAFNAME:
+ len_object = max (min (LEN_OBJECT, strlen (IRAFNAME(fits))),
+ LEN_STRING)
+ call wft_encodec ("IRAFNAME", IRAFNAME(fits), len_object, card,
+ "NAME OF IRAF IMAGE FILE")
+ case KEY_IRAFMAX:
+ if (NAXIS(im) <= 0)
+ stat = NO
+ else
+ call wft_encoder ("IRAF-MAX", IRAFMAX(fits), card, "DATA MAX",
+ NDEC_REAL)
+ case KEY_IRAFMIN:
+ if (NAXIS(im) <= 0)
+ stat = NO
+ else
+ call wft_encoder ("IRAF-MIN", IRAFMIN(fits), card, "DATA MIN",
+ NDEC_REAL)
+ case KEY_IRAFBP:
+ if (NAXIS(im) <= 0)
+ stat = NO
+ else
+ call wft_encodei ("IRAF-BPX", DATA_BITPIX(fits), card,
+ "DATA BITS/PIXEL")
+ case KEY_IRAFTYPE:
+ if (NAXIS(im) <= 0)
+ stat = NO
+ else
+ call wft_encodec ("IRAFTYPE", TYPE_STRING(fits), LEN_STRING,
+ card, "PIXEL TYPE")
+ default:
+ stat = NO
+ }
+
+ optiono = optiono + 1
+
+ return (stat)
+end
+
+
+# WFT_HISTORY_CARD -- Procedure to fetch a single history line, trim newlines
+# and pad with blanks to size LEN_CARD in order to create a FITS HISTORY card.
+
+int procedure wft_history_card (im, hp, card)
+
+pointer im # pointer to the IRAF image
+int hp # pointer to first character to extract from string
+char card[ARB] # FITS card image
+
+char cval
+char chfetch()
+
+begin
+ if (chfetch (HISTORY(im), hp, cval) == EOS)
+ return (NO)
+ else {
+ hp = hp - 1
+ call strcpy ("HISTORY ", card, LEN_KEYWORD)
+ call wft_fits_card (HISTORY(im), hp, card, COL_VALUE - 2, LEN_CARD,
+ '\n')
+ return (YES)
+ }
+end
+
+
+# WFT_UNKNOWN_CARD -- Procedure to fetch a single unknown
+# "line", trim newlines and pad blanks to size LEN_CARD in order to
+# create an unknown keyword card. At present user area information is
+# assumed to be in the form of FITS card images, less then or equal to
+# 80 characters and delimited by a newline.
+
+int procedure wft_unknown_card (im, up, card)
+
+pointer im # pointer to the IRAF image
+int up # pointer to next character in the unknown string
+char card[ARB] # FITS card image
+
+char cval
+int stat, axis, index
+char chfetch()
+int strmatch(), ctoi()
+
+begin
+ if (chfetch (UNKNOWN(im), up, cval) == EOS)
+ return (NO)
+ else {
+ up = up - 1
+ stat = NO
+ while (stat == NO) {
+ call wft_fits_card (UNKNOWN(im), up, card, 1, LEN_CARD, '\n')
+ if (card[1] == EOS)
+ break
+ if (strmatch (card, "^GROUPS ") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^SIMPLE ") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^BITPIX ") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^NAXIS ") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^NAXIS") != 0) {
+ index = LEN_NAXIS_KYWRD + 1
+ if (ctoi (card, index, axis) > 0)
+ stat = NO
+ else
+ stat = YES
+ } else if (strmatch (card, "^GCOUNT ") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^PCOUNT ") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^PSIZE ") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^BSCALE ") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^BZERO ") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^BLANK ") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^IRAF-MAX") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^IRAF-MIN") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^IRAFTYPE") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^IRAF-B/P") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^IRAF-BPX") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^FILENAME") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^IRAFNAME") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^EXTEND ") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^EXTNAME ") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^EXTVER ") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^INHERIT ") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^IRAF-TLM") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^OBJECT ") != 0) {
+ stat = NO
+ } else if (strmatch (card, "^END ") != 0) {
+ stat = NO
+ } else
+ stat = YES
+ }
+
+ return (stat)
+ }
+end
+
+
+# WFT_LAST_CARD -- Procedure to encode the FITS end card.
+
+int procedure wft_last_card (card)
+
+char card[ARB] # FITS card image
+
+begin
+ call sprintf (card, LEN_CARD, "%-8.8s %70w")
+ call pargstr ("END")
+
+ return (YES)
+end
diff --git a/pkg/dataio/fits/fits_files.x b/pkg/dataio/fits/fits_files.x
new file mode 100644
index 00000000..ce2c553c
--- /dev/null
+++ b/pkg/dataio/fits/fits_files.x
@@ -0,0 +1,374 @@
+include <ctype.h>
+include <plset.h>
+
+define DEF_MAXNCOLS 1000
+define DEF_MAXNLINES 4096
+define MAX_NRANGES 100
+
+
+# RFT_FLIST -- Decode a list of files and associated extensions into a pixel
+# list.
+
+pointer procedure rft_flist (file_list, first_file, last_file, nfiles)
+
+char file_list[ARB] # the input file list string
+int first_file # the first file in the list
+int last_file # the last file in the list
+int nfiles # the number of files in the list
+
+int i, j, maxncols, maxnlines, nrfiles, rp, rbegin, rend, rstep
+int last_ext, ebegin, eend, estep, ep, nefiles
+pointer sp, extensions, str, axes, pl
+
+bool pl_linenotempty()
+int rft_gfranges()
+pointer pl_create()
+
+begin
+ # Allocate some working space.
+ call smark (sp)
+ call salloc (extensions, SZ_LINE, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call salloc (axes, 2, TY_INT)
+
+ # Initialize the file list.
+ pl = NULL
+ maxncols = DEF_MAXNCOLS
+ maxnlines = DEF_MAXNLINES
+
+ repeat {
+
+ # Initialize the file counter parameters.
+ first_file = INDEFI
+ last_file = INDEFI
+ nfiles = 0
+ rp = 1
+
+ # Open the file list.
+ Memi[axes] = maxncols
+ Memi[axes+1] = maxnlines
+ pl = pl_create (2, Memi[axes], 1)
+
+ # Decode the file list.
+ nrfiles = rft_gfranges (file_list, rp, YES, maxnlines, rbegin,
+ rend, rstep, NO, Memc[extensions])
+ while (nrfiles > 0) {
+
+ # Check the file number limits and terminate the loop if
+ # the current list size is exceeded.
+ if (IS_INDEFI(first_file))
+ first_file = rbegin
+ else
+ first_file = min (rbegin, first_file)
+ if (IS_INDEFI(last_file))
+ last_file = rend
+ else
+ last_file = max (last_file, rend)
+ if (last_file > maxnlines)
+ break
+
+ # Initialize the extensions list decoding.
+ ep = 1
+ last_ext = INDEFI
+
+ # Decode the associated extensions files. If the extensions
+ # list is empty
+ nefiles = rft_gfranges (Memc[extensions], ep, YES, maxncols,
+ ebegin, eend, estep, YES, Memc[str])
+ while (nefiles > 0) {
+
+ # Check the extensions number limits and quit if they
+ # are exceeded.
+ if (IS_INDEFI(last_ext))
+ last_ext = eend
+ else
+ last_ext = max (last_ext, eend)
+ if (last_ext > maxncols)
+ break
+
+ # Set the appropriate elements in the list.
+ if (rstep == 1) {
+ if (estep == 1)
+ call pl_box (pl, ebegin, rbegin, eend,
+ rend, PIX_SET + PIX_VALUE(1))
+ else {
+ do i = ebegin, eend, estep
+ call pl_box (pl, i, rbegin, i, rend,
+ PIX_SET + PIX_VALUE(1))
+ }
+ } else {
+ do i = rbegin, rend, rstep {
+ do j = ebegin, eend, estep
+ call pl_point (pl, j, i, PIX_SET +
+ PIX_VALUE(1))
+ }
+ }
+
+ nefiles = rft_gfranges (Memc[extensions], ep, NO, maxncols,
+ ebegin, eend, estep, YES, Memc[str])
+ }
+
+ # Break if an extensions list decode error occurs.
+ if (nefiles == 0)
+ break
+
+ nrfiles = rft_gfranges (file_list, rp, NO, maxnlines, rbegin,
+ rend, rstep, NO, Memc[extensions])
+ }
+
+ # Break if a file or extensions list decode error ocurred.
+ if (nrfiles == 0 || nefiles == 0)
+ break
+
+ # If the file or extensions list is larger than the current maximum
+ # then free the list increase the default space and repeat the
+ # procedure.
+
+ if (!IS_INDEFI(last_file)) {
+ if (last_file > maxnlines) {
+ if (pl != NULL)
+ call pl_close (pl)
+ pl = NULL
+ maxnlines = maxnlines + DEF_MAXNLINES
+ } else {
+ do i = first_file, last_file {
+ Memi[axes] = 1
+ Memi[axes+1] = i
+ if (pl_linenotempty (pl, Memi[axes]))
+ nfiles = nfiles + 1
+ }
+ }
+ }
+
+ if (!IS_INDEFI(last_ext)) {
+ if (last_ext > maxncols) {
+ if (pl != NULL)
+ call pl_close (pl)
+ pl = NULL
+ maxncols = maxncols + DEF_MAXNCOLS
+ }
+ }
+
+ } until (pl != NULL)
+
+ # Free space.
+ call sfree (sp)
+
+ # If the file list is empty or a decode error occurred return
+ # a NULL list, otherwise return the pointer to the list.
+
+ if (nfiles <= 0 || nrfiles == 0 || nefiles == 0) {
+ nfiles = 0
+ first_file = INDEFI
+ last_file = INDEFI
+ call pl_close (pl)
+ return (NULL)
+ } else
+ return (pl)
+end
+
+
+# RFT_GFRANGES -- Parse a string containing a list of integer numbers or
+# ranges, delimited by either spaces or commas. Each range may have an
+# associated extensions lists delimited by square brackets. Return as output
+# each range in sequence. Range limits must be positive nonnegative integers.
+# EOF is returned if the end of the file_list is reached. 0 is returned if a
+# conversion error takes place. Otherwise the number of elements in the
+# range is returned.
+
+int procedure rft_gfranges (range_string, ip, firstr, rmax, rbegin, rend,
+ rstep, zeroindex, extensions)
+
+char range_string[ARB] # range string to be decoded
+int ip # the range string pointer
+int firstr # first range to be returned
+int rmax # the maximum file number
+int rbegin # the begining of the range
+int rend # the end of the range
+int rstep # the range step size
+int zeroindex # allow zero indexing ?
+char extensions[ARB] # the output extensions string
+
+int ep, itemp
+int ctoi()
+
+begin
+ # Initialize.
+ if (zeroindex == YES) {
+ rbegin = 0
+ rend = rmax - 1
+ } else {
+ rbegin = 1
+ rend = rmax
+ }
+ rstep = 1
+ extensions[1] = EOS
+
+ # Return default range if the range string is NULL.
+ if (range_string[ip] == EOS) {
+ rbegin = 1
+ rend = rmax
+ if (firstr == YES)
+ return (rend)
+ else
+ return (EOF)
+ }
+
+ # Skip delimiters
+ while (IS_WHITE(range_string[ip]) || range_string[ip] == ',')
+ ip = ip + 1
+
+ # Get first limit.
+ # Must be a number, '-', 'x', *, or EOS.
+ if (range_string[ip] == EOS) { # end of list
+ rbegin = 1
+ rend = rmax
+ if (firstr == YES)
+ return (rend)
+ else
+ return (EOF)
+ } else if (range_string[ip] == '*') {
+ ;
+ } else if (range_string[ip] == '-') {
+ ;
+ } else if (range_string[ip] == 'x') {
+ ;
+ } else if (IS_DIGIT(range_string[ip])) { # ,n..
+ if (ctoi (range_string, ip, rbegin) == 0)
+ return (0)
+ else if (zeroindex == NO) {
+ if (rbegin <= 0)
+ return (0)
+ } else {
+ if (rbegin < 0)
+ return (0)
+ }
+ } else
+ return (0)
+
+ # Extract extensions file list.
+ if (range_string[ip] == '[') {
+ ip = ip + 1
+ ep = 1
+ while (range_string[ip] != EOS) {
+ if (range_string[ip] == ']') {
+ ip = ip + 1
+ break
+ }
+ extensions[ep] = range_string[ip]
+ ip = ip + 1
+ ep = ep + 1
+ }
+ extensions[ep] = EOS
+ if (range_string[ip-1] != ']')
+ return (0)
+ }
+
+ # Skip delimiters
+ while (IS_WHITE(range_string[ip]) || range_string[ip] == ',')
+ ip = ip + 1
+
+ # Get last limit
+ # Must be '-', 'x', or '*' otherwise last = first.
+ if (range_string[ip] == '*')
+ ;
+ else if (range_string[ip] == 'x')
+ ;
+ else if (range_string[ip] == '-') {
+ ip = ip + 1
+ while (IS_WHITE(range_string[ip]) || range_string[ip] == ',')
+ ip = ip + 1
+ if (range_string[ip] == EOS)
+ ;
+ else if (IS_DIGIT(range_string[ip])) {
+ if (ctoi (range_string, ip, rend) == 0)
+ return (0)
+ else if (zeroindex == NO) {
+ if (rend <= 0)
+ return (0)
+ } else {
+ if (rend < 0)
+ return (0)
+ }
+ } else if (range_string[ip] == 'x')
+ ;
+ else
+ return (0)
+ } else
+ rend = rbegin
+
+ # Skip extensions files for now.
+ if (range_string[ip] == '[') {
+ ip = ip + 1
+ ep = 1
+ while (range_string[ip] != EOS) {
+ if (range_string[ip] == ']') {
+ ip = ip + 1
+ break
+ }
+ extensions[ep] = range_string[ip]
+ ip = ip + 1
+ ep = ep + 1
+ }
+ extensions[ep] = EOS
+ if (range_string[ip-1] != ']')
+ return (0)
+ }
+
+ # Skip delimiters
+ while (IS_WHITE(range_string[ip]) || range_string[ip] == ',')
+ ip = ip + 1
+
+ # Get step.
+ # Must be 'x' or assume default step.
+ if (range_string[ip] == '*')
+ ip = ip + 1
+ else if (range_string[ip] == 'x') {
+ ip = ip + 1
+ while (IS_WHITE(range_string[ip]) || range_string[ip] == ',')
+ ip = ip + 1
+ if (range_string[ip] == EOS)
+ ;
+ else if (IS_DIGIT(range_string[ip])) {
+ if (ctoi (range_string, ip, rstep) == 0)
+ ;
+ else if (rstep <= 0)
+ return (0)
+ } else if (range_string[ip] == '-')
+ ;
+ else
+ return (0)
+ }
+
+ # Skip extensions files for now.
+ if (range_string[ip] == '[') {
+ ip = ip + 1
+ ep = 1
+ while (range_string[ip] != EOS) {
+ if (range_string[ip] == ']') {
+ ip = ip + 1
+ break
+ }
+ extensions[ep] = range_string[ip]
+ ip = ip + 1
+ ep = ep + 1
+ }
+ extensions[ep] = EOS
+ if (range_string[ip-1] != ']')
+ return (0)
+ }
+
+ # Output the range triple.
+ if (rend < rbegin) {
+ itemp = rbegin
+ rbegin = rend
+ rend = itemp
+ }
+ if (zeroindex == YES) {
+ rbegin = rbegin + 1
+ rend = rend + 1
+ }
+ return (abs (rend - rbegin) / rstep + 1 )
+end
+
+
diff --git a/pkg/dataio/fits/fits_params.x b/pkg/dataio/fits/fits_params.x
new file mode 100644
index 00000000..6911a925
--- /dev/null
+++ b/pkg/dataio/fits/fits_params.x
@@ -0,0 +1,248 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <time.h>
+include "wfits.h"
+
+# WFT_ENCODEB -- Procedure to encode a boolean parameter into a FITS card.
+
+procedure wft_encodeb (keyword, param, card, comment)
+
+char keyword[ARB] # FITS keyword
+int param # integer parameter equal to YES/NO
+char card[ARB] # FITS card image
+char comment[ARB] # FITS comment string
+
+char truth
+
+begin
+ if (param == YES)
+ truth = 'T'
+ else
+ truth = 'F'
+
+ call sprintf (card, LEN_CARD, "%-8.8s= %20c / %-45.45s")
+ call pargstr (keyword)
+ call pargc (truth)
+ call pargstr (comment)
+end
+
+
+# WFT_ENCODEI -- Procedure to encode an integer parameter into a FITS card.
+
+procedure wft_encodei (keyword, param, card, comment)
+
+char keyword[ARB] # FITS keyword
+int param # integer parameter
+char card[ARB] # FITS card image
+char comment[ARB] # FITS comment string
+
+begin
+ call sprintf (card, LEN_CARD, "%-8.8s= %20d / %-45.45s")
+ call pargstr (keyword)
+ call pargi (param)
+ call pargstr (comment)
+end
+
+
+# WFT_ENCODEL -- Procedure to encode a long parameter into a FITS card.
+
+procedure wft_encodel (keyword, param, card, comment)
+
+char keyword[ARB] # FITS keyword
+long param # long integer parameter
+char card[ARB] # FITS card image
+char comment[ARB] # FITS comment string
+
+begin
+ call sprintf (card, LEN_CARD, "%-8.8s= %20d / %-45.45s")
+ call pargstr (keyword)
+ call pargl (param)
+ call pargstr (comment)
+end
+
+
+# WFT_ENCODER -- Procedure to encode a real parameter into a FITS card.
+
+procedure wft_encoder (keyword, param, card, comment, precision)
+
+char keyword[ARB] # FITS keyword
+real param # real parameter
+char card[ARB] # FITS card image
+char comment[ARB] # FITS comment card
+int precision # precision of real
+
+begin
+ call sprintf (card, LEN_CARD, "%-8.8s= %20.*e / %-45.45s")
+ call pargstr (keyword)
+ call pargi (precision)
+ call pargr (param)
+ call pargstr (comment)
+end
+
+
+# WFT_ENCODED -- Procedure to encode a double parameter into a FITS card.
+
+procedure wft_encoded (keyword, param, card, comment, precision)
+
+char keyword[ARB] # FITS keyword
+double param # double parameter
+char card[ARB] # FITS card image
+char comment[ARB] # FITS comment string
+int precision # FITS precision
+
+begin
+ call sprintf (card, LEN_CARD, "%-8.8s= %20.*e / %-45.45s")
+ call pargstr (keyword)
+ call pargi (precision)
+ call pargd (param)
+ call pargstr (comment)
+end
+
+
+# WFT_ENCODE_AXIS -- Procedure to add the axis number to axis dependent
+# keywords.
+
+procedure wft_encode_axis (root, keyword, axisno)
+
+char root[ARB] # FITS root keyword
+char keyword[ARB] # FITS keyword
+int axisno # FITS axis number
+
+begin
+ call strcpy (root, keyword, LEN_KEYWORD)
+ call sprintf (keyword, LEN_KEYWORD, "%-5.5s%-3.3s")
+ call pargstr (root)
+ call pargi (axisno)
+end
+
+
+# WFT_ENCODEC -- Procedure to encode an IRAF string parameter into a FITS card.
+
+procedure wft_encodec (keyword, param, maxch, card, comment)
+
+char keyword[ARB] # FITS keyword
+char param[ARB] # FITS string parameter
+int maxch # maximum number of characters in string parameter
+char card[ARB] # FITS card image
+char comment[ARB] # comment string
+
+char strparam[LEN_ALIGN+2]
+int maxchar, nblanks
+
+begin
+ maxchar = min (maxch, LEN_OBJECT)
+ if (maxchar <= LEN_ALIGN - 1) {
+ strparam[1] = '\''
+ call sprintf (strparam[2], maxchar, "%*.*s")
+ call pargi (-maxchar)
+ call pargi (maxchar)
+ call pargstr (param)
+ strparam[maxchar+2] = '\''
+ strparam[maxchar+3] = EOS
+ call sprintf (card, LEN_CARD, "%-8.8s= %-20.20s / %-45.45s")
+ call pargstr (keyword)
+ call pargstr (strparam)
+ call pargstr (comment)
+ } else {
+ nblanks = LEN_OBJECT - maxchar
+ if (comment[1] == EOS)
+ call sprintf (card, LEN_CARD, "%-8.8s= '%*.*s' %*.*s")
+ else
+ call sprintf (card, LEN_CARD, "%-8.8s= '%*.*s' / %*.*s")
+ call pargstr (keyword)
+ call pargi (-maxchar)
+ call pargi (maxchar)
+ call pargstr (param)
+ call pargi (-nblanks)
+ call pargi (nblanks)
+ call pargstr (comment)
+ }
+end
+
+
+# WFT_ENCODE_BLANK -- Procedure to encode the FITS blank parameter. Necessary
+# because the 32 bit blank value equals INDEFL.
+
+procedure wft_encode_blank (keyword, blank_str, card, comment)
+
+char keyword[ARB] # FITS keyword
+char blank_str[ARB] # string containing values of FITS blank integer
+char card[ARB] # FITS card image
+char comment[ARB] # FITS comment string
+
+begin
+ call sprintf (card, LEN_CARD, "%-8.8s= %20.20s / %-45.45s")
+ call pargstr (keyword)
+ call pargstr (blank_str)
+ call pargstr (comment)
+end
+
+
+# WFT_ENCODE_DATE -- Procedure to encode the date in the form dd-mm-yy.
+
+procedure wft_encode_date (datestr, szdate)
+
+char datestr[ARB] # string containing the date
+int szdate # number of chars in the date string
+
+long ctime
+int time[LEN_TMSTRUCT]
+long clktime(), lsttogmt()
+
+begin
+ ctime = clktime (long (0))
+ ctime = lsttogmt (ctime)
+ call brktime (ctime, time)
+
+ if (TM_YEAR(time) >= NEW_CENTURY) {
+ call sprintf (datestr, szdate, "%04d-%02d-%02dT%02d:%02d:%02d")
+ call pargi (TM_YEAR(time))
+ call pargi (TM_MONTH(time))
+ call pargi (TM_MDAY(time))
+ call pargi (TM_HOUR(time))
+ call pargi (TM_MIN(time))
+ call pargi (TM_SEC(time))
+ } else {
+ call sprintf (datestr, szdate, "%02d-%02d-%02d")
+ call pargi (TM_MDAY(time))
+ call pargi (TM_MONTH(time))
+ call pargi (mod (TM_YEAR(time), CENTURY))
+ }
+end
+
+
+# WFT_FITS_CARD -- Procedure to fetch a single line from a string parameter
+# padding it to a maximum of maxcols characters and trimmimg the delim
+# character.
+
+procedure wft_fits_card (instr, ip, card, col_out, maxcols, delim)
+
+char instr[ARB] # input string
+int ip # input string pointer, updated at each call
+char card[ARB] # FITS card image
+int col_out # pointer to column in card
+int maxcols # maximum columns in card
+int delim # 1 character string delimiter
+
+int op
+
+begin
+ op = col_out
+
+ # Copy string
+ while (op <= maxcols && instr[ip] != EOS && instr[ip] != delim) {
+ card[op] = instr[ip]
+ ip = ip + 1
+ op = op + 1
+ }
+
+ # Fill remainder of card with blanks
+ while (op <= maxcols ) {
+ card[op] = ' '
+ op = op + 1
+ }
+
+ if (instr[ip] == delim)
+ ip = ip + 1
+
+end
diff --git a/pkg/dataio/fits/fits_read.x b/pkg/dataio/fits/fits_read.x
new file mode 100644
index 00000000..f9b0e46c
--- /dev/null
+++ b/pkg/dataio/fits/fits_read.x
@@ -0,0 +1,469 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <error.h>
+include <imhdr.h>
+include <fset.h>
+include <plset.h>
+include "rfits.h"
+
+define MAX_RANGES 100 # the maximum number of ranges
+
+# RFT_READ_FITZ -- Convert a FITS file. An EOT is signalled by returning EOF.
+
+int procedure rft_read_fitz (fitsfile, iraffile, pl, file_number)
+
+char fitsfile[ARB] # FITS file name
+char iraffile[ARB] # root IRAF file name
+pointer pl # pointer to the file/extensions list
+int file_number # the current file number
+
+bool strne()
+int fits_fd, stat, min_lenuserarea, ip, len_elist, oshort_header
+int olong_header, ext_count, ext_number, max_extensions, naxes
+pointer im, gim, sp, fits, axes, extensions, imname, gimname, gfname, str
+pointer himname
+int rft_read_header(), mtopen(), immap(), strlen(), envfind(), ctoi()
+int rft_ext_skip()
+real asumi()
+errchk smark, sfree, salloc, rft_read_header, rft_read_image, rft_find_eof()
+errchk rft_scan_file, mtopen, immap, imdelete, close, imunmap
+
+include "rfits.com"
+
+begin
+ # Open input FITS data.
+ fits_fd = mtopen (fitsfile, READ_ONLY, 0)
+
+ # Allocate memory for the FITS data structure and initialize the file
+ # dependent components of that structure.
+ call smark (sp)
+ call salloc (fits, LEN_FITS, TY_STRUCT)
+ call salloc (imname, SZ_FNAME, TY_CHAR)
+ call salloc (himname, SZ_FNAME, TY_CHAR)
+ call salloc (gimname, SZ_FNAME, TY_CHAR)
+ call salloc (gfname, SZ_FNAME, TY_CHAR)
+ call salloc (str, SZ_FNAME, TY_CHAR)
+
+ # Initialize.
+ SIMPLE(fits) = NO
+ EXTEND(fits) = NO
+ GLOBALHDR(fits) = NO
+ gim = NULL
+ Memc[gfname] = EOS
+
+ # Determine the length of the user area.
+ if (envfind ("min_lenuserarea", Memc[imname], SZ_FNAME) > 0) {
+ ip = 1
+ if (ctoi (Memc[imname], ip, min_lenuserarea) <= 0)
+ min_lenuserarea = LEN_USERAREA
+ else
+ min_lenuserarea = max (LEN_USERAREA, min_lenuserarea)
+ } else
+ min_lenuserarea = LEN_USERAREA
+
+ # Store the current values of the header printing options.
+ olong_header = long_header
+ oshort_header = short_header
+
+ # Get the extensions list for a given line and count the number of
+ # extensions files.
+ call salloc (axes, 2, TY_INT)
+ call pl_gsize (pl, naxes, Memi[axes], stat)
+ max_extensions = Memi[axes+1]
+ call salloc (extensions, max_extensions, TY_INT)
+ Memi[axes] = 1
+ Memi[axes+1] = file_number
+ call pl_glpi (pl, Memi[axes], Memi[extensions], 1, max_extensions,
+ PIX_SRC)
+ len_elist = nint (asumi (Memi[extensions], max_extensions))
+
+ # Loop over the extensions.
+ ext_count = 1; stat = BOF
+ do ext_number = 1, max_extensions {
+
+ if (stat == EOF)
+ break
+ if (Memi[extensions+ext_number-1] == 0)
+ next
+
+ # Locate the next extension to be read.
+ while (ext_count <= ext_number) {
+
+ # Create the IRAF image header. If only a header listing is
+ # desired or the image extension is to be skipped then map
+ # the scratch image onto DEV$NULL (faster than a real file).
+ # If more than one extension is to be read then append the
+ # extension number to the input name.
+
+ if (make_image == NO || ext_count != ext_number) {
+ call strcpy ("dev$null", Memc[imname], SZ_FNAME)
+ } else if (len_elist > 1 && ext_count == ext_number) {
+ call sprintf (Memc[imname], SZ_FNAME, "%s%04d")
+ call pargstr (iraffile)
+ call pargi (ext_number - 1)
+ } else
+ call strcpy (iraffile, Memc[imname], SZ_FNAME)
+ im = immap (Memc[imname], NEW_IMAGE, min_lenuserarea)
+ call strcpy (IM_HDRFILE(im), Memc[himname], SZ_FNAME)
+
+ # Skip any extensions the user does not want. In order to do
+ # this we must read the header to see how big the data array
+ # to be skipped is.
+ if (ext_count != ext_number) {
+
+ # Turn off header printing.
+ long_header = NO
+ short_header = NO
+
+ # Decode the header and skip the data.
+ iferr {
+ stat = rft_read_header (fits_fd, fits, im, gim)
+ if (stat != EOF)
+ stat = rft_ext_skip (fits_fd, fits, im)
+ if (stat == EOF) {
+ if (ext_count == 1) {
+ call printf ("File: %s\n")
+ call pargstr (fitsfile)
+ } else if (asumi(Memi[extensions],
+ ext_count - 1) < 1.0) {
+ call printf ("File: %s\n")
+ call pargstr (fitsfile)
+ }
+ if (ext_count > 1) {
+ call printf ("Extension: %d End of data\n")
+ call pargi (ext_count - 1)
+ } else
+ call printf (" End of data\n")
+ } else if (EXTEND(fits) == NO) {
+ call printf ("File: %s\n")
+ call pargstr (fitsfile)
+ call printf ("Extension: 1 End of data\n")
+ }
+ } then {
+ call flush (STDOUT)
+ call erract (EA_WARN)
+ }
+
+ # Restore the default header printing values.
+ long_header = olong_header
+ short_header = oshort_header
+
+ # Read the extension the user specified. If the extension
+ # is not the primary data or IMAGE skip the data and
+ # continue.
+ } else {
+
+ # Set up for printing a long or a short header.
+ if (long_header == YES || short_header == YES) {
+ if (long_header == YES) {
+ if (ext_number == 1) {
+ if (make_image == YES) {
+ call printf ("File: %s Image: %s")
+ call pargstr (fitsfile)
+ #call pargstr (Memc[imname])
+ call pargstr (Memc[himname])
+ } else {
+ call printf ("File: %s")
+ call pargstr (fitsfile)
+ }
+ } else if (asumi (Memi[extensions],
+ ext_number -1) < 1.0) {
+ if (make_image == YES) {
+ call printf (
+ "File: %s\nExtension: %d Image: %s")
+ call pargstr (fitsfile)
+ call pargi (ext_number - 1)
+ #call pargstr (Memc[imname])
+ call pargstr (Memc[himname])
+ } else {
+ call printf ("File: %s Extension: %d")
+ call pargstr (fitsfile)
+ call pargi (ext_number - 1)
+ }
+ } else {
+ if (make_image == YES) {
+ call printf ("Extension: %d Image: %s")
+ call pargi (ext_number - 1)
+ #call pargstr (Memc[imname])
+ call pargstr (Memc[himname])
+ } else {
+ call printf ("File: %s Extension: %d")
+ call pargstr (fitsfile)
+ call pargi (ext_number - 1)
+ }
+ }
+ } else {
+ if (ext_number == 1) {
+ call printf ("File: %s ")
+ call pargstr (fitsfile)
+ } else if (asumi (Memi[extensions],
+ ext_number - 1) < 1.0) {
+ call printf ("File: %s\nExtension: %d ")
+ call pargstr (fitsfile)
+ call pargi (ext_number - 1)
+ } else {
+ call printf ("Extension: %d ")
+ call pargi (ext_number - 1)
+ }
+ }
+ if (long_header == YES)
+ call printf ("\n")
+ }
+ call flush (STDOUT)
+
+ # Read header. EOT is signalled by an EOF status from
+ # fits_read_header. Create an IRAF image if desired.
+
+ iferr {
+ stat = rft_read_header (fits_fd, fits, im, gim)
+ if (stat == EOF) {
+ call printf ("End of data\n")
+ } else if (make_image == YES) {
+ if (XTENSION(fits) == EXT_PRIMARY ||
+ XTENSION(fits) == EXT_IMAGE) {
+ call rft_read_image (fits_fd, fits, im)
+ } else if (EXTEND(fits) == YES) {
+ stat = rft_ext_skip (fits_fd, fits, im)
+ if (stat == EOF)
+ call printf ("End of data\n")
+ } else if (EXTEND(fits) == NO && fe > 0.0) {
+ call rft_find_eof (fits_fd)
+ }
+ } else {
+ if (EXTEND(fits) == YES) {
+ stat = rft_ext_skip (fits_fd, fits, im)
+ if (stat == EOF)
+ call printf ("End of data\n")
+ } else if (EXTEND(fits) == NO && fe > 0.0)
+ call rft_scan_file (fits_fd, fits, im, fe)
+ }
+ } then {
+ call flush (STDOUT)
+ call erract (EA_WARN)
+ }
+ }
+
+
+ # Deal with the global header issue. Save the global header
+ # file name for possible future use.
+ if (GLOBALHDR(fits) == YES) {
+ if (gim == NULL && XTENSION(fits) == EXT_PRIMARY) {
+ call mktemp ("tmp$", Memc[gimname], SZ_FNAME)
+ gim = immap (Memc[gimname], NEW_COPY, im)
+ call strcpy (IRAFNAME(fits), Memc[gfname], SZ_FNAME)
+ } else if (IRAFNAME(fits) == EOS)
+ call strcpy (Memc[gfname], IRAFNAME(fits), SZ_FNAME)
+
+ }
+
+ # Close the output image.
+ call imunmap (im)
+
+ # Optionally restore the old IRAF name.
+ if (stat == EOF) {
+ call imdelete (Memc[imname])
+ break
+ } else if (make_image == NO || ext_number != ext_count) {
+ call imdelete (Memc[imname])
+ } else if (XTENSION(fits) != EXT_PRIMARY && XTENSION(fits) !=
+ EXT_IMAGE) {
+ call imdelete (Memc[imname])
+ if (XTENSION(fits) != EXT_SPECIAL && ext_count ==
+ ext_number)
+ call printf (" Skipping non-image data\n")
+ } else if (old_name == YES && strlen (IRAFNAME(fits)) != 0) {
+ iferr {
+ call imgimage (IRAFNAME(fits), IRAFNAME(fits), SZ_FNAME)
+ call imrename (Memc[imname], IRAFNAME(fits))
+ } then {
+ if (len_elist > 1) {
+ call sprintf (Memc[str], SZ_FNAME, ".%d")
+ call pargi (ext_number - 1)
+ call strcat (Memc[str], IRAFNAME(fits), SZ_FNAME)
+ iferr (call imrename (Memc[imname],
+ IRAFNAME(fits))) {
+ call printf (
+ " Cannot rename image %s to %s\n")
+ #call pargstr (Memc[imname])
+ call pargstr (Memc[himname])
+ call pargstr (IRAFNAME(fits))
+ call flush (STDOUT)
+ call erract (EA_WARN)
+ } else {
+ call printf (" Image %s renamed to %s\n")
+ #call pargstr (Memc[imname])
+ call pargstr (Memc[himname])
+ call pargstr (IRAFNAME(fits))
+ }
+ } else {
+ call printf (" Cannot rename image %s to %s\n")
+ #call pargstr (Memc[imname])
+ call pargstr (Memc[himname])
+ call pargstr (IRAFNAME(fits))
+ call flush (STDOUT)
+ call erract (EA_WARN)
+ }
+ } else {
+ call printf (" Image %s renamed to %s\n")
+ #call pargstr (Memc[imname])
+ call pargstr (Memc[himname])
+ call pargstr (IRAFNAME(fits))
+ }
+ } else if (EXTEND(fits) == NO && strne (Memc[imname],
+ iraffile)) {
+ iferr {
+ call imrename (Memc[imname], iraffile)
+ } then {
+ call printf (" Cannot rename image %s to %s\n")
+ #call pargstr (Memc[imname])
+ call pargstr (Memc[himname])
+ call pargstr (iraffile)
+ call flush (STDOUT)
+ call erract (EA_WARN)
+ } else {
+ call printf (
+ " No FITS extensions Image renamed to %s\n")
+ #call pargstr (Memc[imname])
+ call pargstr (iraffile)
+ }
+ }
+
+ if (EXTEND(fits) == YES && XTENSION(fits) == EXT_PRIMARY &&
+ len_elist == 1 && ext_number == 1) {
+ if (short_header == YES || long_header == YES) {
+ if (long_header == NO)
+ call printf (" ")
+ call printf (
+ "Warning: FITS extensions may be present\n")
+ }
+ }
+ if (long_header == YES)
+ call printf ("\n")
+
+ ext_count = ext_count + 1
+ if (EXTEND(fits) == NO || XTENSION(fits) == EXT_SPECIAL)
+ break
+ }
+
+ if (EXTEND(fits) == NO || XTENSION(fits) == EXT_SPECIAL)
+ break
+ }
+
+ if (gim != NULL) {
+ call imunmap (gim)
+ call imdelete (Memc[gimname])
+ }
+ call close (fits_fd)
+ call sfree (sp)
+
+ if (ext_count == 1)
+ return (EOF)
+ else
+ return (OK)
+end
+
+
+# RFT_FIND_EOF -- Read the FITS data file until EOF is reached.
+
+procedure rft_find_eof (fd)
+
+int fd # the FITS file descriptor
+
+int szbuf
+pointer sp, buf
+int fstati(), read()
+errchk read
+
+begin
+ # Scan through the file.
+ szbuf = fstati (fd, F_BUFSIZE)
+ call smark (sp)
+ call salloc (buf, szbuf, TY_CHAR)
+ while (read (fd, Memc[buf], szbuf) != EOF)
+ ;
+ call sfree (sp)
+end
+
+
+# RFT_SCAN_FILE -- Determine whether it is more efficient to read the
+# entire file or to skip forward to the next file if the parameter
+# make_image was set to no.
+
+procedure rft_scan_file (fd, fits, im, fe)
+
+int fd # the FITS file descriptor
+pointer fits # pointer to the FITS descriptor
+pointer im # pointer to the output image
+real fe # maximum file size in Kb for scan mode
+
+int i, szbuf
+pointer sp, buf
+real file_size
+int fstati(), read()
+errchk read
+
+begin
+ # Compute the file size in Kb and return if it is bigger than fe.
+ file_size = 1.0
+ do i = 1, IM_NDIM(im)
+ file_size = file_size * IM_LEN(im,i)
+ if (IM_NDIM(im) <= 0)
+ file_size = 0.0
+ else
+ file_size = file_size * abs (BITPIX(fits)) / FITS_BYTE / 1.0e3
+ if (file_size >= fe)
+ return
+
+ # Scan through the file.
+ szbuf = fstati (fd, F_BUFSIZE)
+ call smark (sp)
+ call salloc (buf, szbuf, TY_CHAR)
+ while (read (fd, Memc[buf], szbuf) != EOF)
+ ;
+ call sfree (sp)
+end
+
+
+# RFT_EXT_SKIP -- Compute the size of the data extension to be skipped
+# and do the skipping.
+
+int procedure rft_ext_skip (fits_fd, fits, im)
+
+int fits_fd # fits file descriptor
+pointer fits # pointer to the fits structure
+pointer im # pointer to the output image
+
+int i, nbits, nblocks, sz_rec, blksize, stat
+pointer buf
+int fstati(), rft_getbuf()
+
+begin
+ # Compute the number of blocks to skip.
+ nbits = NAXISN(im,1)
+ do i = 2, NAXIS(im)
+ nbits = nbits * NAXISN(im,i)
+ nbits = nbits + PCOUNT(fits)
+ nbits = abs (BITPIX(fits)) * GCOUNT(fits) * nbits
+ nblocks = int ((nbits + 23039) / 23040)
+
+ sz_rec = FITS_RECORD / SZB_CHAR
+ call malloc (buf, sz_rec, TY_CHAR)
+ blksize = fstati (fits_fd, F_SZBBLK)
+ if (mod (blksize, FITS_RECORD) == 0)
+ blksize = blksize / FITS_RECORD
+ else
+ blksize = 1
+
+ # Skip the blocks.
+ do i = 1, nblocks {
+ stat = rft_getbuf (fits_fd, Memc[buf], sz_rec, blksize,
+ NRECORDS(fits))
+ if (stat == EOF)
+ break
+ }
+
+ call mfree (buf, TY_CHAR)
+
+ return (stat)
+end
diff --git a/pkg/dataio/fits/fits_rheader.x b/pkg/dataio/fits/fits_rheader.x
new file mode 100644
index 00000000..e15a3559
--- /dev/null
+++ b/pkg/dataio/fits/fits_rheader.x
@@ -0,0 +1,888 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include <imhdr.h>
+include <imio.h>
+include <mach.h>
+include "rfits.h"
+
+define NEPSILON 10.0d0 # number of machine epsilon
+
+# RFT_READ_HEADER -- Read a FITS header.
+# If BSCALE and BZERO are different from 1.0 and 0.0 scale is set to true
+# otherwise scale is false.
+# EOT is detected by an EOF on the first read and EOF is returned to the calling
+# routine. Any error is passed to the calling routine.
+
+int procedure rft_read_header (fits_fd, fits, im, gim)
+
+int fits_fd # FITS file descriptor
+pointer fits # FITS data structure
+pointer im # IRAF image descriptor
+pointer gim # IRAF global header image descriptor
+
+int i, stat, nread, max_lenuser, fd_usr, ndiscard
+char card[LEN_CARD+1], type_str[LEN_TYPESTR]
+int rft_decode_card(), rft_init_read_pixels(), rft_read_pixels(), strmatch()
+int stropen()
+errchk rft_decode_card, rft_init_read_pixels, rft_read_pixels
+errchk stropen, close
+
+include "rfits.com"
+
+begin
+ # Initialization.
+ XTENSION(fits) = EXT_PRIMARY
+ BITPIX(fits) = INDEFI
+ NAXIS(im) = 0
+ do i = 1, IM_MAXDIM
+ IM_LEN(im,i) = 0
+ PCOUNT(fits) = 0
+ GCOUNT(fits) = 1
+ SCALE(fits) = NO
+ FITS_BSCALE(fits) = 1.0d0
+ FITS_BZERO(fits) = 0.0d0
+ BLANKS(fits) = NO
+ BLANK_VALUE(fits) = INDEFL
+ NRECORDS(fits) = 0
+ IRAFNAME(fits) = EOS
+ INHERIT(fits) = NO
+ ndiscard = 0
+ OBJECT(im) = EOS
+ UNKNOWN(im) = EOS
+ max_lenuser = (LEN_IMDES + IM_LENHDRMEM(im) - IMU) * SZ_STRUCT - 1
+
+ # The FITS header is character data in FITS_BYTE form. Open the
+ # header for reading. Open the user area which is a character
+ # string as a file.
+
+ i = rft_init_read_pixels (len_record, FITS_BYTE, LSBF, TY_CHAR)
+ fd_usr = stropen (UNKNOWN(im), max_lenuser, NEW_FILE)
+
+ # Loop until the END card is encountered.
+ nread = 0
+ repeat {
+
+ # Read the card.
+ i = rft_read_pixels (fits_fd, card, LEN_CARD, NRECORDS(fits), 1)
+ card[LEN_CARD + 1] = '\n'
+ card[LEN_CARD + 2] = EOS
+
+ # Decode the card images.
+ if ((i == EOF) && (nread == 0)) {
+ call close (fd_usr)
+ return (EOF)
+ } else if ((nread == 0) && SIMPLE(fits) == NO &&
+ strmatch (card, "^SIMPLE ") == 0) {
+ call flush (STDOUT)
+ call close (fd_usr)
+ call error (30,
+ "RFT_READ_HEADER: Not a FITS file (no SIMPLE keyword)")
+ } else if ((nread == 0) && EXTEND(fits) == YES &&
+ strmatch (card, "^XTENSION") == 0) {
+ XTENSION(fits) = EXT_SPECIAL
+ call flush (STDOUT)
+ call close (fd_usr)
+ call error (30,
+ "RFT_READ_HEADER: Not a FITS extension (no XTENSION keyword)")
+ } else if (i != LEN_CARD) {
+ call close (fd_usr)
+ call error (2, "RFT_READ_HEADER: Error reading FITS header")
+ } else
+ nread = nread + 1
+
+ # Remove contaminating control characters and replace with blanks.
+ call rft_control_to_blank (card, card, LEN_CARD)
+
+ # Print FITS card images if long_header option specified.
+ if (long_header == YES) {
+ call printf ("%-80.80s\n")
+ call pargstr (card)
+ }
+
+ # Stat = YES if FITS END card is encountered.
+ stat = rft_decode_card (fits, im, fd_usr, card, ndiscard)
+
+ } until (stat == YES)
+
+ # Check for the possibility of a global header.
+ if (NAXIS(im) == 0 && XTENSION(fits) == EXT_PRIMARY)
+ GLOBALHDR(fits) = YES
+
+ # Set the output image pixel type.
+ call rft_set_image_pixtype (fits, im, FITS_BSCALE(fits),
+ FITS_BZERO(fits))
+
+ # Copy the global header title and user area into the output image.
+ if (GLOBALHDR(fits) == YES) {
+ if (XTENSION(fits) == EXT_IMAGE && INHERIT(fits) == YES &&
+ gim != NULL) {
+ if (OBJECT(im) == EOS)
+ call strcpy (OBJECT(gim), OBJECT(im), SZ_OBJECT)
+ call close (fd_usr)
+ fd_usr = stropen (UNKNOWN(im), max_lenuser, APPEND)
+ call rft_gheader (im, gim, fd_usr, card, LEN_CARD, ndiscard,
+ long_header)
+ }
+ }
+
+ # Print optional short header.
+ if (short_header == YES && long_header == NO) {
+ call printf ("%s ")
+ switch (XTENSION(fits)) {
+ case EXT_PRIMARY:
+ call pargstr ("")
+ case EXT_IMAGE:
+ call pargstr ("IMAGE")
+ case EXT_TABLE:
+ call pargstr ("TABLE")
+ case EXT_BINTABLE:
+ call pargstr ("BINTABLE")
+ case EXT_UNKNOWN:
+ call pargstr ("UNKNOWN")
+ default:
+ call pargstr ("UNDEFINED")
+ }
+ if (make_image == NO) {
+ if (old_name == YES) {
+ call printf ("-> %s ")
+ call pargstr (IRAFNAME(fits))
+ }
+ } else {
+ call printf ("-> %s ")
+ call pargstr (IM_HDRFILE(im))
+ }
+ call printf ("%-20.20s ")
+ call pargstr (OBJECT(im))
+ call printf ("size=")
+ if (NAXIS(im) == 0)
+ call printf ("0")
+ else {
+ do i = 1, NAXIS(im) {
+ if (i == 1) {
+ call printf ("%d")
+ call pargl (NAXISN(im,i))
+ } else {
+ call printf ("x%d")
+ call pargl (NAXISN(im,i))
+ }
+ }
+ }
+ call printf ("\n")
+ if (XTENSION(fits) == EXT_PRIMARY || XTENSION(fits) == EXT_IMAGE) {
+ call printf (" bitpix=%d")
+ call pargi (BITPIX(fits))
+ if (SCALE(fits) == NO) {
+ call printf (" scaling=none")
+ } else {
+ call printf (" bscale=%.7g bzero=%.7g")
+ call pargd (FITS_BSCALE(fits))
+ call pargd (FITS_BZERO(fits))
+ }
+ call rft_typestring (PIXTYPE(im), type_str, LEN_TYPESTR)
+ call strlwr (type_str)
+ call printf (" pixtype=%s")
+ call pargstr (type_str)
+ call printf ("\n")
+ }
+ }
+
+ # Let the user know if there is not enough space in the user area.
+ if (ndiscard > 0) {
+ if (short_header == YES || long_header == YES) {
+ if (long_header == NO)
+ call printf (" ")
+ call printf (
+ "Warning: User area too small %d card images discarded\n")
+ call pargi (ndiscard)
+ }
+ call rft_last_user (UNKNOWN(im), max_lenuser)
+ }
+
+ call close (fd_usr)
+ return (OK)
+end
+
+
+# RFT_CONTROL_TO_BLANK -- Replace an ACSII control characters in the
+# FITS card image with blanks.
+
+procedure rft_control_to_blank (incard, outcard, len_card)
+
+char incard[ARB] # the input FITS card image
+char outcard[ARB] # the output FITS card image
+int len_card # the length of the FITS card image
+
+int i
+
+begin
+ for (i = 1; i <= len_card; i = i + 1) {
+ if (IS_PRINT(incard[i]))
+ outcard[i] = incard[i]
+ else
+ outcard[i] = ' '
+ }
+end
+
+
+# RFT_DECODE_CARD -- Decode a FITS card and return YES when the END
+# card is encountered. The keywords understood are given in rfits.h.
+
+int procedure rft_decode_card (fits, im, fd_usr, card, ndiscard)
+
+pointer fits # FITS data structure
+pointer im # IRAF image descriptor
+int fd_usr # file descriptor of user area
+char card[ARB] # FITS card
+int ndiscard # Number of cards for which no space available
+
+char cval
+double dval
+int nchar, i, j, k, len
+pointer sp, str, comment
+
+bool rft_equald()
+int strmatch(), ctoi(), ctol(), ctod(), cctoc(), rft_hms()
+errchk putline
+
+include "rfits.com"
+
+begin
+ call smark (sp)
+ call salloc (str, LEN_CARD, TY_CHAR)
+ call salloc (comment, SZ_LINE, TY_CHAR)
+
+ i = COL_VALUE
+ if (strmatch (card, "^END ") != 0) {
+ call sfree (sp)
+ return(YES)
+ } else if (strmatch (card, "^SIMPLE ") != 0) {
+ if (SIMPLE(fits) == YES) {
+ if (short_header == YES || long_header == YES) {
+ if (long_header == NO)
+ call printf (" ")
+ call printf ("Warning: Duplicate SIMPLE keyword ignored\n")
+ }
+ } else {
+ nchar = cctoc (card, i, cval)
+ if (cval != 'T')
+ call error (13, "RFT_DECODE_CARD: Non-standard FITS format")
+ else
+ SIMPLE(fits) = YES
+ }
+ } else if (strmatch (card, "^XTENSION") != 0) {
+ call rft_get_fits_string (card, Memc[str], LEN_CARD)
+ if (strmatch (Memc[str], "^IMAGE") != 0)
+ XTENSION(fits) = EXT_IMAGE
+ else if (strmatch (Memc[str], "^TABLE") != 0)
+ XTENSION(fits) = EXT_TABLE
+ else if (strmatch (Memc[str], "^BINTABLE") != 0)
+ XTENSION(fits) = EXT_BINTABLE
+ else
+ XTENSION(fits) = EXT_UNKNOWN
+ } else if (strmatch (card, "^BITPIX ") != 0) {
+ if (! IS_INDEFI(BITPIX(fits))) {
+ if (short_header == YES || long_header == YES) {
+ if (long_header == NO)
+ call printf (" ")
+ call printf ("Warning: Duplicate BITPIX keyword ignored\n")
+ }
+ } else
+ nchar = ctoi (card, i, BITPIX(fits))
+ } else if (strmatch (card, "^NAXIS ") != 0) {
+ if (NAXIS(im) != 0) {
+ if (short_header == YES || long_header == YES) {
+ if (long_header == NO)
+ call printf (" ")
+ call printf ("Warning: Duplicate NAXIS keyword ignored\n")
+ }
+ } else
+ nchar = ctoi (card, i, NAXIS(im))
+ if (NAXIS(im) > IM_MAXDIM)
+ call error (5, "RFT_DECODE_CARD: FITS NAXIS too large")
+ } else if (strmatch (card, "^NAXIS") != 0) {
+ k = strmatch (card, "^NAXIS")
+ nchar = ctoi (card, k, j)
+ if (NAXISN(im,j) != 0) {
+ if (short_header == YES || long_header == YES) {
+ if (long_header == NO)
+ call printf (" ")
+ call printf ("Warning: Duplicate NAXIS%d keyword ignored\n")
+ call pargi (j)
+ }
+ } else
+ nchar = ctol (card, i, NAXISN(im, j))
+ } else if (strmatch (card, "^GROUPS ") != 0) {
+ nchar = cctoc (card, i, cval)
+ if (cval == 'T') {
+ NAXIS(im) = 0
+ call error (6, "RFT_DECODE_CARD: Group data not implemented")
+ }
+ } else if (strmatch (card, "^EXTEND ") != 0) {
+ if (EXTEND(fits) == YES) {
+ if (short_header == YES || long_header == YES) {
+ if (long_header == NO)
+ call printf (" ")
+ call printf ("Warning: Duplicate EXTEND keyword ignored\n")
+ }
+ } else {
+ nchar = cctoc (card, i, cval)
+ if (cval == 'T')
+ EXTEND(fits) = YES
+ }
+ } else if (strmatch (card, "^INHERIT ") != 0) {
+ if (INHERIT(fits) == YES) {
+ if (short_header == YES || long_header == YES) {
+ if (long_header == NO)
+ call printf (" ")
+ call printf ("Warning: Duplicate INHERIT keyword ignored\n")
+ }
+ } else {
+ nchar = cctoc (card, i, cval)
+ if (cval == 'T')
+ INHERIT(fits) = YES
+ }
+ } else if (strmatch (card, "^PCOUNT ") != 0) {
+ nchar = ctoi (card, i, PCOUNT(fits))
+ if (nchar <= 0)
+ PCOUNT(fits) = 0
+ } else if (strmatch (card, "^GCOUNT ") != 0) {
+ nchar = ctoi (card, i, GCOUNT(fits))
+ if (nchar <= 0)
+ GCOUNT(fits) = 1
+ #} else if (strmatch (card, "^TABLES ") != 0) {
+ #nchar = ctoi (card, i, ival)
+ #if (ival > 0)
+ #call printf ("Warning: FITS special records not decoded\n")
+ } else if (strmatch (card, "^BSCALE ") != 0) {
+ nchar = ctod (card, i, dval)
+ if (nchar > 0)
+ FITS_BSCALE(fits) = dval
+ else if (short_header == YES || long_header == YES) {
+ if (long_header == NO)
+ call printf (" ")
+ call printf ("Warning: Error decoding BSCALE, BSCALE=1.0\n")
+ }
+ if (! rft_equald (dval, 1.0d0) && (scale == YES))
+ SCALE(fits) = YES
+ } else if (strmatch (card, "^BZERO ") != 0) {
+ nchar = ctod (card, i, dval)
+ if (nchar > 0)
+ FITS_BZERO(fits) = dval
+ else if (short_header == YES || long_header == YES) {
+ if (long_header == NO)
+ call printf (" ")
+ call printf ("Warning: Error decoding BZERO, BZERO=0.0\n")
+ }
+ if (! rft_equald (dval, 0.0d0) && (scale == YES))
+ SCALE(fits) = YES
+ } else if (strmatch (card, "^BLANK ") != 0) {
+ BLANKS(fits) = YES
+ nchar = ctol (card, i, BLANK_VALUE(fits))
+ } else if (strmatch (card, "^OBJECT ") != 0) {
+ call rft_get_fits_string (card, OBJECT(im), SZ_OBJECT)
+ } else if (strmatch (card, "^IRAFNAME") != 0) {
+ call rft_get_fits_string (card, IRAFNAME(fits), SZ_FNAME)
+ } else if (strmatch (card, "^FILENAME") != 0) {
+ if (IRAFNAME(fits) == EOS)
+ call rft_get_fits_string (card, IRAFNAME(fits), SZ_FNAME)
+ } else if (strmatch (card, "^EXTNAME ") != 0) {
+ if (XTENSION(fits) != EXT_PRIMARY && XTENSION(fits) != EXT_IMAGE)
+ call rft_get_fits_string (card, IRAFNAME(fits), SZ_FNAME)
+ } else if (strmatch (card, "^EXTVER ") != 0) {
+ # Filter this quantitity out and ignore it for now.
+ ;
+ } else if (strmatch (card, "^ORIGIN ") != 0) {
+ call rft_trim_card (card, card, LEN_CARD)
+ call strcat (card[i], HISTORY(im), SZ_HISTORY)
+ } else if (strmatch (card, "^DATE ") != 0) {
+ call rft_trim_card (card, card, LEN_CARD)
+ call strcat (card[i], HISTORY(im), SZ_HISTORY)
+ } else if (strmatch (card, "^IRAF-TLM") != 0) {
+ call rft_trim_card (card, card, LEN_CARD)
+ call strcat (card[i], HISTORY(im), SZ_HISTORY)
+ #} else if (strmatch (card, "^HISTORY ") != 0) {
+ #call rft_trim_card (card, card, LEN_CARD)
+ #call strcat (card[i - 2], HISTORY(im), SZ_HISTORY)
+ } else if (strmatch (card, "^UT ") != 0) {
+ len = rft_hms (card, Memc[str], Memc[comment], LEN_CARD)
+ if (len > 0) {
+ call wft_encodec ("UT", Memc[str], len, card, Memc[comment])
+ card[LEN_CARD+1] = '\n'
+ card[LEN_CARD+2] = EOS
+ }
+ if (ndiscard > 1)
+ ndiscard = ndiscard + 1
+ else {
+ iferr (call putline (fd_usr, card))
+ ndiscard = ndiscard + 1
+ }
+ } else if (strmatch (card, "^ZD ") != 0) {
+ len = rft_hms (card, Memc[str], Memc[comment], LEN_CARD)
+ if (len > 0) {
+ call wft_encodec ("ZD", Memc[str], len, card, Memc[comment])
+ card[LEN_CARD+1] = '\n'
+ card[LEN_CARD+2] = EOS
+ }
+ if (ndiscard > 1)
+ ndiscard = ndiscard + 1
+ else {
+ iferr (call putline (fd_usr, card))
+ ndiscard = ndiscard + 1
+ }
+ } else if (strmatch (card, "^ST ") != 0) {
+ len = rft_hms (card, Memc[str], Memc[comment], LEN_CARD)
+ if (len > 0) {
+ call wft_encodec ("ST", Memc[str], len, card, Memc[comment])
+ card[LEN_CARD+1] = '\n'
+ card[LEN_CARD+2] = EOS
+ }
+ if (ndiscard > 1)
+ ndiscard = ndiscard + 1
+ else {
+ iferr (call putline (fd_usr, card))
+ ndiscard = ndiscard + 1
+ }
+ } else if (strmatch (card, "^RA ") != 0) {
+ len = rft_hms (card, Memc[str], Memc[comment], LEN_CARD)
+ if (len > 0) {
+ call wft_encodec ("RA", Memc[str], len, card, Memc[comment])
+ card[LEN_CARD+1] = '\n'
+ card[LEN_CARD+2] = EOS
+ }
+ if (ndiscard > 1)
+ ndiscard = ndiscard + 1
+ else {
+ iferr (call putline (fd_usr, card))
+ ndiscard = ndiscard + 1
+ }
+ } else if (strmatch (card, "^DEC ") != 0) {
+ len = rft_hms (card, Memc[str], Memc[comment], LEN_CARD)
+ if (len > 0) {
+ call wft_encodec ("DEC", Memc[str], len, card, Memc[comment])
+ card[LEN_CARD+1] = '\n'
+ card[LEN_CARD+2] = EOS
+ }
+ if (ndiscard > 1)
+ ndiscard = ndiscard + 1
+ else {
+ iferr (call putline (fd_usr, card))
+ ndiscard = ndiscard + 1
+ }
+ } else {
+ if (ndiscard > 1)
+ ndiscard = ndiscard + 1
+ else {
+ iferr (call putline (fd_usr, card))
+ ndiscard = ndiscard + 1
+ }
+ }
+
+ call sfree (sp)
+
+ return (NO)
+
+end
+
+
+# RFT_HMS -- Procedure to decode a FITS HMS card from the mountain.
+
+int procedure rft_hms (card, str, comment, maxch)
+
+char card[ARB] # FITS card
+char str[ARB] # string
+char comment[ARB] # comment string
+int maxch # maximum number of characters
+
+char colon, minus
+int ip, nchar, fst, lst, deg, min
+real sec
+int stridx(), strldx(), strlen(), ctoi(), ctor()
+
+begin
+ # Return if not a FITS string parameter.
+ if (card[COL_VALUE] != '\'')
+ return (0)
+
+ # Set up key characters.
+ colon = ':'
+ minus = '-'
+
+ # Get the FITS string.
+ call rft_get_fits_string (card, str, maxch)
+
+ # Get the comment string.
+ call rft_get_comment (card, comment, maxch)
+
+ # Test for blank string and for 2 colon delimiters.
+ if (str[1] == EOS)
+ return (0)
+ fst = stridx (colon, str)
+ if (fst == 0)
+ return (0)
+ lst = strldx (colon, str)
+ if (lst == 0)
+ return (0)
+ if (fst == lst)
+ return (0)
+
+ # Decode the degrees field.
+ ip = 1
+ while (IS_WHITE(str[ip]))
+ ip = ip + 1
+ if (str[ip] == '+' || str[ip] == '-')
+ ip = ip + 1
+ nchar = ctoi (str, ip, deg)
+ if (nchar == 0)
+ deg = 0
+
+ # Decode the minutes field.
+ ip = fst + 1
+ while (IS_WHITE(str[ip]))
+ ip = ip + 1
+ if (str[ip] == '+' || str[ip] == '-')
+ ip = ip + 1
+ nchar = ctoi (str, ip, min)
+ if (nchar == 0)
+ min = 0
+
+ # Decode the seconds field.
+ ip = lst + 1
+ while (IS_WHITE(str[ip]))
+ ip = ip + 1
+ if (str[ip] == '+' || str[ip] == '-')
+ ip = ip + 1
+ nchar = ctor (str, ip, sec)
+ if (nchar == 0)
+ sec = 0.0
+
+ # Reformat the HMS card.
+ if (stridx (minus, str) > 0 || deg < 0 || min < 0 || sec < 0.0) {
+ call sprintf (str, maxch, "%c%d:%02d:%05.2f")
+ call pargc (minus)
+ call pargi (abs (deg))
+ call pargi (abs (min))
+ call pargr (abs (sec))
+ } else {
+ call sprintf (str, maxch, "%2d:%02d:%05.2f")
+ call pargi (deg)
+ call pargi (abs (min))
+ call pargr (abs (sec))
+ }
+
+ return (strlen (str))
+end
+
+
+# RFT_GET_COMMENT -- Extract the comment field from a FITS card.
+
+procedure rft_get_comment (card, comment, maxch)
+
+char card[ARB] # FITS card
+char comment[ARB] # comment string
+int maxch # maximum number of characters
+
+int istart, j
+
+begin
+ istart = 0
+ for (j = LEN_CARD; (j >= 1) && (card[j] != '\''); j = j - 1) {
+ if (card[j] == '/') {
+ for (istart = j + 1; IS_WHITE(card[istart]) && istart <=
+ LEN_CARD; istart = istart + 1)
+ ;
+ break
+ }
+ }
+
+ if (istart == 0)
+ comment[1] = EOS
+ else
+ call strcpy (card[istart], comment, LEN_CARD - istart + 1 )
+end
+
+
+# RFT_GET_FITS_STRING -- Extract a string from a FITS card and trim trailing
+# blanks. The EOS is marked by either ', /, or the end of the card.
+# There may be an optional opening ' (FITS standard).
+
+procedure rft_get_fits_string (card, str, maxchar)
+
+char card[ARB] # FITS card
+char str[ARB] # FITS string
+int maxchar # maximum number of characters
+
+int j, istart, nchar
+
+begin
+ # Check for opening quote
+ for (istart = COL_VALUE; istart <= LEN_CARD && card[istart] != '\'';
+ istart = istart + 1)
+ ;
+ istart = istart + 1
+
+ # Check for closing quote.
+ for (j = istart; (j<LEN_CARD)&&(card[j]!='\''); j = j + 1)
+ ;
+ for (j = j - 1; (j >= istart) && (card[j] == ' '); j = j - 1)
+ ;
+ nchar = min (maxchar, j - istart + 1)
+
+ # Copy the string.
+ if (nchar <= 0)
+ str[1] = EOS
+ else
+ call strcpy (card[istart], str, nchar)
+end
+
+
+# RFT_EQUALD -- Procedure to compare two double precision numbers for equality
+# to within the machine precision for doubles.
+
+bool procedure rft_equald (x, y)
+
+double x, y # the two numbers to be compared for equality
+
+int ex, ey
+double x1, x2, normed_x, normed_y
+
+begin
+ if (x == y)
+ return (true)
+
+ call rft_normd (x, normed_x, ex)
+ call rft_normd (y, normed_y, ey)
+
+ if (ex != ey)
+ return (false)
+ else {
+ x1 = 1.0d0 + abs (normed_x - normed_y)
+ x2 = 1.0d0 + NEPSILON * EPSILOND
+ return (x1 <= x2)
+ }
+end
+
+
+# RFT_NORMED -- Normalize a double precision number x to the value normed_x,
+# in the range [1-10]. Expon is returned such that x = normed_x *
+# (10.0d0 ** expon).
+
+procedure rft_normd (x, normed_x, expon)
+
+double x # number to be normailized
+double normed_x # normalized number
+int expon # exponent
+
+double ax
+
+begin
+ ax = abs (x)
+ expon = 0
+
+ if (ax > 0) {
+ while (ax < (1.0d0 - NEPSILON * EPSILOND)) {
+ ax = ax * 10.0d0
+ expon = expon - 1
+ }
+
+ while (ax >= (10.0d0 - NEPSILON * EPSILOND)) {
+ ax = ax / 10.0d0
+ expon = expon + 1
+ }
+ }
+
+ if (x < 0)
+ normed_x = -ax
+ else
+ normed_x = ax
+end
+
+
+# RFT_TRIM_CARD -- Procedure to trim trailing whitespace from the card
+
+procedure rft_trim_card (incard, outcard, maxch)
+
+char incard[ARB] # input FITS card image
+char outcard[ARB] # output FITS card
+int maxch # maximum size of card
+
+int ip
+
+begin
+ ip = maxch
+ while (incard[ip] == ' ' || incard[ip] == '\t' || incard[ip] == '\0')
+ ip = ip - 1
+ call amovc (incard, outcard, ip)
+ outcard[ip+1] = '\n'
+ outcard[ip+2] = EOS
+end
+
+
+# RFT_LAST_CARD -- Remove a partially written card from the data base
+
+procedure rft_last_user (user, maxch)
+
+char user[ARB] # user area
+int maxch # maximum number of characters
+
+int ip
+
+begin
+ ip = maxch
+ while (user[ip] != '\n')
+ ip = ip - 1
+ user[ip+1] = EOS
+end
+
+
+# RFT_SET_IMAGE_PIXTYPE -- Set remaining header fields not set in
+# rft_read_header.
+
+procedure rft_set_image_pixtype (fits, im, bscale, bzero)
+
+pointer fits # FITS data structure
+pointer im # IRAF image pointer
+double bscale # FITS scaling parameter
+double bzero # FITS offset parameter
+
+bool rft_equald()
+include "rfits.com"
+
+begin
+ # Determine data type from BITPIX if user data type not specified.
+
+ if (data_type == ERR) {
+ if (BITPIX(fits) < 0) {
+ if (abs (BITPIX(fits)) <= (SZ_REAL * SZB_CHAR * NBITS_BYTE))
+ PIXTYPE(im) = TY_REAL
+ else
+ PIXTYPE(im) = TY_DOUBLE
+ } else if (SCALE(fits) == YES) {
+ if (rft_equald (bscale, 1.0d0)) {
+ if (rft_equald (bzero / 32768.0d0, 1.0d0))
+ PIXTYPE(im) = TY_USHORT
+ else
+ PIXTYPE(im) = TY_REAL
+ } else
+ PIXTYPE(im) = TY_REAL
+ } else {
+ if (BITPIX(fits) <= (SZ_SHORT * SZB_CHAR * NBITS_BYTE))
+ PIXTYPE(im) = TY_SHORT
+ else
+ PIXTYPE(im) = TY_LONG
+ }
+
+ } else
+ PIXTYPE(im) = data_type
+end
+
+
+# Copy the global header into the output image header.
+
+procedure rft_gheader (im, gim, fd_usr, card, len_card, ndiscard, long_header)
+
+pointer im # IRAF image header descriptor
+pointer gim # IRAF global image header descriptor
+int fd_usr # IRAF image header user area
+char card[ARB] # FITS card
+int len_card # length of FITS card
+int ndiscard # number of cards discarded
+int long_header # print the long header
+
+int ngcards, gim_lenuser, ninherit, count
+pointer sp, indices, idb_gim, grp, irp
+bool streq()
+int strlen(), idb_nextcard(), idb_find()
+pointer idb_open()
+errchk putline()
+
+begin
+ # Initialize.
+ call smark (sp)
+ ngcards = strlen (UNKNOWN(gim)) / (len_card + 1)
+ call salloc (indices, ngcards, TY_INT)
+
+ # Mark the global header cards which are to be inherited. These
+ # include all COMMENT, HISTORY, and BLANK cards, plus all those
+ # cards which do not already have values in the extension header.
+ count = 0
+ idb_gim = idb_open (gim, gim_lenuser)
+ while (idb_nextcard (idb_gim, grp) != EOF) {
+ if (count >= ngcards)
+ break
+ call strcpy (Memc[grp], card, 8)
+ if (streq (card, "COMMENT "))
+ Memi[indices+count] = YES
+ else if (streq (card, "HISTORY "))
+ Memi[indices+count] = YES
+ else if (streq (card, " "))
+ Memi[indices+count] = YES
+ else if (idb_find (im, card, irp) > 0)
+ Memi[indices+count] = NO
+ else
+ Memi[indices+count] = YES
+ count = count + 1
+ }
+ call idb_close (idb_gim)
+
+ # Open the global header image user area and loop through the cards.
+ ninherit = 0
+ count = 0
+ idb_gim = idb_open (gim, gim_lenuser)
+ while (idb_nextcard (idb_gim, grp) != EOF) {
+ if (Memi[indices+count] == YES) {
+ call strcpy (Memc[grp], card, len_card)
+ card[len_card+1] = '\n'
+ card[len_card+2] = EOS
+ if (ndiscard > 1)
+ ndiscard = ndiscard + 1
+ else {
+ iferr (call putline (fd_usr, card))
+ ndiscard = ndiscard + 1
+ else
+ ninherit = ninherit + 1
+ }
+ }
+ count = count + 1
+ }
+ call idb_close (idb_gim)
+
+ if (long_header == YES) {
+ call printf ("%d global header keywords were inherited\n")
+ call pargi (ninherit)
+ }
+
+ call sfree (sp)
+end
+
+
+# RFT_TYPESTRING -- Procedure to set the iraf datatype keyword.
+
+procedure rft_typestring (data_type, type_str, maxch)
+
+int data_type # the IRAF data type
+char type_str[ARB] # the output IRAF type string
+int maxch # maximum size of the type string
+
+begin
+ switch (data_type) {
+ case TY_SHORT:
+ call strcpy ("SHORT", type_str, maxch)
+ case TY_USHORT:
+ call strcpy ("USHORT", type_str, maxch)
+ case TY_INT:
+ call strcpy ("INTEGER", type_str, maxch)
+ case TY_LONG:
+ call strcpy ("LONG", type_str, maxch)
+ case TY_REAL:
+ call strcpy ("REAL", type_str, maxch)
+ case TY_DOUBLE:
+ call strcpy ("DOUBLE", type_str, maxch)
+ case TY_COMPLEX:
+ call strcpy ("COMPLEX", type_str, maxch)
+ default:
+ call strcpy ("UNKNOWN", type_str, maxch)
+ }
+end
+
+
diff --git a/pkg/dataio/fits/fits_rimage.x b/pkg/dataio/fits/fits_rimage.x
new file mode 100644
index 00000000..9994c1d4
--- /dev/null
+++ b/pkg/dataio/fits/fits_rimage.x
@@ -0,0 +1,557 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <mach.h>
+include <fset.h>
+include "rfits.h"
+
+# RFT_READ_IMAGE -- Convert FITS image pixels to IRAF image pixels.
+
+procedure rft_read_image (fits_fd, fits, im)
+
+int fits_fd # FITS file descriptor
+pointer fits # FITS data structure
+pointer im # IRAF image descriptor
+
+int i, npix, npix_record, blksize, ndummy
+long v[IM_MAXDIM], nlines, il
+pointer tempbuf, buf
+real linemax, linemin, lirafmin, lirafmax
+double dblank
+
+long clktime()
+int fstati(), rft_init_read_pixels(), rft_read_pixels()
+
+errchk malloc, mfree, rft_init_read_pixels, rft_read_pixels, rft_lscale_pix
+errchk rft_lchange_pix, rft_rchange_pix, rfit_dchange_pix, rft_put_image_line
+errchk rft_pix_limits, rft_rscale_pix, rft_dscale_pix
+
+include "rfits.com"
+
+begin
+ # No pixel file was created.
+ if (NAXIS(im) == 0) {
+ if (short_header == YES || long_header == YES) {
+ if (long_header == NO)
+ call printf (" ")
+ call printf ("Warning: No pixel file created\n")
+ }
+ return
+ }
+
+ # Compute the number of columns and lines in the image.
+ npix = NAXISN(im, 1)
+ nlines = 1
+ do i = 2, NAXIS(im)
+ nlines = nlines * NAXISN(im, i)
+ lirafmax = -MAX_REAL
+ lirafmin = MAX_REAL
+
+ # Compute the number of pixels per record and the number of records
+ # per output block.
+
+ npix_record = len_record * FITS_BYTE / abs (BITPIX(fits))
+ blksize = fstati (fits_fd, F_SZBBLK)
+ if (mod (blksize, FITS_RECORD) == 0)
+ blksize = blksize / FITS_RECORD
+ else
+ blksize = 1
+
+ # FITS data is converted to type LONG, REAL or DOUBLE. If BITPIX is
+ # not one of the MII types then rft_read_pixels returns an ERROR.
+
+ call amovkl (long(1), v, IM_MAXDIM)
+ switch (BITPIX(fits)) {
+ case FITS_REAL:
+
+ # Allocate temporary space.
+ call malloc (tempbuf, npix, TY_REAL)
+
+ # Initialize the read.
+ i = rft_init_read_pixels (npix_record, BITPIX(fits), LSBF, TY_REAL)
+
+ # Turn on the ieee NaN mapping.
+ call ieesnanr (blank)
+ call ieemapr (YES, NO)
+ #call ieezstatr ()
+ NBPIX(im) = 0
+
+ # Allocate the space for the output line, read in the image
+ # line, convert from the ieee to native format, and compute the
+ # minimum and maximum.
+
+ do il = 1, nlines {
+ call rft_put_image_line (im, buf, v, PIXTYPE(im))
+ if (rft_read_pixels (fits_fd, Memr[tempbuf], npix,
+ NRECORDS(fits), blksize) != npix)
+ call printf ("Error reading FITS data\n")
+ if (SCALE(fits) == YES)
+ call rft_rscale_pix (Memr[tempbuf], buf, npix,
+ FITS_BSCALE(fits), FITS_BZERO(fits), PIXTYPE(im))
+ else
+ call rft_rchange_pix (Memr[tempbuf], buf, npix, PIXTYPE(im))
+ call rft_pix_limits (buf, npix, PIXTYPE(im), linemin, linemax)
+ lirafmax = max (lirafmax, linemax)
+ lirafmin = min (lirafmin, linemin)
+ }
+
+ # Set the number of bad pixels.
+ call ieestatr (NBPIX(im), ndummy)
+
+ # Free space.
+ call mfree (tempbuf, TY_REAL)
+
+ case FITS_DOUBLE:
+
+ # Allocate temporary space.
+ call malloc (tempbuf, npix, TY_DOUBLE)
+
+ # Initialize the read.
+ i = rft_init_read_pixels (npix_record, BITPIX(fits), LSBF,
+ TY_DOUBLE)
+
+ # Turn on the ieee NaN mapping.
+ dblank = blank
+ call ieesnand (dblank)
+ call ieemapd (YES, NO)
+ #call ieezstatd ()
+ NBPIX(im) = 0
+
+ # Allocate the space for the output line, read in the image
+ # line, convert from the ieee to native format, and compute the
+ # minimum and maximum.
+
+ do il = 1, nlines {
+ call rft_put_image_line (im, buf, v, PIXTYPE(im))
+ if (rft_read_pixels (fits_fd, Memd[tempbuf], npix,
+ NRECORDS(fits), blksize) != npix)
+ call printf ("Error reading FITS data\n")
+ if (SCALE(fits) == YES)
+ call rft_dscale_pix (Memd[tempbuf], buf, npix,
+ FITS_BSCALE(fits), FITS_BZERO(fits), PIXTYPE(im))
+ else
+ call rft_dchange_pix (Memd[tempbuf], buf, npix, PIXTYPE(im))
+ call rft_pix_limits (buf, npix, PIXTYPE(im), linemin, linemax)
+ if (IS_INDEFR(linemax))
+ lirafmax = INDEFR
+ else
+ lirafmax = max (lirafmax, linemax)
+ if (IS_INDEFR(linemin))
+ lirafmin = INDEFR
+ else
+ lirafmin = min (lirafmin, linemin)
+ }
+
+ # Set the number of bad pixels.
+ call ieestatd (NBPIX(im), ndummy)
+
+ # Free space.
+ call mfree (tempbuf, TY_DOUBLE)
+
+ default:
+
+ # Allocate the required space.
+ call malloc (tempbuf, npix, TY_LONG)
+
+ # Allocate the space for the output line, read in the image
+ # line, convert from the ieee to native format, and compute the
+ # minimum and maximum.
+
+ i = rft_init_read_pixels (npix_record, BITPIX(fits), LSBF, TY_LONG)
+ do il = 1, nlines {
+ call rft_put_image_line (im, buf, v, PIXTYPE(im))
+ if (rft_read_pixels (fits_fd, Meml[tempbuf], npix,
+ NRECORDS(fits), blksize) != npix)
+ call printf ("Error reading FITS data\n")
+ if (SCALE(fits) == YES)
+ call rft_lscale_pix (Meml[tempbuf], buf, npix,
+ FITS_BSCALE(fits), FITS_BZERO(fits), PIXTYPE(im))
+ else
+ call rft_lchange_pix (Meml[tempbuf], buf, npix, PIXTYPE(im))
+ if (BLANKS(fits) == YES)
+ call rft_map_blanks (Meml[tempbuf], buf, npix, PIXTYPE(im),
+ BLANK_VALUE(fits), blank, NBPIX(im))
+ call rft_pix_limits (buf, npix, PIXTYPE(im), linemin, linemax)
+ lirafmax = max (lirafmax, linemax)
+ lirafmin = min (lirafmin, linemin)
+ }
+
+ # Free space.
+ call mfree (tempbuf, TY_LONG)
+ }
+
+ IRAFMIN(im) = lirafmin
+ IRAFMAX(im) = lirafmax
+ LIMTIME(im) = clktime (long(0))
+
+ if (short_header == YES || long_header == YES) {
+ if (NBPIX (im) != 0) {
+ if (long_header == NO)
+ call printf (" ")
+ call printf ("Warning: %d bad pixels replaced in image\n")
+ call pargl (NBPIX (im))
+ }
+ if (IS_INDEFR(lirafmax) || lirafmax > MAX_REAL) {
+ if (long_header == NO)
+ call printf (" ")
+ call printf ("Warning: image contains pixel values > %g\n")
+ call pargr (MAX_REAL)
+ }
+ if (IS_INDEFR(lirafmin) || lirafmin < -MAX_REAL) {
+ if (long_header == NO)
+ call printf (" ")
+ call printf ("Warning: image contains pixel values < %g\n")
+ call pargr (-MAX_REAL)
+ }
+ }
+end
+
+
+# RFT_PUT_IMAGE_LINE -- Procedure to output an image line to and IRAF file.
+
+procedure rft_put_image_line (im, buf, v, data_type)
+
+pointer im # IRAF image descriptor
+pointer buf # Pointer to output image line
+long v[ARB] # imio pointer
+int data_type # output pixel type
+
+int impnll(), impnlr(), impnld(), impnlx()
+errchk impnll, impnlr, impnld, impnlx
+
+begin
+ switch (data_type) {
+ case TY_SHORT, TY_INT, TY_USHORT, TY_LONG:
+ if (impnll (im, buf, v) == EOF)
+ call error (3, "RFT_PUT_IMAGE_LINE: Error writing FITS data")
+ case TY_REAL:
+ if (impnlr (im, buf, v) == EOF)
+ call error (3, "RFT_PUT_IMAGE_LINE: Error writing FITS data")
+ case TY_DOUBLE:
+ if (impnld (im, buf, v) == EOF)
+ call error (3, "RFT_PUT_IMAGE_LINE: Error writing FITS data")
+ case TY_COMPLEX:
+ if (impnlx (im, buf, v) == EOF)
+ call error (3, "RFT_PUT_IMAGE_LINE: Error writing FITS data")
+ default:
+ call error (10, "RFT_PUT_IMAGE_LINE: Unsupported IRAF image type")
+ }
+end
+
+
+# RFT_RSCALE_PIX -- Procedure to convert an IRAF image line from type real
+# to the requested output data type with optional scaling using the
+# FITS parameters BSCALE and BZERO.
+
+procedure rft_rscale_pix (inbuf, outbuf, npix, bscale, bzero, data_type)
+
+real inbuf[ARB] # buffer of FITS integers
+pointer outbuf # pointer to output image line
+int npix # number of pixels
+double bscale, bzero # FITS bscale and bzero
+int data_type # IRAF image pixel type
+
+errchk altmdr, achtrl, amovr, achtrd, achtrx
+
+begin
+ switch (data_type) {
+ case TY_SHORT, TY_USHORT, TY_INT, TY_LONG:
+ call altmdr (inbuf, inbuf, npix, bscale, bzero)
+ call achtrl (inbuf, Meml[outbuf], npix)
+ case TY_REAL:
+ call altmdr (inbuf, inbuf, npix, bscale, bzero)
+ call amovr (inbuf, Memr[outbuf], npix)
+ case TY_DOUBLE:
+ call altmdr (inbuf, inbuf, npix, bscale, bzero)
+ call achtrd (inbuf, Memd[outbuf], npix)
+ case TY_COMPLEX:
+ call altmdr (inbuf, inbuf, npix, bscale, bzero)
+ call achtrx (inbuf, Memx[outbuf], npix)
+ default:
+ call error (10, "RFT_SCALE_LINE: Illegal IRAF image type")
+ }
+end
+
+
+# RFT_DSCALE_PIX -- Procedure to convert an IRAF image line from type double
+# to the requested output data type with optional scaling using the
+# FITS parameters BSCALE and BZERO.
+
+procedure rft_dscale_pix (inbuf, outbuf, npix, bscale, bzero, data_type)
+
+double inbuf[ARB] # buffer of FITS integers
+pointer outbuf # pointer to output image line
+int npix # number of pixels
+double bscale, bzero # FITS bscale and bzero
+int data_type # IRAF image pixel type
+
+errchk altmd, achtdl, amovd, achtdr, achtdx
+
+begin
+ switch (data_type) {
+ case TY_SHORT, TY_USHORT, TY_INT, TY_LONG:
+ call altmd (inbuf, inbuf, npix, bscale, bzero)
+ call achtdl (inbuf, Meml[outbuf], npix)
+ case TY_REAL:
+ call altmd (inbuf, inbuf, npix, bscale, bzero)
+ call achtdr (inbuf, Memr[outbuf], npix)
+ case TY_DOUBLE:
+ call altmd (inbuf, inbuf, npix, bscale, bzero)
+ call amovd (inbuf, Memd[outbuf], npix)
+ case TY_COMPLEX:
+ call altmd (inbuf, inbuf, npix, bscale, bzero)
+ call achtdx (inbuf, Memx[outbuf], npix)
+ default:
+ call error (10, "RFT_SCALE_LINE: Illegal IRAF image type")
+ }
+end
+
+
+
+# RFT_LSCALE_PIX -- Procedure to convert an IRAF image line from type long
+# to the requested output data type with optional scaling using the
+# FITS parameters BSCALE and BZERO.
+
+procedure rft_lscale_pix (inbuf, outbuf, npix, bscale, bzero, data_type)
+
+long inbuf[ARB] # buffer of FITS integers
+pointer outbuf # pointer to output image line
+int npix # number of pixels
+double bscale, bzero # FITS bscale and bzero
+int data_type # IRAF image pixel type
+
+errchk achtll, achtlr, achtld, achtlx
+errchk altml, altmr, altmd, altmx
+
+begin
+ switch (data_type) {
+ case TY_SHORT, TY_USHORT, TY_INT, TY_LONG:
+ call achtll (inbuf, Meml[outbuf], npix)
+ call altml (Meml[outbuf], Meml[outbuf], npix, bscale, bzero)
+ case TY_REAL:
+ call altmlr (inbuf, Memr[outbuf], npix, bscale, bzero)
+ case TY_DOUBLE:
+ call achtld (inbuf, Memd[outbuf], npix)
+ call altmd (Memd[outbuf], Memd[outbuf], npix, bscale, bzero)
+ case TY_COMPLEX:
+ call achtlx (inbuf, Memx[outbuf], npix)
+ call altmx (Memx[outbuf], Memx[outbuf], npix, real (bscale),
+ real (bzero))
+ default:
+ call error (10, "RFT_SCALE_LINE: Illegal IRAF image type")
+ }
+end
+
+
+# RFT_RCHANGE_PIX -- Procedure to change a line of real numbers to the
+# IRAF image type.
+
+procedure rft_rchange_pix (inbuf, outbuf, npix, data_type)
+
+real inbuf[ARB] # array of FITS integers
+pointer outbuf # pointer to IRAF image line
+int npix # number of pixels
+int data_type # IRAF pixel type
+
+errchk achtrl, amovr, achtrd, achtrx
+
+begin
+ switch (data_type) {
+ case TY_SHORT, TY_INT, TY_USHORT, TY_LONG:
+ call achtrl (inbuf, Meml[outbuf], npix)
+ case TY_REAL:
+ call amovr (inbuf, Memr[outbuf], npix)
+ case TY_DOUBLE:
+ call achtrd (inbuf, Memd[outbuf], npix)
+ case TY_COMPLEX:
+ call achtrx (inbuf, Memx[outbuf], npix)
+ default:
+ call error (10, "RFT_RCHANGE_LINE: Illegal IRAF image type")
+ }
+end
+
+
+# RFT_DCHANGE_PIX -- Procedure to change a line of double precision numbers
+# to the IRAF image type.
+
+procedure rft_dchange_pix (inbuf, outbuf, npix, data_type)
+
+double inbuf[ARB] # array of FITS integers
+pointer outbuf # pointer to IRAF image line
+int npix # number of pixels
+int data_type # IRAF pixel type
+
+errchk achtdl, achtdr, amovd, achtdx
+
+begin
+ switch (data_type) {
+ case TY_SHORT, TY_INT, TY_USHORT, TY_LONG:
+ call achtdl (inbuf, Meml[outbuf], npix)
+ case TY_REAL:
+ call achtdr (inbuf, Memr[outbuf], npix)
+ case TY_DOUBLE:
+ call amovd (inbuf, Memd[outbuf], npix)
+ case TY_COMPLEX:
+ call achtdx (inbuf, Memx[outbuf], npix)
+ default:
+ call error (10, "RFT_DCHANGE_LINE: Illegal IRAF image type")
+ }
+end
+
+
+
+# RFT_LCHANGE_PIX -- Procedure to change a line of long integers to the
+# IRAF image type.
+
+procedure rft_lchange_pix (inbuf, outbuf, npix, data_type)
+
+long inbuf[ARB] # array of FITS integers
+pointer outbuf # pointer to IRAF image line
+int npix # number of pixels
+int data_type # IRAF pixel type
+
+begin
+ switch (data_type) {
+ case TY_SHORT, TY_USHORT, TY_INT, TY_LONG:
+ call achtll (inbuf, Meml[outbuf], npix)
+ case TY_REAL:
+ call achtlr (inbuf, Memr[outbuf], npix)
+ case TY_DOUBLE:
+ call achtld (inbuf, Memd[outbuf], npix)
+ case TY_COMPLEX:
+ call achtlx (inbuf, Memx[outbuf], npix)
+ default:
+ call error (10, "RFT_CHANGE_LINE: Illegal IRAF image type")
+ }
+end
+
+
+# RFT_MAP_BLANKS -- Map the blank pixels. Currently only the number of blank
+# pixels is determined without an further mapping.
+
+procedure rft_map_blanks (a, buf, npts, pixtype, blank_value, blank, nbadpix)
+
+long a[ARB] # integer input buffer
+pointer buf # pointer to output image buffer
+int npts # number of points
+int pixtype # image data type
+long blank_value # FITS blank value
+real blank # user blank value
+long nbadpix # number of bad pixels
+
+int i
+
+begin
+ # Do blank mapping here
+ switch (pixtype) {
+ case TY_SHORT, TY_INT, TY_USHORT, TY_LONG:
+ do i = 1, npts {
+ if (a[i] == blank_value) {
+ nbadpix = nbadpix + 1
+ Meml[buf+i-1] = blank
+ }
+ }
+ case TY_REAL:
+ do i = 1, npts {
+ if (a[i] == blank_value) {
+ nbadpix = nbadpix + 1
+ Memr[buf+i-1] = blank
+ }
+ }
+ case TY_DOUBLE:
+ do i = 1, npts {
+ if (a[i] == blank_value) {
+ nbadpix = nbadpix + 1
+ Memd[buf+i-1] = blank
+ }
+ }
+ case TY_COMPLEX:
+ do i = 1, npts {
+ if (a[i] == blank_value) {
+ nbadpix = nbadpix + 1
+ Memx[buf+i-1] = blank
+ }
+ }
+ }
+end
+
+
+# RFT_PIX_LIMITS -- Procedure to determine to maxmimum and minimum values in a
+# line. Note that double precision is somewhat of a special case because
+# MAX_DOUBLE is a lot less than the maximum permitted ieee numbers for iraf.
+
+procedure rft_pix_limits (buf, npix, pixtype, linemin, linemax)
+
+pointer buf # pointer to IRAF image line
+int npix # number of pixels
+int pixtype # output data type
+real linemax, linemin # min and max pixel values
+
+long lmax, lmin
+real rmax, rmin
+double dmax, dmin
+complex xmax, xmin
+
+begin
+ switch (pixtype) {
+ case TY_SHORT, TY_INT, TY_USHORT, TY_LONG:
+ call aliml (Meml[buf], npix, lmin, lmax)
+ linemax = lmax
+ linemin = lmin
+ case TY_REAL:
+ call alimr (Memr[buf], npix, rmin, rmax)
+ linemax = rmax
+ linemin = rmin
+ case TY_DOUBLE:
+ call alimd (Memd[buf], npix, dmin, dmax)
+ if (dmax > MAX_REAL)
+ linemax = INDEFR
+ else
+ linemax = dmax
+ if (dmin < -MAX_REAL)
+ linemin = INDEFR
+ else
+ linemin = dmin
+ case TY_COMPLEX:
+ call alimx (Memx[buf], npix, xmin, xmax)
+ linemax = xmax
+ linemin = xmin
+ default:
+ call error (30, "RFT_PIX_LIMITS: Unknown IRAF type")
+ }
+end
+
+
+# ALTMDR -- procedure to scale a long vector into a real vector using
+# double precision constants to preserve accuracy
+
+procedure altmlr (a, b, npix, bscale, bzero)
+
+long a[ARB] # input array
+real b[ARB] # output array
+int npix # number of pixels
+double bscale, bzero # scaling parameters
+
+int i
+
+begin
+ do i = 1, npix
+ b[i] = a[i] * bscale + bzero
+end
+
+
+# ALTMDR -- procedure to scale a real vector with double precision constants.
+
+procedure altmdr (a, b, npix, bscale, bzero)
+
+real a[ARB] # input array
+real b[ARB] # output array
+int npix # number of pixels
+double bscale, bzero # scaling parameters
+
+int i
+
+begin
+ do i = 1, npix
+ b[i] = a[i] * bscale + bzero
+end
diff --git a/pkg/dataio/fits/fits_rpixels.x b/pkg/dataio/fits/fits_rpixels.x
new file mode 100644
index 00000000..6183120d
--- /dev/null
+++ b/pkg/dataio/fits/fits_rpixels.x
@@ -0,0 +1,154 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <fset.h>
+include <mii.h>
+include <mach.h>
+
+# RFT_INIT_READ_PIXELS and READ_PIXELS -- Read pixel data with record buffering
+# and data type conversion. The input data must meet the MII standard
+# except for possibly in the case of integers having the least significant
+# byte first.
+#
+# Read data in records of len_record and convert to the specified IRAF
+# data type. Successive calls of rft_read_pixels returns the next npix pixels.
+# Read_pixels returns EOF or the number of pixels converted.
+# Init_read_pixels must be called before read_pixels.
+#
+# Error conditions are:
+# 1. A short input record
+# 2. Error in converting the pixels by miiup.
+#
+# This routine is based on the MII unpack routine which is machine dependent.
+# The bitpix must correspond to an MII type. If the lsbf (least significant
+# byte first) flag is YES then the pixels do not satisfy the MII standard.
+# In this case the bytes are first swapped into most significant byte first
+# before the MII unpack routine is called.
+
+int procedure rft_init_read_pixels (npix_record, bitpix, lsbf, spp_type)
+
+int npix_record # number of pixels per input record
+int bitpix # bits per pixel (must correspond to an MII type)
+int lsbf # byte swap?
+int spp_type # SPP data type to be returned
+
+# entry rft_read_pixels (fd, buffer, npix)
+
+int rft_read_pixels
+int fd # input file descriptor
+char buffer[1] # output buffer
+int npix # number of pixels to read
+
+int swap
+int ty_mii, ty_spp, npix_rec, nch_rec, sz_rec, nchars, len_mii, recptr
+int bufsize, i, n, ip, op
+pointer mii, spp
+
+int rft_getbuf(), sizeof(), miilen()
+errchk miilen, mfree, malloc, rft_getbuf, miiupk
+data mii/NULL/, spp/NULL/
+
+begin
+ ty_mii = bitpix
+ ty_spp = spp_type
+ swap = lsbf
+ npix_rec = npix_record
+ nch_rec = npix_rec * sizeof (ty_spp)
+
+ len_mii = miilen (npix_rec, ty_mii)
+ sz_rec = len_mii * SZ_INT32
+
+ if (mii != NULL)
+ call mfree (mii, TY_INT)
+ call malloc (mii, len_mii, TY_INT)
+
+ if (spp != NULL)
+ call mfree (spp, TY_CHAR)
+ call malloc (spp, nch_rec, TY_CHAR)
+
+ ip = nch_rec
+ return (OK)
+
+entry rft_read_pixels (fd, buffer, npix, recptr, bufsize)
+
+ nchars = npix * sizeof (ty_spp)
+ op = 0
+
+ repeat {
+
+ # If data is exhausted read the next record
+ if (ip == nch_rec) {
+
+ i = rft_getbuf (fd, Memi[mii], sz_rec, bufsize, recptr)
+ if (i == EOF)
+ return (EOF)
+
+ if (swap == YES)
+ switch (ty_mii) {
+ case MII_SHORT:
+ call bswap2 (Memi[mii], 1, Memi[mii], 1,
+ sz_rec * SZB_CHAR)
+ case MII_LONG:
+ call bswap4 (Memi[mii], 1, Memi[mii], 1,
+ sz_rec * SZB_CHAR)
+ }
+
+ call miiupk (Memi[mii], Memc[spp], npix_rec, ty_mii, ty_spp)
+
+ ip = 0
+ #recptr = recptr + 1
+ }
+
+ n = min (nch_rec - ip, nchars - op)
+ call amovc (Memc[spp+ip], buffer[1+op], n)
+ ip = ip + n
+ op = op + n
+
+ } until (op == nchars)
+
+ return (npix)
+end
+
+
+# RFT_GETBUF -- Procedure to get the buffer.
+
+int procedure rft_getbuf (fd, buf, sz_rec, bufsize, recptr)
+
+int fd # file descriptor
+char buf[ARB] # buffer to be filled
+int sz_rec # size in chars of record to be read
+int bufsize # buffer size in records
+int recptr # last successful FITS record read
+
+int i, nchars
+int read(), fstati()
+errchk read
+
+begin
+ nchars = 0
+ repeat {
+ iferr {
+ i = read (fd, buf[nchars+1], sz_rec - nchars)
+ } then {
+ call printf ("Error reading FITS record %d\n")
+ if (mod (recptr + 1, bufsize) == 0)
+ call pargi ((recptr + 1) / bufsize)
+ else
+ call pargi ((recptr + 1) / bufsize + 1)
+ call fseti (fd, F_VALIDATE, fstati (fd, F_SZBBLK) / SZB_CHAR)
+ i = read (fd, buf[nchars+1], sz_rec - nchars)
+ }
+
+ if (i == EOF)
+ break
+ else
+ nchars = nchars + i
+
+ } until (nchars >= sz_rec)
+
+ if ((i == EOF) && (nchars == 0))
+ return (EOF)
+ else {
+ recptr = recptr + 1
+ return (nchars)
+ }
+end
diff --git a/pkg/dataio/fits/fits_wheader.x b/pkg/dataio/fits/fits_wheader.x
new file mode 100644
index 00000000..ec06f968
--- /dev/null
+++ b/pkg/dataio/fits/fits_wheader.x
@@ -0,0 +1,469 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <mach.h>
+include <fset.h>
+include "wfits.h"
+
+# WFT_WRITE_HEADER -- Write the FITS headers. The FITS header
+# parameters are encoded one by one until the FITS END keyword is detected.
+# If the long_header switch is set the full FITS header is printed on the
+# standard output. If the short header parameter is specified only the image
+# title and dimensions are printed.
+
+procedure wft_write_header (im, fits, fits_fd)
+
+pointer im # pointer to the IRAF image
+pointer fits # pointer to the FITS structure
+int fits_fd # the FITS file descriptor
+
+char card[LEN_CARD+1], trim_card[LEN_CARD+1]
+int nrecords, recntr, cardptr, cardcnt, stat, cards_per_rec, i
+int wft_card_encode(), wft_set_bitpix(), sizeof(), strncmp()
+int wft_init_card_encode(), fstati()
+
+errchk wft_set_bitpix, wft_get_iraf_typestring, wft_set_scale, wft_set_blank
+errchk wft_fits_set_scale, wft_init_card_encode, wft_card_encode
+errchk wft_init_write_pixels, wft_write_pixels, wft_write_last_record
+
+include "wfits.com"
+
+begin
+ # SET the data and FITS bits per pixel.
+
+ DATA_BITPIX(fits) = sizeof (PIXTYPE(im)) * SZB_CHAR * NBITS_BYTE
+ FITS_BITPIX(fits) = wft_set_bitpix (bitpix, PIXTYPE(im),
+ DATA_BITPIX(fits))
+
+ # Calculate the FITS bscale and bzero parameters. Notice for the
+ # time being that scaling is turned off if IEEE floating point
+ # output is selected. May decide to change this later after
+ # checking the specifications.
+
+ if (FITS_BITPIX(fits) < 0) {
+
+ IRAFMIN(fits) = IM_MIN(im)
+ IRAFMAX(fits) = IM_MAX(im)
+ SCALE(fits) = NO
+ BZERO(fits) = 0.0d0
+ BSCALE(fits) = 1.0d0
+
+ } else if (autoscale == YES) {
+
+ call wft_get_tape_limits (FITS_BITPIX(fits), TAPEMIN(fits),
+ TAPEMAX(fits))
+ call wft_data_limits (im, IRAFMIN(fits), IRAFMAX(fits))
+ call wft_fits_set_scale (im, DATA_BITPIX(fits), FITS_BITPIX(fits),
+ IRAFMIN(fits), IRAFMAX(fits), TAPEMIN(fits), TAPEMAX(fits),
+ SCALE(fits), BSCALE(fits), BZERO(fits))
+
+ } else {
+
+ IRAFMIN(fits) = IM_MIN(im)
+ IRAFMAX(fits) = IM_MAX(im)
+ SCALE(fits) = scale
+ BZERO(fits) = bzero
+ BSCALE(fits) = bscale
+ }
+
+ # If blanks in the image set the blank parameter. Currently information
+ # on blanks is not written out so this is effectively a null operation
+ # in IRAF.
+
+ if (NBPIX(im) > 0)
+ call wft_set_blank (FITS_BITPIX(fits), BLANK(fits),
+ BLANK_STRING(fits))
+
+ # Set the IRAF datatype parameter.
+ call wft_get_iraf_typestring (PIXTYPE(im), TYPE_STRING(fits))
+
+ # Initialize the card counters. These counters are used only for
+ # information printed to the standard output.
+
+ recntr = 1
+ cardptr = 1
+ cardcnt = 1
+ cards_per_rec = len_record / LEN_CARD
+
+ # Get set up to write the FITS header. Initialize for an ASCII write.
+ stat = wft_init_card_encode (im, fits)
+ if (make_image == YES)
+ call wft_init_wrt_pixels (len_record, TY_CHAR, FITS_BYTE, blkfac)
+
+ # Print short header.
+ if (short_header == YES && long_header == NO) {
+
+ call printf ("%-20.20s ")
+ call pargstr (OBJECT(im))
+ do i = 1, NAXIS(im) {
+ if (i == 1) {
+ call printf ("Size = %d")
+ call pargl (NAXISN(im,i))
+ } else {
+ call printf (" x %d")
+ call pargl (NAXISN(im,i))
+ }
+ }
+ call printf ("\n")
+
+ call strlwr (TYPE_STRING(fits))
+ call printf ("\tpixtype=%s bitpix=%d")
+ call pargstr (TYPE_STRING(fits))
+ call pargi (FITS_BITPIX(fits))
+
+ if (fstati (fits_fd, F_BLKSIZE) == 0) {
+ call printf (" blkfac=%d")
+ call pargi (blkfac)
+ } else
+ call printf (" blkfac=fixed")
+
+ if (SCALE(fits) == YES) {
+ call printf (" bscale=%.7g bzero=%.7g\n")
+ call pargd (BSCALE(fits))
+ call pargd (BZERO(fits))
+ } else
+ call printf (" scaling=none\n")
+ call strupr (TYPE_STRING(fits))
+ }
+
+ # Write the cards to the FITS header.
+ repeat {
+
+ # Encode the card.
+ stat = wft_card_encode (im, fits, card)
+ if (stat == NO)
+ next
+
+ # Write the card to the output file if make_image is yes.
+ if (make_image == YES)
+ call wft_write_pixels (fits_fd, card, LEN_CARD)
+
+ # Trim the card and write is to the standard output if
+ # long_header is yes.
+
+ if (long_header == YES) {
+ call wft_trimstr (card, trim_card, LEN_CARD)
+ call printf ("%2d/%2d:-- %s\n")
+ call pargi (recntr)
+ call pargi (cardptr)
+ call pargstr (trim_card)
+ }
+
+ if (mod (cardcnt, cards_per_rec) == 0) {
+ recntr = recntr + 1
+ cardptr = 1
+ } else
+ cardptr = cardptr + 1
+ cardcnt = cardcnt + 1
+
+ } until (strncmp (card, "END ", LEN_KEYWORD) == 0)
+
+ # Issue warning about possible precision loss. Comment this out
+ # for time being, since the short header was modified.
+ #if (SCALE(fits) == YES && bitpix != ERR) {
+ #call printf (
+ #"\tDefault bitpix overridden: maximum precision loss ~%.7g\n")
+ #call pargd (BSCALE(fits))
+ #}
+
+ # Write the last header records.
+ if (make_image == YES) {
+ call wft_write_last_record (fits_fd, nrecords)
+ if (short_header == YES || long_header == YES) {
+ call printf ("\t%d Header ")
+ call pargi (nrecords)
+ }
+ }
+end
+
+
+# WFT_SET_BITPIX -- This procedure sets the FITS bitpix for each image based on
+# either the user given value or the precision of the IRAF data. Notice that
+# the user must explicitly set the bitpix parameter to -16 or -32 to select
+# the IEEE output format.
+
+int procedure wft_set_bitpix (bitpix, datatype, data_bitpix)
+
+int bitpix # the user set bits per pixel, ERR or legal bitpix
+int datatype # the IRAF image data type
+int data_bitpix # the bits per pixel in the data
+
+begin
+ if (bitpix == ERR) {
+ switch (datatype) {
+ case TY_SHORT, TY_INT, TY_USHORT, TY_LONG:
+ if (data_bitpix <= FITS_BYTE)
+ return (FITS_BYTE)
+ else if (data_bitpix <= FITS_SHORT) {
+ #if (datatype == TY_USHORT)
+ #return (FITS_LONG)
+ #else
+ return (FITS_SHORT)
+ } else
+ return (FITS_LONG)
+ case TY_REAL, TY_COMPLEX:
+ return (FITS_REAL)
+ case TY_DOUBLE:
+ return (FITS_DOUBLE)
+ default:
+ call error (2, "SET_BITPIX: Unknown IRAF data type.")
+ }
+ } else
+ return (bitpix)
+end
+
+
+# WFT_GET_IRAF_TYPESTRING -- Procedure to set the iraf datatype keyword.
+
+procedure wft_get_iraf_typestring (datatype, type_str)
+
+int datatype # the IRAF data type
+char type_str[ARB] # the output IRAF type string
+
+begin
+ switch (datatype) {
+ case TY_SHORT:
+ call strcpy ("SHORT", type_str, LEN_STRING)
+ case TY_USHORT:
+ call strcpy ("USHORT", type_str, LEN_STRING)
+ case TY_INT:
+ call strcpy ("INTEGER", type_str, LEN_STRING)
+ case TY_LONG:
+ call strcpy ("LONG", type_str, LEN_STRING)
+ case TY_REAL:
+ call strcpy ("REAL", type_str, LEN_STRING)
+ case TY_DOUBLE:
+ call strcpy ("DOUBLE", type_str, LEN_STRING)
+ case TY_COMPLEX:
+ call strcpy ("COMPLEX", type_str, LEN_STRING)
+ default:
+ call error (3, "IRAF_TYPE: Unknown IRAF image type.")
+ }
+end
+
+
+# WFT_FITS_SET_SCALE -- Procedure to set the FITS scaling parameters if
+# autoscaling is enabled.
+
+procedure wft_fits_set_scale (im, data_bitpix, fits_bitpix, irafmin, irafmax,
+ tapemin, tapemax, scale, bscale, bzero )
+
+pointer im # pointer to IRAF image
+int data_bitpix # bits per pixel of data
+int fits_bitpix # fits bits per pixel
+real irafmin # minimum picture value
+real irafmax # maximum picture value
+double tapemin # minimum tape value
+double tapemax # maximum tape value
+int scale # scale data ?
+double bscale # FITS bscale
+double bzero # FITS bzero
+
+errchk wft_set_scale
+
+begin
+ switch (PIXTYPE(im)) {
+ case TY_SHORT, TY_INT, TY_LONG:
+ if (data_bitpix > fits_bitpix) {
+ scale = YES
+ call wft_set_scale (fits_bitpix, irafmin, irafmax, tapemin,
+ tapemax, bscale, bzero)
+ } else {
+ scale = NO
+ bscale = 1.0d0
+ bzero = 0.0d0
+ }
+ case TY_USHORT:
+ if (data_bitpix > fits_bitpix) {
+ scale = YES
+ call wft_set_scale (fits_bitpix, irafmin, irafmax, tapemin,
+ tapemax, bscale, bzero)
+ } else if (data_bitpix == fits_bitpix) {
+ scale = YES
+ bscale = 1.0d0
+ bzero = 3.2768d4
+ } else {
+ scale = NO
+ bscale = 1.0d0
+ bzero = 0.0d0
+ }
+ case TY_REAL, TY_DOUBLE, TY_COMPLEX:
+ scale = YES
+ call wft_set_scale (fits_bitpix, irafmin, irafmax, tapemin, tapemax,
+ bscale, bzero)
+ default:
+ call error (1, "WRT_HEADER: Unknown IRAF image type.")
+ }
+
+end
+
+
+# WFT_SET_SCALE -- This procedure calculates bscale and bzero for each frame
+# from the FITS bitpix and the maximum and minimum data values.
+
+procedure wft_set_scale (fits_bitpix, datamin, datamax, mintape, maxtape,
+ bscale, bzero)
+
+int fits_bitpix # the FITS integer bits per pixels
+real datamax, datamin # the IRAF image data minimum and maximum
+double mintape, maxtape # min and max FITS tape values
+double bscale, bzero # the calculated bscale and bzero values
+
+double maxdata, mindata, num, denom
+bool rft_equald()
+
+begin
+ # Calculate the maximum and minimum values in the data.
+ maxdata = datamax #+ abs ((datamax / (10.0 ** (NDIGITS_RP - 1))))
+ mindata = datamin #- abs ((datamin / (10.0 ** (NDIGITS_RP - 1))))
+ num = maxdata - mindata
+ denom = (maxtape - mintape) * PREC_RATIO
+
+ # Check for constant image case.
+ #mindata = datamin
+ #maxdata = datamax
+ if (rft_equald (num, 0.0d0)) {
+ bscale = 1.0d0
+ bzero = maxdata
+ } else {
+ bscale = num / denom
+ #bzero = (maxtape / denom) * mindata - (mintape / denom) * maxdata
+ bzero = (maxdata + mindata) / 2.0d0
+ }
+end
+
+
+# WFT_GET_TAPE_LIMITS -- Procedure for calculating the maximum and minimum FITS
+# integer values from the FITS bitpix.
+
+procedure wft_get_tape_limits (fits_bitpix, mintape, maxtape)
+
+int fits_bitpix # the bits per pixel of a FITS integer
+double maxtape, mintape # the maximun and minimum FITS tape integers
+
+begin
+ switch (fits_bitpix) {
+ case FITS_BYTE:
+ maxtape = BYTE_MAX
+ mintape = BYTE_MIN
+ case FITS_SHORT:
+ maxtape = SHORT_MAX
+ mintape = SHORT_MIN
+ case FITS_LONG:
+ maxtape = LONG_MAX
+ mintape = LONG_MIN
+ default:
+ call error (4, "TAPE_LIMITS: Unknown FITS type.")
+ }
+end
+
+
+# WFT_SET_BLANK -- Determine the FITS integer value for a blank pixel from the
+# FITS bitpix. Notice that these are null ops for IEEE floating point format.
+
+procedure wft_set_blank (fits_bitpix, blank, blank_str)
+
+int fits_bitpix # the requested FITS bits per pixel
+long blank # the FITS integer value of a blank pixel
+char blank_str[ARB] # the encoded FITS integer value of a blank pixel
+
+begin
+ switch (fits_bitpix) {
+ case FITS_BYTE:
+ blank = long (BYTE_BLANK)
+ call strcpy ("0", blank_str, LEN_BLANK)
+ case FITS_SHORT:
+ blank = long (SHORT_BLANK)
+ call strcpy ("-32768", blank_str, LEN_BLANK)
+ case FITS_LONG:
+ blank = long (LONG_BLANK)
+ call strcpy ("-2147483648", blank_str, LEN_BLANK)
+ case FITS_REAL:
+ blank = INDEFL
+ call strcpy ("", blank_str, LEN_BLANK)
+ case FITS_DOUBLE:
+ blank = INDEFL
+ call strcpy ("", blank_str, LEN_BLANK)
+ default:
+ call error (5, "SET_BLANK: Unknown FITS type.")
+ }
+end
+
+
+# WFT_INIT_CARD_ENCODE -- This procedure initializes the card encoding
+# procedure. The cards counters are initialized and the number of history cards
+# calculated.
+
+int procedure wft_init_card_encode (im, fits)
+
+# both entry points
+pointer im # pointer to the IRAF image
+pointer fits # pointer to the WFITS structure
+
+# entry wft_card_encode
+int wft_card_encode # entry point
+char card[LEN_CARD+1] # string containing the card image
+
+int cardno, axisno, optiono, hist_ptr, unknown_ptr
+int nstandard, noptions, stat
+int wft_standard_card(), wft_option_card(), wft_last_card()
+int wft_history_card(), wft_unknown_card()
+errchk wft_standard_card, wft_option_card, wft_history_card
+errchk wft_unknown_card, wft_last_card
+
+begin
+ # Initialize the card pointers.
+ cardno = 1
+ axisno = 1
+ optiono = 1
+ unknown_ptr = 1
+ hist_ptr = 1
+
+ # Initilaize the card counters.
+ nstandard = 3 + NAXIS(im)
+ noptions = NOPTIONS + nstandard
+
+ return (YES)
+
+
+# WFT_CARD_ENCODE -- Procedure to encode the FITS header parameters into
+# FITS card images.
+
+entry wft_card_encode (im, fits, card)
+
+ # Fetch the appropriate FITS header card image.
+ if (cardno <= nstandard) {
+ stat = wft_standard_card (cardno, im, fits, axisno, card)
+ } else if (cardno <= noptions) {
+ stat = wft_option_card (im, fits, optiono, card)
+ } else if (wft_unknown_card (im, unknown_ptr, card) == YES) {
+ stat = YES
+ } else if (wft_history_card (im, hist_ptr, card) == YES) {
+ stat = YES
+ } else {
+ stat = wft_last_card (card)
+ }
+
+ cardno = cardno + 1
+
+ return (stat)
+end
+
+
+# WFT_TRIMSTR -- Procedure to trim trailing blanks from a fixed size string.
+
+procedure wft_trimstr (instr, outstr, nchars)
+
+char instr[ARB] # input string
+char outstr[ARB] # output string
+int nchars # last character of instr
+
+int ip
+
+begin
+ call strcpy (instr, outstr, nchars)
+ ip = nchars
+ while (outstr[ip] == ' ')
+ ip = ip - 1
+ outstr[ip+1] = EOS
+end
diff --git a/pkg/dataio/fits/fits_wimage.x b/pkg/dataio/fits/fits_wimage.x
new file mode 100644
index 00000000..7ed00372
--- /dev/null
+++ b/pkg/dataio/fits/fits_wimage.x
@@ -0,0 +1,497 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <imhdr.h>
+include "wfits.h"
+
+# WFT_WRITE_IMAGE -- Procedure to convert IRAF image data to FITS format line by
+# line.
+
+procedure wft_write_image (im, fits, fits_fd)
+
+pointer im # IRAF image descriptor
+pointer fits # FITS data structure
+int fits_fd # FITS file descriptor
+
+int npix, nlines, npix_record, i, stat, nrecords
+long v[IM_MAXDIM]
+pointer tempbuf, buf
+
+int wft_get_image_line()
+errchk malloc, mfree, wft_get_image_line, wft_lscale_line, wft_long_line
+errchk wft_init_write_pixels, wft_write_pixels, wft_write_last_record
+errchk wft_rscale_line, wft_dscale_line
+
+include "wfits.com"
+
+begin
+ if (NAXIS(im) == 0) {
+ if (short_header == YES || long_header == YES) {
+ call printf ("0 Data logical (2880 byte) records written\n")
+ }
+ return
+ }
+
+ # Initialize.
+ npix = NAXISN(im,1)
+ nlines = 1
+ do i = 2, NAXIS(im)
+ nlines = nlines * NAXISN(im, i)
+ npix_record = len_record * FITS_BYTE / abs (FITS_BITPIX(fits))
+
+ call amovkl (long(1), v, IM_MAXDIM)
+ switch (FITS_BITPIX(fits)) {
+ case FITS_REAL:
+
+ # Allocate temporary space.
+ call malloc (tempbuf, npix, TY_REAL)
+
+ # Initialize the pixel write.
+ call wft_init_write_pixels (npix_record, TY_REAL,
+ FITS_BITPIX(fits), blkfac)
+
+ # For the time being explicitly turn off ieee NaN mapping.
+ call ieemapr (NO, NO)
+
+ # Scale the lines, deal with the blanks via the ieee code which
+ # is currently turned off, and write the output records.
+
+ do i = 1, nlines {
+ iferr (stat = wft_get_image_line (im, buf, v, PIXTYPE(im))) {
+ call erract (EA_WARN)
+ call error (10, "WRT_IMAGE: Error writing IRAF image.")
+ }
+ if (stat == EOF )
+ return
+ if (stat != npix)
+ call error (10, "WRT_IMAGE: Error writing IRAF image.")
+ if (SCALE(fits) == YES)
+ call wft_rscale_line (buf, Memr[tempbuf], npix,
+ 1. / BSCALE(fits), -BZERO(fits), PIXTYPE(im))
+ else
+ call wft_real_line (buf, Memr[tempbuf], npix, PIXTYPE(im))
+ call wft_write_pixels (fits_fd, Memr[tempbuf], npix)
+ }
+
+ # Free space.
+ call mfree (tempbuf, TY_REAL)
+
+ case FITS_DOUBLE:
+
+ # Allocate temporary space.
+ call malloc (tempbuf, npix, TY_DOUBLE)
+
+ # Initialize the pixel write.
+ call wft_init_write_pixels (npix_record, TY_DOUBLE,
+ FITS_BITPIX(fits), blkfac)
+
+ # For the time being explicitly turn off ieee NaN mapping.
+ call ieemapd (NO, NO)
+
+ # Scale the lines, deal with the blanks via the ieee code which
+ # is currently turned off, and write the output records.
+
+ do i = 1, nlines {
+ iferr (stat = wft_get_image_line (im, buf, v, PIXTYPE(im))) {
+ call erract (EA_WARN)
+ call error (10, "WRT_IMAGE: Error writing IRAF image.")
+ }
+ if (stat == EOF )
+ return
+ if (stat != npix)
+ call error (10, "WRT_IMAGE: Error writing IRAF image.")
+ if (SCALE(fits) == YES)
+ call wft_dscale_line (buf, Memd[tempbuf], npix,
+ 1. / BSCALE(fits), -BZERO(fits), PIXTYPE(im))
+ else
+ call wft_double_line (buf, Memd[tempbuf], npix,
+ PIXTYPE(im))
+ call wft_write_pixels (fits_fd, Memd[tempbuf], npix)
+ }
+
+ # Free space.
+ call mfree (tempbuf, TY_DOUBLE)
+
+ default:
+
+ # Allocate temporary space.
+ call malloc (tempbuf, npix, TY_LONG)
+
+ # Scale the line, deal with the blanks, and write the output
+ # record. At the moement blanks are not dealt with.
+
+ call wft_init_write_pixels (npix_record, TY_LONG, FITS_BITPIX(fits),
+ blkfac)
+ do i = 1, nlines {
+ iferr (stat = wft_get_image_line (im, buf, v, PIXTYPE(im))) {
+ call erract (EA_WARN)
+ call error (10, "WRT_IMAGE: Error writing IRAF image.")
+ }
+ if (stat == EOF )
+ return
+ if (stat != npix)
+ call error (10, "WRT_IMAGE: Error writing IRAF image.")
+ if (SCALE(fits) == YES)
+ call wft_lscale_line (buf, Meml[tempbuf], npix,
+ 1. / BSCALE(fits), -BZERO(fits), PIXTYPE(im))
+ else
+ call wft_long_line (buf, Meml[tempbuf], npix, PIXTYPE(im))
+ # call map_blanks (im, Meml[tempbuf], blank)
+ call wft_write_pixels (fits_fd, Meml[tempbuf], npix)
+ }
+ # Free space.
+ call mfree (tempbuf, TY_LONG)
+ }
+
+ # Write the final record.
+ call wft_write_last_record (fits_fd, nrecords)
+ if (short_header == YES || long_header == YES) {
+ call printf ("%d Data logical (2880 byte) records written\n")
+ call pargi (nrecords)
+ }
+end
+
+
+# WFT_GET_IMAGE_LINE -- Procedure to fetch the next image line.
+
+int procedure wft_get_image_line (im, buf, v, datatype)
+
+pointer im # IRAF image descriptor
+pointer buf # pointer to image line
+long v[ARB] # imio dimension descriptor
+int datatype # IRAF image data type
+
+int npix
+int imgnll(), imgnlr(), imgnld(), imgnlx()
+errchk imgnll, imgnlr, imgnld, imgnlx
+
+begin
+ switch (datatype) {
+ case TY_SHORT, TY_INT, TY_USHORT, TY_LONG:
+ npix = imgnll (im, buf, v)
+ case TY_REAL:
+ npix = imgnlr (im, buf, v)
+ case TY_DOUBLE:
+ npix = imgnld (im, buf, v)
+ case TY_COMPLEX:
+ npix = imgnlx (im, buf, v)
+ default:
+ call error (11, "GET_IMAGE_LINE: Unknown IRAF image type.")
+ }
+
+ return (npix)
+end
+
+
+# WFT_RSCALE_LINE -- This procedure converts the IRAF data to type real
+# and scales by the FITS parameters bscale and bzero.
+
+procedure wft_rscale_line (buf, outbuffer, npix, bscale, bzero, datatype)
+
+pointer buf # pointer to IRAF image line
+real outbuffer[ARB] # FITS integer buffer
+int npix # number of pixels
+double bscale, bzero # FITS bscale and bzero parameters
+int datatype # data type of image
+
+errchk achtlr, altadr, amovr, achtdr, acthxr
+
+begin
+ switch (datatype) {
+ case TY_SHORT, TY_INT, TY_LONG, TY_USHORT:
+ call achtlr (Meml[buf], outbuffer, npix)
+ call altadr (outbuffer, outbuffer, npix, bzero, bscale)
+ case TY_REAL:
+ call amovr (Memr[buf], outbuffer, npix)
+ call altadr (outbuffer, outbuffer, npix, bzero, bscale)
+ case TY_DOUBLE:
+ call achtdr (Memd[buf], outbuffer, npix)
+ call altadr (outbuffer, outbuffer, npix, bzero, bscale)
+ case TY_COMPLEX:
+ call achtxr (Memx[buf], outbuffer, npix)
+ call altadr (outbuffer, outbuffer, npix, bzero, bscale)
+ default:
+ call error (12, "WFT_RSCALE_LINE: Unknown IRAF image type.")
+ }
+end
+
+
+# WFT_DSCALE_LINE -- This procedure converts the IRAF data to type double with
+# after scaling by the FITS parameters bscale and bzero.
+
+procedure wft_dscale_line (buf, outbuffer, npix, bscale, bzero, datatype)
+
+pointer buf # pointer to IRAF image line
+double outbuffer[ARB] # FITS integer buffer
+int npix # number of pixels
+double bscale, bzero # FITS bscale and bzero parameters
+int datatype # data type of image
+
+errchk achtld, altad, amovd, achtrd, achtxd
+
+begin
+ switch (datatype) {
+ case TY_SHORT, TY_INT, TY_LONG, TY_USHORT:
+ call achtld (Meml[buf], outbuffer, npix)
+ call altad (outbuffer, outbuffer, npix, bzero, bscale)
+ case TY_REAL:
+ call achtrd (Memr[buf], outbuffer, npix)
+ call altad (outbuffer, outbuffer, npix, bzero, bscale)
+ case TY_DOUBLE:
+ call amovd (Memd[buf], outbuffer, npix)
+ call altad (outbuffer, outbuffer, npix, bzero, bscale)
+ case TY_COMPLEX:
+ call achtxd (Memx[buf], outbuffer, npix)
+ call altad (outbuffer, outbuffer, npix, bzero, bscale)
+ default:
+ call error (12, "WFT_DSCALE_LINE: Unknown IRAF image type.")
+ }
+end
+
+
+# WFT_LSCALE_LINE -- This procedure converts the IRAF data to type long with
+# after scaling by the FITS parameters bscale and bzero.
+
+procedure wft_lscale_line (buf, outbuffer, npix, bscale, bzero, datatype)
+
+pointer buf # pointer to IRAF image line
+long outbuffer[ARB] # FITS integer buffer
+int npix # number of pixels
+double bscale, bzero # FITS bscale and bzero parameters
+int datatype # data type of image
+
+errchk altall, altarl, altadl, altaxl
+
+begin
+ switch (datatype) {
+ case TY_SHORT, TY_INT, TY_LONG, TY_USHORT:
+ call altall (Meml[buf], outbuffer, npix, bzero, bscale)
+ case TY_REAL:
+ call altarl (Memr[buf], outbuffer, npix, bzero, bscale)
+ case TY_DOUBLE:
+ call altadl (Memd[buf], outbuffer, npix, bzero, bscale)
+ case TY_COMPLEX:
+ call altaxl (Memx[buf], outbuffer, npix, bzero, bscale)
+ default:
+ call error (12, "WFT_LSCALE_LINE: Unknown IRAF image type.")
+ }
+end
+
+
+# WFT_REAL_LINE -- This procedure converts the IRAF image line to type long with
+# no scaling.
+
+procedure wft_real_line (buf, outbuffer, npix, datatype)
+
+pointer buf # pointer to IRAF image line
+real outbuffer[ARB] # buffer of FITS integers
+int npix # number of pixels
+int datatype # IRAF image datatype
+
+errchk achtlr, achtdr, amovr, achtxr
+
+begin
+ switch (datatype) {
+ case TY_SHORT, TY_INT, TY_LONG, TY_USHORT:
+ call achtlr (Meml[buf], outbuffer, npix)
+ case TY_REAL:
+ call amovr (Memr[buf], outbuffer, npix)
+ case TY_DOUBLE:
+ call achtdr (Memd[buf], outbuffer, npix)
+ case TY_COMPLEX:
+ call achtxr (Memx[buf], outbuffer, npix)
+ default:
+ call error (13, "WFT_REAL_LINE: Unknown IRAF data type.")
+ }
+end
+
+
+# WFT_DOUBLE_LINE -- This procedure converts the IRAF image line to type long
+# with no scaling.
+
+procedure wft_double_line (buf, outbuffer, npix, datatype)
+
+pointer buf # pointer to IRAF image line
+double outbuffer[ARB] # buffer of FITS integers
+int npix # number of pixels
+int datatype # IRAF image datatype
+
+errchk achtld, achtrd, amovd, achtxd
+
+begin
+ switch (datatype) {
+ case TY_SHORT, TY_INT, TY_LONG, TY_USHORT:
+ call achtld (Meml[buf], outbuffer, npix)
+ case TY_REAL:
+ call achtrd (Memr[buf], outbuffer, npix)
+ case TY_DOUBLE:
+ call amovd (Memd[buf], outbuffer, npix)
+ case TY_COMPLEX:
+ call achtxd (Memx[buf], outbuffer, npix)
+ default:
+ call error (13, "WFT_DOUBLE_LINE: Unknown IRAF data type.")
+ }
+end
+
+
+# WFT_LONG_LINE -- This procedure converts the IRAF image line to type long with
+# no scaling.
+
+procedure wft_long_line (buf, outbuffer, npix, datatype)
+
+pointer buf # pointer to IRAF image line
+long outbuffer[ARB] # buffer of FITS integers
+int npix # number of pixels
+int datatype # IRAF image datatype
+
+errchk amovl, achtrl, achtdl, achtxl
+
+begin
+ switch (datatype) {
+ case TY_SHORT, TY_INT, TY_LONG, TY_USHORT:
+ call amovl (Meml[buf], outbuffer, npix)
+ case TY_REAL:
+ call achtrl (Memr[buf], outbuffer, npix)
+ case TY_DOUBLE:
+ call achtdl (Memd[buf], outbuffer, npix)
+ case TY_COMPLEX:
+ call achtxl (Memx[buf], outbuffer, npix)
+ default:
+ call error (13, "WFT_LONG_LINE: Unknown IRAF data type.")
+ }
+end
+
+
+# ALTALL -- Procedure to linearly scale a long vector into a long vector
+# using double precision constants to preserve precision.
+
+procedure altall (a, b, npix, k1, k2)
+
+long a[ARB] # input vector
+long b[ARB] # output vector
+int npix # number of pixels
+double k1, k2 # scaling factors
+
+double dtemp
+int i
+
+begin
+ do i = 1, npix {
+ dtemp = (a[i] + k1) * k2
+ if (dtemp >= 0.0d0)
+ dtemp = dtemp + 0.5d0
+ else
+ dtemp = dtemp - 0.5d0
+ b[i] = dtemp
+ }
+end
+
+
+# ALTARL -- Procedure to linearly scale a real vector into a long vector
+# using double precision constants to preserve precision.
+
+procedure altarl (a, b, npix, k1, k2)
+
+real a[ARB] # input vector
+long b[ARB] # output vector
+int npix # number of pixels
+double k1, k2 # scaling factors
+
+int i
+double dtemp
+
+begin
+ do i = 1, npix {
+ dtemp = (a[i] + k1) * k2
+ if (dtemp >= 0.0d0)
+ dtemp = dtemp + 0.5d0
+ else
+ dtemp = dtemp - 0.5d0
+ b[i] = dtemp
+ }
+end
+
+
+# ALTADL -- Procedure to linearly scale a double vector into a long vector
+# using double precision constants to preserve precision.
+
+procedure altadl (a, b, npix, k1, k2)
+
+double a[ARB] # input vector
+long b[ARB] # output vector
+int npix # number of pixels
+double k1, k2 # scaling factors
+
+int i
+double dtemp
+
+begin
+ do i = 1, npix {
+ dtemp = (a[i] + k1) * k2
+ if (dtemp >= 0.0d0)
+ dtemp = dtemp + 0.5d0
+ else
+ dtemp = dtemp - 0.5d0
+ b[i] = dtemp
+ }
+end
+
+
+# ALTAXL -- Procedure to linearly scale a complex vector into a long vector
+# using double precision constants to preserve precision.
+
+procedure altaxl (a, b, npix, k1, k2)
+
+complex a[ARB] # input vector
+long b[ARB] # output vector
+int npix # number of pixels
+double k1, k2 # scaling factors
+
+int i
+double dtemp
+
+begin
+ do i = 1, npix {
+ dtemp = (a[i] + k1) * k2
+ if (dtemp >= 0.0d0)
+ dtemp = dtemp + 0.5d0
+ else
+ dtemp = dtemp - 0.5d0
+ b[i] = dtemp
+ }
+end
+
+
+# ALTADR -- Procedure to linearly scale a real vector in double precision
+
+procedure altadr (a, b, npix, k1, k2)
+
+real a[ARB] # input vector
+real b[ARB] # output vector
+int npix # number of pixels
+double k1, k2 # scaling factors
+
+int i
+
+begin
+ do i = 1, npix
+ b[i] = (a[i] + k1) * k2
+end
+
+
+# ALTADX -- Procedure to linearly scale a complex vector in double precision
+
+procedure altadx (a, b, npix, k1, k2)
+
+complex a[ARB] # input vector
+complex b[ARB] # output vector
+int npix # number of pixels
+double k1, k2 # scaling factors
+
+int i
+
+begin
+ do i = 1, npix
+ b[i] = (a[i] + k1) * k2
+end
+
diff --git a/pkg/dataio/fits/fits_wpixels.x b/pkg/dataio/fits/fits_wpixels.x
new file mode 100644
index 00000000..7a9389ac
--- /dev/null
+++ b/pkg/dataio/fits/fits_wpixels.x
@@ -0,0 +1,162 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <fset.h>
+include "wfits.h"
+
+# WFT_INIT_WRITE_PIXELS -- This procedure calculates the input and
+# output buffer sizes based in the spp and mii data types and allocates
+# the required space.
+
+procedure wft_init_write_pixels (npix_record, spp_type, bitpix, blkfac)
+
+int npix_record # number of data pixels per record
+int spp_type # pixel data type
+int bitpix # output bits per pixel
+int blkfac # fits blocking factor (0 for disk)
+
+# entry wft_write_pixels, wft_write_last_record
+
+int fd # output file descriptor
+char buffer[1] # input buffer
+int npix # number of pixels in the input buffer
+int nrecords # number of FITS records written
+
+char blank, zero
+int ty_mii, ty_spp, npix_rec, nch_rec, len_mii, sz_rec, nchars, n, nrec
+int bf, szblk
+pointer spp, mii, ip, op
+
+int sizeof(), miilen(), fstati()
+long note()
+errchk malloc, mfree, write, miipak, amovc
+data mii /NULL/, spp/NULL/
+
+begin
+ # Change input parameters into local variables.
+ ty_mii = bitpix
+ ty_spp = spp_type
+ npix_rec = npix_record
+ nch_rec = npix_rec * sizeof (ty_spp)
+ bf = blkfac
+ blank = ' '
+ zero = 0
+
+ # Compute the size of the mii buffer.
+ len_mii = miilen (npix_rec, ty_mii)
+ sz_rec = len_mii * SZ_INT32
+
+ # Allocate space for the buffers.
+ if (spp != NULL)
+ call mfree (spp, TY_CHAR)
+ call malloc (spp, nch_rec, TY_CHAR)
+ if (mii != NULL)
+ call mfree (mii, TY_INT)
+ call malloc (mii, len_mii, TY_INT)
+
+ op = 0
+ nrec = 0
+
+ return
+
+# WFT_WRITE_PIXELS -- Wft_wrt_pixels gets an image line and places it in the
+# output buffer. When the output buffer is full the data are packed by the mii
+# routines and written to the specified output.
+
+entry wft_write_pixels (fd, buffer, npix)
+
+ nchars = npix * sizeof (ty_spp)
+ ip = 0
+
+ repeat {
+
+ # Fill output buffer.
+ n = min (nch_rec - op, nchars - ip)
+ call amovc (buffer[1 + ip], Memc[spp + op], n)
+ ip = ip + n
+ op = op + n
+
+ # Write output record.
+ if (op == nch_rec) {
+ call miipak (Memc[spp], Memi[mii], npix_rec, ty_spp, ty_mii)
+ iferr (call write (fd, Memi[mii], sz_rec)) {
+ if (ty_spp == TY_CHAR) {
+ call printf (" File incomplete: %d logical header")
+ call pargi (nrec)
+ call printf (" (2880 byte) records written\n")
+ call error (18,
+ "WRT_RECORD: Error writing header record.")
+ } else {
+ call printf (" File incomplete: %d logical data")
+ call pargi (nrec)
+ call printf (" (2880 byte) records written\n")
+ call error (19,
+ "WRT_RECORD: Error writing data record.")
+ }
+ }
+
+ nrec = nrec + 1
+ op = 0
+ }
+
+ } until (ip == nchars)
+
+ return
+
+
+# WFT_WRITE_LAST_RECORD -- Procedure to write the last partially filled record
+# to tape. Fill with blanks if header record otherwise fill with zeros.
+
+entry wft_write_last_record (fd, nrecords)
+
+ if (op != 0) {
+
+ # Blank or zero fill the last record.
+ n = nch_rec - op
+ if (ty_spp == TY_CHAR)
+ call amovkc (blank, Memc[spp + op], n)
+ else
+ call amovkc (zero, Memc[spp + op], n)
+
+ # Write last record.
+ call miipak (Memc[spp], Memi[mii], npix_rec, ty_spp, ty_mii)
+ iferr (call write (fd, Memi[mii], sz_rec)) {
+ if (ty_spp == TY_CHAR) {
+ call printf ("File incomplete: %d logical header")
+ call pargi (nrec)
+ call printf (" (2880 byte) records written\n")
+ call error (18,
+ "WRT_LAST_RECORD: Error writing last header record.")
+ } else {
+ call printf ("File incomplete: %d logical data")
+ call pargi (nrec)
+ call printf (" (2880 byte) records written\n")
+ call error (19,
+ "WRT_LAST_RECORD: Error writing last data record.")
+ }
+ }
+
+
+ nrec = nrec + 1
+
+ # Pad out the record if the blocking is non-standard.
+ szblk = fstati (fd, F_BUFSIZE) * SZB_CHAR
+ if ((bf > 0) && mod (szblk, FITS_RECORD) != 0 &&
+ (ty_spp != TY_CHAR)) {
+ szblk = szblk / SZB_CHAR
+ n = note (fd) - 1
+ if (mod (n, szblk) == 0)
+ n = 0
+ else
+ n = szblk - mod (n, szblk)
+ for (op = 1; op <= n; op = op + nch_rec) {
+ szblk = min (nch_rec, n - op + 1)
+ call amovkc (zero, Memc[spp], szblk)
+ #call write (fd, Memc[spp], szblk)
+ }
+ }
+
+ }
+
+ nrecords = nrec
+end
diff --git a/pkg/dataio/fits/fits_write.x b/pkg/dataio/fits/fits_write.x
new file mode 100644
index 00000000..edfc9f83
--- /dev/null
+++ b/pkg/dataio/fits/fits_write.x
@@ -0,0 +1,246 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <fset.h>
+include <error.h>
+include <mach.h>
+include <imhdr.h>
+include "wfits.h"
+
+# WFT_WRITE_FITZ -- Procedure to convert a single IRAF file to a FITS file.
+# If the make_image switch is set the header and pixel files are output
+# to the output destination. If the make_image switch is off the header
+# is printed to the standard output.
+
+procedure wft_write_fitz (iraf_file, fits_file, image_number, nimages)
+
+char iraf_file[ARB] # IRAF file name
+char fits_file[ARB] # FITS file name
+int image_number # the current image number
+int nimages # the number of images
+
+int fits_fd, chars_rec, nchars, ip, min_lenuserarea
+pointer im, sp, fits, envstr
+
+int mtfile(), mtopen(), open(), fnldir(), envfind(), ctoi()
+pointer immap()
+errchk immap, imunmap, open, mtopen, close, smark, salloc, sfree
+errchk delete, wft_write_header, wft_write_image, wft_data_limits
+
+include "wfits.com"
+
+begin
+ # Open the output file. Check whether the output file is a magtape
+ # device or a binary file. If the output file is magtape check
+ # for a legal blocking factor.
+
+ if (image_number == 1 || wextensions == NO) {
+ if (make_image == NO)
+ call strcpy ("dev$null", fits_file, SZ_FNAME)
+ if (mtfile (fits_file) == YES) {
+ chars_rec = (blkfac * len_record * FITS_BYTE) / (SZB_CHAR *
+ NBITS_BYTE)
+ fits_fd = mtopen (fits_file, WRITE_ONLY, chars_rec)
+ } else
+ fits_fd = open (fits_file, NEW_FILE, BINARY_FILE)
+ }
+
+ # Allocate memory for program data structure.
+ call smark (sp)
+ call salloc (fits, LEN_FITS, TY_STRUCT)
+ call salloc (envstr, SZ_FNAME, TY_CHAR)
+
+ # Set up the minimum length of the user area.
+ if (envfind ("min_lenuserarea", Memc[envstr], SZ_FNAME) > 0) {
+ ip = 1
+ if (ctoi (Memc[envstr], ip, min_lenuserarea) <= 0)
+ min_lenuserarea = LEN_USERAREA
+ else
+ min_lenuserarea = max (LEN_USERAREA, min_lenuserarea)
+ } else
+ min_lenuserarea = LEN_USERAREA
+
+ # Write the global header.
+ if (image_number == 1 && gheader == YES) {
+
+ XTENSION(fits) = EXT_PRIMARY
+
+ # Open a dummy image.
+ im = immap ("dev$null", NEW_IMAGE, 0)
+ NAXIS(im) = 0
+ PIXTYPE(im) = TY_SHORT
+ OBJECT(im) = EOS
+ IRAFNAME(fits) = EOS
+
+ if (long_header == YES || short_header == YES) {
+ call printf ("Global header")
+ if (make_image == YES) {
+ call printf (" -> %s[0] ")
+ call pargstr (fits_file)
+ }
+ if (long_header == YES)
+ call printf ("\n")
+ else if (short_header == YES)
+ call printf (" ")
+ }
+ call flush (STDOUT)
+
+ iferr {
+ call wft_write_header (im, fits, fits_fd)
+ if (make_image == YES)
+ call wft_write_image (im, fits, fits_fd)
+ } then {
+
+ # Print the error message.
+ call flush (STDOUT)
+ call erract (EA_WARN)
+
+ # Close files and cleanup.
+ call imunmap (im)
+ #if (image_number == nimages || wextensions == NO)
+ call close (fits_fd)
+ if (make_image == NO)
+ call delete (fits_file)
+ call sfree (sp)
+
+ # Assert an error.
+ call erract (EA_ERROR)
+
+ } else {
+ call imunmap (im)
+ }
+
+ if (long_header == YES)
+ call printf ("\n")
+ }
+
+ # Map the input image. Construct the old iraf name by removing
+ # the directory specification.
+ # Print the id string.
+ if (long_header == YES || short_header == YES) {
+ call printf ("Image %d: %s")
+ call pargi (image_number)
+ call pargstr (iraf_file)
+ }
+
+ # Define whether the image to be written is to be the FITS primary
+ # data image file or a FITS image extension file.
+ if (image_number == 1) {
+ if (wextensions == YES && gheader == YES)
+ XTENSION(fits) = EXT_IMAGE
+ else
+ XTENSION(fits) = EXT_PRIMARY
+ } else {
+ if (wextensions == YES)
+ XTENSION(fits) = EXT_IMAGE
+ else
+ XTENSION(fits) = EXT_PRIMARY
+ }
+
+ im = immap (iraf_file, READ_ONLY, min_lenuserarea)
+ call imgcluster (iraf_file, IRAFNAME(fits), SZ_FNAME)
+ nchars = fnldir (IRAFNAME(fits), IRAFNAME(fits), SZ_FNAME)
+ call strcpy (iraf_file[nchars+1], IRAFNAME(fits), SZ_FNAME)
+
+ # Write header and image.
+ iferr {
+
+ if (short_header == YES || long_header == YES) {
+ if (make_image == YES) {
+ if (wextensions == YES && nimages > 1) {
+ call printf (" -> %s[%d] ")
+ call pargstr (fits_file)
+ if (gheader == YES)
+ call pargi (image_number)
+ else
+ call pargi (image_number - 1)
+ } else {
+ call printf (" -> %s ")
+ call pargstr (fits_file)
+ }
+ }
+ if (long_header == YES)
+ call printf ("\n")
+ else if (short_header == YES)
+ call printf (" ")
+ }
+ call flush (STDOUT)
+
+ call wft_write_header (im, fits, fits_fd)
+ if (make_image == YES)
+ call wft_write_image (im, fits, fits_fd)
+
+ if (long_header == YES)
+ call printf ("\n")
+
+ } then {
+
+ # Print the error message.
+ call flush (STDOUT)
+ call erract (EA_WARN)
+
+ # Close files and cleanup.
+ call imunmap (im)
+ #if (image_number == nimages || wextensions == NO)
+ call close (fits_fd)
+ if (make_image == NO)
+ call delete (fits_file)
+ call sfree (sp)
+
+ # Assert an error.
+ call erract (EA_ERROR)
+
+ } else {
+
+ # Close files and cleanup.
+ call imunmap (im)
+ if (image_number == nimages || wextensions == NO)
+ call close (fits_fd)
+ if (make_image == NO)
+ call delete (fits_file)
+ call sfree (sp)
+ }
+
+end
+
+
+# WFT_DATA_LIMITS -- Procedure to calculate the maximum and minimum data values
+# in an IRAF image. Values are only calculated if the max and min are unknown
+# or the image has been modified since the last values were calculated.
+
+procedure wft_data_limits (im, irafmin, irafmax)
+
+pointer im # image pointer
+real irafmin # minimum picture value
+real irafmax # maximum picture value
+
+int npix
+long v[IM_MAXDIM]
+pointer buf
+real maxval, minval
+int imgnlr()
+errchk imgnlr
+
+begin
+ # Compute the data minimum and maximum if the image values
+ # are undefined out-of-date.
+
+ if (LIMTIME(im) < MTIME(im) && NAXIS(im) > 0) {
+
+ irafmax = -MAX_REAL
+ irafmin = MAX_REAL
+ npix = NAXISN(im,1)
+
+ call amovkl (long(1), v, IM_MAXDIM)
+ while (imgnlr (im, buf, v) != EOF) {
+ call alimr (Memr[buf], npix, minval, maxval)
+ irafmin = min (irafmin, minval)
+ irafmax = max (irafmax, maxval)
+ }
+
+ } else {
+
+ irafmax = IM_MAX(im)
+ irafmin = IM_MIN(im)
+
+ }
+end
diff --git a/pkg/dataio/fits/mkpkg b/pkg/dataio/fits/mkpkg
new file mode 100644
index 00000000..ac5201d0
--- /dev/null
+++ b/pkg/dataio/fits/mkpkg
@@ -0,0 +1,24 @@
+# Make the RFITS / WFITS Tasks
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ fits_cards.x wfits.com wfits.h <imhdr.h>
+ fits_params.x wfits.h <time.h>
+ fits_read.x rfits.com rfits.h <error.h> <fset.h> <imhdr.h>\
+ <mach.h> <plset.h>
+ fits_rheader.x rfits.com rfits.h <ctype.h> <imhdr.h> <imio.h>\
+ <mach.h>
+ fits_rimage.x rfits.com rfits.h <imhdr.h> <fset.h> <mach.h>
+ fits_rpixels.x <fset.h> <mach.h> <mii.h>
+ fits_wheader.x wfits.com wfits.h <fset.h> <imhdr.h> <mach.h>
+ fits_wimage.x wfits.com wfits.h <error.h> <imhdr.h>
+ fits_wpixels.x wfits.h <fset.h> <mach.h>
+ fits_write.x <error.h> wfits.com wfits.h <fset.h> <imhdr.h> <mach.h>
+ fits_files.x <ctype.h> <plset.h>
+ t_rfits.x rfits.com rfits.h <error.h> <fset.h>
+ t_wfits.x wfits.com wfits.h <error.h> <fset.h> <mach.h>
+ ;
diff --git a/pkg/dataio/fits/rfits.com b/pkg/dataio/fits/rfits.com
new file mode 100644
index 00000000..08f44c0e
--- /dev/null
+++ b/pkg/dataio/fits/rfits.com
@@ -0,0 +1,18 @@
+
+# FITS reader common
+
+int len_record # Length of FITS records in bytes
+int data_type # Output data type
+real blank # Blank value
+real fe # Maximum size in megabytes for scan mode
+
+# Option flags
+
+int make_image # Create an IRAF image
+int long_header # Print a long header (FITS header cards)
+int short_header # Print a short header (Title and size)
+int scale # Scale the data
+int old_name # Use old IRAF name?
+
+common /rfitscom/ len_record, data_type, blank, fe, make_image, long_header,
+ short_header, scale, old_name
diff --git a/pkg/dataio/fits/rfits.h b/pkg/dataio/fits/rfits.h
new file mode 100644
index 00000000..bab29220
--- /dev/null
+++ b/pkg/dataio/fits/rfits.h
@@ -0,0 +1,96 @@
+# FITS Definitions
+
+# The FITS standard readable by the FITS reader using these definitions:
+#
+# 1. 8 bits / byte
+# 2. ASCII character code
+# 3. MII integer data format (i.e. 8 bit unsigned integers and 16 and 32
+# bit signed twos complement integers with most significant bytes first.)
+# 4. IEEE 32 and 64 bit floating point format
+#
+#
+# The following deviations from the FITS standard are allowed:
+#
+# 1. The number of FITS bytes per record is normally 2880 or up to 10 times
+# 2880 bytes but may be arbitrarily specified by the user.
+
+# Define the bits per pixel, precision and byte order of the basic FITS types
+
+define FITS_RECORD 2880 # number of bytes in a standard FITS record
+
+define FITS_BYTE 8 # Bits in a FITS byte
+define FITS_SHORT 16 # Bits in a FITS short
+define FITS_LONG 32 # Bits in a FITS long
+define FITS_REAL -32 # Bits in a FITS real * -1
+define FITS_DOUBLE -64 # Bits in a FITS double * -1
+
+define FITSB_PREC 3 # Decimal digits of precision in a FITS byte
+define FITSS_PREC 5 # Decimal digits of precision in a FITS short
+define FITSL_PREC 10 # Decimal digits of precision in a FITS long
+
+define LSBF NO # Least significant byte first
+
+# Define the basic format of a FITS cardimage
+
+define LEN_CARD 80 # Length of FITS card in characters
+define COL_VALUE 11 # Starting column for parameter values
+
+
+# FITS standards not recognized currently by IRAF.
+#
+# 1. SIMPLE SIMPLE = 'F' not implemented, file skipped
+# 2. GROUPS Group data not currently implemented, file skippped
+
+# FITS extension currently recognised by IRAF
+
+define EXT_PRIMARY 1 # recognized and read
+define EXT_IMAGE 2 # recognized and read
+define EXT_TABLE 3 # recognized and skipped
+define EXT_BINTABLE 4 # recognized and skipped
+define EXT_UNKNOWN 5 # unrecognized and skipped
+define EXT_SPECIAL 6 # undefined
+
+
+# Values for the following quantities are stored in the structure below.
+
+define LEN_FITS (20 + SZ_FNAME + 1)
+
+define FITS_BSCALE Memd[P2D($1)] # FITS scaling parameter
+define FITS_BZERO Memd[P2D($1+2)] # FITS zero parameter
+define BLANK_VALUE Meml[P2L($1+4)] # Blank value
+define BLANKS Memi[$1+5] # YES if blank keyword in header
+define BITPIX Memi[$1+6] # Bits per pixel (Must be an MII type)
+define SCALE Memi[$1+7] # Scale the data ?
+define SIMPLE Memi[$1+8] # Standard FITS format
+define NRECORDS Memi[$1+9] # Number of FITS logical records
+define EXTEND Memi[$1+10] # FITS extensions may be present
+define XTENSION Memi[$1+11] # FITS extension type
+define PCOUNT Memi[$1+12] # Number of random parameters
+define GCOUNT Memi[$1+13] # Number of groups
+define GLOBALHDR Memi[$1+14] # Global header may be present
+define INHERIT Memi[$1+15] # Inherit global header if present
+define IRAFNAME Memc[P2C($1+16)] # Old IRAF name
+
+# Mapping of additional IRAF header parameters
+
+define PIXTYPE IM_PIXTYPE($1)
+define NBPIX IM_NBPIX($1)
+define IRAFMAX IM_MAX($1)
+define IRAFMIN IM_MIN($1)
+define LIMTIME IM_LIMTIME($1)
+define LEN_USERAREA 28800
+
+# Mapping of FITS Keywords to IRAF image header
+
+define NAXIS IM_NDIM($1)
+define NAXISN IM_LEN($1,$2)
+define OBJECT IM_TITLE($1)
+define HISTORY IM_HISTORY($1)
+define UNKNOWN Memc[($1+IMU-1)*SZ_STRUCT+1] # All unrecognized keywords
+ # are stored here
+# Miscellaneous definitions.
+
+define SZ_OBJECT SZ_IMTITLE
+define SZ_HISTORY SZ_IMHIST
+define SZ_FCTYPE SZ_CTYPE
+define LEN_TYPESTR 8
diff --git a/pkg/dataio/fits/t_rfits.x b/pkg/dataio/fits/t_rfits.x
new file mode 100644
index 00000000..06c55ec1
--- /dev/null
+++ b/pkg/dataio/fits/t_rfits.x
@@ -0,0 +1,216 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <fset.h>
+include "rfits.h"
+
+define NTYPES 7 # the number of image data types
+
+# RFITS -- Read FITS format data. Further documentation given in rfits.hlp
+
+procedure t_rfits()
+
+int inlist, outlist, len_inlist, len_outlist
+int file_number, offset, stat, first_file, last_file
+pointer sp, infile, file_list, outfile, ext_list, in_fname, out_fname
+pointer pl, axes
+
+bool clgetb(), pl_linenotempty()
+#char clgetc()
+int rft_get_image_type(), clgeti(), mtfile(), strlen(), btoi(), fntlenb()
+int rft_read_fitz(), fntgfnb(), fstati(), mtneedfileno(), fntrfnb()
+pointer fntopnb(), rft_flist()
+real clgetr(), rft_fe()
+
+include "rfits.com"
+
+begin
+ # Set up the standard output to flush on a newline.
+ if (fstati (STDOUT, F_REDIR) == NO)
+ call fseti (STDOUT, F_FLUSHNL, YES)
+
+ # Allocate working space.
+ call smark (sp)
+ call salloc (infile, SZ_FNAME, TY_CHAR)
+ call salloc (file_list, SZ_LINE, TY_CHAR)
+ call salloc (outfile, SZ_FNAME, TY_CHAR)
+ call salloc (ext_list, SZ_LINE, TY_CHAR)
+ call salloc (in_fname, SZ_FNAME, TY_CHAR)
+ call salloc (out_fname, SZ_FNAME, TY_CHAR)
+ call salloc (axes, 2, TY_INT)
+
+ # Get RFITS parameters.
+ call clgstr ("fits_file", Memc[infile], SZ_FNAME)
+ long_header = btoi (clgetb ("long_header"))
+ short_header = btoi (clgetb ("short_header"))
+ len_record = FITS_RECORD
+ old_name = btoi (clgetb ("oldirafname"))
+ make_image = btoi (clgetb ("make_image"))
+
+ # Open the input file list.
+ call clgstr ("file_list", Memc[ext_list], SZ_LINE)
+ if (mtfile (Memc[infile]) == YES) {
+ inlist = NULL
+ if (mtneedfileno (Memc[infile]) == YES) {
+ call strcpy (Memc[ext_list], Memc[file_list], SZ_LINE)
+ } else {
+ call sprintf (Memc[file_list], SZ_LINE, "1[%s]")
+ call pargstr (Memc[ext_list])
+ }
+ } else {
+ inlist = fntopnb (Memc[infile], NO)
+ len_inlist = fntlenb (inlist)
+ if (len_inlist > 0) {
+ if (Memc[ext_list] == EOS) {
+ call sprintf (Memc[file_list], SZ_LINE, "1-%d[0]")
+ call pargi (len_inlist)
+ #call pargstr (Memc[ext_list])
+ } else {
+ call sprintf (Memc[file_list], SZ_LINE, "1-%d[%s]")
+ call pargi (len_inlist)
+ call pargstr (Memc[ext_list])
+ }
+ } else {
+ call sprintf (Memc[file_list], SZ_LINE, "0[%s]")
+ call pargstr (Memc[ext_list])
+ }
+ }
+
+ # Decode the ranges string.
+ pl = rft_flist (Memc[file_list], first_file, last_file, len_inlist)
+ if (pl == NULL || len_inlist <= 0)
+ call error (1, "T_RFITS: Illegal file/extensions number list")
+
+ # Open the output file list.
+ if (make_image == YES) {
+ call clgstr ("iraf_file", Memc[outfile], SZ_FNAME)
+ if (Memc[outfile] == EOS) {
+ if (old_name == YES)
+ call mktemp ("tmp$", Memc[outfile], SZ_FNAME)
+ else
+ call error (0, "T_RFITS: Undefined output file name")
+ }
+ outlist = fntopnb (Memc[outfile], NO)
+ len_outlist = fntlenb (outlist)
+ offset = clgeti ("offset")
+ } else {
+ Memc[outfile] = EOS
+ outlist = NULL
+ len_outlist = 1
+ }
+ if ((len_outlist > 1) && (len_outlist != len_inlist))
+ call error (0,
+ "T_RFITS: Output and input lists have different lengths")
+
+ # Get the remaining parameters. Use the string in_fname as a
+ # temporary variable.
+ #data_type = rft_get_image_type (clgetc ("datatype"))
+ call clgstr ("datatype", Memc[in_fname], SZ_FNAME)
+ data_type = rft_get_image_type (Memc[in_fname])
+ scale = btoi (clgetb ("scale"))
+ blank = clgetr ("blank")
+
+ # Get the scan size parameter.
+ fe = rft_fe (Memc[infile])
+
+ # Read successive FITS files, convert and write into a numbered
+ # succession of output IRAF files.
+
+ do file_number = first_file, last_file {
+
+ # Get the next file number.
+ Memi[axes] = 1
+ Memi[axes+1] = file_number
+ if (! pl_linenotempty (pl, Memi[axes]))
+ next
+
+ # Get the input file name.
+ if (inlist != NULL) {
+ if (fntgfnb (inlist, Memc[in_fname], SZ_FNAME) == EOF)
+ call error (0, "T_RFITS: Error reading input file name")
+ } else {
+ if (mtneedfileno (Memc[infile]) == YES)
+ call mtfname (Memc[infile], file_number, Memc[in_fname],
+ SZ_FNAME)
+ else
+ call strcpy (Memc[infile], Memc[in_fname], SZ_FNAME)
+ }
+
+ # Get the output file name.
+ if (outlist == NULL) {
+ Memc[out_fname] = EOS
+ } else if (len_inlist > len_outlist) {
+ if (fntrfnb (outlist, 1, Memc[out_fname], SZ_FNAME) == EOF)
+ call strcpy (Memc[outfile], Memc[out_fname], SZ_FNAME)
+ if (len_inlist > 1) {
+ call sprintf (Memc[out_fname+strlen(Memc[out_fname])],
+ SZ_FNAME, "%04d")
+ call pargi (file_number + offset)
+ }
+ } else if (fntgfnb (outlist, Memc[out_fname], SZ_FNAME) == EOF)
+ call error (0, "T_RFITS: Error reading output file name")
+
+ # Convert FITS file to the output IRAF file. If EOT is reached
+ # then exit. If an error is detected then print a warning and
+ # continue with the next file.
+
+ iferr (stat = rft_read_fitz (Memc[in_fname], Memc[out_fname],
+ pl, file_number))
+ call erract (EA_FATAL)
+ if (stat == EOF)
+ break
+ }
+
+ if (inlist != NULL)
+ call fntclsb (inlist)
+ if (outlist != NULL)
+ call fntclsb (outlist)
+ if (pl != NULL)
+ call pl_close (pl)
+
+ call sfree (sp)
+end
+
+
+# RFT_GET_IMAGE_TYPE -- Convert a character to and IRAF image type.
+
+int procedure rft_get_image_type (c)
+
+char c
+
+int type_codes[NTYPES], i
+string types "usilrdx"
+int stridx()
+data type_codes /TY_USHORT, TY_SHORT, TY_INT, TY_LONG, TY_REAL,
+ TY_DOUBLE, TY_COMPLEX/
+begin
+ i = stridx (c, types)
+ if (i == 0)
+ return (ERR)
+ else
+ return (type_codes[stridx(c,types)])
+end
+
+
+# RFT_FE -- Fetch the maximum file size in MB for tape scanning mode.
+
+real procedure rft_fe (file)
+
+char file[ARB] # the input file name
+
+pointer gty
+real fe
+int mtfile(), gtygeti()
+pointer mtcap()
+errchk gtygeti()
+
+begin
+ if (mtfile (file) == NO)
+ return (0.0)
+ iferr (gty = mtcap (file))
+ return (0.0)
+ iferr (fe = gtygeti (gty, "fe"))
+ fe = 0.0
+ call gtyclose (gty)
+ return (fe)
+end
diff --git a/pkg/dataio/fits/t_wfits.x b/pkg/dataio/fits/t_wfits.x
new file mode 100644
index 00000000..256b9cde
--- /dev/null
+++ b/pkg/dataio/fits/t_wfits.x
@@ -0,0 +1,253 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <error.h>
+include <fset.h>
+include "wfits.h"
+
+# T_WFITS -- This procedure converts a series of IRAF image files to
+# FITS image files.
+
+procedure t_wfits ()
+
+char iraf_files[SZ_FNAME] # list of IRAF images
+char fits_files[SZ_FNAME] # list of FITS files
+bool newtape # new or used tape ?
+char in_fname[SZ_FNAME] # input file name
+char out_fname[SZ_FNAME] # output file name
+char fextn[SZ_FNAME] # the fits extension
+
+char ch
+int imlist, flist, nimages, nfiles, file_number, addext, index
+bool clgetb(), streq()
+double clgetd()
+int imtopen(), imtlen (), wft_get_bitpix(), clgeti(), imtgetim()
+int mtfile(), btoi(), fstati(), fntlenb(), fntgfnb(), mtneedfileno()
+int wft_blkfac(), fntrfnb(), strlen(), strldx()
+pointer fntopnb()
+
+include "wfits.com"
+
+begin
+ # Flush on a newline if STDOUT has not been redirected.
+ if (fstati (STDOUT, F_REDIR) == NO)
+ call fseti (STDOUT, F_FLUSHNL, YES)
+
+ # Open iraf_files template and determine number of files in list.
+ call clgstr ("iraf_files", iraf_files, SZ_FNAME)
+ imlist = imtopen (iraf_files)
+ nimages = imtlen (imlist)
+
+ # Get the wfits parameters.
+ if (nimages == 1)
+ wextensions = NO
+ else
+ wextensions = btoi (clgetb ("extensions"))
+ if (wextensions == NO)
+ gheader = NO
+ else
+ gheader = btoi (clgetb ("global_hdr"))
+ long_header = btoi (clgetb ("long_header"))
+ short_header = btoi (clgetb ("short_header"))
+ make_image = btoi (clgetb ("make_image"))
+
+ # Get the FITS bits per pixel and the FITS logical record size.
+ bitpix = wft_get_bitpix (clgeti ("bitpix"))
+ len_record = FITS_RECORD
+
+ # Get the scaling parameters.
+ scale = btoi (clgetb ("scale"))
+ if (scale == YES) {
+ if (clgetb ("autoscale"))
+ autoscale = YES
+ else {
+ bscale = clgetd ("bscale")
+ bzero = clgetd ("bzero")
+ autoscale = NO
+ }
+ } else {
+ autoscale = NO
+ bscale = 1.0d0
+ bzero = 0.0d0
+ }
+
+ # Get the output file name and type (tape or disk). If no tape file
+ # number is given for output, the user is asked if the tape is blank
+ # or contains data. If the tape is blank output begins at BOT,
+ # otherwise at EOT.
+
+ call clgstr ("fextn", fextn, SZ_FNAME)
+ ch = '.'
+ if (make_image == YES) {
+ call clgstr ("fits_files", fits_files, SZ_FNAME)
+ if (mtfile (fits_files) == YES) {
+ flist = NULL
+ if (mtneedfileno (fits_files) == YES) {
+ newtape = clgetb ("newtape")
+ if (newtape)
+ call mtfname (fits_files, 1, out_fname, SZ_FNAME)
+ else
+ call mtfname (fits_files, EOT, out_fname, SZ_FNAME)
+ } else {
+ call strcpy (fits_files, out_fname, SZ_FNAME)
+ newtape = false
+ }
+ } else {
+ flist = fntopnb (fits_files, NO)
+ nfiles = fntlenb (flist)
+ if (wextensions == YES && nfiles > 1)
+ call error (0,
+ "Only one output FITS extensions file can be written")
+ if ((nfiles > 1) && (nfiles != nimages))
+ call error (0,
+ "T_WFITS: Input and output lists are not the same length")
+ }
+ } else {
+ fits_files[1] = EOS
+ flist = NULL
+ }
+
+ # Get the fits file blocking factor.
+ blkfac = wft_blkfac (fits_files, clgeti ("blocking_factor"))
+
+ # Loop through the list of input images files.
+
+ file_number = 1
+ while (imtgetim (imlist, in_fname, SZ_FNAME) != EOF) {
+
+ # Get the output file name. If single file output to disk, use
+ # name fits_file. If multiple file output to disk, the file number
+ # is added to the output file name, if no output name list is
+ # supplied. If an output name list is supplied then the names
+ # are extracted one by one from that list.
+
+ if (make_image == YES) {
+ if (mtfile (fits_files) == YES) {
+ if (wextensions == NO && file_number == 2)
+ call mtfname (out_fname, EOT, out_fname, SZ_FNAME)
+ } else if (nfiles > 1) {
+ if (fntgfnb (flist, out_fname, SZ_FNAME) == EOF)
+ call error (0, "Error reading output file name")
+ if (fextn[1] != EOS) {
+ addext = OK
+ index = strldx (ch, out_fname)
+ if (index > 0) {
+ if (streq (fextn, out_fname[index+1]))
+ addext = ERR
+ else
+ addext = OK
+ }
+ if (addext == OK){
+ call strcat (".", out_fname, SZ_FNAME)
+ call strcat (fextn, out_fname, SZ_FNAME)
+ }
+ }
+ } else {
+ if (fntrfnb (flist, 1, out_fname, SZ_FNAME) == EOF)
+ call strcpy (fits_files, out_fname, SZ_FNAME)
+ if (nimages > 1 && wextensions == NO) {
+ call sprintf (out_fname[strlen(out_fname)+1], SZ_FNAME,
+ "%04d")
+ call pargi (file_number)
+ }
+ if (fextn[1] != EOS) {
+ addext = OK
+ index = strldx (ch, out_fname)
+ if (index > 0) {
+ if (streq (fextn, out_fname[index+1]))
+ addext = ERR
+ else
+ addext = OK
+ }
+ if (addext == OK){
+ call strcat (".", out_fname, SZ_FNAME)
+ call strcat (fextn, out_fname, SZ_FNAME)
+ }
+ }
+ }
+ }
+
+ # Write each output file.
+ iferr (call wft_write_fitz (in_fname, out_fname, file_number,
+ nimages)) {
+ call printf ("Error writing file: %s\n")
+ call pargstr (out_fname)
+ call erract (EA_WARN)
+ break
+ } else
+ file_number = file_number + 1
+ }
+
+ # Close up the input and output lists.
+ call clpcls (imlist)
+ if (flist != NULL)
+ call fntclsb (flist)
+end
+
+
+# WFT_GET_BITPIX -- This procedure fetches the user determined bitpix or ERR if
+# the bitpix is not one of the permitted FITS types.
+
+int procedure wft_get_bitpix (bitpix)
+
+int bitpix
+
+begin
+ switch (bitpix) {
+ case FITS_BYTE, FITS_SHORT, FITS_LONG, FITS_REAL, FITS_DOUBLE:
+ return (bitpix)
+ default:
+ return (ERR)
+ }
+end
+
+
+# WFT_BLKFAC -- Get the fits tape blocking factor.
+
+int procedure wft_blkfac (file, ublkfac)
+
+char file[ARB] # the input file name
+int ublkfac # the user supplied blocking factor
+
+int bs, fb, blkfac
+pointer gty
+int mtfile(), mtcap(), gtygeti()
+errchk mtcap(), gtygeti()
+
+begin
+ # Return a blocking factor of 1 if the file is a disk file.
+ if (mtfile (file) == NO)
+ return (0)
+
+ # Open the tapecap device entry for the given device, and get
+ # the device block size and default FITS blocking factor
+ # parameters.
+
+ iferr (gty = mtcap (file))
+ return (max (ublkfac,1))
+ iferr (bs = gtygeti (gty, "bs")) {
+ call gtyclose (gty)
+ return (max (ublkfac,1))
+ }
+ iferr (fb = max (gtygeti (gty, "fb"), 1))
+ fb = 1
+
+ # Determine whether the device is a fixed or variable blocked
+ # device. Set the fits blocking factor to the value of the fb
+ # parameter if device is fixed block or if the user has
+ # requested the default blocking factor. Set the blocking factor
+ # to the user requested value if the device supports variable
+ # blocking factors.
+
+ if (bs == 0) {
+ if (ublkfac <= 0)
+ blkfac = fb
+ else
+ blkfac = ublkfac
+ } else
+ blkfac = fb
+
+ call gtyclose (gty)
+
+ return (blkfac)
+end
diff --git a/pkg/dataio/fits/wfits.com b/pkg/dataio/fits/wfits.com
new file mode 100644
index 00000000..04779ef3
--- /dev/null
+++ b/pkg/dataio/fits/wfits.com
@@ -0,0 +1,17 @@
+# FITS common block
+
+double bscale # FITS scaling factor
+double bzero # FITS offset factor
+int bitpix # Output bits per pixel
+int len_record # Record length in FITS bytes
+int long_header # Print long header?
+int short_header # Print short header?
+int make_image # Make a FITS image?
+int scale # Scale the data with bzero and bscale?
+int autoscale # Allow program to calculate bscale and bzero?
+int blkfac # FITS tape blocking factor
+int wextensions # Write a FITS extensions file
+int gheader # Write a global FITS extensions file header
+
+common /wfitscom/ bscale, bzero, bitpix, len_record, long_header, short_header,
+ make_image, scale, autoscale, blkfac, wextensions, gheader
diff --git a/pkg/dataio/fits/wfits.h b/pkg/dataio/fits/wfits.h
new file mode 100644
index 00000000..a36caa89
--- /dev/null
+++ b/pkg/dataio/fits/wfits.h
@@ -0,0 +1,128 @@
+# WFITS header file
+
+# The basic FITS data structure
+
+define LEN_FITS (44 + SZ_FNAME + 1)
+
+define BSCALE Memd[P2D($1)] # FITS bscale value
+define BZERO Memd[P2D($1+2)] # FITS bzero value
+define TAPEMAX Memd[P2D($1+4)] # IRAF tape max
+define TAPEMIN Memd[P2D($1+6)] # IRAF tape min
+define IRAFMAX Memr[P2R($1+8)] # IRAF image maximum
+define IRAFMIN Memr[P2R($1+9)] # IRAF image minimum
+define BLANK Meml[P2L($1+10)] # FITS blank value
+define FITS_BITPIX Memi[$1+11] # FITS bits per pixel
+define DATA_BITPIX Memi[$1+12] # Data bits per pixel
+define SCALE Memi[$1+13] # Scale data?
+define XTENSION Memi[$1+14] # FITS extension type
+define BLANK_STRING Memc[P2C($1+19)] # String containing FITS blank value
+define TYPE_STRING Memc[P2C($1+31)] # String containing IRAF type
+define IRAFNAME Memc[P2C($1+41)] # IRAF file name
+
+
+# Define the FITS record size
+
+define FITS_RECORD 2880 # Size of standard FITS record (bytes)
+
+# Define the supported FITS extensions
+
+define EXT_PRIMARY 1 # the primary data array
+define EXT_IMAGE 2 # the image extension
+
+# Define the FITS data types
+
+define FITS_BYTE 8 # Number of bits in a FITS byte
+define FITS_SHORT 16 # Number of bits in a FITS short
+define FITS_LONG 32 # Number of bits in a FITS long
+define FITS_REAL -32 # Number of bits in a FITS real * -1
+define FITS_DOUBLE -64 # Number of bits in a FITS double * -1
+
+# Define the FITS precision in decimal digits
+
+define BYTE_PREC 3 # Precision of FITS byte
+define SHORT_PREC 5 # Precision of FITS short
+define LONG_PREC 10 # Precision of FITS long
+
+# Define the FITS blank data values
+
+define BYTE_BLANK 0.0d0 # Blank value for a FITS byte
+define SHORT_BLANK -3.2768d4 # Blank value for a FITS short
+define LONG_BLANK -2.147483648d9 # Blank value for a FITS long
+#define BYTE_BLANK 0 # Blank value for a FITS byte
+#define SHORT_BLANK -32768 # Blank value for a FITS short
+#define LONG_BLANK -2147483648 # Blank value for a FITS long
+
+# Define the FITS integer max and min values
+
+define BYTE_MAX 2.55d2 # Max value for a FITS byte
+define BYTE_MIN 1.0d0 # Min value for a FITS byte
+define SHORT_MAX 3.2767d4 # Max value for a FITS short
+define SHORT_MIN -3.2767d4 # Min value for a FITS short
+define LONG_MAX 2.147483647d9 # Max value for a FITS long
+define LONG_MIN -2.147483647d9 # Min value for a FITS long
+define PREC_RATIO .99978637d0 # Tape span reduction factor
+
+# Define the FITS card image parameters
+
+define LEN_CARD 80 # Length of FITS header card
+define LEN_KEYWORD 8 # Length of FITS keyword
+define LEN_NAXIS_KYWRD 5 # Length of the NAXIS keyword string
+define COL_VALUE 11 # First column of value field
+
+# Mapping of FITS task keywords to IRAF image header keywords
+
+define NAXIS IM_NDIM($1) # Number of dimensions
+define NAXISN IM_LEN($1, $2) # Length of each dimension
+define OBJECT IM_TITLE($1) # Image title
+define HISTORY IM_HISTORY($1) # History
+define UNKNOWN Memc[($1+IMU-1)*SZ_STRUCT+1] # IRAF user area
+
+define PIXTYPE IM_PIXTYPE($1) # Image pixel type
+define NBPIX IM_NBPIX($1) # Number of bad pixels
+define LIMTIME IM_LIMTIME($1) # Last modify limits time
+define MTIME IM_MTIME($1) # Last modify time
+define CTIME IM_CTIME($1) # Create time
+
+define LEN_USERAREA 28800 # Default user area size
+
+# Set up a structure for the WFITS parameters
+
+# Define the required keywords
+
+define FIRST_CARD 1 # FITS simple/xtension parameter
+define SECOND_CARD 2 # FITS bitpix parameter
+define THIRD_CARD 3 # FITS naxis parameter
+
+# Define the optional FITS KEYWORD parameters
+
+define NOPTIONS 15 # Number of optional keywords
+
+define KEY_EXTEND 1 # FITS EXTEND keyword
+define KEY_PCOUNT 2 # Number of random parameter
+define KEY_GCOUNT 3 # Number of groups
+define KEY_BSCALE 4 # FITS bscale parameter
+define KEY_BZERO 5 # FITS bzero parameter
+define KEY_BUNIT 6 # FITS physical units
+define KEY_BLANK 7 # FITS value of blank pixel
+define KEY_OBJECT 8 # FITS title string
+define KEY_ORIGIN 9 # Origin of FITS tape
+define KEY_DATE 10 # Date the tape was written
+define KEY_IRAFNAME 11 # Root name of IRAF image
+define KEY_IRAFMAX 12 # Maximum value of IRAF image
+define KEY_IRAFMIN 13 # Minimum value of IRAF image
+define KEY_IRAFBP 14 # Bits per pixel in IRAF image
+define KEY_IRAFTYPE 15 # IRAF image data type
+
+define LEN_STRING 8 # Minimum length of a string parameter
+define LEN_DATE 19 # Length of the new date string
+define LEN_OBJECT 63 # Maximum length of string parameter
+define LEN_ALIGN 18 # Maximum length for aligning parameter
+define LEN_ORIGIN 9 # Length of origin string
+define LEN_BLANK 11 # Length of the blank string
+define NDEC_REAL 7 # Precision of real data
+define NDEC_DOUBLE 11 # Precision of double precision data
+
+# Miscellaneous
+
+define CENTURY 1900
+define NEW_CENTURY 2000
diff --git a/pkg/dataio/import.par b/pkg/dataio/import.par
new file mode 100644
index 00000000..ba2792c1
--- /dev/null
+++ b/pkg/dataio/import.par
@@ -0,0 +1,30 @@
+# IMPORT Task Parameter File
+binfiles,s,a,"",,,"The list of input binary files to be read"
+images,s,a,"",,,"The list of output IRAF images to be written"
+format,s,h,"sense",,,"The type of format to be processed
+
+ INPUT PARAMETERS
+"
+dims,s,h,"",,,"Input file dimension string"
+pixtype,s,h,"",,,"Input pixel type"
+interleave,i,h,0,,,"Pixel interleave type"
+bswap,s,h,"no","|no|yes|i2|i4||",,"Byte-swap flag"
+hskip,i,h,0,,,"Bytes preceeding pixel data to skip"
+tskip,i,h,0,,,"Bytes to skip at end of file"
+bskip,i,h,0,,,"Bytes between image bands to skip"
+lskip,i,h,0,,,"Bytes to skip at font of each line"
+lpad,i,h,0,,,"Bytes to skip at end of each line
+
+ OUTPUT PARAMETERS
+"
+output,s,h,"image","|none|image|list|info|",,"Type of output to generate"
+outtype,s,h,"s","|u|s|i|l|r|d||",,"The data type of the output image"
+outbands,s,h,"",,,"Output image band expressions"
+imheader,s,h,"",,,"File of FITS-like header info to add
+"
+database,s,h,"dataio$import/images.dat",,,"Format database"
+verbose,b,h,no,,,"Verbose output during conversion?"
+
+# Mode parameter
+buffer_size,i,h,64,,,"Number of image lines to buffer in memory"
+mode,s,h,"ql",,,"mode parameter"
diff --git a/pkg/dataio/import/README b/pkg/dataio/import/README
new file mode 100644
index 00000000..20ab02a1
--- /dev/null
+++ b/pkg/dataio/import/README
@@ -0,0 +1,2 @@
+This directory contains the source code for the IMPORT <something>-to-IRAF
+format conversion task.
diff --git a/pkg/dataio/import/bltins/README b/pkg/dataio/import/bltins/README
new file mode 100644
index 00000000..c15b9cfe
--- /dev/null
+++ b/pkg/dataio/import/bltins/README
@@ -0,0 +1,13 @@
+ This directory contains the source code for the 'builtin' formats
+converted with IMPORT. Here we implement three formats that require different
+levels of processing: the GIF format uses LZW compression and a colormap for
+pixel storage and requires the most work, Sun Rasterfiles have various formats
+that may require colormap application or RLE decoding, and lastly the X
+Window Dump format that fits the generic binary raster model with the exception
+of an 8-bit file with a colormap.
+ Because formats are defined in the data base the user is unaware of
+any special processing that occurs unless implementing a new format that
+requires partivular handling. In the case of colormap files the example of
+XWD can be followed and all that's needed is a routine to read the colormap
+from the image. 'Builtin' formats must, however, be declared in the source
+import$ipbuiltin.x to route execution to the format-specific code.
diff --git a/pkg/dataio/import/bltins/ipcmap.x b/pkg/dataio/import/bltins/ipcmap.x
new file mode 100644
index 00000000..ad44a7cf
--- /dev/null
+++ b/pkg/dataio/import/bltins/ipcmap.x
@@ -0,0 +1,76 @@
+include "../import.h"
+
+# IPCMAP.X -- Procedures for colormap application or lookup.
+
+
+# IP_GRAY_CMAP - Apply the colormap to an array of pixels and convert the
+# pixels to grayscale using the NTSC formula.
+
+procedure ip_gray_cmap (data, len, cmap)
+
+char data[ARB] #i pixel values
+int len #i how many of 'em
+pointer cmap #i colormap pointer
+
+int i
+short val, ip_gcmap_val()
+
+begin
+ do i = 1, len {
+ val = data[i] + 1
+ data[i] = ip_gcmap_val (val, cmap)
+ }
+end
+
+
+# IP_GCMAP_VAL - Apply the colormap to a single pixel and convert the
+# result to grayscale using the NTSC formula.
+
+short procedure ip_gcmap_val (pix, cmap)
+
+char pix #i pixel value
+pointer cmap #i colormap pointer
+
+short val
+
+begin
+ val = (R_COEFF * CMAP(cmap,IP_RED,pix) +
+ G_COEFF * CMAP(cmap,IP_GREEN,pix) +
+ B_COEFF * CMAP(cmap,IP_BLUE,pix))
+ return (val)
+end
+
+
+# IP_RGB_VAL - Given a grayscale value figure out what the requested color
+# component is from the colormap.
+
+short procedure ip_rgb_val (pix, cmap, color)
+
+char pix #i pixel value
+pointer cmap #i colormap pointer
+int color #i requested color
+
+short i, val
+
+begin
+ # Need to optimize this later... For now just compute the colormap
+ # grayscale values until we find a match and use the index.
+ i = 0
+ val = -1
+ while (val != pix && i <= 256) {
+ i = i + 1
+ val = (R_COEFF * CMAP(cmap,IP_RED,i) +
+ G_COEFF * CMAP(cmap,IP_GREEN,i) +
+ B_COEFF * CMAP(cmap,IP_BLUE,i))
+ }
+
+ switch (color) {
+ case IP_RED:
+ val = CMAP(cmap,IP_RED,i-1)
+ case IP_GREEN:
+ val = CMAP(cmap,IP_GREEN,i-1)
+ case IP_BLUE:
+ val = CMAP(cmap,IP_BLUE,i-1)
+ }
+ return (val)
+end
diff --git a/pkg/dataio/import/bltins/ipgif.x b/pkg/dataio/import/bltins/ipgif.x
new file mode 100644
index 00000000..a7394e18
--- /dev/null
+++ b/pkg/dataio/import/bltins/ipgif.x
@@ -0,0 +1,883 @@
+include "../import.h"
+
+
+# IPGIF.X - Source file for the GIF builtin format converter.
+
+
+# Define the GIF data structure
+define MAX_CODE_ENTRIES 4096 # because LZW has 12 bit max
+define SZ_GIFSTRUCT 35
+define SZ_GIFCODE 280
+define SZ_GIFEXTN 256
+define SZ_GIFSTACK (2*MAX_CODE_ENTRIES+2)
+define SZ_GIFCTAB (2*MAX_CODE_ENTRIES+2)
+
+define GIF_FD Memi[$1] # GIF file descriptor
+define GIF_WIDTH Memi[$1+1] # Screen width
+define GIF_HEIGHT Memi[$1+2] # Screen height
+define GIF_CP Memi[$1+3] # Colormap pointer
+define GIF_BITPIX Memi[$1+4] # Bits per pixel
+define GIF_COLRES Memi[$1+5] # Color resolution
+define GIF_BACKGROUND Memi[$1+6] # background color (unused?)
+define GIF_ASPECT Memi[$1+7] # Aspect ratio
+define GIF_IMNUM Memi[$1+8] # Image number
+define GIF_CMAP Memi[$1+9] # Global colormap (ptr)
+
+define GIF_EXTBP Memi[$1+10] # Extension buffer (ptr)
+define GIF_CODEP Memi[$1+11] # Code table buffer (ptr)
+define GIF_CTABP Memi[$1+12] # Code table (ptr)
+define GIF_STACKP Memi[$1+13] # Stack (ptr)
+define GIF_CURBIT Memi[$1+14] # Decoder var
+define GIF_LASTBIT Memi[$1+15] # Decoder var
+define GIF_DONE Memi[$1+16] # Decoder var
+define GIF_LASTBYTE Memi[$1+17] # Decoder var
+define GIF_ZERO_DATABLOCK Memi[$1+18] # Decoder var
+define GIF_SP Memi[$1+19] # stack pointer
+
+define GIF_CLEAR_CODE Memi[$1+20] # LZW clear code
+define GIF_END_CODE Memi[$1+21] # LZW end code
+define GIF_FIRST_CODE Memi[$1+22] # LZW decoder var
+define GIF_OLD_CODE Memi[$1+23] # LZW decoder var
+define GIF_MAX_CODE Memi[$1+24] # LZW free code
+define GIF_MAX_CODE_SIZE Memi[$1+25] # LZW upper limit
+define GIF_CODE_SIZE Memi[$1+26] # LZW current code size
+define GIF_SET_CODE_SIZE Memi[$1+27] # LZW input code size
+define GIF_FRESH Memi[$1+28] # LZW init var
+
+# The following are used for GIF89a only.
+define GIF_TRANSPARENT Memi[$1+30] # Transparent Color Index
+define GIF_DELAYTIME Memi[$1+31] # Delay time
+define GIF_INPUTFLAG Memi[$1+32] # User input flag
+define GIF_DISPOSAL Memi[$1+33] # Disposal Method
+
+# Array macros.
+define CODEBUF Memc[GIF_CODEP($1)+$2]
+define EXTBUF Memc[GIF_EXTBP($1)+$2]
+define CODETAB Memc[GIF_CTABP($1)+($2*MAX_CODE_ENTRIES)+$3]
+define STACK Memc[GIF_STACKP($1)+$2]
+
+#---------------------------------------------------------------------------
+
+define INTERLACE 040X # Image descriptor flags
+define LOCAL_COLORMAP 080X
+
+# Define the flags for the GIF89a extension blocks.
+define GE_PLAINTEXT 001X # Plain Text Extension
+define GE_APPLICATION 0FFX # Application Extension
+define GE_COMMENT 0FEX # Comment Extension
+define GE_GCONTROL 0F9X # Graphics Control Extension
+
+define DEBUG false
+define VDEBUG false
+
+
+# IP_GIF - Read and process a GIF format file into an IRAF image.
+
+procedure ip_gif (ip, fname, info_only, verbose)
+
+pointer ip #i import struct pointer
+char fname[ARB] #i file name
+int info_only #i print out image info only?
+int verbose #i verbosity flag
+
+pointer gif
+int fd
+int bitpix, use_global_cmap, interlace
+int width, height, version
+char ch
+short sig[7], screen[12]
+
+pointer gif_open()
+int btoi(), strncmp(), gif_rdbyte(), gif_getbytes()
+int shifti()
+
+long filepos
+common /gifcom/ filepos
+
+begin
+ # Allocate the gif struct pointer.
+ gif = gif_open()
+ GIF_FD(gif) = IP_FD(ip)
+ fd = GIF_FD(gif)
+
+ # The GIF signature is verified in the database file but check it
+ # here anyway.
+ filepos = 1
+ call ip_lseek (fd, BOF)
+ if (gif_getbytes(fd, sig, 6) != OK)
+ call error (0, "Error reading GIF magic number.")
+ if (strncmp(sig[4],"87a",3) == 0)
+ version = 87
+ else if (strncmp(sig[4],"89a",3) == 0)
+ version = 89
+ else
+ call error (0, "Bad version: File is not a GIF 87a or 89A")
+
+ # Now read the screen descriptor.
+ if (gif_getbytes(fd, screen, 7) != OK)
+ call error (0, "Error reading screen descriptor.")
+
+ GIF_WIDTH(gif) = screen[1] + (256 * screen[2])
+ GIF_HEIGHT(gif) = screen[3] + (256 * screen[4])
+ GIF_BITPIX(gif) = shifti (2, and(int(screen[5]),07X))
+ GIF_COLRES(gif) = shifti (and(int(screen[5]), 070X), -3) + 1
+ GIF_BACKGROUND(gif) = screen[6]
+ GIF_ASPECT(gif) = screen[7]
+ if (DEBUG) {
+ call eprintf ("w:%d h:%d bpix:%d ncol:%d bkg:%d asp:%d\n")
+ call pargi(GIF_WIDTH(gif)); call pargi(GIF_HEIGHT(gif))
+ call pargi(GIF_BITPIX(gif)); call pargi(GIF_COLRES(gif))
+ call pargi(GIF_BACKGROUND(gif)); call pargi(GIF_ASPECT(gif))
+ call flush (STDERR)
+ }
+
+ # We'll set the buffer size to the full image to speed processing.
+ IP_SZBUF(ip) = GIF_HEIGHT(gif)
+
+ # See if we have a global colormap.
+ if (and (int(screen[5]), LOCAL_COLORMAP) > 0)
+ call gif_rdcmap (gif, GIF_BITPIX(gif), GIF_CMAP(gif))
+ IP_CMAP(ip) = GIF_CMAP(gif)
+
+ # Now process the rest of the image blocks.
+ GIF_IMNUM(gif) = 0
+ repeat {
+ if (gif_rdbyte(fd, ch) != OK) {
+ call error (0, "Bad data read.")
+ }
+
+ if (ch == ';') { # GIF terminator
+ break
+ }
+
+ if (ch == '!') { # Extension block
+ # Read the extension function code.
+ if (gif_rdbyte(fd, ch) != OK)
+ call error (0, "Bad data read.")
+ call gif_extension (gif, ch, IP_VERBOSE(ip))
+ next
+ }
+
+ if (ch != ',') { # not a valid start character
+ if (ch != '\0') { # quietly allow a NULL block
+ call eprintf ("Ignoring bogus start char 0x%02x.")
+ call pargc (ch)
+ }
+ next
+ }
+
+ # Read the current image descriptor block. There may be more
+ # than one image in a file so we'll just copy each image into
+ # a separate band of the output image (should be rare).
+ GIF_IMNUM(gif) = GIF_IMNUM(gif) + 1
+ if (gif_getbytes (fd, screen, 9) != OK)
+ call error (0, "Bad scene descriptor")
+
+ # See if this image has a local colormap. There supposedly aren't
+ # a lot of files that use this (GIF89a only) but we'll read it
+ # anyway so we don't get stung on file positioning.
+ if (and (int(screen[9]), LOCAL_COLORMAP) == LOCAL_COLORMAP)
+ use_global_cmap = NO
+ else
+ use_global_cmap = YES
+
+ # Unpack the image descriptor into useful things.
+ bitpix = shifti (1, (and (int(screen[9]), 07X) + 1))
+ interlace = btoi (and (int(screen[9]), INTERLACE) == INTERLACE)
+ width = screen[5] + (screen[6] * 256)
+ height = screen[7] + (screen[8] * 256)
+ if (DEBUG) {
+ call eprintf ("global_cmap:%d bitpix:%d ")
+ call pargi(use_global_cmap); call pargi(bitpix)
+ call eprintf ("interlace:%d w:%d h:%d\n")
+ call pargi(interlace); call pargi(width); call pargi(height)
+ }
+
+ if (info_only == NO) {
+ if (use_global_cmap == NO) {
+ # Process the image with a local colormap.
+ call gif_rdcmap (gif, bitpix, GIF_CMAP(gif))
+ call gif_read_image (ip, gif, width, height,
+ GIF_CMAP(gif), interlace)
+ } else {
+ # Process the image with the global colormap.
+ call gif_read_image (ip, gif, width, height,
+ GIF_CMAP(gif), interlace)
+ }
+ } else {
+ call ip_gif_info (ip, fname, version, width, height,
+ GIF_BITPIX(gif), use_global_cmap, interlace, verbose)
+ break
+ }
+ }
+
+ # Clean up.
+ call gif_close (gif)
+ IP_CMAP(ip) = NULL
+end
+
+
+# IP_GIF_INFO - Print information about the GIF file.
+
+procedure ip_gif_info (ip, fname, version, width, height, colres, global,
+ interlace, verbose)
+
+pointer ip #i task struct pointer
+char fname[ARB] #i file name
+int version #i GIF version
+int width, height #i image dimensions
+int colres #i number of colormap entries
+int global #i image has global colormap
+int interlace #i image is interlaced
+int verbose #i verbosity flag
+
+begin
+ # If not verbose print a one-liner.
+ if (verbose == NO) {
+# call printf ("Input file:\n\t")
+ call printf ("%s: %20t%d x %d \t\tCompuServe GIF %da format file\n")
+ call pargstr (fname)
+ call pargi (width)
+ call pargi (height)
+ call pargi (version)
+
+ # Print out the format comment if any.
+# if (IP_COMPTR(ip) != NULL) {
+# if (COMMENT(ip) != '\0') {
+# call printf ("%s\n")
+# call pargstr (COMMENT(ip))
+# }
+# call strcpy ("\0", COMMENT(ip), SZ_LINE)
+# }
+ return
+ }
+
+ # Print a more verbose description.
+ call printf ("%s: %20tCompuServe GIF %da Format File\n")
+ call pargstr (fname)
+ call pargi (version)
+
+ # Print out the format comment if any.
+ if (IP_COMPTR(ip) != NULL) {
+ if (COMMENT(ip) != '\0') {
+ call printf ("%s\n")
+ call pargstr (COMMENT(ip))
+ }
+ call strcpy ("\0", COMMENT(ip), SZ_LINE)
+ }
+
+ call printf ("%20tResolution:%38t%d x %d\n")
+ call pargi (width)
+ call pargi (height)
+
+ call printf ("%20tPixel storage: %38t%s\n")
+ if (interlace == YES)
+ call pargstr ("Interlaced order")
+ else
+ call pargstr ("Sequential order")
+
+ call printf ("%20tByte Order: %38t%s\n")
+ call pargstr ("LSB first")
+
+ call printf ("%20tType: %38t%s\n")
+ call pargstr ("8-bit Color indexed")
+
+ call printf ("%20t%s Colormap: %38t%d entries\n")
+ if (global == YES)
+ call pargstr ("Global")
+ else
+ call pargstr ("Local")
+ call pargi (colres)
+
+ call printf ("%20tCompression: %38t%s\n")
+ call pargstr ("Lempel-Ziv and Welch (LZW)")
+end
+
+
+# GIF_OPEN - Open the GIF structure descriptor.
+
+pointer procedure gif_open ()
+
+pointer gif
+
+begin
+ iferr (call calloc (gif, SZ_GIFSTRUCT, TY_STRUCT))
+ call error (0, "Error allocating GIF structure.")
+
+ # Allocate the extension and code buffers.
+ iferr (call calloc (GIF_CODEP(gif), SZ_GIFCODE, TY_CHAR))
+ call error (0, "Error allocating GIF code buffer pointer.")
+ iferr (call calloc (GIF_EXTBP(gif), SZ_GIFEXTN, TY_CHAR))
+ call error (0, "Error allocating GIF extension pointer.")
+ iferr (call calloc (GIF_CTABP(gif), SZ_GIFCTAB, TY_CHAR))
+ call error (0, "Error allocating code table pointer.")
+ iferr (call calloc (GIF_STACKP(gif), SZ_GIFSTACK, TY_CHAR))
+ call error (0, "Error allocating GIF stack pointer.")
+
+ # Initialize some of the variables to non-zero values.
+ GIF_ZERO_DATABLOCK(gif) = NO
+ GIF_TRANSPARENT(gif) = -1
+ GIF_DELAYTIME(gif) = -1
+ GIF_INPUTFLAG(gif) = -1
+
+ return (gif)
+end
+
+
+# GIF_CLOSE - Close the GIF structure descriptor.
+
+procedure gif_close (gif)
+
+pointer gif #i GIF struct pointer
+
+begin
+ call mfree (GIF_STACKP(gif), TY_CHAR)
+ call mfree (GIF_CTABP(gif), TY_CHAR)
+ call mfree (GIF_EXTBP(gif), TY_CHAR)
+ call mfree (GIF_CODEP(gif), TY_CHAR)
+
+ if (GIF_CMAP(gif) != NULL)
+ call mfree (GIF_CMAP(gif), TY_CHAR)
+ call mfree (gif, TY_STRUCT)
+end
+
+
+# GIF_READ_IMAGE - Read the image raster from the file. Decompress the
+# LZW compressed data stream into 8-bit pixels.
+
+procedure gif_read_image (ip, gif, width, height, cmap, interlace)
+
+pointer ip #i task struct pointer
+pointer gif #i GIF struct pointer
+int width, height #i image dimensions
+pointer cmap #i colormap pointer
+int interlace #i interlace flag
+
+pointer im, op, out, data
+char csize, pix, val
+int i, v, xpos, ypos, pass
+int nlines, line, percent
+
+pointer ip_evaluate()
+int gif_rdbyte(), gif_lzw_rdbyte()
+short ip_gcmap_val()
+
+begin
+ # Get the initial code_size for the compression routines.
+ if (gif_rdbyte(GIF_FD(gif), csize) != OK)
+ call error (0, "EOF or read error on image data.")
+ call gif_lzw_init (gif, csize)
+
+ # Patch up the pixtype param if needed.
+ call ip_fix_pixtype (ip)
+
+ # See if we need to create any outbands operands if the user didn't.
+ if (IP_NBANDS(ip) == ERR)
+ call ip_fix_outbands (ip)
+
+ im = IP_IM(ip)
+ op = PTYPE(ip,GIF_IMNUM(gif))
+ call malloc (data, width, TY_CHAR)
+ IO_DATA(op) = data
+ IO_NPIX(op) = width
+
+ # Get the pixels.
+ xpos = 0
+ ypos = 0
+ pass = 0
+ nlines = 0
+ percent = 0
+ repeat {
+ v = gif_lzw_rdbyte (gif)
+ if (v < 0)
+ break # at the EOF
+ else {
+ if (cmap != NULL && IP_USE_CMAP(ip) == YES) {
+ # Apply the colormap since this is just an index.
+ val = v + 1
+ pix = ip_gcmap_val (val, cmap)
+ } else
+ pix = char (v)
+ Memc[data+xpos] = pix # assign the pixel
+ }
+
+ xpos = xpos + 1
+ if (xpos == width) {
+ xpos = 0
+ nlines = nlines + 1
+
+ # Evaluate outbands expression.
+ do i = 1, IP_NBANDS(ip) {
+ out = ip_evaluate (ip, O_EXPR(ip,i))
+
+ # Write bands to output image
+ if (IP_OUTPUT(ip) != IP_NONE) {
+ line = ypos + 1
+ call ip_wrline (ip, im, out, GIF_WIDTH(gif), line,
+ (GIF_IMNUM(gif)-1)*IP_NBANDS(ip)+i)
+ }
+ call evvfree (out)
+ }
+
+ # Print percent done if being verbose
+ if (IP_VERBOSE(ip) == YES) {
+ if (nlines * 100 / height >= percent + 10) {
+ percent = percent + 10
+ call printf (" Status: %2d%% complete\r")
+ call pargi (percent)
+ call flush (STDOUT)
+ }
+ }
+
+ # if the image is interlaced adjust the line number accordingly,
+ # otherwise just increment it.
+ if (interlace == YES) {
+ switch (pass) {
+ case 0, 1:
+ ypos = ypos + 8
+ case 2:
+ ypos = ypos + 4
+ case 3:
+ ypos = ypos + 2
+ }
+
+ if (ypos >= height) {
+ pass = pass + 1
+ switch (pass) {
+ case 1:
+ ypos = 4
+ case 2:
+ ypos = 2
+ case 3:
+ ypos = 1
+ }
+ }
+ } else {
+ # Non-interlaced GIF so just increment the line number.
+ ypos = ypos + 1
+ }
+ }
+ }
+
+ if (IP_VERBOSE(ip) == YES) {
+ call printf (" Status: Done \n")
+ call flush (STDOUT)
+ }
+
+ # Clean up the data pointer.
+ call mfree (data, TY_CHAR)
+end
+
+
+# GIF_RDCMAP - Read a colormap (local or global) from the GIF file.
+
+procedure gif_rdcmap (gif, ncolors, cmap)
+
+pointer gif #i GIF struct pointer
+int ncolors #i number of colors to read
+pointer cmap #u local or global colormap ptr
+
+int i
+char rgb[3]
+int gif_getbytes()
+
+begin
+ if (cmap == NULL)
+ iferr (call calloc (cmap, 3*CMAP_SIZE, TY_CHAR))
+ call error (0, "Error allocating color map.")
+
+ do i = 1, ncolors {
+ # Read RGB colors.
+ if (gif_getbytes (GIF_FD(gif), rgb, 3) != OK)
+ call error (0, "Bad GIF colormap - not enough colors.")
+
+ # Load the colormap.
+ CMAP(cmap,IP_RED,i) = rgb[1]
+ CMAP(cmap,IP_GREEN,i) = rgb[2]
+ CMAP(cmap,IP_BLUE,i) = rgb[3]
+ }
+end
+
+
+# GIF_EXTENSION - Process a GIF extension block. For now we'll just ignore
+# these when converting the image but read the data blocks anyway. We should
+# still be able to read the image but won't take advantage of the GIF89a
+# extensions.
+
+procedure gif_extension (gif, label, verbose)
+
+pointer gif #i Gif struct pointer
+char label #i GIF extension label
+int verbose #i print verbose info?
+
+pointer sp, buf
+int val
+int and(), gif_get_data_block()
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_GIFCODE, TY_CHAR)
+
+ switch (label) {
+ case GE_PLAINTEXT: # Plain Text Extension
+ if (verbose == YES) {
+ call eprintf ("Warning: Ignoring a Plain Text Extension.\n")
+ call flush (STDERR)
+ }
+ case GE_APPLICATION: # Application Extension
+ if (verbose == YES) {
+ call eprintf ("Warning: Ignoring an Application Extension.\n")
+ call flush (STDERR)
+ }
+ case GE_COMMENT: # Comment Extension
+ # Simply print out the comment.
+ while (gif_get_data_block (gif, Memc[buf]) != 0) {
+ if (verbose == YES) {
+ call printf ("Comment: %s\n")
+ call pargstr (Memc[buf])
+ }
+ }
+ call sfree (sp)
+ return
+ case GE_GCONTROL: # Graphic Control Extension
+ # Process the graphic control block.
+ val = gif_get_data_block (gif, Memc[buf])
+ GIF_DISPOSAL(gif) = and (int(Memc[buf]/4), 07X)
+ GIF_INPUTFLAG(gif) = and (int(Memc[buf]/2), 01X)
+ GIF_DELAYTIME(gif) = Memc[buf+1] + (256 * Memc[buf+2])
+ if (and(int(Memc[buf]),01X) == 1)
+ GIF_TRANSPARENT(gif) = Memc[buf+3]
+
+ while (gif_get_data_block (gif, Memc[buf]) != 0)
+ ;
+
+ call sfree (sp)
+ return
+ default:
+ call eprintf ("Warning: Unknown extension label (0x%02x).\n")
+ call pargc (label)
+ call flush (STDERR)
+ }
+
+ # If we get here then we've ignored an extension but still need to
+ # eat the data blocks.
+ while (gif_get_data_block (gif, Memc[buf]) != 0)
+ ;
+
+ call sfree (sp)
+end
+
+
+# GIF_LZW_INIT - Initialize the LZW decompression variables.
+
+procedure gif_lzw_init (gif, input_code_size)
+
+pointer gif #i GIF struct pointer
+char input_code_size #i input code size
+
+int i, shifti()
+
+begin
+ GIF_SET_CODE_SIZE(gif) = input_code_size
+ GIF_CODE_SIZE(gif) = GIF_SET_CODE_SIZE(gif) + 1
+ GIF_CLEAR_CODE(gif) = shifti (1, GIF_SET_CODE_SIZE(gif))
+ GIF_END_CODE(gif) = GIF_CLEAR_CODE(gif) + 1
+ GIF_MAX_CODE_SIZE(gif) = 2 * GIF_CLEAR_CODE(gif)
+ GIF_MAX_CODE(gif) = GIF_CLEAR_CODE(gif) + 2
+
+ GIF_CURBIT(gif) = 0 # initialize the code vars
+ GIF_LASTBIT(gif) = 0
+ GIF_DONE(gif) = NO
+
+ GIF_FRESH(gif) = YES
+
+ # Initialize the code table.
+ for (i = 0; i < GIF_CLEAR_CODE(gif); i=i+1) {
+ CODETAB(gif,0,i) = 0
+ CODETAB(gif,1,i) = i
+ }
+ for (; i < MAX_CODE_ENTRIES; i=i+1) {
+ CODETAB(gif,0,i) = 0
+ CODETAB(gif,1,0) = 0
+ }
+
+ GIF_SP(gif) = 0
+end
+
+
+
+# GIF_LZW_RDBYTE -
+
+int procedure gif_lzw_rdbyte (gif)
+
+pointer gif #i GIF struct pointer
+
+pointer sp, buf
+int i, count
+int code, incode
+
+int gif_get_code(), gif_get_data_block()
+
+begin
+ if (GIF_FRESH(gif) == YES) {
+ GIF_FRESH(gif) = NO
+ repeat {
+ GIF_OLD_CODE(gif) = gif_get_code (gif, GIF_CODE_SIZE(gif))
+ GIF_FIRST_CODE(gif) = GIF_OLD_CODE(gif)
+ } until (GIF_FIRST_CODE(gif) != GIF_CLEAR_CODE(gif))
+ return (GIF_FIRST_CODE(gif))
+ }
+
+ if (GIF_SP(gif) > 0) {
+ GIF_SP(gif) = GIF_SP(gif) - 1
+ return (STACK(gif,GIF_SP(gif)))
+ }
+
+ code = gif_get_code (gif, GIF_CODE_SIZE(gif))
+ while (code >= 0) {
+
+ # The Clear Code sets everything back to its initial value, then
+ # reads the immediately subsequent code as uncompressed data.
+ if (code == GIF_CLEAR_CODE(gif)) {
+ for (i = 0; i < GIF_CLEAR_CODE(gif); i=i+1) {
+ CODETAB(gif,0,i) = 0
+ CODETAB(gif,1,i) = i
+ }
+ for ( ; i < MAX_CODE_ENTRIES; i=i+1) {
+ CODETAB(gif,0,i) = 0
+ CODETAB(gif,1,i) = 0
+ }
+ GIF_CODE_SIZE(gif) = GIF_SET_CODE_SIZE(gif) + 1
+ GIF_MAX_CODE_SIZE(gif) = 2 * GIF_CLEAR_CODE(gif)
+ GIF_MAX_CODE(gif) = GIF_CLEAR_CODE(gif) + 2
+ GIF_SP(gif) = 0
+ GIF_OLD_CODE(gif) = gif_get_code (gif, GIF_CODE_SIZE(gif))
+ GIF_FIRST_CODE(gif) = GIF_OLD_CODE(gif)
+ return (GIF_FIRST_CODE(gif))
+
+ # If this is the End Code we'll clean up a little before returning.
+ } else if (code == GIF_END_CODE(gif)) {
+ if (GIF_ZERO_DATABLOCK(gif) == YES)
+ return (ERR)
+
+ call smark (sp)
+ call salloc (buf, 260, TY_CHAR)
+
+ repeat {
+ count = gif_get_data_block (gif, Memc[buf])
+ } until (count <= 0)
+
+ if (count != 0) {
+ call eprintf (
+ "Missing EOD in data stream (common occurance)")
+ }
+ call sfree (sp)
+ return (ERR)
+ }
+
+ # Must be data so save it in incode.
+ incode = code
+
+ # If it's greater or equal than the Free Code it's not in the hash
+ # table yet, repeat the last character decoded.
+ if (code >= GIF_MAX_CODE(gif)) {
+ STACK(gif, GIF_SP(gif)) = GIF_FIRST_CODE(gif)
+ GIF_SP(gif) = GIF_SP(gif) + 1
+ code = GIF_OLD_CODE(gif)
+ }
+
+ while (code >= GIF_CLEAR_CODE(gif)) {
+ STACK(gif, GIF_SP(gif)) = CODETAB(gif,1,code)
+ GIF_SP(gif) = GIF_SP(gif) + 1
+ if (code == CODETAB(gif,0,code))
+ call error (0, "Circular GIF code table entry.")
+ code = CODETAB(gif,0,code)
+ }
+
+ GIF_FIRST_CODE(gif) = CODETAB(gif,1,code)
+ STACK(gif, GIF_SP(gif)) = GIF_FIRST_CODE(gif)
+ GIF_SP(gif) = GIF_SP(gif) + 1
+
+ if (VDEBUG) {
+ call eprintf("code=%d gmax=%d gmaxsz=%d 4096 old:%d frst:%d\n")
+ call pargi(code) ; call pargi(GIF_MAX_CODE(gif))
+ call pargi(GIF_MAX_CODE_SIZE(gif))
+ call pargi(GIF_OLD_CODE(gif))
+ call pargi(GIF_FIRST_CODE(gif))
+ }
+
+ # Point to the next slot in the table. If we exceed the current
+ # MaxCode value, increment the code size unless it's already 12.
+ # If it is, do nothing: the next code decompressed better be CLEAR
+
+ code = GIF_MAX_CODE(gif)
+ if (code < MAX_CODE_ENTRIES) {
+ CODETAB(gif,0,code) = GIF_OLD_CODE(gif)
+ CODETAB(gif,1,code) = GIF_FIRST_CODE(gif)
+ GIF_MAX_CODE(gif) = GIF_MAX_CODE(gif) + 1
+ if ((GIF_MAX_CODE(gif) >= GIF_MAX_CODE_SIZE(gif)) &&
+ (GIF_MAX_CODE_SIZE(gif) < MAX_CODE_ENTRIES)) {
+ GIF_MAX_CODE_SIZE(gif) = GIF_MAX_CODE_SIZE(gif) * 2
+ GIF_CODE_SIZE(gif) = GIF_CODE_SIZE(gif) + 1
+ }
+ }
+
+ GIF_OLD_CODE(gif) = incode
+
+ if (GIF_SP(gif) > 0) {
+ GIF_SP(gif) = GIF_SP(gif) - 1
+ return (STACK(gif,GIF_SP(gif)))
+ }
+
+ code = gif_get_code (gif, GIF_CODE_SIZE(gif))
+ }
+ return code
+end
+
+
+# GIF_GET_CODE - Fetch the next code from the raster data stream. The codes
+# can be any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
+# maintain our location in the Raster array as a BIT Offset. We compute the
+# byte Offset into the raster array by dividing this by 8, pick up three
+# bytes, compute the bit Offset into our 24-bit chunk, shift to bring the
+# desired code to the bottom, then mask it off and return it. Simple.
+
+int procedure gif_get_code (gif, code_size)
+
+pointer gif #i GIF struct pointer
+int code_size #i op code size
+
+int i, j, count, ret
+int val1, val2
+int btoi(), and(), shifti(), ori ()
+int gif_get_data_block()
+
+begin
+ # See if processing the next code will overflow our buffer. If so
+ # we get the next control block from the stream.
+ if ( (GIF_CURBIT(gif) + code_size) >= GIF_LASTBIT(gif)) {
+ if (GIF_DONE(gif) == YES) {
+ if (GIF_CURBIT(gif) >= GIF_LASTBIT(gif)) {
+ call error (0, "GIF_GET_CODE: Ran out of bits.\n")
+ return (ERR)
+ }
+ }
+
+ CODEBUF(gif,0) = CODEBUF(gif,GIF_LASTBYTE(gif)-2)
+ CODEBUF(gif,1) = CODEBUF(gif,GIF_LASTBYTE(gif)-1)
+
+ count = gif_get_data_block (gif, CODEBUF(gif,2))
+ if (count == 0)
+ GIF_DONE(gif) = YES
+
+ GIF_LASTBYTE(gif) = 2 + count
+ GIF_CURBIT(gif) = (GIF_CURBIT(gif) - GIF_LASTBIT(gif)) + 16
+ GIF_LASTBIT(gif) = (2 + count) * 8
+ }
+
+ # for (i = GIF_CURBIT(gif), j = 0; j < code_size; ++i, ++j)
+ # ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
+
+ i = GIF_CURBIT(gif)
+ j = 0
+ ret = 0
+ while (j < code_size) {
+ val1 = btoi ( and (int(CODEBUF(gif,i/8)), shifti(1,mod(i,8))) != 0 )
+ val2 = shifti (val1, j)
+ ret = ori (ret, val2)
+ i = i + 1
+ j = j + 1
+ }
+
+ GIF_CURBIT(gif) = GIF_CURBIT(gif) + code_size
+ if (VDEBUG) {
+ call eprintf (": returning %d\n");call pargi(ret);call flush(STDERR)
+ }
+
+ return (ret)
+end
+
+
+# GIF_GET_DATA_BLOCK - Get the next block of GIF data from the data stream so
+# it can be converted to raster data.
+
+int procedure gif_get_data_block (gif, buf)
+
+pointer gif #i GIF struct pointer
+char buf[ARB] #o data block
+
+char count
+int nb, btoi()
+int gif_rdbyte(), gif_getbytes()
+
+begin
+ if (gif_rdbyte (GIF_FD(gif), count) != OK) {
+ call error (0, "error in getting DataBlock size")
+ return (ERR)
+ }
+
+ GIF_ZERO_DATABLOCK(gif) = btoi (count == 0)
+ if (VDEBUG) {
+ call eprintf ("getDataBlock: count = %d "); call pargs(count) }
+ nb = count
+ if ((count != 0) && (gif_getbytes(GIF_FD(gif), buf, nb) != OK)) {
+ call error (0, "error in reading DataBlock")
+ return (ERR)
+ }
+ return count
+end
+
+
+
+# Byte I/O routines. We use the normal IMPORT procedures but localize the code
+# here to make it easier to keep track of the current file position (in bytes).
+
+# GIF_RDBYTE - Read a single byte at the current offset from the file.
+
+int procedure gif_rdbyte (fd, val)
+
+int fd #i file descriptor
+char val #o byte read
+
+short ip_getb()
+
+long filepos
+common /gifcom/ filepos
+
+begin
+ iferr (val = ip_getb (fd, filepos))
+ return (ERR)
+
+ filepos = filepos + 1
+ call ip_lseek (fd, filepos)
+
+ return (OK)
+end
+
+
+# GIF_GETBYTES - Read an array of bytes from the file at the current offset.
+
+int procedure gif_getbytes (fd, buffer, len)
+
+int fd #i file descriptor
+char buffer[ARB] #o output buffer
+int len #i no. of bytes to read
+
+pointer sp, bp
+
+long filepos
+common /gifcom/ filepos
+
+begin
+ call smark (sp)
+ call salloc (bp, len+1, TY_CHAR)
+ call aclrc (Memc[bp], len+1)
+
+ call ip_agetb (fd, bp, len) # read the bytes
+ call amovc (Memc[bp], buffer, len) # copy to output buffer
+ filepos = filepos + len
+ call ip_lseek (fd, filepos)
+
+ call sfree (sp)
+ return (OK)
+end
diff --git a/pkg/dataio/import/bltins/ipras.x b/pkg/dataio/import/bltins/ipras.x
new file mode 100644
index 00000000..100ca6dc
--- /dev/null
+++ b/pkg/dataio/import/bltins/ipras.x
@@ -0,0 +1,504 @@
+include <mach.h>
+include "../import.h"
+
+
+# IPRAS.X - Source file for the IMPORT task rasterfile builtin format.
+
+
+define SZ_RASHDR 13
+define RAS_MAGIC Memi[$1] # Magic number
+define RAS_WIDTH Memi[$1+1] # Image width (pixels per line)
+define RAS_HEIGHT Memi[$1+2] # Image height (number of lines)
+define RAS_DEPTH Memi[$1+3] # Image depth (bits per pixel)
+define RAS_LENGTH Memi[$1+4] # Image length (bytes)
+define RAS_TYPE Memi[$1+5] # File type
+define RAS_MAPTYPE Memi[$1+6] # Colormap type
+define RAS_MAPLENGTH Memi[$1+7] # Colormap length (bytes)
+
+define RAS_CMAP Memi[$1+10] # Colormap (ptr)
+define RAS_COUNT Memi[$1+11] # RLE decoding var
+define RAS_CH Memi[$1+12] # RLE decoding var
+
+# Rasterfile magic number
+define RAS_MAGIC_NUM 59A66A95X
+define RAS_RLE 80X
+
+# Sun supported ras_types
+define RT_OLD 0 # Raw pixrect image in 68000 byte order
+define RT_STANDARD 1 # Raw pixrect image in 68000 byte order
+define RT_BYTE_ENCODED 2 # Run-length compression of bytes
+define RT_FORMAT_RGB 3 # XRGB or RGB instead of XBGR or BGR
+define RT_FORMAT_TIFF 4 # tiff <-> standard rasterfile
+define RT_FORMAT_IFF 5 # iff (TAAC format) <-> standard rasterfile
+define RT_EXPERIMENTAL 65535 # Reserved for testing
+
+# Sun supported ras_maptypes
+define RMT_NONE 0 # ras_maplength is expected to be 0
+define RMT_EQUAL_RGB 1 # red[ras_maplength/3],green[],blue[]
+define RMT_RAW 2
+
+
+
+# IP_RAS - Read and process a Sun Rasterfile into an IRAF image.
+
+procedure ip_ras (ip, fname, info_only, verbose)
+
+pointer ip #i import struct pointer
+char fname[ARB] #i file name
+int info_only #i print out image info only?
+int verbose #i verbosity flag
+
+pointer ras
+int fd, w, nchars
+pointer ras_open()
+
+long filepos
+common /rascom/ filepos
+
+begin
+ # Allocate the ras struct pointer.
+ ras = ras_open ()
+ fd = IP_FD(ip)
+
+ # Initialize the file position.
+ filepos = 1
+ call ip_lseek (fd, BOF)
+
+ # Read in the rasterfile header, dump it directly to the task struct.
+ call ip_ageti (fd, ras, 8)
+ filepos = filepos + SZ_INT32 * SZB_CHAR * 8
+ call ip_lseek (fd, filepos)
+
+ # Now do some sanity checking on the values.
+ if (RAS_MAGIC(ras) != RAS_MAGIC_NUM)
+ call error (0, "Not a Sun rasterfile.")
+ if (RAS_TYPE(ras) == RT_OLD && RAS_LENGTH(ras) == 0)
+ RAS_LENGTH(ras) = RAS_WIDTH(ras) * RAS_HEIGHT(ras) *
+ RAS_DEPTH(ras) / 8
+
+ # See if we really want to convert this thing.
+ if (info_only == YES) {
+ call ip_ras_info (ip, ras, fname, verbose)
+ call ras_close (ras)
+ return
+ }
+
+ # Get the colormap (if any).
+ call ras_rdcmap (fd, ras, RAS_CMAP(ras))
+ IP_CMAP(ip) = RAS_CMAP(ras)
+
+ # Round up to account for 16 bit line blocking.
+ w = RAS_WIDTH(ras) * (RAS_DEPTH(ras) / 8)
+ nchars = w + mod (w, SZB_CHAR)
+
+
+ # Patch up the pixtype param if needed.
+ call ip_fix_pixtype (ip)
+
+ # See if we need to create any outbands operands if the user didn't.
+ if (IP_NBANDS(ip) == ERR)
+ call ip_fix_outbands (ip)
+
+ # Now process the image.
+ switch (RAS_DEPTH(ras)) {
+ case 1:
+ call eprintf ("Bitmap rasterfiles aren not supported.")
+ call flush (STDERR)
+
+ case 8:
+ # Standard or byte encoded 8-bit rasterfile.
+ if (RAS_TYPE(ras) == RT_OLD || RAS_TYPE(ras) == RT_STANDARD) {
+ call ip_prband (ip, fd, IP_IM(ip), RAS_CMAP(ras))
+
+ } else if (RAS_TYPE(ras) == RT_BYTE_ENCODED) {
+ call ras_rle8 (ip, ras, fd, nchars)
+
+ } else {
+ call eprintf ("Unsupported 8-bit RAS_TYPE: %d\n")
+ call pargi (RAS_TYPE(ras))
+ call flush (STDERR)
+ }
+
+ case 24, 32:
+ # 24 or 32-bit rasterfiles have no colormap (at least they
+ # shouldn't) and are pixel-interleaved. We already know how to
+ # do this so just call the right routines for processing.
+
+ if (RAS_TYPE(ras) == RT_BYTE_ENCODED) {
+ call ip_fix_pixtype (ip)
+ call ras_rle24 (ip, ras, fd, nchars)
+ } else {
+ call ip_fix_pixtype (ip)
+ call ip_prpix (ip, fd, IP_IM(ip), NULL)
+ }
+
+ default:
+ call eprintf ("Invalid pixel size.")
+ call flush (STDERR)
+ }
+
+ # Clean up.
+ call ras_close (ras)
+ IP_CMAP(ip) = NULL
+end
+
+
+# IP_RAS_INFO - Print information about the raster file.
+
+procedure ip_ras_info (ip, ras, fname, verbose)
+
+pointer ip #i ip struct pointer
+pointer ras #i ras struct pointer
+char fname[ARB] #i file name
+int verbose #i verbosity flag
+
+begin
+ # If not verbose print a one-liner.
+ if (verbose == NO) {
+# call printf ("Input file:\n\t")
+ call printf ("%s: %20t%d x %d \t\t%d-bit Sun Rasterfile\n")
+ call pargstr (fname)
+ call pargi (RAS_WIDTH(ras))
+ call pargi (RAS_HEIGHT(ras))
+ call pargi (RAS_DEPTH(ras))
+
+ # Print out the format comment if any.
+# if (IP_COMPTR(ip) != NULL) {
+# if (COMMENT(ip) != '\0') {
+# call printf ("%s\n")
+# call pargstr (COMMENT(ip))
+# }
+# call strcpy ("\0", COMMENT(ip), SZ_LINE)
+# }
+# if (RAS_DEPTH(ras) > 8) {
+# if (RAS_TYPE(ras) != RT_FORMAT_RGB && RAS_TYPE(ras) != RT_OLD) {
+# call eprintf ("\tNote: %d-bit rasterfile is stored as %s\n")
+# call pargi (RAS_DEPTH(ras))
+# call pargstr ("ABGR and not ARGB")
+# }
+# }
+ return
+ }
+
+ # Print a more verbose description.
+ call printf ("%s: %20tSun Rasterfile\n")
+ call pargstr (fname)
+
+ # Print out the format comment if any.
+ if (IP_COMPTR(ip) != NULL) {
+ if (COMMENT(ip) != '\0') {
+ call printf ("%s\n")
+ call pargstr (COMMENT(ip))
+ }
+ call strcpy ("\0", COMMENT(ip), SZ_LINE)
+ }
+ if (RAS_DEPTH(ras) > 8) {
+ if (RAS_TYPE(ras) != RT_FORMAT_RGB && RAS_TYPE(ras) != RT_OLD) {
+ call eprintf ("\tNote: %d-bit rasterfile is stored as %s\n")
+ call pargi (RAS_DEPTH(ras))
+ call pargstr ("ABGR and not ARGB")
+ }
+ }
+
+ call printf ("%20tByte Order:%38t%s\n")
+ if (IP_SWAP(ip) == S_NONE && BYTE_SWAP2 == NO )
+ call pargstr ("Most Significant Byte First")
+ else
+ call pargstr ("Least Significant Byte First")
+
+ call printf ("%20tResolution:%38t%d x %d\n")
+ call pargi (RAS_WIDTH(ras))
+ call pargi (RAS_HEIGHT(ras))
+
+ call printf ("%20tType: %38t%d-bit %s %s\n")
+ call pargi (RAS_DEPTH(ras))
+ switch (RAS_TYPE(ras)) {
+ case RT_OLD:
+ call pargstr ("Old")
+ case RT_STANDARD:
+ call pargstr ("Standard")
+ case RT_BYTE_ENCODED:
+ call pargstr ("Byte Encoded")
+ case RT_FORMAT_RGB:
+ call pargstr ("RGB")
+ case RT_FORMAT_TIFF:
+ call pargstr ("TIFF")
+ case RT_FORMAT_IFF:
+ call pargstr ("IFF")
+ default:
+ call pargstr ("Experimental (or unknown)")
+ }
+ if (RAS_MAPLENGTH(ras) > 0)
+ call pargstr ("Color Index")
+ else
+ call pargstr ("")
+
+ if (RAS_MAPLENGTH(ras) > 0) {
+ call printf ("%20tColormap:%38t%d entries\n")
+ if (RAS_MAPTYPE(ras) == RMT_EQUAL_RGB)
+ call pargi (RAS_MAPLENGTH(ras)/3)
+ else
+ call pargi (RAS_MAPLENGTH(ras))
+ } else
+ call printf ("%20tColormap:%38tnone\n")
+
+ call printf ("%20tCompression: %38t%s\n")
+ if (RAS_TYPE(ras) == RT_BYTE_ENCODED)
+ call pargstr ("Run Length Encoded")
+ else
+ call pargstr ("None")
+
+ call printf ("%20tAlpha Channel: %38t%s\n")
+ if (RAS_DEPTH(ras) == 32)
+ call pargstr ("yes")
+ else
+ call pargstr ("none")
+end
+
+
+# RAS_OPEN - Open the RAS structure descriptor.
+
+pointer procedure ras_open ()
+
+pointer ras
+
+begin
+ iferr (call calloc (ras, SZ_RASHDR, TY_STRUCT))
+ call error (0, "Error allocating RAS structure.")
+ RAS_CMAP(ras) = NULL
+
+ return (ras)
+end
+
+
+# RAS_CLOSE - Close the RAS structure descriptor.
+
+procedure ras_close (ras)
+
+pointer ras #i RAS struct pointer
+
+begin
+ if (RAS_CMAP(ras) != NULL)
+ call mfree (RAS_CMAP(ras), TY_CHAR)
+ call mfree (ras, TY_STRUCT)
+end
+
+
+# RAS_RDCMAP - Read the colormap from the image if necessary.
+
+procedure ras_rdcmap (fd, ras, cmap)
+
+int fd #i file descriptor
+pointer ras #i RAS struct pointer
+pointer cmap #i colormap array ptr
+
+int ncolors
+
+long filepos
+common /rascom/ filepos
+
+begin
+ # Now read the colormap, allocate the pointer if we need to.
+ ncolors = RAS_MAPLENGTH(ras)
+ if (RAS_MAPTYPE(ras) == RMT_EQUAL_RGB && ncolors > 0) {
+ if (cmap == NULL)
+ call calloc (cmap, ncolors*3, TY_CHAR)
+ call ip_agetb (fd, cmap, ncolors)
+
+ } else if (RAS_MAPTYPE(ras) == RMT_RAW) {
+ call eprintf ("Warning: Can't handle RMT_RAW maptype - ignoring.\n")
+ call flush (STDERR)
+
+ # Skip over the bytes anyway.
+ filepos = filepos + ncolors
+ call ip_lseek (fd, filepos)
+ return
+ }
+
+ filepos = filepos + ncolors
+ call ip_lseek (fd, filepos)
+end
+
+
+# RAS_RLE8 - Process an 8-bit rasterfile into an IRAF image. This
+# procedure handles both standard and RLE files.
+
+procedure ras_rle8 (ip, ras, fd, nchars)
+
+pointer ip #i ip struct pointer
+pointer ras #i ras struct pointer
+int fd #i input file descriptor
+int nchars #i line size
+
+pointer im, data, op
+int i, percent
+
+long filepos
+common /rascom/ filepos
+
+begin
+ im = IP_IM(ip)
+ op = PTYPE(ip,1)
+ call malloc (data, nchars, TY_CHAR)
+ IO_DATA(op) = data
+ IO_NPIX(op) = RAS_WIDTH(ras)
+
+ percent = 0
+ do i = 1, RAS_HEIGHT(ras) {
+ call ras_read_rle (ras, fd, Memc[data], nchars)
+
+ # Apply the colormap since this is just an index.
+ if (RAS_MAPLENGTH(ras) != 0 && IP_USE_CMAP(ip) == YES)
+ call ip_gray_cmap (Memc[data], RAS_WIDTH(ras),
+ RAS_CMAP(ras))
+
+ # Evaluate and write the outbands expressions.
+ call ip_probexpr (ip, im, RAS_WIDTH(ras), i)
+
+ # Print percent done if being verbose
+ if (IP_VERBOSE(ip) == YES) {
+ if (i * 100 / RAS_HEIGHT(ras) >= percent + 10) {
+ percent = percent + 10
+ call printf (" Status: %2d%% complete\r")
+ call pargi (percent)
+ call flush (STDOUT)
+ }
+ }
+
+ }
+
+ if (IP_VERBOSE(ip) == YES) {
+ call printf (" Status: Done \n")
+ call flush (STDOUT)
+ }
+end
+
+
+# RAS_RLE24 - Process an 24-bit rasterfile into an IRAF image. This
+# procedure handles both standard and RLE files.
+
+procedure ras_rle24 (ip, ras, fd, nchars)
+
+pointer ip #i ip struct pointer
+pointer ras #i ras struct pointer
+int fd #i input file descriptor
+int nchars #i line size
+
+pointer im, data, op
+int i, percent, npix
+
+long filepos
+common /rascom/ filepos
+
+begin
+ im = IP_IM(ip)
+ op = PTYPE(ip,1)
+ call malloc (data, nchars, TY_SHORT)
+ IO_DATA(op) = data
+ IO_NPIX(op) = RAS_WIDTH(ras)
+
+ # See if we need to create any outbands operands if the user didn't.
+ if (IP_NBANDS(ip) == ERR)
+ call ip_fix_outbands (ip)
+
+ # Allocate the pixtype data pointers.
+ npix = RAS_WIDTH(ras)
+ do i = 1, IP_NPIXT(ip) {
+ op = PTYPE(ip,i)
+ IO_NPIX(op) = npix
+ call calloc (IO_DATA(op), npix, TY_SHORT)
+ }
+
+ percent = 0
+ do i = 1, RAS_HEIGHT(ras) {
+ call ras_read_rle (ras, fd, Memc[data], nchars)
+
+ # Separate pixels into different vectors.
+ call ip_upkpix (ip, data, npix)
+
+ # Evaluate and write the outbands expressions.
+ call ip_probexpr (ip, im, npix, i)
+
+ # Print percent done if being verbose
+ if (IP_VERBOSE(ip) == YES) {
+ if (i * 100 / RAS_HEIGHT(ras) >= percent + 10) {
+ percent = percent + 10
+ call printf (" Status: %2d%% complete\r")
+ call pargi (percent)
+ call flush (STDOUT)
+ }
+ }
+
+ }
+ if (IP_VERBOSE(ip) == YES) {
+ call printf (" Status: Done \n")
+ call flush (STDOUT)
+ }
+end
+
+
+# RAS_READ_RLE - Read a line of RLE encoded data from the file.
+
+procedure ras_read_rle (ras, fd, data, nchars)
+
+pointer ras #i ras struct pointer
+int fd #i file descriptor
+char data[ARB] #u output pixels
+int nchars #i number of pixels to read
+
+int i
+short pix, ras_rdbyte()
+
+long filepos
+common /rascom/ filepos
+
+begin
+ i = 1
+ while (i <= nchars) {
+ if (RAS_COUNT(ras) > 0) {
+ data[i] = RAS_CH(ras)
+ i = i + 1
+ RAS_COUNT(ras) = RAS_COUNT(ras) - 1
+
+ } else {
+ pix = ras_rdbyte (fd)
+ if (pix == RAS_RLE) {
+ RAS_COUNT(ras) = ras_rdbyte (fd)
+ if (RAS_COUNT(ras) == 0) {
+ data[i] = pix
+ i = i + 1
+ } else {
+ RAS_CH(ras) = ras_rdbyte (fd)
+ data[i] = RAS_CH(ras)
+ i = i + 1
+ }
+ } else {
+ data[i] = pix
+ i = i + 1
+ }
+ }
+ }
+end
+
+
+# RAS_RDBYTE - Read a single byte at the current offset from the file.
+
+short procedure ras_rdbyte (fd)
+
+int fd #i file descriptor
+
+short val
+short ip_getb()
+
+long filepos
+common /rascom/ filepos
+
+begin
+ iferr (val = ip_getb (fd, filepos))
+ return (ERR)
+
+ filepos = filepos + 1
+ call ip_lseek (fd, filepos)
+
+ return (val)
+end
diff --git a/pkg/dataio/import/bltins/ipxwd.x b/pkg/dataio/import/bltins/ipxwd.x
new file mode 100644
index 00000000..62a48ff7
--- /dev/null
+++ b/pkg/dataio/import/bltins/ipxwd.x
@@ -0,0 +1,188 @@
+# IPXWD.X - Source file for the IMPORT task X Window Dump builtin format.
+
+include <mach.h>
+include "../import.h"
+
+
+# IP_XWD - Read and process an X Window Dump into an IRAF image.
+
+procedure ip_xwd (ip, fname, info_only, verbose)
+
+pointer ip #i import struct pointer
+char fname[ARB] #i file name
+int info_only #i print out image info only?
+int verbose #i verbosity flag
+
+int fd
+pointer im, cmap
+int nchars
+long depth, cmap_entries, hdr_size
+long hskip, lpad, width,height
+
+long ip_getl()
+
+begin
+ # Get the input file descriptor and initialize the file position.
+ fd = IP_FD(ip)
+ im = IP_IM(ip)
+ call ip_lseek (fd, BOF)
+
+ # Get some information from the header we'll need for processing.
+ hdr_size = ip_getl (fd, 1)
+ width = IP_AXLEN(ip,1)
+ height = IP_AXLEN(ip,2)
+ depth = ip_getl (fd, 45)
+ hskip = IP_HSKIP(ip)
+ lpad = IP_LPAD(ip)
+ cmap_entries = ip_getl (fd, 73)
+ nchars = width + lpad
+
+ # See if we really want to convert this thing.
+ if (info_only == YES) {
+ call ip_xwd_info (ip, fname, depth, cmap_entries, verbose)
+ return
+ }
+
+ # Now process the image. For 24-bit or 32-bit files we have an RGB
+ # image and can process normally, if this is an 8-bit image see if
+ # we have a colormap we need to use.
+
+ if (depth > 8) {
+ call ip_prpix (ip, fd, im, NULL)
+ } else {
+ cmap = NULL
+ if (cmap_entries > 0)
+ call xwd_rdcmap (ip, fd, hdr_size, cmap_entries, cmap)
+ call ip_prband (ip, fd, im, cmap)
+ }
+ IP_CMAP(ip) = NULL
+end
+
+
+# IP_XWD_INFO - Print information about the xwd file.
+
+procedure ip_xwd_info (ip, fname, depth, ncolors, verbose)
+
+pointer ip #i ip struct pointer
+char fname[ARB] #i file name
+int depth #i bits per pixel
+int ncolors #i number of colors
+int verbose #i verbosity flag
+
+begin
+ # If not verbose print a one-liner.
+ if (verbose == NO) {
+ #call printf ("Input file:\n\t")
+ call printf ("%s: %20t%d x %d \t%d-bit X11 Window Dump\n")
+ call pargstr (fname)
+ call pargi (IP_AXLEN(ip,1))
+ call pargi (IP_AXLEN(ip,2))
+ call pargi (depth)
+
+ # Print out the format comment if any.
+ if (IP_COMPTR(ip) != NULL) {
+ if (COMMENT(ip) != '\0') {
+ call printf ("%s\n")
+ call pargstr (COMMENT(ip))
+ }
+ call strcpy ("\0", COMMENT(ip), SZ_LINE)
+ }
+ return
+ }
+
+ # Print a more verbose description.
+ call printf ("%s: %20tX11 Window Dump\n")
+ call pargstr (fname)
+
+ # Print out the format comment if any.
+ if (IP_COMPTR(ip) != NULL) {
+ if (COMMENT(ip) != '\0') {
+ call printf ("%s\n")
+ call pargstr (COMMENT(ip))
+ }
+ call strcpy ("\0", COMMENT(ip), SZ_LINE)
+ }
+
+ call printf ("%20tByte Order:%38t%s\n")
+ if (IP_SWAP(ip) == S_NONE && BYTE_SWAP2 == NO )
+ call pargstr ("Most Significant Byte First")
+ else
+ call pargstr ("Least Significant Byte First")
+
+ call printf ("%20tResolution:%38t%d x %d\n")
+ call pargi (IP_AXLEN(ip,1))
+ call pargi (IP_AXLEN(ip,2))
+
+ call printf ("%20tType: %38t%d-bit %s\n")
+ call pargi (depth)
+ if (ncolors > 0)
+ call pargstr ("Color Index")
+ else
+ call pargstr ("")
+
+ call printf ("%20tHeader size:%38t%d bytes\n")
+ call pargi (IP_HSKIP(ip))
+
+ if (ncolors > 0) {
+ call printf ("%20tColormap:%38t%d entries\n")
+ call pargi (ncolors)
+ } else
+ call printf ("%20tColormap:%38tnone\n")
+
+ call printf ("%20tAlpha Channel: %38t%s\n")
+ if (depth == 32)
+ call pargstr ("8-bit")
+ else
+ call pargstr ("none")
+end
+
+
+# XWD_RDCMAP - Read colormap from an X11 Window Dump file and return a
+# pointer to it.
+
+procedure xwd_rdcmap (ip, fd, hdr_size, ncolors, cmap)
+
+pointer ip #i task struct pointer
+int fd #i file descriptor
+int hdr_size #i header size
+int ncolors #i number of colormap entries
+pointer cmap #i colormap pointer
+
+int i
+long filepos, pixel
+int r, g, b
+char flags, pad
+
+short ip_getb()
+int ip_getu()
+long ip_getl()
+
+define SZ_X11_CSTRUCT 12
+
+begin
+ # Now read the colormap, allocate the pointer if we need to.
+ cmap = NULL
+ if (ncolors == 0)
+ return
+ else
+ call calloc (cmap, CMAP_SIZE*3, TY_CHAR)
+
+ filepos = hdr_size + 3
+ call ip_lseek (fd, filepos)
+ do i = 1, ncolors {
+ pixel = ip_getl (fd, filepos)
+ r = ip_getu (fd, filepos+4)
+ g = ip_getu (fd, filepos+6)
+ b = ip_getu (fd, filepos+8)
+ flags = ip_getb (fd, filepos+10)
+ pad = ip_getb (fd, filepos+11)
+
+ CMAP(cmap,IP_RED,i) = r * 255 / 65535
+ CMAP(cmap,IP_GREEN,i) = g * 255 / 65535
+ CMAP(cmap,IP_BLUE,i) = b * 255 / 65535
+
+ filepos = filepos + SZ_X11_CSTRUCT
+ call ip_lseek (fd, filepos)
+ }
+ IP_CMAP(ip) = cmap
+end
diff --git a/pkg/dataio/import/bltins/mkpkg b/pkg/dataio/import/bltins/mkpkg
new file mode 100644
index 00000000..88c4cadb
--- /dev/null
+++ b/pkg/dataio/import/bltins/mkpkg
@@ -0,0 +1,13 @@
+# Mkpkg file for building the IMPORT task builtin formats.
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ ipcmap.x ../import.h
+ ipgif.x ../import.h
+ ipras.x ../import.h <mach.h>
+ ipxwd.x ../import.h <mach.h>
+ ;
diff --git a/pkg/dataio/import/fmtdb.x b/pkg/dataio/import/fmtdb.x
new file mode 100644
index 00000000..8e5da296
--- /dev/null
+++ b/pkg/dataio/import/fmtdb.x
@@ -0,0 +1,610 @@
+include <ctotok.h>
+include <evvexpr.h>
+include <fset.h>
+include <error.h>
+include "import.h"
+
+define DEBUG false
+define VDEBUG false
+
+
+.help fmtdb Augl93 "Format Database Interface"
+.ih
+DESCRIPTION
+Format Database Procedures -- Routines for opening the format database given
+in the task parameter, reading sequential and randome records within it, as
+well as getting entried from within a selected record.
+
+PROCEDURES
+.nf
+ PUBLIC PROCEDURES:
+
+ fd = fdb_opendb ()
+ fdb_closedb (fd)
+ fmt = fdb_get_rec (fd, format)
+ fmt = fdb_next_rec (fd)
+ fmt = fdb_scan_records (fd, keyword, getop, opdata, fcn, fcndata)
+ fdbgstr (fmt, param, str, maxchar)
+ fdb_close (fmt)
+
+ PRIVATE PROCEDURES:
+
+ fdb_gfield (fd, fmt, key, val)
+ fdb_gexpr (fd, fmt, expr, maxchars)
+ fdb_strip_colon (in, out, maxch)
+ fdb_strip_quote (in, out, maxch)
+
+.fi
+
+The FDB_OPENDB procedure returns a file descriptor to the database file
+(named in the task parameters), and FDB_CLOSEDB will close the file. When
+searching for a specific format, the FDB_GET_REC procedure will return a
+pointer to a symtab containing the database record. The FDB_NEXT_REC
+will return a symtab pointer to the next record in the database when reading
+it sequentially. The FDB_SCAN_RECS procedure can be used to scan the
+database, returning the symtab pointer to a record whose 'keyword' field eval-
+uates as true. The FDB_CLOSE procedure will free the symtab pointer returned
+by the previous two routines.
+
+Once a pointer is found for a database record the FDBGSTR procedure
+can be used to return a value for an entry within that database record.
+.ih
+SEE ALSO
+Source code
+.endhelp
+
+
+# Symbol table definitions.
+define LEN_INDEX 10 # Length of symtab index
+define LEN_STAB (20*SZ_EXPR) # Length of symtab
+define SZ_SBUF 512 # Size of symtab string buffer
+define SYMLEN SZ_EXPR # Length of symbol structure
+define SZ_FMTVAL SZ_EXPR # Size of format value string
+
+# Symbol table structure
+define FMTVAL Memc[P2C($1)] # Format value string
+
+
+# FDB_OPENDB -- Return a file descriptor to the format database. The
+# specified database may be a list of files in which case they will be
+# concatenated to a single temporary file that is removed when the database
+# is closed.
+
+int procedure fdb_opendb ()
+
+int fd, in, out
+int stat, nfiles
+pointer sp, fname, buf
+pointer dbfiles
+
+int open()
+int clpopni(), clplen(), clgfil()
+
+errchk open, clpopni
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_FNAME, TY_CHAR)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+
+ dbfiles = clpopni ("database")
+ nfiles = clplen (dbfiles)
+ if (nfiles == 0) {
+ call error (0, "No format database specified.")
+
+ } else if (nfiles == 1) {
+ call clgstr ("database", Memc[fname], SZ_FNAME)
+ stat = clgfil (dbfiles, Memc[fname], SZ_FNAME)
+
+ } else {
+ # The database parameter specified a list, concatenate the files
+ # to a temp file and open that instead.
+ call mktemp ("tmp$db", Memc[fname], SZ_FNAME)
+ out = open (Memc[fname], APPEND, TEXT_FILE)
+ while (clgfil (dbfiles, Memc[buf], SZ_FNAME) != EOF) {
+ in = open (Memc[buf], READ_ONLY, TEXT_FILE)
+ call fcopyo (in, out)
+ call close (in)
+ }
+ call close (out)
+ }
+
+ # Open format database.
+ fd = open (Memc[fname], READ_ONLY, TEXT_FILE)
+
+ call sfree (sp)
+ return (fd)
+end
+
+
+# FDB_CLOSEDB -- Close the format database.
+
+procedure fdb_closedb (fd)
+
+int fd #i file descriptor
+
+pointer sp, buf
+int strncmp()
+
+begin
+ if (fd == NULL)
+ return
+
+ call smark (sp)
+ call salloc (buf, SZ_FNAME, TY_CHAR)
+
+ # Get the database filename, if it's a temp file then the input
+ # was probably and list and we need to clean up.
+ call fstats (fd, F_FILENAME, Memc[buf], SZ_FNAME)
+ call close (fd)
+ if (strncmp (Memc[buf], "tmp$db", 6) == 0)
+ call delete (Memc[buf])
+
+ call sfree (sp)
+end
+
+
+# FDB_GET_REC -- Get the requested format information in symbol table.
+
+pointer procedure fdb_get_rec (fd, format)
+
+int fd #i database file descriptor
+char format[ARB] #i format name
+
+pointer fmt #o format symbol table pointer
+bool found
+char colon
+pointer sp, key, expr, sym
+
+int fscan(), stridx()
+pointer stopen(), stenter()
+bool streq()
+
+errchk stopen, stenter, fscan
+
+begin
+ # Allocate local storage.
+ call smark (sp)
+ call salloc (key, SZ_FNAME, TY_CHAR)
+ call salloc (expr, SZ_EXPR, TY_CHAR)
+
+ # Find format entry.
+ found = false
+ colon = ':'
+ while (fscan (fd) != EOF) {
+ call fdb_gfield (fd, NULL, Memc[key], Memc[expr])
+ if (stridx (colon, Memc[key]) > 0) {
+ call fdb_strip_colon (Memc[key], Memc[key], SZ_FNAME)
+ } else if (Memc[key]=='#') # skip comment lines
+ next
+ if (streq (Memc[key], format)) {
+ found = true
+ break
+ }
+ }
+ if (!found) { # check if entry was found
+ call sfree (sp)
+ return (NULL)
+ }
+
+ # Create the symbol table.
+ fmt = stopen (format, LEN_INDEX, LEN_STAB, SZ_SBUF)
+
+ # Read the file and enter the parameters in the symbol table.
+ sym = stenter (fmt, "format", SYMLEN)
+ call strcpy (format, FMTVAL(sym), SZ_FMTVAL)
+ while (fscan(fd) != EOF) {
+ call fdb_gfield (fd, fmt, Memc[key], Memc[expr])
+ if (stridx (colon, Memc[key]) > 0) {
+ call fdb_strip_colon (Memc[key], Memc[expr], SZ_FNAME)
+ call strcpy ("alias", Memc[key], SZ_FNAME)
+ } else if (Memc[key] == '#' || Memc[key] == '') {
+ next
+ } else if (Memc[key] == EOS) {
+ call sfree (sp)
+ return (fmt)
+ }
+ sym = stenter (fmt, Memc[key], SYMLEN)
+ call strcpy (Memc[expr], FMTVAL(sym), SZ_FMTVAL)
+ }
+
+ call close (fd)
+ call sfree (sp)
+ return (fmt)
+end
+
+
+# FDB_NEXT_REC -- Open format database and store the requested format
+# information in symbol table.
+
+pointer procedure fdb_next_rec (fd)
+
+int fd #i input binary file descriptor
+
+pointer fmt # Format symbol table pointer
+char colon
+pointer sp, key, expr, sym, tmp
+
+int fscan(), stridx()
+pointer stopen(), stenter()
+
+errchk stopen, stenter, fscan
+
+begin
+ # Allocate local storage.
+ call smark (sp)
+ call salloc (key, SZ_FNAME, TY_CHAR)
+ call salloc (tmp, SZ_FNAME, TY_CHAR)
+ call salloc (expr, SZ_FMTVAL, TY_CHAR)
+
+ # Skip ahead top the beginning of the next record.
+ colon = ':'
+ while (fscan (fd) != EOF) {
+ Memc[key] = EOS
+ Memc[expr] = EOS
+ call fdb_gfield (fd, NULL, Memc[key], Memc[expr])
+ if (stridx (colon, Memc[key]) > 0) {
+ call fdb_strip_colon (Memc[key], Memc[key], SZ_FNAME)
+ break
+ } else if (Memc[key] != '#' && Memc[key] != EOS) # skip comment
+ next
+
+ }
+
+ # The file will either be position at the BOF or at the end of the
+ # previous record. We will just read until the end of record and
+ # return the pointer.
+
+ # Create symbol table, but strip the ':' first.
+ call fdb_strip_colon (Memc[key], Memc[tmp], SZ_FNAME)
+ fmt = stopen (Memc[tmp], LEN_INDEX, LEN_STAB, SZ_SBUF)
+
+ if (DEBUG) {call eprintf("next_rec: fmt='%s' ");call pargstr(Memc[tmp])}
+
+ # Read the file and enter the parameters in the symbol table.
+ sym = stenter (fmt, "format", SYMLEN)
+ call strcpy (Memc[tmp], FMTVAL(sym), SZ_FMTVAL)
+ while (fscan(fd) != EOF) {
+ call fdb_gfield (fd, fmt, Memc[key], Memc[expr])
+ if (stridx (colon, Memc[key]) > 0) {
+ call fdb_strip_colon (Memc[key], Memc[expr], SZ_FNAME)
+ call strcpy ("alias", Memc[key], SZ_FNAME)
+ } else if (Memc[key] == '#' || Memc[key] == '') {
+ next
+ } else if (Memc[key] == EOS) {
+ call sfree (sp)
+ return (fmt)
+ }
+ sym = stenter (fmt, Memc[key], SYMLEN)
+ call strcpy (Memc[expr], FMTVAL(sym), SZ_FMTVAL)
+ }
+
+ call sfree (sp) # shouldn't get here
+ return (NULL)
+end
+
+
+# FDB_SCAN_RECORDS -- Scan the database for a record whose image_id evaluates
+# as true.
+
+pointer procedure fdb_scan_records (fd, keyword, getop, opdata, fcn, fcndata)
+
+int fd #i input binary file descriptor
+char keyword[ARB] #i keyword to be evaluated
+int getop #i func to get an operand
+int opdata #i data pointer for getop
+int fcn #i user functions in evvexpr
+int fcndata #i data pointer for fcn
+
+pointer sp, expr, fm
+pointer fmt, o
+
+pointer fdb_next_rec(), evvexpr()
+
+errchk evvexpr
+
+begin
+ call smark (sp)
+ call salloc (expr, SZ_EXPR, TY_CHAR)
+ call salloc (fm, SZ_FNAME, TY_CHAR)
+
+ # Rewind the file descriptor.
+ call seek (fd, BOF)
+
+ if (DEBUG) { call eprintf("scan_rec: keyw='%s' ");call pargstr(keyword)}
+
+ # Loop over all of the database records.
+ repeat {
+ fmt = fdb_next_rec (fd)
+ if (fmt == NULL)
+ break
+ call fdbgstr (fmt, keyword, Memc[expr], SZ_EXPR)
+
+ if (DEBUG) {
+ call eprintf(" expr='%s'\n"); call pargstr(Memc[expr])
+ call flush (STDERR)
+ }
+
+ # Evaluate keyword expression.
+ iferr {
+ o = evvexpr (Memc[expr], getop, opdata, fcn, fcndata, EV_RNGCHK)
+ if (O_TYPE(o) != TY_BOOL)
+ call error (0, "Expression must be a boolean")
+
+ } then {
+ call erract (EA_WARN)
+ break
+ }
+
+ if (O_VALI(o) == YES) { # see if we've found it
+ if (DEBUG) {
+ call fdbgstr (fmt, "format", Memc[fm], SZ_FNAME)
+ call eprintf(" format='%s'\n");call pargstr(Memc[fm])
+ }
+ call evvfree (o)
+ call sfree (sp)
+ return (fmt)
+ }
+
+ call evvfree (o)
+ call fdb_close (fmt) # free fmt pointer
+ }
+
+ call sfree (sp)
+ return (NULL)
+end
+
+
+# FDBCLOSE -- Close the format symbol table pointer.
+
+procedure fdb_close (fmt)
+
+pointer fmt #i Format symbol table pointer
+
+begin
+ if (fmt != NULL)
+ call stclose (fmt)
+end
+
+
+# FDBGSTR -- Get string valued format parameter. We simply return the
+# expression, evaluation is up to the caller.
+
+procedure fdbgstr (fmt, param, str, maxchar)
+
+pointer fmt #i format symbol table pointer
+char param[ARB] #i format parameter
+char str[ARB] #o format parameter value
+int maxchar #i maximum characters for string
+
+pointer sym, stfind()
+
+begin
+ call aclrc (str, maxchar)
+ sym = stfind (fmt, param)
+ if (sym == NULL)
+ call strcpy ("", str, maxchar)
+ else
+ call strcpy (FMTVAL(sym), str, maxchar)
+end
+
+
+## END OF PUBLIC PROCEDURES ##
+
+
+# FDB_GFIELD - Get field in the database record.
+
+procedure fdb_gfield (fd, fmt, keyword, expr)
+
+int fd #i file descriptor
+pointer fmt #i format symtab pointer
+char keyword[ARB] #o field keyword
+char expr[ARB] #o field expression
+
+pointer sp, tmp
+
+begin
+ call smark (sp)
+ call salloc (tmp, SZ_FNAME, TY_CHAR)
+
+ call gargwrd (keyword, SZ_FNAME)
+ call gargwrd (Memc[tmp], SZ_FNAME)
+
+ if (keyword[1] == EOS) {
+ call sfree (sp)
+ return
+ #} else if (Memc[tmp] == '#') {
+ } else if (keyword[1] == '#') {
+ expr[1] = EOS
+ } else if (Memc[tmp] != EOS)
+ call fdb_gexpr (fd, fmt, expr, SZ_EXPR)
+ else
+ expr[1] = EOS
+
+ if (VDEBUG && keyword[1] != '#' && keyword[1] != '') {
+ call eprintf("'%s'='%s'\n")
+ call pargstr (keyword) ; call pargstr (expr)
+ }
+
+ call sfree (sp)
+end
+
+
+# FDB_GEXPR - Get an expression from the input stream.
+
+procedure fdb_gexpr (fd, fmt, expr, maxchars)
+
+int fd #i file descriptor
+pointer fmt #i format symtab pointer
+char expr[ARB] #o returned expression
+int maxchars #i maxchars
+
+pointer sp, ntok, tok, tokval, next_tok, last_tok
+pointer sym
+int level, qlevel
+
+int fscan()
+pointer stfind()
+
+define dopar_ 99
+
+begin
+ call smark (sp)
+ call salloc (tok, SZ_FNAME, TY_CHAR)
+ call salloc (ntok, SZ_FNAME, TY_CHAR)
+
+ # Gather the expression. For now we'll just eat everything up until
+ # the closing parenthesis.
+ call aclrc (expr, maxchars)
+
+ # An expression is made up of a numeric or symbolic constant, a
+ # quoted literal string, or some boolean or arithmetic operation.
+ # The strategy is to get the first token and take action depending
+ # on it's value and whether a following token completes the expr-
+ # ession. Expressions may break across newlines, literal strings
+ # must be enclosed in double quotes.
+
+ level = 0
+ qlevel = 0
+ last_tok = TOK_UNKNOWN
+ repeat {
+ call gargtok (tokval, Memc[tok], SZ_EXPR)
+
+ switch (tokval) {
+ case TOK_NUMBER:
+ call strcat (Memc[tok], expr, SZ_EXPR)
+ case TOK_STRING:
+ # There are no operations on strings, but they might be passed
+ # to a function as an argument, so check the level. Oh yeah,
+ # keep the double quotes in the string.
+ call strcat ("\"", expr, SZ_EXPR)
+ call strcat (Memc[tok], expr, SZ_EXPR)
+ call strcat ("\"", expr, SZ_EXPR)
+ case TOK_PUNCTUATION:
+ if (Memc[tok] == '(')
+ level = level + 1
+ else if (Memc[tok] == ')')
+ level = level - 1
+ call strcat (Memc[tok], expr, SZ_EXPR)
+ case TOK_OPERATOR:
+ if (Memc[tok] == '"') { # pass quoted strings
+ if (qlevel == 1)
+ qlevel = 0
+ else if (qlevel == 0)
+ qlevel = 1
+ }
+ if (Memc[tok] == '#' && qlevel == 0) { # skip comments
+ if (fscan (fd) == EOF)
+ call eprintf ("WARNING: Unexpected EOF\n")
+ if (level == 0 && last_tok != TOK_OPERATOR)
+ break
+ } else
+ call strcat (Memc[tok], expr, SZ_EXPR)
+ case TOK_NEWLINE:
+ if (level != 0 || last_tok == TOK_OPERATOR) {
+ if (fscan (fd) == EOF)
+ call eprintf ("WARNING: Unexpected EOF\n")
+ }
+ case TOK_IDENTIFIER:
+ if (Memc[tok] == '$') {
+ call strcat (Memc[tok], expr, SZ_EXPR)
+ } else if (fmt != NULL) {
+ sym = stfind (fmt, Memc[tok])
+ if (sym == NULL) {
+ if (Memc[tok] == 'F') {
+ call strcat (Memc[tok], expr, SZ_EXPR)
+ } else {
+ call gargtok (next_tok, Memc[ntok], SZ_EXPR)
+ if (Memc[ntok] == '(') {
+ # Copy to output buffer, it's a function name.
+ call strcat (Memc[tok], expr, SZ_EXPR)
+ call strcat (Memc[ntok], expr, SZ_EXPR)
+ tokval = next_tok
+ level = level + 1
+ next
+ } else {
+ # It's an undefined database field.
+ call eprintf("Undefined database field '%s'.\n")
+ call pargstr (Memc[tok])
+ }
+ }
+ } else
+ call strcat (FMTVAL(sym), expr, SZ_EXPR)
+ } else {
+ call strcat (Memc[tok], expr, SZ_EXPR)
+ }
+ call gargtok (next_tok, Memc[tok], SZ_EXPR)
+dopar_ if (Memc[tok] == '(')
+ level = level + 1
+ else if (Memc[tok] == ')') {
+ level = level - 1
+ if (level == 0) {
+ call strcat (Memc[tok], expr, SZ_EXPR)
+ break
+ }
+ }
+ if (next_tok != TOK_NEWLINE)
+ call strcat (Memc[tok], expr, SZ_EXPR)
+ tokval = next_tok
+ default:
+ break
+ }
+
+ last_tok = tokval
+ }
+
+ # Check for an obvious error.
+ if (level > 0)
+ call eprintf ("Missing right paren in expression: '%s'\n")
+ else if (level < 0)
+ call eprintf ("Missing left paren in expression: '%s'\n")
+ call pargstr (expr)
+
+ call sfree (sp)
+end
+
+
+# FDB_STRIP_COLON -- Return the input string up to a ':' character.
+
+procedure fdb_strip_colon (in, out, maxch)
+
+char in[ARB] #i input string
+char out[ARB] #o output string
+int maxch #i max chars out
+
+int ip, op
+
+begin
+ op = 1
+ do ip = 1, ARB {
+ if (in[ip] == ':' || op > maxch || in[ip] == EOS)
+ break
+ out[op] = in[ip]
+ op = op + 1
+ }
+ out[op] = EOS
+end
+
+
+# FDB_STRIP_QUOTE -- Strip double quote chars from the string.
+
+procedure fdb_strip_quote (in, out, maxch)
+
+char in[ARB] #i input string
+char out[ARB] #o output string
+int maxch #i max chars out
+
+int ip, op
+
+begin
+ op = 1
+ do ip = 1, ARB {
+ if (op > maxch || in[ip] == EOS)
+ break
+ if (in[ip] != '"') {
+ out[op] = in[ip]
+ op = op + 1
+ }
+ }
+ out[op] = EOS
+end
diff --git a/pkg/dataio/import/generic/ipdb.x b/pkg/dataio/import/generic/ipdb.x
new file mode 100644
index 00000000..4dfb81c7
--- /dev/null
+++ b/pkg/dataio/import/generic/ipdb.x
@@ -0,0 +1,813 @@
+include <evvexpr.h>
+include <error.h>
+include <mach.h>
+include <imhdr.h>
+include "../import.h"
+include "../ipfcn.h"
+
+define DEBUG false
+
+
+# IP_EVAL_DBREC -- For each of the keywords defined in the database record,
+# evaluate the expression and load the task structure.
+
+procedure ip_eval_dbrec (ip)
+
+pointer ip #i task struct pointer
+
+int ival
+pointer sp, dims, pixtype, err
+pointer np, stp, sym
+
+pointer stname(), sthead(), stnext
+int or(), ip_dbgeti()
+bool streq()
+
+errchk ip_dbgeti()
+
+begin
+ call smark (sp)
+ call salloc (dims, SZ_EXPR, TY_CHAR)
+ call salloc (pixtype, SZ_EXPR, TY_CHAR)
+ call salloc (err, SZ_EXPR, TY_CHAR)
+ call aclrc (Memc[dims], SZ_EXPR)
+ call aclrc (Memc[pixtype], SZ_EXPR)
+ call aclrc (Memc[err], SZ_EXPR)
+
+ # Load the defaults.
+ call ip_load_defaults (ip)
+
+ # First thing we do is get the byte swap flag so the remaining
+ # fields will be interpreted correctly.
+ ifnoerr (ival = ip_dbgeti (ip, "bswap"))
+ IP_SWAP(ip) = ival
+
+ # Next, we handle 'interleave', 'dims' and 'pixtype' as a special case
+ # since for band- and line-interleaved files we may need to fix up the
+ # pixtype pointers.
+ ifnoerr (ival = ip_dbgeti (ip, "interleave"))
+ IP_INTERLEAVE(ip) = ival
+
+ ifnoerr (call ip_dbstr (ip, "dims", Memc[dims], SZ_EXPR))
+ call ip_do_dims (ip, Memc[dims])
+
+ ifnoerr (call ip_dbstr (ip, "pixtype", Memc[pixtype], SZ_EXPR)) {
+ if (Memc[pixtype] == '"')
+ call fdb_strip_quote (Memc[pixtype], Memc[pixtype], SZ_EXPR)
+ call ip_do_pixtype (ip, Memc[pixtype])
+ }
+
+ # Loop over every symbol in the table.
+ stp = IP_FSYM(ip)
+ for (sym=sthead(stp); sym != NULL; sym=stnext(stp,sym)) {
+ np = stname (stp, sym)
+
+ if (streq(Memc[np],"format") || # ignored or found already
+ streq(Memc[np],"alias") ||
+ streq(Memc[np],"image_id") ||
+ streq(Memc[np],"interleave") ||
+ streq(Memc[np],"dims") ||
+ streq(Memc[np],"pixtype") ||
+ streq(Memc[np],"id_string") ||
+ streq(Memc[np],"bswap")) {
+ next
+ } else if (streq(Memc[np],"hskip")) {
+ IP_HSKIP(ip) = ip_dbgeti (ip, "hskip")
+ } else if (streq(Memc[np],"tskip")) {
+ IP_TSKIP(ip) = ip_dbgeti (ip, "tskip")
+ } else if (streq(Memc[np],"bskip")) {
+ IP_BSKIP(ip) = ip_dbgeti (ip, "bskip")
+ } else if (streq(Memc[np],"lskip")) {
+ IP_LSKIP(ip) = ip_dbgeti (ip, "lskip")
+ } else if (streq(Memc[np],"lpad")) {
+ IP_LPAD(ip) = ip_dbgeti (ip, "lpad")
+ } else if (streq(Memc[np],"yflip")) {
+ if (ip_dbgeti (ip, "yflip") == YES)
+ IP_FLIP(ip) = or (IP_FLIP(ip), FLIP_Y)
+ } else if (streq(Memc[np],"error")) {
+ if (IP_OUTPUT(ip) != IP_INFO)
+ call ip_do_error (ip, Memc[P2C(sym)])
+ } else if (streq(Memc[np],"comment")) {
+ call fdb_strip_quote (Memc[P2C(sym)], Memc[P2C(sym)], SZ_LINE)
+ call ip_do_comment (ip, Memc[P2C(sym)])
+ } else {
+ call eprintf ("Warning: Unknown database keyword '%s'.\n")
+ call pargstr (Memc[np])
+ }
+ }
+
+ if (DEBUG) { call zzi_prstruct ("eval dbrec:", ip) }
+ call sfree (sp)
+end
+
+
+# IP_LOAD_DEFAULTS -- Load the default input parameters to the task structure.
+
+procedure ip_load_defaults (ip)
+
+pointer ip #i task struct pointer
+
+begin
+ IP_SWAP(ip) = DEF_SWAP # type of byte swapping
+ IP_INTERLEAVE(ip) = DEF_INTERLEAVE # type of data interleaving
+ IP_HSKIP(ip) = DEF_HSKIP # bytes to skip before data
+ IP_TSKIP(ip) = DEF_TSKIP # bytes to skip after data
+ IP_BSKIP(ip) = DEF_BSKIP # bytes between image bands
+ IP_LSKIP(ip) = DEF_LSKIP # bytes to skip at front of
+ IP_LPAD(ip) = DEF_LPAD # bytes to skip at end of
+
+ # zero image dimensions
+ for (IP_NDIM(ip)=IM_MAXDIM; IP_NDIM(ip) > 0; IP_NDIM(ip)=IP_NDIM(ip)-1)
+ IP_AXLEN(ip,IP_NDIM(ip)) = 0
+end
+
+
+# IP_DBFCN -- Called by evvexpr to execute format database special functions.
+
+procedure ip_dbfcn (ip, fcn, args, nargs, o)
+
+pointer ip #i task struct pointer
+char fcn[ARB] #i function to be executed
+pointer args[ARB] #i argument list
+int nargs #i number of arguments
+pointer o #o operand pointer
+
+pointer sp, buf, outstr
+int fd, func, v_nargs
+int i, len, nchar, ival, cur_offset, swap
+char ch
+short sval
+real rval
+double dval
+
+short ip_getb(), ip_gets()
+int strdic(), ip_line(), ip_locate(), ip_getu()
+int ctoi(), ctol(), ctor(), ctod(), ctocc(), ctowrd()
+int and(), strlen(), clgeti()
+long ip_getl()
+real ip_getr(), ip_getn()
+double ip_getd(), ip_getn8()
+bool strne(), streq()
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+ call salloc (outstr, SZ_LINE, TY_CHAR)
+ call aclrc (Memc[buf], SZ_LINE)
+ call aclrc (Memc[outstr], SZ_LINE)
+
+ # Lookup function in dictionary.
+ func = strdic (fcn, Memc[buf], SZ_LINE, DB_FUNCTIONS)
+ if (func > 0 && strne(fcn,Memc[buf]))
+ func = 0
+
+ # Abort if the function is not known.
+ if (func <= 0)
+ call xev_error1 ("unknown function `%s' called", fcn)
+
+
+ # Verify the correct number of arguments, negative value means a
+ # variable number of args, handle it in the evaluation.
+ switch (func) {
+ case CTOCC, CTOD, CTOI, CTOL, CTOR, CTOWRD:
+ v_nargs = -1
+
+ case GETSTR:
+ v_nargs = -1
+ case GETB, GETU, GETI, GETI2, GETI4, GETR, GETR4, GETR8,
+ GETN, GETN4, GETN8:
+ v_nargs = 1
+
+ case LOCATE:
+ v_nargs = -1
+ case LINE, SKIP:
+ v_nargs = 1
+
+ case BSWAP:
+ v_nargs = 1
+ case PARAMETER, DEFAULT:
+ v_nargs = 1
+ case SUBSTR:
+ v_nargs = 3
+ case STRIDX:
+ v_nargs = 2
+ case LSB_HOST, MSB_HOST:
+ v_nargs = 0
+ }
+ if (v_nargs > 0 && nargs != v_nargs)
+ call xev_error2 ("function `%s' requires %d arguments",
+ fcn, v_nargs)
+ else if (v_nargs < 0 && nargs < abs(v_nargs))
+ call xev_error2 ("function `%s' requires at least %d arguments",
+ fcn, abs(v_nargs))
+
+ fd = IP_FD(ip)
+ swap = IP_SWAP(ip)
+ cur_offset = IP_OFFSET(ip)
+
+ if (DEBUG) {
+ call eprintf ("cur_offset=%d nargs=%d func=%s swap=%d\n")
+ call pargi(cur_offset) ; call pargi(nargs)
+ call pargstr(fcn) ; call pargi (swap)
+ do i = 1, nargs
+ call zzi_pevop (args[i])
+ call eprintf ("init op => ") ; call zzi_pevop(o)
+
+ }
+
+ # Evaluate the function.
+ switch (func) {
+ case CTOCC: # run the fmtio equivalents of the argument
+ if (nargs == 1)
+ ch = ip_getb (fd, O_VALI(args[1]))
+ else
+ ch = ip_getb (fd, cur_offset)
+ len = ctocc (ch, Memc[outstr], SZ_FNAME) + 1
+ call ip_initop (o, len, TY_CHAR)
+ call aclrc (O_VALC(o), len)
+ call amovc (Memc[outstr], O_VALC(o), len)
+ cur_offset = cur_offset + 1
+ call ip_lseek (fd, cur_offset)
+
+ case CTOWRD:
+ if (nargs == 1)
+ call ip_gstr (fd, O_VALI(args[1]), SZ_FNAME, Memc[outstr])
+ else
+ call ip_gstr (fd, cur_offset, SZ_FNAME, Memc[outstr])
+ nchar = ctowrd (Memc[outstr], i, Memc[outstr], SZ_FNAME) + 1
+ call ip_initop (o, nchar, TY_CHAR)
+ call aclrc (O_VALC(o), nchar)
+ call amovc (Memc[outstr], O_VALC(o), nchar)
+ cur_offset = cur_offset + nchar + 1
+ call ip_lseek (fd, cur_offset)
+
+ case CTOI:
+ i = 1
+ if (nargs == 1) {
+ call ip_gstr (fd, O_VALI(args[i]), SZ_FNAME, Memc[outstr])
+ nchar = ctoi (Memc[outstr], i, ival)
+ cur_offset = cur_offset + nchar - 1
+ } else if (nargs == 2) {
+ call ip_gstr (fd, O_VALI(args[1]), O_VALI(args[2]),Memc[outstr])
+ nchar = ctoi (Memc[outstr], i, ival)
+ cur_offset = O_VALI(args[1]) + nchar - 1
+ }
+ call ip_lseek (fd, cur_offset)
+ O_TYPE(o) = TY_INT
+
+ case CTOL:
+ i = 1
+ if (nargs == 1) {
+ call ip_gstr (fd, O_VALI(args[i]), SZ_FNAME, Memc[outstr])
+ nchar = ctol (Memc[outstr], i, ival)
+ cur_offset = cur_offset + nchar - 1
+ } else if (nargs == 2) {
+ call ip_gstr (fd, O_VALI(args[1]), O_VALI(args[2]),Memc[outstr])
+ nchar = ctol (Memc[outstr], i, ival)
+ cur_offset = O_VALI(args[1]) + nchar - 1
+ }
+ call ip_lseek (fd, cur_offset)
+ O_TYPE(o) = TY_LONG
+
+ case CTOR:
+ i = 1
+ if (nargs == 1) {
+ call ip_gstr (fd, O_VALI(args[i]), SZ_FNAME, Memc[outstr])
+ nchar = ctor (Memc[outstr], i, rval)
+ cur_offset = cur_offset + nchar - 1
+ } else if (nargs == 2) {
+ call ip_gstr (fd, O_VALI(args[1]), O_VALI(args[2]),Memc[outstr])
+ nchar = ctor (Memc[outstr], i, rval)
+ cur_offset = O_VALI(args[1]) + nchar - 1
+ }
+ call ip_lseek (fd, cur_offset)
+ O_TYPE(o) = TY_REAL
+
+ case CTOD:
+ i = 1
+ if (nargs == 1) {
+ call ip_gstr (fd, O_VALI(args[i]), SZ_FNAME, Memc[outstr])
+ nchar = ctod (Memc[outstr], i, dval)
+ cur_offset = cur_offset + nchar - 1
+ } else if (nargs == 2) {
+ call ip_gstr (fd, O_VALI(args[1]), O_VALI(args[2]),Memc[outstr])
+ nchar = ctod (Memc[outstr], i, dval)
+ cur_offset = O_VALI(args[1]) + nchar - 1
+ }
+ call ip_lseek (fd, cur_offset)
+ O_TYPE(o) = TY_DOUBLE
+
+ case GETSTR:
+ if (nargs == 1) {
+ call ip_gstr (fd, cur_offset, O_VALI(args[1]), Memc[outstr])
+ cur_offset = cur_offset + O_VALI(args[1])
+ } else if (nargs == 2) {
+ call ip_gstr (fd, O_VALI(args[1]), O_VALI(args[2]),Memc[outstr])
+ cur_offset = O_VALI(args[1]) + O_VALI(args[2]) - 1
+ }
+ if (strlen(Memc[outstr]) == 0) {
+ len = strlen ("ERR") + 1
+ call ip_initop (o, len, TY_CHAR)
+ call aclrc (O_VALC(o), len)
+ call strcpy ("ERR", O_VALC(o), len-1)
+ } else {
+ len = strlen (Memc[outstr]) + 1
+ call ip_initop (o, len, TY_CHAR)
+ call aclrc (O_VALC(o), len)
+ call amovc (Memc[outstr], O_VALC(o), len-1)
+ }
+
+ case GETB:
+ if (nargs == 0) {
+ sval = ip_getb (fd, cur_offset)
+ cur_offset = cur_offset + SZB_CHAR
+ } else {
+ sval = ip_getb (fd, O_VALI(args[1]))
+ cur_offset = O_VALI(args[1]) + SZB_CHAR
+ }
+ ival = sval
+ O_TYPE(o) = TY_INT
+
+ case GETU:
+ if (nargs == 0) {
+ sval = short (ip_getu (fd, cur_offset))
+ cur_offset = cur_offset + (SZB_CHAR * SZ_SHORT)
+ } else {
+ sval = short (ip_getu (fd, O_VALI(args[1])))
+ cur_offset = O_VALI(args[1]) + (SZB_CHAR * SZ_SHORT)
+ }
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I2) == S_I2)
+ call bswap2 (sval, 1, sval, 1, (SZ_SHORT*SZB_CHAR))
+ ival = sval
+ O_TYPE(o) = TY_INT
+
+ case GETI, GETI2:
+ if (nargs == 0) {
+ sval = ip_gets (fd, cur_offset)
+ cur_offset = cur_offset + (SZB_CHAR * SZ_SHORT)
+ } else {
+ sval = ip_gets (fd, O_VALI(args[1]))
+ cur_offset = O_VALI(args[1]) + (SZB_CHAR * SZ_SHORT)
+ }
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I2) == S_I2)
+ call bswap2 (sval, 1, sval, 1, (SZ_SHORT*SZB_CHAR))
+ ival = sval
+ O_TYPE(o) = TY_INT
+
+ case GETI4:
+ if (nargs == 0) {
+ ival = ip_getl (fd, cur_offset)
+ cur_offset = cur_offset + (SZB_CHAR * SZ_LONG)
+ } else {
+ ival = ip_getl (fd, O_VALI(args[1]))
+ cur_offset = O_VALI(args[1]) + (SZB_CHAR * SZ_LONG)
+ }
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I2) == S_I4)
+ call bswap4 (ival, 1, ival, 1, (SZ_INT32*SZB_CHAR))
+ O_TYPE(o) = TY_INT
+
+ case GETR, GETR4:
+ if (nargs == 0) {
+ rval = ip_getr (fd, cur_offset)
+ cur_offset = cur_offset + (SZB_CHAR * SZ_REAL)
+ } else {
+ rval = ip_getr (fd, O_VALI(args[1]))
+ cur_offset = O_VALI(args[1]) + (SZB_CHAR * SZ_REAL)
+ }
+ if (and(swap, S_ALL) == S_ALL) # handle byte-swapping
+ call bswap4 (rval, 1, rval, 1, (SZ_REAL*SZB_CHAR))
+ O_TYPE(o) = TY_REAL
+
+ case GETR8:
+ if (nargs == 0) {
+ dval = ip_getd (fd, cur_offset)
+ cur_offset = cur_offset + (SZB_CHAR * SZ_DOUBLE)
+ } else {
+ dval = ip_getd (fd, O_VALI(args[1]))
+ cur_offset = O_VALI(args[1]) + (SZB_CHAR * SZ_DOUBLE)
+ }
+ if (and(swap, S_ALL) == S_ALL) # handle byte-swapping
+ call bswap8 (dval, 1, dval, 1, (SZ_DOUBLE*SZB_CHAR))
+ O_TYPE(o) = TY_DOUBLE
+
+ case GETN, GETN4:
+ if (nargs == 0) {
+ rval = ip_getn (fd, cur_offset)
+ cur_offset = cur_offset + (SZB_CHAR * SZ_REAL)
+ } else {
+ rval = ip_getn (fd, O_VALI(args[1]))
+ cur_offset = O_VALI(args[1]) + (SZB_CHAR * SZ_REAL)
+ }
+ if (and(swap, S_ALL) == S_ALL) # handle byte-swapping
+ call bswap4 (rval, 1, rval, 1, (SZ_REAL*SZB_CHAR))
+ O_TYPE(o) = TY_REAL
+
+ case GETN8:
+ if (nargs == 0) {
+ dval = ip_getn8 (fd, cur_offset)
+ cur_offset = cur_offset + (SZB_CHAR * SZ_DOUBLE)
+ } else {
+ dval = ip_getn8 (fd, O_VALI(args[1]))
+ cur_offset = O_VALI(args[1]) + (SZB_CHAR * SZ_DOUBLE)
+ }
+ if (and(swap, S_ALL) == S_ALL) # handle byte-swapping
+ call bswap8 (dval, 1, dval, 1, (SZ_DOUBLE*SZB_CHAR))
+ O_TYPE(o) = TY_DOUBLE
+
+ case LOCATE: # locate the pattern in the file
+ if (nargs == 1)
+ ival = ip_locate (fd, cur_offset, O_VALC(args[1]))
+ else if (nargs == 2)
+ ival = ip_locate (fd, O_VALI(args[1]), O_VALC(args[2]))
+ if (ival == ERR)
+ ival = 1
+ O_TYPE(o) = TY_INT
+ cur_offset = ival
+
+ case LINE: # locate the line no. in the file
+ ival = ip_line (fd, O_VALI(args[1]))
+ if (ival == ERR)
+ ival = 1
+ O_TYPE(o) = TY_INT
+ cur_offset = ival
+
+ case SKIP: # skip a certain number of bytes
+ ival = O_VALI(args[1])
+ O_TYPE(o) = TY_INT
+ cur_offset = cur_offset + ival
+
+ case BSWAP: # byte-swap argument
+ O_TYPE(o) = O_TYPE(args[1])
+ switch (O_TYPE(args[1])) {
+ case TY_SHORT:
+ call bswap2 (O_VALS(args[1]), 1, sval, 1, (SZ_SHORT*SZB_CHAR))
+ case TY_INT:
+ call bswap4 (O_VALI(args[1]), 1, ival, 1, (SZ_INT32*SZB_CHAR))
+ case TY_LONG:
+ call bswap4 (O_VALL(args[1]), 1, ival, 1, (SZ_LONG*SZB_CHAR))
+ case TY_REAL:
+ call bswap4 (O_VALR(args[1]), 1, rval, 1, (SZ_REAL*SZB_CHAR))
+ case TY_DOUBLE:
+ call bswap8 (O_VALD(args[1]), 1, dval, 1, (SZ_DOUBLE*SZB_CHAR))
+ }
+
+ case PARAMETER: # return current task parameter value
+ if (streq(O_VALC(args[1]),"dims")) {
+ call clgstr ("dims", Memc[outstr], SZ_FNAME)
+ len = strlen (Memc[outstr]) + 1
+ call ip_initop (o, len, TY_CHAR)
+ call strcpy (Memc[outstr], O_VALC(o), len)
+ } else if (streq(O_VALC(args[1]),"pixtype")) {
+ call clgstr ("pixtype", Memc[outstr], SZ_FNAME)
+ len = strlen (Memc[outstr]) + 1
+ call ip_initop (o, len, TY_CHAR)
+ call strcpy (Memc[outstr], O_VALC(o), len)
+ } else if (streq(O_VALC(args[1]),"interleave")) {
+ ival = clgeti ("interleave")
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"bswap")) {
+ call clgstr ("bswap", Memc[outstr], SZ_FNAME)
+ if (strne("no",Memc[outstr]) && strne("none",Memc[outstr]))
+ ival = YES
+ else
+ ival = NO
+ O_TYPE(o) = TY_BOOL
+ } else if (streq(O_VALC(args[1]),"hskip")) {
+ ival = clgeti ("hskip")
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"tskip")) {
+ ival = clgeti ("tskip")
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"bskip")) {
+ ival = clgeti ("bskip")
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"lskip")) {
+ ival = clgeti ("lskip")
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"lpad")) {
+ ival = clgeti ("lpad")
+ O_TYPE(o) = TY_INT
+ }
+
+ case DEFAULT: # return default task parameter value
+ if (streq(O_VALC(args[1]),"dims")) {
+ call ip_initop (o, 1, TY_CHAR)
+ call strcpy ("", O_VALC(o), 1)
+ } else if (streq(O_VALC(args[1]),"pixtype")) {
+ call ip_initop (o, 1, TY_CHAR)
+ call strcpy ("", O_VALC(o), 1)
+ } else if (streq(O_VALC(args[1]),"interleave")) {
+ ival = DEF_INTERLEAVE
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"bswap")) {
+ ival = DEF_SWAP
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"hskip")) {
+ ival = DEF_HSKIP
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"tskip")) {
+ ival = DEF_TSKIP
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"bskip")) {
+ ival = DEF_BSKIP
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"lskip")) {
+ ival = DEF_LSKIP
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"lpad")) {
+ ival = DEF_LPAD
+ O_TYPE(o) = TY_INT
+ }
+
+ case LSB_HOST: # host is an LSB byte ordered machine
+ if (BYTE_SWAP2 == YES)
+ ival = YES
+ else
+ ival = NO
+ O_TYPE(o) = TY_BOOL
+
+ case MSB_HOST: # host is an MSB byte ordered machine
+ if (BYTE_SWAP2 == NO)
+ ival = YES
+ else
+ ival = NO
+ O_TYPE(o) = TY_BOOL
+
+ case SUBSTR: # return a substring of the argument
+
+ case STRIDX: # return offset of a char w/in str
+
+ }
+
+ # Write result to output operand.
+ O_LEN(o) = 0
+ switch (O_TYPE(o)) {
+ case TY_USHORT, TY_SHORT:
+ O_VALS(o) = sval
+ case TY_INT, TY_BOOL:
+ O_VALI(o) = ival
+ case TY_LONG:
+ O_VALL(o) = ival
+ case TY_REAL:
+ O_VALR(o) = rval
+ case TY_DOUBLE:
+ O_VALD(o) = dval
+ }
+
+ if (DEBUG) { call eprintf("ip_dbfcn: ") ; call zzi_pevop (o) }
+
+ IP_OFFSET(ip) = cur_offset
+ call sfree (sp)
+end
+
+
+# IP_DBSTR -- Get a string valued expression from the database.
+
+procedure ip_dbstr (ip, param, outstr, maxch)
+
+pointer ip #i task struct pointer
+char param[ARB] #i parameter to evaluate
+char outstr[ARB] #o result string
+int maxch #i max length of string
+
+pointer sp, expr, o
+
+int locpr(), strlen()
+pointer evvexpr()
+extern ip_getop(), ip_dbfcn()
+errchk evvexpr
+
+begin
+ call smark (sp)
+ call salloc (expr, SZ_EXPR, TY_CHAR)
+ call aclrc (Memc[expr], SZ_EXPR)
+
+ # Get the requested parameter.
+ call aclrc (outstr, SZ_EXPR)
+ call fdbgstr (IP_FSYM(ip), param, Memc[expr], SZ_EXPR)
+ if (Memc[expr] == EOS)
+ call error (1, "FDBGET: Format parameter not found")
+
+ if (DEBUG) {
+ call eprintf("ip_dbstr: expr='%s' len=%d ");call pargstr(Memc[expr])
+ call pargi(strlen(Memc[expr]))
+ }
+
+ # Evaluate the expression.
+ iferr {
+ o = evvexpr (Memc[expr], locpr(ip_getop), ip,
+ locpr(ip_dbfcn), ip, EV_RNGCHK)
+ if (O_TYPE(o) != TY_CHAR)
+ call error (0, "ip_dbstr: Expression must be a string valued")
+ else
+ call amovc (O_VALC(o), outstr, (min(strlen(O_VALC(o)),maxch)))
+ } then
+ call erract (EA_WARN)
+
+ if (DEBUG) { call eprintf ("outstr=:%s:\n") ; call pargstr (outstr) }
+
+ call evvfree (o)
+ call sfree (sp)
+end
+
+
+
+# IP_DBGETI -- Get integer valued format parameter from the database.
+
+int procedure ip_dbgeti (ip, param)
+
+pointer ip #i task struct pointer
+char param[ARB] #i requested parameter
+
+int val
+pointer sp, expr, o
+
+int locpr()
+pointer evvexpr()
+extern ip_getop(), ip_dbfcn()
+errchk evvexpr
+
+begin
+ call smark (sp)
+ call salloc (expr, SZ_EXPR, TY_CHAR)
+
+ # Get the requested parameter.
+ call fdbgstr (IP_FSYM(ip), param, Memc[expr], SZ_EXPR)
+ if (Memc[expr] == EOS)
+ call error (1, "IP_DBGET: Format parameter not found")
+
+ # Evaluate the expression.
+ if (DEBUG) {
+ call eprintf ("ip_dbget: expr='%s'\n")
+ call pargstr (Memc[expr])
+ call flush (STDERR)
+ }
+ iferr {
+ o = evvexpr (Memc[expr], locpr(ip_getop), ip,
+ locpr(ip_dbfcn), ip, EV_RNGCHK)
+ if (O_TYPE(o) == TY_BOOL) {
+ val = O_VALI(o)
+ } else if (O_TYPE(o) != TY_INT && O_TYPE(o) != TY_SHORT) {
+ call error (0, "Expression must be an integer")
+ } else
+ val = O_VALI(o)
+
+ if (DEBUG) {
+ call eprintf ("ip_dbget: val=%d type=%d ecpr=:%s:\n")
+ call pargi (val)
+ call pargi (O_TYPE(o))
+ call pargstr (Memc[expr])
+ call flush (STDERR)
+ }
+ } then
+ call erract (EA_WARN)
+
+ call evvfree (o)
+ call sfree (sp)
+ return (val)
+end
+
+
+# IP_DBGETR -- Get real valued format parameter from the database.
+
+real procedure ip_dbgetr (ip, param)
+
+pointer ip #i task struct pointer
+char param[ARB] #i requested parameter
+
+real val
+pointer sp, expr, o
+
+int locpr()
+pointer evvexpr()
+extern ip_getop(), ip_dbfcn()
+errchk evvexpr
+
+begin
+ call smark (sp)
+ call salloc (expr, SZ_EXPR, TY_CHAR)
+
+ # Get the requested parameter.
+ call fdbgstr (IP_FSYM(ip), param, Memc[expr], SZ_EXPR)
+ if (Memc[expr] == EOS)
+ call error (1, "IP_DBGET: Format parameter not found")
+
+ # Evaluate the expression.
+ if (DEBUG) {
+ call eprintf ("ip_dbget: expr='%s'\n")
+ call pargstr (Memc[expr])
+ call flush (STDERR)
+ }
+ iferr {
+ o = evvexpr (Memc[expr], locpr(ip_getop), ip,
+ locpr(ip_dbfcn), ip, EV_RNGCHK)
+ if (O_TYPE(o) == TY_BOOL) {
+ val = O_VALI(o)
+ } else if (O_TYPE(o) != TY_REAL) {
+ call error (0, "Expression must be a real")
+ } else
+ val = O_VALR(o)
+
+ if (DEBUG) {
+ call eprintf ("ip_dbget: val=%d type=%d ecpr=:%s:\n")
+ call pargr (val)
+ call pargi (O_TYPE(o))
+ call pargstr (Memc[expr])
+ call flush (STDERR)
+ }
+ } then
+ call erract (EA_WARN)
+
+ call evvfree (o)
+ call sfree (sp)
+ return (val)
+end
+
+
+# IP_DO_ERROR -- Process the error parameter.
+
+procedure ip_do_error (ip, expr)
+
+pointer ip #i task struct pointer
+char expr[ARB] #i error string
+
+pointer o
+
+int locpr()
+pointer evvexpr()
+extern ip_getop(), ip_dbfcn()
+bool strne()
+errchk evvexpr
+
+begin
+ if (DEBUG) {call eprintf ("error expr: '%s' ") ; call pargstr (expr)}
+
+ # Evaluate the expression.
+ iferr {
+ o = evvexpr (expr, locpr(ip_getop), ip, locpr(ip_dbfcn), ip,
+ EV_RNGCHK)
+
+ if (DEBUG) { call eprintf("-> '%s'\n") ; call pargstr(O_VALC(o)) }
+
+ if (O_TYPE(o) != TY_CHAR)
+ call error (2, "do_error: Expression must be a string valued")
+ else {
+ if (strne("okay",O_VALC(o)))
+ call error (2, O_VALC(o))
+ }
+ call evvfree (o)
+
+ } then
+ if (IP_OUTPUT(ip) != IP_INFO)
+ call erract (EA_FATAL)
+end
+
+
+# IP_DO_COMMENT - Process a comment line in the format database.
+
+procedure ip_do_comment (ip, comstr)
+
+pointer ip #i task struct pointer
+char comstr[ARB] #i comment to add
+
+pointer sp, buf
+
+begin
+ # Copy the comment line to the comment block.
+ if (IP_COMPTR(ip) == NULL)
+ call calloc (IP_COMPTR(ip), SZ_COMMENT, TY_CHAR)
+
+ if (COMMENT(ip) == '\0') {
+ call strcpy ("\t", COMMENT(ip), SZ_LINE)
+ call strcat (comstr, COMMENT(ip), SZ_LINE)
+ } else {
+ call smark (sp)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+
+ Memc[buf] = '\0'
+ call strcpy ("\t", Memc[buf], SZ_LINE)
+ call strcat (comstr, Memc[buf], SZ_LINE)
+ call strcat ("\n", Memc[buf], SZ_LINE)
+ call strcat (COMMENT(ip), Memc[buf], SZ_COMMENT)
+
+ call strcpy (Memc[buf], COMMENT(ip), SZ_COMMENT)
+
+ call sfree (sp)
+ }
+end
+
+
+# IP_INITOP - Initialize an operand pointer to the requested values
+
+procedure ip_initop (o, len, type)
+
+pointer o #u operand pointer
+int len #i length of array
+int type #i data type of operand
+
+begin
+ O_LEN(o) = len
+ O_TYPE(o) = type
+ if (len > 1)
+ call calloc (O_VALP(o), len, type)
+end
diff --git a/pkg/dataio/import/generic/ipfio.x b/pkg/dataio/import/generic/ipfio.x
new file mode 100644
index 00000000..2977d8cb
--- /dev/null
+++ b/pkg/dataio/import/generic/ipfio.x
@@ -0,0 +1,569 @@
+include <mach.h>
+include <fset.h>
+include "../import.h"
+
+define DEBUG false
+
+
+# IP_GSTR -- Get a string of the specifed length from the given offset.
+
+procedure ip_gstr (fd, offset, len, outstr)
+
+int fd
+int offset
+int len
+char outstr[ARB]
+
+int nstat, read()
+pointer sp, buf
+
+begin
+ call smark (sp)
+ call salloc (buf, len+2, TY_CHAR)
+ call aclrc (Memc[buf], len+2)
+ call aclrc (outstr, len+2)
+
+ call ip_lseek (fd, offset)
+ nstat = read (fd, Memc[buf], len)
+
+ if (mod(offset,2) == 0 && offset > 1)
+ call bytmov (Memc[buf], 2, Memc[buf], 1, len)
+ call chrupk (Memc[buf], 1, outstr, 1, len)
+
+ if (DEBUG) { call eprintf ("ip_gstr: :%s: len=%d\n");
+ call pargstr(outstr) ; call pargi (len) }
+ call sfree (sp)
+end
+
+
+# IP_GETB -- Get a byte from the given offset.
+
+short procedure ip_getb (fd, offset)
+
+int fd
+int offset
+
+int nstat, read()
+short val
+char buf[2]
+
+begin
+ call ip_lseek (fd, offset)
+ nstat = read (fd, buf, 2)
+
+ if (mod(offset,2) == 0)
+ call bytmov (buf, 2, buf, 1, 2)
+ call chrupk (buf, 1, buf, 1, 2)
+
+ if (DEBUG) { call eprintf ("ip_getb: %d\n"); call pargs(buf[1]) }
+ if (buf[1] < 0)
+ val = buf[1] + 256
+ else
+ val = buf[1]
+ return (val)
+end
+
+
+# IP_GETU -- Get a unsigned short integer from the given offset.
+
+int procedure ip_getu (fd, offset)
+
+int fd
+int offset
+
+int val
+short ip_gets()
+
+begin
+ val = ip_gets (fd, offset)
+ if (val < 0)
+ val = val + 65536
+ return (val)
+end
+
+# IP_GET[silrd] -- Get a value of <type> from the given offset.
+
+
+
+short procedure ip_gets (fd, offset)
+
+int fd
+int offset
+
+int nstat, read()
+short val
+
+begin
+ call ip_lseek (fd, offset)
+ nstat = read (fd, val, SZ_SHORT * SZB_CHAR)
+
+ if (DEBUG) { call eprintf ("ip_get: %g\n"); call pargs(val) }
+ return (val)
+end
+
+
+int procedure ip_geti (fd, offset)
+
+int fd
+int offset
+
+int nstat, read()
+int val
+
+begin
+ call ip_lseek (fd, offset)
+ nstat = read (fd, val, SZ_INT32 * SZB_CHAR)
+ if (SZ_INT != SZ_INT32)
+ call iupk32 (val, val, 1)
+
+ if (DEBUG) { call eprintf ("ip_get: %g\n"); call pargi(val) }
+ return (val)
+end
+
+
+long procedure ip_getl (fd, offset)
+
+int fd
+int offset
+
+int nstat, read()
+long val
+
+begin
+ call ip_lseek (fd, offset)
+ nstat = read (fd, val, SZ_INT32 * SZB_CHAR)
+ if (SZ_INT != SZ_INT32)
+ call iupk32 (val, val, 1)
+
+ if (DEBUG) { call eprintf ("ip_get: %g\n"); call pargl(val) }
+ return (val)
+end
+
+
+real procedure ip_getr (fd, offset)
+
+int fd
+int offset
+
+int nstat, read()
+real val
+
+begin
+ call ip_lseek (fd, offset)
+ nstat = read (fd, val, SZ_REAL * SZB_CHAR)
+ call ieeupkr (val)
+
+ if (DEBUG) { call eprintf ("ip_get: %g\n"); call pargr(val) }
+ return (val)
+end
+
+
+double procedure ip_getd (fd, offset)
+
+int fd
+int offset
+
+int nstat, read()
+double val
+
+begin
+ call ip_lseek (fd, offset)
+ nstat = read (fd, val, SZ_DOUBLE * SZB_CHAR)
+ call ieeupkd (val)
+
+ if (DEBUG) { call eprintf ("ip_get: %g\n"); call pargd(val) }
+ return (val)
+end
+
+
+# IP_GETN -- Get a native floating point number from the given offset.
+
+real procedure ip_getn (fd, offset)
+
+int fd
+int offset
+
+int nstat, read()
+real rval
+
+begin
+ call ip_lseek (fd, offset)
+ nstat = read (fd, rval, SZ_REAL)
+
+ if (DEBUG) { call eprintf ("ip_getn: %g\n"); call pargr(rval) }
+ return (rval)
+end
+
+
+# IP_GETN8 -- Get a native double precision floating point number from the
+# given offset.
+
+double procedure ip_getn8 (fd, offset)
+
+int fd
+int offset
+
+int nstat, read()
+double dval
+
+begin
+ call ip_lseek (fd, offset)
+ nstat = read (fd, dval, SZ_DOUBLE)
+
+ if (DEBUG) { call eprintf ("ip_getn8: %g\n"); call pargd(dval) }
+ return (dval)
+end
+
+
+# IP_AGETB -- Get an array of bytes from the file. The data pointer is
+# allocated if necessary and contains the data on output.
+
+procedure ip_agetb (fd, ptr, len)
+
+int fd #i file descriptor
+pointer ptr #i data pointer
+int len #i length of array
+
+pointer sp, buf
+int fp, nval, nstat
+int ip_lnote(), read()
+
+begin
+ fp = ip_lnote(fd)
+ if (mod(fp,2) == 0 && fp != 1)
+ nval = len
+ else
+ nval = len + 1
+
+ call smark (sp)
+ call salloc (buf, nval, TY_CHAR)
+
+ if (ptr == NULL)
+ call malloc (ptr, nval * SZB_CHAR, TY_CHAR)
+ nstat = read (fd, Memc[buf], nval / SZB_CHAR + 1)
+
+ fp = ip_lnote(fd)
+ if (mod(fp,2) == 0 && fp != 1)
+ call bytmov (Memc[buf], 2, Memc[buf], 1, nval)
+ call achtbc (Memc[buf], Memc[ptr], len)
+
+ call sfree (sp)
+end
+
+
+# IP_AGETU -- Get an array of <type> from the file. The data pointer is
+# allocated if necessary and contains the data on output.
+
+procedure ip_agetu (fd, ptr, len)
+
+int fd #i file descriptor
+pointer ptr #i data pointer
+int len #i length of array
+
+begin
+ call ip_agets (fd, ptr, len)
+ call achtsu (Mems[ptr], Mems[ptr], len)
+end
+
+
+# IP_AGET[silrd] -- Get an array of <type> from the file. The data pointer is
+# allocated if necessary and contains the data on output.
+
+
+procedure ip_agets (fd, ptr, len)
+
+int fd #i file descriptor
+pointer ptr #i data pointer
+int len #i length of array
+
+int nstat
+int read()
+
+begin
+ if (ptr == NULL)
+ call malloc (ptr, len, TY_SHORT)
+ nstat = read (fd, Mems[ptr], len * SZ_SHORT)
+end
+
+
+procedure ip_ageti (fd, ptr, len)
+
+int fd #i file descriptor
+pointer ptr #i data pointer
+int len #i length of array
+
+int nstat
+int read()
+
+begin
+ if (ptr == NULL)
+ call malloc (ptr, len, TY_INT)
+ nstat = read (fd, Memi[ptr], len * SZ_INT32)
+ if (SZ_INT != SZ_INT32)
+ call iupk32 (Memi[ptr], Memi[ptr], len)
+end
+
+
+procedure ip_agetl (fd, ptr, len)
+
+int fd #i file descriptor
+pointer ptr #i data pointer
+int len #i length of array
+
+int nstat
+int read()
+
+begin
+ if (ptr == NULL)
+ call malloc (ptr, len, TY_LONG)
+ nstat = read (fd, Meml[ptr], len * SZ_INT32)
+ if (SZ_INT != SZ_INT32)
+ call iupk32 (Meml[ptr], Meml[ptr], len)
+end
+
+
+procedure ip_agetr (fd, ptr, len)
+
+int fd #i file descriptor
+pointer ptr #i data pointer
+int len #i length of array
+
+int nstat
+int read()
+
+begin
+ if (ptr == NULL)
+ call malloc (ptr, len, TY_REAL)
+ nstat = read (fd, Memr[ptr], len * SZ_REAL)
+ call ieevupkr (Memr[ptr], Memr[ptr], len)
+end
+
+
+procedure ip_agetd (fd, ptr, len)
+
+int fd #i file descriptor
+pointer ptr #i data pointer
+int len #i length of array
+
+int nstat
+int read()
+
+begin
+ if (ptr == NULL)
+ call malloc (ptr, len, TY_DOUBLE)
+ nstat = read (fd, Memd[ptr], len * SZ_DOUBLE)
+ call ieevupkd (Memd[ptr], Memd[ptr], len)
+end
+
+
+
+# IP_AGETN -- Get an array of native floats from the file. The data pointer is
+# allocated if necessary and contains the data on output.
+
+procedure ip_agetn (fd, ptr, len)
+
+int fd #i file descriptor
+pointer ptr #i data pointer
+int len #i length of array
+
+int nstat
+int read()
+
+begin
+ if (ptr == NULL)
+ call malloc (ptr, len, TY_REAL)
+ nstat = read (fd, Memr[ptr], len * SZ_REAL)
+end
+
+
+# IP_AGETN8 -- Get an array of native doubles from the file. The data pointer
+# is allocated if necessary and contains the data on output.
+
+procedure ip_agetn8 (fd, ptr, len)
+
+int fd #i file descriptor
+pointer ptr #i data pointer
+int len #i length of array
+
+int nstat
+int read()
+
+begin
+ if (ptr == NULL)
+ call malloc (ptr, len, TY_DOUBLE)
+ nstat = read (fd, Memd[ptr], len * SZ_DOUBLE)
+end
+
+
+# -----------------------------------------------------------------
+# ------------------ UTILITY FILE I/O FUNCTIONS -------------------
+# -----------------------------------------------------------------
+
+
+define BLKSIZE 1024
+
+# IP_LINE -- Return the offset of the start of the given line number.
+
+int procedure ip_line (fd, line)
+
+int fd #i input file descriptor
+int line #i line number to search
+
+pointer sp, cbuf, buf
+int nl, offset, i, nread, fsize
+
+int read(), fstati()
+
+define done_ 99
+define err_ 98
+
+begin
+ if (line == 1) {
+ return (1)
+ } else {
+ call smark (sp)
+ call salloc (buf, BLKSIZE, TY_CHAR)
+ call salloc (cbuf, BLKSIZE, TY_CHAR)
+
+ # Rewind file descriptor
+ call ip_lseek (fd, BOF)
+ nl = 1
+ offset = 1
+
+ nread = BLKSIZE / SZB_CHAR
+ fsize = fstati (fd, F_FILESIZE)
+ while (read (fd, Memc[buf], nread) != EOF) {
+ # Convert it to spp chars.
+ call ip_lskip (fd, nread)
+ call chrupk (Memc[buf], 1, Memc[cbuf], 1, BLKSIZE)
+ do i = 1, BLKSIZE {
+ if (Memc[cbuf+i-1] == '\n') {
+ nl = nl + 1
+ offset = offset + 1
+ if (nl == line)
+ goto done_
+ } else
+ offset = offset + 1
+ if (offset >= fsize)
+ goto err_
+ }
+ }
+err_ call sfree (sp)
+ call ip_lseek (fd, BOF)
+ return (ERR)
+
+done_ if (DEBUG) { call eprintf("ip_line: '%s'\n"); call pargi(offset) }
+ call sfree (sp)
+ call ip_lseek (fd, offset)
+ return (offset)
+ }
+end
+
+
+# IP_LOCATE -- Return the offset of the start of the given pattern.
+
+int procedure ip_locate (fd, offset, pattern)
+
+int fd #i input file descriptor
+int offset #i offset to begin search
+char pattern[ARB] #i pattern to locate
+
+pointer sp, cbuf, buf
+int fsize, nread, patlen, cur_offset, loc
+
+int fstati(), read(), strsearch(), strlen()
+
+define done_ 99
+
+begin
+ # Rewind file descriptor
+ call ip_lseek (fd, offset)
+ cur_offset = offset
+
+ call smark (sp)
+ call salloc (buf, BLKSIZE, TY_CHAR)
+ call salloc (cbuf, BLKSIZE, TY_CHAR)
+
+ if (DEBUG) { call eprintf("ip_loc: offset %d\n"); call pargi(offset)}
+
+ nread = BLKSIZE / SZB_CHAR
+ fsize = fstati (fd, F_FILESIZE)
+ patlen = strlen (pattern)
+ while (read (fd, Memc[buf], nread) != EOF) {
+ # Convert it to spp chars.
+ call ip_lskip (fd, nread)
+ call chrupk (Memc[buf], 1, Memc[cbuf], 1, BLKSIZE)
+ loc = strsearch (Memc[cbuf], pattern)
+ if (loc != 0) {
+ cur_offset = cur_offset + loc - 1 - patlen
+ goto done_
+ } else {
+ # Allow some overlap in case the pattern broke over the blocks.
+ cur_offset = cur_offset + BLKSIZE - 2 * patlen
+ call ip_lseek (fd, cur_offset)
+ if (cur_offset + BLKSIZE > fsize)
+ nread = fsize - cur_offset + 1
+ }
+ }
+ call sfree (sp)
+ call ip_lseek (fd, BOF)
+ return (ERR)
+
+done_ if (DEBUG) { call eprintf("ip_loc: %d\n"); call pargi(cur_offset)}
+ call sfree (sp)
+ call ip_lseek (fd, offset)
+ return (cur_offset)
+end
+
+
+# IP_LSEEK -- Set the file position as a byte offset.
+
+procedure ip_lseek (fd, offset)
+
+int fd #i file descriptor
+int offset #i requested offset
+
+long cur_offset, where, fsize
+int fstati()
+common /fiocom/ cur_offset
+
+begin
+ if (offset == BOF || offset == ERR) {
+ cur_offset = 1
+ call seek (fd, BOF)
+ } else {
+ fsize = fstati (fd, F_FILESIZE) * SZB_CHAR
+ cur_offset = min (fsize, offset)
+ where = min (fsize, (offset/SZB_CHAR+mod(offset,2)))
+ call seek (fd, where)
+ }
+end
+
+
+# IP_LNOTE -- Note the file position as a byte offset.
+
+int procedure ip_lnote (fd)
+
+int fd #i file descriptor (unused)
+
+long cur_offset
+common /fiocom/ cur_offset
+
+begin
+ return (cur_offset)
+end
+
+
+# IP_LSKIP -- Bump the file position by a byte offset.
+
+procedure ip_lskip (fd, skip)
+
+int fd #i file descriptor
+int skip
+
+long cur_offset
+common /fiocom/ cur_offset
+
+begin
+ call ip_lseek (fd, cur_offset+skip)
+end
diff --git a/pkg/dataio/import/generic/ipobands.x b/pkg/dataio/import/generic/ipobands.x
new file mode 100644
index 00000000..65c6c1c4
--- /dev/null
+++ b/pkg/dataio/import/generic/ipobands.x
@@ -0,0 +1,375 @@
+include <error.h>
+include <mach.h>
+include <evvexpr.h>
+include <fset.h>
+include "../import.h"
+include "../ipfcn.h"
+
+define DEBUG false
+define VDEBUG false
+
+
+# IP_GETOP -- Called by evvexpr to get an operand.
+
+procedure ip_getop (ip, opname, o)
+
+pointer ip #i task struct pointer
+char opname[ARB] #i operand name to retrieve
+pointer o #o output operand pointer
+
+int i, nops, found, optype
+pointer sp, buf
+pointer op
+
+int fstati(), ip_ptype(), strlen(), strncmp()
+bool streq()
+
+begin
+ # First see if it's one of the special file operands.
+ if (opname[1] == '$') {
+ if (strncmp(opname, "$FSIZE", 3) == 0) {
+ O_LEN(o) = 0
+ O_TYPE(o) = TY_INT
+ O_VALI(o) = fstati (IP_FD(ip), F_FILESIZE) * SZB_CHAR
+ } else if (strncmp(opname, "$FNAME", 3) == 0) {
+ call smark (sp)
+ call salloc (buf, SZ_FNAME, TY_CHAR)
+
+ call fstats (IP_FD(ip), F_FILENAME, Memc[buf], SZ_FNAME)
+
+ O_TYPE(o) = TY_CHAR
+ O_LEN(o) = strlen (Memc[buf]) + 1
+ call malloc (O_VALP(o), O_LEN(o), TY_CHAR)
+ call strcpy (Memc[buf], O_VALC(o), i)
+ call sfree (sp)
+ }
+
+ return
+ }
+
+ nops = IP_NPIXT(ip)
+ found = NO
+ do i = 1, nops {
+ # Search for operand name which matches requested value.
+ op = PTYPE(ip,i)
+ if (streq (Memc[IO_TAG(op)],opname)) {
+ found = YES
+ break
+ }
+ }
+
+ if (VDEBUG) {
+ call eprintf ("getop: opname=%s tag=%s found=%d ")
+ call pargstr(opname) ; call pargstr(Memc[IO_TAG(op)])
+ call pargi(found)
+ if (found == YES) call zzi_prop (op)
+ }
+
+ if (found == YES) {
+ # Copy operand descriptor to 'o'
+ optype = ip_ptype (IO_TYPE(op), IO_NBYTES(op))
+ switch (optype) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ O_LEN(o) = IO_NPIX(op)
+ O_TYPE(o) = TY_SHORT
+ call malloc (O_VALP(o), IO_NPIX(op), TY_SHORT)
+ call amovs (Mems[IO_DATA(op)], Mems[O_VALP(o)], IO_NPIX(op))
+
+ case TY_INT:
+ O_LEN(o) = IO_NPIX(op)
+ O_TYPE(o) = TY_INT
+ call malloc (O_VALP(o), IO_NPIX(op), TY_INT)
+ call amovi (Memi[IO_DATA(op)], Memi[O_VALP(o)], IO_NPIX(op))
+
+ case TY_LONG:
+ O_LEN(o) = IO_NPIX(op)
+ O_TYPE(o) = TY_LONG
+ call malloc (O_VALP(o), IO_NPIX(op), TY_LONG)
+ call amovl (Meml[IO_DATA(op)], Meml[O_VALP(o)], IO_NPIX(op))
+
+ case TY_REAL:
+ O_LEN(o) = IO_NPIX(op)
+ O_TYPE(o) = TY_REAL
+ call malloc (O_VALP(o), IO_NPIX(op), TY_REAL)
+ call amovr (Memr[IO_DATA(op)], Memr[O_VALP(o)], IO_NPIX(op))
+
+ case TY_DOUBLE:
+ O_LEN(o) = IO_NPIX(op)
+ O_TYPE(o) = TY_DOUBLE
+ call malloc (O_VALP(o), IO_NPIX(op), TY_DOUBLE)
+ call amovd (Memd[IO_DATA(op)], Memd[O_VALP(o)], IO_NPIX(op))
+
+ }
+
+ } else {
+ call smark (sp)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[buf], SZ_LINE, "Unknown outbands operand `%s'\n")
+ call pargstr(opname)
+ call sfree (sp)
+ call error (1, Memc[buf])
+ }
+end
+
+
+# IP_EVALUATE -- Evaluate the outbands expression.
+
+pointer procedure ip_evaluate (ip, expr)
+
+pointer ip #i task struct pointer
+char expr[ARB] #i expression to be evaluated
+
+pointer o # operand pointer to result
+
+int locpr()
+pointer evvexpr()
+extern ip_getop(), ip_obfcn()
+errchk evvexpr
+
+begin
+ if (DEBUG) { call eprintf("ip_eval: expr='%s'\n") ; call pargstr(expr) }
+
+ # Evaluate the expression.
+ iferr {
+ o = evvexpr (expr, locpr(ip_getop), ip, locpr(ip_obfcn), ip,
+ EV_RNGCHK)
+ } then
+ call erract (EA_FATAL)
+
+ return (o)
+end
+
+
+# IP_OBFCN -- Called by evvexpr to execute import outbands special functions.
+
+procedure ip_obfcn (ip, fcn, args, nargs, o)
+
+pointer ip #i task struct pointer
+char fcn[ARB] #i function to be executed
+pointer args[ARB] #i argument list
+int nargs #i number of arguments
+pointer o #o operand pointer
+
+pointer sp, buf
+pointer r, g, b, gray, color, cmap
+int i, len, v_nargs, func
+
+int or(), strdic()
+bool strne()
+
+define setop_ 99
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_FNAME, TY_CHAR)
+
+ # Lookup function in dictionary.
+ func = strdic (fcn, Memc[buf], SZ_LINE, OB_FUNCTIONS)
+ if (func > 0 && strne(fcn,Memc[buf]))
+ func = 0
+
+ # Abort if the function is not known.
+ if (func <= 0)
+ call xev_error1 ("unknown function `%s' called", fcn)
+
+ # Verify the correct number of arguments, negative value means a
+ # variable number of args, handle it in the evaluation.
+ switch (func) {
+ case GRAY, GREY:
+ v_nargs = 3
+ case FLIPX, FLIPY:
+ v_nargs = 1
+ case RED, GREEN, BLUE:
+ v_nargs = 1
+ }
+ if (v_nargs > 0 && nargs != v_nargs)
+ call xev_error2 ("function `%s' requires %d arguments",
+ fcn, v_nargs)
+ else if (v_nargs < 0 && nargs < abs(v_nargs))
+ call xev_error2 ("function `%s' requires at least %d arguments",
+ fcn, abs(v_nargs))
+
+ if (DEBUG) {
+ call eprintf ("obfcn: nargs=%d func=%d\n")
+ call pargi (nargs) ; call pargi (func)
+ do i = 1, nargs { call eprintf ("\t") ; call zzi_pevop (args[i]) }
+ call flush (STDERR)
+ }
+
+ # Evaluate the function.
+ switch (func) {
+ case GRAY, GREY:
+ # evaluate expression for NTSC grayscale.
+ r = O_VALP(args[1])
+ g = O_VALP(args[2])
+ b = O_VALP(args[3])
+ len = O_LEN(args[1]) - 1
+ O_LEN(o) = len + 1
+ O_TYPE(o) = TY_REAL
+ call malloc (O_VALP(o), len+1, TY_REAL)
+ gray = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ do i = 0, len {
+ Memr[gray+i] = R_COEFF * Mems[r+i] +
+ G_COEFF * Mems[g+i] +
+ B_COEFF * Mems[b+i]
+ }
+
+ case TY_INT:
+ do i = 0, len {
+ Memr[gray+i] = R_COEFF * Memi[r+i] +
+ G_COEFF * Memi[g+i] +
+ B_COEFF * Memi[b+i]
+ }
+
+ case TY_LONG:
+ do i = 0, len {
+ Memr[gray+i] = R_COEFF * Meml[r+i] +
+ G_COEFF * Meml[g+i] +
+ B_COEFF * Meml[b+i]
+ }
+
+ case TY_REAL:
+ do i = 0, len {
+ Memr[gray+i] = R_COEFF * Memr[r+i] +
+ G_COEFF * Memr[g+i] +
+ B_COEFF * Memr[b+i]
+ }
+
+ case TY_DOUBLE:
+ do i = 0, len {
+ Memr[gray+i] = R_COEFF * Memd[r+i] +
+ G_COEFF * Memd[g+i] +
+ B_COEFF * Memd[b+i]
+ }
+
+ }
+
+ case RED:
+ # Get the red colormap component of the image.
+ cmap = IP_CMAP(ip)
+ if (func <= 0)
+ call xev_error1 ("No colormap in image for function `%s'", fcn)
+ r = O_VALP(args[1])
+ len = O_LEN(args[1]) - 1
+ O_LEN(o) = len + 1
+ O_TYPE(o) = TY_SHORT
+ call malloc (O_VALP(o), len+1, TY_SHORT)
+ color = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ do i = 0, len
+ Mems[color+i] = CMAP(cmap,IP_RED,Mems[r+i]+1)
+
+ case TY_INT:
+ do i = 0, len
+ Mems[color+i] = CMAP(cmap,IP_RED,Memi[r+i]+1)
+
+ case TY_LONG:
+ do i = 0, len
+ Mems[color+i] = CMAP(cmap,IP_RED,Meml[r+i]+1)
+
+ }
+
+ case GREEN:
+ # Get the blue colormap component of the image.
+ cmap = IP_CMAP(ip)
+ if (func <= 0)
+ call xev_error1 ("No colormap in image for function `%s'", fcn)
+ g = O_VALP(args[1])
+ len = O_LEN(args[1]) - 1
+ O_LEN(o) = len + 1
+ O_TYPE(o) = TY_SHORT
+ call malloc (O_VALP(o), len+1, TY_SHORT)
+ color = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ do i = 0, len
+ Mems[color+i] = CMAP(cmap,IP_GREEN,Mems[g+i]+1)
+
+ case TY_INT:
+ do i = 0, len
+ Mems[color+i] = CMAP(cmap,IP_GREEN,char(Memi[g+i]+1))
+
+ case TY_LONG:
+ do i = 0, len
+ Mems[color+i] = CMAP(cmap,IP_GREEN,char(Meml[g+i]+1))
+
+ }
+
+ case BLUE:
+ # Get the blue colormap component of the image.
+ cmap = IP_CMAP(ip)
+ if (func <= 0)
+ call xev_error1 ("No colormap in image for function `%s'", fcn)
+ b = O_VALP(args[1])
+ len = O_LEN(args[1]) - 1
+ O_LEN(o) = len + 1
+ O_TYPE(o) = TY_SHORT
+ call malloc (O_VALP(o), len+1, TY_SHORT)
+ color = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ do i = 0, len
+ Mems[color+i] = CMAP(cmap,IP_BLUE,Mems[b+i]+1)
+
+ case TY_INT:
+ do i = 0, len
+ Mems[color+i] = CMAP(cmap,IP_BLUE,char(Memi[b+i]+1))
+
+ case TY_LONG:
+ do i = 0, len
+ Mems[color+i] = CMAP(cmap,IP_BLUE,char(Meml[b+i]+1))
+
+ }
+
+ case FLIPX:
+ # Set flag to reverse pixel order on output.
+ IP_FLIP(ip) = or (IP_FLIP(ip), FLIP_X)
+ goto setop_
+
+ case FLIPY:
+ # Set flag to write image from bottom to top.
+ IP_FLIP(ip) = or (IP_FLIP(ip), FLIP_Y)
+
+ # Copy argument operand descriptor to 'o'
+setop_ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ O_LEN(o) = O_LEN(args[1])
+ O_TYPE(o) = TY_SHORT
+ call malloc (O_VALP(o), O_LEN(args[1]), TY_SHORT)
+ call amovs (Mems[O_VALP(ARGS[1])], Mems[O_VALP(o)], O_LEN(o))
+
+ case TY_INT:
+ O_LEN(o) = O_LEN(args[1])
+ O_TYPE(o) = TY_INT
+ call malloc (O_VALP(o), O_LEN(args[1]), TY_INT)
+ call amovi (Memi[O_VALP(args[1])], Memi[O_VALP(o)], O_LEN(o))
+
+ case TY_LONG:
+ O_LEN(o) = O_LEN(args[1])
+ O_TYPE(o) = TY_LONG
+ call malloc (O_VALP(o), O_LEN(args[1]), TY_LONG)
+ call amovl (Meml[O_VALP(args[1])], Meml[O_VALP(o)], O_LEN(o))
+
+ case TY_REAL:
+ O_LEN(o) = O_LEN(args[1])
+ O_TYPE(o) = TY_REAL
+ call malloc (O_VALP(o), O_LEN(args[1]), TY_REAL)
+ call amovr (Memr[O_VALP(args[1])], Memr[O_VALP(o)], O_LEN(o))
+
+ case TY_DOUBLE:
+ O_LEN(o) = O_LEN(args[1])
+ O_TYPE(o) = TY_DOUBLE
+ call malloc (O_VALP(o), O_LEN(args[1]), TY_DOUBLE)
+ call amovd (Memd[O_VALP(args[1])], Memd[O_VALP(o)], O_LEN(o))
+
+ }
+
+ }
+
+ if (DEBUG) { call zzi_pevop (o) }
+
+ call sfree (sp)
+end
diff --git a/pkg/dataio/import/generic/ipproc.x b/pkg/dataio/import/generic/ipproc.x
new file mode 100644
index 00000000..def48b1c
--- /dev/null
+++ b/pkg/dataio/import/generic/ipproc.x
@@ -0,0 +1,921 @@
+include <mach.h>
+include <imhdr.h>
+include <evvexpr.h>
+include "../import.h"
+
+define DEBUG false
+
+
+# IP_PRBAND -- Process a band interleaved file.
+
+procedure ip_prband (ip, fd, im, cmap)
+
+pointer ip #i task struct pointer
+int fd #i inpout file descriptor
+pointer im #i output image pointer
+pointer cmap #i colormap pointer
+
+int i, j, nlines, npix
+int optype, nbytes_pix, percent
+int cur_offset, band_offset, line_offset
+
+int ip_ptype()
+long ip_lnote()
+
+begin
+ # Rewind the file and skip header pixels.
+ call ip_lseek (fd, BOF)
+ call ip_lseek (fd, IP_HSKIP(ip)+1)
+
+ # Compute the offset between the same pixel in different bands. This
+ # is the area of the image plus any image padding, computed as a
+ # byte offset.
+ optype = ip_ptype (IO_TYPE(PTYPE(ip,1)),IO_NBYTES(PTYPE(ip,1)))
+ switch (optype) {
+ case TY_UBYTE: nbytes_pix = 1
+ case TY_USHORT, TY_SHORT: nbytes_pix = SZB_CHAR * SZ_SHORT
+ case TY_INT: nbytes_pix = SZB_CHAR * SZ_INT32
+ case TY_LONG: nbytes_pix = SZB_CHAR * SZ_LONG
+ case TY_REAL: nbytes_pix = SZB_CHAR * SZ_REAL
+ case TY_DOUBLE: nbytes_pix = SZB_CHAR * SZ_DOUBLE
+ }
+ band_offset = (IP_AXLEN(ip,1) * (IP_AXLEN(ip,2)-1)) +
+ ((IP_LSKIP(ip) + IP_LPAD(ip)) * (IP_AXLEN(ip,2)-1)) +
+ IP_BSKIP(ip)
+ band_offset = (band_offset * nbytes_pix) #+ 1
+
+ if (DEBUG) {
+ call eprintf ("ip_prband: band_offset=%d curpos=%d\n")
+ call pargi(band_offset) ; call pargi(ip_lnote(fd))
+ call zzi_prstruct ("ip_prband", ip)
+ }
+
+ # Patch up the pixtype param if needed.
+ call ip_fix_pixtype (ip)
+
+ # See if we need to create any outbands operands if the user didn't.
+ if (IP_NBANDS(ip) == ERR)
+ call ip_fix_outbands (ip)
+
+ # Loop over the image lines.
+ nlines = IP_AXLEN(ip,2)
+ npix = IP_AXLEN(ip,1)
+ percent = 0
+ do i = 1, nlines {
+ # Skip pixels at front of line
+ line_offset = ip_lnote (fd)
+ if (IP_LSKIP(ip) != 0)
+ call ip_lskip (fd, IP_LSKIP(ip))
+
+ # Read pixels in the line and save as operand.
+ call ip_rdline (ip, fd, 1, npix, cmap)
+
+ # Skip pixels at end of line.
+ if (IP_LPAD(ip) != 0)
+ call ip_lskip (fd, IP_LPAD(ip))
+ cur_offset = ip_lnote (fd)
+
+ # Loop over each of the remaining pixtypes.
+ do j = 2, IP_NPIXT(ip) {
+ # Seek to offset of next band (i.e. line_offset + band_offset).
+ call ip_lskip (fd, band_offset)
+ if (IP_LSKIP(ip) != 0)
+ call ip_lskip (fd, IP_LSKIP(ip))
+ call ip_rdline (ip, fd, j, npix, cmap) # read pixels in the line
+ if (IP_LPAD(ip) != 0)
+ call ip_lskip (fd, IP_LPAD(ip))
+ }
+
+ # Evaluate and write the outbands expressions.
+ call ip_probexpr (ip, im, npix, i)
+
+ # Print percent done if being verbose
+ #if (IP_VERBOSE(ip) == YES)
+ call ip_pstat (ip, i, percent)
+
+ # Restore file pointer to cur_offset.
+ call ip_lseek (fd, cur_offset)
+ }
+ do i = 1, IP_NBANDS(ip)
+ call mfree (BUFFER(ip,i), IM_PIXTYPE(im))
+end
+
+
+# IP_PRLINE -- Process a line interleaved file.
+
+procedure ip_prline (ip, fd, im, cmap)
+
+pointer ip #i task struct pointer
+int fd #i inpout file descriptor
+pointer im #i output image pointer
+pointer cmap #i colormap pointer
+
+int i, j, nlines, npix, percent
+
+begin
+ # Rewind the file and skip header pixels.
+ call ip_lseek (fd, BOF)
+ call ip_lseek (fd, IP_HSKIP(ip)+1)
+
+ if (DEBUG) {
+ call eprintf ("ip_prline:\n")
+ call zzi_prstruct ("ip_prline", ip)
+ }
+
+ # Patch up the pixtype param if needed.
+ call ip_fix_pixtype (ip)
+
+ # See if we need to create any outbands operands if the user didn't.
+ if (IP_NBANDS(ip) == ERR)
+ call ip_fix_outbands (ip)
+
+ # Loop over the image lines.
+ nlines = IP_AXLEN(ip,2)
+ npix = IP_AXLEN(ip,1)
+ percent = 0
+ do i = 1, nlines {
+
+ do j = 1, IP_NPIXT(ip) {
+ # Skip pixels at front of line
+ call ip_lskip (fd, IP_LSKIP(ip))
+
+ # Read pixels in the line and save as operand.
+ call ip_rdline (ip, fd, j, npix, cmap)
+
+ # Skip pixels at end of line.
+ call ip_lskip (fd, IP_LPAD(ip))
+ }
+
+ # Evaluate and write the outbands expressions.
+ call ip_probexpr (ip, im, npix, i)
+
+ # Print percent done if being verbose
+ #if (IP_VERBOSE(ip) == YES)
+ call ip_pstat (ip, i, percent)
+ }
+ do i = 1, IP_NBANDS(ip)
+ call mfree (BUFFER(ip,i), IM_PIXTYPE(im))
+end
+
+
+# IP_PRPIX -- Process a pixel interleaved file.
+
+procedure ip_prpix (ip, fd, im, cmap)
+
+pointer ip #i task struct pointer
+int fd #i inpout file descriptor
+pointer im #i output image pointer
+pointer cmap #i colormap pointer
+
+pointer op, data
+int i, swap, optype, nlines
+int percent, npix, totpix
+
+int and(), ip_ptype()
+
+begin
+ # Rewind the file and skip header pixels.
+ call ip_lseek (fd, BOF)
+ call ip_lseek (fd, IP_HSKIP(ip)+1)
+
+ if (DEBUG) { call eprintf ("ip_prpix: ") }
+
+ # See if we need to create any outbands operands if the user didn't.
+ if (IP_NBANDS(ip) == ERR)
+ call ip_fix_outbands (ip)
+
+ # Allocate the pixtype data pointers.
+ npix = IP_AXLEN(ip,1)
+ nlines = IP_NPIXT(ip)
+ do i = 1, nlines {
+ op = PTYPE(ip,i)
+ optype = ip_ptype (IO_TYPE(op),IO_NBYTES(op))
+ IO_NPIX(op) = npix
+ if (IO_DATA(op) == NULL)
+ if (optype == TY_UBYTE)
+ call malloc (IO_DATA(op), npix, TY_SHORT)
+ else
+ call malloc (IO_DATA(op), npix, optype)
+ }
+
+ # Loop over the image lines.
+ nlines = IP_AXLEN(ip,2)
+ totpix = npix * IP_NPIXT(ip)
+ swap = IP_SWAP(ip)
+ percent = 0
+ if (DEBUG) {
+ call zzi_prstruct ("ip_prpix", ip)
+ call eprintf ("nl=%d np=%d tp=%d:\n")
+ call pargi(nlines) ; call pargi(npix) ; call pargi(totpix)
+ }
+ do i = 1, nlines {
+
+ # Skip pixels at front of line
+ call ip_lskip (fd, IP_LSKIP(ip))
+
+ # Read pixels in the line.
+ switch (optype) {
+ case TY_UBYTE:
+ call ip_agetb (fd, data, totpix)
+ call ip_lskip (fd, totpix)
+ # Apply a colormap to the bytes. In general a pixel-interleaved
+ # file is a 24-bit True Color image, but maybe this is a
+ # 3-D color index file?
+ if (cmap != NULL && IP_USE_CMAP(ip) == YES)
+ call ip_gray_cmap (Memc[data], totpix, cmap)
+
+ case TY_USHORT:
+ call ip_agetu (fd, data, totpix)
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I2) == S_I2) {
+ call bswap2 (Mems[data], 1, Mems[data], 1,
+ (totpix*(SZ_SHORT*SZB_CHAR)))
+ }
+ call ip_lskip (fd, (totpix * (SZB_CHAR * SZ_SHORT)))
+
+
+ case TY_SHORT:
+ call ip_agets (fd, data, totpix)
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I2) == S_I2) {
+ call bswap2 (Mems[data], 1, Mems[data], 1,
+ (totpix*(SZ_SHORT*SZB_CHAR)))
+ }
+
+ call ip_lskip (fd, (totpix * (SZB_CHAR * SZ_SHORT)))
+
+ case TY_INT:
+ call ip_ageti (fd, data, totpix)
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I4) == S_I4) {
+ if (SZ_INT != SZ_INT32) {
+ call ipak32 (Memi[data], Memi[data], totpix)
+ call bswap4 (Memi[data], 1, Memi[data], 1,
+ (totpix*(SZ_INT32*SZB_CHAR)))
+ } else {
+ call bswap4 (Memi[data], 1, Memi[data], 1,
+ (totpix*(SZ_INT*SZB_CHAR)))
+ }
+ }
+
+ call ip_lskip (fd, (totpix * (SZB_CHAR * SZ_INT32)))
+
+ case TY_LONG:
+ call ip_agetl (fd, data, totpix)
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I4) == S_I4) {
+ if (SZ_INT != SZ_INT32) {
+ call ipak32 (Meml[data], Meml[data], totpix)
+ call bswap4 (Meml[data], 1, Meml[data], 1,
+ (totpix*(SZ_INT32*SZB_CHAR)))
+ } else {
+ call bswap4 (Meml[data], 1, Meml[data], 1,
+ (totpix*(SZ_INT*SZB_CHAR)))
+ }
+ }
+
+ call ip_lskip (fd, (totpix * (SZB_CHAR * SZ_INT32)))
+
+ case TY_REAL:
+ call ip_agetr (fd, data, totpix)
+ if (and(swap, S_ALL) == S_ALL) {
+ call bswap4 (Memr[data], 1, Memr[data], 1,
+ (totpix*(SZ_REAL*SZB_CHAR)))
+ }
+
+ call ip_lskip (fd, (totpix * (SZB_CHAR * SZ_REAL)))
+
+ case TY_DOUBLE:
+ call ip_agetd (fd, data, totpix)
+ if (and(swap, S_ALL) == S_ALL) {
+ call bswap8 (Memd[data], 1, Memd[data], 1,
+ (totpix*(SZ_DOUBLE*SZB_CHAR)))
+ }
+
+ call ip_lskip (fd, (totpix * (SZB_CHAR * SZ_DOUBLE)))
+
+ }
+
+ # Skip pixels at end of line.
+ call ip_lskip (fd, IP_LPAD(ip))
+
+ # Separate pixels into different vectors.
+ call ip_upkpix (ip, data, npix)
+
+ # Evaluate and write the outbands expressions.
+ call ip_probexpr (ip, im, npix, i)
+
+ # Print percent done if being verbose
+ #if (IP_VERBOSE(ip) == YES)
+ call ip_pstat (ip, i, percent)
+ }
+
+ if (optype == TY_UBYTE)
+ call mfree (data, TY_SHORT)
+ else
+ call mfree (data, optype)
+ do i = 1, IP_NBANDS(ip)
+ call mfree (BUFFER(ip,i), IM_PIXTYPE(im))
+end
+
+
+# IP_PROBEXPR -- Process each of the outbands expressions and write the result
+# to the output image.
+
+procedure ip_probexpr (ip, im, npix, line)
+
+pointer ip #i task struct pointer
+pointer im #i output image pointer
+int npix #i number of output pixels
+int line #i line number
+
+int i
+pointer out, ip_evaluate()
+
+begin
+ # Loop over outbands expressions.
+ do i = 1, IP_NBANDS(ip) {
+ # Evaluate outbands expression.
+ out = ip_evaluate (ip, O_EXPR(ip,i))
+
+ # Write bands to output image
+ if (IP_OUTPUT(ip) != IP_NONE)
+ call ip_wrline (ip, im, out, npix, line, i)
+
+ call evvfree (out)
+ }
+end
+
+
+# IP_RDLINE -- Read a line of pixels from the binary file.
+
+procedure ip_rdline (ip, fd, pnum, npix, cmap)
+
+pointer ip #i task struct pointer
+int fd #i input file descriptor
+int pnum #i pixtype number
+int npix #i number of pixels to read
+pointer cmap #i colormap pointer
+
+pointer op, data
+int swap, ptype
+
+int and(), ip_ptype()
+
+begin
+ # Read pixels in the line and save as operand.
+ op = PTYPE(ip,pnum)
+ ptype = ip_ptype (IO_TYPE(op), IO_NBYTES(op))
+ data = IO_DATA(op)
+ swap = IP_SWAP(ip)
+ IO_NPIX(op) = npix
+
+ switch (ptype) {
+ case TY_UBYTE:
+ call ip_agetb (fd, data, npix)
+ call ip_lskip (fd, npix)
+ # Apply a colormap to the bytes. If the colormap is non-null we
+ # assume the bytes are color indices into a colormap.
+ if (cmap != NULL && IP_USE_CMAP(ip) == YES)
+ call ip_gray_cmap (Memc[data], npix, cmap)
+
+ case TY_USHORT:
+ call ip_agetu (fd, data, npix)
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I2) == S_I2) {
+ call bswap2 (Mems[data], 1, Mems[data], 1,
+ (npix*(SZ_SHORT*SZB_CHAR)))
+ }
+ call ip_lskip (fd, (npix * (SZB_CHAR * SZ_SHORT)))
+
+ case TY_SHORT:
+ call ip_agets (fd, data, npix)
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I2) == S_I2) {
+ call bswap2 (Mems[data], 1, Mems[data], 1,
+ (npix*(SZ_SHORT*SZB_CHAR)))
+ }
+
+ call ip_lskip (fd, npix * (SZB_CHAR * SZ_SHORT))
+
+ case TY_INT:
+ call ip_ageti (fd, data, npix)
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I2) == S_I4) {
+ if (SZ_INT != SZ_INT32) {
+ call ipak32 (Memi[data], Memi[data], npix)
+ call bswap4 (Memi[data], 1, Memi[data], 1,
+ (npix*(SZ_INT32*SZB_CHAR)))
+ } else {
+ call bswap4 (Memi[data], 1, Memi[data], 1,
+ (npix*(SZ_INT*SZB_CHAR)))
+ }
+ }
+
+ call ip_lskip (fd, npix * (SZB_CHAR * SZ_INT32))
+
+ case TY_LONG:
+ call ip_agetl (fd, data, npix)
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I2) == S_I4) {
+ if (SZ_INT != SZ_INT32) {
+ call ipak32 (Meml[data], Meml[data], npix)
+ call bswap4 (Meml[data], 1, Meml[data], 1,
+ (npix*(SZ_INT32*SZB_CHAR)))
+ } else {
+ call bswap4 (Meml[data], 1, Meml[data], 1,
+ (npix*(SZ_LONG*SZB_CHAR)))
+ }
+ }
+
+ call ip_lskip (fd, npix * (SZB_CHAR * SZ_INT32))
+
+ case TY_REAL:
+ call ip_agetr (fd, data, npix)
+ if (and(swap, S_ALL) == S_ALL) {
+ call bswap4 (Memr[data], 1, Memr[data], 1,
+ (npix*(SZ_REAL*SZB_CHAR)))
+ }
+
+ call ip_lskip (fd, npix * (SZB_CHAR * SZ_REAL))
+
+ case TY_DOUBLE:
+ call ip_agetd (fd, data, npix)
+ if (and(swap, S_ALL) == S_ALL) {
+ call bswap8 (Memd[data], 1, Memd[data], 1,
+ (npix*(SZ_DOUBLE*SZB_CHAR)))
+ }
+
+ call ip_lskip (fd, npix * (SZB_CHAR * SZ_DOUBLE))
+
+ }
+ IO_DATA(op) = data
+end
+
+
+# IP_WRLINE -- Write a line of pixels to the output image. We handle image
+# flipping here to avoid possibly doing it several times while the outbands
+# expression is being evaluated.
+
+procedure ip_wrline (ip, im, out, npix, line, band)
+
+pointer ip #i task struct pointer
+pointer im #i output image pointer
+pointer out #i output operand pointer
+int npix #i number of pixels to read
+int line #i image line number
+int band #i image band number
+
+int i, lnum, type
+int nldone, blnum
+pointer sp, dptr, data, optr
+bool lastline
+
+int and()
+pointer imps3s(), imps3i(), imps3l(), imps3r(), imps3d()
+pointer ip_chtype()
+
+data blnum /0/
+data nldone /1/
+data lastline /false/
+
+begin
+ call smark (sp)
+
+ # The first thing we do is change the datatype of the operand to
+ # match the output pixel type.
+ if (IP_OUTTYPE(ip) != NULL) {
+ if (IP_OUTTYPE(ip) == O_TYPE(out))
+ optr = O_VALP(out)
+ else
+ optr = ip_chtype (out, IP_OUTTYPE(ip))
+ }
+ type = IP_OUTTYPE(ip)
+
+ # See if we're flipping image in Y, and adjust the line number.
+ if (and(IP_FLIP(ip),FLIP_Y) == FLIP_Y) {
+ lnum = IP_AXLEN(ip,2) - line + 1
+ if (band == 1)
+ blnum = IP_SZBUF(ip) - mod (line-1, IP_SZBUF(ip))
+ lastline = (lnum == 1)
+ } else {
+ lnum = line
+ if (band == 1)
+ blnum = blnum + 1
+ lastline = (lnum == IP_AXLEN(ip,2))
+ }
+
+ # See if we're flipping image in x, and reverse the pixels.
+ if (and(IP_FLIP(ip),FLIP_X) == FLIP_X) {
+ call salloc (dptr, npix, type)
+ do i = 1, npix {
+ switch (type) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ Mems[dptr+i-1] = Mems[optr+(npix-i)]
+
+ case TY_INT:
+ Memi[dptr+i-1] = Memi[optr+(npix-i)]
+
+ case TY_LONG:
+ Meml[dptr+i-1] = Meml[optr+(npix-i)]
+
+ case TY_REAL:
+ Memr[dptr+i-1] = Memr[optr+(npix-i)]
+
+ case TY_DOUBLE:
+ Memd[dptr+i-1] = Memd[optr+(npix-i)]
+
+ }
+ }
+ } else
+ dptr = optr
+
+ # Make sure the image pixtype is set.
+ if (IM_PIXTYPE(im) == NULL)
+ IM_PIXTYPE(im) = type
+
+ # Allocate the buffer pointer if needed.
+ if (BUFFER(ip,band) == NULL)
+ call calloc (BUFFER(ip,band), npix*IP_SZBUF(ip), IP_OUTTYPE(ip))
+
+ if (nldone < IP_SZBUF(ip) && !lastline) {
+ # Copy the image line to the buffer
+ data = BUFFER(ip,band)
+ switch (type) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ call amovs (Mems[dptr], Mems[data+((blnum-1)*npix)], npix)
+
+ case TY_INT:
+ call amovi (Memi[dptr], Memi[data+((blnum-1)*npix)], npix)
+
+ case TY_LONG:
+ call amovl (Meml[dptr], Meml[data+((blnum-1)*npix)], npix)
+
+ case TY_REAL:
+ call amovr (Memr[dptr], Memr[data+((blnum-1)*npix)], npix)
+
+ case TY_DOUBLE:
+ call amovd (Memd[dptr], Memd[data+((blnum-1)*npix)], npix)
+
+ }
+ if (band == IP_NBANDS(ip))
+ nldone = nldone + 1
+
+ } else {
+ # Write the buffer to the image as a section.
+ data = BUFFER(ip,band)
+ switch (type) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ call amovs (Mems[dptr], Mems[data+((blnum-1)*npix)], npix)
+ if (and(IP_FLIP(ip),FLIP_Y) == FLIP_Y) {
+ data = imps3s (im, 1, npix,
+ max(1,(lnum-IP_SZBUF(ip)+1)+IP_SZBUF(ip)-1),
+ max(1,lnum+min(nldone,IP_SZBUF(ip))-1),
+ band, band)
+ call amovs (Mems[BUFFER(ip,band)+(blnum-1)*npix],
+ Mems[data], npix*(IP_SZBUF(ip)-blnum+1))
+ } else {
+ data = imps3s (im, 1, npix,
+ min(IP_AXLEN(ip,2),(lnum-blnum+1)),
+ min(IP_AXLEN(ip,2),lnum),
+ band, band)
+ call amovs (Mems[BUFFER(ip,band)], Mems[data], npix*blnum)
+ }
+
+ case TY_INT:
+ call amovi (Memi[dptr], Memi[data+((blnum-1)*npix)], npix)
+ if (and(IP_FLIP(ip),FLIP_Y) == FLIP_Y) {
+ data = imps3i (im, 1, npix,
+ max(1,(lnum-IP_SZBUF(ip)+1)+IP_SZBUF(ip)-1),
+ max(1,lnum+min(nldone,IP_SZBUF(ip))-1),
+ band, band)
+ call amovi (Memi[BUFFER(ip,band)+(blnum-1)*npix],
+ Memi[data], npix*(IP_SZBUF(ip)-blnum+1))
+ } else {
+ data = imps3i (im, 1, npix,
+ min(IP_AXLEN(ip,2),(lnum-blnum+1)),
+ min(IP_AXLEN(ip,2),lnum),
+ band, band)
+ call amovi (Memi[BUFFER(ip,band)], Memi[data],
+ npix*blnum)
+ }
+
+ case TY_LONG:
+ call amovl (Meml[dptr], Meml[data+((blnum-1)*npix)], npix)
+ if (and(IP_FLIP(ip),FLIP_Y) == FLIP_Y) {
+ data = imps3l (im, 1, npix,
+ max(1,(lnum-IP_SZBUF(ip)+1)+IP_SZBUF(ip)-1),
+ max(1,lnum+min(nldone,IP_SZBUF(ip))-1),
+ band, band)
+ call amovl (Meml[BUFFER(ip,band)+(blnum-1)*npix],
+ Meml[data], npix*(IP_SZBUF(ip)-blnum+1))
+ } else {
+ data = imps3l (im, 1, npix,
+ min(IP_AXLEN(ip,2),(lnum-blnum+1)),
+ min(IP_AXLEN(ip,2),lnum),
+ band, band)
+ call amovl (Meml[BUFFER(ip,band)], Meml[data],
+ npix*blnum)
+ }
+
+ case TY_REAL:
+ call amovr (Memr[dptr], Memr[data+((blnum-1)*npix)], npix)
+ if (and(IP_FLIP(ip),FLIP_Y) == FLIP_Y) {
+ data = imps3r (im, 1, npix,
+ max(1,(lnum-IP_SZBUF(ip)+1)+IP_SZBUF(ip)-1),
+ max(1,lnum+min(nldone,IP_SZBUF(ip))-1),
+ band, band)
+ call amovr (Memr[BUFFER(ip,band)+(blnum-1)*npix],
+ Memr[data], npix*(IP_SZBUF(ip)-blnum+1))
+ } else {
+ data = imps3r (im, 1, npix,
+ min(IP_AXLEN(ip,2),(lnum-blnum+1)),
+ min(IP_AXLEN(ip,2),lnum),
+ band, band)
+ call amovr (Memr[BUFFER(ip,band)], Memr[data],
+ npix*blnum)
+ }
+
+ case TY_DOUBLE:
+ call amovd (Memd[dptr], Memd[data+((blnum-1)*npix)], npix)
+ if (and(IP_FLIP(ip),FLIP_Y) == FLIP_Y) {
+ data = imps3d (im, 1, npix,
+ max(1,(lnum-IP_SZBUF(ip)+1)+IP_SZBUF(ip)-1),
+ max(1,lnum+min(nldone,IP_SZBUF(ip))-1),
+ band, band)
+ call amovd (Memd[BUFFER(ip,band)+(blnum-1)*npix],
+ Memd[data], npix*(IP_SZBUF(ip)-blnum+1))
+ } else {
+ data = imps3d (im, 1, npix,
+ min(IP_AXLEN(ip,2),(lnum-blnum+1)),
+ min(IP_AXLEN(ip,2),lnum),
+ band, band)
+ call amovd (Memd[BUFFER(ip,band)], Memd[data],
+ npix*blnum)
+ }
+
+ }
+ if (band == IP_NBANDS(ip)) {
+ nldone = 1
+ blnum = 0
+ }
+ }
+
+ if (IP_OUTTYPE(ip) != O_TYPE(out))
+ call mfree (optr, type)
+ call sfree (sp)
+end
+
+
+# IP_UPKPIX -- Unpack a line of pixel-interleaved pixels to the separate
+# pixtype operand arrays.
+
+procedure ip_upkpix (ip, ptr, npix)
+
+pointer ip #i task struct pointer
+pointer ptr #i pointer to pixels
+int npix #i number of pixels in line
+
+pointer op[IM_MAXDIM]
+int i, j, np, optype[IM_MAXDIM]
+
+int ip_ptype()
+
+begin
+ np = IP_NPIXT(ip)
+ do j = 1, np {
+ op[j] = PTYPE(ip,j)
+ optype[j] = ip_ptype (IO_TYPE(op[j]),IO_NBYTES(op[j]))
+ }
+
+ do j = 1, np {
+
+ do i = 0, npix-1 {
+ switch (optype[j]) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ Mems[IO_DATA(op[j])+i] = Mems[ptr+(i*np+j)-1]
+
+ case TY_INT:
+ Memi[IO_DATA(op[j])+i] = Memi[ptr+(i*np+j)-1]
+
+ case TY_LONG:
+ Meml[IO_DATA(op[j])+i] = Meml[ptr+(i*np+j)-1]
+
+ case TY_REAL:
+ Memr[IO_DATA(op[j])+i] = Memr[ptr+(i*np+j)-1]
+
+ case TY_DOUBLE:
+ Memd[IO_DATA(op[j])+i] = Memd[ptr+(i*np+j)-1]
+
+ }
+ }
+ }
+end
+
+
+# IP_FIX_PIXTYPE -- Create the pixtype operands for 3-D band or line-
+# interleaved files. These weren't allocated at first since the pixtype
+# parameter or database field was atomic.
+
+procedure ip_fix_pixtype (ip)
+
+pointer ip #i task struct pointer
+
+pointer op, op1
+int i, nnp
+
+begin
+ if (DEBUG) {
+ call eprintf ("fix_pixtype: npixt=%d ndim=%d inter=%d\n")
+ call pargi(IP_NPIXT(ip)) ; call pargi(IP_NDIM(ip))
+ call pargi(IP_INTERLEAVE(ip)) ; call flush (STDERR)
+ }
+
+ # See if there's anything to be fixed.
+ if (IP_NDIM(ip) < 3 || IP_NDIM(ip) < IP_NPIXT(ip))
+ return
+ if (BAND_INTERLEAVED(ip) && (IP_NPIXT(ip) == IP_NDIM(ip)))
+ return
+ if (LINE_INTERLEAVED(ip) && (IP_NPIXT(ip) == IP_INTERLEAVE(ip)))
+ return
+
+ if (LINE_INTERLEAVED(ip))
+ nnp = IP_INTERLEAVE(ip)
+ else
+ #nnp = IP_NDIM(ip)
+ nnp = IP_AXLEN(ip,3)
+
+ # Make the new pixtype operands.
+ op1 = PTYPE(ip,1)
+ do i = 2, nnp {
+ call ip_alloc_operand (PTYPE(ip,i))
+ op = PTYPE(ip,i)
+ IO_TYPE(op) = IO_TYPE(op1)
+ IO_NBYTES(op) = IO_NBYTES(op1)
+ call sprintf (OP_TAG(op), SZ_TAG, "b%d")
+ call pargi (i)
+ }
+ IP_NPIXT(ip) = nnp
+
+ if (DEBUG) { call zzi_prstruct ("fix_pixtype", ip) }
+end
+
+
+# IP_FIX_OUTBANDS -- Create the outbands operands if none were specified in
+# the parameter file.
+
+procedure ip_fix_outbands (ip)
+
+pointer ip #i task struct pointer
+
+pointer sp, buf
+pointer im
+int i, nbands
+
+define SZ_OBSTR 2500
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_FNAME, TY_CHAR)
+
+ if (DEBUG) {
+ call eprintf ("fix_outbands: npixt=%d ndim=%d inter=%d\n")
+ call pargi(IP_NPIXT(ip)) ; call pargi(IP_NDIM(ip))
+ call pargi(IP_INTERLEAVE(ip)) ; call flush (STDERR)
+ }
+
+ # Free up the existing outbands operands.
+ nbands = IP_NBANDS(ip)
+ do i = 1, nbands
+ call ip_free_outbands (OBANDS(ip,i))
+
+ # Create an outbands parameter string according to the tags in the
+ # pixtype structure. This way we preserve any user-defined tags on
+ # output.
+ nbands = IP_NPIXT(ip)
+ call aclrc (Memc[buf], SZ_FNAME)
+ do i = 1, nbands {
+ call ip_alloc_outbands (OBANDS(ip,i))
+ call aclrc (Memc[buf], SZ_FNAME)
+ call sprintf (Memc[buf], SZ_FNAME, "b%d")
+ call pargi (i)
+ call strcpy (Memc[buf], O_EXPR(ip,i), SZ_EXPR)
+
+ # Load the operand struct.
+ call strcpy (Memc[buf], OP_TAG(O_OP(ip,i)), SZ_EXPR)
+ }
+ IP_NBANDS(ip) = nbands
+
+ # Fix the output image dimensions.
+ im = IP_IM(ip)
+ IM_LEN(im,3) = IP_AXLEN(ip,3)
+ if (IP_NBANDS(ip) > 1)
+ IM_NDIM(im) = 3
+ else
+ IM_NDIM(im) = IP_NDIM(ip)
+
+ call sfree (sp)
+
+ if (DEBUG) { call zzi_prstruct ("fix_outbands", ip) }
+end
+
+
+# IP_CHTYPE - Change the expression operand vector to the output datatype.
+# We allocate and return a pointer to the correct type to the converted
+# pixels, this pointer must be freed later on.
+
+pointer procedure ip_chtype (op, type)
+
+pointer op #i evvexpr operand pointer
+int type #i new type of pointer
+
+pointer out, coerce()
+
+begin
+ # Allocate the pointer and coerce it so the routine works.
+ if (type == TY_UBYTE || type == TY_CHAR)
+ call calloc (out, O_LEN(op), TY_CHAR)
+ else {
+ call calloc (out, O_LEN(op), type)
+ out = coerce (out, type, TY_CHAR)
+ }
+
+ # Change the pixel type.
+ switch (O_TYPE(op)) {
+ case TY_CHAR:
+ call achtc (Memc[O_VALP(op)], Memc[out], O_LEN(op), type)
+ case TY_SHORT:
+ call achts (Mems[O_VALP(op)], Memc[out], O_LEN(op), type)
+ case TY_INT:
+ call achti (Memi[O_VALP(op)], Memc[out], O_LEN(op), type)
+ case TY_LONG:
+ call achtl (Meml[O_VALP(op)], Memc[out], O_LEN(op), type)
+ case TY_REAL:
+ call achtr (Memr[O_VALP(op)], Memc[out], O_LEN(op), type)
+ case TY_DOUBLE:
+ call achtd (Memd[O_VALP(op)], Memc[out], O_LEN(op), type)
+ default:
+ call error (0, "Invalid output type requested.")
+ }
+
+ out = coerce (out, TY_CHAR, type)
+ return (out)
+end
+
+
+define NTYPES 6
+define NBITPIX 4
+
+# IP_PTYPE -- For a given pixtype parameter return the corresponding IRAF
+# data type.
+
+int procedure ip_ptype (type, nbytes)
+
+int type #i pixel type
+int nbytes #i number of bytes
+
+int i, pt, pb, ptype
+int tindex[NTYPES], bindex[NBITPIX], ttbl[NTYPES*NBITPIX]
+
+data tindex /PT_BYTE, PT_UINT, PT_INT, PT_IEEE, PT_NATIVE, PT_SKIP/
+data bindex /1, 2, 4, 8/
+
+data (ttbl(i), i= 1, 4) /TY_UBYTE, TY_USHORT, TY_INT, 0/ # B
+data (ttbl(i), i= 5, 8) /TY_UBYTE, TY_USHORT, 0, 0/ # U
+data (ttbl(i), i= 9,12) /TY_UBYTE, TY_SHORT, TY_INT, 0/ # I
+data (ttbl(i), i=13,16) / 0, 0, TY_REAL, TY_DOUBLE/ # R
+data (ttbl(i), i=17,20) / 0, 0, TY_REAL, TY_DOUBLE/ # N
+data (ttbl(i), i=21,24) /TY_UBYTE, TY_USHORT, TY_REAL, TY_DOUBLE/ # X
+
+begin
+ if (type == 0 || nbytes == 0) # uninitialized values
+ return (0)
+
+ pt = NTYPES
+ do i = 1, NTYPES {
+ if (tindex[i] == type)
+ pt = i
+ }
+ pb = NBITPIX
+ do i = 1, NBITPIX {
+ if (bindex[i] == nbytes)
+ pb = i
+ }
+
+ ptype = ttbl[(pt-1)*NBITPIX+pb]
+ if (ptype == 0)
+ call error (0, "Invalid pixtype specified.")
+ else
+ return (ptype)
+end
+
+
+# IP_PSTAT - Print information about the progress we're making.
+
+procedure ip_pstat (ip, row, percent)
+
+pointer ip #i task struct pointer
+int row #u current row
+int percent #u percent completed
+
+begin
+ # Print percent done if being verbose
+ if (row * 100 / IP_AXLEN(ip,2) >= percent + 10) {
+ percent = percent + 10
+ call eprintf (" Status: %2d%% complete\r")
+ call pargi (percent)
+ call flush (STDERR)
+ }
+end
diff --git a/pkg/dataio/import/generic/mkpkg b/pkg/dataio/import/generic/mkpkg
new file mode 100644
index 00000000..9e8721db
--- /dev/null
+++ b/pkg/dataio/import/generic/mkpkg
@@ -0,0 +1,15 @@
+# Compile the generic sources.
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ ipdb.x ../import.h ../ipfcn.h \
+ <error.h> <evvexpr.h> <imhdr.h> <mach.h>
+ ipfio.x ../import.h <fset.h> <mach.h>
+ ipobands.x ../import.h ../ipfcn.h <error.h> <evvexpr.h> \
+ <fset.h> <mach.h>
+ ipproc.x ../import.h <evvexpr.h> <imhdr.h> <mach.h>
+ ;
diff --git a/pkg/dataio/import/images.dat b/pkg/dataio/import/images.dat
new file mode 100644
index 00000000..dd8123ce
--- /dev/null
+++ b/pkg/dataio/import/images.dat
@@ -0,0 +1,433 @@
+# IMAGES.DAT -- Database of known formats recognized by the IMPORT task.
+#
+# Each record of the database is of the form:
+#
+# <format_name>:
+# <alias>:
+# <alias>:
+# keyword = <expr>
+# keyword = <expr>
+# ...and so on
+#
+# A database record begins with the format name at the beginning of a line.
+# Whitespace at the beginning of a line is considered the continuation of a
+# previous line. Comments may be inserted in the database using the normal '#'
+# character, the remainder of the line is considered a comment. Blank lines
+# and comments are ignored, a record ends at the next line with a format name
+# at the beginning of the line.
+#
+# The format_name field is a string identifying each entry in the
+# database, an alias may also be given to identify the same field if known
+# by another name. Supported keywords include:
+#
+# image_id - A boolean expression identifying the image type, either
+# using a literal string or one of the provided functions
+# id_string - Verbose name of file format
+# bswap - Is file byte-swapped? (See Below)
+# dims - A whitespace/comma delimited string of image dimension
+# pixtype - Pixel type, size [and tag], may be a composite
+# interleave - Describes how pixels are stored
+# hskip - # of bytes of header info to skip
+# tskip - # of bytes of trailing info to skip at end of file
+# bskip - # of bytes of info to skip between image bands
+# lskip - # of bytes of info to skip at the front of each line
+# lpad - # of bytes of info to skip at the end of each line
+# yflip - Image is flipped relative to normal IRAF orientation
+# comment - (Multiple) informational comment string to be printed,
+# e.g. to warn the user about the pixel ordering.
+# error - A condition that would cause a file read error, returns
+# a string with the error message, otherwise NULL
+#
+# Expressions include not only functions supported by the system expression
+# evaluator but also special functions particular to the IMPORT task. The
+# user is referred to the IMPORT help page for more details on the database
+# functions.
+#
+# Expressions may also contain *previously defined* database fields, so for
+# instance the 'hskip' keyword can be computed in an expression using the
+# value of the 'pixtype' keyword. Additionally, several special operands are
+# also supported and may be used in expressions:
+#
+# $FSIZE - the size in bytes of the binary file
+# $FNAME - the name of the binary file
+
+
+
+avs: # AVS X image file
+mbfx:
+mbfavs:
+x:
+ image_id = ($FSIZE - (geti4(1) * geti4(5) * 4) == 8)
+ id_string = "AVS X Image Format file"
+ dims = (str(geti4(1)) // "," // str(geti4(5))) // ",4"
+ pixtype = "x1,b1,b1,b1"
+ hskip = 8
+ yflip = 1
+ comment = "Note: The first band of this image is an alpha channel."
+
+
+clementine: # CLEMENTINE mission image
+pds3:
+ image_id = (getstr(1,23) == "PDS_VERSION_ID = PDS3")
+ id_string = "CLEMENTINE 1 PDS3 image data file"
+ pixtype = "b1"
+ hskip = int(locate(1,"OBJECT = IMAGE\r\n")+16)
+ bskip = int(locate(hskip,"LINE_SAMPLES"))
+ lskip = int(locate(hskip,"LINES"))
+# dims = ((str(ctoi((locate(hskip,"LINE_SAMPLES")+17)))) // "," //
+# (str(ctoi((locate(hskip,"LINES")+17)))) )
+ dims = ((str(ctoi((locate(bskip,"=")+1)))) // "," //
+ (str(ctoi((locate(lskip,"=")+1)))) )
+ hskip = (ctoi(locate(1,"^IMAGE ")+18))
+ bskip = 0
+ lskip = 0
+ yflip = 0
+
+
+export: # EXPORT task output format
+ image_id = (getstr(1,15) == "format = EXPORT")
+ id_string = "IRAF EXPORT file (with header)"
+ bswap = (getstr(locate(1,"bswap")+9,locate(1,"bswap")+11) == "no")
+ hskip = ctoi(locate(1,"hdrsize =")+10)
+ pixtype = (getstr(locate(1,"datatype = '")+12,2))
+ dims = ((ctoi(locate(1,"nbands =")+8) > 1) ?
+ (str(ctoi(locate(1,"ncols = ")+8)) // "," //
+ str(ctoi(locate(1,"nrows = ")+8)) // "," //
+ str(ctoi(locate(1,"nbands = ")+9)))
+ : (str(ctoi(locate(1,"ncols = ")+8)) // "," //
+ str(ctoi(locate(1,"nrows = ")+8))))
+ interleave = ctoi(locate(1,"interleave =")+13)
+
+
+fits: # Uhh, use RFITS for this
+ bswap = parameter ("bswap")
+ image_id = (getstr(1,9) == "SIMPLE =")
+ id_string = "FITS Format image"
+ hskip = ( int (locate(1,"END ") / 2800) ) * 2880
+ pixtype = ( str (ctoi((locate(1,"BITPIX")+10))) )
+ pixtype = ((pixtype == "8" ? "b1" :
+ (pixtype == "16" ? "i2" :
+ (pixtype == "32" ? "i4" :
+ (pixtype == "-32" ? "r4" :
+ (pixtype == "-64" ? "r8" : "0"))))))
+ dims = ((ctoi(locate(1,"NAXIS ")+10) == 3) ?
+ (str(ctoi(locate(1,"NAXIS1")+10)) // "," //
+ str(ctoi(locate(1,"NAXIS2")+10)) // "," //
+ str(ctoi(locate(1,"NAXIS3")+10)))
+ : (str(ctoi(locate(1,"NAXIS1")+10)) // "," //
+ str(ctoi(locate(1,"NAXIS2")+10))))
+
+
+gif: # CompuServe's GIF format
+giff:
+ image_id = ( (getstr(1,6) == "GIF87a") || (getstr(1,6) == "GIF89a") )
+ id_string = "CompuServe GIF Format File"
+ dims = (str((getb(7)+(256*getb(8)))) //","// str((getb(9)+(256*getb(10)))))
+ pixtype = "u1"
+ hskip = 22
+ yflip = 1
+ comment = "Note: Colormap information will automatically be applied."
+
+
+oif: # An IRAF OIF pixel file
+imh:
+iraf:
+ bswap = (geti2(1) == 26880 && # bswap("impix" in SPP chars)
+ geti2(3) == 27904 &&
+ geti2(5) == 28672 &&
+ geti2(7) == 26880 &&
+ geti2(9) == 30720)
+ image_id = (geti2(1) == 105 && # "impix" in SPP chars
+ geti2(3) == 109 &&
+ geti2(5) == 112 &&
+ geti2(7) == 105 &&
+ geti2(9) == 120)
+ id_string = "IRAF OIF image pixel file"
+ dims = ((geti2(23) == 3) ?
+ (str(geti2(27)) //","// str(geti2(31)) //","// str(geti2(35)))
+ : (str(geti2(27)) //","// str(geti2(31))) )
+ pixtype = ((geti2(17) == 3 ? "i2" :
+ (geti2(17) == 4 ? "i4" :
+ (geti2(17) == 5 ? "i4" :
+ (geti2(17) == 6 ? "n4" :
+ (geti2(17) == 7 ? "n8" : ""))))) )
+ hskip = 1024
+ lpad = (geti2(55) - geti2(27))
+ lpad = (lpad * ((geti2(17) == 3 ? (2) :
+ (geti2(17) == 4 ? (4) :
+ (geti2(17) == 5 ? (4) :
+ (geti2(17) == 6 ? (4) :
+ (geti2(17) == 7 ? (8) : (1))))))) )
+ error = (geti2(23) > 3) ? "Maximum of 3 dimensions supported." : "okay"
+ error = ((geti2(17) > 7) || (geti2(17) < 3)) ?
+ "Image data type not supported." : "okay"
+
+
+mcidas: # Unidata McIDAS file
+ image_id = (geti4(5) == 4)
+ id_string = "McIDAS"
+ dims = (str(geti4(37)) // "," // str(geti4(33)))
+ pixtype = "b1"
+ hskip = geti4(133)
+ lskip = geti4(57)
+ yflip = 1
+
+
+miff: # ImageMagick MIFF format
+mif:
+ image_id = (locate(1,"id=ImageMagick") < locate (1,":\n"))
+ id_string = "ImageMagick MIFF format file"
+ hskip = ((locate(1,":\n") + 1) + (ctoi(locate(1,"colors=")+7) * 3) + 1)
+ dims = (str(ctoi(locate(1,"columns=")+8)) // "," //
+ str(ctoi(locate(1,"rows=")+5)) )
+ yflip = 1
+ pixtype = (getstr(locate(1,"class=")+6,6) == "Direct" ? "b1,b1,b1" :
+ ((ctoi(locate(1,"colors=")+7) > 256) ? "b2" : "b1"))
+ error = locate(1,"compression") > 1 ?
+ "Compressed files not supported" : "okay"
+ error = ctoi(locate(1,"colors=")+7) > 256 ?
+ "Too many entries in colormap" : "okay"
+ comment = "Note: Colormaps will not be applied to image."
+
+
+pgm: # PBMPlus PGM format
+rpgm:
+ image_id = (getstr(1,2) == "P5" || getstr(1,2) == "P2")
+ id_string = "PBMPlus PGM format file"
+ pixtype = "b1"
+ hskip = ((str(getstr(line(2),1)) != "#") ? # see if there's a comment
+ (int(line(4) - 1))
+ : (int(line(5) - 1)) )
+ dims = ((str(getstr(line(2),1)) != "#") ?
+ (str(ctoi(line(2))) // "," // str(ctoi(locate(line(2)," "))))
+ : (str(ctoi(line(3))) // "," // str(ctoi(locate(line(3)," ")))) )
+ yflip = 1
+ error = getstr(1,2) == "5P" ? "File is byte-swapped" : "okay"
+ error = getstr(1,2) == "P2" ? "Only raw PGM files are supported." : "okay"
+
+
+ppm: # PBMPlus PPM format
+pnm:
+rppm:
+ image_id = (getstr(1,2) == "P6" || getstr(1,2) == "P3")
+ id_string = "PBMPlus PPM format file"
+ pixtype = "b1,b1,b1"
+ hskip = ((str(getstr(line(2),1)) != "#") ? # see if there's a comment
+ (int(line(4) - 1))
+ : (int(line(5) - 1)) )
+ dims = ((str(getstr(line(2),1)) != "#") ?
+ (str(ctoi(line(2))) // "," // str(ctoi(locate(line(2)," "))))
+ : (str(ctoi(line(3))) // "," // str(ctoi(locate(line(3)," ")))) )
+ dims = dims // ",3"
+ yflip = 1
+ error = getstr(1,2) == "6P" ? "File is byte-swapped" : "okay"
+ error = getstr(1,2) == "P3" ? "Only raw PGM files are supported." : "okay"
+
+
+rgb: # SGI RGB format image
+iris:
+sgi:
+ bswap = (getu(1) == bswap(0732b))
+ image_id = (getu(1) == 0732b)
+ id_string = "SGI RGB Image file"
+ dims = ((geti2(5) == 3) ?
+ (str(geti2(7)) // "," // str(geti2(9)) // "," // str(geti2(11)))
+ : (str(geti2(7)) // "," // str(geti2(9))) )
+ pixtype = "b1"
+ hskip = 512
+ interleave = 0
+ error = (geti2(3) == 3) ? "Colormap files not supported" : "okay"
+ error = ((geti2(3) != 0) && (geti2(3) != 1)) ?
+ "Format of RGB file not supported" : "okay"
+ error = (geti2(3) == 257) ? "RLE compressed files not supported" : "okay"
+
+
+sunras: # Sun rasterfile
+ras:
+ bswap = (geti4(1) == bswap(59a66a95x))
+ image_id = (geti4(1) == 59a66a95x || bswap)
+ id_string = "Sun Rasterfile"
+ dims = (str(geti4(5)) // "," // str(geti4(9)) //
+ ((geti4(13) > 8) ? ("," // str(3)) : " ") )
+ pixtype = ((geti4(13) == 8 ? "b1" :
+ (geti4(13) == 24 ? "b1,b1,b1" :
+ (geti4(13) == 32 ? "x1,b1,b1,b1" : "x1,b1,b1,b1") )) )
+ interleave = 0
+ hskip = (32 + geti4(29))
+ yflip = 1
+ comment = "Note: Colormaps will automatically be applied to 8-bit images."
+ error = geti4(13) == 1 ? "1-bit rasters not supported." : "okay"
+
+
+iff: # Sun TAAC Image File Format
+taac:
+vff:
+suniff:
+ image_id = (getstr(1,4) == "ncaa")
+ id_string = "Sun TAAC Image File Format"
+ dims = (str(ctoi(locate(1,"size=")+5)) // "," //
+ str(ctoi(locate((locate(1,"size=")+5)," "))) )
+ dims = ((ctoi((locate(1,"bands=")+6)) == 3) ? (dims // ",3") : dims )
+ hskip = $FSIZE - (ctoi(locate(1,"size=")+5) *
+ ctoi(locate((locate(1,"size=")+5)," ")) *
+ ctoi((locate(1,"bands=")+6)) )
+ pixtype = ((ctoi((locate(1,"bands=")+6)) == 3) ? "b1,b1,b1" : "b1" )
+ yflip = 1
+ comment = "Note: Colormaps will not be applied to 8-bit images."
+
+
+vicar: # VICAR format file
+ bswap = ( msb_host() && (getstr((locate(1,"INTFMT=")+8),3) == "LOW") )
+ image_id = (getstr(1,8) == "LBLSIZE=")
+ id_string = "VICAR format image data file"
+ hskip = (ctoi((locate(1,"LBLSIZE=")+8)) +
+ (ctoi((locate(1,"NLB=")+4)) * ctoi((locate(1,"RECSIZE=")+8))))
+ lskip = (ctoi((locate(1,"NBB=")+4)))
+ interleave = (((getstr((locate(1,"ORG=")+5),3))) == "BSQ" ? 0 :
+ ((getstr((locate(1,"ORG=")+5),3)) == "BIL" ?
+ ctoi(locate(1,"NB=")+3) : 999) )
+ pixtype = (getstr((locate(1,"FORMAT=")+8),4))
+ pixtype = ((pixtype == "BYTE" ? "b1" :
+ (pixtype == "HALF" ? "i2" :
+ (pixtype == "FULL" ? "i4" :
+ (pixtype == "REAL" ? "r4" :
+ (pixtype == "DOUB" ? "r8" : "0"))))))
+ pixtype = (((interleave) != 999) ? pixtype :
+ ((ctoi(locate(1,"DIM=")+5) == 2) ?
+ pixtype // "," // pixtype :
+ ((ctoi(locate(1,"DIM=")+5) == 3) ?
+ pixtype // "," // pixtype // "," // pixtype :
+ (pixtype) )) )
+ dims = (((ctoi(locate(1,"DIM=")+4)==3) && (ctoi(locate(1,"N3=")+3)!=1)) ?
+ (str(ctoi(locate(1,"N1=")+3)) // "," //
+ str(ctoi(locate(1,"N2=")+3)) // "," //
+ str(ctoi(locate(1,"N3=")+3)))
+ : (str(ctoi(locate(1,"N1=")+3)) // "," //
+ str(ctoi(locate(1,"N2=")+3))))
+ yflip = 1
+ error = ((getstr((locate(1,"TYPE=")+6),5) != "IMAGE") ?
+ "Not a VICAR image file." : "okay")
+ error = ((getstr((locate(1,"FORMAT=")+8),4) == "COMP") ?
+ "Complex image data not supported" : "okay")
+
+
+x10: # X10 Window Dump file
+x10wd:
+ image_id = (geti4(5) == 6)
+ id_string = "X10 Window Dump file"
+ hskip = ( geti4(1) + (10 * geti2(39)) )
+ pixtype = "b1"
+ dims = (str(geti4(21)) // "," // str(geti4(25)))
+ comment = "Note: Colormaps will not be applied to image."
+
+
+xwd: # X11 Window Dump file
+x11:
+x11wd:
+ #bswap = ( msb_host() && (geti4(29) == 0) )
+ image_id = (geti4(5) == 7)
+ id_string = "X11 Window Dump file"
+ dims = (str(geti4(17)) // "," // str(geti4(21)))
+ dims = ( (geti4(45) == 24) ? str (dims // ",3") : dims ) # add dims
+ dims = ( (geti4(45) == 32) ? str (dims // ",4") : dims ) # add dims
+ hskip = ( geti4(1) + (12 * geti4(73)) )
+ # On a 64-bit machine the colormap struct is 16 bytes long instead of
+ # 12, see if we have one of these files and pad the header.
+ hskip = ( ((geti4(17)*geti4(21)*(geti4(45)/8)) + hskip) < ($FSIZE-1024) ?
+ (hskip + (4*geti4(73))) : hskip)
+ lpad = ( geti4(49) - (geti4(17) * (geti4(45) / 8)) )
+ pixtype = ( (geti4(45) == 8) ? "b1" :
+ (geti4(45) == 24) ? "b1,b1,b1" :
+ (geti4(45) == 32) ? "x1,b1,b1,b1" : "x1,b1,b1,b1" )
+ yflip = 1
+
+
+
+#########################################################################
+# #
+# The following database entries are not supported for conversion but #
+# are provided for file identification purposes. #
+# #
+#########################################################################
+
+
+cmuwmraster: # CMU Window Manager Raster
+ bswap = (geti4(1) == bswap(00F10040BBx))
+ image_id = (geti4(1) == 00F10040BBx || bswap)
+ id_string = "CMU Window manager Raster file (ID only)"
+ dims = (str(geti4(5)) // "," // str(geti4(9)) // "," // str(geti2(11)))
+ error = (1 == 1) ? "CMU raster supported for file identification only." :
+ "okay"
+
+
+fbm: # Fuzzy Bitmap Format file
+ image_id = (getstr(1,7) == "%bitmap")
+ id_string = "Fuzzy Bitmap Format file (ID only)"
+ dims = (str(ctoi(getstr(17,8))) // "," // str(ctoi(getstr(9,8))))
+ error = (1 == 1) ? "FBM supported for file identification only." :
+ "okay"
+
+
+hdf: # NCSA Hierarchical Data File
+df:
+ncsa:
+ bswap = ( lsb_host() )
+ image_id = (geti4(1) == 0e031301x)
+ id_string = "NCSA Hierarchical Data File (ID only)"
+ dims = (str(geti2(822)) // "," // str(geti2(826)))
+ error = (1 == 1) ? "NCSA HDF supported for file identification only." :
+ "okay"
+
+msp: # Microsoft Paint Bitmap
+ bswap = (geti2(1) == bswap(01800x) || geti2(1) == bswap(0694Cx))
+ image_id = ((geti2(1) == 01800x && geti2(3) == 04D6Ex) ||
+ (geti2(1) == 0694Cx && geti2(3) == 0536Ex))
+ id_string = "Microsoft Paint Bitmap (ID only)"
+ dims = (str(geti2(5)) // "," // str(geti2(7)))
+ error = (1 == 1) ? "MSP supported for file identification only." :
+ "okay"
+
+pcx: # PC Paintbrush File Format
+dcx:
+pcc:
+ image_id = (getb(1) == 010x)
+ id_string = "PC Paintbrush File (ID only)"
+ dims = (str(geti2(9) - geti2(5) + 1) // "," //
+ str(geti2(11) - geti2(7) + 1))
+ error = (1 == 1) ? "PC Paintbrush supported for file identification only." :
+ "okay"
+
+pic: # Pictor PC Paint
+clp:
+ bswap = (geti2(1) == bswap(01234x))
+ image_id = (geti2(1) == 01234x)
+ id_string = "Pictor PC Paint bitmap (ID only)"
+ dims = (str(geti2(3)) // "," // str(geti2(5)))
+ error = (1 == 1) ? "PC Paint supported for file identification only." :
+ "okay"
+
+ps: # Postscript file
+postscript:
+ image_id = (getstr(1,2) == "%!")
+ id_string = "Postscript file (ID only)"
+ error = (1 == 1) ? "PS supported for file identification only." :
+ "okay"
+
+
+rle: # Utah Raster Toolkit file
+utah:
+ image_id = (getb(1) == 52x || getb(1) == 00CCx)
+ id_string = "Utah Raster Toolkit Format file (ID only)"
+ error = (1 == 1) ? "RLE supported for file identification only." :
+ "okay"
+
+
+tif: # TIFF format file
+tiff:
+ bswap = (geti2(1) == bswap(4949x) || geti2(1) == bswap(4D4Dx))
+ image_id = ((geti2(1) == 4D4Dx && geti2(3) == 002Ax) ||
+ (geti2(1) == 4949x && geti2(3) == 2A00x))
+ id_string = "TIFF Format file (ID only)"
+ error = (1 == 1) ? "TIFF supported for file identification only." :
+ "okay"
+
diff --git a/pkg/dataio/import/import.h b/pkg/dataio/import/import.h
new file mode 100644
index 00000000..6d80020a
--- /dev/null
+++ b/pkg/dataio/import/import.h
@@ -0,0 +1,132 @@
+# IMPORT.H - Data structure definition file for the IMPORT task.
+
+define SZ_IMPSTRUCT 40 # size of the import structure
+define SZ_EXPR (20*SZ_LINE) # max size of an expression
+define SZ_COMMENT 1024 # size of a database format comment
+define LEN_UA 20000 # minimum user header length
+define MAX_OPERANDS 1024
+
+# Input format parameters.
+define IP_INTERLEAVE Memi[$1] # type of data interleaving
+define IP_HSKIP Memi[$1+1] # bytes to skip before data
+define IP_TSKIP Memi[$1+2] # bytes to skip after data
+define IP_BSKIP Memi[$1+3] # bytes between image bands
+define IP_LSKIP Memi[$1+4] # bytes to skip at front of line
+define IP_LPAD Memi[$1+5] # bytes to skip at end of line
+define IP_SWAP Memi[$1+6] # type of byte swapping
+define IP_NPIXT Memi[$1+7] # number of pixtypes
+define IP_PIXTYPE Memi[$1+8] # pixtype ptr to operands
+define IP_NDIM Memi[$1+9] # number of input axes
+define IP_AXLEN Memi[($1+10)+$2-1] # input axis dimension
+
+# Output parameters.
+define IP_OUTPUT Memi[$1+20] # type of output generated
+define IP_OUTTYPE Memi[$1+21] # output pixel type
+define IP_NBANDS Memi[$1+22] # no. of outbands expr string
+define IP_OUTBANDS Memi[$1+23] # outbands expr string (ptr)
+define IP_IMHEADER Memi[$1+24] # file w/ header info (ptr)
+define IP_VERBOSE Memi[$1+25] # verbose output flag
+
+define IP_FORMAT Memi[$1+26] # format param
+define IP_BLTIN Memi[$1+27] # format is a 'builtin'
+define IP_FCODE Memi[$1+28] # builtin format code
+define IP_FSYM Memi[$1+29] # symtab pointer to db record
+define IP_IM Memi[$1+30] # output image pointer
+define IP_FD Memi[$1+31] # binary file pointer
+define IP_OFFSET Memi[$1+32] # binary file offset
+define IP_FLIP Memi[$1+33] # output image orientation flag
+define IP_COMPTR Memi[$1+34] # comment block pointer
+
+define IP_BUFPTR Memi[$1+35] # array of image buffers (ptr)
+define IP_NPTRS Memi[$1+36] # number of image buffer
+define IP_SZBUF Memi[$1+37] # size of image buffer (lines)
+
+define IP_CMAP Memi[$1+38] # image colormap (ptr)
+define IP_USE_CMAP Memi[$1+39] # use the image colormap?
+
+# Useful Macros
+define PTYPE Memi[IP_PIXTYPE($1)+$2-1]
+define OBANDS Memi[IP_OUTBANDS($1)+$2-1]
+define COMMENT Memc[IP_COMPTR($1)]
+define BUFFER Memi[IP_BUFPTR($1)+$2-1]
+
+
+#-----------------------------------------------------------------------------
+
+# Outbands structure
+define LEN_OUTBANDS 2
+define OB_EXPR Memi[$1] # expression string
+define OB_OP Memi[$1+1] # operand struct pointer
+define O_EXPR Memc[OB_EXPR(OBANDS($1,$2))]
+define O_OP OB_OP(OBANDS($1,$2))
+
+# Operand structure
+define SZ_TAG 15
+define LEN_OPERAND 6
+define IO_TAG Memi[$1] # operand tag name
+define IO_TYPE Memi[$1+1] # operand type
+define IO_NBYTES Memi[$1+2] # number of bytes
+define IO_NPIX Memi[$1+3] # number of pixels
+define IO_DATA Memi[$1+4] # line of pixels
+define OP_TAG Memc[IO_TAG($1)]
+
+
+# Format type flags
+define IP_NONE 1 # format derived from task params
+define IP_SENSE 2 # format divined from database
+define IP_NAME 3 # format derived from database
+define IP_BUILTIN 4 # format derived from database
+
+# Output type flags
+define IP_IMAGE 5 # generate an output image
+define IP_LIST 6 # list pixels (according to 'outbands')
+define IP_INFO 7 # print info about image format
+
+# Byte swapping flags
+define S_NONE 000B # swap nothing
+define S_ALL 001B # swap everything
+define S_I2 002B # swap short ints
+define S_I4 004B # swap long ints
+define SWAP_STR "|no|none|yes|i2|i4|"
+
+# Image flipping flags
+define FLIP_NONE 000B # don't flip the image
+define FLIP_X 001B # flip image in X
+define FLIP_Y 002B # flip image in Y
+
+# Pixtype pixel types
+define PT_BYTE 1 # byte data (no conversion)
+define PT_UINT 2 # unsigned integer
+define PT_INT 3 # signed integer
+define PT_IEEE 4 # ieee floating point
+define PT_NATIVE 5 # native floating point
+define PT_SKIP 6 # skip
+
+# Default task parameters.
+define DEF_SWAP S_NONE
+define DEF_INTERLEAVE 0
+define DEF_HSKIP 0
+define DEF_TSKIP 0
+define DEF_BSKIP 0
+define DEF_LSKIP 0
+define DEF_LPAD 0
+
+# Useful macros.
+define BAND_INTERLEAVED ((IP_NPIXT($1)==1)&&(IP_INTERLEAVE($1)==0))
+define LINE_INTERLEAVED ((IP_NPIXT($1)==1)&&(IP_INTERLEAVE($1)>1))
+define PIXEL_INTERLEAVED ((IP_NPIXT($1)>1)&&(IP_INTERLEAVE(ip)==0))
+
+# NTSC grayscale coefficients.
+define R_COEFF 0.299
+define G_COEFF 0.587
+define B_COEFF 0.114
+
+# Colormap definitions.
+define CMAP_SIZE 256 # Output colormap length
+define CMAP_MAX 255 # Maximum map value
+define CMAP Memc[$1+($2*CMAP_SIZE)+$3-1]
+
+define IP_RED 0
+define IP_GREEN 1
+define IP_BLUE 2
+
diff --git a/pkg/dataio/import/ipbuiltin.x b/pkg/dataio/import/ipbuiltin.x
new file mode 100644
index 00000000..e95719be
--- /dev/null
+++ b/pkg/dataio/import/ipbuiltin.x
@@ -0,0 +1,91 @@
+include "import.h"
+
+
+# Define the builtin format names. We also define the aliases in case the
+# user specifies one of these instead, the 'sensed' format name is the
+# proper name.
+
+define IP_BUILTINS "|gif|giff\
+ |sunras|ras\
+ |xwd|x11|"
+
+define IP_GIF 1 # CompuServe GIF format
+define IP_GIFF 2 # CompuServe GIF format
+define IP_SUNRAS 3 # Sun Rasterfile
+define IP_RAS 4 # Sun Rasterfile
+define IP_XWD 5 # X11 Window Dump
+define IP_X11 6 # X11 Window Dump
+
+
+
+# IP_PRBUILTIN -- Process a 'builtin' format.
+
+procedure ip_prbuiltin (ip, fname)
+
+pointer ip #i task struct pointer
+char fname[ARB] #i file name
+
+
+begin
+ # Branch off to the particular format.
+ switch (IP_FCODE(ip)) {
+ case IP_GIF, IP_GIFF:
+ call ip_gif (ip, fname, NO, NO)
+ case IP_SUNRAS, IP_RAS:
+ call ip_ras (ip, fname, NO, NO)
+ case IP_XWD, IP_X11:
+ call ip_xwd (ip, fname, NO, NO)
+ default:
+ return
+ }
+end
+
+
+# IP_BLTIN_INFO -- Process a 'builtin' format file information request. These
+# are done separately because in a builtin we can print information such as
+# colormap information, compression schemes, etc.
+
+procedure ip_bltin_info (ip, fname, verbose)
+
+pointer ip #i task struct pointer
+char fname[ARB] #i file name
+int verbose #i verbosity flag
+
+begin
+ # Branch off to the particular format.
+ switch (IP_FCODE(ip)) {
+ case IP_GIF, IP_GIFF:
+ call ip_gif (ip, fname, YES, verbose)
+ case IP_SUNRAS, IP_RAS:
+ call ip_ras (ip, fname, YES, verbose)
+ case IP_XWD, IP_X11:
+ call ip_xwd (ip, fname, YES, verbose)
+ default:
+ return
+ }
+end
+
+
+# IP_IS_BUILTIN -- See if this is a 'builtin' format.
+
+int procedure ip_is_builtin (format)
+
+char format[ARB] #i format to check
+
+int btoi(), strdic()
+
+begin
+ return (btoi(strdic(format,format,SZ_FNAME,IP_BUILTINS) != 0))
+end
+
+
+# IP_FCODE -- Get the format code for a builtin format.
+
+int procedure ip_fcode (format)
+
+char format[ARB] #i format to check
+int strdic()
+
+begin
+ return (strdic (format, format, SZ_FNAME, IP_BUILTINS))
+end
diff --git a/pkg/dataio/import/ipdb.gx b/pkg/dataio/import/ipdb.gx
new file mode 100644
index 00000000..9e4cb5c3
--- /dev/null
+++ b/pkg/dataio/import/ipdb.gx
@@ -0,0 +1,766 @@
+include <evvexpr.h>
+include <error.h>
+include <mach.h>
+include <imhdr.h>
+include "../import.h"
+include "../ipfcn.h"
+
+define DEBUG false
+
+
+# IP_EVAL_DBREC -- For each of the keywords defined in the database record,
+# evaluate the expression and load the task structure.
+
+procedure ip_eval_dbrec (ip)
+
+pointer ip #i task struct pointer
+
+int ival
+pointer sp, dims, pixtype, err
+pointer np, stp, sym
+
+pointer stname(), sthead(), stnext
+int or(), ip_dbgeti()
+bool streq()
+
+errchk ip_dbgeti()
+
+begin
+ call smark (sp)
+ call salloc (dims, SZ_EXPR, TY_CHAR)
+ call salloc (pixtype, SZ_EXPR, TY_CHAR)
+ call salloc (err, SZ_EXPR, TY_CHAR)
+ call aclrc (Memc[dims], SZ_EXPR)
+ call aclrc (Memc[pixtype], SZ_EXPR)
+ call aclrc (Memc[err], SZ_EXPR)
+
+ # Load the defaults.
+ call ip_load_defaults (ip)
+
+ # First thing we do is get the byte swap flag so the remaining
+ # fields will be interpreted correctly.
+ ifnoerr (ival = ip_dbgeti (ip, "bswap"))
+ IP_SWAP(ip) = ival
+
+ # Next, we handle 'interleave', 'dims' and 'pixtype' as a special case
+ # since for band- and line-interleaved files we may need to fix up the
+ # pixtype pointers.
+ ifnoerr (ival = ip_dbgeti (ip, "interleave"))
+ IP_INTERLEAVE(ip) = ival
+
+ ifnoerr (call ip_dbstr (ip, "dims", Memc[dims], SZ_EXPR))
+ call ip_do_dims (ip, Memc[dims])
+
+ ifnoerr (call ip_dbstr (ip, "pixtype", Memc[pixtype], SZ_EXPR)) {
+ if (Memc[pixtype] == '"')
+ call fdb_strip_quote (Memc[pixtype], Memc[pixtype], SZ_EXPR)
+ call ip_do_pixtype (ip, Memc[pixtype])
+ }
+
+ # Loop over every symbol in the table.
+ stp = IP_FSYM(ip)
+ for (sym=sthead(stp); sym != NULL; sym=stnext(stp,sym)) {
+ np = stname (stp, sym)
+
+ if (streq(Memc[np],"format") || # ignored or found already
+ streq(Memc[np],"alias") ||
+ streq(Memc[np],"image_id") ||
+ streq(Memc[np],"interleave") ||
+ streq(Memc[np],"dims") ||
+ streq(Memc[np],"pixtype") ||
+ streq(Memc[np],"id_string") ||
+ streq(Memc[np],"bswap")) {
+ next
+ } else if (streq(Memc[np],"hskip")) {
+ IP_HSKIP(ip) = ip_dbgeti (ip, "hskip")
+ } else if (streq(Memc[np],"tskip")) {
+ IP_TSKIP(ip) = ip_dbgeti (ip, "tskip")
+ } else if (streq(Memc[np],"bskip")) {
+ IP_BSKIP(ip) = ip_dbgeti (ip, "bskip")
+ } else if (streq(Memc[np],"lskip")) {
+ IP_LSKIP(ip) = ip_dbgeti (ip, "lskip")
+ } else if (streq(Memc[np],"lpad")) {
+ IP_LPAD(ip) = ip_dbgeti (ip, "lpad")
+ } else if (streq(Memc[np],"yflip")) {
+ if (ip_dbgeti (ip, "yflip") == YES)
+ IP_FLIP(ip) = or (IP_FLIP(ip), FLIP_Y)
+ } else if (streq(Memc[np],"error")) {
+ if (IP_OUTPUT(ip) != IP_INFO)
+ call ip_do_error (ip, Memc[P2C(sym)])
+ } else if (streq(Memc[np],"comment")) {
+ call fdb_strip_quote (Memc[P2C(sym)], Memc[P2C(sym)], SZ_LINE)
+ call ip_do_comment (ip, Memc[P2C(sym)])
+ } else {
+ call eprintf ("Warning: Unknown database keyword '%s'.\n")
+ call pargstr (Memc[np])
+ }
+ }
+
+ if (DEBUG) { call zzi_prstruct ("eval dbrec:", ip) }
+ call sfree (sp)
+end
+
+
+# IP_LOAD_DEFAULTS -- Load the default input parameters to the task structure.
+
+procedure ip_load_defaults (ip)
+
+pointer ip #i task struct pointer
+
+begin
+ IP_SWAP(ip) = DEF_SWAP # type of byte swapping
+ IP_INTERLEAVE(ip) = DEF_INTERLEAVE # type of data interleaving
+ IP_HSKIP(ip) = DEF_HSKIP # bytes to skip before data
+ IP_TSKIP(ip) = DEF_TSKIP # bytes to skip after data
+ IP_BSKIP(ip) = DEF_BSKIP # bytes between image bands
+ IP_LSKIP(ip) = DEF_LSKIP # bytes to skip at front of
+ IP_LPAD(ip) = DEF_LPAD # bytes to skip at end of
+
+ # zero image dimensions
+ for (IP_NDIM(ip)=IM_MAXDIM; IP_NDIM(ip) > 0; IP_NDIM(ip)=IP_NDIM(ip)-1)
+ IP_AXLEN(ip,IP_NDIM(ip)) = 0
+end
+
+
+# IP_DBFCN -- Called by evvexpr to execute format database special functions.
+
+procedure ip_dbfcn (ip, fcn, args, nargs, o)
+
+pointer ip #i task struct pointer
+char fcn[ARB] #i function to be executed
+pointer args[ARB] #i argument list
+int nargs #i number of arguments
+pointer o #o operand pointer
+
+pointer sp, buf, outstr
+int fd, func, v_nargs
+int i, len, nchar, ival, cur_offset, swap
+char ch
+short sval
+real rval
+double dval
+
+short ip_getb(), ip_gets()
+int strdic(), ip_line(), ip_locate(), ip_getu()
+int ctoi(), ctol(), ctor(), ctod(), ctocc(), ctowrd()
+int and(), strlen(), clgeti()
+long ip_getl()
+real ip_getr(), ip_getn()
+double ip_getd(), ip_getn8()
+bool strne(), streq()
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+ call salloc (outstr, SZ_LINE, TY_CHAR)
+ call aclrc (Memc[buf], SZ_LINE)
+ call aclrc (Memc[outstr], SZ_LINE)
+
+ # Lookup function in dictionary.
+ func = strdic (fcn, Memc[buf], SZ_LINE, DB_FUNCTIONS)
+ if (func > 0 && strne(fcn,Memc[buf]))
+ func = 0
+
+ # Abort if the function is not known.
+ if (func <= 0)
+ call xev_error1 ("unknown function `%s' called", fcn)
+
+
+ # Verify the correct number of arguments, negative value means a
+ # variable number of args, handle it in the evaluation.
+ switch (func) {
+ case CTOCC, CTOD, CTOI, CTOL, CTOR, CTOWRD:
+ v_nargs = -1
+
+ case GETSTR:
+ v_nargs = -1
+ case GETB, GETU, GETI, GETI2, GETI4, GETR, GETR4, GETR8,
+ GETN, GETN4, GETN8:
+ v_nargs = 1
+
+ case LOCATE:
+ v_nargs = -1
+ case LINE, SKIP:
+ v_nargs = 1
+
+ case BSWAP:
+ v_nargs = 1
+ case PARAMETER, DEFAULT:
+ v_nargs = 1
+ case SUBSTR:
+ v_nargs = 3
+ case STRIDX:
+ v_nargs = 2
+ case LSB_HOST, MSB_HOST:
+ v_nargs = 0
+ }
+ if (v_nargs > 0 && nargs != v_nargs)
+ call xev_error2 ("function `%s' requires %d arguments",
+ fcn, v_nargs)
+ else if (v_nargs < 0 && nargs < abs(v_nargs))
+ call xev_error2 ("function `%s' requires at least %d arguments",
+ fcn, abs(v_nargs))
+
+ fd = IP_FD(ip)
+ swap = IP_SWAP(ip)
+ cur_offset = IP_OFFSET(ip)
+
+ if (DEBUG) {
+ call eprintf ("cur_offset=%d nargs=%d func=%s swap=%d\n")
+ call pargi(cur_offset) ; call pargi(nargs)
+ call pargstr(fcn) ; call pargi (swap)
+ do i = 1, nargs
+ call zzi_pevop (args[i])
+ call eprintf ("init op => ") ; call zzi_pevop(o)
+
+ }
+
+ # Evaluate the function.
+ switch (func) {
+ case CTOCC: # run the fmtio equivalents of the argument
+ if (nargs == 1)
+ ch = ip_getb (fd, O_VALI(args[1]))
+ else
+ ch = ip_getb (fd, cur_offset)
+ len = ctocc (ch, Memc[outstr], SZ_FNAME) + 1
+ call ip_initop (o, len, TY_CHAR)
+ call aclrc (O_VALC(o), len)
+ call amovc (Memc[outstr], O_VALC(o), len)
+ cur_offset = cur_offset + 1
+ call ip_lseek (fd, cur_offset)
+
+ case CTOWRD:
+ if (nargs == 1)
+ call ip_gstr (fd, O_VALI(args[1]), SZ_FNAME, Memc[outstr])
+ else
+ call ip_gstr (fd, cur_offset, SZ_FNAME, Memc[outstr])
+ nchar = ctowrd (Memc[outstr], i, Memc[outstr], SZ_FNAME) + 1
+ call ip_initop (o, nchar, TY_CHAR)
+ call aclrc (O_VALC(o), nchar)
+ call amovc (Memc[outstr], O_VALC(o), nchar)
+ cur_offset = cur_offset + nchar + 1
+ call ip_lseek (fd, cur_offset)
+
+ case CTOI:
+ i = 1
+ if (nargs == 1) {
+ call ip_gstr (fd, O_VALI(args[i]), SZ_FNAME, Memc[outstr])
+ nchar = ctoi (Memc[outstr], i, ival)
+ cur_offset = cur_offset + nchar - 1
+ } else if (nargs == 2) {
+ call ip_gstr (fd, O_VALI(args[1]), O_VALI(args[2]),Memc[outstr])
+ nchar = ctoi (Memc[outstr], i, ival)
+ cur_offset = O_VALI(args[1]) + nchar - 1
+ }
+ call ip_lseek (fd, cur_offset)
+ O_TYPE(o) = TY_INT
+
+ case CTOL:
+ i = 1
+ if (nargs == 1) {
+ call ip_gstr (fd, O_VALI(args[i]), SZ_FNAME, Memc[outstr])
+ nchar = ctol (Memc[outstr], i, ival)
+ cur_offset = cur_offset + nchar - 1
+ } else if (nargs == 2) {
+ call ip_gstr (fd, O_VALI(args[1]), O_VALI(args[2]),Memc[outstr])
+ nchar = ctol (Memc[outstr], i, ival)
+ cur_offset = O_VALI(args[1]) + nchar - 1
+ }
+ call ip_lseek (fd, cur_offset)
+ O_TYPE(o) = TY_LONG
+
+ case CTOR:
+ i = 1
+ if (nargs == 1) {
+ call ip_gstr (fd, O_VALI(args[i]), SZ_FNAME, Memc[outstr])
+ nchar = ctor (Memc[outstr], i, rval)
+ cur_offset = cur_offset + nchar - 1
+ } else if (nargs == 2) {
+ call ip_gstr (fd, O_VALI(args[1]), O_VALI(args[2]),Memc[outstr])
+ nchar = ctor (Memc[outstr], i, rval)
+ cur_offset = O_VALI(args[1]) + nchar - 1
+ }
+ call ip_lseek (fd, cur_offset)
+ O_TYPE(o) = TY_REAL
+
+ case CTOD:
+ i = 1
+ if (nargs == 1) {
+ call ip_gstr (fd, O_VALI(args[i]), SZ_FNAME, Memc[outstr])
+ nchar = ctod (Memc[outstr], i, dval)
+ cur_offset = cur_offset + nchar - 1
+ } else if (nargs == 2) {
+ call ip_gstr (fd, O_VALI(args[1]), O_VALI(args[2]),Memc[outstr])
+ nchar = ctod (Memc[outstr], i, dval)
+ cur_offset = O_VALI(args[1]) + nchar - 1
+ }
+ call ip_lseek (fd, cur_offset)
+ O_TYPE(o) = TY_DOUBLE
+
+ case GETSTR:
+ if (nargs == 1) {
+ call ip_gstr (fd, cur_offset, O_VALI(args[1]), Memc[outstr])
+ cur_offset = cur_offset + O_VALI(args[1])
+ } else if (nargs == 2) {
+ call ip_gstr (fd, O_VALI(args[1]), O_VALI(args[2]),Memc[outstr])
+ cur_offset = O_VALI(args[1]) + O_VALI(args[2]) - 1
+ }
+ if (strlen(Memc[outstr]) == 0) {
+ len = strlen ("ERR") + 1
+ call ip_initop (o, len, TY_CHAR)
+ call aclrc (O_VALC(o), len)
+ call strcpy ("ERR", O_VALC(o), len-1)
+ } else {
+ len = strlen (Memc[outstr]) + 1
+ call ip_initop (o, len, TY_CHAR)
+ call aclrc (O_VALC(o), len)
+ call amovc (Memc[outstr], O_VALC(o), len-1)
+ }
+
+ case GETB:
+ if (nargs == 0) {
+ sval = ip_getb (fd, cur_offset)
+ cur_offset = cur_offset + SZB_CHAR
+ } else {
+ sval = ip_getb (fd, O_VALI(args[1]))
+ cur_offset = O_VALI(args[1]) + SZB_CHAR
+ }
+ ival = sval
+ O_TYPE(o) = TY_INT
+
+ case GETU:
+ if (nargs == 0) {
+ sval = short (ip_getu (fd, cur_offset))
+ cur_offset = cur_offset + (SZB_CHAR * SZ_SHORT)
+ } else {
+ sval = short (ip_getu (fd, O_VALI(args[1])))
+ cur_offset = O_VALI(args[1]) + (SZB_CHAR * SZ_SHORT)
+ }
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I2) == S_I2)
+ call bswap2 (sval, 1, sval, 1, (SZ_SHORT*SZB_CHAR))
+ ival = sval
+ O_TYPE(o) = TY_INT
+
+ case GETI, GETI2:
+ if (nargs == 0) {
+ sval = ip_gets (fd, cur_offset)
+ cur_offset = cur_offset + (SZB_CHAR * SZ_SHORT)
+ } else {
+ sval = ip_gets (fd, O_VALI(args[1]))
+ cur_offset = O_VALI(args[1]) + (SZB_CHAR * SZ_SHORT)
+ }
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I2) == S_I2)
+ call bswap2 (sval, 1, sval, 1, (SZ_SHORT*SZB_CHAR))
+ ival = sval
+ O_TYPE(o) = TY_INT
+
+ case GETI4:
+ if (nargs == 0) {
+ ival = ip_getl (fd, cur_offset)
+ cur_offset = cur_offset + (SZB_CHAR * SZ_LONG)
+ } else {
+ ival = ip_getl (fd, O_VALI(args[1]))
+ cur_offset = O_VALI(args[1]) + (SZB_CHAR * SZ_LONG)
+ }
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I2) == S_I4)
+ call bswap4 (ival, 1, ival, 1, (SZ_INT32*SZB_CHAR))
+ O_TYPE(o) = TY_INT
+
+ case GETR, GETR4:
+ if (nargs == 0) {
+ rval = ip_getr (fd, cur_offset)
+ cur_offset = cur_offset + (SZB_CHAR * SZ_REAL)
+ } else {
+ rval = ip_getr (fd, O_VALI(args[1]))
+ cur_offset = O_VALI(args[1]) + (SZB_CHAR * SZ_REAL)
+ }
+ if (and(swap, S_ALL) == S_ALL) # handle byte-swapping
+ call bswap4 (rval, 1, rval, 1, (SZ_REAL*SZB_CHAR))
+ O_TYPE(o) = TY_REAL
+
+ case GETR8:
+ if (nargs == 0) {
+ dval = ip_getd (fd, cur_offset)
+ cur_offset = cur_offset + (SZB_CHAR * SZ_DOUBLE)
+ } else {
+ dval = ip_getd (fd, O_VALI(args[1]))
+ cur_offset = O_VALI(args[1]) + (SZB_CHAR * SZ_DOUBLE)
+ }
+ if (and(swap, S_ALL) == S_ALL) # handle byte-swapping
+ call bswap8 (dval, 1, dval, 1, (SZ_DOUBLE*SZB_CHAR))
+ O_TYPE(o) = TY_DOUBLE
+
+ case GETN, GETN4:
+ if (nargs == 0) {
+ rval = ip_getn (fd, cur_offset)
+ cur_offset = cur_offset + (SZB_CHAR * SZ_REAL)
+ } else {
+ rval = ip_getn (fd, O_VALI(args[1]))
+ cur_offset = O_VALI(args[1]) + (SZB_CHAR * SZ_REAL)
+ }
+ if (and(swap, S_ALL) == S_ALL) # handle byte-swapping
+ call bswap4 (rval, 1, rval, 1, (SZ_REAL*SZB_CHAR))
+ O_TYPE(o) = TY_REAL
+
+ case GETN8:
+ if (nargs == 0) {
+ dval = ip_getn8 (fd, cur_offset)
+ cur_offset = cur_offset + (SZB_CHAR * SZ_DOUBLE)
+ } else {
+ dval = ip_getn8 (fd, O_VALI(args[1]))
+ cur_offset = O_VALI(args[1]) + (SZB_CHAR * SZ_DOUBLE)
+ }
+ if (and(swap, S_ALL) == S_ALL) # handle byte-swapping
+ call bswap8 (dval, 1, dval, 1, (SZ_DOUBLE*SZB_CHAR))
+ O_TYPE(o) = TY_DOUBLE
+
+ case LOCATE: # locate the pattern in the file
+ if (nargs == 1)
+ ival = ip_locate (fd, cur_offset, O_VALC(args[1]))
+ else if (nargs == 2)
+ ival = ip_locate (fd, O_VALI(args[1]), O_VALC(args[2]))
+ if (ival == ERR)
+ ival = 1
+ O_TYPE(o) = TY_INT
+ cur_offset = ival
+
+ case LINE: # locate the line no. in the file
+ ival = ip_line (fd, O_VALI(args[1]))
+ if (ival == ERR)
+ ival = 1
+ O_TYPE(o) = TY_INT
+ cur_offset = ival
+
+ case SKIP: # skip a certain number of bytes
+ ival = O_VALI(args[1])
+ O_TYPE(o) = TY_INT
+ cur_offset = cur_offset + ival
+
+ case BSWAP: # byte-swap argument
+ O_TYPE(o) = O_TYPE(args[1])
+ switch (O_TYPE(args[1])) {
+ case TY_SHORT:
+ call bswap2 (O_VALS(args[1]), 1, sval, 1, (SZ_SHORT*SZB_CHAR))
+ case TY_INT:
+ call bswap4 (O_VALI(args[1]), 1, ival, 1, (SZ_INT32*SZB_CHAR))
+ case TY_LONG:
+ call bswap4 (O_VALL(args[1]), 1, ival, 1, (SZ_LONG*SZB_CHAR))
+ case TY_REAL:
+ call bswap4 (O_VALR(args[1]), 1, rval, 1, (SZ_REAL*SZB_CHAR))
+ case TY_DOUBLE:
+ call bswap8 (O_VALD(args[1]), 1, dval, 1, (SZ_DOUBLE*SZB_CHAR))
+ }
+
+ case PARAMETER: # return current task parameter value
+ if (streq(O_VALC(args[1]),"dims")) {
+ call clgstr ("dims", Memc[outstr], SZ_FNAME)
+ len = strlen (Memc[outstr]) + 1
+ call ip_initop (o, len, TY_CHAR)
+ call strcpy (Memc[outstr], O_VALC(o), len)
+ } else if (streq(O_VALC(args[1]),"pixtype")) {
+ call clgstr ("pixtype", Memc[outstr], SZ_FNAME)
+ len = strlen (Memc[outstr]) + 1
+ call ip_initop (o, len, TY_CHAR)
+ call strcpy (Memc[outstr], O_VALC(o), len)
+ } else if (streq(O_VALC(args[1]),"interleave")) {
+ ival = clgeti ("interleave")
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"bswap")) {
+ call clgstr ("bswap", Memc[outstr], SZ_FNAME)
+ if (strne("no",Memc[outstr]) && strne("none",Memc[outstr]))
+ ival = YES
+ else
+ ival = NO
+ O_TYPE(o) = TY_BOOL
+ } else if (streq(O_VALC(args[1]),"hskip")) {
+ ival = clgeti ("hskip")
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"tskip")) {
+ ival = clgeti ("tskip")
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"bskip")) {
+ ival = clgeti ("bskip")
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"lskip")) {
+ ival = clgeti ("lskip")
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"lpad")) {
+ ival = clgeti ("lpad")
+ O_TYPE(o) = TY_INT
+ }
+
+ case DEFAULT: # return default task parameter value
+ if (streq(O_VALC(args[1]),"dims")) {
+ call ip_initop (o, 1, TY_CHAR)
+ call strcpy ("", O_VALC(o), 1)
+ } else if (streq(O_VALC(args[1]),"pixtype")) {
+ call ip_initop (o, 1, TY_CHAR)
+ call strcpy ("", O_VALC(o), 1)
+ } else if (streq(O_VALC(args[1]),"interleave")) {
+ ival = DEF_INTERLEAVE
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"bswap")) {
+ ival = DEF_SWAP
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"hskip")) {
+ ival = DEF_HSKIP
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"tskip")) {
+ ival = DEF_TSKIP
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"bskip")) {
+ ival = DEF_BSKIP
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"lskip")) {
+ ival = DEF_LSKIP
+ O_TYPE(o) = TY_INT
+ } else if (streq(O_VALC(args[1]),"lpad")) {
+ ival = DEF_LPAD
+ O_TYPE(o) = TY_INT
+ }
+
+ case LSB_HOST: # host is an LSB byte ordered machine
+ if (BYTE_SWAP2 == YES)
+ ival = YES
+ else
+ ival = NO
+ O_TYPE(o) = TY_BOOL
+
+ case MSB_HOST: # host is an MSB byte ordered machine
+ if (BYTE_SWAP2 == NO)
+ ival = YES
+ else
+ ival = NO
+ O_TYPE(o) = TY_BOOL
+
+ case SUBSTR: # return a substring of the argument
+
+ case STRIDX: # return offset of a char w/in str
+
+ }
+
+ # Write result to output operand.
+ O_LEN(o) = 0
+ switch (O_TYPE(o)) {
+ case TY_USHORT, TY_SHORT:
+ O_VALS(o) = sval
+ case TY_INT, TY_BOOL:
+ O_VALI(o) = ival
+ case TY_LONG:
+ O_VALL(o) = ival
+ case TY_REAL:
+ O_VALR(o) = rval
+ case TY_DOUBLE:
+ O_VALD(o) = dval
+ }
+
+ if (DEBUG) { call eprintf("ip_dbfcn: ") ; call zzi_pevop (o) }
+
+ IP_OFFSET(ip) = cur_offset
+ call sfree (sp)
+end
+
+
+# IP_DBSTR -- Get a string valued expression from the database.
+
+procedure ip_dbstr (ip, param, outstr, maxch)
+
+pointer ip #i task struct pointer
+char param[ARB] #i parameter to evaluate
+char outstr[ARB] #o result string
+int maxch #i max length of string
+
+pointer sp, expr, o
+
+int locpr(), strlen()
+pointer evvexpr()
+extern ip_getop(), ip_dbfcn()
+errchk evvexpr
+
+begin
+ call smark (sp)
+ call salloc (expr, SZ_EXPR, TY_CHAR)
+ call aclrc (Memc[expr], SZ_EXPR)
+
+ # Get the requested parameter.
+ call aclrc (outstr, SZ_EXPR)
+ call fdbgstr (IP_FSYM(ip), param, Memc[expr], SZ_EXPR)
+ if (Memc[expr] == EOS)
+ call error (1, "FDBGET: Format parameter not found")
+
+ if (DEBUG) {
+ call eprintf("ip_dbstr: expr='%s' len=%d ");call pargstr(Memc[expr])
+ call pargi(strlen(Memc[expr]))
+ }
+
+ # Evaluate the expression.
+ iferr {
+ o = evvexpr (Memc[expr], locpr(ip_getop), ip,
+ locpr(ip_dbfcn), ip, EV_RNGCHK)
+ if (O_TYPE(o) != TY_CHAR)
+ call error (0, "ip_dbstr: Expression must be a string valued")
+ else
+ call amovc (O_VALC(o), outstr, (min(strlen(O_VALC(o)),maxch)))
+ } then
+ call erract (EA_WARN)
+
+ if (DEBUG) { call eprintf ("outstr=:%s:\n") ; call pargstr (outstr) }
+
+ call evvfree (o)
+ call sfree (sp)
+end
+
+$for (ir)
+
+$if (datatype == i)
+# IP_DBGETI -- Get integer valued format parameter from the database.
+$else
+# IP_DBGETR -- Get real valued format parameter from the database.
+$endif
+
+PIXEL procedure ip_dbget$t (ip, param)
+
+pointer ip #i task struct pointer
+char param[ARB] #i requested parameter
+
+PIXEL val
+pointer sp, expr, o
+
+int locpr()
+pointer evvexpr()
+extern ip_getop(), ip_dbfcn()
+errchk evvexpr
+
+begin
+ call smark (sp)
+ call salloc (expr, SZ_EXPR, TY_CHAR)
+
+ # Get the requested parameter.
+ call fdbgstr (IP_FSYM(ip), param, Memc[expr], SZ_EXPR)
+ if (Memc[expr] == EOS)
+ call error (1, "IP_DBGET: Format parameter not found")
+
+ # Evaluate the expression.
+ if (DEBUG) {
+ call eprintf ("ip_dbget: expr='%s'\n")
+ call pargstr (Memc[expr])
+ call flush (STDERR)
+ }
+ iferr {
+ o = evvexpr (Memc[expr], locpr(ip_getop), ip,
+ locpr(ip_dbfcn), ip, EV_RNGCHK)
+ if (O_TYPE(o) == TY_BOOL) {
+ val = O_VALI(o)
+ $if (datatype == i)
+ } else if (O_TYPE(o) != TY_PIXEL && O_TYPE(o) != TY_SHORT) {
+ call error (0, "Expression must be an integer")
+ $else
+ } else if (O_TYPE(o) != TY_PIXEL) {
+ call error (0, "Expression must be a real")
+ $endif
+ } else
+ val = O_VAL$T(o)
+
+ if (DEBUG) {
+ call eprintf ("ip_dbget: val=%d type=%d ecpr=:%s:\n")
+ call parg$t (val)
+ call pargi (O_TYPE(o))
+ call pargstr (Memc[expr])
+ call flush (STDERR)
+ }
+ } then
+ call erract (EA_WARN)
+
+ call evvfree (o)
+ call sfree (sp)
+ return (val)
+end
+$endfor
+
+# IP_DO_ERROR -- Process the error parameter.
+
+procedure ip_do_error (ip, expr)
+
+pointer ip #i task struct pointer
+char expr[ARB] #i error string
+
+pointer o
+
+int locpr()
+pointer evvexpr()
+extern ip_getop(), ip_dbfcn()
+bool strne()
+errchk evvexpr
+
+begin
+ if (DEBUG) {call eprintf ("error expr: '%s' ") ; call pargstr (expr)}
+
+ # Evaluate the expression.
+ iferr {
+ o = evvexpr (expr, locpr(ip_getop), ip, locpr(ip_dbfcn), ip,
+ EV_RNGCHK)
+
+ if (DEBUG) { call eprintf("-> '%s'\n") ; call pargstr(O_VALC(o)) }
+
+ if (O_TYPE(o) != TY_CHAR)
+ call error (2, "do_error: Expression must be a string valued")
+ else {
+ if (strne("okay",O_VALC(o)))
+ call error (2, O_VALC(o))
+ }
+ call evvfree (o)
+
+ } then
+ if (IP_OUTPUT(ip) != IP_INFO)
+ call erract (EA_FATAL)
+end
+
+
+# IP_DO_COMMENT - Process a comment line in the format database.
+
+procedure ip_do_comment (ip, comstr)
+
+pointer ip #i task struct pointer
+char comstr[ARB] #i comment to add
+
+pointer sp, buf
+
+begin
+ # Copy the comment line to the comment block.
+ if (IP_COMPTR(ip) == NULL)
+ call calloc (IP_COMPTR(ip), SZ_COMMENT, TY_CHAR)
+
+ if (COMMENT(ip) == '\0') {
+ call strcpy ("\t", COMMENT(ip), SZ_LINE)
+ call strcat (comstr, COMMENT(ip), SZ_LINE)
+ } else {
+ call smark (sp)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+
+ Memc[buf] = '\0'
+ call strcpy ("\t", Memc[buf], SZ_LINE)
+ call strcat (comstr, Memc[buf], SZ_LINE)
+ call strcat ("\n", Memc[buf], SZ_LINE)
+ call strcat (COMMENT(ip), Memc[buf], SZ_COMMENT)
+
+ call strcpy (Memc[buf], COMMENT(ip), SZ_COMMENT)
+
+ call sfree (sp)
+ }
+end
+
+
+# IP_INITOP - Initialize an operand pointer to the requested values
+
+procedure ip_initop (o, len, type)
+
+pointer o #u operand pointer
+int len #i length of array
+int type #i data type of operand
+
+begin
+ O_LEN(o) = len
+ O_TYPE(o) = type
+ if (len > 1)
+ call calloc (O_VALP(o), len, type)
+end
diff --git a/pkg/dataio/import/ipfcn.h b/pkg/dataio/import/ipfcn.h
new file mode 100644
index 00000000..090c040e
--- /dev/null
+++ b/pkg/dataio/import/ipfcn.h
@@ -0,0 +1,57 @@
+# IPFCN.H - Include file for the special functions supported by the IMPORT task.
+
+# Format database functions.
+define DB_FUNCTIONS "|ctocc|ctod|ctoi|ctol|ctor|ctowrd|\
+ |getstr|getb|getu|geti|geti2|geti4|\
+ |getr|getr4|getr8|getn|getn4|getn8|\
+ |locate|line|skip|bswap|parameter|default|\
+ |lsb_host|msb_host|substr|stridx|"
+
+define CTOCC 1 # Convert character to printable char constant
+define CTOD 2 # Convert string to double precision real
+define CTOI 3 # Convert string to integer
+define CTOL 4 # Convert string to long
+define CTOR 5 # Convert string to single precision real
+define CTOWRD 6 # Return 1st white-space delimited word from str
+# newline
+define GETSTR 8 # Get a string at offset
+define GETB 9 # Get a byte at offset
+define GETU 10 # Get an unsigned short int at offset
+define GETI 11 # Get a signed int at offset
+define GETI2 12 # Get a signed int at offset
+define GETI4 13 # Get a long signed int at offset
+# newline
+define GETR 15 # Get an IEEE fp number at offset
+define GETR4 16 # Get an IEEE fp number at offset
+define GETR8 17 # Get an IEEE double precision number at offset
+define GETN 18 # Get a native fp number at offset
+define GETN4 19 # Get a native fp number at offset
+define GETN8 20 # Get a native double precision number at offset
+# newline
+define LOCATE 22 # Compute an offset
+define LINE 23 # Offset of line N
+define SKIP 24 # Move offset N-bytes
+define BSWAP 25 # Byte swap the argument
+define PARAMETER 26 # Return current task parameter
+define DEFAULT 27 # Return default task parameter
+# newline
+define LSB_HOST 29 # Host is LSB byte ordered machine
+define MSB_HOST 30 # Host is MSB byte ordered machine
+define SUBSTR 31 # Return a substring of the argument
+define STRIDX 32 # Return occurance of a char within a string
+
+
+# Outbands expression functions.
+define OB_FUNCTIONS "|gray|grey|flipx|flipy|\
+ |red|green|blue|"
+
+define GRAY 1 # Convert to NTSC grayscale
+define GREY 2 # Convert to NTSC grayscale (alias)
+define FLIPX 3 # Flip image in X
+define FLIPY 4 # Flip image in Y
+# newline
+define RED 6 # Get red component of colormap image
+define GREEN 7 # Get green component of colormap image
+define BLUE 8 # Get blue component of colormap image
+
+
diff --git a/pkg/dataio/import/ipfio.gx b/pkg/dataio/import/ipfio.gx
new file mode 100644
index 00000000..61147ea2
--- /dev/null
+++ b/pkg/dataio/import/ipfio.gx
@@ -0,0 +1,443 @@
+include <mach.h>
+include <fset.h>
+include "../import.h"
+
+define DEBUG false
+
+
+# IP_GSTR -- Get a string of the specifed length from the given offset.
+
+procedure ip_gstr (fd, offset, len, outstr)
+
+int fd
+int offset
+int len
+char outstr[ARB]
+
+int nstat, read()
+pointer sp, buf
+
+begin
+ call smark (sp)
+ call salloc (buf, len+2, TY_CHAR)
+ call aclrc (Memc[buf], len+2)
+ call aclrc (outstr, len+2)
+
+ call ip_lseek (fd, offset)
+ nstat = read (fd, Memc[buf], len)
+
+ if (mod(offset,2) == 0 && offset > 1)
+ call bytmov (Memc[buf], 2, Memc[buf], 1, len)
+ call chrupk (Memc[buf], 1, outstr, 1, len)
+
+ if (DEBUG) { call eprintf ("ip_gstr: :%s: len=%d\n");
+ call pargstr(outstr) ; call pargi (len) }
+ call sfree (sp)
+end
+
+
+# IP_GETB -- Get a byte from the given offset.
+
+short procedure ip_getb (fd, offset)
+
+int fd
+int offset
+
+int nstat, read()
+short val
+char buf[2]
+
+begin
+ call ip_lseek (fd, offset)
+ nstat = read (fd, buf, 2)
+
+ if (mod(offset,2) == 0)
+ call bytmov (buf, 2, buf, 1, 2)
+ call chrupk (buf, 1, buf, 1, 2)
+
+ if (DEBUG) { call eprintf ("ip_getb: %d\n"); call pargs(buf[1]) }
+ if (buf[1] < 0)
+ val = buf[1] + 256
+ else
+ val = buf[1]
+ return (val)
+end
+
+
+# IP_GETU -- Get a unsigned short integer from the given offset.
+
+int procedure ip_getu (fd, offset)
+
+int fd
+int offset
+
+int val
+short ip_gets()
+
+begin
+ val = ip_gets (fd, offset)
+ if (val < 0)
+ val = val + 65536
+ return (val)
+end
+
+# IP_GET[silrd] -- Get a value of <type> from the given offset.
+
+$for (silrd)
+
+PIXEL procedure ip_get$t (fd, offset)
+
+int fd
+int offset
+
+int nstat, read()
+PIXEL val
+
+begin
+ call ip_lseek (fd, offset)
+ $if (datatype == il)
+ nstat = read (fd, val, SZ_INT32 * SZB_CHAR)
+ if (SZ_INT != SZ_INT32)
+ call iupk32 (val, val, 1)
+ $else
+ nstat = read (fd, val, SZ_PIXEL * SZB_CHAR)
+ $endif
+ $if (datatype == rd)
+ call ieeupk$t (val)
+ $endif
+
+ if (DEBUG) { call eprintf ("ip_get: %g\n"); call parg$t(val) }
+ return (val)
+end
+$endfor
+
+# IP_GETN -- Get a native floating point number from the given offset.
+
+real procedure ip_getn (fd, offset)
+
+int fd
+int offset
+
+int nstat, read()
+real rval
+
+begin
+ call ip_lseek (fd, offset)
+ nstat = read (fd, rval, SZ_REAL)
+
+ if (DEBUG) { call eprintf ("ip_getn: %g\n"); call pargr(rval) }
+ return (rval)
+end
+
+
+# IP_GETN8 -- Get a native double precision floating point number from the
+# given offset.
+
+double procedure ip_getn8 (fd, offset)
+
+int fd
+int offset
+
+int nstat, read()
+double dval
+
+begin
+ call ip_lseek (fd, offset)
+ nstat = read (fd, dval, SZ_DOUBLE)
+
+ if (DEBUG) { call eprintf ("ip_getn8: %g\n"); call pargd(dval) }
+ return (dval)
+end
+
+
+# IP_AGETB -- Get an array of bytes from the file. The data pointer is
+# allocated if necessary and contains the data on output.
+
+procedure ip_agetb (fd, ptr, len)
+
+int fd #i file descriptor
+pointer ptr #i data pointer
+int len #i length of array
+
+pointer sp, buf
+int fp, nval, nstat
+int ip_lnote(), read()
+
+begin
+ fp = ip_lnote(fd)
+ if (mod(fp,2) == 0 && fp != 1)
+ nval = len
+ else
+ nval = len + 1
+
+ call smark (sp)
+ call salloc (buf, nval, TY_CHAR)
+
+ if (ptr == NULL)
+ call malloc (ptr, nval * SZB_CHAR, TY_CHAR)
+ nstat = read (fd, Memc[buf], nval / SZB_CHAR + 1)
+
+ fp = ip_lnote(fd)
+ if (mod(fp,2) == 0 && fp != 1)
+ call bytmov (Memc[buf], 2, Memc[buf], 1, nval)
+ call achtbc (Memc[buf], Memc[ptr], len)
+
+ call sfree (sp)
+end
+
+
+# IP_AGETU -- Get an array of <type> from the file. The data pointer is
+# allocated if necessary and contains the data on output.
+
+procedure ip_agetu (fd, ptr, len)
+
+int fd #i file descriptor
+pointer ptr #i data pointer
+int len #i length of array
+
+begin
+ call ip_agets (fd, ptr, len)
+ call achtsu (Mems[ptr], Mems[ptr], len)
+end
+
+
+# IP_AGET[silrd] -- Get an array of <type> from the file. The data pointer is
+# allocated if necessary and contains the data on output.
+
+$for (silrd)
+procedure ip_aget$t (fd, ptr, len)
+
+int fd #i file descriptor
+pointer ptr #i data pointer
+int len #i length of array
+
+int nstat
+int read()
+
+begin
+ if (ptr == NULL)
+ call malloc (ptr, len, TY_PIXEL)
+ $if (datatype == il)
+ nstat = read (fd, Mem$t[ptr], len * SZ_INT32)
+ if (SZ_INT != SZ_INT32)
+ call iupk32 (Mem$t[ptr], Mem$t[ptr], len)
+ $else
+ nstat = read (fd, Mem$t[ptr], len * SZ_PIXEL)
+ $endif
+ $if (datatype == rd)
+ call ieevupk$t (Mem$t[ptr], Mem$t[ptr], len)
+ $endif
+end
+
+$endfor
+
+# IP_AGETN -- Get an array of native floats from the file. The data pointer is
+# allocated if necessary and contains the data on output.
+
+procedure ip_agetn (fd, ptr, len)
+
+int fd #i file descriptor
+pointer ptr #i data pointer
+int len #i length of array
+
+int nstat
+int read()
+
+begin
+ if (ptr == NULL)
+ call malloc (ptr, len, TY_REAL)
+ nstat = read (fd, Memr[ptr], len * SZ_REAL)
+end
+
+
+# IP_AGETN8 -- Get an array of native doubles from the file. The data pointer
+# is allocated if necessary and contains the data on output.
+
+procedure ip_agetn8 (fd, ptr, len)
+
+int fd #i file descriptor
+pointer ptr #i data pointer
+int len #i length of array
+
+int nstat
+int read()
+
+begin
+ if (ptr == NULL)
+ call malloc (ptr, len, TY_DOUBLE)
+ nstat = read (fd, Memd[ptr], len * SZ_DOUBLE)
+end
+
+
+# -----------------------------------------------------------------
+# ------------------ UTILITY FILE I/O FUNCTIONS -------------------
+# -----------------------------------------------------------------
+
+
+define BLKSIZE 1024
+
+# IP_LINE -- Return the offset of the start of the given line number.
+
+int procedure ip_line (fd, line)
+
+int fd #i input file descriptor
+int line #i line number to search
+
+pointer sp, cbuf, buf
+int nl, offset, i, nread, fsize
+
+int read(), fstati()
+
+define done_ 99
+define err_ 98
+
+begin
+ if (line == 1) {
+ return (1)
+ } else {
+ call smark (sp)
+ call salloc (buf, BLKSIZE, TY_CHAR)
+ call salloc (cbuf, BLKSIZE, TY_CHAR)
+
+ # Rewind file descriptor
+ call ip_lseek (fd, BOF)
+ nl = 1
+ offset = 1
+
+ nread = BLKSIZE / SZB_CHAR
+ fsize = fstati (fd, F_FILESIZE)
+ while (read (fd, Memc[buf], nread) != EOF) {
+ # Convert it to spp chars.
+ call ip_lskip (fd, nread)
+ call chrupk (Memc[buf], 1, Memc[cbuf], 1, BLKSIZE)
+ do i = 1, BLKSIZE {
+ if (Memc[cbuf+i-1] == '\n') {
+ nl = nl + 1
+ offset = offset + 1
+ if (nl == line)
+ goto done_
+ } else
+ offset = offset + 1
+ if (offset >= fsize)
+ goto err_
+ }
+ }
+err_ call sfree (sp)
+ call ip_lseek (fd, BOF)
+ return (ERR)
+
+done_ if (DEBUG) { call eprintf("ip_line: '%s'\n"); call pargi(offset) }
+ call sfree (sp)
+ call ip_lseek (fd, offset)
+ return (offset)
+ }
+end
+
+
+# IP_LOCATE -- Return the offset of the start of the given pattern.
+
+int procedure ip_locate (fd, offset, pattern)
+
+int fd #i input file descriptor
+int offset #i offset to begin search
+char pattern[ARB] #i pattern to locate
+
+pointer sp, cbuf, buf
+int fsize, nread, patlen, cur_offset, loc
+
+int fstati(), read(), strsearch(), strlen()
+
+define done_ 99
+
+begin
+ # Rewind file descriptor
+ call ip_lseek (fd, offset)
+ cur_offset = offset
+
+ call smark (sp)
+ call salloc (buf, BLKSIZE, TY_CHAR)
+ call salloc (cbuf, BLKSIZE, TY_CHAR)
+
+ if (DEBUG) { call eprintf("ip_loc: offset %d\n"); call pargi(offset)}
+
+ nread = BLKSIZE / SZB_CHAR
+ fsize = fstati (fd, F_FILESIZE)
+ patlen = strlen (pattern)
+ while (read (fd, Memc[buf], nread) != EOF) {
+ # Convert it to spp chars.
+ call ip_lskip (fd, nread)
+ call chrupk (Memc[buf], 1, Memc[cbuf], 1, BLKSIZE)
+ loc = strsearch (Memc[cbuf], pattern)
+ if (loc != 0) {
+ cur_offset = cur_offset + loc - 1 - patlen
+ goto done_
+ } else {
+ # Allow some overlap in case the pattern broke over the blocks.
+ cur_offset = cur_offset + BLKSIZE - 2 * patlen
+ call ip_lseek (fd, cur_offset)
+ if (cur_offset + BLKSIZE > fsize)
+ nread = fsize - cur_offset + 1
+ }
+ }
+ call sfree (sp)
+ call ip_lseek (fd, BOF)
+ return (ERR)
+
+done_ if (DEBUG) { call eprintf("ip_loc: %d\n"); call pargi(cur_offset)}
+ call sfree (sp)
+ call ip_lseek (fd, offset)
+ return (cur_offset)
+end
+
+
+# IP_LSEEK -- Set the file position as a byte offset.
+
+procedure ip_lseek (fd, offset)
+
+int fd #i file descriptor
+int offset #i requested offset
+
+long cur_offset, where, fsize
+int fstati()
+common /fiocom/ cur_offset
+
+begin
+ if (offset == BOF || offset == ERR) {
+ cur_offset = 1
+ call seek (fd, BOF)
+ } else {
+ fsize = fstati (fd, F_FILESIZE) * SZB_CHAR
+ cur_offset = min (fsize, offset)
+ where = min (fsize, (offset/SZB_CHAR+mod(offset,2)))
+ call seek (fd, where)
+ }
+end
+
+
+# IP_LNOTE -- Note the file position as a byte offset.
+
+int procedure ip_lnote (fd)
+
+int fd #i file descriptor (unused)
+
+long cur_offset
+common /fiocom/ cur_offset
+
+begin
+ return (cur_offset)
+end
+
+
+# IP_LSKIP -- Bump the file position by a byte offset.
+
+procedure ip_lskip (fd, skip)
+
+int fd #i file descriptor
+int skip
+
+long cur_offset
+common /fiocom/ cur_offset
+
+begin
+ call ip_lseek (fd, cur_offset+skip)
+end
diff --git a/pkg/dataio/import/ipinfo.x b/pkg/dataio/import/ipinfo.x
new file mode 100644
index 00000000..3ded4a2d
--- /dev/null
+++ b/pkg/dataio/import/ipinfo.x
@@ -0,0 +1,256 @@
+include "import.h"
+
+
+# IP_INFO -- Print information about the binary file.
+
+procedure ip_info (ip, fname, verbose)
+
+pointer ip #i task struct pointer
+char fname[ARB] #i binary file name
+int verbose #i verbose output?
+
+pointer sp, buf
+pointer fmt
+int fdb
+int locpr(), fdb_opendb()
+
+pointer fdb_scan_records()
+extern ip_getop(), ip_dbfcn()
+
+begin
+ if (IP_BLTIN(ip) == YES) {
+ call ip_bltin_info (ip, fname, verbose)
+
+ } else if (IP_FORMAT(ip) == IP_NONE) {
+ call ip_prinfo (ip, "User Specified Format", fname, verbose)
+
+ } else {
+ call smark (sp)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+
+ if (IP_FSYM(ip) == NULL) {
+ fdb = fdb_opendb ()
+ fmt = fdb_scan_records (fdb, "image_id",
+ locpr(ip_getop), ip, locpr(ip_dbfcn), ip)
+ call fdbgstr (fmt, "id_string", Memc[buf], SZ_LINE)
+ call fdb_strip_quote (Memc[buf], Memc[buf], SZ_EXPR)
+ call ip_prinfo (ip, Memc[buf], fname, verbose)
+ call fdb_close (fmt)
+ call fdb_closedb (fdb)
+ } else {
+ call fdbgstr (IP_FSYM(ip), "id_string", Memc[buf], SZ_LINE)
+ call fdb_strip_quote (Memc[buf], Memc[buf], SZ_EXPR)
+ call ip_prinfo (ip, Memc[buf], fname, verbose)
+ }
+
+ call sfree (sp)
+ }
+end
+
+
+# IP_PRINFO -- Print information about the binary file.
+
+procedure ip_prinfo (ip, format, fname, verbose)
+
+pointer ip #i task struct pointer
+char format #i format name
+char fname[ARB] #i binary file name
+int verbose #i verbose output?
+
+int i
+bool itob()
+
+define done_ 99
+
+begin
+ #call printf ("Input file:\n\t")
+ if (verbose == NO) {
+ call printf ("%s: %20t")
+ call pargstr (fname)
+ do i = 1, IP_NDIM(ip) {
+ call printf ("%d ")
+ call pargi (IP_AXLEN(ip,i))
+ if (i < IP_NDIM(ip))
+ call printf ("x ")
+ }
+ call printf (" \t%s\n")
+ call pargstr (format)
+
+ # Print out the format comment if any.
+# if (IP_COMPTR(ip) != NULL) {
+# if (COMMENT(ip) != '\0') {
+# call printf ("%s\n")
+# call pargstr (COMMENT(ip))
+# }
+# call strcpy ("\0", COMMENT(ip), SZ_LINE)
+# }
+ return
+ }
+
+ # Print a more verbose description.
+ call printf ("%s: %20t%s\n")
+ call pargstr (fname)
+ call pargstr (format)
+
+ # Print out the format comment if any.
+ if (IP_COMPTR(ip) != NULL) {
+ if (COMMENT(ip) != '\0') {
+ call printf ("%s\n")
+ call pargstr (COMMENT(ip))
+ }
+ call strcpy ("\0", COMMENT(ip), SZ_LINE)
+ }
+
+ # Print the image size.
+ if (IP_NDIM(ip) > 0) {
+ call printf ("%20tResolution:%38t")
+ do i = 1, IP_NDIM(ip) {
+ call printf ("%d ")
+ call pargi (IP_AXLEN(ip,i))
+ if (i < IP_NDIM(ip))
+ call printf ("x ")
+ }
+ call printf ("\n")
+ }
+
+ # Print other information.
+ if (PTYPE(ip,1) != NULL) {
+ call printf ("%20tPixel type: %38t%d-bit ")
+ call pargi (8 * IO_NBYTES(PTYPE(ip,1)))
+ switch (IO_TYPE(PTYPE(ip,1))) {
+ case PT_UINT:
+ call printf ("unsigned integer\n")
+ case PT_INT:
+ call printf ("signed integer\n")
+ case PT_IEEE:
+ call printf ("IEEE floating point\n")
+ case PT_NATIVE:
+ call printf ("native floating point\n")
+ default:
+ call printf ("\n")
+ }
+ }
+
+ call printf ("%20tPixel storage: %38t%s\n")
+ if (BAND_INTERLEAVED(ip))
+ call pargstr ("non-interleaved")
+ else if (LINE_INTERLEAVED(ip))
+ call pargstr ("line-interleaved")
+ else if (PIXEL_INTERLEAVED(ip))
+ call pargstr ("pixel-interleaved")
+ else
+ call pargstr ("unknown")
+ call printf ("%20tHeader length: %38t%d bytes\n")
+ call pargi (IP_HSKIP(ip))
+ call printf ("%20tByte swapped: %38t%b\n")
+ call pargb (itob(IP_SWAP(ip)))
+end
+
+
+# IP_OBINFO - Print information about the output image contents.
+
+procedure ip_obinfo (ip, imname)
+
+pointer ip #i ip struct pointer
+char imname[ARB] #i image name
+
+int i, nb
+
+begin
+ call printf (" Output image:\n")
+
+ if (IP_NBANDS(ip) != ERR) {
+ nb = IP_NBANDS(ip)
+ do i = 1, nb {
+ call printf ("\t%s[*,*,%d]:%30t==> %s %s\n")
+ call pargstr (imname)
+ call pargi (i)
+ call pargstr (O_EXPR(ip,i))
+ if (i == 1)
+ call pargstr (" # outbands expr")
+ else
+ call pargstr (" ")
+ }
+ } else {
+ nb = max (IP_AXLEN(ip,3), max (IP_INTERLEAVE(ip), IP_NPIXT(ip)))
+ do i = 1, nb {
+ call printf ("\t%s[*,*,%d]:%30t==> %s%d %s\n")
+ call pargstr (imname)
+ call pargi (i)
+ call pargstr ("b")
+ call pargi (i)
+ if (i == 1)
+ call pargstr (" # outbands expr")
+ else
+ call pargstr (" ")
+ }
+ }
+
+end
+
+
+# IP_LIST_FORMATS -- List the formats in the database. The DB is scanned
+# and the format name for each record found, as well as the verbose ID
+# string is printed on the standard output. The file position is left at
+# the same place on exit.
+
+procedure ip_list_formats (fd)
+
+int fd #i input binary file descriptor
+
+pointer sp, format, idstr, alias
+pointer fmt, ap[5]
+int i, nsym, cur_offset
+
+int note()
+pointer stfindall(), fdb_next_rec()
+
+begin
+ # Save current file offset.
+ cur_offset = note (fd)
+
+ call smark (sp)
+ call salloc (format, SZ_EXPR, TY_CHAR)
+ call salloc (idstr, SZ_EXPR, TY_CHAR)
+ call salloc (alias, SZ_LINE, TY_CHAR)
+
+ # Loop through the database records.
+ call seek (fd, BOF)
+ fmt = NULL
+ call printf ("Format%15tAliases%36tFormat Identification\n")
+ call printf ("------%15t-------%36t---------------------\n")
+ repeat {
+ fmt = fdb_next_rec (fd)
+ if (fmt == NULL)
+ break
+ call fdbgstr (fmt, "format", Memc[format], SZ_EXPR)
+ call fdbgstr (fmt, "id_string", Memc[idstr], SZ_EXPR)
+ call fdb_strip_quote (Memc[idstr], Memc[idstr], SZ_EXPR)
+
+ # Generate a list of aliases for the format.
+ call aclrc (Memc[alias], SZ_LINE)
+ nsym = stfindall (fmt, "alias", ap, 5)
+ if (nsym >= 1) {
+ do i = nsym, 1, -1 {
+ call strcat (Memc[P2C(ap[i])], Memc[alias], SZ_LINE)
+ if (i > 1)
+ call strcat (",", Memc[alias], SZ_LINE)
+ }
+ } else
+ Memc[alias] = EOS
+
+ # Print the information
+ call printf ("%s%15t%.20s%36t%s\n")
+ call pargstr (Memc[format])
+ call pargstr (Memc[alias])
+ call pargstr (Memc[idstr])
+
+ call fdb_close (fmt)
+ call flush (STDOUT)
+ }
+
+ # Restore file offset.
+ call seek (fd, cur_offset)
+
+ call sfree (sp)
+end
diff --git a/pkg/dataio/import/iplistpix.x b/pkg/dataio/import/iplistpix.x
new file mode 100644
index 00000000..3f4a001d
--- /dev/null
+++ b/pkg/dataio/import/iplistpix.x
@@ -0,0 +1,137 @@
+include <imhdr.h>
+include <error.h>
+include <mwset.h>
+
+# IP_LISTPIXELS -- Convert image pixels into a text stream, i.e., into a list.
+# Each pixel is printed on a separate line, preceded by its coordinates.
+
+procedure ip_listpix (im)
+
+char wcs[SZ_FNAME]
+double incoords[IM_MAXDIM], outcoords[IM_MAXDIM]
+int i, j, npix, ndim, wcsndim, laxis1, fmtstat
+int paxno[IM_MAXDIM], laxno[IM_MAXDIM]
+long v[IM_MAXDIM], vcoords[IM_MAXDIM]
+pointer im, line, mw, ct, fmtptrs[IM_MAXDIM]
+
+int imgnlr(), mw_stati()
+pointer mw_openim(), mw_sctran()
+
+begin
+ # Get info from the input image.
+ ndim = IM_NDIM(im)
+ npix = IM_LEN(im,1)
+
+ # Get the wcs.
+ call strcpy ("world", wcs, SZ_FNAME)
+ ifnoerr (mw = mw_openim (im)) {
+ # Set up the transformation.
+ call mw_seti (mw, MW_USEAXMAP, NO)
+ ct = mw_sctran (mw, "logical", wcs, 0)
+ wcsndim = mw_stati (mw, MW_NPHYSDIM)
+
+ # Get the physical to logical axis map.
+ call mw_gaxmap (mw, paxno, laxno, wcsndim)
+
+ # Set the default wcs.
+ call mw_ssytem (mw, wcs)
+
+ } else {
+ # Print the error message from the above loop.
+ call erract (EA_WARN)
+
+ # Set the transform to the identity transform.
+ mw = NULL
+ ct = NULL
+ wcsndim = ndim
+
+ # Set the default physical to logical axis map.
+ do i = 1, wcsndim
+ paxno[i] = i
+ }
+
+ # Initialize the v vectors.
+ call amovkl (long (1), v, IM_MAXDIM)
+ call amovkl (long (1), vcoords, IM_MAXDIM)
+
+ # Initialize the coordinates.
+ laxis1 = 0
+ do i = 1, wcsndim {
+ if (paxno[i] == 0) {
+ incoords[i] = 1
+ } else if (paxno[i] == 1) {
+ laxis1 = i
+ incoords[i] = v[1]
+ } else {
+ incoords[i] = v[paxno[i]]
+ }
+ }
+
+ # Check and correct for the no axis mapping case.
+ if (laxis1 == 0) {
+ laxis1 = 1
+ do i = 1, wcsndim
+ paxno[i] = i
+ }
+
+ # Get the logical to physical axis map for the format strings.
+ do i = 1, ndim {
+ laxno[i] = 0
+ do j = 1, wcsndim {
+ if (paxno[j] != i)
+ next
+ laxno[i] = j
+ break
+ }
+ }
+
+ # Set the format strings for the logical axes.
+ fmtstat = EOS
+ do i = 1, ndim {
+ call malloc (fmtptrs[i], SZ_FNAME, TY_CHAR)
+ if (fmtstat != EOF)
+ call gargwrd (Memc[fmtptrs[i]], SZ_FNAME)
+ else
+ Memc[fmtptrs[i]] = EOS
+ if (laxno[i] == 0)
+ call strcpy ("%0.15g ", Memc[fmtptrs[i]], SZ_FNAME)
+ else if (mw == NULL || ct == NULL)
+ call strcpy ("%0.15g ", Memc[fmtptrs[i]], SZ_FNAME)
+ else iferr (call mw_gwattrs (mw, laxno[i], "format",
+ Memc[fmtptrs[i]], SZ_FNAME))
+ call strcpy ("%0.15g ", Memc[fmtptrs[i]], SZ_FNAME)
+ else
+ call strcat (" ", Memc[fmtptrs[i]], SZ_FNAME)
+ }
+
+ # Print the pixels.
+ while (imgnlr (im, line, v) != EOF) {
+ do i = 1, npix {
+ incoords[laxis1] = i
+ if (ct == NULL)
+ call amovd (incoords, outcoords, wcsndim)
+ else
+ call mw_ctrand (ct, incoords, outcoords, wcsndim)
+ do j = 1, ndim { # X, Y, Z, etc.
+ call printf (Memc[fmtptrs[j]])
+ if (laxno[j] == 0)
+ call pargd (double(vcoords[j]))
+ else
+ call pargd (outcoords[laxno[j]])
+ }
+ call printf (" %g\n") # pixel value
+ call pargr (Memr[line+i-1])
+ }
+ call amovl (v, vcoords, IM_MAXDIM)
+ do i = 1, wcsndim {
+ if (paxno[i] == 0)
+ next
+ incoords[i] = v[paxno[i]]
+ }
+ }
+
+ do i = 1, ndim
+ call mfree (fmtptrs[i], TY_CHAR)
+ if (mw != NULL)
+ call mw_close (mw)
+end
diff --git a/pkg/dataio/import/ipmkhdr.x b/pkg/dataio/import/ipmkhdr.x
new file mode 100644
index 00000000..c8432ed2
--- /dev/null
+++ b/pkg/dataio/import/ipmkhdr.x
@@ -0,0 +1,63 @@
+include <imhdr.h>
+include <ctype.h>
+include "import.h"
+
+define LEN_COMMENT 70 # Maximum comment length
+define COMMENT "COMMENT " # Comment key
+define IS_FITS (IS_DIGIT($1)||IS_UPPER($1)||($1=='-')||($1=='_'))
+
+# IP_MKHEADER -- Append or substitute new image header from an image or file.
+# Only the legal FITS cards (ignoring leading whitespace) will be copied
+# from a file.
+
+procedure ip_mkheader (im, fname)
+
+pointer im # IMIO pointer
+char fname[ARB] # Image or data file name
+
+int i, j
+pointer ua, fd
+pointer sp, str
+
+int open(), getline(), nowhite()
+pointer immap()
+errchk open
+
+begin
+ if (nowhite (fname, fname, SZ_FNAME) == 0)
+ return
+
+ ua = IM_USERAREA(im)
+ ifnoerr (fd = immap (fname, READ_ONLY, LEN_UA)) {
+ call strcpy (Memc[IM_USERAREA(fd)], Memc[ua], LEN_UA)
+ call imunmap (fd)
+ } else {
+ fd = open (fname, READ_ONLY, TEXT_FILE)
+
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ Memc[ua] = EOS
+ while (getline (fd, Memc[str]) != EOF) {
+ for (i=str; IS_WHITE(Memc[i]); i=i+1)
+ ;
+ for (j=i; IS_FITS(Memc[j]); j=j+1)
+ ;
+ for (; j<i+8 && Memc[j]==' '; j=j+1)
+ ;
+ if (j<i+8 && (Memc[j] != EOS || Memc[j] != '\n'))
+ next
+ if (Memc[j] == '=' && Memc[j+1] != ' ')
+ next
+ for (; j<i+80 && Memc[j] != EOS; j=j+1)
+ ;
+ if (Memc[j-1] != '\n') {
+ Memc[j] = '\n'
+ Memc[j+1] = EOS
+ }
+ call strcat (Memc[i], Memc[ua], LEN_UA)
+ }
+ call sfree (sp)
+ call close (fd)
+ }
+end
diff --git a/pkg/dataio/import/ipobands.gx b/pkg/dataio/import/ipobands.gx
new file mode 100644
index 00000000..be568818
--- /dev/null
+++ b/pkg/dataio/import/ipobands.gx
@@ -0,0 +1,306 @@
+include <error.h>
+include <mach.h>
+include <evvexpr.h>
+include <fset.h>
+include "../import.h"
+include "../ipfcn.h"
+
+define DEBUG false
+define VDEBUG false
+
+
+# IP_GETOP -- Called by evvexpr to get an operand.
+
+procedure ip_getop (ip, opname, o)
+
+pointer ip #i task struct pointer
+char opname[ARB] #i operand name to retrieve
+pointer o #o output operand pointer
+
+int i, nops, found, optype
+pointer sp, buf
+pointer op
+
+int fstati(), ip_ptype(), strlen(), strncmp()
+bool streq()
+
+begin
+ # First see if it's one of the special file operands.
+ if (opname[1] == '$') {
+ if (strncmp(opname, "$FSIZE", 3) == 0) {
+ O_LEN(o) = 0
+ O_TYPE(o) = TY_INT
+ O_VALI(o) = fstati (IP_FD(ip), F_FILESIZE) * SZB_CHAR
+ } else if (strncmp(opname, "$FNAME", 3) == 0) {
+ call smark (sp)
+ call salloc (buf, SZ_FNAME, TY_CHAR)
+
+ call fstats (IP_FD(ip), F_FILENAME, Memc[buf], SZ_FNAME)
+
+ O_TYPE(o) = TY_CHAR
+ O_LEN(o) = strlen (Memc[buf]) + 1
+ call malloc (O_VALP(o), O_LEN(o), TY_CHAR)
+ call strcpy (Memc[buf], O_VALC(o), i)
+ call sfree (sp)
+ }
+
+ return
+ }
+
+ nops = IP_NPIXT(ip)
+ found = NO
+ do i = 1, nops {
+ # Search for operand name which matches requested value.
+ op = PTYPE(ip,i)
+ if (streq (Memc[IO_TAG(op)],opname)) {
+ found = YES
+ break
+ }
+ }
+
+ if (VDEBUG) {
+ call eprintf ("getop: opname=%s tag=%s found=%d ")
+ call pargstr(opname) ; call pargstr(Memc[IO_TAG(op)])
+ call pargi(found)
+ if (found == YES) call zzi_prop (op)
+ }
+
+ if (found == YES) {
+ # Copy operand descriptor to 'o'
+ optype = ip_ptype (IO_TYPE(op), IO_NBYTES(op))
+ switch (optype) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ O_LEN(o) = IO_NPIX(op)
+ O_TYPE(o) = TY_SHORT
+ call malloc (O_VALP(o), IO_NPIX(op), TY_SHORT)
+ call amovs (Mems[IO_DATA(op)], Mems[O_VALP(o)], IO_NPIX(op))
+ $for (ilrd)
+ case TY_PIXEL:
+ O_LEN(o) = IO_NPIX(op)
+ O_TYPE(o) = TY_PIXEL
+ call malloc (O_VALP(o), IO_NPIX(op), TY_PIXEL)
+ call amov$t (Mem$t[IO_DATA(op)], Mem$t[O_VALP(o)], IO_NPIX(op))
+ $endfor
+ }
+
+ } else {
+ call smark (sp)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[buf], SZ_LINE, "Unknown outbands operand `%s'\n")
+ call pargstr(opname)
+ call sfree (sp)
+ call error (1, Memc[buf])
+ }
+end
+
+
+# IP_EVALUATE -- Evaluate the outbands expression.
+
+pointer procedure ip_evaluate (ip, expr)
+
+pointer ip #i task struct pointer
+char expr[ARB] #i expression to be evaluated
+
+pointer o # operand pointer to result
+
+int locpr()
+pointer evvexpr()
+extern ip_getop(), ip_obfcn()
+errchk evvexpr
+
+begin
+ if (DEBUG) { call eprintf("ip_eval: expr='%s'\n") ; call pargstr(expr) }
+
+ # Evaluate the expression.
+ iferr {
+ o = evvexpr (expr, locpr(ip_getop), ip, locpr(ip_obfcn), ip,
+ EV_RNGCHK)
+ } then
+ call erract (EA_FATAL)
+
+ return (o)
+end
+
+
+# IP_OBFCN -- Called by evvexpr to execute import outbands special functions.
+
+procedure ip_obfcn (ip, fcn, args, nargs, o)
+
+pointer ip #i task struct pointer
+char fcn[ARB] #i function to be executed
+pointer args[ARB] #i argument list
+int nargs #i number of arguments
+pointer o #o operand pointer
+
+pointer sp, buf
+pointer r, g, b, gray, color, cmap
+int i, len, v_nargs, func
+
+int or(), strdic()
+bool strne()
+
+define setop_ 99
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_FNAME, TY_CHAR)
+
+ # Lookup function in dictionary.
+ func = strdic (fcn, Memc[buf], SZ_LINE, OB_FUNCTIONS)
+ if (func > 0 && strne(fcn,Memc[buf]))
+ func = 0
+
+ # Abort if the function is not known.
+ if (func <= 0)
+ call xev_error1 ("unknown function `%s' called", fcn)
+
+ # Verify the correct number of arguments, negative value means a
+ # variable number of args, handle it in the evaluation.
+ switch (func) {
+ case GRAY, GREY:
+ v_nargs = 3
+ case FLIPX, FLIPY:
+ v_nargs = 1
+ case RED, GREEN, BLUE:
+ v_nargs = 1
+ }
+ if (v_nargs > 0 && nargs != v_nargs)
+ call xev_error2 ("function `%s' requires %d arguments",
+ fcn, v_nargs)
+ else if (v_nargs < 0 && nargs < abs(v_nargs))
+ call xev_error2 ("function `%s' requires at least %d arguments",
+ fcn, abs(v_nargs))
+
+ if (DEBUG) {
+ call eprintf ("obfcn: nargs=%d func=%d\n")
+ call pargi (nargs) ; call pargi (func)
+ do i = 1, nargs { call eprintf ("\t") ; call zzi_pevop (args[i]) }
+ call flush (STDERR)
+ }
+
+ # Evaluate the function.
+ switch (func) {
+ case GRAY, GREY:
+ # evaluate expression for NTSC grayscale.
+ r = O_VALP(args[1])
+ g = O_VALP(args[2])
+ b = O_VALP(args[3])
+ len = O_LEN(args[1]) - 1
+ O_LEN(o) = len + 1
+ O_TYPE(o) = TY_REAL
+ call malloc (O_VALP(o), len+1, TY_REAL)
+ gray = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ do i = 0, len {
+ Memr[gray+i] = R_COEFF * Mems[r+i] +
+ G_COEFF * Mems[g+i] +
+ B_COEFF * Mems[b+i]
+ }
+ $for (ilrd)
+ case TY_PIXEL:
+ do i = 0, len {
+ Memr[gray+i] = R_COEFF * Mem$t[r+i] +
+ G_COEFF * Mem$t[g+i] +
+ B_COEFF * Mem$t[b+i]
+ }
+ $endfor
+ }
+
+ case RED:
+ # Get the red colormap component of the image.
+ cmap = IP_CMAP(ip)
+ if (func <= 0)
+ call xev_error1 ("No colormap in image for function `%s'", fcn)
+ r = O_VALP(args[1])
+ len = O_LEN(args[1]) - 1
+ O_LEN(o) = len + 1
+ O_TYPE(o) = TY_SHORT
+ call malloc (O_VALP(o), len+1, TY_SHORT)
+ color = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ do i = 0, len
+ Mems[color+i] = CMAP(cmap,IP_RED,Mems[r+i]+1)
+ $for (il)
+ case TY_PIXEL:
+ do i = 0, len
+ Mems[color+i] = CMAP(cmap,IP_RED,Mem$t[r+i]+1)
+ $endfor
+ }
+
+ case GREEN:
+ # Get the blue colormap component of the image.
+ cmap = IP_CMAP(ip)
+ if (func <= 0)
+ call xev_error1 ("No colormap in image for function `%s'", fcn)
+ g = O_VALP(args[1])
+ len = O_LEN(args[1]) - 1
+ O_LEN(o) = len + 1
+ O_TYPE(o) = TY_SHORT
+ call malloc (O_VALP(o), len+1, TY_SHORT)
+ color = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ do i = 0, len
+ Mems[color+i] = CMAP(cmap,IP_GREEN,Mems[g+i]+1)
+ $for (il)
+ case TY_PIXEL:
+ do i = 0, len
+ Mems[color+i] = CMAP(cmap,IP_GREEN,char(Mem$t[g+i]+1))
+ $endfor
+ }
+
+ case BLUE:
+ # Get the blue colormap component of the image.
+ cmap = IP_CMAP(ip)
+ if (func <= 0)
+ call xev_error1 ("No colormap in image for function `%s'", fcn)
+ b = O_VALP(args[1])
+ len = O_LEN(args[1]) - 1
+ O_LEN(o) = len + 1
+ O_TYPE(o) = TY_SHORT
+ call malloc (O_VALP(o), len+1, TY_SHORT)
+ color = O_VALP(o)
+ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ do i = 0, len
+ Mems[color+i] = CMAP(cmap,IP_BLUE,Mems[b+i]+1)
+ $for (il)
+ case TY_PIXEL:
+ do i = 0, len
+ Mems[color+i] = CMAP(cmap,IP_BLUE,char(Mem$t[b+i]+1))
+ $endfor
+ }
+
+ case FLIPX:
+ # Set flag to reverse pixel order on output.
+ IP_FLIP(ip) = or (IP_FLIP(ip), FLIP_X)
+ goto setop_
+
+ case FLIPY:
+ # Set flag to write image from bottom to top.
+ IP_FLIP(ip) = or (IP_FLIP(ip), FLIP_Y)
+
+ # Copy argument operand descriptor to 'o'
+setop_ switch (O_TYPE(args[1])) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ O_LEN(o) = O_LEN(args[1])
+ O_TYPE(o) = TY_SHORT
+ call malloc (O_VALP(o), O_LEN(args[1]), TY_SHORT)
+ call amovs (Mems[O_VALP(ARGS[1])], Mems[O_VALP(o)], O_LEN(o))
+ $for (ilrd)
+ case TY_PIXEL:
+ O_LEN(o) = O_LEN(args[1])
+ O_TYPE(o) = TY_PIXEL
+ call malloc (O_VALP(o), O_LEN(args[1]), TY_PIXEL)
+ call amov$t (Mem$t[O_VALP(args[1])], Mem$t[O_VALP(o)], O_LEN(o))
+ $endfor
+ }
+
+ }
+
+ if (DEBUG) { call zzi_pevop (o) }
+
+ call sfree (sp)
+end
diff --git a/pkg/dataio/import/ipproc.gx b/pkg/dataio/import/ipproc.gx
new file mode 100644
index 00000000..38217a4d
--- /dev/null
+++ b/pkg/dataio/import/ipproc.gx
@@ -0,0 +1,804 @@
+include <mach.h>
+include <imhdr.h>
+include <evvexpr.h>
+include "../import.h"
+
+define DEBUG false
+
+
+# IP_PRBAND -- Process a band interleaved file.
+
+procedure ip_prband (ip, fd, im, cmap)
+
+pointer ip #i task struct pointer
+int fd #i inpout file descriptor
+pointer im #i output image pointer
+pointer cmap #i colormap pointer
+
+int i, j, nlines, npix
+int optype, nbytes_pix, percent
+int cur_offset, band_offset, line_offset
+
+int ip_ptype()
+long ip_lnote()
+
+begin
+ # Rewind the file and skip header pixels.
+ call ip_lseek (fd, BOF)
+ call ip_lseek (fd, IP_HSKIP(ip)+1)
+
+ # Compute the offset between the same pixel in different bands. This
+ # is the area of the image plus any image padding, computed as a
+ # byte offset.
+ optype = ip_ptype (IO_TYPE(PTYPE(ip,1)),IO_NBYTES(PTYPE(ip,1)))
+ switch (optype) {
+ case TY_UBYTE: nbytes_pix = 1
+ case TY_USHORT, TY_SHORT: nbytes_pix = SZB_CHAR * SZ_SHORT
+ case TY_INT: nbytes_pix = SZB_CHAR * SZ_INT32
+ case TY_LONG: nbytes_pix = SZB_CHAR * SZ_LONG
+ case TY_REAL: nbytes_pix = SZB_CHAR * SZ_REAL
+ case TY_DOUBLE: nbytes_pix = SZB_CHAR * SZ_DOUBLE
+ }
+ band_offset = (IP_AXLEN(ip,1) * (IP_AXLEN(ip,2)-1)) +
+ ((IP_LSKIP(ip) + IP_LPAD(ip)) * (IP_AXLEN(ip,2)-1)) +
+ IP_BSKIP(ip)
+ band_offset = (band_offset * nbytes_pix) #+ 1
+
+ if (DEBUG) {
+ call eprintf ("ip_prband: band_offset=%d curpos=%d\n")
+ call pargi(band_offset) ; call pargi(ip_lnote(fd))
+ call zzi_prstruct ("ip_prband", ip)
+ }
+
+ # Patch up the pixtype param if needed.
+ call ip_fix_pixtype (ip)
+
+ # See if we need to create any outbands operands if the user didn't.
+ if (IP_NBANDS(ip) == ERR)
+ call ip_fix_outbands (ip)
+
+ # Loop over the image lines.
+ nlines = IP_AXLEN(ip,2)
+ npix = IP_AXLEN(ip,1)
+ percent = 0
+ do i = 1, nlines {
+ # Skip pixels at front of line
+ line_offset = ip_lnote (fd)
+ if (IP_LSKIP(ip) != 0)
+ call ip_lskip (fd, IP_LSKIP(ip))
+
+ # Read pixels in the line and save as operand.
+ call ip_rdline (ip, fd, 1, npix, cmap)
+
+ # Skip pixels at end of line.
+ if (IP_LPAD(ip) != 0)
+ call ip_lskip (fd, IP_LPAD(ip))
+ cur_offset = ip_lnote (fd)
+
+ # Loop over each of the remaining pixtypes.
+ do j = 2, IP_NPIXT(ip) {
+ # Seek to offset of next band (i.e. line_offset + band_offset).
+ call ip_lskip (fd, band_offset)
+ if (IP_LSKIP(ip) != 0)
+ call ip_lskip (fd, IP_LSKIP(ip))
+ call ip_rdline (ip, fd, j, npix, cmap) # read pixels in the line
+ if (IP_LPAD(ip) != 0)
+ call ip_lskip (fd, IP_LPAD(ip))
+ }
+
+ # Evaluate and write the outbands expressions.
+ call ip_probexpr (ip, im, npix, i)
+
+ # Print percent done if being verbose
+ #if (IP_VERBOSE(ip) == YES)
+ call ip_pstat (ip, i, percent)
+
+ # Restore file pointer to cur_offset.
+ call ip_lseek (fd, cur_offset)
+ }
+ do i = 1, IP_NBANDS(ip)
+ call mfree (BUFFER(ip,i), IM_PIXTYPE(im))
+end
+
+
+# IP_PRLINE -- Process a line interleaved file.
+
+procedure ip_prline (ip, fd, im, cmap)
+
+pointer ip #i task struct pointer
+int fd #i inpout file descriptor
+pointer im #i output image pointer
+pointer cmap #i colormap pointer
+
+int i, j, nlines, npix, percent
+
+begin
+ # Rewind the file and skip header pixels.
+ call ip_lseek (fd, BOF)
+ call ip_lseek (fd, IP_HSKIP(ip)+1)
+
+ if (DEBUG) {
+ call eprintf ("ip_prline:\n")
+ call zzi_prstruct ("ip_prline", ip)
+ }
+
+ # Patch up the pixtype param if needed.
+ call ip_fix_pixtype (ip)
+
+ # See if we need to create any outbands operands if the user didn't.
+ if (IP_NBANDS(ip) == ERR)
+ call ip_fix_outbands (ip)
+
+ # Loop over the image lines.
+ nlines = IP_AXLEN(ip,2)
+ npix = IP_AXLEN(ip,1)
+ percent = 0
+ do i = 1, nlines {
+
+ do j = 1, IP_NPIXT(ip) {
+ # Skip pixels at front of line
+ call ip_lskip (fd, IP_LSKIP(ip))
+
+ # Read pixels in the line and save as operand.
+ call ip_rdline (ip, fd, j, npix, cmap)
+
+ # Skip pixels at end of line.
+ call ip_lskip (fd, IP_LPAD(ip))
+ }
+
+ # Evaluate and write the outbands expressions.
+ call ip_probexpr (ip, im, npix, i)
+
+ # Print percent done if being verbose
+ #if (IP_VERBOSE(ip) == YES)
+ call ip_pstat (ip, i, percent)
+ }
+ do i = 1, IP_NBANDS(ip)
+ call mfree (BUFFER(ip,i), IM_PIXTYPE(im))
+end
+
+
+# IP_PRPIX -- Process a pixel interleaved file.
+
+procedure ip_prpix (ip, fd, im, cmap)
+
+pointer ip #i task struct pointer
+int fd #i inpout file descriptor
+pointer im #i output image pointer
+pointer cmap #i colormap pointer
+
+pointer op, data
+int i, swap, optype, nlines
+int percent, npix, totpix
+
+int and(), ip_ptype()
+
+begin
+ # Rewind the file and skip header pixels.
+ call ip_lseek (fd, BOF)
+ call ip_lseek (fd, IP_HSKIP(ip)+1)
+
+ if (DEBUG) { call eprintf ("ip_prpix: ") }
+
+ # See if we need to create any outbands operands if the user didn't.
+ if (IP_NBANDS(ip) == ERR)
+ call ip_fix_outbands (ip)
+
+ # Allocate the pixtype data pointers.
+ npix = IP_AXLEN(ip,1)
+ nlines = IP_NPIXT(ip)
+ do i = 1, nlines {
+ op = PTYPE(ip,i)
+ optype = ip_ptype (IO_TYPE(op),IO_NBYTES(op))
+ IO_NPIX(op) = npix
+ if (IO_DATA(op) == NULL)
+ if (optype == TY_UBYTE)
+ call malloc (IO_DATA(op), npix, TY_SHORT)
+ else
+ call malloc (IO_DATA(op), npix, optype)
+ }
+
+ # Loop over the image lines.
+ nlines = IP_AXLEN(ip,2)
+ totpix = npix * IP_NPIXT(ip)
+ swap = IP_SWAP(ip)
+ percent = 0
+ if (DEBUG) {
+ call zzi_prstruct ("ip_prpix", ip)
+ call eprintf ("nl=%d np=%d tp=%d:\n")
+ call pargi(nlines) ; call pargi(npix) ; call pargi(totpix)
+ }
+ do i = 1, nlines {
+
+ # Skip pixels at front of line
+ call ip_lskip (fd, IP_LSKIP(ip))
+
+ # Read pixels in the line.
+ switch (optype) {
+ case TY_UBYTE:
+ call ip_agetb (fd, data, totpix)
+ call ip_lskip (fd, totpix)
+ # Apply a colormap to the bytes. In general a pixel-interleaved
+ # file is a 24-bit True Color image, but maybe this is a
+ # 3-D color index file?
+ if (cmap != NULL && IP_USE_CMAP(ip) == YES)
+ call ip_gray_cmap (Memc[data], totpix, cmap)
+
+ case TY_USHORT:
+ call ip_agetu (fd, data, totpix)
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I2) == S_I2) {
+ call bswap2 (Mems[data], 1, Mems[data], 1,
+ (totpix*(SZ_SHORT*SZB_CHAR)))
+ }
+ call ip_lskip (fd, (totpix * (SZB_CHAR * SZ_SHORT)))
+
+ $for (silrd)
+ case TY_PIXEL:
+ call ip_aget$t (fd, data, totpix)
+ $if (datatype == s)
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I2) == S_I2) {
+ call bswap2 (Mem$t[data], 1, Mem$t[data], 1,
+ (totpix*(SZ_PIXEL*SZB_CHAR)))
+ }
+ $endif
+ $if (datatype == il)
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I4) == S_I4) {
+ if (SZ_INT != SZ_INT32) {
+ call ipak32 (Mem$t[data], Mem$t[data], totpix)
+ call bswap4 (Mem$t[data], 1, Mem$t[data], 1,
+ (totpix*(SZ_INT32*SZB_CHAR)))
+ } else {
+ call bswap4 (Mem$t[data], 1, Mem$t[data], 1,
+ (totpix*(SZ_INT*SZB_CHAR)))
+ }
+ }
+ $endif
+ $if (datatype == r)
+ if (and(swap, S_ALL) == S_ALL) {
+ call bswap4 (Mem$t[data], 1, Mem$t[data], 1,
+ (totpix*(SZ_PIXEL*SZB_CHAR)))
+ }
+ $endif
+ $if (datatype == d)
+ if (and(swap, S_ALL) == S_ALL) {
+ call bswap8 (Mem$t[data], 1, Mem$t[data], 1,
+ (totpix*(SZ_PIXEL*SZB_CHAR)))
+ }
+ $endif
+
+ $if (datatype == il)
+ call ip_lskip (fd, (totpix * (SZB_CHAR * SZ_INT32)))
+ $else
+ call ip_lskip (fd, (totpix * (SZB_CHAR * SZ_PIXEL)))
+ $endif
+ $endfor
+ }
+
+ # Skip pixels at end of line.
+ call ip_lskip (fd, IP_LPAD(ip))
+
+ # Separate pixels into different vectors.
+ call ip_upkpix (ip, data, npix)
+
+ # Evaluate and write the outbands expressions.
+ call ip_probexpr (ip, im, npix, i)
+
+ # Print percent done if being verbose
+ #if (IP_VERBOSE(ip) == YES)
+ call ip_pstat (ip, i, percent)
+ }
+
+ if (optype == TY_UBYTE)
+ call mfree (data, TY_SHORT)
+ else
+ call mfree (data, optype)
+ do i = 1, IP_NBANDS(ip)
+ call mfree (BUFFER(ip,i), IM_PIXTYPE(im))
+end
+
+
+# IP_PROBEXPR -- Process each of the outbands expressions and write the result
+# to the output image.
+
+procedure ip_probexpr (ip, im, npix, line)
+
+pointer ip #i task struct pointer
+pointer im #i output image pointer
+int npix #i number of output pixels
+int line #i line number
+
+int i
+pointer out, ip_evaluate()
+
+begin
+ # Loop over outbands expressions.
+ do i = 1, IP_NBANDS(ip) {
+ # Evaluate outbands expression.
+ out = ip_evaluate (ip, O_EXPR(ip,i))
+
+ # Write bands to output image
+ if (IP_OUTPUT(ip) != IP_NONE)
+ call ip_wrline (ip, im, out, npix, line, i)
+
+ call evvfree (out)
+ }
+end
+
+
+# IP_RDLINE -- Read a line of pixels from the binary file.
+
+procedure ip_rdline (ip, fd, pnum, npix, cmap)
+
+pointer ip #i task struct pointer
+int fd #i input file descriptor
+int pnum #i pixtype number
+int npix #i number of pixels to read
+pointer cmap #i colormap pointer
+
+pointer op, data
+int swap, ptype
+
+int and(), ip_ptype()
+
+begin
+ # Read pixels in the line and save as operand.
+ op = PTYPE(ip,pnum)
+ ptype = ip_ptype (IO_TYPE(op), IO_NBYTES(op))
+ data = IO_DATA(op)
+ swap = IP_SWAP(ip)
+ IO_NPIX(op) = npix
+
+ switch (ptype) {
+ case TY_UBYTE:
+ call ip_agetb (fd, data, npix)
+ call ip_lskip (fd, npix)
+ # Apply a colormap to the bytes. If the colormap is non-null we
+ # assume the bytes are color indices into a colormap.
+ if (cmap != NULL && IP_USE_CMAP(ip) == YES)
+ call ip_gray_cmap (Memc[data], npix, cmap)
+
+ case TY_USHORT:
+ call ip_agetu (fd, data, npix)
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I2) == S_I2) {
+ call bswap2 (Mems[data], 1, Mems[data], 1,
+ (npix*(SZ_SHORT*SZB_CHAR)))
+ }
+ call ip_lskip (fd, (npix * (SZB_CHAR * SZ_SHORT)))
+ $for (silrd)
+ case TY_PIXEL:
+ call ip_aget$t (fd, data, npix)
+ $if (datatype == s)
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I2) == S_I2) {
+ call bswap2 (Mems[data], 1, Mems[data], 1,
+ (npix*(SZ_PIXEL*SZB_CHAR)))
+ }
+ $endif
+ $if (datatype == il)
+ if (and(swap, S_ALL) == S_ALL || and(swap, S_I2) == S_I4) {
+ if (SZ_INT != SZ_INT32) {
+ call ipak32 (Mem$t[data], Mem$t[data], npix)
+ call bswap4 (Mem$t[data], 1, Mem$t[data], 1,
+ (npix*(SZ_INT32*SZB_CHAR)))
+ } else {
+ call bswap4 (Mem$t[data], 1, Mem$t[data], 1,
+ (npix*(SZ_PIXEL*SZB_CHAR)))
+ }
+ }
+ $endif
+ $if (datatype == r)
+ if (and(swap, S_ALL) == S_ALL) {
+ call bswap4 (Mem$t[data], 1, Mem$t[data], 1,
+ (npix*(SZ_PIXEL*SZB_CHAR)))
+ }
+ $endif
+ $if (datatype == d)
+ if (and(swap, S_ALL) == S_ALL) {
+ call bswap8 (Mem$t[data], 1, Mem$t[data], 1,
+ (npix*(SZ_PIXEL*SZB_CHAR)))
+ }
+ $endif
+
+ $if (datatype == il)
+ call ip_lskip (fd, npix * (SZB_CHAR * SZ_INT32))
+ $else
+ call ip_lskip (fd, npix * (SZB_CHAR * SZ_PIXEL))
+ $endif
+ $endfor
+ }
+ IO_DATA(op) = data
+end
+
+
+# IP_WRLINE -- Write a line of pixels to the output image. We handle image
+# flipping here to avoid possibly doing it several times while the outbands
+# expression is being evaluated.
+
+procedure ip_wrline (ip, im, out, npix, line, band)
+
+pointer ip #i task struct pointer
+pointer im #i output image pointer
+pointer out #i output operand pointer
+int npix #i number of pixels to read
+int line #i image line number
+int band #i image band number
+
+int i, lnum, type
+int nldone, blnum
+pointer sp, dptr, data, optr
+bool lastline
+
+int and()
+pointer imps3s(), imps3i(), imps3l(), imps3r(), imps3d()
+pointer ip_chtype()
+
+data blnum /0/
+data nldone /1/
+data lastline /false/
+
+begin
+ call smark (sp)
+
+ # The first thing we do is change the datatype of the operand to
+ # match the output pixel type.
+ if (IP_OUTTYPE(ip) != NULL) {
+ if (IP_OUTTYPE(ip) == O_TYPE(out))
+ optr = O_VALP(out)
+ else
+ optr = ip_chtype (out, IP_OUTTYPE(ip))
+ }
+ type = IP_OUTTYPE(ip)
+
+ # See if we're flipping image in Y, and adjust the line number.
+ if (and(IP_FLIP(ip),FLIP_Y) == FLIP_Y) {
+ lnum = IP_AXLEN(ip,2) - line + 1
+ if (band == 1)
+ blnum = IP_SZBUF(ip) - mod (line-1, IP_SZBUF(ip))
+ lastline = (lnum == 1)
+ } else {
+ lnum = line
+ if (band == 1)
+ blnum = blnum + 1
+ lastline = (lnum == IP_AXLEN(ip,2))
+ }
+
+ # See if we're flipping image in x, and reverse the pixels.
+ if (and(IP_FLIP(ip),FLIP_X) == FLIP_X) {
+ call salloc (dptr, npix, type)
+ do i = 1, npix {
+ switch (type) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ Mems[dptr+i-1] = Mems[optr+(npix-i)]
+ $for (ilrd)
+ case TY_PIXEL:
+ Mem$t[dptr+i-1] = Mem$t[optr+(npix-i)]
+ $endfor
+ }
+ }
+ } else
+ dptr = optr
+
+ # Make sure the image pixtype is set.
+ if (IM_PIXTYPE(im) == NULL)
+ IM_PIXTYPE(im) = type
+
+ # Allocate the buffer pointer if needed.
+ if (BUFFER(ip,band) == NULL)
+ call calloc (BUFFER(ip,band), npix*IP_SZBUF(ip), IP_OUTTYPE(ip))
+
+ if (nldone < IP_SZBUF(ip) && !lastline) {
+ # Copy the image line to the buffer
+ data = BUFFER(ip,band)
+ switch (type) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ call amovs (Mems[dptr], Mems[data+((blnum-1)*npix)], npix)
+ $for (ilrd)
+ case TY_PIXEL:
+ call amov$t (Mem$t[dptr], Mem$t[data+((blnum-1)*npix)], npix)
+ $endfor
+ }
+ if (band == IP_NBANDS(ip))
+ nldone = nldone + 1
+
+ } else {
+ # Write the buffer to the image as a section.
+ data = BUFFER(ip,band)
+ switch (type) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ call amovs (Mems[dptr], Mems[data+((blnum-1)*npix)], npix)
+ if (and(IP_FLIP(ip),FLIP_Y) == FLIP_Y) {
+ data = imps3s (im, 1, npix,
+ max(1,(lnum-IP_SZBUF(ip)+1)+IP_SZBUF(ip)-1),
+ max(1,lnum+min(nldone,IP_SZBUF(ip))-1),
+ band, band)
+ call amovs (Mems[BUFFER(ip,band)+(blnum-1)*npix],
+ Mems[data], npix*(IP_SZBUF(ip)-blnum+1))
+ } else {
+ data = imps3s (im, 1, npix,
+ min(IP_AXLEN(ip,2),(lnum-blnum+1)),
+ min(IP_AXLEN(ip,2),lnum),
+ band, band)
+ call amovs (Mems[BUFFER(ip,band)], Mems[data], npix*blnum)
+ }
+ $for (ilrd)
+ case TY_PIXEL:
+ call amov$t (Mem$t[dptr], Mem$t[data+((blnum-1)*npix)], npix)
+ if (and(IP_FLIP(ip),FLIP_Y) == FLIP_Y) {
+ data = imps3$t (im, 1, npix,
+ max(1,(lnum-IP_SZBUF(ip)+1)+IP_SZBUF(ip)-1),
+ max(1,lnum+min(nldone,IP_SZBUF(ip))-1),
+ band, band)
+ call amov$t (Mem$t[BUFFER(ip,band)+(blnum-1)*npix],
+ Mem$t[data], npix*(IP_SZBUF(ip)-blnum+1))
+ } else {
+ data = imps3$t (im, 1, npix,
+ min(IP_AXLEN(ip,2),(lnum-blnum+1)),
+ min(IP_AXLEN(ip,2),lnum),
+ band, band)
+ call amov$t (Mem$t[BUFFER(ip,band)], Mem$t[data],
+ npix*blnum)
+ }
+ $endfor
+ }
+ if (band == IP_NBANDS(ip)) {
+ nldone = 1
+ blnum = 0
+ }
+ }
+
+ if (IP_OUTTYPE(ip) != O_TYPE(out))
+ call mfree (optr, type)
+ call sfree (sp)
+end
+
+
+# IP_UPKPIX -- Unpack a line of pixel-interleaved pixels to the separate
+# pixtype operand arrays.
+
+procedure ip_upkpix (ip, ptr, npix)
+
+pointer ip #i task struct pointer
+pointer ptr #i pointer to pixels
+int npix #i number of pixels in line
+
+pointer op[IM_MAXDIM]
+int i, j, np, optype[IM_MAXDIM]
+
+int ip_ptype()
+
+begin
+ np = IP_NPIXT(ip)
+ do j = 1, np {
+ op[j] = PTYPE(ip,j)
+ optype[j] = ip_ptype (IO_TYPE(op[j]),IO_NBYTES(op[j]))
+ }
+
+ do j = 1, np {
+
+ do i = 0, npix-1 {
+ switch (optype[j]) {
+ case TY_UBYTE, TY_USHORT, TY_SHORT:
+ Mems[IO_DATA(op[j])+i] = Mems[ptr+(i*np+j)-1]
+ $for (ilrd)
+ case TY_PIXEL:
+ Mem$t[IO_DATA(op[j])+i] = Mem$t[ptr+(i*np+j)-1]
+ $endfor
+ }
+ }
+ }
+end
+
+
+# IP_FIX_PIXTYPE -- Create the pixtype operands for 3-D band or line-
+# interleaved files. These weren't allocated at first since the pixtype
+# parameter or database field was atomic.
+
+procedure ip_fix_pixtype (ip)
+
+pointer ip #i task struct pointer
+
+pointer op, op1
+int i, nnp
+
+begin
+ if (DEBUG) {
+ call eprintf ("fix_pixtype: npixt=%d ndim=%d inter=%d\n")
+ call pargi(IP_NPIXT(ip)) ; call pargi(IP_NDIM(ip))
+ call pargi(IP_INTERLEAVE(ip)) ; call flush (STDERR)
+ }
+
+ # See if there's anything to be fixed.
+ if (IP_NDIM(ip) < 3 || IP_NDIM(ip) < IP_NPIXT(ip))
+ return
+ if (BAND_INTERLEAVED(ip) && (IP_NPIXT(ip) == IP_NDIM(ip)))
+ return
+ if (LINE_INTERLEAVED(ip) && (IP_NPIXT(ip) == IP_INTERLEAVE(ip)))
+ return
+
+ if (LINE_INTERLEAVED(ip))
+ nnp = IP_INTERLEAVE(ip)
+ else
+ #nnp = IP_NDIM(ip)
+ nnp = IP_AXLEN(ip,3)
+
+ # Make the new pixtype operands.
+ op1 = PTYPE(ip,1)
+ do i = 2, nnp {
+ call ip_alloc_operand (PTYPE(ip,i))
+ op = PTYPE(ip,i)
+ IO_TYPE(op) = IO_TYPE(op1)
+ IO_NBYTES(op) = IO_NBYTES(op1)
+ call sprintf (OP_TAG(op), SZ_TAG, "b%d")
+ call pargi (i)
+ }
+ IP_NPIXT(ip) = nnp
+
+ if (DEBUG) { call zzi_prstruct ("fix_pixtype", ip) }
+end
+
+
+# IP_FIX_OUTBANDS -- Create the outbands operands if none were specified in
+# the parameter file.
+
+procedure ip_fix_outbands (ip)
+
+pointer ip #i task struct pointer
+
+pointer sp, buf
+pointer im
+int i, nbands
+
+define SZ_OBSTR 2500
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_FNAME, TY_CHAR)
+
+ if (DEBUG) {
+ call eprintf ("fix_outbands: npixt=%d ndim=%d inter=%d\n")
+ call pargi(IP_NPIXT(ip)) ; call pargi(IP_NDIM(ip))
+ call pargi(IP_INTERLEAVE(ip)) ; call flush (STDERR)
+ }
+
+ # Free up the existing outbands operands.
+ nbands = IP_NBANDS(ip)
+ do i = 1, nbands
+ call ip_free_outbands (OBANDS(ip,i))
+
+ # Create an outbands parameter string according to the tags in the
+ # pixtype structure. This way we preserve any user-defined tags on
+ # output.
+ nbands = IP_NPIXT(ip)
+ call aclrc (Memc[buf], SZ_FNAME)
+ do i = 1, nbands {
+ call ip_alloc_outbands (OBANDS(ip,i))
+ call aclrc (Memc[buf], SZ_FNAME)
+ call sprintf (Memc[buf], SZ_FNAME, "b%d")
+ call pargi (i)
+ call strcpy (Memc[buf], O_EXPR(ip,i), SZ_EXPR)
+
+ # Load the operand struct.
+ call strcpy (Memc[buf], OP_TAG(O_OP(ip,i)), SZ_EXPR)
+ }
+ IP_NBANDS(ip) = nbands
+
+ # Fix the output image dimensions.
+ im = IP_IM(ip)
+ IM_LEN(im,3) = IP_AXLEN(ip,3)
+ if (IP_NBANDS(ip) > 1)
+ IM_NDIM(im) = 3
+ else
+ IM_NDIM(im) = IP_NDIM(ip)
+
+ call sfree (sp)
+
+ if (DEBUG) { call zzi_prstruct ("fix_outbands", ip) }
+end
+
+
+# IP_CHTYPE - Change the expression operand vector to the output datatype.
+# We allocate and return a pointer to the correct type to the converted
+# pixels, this pointer must be freed later on.
+
+pointer procedure ip_chtype (op, type)
+
+pointer op #i evvexpr operand pointer
+int type #i new type of pointer
+
+pointer out, coerce()
+
+begin
+ # Allocate the pointer and coerce it so the routine works.
+ if (type == TY_UBYTE || type == TY_CHAR)
+ call calloc (out, O_LEN(op), TY_CHAR)
+ else {
+ call calloc (out, O_LEN(op), type)
+ out = coerce (out, type, TY_CHAR)
+ }
+
+ # Change the pixel type.
+ switch (O_TYPE(op)) {
+ case TY_CHAR:
+ call achtc (Memc[O_VALP(op)], Memc[out], O_LEN(op), type)
+ case TY_SHORT:
+ call achts (Mems[O_VALP(op)], Memc[out], O_LEN(op), type)
+ case TY_INT:
+ call achti (Memi[O_VALP(op)], Memc[out], O_LEN(op), type)
+ case TY_LONG:
+ call achtl (Meml[O_VALP(op)], Memc[out], O_LEN(op), type)
+ case TY_REAL:
+ call achtr (Memr[O_VALP(op)], Memc[out], O_LEN(op), type)
+ case TY_DOUBLE:
+ call achtd (Memd[O_VALP(op)], Memc[out], O_LEN(op), type)
+ default:
+ call error (0, "Invalid output type requested.")
+ }
+
+ out = coerce (out, TY_CHAR, type)
+ return (out)
+end
+
+
+define NTYPES 6
+define NBITPIX 4
+
+# IP_PTYPE -- For a given pixtype parameter return the corresponding IRAF
+# data type.
+
+int procedure ip_ptype (type, nbytes)
+
+int type #i pixel type
+int nbytes #i number of bytes
+
+int i, pt, pb, ptype
+int tindex[NTYPES], bindex[NBITPIX], ttbl[NTYPES*NBITPIX]
+
+data tindex /PT_BYTE, PT_UINT, PT_INT, PT_IEEE, PT_NATIVE, PT_SKIP/
+data bindex /1, 2, 4, 8/
+
+data (ttbl(i), i= 1, 4) /TY_UBYTE, TY_USHORT, TY_INT, 0/ # B
+data (ttbl(i), i= 5, 8) /TY_UBYTE, TY_USHORT, 0, 0/ # U
+data (ttbl(i), i= 9,12) /TY_UBYTE, TY_SHORT, TY_INT, 0/ # I
+data (ttbl(i), i=13,16) / 0, 0, TY_REAL, TY_DOUBLE/ # R
+data (ttbl(i), i=17,20) / 0, 0, TY_REAL, TY_DOUBLE/ # N
+data (ttbl(i), i=21,24) /TY_UBYTE, TY_USHORT, TY_REAL, TY_DOUBLE/ # X
+
+begin
+ if (type == 0 || nbytes == 0) # uninitialized values
+ return (0)
+
+ pt = NTYPES
+ do i = 1, NTYPES {
+ if (tindex[i] == type)
+ pt = i
+ }
+ pb = NBITPIX
+ do i = 1, NBITPIX {
+ if (bindex[i] == nbytes)
+ pb = i
+ }
+
+ ptype = ttbl[(pt-1)*NBITPIX+pb]
+ if (ptype == 0)
+ call error (0, "Invalid pixtype specified.")
+ else
+ return (ptype)
+end
+
+
+# IP_PSTAT - Print information about the progress we're making.
+
+procedure ip_pstat (ip, row, percent)
+
+pointer ip #i task struct pointer
+int row #u current row
+int percent #u percent completed
+
+begin
+ # Print percent done if being verbose
+ if (row * 100 / IP_AXLEN(ip,2) >= percent + 10) {
+ percent = percent + 10
+ call eprintf (" Status: %2d%% complete\r")
+ call pargi (percent)
+ call flush (STDERR)
+ }
+end
diff --git a/pkg/dataio/import/mkpkg b/pkg/dataio/import/mkpkg
new file mode 100644
index 00000000..c12f77f6
--- /dev/null
+++ b/pkg/dataio/import/mkpkg
@@ -0,0 +1,37 @@
+# MKPKG file for the IMPORT task
+
+$call update
+$exit
+
+update:
+ $checkout libpkg.a ../
+ $update libpkg.a
+ $checkin libpkg.a ../
+ ;
+
+generic:
+ $set GEN = "$$generic -k"
+
+ $ifolder (generic/ipdb.x, ipdb.gx)
+ $(GEN) ipdb.gx -o generic/ipdb.x $endif
+ $ifolder (generic/ipfio.x, ipfio.gx)
+ $(GEN) ipfio.gx -o generic/ipfio.x $endif
+ $ifolder (generic/ipobands.x, ipobands.gx)
+ $(GEN) ipobands.gx -o generic/ipobands.x $endif
+ $ifolder (generic/ipproc.x, ipproc.gx)
+ $(GEN) ipproc.gx -o generic/ipproc.x $endif
+ ;
+
+libpkg.a:
+ $ifeq (USE_GENERIC, yes) $call generic $endif
+ @generic
+ @bltins
+
+ fmtdb.x import.h <ctotok.h> <error.h> <evvexpr.h> <fset.h>
+ ipbuiltin.x import.h
+ ipinfo.x import.h
+ iplistpix.x <imhdr.h> <error.h> <mwset.h>
+ ipmkhdr.x import.h <ctype.h> <imhdr.h>
+ t_import.x import.h <ctype.h> <error.h> <evvexpr.h> <imhdr.h>
+ zzidbg.x import.h <evvexpr.h>
+ ;
diff --git a/pkg/dataio/import/t_import.x b/pkg/dataio/import/t_import.x
new file mode 100644
index 00000000..adb37d17
--- /dev/null
+++ b/pkg/dataio/import/t_import.x
@@ -0,0 +1,768 @@
+include <error.h>
+include <ctype.h>
+include <evvexpr.h>
+include <imhdr.h>
+include "import.h"
+
+define DEBUG false
+
+
+# T_IMPORT -- Convert a generic binary raster file to an IRAF image. The
+# binary file is described either from the task parameters, or as an entry
+# in a database of known formats. Access to the database is either by
+# specifying the format explicitly, or by scanning the database and evaluating
+# an expression which identifies the format. Output is either in the form
+# of information about the file to be converted, a list of the file's pixels
+# or an IRAF image whose bands are computed from a list of expressions.
+
+procedure t_import ()
+
+pointer ip # task structure pointer
+int binfiles # binary files list pointer
+pointer imfiles # output image list pointer
+int fdb # format database descriptor
+int im # image pointer
+pointer sp, bfname, imname # local storage
+pointer format, output, fmt, idstr
+
+int clpopni(), clplen(), imtlen() # function definitions
+int clgfil(), open()
+int locpr(), imtgetim(), fdb_opendb()
+int ip_fcode(), ip_is_builtin()
+pointer imtopenp(), ip_init(), fdb_scan_records(), immap()
+
+extern ip_getop(), ip_dbfcn()
+errchk clpopni, clgfil, imtopenp, open, immap
+
+define done_ 99
+
+begin
+ call smark (sp) # local storage
+ call salloc (bfname, SZ_FNAME, TY_CHAR)
+ call salloc (imname, SZ_FNAME, TY_CHAR)
+ call salloc (format, SZ_FNAME, TY_CHAR)
+ call salloc (output, SZ_FNAME, TY_CHAR)
+ call salloc (fmt, SZ_FNAME, TY_CHAR)
+ call salloc (idstr, SZ_FNAME, TY_CHAR)
+
+ ip = ip_init () # allocate task struct pointer
+
+ call ieemapr (YES, YES) # enable IEEE NaN mapping
+ call ieemapd (YES, YES)
+
+ # Get file names and image lists.
+ binfiles = clpopni ("binfiles")
+ imfiles = imtopenp ("images")
+
+ # Get the format parameter.
+ call clgstr ("format", Memc[format], SZ_FNAME)
+ call ip_do_fmtpar (ip, Memc[format])
+
+ # Get task output parameters.
+ call ip_gout_pars (ip)
+
+ # See if the image lists match. If the lists are empty and we're
+ # asked for info, just dump the database and leave.
+ if (IP_OUTPUT(ip) != IP_INFO && IP_OUTPUT(ip) != IP_NONE) {
+ if (clplen(binfiles) != imtlen(imfiles) && imtlen(imfiles) != 0) {
+ # Clean up and print an error.
+ call clpcls (binfiles)
+ call imtclose (imfiles)
+ call sfree (sp)
+ call error (1, "Input and output lists not the same length.")
+ }
+ } else if (IP_OUTPUT(ip) == IP_INFO) {
+ if (clplen(binfiles) == 0 && imtlen(imfiles) == 0) {
+ fdb = fdb_opendb ()
+ call ip_list_formats (fdb)
+ call fdb_closedb (fdb)
+ goto done_
+ }
+ }
+
+ while (clgfil (binfiles, Memc[bfname], SZ_FNAME) != EOF) {
+ iferr (IP_FD(ip) = open (Memc[bfname], READ_ONLY, BINARY_FILE)) {
+ call eprintf ("Error opening file '%s'.\n")
+ call pargstr (Memc[bfname])
+ break
+ }
+
+ # Process the outbands parameter.
+ call ip_reset_outbands (ip)
+
+ if (IP_FORMAT(ip) == IP_SENSE) {
+ # Scan the database and get symtab pointer to format record.
+ fdb = fdb_opendb ()
+ call ip_lseek (fdb, BOF)
+ IP_FSYM(ip) = fdb_scan_records (fdb, "image_id",
+ locpr(ip_getop), ip, locpr(ip_dbfcn), ip)
+ if (IP_FSYM(ip) == NULL) {
+ # Try it byte-swapped.
+ IP_SWAP(ip) = S_ALL
+ call ip_lseek (fdb, BOF)
+ IP_FSYM(ip) = fdb_scan_records (fdb, "image_id",
+ locpr(ip_getop), ip, locpr(ip_dbfcn), ip)
+ IP_SWAP(ip) = NULL
+
+ if (IP_FSYM(ip) == NULL) {
+ if (IP_OUTPUT(ip) == IP_INFO) {
+ call printf ("%.19s%20tUnrecognized format\n")
+ call pargstr (Memc[bfname])
+ call fdb_closedb (fdb)
+ next
+ } else {
+ call printf (
+ "Unrecognized format. Known formats include:\n\n")
+ call ip_lseek (fdb, BOF)
+ call ip_list_formats (fdb)
+ call fdb_closedb (fdb)
+ break
+ }
+ }
+ }
+ call fdb_closedb (fdb)
+ }
+
+ # See if this is a 'builtin' format.
+ if (IP_FSYM(ip) != NULL) {
+ call fdbgstr (IP_FSYM(ip), "format", Memc[fmt], SZ_LINE)
+ call fdbgstr (IP_FSYM(ip), "id_string", Memc[idstr], SZ_LINE)
+ call fdb_strip_quote (Memc[idstr], Memc[idstr], SZ_LINE)
+ IP_BLTIN(ip) = ip_is_builtin (Memc[fmt])
+ IP_FCODE(ip) = ip_fcode (Memc[fmt])
+ } else
+ IP_BLTIN(ip) = NO
+
+
+ if (IP_FORMAT(ip) != IP_NONE) {
+ # Evaluate database expressions for this binary file.
+ call ip_eval_dbrec (ip)
+ }
+
+ if (IP_OUTPUT(ip) == IP_INFO) {
+ # Just print some information about the file.
+ call ip_info (ip, Memc[bfname], IP_VERBOSE(ip))
+
+ } else {
+ if (IP_OUTPUT(ip) != IP_NONE) {
+ # Get an output image name.
+ if (IP_OUTPUT(ip) == IP_IMAGE) {
+ if (imtgetim (imfiles, Memc[imname], SZ_FNAME) == EOF)
+ call error (1, "Short image list.")
+ } else if (IP_OUTPUT(ip) == IP_LIST) {
+ # Get a temporary image name.
+ call mktemp ("tmp$imp", Memc[imname], SZ_FNAME)
+ }
+
+ # Open the output image.
+ iferr (im = immap(Memc[imname], NEW_IMAGE, 0)) {
+ call erract (EA_WARN)
+ next
+ }
+ IP_IM(ip) = im
+
+ # Calculate the size of output image and number of bands.
+ IM_LEN(im,1) = IP_AXLEN(ip,1)
+ IM_LEN(im,2) = IP_AXLEN(ip,2)
+ IM_LEN(im,3) = IP_NBANDS(ip)
+ if (IP_NBANDS(ip) > 1)
+ IM_NDIM(im) = 3
+ else
+ IM_NDIM(im) = IP_NDIM(ip)
+ IM_PIXTYPE(im) = IP_OUTTYPE(ip)
+ }
+
+ if (IP_VERBOSE(ip) == YES && IP_OUTPUT(ip) != IP_LIST) {
+ # Print chatter about the conversion.
+ call printf ("%s -> %s\n ")
+ call pargstr (Memc[bfname])
+ call pargstr (Memc[imname])
+ call ip_info (ip, Memc[bfname], NO)
+ call ip_obinfo (ip, Memc[imname])
+ call flush (STDOUT)
+ }
+
+ if (IP_BLTIN(ip) == YES) {
+ call ip_prbuiltin (ip, Memc[bfname])
+ } else {
+ # This is it, process the binary file.
+ if (BAND_INTERLEAVED(ip))
+ # Input file is band interleaved.
+ call ip_prband (ip, IP_FD(ip), IP_IM(ip), NULL)
+ else if (LINE_INTERLEAVED(ip))
+ # Input file is line interleaved.
+ call ip_prline (ip, IP_FD(ip), IP_IM(ip), NULL)
+ else if (PIXEL_INTERLEAVED(ip))
+ # Input file is pixel interleaved.
+ call ip_prpix (ip, IP_FD(ip), IP_IM(ip), NULL)
+ else
+ call error (0, "Unrecognized pixel storage.")
+
+ if (IP_VERBOSE(ip) == YES) {
+ call eprintf (" Status: Done \n")
+ call flush (STDERR)
+ }
+ }
+
+
+ if (IP_IMHEADER(ip) != NULL && IP_OUTPUT(ip) != IP_NONE)
+ # Copy header info to new image (can contain wcs info)
+ call ip_mkheader (IP_IM(ip), Memc[IP_IMHEADER(ip)])
+
+ if (IP_OUTPUT(ip) == IP_LIST) {
+ # List the image pixels band by band.
+ call ip_listpix (IP_IM(ip))
+ call imdelete (Memc[imname])
+ }
+
+ if (IP_IM(ip) != NULL)
+ call imunmap (IP_IM(ip)) # close the output image
+ }
+
+ call close (IP_FD(ip))
+ if (IP_FORMAT(ip) == IP_SENSE)
+ call fdb_close (IP_FSYM(ip)) # free format pointer
+ }
+
+ # Free task structure ptr and clean up.
+ call fdb_close (IP_FSYM(ip))
+done_ call ip_free (ip)
+ call clpcls (binfiles)
+ call imtclose (imfiles)
+ call sfree (sp)
+end
+
+
+# IP_INIT -- Initialize the task structure pointers.
+
+pointer procedure ip_init ()
+
+pointer ptr
+
+begin
+ # Allocate task structure pointer.
+ iferr (call calloc (ptr, SZ_IMPSTRUCT, TY_STRUCT))
+ call error (0, "Error allocating IMPORT task structure.")
+
+ # Allocate the pixtype, outbands, and buffer struct pointers.
+ call calloc (IP_PIXTYPE(ptr), MAX_OPERANDS, TY_POINTER)
+ call calloc (IP_OUTBANDS(ptr), MAX_OPERANDS, TY_POINTER)
+ call calloc (IP_BUFPTR(ptr), MAX_OPERANDS, TY_POINTER)
+
+ # Initialize some parameters
+ IP_IM(ptr) = NULL
+ IP_FD(ptr) = NULL
+ IP_OFFSET(ptr) = 1
+ IP_FLIP(ptr) = FLIP_NONE
+
+ return (ptr)
+end
+
+
+# IP_FREE -- Free the task structure pointers.
+
+procedure ip_free (ip)
+
+pointer ip #i task struct pointer
+
+int i
+
+begin
+ # Free pixtype pointers.
+ for (i=1; i < IP_NPIXT(ip); i=i+1)
+ call mfree (PTYPE(ip,i), TY_STRUCT)
+ call mfree (IP_PIXTYPE(ip), TY_POINTER)
+
+ # Free outbands pointers.
+ for (i=1; i < MAX_OPERANDS; i=i+1)
+ call mfree (OBANDS(ip,i), TY_STRUCT)
+ call mfree (IP_OUTBANDS(ip), TY_POINTER)
+
+ # Free buffer pointers.
+ call mfree (IP_BUFPTR(ip), TY_POINTER)
+
+ if (IP_COMPTR(ip) != NULL)
+ call mfree (IP_COMPTR(ip), TY_CHAR)
+ call mfree (ip, TY_STRUCT)
+end
+
+
+# IP_GIN_PARS -- Get the task input file parameters.
+
+procedure ip_gin_pars (ip)
+
+pointer ip #i task struct pointer
+
+pointer sp, dims, bswap, pixtype
+
+int clgeti()
+
+begin
+ call smark (sp)
+ call salloc (dims, SZ_FNAME, TY_CHAR)
+ call salloc (bswap, SZ_FNAME, TY_CHAR)
+ call salloc (pixtype, SZ_FNAME, TY_CHAR)
+
+ # Get the storage parameters.
+ IP_HSKIP(ip) = clgeti ("hskip")
+ IP_TSKIP(ip) = clgeti ("tskip")
+ IP_BSKIP(ip) = clgeti ("bskip")
+ IP_LSKIP(ip) = clgeti ("lskip")
+ IP_LPAD(ip) = clgeti ("lpad")
+
+ # Process the dims parameter.
+ call aclrc (Memc[dims], SZ_FNAME)
+ call clgstr ("dims", Memc[dims], SZ_FNAME)
+ call ip_do_dims (ip, Memc[dims])
+
+ # Process the bswap parameter.
+ call aclrc (Memc[bswap], SZ_FNAME)
+ call clgstr ("bswap", Memc[bswap], SZ_FNAME)
+ call ip_do_bswap (ip, Memc[bswap])
+
+ # Process the pixtype parameter.
+ call aclrc (Memc[pixtype], SZ_FNAME)
+ call clgstr ("pixtype", Memc[pixtype], SZ_FNAME)
+ call ip_do_pixtype (ip, Memc[pixtype])
+
+ if (IP_NPIXT(ip) > 1)
+ IP_INTERLEAVE(ip) = 0 # composite pixtype, ignore interleave
+ else
+ IP_INTERLEAVE(ip) = clgeti ("interleave")
+
+ # Do a little sanity checking.
+ if (IP_NPIXT(ip) > 1 && IP_NDIM(ip) > IP_NPIXT(ip))
+ call error (1,
+ "Image dimensions don't match `pixtype' specification.")
+ if (IP_NPIXT(ip) == 1 && IP_NDIM(ip) > 2 && (IP_INTERLEAVE(ip) != 0 &&
+ IP_INTERLEAVE(ip) != IP_AXLEN(ip,3)))
+ call error (1,
+ "Dimensions don't match `pixtype' and `interleave' params.")
+
+ if (DEBUG) { call zzi_prstruct ("init inpars", ip) }
+ call sfree (sp)
+end
+
+
+# IP_GOUT_PARS -- Get the task output file parameters.
+
+procedure ip_gout_pars (ip)
+
+pointer ip #i task struct pointer
+
+pointer sp, out, otype, obands, imhead
+int btoi(), clgeti()
+bool clgetb(), streq()
+
+begin
+ call smark (sp)
+ call salloc (out, SZ_FNAME, TY_CHAR)
+ call salloc (otype, SZ_FNAME, TY_CHAR)
+ call salloc (obands, SZ_FNAME, TY_CHAR)
+ call salloc (imhead, SZ_FNAME, TY_CHAR)
+
+ # Get the type of output to do.
+ call aclrc (Memc[out], SZ_FNAME)
+ call clgstr ("output", Memc[out], SZ_FNAME)
+ switch (Memc[out]) {
+ case 'i':
+ if (Memc[out+1] == 'n') # info
+ IP_OUTPUT(ip) = IP_INFO
+ else if (Memc[out+1] == 'm') # image
+ IP_OUTPUT(ip) = IP_IMAGE
+ case 'l': # list
+ IP_OUTPUT(ip) = IP_LIST
+ case 'n': # none, no
+ IP_OUTPUT(ip) = IP_NONE
+ default:
+ call error (2, "Unrecognized output type in 'output'.")
+ }
+
+ # Get the output image type.
+ call aclrc (Memc[otype], SZ_FNAME)
+ call clgstr ("outtype", Memc[otype], SZ_FNAME)
+ switch (Memc[otype]) {
+ case 'u':
+ IP_OUTTYPE(ip) = TY_USHORT
+ case 's':
+ IP_OUTTYPE(ip) = TY_SHORT
+ case 'i':
+ IP_OUTTYPE(ip) = TY_INT
+ case 'l':
+ IP_OUTTYPE(ip) = TY_LONG
+ case 'r':
+ IP_OUTTYPE(ip) = TY_REAL
+ case 'd':
+ IP_OUTTYPE(ip) = TY_DOUBLE
+ default:
+ IP_OUTTYPE(ip) = NULL
+ call error (2, "Unrecognized output image type in 'outtype'.")
+ }
+
+ # Process the outbands parameter.
+ #call ip_reset_outbands (ip)
+
+ # Get optional image header info file name.
+ call aclrc (Memc[imhead], SZ_FNAME)
+ call clgstr ("imheader", Memc[imhead], SZ_FNAME)
+ if (streq (Memc[imhead],"")) {
+ IP_IMHEADER(ip) = NULL
+ } else {
+ call calloc (IP_IMHEADER(ip), SZ_FNAME, TY_CHAR)
+ call strcpy (Memc[imhead], Memc[IP_IMHEADER(ip)], SZ_FNAME)
+ }
+ IP_VERBOSE(ip) = btoi (clgetb("verbose"))
+ IP_SZBUF(ip) = clgeti ("buffer_size")
+
+ if (DEBUG) { call zzi_prstruct ("init outpars", ip) }
+ call sfree (sp)
+end
+
+
+# IP_RESET_OUTBANDS - Initialize the 'outbands' parameter structure to the
+# default values.
+
+procedure ip_reset_outbands (ip)
+
+pointer ip #i task struct pointer
+
+pointer sp, obands
+int i
+
+begin
+ if (IP_OUTPUT(ip) == IP_INFO)
+ return
+
+ call smark (sp)
+ call salloc (obands, SZ_FNAME, TY_CHAR)
+
+ do i = 1, IP_NBANDS(ip)
+ call ip_free_outbands (OBANDS(ip,i))
+
+ # Process the outbands parameter.
+ call aclrc (Memc[obands], SZ_FNAME)
+ call clgstr ("outbands", Memc[obands], SZ_FNAME)
+ call ip_do_outbands (ip, Memc[obands])
+
+ call sfree (sp)
+end
+
+
+# IP_DO_BSWAP -- Read the byte-swap string an load the ip structure.
+
+procedure ip_do_bswap (ip, bswap)
+
+pointer ip #i task struct pointer
+char bswap[ARB] #i byte swap string
+
+char ch, flag[SZ_FNAME]
+int sp, i
+
+int strdic()
+
+begin
+ if (DEBUG) { call eprintf("swap='%s'\n");call pargstr (bswap) }
+
+ sp = 1
+ IP_SWAP(ip) = NULL
+ while (bswap[sp] != EOS) {
+ i = 1
+ for (ch=bswap[sp]; ch != EOS && ch != ','; ch=bswap[sp]) {
+ flag[i] = ch
+ i = i + 1
+ sp = sp + 1
+ }
+ flag[i] = EOS
+ if (DEBUG) { call eprintf("\tflag='%s'\n");call pargstr (flag) }
+
+ switch (strdic (flag, flag, SZ_FNAME, SWAP_STR)) {
+ case 1, 2:
+ IP_SWAP(ip) = or (IP_SWAP(ip), S_NONE)
+ case 3:
+ IP_SWAP(ip) = or (IP_SWAP(ip), S_ALL)
+ case 4:
+ IP_SWAP(ip) = or (IP_SWAP(ip), S_I2)
+ case 5:
+ IP_SWAP(ip) = or (IP_SWAP(ip), S_I4)
+ default:
+ break
+ }
+ }
+end
+
+
+# IP_DO_DIMS -- Parse the 'dims' parameter to get number of axes and dimensions.
+
+procedure ip_do_dims (ip, dims)
+
+pointer ip #i task struct pointer
+char dims[ARB] #i dimension string
+
+char ch
+int sp, ndim, npix
+int ctoi()
+
+begin
+ if (DEBUG) { call eprintf("dims='%s'\n");call pargstr (dims) }
+
+ ndim = 0
+ for (sp=1; ctoi(dims[1],sp,npix) > 0; ) {
+ ndim = ndim + 1
+ IP_AXLEN(ip,ndim) = npix
+ for (ch=dims[sp]; IS_WHITE(ch) || ch == ','; ch=dims[sp])
+ sp = sp + 1
+ }
+ if (ndim == 1)
+ IP_AXLEN(ip,2) = 1
+ IP_NDIM(ip) = ndim
+end
+
+
+# IP_DO_FMTPAR -- Given the format parameter, figure out what to do with it.
+
+procedure ip_do_fmtpar (ip, format)
+
+pointer ip #i task struct pointer
+char format[ARB] #i format string
+
+pointer fsym
+int fd
+
+int fdb_opendb()
+pointer fdb_get_rec()
+bool streq()
+
+begin
+ if (DEBUG) { call eprintf("format='%s'\n");call pargstr(format) }
+
+ IP_FSYM(ip) = NULL
+ if (streq(format,"none")) {
+ # Get the task input parameters.
+ IP_FORMAT(ip) = IP_NONE
+ call ip_gin_pars (ip)
+
+ } else if (streq(format,"sense")) {
+ # Set a flag and figure it out from the database later.
+ IP_FORMAT(ip) = IP_SENSE
+
+ } else {
+ # Get a pointer to a symtab entry for the requested format
+ IP_FORMAT(ip) = IP_NAME
+ fd = fdb_opendb ()
+ fsym = fdb_get_rec (fd, format)
+ call fdb_closedb (fd)
+ if (fsym == NULL) {
+ call error (2,"Requested format not found in the database.")
+ } else
+ IP_FSYM(ip) = fsym
+ }
+end
+
+
+# IP_DO_PIXTYPE -- Process the pixtype parameter
+
+procedure ip_do_pixtype (ip, pixtype)
+
+pointer ip #i task struct pointer
+char pixtype[ARB] #i pixtype string
+
+int i, pp, npix, nbytes
+pointer op
+
+int ctoi()
+
+begin
+ if (DEBUG) { call eprintf("pixtype=:%s:\n");call pargstr(pixtype) }
+
+ # Check for a bonehead user.
+ if (pixtype[2] == EOS || pixtype[2] == ',') {
+ call error (0, "Invalid `pixtype' parameter: no size given")
+ }
+
+ pp = 1
+ npix = 0
+ nbytes = ERR
+ repeat {
+ npix = npix + 1
+
+ call ip_alloc_operand (PTYPE(ip,npix))
+ op = PTYPE(ip,npix)
+
+ # Get pixel type.
+ switch (pixtype[pp]) {
+ case 'b':
+ IO_TYPE(op) = PT_BYTE
+ case 'u':
+ IO_TYPE(op) = PT_UINT
+ case 'i':
+ IO_TYPE(op) = PT_INT
+ case 'r':
+ IO_TYPE(op) = PT_IEEE
+ case 'n':
+ IO_TYPE(op) = PT_NATIVE
+ case 'x':
+ IO_TYPE(op) = PT_SKIP
+ }
+ pp = pp + 1
+
+ # Get the number of bytes.
+ i = ctoi (pixtype, pp, IO_NBYTES(op))
+
+ # Force equivalence of 'b1' and 'u1' pixtypes.
+ if (IO_TYPE(op) == PT_UINT && IO_NBYTES(op) == 1)
+ IO_TYPE(op) = PT_BYTE
+
+ # Get a tag name or create one.
+ if (pixtype[pp] == ',' || pixtype[pp] == EOS) { # no tag given
+ call sprintf (OP_TAG(op), SZ_TAG, "b%d")
+ call pargi (npix)
+ if (pixtype[pp] != EOS)
+ pp = pp + 1
+ } else if (pixtype[pp] == ':') { # get the tag
+ pp = pp + 1
+ for (i=1; (pixtype[pp] != ',' && pixtype[pp] != EOS) ; i=i+1) {
+ Memc[IO_TAG(op)+i-1] = pixtype[pp]
+ pp = pp + 1
+ }
+ pp = pp + 1
+ }
+
+ # Make sure all of the pixtypes are the same datatype.
+ if (nbytes != ERR) {
+ if (nbytes != IO_NBYTES(op))
+ call error (0, "Pixtypes must all be the same size")
+ } else
+ nbytes = IO_NBYTES(op)
+
+ if (DEBUG) { call zzi_prop (op) }
+
+ } until (pixtype[pp] == EOS)
+ IP_NPIXT(ip) = npix
+end
+
+
+# IP_DO_OUTBANDS -- Get the outbands parameter and break it up into a list
+# of individual expressions.
+
+procedure ip_do_outbands (ip, outbands)
+
+pointer ip #i task struct pointer
+char outbands[ARB] #i outbands string
+
+pointer sp, buf
+int i, op, nbands, level
+
+int strsearch()
+
+begin
+ # If there is no outbands parameter specified, warn the user, we'll
+ # make something up later.
+ IP_USE_CMAP(ip) = YES
+ if (outbands[1] == EOS && IP_OUTPUT(ip) != IP_INFO) {
+ call eprintf ("Warning: No 'outbands' parameter specified: ")
+ call eprintf ("Converting all pixels.\n")
+ IP_NBANDS(ip) = ERR
+ return
+ }
+
+ call smark (sp)
+ call salloc (buf, SZ_EXPR, TY_CHAR)
+ call aclrc (Memc[buf], SZ_EXPR)
+
+ if (DEBUG) { call eprintf("outbands='%s'\n");call pargstr(outbands) }
+
+ op = 1
+ nbands = 0
+ while (outbands[op] != EOS) {
+ level = 0
+ nbands = nbands + 1
+ # Copy expr up to the delimiting comma into a buffer.
+ call aclrc (Memc[buf], SZ_EXPR)
+ for (i=0; i < SZ_EXPR; i = i + 1) {
+ if (outbands[op] == '(') {
+ level = level + 1
+ Memc[buf+i] = outbands[op]
+ } else if (outbands[op] == ')') {
+ level = level - 1
+ Memc[buf+i] = outbands[op]
+ } else if ((outbands[op] == ',' && level == 0) ||
+ outbands[op] == EOS) {
+ Memc[buf+i] = EOS
+ op = op + 1
+ break
+ } else if (! IS_WHITE(outbands[op]))
+ Memc[buf+i] = outbands[op]
+ op = op + 1
+ }
+
+ if (Memc[buf] != EOS) {
+ # Save expression to main outbands structure.
+ call ip_alloc_outbands (OBANDS(ip,nbands))
+ call strcpy (Memc[buf], O_EXPR(ip,nbands), SZ_EXPR)
+
+ if (strsearch(Memc[buf], "red") > 0 ||
+ strsearch(Memc[buf], "green") > 0 ||
+ strsearch(Memc[buf], "blue") > 0)
+ IP_USE_CMAP(ip) = NO
+
+ # Load the operand struct.
+ call strcpy (Memc[buf], OP_TAG(O_OP(ip,nbands)), SZ_EXPR)
+
+ if (DEBUG) { call zzi_proband (ip, nbands) }
+ }
+ }
+ IP_NBANDS(ip) = nbands
+ IP_AXLEN(ip,3) = nbands
+
+ call sfree (sp)
+end
+
+
+# IP_ALLOC_OUTBANDS -- Allocate an outbands structure.
+
+procedure ip_alloc_outbands (op)
+
+pointer op #i outbands struct pointer
+
+begin
+ call calloc (op, LEN_OUTBANDS, TY_STRUCT)
+ call calloc (OB_EXPR(op), SZ_EXPR, TY_CHAR)
+ call ip_alloc_operand (OB_OP(op))
+end
+
+
+# IP_FREE_OUTBANDS -- Free an outbands structure.
+
+procedure ip_free_outbands (op)
+
+pointer op #i outbands struct pointer
+
+begin
+ call ip_free_operand (OB_OP(op))
+ call mfree (OB_EXPR(op), TY_CHAR)
+ call mfree (op, TY_STRUCT)
+end
+
+
+# IP_ALLOC_OPERAND -- Allocate an operand structure.
+
+procedure ip_alloc_operand (op)
+
+pointer op #i operand struct pointer
+
+begin
+ call calloc (op, LEN_OPERAND, TY_STRUCT)
+ call calloc (IO_TAG(op), SZ_FNAME, TY_CHAR)
+end
+
+
+# IP_FREE_OPERAND -- Free an operand structure.
+
+procedure ip_free_operand (op)
+
+pointer op #i operand struct pointer
+
+begin
+ call mfree (IO_TAG(op), TY_CHAR)
+ call mfree (op, TY_STRUCT)
+end
diff --git a/pkg/dataio/import/zzidbg.x b/pkg/dataio/import/zzidbg.x
new file mode 100644
index 00000000..25c58778
--- /dev/null
+++ b/pkg/dataio/import/zzidbg.x
@@ -0,0 +1,145 @@
+include <evvexpr.h>
+include "import.h"
+
+procedure zzi_prstruct (whence, ip)
+
+char whence[SZ_FNAME]
+pointer ip
+int i
+
+begin
+ call eprintf ("%s:\n") ; call pargstr (whence)
+ call eprintf ("\tformat=%s interleave=%d bswap=%s\n")
+ switch (IP_FORMAT(ip)) {
+ case IP_NONE: call pargstr ("IP_NONE")
+ case IP_SENSE: call pargstr ("IP_SENSE")
+ case IP_NAME: call pargstr ("IP_NAME")
+ case IP_BUILTIN: call pargstr ("IP_BUILTIN")
+ default: call pargstr ("ERR")
+ }
+ call pargi (IP_INTERLEAVE(ip))
+ switch(IP_SWAP(ip)) {
+ case S_NONE: call pargstr ("S_NONE")
+ case S_ALL: call pargstr ("S_ALL")
+ case S_I2: call pargstr ("S_I2")
+ case S_I4: call pargstr ("S_I4")
+ default: call pargstr ("ERR")
+ }
+ call eprintf ("\thskip=%d tskip=%d bskip=%d lskip=%d lpad=%d\n")
+ call pargi (IP_HSKIP(ip))
+ call pargi (IP_TSKIP(ip))
+ call pargi (IP_BSKIP(ip))
+ call pargi (IP_LSKIP(ip))
+ call pargi (IP_LPAD(ip))
+ call eprintf ("\tndim=%s dims=(%d,%d,%d,%d,%d,%d,%d)\n")
+ call pargi (IP_NDIM(ip))
+ do i = 1, 7
+ call pargi (IP_AXLEN(ip,i))
+
+ call eprintf ("\toutput=%s outtype=%s imheader='%s' verbose=%d\n")
+ switch(IP_OUTPUT(ip)) {
+ case IP_NONE: call pargstr ("IP_NONE")
+ case IP_IMAGE: call pargstr ("IP_IMAGE")
+ case IP_LIST: call pargstr ("IP_LIST")
+ case IP_INFO: call pargstr ("IP_INFO")
+ default: call pargstr ("ERR")
+ }
+ switch(IP_OUTTYPE(ip)) {
+ case TY_SHORT: call pargstr ("TY_SHORT")
+ case TY_INT: call pargstr ("TY_INT")
+ case TY_LONG: call pargstr ("TY_LONG")
+ case TY_REAL: call pargstr ("TY_REAL")
+ case TY_DOUBLE: call pargstr ("TY_DOUBLE")
+ default: call pargstr ("ERR")
+ }
+ if (IP_IMHEADER(ip) == NULL)
+ call pargstr ("")
+ else
+ call pargstr (Memc[IP_IMHEADER(ip)])
+ call pargi (IP_VERBOSE(ip))
+ call eprintf ("\tpixtype:\n")
+ do i = 1, IP_NPIXT(ip) {
+ call eprintf ("\t ")
+ call zzi_prop (PTYPE(ip,i))
+ }
+ call eprintf ("\toutbands:\n")
+ do i = 1, IP_NBANDS(IP) {
+ call eprintf ("\t ")
+ call zzi_proband (ip, i)
+ }
+ call flush (STDERR)
+end
+
+
+procedure zzi_proband (ip,band)
+
+pointer ip
+int band
+
+begin
+ call eprintf ("ob=%d expr='%s' op->")
+ call pargi (OBANDS(ip,band))
+ call pargstr (O_EXPR(ip,band))
+ call zzi_prop (O_OP(ip,band))
+end
+
+
+procedure zzi_prop (o)
+
+pointer o
+char buf[8]
+int type, ip_ptype()
+
+begin
+ call sprintf (buf, 8, " buirnx")
+ type = ip_ptype(IO_TYPE(o), IO_NBYTES(o))
+ call eprintf ("(o=%d expr='%s' tag='%s' (t='%c' N=%d=>%s) Np=%d %d)\n")
+ call pargi (o)
+ call pargstr (Memc[OB_EXPR(o)])
+ call pargstr (OP_TAG(o))
+ call pargc (buf[IO_TYPE(o)+1])
+ call pargi (IO_NBYTES(o))
+ switch (type) {
+ case TY_UBYTE: call pargstr ("TY_UBYTE")
+ case TY_USHORT: call pargstr ("TY_USHORT")
+ case TY_SHORT: call pargstr ("TY_SHORT")
+ case TY_INT: call pargstr ("TY_INT")
+ case TY_LONG: call pargstr ("TY_LONG")
+ case TY_REAL: call pargstr ("TY_REAL")
+ case TY_DOUBLE: call pargstr ("TY_DOUBLE")
+ default: call pargstr ("ERR")
+ }
+ call pargi (IO_NPIX(o))
+ call pargi (IO_DATA(o))
+ call flush (STDERR)
+end
+
+
+procedure zzi_pevop (o)
+
+pointer o
+
+begin
+ call eprintf ("o=%d type=%d len=%d flags=%d ")
+ call pargi (o)
+ call pargi (O_TYPE(o))
+ call pargi (O_LEN(o))
+ call pargi (O_FLAGS(o))
+ switch (O_TYPE(o)) {
+ case TY_CHAR:
+ call eprintf ("val='%s'\n") ; call pargstr (O_VALC(o))
+ case TY_SHORT:
+ call eprintf ("val=%d\n") ; call pargs (O_VALS(o))
+ case TY_INT:
+ call eprintf ("val=%d\n") ; call pargi (O_VALI(o))
+ case TY_LONG:
+ call eprintf ("val=%d\n") ; call pargl (O_VALL(o))
+ case TY_REAL:
+ call eprintf ("val=%g\n") ; call pargr (O_VALR(o))
+ case TY_DOUBLE:
+ call eprintf ("val=%g\n") ; call pargd (O_VALD(o))
+ default:
+ call eprintf ("ptr=%d\n") ; call pargi (O_VALP(o))
+ }
+ call flush (STDERR)
+end
diff --git a/pkg/dataio/imtext/imtext.h b/pkg/dataio/imtext/imtext.h
new file mode 100644
index 00000000..76506eda
--- /dev/null
+++ b/pkg/dataio/imtext/imtext.h
@@ -0,0 +1,21 @@
+# Definitions used for conversions between text files and IRAF images.
+# Both tasks rtextimage and wtextimage include this file.
+
+define LEN_WT (2+20+20)
+
+define IRAFTYPE Memc[P2C($1)]
+define FORM Memc[P2C($1+20)]
+
+define UNSET 0 # Flag for unitialized header values
+define INT_FORM 1 # Text file pixels written as integers
+define FP_FORM 2 # Text file pixels written as floating point
+define CPX_FORM 3 # Text file pixels written as complex
+
+define COL_VALUE 11 # Starting column for FITS keyword values
+define LEN_CARD 80
+define SZ_STRING 20
+define MAX_LENTEXT (2*SZ_LINE)
+define NFITS_LINES 10
+define NCARDS_FITS_BLK 36
+define LEN_STRING 18
+define LEN_KEYWORD 8
diff --git a/pkg/dataio/imtext/mkpkg b/pkg/dataio/imtext/mkpkg
new file mode 100644
index 00000000..8cabe34c
--- /dev/null
+++ b/pkg/dataio/imtext/mkpkg
@@ -0,0 +1,19 @@
+# The image to text file conversion program WTEXTIMAGE makes the following
+# contributions to the dataio package library:
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ putcplx.x <imhdr.h> <mach.h>
+ putint.x <imhdr.h> <mach.h> <ctype.h>
+ putreal.x <imhdr.h> <mach.h>
+ wti_wheader.x imtext.h <imhdr.h> <mach.h> <imio.h>
+ t_wtextimage.x imtext.h <imhdr.h> <mach.h> <ctype.h> <fset.h> <error.h>
+ rt_rheader.x imtext.h <imhdr.h> <imio.h>
+ rt_cvtpix.x imtext.h <imhdr.h>
+ rt_rwpix.x imtext.h <imhdr.h> <ctype.h>
+ t_rtextimage.x imtext.h <imhdr.h> <error.h>
+ ;
diff --git a/pkg/dataio/imtext/putcplx.x b/pkg/dataio/imtext/putcplx.x
new file mode 100644
index 00000000..df498479
--- /dev/null
+++ b/pkg/dataio/imtext/putcplx.x
@@ -0,0 +1,88 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <mach.h>
+
+# WTI_PUTCOMPLEX -- Output pixels to a text file in complex floating format.
+# Pixels are output in storage order for images of any dimension (leftmost
+# subscript varying fastest). We do not bother to implement a different
+# datapath for each image pixel datatype because the execution time is
+# entirely dominated by the binary to character conversion, and because we
+# need type complex pixels for XTOC anyhow.
+
+procedure wti_putcomplex (im, tx, maxll, decpl, fmtchar, width)
+
+pointer im # pointer to image file
+int tx # file descriptor of output text file
+int maxll # maximum length of output text line
+int decpl # number of decimal places of precision
+int fmtchar # format character (efg)
+int width # field width of each number (0=free format)
+
+char numbuf[MAX_DIGITS]
+int npix, ip, j, ndigits, nspaces, maxch
+pointer sp, obuf, op, pix, cp
+long v[IM_MAXDIM]
+int imgnlx(), xtoc()
+errchk imgnlx, putline
+
+begin
+ call smark (sp)
+ call salloc (obuf, maxll+1, TY_CHAR)
+
+ call amovkl (long(1), v, IM_MAXDIM)
+ npix = IM_LEN(im,1)
+ op = obuf
+
+ while (imgnlx (im, pix, v) != EOF) {
+ do j = 1, npix {
+ # Encode the number.
+ if (width <= 0)
+ maxch = MAX_DIGITS
+ else
+ maxch = width
+
+ ndigits = xtoc (Memx[pix+j-1], numbuf, MAX_DIGITS,
+ decpl, fmtchar, maxch)
+
+ # Determine the number of spaces needed to right justify the
+ # field. If the field width is zero the output is free format
+ # and we always output a single space.
+
+ if (width <= 0)
+ nspaces = 1
+ else
+ nspaces = width - ndigits
+
+ # Break the output line if insufficient space remains on the
+ # line.
+
+ if (op-obuf + ndigits + nspaces > maxll) {
+ Memc[op] = '\n'
+ Memc[op+1] = EOS
+ call putline (tx, Memc[obuf])
+ op = obuf
+ }
+
+ # Append sufficient blanks to right justify the number in
+ # the given field.
+ do cp = op, op + nspaces - 1
+ Memc[cp] = ' '
+ op = op + nspaces
+
+ # Append the number to the output line.
+ do ip = 1, ndigits
+ Memc[op+ip-1] = numbuf[ip]
+ op = op + ndigits
+ }
+ }
+
+ # Break the last line if there is anything on it.
+ if (op > obuf) {
+ Memc[op] = '\n'
+ Memc[op+1] = EOS
+ call putline (tx, Memc[obuf])
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/dataio/imtext/putint.x b/pkg/dataio/imtext/putint.x
new file mode 100644
index 00000000..a98d3fb5
--- /dev/null
+++ b/pkg/dataio/imtext/putint.x
@@ -0,0 +1,160 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <mach.h>
+include <ctype.h>
+
+# WTI_PUTINT -- Output pixels to a text file in integer format. Pixels are
+# output in storage order for images of any dimension (leftmost subscript
+# varying fastest).
+
+procedure wti_putint (im, tx, maxll, width)
+
+pointer im # pointer to image file
+int tx # file descriptor of output text file
+int maxll # maximum length of output text line
+int width # field width of each number (0=free format)
+
+char numbuf[MAX_DIGITS]
+int npix, ip, j, ndigits
+pointer sp, obuf, op, pix
+long v[IM_MAXDIM]
+int imgnll(), ltoc()
+errchk imgnll, putline
+
+begin
+ call smark (sp)
+ call salloc (obuf, maxll+1, TY_CHAR)
+
+ call amovkl (long(1), v, IM_MAXDIM)
+ npix = IM_LEN(im,1)
+ op = obuf
+
+ if (width <= 0) {
+ # If the encoding is free format call LTOC to encode the number,
+ # compute the number of spaces required to right justify the
+ # numeric string in the specified field width, then move the
+ # spaces and the number into the output line.
+
+ while (imgnll (im, pix, v) != EOF) {
+ do j = 1, npix {
+ # Encode the number.
+ ndigits = ltoc (Meml[pix+j-1], numbuf, MAX_DIGITS)
+
+ # Break output line if insufficient space remains.
+ if (op-obuf + ndigits + 1 > maxll) {
+ Memc[op] = '\n'
+ Memc[op+1] = EOS
+ call putline (tx, Memc[obuf])
+ op = obuf
+ }
+
+ # Append a blank and the number to the output line.
+ if (op > obuf) {
+ Memc[op] = ' '
+ op = op + 1
+ }
+ do ip = 1, ndigits
+ Memc[op+ip-1] = numbuf[ip]
+ op = op + ndigits
+ }
+ }
+
+ } else {
+ # Fixed format. Encode the integer number from right to left
+ # in the given field, blank filling at the left. Note that
+ # fancy formats such as left justify or zero fill are not
+ # presently supported (and are probably not worth it here).
+
+ while (imgnll (im, pix, v) != EOF) {
+ do j = 1, npix {
+ # Break output line if insufficient space remains.
+ if (op-obuf + width > maxll) {
+ Memc[op] = '\n'
+ Memc[op+1] = EOS
+ call putline (tx, Memc[obuf])
+ op = obuf
+ }
+
+ # Encode the number in the output field.
+ call wti_encode_l (Meml[pix+j-1], Memc[op], width)
+ op = op + width
+ }
+ }
+ }
+
+ # Break the last line if there is anything on it.
+ if (op > obuf) {
+ Memc[op] = '\n'
+ Memc[op+1] = EOS
+ call putline (tx, Memc[obuf])
+ }
+
+ call sfree (sp)
+end
+
+
+# WTI_ENCODE_L -- Encode a long integer number as a decimal integer, right
+# justified with blank fill in the indicated field. Since we know the field
+# width in advance we can encode the number from right to left (least
+# significant digits first), without having to reverse the digits and copy
+# the string as is the case with LTOC.
+procedure wti_encode_l (lval, out, w)
+
+long lval # number to be encoded
+char out[w] # output field (NOT EOS DELIMITED)
+int w # field width
+
+bool neg
+int op, i
+long val, quotient
+define overflow_ 91
+
+begin
+ if (IS_INDEFL (lval)) {
+ if (w < 5)
+ goto overflow_
+ call amovc ("INDEF", out[w-4], 5)
+ op = w - 5
+
+ } else {
+ neg = (lval < 0)
+ if (neg)
+ val = -lval
+ else
+ val = lval
+
+ # Output digits from right to left.
+ do i = w, 1, -1 {
+ quotient = val / 10
+ out[i] = TO_DIGIT (val - quotient * 10)
+ val = quotient
+ if (val == 0) {
+ op = i - 1
+ break
+ }
+ }
+
+ # Add minus sign if negative.
+ if (neg) {
+ if (op > 0)
+ out[op] = '-'
+ op = op - 1
+ }
+
+ # Check for overflow.
+ if (op < 0 || val > 0)
+ goto overflow_
+ }
+
+ # Blank fill at left.
+ do i = op, 1, -1
+ out[i] = ' '
+
+ return
+
+overflow_
+ # Number was too large to fit in the given field width.
+ do i = 1, w
+ out[i] = '*'
+end
diff --git a/pkg/dataio/imtext/putreal.x b/pkg/dataio/imtext/putreal.x
new file mode 100644
index 00000000..217a45aa
--- /dev/null
+++ b/pkg/dataio/imtext/putreal.x
@@ -0,0 +1,88 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <mach.h>
+
+# WTI_PUTREAL -- Output pixels to a text file in a floating point format.
+# Pixels are output in storage order for images of any dimension (leftmost
+# subscript varying fastest). We do not bother to implement a different
+# datapath for each image pixel datatype because the execution time is
+# entirely dominated by the binary to character conversion, and because we
+# need type double pixels for DTOC anyhow.
+
+procedure wti_putreal (im, tx, maxll, decpl, fmtchar, width)
+
+pointer im # pointer to image file
+int tx # file descriptor of output text file
+int maxll # maximum length of output text line
+int decpl # number of decimal places of precision
+int fmtchar # type of encoding (efg)
+int width # field width of each number (0=free format)
+
+char numbuf[MAX_DIGITS]
+int npix, ip, j, ndigits, nspaces, maxch
+pointer sp, obuf, op, pix, cp
+long v[IM_MAXDIM]
+int imgnld(), dtoc()
+errchk imgnld, putline
+
+begin
+ call smark (sp)
+ call salloc (obuf, maxll+1, TY_CHAR)
+
+ call amovkl (long(1), v, IM_MAXDIM)
+ npix = IM_LEN(im,1)
+ op = obuf
+
+ while (imgnld (im, pix, v) != EOF) {
+ do j = 1, npix {
+ # Encode the number.
+ if (width <= 0)
+ maxch = MAX_DIGITS
+ else
+ maxch = width
+
+ ndigits = dtoc (Memd[pix+j-1], numbuf, MAX_DIGITS,
+ decpl, fmtchar, maxch)
+
+ # Determine the number of spaces needed to right justify the
+ # field. If the field width is zero the output is free format
+ # and we always output a single space.
+
+ if (width <= 0)
+ nspaces = 1
+ else
+ nspaces = width - ndigits
+
+ # Break the output line if insufficient space remains on the
+ # line.
+
+ if (op-obuf + ndigits + nspaces > maxll) {
+ Memc[op] = '\n'
+ Memc[op+1] = EOS
+ call putline (tx, Memc[obuf])
+ op = obuf
+ }
+
+ # Append sufficient blanks to right justify the number in
+ # the given field.
+ do cp = op, op + nspaces - 1
+ Memc[cp] = ' '
+ op = op + nspaces
+
+ # Append the number to the output line.
+ do ip = 1, ndigits
+ Memc[op+ip-1] = numbuf[ip]
+ op = op + ndigits
+ }
+ }
+
+ # Break the last line if there is anything on it.
+ if (op > obuf) {
+ Memc[op] = '\n'
+ Memc[op+1] = EOS
+ call putline (tx, Memc[obuf])
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/dataio/imtext/rt_cvtpix.x b/pkg/dataio/imtext/rt_cvtpix.x
new file mode 100644
index 00000000..170a26d4
--- /dev/null
+++ b/pkg/dataio/imtext/rt_cvtpix.x
@@ -0,0 +1,115 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include "imtext.h"
+
+# RT_CONVERT_PIXELS -- Called once for each text file to be converted. All
+# pixels in the text file are converted to image pixels.
+
+procedure rt_convert_pixels (tf, im, format, pixels)
+
+int tf # File descriptor of input text file
+pointer im # Pointer to image header
+int format # Format of text pixels (integer/floating point)
+int pixels # Get pixels from input text file?
+
+pointer bufptr, sp, word1, pattern
+int stat, nlines, npix, i
+long v[IM_MAXDIM], start
+int impnll(), impnld(), impnlx()
+int fscan(), stridxs(), patmatch(), patmake()
+long note()
+
+errchk impnll, impnld, impnlx
+errchk rt_get_lineptr, rt_output_line, fscan, seek, amovkl
+
+begin
+ # Determine if text file pixels were written with an integer, complex
+ # or floating point format. This information may have been already
+ # determined from the header. If not, the first pixel is read
+ # from text file. If it contains a decimal point, the character E,
+ # or a + or - sign not in the first position, it is a floating point
+ # number. Complex numbers are assumed to be written as "(r,i)".
+
+ if (pixels == YES && format == UNSET) {
+ call smark (sp)
+ call salloc (word1, SZ_LINE, TY_CHAR)
+ call salloc (pattern, SZ_LINE, TY_CHAR)
+
+ # Note position so we can return to it
+ start = note (tf)
+
+ stat = fscan (tf)
+ call gargwrd (Memc[word1], SZ_LINE)
+ if (patmake ("[DdEe]", Memc[pattern], SZ_LINE) == ERR)
+ call error (7, "Error creating format pattern")
+
+ if (stridxs ("(", Memc[word1]) > 0)
+ format = CPX_FORM
+ else if (stridxs (".", Memc[word1]) > 0)
+ format = FP_FORM
+ else if (patmatch (Memc[word1], Memc[pattern]) > 0)
+ format = FP_FORM
+ else if (stridxs ("+", Memc[word1]) > 1)
+ format = FP_FORM
+ else if (stridxs ("-", Memc[word1]) > 1)
+ format = FP_FORM
+ else
+ format = INT_FORM
+
+ call sfree (sp)
+ call seek (tf, start)
+ }
+
+ # Pixel type may not have been set by this point either...
+ if (IM_PIXTYPE(im) == UNSET) {
+ switch (format) {
+ case FP_FORM:
+ IM_PIXTYPE(im) = TY_REAL
+ case INT_FORM:
+ IM_PIXTYPE(im) = TY_INT
+ case CPX_FORM:
+ IM_PIXTYPE(im) = TY_COMPLEX
+ default:
+ call error (0, "Unrecognized format type")
+ }
+ }
+
+ nlines = 1
+ do i = 2, IM_NDIM(im)
+ nlines = nlines * IM_LEN (im, i)
+ call amovkl (long(1), v, IM_MAXDIM)
+ npix = IM_LEN (im, 1)
+
+ # Initialize text buffer
+ call rt_rinit
+
+ switch (IM_PIXTYPE(im)) {
+ case TY_SHORT, TY_INT, TY_USHORT, TY_LONG:
+ do i = 1, nlines {
+ stat = impnll (im, bufptr, v)
+ if (pixels == YES)
+ call rt_output_linel (tf, format, bufptr, npix)
+ else
+ call aclrl (Meml[bufptr], npix)
+ }
+ case TY_REAL, TY_DOUBLE:
+ do i = 1, nlines {
+ stat = impnld (im, bufptr, v)
+ if (pixels == YES)
+ call rt_output_lined (tf, format, bufptr, npix)
+ else
+ call aclrd (Memd[bufptr], npix)
+ }
+ case TY_COMPLEX:
+ do i = 1, nlines {
+ stat = impnlx (im, bufptr, v)
+ if (pixels == YES)
+ call rt_output_linex (tf, format, bufptr, npix)
+ else
+ call aclrx (Memx[bufptr], npix)
+ }
+ default:
+ call error (0, "Image pixel type unset")
+ }
+end
diff --git a/pkg/dataio/imtext/rt_rheader.x b/pkg/dataio/imtext/rt_rheader.x
new file mode 100644
index 00000000..9c4323bf
--- /dev/null
+++ b/pkg/dataio/imtext/rt_rheader.x
@@ -0,0 +1,170 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <imio.h>
+include "imtext.h"
+
+# RT_RHEADER -- read FITS header, saving the image dimension information in
+# the image header. The format (integer/floating point) is returned.
+
+procedure rt_rheader (tf, im, format)
+
+int tf # File descriptor for input text file
+pointer im # Pointer to image header
+int format # Format of text file pixels (integer/floating point)
+
+pointer sp, wt, card
+bool streq()
+int ncard, fd_user, max_lenuser
+int getline(), rt_decode_card(), stridxs(), strlen(), stropen()
+errchk getline, rt_decode_card
+
+begin
+ call smark (sp)
+ call salloc (wt, LEN_WT, TY_STRUCT)
+ call salloc (card, LEN_CARD+1, TY_CHAR)
+
+ Memc[card+LEN_CARD] = '\n'
+ Memc[card+LEN_CARD+1] = EOS
+
+ # Prepare user area string to be written
+ max_lenuser = (LEN_IMDES + IM_LENHDRMEM(im) - IMU) * SZ_STRUCT - 1
+ fd_user = stropen (Memc[IM_USERAREA(im)], max_lenuser, NEW_FILE)
+
+ ncard = 1
+ repeat {
+ if (getline (tf, Memc[card]) == EOF)
+ call error (2, "RT_RHEADER: EOF encountered before END card")
+
+ ncard = ncard + 1
+ if (rt_decode_card (wt, im, fd_user, Memc[card]) == YES)
+ break
+ }
+
+ # Encountered END card; examine a few header keyword values. From
+ # the FORMAT keyword, determine if the pixel values are written as
+ # integers, floating point numbers or complex numbers.
+
+ if (strlen (FORM(wt)) > 0) {
+ if (stridxs ("I", FORM(wt)) > 0)
+ format = INT_FORM
+ else if (stridxs ("(", FORM(wt)) > 0)
+ format = CPX_FORM
+ else
+ format = FP_FORM
+ } else
+ format = UNSET
+
+ # The image pixel type is set by the IRAFTYPE keyword value.
+
+ if (streq (IRAFTYPE(wt), "SHORT INTEGER"))
+ IM_PIXTYPE (im) = TY_SHORT
+ else if (streq (IRAFTYPE(wt), "UNSIGNED SHORT INT"))
+ IM_PIXTYPE (im) = TY_USHORT
+ else if (streq (IRAFTYPE(wt), "INTEGER"))
+ IM_PIXTYPE (im) = TY_INT
+ else if (streq (IRAFTYPE(wt), "LONG INTEGER"))
+ IM_PIXTYPE (im) = TY_LONG
+ else if (streq (IRAFTYPE(wt), "REAL FLOATING"))
+ IM_PIXTYPE (im) = TY_REAL
+ else if (streq (IRAFTYPE(wt), "DOUBLE FLOATING"))
+ IM_PIXTYPE (im) = TY_DOUBLE
+ else if (streq (IRAFTYPE(wt), "COMPLEX"))
+ IM_PIXTYPE (im) = TY_COMPLEX
+
+ call close (fd_user)
+ call sfree (sp)
+end
+
+
+# RT_DECODE_CARD -- Decode a FITS format card and return YES when the END
+# card is encountered. The decoded value is stored in the image header,
+# or in the user area if there is no other place for it. The END card is
+# tested only to the first three characters; strictly speaking the END
+# card begins with the 8 characters "END ".
+
+int procedure rt_decode_card (wt, im, fd, card)
+
+pointer wt # Pointer to wtextimage keyword structure
+pointer im # Pointer to image header being written
+int fd # File descriptor of user area
+char card[ARB] # Card image read from FITS header
+
+int nchar, ival, i, j, k, ndim
+
+int strmatch(), ctoi()
+errchk rt_get_fits_string, putline, putline
+
+begin
+
+ i = COL_VALUE
+ if (strmatch (card, "^END") > 0)
+ return (YES)
+
+ else if (strmatch (card, "^NAXIS ") > 0) {
+ nchar = ctoi (card, i, ndim)
+ if (ndim > 0)
+ IM_NDIM(im) = ndim
+
+ } else if (strmatch (card, "^NAXIS") > 0) {
+ k = strmatch (card, "^NAXIS")
+ nchar = ctoi (card, k, j)
+ nchar = ctoi (card, i, IM_LEN(im,j))
+
+ } else if (strmatch (card, "^NDIM ") > 0)
+ nchar = ctoi (card, i, IM_NDIM(im))
+
+ else if (strmatch (card, "^LEN") > 0) {
+ k = strmatch (card, "^LEN")
+ nchar = ctoi (card, k, j)
+ nchar = ctoi (card, i, IM_LEN(im,j))
+
+ } else if (strmatch (card, "^BITPIX ") > 0) {
+ nchar = ctoi (card, i, ival)
+ if (ival != 8)
+ call error (6, "Not 8-bit ASCII characters")
+
+ } else if (strmatch (card, "^FORMAT ") > 0) {
+ call rt_get_fits_string (card, FORM(wt), SZ_STRING)
+ } else if (strmatch (card, "^IRAFTYPE") > 0) {
+ call rt_get_fits_string (card, IRAFTYPE(wt), SZ_STRING)
+ } else if (strmatch (card, "^OBJECT ") > 0) {
+ call rt_get_fits_string (card, IM_TITLE(im), SZ_IMTITLE)
+ } else {
+ # Putline returns an error if there is no room in the user area
+ iferr (call putline (fd, card)) {
+ call eprintf ("Space in user area has been exceeded\n")
+ return (YES)
+ }
+ }
+
+ return (NO)
+end
+
+
+# RT_GET_FITS_STRING -- Extract a string from a FITS card and trim trailing
+# blanks. The EOS is marked by either ', /, or the end of the card.
+# There may be an optional opening ' (FITS standard).
+
+procedure rt_get_fits_string (card, str, maxchar)
+
+char card[ARB] # Input card image containing keyword and value
+char str[maxchar] # Output string
+int maxchar # Maximum number of characters output
+int j, istart, nchar
+
+begin
+ # Check for opening quote
+ if (card[COL_VALUE] == '\'')
+ istart = COL_VALUE + 1
+ else
+ istart = COL_VALUE
+
+ for (j=istart; (j < LEN_CARD) && (card[j] != '\''); j=j+1)
+ ;
+ for (j=j-1; (j >= istart) && (card[j] == ' '); j=j-1)
+ ;
+
+ nchar = min (maxchar, j - istart + 1)
+ call strcpy (card[istart], str, nchar)
+end
diff --git a/pkg/dataio/imtext/rt_rwpix.x b/pkg/dataio/imtext/rt_rwpix.x
new file mode 100644
index 00000000..a3ba26bf
--- /dev/null
+++ b/pkg/dataio/imtext/rt_rwpix.x
@@ -0,0 +1,271 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <ctype.h>
+include "imtext.h"
+
+# RT_RINIT -- Initialize buffer and buffer pointer for reading text.
+
+procedure rt_rinit ()
+
+int ip
+char text_buf[SZ_LINE]
+common /rpix_init/ ip, text_buf
+
+begin
+ ip = 1
+ text_buf[1] = EOS
+end
+
+
+# RT_OUTPUT_LINEL -- Put line of long pixels to image from text file.
+
+procedure rt_output_linel (tf, format, bufptr, npix)
+
+int tf # File descriptor for input text file
+int format # Format of pixels in text file (integer/ floating)
+pointer bufptr # Pointer to image line to be filled
+int npix # Number of pixels per image line
+
+pointer sp, dbl_buf, cplx_buf
+errchk rt_ripixels, rt_rfpixels, rt_rcpixels
+
+begin
+ call smark (sp)
+
+ switch (format) {
+ case INT_FORM:
+ call salloc (dbl_buf, npix, TY_DOUBLE)
+ call rt_ripixels (tf, Memd[dbl_buf], npix)
+ call achtdl (Memd[dbl_buf], Meml[bufptr], npix)
+ case FP_FORM:
+ call salloc (dbl_buf, npix, TY_DOUBLE)
+ call rt_rfpixels (tf, Memd[dbl_buf], npix)
+ call achtdl (Memd[dbl_buf], Meml[bufptr], npix)
+ case CPX_FORM:
+ call salloc (cplx_buf, npix, TY_COMPLEX)
+ call rt_rcpixels (tf, Memx[cplx_buf], npix)
+ call achtxl (Memx[cplx_buf], Meml[bufptr], npix)
+ }
+
+ call sfree (sp)
+end
+
+
+# RT_OUTPUT_LINED -- Put line of double pixels to image from text file.
+
+procedure rt_output_lined (tf, format, bufptr, npix)
+
+int tf # File descriptor for input text file
+int format # Format of pixels in text file (integer/ floating)
+pointer bufptr # Pointer to image line to be filled
+int npix # Number of pixels per image line
+
+pointer sp, cplx_buf
+errchk rt_ripixels, rt_rfpixels, rt_rcpixels
+
+begin
+ call smark (sp)
+
+ switch (format) {
+ case INT_FORM:
+ call rt_ripixels (tf, Memd[bufptr], npix)
+ case FP_FORM:
+ call rt_rfpixels (tf, Memd[bufptr], npix)
+ case CPX_FORM:
+ call salloc (cplx_buf, npix, TY_COMPLEX)
+ call rt_rcpixels (tf, Memx[cplx_buf], npix)
+ call achtxd (Memx[cplx_buf], Memd[bufptr], npix)
+ }
+
+ call sfree (sp)
+end
+
+
+# RT_OUTPUT_LINEX -- Put line of complex pixels to image from text file.
+
+procedure rt_output_linex (tf, format, bufptr, npix)
+
+int tf # File descriptor for input text file
+int format # Format of pixels in text file (integer/ floating)
+pointer bufptr # Pointer to image line to be filled
+int npix # Number of pixels per image line
+
+pointer sp, dbl_buf
+errchk rt_ripixels, rt_rfpixels, rt_rcpixels
+
+begin
+ call smark (sp)
+
+ switch (format) {
+ case INT_FORM:
+ call salloc (dbl_buf, npix, TY_DOUBLE)
+ call rt_ripixels (tf, Memd[dbl_buf], npix)
+ call achtdx (Memd[dbl_buf], Memx[bufptr], npix)
+ case FP_FORM:
+ call salloc (dbl_buf, npix, TY_DOUBLE)
+ call rt_rfpixels (tf, Memd[dbl_buf], npix)
+ call achtdx (Memd[dbl_buf], Memx[bufptr], npix)
+ case CPX_FORM:
+ call rt_rcpixels (tf, Memx[bufptr], npix)
+ }
+
+ call sfree (sp)
+end
+
+
+# RT_RIPIXELS -- read integer pixels free format from text file into a
+# type double real buffer.
+
+procedure rt_ripixels (tf, dbl_out, npix)
+
+int tf # File descriptor for input text file
+double dbl_out[ARB] # Output pixel array
+int npix # Number of pixels to output
+
+bool neg
+int i, sum, ip_start, ip
+char text_buf[SZ_LINE]
+common /rpix_init/ ip, text_buf
+int getline()
+errchk getline
+
+begin
+ # Read values until satisfied
+ for (i=0; i < npix; ) {
+ sum = 0
+
+ # Position to first non white space character
+ while (IS_WHITE (text_buf[ip]))
+ ip = ip + 1
+ ip_start = ip
+
+ neg = (text_buf[ip] == '-')
+ if (neg)
+ ip = ip + 1
+
+ while (IS_DIGIT (text_buf[ip])) {
+ sum = sum * 10 + TO_INTEG (text_buf[ip])
+ ip = ip + 1
+ }
+
+ if (ip == ip_start) {
+ if (getline (tf, text_buf) == EOF) {
+ call eprintf ("Premature EOF seen by rt_ripixels\n")
+ break
+ }
+ ip = 1
+
+ } else {
+ i = i + 1
+ if (neg)
+ dbl_out[i] = double (-sum)
+ else
+ dbl_out[i] = double ( sum)
+ }
+ }
+end
+
+
+# RT_RFPIXELS -- read floating point pixels free format from text file into a
+# double floating point buffer.
+
+procedure rt_rfpixels (tf, dbl_out, npix)
+
+int tf # File descriptor for text file
+double dbl_out[npix] # Output pixel buffer
+int npix # Number of pixels to output
+
+int i, nchars
+double dval
+int gctod(), getline()
+
+int ip
+char text_buf[SZ_LINE]
+common /rpix_init/ ip, text_buf
+errchk gctod, getline
+
+begin
+ # Read values until satisfied
+ for (i=0; i < npix; ) {
+ nchars = gctod (text_buf, ip, dval)
+
+ if (nchars == 0) {
+ if (getline (tf, text_buf) == EOF) {
+ call eprintf ("Premature EOF seen in rt_rfpixels\n")
+ break
+ }
+ ip = 1
+
+ } else {
+ i = i + 1
+ dbl_out[i] = dval
+ }
+ }
+end
+
+
+# RT_RCPIXELS -- read complex pixels free format from text file into a
+# complex floating point buffer.
+
+procedure rt_rcpixels (tf, cplx_out, npix)
+
+int tf # File descriptor for text file
+complex cplx_out[npix] # Output pixel buffer
+int npix # Number of pixels to output
+
+int i, nchars
+complex xval
+int gctox(), getline()
+
+int ip
+char text_buf[SZ_LINE]
+common /rpix_init/ ip, text_buf
+errchk gctox, getline
+
+begin
+ # Read values until satisfied
+ for (i=0; i < npix; ) {
+ nchars = gctox (text_buf, ip, xval)
+
+ if (nchars == 0) {
+ if (getline (tf, text_buf) == EOF) {
+ call eprintf ("Premature EOF seen in rt_rcpixels\n")
+ break
+ }
+ ip = 1
+
+ } else {
+ i = i + 1
+ cplx_out[i] = xval
+ }
+ }
+end
+
+
+# RT_SKIP_LINES -- Skip lines of text file.
+
+int procedure rt_skip_lines (tf, nskip)
+
+int tf # File descriptor of text file
+int nskip # Number of lines to skip
+
+pointer sp, buffer
+int i
+int fscan()
+
+begin
+ call smark (sp)
+ call salloc (buffer, SZ_LINE, TY_CHAR)
+
+ for (i = 1; i <= nskip; i = i + 1) {
+ if (fscan (tf) == EOF) {
+ call sfree (sp)
+ return (EOF)
+ } else
+ call gargstr (Memc[buffer], SZ_LINE)
+ }
+
+ call sfree (sp)
+ return (OK)
+end
diff --git a/pkg/dataio/imtext/t_rtextimage.x b/pkg/dataio/imtext/t_rtextimage.x
new file mode 100644
index 00000000..603e9134
--- /dev/null
+++ b/pkg/dataio/imtext/t_rtextimage.x
@@ -0,0 +1,109 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <error.h>
+include "imtext.h"
+
+# T_RTEXTIMAGE -- Read text files into IRAF images. Information
+# about the dimensionality of the image (the number of dimensions and the
+# length of each dimension) must either be read from a FITS header or supplied
+# by the user.
+
+procedure t_rtextimage ()
+
+char output[SZ_FNAME], text_file[SZ_FNAME], temp[SZ_FNAME]
+char out_fname[SZ_FNAME]
+pointer im
+int header, pixels, nskip, nfiles, ntext, format, data_type, tf, i, input
+int fd_dim, junk, ndim, ip
+
+bool clgetb()
+#char clgetc()
+pointer immap()
+int btoi(), clgeti(), clpopni(), clplen(), clgfil(), get_data_type()
+int open(), rt_skip_lines(), clpopnu(), ctoi()
+
+begin
+ # Determine the input and output file names
+ input = clpopni ("input")
+ call clgstr ("output", output, SZ_FNAME)
+
+ # Get hidden parameters from cl.
+ # data_type = get_data_type (clgetc ("otype"))
+ call clgstr ("otype", out_fname, SZ_FNAME)
+ data_type = get_data_type (out_fname[1])
+ header = btoi (clgetb ("header"))
+ pixels = btoi (clgetb ("pixels"))
+ if (header == NO)
+ nskip = clgeti ("nskip")
+
+ # Loop over the input files, generating an output name and processing.
+ nfiles = clplen (input)
+ do ntext = 1, nfiles {
+ if (clgfil (input, text_file, SZ_FNAME) == EOF)
+ return
+ tf = open (text_file, READ_ONLY, TEXT_FILE)
+ if (nfiles > 1) {
+ call sprintf (out_fname, SZ_FNAME, "%s.%03d")
+ call pargstr (output)
+ call pargi (ntext)
+ } else
+ call strcpy (output, out_fname, SZ_FNAME)
+
+ im = immap (out_fname, NEW_IMAGE, 0)
+
+ # Initialize those values that could be read from the header.
+ format = UNSET
+ IM_NDIM(im) = UNSET
+ IM_PIXTYPE(im) = UNSET
+
+ if (header == YES) {
+ iferr (call rt_rheader (tf, im, format))
+ call erract (EA_FATAL)
+ } else if (nskip > 0) {
+ if (rt_skip_lines (tf, nskip) == EOF)
+ call error (1, "Unexpected EOF when skipping lines")
+ }
+
+ # Get data_type of output image. If supplied by user, use parameter
+ # value over anything read from FITS header.
+
+ if (IM_PIXTYPE(im) == UNSET) {
+ # Not read from header, use parameter value if supplied.
+ # Otherwise, wait until pixels are read to set pixel type.
+ if (data_type == ERR)
+ IM_PIXTYPE(im) = UNSET
+ else
+ IM_PIXTYPE(im) = data_type
+ } else if (data_type != ERR)
+ # Available in header, but user has specified value to be used
+ IM_PIXTYPE(im) = data_type
+
+ # If image dimension information wasn't read from header, the user
+ # must supply it.
+
+ if (IM_NDIM(im) == UNSET) {
+ fd_dim = clpopnu ("dim")
+ ndim = clplen (fd_dim)
+ do i = 1, ndim {
+ junk = clgfil (fd_dim, temp, SZ_FNAME)
+ ip = 1
+ junk = ctoi (temp, ip, IM_LEN (im, i))
+ }
+ IM_NDIM(im) = ndim
+ call clpcls (fd_dim)
+ }
+
+ # Convert text pixels to image pixels, posting only a warning
+ # message if an error occurs. Processing continues to the next
+ # file in the input list.
+
+ iferr (call rt_convert_pixels (tf, im, format, pixels))
+ call erract (EA_WARN)
+
+ call imunmap (im)
+ call close (tf)
+ }
+
+ call clpcls (input)
+end
diff --git a/pkg/dataio/imtext/t_wtextimage.x b/pkg/dataio/imtext/t_wtextimage.x
new file mode 100644
index 00000000..8860f3d6
--- /dev/null
+++ b/pkg/dataio/imtext/t_wtextimage.x
@@ -0,0 +1,261 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include <fset.h>
+include <error.h>
+include <mach.h>
+include <imhdr.h>
+include "imtext.h"
+
+define SZ_FORMAT 20
+
+
+# WTEXTIMAGE -- Write a text file from an IRAF image. Image header information
+# is written in the "keyword = value / comment" format of FITS. Pixel values
+# follow the header. The resulting text file can be read as a FITS image. The
+# header cards include "NAXIS = 0", indicating no binary data matrix is written.
+# The encoded pixel values can be read as special records following the null
+# data matrix.
+
+procedure t_wtextimage ()
+
+bool header
+bool pixels
+pointer im
+char output[SZ_FNAME], format[SZ_FORMAT], imlist[SZ_LINE]
+char image[SZ_FNAME], out_fname[SZ_FNAME]
+int maxll, file_num, out, input, nfiles
+
+pointer immap()
+bool clgetb(), strne()
+int clgeti(), imtgetim(), open(), imtopen(), fstati(), imtlen()
+
+begin
+ # Open template of input image filenames.
+ call clgstr ("input", imlist, SZ_LINE)
+ input = imtopen (imlist)
+ nfiles = imtlen (input)
+
+ # See if STDOUT has been redirected and get output filename.
+ if (fstati (STDOUT, F_REDIR) == YES) {
+ # Output has been redirected, set output filename to STDOUT
+ call strcpy ("STDOUT", output, SZ_FNAME)
+ } else {
+ # Get output filename from cl
+ call clgstr ("output", output, SZ_FNAME)
+ }
+
+ # Get other parameters from cl.
+ header = clgetb ("header")
+ pixels = clgetb ("pixels")
+ maxll = min (MAX_LENTEXT, clgeti ("maxlinelen"))
+ if (maxll <= 0)
+ call error (1, "Illegal maximum line length: must be > 0")
+
+ call clgstr ("format", format, SZ_FORMAT)
+ call strlwr (format)
+
+ file_num = 0
+
+ while (imtgetim (input, image, SZ_FNAME) != EOF) {
+ file_num = file_num + 1
+
+ # Open image.
+ iferr (im = immap (image, READ_ONLY, 0)) {
+ call erract (EA_WARN)
+ next
+ }
+
+ if (nfiles > 1 && strne (output, "STDOUT")) {
+ # Generate unique output file name
+ call sprintf (out_fname, SZ_FNAME, "%s.%03d")
+ call pargstr (output)
+ call pargi (file_num)
+ } else
+ call strcpy (output, out_fname, SZ_FNAME)
+
+ # Open output file.
+ iferr (out = open (out_fname, APPEND, TEXT_FILE)) {
+ call imunmap (im)
+ call erract (EA_WARN)
+ next
+ }
+
+ iferr (call wti_convert_image (im,image,out,header,pixels,
+ maxll,format))
+ call erract (EA_WARN)
+
+ call imunmap (im)
+ call close (out)
+ }
+
+ call imtclose (input)
+end
+
+
+# WTI_CONVERT_IMAGE -- called once for each image to be converted. This
+# procedure determines the output pixel format and then directs the processing
+# depending on user request.
+
+procedure wti_convert_image (im, image, out, header, pixels, maxll, user_format)
+
+pointer im # input image
+char image[ARB] # image name
+int out # output text file descriptor
+bool header # convert header information (y/n)?
+bool pixels # convert pixels (y/n)?
+int maxll # maximum line length of text file
+char user_format[ARB] # output format for single pixel entered by user
+
+int width, decpl, fmtchar
+pointer sp, out_format, ftn_format, spp_format, ep
+errchk wti_determine_fmt, wti_write_header
+errchk wti_putint, wti_putreal, wti_putcomplex
+
+begin
+ call smark (sp)
+ call salloc (out_format, SZ_FORMAT, TY_CHAR)
+ call salloc (spp_format, SZ_FORMAT, TY_CHAR)
+ call salloc (ftn_format, SZ_FORMAT, TY_CHAR)
+ call salloc (ep, SZ_LINE, TY_CHAR)
+
+ # Clear the format variables.
+ call aclrc (Memc[out_format], SZ_FORMAT)
+ call aclrc (Memc[spp_format], SZ_FORMAT)
+ call aclrc (Memc[ftn_format], SZ_FORMAT)
+ call aclrc (Memc[ep], SZ_LINE)
+ fmtchar = ' '
+
+ # Determine the output format.
+
+ if (user_format[1] == EOS) {
+ # Format has not been set by user. Set appropriate defaults.
+ switch (IM_PIXTYPE(im)) {
+ case TY_USHORT:
+ call strcpy ("6d", Memc[spp_format], SZ_FORMAT)
+ case TY_SHORT:
+ call strcpy ("7d", Memc[spp_format], SZ_FORMAT)
+ case TY_INT:
+ call strcpy ("12d", Memc[spp_format], SZ_FORMAT)
+ case TY_LONG:
+ call strcpy ("12d", Memc[spp_format], SZ_FORMAT)
+ case TY_REAL:
+ call strcpy ("14.7g", Memc[spp_format], SZ_FORMAT)
+ case TY_DOUBLE:
+ call strcpy ("22.15g", Memc[spp_format], SZ_FORMAT)
+ case TY_COMPLEX:
+ call strcpy ("21.7z", Memc[spp_format], SZ_FORMAT)
+ }
+ } else
+ call strcpy (user_format, Memc[spp_format], SZ_FORMAT)
+
+ call wti_determine_fmt (Memc[spp_format], Memc[ftn_format],
+ decpl, fmtchar, width)
+
+ # Write the header.
+ if (header) {
+ if (width > 0) {
+ if ((maxll / width) < 1) {
+ call sprintf (Memc[ep], SZ_LINE,
+ "%s: output maxlinelen=%d is too short for format %s")
+ call pargstr (image)
+ call pargi (maxll)
+ call pargstr (Memc[ftn_format])
+ call error (2, Memc[ep])
+ }
+
+ call sprintf (Memc[out_format], SZ_FORMAT, "%d%s")
+ call pargi (maxll / width)
+ call pargstr (Memc[ftn_format])
+ } else
+ call strcpy ("*", Memc[out_format], SZ_FORMAT)
+
+ call wti_write_header (im, image, out, Memc[out_format])
+ }
+
+ # Write out the pixels in text form.
+ if (pixels) {
+ switch (fmtchar) {
+ case 'd':
+ call wti_putint (im, out, maxll, width)
+ case 'e', 'f', 'g':
+ call wti_putreal (im, out, maxll, decpl, fmtchar, width)
+ case 'z':
+ call wti_putcomplex (im, out, maxll, decpl, 'e', width)
+ }
+ }
+
+ call sfree (sp)
+end
+
+
+# WTI_DETERMINE_FMT -- Extract field width from input format string and
+# generate a fortran format equivalent to the input spp format. The input
+# format may be either a Fortran sytle format or an SPP format.
+
+procedure wti_determine_fmt (spp_format, ftn_format, decpl, fmtchar, width)
+
+char spp_format[ARB] # SPP format of each pixel
+char ftn_format[ARB] # equivalent Fortran format (output)
+int decpl # number of decimal places of precision (output)
+int fmtchar # format character (output)
+int width # field width (output)
+
+int ip
+bool fortran_format
+int ctoi()
+
+begin
+ # Parse either an SPP format "W.Dc" or a Fortran format "cW.D" to
+ # determine the field width, number of decimal places or precision,
+ # and the format char. If the field width is missing or zero we set
+ # width=0 to flag that free format output is desired.
+
+ for (ip=1; IS_WHITE (spp_format[ip]); ip=ip+1)
+ ;
+ fortran_format = IS_ALPHA (spp_format[ip])
+ if (fortran_format) {
+ if (spp_format[ip] == 'i')
+ fmtchar = 'd'
+ ip = ip + 1
+ }
+
+ # Extract W and D fields.
+ if (ctoi (spp_format, ip, width) == 0)
+ width = 0
+ if (spp_format[ip] == '.') {
+ ip = ip + 1
+ if (ctoi (spp_format, ip, decpl) == 0)
+ decpl = 0
+ } else
+ decpl = 0
+
+ if (!fortran_format && spp_format[ip] != EOS) {
+ fmtchar = spp_format[ip]
+ ip = ip + 1
+ }
+
+ if (spp_format[ip] != EOS)
+ call error (3, "unacceptable numeric format")
+
+ # Construct the FTN version of the spp_format. This will be
+ # output in the header.
+
+ switch (fmtchar) {
+ case 'd':
+ call sprintf (ftn_format, SZ_FORMAT, "I%d")
+ call pargi (width)
+ case 'e', 'f', 'g':
+ call sprintf (ftn_format, SZ_FORMAT, "%c%d.%d")
+ call pargi (TO_UPPER (fmtchar))
+ call pargi (width)
+ call pargi (decpl)
+ case 'z':
+ # Tell Fortran to use a list directed read to read complex data.
+ call strcpy ("*", ftn_format, SZ_FORMAT)
+ width = 0
+
+ default:
+ call error (4, "Improper format. Must be chosen from [defgz].")
+ }
+end
diff --git a/pkg/dataio/imtext/wtextimage.semi b/pkg/dataio/imtext/wtextimage.semi
new file mode 100644
index 00000000..4574722a
--- /dev/null
+++ b/pkg/dataio/imtext/wtextimage.semi
@@ -0,0 +1,91 @@
+# Semicode for the IRAF image to text file converter.
+
+procedure t_wtextimage (input, output)
+
+begin
+ input = expand template of input image file names
+ if (output hasn't been redirected)
+ get name of output file from cl
+
+ # Get hidden parameters from cl
+ header = is header to be written?
+ maxlinelen = max number of characters per line of text
+ if (format not user specified)
+ format = NOT_SET
+
+ for (each file name in input) {
+ im = open image file
+ generate output file name
+ text = open text file
+ call convert_image (im, text, header, maxlinelen, format)
+ close image file
+ close text file
+ }
+end
+
+
+# CONVERT_IMAGE -- called once for each image to be converted. Directs
+# the processing depending on user request.
+
+procedure convert_image (im, text, header, maxlinelen, format)
+
+begin
+ if (format = NOT_SET)
+ format = appropriate value for data type of image
+
+ # Calculate number of pixels per line of text
+ npix_line = maxlinelen / (field width of pixel output format)
+ output_format = "npix_line.pixel_format"
+
+ if (header is to be written)
+ call write_header (im, text, output_format, maxlinelen)
+
+ call convert_pixels (im, text, output_format)
+end
+
+
+# WRITE_HEADER -- write information from IRAF image header in
+# "keyword = value" format, one keyword per line of text.
+
+procedure convert_header (image, text, output_format, maxlinelen)
+
+begin
+ # Write header information to text file
+ SIMPLE = T
+ BITPIX = 8
+ NAXIS = 0
+ ORIGIN = NOAO
+ IRAF-MAX= IM_MAX
+ IRAF-MIN= IM_MIN
+ IRAF-B/P=
+ IRAFTYPE=
+ OBJECT = IM_TITLE
+ NDIM = IM_NDIM
+ LEN1 = IM_LEN(1)
+ FILENAME= IM_HDRFILE
+ FORMAT = output_format
+
+ # Write any information stored in image user area
+ if (user area contains information) {
+ COMMENT = "Copying user area"
+ KEYWORD = copy user area to text file
+ }
+
+ # Final header line is END
+ END = last line of header
+
+ Pad with blank lines until multiple of 36 lines is output
+end
+
+
+# CONVERT_IMAGE -- write pixel values from IRAF image into text file. The
+# pixels are output in "leftmost subscript varying most rapidly" order.
+
+procedure convert_image (image, text, format)
+
+begin
+ get next line of image
+ for each pixel in line
+ convert pixel to character
+ put out line to text file according to format
+end
diff --git a/pkg/dataio/imtext/wti_wheader.x b/pkg/dataio/imtext/wti_wheader.x
new file mode 100644
index 00000000..2cad585d
--- /dev/null
+++ b/pkg/dataio/imtext/wti_wheader.x
@@ -0,0 +1,152 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <imio.h>
+include <mach.h>
+include "imtext.h"
+
+define NBITS_ASCII 8
+define NDEC_PLACES 7
+
+
+# WTI_WRITE_HEADER -- write information from IRAF image header to text file in
+# FITS "keyword = value / comment" format. One keyword is written per line
+# of text.
+
+procedure wti_write_header (im, image, tx, out_format)
+
+pointer im # Pointer to image file
+char image[ARB] # Image filename
+int tx # File descriptor of text file
+char out_format[ARB] # Output format for pixel conversion
+
+int i, nlines, user, op, max_lenuser
+pointer sp, root, line, comment
+bool streq()
+int strlen(), sizeof(), getline(), stropen(), gstrcpy(), stridx()
+
+errchk addcard_b, addcard_i, addcard_r, addcard_st
+errchk wti_iraf_type, streq, strupr, stropen, strclose, getline
+
+begin
+ call smark (sp)
+ call salloc (root, SZ_FNAME, TY_CHAR)
+ call salloc (line, SZ_LINE, TY_CHAR)
+ call salloc (comment, SZ_LINE, TY_CHAR)
+
+ call addcard_i (tx, "BITPIX", NBITS_ASCII, "8-bit ASCII characters")
+ call addcard_i (tx, "NAXIS", IM_NDIM(im), "Number of Image Dimensions")
+
+ nlines = NFITS_LINES
+
+ # Construct and output an NAXISn card for each axis
+ do i = 1, IM_NDIM(im) {
+ op = gstrcpy ("NAXIS", Memc[root], LEN_KEYWORD)
+ call sprintf (Memc[root+op], LEN_KEYWORD-op, "%d")
+ call pargi (i)
+ call addcard_i (tx, Memc[root], IM_LEN(im,i), "Length of axis")
+ nlines = nlines + 1
+ }
+
+ call addcard_st (tx, "ORIGIN", "NOAO-IRAF: WTEXTIMAGE", "",
+ strlen("NOAO-IRAF: WTEXTIMAGE"))
+
+ # Add the image MIN and MAX header cards
+ call strcpy ("Max image pixel", Memc[comment], SZ_LINE)
+ if (IM_MTIME(im) > IM_LIMTIME(im))
+ call strcat (" (out of date)", Memc[comment], SZ_LINE)
+ call addcard_r (tx, "IRAF-MAX", IM_MAX(im), Memc[comment],
+ NDEC_PLACES)
+
+ call strcpy ("Min image pixel", Memc[comment], SZ_LINE)
+ if (IM_MTIME(im) > IM_LIMTIME(im))
+ call strcat (" (out of date)", Memc[comment], SZ_LINE)
+ call addcard_r (tx, "IRAF-MIN", IM_MIN(im), Memc[comment],
+ NDEC_PLACES)
+
+ # The number of bits per pixel is calculated and output
+ call addcard_i (tx, "IRAF-B/P", sizeof (IM_PIXTYPE(im)) *
+ SZB_CHAR * NBITS_BYTE, "Image bits per pixel")
+
+ call wti_iraf_type (IM_PIXTYPE(im), Memc[root])
+ call addcard_st (tx, "IRAFTYPE", Memc[root], "Image datatype",
+ strlen(Memc[root]))
+
+ call strupr (IM_TITLE(im))
+ call addcard_st (tx, "OBJECT" , IM_TITLE(im), "",
+ strlen (IM_TITLE(im)))
+
+ call strupr (image)
+ call addcard_st (tx, "FILENAME", image, "IRAF filename",
+ strlen (image))
+ nlines = nlines + 1
+
+ call strcpy ("Text line format", Memc[comment], SZ_LINE)
+ if (streq (out_format, "*"))
+ call strcat (" (* = list directed)", Memc[comment], SZ_LINE)
+ call addcard_st (tx, "FORMAT", out_format, Memc[comment],
+ LEN_STRING)
+ nlines = nlines + 1
+
+ # Write any information stored in image user area
+ if ((IM_HDRLEN(im) - LEN_IMHDR) > 0) {
+ max_lenuser = (LEN_IMDES + IM_LENHDRMEM(im) - IMU) * SZ_STRUCT - 1
+ user = stropen (Memc[IM_USERAREA(im)], max_lenuser, READ_ONLY)
+
+ while (getline (user, Memc[line]) != EOF) {
+ call putline (tx, Memc[line])
+ nlines = nlines + 1
+ }
+
+ # Make sure last line written out included a newline. It won't if
+ # the user area was truncated when it was read.
+ if (stridx ("\n", Memc[line]) == 0)
+ call putline (tx, "\n")
+
+ call close (user)
+ }
+
+ # Final header line is END (FITS keywords are 8 characters long)
+ call fprintf (tx, "END%77w\n")
+ nlines = nlines + 1
+
+ # Pad output file with blank lines until header block occupies
+ # a multiple of 36 lines.
+
+ if (nlines != NCARDS_FITS_BLK) {
+ do i = 1, NCARDS_FITS_BLK - mod(nlines, NCARDS_FITS_BLK)
+ call fprintf (tx, "%80w\n")
+ }
+
+ call sfree (sp)
+end
+
+
+# WTI_IRAF_TYPE -- Procedure to set the iraf datatype keyword. Permitted strings
+# are INTEGER, FLOATING or COMPLEX.
+
+procedure wti_iraf_type (datatype, type_str)
+
+int datatype # the IRAF data type
+char type_str[ARB] # the output IRAF type string
+
+begin
+ switch (datatype) {
+ case TY_SHORT:
+ call strcpy ("SHORT INTEGER", type_str, LEN_STRING)
+ case TY_USHORT:
+ call strcpy ("UNSIGNED SHORT INT", type_str, LEN_STRING)
+ case TY_INT:
+ call strcpy ("INTEGER", type_str, LEN_STRING)
+ case TY_LONG:
+ call strcpy ("LONG INTEGER", type_str, LEN_STRING)
+ case TY_REAL:
+ call strcpy ("REAL FLOATING", type_str, LEN_STRING)
+ case TY_DOUBLE:
+ call strcpy ("DOUBLE FLOATING", type_str, LEN_STRING)
+ case TY_COMPLEX:
+ call strcpy ("COMPLEX", type_str, LEN_STRING)
+ default:
+ call error (4, "IRAF_TYPE: Unknown IRAF image type.")
+ }
+end
diff --git a/pkg/dataio/lib/addcards.x b/pkg/dataio/lib/addcards.x
new file mode 100644
index 00000000..42699380
--- /dev/null
+++ b/pkg/dataio/lib/addcards.x
@@ -0,0 +1,140 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+define MAXLEN_STRVAL 65
+define LEN_KEYWORD 8
+define LEN_STRING 18
+
+# ADDCARD_R -- Format and append a FITS header card with a real
+# keyword value to the input string buffer.
+
+procedure addcard_r (fd, keyword, value, comment, precision)
+
+int fd # File descriptor of input string buffer
+char keyword[LEN_KEYWORD] # FITS keyword
+real value # Value of FITS keyword
+char comment[ARB] # Comment string
+int precision # Number of decimal places output
+
+
+begin
+ call fprintf (fd, "%-8.8s= %20.*g / %-45.45s\n")
+ call pargstr (keyword)
+ call pargi (precision)
+ call pargr (value)
+ call pargstr (comment)
+end
+
+
+# ADDCARD_I -- Format and append a FITS header card with an integer
+# keyword value to the input string buffer.
+
+procedure addcard_i (fd, keyword, value, comment)
+
+int fd # File descriptor of input string buffer
+char keyword[LEN_KEYWORD] # FITS keyword
+int value # Value of FITS keyword
+char comment[ARB] # Comment string
+
+begin
+ call fprintf (fd, "%-8.8s= %20d / %-45.45s\n")
+ call pargstr (keyword)
+ call pargi (value)
+ call pargstr (comment)
+end
+
+
+# ADDCARD_TIME -- Format and append a FITS header card to the input
+# file descriptor. The value is input as a real number; it is output
+# in HH:MM:SS.S format with %h. The procedure can be used for RA, DEC
+# and ST, UT and HA.
+
+procedure addcard_time (fd, keyword, value, comment)
+
+int fd # File descriptor
+char keyword[LEN_KEYWORD] # FITS keyword
+real value # Value of FITS keyword to be encoded
+char comment[ARB] # Comment string
+
+
+begin
+ call fprintf (fd, "%-8.8s= '%-18.1h' / %-45s\n")
+ call pargstr (keyword)
+ call pargr (value)
+ call pargstr (comment)
+end
+
+
+# ADDCARD_ST -- Format and output a FITS header card to the input
+# file descriptor. The value is output as a string with the given keyword.
+# If the string value is longer than 18 characters, it is output without
+# a comment.
+
+procedure addcard_st (fd, keyword, value, comment, length)
+
+int fd # File descriptor
+char keyword[LEN_KEYWORD] # FITS keyword
+char value[SZ_LINE] # String value of FITS keyword to be encoded
+char comment[ARB] # Comment string
+int length # Length of string value
+
+begin
+ if (length <= LEN_STRING) {
+ call fprintf (fd, "%-8.8s= '%-18.18s' / %-44s\n")
+ call pargstr (keyword)
+ call pargstr (value)
+ call pargstr (comment)
+ } else {
+ length = min (length, MAXLEN_STRVAL)
+ call fprintf (fd, "%-8.8s= '%*.*s' /\n")
+ call pargstr (keyword)
+ call pargi (-length)
+ call pargi (length)
+ call pargstr (value)
+ }
+end
+
+
+# ADDCARD_B -- Format and output a FITS header card to the input file
+# descriptor. The value is output as a boolean with the given keyword.
+# Unlike string parameters, booleans are not enclosed in quotes.
+
+procedure addcard_b (fd, keyword, value, comment)
+
+int fd # File descriptor
+char keyword[LEN_KEYWORD] # FITS keyword
+bool value # Boolean parameter (T/F)
+char comment[ARB] # Comment string
+char truth
+
+begin
+ if (value)
+ truth = 'T'
+ else
+ truth = 'F'
+
+ call fprintf (fd, "%-8.8s= %20c / %-45.45s\n")
+ call pargstr (keyword)
+ call pargc (truth)
+ call pargstr (comment)
+end
+
+
+# ADDCARD_D -- Format and append a FITS header card with a double
+# keyword value to the input string buffer.
+
+procedure addcard_d (fd, keyword, value, comment, precision)
+
+int fd # File descriptor of input string buffer
+char keyword[LEN_KEYWORD] # FITS keyword
+double value # Value of FITS keyword
+char comment[ARB] # Comment string
+int precision # Number of decimal places output
+
+
+begin
+ call fprintf (fd, "%-8.8s= %20.*f / %-45.45s\n")
+ call pargstr (keyword)
+ call pargi (precision)
+ call pargd (value)
+ call pargstr (comment)
+end
diff --git a/pkg/dataio/lib/getdatatype.x b/pkg/dataio/lib/getdatatype.x
new file mode 100644
index 00000000..9502e82f
--- /dev/null
+++ b/pkg/dataio/lib/getdatatype.x
@@ -0,0 +1,57 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+define NTYPES 9
+
+# GETDATATYPE -- Convert a character to an IRAF data type
+
+int procedure getdatatype (ch)
+
+char ch
+int i, type_code[NTYPES]
+int stridx()
+
+string types "bcusilrdx" # Supported data types
+data type_code /TY_UBYTE, TY_CHAR, TY_USHORT, TY_SHORT, TY_INT, TY_LONG,
+ TY_REAL, TY_DOUBLE, TY_COMPLEX/
+
+begin
+ i = stridx (ch, types)
+ if (i == 0)
+ return (ERR)
+ else
+ return (type_code[stridx(ch,types)])
+end
+
+
+# DTSTRING -- Convert a datatype to a string
+
+procedure dtstring (datatype, str, maxchar)
+
+int datatype # IRAF datatype
+char str[maxchar] # Output string
+int maxchar # Maximum characters in string
+
+begin
+ switch (datatype) {
+ case TY_UBYTE:
+ call strcpy ("unsigned byte", str, maxchar)
+ case TY_CHAR:
+ call strcpy ("character", str, maxchar)
+ case TY_USHORT:
+ call strcpy ("unsigned short", str, maxchar)
+ case TY_SHORT:
+ call strcpy ("short", str, maxchar)
+ case TY_INT:
+ call strcpy ("integer", str, maxchar)
+ case TY_LONG:
+ call strcpy ("long", str, maxchar)
+ case TY_REAL:
+ call strcpy ("real", str, maxchar)
+ case TY_DOUBLE:
+ call strcpy ("double", str, maxchar)
+ case TY_COMPLEX:
+ call strcpy ("complex", str, maxchar)
+ default:
+ call strcpy ("unknown", str, maxchar)
+ }
+end
diff --git a/pkg/dataio/lib/mkpkg b/pkg/dataio/lib/mkpkg
new file mode 100644
index 00000000..698997dd
--- /dev/null
+++ b/pkg/dataio/lib/mkpkg
@@ -0,0 +1,12 @@
+# These routines are used by more than one task in the dataio package:
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ addcards.x
+ #getdatatype.x
+ #ranges.x <ctype.h> <mach.h>
+ ;
diff --git a/pkg/dataio/lib/ranges.x b/pkg/dataio/lib/ranges.x
new file mode 100644
index 00000000..b3812cd1
--- /dev/null
+++ b/pkg/dataio/lib/ranges.x
@@ -0,0 +1,234 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <ctype.h>
+
+define FIRST 1 # Default starting range
+define LAST MAX_INT # Default ending range
+define STEP 1 # Default step
+
+# DECODE_RANGES -- Parse a string containing a list of integer numbers or
+# ranges, delimited by either spaces or commas. Return as output a list
+# of ranges defining a list of numbers, and the count of list numbers.
+# Range limits must be positive nonnegative integers. ERR is returned as
+# the function value if a conversion error occurs. The list of ranges is
+# delimited by a single NULL.
+
+int procedure decode_ranges (range_string, ranges, max_ranges, nvalues)
+
+char range_string[ARB] # Range string to be decoded
+int ranges[3, max_ranges] # Range array
+int max_ranges # Maximum number of ranges
+int nvalues # The number of values in the ranges
+
+int ip, nrange, first, last, step, ctoi()
+
+begin
+ ip = 1
+ nvalues = 0
+
+ do nrange = 1, max_ranges - 1 {
+ # Defaults to all positive integers
+ first = FIRST
+ last = LAST
+ step = STEP
+
+ # Skip delimiters
+ while (IS_WHITE(range_string[ip]) || range_string[ip] == ',')
+ ip = ip + 1
+
+ # Get first limit.
+ # Must be a number, '-', 'x', or EOS. If not return ERR.
+ if (range_string[ip] == EOS) { # end of list
+ if (nrange == 1) {
+ # Null string defaults
+ ranges[1, 1] = first
+ ranges[2, 1] = last
+ ranges[3, 1] = step
+ ranges[1, 2] = NULL
+ nvalues = nvalues + abs (last-first) / step + 1
+ return (OK)
+ } else {
+ ranges[1, nrange] = NULL
+ return (OK)
+ }
+ } else if (range_string[ip] == '-')
+ ;
+ else if (range_string[ip] == 'x')
+ ;
+ else if (IS_DIGIT(range_string[ip])) { # ,n..
+ if (ctoi (range_string, ip, first) == 0)
+ return (ERR)
+ } else
+ return (ERR)
+
+ # Skip delimiters
+ while (IS_WHITE(range_string[ip]) || range_string[ip] == ',')
+ ip = ip + 1
+
+ # Get last limit
+ # Must be '-', or 'x' otherwise last = first.
+ if (range_string[ip] == 'x')
+ ;
+ else if (range_string[ip] == '-') {
+ ip = ip + 1
+ while (IS_WHITE(range_string[ip]) || range_string[ip] == ',')
+ ip = ip + 1
+ if (range_string[ip] == EOS)
+ ;
+ else if (IS_DIGIT(range_string[ip])) {
+ if (ctoi (range_string, ip, last) == 0)
+ return (ERR)
+ } else if (range_string[ip] == 'x')
+ ;
+ else
+ return (ERR)
+ } else
+ last = first
+
+ # Skip delimiters
+ while (IS_WHITE(range_string[ip]) || range_string[ip] == ',')
+ ip = ip + 1
+
+ # Get step.
+ # Must be 'x' or assume default step.
+ if (range_string[ip] == 'x') {
+ ip = ip + 1
+ while (IS_WHITE(range_string[ip]) || range_string[ip] == ',')
+ ip = ip + 1
+ if (range_string[ip] == EOS)
+ ;
+ else if (IS_DIGIT(range_string[ip])) {
+ if (ctoi (range_string, ip, step) == 0)
+ ;
+ } else if (range_string[ip] == '-')
+ ;
+ else
+ return (ERR)
+ }
+
+ # Output the range triple.
+ ranges[1, nrange] = first
+ ranges[2, nrange] = last
+ ranges[3, nrange] = step
+ nvalues = nvalues + abs (last-first) / step + 1
+ }
+
+ return (ERR) # ran out of space
+end
+
+
+# GET_NEXT_NUMBER -- Given a list of ranges and the current file number,
+# find and return the next file number. Selection is done in such a way
+# that list numbers are always returned in monotonically increasing order,
+# regardless of the order in which the ranges are given. Duplicate entries
+# are ignored. EOF is returned at the end of the list.
+
+int procedure get_next_number (ranges, number)
+
+int ranges[ARB] # Range array
+int number # Both input and output parameter
+
+int ip, first, last, step, next_number, remainder
+
+begin
+ # If number+1 is anywhere in the list, that is the next number,
+ # otherwise the next number is the smallest number in the list which
+ # is greater than number+1.
+
+ number = number + 1
+ next_number = MAX_INT
+
+ for (ip=1; ranges[ip] != NULL; ip=ip+3) {
+ first = min (ranges[ip], ranges[ip+1])
+ last = max (ranges[ip], ranges[ip+1])
+ step = ranges[ip+2]
+ if (number >= first && number <= last) {
+ remainder = mod (number - first, step)
+ if (remainder == 0)
+ return (number)
+ if (number - remainder + step <= last)
+ next_number = number - remainder + step
+ } else if (first > number)
+ next_number = min (next_number, first)
+ }
+
+ if (next_number == MAX_INT)
+ return (EOF)
+ else {
+ number = next_number
+ return (number)
+ }
+end
+
+
+# GET_PREVIOUS_NUMBER -- Given a list of ranges and the current file number,
+# find and return the previous file number. Selection is done in such a way
+# that list numbers are always returned in monotonically decreasing order,
+# regardless of the order in which the ranges are given. Duplicate entries
+# are ignored. EOF is returned at the end of the list.
+
+int procedure get_previous_number (ranges, number)
+
+int ranges[ARB] # Range array
+int number # Both input and output parameter
+
+int ip, first, last, step, next_number, remainder
+
+begin
+ # If number-1 is anywhere in the list, that is the previous number,
+ # otherwise the previous number is the largest number in the list which
+ # is less than number-1.
+
+ number = number - 1
+ next_number = 0
+
+ for (ip=1; ranges[ip] != NULL; ip=ip+3) {
+ first = min (ranges[ip], ranges[ip+1])
+ last = max (ranges[ip], ranges[ip+1])
+ step = ranges[ip+2]
+ if (number >= first && number <= last) {
+ remainder = mod (number - first, step)
+ if (remainder == 0)
+ return (number)
+ if (number - remainder >= first)
+ next_number = number - remainder
+ } else if (last < number) {
+ remainder = mod (last - first, step)
+ if (remainder == 0)
+ next_number = max (next_number, last)
+ else if (last - remainder >= first)
+ next_number = max (next_number, last - remainder)
+ }
+ }
+
+ if (next_number == 0)
+ return (EOF)
+ else {
+ number = next_number
+ return (number)
+ }
+end
+
+
+# IS_IN_RANGE -- Test number to see if it is in range.
+
+bool procedure is_in_range (ranges, number)
+
+int ranges[ARB] # Range array
+int number # Number to be tested against ranges
+
+int ip, first, last, step
+
+begin
+ for (ip=1; ranges[ip] != NULL; ip=ip+3) {
+ first = min (ranges[ip], ranges[ip+1])
+ last = max (ranges[ip], ranges[ip+1])
+ step = ranges[ip+2]
+ if (number >= first && number <= last)
+ if (mod (number - first, step) == 0)
+ return (true)
+ }
+
+ return (false)
+end
diff --git a/pkg/dataio/mkpkg b/pkg/dataio/mkpkg
new file mode 100644
index 00000000..bba288df
--- /dev/null
+++ b/pkg/dataio/mkpkg
@@ -0,0 +1,33 @@
+# Make the DATAIO package
+
+$call relink
+$exit
+
+update:
+ $call relink
+ $call install
+ ;
+
+relink:
+ $set LIBS = "-lxtools"
+ $update libpkg.a
+ $omake x_dataio.x
+ $link x_dataio.o libpkg.a $(LIBS) -o xx_dataio.e
+ ;
+
+install:
+ $move xx_dataio.e bin$x_dataio.e
+ ;
+
+libpkg.a:
+ @lib
+ @export
+ @import
+ @imtext
+ @reblock
+ @fits
+ @bintext
+ @mtexamine
+ @cardimage
+ @t2d
+ ;
diff --git a/pkg/dataio/mtexamine.par b/pkg/dataio/mtexamine.par
new file mode 100644
index 00000000..07269aa1
--- /dev/null
+++ b/pkg/dataio/mtexamine.par
@@ -0,0 +1,8 @@
+tape_file,s,a,,,,Tape file
+file_list,s,h,1-999,,,List of file numbers
+dump_records,b,h,no,,,Dump selected records?
+rec_list,s,h,1-999,,,List of records to be dumped
+byte_chunk,i,h,1,,,Byte chunk
+swapbytes,b,h,no,,,Swap bytes?
+output_format,s,h,o,,,Dump format (c|d|o|u|x)
+mode,s,h,"ql",,,
diff --git a/pkg/dataio/mtexamine/mkpkg b/pkg/dataio/mtexamine/mkpkg
new file mode 100644
index 00000000..99e96080
--- /dev/null
+++ b/pkg/dataio/mtexamine/mkpkg
@@ -0,0 +1,10 @@
+# Mtexamine library
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ t_mtexamine.x <error.h> <fset.h> <printf.h> <mach.h> mtexamine.com
+ ;
diff --git a/pkg/dataio/mtexamine/mtexamine.com b/pkg/dataio/mtexamine/mtexamine.com
new file mode 100644
index 00000000..46969458
--- /dev/null
+++ b/pkg/dataio/mtexamine/mtexamine.com
@@ -0,0 +1,6 @@
+int dump_records
+int byteswap
+int byte_chunk
+char output_format
+
+common /mtexam/ dump_records, byteswap, byte_chunk, output_format
diff --git a/pkg/dataio/mtexamine/t_mtexamine.x b/pkg/dataio/mtexamine/t_mtexamine.x
new file mode 100644
index 00000000..26f7b2fd
--- /dev/null
+++ b/pkg/dataio/mtexamine/t_mtexamine.x
@@ -0,0 +1,376 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <fset.h>
+include <printf.h>
+include <mach.h>
+
+define MAX_RANGES 100
+define LEN_LINE 80
+define TAPE_BYTE 8
+define TWO_TO_EIGHT 256
+define FIELD_INDEX 5
+define NFORMATS 5
+
+
+# MTEXAMINE -- Examine one or more magtape files, counting the number and size
+# of the records in a file, and the number of files on the tape.
+
+procedure t_mtexamine()
+
+int nfiles, file_number, ndumps, nrecords
+int file_range[2*MAX_RANGES+1], rec_range[2*MAX_RANGES+1]
+pointer sp, tape_name, tape_file, file_list, rec_list
+
+bool clgetb()
+char clgetc()
+int fstati(), mtfile(), mtneedfileno(), decode_ranges(), get_next_number()
+int mt_examine(), mt_get_format(), clgeti(), btoi()
+include "mtexamine.com"
+
+begin
+ # Allocate working space.
+ call smark (sp)
+ call salloc (tape_name, SZ_FNAME, TY_CHAR)
+ call salloc (tape_file, SZ_FNAME, TY_CHAR)
+ call salloc (file_list, SZ_LINE, TY_CHAR)
+ call salloc (rec_list, SZ_LINE, TY_CHAR)
+
+ # Flush STDOUT on a newline only if output is not redirected.
+ if (fstati (STDOUT, F_REDIR) == NO)
+ call fseti (STDOUT, F_FLUSHNL, YES)
+
+ # Get input file(s).
+ call clgstr ("tape_file", Memc[tape_file], SZ_FNAME)
+ if (mtfile (Memc[tape_file]) == NO)
+ call strcpy ("1", Memc[file_list], SZ_LINE)
+ else if (mtneedfileno (Memc[tape_file]) == NO)
+ call strcpy ("1", Memc[file_list], SZ_LINE)
+ else
+ call clgstr ("file_list", Memc[file_list], SZ_LINE)
+ if (decode_ranges (Memc[file_list],file_range,MAX_RANGES,nfiles) == ERR)
+ call error (0, "Illegal file number list.")
+
+ # Get dump parameters
+ dump_records = btoi (clgetb ("dump_records"))
+ if (dump_records == YES) {
+ call clgstr ("rec_list", Memc[rec_list], SZ_LINE)
+ if (decode_ranges (Memc[rec_list], rec_range, MAX_RANGES,
+ ndumps) == ERR)
+ call error (0, "Illegal record list.")
+ byteswap = btoi (clgetb ("swapbytes"))
+ byte_chunk = clgeti ("byte_chunk")
+ if (byte_chunk < 1 || byte_chunk > (SZ_LONG * SZB_CHAR))
+ call error (0, "Illegal byte chunk size.")
+ output_format = mt_get_format (clgetc ("output_format"))
+ if (output_format == ERR)
+ call error (0, "Illegal format.")
+ if (byte_chunk != 1 && output_format == FMT_CHAR)
+ call error (0, "Cannot output integers as chars.")
+ }
+
+ # Loop over files
+ file_number = 0
+ while (get_next_number (file_range, file_number) != EOF) {
+
+ if (mtfile (Memc[tape_file]) == YES &&
+ mtneedfileno (Memc[tape_file]) == YES)
+ call mtfname (Memc[tape_file], file_number, Memc[tape_name],
+ SZ_FNAME)
+ else
+ call strcpy (Memc[tape_file], Memc[tape_name], SZ_FNAME)
+
+ iferr {
+ nrecords = mt_examine (Memc[tape_name], rec_range)
+ } then {
+ call eprintf ("Error reading file: %s\n")
+ call pargstr (Memc[tape_name])
+ call erract (EA_WARN)
+ break
+ } else if (nrecords == 0) {
+ call printf ("Tape at EOT\n")
+ break
+ }
+
+ }
+
+ call sfree (sp)
+end
+
+
+# MT_EXAMINE -- Procedure to examine a tape file. If dump_record is
+# no mtexamine gives a summary of the record structure of the file,
+# otherwise the specified records are dumped.
+
+int procedure mt_examine (tape_file, dump_range)
+
+char tape_file[ARB] # input file name
+int dump_range[ARB] # range of records to be dumped
+
+pointer sp, inbuf, pchar, junk
+int in, bufsize, totrecords, nrecords, totbytes, last_recsize, nbadrec
+int stat, rec_number, next_dump, recsize, nelems, vals_per_line, field_len
+long maxval, max_plusint, twice_max_plusint
+
+int mtopen(), fstati(), get_next_number(), read(), gltoc()
+errchk mtopen, malloc, read, mfree, close
+include "mtexamine.com"
+
+begin
+ call smark (sp)
+ call salloc (junk, SZ_FNAME, TY_CHAR)
+
+ in = mtopen (tape_file, READ_ONLY, 0)
+ bufsize = fstati (in, F_BUFSIZE)
+ call salloc (pchar, bufsize, TY_CHAR)
+
+ call printf ("File %s:\n")
+ call pargstr (tape_file)
+
+ totrecords = 0
+ nrecords = 0
+ totbytes = 0
+ nbadrec = 0
+ last_recsize = 0
+
+ # Prepare formatting parameters for dumping records.
+ if (dump_records == YES) {
+ call salloc (inbuf, bufsize * SZB_CHAR, TY_LONG)
+ rec_number = 0
+ next_dump = get_next_number (dump_range, rec_number)
+ maxval = 2 ** (byte_chunk * TAPE_BYTE - 1) - 1
+ field_len = gltoc (maxval, Memc[junk], SZ_FNAME, TAPE_BYTE) + 1
+ vals_per_line = (LEN_LINE - FIELD_INDEX) / (field_len + 1)
+ if (output_format == FMT_DECIMAL && byte_chunk > 1 &&
+ byte_chunk < (SZ_LONG * SZB_CHAR)) {
+ max_plusint = maxval + 1
+ twice_max_plusint = 2 * max_plusint
+ }
+ }
+
+ # Loop through the records.
+ repeat {
+ iferr (stat = read (in, Memc[pchar], bufsize)) {
+ call fseti (in, F_VALIDATE, last_recsize / SZB_CHAR)
+ nbadrec = nbadrec + 1
+ call printf ("\tRead error on record: %d\n")
+ call pargi (totrecords + 1)
+ stat = read (in, Memc[pchar], bufsize)
+ }
+ if (stat == EOF)
+ break
+
+ recsize = fstati (in, F_SZBBLK)
+ if (dump_records == NO) {
+ if (nrecords == 0) {
+ nrecords = 1
+ last_recsize = recsize
+ } else if (recsize == last_recsize) {
+ nrecords = nrecords + 1
+ } else {
+ call printf ("\t%d %d-byte records\n")
+ call pargi (nrecords)
+ call pargi (last_recsize)
+ nrecords = 1
+ last_recsize = recsize
+ }
+ } else if (next_dump != EOF && rec_number == totrecords + 1) {
+ call printf (" Record %d,")
+ call pargi (totrecords + 1)
+ call printf (" %d bytes,")
+ call pargi (recsize)
+ nelems = recsize / byte_chunk
+ call printf (" %d elements")
+ call pargi (nelems)
+ call mt_bytupkl (Memc[pchar], Meml[inbuf], recsize, byte_chunk,
+ byteswap)
+ call mt_dump (Meml[inbuf], nelems, field_len, vals_per_line,
+ max_plusint, twice_max_plusint)
+ next_dump = get_next_number (dump_range, rec_number)
+ }
+
+ totrecords = totrecords + 1
+ totbytes = totbytes + recsize
+ }
+
+ if (nrecords > 0 && dump_records == NO) {
+ call printf ("\t%d %d-byte records\n")
+ call pargi (nrecords)
+ call pargi (last_recsize)
+ }
+
+ # Print total number of records and bytes
+ if (dump_records == YES) {
+ call printf (" Total %d records, %d bytes\n")
+ call pargi (totrecords)
+ call pargi (totbytes)
+ } else {
+ call printf ("\tTotal %d records, %d bytes")
+ call pargi (totrecords)
+ call pargi (totbytes)
+ if (nbadrec > 0) {
+ call printf (" [%d bad records]")
+ call pargi (nbadrec)
+ }
+ call printf ("\n")
+ }
+
+ call close (in)
+
+ call sfree (sp)
+ return (totrecords)
+end
+
+
+# MT_DUMP -- Procedure to format and dump a tape record in chars, shorts or
+# longs in char, decimal, octal, unsigned decimal or hexadecimal format.
+
+procedure mt_dump (buffer, nelems, field_len, vals_per_line, max_plusint,
+ twice_max_plusint)
+
+int nelems, field_len, vals_per_line
+long buffer[ARB], max_plusint, twice_max_plusint
+
+int i, nchars
+char ch, outstr[SZ_FNAME]
+int ctocc()
+include "mtexamine.com"
+
+begin
+ for (i = 1; i <= nelems; i = i + 1) {
+ if (mod (i, vals_per_line) == 1) {
+ call printf ("\n%*d:")
+ call pargi (FIELD_INDEX)
+ call pargi (i)
+ }
+ if (output_format == FMT_CHAR) {
+ ch = buffer[i]
+ nchars = ctocc (ch, outstr, SZ_FNAME)
+ call printf ("%*s")
+ call pargi (field_len)
+ call pargstr (outstr)
+ } else {
+ if (output_format == FMT_DECIMAL && byte_chunk > 1
+ && byte_chunk < (SZ_LONG * SZB_CHAR))
+ call mt_sign_convert (buffer[i], 1, max_plusint,
+ twice_max_plusint)
+ call printf ("%**")
+ call pargi (field_len)
+ call pargc (output_format)
+ call pargl (buffer[i])
+ }
+ }
+
+ call printf ("\n")
+end
+
+
+# MT_GET_FORMAT -- Procedure to return the appropriate output format.
+
+int procedure mt_get_format (c)
+
+char c
+int i, format_code[NFORMATS]
+int stridx()
+string formats "cdoxu"
+data format_code /FMT_CHAR, FMT_DECIMAL, FMT_OCTAL, FMT_HEX, FMT_UNSIGNED/
+
+begin
+ i = stridx (c, formats)
+ if ( i == 0)
+ return (ERR)
+ else
+ return (format_code[i])
+end
+
+
+# MT_BYTUPKL -- Procedure to unpack an array in chunks byte_chunk bytes long
+# into a long array with optional byteswapping.
+
+procedure mt_bytupkl (a, b, nbytes, byte_chunk, byteswap)
+
+char a[ARB] # input buffer
+long b[ARB] # output array
+int nbytes # number of bytes
+int byte_chunk # number of bytes to be formatted, swapped etc.
+int byteswap # swap bytes
+
+int op, i, j, rem
+long sum
+
+begin
+ op = 1
+
+ # Unpack unsigned bytes into a long integer array
+ call achtbl (a, b, nbytes)
+
+ # Flip bytes if necessary
+ if (byteswap == YES && byte_chunk > 1) {
+ for (i = 1; i <= nbytes - byte_chunk + 1; i = i + byte_chunk)
+ call mt_aflipl (b[i], byte_chunk)
+ }
+
+ # Convert the bytes into unsigned integers
+ for (i = 1; i <= nbytes - byte_chunk + 1; i = i + byte_chunk) {
+ sum = 0
+ for (j = 1; j <= byte_chunk; j = j + 1) {
+ sum = sum + TWO_TO_EIGHT ** (byte_chunk - j) *
+ b[i + j - 1]
+ }
+ b[op] = sum
+ op = op + 1
+ }
+
+ # Convert remaining bytes
+ rem = nbytes - i + 1
+ if (rem > 0) {
+ if (byteswap == YES && byte_chunk > 1)
+ call mt_aflipl (b[i], rem)
+ sum = 0
+ for (j = 1; j <= rem; j = j + 1)
+ sum = sum + TWO_TO_EIGHT ** (rem - j) *
+ b[i + j - 1]
+ b[op] = sum
+ }
+end
+
+
+# MT_AFLIPL -- Procedure to flip a long integer array in place.
+
+procedure mt_aflipl (buf, npix)
+
+long buf[npix] # array to be flipped
+int npix # number of elements in array
+
+int n_total, n_half, i, j
+
+begin
+ n_half = npix / 2
+ n_total = npix + 1
+ for (i = 1; i <= n_half; i = i + 1) {
+ j = buf[i]
+ buf[i] = buf[n_total - i]
+ buf[n_total - i] = j
+ }
+end
+
+
+# MT_SIGN_CONVERT -- Procedure to convert unsigned long integers in the range
+# 0 to twice_max_plusint - 1 to integers in the range - max_plusint
+# to max_plusint - 1.
+
+procedure mt_sign_convert (b, nelems, max_plusint, twice_max_plusint)
+
+long b[nelems] # array of long integers to be converted
+int nelems # number of elements in the array
+long max_plusint # 0 <= b[i] <= max_plusint - 1
+long twice_max_plusint # twice max_plusint
+
+int i
+
+begin
+ for (i = 1; i <= nelems; i = i + 1) {
+ if (b[i] >= max_plusint)
+ b[i] = b[i] - twice_max_plusint
+ }
+end
diff --git a/pkg/dataio/rcardimage.par b/pkg/dataio/rcardimage.par
new file mode 100644
index 00000000..98276eed
--- /dev/null
+++ b/pkg/dataio/rcardimage.par
@@ -0,0 +1,14 @@
+mode,s,h,"ql"
+cardfile,s,a,,,,"Card image file"
+file_list,s,a,,,,"List of tape file numbers"
+textfile,s,a,,,,"Output file text file(s)"
+card_length,i,h,80,,,"Columns per card"
+max_line_length,i,h,161,,161,"Maximum line length"
+entab,b,h,yes,,,"Replace blanks with tabs and blanks?"
+join,b,a,no,,,"Join oversize lines?"
+contn_string,s,a,>>,,,"Continuation line marker"
+trim,b,h,yes,,,"Trim trailing whitespace?"
+verbose,b,h,yes,,,"Print messages?"
+ebcdic,b,h,no,,,"Convert from EBCDIC to ASCII?"
+ibm,b,h,no,,,"Translate from IBM(EBCDIC) to ASCII?"
+offset,i,h,0,,,Tape file number offset
diff --git a/pkg/dataio/reblock.par b/pkg/dataio/reblock.par
new file mode 100644
index 00000000..01916973
--- /dev/null
+++ b/pkg/dataio/reblock.par
@@ -0,0 +1,16 @@
+infiles,s,a,,,,Input file
+outfiles,s,a,,,,Output file
+file_list,s,a,,,,Tape file list
+newtape,b,a,,,,Blank tape?
+outblock,i,h,INDEF,,,Size of output block in bytes
+inrecord,i,h,INDEF,,,Size of input records in bytes
+outrecord,i,h,INDEF,,,Size of output records in btyes
+pad_block,b,h,no,,,Pad last block?
+padchar,s,h,'0',,,Pad character
+skipn,i,h,0,,,Skip n blocks (tape) or records (disk)
+copyn,i,h,INDEF,,,Copy n blocks (tape) or records (disk)
+byteswap,b,h,no,,,Swap bytes?
+wordswap,b,h,no,,,Swap words?
+offset,i,h,0,,,Tape file number offset
+verbose,b,h,yes,,,Print messages?
+mode,s,h,"ql",,,
diff --git a/pkg/dataio/reblock/mkpkg b/pkg/dataio/reblock/mkpkg
new file mode 100644
index 00000000..5baf1a30
--- /dev/null
+++ b/pkg/dataio/reblock/mkpkg
@@ -0,0 +1,12 @@
+# Reblock Library
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ t_reblock.x reblock.com reblock.h <fset.h> <error.h> <ctype.h>\
+ <mach.h>
+ reblock_file.x reblock.com reblock.h <fset.h> <error.h> <mach.h>
+ ;
diff --git a/pkg/dataio/reblock/reblock.com b/pkg/dataio/reblock/reblock.com
new file mode 100644
index 00000000..35bc652d
--- /dev/null
+++ b/pkg/dataio/reblock/reblock.com
@@ -0,0 +1,21 @@
+# input parameters
+int szb_outblock # size of output block in bytes
+int szb_inrecord # size of input record in bytes
+int szb_outrecord # size of output record in bytes
+int nskip # number blocks (tape) or records (disk) to be skipped
+int ncopy # number of blocks (tape) or records (disk) to be copied
+int padvalue # integer value of padcharacter
+
+# integer switches
+int intape # input tape device
+int outtape # output tape device
+int reblock # reformat?
+int pad_block # pad short blocks
+int pad_record # pad records
+int trim_record # trim records
+int byteswap # swap every other byte
+int wordswap # swap every other word
+
+common /reblock/ szb_outblock, szb_inrecord, szb_outrecord, nskip, ncopy,
+ padvalue, intape, outtape, reblock, pad_block, pad_record,
+ trim_record, byteswap, wordswap
diff --git a/pkg/dataio/reblock/reblock.h b/pkg/dataio/reblock/reblock.h
new file mode 100644
index 00000000..c88d38a8
--- /dev/null
+++ b/pkg/dataio/reblock/reblock.h
@@ -0,0 +1,7 @@
+# define the output parameters
+define BLKS_RD $1[1]
+define BLKS_WRT $1[2]
+define RECS_RD $1[3]
+define RECS_WRT $1[4]
+define LEN_OUTPARAM 4
+
diff --git a/pkg/dataio/reblock/reblock.hlp b/pkg/dataio/reblock/reblock.hlp
new file mode 100644
index 00000000..465314be
--- /dev/null
+++ b/pkg/dataio/reblock/reblock.hlp
@@ -0,0 +1,154 @@
+.help reblock Mar84 dataio
+.ih
+NAME
+reblock -- copy a file on tape or disk with optional reblocking
+.ih
+USAGE
+reblock (infiles, outfiles, file_list)
+.ih
+PARAMETERS
+.ls infiles
+File or device name e.g. "mta1600[2]" or "mta800" or "file1".
+.le
+.ls outfiles
+If multiple file to disk is requested, the ouput file names will be generated
+by concatenating the tape file number onto the output file name.
+.le
+.ls file_list
+List of tape file numbers or ranges delimited by whitespace or commas,
+e.g. "1-3, 5_8".
+File_list is requested only if the magtape input device is specified.
+Files will be read in ascending order regardless of the ordering of the list.
+Reading will terminate silently if EOT is reached, thus a list such as
+"1-999" may be used to read all files on the tape.
+.le
+.ls newtape
+If the output device is magtape, newtape specifies whether the tape is
+blank or contains data.
+Newtape is requested only if no tape file number is specified, e.g. "mta1600".
+.le
+.ls outblock = INDEF
+Size of the output block bytes.
+In the default case and for disk output, the output block size is set to the
+file i/o disk default buffer size.
+.le
+.ls inrecord = INDEF, outrecord = INDEF
+The sizes of the input and output logical records in bytes.
+The default input and output record sizes are set equal to
+the input and output block sizes respectively. If inrecord > outrecord,
+records are trimmed; if inrecord < outrecord, records are padded; if
+inrecord = outrecord, records are simply counted. If only one of inrecord or
+outrecord is set, the undefined parameter defaults to the value of the
+other.
+.le
+.ls nskip = 0
+The number of input blocks (tape input) or records (disk input, size inrecord)
+to be skipped.
+.le
+.ls ncopy = INDEF
+The number of input blocks (tape input) or records
+(disk input, size inrecord) to be copied. Ncopy defaults to a very large number.
+.le
+.ls byteswap = no
+Swap every other byte.
+.le
+.ls wordswap = no
+Swap every other word.
+.le
+.ls pad_block = no
+If pad_block is set, reblock pads trailing blocks until they are outblock
+bytes long, otherwise trailing blocks may be short.
+.le
+.ls padchar = 0
+Single character used to pad blocks or records.
+Padchar is only requested if pad_record or pad_block
+is set. If padchar equals one of the digits 0 through nine, records and
+blocks are padded with the face value of the character, otherwise the
+ASCII value is used.
+.le
+.ls verbose = yes
+Print messages about files, blocks copied etc.
+.le
+.ih
+DESCRIPTION
+
+REBLOCK is a procedure to copy disk or tape resident files to
+disk or tape. Multiple tape files or a single disk input file may be specified.
+If multiple files are output to disk the output file names will be
+generated by concatenating the tape file number onto the output file name.
+The user may request magnetic tape output to begin at a specific file on
+tape, e.g. mta1600[5] in which case file five will be overwritten if it
+exists, or at BOT or EOT. If no file number is specified REBLOCK asks
+whether the tape is new or old and begin writing at BOT or EOT as
+appropriate.
+
+Before beginning the copy, the user may request reblock to skip
+n (default 0) blocks (tape input) or logical records (disk input).
+The user can also specify that
+only n (default all) blocks (tape input) or records (disk input)
+are to be copied. Before the copy the data may be optionally word-swapped
+(default no) and/or byte-swapped (default no). If verbose is specified
+(default yes) reblock prints the input and output file names,
+the number of blocks read and written and the number of records read and
+written.
+
+Reblock
+uses the default buffer sizes supplied by mtio and file i/o to determine the
+maximum number of bytes which can be read in a single read call. For tapes
+this corresponds to the maximum number of bytes per block permitted by the
+device. Mtio will not read more than one block per read call. Therefore the
+actual number of bytes read will be less than or equal to the mtio buffer size.
+For disk files the default buffer size set by IRAF is a multiple of the
+disk block size. If the disk file is smaller than one block
+or the last block is partially full, the number of bytes read
+will be less than the default buffer size. All magtape and disk reads are
+done with the file i/o read procedure and a call to fstati determines the number
+of bytes actually read.
+
+If all the defaults are set, a binary copy is performed.
+In tape to tape copies the block and record sizes are preserved,
+but the density may
+be changed by specifying the appropriate output file name e.g. mta800 or
+mta1600.
+Reblocking occurs in tape to disk transfers, if records, are trimmed,
+padded or counted, or if blocks are padded.
+If a disk to tape transfer is requested
+the output block size will be the default file i/o buffer size.
+The last block in a file may be short. If uniform sized blocks are
+desired, pad_block must be set, in which case trailing partially filled
+blocks will be padded with padchar.
+
+Logical records are distinguished from blocks (physical records).
+The input and output record sizes default to
+the size of the input and output blocks respectively.
+Logical records may be shorter or longer than the block sizes.
+.ih
+EXAMPLES
+
+Copy a magnetic tape preserving the record sizes but changing
+the density from 800 bpi to 1600 bpi.
+
+.nf
+ da> reblock mtb800, "mta1600[1]", "1-999"
+.fi
+
+Reblock a magnetic tape changing the block size from 4000 bytes to 8000
+bytes and padding the last block.
+
+.nf
+ da> reblock mtb1600, "mta1600[1]", "1-999", outb=8000, padb+
+.fi
+
+Trim the records of a disk file.
+
+.nf
+ da> reblock input, output, inrec=80, outrec=72
+.fi
+
+Pad the records of a disk file with blanks.
+
+.nf
+ da> reblock input, output, inrec=81, outrec=82, padchar=" "
+.fi
+
+.endhelp
diff --git a/pkg/dataio/reblock/reblock_file.x b/pkg/dataio/reblock/reblock_file.x
new file mode 100644
index 00000000..2801a1b1
--- /dev/null
+++ b/pkg/dataio/reblock/reblock_file.x
@@ -0,0 +1,416 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <fset.h>
+include <mach.h>
+include "reblock.h"
+
+# REB_REBLOCK_FILE -- Copy and optionally reblock files.
+
+procedure reb_reblock_file (in_fname, out_fname, outparam)
+
+char in_fname[ARB] # input file name
+char out_fname[ARB] # output file name
+int outparam[ARB] # output parameters
+
+char padchar
+int in, out, sz_charsin, sz_charsout, mov_nbytes, rem_in, rem_out
+int bytes_read, ip, op, i, first_byte, nchars, rec_count, ntrim
+long offset
+pointer inbuf, outbuf
+
+int mtopen(), reb_roundup(), read(), reb_skipover(), fstati(), open()
+errchk open, mtopen, read, awriteb, awaitb, close, mfree, malloc, flush
+errchk reb_write_block, reb_pad_block, reb_pad_record, reb_skipover
+include "reblock.com"
+
+begin
+ # Open input and output files
+ in = mtopen (in_fname, READ_ONLY, 0)
+ out = NULL
+
+ # Allocate space for input buffer.
+ sz_charsin = fstati (in, F_BUFSIZE)
+ call malloc (inbuf, sz_charsin, TY_CHAR)
+ outbuf = NULL
+
+ # Skip over n input blocks (tape) or records (disk).
+ first_byte = 1
+ if (intape == YES) {
+ for (i=1; i <= nskip; i = i + 1) {
+ nchars = read (in, Memc[inbuf], sz_charsin)
+ if (nchars == EOF)
+ call error (1,"Skipped past EOF on input.")
+ }
+ } else {
+ first_byte = reb_skipover (in, szb_inrecord, nskip)
+ if (first_byte == EOF)
+ call error (2, "Skipped past EOF on input.")
+ }
+
+ # Initialize the input and output block and record counters
+ BLKS_RD(outparam) = 0
+ BLKS_WRT(outparam) = 0
+ RECS_RD(outparam) = 0
+ RECS_WRT(outparam) = 0
+
+ # Initalize the record counter.
+ rec_count = 0
+
+ # Set of the offset in output file for asyncrhronous i/o.
+ offset = 1
+
+ # Loop over the input blocks.
+ repeat {
+
+ # Read a block and update block counter.
+ nchars = read (in, Memc[inbuf], sz_charsin)
+ if (nchars == EOF)
+ break
+ bytes_read = nchars * SZB_CHAR
+ if (mod (fstati (in, F_SZBBLK), SZB_CHAR) != 0)
+ bytes_read = bytes_read - mod (fstati (in, F_SZBBLK), SZB_CHAR)
+ BLKS_RD(outparam) = BLKS_RD(outparam) + 1
+
+ # Align to first byte.
+ if (rec_count == 0 && first_byte > 1) {
+ bytes_read = bytes_read - first_byte + 1
+ call bytmov (Memc[inbuf],first_byte, Memc[inbuf],1, bytes_read)
+ }
+
+ # Open the output file. This has been moved from the beginning
+ # of the routine to avoid a magtape problem.
+ # driver problem.
+ if (BLKS_RD(outparam) == 1) {
+ if (outtape == NO)
+ out = open (out_fname, NEW_FILE, BINARY_FILE)
+ else
+ out = mtopen (out_fname, WRITE_ONLY, 0)
+ }
+
+ # Binary copy.
+ if (reblock == NO) {
+
+ RECS_RD(outparam) = BLKS_RD(outparam)
+ call reb_write_block (out, Memc[inbuf], bytes_read, offset,
+ byteswap, wordswap)
+ BLKS_WRT(outparam) = BLKS_WRT(outparam) + 1
+ RECS_WRT(outparam) = BLKS_WRT(outparam)
+
+ # Reblock.
+ } else {
+
+ # Initialize reblocking parameters after first read.
+ if (BLKS_RD(outparam) == 1) {
+
+ # Initialize block and record sizes
+ if (IS_INDEFI(szb_inrecord))
+ szb_inrecord = sz_charsin * SZB_CHAR
+ if (IS_INDEFI(szb_outblock))
+ szb_outblock = fstati (out, F_BUFSIZE) * SZB_CHAR
+ if (IS_INDEFI(szb_outrecord))
+ szb_outrecord = szb_outblock
+
+ # Set pad character.
+ if (pad_record == YES || pad_block == YES) {
+ padchar = char (padvalue)
+ call chrpak (padchar, 1, padchar, 1, 1)
+ }
+
+ # Allocate space for the output buffer.
+ sz_charsout = reb_roundup (szb_outblock, SZB_CHAR) /
+ SZB_CHAR
+ call malloc (outbuf, sz_charsout, TY_CHAR)
+
+ # Intialize the record remainder counters
+ rem_in = szb_inrecord
+ rem_out = szb_outrecord
+
+ # Initialize input and output buffer pointers
+ ip = 1
+ op = 1
+ }
+
+ # Loop over the input buffer.
+ repeat {
+
+ # Calculate the number of bytes to be moved.
+ mov_nbytes = min (bytes_read - ip + 1,
+ rem_in, rem_out, szb_outblock - op + 1)
+ call bytmov (Memc[inbuf], ip, Memc[outbuf], op, mov_nbytes)
+
+ # Update the remainders
+ rem_in = rem_in - mov_nbytes
+ if (rem_in == 0)
+ rem_in = szb_inrecord
+ rem_out = rem_out - mov_nbytes
+ if (rem_out == 0)
+ rem_out = szb_outrecord
+
+ # Update the input and output buffer pointers.
+ ip = ip + mov_nbytes
+ op = op + mov_nbytes
+
+ # Pad records.
+ if (pad_record == YES && rem_in == szb_inrecord) {
+
+ # Do the padding.
+ if (mov_nbytes != 0) {
+ RECS_RD(outparam) = RECS_RD(outparam) + 1
+ call reb_pad_record (Memc[outbuf], op, rem_out,
+ szb_outblock, szb_outrecord, padchar)
+ } else if (rem_out < szb_outrecord)
+ call reb_pad_record (Memc[outbuf], op, rem_out,
+ szb_outblock, szb_outrecord, padchar)
+
+ # Increment the output record counter.
+ if (rem_out == szb_outrecord)
+ RECS_WRT(outparam) = RECS_WRT(outparam) + 1
+ else if (rem_out < szb_outrecord)
+ rem_in = 0
+ }
+
+ # If the output buffer is exhausted, output block of data.
+ if (op > szb_outblock) {
+ call reb_write_block (out, Memc[outbuf], szb_outblock,
+ offset, byteswap, wordswap)
+ BLKS_WRT(outparam) = BLKS_WRT(outparam) + 1
+ op = 1
+ }
+
+ # Trim records.
+ if (trim_record == YES && rem_out == szb_outrecord) {
+
+ # Do the trimming.
+ if (mov_nbytes != 0)
+ RECS_WRT(outparam) = RECS_WRT(outparam) + 1
+ ntrim = min (rem_in, bytes_read - ip + 1)
+ ip = ip + ntrim
+ rem_in = rem_in - ntrim
+ if (rem_in == 0)
+ rem_in = szb_inrecord
+
+ # Increment the record counter.
+ if (rem_in == szb_inrecord)
+ RECS_RD(outparam) = RECS_RD(outparam) + 1
+ else if (rem_in < szb_inrecord)
+ rem_out = 0
+ }
+
+ # Count the records.
+ if (pad_record == NO && trim_record == NO) {
+ if (szb_inrecord == sz_charsin * SZB_CHAR)
+ RECS_RD(outparam) = BLKS_RD(outparam)
+ else if (rem_in == szb_inrecord)
+ RECS_RD(outparam) = RECS_RD(outparam) + 1
+ if (rem_out == szb_outrecord)
+ RECS_WRT(outparam) = RECS_WRT(outparam) + 1
+ }
+
+ # Quit if ncopy records has been reached.
+ if (intape == NO && RECS_RD(outparam) == ncopy)
+ break
+
+ } until (ip > bytes_read)
+
+ # Reset the input buffer pointer
+ ip = 1
+ }
+
+ # Update the record counter.
+ if (intape == YES)
+ rec_count = BLKS_RD(outparam)
+ else
+ rec_count = RECS_RD(outparam)
+
+ } until (rec_count >= ncopy)
+
+ # Output remainder of data
+ if (reblock == YES) {
+
+ # Pad last record if short.
+ if (pad_record == YES) {
+ if (rem_in < szb_inrecord)
+ RECS_RD(outparam) = RECS_RD(outparam) + 1
+ if (rem_out < szb_outrecord)
+ RECS_WRT(outparam) = RECS_WRT(outparam) + 1
+ while (rem_out < szb_outrecord) {
+ call reb_pad_record (Memc[outbuf], op, rem_out,
+ szb_outblock, szb_outrecord, padchar)
+ if (op > szb_outblock) {
+ call reb_write_block (out, Memc[outbuf], szb_outblock,
+ offset, byteswap, wordswap)
+ BLKS_WRT(outparam) = BLKS_WRT(outparam) + 1
+ op = 1
+ }
+ }
+ }
+
+ # Pad last block if short.
+ if (pad_block == YES && op > 1)
+ call reb_pad_block (Memc[outbuf], op, rem_out, outparam,
+ szb_outblock, szb_outrecord, padchar)
+
+ # Write last block
+ if (op > 1) {
+ call reb_write_block (out, Memc[outbuf], op - 1, offset,
+ byteswap, wordswap)
+ op = 1
+ BLKS_WRT(outparam) = BLKS_WRT(outparam) + 1
+ if (pad_record == YES && rem_out < szb_outrecord)
+ RECS_WRT(outparam) = RECS_WRT(outparam) + 1
+ else if (rem_out < szb_outrecord)
+ RECS_WRT(outparam) = RECS_WRT(outparam) + 1
+ }
+
+ }
+
+ call mfree (inbuf, TY_CHAR)
+ if (outbuf != NULL)
+ call mfree (outbuf, TY_CHAR)
+ call close (in)
+ if (out != NULL)
+ call close (out)
+end
+
+
+# REB_PAD_RECORD -- Procedure for padding records.
+
+procedure reb_pad_record (buffer, op, rem_out, szb_outblock, szb_outrecord,
+ padchar)
+
+char buffer[ARB], padchar
+int szb_outblock, szb_outrecord, op, rem_out
+int i, junk
+
+begin
+ junk = rem_out
+ for (i = 1; i <= junk && op <= szb_outblock; i = i + 1) {
+ call bytmov (padchar, 1, buffer, op, 1)
+ op = op + 1
+ rem_out = rem_out - 1
+ }
+
+ if (rem_out == 0)
+ rem_out = szb_outrecord
+end
+
+
+# REB_PAD_BLOCK -- Procedure to pad the last block so that all output blocks
+# will have the same size.
+
+procedure reb_pad_block (buffer, op, rem_out, outparam, szb_outblock,
+ szb_outrecord, padchar)
+
+char buffer[ARB] # data to be padded
+int op # pointer to first element for padding
+int rem_out # number of remaining bytes to be padded in a record
+int outparam[ARB] # output parameters, number of records, blocks written
+int szb_outblock # size in bytes of output block
+int szb_outrecord # size in bytes of an output record
+char padchar # character used for padding
+
+int i, junk
+
+begin
+ junk = szb_outblock - op + 1
+ for (i = 1; i <= junk; i = i + 1) {
+ call bytmov (padchar, 1, buffer, op, 1)
+ op = op + 1
+ rem_out = rem_out - 1
+ if (rem_out == 0) {
+ rem_out = szb_outrecord
+ RECS_WRT(outparam) = RECS_WRT(outparam) + 1
+ }
+ }
+end
+
+
+# REB_WRITE_BLOCK -- Procedure to write blocks using the asynchronous read
+# and write functions in file i/o. Writing must occur on block boundaries.
+
+procedure reb_write_block (fd, buffer, nbytes, offset, byteswap, wordswap)
+
+int fd # output file descriptor
+char buffer[ARB] # data to be output
+int nbytes # number of bytes of data
+long offset # offset in chars in output file for writing
+int byteswap # swap every other byte before output
+int wordswap # swap every other word before output
+
+int nbread
+int awaitb()
+errchk awriteb, awaitb
+
+begin
+ if (byteswap == YES)
+ call bswap2 (buffer, 1, buffer, 1, nbytes)
+ if (wordswap == YES)
+ call bswap4 (buffer, 1, buffer, 1, nbytes)
+ call awriteb (fd, buffer, nbytes, offset)
+ nbread = awaitb (fd)
+ if (nbread == ERR)
+ call error (3, "Error writing block data")
+ else
+ offset = offset + nbread
+end
+
+
+# REB_SKIPOVER -- Procedure to find the first byte containing data given the
+# input block size and the number of input blocks to be skipped.
+
+int procedure reb_skipover (fd, szb_inblock, nskip)
+
+int fd # file descriptor
+int szb_inblock # size of an input block
+int nskip # number of blocks to skip
+
+int first_byte
+long szb_skip, szb_physkip, skip_diff, sz_charoff, loff
+long fstatl()
+int reb_roundup()
+errchk fstatl, seek
+
+begin
+ szb_skip = long (szb_inblock) * long (nskip)
+ szb_physkip = reb_roundup (szb_skip, SZB_CHAR)
+ skip_diff = szb_physkip - szb_skip
+
+ if (skip_diff == 0) {
+ sz_charoff = (szb_physkip / SZB_CHAR) + 1
+ first_byte = 1
+ } else {
+ sz_charoff = (szb_physkip / SZB_CHAR) - 1
+ first_byte = int (szb_skip - (SZB_CHAR * sz_charoff) + 1)
+ }
+
+ loff = long (sz_charoff)
+
+ if (loff > fstatl (fd, F_FILESIZE)) {
+ call seek (fd, EOF)
+ return (EOF)
+ } else {
+ call seek (fd, loff)
+ return (first_byte)
+ }
+end
+
+
+# REB_ROUNDUP -- Procedure to round a number to the next highest number
+# divisible by base.
+
+int procedure reb_roundup (number, base)
+
+int number # number to be rounded upwards
+int base # base for rounding
+
+int value
+
+begin
+ if (mod(number, base) == 0)
+ return (number)
+ else {
+ value = (number/base + 1) * base
+ return (value)
+ }
+end
diff --git a/pkg/dataio/reblock/structure.hlp b/pkg/dataio/reblock/structure.hlp
new file mode 100644
index 00000000..1a7c5221
--- /dev/null
+++ b/pkg/dataio/reblock/structure.hlp
@@ -0,0 +1,50 @@
+.help gcopy "Program Structure"
+.sh
+Program Structure
+.nf
+t_bincopy()
+# Returns when file list is finished or EOT reached.
+
+ read_file (in_fname, out_fname, outparam)
+ Returns when an EOF is encountered on read.
+
+ skipover (fd, szb_outblock, nskip)
+ # Returns the offset of the first data byte in the first char
+ # to contain data of interest or EOF
+
+ record_pad (szb_outblock, szb_outrecord, padchar, buffer, op, rem_out)
+
+ block_pad (szb_outblock, szb_outrecord, padchar, buffer, op, rem_out,
+ outparam)
+.fi
+.sh
+BINCOPY Structure Summary
+.ls t_bincopy
+The main program gets the input and output filenames, creates a list of
+files to be processed and gets the program parameters.
+For each file in the input list READFILE is called,
+and the input and output file names, blocks read and written and records read
+and written are printed.
+The program terminates when the input file list is exhausted or EOT is reached.
+.ls read_file
+READ_FILE opens the input and output devices, allocates space for the input
+and output buffers and copies the data optionally skipping data
+and byteswapping and/or wordswapping the data.
+The routine terminates when an EOF is encountered on a read.
+READ_FILE calls SKIPOVER to find the first data byte of interest and
+RECORD_PAD and BLOCK_PAD to pad records and blocks respectively.
+.ls skipover
+SKIPOVER seeks to the first char containing data of interest and calculates
+the offset in that char of the first byte of interest. Returns the offset
+or EOF if the requested position is past EOF.
+.le
+.ls record_pad
+Record_pad pads input records of szb_inrecord bytes long to output records
+szb_outrecord long.
+.le
+.ls block_pad
+Pads short blocks to size szb_outblock.
+.le
+.le
+.le
+.endhelp
diff --git a/pkg/dataio/reblock/t_reblock.x b/pkg/dataio/reblock/t_reblock.x
new file mode 100644
index 00000000..09c86a9a
--- /dev/null
+++ b/pkg/dataio/reblock/t_reblock.x
@@ -0,0 +1,214 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <fset.h>
+include <error.h>
+include <ctype.h>
+include <mach.h>
+include "reblock.h"
+
+define MAX_RANGES 100
+define SZ_PADCHAR 10
+
+# T_REBLOCK -- Procedure to copy binary files optionally changing the blocking
+# factor. Further documentation in reblock.hlp.
+
+procedure t_reblock ()
+
+char infiles[SZ_FNAME] # list of input files
+char file_list[SZ_LINE] # list of tape file numbers
+char outfiles[SZ_FNAME] # list of output files
+char padchar[SZ_PADCHAR] # character for padding blocks and records
+bool verbose # print messages ?
+
+char in_fname[SZ_FNAME], out_fname[SZ_FNAME], cval
+int inlist, outlist, len_inlist, len_outlist, file_number, file_cnt
+int range[2 * MAX_RANGES + 1]
+int outparam[LEN_OUTPARAM], offset, ip
+
+bool clgetb()
+int fstati(), mtfile(), mtneedfileno(), fntopnb(), fntlenb(), fntgfnb()
+int decode_ranges(), btoi(), clgeti(), get_next_number(), cctoc()
+include "reblock.com"
+
+begin
+ # Flush on a newline if the output is not redirected.
+ if (fstati (STDOUT, F_REDIR) == NO)
+ call fseti (STDOUT, F_FLUSHNL, YES)
+
+ # Get the input and output file(s).
+ call clgstr ("infiles", infiles, SZ_FNAME)
+ call clgstr ("outfiles", outfiles, SZ_FNAME)
+
+ # Get the input file names.
+ if (mtfile (infiles) == YES) {
+ inlist = NULL
+ intape = YES
+ if (mtneedfileno (infiles) == YES)
+ call clgstr ("file_list", file_list, SZ_LINE)
+ else
+ call strcpy ("1", file_list, SZ_LINE)
+ } else {
+ inlist = fntopnb (infiles, NO)
+ len_inlist = fntlenb (inlist)
+ intape = NO
+ if (len_inlist > 0) {
+ call sprintf (file_list, SZ_LINE, "1-%d")
+ call pargi (len_inlist)
+ } else
+ call strcpy ("0", file_list, SZ_LINE)
+ }
+
+ # Decode the tape file number list.
+ if (decode_ranges (file_list, range, MAX_RANGES, len_inlist) == ERR)
+ call error (0, "Illegal file number list.")
+ offset = clgeti ("offset")
+
+ # Get the output file names.
+ if (mtfile (outfiles) == YES) {
+ outlist = NULL
+ len_outlist = len_inlist
+ outtape = YES
+ if (mtneedfileno (outfiles) == YES) {
+ if (! clgetb ("newtape"))
+ call mtfname (outfiles, EOT, out_fname, SZ_FNAME)
+ else
+ call mtfname (outfiles, 1, out_fname, SZ_FNAME)
+ } else
+ call strcpy (outfiles, out_fname, SZ_FNAME)
+ } else {
+ outlist = fntopnb (outfiles, NO)
+ len_outlist = fntlenb (outlist)
+ outtape = NO
+ }
+ if ((len_inlist > 1) && (len_outlist != 1) &&
+ (len_outlist != len_inlist))
+ call error (0,
+ "The number of input and output files is not equal")
+
+ # Get the block and record sizes.
+ szb_outblock = clgeti ("outblock")
+ if (outtape == NO)
+ szb_outblock = INDEFI
+ szb_inrecord = clgeti ("inrecord")
+ szb_outrecord = clgeti ("outrecord")
+ if (IS_INDEFI(szb_inrecord) && !IS_INDEFI(szb_outrecord))
+ szb_inrecord = szb_outrecord
+ if (IS_INDEFI(szb_outrecord) && !IS_INDEFI(szb_inrecord))
+ szb_outrecord = szb_inrecord
+
+ # Get the pad and trim parameters.
+ pad_block = btoi (clgetb ("pad_block"))
+ if (szb_inrecord < szb_outrecord)
+ pad_record = YES
+ else
+ pad_record = NO
+ if (szb_inrecord > szb_outrecord)
+ trim_record = YES
+ else
+ trim_record = NO
+ if (pad_block == YES || pad_record == YES) {
+ call clgstr ("padchar", padchar, SZ_PADCHAR)
+ ip = 1
+ if (cctoc (padchar, ip, cval) <= 0)
+ cval = ' '
+ if (IS_DIGIT (cval))
+ padvalue = TO_INTEG (cval)
+ else
+ padvalue = cval
+ }
+
+ # Tape to disk always requires reblocking.
+ if (intape == YES && outtape == NO)
+ reblock = YES
+ else if (pad_record == YES || pad_block == YES || trim_record == YES)
+ reblock = YES
+ else if (!IS_INDEFI(szb_outblock) || !IS_INDEFI(szb_inrecord) ||
+ !IS_INDEFI(szb_outrecord))
+ reblock = YES
+ else
+ reblock = NO
+
+ # Get remaining parameters.
+ nskip = max (0, clgeti ("skipn"))
+ ncopy = clgeti ("copyn")
+ if (IS_INDEFI(ncopy))
+ ncopy = MAX_INT
+ byteswap = btoi (clgetb ("byteswap"))
+ wordswap = btoi (clgetb ("wordswap"))
+ verbose = clgetb ("verbose")
+
+ # Loop through the files
+ file_cnt = 1
+ file_number = 0
+ while (get_next_number (range, file_number) != EOF) {
+
+ # Construct the input file name.
+ if (intape == YES) {
+ if (mtneedfileno (infiles) == YES)
+ call mtfname (infiles, file_number, in_fname, SZ_FNAME)
+ else
+ call strcpy (infiles, in_fname, SZ_FNAME)
+ } else if (fntgfnb (inlist, in_fname, SZ_FNAME) != EOF)
+ ;
+
+ # Construct the output file name.
+ if (outtape == NO) {
+ if (len_inlist > 1 && len_outlist == 1) {
+ call sprintf (out_fname[1], SZ_FNAME, "%s%03d")
+ call pargstr (outfiles)
+ if (intape == YES)
+ call pargi (file_number + offset)
+ else
+ call pargi (file_cnt)
+ } else if (fntgfnb (outlist, out_fname, SZ_FNAME) != EOF)
+ ;
+ } else if (file_cnt == 2)
+ call mtfname (out_fname, EOT, out_fname, SZ_FNAME)
+
+ iferr {
+
+ if (verbose) {
+ call printf ("File: %s -> %s: ")
+ call pargstr (in_fname)
+ call pargstr (out_fname)
+ }
+
+ call reb_reblock_file (in_fname, out_fname, outparam)
+
+ if (verbose) {
+ if (intape == YES)
+ call printf ("[skip %d blks] ")
+ else
+ call printf ("[skip %d recs] ")
+ call pargi (nskip)
+ call printf ("blks r/w %d/%d ")
+ call pargi (BLKS_RD(outparam))
+ call pargi (BLKS_WRT(outparam))
+ if (reblock == YES) {
+ call printf ("recs r/w %d/%d\n")
+ call pargi (RECS_RD(outparam))
+ call pargi (RECS_WRT(outparam))
+ } else
+ call printf ("\n")
+ }
+
+ } then {
+ call flush (STDOUT)
+ call eprintf ("Cannot read file %s\n")
+ call pargstr (in_fname)
+ } else if (BLKS_RD(outparam) == 0) {
+ if (verbose) {
+ call printf ("Empty file: %s\n")
+ call pargstr (in_fname)
+ }
+ break
+ } else {
+ file_cnt = file_cnt + 1
+ }
+ }
+
+ if (inlist != NULL)
+ call fntclsb (inlist)
+ if (outlist != NULL)
+ call fntclsb (outlist)
+end
diff --git a/pkg/dataio/rfits.par b/pkg/dataio/rfits.par
new file mode 100644
index 00000000..6ea66586
--- /dev/null
+++ b/pkg/dataio/rfits.par
@@ -0,0 +1,12 @@
+fits_file,f,a,"mta",,,"FITS data source"
+file_list,s,a,"",,,"File/extensions list"
+iraf_file,f,a,"",,,"IRAF filename"
+make_image,b,h,yes,,,"Create an IRAF image?"
+long_header,b,h,no,,,"Print FITS header cards?"
+short_header,b,h,yes,,,"Print short header?"
+datatype,s,h,"",,,"IRAF data type"
+blank,r,h,0.,,,"Blank value"
+scale,b,h,yes,,,"Scale the data?"
+oldirafname,b,h,no,,,"Use old IRAF name in place of iraf_file?"
+offset,i,h,0,,,"Tape file offset"
+mode,s,h,"ql",,,
diff --git a/pkg/dataio/rtextimage.par b/pkg/dataio/rtextimage.par
new file mode 100644
index 00000000..86614e90
--- /dev/null
+++ b/pkg/dataio/rtextimage.par
@@ -0,0 +1,9 @@
+# Parameter file for t_rtextimage, text file to IRAF image converter
+
+input,f,a,,,,Input text file
+output,f,a,,,,Output image file
+otype,s,h,"",,,Pixel type on output
+header,b,h,yes,,,Read FITS header preceding pixels?
+pixels,b,h,yes,,,Read pixels?
+nskip,i,h,0,,,Number of lines to skip
+dim,s,h,,,,Image dimension string
diff --git a/pkg/dataio/t2d.par b/pkg/dataio/t2d.par
new file mode 100644
index 00000000..a50cbbd5
--- /dev/null
+++ b/pkg/dataio/t2d.par
@@ -0,0 +1,5 @@
+input,s,a,,,,Input file descriptor
+ofroot,s,a,,,,Output file root name
+files,s,a,,,,List of files
+verbose,b,h,yes,,,Print out progress reports
+errignore,b,h,yes,,,Assume an error record is zero bytes long
diff --git a/pkg/dataio/t2d/mkpkg b/pkg/dataio/t2d/mkpkg
new file mode 100644
index 00000000..32b680dd
--- /dev/null
+++ b/pkg/dataio/t2d/mkpkg
@@ -0,0 +1,10 @@
+# T2d contributions to Dataio Library
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ t_t2d.x <fset.h> <error.h> <mach.h>
+ ;
diff --git a/pkg/dataio/t2d/t_t2d.x b/pkg/dataio/t2d/t_t2d.x
new file mode 100644
index 00000000..f21fe4da
--- /dev/null
+++ b/pkg/dataio/t2d/t_t2d.x
@@ -0,0 +1,280 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <fset.h>
+include <mach.h>
+
+define OBUF_PAD 35536
+define SZ_OBUF 100000
+define SWAP {temp=$1;$1=$2;$2=temp}
+define MAX_RANGES 200
+
+# T2D -- This is an asynchronous tape to disk copy routine.
+# T2d sets up a large output buffer (many blocks long) and reads from
+# the input device directly into this output buffer, keeping track of where in
+# the output buffer it is. When it reaches a predetermined point in the output
+# buffer, it writes an integral number of blocks to the output device, moves
+# the leftover input data to the beginning of the alternate buffer and
+# continues reading. (until EOF, then it writes out whatever is left).
+# The user specifies which files on tape he or she wants and a root name
+# for the output file names.
+
+procedure t_t2d()
+
+char input[SZ_FNAME]
+char files[SZ_LINE]
+char ofroot[SZ_FNAME] # Root file name, output files.
+
+char tapename[SZ_FNAME]
+char dfilename[SZ_FNAME] # Disk file name.
+int filerange[2 * MAX_RANGES + 1]
+int nfiles, filenumber, numrecords
+bool verbose
+bool errignore
+
+int mtfile(), strlen(), decode_ranges(), mtneedfileno()
+int get_next_number(), tape2disk()
+bool clgetb()
+
+begin
+ call fseti (STDOUT, F_FLUSHNL, YES)
+
+ # Get input file(s).
+ call clgstr ("input", input, SZ_FNAME)
+ if (mtfile(input) == NO || mtneedfileno(input) == NO)
+ call strcpy ("1", files, SZ_LINE)
+ else
+ call clgstr ("files", files, SZ_LINE)
+
+ if (decode_ranges (files, filerange, MAX_RANGES, nfiles) == ERR)
+ call error (0, "Illegal file number list.")
+
+ # Get root output filename, the verbose flag, and the error-ignore flag.
+ call clgstr ("ofroot", ofroot, SZ_FNAME)
+ verbose = clgetb ("verbose")
+ errignore = clgetb ("errignore")
+ filenumber = 0
+
+ if (mtfile(input) == YES && mtneedfileno(input) == YES) {
+ # Loop over files
+ while (get_next_number (filerange, filenumber) != EOF) {
+
+ # Assemble the appropriate tape file name.
+ call mtfname (input, filenumber, tapename, SZ_FNAME)
+
+ # Assemble the appropriate disk file name.
+ call strcpy (ofroot, dfilename, SZ_FNAME)
+ call sprintf (dfilename[strlen(ofroot) + 1], SZ_FNAME, "%03d")
+ call pargi (filenumber)
+
+ # Print out the tape file we are trying to read.
+ if (verbose) {
+ call printf ("%s ")
+ call pargstr (tapename)
+ call flush (STDOUT)
+ }
+
+
+ # Do the tape to disk transfer.
+ iferr {
+ numrecords = tape2disk (tapename, dfilename, errignore)
+ } then {
+ call eprintf ("Error reading file: %s\n")
+ call pargstr (tapename)
+ call erract (EA_WARN)
+ next
+ } else if (numrecords == 0) {
+ call deletefg (dfilename, YES, YES)
+ if (verbose)
+ call printf ("Tape at EOT\n")
+ break
+ } else if (verbose){
+ call printf (" wrote `%s'\n")
+ call pargstr(dfilename)
+ }
+
+ } # End while.
+
+ } else {
+
+ # Print out the tape file we are trying to read.
+ if (verbose) {
+ call printf ("%s ")
+ call pargstr(input)
+ call flush (STDOUT)
+ }
+
+ # Do the tape to disk transfer.
+ iferr {
+ numrecords = tape2disk (input, ofroot, errignore)
+ } then {
+ call eprintf ("Error reading file: %s\n")
+ call pargstr (input)
+ call erract (EA_WARN)
+ } else if (numrecords == 0) {
+ call deletefg (input, YES, YES)
+ if (verbose)
+ call printf ("Tape at EOT\n")
+ } else if (verbose){
+ call printf (" wrote `%s'\n")
+ call pargstr(ofroot)
+ }
+ }
+end
+
+
+# TAPE2DISK -- This is the actual tape to disk copy routine.
+
+int procedure tape2disk (infile, outfile, errignore)
+
+char infile[SZ_FNAME]
+char outfile[SZ_FNAME]
+bool errignore
+
+bool inblock
+int blksize, mxbufszo, numblks, cutoff, obufsize, temp, numrecords
+int inblksize, innumblks, toread, mxbufszi
+long ooffset
+int nchars, stat, in, out, lastnchars
+pointer op, otop, bufa, bufb
+
+int fstati(), mtopen(), open(), await()
+
+begin
+ # Open the input and output files.
+ in = mtopen (infile, READ_ONLY, 0)
+ out = open (outfile, NEW_FILE, BINARY_FILE)
+
+ # Find out how big the blocks are on the output device. Calculate
+ # an output buffer size which is an integral number of blocks long
+ # and is long enough to permit many input reads per output write.
+ # Here, I use the maximum output buffer size.
+
+ blksize = fstati (out, F_BLKSIZE) # Outputfile block size
+ mxbufszo = fstati (out, F_MAXBUFSIZE) # Maximum output buffer size
+ mxbufszi = fstati (in, F_MAXBUFSIZE) # Maximum in buffer size
+ if (mxbufszo <= 0) # if no max, set a max
+ mxbufszo = SZ_OBUF
+ if (mxbufszi <= 0) # if no max, set a max
+ mxbufszi = OBUF_PAD
+ numblks = mxbufszo / blksize # No. blocks in 'out' buffer
+
+ # Find out if the input device is blocked and if it is, the block
+ # size.
+ inblksize = fstati (in, F_BLKSIZE) # Inputfile block size
+ inblock = true
+ if (inblksize == 0)
+ inblock = false
+
+ # Put an extra OBUF_PAD chars in the output buffer to allow for
+ # overruns on the last input read before we do an output write.
+
+ cutoff = numblks * blksize
+ obufsize = cutoff + OBUF_PAD
+
+ call malloc (bufa, obufsize, TY_CHAR) # Allocate output buffer.
+ call malloc (bufb, obufsize, TY_CHAR) # Other output buffer
+ op = bufa # Movable pointer inside buffer
+ otop = bufa + cutoff # Point to full position (top)
+
+ ooffset = 1 # Output offset.
+ nchars = 0 # Number of chars.
+ numrecords = 0 # Number of records read.
+ lastnchars = 0
+
+ # Main Loop.
+ repeat {
+ # A series of reads of the input file are required to fill the
+ # output buffer.
+
+ if (inblock) {
+ innumblks = (cutoff - (op - bufa)) / inblksize
+ toread = (innumblks+1) * inblksize
+
+ call aread (in, Memc[op], toread, 1)
+ nchars = await (in)
+ if (nchars <= 0) {
+ if (nchars == ERR) {
+ # report read error
+ call eprintf ("error on read\n")
+ call flush (STDERR)
+
+ # If errignore, do not move pointer, else,
+ # assume data.
+ if (!errignore)
+ nchars = toread
+ }
+ # If we found the EOF
+ if (nchars == 0) {
+ cutoff = op - bufa
+ }
+ } else if (nchars < toread) {
+ numrecords = numrecords + 1
+ cutoff = op - bufa + nchars
+ nchars = 0
+ } else {
+ numrecords = numrecords + 1
+ op = op + nchars
+ }
+
+ } else {
+
+ repeat {
+ call aread (in, Memc[op], mxbufszi, 1)
+ nchars = await (in)
+
+ if (nchars <= 0) {
+ if (nchars == ERR) {
+ # report read error
+ call eprintf ("error on read\n")
+ call flush (STDERR)
+
+ # If errignore, do not move pointer, else,
+ # assume data.
+ if (!errignore)
+ nchars = lastnchars
+ }
+ # If we found the EOF
+ if (nchars == 0) {
+ cutoff = op - bufa
+ break
+ }
+ }
+
+ if (nchars > 0) {
+ numrecords = numrecords + 1
+ lastnchars = nchars
+ op = op + nchars
+ }
+
+ } until (op >= otop)
+ } # end of 'if (inblock)'
+
+ # Wait for last write to finish and initiate next write.
+ stat = await (out)
+ if (stat == ERR)
+ call eprintf ("error on write\n")
+ call awrite (out, Memc[bufa], cutoff, ooffset)
+ ooffset = ooffset + cutoff # Update the output offset.
+
+ # Copy leftover buffer elements into the bottom of other buffer.
+ if ((op - otop) > 0)
+ call amovc (Memc[otop], Memc[bufb], op - otop)
+ op = bufb + (op - otop)
+
+ # Swap buffers
+ SWAP (bufa, bufb)
+ otop = bufa + cutoff
+ } until (nchars == 0) # all done
+
+ stat = await (out) # wait for final write to finish.
+ if (stat == ERR)
+ call eprintf ("error on write\n")
+
+ call close (in)
+ call close (out)
+ call mfree (bufa, TY_CHAR)
+ call mfree (bufb, TY_CHAR)
+
+ return (numrecords)
+end
diff --git a/pkg/dataio/txtbin.par b/pkg/dataio/txtbin.par
new file mode 100644
index 00000000..09e9bf97
--- /dev/null
+++ b/pkg/dataio/txtbin.par
@@ -0,0 +1,4 @@
+mode,s,h,"ql",,,
+text_file,s,a,,,,Input file name(s)
+binary_file,s,a,,,,Output file name(s)
+verbose,b,h,yes,,,Print messages?
diff --git a/pkg/dataio/wcardimage.par b/pkg/dataio/wcardimage.par
new file mode 100644
index 00000000..610a867d
--- /dev/null
+++ b/pkg/dataio/wcardimage.par
@@ -0,0 +1,11 @@
+mode,s,h,"ql",,,
+textfile,s,a,,,,"Text file(s)"
+cardfile,s,a,,,,"Card image file(s)"
+new_tape,b,a,,,,"Blank tape?"
+contn_string,s,h,>>,,,"Marker for oversize lines"
+verbose,b,h,yes,,,"Print messages of actions performed?"
+detab,b,h,yes,,,"Detab string and replace with blanks?"
+card_length,i,h,80,,,"Columns per card"
+cards_per_blk,i,h,50,,,"Card images per block"
+ebcdic,b,h,no,,,"Convert from ASCII to EBCDIC?"
+ibm,b,h,no,,,"Convert from ASCII to IBM(EBCDIC)?"
diff --git a/pkg/dataio/wfits.par b/pkg/dataio/wfits.par
new file mode 100644
index 00000000..eb48586b
--- /dev/null
+++ b/pkg/dataio/wfits.par
@@ -0,0 +1,18 @@
+# WFITS parameters
+
+iraf_files,s,a,,,,IRAF images
+fits_files,f,a,,,,FITS filename(s)
+newtape,b,a,,,,Blank tape?
+fextn,s,h,"fits",,,Extension to append to output disk FITS filename(s)
+extensions,b,h,no,,,Write all images to a single FITS file ?
+global_hdr,b,h,yes,,,Prepend a global header to the FITS extensions file ?
+make_image,b,h,yes,,,Create a FITS image file?
+long_header,b,h,no,,,Print FITS header cards?
+short_header,b,h,yes,,,Print short header?
+bitpix,i,h,0,,,FITS bits per pixel
+blocking_factor,i,h,0,0,10,FITS tape blocking factor
+scale,b,h,yes,,,Scale data?
+autoscale,b,h,yes,,,Auto_scaling?
+bscale,r,a,1.0,,,FITS bscale
+bzero,r,a,0.0,,,FITS bzero
+mode,s,h,ql,,,
diff --git a/pkg/dataio/wtextimage.par b/pkg/dataio/wtextimage.par
new file mode 100644
index 00000000..276a9728
--- /dev/null
+++ b/pkg/dataio/wtextimage.par
@@ -0,0 +1,8 @@
+# Parameter file for t_wtextimage, IRAF image to text file converter
+
+input,f,a,,,,Input image file
+output,f,a,,,,Output text file
+header,b,h,yes,,,Print header information?
+pixels,b,h,yes,,,Print pixel values?
+format,s,h,"",,,Pixel format <w.d[defgz]>
+maxlinelen,i,h,80,1,322,Maximum line length output
diff --git a/pkg/dataio/x_dataio.x b/pkg/dataio/x_dataio.x
new file mode 100644
index 00000000..598c1e6e
--- /dev/null
+++ b/pkg/dataio/x_dataio.x
@@ -0,0 +1,17 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# Dataio package.
+
+task rcardimage = t_rcardimage,
+ wcardimage = t_wcardimage,
+ mtexamine = t_mtexamine,
+ txtbin = t_txtbin,
+ bintxt = t_bintxt,
+ rtextimage = t_rtextimage,
+ wtextimage = t_wtextimage,
+ reblock = t_reblock,
+ rfits = t_rfits,
+ wfits = t_wfits,
+ t2d = t_t2d,
+ import = t_import,
+ export = t_export