aboutsummaryrefslogtreecommitdiff
path: root/pkg/utilities/nttools
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/utilities/nttools')
-rw-r--r--pkg/utilities/nttools/README32
-rw-r--r--pkg/utilities/nttools/atools/mkpkg10
-rw-r--r--pkg/utilities/nttools/atools/taextract.x214
-rw-r--r--pkg/utilities/nttools/atools/taincr.x55
-rw-r--r--pkg/utilities/nttools/atools/tainsert.x260
-rw-r--r--pkg/utilities/nttools/copyone/addslash.x32
-rw-r--r--pkg/utilities/nttools/copyone/datatype.x79
-rw-r--r--pkg/utilities/nttools/copyone/filetype.h5
-rw-r--r--pkg/utilities/nttools/copyone/filetype.x28
-rw-r--r--pkg/utilities/nttools/copyone/filetype.x.OLD61
-rw-r--r--pkg/utilities/nttools/copyone/getimghdr.x35
-rw-r--r--pkg/utilities/nttools/copyone/gettabdat.x111
-rw-r--r--pkg/utilities/nttools/copyone/gettabhdr.x55
-rw-r--r--pkg/utilities/nttools/copyone/isdouble.x37
-rw-r--r--pkg/utilities/nttools/copyone/keypar.x109
-rw-r--r--pkg/utilities/nttools/copyone/keytab.x113
-rw-r--r--pkg/utilities/nttools/copyone/mkpkg29
-rw-r--r--pkg/utilities/nttools/copyone/parkey.x71
-rw-r--r--pkg/utilities/nttools/copyone/partab.x51
-rw-r--r--pkg/utilities/nttools/copyone/putimghdr.x118
-rw-r--r--pkg/utilities/nttools/copyone/puttabdat.x106
-rw-r--r--pkg/utilities/nttools/copyone/puttabhdr.x104
-rw-r--r--pkg/utilities/nttools/copyone/tabaccess.x19
-rw-r--r--pkg/utilities/nttools/copyone/tabhdrtyp.x34
-rw-r--r--pkg/utilities/nttools/copyone/tabkey.x94
-rw-r--r--pkg/utilities/nttools/copyone/tabpar.x54
-rw-r--r--pkg/utilities/nttools/doc/axispar.hlp138
-rw-r--r--pkg/utilities/nttools/doc/dvpar.hlp68
-rw-r--r--pkg/utilities/nttools/doc/gtedit.hlp116
-rw-r--r--pkg/utilities/nttools/doc/gtpar.hlp117
-rw-r--r--pkg/utilities/nttools/doc/imtab.hlp169
-rw-r--r--pkg/utilities/nttools/doc/keypar.hlp83
-rw-r--r--pkg/utilities/nttools/doc/keyselect.hlp246
-rw-r--r--pkg/utilities/nttools/doc/keytab.hlp61
-rw-r--r--pkg/utilities/nttools/doc/parkey.hlp73
-rw-r--r--pkg/utilities/nttools/doc/partab.hlp62
-rw-r--r--pkg/utilities/nttools/doc/pltpar.hlp160
-rw-r--r--pkg/utilities/nttools/doc/tabim.hlp98
-rw-r--r--pkg/utilities/nttools/doc/tabkey.hlp68
-rw-r--r--pkg/utilities/nttools/doc/tabpar.hlp95
-rw-r--r--pkg/utilities/nttools/doc/taextract.hlp109
-rw-r--r--pkg/utilities/nttools/doc/tainsert.hlp132
-rw-r--r--pkg/utilities/nttools/doc/tcalc.hlp153
-rw-r--r--pkg/utilities/nttools/doc/tchcol.hlp80
-rw-r--r--pkg/utilities/nttools/doc/tcheck.hlp137
-rw-r--r--pkg/utilities/nttools/doc/tchsize.hlp158
-rw-r--r--pkg/utilities/nttools/doc/tcopy.hlp113
-rw-r--r--pkg/utilities/nttools/doc/tcreate.hlp378
-rw-r--r--pkg/utilities/nttools/doc/tdelete.hlp74
-rw-r--r--pkg/utilities/nttools/doc/tdiffer.hlp65
-rw-r--r--pkg/utilities/nttools/doc/tdump.hlp150
-rw-r--r--pkg/utilities/nttools/doc/tedit.hlp295
-rw-r--r--pkg/utilities/nttools/doc/texpand.hlp159
-rw-r--r--pkg/utilities/nttools/doc/thedit.hlp208
-rw-r--r--pkg/utilities/nttools/doc/thistogram.hlp152
-rw-r--r--pkg/utilities/nttools/doc/thselect.hlp90
-rw-r--r--pkg/utilities/nttools/doc/tinfo.hlp125
-rw-r--r--pkg/utilities/nttools/doc/tintegrate.hlp97
-rw-r--r--pkg/utilities/nttools/doc/tjoin.hlp120
-rw-r--r--pkg/utilities/nttools/doc/tlcol.hlp75
-rw-r--r--pkg/utilities/nttools/doc/tlinear.hlp127
-rw-r--r--pkg/utilities/nttools/doc/tmatch.hlp225
-rw-r--r--pkg/utilities/nttools/doc/tmerge.hlp231
-rw-r--r--pkg/utilities/nttools/doc/tprint.hlp276
-rw-r--r--pkg/utilities/nttools/doc/tproduct.hlp48
-rw-r--r--pkg/utilities/nttools/doc/tproject.hlp79
-rw-r--r--pkg/utilities/nttools/doc/tquery.hlp115
-rw-r--r--pkg/utilities/nttools/doc/tread.hlp159
-rw-r--r--pkg/utilities/nttools/doc/trebin.hlp257
-rw-r--r--pkg/utilities/nttools/doc/tselect.hlp147
-rw-r--r--pkg/utilities/nttools/doc/tsort.hlp84
-rw-r--r--pkg/utilities/nttools/doc/tstat.hlp225
-rw-r--r--pkg/utilities/nttools/doc/ttranspose.hlp139
-rw-r--r--pkg/utilities/nttools/doc/tunits.hlp143
-rw-r--r--pkg/utilities/nttools/doc/tupar.hlp365
-rw-r--r--pkg/utilities/nttools/doc/wcspars.hlp184
-rw-r--r--pkg/utilities/nttools/doc/wlpars.hlp440
-rw-r--r--pkg/utilities/nttools/gtedit.par11
-rw-r--r--pkg/utilities/nttools/gtedit/gtdelete.x360
-rw-r--r--pkg/utilities/nttools/gtedit/gtdodel.x41
-rw-r--r--pkg/utilities/nttools/gtedit/gtedit.key25
-rw-r--r--pkg/utilities/nttools/gtedit/gthinfo.x69
-rw-r--r--pkg/utilities/nttools/gtedit/gtplot.x501
-rw-r--r--pkg/utilities/nttools/gtedit/gtrdxycol.x50
-rw-r--r--pkg/utilities/nttools/gtedit/gtupdate.x36
-rw-r--r--pkg/utilities/nttools/gtedit/gtwrdata.x90
-rw-r--r--pkg/utilities/nttools/gtedit/gtwrhead.x47
-rw-r--r--pkg/utilities/nttools/gtedit/mkpkg19
-rw-r--r--pkg/utilities/nttools/gtedit/t_gtedit.x184
-rw-r--r--pkg/utilities/nttools/gtpar.par27
-rw-r--r--pkg/utilities/nttools/imtab.par8
-rw-r--r--pkg/utilities/nttools/imtab/imtab.h4
-rw-r--r--pkg/utilities/nttools/imtab/imtab.x476
-rw-r--r--pkg/utilities/nttools/imtab/itbwcs.x129
-rw-r--r--pkg/utilities/nttools/imtab/mkpkg13
-rw-r--r--pkg/utilities/nttools/imtab/tabim.x176
-rw-r--r--pkg/utilities/nttools/keypar.par6
-rw-r--r--pkg/utilities/nttools/keyselect.par6
-rw-r--r--pkg/utilities/nttools/keyselect/expr.x193
-rw-r--r--pkg/utilities/nttools/keyselect/keyselect.com9
-rw-r--r--pkg/utilities/nttools/keyselect/keyselect.h17
-rw-r--r--pkg/utilities/nttools/keyselect/keyselect.x122
-rw-r--r--pkg/utilities/nttools/keyselect/keyword.x253
-rw-r--r--pkg/utilities/nttools/keyselect/list.x215
-rw-r--r--pkg/utilities/nttools/keyselect/mkpkg15
-rw-r--r--pkg/utilities/nttools/keyselect/tab.x353
-rw-r--r--pkg/utilities/nttools/keytab.par7
-rw-r--r--pkg/utilities/nttools/lib/allcols.x29
-rw-r--r--pkg/utilities/nttools/lib/allrows.x29
-rw-r--r--pkg/utilities/nttools/lib/compare.com7
-rw-r--r--pkg/utilities/nttools/lib/compare.x258
-rw-r--r--pkg/utilities/nttools/lib/ftnexpr.x127
-rw-r--r--pkg/utilities/nttools/lib/gettabcol.x67
-rw-r--r--pkg/utilities/nttools/lib/inquotes.x121
-rw-r--r--pkg/utilities/nttools/lib/invert.x55
-rw-r--r--pkg/utilities/nttools/lib/mjd.x94
-rw-r--r--pkg/utilities/nttools/lib/mkpkg33
-rw-r--r--pkg/utilities/nttools/lib/movenulls.x35
-rw-r--r--pkg/utilities/nttools/lib/msort.x113
-rw-r--r--pkg/utilities/nttools/lib/newcolnam.x97
-rw-r--r--pkg/utilities/nttools/lib/reloperr.h3
-rw-r--r--pkg/utilities/nttools/lib/reorder.x60
-rw-r--r--pkg/utilities/nttools/lib/select.x99
-rw-r--r--pkg/utilities/nttools/lib/tabvar.x118
-rw-r--r--pkg/utilities/nttools/lib/tbfile.x85
-rw-r--r--pkg/utilities/nttools/lib/tbleval.x159
-rw-r--r--pkg/utilities/nttools/lib/tbljoin.x168
-rw-r--r--pkg/utilities/nttools/lib/tblmerge.x162
-rw-r--r--pkg/utilities/nttools/lib/tblsearch.x104
-rw-r--r--pkg/utilities/nttools/lib/tblsort.x39
-rw-r--r--pkg/utilities/nttools/lib/tblsort1.x157
-rw-r--r--pkg/utilities/nttools/lib/tblsortm.x168
-rw-r--r--pkg/utilities/nttools/lib/tblterm.com7
-rw-r--r--pkg/utilities/nttools/lib/tblterm.x256
-rw-r--r--pkg/utilities/nttools/lib/tctexp.x442
-rw-r--r--pkg/utilities/nttools/lib/tldtype.x70
-rw-r--r--pkg/utilities/nttools/lib/tuopen.x197
-rw-r--r--pkg/utilities/nttools/lib/unique.x64
-rw-r--r--pkg/utilities/nttools/mkpkg80
-rw-r--r--pkg/utilities/nttools/nttools.cl60
-rw-r--r--pkg/utilities/nttools/nttools.hd91
-rw-r--r--pkg/utilities/nttools/nttools.hlp244
-rw-r--r--pkg/utilities/nttools/nttools.men61
-rw-r--r--pkg/utilities/nttools/nttools.par3
-rw-r--r--pkg/utilities/nttools/parkey.par5
-rw-r--r--pkg/utilities/nttools/partab.par5
-rw-r--r--pkg/utilities/nttools/stxtools/changt.x98
-rw-r--r--pkg/utilities/nttools/stxtools/checkdim.x24
-rw-r--r--pkg/utilities/nttools/stxtools/cif.h95
-rw-r--r--pkg/utilities/nttools/stxtools/cif.x806
-rw-r--r--pkg/utilities/nttools/stxtools/clgnone.x37
-rw-r--r--pkg/utilities/nttools/stxtools/copyimg.x78
-rw-r--r--pkg/utilities/nttools/stxtools/doc/wcs.doc177
-rw-r--r--pkg/utilities/nttools/stxtools/errxit.x30
-rw-r--r--pkg/utilities/nttools/stxtools/fbuild.x97
-rw-r--r--pkg/utilities/nttools/stxtools/fparse.x170
-rw-r--r--pkg/utilities/nttools/stxtools/grmimy.x68
-rw-r--r--pkg/utilities/nttools/stxtools/isblank.x18
-rw-r--r--pkg/utilities/nttools/stxtools/lubksb.f50
-rw-r--r--pkg/utilities/nttools/stxtools/lubksd.f53
-rw-r--r--pkg/utilities/nttools/stxtools/ludcmd.x99
-rw-r--r--pkg/utilities/nttools/stxtools/ludcmp.x87
-rw-r--r--pkg/utilities/nttools/stxtools/mkpkg54
-rw-r--r--pkg/utilities/nttools/stxtools/od/mkpkg15
-rw-r--r--pkg/utilities/nttools/stxtools/od/od.h32
-rw-r--r--pkg/utilities/nttools/stxtools/od/odget.x56
-rw-r--r--pkg/utilities/nttools/stxtools/od/odmap.x250
-rw-r--r--pkg/utilities/nttools/stxtools/od/odopep.x56
-rw-r--r--pkg/utilities/nttools/stxtools/od/odpare.x84
-rw-r--r--pkg/utilities/nttools/stxtools/od/odput.x50
-rw-r--r--pkg/utilities/nttools/stxtools/od/odsetn.x29
-rw-r--r--pkg/utilities/nttools/stxtools/od/odunmp.x44
-rw-r--r--pkg/utilities/nttools/stxtools/od/odwcsn.x39
-rw-r--r--pkg/utilities/nttools/stxtools/postexit.x52
-rw-r--r--pkg/utilities/nttools/stxtools/savgol.x140
-rw-r--r--pkg/utilities/nttools/stxtools/sbuf.h15
-rw-r--r--pkg/utilities/nttools/stxtools/sbuf.x110
-rw-r--r--pkg/utilities/nttools/stxtools/sgcone.x94
-rw-r--r--pkg/utilities/nttools/stxtools/similar.x127
-rw-r--r--pkg/utilities/nttools/stxtools/sp_util/mkpkg16
-rw-r--r--pkg/utilities/nttools/stxtools/sp_util/spchag.x64
-rw-r--r--pkg/utilities/nttools/stxtools/sp_util/spdise.x44
-rw-r--r--pkg/utilities/nttools/stxtools/sp_util/spmapt.x94
-rw-r--r--pkg/utilities/nttools/stxtools/sp_util/sprote.x49
-rw-r--r--pkg/utilities/nttools/stxtools/sp_util/spstry.x24
-rw-r--r--pkg/utilities/nttools/stxtools/sp_util/sptras.x35
-rw-r--r--pkg/utilities/nttools/stxtools/sp_util/spw2ld.x50
-rw-r--r--pkg/utilities/nttools/stxtools/sp_util/spwcss.x90
-rw-r--r--pkg/utilities/nttools/stxtools/strjust.x31
-rw-r--r--pkg/utilities/nttools/stxtools/stxgetcoord.x182
-rw-r--r--pkg/utilities/nttools/stxtools/template.h21
-rw-r--r--pkg/utilities/nttools/stxtools/tpbreak.x80
-rw-r--r--pkg/utilities/nttools/stxtools/tpclose.x21
-rw-r--r--pkg/utilities/nttools/stxtools/tpcount.x134
-rw-r--r--pkg/utilities/nttools/stxtools/tpfetch.x43
-rw-r--r--pkg/utilities/nttools/stxtools/tpgroup.x87
-rw-r--r--pkg/utilities/nttools/stxtools/tpimtype.x116
-rw-r--r--pkg/utilities/nttools/stxtools/tpopen.x38
-rw-r--r--pkg/utilities/nttools/stxtools/tpparse.x108
-rw-r--r--pkg/utilities/nttools/stxtools/vex.com11
-rw-r--r--pkg/utilities/nttools/stxtools/vex.h107
-rw-r--r--pkg/utilities/nttools/stxtools/vexcompile.x973
-rw-r--r--pkg/utilities/nttools/stxtools/vexcompile.y616
-rw-r--r--pkg/utilities/nttools/stxtools/vexeval.x228
-rw-r--r--pkg/utilities/nttools/stxtools/vexfree.x22
-rw-r--r--pkg/utilities/nttools/stxtools/vexfunc.x2011
-rw-r--r--pkg/utilities/nttools/stxtools/vexstack.x585
-rw-r--r--pkg/utilities/nttools/stxtools/wcslab/mkpkg17
-rw-r--r--pkg/utilities/nttools/stxtools/wcslab/mkpkg.ori18
-rw-r--r--pkg/utilities/nttools/stxtools/wcslab/psiescape.h80
-rw-r--r--pkg/utilities/nttools/stxtools/wcslab/t_wcslab.x136
-rw-r--r--pkg/utilities/nttools/stxtools/wcslab/wcs_desc.h219
-rw-r--r--pkg/utilities/nttools/stxtools/wcslab/wcslab.h98
-rw-r--r--pkg/utilities/nttools/stxtools/wcslab/wcslab.x935
-rw-r--r--pkg/utilities/nttools/stxtools/wcslab/wlgrid.x448
-rw-r--r--pkg/utilities/nttools/stxtools/wcslab/wllabel.x1100
-rw-r--r--pkg/utilities/nttools/stxtools/wcslab/wllabel.x.ori1077
-rw-r--r--pkg/utilities/nttools/stxtools/wcslab/wlsetup.x1000
-rw-r--r--pkg/utilities/nttools/stxtools/wcslab/wlutil.x390
-rw-r--r--pkg/utilities/nttools/stxtools/wcslab/wlwcslab.x181
-rw-r--r--pkg/utilities/nttools/stxtools/word.x229
-rw-r--r--pkg/utilities/nttools/stxtools/xtwcs.x1286
-rw-r--r--pkg/utilities/nttools/tabim.par11
-rw-r--r--pkg/utilities/nttools/tabkey.par7
-rw-r--r--pkg/utilities/nttools/tabpar.par7
-rw-r--r--pkg/utilities/nttools/tabvar.com9
-rw-r--r--pkg/utilities/nttools/taextract.par10
-rw-r--r--pkg/utilities/nttools/tainsert.par11
-rw-r--r--pkg/utilities/nttools/tcalc.par7
-rw-r--r--pkg/utilities/nttools/tcalc/mkpkg11
-rw-r--r--pkg/utilities/nttools/tcalc/tcalc.x132
-rw-r--r--pkg/utilities/nttools/tchcol.par7
-rw-r--r--pkg/utilities/nttools/tchcol/mkpkg20
-rw-r--r--pkg/utilities/nttools/tchcol/tchcol.x162
-rw-r--r--pkg/utilities/nttools/tcheck.par3
-rw-r--r--pkg/utilities/nttools/tcheck/cmdsplit.x57
-rw-r--r--pkg/utilities/nttools/tcheck/mkpkg13
-rw-r--r--pkg/utilities/nttools/tcheck/tcheck.h4
-rw-r--r--pkg/utilities/nttools/tcheck/tcheck.x91
-rw-r--r--pkg/utilities/nttools/tcheck/wrtcheck.x61
-rw-r--r--pkg/utilities/nttools/tchsize.par8
-rw-r--r--pkg/utilities/nttools/tchsize/mkpkg11
-rw-r--r--pkg/utilities/nttools/tchsize/tchsize.x173
-rw-r--r--pkg/utilities/nttools/tcopy.par4
-rw-r--r--pkg/utilities/nttools/tcopy/iswholetab.x24
-rw-r--r--pkg/utilities/nttools/tcopy/mkpkg13
-rw-r--r--pkg/utilities/nttools/tcopy/tcopy.x283
-rw-r--r--pkg/utilities/nttools/tcopy/tdelete.x126
-rw-r--r--pkg/utilities/nttools/tcopy/trename.x185
-rw-r--r--pkg/utilities/nttools/tcreate.par12
-rw-r--r--pkg/utilities/nttools/tcreate/gnextl.x152
-rw-r--r--pkg/utilities/nttools/tcreate/mkpkg12
-rw-r--r--pkg/utilities/nttools/tcreate/tcreate.x958
-rw-r--r--pkg/utilities/nttools/tdelete.par5
-rw-r--r--pkg/utilities/nttools/tdiffer.par6
-rw-r--r--pkg/utilities/nttools/tdiffer/mkpkg12
-rw-r--r--pkg/utilities/nttools/tdiffer/tbldiff.x99
-rw-r--r--pkg/utilities/nttools/tdiffer/tdiffer.x92
-rw-r--r--pkg/utilities/nttools/tdump.par8
-rw-r--r--pkg/utilities/nttools/tedit.par6
-rw-r--r--pkg/utilities/nttools/tedit/bell.x19
-rw-r--r--pkg/utilities/nttools/tedit/command.com6
-rw-r--r--pkg/utilities/nttools/tedit/command.h21
-rw-r--r--pkg/utilities/nttools/tedit/command.x1458
-rw-r--r--pkg/utilities/nttools/tedit/display/curses.h86
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/README387
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/addch.x30
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/addstr.x157
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/bindstruct.x35
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/box.x56
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/clear.x35
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/clearok.x21
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/clrtobot.x56
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/clrtoeol.x45
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/delch.x41
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/deleteln.x41
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/delwin.x42
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/echo.x23
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/endwin.x34
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/erase.x37
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/freescreen.x13
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/getch.x53
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/getscreen.x48
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/getstr.x317
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/getstruct.x27
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/getyx.x22
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/hidewin.x40
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/inch.x49
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/initscr.x33
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/insch.x51
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/insertln.x41
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/leaveok.x21
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/mkpkg49
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/move.x39
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/mvwin.x63
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/mvword.x56
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/newwin.x83
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/omkpkg65
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/putscreen.x84
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/refresh.x42
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/savewin.x23
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/scrollok.x21
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/showwin.x39
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/standout.x48
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/wdimen.x45
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/window.com7
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/window.h28
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/winstat.x51
-rw-r--r--pkg/utilities/nttools/tedit/display/curses/wslide.x91
-rw-r--r--pkg/utilities/nttools/tedit/display/forms/README115
-rw-r--r--pkg/utilities/nttools/tedit/display/forms/fmbegin.x20
-rw-r--r--pkg/utilities/nttools/tedit/display/forms/fmcheck.x98
-rw-r--r--pkg/utilities/nttools/tedit/display/forms/fmend.x12
-rw-r--r--pkg/utilities/nttools/tedit/display/forms/fmgetform.x89
-rw-r--r--pkg/utilities/nttools/tedit/display/forms/fmhelp.x132
-rw-r--r--pkg/utilities/nttools/tedit/display/forms/fmmkform.x82
-rw-r--r--pkg/utilities/nttools/tedit/display/forms/fmprompt.x70
-rw-r--r--pkg/utilities/nttools/tedit/display/forms/fmredraw.x69
-rw-r--r--pkg/utilities/nttools/tedit/display/forms/formfn.h20
-rw-r--r--pkg/utilities/nttools/tedit/display/forms/formfn.x278
-rw-r--r--pkg/utilities/nttools/tedit/display/forms/forms.com5
-rw-r--r--pkg/utilities/nttools/tedit/display/forms/linefn.h8
-rw-r--r--pkg/utilities/nttools/tedit/display/forms/linefn.x134
-rw-r--r--pkg/utilities/nttools/tedit/display/forms/mkpkg19
-rw-r--r--pkg/utilities/nttools/tedit/display/forms/promptfn.h7
-rw-r--r--pkg/utilities/nttools/tedit/display/forms/promptfn.x134
-rw-r--r--pkg/utilities/nttools/tedit/display/mkpkg14
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/README211
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/kbegin.x40
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/kcompile.x148
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/kconvert.x61
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/kdoline.x96
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/kend.x49
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/kget.x96
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/khelp.x61
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/kpushbk.x11
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/mkpkg32
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/psbeep.x9
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/psbegin.x59
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/psend.x48
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/psfill.x135
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/psheight.x12
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/psintersect.x27
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/psscreen.x14
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/pssendcap.x74
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/pssetcur.x117
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/psslide.x182
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/pssynch.x12
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/pswidth.x12
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/pswrite.x79
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/pswrtcells.x114
-rw-r--r--pkg/utilities/nttools/tedit/display/screen/screen.com18
-rw-r--r--pkg/utilities/nttools/tedit/edit.x70
-rw-r--r--pkg/utilities/nttools/tedit/field.h23
-rw-r--r--pkg/utilities/nttools/tedit/field.x749
-rw-r--r--pkg/utilities/nttools/tedit/mkpkg27
-rw-r--r--pkg/utilities/nttools/tedit/paste.h6
-rw-r--r--pkg/utilities/nttools/tedit/paste.x142
-rw-r--r--pkg/utilities/nttools/tedit/prompt.x225
-rw-r--r--pkg/utilities/nttools/tedit/screen.h18
-rw-r--r--pkg/utilities/nttools/tedit/screen.x699
-rw-r--r--pkg/utilities/nttools/tedit/substitute.x372
-rw-r--r--pkg/utilities/nttools/tedit/table.h22
-rw-r--r--pkg/utilities/nttools/tedit/table.x312
-rw-r--r--pkg/utilities/nttools/tedit/tedit.key23
-rw-r--r--pkg/utilities/nttools/tedit/tedit.x33
-rw-r--r--pkg/utilities/nttools/tedit/tread.x31
-rw-r--r--pkg/utilities/nttools/tedit/window.com8
-rw-r--r--pkg/utilities/nttools/tedit/window.x246
-rw-r--r--pkg/utilities/nttools/texpand.par6
-rw-r--r--pkg/utilities/nttools/texpand/dbgrules.x164
-rw-r--r--pkg/utilities/nttools/texpand/lexer.x114
-rw-r--r--pkg/utilities/nttools/texpand/lexoper.h29
-rw-r--r--pkg/utilities/nttools/texpand/mkpkg21
-rw-r--r--pkg/utilities/nttools/texpand/mkrules.x48
-rw-r--r--pkg/utilities/nttools/texpand/movelem.x113
-rw-r--r--pkg/utilities/nttools/texpand/movtbrow.x43
-rw-r--r--pkg/utilities/nttools/texpand/parser.com6
-rw-r--r--pkg/utilities/nttools/texpand/parser.x283
-rw-r--r--pkg/utilities/nttools/texpand/pushstack.x226
-rw-r--r--pkg/utilities/nttools/texpand/span.x97
-rw-r--r--pkg/utilities/nttools/texpand/texpand.x94
-rw-r--r--pkg/utilities/nttools/texpand/userules.x286
-rw-r--r--pkg/utilities/nttools/texpand/x_texpand.x3
-rw-r--r--pkg/utilities/nttools/thedit.par7
-rw-r--r--pkg/utilities/nttools/thedit/mkpkg13
-rw-r--r--pkg/utilities/nttools/thedit/t_thedit.x833
-rw-r--r--pkg/utilities/nttools/thedit/t_thselect.x150
-rw-r--r--pkg/utilities/nttools/thedit/tkw.x405
-rw-r--r--pkg/utilities/nttools/thistogram.par14
-rw-r--r--pkg/utilities/nttools/threed/doc/selectors.hlp91
-rw-r--r--pkg/utilities/nttools/threed/doc/tiimage.hlp108
-rw-r--r--pkg/utilities/nttools/threed/doc/titable.hlp100
-rw-r--r--pkg/utilities/nttools/threed/doc/tscopy.hlp94
-rw-r--r--pkg/utilities/nttools/threed/doc/tximage.hlp85
-rw-r--r--pkg/utilities/nttools/threed/doc/txtable.hlp89
-rw-r--r--pkg/utilities/nttools/threed/mkpkg25
-rw-r--r--pkg/utilities/nttools/threed/tblerr.h27
-rw-r--r--pkg/utilities/nttools/threed/tbtables.h123
-rw-r--r--pkg/utilities/nttools/threed/tiimage.par7
-rw-r--r--pkg/utilities/nttools/threed/tiimage/design1.txt353
-rw-r--r--pkg/utilities/nttools/threed/tiimage/generic/mkpkg14
-rw-r--r--pkg/utilities/nttools/threed/tiimage/generic/tmcp1d.x54
-rw-r--r--pkg/utilities/nttools/threed/tiimage/generic/tmcp1i.x54
-rw-r--r--pkg/utilities/nttools/threed/tiimage/generic/tmcp1r.x54
-rw-r--r--pkg/utilities/nttools/threed/tiimage/generic/tmcp1s.x54
-rw-r--r--pkg/utilities/nttools/threed/tiimage/list.tex789
-rw-r--r--pkg/utilities/nttools/threed/tiimage/list.toc10
-rw-r--r--pkg/utilities/nttools/threed/tiimage/loc.txt12
-rw-r--r--pkg/utilities/nttools/threed/tiimage/mkpkg29
-rw-r--r--pkg/utilities/nttools/threed/tiimage/tiimage.h9
-rw-r--r--pkg/utilities/nttools/threed/tiimage/tiimage.x147
-rw-r--r--pkg/utilities/nttools/threed/tiimage/tmcopy.x67
-rw-r--r--pkg/utilities/nttools/threed/tiimage/tmcp1.gx54
-rw-r--r--pkg/utilities/nttools/threed/tiimage/tmhc.x57
-rw-r--r--pkg/utilities/nttools/threed/tiimage/tmheader.x60
-rw-r--r--pkg/utilities/nttools/threed/tiimage/tmloop.x104
-rw-r--r--pkg/utilities/nttools/threed/tiimage/tmmode.x108
-rw-r--r--pkg/utilities/nttools/threed/tiimage/tmscan.x96
-rw-r--r--pkg/utilities/nttools/threed/titable.par7
-rw-r--r--pkg/utilities/nttools/threed/titable/design1.txt224
-rw-r--r--pkg/utilities/nttools/threed/titable/design2.txt244
-rw-r--r--pkg/utilities/nttools/threed/titable/generic/mkpkg22
-rw-r--r--pkg/utilities/nttools/threed/titable/generic/tichb.x52
-rw-r--r--pkg/utilities/nttools/threed/titable/generic/tichc.x54
-rw-r--r--pkg/utilities/nttools/threed/titable/generic/tichd.x52
-rw-r--r--pkg/utilities/nttools/threed/titable/generic/tichi.x52
-rw-r--r--pkg/utilities/nttools/threed/titable/generic/tichr.x52
-rw-r--r--pkg/utilities/nttools/threed/titable/generic/tichs.x52
-rw-r--r--pkg/utilities/nttools/threed/titable/generic/tirowsb.x71
-rw-r--r--pkg/utilities/nttools/threed/titable/generic/tirowsc.x72
-rw-r--r--pkg/utilities/nttools/threed/titable/generic/tirowsd.x71
-rw-r--r--pkg/utilities/nttools/threed/titable/generic/tirowsi.x71
-rw-r--r--pkg/utilities/nttools/threed/titable/generic/tirowsr.x71
-rw-r--r--pkg/utilities/nttools/threed/titable/generic/tirowss.x71
-rw-r--r--pkg/utilities/nttools/threed/titable/help.txt117
-rw-r--r--pkg/utilities/nttools/threed/titable/list.tex979
-rw-r--r--pkg/utilities/nttools/threed/titable/loc.txt11
-rw-r--r--pkg/utilities/nttools/threed/titable/mkpkg36
-rw-r--r--pkg/utilities/nttools/threed/titable/ticc.x56
-rw-r--r--pkg/utilities/nttools/threed/titable/tich.gx74
-rw-r--r--pkg/utilities/nttools/threed/titable/ticopy.x116
-rw-r--r--pkg/utilities/nttools/threed/titable/tiheader.x192
-rw-r--r--pkg/utilities/nttools/threed/titable/tinew.x101
-rw-r--r--pkg/utilities/nttools/threed/titable/tinsert.x99
-rw-r--r--pkg/utilities/nttools/threed/titable/tirows.gx98
-rw-r--r--pkg/utilities/nttools/threed/titable/tisetc.x83
-rw-r--r--pkg/utilities/nttools/threed/titable/titable.x83
-rw-r--r--pkg/utilities/nttools/threed/titable/tiupdate.x39
-rw-r--r--pkg/utilities/nttools/threed/tscopy.par5
-rw-r--r--pkg/utilities/nttools/threed/tscopy/mkpkg14
-rw-r--r--pkg/utilities/nttools/threed/tscopy/tbracket.x105
-rw-r--r--pkg/utilities/nttools/threed/tscopy/tcpyone.x141
-rw-r--r--pkg/utilities/nttools/threed/tscopy/tcpyrow.x79
-rw-r--r--pkg/utilities/nttools/threed/tscopy/tscopy.x110
-rw-r--r--pkg/utilities/nttools/threed/tximage.par5
-rw-r--r--pkg/utilities/nttools/threed/tximage/mkpkg15
-rw-r--r--pkg/utilities/nttools/threed/tximage/txicpy.x61
-rw-r--r--pkg/utilities/nttools/threed/tximage/txihc.x53
-rw-r--r--pkg/utilities/nttools/threed/tximage/tximage.x117
-rw-r--r--pkg/utilities/nttools/threed/tximage/txione.x214
-rw-r--r--pkg/utilities/nttools/threed/txtable.par6
-rw-r--r--pkg/utilities/nttools/threed/txtable/generic/mkpkg22
-rw-r--r--pkg/utilities/nttools/threed/txtable/generic/txtcptb.x34
-rw-r--r--pkg/utilities/nttools/threed/txtable/generic/txtcptc.x35
-rw-r--r--pkg/utilities/nttools/threed/txtable/generic/txtcptd.x34
-rw-r--r--pkg/utilities/nttools/threed/txtable/generic/txtcpti.x34
-rw-r--r--pkg/utilities/nttools/threed/txtable/generic/txtcptr.x34
-rw-r--r--pkg/utilities/nttools/threed/txtable/generic/txtcpts.x34
-rw-r--r--pkg/utilities/nttools/threed/txtable/generic/txthvb.x30
-rw-r--r--pkg/utilities/nttools/threed/txtable/generic/txthvc.x30
-rw-r--r--pkg/utilities/nttools/threed/txtable/generic/txthvd.x30
-rw-r--r--pkg/utilities/nttools/threed/txtable/generic/txthvi.x30
-rw-r--r--pkg/utilities/nttools/threed/txtable/generic/txthvr.x30
-rw-r--r--pkg/utilities/nttools/threed/txtable/generic/txthvs.x30
-rw-r--r--pkg/utilities/nttools/threed/txtable/mkpkg34
-rw-r--r--pkg/utilities/nttools/threed/txtable/txtable.x121
-rw-r--r--pkg/utilities/nttools/threed/txtable/txtcpt.gx53
-rw-r--r--pkg/utilities/nttools/threed/txtable/txtcpy.x94
-rw-r--r--pkg/utilities/nttools/threed/txtable/txtcpyco.x45
-rw-r--r--pkg/utilities/nttools/threed/txtable/txtcpysc.x34
-rw-r--r--pkg/utilities/nttools/threed/txtable/txthc.x85
-rw-r--r--pkg/utilities/nttools/threed/txtable/txthv.gx55
-rw-r--r--pkg/utilities/nttools/threed/txtable/txtone.x227
-rw-r--r--pkg/utilities/nttools/threed/x_threed.x5
-rw-r--r--pkg/utilities/nttools/thselect.par5
-rw-r--r--pkg/utilities/nttools/tinfo.par15
-rw-r--r--pkg/utilities/nttools/tinfo/mkpkg12
-rw-r--r--pkg/utilities/nttools/tinfo/tinfo.x179
-rw-r--r--pkg/utilities/nttools/tinfo/tlcol.x128
-rw-r--r--pkg/utilities/nttools/tintegrate.par6
-rw-r--r--pkg/utilities/nttools/tintegrate/mkpkg11
-rw-r--r--pkg/utilities/nttools/tintegrate/tintegrate.x155
-rw-r--r--pkg/utilities/nttools/tjoin.par9
-rw-r--r--pkg/utilities/nttools/tjoin/closeiotab.x22
-rw-r--r--pkg/utilities/nttools/tjoin/dojoin.x97
-rw-r--r--pkg/utilities/nttools/tjoin/freetol.x15
-rw-r--r--pkg/utilities/nttools/tjoin/isnumber.x35
-rw-r--r--pkg/utilities/nttools/tjoin/issame.x127
-rw-r--r--pkg/utilities/nttools/tjoin/mkjoin.x106
-rw-r--r--pkg/utilities/nttools/tjoin/mkpkg23
-rw-r--r--pkg/utilities/nttools/tjoin/openitab.x82
-rw-r--r--pkg/utilities/nttools/tjoin/openotab.x91
-rw-r--r--pkg/utilities/nttools/tjoin/readtol.x55
-rw-r--r--pkg/utilities/nttools/tjoin/removejcol.x43
-rw-r--r--pkg/utilities/nttools/tjoin/renamecol.x109
-rw-r--r--pkg/utilities/nttools/tjoin/spptype.x29
-rw-r--r--pkg/utilities/nttools/tjoin/tjoin.h27
-rw-r--r--pkg/utilities/nttools/tjoin/tjoin.x124
-rw-r--r--pkg/utilities/nttools/tlcol.par4
-rw-r--r--pkg/utilities/nttools/tlinear.par10
-rw-r--r--pkg/utilities/nttools/tlinear/mkpkg11
-rw-r--r--pkg/utilities/nttools/tlinear/tlinear.x468
-rw-r--r--pkg/utilities/nttools/tmatch.par18
-rw-r--r--pkg/utilities/nttools/tmatch/getmatch.x101
-rw-r--r--pkg/utilities/nttools/tmatch/getnorm.x67
-rw-r--r--pkg/utilities/nttools/tmatch/getweight.x96
-rw-r--r--pkg/utilities/nttools/tmatch/infomatch.x219
-rw-r--r--pkg/utilities/nttools/tmatch/mkpkg20
-rw-r--r--pkg/utilities/nttools/tmatch/putmatch.x102
-rw-r--r--pkg/utilities/nttools/tmatch/rowname.x61
-rw-r--r--pkg/utilities/nttools/tmatch/setindex.x13
-rw-r--r--pkg/utilities/nttools/tmatch/sortclose.x50
-rw-r--r--pkg/utilities/nttools/tmatch/sortdist.x50
-rw-r--r--pkg/utilities/nttools/tmatch/tmatch.x138
-rw-r--r--pkg/utilities/nttools/tmerge.par9
-rw-r--r--pkg/utilities/nttools/tmerge/mkpkg20
-rw-r--r--pkg/utilities/nttools/tmerge/tmerge.x425
-rw-r--r--pkg/utilities/nttools/tprint.par16
-rw-r--r--pkg/utilities/nttools/tprint/mkpkg15
-rw-r--r--pkg/utilities/nttools/tprint/notes40
-rw-r--r--pkg/utilities/nttools/tprint/tdump.x486
-rw-r--r--pkg/utilities/nttools/tprint/tprhtml.x592
-rw-r--r--pkg/utilities/nttools/tprint/tprint.h5
-rw-r--r--pkg/utilities/nttools/tprint/tprint.x535
-rw-r--r--pkg/utilities/nttools/tprint/tprlatex.x579
-rw-r--r--pkg/utilities/nttools/tprint/tprplain.x530
-rw-r--r--pkg/utilities/nttools/tproduct.par4
-rw-r--r--pkg/utilities/nttools/tproduct/mkpkg11
-rw-r--r--pkg/utilities/nttools/tproduct/tproduct.x113
-rw-r--r--pkg/utilities/nttools/tproject.par5
-rw-r--r--pkg/utilities/nttools/tproject/mkpkg13
-rw-r--r--pkg/utilities/nttools/tproject/nextuniq.x39
-rw-r--r--pkg/utilities/nttools/tproject/tproject.x100
-rw-r--r--pkg/utilities/nttools/tproject/wproject.x64
-rw-r--r--pkg/utilities/nttools/tquery.par9
-rw-r--r--pkg/utilities/nttools/tquery/doquery.x72
-rw-r--r--pkg/utilities/nttools/tquery/mkpkg13
-rw-r--r--pkg/utilities/nttools/tquery/tquery.x113
-rw-r--r--pkg/utilities/nttools/tquery/wquery.x50
-rw-r--r--pkg/utilities/nttools/tread.par4
-rw-r--r--pkg/utilities/nttools/trebin.par14
-rw-r--r--pkg/utilities/nttools/trebin/mkpkg27
-rw-r--r--pkg/utilities/nttools/trebin/tnamcls.x24
-rw-r--r--pkg/utilities/nttools/trebin/tnamgio.x79
-rw-r--r--pkg/utilities/nttools/trebin/tnaminit.x75
-rw-r--r--pkg/utilities/nttools/trebin/trebin.h5
-rw-r--r--pkg/utilities/nttools/trebin/trebin.x136
-rw-r--r--pkg/utilities/nttools/trebin/tucspl.f52
-rw-r--r--pkg/utilities/nttools/trebin/tudcol.x140
-rw-r--r--pkg/utilities/nttools/trebin/tugcol.x87
-rw-r--r--pkg/utilities/nttools/trebin/tugetput.x142
-rw-r--r--pkg/utilities/nttools/trebin/tuhunt.f103
-rw-r--r--pkg/utilities/nttools/trebin/tuiep3.f71
-rw-r--r--pkg/utilities/nttools/trebin/tuifit.x63
-rw-r--r--pkg/utilities/nttools/trebin/tuinterp.x139
-rw-r--r--pkg/utilities/nttools/trebin/tuiset.x26
-rw-r--r--pkg/utilities/nttools/trebin/tuispl.f32
-rw-r--r--pkg/utilities/nttools/trebin/tuival.x272
-rw-r--r--pkg/utilities/nttools/trebin/tutrim.x43
-rw-r--r--pkg/utilities/nttools/trebin/tuxget.x134
-rw-r--r--pkg/utilities/nttools/tselect.par4
-rw-r--r--pkg/utilities/nttools/tselect/mkpkg12
-rw-r--r--pkg/utilities/nttools/tselect/subset.x83
-rw-r--r--pkg/utilities/nttools/tselect/tselect.x83
-rw-r--r--pkg/utilities/nttools/tsort.par5
-rw-r--r--pkg/utilities/nttools/tsort/mkpkg14
-rw-r--r--pkg/utilities/nttools/tsort/tblextsort.x496
-rw-r--r--pkg/utilities/nttools/tsort/tblintsort.x48
-rw-r--r--pkg/utilities/nttools/tsort/tblmaxrow.x39
-rw-r--r--pkg/utilities/nttools/tsort/tsort.x98
-rw-r--r--pkg/utilities/nttools/tstat.par21
-rw-r--r--pkg/utilities/nttools/tstat/mkpkg13
-rw-r--r--pkg/utilities/nttools/tstat/thistogram.h8
-rw-r--r--pkg/utilities/nttools/tstat/thistogram.x348
-rw-r--r--pkg/utilities/nttools/tstat/thoptions.x343
-rw-r--r--pkg/utilities/nttools/tstat/tstat.x465
-rw-r--r--pkg/utilities/nttools/ttranspose.par6
-rw-r--r--pkg/utilities/nttools/ttranspose/mkpkg11
-rw-r--r--pkg/utilities/nttools/ttranspose/ttranspose.x419
-rw-r--r--pkg/utilities/nttools/ttranspose/ttrflip.x266
-rw-r--r--pkg/utilities/nttools/tunits.par8
-rw-r--r--pkg/utilities/nttools/tunits/abrev.tab62
-rw-r--r--pkg/utilities/nttools/tunits/abrev.x113
-rw-r--r--pkg/utilities/nttools/tunits/convertcol.x68
-rw-r--r--pkg/utilities/nttools/tunits/factor.x125
-rw-r--r--pkg/utilities/nttools/tunits/mkpkg19
-rw-r--r--pkg/utilities/nttools/tunits/parseunits.com9
-rw-r--r--pkg/utilities/nttools/tunits/parseunits.x624
-rw-r--r--pkg/utilities/nttools/tunits/parseunits.y322
-rw-r--r--pkg/utilities/nttools/tunits/tuniterr.x24
-rw-r--r--pkg/utilities/nttools/tunits/tunits.h14
-rw-r--r--pkg/utilities/nttools/tunits/tunits.x112
-rw-r--r--pkg/utilities/nttools/tunits/unhash.x212
-rw-r--r--pkg/utilities/nttools/tunits/units.tab60
-rw-r--r--pkg/utilities/nttools/tunits/units.x162
-rw-r--r--pkg/utilities/nttools/tunits/unstr.x381
-rw-r--r--pkg/utilities/nttools/tupar.par9
-rw-r--r--pkg/utilities/nttools/tupar/mkpkg12
-rw-r--r--pkg/utilities/nttools/tupar/tuinstr.x971
-rw-r--r--pkg/utilities/nttools/tupar/tupar.h3
-rw-r--r--pkg/utilities/nttools/tupar/tupar.x260
-rw-r--r--pkg/utilities/nttools/x_nttools.x50
-rw-r--r--pkg/utilities/nttools/zz.xml3427
-rw-r--r--pkg/utilities/nttools/zz_bad.xml3427
-rw-r--r--pkg/utilities/nttools/zz_rewrite.xml1191
616 files changed, 80508 insertions, 0 deletions
diff --git a/pkg/utilities/nttools/README b/pkg/utilities/nttools/README
new file mode 100644
index 00000000..804a2a35
--- /dev/null
+++ b/pkg/utilities/nttools/README
@@ -0,0 +1,32 @@
+These directories contain tasks for working with tables. The various
+subdirectories and the tasks that they contain are as follows:
+
+copyone keypar, keytab, parkey, partab, tabkey, tabpar
+doc help files
+gtedit gtedit
+keyselect keyselect
+lib subroutines used by more than one task
+tcalc tcalc
+tchcol tchcol
+tchsize tchsize
+tcopy tcopy, tdelete
+tcreate tcreate
+tdiffer tdiffer
+tedit tedit, tread
+texpand texpand
+thedit thedit, thselect
+tinfo tinfo, tlcol
+tintegrate tintegrate
+tjoin tjoin
+tlinear tlinear
+tmerge tmerge
+tprint tdump, tprint
+tproduct tproduct
+tproject tproject
+tquery tquery
+trebin trebin
+tselect tselect
+tsort tsort
+tstat thistogram, tstat
+tunits tunits
+tupar tupar
diff --git a/pkg/utilities/nttools/atools/mkpkg b/pkg/utilities/nttools/atools/mkpkg
new file mode 100644
index 00000000..7c969a01
--- /dev/null
+++ b/pkg/utilities/nttools/atools/mkpkg
@@ -0,0 +1,10 @@
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ taextract.x <tbset.h>
+ tainsert.x <tbset.h>
+ taincr.x
+ ;
diff --git a/pkg/utilities/nttools/atools/taextract.x b/pkg/utilities/nttools/atools/taextract.x
new file mode 100644
index 00000000..a89be676
--- /dev/null
+++ b/pkg/utilities/nttools/atools/taextract.x
@@ -0,0 +1,214 @@
+include <tbset.h>
+
+define BUFSIZE 1024 # max number of elements copied at one time
+
+# taextract -- copy an entry from one table to another
+# This task extracts an entry at a specified row & column (presumably
+# an array of values) and writes it as a column of scalar values to
+# another table. If the output table exists it will be written to in-place;
+# otherwise, it will be created. The same column name is used in both
+# tables. The input row number is written to the header of the output
+# table using keyword ORIG_ROW.
+#
+# Phil Hodge, 28-Jul-1994 Task created.
+# Phil Hodge, 15-Dec-1995 Add nremain, fix while loop on ncopy.
+# Phil Hodge, 29-Jul-1997 Rename delete to delete_flag to avoid confusion
+# with the delete subroutine.
+# Phil Hodge, 30-Jan-1998 Add optional parameters to define new column.
+# Phil Hodge, 8-Apr-1999 Call tbfpri.
+
+procedure taextract()
+
+pointer intable
+pointer outtable
+int row # row number at which to extract
+char column[SZ_COLNAME] # name of column from which to extract
+char outcolumn[SZ_COLNAME] # name to use for column in output table
+char colunits[SZ_COLUNITS] # units for new column
+char colfmt[SZ_COLFMT] # display format for new column
+pointer dtype # data type of new column
+#--
+pointer sp
+pointer x # scratch for array of data
+pointer itp, otp # pointers to table structs
+pointer icp, ocp # pointers to column structs
+int datatype # data type of column
+char icolname[SZ_COLNAME] # from tbcinf for input table column
+char icolunits[SZ_COLUNITS] # from tbcinf, units for column
+char icolfmt[SZ_COLFMT] # from tbcinf, display format
+int idatatype # from tbcinf, data type of column
+int colnum, lenfmt # output from tbcinf and ignored
+int nelem # input length of array, output number of rows
+int nremain # number of elements that remain to be copied
+int ncopy # number of elements to copy at once
+int i # loop index
+int first, last # first and last elements (or rows)
+int slen # length of string to copy
+int phu_copied # set by tbfpri and ignored
+bool inplace # true if output table already exists
+bool newcolumn # true if output column does not already exist
+int delete_flag # should we delete output table if error?
+pointer tbtopn()
+int clgeti(), tbpsta(), tbtacc(), tbcigi()
+int tbagtr(), tbagtd(), tbagti(), tbagts(), tbagtb(), tbagtt()
+bool isblank()
+
+begin
+ call smark (sp)
+ call salloc (intable, SZ_FNAME, TY_CHAR)
+ call salloc (outtable, SZ_FNAME, TY_CHAR)
+ call salloc (dtype, SZ_FNAME, TY_CHAR)
+
+ call clgstr ("intable", Memc[intable], SZ_FNAME)
+ call clgstr ("outtable", Memc[outtable], SZ_FNAME)
+ row = clgeti ("row")
+ call clgstr ("column", column, SZ_COLNAME)
+ call clgstr ("outcolumn", outcolumn, SZ_COLNAME)
+
+ # The input column name is the default for the output.
+ if (isblank (outcolumn))
+ call strcpy (column, outcolumn, SZ_COLNAME)
+
+ # Open input and output tables.
+ itp = tbtopn (Memc[intable], READ_ONLY, NULL)
+ if (tbtacc (Memc[outtable]) == YES) {
+ otp = tbtopn (Memc[outtable], READ_WRITE, NULL)
+ inplace = true
+ } else {
+ call tbfpri (Memc[intable], Memc[outtable], phu_copied)
+ otp = tbtopn (Memc[outtable], NEW_FILE, NULL)
+ inplace = false
+ }
+ if (inplace)
+ delete_flag = NO
+ else
+ delete_flag = YES # delete output table in case of error
+
+ if (row < 1 || row > tbpsta (itp, TBL_NROWS)) {
+ call taex_disaster (itp, otp, NO, "row not found in input table")
+ }
+
+ # Find input column.
+ call tbcfnd (itp, column, icp, 1)
+ if (icp == NULL)
+ call taex_disaster (itp, otp, NO, "column not found in input table")
+
+ # Find or create output column.
+ call tbcfnd (otp, outcolumn, ocp, 1)
+ if (ocp == NULL) {
+ # Column not found in output. Create it using the input column
+ # as a template, except that the output will not be an array.
+ # The name might also be different.
+ call tbcinf (icp, colnum, icolname, icolunits, icolfmt,
+ idatatype, nelem, lenfmt)
+ # Get optional parameters if creating new column.
+ call clgstr ("colunits", colunits, SZ_COLUNITS)
+ call clgstr ("colfmt", colfmt, SZ_COLFMT)
+ call clgstr ("datatype", Memc[dtype], SZ_FNAME)
+ # Assign default values if not specified.
+ if (isblank (colunits))
+ call strcpy (icolunits, colunits, SZ_COLUNITS)
+ if (isblank (colfmt))
+ call strcpy (icolfmt, colfmt, SZ_COLFMT)
+ if (isblank (Memc[dtype]))
+ datatype = idatatype
+ else
+ call tbbtyp (Memc[dtype], datatype)
+ call tbcdef (otp, ocp, outcolumn, colunits, colfmt,
+ datatype, 1, 1) # a column of scalars
+ newcolumn = true
+ } else {
+ newcolumn = false
+ }
+ if (!inplace)
+ call tbtcre (otp)
+
+ # Save the row number as a header parameter.
+ call tbhadi (otp, "orig_row", row)
+
+ # Get number of elements to copy.
+ nelem = tbcigi (icp, TBL_COL_LENDATA)
+ nremain = nelem # initialize to total number to copy
+ ncopy = min (nremain, BUFSIZE)
+ first = 1
+ last = ncopy
+
+ # Copy the data.
+ datatype = tbcigi (icp, TBL_COL_DATATYPE)
+ if (datatype == TY_REAL) {
+ call salloc (x, ncopy, TY_REAL)
+ while (ncopy > 0) {
+ if (tbagtr (itp, icp, row, Memr[x], first, ncopy) < ncopy)
+ call taex_disaster (itp, otp, delete_flag,
+ "error reading input")
+ call tbcptr (otp, ocp, Memr[x], first, last)
+ call taex_incr (nremain, ncopy, first, last, BUFSIZE)
+ }
+
+ } else if (datatype == TY_DOUBLE) {
+ call salloc (x, ncopy, TY_DOUBLE)
+ while (ncopy > 0) {
+ if (tbagtd (itp, icp, row, Memd[x], first, ncopy) < ncopy)
+ call taex_disaster (itp, otp, delete_flag,
+ "error reading input")
+ call tbcptd (otp, ocp, Memd[x], first, last)
+ call taex_incr (nremain, ncopy, first, last, BUFSIZE)
+ }
+
+ } else if (datatype == TY_INT) {
+ call salloc (x, ncopy, TY_INT)
+ while (ncopy > 0) {
+ if (tbagti (itp, icp, row, Memi[x], first, ncopy) < ncopy)
+ call taex_disaster (itp, otp, delete_flag,
+ "error reading input")
+ call tbcpti (otp, ocp, Memi[x], first, last)
+ call taex_incr (nremain, ncopy, first, last, BUFSIZE)
+ }
+
+ } else if (datatype == TY_SHORT) {
+ call salloc (x, ncopy, TY_SHORT)
+ while (ncopy > 0) {
+ if (tbagts (itp, icp, row, Mems[x], first, ncopy) < ncopy)
+ call taex_disaster (itp, otp, delete_flag,
+ "error reading input")
+ call tbcpts (otp, ocp, Mems[x], first, last)
+ call taex_incr (nremain, ncopy, first, last, BUFSIZE)
+ }
+
+ } else if (datatype == TY_BOOL) {
+ call salloc (x, ncopy, TY_BOOL)
+ while (ncopy > 0) {
+ if (tbagtb (itp, icp, row, Memb[x], first, ncopy) < ncopy)
+ call taex_disaster (itp, otp, delete_flag,
+ "error reading input")
+ call tbcptb (otp, ocp, Memb[x], first, last)
+ call taex_incr (nremain, ncopy, first, last, BUFSIZE)
+ }
+
+ } else if (datatype < 0) { # character string
+ slen = -datatype + 3 # a little extra space
+ call salloc (x, slen, TY_CHAR)
+ do i = 1, nelem {
+ if (tbagtt (itp, icp, row, Memc[x], slen, i, 1) < 1)
+ call taex_disaster (itp, otp, delete_flag,
+ "error reading input")
+ call tbeptt (otp, ocp, i, Memc[x])
+ }
+
+ } else {
+ call taex_disaster (itp, otp, delete_flag, "unknown data type")
+ }
+
+ # If we wrote to an existing column in an existing table, and the
+ # output table has more rows than we just wrote, then we should set
+ # the remaining rows in this column to INDEF.
+ if (!newcolumn) {
+ do i = nelem+1, tbpsta (otp, TBL_NROWS)
+ call tbrudf (otp, ocp, 1, i)
+ }
+
+ call tbtclo (otp)
+ call tbtclo (itp)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/atools/taincr.x b/pkg/utilities/nttools/atools/taincr.x
new file mode 100644
index 00000000..7d297e23
--- /dev/null
+++ b/pkg/utilities/nttools/atools/taincr.x
@@ -0,0 +1,55 @@
+# This file contains taex_incr and taex_disaster, which are used by
+# both tainsert and taextract.
+#
+# Phil Hodge, 7-Mar-1996 Extracted from taextract.x.
+# Phil Hodge, 29-Jul-1997 In taex_disaster, get table name before closing
+# the table; rename delete to delete_flag to avoid
+# confusion with the delete subroutine.
+
+# taex_incr -- increment variables
+
+# On input, ncopy is the number of elements that were copied in
+# the previous step. We decrement nremain and increment first by
+# this amount. Then we determine the appropriate value of ncopy
+# for the next step and update last.
+
+procedure taex_incr (nremain, ncopy, first, last, bufsize)
+
+int nremain # io: number of elements remaining to be copied
+int ncopy # io: number of elements copied/to copy next
+int first # io: first element (or row number)
+int last # io: last element (or row number)
+int bufsize # i: maximum number to copy in one step
+
+begin
+ nremain = nremain - ncopy
+ first = first + ncopy
+ ncopy = min (nremain, bufsize)
+ last = first + ncopy - 1
+end
+
+# taex_disaster -- clean up and call error
+
+procedure taex_disaster (itp, otp, delete_flag, message)
+
+pointer itp, otp # io: pointers to table struct
+int delete_flag # i: YES if we should delete the output table
+char message[ARB] # i: error message
+#--
+pointer sp
+pointer outtable # scratch for name of output table
+
+begin
+ call tbtclo (itp)
+ if (delete_flag == YES) {
+ call smark (sp)
+ call salloc (outtable, SZ_FNAME, TY_CHAR)
+ call tbtnam (otp, Memc[outtable], SZ_FNAME)
+ call tbtclo (otp)
+ call tbtdel (Memc[outtable])
+ call sfree (sp)
+ } else {
+ call tbtclo (otp)
+ }
+ call error (1, message)
+end
diff --git a/pkg/utilities/nttools/atools/tainsert.x b/pkg/utilities/nttools/atools/tainsert.x
new file mode 100644
index 00000000..125ed348
--- /dev/null
+++ b/pkg/utilities/nttools/atools/tainsert.x
@@ -0,0 +1,260 @@
+include <tbset.h>
+
+define BUFSIZE 1024 # max number of elements copied at one time
+
+# tainsert -- copy a column from one table to an entry in another
+# This task inserts an array of values into a row for a column that contains
+# array entries. If the output table exists it will be written to in-place;
+# otherwise, it will be created. The same column name is used in both
+# tables. If the row number is less than one, the output row number will be
+# taken from the keyword ORIG_ROW in the input table.
+#
+# Phil Hodge, 28-Jul-1994 Task created.
+# Phil Hodge, 15-Dec-1995 Add nremain, fix while loop on ncopy.
+# Phil Hodge, 4-Apr-1996 Remove slen from calling sequence of tbaptr, etc.,
+# for writing indef to extra elements of array.
+# Phil Hodge, 30-Jan-1998 Add optional parameters to define new column;
+# call tbhgti as a function, not a subroutine.
+# Phil Hodge, 8-Apr-1999 Call tbfpri.
+# Phil Hodge, 13-Apr-2000 Add column name to warning message.
+
+procedure tainsert()
+
+pointer intable
+pointer outtable
+int row # row number at which to insert
+char column[SZ_COLNAME] # name of column to copy
+char outcolumn[SZ_COLNAME] # name to use for column in output table
+int size # length of output array for new column
+char colunits[SZ_COLUNITS] # units for new column
+char colfmt[SZ_COLFMT] # display format for new column
+pointer dtype # data type of new column
+#--
+pointer sp
+pointer x # scratch for array of data
+pointer nbuf # scratch for array of null flags
+pointer itp, otp # pointers to table structs
+pointer icp, ocp # pointers to column structs
+int datatype # data type of column
+char icolname[SZ_COLNAME] # from tbcinf for input table column
+char icolunits[SZ_COLUNITS] # from tbcinf, units for column
+char icolfmt[SZ_COLFMT] # from tbcinf, display format
+int idatatype # from tbcinf, data type of column
+int colnum, lenfmt # output from tbcinf and ignored
+int nrows # number of rows in input table
+int nelem # input number of rows, output length of array
+int nremain # number of elements that remain to be copied
+int ncopy # number of elements to copy at once
+int i # loop index
+int first, last # first and last elements (or rows)
+int slen # length of string to copy
+int phu_copied # set by tbfpri and ignored
+bool inplace # true if output table already exists
+bool newcolumn # true if output column does not already exist
+int delete # should we delete output table if error?
+pointer tbtopn()
+int clgeti(), tbpsta(), tbtacc(), tbcigi(), tbhgti()
+bool isblank()
+
+# INDEF values for use in a calling sequence:
+# (The problem is that INDEFS is an int, not a short; the others may be OK.)
+double undefd
+real undefr
+int undefi
+short undefs
+
+begin
+ call smark (sp)
+ call salloc (intable, SZ_FNAME, TY_CHAR)
+ call salloc (outtable, SZ_FNAME, TY_CHAR)
+ call salloc (dtype, SZ_FNAME, TY_CHAR)
+
+ call clgstr ("intable", Memc[intable], SZ_FNAME)
+ call clgstr ("outtable", Memc[outtable], SZ_FNAME)
+ row = clgeti ("row")
+ call clgstr ("column", column, SZ_COLNAME)
+ call clgstr ("outcolumn", outcolumn, SZ_COLNAME)
+
+ # The input column name is the default for the output.
+ if (isblank (outcolumn))
+ call strcpy (column, outcolumn, SZ_COLNAME)
+
+ # Open input and output tables.
+ itp = tbtopn (Memc[intable], READ_ONLY, NULL)
+ if (tbtacc (Memc[outtable]) == YES) {
+ otp = tbtopn (Memc[outtable], READ_WRITE, NULL)
+ inplace = true
+ } else {
+ call tbfpri (Memc[intable], Memc[outtable], phu_copied)
+ otp = tbtopn (Memc[outtable], NEW_FILE, NULL)
+ inplace = false
+ }
+ if (inplace)
+ delete = NO
+ else
+ delete = YES # delete output table in case of error
+
+ undefd = INDEFD
+ undefr = INDEFR
+ undefi = INDEFI
+ undefs = INDEFS
+
+ if (row < 1 || IS_INDEFI(row)) {
+ iferr (row = tbhgti (itp, "orig_row"))
+ call taex_disaster (itp, otp, NO,
+ "row number not specified, and ORIG_ROW not found in intable")
+ }
+
+ # This will be the number of elements in the output array,
+ # unless the user explicitly specifies a different size.
+ nrows = tbpsta (itp, TBL_NROWS)
+
+ # Find input column.
+ call tbcfnd (itp, column, icp, 1)
+ if (icp == NULL)
+ call taex_disaster (itp, otp, NO, "column not found in input table")
+
+ # Find or create output column. If we're creating a new column,
+ # use the input column as a template, except that the output will be
+ # an array of length 'size', which defaults to nrows but can be
+ # different if the user specifies a value. The name of the output
+ # column can also be different from the input.
+ call tbcfnd (otp, outcolumn, ocp, 1)
+ if (ocp == NULL) {
+ # Column not found in output, so create it.
+ call tbcinf (icp, colnum, icolname, icolunits, icolfmt,
+ idatatype, nelem, lenfmt)
+ if (nelem > 1)
+ call taex_disaster (itp, otp, NO,
+ "column in input table contains arrays")
+ # Get optional parameters if creating new column.
+ size = clgeti ("size")
+ call clgstr ("colunits", colunits, SZ_COLUNITS)
+ call clgstr ("colfmt", colfmt, SZ_COLFMT)
+ call clgstr ("datatype", Memc[dtype], SZ_FNAME)
+ # Assign default values if not specified.
+ if (IS_INDEFI(size) || size < 1)
+ size = nrows
+ if (isblank (colunits))
+ call strcpy (icolunits, colunits, SZ_COLUNITS)
+ if (isblank (colfmt))
+ call strcpy (icolfmt, colfmt, SZ_COLFMT)
+ if (isblank (Memc[dtype])) {
+ datatype = idatatype
+ } else {
+ # convert e.g. "real" to 6
+ call tbbtyp (Memc[dtype], datatype)
+ }
+ call tbcdef (otp, ocp, outcolumn, colunits, colfmt,
+ datatype, size, 1) # an array
+ newcolumn = true
+ } else {
+ newcolumn = false
+ }
+ if (!inplace)
+ call tbtcre (otp)
+
+ # Get number of elements to copy.
+ nelem = tbcigi (ocp, TBL_COL_LENDATA)
+ if (nrows > nelem) {
+ call eprintf (
+"Warning: The number of input rows (%d) in column %s\n")
+ call pargi (nrows)
+ call pargstr (column)
+ call eprintf (
+" is greater than the array size (%d); the extra rows will be ignored.\n")
+ call pargi (nelem)
+ }
+ nremain = min (nrows, nelem) # total number to copy
+ ncopy = min (nremain, BUFSIZE)
+ first = 1
+ last = ncopy
+
+ # Copy the data.
+ datatype = tbcigi (icp, TBL_COL_DATATYPE)
+ call salloc (nbuf, ncopy, TY_BOOL)
+ if (datatype == TY_REAL) {
+ call salloc (x, ncopy, TY_REAL)
+ while (ncopy > 0) {
+ call tbcgtr (itp, icp, Memr[x], Memb[nbuf], first, last)
+ call tbaptr (otp, ocp, row, Memr[x], first, ncopy)
+ call taex_incr (nremain, ncopy, first, last, BUFSIZE)
+ }
+
+ } else if (datatype == TY_DOUBLE) {
+ call salloc (x, ncopy, TY_DOUBLE)
+ while (ncopy > 0) {
+ call tbcgtd (itp, icp, Memd[x], Memb[nbuf], first, last)
+ call tbaptd (otp, ocp, row, Memd[x], first, ncopy)
+ call taex_incr (nremain, ncopy, first, last, BUFSIZE)
+ }
+
+ } else if (datatype == TY_INT) {
+ call salloc (x, ncopy, TY_INT)
+ while (ncopy > 0) {
+ call tbcgti (itp, icp, Memi[x], Memb[nbuf], first, last)
+ call tbapti (otp, ocp, row, Memi[x], first, ncopy)
+ call taex_incr (nremain, ncopy, first, last, BUFSIZE)
+ }
+
+ } else if (datatype == TY_SHORT) {
+ call salloc (x, ncopy, TY_SHORT)
+ while (ncopy > 0) {
+ call tbcgts (itp, icp, Mems[x], Memb[nbuf], first, last)
+ call tbapts (otp, ocp, row, Mems[x], first, ncopy)
+ call taex_incr (nremain, ncopy, first, last, BUFSIZE)
+ }
+
+ } else if (datatype == TY_BOOL) {
+ call salloc (x, ncopy, TY_BOOL)
+ while (ncopy > 0) {
+ call tbcgtb (itp, icp, Memb[x], Memb[nbuf], first, last)
+ call tbaptb (otp, ocp, row, Memb[x], first, ncopy)
+ call taex_incr (nremain, ncopy, first, last, BUFSIZE)
+ }
+
+ } else if (datatype < 0) { # character string
+ slen = -datatype + 3 # a little extra space
+ call salloc (x, slen, TY_CHAR)
+ do i = 1, nelem {
+ call tbegtt (itp, icp, i, Memc[x], slen)
+ call tbaptt (otp, ocp, row, Memc[x], slen, i, 1)
+ }
+
+ } else {
+ call eprintf ("datatype = %d\n")
+ call pargi (datatype)
+ call taex_disaster (itp, otp, delete, "unknown data type")
+ }
+
+ # If we wrote to an existing column in an existing table, and the
+ # output column array has more elements than input rows, then we
+ # should set the remaining elements in this entry to INDEF.
+ if (!newcolumn) {
+ if (datatype == TY_REAL) {
+ do i = nrows+1, nelem
+ call tbaptr (otp, ocp, row, undefr, i, 1)
+ } else if (datatype == TY_DOUBLE) {
+ do i = nrows+1, nelem
+ call tbaptd (otp, ocp, row, undefd, i, 1)
+ } else if (datatype == TY_INT) {
+ do i = nrows+1, nelem
+ call tbapti (otp, ocp, row, undefi, i, 1)
+ } else if (datatype == TY_SHORT) {
+ do i = nrows+1, nelem
+ call tbapts (otp, ocp, row, undefs, i, 1)
+ } else if (datatype == TY_BOOL) {
+ do i = nrows+1, nelem
+ call tbaptb (otp, ocp, row, false, i, 1)
+ } else if (datatype < 0) {
+ slen = -datatype
+ do i = nrows+1, nelem
+ call tbaptt (otp, ocp, row, "", slen, i, 1)
+ }
+ }
+
+ call tbtclo (otp)
+ call tbtclo (itp)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/copyone/addslash.x b/pkg/utilities/nttools/copyone/addslash.x
new file mode 100644
index 00000000..6c5c2ded
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/addslash.x
@@ -0,0 +1,32 @@
+# ADDSLASH -- Convert a string by prefixing quote marks with backslashes
+#
+# B.Simon 30-Sep-87 First Code
+
+procedure addslash (str, maxch)
+
+char str[ARB] # String to be converted
+int maxch # Maximum length of string
+
+int i, j
+pointer sp, aux
+
+begin
+ call smark (sp)
+ call salloc (aux, maxch, TY_CHAR)
+
+ j = 1
+ for (i = 1; (str[i] != EOS) && (j <= maxch); i = i + 1) {
+ if (str[i] == '"') {
+ if (j == maxch)
+ break
+ Memc[aux+j-1] = '\\'
+ j = j + 1
+ }
+ Memc[aux+j-1] = str[i]
+ j = j + 1
+ }
+
+ Memc[aux+j-1] = EOS
+ call strcpy (Memc[aux], str, maxch)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/copyone/datatype.x b/pkg/utilities/nttools/copyone/datatype.x
new file mode 100644
index 00000000..d35732f9
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/datatype.x
@@ -0,0 +1,79 @@
+include <lexnum.h>
+
+# DATATYPE -- Determine the data type of a character string token
+#
+# B.Simon 13-Aug-87 First Code
+# B.Simon 27-Jul-94 Distinguish between double and real
+# B.Simon 15-Sep-94 Add check of token length for TY_CHAR
+# B.Simon 15-Dec-94 Replace test for double
+
+int procedure datatype (token)
+
+char token[ARB] # i: Character string token
+#--
+int ic, dtype, nchar, ndigit
+pointer sp, utoken
+
+
+bool streq()
+int nowhite(), lexnum(), is_double()
+
+begin
+ # Convert token to upper case with no whitespace
+
+ call smark (sp)
+ call salloc (utoken, SZ_LINE, TY_CHAR)
+
+ nchar = nowhite (token, Memc[utoken], SZ_LINE)
+ call strupr (Memc[utoken])
+
+ # Determine if token is a number
+
+ ic = 1
+ switch (lexnum (Memc[utoken], ic, ndigit)) {
+ case LEX_OCTAL :
+ dtype = TY_INT
+ case LEX_DECIMAL :
+ dtype = TY_INT
+ case LEX_HEX :
+ dtype = TY_CHAR
+ case LEX_REAL :
+ dtype = TY_REAL
+ case LEX_NONNUM :
+ dtype = TY_CHAR
+ }
+
+ # Check number of digits parsed against length of string
+ # if it is shorter, we have a character string that starts
+ # with a digit
+
+ if (ndigit != nchar)
+ dtype = TY_CHAR
+
+ # Determine if string is boolean
+
+ switch (Memc[utoken]) {
+ case 'T':
+ if (streq (Memc[utoken],"T") || streq (Memc[utoken],"TRUE"))
+ dtype = TY_BOOL
+ case 'F':
+ if (streq (Memc[utoken],"F") || streq (Memc[utoken],"FALSE"))
+ dtype = TY_BOOL
+ case 'Y':
+ if (streq (Memc[utoken],"Y") || streq (Memc[utoken],"YES"))
+ dtype = TY_BOOL
+ case 'N':
+ if (streq (Memc[utoken],"N") || streq (Memc[utoken],"NO"))
+ dtype = TY_BOOL
+ }
+
+ # Determine if datatype is real or double by the number of digits
+ # and / or the presence of "D"
+
+ if (dtype == TY_REAL)
+ dtype = is_double (Memc[utoken])
+
+ call sfree (sp)
+ return (dtype)
+end
+
diff --git a/pkg/utilities/nttools/copyone/filetype.h b/pkg/utilities/nttools/copyone/filetype.h
new file mode 100644
index 00000000..b2d84cc6
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/filetype.h
@@ -0,0 +1,5 @@
+# Symbolic representation of file types supported by SDAS
+
+define UNKNOWN_FILE 0
+define IMAGE_FILE 1
+define TABLE_FILE 2
diff --git a/pkg/utilities/nttools/copyone/filetype.x b/pkg/utilities/nttools/copyone/filetype.x
new file mode 100644
index 00000000..3424b5ea
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/filetype.x
@@ -0,0 +1,28 @@
+include "filetype.h"
+
+# FILETYPE -- Determine filetype of file
+
+int procedure filetype (file)
+
+char file # i: file name
+#--
+int flag
+
+int is_image()
+
+begin
+ # Is_image is in the selector sublibrary of tbtables
+ # and is the recommended procedure for determining file
+ # type
+
+ switch (is_image(file)) {
+ case ERR:
+ flag = UNKNOWN_FILE
+ case NO:
+ flag = TABLE_FILE
+ case YES:
+ flag = IMAGE_FILE
+ }
+
+ return (flag)
+end
diff --git a/pkg/utilities/nttools/copyone/filetype.x.OLD b/pkg/utilities/nttools/copyone/filetype.x.OLD
new file mode 100644
index 00000000..65e30293
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/filetype.x.OLD
@@ -0,0 +1,61 @@
+include "filetype.h"
+
+# FILETYPE -- Determine the file type from the file name. Say the file type
+# is unknown if the file cannot be accessed or the name is ambiguous.
+#
+# B.Simon Aug-13-87 First Code
+# B.Simon Jan-24-92 Added salloc for extension
+
+int procedure filetype (fname)
+
+char fname[ARB] # i: file name
+#--
+int ftype
+pointer sp, extension, cluster
+
+int fnextn(), imaccess(), tabaccess(), access()
+
+begin
+ call smark (sp)
+ call salloc (extension, SZ_FNAME, TY_CHAR) # Added (BPS 01.24.92)
+ call salloc (cluster, SZ_FNAME, TY_CHAR)
+
+ ftype = UNKNOWN_FILE
+ call imgcluster (fname, Memc[cluster], SZ_FNAME)
+
+ if (access (Memc[cluster], 0, 0) == YES) {
+
+ # File exists with specified name
+
+ if (imaccess (Memc[cluster], READ_ONLY) == YES &&
+ imaccess (Memc[cluster], NEW_FILE) == YES )
+
+ ftype = IMAGE_FILE
+
+ else if (tabaccess (Memc[cluster], READ_ONLY) == YES)
+
+ ftype = TABLE_FILE
+
+ } else if (fnextn (Memc[cluster], Memc[extension], SZ_FNAME) == 0) {
+
+ # File name does not contain an extension,
+ # try adding default extensions
+
+ if (tabaccess (Memc[cluster], READ_ONLY) == YES &&
+ imaccess (Memc[cluster], READ_ONLY) == YES )
+
+ ftype = UNKNOWN_FILE
+
+ else if (imaccess (Memc[cluster], READ_ONLY) == YES)
+
+ ftype = IMAGE_FILE
+
+ else if (tabaccess (Memc[cluster], READ_ONLY) == YES)
+
+ ftype = TABLE_FILE
+
+ }
+
+ call sfree (sp)
+ return (ftype)
+end
diff --git a/pkg/utilities/nttools/copyone/getimghdr.x b/pkg/utilities/nttools/copyone/getimghdr.x
new file mode 100644
index 00000000..03dc9ced
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/getimghdr.x
@@ -0,0 +1,35 @@
+# GETIMGHDR -- Read a keyword from an image header into a string
+#
+# B.Simon 13-Aug-87 First Code
+# B.Simon 12-Dec-94 Added error check
+# B.Simon 21-Jul-97 Add extra check to work around imgftype bug
+
+procedure getimghdr (hd, keyword, maxch, value, keytype)
+
+pointer hd # i: Image descriptor
+char keyword[ARB] # i: Name of header keyword
+int maxch # i: Maximum length of keyword value
+char value[ARB] # o: Keyword value
+int keytype # o: Type of header keyword
+#--
+int imgftype()
+errchk imgstr
+
+begin
+ # Read image header keyword and get datatype
+
+ call imgstr (hd, keyword, value, maxch)
+ keytype = imgftype (hd, keyword)
+
+ # If boolean, convert to the standard names
+ # The check on value[2] is to work around a
+ # bug in imgftype()
+
+ if (value[2] == EOS && keytype == TY_BOOL)
+ if (value[1] == 'T')
+ call strcpy ("yes", value, maxch)
+ else
+ call strcpy ("no", value, maxch)
+
+ return
+end
diff --git a/pkg/utilities/nttools/copyone/gettabdat.x b/pkg/utilities/nttools/copyone/gettabdat.x
new file mode 100644
index 00000000..66a6c215
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/gettabdat.x
@@ -0,0 +1,111 @@
+include <tbset.h>
+define USRERR 1
+
+# GETTABDAT -- Read an element from a table into a string
+#
+# B.Simon 17-Aug-1987 First Code
+# Phil Hodge 15-May-2002 Add 'format' argument. ctowrd is a function.
+
+procedure gettabdat (hd, colname, rownum, maxch, format, value, undef, eltype)
+
+pointer hd # i: Table descriptor
+char colname[ARB] # i: Table column name
+int rownum # i: Table row number
+int maxch # i: Maximum length of element value
+bool format # i: Format the value using table print format?
+char value[ARB] # o: Table element value
+bool undef # o: Is table element undefined?
+int eltype # o: Type of table element
+
+bool nullbuf[1]
+int lendata, ip
+pointer colptr[1]
+pointer sp, errtxt, valbuf
+
+double dval[1]
+real rval[1]
+int ival[1]
+bool bval[1]
+
+string badnamerr "Column name not found in table (%s)"
+string unknown_type "Unknown data type in table"
+
+int tbcigi()
+int junk, ctowrd()
+
+begin
+ # Allocate dynamic memory to hold strings
+
+ call smark (sp)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+ call salloc (valbuf, maxch, TY_CHAR)
+
+ # Get the column pointer from the column name
+
+ call tbcfnd (hd, colname, colptr, 1)
+
+ # If the pointer is NULL, the column was not found
+
+ if (colptr[1] == NULL) {
+ call sprintf (Memc[errtxt], SZ_LINE, badnamerr)
+ call pargstr (colname)
+ call error (USRERR, Memc[errtxt])
+ }
+
+ # Get the column data type. Store in eltype
+
+ eltype = tbcigi (colptr[1], TBL_COL_DATATYPE)
+ if (eltype < 0) {
+ lendata = - eltype
+ eltype = TY_CHAR
+ }
+
+ # Get the table element as a text string
+
+ if (format || eltype == TY_CHAR) {
+ call tbrgtt (hd, colptr, Memc[valbuf], nullbuf, maxch, 1, rownum)
+ } else {
+ switch (eltype) {
+ case TY_BOOL :
+ call tbrgtb (hd, colptr, bval, nullbuf, 1, rownum)
+ if (bval[1])
+ call strcpy ("yes", Memc[valbuf], maxch)
+ else
+ call strcpy ("no", Memc[valbuf], maxch)
+ case TY_SHORT,TY_INT :
+ call tbrgti (hd, colptr, ival, nullbuf, 1, rownum)
+ call sprintf (Memc[valbuf], maxch, "%d")
+ call pargi (ival)
+ case TY_REAL :
+ call tbrgtr (hd, colptr, rval, nullbuf, 1, rownum)
+ call sprintf (Memc[valbuf], maxch, "%15.7g")
+ call pargr (rval)
+ case TY_DOUBLE :
+ call tbrgtd (hd, colptr, dval, nullbuf, 1, rownum)
+ call sprintf (Memc[valbuf], maxch, "%25.16g")
+ call pargd (dval)
+ default :
+ call error (1, unknown_type)
+ }
+ }
+
+ if (eltype == TY_CHAR) {
+
+ # Just do a straight copy if the element is a string
+
+ call strcpy (Memc[valbuf], value, maxch)
+
+ } else{
+
+ # Otherwise, strip whitespace from element value
+
+ ip = 1
+ junk = ctowrd (Memc[valbuf], ip, value, maxch)
+
+ }
+
+ undef = nullbuf[1]
+ call sfree (sp)
+
+ return
+end
diff --git a/pkg/utilities/nttools/copyone/gettabhdr.x b/pkg/utilities/nttools/copyone/gettabhdr.x
new file mode 100644
index 00000000..4e9812bc
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/gettabhdr.x
@@ -0,0 +1,55 @@
+# GETTABHDR -- Read a keyword from an table header into a string
+#
+# B.Simon 14-Aug-87 First Code
+# B.Simon 12-Dec-94 Added error check
+
+procedure gettabhdr (hd, keyword, maxch, value, keytype)
+
+pointer hd # i: Table descriptor
+char keyword[ARB] # i: Name of header keyword
+int maxch # i: Maximum length of keyword value
+char value[ARB] # o: Keyword value
+int keytype # o: Type of header keyword
+#--
+int ip
+pointer keyval, sp
+
+int tabhdrtyp()
+errchk tbhgtt
+
+begin
+ call smark (sp)
+ call salloc (keyval, maxch, TY_CHAR)
+
+ # Read table header keyword and get datatype
+
+ call tbhgtt (hd, keyword, Memc[keyval], maxch)
+ keytype = tabhdrtyp (hd, keyword)
+
+ if (keytype == TY_CHAR) {
+
+ # Just do a straight copy if the keyword is a string
+
+ call strcpy (Memc[keyval], value, maxch)
+
+ } else{
+
+ # Otherwise, strip whitespace from keyword value
+
+ ip = 1
+ call ctowrd (Memc[keyval], ip, value, maxch)
+
+ # If boolean, convert to the standard names
+
+ if (keytype == TY_BOOL) {
+
+ if (value[1] == '1')
+ call strcpy ("yes", value, maxch)
+ else
+ call strcpy ("no", value, maxch)
+ }
+ }
+
+ call sfree (sp)
+ return
+end
diff --git a/pkg/utilities/nttools/copyone/isdouble.x b/pkg/utilities/nttools/copyone/isdouble.x
new file mode 100644
index 00000000..4ee128cc
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/isdouble.x
@@ -0,0 +1,37 @@
+include <ctype.h>
+include <mach.h>
+
+# IS_DOUBLE -- Check to see if a real number is actually double precision
+#
+# B.Simon 15-Dec-94 First Code
+
+int procedure is_double (token)
+
+char token[ARB] # i: token containing number
+#--
+int ic, ndigit
+
+begin
+ # Count number of digits in mantissa and look for D exponent
+
+ ndigit = 0
+ for (ic = 1; token[ic] != EOS; ic = ic + 1) {
+ if (token[ic] == 'D' || token[ic] == 'd') {
+ return (TY_DOUBLE)
+
+ } else if (token[ic] == 'E' || token[ic] == 'e') {
+ break
+ }
+
+ if (IS_DIGIT(token[ic]))
+ ndigit = ndigit + 1
+ }
+
+ # If no D exponent, set the type according to the number of digits
+
+ if (ndigit > NDIGITS_RP) {
+ return (TY_DOUBLE)
+ } else {
+ return (TY_REAL)
+ }
+end
diff --git a/pkg/utilities/nttools/copyone/keypar.x b/pkg/utilities/nttools/copyone/keypar.x
new file mode 100644
index 00000000..0a5c9423
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/keypar.x
@@ -0,0 +1,109 @@
+include "filetype.h"
+
+define SZ_KEYWORD 64
+define USRERR 1
+
+# KEYPAR -- Transfer header keyword to IRAF parameter
+#
+# B.Simon 14-Aug-87 First Code
+# B.Simon 14-Dec-94 Added error checking
+
+procedure t_keypar()
+
+#--
+pointer input # Name of file containing header keyword
+pointer keyword # Name of header keyword
+bool silent # Don't print warning message
+pointer value # IRAF parameter value
+
+bool found
+int ftype, keytype, junk
+pointer errtxt, sp, hd
+
+string unfilerr "Header file name not found or ambiguous (%s)"
+
+bool clgetb()
+int filetype(), errget()
+pointer immap(), tbtopn()
+
+begin
+ # Allocate storage for character strings
+
+ call smark (sp)
+ call salloc (input, SZ_FNAME, TY_CHAR)
+ call salloc (keyword, SZ_KEYWORD, TY_CHAR)
+ call salloc (value, SZ_KEYWORD, TY_CHAR)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ # Read input parameters
+
+ call clgstr ("input", Memc[input], SZ_FNAME)
+ call clgstr ("keyword", Memc[keyword], SZ_KEYWORD)
+ silent = clgetb ("silent")
+
+ ftype = filetype (Memc[input])
+
+ if (ftype == IMAGE_FILE) {
+
+ # Read image header keyword and get datatype
+
+ found = true
+ hd = immap (Memc[input], READ_ONLY, NULL)
+ iferr {
+ call getimghdr (hd, Memc[keyword], SZ_KEYWORD,
+ Memc[value], keytype)
+ } then {
+ junk = errget (Memc[errtxt], SZ_LINE)
+ call xer_reset
+
+ keytype = TY_CHAR
+ Memc[value] = EOS
+ found = false
+
+ if (! silent) {
+ call eprintf ("Warning: %s\n")
+ call pargstr (Memc[errtxt])
+ }
+ }
+ call imunmap (hd)
+
+ } else if (ftype == TABLE_FILE) {
+
+ # Read table header keyword and get datatype
+
+ found = true
+ hd = tbtopn (Memc[input], READ_ONLY, NULL)
+ iferr {
+ call gettabhdr (hd, Memc[keyword], SZ_KEYWORD,
+ Memc[value], keytype)
+ } then {
+ junk = errget (Memc[errtxt], SZ_LINE)
+ call xer_reset
+
+ keytype = TY_CHAR
+ Memc[value] = EOS
+ found = false
+
+ if (! silent) {
+ call eprintf ("Warning: %s\n")
+ call pargstr (Memc[errtxt])
+ }
+ }
+ call tbtclo (hd)
+
+ } else {
+
+ call sprintf (Memc[errtxt], SZ_LINE, unfilerr)
+ call pargstr (Memc[input])
+ call error (USRERR, Memc[errtxt])
+
+ }
+
+ # Write output parameters and free string storage
+
+ call addslash (Memc[value], SZ_KEYWORD)
+ call clpstr ("value", Memc[value])
+ call clputb ("found", found)
+ call sfree(sp)
+ return
+end
diff --git a/pkg/utilities/nttools/copyone/keytab.x b/pkg/utilities/nttools/copyone/keytab.x
new file mode 100644
index 00000000..38577404
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/keytab.x
@@ -0,0 +1,113 @@
+include <tbset.h>
+include "filetype.h"
+
+define SZ_KEYWORD 64
+define USRERR 1
+
+# KEYTAB -- Transfer a header keyword to a table element
+#
+# B.Simon 17-Aug-87 First Code
+# B.Simon 14-Dec-94 Added error checking
+
+procedure t_keytab ()
+
+#--
+pointer input # Name of file containing header keyword
+pointer keyword # Name of header keyword
+pointer table # Name of table
+pointer column # Name of column
+int row # Row number of element in the table
+bool silent # Don't print warning message
+
+bool undef
+int ftype, keytype, junk
+pointer value, errtxt, sp, hd
+
+string unfilerr "Header file name not found or ambiguous (%s)"
+
+bool clgetb()
+int clgeti(), filetype(), errget()
+pointer immap(), tbtopn()
+
+begin
+ # Allocate storage for character strings
+
+ call smark (sp)
+ call salloc (input, SZ_FNAME, TY_CHAR)
+ call salloc (keyword, SZ_KEYWORD, TY_CHAR)
+ call salloc (table, SZ_FNAME, TY_CHAR)
+ call salloc (column, SZ_COLNAME, TY_CHAR)
+ call salloc (value, SZ_KEYWORD, TY_CHAR)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ # Read input parameters
+
+ call clgstr ("input", Memc[input], SZ_FNAME)
+ call clgstr ("keyword", Memc[keyword], SZ_KEYWORD)
+ call clgstr ("table", Memc[table], SZ_FNAME)
+ call clgstr ("column", Memc[column], SZ_COLNAME)
+ row = clgeti ("row")
+ silent = clgetb ("silent")
+
+ undef = false
+ ftype = filetype (Memc[input])
+
+ if (ftype == IMAGE_FILE) {
+
+ # Read image header keyword and get datatype
+
+ hd = immap (Memc[input], READ_ONLY, NULL)
+ iferr {
+ call getimghdr (hd, Memc[keyword], SZ_KEYWORD,
+ Memc[value], keytype)
+ } then {
+ junk = errget (Memc[errtxt], SZ_LINE)
+ call xer_reset
+ undef = true
+
+ if (! silent) {
+ call eprintf ("Warning: %s\n")
+ call pargstr (Memc[errtxt])
+ }
+ }
+ call imunmap (hd)
+
+ } else if (ftype == TABLE_FILE) {
+
+ # Read table header keyword and get datatype
+
+ hd = tbtopn (Memc[input], READ_ONLY, NULL)
+ iferr {
+ call gettabhdr (hd, Memc[keyword], SZ_KEYWORD,
+ Memc[value], keytype)
+ } then {
+ junk = errget (Memc[errtxt], SZ_LINE)
+ call xer_reset
+ undef = true
+
+ if (! silent) {
+ call eprintf ("Warning: %s\n")
+ call pargstr (Memc[errtxt])
+ }
+ }
+ call tbtclo (hd)
+
+ } else {
+
+ call sprintf (Memc[errtxt], SZ_LINE, unfilerr)
+ call pargstr (Memc[input])
+ call error (USRERR, Memc[errtxt])
+
+ }
+
+ # Write the table element according to its datatype
+
+ hd = tbtopn (Memc[table], READ_WRITE, NULL)
+ call puttabdat (hd, Memc[column], row, Memc[value], undef, keytype)
+ call tbtclo (hd)
+
+ # Free string storage
+
+ call sfree (sp)
+ return
+end
diff --git a/pkg/utilities/nttools/copyone/mkpkg b/pkg/utilities/nttools/copyone/mkpkg
new file mode 100644
index 00000000..815e2d9d
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/mkpkg
@@ -0,0 +1,29 @@
+# Update the KEYPAR, KEYTAB, PARKEY, PARTAB, TABKEY, TABPAR task code
+# in the ttools package library
+# Author: B.Simon, 25-NOV-1987
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ addslash.x
+ datatype.x <lexnum.h>
+ filetype.x filetype.h
+ getimghdr.x
+ gettabdat.x <tbset.h>
+ gettabhdr.x
+ isdouble.x <ctype.h> <mach.h>
+ keypar.x filetype.h
+ keytab.x <tbset.h> filetype.h
+ parkey.x filetype.h
+ partab.x <tbset.h>
+ putimghdr.x
+ puttabdat.x <tbset.h>
+ puttabhdr.x
+ tabaccess.x
+ tabhdrtyp.x <tbset.h>
+ tabkey.x <tbset.h> filetype.h
+ tabpar.x <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/copyone/parkey.x b/pkg/utilities/nttools/copyone/parkey.x
new file mode 100644
index 00000000..c473ee80
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/parkey.x
@@ -0,0 +1,71 @@
+include "filetype.h"
+
+define SZ_KEYWORD 64
+define USRERR 1
+
+# PARKEY -- Transfer IRAF parameter to header keyword
+#
+# B.Simon 14-Aug-87 First Code
+
+procedure t_parkey()
+
+pointer value # IRAF parameter value
+pointer output # Name of file containing header keyword
+pointer keyword # Name of header keyword
+bool add # Is it OK to add a new keyword?
+
+int ftype, keytype
+pointer errtxt, sp, hd
+
+string unfilerr "Header file name not found or ambiguous (%s)"
+
+bool clgetb()
+int filetype(), datatype()
+pointer immap(), tbtopn()
+
+begin
+ # Allocate storage for character strings
+
+ call smark (sp)
+ call salloc (value, SZ_KEYWORD, TY_CHAR)
+ call salloc (output, SZ_FNAME, TY_CHAR)
+ call salloc (keyword, SZ_KEYWORD, TY_CHAR)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ # Read parameters
+
+ call clgstr ("value", Memc[value], SZ_KEYWORD)
+ call clgstr ("output", Memc[output], SZ_FNAME)
+ call clgstr ("keyword", Memc[keyword], SZ_KEYWORD)
+ add = clgetb("add")
+
+ ftype = filetype (Memc[output])
+ keytype = datatype (Memc[value])
+
+ if (ftype == IMAGE_FILE) {
+
+ # Write image header keyword
+
+ hd = immap (Memc[output], READ_WRITE, NULL)
+ call putimghdr (hd, Memc[keyword], Memc[value], keytype, add)
+ call imunmap (hd)
+
+ } else if (ftype == TABLE_FILE) {
+
+ # Write table header keyword
+
+ hd = tbtopn (Memc[output], READ_WRITE, NULL)
+ call puttabhdr (hd, Memc[keyword], Memc[value], keytype, add)
+ call tbtclo (hd)
+
+ } else {
+
+ call sprintf (Memc[errtxt], SZ_LINE, unfilerr)
+ call pargstr (Memc[output])
+ call error (USRERR, Memc[errtxt])
+
+ }
+
+ call sfree(sp)
+ return
+end
diff --git a/pkg/utilities/nttools/copyone/partab.x b/pkg/utilities/nttools/copyone/partab.x
new file mode 100644
index 00000000..19505049
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/partab.x
@@ -0,0 +1,51 @@
+include <tbset.h>
+define SZ_KEYWORD 64
+
+# PARTAB -- Transfer an IRAF parameter value to a table element
+#
+# B.Simon 17-Aug-87 First Code
+
+procedure t_partab ()
+
+pointer value # Value of table element
+pointer table # Name of table
+pointer column # Name of column
+int row # Row number of element in the table
+
+bool undef
+int eltype
+pointer sp, hd
+
+bool streq()
+int clgeti(), datatype()
+pointer tbtopn()
+
+begin
+ # Allocate storage for character strings
+
+ call smark (sp)
+ call salloc (value, SZ_KEYWORD, TY_CHAR)
+ call salloc (table, SZ_FNAME, TY_CHAR)
+ call salloc (column, SZ_COLNAME, TY_CHAR)
+
+ # Read input parameters
+
+ call clgstr ("value", Memc[value], SZ_KEYWORD)
+ call clgstr ("table", Memc[table], SZ_FNAME)
+ call clgstr ("column", Memc[column], SZ_COLNAME)
+ row = clgeti ("row")
+
+ eltype = datatype (Memc[value])
+ undef = streq (Memc[value], "INDEF")
+
+ # Write the table element according to its datatype
+
+ hd = tbtopn (Memc[table], READ_WRITE, NULL)
+ call puttabdat (hd, Memc[column], row, Memc[value], undef, eltype)
+ call tbtclo (hd)
+
+ # Free string storage
+
+ call sfree (sp)
+ return
+end
diff --git a/pkg/utilities/nttools/copyone/putimghdr.x b/pkg/utilities/nttools/copyone/putimghdr.x
new file mode 100644
index 00000000..bc0b34c6
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/putimghdr.x
@@ -0,0 +1,118 @@
+define USRERR 1
+
+# PUTIMGHDR -- Put a keyword given as a string in an image header
+#
+# B.Simon 14-Aug-87 First Code
+# B.Simon 27-Jul-94 Fix bug in addition of double
+# B.Simon 21-Jul-97 Workaround for imgftype bug
+
+procedure putimghdr (hd, keyword, value, keytype, add)
+
+pointer hd # i: Image descriptor
+char keyword[ARB] # i: Keyword to put
+char value[ARB] # i: Keyword value
+int keytype # i: Keyword type
+bool add # i: Is adding a new keyword legal?
+#--
+bool bvalue
+double dvalue
+int ip, junk, hdrtype
+pointer sp, rp, keyval, errtxt
+
+string badtyperr "Type mismatch in header keyword (%s)"
+string notadderr "Keyword not found in header (%s)"
+
+int ctod(), idb_findrecord(), imgftype(), stridx()
+
+begin
+
+ call smark (sp)
+ call salloc (keyval, SZ_FNAME, TY_CHAR)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ # Convert keyword value to a double
+
+ ip = 1
+ junk = ctod (value, ip, dvalue)
+
+ # If keyword is already in the image header
+
+ if (idb_findrecord (hd, keyword, rp) > 0) {
+
+ hdrtype = imgftype (hd, keyword)
+
+ # Extra test to work around bug in imgftype
+
+ if (hdrtype == TY_BOOL) {
+ call imgstr(hd, keyword, Memc[keyval], SZ_FNAME)
+ if (Memc[keyval+1] != EOS)
+ hdrtype = TY_CHAR
+ }
+
+ # Check for illegal type conversions
+
+ if ((hdrtype == TY_BOOL && keytype != TY_BOOL) ||
+ (!(hdrtype == keytype || hdrtype == TY_CHAR) &&
+ (keytype == TY_BOOL || keytype == TY_CHAR) ) ) {
+
+ call sprintf (Memc[errtxt], SZ_LINE, badtyperr)
+ call pargstr (keyword)
+ call error (USRERR, Memc[errtxt])
+
+ }
+
+ # Use the proper procedure to write the new keyword value
+
+ switch (hdrtype) {
+ case TY_BOOL :
+ bvalue = stridx (value[1], "TtYy") > 0
+ call imputb (hd, keyword, bvalue)
+ case TY_CHAR :
+ call impstr (hd, keyword, value)
+ case TY_SHORT :
+ call imputs (hd, keyword, short(dvalue))
+ case TY_INT :
+ call imputi (hd, keyword, int(dvalue))
+ case TY_LONG :
+ call imputl (hd, keyword, long(dvalue))
+ case TY_REAL :
+ call imputr (hd, keyword, real(dvalue))
+ case TY_DOUBLE :
+ call imputd (hd, keyword, dvalue)
+ }
+
+ } else {
+
+ # Check to see if it legal to add a new keyword
+
+ if (! add) {
+ call sprintf (Memc[errtxt], SZ_LINE, notadderr)
+ call pargstr (keyword)
+ call error (USRERR, Memc[errtxt])
+ }
+
+ # Create the new keyword and set its value
+
+ switch (keytype) {
+ case TY_BOOL :
+ bvalue = stridx (value[1], "TtYy") > 0
+ call imaddb (hd, keyword, bvalue)
+ case TY_CHAR :
+ call imastr (hd, keyword, value)
+ case TY_SHORT :
+ call imadds (hd, keyword, short(dvalue))
+ case TY_INT :
+ call imaddi (hd, keyword, int(dvalue))
+ case TY_LONG :
+ call imaddl (hd, keyword, long(dvalue))
+ case TY_REAL :
+ call imaddr (hd, keyword, real(dvalue))
+ case TY_DOUBLE :
+ call imaddd (hd, keyword, dvalue)
+ }
+
+ }
+
+ call sfree (sp)
+ return
+end
diff --git a/pkg/utilities/nttools/copyone/puttabdat.x b/pkg/utilities/nttools/copyone/puttabdat.x
new file mode 100644
index 00000000..b5742f98
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/puttabdat.x
@@ -0,0 +1,106 @@
+include <tbset.h>
+define USRERR 1
+
+# PUTTABDAT -- Write a value passed as a string into a table element
+#
+# B.Simon 17-Aug-87 First Code
+
+procedure puttabdat (hd, colname, rownum, value, undef, eltype)
+
+pointer hd # i: Table descriptor
+char colname[ARB] # i: Table column name
+int rownum # i: Table row number
+char value[ARB] # i: Table element value
+bool undef # i: Is table element undefined?
+int eltype # i: Type of table element
+
+bool bvalue[1]
+double dvalue[1]
+int ivalue[1]
+pointer colptr[1]
+real rvalue[1]
+
+int coltype, lendata, ip, junk, maxch
+pointer sp, errtxt
+
+string badtyperr "Type mismatch in table column (%s)"
+string badnamerr "Column name not found in table (%s)"
+
+int ctod()
+int stridx(), strlen(), tbcigi()
+
+begin
+ # Allocate dynamic memory to hold strings
+
+ call smark (sp)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ # Get the column pointer from the column name
+
+ call tbcfnd (hd, colname, colptr, 1)
+
+ # If the pointer is NULL, the column was not found
+
+ if (colptr[1] == NULL) {
+ call sprintf (Memc[errtxt], SZ_LINE, badnamerr)
+ call pargstr (colname)
+ call error (USRERR, Memc[errtxt])
+ }
+
+ # Get the column data type. Store in coltype
+
+ coltype = tbcigi (colptr[1], TBL_COL_DATATYPE)
+ if (coltype < 0) {
+ lendata = - coltype
+ coltype = TY_CHAR
+ }
+
+ if (undef)
+
+ # Set table element to undefined
+
+ call tbrudf (hd, colptr, 1, rownum)
+
+ else {
+
+ # Convert element value to a double
+
+ ip = 1
+ junk = ctod (value, ip, dvalue[1])
+
+ # Check for illegal type conversions
+
+ if ((coltype == TY_BOOL && eltype != TY_BOOL) ||
+ (!(coltype == eltype || coltype == TY_CHAR) &&
+ (eltype == TY_BOOL || eltype == TY_CHAR) ) ) {
+
+ call sprintf (Memc[errtxt], SZ_LINE, badtyperr)
+ call pargstr (colname)
+ call error (USRERR, Memc[errtxt])
+
+ }
+
+ # Use the proper procedure to write the new element value
+
+ switch (coltype) {
+ case TY_BOOL :
+ bvalue[1] = stridx (value[1], "TtYy") > 0
+ call tbrptb (hd, colptr, bvalue, 1, rownum)
+ case TY_CHAR :
+ maxch = strlen (value) + 1
+ call tbrptt (hd, colptr, value, maxch, 1, rownum)
+ case TY_SHORT,TY_INT,TY_LONG :
+ ivalue[1] = int (dvalue[1])
+ call tbrpti (hd, colptr, ivalue, 1, rownum)
+ case TY_REAL :
+ rvalue[1] = real (dvalue[1])
+ call tbrptr (hd, colptr, rvalue, 1, rownum)
+ case TY_DOUBLE :
+ call tbrptd (hd, colptr, dvalue, 1, rownum)
+ }
+ }
+
+ call sfree (sp)
+
+ return
+end
diff --git a/pkg/utilities/nttools/copyone/puttabhdr.x b/pkg/utilities/nttools/copyone/puttabhdr.x
new file mode 100644
index 00000000..ffcb6643
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/puttabhdr.x
@@ -0,0 +1,104 @@
+define USRERR 1
+
+# PUTTABHDR -- Put a keyword given as a string in a table header
+#
+# B.Simon 14-Aug-87 First Code
+# B.Simon 27-Jul-94 Fix bug in addition of double
+# B.Simon 10-Nov-95 Add check for history keyword
+
+procedure puttabhdr (hd, keyword, value, keytype, add)
+
+pointer hd # i: Table descriptor
+char keyword[ARB] # i: Keyword to put
+char value[ARB] # i: Keyword value
+int keytype # i: Keyword type
+bool add # i: Is adding a new keyword legal?
+#--
+bool bvalue
+double dvalue
+int ip, junk, hdrtype, keynum
+pointer sp, errtxt
+
+string badtyperr "Type mismatch in header keyword (%s)"
+string notadderr "Keyword not found in header (%s)"
+
+bool tbhisc()
+int ctod(), tabhdrtyp(), stridx()
+
+begin
+
+ call smark (sp)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ # Convert keyword value to a double
+
+ ip = 1
+ junk = ctod (value, ip, dvalue)
+
+ # If keyword is not already in the table header
+ # or this is a history keyword
+
+ call tbhfkw (hd, keyword, keynum)
+ if ( keynum == 0 || tbhisc (keyword)) {
+
+ # Check to see if it legal to add a new keyword
+
+ if (! add) {
+ call sprintf (Memc[errtxt], SZ_LINE, notadderr)
+ call pargstr (keyword)
+ call error (USRERR, Memc[errtxt])
+ }
+
+ # Create the new keyword and set its value
+
+ switch (keytype) {
+ case TY_BOOL :
+ bvalue = stridx (value[1], "TtYy") > 0
+ call tbhadb (hd, keyword, bvalue)
+ case TY_CHAR :
+ call tbhadt (hd, keyword, value)
+ case TY_SHORT,TY_INT,TY_LONG :
+ call tbhadi (hd, keyword, int(dvalue))
+ case TY_REAL :
+ call tbhadr (hd, keyword, real(dvalue))
+ case TY_DOUBLE :
+ call tbhadd (hd, keyword, dvalue)
+ }
+
+ } else {
+
+ hdrtype = tabhdrtyp (hd, keyword)
+
+ # Check for illegal type conversions
+
+ if ((hdrtype == TY_BOOL && keytype != TY_BOOL) ||
+ (!(hdrtype == keytype || hdrtype == TY_CHAR) &&
+ (keytype == TY_BOOL || keytype == TY_CHAR) ) ) {
+
+ call sprintf (Memc[errtxt], SZ_LINE, badtyperr)
+ call pargstr (keyword)
+ call error (USRERR, Memc[errtxt])
+
+ }
+
+ # Use the proper procedure to write the new keyword value
+
+ switch (hdrtype) {
+ case TY_BOOL :
+ bvalue = stridx (value[1], "TtYy") > 0
+ call tbhptb (hd, keyword, bvalue)
+ case TY_CHAR :
+ call tbhptt (hd, keyword, value)
+ case TY_SHORT,TY_INT,TY_LONG :
+ call tbhpti (hd, keyword, int(dvalue))
+ case TY_REAL :
+ call tbhptr (hd, keyword, real(dvalue))
+ case TY_DOUBLE :
+ call tbhptd (hd, keyword, dvalue)
+ }
+
+ }
+
+ call sfree (sp)
+ return
+end
diff --git a/pkg/utilities/nttools/copyone/tabaccess.x b/pkg/utilities/nttools/copyone/tabaccess.x
new file mode 100644
index 00000000..93c93337
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/tabaccess.x
@@ -0,0 +1,19 @@
+# TABACCESS -- Test to see if an table is accessible with the given access
+# mode. Return the result of the test as YES or NO.
+#
+# B.Simon 12-Aug-87 First Code
+# B.Simon 19-Jun-95 Revised to use tbtacc
+
+int procedure tabaccess (tablename, acmode)
+
+char tablename[ARB] # i: table file name
+int acmode # i: access mode
+#--
+int tbtacc()
+
+begin
+ if (acmode == NEW_FILE || acmode == NEW_COPY)
+ return (YES)
+
+ return (tbtacc (tablename))
+end
diff --git a/pkg/utilities/nttools/copyone/tabhdrtyp.x b/pkg/utilities/nttools/copyone/tabhdrtyp.x
new file mode 100644
index 00000000..7d65e89f
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/tabhdrtyp.x
@@ -0,0 +1,34 @@
+include <tbset.h>
+define USRERR 1
+
+# TABHDRTYP -- Return the type of a table header keyword
+#
+# B. Simon 12-Aug-87 First Code
+# Phil Hodge 9-Mar-89 Change to itype in calling sequence of tbhfkr.
+
+int procedure tabhdrtyp (tp, keyword)
+
+pointer tp # i: Table descriptor
+char keyword[ARB] # i: Header keyword
+#--
+int parnum, itype
+pointer sp, keyval, errtxt
+
+string nokeyfnd "Keyword not found (%s)"
+
+begin
+ call smark (sp)
+ call salloc (keyval, SZ_PARREC, TY_CHAR)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ call tbhfkr (tp, keyword, itype, Memc[keyval], parnum)
+
+ if (parnum == 0) {
+ call sprintf (Memc[errtxt], SZ_LINE, nokeyfnd)
+ call pargstr (keyword)
+ call error (USRERR, Memc[errtxt])
+ }
+
+ call sfree (sp)
+ return (itype)
+end
diff --git a/pkg/utilities/nttools/copyone/tabkey.x b/pkg/utilities/nttools/copyone/tabkey.x
new file mode 100644
index 00000000..9efd2329
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/tabkey.x
@@ -0,0 +1,94 @@
+include <tbset.h>
+include "filetype.h"
+define SZ_KEYWORD 64
+define USRERR 1
+
+# TABKEY -- Transfer a table element to a header keyword
+#
+# B.Simon 17-Aug-87 First Code
+# B.Simon 24-Jan-92 Added salloc for errtxt
+# Phil Hodge 15-May-2002 Add 'format' argument to gettabdat.
+
+procedure t_tabkey ()
+
+pointer table # Name of table
+pointer column # Name of column
+int row # Row number of element in the table
+pointer output # Name of file containing header keyword
+pointer keyword # Name of header keyword
+bool add # Is it OK to add a new keyword?
+
+bool undef
+bool format # Format the value using table print format?
+int ftype, eltype
+pointer sp, hd, value, errtxt
+
+string undeferr "Table element is undefined"
+string unfilerr "Header file name not found or ambiguous (%s)"
+
+bool clgetb()
+int clgeti(), filetype()
+pointer immap(), tbtopn()
+
+begin
+ # Allocate storage for character strings
+
+ call smark (sp)
+ call salloc (table, SZ_FNAME, TY_CHAR)
+ call salloc (column, SZ_COLNAME, TY_CHAR)
+ call salloc (output, SZ_FNAME, TY_CHAR)
+ call salloc (keyword, SZ_KEYWORD, TY_CHAR)
+ call salloc (value, SZ_KEYWORD, TY_CHAR)
+ call salloc (errtxt, SZ_LINE, TY_CHAR) # Added (BPS 01.24.92)
+
+ # Read input parameters
+
+ call clgstr ("table", Memc[table], SZ_FNAME)
+ call clgstr ("column", Memc[column], SZ_COLNAME)
+ row = clgeti ("row")
+ call clgstr ("output", Memc[output], SZ_FNAME)
+ call clgstr ("keyword", Memc[keyword], SZ_KEYWORD)
+ add = clgetb("add")
+
+ # Read the table element as a character string
+
+ format = false
+ hd = tbtopn (Memc[table], READ_ONLY, NULL)
+ call gettabdat (hd, Memc[column], row, SZ_KEYWORD, format,
+ Memc[value], undef, eltype)
+ call tbtclo (hd)
+
+ # It is an error to try to write an undefined value to the header
+
+ if (undef)
+ call error (USRERR, undeferr)
+
+ ftype = filetype (Memc[output])
+
+ if (ftype == IMAGE_FILE) {
+
+ # Write image header keyword
+
+ hd = immap (Memc[output], READ_WRITE, NULL)
+ call putimghdr (hd, Memc[keyword], Memc[value], eltype, add)
+ call imunmap (hd)
+
+ } else if (ftype == TABLE_FILE) {
+
+ # Write table header keyword
+
+ hd = tbtopn (Memc[output], READ_WRITE, NULL)
+ call puttabhdr (hd, Memc[keyword], Memc[value], eltype, add)
+ call tbtclo (hd)
+
+ } else {
+
+ call sprintf (Memc[errtxt], SZ_LINE, unfilerr)
+ call pargstr (Memc[output])
+ call error (USRERR, Memc[errtxt])
+
+ }
+
+ call sfree(sp)
+ return
+end
diff --git a/pkg/utilities/nttools/copyone/tabpar.x b/pkg/utilities/nttools/copyone/tabpar.x
new file mode 100644
index 00000000..a4f452c3
--- /dev/null
+++ b/pkg/utilities/nttools/copyone/tabpar.x
@@ -0,0 +1,54 @@
+include <tbset.h>
+define SZ_KEYWORD 64
+
+# TABPAR -- Transfer a table element to an IRAF parameter
+#
+# B.Simon 17-Aug-1987 First Code
+# Phil Hodge 15-May-2002 Add 'format' parameter.
+
+procedure t_tabpar ()
+
+pointer table # Name of table
+pointer column # Name of column
+int row # Row number of element in the table
+bool format # Format the value using table print format?
+pointer value # Value of table element
+bool undef # Is table element undefined?
+
+int eltype
+pointer sp, hd
+
+bool clgetb()
+int clgeti()
+pointer tbtopn()
+
+begin
+ # Allocate storage for character strings
+
+ call smark (sp)
+ call salloc (table, SZ_FNAME, TY_CHAR)
+ call salloc (column, SZ_COLNAME, TY_CHAR)
+ call salloc (value, SZ_KEYWORD, TY_CHAR)
+
+ # Read input parameters
+
+ call clgstr ("table", Memc[table], SZ_FNAME)
+ call clgstr ("column", Memc[column], SZ_COLNAME)
+ row = clgeti ("row")
+ format = clgetb ("format")
+
+ # Read the table element as a character string
+
+ hd = tbtopn (Memc[table], READ_ONLY, NULL)
+ call gettabdat (hd, Memc[column], row, SZ_KEYWORD, format,
+ Memc[value], undef, eltype)
+ call tbtclo (hd)
+
+ # Write output parameters and free string storage
+
+ call addslash (Memc[value], SZ_KEYWORD)
+ call clpstr ("value", Memc[value])
+ call clputb ("undef", undef)
+ call sfree (sp)
+ return
+end
diff --git a/pkg/utilities/nttools/doc/axispar.hlp b/pkg/utilities/nttools/doc/axispar.hlp
new file mode 100644
index 00000000..d2a8dcbc
--- /dev/null
+++ b/pkg/utilities/nttools/doc/axispar.hlp
@@ -0,0 +1,138 @@
+.help axispar Jul93 tables
+.ih
+NAME
+pltpar -- Edit the parameter set that describes axis attributes.
+.ih
+USAGE
+pltpar
+.ih
+DESCRIPTION
+The 'axispar' parameters specify the attributes of plot axes.
+
+Note that this is a pset, not an executable task; it defines a set of
+parameters used by other tasks. Invoking the pset by name runs
+'eparam' on the parameter set, allowing the user to modify the
+parameters. Alternatively, the parameters may be modified on the
+command line by specifying the pset name and parameter name, for
+example, the user can type "pltpar.pointmode=yes" to set only the
+'pointmode' parameter. Parameters can also be edited by using
+'eparam' on the calling task (e.g., by typing "eparam sgraph"), in
+which case, 'pltpar' will appear as one of the task parameters; the
+'pltpar' parameters may then be edited by positioning the cursor on
+the line containing the pset name and typing ":e". After editing
+the pset parameters, type Control-Z (or ":q")
+to return to the main task parameter menu.
+.ih
+PARAMETERS
+.ls (wl = 0.) [real]
+Left world X-coordinate if not autoscaling.
+.le
+.ls (wr = 0.) [real]
+Right world X-coordinate if not autoscaling.
+.le
+.ls (wb = 0.) [real]
+Lower world Y-coordinate if not autoscaling.
+.le
+.ls (wt = 0.) [real]
+Upper world Y-coordinate if not autoscaling.
+.le
+.ls (xflip = no) [boolean]
+Flip the autoscaled X axis?
+.le
+.ls (yflip = no) [boolean]
+Flip the autoscaled Y axis?
+.le
+.ls (transpose = no) [boolean]
+Transpose the X and Y axes of the plot? If 'transpose = no', the
+horizontal axis will have the X values or pixel number.
+.le
+.ls (logx = no) [boolean]
+Scale the X axis logarithmically?
+.le
+.ls (logy = no) [boolean]
+Scale the Y axis logarithmically?
+.le
+.ls (rejectlog = yes) [boolean]
+Replace invalid logarithmic values with 'INDEF'? Invalid values will
+be ignored in scaling and plotting.
+.le
+.ls (box = yes) [boolean]
+Draw the box containing the axes and labels around the edge of the
+window?
+.le
+.ls (ticklabels = yes) [boolean]
+Label major tick marks?
+.le
+.ls (grid = no) [boolean]
+Draw grid lines on the plot?
+.le
+.ls (xlabel) [string]
+X-axis label.
+.le
+.ls (ylabel) [string]
+Y-axis label.
+.le
+.ls (title = imtitle) [string]
+The plot title may consist of one or two lines of text. If the
+parameter 'sysid' is set to "yes", then the first line of the title is
+a standard system-supplied string containing the user's name, date,
+etc. If the 'title' parameter contains the string "imtitle" (the
+default), then the plot title will contain a line made up from the
+input file, image, or table name. The user can supply an optional
+string for the 'title' parameter--this string will replace the string
+resulting from the "imtitle" specification.
+.le
+.ls (sysid = yes) [boolean]
+Include standard system information in the plot title? If the 'sysid'
+parameter is "yes", then a string including the user's name, date, host
+name, etc. is included in the plot title.
+.le
+.ls (lintran = no) [boolean]
+Perform a linear transformation of the X axis?
+.le
+.ls (p1 = 0.) [real]
+Starting input pixel value if 'lintran = yes'.
+.le
+.ls (p2 = 0.) [real]
+Ending input pixel value if 'lintran = yes'.
+.le
+.ls (q1 = 0.) [real]
+Starting output pixel value if 'lintran = yes'.
+.le
+.ls (q2 = 1.) [real]
+Ending output pixel value if 'lintran = yes'.
+.le
+.ls (majrx = 5) [integer]
+Number of major divisions along the X grid.
+.le
+.ls (minrx = 5) [integer]
+Number of minor divisions along the X grid.
+.le
+.ls (majry = 5) [integer]
+Number of major divisions along the Y grid.
+.le
+.ls (minry = 5) [integer]
+Number of minor divisions along the Y grid.
+.le
+.ls (round = no) [boolean]
+Round axes to nice values? (Values at tick marks will be significant,
+based on scale of the data.)
+.le
+.ls (margin = INDEF) [real, min = 0, max = 1]
+The margin between the viewport edges (plot axes) and the limits of the
+plotted curve(s) as a fraction of the viewport (NDC). If 'margin =
+INDEF', the default, a 2.5% margin will apply. That is, the plotted
+curve(s) will be inset .025 times the size of the viewport. Set
+'margin = 0' to plot curves to the axes.
+.le
+.ls (version = 17August92) [string]
+Date the task was installed. This should not be changed by the user.
+.le
+.ih
+EXAMPLES
+.ih
+BUGS
+.ih
+SEE ALSO
+sgraph, pltpar, dvpar
+.endhelp
diff --git a/pkg/utilities/nttools/doc/dvpar.hlp b/pkg/utilities/nttools/doc/dvpar.hlp
new file mode 100644
index 00000000..94bb4971
--- /dev/null
+++ b/pkg/utilities/nttools/doc/dvpar.hlp
@@ -0,0 +1,68 @@
+.help dvpar Jul93 tables
+.ih
+NAME
+dvpar -- Edit the parameter set that describes the graphics device.
+.ih
+USAGE
+dvpar
+.ih
+DESCRIPTION
+The 'dvpar' parameter set (pset) specifies device-related parameters.
+These include the device name, whether plots should be appended to
+existing plots, and the edges of the device viewport--that part of the
+display device on which to draw the plot.
+
+Note that this is a parameter set (pset)--not an executable task. That
+means that if the task is invoked by name on the command line, it will
+start the 'eparam' task to edit the 'dvpar' parameters. Individual
+parameters may be assigned using CL assignment statements from the
+command line, or through the task parameters for 'fieldplot'.
+.ih
+PARAMETERS
+.ls (device = "stdgraph") [string]
+The graphics device name. The default, "stdgraph", uses the CL
+environment parameter `stdgraph' to find the device name. For
+example, if you are using gterm in SunView, you could have set
+`stdgraph=gterm' or `device=gterm'. To overlay graphics on an image
+display, use an "imd" device, "imdr" for red, "imdg" for green, etc.
+.le
+.ls (append = no) [boolean]
+Append the graph to an existing plot?
+.le
+.ls (left = 0) [real, min = 0, max = 1]
+The NDC coordinates of the left edge of the plot.
+.le
+.ls (right = 0) [real, min = 0, max = 1]
+The NDC coordinates of the right edge of the plot.
+.le
+.ls (bottom = 0) [real, min = 0, max = 1]
+The NDC coordinates of the bottom edge of the plot.
+.le
+.ls (top = 0) [real, min = 0, max = 1]
+The NDC coordinates of the top edge of the plot.
+.le
+.ls (fill = yes) [boolean]
+Fill the viewport?
+
+If set to "yes", the plot will fill the area specified by
+the 'left', 'right', 'bottom', and 'top' viewport parameters. Otherwise, the
+shape of the plot will reflect the aspect of the input data, but will
+not be larger than the specified viewport. Note that this does not
+apply to all tasks using the 'dvpar' pset.
+.le
+.ls (coords) [*gcur]
+Graphics cursor file.
+This is used if the task supports interaction via the graphics cursor.
+.le
+.ls (image_coord) [*imcur]
+Used if the task supports interaction via the image display cursor.
+.le
+.ih
+EXAMPLES
+.ih
+BUGS
+.ih
+SEE ALSO
+fieldplot, newcont, sgraph, siaper, wcslab,
+cursor, plot
+.endhelp
diff --git a/pkg/utilities/nttools/doc/gtedit.hlp b/pkg/utilities/nttools/doc/gtedit.hlp
new file mode 100644
index 00000000..6ce396cc
--- /dev/null
+++ b/pkg/utilities/nttools/doc/gtedit.hlp
@@ -0,0 +1,116 @@
+.help gtedit Aug93 tables
+.ih
+NAME
+gtedit -- Graphically edit an STSDAS table.
+.ih
+USAGE
+gtedit input xcolumn ycolumn
+.ih
+DESCRIPTION
+The 'gtedit' task lets you graphically edit
+an STSDAS table.
+You can use the editor to delete rows. You can
+also choose whether to overwrite the existing
+file (by setting 'inplace=yes') or you
+can create a new output table. You can also
+save deleted points in a separate file by
+setting the 'reject' parameter to an output
+file name.
+
+The rows that are plotted can be selected using the :x and :y
+commands to specify columns for the X and Y axes. Points that
+are to be deleted will be marked with an "x" (this information
+is retained if columns change).
+
+To mark a point for deletion you can:
+.nf
+1) Specify the points individually
+2) Define a box in which all points will be deleted
+3) Delete all points on one side of the cursor or line segment
+.fi
+
+You can also toggle between "delete mode" and "undelete mode". When
+you are in undelete mode, any previously-deleted points that you
+selected will be unmarked.
+
+If you don't like using 'gtedit', you can switch to the 'tedit'
+task and edit the table in the usual manner.
+.ih
+CURSOR COMMANDS
+
+.nf
+ GTEDIT Interactive Cursor Commands
+
+? Print options
+: Colon commands
+a print out the complete row for the data point nearest the cursor
+b delete all points with Y values less than the cursor Y position
+c mark the corner of a box
+d delete the point nearest the cursor
+e exit and save changes in the output table
+f make all the marked deletions and replot remaining data
+h print out the column names of the input table
+l delete all points with X values less than the cursor X position
+p replot the graph possibly using new data columns
+q quit and do not save changes made since the last 'f'
+r delete all points with X values greater than the cursor X position
+s mark one end of a line segment
+t delete all points with Y values greater than the cursor Y position
+u toggle between delete and undelete mode
+v change from gtedit to tedit mode
+z display current status (delete or undelete)
+
+:x(-) xcolumn set the table column for the X axis and possibly replot
+:y(-) ycolumn set the table column for the Y axis and possibly replot
+- do not automatically replot after reading in new column
+
+.fi
+.ih
+PARAMETERS
+.ls input [file name]
+The input table to be edited.
+.le
+.ls xcolumn
+The name of the column in the input table to use for the X-axis of the plot.
+.le
+.ls ycolumn
+The name of the column in the input table to use for the Y-axis of the plot.
+.le
+.ls (device = "stdgraph")
+The standard graphics device.
+.le
+.ls (commands = "")
+The graphics cursor.
+.le
+.ls (inplace = no)
+Edit the table inplace. No new output table is created and the original
+table is overwritten.
+.le
+.ls (output = "")
+The name of the output table if the input table is not edited inplace. If
+inplace = no then output should be a valid filename.
+.le
+.ls (reject = "")
+If this parameter contains a valid filename then this table will contain
+the points which were deleted using this task.
+.le
+.ls (gtpar = "") [pset]
+The name of the pset containing the parameters which describe the plot
+attributes.
+.ih
+EXAMPLES
+1. Edit a table containing the output photometry from DAOPHOT.
+Initially plot the magnitude (MAG) versus the error in the magnitude (MAGERR)
+to decide which points to delete.
+
+.nf
+ st> gtedit m31.mag MAG MERR
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Dennis Crabtree.
+.ih
+SEE ALSO
+.endhelp
diff --git a/pkg/utilities/nttools/doc/gtpar.hlp b/pkg/utilities/nttools/doc/gtpar.hlp
new file mode 100644
index 00000000..7a06d627
--- /dev/null
+++ b/pkg/utilities/nttools/doc/gtpar.hlp
@@ -0,0 +1,117 @@
+.help gtpar May92 tables
+.ih
+NAME
+pltpar -- Parameters describing plot attributes.
+.ih
+USAGE
+pltpar
+.ih
+DESCRIPTION
+Parameters in the 'gtpar' pset specify the attributes of plots drawn with the
+'gtedit' task.
+
+Note that this is a pset, not an executable task. Invoking the pset by name
+runs 'eparam', enabling the parameters to be interactively edited.
+Parameters can also be modified on the
+CL command line by specifying the pset name and parameter name,
+for example, "gtpar.box = no").
+The pset name will also appear as one of
+the task parameters in the 'gtedit' task;
+to change values in the pset,
+position the cursor to the 'gtpar' pset name and type ":e" to invoke 'eparam'.
+.ih
+PARAMETERS
+.ls (wx1 = 0) [real]
+Left world X-coordinate (if autoscaling is not used).
+.le
+.ls (wx2 = 0.) [real]
+Right world X-coordinate (if autoscaling is not used).
+.le
+.ls (wy1 = 0.) [real]
+Lower world Y-coordinate (if no autoscaling is used).
+.le
+.ls (wy2 = 0.) [real]
+Upper world Y-coord (if not autoscaling).
+.le
+.ls (marker = box) [string, allowed values: point | box | plus |
+cross | circle | diamond | hline | vline | hebar | vebar]
+
+The name of the style of marker plotted at each point if 'pointmode=yes'.
+.le
+.ls (szmarker = 0.005) [real]
+The size of the markers if 'pointmode = yes'. If this parameter is greater
+than 0, its value represents the marker size in world coordinates (WC). If it
+is less than zero, the absolute value will be used, representing size in
+normalized device coordinates (NDC). If it is set to exactly zero, and the
+input is from a list file,
+then the third column in the input data is used as the marker size.
+.le
+.ls (logx = no) [boolean]
+Scale the X axis logarithmically?
+.le
+.ls (logy = no) [boolean]
+Scale the Y axis logarithmically?
+.le
+.ls (box = yes) [boolean]
+Draw the box containing the axes and labels around periphery of the
+window?
+.le
+.ls (ticklabels = yes) [boolean]
+Label major tick marks?
+.le
+.ls (grid = no) [boolean]
+Draw grid lines on plot?
+.le
+.ls (xlabel) [string]
+X-axis label.
+.le
+.ls (ylabel) [string]
+Y-axis label.
+.le
+.ls (title = imtitle)
+The plot title consists of a standard system-supplied string containing
+the user's name, date, etc. If the 'title' parameter contains the string
+"imtitle" (the default), then the plot title will contain a second line
+made up from the input file or table name. Otherwise, the title will
+contain the string value.
+.le
+.ls (vx1 = 0.) [real, min = 0, max = 1]
+Left limit of device viewport.
+.le
+.ls (vx2 = 0.) [real, min = 0, max = 1]
+Right limit of device viewport.
+.le
+.ls (vy1 = 0.) [real, min = 0, max = 1]
+Bottom limit of device viewport.
+.le
+.ls (vy2 = 0.) [real], min = 0, max = 1]
+Upper limit of device viewport.
+.le
+.ls (majrx = 5) [integer]
+Number of major divisions along the X grid.
+.le
+.ls (minrx = 5) [integer]
+Number of minor divisions along the X grid.
+.le
+.ls (majry = 5) [integer]
+Number of major divisions along the Y grid.
+.le
+.ls (minry = 5) [integer]
+Number of minor divisions along the Y grid.
+.le
+.ls (round = no) [boolean]
+Round axes to nice values?
+.le
+.ls (fill = yes) [boolean]
+Fill the viewport rather than enforcing unity aspect ratio?
+.ih
+EXAMPLES
+.ih
+BUGS
+.ih
+SEE ALSO
+sgraph
+
+Type "help tables opt=sys" for a higher-level description of the 'tables'
+package.
+.endhelp
diff --git a/pkg/utilities/nttools/doc/imtab.hlp b/pkg/utilities/nttools/doc/imtab.hlp
new file mode 100644
index 00000000..a2438f8a
--- /dev/null
+++ b/pkg/utilities/nttools/doc/imtab.hlp
@@ -0,0 +1,169 @@
+.help imtab Mar2000 tables
+.nj
+.ih
+NAME
+imtab -- Create a table from an image.
+.ih
+USAGE
+imtab input outtable colname
+.ih
+DESCRIPTION
+This task copies data from an image to a table.
+Pixel values are read from the image line by line
+and written to a column in increasing row number.
+The image may be of any dimension,
+but a single column is written.
+If the table already exists then columns will be added to it;
+names of new columns must not conflict with existing names.
+If the table does not exist it will be created.
+
+The number of names in the 'input' list must be the same as
+the number of names in the 'outtable' list,
+unless 'outtable' is "STDOUT".
+
+Information about the image dimension and axis lengths will not be kept
+in keywords, but there is an option to write the image pixel numbers
+to columns of the table.
+The pixel coordinates may be just the pixel numbers,
+or they may be world coordinates at the pixel locations.
+
+A history record will be added to the table giving
+the name of the data column and the name of the image.
+If pixel coordinates are written to the table,
+another history record is written that also gives
+the column name for the image data
+and gives the column names for the pixel coordinates.
+.ih
+PARAMETERS
+.ls input = "" [file name template]
+The names of the images to be written to the tables.
+.le
+.ls outtable = "" [file name template]
+The names of the output tables.
+If outtable = "STDOUT" or if the output has been redirected,
+the values will be written to the standard output.
+
+If the output table is of type text (e.g. STDOUT),
+the data values will be in the first column.
+If the pixel coordinates are also printed,
+they will be in the following columns.
+.le
+.ls colname = "" [string]
+A column of this name will be created in the output table,
+and the values of the image will be written to this column.
+The same column name will be used for all output tables.
+.le
+.ls (pname = "") [string]
+If 'pname' is not null,
+the pixel coordinates will also be written to columns of the table.
+The names of these columns will be the value of 'pname' with the
+numbers 1, 2, 3, etc appended,
+corresponding to the sample number, line number, band number, etc.
+This may be especially useful for a multi-dimensional input image,
+since all the data values are written to one column.
+The same column names will be used for all output tables.
+See also 'wcs' and 'formats'.
+
+If 'pname' is null (or blank) the pixel numbers will not be written.
+.le
+.ls (wcs = "logical") [string, allowed values: logical | physical | world]
+This parameter is only gotten if 'pname' is not null.
+In this case, the user has the option of which coordinate system
+should be used when writing pixel coordinates to the table.
+The "logical" coordinates are simply the pixel numbers
+of the image or image section.
+The "physical" coordinates are also pixel numbers,
+but they can differ from logical coordinates
+if an image section has been taken.
+Physical coordinates have the same origin and sampling as the original image.
+The "world" coordinates are coordinates such as wavelength, time,
+or right ascension and declination.
+The translation from logical to world coordinates is given by
+header keywords CRVAL1, CRPIX1, CD1_1, CTYPE1, etc.
+
+The number of pixel coordinates written by 'imtab' differs from
+the number written by 'listpixels' when wcs = "physical" or "world"
+and an image section was used that reduces the dimension of the image.
+'imtab' gives one pixel coordinate column for each dimension
+of the original image, while 'listpixels' gives one pixel coordinate
+for each dimension of the image section.
+
+Type "help mwcs$MWCS.hlp fi+" for extensive information on coordinate systems.
+.le
+.ls (formats) [string]
+The print formats to use for the pixel coordinates, one format
+per axis, with the individual formats separated by whitespace.
+This parameter is only gotten if 'pname' is not null.
+If the formats are not given, a default format is assigned.
+See the help for 'listpixels' for extensive information on formats.
+These formats are saved in the descriptors for the table columns,
+so these formats will be used if the table is printed.
+If the output table is text rather than binary,
+these formats will be used to write the coordinates to the text table.
+.le
+.ls (tbltype = "default") [string, allowed values: default | row |
+column | text ]
+
+If the output table does not already exist,
+you can specify whether the table should be created in row or column
+ordered format.
+As an alternative to a binary table,
+tbltype = "text" means the output will be a plain text file.
+.le
+.ih
+EXAMPLES
+1. Copy image "hr465_flux.imh" to table "hr465.tab", column "flux":
+
+.nf
+ tt> imtab hr465_flux.imh hr465.tab flux
+.fi
+
+2. Copy the 2-D image "ir27.hhh" to column "ir27" of table "map.tab",
+saving the pixel numbers in columns "pix1" and "pix2":
+
+.nf
+ tt> imtab ir27.hhh map.tab ir27 pname="pix"
+.fi
+
+3. Copy the 1-D section [257:257,129:384] of
+x0y70206t.d0h to column "x0y70206" of table "focus.tab".
+Also write the right ascension and declination
+("world" coordinates) to columns "p1" and "p2" respectively
+using HH:MM:SS.d and DD:MM:SS.d formats.
+We use "%12.1H" for right ascension and "%12.1h" for declination.
+The capital "H" in the format means that the values will be divided by 15
+to convert from degrees to hours before formatting in sexagesimal.
+Note that we get two columns of pixel coordinates even though
+the image section is only 1-D.
+Physical or world coordinates will be 2-D in this case
+because the original image "x0y70206t.d0h" is 2-D.
+
+.nf
+ tt> imtab x0y70206t.d0h[257:257,129:384] focus.tab x0y70206 \
+ >>> pname="p" wcs="world" formats="%12.1H %12.1h"
+.fi
+
+4. Use the same image as in the previous example,
+but print the values on the standard output.
+
+.nf
+ tt> imtab x0y70206t.d0h[257:257,129:384] STDOUT x0y70206 \
+ >>> pname="p" wcs="world" formats="%12.1H %12.1h"
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+.ih
+SEE ALSO
+The 'tabim' task copies a column of a table to an image.
+The 'listpixels' task in the 'images' package writes data values and
+pixel coordinates to the standard output.
+The parameters 'wcs' and 'formats' are the same in 'imtab' and 'listpixels'.
+For detailed information on the distinction between logical, physical and
+world coordinates, type "help mwcs$MWCS.hlp fi+".
+
+Type "help tables option=sys" for a higher-level description of
+the tables package.
+.endhelp
diff --git a/pkg/utilities/nttools/doc/keypar.hlp b/pkg/utilities/nttools/doc/keypar.hlp
new file mode 100644
index 00000000..b1f395f6
--- /dev/null
+++ b/pkg/utilities/nttools/doc/keypar.hlp
@@ -0,0 +1,83 @@
+.help keypar Dec94 tables
+.ih
+NAME
+keypar -- Copy a header keyword to an IRAF parameter.
+.ih
+USAGE
+keypar input keyword
+.ih
+DESCRIPTION
+This task reads a header keyword from an image or table file. The
+keyword is written to the IRAF parameter 'value' as a character
+string. If the header keyword is boolean, the value of 'value' will
+either be "yes" or "no". If the header keyword is not found, 'value'
+will be set to a null string. String parameters, such as 'value', can
+be converted to numeric data types with the built in functions real()
+and int().
+.ih
+PARAMETERS
+.ls input [file name]
+Name of the file containing the header keyword.
+.le
+.ls keyword [string]
+Name of the header keyword to be retrieved. (The keyword
+name is not case sensitive.)
+.le
+.ls (silent = no) [bool]
+If this parameter is set to no (the default) a warning message will be
+printed if the keyword is not found in the header. If it is set to
+yes, the warning message is suppressed.
+.le
+.ls (value) [string]
+An output parameter that will contain the value passed from the header
+keyword.
+.le
+.ls (found) [bool]
+An output parameter that will be set to yes if the keyword is found in
+the header and no if it is not.
+.le
+.ih
+EXAMPLES
+1. Print the number of groups (i.e., the 'GCOUNT' keyword)
+in the image file 'image.hhh':
+
+.nf
+tt> keypar image.hhh gcount
+tt> print(keypar.value)
+.fi
+
+2. Print the range of the data in the second group of the same image by
+reading the values of the 'DATAMIN' and 'DATAMAX' keywords:
+
+.nf
+tt> keypar image.hhh[2] datamin
+tt> x = real(keypar.value)
+tt> keypar image.hhh[2] datamax
+tt> y = real(keypar.value)
+tt> print(y-x)
+.fi
+
+3. Print the component name (i.e., the 'COMPNAME' header keyword)
+for the table 'thruput.tab':
+
+.nf
+tt> keypar thruput.tab compname
+tt> print(keypar.value)
+.fi
+
+4. Check for the existence of the exposure time in an image header:
+
+.nf
+tt> keypar image.hhh exptime silent+
+tt> if (keypar.found) {
+>>> print keypar.value
+>>> } else {
+>>> print INDEF
+>>> }
+.fi
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+SEE ALSO
+keytab, parkey, partab, tabkey, tabpar
+.endhelp
diff --git a/pkg/utilities/nttools/doc/keyselect.hlp b/pkg/utilities/nttools/doc/keyselect.hlp
new file mode 100644
index 00000000..57e96137
--- /dev/null
+++ b/pkg/utilities/nttools/doc/keyselect.hlp
@@ -0,0 +1,246 @@
+.help keyselect Mar92 tables
+.ih
+NAME
+keyselect -- Copy selected image header keywords to an STSDAS table.
+.ih
+USAGE
+keyselect input output cols
+.ih
+DESCRIPTION
+This task copies the specified image header keywords to an STSDAS
+table. The required parameters are the input list of image names, the
+output STSDAS table name, and the list of header keywords. All groups of
+each image will be examined if the list of header keywords contains a
+group parameter. Otherwise only the first group of each image will be
+examined. The task appends rows to the output table if it exists or
+creates a new table if the output table does not exist. If the output
+table exists, column names must match the names in the existing table.
+The column names in the output table are the same as the header keywords
+unless they are explicitly specified, as described below.
+
+If a keyword is missing from an image header a warning message is
+printed and a null value inserted into the table. The default type of
+the table column is determined from the type of the header keyword.
+Text columns have a default length of 19 characters, unless the table
+column is the concatenation of several keywords, in which case the
+default length will be 63 characters. A column description file must
+be used if you want to override the default type or length of a table
+column.
+
+The third parameter ('cols') is a list of items specifying the header keyword
+names and table column names. Items in the list are separated by
+commas or whitespace. Three different kinds of items may appear in the
+list: a keyword name, a table column name followed by a equals sign
+followed by a keyword name, or a table column name followed by an
+equals sign followed by a list of keyword names separated by colons.
+If the item in the list is a keyword name, the table column name is
+the same as the keyword name. To specify a table column name different
+than the keyword name, the item in the list should be the table column
+name followed by an equals sign followed by the keyword name. To
+concatenate several header keywords into a string separated by commas,
+a list of keyword names separated by colons should replace the header
+keyword name in the item. The following list gives examples of the
+three types of items.
+
+.nf
+FGWA_ID
+GRATING=FGWA_ID
+OBS_MODE=DETECTOR:FGWA_ID:APER_ID
+.fi
+
+In the first case, both the header keyword name and table column name
+are 'fgwa_id'. In the second case the table column name is 'grating'.
+In the third case table column name is 'obs_mode' and the values in
+the column are the concatenation of the header keywords 'detector',
+'fgwa_id', and 'aper_id' separated by commas.
+
+Special keywords may also be used in the list wherever a header
+keyword may be used. Special keywords are used to place the image name
+or parts of the image name in the output table. The name of a special
+keyword always starts with a "$". The different special keywords,
+their types, and default table column names are given in the following
+list.
+
+.nf
+$group int group
+$dir text directory
+$ext text extension
+$hdr text header_file
+$pix text data_file
+$root text rootname
+.fi
+
+If an image has the name 'yref$y00vk101a.r1h[1]', the group will be 1,
+the directory 'yref$', the extension 'r1h', the header file
+'y00vk101a.r1h', the data file 'y00vk101a.r1d', and the root name
+'y00vk101a'.
+
+The hidden task parameter 'expr' is used to select which images are
+examined when writing header keywords to the output table. If this
+task parameter is set to its default value, ' ' (a blank string), all
+images named in the image template will be examined. Otherwise the
+task parameter is interpreted as a boolean (logical) expression. The
+variables in the expression are header keyword names. As each image is
+opened the values of the header keywords are substituted for the
+keyword name. If the expression is true, the header keywords specified
+in the 'cols' parameter are copied into the output table. The special
+keywords mentioned above may also be used in the expression. If a
+keyword name contains dashes the keyword name should be preceded by a
+'@' and enclosed in quotes. For example, 'date-obs' should be given as
+'@"date-obs"' in the expression.
+
+The following boolean operators may be used in the expression:
+
+.nf
+equal == not equal !=
+less than < less than or equal <=
+greater than > greater than or equal >=
+or || and &&
+negation !
+.fi
+
+The expression may also include the usual arithmetic operators and
+functions. Arguments to the trigonometric functions must be in
+degrees. The available operators are:
+
+.nf
+addition + subtraction -
+multiplication * division /
+negation - exponentiation **
+string concatenation //
+.fi
+
+The following is a list of the available functions:
+
+.nf
+absolute value abs(x) cosine cos(x)
+sine sin(x) tangent tan(x)
+arc cosine acos(x) arc sine asin(x)
+arc tangent atan(x) arc tangent atan2(x,y)
+exponential exp(x) square root sqrt(x)
+natural log log(x) common log log10(x)
+minimum min(x,y) maximum max(x,y)
+modulo mod(x,y) keyword found find(x,y,z,..)
+.fi
+
+One new function, find, is available in addition to the usual arithmetic
+functions. The argument of this function is a list of header keyword
+names. The function returns true if all the header keywords are found
+in the image and false if one or more header keywords in the list are
+not found. The arguments to this function should be placed in quotes
+as otherwise the value of the header keyword will checked instead of
+the name. That is, if 'find(detector)' is used instead of
+'find("detector")', the task will look for a header keyword whose name
+is the value of the detector keyword.
+
+The 'cols' and 'expr' parameters can also be the name of a file
+preceded by an '@' character. If this is done, the task will read the
+list of keyword names or boolean expression from the specified file.
+Newlines in the file are treated as if they were blanks, so lines may
+be broken wherever a blank would be correct. Comments (lines starting
+with a '#' character) are not permitted in either file.
+
+The hidden parameter 'cdfile' is the name of the column description
+file. The default value for this parameter is ' ' (a blank string). If
+the parameter contains a blank string no column description file is
+used and the column data type is taken from the type of the header
+keyword. A column description file contains one line for each column
+in the table. Each line contains four fields in the following order:
+the column name, the data type, the print format, and the units. Any
+of the fields except the column name may be omitted. If a field is
+omitted the default for that field will be used instead. Fields are
+not case sensitive except for the units field. The column name in the
+column description file must match the column name in the 'cols'
+parameter. If a column name in the 'cols' parameter is not found in
+the column description file, a warning message is printed and the
+defaults are used for that table column. Column names in the column
+description file that are not in the 'cols' parameter are ignored. For
+further information on the format of a column description file, refer
+to the help file for 'tlcol'.
+
+.ih
+PARAMETERS
+.ls input [file name template]
+List of image names. The usual wild card characters can be used. If
+the list of keyword names or the expression contains a group parameter
+all groups of each image will be examined unless a group is explicitly
+specified as part of the image name.
+.le
+.ls output [file name]
+The name of the output STSDAS table. If the table already exists new
+rows will be added to the existing table. Column names must match
+names in the existing table. If the table does not exist a new table
+will be created and any column names may be used.
+.le
+.ls cols [string]
+The list of header keyword names separated by white space or commas.
+Table column names are the same as the keyword names unless explicitly
+specified in the form <colname>=<keyword>. Several keywords can be
+concatenated by using the form <colname>=<keyword>:<keyword>. If the
+first character in the parameter is an '@', the rest of the parameter
+is interpreted as a file name containing the list of keyword names.
+.le
+.ls (expr = " ") [string]
+A boolean expression used to select which images are examined for
+header keywords. If the string is blank (the default) all images named
+in the input list are examined. Variables in the expression are
+header keyword names. An image is selected if substituting the value
+of the header keywords for their names makes the expression true. The
+syntax of the expression follows the usual CL and SPP conventions. If
+the first character in the expression is a '@', the rest of the
+expression is interpreted as a filename containing the expression.
+.le
+.ls (cdfile = " ") [file name]
+The name of the column description file. The format of a column
+description file is defined in the help for 'tlcol'. Column names used
+in the column description file must match the names in the 'cols'
+parameter (except for case).
+.le
+.ih
+EXAMPLES
+1. Create an STSDAS table from the headers of the dead diode reference
+images:
+
+.nf
+tt> keyselect yref$*.r4h ddt.tab detector,headname,dataname
+.fi
+
+2. Create the same table, only name the columns "header_file" and
+"data_file":
+
+.nf
+tt> keyselect yref$*.r4h ddt.tab \
+>>> detector,header_file=headname,data_file=dataname
+.fi
+
+3. Only select images with the blue detector:
+
+.nf
+tt> keyselect yref$*.r4h ddt.tab detector,headname,dataname \
+>>> expr="detector='blue'"
+.fi
+
+4. Use a column description file when creating the table:
+
+.nf
+tt> keyselect yref$*.r4h ddt.tab \
+>>> detector,header_file=headname,data_file=dataname cdfile="ddt.cd"
+.fi
+
+The contents of the column description file:
+
+.nf
+DETECTOR CH*5
+HEADER_FILE CH*18
+DATA_FILE CH*18
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+
+Type "help tables opt=sys" for a description of the 'tables' package.
+.endhelp
diff --git a/pkg/utilities/nttools/doc/keytab.hlp b/pkg/utilities/nttools/doc/keytab.hlp
new file mode 100644
index 00000000..1bccecf5
--- /dev/null
+++ b/pkg/utilities/nttools/doc/keytab.hlp
@@ -0,0 +1,61 @@
+.help keytab Dec94 tables
+.ih
+NAME
+keytab -- Copy a header keyword to a table element.
+.ih
+USAGE
+keytab input keyword table column row
+.ih
+DESCRIPTION
+This task reads a header keyword from either an image or a table file
+and writes it to a table element (row and column position). If the
+data type of the header keyword differs from that of the table
+element, then the value is converted to the appropriate data type. If
+the keyword is not found in the header, the element will be set to the
+null value appropriate for the column type.
+.ih
+PARAMETERS
+.ls input [file name]
+Name of the file containing header keyword.
+.le
+.ls keyword [string]
+Name of the header keyword to be read. (Keyword names are not case sensitive.)
+.le
+.ls table [file name]
+Name of the table to which the value will be written.
+.le
+.ls column [string]
+Name of table column. (Column names are not case sensitive.)
+.le
+.ls row [integer, min=1, max=INDEF]
+Table row number.
+.le
+.ls (silent = no) [bool]
+If this parameter is set to no (the default) a warning message will be
+printed if the keyword is not found in the header. If it is set
+to yes, the warning message is suppressed.
+.le
+.ih
+EXAMPLES
+1. Copy the component name (i.e., the 'COMPNAME' header keyword)
+from the table 'thruput.tab' to the
+first row of the table 'graph.tab'.
+
+.nf
+tt> keytab thruput.tab COMPNAME graph.tab COMPNAME 1
+.fi
+
+2. Copy the zero point of the second group (i.e., the 'CRVAL1' keyword)
+in the image file 'image.hhh' to the first
+wavelength in the table 'spectrum.tab'.
+
+.nf
+tt> keytab image.hhh[2] CRVAL1 spectrum.tab WAVELENGTH 1
+.fi
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+keypar, parkey, partab, tabkey, tabpar
+.endhelp
diff --git a/pkg/utilities/nttools/doc/parkey.hlp b/pkg/utilities/nttools/doc/parkey.hlp
new file mode 100644
index 00000000..8cf317ee
--- /dev/null
+++ b/pkg/utilities/nttools/doc/parkey.hlp
@@ -0,0 +1,73 @@
+.help parkey Dec90 tables
+.ih
+NAME
+parkey -- Write an IRAF parameter to a header keyword.
+.ih
+USAGE
+parkey value output keyword
+.ih
+DESCRIPTION
+This task changes the value of a header keyword in either a table or an
+image. If the value of the task parameter 'add' is "yes", the task will
+allow you to add a new keyword to the header, otherwise, adding a new
+keyword will cause an error. Type conversion is performed if the data type of
+the header keyword differs from the data type of the input parameter 'value'.
+If a new
+keyword is added to the file, the type is determined
+from the input value. The
+strings "yes", "y", "no", "n", "true", "t", "false", and "f", in either
+upper or lower case, are interpreted as boolean values.
+.ih
+PARAMETERS
+.ls value [string]
+Input value to be written to the header keyword. (Strings are case sensitive.)
+.le
+.ls output [file name]
+Name of the file whose header keyword is to be changed.
+.le
+.ls keyword [string]
+Name of the header keyword to be changed. (The name is not case sensitive.)
+.le
+.ls (add = no) [boolean]
+Allow new header keywords to be added?
+
+If 'add = no', then existing keywords
+can take new values but no new keywords can be added to the file.
+.le
+.ih
+EXAMPLES
+1. Set the header keyword 'OVERSCAN' in the file 'image.hhh' to 5:
+
+.nf
+tt> parkey 5 image.hhh overscan
+.fi
+
+2. Set the group parameter 'CTYPE1' in the second group of the same
+file to "ANGSTROM":
+
+.nf
+tt> parkey ANGSTROM image.hhh[2] ctype1
+.fi
+
+3. Set the header keyword 'YSTEP' to the value stored
+in the IRAF parameter 'x':
+
+.nf
+tt> parkey (x) image.hhh ystep
+.fi
+
+4. Add the keyword 'COMPNAME' to the table header and put the value "FILTER1"
+in it:
+
+.nf
+tt> parkey FILTER1 graph.tab compname add+
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+keypar, keytab, partab, tabkey, tabpar
+.endhelp
diff --git a/pkg/utilities/nttools/doc/partab.hlp b/pkg/utilities/nttools/doc/partab.hlp
new file mode 100644
index 00000000..fb0b9239
--- /dev/null
+++ b/pkg/utilities/nttools/doc/partab.hlp
@@ -0,0 +1,62 @@
+.help partab Nov91 tables
+.ih
+NAME
+partab -- Copy an IRAF parameter to a table element.
+.ih
+USAGE
+partab value table column row
+.ih
+DESCRIPTION
+This task changes the value of a table element to the value of the input
+parameter 'value'. If 'value' is set to "INDEF", the table element will be
+set to undefined. If the data type of the table element is different from
+that of the input parameter 'value', this task will perform
+type conversion. The strings
+"yes", "y", "no", "n", "true", "t", "false", and "f", in either upper or
+lower case are interpreted as boolean values.
+.ih
+PARAMETERS
+.ls value [string]
+The IRAF parameter that will be copied into the table element.
+.le
+.ls table [file name]
+Name of the table.
+.le
+.ls column [string]
+Column name. (Column names are not case sensitive).
+.le
+.ls row [integer, min=1, max=INDEF]
+Row number.
+.le
+.ih
+EXAMPLES
+1. Set the twelfth component (i.e., row 12 of column 'COMPNAME')
+in the file 'graph.tab' to "FILTER1":
+
+.nf
+tt> partab FILTER1 graph.tab COMPNAME 12
+.fi
+
+2. Set the first wavelength (i.e., row 1 of column 'WAVELENGTH') in
+the file 'spectrum.tab' to the value contained in parameter
+'x':
+
+.nf
+tt> partab (x) spectrum.tab WAVELENGTH 1
+.fi
+
+3. Set the hundreth wavelength (i.e., row 100 of column 'WAVELENGTH')
+in 'spectrum.tab' to undefined:
+
+.nf
+tt> partab INDEF spectrum.tab WAVELENGTH 100
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+keypar, keytab, parkey, tabkey, tabpar
+.endhelp
diff --git a/pkg/utilities/nttools/doc/pltpar.hlp b/pkg/utilities/nttools/doc/pltpar.hlp
new file mode 100644
index 00000000..d43ecde7
--- /dev/null
+++ b/pkg/utilities/nttools/doc/pltpar.hlp
@@ -0,0 +1,160 @@
+.help pltpar Jul93 tables
+.ih
+NAME
+pltpar -- Edit the parameter set that describes plot attributes.
+.ih
+USAGE
+pltpar
+.ih
+DESCRIPTION
+The 'pltpar' parameters specify the attributes of plots drawn by the
+'sgraph' task.
+
+Note that this is a pset, not an executable task; it defines a set of
+parameters used by other tasks. Invoking the pset by name runs
+'eparam' on the parameter set, allowing the user to modify the
+parameters. Alternatively, the parameters may be modified on the
+command line by specifying the pset name and parameter name, for
+example, you can type "pltpar.pointmode=yes" to set only the
+'pointmode' parameter. Parameters can also be edited by using
+'eparam' on the calling task (e.g., by typing "eparam sgraph"), in
+which case, 'pltpar' will appear as one of the task parameters; the
+'pltpar' parameters may then be edited by positioning the cursor on
+the line containing the pset name and typing ":e". After editing
+the pset parameters, press Control-Z to return to the main task parameter menu.
+.ih
+PARAMETERS
+.ls (stack = no) [boolean]
+Stack multiple curves on separate vertical axes?
+
+If this is set to
+"no", all curves will be scaled together and plotted on a single set of
+axes. Otherwise a separate set of axes will be drawn, joined into a
+single vertical column.
+.le
+.ls (axis = 1) [integer, min = 1, max = 7]
+Axis along which projection is to be taken. If the input image has
+more than one dimension, the data will be projected to a single
+dimension. This parameter specifies the axis along which projection
+will occur. The default is one, i.e., project along the X axis.
+.le
+.ls (pointmode = no) [boolean]
+Plot points only?
+
+If set to "no", the task will plot connected curves. Note that to
+plot error bars, you must set 'pointmode = no' and 'erraxis = 1' or 'erraxis =
+2'. See the descriptions of 'marker' and 'szmarker'.
+.le
+.ls (marker = box) [string, allowed values: point | box | plus |
+cross | circle | diamond | hline | vline | hebar | vebar]
+
+The marker style for each plotted point if 'pointmode=yes'. See also
+'szmarker'.
+.le
+.ls (szmarker = 0.005) [real]
+The size of the markers if 'pointmode = yes'. If 'szmarker > 0', use
+this value as the size in normalized device coordinates (NDC) . If
+'szmarker < 0', use the absolute value as the size in world coordinates
+(WCS). If 'szmarker = 0' and the input comes from a text file, use the
+third column in the input data as the marker size. If data are from an
+image or a table, then 'szmarker' specifies the same size of every point.
+.le
+.ls (erraxis = 0) [integer, min = 0, max = 2]
+Plot the data as error bars? If 'erraxis = 0', plot the data as values
+rather than error bars; if 'erraxis = 1', plot the data as errors
+parallel to the X axis; if 'erraxis =2', plot the data as errors
+parallel to the Y axis. Note that the value of 'erraxis' is ignored if
+'pointmode = yes' and error bars will not be drawn.
+.le
+.ls (errtype = bartck) [string, allowed values: tckbar | bar | tick |
+limit]
+
+The style of error bars (if 'erraxis' is not zero).
+.le
+.ls (pattern = solid) [string, allowed values: solid | dashed |
+dotted | dotdash]
+
+The line pattern style for the curve or the first of multiple curves.
+.le
+.ls (crvstyle = straight) [string, allowed values: straight | pseudohist
+| fullhist]
+
+The curve style. 'straight' means line segments will connect data
+points, 'pseudohist' means that horizontal segments will be placed at
+each value and vertical segments will connect these, 'fullhist' means a
+bar graph, or horizontal segments at each value with vertical lines
+connecting the value with the bottom axis.
+.le
+.ls (rejectlog = yes) [boolean]
+Replace invalid logarithmic values with 'INDEF'?
+
+Invalid values will
+be ignored in scaling and plotting.
+.le
+.ls (box = yes) [boolean]
+Draw the box containing the axes and labels around the edge of the
+window?
+.le
+.ls (sysid = yes) [boolean]
+Include standard system information in the plot title?
+
+If the 'sysid'
+parameter is "yes", then a string including the user's name, date, host
+name, etc. is included in the plot title.
+.le
+.sp
+.ls (barpat ="hollow") [string, allowed values: hollow, solid, ahatch,
+bhatch, chatch, dhatch]
+
+Fill pattern for bar plot. The nature of the pattern depends on the
+device and graphics kernel (driver) used to plot. Many kernels do not
+support fill patterns.
+.le
+.sp
+.ls (crvcolor = INDEF) [integer, min = 1]
+Color index of data curve(s). This color applies only to plotted data
+curves. The color of any axes, labels, etc., is specified by
+the `color' parameter. Note that the actual, drawn color will depend
+on the device and graphics kernel (driver) used to plot. Many kernels
+do not support color at all. The usual interpretation of the color
+index is:
+.nf
+
+ 1 -- Black
+ 2 -- White
+ 3 -- Red
+ 4 -- Green
+ 5 -- Blue
+ 6 -- Yellow
+ 7 -- Cyan (blue/green)
+ 8 -- Magenta (red/blue)
+.fi
+.le
+.ls (color = INDEF) [integer, min = 1]
+Color index of axis and labels. The color of the data curve(s) is
+specified by the `crvcolor' parameter. Note that the actual, drawn
+color will depend on the device and graphics kernel (driver) used to
+plot. Most kernels do not support color.
+.le
+.ls (cycolor = no) [boolean]
+Cycle colors instead of line style for multiple curves?
+
+If multiple curves are plotted on the same viewport (axes), i.e.,
+'stack=no', then use the color specified by the 'crvcolor' parameter
+for the first curve, and the next available color for each subsequent
+curve. There are eight available colors, as described in the
+description of the 'crvcolor' parameter.
+.le
+.sp
+.ls (version = 17August92) [string]
+Date that the task was installed. This parameter should not be changed by
+the user.
+.le
+.ih
+EXAMPLES
+.ih
+BUGS
+.ih
+SEE ALSO
+sgraph
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tabim.hlp b/pkg/utilities/nttools/doc/tabim.hlp
new file mode 100644
index 00000000..2fdba5fb
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tabim.hlp
@@ -0,0 +1,98 @@
+.help tabim Mar2000 tables
+.nj
+.ih
+NAME
+tabim -- Copy a table column to an image.
+.ih
+USAGE
+tabim intable output colname ndim n1 n2 n3 n4 n5 n6
+.ih
+DESCRIPTION
+This task writes values from a column of a table to an image.
+If the image does not exist, it will be created.
+The value in the first row is assigned to the first pixel of the image,
+and the value in the last row is assigned to the last pixel of the image.
+Columns containing pixel numbers (optionally written by 'imtab') are ignored,
+but you can specify the axis lengths of a multi-dimensional output image.
+The number of rows in the table must equal the number of pixels in the image.
+.ih
+PARAMETERS
+.ls intable = "" [file name template]
+The names of the input tables.
+.le
+.ls output = "" [file name template]
+The names of the output images.
+If an output image does not exist it will be created.
+If the image does exist it will be overwritten with values from the table.
+A section of an existing image may be specified,
+but note that the size must equal the number of rows in the table.
+.le
+.ls colname = "" [string]
+The name of the column in 'intable' that is to be written to the image.
+The same column name is used for all input tables.
+.le
+.ls ndim = 0 [integer, min=0, max=7]
+If the output image does not exist,
+'ndim' can be used to specify
+the dimension of the image to be created.
+ndim = 0 or 1 results in a one-dimensional image
+which has as many elements as rows in the table.
+If 'ndim' is greater than one
+and the output image does not already exist,
+then the parameters 'n1', 'n2', etc will be taken
+to specify the axis lengths of the output image.
+The lengths of all but the last axis will be gotten from 'n1', 'n2', etc.;
+the last axis length will be computed from
+the number of rows in the table
+and the lengths of the other axes.
+It is an error if the product of the specified axis lengths
+does not divide evenly into the number of rows in the table.
+.le
+.ls n1 = 1 [integer, min=1, max=INDEF]
+Length of first axis.
+'n1', 'n2', etc., are ignored if ndim = 0 or 1.
+.le
+.ls n2 = 1 [integer, min=1, max=INDEF]
+Length of second axis.
+This and the subsequent axis length parameters will be ignored if ndim < 3.
+.le
+.ls n3 = 1 [integer, min=1, max=INDEF]
+Length of third axis.
+.le
+.ls n4 = 1 [integer, min=1, max=INDEF]
+Length of fourth axis.
+.le
+.ls n5 = 1 [integer, min=1, max=INDEF]
+Length of fifth axis.
+.le
+.ls n6 = 1 [integer, min=1, max=INDEF]
+Length of sixth axis.
+.le
+.ih
+EXAMPLES
+1. Copy column "flux" from table "hr465.tab" to
+the 1-D image "hr465_flux.imh":
+
+.nf
+ ta> tabim hr465.tab hr465_flux.imh flux 1
+.fi
+
+2. Create a three-dimensional image "ir27.imh" of size 62 x 64 x 4.
+Read the values from column "v1" of table "t18_30.tab",
+which has 62*64*4 rows.
+
+.nf
+ ta> tabim t18_30.tab ir27.imh v1 3 62 64
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+.ih
+SEE ALSO
+The 'imtab' task copies an image to a column of a table.
+
+Type "help tables option=sys" for a higher-level description of
+the tables package.
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tabkey.hlp b/pkg/utilities/nttools/doc/tabkey.hlp
new file mode 100644
index 00000000..0f87c64f
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tabkey.hlp
@@ -0,0 +1,68 @@
+.help tabkey Nov91 tables
+.ih
+NAME
+tabkey -- Copy a table element to a header keyword.
+.ih
+USAGE
+tabkey table column row output keyword
+.ih
+DESCRIPTION
+This task copies the value of a table element to a header
+keyword in either a table
+or an image. If the table element and the header keyword are of different
+data types, this task will convert the type.
+An error will occur if any attempt is made
+to copy an undefined table element to a header keyword. If the value of
+the task parameter 'add' is "yes", the task will allow you to add a new
+keyword to the header, otherwise, adding a new keyword will cause an
+error.
+.ih
+PARAMETERS
+.ls table [file name]
+Name of table containing the element to be copied. The particular element
+is defined by the 'column' and 'row' parameters.
+.le
+.ls column [string]
+Name of column. (Column names are not case sensitive.)
+.le
+.ls row [integer, min=1, max=INDEF]
+Row number.
+.le
+.ls output [file name]
+Name of the file with the header keyword whose value is to be changed.
+.le
+.ls keyword [string]
+Name of header keyword. (Header keyword names are not case sensitive.)
+.le
+.ls (add = no) [boolean]
+Allow new keywords to be added to the header?
+If 'add = no', then only existing header keywords can be modified--an error
+will occur if a keyword is specified that does not already exist.
+.le
+.ih
+EXAMPLES
+1. Copy the first component name (i.e., row 1 of column 'COMPNAME'
+from the file 'graph.tab' to the header of the
+table 'thruput.tab'. If the keyword does not already exist, then add
+it:
+
+.nf
+tt> tabkey graph.tab COMPNAME 1 thruput.tab COMPNAME add+
+.fi
+
+2. Copy the date of the tenth observation (i.e., row 10 of column 'DATE')
+from the file 'schedule.tab' to the
+header keyword 'DATE' in 'image.hhh'. The keyword 'DATE' must already exist:
+
+.nf
+tt> tabkey schedule.tab DATE 10 image.hhh date
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+keypar, keytab, parkey, partab, tabpar
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tabpar.hlp b/pkg/utilities/nttools/doc/tabpar.hlp
new file mode 100644
index 00000000..8a5b9ffb
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tabpar.hlp
@@ -0,0 +1,95 @@
+.help tabpar May2002 tables
+.ih
+NAME
+tabpar -- Copy a table element to an IRAF parameter.
+.ih
+USAGE
+tabpar table column row
+.ih
+DESCRIPTION
+This task reads a table element specified by a table name, column name,
+and row number. The element is written to the task parameter 'value' as
+a character string. If the table element is boolean, then 'value' will
+be either "yes" or "no". If the element is undefined, the task parameter
+'undef' will be set to "yes". String parameters, such as 'value', can be
+converted to numeric types with the built in functions real() and int().
+.ih
+PARAMETERS
+.ls table [file name]
+Name of the table from which this task is to read a value.
+.le
+.ls column [string]
+Column name. (The column name is not case sensitive.)
+.le
+.ls row [integer, min=1, max=INDEF]
+Row number.
+.le
+.ls (format=yes) [boolean]
+Format the value using table print format?
+
+The value from the table is returned to this task as a string parameter
+(see 'value').
+The default is to use the print format for 'column' to format the value,
+because this preserves the behavior of the task
+prior to the addition of the 'format' parameter.
+This behavior may be desirable when using h or m format, for example,
+or perhaps when using x or o format.
+On the other hand,
+it will often be the case that what you want is
+the actual value in the table,
+and using the print format
+could significantly limit the accuracy of the result.
+In this case, use format=no.
+.le
+.ls (value) [string]
+This parameter is used to store the value read in from 'table'.
+.le
+.ls (undef) [boolean]
+Is the value read in from 'table' undefined?
+.le
+.ih
+EXAMPLES
+1. Print the interval between the first 2 wavelengths (i.e., rows 1 and 2
+in the column 'WAVELENGTH') in the table 'spectrum.tab':
+
+.nf
+tt> tabpar spectrum.tab WAVELENGTH 1
+tt> x = real(tabpar.value)
+tt> tabpar spectrum.tab WAVELENGTH 2
+tt> y = real(tabpar.value)
+tt> print(y-x)
+.fi
+
+2. Print the twelfth component name (i.e., row 12 of the column 'COMPNAME',
+after checking to see if it is undefined. If the value is undefined, then
+print a message instead:
+
+.nf
+tt> tabpar graph.tab COMPNAME 12
+tt> if (tabpar.undef) {
+>>> print ("Component name undefined")
+>>> } else {
+>>> print ("Component name = ",tabpar.value)
+>>> }
+.fi
+
+3. Here is an example illustrating the difference between
+format=yes and format=no for an integer column with x (hexadecimal) format:
+
+.nf
+tt> tabpar g.tab counts 4 format=yes
+tt> =tabpar.value
+31
+tt> tabpar g.tab counts 4 format=no
+tt> =tabpar.value
+49
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+keypar, keytab, parkey, partab, tabkey
+.endhelp
diff --git a/pkg/utilities/nttools/doc/taextract.hlp b/pkg/utilities/nttools/doc/taextract.hlp
new file mode 100644
index 00000000..50e34dbe
--- /dev/null
+++ b/pkg/utilities/nttools/doc/taextract.hlp
@@ -0,0 +1,109 @@
+.help taextract Jan98 tables
+.nj
+.ih
+NAME
+taextract -- Copy an array entry from one table
+to a column of scalars in another.
+.ih
+USAGE
+taextract intable outtable row column
+.ih
+DESCRIPTION
+This task extracts one entry (presumably an array of values)
+at a specified row and column
+and writes it as a column of scalar values to another table.
+If the output table exists it will be written to in-place;
+otherwise, it will be created.
+
+By default, the same column name is used in both tables.
+If the output table and column already exist,
+the data in that column will be overwritten;
+otherwise, the column will be created.
+If the array size for the specified column in the input table is N,
+then the values will be written to rows 1 through N of the output table.
+If the output column already exists,
+and the output table contains more than N rows,
+then rows N+1 through the last will be set to INDEF for this column.
+
+The input row number is written to the header of the output table
+using keyword ORIG_ROW.
+This allows 'tainsert' to put the data back where 'taextract' got them from.
+.ih
+PARAMETERS
+.ls intable [file name]
+Name of the input table containing a column with array entries.
+It is not an error for the array length to be one.
+.le
+.ls outtable [file name]
+Name of the output table.
+If this table doesn't exist it will be created.
+If the table does exist the column will either be created or overwritten.
+The input and output tables may not be the same,
+and they may not be in the same file if FITS format is used.
+.le
+.ls row [integer, min=1, max=INDEF]
+This is the row number in the input table.
+In the output table there will be as many rows
+as there are elements in the input table entry for 'column'.
+.le
+.ls column [string]
+Column name.
+This is used to find the column in the input table,
+and by default the same name is used to create
+(or find, if it already exists)
+the column in the output table.
+See the description for 'outcolumn'.
+.le
+.ls outcolumn = "" [string]
+If 'outcolumn' is specified,
+that name will be used for the output table;
+otherwise, 'column' will be used for both input and output tables.
+This provides an easier way to change the name of the output column
+than by running 'tchcol' after running 'taextract'.
+Note that if 'outcolumn' is specified,
+it is used not only for finding the column in the output table
+but also for creating the column if it wasn't found.
+The 'datatype', 'colunits', and 'colfmt' parameters, by contrast,
+are only used when creating a new column.
+.le
+.ls (datatype = "") [string]
+When creating a new column in the output table,
+the default is to use the same data type as the column in the input table.
+However, if 'datatype' is specified (i.e. not null or blank),
+this will be used as the data type when creating the new column.
+For numeric and boolean columns, only the first character is used:
+"r" and "d" for single and double precision floating point,
+"s" and "i" for short integer and integer,
+"b" for boolean.
+For a character string of maximum length 12 (for example), use "ch*12".
+.le
+.ls (colunits = "") [string]
+When creating a new column in the output table,
+the units will be set to 'colunits' if it has been specified;
+otherwise, the units will be copied from the column in the input table.
+.le
+.ls (colfmt = "") [string]
+When creating a new column in the output table,
+the print format will be set to 'colfmt' if it has been specified;
+otherwise, the print format will be copied from the column in the input table.
+.le
+.ih
+EXAMPLES
+1. Extract the array from row 5, column "polar", from table "array.tab",
+putting the values in column "polar" of table "scalar.tab".
+
+.nf
+at> taextract array.tab scalar.tab 5 polar
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+.ih
+SEE ALSO
+tainsert
+
+Type "help ttools opt=sysdoc" for a higher-level description of the 'ttools'
+package.
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tainsert.hlp b/pkg/utilities/nttools/doc/tainsert.hlp
new file mode 100644
index 00000000..3d07855b
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tainsert.hlp
@@ -0,0 +1,132 @@
+.help tainsert Jan98 tables
+.nj
+.ih
+NAME
+tainsert -- Copy a column of scalars from one table
+to an array entry in another.
+.ih
+USAGE
+tainsert intable outtable row column
+.ih
+DESCRIPTION
+This task reads an entire column from one table
+and inserts those values (presumably more than one)
+at a specified row and column in an output table.
+If the output table exists it will be written to in-place;
+otherwise, it will be created.
+
+By default, the same column name is used in both tables.
+If the column does not exist in the output table, the column will be created.
+If the output table and the row and column already exist,
+the array of values at that location will be overwritten.
+The number of elements copied will be the minimum of
+the number of input rows and the output column array size.
+If the number of input rows is larger than the array size,
+a warning message will be printed,
+and the extra rows will be ignored.
+If the number of input rows is smaller than the array size,
+the remaining array elements will be set to INDEF.
+
+If the specified row number is less than one or is INDEF,
+'tainsert' looks for the header keyword ORIG_ROW in the input table.
+ORIG_ROW is written by 'taextract'.
+If that keyword exists, its value is used as the row number.
+.ih
+PARAMETERS
+.ls intable [file name]
+Name of the input table.
+.le
+.ls outtable [file name]
+Name of the output table.
+If this table doesn't exist it will be created.
+.le
+.ls row = -1 [integer]
+This is the row number in the output table.
+The default means that 'tainsert' should use
+the value of the header keyword ORIG_ROW.
+.le
+.ls column [string]
+Column name in the input table and, by default, also in the output table.
+If this column does not exist in the output table, it will be created,
+and the array size will be set to the number of rows in the input table.
+See the descriptions for 'outcolumn' and 'size', however.
+
+It is an error if this column in the input table contains array entries.
+.le
+.ls outcolumn = "" [string]
+If 'outcolumn' is specified,
+that name will be used for the output table;
+otherwise, 'column' will be used for both input and output tables.
+This provides an easier way to change the name of the output column
+than by running 'tchcol' after running 'taextract'.
+Note that if 'outcolumn' is specified,
+it is used not only for finding the column in the output table
+but also for creating the column if it wasn't found.
+The 'size', 'datatype', 'colunits', and 'colfmt' parameters,
+by contrast, are only used when creating a new column.
+.le
+.ls (size = INDEF) [int]
+When creating a new column in the output table,
+the default is for the array size of that column to be set to
+the number of rows in the input table.
+This may be overridden by specifying a value for 'size'.
+If 'size' is a positive integer, not INDEF,
+this will be used as the array size when creating the new column.
+.le
+.ls (datatype = "") [string]
+When creating a new column in the output table,
+the default is to use the same data type as the column in the input table.
+However, if 'datatype' is specified (i.e. not null or blank),
+this will be used as the data type when creating the new column.
+For numeric and boolean columns, only the first character is used:
+"r" and "d" for single and double precision floating point,
+"s" and "i" for short integer and integer,
+"b" for boolean.
+For a character string of maximum length 12 (for example), use "ch*12".
+.le
+.ls (colunits = "") [string]
+When creating a new column in the output table,
+the units will be set to 'colunits' if it has been specified;
+otherwise, the units will be copied from the column in the input table.
+.le
+.ls (colfmt = "") [string]
+When creating a new column in the output table,
+the print format will be set to 'colfmt' if it has been specified;
+otherwise, the print format will be copied from the column in the input table.
+.le
+.ih
+EXAMPLES
+1. Copy the entire column "polar" from table "scalar.tab",
+and insert the values into row 5, column "polar", of table "array.tab".
+If "array.tab" does not exist it will be created.
+If column "polar" does not exist in "array.tab",
+that column will be created.
+
+.nf
+at> tainsert scalar.tab array.tab 5 polar
+.fi
+
+2. Copy the arrays from row 5, columns "wavelength" and "flux",
+from "array.tab" to a temporary table,
+sort them on the wavelength,
+and insert them back where they came from.
+
+.nf
+at> taextract array temp 5 wavelength
+at> taextract array temp 5 flux
+at> tsort temp wavelength
+at> tainsert temp array 0 wavelength
+at> tainsert temp array 0 flux
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+.ih
+SEE ALSO
+taextract
+
+Type "help ttools opt=sysdoc" for a higher-level description of the 'ttools'
+package.
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tcalc.hlp b/pkg/utilities/nttools/doc/tcalc.hlp
new file mode 100644
index 00000000..10b5415d
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tcalc.hlp
@@ -0,0 +1,153 @@
+.help tcalc Jan92 ttools
+.ih
+NAME
+tcalc -- Perform arithmetic operations on table columns.
+.ih
+USAGE
+tcalc table outcol equals
+.ih
+DESCRIPTION
+This task evaluates an arbitrary expression that includes column names,
+constants, and operators, and creates a specified column in the
+table---or overwrites an existing column if the specified name already exists.
+Variables in the expression are column names in either case.
+
+Columns
+may be of any type except string. If the column name contains
+non-alphanumeric characters, it should be preceded by a dollar sign
+and followed by a blank. For example, the expression "date-obs+1."
+contains the column "date-obs", but the task thinks that it contains
+two column names, "date" and "obs". To ensure that the expression is
+evaluated correctly, rewrite it as "$date-obs +1.". The variable
+"rownum" may also be used in an expression if there is no column in
+the table of the same name. Its value is the current row number. The
+expression will be evaluated using the data types of the columns and
+constants in the expression, with the usual rules of type promotion used in
+Fortran. Please remember that integer division truncates.
+
+The output value in any row will be set to INDEF if one or more column
+values used in the calculation is equal to INDEF. The result will be
+INDEF if either of the clauses in an if expression contains a row with
+an INDEF value. If the result of an operation is undefined (such as
+division by zero) the output column will also be set to INDEF.
+
+The following Fortran-type arithmetic operators are supported. If the
+second argument of the exponentiation is not an integer, the result
+will be undefined if the first argument is not positive. Again,
+remember that integer division truncates.
+
+.nf
++ addition - subtraction
+* multiplication / division
+- negation ** exponentiation
+.fi
+
+The following logical operators are supported. Logical operators will
+return a value of 1 if true or 0 if false. Logical operators are
+supported in both their Fortran and SPP form.
+
+.nf
+.or. || logical or .and. && logical and
+.eq. == equality .ne. != inequality
+.lt. < less than .gt. > greater than
+.le. <= less or equal .ge. >= greater or equal
+.not. ! not
+.fi
+
+The following functions are supported. These functions all take a
+single argument, which may be an expression. The argument or result of
+trigonometric functions are in radians.
+
+.nf
+abs absolute value acos arc cosine
+asin arc sine atan arc tangent
+cos arc cosine cosh hyperbolic cosine
+cube third power double convert to double
+exp E raised to power int convert to integer
+log natural logarithm log10 common logarithm
+nint nearest integer real convert to real
+sin sine sinh hyperbolic sine
+sqr second power sqrt square root
+tan tangent tanh hyperbolic tangent
+.fi
+
+The following functions take two arguments.
+
+.nf
+atan2 arc tangent dim positive difference
+max maximum min minimum
+mod modulus sign sign transfer
+.fi
+
+Conditional expressions of the form "if expr then expr else expr" are
+supported. The expression after the else may be another conditional
+expression. The words "if", "then", and "else" must be surrounded by
+blanks.
+.ih
+PARAMETERS
+.ls table [file name template]
+The input table, or tables; these files are modified in-place.
+Results will be written to a new column in the table unless an
+existing column name is specified, in which case the existing values
+will be overwritten.
+.le
+.ls outcol [string]
+Output column name. This is the column where results are written.
+Caution: if this column already exists, then it will be overwritten
+with the results of the calculation. Note that column names are not
+case sensitive.
+.le
+.ls equals [string]
+The arithmetic expression to evaluate. If the expression is too long
+to pass as a parameter, place the expression in a file and set the
+value of this parameter to the file name preceded by an "@", for
+example, "@filename".
+.le
+.ls (datatype = real) [string, allowed values: real | double | int ]
+
+Type of data stored in the output column, if it is a new column.
+.le
+.ls (colunits) [string]
+Units for the output column, if it is a new column. This parameter
+may be blank.
+.le
+.ls (colfmt) [string]
+Print format for the output column, if it is a new column. If this
+parameter is left blank then a default will be used. Type "help
+ttools opt=sysdoc" for more information about print formats.
+.le
+.ih
+EXAMPLES
+1. Create a column called 'FLUX', which will contain a value equal to
+10.0**(-x/2.5) where x is the value in the column 'MAG'. The new
+column will contain single precision data.
+
+.nf
+tt> tcalc "intab" "FLUX" "10.0**(-mag/2.5)"
+.fi
+
+2. Create a column called 'POLY', which will contain a value equal to
+x+x**2 where x is the row number in the table.
+
+.nf
+tt> tcalc "test" "POLY" "rownum+sqr(rownum)"
+.fi
+
+3. Set quotient to zero where divison by zero would otherwise occur:
+
+.nf
+tt> tcalc "test" "QUOT" "if y != 0 then x / y else 0."
+.fi
+
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+imcalc
+
+Type "help ttools opt=sys" for a higher-level description of the 'tables'
+package.
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tchcol.hlp b/pkg/utilities/nttools/doc/tchcol.hlp
new file mode 100644
index 00000000..1a53c00c
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tchcol.hlp
@@ -0,0 +1,80 @@
+.help tchcol Jan92 tables
+.nj
+.ih
+NAME
+tchcol -- Change column description.
+.ih
+USAGE
+tchcol table oldname newname newfmt newunits
+.ih
+DESCRIPTION
+This task may be used to change the name of a column, the display
+format, or the units.
+To change more than one column the task must be called more than once.
+Only those items (name, units, format) that are not null will be changed.
+The word "default" may be used to set
+the print format or the units to their default values.
+.ih
+PARAMETERS
+.ls table [file name template]
+Names of tables to be modified.
+The same change(s) will be made to all tables.
+
+Note that the tables are modified in-place.
+.le
+.ls oldname = "" [string]
+Name of column to be changed.
+If the column is not found,
+a message will be printed,
+and the current table will not be changed.
+.le
+.ls newname = "" [string]
+New column name or a null string ("").
+
+If this is null or blank, the column name will not be changed.
+.le
+.ls newfmt = "" [string]
+New value for print format, or "default" or "".
+
+If this is null or blank, the display format will not be changed.
+If 'newfmt = "default"' the print format will be set to the default
+for the column data type.
+Type "help ttools opt=sysdoc" for more information about print formats.
+.le
+.ls newunits = "" [string]
+New value for units, or "default" or "".
+
+If this is null or blank the units will not be changed.
+If newunits = "default" the units will be set to null.
+There is no way (with this task) to set the units to the value "default"!
+.le
+.ls (verbose = yes) [boolean]
+Print the names of tables as the task progresses?
+
+If 'verbose=yes' then the table names are printed,
+and for each item that is changed, a message is printed
+giving the old and new values.
+.le
+.ih
+EXAMPLES
+In table 'm87pol.tab', change column name "chi" to "CHI" and set the units
+to degrees. The display format is not changed.
+
+.nf
+tt> tchcol m87pol chi CHI "" degrees
+.fi
+
+In the same table, set the units of column "P" to null.
+The name and format are not changed.
+
+.nf
+tt> tchcol m87pol P "" "" default
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by J.C. Hsu and was modified by Phil Hodge.
+.ih
+SEE ALSO
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tcheck.hlp b/pkg/utilities/nttools/doc/tcheck.hlp
new file mode 100644
index 00000000..e9cb3e89
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tcheck.hlp
@@ -0,0 +1,137 @@
+.help tcheck Aug91 tables
+.ih
+NAME
+tcheck -- Check STSDAS table values.
+.ih
+USAGE
+tcheck input chkfile
+.ih
+DESCRIPTION
+This task allows the user to check the correctness of an STSDAS table by
+printing the rows, column names, and values of selected table
+elements. The table elements selected are controlled by lines in the
+check file. Table elements are printed by placing their names on a
+line in the check file followed by the word "when" and a logical
+expression. The values of all columns listed before the "when" will be
+printed for each row for which the expression is true. For example,
+
+.nf
+ylower, yupper when ylower >= yupper
+.fi
+
+prints the values of the columns 'ylower' and 'yupper' for any row
+where 'ylower' is greater than or equal to 'yupper'. If the column names
+and expression are too long to fit on a line, the line can be
+continued by placing a backslash as the last character on the line.
+Lines which are blank, or start with a comment character (#), are
+ignored.
+
+An expression may contain table column names and string or numerical
+constants. The table column names may be in either lower or upper
+case. If "when" is a column name, place it in upper case so its
+meaning will not be ambiguous. String constants may be surrounded by
+either single or double quotes. Numeric constants will be treated as
+real numbers if they contain a decimal point or integers if they do
+not.
+
+The expression must have a boolean (logical) value. Boolean operators
+can be used in an expression in either their SPP or Fortran form:
+
+.nf
+equal == .eq. not equal != .ne.
+less than < .lt. less than or equal <= .le.
+greater than > .gt. greater than or equal >= .ge.
+or || .or. and && .and.
+negation ! .not.
+.fi
+
+The expression may also include the usual arithmetic operators and
+functions. Arguments to the trigonometric functions must be in
+degrees. The available operators are:
+
+.nf
+addition + subtraction -
+multiplication * division /
+negation - exponentiation **
+string concatenation //
+.fi
+
+Three new functions are available in addition to the usual arithmetic
+functions:
+.nf
+
+row takes no argument, returns current row number
+delta takes two dates (in CDBS format) and returns the
+ number of days between them
+match returns true if the first argument matches one or more
+ of the remaining arguments of the function (the arguments
+ may be of any type, as long as all arguments have the
+ same type.
+.fi
+
+The
+following is a list of the available functions:
+
+.nf
+absolute value abs(x) cosine cos(x)
+sine sin(x) tangent tan(x)
+arc cosine acos(x) arc sine asin(x)
+arc tangent atan(x) arc tangent atan2(x,y)
+exponential exp(x) square root sqrt(x)
+natural log log(x) common log log10(x)
+minimum min(x,y) maximum max(x,y)
+modulo mod(x,y) row number row()
+date difference delta(x,y) equality match (x,y,z,...)
+.fi
+
+.ih
+PARAMETERS
+.ls input [file name template]
+List of tables that will be checked.
+.le
+.ls chkfile [file name]
+Text file containing consistency checks.
+.le
+.ih
+EXAMPLES
+1. The simplest check is when a table element has one legal
+value. This can be tested for as follows.
+
+.nf
+overscan when overscan != 5
+.fi
+
+2. A range of values can also be tested, as in the following expressions.
+
+.nf
+aper_area when aper_area <= 0.0
+pass_dir when detnum < 1 || detnum > 2
+.fi
+
+3. If a keyword has several legal values and they do not form a range, it
+may be easier to use the match function.
+
+.nf
+fgwa_id when ! match(fgwa_id,"CAM","H13","H19","H27",\
+"H40","H57","H78")
+.fi
+
+4. The value of one keyword may depend on the value of another. This can
+be tested by combining the conditions with an "and":
+
+.nf
+aper_pos when aper_id == 'A-1' && aper_pos != 'SINGLE'
+polar_id when fgwa_id == 'CAM' && polar_id != 'C'
+.fi
+
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+hcheck
+
+Type "help tables opt=sys" for a description of the 'tables' package.
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tchsize.hlp b/pkg/utilities/nttools/doc/tchsize.hlp
new file mode 100644
index 00000000..fa9bbb96
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tchsize.hlp
@@ -0,0 +1,158 @@
+.help tchsize Oct95 tables
+.nj
+.ih
+NAME
+tchsize -- Change the size of tables.
+.ih
+USAGE
+tchsize intable outtable maxpar maxcols rowlen allrows
+.ih
+DESCRIPTION
+This task changes the allocated sizes of various portions of a table
+or a list of tables.
+In some cases it is difficult to effectively use this task,
+so caution is advised.
+
+NOTE: This task should not be used on FITS tables.
+If any input table is of type FITS,
+a message will be printed, and that file will be skipped.
+
+Four integer parameters specify table sizes.
+Passing a value of -1 to any parameter means that the current value
+should not be changed. A value (such as zero) that is smaller than
+the minimum allowed value for that parameter results in the truncation
+of unused space; for example, if three header parameters have already
+been written to a table then setting 'maxpar=0' gives you a table with
+space for only three header parameters.
+
+The input may be a general filename
+template, including wildcard characters or the name of a list file (preceded
+by an "@" sign) containing table names. The output may be null, a directory
+specification, or a list of table names. If the output is a list of tables
+then there must be the same number of names in the input and output lists,
+and the names are taken in pairs, one from input and one from output.
+A null string for the output is equivalent to specifying the same names
+for the input and output tables.
+
+NOTE: Be careful when using a wildcard for the extension.
+If you have the files 'table.tab' and 'table.lis' in the current directory,
+for example, then "tchsize tab* test/" would crash when trying to open
+'table.lis' as a table.
+.ih
+PARAMETERS
+.ls intable [file name template]
+A list of one or more tables whose sizes are to be changed.
+.le
+.ls outtable = "" [file name template]
+Either a null string, a directory name, or a list of output table names.
+.le
+.ls maxpar = -1 [integer]
+The number of records to allocate for header (i.e., user) parameters.
+
+Use 'maxpar=-1' if no change is to be made; set 'maxpar=0' to
+truncate unused space.
+.le
+.ls maxcols = -1 [integer]
+The amount of space to allocate for column descriptors. There must be
+at least one for each column that is defined or is to be defined.
+For a column-ordered table 'maxcols' actually determines the maximum
+number of columns that may be defined (without having to rewrite the
+table). For a row-ordered table, however, you must also specify an
+appropriate value for 'rowlen'; you may want to use the 'tinfo' task
+to get the
+current row length before using this task.
+
+Set 'maxcols=-1' if no change is to be made; set 'maxcols=0'
+to truncate unused space.
+.le
+.ls rowlen = -1 [integer]
+The row length; this is only relevant for a row-ordered table.
+The unit of length is the amount of memory used to store
+a real number; so a double-precision column
+takes two units, and a character*24 column takes six units (assuming
+that a real
+is four bytes).
+The number of columns that may be defined is limited both by the
+space allocated for column descriptors and by the row length.
+
+Set 'rowlen=-1' if no change is to be made; set 'rowlen=0'
+to truncate unused space.
+.le
+.ls allrows = -1 [integer]
+The number of rows to allocate; this is only relevant for a column-ordered
+table.
+
+Set 'allrows=-1' if no change is to be made; set 'allrows=0' to truncate
+unused space.
+.le
+.ls (verbose = yes) [boolean]
+Display the names of the input and output tables for each table that is
+processed?
+.le
+.ih
+EXAMPLES
+1. Truncate (in-place) all unused space in a single table:
+
+.nf
+ tt> tchsize table "" 0 0 0 0
+ or
+ tt> tchsize table table 0 0 0 0
+.fi
+
+2. Set the allocated space for user (header) parameters to 27 records
+without changing any other size parameter. The result is to be put
+in a new file called 'table2.tab', leaving the input table unchanged.
+
+ tt> tchsize table table2 27 -1 -1 -1
+
+3. Truncate unused space in three different tables, with the truncated tables
+named 'a.tab', 'b.tab', and 'c.tab':
+
+.nf
+ tt> tchsize table1,table2,tab67 a,b,c 0 0 0 0
+ or
+ tt> tchsize tab*.tab a,b,c 0 0 0 0
+.fi
+In the latter case the extension is given explicitly in case there
+are other files beginning with 'tab' that are not tables; there must
+be exactly three tables beginning with tab because the output list
+has three names.
+
+4. Increase the space available for allocating new columns:
+
+Suppose the following information about the table has been obtained
+by using the 'tinfo' task:
+
+.nf
+ tinfo.ncols = 7
+ tinfo.maxcols = 8
+ tinfo.rowlen = 12
+ tinfo.rowused = 10
+ tinfo.tbltype = "row"
+.fi
+
+Suppose we want to add 10 more columns: five single-precision columns,
+two double-precision, and three character*12. If the table were
+column-ordered we would only have to increase 'maxcols' to at least 17
+('ncols'+10). Since the table is row-ordered we still must have 'maxcols=17',
+but we also have to increase the row length to allow room for the
+additional columns. The extra row length needed is 5 + 2*2 + 3*3 = 18,
+so we must set the new row length to at least 'tinfo.rowused' + 18 = 28.
+So we have
+
+.nf
+ tt> tchsize table "" -1 17 28 -1
+.fi
+
+if the space for header parameters does not need to be changed, and
+the allocated number of rows is irrelevant for a row-ordered table.
+
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+.ih
+SEE ALSO
+tinfo
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tcopy.hlp b/pkg/utilities/nttools/doc/tcopy.hlp
new file mode 100644
index 00000000..a7ac05d7
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tcopy.hlp
@@ -0,0 +1,113 @@
+.help tcopy Jan2001 tables
+.nj
+.ih
+NAME
+tcopy -- Copy tables.
+.ih
+USAGE
+tcopy intable outtable
+.ih
+DESCRIPTION
+This task is used to copy tables. The input may be a general filename
+template, including wildcard characters or the name of a file (preceded
+by an @ sign) containing table names. The output may be either a directory
+specification or a list of table names. If the output is a list of tables
+then there must be the same number of names in the input and output lists,
+and the names are taken in pairs, one from input and one from output.
+The input and output tables must not be the same.
+This task will convert the format of the table
+if the output filename extension indicates it.
+For example, if the output filename extension is ".fits",
+the output table will be a fits file.
+If the output is redirected or piped,
+it will be written to a text table.
+
+NOTE: Be careful when using a wildcard for the extension.
+If you have the files "table.tab" and "table.lis" in the current directory,
+for example, then the command "tcopy tab* test/" would copy both files
+to the subdirectory "test".
+.ih
+PARAMETERS
+.ls intable [file name template]
+A list of one or more tables to be copied.
+.le
+.ls outtable [file name template]
+Either a directory name or a list of output table names.
+
+If 'outtable' is not a directory,
+the number of input tables and output tables must be the same.
+An exception to this rule is that if 'outtable' is a FITS file
+(i.e. an existing FITS file, or the name ends in ".fits")
+then multiple input tables can be copied to one output file.
+.le
+.ls (verbose = yes) [boolean]
+Display names of input and output tables as they are copied?
+.le
+.ih
+EXAMPLES
+1. To simply copy a table:
+
+.nf
+ tt> tcopy table.tab tablecopy.tab
+.fi
+
+2. To copy one or more tables, possibly changing table type:
+
+.nf
+ tt> tcopy table1.tab,table2.tab a.fits,b.tab
+ tt> tcopy a.fits,b.tab a.tab,b.fits
+ tt> tcopy a.fits > a.txt
+.fi
+
+The number of input and output tables must be the same.
+In the third case,
+"a.txt" will be a text file because
+the output table name was "STDOUT"
+(the name was implicitly set, in this case,
+because the output was redirected.)
+
+3. To copy a set of tables to a new directory:
+
+.nf
+ tt> tcopy table*.tab directory
+ or
+ tt> tcopy table*.tab directory$
+ or
+ tt> tcopy table*.tab osdirectory
+.fi
+
+where "directory" is an IRAF environment variable for a directory name,
+and "osdirectory" is an operating system directory name
+(e.g., "/user/me/" in UNIX).
+
+4. To copy only specified extensions of a FITS file:
+
+.nf
+ tt> tcopy xyz.fits[3],xyz.fits[5] b.fits
+.fi
+
+If "b.fits" did not already exist,
+it would be created and would then contain two table extensions.
+If it did already exist,
+the two extensions would be appended.
+Note that the number of input and output files are not the same;
+this is OK because the output is a FITS file
+and can therefore contain multiple table extensions.
+
+5. The input and/or output may be redirected:
+
+.nf
+ tt> dir l+ | tproject columns=c7,c3 | tcopy dir.tab > verbose.lis
+.fi
+
+"verbose.lis" contains just the one line "# STDIN -> dir.tab",
+and "dir.tab" has the output of 'tproject', the file names and sizes.
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+.ih
+SEE ALSO
+tdelete
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tcreate.hlp b/pkg/utilities/nttools/doc/tcreate.hlp
new file mode 100644
index 00000000..0d12d277
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tcreate.hlp
@@ -0,0 +1,378 @@
+.help tcreate Dec2003 tables
+.nj
+.ih
+NAME
+tcreate -- Create a table from ASCII files describing a table format.
+.ih
+USAGE
+tcreate table cdfile datafile
+.ih
+DESCRIPTION
+This task reads an ASCII file containing column descriptions for a new table.
+The columns are defined and the table created;
+data are read in from a file specified by
+the 'datafile' parameter
+(a specified number of lines may be skipped when reading in data).
+There may be several lines of data per table row.
+Blanks and tabs are skipped.
+Blank lines and lines beginning with # are ignored.
+In-line comments using # are permitted.
+The lines in the input files may be up to 8195 characters long,
+plus one character for the carriage return.
+The input 'datafile' is read free-format.
+
+Undefined values require a place holder in the data file.
+The word INDEF should be used as the place holder
+for undefined (indefinite) numerical values,
+the word "no" for boolean values,
+and a pair of adjacent quotes ("") for undefined character strings.
+If a value for a character string contains one or more blanks,
+or the comment character (#),
+then the entire value must be enclosed in quotes, e.g., "R CrB".
+
+This task can also read a file containing header parameters for the table.
+
+If a problem occurs when reading a particular data field,
+the execution continues, and the table entry is marked as undefined.
+.ih
+PARAMETERS
+.ls table [file name]
+Output file name for the table created by this task.
+
+Note that, if 'table' is an existing FITS file,
+the table that is created will be appended
+as a new extension to the end of the file.
+.le
+.ls cdfile = STDIN [file name]
+The name of the column definition file.
+
+The column definition file contains one line for each column to be created.
+Each line contains up to four values giving attributes of the particular column.
+Every line must have a column name; optionally, it may have a data type,
+display format, and units. (Embedded blanks in any of these
+attributes must be enclosed in quotes.) Adjacent quotes are used as
+place holders and let you skip an attribute while defining the next one.
+Column names and data types are NOT case sensitive.
+Neither the format nor data type may contain embedded blanks.
+Display formats may be of the type used by Fortran or those used by SPP.
+If the format is not defined, a default format will be used.
+The format is not used for internal representation of the data and
+is ignored when reading data---it is used only for display purposes,
+for example, by tasks such as 'tedit', 'tread', and 'tprint'.
+Type "help ttools opt=sysdoc" for detailed information about print formats.
+Comment lines may be included in this file
+by beginning the line with the comment symbol (#).
+
+The following data types are recognized by this parameter
+(the default data type is single-precision real):
+.nf
+
+ r - Single-precision real.
+ d - Double-precision real.
+ i - Integer.
+ s - Short integer.
+ b - Boolean.
+ ch*n - Character string of maximum length n.
+.fi
+
+A column of arrays can be created by giving the array length
+in square brackets appended to the data type.
+For example, a data type of r[400] would mean that the column
+contains an array of 400 single-precision real numbers in each row.
+r[20,5,4] would also mean an array of 400 reals,
+but in this case a TDIMi keyword will be written (for column number i)
+that gives the numbers 20, 5 and 4,
+indicating that the array should be regarded as 3-D,
+with 20 elements along the most rapidly varying axis
+and four elements along the least rapidly varying axis.
+Up to seven dimensions may be specified, separated by commas.
+For both of these cases, the data file must contain 400 values
+for that column for each row;
+the values need not all be on the same line of the data file.
+Text tables and column-ordered stsdas tables
+cannot contain arrays; see 'tbltype'.
+
+If you have an existing table
+with columns similar to those
+in the table you would like to create,
+you can use the 'tlcol' task to generate a file
+which can be edited and used as the input 'cdfile' for 'tcreate'.
+That is, the output of 'tlcol' is exactly the format
+that is expected for 'tcreate.cdfile'.
+The syntax is also the same as
+for column definitions in text tables,
+except for the leading "#c " in text tables.
+
+If cdfile = "STDIN" and the input is not redirected,
+the task prints a prompt asking for input.
+Press Control-Z (or Control-D, i.e. your EOF character)
+to terminate the list of column definitions;
+note that the Control-Z must NOT occur on the same line as the last
+column definition.
+.le
+.ls datafile = "STDIN" [file name]
+The name of the input ASCII data file.
+
+The values in the file must be in the order of the columns
+as given in the column-definitions file 'cdfile'.
+Undefined values should have INDEF or "" as place holders
+for numerical or character values, respectively.
+Each row for the table must begin with a new line in 'datafile',
+but there can be multiple lines in 'datafile' for each table row
+(see also 'nlines').
+
+If all data for a table row have been read from an input line
+but there are additional data on the line,
+or if there is a data type mismatch,
+the following warning will be
+printed: "out of synch or extra data in line <number>".
+
+Lines in the input data file are limited to 8196 characters,
+including the newline at the end of each line.
+If a longer line is encountered, the task will stop with an error.
+
+As with 'cdfile',
+if datafile = "STDIN" and the input is not redirected,
+the task prints a prompt asking for input.
+Enter a carriage return before ending the last line
+and then press Control-Z (or Control-D, i.e. EOF) to close the file.
+.le
+.ls (uparfile) [file name]
+The name of the input ASCII file of header parameters.
+This file is optional.
+
+Each line of this file defines one header parameter,
+except that blank lines and lines beginning with # will be ignored.
+Each line should contain three parts: keyword, datatype, and value;
+an optional comment may be added following the value.
+The keyword is a string (no embedded blanks) of up to eight characters.
+The datatype is a single letter (t, b, i, r, or d) that indicates the type.
+The value is limited to 70 characters.
+If the type is text (t) it may contain more than one word,
+but in that case it must be enclosed in quotes;
+otherwise, the portion of the value following the first word
+will be interpreted as a comment.
+
+Note that the syntax is not the same as
+for header keywords in text tables.
+The latter uses the much more reasonable "#k keyword = value comment".
+The datatype shouldn't need to be specified,
+since keywords are stored in the table as text strings anyway;
+the current syntax has been retained for backward compatibility.
+
+It is possible, though not recommended, to set uparfile = "STDIN".
+The problem is that it is read twice,
+once just to count the number of entries, and once to read the values,
+so you would have to type in the values twice.
+.le
+.ls (nskip = 0) [integer, min=0, max=INDEF]
+Number of lines to skip at the beginning of the data file.
+
+The 'tcreate' task will also skip blank lines and lines beginning with #;
+it will therefore not usually be necessary to specify 'nskip',
+as header lines may be commented out by inserting a leading #.
+Note that if 'nskip > 0' then exactly 'nskip' lines will be skipped,
+even if some of them are blank or comment lines.
+.le
+.ls (nlines = 0) [integer, min=0, max=INDEF]
+The number of lines in the input data file
+corresponding to one row in the output table.
+If 'nlines = 0' (the default) then lines will
+be read from the data file until every column in the row is filled.
+If 'nlines > 0' then exactly this many lines will be read for each row;
+if for some rows the input data are compressed into fewer than this
+many lines, extra dummy lines must be included following the good data.
+Note that comment lines and blank lines are not counted.
+.le
+.ls (nrows = 0) [integer, min=0, max=INDEF]
+The number of rows to write into the table.
+
+If this value is zero, then the entire input data file will be read.
+If this value is greater than zero then
+no more than 'nrows' will be written to the table,
+even if the data file contains enough data to fill more than
+'nrows' rows of data.
+For a column-ordered table (see the 'tbltype' parameter),
+'nrows' is the number of rows that will be allocated,
+and the actual number in the data file may be smaller.
+.le
+.ls (hist = yes) [boolean]
+Add a history record containing a creation date?
+
+If 'hist = yes', a header parameter will be written to the table with the
+keyword 'HISTORY' that gives the date and time that 'tcreate' was run.
+This parameter is added after those that were read from the 'uparfile', if any.
+.le
+.ls (extrapar = 5) [integer, min=0, max=INDEF]
+Extra space to be reserved for header-parameter records.
+This is the number of records for header parameters that will be allocated,
+in addition to the number needed to hold the parameters
+specified in the 'uparfile' parameter file.
+The default is five,
+which means that after the table is created
+up to five more parameters may be added
+(e.g., by using the 'tupar' task)
+without the table being rewritten to reallocate space.
+.le
+.ls (tbltype = "default") [string, allowed values: default | row |
+column | text]
+Type of table to create.
+The default is row-ordered stsdas format.
+To create a FITS table,
+use tbltype = "default"
+and specify a table name ('table')
+with filename extension ".fits", ".fit", or ".??f"
+('?' is any single character).
+.le
+.ls (extracol = 0) [integer, min=0, max=INDEF]
+Extra space to be reserved for columns in the output table.
+This parameter is relevant only for a row-ordered stsdas format table.
+
+This is in addition to the number required to contain those columns
+described by 'cdfile'.
+One unit of space is taken by each
+single-precision, integer, or boolean column.
+A double-precision column requires two units of allocated space,
+and a character-string column takes one unit of space for each four
+characters, or fraction thereof.
+.le
+.ih
+EXAMPLES
+1. Wait for the user to type in column definitions and data,
+each of which will be terminated by a Control-Z (or Control-D, i.e. EOF).
+The prompts are printed by the 'tcreate' task;
+these are the lines beginning with "Give column definitions"
+and "Give table data".
+The table will have 4 columns and 2 rows.
+.nf
+
+tt> tcreate test STDIN STDIN
+
+Give column definitions (name, datatype, print format, units)
+ ... then newline & EOF to finish.
+name ch*12
+ra d h12.1 hours
+dec d h12.0 degrees
+mag r f8.2
+^Z
+
+Give table data ... then newline & EOF to finish.
+nameless 3:18:47 42:24 INDEF
+"SA0 123456" 19:00:06.3 -0:00:01 3.5
+^Z
+
+.fi
+2. Create a table called "outfile.tab" using the columns specified
+in "columns.cd" and the data in "data.dat".
+
+tt> tcreate outfile columns.cd data.dat nskip=3
+
+"columns.cd" may contain just the following:
+.sp
+.nf
+STARno I i5
+X r "F6.2" pixels
+Y R F6.2 "pixels"
+MAG R "" magnitude
+ SHARP R
+ ROUND r
+STARNAME ch*15
+.fi
+
+Note the free format of, and embedded tabs in, the column definitions file
+itself. The format for display of MAG is not specified, but the unit is
+given as magnitude, so adjacent quotes are used to mark the position where
+the display format is expected.
+
+The file "data.dat" may contain (if 'nskip=3', 'nlines=2'):
+.sp
+.nf
+This is a header
+ header2
+ header3
+ 1 3.0 4.0
+ 5.0 6.0 7.0 HD12345
+ 2 10.0 11.0 12.0 13.0
+14.0 "HD 122"
+3 20.0 21.0 22.0 23.0 24.0 ""
+dummy line
+.fi
+
+Note the tabbed and free format of the data file
+and the specification of the character strings.
+If the character data contain embedded blanks
+then the whole string should be quoted,
+otherwise this is not necessary.
+The final entry is the null character string.
+
+3. The following column definitions:
+.sp
+.nf
+STARno i i6
+X r f9.2 pixels
+Y r f9.2 pixels
+MAG r f9.3
+SHARP r f9.3
+ROUND r f9.3
+STARNAME ch*15
+
+could be used with the following data file:
+
+ 1 7.92 2.64 -3.075 0.436 0.019 XXXXXXXXXXXXXXX
+ 2 33.89 3.14 -1.162 0.419 0.223
+ 3 3.68 5.07 -2.454 0.421 -0.123 HD12345
+ 4 42.70 5.08 -1.285 0.445 0.195 HD 123
+.fi
+
+4. The aperture photometry file from the 'daophot' task
+may have the following data:
+.sp
+.nf
+ 1 6.95 2.61 99.999 99.999 99.999 99.999 . . .
+ 464.618 9.71 0.52 9.999 9.999 9.999 9.999 . . .
+ 2 200.06 2.80 99.999 99.999 99.999 99.999
+ 465.180 7.79 0.16 9.999 9.999 9.999 9.999
+ 3 156.25 5.17 14.610 14.537 14.483 14.438
+ 462.206 7.26 0.37 0.013 0.014 0.015 0.016
+
+
+and could have the following column-definition file:
+
+STARno i
+X r
+Y r
+MAG1 r
+MAG2 r
+MAG3 r
+ .
+ .
+ .
+MAG15 r
+SKYMOD r
+SKYSD r
+.fi
+
+The following could be used as an input file to define header parameters.
+.sp
+.nf
+comment t Created 1987 July 22
+NL i 2
+NX i 284
+NY i 492
+THRESH r 27.0
+AP1 r 3.0
+PH/ADU r 20.0
+RNOISE r 6.50
+BAD r 300.0
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+.ih
+SEE ALSO
+Type "help ttools opt=sysdoc" for a higher-level description of the 'ttools'
+package.
+See also the files in "tables$doc/".
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tdelete.hlp b/pkg/utilities/nttools/doc/tdelete.hlp
new file mode 100644
index 00000000..43b9ee64
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tdelete.hlp
@@ -0,0 +1,74 @@
+.help tdelete Aug93 tables
+.nj
+.ih
+NAME
+tdelete -- Delete a table.
+.ih
+USAGE
+tdelete table
+.ih
+DESCRIPTION
+This task deletes tables.
+The input may be a general filename template,
+including wildcard characters, or the name of a list file
+(preceded by the "@" character) containing table names.
+
+The task checks that the file to be deleted really is a table
+before deleting it.
+In order to protect against accidental deletion of files other than tables,
+text tables may be deleted using 'tdelete' only if 'verify = yes'.
+.ih
+PARAMETERS
+.ls table [file name template]
+A list of one or more tables to be deleted.
+.le
+.ls (verify = no) [boolean]
+Prompt for confirmation before deleting? It is possible to delete
+text tables using 'tdelete' if 'verify' is set to "yes".
+.le
+.ls (default_action = yes) [boolean]
+Default action for the verify query. If 'default_action = yes', then the
+prompt will come back with "yes?" and striking return will proceed with
+the delete.
+.le
+.ls go_ahead = yes [boolean]
+This is a copy of 'default_action' used for prompting if 'verify = yes'.
+This parameter is set by the task, it copies the value of 'default_action',
+but cannot be directly set by the user.
+.le
+.ih
+EXAMPLES
+1. Delete a single table.
+
+.nf
+ cl> tdelete table
+.fi
+
+2. Delete several tables.
+
+.nf
+ cl> tdelete table1,table2,tab67
+ cl> tdelete *.tab,a,b,c
+
+.fi
+In the latter case, the extension is given explicitly because there may be
+other files beginning with "tab" that are not tables.
+
+3. Delete a list of tables using verify.
+
+.nf
+ cl> tdelete fits*.tab ver+
+ cl> delete table `fits1.tab' ? (yes): yes
+ cl> delete table `fits2.tab' ? (yes): yes
+ cl> delete table `fits3.tab' ? (yes): yes
+.fi
+.ih
+BUGS
+Text tables cannot be deleted by 'tdelete' unless 'verify' is set to yes.
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+.ih
+SEE ALSO
+delete, tcopy, trename
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tdiffer.hlp b/pkg/utilities/nttools/doc/tdiffer.hlp
new file mode 100644
index 00000000..915aa4c6
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tdiffer.hlp
@@ -0,0 +1,65 @@
+.help tdiffer May92 tables
+.ih
+NAME
+tdiffer -- Create a new table which is the difference of two tables.
+.ih
+USAGE
+tdiffer intable1 intable2 outtable colnam1 colnam2
+.ih
+DESCRIPTION
+This task creates an output table containing all the rows of the first table
+which do not match the rows in the second table.
+The first, second, and output tables are given by the task
+parameters 'intable1', 'intable2', and 'outtable' respectively.
+The match is done on the columns specified by the task parameters 'colnam1'
+and 'colnam2'.
+Other columns are ignored.
+If the two tables are disjoint, the output table will be a copy of
+the first table, except the rows will be sorted.
+If the first table is a subset of the second, the output table will be empty.
+.ih
+PARAMETERS
+.ls intable1 [file name]
+The name of the first input table.
+.le
+.ls intable2 [file name]
+The name of the second input table.
+.le
+.ls outtable [file name]
+The name of the output table. The output table has the same header parameters
+and column names as the first table.
+.le
+.ls colnam1 [string]
+The column names in the first table used in the match. If more than one
+column is used, columns from the first and second
+table are associated with each other based on their position in the list
+and not on their names, i.e., the first column name in 'colnam1' is matched
+to the first column name passed to 'colnam2', regardless of whether the
+names match.
+.le
+.ls colnam2 [string]
+The column names in the second table used in the match. The same number of
+column names must be passed to both the 'colnam1' and 'colnam2' parameters.
+.le
+.ih
+EXAMPLES
+1. There are two tables, "targets.tab", containing a list of targets
+for observation, and "images.tab", containing a list of targets which
+have already been observed. Create a table named "new.tab" containing
+those targets which have not previously been observed:
+
+.nf
+tt> tdiffer targets.tab images.tab new.tab targetid targetid
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+tselect
+
+Type "help tables opt=sys" for a higher-level description of the 'tables'
+package.
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tdump.hlp b/pkg/utilities/nttools/doc/tdump.hlp
new file mode 100644
index 00000000..ef146b58
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tdump.hlp
@@ -0,0 +1,150 @@
+.help tdump Nov2000 tables
+.nj
+.ih
+NAME
+tdump -- Convert an STSDAS table to ASCII format.
+.ih
+USAGE
+tdump table
+.ih
+DESCRIPTION
+This task converts an STSDAS table to ASCII format.
+The output does not include row numbers or column names;
+use the 'tprint' task for more readable output.
+
+The two primary uses for 'tdump' are to allow editing that would be
+difficult or impossible with 'tedit' (such as global substitutions)
+and copying a table over a network to another computer.
+For such purposes the table can be dumped to three separate files
+(i.e., one containing column definitions, one for header parameters,
+and one for table data),
+the data may be edited, column data types changed, etc.,
+and then the 'tcreate' task can be used to reassemble the table
+from the three ASCII files.
+To prevent loss of information due to truncation,
+floating point data are printed using g format with a wide field.
+A character value with multiple words is printed with enclosing quotes
+to make it clear that it is the value for a single column
+and also for compatibility with 'tcreate'.
+
+All rows and columns of the table are dumped by default,
+but ranges of rows and individual columns may be specified.
+
+The order of printing the data is as follows.
+The first column of the first row is printed,
+then the second column of the first row is printed,
+then the third column of the first row, etc.
+If any column contains arrays,
+each element of the column array in the current row is printed
+before moving on to the next column.
+If the printed output is wider than a page (see 'pwidth'),
+the output will consist of more than one line per row of the table.
+After printing all columns in the first row,
+the second row is printed in the same way.
+Each row begins with a new line in the output text file.
+Note that this can be different from 'tprint',
+which prints all rows for those columns that will fit on a page,
+then prints all rows for the next set of columns.
+.ih
+PARAMETERS
+.ls table [file name]
+The name of the STSDAS table to be dumped.
+.le
+.ls (cdfile = STDOUT) [file name]
+If 'cdfile' is not null (i.e., it is not passed a value of "")
+then the column definitions will be written
+to an output file having the name passed to 'cdfile'.
+(Note: A space is not null.) The column definitions consist of
+the column name, data type ("R" for real,
+"D" for double, "I" for integer, "B" for boolean,
+or "CH*n" for character strings of length n), print format, and units.
+For columns of arrays,
+the array size is shown in square brackets appended to the data type.
+.le
+.ls (pfile = STDOUT) [file name]
+If 'pfile' is not null (i.e., it is not passed a value of "")
+then the header parameters will be written
+to an output file with the name passed to 'pfile'.
+This file will not be created
+if there are no header parameters in the input file.
+.le
+.ls (datafile = STDOUT) [file name]
+If 'datafile' is not null (i.e., it is not passed a value of "") then
+the table data will be written
+to an output file with the name passed to 'datafile'.
+This file will not be created if the input table is empty.
+.le
+.ls (columns = "") [string]
+The names of the columns to be printed.
+A null value causes all columns to be printed.
+A column template consists of a list
+of either column names or column name templates that include wildcards.
+Individual column names or templates are separated by commas or white space.
+This list of column names can be placed in a list file and 'column'
+will then be passed the file name preceded by a "@" character.
+If the first non-white character in the column template
+is the negation character (either "~" or "!")
+the columns NOT named in the template will be printed.
+
+The 'tlcol' task (with the 'nlist' parameter set to 1) may be used
+to generate a list of column names so there is no question about spelling.
+This list may be edited to rearrange or delete columns.
+.le
+.ls (rows = "-") [string]
+The range of rows to be printed.
+The default of "-" means print all rows.
+The first ten rows could be specified as 'rows="1-10"'.
+To print the first ten rows and all rows from 900 through
+the last (inclusive), use 'rows="1-10,900-"'.
+Setting 'rows="1,3,7,23"' will print only those four rows.
+It is not an error to specify rows larger than the largest row number;
+they will simply be ignored.
+Type "help xtools.ranges" for more information.
+.le
+.ls (pwidth = -1) [integer, min=-1, max=INDEF]
+Width of the output for printing the table data.
+The default value of -1 means that
+checking the width should be disabled,
+and each table row will be written to one line in the output file.
+
+If any column to be printed is wider than 'pwidth',
+a warning message will be displayed,
+and the data will overflow the page width.
+The width of each character column is
+increased by two to allow space for a pair of enclosing quotes,
+which will be used if the value to be printed includes a blank or tab.
+.le
+.ih
+EXAMPLES
+1. Dump the table "junk.tab" to STDOUT:
+.nf
+
+ tt> tdump junk.tab cdfile=STDOUT pfile=STDOUT datafile=STDOUT
+
+.fi
+2. Dump "junk.tab", but with the order of the columns rearranged:
+.nf
+
+ tt> tlcol junk.tab nlist=1 > colnames.lis
+ tt> edit colnames.lis
+ (Rearrange the column names and perhaps delete some of them.)
+ tt> tdump junk.tab columns=@colnames.lis
+.fi
+
+3. Dump only the first 100 rows of the file "big.fits":
+
+.nf
+ tt> tdump big.fits rows="1-100"
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+.ih
+SEE ALSO
+tprint, tlcol, tcreate, ranges
+
+Type "help tables opt=sys" for a higher-level description of the 'tables'
+package.
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tedit.hlp b/pkg/utilities/nttools/doc/tedit.hlp
new file mode 100644
index 00000000..80ff3381
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tedit.hlp
@@ -0,0 +1,295 @@
+.help tedit Oct94 tables
+.ih
+NAME
+tedit -- Edit a table.
+.ih
+USAGE
+tedit table
+.ih
+DESCRIPTION
+This task is a screen editor for STSDAS tables. You edit a table by
+moving the cursor around the screen with the cursor keys and typing in
+the new value of the table element. The screen scrolls both sideways
+and up and down as you move the cursor, so all elements of the table
+can be reached. Other editing commands are entered on the command
+line. To switch from table editing mode to command line mode, you
+press the EXIT key (usually Control-Z, however, you can change this). After
+performing your command, the editor returns to table editing mode,
+unless the command exits the editor. The most important commands in
+command mode are `help', `exit', and `quit'. The `help' command
+displays all the editing key bindings and the command line commands.
+The `exit' command will get you out of the editor and automatically
+save the edited table. The `quit' command will get you out of the
+editor after asking you whether you want to save the table. By
+default, the editor modifies a copy instead of the original table, so
+if you quit without saving the table, the original table is still
+there without any modifications.
+
+If you try to edit a table that does not exist, the editor will ask if
+you want to create the table. If you answer "no", the editor will
+exit. If you answer "yes", the editor will ask you for each column
+name, type, unit, and print format. When you have finished entering
+all the columns, press the return key instead of entering another
+column name. The editor will create the table and put you in table
+editing mode.
+
+To add a new, blank line to the end of a table, press the return key
+while you are on the last line of the table. You can add blank lines
+anywhere in the table with the `add row' command, which will be
+described later.
+
+Some editing commands are entered from the command line in command
+mode. To get to command line mode, press the exit key. This key is
+bound to Control-Z by default. If you enter a blank line, the editor will
+return to table editing mode. Some commands take arguments. They can
+be included when the command is entered, or if they are omitted, the
+editor will prompt you for their values. If the argument has embedded
+blanks, the argument should be enclosed in quotes if passed on the
+command line. No quotes should be used if the argument is entered
+interactively. When the editor interactively prompts you for a command
+argument it will also display a default value for the argument.
+Pressing the return key gets the default value. Some command names are
+two words long, for example, "add row". Usually the second word is
+optional and modifies the meaning of the first, for example "copy
+append". If the second word is not optional and you omit it, the
+editor will prompt you for it. All command names can be abbreviated to
+one or more letters. If the command name is two words long, both words
+can be abbreviated to one or more letters.
+
+The following is a list of the available commands:
+
+.ls add column <name> <type> <format> <units>
+Add a new column to the table with the specified name and data type.
+.le
+.ls add row <row> <number>
+Add new, blank rows after row number <row>. The legal range of <row> is
+0 to the number of rows in the table. The number of blank rows to add is
+<number>.
+.le
+.ls copy <first> <last>
+Copy the rows between <first> and <last> into the paste buffer. The
+current contents of the paste buffer are destroyed before the copy.
+The table is not modified by this command. The contents of the paste
+buffer can be put back into the table by the 'insert' command.
+.le
+.ls copy append <first> <last>
+Copy the rows between <first> and <last> into the paste buffer. The
+current contents of the paste buffer are preserved and the new rows
+are inserted after them.
+.le
+.ls delete <first> <last>
+Delete the rows between <first> and <last>. The deleted rows are placed
+into the paste buffer and the current contents of the paste buffer are
+destroyed.
+.le
+.ls delete append <first> <last>
+Delete the rows between <first> and <last>. The deleted rows are appended
+to the paste buffer.
+.le
+.ls exit
+Exit the table editor, saving any changes made to the table.
+.le
+.ls find <expression>
+Find the next row in the table which makes <expression> true and move
+the cursor to that row. The expression has the same syntax as an
+expression in a Fortran if statement. The variables in the expression
+are column names. For more information on the syntax of the
+expression, read the help for 'tselect'. The direction of the search depends
+upon previous 'find' commands. By default the search direction is forward;
+however, if a "find backwards" command has been executed previously,
+searches will be done in a backwards direction until a "find forward"
+command is executed.
+.le
+.ls find forward <expression>
+Find the next row in the table which makes <expression> true and move the
+cursor to that row. The search is done in the forwards direction.
+.le
+.ls find backwards <expression>
+Find the next row in the table which makes <expression> true and move the
+cursor to that row. The search is done in the backwards direction.
+.le
+.ls goto <row> <column>
+Move the cursor to <row> and <column>.
+.le
+.ls help
+Display online help information for the table editor. The help includes
+a brief description of each command line command and the key bindings
+for table editing commands.
+.le
+.ls insert <row>
+Insert the contents of the paste buffer after row number <row>. The
+contents of the paste buffer are not changed.
+.le
+.ls lower <column>
+Convert <column> to lower case. Only string columns can be converted.
+.le
+.ls next
+Repeat the previous find command, using the same expression and search
+direction that was used with it.
+.le
+.ls next forward
+Repeat the previous find command, changing the search direction to
+forwards.
+.le
+.ls next backwards
+Repeat the previous find command, changing the search direction to
+backwards.
+.le
+.ls quit
+Exit the table editor. If the table has been changed, the table editor
+will ask you whether to save it before exiting.
+.le
+.ls set <column> <expression>
+Set a column equal to an expression. If the column is a string column,
+the expression must be a constant. If the column is numeric, the
+expression can either be a constant or a Fortran-like expression. For
+the exact syntax of the expression, see the help file for tcalc.
+.le
+.ls substitute <column> <target> <replacement>
+Search for and replace text patterns in a column. The syntax for the
+target and replacement pattern strings largely follows that used in
+the substitute command by the Unix text editors `ed' and `ex'. The
+pattern consists of a sequence of ordinary characters, which match
+themselves, and meta-characters, which match a set of characters. A
+meta-character can be matched as if it were an ordinary character by
+preceding it with the escape character, `\'. For example, the escape
+character itself is indicated in a pattern by `\\'. The meta-characters
+which can be used in the target pattern are:
+
+.nf
+beginning of string ^ end of string $
+white space # escape character \
+ignore case { end ignore case }
+begin character class [ end character class ]
+not, in char class ^ range, in char class -
+one character ? zero or more occurrences *
+begin tagged string \( end tagged string \)
+.fi
+
+A set of characters is indicated in the target string by the character
+class construct. For example, punctuation could be indicated by
+`[,;.!]'. A range of characters contiguous in the underlying
+character set can be abbreviated by the range construct. For example,
+`[a-z]' matches any lower case character. The complement of a
+character set is indicated by making `^' the first character in a
+class. For example, `[^0-9]' matches any non-digit. Repetition of a
+character or character class is indicated by the following it with the
+`*' meta-character. Thus, zero or more occurrences of a lower case
+character is indicated by `[a-z]*'. The tagged string meta-characters
+have no effect on the match, they only serve to identify portions of
+the matched string for the replacement pattern. The meta-characters
+which are used in the replacement pattern are the following:
+
+.nf
+entire string & tagged string \n
+capitalize \u upper case \U
+lower case \L end case conversion \e \E
+.fi
+
+The ditto meta-character, `&', indicates that the entire portion of the
+string that was matched by the target pattern. The tag meta-character
+indicates that the n-th tagged string. For example, `\1' indicates
+the first tagged string and `\2' the second. The remaining
+meta-characters affect the case of the output string. The
+capitalization meta-character only affects the immediately following
+meta-character, but the upper and lower case meta-characters must be
+turned off explicitly with `\e' or `\E'.
+.le
+.ls upper <column>
+Convert <column> to upper case. Only string columns can be converted.
+.le
+
+The bindings to the table editing keys are read from the edcap file.
+This is the same file which is used to define the key bindings for the
+parameter editor and history editor. The edcap file defines key
+bindings which resemble those of commonly used text editors. Three
+edcap files are distributed with IRAF. They define key bindings which
+resemble EDT, Emacs, and vi. These edcap files are located in the 'dev$'
+directory and have the extension '.ed'. The appropriate file is chosen
+according to the value of the environment variable 'EDITOR'. If you
+want to customize the key bindings of the table editor, copy the
+appropriate edcap file from the 'dev$' directory to your 'home$' directory
+and edit the second column of the file. The table editor searches your
+home directory first for the edcap file and if it does not find it,
+then it searches the 'dev$' directory.
+
+The table editor also uses the termcap file to determine the screen
+size and the escape sequences used to modify the screen. There are
+entries in the termcap file for almost all terminal types. The proper
+entry is selected according to the environment variable 'TERMINAL'. To
+change your terminal type or the screen size, use the IRAF 'stty'
+command.
+
+The 'tread' task can also be used to view a file in readonly mode.
+.ih
+PARAMETERS
+.ls table [string]
+The name of the table to be edited. The editor checks for the
+existence of the table and its access mode before editing. If the
+table does not exist, the editor will ask whether you want to create
+a new table. If you do not have write access to a table you can only
+edit it by setting 'rdonly=yes'.
+.le
+.ls (columns = "") [string]
+The names of the columns to be edited.
+A null or blank string means edit all columns.
+A column template consists of a list of either
+column names or column patterns containing the usual pattern matching
+meta-characters. The names or patterns are separated by commas or
+white space. The list can be placed in a file and the name of the
+file preceded by an "@" given in its place.
+If the first character in the column template is a bang (!),
+all columns NOT named will be displayed.
+
+The 'tlcol' task (with the 'nlist' parameter set to 1) may be used to generate
+a list of
+column names so there is no question about spelling. This list may be
+edited to rearrange or delete the names, and then the list
+file is given preceded by an '@' sign, for example:
+
+.nf
+tt> tedit junk columns=@colnames.lis
+.fi
+.le
+.ls (silent = no) [boolean]
+Turn off the bell indicating warning messages?
+.le
+.ls (rdonly = no) [boolean]
+View a table without modifying it? This parameter prevents you from
+executing
+any command that would modify the file.
+.le
+.ls (inplace = no) [boolean]
+Replace existing table? If 'rdonly' is
+set to "yes" the table is always edited in place.
+.le
+.ih
+EXAMPLES
+1. Make a copy of the table 'm12b.tab' (if it exists) and edit the copy.
+If the table does not exist
+then a temporary table is created, and you will be prompted for the
+name of the first column to be created. In either case, if you
+exit (rather than quitting) the temporary table will be renamed to
+'m12b.tab'.
+
+.nf
+tt> tedit m12b
+.fi
+
+2. Display the columns 'SHARP' and 'ROUND' in an existing table. Rows may
+be added or deleted, and columns may be added.
+
+.nf
+tt> tedit m12b columns="SHARP,ROUND"
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+tread, tprint, tselect, stty
+
+Type "help tables opt=sys" for a description of the 'tables' package.
+.endhelp
diff --git a/pkg/utilities/nttools/doc/texpand.hlp b/pkg/utilities/nttools/doc/texpand.hlp
new file mode 100644
index 00000000..52fd03e6
--- /dev/null
+++ b/pkg/utilities/nttools/doc/texpand.hlp
@@ -0,0 +1,159 @@
+.help texpand Dec90 tables
+.ih
+NAME
+texpand -- Expand table rows according to a set of rules.
+.ih
+USAGE
+texpand input output rbase
+.ih
+DESCRIPTION
+This task uses a set of rules to convert each row in the input table
+into one or more rows in the output table. Except for these
+conversions, the output table is identical to the input table. The set
+of rules is contained in a text file specified by the 'rbase' parameter.
+Each rule has two parts, the target and
+the action.
+
+Rules are applied in the following ways. The task reads a row
+from the input table. It then looks at the target part of each rule in
+the rules file in the order that they were placed in the file. If the
+input row does not match the target part of any rule, it is written to
+the output table without being changed.
+Otherwise, the first rule whose target matches the
+input row is used to convert the input row. The columns and values
+contained in the action part of the rule are used to modify the
+input row to produce a new output row. After the new row is produced, the set
+of rules is searched again to see if any of the rules can be applied
+to the new row. This process continues until no further matches can be
+found, at which point the new rows are written to the output table.
+
+For example, suppose the following rules are contained in the rules
+file:
+.nf
+
+SEX = M && NAME = ANY => NAME = Tom || NAME = Dick || NAME = Harry;
+SEX = F && NAME = ANY => NAME = Mary || NAME = Jane;
+SEX = X => SEX = M || SEX = F;
+
+.fi
+And suppose the input table contains the following information:
+.nf
+
+NAME SEX TITLE
+ANY X Astronomer
+
+.fi
+The first two rules impose two conditions, the first on the value of
+the 'SEX' column and the second on the value of the 'NAME' column. While
+the value of the 'NAME' column matches the conditions in the first two
+rules, the value of 'SEX' does not. The third rule only imposes one
+condition, which does match the row in the input table. Thus the third
+rule of the rule file is applied to the input table and the following
+intermediate result is produced:
+
+.nf
+
+NAME SEX TITLE
+ANY M Astronomer
+ANY F Astronomer
+
+.fi
+The rules file is searched again, and now the first rule matches the
+first row and the second rule matches the second row. So the following
+result is produced when these two rules are applied:
+.nf
+
+NAME SEX TITLE
+Tom M Astronomer
+Dick M Astronomer
+Harry M Astronomer
+Mary F Astronomer
+Jane F Astronomer
+
+.fi
+The rules file is searched again, and because no matches are found,
+the results are written to the output table.
+
+The above example shows some of the syntax of the rules file. The
+target and action parts of a rule are separated by the symbol "=>" and
+the entire rule is terminated by a semicolon. Unlike the above
+example, a rule need not be contained on a single line; it can be
+split among as many lines as desired, since the semicolon marks the
+end of the rule. The amount of white space used is also optional,
+symbols and identifiers may be run together or separated by blanks,
+tabs, and blank lines. Comments may be placed on any line; they begin
+with the "#" character and run to the end of the line. The different
+conditions in the target part of a rule are separated by the symbol
+"&&". Each condition consists of a column name and a column value
+separated by an equals sign. The different results in the action part
+of a rule are separated by the symbol "||". Each result consists of a
+set of column names and values separated by equals signs. If there is
+more than one column name and value in the result, the different
+name/value pairs are separated by "&&" symbols. An example of a rule
+with all these syntax elements is:
+.nf
+
+TARGET = ANY && OBSERVER = ANY => # Two conditions
+ TARGET=M31 && OBSERVER = HUBBLE || # First result
+ TARGET='OMEGA CENT' && OBSERVER = STRUVE ; # Second result
+
+.fi
+Notice that in the above example that an identifier containing a blank
+can be used if the identifier is enclosed in quotes. Double quotes
+could also have been used. Case is significant in an identifier. If a
+syntax error is detected in a rules file or a column is named which
+does occur in the input table, the task is terminated with a syntax
+error. The error message contains the line and line number where the
+error was detected and a brief message indicating the type of error.
+
+This task can also be used to process more than one table by using file
+name templates for the 'input' and 'output' parameters instead of file names.
+Because processing each table takes a relatively long time, the
+parameter 'verbose' can be set to "yes" so that the name of each table
+will be displayed when it is processed.
+.ih
+PARAMETERS
+.ls input [file name template]
+Name of a table, or list of tables, used as input to the task
+.le
+.ls output [file name template]
+Name of a table, or list of tables, to be produced as output to the task. The
+number of input and output tables must be equal.
+.le
+.ls rbase [file name]
+The file containing the rules used to expand the tables.
+.le
+.ls (debug = "") [file name]
+The file containing the debugging output. If the file name is blank or null,
+no debugging output is produced. When creating a set of rules, the output
+produced by this task is not always what you expect. Turning on the debugging
+output prints all the intermediate rule expansions to the designated file
+as an aid in debugging the set of rules.
+.le
+.ls (verbose = no) [boolean]
+Display the names of the input and output tables on the terminal screen (i.e.,
+STDOUT) after each file is processed?
+.le
+.ih
+EXAMPLES
+1. Expand the table 'example' into 'example_2' using the rules in
+'xrules.txt':
+
+.nf
+tt> texpand example.tab example_2.tab xrules.txt
+.fi
+
+2. Expand a set of fos tables using the rules in 'fosrules.txt':
+
+.nf
+tt> texpand y*.tab y*%%_2%.tab fosrules.txt verbose+
+.fi
+.ih
+BUGS
+The task cannot expand tables with boolean columns.
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+.endhelp
diff --git a/pkg/utilities/nttools/doc/thedit.hlp b/pkg/utilities/nttools/doc/thedit.hlp
new file mode 100644
index 00000000..9a3b2a2f
--- /dev/null
+++ b/pkg/utilities/nttools/doc/thedit.hlp
@@ -0,0 +1,208 @@
+.help thedit Feb2002 ttools
+.nj
+.ih
+NAME
+thedit -- Edit or view keyword values in tables.
+.ih
+USAGE
+thedit table keywords value
+.ih
+DESCRIPTION
+This table header editor can be used to add, delete, edit,
+or just print the values of table header keywords.
+
+Although this task was based on 'hedit',
+there are significant differences.
+The 'add', 'verify', and 'update' parameters of 'hedit'
+are not included in 'thedit'.
+If a specified keyword does not already exist,
+then it will be added
+(equivalent to add=yes in 'hedit').
+If a keyword does not exist,
+and the value expression is ".",
+a warning will be printed
+('hedit' is silent in this case).
+
+Such parameters as the number of rows or columns in the table
+are stored differently in FITS, STSDAS, and text tables.
+The following special "keywords" can be used
+to reference such information regardless of table type.
+These may be used in the 'keywords' parameter when value=".",
+or they can be used in the 'value' parameter as part of an expression.
+
+.nf
+ i_table string table name (may include extension ID)
+ i_file string name of the file containing the table
+ i_ctime string file modification (or creation) time
+ i_nrows int number of rows in the table
+ i_ncols int number of columns in the table
+ i_npar int number of keywords in the table header
+ i_type string table type
+.fi
+
+'thedit' supports two of the special operands
+that are available in 'hedit': "$" and "$I".
+When 'value' is an expression,
+"$" gives the value of the current keyword.
+"$I" is equivalent to "i_table",
+the name of the current table.
+"$I" can be used as a keyword or as part of an expression.
+.ih
+PARAMETERS
+.ls table [file name template]
+A list of tables for which keywords are to be edited or printed.
+If 'value' is ".", each table will be opened read-only;
+otherwise, each table will be opened read-write.
+.le
+.ls keywords [string]
+One or more keywords, separated by commas and/or blanks,
+which are to be added, modified, or printed.
+If the value expression (see 'value') is not ".",
+any keyword in 'keywords' that is not already present
+will be added to the header.
+
+Wildcards are supported; however,
+the "@filename" syntax is not supported.
+Do not use wildcard or other special characters
+if a keyword is to be added to the header.
+.le
+.ls value = "." [string]
+This is the value to be assigned to each keyword in 'keywords'.
+The special value "." means that
+the keywords should be printed rather than edited,
+and in this case the table will be opened read-only.
+If 'value' is not equal to ".",
+the same value will be assigned to all the keywords
+matching the template 'keywords'.
+
+In order to set a keyword value to "." or ",",
+specify the value as "\." or "\," respectively.
+(Note that if given on the command line,
+the quotes are required in this case.) Requiring "," to be escaped
+was added as protection against accidentally typing "," instead of ".".
+
+As with 'hedit',
+a general expression may be given for 'value'
+by enclosing the expression in parentheses.
+The expression may include constants and/or keyword names;
+it will be evaluated and then assigned to each keyword in 'keywords'.
+
+Note that if delete = yes, then 'value' will be ignored.
+.le
+.ls (delete = no) [bool]
+If delete = yes, the specified keywords will be deleted.
+All the keywords listed in 'keywords' will be deleted,
+for each table in 'table'.
+.le
+.ls (show = yes) [bool]
+Print a record of each edit operation?
+.le
+.ih
+EXAMPLES
+1. Display all the header keywords (except blank) in "example.tab".
+
+.nf
+ tt> thedit example.tab * .
+.fi
+
+2. Display only the special keywords for "timetag.fits[events]".
+
+.nf
+ tt> thedit timetag.fits[events] i_* .
+
+ timetag.fits[events],i_table = timetag.fits[events]
+ timetag.fits[events],i_file = timetag.fits
+ timetag.fits[events],i_ctime = "Wed 12:07:58 31-May-2000"
+ timetag.fits[events],i_nrows = 337824
+ timetag.fits[events],i_ncols = 6
+ timetag.fits[events],i_npar = 58
+ timetag.fits[events],i_type = "fits, binary"
+.fi
+
+3. Print all HISTORY keywords in "example.txt".
+
+.nf
+ tt> thedit example.txt history .
+.fi
+
+4. Add a new HISTORY keyword to "example.tab".
+
+.nf
+ tt> thedit example.tab history \
+ "('file name is ' // i_file) // '; number of rows = ' // str (i_nrows)"
+.fi
+
+5. Increment the value of COUNT.
+
+.nf
+ tt> thedit example.tab count "($ + 1)"
+.fi
+
+6. Delete all HISTORY and COMMENT keywords in "example.fits[1]".
+
+.nf
+ tt> thedit example.fits history,comment delete+
+.fi
+
+7. Evaluate a simple expression
+and assign the result to keyword WAVELEN.
+Keywords TCRVL1, TCDLT1, and NELEM
+are assumed to be already present in the header.
+
+.nf
+ tt> thedit example.fits wavelen "(tcrvl1 + tcdlt1 * nelem/2.)"
+.fi
+
+8. A keyword can be renamed by using a two-step process,
+first creating a new keyword with the old value, and then
+deleting the old keyword.
+Note that while this procedure does copy the value,
+the comment will be lost.
+(The "k" instruction in 'tupar' can also be used to rename a keyword.)
+
+.nf
+ tt> thedit example.tab newkey "(oldkey)"
+ tt> thedit example.tab oldkey delete+
+.fi
+
+9. The primary header or an image extension of a FITS file
+can also be opened as a table in order to access the keywords.
+
+.nf
+ tt> thedit o47s01kdm_raw.fits[0] rootname .
+ tt> thedit o47s01kdm_flt.fits[1] bunit "COUNTS/S"
+.fi
+
+10. This could have been a big mistake.
+
+.nf
+ tt> thedit abc.fits[1] * ,
+
+ ERROR: In order to set a keyword value to ',' you must use value='\,'
+.fi
+.ih
+BUGS
+Expressions are evaluated using EVEXPR,
+which does not support double precision.
+
+Header lines with keyword = ' ' cannot be displayed.
+
+The 'value' parameter is of type string,
+and 'thedit' interprets the value
+to determine what data type to use
+when writing the value to the table.
+This can fail when a value appears to be a number
+but really should be treated as a string.
+For example, a date and time could be written as "19940531:11515000".
+'thedit' would interpret this as hours and minutes (HH:MMss)
+and convert the value to 1994053. + 11515000./60.
+A workaround for this case is to use 'tupar' instead of 'thedit';
+use the "pt" instruction, meaning put a keyword of type text.
+.ih
+REFERENCES
+This task was written by Phil Hodge,
+based on the 'hedit' task.
+.ih
+SEE ALSO
+hedit, tupar
+.endhelp
diff --git a/pkg/utilities/nttools/doc/thistogram.hlp b/pkg/utilities/nttools/doc/thistogram.hlp
new file mode 100644
index 00000000..f8c0003e
--- /dev/null
+++ b/pkg/utilities/nttools/doc/thistogram.hlp
@@ -0,0 +1,152 @@
+.help thistogram Mar94 tables
+.nj
+.ih
+NAME
+thistogram -- Make a histogram of a table column.
+.ih
+USAGE
+thistogram intable outtable column
+.ih
+DESCRIPTION
+This task generates a histogram of the values in a column.
+The histogram may be written to STDOUT or to a table.
+If there is more than one table in the input list then a separate histogram
+is generated for each table.
+If there is more than one input table and the histogram of the values
+in all the tables combined is needed, then the tables should first be
+merged using the 'tmerge' task with the 'option' parameter set to "append".
+
+If x1 and x2 are the lower and upper limits of a particular bin,
+a value X will be included in the bin if x1 <= X < x2.
+Note that this also applies to the upper limit ('highval') of the last bin.
+
+There are six interrelated parameters
+having to do with the number of bins, bin width, and bin locations.
+Any number of these may be specified as long as the values are consistent.
+As a minimum, only one value is required, either 'nbins' or 'dx'.
+The task computes what it doesn't have
+based on the parameters that were specified,
+or based on the minimum and maximum data values
+in the table column if necessary.
+If the minimum (maximum) column data value is used,
+that value will normally be reduced (increased) a bit
+before being used as 'lowval' ('highval')
+to ensure that the value is included in the range.
+The relationships between the parameters is as follows:
+
+.nf
+ dx = (highval - lowval) / nbins
+ dx = (chigh - clow) / (nbins - 1)
+ clow = lowval + dx / 2
+ chigh = highval - dx / 2
+.fi
+.ih
+PARAMETERS
+.ls intable [file name template]
+A list of input tables.
+A histogram will be generated for one column in the table;
+the same column name is used for each table in the list.
+The name of the column is specified using the 'column' parameter,
+.le
+.ls outtable = STDOUT [file name template]
+Output tables or STDOUT.
+If the value of this parameter is "STDOUT"
+then the histogram will be written to the standard output
+preceded by a header line (beginning with "#")
+that gives the number of rows included in the histogram
+and the name of the table.
+If 'outtable' is passed a file name,
+then the number of names must match the number of file names in 'intable',
+and the histogram of each input table
+will be written to an output table of the specified name.
+.le
+.ls column [string]
+Column name in input tables that will be used to generate the histogram.
+Only the values in the column with this name will be used.
+The same column name is used for each input table.
+.le
+.ls (nbins = 100) [integer, min=1]
+Number of bins in the histogram.
+Normally either 'nbins' or 'dx' (or both) must be given.
+You could also give both 'lowval' and 'clow',
+or both 'chigh' and 'highval',
+since the bin width can be computed from these.
+.le
+.ls (lowval = INDEF) [real]
+Lower limit for histogram.
+Values below 'lowval' will not be used in generating the histogram.
+If 'lowval = INDEF', then the minimum value in the table column will be used.
+.le
+.ls (highval = INDEF) [real]
+Upper limit for histogram.
+Values equal to or greater than 'highval' will not be used in generating
+the histogram.
+If 'highval = INDEF', then the maximum value in the table column will be used.
+.le
+.ls (dx = INDEF) [real]
+Bin width.
+.le
+.ls (clow = INDEF) [real]
+Value at the center of the first bin.
+.le
+.ls (chigh = INDEF) [real]
+Value at the center of the last bin.
+.le
+.ls (rows = -) [string]
+Range of rows to use for generating the histogram.
+The default "-" means that all rows are used.
+(Type "help xtools.ranges" for more information.)
+.le
+.ls (outcolx = value) [string]
+Column name for bin centers.
+If the output is written to a table rather than to STDOUT, then 'outcolx'
+is the column name containing the bin centers.
+This column will be double precision.
+.le
+.ls (outcoly = counts) [string]
+Column name for histogram values.
+If the output is written to a table then 'outcoly' is the column name
+containing the number of counts in the bin.
+This column will be of integer data type.
+.le
+.ih
+EXAMPLES
+1. Generate a histogram of the values in the 'flux' column in every table
+whose name begins with "hr"; put all the histograms in the ASCII file
+'hist.lis'.
+
+.nf
+ tt> thistogram hr*.tab STDOUT flux > hist.lis
+.fi
+
+2. Generate the same histograms as in the previous example, but put the
+results in tables rather than displaying them on the terminal screen.
+One output file is produced for each input table; for example,
+the histogram for an input table 'hr465.tab' would be put in 'hr465h.tab'.
+
+.nf
+ tt> thistogram hr*.tab hr*%%h%.tab flux
+.fi
+
+3. Plot the histogram of column 'V' in 'bs.tab':
+
+.nf
+ tt> thistogram bs STDOUT V | sgraph (crvstyle="pseudohist")
+.fi
+
+4. Plot the same histogram as in the previous example,
+but set the spacing between bins to be 0.1.
+
+.nf
+ tt> thistogram bs STDOUT V nbins=INDEF dx=0.1 | \\
+ >>> sgraph (crvstyle="pseudohist")
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+.ih
+SEE ALSO
+ranges
+.endhelp
diff --git a/pkg/utilities/nttools/doc/thselect.hlp b/pkg/utilities/nttools/doc/thselect.hlp
new file mode 100644
index 00000000..7cabe98d
--- /dev/null
+++ b/pkg/utilities/nttools/doc/thselect.hlp
@@ -0,0 +1,90 @@
+.help thselect Jul2000 ttools
+.nj
+.ih
+NAME
+thselect -- Print table keyword values.
+.ih
+USAGE
+thselect table keywords expr
+.ih
+DESCRIPTION
+This task was based on 'hselect',
+and it behaves in a very similar manner,
+except that it works on tables rather than images.
+
+Keyword values will be printed to the standard output,
+one line per input table,
+with the values separated by tabs.
+String values that contain whitespace will be enclosed in quotes.
+.ih
+PARAMETERS
+.ls table [file name template]
+A list of tables for which keywords are to be printed.
+These will be opened read-only and will not be modified.
+.le
+.ls keywords [string]
+One or more keywords, separated by commas and/or blanks.
+The special keywords such as "i_table"
+that are supported by 'thedit' can also be used with 'thselect'.
+
+For each input table,
+the values of these keywords in the current input table will be printed,
+if 'expr' is a true expression for the current table.
+Any keyword that is not found will be silently ignored.
+
+Wildcards are supported; however,
+the "@filename" syntax is not supported.
+.le
+.ls expr = "yes" [string]
+This is a boolean expression
+to be evaluated for each table in the list.
+The default value may be used to unconditionally print keyword values.
+
+The expression may include constants and/or keyword names.
+.le
+.ih
+EXAMPLES
+1. Compare 'thselect' with 'thedit' for displaying a single keyword value.
+
+.nf
+ tt> thselect timetag.fits[events,7] rootname yes
+
+ O57P03030
+
+ tt> thedit timetag.fits[events,7] rootname .
+
+ timetag.fits[events,7],ROOTNAME = O57P03030 / rootname of the obser
+ vation set
+.fi
+
+2. Compare i_file with i_table for a FITS table
+($I and i_table are equivalent).
+
+.nf
+ tt> thselect timetag.fits[events,7] i_file,i_table yes
+
+ timetag.fits timetag.fits[EVENTS,7]
+.fi
+
+3. Find all FITS files with DETECTOR = 'CCD' in the primary header.
+Since the primary header of a FITS file can be opened
+either as an image or as a table,
+either 'hselect' or 'thselect' could be used for this example.
+
+.nf
+ tt> thselect *.fits[0] $I "detector == 'CCD'"
+
+ h1v11148o_1dx.fits[0]
+ h4s13500o_1dx.fits[0]
+ i1c1615po_1dx.fits[0]
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Phil Hodge,
+based on 'hselect'.
+.ih
+SEE ALSO
+hselect, thedit
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tinfo.hlp b/pkg/utilities/nttools/doc/tinfo.hlp
new file mode 100644
index 00000000..4c712fbe
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tinfo.hlp
@@ -0,0 +1,125 @@
+.help tinfo Jun1999 tables
+.nj
+.ih
+NAME
+tinfo -- Display information about a table.
+.ih
+USAGE
+tinfo table
+.ih
+DESCRIPTION
+This task is used to display information about a table.
+This information includes
+such things as the number of rows and columns.
+The output is written to STDOUT by default.
+The first line of output for each table in the input list is the table
+name preceded by a # sign.
+The values for the last table in the list are also put into parameters
+for the 'tinfo' task so that other tasks in a script may use the values.
+
+The parameters 'nrows', 'ncols', 'npar', 'rowlen', 'rowused', 'allrows',
+'maxpar', 'maxcols', 'tbltype', 'subtype' and 'tblversion'
+are output parameters.
+Since they are set rather than read by 'tinfo',
+any value assigned by the user will be overwritten.
+.ih
+PARAMETERS
+.ls table [file name template]
+A list of tables for which size information is to be produced.
+.le
+.ls (ttout = yes) [boolean]
+Display information on the terminal screen as it is being placed into
+parameters? Setting 'ttout = no' will cause information to be placed
+only into task parameters.
+.le
+.ls (nrows) [integer]
+The number of rows written to the table.
+This and all subsequent parameters are output task parameters;
+that is, they are written by the 'tinfo' task.
+.le
+.ls (ncols) [integer]
+The number of columns in the table.
+.le
+.ls (npar) [integer]
+The number of header parameters in the table.
+.le
+.ls (rowlen) [real]
+For a row-ordered table,
+'rowlen' is the amount of space allocated for each row in the table file.
+The unit of 'rowlen' is the size of a single-precision real number.
+
+This is only relevant for row-ordered STSDAS format tables.
+.le
+.ls (rowused) [real]
+'rowused' is the amount of the row length ('rowlen')
+that has actually been used
+by the columns that have been defined,
+in units of the size of a real number.
+For example, if a table contains three columns
+with data types integer, real and double precision,
+then 'rowused' would be four.
+If the table contains only one column of data type short,
+then 'rowused' would be 0.5.
+
+This is only relevant for row-ordered STSDAS format tables.
+.le
+.ls (allrows) [integer]
+The number of allocated rows.
+This is relevant only for column-ordered STSDAS format tables.
+.le
+.ls (maxpar) [integer]
+The space allocated for header parameters.
+.le
+.ls (maxcols) [integer]
+The space allocated for column descriptors.
+.le
+.ls (tbltype) [string]
+The table type, currently either "stsdas", "fits" or "text".
+"stsdas" is a machine dependent binary format,
+the default .tab format.
+"fits" means that the table is a TABLE or BINTABLE extension
+in a FITS file.
+"text" is an ASCII file in tabular format.
+See also 'subtype'.
+.le
+.ls (subtype) [string]
+For FITS tables the subtype can be either
+"ascii" (a TABLE extension) or "binary" (a BINTABLE extension).
+For text tables the subtype can be either
+"simple" or "explicit column definitions".
+The latter subtype means there are column definition lines in the file,
+in the format: "#c column_name datatype print_format units".
+A simple text table has column names c1, c2, etc., and no units.
+For STSDAS format tables
+the subtype will be either "row ordered" or "column ordered",
+which indicates the way the elements are stored in the table file.
+.le
+.ls (tblversion) [integer]
+The version code is an integer that identifies the version of
+the tables package that created or last modified the table.
+For STSDAS tables, the version code is stored in the table file;
+for other formats this parameter is just
+the current tables version code number.
+This number is zero for 'stsdas' and 'tables' versions 1.2.3 and earlier,
+the number is one for versions 1.3 through 1.3.3,
+the number is two beginning 1995 March 6,
+and the number is three beginning 1998 April 14.
+.le
+.ih
+EXAMPLES
+1. Get size information about the file 'm87pol.tab',
+but do not print the information to STDOUT,
+just put the values into parameters.
+
+.nf
+ tt> tinfo m87pol ttout=no
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+.ih
+SEE ALSO
+tlcol
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tintegrate.hlp b/pkg/utilities/nttools/doc/tintegrate.hlp
new file mode 100644
index 00000000..9ea9f081
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tintegrate.hlp
@@ -0,0 +1,97 @@
+.help tintegrate Jan96 tables
+.ih
+NAME
+tintegrate -- Calculate the integral of one table column with
+respect to another.
+.ih
+USAGE
+tintegrate table integrand independent
+.ih
+DESCRIPTION
+The program evaluates the integral of the column name passed to
+'integrand' with respect to
+the column passed to 'independent' using the simple trapezoidal rule.
+The column passed to 'independent' must have values
+sorted in ascending order.
+INDEF values in either column are ignored, and there must be at least
+two good points common to both columns.
+The result is written to STDOUT and also recorded as a task parameter
+'integral'.
+
+If the 'independent' parameter is null or blank,
+the values in the 'integrand' column will simply be added up.
+Note that this is not exactly the same as the trapezoidal rule
+for integrating over row number. (A row number column
+can be created using 'tcalc'.) When integrating over a column
+that contains the row numbers,
+'tintegrate' adds together all rows except the first and last
+with unit weight;
+the first and last are included with a weight of one half.
+.ih
+PARAMETERS
+.ls table [file name]
+The input table.
+.le
+.ls integrand [string]
+Column name whose contents will be the integrand.
+.le
+.ls independent [string]
+Column name whose contents will be the independent variable;
+the values in this column must be increasing with row number.
+If 'independent' is null,
+then 'tintegrate' will just sum the values in the 'integrand' column.
+.le
+.ls (integral) [real]
+The result returned by the task.
+This is an output parameter; it is not directly changed by the user.
+.le
+.ls (ptsused) [integer]
+The number of points used in calculating the integral.
+This is also an output parameter and is not specified by the user.
+.le
+.ih
+EXAMPLES
+1. Calculate the integral of flux over wavelength,
+printing the result to STDOUT
+(and also storing it in the 'integral' parameter).
+
+.nf
+tt> tintegrate intab flux lambda
+ integral= 0.8752311663155779 using 401 points
+.fi
+
+2. Sum the values of flux, rather than integrating over wavelength.
+
+.nf
+tt> tintegrate intab flux ""
+ integral= 30.32557976245881 using 401 points
+
+as an alternative:
+
+tt> tstat intab flux
+# civ flux
+# nrows mean stddev median min max
+ 401 0.07562488719 0.171107 -0.0381 -0.72729 0.22527
+tt> =0.07562488719 * 401
+30.32557976319
+
+.fi
+
+3. Integrate the flux over row number.
+This is the same as summing the flux except for the first and last rows.
+
+.nf
+tt> tcalc intab row rownum datatype="real" colfmt="%8.1f"
+tt> tintegrate intab flux row
+ integral= 30.34466478228569 using 401 points
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by David Giaretta.
+.ih
+SEE ALSO
+tcalc
+tstat
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tjoin.hlp b/pkg/utilities/nttools/doc/tjoin.hlp
new file mode 100644
index 00000000..45d2dcc2
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tjoin.hlp
@@ -0,0 +1,120 @@
+.help tjoin Apr99 tables
+.ih
+NAME
+tjoin -- Combine two tables based on equal values in common columns
+.ih
+USAGE
+tjoin intable1 intable2 outtable column1 column2
+.ih
+DESCRIPTION
+This task combines two tables into a new table on the basis of one or
+more common columns. Two rows from the input tables are combined to
+form a row of the output table whenever the values in the common
+columns are equal. If a row in one of the input tables matches several
+rows in the other input table, all combinations of the rows are placed
+in the output table. Null table elements are never matched. Tables
+can be joined on row number as well as on column by setting the column
+name to "row".
+
+This task has three hidden parameters, 'extrarows', 'tolerance', and
+'casesens'. By default, if a row in one of the input tables does not
+match any row in the other input table, it is not placed in the output
+table. However, if the parameter 'extrarows' is set to 'first', rows
+in the first table that are unmatched are added to the output table
+and if 'extrarows' is set to 'both', unmatched rows from both input
+tables are added to the output table.
+
+The task parameter 'tolerance' is a comma separated list of
+values. The number of values should either equal to the number of join
+columns or one. If only one value is supplied and there are more than
+one join column, the value is used for all columns. If the difference
+between two column values is less than or equal to the corresponding
+value of 'tolerance', the values are considered equal and their
+respective rows are placed in the output table.
+
+If 'casesens = no', the case of a string is ignored when testing for
+equality. 'tolerance' must be set to zero when comparing string or
+boolean columns.
+
+If a value of 'tolerance' is nonzero, the output table will contain the
+corresponding join columns from both tables. If a value of
+'tolerance' is zero, the output table will contain a single join column,
+as both values are identical. If a column name in the first input
+table is the same as a column name in the second input table, this
+task tries to create a unique name by appending "_1" to the first name
+and "_2" to the second name. If the task cannot create a unique name
+in this way, it stops with an error.
+.ih
+PARAMETERS
+.ls intable1 [file name]
+First input table.
+.le
+.ls intable2 [file name]
+Second input table.
+.le
+.ls outtable [file name]
+Output table. This is the join of the two input tables.
+.le
+.ls column1 [string]
+Names of the common columns in the first table. If there is more than
+one column name, the names should be separated by commas. If a column
+name is "row", the join is done on row number instead of the value of
+a column. This only works if there is not column named "row" in the
+table.
+.le
+.ls column2 [string]
+Comma separated list of names of the common columns in the second
+table. The number of names must match the number of names in column1.
+The name may be "row", in which case the join is done on row number.
+.le
+.ls (extrarows = "neither") [string, allowed values: neither|first|both]
+This parameter controls whether unmatched rows are added to the output
+table. If it is set to 'neither', unmatched rows are not added. If it
+is set to 'first', unmatched rows from the first table are added. If
+it is set to 'both', unmatched rows from both tables are added. When
+unmatched rows are added to the output table columns in the output
+table derived from the other table have their values left undefined.
+.le
+.ls (tolerance = "0.0") [string]
+Tolerance used in testing for equality between common columns. The
+values must be greater than or equal to zero. If there is more than
+one common column, this parameter may be a comma separated list of
+values. In this case, the number of tolerance values must equal the
+number of common columns or be one. If there is only one tolerance
+value, the same value is used for all columns.
+.le
+.ls (casesens = yes) [boolean]
+Is case important in testing equality of strings?
+If set to "yes", the test for equality is case sensitive.
+.le
+.ih
+EXAMPLES
+1. Combine a table of star positions and a table of star magnitudes to create
+a star catalog. The star name is not case sensitive:
+
+.nf
+tt> tjoin starpos.tab starmag.tab starcat.tab name name case-
+.fi
+
+2. Create a table of all spectral lines that match a set of reference
+wavelengths within 10 angstroms:
+
+.nf
+tt> tjoin spectrum.tab reference.tab lines.tab WAVE WAVE tol=10.
+.fi
+
+3. Combine a phone list with an address list where the name is stored
+in two columns, "last" and "first".
+
+.nf
+tt> tjoin phone.tab address.tab output.tab LAST,FIRST LAST,FIRST
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+tselect, tproject, tproduct
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tlcol.hlp b/pkg/utilities/nttools/doc/tlcol.hlp
new file mode 100644
index 00000000..c9bd9c94
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tlcol.hlp
@@ -0,0 +1,75 @@
+.help tlcol May2000 tables
+.nj
+.ih
+NAME
+tlcol -- Display column information.
+.ih
+USAGE
+tlcol table
+.ih
+DESCRIPTION
+This task is used to list column information for a table. The output is
+written to STDOUT, which may be redirected to a file. There will be one line
+of output for each column in the table, and each output line may contain the
+column name, data type, print format, and units.
+The first line of output for each table in the input list is the table
+name preceded by a # sign.
+
+The output from this task may be used as input to various tasks such
+as 'tcreate', 'tprint', and 'tproject'.
+.ih
+PARAMETERS
+.ls table [file name template]
+A list of tables for which column info is to be printed.
+.le
+.ls (nlist = 4) [integer, min=1, max=4]
+The number of items to list.
+The output will consist of 'nlist' columns,
+one line for each column that is defined in the table.
+The items listed out are column name (displayed for all 'nlist' values),
+data type (displayed if 'nlist' is 2 or higher),
+display format (if 'nlist' is 3 or higher),
+units (if 'nlist' is 4).
+If 'nlist = 1', only the column name will be displayed;
+the output list may be edited and used as input to
+'tprint', 'tdump,' 'tedit', 'tread', 'tproject', or 'tquery'.
+The default of 4 can be used to generate
+a column-description file for the 'tcreate' task.
+
+If a column contains an array of values at each row,
+rather than just a single element,
+the array size is shown in square brackets appended to the data type.
+.le
+.ih
+EXAMPLES
+1. Display the names, data types, print formats, and units of all the
+columns in the table "example.tab":
+
+.nf
+ tt> tlcol example.tab
+.fi
+
+2. Print (using the 'tprint' task) specific columns:
+.nf
+
+ tt> tlcol example.tab nlist=1 >colnames.lis
+ tt> edit colnames.lis
+ (Rearrange the column names and perhaps delete some of them.)
+ tt> tprint example.tab columns=@colnames.lis
+
+3. Create a new table based on the columns in "example.tab":
+
+ tt> tlcol example.tab nlist=4 >colnames.lis
+ tt> edit colnames.lis
+ (Delete or modify some column descriptions and/or add new ones.)
+ tt> tcreate ex2.tab cdfile=colnames.lis ...
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+.ih
+SEE ALSO
+tinfo, tcreate, tdump
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tlinear.hlp b/pkg/utilities/nttools/doc/tlinear.hlp
new file mode 100644
index 00000000..66817fef
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tlinear.hlp
@@ -0,0 +1,127 @@
+.help tlinear Aug2000 tables
+.ih
+NAME
+tlinear -- Fit a linear function to one or two table columns by linear
+regression.
+.ih
+USAGE
+tlinear intable outtable xcol ycol
+.ih
+DESCRIPTION
+This task generates fitted Y values and their residuals in two columns.
+These columns may be written to an output table, but cannot be written
+to STDOUT--only the fit parameters can be written to STDOUT.
+If there is more than one table in the input list then a separate fit
+is made for each table.
+
+When a column of weights is used (see 'wcol'),
+the weights will be applied when computing the
+coefficients of the fit (a, b),
+their standard deviations (siga2, sigb2),
+and chi squared (chi2),
+where the names in parentheses are the headings in
+the output printed to STDOUT.
+If any row has a weight that is exactly zero,
+that row will not be counted in the "pts in fit" value.
+The weights will NOT be used when computing
+the RMS of the residuals and mean of the residuals
+(residual rms, residual mean);
+these are unweighted averages
+except that rows with exactly zero weight will not be included.
+.ih
+PARAMETERS
+.ls intable [file name template]
+A list of input tables containing the columns to be fit.
+A fit will be made of the columns specified by the 'xcol' and 'ycol'
+parameters. If more than one file name is passed to 'intable', all of
+the files must use the same column names.
+.le
+.ls outtable = STDOUT [file name template]
+File names for creating output files, or STDOUT to send output to the screen.
+If the value of this parameter is "STDOUT" then the parameters of the fit will
+be written to STDOUT preceded by a header line (beginning with #) in tabular
+form.
+If 'outtable' is not "STDOUT" then the number of file
+names must match the number
+of names in 'intable', and the fitted Y values and residuals will be written
+to an output table with the specified name. The parameters of the fit will
+be written to the table header.
+.le
+.ls xcol [string]
+Column name in the input tables to be fit.
+The values in this column will be fit for the X axis.
+(The same column name is used for each input table.) If a name is not specified
+for the X values then row number is used. The values in the 'xcol' column will
+be copied to 'outtable' unless the output is being directed to STDOUT.
+.le
+.ls ycol [string]
+Column name in the input tables containing value to be fit for the Y axis.
+(The same column name is used for each input table.) Values in 'ycol' will
+be copied to 'outtable' unless 'outtable = STDOUT'.
+.le
+.ls (wcol) [string]
+Column name in 'intable' that contains weight values for X and Y.
+(The same column name is used for each input table.) If no column
+name is passed to either the 'wcol' or 'scol' parameters, then a weight
+of 1. is used. The value of the 'wcol' column is copied to 'outtable' unless
+'outtable = STDOUT'.
+.le
+.ls (scol) [string]
+Column in 'intable' containing the standard deviation of X and Y.
+The X and Y values are weighted by the values in 'scol'
+as the reciprocal of the values squared. (The same column name is used for each
+input table.) If no value is passed to 'wcol' or 'scol', then
+a weight of 1. is used. This task can accept either a weight value or a
+standard deviation value, but not both. If both 'wcol' and 'scol' are
+specified, then the weight column (i.e., 'wcol') will be used.
+The value in the 'scol' column is written to 'outtable' unless 'outtable'
+= STDOUT.
+.le
+.ls (rows = "-") [string]
+Range of rows to use for fitting the data.
+The default "-" means that all rows are used.
+(Type "help xtools.ranges" for more information.)
+.le
+.ls (outcoly = "yfit") [string]
+Column name for fitted Y values.
+This parameter is not used if 'outtable' = STDOUT.
+This column will be double data type.
+.le
+.ls (outcolr = "yres") [string]
+Name of the column to contain residuals.
+This parameter is ignored if 'outtable' = STDOUT.
+This column will be of double data type.
+.le
+.ih
+EXAMPLES
+1. Fit the values in the "flux" column in every table whose name begins with
+"hr"; put all parameters of the fits in the ASCII file "fit.lis".
+
+.nf
+ tt> tlinear hr*.tab STDOUT "" flux > fit.lis
+.fi
+
+2. Generate the same fits as in the previous example, but put the
+results in tables, one output for each input table. For example,
+the fitted Y values and
+residuals for an input table named "hr465.tab" would be put in "hr465h.tab".
+
+.nf
+ tt> tlinear hr*.tab hr*%%h%.tab "" flux
+.fi
+
+3. Fit the values in the "flux" column as a function of the values in the
+"wavelength" column and write all the parameters of the fit to STDOUT.
+
+.nf
+ tt> tlinear hr*.tab STDOUT wavelength flux
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Betty Stobie.
+.ih
+SEE ALSO
+ranges
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tmatch.hlp b/pkg/utilities/nttools/doc/tmatch.hlp
new file mode 100644
index 00000000..20b5abe4
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tmatch.hlp
@@ -0,0 +1,225 @@
+.help tmatch Jan1999 tables
+.ih
+NAME
+tmatch -- Find closest match between rows in two tables
+.ih
+USAGE
+tmatch (input1, input2, output, match1, match2, maxnorm)
+.ih
+DESCRIPTION
+This task combines rows from two tables into one. Rows are combined by
+looking at each row in the first table and finding the row in the
+second table whose match columns are closest to those in the first.
+The distance between two rows is defined in the usual way to be the
+square root of the sum of the squares of the difference between the
+corresponding match columns. Rows are only written to the output table
+if the distance between them is less than the distance specified by
+maxnorm. This task converts match column units to degrees for the
+purpose of computing the distance if the column units are recognized
+angular units (seconds, minutes, degrees, hours, or radians or any
+abbreviation of these). If the column units are blank or some
+unrecognized string, no conversion is done. Thus, if the match column
+is in some recognized angular units, maxnorm should be specified in
+degrees.
+
+Columns named by the parameters 'incol1' and 'incol2' will be copied to
+the output table. If these parameters are left blank, all columns will
+be copied to the output table. Columns will have the same name in the
+output table as in the input table, except that columns with the same
+name in both input tables will have the suffix "_1" and "_2" added to
+indicate which table they were copied from.
+
+This task optionally allows you to supply a set of weighting factors
+that are multiplied by the difference between corresponding match
+columns when computing the distance. These factors can be used to
+supply units conversion when column units information is missing from
+the input table or as a way to weight information from columns
+containing distinct information. If factors are supplied, any column
+units information is ignored. If the factors are left bank, they are
+ignored and column units information is used to convert to degrees
+when possible.
+
+If the match columns contain spherical coordinates, parameter 'sphere'
+should be set to yes so that the distance on a sphere can be computed.
+If the match columns do contain spherical units, the first column
+should be the longitude column (such as right ascension) and the
+second column should be the latitude column (such as declination).
+Columns should also be in some recognized angular units, or a
+conversion factor should be supplied explicitly.
+
+The task optionally produces a diagnostic output file if a file name
+is supplied to parameter 'diagfile'. The diagnostic file contains the
+rows from the first table that were not matched, the cases where
+more than one row in the first table matched a single row in the
+second table, and the ten matched rows in the with the largest
+distance between them. Rows in the diagnostic output are identified by
+their table number and row number and optionally by the contents of
+the columns specified by the parameters 'nmcol1' and 'nmcol2'.
+
+This task differs from tjoin in two respects. First tjoin combines
+tables on the basis of a single column, while this task can combine
+tables based on multiple columns. Second, tjoin places every
+combination of rows matching within the specified tolerance in the output
+table, while this task only puts the closest match in the output table.
+.ih
+PARAMETERS
+.ls input1 [string]
+First input table name.
+.le
+.ls input2 [string]
+Second input table name.
+.le
+.ls output [string]
+Output table name.
+.le
+.ls match1 [string]
+A column template describing columns from the first table used to
+match the two tables. A column name template is a comma or whitespace
+list of strings. Each string may either be a column name a pattern
+containing wildcard characters which matches several column names. This
+parameter will also accept the name of a list file (preceded by the
+"@" character) containing column names to be matched.
+If the first non-white character in the template
+is the negation character (either "~" or "!"),
+all columns NOT appearing in the list will be matched.
+.le
+.ls match2 [string]
+A column name template describing columns from the second table used
+to match the two tables. This parameter follows the same format rules
+as 'match1'. The number of columns must equal those in 'match1'.
+.le
+.ls maxnorm min= 0.0, max=INDEF [real]
+The distance between two rows must be less than 'maxnorm' in order for
+them to match. Recognized angular units are converted to degrees
+before computing the distance. The recognized units are seconds,
+minutes, degrees, hours, radians, or any abbreviation of these.
+.le
+.ls (incol1 = " ") [string]
+A column name template describing the columns to be copied from the
+first input table to the output table. If this parameter is left blank
+(the default) all columns in the first input table will be copied to
+the output.
+.le
+.ls (incol2 = " ") [string]
+A column name template describing the columns to be copied from the
+second input table to the output table. If this parameter is left
+blank (the default) all columns in the second input table will be
+copied to the output.
+.le
+.ls (factor = " ") [string]
+A comma or white space separated list of numeric factors multiplied by
+the individual column differences when computing the distance between
+rows in the first and second tables. If this parameter is left blank
+(the default) conversion of angular units to degrees will be
+performed, but not other weighting will be performed. If a list of
+values is supplied, units conversion will NOT be performed, the
+supplied numeric factors will be used instead.
+.le
+.ls (diagfile = " ") [string]
+The name of the diagnostic output file. If the name is left blank (the
+default) no diagnostic output is produced. Diagnostic output can be
+sent to the terminal by setting this parameter to STDOUT or STDERR.
+The diagnostic output contains a list of rows that were not matched,
+cases where more than one row in the first table matched a single row
+in the second table, and the ten pairs of rows with the largest
+distance between them.
+.le
+.ls (nmcol1 = " ") [string]
+A column template describing the columns from the first table that are
+printed in the diagnostic output. The table and row number are always
+printed, if this parameter is not blank, the specified columns are
+also printed.
+.le
+.ls (nmcol2 = " ") [string]
+A column template describing the columns from the second table that are
+printed in the diagnostic output.
+.le
+.ls (sphere = no) [bool]
+If this parameter is set to yes, a correction appropriate for
+spherical coordinates will be applied to the first column
+difference. The correction is the cosine of the average of the two
+second column values. In order for this correction to be valid, the
+first column must contain the longitude component and the second
+column the latitude component. Units should be convertable to degrees
+or an explicit conversion factor should be supplied.
+.le
+.ih
+EXAMPLES
+1. Two star catalogs are being matched. They both have the following
+columns:
+
+.nf
+Name CH*12 %12s ""
+RA D %10.1h hours
+Dec D %10.0h degrees
+V R %7.2f ""
+B-V R %7.2f ""
+U-B R %7.2f ""
+.fi
+
+To find the best match between the catalogs within a ten arcsecond
+radius one would use the following command:
+
+.nf
+tt> tmatch catalog1.tab catalog2.tab match.tab \
+>>> ra,dec ra,dec 0:00:10 sphere+
+.fi
+
+The search radius can either be supplied in sexagesimal notation, as
+above, or in decimal degrees.
+
+2. Suppose the input catalogs did not contain units information, as
+would be the case if they were text files. The units conversion could
+then be supplied explicitly through the factor parameter:
+
+.nf
+tt> tmatch catalog1.tab catalog2.tab match.tab \
+>>> ra,dec ra,dec 0:00:10 factor=15,1 sphere+
+.fi
+
+3. Suppose we want the output table to only contain the name from the
+first catalog and get the rest of its information from the second
+catalog. This could be done with the following command:
+
+
+.nf
+tt> tmatch catalog1.tab catalog2.tab match.tab \
+>>> ra,dec ra,dec 0:00:10 incol1=name sphere+
+.fi
+
+4. To get diagnostic output from the task, use the following command:
+
+.nf
+tt> tmatch catalog1.tab catalog2.tab match.tab ra,dec ra,dec \
+>>> diag=diag.txt nmcol1=name nmcol2=name 0:00:10 sphere+
+.fi
+
+The following is a subset of the diagnostic output produced:
+
+.nf
+The following objects matched the same object:
+1:163 6601 GEM
+1:164 6601 GEM
+2:163 6601 GEM
+
+
+The following objects have the largest norms:
+Norm = 0.00253
+1:371 2319 SCO
+2:371 2319 SCO
+
+Norm = 0.00247
+1:368 2101 SCO
+2:368 2101 SCO
+.fi
+
+The number before the colon is the table number, the number after the
+colon is the row number, and the rest of the line is from the name
+column.
+.ih
+REFERENCES
+Written by Bernie Simon
+.ih
+SEE ALSO
+tjoin
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tmerge.hlp b/pkg/utilities/nttools/doc/tmerge.hlp
new file mode 100644
index 00000000..301d7802
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tmerge.hlp
@@ -0,0 +1,231 @@
+.help tmerge Jun1999 tables
+.nj
+.ih
+NAME
+tmerge -- Merge two tables, or append one to the other.
+.ih
+USAGE
+tmerge intable outtable option
+.ih
+DESCRIPTION
+This task is used to either merge or append tables,
+depending on the option selected by the 'option' parameter.
+The data type of each column is defined by
+the first table in the input list containing that column.
+If subsequent tables use the same column name,
+then data are converted to the type defined by the first table.
+Problems may occur when numerical data are written to
+a boolean column or a narrow character column.
+
+The "merge" option is normally used for tables containing few,
+if any, common columns.
+When the user selects "merge",
+an output table is created containing as many columns
+as there are unique column names in all the input tables.
+(But see the description of the 'allcols' parameter.)
+The output table will have as many rows as the largest
+number of rows in the input tables.
+The input tables are read in order,
+with all values being placed into the output table.
+If different input tables have the same column names
+then the first values put into the output table
+will be overwritten by the later table values.
+For example, if the two input tables both have the column name "X_VAL",
+then for each row number,
+the values written to the output table
+will be taken from the second input table.
+See below regarding text tables.
+
+On the other hand, if the "append" option is selected, all rows of
+the first input table are written to the output table, followed by all
+rows of the second table, and so on, until all input tables are written
+to the output table.
+The total number of output rows will be the sum
+of the numbers of rows in the input tables.
+Columns with the same name in different
+input tables will be written into the same output column, but no data
+will be overwritten because they are put into different rows.
+The "append" option would normally be used for tables that have all
+the same columns.
+
+An input table may have no rows.
+Such a table may be used as the first input table
+to control the order and definitions of columns in the output table.
+
+Header parameters are appended,
+and parameters with the same keyword name
+in different input tables are overwritten in the output file,
+except for history and comment keywords.
+
+Care must be taken with text tables.
+It is very likely that you would want
+'allcols = yes' if 'option = merge' and
+'allcols = no' if 'option = append'.
+See the description of the 'allcols' parameter for details.
+If the output table is a text file,
+the line length may not be longer than 4095 characters,
+which is a limitation for any text table.
+
+Column units are not checked.
+If columns with the same name have different units
+in two different input tables,
+the merged (or appended) data are likely to have mixed units.
+In addition, the column definition is taken from the first input table,
+but some and perhaps all of the data would come from the second input table,
+so the units in the output column definition would not be correct
+for those data.
+.ih
+PARAMETERS
+.ls intable [file name template]
+Names of the tables to be merged or appended. This parameter will take
+either a file name template describing several input tables, and may include
+wildcard characters, or it will take the name of a list file preceded by the
+"@" character; in the latter case the list file contains a list of file names
+with each file name on a separate line. Wildcard characters should not be
+used for file name extensions because files other than tables will be
+processed, causing the program to crash. For example, if the directory
+contains files "table.tab" and "table.lis", the command "tmerge tab*" would
+open both files.
+.le
+.ls outtable [file name]
+The name of the output table.
+.le
+.ls option = "merge" [string]
+allowed values: merge | append
+
+Either merge the columns in each row of each input table--overwriting
+previous values--or append files to each other.
+See also 'allcols' below.
+(These options are discussed in greater detail in the DESCRIPTION section.)
+.le
+.ls (allcols = yes) [boolean]
+Define output table columns using columns from
+all input tables?
+
+If 'allcols = no', the output table will contain
+only those columns defined in the first input table.
+If 'allcols = yes', the output table will contain
+all columns from all input tables.
+If 'option = merge', then it is likely that 'allcols' should be set to yes.
+
+For input tables that are simple text tables
+(i.e. that do not contain explicit column definitions),
+the 'allcols' parameter serves an additional function.
+When 'allcols = yes' the name of each column
+in a simple text table is changed
+to be "c" followed by the column number in the output table.
+This is intended to make the column names unique
+in order to allow merging text tables
+without having the columns overwrite previously written columns.
+Since the column names in simple text tables are just c1, c2, etc.,
+columns would overwrite previously written columns in the output
+if the names were not modified.
+If all input tables are simple text tables,
+and the output is also a text table,
+the new names will be discarded,
+so the net effect of this scheme is just to preserve all input data.
+If the output is a binary table, however,
+the modified column names will be retained.
+If the modified column names turn out not to be unique,
+a warning message will be printed.
+.le
+.ls (tbltype = "default") [string, allowed values: default | row |
+column | text]
+
+This parameter specifies the table type.
+Setting 'tbltype' to "row" or "column" results in an stsdas binary table,
+the contents of which may be either row ordered or column ordered;
+row order is recommended.
+You can also specify that the output be a text table.
+The default ('tbltype = "default"') means that the type of the output table
+will be taken from the first input table.
+
+If the extension of the output file name is ".fits" or ".??f",
+the table to be created will be a BINTABLE extension in a FITS file,
+regardless of how 'tbltype' is set.
+.le
+.ls (allrows = 100) [integer, min=1, max=INDEF]
+The number of rows to allocate.
+This parameter is only used for column-ordered tables
+(specified by the 'tbltype' parameter).
+The 'allrows' parameter is the minimum number of rows an output
+table will contain.
+If the number of rows required by the input tables
+is greater than 'allrows' then the number of rows in the output table will
+be greater than 'allrows'.
+If 'option = merge', then the total number of rows will be
+the larger of 'allrows' or the number of rows in the largest table.
+If 'option = append', the total rows in the output table will be the larger
+of 'allrows' or the total number of rows in all input tables.
+.le
+.ls (extracol = 0) [integer, min=0, max=INDEF]
+Extra space to be reserved for columns in the output table.
+
+This parameter is relevant only for a row-ordered table
+(specified by the 'tbltype' parameter).
+The default value of zero is normally appropriate,
+but if you expect to define additional columns in the output table
+at a later time
+then you can allocate the necessary space
+by specifying a value for 'extracol'.
+One unit of space is taken by each single-precision real value,
+integer value, or boolean value.
+A double-precision column requires two units of allocated space,
+and a character-string column takes one unit of space for each four
+characters, or fraction thereof.
+.le
+.ih
+EXAMPLES
+.nf
+1. Suppose you have the following two tables.
+
+tbl1.tab:
+ one two three
+ --- --- -----
+ 1 -17 alpha
+ 2 -19 beta
+ 3 -23 gamma
+
+tbl2.tab:
+ one three four
+ --- ----- ----
+ 27 beta 3.14
+ 28 delta 2.72
+
+then the statement
+
+ cl> tmerge tbl1,tbl2 mrg merge
+
+would create the following output table:
+
+mrg.tab:
+ one two three four
+ --- --- ----- ----
+ 27 -17 beta 3.14
+ 28 -19 delta 2.72
+ 3 -23 gamma INDEF
+
+while the statement
+
+ cl> tmerge tbl1,tbl2 app append
+
+would create the following table:
+
+app.tab:
+ one two three four
+ --- --- ----- ----
+ 1 -17 alpha INDEF
+ 2 -19 beta INDEF
+ 3 -23 gamma INDEF
+ 27 INDEF beta 3.14
+ 28 INDEF delta 2.72
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+.ih
+SEE ALSO
+tselect, tproject, and proto.joinlines for text files
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tprint.hlp b/pkg/utilities/nttools/doc/tprint.hlp
new file mode 100644
index 00000000..47690159
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tprint.hlp
@@ -0,0 +1,276 @@
+.help tprint Aug1999 tables
+.nj
+.ih
+NAME
+tprint -- Convert an STSDAS table to a readable ASCII file.
+.ih
+USAGE
+tprint table
+.ih
+DESCRIPTION
+This task is similar to the 'tdump' task in that it takes an STSDAS
+table and produces a file in ASCII format;
+however, this task offers more control over the appearance
+of the final product and better prepares it for printing.
+Formatting options are available
+to control the width and length of a page,
+and to produce the output in HTML, TeX or LaTeX format.
+
+By default, all rows and columns in the input tables will be printed,
+but the 'rows' and 'columns' parameters can be used
+to limit the range of rows and columns, respectively, that will be used.
+When using the TeX or LaTeX options,
+the number of output columns is limited to 52.
+For the HTML option,
+all the rows and columns that are to be printed
+will be written to one HTML table,
+rather than broken into pages.
+There is no limit to the number of columns in ASCII format;
+however, if the aggregate column width exceeds the page width
+the output will be produced in sections
+with columns kept together on a page--lines will not wrap.
+If different columns for each row are printed on separate pages,
+the row number will appear on each page, if 'showrow = yes'.
+
+The output will be printed to the standard output.
+.ih
+PARAMETERS
+.ls table [file name template]
+The file names of tables to be printed.
+This parameter will accept a general file name template,
+containing wildcard characters,
+individual file names with each file name separated by a comma,
+or the name of a list file (preceded by the "@" character)
+containing the file names of all tables to be processed.
+If more than one table is to be processed,
+a blank line will be printed between tables.
+.le
+.ls (prparam = no) [boolean]
+Should the header parameters be printed?
+.le
+.ls (prdata = yes) [boolean]
+Should the table data be printed?
+.le
+.ls (pwidth = 80) [integer, min=40, max=INDEF]
+If the output is redirected,
+'pwidth' specifies the width of the output page;
+otherwise, the screen size is taken from the environment variable 'ttyncols'.
+Columns that are too wide to fit within this page size
+(allowing also for the row number) will be truncated.
+
+This parameter is not used if option = "html".
+.le
+.ls (plength = 0) [integer, min=0, max=INDEF]
+Lines of data per page.
+This is the number of rows from the table to be printed on each page;
+it does not include the line of column names.
+It does, however, include any blank lines inserted in the data
+because the user specified a value for 'lgroup'.
+The default of zero gives no page breaks.
+
+This parameter is not used if option = "html".
+
+If the 'sp_col' parameter is not null
+or if the 'lgroup' parameter is greater than zero,
+the blank lines between groups are included in the count of lines per page.
+Thus 'lgroup = 50' and 'plength = 51' would be consistent
+and would give the same result as 'lgroup = 0', 'plength = 50'.
+.le
+.ls (showrow = yes) [boolean]
+Print the number of each row?
+
+If more than one page is needed in order to print all the columns specified,
+then the row numbers will be printed on each page.
+If 'showrow = no' then row numbers are not printed.
+.le
+.ls (orig_row = yes) [boolean]
+Print row numbers of the underlying table?
+
+This parameter only has an effect if a row selector expression
+was included with the table name,
+in which case the table appears to have fewer rows
+than are actually present in the underlying table
+(the complete table, including all rows).
+When 'orig_row' is yes, the default,
+the row numbers printed are those in the underlying table;
+when 'orig_row' is no,
+the selected rows are numbered sequentially starting with one,
+as if those were the only rows in the table.
+.le
+.ls (showhdr = yes) [boolean]
+Print header information?
+
+The table name, date of last modification,
+and column names are printed only if 'showhdr = yes'.
+If the 'option' parameter (see below) is set to either "latex" or "tex",
+then 'showhdr' will affect the printing of
+the default macro definitions for column separators
+and the end-of-line string as well as the begin-table string
+(i.e., "\begin{tabular}..." or "\halign...").
+.le
+.ls (showunits = yes) [boolean]
+Print the units for each column? If 'showunits = yes'
+then the column units will be printed on the line below the column names.
+.le
+.ls (columns = "") [string]
+The names of the columns to be printed.
+An alternative way to do this
+is to use a column selector with the table name
+(type "help selectors" for more information).
+
+A null or blank string means print all columns.
+This parameter is a column template--that is,
+either a list of column names
+or a template that can contain wildcard characters.
+The column names should be separated by commas or white space.
+The list of column names can be placed in a file
+and the name of the file preceded by "@" passed to 'columns'.
+If the first character in the column template
+is the negation character (either "~" or "!"),
+all columns NOT named will be printed.
+
+If you want to use a list file for this parameter,
+the 'tlcol' task can be used to make the list
+(be sure to set the 'nlist' parameter to 1).
+Using the 'tlcol' task can eliminate potential problems
+caused by incorrect spelling.
+The list produced by 'tlcol' can also be edited to
+rearrange column names (to change the order for printing)
+or to delete unwanted columns.
+.le
+.ls (rows = "-") [string]
+The range of rows which are to be printed.
+An alternative way to do this
+is to use a row selector with the table name
+(type "help selectors" for more information).
+
+This parameter takes a character string
+defining either specific rows to be printed,
+a range of rows, or upper or lower limits on row numbers.
+The default value "-" means print all rows.
+The first ten rows could be specified as rows="1-10" or just rows="-10".
+To print the first ten rows
+and all rows from 900 through the last (inclusive), use rows="-10,900-".
+Setting rows="1,3,7,23" will print only those four rows.
+It is not an error to specify rows larger than the largest row number;
+excess row numbers will simply be ignored.
+(For more information type "help ranges".)
+.le
+.ls (option = "plain") [string, allowed values: plain | html | latex | tex]
+The format in which output will be produced.
+If option = "plain", the output will be ordinary ASCII text which may
+be read or printed directly.
+(See also the 'align' parameter, below.)
+
+If option = "html",
+the output will be formatted with HTML tags,
+and the output should be redirected to a file having the extension ".html".
+
+If option = "latex",
+the output will be formatted for use as input to LaTeX,
+and if option = "tex",
+the output will be formatted for use as input to TeX.
+In these two cases the output should be redirected to a file having
+the extension ".tex".
+Each value in each row will be preceded by a column-separator of the
+form "\cola" through "\colz", "\colA" through "\colZ".
+(Yes, there
+is a limit of 52 columns to be printed on one page.) If the row number
+is printed (i.e., by using the 'showrow' parameter) it will
+be preceded by the string "\colzero"; the string "\cola" always
+precedes the first column from the table.
+The default definitions assign "\null" to the first of these
+(either "\colzero" or "\cola") and assign "&" to all the rest.
+Each row may span several physical rows and is terminated by "\eol",
+which has the default definition of "\\" or "\cr" as appropriate.
+(See also the description of the parameter 'showhdr').
+.le
+.ls (align = yes) [boolean]
+Increase column width to align with header? This parameter is only useful
+when option = "plain".
+If 'align = no', the print format stored in the table for each column
+will be used without modification.
+This can cause a problem in that some
+column names may be longer that the field width for those columns,
+consequently, the column names and their values will be misaligned
+(this is especially true of subsequent columns).
+The default value 'align = yes' will force the columns to be aligned
+with the column names regardless of the print format.
+Note that you can set 'showhdr = no' but 'align = yes', in which case the
+column names will not be printed, but the columns will be spaced the
+same as if the names were printed.
+.le
+.ls (sp_col = "") [string]
+This is the name of a column in the table.
+If it is specified (non-null),
+and if the column is found in the input table,
+a blank line will be printed
+whenever the value in this column changes
+from the value in the preceding row
+(or from the preceding element,
+if 'sp_col' contains arrays).
+
+The equality test is made on formatted
+values in the column so that the user has more control over spacing
+when the data type of 'sp_col' is either real or double.
+The print format may be changed using either the 'tedit' or 'tchcol' tasks.
+Both 'sp_col' and 'lgroup' may be used together,
+which may be useful if the 'sp_col' column does not change very often.
+.le
+.ls (lgroup = 0) [integer, min=0, max=INDEF]
+Print a blank line after each 'lgroup' lines.
+If 'lgroup' is greater than zero,
+a blank line will be printed between each block of 'lgroup' lines.
+These blank lines are included in the count for 'plength' (page length).
+For example, if lgroup = 10 and plength = 55,
+five groups of ten lines will be produced for each page;
+lgroup = 5, plength = 60 will
+give ten groups of five lines per page.
+The count of lines for these groups is reset at the beginning of each page,
+so even if lgroup+1 does not divide into 'plength',
+the first group on each page will have 'lgroup' lines.
+
+If any column that is being printed contains array elements
+rather than just scalar values,
+grouping by 'lgroup' will be applied to array elements
+rather than to row numbers.
+If option = "plain"
+and the window width (or 'pwidth' if output is redirected)
+is not large enough for all the columns,
+the spacing can be by row number on some pages
+and element number on other pages,
+depending on which columns fit on those pages
+(i.e. whether the columns contain arrays).
+.le
+.ih
+EXAMPLES
+1. Print all tables in the default directory.
+
+.nf
+ tt> tprint *.tab
+.fi
+
+2. Print 'junk.tab', but rearrange the columns.
+
+.nf
+ tt> tlcol junk nlist=1 >colnames.lis
+ tt> edit colnames.lis
+ (Rearrange the column names and perhaps delete some of them.)
+ tt> tprint junk columns=@colnames.lis
+.fi
+
+3. After using the 'tinfo' task to find that 'big.tab' has 100000 rows,
+print the first five and last five rows.
+
+.nf
+ tt> tprint big rows="1-5,99996-"
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+.ih
+SEE ALSO
+tdump, ranges
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tproduct.hlp b/pkg/utilities/nttools/doc/tproduct.hlp
new file mode 100644
index 00000000..8b9c2534
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tproduct.hlp
@@ -0,0 +1,48 @@
+.help tproduct Dec90 tables
+.ih
+NAME
+tproduct -- Form the Cartesian product of two tables.
+.ih
+USAGE
+tproduct intable1 intable2 outtable
+.ih
+DESCRIPTION
+This task creates an output table which is the Cartesian product of two input
+tables. This Cartesian product consists of every possible combination of the
+rows of the two input tables. Therefore, the number of rows in the output table
+is the product of the number of rows in the two input tables. The output table
+will contain all the columns from both input tables. If a column name in the
+first input table is the same as a column name in the second input table, this
+task tries to create a unique name by appending "_1" to the first name and "_2"
+to the second name. If the task cannot create a unique name in this way, it
+stops with an error.
+.ih
+PARAMETERS
+.ls intable1 [file name]
+First input table.
+.le
+.ls intable2 [file name]
+Second input table.
+.le
+.ls outtable [file name]
+Output table containing the possible Cartesian products.
+.le
+.ih
+EXAMPLES
+1. Find all persons sharing a phone from a phone list:
+
+.nf
+tt> tproduct phone.tab phone.tab phone.tmp
+tt> tselect phone.tmp share.tmp "phone_1 == phone_2 && name_1 < name_2"
+tt> tproject share.tmp share.tab phone_2 inc-
+tt> delete *.tmp
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+tselect, tproject, tjoin
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tproject.hlp b/pkg/utilities/nttools/doc/tproject.hlp
new file mode 100644
index 00000000..7ab88158
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tproject.hlp
@@ -0,0 +1,79 @@
+.help tproject May1999 tables
+.ih
+NAME
+tproject -- Create a new table from selected columns of an old table.
+.ih
+USAGE
+tproject intable outtable columns
+.ih
+DESCRIPTION
+This task will create a new table containing a subset of the columns in an
+old table. The column names are given as a column name template. There is an
+optional parameter, 'uniq', that filters out duplicate rows from the
+new table.
+
+If you do not need to eliminate duplicate rows, you can also use tcopy
+with a column selector on the input table name.
+.ih
+PARAMETERS
+.ls intable [file name template]
+The table(s) from which the columns are to be copied. If input is
+redirected, this parameter will ignored and input will be read from
+STDIN instead.
+.le
+.ls outtable [file name template]
+The new table(s) containing the copied columns.
+The number of output tables must equal the number of input tables.
+.le
+.ls columns [string]
+This is the column template describing those columns that should be
+selected from the old table and put in the new table.
+A column template consists of a list
+of either column names or column name templates that include wildcard
+characters. Column names (or templates) are separated by commas or white space.
+This parameter will accept the name of a list file (preceded by the "@"
+character) containing all of the column names to be selected.
+If the first non-white character in the column template
+is the negation character (either "~" or "!"),
+the new table will contain those columns
+whose names DO NOT match rest of the column template.
+.le
+.ls (uniq = no) [boolean]
+Eliminate duplicate rows from the output table?
+
+If 'unique' is set to "yes", only one of each set of duplicate rows is
+included in the output table. All columns in the output table must be
+identical for the row to be removed. String comparisons are case
+sensitive. Care should be used in setting this option for
+large tables, as it significantly increases the running time.
+.le
+.ih
+EXAMPLES
+1. Extract the star names, magnitudes, and colors from a catalog:
+
+.nf
+tt> tproject starcat.tab starmag.tab "name,mag,color"
+.fi
+
+2. Exclude the measurement error from a set of spectra. Change the file name
+extensions from ".tab" to ".tbl":
+
+.nf
+tt> tproject *.tab *.%tab%tbl% "!error"
+.fi
+
+3. Create a new table of engineering parameters using a column template stored
+in the file 'columns.dat'. Eliminate duplicate rows:
+
+.nf
+tt> tproject datalog.tab sublog.tab @columns.dat uniq+
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+tselect, tjoin, tproduct,tcopy
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tquery.hlp b/pkg/utilities/nttools/doc/tquery.hlp
new file mode 100644
index 00000000..61857fd7
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tquery.hlp
@@ -0,0 +1,115 @@
+.help tquery Jan1999 tables
+.ih
+NAME
+tquery -- Create a new table from selected rows and columns of an old table.
+.ih
+USAGE
+tquery intable outtable expr columns sort
+.ih
+DESCRIPTION
+This task combines the functions of the tasks 'tselect', 'tproject', and
+'tsort' to create a more powerful task that can produce a sorted table of
+user-selected rows and columns.
+It can be used whenever you want to do more than one of these operations
+without creating intermediate tables. This task creates a new table
+containing a subset of the rows and columns in an old table. The rows in the
+new table can be sorted on any column or combination of columns. The select,
+project, and sort operations are controlled by the parameters 'expr',
+'columns', and 'sort',
+respectively. If the value of any of these parameters is a null or
+blank string, the corresponding operation is not performed. Otherwise, the rows
+are selected whenever the row meets the conditions defined by 'expr';
+columns are
+selected by the 'columns' parameter, and rows are
+sorted on the columns named in 'sort'. The hidden parameter 'uniq' is used
+to eliminate duplicate rows from the output table. The hidden parameter
+'ascend' sorts the table in ascending order, and the parameter 'casesens'
+specifies whether sort conditions are to be case sensitive.
+.ih
+PARAMETERS
+.ls intable [file name template]
+Table(s) from which rows are copied. If input is redirected, this
+parameter will ignored and input will be read from STDIN instead.
+.le
+.ls outtable [file name template]
+The new table(s) containing the copied rows.
+The number of output tables must equal the number of input tables.
+.le
+.ls expr [string]
+The boolean expression which determines which rows are copied to the new
+table. The expression may be placed in a file and the name of the file
+preceeded by a '@' can be given in its place. If the expression is null
+or blank, all rows are selected. The syntax and method used to define
+this boolean expression is explained in detail in the help file for the
+'tselect' task (type "help tselect" for more information).
+.le
+.ls columns [string]
+Column template describing the columns that are to be selected
+from the old table. A column template consists of a list
+of column names, which can include wildcard characters.
+The column names, or patterns, are separated by commas or white space.
+The list of columns can be placed in a file and then
+the name of that file passed to 'columns' (preceded by
+the "@" character). If the first non-white character in the template
+is the negation character (either "~" or "!"),
+the new table will contain those columns
+that do NOT match the column template. If the column template
+is null or blank, all columns will be selected.
+.le
+.ls sort [string]
+Column template describing the columns to be sorted. The
+first column name is the primary sort key with subsequent columns
+used to break ties. If this parameter
+is null or blank, no sort will be done.
+.le
+.ls (uniq = no) [boolean]
+Make sure all rows are unique in a table?
+
+If 'unique' is set to "yes", only one of each set of duplicate rows is included
+in the output table. All columns in the output table must be identical for
+the row to be removed. String comparisons are case sensitive. Care should
+be used in setting this option for large tables, as it significantly increases
+the running time.
+.le
+.ls (ascend = yes) [boolean]
+Should sorts be performed in ascending order?
+
+If 'ascend = yes', the table is sorted in ascending order, with the first
+row containing the smallest value of the sorted column. Otherwise, the table
+is sorted in descending order, with the largest value first.
+.le
+.ls (casesens = yes) [boolean]
+Are sort operations case sensitive?
+
+If 'casesens = yes', sorts on character columns are case sensitive, with upper
+case letters preceding lower case. Otherwise, the sort is not case
+sensitive.
+.le
+.ih
+EXAMPLES
+1. Extract all binary stars from a catalog; write their names, magnitudes,
+and colors to a new table, sorted on magnitude:
+
+.nf
+tt> tquery starcat.tab binary.tab binary name,mag,color mag
+.fi
+
+2. Remove duplicate rows from a set of tables. Otherwise, leave the tables
+unchanged. Using file name editing (i.e., the "%" characters to delineate
+old strings and new strings), change the file name extensions from ".tab"
+to ".tbl".
+
+.nf
+tt> tquery *.tab *.%tab%tbl% "" "" "" uniq+
+.fi
+.ih
+BUGS
+Column names must be set off from operators by blanks in the expression so
+that they can be correctly parsed by the expression evaluator.
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+tsort, tselect, tproject
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tread.hlp b/pkg/utilities/nttools/doc/tread.hlp
new file mode 100644
index 00000000..871ec66f
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tread.hlp
@@ -0,0 +1,159 @@
+.help tread Aug91 tables
+.ih
+NAME
+tread -- View a table (read only).
+.ih
+USAGE
+tread table
+.ih
+DESCRIPTION
+The 'tread' task is a read-only version of 'tedit', the screen editor for STSDAS
+tables. 'tread' lets you view a table by moving the cursor around the
+screen with the cursor keys. The screen scrolls both sideways and up
+and down as you move the cursor, so all elements of the table can be
+reached. Other editing commands are entered on the command line. To
+switch from table editing mode to command line mode, you press the
+exit key (generally bound to Control-Z, though this can be changed).
+When your
+command is completed, the editor returns to table editing mode, unless
+the command exits the editor. The most important commands in command
+mode are `help' and `exit'. The `help' command displays all the
+editing key bindings and the command line commands. The `exit' command
+will get you out of the editor.
+
+Some editing commands are entered from the command line in command
+mode. To get to command line mode, press the exit key (Control-Z).
+If you enter a
+blank line, the editor will
+return to table editing mode. Some commands take arguments. They can
+be included when the command is entered, or if they are omitted, the
+editor will prompt you for their values. If the argument has embedded
+blanks, the argument should be enclosed in quotes if passed on the
+command line. No quotes should be used if the argument is entered
+interactively. When the editor interactively prompts you for a command
+argument it will also display a default value for the argument.
+Pressing the return key gets the default value. Some command names are
+two
+words long, for example, "find forward". Usually the second word is
+optional and modifies the meaning of the first. If the second word is
+not optional and you omit it, the editor will prompt you for it. All
+command names can be abbreviated to one or more letters. If the
+command name is two words long, both words can be abbreviated to one
+or more letters.
+
+The following commands are used by 'tread':
+.ls exit
+Exit the table editor.
+.le
+.ls find <expression>
+Find the next row in the table which makes <expression> true and move
+the cursor to that row. The expression has the same syntax as an
+expression in a Fortran if statement. The variables in the expression
+are column names. For more information on the syntax of the
+expression, read the help for the 'tselect' task. The direction of the search
+depends
+upon previous find commands. By default the search direction is forward;
+however, if a "find backwards" command has been executed previously,
+searches will be done in a backwards direction until a "find forward"
+command is executed.
+.le
+.ls find forward <expression>
+Find the next row in the table which makes <expression> true and move the
+cursor to that row. The search is done in the forwards direction.
+.le
+.ls find backwards <expression>
+Find the next row in the table which makes <expression> true and move the
+cursor to that row. The search is done in the backwards direction.
+.le
+.ls goto <row> <column>
+Move the cursor to <row> and <column>.
+.le
+.ls help
+Display online help information for the table editor. The help includes
+a brief description of each command line command and the key bindings
+for table editing commands.
+.le
+.ls next
+Repeat the previous find command, using the same expression and search
+direction that was used with it.
+.le
+.ls next forward
+Repeat the previous find command, changing the search direction to
+forwards.
+.le
+.ls next backwards
+Repeat the previous find command, changing the search direction to
+backwards.
+.le
+.ls quit
+Exit the table editor.
+.le
+
+The bindings to the table editing keys are read from the edcap file.
+This is the file that defines key bindings for the
+parameter editor and history editor. The edcap file defines key
+bindings that resemble those of commonly used text editors. Three
+edcap files are distributed with IRAF. They define key bindings which
+resemble EDT, Emacs, and vi. These edcap files are located in the 'dev$'
+directory and have the extension '.ed'. The appropriate file is chosen
+according to the value of the environment variable 'EDITOR'. If you
+want to customize the key bindings of the table editor, copy the
+appropriate edcap file from the 'dev$' directory to your 'home$' directory
+and edit the second column. The table editor searches your
+home directory first for the edcap file and if it does not find it,
+searches the 'dev$' directory.
+
+The table editor also uses the termcap file to determine the screen
+size and the escape sequences used to modify the screen. There are
+entries in the termcap file for almost all terminal types. The proper
+entry is selected according to the environment variable terminal. To
+change your terminal type or the screen size, use the IRAF 'stty'
+command.
+
+.ih
+PARAMETERS
+.ls table [string]
+Name of the table to be edited. The editor checks for the
+existence of the table and its access mode before editing. The table
+must exist in order to edit it with 'tread'.
+.le
+.ls (columns = "") [string]
+Names of the columns to be edited.
+A null or blank string means edit all columns.
+A column template consists of a list of either
+column names or column patterns containing the usual pattern matching
+meta-characters. The names or patterns are separated by commas or
+white space. The list can be placed in a file and the name of the
+file preceded by an "@" character.
+If the first character in the column template is a bang (!),
+all columns NOT named will be displayed.
+
+The 'tlcol' task (with the 'nlist' parameter set to 1) may be used to generate a
+list of
+column names so there is no question about spelling. This list may be
+edited to rearrange (or delete) the names, and then pass the list to this task
+by preceding the its file name with an "@", for example,
+
+tt> tedit junk columns=@colnames.lis
+.le
+.ls (silent = no) [boolean]
+Turn off the bell indicating warning messages?
+.le
+.ih
+EXAMPLES
+1. Display only the columns 'SHARP' and 'ROUND' from the table 'm12b.tab':
+
+.nf
+tt> tread m12b columns="SHARP,ROUND"
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+tedit, tprint, tselect, stty
+
+Type "help tables opt=sys" for a description of the 'tables' package.
+.endhelp
diff --git a/pkg/utilities/nttools/doc/trebin.hlp b/pkg/utilities/nttools/doc/trebin.hlp
new file mode 100644
index 00000000..293c08ec
--- /dev/null
+++ b/pkg/utilities/nttools/doc/trebin.hlp
@@ -0,0 +1,257 @@
+.help trebin Jul2000 tables
+.nj
+.ih
+NAME
+trebin -- Resample tables.
+.ih
+USAGE
+trebin intable outtable column start end step
+.ih
+DESCRIPTION
+This task resamples tables.
+The grid on which to interpolate an input table
+may be specified either by a table giving explicit values
+or by start, end, and step values for uniform spacing.
+The column names in the output table
+will be the same as in the input table.
+
+If the independent variable column ('column')
+in the input table contains scalar values,
+each numeric column in the input table will be rebinned
+to the values of the output independent variable.
+Character and boolean columns
+will not be copied to the output table.
+Columns that contain arrays will also not be copied to output.
+On the other hand,
+if the input independent variable column contains arrays
+rather than scalar values,
+then each row of the input table will be rebinned individually.
+Scalar columns will be copied to output unchanged.
+Array columns which have the same length as 'column'
+will be rebinned and written to the output table;
+if the array size is not the same,
+the column will not be copied to output.
+
+Except for function = "linear",
+the output values are obtained by interpolation, not by fitting.
+The distinction is important when rebinning to a spacing ('step')
+that is significantly coarser than the spacing of the input data.
+For functions other than linear,
+each interpolated value is obtained as follows.
+The values of the input data
+nearest the current output independent variable value (X) are selected;
+the input data are then interpolated at X
+to obtain the value to write to the output table.
+For function = "nearest", only one input point is used;
+for function = "poly3" or "spline", four input points are used.
+This is appropriate for rebinning
+to a spacing not much different from the input data.
+For resampling noisy data
+to a significantly wider spacing than the input data, however,
+these options will give very poor results.
+In the latter case, function = "linear" (the default) should be used.
+This option uses a linear fit to all the data
+within an interval of width 'step' centered on each output X value.
+If there are fewer than two input points in a given interval, however,
+the value is interpolated the same way as is done for the other functions;
+that is, the two input points nearest to X are selected,
+and the value is interpolated at X
+(note that these two points can be outside the 'step' interval).
+
+A significant limitation to this task is that
+there is no option to conserve total counts.
+'trebin' averages the data values,
+rather than summing the input bins.
+What 'trebin' does is appropriate for flux-calibrated spectra,
+or for time series data expressed as count rate,
+but it would not be correct for data in counts,
+or for count rate spectra.
+.ih
+PARAMETERS
+.ls intable [file name template]
+List of input tables to be resampled.
+.le
+.ls outtable [file name template]
+Output tables or directory.
+The number of output tables must match the number of input tables unless
+'outtable' is a directory name.
+.le
+.ls column [string]
+Name of the independent variable column in the input table,
+i.e., the column on which the data are being resampled.
+The same column name is used for all input tables.
+The values in this column must be
+either monotonically increasing or decreasing.
+INDEF values and trailing 'padvalue' (described below) will be ignored.
+
+The data type of the column is assumed to be a numeric type.
+.le
+.ls start [real]
+If the independent variable values at which to interpolate the input values
+are to be uniformly spaced,
+they may be specified using 'start', 'end', and 'step'.
+'start' is the first value of the output independent variable.
+
+See also 'xtable';
+'start', 'end', and 'step' will be ignored if 'xtable' was specified.
+.le
+.ls end [real]
+Last value of the independent variable.
+This may be rounded up by a fraction of 'step' to ensure that the entire
+range from 'start' to 'end' is included in the output table.
+.le
+.ls step [real]
+Increment in independent variable.
+The sign of 'step' is ignored;
+internally to 'trebin' the sign will be set to negative
+if 'start' is larger than 'end'.
+
+If 'start' and 'end' are the same,
+the output table will contain one row,
+and 'step' will only be used for the case of function = "linear".
+For other values of 'function',
+since the data will be interpolated at just the one point 'start',
+the step size will not be needed.
+.le
+.ls (xtable) [file name template]
+The independent variable values at which to interpolate the input values
+can either be specified explicitly with 'xtable'
+or computed using 'start', 'end', 'step'.
+If 'xtable' is specified,
+there must either be just one table name,
+or the number of names must be the same as
+the number of names in 'intable'.
+If there is only one 'xtable',
+it will be used for all input tables.
+
+'xtable' must contain only one column.
+The name of the column does not matter;
+it does not need to be the same as given by 'column'.
+If the actual table contains more than one column,
+use the column selector syntax to specify which one to use.
+The column may contain either scalar values or arrays.
+If the column contains arrays,
+there must be only one row;
+if the actual table contains more than one row,
+use the row selector syntax to specify which one to use.
+
+The data type of the column is assumed to be a numeric type.
+.le
+.ls (function = "linear") [string, allowed values: nearest | linear |
+poly3 | spline]
+
+Interpolation function.
+There must be at least four rows in the input table
+for cubic polynomial or cubic spline interpolation.
+Two rows are required for linear interpolation,
+and only one for nearest-neighbor.
+
+The "linear" option uses a linear fit,
+while all other functions are interpolations
+using only the required number of points
+nearest the value of the independent variable.
+
+If an input table does not contain enough rows,
+or if a column being interpolated contains INDEF values
+so that the total number of values is insufficient for interpolation,
+the output column will be entirely INDEF;
+if verbose = yes, a message will be printed.
+.le
+.ls (extrapolate = no) [boolean]
+Extrapolate if out of bounds? See 'value' below.
+.le
+.ls (value = INDEF) [real]
+Value to use if out of bounds.
+The independent variable values
+at which the input table is to be interpolated
+may fall outside the range of values
+in the independent variable column in the input table.
+The value to write to the output table
+for out of bounds independent variables depends on
+the 'extrapolate' and 'value' parameters.
+If 'extrapolate' is yes, then 'value' is ignored,
+and the interpolation function is used for extrapolation.
+If 'extrapolate' is no,
+then 'value' is written to each dependent variable column
+for each row that the independent variable
+is outside the range of values in the input table.
+Note that for columns of type integer or short,
+'value' should be within the range of possible values of that type,
+and if 'value' contains a fractional part
+it will be rounded to the nearest integer.
+.le
+.ls (padvalue = INDEF) [real]
+Trailing INDEF values in the independent variable column
+(either in 'intable' or in 'xtable')
+will be ignored.
+'padvalue' can be used to specify an additional value,
+such as zero,
+which will also be ignored
+if it occurs at the end of an array of independent variable values.
+Values will be trimmed off the end of the array
+until a value that is neither INDEF nor 'padvalue' is encountered.
+.le
+.ls (verbose = yes) [boolean]
+If verbose = yes,
+the input and output table names will be printed as they are processed,
+and the names of columns that are not being copied to output
+will also be printed.
+.le
+.ls (Version) [string]
+This gives the date of installation of the current version.
+.le
+.ih
+EXAMPLES
+1. Resample all the columns in all tables beginning with "hr" so the values
+in the "Wavelength" column range from 3000 to 8000 in steps of 10.
+The output tables will have the same names, but will be written in the
+directory "home$spec" (which should be different from the default directory).
+
+.nf
+ tt> trebin hr*.tab "home$spec/" Wavelength 3000. 8000. 10.
+.fi
+
+2. Interpolate the text table "in" at a single point,
+where the value in column one is 5,
+and print the results on the standard output.
+
+.nf
+ tt> trebin in STDOUT c1 5. 5. 0.
+.fi
+
+3. Interpolate the table from example 2
+onto the array of independent variable values
+in column "wavelength" at row 37 of "x1d.fits".
+As in example 2,
+the independent variable in "in" is the first column, "c1".
+
+.nf
+ tt> trebin in STDOUT c1 xtable="x1d.fits[r:row=37][c:wavelength]"
+.fi
+.ih
+BUGS
+A column which contains an integer bit mask
+will be interpolated as if it were an ordinary numeric column,
+which is not the correct behavior.
+
+Sometimes a table contains array columns
+where the allocated array size is (or can be)
+larger than the number of elements actually used.
+In this case, a scalar column might be used
+to specify the effective array length.
+The array size in the output table
+will typically be different from the array size in the input table;
+'trebin' will update the allocated array size,
+but it will not modify any scalar column that gives the effective array size.
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+The following Numerical Recipes subroutines are used by this task:
+TUCSPL, TUHUNT, TUIEP3, and TUISPL.
+Numerical Recipes was written by W.H. Press, B.P. Flannery,
+S.A. Teukolsky, and W.T. Vetterling.
+.ih
+SEE ALSO
+Type "help tables opt=sys" for a higher-level description of the 'tables'
+package.
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tselect.hlp b/pkg/utilities/nttools/doc/tselect.hlp
new file mode 100644
index 00000000..56299faa
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tselect.hlp
@@ -0,0 +1,147 @@
+.help tselect Jul92 tables
+.ih
+NAME
+tselect -- Create a new table from selected rows of an old table.
+.ih
+USAGE
+tselect intable outtable expr
+.ih
+DESCRIPTION
+This task creates a new table from a subset of rows in an input table.
+The rows are selected on the basis of a boolean expression whose
+variables are table column names. If, after substituting the values associated
+with a particular row into the column name variables, the expression evaluates
+to yes, that row is included in the output table. Boolean operators can be used
+in the expression in either their Fortran or SPP forms. The following boolean
+operators can be used in the expression:
+
+.nf
+equal .eq. == not equal .ne. !=
+less than .lt. < less than or equal .le. <=
+greater than .gt. > greater than or equal .ge. >=
+or .or. || and .and. &&
+negation .not. ! pattern match ?=
+.fi
+
+The pattern match operator (?=) has no corresponding Fortran form. It takes a
+string expression as its first argument and a pattern as its second argument.
+The result is "yes" if the pattern is contained in the string expression.
+Patterns are strings which may contain meta-characters (i.e., wildcard
+characters used in pattern matching).
+The meta-characters themselves can be matched by preceeding them with the escape
+character (\).
+The meta-characters are:
+
+.nf
+beginning of string ^ end of string $
+one character ? zero or more characters *
+white space # escape character \
+begin ignoring case { end ignore case }
+begin character class [ end character class ]
+not, in char class ^ range, in char class -
+.fi
+
+The expression may also include arithmetic operators and functions.
+Trigonometric functions use degrees, not radians. The following arithmetic
+operators and functions can be used in the expression:
+
+.nf
+addition + subtraction -
+multiplication * division /
+negation - exponentiation **
+concatenation // date difference delta(x,y)
+absolute value abs(x) cosine cos(x)
+sine sin(x) tangent tan(x)
+arc cosine acos(x) arc sine asin(x)
+arc tangent atan(x) arc tangent atan2(x,y)
+exponential exp(x) square root sqrt(x)
+natural log log(x) common log log10(x)
+modulo mod(x) minimum min(x,y)
+row number row() maximum max(x,y)
+nearest integer nint(x) convert to integer int(x)
+convert to real real(x) convert to string str(x)
+.fi
+
+The row number function returns an integer value corresponding to the
+row number in the table. The date difference function returns a real
+value corresponding to the Julian date of the first argument minus the
+Julian date of the second argument; the arguments to the data function
+must be in CDBS date format: i.e., character strings of the form
+YYYYMMDD:HHMMSSCC. Any field after the colon is optional. The last
+date field (CC) is hundreths of a second.
+
+One concept in most databases and in STSDAS tables is the concept of a
+null value: a value which indicates that the element is unknown or
+non-existent. An element in an STSDAS table is null if it is INDEF in a
+numeric column or a zero length string in a text column. Evaluating
+expressions involving nulls requires a three valued logic: true,
+false, and unknown. Any arithmetic operation on a null element should
+return another null and any comparison operation should return an
+unknown. Unfortunately, tselect does not implement a true three
+valued logic correctly. The code instead evaluates any expression
+containing a null element as unknown. Since tselect only returns rows
+for which the expression is true, all such rows are excluded from the
+output of tselect. This is usually right, but sometimes wrong, as in
+the case where two comparisons are joined by an or and one evaluates
+to true and the other evaluates to unknown. It also sometimes returns
+nonintuitive results, as when checking that a column is not equal to
+INDEF.
+.ih
+PARAMETERS
+.ls intable [file name template]
+Table(s) from which rows are copied. If input is redirected, this
+parameter will ignored and input will be read from STDIN instead.
+.le
+.ls outtable [file name template]
+The new table(s) containing the copied rows.
+If more than one input table was used, then the number of output
+tables must equal the number of input tables.
+.le
+.ls expr [string]
+The boolean expression which determines which rows are copied to the new
+table. The expression may be placed in a list file and the name of the file
+passed to this parameter (preceded by the "@" character).
+.le
+.ih
+EXAMPLES
+1. Extract all binary stars brighter than fifth magnitude from a catalog:
+
+.nf
+tt> tselect starcat.tab binary.tab "binary && mag <= 5."
+.fi
+
+2. Create a new set of spectra where all measurements with errors greater
+than ten percent are excluded. Use file name editing to create new tables
+with the extension ".tbl" instead of ".tab":
+
+.nf
+tt> tselect *.tab *.%tab%tbl% "ERROR / (FLUX + .001) < .1"
+.fi
+
+3. Create a table of engineering parameters whose names begin with a digit:
+
+.nf
+tt> tselect datalog.tab sublog.tab "name ?= '^[0-9]'"
+.fi
+
+4. Return all observations in a schedule for the day of Dec 31, 1989:
+
+.nf
+tt> tselect schedule.tab week.tab "abs(delta(date,'19891231:12'))<.5"
+.fi
+.ih
+BUGS
+Column names must be set off from operators by blanks in the
+expression so that they can be correctly parsed by the expression
+evaluator. Expressions involving nulls may evaluate incorrectly, see
+above for a discussion.
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+tproject, tjoin, tproduct
+
+Type "help tables opt=sys" for a higher-level description of the 'tables'
+package.
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tsort.hlp b/pkg/utilities/nttools/doc/tsort.hlp
new file mode 100644
index 00000000..f07605e4
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tsort.hlp
@@ -0,0 +1,84 @@
+.help tsort Dec90 tables
+.ih
+NAME
+tsort -- Sort a table on one or more columns.
+.ih
+USAGE
+tsort table columns
+.ih
+DESCRIPTION
+This task sorts an STSDAS-format table. The sort is done in place, so if you want
+to keep a copy of the unsorted table, you should copy it with the 'tcopy'
+task before you
+do the sort. The column, or columns, on which to sort are specified
+using the parameter
+'columns', which is a list of column names, or column name templates,
+separated by
+commas. The most significant column name is the first in the list---the
+column whose values are sorted; subsequent
+columns are used only to break ties. There are two flags, 'ascend' and
+'casesens'. The 'ascend' parameter determines whether the sort is done
+in ascending or descending order, if
+'ascend = yes', the first row in the output table holds the lowest value (if
+the sorted column is numeric) or the first string in alphabetic order (if the
+sorted column is a character string). If 'casesens = yes', upper
+case characters
+precede lower case characters. Otherwise, case is not significant
+in determining the sort order. When sorting a boolean column, "no" precedes
+"yes". Null table elements are always last in the sort, regardless
+of the value of 'ascend'.
+.ih
+PARAMETERS
+.ls table [file name template]
+Name of the table, or tables, to be sorted in-place.
+All tables are sorted on the same column or columns; if more than one table
+is specified all tables must have the column(s) specified by the 'columns'
+parameter.
+.le
+.ls columns [string]
+Column name or column name template describing columns on which sort will
+be performed. A column name template consists of a list of
+column names, or column patterns containing wildcard characters.
+Individual column names, or templates, are separated by commas or white space.
+The list of columns can be placed in a file and the name of the
+file passed to 'columns' (preceded by a
+"@" character).
+.le
+.ls (ascend = yes) [boolean]
+Sort the table in ascending order? If you want the table sorted in descending
+order, set 'ascend = no'.
+.le
+.ls (casesens = yes) [boolean]
+Are sorts on character columns to be case sensitive? If 'casesens = yes',
+upper case letters will precede lower case letters. If 'casesens = no',
+case is ignored by the sort operation.
+.ls
+.ih
+EXAMPLES
+1. Sort a table of star positions by right ascension and declination:
+
+.nf
+tt> tsort starcat.tab ra,dec
+.fi
+
+2. Sort a phone list. Make the sort case insensitive:
+
+.nf
+tt> tsort phone.tab lname,fname case-
+.fi
+
+3. Sort a star catalog so that all binary stars (i.e., a boolean column
+named 'binary') are first:
+
+.nf
+tt> tsort starcat.tab binary asc-
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+tcopy
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tstat.hlp b/pkg/utilities/nttools/doc/tstat.hlp
new file mode 100644
index 00000000..709ddd57
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tstat.hlp
@@ -0,0 +1,225 @@
+.help tstat Jan2001 tables
+.nj
+.ih
+NAME
+tstat -- Get statistics for a table column.
+.ih
+USAGE
+tstat intable column
+.ih
+DESCRIPTION
+This task gets the mean, standard deviation, median, minimum and maximum
+values for a table column.
+The output will be written to cl parameters and may also be written either
+to the standard output (STDOUT) or to a table.
+When more than one table is specified as 'intable', the statistics are
+determined for each table separately, not cumulatively. The values
+in the cl parameters therefore refer to the last table in the list.
+
+If an input table contains only one column
+(either in fact or due to the use of a column selector with the table name),
+then the 'column' parameter is ignored,
+and statistics are computed for that one column.
+If 'intable' includes more than one table,
+the 'column' parameter may be required for some tables
+(those with more than one column) but not for others.
+
+The range of rows to use for statistics
+may be restricted either by the 'rows' parameter
+or by use of a row selector with the table name.
+Both may be used, in which case 'rows'
+is interpreted to mean selected row numbers,
+rather than rows in the underlying table.
+That is, the row selector with the table name is applied first,
+then the 'rows' parameter is used to further restrict the rows.
+
+For a column that contains arrays,
+this task reads all elements of all selected rows
+and computes statistics on all those elements together.
+Typical usage for array columns would be to specify just one row,
+but any number of rows may be included,
+limited only by memory.
+
+Lower and upper limits may be set using the parameters 'lowlim' and 'highlim'
+such that table values outside that range are not used when computing
+the statistics.
+Either the lower or upper limit may be set individually.
+If there are no values within the range specified
+and within the range of rows given by the 'rows' parameter,
+then the average, etc, will be printed as INDEF.
+
+For some tables, one can get statistics on the data in a row
+by using 'tdump' and piping the output to 'tstat'.
+See the examples for more information.
+.ih
+PARAMETERS
+.ls intable [file name template]
+A list of input tables.
+Statistics will be obtained for one column, the same name in every table.
+If the input is redirected,
+this parameter need not be specified;
+that is, if there's only one command-line argument,
+it will be taken to be the column name.
+.le
+.ls column [string]
+Column in input tables.
+The statistics are gotten for the values in the column with this name.
+If an input table contains only one column,
+this parameter will be ignored,
+and you will not even be prompted for a value.
+If 'intable' includes more than one table with only one column,
+the column name does not need to be the same in each of these tables.
+For tables containing more than one column,
+this parameter is required,
+and the same column name will be used for each table in the list
+that contains more than one column.
+.le
+.ls (outtable = "STDOUT") [string]
+Output table, STDOUT, or null.
+If 'outtable' is null ("") then the results will only be written to cl
+parameters (see 'nrows', 'mean', 'stddev', 'vmin', 'vmax').
+If 'outtable' is "STDOUT" then the results will be written to
+the standard output preceded by a header line (beginning with #)
+that gives the name of the table and the name of the column.
+If 'outtable' is not "STDOUT" and is not null then it is interpreted as
+a table name (just one name), and the statistics for the input tables
+will be written to separate rows of the output table.
+If the table already exists,
+the rows will be appended to what is already there.
+The output column names are given by
+the parameters 'n_tab', 'n_nam', 'n_nrows', etc.
+.le
+.ls (lowlim = INDEF) [real]
+Values below this are ignored.
+.le
+.ls (highlim = INDEF) [real]
+Values above this are ignored.
+.le
+.ls (rows = -) [string]
+Range of rows to use for statistics.
+The default "-" means that all rows are used.
+See the help for RANGES in XTOOLS for a description of the syntax.
+.le
+.ls (n_tab = table) [string]
+Column name for name of input table.
+This and other parameters that begin with "n_" are only used if the output values are
+written to a table.
+.le
+.ls (n_nam = column) [string]
+Column name for name of input column.
+This and other parameters that begin with "n_" are only used if the output values are
+written to a table.
+.le
+.ls (n_nrows = nrows) [string]
+Column name for number of good rows.
+.le
+.ls (n_mean = mean) [string]
+Column name for mean.
+.le
+.ls (n_stddev = stddev) [string]
+Column name for standard deviation.
+.le
+.ls (n_median = value) [string]
+Column name for median.
+.le
+.ls (n_min = min) [string]
+Column name for minimum.
+.le
+.ls (n_max = max) [string]
+Column name for maximum.
+.le
+.ls (nrows) [integer]
+The number of rows for which the column value was not INDEF and was
+within the range 'lowlim' to 'highlim'.
+This is a task output parameter.
+.le
+.ls (mean) [real]
+Mean value (of the last table in the input list 'intable').
+This is a task output parameter.
+.le
+.ls (stddev) [real]
+Standard deviation of the values (not of the mean).
+This is a task output parameter.
+.le
+.ls (median) [real]
+Median value.
+This is a task output parameter.
+.le
+.ls (vmin) [real]
+Minimum.
+This is a task output parameter.
+.le
+.ls (vmax) [real]
+Maximum.
+This is a task output parameter.
+.le
+.ih
+EXAMPLES
+1. Get statistics on column "flux" in all tables, putting the output
+(assuming outtable="STDOUT") in the ASCII file 'flux.lis':
+.nf
+
+ tt> tstat *.tab flux > flux.lis
+.fi
+
+2. In order to get statistics on the data
+in a row rather than a column,
+you can use 'tdump' for one row
+and specify pwidth to be so small that
+each value will be printed on a separate line.
+The output of 'tdump' will then be a one-column table
+containing the row from the input table,
+and 'tstat' can be run on that one-column table.
+Since the input is redirected, we don't specify the table name.
+Note also that in this case the input contains only one column,
+so we don't specify the column name either.
+In this example, we get statistics on row 17 of "bs.fits":
+.nf
+
+ tt> tdump bs.fits cdfile="" pfile="" \
+ >>> row=17 pwidth=15 | tstat
+.fi
+
+3. When the input is redirected and has multiple columns,
+the command-line argument should be the column name to use,
+not the table name.
+The table name in this case will internally be set to "STDIN".
+.nf
+
+ tt> dir l+ | tstat c3
+.fi
+
+4. The statistics on column "flux" in 'hr465.tab' are put in parameters
+'tstat.nrows', 'tstat.mean', etc.,
+and are not written to STDOUT or to a table.
+We only include rows for which column V is no larger than 12.
+.nf
+
+ tt> tstat "hr465.tab[r:v=:12][c:flux]" outtable=""
+.fi
+
+5. The output statistics are written to a table. The default column name
+for the mean value is overridden:
+.nf
+
+ tt> tstat hr465.tab flux outtable=hr465s.tab n_mean="mean_flux"
+.fi
+
+6. Get statistics on column "flux" in table 'hr465.tab', but only for
+rows 17 through 116, row 271, and row 952:
+.nf
+
+ tt> tstat hr465.tab[c:flux] outtable="STDOUT" row="17-116,271,952"
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+.ih
+SEE ALSO
+thistogram, ranges
+
+Type "help tables opt=sys" for a higher-level description of the 'tables'
+package.
+.endhelp
diff --git a/pkg/utilities/nttools/doc/ttranspose.hlp b/pkg/utilities/nttools/doc/ttranspose.hlp
new file mode 100644
index 00000000..9a1a7c25
--- /dev/null
+++ b/pkg/utilities/nttools/doc/ttranspose.hlp
@@ -0,0 +1,139 @@
+.help ttranspose Nov94 tables
+.nj
+.ih
+NAME
+ttranspose -- Transpose or flip a table.
+.ih
+USAGE
+ttranspose intable outtable action
+.ih
+DESCRIPTION
+This task can be used to transpose a table
+so that input rows become output columns
+and input columns become output rows.
+Another option is to flip the table horizontally,
+that is, the first input column is the last output column.
+Finally, the table can be flipped vertically,
+i.e., the first input row is the last output row.
+Any combination of these operations may be performed.
+
+If the table is actually transposed
+(rather than just flipped horizontally and/or vertically),
+the data types of all input columns must be the same.
+In addition, if the columns contain arrays rather than scalars,
+all the array lengths must be the same.
+The data type and array size will be preserved in the output table,
+but the column names of the output table will be "c1", "c2", "c3", etc,
+with default print format and null units.
+Actually, some mixing of data types is permitted.
+If some columns are type real and others are double precision,
+the output data type will be double precision.
+Similarly, short integers will be promoted to integers.
+Boolean columns can be mixed with any other data type;
+for numeric columns, yes becomes 1 and no becomes 0.
+When the columns in the input table are character strings,
+different maximum string lengths are permitted,
+and the output length will be the maximum of the input lengths.
+The restrictions on data type are not imposed on text tables,
+which can contain mixed integer, double precision and text columns.
+
+If the table is only flipped but not transposed,
+the above restrictions on data type do not apply,
+and the column names, units and print formats will be preserved.
+Note that an operation such as "tht"
+(which happens to be equivalent to "v")
+does not actually transpose the table,
+so the data types of the columns need not all be the same.
+
+The 'tstat' task gives statistics for the values in a column,
+so one application of 'ttranspose' is to get statistics on
+the values in a row by first transposing the table and then running 'tstat'.
+
+Text tables with too many rows cannot be transposed
+due to the limit of 1024 on the length of each row of a text table.
+.ih
+PARAMETERS
+.ls intable [file name template]
+The list of input table names.
+.le
+.ls outtable [file name template]
+The list of output table names.
+There must be the same number of input and output names.
+If the output is to be written to the standard output, however,
+you can use outtable = "STDOUT" even if there several input tables.
+.le
+.ls action = "t" [string]
+This is a string made up of the letters "t", "h", and "v"
+which specify the operations to perform on the tables.
+"t" means transpose (input rows become output columns),
+"h" means flip horizontally (reverse the order of the columns),
+and "v" means flip vertically (reverse the order of the rows).
+The operations are performed in the order given from left to right.
+Any combination of "t", "h", and "v" may be used,
+in any order, and the letters may be repeated.
+
+Operations such as "tt", "hh" or "vv" are valid,
+and they result in a simple copy of input to output.
+
+The symbols "/", "-" and "|" are equivalent to
+the letters "t", "h" and "v" respectively.
+.le
+.ls verbose = yes [boolean]
+Print the names of the tables as they are processed?
+.le
+.ih
+EXAMPLES
+1. The input is the text file "in",
+and the output is to be displayed on the screen.
+Each of the three operations ("t", "h", "v")
+and some combinations are illustrated.
+
+.nf
+ tt> type in
+ one two three
+ four five six
+ seven eight nine
+ ten eleven twelve
+
+ tt> ttranspose in STDOUT t
+ in --> STDOUT
+ one four seven ten
+ two five eight eleven
+ three six nine twelve
+
+ tt> ttranspose in STDOUT h
+ in --> STDOUT
+ three two one
+ six five four
+ nine eight seven
+ twelve eleven ten
+
+ tt> ttranspose in STDOUT v
+ in --> STDOUT
+ ten eleven twelve
+ seven eight nine
+ four five six
+ one two three
+
+ tt> ttranspose in STDOUT hv
+ in --> STDOUT
+ twelve eleven ten
+ nine eight seven
+ six five four
+ three two one
+
+ tt> ttranspose in STDOUT th
+ in --> STDOUT
+ ten seven four one
+ eleven eight five two
+ twelve nine six three
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+.ih
+SEE ALSO
+Type "help ttools opt=sys" for a description of the 'tables' package.
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tunits.hlp b/pkg/utilities/nttools/doc/tunits.hlp
new file mode 100644
index 00000000..553ebb6e
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tunits.hlp
@@ -0,0 +1,143 @@
+.help tunits Jan99 ttools
+.ih
+NAME
+tunits -- Convert a table column from one set of units to another
+.ih
+USAGE
+tunits table column newunits
+.ih
+DESCRIPTION
+Tunits converts a column in a table from one set of units to
+another. It supports both scalar and array columns. You supply the
+table and column name and the new units you want the column to be
+in. Optionally, you can apply the current column units if the units
+string stored in the table is missing or incorrect. Tunits only
+supports multiplicative conversions, conversions that involve additive
+changes, like Kelvin to Celsius, are not supported. Unit names and
+conversions are read from two tables. You can copy these tables and
+edit them if you want to add new conversions.
+
+You can find out the current units for a table column by running
+tlcol. If a units conversion is not supported by this task and you
+know the conversion formula, you can run tcalc.
+
+Tunits must parse the unit strings you pass it, which requires that
+they follow a certain set of rules. Units can be a simple units name,
+such as ergs, or a units name raised to a power, such as meters^2, or
+the product or quotient of units names raised to a power, such as
+feet/sec or gm*cm/s^2. If two units names are next to each other
+without any operator between them, a multiplication is assumed. If a
+units name is followed by a number, the units name is assumed to be
+raised to that power.
+
+Powers can also be specified by preceding the unit name with the
+string "square", "sq", "cubic", or "cu". For example, "square meter"
+is equivalent to "meter^2".
+
+The operators recognized are:
+
+.nf
+division / or per
+multiplication *
+exponentiation ^ or **
+.fi
+
+Division has the lowest priority and exponentiation the highest. This
+means ergs/sec*angstrom is interpreted as ergs/(sec*angstrom) and not
+(ergs/sec)*angstrom, as it would be in most computer languages. The
+default priority can be changed by changed by grouping terms with
+parentheses.
+
+Each set of units can have several synonymous names. These names are
+listed in the abbreviations table. Case is not significant in names
+and regular plurals (made by adding an "s") are converted to the
+singular. Names should contain only alphabetic characters. Blanks,
+underscores and digits are not allowed.
+
+The conversions supported by this task are read from the units
+conversion table. The table lists the old and new units and a
+conversion factor. Only one conversion is allowed for each set of
+units.
+
+.ih
+PARAMETERS
+.ls table [file]
+The name of the table the conversion is applied to.
+.le
+.ls column [string]
+The column to be converted. Both scalar and array columns are
+supported.
+.le
+.ls newunits [string]
+The new set of units for the column. The format of this parameter is
+described above. This task writes the new units to the units field in
+the table column.
+.le
+.ls (oldunits = " ") [string]
+The units that the table column is currently in. If the value of this
+parameter is blank, the units will be read from the table.
+.le
+.ls (abrevtab = "ttools$tunits/abrev.tab") [file]
+A table of alternate names for each unit. This table contains two
+columns. The first column is the name of the units and the second
+column is the standard abbreviation. Because the default table is an
+ascii file, columns are read positionally and not by column names
+
+Many units have more than one name or abbreviation. Using a standard
+abbreviation allows units to be converted to a standard form, which
+simplifies calculations. The standard abbreviation is used internally
+when computing the conversion factor. Case is not significant in names
+and regular plurals (made by adding an "s") are converted to the
+singular before looking them up in the table. Names should contain
+only alphabetic characters. Blanks, underscores and digits are not
+allowed.
+
+The name of this table is a parameter to allow you to create your own
+table of standard abbreviations, with additional units.
+.le
+.ls (unittab = "ttools$tunits/units.tab") [file]
+A table of conversion factors from one set of units into another.
+This table contains four columns. The first is the conversion factor,
+a double precision number. The second is the units the task tries to
+convert from. The third column is the units the task tries to convert
+to. The fourth column is contains the boolean variable swap, explained
+a little later.
+
+The table is interpreted as "There are <factor> <from> in a <to>."
+For example, "There are 100 centimeters in a meter." The last column,
+swap, does not change the sense of the sentence but does change the
+direction that the conversion is applied, For example, "60 seconds in
+a minute" is actually a conversion from minutes to seconds because
+swap is yes. Unit conversions should set swap to yes when the desired
+conversion is not an exact value, but its inverse is. Only one
+conversion is allowed per unit, which simplifies the program logic
+considerably. Conversions should be chosen so that they ultimately
+resolve to MKS units. To prevent endless loops conversions from the
+fundamental units of MKS are checked for and forbidden. However, the
+program does not check for other loops, so be careful when adding new
+conversions!
+
+As in the case of the abbreviation table, the table name is a
+parameter to allow you to create your own table with additional unit
+conversions.
+.le
+.ls (verbose = no) [bool]
+If you set this parameter to yes, the task will print a message to
+STDERR for each units conversion utilized in computing the conversion
+factor.
+.le
+.ih
+EXAMPLES
+Convert watts to ergs per second. Print the diagnostic messages:
+
+.nf
+tt> tunits source.tab power "ergs/sec" old=watts verb+
+.fi
+.ih
+REFERENCES
+This task was written by Bernie Simon
+.ih
+SEE ALSO
+tlcol, tcalc
+
+.endhelp
diff --git a/pkg/utilities/nttools/doc/tupar.hlp b/pkg/utilities/nttools/doc/tupar.hlp
new file mode 100644
index 00000000..3c8d99b3
--- /dev/null
+++ b/pkg/utilities/nttools/doc/tupar.hlp
@@ -0,0 +1,365 @@
+.help tupar Jun97 tables
+.nj
+.ih
+NAME
+tupar -- Edit table header parameters.
+.ih
+USAGE
+tupar table
+.ih
+DESCRIPTION
+This task is an interactive editor that allows the user to modify table
+header parameters.
+Prompts are written to STDERR rather than
+STDOUT so that STDOUT can be redirected to a file.
+If STDERR is redirected, no prompts will appear.
+Prompting is also turned off if the input is redirected from a file.
+
+The table to be edited is copied to a temporary table
+in the same directory as the original table
+(or in tmp$ if the first copy attempt fails),
+and the changes are made to that copy.
+When you exit 'tupar',
+the copy is renamed back to the name of the original table.
+If you quit rather than exit,
+then the copy is deleted, so the original table will remain unchanged.
+
+The prompt ":" is used by the task when it is waiting for user input.
+At this prompt the user can enter any editor command.
+The "e" command (or end of file, e.g. Control-Z) will exit the editor.
+The following commands are available: e, q, g, p, d, r, k, t, l.
+These commands are interpreted as exit, quit (without saving changes),
+get, put, delete, replace, change keyword name, type, and list respectively.
+Each of these commands is described in detail below:
+
+The exit command, specified by "e" or end of file,
+will close the file--saving all changes,
+and open the next file if more than one file was specified
+for the 'table' input parameter.
+
+The quit command is similar to exit except that changes that were made
+to the header parameters will not take effect,
+unless 'inplace = yes'.
+If changes were made to the table header
+you will be prompted for confirmation
+unless the command was given followed by "!";
+for example, "q!" or "quit!".
+
+The type command, specified by "t", and the list command,
+specified by "l",
+both display header parameters---one header per line of output.
+The difference between the two commands is that list will show the parameter
+number and type will not.
+Entering the command "t" or "l" will produce
+a listing of all header parameters.
+Optionally, an integer may follow
+the command indicating that only a particular parameter is to be displayed.
+Two integers following the command indicate a range of parameters.
+If a number is specified that is beyond the range of valid headers,
+an error message will be displayed.
+The output consists of the name of the header parameter,
+its data type (indicated by a single letter,
+"r" for real, "b" for boolean, "i" for integer, or "d" for double),
+and its current value.
+If the keyword has an associated comment,
+the comment will be displayed following the value.
+The following are examples of valid syntax for listing header parameters:
+.nf
+t
+l
+t 3
+l 300 310
+.fi
+
+The get command, indicated by "g", will look for a specific keyword and
+display its current value.
+Optionally, the data type can be specified
+using the letter "r" for real, "i" for integer, "d" for double, or
+"b" for boolean.
+If no data type is specified, then the type is assumed to be text.
+If the data type is specified,
+the type immediately follows the "g" command;
+for example, typing the command "gd X" will get the value
+contained in the header keyword "X" and display it as a double-precision
+real value.
+If "X" does not exist, no output will be produced.
+If the keyword has an associated comment,
+the get command displays the comment following the value;
+a text string value will be enclosed in quotes
+to distinguish the value from the comment.
+Examples of valid syntax follow:
+.nf
+g history
+gd coeff0
+gi numpts
+.fi
+
+The put command, specified by "p", will either replace the value of an
+existing parameter,
+or it will create a new parameter if the specified parameter is not found.
+The "p" command is followed on the command line by a keyword
+name and the parameter value.
+A comment may optionally follow the value.
+The "p" command itself should
+be followed by a single letter type specifier, "i" for integer,
+"r" for real, "d" for double, or "b" for boolean.
+If no type is specified, then the data type is assumed to be text.
+In order to specify a comment with a parameter of type text,
+the parameter value must be enclosed in quotes
+in order to distinguish it from the comment. (Keyword names
+HISTORY and COMMENT are already comments,
+and further comments cannot be added to them.)
+Examples of valid put command syntax follow:
+.nf
+p comment Created for testing.
+gd coeff0
+pd coeff0 3.141592653589793
+pi ncoeff 7 number of coefficients
+pt fittype chebychev
+pt fittype "chebychev" type of fit that these coefficients represent
+.fi
+
+The replace command, specified by "r", works much like the put command
+described above; however, it will prompt the user for confirmation before
+actually changing any values in the table.
+A parameter can be specified by name or by number.
+The "r" command will not change a keyword name or a data type,
+whereas the "p" command can.
+After the command is entered,
+the current value of the keyword is displayed and
+the editor waits for a new value to be entered by the user.
+Pressing the return key indicates that no change is to be made.
+Pressing the space bar will blank the current value.
+You will then be prompted for
+confirmation unless the command was issued as "r!" or the input was
+redirected from a file.
+The default action is given by the 'delete_default' parameter.
+
+A range of contiguous parameters can be replaced at one time by giving
+the names or numbers of the first and last parameters to be replaced.
+This can involve a lot of prompting for confirmation,
+especially if several tables are being edited with 'same=yes'.
+In this context, "contiguous" means adjacent in the table header.
+Thus, when replacing a range by name,
+it is not the parameters that fall alphabetically within the limits
+that will be replaced
+but rather the parameters that are numerically within the limits.
+When editing a list of tables with 'same=yes',
+the same replacement string is used for each table.
+Thus it is essential that there be the same number of parameters in
+the range in all tables being edited.
+When no replacement value is given (i.e., just hit the return key),
+then the current keyword value is not changed,
+either in the first table or in subsequent tables.
+
+Sample replace commands follow:
+.nf
+r coeff0
+r 17
+r! 17
+r junk dummy
+r junk 12
+r 5 12
+.fi
+
+The delete command, specified by "d", will delete a header parameter by
+either name or number.
+The editor prompts for confirmation of delete,
+unless input is redirected from a file.
+The default action is given by the 'delete_default' parameter.
+If you do not want to be prompted for confirmation, enter the command as "d!".
+If you want to delete a history or comment record other than the first,
+you can identify the parameter by number rather than name.
+
+A range of contiguous parameters can be deleted at one time by giving
+the names or numbers of the first and last parameters to be deleted.
+As with replacing a range of parameters,
+a contiguous block of parameters will be deleted.
+
+Examples of valid delete commands follow:
+.nf
+d testflag
+d 17
+d! 17
+d junk dummy
+d junk 12
+d 5 12
+.fi
+
+The "k" command changes the name of a keyword
+without changing the data type, value, or comment.
+Give the current and new keyword names following the "k".
+Note that keywords are limited to eight characters.
+If the name of a COMMENT or HISTORY keyword is changed,
+only the first occurrence of that keyword will be changed.
+
+Examples of valid change keyword commands follow:
+.nf
+k history comment
+k dummy test
+.fi
+.ih
+PARAMETERS
+.ls table [file name template]
+A table name or list of table names whose header parameters are to be edited.
+Unless 'inplace = yes',
+each table will be copied (one at a time) to a temporary table,
+and changes are made to the copy until you exit.
+This can cause problems if there is not enough disk space for the copy;
+however, the 'inplace' parameter can
+be set to "yes" so that the tables are opened in-place.
+.le
+.ls (same = no) [boolean]
+Apply the same set of instructions to all tables?
+
+This is only relevant when more than one table is being edited.
+If 'same = no', instructions are processed separately for each table,
+with the "e" command used to end processing of a table and open
+the next table.
+
+If 'same = yes', the same instruction set is applied to all tables.
+These instructions will be read from STDIN (which may be redirected)
+and saved in a local buffer while the first table in the list is open.
+For each subsequent table the instructions will be read from the local buffer.
+Caution is advised when deleting or replacing parameters, especially by
+number; remember that prompting for confirmation is turned off if the
+input is redirected or if the instruction is given as "d!" or "r!".
+
+If 'same = yes' and you quit (rather than exit) from editing the first table,
+the behavior of the task depends on whether changes were made before quitting.
+If changes were made then the task aborts immediately
+without opening the other tables in the input list.
+If no change was made then the other tables are processed.
+The idea is to allow "g", "t", and "l" commands
+and still be able to quit rather than exit,
+since nothing was modified.
+If changes were made but you quit,
+that's interpreted as trying to recover from an error,
+so we don't change the first table and we don't continue.
+.le
+.ls (verbose = yes) [boolean]
+Display the name of each table when it is opened?
+
+If STDOUT is redirected
+then these file names will be written to STDERR as well as to STDOUT.
+.le
+.ls (readonly = no) [boolean]
+Prevent changes from being made to the file?
+
+If 'readonly = yes', then the
+table is opened with read only access. This is useful for viewing the
+contents of the table while at the same time preventing changes from
+being made to it. (Only the "g", "t", and "l" commands are useful in
+read only mode).
+.le
+.ls (inplace = no) [boolean]
+Edit the original table in-place?
+
+By default a copy of the original table is made,
+either in the same directory or in tmp$.
+This makes it possible to quit without saving changes.
+If the table is large, however,
+it may be undesirable to make a copy,
+so the 'inplace' parameter gives you the option
+of editing the original table.
+In this case, however, it will not be possible to quit without saving changes.
+.le
+.ls (quit_default = no) [boolean]
+The value of this parameter is the default response to the prompt
+for confirmation if you give the quit command.
+.le
+.ls (delete_default = yes) [boolean]
+The value of this parameter is the default response to the prompt
+for confirmation for the delete and replace commands.
+.le
+.ls go_ahead [boolean]
+The user does not set this explicitly.
+It is the parameter which is actually gotten in response to a prompt.
+.le
+.ih
+EXAMPLES
+1. This example reads all history records from all tables in the default
+directory and writes them to 'history.lis'.
+.nf
+
+tt> tupar *.tab same=yes verbose=no readonly=yes >history.lis
+ (The task writes a ":" prompt and waits for input.)
+:g history
+:q
+tt>
+.fi
+
+2. This example illustrates the use of each of the commands when editing
+parameters in one table. This kind of interactive use of the task
+would not be appropriate when operating on a list of tables unless
+the 'same' parameter is set to "no".
+.nf
+
+tt> tupar junk
+ (The task writes the table name and a ":" prompt and waits for input.)
+junk.lis
+:g garvage
+ (The keyword was not found, so nothing was displayed.)
+:g garbage
+GARBAGE = 3.1416926535
+:pd garbage 3.1415926535
+:p comment yet another comment
+:t
+GARBAGE d 3.1415926535
+COMMENT t This is the first comment.
+PI t 3.1415926535 not an accurate value
+COMMENT t yet another comment
+:l 3 999
+ 3 PI t '3.1415926535' not an accurate value
+ 4 COMMENT t yet another comment
+:g pi
+PI = '3.1415926535' not an accurate value
+:gd pi
+PI = 3.1415926535 not an accurate value
+:pd pi 3.14159265358979323846 a more accurate value
+:l
+ 1 GARBAGE d 3.1415926535
+ 2 COMMENT t This is the first comment.
+ 3 PI d 3.141592653589793 a more accurate value
+ 4 COMMENT t yet another comment
+:d garbage
+The following parameter is to be deleted:
+GARBAGE d 3.1415926535
+ ... OK to delete ? (yes): (user hits return)
+:d comment
+The following parameter is to be deleted:
+COMMENT t This is the first comment.
+ ... OK to delete ? (yes): n (user types n)
+:l 4
+parameter out of range; max is 3
+:d 3
+The following parameter is to be deleted:
+COMMENT t yet another comment
+ ... OK to delete ? (yes): (user hits return)
+:t
+COMMENT t This is the first comment.
+PI d 3.141592653589793 a more accurate value
+:r 1
+keyword COMMENT, type t; give replacement value:
+This is the first comment. (TUPAR writes this & waits)
+this is a comment (this line entered by user)
+Current parameter and its replacement are:
+COMMENT t This is the first comment.
+COMMENT t this is a comment
+ ... OK to replace ? (yes): n (user types n)
+no action taken
+:q
+tt>
+.fi
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Phil Hodge.
+.ih
+SEE ALSO
+tprint, tdump, tedit
+
+Type "help tables opt=sys" for a higher-level description of the 'tables'
+package.
+.endhelp
diff --git a/pkg/utilities/nttools/doc/wcspars.hlp b/pkg/utilities/nttools/doc/wcspars.hlp
new file mode 100644
index 00000000..12e2dae1
--- /dev/null
+++ b/pkg/utilities/nttools/doc/wcspars.hlp
@@ -0,0 +1,184 @@
+.help wcspars Jul93 tables
+.ih
+NAME
+wcspars -- Edit the parameter set that defines a world coordinate
+system.
+.ih
+USAGE
+wcspars
+.ih
+DESCRIPTION
+The parameters in this pset are used to define a simple world
+coordinate system (WCS) for use by various tasks that require such
+information, such as 'wcslab' or 'siaper'.
+
+Note that this is a pset, not an executable task; it defines a set of
+parameters used by other tasks. Invoking the pset by name runs 'eparm'
+on the parameter set, allowing the user to modify the parameters.
+Alternatively, the parameters may be modified on the command linne by
+specifying the pset name and parameter name. For example, you can
+type 'wcspars.ctype="ra---tan"'. Parameters may also be edited by
+using 'eparam' on the calling task. An example is the task 'wcslab'. By
+typing 'eparam wcslab', positioning the cursor on the parameter
+'wcspars', and type ':e', the user would then be editing the parameters
+in this pset.
+
+A WCS is used to transform coordinates from one system to another.
+For example, for converting from pixel coordinates to celestial
+coordinates. To perform such transformations, certain information is
+required, such as the type of system. Below is a brief description of
+the IRAF implementation of WCS and how to the parameters in this pset
+to define a WCS.
+
+The IRAF implementation defines a transformation from some "logical"
+system (e.g., pixel space) to some "world" system (e.g., RA and DEC).
+The first piece of information required is the type of world system is
+being dealt with. At the moment, there are two general systems
+defined: 'linear' which provides a linear mapping from the logical to
+world systems, and the celestial projects which provide a mapping from
+pixel space to celestial coordinate space. The parameters 'crtype1' and
+'ctype2' are used to specify the type of system. If a linear system is
+desired, both parameters will have the value "linear". If the TANGENT
+plane projection is desired where the first axis represents RA and the
+second represents DEC, then the parameters would have the values,
+'ctype1 = "ra---tan"', 'ctype2 = "dec--tan"'. There are also a sine
+projection (SIN) and arc (ARC) projection provided.
+
+The scale factor and rotation between the two systems are defined by
+a coordinate transformation (CD) matrix. Through matrix
+multiplication, the logical coordinates are multiplied by the CD
+matrix to produce the world coordinates. The matrix is represented in
+the parameters as follows:
+.nf
+
+ |---------------|
+ | cd1_1 cd1_2 |
+ | |
+ | cd2_1 cd2_2 |
+ |---------------|
+
+.fi
+To construct the CD matrix, the following definitions may be used:
+.nf
+
+ cd1_1 = Sx * cos(PA)
+ cd1_2 = -Sy * sin(PA)
+ cd2_1 = Sx * sin(PA)
+ cd2_2 = Sy * cos(PA)
+
+.fi
+where Sx and Sy are the scale factors from the logical to world
+systems and PA is the angle of rotation between the two systems
+(positive rotation is counterclockwise).
+
+There is a special case for the transformation to RA and DEC. Since RA
+increases "to the left", opposite of standard convention, -1 needs
+to be multiplied through the CD matrix for the first axis. This
+results in the formulas below:
+.nf
+
+ cd1_1 = -Sx * cos(PA)
+ cd1_2 = Sy * sin(PA)
+ cd2_1 = Sx * sin(PA)
+ cd2_2 = Sy * cos(PA)
+
+.fi
+
+Finally, the origins of the logical and world systems must be defined.
+The parameters 'crpix1' and 'crpix2' define the coordinate in the logical
+space that corresponds to the coordinate in world space defined by the
+parameters 'crval1' and 'crval2'. Quite simply, the coordinate (crpix1,
+crpix2) in the logical space, when transformed to the world space,
+would be the coordinate (crval1, crval2).
+
+The last set of parameters, 'log_x1', 'log_x2', 'log_y1', 'log_y2', define a
+region in the logical space over which the transformation is valid.
+.ih
+PARAMETERS
+.ls (crtype1 = "linear") [string]
+The system type of the first axis. Possible values depend on what
+transformations have been implemented in the IRAF system. To date the
+following values represent valid transformations: linear, xxx--tan,
+xxx-sin, xxx-arc (where xxx is either "ra-" or "dec"). Note that if any
+of the celestial transformations are used, the "ra" must appear in one
+of 'crtype1' or 'crtype2' and "dec" must appear in the other parameter.
+.le
+.ls (crtype2 = "linear") [string]
+The system type of the second axis. See above for values.
+.le
+.ls (crpix1 = 0.) [real]
+The X coordinate of the reference point in logical space that
+corresponds to the reference point in the world space.
+.le
+.ls (crpix2 = 0.) [real]
+The Y coordinate of the reference point in logical space that
+corresponds to the reference point in the world space.
+.le
+.ls (crval1 = 0.) [real]
+The X coordinate of the reference point in world space that
+corresponds to the reference point in the logical space.
+.le
+.ls (crval2 = 0.) [real]
+The Y coordinate of the reference point in world space that
+corresponds to the reference point in the logical space.
+.le
+.ls (cd1_1 = 1.) [real]
+Entry in the CD matrix. Usually has the value <xscale * cos(angle)>,
+or for RA and DEC systems, <-xscale * cos(angle)>.
+.le
+.ls (cd1_2 = 0.) [real]
+Entry in the CD matrix. Usually has the value <-yscale * sin(angle)>,
+or for RA and DEC systems, <yscale * sin(angle)>.
+.le
+.ls (cd2_1 = 0.) [real]
+Entry in the CD matrix. Usually has the value <xscale * sin(angle)>.
+.le
+.ls (cd2_2 = 1.) [real]
+Entry in the CD matrix. Usually has the value <yscale * cos(angle)>.
+.le
+.ls (log_x1 = 0.) [real]
+The lower X axis extent in logical space over which the transformation
+is valid.
+.le
+.ls (log_x2 = 0.) [real]
+The upper X axis extent in logical space over which the transformation
+is valid.
+.le
+.ls (log_y1 = 0.) [real]
+The lower Y axis extent in logical space over which the transformation
+is valid.
+.le
+.ls (log_y2 = 0.) [real]
+The upper Y axis extent in logical space over which the transformation
+is valid.
+.le
+.ih
+EXAMPLES
+1. The following example
+is for an image that does not contain any WCS information.
+The image is 512x512 pixels, where the pixels are approximately 1/10th
+an arcsecond in size, whose center pixel is located at 9h 22m 30.5s
+and -15o 5m 42s and is rotated 30 degrees towards the west:
+.nf
+
+ ctype1 = 'ra---tan'
+ ctype2 = 'dec--tan'
+ crpix1 = 256.0
+ crpix2 = 256.0
+ crval1 = 140.62708
+ crval2 = -15.09500
+ cd1_1 = -2.405626e-5
+ cd1_2 = 1.388889e-5
+ cd2_1 = 1.388889e-5
+ cd2_2 = 2.405626e-5
+ log_x1 = 1.
+ log_x2 = 512.
+ log_y1 = 1.
+ log_y2 = 512.
+
+.fi
+.ih
+BUGS
+.ih
+SEE ALSO
+.endhelp
diff --git a/pkg/utilities/nttools/doc/wlpars.hlp b/pkg/utilities/nttools/doc/wlpars.hlp
new file mode 100644
index 00000000..08f987a9
--- /dev/null
+++ b/pkg/utilities/nttools/doc/wlpars.hlp
@@ -0,0 +1,440 @@
+.help wlpars Jul93 tables
+.ih
+NAME
+wlpars -- Edit the parameter set that determines how WCS labeling
+appears.
+.ih
+USAGE
+wlpars
+.ih
+DESCRIPTION
+These parameters determine the characteristics of plots that are
+produced by the various tasks that use the World Coordinate System
+(WCS) information from image data. Various
+parameters can be set in 'wlpars', including those controlling
+the appearance of features such as
+major and minor tick marks, the use of grid lines, etc.
+
+Note that this is a pset, not an executable task; it defines a set of
+parameters used by other tasks. Invoking the pset by name runs
+`eparam' on the parameter set, allowing you to modify the
+parameters. Alternatively, the parameters may be modified on the
+command line by specifying the pset name and parameter name. For
+example, the user can type "wlpars.major_grid=no" to not draw lines
+for the major grid, but to include tick marks.
+Parameters can also be edited by
+using `eparam' on the calling task (e.g., by typing "eparam wcslab"),
+in which case, `wlpars' will appear as one of the task parameters; the
+`wlpars' parameters may then be edited by positioning the cursor on
+the line containing the pset name and typing ":e". After editing the
+pset parameters, press Control-Z to return to the main task parameter
+menu.
+
+Below is a list of areas that explain in more detail what the
+parameters in this pset accomplish. This explanation also occurs in
+the help for 'wcslab'.
+
+.ls Axis Specification
+For all linear transformations axis 1 and axis 2 specify which axis in
+the image WCS is being referred to.
+For example in a 2-dimensional image, the FITS image header keywords
+CTYPE1, CRPIX1, CRVAL1, CDELT1,
+CD1_1, and CD1_2 define the world coordinate transformation for axis 1.
+Similarly the FITS image header keywords
+CTYPE2, CRPIX2, CRVAL2, CDELT2,
+CD2_1, CD2_2, define the world coordinate transformation for axis 2.
+
+THIS RULE DOES NOT APPLY TO THE CELESTIAL plane projection WCSs.
+For this type of WCS, axis 1 and axis 2
+always refer to right ascension and declination respectively,
+and 'wcslab' assumes that all axis 1 parameters refer to right
+ascension and all axis 2 parameters refer to declination, regardless of
+which axis in the image WCS actually specifies right ascension and declination.
+
+.le
+.ls Grid Drawing
+There are two types of grid lines and tick marks, "major" and
+"minor". The major grid lines and tick marks are the lines or ticks
+that will be labeled. The minor grid lines or tick marks are plotted
+between the major marks. Whether lines or tick marks are drawn is
+determined by the boolean parameters 'major_grid' and 'minor_grid'.
+If these are set to "yes", lines are drawn; if "no",
+tick marks are drawn. How the lines
+appear is controlled by the parameters 'major_line' and 'minor_line'.
+
+The spacing of minor marks is controlled by the parameters 'axis1_minor'
+and 'axis2_minor'. These parameters specify the number of minor marks
+that will appear between the major marks along the axis 1
+and axis 2 axes.
+
+Spacing of major marks is more complicated. 'wcslab' tries to
+present major marks only along "significant values" in the
+coordinate system. For example, if the graph spans several hours of
+right ascension, the interval between major marks will generally be an
+hour and the major marks will appear at whole hours within the graph.
+If the values chosen by 'wcslab' are unacceptable, the interval and range can
+be modified by the parameters 'axis1_int', 'axis1_beg',
+'axis1_end' for the 'axis 1', and 'axis2_int', 'axis2_beg',
+and 'axis2_end' for 'axis 2'. All three parameters must be specified for
+each axis in order for the new values to take affect
+
+.le
+.ls Graph Appearance
+'wcslab' supports three types of graph: normal, polar, and near_polar.
+
+A normal graph is the usual Cartesian graph where lines of constant
+axis 1 or 2 values cross at least two different sides of the graph.
+'wcslab' will, by default, plot a normal type graph for any image that
+meets the following criteria: 1)
+has no defined WCS, 2) has a linear WCS, and 3) where the sky
+projection WCS approximates a Cartesian system.
+
+A polar graph is one in which the north or south pole of the
+coordinate system actually appears on the graph.
+Lines of constant declination are no longer approximately
+straight lines, but are circles that may not intersect any
+of the edges of the graph. In this type of graph, axis 1 values
+are labeled all the way around the graph.
+Axis 2 values are labeled within the graph
+next to each circle. An attempt is made to label as many circles as
+possible. If you don't like the labeling defaults,
+the parameters, 'axis2_dir' and 'justify' can be modified
+to control how the labeling is done.
+The parameter 'axis2_dir' specifies along which axis 1 value the
+axis 2 labels should be written; 'justify' specifies the side of
+the value on which the label will appear.
+
+The "near_polar" graph is a cross between the normal graph and the polar
+graph. In this case the pole is not on the graph, but is close enough
+to significantly affect the appearance of the plot. The "near_polar" graph
+is handled like a polar graph.
+
+The parameter 'graph_type' can be used to force 'wcslab'
+to plot a graph of the type specified, although you may need to
+change other 'wlpars' parameters to get good results.
+For example, trying to plot a polar graph as
+cartesian may producing a strange looking graph.
+.le
+.ls Graph Labeling
+Due to the variety of graph types that can be plotted (see above), and
+the arbitrary rotation that any WCS can have, the task of labeling
+the major grid lines in a coherent and pleasing manner is not trivial.
+
+The basic model used is the cartesian or normal graph. Labels
+normally appear on the left and bottom edges of the graph with one side
+devoted solely to one of the WCS coordinate axis. For example, right
+ascension might be labeled only along the bottom edge of the graph
+and declination only along the left edge, or vice versa.
+
+If the defaults chosen by the task are unacceptable, the
+parameters 'axis1_side' and 'axis2_side', can be used to specify which
+side (or sides) the labels for axis 1 and axis 2 will appear.
+Either a single side or a list of sides can be specified for either
+axis. If a list is specified, labels will appear on each side listed,
+even if the same side appears in both of the parameters. In this way,
+labels can be made to appear on the same side of the graph.
+.le
+.ls Label Appearance
+Due to coordinate rotations, lines of constant axis 1 or axis 2 value
+may not intersect the edges
+of the graph perpendicularly. To help clarify which line belongs to
+which label, the labels will be drawn at an angle equal to that of the
+line which is being labeled. If this is not desired,
+the parameter rotate may be set to no, and labels will always appear
+"normal", i.e., the text will not be rotated in any way.
+
+By default, all labels will be shortened to the smallest unit
+needed to indicate the value of the labeled line. For example, if the
+graph spans about 30 seconds of declination, the interval between the
+labels will be approximately 5 or 10 seconds. The first label will contain the
+full specification, i.e., -22:32:20. But the rest of the labels will
+only be the seconds, i.e., 30, 40, 50. However, at the change in
+minutes, the full format would be used again, -22:33:00, but then
+again afterwards only seconds will be displayed, i.e., 10, 20, etc.
+If this shortening of labels is undesirable, it
+can be turned off by setting the parameter 'full_label = yes'. This
+forces every label to use the full specification.
+
+Finally, the parameter 'label_size' can be used to adjust the size of the
+characters used in the axis labels.
+.le
+.ls Titles
+A graph title may specified using the parameter 'title'.
+If 'title = "imtitle"', a default title constructed from the image name and title
+is used. The location and size of the graph title are controlled by
+the parameters 'title_side' and 'title_size'.
+Similarly the content, placement and size of the axis titles are
+controlled by the parameters 'axis1_title', 'axis2_title',
+'axis1_title_side', 'axis2_title_side', and
+'axis_title_size'.
+.le
+.ls Interactive Cursor
+'wcslab' provides a simple cursor readback capability for retrieving
+coordinates of objects and saving them in a file. However, you should
+also look at the tasks 'tvmark' and 'rimcursor' for more advance
+functionality.
+
+The cursor allows the user to examine
+coordinates of specific objects and to make a file containing a
+list of coordinates. For graphic displays, the user has the full cursor
+functionality described by 'gcur'. However, there are a few extra
+commands provided for transforming cursor position to celestial
+coordinates. While in cursor mode, striking most lower-case
+characters will result in the celestial coordinates of the cursor
+position to be displayed on the terminal.
+
+Coordinates can also be written to a file by
+striking the lower-case 'm'. When 'm' is hit, an 'X' is placed on the
+display, and the coordinates are written to a coordinate list file.
+This file can be specified in two ways. If you just start hitting
+'m', a file called '<imagename>.coord.list' will be created. You can
+specify a
+different
+file with the colon command ":open <filename>". After opening the
+file, any
+new coordinates marked with the 'm' key are written to the
+file. You can go through as many files as you like. If a file is
+specified that already exists, an attempt is made to read the file.
+If it contains coordinate values, those coordinate positions are
+displayed as crosses in the window, and any new position marked
+will be appended.
+
+Striking the '?' key will display help concerning these task-specific
+commands. Striking the 'q' key will exit the task.
+.le
+.ls Output Formats
+Currently, only one coordinate format is supported: all right
+ascensions are output in HH:MM:SS (hours:minutes:seconds) format
+and
+all declinations are output in DD:MM:SS (degrees:minutes:seconds). If
+parameters are changed, such as 'axis1_int', they should be
+input in the same format. For the coordinate list files, the first
+line of the file begins with the comment character, '#', and displays
+the format used in the file.
+
+If the WCS is linear, then output will not be formatted in any special
+way; i.e., no assumptions are made about units, etc.
+.le
+.ih
+PARAMETERS
+.ls (major_grid = yes) [boolean]
+Draw a coordinate grid instead of tick marks at the position of the major
+intervals?
+
+If set to "yes", lines of constant axis1 and axis2 values are drawn.
+If set to "no", tick marks will be drawn instead. Major grid lines and
+tick marks will be labeled with the appropriate axis values.
+.le
+.ls (minor_grid = no) [boolean]
+Draw a coordinate grid instead of tick marks at the position of the
+minor intervals?
+
+If set to "yes", lines of constant axis1 and axis2 values
+are drawn between the major grid lines and tick
+marks. If this is set to "no", tick
+marks will be drawn instead. Minor grid lines and tick
+marks are not labeled.
+.le
+.ls (dolabel = yes) [boolean]
+Label the major grid lines or tick marks?
+.le
+.ls (remember = no) [boolean]
+Modify the 'wlpars' parameter file when done?
+
+Setting this to "yes" allows parameters that may have been calculated
+by the task to be written back to the parameter file. If set to "no",
+the default, the parameter file is left untouched by the task. This is
+useful if some slight modification is desired to produce a slightly
+different graph.
+.le
+.ls (axis1_beg = "") [string]
+The lowest value of axis 1 in world coordinates units at which a major
+grid line or tick mark will be plotted. If set to null ('axis1_beg =
+""'), 'wcslab' will compute this quantity. 'axis1_beg' will be
+ignored if 'axis1_end' and 'axis1_int' are undefined.
+.le
+.ls (axis1_end = "") [string]
+The highest value of axis 1 in world coordinate
+units at which a major grid line or tick mark will be plotted.
+If 'axis1_end = ""', the task will compute this quantity.
+'axis1_end' will be ignored if 'axis1_beg' and 'axis1_int' are undefined.
+.le
+.ls (axis1_int = "") [string]
+The interval in world coordinate units at which
+major grid lines and tick marks will be drawn along axis 1.
+If 'axis1_int = ""', 'wcslab' will compute this quantity.
+'axis1_int' will be ignored if 'axis1_beg' and 'axis1_end' are undefined.
+.le
+.ls (axis2_beg = "") [string]
+The lowest value of axis 2 in world coordinates units
+at which a major grid line or tick mark will be plotted.
+If 'axis2_beg = ""', 'wcslab' will compute this quantity.
+'axis2_beg' will be ignored if 'axis2_end' and 'axis2_int' are undefined.
+.le
+.ls (axis2_end = "") [string]
+The highest value of axis 2 in world coordinate
+units at which a major grid line or tick mark will be plotted.
+If 'axis2_end = ""', 'wcslab' will compute this quantity.
+'axis2_end' will be ignored if 'axis2_beg' and 'axis2_int' are undefined.
+.le
+.ls (axis2_int = "") [string]
+The interval in world coordinate units at which
+major grid lines or tick marks will be drawn along axis 2.
+If 'axis2_int = ""', 'wcslab' will compute this quantity.
+'axis2_int' will be ignored if 'axis1_beg' and 'axis1_end' are undefined.
+.le
+.ls (major_line = "solid") [string, allowed values: solid |
+dotted | dashed | dotdash]
+
+The type of major grid lines to be plotted.
+The permitted values are "solid", "dotted", "dashed", and "dotdash".
+.le
+.ls (major_tick = .03) [real]
+Size of major tick marks relative to the size of the viewport.
+By default the major tick marks are .03 times the size of the
+viewport.
+.le
+.ls (axis1_minor = 5) [integer]
+The number of minor grid lines or tick marks that will appear between major
+grid lines or tick marks for axis 1.
+.le
+.ls (axis2_minor = 5) [integer]
+The number of minor grid lines or tick marks that will appear between major
+grid lines or tick marks for axis 2.
+.le
+.ls (minor_line = "dotted") [string, allowed values: solid |
+dotted | dashed | dotdash]
+
+The type of minor grid lines to be plotted.
+The permitted values are "solid", "dotted", "dashed", and "dotdash".
+.le
+.ls (minor_tick = .01) [real]
+Size of minor tick marks relative to the size of the viewport.
+BY default the minor tick marks are .01 times the size of the
+viewport.
+.le
+.ls (tick_in = yes) [boolean]
+Do tick marks point into instead of away from the graph?
+.le
+.ls (axis1_side = "default") [string]
+The list of viewport edges, separated by commas, on which to place the axis
+1 labels. If 'axis1_side' is "default", 'wcslab' will choose a side.
+'axis1_side' may contain any combination of "left", "right",
+"bottom", "top", or "default".
+.le
+.ls (axis2_side = "default") [string]
+The list of viewport edges, separated by commas, on which to place the axis
+2 labels. If 'axis2_side' is "default", 'wcslab' will choose a side.
+'axis2_side' may contain any combination of "left", "right",
+"bottom", "top", or "default".
+.le
+.ls (axis2_dir = "") [string]
+The axis 1 value at which the axis 2 labels will be written for polar graphs.
+If 'axis2_dir' is "", 'wcslab' will compute this number.
+.le
+.ls (justify = "default") [string]
+The direction with respect to axis 2 along which the axis 2
+labels will be drawn from the point they are labeling on polar graphs.
+If 'justify = ""', then 'wcslab' will calculate this quantity. The permitted
+values are "default", "left", "right", "top", and "bottom".
+.le
+.ls (labout = yes) [boolean]
+Draw the labels outside the axes?
+
+Setting this to "yes", draws labels outside the image viewport.
+Otherwise, the axes labels will be drawn inside
+the image border. The latter option is useful if the image fills the
+display frame buffer.
+.le
+.ls (full_label = no) [boolean]
+Always draw all the labels in full format (h:m:s or d:m:s) if the world
+coordinate system of the image is in RA and DEC?
+
+If 'full_label = no', then
+only certain axes will be labeled in full format, with the rest
+labeled in minutes or seconds, as appropriate.
+.le
+.ls (rotate = yes) [boolean]
+Permit the labels to rotate ?
+
+If 'rotate = yes', then labels will be written
+at an angle to match that of the major grid lines that are being
+labeled. If 'rotate = no', then labels are always written
+"normally", that is horizontally. If 'labout = no', then rotate is
+set to "no" by default.
+.le
+.ls (label_size = 1.0) [real]
+The size of the characters used to draw the major grid line labels.
+.le
+.ls (title = "imtitle") [string]
+The graph title. If 'title = "imtitle"', then a default title containing
+the image name and title is created.
+.le
+.ls (axis1_title = "") [string]
+The title for axis 1. By default no axis 1 title is drawn.
+.le
+.ls (axis2_title = "") [string]
+The title for axis 2. By default no axis title will be written.
+.le
+.ls (title_side = "top") [string, allowed values: top | bottom |
+left | right]
+
+The side of the plot on which to place the title.
+The options are "left", "right", "bottom", and "top".
+.le
+.ls (axis1_title_side = "default") [string, allowed values: default |
+top | bottom | left | right]
+
+The side of the plot on which to place the axis 1 title.
+If 'axis1_title_side = "default"', 'wcslab' will choose a side for the title.
+The permitted values are "default", "right", "left", "top", and
+"bottom".
+.le
+.ls (axis2_title_side = "default") [string, allowed values: default |
+top | bottom | left | right]
+
+The side of the plot on which to place the axis 2 title.
+If 'axis2_title_side = "default"', 'wcslab' will choose a side for the title.
+The permitted values are "default", "right", "left", "top", and
+"bottom".
+.le
+.ls (title_size = 1.0) [real]
+The size of characters used to draw the title.
+.le
+.ls (axis_title_size = 1.0) [real]
+The size of the characters used to draw the axis titles.
+.le
+.ls (linecolor = INDEF) [integer]
+Color used for drawing lines and tick marks. If this is not specified,
+the default color
+for the graphics output device will be used.
+.le
+.ls (labelcolor = INDEF) [integer]
+Color used to write axis labels. If not specified, the color for the lines
+and tickmarks will be used.
+.le
+.ls (titlecolor = INDEF) [integer]
+Color used to write the plot title. If not specified, the color for the
+labels will be used.
+.le
+.ls (graph_type = "") [normal | polar | near_polar]
+String indicating what type of graph will be drawn. If empty, the
+default, the task will determine the type.
+.le
+.ls (coords) [gcur]
+The graphics cursor.
+.le
+.ls (image_coord) [imcur]
+The image display cursor.
+.le
+.ls (version = "16Jun92" ) [string]
+The date the current software was installed.
+.le
+.ih
+EXAMPLES
+.ih
+BUGS
+.ih
+SEE ALSO
+wcslab, cursors, newcont
+.endhelp
diff --git a/pkg/utilities/nttools/gtedit.par b/pkg/utilities/nttools/gtedit.par
new file mode 100644
index 00000000..6455ec5d
--- /dev/null
+++ b/pkg/utilities/nttools/gtedit.par
@@ -0,0 +1,11 @@
+input,s,a,,,,"Name of the input table"
+xcolumn,s,a,,,,"Name of column in input to use as X axis"
+ycolumn,s,a,,,,"Name of column in input to use as Y axis"
+device,s,h,"stdgraph",,,output device
+commands,*gcur,h,"",,,graphics commands
+inplace,b,h,no,,,"Edit the table in place?"
+output,s,h,"",,,"Name of output table to contain edited output"
+reject,s,h,"",,,"Name of output table for deleted entries"
+columns,s,h,"",,,"Columns to edit in text mode"
+insert,b,h,yes,,,"Begin editing in insert mode (text mode)"
+gtpar,pset,h,,,,"Plot attributes"
diff --git a/pkg/utilities/nttools/gtedit/gtdelete.x b/pkg/utilities/nttools/gtedit/gtdelete.x
new file mode 100644
index 00000000..c09f6a96
--- /dev/null
+++ b/pkg/utilities/nttools/gtedit/gtdelete.x
@@ -0,0 +1,360 @@
+include <mach.h>
+include <gset.h>
+include <gio.h>
+
+define MSIZE 2.0
+
+# GT_DELPT -- Mark a point as deleted
+
+procedure gt_delpt (gd, wx, wy, x, y, npix, deleted, undelete)
+
+pointer gd # Graphics descriptor
+real wx # Cursor position
+real wy # ""
+real x[ARB] # Plotted data
+real y[ARB] # Plotted data
+int npix # # of pixels
+int deleted[ARB] # Array of delete indicators
+int undelete # Undelete flag
+
+int row, i
+real r2min, r2, x0, y0
+
+begin
+ # Search for the nearest point which has not been deleted
+
+ row = 0
+ r2min = MAX_REAL
+
+ # Transform world cursor coordintes to NDC
+ call gctran (gd, wx, wy, wx, wy, 1, 0)
+ do i = 1 , npix {
+ if ((deleted[i] == YES && undelete == NO) ||
+ (deleted[i] == NO && undelete == YES))
+ next
+
+ call gctran (gd, x[i], y[i], x0, y0, 1, 0)
+ if (x[i] < INDEFR && y[i] < INDEFR)
+ r2 = (wx - x0) ** 2 + (wy - y0) ** 2
+ else
+ r2 = MAX_REAL
+
+ if (r2 < r2min) {
+ r2min = r2
+ row = i
+ }
+ }
+
+ if (row != 0) {
+ # Mark row as being deleted
+ if (undelete == NO) {
+ # Plot X over point
+ call gscur (gd, x[row], y[row])
+ call gseti (gd, G_PMLTYPE, GL_SOLID)
+ call gmark (gd, x[row], y[row], GM_CROSS, MSIZE, MSIZE)
+ deleted[row] = YES
+ } else {
+ deleted[row] = NO
+ call gscur (gd, x[row], y[row])
+ call gseti (gd, G_PMLTYPE, GL_CLEAR)
+ call gmark (gd, x[row], y[row], GM_CROSS, MSIZE, MSIZE)
+ }
+
+ }
+
+end
+
+# GT_DYGT -- Delete all point > input Y
+
+procedure gt_dygt (gd, wy, x, y, npix, deleted, undelete)
+
+pointer gd # Graphics descriptor
+real wy # Cursor position
+real x[ARB] # Plotted data
+real y[ARB] # Plotted data
+int npix # # of pixels
+int deleted[ARB] # Array of delete indicators
+int undelete
+
+int i
+
+begin
+ # Search for points with Y values > than the critical value
+
+ do i = 1 , npix {
+ if ((deleted[i] == YES && undelete == NO) ||
+ (deleted[i] == NO && undelete == YES))
+ next
+
+ if (y[i] > wy) {
+ if (undelete == NO) {
+ # Plot X over point
+ call gseti (gd, G_PMLTYPE, GL_SOLID)
+ call gmark (gd, x[i], y[i], GM_CROSS, MSIZE, MSIZE)
+ deleted[i] = YES
+ } else {
+ deleted[i] = NO
+ call gseti (gd, G_PMLTYPE, GL_CLEAR)
+ call gmark (gd, x[i], y[i], GM_CROSS, MSIZE, MSIZE)
+ }
+ }
+ }
+end
+
+# GT_DYLT -- Delete all point < input Y
+
+procedure gt_dylt (gd, wy, x, y, npix, deleted, undelete)
+
+pointer gd # Graphics descriptor
+real wy # Cursor position
+real x[ARB] # Plotted data
+real y[ARB] # Plotted data
+int npix # # of pixels
+int deleted[ARB] # Array of delete indicators
+int undelete
+
+int i
+
+begin
+ # Search for points with Y values > than the critical value
+
+ do i = 1 , npix {
+ if ((deleted[i] == YES && undelete == NO) ||
+ (deleted[i] == NO && undelete == YES))
+ next
+
+ if (y[i] < wy) {
+ if (undelete == NO) {
+ deleted[i] = YES
+ # Plot X over point
+ call gseti (gd, G_PMLTYPE, GL_SOLID)
+ call gmark (gd, x[i], y[i], GM_CROSS, MSIZE, MSIZE)
+ } else {
+ deleted[i] = NO
+ call gseti (gd, G_PMLTYPE, GL_CLEAR)
+ call gmark (gd, x[i], y[i], GM_CROSS, MSIZE, MSIZE)
+ }
+ }
+ }
+end
+
+# GT_DXGT -- Delete all point > input X
+
+procedure gt_dxgt (gd, wx, x, y, npix, deleted, undelete)
+
+pointer gd # Graphics descriptor
+real wx # Cursor position
+real x[ARB] # Plotted data
+real y[ARB] # Plotted data
+int npix # # of pixels
+int deleted[ARB] # Array of delete indicators
+int undelete
+
+int i
+
+begin
+ # Search for points with X values > than the critical value
+
+ do i = 1 , npix {
+ if ((deleted[i] == YES && undelete == NO) ||
+ (deleted[i] == NO && undelete == YES))
+ next
+
+ if (x[i] > wx) {
+ if (undelete == NO) {
+ deleted[i] = YES
+ # Plot X over point
+ call gseti (gd, G_PMLTYPE, GL_SOLID)
+ call gmark (gd, x[i], y[i], GM_CROSS, MSIZE, MSIZE)
+ } else {
+ deleted[i] = NO
+ call gseti (gd, G_PMLTYPE, GL_CLEAR)
+ call gmark (gd, x[i], y[i], GM_CROSS, MSIZE, MSIZE)
+ }
+ }
+ }
+end
+
+# GT_DXLT -- Delete all point > input Y
+
+procedure gt_dxlt (gd, wx, x, y, npix, deleted, undelete)
+
+pointer gd # Graphics descriptor
+real wx # Cursor position
+real x[ARB] # Plotted data
+real y[ARB] # Plotted data
+int npix # # of pixels
+int deleted[ARB] # Array of delete indicators
+int undelete
+
+int i
+
+begin
+ # Search for points with X values < than the critical value
+
+ do i = 1 , npix {
+ if ((deleted[i] == YES && undelete == NO) ||
+ (deleted[i] == NO && undelete == YES))
+ next
+
+ if (x[i] < wx) {
+ if (undelete == NO) {
+ deleted[i] = YES
+ # Plot X over point
+ call gseti (gd, G_PMLTYPE, GL_SOLID)
+ call gmark (gd, x[i], y[i], GM_CROSS, MSIZE, MSIZE)
+ } else {
+ deleted[i] = NO
+ call gseti (gd, G_PMLTYPE, GL_CLEAR)
+ call gmark (gd, x[i], y[i], GM_CROSS, MSIZE, MSIZE)
+ }
+ }
+ }
+end
+
+# GT_DBOX -- Delete all point in a box
+
+procedure gt_dbox (gd, npix, deleted, undelete, x, y, x1, y1, x2, y2)
+
+pointer gd # Graphics descriptor
+int npix # # of pixels
+int deleted[ARB] # Array of delete indicators
+int undelete
+real x[ARB] # Plotted data
+real y[ARB] # Plotted data
+real x1, y1, x2, y2 # Corners of the box
+
+int i
+real temp
+
+begin
+ # Make sure the points are in the correct order
+ if (y2 < y1) {
+ temp = y1
+ y1 = y2
+ y2 = temp
+ }
+ if (x2 < x1) {
+ temp = x1
+ x1 = x2
+ x2 = temp
+ }
+ # Search for points within the box
+ do i = 1 , npix {
+ if ((deleted[i] == YES && undelete == NO) ||
+ (deleted[i] == NO && undelete == YES))
+ next
+
+ if (x[i] <= x2 && x[i] >= x1) {
+ if (y[i] <= y2 && y[i] >= y1) {
+ if (undelete == NO) {
+ deleted[i] = YES
+ # Plot X over point
+ call gseti (gd, G_PMLTYPE, GL_SOLID)
+ call gmark (gd, x[i], y[i], GM_CROSS, MSIZE, MSIZE)
+ } else {
+ deleted[i] = NO
+ call gseti (gd, G_PMLTYPE, GL_CLEAR)
+ call gmark (gd, x[i], y[i], GM_CROSS, MSIZE, MSIZE)
+ }
+ }
+ }
+ }
+end
+
+# GT_DSEG -- Delete all point on one side of a line segment
+
+procedure gt_dseg (gd, npix, deleted, undelete, x, y, x1, y1, x2, y2, x0, y0)
+
+pointer gd # Graphics descriptor
+int npix # # of pixels
+int deleted[ARB] # Array of delete indicators
+int undelete
+real x[ARB] # Plotted data
+real y[ARB] # Plotted data
+real x1, y1, x2, y2 # Corners of the box
+real x0, y0, slope, inter, temp
+
+int i, lessthan
+
+begin
+ # Make sure the points are in the correct order
+ if (y2 < y1) {
+ temp = y1
+ y1 = y2
+ y2 = temp
+ }
+ if (x2 < x1) {
+ temp = x1
+ x1 = x2
+ x2 = temp
+ }
+
+ # Calculate slope and intercept
+ slope = (y2 - y1) / (x2 - x1)
+ inter = (x2 * y1 - x1 * y2) / (x2 - x1)
+
+ # Which side should we delete the lines from?
+ temp = x0 * slope + inter
+ if (temp <= y0)
+ lessthan = NO
+ else
+ lessthan = YES
+
+ # Search for points with X values between x1 and x2
+ do i = 1 , npix {
+ if ((deleted[i] == YES && undelete == NO) ||
+ (deleted[i] == NO && undelete == YES))
+ next
+
+ if (x[i] <= x2 && x[i] >= x1) {
+ # Now which side of the line does this point fall on
+ temp = x[i] * slope + inter
+ if (y[i] < temp && lessthan == YES) {
+ if (undelete == NO) {
+ deleted[i] = YES
+ # Plot X over point
+ call gseti (gd, G_PMLTYPE, GL_SOLID)
+ call gmark (gd, x[i], y[i], GM_CROSS, MSIZE, MSIZE)
+ } else {
+ deleted[i] = NO
+ call gseti (gd, G_PMLTYPE, GL_CLEAR)
+ call gmark (gd, x[i], y[i], GM_CROSS, MSIZE, MSIZE)
+ }
+ } else if (y[i] > temp && lessthan == NO) {
+ if (undelete == NO) {
+ deleted[i] = YES
+ # Plot X over point
+ call gseti (gd, G_PMLTYPE, GL_SOLID)
+ call gmark (gd, x[i], y[i], GM_CROSS, MSIZE, MSIZE)
+ } else {
+ deleted[i] = NO
+ call gseti (gd, G_PMLTYPE, GL_CLEAR)
+ call gmark (gd, x[i], y[i], GM_CROSS, MSIZE, MSIZE)
+ }
+ }
+ }
+ }
+end
+
+# GT_PDEL -- Overplot crosses on those points which have been marked for zap.
+
+procedure gt_pdel (gd, x, y, deleted, npix)
+
+pointer gd
+real x[ARB]
+real y[ARB]
+int deleted[ARB]
+int npix
+
+int i
+
+begin
+ do i = 1, npix {
+ if (deleted[i] == YES) {
+ # Plot X over point
+ call gseti (gd, G_PMLTYPE, GL_SOLID)
+ call gmark (gd, x[i], y[i], GM_CROSS, MSIZE, MSIZE)
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/gtedit/gtdodel.x b/pkg/utilities/nttools/gtedit/gtdodel.x
new file mode 100644
index 00000000..7292048c
--- /dev/null
+++ b/pkg/utilities/nttools/gtedit/gtdodel.x
@@ -0,0 +1,41 @@
+include <tbset.h>
+
+# GT_DODEL -- Actually delete the rows marked for deletion
+
+procedure gt_dodel (tp, tpr, deleted, npix)
+
+pointer tp
+pointer tpr
+int deleted[ARB] # io: Array of deleted flags
+int npix # io: # of rows in table
+
+int i, j, k
+
+int tbpsta()
+
+begin
+ if (tpr != NULL) {
+ # Append to whatever is already in the table
+ k = tbpsta (tpr, TBL_NROWS)
+ do i = 1, npix {
+ if (deleted[i] == YES) {
+ k = k + 1
+ call tbrcpy (tp, tpr, i, k)
+ }
+ }
+ }
+
+ for (j = npix; j> 0; j = j - 1) {
+ if (deleted[j] == YES) {
+ i = j
+ while (deleted[i] == YES) {
+ i = i - 1
+ if (i < 1)
+ break
+ }
+ i = i + 1
+ call tbrdel (tp, i, j)
+ j = i - 1
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/gtedit/gtedit.key b/pkg/utilities/nttools/gtedit/gtedit.key
new file mode 100644
index 00000000..2a51e584
--- /dev/null
+++ b/pkg/utilities/nttools/gtedit/gtedit.key
@@ -0,0 +1,25 @@
+ GTEDIT Interactive Cursor Commands
+
+? Print options
+: Colon commands
+a print out the complete row for the data point nearest the cursor
+b delete all points with Y values less than the cursor Y position
+c mark the corner of a box
+d delete the point nearest the cursor
+e exit and save changes in the output table
+f make all the marked deletions and replot remaining data
+h print out the column names of the input table
+l delete all points with X values less than the cursor Y position
+p replot the graph possibly using new data columns
+q quit and do not save changes made since the last 'f'
+r delete all points with X values greater than the cursor Y position
+s mark one end of a line segment
+t delete all points with Y values greater than the cursor Y position
+u toggle between delete and undelete mode
+v change from gtedit to tedit mode
+z display current status (delete or undelete)
+
+:x(-) xcolumn set the table column for the X axis and possibly replot
+:y(-) ycolumn set the table column for the Y axis and possibly replot
+
+- do not automatically replot after reading in new column
diff --git a/pkg/utilities/nttools/gtedit/gthinfo.x b/pkg/utilities/nttools/gtedit/gthinfo.x
new file mode 100644
index 00000000..dbc3d345
--- /dev/null
+++ b/pkg/utilities/nttools/gtedit/gthinfo.x
@@ -0,0 +1,69 @@
+include <error.h>
+include <ctype.h>
+include <fset.h> # FIO
+include <tbset.h> # TBtables
+
+# GT_HINFO -- Get the title and axes labels for the plot
+
+procedure gt_hinfo (tp, xlabel, ylabel, xcolumn, ycolumn, maxch)
+
+pointer tp # Table pointer
+char xlabel[SZ_LINE] # Axis label strings (output)
+char ylabel[SZ_LINE] # Axis label strings (output)
+char xcolumn[SZ_COLNAME] # X column
+char ycolumn[SZ_COLNAME] # Y column
+int maxch
+
+char colunit[SZ_COLUNITS]
+char errmsg[SZ_LINE] # Error message
+pointer xcd, ycd
+
+int strlen()
+bool streq()
+
+begin
+ # Single table; X and Y column
+
+ if (!streq (xcolumn, NULL)) {
+ call tbcfnd (tp, xcolumn, xcd, 1)
+ if (xcd <= 0) {
+ call sprintf (errmsg, SZ_LINE, "Cannot find column %s")
+ call pargstr (xcolumn)
+ call error (0, errmsg)
+ }
+ # X axis label comes from column name
+ call sprintf (xlabel, maxch, "%s")
+ call pargstr (xcolumn)
+ } else {
+ call sprintf (xlabel, maxch, "%s")
+ call pargstr ("Number")
+ }
+
+ # Find the column units
+ call tbcigt (xcd, TBL_COL_UNITS, colunit, SZ_COLUNITS)
+ if (colunit[1] != EOS) {
+ # Column units exist; append to X label
+ call sprintf (xlabel[strlen (xlabel)+1], maxch, " [%s]")
+ call pargstr (colunit)
+ }
+
+ call tbcfnd (tp, ycolumn, ycd, 1)
+ if (ycd <= 0) {
+ call sprintf (errmsg, SZ_LINE, "Cannot find column %s")
+ call pargstr (ycolumn)
+ call error (0, errmsg)
+ }
+
+ # Y label comes from column name
+ call sprintf (ylabel, maxch, "%s")
+ call pargstr (ycolumn)
+
+ # Find the column units
+ call tbcigt (ycd, TBL_COL_UNITS, colunit, SZ_COLUNITS)
+ if (colunit[1] != EOS) {
+ # Column units exist; append to Y label
+ call sprintf (ylabel[strlen (ylabel)+1], maxch, " [%s]")
+ call pargstr (colunit)
+ }
+
+end
diff --git a/pkg/utilities/nttools/gtedit/gtplot.x b/pkg/utilities/nttools/gtedit/gtplot.x
new file mode 100644
index 00000000..160ed978
--- /dev/null
+++ b/pkg/utilities/nttools/gtedit/gtplot.x
@@ -0,0 +1,501 @@
+include <xwhen.h>
+include <config.h>
+include <mach.h>
+include <error.h>
+include <ctype.h>
+include <fset.h> # FIO
+include <gset.h> # GIO
+include <tbset.h> # TBtables
+
+define HELPFILE "tables$pkg/ttools/gtedit/gtedit.key" # (BPS 05.31.94)
+define GT_QUIT 0
+define GT_EXIT 1
+
+procedure gteplot (device, input, tp, tpr, deleted, xcolumn, ycolumn, x, y,
+ size, null, npix, table_name, status)
+
+char device[SZ_FNAME] # Graphics device
+char input[SZ_FNAME] # Input table name
+pointer tp # Table descriptor
+pointer tpr # Reject Table descriptor
+pointer deleted # Pointer for array of delete flags
+char xcolumn[SZ_COLNAME] # X column in table
+char ycolumn[SZ_COLNAME] # Y column in table
+pointer x
+pointer y
+pointer size # Size of markers to plot
+pointer null #
+int npix # Number of points per curve
+char table_name[SZ_FNAME] # Table name
+int status # return status
+
+pointer gd
+int mode, npix_save
+char col_save[SZ_COLNAME]
+char xlabel[SZ_LINE], ylabel[SZ_LINE]
+char plotitle[2*SZ_LINE]
+char marker[SZ_FNAME]
+char cmd[SZ_LINE]
+char bad_column[SZ_COLNAME]
+bool xautoscale, yautoscale, mark_del
+bool drawbox, rdmarks
+bool silent, readonly, inplace, auto_replot
+int xtran, ytran, ticklabels, marker_type, j, drawgrid
+int wcs, key, ip
+int undelete
+real px, py
+real wx1, wx2, wy1, wy2, szmarker, vx1, vx2, vy1, vy2
+real wb, wt, wl, wr
+real tol, xx, yy, sz
+real x1, y1, x2, y2
+pointer sp, system_id, errmsg
+
+string bell "\007"
+define replot_ 91
+define next_ 92
+
+pointer gopen()
+bool clgetb()
+int strncmp()
+int clgeti(), gstati()
+int clgcur()
+real clgetr()
+pointer tbtopn()
+errchk clgetb, clgeti, clgstr, clgetr, glabax, gpmark
+errchk gswind, gseti, gascale, grscale
+
+begin
+ call smark (sp)
+ call salloc (system_id, SZ_LINE, TY_CHAR)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ mode = NEW_FILE
+ mark_del = false
+ undelete = NO
+
+ # Get the marker character to be drawn at
+ # each point. The size of the character is given by szmarker. If
+ # zero and the input operadd is a list, marker sizes are taken
+ # individually from the third column of each list element. If
+ # negative, all markers are of size |szmarker| in NDC. If
+ # positive and the input operand is a list, the size of a marker
+ # is the third column of each list element times szmarker.
+
+ szmarker = 0.0
+ rdmarks = false
+
+ # Draw markers only
+ call clgstr ("marker", marker, SZ_FNAME)
+ call init_mark2 (marker, marker_type)
+ if (marker_type != GM_POINT) {
+ szmarker = clgetr ("szmarker")
+ rdmarks = (szmarker <= 0)
+ }
+
+ gd = gopen (device, mode, STDGRAPH)
+
+ call gsetr (gd, G_PLWIDTH, 2.0)
+
+ tol = 10.0 * EPSILONR
+ xautoscale = false
+ yautoscale = false
+
+ # Set window and viewport. If user window has not been set, enable
+ # autoscaling. If device viewport has not been set, let glabax
+ # handle the viewport internally.
+
+ call gclear (gd)
+ wx1 = clgetr ("wx1")
+ wx2 = clgetr ("wx2")
+ wy1 = clgetr ("wy1")
+ wy2 = clgetr ("wy2")
+
+ if (abs (wx2 - wx1) < tol)
+ xautoscale = true
+ if (abs (wy2 - wy1) < tol)
+ yautoscale = true
+
+ vx1 = clgetr ("vx1")
+ vx2 = clgetr ("vx2")
+ vy1 = clgetr ("vy1")
+ vy2 = clgetr ("vy2")
+
+ if ((abs (vx2 - vx1) > tol) && (abs (vy2 - vy1) > tol))
+ call gsview (gd, vx1, vx2, vy1, vy2)
+
+ if (!clgetb ("fill"))
+ call gseti (gd, G_ASPECT, 1)
+
+ if (clgetb ("round"))
+ call gseti (gd, G_ROUND, YES)
+
+replot_
+ # Draw box around plot?
+ drawbox = false
+ if (mode != APPEND)
+ if (clgetb ("box"))
+ drawbox = true
+
+ if (drawbox) {
+ # Get number of major and minor tick marks.
+ call gseti (gd, G_XNMAJOR, clgeti ("majrx"))
+ call gseti (gd, G_XNMINOR, clgeti ("minrx"))
+ call gseti (gd, G_YNMAJOR, clgeti ("majry"))
+ call gseti (gd, G_YNMINOR, clgeti ("minry"))
+
+ # Fetch labels and plot title string.
+
+ call clgstr ("xlabel", xlabel, SZ_LINE)
+ call clgstr ("ylabel", ylabel, SZ_LINE)
+
+ call gt_hinfo (tp, xlabel, ylabel, xcolumn, ycolumn, SZ_LINE)
+
+ # Label tick marks on axes?
+ ticklabels = NO
+ if (clgetb ("ticklabels"))
+ ticklabels = YES
+
+ # Draw grid ?
+ drawgrid = NO
+ if (clgetb ("grid"))
+ drawgrid = YES
+
+ call gseti (gd, G_DRAWGRID, drawgrid)
+ }
+
+ # Log scale? Call gswind to set log scaling regardless of whether
+ # the user window is known; if the user window was not input,
+ # autoscaling will reset it later.
+
+ if (mode == APPEND) {
+ xtran = gstati (gd, G_XTRAN)
+ ytran = gstati (gd, G_YTRAN)
+ call ggwind (gd, wx1, wx2, wy1, wy2)
+ } else {
+ xtran = GW_LINEAR
+ if (clgetb ("logx"))
+ xtran = GW_LOG
+ ytran = GW_LINEAR
+ if (clgetb ("logy"))
+ ytran = GW_LOG
+ call gswind (gd, wx1, wx2, wy1, wy2)
+ call gseti (gd, G_XTRAN, xtran)
+ call gseti (gd, G_YTRAN, ytran)
+ }
+
+ # Autoscale if enabled.
+ if (xautoscale) {
+ call gascale (gd, Memr[x], npix, 1)
+ }
+ call ggwind (gd, wl, wr, wb, wt)
+
+ if (yautoscale) {
+ # Overplot multiple curves on the same viewport
+ call gascale (gd, Memr[y], npix, 2)
+ }
+
+ if (drawbox) {
+ # Draw box around plot
+ call gseti (gd, G_LABELTICKS, ticklabels)
+ # Overplot multiple curves on the same viewport
+ call strcpy ("", plotitle, SZ_FNAME)
+ call glabax (gd, plotitle, xlabel, ylabel)
+ }
+
+ # Markers at each point with no connection
+ if (rdmarks) {
+ # Variable marker sizes
+ if (szmarker < 0)
+ # World coordinate marker sizes
+ call amulkr (Memr[size], -szmarker, Memr[size],
+ npix)
+ do j = 1, npix { # For each point in the curve
+ xx = Memr[x+j-1]
+ yy = Memr[y+j-1]
+ sz = Memr[size+j-1]
+ call gmark (gd, xx, yy, marker_type, sz, sz)
+ }
+ } else {
+ call gpmark (gd, Memr[x], Memr[y],npix, marker_type,
+ szmarker, szmarker)
+ }
+
+ # We have plotted things so now is the time to let the user
+ # do his thing.
+
+ # Over plot crosses for those points which have been deleted
+ if (mark_del) {
+ call gt_pdel (gd, Memr[x], Memr[y], Memr[deleted], npix)
+ mark_del = false
+ }
+
+next_
+ while (clgcur ("commands", px, py, wcs, key, cmd, SZ_LINE)
+ != EOF) {
+
+ switch (key) {
+
+ # Quit and do not make changes
+ case 'q':
+ status = GT_QUIT
+ break
+
+ # Exit and do the changes
+ case 'e':
+ status = GT_EXIT
+ break
+
+ # Help page
+ case '?':
+ if (gd == NULL)
+ call pagefile (HELPFILE, "")
+ else
+ call gpagefile (gd, HELPFILE, "")
+
+ # Simply replot (may have new columns)
+ case 'p':
+ call gclear (gd)
+ mark_del = true
+ goto replot_
+
+ # Mark the corners of a box and delete the points within
+ case 'c':
+ x1 = px; y1 = py
+ call gmark (gd, x1, y1, GM_DIAMOND, 1., 1.)
+ call printf ("again:")
+ if (clgcur ("commands", px, py, wcs, key, cmd, SZ_LINE) == EOF)
+ goto next_
+
+ call gt_dbox (gd, npix, Memi[deleted], undelete, Memr[x],
+ Memr[y], x1, y1, px, py)
+
+ # Mark the end points of a line segment and delete points on
+ # one side of this segment (indicated by user) for points with
+ # X values between x1 and x2
+ case 's':
+ x1 = px; y1 = py
+ call gmark (gd, x1, y1, GM_DIAMOND, 1., 1.)
+ call printf ("again:")
+ if (clgcur ("commands", px, py, wcs, key, cmd, SZ_LINE) == EOF)
+ goto next_
+ x2 = px
+ y2 = py
+ call gmark (gd, x1, y1, GM_DIAMOND, 1., 1.)
+ call gline (gd, x1, y1, x2, y2)
+ call printf ("Move cursor to one side of line and hit any key")
+ if (clgcur ("commands", px, py, wcs, key, cmd, SZ_LINE) == EOF)
+ goto next_
+
+ call gt_dseg (gd, npix, Memi[deleted], undelete, Memr[x],
+ Memr[y], x1, y1, x2, y2, px, py)
+
+ # Update graph (delete points and replot)
+ case 'f':
+ call gt_update (tp, tpr, Memr[x], Memr[y], Memi[deleted], npix)
+ call gclear (gd)
+ goto replot_
+
+ # Print out the complete record for this point
+ case 'a':
+ call gt_wrdata (gd, tp, px, py, Memr[x], Memr[y], npix)
+
+ # Print out the column names
+ case 'h':
+ call gt_wrhead (gd, tp)
+
+ # Delete a point
+ case 'd':
+ call gt_delpt (gd,px, py, Memr[x], Memr[y], npix,
+ Memi[deleted], undelete)
+
+ # Undelete a point
+ case 'u':
+ if (undelete == YES) {
+ undelete = NO
+ call printf ("Now deleting points\n")
+ } else {
+ undelete = YES
+ call printf ("Now undeleting points\n")
+ }
+
+ # Revert to normal table editor
+ case 'v':
+ silent = false
+ readonly = false
+ inplace = false
+
+ # First update the table
+ call gt_update (tp, tpr, Memr[x], Memr[y], Memi[deleted], npix)
+ call tbtclo (tp)
+ call gdeactivate (gd, 0)
+ call edit (table_name, " ", silent, readonly, inplace)
+
+ # Now read in the data (which may have been edited
+ npix_save = npix
+ tp = tbtopn (table_name, READ_WRITE, NULL)
+ call gt_rdxycol (tp, xcolumn, ycolumn, x, y, size, null, npix,
+ bad_column)
+ if (npix < 0) {
+ npix = npix_save
+ call printf ("Cannot find column %s")
+ call pargstr (bad_column)
+ }
+ call greactivate (gd, AW_PAUSE)
+ call gclear (gd)
+ goto replot_
+
+ # Undelete status
+ case 'z':
+ if (undelete == NO) {
+ call printf ("Currently deleting points\n")
+ } else {
+ call printf ("Currently undeleting points\n")
+ }
+
+ # Delete points > Y
+ case 't':
+ call gt_dygt (gd, py, Memr[x], Memr[y], npix,
+ Memi[deleted], undelete)
+
+ # Delete points < Y
+ case 'b':
+ call gt_dylt (gd, py, Memr[x], Memr[y], npix,
+ Memi[deleted], undelete)
+
+ # Delete points > X
+ case 'r':
+ call gt_dxgt (gd, px, Memr[x], Memr[y], npix,
+ Memi[deleted], undelete)
+
+ # Delete points < X
+ case 'l':
+ call gt_dxlt (gd, px, Memr[x], Memr[y], npix,
+ Memi[deleted], undelete)
+
+ # Colon commands:
+ case ':':
+ # Command mode
+ for (ip=1; IS_WHITE (cmd[ip]); ip = ip + 1)
+ ;
+
+ switch (cmd[ip]) {
+ case 'x':
+ # Read in a new X column
+ ip = ip + 1
+ auto_replot = true
+ if (strncmp (cmd[ip], "-", 1) == 0) {
+ ip = ip + 1
+ auto_replot = false
+ }
+ call amovc (xcolumn, col_save, SZ_COLNAME)
+ call ctowrd (cmd, ip, xcolumn, SZ_FNAME)
+ npix_save = npix
+ call gt_rdxycol (tp, xcolumn, ycolumn, x, y, size, null,
+ npix, bad_column)
+ if (npix < 0) {
+ npix = npix_save
+ call gdeactivate (gd, 0)
+ call printf ("Cannot find column %s")
+ call pargstr (bad_column)
+ call greactivate (gd, 0)
+ call amovc (col_save, xcolumn, SZ_COLNAME)
+ }
+ if (auto_replot) {
+ call gclear (gd)
+ mark_del = true
+ goto replot_
+ }
+
+ case 'y':
+ # Read in a new Y column
+ ip = ip + 1
+ auto_replot = true
+ if (strncmp (cmd[ip], "-", 1) == 0) {
+ ip = ip + 1
+ auto_replot = false
+ }
+ call amovc (ycolumn, col_save, SZ_COLNAME)
+ call ctowrd (cmd, ip, ycolumn, SZ_FNAME)
+ npix_save = npix
+ call gt_rdxycol (tp, xcolumn, ycolumn, x, y,
+ size, null, npix, bad_column)
+ if (npix < 0) {
+ call gdeactivate (gd, 0)
+ npix = npix_save
+ call printf ("Cannot find column %s")
+ call pargstr (bad_column)
+ call greactivate (gd, 0)
+ call amovc (col_save, ycolumn, SZ_COLNAME)
+ }
+ if (auto_replot) {
+ call gclear (gd)
+ mark_del = true
+ goto replot_
+ }
+
+ default:
+ call printf (bell)
+
+ }
+
+ default:
+ call printf (bell)
+
+ }
+ }
+ call sfree (sp)
+ call gclose (gd)
+end
+
+# TGR_ONINT2 -- Interrupt handler for the task graph. Branches back to ZSVJMP
+# in the main routine to permit shutdown without an error message.
+
+procedure tgr_onint2 (vex, next_handler)
+
+int vex # Virtual exception
+int next_handler # not used
+
+int tgrjmp[LEN_JUMPBUF]
+common /tgrcom/ tgrjmp
+
+begin
+ call xer_reset()
+ call zdojmp (tgrjmp, vex)
+end
+
+
+# INIT_MARK2 -- Returns integers code for marker type string.
+
+procedure init_mark2 (marker, imark)
+
+char marker[SZ_FNAME] # Marker type as a string
+int imark # Integer code for marker - returned
+
+bool streq()
+
+begin
+ if (streq (marker, "point"))
+ imark = GM_POINT
+ else if (streq (marker, "box"))
+ imark = GM_BOX
+ else if (streq (marker, "plus"))
+ imark = GM_PLUS
+ else if (streq (marker, "cross"))
+ imark = GM_CROSS
+ else if (streq (marker, "circle"))
+ imark = GM_CIRCLE
+ else if (streq (marker, "hebar"))
+ imark = GM_HEBAR
+ else if (streq (marker, "vebar"))
+ imark = GM_VEBAR
+ else if (streq (marker, "hline"))
+ imark = GM_HLINE
+ else if (streq (marker, "vline"))
+ imark = GM_VLINE
+ else if (streq (marker, "diamond"))
+ imark = GM_DIAMOND
+ else {
+ call eprintf ("Unrecognized marker type, using 'box'\n")
+ imark = GM_BOX
+ }
+end
diff --git a/pkg/utilities/nttools/gtedit/gtrdxycol.x b/pkg/utilities/nttools/gtedit/gtrdxycol.x
new file mode 100644
index 00000000..8bf47f98
--- /dev/null
+++ b/pkg/utilities/nttools/gtedit/gtrdxycol.x
@@ -0,0 +1,50 @@
+include <error.h>
+include <tbset.h>
+
+# GT_RDXYCOL -- read X and Y plot data from two column of the same table
+
+procedure gt_rdxycol (tp, xcolumn, ycolumn, x, y, size, null, numrows, bad_column)
+
+pointer tp # Table descriptor
+char xcolumn[SZ_COLNAME], ycolumn[SZ_COLNAME] # Column names
+pointer x, y, size # Pointers to x, y and size vectors
+int numrows # number of pixels or rows in the table
+char bad_column[SZ_COLNAME] # Return bad column name
+
+pointer xcdp, ycdp # Pointers to column descriptors
+pointer null # Pointer to null
+int numcols
+int i
+
+int tbpsta()
+bool streq()
+
+begin
+ numcols = 1
+ numrows = tbpsta (tp, TBL_NROWS)
+ call aclrc (bad_column, SZ_COLNAME)
+
+ if (streq (xcolumn, NULL)) {
+ do i = 1, numrows
+ Memr[x + i - 1] = float(i)
+ } else {
+ call tbcfnd (tp, xcolumn, xcdp, numcols)
+ if (xcdp <= 0) {
+ numrows = -1
+ call amovc (xcolumn, bad_column, SZ_COLNAME)
+ return
+ }
+ call tbcgtr (tp, xcdp, Memr[x], Memb[null], 1, numrows)
+ }
+
+ call tbcfnd (tp, ycolumn, ycdp, numcols)
+ if (ycdp <= 0) {
+ numrows = -1
+ call amovc (ycolumn, bad_column, SZ_COLNAME)
+ return
+ }
+
+ call tbcgtr (tp, ycdp, Memr[y], Memb[null], 1, numrows)
+
+ return
+end
diff --git a/pkg/utilities/nttools/gtedit/gtupdate.x b/pkg/utilities/nttools/gtedit/gtupdate.x
new file mode 100644
index 00000000..7308c38f
--- /dev/null
+++ b/pkg/utilities/nttools/gtedit/gtupdate.x
@@ -0,0 +1,36 @@
+# GT_UPDATE -- Delete points currently marked for deletion and update data
+
+procedure gt_update (tp, tpr, x, y, deleted, npix)
+
+pointer tp, tpr
+real x[ARB]
+real y[ARB]
+int npix
+int deleted[ARB]
+
+int i, j, ndelete
+
+begin
+ # Delete the points
+ call gt_dodel (tp, tpr, deleted, npix)
+
+ # Update data arrays j = 0
+ ndelete = 0
+ for (i = 1; i <= npix; i = i + 1) {
+ j = j + 1
+ if (deleted[i] == YES) {
+ ndelete = ndelete + 1
+ i = i + 1
+ while (deleted[i] == YES) {
+ ndelete = ndelete + 1
+ i = i + 1
+ }
+ }
+ x[j] = x[i]
+ y[j] = y[i]
+ }
+
+ call aclri (deleted, npix)
+ npix = npix - ndelete
+end
+
diff --git a/pkg/utilities/nttools/gtedit/gtwrdata.x b/pkg/utilities/nttools/gtedit/gtwrdata.x
new file mode 100644
index 00000000..bc0022e2
--- /dev/null
+++ b/pkg/utilities/nttools/gtedit/gtwrdata.x
@@ -0,0 +1,90 @@
+include <mach.h>
+include <gset.h>
+include <tbset.h>
+
+# GT_WRDATA -- Write out the complete table record for this point
+
+procedure gt_wrdata (gd, tp, wx, wy, x, y, npix)
+
+pointer gd # Graphics descriptor
+pointer tp # Table descriptor
+real wx # Cursor position
+real wy # ""
+real x[ARB] # Plotted data
+real y[ARB] # Plotted data
+int npix # # of pixels
+
+pointer sp
+pointer cname, cunits, cfmt # pointers to scratch space for column info
+pointer ctext, cp
+int row, i, colnum, datatype, lendata, lenfmt, ncols
+int ip
+real r2min, r2, x0, y0
+
+pointer tbpsta(), tbcnum()
+
+begin
+ # Allocate some space
+ call smark (sp)
+ call salloc (cname, SZ_LINE, TY_CHAR)
+ call salloc (cunits, SZ_LINE, TY_CHAR)
+ call salloc (cfmt, SZ_COLFMT, TY_CHAR)
+ call salloc (ctext, SZ_LINE, TY_CHAR)
+
+ # Search for the nearest point
+ row = 0
+ r2min = MAX_REAL
+
+ # Transform world cursor coordintes to NDC
+ call gctran (gd, wx, wy, wx, wy, 1, 0)
+ do i = 1 , npix {
+ call gctran (gd, x[i], y[i], x0, y0, 1, 0)
+ if (x[i] < INDEFR && y[i] < INDEFR)
+ r2 = (wx - x0) ** 2 + (wy - y0) ** 2
+ else
+ r2 = MAX_REAL
+
+ if (r2 < r2min) {
+ r2min = r2
+ row = i
+ }
+ }
+
+ if (row != 0) {
+ # Deactivate the workstation
+ call gdeactivate (gd, 0)
+ # Now get the info on the columns
+ ncols = tbpsta (tp, TBL_NCOLS)
+
+ call printf ("\n")
+ do i = 1, ncols {
+ cp = tbcnum (tp, i)
+ call tbcinf (cp,
+ colnum, Memc[cname], Memc[cunits], Memc[cfmt],
+ datatype, lendata, lenfmt)
+
+ # Print column units (ignore trailing blanks)
+ # (calling sequence of inquotes modified by PEH on 13 Jan 1995)
+ call inquotes (Memc[cunits], Memc[cunits], SZ_LINE, NO)
+ call printf (" %-14s ")
+ call pargstr (Memc[cunits])
+
+ # Print column name (and include trailing blanks)
+ call inquotes (Memc[cname], Memc[cname], SZ_LINE, YES)
+ call printf ("%-16s ")
+ call pargstr (Memc[cname])
+
+ #Print column value
+ # Modified by by PEH, 9 Sept 1994:
+ # remove case statement, and skip leading blanks.
+ call tbegtt (tp, cp, row, Memc[ctext], SZ_LINE)
+ ip = 0
+ while (Memc[ctext+ip] == ' ')
+ ip = ip + 1
+ call printf ("%s\n")
+ call pargstr (Memc[ctext+ip])
+ }
+ }
+ call greactivate (gd, AW_PAUSE)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/gtedit/gtwrhead.x b/pkg/utilities/nttools/gtedit/gtwrhead.x
new file mode 100644
index 00000000..2b941be4
--- /dev/null
+++ b/pkg/utilities/nttools/gtedit/gtwrhead.x
@@ -0,0 +1,47 @@
+include <gset.h>
+include <tbset.h>
+
+# GT_WRHEAD -- Write out the column names of the table
+
+procedure gt_wrhead (gd, tp)
+
+pointer gd # Graphics descriptor
+pointer tp # Table descriptor
+
+pointer sp
+pointer cname, cunits, cfmt # pointers to scratch space for column info
+pointer ctext, cp
+int i, colnum, datatype, lendata, lenfmt, ncols
+
+pointer tbpsta(), tbcnum()
+
+begin
+ # Allocate some space
+ call smark (sp)
+ call salloc (cname, SZ_LINE, TY_CHAR)
+ call salloc (cunits, SZ_LINE, TY_CHAR)
+ call salloc (cfmt, SZ_COLFMT, TY_CHAR)
+ call salloc (ctext, SZ_LINE, TY_CHAR)
+
+ # Deactivate the workstation
+ call gdeactivate (gd, 0)
+ # Now get the info on the columns
+ ncols = tbpsta (tp, TBL_NCOLS)
+
+ call printf ("Column names:\n\n")
+ do i = 1, ncols {
+ cp = tbcnum (tp, i)
+ call tbcinf (cp,
+ colnum, Memc[cname], Memc[cunits], Memc[cfmt],
+ datatype, lendata, lenfmt)
+
+ # Print column name (and include trailing blanks)
+ # (calling sequence of inquotes modified by PEH on 13 Jan 1995)
+ call inquotes (Memc[cname], Memc[cname], SZ_LINE, YES)
+ call printf ("%-16s \n")
+ call pargstr (Memc[cname])
+
+ }
+ call greactivate (gd, AW_PAUSE)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/gtedit/mkpkg b/pkg/utilities/nttools/gtedit/mkpkg
new file mode 100644
index 00000000..6c58f092
--- /dev/null
+++ b/pkg/utilities/nttools/gtedit/mkpkg
@@ -0,0 +1,19 @@
+# GTEDIT task
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ gtdelete.x <gio.h>
+ gtdodel.x <tbset.h>
+ gthinfo.x <tbset.h>
+ gtplot.x <config.h> <ctype.h> <error.h> <fset.h> <gset.h> \
+ <imhdr.h> <mach.h> <xwhen.h> <tbset.h>
+ gtrdxycol.x <error.h> <tbset.h>
+ gtupdate.x
+ gtwrdata.x <gset.h> <tbset.h>
+ gtwrhead.x <gset.h> <tbset.h>
+ t_gtedit.x <config.h> <ctype.h> <error.h> \
+ <imhdr.h> <mach.h> <xwhen.h> <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/gtedit/t_gtedit.x b/pkg/utilities/nttools/gtedit/t_gtedit.x
new file mode 100644
index 00000000..dc1b105d
--- /dev/null
+++ b/pkg/utilities/nttools/gtedit/t_gtedit.x
@@ -0,0 +1,184 @@
+include <xwhen.h>
+include <config.h>
+include <imhdr.h>
+include <mach.h>
+include <error.h>
+include <ctype.h>
+include <fio.h>
+include <fset.h>
+include <tbset.h> # TBtables
+
+define GT_QUIT 0
+define GT_EXIT 1
+
+# GTEDIT -- Interactive STSDAS Table editor.
+
+procedure t_gtedit()
+
+pointer input # Name of input table
+pointer device
+pointer xcolumn # Name of column for X
+pointer ycolumn # Name of column for Y
+pointer output
+pointer reject
+pointer scrname
+bool inplace
+
+pointer x, y, null, size, sp, tp, deleted, tpr
+pointer errmsg, bad_column
+int npix
+int window # note: this is apparently not used
+int phu_copied # set by tbfpri and ignored
+int tgrjmp[LEN_JUMPBUF], epa, old_onint, status
+bool do_delete, do_quit
+
+bool clgetb()
+int fstati(), scan(), strncmp(), tbpsta()
+pointer tbtopn()
+extern tgr_onint2()
+data window /0/
+common /tgrcom/ tgrjmp
+
+begin
+ if (fstati (STDOUT, F_REDIR) == NO)
+ call fseti (STDOUT, F_FLUSHNL, YES)
+
+ # Initialize curve pointers to NULL, in case ggplot aborts without
+ # allocating any buffers.
+ x = NULL
+ y = NULL
+ size = NULL
+ npix = NULL
+
+ # Get some Memory
+ call smark (sp)
+ call salloc (input, SZ_FNAME, TY_CHAR)
+ call salloc (device, SZ_FNAME, TY_CHAR)
+ call salloc (xcolumn, SZ_FNAME, TY_CHAR)
+ call salloc (ycolumn, SZ_FNAME, TY_CHAR)
+ call salloc (output, SZ_FNAME, TY_CHAR)
+ call salloc (reject, SZ_FNAME, TY_CHAR)
+ call salloc (scrname, SZ_FNAME, TY_CHAR)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+ call salloc (bad_column, SZ_COLNAME, TY_CHAR)
+ call aclrc (Memc[reject], SZ_FNAME)
+ call aclrc (Memc[output], SZ_FNAME)
+
+ call clgstr ("input", Memc[input], SZ_FNAME)
+
+ # Fetch plotting parameters.
+ call clgstr ("device", Memc[device], SZ_FNAME)
+
+ # Get column names etc.
+ call clgstr ("xcolumn", Memc[xcolumn], SZ_FNAME)
+ call clgstr ("ycolumn", Memc[ycolumn], SZ_FNAME)
+ inplace = clgetb ("inplace") # modified by PEH 13-Jul-92
+
+ # Do we need to get the output file name
+ if (!inplace) {
+ call clgstr ("output", Memc[output], SZ_FNAME)
+ if (strncmp (Memc[output], "", 1) == 0) {
+ call clpstr ("gtedit.output.p_mode", "q")
+ call clgstr ("output", Memc[output], SZ_FNAME)
+ call clpstr ("gtedit.output.p_mode", "h")
+ }
+ }
+ call clgstr ("reject", Memc[reject], SZ_FNAME)
+
+ if (inplace) {
+ # Copy the name of the table to scrname and open it by that name
+ call strcpy (Memc[input], Memc[scrname], SZ_FNAME)
+ tp = tbtopn (Memc[scrname], READ_WRITE, 0)
+ } else {
+ # Copy the table to the output and work on the output.
+ # The call to fcopy was replaced by tbtcpy by PEH on 8-Nov-1993.
+ # The call to tbfpri was added by PEH on 8-Apr-1999.
+ call tbfpri (Memc[input], Memc[output], phu_copied)
+ call tbtcpy (Memc[input], Memc[output])
+ tp = tbtopn (Memc[output], READ_WRITE, 0)
+ }
+
+ # Number of rows
+ npix = tbpsta (tp, TBL_NROWS)
+ iferr {
+ call malloc (x, npix, TY_REAL)
+ call malloc (y, npix, TY_REAL)
+ call malloc (size, npix, TY_REAL)
+ call malloc (null, npix, TY_REAL)
+ } then
+ call erract (EA_FATAL)
+
+
+ # Open reject table if required
+ tpr = NULL
+ if (Memc[reject] != EOS) {
+ tpr = tbtopn (Memc[reject], NEW_COPY, tp)
+ call tbtcre (tpr)
+ call tbhcal (tp, tpr)
+ }
+
+ # Install interrupt exception handler.
+ call zlocpr (tgr_onint2, epa)
+ call xwhen (X_INT, epa, old_onint)
+
+ call zsvjmp (tgrjmp, status)
+ if (status == OK) {
+ # Fetch remaining params and draw the plot.
+ call gt_rdxycol (tp, Memc[xcolumn], Memc[ycolumn], x, y, size,
+ null, npix, Memc[bad_column])
+
+ # Exit if no column
+ if (npix < 0) {
+ call sprintf (Memc[errmsg], SZ_LINE, "Cannot find column %s")
+ call pargstr (Memc[bad_column])
+ call error (0, Memc[errmsg])
+ }
+ # Now allocate space for the deleted array
+ call salloc (deleted, npix, TY_INT)
+ call aclri (Memi[deleted], npix)
+
+ call gteplot (Memc[device], Memc[input], tp, tpr, deleted,
+ Memc[xcolumn], Memc[ycolumn], x, y, size, null, npix,
+ Memc[input], status)
+ }
+
+ if (status == GT_EXIT) {
+
+ # Actually delete the rows and save rejects (if requested)
+ call printf ("Please confirm update of output table [y/n]: ")
+ call flush (STDOUT)
+ if (scan() == EOF)
+ call gt_dodel (tp, tpr, Memi[deleted], npix)
+ else {
+ call gargb (do_delete)
+ if (do_delete)
+ call gt_dodel (tp, tpr, Memi[deleted], npix)
+ }
+ } else if (status == GT_QUIT) {
+
+ call printf (
+ "Please confirm quit with NO update of output table [y/n]: ")
+ call flush (STDOUT)
+ do_quit = false # bug fix from Doug Tody, 22-Jan-1993
+ if (scan() != EOF)
+ call gargb (do_quit)
+ if (!do_quit)
+ call gt_dodel (tp, tpr, Memi[deleted], npix)
+ } else if (status == ERR)
+ call fseti (STDOUT, F_CANCEL, OK)
+
+ # Close table
+ call tbtclo (tp)
+ if (tpr != NULL)
+ call tbtclo (tpr)
+
+ # Return buffer space whether or not an error occurs while plotting.
+
+ call mfree (x, TY_REAL)
+ call mfree (y, TY_REAL)
+ call mfree (size, TY_REAL)
+ call mfree (null, TY_REAL)
+
+ call sfree (sp)
+
+end
diff --git a/pkg/utilities/nttools/gtpar.par b/pkg/utilities/nttools/gtpar.par
new file mode 100644
index 00000000..c5e66541
--- /dev/null
+++ b/pkg/utilities/nttools/gtpar.par
@@ -0,0 +1,27 @@
+wx1,r,h,0.,,,left world x-coord if not autoscaling
+wx2,r,h,0.,,,right world x-coord if not autoscaling
+wy1,r,h,0.,,,lower world y-coord if not autoscaling
+wy2,r,h,0.,,,upper world y-coord if not autoscaling
+marker,s,h,"box","point|box|plus|cross|circle|diamond|hline|vline|hebar|vebar",\
+,"point marker character: \n\
+ point, box, plus, cross, circle,\n\
+ diamond, hline, vline, hebar, vebar"
+szmarker,r,h,5E-3,,,marker size (0 => list input; < 0 => NDC)
+logx,b,h,no,,,log scale x-axis?
+logy,b,h,no,,,log scale y-axis?
+box,b,h,yes,,,draw box around periphery of window?
+ticklabels,b,h,yes,,,label tick marks?
+grid,b,h,no,,,draw grid lines on plot
+xlabel,s,h,"",,,x-axis label
+ylabel,s,h,"",,,y-axis label
+title,s,h,"imtitle",,,title for plot
+vx1,r,h,0.,,,left limit of device viewport (0.0:1.0)
+vx2,r,h,0.,,,right limit of device viewport (0.0:1.0)
+vy1,r,h,0.,,,bottom limit of device viewport (0.0:1.0)
+vy2,r,h,0.,,,upper limit of device viewport (0.0:1.0)
+majrx,i,h,5,,,number of major divisions along x grid
+minrx,i,h,5,,,number of minor divisions along x grid
+majry,i,h,5,,,number of major divisions along y grid
+minry,i,h,5,,,number of minor divisions along y grid
+round,b,h,no,,,round axes to nice values?
+fill,b,h,yes,,,fill viewport vs enforce unity aspect ratio?
diff --git a/pkg/utilities/nttools/imtab.par b/pkg/utilities/nttools/imtab.par
new file mode 100644
index 00000000..8cbdb470
--- /dev/null
+++ b/pkg/utilities/nttools/imtab.par
@@ -0,0 +1,8 @@
+input,s,a,"",,,"name of input image"
+outtable,s,a,"",,,"name of output table"
+colname,s,a,"",,,"name of column for image data"
+pname,s,h,"",,,"root for pixel position column name, or null"
+wcs,s,h,"logical","logical|physical|world",,"coordinate system for pixels"
+formats,s,h,"",,,"list of pixel coordinate formats"
+tbltype,s,h,"default","default|row|column|text",,"row or column ordered table"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/imtab/imtab.h b/pkg/utilities/nttools/imtab/imtab.h
new file mode 100644
index 00000000..2f280d60
--- /dev/null
+++ b/pkg/utilities/nttools/imtab/imtab.h
@@ -0,0 +1,4 @@
+define IMTAB_NO_WCS 0 # pixel coordinates will not be written out
+define IMTAB_LOGICAL 1 # wcs = logical
+define IMTAB_PHYSICAL 2 # wcs = physical
+define IMTAB_WORLD 3 # wcs = world
diff --git a/pkg/utilities/nttools/imtab/imtab.x b/pkg/utilities/nttools/imtab/imtab.x
new file mode 100644
index 00000000..8e8cb324
--- /dev/null
+++ b/pkg/utilities/nttools/imtab/imtab.x
@@ -0,0 +1,476 @@
+include <error.h>
+include <fset.h> # to check whether output is redirected
+include <imhdr.h>
+include <mach.h> # for MAX_SHORT
+include <tbset.h>
+include "imtab.h"
+
+define NCOLS (1 + IM_MAXDIM) # max number of columns to write to the table
+
+# imtab -- create a table from an image
+# This task copies data from an image to a table. Pixel values are
+# read from the image line by line and written to a column in increasing
+# row number.
+# If the table already exists then columns will be added to it; note that
+# the column names must not conflict with existing names.
+#
+# Phil Hodge, 10-Jan-1991 Task created.
+# Phil Hodge, 17-Mar-1992 Include text as a valid table type; call pargstr
+# to pass cname in case column name already exists.
+# Phil Hodge, 16-Apr-1993 Include short datatype.
+# Phil Hodge, 28-Sep-1993 Include wcs option for pixel coordinates.
+# Phil Hodge, 13-Dec-1993 Slight changes to itb_init because of optimizer
+# problems with SGI Fortran.
+# Phil Hodge, 8-Jun-1999 Set output to STDOUT if redirected.
+# Phil Hodge, 30-Mar-2000 Allow lists of names for input and output.
+
+procedure imtab()
+
+pointer input # name of an input image
+pointer outlist # names of output tables
+pointer outtable # name of an output table
+char cname[SZ_COLNAME,NCOLS] # column names
+char c_root[SZ_COLNAME] # root for column names for position
+pointer wcs # wcs name if c_root != ""
+pointer formats # list of formats for pixel coords
+pointer ttype # type of output table (if new)
+#--
+pointer sp
+pointer im # pointer to image descriptors
+pointer xps, xpr, xpd # pointer to input data from image
+pointer tp # pointer to descriptor for output table
+pointer cp[NCOLS] # column descriptors
+pointer mw, ct # mwcs pointers
+
+pointer imt, tnt # pointers for filename templates
+int nin, nout # numbers of names in lists
+int junk
+
+long v[IM_MAXDIM] # for call to imgnld
+int lcoords[IM_MAXDIM] # "logical" coordinates, copied from v
+real ipcoords[IM_MAXDIM] # "logical" coordinates, copied from v
+real opcoords[IM_MAXDIM] # "physical" coordinates from ipcoords
+double iwcoords[IM_MAXDIM] # "logical" coordinates, copied from v
+double owcoords[IM_MAXDIM] # "world" coordinates from iwcoords
+
+int wcs_type # wcs name as an int
+int ax[IM_MAXDIM] # ax[i] is physical axis for logical axis i
+real inr[IM_MAXDIM] # copy of input coordinates used by itb_ctranr
+double ind[IM_MAXDIM] # copy of input coordinates used by itb_ctrand
+int wcsdim # dimension of physical image coord system
+int impixtype # data type of image
+
+int ncols # number of columns to create
+int dtype[NCOLS] # data type of each table column
+int frow, lrow # row number limits for tbcptd
+int row # loop index
+int i, j, k # loop indexes
+bool done # loop-termination flag
+int clgwrd()
+int fstati()
+int imgnls(), imgnlr(), imgnld()
+pointer imtopenp(), tbnopen()
+int imtlen(), imtgetim(), tbnlen(), tbnget()
+bool streq()
+
+begin
+ call smark (sp)
+ call salloc (input, SZ_FNAME, TY_CHAR)
+ call salloc (outlist, SZ_LINE, TY_CHAR)
+ call salloc (outtable, SZ_FNAME, TY_CHAR)
+ call salloc (wcs, SZ_FNAME, TY_CHAR)
+ call salloc (formats, SZ_FNAME, TY_CHAR)
+ call salloc (ttype, SZ_FNAME, TY_CHAR)
+
+ imt = imtopenp ("input")
+ nin = imtlen (imt)
+
+ if (fstati (STDOUT, F_REDIR) == YES)
+ call strcpy ("STDOUT", Memc[outlist], SZ_LINE)
+ else
+ call clgstr ("outtable", Memc[outlist], SZ_LINE)
+ tnt = tbnopen (Memc[outlist])
+ nout = tbnlen (tnt)
+
+ # Compare the numbers of input and output names.
+ call itb_names (nin, nout, Memc[outlist])
+
+ # Get the column names.
+ call clgstr ("colname", cname[1,1], SZ_COLNAME) # name for data
+ call clgstr ("pname", c_root, SZ_COLNAME) # root name for position
+ call xt_stripwhite (c_root)
+ if (c_root[1] != EOS) {
+ wcs_type = clgwrd ("wcs", Memc[wcs], SZ_FNAME,
+ "|logical|physical|world")
+ call clgstr ("formats", Memc[formats], SZ_FNAME)
+ } else {
+ wcs_type = IMTAB_NO_WCS
+ Memc[formats] = EOS
+ }
+
+ # What table type should be created?
+ if (streq (Memc[outlist], "STDOUT"))
+ call strcpy ("default", Memc[ttype], SZ_FNAME)
+ else
+ call clgstr ("tbltype", Memc[ttype], SZ_FNAME)
+
+ # Loop over the list of input images.
+ while (imtgetim (imt, Memc[input], SZ_FNAME) != EOF) {
+
+ if (nout == 1)
+ call tbnrew (tnt)
+ junk = tbnget (tnt, Memc[outtable], SZ_FNAME)
+
+ # Open the input image and the wcs and get the column data types.
+ call itb_init (Memc[input], wcs_type, im, dtype)
+ impixtype = IM_PIXTYPE(im)
+
+ # Initialize the wcs.
+ call itb_wcs_init (im, wcs_type, mw, ct, ax, wcsdim)
+ call amovkr (1., inr, IM_MAXDIM)
+ call amovkd (1.d0, ind, IM_MAXDIM)
+
+ # Initialize for reading the image.
+ do k = 1, IM_MAXDIM
+ v[k] = 1
+
+ # Initialize for writing to the table.
+ row = 1
+ frow = 1
+ lrow = IM_LEN(im,1)
+ if (wcs_type == IMTAB_NO_WCS)
+ ncols = 1
+ else if (wcs_type == IMTAB_LOGICAL)
+ ncols = 1 + IM_NDIM(im)
+ else if (wcs_type == IMTAB_PHYSICAL || wcs_type == IMTAB_WORLD)
+ ncols = 1 + wcsdim
+
+ # Open or create the output table.
+ call itb_table (im, Memc[outtable], wcs_type, Memc[ttype], ncols,
+ cname, c_root, Memc[formats], dtype, tp, cp)
+
+ # Copy each line of the image into a column of the table.
+ done = false
+ while (!done) {
+
+ # Assign pixel index for all but the first axis.
+ if (wcs_type == IMTAB_LOGICAL)
+ do j = 2, ncols-1
+ lcoords[j] = v[j]
+ else if (wcs_type == IMTAB_PHYSICAL)
+ do j = 2, ncols-1
+ ipcoords[j] = real (v[j])
+ else if (wcs_type == IMTAB_WORLD)
+ do j = 2, ncols-1
+ iwcoords[j] = double (v[j])
+
+ if (impixtype == TY_SHORT || impixtype == TY_UBYTE)
+ done = (imgnls (im, xps, v) == EOF)
+ else if (impixtype == TY_REAL || impixtype == TY_USHORT)
+ done = (imgnlr (im, xpr, v) == EOF)
+ else
+ done = (imgnld (im, xpd, v) == EOF)
+
+ if (!done) {
+
+ # Write the pixel coordinates.
+ if (wcs_type == IMTAB_LOGICAL) {
+ do i = 1, IM_LEN(im,1) { # simply write pixel numbers
+ lcoords[1] = i
+ call tbrpti (tp, cp[2], lcoords, ncols-1, row)
+ row = row + 1
+ }
+ } else if (wcs_type == IMTAB_PHYSICAL) {
+ do i = 1, IM_LEN(im,1) {
+ ipcoords[1] = real (i)
+ call itb_ctranr (im, ct, ax, inr,
+ ipcoords, opcoords, wcsdim)
+ call tbrptr (tp, cp[2], opcoords, ncols-1, row)
+ row = row + 1
+ }
+ } else if (wcs_type == IMTAB_WORLD) {
+ do i = 1, IM_LEN(im,1) {
+ iwcoords[1] = double (i)
+ call itb_ctrand (im, ct, ax, ind,
+ iwcoords, owcoords, wcsdim)
+ call tbrptd (tp, cp[2], owcoords, ncols-1, row)
+ row = row + 1
+ }
+ }
+
+ # Copy image line into a portion of a column of the table.
+ if (impixtype == TY_SHORT || impixtype == TY_UBYTE)
+ call tbcpts (tp, cp[1], Mems[xps], frow, lrow)
+ else if (impixtype == TY_REAL || impixtype == TY_USHORT)
+ call tbcptr (tp, cp[1], Memr[xpr], frow, lrow)
+ else
+ call tbcptd (tp, cp[1], Memd[xpd], frow, lrow)
+ frow = frow + IM_LEN(im,1)
+ lrow = lrow + IM_LEN(im,1)
+ }
+ }
+ if (mw != NULL)
+ call mw_close (mw) # close mwcs
+ call imunmap (im) # close image
+ call tbtclo (tp) # close table
+ }
+
+ call imtclose (imt)
+ call tbnclose (tnt)
+
+ call sfree (sp)
+end
+
+# This routine checks the number of input and output file names.
+# The number of names in the input and output lists must be the same,
+# unless all the input will be written to the standard output.
+
+procedure itb_names (nin, nout, outlist)
+
+int nin # i: number of input image names
+int nout # i: number of output table names
+char outlist[ARB] # i: output names (to be compared with "STDOUT")
+#--
+bool strne()
+
+begin
+ if (nin == 0)
+ call error (1, "no input image specified")
+
+ if (nout == 0)
+ call error (1, "no output table specified")
+
+ if (nin != nout && strne (outlist, "STDOUT")) {
+
+ if (nin == 1) {
+ call eprintf ("There is one input image")
+ } else {
+ call eprintf ("There are %d input images")
+ call pargi (nin)
+ }
+ if (nout == 1) {
+ call eprintf (" and one output table;\n")
+ } else {
+ call eprintf (" and %d output tables;\n")
+ call pargi (nout)
+ }
+ call error (1, "the lists must have the same length")
+ }
+end
+
+# itb_init -- get data types and column info
+# This routine opens the input image and gets the data type for each column.
+
+procedure itb_init (input, wcs_type, im, dtype)
+
+char input[ARB] # i: name of image
+int wcs_type # i: type of wcs for pixel coordinates
+pointer im # o: imhdr pointer
+int dtype[NCOLS] # o: data type of each table column
+#--
+int i # loop index
+int fill_extra # dummy
+pointer immap()
+
+begin
+ # Open input image.
+ im = immap (input, READ_ONLY, NULL)
+
+ # Fewer data types are allowed for tables than for images.
+ switch (IM_PIXTYPE(im)) {
+ case TY_UBYTE, TY_SHORT:
+ dtype[1] = TY_SHORT
+ case TY_USHORT, TY_INT, TY_LONG:
+ dtype[1] = TY_INT
+ case TY_REAL:
+ dtype[1] = TY_REAL
+ case TY_DOUBLE:
+ dtype[1] = TY_DOUBLE
+ default:
+ call error (1, "image data type not supported for tables")
+ }
+
+ # Set the data types of columns for pixel coordinates.
+ fill_extra = IM_NDIM(im) + 2
+ if (wcs_type == IMTAB_NO_WCS) {
+ do i = 2, NCOLS
+ dtype[i] = TY_SHORT # ignored
+
+ } else if (wcs_type == IMTAB_LOGICAL) {
+ # Check the image size to see if we can use TY_SHORT.
+ do i = 1, IM_NDIM(im) {
+ if (IM_LEN(im,i) > MAX_SHORT)
+ dtype[i+1] = TY_INT
+ else
+ dtype[i+1] = TY_SHORT
+ }
+ do i = fill_extra, NCOLS
+ dtype[i] = TY_SHORT # ignored
+
+ } else if (wcs_type == IMTAB_PHYSICAL) {
+ do i = 2, NCOLS
+ dtype[i] = TY_REAL
+
+ } else if (wcs_type == IMTAB_WORLD) {
+ do i = 2, NCOLS
+ dtype[i] = TY_DOUBLE
+ }
+end
+
+# itb_table -- initialization for output table
+# This routine opens the output table (or creates it if it doesn't already
+# exist) and creates the columns for the data and the pixel coordinates.
+
+procedure itb_table (im, outtable, wcs_type, ttype, ncols,
+ cname, c_root, formats, dtype, tp, cp)
+
+pointer im # i: imhdr pointer for input image
+char outtable[ARB] # i: name of output table
+int wcs_type # i: type of wcs for pixel coordinates
+char ttype[ARB] # i: table type (e.g. "row")
+int ncols # i: total number of columns to write
+char cname[SZ_COLNAME,NCOLS] # io: column names
+char c_root[ARB] # i: root for column name for pixels
+char formats[ARB] # i: user-specified formats for pixels
+int dtype[NCOLS] # i: data types of table columns
+pointer tp # o: pointer to table descriptor
+pointer cp[NCOLS] # o: column descriptors
+#--
+char colunits[SZ_COLUNITS,NCOLS] # column units
+char colfmt[SZ_COLFMT,NCOLS] # column format
+char history[SZ_FNAME] # for history records
+int lendat[NCOLS] # one
+int nrows
+int i
+bool new_table # true if the table does not already exist
+bool column_conflict # true if column already exists
+int ip, ctowrd()
+pointer tbtopn()
+int tbtacc()
+
+begin
+ colunits[1,1] = EOS
+ colfmt[1,1] = EOS
+
+ # Assign column names.
+ do i = 2, NCOLS {
+ call sprintf (cname[1,i], SZ_COLNAME, "%s%d")
+ call pargstr (c_root)
+ call pargi (i-1)
+ }
+
+ # Replace commas with blanks in the user-specified format string.
+ ip = 1
+ while (formats[ip] != EOS) {
+ if (formats[ip] == ',')
+ formats[ip] = ' '
+ ip = ip + 1
+ }
+
+ # Assign print format and units.
+ ip = 1
+ do i = 2, NCOLS {
+
+ if (wcs_type == IMTAB_LOGICAL) {
+
+ # If the user specified a format, use it; otherwise,
+ # assign a default.
+ if (ctowrd (formats, ip, colfmt[1,i], SZ_COLFMT) < 1) {
+ if (dtype[i] == TY_INT)
+ call strcpy ("%11d", colfmt[1,i], SZ_COLFMT)
+ else if (dtype[i] == TY_SHORT)
+ call strcpy ("%5d", colfmt[1,i], SZ_COLFMT)
+ }
+ call strcpy ("pixels", colunits[1,i], SZ_COLUNITS)
+
+ } else if (wcs_type == IMTAB_PHYSICAL) {
+
+ if (ctowrd (formats, ip, colfmt[1,i], SZ_COLFMT) < 1)
+ call strcpy ("%9.3f", colfmt[1,i], SZ_COLFMT)
+ call strcpy ("pixels", colunits[1,i], SZ_COLUNITS)
+
+ } else if (wcs_type == IMTAB_WORLD) {
+
+ if (ctowrd (formats, ip, colfmt[1,i], SZ_COLFMT) < 1)
+ colfmt[1,i] = EOS # take the default
+ colunits[1,i] = EOS # we don't know the units
+
+ } else {
+ colfmt[1,i] = EOS
+ colunits[1,i] = EOS
+ }
+ }
+
+ do i = 1, NCOLS {
+ lendat[i] = 1
+ cp[i] = NULL
+ }
+
+ nrows = 1
+ do i = 1, IM_NDIM(im)
+ nrows = nrows * IM_LEN(im,i)
+
+ # Does the table already exist?
+ new_table = (tbtacc (outtable) == NO)
+
+ if (new_table) {
+ tp = tbtopn (outtable, NEW_FILE, NULL)
+
+ if (ttype[1] == 'r') {
+ call tbpset (tp, TBL_WHTYPE, TBL_TYPE_S_ROW)
+ } else if (ttype[1] == 'c') {
+ call tbpset (tp, TBL_WHTYPE, TBL_TYPE_S_COL)
+ call tbpset (tp, TBL_ALLROWS, nrows)
+ } else if (ttype[1] == 't') {
+ call tbpset (tp, TBL_WHTYPE, TBL_TYPE_TEXT)
+ }
+ } else {
+ tp = tbtopn (outtable, READ_WRITE, NULL)
+ }
+
+ # Make sure the columns don't already exist.
+ column_conflict = false
+ if ( ! new_table ) {
+ call tbcfnd (tp, cname, cp, ncols)
+ do i = 1, ncols {
+ if (cp[i] != NULL) {
+ call eprintf ("Column %s already exists.\n")
+ call pargstr (cname[1,i])
+ column_conflict = true
+ }
+ }
+ if (column_conflict) {
+ call imunmap (im)
+ call tbtclo (tp)
+ call error (1,
+ "new columns in existing table must be unique")
+ }
+ }
+
+ # Define the columns.
+ call tbcdef (tp, cp, cname, colunits, colfmt, dtype, lendat, ncols)
+
+ if (new_table)
+ call tbtcre (tp) # open the file
+
+ # Write history info.
+ call strcpy ("Column ", history, SZ_FNAME)
+ call strcat (cname[1,1], history, SZ_FNAME) # column name for data
+ call strcat (" from ", history, SZ_FNAME)
+ call strcat (IM_HDRFILE(im), history, SZ_FNAME) # name of input image
+ call tbhadt (tp, "history", history)
+ if (ncols > 1) {
+ call strcpy ("Column ", history, SZ_FNAME)
+ call strcat (cname[1,1], history, SZ_FNAME)
+ if (ncols > 2)
+ call strcat (", pixel columns ", history, SZ_FNAME)
+ else
+ call strcat (", pixel column ", history, SZ_FNAME)
+ do i = 2, ncols-1 {
+ call strcat (cname[1,i], history, SZ_FNAME)
+ call strcat (", ", history, SZ_FNAME)
+ }
+ call strcat (cname[1,ncols], history, SZ_FNAME)
+ call tbhadt (tp, "history", history)
+ }
+end
diff --git a/pkg/utilities/nttools/imtab/itbwcs.x b/pkg/utilities/nttools/imtab/itbwcs.x
new file mode 100644
index 00000000..4ecea420
--- /dev/null
+++ b/pkg/utilities/nttools/imtab/itbwcs.x
@@ -0,0 +1,129 @@
+include <imhdr.h>
+include <mwset.h>
+include "imtab.h"
+
+# This file contains three routines: itb_wcs_init and the single and
+# double precision routines itb_ctranr & itb_ctrand.
+#
+# Phil Hodge, 30-Sep-1993 Subroutines created.
+
+# itb_wcs_init -- open wcs, etc
+# This routine gets the wcs, turns axis mapping off, and initializes
+# the transformation for physical or world coordinates. The dimension
+# of the original image and the mapping from logical to physical axis
+# numbers are returned for use by itb_ctrand and itb_ctranr.
+
+procedure itb_wcs_init (im, wcs_type, mw, ct, ax, wcsdim)
+
+pointer im # i: imhdr pointer for image
+int wcs_type # i: wcs type
+pointer mw, ct # o: mwcs pointers
+int ax[IM_MAXDIM] # o: ax[i] is physical axis for logical axis i
+int wcsdim # o: dimension of physical image coord system
+#--
+int axno[IM_MAXDIM] # axno[j] is logical axis for physical axis j
+int axval[IM_MAXDIM] # axval[j] is value if axno[j] is zero
+int ndim # number of "logical" axes
+int i, j
+pointer mw_openim(), mw_sctran()
+int mw_stati()
+
+begin
+ if (wcs_type == IMTAB_NO_WCS || wcs_type == IMTAB_LOGICAL) {
+ mw = NULL
+ ct = NULL
+ wcsdim = IM_NDIM(im)
+ return
+ }
+
+ # Get the wcs.
+ mw = mw_openim (im)
+
+ # Set up the transformation.
+ call mw_seti (mw, MW_USEAXMAP, NO)
+ if (wcs_type == IMTAB_PHYSICAL)
+ ct = mw_sctran (mw, "logical", "physical", 0)
+ else if (wcs_type == IMTAB_WORLD)
+ ct = mw_sctran (mw, "logical", "world", 0)
+ wcsdim = mw_stati (mw, MW_NPHYSDIM)
+ ndim = IM_NDIM(im)
+
+ # Get the logical axis number corresponding to each physical axis.
+ call mw_gaxmap (mw, axno, axval, wcsdim)
+
+ # Invert axno: get the physical axis number for each logical axis.
+ do i = 1, ndim # initialize
+ ax[i] = 0
+ do j = 1, wcsdim {
+ do i = 1, ndim {
+ if (axno[j] == i) {
+ ax[i] = j
+ break
+ }
+ }
+ }
+
+ # Check to be sure each axis was found.
+ do i = 1, ndim {
+ if (ax[i] < 1)
+ call error (1, "itb_mwcs_init: an axis was not found")
+ }
+end
+
+# itb_ctran -- translate coordinates with axis mapping = NO
+# This routine translates "logical" coordinates to "physical" or "world".
+# Axis mapping must have been turned off, and the mapping from logical
+# to physical axes is given by the array AX: if I is a logical axis
+# number, AX[I] is the corresponding physical axis number. Each element
+# of the array IN must have been initialized to one by the calling routine.
+# Separate single and double precision versions are included.
+
+procedure itb_ctrand (im, ct, ax, in, incoords, outcoords, wcsdim)
+
+pointer im # i: imhdr pointer
+pointer ct # i: coordinate transformation pointer
+int ax[wcsdim] # i: "logical" to "physical" mapping
+double in[IM_MAXDIM] # io: copy of incoords but includes axis mapping
+double incoords[wcsdim] # i: input "logical" coordinates
+double outcoords[wcsdim] # o: output coordinates
+int wcsdim # i: length of incoords & outcoords arrays
+#--
+int i
+
+begin
+ if (ct == NULL) {
+ call amovd (incoords, outcoords, wcsdim)
+ return
+ }
+
+ # Take account of axis mapping; i is the logical axis number.
+ do i = 1, IM_NDIM(im)
+ in[ax[i]] = incoords[i]
+
+ call mw_ctrand (ct, in, outcoords, wcsdim)
+end
+
+procedure itb_ctranr (im, ct, ax, in, incoords, outcoords, wcsdim)
+
+pointer im # i: imhdr pointer
+pointer ct # i: coordinate transformation pointer
+int ax[wcsdim] # i: "logical" to "physical" mapping
+real in[IM_MAXDIM] # io: copy of incoords but includes axis mapping
+real incoords[wcsdim] # i: input "logical" coordinates
+real outcoords[wcsdim] # o: output coordinates
+int wcsdim # i: length of incoords & outcoords arrays
+#--
+int i
+
+begin
+ if (ct == NULL) {
+ call amovr (incoords, outcoords, wcsdim)
+ return
+ }
+
+ # Take account of axis mapping; i is the logical axis number.
+ do i = 1, IM_NDIM(im)
+ in[ax[i]] = incoords[i]
+
+ call mw_ctranr (ct, in, outcoords, wcsdim)
+end
diff --git a/pkg/utilities/nttools/imtab/mkpkg b/pkg/utilities/nttools/imtab/mkpkg
new file mode 100644
index 00000000..6e6431a0
--- /dev/null
+++ b/pkg/utilities/nttools/imtab/mkpkg
@@ -0,0 +1,13 @@
+# Update the imtab & tabim application code in the ttools package library.
+# Author: HODGE, 31-DEC-1990
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ imtab.x <error.h> <imhdr.h> <mach.h> <tbset.h> "imtab.h"
+ itbwcs.x <imhdr.h> <mwset.h> "imtab.h"
+ tabim.x <imhdr.h> <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/imtab/tabim.x b/pkg/utilities/nttools/imtab/tabim.x
new file mode 100644
index 00000000..8a9e7211
--- /dev/null
+++ b/pkg/utilities/nttools/imtab/tabim.x
@@ -0,0 +1,176 @@
+include <imhdr.h>
+include <fset.h> # to check whether input is redirected
+include <tbset.h>
+
+# tabim -- create an image from one column of a table
+# This task copies a column of a table into an image. If the image already
+# exists, it will be overwritten; otherwise, a new image will be created.
+# For a new image, if the 'ndim' parameter is greater than zero, the size of
+# the image will be taken from the parameters 'n1', 'n2', etc. It is the
+# user's responsibility to ensure that the product of these values equals
+# the number of rows in the table.
+#
+# Phil Hodge, 12-Oct-1989 Task created
+# Phil Hodge, 11-Jan-1991 Allow multi-dimensional output.
+# Phil Hodge, 15-May-1998 Check null flag, and replace INDEF with -999.
+# Phil Hodge, 8-Jun-1999 Set input to STDIN if redirected.
+# Phil Hodge, 30-Mar-2000 Allow lists of names for input and output.
+
+procedure tabim()
+
+pointer inlist, outlist # for input and output names
+char intable[SZ_FNAME] # name of an input table
+char output[SZ_FNAME] # name of an output image
+char colname[SZ_COLNAME] # column name
+int ndim # dimension of output image
+int axlen[IM_MAXDIM] # length of each axis of output image
+#--
+pointer sp # stack pointer for scratch space
+pointer tp # pointer to descriptor for input table
+pointer cp # column descriptor
+pointer im # pointer to image descriptor
+pointer xp # pointer to output data for image
+pointer temp # scratch for parameter name
+pointer nullflag # scratch for null flags (ignored)
+long v[IM_MAXDIM] # for call to impnld()
+int dtype # data type
+int npix # number of pixels, accumulated one axis at a time
+int nrows # number of rows in table
+int nlines # number of lines in image
+int frow, lrow # row number limits for tbcgtd
+int i, k
+int junk
+bool new_image # true if the image does not already exist
+pointer immap(), tbtopn()
+int clgeti(), impnld(), imaccess()
+int fstati()
+int tbpsta(), tbcigi()
+
+pointer imt, tnt # pointers for filename templates
+int nin, nout # numbers of names in lists
+pointer imtopen(), tbnopen()
+int imtlen(), imtgetim(), tbnlen(), tbnget()
+
+begin
+ call smark (sp)
+ call salloc (inlist, SZ_LINE, TY_CHAR)
+ call salloc (outlist, SZ_LINE, TY_CHAR)
+ call salloc (temp, SZ_FNAME, TY_CHAR)
+
+ # Get the names of the input tables.
+ if (fstati (STDIN, F_REDIR) == YES)
+ call strcpy ("STDIN", Memc[inlist], SZ_FNAME)
+ else
+ call clgstr ("intable", Memc[inlist], SZ_FNAME)
+ tnt = tbnopen (Memc[inlist])
+ nin = tbnlen (tnt)
+
+ # Get the names of the output images.
+ call clgstr ("output", Memc[outlist], SZ_FNAME)
+ imt = imtopen (Memc[outlist])
+ nout = imtlen (imt)
+
+ if (nin == 0)
+ call error (1, "no input table specified")
+ if (nout == 0)
+ call error (1, "no output image specified")
+ if (nin != nout)
+ call error (1, "input and output lists must have the same length")
+
+ call clgstr ("colname", colname, SZ_COLNAME)
+
+ # ndim is either zero or the dimension for new output images.
+ ndim = clgeti ("ndim")
+ if (ndim < 1)
+ ndim = 1
+ do k = 1, IM_MAXDIM # initial values
+ axlen[k] = 1
+ # Get the length of all but the last axis.
+ do k = 1, ndim-1 {
+ call sprintf (Memc[temp], SZ_FNAME, "n%d")
+ call pargi (k)
+ axlen[k] = clgeti (Memc[temp])
+ }
+
+ # Loop over the list of input tables.
+ while (tbnget (tnt, intable, SZ_FNAME) != EOF) {
+
+ junk = imtgetim (imt, output, SZ_FNAME)
+
+ tp = tbtopn (intable, READ_ONLY, NULL)
+ call tbcfnd (tp, colname, cp, 1) # only one column name
+ if (cp == NULL) {
+ call tbtclo (tp)
+ call error (1, "column not found")
+ }
+ nrows = tbpsta (tp, TBL_NROWS)
+
+ # Open the output image.
+ if (imaccess (output, READ_WRITE) == YES) {
+ new_image = false
+ im = immap (output, READ_WRITE, NULL)
+ } else {
+ new_image = true
+ im = immap (output, NEW_IMAGE, NULL)
+ }
+
+ if (new_image) {
+ # Set the size of the new image.
+ IM_NDIM(im) = ndim
+ npix = 1 # initial value
+ do k = 1, ndim-1 {
+ IM_LEN(im,k) = axlen[k]
+ npix = npix * axlen[k]
+ }
+ axlen[ndim] = nrows / npix
+ IM_LEN(im,ndim) = axlen[ndim]
+
+ # The image data type is the same as that of the column.
+ dtype = tbcigi (cp, TBL_COL_DATATYPE)
+ if (dtype == TY_BOOL)
+ dtype = TY_SHORT
+ IM_PIXTYPE(im) = dtype
+ }
+
+ nlines = 1 # initial value
+ do k = 2, IM_NDIM(im)
+ nlines = nlines * IM_LEN(im,k)
+ if (IM_LEN(im,1) * nlines != nrows) {
+ call tbtclo (tp)
+ call imunmap (im)
+ if (new_image) {
+ call imdelete (output)
+ call error (1,
+ "specified axis lengths are not consistent with size of table")
+ } else {
+ call error (1,
+ "size of existing image is not consistent with size of table")
+ }
+ }
+
+ # Allocate space for the array of null flags (which we ignore),
+ # one element for each pixel in a line.
+ call salloc (nullflag, IM_LEN(im,1), TY_BOOL)
+
+ # Copy the column into the image, one line at a time.
+ do k = 1, IM_MAXDIM
+ v[k] = 1
+ frow = 1
+ lrow = IM_LEN(im,1)
+ do k = 1, nlines {
+ junk = impnld (im, xp, v)
+ call tbcgtd (tp, cp, Memd[xp], Memb[nullflag], frow, lrow)
+ do i = 0, lrow-frow {
+ if (Memb[nullflag+i])
+ Memd[xp+i] = -999.d0
+ }
+ frow = frow + IM_LEN(im,1)
+ lrow = lrow + IM_LEN(im,1)
+ }
+
+ call imunmap (im)
+ call tbtclo (tp)
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/keypar.par b/pkg/utilities/nttools/keypar.par
new file mode 100644
index 00000000..c379bec1
--- /dev/null
+++ b/pkg/utilities/nttools/keypar.par
@@ -0,0 +1,6 @@
+input,f,a,"",,,"Name of file containing header keyword"
+keyword,s,a,"",,,"Name of header keyword"
+silent,b,h,no,,,"Do not print any warning messages?"
+value,s,h,"",,,"Value of header keyword"
+found,b,h,no,,,"Was keyword found in header?"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/keyselect.par b/pkg/utilities/nttools/keyselect.par
new file mode 100644
index 00000000..6302af1d
--- /dev/null
+++ b/pkg/utilities/nttools/keyselect.par
@@ -0,0 +1,6 @@
+input,s,a,"",,,list of image names
+output,s,a,"",,,output table name
+cols,s,a,"",,,list of keyword and table column names
+expr,s,h," ",,,boolean expression used to select images
+cdfile,s,h," ",,,column description file name
+mode,s,h,"al"
diff --git a/pkg/utilities/nttools/keyselect/expr.x b/pkg/utilities/nttools/keyselect/expr.x
new file mode 100644
index 00000000..fa7e5d31
--- /dev/null
+++ b/pkg/utilities/nttools/keyselect/expr.x
@@ -0,0 +1,193 @@
+include <evexpr.h>
+include "keyselect.h"
+
+#* HISTORY *
+#* B.Simon 12-Mar-1992 Original
+#* Phil Hodge 4-Mar-2002 Free memory allocated by evexpr.
+
+# EVAL_EXPR -- Evaluate a boolean expression using image header keywords
+
+bool procedure eval_expr (im, expr)
+
+pointer im # i: image descriptor
+char expr[ARB] # i: boolean expression
+#--
+include "keyselect.com"
+
+pointer op, sp, errmsg
+
+string badtype "Expression is not of boolean type"
+string badname "Warning: header keyword %s not found in %s\n"
+
+int errget()
+pointer evexpr(), locpr()
+extern fun_expr, var_expr
+
+begin
+ call smark (sp)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ img = im
+ iferr {
+ op = evexpr (expr, locpr(var_expr), locpr (fun_expr))
+
+ } then {
+ if (errget(Memc[errmsg], SZ_LINE) == ERR_SYNTAX) {
+ call xer_reset
+ call error (ERR_SYNTAX, Memc[errmsg])
+
+ } else {
+ call xer_reset
+ call eprintf ("Warning: %s\n")
+ call pargstr (Memc[errmsg])
+ call mfree (op, TY_STRUCT)
+
+ return (false)
+ }
+ }
+
+ if (O_TYPE(op) != TY_BOOL)
+ call error (ERR_SYNTAX, badtype)
+
+ call xev_freeop (op)
+ call mfree (op, TY_STRUCT)
+ call sfree (sp)
+ return (O_VALB(op))
+end
+
+# FMT_EXPR -- Format an expression to make it easier to parse
+
+procedure fmt_expr (expr)
+
+char expr[ARB] # i: expression
+#--
+int ic, jc
+
+begin
+ # Find first non-white character
+
+ for (ic = 1; expr[ic] != EOS; ic = ic + 1) {
+ if (expr[ic] > ' ')
+ break
+ }
+
+ # Copy remaining characters, replacing newlines with blanks
+
+ jc = 1
+ for ( ; expr[ic] != EOS; ic = ic + 1) {
+ if (expr[ic] == '\n') {
+ expr[jc] = ' '
+ } else if (jc < ic) {
+ expr[jc] = expr[ic]
+ }
+ jc = jc + 1
+ }
+
+ expr[jc] = EOS
+end
+
+# FUN_EXPR -- Evaluate non-standard functions used in expression
+
+procedure fun_expr (func, argptr, nargs, op)
+
+char func[ARB] # i: function name
+pointer argptr[ARB] # i: pointers to function arguments
+int nargs # i: number of function arguments
+pointer op # o: structure containing function value
+#--
+include "keyselect.com"
+
+int arg
+pointer sp, errmsg
+
+string flist "find"
+string badfun "Unknown function name (%s)"
+string badtyp "Invalid argument type for %s"
+
+int word_match(), imaccf()
+
+begin
+ call smark (sp)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ switch (word_match (func, flist)) {
+ case 0: # unrecognized function name
+ call sprintf (Memc[errmsg], SZ_LINE, badfun)
+ call pargstr (func)
+ call error (ERR_SYNTAX, Memc[errmsg])
+
+ case 1: # find keyword in header ?
+ call xev_initop (op, 0, TY_BOOL)
+ O_VALB(op) = true
+
+ do arg = 1, nargs {
+ if (O_TYPE(argptr[arg]) != TY_CHAR) {
+ call sprintf (Memc[errmsg], SZ_LINE, badtyp)
+ call pargstr (func)
+ call error (ERR_SYNTAX, Memc[errmsg])
+ }
+
+ if (imaccf (img, O_VALC(argptr[arg])) == NO)
+ O_VALB(op) = false
+ }
+ }
+
+ call sfree (sp)
+end
+
+# VAR_EXPR -- Retrieve keyword used in expression
+
+procedure var_expr (name, op)
+
+char name[ARB] # i: keyword name
+pointer op # o: structure containing value of variable
+#--
+include "keyselect.com"
+
+int ic, dtype, type, length, junk
+pointer sp, value
+
+string badname "Expression cannot be evaluated because keyword not found"
+
+bool streq()
+int ctoi(), ctor()
+
+begin
+ call smark(sp)
+ call salloc (value, SZ_BIGCOL, TY_CHAR)
+
+ # Retrieve keyword value from image header
+
+ call get_keyword (img, name, dtype, Memc[value], SZ_BIGCOL)
+
+ # Allocate structure to hold value
+
+ if (dtype == 0) {
+ call error (ERR_NOFIND, badname)
+ } else if (dtype < 0) {
+ type = TY_CHAR
+ length = - dtype
+ } else {
+ type = dtype
+ length = 0
+ }
+
+ call xev_initop (op, length, type)
+
+ # Copy value to structure
+
+ switch (type) {
+ case TY_BOOL:
+ O_VALB(op) = streq (Memc[value], "yes")
+ case TY_CHAR:
+ call strcpy (Memc[value], O_VALC(op), length)
+ case TY_SHORT,TY_INT,TY_LONG:
+ ic = 1
+ junk = ctoi (Memc[value], ic, O_VALI(op))
+ case TY_REAL,TY_DOUBLE:
+ ic = 1
+ junk = ctor (Memc[value], ic, O_VALR(op))
+ }
+
+ call sfree(sp)
+end
diff --git a/pkg/utilities/nttools/keyselect/keyselect.com b/pkg/utilities/nttools/keyselect/keyselect.com
new file mode 100644
index 00000000..fc0e63b5
--- /dev/null
+++ b/pkg/utilities/nttools/keyselect/keyselect.com
@@ -0,0 +1,9 @@
+# KEYSELECT.COM -- Global variables used by keyselect
+
+#* HISTORY *
+#* B.Simon 12-Mar-92 Original
+
+common /global/ hasgroup, img
+
+bool hasgroup # true if image has group parameters
+pointer img # image descriptor
diff --git a/pkg/utilities/nttools/keyselect/keyselect.h b/pkg/utilities/nttools/keyselect/keyselect.h
new file mode 100644
index 00000000..ef001849
--- /dev/null
+++ b/pkg/utilities/nttools/keyselect/keyselect.h
@@ -0,0 +1,17 @@
+# KEYSELECT.H -- Global constants used by keyselect
+
+#* HISTORY *
+#* B.Simon 12-Mar-92 Original
+
+define SZ_STRCOL 19
+define SZ_BIGCOL 63
+
+define ERR_SYNTAX 1
+define ERR_NOFIND 2
+
+define ASSIGN_CHAR '='
+define CONCAT_CHAR ':'
+define SEP_CHAR ','
+
+define IS_SEP ($1 <= ' ' || $1 == ',')
+
diff --git a/pkg/utilities/nttools/keyselect/keyselect.x b/pkg/utilities/nttools/keyselect/keyselect.x
new file mode 100644
index 00000000..2bc8a72e
--- /dev/null
+++ b/pkg/utilities/nttools/keyselect/keyselect.x
@@ -0,0 +1,122 @@
+# KEYSELECT -- Copy selected image header keywords to sdas table
+
+#* HISTORY *
+#* B.Simon 12-Mar-1992 Original
+# Phil Hodge 8-Apr-1999 Call tbfpri.
+
+procedure keyselect ()
+
+#--
+include "keyselect.com"
+
+pointer input # list of image names
+pointer output # sdas table name
+pointer cols # list of keyword and table column names
+pointer expr # boolean expression used to select images
+pointer cdfile # column description file
+
+bool first
+int ngroup
+int phu_copied # set by tbfpri and ignored
+pointer sp, keywords, columns, cluster, image
+pointer imlist, grplist, colptr, im, tp
+
+string noread "No images read. Output table not created."
+
+bool tp_fetch(), eval_expr()
+int imtgetim()
+pointer imtopen(), immap(), tp_open(), op_table()
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark(sp)
+ call salloc (input, SZ_FNAME, TY_CHAR)
+ call salloc (output, SZ_FNAME, TY_CHAR)
+ call salloc (cols, SZ_COMMAND, TY_CHAR)
+ call salloc (expr, SZ_COMMAND, TY_CHAR)
+ call salloc (cdfile, SZ_FNAME, TY_CHAR)
+
+ call salloc (keywords, SZ_COMMAND, TY_CHAR)
+ call salloc (columns, SZ_COMMAND, TY_CHAR)
+ call salloc (cluster, SZ_FNAME, TY_CHAR)
+ call salloc (image, SZ_FNAME, TY_CHAR)
+
+ # Read task parameters
+
+ call clgstr ("input", Memc[input], SZ_FNAME)
+ call clgstr ("output", Memc[output], SZ_FNAME)
+ call clgstr ("cols", Memc[cols], SZ_FNAME)
+ call clgstr ("expr", Memc[expr], SZ_FNAME)
+ call clgstr ("cdfile", Memc[cdfile], SZ_FNAME)
+
+ # If keyword list or expression is contained in a file, read the file
+
+ if (Memc[cols] == '@')
+ call rd_list (Memc[cols+1], Memc[cols], SZ_COMMAND)
+ call fmt_list (Memc[cols])
+
+ if (Memc[expr] == '@')
+ call rd_list (Memc[expr+1], Memc[expr], SZ_COMMAND)
+ call fmt_expr (Memc[expr])
+
+ # Separate out the header keyword and table column names
+
+ call sep_list (Memc[cols], Memc[keywords], Memc[columns], SZ_COMMAND)
+
+ # Loop over all images and all groups in image
+
+ first = true
+ imlist = imtopen (Memc[input])
+
+ while (imtgetim (imlist, Memc[cluster], SZ_FNAME) != EOF) {
+
+ # Hasgroup is set to true to get us through the loop the
+ # first time. It then is set to false, but can be set to
+ # true if either eval_expr() or cpy_table() accesses a
+ # group parameter.
+
+ hasgroup = true
+ grplist = tp_open (Memc[cluster], 0, ngroup)
+
+ while (hasgroup && tp_fetch (grplist, Memc[image])) {
+ im = immap (Memc[image], READ_ONLY, 0)
+ hasgroup = false
+
+ # Open output table first time through loop
+
+ if (first) {
+ first = false
+ call tbfpri (Memc[cluster], Memc[output], phu_copied)
+ tp = op_table (im, Memc[output], Memc[keywords],
+ Memc[columns], Memc[cdfile])
+ call rd_table (Memc[columns], tp, colptr)
+ }
+
+ # Copy keywords from header to table if expression is true
+
+ if (Memc[expr] == EOS) {
+ call cpy_table (im, tp, colptr, Memc[keywords])
+ } else if (eval_expr (im, Memc[expr])) {
+ call cpy_table (im, tp, colptr, Memc[keywords])
+ }
+
+ call imunmap (im)
+ }
+ call tp_close (grplist)
+ }
+
+ # Close files and release memory
+
+ call imtclose (imlist)
+ call sfree(sp)
+
+ if (first) {
+ call eprintf (noread)
+
+ } else {
+ call mfree (colptr, TY_POINTER)
+ call tbtclo (tp)
+ }
+
+end
diff --git a/pkg/utilities/nttools/keyselect/keyword.x b/pkg/utilities/nttools/keyselect/keyword.x
new file mode 100644
index 00000000..b360e7cd
--- /dev/null
+++ b/pkg/utilities/nttools/keyselect/keyword.x
@@ -0,0 +1,253 @@
+include <imio.h>
+include <imhdr.h>
+include "keyselect.h"
+
+#* HISTORY *
+#* B.Simon 12-Mar-92 Original
+
+# GET_KEYWORD -- Get the keyword from the image header
+
+procedure get_keyword (im, name, dtype, value, maxch)
+
+pointer im # i: image descriptor
+char name[ARB] # i: keyword name
+int dtype # o: keyword data type
+char value[ARB] # o: keyword value
+int maxch # i: maximum length of value string
+#--
+include "keyselect.com"
+
+string badname "Warning: header keyword %s not found in %s\n"
+
+int imgftype(), gf_gfind()
+
+begin
+ # Any name beginning with a $ is a special keyword
+
+ if (name[1] == '$') {
+ call spec_keyword (im, name, dtype, value, maxch)
+
+ } else {
+ # Get the data type of the header keyword
+ # If the keyword is not found set the data type to
+ # zero to indicate this and return
+
+ iferr {
+ dtype = imgftype (im, name)
+ } then {
+ call eprintf (badname)
+ call pargstr (name)
+ call pargstr (IM_HDRFILE(im))
+
+ dtype = 0
+ value[1] = EOS
+ return
+ }
+
+ if (dtype == TY_SHORT || dtype == TY_LONG)
+ dtype = TY_INT
+ if (dtype == TY_CHAR)
+ dtype = - maxch
+
+ # Read header keyword from image. This procedure sets hasgroup
+ # to true if asked to retrieve a group parameter
+
+ call imgstr (im, name, value, maxch)
+ if (dtype == TY_BOOL) {
+ if (value[1] == 'T') {
+ call strcpy ("yes", value, maxch)
+ } else {
+ call strcpy ("no", value, maxch)
+ }
+ }
+
+ if (gf_gfind (im, name) > 0)
+ hasgroup = true
+ }
+
+end
+
+# NAME_KEYWORD -- Retrieve the default column name for a special keyword
+
+procedure name_keyword (name, colname, maxch)
+
+char name[ARB] # i: keyword name
+char colname[ARB] # o: default column name
+int maxch # i: maximum length of column name
+#--
+int idx, junk
+pointer sp, errmsg
+
+string special "group,dir,ext,hdr,pix,root"
+string defaults "group,directory,extension,header_file,data_file,rootname"
+string badname "Name for special keyword not recognized (%s)"
+
+int word_match(), word_find()
+
+begin
+ call smark (sp)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ if (name[1] != '$') {
+ call strcpy (name, colname, maxch)
+ return
+ }
+
+ # Get the index of special keyword name in the list
+ # The find the corresponding name in the list of defaults
+
+ idx = word_match (name[2], special)
+ if (idx == 0) {
+ call sprintf (Memc[errmsg], SZ_LINE, badname)
+ call pargstr (name)
+ call error (1, Memc[errmsg])
+ } else {
+ junk = word_find (idx, defaults, colname, maxch)
+ }
+
+ call sfree (sp)
+end
+
+# SPEC_KEYWORD -- Get the value of a special keyword
+
+procedure spec_keyword (im, name, dtype, value, maxch)
+
+pointer im # i: image descriptor
+char name[ARB] # i: keyword name
+int dtype # o: keyword data type
+char value[ARB] # o: keyword value
+int maxch # i: maximum length of value string
+#--
+include "keyselect.com"
+
+int match, ival, junk
+pointer sp, image, ldir, root, errmsg, hdr, ext
+
+string int_special "group"
+string str_special "dir,ext,hdr,pix,root"
+
+string badname "Name for special keyword not recognized (%s)"
+string badimgext "Image extension not recognized (%s)"
+
+bool streq()
+int word_match(), fnldir(), fnroot(), itoc()
+
+begin
+ call smark (sp)
+ call salloc (image, SZ_FNAME, TY_CHAR)
+ call salloc (ldir, SZ_FNAME, TY_CHAR)
+ call salloc (root, SZ_FNAME, TY_CHAR)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ # Search lists for special keyword
+
+ match = - word_match (name[2], int_special)
+ if (match == 0)
+ match = word_match (name[2], str_special)
+
+ # Data type is determined from which list it is on
+
+ if (match < 0) {
+ dtype = TY_INT
+ } else if (match > 0) {
+ dtype = - maxch
+ } else {
+ call sprintf (Memc[errmsg], SZ_LINE, badname)
+ call pargstr (name)
+ call error (1, Memc[errmsg])
+ }
+
+ # Break image name into its component parts
+
+ if (match > 0) {
+ call imgcluster (IM_HDRFILE(im), Memc[image], SZ_FNAME)
+
+ hdr = image + fnldir (Memc[image], Memc[ldir], SZ_FNAME)
+ ext = hdr + 1 + fnroot (Memc[hdr], Memc[root], SZ_FNAME)
+ }
+
+
+ # Get value of special keyword
+
+ switch (match) {
+ case -1:
+ # group number $group
+ hasgroup = true
+ ival = max (1, IM_CLINDEX(im))
+ junk = itoc (ival, value, maxch)
+ case 0:
+ # (not used)
+ ;
+ case 1:
+ # directory name $dir
+ call strcpy (Memc[ldir], value, maxch)
+ case 2:
+ # extension $ext
+ call strcpy (Memc[ext], value, maxch)
+ case 3:
+ # header file name $hdr
+ call strcpy (Memc[hdr], value, maxch)
+ case 4:
+ # pixel file name $pix
+ if (Memc[ext+2] != 'h' || Memc[ext+3] != EOS) {
+ call sprintf (Memc[errmsg], SZ_LINE, badimgext)
+ call pargstr (Memc[hdr])
+ call error (1, Memc[errmsg])
+ }
+
+ call strcpy (Memc[root], value, maxch)
+ if (streq (Memc[ext], "imh")) {
+ call strcat (".pix", value, maxch)
+ } else {
+ Memc[ext+2] = 'd'
+ call strcat (".", value, maxch)
+ call strcat (Memc[ext], value, maxch)
+ }
+ case 5:
+ # root name $root
+ call strcpy (Memc[root], value, maxch)
+ }
+
+ call sfree (sp)
+end
+
+# TYPE_KEYWORD -- Retrieve the type of a special keyword
+
+int procedure type_keyword (name)
+
+char name[ARB] # i: special keyword name
+#--
+int dtype
+pointer sp, errmsg
+
+string int_special "group"
+string str_special "dir,ext,hdr,pix,root"
+string badname "Name for special keyword not recognized (%s)"
+
+int word_match()
+
+begin
+ call smark (sp)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ if (name[1] != '$') {
+ call sprintf (Memc[errmsg], SZ_LINE, badname)
+ call pargstr (name)
+ call error (1, Memc[errmsg])
+
+ } else if (word_match (name[2], int_special) > 0) {
+ dtype = TY_INT
+
+ } else if (word_match (name[2], str_special) > 0) {
+ dtype = TY_CHAR
+
+ } else {
+ call sprintf (Memc[errmsg], SZ_LINE, badname)
+ call pargstr (name)
+ call error (1, Memc[errmsg])
+ }
+
+ call sfree (sp)
+ return (dtype)
+end
+
diff --git a/pkg/utilities/nttools/keyselect/list.x b/pkg/utilities/nttools/keyselect/list.x
new file mode 100644
index 00000000..b25e1a7e
--- /dev/null
+++ b/pkg/utilities/nttools/keyselect/list.x
@@ -0,0 +1,215 @@
+include "keyselect.h"
+
+#* HISTORY *
+#* B.Simon 12-Mar-92 Original
+
+# BRK_LIST -- Retrieve a string from the list
+
+int procedure brk_list (list, ic, sep, str, maxch)
+
+char list[ARB] # i: list of items
+int ic # u: index into list
+char sep # i: character separating strings in the list
+char str[ARB] # o: output string
+int maxch # i: maximum length of output string
+#--
+int jc
+
+begin
+ # Copy characters into output string until separation character
+ # or end of list is found
+
+ for (jc = 1; jc <= maxch; jc = jc + 1) {
+ str[jc] = list[ic]
+ ic = ic + 1
+
+ if (str[jc] == sep) {
+ break
+ } else if (str[jc] == EOS) {
+ ic = ic - 1 # back up to EOS character
+ break
+ }
+ }
+
+ str[jc] = EOS
+ return (jc-1)
+end
+
+# CNT_LIST -- Count the number of items in a list
+
+int procedure cnt_list (list)
+
+char list[ARB] # i: list of items
+#--
+int ic, count
+
+begin
+ # Number of items is number of separation characters plus one
+
+ count = 1
+ for (ic = 1; list[ic] != EOS; ic = ic + 1) {
+ if (list[ic] == SEP_CHAR)
+ count = count + 1
+ }
+
+ return (count)
+end
+
+# FMT_LIST -- Format a list into canonical form
+
+procedure fmt_list (list)
+
+char list[ARB] # u: list of keyword names
+#--
+bool tween
+int ic, jc
+
+begin
+ jc = 1
+ tween = true
+
+ # Eliminate consecutive separation characters between list items
+
+ for (ic = 1; list[ic] != EOS; ic = ic + 1) {
+ if (IS_SEP(list[ic])) {
+ if (! tween) {
+ tween = true
+ list[jc] = SEP_CHAR
+ jc = jc + 1
+ }
+
+ } else {
+ tween = false
+ if (jc < ic)
+ list[jc] = list[ic]
+ jc = jc + 1
+ }
+ }
+
+ # Eliminate trailing separation character
+
+ if (! tween || jc == 1) {
+ list[jc] = EOS
+ } else {
+ list[jc-1] = EOS
+ }
+
+end
+
+# RD_LIST -- Read values from a file into a list
+
+procedure rd_list (fname, list, maxch)
+
+char fname[ARB] # i: file containing list
+char list[ARB] # o: output list
+int maxch # i: maximum length of list
+#--
+int fd, ic, nc
+
+int open(), getline()
+
+begin
+ # Concatenate contents of the file into a single long string
+ # while preserving the newlines between them
+
+ fd = open (fname, READ_ONLY, TEXT_FILE)
+
+ for (ic = 1; ic < maxch; ic = ic + nc) {
+ nc = getline (fd, list[ic])
+ if (nc <= 0)
+ break
+ }
+
+ list[ic] = EOS
+ call close (fd)
+
+end
+
+# SEP_LIST -- Separate list into keywords and table column names
+
+procedure sep_list (list, keywords, columns, maxch)
+
+char list[ARB] # i: combined list of columns and keywords
+char keywords[ARB] # o: list of header keyword names
+char columns[ARB] # o: list of table column names
+int maxch # i: declared length of output strings
+#--
+char eq, sep, cat
+int ic, jc, kc, mc, nc
+pointer sp, word, key, col
+
+data eq / ASSIGN_CHAR /
+data sep / SEP_CHAR /
+data cat / CONCAT_CHAR /
+
+string nolist "List of header keywords is empty. No table created."
+
+int stridx(), gstrcpy(), brk_list()
+
+begin
+ call smark(sp)
+ call salloc (word, SZ_LINE, TY_CHAR)
+ call salloc (key, SZ_LINE, TY_CHAR)
+ call salloc (col, SZ_LINE, TY_CHAR)
+
+ ic = 1
+ jc = 1
+ kc = 1
+
+ # Extract the next item from the combined list of columns and keywords
+
+ while (brk_list (list, ic, sep, Memc[word], SZ_LINE) > 0) {
+
+ # Break the item into the column and keyword names
+ # If both are not given in the item assume they are the same
+
+ nc = stridx (eq, Memc[word])
+ if (nc > 0) {
+ Memc[word+nc-1] = EOS
+ call strcpy (Memc[word], Memc[col], SZ_LINE)
+ call strcpy (Memc[word+nc], Memc[key], SZ_LINE)
+
+ } else {
+ call strcpy (Memc[word], Memc[col], SZ_LINE)
+ call strcpy (Memc[word], Memc[key], SZ_LINE)
+
+ # Translate keyword names into their default column names
+ # and substitute underscores for the concatenation char
+
+ if (Memc[col] == '$') {
+ call name_keyword (Memc[col], Memc[col], SZ_LINE)
+
+ } else {
+ repeat {
+ mc = stridx (cat, Memc[col])
+ if (mc == 0)
+ break
+
+ Memc[col+mc-1] = '_'
+ }
+ }
+ }
+
+ # Append keyword and column name to output string
+
+ jc = jc + gstrcpy (Memc[key], keywords[jc], maxch-jc)
+ keywords[jc] = SEP_CHAR
+ jc = jc + 1
+
+ kc = kc + gstrcpy (Memc[col], columns[kc], maxch-kc)
+ columns[kc] = SEP_CHAR
+ kc = kc + 1
+ }
+
+ # Exit with error if either list is empty
+
+ if (jc == 1 || kc == 1)
+ call error (1, nolist)
+
+ # Eliminate trailing separation character
+
+ keywords[jc-1] = EOS
+ columns[kc-1] = EOS
+
+ call sfree(sp)
+end
diff --git a/pkg/utilities/nttools/keyselect/mkpkg b/pkg/utilities/nttools/keyselect/mkpkg
new file mode 100644
index 00000000..d22d2201
--- /dev/null
+++ b/pkg/utilities/nttools/keyselect/mkpkg
@@ -0,0 +1,15 @@
+# Update the keyselect application code in the ttools package library
+# Author: B.Simon, 12-Mar-92
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ expr.x <evexpr.h> "keyselect.h"
+ keyselect.x "keyselect.com"
+ keyword.x <imio.h> <imhdr.h> "keyselect.h" "keyselect.com"
+ list.x "keyselect.h"
+ tab.x <imhdr.h> <tbset.h> "keyselect.h"
+ ;
diff --git a/pkg/utilities/nttools/keyselect/tab.x b/pkg/utilities/nttools/keyselect/tab.x
new file mode 100644
index 00000000..1e4dd769
--- /dev/null
+++ b/pkg/utilities/nttools/keyselect/tab.x
@@ -0,0 +1,353 @@
+include <imhdr.h>
+include <tbset.h>
+include "keyselect.h"
+
+#* HISTORY *
+#* B.Simon 12-Mar-92 Original
+
+# CPY_TABLE -- Copy keywords from header to table row
+
+procedure cpy_table (im, tp, colptr, keywords)
+
+pointer im # i: image descriptor
+pointer tp # i: table descriptor
+pointer colptr # i: pointer to array of column descriptors
+char keywords # i: list of header keywords
+#--
+char cat, sep
+int row, dtype, ic, jc, kc
+pointer sp, cp, nlist, vlist, name, value
+
+data cat / CONCAT_CHAR /
+data sep / SEP_CHAR /
+
+string nocolumn "cpy_table: not enough columns to store keywords"
+
+int tbpsta(), brk_list(), stridx(), gstrcpy()
+
+begin
+ call smark(sp)
+ call salloc (nlist, SZ_LINE, TY_CHAR)
+ call salloc (vlist, SZ_LINE, TY_CHAR)
+ call salloc (name, SZ_LINE, TY_CHAR)
+ call salloc (value, SZ_LINE, TY_CHAR)
+
+ ic = 1
+ cp = colptr
+ row = tbpsta (tp, TBL_NROWS) + 1
+
+ # Extract each keyword from the list of keywords
+
+ while (brk_list (keywords, ic, sep, Memc[nlist], SZ_LINE) > 0) {
+
+ # If the keyword is not a list of concatenated keywords
+ # copy its value into a string
+
+ if (stridx (cat, Memc[nlist]) == 0) {
+ call get_keyword (im, Memc[nlist], dtype,
+ Memc[vlist], SZ_LINE)
+
+ # Otherwise break the list of concatenated keywords
+ # and concatenate their values into a string
+
+ } else {
+ jc = 1
+ kc = 0
+ while (brk_list (Memc[nlist], jc, cat,
+ Memc[name], SZ_LINE) > 0){
+
+ call get_keyword (im, Memc[name], dtype,
+ Memc[value], SZ_LINE)
+
+ if (dtype != 0) {
+ kc = kc + gstrcpy (Memc[value], Memc[vlist+kc],
+ SZ_LINE-kc)
+ Memc[vlist+kc] = SEP_CHAR
+ kc = kc + 1
+ }
+ }
+ kc = max (kc, 1)
+ Memc[vlist+kc-1] = EOS
+ }
+
+ # Write the value into the table
+
+ if (Memi[cp] == NULL)
+ call error (1, nocolumn)
+
+ call tbeptt (tp, Memi[cp], row, Memc[vlist])
+ cp = cp + 1
+ }
+
+ call sfree(sp)
+end
+
+# FMT_TABLE -- Retrieve column format from column description file
+
+procedure fmt_table (cd, col, units, fmt, dtype)
+
+int cd # i: file descriptor of column description file
+char col[ARB] # i: name of column to retrieve information for
+char units[ARB] # o: column units
+char fmt[ARB] # o: column format
+int dtype # o: column data type
+#--
+char star, comment
+bool match
+int idx, junk, length, typevals[5]
+pointer sp, line, input, name, type, ftnfmt, errmsg
+
+string typestr "rdibc"
+string badtype "Illegal datatype for column %s (%s)"
+string badname "Warning: column not found in column description file (%s)\n"
+
+data star / '*' /
+data comment / '#' /
+data typevals /TY_REAL, TY_DOUBLE, TY_INT, TY_BOOL, TY_CHAR /
+
+bool streq()
+int getline(), stridx(), ctoi
+
+begin
+ call smark (sp)
+ call salloc (line, SZ_LINE, TY_CHAR)
+ call salloc (input, SZ_COLNAME, TY_CHAR)
+ call salloc (name, SZ_COLNAME, TY_CHAR)
+ call salloc (type, SZ_COLFMT, TY_CHAR)
+ call salloc (ftnfmt, SZ_COLFMT, TY_CHAR)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ call strcpy (col, Memc[input], SZ_COLNAME)
+ call strlwr (Memc[input])
+
+ match = false
+ call seek (cd, BOF)
+ while (! match && getline (cd, Memc[line]) != EOF) {
+
+ # Remove trailing comments from line
+
+ idx = stridx (comment, Memc[line])
+ if (idx > 0)
+ Memc[line+idx-1] = EOS
+
+ # Column name is the first word on the line
+
+ call sscan (Memc[line])
+ call gargwrd (Memc[name], SZ_COLNAME)
+ call strlwr (Memc[name])
+
+ # If the name matches the procedure argument
+ # read the remaining fields on the line
+
+ match = streq (Memc[input], Memc[name])
+ if (match) {
+ call gargwrd (Memc[type], SZ_COLFMT)
+ call gargwrd (Memc[ftnfmt], SZ_COLFMT)
+ call gargwrd (units, SZ_COLUNITS)
+
+ call strlwr (Memc[type])
+ call tbbftp (Memc[ftnfmt], fmt)
+
+ # Convert the type string to the corresponding integer value
+
+ if (Memc[type] == EOS) {
+ dtype = 0
+
+ } else {
+ idx = stridx (Memc[type], typestr)
+ if (idx == 0) {
+ call sprintf (Memc[errmsg], SZ_LINE, badtype)
+ call pargstr (Memc[name])
+ call pargstr (Memc[type])
+ call error (1, Memc[errmsg])
+ }
+
+ dtype = typevals[idx]
+ if (dtype == TY_CHAR) {
+ idx = stridx (star, Memc[type])
+ if (idx > 0) {
+ idx = idx + 1
+ junk = ctoi (Memc[type], idx, length)
+ if (length > 0)
+ dtype = - length
+ }
+ }
+ }
+
+ }
+ }
+
+ # Send warning message and set defaults if no match
+
+ if (! match) {
+ dtype = 0
+ fmt[1] = EOS
+ units[1] = EOS
+
+ call eprintf (badname)
+ call pargstr (col)
+ }
+
+ call sfree (sp)
+end
+
+# OP_TABLE -- Open the output table
+
+pointer procedure op_table(im, output, keywords, columns, cdfile)
+
+pointer im # i: image descriptor
+char output[ARB] # i: table name
+char keywords[ARB] # i: list of header keywords
+char columns[ARB] # i: list of column names
+char cdfile[ARB] # i: optional column description file
+#--
+bool append
+char sep, cat
+int ic, jc, dtype
+pointer sp, tp, cp, cd, col, key, units, fmt, errmsg
+
+data sep / SEP_CHAR /
+data cat / CONCAT_CHAR /
+
+string nocolumn "Column not found in existing output table (%s)"
+string nokeyword "op_table: no matching keyword for column"
+string notfound "Warning: keyword not found when creating table (%s)\n"
+
+bool isblank()
+int open(), stridx(), imgftype(), brk_list(), type_keyword()
+pointer tbtopn()
+
+begin
+ call smark (sp)
+ call salloc (col, SZ_COLNAME, TY_CHAR)
+ call salloc (key, SZ_LINE, TY_CHAR)
+ call salloc (units, SZ_COLUNITS, TY_CHAR)
+ call salloc (fmt, SZ_COLFMT, TY_CHAR)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ # Open column description file
+
+ if (isblank (cdfile)) {
+ cd = NULL
+ } else {
+ cd = open (cdfile, READ_ONLY, TEXT_FILE)
+ }
+
+ # Append rows to the table if the table already exists
+ # otherwise create a new table
+
+ append = true
+ iferr (tp = tbtopn (output, READ_WRITE, NULL)) {
+ append = false
+ tp = tbtopn (output, NEW_FILE, NULL)
+ }
+
+ ic = 1
+ jc = 1
+ while (brk_list (columns, ic, sep, Memc[col], SZ_COLNAME) > 0) {
+
+ if (brk_list (keywords, jc, sep, Memc[key], SZ_LINE) == 0)
+ call error (1, nokeyword)
+
+ # Verify that the columns exist if we are in append mode
+ # Define the new columns if we are not
+
+ if (append) {
+ call tbcfnd (tp, Memc[col], cp, 1)
+ if (cp == NULL) {
+ call sprintf (Memc[errmsg], SZ_LINE, nocolumn)
+ call pargstr (Memc[col])
+ call error (1, Memc[errmsg])
+ }
+
+ } else {
+ # Get column characteristics from the column description file
+ # or use defaults and image header keyword type
+
+ if (cd != NULL)
+ call fmt_table (cd, Memc[col],
+ Memc[units], Memc[fmt], dtype)
+
+ if (cd == NULL || dtype == 0) {
+ Memc[units] = EOS
+ Memc[fmt] = EOS
+
+ if (stridx (cat, Memc[key]) != 0) {
+ dtype = - SZ_BIGCOL
+
+ } else if (Memc[key] == '$'){
+ dtype = type_keyword (Memc[key])
+
+ } else {
+ iferr {
+ dtype = imgftype (im, Memc[key])
+ } then {
+ dtype = 0
+ call eprintf (notfound)
+ call pargstr (Memc[key])
+ }
+ }
+ }
+
+ if (dtype == 0 || dtype == TY_CHAR)
+ dtype = - SZ_STRCOL
+ if (dtype == TY_SHORT || dtype == TY_LONG)
+ dtype = TY_INT
+ if (dtype == TY_REAL)
+ dtype = TY_DOUBLE
+
+ call tbcdef (tp, cp, Memc[col], Memc[units], Memc[fmt],
+ dtype, 1, 1)
+ }
+ }
+
+ # Create the new table if not in append mode
+
+ if (! append)
+ call tbtcre (tp)
+
+ call sfree (sp)
+ return (tp)
+end
+
+# RD_TABLE -- Create an array of column pointers from the list of column names
+
+procedure rd_table (columns, tp, colptr)
+
+char columns[ARB] # i: list of column names
+pointer tp # i: table descriptor
+pointer colptr # o: pointer to array of column names
+#--
+char sep
+int nptr, ic
+pointer sp, cp, col, errmsg
+
+data sep / SEP_CHAR /
+string nocolumn "rd_table: column not found (%s)"
+
+int cnt_list(), brk_list()
+
+begin
+ call smark (sp)
+ call salloc (col, SZ_LINE, TY_CHAR)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ nptr = cnt_list (columns) + 1
+ call malloc (colptr, nptr, TY_POINTER)
+
+ ic = 1
+ cp = colptr
+ while (brk_list (columns, ic, sep, Memc[col], SZ_LINE) > 0) {
+ call tbcfnd (tp, Memc[col], Memi[cp], 1)
+ if (cp == NULL) {
+ call sprintf (Memc[errmsg], SZ_LINE, nocolumn)
+ call pargstr (Memc[col])
+
+ call error (1, Memc[errmsg])
+ }
+ cp = cp + 1
+ }
+
+ Memi[cp] = NULL
+ call sfree(sp)
+end
diff --git a/pkg/utilities/nttools/keytab.par b/pkg/utilities/nttools/keytab.par
new file mode 100644
index 00000000..3aaa5a67
--- /dev/null
+++ b/pkg/utilities/nttools/keytab.par
@@ -0,0 +1,7 @@
+input,f,a,"",,,"Name of file containing header keyword"
+keyword,s,a,"",,,"Name of header keyword"
+table,f,a,"",,,"Name of table"
+column,s,a,"",,,"Name of column"
+row,i,a,,1,,"Number of row"
+silent,b,h,no,,,"Do not print any warning messages?"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/lib/allcols.x b/pkg/utilities/nttools/lib/allcols.x
new file mode 100644
index 00000000..64e49786
--- /dev/null
+++ b/pkg/utilities/nttools/lib/allcols.x
@@ -0,0 +1,29 @@
+include <tbset.h>
+
+# ALLCOLS -- Return a pointer to an array containing the indices of all
+# the columns in a table. The calling procedure must free the array when it
+# is through with it.
+#
+# B.Simon 11-Dec-87 First Code
+
+procedure allcolumns (tp, numcol, colptr)
+
+pointer tp # i: Table descriptor
+int numcol # o: Number of columns in the table
+pointer colptr # o: Pointer to array of indices
+
+int icol
+
+int tbpsta(), tbcnum()
+
+errchk tbpsta, malloc
+
+begin
+
+ numcol = tbpsta (tp, TBL_NCOLS)
+ call malloc (colptr, numcol, TY_INT)
+
+ do icol = 1, numcol
+ Memi[colptr+icol-1] = tbcnum (tp, icol)
+
+end
diff --git a/pkg/utilities/nttools/lib/allrows.x b/pkg/utilities/nttools/lib/allrows.x
new file mode 100644
index 00000000..086e6a4a
--- /dev/null
+++ b/pkg/utilities/nttools/lib/allrows.x
@@ -0,0 +1,29 @@
+include <tbset.h>
+
+# ALLROWS -- Return a pointer to an array containing the indices of all
+# the rows in a table. The calling procedure must free the array when it
+# is through with it.
+#
+# B.Simon 11-Dec-87 First Code
+
+procedure allrows (tp, numrow, rowptr)
+
+pointer tp # i: Table descriptor
+int numrow # o: Number of rows in the table
+pointer rowptr # o: Pointer to array of indices
+
+int irow
+
+int tbpsta()
+
+errchk tbpsta, malloc
+
+begin
+
+ numrow = tbpsta (tp, TBL_NROWS)
+ call malloc (rowptr, numrow, TY_INT)
+
+ do irow = 1, numrow
+ Memi[rowptr+irow-1] = irow
+
+end
diff --git a/pkg/utilities/nttools/lib/compare.com b/pkg/utilities/nttools/lib/compare.com
new file mode 100644
index 00000000..546e7222
--- /dev/null
+++ b/pkg/utilities/nttools/lib/compare.com
@@ -0,0 +1,7 @@
+# Variables needed by comparison routines used by the sort routines
+
+int lendata # length of a data element in units of its type
+pointer dataptr # pointer to the beginning of array holding
+ # data to be sorted
+
+common /compare/ lendata, dataptr
diff --git a/pkg/utilities/nttools/lib/compare.x b/pkg/utilities/nttools/lib/compare.x
new file mode 100644
index 00000000..b05a50c1
--- /dev/null
+++ b/pkg/utilities/nttools/lib/compare.x
@@ -0,0 +1,258 @@
+.help compare
+.nf___________________________________________________________________________
+
+Comparison routines used to sort table columns. There are two sets of routines,
+compasc[bdirt] for sorting in ascending order and compdsc[bdirt] for sorting in
+descending order. The last letter indicates the type of data compared in the
+sort. All routines return an integer that indicates the results of comparison.
+The value of the integer is set according to the following scheme:
+
+ Ascending Descending
+
+ if mem[i] < mem[j], order = -1 if mem[i] > mem[j], order = -1
+ if mem[i] == mem[j], order = 0 if mem[i] == mem[j], order = 0
+ if mem[i] > mem[j], order = 1 if mem[i] < mem[j], order = 1
+
+.endhelp_______________________________________________________________________
+
+# B.Simon 16-Sept-87 First Code
+
+# COMPASCB -- Boolean comparison routine used for sort in ascending order
+
+int procedure compascb (i, j)
+
+int i # i: Index to first array element in comparison
+int j # i: Index to second element in comparison
+#--
+include "compare.com"
+
+int order
+
+begin
+ # false < true
+
+ if (! Memb[dataptr+i-1] && Memb[dataptr+j-1])
+ order = -1
+ else if (Memb[dataptr+i-1] && ! Memb[dataptr+j-1])
+ order = 1
+ else
+ order = 0
+
+ return (order)
+end
+
+# COMPASCD -- Double comparison routine used for sort in ascending order
+
+int procedure compascd (i, j)
+
+int i # i: Index to first array element in comparison
+int j # i: Index to second element in comparison
+#--
+include "compare.com"
+
+int order
+
+begin
+
+ if (Memd[dataptr+i-1] < Memd[dataptr+j-1])
+ order = -1
+ else if (Memd[dataptr+i-1] > Memd[dataptr+j-1])
+ order = 1
+ else
+ order = 0
+
+ return (order)
+end
+
+# COMPASCI -- Integer comparison routine used for sort in ascending order
+
+int procedure compasci (i, j)
+
+int i # i: Index to first array element in comparison
+int j # i: Index to second element in comparison
+#--
+include "compare.com"
+
+int order
+
+begin
+
+ if (Memi[dataptr+i-1] < Memi[dataptr+j-1])
+ order = -1
+ else if (Memi[dataptr+i-1] > Memi[dataptr+j-1])
+ order = 1
+ else
+ order = 0
+
+ return (order)
+end
+
+# COMPASCR -- Real comparison routine used for sort in ascending order
+
+int procedure compascr (i, j)
+
+int i # i: Index to first array element in comparison
+int j # i: Index to second element in comparison
+#--
+include "compare.com"
+
+int order
+
+begin
+
+ if (Memr[dataptr+i-1] < Memr[dataptr+j-1])
+ order = -1
+ else if (Memr[dataptr+i-1] > Memr[dataptr+j-1])
+ order = 1
+ else
+ order = 0
+
+ return (order)
+end
+
+# COMPASCT -- Text comparison routine used for sort in ascending order
+
+int procedure compasct (i, j)
+
+int i # i: Index to first array element in comparison
+int j # i: Index to second element in comparison
+#--
+include "compare.com"
+
+int order
+
+bool strlt(), strgt()
+
+begin
+
+ if (strlt (Memc[dataptr+(i-1)*(lendata+1)],
+ Memc[dataptr+(j-1)*(lendata+1)]) )
+ order = -1
+ else if (strgt (Memc[dataptr+(i-1)*(lendata+1)],
+ Memc[dataptr+(j-1)*(lendata+1)]) )
+ order = 1
+ else
+ order = 0
+
+ return (order)
+end
+
+# COMPDSCB -- Boolean comparison routine used for sort in descending order
+
+int procedure compdscb (i, j)
+
+int i # i: Index to first array element in comparison
+int j # i: Index to second element in comparison
+#--
+include "compare.com"
+
+int order
+
+begin
+ # true > false
+
+ if (Memb[dataptr+i-1] && ! Memb[dataptr+j-1])
+ order = -1
+ else if (! Memb[dataptr+i-1] && Memb[dataptr+j-1])
+ order = 1
+ else
+ order = 0
+
+ return (order)
+end
+
+# COMPDSCD -- Double comparison routine used for sort in descending order
+
+int procedure compdscd (i, j)
+
+int i # i: Index to first array element in comparison
+int j # i: Index to second element in comparison
+#--
+include "compare.com"
+
+int order
+
+begin
+
+ if (Memd[dataptr+i-1] > Memd[dataptr+j-1])
+ order = -1
+ else if (Memd[dataptr+i-1] < Memd[dataptr+j-1])
+ order = 1
+ else
+ order = 0
+
+ return (order)
+end
+
+# COMPDSCI -- Integer comparison routine used for sort in descending order
+
+int procedure compdsci (i, j)
+
+int i # i: Index to first array element in comparison
+int j # i: Index to second element in comparison
+#--
+include "compare.com"
+
+int order
+
+begin
+
+ if (Memi[dataptr+i-1] > Memi[dataptr+j-1])
+ order = -1
+ else if (Memi[dataptr+i-1] < Memi[dataptr+j-1])
+ order = 1
+ else
+ order = 0
+
+ return (order)
+end
+
+# COMPDSCR -- Real comparison routine used for sort in descending order
+
+int procedure compdscr (i, j)
+
+int i # i: Index to first array element in comparison
+int j # i: Index to second element in comparison
+#--
+include "compare.com"
+
+int order
+
+begin
+
+ if (Memr[dataptr+i-1] > Memr[dataptr+j-1])
+ order = -1
+ else if (Memr[dataptr+i-1] < Memr[dataptr+j-1])
+ order = 1
+ else
+ order = 0
+
+ return (order)
+end
+
+# COMPDSCT -- Text comparison routine used for sort in descending order
+
+int procedure compdsct (i, j)
+
+int i # i: Index to first array element in comparison
+int j # i: Index to second element in comparison
+#--
+include "compare.com"
+
+int order
+
+bool strgt(), strlt()
+
+begin
+
+ if (strgt (Memc[dataptr+(i-1)*(lendata+1)],
+ Memc[dataptr+(j-1)*(lendata+1)]) )
+ order = -1
+ else if (strlt (Memc[dataptr+(i-1)*(lendata+1)],
+ Memc[dataptr+(j-1)*(lendata+1)]) )
+ order = 1
+ else
+ order = 0
+
+ return (order)
+end
diff --git a/pkg/utilities/nttools/lib/ftnexpr.x b/pkg/utilities/nttools/lib/ftnexpr.x
new file mode 100644
index 00000000..a8472bdb
--- /dev/null
+++ b/pkg/utilities/nttools/lib/ftnexpr.x
@@ -0,0 +1,127 @@
+include <ctype.h>
+define DOT '.'
+define SQUOTE '\''
+define DQUOTE '"'
+define BSLASH '\\'
+
+#* HISTORY *
+#* B.Simon 04-Jan-93 Original
+#* B.Simon 01-Dec-93 No longer removes backslashes
+
+
+# FTNEXPR -- Convert a Fortran boolean expression to SPP
+
+procedure ftnexpr (oldexpr, newexpr, maxch)
+
+char oldexpr[ARB] # i: Fortran expression
+char newexpr[ARB] # o: SPP expression
+int maxch # i: Maximum length of SPP expression
+#--
+char ch, term
+int ic, jc, kc, iw
+pointer sp, dotbuf
+
+string ftnlist ".eq. .and. .or. .gt. .ge. .lt. .le. .not. .ne."
+string spplist " == && || > >= < <= ! !="
+
+int gstrcpy(), word_match(), word_find()
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (dotbuf, SZ_LINE, TY_CHAR)
+
+ # Loop over each character in the old expression
+ # Characters between quote marks or dots are treated specially
+ # To indicate this, term is set to the leading character
+
+ ic = 1
+ jc = 1
+ kc = 0
+ term = EOS
+
+ while (oldexpr[ic] != EOS) {
+ ch = oldexpr[ic]
+
+ if (ch != term) {
+ if (term == EOS) {
+ if (ch == DOT) {
+ kc = 1
+ term = ch
+ Memc[dotbuf] = ch
+ } else {
+ if (ch == SQUOTE || ch == DQUOTE)
+ term = ch
+
+ newexpr[jc] = ch
+ jc = jc + 1
+ }
+
+ } else if (term == DOT) {
+ if (IS_ALPHA(ch)) {
+ if (kc < SZ_LINE) {
+ Memc[dotbuf+kc] = ch
+ kc = kc + 1
+ }
+ } else {
+ Memc[dotbuf+kc] = ch
+ Memc[dotbuf+kc+1] = EOS
+ jc = jc + gstrcpy (Memc[dotbuf], newexpr[jc],
+ maxch-jc+1)
+
+ kc = 0
+ term = EOS
+ }
+
+ } else {
+ newexpr[jc] = ch
+ jc = jc + 1
+
+ if (ch == BSLASH) {
+ ic = ic + 1
+ newexpr[jc] = oldexpr[ic]
+ jc = jc + 1
+ }
+ }
+
+ } else {
+ term = EOS
+
+ if (ch != DOT) {
+ newexpr[jc] = ch
+ jc = jc + 1
+
+ } else {
+ Memc[dotbuf+kc] = ch
+ Memc[dotbuf+kc+1] = EOS
+ call strlwr (Memc[dotbuf])
+
+ iw = word_match (Memc[dotbuf], ftnlist)
+ if (iw == 0) {
+ jc = jc + gstrcpy (Memc[dotbuf], newexpr[jc],
+ maxch-jc+1)
+ } else {
+ jc = jc + word_find (iw, spplist, newexpr[jc],
+ maxch-jc+1)
+ }
+
+ kc = 0
+ }
+ }
+
+ ic = ic + 1
+ }
+
+ # If there is anything left in the dot buffer copy it unchanged
+ # to the output string
+
+ newexpr[jc] = EOS
+
+ if (kc > 0) {
+ Memc[dotbuf+kc] = EOS
+ call strcat (Memc[dotbuf], newexpr, maxch)
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/lib/gettabcol.x b/pkg/utilities/nttools/lib/gettabcol.x
new file mode 100644
index 00000000..154aff4f
--- /dev/null
+++ b/pkg/utilities/nttools/lib/gettabcol.x
@@ -0,0 +1,67 @@
+include <tbset.h>
+
+# GETTABCOL -- Read in a table column of any data type
+#
+# This procedure produces an array of table column values and an array of
+# null flags given an input table descriptor, column descriptor, and data
+# type. If the data type is set to zero, the column data type is queried
+# and returned to the calling program. The arrays are put in dynamic memory
+# and pointers to these arrays are returned to the calling program, which must
+# free the arrays when it is done with them.
+#
+# B.Simon 15-Dec-87 First Code
+
+procedure gettabcol (tp, cp, dtype, nary, aryptr, nulptr)
+
+pointer tp # i: Table descriptor
+pointer cp # i: Column descriptor
+int dtype # io: Data type of column (strings are -length)
+int nary # o: Length of output arrays
+pointer aryptr # o: Pointer to array of values
+pointer nulptr # o: Pointer to array of null flags
+#--
+int lendata, spptype
+int tbpsta(), tbcigi()
+
+errchk malloc, tbpsta
+
+begin
+ # Allocate storage for null flags
+
+ nary = tbpsta (tp, TBL_NROWS)
+ call malloc (nulptr, nary, TY_BOOL)
+ if (dtype == 0)
+ dtype = tbcigi (cp, TBL_COL_DATATYPE)
+
+ # Break down data type into spp type and length
+
+ if (dtype < 0) {
+ lendata = - dtype
+ spptype = TY_CHAR
+ } else {
+ lendata = 1
+ spptype = dtype
+ }
+
+ # Read in the column of table values
+
+ switch (spptype) {
+ case TY_BOOL:
+ call malloc (aryptr, nary, TY_BOOL)
+ call tbcgtb (tp, cp, Memb[aryptr], Memb[nulptr], 1, nary)
+ case TY_CHAR:
+ call malloc (aryptr, nary*(lendata+1), TY_CHAR)
+ call tbcgtt (tp, cp, Memc[aryptr], Memb[nulptr], lendata,
+ 1, nary)
+ case TY_SHORT,TY_INT,TY_LONG:
+ call malloc (aryptr, nary, TY_INT)
+ call tbcgti (tp, cp, Memi[aryptr], Memb[nulptr], 1, nary)
+ case TY_REAL:
+ call malloc (aryptr, nary, TY_REAL)
+ call tbcgtr (tp, cp, Memr[aryptr], Memb[nulptr], 1, nary)
+ case TY_DOUBLE:
+ call malloc (aryptr, nary, TY_DOUBLE)
+ call tbcgtd (tp, cp, Memd[aryptr], Memb[nulptr], 1, nary)
+ }
+
+end
diff --git a/pkg/utilities/nttools/lib/inquotes.x b/pkg/utilities/nttools/lib/inquotes.x
new file mode 100644
index 00000000..2cc0d8ce
--- /dev/null
+++ b/pkg/utilities/nttools/lib/inquotes.x
@@ -0,0 +1,121 @@
+include <chars.h>
+
+# inquotes -- Put quotes around string
+# This procedure examines the input/output string for blanks, tabs and
+# double quotes. If any of these is found, the string will be enclosed in
+# double quotes (unless it already begins with "), and embedded quotes will
+# be escaped with the '\' character. If the input string is null then it
+# will be replaced with a pair of adjacent double quotes. If maxch is not
+# large enough to include the extra characters, however, the string will not
+# be modified. The input and output strings may be the same.
+#
+# If there are trailing blanks but no embedded blanks, tabs or quotes,
+# then the input will be copied unmodified to the output. (6/17/92)
+#
+# The reason for enclosing a string in quotes is so that it may be read
+# later using ctowrd, and the entire string will be taken as one "word".
+#
+# Phil Hodge, 21-Jul-1987 Subroutine created.
+# Phil Hodge, 11-Aug-1987 Add outstr to calling sequence.
+# Phil Hodge, 17-Jun-1992 Also check for tabs; ignore trailing whitespace.
+# Phil Hodge, 13-Jan-1995 Include show_trailing argument in calling sequence.
+
+procedure inquotes (instr, outstr, maxch, show_trailing)
+
+char instr[ARB] # i: the string to be enclosed in quotes
+char outstr[ARB] # o: copy of instr, possibly enclosed in quotes
+int maxch # i: maximum length of string outstr
+int show_trailing # i: YES means show trailing blanks
+#--
+bool must_fix # true if str contains blanks and/or quotes
+int non_blank_len # length of instr up to last non-blank char
+int inlen # same as non_blank_len
+int outlen # length of outstr on output
+int numquotes # a count of the number of embedded quotes
+int ip, op # counters for input & output locations
+int strlen()
+
+begin
+ # Find the length of the string ...
+ if (show_trailing == YES) {
+ # ... including trailing blanks.
+ non_blank_len = strlen (instr)
+ } else {
+ # ... up to the last non-blank character.
+ non_blank_len = 0 # initial value
+ do ip = 1, maxch {
+ if (instr[ip] == EOS)
+ break
+ if (instr[ip] != BLANK) # else ignore blank
+ non_blank_len = ip
+ }
+ }
+
+ # Replace a null or completely blank string with "".
+ if (instr[1] == EOS || non_blank_len < 1) {
+ if (maxch >= 2)
+ call strcpy ("\"\"", outstr, maxch)
+ else # can't fix it
+ call strcpy (instr, outstr, maxch)
+ return
+ }
+
+ inlen = non_blank_len
+ numquotes = 0 # initial values
+ must_fix = false
+
+ # Run through the input string, but only go as far as the last
+ # non-blank character so we don't include trailing blanks.
+ do ip = 1, non_blank_len {
+ if (instr[ip] == EOS) {
+ break
+ } else if (instr[ip] == BLANK) {
+ must_fix = true
+ } else if (instr[ip] == TAB) {
+ must_fix = true
+ } else if (instr[ip] == DQUOTE) {
+ if (ip == 1) {
+ call strcpy (instr, outstr, maxch)
+ return # begins with ", so don't "fix" it
+ }
+ if (instr[ip-1] != ESCAPE) {
+ must_fix = true
+ numquotes = numquotes + 1
+ }
+ }
+ }
+
+ outlen = inlen + numquotes + 2
+ if (outlen > maxch || !must_fix) {
+ call strcpy (instr, outstr, maxch)
+ return # can't fix it or don't need to
+ }
+
+ # Work from the end toward the beginning in case instr = outstr.
+ outstr[outlen+1] = EOS
+ outstr[outlen] = DQUOTE
+ op = outlen - 1
+
+ if (numquotes > 0) {
+ # There are quotes within the string.
+ do ip = inlen, 1, -1 {
+ outstr[op] = instr[ip]
+ if (instr[ip] == DQUOTE) {
+ if (instr[ip-1] != ESCAPE) {
+ op = op - 1
+ outstr[op] = ESCAPE
+ }
+ }
+ op = op - 1
+ }
+ } else {
+ # No embedded quotes.
+ do ip = inlen, 1, -1 {
+ outstr[op] = instr[ip]
+ op = op - 1
+ }
+ }
+ outstr[1] = DQUOTE
+ if (op != 1)
+ call error (1, "miscount in inquotes")
+end
diff --git a/pkg/utilities/nttools/lib/invert.x b/pkg/utilities/nttools/lib/invert.x
new file mode 100644
index 00000000..f8a36675
--- /dev/null
+++ b/pkg/utilities/nttools/lib/invert.x
@@ -0,0 +1,55 @@
+
+include <tbset.h>
+
+# INVERT -- Create the complement (inverse) of an array of column pointers
+#
+# B.Simon 20-Oct-87 First Code
+
+procedure invert (tp, numptr, colptr)
+
+pointer tp # i: Table descriptor
+int numptr # io: Number of column pointers
+pointer colptr[ARB] # io: Array of column pointers
+
+bool match
+int numcol, icol, iptr, jptr
+pointer newptr, cp
+
+int tbpsta(), tbcnum()
+
+begin
+ # Create a temporary array to hold the pointers
+
+ numcol = tbpsta (tp, TBL_NCOLS)
+ call malloc (newptr, numcol, TY_INT)
+
+ jptr = 0
+ do icol = 1, numcol {
+
+ # Get each pointer in the table and
+ # see if it is in the original array
+
+ cp = tbcnum (tp, icol)
+ match = false
+ do iptr = 1, numptr {
+ if (cp == colptr[iptr]) {
+ match = true
+ break
+ }
+ }
+
+ # If not, add it to the temporary array
+
+ if (! match) {
+ Memi[newptr+jptr] = cp
+ jptr = jptr + 1
+ }
+ }
+
+# Copy the temporary array to the output array
+
+ numptr = jptr
+ call amovi (Memi[newptr], colptr, numptr)
+ call mfree (newptr, TY_INT)
+
+end
diff --git a/pkg/utilities/nttools/lib/mjd.x b/pkg/utilities/nttools/lib/mjd.x
new file mode 100644
index 00000000..601cf546
--- /dev/null
+++ b/pkg/utilities/nttools/lib/mjd.x
@@ -0,0 +1,94 @@
+include <ctype.h>
+include "reloperr.h"
+
+define TFIELDS 7
+define REQFIELD 3
+
+# MJD -- Compute the modified julian date of a time expressed as a string
+#
+# Dates are of the form YYYYMMDD:HHMMSSCC (fields after the colon are optional).
+# If an optional field is not present, its value is considered to be zero.
+# Dates must be between 1 Jan 1858 and 31 Dec 2099
+#
+# B.Simon 7-Oct-87 First Code
+# Phil Hodge 20-Feb-91 Move the data statements.
+
+double procedure mjd (date)
+
+char date[ARB] # i: String in the form YYYYMMDD:HHMMSSCC
+#--
+int jd, datelen, it, ic
+int time[TFIELDS], tpos[2,TFIELDS], tlim[2,TFIELDS]
+pointer sp, errtxt
+double df
+
+int strlen()
+
+string badfmt "Date has incorrect format (%s)"
+
+data tpos / 1, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17 /
+data tlim / 1858, 2099, 1, 12, 1, 31, 0, 23, 0, 59, 0, 59, 0, 99 /
+
+begin
+ # Allocate dynamic memory for error string
+
+ call smark (sp)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ datelen = strlen (date)
+ call aclri (time, TFIELDS)
+
+ # Convert the date string into integer fields
+
+ do it = 1, TFIELDS {
+
+ # Check for absence of optional fields
+
+ if (tpos[1,it] > datelen) {
+ if (it > REQFIELD)
+ break
+ else {
+ call sprintf (Memc[errtxt], SZ_LINE, badfmt)
+ call pargstr (date)
+ call error (SYNTAX, Memc[errtxt])
+ }
+ }
+
+ # Convert a field in the date string to an integer
+
+ do ic = tpos[1,it], tpos[2,it] {
+ if (IS_DIGIT(date[ic]))
+ time[it] = 10 * time[it] + TO_INTEG(date[ic])
+ else {
+ call sprintf (Memc[errtxt], SZ_LINE, badfmt)
+ call pargstr (date)
+ call error (SYNTAX, Memc[errtxt])
+ }
+ }
+
+ # Do bounds checking on the field
+ # Some errors can slip thru, e.g., Feb 30
+
+ if ((time[it] < tlim[1,it]) || (time[it] > tlim[2,it])) {
+ call sprintf (Memc[errtxt], SZ_LINE, badfmt)
+ call pargstr (date)
+ call error (SYNTAX, Memc[errtxt])
+ }
+ }
+
+ # Compute integer part of modified julian date
+ # From Van Flandern & Pulkkinen ApJ Sup 41:391-411 Nov 79
+
+ jd = 367 * time[1] - 7 * (time[1] + (time[2] + 9) / 12) / 4 -
+ 3 * ((time[1] + (time[2] - 9) / 7) / 100 + 1) / 4 +
+ 275 * time[2] / 9 + time[3] - 678971
+
+ # Compute fractional part of modified julian date
+ # N.B. julian date begins at noon, modified julian date at midnight
+
+ df = double (time[7] + 100 * (time[6] + 60 *
+ (time[5] + 60 * time[4]))) / 8640000.0
+
+ call sfree (sp)
+ return (jd + df)
+end
diff --git a/pkg/utilities/nttools/lib/mkpkg b/pkg/utilities/nttools/lib/mkpkg
new file mode 100644
index 00000000..3644f8e3
--- /dev/null
+++ b/pkg/utilities/nttools/lib/mkpkg
@@ -0,0 +1,33 @@
+# Update the library application code in the ttools package library
+# Author: B.Simon, 21-Dec-87
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ allcols.x <tbset.h>
+ allrows.x <tbset.h>
+ ftnexpr.x <ctype.h>
+ gettabcol.x <tbset.h>
+ inquotes.x <chars.h>
+ invert.x <tbset.h>
+ mjd.x <ctype.h> reloperr.h
+ newcolnam.x <ctype.h> <tbset.h> reloperr.h
+ reorder.x <tbset.h>
+ select.x reloperr.h
+ tabvar.x <tbset.h> "../tabvar.com"
+ tbfile.x <ctype.h>
+ tuopen.x
+ tbleval.x <config.h> <error.h> <evexpr.h> \
+ <xwhen.h> reloperr.h tblterm.com
+ tblsearch.x <config.h> <evexpr.h> <xwhen.h> \
+ reloperr.h tblterm.com
+ tblsort.x
+ tblterm.x <config.h> <evexpr.h> <tbset.h> \
+ <xwhen.h> reloperr.h tblterm.com
+ tctexp.x <tbset.h> <ctype.h> reloperr.h
+ tldtype.x
+ unique.x
+ ;
diff --git a/pkg/utilities/nttools/lib/movenulls.x b/pkg/utilities/nttools/lib/movenulls.x
new file mode 100644
index 00000000..5e961d20
--- /dev/null
+++ b/pkg/utilities/nttools/lib/movenulls.x
@@ -0,0 +1,35 @@
+# MOVENULLS -- Move all null elements to the end of the index array
+#
+# This procedure rearranges an array of row indices so that all rows with
+# nulls in a particular column are moved to the end of the index array.
+# The position of the nulls in the column is indicated by an array of null
+# flags, whose length might be greater than the length of the array of
+# indices, i.e., only a subset of the rows in a table might be in the index
+# array.
+#
+# B.Simon 15-Dec-87 First Code
+
+int procedure movenulls (nindex, nulflg, index)
+
+int nindex # i: Number of indices
+bool nulflg[ARB] # i: Array of null flags
+int index[ARB] # io: Array of row indices
+#--
+int nelem, idx, jdx
+
+begin
+ nelem = nindex
+
+ do idx = nindex, 1, -1 {
+ jdx = index[idx]
+ if (nulflg[jdx]) {
+ if (nelem != idx) {
+ index[idx] = index[nelem]
+ index[nelem] = jdx
+ }
+ nelem = nelem - 1
+ }
+ }
+
+ return (nelem)
+end
diff --git a/pkg/utilities/nttools/lib/msort.x b/pkg/utilities/nttools/lib/msort.x
new file mode 100644
index 00000000..2731351f
--- /dev/null
+++ b/pkg/utilities/nttools/lib/msort.x
@@ -0,0 +1,113 @@
+include "reloperr.h"
+
+# MSORT -- General merge sort for arbitrary objects. X is an integer array
+# indexing the array to be sorted. The user supplied COMPARE function is used
+# to compare objects indexed by X:
+#
+# -1,0,1 = compare (x1, x2)
+#
+# where the value returned by COMPARE has the following significance:
+#
+# -1 obj[x1] < obj[x2]
+# 0 obj[x1] == obj[x2]
+# 1 obj[x1] > obj[x2]
+#
+# MSORT reorders the elements of the X array, which must be of type integer.
+#
+# B.Simon 28-Sept-87 First Code
+
+procedure msort (x, nx, nelem, compare)
+
+int x[ARB] # array to be sorted
+int nx # length of array x (Must be >= 2 * nelem)
+int nelem # number of elements to be sorted
+extern compare() # function to be called to compare elements
+#--
+bool up
+int ielem, jelem, kelem, melem
+int runlen, ilen, jlen
+
+int compare()
+
+begin
+ if (2 * nelem > nx)
+ call error (BOUNDS, "Index array too small")
+
+ # Merging two sorted runs creates a new sorted run twice the length
+ # of the original run. Continue this process until the sorted run
+ # length is equal to the array length.
+
+ up = false
+ for (runlen = 1; runlen < nelem; runlen = 2 * runlen) {
+
+ # The runs are stored in one of two halves of the x array.
+ # Set the array pointers according to the half the runs are
+ # located in now.
+
+ if (! up) {
+ ielem = 1
+ jelem = runlen + 1
+ kelem = nx - nelem + 1
+ melem = nelem
+ } else {
+ ielem = nx - nelem + 1
+ jelem = runlen + ielem
+ kelem = 1
+ melem = nx
+ }
+
+ # Loop over each pair of runs in the array
+
+ while (ielem <= melem) {
+ ilen = min (runlen, melem-ielem+1)
+ jlen = min (runlen, melem-jelem+1)
+
+ # Merge the pair of runs into the other half of the x array
+
+ while (ilen > 0 && jlen > 0) {
+ if (compare (x[ielem], x[jelem]) <= 0) {
+ x[kelem] = x[ielem]
+ ielem = ielem + 1
+ kelem = kelem + 1
+ ilen = ilen - 1
+ } else {
+ x[kelem] = x[jelem]
+ jelem = jelem + 1
+ kelem = kelem + 1
+ jlen = jlen - 1
+ }
+ }
+
+ # Copy the remaining elements from i when j is exhausted
+
+ while (ilen > 0) {
+ x[kelem] = x[ielem]
+ ielem = ielem + 1
+ kelem = kelem + 1
+ ilen = ilen - 1
+ }
+
+ # Copy the remaining elements from j when i is exhausted
+
+ while (jlen > 0) {
+ x[kelem] = x[jelem]
+ jelem = jelem + 1
+ kelem = kelem + 1
+ jlen = jlen - 1
+ }
+
+ # Set array pointers to next set of runs
+
+ ielem = ielem + runlen
+ jelem = jelem + runlen
+ }
+ up = ! up
+ }
+
+ # If result is in the upper end of x array, move it to the lower
+ # end
+
+ if (up)
+ call amovi (x[nx-nelem+1], x[1], nelem)
+
+ end
diff --git a/pkg/utilities/nttools/lib/newcolnam.x b/pkg/utilities/nttools/lib/newcolnam.x
new file mode 100644
index 00000000..4179383d
--- /dev/null
+++ b/pkg/utilities/nttools/lib/newcolnam.x
@@ -0,0 +1,97 @@
+include <ctype.h>
+include <tbset.h>
+include "reloperr.h"
+
+# NEWCOLNAM -- Create a new, unique column name
+#
+# This procedure receives as input an array of column pointers from two or
+# more tables and an index into that array. If the name of the column pointed
+# to by that index is unique, it is output as the new name. If it is not
+# unique, a suffix of the form "_i" is appended to the name, where i is
+# a digit which (hopefully) makes the name unique.
+#
+# B.Simon 3-Nov-87 first code
+# B.Simon 4-Sep-90 Replaced call to strncmp with streq
+
+procedure newcolnam (numcol, colptr, colidx, newnam, maxch)
+
+int numcol # i: Number of column pointers
+pointer colptr[ARB] # i: Array of column pointers
+int colidx # i: Index to column to be renamed
+char newnam[ARB] # o: New column name
+int maxch # i: Maximum characters in new name
+#--
+int olen, nmatch, nbefore, icol
+pointer sp, oldnam, colnam, errtxt
+
+string notuniq "Cannot create a unique column name (%s)"
+
+bool streq()
+int strlen()
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (oldnam, SZ_COLNAME, TY_CHAR)
+ call salloc (colnam, SZ_COLNAME, TY_CHAR)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ # Read column name pointed to by index
+
+ call tbcigt (colptr[colidx], TBL_COL_NAME, Memc[oldnam], SZ_COLNAME)
+ call strupr (Memc[oldnam])
+
+ # See if the name is unique, and if not, how many columns with
+ # the same name precede this one
+
+ nmatch = 0
+ nbefore = 0
+ do icol = 1, numcol {
+ call tbcigt (colptr[icol], TBL_COL_NAME, Memc[colnam], SZ_COLNAME)
+ call strupr (Memc[colnam])
+
+ if (streq (Memc[colnam], Memc[oldnam])) {
+ nmatch = nmatch + 1
+ if (icol <= colidx)
+ nbefore = nbefore + 1
+ }
+ }
+
+ # If the name is not unique, add a suffix of the form "_i"
+
+ if (nmatch > 1) {
+
+ # Check for ridiculous values of maxch
+
+ olen = min (maxch-2, strlen(Memc[oldnam]))
+ if (olen < 1) {
+ call sprintf (Memc[errtxt], SZ_LINE, notuniq)
+ call pargstr (Memc[oldnam])
+ call error (SYNTAX, Memc[errtxt])
+ }
+
+ # Add the suffix
+
+ Memc[oldnam+olen] = '_'
+ Memc[oldnam+olen+1] = TO_DIGIT (nbefore)
+ Memc[oldnam+olen+2] = EOS
+
+ # Make sure it is unique
+
+ do icol = 1, numcol {
+ call tbcigt (colptr[icol], TBL_COL_NAME, Memc[colnam],
+ SZ_COLNAME)
+ if (streq (Memc[oldnam], Memc[colnam])) {
+ call sprintf (Memc[errtxt], SZ_LINE, notuniq)
+ call pargstr (Memc[oldnam])
+ call error (SYNTAX, Memc[errtxt])
+ }
+ }
+ }
+
+ # Copy to the output string
+
+ call strcpy (Memc[oldnam], newnam, maxch)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/lib/reloperr.h b/pkg/utilities/nttools/lib/reloperr.h
new file mode 100644
index 00000000..6dff85c7
--- /dev/null
+++ b/pkg/utilities/nttools/lib/reloperr.h
@@ -0,0 +1,3 @@
+define SYNTAX 1
+define BOUNDS 2
+define PUTNULL 11
diff --git a/pkg/utilities/nttools/lib/reorder.x b/pkg/utilities/nttools/lib/reorder.x
new file mode 100644
index 00000000..cacd98e2
--- /dev/null
+++ b/pkg/utilities/nttools/lib/reorder.x
@@ -0,0 +1,60 @@
+include <tbset.h>
+
+# REORDER -- Reorder table rows according to an index array
+#
+# This procedure rearranges the rows of a table according to the contents
+# of an index array. The index array is produced by one of the two table
+# sort routines, tsort1 or tsortm. The algorithm used is taken from Knuth's
+# Sorting and Searching p.595.
+#
+# B.Simon 17-Sept-87 First Code
+# B.Simon 15-Jul-88 Rewritten
+# Phil Hodge 12-Sep-88 Don't include tbtables.h
+
+procedure reorder (tp, nindex, index)
+
+pointer tp # i: Table descriptor
+int nindex # i: Number of indices
+int index[ARB] # io: Array of row indices
+#--
+int idx, jdx, kdx, ndx
+int tbpsta()
+
+errchk tbrcpy
+
+begin
+ # Use the row after the end of the table for temporary storage
+
+ ndx = tbpsta (tp, TBL_NROWS) + 1
+
+ # Loop over all rows of the table, moving them into their proper
+ # order
+
+ do idx = 1, nindex {
+
+ # The index array forms one or more cycles. Move the first
+ # row in the cycle to the temporary location. Repeatedly
+ # move the remaining rows in the cycle until the final
+ # location of the first row is found. Move the first row
+ # from its temporary location to its final location. Update
+ # the index array to indicate which rows have been moved.
+
+ if (index[idx] != idx) {
+ call tbrcpy (tp, tp, idx, ndx)
+ jdx = idx
+ while (index[jdx] != idx) {
+ kdx = index[jdx]
+ call tbrcpy (tp, tp, kdx, jdx)
+ index[jdx] = jdx
+ jdx = kdx
+ }
+ call tbrcpy (tp, tp, ndx, jdx)
+ index[jdx] = jdx
+ }
+
+ }
+
+ # Remove the temporary row
+
+ call tbrdel (tp, ndx, ndx)
+end
diff --git a/pkg/utilities/nttools/lib/select.x b/pkg/utilities/nttools/lib/select.x
new file mode 100644
index 00000000..02cc73f8
--- /dev/null
+++ b/pkg/utilities/nttools/lib/select.x
@@ -0,0 +1,99 @@
+include "reloperr.h"
+
+# SELECT -- Select table rows according to expression
+#
+# This procedure evaluates a boolean expession for selected rows in a table.
+# If the expression is true and does not involve null elements, the index
+# of that row is kept in the index array.
+#
+# B.Simon 7-Oct-87 First Code
+# B.Simon 16-Dec-87 Changed to handle table subsets
+# B.Simon 06-Jan-93 Changed to use ftnexpr
+
+procedure select (tp, expr, nindex, index)
+
+pointer tp # i: Table descriptor
+char expr[ARB] # i: Algebraic expression used in selection
+int nindex # io: Number of rows selected
+int index[ARB] # io: Indices of selected rows
+#--
+char ch
+pointer sp, oldexp, newexp, ic, aryptr, nulptr
+int fd, sd, jc, dtype, nary, iary
+
+int open(), stropen(), stridx()
+
+errchk open, stropen, tbl_eval
+
+string badtype "Expression is not boolean"
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (oldexp, SZ_COMMAND, TY_CHAR)
+ call salloc (newexp, SZ_COMMAND, TY_CHAR)
+
+ # Check to see if the expression is a file name
+
+ if (expr[1] == '@') {
+
+ # Copy the file into a string
+
+ fd = open (expr[2], READ_ONLY, TEXT_FILE)
+ sd = stropen (Memc[oldexp], SZ_COMMAND, WRITE_ONLY)
+ call fcopyo (fd, sd)
+ call close (fd)
+ call strclose (sd)
+
+ # Replace the newlines with blanks
+
+ ic = oldexp
+ ch = '\n'
+ repeat {
+ jc = stridx (ch, Memc[ic])
+ if (jc == 0)
+ break
+ ic = ic + jc
+ Memc[ic-1] = ' '
+ }
+
+ # Convert Fortran relational operators to SPP
+
+ call ftnexpr (Memc[oldexp], Memc[newexp], SZ_COMMAND)
+
+ } else {
+
+ # Convert Fortran relational operators to SPP
+
+ call ftnexpr (expr, Memc[newexp], SZ_COMMAND)
+ }
+
+ # Evaluate the expression
+
+ dtype = TY_BOOL
+ call tbl_eval (tp, nindex, index, Memc[newexp], dtype, aryptr, nulptr)
+
+ # Check to see if result is boolean
+
+ if (dtype != TY_BOOL) {
+ call mfree (aryptr, dtype)
+ call mfree (nulptr, TY_BOOL)
+ call error (SYNTAX, badtype)
+ }
+
+ # Put indices of true, non-null rows in index array
+
+ nary = nindex
+ nindex = 0
+ do iary = 1, nary
+
+ if (Memb[aryptr+iary-1] && ! Memb[nulptr+iary-1]) {
+ nindex = nindex + 1
+ index[nindex] = index[iary]
+ }
+
+ call mfree (aryptr, dtype)
+ call mfree (nulptr, TY_BOOL)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/lib/tabvar.x b/pkg/utilities/nttools/lib/tabvar.x
new file mode 100644
index 00000000..339f2d95
--- /dev/null
+++ b/pkg/utilities/nttools/lib/tabvar.x
@@ -0,0 +1,118 @@
+include <tbset.h>
+
+# TABVAR -- Retrieve a table column given its name
+#
+# B.Simon 03-May-91 Original
+# B.Simon 23-Jun-97 Peicewise evaluation of column
+
+procedure tabvar (stack, colname)
+
+pointer stack # u: Expression stack pointer
+char colname[ARB] # i: Column name
+#--
+include "../tabvar.com"
+
+int i, coltype, nrows
+pointer sp, nullbuf, buffer, errmsg, cp
+
+string badcolnam "Column name not found (%s)"
+
+bool streq()
+int tbcigi()
+pointer stk_alloc()
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ # Get column pointer from name
+
+ call tbcfnd (tabptr, colname, cp, 1)
+ if (cp == NULL) {
+ if (streq (colname, "rownum")) {
+ call rowvar (stack)
+ return
+ } else {
+ call sprintf (Memc[errmsg], SZ_LINE, badcolnam)
+ call pargstr (colname)
+ call error (1, Memc[errmsg])
+ }
+ }
+
+ # Get column type
+
+ coltype = tbcigi (cp, TBL_COL_DATATYPE)
+ if (coltype == TY_BOOL || coltype == TY_SHORT || coltype == TY_LONG) {
+ coltype = TY_INT
+ } else if (coltype < 0) {
+ coltype = TY_DOUBLE
+ }
+
+ # Allocate a buffer on the expression evaluator stack
+
+ nrows = (lastrow - firstrow) + 1
+ call malloc (nullbuf, nrows, TY_BOOL)
+ buffer = stk_alloc (stack, nrows, coltype)
+
+ # Copy the table column into the buffer
+ # Substitute the user supplied vales for nulls
+
+ switch (coltype) {
+ case TY_SHORT, TY_INT, TY_LONG:
+ call tbcgti (tabptr, cp, Memi[buffer], Memb[nullbuf],
+ firstrow, lastrow)
+ do i = 0, nrows-1 {
+ if (Memb[nullbuf+i])
+ Memi[buffer+i] = nullval
+ }
+
+ case TY_REAL:
+ call tbcgtr (tabptr, cp, Memr[buffer], Memb[nullbuf],
+ firstrow, lastrow)
+ do i = 0, nrows-1 {
+ if (Memb[nullbuf+i])
+ Memr[buffer+i] = nullval
+ }
+ case TY_DOUBLE:
+ call tbcgtd (tabptr, cp, Memd[buffer], Memb[nullbuf],
+ firstrow, lastrow)
+ do i = 0, nrows-1 {
+ if (Memb[nullbuf+i])
+ Memd[buffer+i] = nullval
+ }
+ }
+
+ # Update the null array
+ call stk_ornull (stack, Memb[nullbuf], nrows)
+
+ call mfree (nullbuf, TY_BOOL)
+ call sfree (sp)
+
+end
+
+# ROWVAR -- Handle the variable "rownum"
+
+procedure rowvar (stack)
+
+pointer stack # u: Expression stack pointer
+#--
+include "../tabvar.com"
+
+int irow, nrows
+pointer buffer
+
+pointer stk_alloc()
+
+begin
+ # Allocate a buffer on the expression evaluator stack
+
+ nrows = (lastrow - firstrow) + 1
+ buffer = stk_alloc (stack, nrows, TY_INT)
+
+ # Fill the buffer with the row number
+ do irow = 0, nrows-1
+ Memi[buffer+irow] = firstrow + irow
+end
+
diff --git a/pkg/utilities/nttools/lib/tbfile.x b/pkg/utilities/nttools/lib/tbfile.x
new file mode 100644
index 00000000..d11e1720
--- /dev/null
+++ b/pkg/utilities/nttools/lib/tbfile.x
@@ -0,0 +1,85 @@
+include <ctype.h> # for IS_ALNUM
+
+# tbfile -- get table and file name
+# This routine takes a table name as specified by a user and returns
+# the full table name, the full file name, and the filename extension
+# (including the dot; e.g. ".tab"). The filename extension may be the
+# null string if the file is a text table. The file name will be a
+# subset of the table name, as the table name may include a bracketed
+# expression giving EXTNAME or HDU number or table name in CDF file.
+#
+# Phil Hodge, 27-Jun-1995 Subroutine created.
+# Phil Hodge, 29-Sep-1997 No longer necessary to enclose extname expression
+# in brackets, as the brackets are now included.
+# Phil hodge, 16-Apr-1999 Remove ttype from calling sequence of tbparse.
+
+procedure tbfile (input, tabname, filename, extn, maxch)
+
+char input[ARB] # i: input table name
+char tabname[maxch] # o: full table name
+char filename[maxch] # o: name of file containing table
+char extn[maxch] # o: filename extension, including '.'
+int maxch # i: size of strings
+#--
+pointer sp
+pointer fname # full file name
+pointer brackets # for CDF or HDU name or number, and/or selectors
+int hdu # returned by tbparse and ignored
+int dotloc # location of last '.' in file name
+int i
+int strlen(), access()
+int tbparse()
+bool strne()
+errchk tbparse, tbtext
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_LINE, TY_CHAR)
+ call salloc (brackets, SZ_LINE, TY_CHAR)
+
+ # Separate filename from any bracketed expression (such as
+ # EXTNAME or HDU number) that may be present.
+ if (tbparse (input, Memc[fname], Memc[brackets], SZ_LINE, hdu) < 1) {
+ tabname[1] = EOS
+ filename[1] = EOS
+ extn[1] = EOS
+ call sfree (sp)
+ return
+ }
+
+ # Append default extension (if appropriate) to get full file name.
+ # A text table need not have an extension, so first check whether
+ # a file of the given name exists. If not, then append extension.
+ if (access (Memc[fname], 0, 0) == NO &&
+ strne (input, "STDIN") && strne (input, "STDOUT"))
+ call tbtext (Memc[fname], Memc[fname], SZ_LINE)
+
+ # At this point we have the full file name; copy it to output.
+ call strcpy (Memc[fname], filename, maxch)
+
+ # Append bracketed expression (if present) to get full table name,
+ # and copy it to output.
+ call strcpy (Memc[fname], tabname, maxch)
+ if (Memc[brackets] != EOS)
+ call strcat (Memc[brackets], tabname, maxch)
+
+ # Search for a filename extension. Look for a dot that is not
+ # followed by any special character.
+ dotloc = 0 # initial value
+ do i = strlen (Memc[fname]), 1, -1 {
+ if (Memc[fname+i-1] == '.') { # found it
+ dotloc = i
+ break
+ }
+ if (!IS_ALNUM(Memc[fname+i-1])) # stop at first special char
+ break
+ }
+
+ # If the file name includes an extension, copy it to output.
+ if (dotloc > 0)
+ call strcpy (Memc[fname+dotloc-1], extn, maxch)
+ else
+ extn[1] = EOS
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/lib/tbleval.x b/pkg/utilities/nttools/lib/tbleval.x
new file mode 100644
index 00000000..c9382699
--- /dev/null
+++ b/pkg/utilities/nttools/lib/tbleval.x
@@ -0,0 +1,159 @@
+include <config.h>
+include <error.h>
+include <evexpr.h>
+include <xwhen.h>
+include "reloperr.h"
+
+# TBL_EVAL -- Evaluate an arbitrary expression over table columns
+#
+# This procedure receives as input a table descriptor, an index array, and
+# a character string containing an algebraic expression. The terms in the
+# expression are column names. The expression is evaluated for each row in
+# the index array using the values from the indicated columns and the results
+# stored in the output array (aryptr). The array pointed to by nulptr
+# contains null flags. A null flag is set to true if any of the table elements
+# in the expression is null or an arithmetic error ocurs during the
+# evaluation of the expression. Otherwise the null flag is set to false.
+# The type of the output array is determined by the type of the expression
+# unless all the elements are null, in which case the type input by the
+# calling routine is used. The two arrays pointed to by aryptr and nulptr
+# must be deallocated by the calling routine.
+#
+# B.Simon 29-Sept-87 First Code
+# B.Simon 16-Dec-87 Changed to handle table subsets
+# B.Simon 13-Apr-88 tbl_term, tbl_func moved to separate file
+
+procedure tbl_eval (tp, nindex, index, expr, dtype, aryptr, nulptr)
+
+pointer tp # i: Table descriptor
+int nindex # i: Number of elements in index array
+int index[ARB] # i: Array of row indices
+char expr[ARB] # i: Expression to be evaluated
+int dtype # io: Type of output array
+pointer aryptr # o: Array of output values
+pointer nulptr # o: Array of null flags
+#--
+include "tblterm.com"
+
+int iary, status, junk
+int old_handler, tbl_term_adr, tbl_func_adr
+pointer op
+
+string badtype "Character expressions not allowed"
+
+int locpr(), errcode()
+pointer evexpr()
+
+extern tbl_handler(), tbl_term(), tbl_func()
+
+begin
+ # Initialize output variables
+
+ aryptr = NULL
+ call malloc (nulptr, nindex, TY_BOOL)
+
+ # Set up error handler to catch arithmetic errors
+
+ call xwhen (X_ARITH, locpr(tbl_handler), old_handler)
+
+ table = tp
+ nterm = 0
+ constant = true
+
+ tbl_term_adr = locpr (tbl_term)
+ tbl_func_adr = locpr (tbl_func)
+
+ # Loop over all rows of the table
+
+ do iary = 1, nindex {
+
+ irow = index[iary]
+ iterm = 0
+
+ # Execution will resume here when an arithmetic error occurs
+
+ call zsvjmp (jumpbuf, status)
+
+ if (status != OK) {
+ Memb[nulptr+iary-1] = true
+
+ # Special case to speed up the evaluation of constant expressions
+
+ } else if (constant && (iary != 1)) {
+ Memb[nulptr+iary-1] = false
+ switch (dtype) {
+ case TY_BOOL:
+ Memb[aryptr+iary-1] = Memb[aryptr]
+ case TY_INT:
+ Memi[aryptr+iary-1] = Memi[aryptr]
+ case TY_REAL:
+ Memr[aryptr+iary-1] = Memr[aryptr]
+ }
+
+ # Evaluate the expression using the values in the current row
+
+ } else {
+ iferr {
+ op = evexpr (expr, tbl_term_adr, tbl_func_adr)
+ } then {
+
+ # Catch the error sent when a table element is null
+
+ if (errcode() == PUTNULL)
+ Memb[nulptr+iary-1] = true
+ else {
+ call mfree (nulptr, TY_BOOL)
+ call xwhen (X_ARITH, old_handler, junk)
+ call erract (EA_ERROR)
+ }
+
+ # Usual case
+
+ } else {
+
+ Memb[nulptr+iary-1] = false
+
+ # Determine array type from type of expression
+
+ if (aryptr == NULL) {
+ if (O_TYPE(op) == TY_CHAR) {
+ call mfree (nulptr, TY_BOOL)
+ call xwhen (X_ARITH, old_handler, junk)
+ call error (SYNTAX, badtype)
+ }
+ dtype = O_TYPE(op)
+ call calloc (aryptr, nindex, dtype)
+ }
+
+ # Assign the result of the expression to the output
+ # array
+
+ switch (dtype) {
+ case TY_BOOL:
+ Memb[aryptr+iary-1] = O_VALB(op)
+ case TY_INT:
+ Memi[aryptr+iary-1] = O_VALI(op)
+ case TY_REAL:
+ Memr[aryptr+iary-1] = O_VALR(op)
+ }
+
+ call mfree (op, TY_STRUCT) # Bug fix (BPS 04.20.93)
+ }
+ }
+ }
+
+ # Allocate array when all results are null
+
+ if (aryptr == NULL) {
+ if (dtype == TY_CHAR) {
+ call mfree (nulptr, TY_BOOL)
+ call xwhen (X_ARITH, old_handler, junk)
+ call error (SYNTAX, badtype)
+ }
+ call calloc (aryptr, nindex, dtype)
+ }
+ # Restore old error handler
+
+ call xwhen (X_ARITH, old_handler, junk)
+
+end
diff --git a/pkg/utilities/nttools/lib/tbljoin.x b/pkg/utilities/nttools/lib/tbljoin.x
new file mode 100644
index 00000000..c2a26fd6
--- /dev/null
+++ b/pkg/utilities/nttools/lib/tbljoin.x
@@ -0,0 +1,168 @@
+include <tbset.h>
+define MAXPRI 7
+
+# TBL_JOIN -- Relational join of two tables
+#
+# This procedure peforms a relational join by sorting the two tables on
+# the column to be joined and then merging the tables on the basis of the
+# common column. An input tolerance is used to control the test for equality
+# in the merge. The variables which describe the two tables are the table
+# descriptors (tp1 & tp2), column descriptors (cp1 & cp2), row index arrays
+# (index1 & index2), and index array lengths (nindex1 & nindex2). The merged
+# output table is described by two index arrays which contain the row indices
+# from the respective input tables (index3 & index4) and the index array
+# lengths (nindex3 & nindex4). On input these lengths are the declared length
+# of the output index arrays, on output, they are the number of rows in
+# the merged output table. The total number of merged rows is output as
+# njoin. The output index arrays may not be large enough to hold the merged
+# table indices. In this case, the output index arrays will be filled as much
+# as possible. So if njoin is greater than nindex3 or nindex4, an error has
+# occured, but this error can be recovered from by reallocating the output
+# index arrays so that the can hold njoin elements and calling this procedure
+# again.
+#
+# B.Simon 03-Nov-87 First Code
+# B.Simon 16-Dec-87 Changed to handle table subsets
+# B.Simon 06-Feb-90 Changed to use tbtsrt
+
+procedure tbl_join (tol, casesens, tp1, tp2, cp1, cp2, nindex1, nindex2,
+ index1, index2, nindex3, nindex4, index3, index4, njoin)
+
+double tol # i: Tolerance used in testing for equality
+bool casesens # i: Join is case sensitive
+pointer tp1 # i: Table descriptor of first table
+pointer tp2 # i: Table descriptor of second table
+pointer cp1 # i: Column descriptor of merged column in first table
+pointer cp2 # i: Column descriptor of merged column in second table
+int nindex1 # i: Number of indices in first input array
+int nindex2 # i: Number of indices in second input array
+int index1 # i: Array of row indices for first input table
+int index2 # i: Array of row indices for second input table
+int nindex3 # io: Number of indices in first output array
+int nindex4 # io: Number of indices in second output array
+int index3 # o: Array of row indices for first output table
+int index4 # o: Array of row indices for second output table
+int njoin # o: Number of joined rows
+#--
+bool fold
+int dtype[2], spptype[2], lendata[2], colpri[2], nary[2], nidx[2]
+int itab, iary, nmax
+
+pointer nulptr, temptr, curptr
+pointer tp[2], cp[2], idxptr[2], aryptr[2]
+
+int priority[MAXPRI]
+data priority / TY_DOUBLE, TY_REAL, TY_LONG, TY_INT, TY_SHORT,
+ TY_CHAR, TY_BOOL /
+double mjd()
+int tbcigi()
+
+begin
+ # Move input variables into arrays
+
+ fold = ! casesens
+
+ tp[1] = tp1
+ tp[2] = tp2
+
+ cp[1] = cp1
+ cp[2] = cp2
+
+ nmax = min (nindex3, nindex4)
+
+ nidx[1] = nindex1
+ nidx[2] = nindex2
+
+ call malloc (idxptr[1], nindex1, TY_INT)
+ call amovi (index1, Memi[idxptr[1]], nindex1)
+
+ call malloc (idxptr[2], nindex2, TY_INT)
+ call amovi (index2, Memi[idxptr[2]], nindex2)
+
+ # Determine the data type of the merged column
+
+ do itab = 1, 2 {
+
+ dtype[itab] = tbcigi (cp[itab], TBL_COL_DATATYPE)
+
+ if (dtype[itab] < 0) {
+ lendata[itab] = - dtype[itab]
+ spptype[itab] = TY_CHAR
+ } else {
+ lendata[itab] = 1
+ spptype[itab] = dtype[itab]
+ }
+
+ for (colpri[itab] = 1;
+ spptype[itab] != priority[colpri[itab]];
+ colpri[itab] = colpri[itab] + 1
+ ) ;
+
+ }
+
+ if (colpri[1] < colpri[2]) {
+ spptype[2] = spptype[1]
+ lendata[2] = lendata[1]
+ } else if (colpri[2] < colpri[1]) {
+ spptype[1] = spptype[2]
+ lendata[1] = lendata[2]
+ }
+
+ # Read common columns into arrays and sort
+
+ do itab = 1, 2 {
+
+ # Sort the index array on the common column
+
+ call tbtsrt (tp[itab], 1, cp[itab], fold,
+ nidx[itab], Memi[idxptr[itab]])
+
+ # Read in the common column
+
+ if (spptype[itab] == TY_CHAR)
+ dtype[itab] = - lendata[itab]
+ else
+ dtype[itab] = spptype[itab]
+
+ call gettabcol (tp[itab], cp[itab], dtype[itab],
+ nary[itab], aryptr[itab], nulptr)
+
+ # If the tolerance of a string column is non-zero,
+ # interpret the column as a date
+
+ if (dtype[itab] < 0 && tol > 0.0) {
+
+ call malloc (temptr, nary[itab], TY_DOUBLE)
+ curptr = aryptr[itab]
+ do iary = 1, nary[itab] {
+ if (Memb[nulptr+iary-1])
+ Memd[temptr+iary-1] = INDEFD
+ else
+ Memd[temptr+iary-1] = mjd (Memc[curptr])
+ curptr = curptr + lendata[itab] + 1
+ }
+ call mfree (aryptr[itab], TY_CHAR)
+ dtype[itab] = TY_DOUBLE
+ spptype[itab] = TY_DOUBLE
+ lendata[itab] = 1
+ aryptr[itab] = temptr
+ }
+ }
+
+ # Merge the two tables
+
+ call tbl_merge (tol, dtype, nary, aryptr, nidx, idxptr,
+ nmax, njoin, index3, index4)
+
+ nindex3 = min (nmax, njoin)
+ nindex4 = min (nmax, njoin)
+
+ # Free dynamic memory
+
+ call mfree (nulptr, TY_BOOL)
+ do itab = 1, 2 {
+ call mfree (idxptr[itab], TY_INT)
+ call mfree (aryptr[itab], spptype[itab])
+ }
+
+end
diff --git a/pkg/utilities/nttools/lib/tblmerge.x b/pkg/utilities/nttools/lib/tblmerge.x
new file mode 100644
index 00000000..ead8cbe6
--- /dev/null
+++ b/pkg/utilities/nttools/lib/tblmerge.x
@@ -0,0 +1,162 @@
+include "reloperr.h"
+
+# TBL_MERGE -- Merge two tables on the basis of a common column
+#
+# This procedure creates an array of row indices from two tables where the
+# row indices point to a pair of rows where the values stored in the two
+# columns are equal within an input tolerance. The column values are stored in
+# the two arrays pointed to by aryptr. The two columns must already be sorted
+# in ascending order with the row indices of the two columns stored in the
+# arrays pointed to by idxptr. This procedure keeps on going even when an
+# output array overflow condition is detected so that the caller knows how
+# large the output array must be.
+#
+# B.Simon 1-Nov-87 First code
+# B.Simon 16-Dec-87 Changed to handle table subsets
+
+procedure tbl_merge (tol, dtype, nary, aryptr, nidx, idxptr, nmax,
+ nmerge, index1, index2)
+
+double tol # i: Tolerance used in test for equality
+int dtype[2] # i: Data types of columns
+int nary[2] # i: Size of arrays containing columns
+pointer aryptr[2] # i: Pointers to column arrays
+int nidx[2] # i: Size of arrays containing row indices
+pointer idxptr[2] # i: Pointers to index arrays
+int nmax # i: Max size of arrays containing merged row indices
+int nmerge # o: Number of merged row indices
+int index1[ARB] # o: Array of merged row indices for first table
+int index2[ARB] # o: Array of merged row indices for second table
+#--
+double dbl_tol
+int itab, int_tol, idx, jdx, kdx, order, lendata[2], spptype[2]
+pointer ptr1, ptr2
+real real_tol
+
+bool strlt(), strgt()
+
+string badtype "Data types of the two columns to be merged must be equal"
+string badtol "Tolerance for boolean or character columns must be zero"
+
+begin
+ # Get data type and length from dtype
+
+ do itab = 1, 2 {
+ if (dtype[itab] < 0) {
+ lendata[itab] = 1 - dtype[itab]
+ spptype[itab] = TY_CHAR
+ } else {
+ lendata[itab] = 1
+ spptype[itab] = dtype[itab]
+ }
+ }
+
+ if (spptype[1] != spptype[2])
+ call error (SYNTAX, badtype)
+
+ # Convert tolerance to the same type as the data
+
+ switch (spptype[1]) {
+ case TY_BOOL, TY_CHAR:
+ if (tol > 0.0)
+ call error (SYNTAX, badtol)
+ case TY_SHORT, TY_INT, TY_LONG:
+ int_tol = tol
+ case TY_REAL:
+ real_tol = tol
+ case TY_DOUBLE:
+ dbl_tol = tol
+ }
+
+ idx = 1
+ jdx = 1
+ kdx = 1
+
+ nmerge = 0
+ while (idx <= nidx[1] && jdx <= nidx[2]) {
+
+ # Calculate addresses of array elements
+
+ ptr1 = aryptr[1] + lendata[1] * (Memi[idxptr[1]+idx-1] - 1)
+ ptr2 = aryptr[2] + lendata[2] * (Memi[idxptr[2]+jdx-1] - 1)
+
+ # Determine relative order of the two elements
+ # If mem[ptr1] < mem[ptr2], order = -1
+ # If mem[ptr1] == mem[ptr2], order = 0
+ # If mem[ptr1] > mem[ptr2], order = 1
+
+ switch (spptype[1]) {
+ case TY_BOOL:
+ # false < true
+
+ if (! Memb[ptr1] && Memb[ptr2])
+ order = -1
+ else if (Memb[ptr1] && ! Memb[ptr2])
+ order = 1
+ else
+ order = 0
+ case TY_CHAR:
+ if (strlt (Memc[ptr1], Memc[ptr2]))
+ order = -1
+ else if (strgt (Memc[ptr1], Memc[ptr2]))
+ order = 1
+ else
+ order = 0
+ case TY_SHORT,TY_INT, TY_LONG:
+ if (Memi[ptr1] + int_tol < Memi[ptr2])
+ order = -1
+ else if (Memi[ptr1] > Memi[ptr2] + int_tol)
+ order = 1
+ else
+ order = 0
+ case TY_REAL:
+ if (Memr[ptr1] + real_tol < Memr[ptr2])
+ order = -1
+ else if (Memr[ptr1] > Memr[ptr2] + real_tol)
+ order = 1
+ else
+ order = 0
+ case TY_DOUBLE:
+ if (Memd[ptr1] + dbl_tol < Memd[ptr2])
+ order = -1
+ else if (Memd[ptr1] > Memd[ptr2] + dbl_tol)
+ order = 1
+ else
+ order = 0
+ }
+
+ # Increment the indices to the two arrays and if a match is
+ # found, add it to the index array.
+
+ # The third index, kdx, tells where to fall back to when the
+ # value in the first array exceeds the value in the second array.
+ # Because the arrays are sorted in ascending order, the array
+ # element pointed to by idx exceeds all those previous to the
+ # element pointed to by kdx, so there is no use checking them.
+
+ switch (order) {
+ case -1:
+ idx = idx + 1
+ jdx = kdx
+ case 0:
+ nmerge = nmerge + 1
+ if (nmerge <= nmax) {
+ index1[nmerge] = Memi[idxptr[1]+idx-1]
+ index2[nmerge] = Memi[idxptr[2]+jdx-1]
+ }
+
+ # Keep fron reading past the end of the array
+
+ if (jdx < nidx[2]) {
+ jdx = jdx + 1
+ } else {
+ idx = idx + 1
+ jdx = kdx
+ }
+ case 1:
+ jdx = jdx + 1
+ kdx = jdx
+ }
+ }
+
+end
diff --git a/pkg/utilities/nttools/lib/tblsearch.x b/pkg/utilities/nttools/lib/tblsearch.x
new file mode 100644
index 00000000..87e17106
--- /dev/null
+++ b/pkg/utilities/nttools/lib/tblsearch.x
@@ -0,0 +1,104 @@
+include <config.h>
+include <evexpr.h>
+include <xwhen.h>
+include "reloperr.h"
+
+# TBL_SEARCH -- Search table for a row which makes an expression true
+#
+# This procedure evaluates a boolean expession for the indicated rows in a
+# table. When it finds a row which makes the expression true, it returns
+# the row number. If it does not find any such row, it returns zero. If
+# there is a syntax error in the expression, it returns ERR.
+#
+# B.Simon 13-Apr-1988 First Code
+# Phil Hodge 4-Mar-2002 Free memory allocated by evexpr.
+# Phil Hodge 23-Apr-2002 Move xev_freeop and mfree.
+
+int procedure tbl_search (tp, expr, first, last)
+
+pointer tp # i: Table descriptor
+char expr[ARB] # i: Boolean expression used in search
+int first # i: First row to look at
+int last # i: Last row to look at
+#--
+include "tblterm.com"
+
+int old_handler, tbl_term_adr, tbl_func_adr
+int status, found, dir, iary, junk
+pointer sp, op, newexp
+bool done
+
+int locpr(), errcode()
+pointer evexpr()
+
+extern tbl_handler(), tbl_term(), tbl_func()
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (newexp, SZ_COMMAND, TY_CHAR)
+
+ # Convert Fortran relational operators to SPP
+
+ call ftnexpr (expr, Memc[newexp], SZ_COMMAND)
+
+ # Set up error handler to catch arithmetic errors
+
+ call xwhen (X_ARITH, locpr(tbl_handler), old_handler)
+
+ table = tp
+ nterm = 0
+ constant = false
+
+ tbl_term_adr = locpr (tbl_term)
+ tbl_func_adr = locpr (tbl_func)
+
+ found = 0
+ done = false
+
+ dir = sign (1, last - first)
+ do iary = first, last, dir {
+
+ irow = iary
+ iterm = 0
+
+ # Execution will resume here when an arithmetic error occurs
+
+ call zsvjmp (jumpbuf, status)
+
+ if (status != OK)
+ next
+
+ # Evaluate expression. Check if result is true
+
+ ifnoerr {
+ op = evexpr (Memc[newexp], tbl_term_adr, tbl_func_adr)
+ } then {
+
+ if (O_TYPE(op) != TY_BOOL) {
+ found = ERR
+ done = true
+ } else if (O_VALB(op)) {
+ found = irow
+ done = true
+ }
+ call xev_freeop (op)
+ call mfree (op, TY_STRUCT)
+
+ } else if (errcode() != PUTNULL) {
+ # Ignore errors caused by nulls
+ found = ERR
+ done = true
+ }
+ if (done)
+ break
+ }
+
+ # Restore old error handler
+
+ call xwhen (X_ARITH, old_handler, junk)
+ call sfree (sp)
+
+ return (found)
+end
diff --git a/pkg/utilities/nttools/lib/tblsort.x b/pkg/utilities/nttools/lib/tblsort.x
new file mode 100644
index 00000000..9af87bf6
--- /dev/null
+++ b/pkg/utilities/nttools/lib/tblsort.x
@@ -0,0 +1,39 @@
+# TBL_SORT -- Sort a table on selected table columns
+#
+# B.Simon 06-Fab-90 First Code
+
+procedure tbl_sort (ascend, casesens, tp, numptr, colptr, nindex, index)
+
+bool ascend # i: Sort in ascending order
+bool casesens # i: Sort is case sensitive
+pointer tp # i: Table descriptor
+int numptr # i: Number of columns to sort on
+pointer colptr[ARB] # i: Array of column descriptors
+int nindex # i: Number of elements in index array
+int index[ARB] # io: Array of row indices to sort
+#--
+bool fold
+int idx, jdx, temp
+
+begin
+ # Call the sort routine in the table library
+
+ fold = ! casesens
+ call tbtsrt (tp, numptr, colptr, fold, nindex, index)
+
+ # Reorder the index array if ascend is false
+
+ if (! ascend) {
+ idx = 1
+ jdx = nindex
+ while (idx < jdx) {
+ temp = index[idx]
+ index[idx] = index[jdx]
+ index[jdx] = temp
+ idx = idx + 1
+ jdx = jdx - 1
+ }
+ }
+
+
+end
diff --git a/pkg/utilities/nttools/lib/tblsort1.x b/pkg/utilities/nttools/lib/tblsort1.x
new file mode 100644
index 00000000..5d68751b
--- /dev/null
+++ b/pkg/utilities/nttools/lib/tblsort1.x
@@ -0,0 +1,157 @@
+include "reloperr.h"
+
+.help tbl_sort1
+.nf____________________________________________________________________________
+
+This file contains two routines that sort a table on a single column. Both
+routines put an existing array of row indices into sorted order. The first
+routine, tbl_sort1 has a simpler interface and is the routine to be used in
+a majority of cases. The second routine, tbl_qsort, requires that the calling
+routine read the table column into an array and handle null elements by
+itself. This routine should be used if the table column requires some
+special preprocessing before it can be sorted. One example of required
+preprocessing is conversion of dates from character strings to julian dates.
+Both routines use quick sort to sort the data. Quick is one of the fastest
+sorting routines, but it cannot be used to sort several table columns because
+it is not stable. This means that one sort destroys the ordering of a previous
+sort on a different column.
+
+.endhelp_______________________________________________________________________
+
+# TBL_SORT1 -- Sort a table on a single column
+#
+# This procedure rearranges an array of row indices into sorted order. The
+# order is from smallest to largest value if ascend is true, if ascend is
+# false, the order is from largest to smallest. In either case undefined
+# elements will be last in the array. For purposes of this routine boolean
+# false is considered to be less than true. If character strings are being
+# sorted, case can be ignored by setting casesens to false. The array of row
+# indices must be created before calling this procedure.
+#
+# B.Simon 16-Sept-87 First Code
+# B.Simon 15-Dec-87 Changed to handle table subsets
+
+procedure tbl_sort1 (ascend, casesens, tp, cp, nindex, index)
+
+bool ascend # i: Sort in ascending order
+bool casesens # i: Sort is case sensitive
+pointer tp # i: Table descriptor
+pointer cp # i: Column descriptor
+int nindex # io: Number of rows
+int index[ARB] # io: Array of row pointers in sorted order
+#--
+int dtype, spptype, lendata
+int nary, iary, nelem
+pointer idxptr, nulptr, aryptr, curptr
+
+int movenulls()
+
+begin
+ # Allocate storage for index array
+
+ call malloc (idxptr, nindex, TY_INT)
+
+ # Initialize the array of row indices
+
+ call amovi (index, Memi[idxptr], nindex)
+
+ # Read in the column of table values. Setting dtype to
+ # zero gets the actual data type of the column
+
+ dtype = 0
+ call gettabcol (tp, cp, dtype, nary, aryptr, nulptr)
+
+ if (dtype < 0) {
+ lendata = - dtype
+ spptype = TY_CHAR
+
+ if (! casesens) {
+ curptr = aryptr
+ do iary = 1, nary {
+ call strupr (Memc[curptr])
+ curptr = curptr + lendata + 1
+ }
+ }
+ } else {
+ lendata = 1
+ spptype = dtype
+ }
+
+ # Move all null elements to the end of the array
+
+ nelem = movenulls (nindex, Memb[nulptr], Memi[idxptr])
+
+ # Perform an indirect sort on the row indices using quicksort
+
+ call tbl_qsort (ascend, dtype, aryptr, nelem, idxptr)
+
+ # Move the row indices into the output array
+
+ call amovi (Memi[idxptr], index, nindex)
+
+ call mfree (idxptr, TY_INT)
+ call mfree (nulptr, TY_BOOL)
+ call mfree (aryptr, spptype)
+
+end
+
+# TBL_QSORT -- Indirect quick sort of a table column using an index array
+
+procedure tbl_qsort (ascend, dtype, aryptr, nelem, idxptr)
+
+bool ascend # i: Sort array in ascending order
+int dtype # i: Data type of array to be sorted
+pointer aryptr # i: Pointer to array to be sorted
+int nelem # i: Number of elements to be sorted
+pointer idxptr # o: Pointer to array of indices
+
+include "compare.com"
+
+int spptype
+
+extern compascb, compascd, compasci, compascr, compasct
+extern compdscb, compdscd, compdsci, compdscr, compdsct
+
+begin
+ dataptr = aryptr
+
+ # Convert the type to the SPP format
+
+ if (dtype < 0) {
+ lendata = - dtype
+ spptype = TY_CHAR
+ } else {
+ lendata = 1
+ spptype = dtype
+ }
+
+ # Call the quick sort procedure with the proper comparison routine
+
+ switch (spptype) {
+ case TY_BOOL:
+ if (ascend)
+ call qsort (Memi[idxptr], nelem, compascb)
+ else
+ call qsort (Memi[idxptr], nelem, compdscb)
+ case TY_CHAR:
+ if (ascend)
+ call qsort (Memi[idxptr], nelem, compasct)
+ else
+ call qsort (Memi[idxptr], nelem, compdsct)
+ case TY_SHORT,TY_INT,TY_LONG:
+ if (ascend)
+ call qsort (Memi[idxptr], nelem, compasci)
+ else
+ call qsort (Memi[idxptr], nelem, compdsci)
+ case TY_REAL:
+ if (ascend)
+ call qsort (Memi[idxptr], nelem, compascr)
+ else
+ call qsort (Memi[idxptr], nelem, compdscr)
+ case TY_DOUBLE:
+ if (ascend)
+ call qsort (Memi[idxptr], nelem, compascd)
+ else
+ call qsort (Memi[idxptr], nelem, compdscd)
+ }
+end
diff --git a/pkg/utilities/nttools/lib/tblsortm.x b/pkg/utilities/nttools/lib/tblsortm.x
new file mode 100644
index 00000000..1ece995d
--- /dev/null
+++ b/pkg/utilities/nttools/lib/tblsortm.x
@@ -0,0 +1,168 @@
+include "reloperr.h"
+
+.help tbl_sortm
+.nf____________________________________________________________________________
+
+This file contains two routines that sort a table on multiple columns. Both
+routines put an existing array of row indices into sorted order. The first
+routine, tbl_sortm has a simpler interface and is the routine to be used in
+a majority of cases. The second routine, tbl_msort, requires that the calling
+routine read the table column into an array and handle null elements by
+itself. This routine should be used if the table column requires some
+special preprocessing before it can be sorted. One example of required
+preprocessing is conversion of dates from character strings to julian dates.
+Both routines use merge sort to sort the data. Merge sort is fast, though not
+as fast as quick sort, and stable, so it can be used to sort on multiple
+columns. Its disadvantage is that it requires additional work space to run.
+
+.endhelp_______________________________________________________________________
+
+# TBL_SORTM -- Sort a table on multiple columns
+#
+# This procedure rearranges an array of row indices into sorted order. The
+# order is from smallest to largest value if ascend is true, if ascend is
+# false, the order is from largest to smallest. In either case undefined
+# elements will be last in the array. For purposes of this routine boolean
+# false is considered to be less than true. If character strings are being
+# sorted, case can be ignored by setting casesens to false. The array of row
+# indices must be created before calling this procedure.
+#
+# B.Simon 28-Sept-87 First Code
+# B.Simon 15-Dec-87 Changed to handle table subsets
+
+procedure tbl_sortm (ascend, casesens, tp, numptr, colptr, nindex, index)
+
+bool ascend # i: Sort in ascending order
+bool casesens # i: Sort is case sensitive
+pointer tp # i: Table descriptor
+int numptr # i: Number of columns to sort on
+pointer colptr[ARB] # i: Array of column descriptors
+int nindex # io: Number of rows
+int index[ARB] # io: Array of row indices in sorted order
+#--
+int dtype, spptype, lendata
+int iptr, nary, iary, nelem, nidx
+pointer cp, idxptr, nulptr, aryptr, curptr
+
+int movenulls()
+
+begin
+ # Allocate storage for index array
+
+ nidx = 2 * nindex
+ call malloc (idxptr, nidx, TY_INT)
+
+ # Initialize the array of row indices
+
+ call amovi (index, Memi[idxptr], nindex)
+
+ # Loop over all columns to be sorted
+
+ do iptr = numptr, 1, -1 {
+
+ cp = colptr(iptr)
+
+ # Read in the column of table values. Setting dtype to zero
+ # gets the actual column type.
+
+ dtype = 0
+ call gettabcol (tp, cp, dtype, nary, aryptr, nulptr)
+
+ if (dtype < 0) {
+ lendata = - dtype
+ spptype = TY_CHAR
+
+ if (! casesens) {
+ curptr = aryptr
+ do iary = 1, nary {
+ call strupr (Memc[curptr])
+ curptr = curptr + lendata + 1
+ }
+ }
+ } else {
+ lendata = 1
+ spptype = dtype
+ }
+
+ # Move all null elements to the end of the array
+
+ nelem = movenulls (nindex, Memb[nulptr], Memi[idxptr])
+
+ # Perform an indirect sort on the row indices using merge sort
+
+ call tbl_msort (ascend, dtype, aryptr, nelem, nidx, idxptr)
+
+ # Free memory used to hold table column and null flags
+
+ call mfree (aryptr, spptype)
+ call mfree (nulptr, TY_BOOL)
+ }
+
+ # Move the row indices into the output array
+
+ call amovi (Memi[idxptr], index, nindex)
+ call mfree (idxptr, TY_INT)
+
+end
+
+# TBL_MSORT -- Indirect merge sort of a table column using an index array
+
+procedure tbl_msort (ascend, dtype, aryptr, nelem, nidx, idxptr)
+
+bool ascend # i: Sort array in ascending order
+int dtype # i: Data type of array to be sorted
+pointer aryptr # i: Pointer to array to be sorted
+int nelem # i: Number of array elements to be sorted
+int nidx # i: Size of index array
+pointer idxptr # o: Pointer to array of indices
+
+include "compare.com"
+
+int spptype
+
+extern compascb, compascd, compasci, compascr, compasct
+extern compdscb, compdscd, compdsci, compdscr, compdsct
+
+begin
+ dataptr = aryptr
+
+ if (dtype < 0) {
+ lendata = - dtype
+ spptype = TY_CHAR
+ } else {
+ lendata = 1
+ spptype = dtype
+ }
+
+ # Convert the type to the SPP format
+
+ # Call the merge sort procedure with the proper comparison routine
+
+ switch (spptype) {
+ case TY_BOOL:
+ if (ascend)
+ call msort (Memi[idxptr], nidx, nelem, compascb)
+ else
+ call msort (Memi[idxptr], nidx, nelem, compdscb)
+ case TY_CHAR:
+ if (ascend)
+ call msort (Memi[idxptr], nidx, nelem, compasct)
+ else
+ call msort (Memi[idxptr], nidx, nelem, compdsct)
+ case TY_SHORT,TY_INT,TY_LONG:
+ if (ascend)
+ call msort (Memi[idxptr], nidx, nelem, compasci)
+ else
+ call msort (Memi[idxptr], nidx, nelem, compdsci)
+ case TY_REAL:
+ if (ascend)
+ call msort (Memi[idxptr], nidx, nelem, compascr)
+ else
+ call msort (Memi[idxptr], nidx, nelem, compdscr)
+ case TY_DOUBLE:
+ if (ascend)
+ call msort (Memi[idxptr], nidx, nelem, compascd)
+ else
+ call msort (Memi[idxptr], nidx, nelem, compdscd)
+ }
+end
diff --git a/pkg/utilities/nttools/lib/tblterm.com b/pkg/utilities/nttools/lib/tblterm.com
new file mode 100644
index 00000000..56d6c564
--- /dev/null
+++ b/pkg/utilities/nttools/lib/tblterm.com
@@ -0,0 +1,7 @@
+int jumpbuf[LEN_JUMPBUF]
+common /jmpcom/ jumpbuf
+
+bool constant
+int nterm, irow, iterm
+pointer table
+common /opcom/ constant, nterm, irow, iterm, table
diff --git a/pkg/utilities/nttools/lib/tblterm.x b/pkg/utilities/nttools/lib/tblterm.x
new file mode 100644
index 00000000..65904221
--- /dev/null
+++ b/pkg/utilities/nttools/lib/tblterm.x
@@ -0,0 +1,256 @@
+include <config.h>
+include <evexpr.h>
+include <tbset.h>
+include <xwhen.h>
+include "reloperr.h"
+
+define MAXTERM 64
+
+# TBL_TERM -- Return the value of the term in the expression
+#
+# B.Simon 13-Apr-88 Separated from tbl_eval
+
+procedure tbl_term (term, op)
+
+char term[ARB] # i: The name of the term
+pointer op # o: A structure holding the term value and type
+#--
+include "tblterm.com"
+
+bool isnull
+int datalen[MAXTERM], datatype[MAXTERM], dtype
+pointer colptr[MAXTERM]
+pointer sp, errtxt
+
+string badname "Column name not found (%s)"
+string badnum "Too many terms in expression"
+string nulvalue "Null found in table element"
+
+int tbcigi()
+
+errchk tbcfnd, tbcigi, tbegtb, tbegtt, tbegti, tbegtr
+
+begin
+ # Allocate storage for character strings
+
+ call smark (sp)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ constant = false
+ iterm = iterm + 1
+ if (iterm > MAXTERM)
+ call error (BOUNDS, badnum)
+
+ # If this is a new term, get its column pointer, type, and length
+
+ if (iterm > nterm) {
+ nterm = iterm
+ call tbcfnd (table, term, colptr[iterm], 1)
+
+ if (colptr[iterm] == NULL) {
+ call sprintf (Memc[errtxt], SZ_LINE, badname)
+ call pargstr (term)
+ call error (SYNTAX, Memc[errtxt])
+ }
+
+ dtype = tbcigi (colptr[iterm], TBL_COL_DATATYPE)
+ switch (dtype) {
+ case TY_BOOL:
+ datalen[iterm] = 0
+ datatype[iterm] = TY_BOOL
+ case TY_CHAR:
+ datalen[iterm] = 1
+ datatype[iterm] = TY_CHAR
+ case TY_SHORT,TY_INT,TY_LONG:
+ datalen[iterm] = 0
+ datatype[iterm] = TY_INT
+ case TY_REAL,TY_DOUBLE:
+ datalen[iterm] = 0
+ datatype[iterm] = TY_REAL
+ default:
+ datalen[iterm] = - dtype
+ datatype[iterm] = TY_CHAR
+ }
+ }
+
+ # Read the table to get the value of term
+
+ call xev_initop (op, datalen[iterm], datatype[iterm])
+
+ switch (datatype[iterm]) {
+ case TY_BOOL:
+ call tbegtb (table, colptr[iterm], irow, O_VALB(op))
+ isnull = false
+ case TY_CHAR:
+ call tbegtt (table, colptr[iterm], irow, O_VALC(op),
+ datalen[iterm])
+ isnull = O_VALC(op) == EOS
+ case TY_SHORT,TY_INT,TY_LONG:
+ call tbegti (table, colptr[iterm], irow, O_VALI(op))
+ isnull = IS_INDEFI (O_VALI(op))
+ case TY_REAL,TY_DOUBLE:
+ call tbegtr (table, colptr[iterm], irow, O_VALR(op))
+ isnull = IS_INDEFR (O_VALR(op))
+ }
+
+ # Error exit if table element is null
+
+ if (isnull)
+ call error (PUTNULL, nulvalue)
+
+ call sfree (sp)
+end
+
+# TBL_FUNC -- Return the value of a nonstandard function in the expression
+
+procedure tbl_func (func_name, arg_ptr, nargs, op)
+
+char func_name[ARB] # i: String containing function name
+pointer arg_ptr[ARB] # i: Pointers to function arguments
+int nargs # i: Number of function arguments
+pointer op # o: Pointer to output structure
+#--
+include "tblterm.com"
+
+bool valflag
+int type, iarg
+pointer sp, errtxt
+
+string badtyp "Invalid argument type in %s"
+string badarg "Incorrect number of arguments for %s"
+string badfun "Unknown function named %s"
+
+bool streq()
+double mjd()
+
+errchk mjd()
+
+begin
+ # Allocate storage for character strings
+
+ call smark (sp)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ # Call appropriate function according to name
+
+ if (streq (func_name, "row")) {
+
+ # Table row number function: row()
+
+ constant = false
+ if (nargs != 0) {
+ call sprintf (Memc[errtxt], SZ_LINE, badarg)
+ call pargstr (func_name)
+ call error (SYNTAX, Memc[errtxt])
+ }
+ call xev_initop (op, 0, TY_INT)
+ O_VALI(op) = irow
+
+ } else if (streq (func_name, "delta")) {
+
+ # Difference between two Julian dates: mjd(date1) - mjd(date2)
+
+ if (nargs != 2) {
+ call sprintf (Memc[errtxt], SZ_LINE, badarg)
+ call pargstr (func_name)
+ call error (SYNTAX, Memc[errtxt])
+ }
+ if (O_TYPE(arg_ptr[1]) != TY_CHAR ||
+ O_TYPE(arg_ptr[2]) != TY_CHAR ) {
+ call sprintf (Memc[errtxt], SZ_LINE, badtyp)
+ call pargstr (func_name)
+ call error (SYNTAX, Memc[errtxt])
+ }
+ call xev_initop (op, 0, TY_REAL)
+ O_VALR(op) = mjd (O_VALC(arg_ptr[1])) - mjd (O_VALC(arg_ptr[2]))
+
+ } else if (streq (func_name, "match")) {
+ if (nargs < 2) {
+ call sprintf (Memc[errtxt], SZ_LINE, badarg)
+ call pargstr (func_name)
+ call error (SYNTAX, Memc[errtxt])
+ }
+
+ type = O_TYPE(arg_ptr[1])
+ do iarg = 2, nargs {
+ if (type != O_TYPE(arg_ptr[iarg])) {
+ call sprintf (Memc[errtxt], SZ_LINE, badtyp)
+ call pargstr (func_name)
+ call error (SYNTAX, Memc[errtxt])
+ }
+ }
+
+ valflag = false
+ call xev_initop (op, 0, TY_BOOL)
+
+ switch (type) {
+ case TY_BOOL:
+ if (O_VALB(arg_ptr[1])) {
+ do iarg = 2, nargs {
+ if (O_VALB(arg_ptr[iarg])) {
+ valflag = true
+ break
+ }
+ }
+ } else {
+ do iarg = 2, nargs {
+ if (! O_VALB(arg_ptr[iarg])) {
+ valflag = true
+ break
+ }
+ }
+ }
+ case TY_CHAR:
+ do iarg = 2, nargs {
+ if (streq (O_VALC(arg_ptr[1]), O_VALC(arg_ptr[iarg]))) {
+ valflag = true
+ break
+ }
+ }
+ case TY_SHORT,TY_INT,TY_LONG:
+ do iarg = 2, nargs {
+ if (O_VALI(arg_ptr[1]) == O_VALI(arg_ptr[iarg])) {
+ valflag = true
+ break
+ }
+ }
+ case TY_REAL:
+ do iarg = 2, nargs {
+ if (O_VALR(arg_ptr[1]) == O_VALR(arg_ptr[iarg])) {
+ valflag = true
+ break
+ }
+ }
+ }
+ O_VALB(op) = valflag
+
+ } else {
+
+ call sprintf (Memc[errtxt], SZ_LINE, badfun)
+ call pargstr (func_name)
+ call error (SYNTAX, Memc[errtxt])
+
+ }
+
+ call sfree (sp)
+end
+
+# TBL_HANDLER -- Error handler to catch arithmetic errors
+
+procedure tbl_handler (code, nxt_handler)
+
+int code # i: error code which trigerred this exception
+int nxt_handler # o: handler called after this handler exits
+#--
+include "tblterm.com"
+
+bool junk
+bool xerpop()
+
+begin
+ # Resume execution at zsvjmp
+
+ nxt_handler = X_IGNORE
+ junk = xerpop()
+ call zdojmp (jumpbuf, code)
+end
diff --git a/pkg/utilities/nttools/lib/tctexp.x b/pkg/utilities/nttools/lib/tctexp.x
new file mode 100644
index 00000000..263b18bc
--- /dev/null
+++ b/pkg/utilities/nttools/lib/tctexp.x
@@ -0,0 +1,442 @@
+include <tbset.h>
+include <ctype.h>
+include "reloperr.h"
+
+define MAX_STACK 8
+define BLANK ' '
+define DELIM ','
+define ESCAPE '\\'
+define NEGCHAR '~' # negation character
+define ALT_NEGCHAR '!' # alternate negation character
+
+.help tctexp
+.nf___________________________________________________________________________
+Column template package
+
+This package contains subroutines to expand a column name template into
+an array of column pointers which match the template. The template is a
+list of column patterns separated by commas or whitespace. The column
+pattern is either a column name, a file name containing a list of column
+names, or a pattern using the usual IRAF pattern matching syntax. For
+example, the string
+
+ a[1-9], b, time*, @column.lis
+
+would be expanded as the column names a1 through a9, b, any column name
+beginning with "time", and all the column names in the file column.lis.
+If the column template is entirely whitespace, the array of column pointers
+will include all the columns in the table, as this seems the most reasonable
+default. If the first non-white character is the negation character (~),
+the array of column pointers will include all columns not matched by the
+template. The negation character only has this meaning as the first character
+in the column template, and is interpreted as part of a column name if
+found later in the template or in a file.
+
+.endhelp______________________________________________________________________
+
+# TCTEXP -- Expand a column template into an array of column pointers
+#
+# Given a table pointed to by a table descriptor and a column name template,
+# return an array of column pointers. The size of the column pointer array
+# is given by numcol and should be greater than or equal to the number of
+# columns in the table. The actual number of columns found that match the
+# template is returned as numptr.
+#
+# B.Simon 24-Jul-1987 First Code
+# Phil Hodge 1-Jun-1989 make search for columns case insensitive
+# Phil Hodge 28-Jan-1999 add ! as an alternate negation character
+
+procedure tctexp (tp, template, numcol, numptr, colptr)
+
+pointer tp # i: pointer to table descriptor
+char template[ARB] # i: column template
+int numcol # i: size of column pointer array
+int numptr # o: number of columns matched
+pointer colptr[ARB] # o: array of column pointers
+#--
+
+bool nometa # true if pattern does not contain metacharacters
+bool negate # true if template starts with negation character
+
+int fd_ptr # pointer to stack of open list file descriptors
+int ic # first non-white character in template
+
+pointer fd_stack[MAX_STACK]
+ # stack of file descriptors for open list files
+
+pointer sp, colpat, pattern, auxcol, fd
+
+string stkovflerr "List files are nested too deeply, stack overflow"
+
+int strlen(), tctgetpat()
+pointer stropen(), open()
+
+errchk salloc, stropen, open, close
+errchk tctgetpat, tctmakpat, tctstrmatch, tctpatmatch
+
+begin
+ numptr = 0
+ negate = false
+
+ call smark (sp)
+ call salloc (colpat, SZ_FNAME, TY_CHAR)
+ call salloc (pattern, SZ_FNAME, TY_CHAR)
+
+ # Check the column name template to find the first non-white character.
+
+ for (ic = 1; IS_WHITE (template[ic]); ic = ic + 1)
+ ;
+
+ if (template[ic] == EOS) {
+
+ # If the template is blank, include all columns in the array
+
+ call allcolumns (tp, numptr, auxcol)
+ call amovi (Memi[auxcol], colptr, numptr)
+ call mfree (auxcol, TY_INT)
+ fd_ptr = 0
+
+ } else {
+
+ # If the first non-white character is the negation character
+ # (either ~ or !), the meaning of the column name template is
+ # negated, that is, the array of column pointers will include
+ # those columns whose names were not matched by the column template
+
+ if (template[ic] == NEGCHAR || template[ic] == ALT_NEGCHAR) {
+ negate = true
+ ic = ic + 1
+ }
+
+ # Open the column name template as a file and push on
+ # the list file stack
+
+ fd_ptr = 1
+ fd_stack[1] =
+ stropen (template[ic], strlen(template[ic]), READ_ONLY)
+
+ }
+
+ while (fd_ptr > 0) {
+
+ # Pop file descriptor off of the list file stack
+
+ fd = fd_stack[fd_ptr]
+ fd_ptr = fd_ptr - 1
+
+ # Loop over all column patterns in the file
+
+ while (tctgetpat (fd, Memc[colpat], SZ_FNAME) > 0) {
+
+ if (Memc[colpat] == '@') {
+
+ # If this pattern is a list file name, push the
+ # current descriptor on the stack and open the file
+
+ if (fd_ptr == MAX_STACK)
+ call error (BOUNDS, stkovflerr)
+ fd_ptr = fd_ptr + 1
+ fd_stack[fd_ptr] = fd
+ fd = open (Memc[colpat+1], READ_ONLY, TEXT_FILE)
+
+ } else {
+
+ # Otherwise, encode the pattern and search the table
+ # for matching column names. To speed the search, use
+ # a special routine if the pattern does not include
+ # metacharacters
+
+ call strlwr (Memc[colpat]) # for case insensitivity
+ call tctmakpat (Memc[colpat], Memc[pattern], SZ_FNAME,
+ nometa)
+ if (nometa)
+ call tctstrmatch (tp, Memc[pattern], numcol,
+ numptr, colptr)
+ else
+ call tctpatmatch (tp, Memc[pattern], numcol,
+ numptr, colptr)
+ }
+ }
+ call close (fd)
+ }
+
+ if (negate)
+ call invert (tp, numptr, colptr)
+
+ call sfree (sp)
+end
+
+# TCTGETPAT -- Get next comma or whitespace delimeted pattern from file
+#
+# Copy characters into colpat until a field delimeter or the maximum number of
+# characters is reached. The number of characters in colpat is returned as the
+# value of the function, so the procedure which calls this one can test for
+# the last field in the template.
+#
+# B. Simon 24-Jul-87 First Code
+
+int procedure tctgetpat (fd, colpat, maxch)
+
+pointer fd # i: template file descriptor
+char colpat[ARB] # o: pattern from column name template
+int maxch # i: maximum number of characters in field
+#--
+char ch # next character from template
+int iq # pointer to character in colpat
+
+char getc()
+
+begin
+ # Skip leading whitespace or commas
+
+ ch = getc (fd, ch)
+ while (IS_CNTRL(ch) || ch == BLANK || ch == DELIM)
+ ch = getc (fd, ch)
+
+ # Copy characters to colpat. End when maxch is reached, or
+ # when comma, whitespace, or EOF is found
+
+ for (iq = 1; iq <= maxch; iq = iq + 1) {
+
+ if (IS_CNTRL(ch) || ch == BLANK || ch == DELIM || ch == EOF)
+ break
+
+ colpat[iq] = ch
+ ch = getc (fd, ch)
+ }
+ colpat[iq] = EOS
+
+ # If loop is terminated because of maxch, eat remaining characters
+ # in field
+
+ while (! IS_CNTRL(ch) && ch != BLANK && ch != DELIM && ch != EOF)
+ ch = getc (fd, ch)
+
+ # Return number of characters in colpat
+
+ return (iq-1)
+end
+
+# TCTMAKPAT -- Encode the column pattern
+#
+# Create the pattern used by the matching routines. Check for metacharacters
+# (unescaped pattern matching characters) to see if the faster constant
+# pattern routine can be used.
+#
+# B.Simon 24-Jul-87 First Code
+
+procedure tctmakpat (colpat, pattern, maxch, nometa)
+
+char colpat[ARB] # i: Column pattern string
+char pattern[ARB] # o: Encoded pattern string
+int maxch # i: Maximum length of encoded pattern string
+bool nometa # o: True if no metacharacters in string
+#--
+int ic, ip
+pointer sp, buffer, buffer2, errtxt, ib
+
+int stridx(), strlen(), patmake()
+
+string patovflerr "Column pattern too long (%s)"
+string badpaterr "Column pattern has bad syntax (%s)"
+
+begin
+ call smark (sp)
+ call salloc (buffer, maxch, TY_CHAR)
+ call salloc (buffer2, maxch, TY_CHAR)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ nometa = true
+ ib = buffer
+
+ # Copy the column pattern to a temporary buffer
+
+ for (ic = 1; colpat[ic] != EOS ; ic = ic + 1) {
+
+ # Copy escape sequences, but do not count as metacharacters
+
+ if (colpat[ic] == ESCAPE && colpat[ic+1] != EOS) {
+ Memc[ib] = ESCAPE
+ ib = ib + 1
+ ic = ic + 1
+
+ # Covert '*' to '?*', count as a metacharacter
+
+ } else if (colpat[ic] == '*') {
+ nometa = false
+ Memc[ib] = '?'
+ ib = ib + 1
+
+ # Check for the other metacharacters
+
+ } else if (stridx (colpat[ic], "[?{") > 0)
+ nometa = false
+
+ Memc[ib] = colpat[ic]
+ ib = ib + 1
+ }
+ Memc[ib] = EOS
+
+ # Check the buffer length against maximum pattern length
+
+ if (strlen (Memc[buffer]) > maxch) {
+ call sprintf (Memc[errtxt], SZ_LINE, patovflerr)
+ call pargstr (colpat)
+ call error (BOUNDS, Memc[errtxt])
+ }
+
+ # If no metacharacters, strip escape sequences
+
+ if (nometa) {
+ ip = 1
+ for (ib = buffer; Memc[ib] != EOS; ib = ib + 1) {
+ if (Memc[ib] == ESCAPE && Memc[ib+1] != EOS)
+ ib = ib + 1
+ pattern[ip] = Memc[ib]
+ ip = ip + 1
+ }
+ pattern[ip] = EOS
+
+ # Otherwise, encode with patmake
+
+ } else {
+ call sprintf (Memc[buffer2], maxch, "^%s$")
+ call pargstr (Memc[buffer])
+
+ if (patmake (Memc[buffer2], pattern, SZ_LINE) == ERR) {
+ call sprintf (Memc[errtxt], SZ_LINE, badpaterr)
+ call pargstr (colpat)
+ call error (SYNTAX, Memc[errtxt])
+ }
+ }
+
+ call sfree (sp)
+end
+
+# TCTSTRMATCH -- Add a column pointer for a column name to the array
+#
+# Used to match column names when the column pattern contains no
+# metacharacters.
+#
+# B. Simon 24-Jul-87 First Code
+
+procedure tctstrmatch (tp, pattern, numcol, numptr, colptr)
+
+pointer tp # i: pointer to table descriptor
+char pattern[ARB] # i: column pattern
+int numcol # i: size of column pointer array
+int numptr # o: number of columns matched
+pointer colptr[ARB] # o: array of column pointers
+#--
+int iptr
+pointer sp, errtxt, cp
+
+string maxcolerr "Maximum number of columns in table exceeded (%d)"
+
+errchk tbcfnd
+
+begin
+ call smark (sp)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ # Find the column pointer corresponding to the column name
+
+ call tbcfnd (tp, pattern, cp, 1)
+
+ # Pointer is null if column not found in table
+
+ if (cp == NULL)
+ return
+
+ # See if the column name has already been matched
+
+ for (iptr = 1; iptr <= numptr; iptr = iptr +1) {
+ if (cp == colptr[iptr])
+ break
+ }
+
+ # If not, add its pointer in the array of pointers
+ # after checking for array overflow
+
+ if (iptr > numptr) {
+ if (numptr >= numcol) {
+ call sprintf (Memc[errtxt], SZ_LINE, maxcolerr)
+ call pargi (numcol)
+ call error (BOUNDS, Memc[errtxt])
+ }
+ numptr = numptr + 1
+ colptr[numptr] = cp
+ }
+
+ call sfree (sp)
+end
+
+# TCTPATMATCH -- Find column pointers for columns matching a pattern
+#
+# This routine is called when the column pattern contains metacharacters.
+#
+# B.Simon 27-Jul-87 First Code
+
+procedure tctpatmatch (tp, pattern, numcol, numptr, colptr)
+
+pointer tp # i: pointer to table descriptor
+char pattern[ARB] # i: column pattern
+int numcol # i: size of column pointer array
+int numptr # o: number of columns matched
+pointer colptr[ARB] # o: array of column pointers
+#--
+int maxcol, icol, iptr
+pointer sp, errtxt, cp
+pointer colname
+
+string maxcolerr "Maximum number of columns in table exceeded (%d)"
+
+int tbpsta(), tbcnum(), patmatch()
+
+errchk tbpsta, tbcnum, tbcinf, patmatch
+
+begin
+ call smark (sp)
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ maxcol = tbpsta (tp, TBL_NCOLS)
+
+ # Compare the column pattern to each column name in the table
+
+ do icol = 1, maxcol {
+
+ # Get the next column name in the table
+
+ cp = tbcnum (tp, icol)
+ call tbcigt (cp, TBL_COL_NAME, Memc[colname], SZ_COLNAME)
+ call strlwr (Memc[colname]) # for case insensitivity
+
+ # Check the column name for a match
+
+ if (patmatch (Memc[colname], pattern) > 0) {
+ # See if the column name has already been matched
+
+ for (iptr = 1; iptr <= numptr; iptr = iptr +1) {
+ if (cp == colptr[iptr])
+ break
+ }
+
+ # If not, add its pointer in the array of pointers
+ # after checking for array overflow
+
+ if (iptr > numptr) {
+ if (numptr >= numcol) {
+ call sprintf (Memc[errtxt], SZ_LINE, maxcolerr)
+ call pargi (numcol)
+ call error (BOUNDS, Memc[errtxt])
+ }
+ numptr = numptr + 1
+ colptr[numptr] = cp
+ }
+ }
+ }
+
+ call sfree (sp)
+
+end
diff --git a/pkg/utilities/nttools/lib/tldtype.x b/pkg/utilities/nttools/lib/tldtype.x
new file mode 100644
index 00000000..52e35960
--- /dev/null
+++ b/pkg/utilities/nttools/lib/tldtype.x
@@ -0,0 +1,70 @@
+define T_MAXDIM 7 # maximum dimension of array
+
+# tl_dtype -- data type and array size
+# Convert integer data type code to a character string. If the column
+# contains arrays, append the length of each axis, e.g. R[25,75].
+#
+# Phil Hodge, 9-Dec-1994 Moved from tlcol.x to ttools$lib/.
+# Phil Hodge, 19-Jul-1995 Add tp to calling sequence (needed for tbciga).
+
+procedure tl_dtype (tp, cp, datatype, nelem, chartyp, maxch)
+
+pointer tp # i: pointer to table descriptor
+pointer cp # i: pointer to column descriptor
+int datatype # i: integer code for data type
+int nelem # i: total array size
+char chartyp[maxch] # o: data type, possibly with array size
+int maxch # i: maximum size of chartyp string
+#--
+int nchar # number of characters
+int i # loop index
+int ndim # dimension of array
+int axlen[T_MAXDIM] # length of each axis
+int ip, itoc()
+int strlen()
+errchk tbciga
+
+begin
+ if (datatype > 0) { # numeric or Boolean
+
+ switch (datatype) {
+ case TY_REAL:
+ call strcpy ("R", chartyp, maxch)
+ case TY_DOUBLE:
+ call strcpy ("D", chartyp, maxch)
+ case TY_INT:
+ call strcpy ("I", chartyp, maxch)
+ case TY_SHORT:
+ call strcpy ("S", chartyp, maxch)
+ case TY_BOOL:
+ call strcpy ("B", chartyp, maxch)
+ default:
+ call error (1, "bad data type in table")
+ }
+
+ } else { # < 0 ==> char string
+
+ nchar = -datatype # length of string
+ call sprintf (chartyp, maxch, "CH*%d")
+ call pargi (nchar)
+ }
+
+ if (nelem > 1) {
+
+ # Get the dimension of array and size of each axis.
+ call tbciga (tp, cp, ndim, axlen, T_MAXDIM)
+
+ call strcat ("[", chartyp, maxch)
+
+ ip = strlen (chartyp) + 1 # points to EOS
+
+ do i = 1, ndim-1 {
+ nchar = itoc (axlen[i], chartyp[ip], maxch-ip+1)
+ call strcat (",", chartyp, maxch)
+ ip = ip + nchar + 1
+ }
+
+ nchar = itoc (axlen[ndim], chartyp[ip], maxch-ip+1)
+ call strcat ("]", chartyp, maxch)
+ }
+end
diff --git a/pkg/utilities/nttools/lib/tuopen.x b/pkg/utilities/nttools/lib/tuopen.x
new file mode 100644
index 00000000..7434a72b
--- /dev/null
+++ b/pkg/utilities/nttools/lib/tuopen.x
@@ -0,0 +1,197 @@
+# This file contains tu_open and tu_close, which are used to open
+# and close a temporary table.
+#
+# Phil Hodge, 28-Jun-1995 Subroutines created based on Bernie's tedit code.
+# Phil hodge, 16-Apr-1999 Remove ttype from calling sequence of tbparse.
+
+# tu_open -- open a temporary table
+# If the table is to be opened in-place, then it's just opened.
+# Otherwise, a copy of the table is made, and that table is opened
+# read-write. The name of the original table will be returned as
+# 'tabname' so it can be passed to tu_close, which needs the name of
+# the original file. If the filename extension is ".tab", then 'table'
+# might not include the extension. This is the reason we need a
+# separate output argument 'tabname'. Note, however, that text tables
+# need not have an extension. If 'table' does not include an extension,
+# and a file of that name exists, then ".tab" will not be appended when
+# copying to 'tabname'. 'tabname' can differ from the actual file name
+# by including a name or number in brackets after the file name.
+#
+# Note that it is an error if readonly=true but inplace=false.
+
+procedure tu_open (table, root, readonly, inplace, tp, tabname, maxch)
+
+char table[ARB] # i: name of table
+char root[ARB] # i: beginning of name for scratch file
+bool readonly # i: true if the table is to be opened read-only
+bool inplace # i: true if the table is to be opened in-place
+pointer tp # o: pointer to table struct
+char tabname[maxch] # o: full name of original table (incl extension, etc)
+int maxch # i: size of filename string
+#--
+pointer sp
+pointer temp # name of temporary table
+pointer tname, fname # full table and file names
+pointer extn # file extension, or EOS
+pointer tempdir # name of directory for temporary copy
+pointer errmess # scratch for error message
+int tlen, flen # length of table and file names
+int try # loop index
+int junk, fnldir()
+pointer tbtopn()
+int strlen()
+errchk tbtopn, tbtnam, tbfile, fcopy
+
+begin
+ if (readonly && !inplace)
+ call error (1, "readonly = yes, but inplace = no")
+
+ if (inplace) {
+
+ if (readonly) {
+ tp = tbtopn (table, READ_ONLY, NULL)
+ } else {
+ tp = tbtopn (table, READ_WRITE, NULL)
+ }
+
+ call tbtnam (tp, tabname, maxch) # get the full table name
+
+ } else {
+
+ call smark (sp)
+ call salloc (temp, SZ_LINE, TY_CHAR)
+ call salloc (tname, SZ_LINE, TY_CHAR)
+ call salloc (fname, SZ_LINE, TY_CHAR)
+ call salloc (extn, SZ_LINE, TY_CHAR)
+ call salloc (tempdir, SZ_LINE, TY_CHAR)
+
+ # Get the full table name, full file name, and extension (if any)
+ # of the original file. Copy the table name to output.
+ call tbfile (table, Memc[tname], Memc[fname], Memc[extn], SZ_LINE)
+ call strcpy (Memc[tname], tabname, maxch)
+
+ # Get the name of the directory containing the original file.
+ junk = fnldir (Memc[fname], Memc[tempdir], SZ_LINE)
+
+ # Copy the original file to a temporary file. First try to
+ # make the copy in the directory containing the original file.
+ # If that fails then copy the file to tmp$.
+ do try = 1, 2 {
+
+ # Construct the name of a temporary file by concatenating
+ # the directory, root, a random number, and the extension
+ # of the original file name.
+ call strcat (root, Memc[tempdir], SZ_LINE)
+ call mktemp (Memc[tempdir], Memc[temp], SZ_LINE)
+ call strcat (Memc[extn], Memc[temp], SZ_LINE)
+
+ # Copy the file.
+ ifnoerr (call fcopy (Memc[fname], Memc[temp]))
+ break
+
+ if (try == 1) {
+ # The first try failed. Copy the file to tmp$.
+ call strcpy ("tmp$", Memc[tempdir], SZ_LINE)
+ } else {
+ # The second try failed as well.
+ call salloc (errmess, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[errmess], SZ_LINE,
+ "unable to make a temporary copy of %s")
+ call pargstr (Memc[fname])
+ call error (1, Memc[errmess])
+ }
+ }
+
+ # If there was a bracketed expression (e.g. EXTNAME) in the
+ # input table name, append it to the name of the temp file
+ # to convert the file name to a complete table name.
+ tlen = strlen (Memc[tname])
+ flen = strlen (Memc[fname])
+ if (tlen > flen)
+ call strcat (Memc[tname+flen], Memc[temp], SZ_LINE)
+
+ tp = tbtopn (Memc[temp], READ_WRITE, NULL)
+
+ call sfree (sp)
+ }
+end
+
+# tu_close -- close a temporary table
+# This routine first closes the table that was edited. If it was opened
+# inplace, then we have nothing further to do. Otherwise, we were editing
+# a temporary copy of the original. If the command was to quit without
+# saving changes, we delete the temporary file. If the command was to
+# exit, saving changes, we rename the copy back to the original.
+# The quit and tabname arguments will be ignored if inplace is true.
+
+procedure tu_close (tp, inplace, quit, tabname)
+
+pointer tp # i: pointer to table struct for edited table
+bool inplace # i: true if the table was edited inplace
+bool quit # i: true if we should quit without saving changes
+char tabname[ARB] # i: name of original table (not temp copy)
+#--
+pointer sp
+pointer temp # name of temporary file
+pointer tname # name of temporary table
+pointer filename # name of original file
+pointer cdfname # scratch
+pointer errmess # for error message
+int hdu # ignored
+int junk
+int errget()
+int tbparse()
+errchk tbparse, delete, rename
+
+begin
+ if (tp == NULL)
+ return
+
+ call smark (sp)
+ call salloc (tname, SZ_LINE, TY_CHAR)
+
+ # Get the name of the table that we edited, then close it.
+ call tbtnam (tp, Memc[tname], SZ_LINE)
+ call tbtclo (tp)
+
+ if (!inplace) {
+
+ call salloc (temp, SZ_LINE, TY_CHAR)
+ call salloc (filename, SZ_LINE, TY_CHAR)
+ call salloc (cdfname, SZ_LINE, TY_CHAR)
+
+ # Strip off brackets (if present) to get the file name
+ # for the table that we edited.
+ junk = tbparse (Memc[tname], Memc[temp],
+ Memc[cdfname], SZ_LINE, hdu)
+
+ # Strip off brackets (if present) to get the file name
+ # of the original table.
+ junk = tbparse (tabname, Memc[filename],
+ Memc[cdfname], SZ_LINE, hdu)
+
+ if (quit) {
+
+ call delete (Memc[temp]) # delete temp copy
+
+ } else {
+
+ iferr {
+ call delete (Memc[filename]) # delete original file
+ call rename (Memc[temp], Memc[filename])
+ } then {
+ call salloc (errmess, SZ_LINE, TY_CHAR)
+ junk = errget (Memc[errmess], SZ_LINE)
+ call eprintf ("%s\n")
+ call pargstr (Memc[errmess])
+ call sprintf (Memc[errmess], SZ_LINE,
+ "couldn't rename edited file %s to original %s\n")
+ call pargstr (Memc[temp])
+ call pargstr (Memc[filename])
+ call error (1, Memc[errmess])
+ }
+ }
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/lib/unique.x b/pkg/utilities/nttools/lib/unique.x
new file mode 100644
index 00000000..ca54f840
--- /dev/null
+++ b/pkg/utilities/nttools/lib/unique.x
@@ -0,0 +1,64 @@
+# UNIQUE -- Find unique rows in a table
+#
+# First, the table is sorted on columns input in the colptr array. The
+# results are stored in the index array. Then each row in the index array
+# is compared to the most recent unique row in the index array, column by
+# column. If any column differs, the row is also considered to be unique.
+# The index array is updated to reflect the new unique row and the number of
+# unique rows is incremented.
+#
+# B.Simon 19-Oct-87 First Code
+# B.Simon 14-Dec-87 Changed to handle table subsets
+# B.Simon 06-Feb-90 Changed to use tbtsrt and tbrcmp
+
+procedure unique (tp, numptr, colptr, nindex, index)
+
+pointer tp # i: Table descriptor
+int numptr # i: Number of column pointers
+pointer colptr[ARB] # i: Array of column pointers
+int nindex # io: Number of unique row indices returned
+int index[ARB] # io: Array of unique indices
+#--
+bool fold
+int order, idx, jdx, n, i
+
+int tbrcmp()
+
+begin
+
+ # Sort the array on the selected columns. The sort is in ascending
+ # order and case sensitive
+
+ fold = false
+ call tbtsrt (tp, numptr, colptr, fold, nindex, index)
+
+ # Search for unique rows
+
+ jdx = 0
+ n = nindex
+ nindex = 0
+
+ do i = 1, n {
+ idx = index[i]
+
+ # First row is always unique
+
+ if (i == 1)
+ order = 1
+ else
+ order = tbrcmp (tp, numptr, colptr, fold, idx, jdx)
+
+ # Update pointer to most recent unique row and modify index
+ # array in place
+
+ if (order != 0) {
+ jdx = idx
+ nindex = nindex + 1
+ index[nindex] = idx
+ }
+ }
+
+ do i = nindex+1, n
+ index[i] = 0
+
+end
diff --git a/pkg/utilities/nttools/mkpkg b/pkg/utilities/nttools/mkpkg
new file mode 100644
index 00000000..abd34f79
--- /dev/null
+++ b/pkg/utilities/nttools/mkpkg
@@ -0,0 +1,80 @@
+# Make the nttools package
+# Author: CDBS, 23-NOV-1987
+# to include copyone,keyselect,lib,tcalc,tchsize,tcopy,tcreate,tedit,
+# tinfo,tjoin,tmerge,tprint,tproduct,tproject,tselect,tsort,tupar,
+# tintegrate application(s)
+# 03-Jun-97 3-D table translators (I. Busko)
+#
+# Special keywords recognized by IRAF mkpkg files:
+#
+# mkpkg relink update object library and link
+# mkpkg linkonly skip object library updates and just link
+# mkpkg install move executable to lib$
+# mkpkg update update object library, link, and move to lib$
+
+$call relink
+$exit
+
+update:
+ $call relink
+ $call install
+ ;
+
+debug:
+ $set XFLAGS = "-fgq $(XFLAGS)"
+ $call relink
+ ;
+
+relink:
+ $update libpkg.a
+ $call nttools
+ ;
+
+install:
+ $move xx_nttools.e bin$x_nttools.e
+ ;
+
+nttools:
+linkonly:
+ $omake x_nttools.x
+ $link x_nttools.o libpkg.a -lxtools -ltbtables -o xx_nttools.e
+ ;
+
+libpkg.a:
+ @threed
+ @stxtools
+
+ @atools
+ @copyone
+ @gtedit
+ @imtab
+ @keyselect
+ @lib
+ @tcalc
+ @tchcol
+ @tchsize
+ @tcheck
+ @tcopy
+ @tcreate
+ @tdiffer
+ @tedit
+ @texpand
+ @thedit
+ @tinfo
+ @tintegrate
+ @tjoin
+ @tlinear
+ @tmatch
+ @tmerge
+ @tprint
+ @tproduct
+ @tproject
+ @tquery
+ @trebin
+ @tselect
+ @tsort
+ @tstat
+ @ttranspose
+ @tunits
+ @tupar
+ ;
diff --git a/pkg/utilities/nttools/nttools.cl b/pkg/utilities/nttools/nttools.cl
new file mode 100644
index 00000000..4b669406
--- /dev/null
+++ b/pkg/utilities/nttools/nttools.cl
@@ -0,0 +1,60 @@
+procedure nttools()
+string mode="al"
+
+begin
+ package nttools
+ task gtedit,
+ imtab,
+ keypar,
+ keytab,
+ parkey,
+ partab,
+ tabim,
+ tabkey,
+ tabpar,
+ taextract,
+ tainsert,
+ tcalc,
+ tchcol,
+ tcheck,
+ tchsize,
+ tcopy,
+ tcreate,
+ tdelete,
+ tdiffer,
+ tdump,
+ tedit,
+ texpand,
+ thedit,
+ thistogram,
+ thselect,
+ tinfo,
+ tintegrate,
+ tjoin,
+ tlcol,
+ tlinear,
+ tmatch,
+ tmerge,
+ tprint,
+ tproduct,
+ tproject,
+ tquery,
+ tread,
+ trebin,
+ tselect,
+ tsort,
+ tstat,
+ ttranspose,
+ tunits,
+ tupar = "nttools$x_nttools.e"
+
+ task gtpar = "nttools$gtpar.par"
+
+ task txtable,
+ tximage,
+ titable,
+ tiimage,
+ tscopy = "nttools$threed/x_nttools.e"
+
+ clbye()
+end
diff --git a/pkg/utilities/nttools/nttools.hd b/pkg/utilities/nttools/nttools.hd
new file mode 100644
index 00000000..91010db4
--- /dev/null
+++ b/pkg/utilities/nttools/nttools.hd
@@ -0,0 +1,91 @@
+# Help directory for the TTOOLS package
+
+$doc = "pkg$utilities/nttools/doc/"
+$tdoc = "pkg$utilities/nttools/threed/doc/"
+$atools = "pkg$utilities/nttools/atools/"
+$copyone = "pkg$utilities/nttools/copyone/"
+$gtedit = "pkg$utilities/nttools/gtedit/"
+$imtab = "pkg$utilities/nttools/imtab/"
+$tcalc = "pkg$utilities/nttools/tcalc/"
+$tchcol = "pkg$utilities/nttools/tchcol/"
+$tcheck = "pkg$utilities/nttools/tcheck/"
+$tchsize = "pkg$utilities/nttools/tchsize/"
+$tcopy = "pkg$utilities/nttools/tcopy/"
+$tcreate = "pkg$utilities/nttools/tcreate/"
+$tdiffer = "pkg$utilities/nttools/tdiffer/"
+$tedit = "pkg$utilities/nttools/tedit/"
+$texpand = "pkg$utilities/nttools/texpand/"
+$thedit = "pkg$utilities/nttools/thedit/"
+$tinfo = "pkg$utilities/nttools/tinfo/"
+$tintegrate = "pkg$utilities/nttools/tintegrate/"
+$tjoin = "pkg$utilities/nttools/tjoin/"
+$tlinear = "pkg$utilities/nttools/tlinear/"
+$tmatch = "pkg$utilities/nttools/tmatch/"
+$tmerge = "pkg$utilities/nttools/tmerge/"
+$tprint = "pkg$utilities/nttools/tprint/"
+$tproduct = "pkg$utilities/nttools/tproduct/"
+$tproject = "pkg$utilities/nttools/tproject/"
+$tquery = "pkg$utilities/nttools/tquery/"
+$trebin = "pkg$utilities/nttools/trebin/"
+$tselect = "pkg$utilities/nttools/tselect/"
+$tsort = "pkg$utilities/nttools/tsort/"
+$tstat = "pkg$utilities/nttools/tstat/"
+$ttranspose = "pkg$utilities/nttools/ttranspose/"
+$tupar = "pkg$utilities/nttools/tupar/"
+$tunits = "pkg$utilities/nttools/tunits/"
+$threed = "pkg$utilities/nttools/threed/"
+
+taextract hlp=doc$taextract.hlp, src=atools$taextract.x
+tainsert hlp=doc$tainsert.hlp, src=atools$tainsert.x
+gtedit hlp=doc$gtedit.hlp, src=gtedit$t_gtedit.x
+gtpar hlp=doc$gtpar.hlp, src=ttools$gtpar.par
+imtab hlp=doc$imtab.hlp, src=imtab$imtab.x
+tabim hlp=doc$tabim.hlp, src=imtab$tabim.x
+keypar hlp=doc$keypar.hlp, src=copyone$keypar.x
+keytab hlp=doc$keytab.hlp, src=copyone$keytab.x
+parkey hlp=doc$parkey.hlp, src=copyone$parkey.x
+partab hlp=doc$partab.hlp, src=copyone$partab.x
+tabkey hlp=doc$tabkey.hlp, src=copyone$tabkey.x
+tabpar hlp=doc$tabpar.hlp, src=copyone$tabpar.x
+tcalc hlp=doc$tcalc.hlp, src=tcalc$tcalc.x
+tchcol hlp=doc$tchcol.hlp, src=tchcol$tchcol.x
+tcheck hlp=doc$tcheck.hlp, src=tcheck$tcheck.x
+tchsize hlp=doc$tchsize.hlp, src=tchsize$tchsize.x
+tcopy hlp=doc$tcopy.hlp, src=tcopy$tcopy.x
+tcreate hlp=doc$tcreate.hlp, src=tcreate$tcreate.x
+tdelete hlp=doc$tdelete.hlp, src=tcopy$tdelete.x
+tdiffer hlp=doc$tdiffer.hlp, src=tdiffer$tdiffer.x
+tdump hlp=doc$tdump.hlp, src=tprint$tdump.x
+tedit hlp=doc$tedit.hlp, src=tedit$tedit.x
+texpand hlp=doc$texpand.hlp, src=texpand$texpand.x
+thedit hlp=doc$thedit.hlp, src=thedit$t_thedit.x
+thistogram hlp=doc$thistogram.hlp, src=tstat$thistogram.x
+thselect hlp=doc$thselect.hlp, src=thedit$t_thselect.x
+tinfo hlp=doc$tinfo.hlp, src=tinfo$tinfo.x
+tintegrate hlp=doc$tintegrate.hlp, src=tintegrate$tintegrate.x
+tjoin hlp=doc$tjoin.hlp, src=tjoin$tjoin.x
+tlcol hlp=doc$tlcol.hlp, src=tinfo$tlcol.x
+tlinear hlp=doc$tlinear.hlp, src=tlinear$tlinear.x
+tmatch hlp=doc$tmatch.hlp, src=tmatch$tmatch.x
+tmerge hlp=doc$tmerge.hlp, src=tmerge$tmerge.x
+tprint hlp=doc$tprint.hlp, src=tprint$tprint.x
+tproduct hlp=doc$tproduct.hlp, src=tproduct$tproduct.x
+tproject hlp=doc$tproject.hlp, src=tproject$tproject.x
+tquery hlp=doc$tquery.hlp, src=tquery$tquery.x
+tread hlp=doc$tread.hlp, src=tedit$tread.x
+trebin hlp=doc$trebin.hlp, src=trebin$trebin.x
+tselect hlp=doc$tselect.hlp, src=tselect$tselect.x
+tsort hlp=doc$tsort.hlp, src=tsort$tsort.x
+tstat hlp=doc$tstat.hlp, src=tstat$tstat.x
+ttranspose hlp=doc$ttranspose.hlp, src=ttranspose$ttranspose.x
+tupar hlp=doc$tupar.hlp, src=tupar$tupar.x
+tunits hlp=doc$tunits.hlp, src=tunits$tunits.x
+
+text_tables hlp="pkg$utilities/nttools/text_tables.hlp"
+
+txtable hlp=tdoc$txtable.hlp, src=threed$txtable.x
+tximage hlp=tdoc$tximage.hlp, src=threed$tximage.x
+titable hlp=tdoc$titable.hlp, src=threed$titable.x
+tiimage hlp=tdoc$tiimage.hlp, src=threed$tiimage.x
+tscopy hlp=tdoc$tscopy.hlp, src=threed$tcopy.x
+selectors hlp=tdoc$selectors.hlp
diff --git a/pkg/utilities/nttools/nttools.hlp b/pkg/utilities/nttools/nttools.hlp
new file mode 100644
index 00000000..e02ffbd4
--- /dev/null
+++ b/pkg/utilities/nttools/nttools.hlp
@@ -0,0 +1,244 @@
+.help ttools May2000 tables
+.nj
+
+This package contains tasks for working with tables.
+Tables are files that contain data in row & column format.
+The supported table formats are FITS, STSDAS, and ASCII text.
+Different columns may have different data types,
+but all the values in one column have the same data type.
+In addition to the tabular data,
+a table may contain header parameters identified by keywords.
+
+.nf
+Each column has the following four items of information:
+ (1) a name (case insensitive),
+ (2) data type (real, double, integer, short int, boolean, or text),
+ (3) a format specification for printing the contents of the column,
+ (4) "units", a string (default is null).
+.fi
+
+For STSDAS tables the column names and units
+can be up to 20 characters in length.
+For FITS tables the limit is 68 characters.
+The default column names for ASCII tables are "c1", "c2", "c3", etc.;
+however, there is a "#c" syntax for giving explicit column definitions,
+which is described below.
+
+Header parameters may have data types of
+floating point, integer, boolean, or text.
+Header keywords are limited to eight characters (for FITS compatibility)
+and are converted to upper case.
+
+The print formats are discussed below.
+
+Here is a list of the ttools tasks organized by function:
+
+.nf
+ create a table:
+ tcreate, tedit
+
+ display contents:
+ tprint, tread, tedit, tcheck, thedit, thselect, tupar, gtedit
+
+ modify contents:
+ tedit, thedit, tupar, gtedit
+
+ information about a table:
+ tinfo, tlcol
+
+ database-like utilities:
+ tquery, tsort, tproject, tselect, tdiffer, tjoin, tmatch,
+ tmerge, tproduct, texpand
+
+ statistics, etc:
+ thistogram, tlinear, trebin, tstat
+
+ arithmetic:
+ tcalc, tunits, tintegrate
+
+ convert between table or image header parameter, cl parameter, table datum:
+ keypar, keytab, parkey, partab, tabkey, tabpar
+
+ convert columns of arrays to other formats:
+ txtable, tximage, titable, tiimage, taextract, tainsert
+
+ change column definition or table size:
+ tchcol, tchsize
+
+ miscellaneous:
+ tcopy, tdelete
+.fi
+
+ASCII text tables can be simple files
+(just data in row and column format),
+or they can have header keywords and/or explicit column definitions.
+
+Header keywords and column definitions
+in text tables have the following syntax:
+.nf
+#k keyword = value comment
+#c column_name data_type print_format units
+.fi
+
+The "#k " (or "#K ") must be the first three characters of the line,
+and the space following "k" is required.
+Header keywords can be added to any text table,
+and they do not have to precede the data.
+For a text string keyword,
+quotes around the value are needed if there is a comment,
+in order to distinguish value from comment.
+
+The "#c " (or "#C ") must be the first three characters of the line,
+and the space following "c" is required.
+All column definitions must precede the table data.
+Aside from the "#c ", the syntax is the same as
+the output from 'tlcol' or the 'tcreate.cdfile'.
+Only the column name is required,
+although in most cases you will also need to give the data type
+(the default is d, double precision).
+The print format is not used for reading the text file,
+only for displaying it or printing it out if it was modified.
+The file is read in free format,
+with whitespace (blank or tab) separated columns.
+Text string columns must be enclosed in quotes
+if they contain embedded blanks.
+
+For more information about text tables, "page tables$doc/text_tables.doc".
+
+The print format is used by such tasks as 'tprint', 'tedit', and 'tread'
+to determine how the column values are to be displayed.
+Most of the ordinary Fortran formats are supported for tables.
+Nonstandard formats should not be used for FITS tables
+for reasons of portability.
+The differences between the capabilities of Fortran formats
+and SPP formats are discussed below.
+
+Here is a list of the default print format for each data type,
+given in both SPP style and Fortran style.
+
+.nf
+default formats:
+
+ data type SPP Fortran
+ --------- --- -------
+ real %15.7g G15.7
+ double prec %25.16g G25.16
+ integer %11d I11
+ short %11d I11
+ boolean %6b L6
+ text string %-ns A-n
+.fi
+
+where n for character strings is the string size as given when the
+column was defined.
+The minus sign means that the string will be left justified.
+While a format such as "A-12" is not available in standard Fortran,
+a format may be given with that syntax when using ttools tasks,
+and the format will be converted to SPP style.
+
+SPP formats (and Fortran equivalents) that are supported
+for STSDAS tables are as follows.
+
+.nf
+ SPP Fortran meaning
+ --- ------- -------
+ b L boolean "yes" or "no"
+ d I integer, displayed in decimal
+ x Z integer, displayed in hexadecimal
+ e E or D exponential format
+ f F floating point
+ g G use F or E as appropriate
+ h H nn:nn:nn.n
+ H (none) divide by 15, then nn:nn:nn.n
+ m M nn:nn.n
+ M (none) divide by 15, then nn:nn.n
+ s A character string
+.fi
+
+The syntax is "%w.dC" (SPP style) or "Cw.d" (Fortran style),
+where w is the field width,
+d is the number of decimal places (or precision for g format),
+and C is the format code as given in the left column below.
+When giving a format in Fortran style,
+use the format code given in the second column;
+these are shown in upper case but may also be given in lower case.
+Note that H and M are not standard Fortran formats;
+in particular, H is not interpreted as Hollerith.
+See below for more information about H and M formats.
+
+The field width (w) may be given as a positive number,
+a negative number, or preceded by a zero.
+A negative field width means the value should be left justified in the field.
+A leading zero means the field should be padded on the left by zeroes;
+for example, "%04d" or "I04" is equivalent to the standard Fortran "I4.4".
+The d value means the number of decimal places
+for f, h, m, H or M format,
+but it means the digits of precision for g format.
+For character strings, "%s" means left justify and
+use only as much space as needed to print the value;
+"%40s" and "%-40s" mean right and justify respectively in a 40-character field.
+
+When the format is given in SPP style,
+there are two relatively new formats that are not available in Fortran.
+Specifying upper case H or M means that
+the numbers will be divided by 15 before being formatted
+using h or m format respectively.
+This is intended for converting hours to degrees.
+When two table columns contain right ascension and declination,
+both in decimal degrees,
+then appropriate formats might be,
+for example, %12.2H or %9.2M for right ascension
+and %12.1h for declination.
+This would print the right ascension in hours, minutes, seconds
+(or hours and minutes for M format) with two decimals,
+and would print the declination in degrees, minutes, seconds
+with one decimal after the seconds.
+
+Here are some examples.
+
+.nf
+ internal value format displayed value
+ -------------- ------ ---------------
+ 2.71828 %10.4g 2.718
+ 2.71828e27 %10.4g 2.718E27
+ 2.71828 %10.4f 2.7183
+ 2.71828 %10.4e 2.718E0
+ 2.71828 %10.1h 2:43:05.8
+ 2.71828 %10.1m 2:43.1
+ 2.71828 %07.1m 02:43.1
+ 2.71828 %10d 2
+ 927 %10d 927
+ 927 %-10d 927
+ 927 %010d 0000000927
+ ttools %s ttools
+ ttools %10s ttools
+ ttools %-10s ttools
+.fi
+
+FITS and STSDAS tables can have columns that contain arrays ("3-D tables").
+That is, each cell (designated by both a column name and a row number)
+stores a 1-dimensional array of elements instead of a single value.
+
+There are four tasks that act as 3-D table translators. These tasks extract
+information from or insert information into "3-D tables".
+
+The information moved from/to a 3-D table by the tasks in this package can
+have either of two forms, regular 2-D tables or 1-dimensional images.
+Tasks 'txtable' and 'titable' perform, respectively, extractions and
+insertions of 2-D tables. Tasks 'tximage' and 'tiimage' perform, respectively,
+extractions and insertions of images.
+
+Task 'tscopy' is a variant of the 'tcopy' task.
+It performs a standard table copy
+but also supports the selector mechanism to allow copying of sections
+of columns that contain arrays.
+Type "help selectors" for further information about sections.
+
+.ih
+SEE ALSO
+.nf
+selectors
+files in tables$doc/
+.fi
+
+.endhelp
diff --git a/pkg/utilities/nttools/nttools.men b/pkg/utilities/nttools/nttools.men
new file mode 100644
index 00000000..53cd4fe9
--- /dev/null
+++ b/pkg/utilities/nttools/nttools.men
@@ -0,0 +1,61 @@
+Menu for the package tables.ttools
+
+ keypar - Copy an image or table header keyword to an IRAF parameter.
+ keytab - Copy an image or table header keyword to a table element.
+ parkey - Put an IRAF parameter into an image or table header keyword.
+ partab - Transfer an IRAF parameter to a table element.
+ tabkey - Copy a table element to an image or table header keyword.
+ tabpar - Transfer a table element to an IRAF parameter.
+
+ gtedit - Graphically edit a table.
+ gtpar - Pset to specify graph parameters for 'gtedit' task.
+
+ imtab - Copy an image to a table column.
+ tabim - Copy a table column to an image.
+
+ taextract - Copy an array entry to a column of scalars in another table.
+ tainsert - Copy a column of scalars to an array entry in another table.
+
+ tcalc - Perform arithmetic operations on table columns.
+ tchcol - Change column name, print format, or units.
+ tcheck - Check STSDAS table element values.
+ tchsize - Change allocated sizes of various sections of a table.
+ tcopy - Copy tables.
+ tcreate - Create a STSDAS table from an ASCII descriptor table.
+ tdelete - Delete tables.
+ tdiffer - Form a table which is the difference of two tables.
+ tdump - Dump the contents of a table to an ASCII file.
+ tedit - Edit a table.
+ texpand - Expand tables according to a set of rules.
+ thedit - Edit or print table header keywords.
+ thistogram - Make a histogram of a column in a table.
+ thselect - Select tables satisfying an expression; print keywords.
+ tinfo - Display table size information.
+ tintegrate - Numerically integrate one column with respect to another.
+ tjoin - Perform a relational join of two tables.
+ tlcol - List column information for a table.
+ tlinear - Use linear regression to fit one or two table columns.
+ tmatch - Find closest match between rows in two tables
+ tmerge - Either merge or append tables.
+ tprint - Print tables--both headers and data.
+ tproduct - Form the Cartesian product of two tables.
+ tproject - Create new table from selected columns in a table.
+ tquery - Create a new table from selected rows and columns in a table.
+ tread - Browse through a table.
+ trebin - Resample a table to uniform spacing.
+ tselect - Create a new table from selected rows of a table.
+ tsort - Sort a table.
+ tstat - Get mean, standard deviation, min, and max for a column.
+ ttranspose - Transpose or flip a table.
+ tunits - Convert table column from one set of units to another
+ tupar - Edit table header keywords.
+
+ 3-D table functions
+ tiimage - Insert images into rows of a 3-D table.
+ titable - Insert 2-D tables into rows of a 3-D table.
+ tximage - Extract images from rows of 3-D tables.
+ txtable - Extract 2-D tables from rows of 3-D tables.
+ tscopy - Copy row/column subsets of tables using selectors.
+
+Type "help selectors" for information about row and column selector syntax.
+
diff --git a/pkg/utilities/nttools/nttools.par b/pkg/utilities/nttools/nttools.par
new file mode 100644
index 00000000..6a302939
--- /dev/null
+++ b/pkg/utilities/nttools/nttools.par
@@ -0,0 +1,3 @@
+# Dummy LOCAL package parameter file.
+
+version,s,h,"10May2000"
diff --git a/pkg/utilities/nttools/parkey.par b/pkg/utilities/nttools/parkey.par
new file mode 100644
index 00000000..35c138b4
--- /dev/null
+++ b/pkg/utilities/nttools/parkey.par
@@ -0,0 +1,5 @@
+value,s,a,"",,,"Value of header keyword"
+output,f,a,"",,,"Name of file containing header keyword"
+keyword,s,a,"",,,"Name of header keyword"
+add,b,h,no,,,"Is it OK to create a new keyword?"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/partab.par b/pkg/utilities/nttools/partab.par
new file mode 100644
index 00000000..b8860f99
--- /dev/null
+++ b/pkg/utilities/nttools/partab.par
@@ -0,0 +1,5 @@
+value,s,a,"",,,"Value of table element"
+table,f,a,"",,,"Name of table"
+column,s,a,"",,,"Name of column"
+row,i,a,,,,"Number of row"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/stxtools/changt.x b/pkg/utilities/nttools/stxtools/changt.x
new file mode 100644
index 00000000..c3d4e511
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/changt.x
@@ -0,0 +1,98 @@
+#---------------------------------------------------------------------------
+.help change_ext Jun93 xtools
+.ih
+NAME
+change_ext -- Put the specified extension on a file name.
+.ih
+USAGE
+call change_ext (in_name, newext, out_name, max_size)
+.ih
+ARGUMENTS
+.ls in_name (I: char[ARB])
+The input pathname with which to change the arguments.
+.le
+.ls newext (I: char[ARB])
+The extension to replace the original extension with.
+.le
+.ls out_name (O: char[max_size])
+The resultant pathname with the new extension inserted. May be the
+same as the in_name.
+.le
+.ls max_size (I: int)
+The maximum length of the string out_name.
+.le
+.ih
+DESCRIPTION
+This routine replaces the old extension on a pathname with the new
+extension specified in the argument "newext". Thus:
+
+.nf
+ dir$root.ext --> dir$root.newext
+.fi
+.ih
+SEE ALSO
+fparse
+.endhelp
+#---------------------------------------------------------------------------
+procedure change_ext (in_name, newext, out_name, max_size)
+
+char in_name[ARB] # I: Original input name.
+char newext[ARB] # I: Extension to replace old one.
+char out_name[max_size] # O: File name with new extension.
+int max_size # I: Maximum size out_name.
+
+# Misc.
+pointer dir # Directory part of pathname.
+int index # Group index in pathname.
+pointer ksection # Unparsable part of pathname.
+int ngroup # Number of groups.
+pointer root # Root part of pathname.
+pointer section # Section part of pathname.
+pointer sp # Stack pointer.
+pointer sx # Generic string.
+
+begin
+ call smark (sp)
+ call salloc (dir, SZ_LINE, TY_CHAR)
+ call salloc (root, SZ_LINE, TY_CHAR)
+ call salloc (section, SZ_LINE, TY_CHAR)
+ call salloc (ksection, SZ_LINE, TY_CHAR)
+ call salloc (sx, SZ_LINE, TY_CHAR)
+
+ # Parse the file name COMPLETELY.
+ call fparse (in_name, Memc[dir], SZ_LINE, Memc[root], SZ_LINE,
+ Memc[sx], SZ_LINE, index, ngroup,
+ Memc[section], SZ_LINE, Memc[ksection], SZ_LINE)
+
+ # Put directory and root together.
+ call strcpy (Memc[dir], out_name, max_size)
+ call strcat (Memc[root], out_name, max_size)
+
+ # Change the extension.
+ call strcat (".", out_name, max_size)
+ call strcat (newext, out_name, max_size)
+
+ # Handle group syntax.
+ if (index > 0) {
+ call sprintf (Memc[sx], SZ_LINE, "[%d")
+ call pargi (index)
+ call strcat (Memc[sx], out_name, max_size)
+ if (ngroup > 0) {
+ call sprintf (Memc[sx], SZ_LINE, "/%d")
+ call pargi (ngroup)
+ call strcat (Memc[sx], out_name, max_size)
+ }
+ call strcat ("]", out_name, max_size)
+ }
+
+ # Append the "unparsable" parts.
+ call strcat (Memc[ksection], out_name, max_size)
+
+ # Finally image sections.
+ call strcat (Memc[section], out_name, max_size)
+
+ call sfree (sp)
+end
+#---------------------------------------------------------------------------
+# End of change_ext
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/checkdim.x b/pkg/utilities/nttools/stxtools/checkdim.x
new file mode 100644
index 00000000..ef9ed017
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/checkdim.x
@@ -0,0 +1,24 @@
+include <imhdr.h>
+
+#* HISTORY*
+#* B.Simon 04-Mar-93 original
+
+# CHECKDIM -- Get the real dimension of an image
+
+int procedure checkdim (im)
+
+pointer im # i: image descriptor
+#--
+int idim, jdim
+
+begin
+ # Ignore higher dimesions that only have length one
+
+ jdim = 1
+ do idim = 1, IM_NDIM(im) {
+ if (IM_LEN(im,idim) > 1)
+ jdim = idim
+ }
+
+ return (jdim)
+end
diff --git a/pkg/utilities/nttools/stxtools/cif.h b/pkg/utilities/nttools/stxtools/cif.h
new file mode 100644
index 00000000..55d87ab5
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/cif.h
@@ -0,0 +1,95 @@
+#---------------------------------------------------------------------------
+.help cif.h Apr94 source
+.ih
+NAME
+cif.h -- Definitions for the Coordinated Input File object.
+.endhelp
+#---------------------------------------------------------------------------
+#====
+# Below are the PUBLIC definitions of the CIF object. These may be
+# used by any external application as desired.
+#====
+
+# Generic size of file names/character strings used by CIF.
+define CIF_SZ_FNAME SZ_PATHNAME
+
+# Possible values for the operation code passed to the 'cif_next' routine.
+define CIF_NEXT_GROUP 1 # Get next, if any groups
+define CIF_NEXT_FILE 2 # Get next primary file
+
+# Status of the secondary files after a 'cif_next" call.
+define CIF_OK 1 # New file which is accessable.
+define CIF_NONE 2 # No accessable file found.
+define CIF_SAME 3 # File name is the same as previous.
+define CIF_EXISTS 4 # Output file exists.
+
+# CIF structure variables: Primary file
+define CIF_p_file_list CIF_file_list(CIF_p($1))
+define CIF_p_file CIF_file(CIF_p($1))
+define CIF_p_ext CIF_ext(CIF_p($1))
+define CIF_p_status CIF_status(CIF_p($1))
+define CIF_p_nloop CIF_nloop(CIF_p($1))
+
+# CIF structure variables: Input Files
+define CIF_in_file_list CIF_file_list(CIF_in($1,$2))
+define CIF_in_file CIF_file(CIF_in($1,$2))
+define CIF_in_ext CIF_ext(CIF_in($1,$2))
+define CIF_in_status CIF_status(CIF_in($1,$2))
+define CIF_in_nloop CIF_nloop(CIF_in($1,$2))
+
+# CIF structure variables: Output Files.
+define CIF_out_file_list CIF_file_list(CIF_out($1,$2))
+define CIF_out_file CIF_file(CIF_out($1,$2))
+define CIF_out_ext CIF_ext(CIF_out($1,$2))
+define CIF_out_status CIF_status(CIF_out($1,$2))
+
+#===========================================================================
+#===========================================================================
+# The Private definitions to be used by the object code alone. Any use
+# of the below macros constitutes an interface violation.
+#===========================================================================
+
+# Type of file which the current file name represents.
+define CIF_GENERIC 1
+define CIF_IMAGE 2
+define CIF_DIRECTORY 3
+define CIF_SAME_ROOT 4
+
+#====
+# The CIF object structure.
+#====
+define CIF_p Memi[$1]
+define CIF_in_ptr Memi[$1+1]
+define CIF_n_in Memi[$1+2]
+define CIF_out_ptr Memi[$1+3]
+define CIF_n_out Memi[$1+4]
+define CIF_loop Memi[$1+5]
+define CIF_SZ 6
+
+define CIF_in Memi[CIF_in_ptr($1)+$2-1]
+define CIF_out Memi[CIF_out_ptr($1)+$2-1]
+
+#====
+# CIF File Object Structure
+#====
+define CIF_list Memi[$1]
+define CIF_group Memi[$1+1]
+define CIF_status Memi[$1+2]
+define CIF_nloop Memi[$1+3]
+define CIF_cg Memi[$1+5]
+define CIF_type Memi[$1+6]
+define CIF_cbuf Memi[$1+7]
+define CIF_SZ_FILE 8
+
+define CIF_file_list Memc[CIF_cbuf($1)]
+define CIF_file Memc[CIF_cbuf($1)+CIF_SZ_FNAME+1]
+define CIF_ext Memc[CIF_cbuf($1)+2*(CIF_SZ_FNAME+1)]
+define CIF_base Memc[CIF_cbuf($1)+3*(CIF_SZ_FNAME+1)]
+define CIF_SZ_FILE_CBUF 4*(CIF_SZ_FNAME+1)
+
+# Indexed versions of some strings.
+define CIF_basei Memc[CIF_CBUF($1)+3*(CIF_SZ_FNAME+1)+$2-1]
+
+#---------------------------------------------------------------------------
+# End of cif.h
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/cif.x b/pkg/utilities/nttools/stxtools/cif.x
new file mode 100644
index 00000000..6fa3a7f2
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/cif.x
@@ -0,0 +1,806 @@
+include <imhdr.h>
+include "cif.h"
+
+#---------------------------------------------------------------------------
+.help cif Apr94 source
+.ih
+NAME
+cif -- Coordinated Input File object
+.ih
+DESCRIPTION
+The Coordinated Input File (CIF) object manages multiple input/output
+files that are keyed on a single input file list. This is useful for
+tasks whose input data may come from several different types of input
+files. These input files are coordinated, or linked with, some
+primary input file. This object also handles the creation of output
+files, again linked in some way with the primary input file list.
+
+An explanation of the problem for which this interface was developed
+should help demonstrate the point of the CIF object. For GHRS, the
+calibrated output products includes a flux file, indicated by a file
+extension of C1H, and a wavelength vector file, indicated by a file
+extension of C0H. The number of groups in each file is the same, with
+each group of the wavelength file corresponding to each group of the
+flux file. The primary input file list would be the flux files and
+the one of the secondary input files would be the rootname of the flux
+file but with the C0H extension. The CIF object ensures that the
+files are opened "in lock step". As output, there probably is only
+one output list, each file with the same number of groups as the
+primary input file, but with a new extension, some addition to the
+rootname, or placed in another directory with the same root/extension.
+
+The following sections discuss the public and private
+interfaces.
+.ih
+PUBLIC INTERFACE
+The public interface to CIF consists of three subroutines and a number
+of variables. The subroutines are:
+
+.nf
+ cif_alloc
+ cif_next
+ cif_free
+.fi
+
+Detailed description of the subroutines are:
+
+.ls pointer = cif_alloc (n_in, n_out)
+This routine creates the CIF object. It requires the number of input
+files and output files that will be coordinated with the primary input
+file. Note, the primary input file is NOT counted as one of the
+inputs. The CIF variables are initialized to default or undefined
+values.
+.ls n_in (int)
+Number of input files that will be coordinated. 0 if no input files
+are required.
+.le
+.ls n_out (int)
+Number of output files that will be coordinated. 0 if no output files
+are requierd.
+.le
+.ls RETURNS (pointer)
+Pointer to the CIF object. This pointer will be used in other
+subroutine calls and accessing the CIF object variables.
+.le
+.le
+.ls boolean = cif_next (o, type)
+This is the main loop call for the CIF object. The CIF variables are
+populated with the next set of file names. This can either be the
+next groups of files, or a new set of files depending on the type
+specified. If the value of cif_next is TRUE, then there are more
+files. If FALSE, the end of the list has been reached, i.e. there are
+no more primary files to be had. On return, the CIF variables *_file
+and *_status are set. See the description below of the CIF
+variables for more information.
+.ls o (pointer)
+The pointer to a CIF object created with cif_alloc.
+.le
+.ls type (int)
+What "type" to get next. Possible values are
+.nf
+ CIF_FILE - Get next primary file and associated
+ in/out files.
+ CIF_GROUP - Get next group
+.fi
+.le
+.ls RETURNS (bool)
+TRUE if there is another set of file names available. FALSE if no
+more primary files are found.
+.le
+.le
+.ls cif_free (o)
+Deallocates the CIF object.
+.ls o (pointer)
+The pointer to the CIF object to destroy. Value will be NULL on
+return.
+.le
+.le
+
+The CIF variables can be found in the include file 'cif.h' under the
+public definition section. Below is the current list followed by a
+detailed explanation.
+
+.nf
+ # CIF structure variables: Primary file
+ CIF_p_file_list(o)
+ CIF_p_file(o)
+ CIF_p_ext(o)
+ CIF_p_status(o)
+ CIF_p_nloop(o)
+
+ # CIF structure variables: Input Files
+ CIF_in_file_list(o,i)
+ CIF_in_file(o,i)
+ CIF_in_ext(o,i)
+ CIF_in_status(o,i)
+ CIF_in_nloop(o,i)
+
+ # CIF structure variables: Output Files.
+ CIF_out_file_list(o,i)
+ CIF_out_file(o,i)
+ CIF_out_ext(o,i)
+ CIF_out_status(o,i)
+.fi
+
+For all of the above variables, 'o' is the pointer to the CIF object
+and 'i' is the particular input/output file list to access, since
+there can be multiple input/output files. The definition of each
+variable is as follows:
+.ls CIF_p_file_list, CIF_in_file_list, CIF_out_file_list (char[CIF_SZ_FNAME])
+These variables contain the initial file lists for the primary, input,
+and output files. The lists can contain wildcards, substitution, and
+"@file" specifications. Anything that is consistent with the IRAF
+'imtopen' IMIO call. These variables have to be set after the call to
+'cif_alloc' but before calling 'cif_next'.
+
+The output list is used a bit differently from the input lists. If
+the next file name from an output list is a directory, the output file
+name will be the same as the current primary file, but with this
+directory. If the output list is empty, and the last name retrieved
+from the output list is not a directory, then the output filename will
+be the same as the current primary file, depending on the value of
+CIF_out_ext, see below. If the output list is empty and the last file
+from the output list was a directory, that directory will be used for
+all subsequent primary files.
+.le
+.ls CIF_p_ext, CIF_in_ext, CIF_out_ext (char[CIF_SZ_FNAME])
+These variables contain the default file name extension to use for
+each file. The default extensions do not have to be specified, i.e.
+the value of these variables is an empty string. In that case, the
+actions described below for each variable does not occur. The
+symantics of the _EXT variable is slightly different for each type of
+file:
+.ls CIF_p_ext
+If the next primary file, as retrieved from the primary file list,
+does not exist, replace the original extension with this extension.
+If the file still does not exist, the call to cif_next will error.
+.le
+.ls CIF_in_ext
+This variable is used in two different ways. If the input file list
+is empty, then this extension is placed on the current primary file
+and the file is looked for. If the input list is not empty but the
+next input file does not exist, this extension replaces the original
+extension and existance is checked again.
+.le
+.ls CIF_out_ext
+If specified, this extension is always placed on the output file name.
+.le
+.le
+.ls CIF_p_nloop, CIF_in_nloop (int)
+These variable specify how many calls to 'cif_next' must occur before
+the next group/file is retrieved from the particular primary or input
+list. The default value is 1, or every time 'cif_next' is called,
+retrieve the next group/file. This is useful when a single group in
+either the primary or input file corresponds to a number of groups in
+another input file (or primary file).
+
+The output files don't have a counter, since the output file names are
+created based on the primary file.
+.le
+.ls CIF_p_file, CIF_in_file, CIF_out_file (char[CIF_SZ_FNAME])
+On return from 'cif_next', these variables contain the next set of
+file names. The validity of the name contained in each variable is
+determined by the corresponding *_STATUS variable, see below. If any
+of the files are images, a group specification is appended.
+.le
+.ls CIF_p_status, CIF_in_status, CIF_out_status (int)
+The status or validity of the names contained in the *_FILE variables
+after a call to 'cif_next'. The possible values are:
+.ls CIF_OK
+The name represents another file, different from the name returned by
+a previous call to 'cif_next'. For the primary and input files, the
+file exists. For output files, the file does not exist.
+.le
+.ls CIF_NONE
+For input files, there is no more files in that particular input list.
+The value of CIF_in_file is invalid, i.e. contains "garbage". The
+primary file and output files will never have this status value. This
+is because, when there are no more primary files, 'cif_next' returns
+FALSE and the output files are created based on the primary files.
+.le
+.ls CIF_SAME
+For primary and input values, this value indicates that the file name
+is the same as that returned from a previous call to 'cif_next'. A
+file name will not change only because the value of *_NLOOP and the
+current call to 'cif_next' implied to not change the file name.
+
+For output files, this status indicates that the output file name is
+the same as the current primary file. This can occur if the output
+file list is empty and either no default extension was specified, or
+the default extension happens to be the same as the current primary
+file. Note, this indicates that the character string of the output
+file matches the character string of the current primary file. There
+is no check whether the created files would actually be the same.
+For example, if the current primary file is "root.ext", and the output
+file is "./root.ext", the status would be CIF_OK, not CIF_SAME. See
+CIF_EXISTS.
+.le
+.ls CIF_EXISTS
+For output files only, this indicates that the file exists.
+.le
+.le
+The one constant in use is CIF_SZ_FNAME, size of all character
+variables used by CIF.
+.ih
+PRIVATE INTERFACE
+Note: There won't be much discussion here. Remember: "Use the force,
+read the source".
+
+The CIF object consists of two structures. The CIF file object, which
+maintains the individual files, and the CIF structure which
+manages the number of files.
+
+.ls Subroutines
+The subroutines are as follows:
+.ls pointer = cif_alloc_file_obj()
+Create the CIF file object. This contains the information specific to
+an individual file list.
+.ls RETURNS (pointer)
+Returns a pointer to a CIF FILE object.
+.le
+.le
+.ls cif_free_file_obj (o)
+Destroy a CIF FILE object.
+.ls o (pointer)
+The FILE object to destroy. On return, the value will be NULL.
+.le
+.le
+.ls bool = cif_next_primary (o)
+Get the next primary file and all input/output files. Besides the
+routines in the public interface, this is the only one that deals with
+the CIF structure. This routine, regardless of the group counts and
+whether there are any groups left, retrieve the next files from the
+primary, input, and output lists and populates the CIF public
+variables appropriately.
+.ls o (pointer)
+A pointer to the CIF object.
+.le
+.ls RETURNS (boolean)
+TRUE if there is another set of files. FALSE if there are no more
+primary files.
+.le
+.le
+.ls cif_base2name (o, p)
+Get the next file name for the specified FILE object, using
+information from the primary FILE object.
+.ls o (pointer)
+The FILE object to get the next name for. This should only be a
+primary FILE object or an input FILE object. Output FILE objects use
+'cif_out'.
+.le
+.ls p (pointer)
+The FILE object for the primary file list.
+.le
+.le
+.ls int = cif_file_type (fname)
+Determine the type of file specified. If the file does not exist, the
+routine generates an error.
+.ls fname (char[ARB])
+The name of the file to determine the type of.
+.le
+.ls RETURNS (int)
+A file type id. See 'cif.h' under the Private definitions for a list
+of file types.
+.le
+.le
+.ls bool = cif_next_group (o, loop)
+Get the file name representing the next group of the specified file.
+.ls o
+The primary or input FILE object to get the next group of.
+.le
+.ls loop (int)
+The number of times 'cif_next' has been called. Used to decide
+whether another group should be returned or not.
+.le
+.ls RETURNS (bool)
+TRUE if there is another group, even if the group has not changed.
+FALSE if there are no more groups in the current image.
+.le
+.le
+.ls cif_out (o, p)
+Find the next output file name based on the primary file.
+.ls o (pointer)
+The output FILE object to get the name for.
+.le
+.ls p (pointer)
+The primary FILE object.
+.le
+.le
+.le
+.endhelp
+#---------------------------------------------------------------------------
+pointer procedure cif_alloc (n_in, n_out)
+
+int n_in # I: Number of secondary input files.
+int n_out # I: Number of output files.
+
+# Declarations.
+pointer cif_alloc_file_obj() # Alloce a CIF FILE object.
+pointer o # The CIF object.
+int i # Generic.
+
+errchk cif_alloc_file_obj, malloc
+
+begin
+ # Allocate the CIF object.
+ call malloc (o, CIF_SZ, TY_STRUCT)
+
+ # Allocate the CIF FILE object for the primary file.
+ CIF_p(o) = cif_alloc_file_obj()
+
+ # Allocate FILE objects for each input file.
+ CIF_n_in(o) = n_in
+ call malloc (CIF_in_ptr(o), CIF_n_in(o), TY_POINTER)
+ do i = 1, CIF_n_in(o) {
+ CIF_in(o,i) = cif_alloc_file_obj ()
+ }
+
+ # Allocate FILE objects for each output file.
+ CIF_n_out(o) = n_out
+ call malloc (CIF_out_ptr(o), CIF_n_out(o), TY_POINTER)
+ do i = 1, CIF_n_out(o) {
+ CIF_out(o,i) = cif_alloc_file_obj ()
+ }
+
+ # Initialize the loop count
+ CIF_loop(o) = 0
+
+ # That's all folks.
+ return (o)
+end
+#---------------------------------------------------------------------------
+# End of cif_alloc
+#---------------------------------------------------------------------------
+procedure cif_free (o)
+
+pointer o # IO: CIF object, NULL on return.
+
+# Declarations.
+int i # generic.
+
+errchk cif_free_file_obj, mfree
+
+begin
+ # Free FILE objects for each output file.
+ do i = 1, CIF_n_out(o)
+ call cif_free_file_obj (CIF_out(o,i))
+ call mfree (CIF_out_ptr(o), TY_POINTER)
+
+ # Free FILE objects for each input file.
+ do i = 1, CIF_n_in(o)
+ call cif_free_file_obj (CIF_in(o,i))
+ call mfree (CIF_in_ptr(o), TY_POINTER)
+
+ # Free the primary FILE object.
+ call cif_free_file_obj (CIF_p(o))
+
+ # Remove the object.
+ call mfree (o, TY_STRUCT)
+end
+#---------------------------------------------------------------------------
+# End of cif_free
+#---------------------------------------------------------------------------
+pointer procedure cif_alloc_file_obj ()
+
+# Declarations.
+pointer o # The CIF FILE object.
+
+errchk malloc
+
+begin
+ # Get memory.
+ call malloc (o, CIF_SZ_FILE, TY_STRUCT)
+ call malloc (CIF_cbuf(o), CIF_SZ_FILE_CBUF, TY_CHAR)
+
+ # Setup initial values.
+ call strcpy ("", CIF_file_list(o), CIF_SZ_FNAME)
+ call strcpy ("", CIF_file(o), CIF_SZ_FNAME)
+ CIF_list(o) = NULL
+ CIF_group(o) = NULL
+ call strcpy ("", CIF_ext(o), CIF_SZ_FNAME)
+ CIF_status(o) = CIF_NONE
+ CIF_nloop(o) = 1
+ CIF_cg(o) = INDEFI
+ call strcpy ("", CIF_base(o), CIF_SZ_FNAME)
+ CIF_type(o) = INDEFI
+
+ # That's all folks.
+ return (o)
+end
+#---------------------------------------------------------------------------
+# End of cif_alloc_file_obj
+#---------------------------------------------------------------------------
+procedure cif_free_file_obj (o)
+
+pointer o # IO: CIF FILE object, NULL on return.
+
+# Declarations.
+errchk imtclose, mfree, tp_close
+
+begin
+ # Close other opened objects.
+ if (CIF_list(o) != NULL)
+ call imtclose (CIF_list(o))
+ if (CIF_group(o) != NULL)
+ call tp_close (CIF_group(o))
+
+ # That's all folks.
+ call mfree (CIF_cbuf(o), TY_CHAR)
+ call mfree (o, TY_STRUCT)
+end
+#---------------------------------------------------------------------------
+# End of cif_free_file_obj
+#---------------------------------------------------------------------------
+bool procedure cif_next (o, type)
+
+pointer o # I: The CIF object.
+int type # I: Get a group or file.
+
+# Declarations
+bool another # True if another set of files are available.
+bool bx # Generic.
+bool cif_next_group() # Get next group.
+bool cif_next_primary() # Get next primary files.
+int i # Generic.
+int imtlen() # Length of a file list.
+pointer imtopen() # Open an file list.
+
+errchk imtlen, imtopen
+
+begin
+ # Increment the loop count.
+ CIF_loop(o) = CIF_loop(o) + 1
+
+ # If the lists have not been opened, do it now.
+ if (CIF_list(CIF_p(o)) == NULL) {
+ CIF_list(CIF_p(o)) = imtopen (CIF_file_list(CIF_p(o)))
+ if (imtlen (CIF_list(CIF_p(O))) <= 0)
+ call error (1, "cif: no input files specified")
+ do i = 1, CIF_n_in(o)
+ CIF_list(CIF_in(o,i)) = imtopen (CIF_file_list(CIF_in(o,i)))
+ do i = 1, CIF_n_out(o)
+ CIF_list(CIF_out(o,i)) = imtopen (CIF_file_list(CIF_out(o,i)))
+ another = cif_next_primary (o)
+ }
+
+ # Else, if type is FILE, just get next set of files.
+ else if (type == CIF_NEXT_FILE)
+ another = cif_next_primary (o)
+
+ # Else, loop through groups.
+ else {
+ if (cif_next_group (CIF_p(o), CIF_loop(o))) {
+
+ # Loop through all the inputs.
+ do i = 1, CIF_n_in(o)
+ bx = cif_next_group (CIF_in(o,i), CIF_loop(o))
+
+ # Loop through all the outputs.
+ do i = 1, CIF_n_out(o)
+ call cif_out (CIF_out(o,i), CIF_p(o))
+
+ # There is another file.
+ another = true
+ }
+
+ # Else, get the next set of files.
+ else
+ another = cif_next_primary (o)
+ }
+
+ # That's all folks.
+ return (another)
+end
+#---------------------------------------------------------------------------
+# End of cif_next
+#---------------------------------------------------------------------------
+bool procedure cif_next_primary (o)
+
+pointer o # I: The CIF object.
+
+# Declarations.
+bool another # True if another set of files is available.
+int i # Generic.
+int imtgetim() # Get next file from file list.
+char sx[SZ_LINE] # Generic string.
+
+errchk imtgetim
+
+begin
+ # Open next primary image. If there are no more, then
+ # that's all.
+ if (imtgetim (CIF_list(CIF_p(o)), CIF_base(CIF_p(o)),
+ CIF_SZ_FNAME) != EOF) {
+ call cif_base2name (CIF_p(o), CIF_p(o))
+ if (CIF_status(CIF_p(o)) == CIF_NONE) {
+ call sprintf (sx, SZ_LINE, "cif: no primary file %s")
+ call pargstr (CIF_base(CIF_p(o)))
+ call error (1, sx)
+ }
+
+ # Open the next set of input files.
+ do i = 1,CIF_n_in(o) {
+ if (imtgetim (CIF_list(CIF_in(o,i)), CIF_base(CIF_in(o,i)),
+ CIF_SZ_FNAME) == EOF)
+ call strcpy ("", CIF_base(CIF_in(o,i)), CIF_SZ_FNAME)
+ call cif_base2name (CIF_in(o,i), CIF_p(o))
+ }
+
+ # Open the next set of output files.
+ do i = 1, CIF_n_out(o) {
+ CIF_status(CIF_out(o,i)) = CIF_OK
+ if (imtgetim (CIF_list(CIF_out(o,i)), CIF_base(CIF_out(o,i)),
+ CIF_SZ_FNAME) == EOF) {
+ if (IS_INDEFI(CIF_type(CIF_out(o,i))))
+ CIF_type(o,i) = CIF_GENERIC
+ else
+ CIF_status(CIF_out(o,i)) = CIF_SAME
+ }
+
+ call cif_out (CIF_out(o,i), CIF_p(o))
+ }
+
+ # Indicate that another set of files are available.
+ another = true
+
+ } else
+ another = false
+
+ # That's all folks.
+ return (another)
+end
+#---------------------------------------------------------------------------
+# End of cif_next_primary
+#---------------------------------------------------------------------------
+procedure cif_base2name (o, p)
+
+pointer o # I: CIF FILE Object to find name for.
+pointer p # I: CIF FILE Object of primary file.
+
+# Declarations
+bool bx # Generic.
+int cif_file_type() # Determine file type of file.
+int i # Generic.
+int strlen() # Get length of string.
+bool tp_fetch() # Get next group.
+pointer tp_open() # Open a group list.
+
+errchk tp_close, tp_fetch, tp_open
+
+begin
+ # If there is a group list open, close it.
+ if (CIF_group(o) != NULL)
+ call tp_close (CIF_group(o))
+
+ # Determine file type. If there is an error, try with
+ # the default extension. If that doesn't exist, try default
+ # extension of the primary name.
+ CIF_status(o) = CIF_OK
+ if (strlen(CIF_base(o)) <= 0) {
+ call change_ext (CIF_base(p), CIF_ext(o), CIF_file(o),
+ CIF_SZ_FNAME)
+ iferr (CIF_type(o) = cif_file_type (CIF_file(o)))
+ CIF_status(o) = CIF_NONE
+ } else {
+ call strcpy (CIF_base(o), CIF_file(o), CIF_SZ_FNAME)
+ iferr (CIF_type(o) = cif_file_type (CIF_file(o))) {
+ call change_ext (CIF_file(o), CIF_ext(o), CIF_file(o),
+ CIF_SZ_FNAME)
+ iferr (CIF_type(o) = cif_file_type (CIF_file(o)))
+ CIF_status(o) = CIF_NONE
+ }
+ }
+
+ # Make the new name the base.
+ if (CIF_status(o) == CIF_OK) {
+ call strcpy (CIF_file(o), CIF_base(o), CIF_SZ_FNAME)
+
+ # If the file is an image, open the group list.
+ if (CIF_type(o) == CIF_IMAGE) {
+ CIF_group(o) = tp_open (CIF_file(o), 0, i)
+ bx = tp_fetch (CIF_group(o), CIF_file(o))
+ }
+ CIF_cg(o) = 1
+ }
+end
+#---------------------------------------------------------------------------
+# End of cif_base2name
+#---------------------------------------------------------------------------
+int procedure cif_file_type (fname)
+
+char fname[ARB] # I: The file to determine type of.
+
+# Declarations.
+int access() # Get file access.
+pointer immap() # Open an image.
+pointer px # Generic.
+int strlen() # Get length of string.
+int type # Type of file.
+
+errchk access, imunmap
+
+begin
+ if (strlen (fname) <= 0)
+ call error (1, "cif: Unknown type")
+ else ifnoerr (px = immap (fname, READ_ONLY, NULL)) {
+ type = CIF_IMAGE
+ call imunmap (px)
+ } else if (access (fname, 0, 0) == YES)
+ type = CIF_GENERIC
+ else
+ call error (1, "cif: Unknown type")
+
+ return (type)
+end
+#---------------------------------------------------------------------------
+# End of cif_file_type
+#---------------------------------------------------------------------------
+bool procedure cif_next_group (o, loop)
+
+pointer o # I: The CIF FILE object.
+int loop # I: Current loop count.
+
+# Declarations
+bool tp_fetch() # Get next group.
+
+errchk tp_fetch
+
+begin
+ # Is this file a type to have groups?
+ if (CIF_type(o) == CIF_IMAGE) {
+
+ # Is this loop one to change on?
+ if (mod (loop-1, CIF_nloop(o)) == 0) {
+
+ # Get the next group.
+ if (tp_fetch (CIF_group(o), CIF_file(o))) {
+ CIF_status(o) = CIF_OK
+ CIF_cg(o) = CIF_cg(o) + 1
+ }
+
+ # Else, no more data.
+ else
+ CIF_status(o) = CIF_NONE
+ }
+
+ # Nope, keep it the same.
+ else
+ CIF_status(o) = CIF_SAME
+ }
+
+ # Else, nope, no groups here.
+ else
+ CIF_status(o) = CIF_NONE
+
+ # Return true if a file exists.
+ return (CIF_status(o) != CIF_NONE)
+end
+#---------------------------------------------------------------------------
+# End of cif_next_group
+#---------------------------------------------------------------------------
+procedure cif_out (o, p)
+
+pointer o # I: CIF FILE Object to get output name.
+pointer p # I: Primary CIF FILE Object to get info.
+
+# Declarations
+int access() # Is file accessable?
+int cl_index, cl_size # Cluster info.
+char dir[CIF_SZ_FNAME] # Directory of the file name.
+char ext[CIF_SZ_FNAME] # Extension of the file name.
+int i # Generic.
+int isdirectory() # Is a file a directory?
+char ksection[CIF_SZ_FNAME] # Ksection of the file name.
+char root[CIF_SZ_FNAME] # Root of the file name.
+char section[CIF_SZ_FNAME] # Section of the file name.
+bool streq() # Are strings equal?
+int strlen() # Get length of string.
+char sx[1] # Generic.
+
+errchk access, fbuild, fparse, isdirectory
+
+begin
+ # If a new input, determine what it is.
+ if (CIF_status(o) != CIF_SAME) {
+ if (strlen (CIF_base(o)) <= 0)
+ CIF_type(o) = CIF_SAME_ROOT
+ else if (isdirectory (CIF_base(o), root, SZ_PATHNAME) > 0)
+ CIF_type(o) = CIF_DIRECTORY
+ else
+ CIF_type(o) = CIF_GENERIC
+ }
+
+ # Create the new file name.
+ call fparse (CIF_file(p), dir, CIF_SZ_FNAME, root, CIF_SZ_FNAME,
+ ext, CIF_SZ_FNAME, cl_index, cl_size, section,
+ CIF_SZ_FNAME, ksection, CIF_SZ_FNAME)
+ switch (CIF_type(o)) {
+ case CIF_DIRECTORY:
+ call strcpy (CIF_base(o), dir, CIF_SZ_FNAME)
+
+ case CIF_GENERIC:
+ call fparse (CIF_base(o), dir, CIF_SZ_FNAME, root, CIF_SZ_FNAME,
+ ext, CIF_SZ_FNAME, i, i, sx, 1, sx, 1)
+ }
+
+ # If a different extension is supplied, use it.
+ if (strlen (CIF_ext(o)) > 0) {
+ call strcpy (".", ext, CIF_SZ_FNAME)
+ call strcat (CIF_ext(o), ext, CIF_SZ_FNAME)
+ }
+
+ # Build the new file name.
+ call fbuild (dir, root, ext, cl_index, cl_size, section, ksection,
+ CIF_file(o), CIF_SZ_FNAME)
+
+ # Set status if the name is the same as the primary file.
+ if (streq (CIF_file(p), CIF_file(o)))
+ CIF_status(o) = CIF_SAME
+ else {
+ if (access (CIF_file(o), 0, 0) == YES)
+ CIF_status(o) = CIF_EXISTS
+ else
+ CIF_status(o) = CIF_OK
+ }
+end
+#---------------------------------------------------------------------------
+# End of cif_out
+#---------------------------------------------------------------------------
+procedure cif_test()
+
+pointer cif, cif_alloc()
+bool cif_next()
+int clgeti(), i
+
+begin
+ cif = cif_alloc (2, 1)
+
+ call clgstr ("primary", CIF_p_file_list(cif), CIF_SZ_FNAME)
+ call clgstr ("p_ext", CIF_p_ext(cif), CIF_SZ_FNAME)
+ CIF_p_nloop(cif) = clgeti ("p_loop")
+ call clgstr ("in1", CIF_in_file_list(cif,1), CIF_SZ_FNAME)
+ call clgstr ("in1_ext", CIF_in_ext(cif,1), CIF_SZ_FNAME)
+ CIF_in_nloop(cif,1) = clgeti ("in1_loop")
+ call clgstr ("in2", CIF_in_file_list(cif,2), CIF_SZ_FNAME)
+ call clgstr ("in2_ext", CIF_in_ext(cif,2), CIF_SZ_FNAME)
+ CIF_in_nloop(cif,2) = clgeti ("in2_loop")
+ call clgstr ("out1", CIF_out_file_list(cif,1), CIF_SZ_FNAME)
+ call clgstr ("out1_ext", CIF_out_ext(cif,1), CIF_SZ_FNAME)
+
+ while (cif_next (cif, CIF_NEXT_GROUP)) {
+ call printf ("Primary file == '%s'")
+ call pargstr (CIF_p_file(cif))
+ if (CIF_p_status(cif) == CIF_SAME)
+ call printf (" (same as previous)")
+ call printf ("\n")
+
+ do i = 1, 2 {
+ switch (CIF_in_status(cif,i)) {
+ case CIF_OK:
+ call printf (" Input %d is '%s'\n")
+ call pargi (i)
+ call pargstr (CIF_in_file(cif,i))
+ case CIF_NONE:
+ call printf (" No files for input %d\n")
+ call pargi (i)
+ case CIF_SAME:
+ call printf (" Input %d is '%s' (same as previous)\n")
+ call pargi (i)
+ call pargstr (CIF_in_file(cif,i))
+ }
+ }
+
+ call printf (" Output file is '%s'")
+ call pargstr (CIF_out_file(cif,1))
+ if (CIF_out_status(cif,1) == CIF_EXISTS)
+ call printf (" (file exists)")
+ else if (CIF_out_status(cif,1) == CIF_SAME)
+ call printf (" (same as input)")
+ call printf ("\n")
+ }
+
+ call cif_free (cif)
+end
+#---------------------------------------------------------------------------
+# End of cif_test
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/clgnone.x b/pkg/utilities/nttools/stxtools/clgnone.x
new file mode 100644
index 00000000..b6fde15c
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/clgnone.x
@@ -0,0 +1,37 @@
+# CLGNONE -- Get a string parameter whose value may be "none"
+#
+# B.Simon 20-Jun-94 original
+# B.Simon 30-Jan-95 moved to stxtools
+
+procedure clgnone (param, value, maxch)
+
+char param[ARB] # i: parameter name
+char value[ARB] # o: parameter value
+int maxch # i: maximum length of value
+#--
+pointer sp, temp1, temp2
+bool streq()
+
+begin
+ # Allocate memory for temporary strings
+
+ call smark (sp)
+ call salloc (temp1, maxch, TY_CHAR)
+ call salloc (temp2, maxch, TY_CHAR)
+
+ # Read parameter and convert to lower case for simpler comparison
+
+ call clgstr (param, Memc[temp1], maxch)
+ call strcpy (Memc[temp1], Memc[temp2], maxch)
+ call strjust (Memc[temp2])
+
+ # If value is none, set to null string
+
+ if (Memc[temp2] == EOS || streq (Memc[temp2], "none")) {
+ value[1] = EOS
+ } else {
+ call strcpy (Memc[temp1], value, maxch)
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/stxtools/copyimg.x b/pkg/utilities/nttools/stxtools/copyimg.x
new file mode 100644
index 00000000..0248cfa9
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/copyimg.x
@@ -0,0 +1,78 @@
+include <imhdr.h>
+
+# COPYIMG -- Copy one image to another
+#
+# B.Simon 02-Mar-92 Original
+# B.Simon 16-Mar-94 Delete fast copy, check for existing image
+
+procedure copyimg (old, new)
+
+char old[ARB] # i: old image
+char new[ARB] # i: new image
+#--
+int npix, junk
+pointer buf1, buf2, im1, im2
+long v1[IM_MAXDIM], v2[IM_MAXDIM]
+
+int imaccess()
+int imgnls(), imgnll(), imgnlr(), imgnld(), imgnlx()
+int impnls(), impnll(), impnlr(), impnld(), impnlx()
+pointer immap()
+
+errchk immap, imunmap
+
+begin
+ # Map the input and output images
+ # Code adapted from iraf's imcopy task
+
+ im1 = immap (old, READ_ONLY, 0)
+ if (imaccess (new, READ_WRITE) == NO) {
+ im2 = immap (new, NEW_COPY, im1)
+ } else {
+ im2 = immap (new, READ_WRITE, NULL)
+ }
+
+ # Setup start vector for sequential reads and writes
+
+ call amovkl (long(1), v1, IM_MAXDIM)
+ call amovkl (long(1), v2, IM_MAXDIM)
+
+ # Copy the image.
+
+ npix = IM_LEN(im1, 1)
+ switch (IM_PIXTYPE(im1)) {
+ case TY_SHORT:
+ while (imgnls (im1, buf1, v1) != EOF) {
+ junk = impnls (im2, buf2, v2)
+ call amovs (Mems[buf1], Mems[buf2], npix)
+ }
+ case TY_USHORT, TY_INT, TY_LONG:
+ while (imgnll (im1, buf1, v1) != EOF) {
+ junk = impnll (im2, buf2, v2)
+ call amovl (Meml[buf1], Meml[buf2], npix)
+ }
+ case TY_REAL:
+ while (imgnlr (im1, buf1, v1) != EOF) {
+ junk = impnlr (im2, buf2, v2)
+ call amovr (Memr[buf1], Memr[buf2], npix)
+ }
+ case TY_DOUBLE:
+ while (imgnld (im1, buf1, v1) != EOF) {
+ junk = impnld (im2, buf2, v2)
+ call amovd (Memd[buf1], Memd[buf2], npix)
+ }
+ case TY_COMPLEX:
+ while (imgnlx (im1, buf1, v1) != EOF) {
+ junk = impnlx (im2, buf2, v2)
+ call amovx (Memx[buf1], Memx[buf2], npix)
+ }
+ default:
+ call error (1, "unknown pixel datatype")
+ }
+
+ # Unmap the images
+
+ call imunmap (im2)
+ call imunmap (im1)
+
+end
diff --git a/pkg/utilities/nttools/stxtools/doc/wcs.doc b/pkg/utilities/nttools/stxtools/doc/wcs.doc
new file mode 100644
index 00000000..8154a944
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/doc/wcs.doc
@@ -0,0 +1,177 @@
+Routines for conversion between pixel coordinates and world coordinates.
+
+ This package contains the following high-level routines for converting
+between world coordinates and pixel coordinates:
+
+xt_wcs_init initialize structure for world coordinate system
+xt_wcs_init_c initialize from input cdelt, crota, etc
+xt_wcs_init_cd initialize from input CD matrix, etc
+xt_wc_pix convert from world coordinates to pixel coordinates
+xt_pix_wc convert from pixel coordinates to world coordinates
+xt_wcs_free deallocate wcs struct
+
+After calling any one of the three initialization routines, either or both
+of the conversion routines (xt_wc_pix, xt_pix_wc) may be called any number
+of times. When finished, xt_wcs_free should be called to deallocate memory
+that was allocated by the initialization routine.
+
+ Eight different projection geometries are currently implemented for
+spherical coordinates. The projection type is obtained from the CTYPE
+parameter, or the type defaults to gnomonic if nothing is specified in
+CTYPE. Here is a list of CTYPE values for the right ascension axis with
+the various projection types. For Aitoff and Mercator projections the
+reference pixel is assumed to be on the equator. In addition, for Aitoff
+projection the difference between right ascension and RA at the reference
+pixel is limited to 180 degrees.
+
+ CTYPE projection type
+ ----- ---------------
+ RA---TAN gnomonic (tangent)
+ RA---SIN radial distance proportional to sine of angle
+ RA---ARC radial distance proportional to angle
+ RA---NCP north celestial pole
+ RA---GBS global sine (equal area)
+ RA---STG stereographic
+ RA---AIT Aitoff equal area
+ RA---MER Mercator
+
+
+ To use the following sample program, extract into a file "ttt.x"
+and compile and link with:
+
+ xc -p tables ttt.x -lstxtools
+
+task ttt
+
+include <imhdr.h>
+
+procedure ttt()
+
+pointer im, wcs
+double phys[IM_MAXDIM]
+real pix[IM_MAXDIM], opix[IM_MAXDIM]
+int naxis, k
+char input[SZ_FNAME]
+pointer immap()
+int scan()
+
+begin
+ call clgstr ("input", input, SZ_FNAME)
+ im = immap (input, READ_ONLY, NULL)
+ naxis = IM_NDIM(im)
+ call xt_wcs_init (im, wcs) # initialize
+ call imunmap (im)
+
+ call printf ("naxis = %d\n")
+ call pargi (naxis)
+ call printf ("enter pixel coordinates\n")
+
+ while (scan() != EOF) {
+ do k = 1, naxis
+ call gargr (pix[k])
+ call xt_pix_wc (wcs, pix, phys, naxis) # to world coords
+ call xt_wc_pix (wcs, phys, opix, naxis) # to pixel coords
+ # Print the input pixel coordinates, the world coordinates,
+ # and the output pixel coordinates (which should be the same
+ # as the input).
+ do k = 1, naxis {
+ call printf ("%.3f %18.10g %.3f\n")
+ call pargr (pix[k])
+ call pargd (phys[k])
+ call pargr (opix[k])
+ }
+ }
+ call xt_wcs_free (wcs) # free memory
+end
+
+
+
+# xt_wcs_init -- initialize wcs struct
+# This routine allocates space for a structure describing the world
+# coordinate system for an image, fills in the values or defaults, and
+# returns a pointer to that structure.
+
+call xt_wcs_init (im, wcs)
+
+pointer im # i: pointer to image descriptor
+pointer wcs # o: pointer to world coord system struct
+
+
+# xt_wcs_init_c -- initialize wcs struct
+# xt_wcs_init_c and xt_wcs_init_cd allocate space for a structure
+# describing the world coordinate system for an image, fill in the values
+# or defaults, and return a pointer to that structure. They differ from
+# xt_wcs_init in that these take the coordinate parameters as arguments
+# rather than getting them from the image.
+# xt_wcs_init_c takes cdelt & crota, and xt_wcs_init_cd takes the CD matrix.
+
+call xt_wcs_init_c (crval, crpix, cdelt, crota, ctype, naxis, wcs)
+
+double crval[naxis] # i: coordinate values at reference pixel
+real crpix[naxis] # i: reference pixel
+real cdelt[naxis] # i: pixel spacing
+real crota # i: rotation angle (if 2-D)
+char ctype[SZ_CTYPE,naxis] # i: e.g. "RA---TAN"
+int naxis # i: size of arrays
+pointer wcs # o: pointer to world coord system struct
+
+
+call xt_wcs_init_cd (crval, crpix, cd, ctype, naxis, wcs)
+
+double crval[naxis] # i: coordinate values at reference pixel
+real crpix[naxis] # i: reference pixel
+real cd[naxis,naxis] # i: CD matrix
+char ctype[SZ_CTYPE,naxis] # i: e.g. "RA---TAN"
+int naxis # i: size of arrays
+pointer wcs # o: pointer to world coord system struct
+
+
+# xt_wcs_free -- deallocate wcs struct
+# This routine deallocates space for a wcs structure.
+
+call xt_wcs_free (wcs)
+
+pointer wcs # io: pointer to world coord system struct
+
+
+
+# xt_wc_pix -- wcs to pixels
+# This routine converts world coordinates to pixel coordinates.
+#
+# In the 1-D case, CRVAL is subtracted from the coordinate, the
+# result is divided by CDELT (same as CD1_1), and CRPIX is added.
+#
+# For 2-D or higher dimension, if two of the axes are like RA and Dec,
+# the input coordinates are converted to standard coordinates Xi
+# and Eta. The (Xi, Eta) vector is then multiplied on the left by
+# the inverse of the CD matrix, and CRPIX is added.
+# The units for axes like Ra & Dec are degrees, not hours or radians.
+# For linear axes the conversion is the same as for 1-D.
+
+call xt_wc_pix (wcs, phys, pix, naxis)
+
+pointer wcs # i: pointer to world coord system struct
+double phys[naxis] # i: physical (world) coordinates (e.g. degrees)
+real pix[naxis] # o: pixel coordinates
+int naxis # i: size of arrays
+
+
+
+# xt_pix_wc -- pixels to wcs
+# This routine converts pixel coordinates to world coordinates.
+#
+# In the 1-D case, CRPIX is subtracted from the pixel coordinate,
+# the result is multiplied by CDELT (same as CD1_1), and CRVAL is added.
+#
+# For 2-D or higher dimension, CRPIX is subtracted, and the result is
+# multiplied on the left by the CD matrix. If two of the axes are like
+# RA and Dec, the pixel coordinates are converted to standard coordinates
+# Xi and Eta. The (Xi, Eta) vector is then converted to differences
+# between RA and Dec and CRVAL, and then CRVAL is added to each coordinate.
+
+call xt_pix_wc (wcs, pix, phys, naxis)
+
+pointer wcs # i: pointer to world coord system struct
+real pix[naxis] # i: pixel coordinates
+double phys[naxis] # o: physical (world) coordinates (e.g. degrees)
+int naxis # i: size of arrays
diff --git a/pkg/utilities/nttools/stxtools/errxit.x b/pkg/utilities/nttools/stxtools/errxit.x
new file mode 100644
index 00000000..45b5a7a3
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/errxit.x
@@ -0,0 +1,30 @@
+# ERRXIT -- Take an error exit and set the error code
+
+# This error exit routine is used on VMS system. The VMS symbol $status
+# will be set to the exit_code, so that the process running this program
+# will know the error condition that terminated the program. In order
+# to avoid conflict with other VMS exit codes, it would be best if the
+# exit_code is set to an odd value greater than one.
+#
+# Nelson Zarate 30-Nov-95 original
+# Perry Greenfield 18-Apr-95 change exit code from 122 to 2
+# so that misleading DCL error message
+# is not given (severity level remains
+# the same: 2 --> ERROR). 122 results
+# in a "DEVICE NOT MOUNTED" message.
+
+procedure errxit (exit_code)
+
+int exit_code
+#--
+
+begin
+ # Reset the exit code to a constant value for this routine that
+ # will be called on a VMS system. Other system will run the
+ # errxit.c that lives in tables$lib/stxtools/errxit.c to be inserted
+ # at compilation time by mkpkg.sf..
+ # NZ Nov 30 1995
+ exit_code = 2
+
+ call exit (exit_code)
+end
diff --git a/pkg/utilities/nttools/stxtools/fbuild.x b/pkg/utilities/nttools/stxtools/fbuild.x
new file mode 100644
index 00000000..1dcf6448
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/fbuild.x
@@ -0,0 +1,97 @@
+#---------------------------------------------------------------------------
+.help fbuild Nov93 source
+.ih
+NAME
+fbuild -- Build a file name based on components.
+.ih
+USAGE
+call fbuild (dir, root, ext, clindex, clsize, section, ksection,
+ file, sz_file)
+.ih
+ARGUMENTS
+.ls dir (Input: char[ARB])
+The directory specification. This may be blank. If not, it should
+include the directory separator, i.e. a '$' or '/' at the end of the
+directory.
+.le
+.ls root (Input: char[ARB])
+The rootname specification. This may be left blank. No other
+punctuation besides what goes into a rootname is required.
+.le
+.ls ext (Input: char[ARB])
+The file extension specification. This may be left blank. If
+specified, the extension separater must be prepended, i.e. a period
+'.' must be the first character.
+.le
+.ls clindex (Input: int)
+The cl index or group number. If zero, it will not be placed into the
+pathname.
+.le
+.ls clsize (Input: int)
+The cl size (or maximum group) number. If zero, it will not be placed
+into the pathname.
+.le
+.ls section (Input: char[ARB])
+The section specification. Must include the surrounding '[' and ']'
+section separators.
+.le
+.ls ksection (Input: char[ARB])
+The ksection specification. Must include the surrounding '[' and ']'
+ksection separators.
+.le
+.ls file (Output: char[sz_file])
+The output pathname.
+.le
+.ls sz_file (Input: int)
+The maximum size of the output file specification.
+.le
+.ih
+DESCRIPTION
+fbuild builds a pathname based on individual components. This
+complements the routine fparse. For example, if a full pathname
+exists, a call to fparse followed by a call to fbuild should reproduce
+the pathname.
+.ih
+REFERENCES
+Jonathan Eisenhamer, STSDAS
+.ih
+SEE ALSO
+fparse
+.endhelp
+#---------------------------------------------------------------------------
+procedure fbuild (dir, root, ext, clindex, clsize, section, ksection,
+ file, sz_file)
+
+char dir[ARB] # I: Directory specification.
+char root[ARB] # I: Rootname specification.
+char ext[ARB] # I: Extension specification.
+int clindex # I: Index number.
+int clsize # I: Size number.
+char section[ARB] # I: Section specification.
+char ksection[ARB] # I: KSection specification.
+char file[sz_file] # O: File name.
+int sz_file # I: Maximum size of the file name.
+
+char Index[SZ_PATHNAME] # The Group specification.
+
+begin
+ call strcpy (dir, file, sz_file)
+ call strcat (root, file, sz_file)
+ call strcat (ext, file, sz_file)
+ call strcpy ("", Index, SZ_PATHNAME)
+ if (clindex > 0)
+ if (clsize > 0) {
+ call sprintf (Index, SZ_PATHNAME, "[%d/%d]")
+ call pargi (clindex)
+ call pargi (clsize)
+ } else {
+ call sprintf (Index, SZ_PATHNAME, "[%d]")
+ call pargi (clindex)
+ }
+ call strcat (Index, file, sz_file)
+ call strcat (section, file, sz_file)
+ call strcat (ksection, file, sz_file)
+end
+#---------------------------------------------------------------------------
+# End of fbuild
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/fparse.x b/pkg/utilities/nttools/stxtools/fparse.x
new file mode 100644
index 00000000..33dee6ff
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/fparse.x
@@ -0,0 +1,170 @@
+#---------------------------------------------------------------------------
+.help fparse Aug98 xtools
+.ih
+NAME
+fparse -- Parse a file name
+.ih
+USAGE
+call fparse (input, dir, dir_size, root, root_size, ext, ext_size,
+ cl_index, cl_size, section, section_size, ksection,
+ ksection_size)
+.ih
+ARGUMENTS
+.ls input (I: char[ARB])
+The input file name to parse into its components.
+.le
+.ls dir (O: char[dir_size])
+The directory component of the file name. Includes the directory
+separator character.
+.le
+.ls dir_size (I: int)
+The maximum length of the string to place in the dir argument.
+.le
+.ls root (O: char[root_size])
+The root component of the file name. Includes any wildcard characters
+specified for the root.
+.le
+.ls root_size (I: int)
+The maximum length of the string to place in the root argument.
+.le
+.ls ext (O: char[ext_size])
+The extension component of the file name. DOES NOT INCLUDE the
+extension separator, i.e. the ".".
+.le
+.ls ext_size (I: int)
+The maximum length of the string to place in the ext argument.
+.le
+.ls cl_index (O: int)
+The cluster or group index found in the file name. If none is found,
+this returns -1. Before IRAF v2.11, returned 0.
+.le
+.ls cl_size (O: int)
+The number of clusters or groups found in the file name. If none is
+found, this returns -1. Before IRAF v2.11, returned 0.
+.le
+.ls section (O: char[section_size])
+The image section specification part of the file name. Will contain
+the standard image section specifications.
+.le
+.ls section_size (I: int)
+The maximum length of the string to place in the section argument.
+.le
+.ls ksection (O: char[ksection_size])
+This is the "catchall". If the filename cannot be parsed into the
+form "dir$root.ext[cl_index/cl_size][section]", ksection will contain
+the extra.
+.le
+.ih
+DESCRIPTION
+This routine basically performs the individual functions of fnldir,
+fnext, and fnroot, and the "illegal" imparse. The only distinct
+advantage to this routine is that wildcard characters, and the
+relative directory characters ".", and ".." can be present in the file
+name.
+.ih
+BUGS
+This routine calls the illegal routine imparse. If the image naming
+conventions in IMIO ever change, this routine will surely break all to
+pieces.
+.endhelp
+#---------------------------------------------------------------------------
+#
+# M.D. De La Pena - 11 August 1998: updated internal documentation for
+# cl_index and cl_size to reflect changes made for IRAF v2.11.
+#
+procedure fparse (input, dir, dir_size, root, root_size, ext, ext_size,
+ cl_index, cl_size, section, section_size, ksection,
+ ksection_size)
+
+char input[ARB] # I: Input pathname
+char dir[dir_size] # O: Directory part of pathname.
+int dir_size # I: Max size of dir.
+char root[root_size] # O: Root part of pathname.
+int root_size # I: Max size of root.
+char ext[ext_size] # O: Extension part of pathname.
+int ext_size # I: Max size of extension.
+int cl_index # O: The cluster index.
+int cl_size # O: The cluster size.
+char section[section_size] # O: The section part of pathname.
+int section_size # I: Max size of section.
+char ksection[ksection_size] # O: The remainder of the pathname.
+int ksection_size # I: Max size of ksection.
+
+# Declarations
+int i # Generic.
+int len_dir # Length of the directory spec.
+
+pointer cluster # Cluster.
+pointer last_period # Pointer to the last period.
+pointer new_cluster # Cluster without the directory spec.
+pointer ptr # Pointer into strings.
+pointer sp # Stack pointer.
+
+string wildcards "*?"
+
+# Function prototypes.
+int fnldir(), stridxs()
+bool streq()
+
+begin
+
+ call smark(sp)
+ call salloc (cluster, SZ_LINE, TY_CHAR)
+
+ # Parse the name with the (illegal) call imparse.
+ call imparse (input, Memc[cluster], SZ_LINE, ksection,
+ ksection_size, section, section_size, cl_index,
+ cl_size)
+
+ # Further parse the the cluster name into directory, root,
+ # and extension.
+ # Wildcards are a problem. The above only deals with fully qualified
+ # pathnames, not templates. But, it seems it could be done. Scan
+ # the directory for wildcards and try to parse out a bit more. The
+ # assumption made is that directories cannot be wildcarded.
+ root[1] = EOS
+ ext[1] = EOS
+ len_dir = fnldir (Memc[cluster], dir, dir_size)
+ i = stridxs (wildcards, dir)
+ if (i > 0) {
+ dir[i] = EOS
+ len_dir = fnldir (dir, dir, dir_size)
+ }
+
+ # Now there is just root and extension. Check to see if root is just
+ # the relative directory names. If so, append them to the directory
+ # specification.
+ new_cluster = cluster + len_dir
+ if (streq (Memc[new_cluster], ".") || streq (Memc[new_cluster], "..")) {
+ call strcat (Memc[new_cluster], dir, dir_size)
+ call strcat ("/", dir, dir_size)
+ }
+
+ # Else, find the extension. This is just the last found "." in the
+ # specification.
+ else {
+ last_period = NULL
+ ptr = new_cluster
+ while (Memc[ptr] != EOS) {
+ if ( Memc[ptr] == '.')
+ last_period = ptr
+ ptr = ptr + 1
+ }
+ if (last_period == NULL) {
+ call strcpy (Memc[new_cluster], root, root_size)
+ ext[1] = EOS
+ } else {
+ Memc[last_period] = EOS
+ call strcpy (Memc[new_cluster], root, root_size )
+ Memc[last_period] = '.'
+ call strcpy (Memc[last_period], ext, ext_size)
+ }
+ }
+
+ # That's all folks.
+ call sfree(sp)
+
+end
+#---------------------------------------------------------------------------
+# End of fparse
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/grmimy.x b/pkg/utilities/nttools/stxtools/grmimy.x
new file mode 100644
index 00000000..bd30f93e
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/grmimy.x
@@ -0,0 +1,68 @@
+include <imhdr.h>
+
+#---------------------------------------------------------------------------
+.help grm_imcopy Oct92 source
+.ih
+NAME
+grm_imcopy -- Copy images given their image descriptors.
+.endhelp
+#---------------------------------------------------------------------------
+procedure grm_imcopy (in, out)
+
+pointer in # I: Input image descriptor of image to copy.
+pointer out # I: Output image descriptor of resultant image.
+
+# Declarations.
+long v1[IM_MAXDIM], v2[IM_MAXDIM] # Line and section counters.
+
+int junk # Generic.
+int npix # Length of a line of data.
+
+pointer buf1, buf2 # Data buffers.
+
+# Function Prototypes.
+int imgnls(), imgnll(), imgnlr(), imgnld(), imgnlx()
+int impnls(), impnll(), impnlr(), impnld(), impnlx()
+
+begin
+
+ # Setup start vector for sequential reads and writes.
+ call amovkl (long(1), v1, IM_MAXDIM)
+ call amovkl (long(1), v2, IM_MAXDIM)
+
+ # Copy the image.
+ npix = IM_LEN(in, 1)
+ switch (IM_PIXTYPE(in)) {
+ case TY_SHORT:
+ while (imgnls (in, buf1, v1) != EOF) {
+ junk = impnls (out, buf2, v2)
+ call amovs (Mems[buf1], Mems[buf2], npix)
+ }
+ case TY_USHORT, TY_INT, TY_LONG:
+ while (imgnll (in, buf1, v1) != EOF) {
+ junk = impnll (out, buf2, v2)
+ call amovl (Meml[buf1], Meml[buf2], npix)
+ }
+ case TY_REAL:
+ while (imgnlr (in, buf1, v1) != EOF) {
+ junk = impnlr (out, buf2, v2)
+ call amovr (Memr[buf1], Memr[buf2], npix)
+ }
+ case TY_DOUBLE:
+ while (imgnld (in, buf1, v1) != EOF) {
+ junk = impnld (out, buf2, v2)
+ call amovd (Memd[buf1], Memd[buf2], npix)
+ }
+ case TY_COMPLEX:
+ while (imgnlx (in, buf1, v1) != EOF) {
+ junk = impnlx (out, buf2, v2)
+ call amovx (Memx[buf1], Memx[buf2], npix)
+ }
+ default:
+ call error (1, "unknown pixel datatype")
+ }
+
+end
+#---------------------------------------------------------------------------
+# End of grm_imcopy
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/isblank.x b/pkg/utilities/nttools/stxtools/isblank.x
new file mode 100644
index 00000000..85edb9d7
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/isblank.x
@@ -0,0 +1,18 @@
+include <ctype.h>
+
+# ISBLANK -- Return true if the string is entirely white space
+#
+# B.Simon 11-Nov-87 First Code
+
+bool procedure isblank (str)
+
+char str[ARB] # i: string to be tested
+int ip
+
+begin
+ do ip = 1, ARB
+ if (str[ip] == EOS)
+ return (true)
+ else if (! IS_WHITE(str[ip]) )
+ return (false)
+end
diff --git a/pkg/utilities/nttools/stxtools/lubksb.f b/pkg/utilities/nttools/stxtools/lubksb.f
new file mode 100644
index 00000000..429cf2e4
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/lubksb.f
@@ -0,0 +1,50 @@
+ SUBROUTINE LUBKSB (A, N, NP, INDX, B)
+
+C Solves a matrix equation AX = B. Before using this routine you must
+C call ludcmp to decompose the matrix A (in-place) into lower and upper
+C triangular portions. The vector B is input to this routine, and the
+C answer X is returned in B.
+C
+C real a(np,np) i: matrix returned by ludcmp
+C int n i: logical size of a is n x n
+C int np i: space allocated for a is np x np
+C int indx(n) i: index returned by ludcmp
+C real b(n) io: input b, output x in equation ax = b
+C
+C 1988 Oct 28 From Numerical Recipes
+
+ INTEGER N, NP
+ REAL A(NP,NP)
+ INTEGER INDX(N)
+ REAL B(N)
+
+ REAL SUM
+ INTEGER II, LL, I, J
+
+ II = 0
+ DO 20 I = 1, N
+ LL = INDX(I)
+ SUM = B(LL)
+ B(LL) = B(I)
+ IF (II .NE. 0) THEN
+ DO 10 J = II, I-1
+ SUM = SUM - A(I,J) * B(J)
+ 10 CONTINUE
+ ELSE IF (SUM .NE. 0.) THEN
+ II = I
+ ENDIF
+ B(I) = SUM
+ 20 CONTINUE
+
+ DO 40 I = N, 1, -1
+ SUM = B(I)
+ IF (I .LT. N) THEN
+ DO 30 J = I+1, N
+ SUM = SUM - A(I,J) * B(J)
+ 30 CONTINUE
+ ENDIF
+ B(I) = SUM / A(I,I)
+ 40 CONTINUE
+
+ RETURN
+ END
diff --git a/pkg/utilities/nttools/stxtools/lubksd.f b/pkg/utilities/nttools/stxtools/lubksd.f
new file mode 100644
index 00000000..04e17c6c
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/lubksd.f
@@ -0,0 +1,53 @@
+ SUBROUTINE LUBKSD (A, N, NP, INDX, B)
+
+C Double-precision version of LUBKSB.
+C
+C Solves a matrix equation AX = B. Before using this routine you must
+C call ludcmd to decompose the matrix A (in-place) into lower and upper
+C triangular portions. The vector B is input to this routine, and the
+C answer X is returned in B.
+C
+C double a(np,np) i: matrix returned by ludcmp
+C int n i: logical size of a is n x n
+C int np i: space allocated for a is np x np
+C int indx(n) i: index returned by ludcmp
+C double b(n) io: input b, output x in equation ax = b
+C
+C 1988 Oct 28 From Numerical Recipes.
+C 1992 Sep 10 Rename from LUBKSB and convert to double precision.
+
+ INTEGER N, NP
+ DOUBLE PRECISION A(NP,NP)
+ INTEGER INDX(N)
+ DOUBLE PRECISION B(N)
+
+ DOUBLE PRECISION SUM
+ INTEGER II, LL, I, J
+
+ II = 0
+ DO 20 I = 1, N
+ LL = INDX(I)
+ SUM = B(LL)
+ B(LL) = B(I)
+ IF (II .NE. 0) THEN
+ DO 10 J = II, I-1
+ SUM = SUM - A(I,J) * B(J)
+ 10 CONTINUE
+ ELSE IF (SUM .NE. 0.) THEN
+ II = I
+ ENDIF
+ B(I) = SUM
+ 20 CONTINUE
+
+ DO 40 I = N, 1, -1
+ SUM = B(I)
+ IF (I .LT. N) THEN
+ DO 30 J = I+1, N
+ SUM = SUM - A(I,J) * B(J)
+ 30 CONTINUE
+ ENDIF
+ B(I) = SUM / A(I,I)
+ 40 CONTINUE
+
+ RETURN
+ END
diff --git a/pkg/utilities/nttools/stxtools/ludcmd.x b/pkg/utilities/nttools/stxtools/ludcmd.x
new file mode 100644
index 00000000..708a9df9
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/ludcmd.x
@@ -0,0 +1,99 @@
+define TINY 1.d-20
+
+# ludcmd -- lower-upper decomposition
+# Double-precision version of ludcmp from Numerical Recipes.
+# This differs from the Numerical Recipes version in the following ways:
+# (1) the calling sequence also includes an ISTAT parameter, (2) memory
+# is allocated instead of using the fixed array VV, and (3) double
+# precision is used.
+# This routine decomposes a matrix (in-place) into lower and upper
+# triangular portions. Use lubksd to obtain a solution to A * X = B
+# or to compute the inverse of the matrix A.
+# If the matrix is singular, ISTAT is set to one.
+#
+# Phil Hodge, 28-Oct-1988 Subroutine copied from Numerical Recipes.
+# Phil Hodge, 10-Sep-1992 Convert to double precision and rename from ludcmp.
+
+procedure ludcmd (a, n, np, indx, d, istat)
+
+double a[np,np] # io: input a, output decomposed a
+int n # i: logical size of a is n x n
+int np # i: space allocated for a
+int indx[n] # o: index to be used by xt_lubksb
+double d # o: +1 or -1
+int istat # o: OK if no problem; 1 if matrix is singular
+#--
+pointer sp
+pointer vv # scratch space
+double aamax
+double sum
+double dum
+int i, j, k
+int imax
+
+begin
+ istat = OK # initial value
+
+ call smark (sp)
+ call salloc (vv, n, TY_DOUBLE)
+
+ d = 1.d0
+ do i = 1, n {
+ aamax = 0.d0
+ do j = 1, n
+ if (abs(a[i,j]) > aamax)
+ aamax = abs(a[i,j])
+ if (aamax == 0.d0) {
+ istat = 1
+ return
+ }
+ Memd[vv+i-1] = 1.d0 / aamax
+ }
+ do j = 1, n {
+ if (j > 1) {
+ do i = 1, j-1 {
+ sum = a[i,j]
+ if (i > 1) {
+ do k = 1, i-1
+ sum = sum - a[i,k] * a[k,j]
+ a[i,j] = sum
+ }
+ }
+ }
+ aamax = 0.d0
+ do i = j, n {
+ sum = a[i,j]
+ if (j > 1) {
+ do k = 1, j-1
+ sum = sum - a[i,k] * a[k,j]
+ a[i,j] = sum
+ }
+ dum = Memd[vv+i-1] * abs[sum]
+ if (dum >= aamax) {
+ imax = i
+ aamax = dum
+ }
+ }
+ if (j != imax) {
+ do k = 1, n {
+ dum = a[imax,k]
+ a[imax,k] = a[j,k]
+ a[j,k] = dum
+ }
+ d = -d
+ Memd[vv+imax-1] = Memd[vv+j-1]
+ }
+ indx[j] = imax
+ if (j != n) {
+ if (a[j,j] == 0.d0)
+ a[j,j] = TINY
+ dum = 1.d0 / a[j,j]
+ do i = j+1, n
+ a[i,j] = a[i,j] * dum
+ }
+ }
+ if (a[n,n] == 0.d0)
+ a[n,n] = TINY
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/stxtools/ludcmp.x b/pkg/utilities/nttools/stxtools/ludcmp.x
new file mode 100644
index 00000000..cb2ce43d
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/ludcmp.x
@@ -0,0 +1,87 @@
+define TINY 1.e-20
+
+# ludcmp -- lower-upper decomposition
+# This routine decomposes a matrix (in-place) into lower and upper
+# triangular portions. This is the same as the Numerical Recipes version
+# except that memory is allocated instead of using the fixed array VV.
+#
+# Phil Hodge, 28-Oct-1988 Subroutine copied from Numerical Recipes.
+
+procedure ludcmp (a, n, np, indx, d)
+
+real a[np,np] # io: input a, output decomposed a
+int n # i: logical size of a is n x n
+int np # i: space allocated for a
+int indx[n] # o: index to be used by xt_lubksb
+real d # o: +1 or -1
+#--
+pointer sp
+pointer vv # scratch space
+real aamax
+real sum
+real dum
+int i, j, k
+int imax
+
+begin
+ call smark (sp)
+ call salloc (vv, n, TY_REAL)
+
+ d = 1.
+ do i = 1, n {
+ aamax = 0.
+ do j = 1, n
+ if (abs(a[i,j]) > aamax)
+ aamax = abs(a[i,j])
+ if (aamax == 0.)
+ call error (0, "singular matrix")
+ Memr[vv+i-1] = 1. / aamax
+ }
+ do j = 1, n {
+ if (j > 1) {
+ do i = 1, j-1 {
+ sum = a[i,j]
+ if (i > 1) {
+ do k = 1, i-1
+ sum = sum - a[i,k] * a[k,j]
+ a[i,j] = sum
+ }
+ }
+ }
+ aamax = 0.
+ do i = j, n {
+ sum = a[i,j]
+ if (j > 1) {
+ do k = 1, j-1
+ sum = sum - a[i,k] * a[k,j]
+ a[i,j] = sum
+ }
+ dum = Memr[vv+i-1] * abs[sum]
+ if (dum >= aamax) {
+ imax = i
+ aamax = dum
+ }
+ }
+ if (j != imax) {
+ do k = 1, n {
+ dum = a[imax,k]
+ a[imax,k] = a[j,k]
+ a[j,k] = dum
+ }
+ d = -d
+ Memr[vv+imax-1] = Memr[vv+j-1]
+ }
+ indx[j] = imax
+ if (j != n) {
+ if (a[j,j] == 0.)
+ a[j,j] = TINY
+ dum = 1. / a[j,j]
+ do i = j+1, n
+ a[i,j] = a[i,j] * dum
+ }
+ }
+ if (a[n,n] == 0.)
+ a[n,n] = TINY
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/stxtools/mkpkg b/pkg/utilities/nttools/stxtools/mkpkg
new file mode 100644
index 00000000..218ad5f5
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/mkpkg
@@ -0,0 +1,54 @@
+# Update the xtools library.
+# Author: Phil Hodge, 16-NOV-1988
+# Modified to include similar.x : B.Simon 14-Mar-1989
+# Modified to include group template expansion routines : B.Simon 14-Feb-1990
+# Modified to include word.x and vex*.x : B.Simon 21-May-1990
+# Modified to include copyimg.x: B.Simon 02-Mar-1992
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+
+libpkg.a:
+ @od
+ @sp_util
+ @wcslab
+ changt.x
+ checkdim.x <imhdr.h>
+ cif.x "cif.h"
+ clgnone.x
+ copyimg.x <imhdr.h>
+ errxit.x
+ fbuild.x
+ fparse.x
+ grmimy.x <imhdr.h>
+ isblank.x <ctype.h>
+ lubksb.f
+ lubksd.f
+ ludcmd.x
+ ludcmp.x
+ postexit.x <clset.h>
+ savgol.x
+ sbuf.x "sbuf.h"
+ sgcone.x
+ similar.x
+ strjust.x <ctype.h>
+ stxgetcoord.x <imhdr.h> <mwset.h> <math.h>
+ tpbreak.x
+ tpclose.x "template.h"
+ tpcount.x "template.h"
+ tpfetch.x "template.h"
+ tpgroup.x <ctype.h> <imio.h>
+ tpimtype.x <ctype.h> "template.h"
+ tpopen.x "template.h"
+ tpparse.x <imio.h>
+ vexcompile.x <lexnum.h> <ctype.h> <fset.h> "vex.h" "vex.com"
+ vexeval.x "vex.h"
+ vexfree.x "vex.h"
+ vexfunc.x <mach.h> "vex.h"
+ vexstack.x "vex.h"
+ word.x
+ xtwcs.x <imhdr.h> <math.h>
+ ;
diff --git a/pkg/utilities/nttools/stxtools/od/mkpkg b/pkg/utilities/nttools/stxtools/od/mkpkg
new file mode 100644
index 00000000..a72fbad9
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/od/mkpkg
@@ -0,0 +1,15 @@
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ odget.x "od.h"
+ odmap.x <error.h> <imhdr.h> <imio.h> <tbset.h> "od.h"
+ odopep.x "od.h"
+ odpare.x
+ odput.x "od.h"
+ odsetn.x <imhdr.h> "od.h"
+ odunmp.x "od.h"
+ odwcsn.x <mwset.h> "od.h"
+ ;
diff --git a/pkg/utilities/nttools/stxtools/od/od.h b/pkg/utilities/nttools/stxtools/od/od.h
new file mode 100644
index 00000000..2070d551
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/od/od.h
@@ -0,0 +1,32 @@
+#---------------------------------------------------------------------------
+.help od.h Feb93 source
+.ih
+NAME
+od.h -- Include parameters for the 1D I/O data system.
+.endhelp
+#---------------------------------------------------------------------------
+#-----
+# Below describes the structure and access to the OD descriptor.
+define OD_FD Memi[$1] # The image/table descriptor
+define OD_TYPE Memi[$1+1] # TABLE/IMAGE flag.
+define OD_CD_PTR Memi[$1+2] # Table column descriptor.
+define OD_CD Memi[OD_CD_PTR($1)+$2-1]
+define OD_LEN Memi[$1+3] # Dimension of the data.
+define OD_NGRP Memi[$1+4] # Number of groups in image.
+define OD_GRP Memi[$1+5] # Current open group.
+define OD_NAME_PTR Memi[$1+6] # Specified file name.
+define OD_NAME Memc[OD_NAME_PTR($1)]
+define OD_MW Memi[$1+7] # MWCS descriptor.
+define OD_WL Memi[$1+8] # World-to-Logical transformation.
+define OD_LW Memi[$1+9] # Logical-to-World transformation.
+define OD_WSYS_PTR Memi[$1+10] # WCS system type.
+define OD_WSYS Memc[OD_WSYS_PTR($1)]
+define OD_OLD Memi[$1+11] # Template which opened this OD.
+define OD_SZ_OD 12 # Size of structure.
+
+# The flag of what type of file we are dealing with.
+define OD_TABLE 1
+define OD_IMAGE 2
+#---------------------------------------------------------------------------
+# End of od.h
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/od/odget.x b/pkg/utilities/nttools/stxtools/od/odget.x
new file mode 100644
index 00000000..013acc67
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/od/odget.x
@@ -0,0 +1,56 @@
+include "od.h"
+
+#---------------------------------------------------------------------------
+.help od_get Feb93 source
+.ih
+NAME
+od_get -- Retrieve data from file.
+.ih
+USAGE
+.nf
+call od_getd (od, data)
+.fi
+.ih
+ARGUMENTS
+.ls od (pointer :input)
+The OD I/O descriptor.
+.le
+.ls data (double[ARB] :output)
+The data from the OD file.
+.le
+.endhelp
+#---------------------------------------------------------------------------
+procedure od_get (od, data)
+
+pointer od # I: The OD I/O descriptor.
+double data[ARB] # O: The data.
+
+pointer null # Null flag array for table IO.
+
+# Functions
+pointer imgl1d()
+
+errchk gf_opengr, imgl1d, malloc, mfree, tbcgtd
+
+begin
+ # Check if a file is actually opened. If not, do nothing.
+ if (od != NULL) {
+
+ # Get data depending on file type.
+ switch (OD_TYPE(od)) {
+ case OD_TABLE:
+ call malloc (null, OD_LEN(od), TY_BOOL)
+ call tbcgtd (OD_FD(od), OD_CD(od,OD_GRP(od)), data, Memb[null],
+ 1, OD_LEN(od))
+ call mfree (null, TY_BOOL)
+
+ case OD_IMAGE:
+
+ # Retrieve the data.
+ call amovd (Memd[imgl1d(OD_FD(od))], data, OD_LEN(od))
+ }
+ }
+end
+#---------------------------------------------------------------------------
+# End of od_get
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/od/odmap.x b/pkg/utilities/nttools/stxtools/od/odmap.x
new file mode 100644
index 00000000..f41ad5e1
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/od/odmap.x
@@ -0,0 +1,250 @@
+include <error.h>
+include <imhdr.h>
+include <imio.h>
+include <tbset.h>
+include "od.h"
+
+# Define the default column number to retrieve table data from
+define DEFAULT_COL 1
+
+#---------------------------------------------------------------------------
+.help od_map Feb93 source
+.ih
+NAME
+.nf
+od_map -- Open a file as either an image or table.
+
+od_image_map -- Internal: Map an image.
+od_table_map -- Internal: Map a table.
+.fi
+.ih
+USAGE
+.nf
+od = od_map (name, mode, old)
+
+call od_image_map (name, od)
+call od_table_map (name, mode, od)
+.fi
+.ih
+ARGUMENTS
+.ls name (char[ARB] :input)
+The name of the file to open.
+.le
+.ls mode (int :input)
+The access mode to open the file in. Same as the standard IRAF open
+modes.
+.le
+.ls old (pointer :input)
+If creating a new file, use this as a template. If NULL, no template will
+be assumed. This is the OD descriptor, not an IMIO or TABLE descriptor.
+.le
+.ls od (pointer :input)
+The OD I/O descriptor.
+.le
+.ih
+RETURNS
+An od i/o file descriptor containing the image/table descriptor, a flag
+indicating whether it is an image or table, and, if a table, the column
+descriptor to retrieve the data from.
+.ih
+DESCRIPTION
+This provides a common interface to retrieve one dimensional data from
+either an image or a table. This is vary basic and is not intended to
+handle a full i/o interface. Just need to open, close, and read data.
+
+Added some syntax to the table name specification. We will allow the
+column names/numbers to be specified in a "section" notation. An
+example:
+
+.nf
+ tablename[columnname1,...]
+.fi
+
+where columnnameX are either names or numbers. If no column
+specification is used, then it is assumed all columns of the table are
+to be used and will be considered with the appropriate "group" of
+multigroup input.
+.endhelp
+#---------------------------------------------------------------------------
+pointer procedure od_map(name, mode, old)
+
+char name[ARB] # I: The file name to open.
+int mode # I: The mode to open the file in.
+pointer old # I: Template OD I/O descriptor as template.
+
+# Declarations.
+pointer od # OD I/O descriptor.
+pointer sp # Stack Pointer.
+pointer sx # Generic string.
+
+# Function prototypes
+pointer immap()
+
+errchk malloc, od_image_map, od_table_map
+
+begin
+ call smark (sp)
+ call salloc (sx, SZ_LINE, TY_CHAR)
+
+ # Allocate the od i/o descriptor.
+ call malloc (od, OD_SZ_OD, TY_STRUCT)
+ call malloc (OD_NAME_PTR(od), SZ_LINE, TY_CHAR)
+ call malloc (OD_WSYS_PTR(od), SZ_LINE, TY_CHAR)
+
+ # If an old descriptor is given, base what open occurs on
+ # its type.
+ OD_OLD(od) = old
+ if (old != NULL)
+ switch (OD_TYPE(old)) {
+ case OD_IMAGE:
+ OD_FD(od) = immap (name, mode, OD_FD(old))
+ call od_image_map (name, od)
+ case OD_TABLE:
+ call od_table_map (name, mode, OD_FD(old), od)
+ }
+
+ # Else, just open up that data file. If the image call doesn't fail,
+ # then assume its an image.
+ else ifnoerr (OD_FD(od) = immap (name, mode, NULL))
+ call od_image_map (name, od)
+
+ # If it cannot be opened as a table, try changing the extension.
+ # If that fails, then give it up.
+ else iferr (call od_table_map (name, mode, NULL, od)) {
+ call change_ext (name, "c1h", Memc[sx], SZ_LINE)
+ iferr (OD_FD(od) = immap (Memc[sx], mode, NULL)) {
+ call erract (EA_ERROR)
+ }
+ call od_image_map (Memc[sx], od)
+ }
+
+ # That's all folks.
+ call sfree (sp)
+ return (od)
+end
+#---------------------------------------------------------------------------
+# End of od_map
+#---------------------------------------------------------------------------
+procedure od_image_map (name, od)
+
+char name[ARB] # I: Full specified name.
+pointer od # I: OD I/O descriptor.
+
+# Declarations.
+int i # Generic.
+
+pointer sp # Stack pointer.
+pointer sx
+
+begin
+ call smark (sp)
+ call salloc (sx, SZ_LINE, TY_CHAR)
+
+ # Fill the OD I/O descriptor.
+ OD_TYPE(od) = OD_IMAGE
+ OD_CD_PTR(od) = NULL
+ OD_LEN(od) = IM_LEN(OD_FD(od),1)
+ OD_NGRP(od) = max(1,IM_CLSIZE(OD_FD(od)))
+ call strcpy (IM_HDRFILE(OD_FD(od)), OD_NAME(od), SZ_LINE)
+
+ # See whether a specific group was opened.
+ call fparse (name, Memc[sx], SZ_LINE, Memc[sx], SZ_LINE, Memc[sx],
+ SZ_LINE, OD_GRP(od), i, Memc[sx], SZ_LINE, Memc[sx],
+ SZ_LINE)
+ if (OD_GRP(od) > 0)
+ OD_NGRP(od) = 1
+ else
+ OD_GRP(od) = 1
+
+ # Get world coordinate information.
+ call od_wcs_open (od)
+
+ # That's all folks.
+ call sfree (sp)
+end
+#---------------------------------------------------------------------------
+# End of od_image_map
+#---------------------------------------------------------------------------
+procedure od_table_map (name, mode, old, od)
+
+char name[ARB] # I: The specified file name.
+int mode # I: The file access mode.
+pointer old # I: Original OD descriptor.
+pointer od # I: The OD I/O descriptor.
+
+# Declarations.
+int i, j, k # Generic.
+int ic # Pointer into section list.
+
+pointer colname # Current column name.
+pointer section # Section specification.
+pointer sp # Stack pointer.
+pointer sx # Generic.
+
+# Functions.
+int ctoi(), strlen(), word_count(), word_fetch(), tbpsta()
+pointer tbcnum(), tbtopn()
+
+errchk tbcnum, tbpsta, tbtopn, word_count, word_fetch
+
+begin
+ call smark (sp)
+ call salloc (colname, SZ_LINE, TY_CHAR)
+ call salloc (section, SZ_LINE, TY_CHAR)
+ call salloc (sx, SZ_LINE, TY_CHAR)
+
+ # Set what type of file.
+ OD_TYPE(od) = OD_TABLE
+
+ # Get the base filename and section.
+ call od_parse (name, OD_NAME(od), SZ_LINE, Memc[section], SZ_LINE)
+
+ # Open up and get some parameters.
+ OD_FD(od) = tbtopn (OD_NAME(od), mode, old)
+ OD_LEN(od) = tbpsta (OD_FD(od), TBL_NROWS)
+ OD_GRP(od) = 1
+ OD_MW(od) = NULL
+ OD_WL(od) = NULL
+ OD_LW(od) = NULL
+
+ # Now retrieve the columns. If no columns are specified, then use
+ # all the columns.
+ if (strlen (Memc[section]) <= 0) {
+ OD_NGRP(od) = tbpsta (OD_FD(od), TBL_NCOLS)
+ call malloc (OD_CD_PTR(od), OD_NGRP(od), TY_POINTER)
+ do i = 1, OD_NGRP(od) {
+ OD_CD(od,i) = tbcnum (OD_FD(od), i)
+ if (OD_CD(od,i) == NULL) {
+ call sprintf (Memc[sx], SZ_LINE, "Cannot open column %d in table %s")
+ call pargi (i)
+ call pargstr (OD_NAME(od))
+ call error (1, Memc[sx])
+ }
+ }
+ } else {
+ OD_NGRP(od) = word_count (Memc[section])
+ call malloc (OD_CD_PTR(od), OD_NGRP(od), TY_POINTER)
+ i = 0
+ ic = 1
+ while (word_fetch (Memc[section], ic, Memc[colname], SZ_LINE) > 0) {
+ i = i + 1
+ k = 1
+ if (ctoi (Memc[colname], k, j) > 0)
+ OD_CD(od,i) = tbcnum (OD_FD(od), j)
+ else
+ call tbcfnd (OD_FD(od), Memc[colname], OD_CD(od,i), 1)
+ }
+ if (OD_CD(od,i) == NULL) {
+ call sprintf (Memc[sx], SZ_LINE, "Cannot open column %s in table %s")
+ call pargstr (Memc[colname])
+ call pargstr (OD_NAME(od))
+ call error (1, Memc[sx])
+ }
+ }
+
+ # That's all folks.
+ call sfree (sp)
+end
+#---------------------------------------------------------------------------
+# End of od_table_map
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/od/odopep.x b/pkg/utilities/nttools/stxtools/od/odopep.x
new file mode 100644
index 00000000..cd757f93
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/od/odopep.x
@@ -0,0 +1,56 @@
+include "od.h"
+
+#---------------------------------------------------------------------------
+.help od_open_group 11Jul95 source
+.ih
+NAME
+od_open_group -- Open another "group" of the file
+.ih
+USAGE
+call od_open_group (od, group)
+.fi
+.ih
+ARGUMENTS
+.ls od (pointer :input)
+The OD I/O descriptor.
+.le
+.ls group (int :input)
+The "group" to open. For tables, this means the column number to open.
+.le
+.endhelp
+#---------------------------------------------------------------------------
+procedure od_open_group (od, group)
+
+pointer od # I: The 1D descriptor.
+int group # I: The group to open.
+
+# Misc.
+real rx # Generic.
+
+errchk gf_opengr, mw_close, od_wcs_open
+
+begin
+ switch (OD_TYPE(od)) {
+ case OD_TABLE:
+ if (group > OD_NGRP(od))
+ call error (1, "Attempt to open non-existant column")
+ OD_GRP(od) = group
+
+ case OD_IMAGE:
+ if (group > OD_NGRP(od))
+ call error (1, "Attempt to open non-existant group")
+
+ call mw_close (OD_MW(od))
+
+ if (OD_OLD(od) != NULL)
+ call gf_opengr (OD_FD(od), group, rx, rx, OD_FD(OD_OLD(od)))
+ else
+ call gf_opengr (OD_FD(od), group, rx, rx, NULL)
+ OD_GRP(od) = group
+
+ call od_wcs_open (od)
+ }
+end
+#---------------------------------------------------------------------------
+# End of od_open_group
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/od/odpare.x b/pkg/utilities/nttools/stxtools/od/odpare.x
new file mode 100644
index 00000000..0bea6112
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/od/odpare.x
@@ -0,0 +1,84 @@
+#---------------------------------------------------------------------------
+.help od_parse Feb93 source
+.ih
+NAME
+od_parse -- Parse a section for column names.
+.ih
+USAGE
+call od_parse
+.ih
+ARGUMENTS
+.ih
+DESCRIPTION
+Taken from Bernie Simon's aspare without any modifications.
+.endhelp
+#---------------------------------------------------------------------------
+#* HISTORY *
+#* D.Ball 18-Apr-88 original
+#* B.Simon 06-Aug-92 removed code which deletes commas
+
+# OD_PARSE -- Parse a file name specification into file name and section fields
+#
+# Syntax: filename[section]
+#
+# The [ character must be escaped to be included in the filename.
+# This syntax is similar to the image section syntax in imio, but
+# is intended to extract variable names or numbers, column names, etc.
+# for the Astronomical Survival analysis suite of programs.
+# The section field is returned as a string with no leading or trailing
+# brackets.
+
+procedure od_parse (filespec, file, sz_file, section, sz_section)
+
+char filespec[ARB] # i: full file specification
+char file[sz_file] # o: receives file name
+int sz_file # i: max chars in file name
+char section[sz_section] # o: receives section
+int sz_section # i: max chars in section name
+#--
+int ch, ip, op, right
+
+int strlen()
+
+begin
+ ip = 1
+ op = 1
+
+ # Extract file name. The first (unescaped) [ marks the start of
+ # the section field.
+
+ for (ch=filespec[ip]; ch != EOS && ch != '['; ch=filespec[ip]) {
+ if (ch == '\\' && filespec[ip+1] == '[') {
+ file[op] = '\\'
+ op = op + 1
+ file[op] = '['
+ ip = ip + 1
+ } else
+ file[op] = ch
+
+ op = min (sz_file, op + 1)
+ ip = ip + 1
+ }
+
+ file[op] = EOS
+ section[1] = EOS
+
+ if (ch == EOS)
+ return
+
+ # If we have a [...] field, copy the section string,
+ # removing the brackets, and any commas used as delimiters.
+
+ # Eliminate the leading "["
+ ip = ip + 1
+ call strcpy (filespec[ip], section, sz_section)
+
+ # Remove the trailing "]"
+ right = strlen (section)
+ if (section[right] == ']')
+ section[right] = EOS
+
+end
+#---------------------------------------------------------------------------
+# End of od_parse
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/od/odput.x b/pkg/utilities/nttools/stxtools/od/odput.x
new file mode 100644
index 00000000..d02f59a5
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/od/odput.x
@@ -0,0 +1,50 @@
+include "od.h"
+
+#---------------------------------------------------------------------------
+.help od_put Feb93 source
+.ih
+NAME
+od_put -- Put the data in the file.
+.ih
+USAGE
+.nf
+call od_putd (od, data)
+.fi
+.ih
+ARGUMENTS
+.ls od (input: pointer)
+The OD I/O descriptor.
+.le
+.ls data (input: double[ARB])
+The data to put in the OD file.
+.le
+.endhelp
+#---------------------------------------------------------------------------
+procedure od_put (od, data)
+
+pointer od # I: The OD I/O descriptor.
+double data[ARB] # I: The data.
+
+# Functions
+pointer impl1d()
+
+errchk impl1d, tbcptd
+
+begin
+ # Check if a file is actually opened. If not, do nothing.
+ if (od != NULL) {
+
+ # Get data depending on file type.
+ switch (OD_TYPE(od)) {
+ case OD_TABLE:
+ call tbcptd (OD_FD(od), OD_CD(od,OD_GRP(od)), data,
+ 1, OD_LEN(od))
+
+ case OD_IMAGE:
+ call amovd (data, Memd[impl1d (OD_FD(od))], OD_LEN(od))
+ }
+ }
+end
+#---------------------------------------------------------------------------
+# End of od_put
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/od/odsetn.x b/pkg/utilities/nttools/stxtools/od/odsetn.x
new file mode 100644
index 00000000..3abf97f7
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/od/odsetn.x
@@ -0,0 +1,29 @@
+include <imhdr.h>
+include "od.h"
+
+#---------------------------------------------------------------------------
+.help od_set_len Jun93 source
+.ih
+NAME
+od_set_len -- Set the length of data.
+.ih
+DESCRIPTION
+This sets how much data is read/written from the OD file. For images,
+the dimensionality is changed. For tables, it just changes how much
+is read/written; nothing is physically changed about the table.
+.endhelp
+#---------------------------------------------------------------------------
+procedure od_set_len (od, len)
+
+pointer od # I: OD descriptor.
+int len # I: New length.
+
+begin
+ OD_LEN(od) = len
+ if (OD_TYPE(od) == OD_IMAGE) {
+ IM_LEN(OD_FD(od),1) = len
+ }
+end
+#---------------------------------------------------------------------------
+# End of od_set_len
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/od/odunmp.x b/pkg/utilities/nttools/stxtools/od/odunmp.x
new file mode 100644
index 00000000..e776ecd7
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/od/odunmp.x
@@ -0,0 +1,44 @@
+include "od.h"
+
+#---------------------------------------------------------------------------
+.help od_unmap Feb93 source
+.ih
+NAME
+od_unmap -- Close the 1D image.
+.ih
+USAGE
+call od_unmap (od)
+.ih
+ARGUMENTS
+.ls od (input/output: pointer)
+The OD I/O descriptor. On return, the value will be NULL.
+.le
+.endhelp
+#---------------------------------------------------------------------------
+procedure od_unmap (od)
+
+pointer od # I: The OD I/O descriptor.
+
+errchk tbtclo, imunmap, mfree
+
+begin
+ if (od != NULL) {
+ switch (OD_TYPE(od)) {
+ case OD_TABLE:
+ call tbtclo (OD_FD(od))
+ call mfree (OD_CD_PTR(od), TY_POINTER)
+ case OD_IMAGE:
+ call mw_ctfree (OD_WL(od))
+ call mw_ctfree (OD_LW(od))
+ call mw_close (OD_MW(od))
+ call imunmap (OD_FD(od))
+ }
+
+ call mfree (OD_WSYS_PTR(od), TY_CHAR)
+ call mfree (OD_NAME_PTR(od), TY_CHAR)
+ call mfree (od, TY_STRUCT)
+ }
+end
+#---------------------------------------------------------------------------
+# End of od_unmap
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/od/odwcsn.x b/pkg/utilities/nttools/stxtools/od/odwcsn.x
new file mode 100644
index 00000000..e79a4154
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/od/odwcsn.x
@@ -0,0 +1,39 @@
+include <mwset.h>
+include "od.h"
+
+#---------------------------------------------------------------------------
+.help od_wcs_open May93 source
+.ih
+NAME
+od_wcs_open -- Open the WCS information for an image.
+.endhelp
+#---------------------------------------------------------------------------
+procedure od_wcs_open (od)
+
+pointer od # I: Image descriptor.
+
+pointer mw_openim()
+pointer mw_sctran()
+bool streq()
+
+begin
+ if (OD_TYPE(od) == OD_IMAGE) {
+ OD_MW(od) = mw_openim (OD_FD(od))
+ call mw_gwattrs (OD_MW(od), 0, "system", OD_WSYS(od), SZ_LINE)
+ if (streq ("multispec", OD_WSYS(od))) {
+ call mw_seti (OD_MW(od), MW_USEAXMAP, NO)
+ OD_WL(od) = mw_sctran (OD_MW(od), "multispec", "logical", 3b)
+ OD_LW(od) = mw_sctran (OD_MW(od), "logical", "multispec", 3b)
+ } else {
+ OD_WL(od) = mw_sctran (OD_MW(od), "world", "logical", 1)
+ OD_LW(od) = mw_sctran (OD_MW(od), "logical", "world", 1)
+ }
+ } else {
+ OD_MW(od) = NULL
+ OD_LW(od) = NULL
+ OD_WL(od) = NULL
+ }
+end
+#---------------------------------------------------------------------------
+# End of od_wcs_open
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/postexit.x b/pkg/utilities/nttools/stxtools/postexit.x
new file mode 100644
index 00000000..ebad32f9
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/postexit.x
@@ -0,0 +1,52 @@
+include <clset.h>
+
+# POST_EXIT_HANDLER -- Post an error handler that exits with an error code
+
+# The standard behavior of an iraf program is to exit with an error code
+# of zero regardless of whether program execution is halted with an error.
+# This behavior complicates control of tasks by user scripts. To change this
+# behavor, this procedure posts an error handler that exits the program with
+# its error code set to the value passed to the error procedure. The exit
+# procedure is only called of the program terminates with a non-zero error
+# status and the program is being run at the host level. The latter
+# restriction is in place because exiting a program running under the iraf
+# command language (cl) hangs the command language. Since error handlers
+# a run in the order that they are posted, this procedure should be called
+# after any other error handlers you may have in your program.
+#
+# Nelson Zarate 30-Nov-95 original
+
+procedure post_exit_handler ()
+
+#--
+extern exit_handler()
+int clstati()
+
+begin
+ # Only post the exit handler if the task is being run in host mode
+
+ if (clstati(CL_PRTYPE) == PR_HOST)
+ call onerror(exit_handler)
+end
+
+# EXIT_HANDLER -- Error handler that exits the program, setting the error code
+
+procedure exit_handler (status)
+
+int status # i: program exit status
+#--
+
+begin
+ # Only take exit if error status is non-zero (not OK)
+
+ if (status != OK) {
+ # Must clean up file i/o first
+ # The OK flag flushes the buffers
+
+ call fio_cleanup (OK)
+
+ # Take the error exit with the specified status
+
+ call errxit (status)
+ }
+end
diff --git a/pkg/utilities/nttools/stxtools/savgol.x b/pkg/utilities/nttools/stxtools/savgol.x
new file mode 100644
index 00000000..48958ede
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/savgol.x
@@ -0,0 +1,140 @@
+# Define some memory management.
+define A Memd[a+((($2)-1)*(m+1))+($1)-1]
+define B Memd[b+($1)-1]
+
+#---------------------------------------------------------------------------
+.help savgol Jun93 source
+.ih
+NAME
+savgol -- Create a kernel for Savitzky-Golay smoothing.
+.ih
+USAGE
+call savgol (c, np, nl, nr, ld, m)
+.ih
+ARGUMENTS
+.ls c (O: double[np])
+The smoothing kernel in "wrap-around" order. See discussion for
+details.
+.le
+.ls np (I: int)
+The number of points allocated in the array represented by the "c"
+argument.
+.le
+.ls nl (I: int)
+Size of the kernel "to the left" of the central point. See discussion
+for more details.
+.le
+.ls nr (I: int)
+Size of the kernel "to the right" of the central point. See discussion
+for more details.
+.le
+.ls ld (I: int)
+Order of the derivative desired. Should be 0 for smoothing, higher
+for smoothed versions of the specified derivative.
+.le
+.ls m (I: int)
+Order of the smoothing polynomial. Should be 0 or 1 for standard
+"boxcar" or "moving window" averaging.
+.le
+.ih
+DISCUSSION
+For an introduction to Savitzky-Golay filtering, see:
+
+.nf
+ Press, Teukolsky, Vetterling, & Falnnery, "Numeric Recipies:
+ The Art of Scientifitc Computing, Second Edition", Cambridge,
+ 1992.
+.fi
+
+This routine returns the set of Savitzky-Golay smoothing coefficients
+given the size, order of smoothing polynomial, and derivative to
+return. The coefficients are returned in "wrap-around" order. Thus,
+if the smoothing coefficients are C[-nl]...C[0]...C[nr], they are
+returned in the array, c[i], as follows:
+
+.nf
+ c[1], c[2], c[3], ..., c[nl+1],c[nl+2],...,c[np-1],c[np]
+
+ C[0], C[-1], C[-2],..., C[-nl], C[nr], ...,C[2], C[1]
+.fi
+
+A code fragment to transform the array c[i] to the orginal order,
+k[i], is:
+
+.nf
+ do i = 1, nl+1
+ k[i] = c[nl+2-i]
+ do i = 1, nr
+ k[nl+1+i] = c[np+1-i]
+.fi
+
+Array k[i], is now suitable for routines such as the IRAF VOPS routine
+acnvrd.
+.endhelp
+#---------------------------------------------------------------------------
+procedure savgol (c, np, nl, nr, ld, m)
+
+double c[np] # O: The kernel.
+int np # I: Size of the smoothing kernel.
+int nl # I: Points to the left of center.
+int nr # I: Points to the right of center.
+int ld # I: Order of derivative to return.
+int m # I: Order of the smoothing polynomial.
+
+int imj, ipj, j, k, kk, mm, ix
+double d, fac, sum
+pointer indx, a, b, sp
+int shifti()
+
+begin
+ call smark (sp)
+ # Check input parameters.
+ if (np < nl+nr+1 || nl < 0 || nr < 0 || ld > m || nl+nr < m)
+ call error (1, "savgol: invalid inputs")
+
+ # Allocate memory.
+ call salloc (indx, m+1, TY_INT)
+ call salloc (a, (m+1)**2, TY_DOUBLE)
+ call salloc (b, m+1, TY_DOUBLE)
+
+ # Do it.
+ ipj = shifti (m, 1)
+ do ipj = 0, shifti (m, 1) {
+ if (ipj != 0)
+ sum = 0.d0
+ else
+ sum = 1.d0
+ do k = 1, nr
+ sum = sum + k**ipj
+ do k = 1, nl
+ sum = sum + (-k)**ipj
+ mm = min (ipj, 2*m-ipj)
+ do imj = -mm, mm, 2
+ A(1+(ipj-imj)/2,1+(ipj+imj)/2) = sum
+ }
+ call ludcmd (Memd[a], m+1, m+1, Memi[indx], d, ix)
+ if (ix != OK)
+ call error (1, "savgol: singular matrix")
+ do j = 1, m+1
+ B(j) = 0.d0
+ B(ld+1) = 1.d0;
+ call lubksd (Memd[a], m+1, m+1, Memi[indx], Memd[b])
+ do kk = 1, np
+ c[kk] = 0.d0
+ do k = -nl, nr {
+ sum = B(1)
+ fac = 1.d0
+ do mm = 1, m {
+ fac = fac * k
+ sum = sum + B(mm+1) * fac
+ }
+ kk = mod (np - k, np) + 1
+ c[kk] = sum
+ }
+
+ # That's all folks.
+ call sfree (sp)
+end
+#---------------------------------------------------------------------------
+# End of savgol
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/sbuf.h b/pkg/utilities/nttools/stxtools/sbuf.h
new file mode 100644
index 00000000..cda82d9b
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/sbuf.h
@@ -0,0 +1,15 @@
+#---------------------------------------------------------------------------
+.help sbuf.h Feb93 source
+.ih
+NAME
+sbuf.h -- Memory structure for long strings.
+.endhelp
+#---------------------------------------------------------------------------
+define SB_LEN Memi[$1] # Current length of string.
+define SB_MAXLEN Memi[$1+1] # Current maximum size of buffer.
+define SB_PTR Memi[$1+2] # Pointer to the string array.
+define SB_BUF Memc[SB_PTR($1)+$2]
+define SB_SZ_SB 3 # Size of memory structure.
+#---------------------------------------------------------------------------
+# End of sbuf.h
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/sbuf.x b/pkg/utilities/nttools/stxtools/sbuf.x
new file mode 100644
index 00000000..a5bead52
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/sbuf.x
@@ -0,0 +1,110 @@
+include "sbuf.h"
+
+#---------------------------------------------------------------------------
+.help sbuf Mar93 source
+.ih
+NAME
+.nf
+sb_open -- Open an sbuf.
+sb_cat -- Add a string to the end of sbuf.
+sb_close -- Close an sbuf.
+sb_string -- Get the string to an sbuf.
+.fi
+.ih
+USAGE
+.nf
+sb = sb_open()
+call sb_cat (sb, str)
+call sb_close (sb)
+str_ptr = sb_string (sb)
+.fi
+.ih
+ARGUMENTS
+.ls sb (pointer :input/output)
+The string buffer descriptor.
+.le
+.ls str (char[ARB] :input)
+The string to append to the string buffer.
+.le
+.ls str_ptr (pointer :output)
+A pointer to a string array containing the contents of the string buffer.
+When done, the user is required to deallocate this memory using the call
+"call mfree (str_ptr, TY_CHAR)".
+.le
+.ih
+DISCUSSION
+This interface allows one to handle arbitrarily long strings without
+having to worry about the memory management.
+
+There may be other utility routines to add; feel free to do so.
+.endhelp
+#---------------------------------------------------------------------------
+pointer procedure sb_open
+
+pointer sb # The sbuf pointer
+
+errchk malloc
+
+begin
+ call malloc (sb, SB_SZ_SB, TY_STRUCT)
+ call malloc (SB_PTR(sb), SZ_LINE, TY_CHAR)
+ SB_LEN(sb) = 0
+ SB_MAXLEN(sb) = SZ_LINE
+
+ return (sb)
+end
+#---------------------------------------------------------------------------
+# End of sb_open
+#---------------------------------------------------------------------------
+procedure sb_close (sb)
+
+pointer sb # IO: The sbuf descriptor, NULL on exit.
+
+errchk mfree
+
+begin
+ if (sb != NULL) {
+ call mfree (SB_PTR(sb), TY_CHAR)
+ call mfree (sb, TY_STRUCT)
+ }
+end
+#---------------------------------------------------------------------------
+# End of sb_close
+#---------------------------------------------------------------------------
+pointer procedure sb_string (sb)
+
+pointer sb # I: The sbuf descriptor.
+
+pointer str # New string pointer.
+
+begin
+ call malloc (str, SB_LEN(sb), TY_CHAR)
+ call strcpy (SB_BUF(sb,0), Memc[str], SB_LEN(sb))
+
+ return (str)
+end
+#---------------------------------------------------------------------------
+# End of sb_string
+#---------------------------------------------------------------------------
+procedure sb_cat (sb, str)
+
+pointer sb # I: The sbuf descriptor.
+char str[ARB] # I: The string to concatenate.
+
+int i, strlen() # Length of input string.
+
+errchk realloc
+
+begin
+ i = strlen (str)
+ if (i + SB_LEN(sb) >= SB_MAXLEN(sb)) {
+ SB_MAXLEN(sb) = SB_MAXLEN(sb) + i + SZ_LINE
+ call realloc (SB_PTR(sb), SB_MAXLEN(sb), TY_CHAR)
+ }
+
+ call strcpy (str, SB_BUF(sb,SB_LEN(sb)), i)
+ SB_LEN(sb) = SB_LEN(sb) + i
+end
+#---------------------------------------------------------------------------
+# End of sb_cat
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/sgcone.x b/pkg/utilities/nttools/stxtools/sgcone.x
new file mode 100644
index 00000000..074f4089
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/sgcone.x
@@ -0,0 +1,94 @@
+#---------------------------------------------------------------------------
+.help sg_convolve Jun93 source
+.ih
+NAME
+sg_convolve -- Convolve an array using Savitzky-Golay filter.
+.ih
+USAGE
+call sg_convolve (size, order, in, out, n)
+.ih
+ARGUMENTS
+.ls size (I: int)
+The full size of the smoothing kernel. If less than or equal to 1,
+then no convolving takes place.
+.le
+.ls order (I: int)
+The order of the smoothing polynomial. For normal "boxcar" smoothing,
+this should be 0 or 1. Greater values preserve higher order terms in the
+original data. Larger sizes are needed for this to be effective.
+.le
+.ls in (I: double[n])
+The data array to be convolved.
+.le
+.ls out (O: double[n])
+The convolved array. May be the same as the input array.
+.le
+.ih
+DESCRIPTION
+The routine, savgol, is used to calculate a Savitsky-Golay convolving
+kernel. This kernel is then applied, using standard routines, to the
+input data. See the routine savgol for more information.
+.ih
+SEE ALSO
+savgol
+.endhelp
+#---------------------------------------------------------------------------
+procedure sg_convolve (size, order, in, out, n)
+
+int size # I: The size of the filter.
+int order # I: The order to preserve while filtering.
+double in[n] # I: Data to be convolved.
+double out[n] # O: The convolved data.
+int n # I: Length of the arrays.
+
+# Kernel parameters.
+int half # Half size of kernel.
+int isize # Odd size of kernel.
+pointer k, kx # The kernel in real/double-wrap versions.
+
+# Misc.
+pointer adx # Generic double array.
+int i # Generic.
+pointer sp # Stack pointer.
+
+begin
+ call smark (sp)
+
+ # Fix the kernel size to be odd.
+ half = size / 2
+ isize = half * 2 + 1
+
+ # Make sure there is something to convolve. If not, just copy and
+ # run.
+ if (isize <= 1)
+ call amovd (in, out, n)
+ else {
+ call salloc (k, isize, TY_REAL)
+ call salloc (kx, isize, TY_DOUBLE)
+ call salloc (adx, n+isize, TY_DOUBLE)
+
+ # Compute the kernel.
+ call savgol (Memd[kx], isize, half, half, 0, order)
+ do i = 0, half
+ Memr[k+i] = Memd[kx+half-i]
+ do i = 0, half-1
+ Memr[k+half+i+1] = Memd[kx+isize -i-1]
+
+ # Put the data in the extended array and pad the ends as
+ # constants.
+ call amovd (in, Memd[adx+half], n)
+ do i = 1, half {
+ Memd[adx+half-i] = in[1]
+ Memd[adx+half+n+i-1] = in[n]
+ }
+
+ # Filter it.
+ call acnvrd (Memd[adx], out, n, Memr[k], isize)
+ }
+
+ # That's all folks.
+ call sfree (sp)
+end
+#---------------------------------------------------------------------------
+# End of sg_convolve
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/similar.x b/pkg/utilities/nttools/stxtools/similar.x
new file mode 100644
index 00000000..a7b1a644
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/similar.x
@@ -0,0 +1,127 @@
+define SZ_STACK 25
+
+# SIMILAR -- Return a score base on the similarity between two strings
+
+# This procedure returns a number representing the similarity between
+# two strings. The number is computed by finding the combined length of
+# all the common substrings between the two strings, normalized to a value
+# between zero and one hundred.
+#
+# B.Simon 13-Mar-89 Original
+
+int procedure similar (str1, str2)
+
+char str1[ARB] # i: First string
+char str2[ARB] # i: Second string
+#--
+int score, istack, len1, len2, maxch, ic, nc
+pointer stack[4,SZ_STACK]
+pointer sp, word1, word2, s1, s2
+pointer start1, end1, start2, end2, newstart1, newend1, newstart2, newend2
+
+string overflow "Stack overflow in procedure similar"
+
+int strlen()
+
+begin
+ # If either string is zero length, return zero as score
+
+ score = 0
+ len1 = strlen (str1)
+ len2 = strlen (str2)
+ if (len1 == 0 || len2 == 0)
+ return (score)
+
+ # Compare the lower case version of the strings
+
+ call smark (sp)
+ call salloc (word1, len1, TY_CHAR)
+ call salloc (word2, len2, TY_CHAR)
+
+ call strcpy (str1, Memc[word1], len1)
+ call strlwr (Memc[word1])
+
+ call strcpy (str2, Memc[word2], len2)
+ call strlwr (Memc[word2])
+
+ # The first substrings to compare are the entire strings
+
+ istack = 1
+ stack[1,istack] = word1
+ stack[2,istack] = word1 + len1 - 1
+ stack[3,istack] = word2
+ stack[4,istack] = word2 + len2 - 1
+
+ # While there are more substrings on the stack
+
+ while (istack > 0) {
+
+ # Find the longest match between the substrings
+
+ maxch = 0
+ start1 = stack[1,istack]
+ end1 = stack[2,istack]
+ start2 = stack[3,istack]
+ end2 = stack[4,istack]
+
+ for (s1 = start1; s1 <= end1 - maxch; s1 = s1 + 1) {
+
+ nc = end1 - s1
+
+ for (s2 = start2; s2 <= end2 - maxch; s2 = s2 + 1) {
+
+ if (Memc[s1] == Memc[s2]) {
+
+ # Compute the length of the match
+
+ for (ic = 1;
+ ic <= nc && Memc[s1+ic] == Memc[s2+ic];
+ ic = ic + 1)
+ ;
+
+ # If this is the longest match so far, save
+ # the length and start and end points
+
+ if (ic > maxch) {
+ maxch = ic
+ newstart1 = s1
+ newstart2 = s2
+ newend1 = s1 + ic - 1
+ newend2 = s2 + ic - 1
+ }
+ s2 = s2 + ic - 1
+ }
+ }
+ }
+
+ # Pop the stack and push the new substings on the stack
+
+ istack = istack - 1
+ if (maxch > 0) {
+ score = score + 2 * maxch
+
+ if (start1 != newstart1 && start2 != newstart2) {
+ if (istack == SZ_STACK)
+ call error (1, overflow)
+ istack = istack + 1
+ stack[1,istack] = start1
+ stack[2,istack] = newstart1 - 1
+ stack[3,istack] = start2
+ stack[4,istack] = newstart2 - 1
+ }
+
+ if (end1 != newend1 && end2 != newend2) {
+ if (istack == SZ_STACK)
+ call error (1, overflow)
+ istack = istack + 1
+ stack[1,istack] = newend1 + 1
+ stack[2,istack] = end1
+ stack[3,istack] = newend2 + 1
+ stack[4,istack] = end2
+ }
+ }
+ }
+
+ call sfree (sp)
+ return (100 * score / (len1 + len2))
+end
diff --git a/pkg/utilities/nttools/stxtools/sp_util/mkpkg b/pkg/utilities/nttools/stxtools/sp_util/mkpkg
new file mode 100644
index 00000000..52a93adb
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/sp_util/mkpkg
@@ -0,0 +1,16 @@
+# Make the wcslab package
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ spchag.x
+ spdise.x
+ spmapt.x <gset.h>
+ sprote.x <math.h>
+ spstry.x
+ sptras.x
+ spw2ld.x
+ spwcss.x <ctype.h>
diff --git a/pkg/utilities/nttools/stxtools/sp_util/spchag.x b/pkg/utilities/nttools/stxtools/sp_util/spchag.x
new file mode 100644
index 00000000..f6292a4e
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/sp_util/spchag.x
@@ -0,0 +1,64 @@
+# sp_change_string - Replace a string with the indicated string.
+#
+# History
+# 1Apr91 - Created by Jonathan D. Eisenhamer, STScI.
+#---------------------------------------------------------------------------
+
+procedure sp_change_string( input, old, new, output, max )
+
+char input[ARB] # I: The input string.
+char old[ARB] # I: The string segment to be replaced.
+char new[ARB] # I: The string to replace the old with.
+char output[ARB] # O: The modified input string.
+int max # I: The maximun length of the output string.
+
+# Declarations.
+int after # Next character position after match.
+int first # First character position of matched string.
+int ilen # Length of input.
+int ip # Pointer into input.
+int last # Last character position of matched string.
+int old_len # Length of old.
+int op # Pointer into output.
+
+# Function declarations.
+int gstrcpy(), strlen(), gstrmatch()
+
+begin
+
+ # Initialize the string pointers.
+ ip = 1
+ op = 1
+ ilen = strlen( input )
+ old_len = strlen( old )
+
+ # Keep going until either the input string has been completely copied
+ # or the output string is full.
+ while( ip < ( ilen + 1 ) && op < ( max + 1 ) ) {
+
+ # Search for the old string.
+ after = gstrmatch( input[ip], old, first, last )
+
+ # If the string is not found, then copy the rest of the input to the
+ # output.
+ if( after == 0 ) {
+ call strcpy( input[ip], output[op], max - op + 1 )
+ ip = ilen + 1
+ }
+
+ # The old string is found, copy the input up to the old string
+ # and replace the old string.
+ else {
+ first = min( first - 1, max - op + 1 )
+ call sp_strncpy( input[ip], first, output[op] )
+ ip = ip + last
+ op = op + first
+ op = op + gstrcpy( new, output[op], max - op + 1 )
+ }
+
+ }
+
+end
+#---------------------------------------------------------------------------
+# End of sp_change_string
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/sp_util/spdise.x b/pkg/utilities/nttools/stxtools/sp_util/spdise.x
new file mode 100644
index 00000000..9985c790
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/sp_util/spdise.x
@@ -0,0 +1,44 @@
+# sp_distanced - Determine the distance between two points.
+#
+# History
+# 4Dec90 - Created by Jonathan D. Eisenhamer, STScI.
+#---------------------------------------------------------------------------
+
+double procedure sp_distanced( x1, y1, x2, y2 )
+
+double x1, y1, x2, y2
+
+double a, b
+
+begin
+
+ a = x1 - x2
+ b = y1 - y2
+ return( sqrt( ( a * a ) + ( b * b ) ) )
+
+end
+#---------------------------------------------------------------------------
+# End of sp_distanced
+#---------------------------------------------------------------------------
+# sp_distancer - Determine the distance between two points.
+#
+# History
+# 4Dec90 - Created by Jonathan D. Eisenhamer, STScI.
+#---------------------------------------------------------------------------
+
+real procedure sp_distancer( x1, y1, x2, y2 )
+
+real x1, y1, x2, y2
+
+real a, b
+
+begin
+
+ a = x1 - x2
+ b = y1 - y2
+ return( sqrt( ( a * a ) + ( b * b ) ) )
+
+end
+#---------------------------------------------------------------------------
+# End of sp_distancer
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/sp_util/spmapt.x b/pkg/utilities/nttools/stxtools/sp_util/spmapt.x
new file mode 100644
index 00000000..cef87fed
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/sp_util/spmapt.x
@@ -0,0 +1,94 @@
+include <gset.h>
+
+# Default viewport edges.
+define EDGE1 0.1
+define EDGE2 0.9
+define EDGE3 0.12
+define EDGE4 0.85
+
+#---------------------------------------------------------------------------
+.help sp_map_viewport Sep92 source
+.ih
+NAME
+sp_map_viewport -- set device viewport for contour plots.
+.endhelp
+#---------------------------------------------------------------------------
+
+procedure sp_map_viewport (gp, ncols, nlines, ux1, ux2, uy1, uy2, pre, perim)
+
+pointer gp # I: pointer to graphics descriptor
+real ncols, nlines # I: size of image area, after block reduction
+real ux1, ux2, uy1, uy2 # I: NDC coordinates of requested viewort
+bool pre # I: Preserve aspect ratio.
+bool perim # I: draw perimeter
+
+real xcen, ycen, x, y
+real aspect_ratio
+real x1, x2, y1, y2, ext, xdis, ydis
+data ext /0.0625/
+real ggetr()
+
+begin
+ # Determine the standard window sizes.
+ if (!pre && !perim) {
+ x1 = 0.0; x2 = 1.0
+ y1 = 0.0; y2 = 1.0
+ } else {
+ x1 = EDGE1; x2 = EDGE2
+ y1 = EDGE3; y2 = EDGE4
+
+ }
+
+ # If any values were specified, then replace them here.
+ if( !IS_INDEFR( ux1 ) )
+ x1 = ux1
+ if( !IS_INDEFR( ux2 ) )
+ x2 = ux2
+ if( !IS_INDEFR( uy1 ) )
+ y1 = uy1
+ if( !IS_INDEFR( uy2 ) )
+ y2 = uy2
+
+ xdis = x2 - x1
+ ydis = y2 - y1
+ xcen = ( x2 + x1 ) / 2.
+ ycen = ( y2 + y1 ) / 2.
+
+ # So far, the viewport has been calculated so that equal numbers of
+ # image pixels map to equal distances in NDC space, regardless of
+ # the aspect ratio of the device. If preserving aspect ratio,
+ # modify viewport to correctly display the contour aspect.
+ if (pre) {
+ aspect_ratio = ggetr (gp, "ar")
+ if (aspect_ratio == 0.0) {
+ x = ggetr (gp, "xr")
+ y = ggetr (gp, "yr")
+ if ( x != 0.0 && y != 0.0)
+ aspect_ratio = y / x
+ else
+ aspect_ratio = 1.0
+ }
+ aspect_ratio = nlines / ncols / aspect_ratio
+ x = ydis / aspect_ratio
+ y = ydis
+ if ( x > xdis) {
+ y = aspect_ratio * xdis
+ x = xdis
+ }
+ xdis = x
+ ydis = y
+ }
+
+ # All set.
+ ux1 = xcen - (xdis / 2.0)
+ ux2 = xcen + (xdis / 2.0)
+ uy1 = ycen - (ydis / 2.0)
+ uy2 = ycen + (ydis / 2.0)
+
+ call gsview (gp, ux1, ux2, uy1, uy2)
+ call gswind (gp, 1.0, ncols, 1.0, nlines)
+
+end
+#---------------------------------------------------------------------------
+# End of sp_map_viewport
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/sp_util/sprote.x b/pkg/utilities/nttools/stxtools/sp_util/sprote.x
new file mode 100644
index 00000000..c9baeb65
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/sp_util/sprote.x
@@ -0,0 +1,49 @@
+include <math.h>
+
+# The dimensionality.
+define N_DIM 2
+
+# Define some memory management.
+define ONER Memr[$1+$2-1]
+
+# sp_rotate - Rotate a vector.
+#
+# History
+# 8Mar91 - Created by Jonathan D. Eisenhamer, STScI.
+#---------------------------------------------------------------------------
+
+procedure sp_rotate( x, y, npts, angle, nx, ny )
+
+real x[npts], y[npts] # I: The vectors to rotate.
+int npts # I: The number of points in the vectors.
+real angle # I: The angle to rotate (radians).
+real nx[npts], ny[npts] # O: The translated vectors.
+
+# Declarations
+pointer center # To specify the center.
+pointer mw # MWCS structure.
+pointer sp # Stack pointer.
+
+# Function prototypes.
+pointer mw_open(), mw_sctran()
+
+begin
+
+ # Suck some memory.
+ call smark( sp )
+ call salloc( center, N_DIM, TY_REAL )
+
+ mw = mw_open( NULL, N_DIM )
+ ONER(center,1) = 0.
+ ONER(center,2) = 0.
+ call mw_rotate( mw, -DEGTORAD( angle ), ONER(center,1), 3b )
+ call mw_v2tranr( mw_sctran( mw, "physical", "logical", 3b ),
+ x, y, nx, ny, npts )
+
+ call mw_close( mw )
+ call sfree( sp )
+
+end
+#---------------------------------------------------------------------------
+# End of sp_rotate
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/sp_util/spstry.x b/pkg/utilities/nttools/stxtools/sp_util/spstry.x
new file mode 100644
index 00000000..545b0b06
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/sp_util/spstry.x
@@ -0,0 +1,24 @@
+# sp_strncpy - Counted character copy.
+#
+# History
+# 1Apr91 - Created by Jonathan D. Eisenhamer, STScI.
+#---------------------------------------------------------------------------
+
+procedure sp_strncpy( input, n_chars, output )
+
+char input[ARB] # I: The input string to copy to the output.
+int n_chars # I: The number of characters to copy.
+char output[ARB] # O: The output string.
+
+# Declarations.
+int i # Index.
+
+begin
+
+ for( i = 1; i <= n_chars; i = i + 1 )
+ output[i] = input[i]
+
+end
+#---------------------------------------------------------------------------
+# End of sp_strncpy.
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/sp_util/sptras.x b/pkg/utilities/nttools/stxtools/sp_util/sptras.x
new file mode 100644
index 00000000..f62e9ceb
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/sp_util/sptras.x
@@ -0,0 +1,35 @@
+# Set the dimensionality
+define N_DIM 2
+
+# sp_trans - Translate the origin to a new center.
+#
+# History
+# 11Mar91 - Created by Jonathan D. Eisenhamer, STScI.
+#---------------------------------------------------------------------------
+
+procedure sp_trans( x, y, npts, center, nx, ny )
+
+real x[npts], y[npts] # I: The x, y vectors to translate.
+int npts # I: The number of points in the vectors.
+real center[N_DIM] # I: The new coordinate center.
+real nx[npts], ny[npts] # O: The translated vectors.
+
+# Declarations
+pointer mw # MWCS structure.
+
+# Function prototypes.
+pointer mw_open(), mw_sctran()
+
+begin
+
+ mw = mw_open( NULL, N_DIM )
+ call mw_shift( mw, center, 3b )
+ call mw_v2tranr( mw_sctran( mw, "physical", "logical", 3b ),
+ x, y, nx, ny, npts )
+
+ call mw_close( mw )
+
+end
+#---------------------------------------------------------------------------
+# End of sp_trans
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/sp_util/spw2ld.x b/pkg/utilities/nttools/stxtools/sp_util/spw2ld.x
new file mode 100644
index 00000000..a31ce22d
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/sp_util/spw2ld.x
@@ -0,0 +1,50 @@
+# sp_w2ld - Transform world coordinates to logical coordinates (double).
+#
+# History
+# 24Jun91 - Created by Jonathan D. Eisenhamer, STScI.
+#---------------------------------------------------------------------------
+
+procedure sp_w2ld( wlct, flip, wx, wy, lx, ly, npts )
+
+pointer wlct # I: The MWCS coordinate trans. descriptor.
+bool flip # I: True if the axes are transposed.
+double wx[npts], wy[npts] # I: The world coordinates.
+double lx[npts], ly[npts] # O: The logical coordinates.
+int npts # I: The number of points to translate.
+
+begin
+
+ if( flip )
+ call mw_v2trand( wlct, wx, wy, ly, lx, npts )
+ else
+ call mw_v2trand( wlct, wx, wy, lx, ly, npts )
+
+end
+#---------------------------------------------------------------------------
+# End of sp_w2ld
+#---------------------------------------------------------------------------
+# sp_l2wd - Transform logical coordinates to world coordinates (double).
+#
+# History
+# 24Jun91 - Created by Jonathan D. Eisenhamer, STScI.
+#---------------------------------------------------------------------------
+
+procedure sp_l2wd( lwct, flip, lx, ly, wx, wy, npts )
+
+pointer lwct # I: The MWCS coordinate trans. descriptor.
+bool flip # I: True if the axes are transposed.
+double lx[npts], ly[npts] # I: The logical coordinates.
+double wx[npts], wy[npts] # O: The world coordinates.
+int npts # I: The number of points to translate.
+
+begin
+
+ if( flip )
+ call mw_v2trand( lwct, ly, lx, wx, wy, npts )
+ else
+ call mw_v2trand( lwct, lx, ly, wx, wy, npts )
+
+end
+#---------------------------------------------------------------------------
+# End of sp_l2wd
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/sp_util/spwcss.x b/pkg/utilities/nttools/stxtools/sp_util/spwcss.x
new file mode 100644
index 00000000..bb2feb49
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/sp_util/spwcss.x
@@ -0,0 +1,90 @@
+include <ctype.h>
+include <imhdr.h>
+
+#---------------------------------------------------------------------------
+.help sp_wcsparams 3Aug95 source
+.ih
+NAME
+sp_wcsparams -- Read the WCS descriptor from the parameters.
+.ih
+DESCRIPTION
+This procedure returns the WCS descriptor created from task parameters
+and the logical space that will be graphed.
+.ih
+BUGS
+This only deals with two axes.
+.endhelp
+#---------------------------------------------------------------------------
+procedure sp_wcsparams( mw, log_x1, log_x2, log_y1, log_y2 )
+
+pointer mw # O: The MWCS descriptor.
+real log_x1, log_x2,
+ log_y1, log_y2 # O: The extent of the logical space to graph.
+
+# Declarations.
+pointer b # Buffer pointer.
+double clgetd() # Get double-valued parameter.
+real clgetr() # Get real-valued parameter.
+pointer im # Temporary image descriptor.
+pointer immap() # Open an image.
+pointer impl2s() # Put line in 2d image.
+pointer imw # Temporary MWCS descriptor.
+pointer mw_newcopy() # Copy MWCS descriptor.
+pointer mw_openim() # Get MWCS descriptor from image.
+char s[SZ_LINE] # Generic string.
+
+string tmpimage ".SPWCSS"
+
+begin
+ # Since no one knows how mwcs really works, we cheat.
+ # Create an image and set the header keywords to what
+ # the parameters are. Then use the image load to get the
+ # mwcs instead of trying to create it from scratch.
+
+ # Create an image.
+ iferr (call imdelete (tmpimage))
+ ;
+ im = immap (tmpimage, NEW_IMAGE, 20000)
+ IM_NDIM(im) = 2
+ IM_LEN(im,1) = 1
+ IM_LEN(im,2) = 1
+ IM_PIXTYPE(im) = TY_SHORT
+
+ # Now populate the WCS-relevant keywords.
+ call clgstr ("ctype1", s, SZ_LINE)
+ call imastr (im, "ctype1", s)
+ call clgstr ("ctype2", s, SZ_LINE)
+ call imastr (im, "ctype2", s)
+ call imaddd (im, "crpix1", clgetd ("crpix1"))
+ call imaddd (im, "crpix2", clgetd ("crpix2"))
+ call imaddd (im, "crval1", clgetd ("crval1"))
+ call imaddd (im, "crval2", clgetd ("crval2"))
+ call imaddd (im, "cd1_1", clgetd ("cd1_1"))
+ call imaddd (im, "cd1_2", clgetd ("cd1_2"))
+ call imaddd (im, "cd2_1", clgetd ("cd2_1"))
+ call imaddd (im, "cd2_2", clgetd ("cd2_2"))
+
+ # Write a pixel, close and reopen the image.
+ b = impl2s (im, 1)
+ call imunmap (im)
+ im = immap (tmpimage, READ_ONLY, 0)
+
+ # Retrieve the MWCS descriptor. Make a copy so we can close the
+ # temporary image.
+ imw = mw_openim (im)
+ mw = mw_newcopy (imw)
+
+ # Get the logical workspace.
+ log_x1 = clgetr ("log_x1")
+ log_x2 = clgetr ("log_x2")
+ log_y1 = clgetr ("log_y1")
+ log_y2 = clgetr ("log_y2")
+
+ # That's all folks.
+ call mw_close (imw)
+ call imunmap (im)
+ call imdelete (tmpimage)
+end
+#---------------------------------------------------------------------------
+# End of sp_wcsparams
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/strjust.x b/pkg/utilities/nttools/stxtools/strjust.x
new file mode 100644
index 00000000..5f50f080
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/strjust.x
@@ -0,0 +1,31 @@
+include <ctype.h>
+
+# STRJUST -- Remove whitspace from a string and convert to lower case
+#
+# B.Simon 30-Jan-95 copied from synphot$strfix
+
+procedure strjust (str)
+
+char str[ARB] # u: string to convert
+#--
+int ic, jc
+
+begin
+ jc = 1
+ for (ic = 1; str[ic] != EOS; ic = ic + 1) {
+ if (IS_WHITE(str[ic]))
+ next
+
+ if (IS_UPPER(str[ic])) {
+ str[jc] = TO_LOWER(str[ic])
+
+ } else if (jc < ic) {
+ str[jc] = str[ic]
+ }
+
+ jc = jc + 1
+ }
+
+ str[jc] = EOS
+end
+
diff --git a/pkg/utilities/nttools/stxtools/stxgetcoord.x b/pkg/utilities/nttools/stxtools/stxgetcoord.x
new file mode 100644
index 00000000..0fc9842c
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/stxgetcoord.x
@@ -0,0 +1,182 @@
+include <imhdr.h>
+include <mwset.h>
+include <math.h>
+
+define SZ_PNAME 8
+
+# stx_getcoord -- get coordinate parameters
+# This procedure gets the coordinate parameters from an image.
+# The parameter values are gotten via mwcs, and the lterm is factored
+# into the wterm so that the parameters are relative to the actual image
+# section that was opened rather than to the "original" image.
+#
+# Phil Hodge, 5-Jan-1993 Copied from fourier$lib/loadct.x.
+# Phil Hodge, 2-Feb-1994 Errchk mwcs routines.
+
+procedure stx_getcoord (im, crpix, crval, cd, maxdim, ctype, maxch)
+
+pointer im # i: pointer to imhdr struct for input image
+double crpix[ARB] # o: reference pixel
+double crval[ARB] # o: coordinates at reference pixel
+double cd[maxdim,maxdim] # o: derivatives of l & m with respect to x & y
+int maxdim # i: dimension of arrays (e.g. IM_MAXDIM)
+char ctype[maxch,maxdim] # o: coord. type of each axis (e.g. "RA---TAN")
+int maxch # i: size of ctype string (e.g. SZ_CTYPE)
+#--
+pointer mw
+
+double o_crval[IM_MAXDIM] # world coordinates at reference pixel
+double o_crpix[IM_MAXDIM] # not corrected for image section
+double o_cd[IM_MAXDIM,IM_MAXDIM] # wterm only (not corr. for section)
+
+double n_crpix[IM_MAXDIM] # corrected for image section
+double n_cd[IM_MAXDIM,IM_MAXDIM] # CD matrix corrected for section
+
+double ltm[IM_MAXDIM,IM_MAXDIM] # lterm matrix
+double i_ltm[IM_MAXDIM,IM_MAXDIM] # inverse of ltm
+double ltv[IM_MAXDIM] # lterm vector
+
+int ndim # dimension of image
+int wcsdim # dimension of mwcs coordinates
+pointer mw_openim()
+int mw_stati()
+errchk mw_openim, mw_stati, mw_gwtermd, mw_gltermd, mw_invertd, mw_close,
+ stx_extract
+
+begin
+ ndim = IM_NDIM(im)
+ if (ndim > maxdim)
+ call error (1,
+ "stx_getcoord: dimension of image is larger than array size")
+
+ mw = mw_openim (im)
+ wcsdim = mw_stati (mw, MW_NPHYSDIM) # get mwcs dimension
+
+ # Get the wterm and the lterm.
+ call mw_gwtermd (mw, o_crpix, o_crval, o_cd, wcsdim)
+ call mw_gltermd (mw, ltm, ltv, wcsdim)
+
+ # Convert the wterm to be the values relative to the current
+ # image section. (Comments & code copied from mwcs.)
+
+ # Output CRPIX = R' = (LTM * R + LTV).
+ call mw_vmuld (ltm, o_crpix, n_crpix, wcsdim)
+ call aaddd (ltv, n_crpix, n_crpix, wcsdim)
+
+ # Output CD matrix = CD' = (CD * inv(LTM)).
+ call mw_invertd (ltm, i_ltm, wcsdim)
+ call mw_mmuld (o_cd, i_ltm, n_cd, wcsdim)
+
+ # Extract the coordinate parameters, and get ctype.
+ call stx_extract (im, mw, n_crpix, o_crval, n_cd, wcsdim,
+ crpix, crval, cd, maxdim, ctype, maxch)
+
+ call mw_close (mw)
+
+ # Check for invalid CD matrix.
+ if (ndim == 1) {
+ if (cd[1,1] == 0.d0) {
+ call eprintf ("warning: pixel spacing = 0; reset to 1\n")
+ cd[1,1] = 1.d0
+ }
+ } else if (ndim == 2) {
+ if (cd[1,1] * cd[2,2] - cd[1,2] * cd[2,1] == 0.d0) {
+ call eprintf (
+ "warning: CD matrix is singular; reset to identity matrix\n")
+ cd[1,1] = 1.d0
+ cd[2,1] = 0.d0
+ cd[1,2] = 0.d0
+ cd[2,2] = 1.d0
+ }
+ }
+end
+
+# stx_extract -- extract coordinate parameters
+# This routine is needed to take care of the situation where the dimension
+# of the input image was reduced by taking an image section. In that case,
+# the coordinate information gotten using mwcs has the dimension of the
+# original image, which results in two problems. (1) We need to know which
+# axis of the original image maps to which axis of the image that we've
+# got. (2) We have to dimension the CD matrix differently. When MWCS
+# puts values into a 2-D array it is dimensioned wcsdim X wcsdim, but we
+# declared it maxdim X maxdim in the calling routine. In this routine
+# we declare the input CD matrix to be wcsdim X wcsdim, while the output
+# CD matrix is maxdim X maxdim.
+
+procedure stx_extract (im, mw, n_crpix, n_crval, n_cd, wcsdim,
+ crpix, crval, cd, maxdim, ctype, maxch)
+
+pointer im # i: pointer to imhdr struct for input image
+pointer mw # i: mwcs pointer
+double n_crpix[wcsdim] # i: crpix
+double n_crval[wcsdim] # i: crval
+double n_cd[wcsdim,wcsdim] # i: CD matrix
+int wcsdim # i: dimension of wcs
+double crpix[maxdim] # o: crpix extracted from n_crpix
+double crval[maxdim] # o: crval extracted from n_crval
+double cd[maxdim,maxdim] # o: CD matrix extracted from n_cd
+int maxdim # i: dimension of arrays (e.g. IM_MAXDIM)
+char ctype[maxch,maxdim] # o: coord. type of each axis (e.g. "RA---TAN")
+int maxch # i: size of ctype string (e.g. SZ_CTYPE)
+#--
+char keyword[SZ_PNAME] # keyword for getting ctype
+int ndim # actual dimension of image
+int axno[IM_MAXDIM] # axis numbers
+int axval[IM_MAXDIM] # ignored
+int ax[IM_MAXDIM] # physical axis number for each logical axis
+int i, j
+bool ax_ok # for checking that axis numbers were found
+int imaccf()
+errchk mw_gaxmap
+
+begin
+ ndim = IM_NDIM(im)
+
+ # Get the axis mapping.
+ call mw_gaxmap (mw, axno, axval, wcsdim)
+
+ # Find the image axis numbers corresponding to the mwcs numbers.
+ do i = 1, ndim # initialize
+ ax[i] = 0
+ do j = 1, wcsdim {
+ do i = 1, ndim {
+ if (axno[j] == i) {
+ ax[i] = j
+ break
+ }
+ }
+ }
+
+ # It's an error if any axis number was not found.
+ ax_ok = true # initial value
+ do i = 1, ndim {
+ if (ax[i] < 1)
+ ax_ok = false
+ }
+ if (!ax_ok) {
+# call error (1, "stx_extract: mwcs axis mapping is messed up")
+# This is a temporary fix to prevent crashing on a vax.
+ do i = 1, ndim
+ ax[i] = i
+ }
+
+ # Extract crpix, crval and the CD matrix.
+ # Note that we transpose the CD matrix because of different
+ # conventions regarding how a matrix is stored.
+ do i = 1, ndim {
+ crpix[i] = n_crpix[ax[i]]
+ crval[i] = n_crval[ax[i]]
+ do j = 1, ndim
+ cd[i,j] = n_cd[ax[j],ax[i]] # transpose
+ }
+
+ # Get ctype.
+ do i = 1, ndim {
+ call sprintf (keyword, SZ_PNAME, "ctype%d")
+ call pargi (ax[i]) # physical axis number
+ if (imaccf (im, keyword) == YES)
+ call imgstr (im, keyword, ctype[1,i], maxch)
+ else
+ call strcpy ("PIXEL", ctype[1,i], maxch)
+ }
+end
diff --git a/pkg/utilities/nttools/stxtools/template.h b/pkg/utilities/nttools/stxtools/template.h
new file mode 100644
index 00000000..9df66f37
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/template.h
@@ -0,0 +1,21 @@
+# TEMPLATE.H -- Structure used to expand image names over groups
+
+define LEN_TPSTRUCT 5
+
+define TP_ROOTPTR Memi[$1] # Pointer to image root name
+define TP_SECTPTR Memi[$1+1] # Pointer to image section
+define TP_START Memi[$1+2] # First group
+define TP_COUNT Memi[$1+3] # Total number of groups
+define TP_INDEX Memi[$1+4] # Current group
+
+define TP_ROOT Memc[TP_ROOTPTR($1)]
+define TP_SECT Memc[TP_SECTPTR($1)]
+
+define TP_EXT_LIST "|stf|fxf|oif|plf|qpf|"
+
+define TP_UNKNOWN 0
+define TP_GEIS 1
+define TP_FITS 2
+define TP_IRAF 3
+define TP_PIXLIST 4
+define TP_QPOE 5
diff --git a/pkg/utilities/nttools/stxtools/tpbreak.x b/pkg/utilities/nttools/stxtools/tpbreak.x
new file mode 100644
index 00000000..be5aed1d
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/tpbreak.x
@@ -0,0 +1,80 @@
+# TP_BREAK -- Break an image name into bracket delimeted substrings
+#
+# B.Simon 02-Jun-89 Original
+
+procedure tp_break (imname, part, npart, maxch)
+
+char imname[ARB] # i: Image name
+char part[maxch,ARB] # o: Array of image name parts
+int npart # i: Maximum number of parts
+int maxch # i: Maximum length of part
+#--
+bool inside
+char ch
+int ic, jc, ipart
+pointer sp, errmsg
+
+string syntax "Syntax error in image name (%s)"
+
+begin
+ # Allocate memory for error message
+
+ call smark (sp)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ # Initialize output to null string
+
+ do ipart = 1, npart
+ part[1,ipart] = EOS
+
+ # Break image name into bracket delimeted components
+ # The variable inside is used as a check that brackets are paired
+
+ jc = 1
+ ipart = 1
+ inside = false
+
+ for (ic = 1; ipart <= npart && imname[ic] != EOS; ic = ic + 1) {
+
+ ch = imname[ic]
+ if (ch == '\\') {
+ ic = ic + 1
+
+ } else if (ch == '[') {
+ if (inside) {
+ call sprintf (Memc[errmsg], SZ_LINE, syntax)
+ call pargstr (imname)
+ call error (1, Memc[errmsg])
+ }
+ part[jc,ipart] = EOS
+ ipart = ipart + 1
+ inside = true
+ jc = 1
+
+ } else if (ch == ']') {
+ if (! inside) {
+ call sprintf (Memc[errmsg], SZ_LINE, syntax)
+ call pargstr (imname)
+ call error (1, Memc[errmsg])
+ }
+ inside = false
+
+ } else if (ipart > 1 && ! inside) {
+ call sprintf (Memc[errmsg], SZ_LINE, syntax)
+ call pargstr (imname)
+ call error (1, Memc[errmsg])
+ }
+
+ part[jc,ipart] = imname[ic]
+ jc = jc + 1
+
+ if (jc > maxch) {
+ call sprintf (Memc[errmsg], SZ_LINE, syntax)
+ call pargstr (imname)
+ call error (1, Memc[errmsg])
+ }
+ }
+
+ part[jc,ipart] = EOS
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/stxtools/tpclose.x b/pkg/utilities/nttools/stxtools/tpclose.x
new file mode 100644
index 00000000..8afac19c
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/tpclose.x
@@ -0,0 +1,21 @@
+include "template.h"
+
+# TP_CLOSE -- Close the group template expansion routines
+
+# Free the dynamic memory used to store the group template structure
+#
+# B.Simon 28-Feb-89 Original
+# B.Simon 21-Aug-91 Changed template structure
+
+procedure tp_close (ptr)
+
+pointer ptr # u: Pointer to list of file names
+#--
+errchk mfree
+
+begin
+ call mfree (TP_ROOTPTR(ptr), TY_CHAR)
+ call mfree (TP_SECTPTR(ptr), TY_CHAR)
+ call mfree (ptr, TY_STRUCT)
+ ptr = NULL
+end
diff --git a/pkg/utilities/nttools/stxtools/tpcount.x b/pkg/utilities/nttools/stxtools/tpcount.x
new file mode 100644
index 00000000..f233aa26
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/tpcount.x
@@ -0,0 +1,134 @@
+include "template.h"
+
+# TP_COUNT -- Count the number of groups in an image
+#
+# B.Simon 02-Oct-98 Original
+# B.Simon 26-Apr-99 Check value of NEXTEND before using
+
+int procedure tp_count (root)
+
+char root[ARB] # i: image name minus any sections
+#--
+int imtype, count, lo, hi, mid
+pointer sp, image, im
+
+int imgeti(), imaccf(), tp_imtype(), tp_hasgroup()
+pointer immap()
+
+begin
+ # If the image is not a geis or fits file it can only have one group
+
+ imtype = tp_imtype (root)
+ if (imtype != TP_GEIS && imtype != TP_FITS)
+ return (1)
+
+ # Open the image to read the number of groups or extensions
+ # as recorded in the appropriate header keyword
+
+ call smark (sp)
+ call salloc (image, SZ_FNAME, TY_CHAR)
+
+ call strcpy (root, Memc[image], SZ_FNAME)
+ call strcat ("[0]", Memc[image], SZ_FNAME)
+
+ iferr (im = immap (Memc[image], READ_ONLY, NULL)) {
+ # If image can't be opened, report an error condition
+
+ count = ERR
+
+ } else if (imtype == TP_GEIS) {
+ # Number of groups is trustworthy, report it to user
+
+ count = imgeti (im, "GCOUNT")
+ call imunmap (im)
+
+ } else {
+ # Number of extensions is not, it must be checked
+
+ lo = 1
+ hi = 0
+
+ # Check number of extensions
+
+ if (imaccf (im, "NEXTEND") == YES) {
+ mid = imgeti (im, "NEXTEND")
+
+ if (mid > 0) {
+ if (tp_hasgroup (root, mid) == NO) {
+ hi = mid
+
+ } else {
+ lo = mid
+ mid = mid + 1
+
+ if (tp_hasgroup (root, mid) == NO) {
+ hi = mid
+ } else {
+ lo = mid
+ }
+ }
+ }
+ }
+
+ # Find bracket for number of extensions
+
+ while (hi < lo) {
+ mid = 2 * lo
+
+ if (tp_hasgroup (root, mid) == NO) {
+ hi = mid
+ } else {
+ lo = mid
+ }
+ }
+
+ # Use binary search to find actual number of extensions
+
+ while (hi - lo > 1) {
+ mid = (hi + lo) / 2
+
+ if (tp_hasgroup (root, mid) == NO) {
+ hi = mid
+ } else {
+ lo = mid
+ }
+ }
+
+ count = lo
+ call imunmap (im)
+ }
+
+ call sfree (sp)
+ return (count)
+end
+
+# TP_HASGROUP -- Determine if group is preent in image
+
+int procedure tp_hasgroup (root, index)
+
+char root[ARB] # i: image name
+int index # i: index of group to check
+#--
+int has
+pointer sp, image, im
+
+pointer immap()
+
+begin
+ call smark (sp)
+ call salloc (image, SZ_FNAME, TY_CHAR)
+
+ call sprintf (Memc[image], SZ_FNAME, "%s[%d]")
+ call pargstr (root)
+ call pargi (index)
+
+ iferr (im = immap (Memc[image], READ_ONLY, NULL)) {
+ has = NO
+ } else {
+ call imunmap (im)
+ has = YES
+ }
+
+ call sfree (sp)
+ return (has)
+end
diff --git a/pkg/utilities/nttools/stxtools/tpfetch.x b/pkg/utilities/nttools/stxtools/tpfetch.x
new file mode 100644
index 00000000..885fd847
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/tpfetch.x
@@ -0,0 +1,43 @@
+include "template.h"
+
+# TP_FETCH -- Fetch the next image name from the group image template
+#
+# Create the next file name from the structure created by tp_open.
+# Return true if another group exists, false otherwise.
+#
+# B.Simon 28-Feb-89 Original
+# B.Simon 21-Aug-91 Changed template structure
+# B.Simon 24-Jul-98 Revised to handle unparsable sections
+
+bool procedure tp_fetch (ptr, file_name)
+
+pointer ptr # i: A pointer to a list of file names
+char file_name[SZ_FNAME] # o: The next file name in the list
+#--
+
+begin
+ if ((TP_INDEX(ptr) - TP_START(ptr)) + 1 > TP_COUNT(ptr))
+ return (false)
+
+ if (TP_START(ptr) == ERR) {
+ call sprintf (file_name, SZ_FNAME, "%s%s")
+ call pargstr (TP_ROOT(ptr))
+ call pargstr (TP_SECT(ptr))
+
+ } else if (TP_COUNT(ptr) > 1 && TP_INDEX(ptr) == TP_START(ptr)) {
+ call sprintf (file_name, SZ_FNAME, "%s[%d/%d]%s")
+ call pargstr (TP_ROOT(ptr))
+ call pargi (TP_INDEX(ptr))
+ call pargi (TP_COUNT(ptr))
+ call pargstr (TP_SECT(ptr))
+
+ } else {
+ call sprintf (file_name, SZ_FNAME, "%s[%d]%s")
+ call pargstr (TP_ROOT(ptr))
+ call pargi (TP_INDEX(ptr))
+ call pargstr (TP_SECT(ptr))
+ }
+
+ TP_INDEX(ptr) = TP_INDEX(ptr) + 1
+ return (true)
+end
diff --git a/pkg/utilities/nttools/stxtools/tpgroup.x b/pkg/utilities/nttools/stxtools/tpgroup.x
new file mode 100644
index 00000000..1dac1895
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/tpgroup.x
@@ -0,0 +1,87 @@
+include <ctype.h>
+include <imio.h>
+
+# TP_GROUP -- Extract the group index and count from an image name
+#
+# B.Simon 02-Jun-89 Original
+# B.Simon 10-Jul-98 Revised to ignore what it can't parse
+# B.Simon 02-Oct-98 added call to tp_count
+# B.Simon 26-Apr-99 set index to ERR if undefined
+
+procedure tp_group (root, gsect, def_count, index, count)
+
+char root[ARB] # i: Root section of image name
+char gsect[ARB] # i: Group section of image name
+int def_count # i: Default count if not specified
+int index # o: Starting group index
+int count # o: Group count
+#--
+bool star
+int ic, inum, num[2]
+
+int tp_count()
+
+begin
+ inum = 0
+ num[1] = 0
+ num[2] = 0
+ star = false
+
+ # Extract the numeric fields from the group section
+ # Set a flag if a star was found
+
+ for (ic = 1; gsect[ic] != EOS; ic = ic + 1) {
+ switch (gsect[ic]) {
+ case ' ':
+ ;
+ case '[':
+ inum = 1
+ case ']':
+ break
+ case '*':
+ star = true
+ inum = inum - 1
+ case '/':
+ inum = inum + 1
+ default:
+ if (! star && IS_DIGIT(gsect[ic])) {
+ if (inum > 2) {
+ inum = 2
+ break
+ }
+ num[inum] = 10 * num[inum] + TO_INTEG(gsect[ic])
+
+ } else {
+ inum = 0
+ star = false
+ break
+ }
+ }
+ }
+
+ # Set the output variables according to the number of fields found
+
+ switch (inum) {
+ case 0:
+ index = ERR
+ count = ERR
+ case 1:
+ index = num[1]
+ count = 1
+ case 2:
+ index = num[1]
+ count = max (1, num[2])
+ }
+
+ # Either use the default count or if the default is zero,
+ # Open the image and read the count from it
+
+ if (star) {
+ if (def_count > 0) {
+ count = def_count
+
+ } else {
+ count = tp_count (root)
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/stxtools/tpimtype.x b/pkg/utilities/nttools/stxtools/tpimtype.x
new file mode 100644
index 00000000..3ed7580f
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/tpimtype.x
@@ -0,0 +1,116 @@
+include <ctype.h>
+include "template.h"
+
+define MAXEXT 25
+
+# TP_IMTYPE -- Determine image type from image extension
+#
+# B.Simon 02-Oct-98 Original
+
+int procedure tp_imtype (root)
+
+int root[ARB] # i: image extension
+#--
+int loadext
+pointer extlist[MAXEXT]
+pointer extbuf
+
+data loadext / NO /
+
+int nc, iext, imtype
+pointer sp, ext
+
+int fnextn(), strdic(), iki_validextn()
+
+begin
+ call smark (sp)
+ call salloc (ext, SZ_FNAME, TY_CHAR)
+
+ if (loadext == NO) {
+ call tp_loadext (extlist, extbuf)
+ loadext = YES
+ }
+
+ nc = fnextn (root, Memc[ext], SZ_FNAME)
+ iext = iki_validextn (0, Memc[ext])
+
+ if (iext == 0) {
+ imtype = TP_UNKNOWN
+
+ } else {
+ call strcpy (Memc[extlist[iext]], Memc[ext], SZ_FNAME)
+ imtype = strdic (Memc[ext], Memc[ext], SZ_FNAME, TP_EXT_LIST)
+ }
+
+ call sfree (sp)
+ return (imtype)
+end
+
+# TP_LOADEXT -- Load list of image kernel names indexed by extension
+
+procedure tp_loadext (extlist, extbuf)
+
+pointer extlist[MAXEXT] # o: pointers to kernel names
+int extbuf # o: string buffer containing names
+#--
+int fd, flags, taglen, iext, ic, jc, nc
+pointer sp, line, jstr, kstr
+
+string kernel_tag "installed kernels "
+
+int open(), strlen(), getline(), strncmp(), ctoi()
+
+begin
+ call smark (sp)
+ call salloc (line, SZ_LINE, TY_CHAR)
+
+ # Initialize the image kernel tables
+
+ call iki_init ()
+
+ # Call the kernel debug routine to dump the information
+ # about which kernels are associated with which indices
+
+ fd = open ("tp_spool", READ_WRITE, SPOOL_FILE)
+ call iki_debug ("Kernel Names", fd, flags)
+
+ # Search the file for the line containing the image kernel info
+
+ call seek (fd, BOF)
+ taglen = strlen (kernel_tag)
+
+ while (getline (fd, Memc[line]) != EOF) {
+ if (strncmp (Memc[line], kernel_tag, taglen) != 0)
+ next
+
+ # Parse the line to extract the info
+
+ call malloc (extbuf, strlen (Memc[line+taglen]), TY_CHAR)
+ jstr = extbuf
+ kstr = extbuf
+
+ for (ic = taglen; Memc[line+ic] != EOS; ic = ic + 1) {
+ if (Memc[line+ic] == '=') {
+ Memc[jstr] = EOS
+ jstr = jstr + 1
+
+ jc = 1
+ nc = ctoi (Memc[line+ic+1], jc, iext)
+ ic = ic + 1
+
+ extlist[iext] = kstr
+ kstr = jstr
+
+ } else if (! IS_WHITE (Memc[line+ic])) {
+ Memc[jstr] = Memc[line+ic]
+ jstr = jstr + 1
+ }
+ }
+
+ break
+ }
+
+ call close (fd)
+ call sfree (sp)
+end
+
diff --git a/pkg/utilities/nttools/stxtools/tpopen.x b/pkg/utilities/nttools/stxtools/tpopen.x
new file mode 100644
index 00000000..d9b7a2af
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/tpopen.x
@@ -0,0 +1,38 @@
+include "template.h"
+
+# TP_OPEN -- Expand a group image template into a list of image names.
+
+# Create an array of image names that contain the group specification.
+# Return a pointer to the list of names and the total number of names.
+#
+# B.Simon 28-Feb-89 Original
+# B.Simon 23-Jun-89 Hint character added
+# B.Simon 21-Aug-91 Changed template structure
+
+pointer procedure tp_open (imname, def_count, count)
+
+char imname[ARB] # i: image template
+int def_count # i: default image name count
+int count # o: number of image names
+#--
+pointer ptr
+
+errchk tp_parse, malloc
+
+begin
+ # Allocate data structure
+
+ call malloc (ptr, LEN_TPSTRUCT, TY_STRUCT)
+ call malloc (TP_ROOTPTR(ptr), SZ_FNAME, TY_CHAR)
+ call malloc (TP_SECTPTR(ptr), SZ_FNAME, TY_CHAR)
+
+ # Parse the template into a root name, starting group number,
+ # and group count
+
+ call tp_parse (imname, def_count, TP_ROOT(ptr), TP_SECT(ptr),
+ TP_START(ptr), TP_COUNT(ptr))
+
+ TP_INDEX(ptr) = TP_START(ptr)
+ count = TP_COUNT(ptr)
+ return(ptr)
+end
diff --git a/pkg/utilities/nttools/stxtools/tpparse.x b/pkg/utilities/nttools/stxtools/tpparse.x
new file mode 100644
index 00000000..f261a763
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/tpparse.x
@@ -0,0 +1,108 @@
+include <imio.h>
+
+define NFIELD 4
+define FIELD Memc[($1)+($2-1)*(SZ_FNAME+1)]
+
+# TP_PARSE -- Parse an image name into its component parts
+#
+# Parse an image name to obtain the root name, the image section, the
+# group index, and the group count.
+#
+# B.Simon 28-Feb-89 Original
+# B.Simon 02-Jun-89 imparse replaced
+# B.Simon 16-Jul-98 Revised to flag unparsable sections
+# B.Simon 02-Oct-98 added call to tp_count
+# B.Simon 26-Apr-99 check for data in extension zero
+# B.Simon 06-May-99 set index to one for new files w/o sections
+# B.Simon 14-Jun-99 set count to one if section could not be parsed
+# B.Simon 20-Nov-00 get default extension with iki_access
+
+procedure tp_parse (imname, def_count, root, section, index, count)
+
+char imname[ARB] # i: image name
+int def_count # i: default group count
+char root[ARB] # o: root name
+char section[ARB] # o: image section
+int index # o: group index
+int count # o: group count
+#--
+int ifield, nc
+pointer sp, image, root2, sect, ext
+
+int access(), strlen(), fnextn(), envgets(), iki_access()
+int tp_count(), tp_hasgroup()
+
+string ambiguous " Ambiguous image name, extension required"
+
+errchk immap, imunmap
+
+begin
+ # Allocate dynamic memory for error string
+
+ call smark (sp)
+ call salloc (image, SZ_FNAME, TY_CHAR)
+ call salloc (root2, SZ_FNAME, TY_CHAR)
+ call salloc (sect, (SZ_FNAME+1)*NFIELD, TY_CHAR)
+ call salloc (ext, SZ_FNAME, TY_CHAR)
+
+ # Break the image name into its component parts and
+ # get the group index and count
+
+ call tp_break (imname, Memc[sect], NFIELD, SZ_FNAME)
+
+ call tp_group (FIELD(sect,1), FIELD(sect,2), def_count, index, count)
+
+ call strcpy (FIELD(sect,1), root, SZ_FNAME)
+ call strcpy (FIELD(sect,2), section, SZ_FNAME)
+
+ # Copy the remaining fields into the section
+
+ do ifield = 3, NFIELD
+ call strcat (FIELD(sect,ifield), section, SZ_FNAME)
+
+ # Add default extension onto image if no extension given
+
+ nc = strlen (root)
+ if (root[nc] != '.' && fnextn (root, Memc[ext], SZ_FNAME) == 0) {
+ # Determine the access mode from the default grou[ count
+
+ if (def_count > 0) {
+ nc = envgets ("imtype", Memc[ext], SZ_FNAME)
+
+ } else {
+ if (iki_access (root, Memc[root2],
+ Memc[ext], READ_ONLY) == ERR)
+ call error (1, ambiguous)
+ }
+
+ call strcat (".", root, SZ_FNAME)
+ call strcat (Memc[ext], root, SZ_FNAME)
+ }
+
+ # Set index and count when the image does not contain a section
+
+ if (section[1] == EOS) {
+ if (access (root, 0, 0) == NO) {
+ index = 1
+ } else if (tp_hasgroup (root, 1) == YES) {
+ index = 1
+ } else {
+ index = 0
+ }
+ }
+
+ if (count != ERR) {
+ count = max (count, 1)
+
+ } else if (index == ERR) {
+ count = 1
+
+ } else if (def_count > 0) {
+ count = def_count
+
+ } else {
+ count = tp_count (root)
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/stxtools/vex.com b/pkg/utilities/nttools/stxtools/vex.com
new file mode 100644
index 00000000..d89b8788
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/vex.com
@@ -0,0 +1,11 @@
+# VEX.COM -- Global variables used by vex parsing routine
+
+pointer line # Buffer containing next line in expression
+pointer ch # Pointer to next character in expression
+int ncode # Length of code array
+int maxcode # Maximum length of code array
+pointer code # Pointer to next available code
+pointer stack # Pointer to stack structure
+
+common /vex/ line, ch, ncode, maxcode, code, stack
+
diff --git a/pkg/utilities/nttools/stxtools/vex.h b/pkg/utilities/nttools/stxtools/vex.h
new file mode 100644
index 00000000..200d717c
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/vex.h
@@ -0,0 +1,107 @@
+# VEX.H -- Structures and constants used by vex
+
+# Strings
+
+define FN1STR "abs acos asin atan cos cosh cube double exp int log log10 \
+nint real sin sinh sqr sqrt tan tanh"
+
+define FN2STR "atan2 dim max min mod sign"
+
+# Characters
+
+define BLANK ' '
+define CMTCHAR '#'
+define DOLLAR '$'
+define DOT '.'
+
+# Function codes
+
+define FN1_ABS 1
+define FN1_ACOS 2
+define FN1_ASIN 3
+define FN1_ATAN 4
+define FN1_COS 5
+define FN1_COSH 6
+define FN1_CUBE 7
+define FN1_DOUBLE 8
+define FN1_EXP 9
+define FN1_INT 10
+define FN1_LOG 11
+define FN1_LOG10 12
+define FN1_NINT 13
+define FN1_REAL 14
+define FN1_SIN 15
+define FN1_SINH 16
+define FN1_SQR 17
+define FN1_SQRT 18
+define FN1_TAN 19
+define FN1_TANH 20
+
+define FN2_ATAN2 1
+define FN2_DIM 2
+define FN2_MAX 3
+define FN2_MIN 4
+define FN2_MOD 5
+define FN2_SIGN 6
+
+# These constants are taken from the output of xyacc run on vexcompile.y
+
+define Y_WRONG 257
+define Y_LPAR 258
+define Y_RPAR 259
+define Y_COMMA 260
+define Y_VAR 261
+define Y_INT 262
+define Y_REAL 263
+define Y_DOUBLE 264
+define Y_FN1 265
+define Y_FN2 266
+define Y_IF 267
+define Y_THEN 268
+define Y_ELSE 269
+define Y_DONE 270
+define Y_OR 271
+define Y_AND 272
+define Y_NOT 273
+define Y_EQ 274
+define Y_NE 275
+define Y_LT 276
+define Y_GT 277
+define Y_LE 278
+define Y_GE 279
+define Y_ADD 280
+define Y_SUB 281
+define Y_MUL 282
+define Y_DIV 283
+define Y_NEG 284
+define Y_POW 285
+
+# Array lengths
+
+define MAX_TOKEN 31
+define MAX_STACK 64
+
+# Pseudocode structure
+
+define SZ_VEXSTRUCT 2
+
+define VEX_CODE Memi[$1] # pointer to code array
+define VEX_STACK Memi[$1+1] # pointer to stack structure
+
+# Stack structure
+
+define SZ_STKSTRUCT 6
+
+define STK_TOP Memi[$1] # top of stack
+define STK_HIGH Memi[$1+1] # high water mark in stack
+define STK_LENVAL Memi[$1+2] # length of each value array
+define STK_NULLARY Memi[$1+3] # pointer to array of null values
+define STK_VALARY Memi[$1+4] # pointer to value stack
+define STK_TYPARY Memi[$1+5] # pointer to type stack
+
+define STK_NULL Memb[STK_NULLARY($1)+$2]
+define STK_VALUE Memi[STK_VALARY($1)+$2]
+define STK_TYPE Memi[STK_TYPARY($1)+$2]
+
+define TOP -1 # Symbolic constant for top of stack
+
diff --git a/pkg/utilities/nttools/stxtools/vexcompile.x b/pkg/utilities/nttools/stxtools/vexcompile.x
new file mode 100644
index 00000000..c7054b2d
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/vexcompile.x
@@ -0,0 +1,973 @@
+include <lexnum.h>
+include <ctype.h>
+include <fset.h>
+include "vex.h"
+
+#* HISTORY *
+#* B.Simon ?? original
+# Phil Hodge 12-Jul-2005 Add 'int vex_gettok()' and declare 'debug'
+# to be bool rather than int, in vex_compile.
+
+define YYMAXDEPTH 64
+define YYOPLEN 1
+define yyparse vex_parse
+
+# Tokens generated by xyacc have been moved to vex.h
+
+define yyclearin yychar = -1
+define yyerrok yyerrflag = 0
+define YYMOVE call amovi (Memi[$1], Memi[$2], YYOPLEN)
+define YYERRCODE 256
+
+# line 148 "vexcompile.y"
+
+
+# VEX_COMPILE -- Compile an expression, producing pseudocode
+#
+# This procedure takes a string containing a fortran expression and produces
+# pseudocode that can be evaluated by vex_eval(). The pseudocode is stored in
+# structure adressed by the pointer returned as the function value. This
+# structure is freed by calling vex_free(). If the string begins with an @
+# symbol, the rest of the string is treated as a the name of a file which
+# contains the expression. The expression can contain all the fortran
+# operators, including logical and relational operators and supports all the
+# fortran intrinsic functions which can take real arguments. It also supports
+# conditional expressions of the form: if <expr> then <expr> else <expr>
+# Variables must follow the fortran rules, and may be up to 31 characters long.
+# All variables and constants are treated as real numbers. A variable may
+# contain non-alphanumeric characters if it is preceded by a dollar sign, in
+# which case all characters until the next blank are part of the variable name.
+#
+# B.Simon 21-May-90 Original
+# B.Simon 19-Apr-91 Revised to handle multiple types
+# B.Simon 31-Mar-94 Better syntax error message
+# B.Simon 15-Oct-98 Embed strings in pseudocode
+
+pointer procedure vex_compile (expr)
+
+char expr[ARB] # i: Expression to be parsed
+#--
+include "vex.com"
+
+int ic, fd, len
+bool debug
+pointer sp, pcode
+
+data debug / false /
+
+int open(), stropen(), strlen(), fstati(), yyparse()
+
+int vex_gettok()
+extern vex_gettok
+
+begin
+ # Open the expression as a file
+
+ for (ic = 1; IS_WHITE(expr[ic]); ic = ic + 1)
+ ;
+
+ if (expr[ic] == '@') {
+ fd = open (expr[ic+1], READ_ONLY, TEXT_FILE)
+ len = fstati (fd, F_FILESIZE) + 1
+
+ } else {
+ len = strlen (expr[ic]) + 1
+ fd = stropen (expr[ic], len, READ_ONLY)
+ }
+
+ # Create pseudocode structure
+
+ call malloc (pcode, SZ_VEXSTRUCT, TY_STRUCT)
+
+ call malloc (VEX_CODE(pcode), 2 * len, TY_INT)
+ call stk_init (VEX_STACK(pcode))
+
+ # Initialize parsing common block
+
+ call smark (sp)
+ call salloc (line, SZ_LINE, TY_CHAR)
+
+ ch = line
+ Memc[line] = EOS
+
+ ncode = 0
+ maxcode = 2 * len
+ code = VEX_CODE(pcode)
+ stack = VEX_STACK(pcode)
+
+ # Parse expression to produce reverse polish code
+
+ if (yyparse (fd, debug, vex_gettok) == ERR) {
+ call eprintf ("%s\n%*t^\n")
+ call pargstr (Memc[line])
+ call pargi (ch-line)
+
+ call error (1, "Syntax error in expression")
+ }
+
+ # Clean up and return pseudocode structure
+
+ call stk_clear (VEX_STACK(pcode))
+
+ call close (fd)
+ call sfree (sp)
+ return (pcode)
+end
+
+# VEX_GETTOK -- Get the next token from the input
+
+int procedure vex_gettok (fd, value)
+
+int fd # i: File containing expression to be lexed
+pointer value # o: Address on parse stack to store token
+#--
+include "vex.com"
+
+double constant
+int ic, jc, nc, type, index
+int idftype[4], keytype[3], btype[9]
+pointer sp, errmsg, token
+
+string fn1tok FN1STR
+string fn2tok FN2STR
+
+string idftok "indefi indefr indefd indef"
+data idftype / Y_INT, Y_REAL, Y_DOUBLE, Y_REAL /
+
+string keytok "if then else"
+data keytype / Y_IF, Y_THEN, Y_ELSE /
+
+string btoken ".or. .and. .eq. .ne. .lt. .gt. .le. .ge. .not."
+data btype / Y_OR, Y_AND, Y_EQ, Y_NE, Y_LT, Y_GT, Y_LE, Y_GE, Y_NOT /
+
+string badsymb "Operator not recognized (%s)"
+
+int getline(), lexnum(), ctod(), stridxs(), word_match()
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+ call malloc (token, MAX_TOKEN, TY_CHAR)
+
+ # Skip over leading white space and comments
+
+ while (Memc[ch] <= BLANK || Memc[ch] == CMTCHAR) {
+
+ # If all characters have been read from the current line
+ # or a comment character was found, get the next line
+
+ if (Memc[ch] == EOS || Memc[ch] == CMTCHAR) {
+ ch = line
+ if (getline (fd, Memc[line]) == EOF) {
+ Memc[ch] = EOS
+ break
+ }
+ } else {
+ ch = ch + 1
+ }
+ }
+
+ # The token type is determined from the first character in the token
+
+ Memc[token] = EOS
+
+ # End of expression token
+
+ if (Memc[ch] == EOS) {
+ type = Y_DONE
+
+ # Numeric constant is too difficult to parse,
+ # Pass the job to lexnum and ctod
+
+ } else if (IS_DIGIT(Memc[ch])) {
+
+ ic = 1
+ index = lexnum (Memc[ch], ic, nc)
+ if (index != LEX_REAL) {
+ type = Y_INT
+ } else if (nc > 8) {
+ type = Y_DOUBLE
+ } else {
+ jc = stridxs ("dD", Memc[ch])
+ if (jc == 0 || jc > nc) {
+ type = Y_REAL
+ } else {
+ type = Y_DOUBLE
+ }
+ }
+
+ ic = 1
+ nc = ctod (Memc[ch], ic, constant)
+ nc = min (nc, MAX_TOKEN)
+
+ call strcpy (Memc[ch], Memc[token], nc)
+ ch = ch + ic - 1
+
+ # Token is alphanumeric. Determine what type of token
+
+ } else if (IS_ALPHA (Memc[ch])) {
+
+ # Gather characters in token
+
+ for (ic = 1; ic <= MAX_TOKEN; ic = ic + 1) {
+ if (Memc[ch] != '_' && ! IS_ALNUM(Memc[ch]))
+ break
+
+ if (IS_UPPER(Memc[ch]))
+ Memc[token+ic-1] = TO_LOWER(Memc[ch])
+ else
+ Memc[token+ic-1] = Memc[ch]
+ ch = ch + 1
+ }
+ Memc[token+ic-1] = EOS
+
+ # Check to see if token is string "INDEF"
+
+ index = word_match (Memc[token], idftok)
+
+ if (index > 0) {
+ type = idftype[index]
+ call strupr (Memc[token])
+
+ } else {
+
+ # Check to see if token is function or keyword name
+ # If not, add it as a new variable
+
+ index = word_match (Memc[token], fn1tok)
+ if (index > 0) {
+ type = Y_FN1
+
+ } else {
+ index = word_match (Memc[token], fn2tok)
+ if (index > 0) {
+ type = Y_FN2
+
+ } else {
+ index = word_match (Memc[token], keytok)
+ if (index > 0) {
+ type = keytype[index]
+ Memc[token] = EOS
+ } else {
+ type = Y_VAR
+ }
+ }
+ }
+ }
+
+ # Tokens beginning with a dot are numbers or boolean operators
+
+ } else if (Memc[ch] == DOT) {
+
+ if (IS_DIGIT (Memc[ch+1])) {
+ ic = 1
+ index = lexnum (Memc[ch], ic, nc)
+
+ if (index != LEX_REAL) {
+ type = Y_INT
+ } else if (nc < 9) {
+ type = Y_REAL
+ } else {
+ type = Y_DOUBLE
+ }
+
+ ic = 1
+ nc = ctod (Memc[ch], ic, constant)
+ nc = min (nc, MAX_TOKEN)
+
+ call strcpy (Memc[ch], Memc[token], nc)
+ ch = ch + ic - 1
+
+ } else {
+
+ # Gather characters in token
+
+ ch = ch + 1
+ Memc[token] = DOT
+ for (ic = 2; ic < MAX_TOKEN && Memc[ch] != DOT; ic = ic + 1) {
+ if (Memc[ch] == EOS)
+ break
+ if (IS_UPPER(Memc[ch]))
+ Memc[token+ic-1] = TO_LOWER(Memc[ch])
+ else
+ Memc[token+ic-1] = Memc[ch]
+ ch = ch + 1
+ }
+
+ Memc[token+ic-1] = Memc[ch]
+ Memc[token+ic] = EOS
+ ch = ch + 1
+
+ index = word_match (Memc[token], btoken)
+ if (type > 0) {
+ type = btype[index]
+ } else {
+ call sprintf (Memc[errmsg], SZ_LINE, badsymb)
+ call pargstr (Memc[token])
+ call error (1, Memc[errmsg])
+ }
+ }
+
+ # Characters preceded by a dollar sign are identifiers
+
+ } else if (Memc[ch] == DOLLAR) {
+
+ ch = ch + 1
+ for (ic = 1; ic <= MAX_TOKEN && Memc[ch] > BLANK; ic = ic + 1) {
+ if (IS_UPPER(Memc[ch]))
+ Memc[token+ic-1] = TO_LOWER(Memc[ch])
+ else
+ Memc[token+ic-1] = Memc[ch]
+ ch = ch + 1
+ }
+ Memc[token+ic-1] = EOS
+
+ type = Y_VAR
+
+ # Anything else is a symbol
+
+ } else {
+ switch (Memc[ch]) {
+ case '*':
+ if (Memc[ch+1] != '*') {
+ type = Y_MUL
+ } else {
+ type = Y_POW
+ ch = ch + 1
+ }
+ case '/':
+ type = Y_DIV
+ case '+':
+ type = Y_ADD
+ case '-':
+ type = Y_SUB
+ case '(':
+ type = Y_LPAR
+ case ')':
+ type = Y_RPAR
+ case ',':
+ type = Y_COMMA
+ case '<':
+ if (Memc[ch+1] != '=') {
+ type = Y_LT
+ } else {
+ type = Y_LE
+ ch = ch + 1
+ }
+ case '>':
+ if (Memc[ch+1] != '=') {
+ type = Y_GT
+ } else {
+ type = Y_GE
+ ch = ch + 1
+ }
+ case '|':
+ if (Memc[ch+1] != '|') {
+ type = Y_WRONG
+ } else {
+ type = Y_OR
+ ch = ch + 1
+ }
+ case '&':
+ if (Memc[ch+1] != '&') {
+ type = Y_WRONG
+ } else {
+ type = Y_AND
+ ch = ch + 1
+ }
+ case '=':
+ if (Memc[ch+1] != '=') {
+ type = Y_WRONG
+ } else {
+ type = Y_EQ
+ ch = ch + 1
+ }
+ case '!':
+ if (Memc[ch+1] != '=') {
+ type = Y_NOT
+ } else {
+ type = Y_NE
+ ch = ch + 1
+ }
+ default:
+ Memc[ch+1] = EOS
+ call sprintf (Memc[errmsg], SZ_LINE, badsymb)
+ call pargstr (Memc[ch])
+ call error (1, Memc[errmsg])
+ }
+
+ ch = ch + 1
+ }
+
+ #
+ if (Memc[token] == EOS) {
+ call mfree (token, TY_CHAR)
+ token = NULL
+ }
+
+ Memi[value] = token
+ return (type)
+end
+
+# VEX_ADDCODE -- Add an instruction to the code array
+
+procedure vex_addcode (type)
+
+int type # i: Instruction type
+#--
+include "vex.com"
+
+begin
+
+ if (ncode == maxcode)
+ call error (1, "Expression too complex")
+ else {
+ Memi[code] = type
+ code = code + 1
+ ncode = ncode + 1
+ }
+
+end
+
+# VEX_ADDSTR -- Embed a string constant in the pseudo-code
+
+procedure vex_addstr (token)
+
+pointer token # u: Pointer to token string
+#--
+include "vex.com"
+
+int ic
+
+begin
+ if (token == NULL)
+ call error (1, "Expression token missing")
+
+ if (Memc[token] == EOS)
+ call error (1, "Expression token blank")
+
+ ic = 0
+ repeat {
+ ic = ic + 1
+
+ if (ncode == maxcode)
+ call error (1, "Expression too complex")
+ else {
+ Memi[code] = Memc[token+ic-1]
+ code = code + 1
+ ncode = ncode + 1
+ }
+
+ } until (Memc[token+ic-1] == EOS)
+
+ call mfree (token, TY_CHAR)
+end
+
+# VEX_GETSTR -- Retrieve a token string from the pseudocode array
+
+procedure vex_getstr (op, token, maxch)
+
+pointer op # u: Location of token string in pseudocode
+char token[ARB] # o: Token string
+int maxch # i: Maximum length of token
+#--
+int ic
+
+begin
+ # The token begins one position after op and is
+ # termminated by an EOS
+
+ ic = 0
+ repeat {
+ ic = ic + 1
+ op = op + 1
+ if (ic <= maxch)
+ token[ic] = Memi[op]
+
+ } until (Memi[op] == EOS)
+
+end
+define YYNPROD 27
+define YYLAST 264
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# Parser for yacc output, translated to the IRAF SPP language. The contents
+# of this file form the bulk of the source of the parser produced by Yacc.
+# Yacc recognizes several macros in the yaccpar input source and replaces
+# them as follows:
+# A user suppled "global" definitions and declarations
+# B parser tables
+# C user supplied actions (reductions)
+# The remainder of the yaccpar code is not changed.
+
+define yystack_ 10 # statement labels for gotos
+define yynewstate_ 20
+define yydefault_ 30
+define yyerrlab_ 40
+define yyabort_ 50
+
+define YYFLAG (-1000) # defs used in user actions
+define YYERROR goto yyerrlab_
+define YYACCEPT return (OK)
+define YYABORT return (ERR)
+
+
+# YYPARSE -- Parse the input stream, returning OK if the source is
+# syntactically acceptable (i.e., if compilation is successful),
+# otherwise ERR. The parameters YYMAXDEPTH and YYOPLEN must be
+# supplied by the caller in the %{ ... %} section of the Yacc source.
+# The token value stack is a dynamically allocated array of operand
+# structures, with the length and makeup of the operand structure being
+# application dependent.
+
+int procedure yyparse (fd, yydebug, yylex)
+
+int fd # stream to be parsed
+bool yydebug # print debugging information?
+int yylex() # user-supplied lexical input function
+extern yylex()
+
+short yys[YYMAXDEPTH] # parser stack -- stacks tokens
+pointer yyv # pointer to token value stack
+pointer yyval # value returned by action
+pointer yylval # value of token
+int yyps # token stack pointer
+pointer yypv # value stack pointer
+int yychar # current input token number
+int yyerrflag # error recovery flag
+int yynerrs # number of errors
+
+short yyj, yym # internal variables
+pointer yysp, yypvt
+short yystate, yyn
+int yyxi, i
+errchk salloc, yylex
+
+
+
+short yyexca[70]
+data (yyexca(i),i= 1, 8) / -1, 1, 0, -1, -2, 0, -1, 41/
+data (yyexca(i),i= 9, 16) / 276, 0, 277, 0, 278, 0, 279, 0/
+data (yyexca(i),i= 17, 24) / -2, 18, -1, 42, 276, 0, 277, 0/
+data (yyexca(i),i= 25, 32) / 278, 0, 279, 0, -2, 19, -1, 43/
+data (yyexca(i),i= 33, 40) / 276, 0, 277, 0, 278, 0, 279, 0/
+data (yyexca(i),i= 41, 48) / -2, 20, -1, 44, 276, 0, 277, 0/
+data (yyexca(i),i= 49, 56) / 278, 0, 279, 0, -2, 21, -1, 45/
+data (yyexca(i),i= 57, 64) / 274, 0, 275, 0, -2, 22, -1, 46/
+data (yyexca(i),i= 65, 70) / 274, 0, 275, 0, -2, 23/
+short yyact[264]
+data (yyact(i),i= 1, 8) / 58, 22, 23, 24, 25, 20, 21, 18/
+data (yyact(i),i= 9, 16) / 19, 17, 17, 31, 29, 28, 15, 26/
+data (yyact(i),i= 17, 24) / 27, 22, 23, 24, 25, 20, 21, 18/
+data (yyact(i),i= 25, 32) / 19, 55, 17, 29, 28, 30, 26, 27/
+data (yyact(i),i= 33, 40) / 22, 23, 24, 25, 20, 21, 18, 19/
+data (yyact(i),i= 41, 48) / 54, 17, 20, 21, 18, 19, 1, 17/
+data (yyact(i),i= 49, 56) / 0, 0, 0, 29, 28, 0, 26, 27/
+data (yyact(i),i= 57, 64) / 22, 23, 24, 25, 20, 21, 18, 19/
+data (yyact(i),i= 65, 72) / 53, 17, 18, 19, 0, 17, 0, 0/
+data (yyact(i),i= 73, 80) / 0, 0, 2, 0, 29, 28, 0, 26/
+data (yyact(i),i= 81, 88) / 27, 22, 23, 24, 25, 20, 21, 18/
+data (yyact(i),i= 89, 96) / 19, 51, 17, 0, 0, 0, 0, 0/
+data (yyact(i),i= 97,104) / 0, 0, 0, 0, 0, 29, 28, 0/
+data (yyact(i),i=105,112) / 26, 27, 22, 23, 24, 25, 20, 21/
+data (yyact(i),i=113,120) / 18, 19, 35, 17, 0, 29, 28, 0/
+data (yyact(i),i=121,128) / 26, 27, 22, 23, 24, 25, 20, 21/
+data (yyact(i),i=129,136) / 18, 19, 57, 17, 29, 28, 0, 26/
+data (yyact(i),i=137,144) / 27, 22, 23, 24, 25, 20, 21, 18/
+data (yyact(i),i=145,152) / 19, 28, 17, 26, 27, 22, 23, 24/
+data (yyact(i),i=153,160) / 25, 20, 21, 18, 19, 0, 17, 26/
+data (yyact(i),i=161,168) / 27, 22, 23, 24, 25, 20, 21, 18/
+data (yyact(i),i=169,176) / 19, 3, 17, 14, 0, 0, 6, 7/
+data (yyact(i),i=177,184) / 8, 9, 10, 11, 4, 0, 0, 0/
+data (yyact(i),i=185,192) / 14, 0, 13, 6, 7, 8, 9, 10/
+data (yyact(i),i=193,200) / 11, 4, 12, 0, 0, 14, 0, 13/
+data (yyact(i),i=201,208) / 6, 7, 8, 9, 10, 11, 0, 12/
+data (yyact(i),i=209,216) / 5, 0, 0, 0, 13, 16, 0, 0/
+data (yyact(i),i=217,224) / 0, 0, 0, 0, 12, 32, 33, 34/
+data (yyact(i),i=225,232) / 0, 0, 36, 37, 38, 39, 40, 41/
+data (yyact(i),i=233,240) / 42, 43, 44, 45, 46, 47, 48, 49/
+data (yyact(i),i=241,248) / 50, 0, 0, 0, 52, 0, 0, 0/
+data (yyact(i),i=249,256) / 0, 0, 0, 0, 0, 0, 0, 0/
+data (yyact(i),i=257,264) / 0, 0, 0, 0, 0, 0, 0, 56/
+short yypact[59]
+data (yypact(i),i= 1, 8) / -87,-1000,-256,-1000, -61,-139,-1000,-1000/
+data (yypact(i),i= 9, 16) /-1000,-1000,-229,-247, -61, -61, -61,-1000/
+data (yypact(i),i= 17, 24) /-154, -61, -61, -61, -61, -61, -61, -61/
+data (yypact(i),i= 25, 32) / -61, -61, -61, -61, -61, -61, -61, -61/
+data (yypact(i),i= 33, 40) /-276,-115,-170, -61,-276,-276,-276,-216/
+data (yypact(i),i= 41, 48) /-216,-238,-238,-238,-238,-275,-275,-115/
+data (yypact(i),i= 49, 56) /-127,-195,-220,-1000,-244,-1000, -61, -74/
+data (yypact(i),i= 57, 59) /-259,-1000,-1000/
+short yypgo[4]
+data (yypgo(i),i= 1, 4) / 0, 46, 74, 208/
+short yyr1[27]
+data (yyr1(i),i= 1, 8) / 0, 1, 1, 2, 2, 3, 3, 3/
+data (yyr1(i),i= 9, 16) / 3, 3, 3, 3, 3, 3, 3, 3/
+data (yyr1(i),i= 17, 24) / 3, 3, 3, 3, 3, 3, 3, 3/
+data (yyr1(i),i= 25, 27) / 3, 3, 3/
+short yyr2[27]
+data (yyr2(i),i= 1, 8) / 0, 2, 1, 6, 1, 1, 1, 1/
+data (yyr2(i),i= 9, 16) / 1, 4, 6, 2, 2, 3, 3, 3/
+data (yyr2(i),i= 17, 24) / 3, 3, 3, 3, 3, 3, 3, 3/
+data (yyr2(i),i= 25, 27) / 3, 3, 3/
+short yychk[59]
+data (yychk(i),i= 1, 8) /-1000, -1, -2, 256, 267, -3, 261, 262/
+data (yychk(i),i= 9, 16) / 263, 264, 265, 266, 281, 273, 258, 270/
+data (yychk(i),i= 17, 24) / -3, 285, 282, 283, 280, 281, 276, 277/
+data (yychk(i),i= 25, 32) / 278, 279, 274, 275, 272, 271, 258, 258/
+data (yychk(i),i= 33, 40) / -3, -3, -3, 268, -3, -3, -3, -3/
+data (yychk(i),i= 41, 48) / -3, -3, -3, -3, -3, -3, -3, -3/
+data (yychk(i),i= 49, 56) / -3, -3, -3, 259, -3, 259, 260, 269/
+data (yychk(i),i= 57, 59) / -3, -2, 259/
+short yydef[59]
+data (yydef(i),i= 1, 8) / 0, -2, 0, 2, 0, 4, 5, 6/
+data (yydef(i),i= 9, 16) / 7, 8, 0, 0, 0, 0, 0, 1/
+data (yydef(i),i= 17, 24) / 0, 0, 0, 0, 0, 0, 0, 0/
+data (yydef(i),i= 25, 32) / 0, 0, 0, 0, 0, 0, 0, 0/
+data (yydef(i),i= 33, 40) / 11, 12, 0, 0, 13, 14, 15, 16/
+data (yydef(i),i= 41, 48) / 17, -2, -2, -2, -2, -2, -2, 24/
+data (yydef(i),i= 49, 56) / 25, 0, 0, 26, 0, 9, 0, 0/
+data (yydef(i),i= 57, 59) / 0, 3, 10/
+
+begin
+ call smark (yysp)
+ call salloc (yyv, (YYMAXDEPTH+2) * YYOPLEN, TY_STRUCT)
+
+ # Initialization. The first element of the dynamically allocated
+ # token value stack (yyv) is used for yyval, the second for yylval,
+ # and the actual stack starts with the third element.
+
+ yystate = 0
+ yychar = -1
+ yynerrs = 0
+ yyerrflag = 0
+ yyps = 0
+ yyval = yyv
+ yylval = yyv + YYOPLEN
+ yypv = yylval
+
+yystack_
+ # SHIFT -- Put a state and value onto the stack. The token and
+ # value stacks are logically the same stack, implemented as two
+ # separate arrays.
+
+ if (yydebug) {
+ call printf ("state %d, char 0%o\n")
+ call pargs (yystate)
+ call pargi (yychar)
+ }
+ yyps = yyps + 1
+ yypv = yypv + YYOPLEN
+ if (yyps > YYMAXDEPTH) {
+ call sfree (yysp)
+ call eprintf ("yacc stack overflow\n")
+ return (ERR)
+ }
+ yys[yyps] = yystate
+ YYMOVE (yyval, yypv)
+
+yynewstate_
+ # Process the new state.
+ yyn = yypact[yystate+1]
+
+ if (yyn <= YYFLAG)
+ goto yydefault_ # simple state
+
+ # The variable "yychar" is the lookahead token.
+ if (yychar < 0) {
+ yychar = yylex (fd, yylval)
+ if (yychar < 0)
+ yychar = 0
+ }
+ yyn = yyn + yychar
+ if (yyn < 0 || yyn >= YYLAST)
+ goto yydefault_
+
+ yyn = yyact[yyn+1]
+ if (yychk[yyn+1] == yychar) { # valid shift
+ yychar = -1
+ YYMOVE (yylval, yyval)
+ yystate = yyn
+ if (yyerrflag > 0)
+ yyerrflag = yyerrflag - 1
+ goto yystack_
+ }
+
+yydefault_
+ # Default state action.
+
+ yyn = yydef[yystate+1]
+ if (yyn == -2) {
+ if (yychar < 0) {
+ yychar = yylex (fd, yylval)
+ if (yychar < 0)
+ yychar = 0
+ }
+
+ # Look through exception table.
+ yyxi = 1
+ while ((yyexca[yyxi] != (-1)) || (yyexca[yyxi+1] != yystate))
+ yyxi = yyxi + 2
+ for (yyxi=yyxi+2; yyexca[yyxi] >= 0; yyxi=yyxi+2) {
+ if (yyexca[yyxi] == yychar)
+ break
+ }
+
+ yyn = yyexca[yyxi+1]
+ if (yyn < 0) {
+ call sfree (yysp)
+ return (OK) # ACCEPT -- all done
+ }
+ }
+
+
+ # SYNTAX ERROR -- resume parsing if possible.
+
+ if (yyn == 0) {
+ switch (yyerrflag) {
+ case 0, 1, 2:
+ if (yyerrflag == 0) { # brand new error
+ call eprintf ("syntax error\n")
+yyerrlab_
+ yynerrs = yynerrs + 1
+ # fall through...
+ }
+
+ # case 1:
+ # case 2: incompletely recovered error ... try again
+ yyerrflag = 3
+
+ # Find a state where "error" is a legal shift action.
+ while (yyps >= 1) {
+ yyn = yypact[yys[yyps]+1] + YYERRCODE
+ if ((yyn >= 0) && (yyn < YYLAST) &&
+ (yychk[yyact[yyn+1]+1] == YYERRCODE)) {
+ # Simulate a shift of "error".
+ yystate = yyact[yyn+1]
+ goto yystack_
+ }
+ yyn = yypact[yys[yyps]+1]
+
+ # The current yyps has no shift on "error", pop stack.
+ if (yydebug) {
+ call printf ("error recovery pops state %d, ")
+ call pargs (yys[yyps])
+ call printf ("uncovers %d\n")
+ call pargs (yys[yyps-1])
+ }
+ yyps = yyps - 1
+ yypv = yypv - YYOPLEN
+ }
+
+ # ABORT -- There is no state on the stack with an error shift.
+yyabort_
+ call sfree (yysp)
+ return (ERR)
+
+
+ case 3: # No shift yet; clobber input char.
+
+ if (yydebug) {
+ call printf ("error recovery discards char %d\n")
+ call pargi (yychar)
+ }
+
+ if (yychar == 0)
+ goto yyabort_ # don't discard EOF, quit
+ yychar = -1
+ goto yynewstate_ # try again in the same state
+ }
+ }
+
+
+ # REDUCE -- Reduction by production yyn.
+
+ if (yydebug) {
+ call printf ("reduce %d\n")
+ call pargs (yyn)
+ }
+ yyps = yyps - yyr2[yyn+1]
+ yypvt = yypv
+ yypv = yypv - yyr2[yyn+1] * YYOPLEN
+ YYMOVE (yypv + YYOPLEN, yyval)
+ yym = yyn
+
+ # Consult goto table to find next state.
+ yyn = yyr1[yyn+1]
+ yyj = yypgo[yyn+1] + yys[yyps] + 1
+ if (yyj >= YYLAST)
+ yystate = yyact[yypgo[yyn+1]+1]
+ else {
+ yystate = yyact[yyj+1]
+ if (yychk[yystate+1] != -yyn)
+ yystate = yyact[yypgo[yyn+1]+1]
+ }
+
+ # Perform action associated with the grammar rule, if any.
+ switch (yym) {
+
+case 1:
+# line 34 "vexcompile.y"
+{
+ # Normal exit. Code a stop instruction
+ call vex_addcode (Y_DONE)
+ return (OK)
+ }
+case 2:
+# line 39 "vexcompile.y"
+{
+ return (ERR)
+ }
+case 3:
+# line 44 "vexcompile.y"
+{
+ # Code an if instruction
+ call vex_addcode (Y_IF)
+ }
+case 4:
+# line 48 "vexcompile.y"
+{
+ # Null action
+ }
+case 5:
+# line 53 "vexcompile.y"
+{
+ # Code a push variable instruction
+ call vex_addcode (Y_VAR)
+ call vex_addstr (Memi[yypvt])
+ }
+case 6:
+# line 58 "vexcompile.y"
+{
+ # Code a push variable instruction
+ call vex_addcode (Y_INT)
+ call vex_addstr (Memi[yypvt])
+ }
+case 7:
+# line 63 "vexcompile.y"
+{
+ # Code a push variable instruction
+ call vex_addcode (Y_REAL)
+ call vex_addstr (Memi[yypvt])
+ }
+case 8:
+# line 68 "vexcompile.y"
+{
+ # Code a push variable instruction
+ call vex_addcode (Y_DOUBLE)
+ call vex_addstr (Memi[yypvt])
+ }
+case 9:
+# line 73 "vexcompile.y"
+{
+ # Code a single argument function call
+ call vex_addcode (Y_FN1)
+ call vex_addstr (Memi[yypvt-3*YYOPLEN])
+ }
+case 10:
+# line 78 "vexcompile.y"
+{
+ # Code a double argument function call
+ call vex_addcode (Y_FN2)
+ call vex_addstr (Memi[yypvt-5*YYOPLEN])
+ }
+case 11:
+# line 83 "vexcompile.y"
+{
+ # Code a negation instruction
+ call vex_addcode (Y_NEG)
+ }
+case 12:
+# line 87 "vexcompile.y"
+{
+ # Code a logical not
+ call vex_addcode (Y_NOT)
+ }
+case 13:
+# line 91 "vexcompile.y"
+{
+ # Code an exponentiation instruction
+ call vex_addcode (Y_POW)
+ }
+case 14:
+# line 95 "vexcompile.y"
+{
+ # Code a multiply instruction
+ call vex_addcode (Y_MUL)
+ }
+case 15:
+# line 99 "vexcompile.y"
+{
+ # Code a divide instruction
+ call vex_addcode (Y_DIV)
+ }
+case 16:
+# line 103 "vexcompile.y"
+{
+ # Code an addition instruction
+ call vex_addcode (Y_ADD)
+ }
+case 17:
+# line 107 "vexcompile.y"
+{
+ # Code a subtraction instruction
+ call vex_addcode (Y_SUB)
+ }
+case 18:
+# line 111 "vexcompile.y"
+{
+ # Code a less than instruction
+ call vex_addcode (Y_LT)
+ }
+case 19:
+# line 115 "vexcompile.y"
+{
+ # Code a greater than instruction
+ call vex_addcode (Y_GT)
+ }
+case 20:
+# line 119 "vexcompile.y"
+{
+ # Code a less than or equal instruction
+ call vex_addcode (Y_LE)
+ }
+case 21:
+# line 123 "vexcompile.y"
+{
+ # Code a greater than instruction
+ call vex_addcode (Y_GE)
+ }
+case 22:
+# line 127 "vexcompile.y"
+{
+ # Code a logical equality instruction
+ call vex_addcode (Y_EQ)
+ }
+case 23:
+# line 131 "vexcompile.y"
+{
+ # Code a logical inequality instruction
+ call vex_addcode (Y_NE)
+ }
+case 24:
+# line 135 "vexcompile.y"
+{
+ # Code a logical and instruction
+ call vex_addcode (Y_AND)
+ }
+case 25:
+# line 139 "vexcompile.y"
+{
+ # Code a logical or instruction
+ call vex_addcode (Y_OR)
+ }
+case 26:
+# line 143 "vexcompile.y"
+{
+ # Null action
+ } }
+
+ goto yystack_ # stack new state and value
+end
diff --git a/pkg/utilities/nttools/stxtools/vexcompile.y b/pkg/utilities/nttools/stxtools/vexcompile.y
new file mode 100644
index 00000000..4b2cd958
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/vexcompile.y
@@ -0,0 +1,616 @@
+%{
+
+include <lexnum.h>
+include <ctype.h>
+include <fset.h>
+include "vex.h"
+
+define YYMAXDEPTH 64
+define YYOPLEN 1
+define yyparse vex_parse
+
+# Tokens generated by xyacc have been moved to vex.h
+
+%L
+
+%}
+
+%token Y_WRONG Y_LPAR Y_RPAR Y_COMMA
+%token Y_VAR Y_INT Y_REAL Y_DOUBLE
+%token Y_FN1 Y_FN2 Y_IF Y_THEN Y_ELSE Y_DONE
+
+%left Y_OR
+%left Y_AND
+%right Y_NOT
+%nonassoc Y_EQ Y_NE
+%nonassoc Y_LT Y_GT Y_LE Y_GE
+%left Y_ADD Y_SUB
+%left Y_MUL Y_DIV
+%right Y_NEG
+%right Y_POW
+
+%%
+
+stmt : ifexpr Y_DONE {
+ # Normal exit. Code a stop instruction
+ call vex_addcode (Y_DONE)
+ return (OK)
+ }
+ | error {
+ return (ERR)
+ }
+ ;
+
+ifexpr : Y_IF expr Y_THEN expr Y_ELSE ifexpr {
+ # Code an if instruction
+ call vex_addcode (Y_IF)
+ }
+ | expr {
+ # Null action
+ }
+ ;
+
+expr : Y_VAR {
+ # Code a push variable instruction
+ call vex_addcode (Y_VAR)
+ call vex_addstr (Memi[$1])
+ }
+ | Y_INT {
+ # Code a push variable instruction
+ call vex_addcode (Y_INT)
+ call vex_addstr (Memi[$1])
+ }
+ | Y_REAL {
+ # Code a push variable instruction
+ call vex_addcode (Y_REAL)
+ call vex_addstr (Memi[$1])
+ }
+ | Y_DOUBLE {
+ # Code a push variable instruction
+ call vex_addcode (Y_DOUBLE)
+ call vex_addstr (Memi[$1])
+ }
+ | Y_FN1 Y_LPAR expr Y_RPAR {
+ # Code a single argument function call
+ call vex_addcode (Y_FN1)
+ call vex_addstr (Memi[$1])
+ }
+ | Y_FN2 Y_LPAR expr Y_COMMA expr Y_RPAR {
+ # Code a double argument function call
+ call vex_addcode (Y_FN2)
+ call vex_addstr (Memi[$1])
+ }
+ | Y_SUB expr %prec Y_NEG {
+ # Code a negation instruction
+ call vex_addcode (Y_NEG)
+ }
+ | Y_NOT expr {
+ # Code a logical not
+ call vex_addcode (Y_NOT)
+ }
+ | expr Y_POW expr {
+ # Code an exponentiation instruction
+ call vex_addcode (Y_POW)
+ }
+ | expr Y_MUL expr {
+ # Code a multiply instruction
+ call vex_addcode (Y_MUL)
+ }
+ | expr Y_DIV expr {
+ # Code a divide instruction
+ call vex_addcode (Y_DIV)
+ }
+ | expr Y_ADD expr {
+ # Code an addition instruction
+ call vex_addcode (Y_ADD)
+ }
+ | expr Y_SUB expr {
+ # Code a subtraction instruction
+ call vex_addcode (Y_SUB)
+ }
+ | expr Y_LT expr {
+ # Code a less than instruction
+ call vex_addcode (Y_LT)
+ }
+ | expr Y_GT expr {
+ # Code a greater than instruction
+ call vex_addcode (Y_GT)
+ }
+ | expr Y_LE expr {
+ # Code a less than or equal instruction
+ call vex_addcode (Y_LE)
+ }
+ | expr Y_GE expr {
+ # Code a greater than instruction
+ call vex_addcode (Y_GE)
+ }
+ | expr Y_EQ expr {
+ # Code a logical equality instruction
+ call vex_addcode (Y_EQ)
+ }
+ | expr Y_NE expr {
+ # Code a logical inequality instruction
+ call vex_addcode (Y_NE)
+ }
+ | expr Y_AND expr {
+ # Code a logical and instruction
+ call vex_addcode (Y_AND)
+ }
+ | expr Y_OR expr {
+ # Code a logical or instruction
+ call vex_addcode (Y_OR)
+ }
+ | Y_LPAR expr Y_RPAR {
+ # Null action
+ }
+ ;
+
+%%
+
+# VEX_COMPILE -- Compile an expression, producing pseudocode
+#
+# This procedure takes a string containing a fortran expression and produces
+# pseudocode that can be evaluated by vex_eval(). The pseudocode is stored in
+# structure adressed by the pointer returned as the function value. This
+# structure is freed by calling vex_free(). If the string begins with an @
+# symbol, the rest of the string is treated as a the name of a file which
+# contains the expression. The expression can contain all the fortran
+# operators, including logical and relational operators and supports all the
+# fortran intrinsic functions which can take real arguments. It also supports
+# conditional expressions of the form: if <expr> then <expr> else <expr>
+# Variables must follow the fortran rules, and may be up to 31 characters long.
+# All variables and constants are treated as real numbers. A variable may
+# contain non-alphanumeric characters if it is preceded by a dollar sign, in
+# which case all characters until the next blank are part of the variable name.
+#
+# B.Simon 21-May-90 Original
+# B.Simon 19-Apr-91 Revised to handle multiple types
+# B.Simon 31-Mar-94 Better syntax error message
+# B.Simon 15-Oct-98 Embed strings in pseudocode
+
+pointer procedure vex_compile (expr)
+
+char expr[ARB] # i: Expression to be parsed
+#--
+include "vex.com"
+
+int ic, fd, len
+bool debug
+pointer sp, pcode
+
+data debug / false /
+
+int open(), stropen(), strlen(), fstati(), yyparse()
+
+int vex_gettok ()
+extern vex_gettok
+
+begin
+ # Open the expression as a file
+
+ for (ic = 1; IS_WHITE(expr[ic]); ic = ic + 1)
+ ;
+
+ if (expr[ic] == '@') {
+ fd = open (expr[ic+1], READ_ONLY, TEXT_FILE)
+ len = fstati (fd, F_FILESIZE) + 1
+
+ } else {
+ len = strlen (expr[ic]) + 1
+ fd = stropen (expr[ic], len, READ_ONLY)
+ }
+
+ # Create pseudocode structure
+
+ call malloc (pcode, SZ_VEXSTRUCT, TY_STRUCT)
+
+ call malloc (VEX_CODE(pcode), 2 * len, TY_INT)
+ call stk_init (VEX_STACK(pcode))
+
+ # Initialize parsing common block
+
+ call smark (sp)
+ call salloc (line, SZ_LINE, TY_CHAR)
+
+ ch = line
+ Memc[line] = EOS
+
+ ncode = 0
+ maxcode = 2 * len
+ code = VEX_CODE(pcode)
+ stack = VEX_STACK(pcode)
+
+ # Parse expression to produce reverse polish code
+
+ if (yyparse (fd, debug, vex_gettok) == ERR) {
+ call eprintf ("%s\n%*t^\n")
+ call pargstr (Memc[line])
+ call pargi (ch-line)
+
+ call error (1, "Syntax error in expression")
+ }
+
+ # Clean up and return pseudocode structure
+
+ call stk_clear (VEX_STACK(pcode))
+
+ call close (fd)
+ call sfree (sp)
+ return (pcode)
+end
+
+# VEX_GETTOK -- Get the next token from the input
+
+int procedure vex_gettok (fd, value)
+
+int fd # i: File containing expression to be lexed
+pointer value # o: Address on parse stack to store token
+#--
+include "vex.com"
+
+double constant
+int ic, jc, nc, type, index
+int idftype[4], keytype[3], btype[9]
+pointer sp, errmsg, token
+
+string fn1tok FN1STR
+string fn2tok FN2STR
+
+string idftok "indefi indefr indefd indef"
+data idftype / Y_INT, Y_REAL, Y_DOUBLE, Y_REAL /
+
+string keytok "if then else"
+data keytype / Y_IF, Y_THEN, Y_ELSE /
+
+string btoken ".or. .and. .eq. .ne. .lt. .gt. .le. .ge. .not."
+data btype / Y_OR, Y_AND, Y_EQ, Y_NE, Y_LT, Y_GT, Y_LE, Y_GE, Y_NOT /
+
+string badsymb "Operator not recognized (%s)"
+
+int getline(), lexnum(), ctod(), stridxs(), word_match()
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+ call malloc (token, MAX_TOKEN, TY_CHAR)
+
+ # Skip over leading white space and comments
+
+ while (Memc[ch] <= BLANK || Memc[ch] == CMTCHAR) {
+
+ # If all characters have been read from the current line
+ # or a comment character was found, get the next line
+
+ if (Memc[ch] == EOS || Memc[ch] == CMTCHAR) {
+ ch = line
+ if (getline (fd, Memc[line]) == EOF) {
+ Memc[ch] = EOS
+ break
+ }
+ } else {
+ ch = ch + 1
+ }
+ }
+
+ # The token type is determined from the first character in the token
+
+ Memc[token] = EOS
+
+ # End of expression token
+
+ if (Memc[ch] == EOS) {
+ type = Y_DONE
+
+ # Numeric constant is too difficult to parse,
+ # Pass the job to lexnum and ctod
+
+ } else if (IS_DIGIT(Memc[ch])) {
+
+ ic = 1
+ index = lexnum (Memc[ch], ic, nc)
+ if (index != LEX_REAL) {
+ type = Y_INT
+ } else if (nc > 8) {
+ type = Y_DOUBLE
+ } else {
+ jc = stridxs ("dD", Memc[ch])
+ if (jc == 0 || jc > nc) {
+ type = Y_REAL
+ } else {
+ type = Y_DOUBLE
+ }
+ }
+
+ ic = 1
+ nc = ctod (Memc[ch], ic, constant)
+ nc = min (nc, MAX_TOKEN)
+
+ call strcpy (Memc[ch], Memc[token], nc)
+ ch = ch + ic - 1
+
+ # Token is alphanumeric. Determine what type of token
+
+ } else if (IS_ALPHA (Memc[ch])) {
+
+ # Gather characters in token
+
+ for (ic = 1; ic <= MAX_TOKEN; ic = ic + 1) {
+ if (Memc[ch] != '_' && ! IS_ALNUM(Memc[ch]))
+ break
+
+ if (IS_UPPER(Memc[ch]))
+ Memc[token+ic-1] = TO_LOWER(Memc[ch])
+ else
+ Memc[token+ic-1] = Memc[ch]
+ ch = ch + 1
+ }
+ Memc[token+ic-1] = EOS
+
+ # Check to see if token is string "INDEF"
+
+ index = word_match (Memc[token], idftok)
+
+ if (index > 0) {
+ type = idftype[index]
+ call strupr (Memc[token])
+
+ } else {
+
+ # Check to see if token is function or keyword name
+ # If not, add it as a new variable
+
+ index = word_match (Memc[token], fn1tok)
+ if (index > 0) {
+ type = Y_FN1
+
+ } else {
+ index = word_match (Memc[token], fn2tok)
+ if (index > 0) {
+ type = Y_FN2
+
+ } else {
+ index = word_match (Memc[token], keytok)
+ if (index > 0) {
+ type = keytype[index]
+ Memc[token] = EOS
+ } else {
+ type = Y_VAR
+ }
+ }
+ }
+ }
+
+ # Tokens beginning with a dot are numbers or boolean operators
+
+ } else if (Memc[ch] == DOT) {
+
+ if (IS_DIGIT (Memc[ch+1])) {
+ ic = 1
+ index = lexnum (Memc[ch], ic, nc)
+
+ if (index != LEX_REAL) {
+ type = Y_INT
+ } else if (nc < 9) {
+ type = Y_REAL
+ } else {
+ type = Y_DOUBLE
+ }
+
+ ic = 1
+ nc = ctod (Memc[ch], ic, constant)
+ nc = min (nc, MAX_TOKEN)
+
+ call strcpy (Memc[ch], Memc[token], nc)
+ ch = ch + ic - 1
+
+ } else {
+
+ # Gather characters in token
+
+ ch = ch + 1
+ Memc[token] = DOT
+ for (ic = 2; ic < MAX_TOKEN && Memc[ch] != DOT; ic = ic + 1) {
+ if (Memc[ch] == EOS)
+ break
+ if (IS_UPPER(Memc[ch]))
+ Memc[token+ic-1] = TO_LOWER(Memc[ch])
+ else
+ Memc[token+ic-1] = Memc[ch]
+ ch = ch + 1
+ }
+
+ Memc[token+ic-1] = Memc[ch]
+ Memc[token+ic] = EOS
+ ch = ch + 1
+
+ index = word_match (Memc[token], btoken)
+ if (type > 0) {
+ type = btype[index]
+ } else {
+ call sprintf (Memc[errmsg], SZ_LINE, badsymb)
+ call pargstr (Memc[token])
+ call error (1, Memc[errmsg])
+ }
+ }
+
+ # Characters preceded by a dollar sign are identifiers
+
+ } else if (Memc[ch] == DOLLAR) {
+
+ ch = ch + 1
+ for (ic = 1; ic <= MAX_TOKEN && Memc[ch] > BLANK; ic = ic + 1) {
+ if (IS_UPPER(Memc[ch]))
+ Memc[token+ic-1] = TO_LOWER(Memc[ch])
+ else
+ Memc[token+ic-1] = Memc[ch]
+ ch = ch + 1
+ }
+ Memc[token+ic-1] = EOS
+
+ type = Y_VAR
+
+ # Anything else is a symbol
+
+ } else {
+ switch (Memc[ch]) {
+ case '*':
+ if (Memc[ch+1] != '*') {
+ type = Y_MUL
+ } else {
+ type = Y_POW
+ ch = ch + 1
+ }
+ case '/':
+ type = Y_DIV
+ case '+':
+ type = Y_ADD
+ case '-':
+ type = Y_SUB
+ case '(':
+ type = Y_LPAR
+ case ')':
+ type = Y_RPAR
+ case ',':
+ type = Y_COMMA
+ case '<':
+ if (Memc[ch+1] != '=') {
+ type = Y_LT
+ } else {
+ type = Y_LE
+ ch = ch + 1
+ }
+ case '>':
+ if (Memc[ch+1] != '=') {
+ type = Y_GT
+ } else {
+ type = Y_GE
+ ch = ch + 1
+ }
+ case '|':
+ if (Memc[ch+1] != '|') {
+ type = Y_WRONG
+ } else {
+ type = Y_OR
+ ch = ch + 1
+ }
+ case '&':
+ if (Memc[ch+1] != '&') {
+ type = Y_WRONG
+ } else {
+ type = Y_AND
+ ch = ch + 1
+ }
+ case '=':
+ if (Memc[ch+1] != '=') {
+ type = Y_WRONG
+ } else {
+ type = Y_EQ
+ ch = ch + 1
+ }
+ case '!':
+ if (Memc[ch+1] != '=') {
+ type = Y_NOT
+ } else {
+ type = Y_NE
+ ch = ch + 1
+ }
+ default:
+ Memc[ch+1] = EOS
+ call sprintf (Memc[errmsg], SZ_LINE, badsymb)
+ call pargstr (Memc[ch])
+ call error (1, Memc[errmsg])
+ }
+
+ ch = ch + 1
+ }
+
+ #
+ if (Memc[token] == EOS) {
+ call mfree (token, TY_CHAR)
+ token = NULL
+ }
+
+ Memi[value] = token
+ return (type)
+end
+
+# VEX_ADDCODE -- Add an instruction to the code array
+
+procedure vex_addcode (type)
+
+int type # i: Instruction type
+#--
+include "vex.com"
+
+begin
+
+ if (ncode == maxcode)
+ call error (1, "Expression too complex")
+ else {
+ Memi[code] = type
+ code = code + 1
+ ncode = ncode + 1
+ }
+
+end
+
+# VEX_ADDSTR -- Embed a string constant in the pseudo-code
+
+procedure vex_addstr (token)
+
+pointer token # u: Pointer to token string
+#--
+include "vex.com"
+
+int ic
+
+begin
+ if (token == NULL)
+ call error (1, "Expression token missing")
+
+ if (Memc[token] == EOS)
+ call error (1, "Expression token blank")
+
+ ic = 0
+ repeat {
+ ic = ic + 1
+
+ if (ncode == maxcode)
+ call error (1, "Expression too complex")
+ else {
+ Memi[code] = Memc[token+ic-1]
+ code = code + 1
+ ncode = ncode + 1
+ }
+
+ } until (Memc[token+ic-1] == EOS)
+
+ call mfree (token, TY_CHAR)
+end
+
+# VEX_GETSTR -- Retrieve a token string from the pseudocode array
+
+procedure vex_getstr (op, token, maxch)
+
+pointer op # u: Location of token string in pseudocode
+char token[ARB] # o: Token string
+int maxch # i: Maximum length of token
+#--
+int ic
+
+begin
+ # The token begins one position after op and is
+ # termminated by an EOS
+
+ ic = 0
+ repeat {
+ ic = ic + 1
+ op = op + 1
+ if (ic <= maxch)
+ token[ic] = Memi[op]
+
+ } until (Memi[op] == EOS)
+
+end
diff --git a/pkg/utilities/nttools/stxtools/vexeval.x b/pkg/utilities/nttools/stxtools/vexeval.x
new file mode 100644
index 00000000..40b10fbd
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/vexeval.x
@@ -0,0 +1,228 @@
+include "vex.h"
+
+# VEX_EVAL -- Evaluate the pseudocode
+#
+# This procedure evaluates the pseudocode produced by vex_compile(). Evaluation
+# is performed on an entire vector at a time. The calling program must
+# supply a subroutine which returns the vector associated with a variable name.
+# The procedure is called as follows: call getvar(stack, name), where
+# stack is a pointer to the stack structure and name is the variable name.
+# This procedure should call stk_alloc(stack, len, type) passing it the stack
+# pointer, the length of the new array, and the type of the new array. The
+# pointer to the new array is returned as the function value. The procedure
+# should then fill in the values in the array. Code is the pointer returned
+# by vex_compile(). Nil is a value substituted for the result of an illegal
+# operation, such as division by zero. Type is the data type of expression.
+# To retrieve the results of the expression, call vex_copy[dir], which
+# retrieves the result as a double, integer, or real array and clears the
+# stack for the next call of vex_eval.
+#
+# B.Simon 21-May-90 Original
+# B.Simon 24-Apr-91 Revised to handle multiple types
+# B.Simon 15-Oct-98 Embed strings in pseudocode
+
+procedure vex_eval (code, getvar, nil, type)
+
+pointer code # i: Pointer to pseudocode structure
+extern getvar # i: Function which returns a vector given a name
+double nil # i: Nil value used to replace illegal ops
+int type # o: Data type of expression
+#--
+double junk
+int len, toktype
+pointer sp, token, errmsg, stack, op, var
+
+string fn1tok FN1STR
+string fn2tok FN2STR
+
+int word_match
+double vex_nilf()
+errchk vex_push
+
+string badcode "vex_eval : Illegal opcode (%d)"
+string badfunc "vex_eval : Illegal function name (%s)"
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (token, MAX_TOKEN, TY_CHAR)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ # Initialize the undefined operation function
+
+ junk = vex_nilf (nil)
+
+ # Execute each code token until stop token found
+
+ stack = VEX_STACK(code)
+ for (op = VEX_CODE(code); Memi[op] != Y_DONE; op = op + 1) {
+ call pargi (Memi[op])
+
+ # Perform the indicated operation on the stack variables
+
+ switch (Memi[op]) {
+ case Y_VAR, Y_INT, Y_REAL, Y_DOUBLE:
+ toktype = Memi[op]
+ call vex_getstr (op, Memc[token], MAX_TOKEN)
+ call vex_push (stack, getvar, toktype, Memc[token])
+
+ case Y_FN1:
+ call vex_getstr (op, Memc[token], MAX_TOKEN)
+
+ switch (word_match (Memc[token], fn1tok)) {
+ case FN1_ABS:
+ call vex_abs (stack)
+
+ case FN1_ACOS:
+ call vex_acos (stack)
+
+ case FN1_ASIN:
+ call vex_asin (stack)
+
+ case FN1_ATAN:
+ call vex_atan (stack)
+
+ case FN1_COS:
+ call vex_cos (stack)
+
+ case FN1_COSH:
+ call vex_cosh (stack)
+
+ case FN1_CUBE:
+ call vex_cube (stack)
+
+ case FN1_DOUBLE:
+ call vex_double (stack)
+
+ case FN1_EXP:
+ call vex_exp (stack)
+
+ case FN1_INT:
+ call vex_int (stack)
+
+ case FN1_LOG:
+ call vex_log (stack)
+
+ case FN1_LOG10:
+ call vex_log10 (stack)
+
+ case FN1_NINT:
+ call vex_nint (stack)
+
+ case FN1_REAL:
+ call vex_real (stack)
+
+ case FN1_SIN:
+ call vex_sin (stack)
+
+ case FN1_SINH:
+ call vex_sinh (stack)
+
+ case FN1_SQR:
+ call vex_sqr (stack)
+
+ case FN1_SQRT:
+ call vex_sqrt (stack)
+
+ case FN1_TAN:
+ call vex_tan (stack)
+
+ case FN1_TANH:
+ call vex_tanh (stack)
+
+ default:
+ call sprintf (Memc[errmsg], SZ_LINE, badfunc)
+ call pargstr (Memc[token])
+ call error (1, Memc[errmsg])
+ }
+
+ case Y_FN2:
+ call vex_getstr (op, Memc[token], MAX_TOKEN)
+
+ switch (word_match (Memc[token], fn2tok)) {
+ case FN2_ATAN2:
+ call vex_atan2 (stack)
+
+ case FN2_DIM:
+ call vex_dim (stack)
+
+ case FN2_MAX:
+ call vex_max (stack)
+
+ case FN2_MIN:
+ call vex_min (stack)
+
+ case FN2_MOD:
+ call vex_mod (stack)
+
+ case FN2_SIGN:
+ call vex_sig (stack)
+
+ default:
+ call sprintf (Memc[errmsg], SZ_LINE, badfunc)
+ call pargstr (Memc[token])
+ call error (1, Memc[errmsg])
+ }
+
+ case Y_IF:
+ call vex_if (stack)
+
+ case Y_OR:
+ call vex_or (stack)
+
+ case Y_AND:
+ call vex_and (stack)
+
+ case Y_NOT:
+ call vex_not (stack)
+
+ case Y_EQ:
+ call vex_eq (stack)
+
+ case Y_NE:
+ call vex_ne (stack)
+
+ case Y_LT:
+ call vex_lt (stack)
+
+ case Y_GT:
+ call vex_gt (stack)
+
+ case Y_LE:
+ call vex_le (stack)
+
+ case Y_GE:
+ call vex_ge (stack)
+
+ case Y_ADD:
+ call vex_add (stack)
+
+ case Y_SUB:
+ call vex_sub (stack)
+
+ case Y_MUL:
+ call vex_mul (stack)
+
+ case Y_DIV:
+ call vex_div (stack)
+
+ case Y_NEG:
+ call vex_neg (stack)
+
+ case Y_POW:
+ call vex_pow (stack)
+
+ default:
+ call sprintf (Memc[errmsg], SZ_LINE, badcode)
+ call pargs (Memi[op])
+ call error (1, Memc[errmsg])
+ }
+ }
+
+ # Retrieve the result of the expression,
+ # but only return the type to the user
+
+ call stk_fetch (stack, 1, var, len, type)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/stxtools/vexfree.x b/pkg/utilities/nttools/stxtools/vexfree.x
new file mode 100644
index 00000000..f98bee57
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/vexfree.x
@@ -0,0 +1,22 @@
+include "vex.h"
+
+# VEX_FREE -- Free the pseudocode structure
+#
+# This procedure frees the structure created by vex_compile() and evaluated
+# by vex_eval()
+#
+# B.Simon 21-May-90 Original
+# B.Simon 19-Apr-91 Revised to handle multiple types
+
+procedure vex_free (code)
+
+pointer code # i: Pointer to pseudocode structure
+#--
+
+begin
+ call stk_free (VEX_STACK(code))
+
+ call mfree (VEX_CODE(code), TY_INT)
+ call mfree (code, TY_STRUCT)
+end
+
diff --git a/pkg/utilities/nttools/stxtools/vexfunc.x b/pkg/utilities/nttools/stxtools/vexfunc.x
new file mode 100644
index 00000000..b4e40ae6
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/vexfunc.x
@@ -0,0 +1,2011 @@
+include <mach.h>
+include "vex.h"
+
+define MAX_EXP (2.3 * MAX_EXPONENT)
+define MIN_REAL 1.0e-20
+define MIN_DOUBLE 1.0d-20
+
+# VEX_FUNC -- Miscelaneous procedures used by the vex expression evaluator.
+#
+# Mostly these functions implement single opcodes such as add, sin, and
+# push. However, it also includes vex_copy[dir], which copies the array
+# on the top of the stack into a user array and vex_errf, which returns
+# the substitute value used when an opcode would return an undefined
+# value. The only functions which should be called directly from a user's
+# program are vex_copy[dir].
+#
+# B.Simon 24-Apr-91 Original
+# B.Simon 15-Oct-98 Rewrite vex_push to use embedded strings
+
+# VEX_ABS -- Absolute value function
+
+procedure vex_abs (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ out = stk_alloc (stack, len, type)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memi[out+i] = abs (Memi[in+i])
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = abs (Memr[in+i])
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = abs (Memd[in+i])
+
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_ACOS -- Arc cosine function
+
+procedure vex_acos (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+double vex_errf()
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ if (type == TY_INT) {
+ out = stk_alloc (stack, len, TY_REAL)
+ } else {
+ out = stk_alloc (stack, len, type)
+ }
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in+i] < -1 || Memi[in+i] > 1) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = acos (real (Memi[in+i]))
+ }
+ }
+
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in+i] < -1.0 || Memr[in+i] > 1.0) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = acos (Memr[in+i])
+ }
+ }
+
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in+i] < -1.0 || Memd[in+i] > 1.0) {
+ Memd[out+i] = vex_errf (stack, i)
+ } else {
+ Memd[out+i] = acos (Memd[in+i])
+ }
+ }
+
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_ADD -- Addition function
+
+procedure vex_add (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, type)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memi[out+i] = Memi[in[1]+i] + Memi[in[2]+i]
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = Memr[in[1]+i] + Memr[in[2]+i]
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = Memd[in[1]+i] + Memd[in[2]+i]
+
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_AND -- Logical and
+
+procedure vex_and (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, TY_INT)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in[1]+i] != 0 && Memi[in[2]+i] != 0) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in[1]+i] != 0.0 && Memr[in[2]+i] != 0.0) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in[1]+i] != 0.0 && Memd[in[2]+i] != 0.0) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_ASIN -- Arc sine function
+
+procedure vex_asin (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+double vex_errf()
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ if (type == TY_INT) {
+ out = stk_alloc (stack, len, TY_REAL)
+ } else {
+ out = stk_alloc (stack, len, type)
+ }
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in+i] < -1 || Memi[in+i] > 1) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = asin (real (Memi[in+i]))
+ }
+ }
+
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in+i] < -1.0 || Memr[in+i] > 1.0) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = asin (Memr[in+i])
+ }
+ }
+
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in+i] < -1.0 || Memd[in+i] > 1.0) {
+ Memd[out+i] = vex_errf (stack, i)
+ } else {
+ Memd[out+i] = asin (Memd[in+i])
+ }
+ }
+
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_ATAN -- Arc tangent function with one argument
+
+procedure vex_atan (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ if (type == TY_INT) {
+ out = stk_alloc (stack, len, TY_REAL)
+ } else {
+ out = stk_alloc (stack, len, type)
+ }
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memr[out+i] = atan (real (Memi[in+i]))
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = atan (Memr[in+i])
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = atan (Memd[in+i])
+
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_ATAN2 -- Arc tangent function with two arguments
+
+procedure vex_atan2 (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+double vex_errf()
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ if (type == TY_INT) {
+ out = stk_alloc (stack, len, TY_REAL)
+ } else {
+ out = stk_alloc (stack, len, type)
+ }
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in[1]+i] == 0 && Memi[in[2]+i] == 0) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = atan2 (real (Memi[in[1]+i]),
+ real (Memi[in[2]+i]))
+ }
+ }
+
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in[1]+i] == 0.0 && Memr[in[2]+i] == 0.0) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = atan2 (Memr[in[1]+i], Memr[in[2]+i])
+ }
+ }
+
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in[1]+i] == 0.0 && Memd[in[2]+i] == 0.0) {
+ Memd[out+i] = vex_errf (stack, i)
+ } else {
+ Memd[out+i] = atan2 (Memd[in[1]+i], Memd[in[2]+i])
+ }
+ }
+
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_COPYD -- Copy the top element of the stack into a double array
+
+procedure vex_copyd (code, nullval, buffer, maxbuf)
+
+pointer code # i: Pseudocode structure pointer
+double nullval # i: Value to substitute for nulls
+double buffer[ARB] # o: Output array
+int maxbuf # i: Length of buffer
+#--
+int len, type, ibuf
+pointer stack, var, nullbuf
+
+string badsize "Cannot copy more elements than stack contains"
+
+begin
+ stack = VEX_STACK(code)
+ call stk_get (stack, TOP, var, len, type)
+
+ if (type != TY_DOUBLE)
+ call stk_coerce (stack, TOP, TY_DOUBLE, var)
+
+ if (maxbuf <= len) {
+ do ibuf = 1, maxbuf {
+ buffer[ibuf] = Memd[var]
+ var = var + 1
+ }
+
+ } else if (len != 0) {
+ call error (1, badsize)
+
+ } else {
+ do ibuf = 1, maxbuf
+ buffer[ibuf] = Memd[var]
+ }
+
+ # Set the null value in the output array
+
+ call stk_getnull (stack, nullbuf)
+ if (nullbuf != NULL) {
+ do ibuf = 1, maxbuf {
+ if (Memb[nullbuf])
+ buffer[ibuf] = nullval
+ if (len > 0)
+ nullbuf = nullbuf + 1
+ }
+ }
+
+ call stk_clear (stack)
+end
+
+# VEX_COPYI -- Copy the top element of the stack into an integer array
+
+procedure vex_copyi (code, nullval, buffer, maxbuf)
+
+pointer code # i: Pseudocode structure pointer
+int nullval # i: Value to substitute for nulls
+int buffer[ARB] # o: Output array
+int maxbuf # i: Length of buffer
+#--
+int len, type, ibuf
+pointer stack, var, nullbuf
+
+string badsize "Cannot copy more elements than stack contains"
+
+begin
+ stack = VEX_STACK(code)
+ call stk_get (stack, TOP, var, len, type)
+
+ if (type != TY_INT)
+ call stk_coerce (stack, TOP, TY_INT, var)
+
+ if (maxbuf <= len) {
+ do ibuf = 1, maxbuf {
+ buffer[ibuf] = Memi[var]
+ var = var + 1
+ }
+
+ } else if (len != 0) {
+ call error (1, badsize)
+
+ } else {
+ do ibuf = 1, maxbuf
+ buffer[ibuf] = Memi[var]
+ }
+
+ # Set the null value in the output array
+
+ call stk_getnull (stack, nullbuf)
+ if (nullbuf != NULL) {
+ do ibuf = 1, maxbuf {
+ if (Memb[nullbuf])
+ buffer[ibuf] = nullval
+ if (len > 0)
+ nullbuf = nullbuf + 1
+ }
+ }
+
+ call stk_clear (stack)
+end
+
+# VEX_COPYR -- Copy the top element of the stack into a real array
+
+procedure vex_copyr (code, nullval, buffer, maxbuf)
+
+pointer code # i: Pseudocode structure pointer
+real nullval # i: Value to substitute for nulls
+real buffer[ARB] # o: Output array
+int maxbuf # i: Length of buffer
+#--
+int len, type, ibuf
+pointer stack, var, nullbuf
+
+string badsize "Cannot copy more elements than stack contains"
+
+begin
+ stack = VEX_STACK(code)
+ call stk_get (stack, TOP, var, len, type)
+
+ if (type != TY_REAL)
+ call stk_coerce (stack, TOP, TY_REAL, var)
+
+ if (maxbuf <= len) {
+ do ibuf = 1, maxbuf {
+ buffer[ibuf] = Memr[var]
+ var = var + 1
+ }
+
+ } else if (len != 0) {
+ call error (1, badsize)
+
+ } else {
+ do ibuf = 1, maxbuf
+ buffer[ibuf] = Memr[var]
+ }
+
+ # Set the null value in the output array
+
+ call stk_getnull (stack, nullbuf)
+ if (nullbuf != NULL) {
+ do ibuf = 1, maxbuf {
+ if (Memb[nullbuf])
+ buffer[ibuf] = nullval
+ if (len > 0)
+ nullbuf = nullbuf + 1
+ }
+ }
+
+ call stk_clear (stack)
+end
+
+# VEX_COS -- Cosine function
+
+procedure vex_cos (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ if (type == TY_INT) {
+ out = stk_alloc (stack, len, TY_REAL)
+ } else {
+ out = stk_alloc (stack, len, type)
+ }
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memr[out+i] = cos (real (Memi[in+i]))
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = cos (Memr[in+i])
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = cos (Memd[in+i])
+
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_COSH -- Hyperbolic cosine function
+
+procedure vex_cosh (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+double vex_errf()
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ if (type == TY_INT) {
+ out = stk_alloc (stack, len, TY_REAL)
+ } else {
+ out = stk_alloc (stack, len, type)
+ }
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in+i] > MAX_EXP) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = cosh (real (Memi[in+i]))
+ }
+ }
+
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in+i] > MAX_EXP) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = cosh (Memr[in+i])
+ }
+ }
+
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in+i] > MAX_EXP) {
+ Memd[out+i] = vex_errf (stack, i)
+ } else {
+ Memd[out+i] = cosh (Memd[in+i])
+ }
+ }
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_CUBE -- Third power
+
+procedure vex_cube (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ out = stk_alloc (stack, len, type)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memi[out+i] = Memi[in+i] * Memi[in+i] * Memi[in+i]
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = Memr[in+i] * Memr[in+i] * Memr[in+i]
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = Memd[in+i] * Memd[in+i] * Memd[in+i]
+
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_DIM -- Positive difference
+
+procedure vex_dim (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, type)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memi[out+i] = dim (Memi[in[1]+i], Memi[in[2]+i])
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = dim (Memr[in[1]+i], Memr[in[2]+i])
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = dim (Memd[in[1]+i], Memd[in[2]+i])
+
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_DIV -- Division function
+
+procedure vex_div (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+double vex_errf()
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, type)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in[2]+i] == 0) {
+ Memi[out+i] = vex_errf (stack, i)
+ } else {
+ Memi[out+i] = Memi[in[1]+i] / Memi[in[2]+i]
+ }
+ }
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (abs(Memr[in[2]+i]) < MIN_REAL) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = Memr[in[1]+i] / Memr[in[2]+i]
+ }
+ }
+
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (abs(Memd[in[2]+i]) < MIN_DOUBLE) {
+ Memd[out+i] = vex_errf (stack, i)
+ } else {
+ Memd[out+i] = Memd[in[1]+i] / Memd[in[2]+i]
+ }
+ }
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_DOUBLE -- Convert to double
+
+procedure vex_double (stack)
+
+pointer stack # u: Stack descriptor
+#--
+pointer out
+
+begin
+ call stk_coerce (stack, TOP, TY_DOUBLE, out)
+
+end
+
+# VEX_EQ -- Logical equality
+
+procedure vex_eq (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, TY_INT)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in[1]+i] == Memi[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in[1]+i] == Memr[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in[1]+i] == Memd[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_ERRF -- Called when a function cannot be evaluated
+
+double procedure vex_errf (stack, index)
+
+pointer stack # u: Stack descriptor
+int index # i: Index to row with illegal operation
+double nil # i: Value substituted for illegal operation
+#--
+double substitute
+double temp
+
+data substitute / 0.0 /
+
+double vex_nilf()
+
+begin
+ call stk_initnull (stack, false)
+ call stk_setnull (stack, index)
+
+ return (substitute)
+
+ entry vex_nilf (nil)
+
+ temp = substitute
+ substitute = nil
+ return (temp)
+
+end
+
+# VEX_EXP -- Exponentiation function
+
+procedure vex_exp (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+double vex_errf()
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ if (type == TY_INT) {
+ out = stk_alloc (stack, len, TY_REAL)
+ } else {
+ out = stk_alloc (stack, len, type)
+ }
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in+i] > MAX_EXP) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = exp (real (Memi[in+i]))
+ }
+ }
+
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in+i] > MAX_EXP) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = exp (Memr[in+i])
+ }
+ }
+
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in+i] > MAX_EXP) {
+ Memd[out+i] = vex_errf (stack, i)
+ } else {
+ Memd[out+i] = exp (Memd[in+i])
+ }
+ }
+
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_GE -- Greater than or equal to function
+
+procedure vex_ge (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, TY_INT)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in[1]+i] >= Memi[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in[1]+i] >= Memr[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in[1]+i] >= Memd[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_GT -- Greater than function
+
+procedure vex_gt (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, TY_INT)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in[1]+i] > Memi[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in[1]+i] > Memr[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in[1]+i] > Memd[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_IF -- Conditional evaluation
+
+procedure vex_if (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, index, i
+pointer out, in[3]
+
+int stk_pos()
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 3, in, len, type)
+ index = stk_pos (stack, 3)
+ call stk_coerce (stack, index, TY_INT, in[1])
+
+ out = stk_alloc (stack, len, type)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in[1]+i] != 0) {
+ Memi[out+i] = Memi[in[2]+i]
+ } else {
+ Memi[out+i] = Memi[in[3]+i]
+ }
+ }
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memi[in[1]+i] != 0) {
+ Memr[out+i] = Memr[in[2]+i]
+ } else {
+ Memr[out+i] = Memr[in[3]+i]
+ }
+ }
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memi[in[1]+i] != 0) {
+ Memd[out+i] = Memd[in[2]+i]
+ } else {
+ Memd[out+i] = Memd[in[3]+i]
+ }
+ }
+ }
+
+ call stk_pop (stack, 3)
+end
+
+# VEX_INT -- Convert to integer
+
+procedure vex_int (stack)
+
+pointer stack # u: Stack descriptor
+#--
+pointer out
+
+begin
+ call stk_coerce (stack, TOP, TY_INT, out)
+
+end
+
+# VEX_LE -- Less than or equal to function
+
+procedure vex_le (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, TY_INT)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in[1]+i] <= Memi[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in[1]+i] <= Memr[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in[1]+i] <= Memd[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_LT -- Less than function
+
+procedure vex_lt (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, TY_INT)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in[1]+i] < Memi[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in[1]+i] < Memr[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in[1]+i] < Memd[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_LOG -- Natural log function
+
+procedure vex_log (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+double vex_errf()
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ if (type == TY_INT) {
+ out = stk_alloc (stack, len, TY_REAL)
+ } else {
+ out = stk_alloc (stack, len, type)
+ }
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in+i] <= 0) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = log (real (Memi[in+i]))
+ }
+ }
+
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in+i] <= 0.0) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = log (Memr[in+i])
+ }
+ }
+
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in+i] <= 0.0) {
+ Memd[out+i] = vex_errf (stack, i)
+ } else {
+ Memd[out+i] = log (Memd[in+i])
+ }
+ }
+
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_LOG10 -- Common log function
+
+procedure vex_log10 (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+double vex_errf()
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ if (type == TY_INT) {
+ out = stk_alloc (stack, len, TY_REAL)
+ } else {
+ out = stk_alloc (stack, len, type)
+ }
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in+i] <= 0) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = log10 (real (Memi[in+i]))
+ }
+ }
+
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in+i] <= 0.0) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = log10 (Memr[in+i])
+ }
+ }
+
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in+i] <= 0.0) {
+ Memd[out+i] = vex_errf (stack, i)
+ } else {
+ Memd[out+i] = log10 (Memd[in+i])
+ }
+ }
+
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_MAX -- Maximum of two numbers
+
+procedure vex_max (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, type)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memi[out+i] = max (Memi[in[1]+i], Memi[in[2]+i])
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = max (Memr[in[1]+i], Memr[in[2]+i])
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = max (Memd[in[1]+i], Memd[in[2]+i])
+
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_MIN -- Minimum of two numbers
+
+procedure vex_min (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, type)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memi[out+i] = min (Memi[in[1]+i], Memi[in[2]+i])
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = min (Memr[in[1]+i], Memr[in[2]+i])
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = min (Memd[in[1]+i], Memd[in[2]+i])
+
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_MOD -- Remainder function
+
+procedure vex_mod (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, type)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memi[out+i] = mod (Memi[in[1]+i], Memi[in[2]+i])
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = mod (Memr[in[1]+i], Memr[in[2]+i])
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = mod (Memd[in[1]+i], Memd[in[2]+i])
+
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_MUL -- Multiplication function
+
+procedure vex_mul (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, type)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memi[out+i] = Memi[in[1]+i] * Memi[in[2]+i]
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = Memr[in[1]+i] * Memr[in[2]+i]
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = Memd[in[1]+i] * Memd[in[2]+i]
+
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_NE -- Logical inequality
+
+procedure vex_ne (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, TY_INT)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in[1]+i] != Memi[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in[1]+i] != Memr[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in[1]+i] != Memd[in[2]+i]) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_NEG -- Negation function
+
+procedure vex_neg (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ out = stk_alloc (stack, len, type)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memi[out+i] = - Memi[in+i]
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = - Memr[in+i]
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = - Memd[in+i]
+
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_NINT -- Nearest integer
+
+procedure vex_nint (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer in, out
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ out = stk_alloc (stack, len, type)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memi[out+i] = Memi[in+i]
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = anint (Memr[in+i])
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = anint (Memd[in+i])
+
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_NOT -- Logical negation
+
+procedure vex_not (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ out = stk_alloc (stack, len, TY_INT)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in+i] != 0) {
+ Memi[out+i] = 0
+ } else {
+ Memi[out+i] = 1
+ }
+ }
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in+i] != 0.0) {
+ Memi[out+i] = 0
+ } else {
+ Memi[out+i] = 1
+ }
+ }
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in+i] != 0.0) {
+ Memi[out+i] = 0
+ } else {
+ Memi[out+i] = 1
+ }
+ }
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_OR -- Logical or
+
+procedure vex_or (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, TY_INT)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in[1]+i] != 0 || Memi[in[2]+i] != 0) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in[1]+i] != 0.0 || Memr[in[2]+i] != 0.0) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in[1]+i] != 0.0 || Memd[in[2]+i] != 0.0) {
+ Memi[out+i] = 1
+ } else {
+ Memi[out+i] = 0
+ }
+ }
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_POW -- Exponentiation function
+
+procedure vex_pow (stack)
+
+pointer stack # u: Stack descriptor
+#--
+double dtemp
+int index, len, type, i
+pointer out, in[2]
+real rtemp
+
+double vex_errf()
+int stk_pos()
+pointer stk_alloc()
+
+begin
+ # If the exponent is an integer, use the normal exponentiation
+ # otherwise, use the logarithmic formulation
+
+ call stk_get (stack, TOP, in[2], len, type)
+
+ if (type == TY_INT) {
+ index = stk_pos (stack, 2)
+ call stk_get (stack, index, in[1], len, type)
+
+ out = stk_alloc (stack, len, type)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memi[out+i] = Memi[in[1]+i] ** Memi[in[2]+i]
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = Memr[in[1]+i] ** Memi[in[2]+i]
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = Memd[in[1]+i] ** Memi[in[2]+i]
+ }
+
+ } else {
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, type)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in[1]+i] <= 0.0) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ rtemp = Memr[in[2]+i] * log(Memr[in[1]+i])
+ if (rtemp > MAX_EXP) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = exp (rtemp)
+ }
+ }
+ }
+
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in[1]+i] <= 0.0) {
+ Memd[out+i] = vex_errf (stack, i)
+ } else {
+ dtemp = Memd[in[2]+i] * log(Memd[in[1]+i])
+ if (dtemp > MAX_EXP) {
+ Memd[out+i] = vex_errf (stack, i)
+ } else {
+ Memd[out+i] = exp (dtemp)
+ }
+ }
+ }
+ }
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_PUSH -- Push a token onto the stack
+
+procedure vex_push (stack, getvar, type, token)
+
+pointer stack # i: Stack structure
+extern getvar # i: Function to return a variable
+int type # i: Token type
+char token[ARB] # i: Token string
+#--
+double dval
+int len, ic, nc, ival
+pointer sp, errmsg, var
+real rval
+
+string badtype "Unrecognized token type (%d)"
+
+int ctoi(), ctor(), ctod()
+pointer stk_alloc()
+errchk getvar
+
+begin
+ call smark (sp)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ len = STK_LENVAL(stack)
+
+ switch (type) {
+ case Y_VAR:
+ call getvar (stack, token)
+
+ case Y_INT:
+ var = stk_alloc (stack, len, TY_INT)
+
+ ic = 1
+ len = max (len, 1)
+ nc = ctoi (token, ic, ival)
+ call amovki (ival, Memi[var], len)
+
+ case Y_REAL:
+ var = stk_alloc (stack, len, TY_REAL)
+
+ ic = 1
+ len = max (len, 1)
+ nc = ctor (token, ic, rval)
+ call amovkr (rval, Memr[var], len)
+
+ case Y_DOUBLE:
+ var = stk_alloc (stack, len, TY_DOUBLE)
+
+ ic = 1
+ len = max (len, 1)
+ nc = ctod (token, ic, dval)
+ call amovkd (dval, Memd[var], len)
+
+ default:
+ call sprintf (Memc[errmsg], SZ_LINE, badtype)
+ call pargi (type)
+ call error (1, Memc[errmsg])
+ }
+
+ call sfree (sp)
+end
+
+# VEX_REAL -- Convert to real
+
+procedure vex_real (stack)
+
+pointer stack # u: Stack descriptor
+#--
+pointer out
+
+begin
+ call stk_coerce (stack, TOP, TY_REAL, out)
+
+end
+
+# VEX_SIG -- Sign transfer function
+
+procedure vex_sig (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, type)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memi[out+i] = sign (Memi[in[1]+i], Memi[in[2]+i])
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = sign (Memr[in[1]+i], Memr[in[2]+i])
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = sign (Memd[in[1]+i], Memd[in[2]+i])
+
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_SIN -- Sine function
+
+procedure vex_sin (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ if (type == TY_INT) {
+ out = stk_alloc (stack, len, TY_REAL)
+ } else {
+ out = stk_alloc (stack, len, type)
+ }
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memr[out+i] = sin (real (Memi[in+i]))
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = sin (Memr[in+i])
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = sin (Memd[in+i])
+
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_SINH -- Hyperbolic sine function
+
+procedure vex_sinh (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+double vex_errf()
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ if (type == TY_INT) {
+ out = stk_alloc (stack, len, TY_REAL)
+ } else {
+ out = stk_alloc (stack, len, type)
+ }
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in+i] > MAX_EXP) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = sinh (real (Memi[in+i]))
+ }
+ }
+
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in+i] > MAX_EXP) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = sinh (Memr[in+i])
+ }
+ }
+
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in+i] > MAX_EXP) {
+ Memd[out+i] = vex_errf (stack, i)
+ } else {
+ Memd[out+i] = sinh (Memd[in+i])
+ }
+ }
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_SQR -- Second power
+
+procedure vex_sqr (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ out = stk_alloc (stack, len, type)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memi[out+i] = Memi[in+i] * Memi[in+i]
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = Memr[in+i] * Memr[in+i]
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = Memd[in+i] * Memd[in+i]
+
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_SQRT -- Square root function
+
+procedure vex_sqrt (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+double vex_errf()
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ if (type == TY_INT) {
+ out = stk_alloc (stack, len, TY_REAL)
+ } else {
+ out = stk_alloc (stack, len, type)
+ }
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1 {
+ if (Memi[in+i] < 0) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = sqrt (real (Memi[in+i]))
+ }
+ }
+
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (Memr[in+i] < 0.0) {
+ Memr[out+i] = vex_errf (stack, i)
+ } else {
+ Memr[out+i] = sqrt (Memr[in+i])
+ }
+ }
+
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (Memd[in+i] < 0.0) {
+ Memd[out+i] = vex_errf (stack, i)
+ } else {
+ Memd[out+i] = sqrt (Memd[in+i])
+ }
+ }
+
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_SUB -- Subtraction function
+
+procedure vex_sub (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in[2]
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 2, in, len, type)
+ out = stk_alloc (stack, len, type)
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memi[out+i] = Memi[in[1]+i] - Memi[in[2]+i]
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = Memr[in[1]+i] - Memr[in[2]+i]
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = Memd[in[1]+i] - Memd[in[2]+i]
+
+ }
+
+ call stk_pop (stack, 2)
+end
+
+# VEX_TAN -- Tangent function
+
+procedure vex_tan (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ if (type == TY_INT) {
+ out = stk_alloc (stack, len, TY_REAL)
+ } else {
+ out = stk_alloc (stack, len, type)
+ }
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memr[out+i] = tan (real (Memi[in+i]))
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = tan (Memr[in+i])
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = tan (Memd[in+i])
+
+ }
+
+ call stk_pop (stack, 1)
+end
+
+# VEX_TANH -- Hyperbolic tangent function
+
+procedure vex_tanh (stack)
+
+pointer stack # u: Stack descriptor
+#--
+int len, type, i
+pointer out, in
+
+pointer stk_alloc()
+
+begin
+ call stk_fetch (stack, 1, in, len, type)
+ if (type == TY_INT) {
+ out = stk_alloc (stack, len, TY_REAL)
+ } else {
+ out = stk_alloc (stack, len, type)
+ }
+ len = max (len, 1)
+
+ switch (type) {
+ case TY_INT, TY_LONG:
+ do i = 0, len-1
+ Memr[out+i] = tanh (real (Memi[in+i]))
+
+ case TY_REAL:
+ do i = 0, len-1
+ Memr[out+i] = tanh (Memr[in+i])
+
+ case TY_DOUBLE:
+ do i = 0, len-1
+ Memd[out+i] = tanh (Memd[in+i])
+
+ }
+
+ call stk_pop (stack, 1)
+end
+
+
+
+
diff --git a/pkg/utilities/nttools/stxtools/vexstack.x b/pkg/utilities/nttools/stxtools/vexstack.x
new file mode 100644
index 00000000..8f51b2bb
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/vexstack.x
@@ -0,0 +1,585 @@
+include "vex.h"
+
+# VEX_STACK -- Procedures which manipulate the vex stack
+#
+# The expression evaluator, vex_eval, uses a stack to hold intermediate
+# results, constants, and variable names in the expression. There are
+# actually two stacks, a type stack wich contains the data types of the
+# elements on the stack, and a value stack, which contains pointers to
+# the stack elements. Constants and variable names are stored in two
+# buffers which are part of the stack structure and pointers to their
+# locations are placed on the stack. Intermediate results are stored in
+# malloc'ed arrays and their pointers are also placed on the stack. The
+# stack structure contains three indices, bottom, an index one greater
+# than the last constant or variable name, top, an index that is one
+# greater than the current top of stack, and high, an index that is one
+# greater than the last valid pointer on the stack. Valid pointers exist
+# beyond the top of stack because the arrays which store intermediate
+# results are not mfree'd when the stack is popped, instead, they are
+# kept in case they may be needed for a future intermediate result. The
+# only user callable procedure in this file is stk_alloc, which should
+# be called by getvar, the user's function which fills an array when
+# passed the name of a variable.
+#
+# B.Simon 24-Apr-91 Original
+# B.Simon 15-Oct-98 Store strings in pseudocode, not on stack
+
+# STK_ALLOC -- Allocate an array of the specified length and type
+
+pointer procedure stk_alloc (stack, len, type)
+
+pointer stack # i: Stack structure
+int len # i: Length of array to allocate
+int type # i: Data type of array (spp type)
+#--
+int index, stype, top
+pointer var, svar
+
+string badstack "stk_alloc: illegal type on stack"
+string badsize "Requested array size does not match previous requests"
+
+errchk stk_find
+
+begin
+ # Check to see if array length is being defined for the first time
+
+ if (STK_LENVAL(stack) == 0 && len != 0) {
+
+ # Store length in stack structure
+
+ STK_LENVAL(stack) = len
+
+ # Free all stack arrays not currently being used
+
+ index = STK_TOP(stack)
+ while (index < STK_HIGH(stack)) {
+ svar = STK_VALUE(stack,index)
+ stype = STK_TYPE(stack,index)
+ call mfree (svar, stype)
+ index = index + 1
+ }
+ STK_HIGH(stack) = STK_TOP(stack)
+
+ # Reallocate the null buffer
+
+ if (STK_NULLARY(stack) != NULL) {
+ call stk_freenull (stack)
+ call stk_initnull (stack, true)
+ }
+
+ # Convert length one arrays to their full length
+
+ index = 0
+ while (index < STK_TOP(stack)) {
+ svar = STK_VALUE(stack,index)
+ stype = STK_TYPE(stack,index)
+
+ call malloc (var, len, stype)
+ STK_VALUE(stack,index) = var
+ switch (stype) {
+ case TY_INT,TY_LONG:
+ call amovki (Memi[svar], Memi[var], len)
+ call mfree (svar, TY_INT)
+ case TY_REAL:
+ call amovkr (Memr[svar], Memr[var], len)
+ call mfree (svar, TY_REAL)
+ case TY_DOUBLE:
+ call amovkd (Memd[svar], Memd[var], len)
+ call mfree (svar, TY_DOUBLE)
+ default:
+ call error (1, badstack)
+ }
+ index = index + 1
+ }
+ }
+
+ # Check requested size
+
+ if (len != 0 && len != STK_LENVAL(stack))
+ call error (1, badsize)
+
+ # Look for an existing array of the same type
+
+ call stk_find (stack, type, index)
+
+ # Increment top of stack pointer
+
+ top = STK_TOP(stack)
+ STK_TOP(stack) = top + 1
+
+ # Swap array with one currently at top of stack
+
+ if (top != index) {
+ stype = STK_TYPE(stack,top)
+ STK_TYPE(stack,top) = STK_TYPE(stack,index)
+ STK_TYPE(stack,index) = stype
+
+ svar = STK_VALUE(stack,top)
+ STK_VALUE(stack,top) = STK_VALUE(stack,index)
+ STK_VALUE(stack,index) = svar
+ }
+
+ var = STK_VALUE(stack,top)
+ return (var)
+end
+
+# STK_CLEAR -- Clear all stack elements above the bottom
+
+procedure stk_clear (stack)
+
+pointer stack # u: Stack pointer
+#--
+int index
+
+begin
+ # Free all value arrays above the bottom of stack
+
+ index = 0
+ while (index < STK_HIGH(stack)) {
+ call mfree (STK_VALUE(stack,index), STK_TYPE(stack,index))
+ index = index + 1
+ }
+
+ # Free null array
+
+ call stk_freenull (stack)
+
+ # Reset scalars
+
+ STK_TOP(stack) = 0
+ STK_HIGH(stack) = 0
+ STK_LENVAL(stack) = 0
+end
+
+# STK_COERCE -- Coerce an array in the stack to the specified type
+
+procedure stk_coerce (stack, pos, type, var)
+
+pointer stack # i: Stack descriptor
+int pos # i: Position of array in stack
+int type # i: New type for array
+pointer var # o: New pointer to array
+#--
+int index, last, stype, len, i
+pointer svar
+
+string underflow "stk_coerce: underflow in expression evaluator"
+
+errchk stk_find
+
+begin
+ # Convert relative to absolute position
+
+ if (pos == TOP) {
+ index = STK_TOP(stack) - 1
+ if (index < 0)
+ call error (1, underflow)
+ } else {
+ index = pos
+ }
+
+ # If type of array matches requested type, return pointer to array
+ # Otherwise, get new array and copy old array to it
+
+ if (type == STK_TYPE(stack,index)) {
+ var = STK_VALUE(stack,index)
+
+ } else {
+ # Find array of correct type
+
+ last = index
+ call stk_find (stack, type, index)
+
+ # Copy array, converting to new type
+
+ len = max (1, STK_LENVAL(stack))
+ var = STK_VALUE(stack,index)
+
+ stype = STK_TYPE(stack,last)
+ svar = STK_VALUE(stack,last)
+
+ switch (type) {
+ case TY_INT,TY_LONG:
+ switch (stype) {
+ case TY_INT,TY_LONG:
+ ; # can't happen
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (IS_INDEFR(Memr[svar+i])) {
+ Memi[var+i] = INDEFI
+ } else {
+ Memi[var+i] = Memr[svar+i]
+ }
+ }
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (IS_INDEFD(Memd[svar+i])) {
+ Memi[var+i] = INDEFI
+ } else {
+ Memi[var+i] = Memd[svar+i]
+ }
+ }
+ }
+ case TY_REAL:
+ switch (stype) {
+ case TY_INT,TY_LONG:
+ do i = 0, len-1 {
+ if (IS_INDEFI(Memi[svar+i])) {
+ Memr[var+i] = INDEFR
+ } else {
+ Memr[var+i] = Memi[svar+i]
+ }
+ }
+ case TY_REAL:
+ ; # can't happen
+ case TY_DOUBLE:
+ do i = 0, len-1 {
+ if (IS_INDEFD(Memd[svar+i])) {
+ Memr[var+i] = INDEFR
+ } else {
+ Memr[var+i] = Memd[svar+i]
+ }
+ }
+ }
+ case TY_DOUBLE:
+ switch (stype) {
+ case TY_INT,TY_LONG:
+ do i = 0, len-1 {
+ if (IS_INDEFI(Memi[svar+i])) {
+ Memd[var+i] = INDEFD
+ } else {
+ Memd[var+i] = Memi[svar+i]
+ }
+ }
+ case TY_REAL:
+ do i = 0, len-1 {
+ if (IS_INDEFR(Memr[svar+i])) {
+ Memd[var+i] = INDEFD
+ } else {
+ Memd[var+i] = Memr[svar+i]
+ }
+ }
+ case TY_DOUBLE:
+ ; # can't happen
+ }
+ }
+
+ # Swap position of new and old arrays on stack
+
+ STK_TYPE(stack,last) = STK_TYPE(stack,index)
+ STK_TYPE(stack,index) = stype
+
+ STK_VALUE(stack,last) = STK_VALUE(stack,index)
+ STK_VALUE(stack,index) = svar
+ }
+
+end
+
+# STK_FETCH -- Fetch the specified number of arrays from the stack
+
+procedure stk_fetch (stack, nvar, var, len, type)
+
+pointer stack # i: Stack descriptor
+int nvar # i: Number of pointers requested
+pointer var[ARB] # o: Array pointers
+int len # o: Length of arrays
+int type # o: Type of arrays
+#--
+int one, two, index, ivar
+
+string underflow "stk_fetch: underflow in expression evaluator"
+
+errchk stk_coerce
+
+begin
+ # If length is not yet defined, STK_LENVAL equals zero
+
+ len = STK_LENVAL(stack)
+
+ # Find the highest type in the pointers to be returned
+
+ one = STK_TOP(stack) - 1
+ two = STK_TOP(stack) - 2
+
+ type = STK_TYPE(stack,one)
+ if (nvar > 1) {
+ switch (STK_TYPE(stack,two)) {
+ case TY_INT, TY_LONG:
+ ;
+ case TY_REAL:
+ if (type == TY_INT)
+ type = TY_REAL
+ case TY_DOUBLE:
+ type = TY_DOUBLE
+ }
+ }
+
+ # Retrieve pointers to arrays from stack. var[nvar] is top of stack
+ # Convert arrays to output type when the type differs
+
+ index = STK_TOP(stack) - nvar
+ do ivar = 1, nvar {
+ if (index < 0)
+ call error (1, underflow)
+
+ if (type == STK_TYPE(stack,index) || index < two) {
+ var[ivar] = STK_VALUE(stack,index)
+ } else {
+ call stk_coerce (stack, index, type, var[ivar])
+ }
+ index = index + 1
+ }
+
+end
+
+# STK_FIND -- Find a free array of the proper type on the stack
+
+procedure stk_find (stack, type, index)
+
+pointer stack # i: Stack descriptor
+int type # i: Required type
+int index # o: Position on the stack
+#--
+int len
+pointer var
+
+string overflow "Expression too complex to be evaluated"
+
+begin
+ # Try to find an array of the proper type already on the stack
+
+ index = STK_TOP(stack)
+ while (index < STK_HIGH(stack)) {
+ if (type == STK_TYPE(stack,index))
+ break
+
+ index = index + 1
+ }
+
+ # If not found, allocate a new array
+
+ if (index == MAX_STACK) {
+ call error (1, overflow)
+
+ } else if (index == STK_HIGH(stack)) {
+ len = max (1, STK_LENVAL(stack))
+ call malloc (var, len, type)
+
+ STK_TYPE(stack,index) = type
+ STK_VALUE(stack,index) = var
+ STK_HIGH(stack) = STK_HIGH(stack) + 1
+ }
+
+end
+
+# STK_FREE -- Free memory used by the stack
+
+procedure stk_free (stack)
+
+pointer stack # u: Stack pointer
+#--
+
+begin
+ # Free all values above the stack bottom
+
+ call stk_clear (stack)
+
+ # Free substructures in stack
+
+ if (STK_NULLARY(stack) != NULL)
+ call mfree (STK_NULLARY(stack), TY_BOOL)
+
+ call mfree (STK_VALARY(stack), TY_INT)
+ call mfree (STK_TYPARY(stack), TY_INT)
+
+ # Free the stack structure
+ call mfree (stack, TY_INT)
+end
+
+# STK_FREENULL -- Free the null array in the stack
+
+procedure stk_freenull (stack)
+
+pointer stack # u: Stack structure
+#--
+
+begin
+ if (STK_NULLARY(stack) != NULL)
+ call mfree (STK_NULLARY(stack), TY_BOOL)
+
+ STK_NULLARY(stack) = NULL
+end
+
+# STK_GET -- Get a single array from the stack
+
+procedure stk_get (stack, pos, var, len, type)
+
+pointer stack # i: Stack descriptor
+int pos # i: Position on the stack
+pointer var # o: Pointer to array
+int len # o: Length of array
+int type # o: Type of the array
+#--
+int index
+
+string underflow "stk_get: underflow in expression evaluator"
+
+begin
+ # Convert relative to absolute position
+
+ if (pos == TOP) {
+ index = STK_TOP(stack) - 1
+ if (index < 0)
+ call error (1, underflow)
+ } else {
+ index = pos
+ }
+
+ var = STK_VALUE(stack,index)
+ len = STK_LENVAL(stack)
+ type = STK_TYPE(stack,index)
+end
+
+# STK_GETNULL -- Get the null array from the stack
+
+procedure stk_getnull (stack, nullvec)
+
+pointer stack # i: Stack structure
+pointer nullvec # o: Null array
+#--
+
+begin
+ nullvec = STK_NULLARY(stack)
+end
+
+# STK_INIT -- Initialize the stack
+
+procedure stk_init (stack)
+
+pointer stack # o: Stack pointer
+#--
+
+begin
+ # Allocate stack and initialize members to zero
+
+ call calloc (stack, SZ_STKSTRUCT, TY_INT)
+
+ # Allocate substructures in stack
+
+ call malloc (STK_VALARY(stack), MAX_STACK, TY_INT)
+ call malloc (STK_TYPARY(stack), MAX_STACK, TY_INT)
+
+end
+
+# STK_INITNULL -- Initialize the null array on the stack
+
+procedure stk_initnull (stack, value)
+
+pointer stack # u: Stack structure
+bool value # i: Value used in initialization
+#--
+int len, i
+pointer nullvec
+
+begin
+ # Only initialize if array doesn't exist
+
+ if (STK_NULLARY(stack) == NULL) {
+ len = STK_LENVAL(stack)
+
+ # Allocate array
+ call malloc (nullvec, len, TY_BOOL)
+ STK_NULLARY(stack) = nullvec
+
+ # Initialize to value
+ do i = 0, len-1
+ Memb[nullvec+i] = value
+ }
+
+end
+
+# STK_ORNULL -- Update null array by doing a logical or
+
+procedure stk_ornull (stack, newvec, newlen)
+
+pointer stack # u: Stack structure
+bool newvec[ARB] # i: Array of new values
+int newlen # i: Length of new array
+#--
+int len, i
+pointer nullvec
+
+string badlength "stk_ornull: length of array does not match null array"
+
+begin
+ len = STK_LENVAL(stack)
+ if (len != newlen)
+ call error (1, badlength)
+
+ call stk_initnull (stack, false)
+ nullvec = STK_NULLARY(stack)
+
+ do i = 1, len {
+ Memb[nullvec] = Memb[nullvec] || newvec[i]
+ nullvec = nullvec + 1
+ }
+
+end
+
+# STK_POP -- Remove the specified number of arrays from the stack
+
+procedure stk_pop (stack, npop)
+
+pointer stack # u: Stack structure
+int npop # i: Number of arrays to pop
+#--
+int top, index, type
+pointer var
+
+string underflow "stk_pop: underflow in expression evaluator"
+
+begin
+
+ top = STK_TOP(stack) - 1
+ index = top - npop
+
+ if (index < 0) {
+ call error (1, underflow)
+ } else {
+ STK_TOP(stack) = index + 1
+ }
+
+ var = STK_VALUE(stack,index)
+ STK_VALUE(stack,index) = STK_VALUE(stack,top)
+ STK_VALUE(stack,top) = var
+
+ type = STK_TYPE(stack,index)
+ STK_TYPE(stack,index) = STK_TYPE(stack,top)
+ STK_TYPE(stack,top) = type
+
+end
+
+# STK_POS -- Compute absolute position on stack
+
+int procedure stk_pos (stack, pos)
+
+pointer stack # i: Stack structure
+int pos # i: Position relative to top of stack
+#--
+
+begin
+ return (STK_TOP(stack) - pos)
+end
+
+# STK_SETNULL -- Set a single value in the null array to true
+
+procedure stk_setnull (stack, index)
+
+pointer stack # u: Stack structure
+int index # i: Index into null array
+#--
+
+begin
+ STK_NULL(stack,index) = true
+end
+
diff --git a/pkg/utilities/nttools/stxtools/wcslab/mkpkg b/pkg/utilities/nttools/stxtools/wcslab/mkpkg
new file mode 100644
index 00000000..f5083925
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/wcslab/mkpkg
@@ -0,0 +1,17 @@
+# WCSLAB
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ wlutil.x <imio.h> <imhdr.h> <gset.h> <math.h>
+ wcslab.x <gset.h> <imhdr.h> <mwset.h> <math.h> "wcslab.h"\
+ "wcs_desc.h"
+ wlwcslab.x <gio.h> <gset.h> "wcslab.h" "wcs_desc.h"
+ wlsetup.x <gset.h> <mach.h> <math.h> <math/curfit.h>\
+ "wcslab.h" "wcs_desc.h"
+ wlgrid.x <gset.h> <math.h> "wcslab.h" "wcs_desc.h"
+ wllabel.x <gset.h> <math.h> "psiescape.h" "wcslab.h" "wcs_desc.h"
+ ;
diff --git a/pkg/utilities/nttools/stxtools/wcslab/mkpkg.ori b/pkg/utilities/nttools/stxtools/wcslab/mkpkg.ori
new file mode 100644
index 00000000..7108366c
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/wcslab/mkpkg.ori
@@ -0,0 +1,18 @@
+# WCSLAB
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ t_wcslab.x <gset.h> <imhdr.h>
+ wlutil.x <imio.h> <imhdr.h> <gset.h> <math.h>
+ wcslab.x <gset.h> <imhdr.h> <mwset.h> <math.h> "wcslab.h"\
+ "wcs_desc.h"
+ wlwcslab.x <gio.h> <gset.h> "wcslab.h" "wcs_desc.h"
+ wlsetup.x <gset.h> <mach.h> <math.h> <math/curfit.h>\
+ "wcslab.h" "wcs_desc.h"
+ wlgrid.x <gset.h> <math.h> "wcslab.h" "wcs_desc.h"
+ wllabel.x <gset.h> <math.h> "wcslab.h" "wcs_desc.h"
+ ;
diff --git a/pkg/utilities/nttools/stxtools/wcslab/psiescape.h b/pkg/utilities/nttools/stxtools/wcslab/psiescape.h
new file mode 100644
index 00000000..46da4ea2
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/wcslab/psiescape.h
@@ -0,0 +1,80 @@
+.help psiescape.h 1May92 plot
+.ih
+.NAME
+psiescape.h -- Define the special GIO escape instructions.
+.ih
+DESCRIPTION
+The following escape instructions are defined for the PostScript GKI
+Interpreter:
+
+ PS_CODE - Send the raw PostScript code to the output.
+ PS_IMAGE_RED_LUT - Download a new lookup table for the Red component
+ of an image.
+ PS_IMAGE_GREEN_LUT - Download a new lookup table for the Green component
+ of an image.
+ PS_IMAGE_BLUE_LUT - Download a new lookup table for the Blue component
+ of an image.
+ PS_GR_RED_LUT - Download a new lookup table for the Red component
+ for the graphics.
+ PS_GR_GREEN_LUT - Download a new lookup table for the Green component
+ for the graphics.
+ PS_GR_BLUE_LUT - Download a new lookup table for the Blue component
+ for the graphics.
+ PS_ROMAN_FONT - Specify a new font for the normal font.
+ PS_GREEK_FONT - Specify a new font for the greek font.
+ PS_ITALIC_FONT - Specify a new font for the italic font.
+ PS_BOLD_FONT - Specify a new font for the bold font.
+ PS_VARIABLE_SPACE - Change whether characters are mono-spaced or
+ variable-spaced.
+ PS_DASH, PS_DOT,
+ PS_SPACE - Change the sizes of a dash, a dot, and the space
+ between them.
+ PS_FILL_PATTERN - Add/change fill patterns.
+
+The size of the instruction array should have the following minimums:
+ - For the PS_CODE instruction, the array should be the length of the string
+ being passed.
+ - The size of each image LUT array is PS_IMAGE_LUT_SIZE.
+ - The size of each graphics LUT array is PS_GR_LUT_SIZE.
+ - The font arrays should be the length of the string containing the name
+ of the font to use.
+ - For the PS_VARIABLE_SPACE, the size is PS_VARIABLE_SPACE_SIZE.
+ - For PS_FILL_PATTERN, the size is PS_FILL_SIZE.
+
+.ih
+SEE ALSO
+t_psikern
+.endhelp
+#---------------------------------------------------------------------------
+
+# Define the escape instructions.
+define PS_CODE 1001
+define PS_IMAGE_RED_LUT 1002
+define PS_IMAGE_GREEN_LUT 1003
+define PS_IMAGE_BLUE_LUT 1004
+define PS_GR_RED_LUT 1005
+define PS_GR_GREEN_LUT 1006
+define PS_GR_BLUE_LUT 1007
+define PS_ROMAN_FONT 1008
+define PS_GREEK_FONT 1009
+define PS_ITALIC_FONT 1010
+define PS_BOLD_FONT 1011
+define PS_VARIABLE_SPACE 1012
+define PS_DOT 1013
+define PS_DASH 1014
+define PS_SPACE 1015
+define PS_FILL_PATTERN 1016
+define PS_IMAGE_LUT 1017
+define PS_GRAPHICS_LUT 1018
+
+# Define the sizes of the instruction arrays.
+define PS_MAX_LUT_VALUE 255
+define PS_IMAGE_LUT_SIZE 256
+define PS_GR_LUT_SIZE 16
+define PS_VARIABLE_SPACE_SIZE 1
+define PS_FILL_SIZE 9
+
+# Define how to pack/unpack a LUT defined as reals from 0-1 into
+# a short array from 0-PS_MAX_LUT_VALUE.
+define PS_PACKLUT (int($1*PS_MAX_LUT_VALUE))
+define PS_UNPACKLUT ($1/real(PS_MAX_LUT_VALUE))
diff --git a/pkg/utilities/nttools/stxtools/wcslab/t_wcslab.x b/pkg/utilities/nttools/stxtools/wcslab/t_wcslab.x
new file mode 100644
index 00000000..acafdf2f
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/wcslab/t_wcslab.x
@@ -0,0 +1,136 @@
+include <gset.h>
+include <imhdr.h>
+
+# T_WCSLAB -- Procedure to draw labels and grids in sky projection coordinates.
+#
+# Description
+# T_wcslab produces a labelling and grid based on the MWCS of a
+# specified image. This is the task interface to the programmer interface
+# wcslab. See wcslab.x for more information.
+#
+# Bugs
+# Can only handle sky projections for Right Ascension/Declination. This
+# should be able to deal with any of the projections for this system, but
+# has only been tested with the Tangent projection.
+#
+
+procedure t_wcslab()
+
+pointer image # I: name of the image
+int frame # I: display frame containing the image
+bool do_fill # I: true if the graph fills the specified viewport
+int mode # I: the graphics stream mode
+pointer device # I: the name of the graphics device
+real vl, vr, vb, vt # I: the edges of the graphics viewport
+
+pointer sp, title, gp, im, mw
+real c1, c2, l1, l2
+bool clgetb()
+int clgeti(), strncmp()
+pointer gopen(), immap(), mw_openim()
+real clgetr()
+
+begin
+ # Get memory.
+ call smark (sp)
+ call salloc (device, SZ_FNAME, TY_CHAR)
+ call salloc (image, SZ_FNAME, TY_CHAR)
+ call salloc (title, SZ_LINE, TY_CHAR)
+
+ # Since all the MWCS information comes from an image open it.
+ call clgstr ("image", Memc[image], SZ_FNAME)
+
+ if (Memc[image] != EOS) {
+
+ # Open the image.
+ im = immap (Memc[image], READ_ONLY, 0)
+
+ # Quit if the image is not 2-dimensional.
+ if (IM_NDIM(im) != 2) {
+ call eprintf ("Image: %s is not 2-dimensional\n")
+ call pargstr (Memc[image])
+ call sfree (sp)
+ return
+ }
+
+ # Set the default input image column and line limits.
+ c1 = 1.0
+ c2 = real (IM_LEN(im,1))
+ l1 = 1.0
+ l2 = real (IM_LEN(im,2))
+
+ # Open the WCS.
+ mw = mw_openim (im)
+
+ # Set up the default image title.
+ call strcpy (Memc[image], Memc[title], SZ_LINE)
+ call strcat (": ", Memc[title], SZ_LINE)
+ call strcat (IM_TITLE(im), Memc[title], SZ_LINE)
+
+ } else {
+
+ # Set the image information to undefined. All this will
+ # be determined in wcslab.
+ Memc[title] = EOS
+ im = NULL
+ mw = NULL
+ c1 = 0.0
+ c2 = 1.0
+ l1 = 0.0
+ l2 = 1.0
+ }
+
+ # Set the graphics mode depending on whether we are appending to a plot
+ # or starting a new plot.
+ do_fill = clgetb ("fill")
+ if (clgetb ("append"))
+ mode = APPEND
+ else
+ mode = NEW_FILE
+
+ # Open graphics.
+ call clgstr ("device", Memc[device], SZ_FNAME)
+
+ # If we are appending, get the previous viewing parameters.
+ if (mode == APPEND) {
+
+ gp = gopen (Memc[device], APPEND, STDGRAPH)
+ call ggview (gp, vl, vr, vb, vt)
+ do_fill = true
+
+ # If drawing on the image display device try to match viewports.
+ } else if (strncmp (Memc[device], "imd", 3) == 0) {
+
+ frame = clgeti ("frame")
+ vl = clgetr ("vl")
+ vr = clgetr ("vr")
+ vb = clgetr ("vb")
+ vt = clgetr ("vt")
+ call wl_imd_viewport (frame, im, c1, c2, l1, l2, vl, vr, vb, vt)
+ gp = gopen (Memc[device], NEW_FILE, STDGRAPH)
+
+ # Otherwise set up a standard viewport.
+ } else {
+ vl = clgetr ("vl")
+ vr = clgetr ("vr")
+ vb = clgetr ("vb")
+ vt = clgetr ("vt")
+ gp = gopen (Memc[device], NEW_FILE, STDGRAPH)
+ }
+
+ # Set the viewport.
+ call gseti (gp, G_WCS, 1)
+ call wl_map_viewport (gp, c1, c2, l1, l2, vl, vr, vb, vt, do_fill)
+
+ # All reading from CL parameters is now done. Everything necessary to
+ # do the plotting is in the WCSLAB descriptor. Do it.
+ call wcslab (mw, c1, c2, l1, l2, gp, Memc[title])
+
+ # Release the memory.
+ call gclose (gp)
+ if (mw != NULL)
+ call mw_close (mw)
+ if (im != NULL)
+ call imunmap (im)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/stxtools/wcslab/wcs_desc.h b/pkg/utilities/nttools/stxtools/wcslab/wcs_desc.h
new file mode 100644
index 00000000..4f6b2a30
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/wcslab/wcs_desc.h
@@ -0,0 +1,219 @@
+# WCS_DESC - The definition of the WCSLAB descriptor memory structure.
+#
+# Description
+# This include file defines the memory structures and macros needed to
+# access elements of a WCSLAB descriptor. The descriptor provides all
+# the necessary elements for the routine wcslab to produce a labeled
+# graph.
+#
+# History
+# 9May91 - Created the descriptor. Jonathan D. Eisenhamer, STScI.
+# 15May91 - Modified the descriptor to contain only pointers to arrays.
+# Two routines, wcs_create and wcs_destroy are required to
+# create the arrays that are pointed to in the descriptor.
+# Also seperated the include file from the wcslab.h file. jde
+# 12Jun91 - Rewrote some of the labelling parameters. jde
+# 20Jun91 - Redesigned much of the parameters. jde
+#---------------------------------------------------------------------------
+
+# Value of opposite axis that polar labels should appear along.
+define WL_POLAR_LABEL_POSITION Memd[P2D($1)]
+
+# The rotation between the Logical and World coordinate systems.
+define WL_ROTA Memd[P2D($1+2)]
+
+# Size of the axis titles.
+define WL_AXIS_TITLE_SIZE Memr[P2R($1+4)]
+
+# The offset required to properly calculate positions in the image display.
+define WL_IMAGE_X_OFF Memr[P2R($1+5)]
+define WL_IMAGE_Y_OFF Memr[P2R($1+6)]
+
+# Size of the grid labels.
+define WL_LABEL_SIZE Memr[P2R($1+7)]
+
+# Major tick mark size.
+define WL_MAJ_TICK_SIZE Memr[P2R($1+8)]
+
+# Minor tick mark size.
+define WL_MIN_TICK_SIZE Memr[P2R($1+9)]
+
+# Magnification of the text size for the title.
+define WL_TITLE_SIZE Memr[P2R($1+10)]
+
+# The side in polar/near-polar plots not to put Axis 1 labels.
+define WL_BAD_LABEL_SIDE Memi[$1+11]
+
+# The type of graph that will be produced. The possible value are:
+#
+# UNKNOWN -> Graph type will be determined
+# NORMAL -> Approximate a cartesian grid
+# POLAR -> Graph center on a pole
+# NEAR_POLAR -> Graph very close to a pole
+
+define WL_GRAPH_TYPE Memi[$1+12]
+
+# Number of segments each line should be broken into to plot it.
+define WL_LINE_SEGMENTS Memi[$1+13]
+
+# The grid line type for major grids. The possible values are to standard
+# IRAF GIO polyline types.
+define WL_MAJ_LINE_TYPE Memi[$1+14]
+
+# The grid line type for minor grids. The possible values are to standard
+# IRAF GIO polyline types.
+define WL_MIN_LINE_TYPE Memi[$1+15]
+
+# The number of label points.
+define WL_N_LABELS Memi[$1+16]
+
+# The graphic WCS that is set to NDC units.
+define WL_NDC_WCS Memi[$1+17]
+
+# The graphic WCS used to plot the grid lines.
+define WL_PLOT_WCS Memi[$1+18]
+
+# The direction of the latitude labelling on polar graphs. Possible values are:
+#
+# BOTTOM -> Towards the bottom of the graph.
+# TOP -> Towards the top of the graph.
+# RIGHT -> Towards the right of the graph.
+# LEFT -> Towards the left of the graph.
+
+define WL_POLAR_LABEL_DIRECTION Memi[$1+19]
+
+# The possible axis types. The possible values are:
+#
+# RA_DEC_TAN - The tangential display in right ascension and declination.
+# LINEAR - General linear systems.
+
+define WL_SYSTEM_TYPE Memi[$1+20]
+
+# Define which side of the graph will have the title.
+define WL_TITLE_SIDE Memi[$1+21]
+
+# True if the axis mapping has reversed the order of the axis relative
+# to the logical system.
+define WL_AXIS_FLIP Memi[$1+22]
+
+# TRUE if the labels should always be printed in full form.
+define WL_ALWAYS_FULL_LABEL Memi[$1+23]
+
+# TRUE if the grid labels should rotate with the grid lines.
+define WL_LABEL_ROTATE Memi[$1+26]
+
+# True if coordinate labels are to be written.
+define WL_LABON Memi[$1+27]
+
+# True if we are to write labels outside the window borders. Else, write
+# them inside.
+define WL_LABOUT Memi[$1+28]
+
+# True if we are to draw the major grid lines.
+define WL_MAJ_GRIDON Memi[$1+29]
+
+# True if we are to draw the minor grid lines.
+define WL_MIN_GRIDON Memi[$1+30]
+
+# True if the graph parameters should be written back out to the
+# parameter file.
+define WL_REMEMBER Memi[$1+31]
+
+# TRUE if tick marks should point into the graph.
+define WL_TICK_IN Memi[$1+32]
+
+# Titles to label each axis.
+define WL_AXIS_TITLE_PTR Memi[$1+33]
+define WL_AXIS_TITLE Memc[WL_AXIS_TITLE_PTR($1)+(($2-1)*SZ_LINE)]
+
+# The sides the axis titles will appear.
+define WL_AXIS_TITLE_SIDE_PTR Memi[$1+34]
+define WL_AXIS_TITLE_SIDE Memi[WL_AXIS_TITLE_SIDE_PTR($1)+$2-1]
+
+# Beginning values to start labeling the axes.
+define WL_BEGIN_PTR Memi[$1+35]
+define WL_BEGIN Memd[WL_BEGIN_PTR($1)+$2-1]
+
+# The name of the graphics device.
+#define WL_DEVICE_PTR Memi[$1+36]
+#define WL_DEVICE Memc[WL_DEVICE_PTR($1)]
+
+# Value to stop labeling the axes.
+define WL_END_PTR Memi[$1+37]
+define WL_END Memd[WL_END_PTR($1)+$2-1]
+
+# The graphics descriptor.
+define WL_GP Memi[$1+38]
+
+# The angle of text at this label point.
+define WL_LABEL_ANGLE_PTR Memi[$1+40]
+define WL_LABEL_ANGLE Memd[WL_LABEL_ANGLE_PTR($1)+$2-1]
+
+# Which axis the label represents.
+define WL_LABEL_AXIS_PTR Memi[$1+41]
+define WL_LABEL_AXIS Memi[WL_LABEL_AXIS_PTR($1)+$2-1]
+
+# The positions of tick mark/grid labels.
+define WL_LABEL_POSITION_PTR Memi[$1+42]
+define WL_LABEL_POSITION Memd[WL_LABEL_POSITION_PTR($1)+$2-1+(($3-1)*MAX_LABEL_POINTS)]
+#
+# NOTE: If the axis are transposed, the positions represented here are
+# the corrected, transposed values.
+
+# The sides the labels for each axis should appear on.
+define WL_LABEL_SIDE_PTR Memi[$1+43]
+define WL_LABEL_SIDE Memb[WL_LABEL_SIDE_PTR($1)+$2-1+(($3-1)*N_SIDES)]
+
+# The value of the label.
+define WL_LABEL_VALUE_PTR Memi[$1+44]
+define WL_LABEL_VALUE Memd[WL_LABEL_VALUE_PTR($1)+$2-1]
+
+# The center of the transformations in the logical system.
+define WL_LOGICAL_CENTER_PTR Memi[$1+45]
+define WL_LOGICAL_CENTER Memd[WL_LOGICAL_CENTER_PTR($1)+$2-1]
+
+# The coordinate transformation from Logical to World.
+define WL_LWCT Memi[$1+46]
+
+# Major grid intervals for the axis.
+define WL_MAJ_I_PTR Memi[$1+47]
+define WL_MAJOR_INTERVAL Memd[WL_MAJ_I_PTR($1)+$2-1]
+
+# The minor intervals for the axis.
+define WL_MIN_I_PTR Memi[$1+48]
+define WL_MINOR_INTERVAL Memi[WL_MIN_I_PTR($1)+$2-1]
+
+# Remember the extent of the labels around the plot box.
+define WL_NV_PTR Memi[$1+49]
+define WL_NEW_VIEW Memr[WL_NV_PTR($1)+$2-1]
+
+# The MWL structure.
+define WL_MW Memi[$1+50]
+
+# The values of the sides of the screen. The indexes are defined as follows:
+#
+# TOP -> Y-axis value at the top of display.
+# BOTTOM -> Y-axis value at bottom of display
+# RIGHT -> X-axis value at right of display.
+# LEFT -> X-axis value at left of display.
+#
+define WL_SCREEN_BOUNDARY_PTR Memi[$1+51]
+define WL_SCREEN_BOUNDARY Memd[WL_SCREEN_BOUNDARY_PTR($1)+$2-1]
+
+# The title that will be placed on the plot.
+define WL_TITLE_PTR Memi[$1+52]
+define WL_TITLE Memc[WL_TITLE_PTR($1)]
+
+# The coordinate transformation from World to Logical.
+define WL_WLCT Memi[$1+53]
+
+# The center of the transformations in the world system.
+define WL_WORLD_CENTER_PTR Memi[$1+54]
+define WL_WORLD_CENTER Memd[WL_WORLD_CENTER_PTR($1)+$2-1]
+
+# The length of this structure.
+define WL_LEN 55+1
+
+#---------------------------------------------------------------------------
+# End of wcs_desc
+#---------------------------------------------------------------------------
diff --git a/pkg/utilities/nttools/stxtools/wcslab/wcslab.h b/pkg/utilities/nttools/stxtools/wcslab/wcslab.h
new file mode 100644
index 00000000..cf088323
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/wcslab/wcslab.h
@@ -0,0 +1,98 @@
+# Definitions file for WCSLAB
+
+# Define various important dimensions
+
+define MAX_DIM 10 # Maximum number of dimensions
+define N_DIM 2 # Dimensionality of plotting space
+define N_SIDES 4 # Number of sides to a window
+define MAX_LABEL_POINTS 100 # The maximum number of possible label points
+define N_EDGES 20 # Number of edges being examined from the window
+
+# Define the types of graphs possible.
+
+define GRAPHTYPES "|normal|polar|near_polar|"
+define NORMAL 1
+define POLAR 2
+define NEAR_POLAR 3
+
+# Define the graph sides. The ordering matches the calls to the GIO package.
+
+define GRAPHSIDES "|left|right|bottom|top|"
+define LEFT 1
+define RIGHT 2
+define BOTTOM 3
+define TOP 4
+
+# Define which index refers to the X-axis and which refers to the Y-axis.
+
+define X_DIM 1
+define Y_DIM 2
+define AXIS1 1
+define AXIS2 2
+
+# Define which axis is longitude and which axis is latitude.
+
+define LONGITUDE 1
+define LATITUDE 2
+
+# Define the available precisions for labelling
+
+define HOUR 1
+define DEGREE 1
+define MINUTE 2
+define SECOND 3
+define SUBSEC_LOW 4
+define SUBSEC_HIGH 5
+
+# Define the possible MWCS transformation types.
+
+define RA_DEC_DICTIONARY "|tan|arc|sin|"
+define LINEAR_DICTIONARY "|linear|"
+
+define NUMBER_OF_SUPPORTED_TYPES 2
+define RA_DEC 1
+define LINEAR 2
+
+define AXIS 3B # transform all axes in any MWCS call
+
+# Some useful graphics definitions and defaults
+
+define NDC_WCS 0 # the base graphics WCS
+define POLE_MARK_SHAPE 4 # the pole mark is a cross
+define POLE_MARK_SIZE 3.0 # the half-size of the cross
+define DISTANCE_TO_POLE 0.1 # % distance to pole for lines of longitude
+define LINE_SIZE 1. # line width for lines and ticks
+define MIN_ANGLE 10. # minimum angle for text rotation
+define BOTTOM_LEFT .1 # default bottom left corner of viewport
+define TOP_RIGHT .9 # default top right corner of viewport
+
+# Units conversion macros
+
+define RADTOST (240*RADTODEG($1)) # Radians to seconds of time
+define RADTOSA (3600*RADTODEG($1)) # Radians to seconds of arc
+define STTORAD (DEGTORAD(($1)/240)) # Seconds of time to radians
+define SATORAD (DEGTORAD(($1)/3600)) # Seconds of arc to radians
+define RADTOHRS (RADTODEG(($1)/15)) # Radians to hours
+define HRSTORAD (DEGTORAD(15*($1))) # Hours to radians
+define DEGTOST (240*($1)) # Degrees to seconds of time.
+define STTODEG (($1)/240) # Seconds of time to degrees.
+define DEGTOSA (3600*($1)) # Degrees to seconds of arc.
+define SATODEG (($1)/3600) # Seconds of arc to degrees.
+define HRSTODEG (($1)*15) # Hours to degrees.
+define DEGTOHRS (($1)/15) # Degrees to hours.
+define STPERDAY 86400 # Seconds per day
+
+# Other useful macros
+
+define INVERT ($1 < 45 || $1 > 315 || ( $1 > 135 && $1 < 225 ))
+
+# Define the latitudes of the north and south poles
+
+define NORTH_POLE_LATITUDE 90.0D0
+define SOUTH_POLE_LATITUDE -90.0D0
+
+# Define sections of a circle
+
+define QUARTER_CIRCLE 90.0D0
+define HALF_CIRCLE 180.0D0
+define FULL_CIRCLE 360.0D0
diff --git a/pkg/utilities/nttools/stxtools/wcslab/wcslab.x b/pkg/utilities/nttools/stxtools/wcslab/wcslab.x
new file mode 100644
index 00000000..2e6974c6
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/wcslab/wcslab.x
@@ -0,0 +1,935 @@
+include <gset.h>
+include <imhdr.h>
+include <math.h>
+include <mwset.h>
+include "wcslab.h"
+include "wcs_desc.h"
+include <ctype.h>
+
+
+# WCSLAB -- Procedure to draw labels and grids in sky projection coordinates.
+#
+# Description
+# Wcslab produces a labelling and grid based on the MWCS of a
+# specified image.
+#
+# The only things necessary to run this routine are:
+# 1) Open an image and pass the image descriptor in im.
+# 2) Open the graphics device and set the desired viewport (with a
+# gsview call).
+# 3) Make sure that the wlpars pset is available.
+#
+# Upon return, the graphics system will be in the state that it had been
+# left in and a "virtual viewport" will be returned in the arguments
+# left, right, bottom, top. This viewport defines the region where labels
+# and/or titles were written. If any graphics is performed within this
+# region, chances are that something will be overwritten. If any other
+# graphics remain outside this region, then what was produced by this
+# subroutine will remain untouched.
+#
+# Bugs
+# Can only handle sky projections for Right Ascension/Declination. This
+# should be able to deal with any of the projections for this system, but
+# has only been tested with the Tangent projection.
+
+procedure wcslab (mw, log_x1, log_x2, log_y1, log_y2, gp, title)
+
+pointer mw # I: the wcs descriptor
+real log_x1, log_x2 # I/O: the viewport
+real log_y1, log_y2 # I/O: the viewport
+pointer gp # I: the graphics descriptor
+char title[ARB] # I: the image title
+
+pointer wd
+real junkx1, junkx2, junky1, junky2
+bool clgetb()
+pointer wl_create()
+errchk clgstr
+
+begin
+ # Allocate the descriptor.
+ wd = wl_create()
+
+ # Set the title name.
+ call strcpy (title, WL_TITLE(wd), SZ_LINE)
+
+ # Set the WCS descriptor. If the descriptor is NULL or if
+ # the use_wcs parameter is yes, retrieve the parameter
+ # specified wcs.
+ if (mw == NULL)
+ call wl_wcs_params (mw, log_x1, log_x2, log_y1, log_y2)
+ else if (clgetb ("usewcs"))
+ call wl_wcs_params (mw, junkx1, junkx2, junky1, junky2)
+ WL_MW(wd) = mw
+
+ # Determine axis types.
+ call wl_get_system_type (WL_MW(wd), WL_SYSTEM_TYPE(wd),
+ WL_LOGICAL_CENTER(wd,1), WL_WORLD_CENTER(wd,1), WL_AXIS_FLIP(wd))
+ if (IS_INDEFI(WL_SYSTEM_TYPE(wd)))
+ call error (0, "WCSLAB: Image WCS is unsupported\n")
+
+ # Get the parameters.
+ call wl_gr_inparams (wd)
+
+ # Copy the graphics descriptor.
+ WL_GP(wd) = gp
+
+ # Set the plot window in pixels (the logical space of the WCS).
+ WL_SCREEN_BOUNDARY(wd,LEFT) = log_x1
+ WL_SCREEN_BOUNDARY(wd,RIGHT) = log_x2
+ WL_SCREEN_BOUNDARY(wd,BOTTOM) = log_y1
+ WL_SCREEN_BOUNDARY(wd,TOP) = log_y2
+
+ # Plot and label the coordinate grid.
+ call wl_wcslab (wd)
+
+ # Return the possibly modified graphics descriptor and viewport.
+ gp = WL_GP(wd)
+ call gsview (gp, WL_NEW_VIEW(wd,LEFT), WL_NEW_VIEW(wd,RIGHT),
+ WL_NEW_VIEW(wd,BOTTOM), WL_NEW_VIEW(wd,TOP))
+
+ # Save the current parameters.
+ if (WL_REMEMBER(wd) == YES)
+ call wl_gr_remparams (wd)
+
+ # Release the memory.
+ call wl_destroy (wd)
+end
+
+
+# WL_CREATE -- Create a WCSLAB descriptor and initialize it.
+#
+# Description
+# This routine allocates the memory for the WCSLAB descriptor and
+# subarrays and initializes values.
+#
+# Returns
+# the pointer to the WCSLAB descriptor.
+
+pointer procedure wl_create()
+
+int i,j
+pointer wd
+
+begin
+ # Allocate the descriptor memory.
+ call malloc (wd, WL_LEN, TY_STRUCT)
+
+ # Allocate the subarrays.
+ call malloc (WL_AXIS_TITLE_PTR(wd), SZ_LINE * N_DIM, TY_CHAR)
+ call malloc (WL_AXIS_TITLE_SIDE_PTR(wd), N_SIDES * N_DIM, TY_BOOL)
+ call malloc (WL_BEGIN_PTR(wd), N_DIM, TY_DOUBLE)
+ call malloc (WL_END_PTR(wd), N_DIM, TY_DOUBLE)
+ call malloc (WL_LABEL_ANGLE_PTR(wd), MAX_LABEL_POINTS, TY_DOUBLE)
+ call malloc (WL_LABEL_AXIS_PTR(wd), MAX_LABEL_POINTS, TY_INT)
+ call malloc (WL_LABEL_POSITION_PTR(wd), N_DIM * MAX_LABEL_POINTS,
+ TY_DOUBLE)
+ call malloc (WL_LABEL_SIDE_PTR(wd), N_DIM * N_SIDES, TY_BOOL)
+ call malloc (WL_LABEL_VALUE_PTR(wd), MAX_LABEL_POINTS, TY_DOUBLE)
+ call malloc (WL_LOGICAL_CENTER_PTR(wd), N_DIM, TY_DOUBLE)
+ call malloc (WL_MAJ_I_PTR(wd), N_DIM, TY_DOUBLE)
+ call malloc (WL_MIN_I_PTR(wd), N_DIM, TY_INT)
+ call malloc (WL_NV_PTR(wd), N_SIDES, TY_REAL)
+ call malloc (WL_SCREEN_BOUNDARY_PTR(wd), N_SIDES, TY_DOUBLE)
+ call malloc (WL_TITLE_PTR(wd), SZ_LINE, TY_CHAR)
+ call malloc (WL_WORLD_CENTER_PTR(wd), N_DIM, TY_DOUBLE)
+
+ # Initialize the simple values (should be the same as the parameter
+ # file).
+ WL_POLAR_LABEL_POSITION(wd) = INDEF
+ WL_AXIS_TITLE_SIZE(wd) = 1.5
+ WL_LABEL_SIZE(wd) = 1.0
+ WL_MAJ_TICK_SIZE(wd) = .03
+ WL_MIN_TICK_SIZE(wd) = .01
+ WL_TITLE_SIZE(wd) = 2.0
+ WL_GRAPH_TYPE(wd) = INDEFI
+ WL_MAJ_LINE_TYPE(wd) = GL_SOLID
+ WL_MIN_LINE_TYPE(wd) = GL_DOTTED
+ WL_TITLE_SIDE(wd) = TOP
+ WL_ALWAYS_FULL_LABEL(wd) = NO
+ WL_LABEL_ROTATE(wd) = YES
+ WL_LABON(wd) = YES
+ WL_LABOUT(wd) = YES
+ WL_MAJ_GRIDON(wd) = YES
+ WL_MIN_GRIDON(wd) = NO
+ WL_REMEMBER(wd) = NO
+ WL_TICK_IN(wd) = YES
+
+ # Initialize any strings.
+ call strcpy ("imtitle", WL_TITLE(wd), SZ_LINE)
+
+ # Initialize the axis dependent values.
+ do i = 1, N_DIM {
+ WL_AXIS_TITLE(wd,i) = EOS
+ WL_AXIS_TITLE_SIDE(wd,i) = INDEFI
+ WL_BEGIN(wd,i) = INDEFD
+ WL_END(wd,i) = INDEFD
+ WL_MAJOR_INTERVAL(wd,i) = INDEFD
+ WL_MINOR_INTERVAL(wd,i) = 5
+ do j = 1, N_SIDES
+ WL_LABEL_SIDE(wd,j,i) = false
+ }
+
+ # Return the descriptor.
+ return (wd)
+end
+
+
+# WL_WCS_PARAMS -- Read the WCS descriptor from the parameters.
+#
+# Description
+# This procedure returns the WCS descriptor created from task parameters
+# and the logical space that will be graphed.
+#
+# Bugs
+# This only deals with two axes.
+
+procedure wl_wcs_params (mw, log_x1, log_x2, log_y1, log_y2)
+
+pointer mw # O: The MWCS descriptor.
+real log_x1, log_x2, # O: The extent of the logical space to graph.
+real log_y1, log_y2
+
+real cd[2,2], r[2], w[2]
+pointer sp, input, pp
+pointer clopset(), mw_open()
+real clgpsetr()
+
+begin
+ call smark (sp)
+ call salloc (input, SZ_LINE, TY_CHAR)
+
+ # Open the pset.
+ pp = clopset ("wcspars")
+
+ # Create an MWCS descriptor.
+ mw = mw_open (NULL, 2)
+
+ # Get the types.
+ call clgpset (pp, "ctype1", Memc[input], SZ_LINE)
+ call wl_decode_ctype (mw, Memc[input], 1)
+ call clgpset (pp, "ctype2", Memc[input], SZ_LINE)
+ call wl_decode_ctype (mw, Memc[input], 2)
+
+ # Get the reference coordinates.
+ r[1] = clgpsetr (pp, "crpix1")
+ r[2] = clgpsetr (pp, "crpix2")
+ w[1] = clgpsetr (pp, "crval1")
+ w[2] = clgpsetr (pp, "crval2")
+
+ # Get the CD matrix.
+ cd[1,1] = clgpsetr (pp, "cd1_1")
+ cd[1,2] = clgpsetr (pp, "cd1_2")
+ cd[2,1] = clgpsetr (pp, "cd2_1")
+ cd[2,2] = clgpsetr (pp, "cd2_2")
+
+ # Set the Wterm.
+ call mw_swtermr (mw, r, w, cd, 2)
+
+ # Get the extent of the logical space.
+ log_x1 = clgpsetr (pp, "log_x1")
+ log_x2 = clgpsetr (pp, "log_x2")
+ log_y1 = clgpsetr (pp, "log_y1")
+ log_y2 = clgpsetr (pp, "log_y2")
+
+ # Close the pset.
+ call clcpset (pp)
+
+ call sfree (sp)
+end
+
+
+# WL_DECODE_CTYPE -- Decode the ctype string into axis type and system type.
+#
+# Description
+# The CTYPE is what is found in FITS keywords CTYPEn. The value may
+# contain two pieces of information, always the system type and possibly
+# an individual axis type. For systems such as plain old linear systems
+# just a system type is defined. However, for celestial systems, both
+# types are defined in the form "axistype-systemtype". There may be
+# any number of '-' in between the values.
+
+procedure wl_decode_ctype (mw, input, axno)
+
+pointer mw # I: the MWCS descriptor
+char input[ARB] # I: the string input
+int axno # I: the axis being worked on
+
+int i, input_len
+int strncmp(), strldx(), strlen()
+string empty ""
+
+begin
+
+ input_len = strlen (input)
+
+ # Fix some characters.
+ do i = 1, input_len {
+ if (input[i] == ' ' || input[i] == '\'')
+ break
+ else if (IS_UPPER(input[i]))
+ input[i] = TO_LOWER(input[i])
+ else if (input[i] == '_')
+ input[i] = '-'
+ }
+
+ # Determine the type of function on this axis.
+ if (strncmp (input, "linear", 6) == 0) {
+ call mw_swtype (mw, 1, 2, "linear", empty)
+
+ } else if (strncmp (input, "ra--", 4) == 0) {
+ i = strldx ("-", input) + 1
+ call mw_swtype (mw, 1, 2, input[i], empty)
+ call mw_swattrs (mw, axno, "axtype", "ra")
+
+ } else if (strncmp (input, "dec-", 4) == 0) {
+ i = strldx ("-", input) + 1
+ call mw_swtype (mw, 1, 2, input[i], empty)
+ call mw_swattrs (mw, axno, "axtype", "dec")
+
+ } else {
+ # Since we have to be able to read any FITS header, we have
+ # no control over the value of CTYPEi. If the value is
+ # something we don't know about, assume a LINEAR axis, using
+ # the given value of CTYPEi as the default axis label.
+ call mw_swtype (mw, 1, 2, "linear", empty)
+ call mw_swattrs (mw, axno, "label", input)
+ }
+
+end
+
+
+# WL_GET_SYSTEM_TYPE -- Determine type of transformation the MWCS represents.
+#
+# Note
+# For some systems, the axis mapping reverses the order to make
+# the rest of the code tractable. The only problem is that when graphing,
+# the graph routines need to "fix" this reversal. Also note that this
+# occurs only for systems that have distinct axis types, such as RA and
+# DEC.
+#
+# Bugs
+# A potential problem: For a WCS that has more axes than necessary
+# for the sky projections, those axis are set such that during
+# transformations, the first index position is used. For the one
+# example I have seen, the "third" axis is time and this interpretation
+# works. But, I am sure something will fall apart because of this.
+
+procedure wl_get_system_type (mw, system_type, logical_center, world_center,
+ flip)
+
+pointer mw # I: the MWCS descriptor.
+int system_type # O: the transformation type:
+ # RA_DEC -> tan, sin, or arc projection
+ # in right ascension and
+ # declination
+ # LINEAR -> any regular linear system
+ # INDEFI -> could not be determined
+double logical_center[N_DIM] # O: the center point in the logical system.
+double world_center[N_DIM] # O: the center point in the world system.
+int flip # O: true if the order of the axes have been
+ # changed by axis mappins
+
+double tmp_logical[MAX_DIM], tmp_world[MAX_DIM]
+int wcs_dim, axis, index_sys1, index_sys2, found_axis
+int axno[MAX_DIM], axval[MAX_DIM], found_axis_list[N_DIM]
+pointer sp, axtype, cd, cur_type
+int mw_stati(), strncmp(), strdic()
+errchk mw_gwattrs
+
+begin
+ # Get some memory.
+ call smark (sp)
+ call salloc (axtype, SZ_LINE, TY_CHAR)
+ call salloc (cur_type, SZ_LINE, TY_CHAR)
+ call salloc (cd, MAX_DIM, TY_DOUBLE)
+
+ # Get the dimensionality of the WCS.
+ call mw_seti (mw, MW_USEAXMAP, NO)
+ wcs_dim = mw_stati (mw, MW_NDIM)
+
+ # Initialize the two dimensions.
+ index_sys1 = INDEFI
+ index_sys2 = INDEFI
+
+ # Look through the possible supported axis types. When a type has
+ # exactly N_DIM axes defined, that will be the one used.
+
+ for (system_type = 1; system_type <= NUMBER_OF_SUPPORTED_TYPES;
+ system_type = system_type + 1) {
+
+ # Determine the string that should be looked for.
+ switch (system_type) {
+ case RA_DEC:
+ call strcpy (RA_DEC_DICTIONARY, Memc[cur_type], SZ_LINE)
+ case LINEAR:
+ call strcpy (LINEAR_DICTIONARY, Memc[cur_type], SZ_LINE)
+ }
+
+ # Initialize the number of found axis.
+ found_axis = 0
+
+ # Examine each axis to determine whether the current axis type is
+ # the one to use.
+ for (axis = 1; axis <= wcs_dim; axis = axis + 1) {
+
+ # If the current physical axis is not mapped, ignore it.
+ # This statement is causing a problem in 2.10.3, not sure
+ # why but am removing it for now.
+ #if (axno[axis] == 0)
+ #next
+
+ ifnoerr (call mw_gwattrs( mw, axis, "wtype", Memc[axtype],
+ SZ_LINE)) {
+ call strlwr (Memc[axtype])
+
+ # If this axis type matches the one being looked for, add
+ # it to the axis list. If there are too many axis of the
+ # current type found, don't add to the found axis list.
+
+ if (strdic (Memc[axtype], Memc[axtype], SZ_LINE,
+ Memc[cur_type]) > 0) {
+ found_axis = found_axis + 1
+ if (found_axis <= N_DIM)
+ found_axis_list[found_axis] = axis
+ }
+ }
+ }
+
+ # Check to see whether we have the right number axes.
+ if (found_axis == N_DIM)
+ break
+
+ }
+
+ # If any axes were found, then further check axis types.
+ # Depending on the axis type, there may be need to distinguish
+ # between the two possible axis further.
+
+ if (found_axis == N_DIM)
+ switch (system_type) {
+ case RA_DEC:
+ for (axis = 1; axis <= N_DIM; axis = axis + 1)
+ ifnoerr (call mw_gwattrs (mw, found_axis_list[axis],
+ "axtype", Memc[axtype], SZ_LINE)) {
+ call strlwr( Memc[axtype] )
+ if (strncmp (Memc[axtype], "ra", 2) == 0)
+ index_sys1 = found_axis_list[axis]
+ else if (strncmp (Memc[axtype], "dec", 3) == 0)
+ index_sys2 = found_axis_list[axis]
+ }
+
+ # The "default" seems to be the LINEAR case for MWCS.
+ # Since no other information is provided, this is all we know.
+ default:
+ index_sys1 = found_axis_list[1]
+ index_sys2 = found_axis_list[2]
+ }
+
+ # If either axis is unknown, something is wrong. If the WCS has two
+ # axes defined, then make some grand assumptions. If not, then there
+ # is nothing more to be done.
+
+ if (IS_INDEFI (index_sys1) || IS_INDEFI (index_sys2)) {
+ if (wcs_dim >= N_DIM) {
+ index_sys1 = 1
+ index_sys2 = 2
+ } else
+ call error (0, "Wcslab: Fewer than two defined axes")
+ }
+
+ # Zero the axis values and set any "unknown" axis to always use the
+ # "first" position in that axis direction. This will more than likely
+ # be a problem, but no general solution comes to mind this second.
+
+ call amovki (0, axno, wcs_dim)
+ call amovki (0, axval, wcs_dim)
+
+ # Setup so that the desired axes are set as the X and Y axis.
+ axno[index_sys1] = X_DIM
+ axno[index_sys2] = Y_DIM
+ call mw_saxmap (mw, axno, axval, wcs_dim)
+
+ # Recover the center points of the Logical and World systems.
+ call mw_gwtermd (mw, tmp_logical, tmp_world, Memd[cd], wcs_dim)
+
+ logical_center[X_DIM] = tmp_logical[index_sys1]
+ logical_center[Y_DIM] = tmp_logical[index_sys2]
+ world_center[X_DIM] = tmp_world[index_sys1]
+ world_center[Y_DIM] = tmp_world[index_sys2]
+
+ # Check for reversal of axes
+ if (index_sys1 > index_sys2)
+ flip = YES
+ else
+ flip = NO
+
+ # Release the memory.
+ call sfree (sp)
+end
+
+
+# WL_GR_INPARAMS -- Read in the graphics parameters for wcslab.
+#
+# Description
+# Read all the parameters in and make some decisions about what
+# will be done.
+
+procedure wl_gr_inparams (wd)
+
+pointer wd # I: the WCSLAB descriptor
+
+pointer sp, aline, pp
+bool clgpsetb(), streq()
+double wl_string_to_internal()
+int btoi(), strdic(), wl_line_type(), clgpseti()
+pointer clopset()
+real clgpsetr()
+
+begin
+ # Get some memory.
+ call smark (sp)
+ call salloc (aline, SZ_LINE, TY_CHAR)
+
+ # Open the pset.
+ pp = clopset ("wlpars")
+
+ # Get the title if other than the default.
+ call clgpset (pp, "title", Memc[aline], SZ_LINE)
+ if (! streq (Memc[aline], "imtitle"))
+ call strcpy (Memc[aline], WL_TITLE(wd), SZ_LINE)
+
+ # Get the axis titles.
+ call clgpset (pp, "axis1_title", WL_AXIS_TITLE(wd,AXIS1), SZ_LINE)
+ call clgpset (pp, "axis2_title", WL_AXIS_TITLE(wd,AXIS2), SZ_LINE)
+
+ # Get the parameters.
+ WL_ALWAYS_FULL_LABEL(wd) = btoi (clgpsetb (pp,"full_label"))
+ WL_AXIS_TITLE_SIZE(wd) = clgpsetr (pp, "axis_title_size")
+ WL_LABEL_ROTATE(wd) = btoi (clgpsetb (pp, "rotate"))
+ WL_LABEL_SIZE(wd) = clgpsetr (pp, "label_size")
+ WL_LABON(wd) = btoi (clgpsetb (pp, "dolabel"))
+ WL_LABOUT(wd) = btoi (clgpsetb (pp, "labout"))
+ WL_MAJ_GRIDON(wd) = btoi (clgpsetb (pp, "major_grid"))
+ WL_MAJ_TICK_SIZE(wd) = clgpsetr (pp, "major_tick")
+ WL_MIN_GRIDON(wd) = btoi (clgpsetb (pp, "minor_grid"))
+ WL_MINOR_INTERVAL(wd,AXIS1) = clgpseti (pp, "axis1_minor")
+ WL_MINOR_INTERVAL(wd,AXIS2) = clgpseti (pp, "axis2_minor")
+ WL_MIN_TICK_SIZE(wd) = clgpsetr (pp, "minor_tick")
+ WL_REMEMBER(wd) = btoi (clgpsetb (pp, "remember"))
+ WL_TICK_IN(wd) = btoi (clgpsetb (pp, "tick_in"))
+ WL_TITLE_SIZE(wd) = clgpsetr (pp, "title_size")
+
+ # Set what type of graph will be plotted.
+ call clgpset (pp, "graph_type", Memc[aline], SZ_LINE)
+ call strlwr (Memc[aline])
+ WL_GRAPH_TYPE(wd) = strdic (Memc[aline], Memc[aline], SZ_LINE,
+ GRAPHTYPES)
+ if (WL_GRAPH_TYPE(wd) <= 0)
+ WL_GRAPH_TYPE(wd) = INDEFI
+
+ # Get which sides labels will appear on.
+ call clgpset (pp, "axis1_side", Memc[aline], SZ_LINE)
+ call strlwr (Memc[aline])
+ call wl_label_side (Memc[aline], WL_LABEL_SIDE(wd,1,AXIS1))
+
+ call clgpset (pp, "axis2_side", Memc[aline], SZ_LINE)
+ call strlwr (Memc[aline])
+ call wl_label_side (Memc[aline], WL_LABEL_SIDE(wd,1,AXIS2))
+
+ # Get the polar justification direction.
+ call clgpset (pp, "justify", Memc[aline], SZ_LINE)
+ call strlwr (Memc[aline])
+ WL_POLAR_LABEL_DIRECTION(wd) = strdic (Memc[aline], Memc[aline],
+ SZ_LINE, GRAPHSIDES)
+ if (WL_POLAR_LABEL_DIRECTION(wd) <= 0)
+ WL_POLAR_LABEL_DIRECTION(wd) = INDEFI
+
+ # Decode the graphing parameters.
+ call clgpset (pp, "axis1_int", Memc[aline], SZ_LINE)
+ WL_MAJOR_INTERVAL(wd,AXIS1) = wl_string_to_internal (Memc[aline],
+ WL_SYSTEM_TYPE(wd), AXIS1)
+ call clgpset (pp, "axis1_beg", Memc[aline], SZ_LINE)
+ WL_BEGIN(wd,AXIS1) = wl_string_to_internal (Memc[aline],
+ WL_SYSTEM_TYPE(wd), AXIS1)
+ call clgpset (pp, "axis1_end", Memc[aline], SZ_LINE)
+ WL_END(wd,AXIS1) = wl_string_to_internal (Memc[aline],
+ WL_SYSTEM_TYPE(wd), AXIS1)
+
+ call clgpset (pp, "axis2_int", Memc[aline], SZ_LINE)
+ WL_MAJOR_INTERVAL(wd,AXIS2) = wl_string_to_internal (Memc[aline],
+ WL_SYSTEM_TYPE(wd), AXIS2)
+ call clgpset (pp, "axis2_beg", Memc[aline], SZ_LINE)
+ WL_BEGIN(wd,AXIS2) = wl_string_to_internal(Memc[aline],
+ WL_SYSTEM_TYPE(wd), AXIS2 )
+ call clgpset (pp, "axis2_end", Memc[aline], SZ_LINE)
+ WL_END(wd,AXIS2) = wl_string_to_internal (Memc[aline],
+ WL_SYSTEM_TYPE(wd), AXIS2)
+
+ # Get the polar label position.
+ call clgpset (pp, "axis2_dir", Memc[aline], SZ_LINE)
+ WL_POLAR_LABEL_POSITION(wd) = wl_string_to_internal( Memc[aline],
+ WL_SYSTEM_TYPE(wd), AXIS1)
+
+ # Get the axis titles.
+ call clgpset (pp, "axis1_title_side", Memc[aline], SZ_LINE)
+ call strlwr (Memc[aline])
+ WL_AXIS_TITLE_SIDE(wd,AXIS1) = strdic (Memc[aline], Memc[aline],
+ SZ_LINE, GRAPHSIDES)
+ if (WL_AXIS_TITLE_SIDE(wd,AXIS1) <= 0)
+ WL_AXIS_TITLE_SIDE(wd,AXIS1) = INDEFI
+
+ call clgpset (pp, "axis2_title_side", Memc[aline], SZ_LINE)
+ call strlwr (Memc[aline])
+ WL_AXIS_TITLE_SIDE(wd,AXIS2) = strdic (Memc[aline], Memc[aline],
+ SZ_LINE, GRAPHSIDES)
+ if (WL_AXIS_TITLE_SIDE(wd,AXIS2) <= 0)
+ WL_AXIS_TITLE_SIDE(wd,AXIS2) = INDEFI
+
+ # Decode the grid line types.
+ call clgpset (pp, "major_line", Memc[aline], SZ_LINE)
+ WL_MAJ_LINE_TYPE(wd) = wl_line_type (Memc[aline])
+ call clgpset (pp, "minor_line", Memc[aline], SZ_LINE)
+ WL_MIN_LINE_TYPE(wd) = wl_line_type (Memc[aline])
+
+ # Get the title side.
+ call clgpset (pp, "title_side", Memc[aline], SZ_LINE)
+ call strlwr (Memc[ aline])
+ WL_TITLE_SIDE(wd) = strdic (Memc[aline], Memc[aline], SZ_LINE,
+ GRAPHSIDES)
+
+ # Close the pset.
+ call clcpset (pp)
+
+ # Free memory.
+ call sfree (sp)
+end
+
+
+# WL_GR_REMPARAMS -- Write out the graphing parameters.
+
+procedure wl_gr_remparams (wd)
+
+pointer wd # I: the WCSLAB descriptor.
+
+pointer sp, output, pp
+pointer clopset()
+
+begin
+ # Get some memory.
+ call smark (sp)
+ call salloc (output, SZ_LINE, TY_CHAR)
+
+ # Open the pset.
+ pp = clopset ("wlpars")
+
+ # Set the graph type.
+ switch (WL_GRAPH_TYPE(wd)) {
+ case NORMAL:
+ call clppset (pp, "graph_type", "normal")
+ case POLAR:
+ call clppset (pp, "graph_type", "polar")
+ case NEAR_POLAR:
+ call clppset (pp, "graph_type", "near_polar")
+ default:
+ call clppset (pp, "graph_type", "default")
+ }
+
+ # Write back the labelling parameters.
+ call wl_internal_to_string (WL_MAJOR_INTERVAL(wd,AXIS1),
+ WL_SYSTEM_TYPE(wd), AXIS1, Memc[output])
+ call clppset (pp, "axis1_int", Memc[output])
+ call wl_internal_to_string (WL_BEGIN(wd,AXIS1), WL_SYSTEM_TYPE(wd),
+ AXIS1, Memc[output])
+ call clppset (pp, "axis1_beg", Memc[output])
+ call wl_internal_to_string (WL_END(WD,AXIS1), WL_SYSTEM_TYPE(wd),
+ AXIS1, Memc[output])
+ call clppset (pp, "axis1_end", Memc[output])
+ call wl_internal_to_string (WL_MAJOR_INTERVAL(wd,AXIS2),
+ WL_SYSTEM_TYPE(wd), AXIS2, Memc[output])
+ call clppset (pp, "axis2_int", Memc[output])
+ call wl_internal_to_string (WL_BEGIN(wd,AXIS2), WL_SYSTEM_TYPE(wd),
+ AXIS2, Memc[output])
+ call clppset (pp, "axis2_beg", Memc[output])
+ call wl_internal_to_string (WL_END(wd,AXIS2), WL_SYSTEM_TYPE(wd),
+ AXIS2, Memc[output])
+ call clppset (pp, "axis2_end", Memc[output])
+ call wl_internal_to_string (WL_POLAR_LABEL_POSITION(wd),
+ WL_SYSTEM_TYPE(wd), AXIS1, Memc[output])
+ call clppset (pp, "axis2_dir", Memc[output])
+
+ # Write back labelling justification.
+ call wl_side_to_string (WL_POLAR_LABEL_DIRECTION(wd), Memc[output],
+ SZ_LINE)
+ call clppset (pp, "justify", Memc[output])
+
+ # Put the axis title sides out.
+ call wl_side_to_string (WL_AXIS_TITLE_SIDE(wd,AXIS1), Memc[output],
+ SZ_LINE)
+ call clppset (pp, "axis1_title_side", Memc[output])
+ call wl_side_to_string (WL_AXIS_TITLE_SIDE(wd,AXIS2), Memc[output],
+ SZ_LINE )
+ call clppset (pp, "axis2_title_side", Memc[output])
+
+ # Put the label sides out.
+ call wl_put_label_sides (WL_LABEL_SIDE(wd,1,AXIS1), Memc[output],
+ SZ_LINE )
+ call clppset (pp, "axis1_side", Memc[output])
+ call wl_put_label_sides (WL_LABEL_SIDE(wd,1,AXIS2), Memc[output],
+ SZ_LINE)
+ call clppset (pp, "axis2_side", Memc[output])
+
+ # Close the pset.
+ call clcpset (pp)
+
+ # Free memory.
+ call sfree (sp)
+end
+
+
+# WL_DESTROY -- Deallocate the WCSLAB descriptor.
+
+procedure wl_destroy (wd)
+
+pointer wd # I: the WCSLAB descriptor to be destroyed
+
+begin
+ # Deallocate all the subarrays.
+ call mfree (WL_WORLD_CENTER_PTR(wd), TY_DOUBLE)
+ call mfree (WL_TITLE_PTR(wd), TY_CHAR)
+ call mfree (WL_SCREEN_BOUNDARY_PTR(wd), TY_DOUBLE)
+ call mfree (WL_NV_PTR(wd), TY_REAL)
+ call mfree (WL_MIN_I_PTR(wd), TY_INT)
+ call mfree (WL_MAJ_I_PTR(wd), TY_DOUBLE)
+ call mfree (WL_LOGICAL_CENTER_PTR(wd), TY_DOUBLE)
+ call mfree (WL_LABEL_VALUE_PTR(wd), TY_DOUBLE)
+ call mfree (WL_LABEL_SIDE_PTR(wd), TY_BOOL)
+ call mfree (WL_LABEL_POSITION_PTR(wd), TY_DOUBLE)
+ call mfree (WL_LABEL_AXIS_PTR(wd), TY_INT)
+ call mfree (WL_LABEL_ANGLE_PTR(wd), TY_DOUBLE)
+ call mfree (WL_END_PTR(wd), TY_DOUBLE)
+ call mfree (WL_BEGIN_PTR(wd), TY_DOUBLE)
+ call mfree (WL_AXIS_TITLE_SIDE_PTR(wd), TY_BOOL)
+ call mfree (WL_AXIS_TITLE_PTR(wd), TY_CHAR)
+
+ # Now deallocate the structure.
+ call mfree (wd, TY_STRUCT)
+end
+
+
+# WL_LABEL_SIDE -- Decode string into set of booleans sides.
+
+procedure wl_label_side (input, flag)
+
+char input[ARB] # I: string listing the sides to be labeled
+bool flag[N_SIDES] # O: the flags indicating which sides wll be labeled
+
+int i
+int strmatch()
+
+begin
+ # Initialize all the flags to false.
+ do i = 1, N_SIDES
+ flag[i] = false
+
+ # Now set each side that is in the list.
+ if (strmatch (input, "right") != 0)
+ flag[RIGHT] = true
+ if (strmatch (input, "left") != 0)
+ flag[LEFT] = true
+ if (strmatch (input, "top") != 0)
+ flag[TOP] = true
+ if (strmatch (input, "bottom") != 0)
+ flag[BOTTOM] = true
+end
+
+
+# WL_STRING_TO_INTERVAL -- Convert from a string to a number.
+#
+# Description
+# Since (ideally) the wcslab task should be able to handle any sky
+# map transformation, there are a number of potential units that can be
+# transformed from. The specification of coordinates in these systems
+# are also quite varied. Thus, for input purposes, coordinates are entered
+# as strings. This routine decodes the strings to a common unit (degrees)
+# based on the type of system being graphed.
+#
+# Function Returns
+# This returns the single coordinate value converted to a base system
+# (degrees).
+
+double procedure wl_string_to_internal (input, axis_type, which_axis)
+
+char input[ARB] # I; the string containing the numerical value
+int axis_type # I: the type of wcs
+int which_axis # I: the axis number
+
+double value
+int strlen(), nscan()
+
+begin
+ # It is possible that the value was not defined.
+ if (strlen (input) <= 0)
+ value = INDEFD
+
+ # Decode based on the system.
+ else
+ switch (axis_type) {
+
+ # The RA and DEC systems.
+ case RA_DEC:
+
+ # Since SPP FMTIO can handle the HH:MM:SS format, just let it
+ # read in the value. However, there is no way to distinquish
+ # H:M:S from D:M:S. If the axis being read is RA, assume that
+ # it was H:M:S.
+
+ call sscan (input)
+ call gargd (value)
+
+ # If the axis is Longitude == RA, then convert the hours to
+ # degrees.
+ if (nscan() < 1) {
+ value = INDEFD
+ } else {
+ if (which_axis == AXIS1)
+ value = HRSTODEG (value)
+ }
+
+ # Default- unknown system, just read the string as a double
+ # precision and return it.
+ default:
+ call sscan (input)
+ call gargd (value)
+ if (nscan() < 1)
+ value = INDEFD
+ }
+
+ return (value)
+end
+
+
+# WL_LINE_TYPE -- Decode a string into an IRAF GIO polyline type.
+
+int procedure wl_line_type (line_type_string)
+
+char line_type_string[ARB] # I: the string specifying the line type
+ # "solid" -> GL_SOLID
+ # "dotted" -> GL_DOTTED
+ # "dashed" -> GL_DASHED
+ # "dotdash" -> GL_DOTDASH
+int type
+bool streq()
+
+begin
+ if (streq (line_type_string, "solid"))
+ type = GL_SOLID
+ else if (streq (line_type_string, "dotted"))
+ type = GL_DOTTED
+ else if (streq( line_type_string, "dashed"))
+ type = GL_DASHED
+ else if (streq (line_type_string, "dotdash"))
+ type = GL_DOTDASH
+ else {
+ call eprintf ("Pattern unknown, using 'solid'.\n")
+ type = GL_SOLID
+ }
+
+ return (type)
+end
+
+
+# WL_INTERNAL_TO_STRING - Convert internal representation to a string.
+
+procedure wl_internal_to_string (value, system_type, which_axis, output)
+
+double value # I: the value to convert
+int system_type # I: the wcs type
+int which_axis # I: the axis
+char output[ARB] # O: the output string
+
+begin
+ # If the value is undefined, write an empty string.
+ if (IS_INDEFD (value))
+ output[1] = EOS
+
+ # Else, convert the value depending on the axis types.
+ else
+ switch (system_type) {
+
+ # Handle the RA, DEC
+ case RA_DEC:
+
+ # If this is Axis1 == Right Ascension, then convert to hours.
+ if (which_axis == AXIS1)
+ value = value / 15.0D0
+
+ call sprintf (output, SZ_LINE, "%.6h")
+ call pargd (value)
+
+ # Else, just write a value.
+ default:
+ call sprintf (output, SZ_LINE, "%.7g")
+ call pargd (value)
+ }
+
+end
+
+
+# WL_SIDE_TO_STRING -- Convert a side to its string representation.
+
+procedure wl_side_to_string (side, output, max_len)
+
+int side # I: the side to convert
+char output[max_len] # O: the string representation of the side
+int max_len # I: the maximum length of the output string
+
+begin
+ switch (side) {
+ case RIGHT:
+ call strcpy ("right", output, max_len)
+ case LEFT:
+ call strcpy ("left", output, max_len)
+ case TOP:
+ call strcpy ("top", output, max_len)
+ case BOTTOM:
+ call strcpy ("bottom", output, max_len)
+ default:
+ call strcpy ("default", output, max_len)
+ }
+end
+
+
+# WL_PUT_LABEL_SIDES -- Create a string containing the sides specified.
+
+procedure wl_put_label_sides (side_flags, output, max_len)
+
+bool side_flags[N_SIDES] # I: the boolean array of sides
+char output[ARB] # O: the output comma separated list of sides
+int max_len # I: maximum length of the output string
+
+int i
+pointer sp, side
+int strlen()
+
+begin
+ # Get memory.
+ call smark (sp)
+ call salloc (side, max_len, TY_CHAR)
+
+ # Build the list.
+ output[1] = EOS
+ do i = 1, N_SIDES
+ if (side_flags[i]) {
+ if (strlen (output) != 0)
+ call strcat (",", output, max_len)
+ call wl_side_to_string (i, Memc[side], max_len)
+ call strcat (Memc[side], output, max_len)
+ }
+
+ if (strlen (output) == 0)
+ call strcat ("default", output, max_len)
+
+ # Free memory.
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/stxtools/wcslab/wlgrid.x b/pkg/utilities/nttools/stxtools/wcslab/wlgrid.x
new file mode 100644
index 00000000..4f457af4
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/wcslab/wlgrid.x
@@ -0,0 +1,448 @@
+include <gset.h>
+include <math.h>
+include "wcslab.h"
+include "wcs_desc.h"
+
+
+# WL_GRID -- Put the grid lines/tick marks on the plot.
+#
+# Description
+# Based on previously determined parameters., draw the grid lines and/or
+# tick marks onto the graph. While in the process of doing this, create
+# a list of possible label points for use by the label_grid routine.
+
+procedure wl_grid (wd)
+
+pointer wd # I: the WCSLAB descriptor
+
+double current, tmp_begin, tmp_end, tmp_minor_interval
+int old_type, old_n_labels, min_counter
+int gstati()
+
+begin
+ # Initialize the label counter.
+ WL_N_LABELS(wd) = 0
+
+ # Remember what line type is currently active.
+ old_type = gstati (WL_GP(wd), G_PLTYPE)
+
+ # Determine integer range for axis 1.
+ tmp_minor_interval = WL_MAJOR_INTERVAL(wd,AXIS1) /
+ double (WL_MINOR_INTERVAL(wd,AXIS1))
+
+ # If near-polar, the lines should go all the way to the poles.
+ if (WL_GRAPH_TYPE(wd) == NEAR_POLAR)
+ if (abs (WL_BEGIN(wd,AXIS2)) < abs (WL_END(wd,AXIS2))) {
+ tmp_begin = WL_BEGIN(wd,AXIS2)
+ tmp_end = NORTH_POLE_LATITUDE
+ } else {
+ tmp_begin = SOUTH_POLE_LATITUDE
+ tmp_end = WL_END(wd,AXIS2)
+ }
+ else {
+ tmp_begin = WL_BEGIN(wd,AXIS2)
+ tmp_end = WL_END(wd,AXIS2)
+ }
+
+ # Plot lines of constant value in axis 1.
+ current = WL_BEGIN(wd,AXIS1)
+ min_counter = 0
+ repeat {
+
+ if (mod (min_counter, WL_MINOR_INTERVAL(wd,AXIS1)) == 0) {
+ call gseti (WL_GP(wd), G_PLTYPE, WL_MAJ_LINE_TYPE(wd))
+ call wl_graph_constant_axis1 (wd, current, tmp_begin, tmp_end,
+ WL_MAJ_GRIDON(wd), WL_LABON(wd), WL_MAJ_TICK_SIZE(wd))
+ } else {
+ call gseti (WL_GP(wd), G_PLTYPE, WL_MIN_LINE_TYPE(wd))
+ call wl_graph_constant_axis1 (wd, current, tmp_begin, tmp_end,
+ WL_MIN_GRIDON(wd), NO, WL_MIN_TICK_SIZE(wd))
+ }
+
+ min_counter = min_counter + 1
+ current = WL_BEGIN(wd,AXIS1) + tmp_minor_interval * min_counter
+
+ } until (real (current) > real (WL_END(wd,AXIS1)))
+
+ # Determine the interval range for the second axis.
+ tmp_minor_interval = WL_MAJOR_INTERVAL(wd,AXIS2) /
+ double (WL_MINOR_INTERVAL(wd,AXIS2))
+
+ # Plot lines of constant value in axis 2.
+ if (WL_END(wd,AXIS2) < WL_BEGIN(wd,AXIS2)) {
+ current = WL_END(wd,AXIS2)
+ tmp_minor_interval = -tmp_minor_interval
+ tmp_end = WL_BEGIN(wd,AXIS2)
+ } else {
+ current = WL_BEGIN(wd,AXIS2)
+ tmp_end = WL_END(wd,AXIS2)
+ }
+
+ min_counter = 0
+ tmp_begin = current
+ repeat {
+ if (mod (min_counter, WL_MINOR_INTERVAL(wd,AXIS2)) == 0) {
+
+ call gseti (WL_GP(wd), G_PLTYPE, WL_MAJ_LINE_TYPE(wd))
+ old_n_labels = WL_N_LABELS(wd)
+ call wl_graph_constant_axis2 (wd, current, WL_BEGIN(wd,AXIS1),
+ WL_END(wd,AXIS1), WL_MAJ_GRIDON(wd), WL_LABON(wd),
+ WL_MAJ_TICK_SIZE(wd))
+
+ # If this is a polar or near_polar plot, the latitudes
+ # should be placed near the line, not where it crosses the
+ # window boundary.
+
+ if (WL_GRAPH_TYPE(wd) == POLAR &&
+ (WL_MAJ_GRIDON(wd) == YES) && (WL_LABON(wd) == YES)) {
+ WL_N_LABELS(wd) = old_n_labels + 1
+ call wl_w2ld (WL_WLCT(wd), WL_AXIS_FLIP(wd),
+ WL_POLAR_LABEL_POSITION(wd), current,
+ WL_LABEL_POSITION(wd,WL_N_LABELS(wd),X_DIM),
+ WL_LABEL_POSITION(wd,WL_N_LABELS(wd),Y_DIM), 1)
+ WL_LABEL_VALUE(wd,WL_N_LABELS(wd)) = current
+ WL_LABEL_AXIS(wd,WL_N_LABELS(wd)) = AXIS2
+ }
+
+ } else {
+ call gseti (WL_GP(wd), G_PLTYPE, WL_MIN_LINE_TYPE(wd))
+ call wl_graph_constant_axis2 (wd, current, WL_BEGIN(wd,AXIS1),
+ WL_END(wd,AXIS1), WL_MIN_GRIDON(wd), NO,
+ WL_MIN_TICK_SIZE(wd))
+ }
+
+ # Increment and continue
+ min_counter = min_counter + 1
+ current = tmp_begin + tmp_minor_interval * min_counter
+
+ } until (real (current) > real (tmp_end))
+
+ # Set the line type back to the way it was.
+ call gseti (WL_GP(wd), G_PLTYPE, old_type)
+end
+
+
+# WL_GRAPH_CONSTANT_AXIS1 - Graph lines of constant X-axis values.
+#
+# Description
+# Because projections are rarely linear, the basic GIO interface to draw
+# lines cannot be used. Instead, this routine handles the line drawing.
+# Also, possible label points are found and added to a label list array.
+#
+# CLUDGE! Finding labels here is WRONG. Ideally, crossing points (where the
+# line crosses a screen boundary) should be determined analytically. However,
+# the MWCS interface lacks the required "cross-transformations". It can
+# still be done, but requires a total bypassing of MWCS. Instead, this
+# simplistic approach is used.
+
+procedure wl_graph_constant_axis1 (wd, x, ymin, ymax, gridon, label, tick_size)
+
+pointer wd # I: the WCSLAB descriptor
+double x # I: X value to hold constant
+double ymin, ymax # I: Y values to vary between
+int gridon # I: true if gridding is on
+int label # I: true if the points should be labelled
+real tick_size # I: size of tick marks
+
+bool done
+double lastx, lasty, lx, ly, y, yinc
+real rlx, rly
+
+begin
+ # Determine the scale at which Y should be incremented.
+ yinc = (ymax - ymin) / WL_LINE_SEGMENTS(wd)
+
+ # Now graph the line segments.
+ y = ymin
+ call wl_w2ld (WL_WLCT(wd), WL_AXIS_FLIP(wd), x, y, lastx, lasty, 1)
+
+ rlx = lastx
+ rly = lasty
+ call gamove (WL_GP(wd), rlx, rly)
+
+ repeat {
+ call wl_w2ld (WL_WLCT(wd), WL_AXIS_FLIP(wd), x, y, lx, ly, 1)
+ call wl_point_to_label (wd, lastx, lasty, lx, ly, AXIS1, x, gridon,
+ label, tick_size)
+ if (gridon == YES) {
+ rlx = lx
+ rly = ly
+ call gadraw (WL_GP(wd), rlx, rly)
+ }
+ if (yinc < 0.)
+ done = y < ymax
+ else
+ done = y > ymax
+ y = y + yinc
+ lastx = lx
+ lasty = ly
+ } until (done)
+end
+
+
+# WL_GRAPH_CONSTANT_AXIS2 -- Graph lines of constant Y-axis values.
+#
+# Description
+# Because projections are rarely linear, the basic GIO interface to draw
+# lines cannot be used. Instead, this routine handles the line drawing.
+# Also, possible label points are found and added to an label list array.
+#
+# CLUDGE! Finding labels here is WRONG. Ideally, crossing points (where the
+# line crosses a screen boundary) should be determined analytically. However,
+# the MWCS interface lacks the required "cross-transformations". It can
+# still be done, but requires a total bypassing of MWCS. Instead, this
+# simplistic approach is used.
+
+procedure wl_graph_constant_axis2 (wd, y, xmin, xmax, gridon, label, tick_size)
+
+pointer wd # I: the WCSLAB descriptor
+double y # I: Y value to hold constant
+double xmin, xmax # I: X values to vary between
+int gridon # I: true if gridding is on
+int label # I: true if points should be labelled
+real tick_size # I: tick mark size
+
+bool done
+double lx, ly, lastx, lasty, x, xinc
+real rlx, rly
+
+begin
+ # Determine the scale at which X should be incremented.
+ xinc = (xmax - xmin) / WL_LINE_SEGMENTS(wd)
+
+ # Now graph the line segments.
+ x = xmin
+ call wl_w2ld (WL_WLCT(wd), WL_AXIS_FLIP(wd), x, y, lastx, lasty, 1)
+
+ rlx = lastx
+ rly = lasty
+ call gamove (WL_GP(wd), rlx, rly)
+
+ repeat {
+ call wl_w2ld (WL_WLCT(wd), WL_AXIS_FLIP(wd), x, y, lx, ly, 1)
+ call wl_point_to_label (wd, lastx, lasty, lx, ly, AXIS2, y, gridon,
+ label, tick_size)
+ if (gridon == YES) {
+ rlx = lx
+ rly = ly
+ call gadraw (WL_GP(wd), rlx, rly)
+ }
+ if (xinc < 0.)
+ done = x < xmax
+ else
+ done = x > xmax
+ lastx = lx
+ lasty = ly
+ x = x + xinc
+ } until (done)
+end
+
+
+# Define the inside and outside of the window.
+
+define OUT (($1<=WL_SCREEN_BOUNDARY(wd,LEFT))||($1>=WL_SCREEN_BOUNDARY(wd,RIGHT))||($2<=WL_SCREEN_BOUNDARY(wd,BOTTOM))||($2>=WL_SCREEN_BOUNDARY(wd,TOP)))
+
+define IN (($1>WL_SCREEN_BOUNDARY(wd,LEFT))&&($1<WL_SCREEN_BOUNDARY(wd,RIGHT))&&($2>WL_SCREEN_BOUNDARY(wd,BOTTOM))&&($2<WL_SCREEN_BOUNDARY(wd,TOP)))
+
+
+# WL_POINT_TO_LABEL - Record a points position along a window boundary.
+#
+# Description
+# Since the MWCS interface lacks "cross-transformations", i.e. If given
+# RA and and X axis location, find DEC and Y axis, we need a different
+# method of determining when lines of constant Axis 1/Axis 2 cross
+# the window boundary. Since each line is drawn by small increments, each
+# increment is watched to see if a window boundary has been crossed. This
+# is what this routine does: Confirms that a boundary has been crossed,
+# records this position and label value. Tick marks are also drawn here
+# because all the necessary information is known at this point.
+#
+# NOTE: THIS WAY IS A CLUDGE ! A more formal method of finding
+# cross-transformations is needed- most likely an iterative method. This
+# way was just "convenient at the time".
+
+procedure wl_point_to_label (wd, x1, y1, x2, y2, axis, axis_value, gridon,
+ label, tick_size)
+
+pointer wd # I: the WCSLAB descriptor
+double x1, y1, x2, y2 # I: the two possible points to label
+int axis # I: which axis are we dealing with ?
+double axis_value # I: the value of the axis at this point
+int gridon # I: true if gridding is on
+int label # I: true if this point should have a label
+real tick_size # I: size of the tick mark
+
+double nx, ny, tick_x, tick_y
+double wl_vector_angle()
+
+begin
+ # Determine whether the two points straddle a window boundary. If they
+ # do, then this is the point to label.
+ if (OUT (x1, y1) && IN (x2, y2)) {
+
+ call wl_axis_on_line (x1, y1, x2, y2, WL_SCREEN_BOUNDARY(wd,1),
+ nx, ny)
+
+ if (gridon == NO) {
+ call wl_mark_tick (WL_GP(wd), WL_NDC_WCS(wd), tick_size,
+ WL_TICK_IN(wd), x1, y1, x2, y2, nx, ny, tick_x, tick_y)
+ if (WL_TICK_IN(wd) != WL_LABOUT(wd)) {
+ nx = tick_x
+ ny = tick_y
+ }
+ }
+
+ if ((label == YES) && WL_N_LABELS(wd) < MAX_LABEL_POINTS) {
+ WL_N_LABELS(wd) = WL_N_LABELS(wd) + 1
+ WL_LABEL_POSITION(wd,WL_N_LABELS(wd),AXIS1) = nx
+ WL_LABEL_POSITION(wd,WL_N_LABELS(wd),AXIS2) = ny
+ WL_LABEL_VALUE(wd,WL_N_LABELS(wd)) = axis_value
+ WL_LABEL_AXIS(wd,WL_N_LABELS(wd)) = axis
+ WL_LABEL_ANGLE(wd,WL_N_LABELS(wd)) =
+ wl_vector_angle (WL_GP(wd), x1, y1, x2, y2)
+ }
+ }
+
+ if (IN (x1, y1) && OUT (x2, y2)) {
+
+ call wl_axis_on_line (x2, y2, x1, y1, WL_SCREEN_BOUNDARY(wd,1),
+ nx, ny)
+
+ if (gridon == NO) {
+ call wl_mark_tick (WL_GP(wd), WL_NDC_WCS(wd), tick_size,
+ WL_TICK_IN(wd), x2, y2, x1, y1, nx, ny, tick_x, tick_y)
+ if (WL_TICK_IN(wd) != WL_LABOUT(wd)) {
+ nx = tick_x
+ ny = tick_y
+ }
+ }
+
+ if ((label == YES) && WL_N_LABELS(wd) < MAX_LABEL_POINTS) {
+ WL_N_LABELS(wd) = WL_N_LABELS(wd) + 1
+ WL_LABEL_POSITION(wd,WL_N_LABELS(wd),AXIS1) = nx
+ WL_LABEL_POSITION(wd,WL_N_LABELS(wd),AXIS2) = ny
+ WL_LABEL_VALUE(wd,WL_N_LABELS(wd)) = axis_value
+ WL_LABEL_AXIS(wd,WL_N_LABELS(wd)) = axis
+ WL_LABEL_ANGLE(wd,WL_N_LABELS(wd)) =
+ wl_vector_angle (WL_GP(wd), x1, y1, x2, y2)
+ }
+ }
+
+end
+
+
+# WL_MARK_TICK - Draw the tick mark at the point.
+#
+# Description
+# Draw a tick mark rooted at (sx,sy), whose direction is defined by
+# the vector (x0,y0) to (x1,y1). The other end of the tick mark is
+# returned in (tick_x,tick_y).
+
+procedure wl_mark_tick (gp, wcs, tick_size, in, x0, y0, x1, y1, sx, sy,
+ tick_x, tick_y)
+
+pointer gp # I: the graphics pointer
+int wcs # I: the WCS to use to draw the tick marks
+real tick_size # I: size of the tick mark
+int in # I: true if ticks should be into the graph
+double x0, y0, x1, y1 # I: the points defining the tick direction
+double sx, sy # I: the root point of the tick mark
+double tick_x, tick_y # O: the end point of the tick mark
+
+int old_line, old_wcs
+real dx, dy, t, ndc_x0, ndc_y0, ndc_x1, ndc_y1, ndc_x2, ndc_y2
+real ndc_sx, ndc_sy
+int gstati()
+real wl_distancer()
+
+begin
+ # Change graphics coordinates to NDC.
+ old_wcs = gstati (gp, G_WCS)
+ old_line = gstati (gp, G_PLTYPE)
+ call gseti (gp, G_WCS, wcs)
+ call gseti (gp, G_PLTYPE, GL_SOLID)
+
+ # Convert the points to NDC coordinates.
+ ndc_x2 = real (sx)
+ ndc_y2 = real (sy)
+ call gctran (gp, ndc_x2, ndc_y2, ndc_sx, ndc_sy, old_wcs, wcs)
+ ndc_x2 = real (x0)
+ ndc_y2 = real (y0)
+ call gctran (gp, ndc_x2, ndc_y2, ndc_x0, ndc_y0, old_wcs, wcs)
+ ndc_x2 = real (x1)
+ ndc_y2 = real (y1)
+ call gctran (gp, ndc_x2, ndc_y2, ndc_x1, ndc_y1, old_wcs, wcs)
+
+ # Determine the parameterized line parameters.
+ dx = ndc_x1 - ndc_x0
+ dy = ndc_y1 - ndc_y0
+
+ # Determine how large in "time" the tick mark is.
+ t = tick_size / wl_distancer (ndc_x0, ndc_y0, ndc_x1, ndc_y1)
+
+ # If tick marks are to point out of the graph, reverse the sign of t.
+ # Also need to turn clipping off for the ticks appear.
+ if (in == NO) {
+ t = -t
+ call gseti (gp, G_CLIP, NO)
+ }
+
+ # Determine the end point of the tick mark.
+ ndc_x2 = t * dx + ndc_sx
+ ndc_y2 = t * dy + ndc_sy
+
+ # Now draw the tick mark.
+ call gamove (gp, ndc_sx, ndc_sy)
+ call gadraw (gp, ndc_x2, ndc_y2)
+
+ # Restore clipping if necessary.
+ if (in == NO)
+ call gseti (gp, G_CLIP, YES)
+
+ # Restore previous settings.
+ call gseti (gp, G_WCS, old_wcs)
+ call gseti (gp, G_PLTYPE, old_line)
+
+ # Transform the end of the tick mark.
+ call gctran (gp, ndc_x2, ndc_y2, dx, dy, wcs, old_wcs)
+ tick_x = double (dx)
+ tick_y = double (dy)
+end
+
+
+# WL_VECTOR_ANGLE -- Return the angle represented by the given vector.
+#
+# Returns
+# The angle of the given vector.
+
+double procedure wl_vector_angle (gp, x1, y1, x2, y2)
+
+pointer gp # I: the graphics descriptor
+double x1, y1, x2, y2 # I: the end points of the vector
+
+double dangle
+real angle, delx, dely, ndc_x1, ndc_x2, ndc_y1, ndc_y2
+bool fp_equalr()
+int gstati()
+
+begin
+ # Translate the input points to NDC coordinates.
+ ndc_x1 = real (x1)
+ ndc_x2 = real (x2)
+ ndc_y1 = real (y1)
+ ndc_y2 = real (y2)
+ call gctran (gp, ndc_x1, ndc_y1, ndc_x1, ndc_y1, gstati (gp, G_WCS),
+ NDC_WCS)
+ call gctran (gp, ndc_x2, ndc_y2, ndc_x2, ndc_y2, gstati (gp, G_WCS),
+ NDC_WCS)
+
+ dely = ndc_y2 - ndc_y1
+ delx = ndc_x2 - ndc_x1
+ if (fp_equalr (delx, 0.) && fp_equalr (dely, 0.))
+ angle = 0.0
+ else
+ angle = RADTODEG (atan2 (dely, delx))
+ dangle = angle
+
+ return (dangle)
+end
diff --git a/pkg/utilities/nttools/stxtools/wcslab/wllabel.x b/pkg/utilities/nttools/stxtools/wcslab/wllabel.x
new file mode 100644
index 00000000..4578f89c
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/wcslab/wllabel.x
@@ -0,0 +1,1100 @@
+include <gset.h>
+include <math.h>
+include "psiescape.h"
+include "wcslab.h"
+include "wcs_desc.h"
+
+
+# Define the offset array.
+define OFFSET Memr[$1+$2-1]
+
+# Define the postscript kernel
+define PSIKERN "psikern"
+
+# WL_LABEL -- Place the labels on the grids.
+#
+# Description
+# Format and write the labels for the grid/tick marks. Much of this
+# is wading through conditions to decide whether a label should be
+# written or not.
+
+procedure wl_label (wd)
+
+pointer wd # I: the WCSLAB descriptor
+
+bool no_side_axis1, no_side_axis2, streq()
+int i, axis1_side, axis2_side
+short flag
+pointer kernel, sp, offset_ptr
+real offset
+
+begin
+ # Get some memory.
+ call smark (sp)
+ call salloc (offset_ptr, N_SIDES, TY_REAL)
+ do i = 1, N_SIDES
+ OFFSET(offset_ptr,i) = 0.
+ call salloc (kernel, SZ_LINE, TY_CHAR )
+
+ # Decide whether any sides were specified for either axis.
+ no_side_axis1 = true
+ no_side_axis2 = true
+ do i = 1, N_SIDES {
+ if (WL_LABEL_SIDE(wd,i,AXIS1))
+ no_side_axis1 = false
+ if (WL_LABEL_SIDE(wd,i,AXIS2))
+ no_side_axis2 = false
+ }
+
+ # If polar, then label the axis 2's next to their circles on the
+ # graph and allow the Axis 1s to be labeled on all sides of the graph.
+
+ if (WL_GRAPH_TYPE(wd) == POLAR) {
+
+ call wl_polar_label (wd)
+
+ if (no_side_axis1) {
+ do i = 1, N_SIDES {
+ WL_LABEL_SIDE(wd,i,AXIS1) = true
+ }
+ if (IS_INDEFI (WL_AXIS_TITLE_SIDE(WD,AXIS1)))
+ WL_AXIS_TITLE_SIDE(WD,AXIS1) = BOTTOM
+ }
+
+ # If we are near-polar, label the Axis 2 as if polar, and label
+ # Axis1 on all sides except the side closest to the pole.
+
+ } else if (WL_GRAPH_TYPE(wd) == NEAR_POLAR) {
+
+ if (no_side_axis1) {
+ WL_LABEL_SIDE(wd,WL_BAD_LABEL_SIDE(wd),AXIS1) = true
+ if (IS_INDEFI (WL_AXIS_TITLE_SIDE(wd,AXIS1)))
+ WL_AXIS_TITLE_SIDE(wd,AXIS1) = WL_BAD_LABEL_SIDE(wd)
+ }
+
+ if (no_side_axis2) {
+ WL_LABEL_SIDE(wd,WL_POLAR_LABEL_DIRECTION(wd),AXIS2) = true
+ if (IS_INDEFI (WL_AXIS_TITLE_SIDE(wd,AXIS2)))
+ WL_AXIS_TITLE_SIDE(wd,AXIS2) = WL_POLAR_LABEL_DIRECTION(wd)
+ }
+
+ # Final case- adjacent sides should be labelled.
+
+ } else {
+
+ # Determine the best sides for labelling.
+ if (INVERT (WL_ROTA(wd))) {
+ axis1_side = LEFT
+ axis2_side = BOTTOM
+ } else {
+ axis1_side = BOTTOM
+ axis2_side = LEFT
+ }
+
+ # If no sides were specified, use the calculated ones above.
+ if (no_side_axis1)
+ WL_LABEL_SIDE(wd,axis1_side,AXIS1) = true
+ if (no_side_axis2)
+ WL_LABEL_SIDE(wd,axis2_side,AXIS2) = true
+ }
+
+ # Check to see if this is a psikern printer. If so, set text
+ # so that it is mono-spaced. The superscripting algorithm
+ # doesn't work too well in a proportional-spaced system.
+ call ggets (WL_GP(wd), "tn", Memc[kernel], SZ_LINE )
+ if (streq (Memc[kernel], PSIKERN)) {
+ flag = NO
+ call gescape (WL_GP(wd), PS_VARIABLE_SPACE, flag,
+ PS_VARIABLE_SPACE_SIZE)
+ }
+
+ # Now draw the labels for axis 1.
+ do i = 1, N_SIDES {
+
+ if (WL_LABEL_SIDE(wd,i,AXIS1)) {
+ call wl_lab_edges (wd, AXIS1, i, offset)
+ if (IS_INDEFI (WL_AXIS_TITLE_SIDE(WD,AXIS1)))
+ WL_AXIS_TITLE_SIDE(WD,AXIS1) = i
+ } else
+ offset = 0.
+
+ # Modify the bounding box for the new viewport.
+ if (abs (offset) > abs (OFFSET(offset_ptr,i)))
+ OFFSET(offset_ptr,i) = offset
+ }
+
+ # Draw the labels for axis 2.
+ if (WL_GRAPH_TYPE(wd) != POLAR)
+ do i = 1, N_SIDES {
+
+ if (WL_LABEL_SIDE(wd,i,AXIS2)) {
+ call wl_lab_edges (wd, AXIS2, i, offset)
+ if (IS_INDEFI (WL_AXIS_TITLE_SIDE(wd,AXIS2)))
+ WL_AXIS_TITLE_SIDE(wd,AXIS2) = i
+ } else
+ offset = 0.
+
+ # Modify the bounding box for the new viewport.
+ if (abs (offset) > abs (OFFSET(offset_ptr,i)))
+ OFFSET(offset_ptr,i) = offset
+ }
+
+ # Reset to variable spacing.
+ if (streq (Memc[kernel], PSIKERN)) {
+ flag = YES
+ call gescape (WL_GP(wd), PS_VARIABLE_SPACE, flag,
+ PS_VARIABLE_SPACE_SIZE)
+ }
+
+ # Set the bounding box.
+ do i = 1, N_SIDES
+ WL_NEW_VIEW(wd,i) = WL_NEW_VIEW(wd,i) + OFFSET(offset_ptr,i)
+
+ # Now write the graph title.
+ call wl_title (WL_GP(wd), WL_AXIS_TITLE(wd,AXIS1),
+ WL_AXIS_TITLE_SIDE(wd,AXIS1), WL_AXIS_TITLE_SIZE(wd),
+ WL_NEW_VIEW(wd,1))
+ if (WL_GRAPH_TYPE(wd) != POLAR)
+ call wl_title (WL_GP(wd), WL_AXIS_TITLE(wd,AXIS2),
+ WL_AXIS_TITLE_SIDE(wd,AXIS2), WL_AXIS_TITLE_SIZE(WD),
+ WL_NEW_VIEW(wd,1))
+ if (! IS_INDEFI (WL_TITLE_SIDE(wd)))
+ call wl_title (WL_GP(wd), WL_TITLE(wd), WL_TITLE_SIDE(wd),
+ WL_TITLE_SIZE(wd), WL_NEW_VIEW(wd,1))
+
+ # Release memory.
+ call sfree (sp)
+end
+
+
+# Define what is in the screen.
+
+define IN (($1>WL_SCREEN_BOUNDARY(wd,LEFT))&&($1<WL_SCREEN_BOUNDARY(wd,RIGHT))&&($2>WL_SCREEN_BOUNDARY(wd,BOTTOM))&&($2<WL_SCREEN_BOUNDARY(wd,TOP)))
+
+# WL_POLAR_LABEL -- Place Latitude labels next to Latitude circles.
+#
+# Description
+# Since Lines of constant Latitude on a polar graph are usually circles
+# around the pole, the lines may never cross edges. Instead, the labels
+# are placed next to circles. The grid-drawing routines should setup
+# the label position array such that each line has only one label point.
+
+procedure wl_polar_label (wd)
+
+pointer wd # I: the WCSLAB descriptor
+
+int i, prec
+pointer sp, label, units, label_format, units_format
+real char_height, char_width, ndc_textx, ndc_texty, old_text_size
+real textx, texty
+int wl_precision()
+real gstatr(), ggetr()
+
+begin
+ # Get some memory.
+ call smark (sp)
+ call salloc (label, SZ_LINE, TY_CHAR)
+ call salloc (units, SZ_LINE, TY_CHAR)
+ call salloc (label_format, SZ_LINE, TY_CHAR)
+ call salloc (units_format, SZ_LINE, TY_CHAR)
+
+ # Get the character height and width. This is used to ensure that we
+ # have moved the label strings off the border.
+
+ char_height = ggetr (WL_GP(wd), "ch") * gstatr (WL_GP(wd), G_TXSIZE) /
+ 2.
+ char_width = ggetr (WL_GP(wd), "cw") * gstatr (WL_GP(wd), G_TXSIZE) /
+ 2.
+
+ # Get the text size and cut it in half for on the plot labelling.
+ old_text_size = gstatr (WL_GP(wd), G_TXSIZE)
+ call gsetr (WL_GP(wd), G_TXSIZE, old_text_size)
+ call gsetr (WL_GP(wd), G_TXSIZE, old_text_size * 0.80)
+
+ # Determine the precision of the output.
+ prec = wl_precision (wd, AXIS2)
+
+ # Place the labels.
+ for (i = 1; i <= WL_N_LABELS(wd); i = i + 1)
+ if (WL_LABEL_AXIS(wd,i) == AXIS2) {
+
+ # Decode the coordinate into a text string.
+ call wl_dms (WL_LABEL_VALUE(wd,i), Memc[label], Memc[units],
+ SZ_LINE, prec, true)
+
+ # Convert text position from "unknown" coordinates to NDC.
+ call gctran (WL_GP(wd), real (WL_LABEL_POSITION(wd,i,AXIS1)),
+ real (WL_LABEL_POSITION(wd,i,AXIS2)), ndc_textx, ndc_texty,
+ WL_PLOT_WCS(wd), WL_NDC_WCS(wd))
+
+ # Determine the text justification.
+ switch (WL_POLAR_LABEL_DIRECTION(wd)) {
+ case BOTTOM:
+ call strcpy ("h=c;v=t", Memc[label_format], SZ_LINE)
+ call strcpy ("h=c;v=c", Memc[units_format], SZ_LINE)
+ ndc_texty = ndc_texty - char_height
+ case TOP:
+ call strcpy ("h=c;v=c", Memc[label_format], SZ_LINE)
+ call strcpy ("h=c;v=b", Memc[units_format], SZ_LINE)
+ ndc_texty = ndc_texty + char_height
+ case LEFT:
+ call strcpy ("h=r;v=c", Memc[label_format], SZ_LINE)
+ call strcpy ("h=r;v=b", Memc[units_format], SZ_LINE)
+ ndc_textx = ndc_textx - char_width
+ case RIGHT:
+ call strcpy ("h=l;v=c", Memc[label_format], SZ_LINE)
+ call strcpy ("h=l;v=b", Memc[units_format], SZ_LINE)
+ ndc_textx = ndc_textx + char_width
+ }
+
+ # Convert the text position from NDC back to the "unknown"
+ # system.
+ call gctran (WL_GP(wd), ndc_textx, ndc_texty, textx, texty,
+ WL_NDC_WCS(wd), WL_PLOT_WCS(wd))
+
+ # Print the label.
+ if (IN (textx, texty)) {
+ call gtext (WL_GP(wd), textx, texty, Memc[label],
+ Memc[label_format])
+ call gtext (WL_GP(wd), textx, texty, Memc[units],
+ Memc[units_format])
+ }
+
+ }
+
+ # Set the text size back.
+ call gsetr (WL_GP(wd), G_TXSIZE, old_text_size)
+
+ # Release memory.
+ call sfree (sp)
+
+end
+
+
+# Memory management for labels
+
+define LABEL_LIST Memi[labels+$1-1]
+
+# WL_LAB_EDGES -- Place labels along the edges of the window.
+#
+# Description
+# Place labels on the specified side of the graph.
+
+procedure wl_lab_edges (wd, axis, side, offset)
+
+pointer wd # I: the WCSLAB descriptor
+int axis # I: the type of axis being labeled
+int side # I: the side to place the labels
+real offset # O: offset in NDC units for titles
+
+bool do_full
+double angle, tangle
+int i, full_label, nlabels, old_wcs, prec
+pointer sp, labels
+real ndc_textx, ndc_texty, old_text_size, textx, texty
+
+int wl_full_label_position(), wl_find_side()
+double wl_string_angle(), wl_angle()
+int gstati(), wl_precision()
+real gstatr()
+
+begin
+ call smark (sp)
+
+ # All label placement is done in NDC coordinates.
+ old_wcs = gstati (WL_GP(wd), G_WCS)
+ call gseti (WL_GP(wd), G_WCS, WL_NDC_WCS(wd))
+
+ # Set text labelling size.
+ old_text_size = gstatr (WL_GP(wd), G_TXSIZE)
+ call gsetr (WL_GP(wd), G_TXSIZE, WL_LABEL_SIZE(wd))
+
+ # Get the precision of the axis interval.
+ prec = wl_precision (wd, axis)
+
+ # Initialize string size.
+ offset = 0.
+
+ # Build a list of possible labels for this side. The conditions are
+ # that the label should be for the current axis and that it lies on
+ # the current side.
+
+ call salloc (labels, WL_N_LABELS(wd), TY_INT)
+ nlabels = 0
+ for (i = 1; i <= WL_N_LABELS(wd); i = i + 1)
+ if (WL_LABEL_AXIS(wd,i) == axis &&
+ wl_find_side (WL_LABEL_POSITION(wd,i,AXIS1),
+ WL_LABEL_POSITION(wd,i,AXIS2),
+ WL_SCREEN_BOUNDARY(wd,1)) == side) {
+ nlabels = nlabels + 1
+ LABEL_LIST(nlabels) = i
+ }
+
+ # If no labels found, then just forget it. If labels found, well
+ # write them out.
+
+ if (nlabels != 0) {
+
+ # Determine which label should be written out in full.
+ full_label = wl_full_label_position (wd, Memi[labels], nlabels,
+ axis, side, prec)
+
+ # Determine the angle that all the labels will be written at.
+ if ((WL_LABOUT(wd) == NO) && (WL_GRAPH_TYPE(wd) != NORMAL) &&
+ (WL_LABEL_ROTATE(wd) == YES))
+ angle = INDEFR
+ else if ((WL_GRAPH_TYPE(wd) == NORMAL) && ((WL_LABEL_ROTATE(wd) ==
+ YES) || ((WL_LABOUT(wd) == NO) && (WL_MAJ_GRIDON(wd) == YES))))
+ angle = wl_angle (wd, Memi[labels], nlabels)
+ else
+ angle = 0.0
+
+ # Place the labels.
+ for (i = 1; i <= nlabels; i = i + 1) {
+
+ # Save some pertinent information.
+ textx = real (WL_LABEL_POSITION(wd,LABEL_LIST(i),AXIS1))
+ texty = real (WL_LABEL_POSITION(wd,LABEL_LIST(i),AXIS2))
+ do_full = ((LABEL_LIST(i) == full_label) ||
+ (WL_ALWAYS_FULL_LABEL(wd) == YES))
+
+ # Transform the "unknown" coordinate system to a known
+ # coordinate system, NDC, for text placement.
+ call gctran (WL_GP(wd), textx, texty, ndc_textx, ndc_texty,
+ old_wcs, WL_NDC_WCS(wd))
+
+ # If angle is undefined, determine the angle for each label.
+ if (IS_INDEFR(angle))
+ tangle = wl_string_angle (WL_LABEL_ANGLE(wd,
+ LABEL_LIST(i)), WL_LABOUT(wd))
+ else
+ tangle = angle
+
+ # Format and write the label.
+ call wl_write_label (wd, WL_LABEL_VALUE(wd,LABEL_LIST(i)),
+ side, ndc_textx, ndc_texty, tangle, axis, prec, do_full,
+ offset)
+ }
+ }
+
+ # Reset the graphics WCS.
+ call gsetr (WL_GP(wd), G_TXSIZE, old_text_size)
+ call gseti (WL_GP(wd), G_WCS, old_wcs)
+
+ call sfree (sp)
+end
+
+
+# WL_TITLE - Write the title of the graph.
+
+procedure wl_title (gp, title, side, size, viewport)
+
+pointer gp # I: the graphics descriptor
+char title[ARB] # I: the title to write
+int side # I: which side the title will go
+real size # I: the character size to write the title
+real viewport[N_SIDES] # I: the viewport in NDC to keep the title out of
+
+int old_wcs
+real char_height, char_width, left, right, top, bottom, old_rotation
+real old_text_size, x, y
+int gstati(), strlen()
+real ggetr(), gstatr()
+
+begin
+ # Make sure there is a title to write. If not, then punt.
+ if (strlen (title) <= 0)
+ return
+
+ # Get/Set pertinent graphics info.
+ call ggview (gp, left, right, bottom, top)
+
+ old_text_size = gstatr (gp, G_TXSIZE)
+ call gsetr (gp, G_TXSIZE, size)
+ old_rotation = gstatr (gp, G_TXUP)
+
+ char_height = ggetr (gp, "ch") * size
+ char_width = ggetr (gp, "cw") * size
+
+ old_wcs = gstati (gp, G_WCS)
+ call gseti (gp, G_WCS, NDC_WCS)
+
+ # Depending on side, set text position and rotation.
+ switch (side) {
+ case TOP:
+ call gsetr (gp, G_TXUP, 90.)
+ x = (right + left) / 2.
+ y = viewport[TOP] + (2 * char_height)
+ viewport[TOP] = y + (char_height / 2.)
+ case BOTTOM:
+ call gsetr (gp, G_TXUP, 90.)
+ x = (right + left) / 2.
+ y = viewport[BOTTOM] - (2 * char_height)
+ viewport[BOTTOM] = y - (char_height / 2.)
+ case RIGHT:
+ call gsetr (gp, G_TXUP, 180.)
+ x = viewport[RIGHT] + (2 * char_width)
+ y = (top + bottom) / 2.
+ viewport[RIGHT] = x + (char_width / 2.)
+ case LEFT:
+ call gsetr (gp, G_TXUP, 180.)
+ x = viewport[LEFT] - (2 * char_width)
+ y = (top + bottom) / 2.
+ viewport[LEFT] = x - (char_width / 2.)
+ }
+
+ # Write the puppy out.
+ call gtext (gp, x, y, title, "h=c;v=c")
+
+ # Set the graphics state back.
+ call gseti (gp, G_WCS, old_wcs)
+ call gsetr (gp, G_TXSIZE, old_text_size)
+ call gsetr (gp, G_TXUP, old_rotation)
+end
+
+
+# WL_PRECISION -- Determine the precision of the interval.
+
+int procedure wl_precision (wd, axis)
+
+pointer wd # I: the WCSLAB descriptor
+int axis # I: which axis is being examined ?
+
+int prec
+
+begin
+ # Handle the sky coordinates.
+ if (WL_SYSTEM_TYPE(wd) == RA_DEC)
+
+ if (axis == AXIS1) {
+ if (WL_MAJOR_INTERVAL(wd,AXIS1) >= STTODEG (3600.0D0))
+ prec = HOUR
+ else if (WL_MAJOR_INTERVAL(wd,AXIS1) >= STTODEG (60.0D0))
+ prec = MINUTE
+ else if (WL_MAJOR_INTERVAL(wd,AXIS1) >= STTODEG (1.0D0))
+ prec = SECOND
+ else if (WL_MAJOR_INTERVAL(wd,AXIS1) >= STTODEG (.01D0))
+ prec = SUBSEC_LOW
+ else
+ prec = SUBSEC_HIGH
+ } else {
+ if (WL_MAJOR_INTERVAL(wd,AXIS2) >= SATODEG (3600.0D0))
+ prec = DEGREE
+ else if (WL_MAJOR_INTERVAL(wd,AXIS2) >= SATODEG (60.0D0))
+ prec = MINUTE
+ else if (WL_MAJOR_INTERVAL(wd,AXIS2) >= SATODEG (1.0D0))
+ prec = SECOND
+ else if (WL_MAJOR_INTERVAL(wd,AXIS2) >= SATODEG (.01D0))
+ prec = SUBSEC_LOW
+ else
+ prec = SUBSEC_HIGH
+ }
+
+ # Handle other coordinate types.
+ else
+ prec = INDEFI
+
+ return (prec)
+
+end
+
+
+# Define some value constraints.
+
+define LOW_ACCURACY .01
+define HIGH_ACCURACY .0001
+
+# WL_HMS -- Convert value to number in hours, minutes, and seconds.
+
+procedure wl_hms (rarad, hms, units, maxch, precision, all)
+
+double rarad # I: the value to format into a string (degrees)
+char hms[ARB] # O: string containing formatted value
+char units[ARB] # O: string containing formatted units
+int maxch # I: the maximum number of characters allowed
+int precision # I: how precise the output should be
+bool all # I: true if all relevent fields should be formatted
+
+double accuracy, fraction
+int sec, h, m, s
+pointer sp, temp_hms, temp_units
+
+begin
+ # Get some memory.
+ call smark (sp)
+ call salloc (temp_hms, maxch, TY_CHAR)
+ call salloc (temp_units, maxch, TY_CHAR)
+
+ units[1] = EOS
+ hms[1] = EOS
+
+ # Define how close to zero is needed.
+ accuracy = LOW_ACCURACY
+ if (precision == SUBSEC_HIGH)
+ accuracy = HIGH_ACCURACY
+
+ # Seconds of time.
+ fraction = double (abs(DEGTOST (rarad)))
+ if (precision == SUBSEC_LOW || precision == SUBSEC_HIGH) {
+ sec = int (fraction)
+ fraction = fraction - double (sec)
+ } else {
+ sec = int (fraction + 0.5)
+ fraction = 0.
+ }
+
+ # Range: 0 to 24 hours.
+ if (sec < 0)
+ sec = sec + STPERDAY
+ else if (sec >= STPERDAY)
+ sec = mod (sec, STPERDAY)
+
+ # Separater fields.
+ s = mod (sec, 60)
+ m = mod (sec / 60, 60)
+ h = sec / 3600
+
+ # Format fields.
+
+ # Subseconds.
+ if (precision == SUBSEC_LOW || precision == SUBSEC_HIGH) {
+ fraction = s + fraction
+ if (precision == SUBSEC_LOW) {
+ call sprintf (hms, 6, "%05.2f")
+ call pargd (fraction)
+ call strcpy (" s ", units, maxch)
+ } else {
+ call sprintf (hms, 8, "%07.4f")
+ call pargd (fraction)
+ call strcpy (" s ", units, maxch)
+ }
+ if (!all)
+ all = (fraction < accuracy)
+
+ # Seconds
+ } else if (precision == SECOND) {
+
+ # NOTE: The all is not part of the if statement because if
+ # SUBSEC's have been printed, then seconds have already been
+ # dealt with. If SUBSEC's have not been dealt with, then this
+ # is the first field to be checked anyways.
+
+ call sprintf (hms, 3, "%02d ")
+ call pargi (s)
+ call strcpy (" s", units, maxch)
+ if (! all)
+ all = (s == 0)
+ }
+
+ # Minutes.
+ if (precision == MINUTE || (precision > MINUTE && all)) {
+ if (all) {
+ call strcpy (hms, Memc[temp_hms], maxch)
+ call strcpy (units, Memc[temp_units], maxch)
+ }
+ call sprintf (hms, 3, "%02d ")
+ call pargi (m)
+ call strcpy (" m", units, maxch)
+ if (all) {
+ call strcat (Memc[temp_hms], hms, maxch)
+ call strcat (Memc[temp_units], units, maxch)
+ } else
+ all = (m == 0)
+ }
+
+ # Non-zero hours.
+ if (precision == HOUR || all) {
+ if (all) {
+ call strcpy (hms, Memc[temp_hms], maxch)
+ call strcpy (units, Memc[temp_units], maxch)
+ }
+ call sprintf (hms, 3, "%2.2d ")
+ call pargi (h)
+ call strcpy(" h", units, maxch)
+ if (all) {
+ call strcat (Memc[temp_hms], hms, maxch)
+ call strcat (Memc[temp_units], units, maxch)
+ }
+ }
+
+ # Release memory
+ call sfree (sp)
+end
+
+
+# WL_DMS - Convert value to number in degrees, minutes, and seconds.
+
+procedure wl_dms (arcrad, dms, units, maxch, precision, all)
+
+double arcrad # I: the value to format into a string (degrees)
+char dms[ARB] # O: string containing formatted value
+char units[ARB] # O: string containing formatted units
+int maxch # I: the maximum number of characters allowed
+int precision # I: how precise the output should be ?
+bool all # I: true if all relavent fields should be formatted
+
+double accuracy, fraction
+int sec, h, m, s
+pointer sp, temp_dms, temp_units
+int strlen()
+
+begin
+ # Get some memory.
+ call smark (sp)
+ call salloc (temp_dms, maxch, TY_CHAR)
+ call salloc (temp_units, maxch, TY_CHAR)
+
+ units[1] = EOS
+ dms[1] = EOS
+
+ # Define how close to zero is needed.
+ accuracy = LOW_ACCURACY
+ if (precision == SUBSEC_HIGH)
+ accuracy = HIGH_ACCURACY
+
+ # Seconds of time.
+ fraction = double (abs (DEGTOSA (arcrad)))
+ if (precision == SUBSEC_LOW || precision == SUBSEC_HIGH) {
+ sec = int (fraction)
+ fraction = fraction - double (sec)
+ } else {
+ sec = nint (fraction)
+ fraction = 0.
+ }
+
+ # Separater fields.
+ s = mod (abs(sec), 60)
+ m = mod (abs(sec) / 60, 60)
+ h = abs(sec) / 3600
+
+ # Format fields
+ #
+ # Subseconds.
+ if (precision == SUBSEC_LOW || precision == SUBSEC_HIGH) {
+
+ fraction = s + fraction
+ call strcpy (dms, Memc[temp_dms], maxch)
+ call strcpy (units, Memc[temp_units], maxch)
+ if (precision == SUBSEC_LOW) {
+ call sprintf (dms, 6, "%05.2f\"")
+ call pargd (fraction)
+ call strcpy (" ", units, maxch)
+ } else {
+ call sprintf (dms, 8, "%07.4f\"")
+ call pargd (fraction)
+ call strcpy (" ", units, maxch)
+ }
+ if (! all)
+ all = (fraction < accuracy)
+ call strcat (Memc[temp_dms], dms, maxch)
+ call strcat (Memc[temp_units], units, maxch)
+
+ # Seconds
+ } else if (precision == SECOND) {
+
+ # NOTE: The all is not part of the if statement because if
+ # SUBSEC's have been printed, then seconds have already been
+ # dealt with. If SUBSEC's have not been dealt with, then this
+ # is the first field to be checked anyways.
+
+ call strcpy (dms, Memc[temp_dms], maxch)
+ call strcpy (units, Memc[temp_units], maxch)
+ call sprintf (dms, 3, "%02d\"")
+ call pargi (s)
+ call strcpy (" ", units, maxch)
+ if (! all)
+ all = (s == 0)
+ call strcat (Memc[temp_dms], dms, maxch)
+ call strcat (Memc[temp_units], units, maxch)
+ }
+
+ # Minutes.
+ if (precision == MINUTE || (precision > MINUTE && all)) {
+ call strcpy (dms, Memc[temp_dms], maxch)
+ call strcpy (units, Memc[temp_units], maxch)
+ call sprintf (dms, 3, "%02d'")
+ call pargi (m)
+ call strcpy (" ", units, maxch)
+ call strcat (Memc[temp_dms], dms, maxch)
+ call strcat (Memc[temp_units], units, maxch)
+ if (! all)
+ all = (m == 0)
+ }
+
+ # Hours.
+ if (precision == DEGREE || all) {
+ call strcpy (dms, Memc[temp_dms], maxch)
+ call strcpy (units, Memc[temp_units], maxch)
+ if (sec + fraction < accuracy)
+ call strcpy (" 0 ", dms, maxch)
+ else if (arcrad < 0.) {
+ call sprintf (dms, 4, "-%d ")
+ call pargi (h)
+ } else {
+ call sprintf (dms, 4, "+%d ")
+ call pargi (h)
+ }
+ call sprintf(units, 4, "%*wo")
+ call pargi (strlen (dms) - 1)
+ call strcat (Memc[temp_dms], dms, maxch)
+ call strcat (Memc[temp_units], units, maxch)
+ }
+
+ # Release memory.
+ call sfree (sp)
+end
+
+
+# WL_FULL_LABEL_POSTION -- Find the position where the full label should be.
+#
+# Description
+# This routine returns the index to the label that should be printed
+# in its full form, regardless of its value. This is so there is always
+# at least one labelled point with the full information. This point is
+# choosen by examining which label is the closest to the passed point
+# (usually one of the four corners of the display).
+#
+# Returns
+# Index into the labell arrays of the label to be fully printed.
+# If the return index is 0, then there are no labels for the given
+# side.
+
+int procedure wl_full_label_position (wd, labels, nlabels, axis, side,
+ precision)
+
+pointer wd # I: the WCSLAB descriptor
+int labels[nlabels] # I: array of indexes of labels to be printed
+int nlabels # I: the number of labels in labels
+int axis # I: the axis being dealt with
+int side # I: the side being dealt with
+int precision # I: precision of the label
+
+bool all
+double cur_dist, dist
+int i, cur_label, xside, yside
+pointer sp, temp1
+double wl_distanced()
+
+begin
+ # Allocate some working space.
+ call smark (sp)
+ call salloc (temp1, SZ_LINE, TY_CHAR)
+
+ # Initialize.
+ xside = INDEFI
+ yside = INDEFI
+
+ # Determine which corner will have the full label.
+ if (side == TOP || side == BOTTOM) {
+ yside = side
+ if (axis == AXIS1) {
+ if (WL_LABEL_SIDE(wd,RIGHT,AXIS2))
+ xside = RIGHT
+ if (WL_LABEL_SIDE(wd,LEFT,AXIS2))
+ xside = LEFT
+ } else {
+ if (WL_LABEL_SIDE(wd,RIGHT,AXIS1))
+ xside = RIGHT
+ if (WL_LABEL_SIDE(wd,LEFT,AXIS1))
+ xside = LEFT
+ }
+ if (IS_INDEFI (xside))
+ xside = LEFT
+ } else {
+ xside = side
+ if (axis == AXIS1) {
+ if (WL_LABEL_SIDE(wd,TOP,AXIS2))
+ yside = TOP
+ if (WL_LABEL_SIDE(wd,BOTTOM,AXIS2))
+ yside = BOTTOM
+ } else {
+ if (WL_LABEL_SIDE(wd,TOP,AXIS1))
+ yside = TOP
+ if (WL_LABEL_SIDE(wd,BOTTOM,AXIS1))
+ yside = BOTTOM
+ }
+ if (IS_INDEFI (yside))
+ yside = BOTTOM
+ }
+
+ # Find the full label.
+ cur_label = labels[1]
+ cur_dist = wl_distanced (WL_SCREEN_BOUNDARY(wd,xside),
+ WL_SCREEN_BOUNDARY(wd,yside),
+ WL_LABEL_POSITION(wd,cur_label,AXIS1),
+ WL_LABEL_POSITION(wd,cur_label,AXIS2))
+
+ # Now go through the rest of the labels to find a closer label.
+ for (i = 2; i <= nlabels; i = i + 1) {
+
+ # Check to see if the label would be written in full anyways.
+ all = false
+ if (WL_SYSTEM_TYPE(wd) == RA_DEC) {
+ if (WL_LABEL_AXIS(wd, labels[i]) == LONGITUDE)
+ call wl_hms (WL_LABEL_VALUE(wd, labels[i]),
+ Memc[temp1], Memc[temp1], SZ_LINE, precision, all)
+ else
+ call wl_dms (WL_LABEL_VALUE(wd, labels[i]),
+ Memc[temp1], Memc[temp1], SZ_LINE, precision, all)
+ }
+
+ # If so, don't figure out which label should be full, there
+ # will be one someplace.
+ if (all) {
+ cur_label = INDEFI
+ break
+ }
+
+ dist = wl_distanced (WL_SCREEN_BOUNDARY(wd,xside),
+ WL_SCREEN_BOUNDARY(wd,yside),
+ WL_LABEL_POSITION(wd,labels[i],AXIS1),
+ WL_LABEL_POSITION(wd,labels[i],AXIS2))
+ if (dist < cur_dist) {
+ cur_dist = dist
+ cur_label = labels[i]
+ }
+ }
+
+ # Release memory.
+ call sfree (sp)
+
+ # Return the label index.
+ return (cur_label)
+end
+
+
+# WL_WRITE_LABEL - Write the label in the format specified by the WCS type.
+
+procedure wl_write_label (wd, value, side, x, y, angle, axis, precision,
+ do_full, offset)
+
+pointer wd # I: the WCSLAB descriptor
+double value # I: the value to use as the label
+int side # I: the side the label is going on
+real x, y # I: position of the label in NDC coordinates
+double angle # I: the angle the text should be written at
+int axis # I: which axis is being labelled
+int precision # I: level of precision for labels
+bool do_full # I: true if the full label should be printed
+real offset # I/O: offset for titles in NDC units
+
+int tside
+pointer sp, label, label_format, units, units_format
+real char_height, char_width, in_off_x, in_off_y, length
+real lx, ly, new_offset, rx, ry, text_angle
+real unit_off_x, unit_off_y, ux, uy
+
+bool fp_equalr()
+double wl_string_angle()
+int wl_opposite_side(), strlen()
+real ggetr(), gstatr()
+
+begin
+ # Get some memory.
+ call smark (sp)
+ call salloc (label, SZ_LINE, TY_CHAR)
+ call salloc (units, SZ_LINE, TY_CHAR)
+ call salloc (label_format, SZ_LINE, TY_CHAR)
+ call salloc (units_format, SZ_LINE, TY_CHAR)
+
+ # Get character size. This info is used to move the character string
+ # by the appropriate amounts.
+
+ char_height = ggetr (WL_GP(wd), "ch") * gstatr (WL_GP(wd), G_TXSIZE)
+ char_width = ggetr (WL_GP(wd), "cw") * gstatr (WL_GP(wd), G_TXSIZE)
+
+ # Determine the "corrected" angle to write text in.
+ text_angle = wl_string_angle (angle, WL_LABOUT(wd))
+
+ # Determine the units offset.
+ call wl_rotate (0., char_height / 2., 1, text_angle - 90., unit_off_x,
+ unit_off_y)
+
+ # If the labels are to appear inside the graph and the major grid lines
+ # have been drawn, then determine the necessary offset to get the label
+ # off the line.
+
+ if ((WL_LABOUT(wd) == NO) && (WL_MAJ_GRIDON(wd) == YES))
+ call wl_rotate (0., 0.75 * char_height, 1, text_angle - 90.,
+ in_off_x, in_off_y)
+ else {
+ in_off_x = 0.
+ in_off_y = 0.
+ }
+
+ # Decode the coordinate into a text string.
+ switch (WL_SYSTEM_TYPE(wd)) {
+ case RA_DEC:
+ if (axis == LONGITUDE)
+ call wl_hms (value, Memc[label], Memc[units], SZ_LINE,
+ precision, do_full)
+ else
+ call wl_dms (value, Memc[label], Memc[units], SZ_LINE,
+ precision, do_full)
+ default:
+ call sprintf (Memc[label], SZ_LINE, "%.2g")
+ call pargd (value)
+ }
+
+ # Set the text justification.
+ call sprintf (Memc[label_format], SZ_LINE, "h=c;v=c;u=%f")
+ call pargr (text_angle)
+ call sprintf (Memc[units_format], SZ_LINE, "h=c;v=c;u=%f")
+ call pargr (text_angle)
+
+ # Determine offset needed to rotate text about the point of placement.
+ # NOTE: The STDGRAPH kernel messes up rotate text placement. Try to
+ # accomodate with extra offset.
+
+ length = .5 * char_width * (2 + strlen (Memc[label]))
+ call wl_rotate (length, 0., 1, text_angle - 90., rx, ry)
+ rx = abs (rx)
+ ry = abs (ry)
+
+ # If labels are to appear inside the graph, then justification should
+ # appear as if it were done for the opposite side.
+ if (WL_LABOUT(wd) == YES)
+ tside = side
+ else
+ tside = wl_opposite_side (side)
+
+ # Now add the offsets appropriately.
+ switch (tside) {
+ case TOP:
+ ly = y + ry + in_off_y + unit_off_y
+ if (fp_equalr (text_angle, 90.)) {
+ lx = x
+ ly = ly + unit_off_y
+ } else if (text_angle < 90.)
+ lx = x - rx
+ else
+ lx = x + rx
+ lx = lx + in_off_x
+ new_offset = ry + ry
+
+ case BOTTOM:
+ ly = y - ry - in_off_y - unit_off_y
+ if (fp_equalr (text_angle, 90.)) {
+ lx = x
+ ly = ly - unit_off_y
+ } else if (text_angle < 90.)
+ lx = x + rx
+ else
+ lx = x - rx
+ lx = lx - in_off_x
+ new_offset = ry + ry
+
+ case LEFT:
+ lx = x - rx - abs (unit_off_x)
+ if (text_angle < 90.) {
+ ly = y + ry - in_off_y
+ lx = lx - in_off_x
+ } else {
+ ly = y - ry + in_off_y
+ lx = lx + in_off_x
+ }
+ new_offset = rx + rx + abs (unit_off_x)
+
+ case RIGHT:
+ lx = x + rx + abs (unit_off_x)
+ if (text_angle < 90.) {
+ ly = y - ry + in_off_y
+ lx = lx + in_off_x
+ } else {
+ ly = y + ry - in_off_y
+ lx = lx - in_off_x
+ }
+ new_offset = rx + rx + abs (unit_off_x)
+ }
+
+ lx = lx - (unit_off_x / 2.)
+ ly = ly - (unit_off_y / 2.)
+ ux = lx + unit_off_x
+ uy = ly + unit_off_y
+
+ # Print the label.
+ call gtext (WL_GP(wd), lx, ly, Memc[label], Memc[label_format])
+
+ # Print the units (if appropriate).
+ if (WL_SYSTEM_TYPE(wd) == RA_DEC)
+ call gtext (WL_GP(wd), ux, uy, Memc[units], Memc[units_format])
+
+ # Determine new maximum string size.
+ if ((WL_LABOUT(wd) == YES) && (abs (offset) < new_offset))
+ if (side == LEFT || side == BOTTOM)
+ offset = -new_offset
+ else
+ offset = new_offset
+
+ # Release memory.
+ call sfree (sp)
+end
+
+
+# WL_STRING_ANGLE -- Produce the angle that a label string should be written to.
+#
+# Description
+# Fixes the input angle so that the output angle is in the range 0 to 180.
+#
+# Returns
+# the angle that the label should be written as.
+
+double procedure wl_string_angle (angle, right_to_up)
+
+double angle # I: the input angle in degrees
+int right_to_up # I: true if angle near horizontal/vertical are fixed
+
+double output_angle
+
+begin
+ # Try to ensure that the angle is "upright", i.e. the string will not
+ # be printed upside-down.
+
+ output_angle = angle
+ if (output_angle > QUARTER_CIRCLE)
+ output_angle = output_angle - HALF_CIRCLE
+ if (output_angle < -QUARTER_CIRCLE)
+ output_angle = output_angle + HALF_CIRCLE
+
+ # If the angle is close to parallel with one of the axis, then just
+ # print it normally.
+
+ if ((right_to_up == YES) && ((mod (abs (output_angle),
+ QUARTER_CIRCLE) < MIN_ANGLE) || (QUARTER_CIRCLE -
+ mod (abs (output_angle), QUARTER_CIRCLE) < MIN_ANGLE)))
+ output_angle = 0.
+
+ # Return the angle modified for the idiocincracy of GIO text angle
+ # specification.
+
+ return (output_angle + QUARTER_CIRCLE)
+end
+
+
+# WL_ANGLE -- Return the average angle of the labels in the list.
+#
+# Returns
+# Average angle
+#
+# Description
+# So that labels on a side are uniform (in some sense), the average angle
+# of all the labels is taken and is defined as the angle that all the labels
+# will be printed at.
+
+double procedure wl_angle (wd, labels, nlabels)
+
+pointer wd # I: the WCSLAB descriptor
+int labels[nlabels] # I: the indexes of the labels to be printed out
+int nlabels # I: the number of indexes in the list
+
+double total, average
+int i
+
+begin
+ total = 0.0
+ for (i = 1; i <= nlabels; i = i + 1)
+ total = total + WL_LABEL_ANGLE(wd,labels[i])
+ average = real (total / nlabels)
+
+ return (average)
+end
diff --git a/pkg/utilities/nttools/stxtools/wcslab/wllabel.x.ori b/pkg/utilities/nttools/stxtools/wcslab/wllabel.x.ori
new file mode 100644
index 00000000..33e86878
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/wcslab/wllabel.x.ori
@@ -0,0 +1,1077 @@
+include <gset.h>
+include <math.h>
+include "wcslab.h"
+include "wcs_desc.h"
+
+
+# Define the offset array.
+define OFFSET Memr[$1+$2-1]
+
+# WL_LABEL -- Place the labels on the grids.
+#
+# Description
+# Format and write the labels for the grid/tick marks. Much of this
+# is wading through conditions to decide whether a label should be
+# written or not.
+
+procedure wl_label (wd)
+
+pointer wd # I: the WCSLAB descriptor
+
+bool no_side_axis1, no_side_axis2
+int i, axis1_side, axis2_side
+pointer sp, offset_ptr
+real offset
+
+begin
+ # Get some memory.
+ call smark (sp)
+ call salloc (offset_ptr, N_SIDES, TY_REAL)
+ do i = 1, N_SIDES
+ OFFSET(offset_ptr,i) = 0.
+
+ # Decide whether any sides were specified for either axis.
+ no_side_axis1 = true
+ no_side_axis2 = true
+ do i = 1, N_SIDES {
+ if (WL_LABEL_SIDE(wd,i,AXIS1))
+ no_side_axis1 = false
+ if (WL_LABEL_SIDE(wd,i,AXIS2))
+ no_side_axis2 = false
+ }
+
+ # If polar, then label the axis 2's next to their circles on the
+ # graph and allow the Axis 1s to be labeled on all sides of the graph.
+
+ if (WL_GRAPH_TYPE(wd) == POLAR) {
+
+ call wl_polar_label (wd)
+
+ if (no_side_axis1) {
+ do i = 1, N_SIDES {
+ WL_LABEL_SIDE(wd,i,AXIS1) = true
+ }
+ if (IS_INDEFI (WL_AXIS_TITLE_SIDE(WD,AXIS1)))
+ WL_AXIS_TITLE_SIDE(WD,AXIS1) = BOTTOM
+ }
+
+ # If we are near-polar, label the Axis 2 as if polar, and label
+ # Axis1 on all sides except the side closest to the pole.
+
+ } else if (WL_GRAPH_TYPE(wd) == NEAR_POLAR) {
+
+ if (no_side_axis1) {
+ WL_LABEL_SIDE(wd,WL_BAD_LABEL_SIDE(wd),AXIS1) = true
+ if (IS_INDEFI (WL_AXIS_TITLE_SIDE(wd,AXIS1)))
+ WL_AXIS_TITLE_SIDE(wd,AXIS1) = WL_BAD_LABEL_SIDE(wd)
+ }
+
+ if (no_side_axis2) {
+ WL_LABEL_SIDE(wd,WL_POLAR_LABEL_DIRECTION(wd),AXIS2) = true
+ if (IS_INDEFI (WL_AXIS_TITLE_SIDE(wd,AXIS2)))
+ WL_AXIS_TITLE_SIDE(wd,AXIS2) = WL_POLAR_LABEL_DIRECTION(wd)
+ }
+
+ # Final case- adjacent sides should be labelled.
+
+ } else {
+
+ # Determine the best sides for labelling.
+ if (INVERT (WL_ROTA(wd))) {
+ axis1_side = LEFT
+ axis2_side = BOTTOM
+ } else {
+ axis1_side = BOTTOM
+ axis2_side = LEFT
+ }
+
+ # If no sides were specified, use the calculated ones above.
+ if (no_side_axis1)
+ WL_LABEL_SIDE(wd,axis1_side,AXIS1) = true
+ if (no_side_axis2)
+ WL_LABEL_SIDE(wd,axis2_side,AXIS2) = true
+ }
+
+ # Now draw the labels for axis 1.
+ do i = 1, N_SIDES {
+
+ if (WL_LABEL_SIDE(wd,i,AXIS1)) {
+ call wl_lab_edges (wd, AXIS1, i, offset)
+ if (IS_INDEFI (WL_AXIS_TITLE_SIDE(WD,AXIS1)))
+ WL_AXIS_TITLE_SIDE(WD,AXIS1) = i
+ } else
+ offset = 0.
+
+ # Modify the bounding box for the new viewport.
+ if (abs (offset) > abs (OFFSET(offset_ptr,i)))
+ OFFSET(offset_ptr,i) = offset
+ }
+
+ # Draw the labels for axis 2.
+ if (WL_GRAPH_TYPE(wd) != POLAR)
+ do i = 1, N_SIDES {
+
+ if (WL_LABEL_SIDE(wd,i,AXIS2)) {
+ call wl_lab_edges (wd, AXIS2, i, offset)
+ if (IS_INDEFI (WL_AXIS_TITLE_SIDE(wd,AXIS2)))
+ WL_AXIS_TITLE_SIDE(wd,AXIS2) = i
+ } else
+ offset = 0.
+
+ # Modify the bounding box for the new viewport.
+ if (abs (offset) > abs (OFFSET(offset_ptr,i)))
+ OFFSET(offset_ptr,i) = offset
+ }
+
+ # Set the bounding box.
+ do i = 1, N_SIDES
+ WL_NEW_VIEW(wd,i) = WL_NEW_VIEW(wd,i) + OFFSET(offset_ptr,i)
+
+ # Now write the graph title.
+ call wl_title (WL_GP(wd), WL_AXIS_TITLE(wd,AXIS1),
+ WL_AXIS_TITLE_SIDE(wd,AXIS1), WL_AXIS_TITLE_SIZE(wd),
+ WL_NEW_VIEW(wd,1))
+ if (WL_GRAPH_TYPE(wd) != POLAR)
+ call wl_title (WL_GP(wd), WL_AXIS_TITLE(wd,AXIS2),
+ WL_AXIS_TITLE_SIDE(wd,AXIS2), WL_AXIS_TITLE_SIZE(WD),
+ WL_NEW_VIEW(wd,1))
+ if (! IS_INDEFI (WL_TITLE_SIDE(wd)))
+ call wl_title (WL_GP(wd), WL_TITLE(wd), WL_TITLE_SIDE(wd),
+ WL_TITLE_SIZE(wd), WL_NEW_VIEW(wd,1))
+
+ # Release memory.
+ call sfree (sp)
+end
+
+
+# Define what is in the screen.
+
+define IN (($1>WL_SCREEN_BOUNDARY(wd,LEFT))&&($1<WL_SCREEN_BOUNDARY(wd,RIGHT))&&($2>WL_SCREEN_BOUNDARY(wd,BOTTOM))&&($2<WL_SCREEN_BOUNDARY(wd,TOP)))
+
+# WL_POLAR_LABEL -- Place Latitude labels next to Latitude circles.
+#
+# Description
+# Since Lines of constant Latitude on a polar graph are usually circles
+# around the pole, the lines may never cross edges. Instead, the labels
+# are placed next to circles. The grid-drawing routines should setup
+# the label position array such that each line has only one label point.
+
+procedure wl_polar_label (wd)
+
+pointer wd # I: the WCSLAB descriptor
+
+int i, prec
+pointer sp, label, units, label_format, units_format
+real char_height, char_width, ndc_textx, ndc_texty, old_text_size
+real textx, texty
+int wl_precision()
+real gstatr(), ggetr()
+
+begin
+ # Get some memory.
+ call smark (sp)
+ call salloc (label, SZ_LINE, TY_CHAR)
+ call salloc (units, SZ_LINE, TY_CHAR)
+ call salloc (label_format, SZ_LINE, TY_CHAR)
+ call salloc (units_format, SZ_LINE, TY_CHAR)
+
+ # Get the character height and width. This is used to ensure that we
+ # have moved the label strings off the border.
+
+ char_height = ggetr (WL_GP(wd), "ch") * gstatr (WL_GP(wd), G_TXSIZE) /
+ 2.
+ char_width = ggetr (WL_GP(wd), "cw") * gstatr (WL_GP(wd), G_TXSIZE) /
+ 2.
+
+ # Get the text size and cut it in half for on the plot labelling.
+ old_text_size = gstatr (WL_GP(wd), G_TXSIZE)
+ call gsetr (WL_GP(wd), G_TXSIZE, old_text_size)
+ call gsetr (WL_GP(wd), G_TXSIZE, old_text_size * 0.80)
+
+ # Determine the precision of the output.
+ prec = wl_precision (wd, AXIS2)
+
+ # Place the labels.
+ for (i = 1; i <= WL_N_LABELS(wd); i = i + 1)
+ if (WL_LABEL_AXIS(wd,i) == AXIS2) {
+
+ # Decode the coordinate into a text string.
+ call wl_dms (WL_LABEL_VALUE(wd,i), Memc[label], Memc[units],
+ SZ_LINE, prec, true)
+
+ # Convert text position from "unknown" coordinates to NDC.
+ call gctran (WL_GP(wd), real (WL_LABEL_POSITION(wd,i,AXIS1)),
+ real (WL_LABEL_POSITION(wd,i,AXIS2)), ndc_textx, ndc_texty,
+ WL_PLOT_WCS(wd), WL_NDC_WCS(wd))
+
+ # Determine the text justification.
+ switch (WL_POLAR_LABEL_DIRECTION(wd)) {
+ case BOTTOM:
+ call strcpy ("h=c;v=t", Memc[label_format], SZ_LINE)
+ call strcpy ("h=c;v=c", Memc[units_format], SZ_LINE)
+ ndc_texty = ndc_texty - char_height
+ case TOP:
+ call strcpy ("h=c;v=c", Memc[label_format], SZ_LINE)
+ call strcpy ("h=c;v=b", Memc[units_format], SZ_LINE)
+ ndc_texty = ndc_texty + char_height
+ case LEFT:
+ call strcpy ("h=r;v=c", Memc[label_format], SZ_LINE)
+ call strcpy ("h=r;v=b", Memc[units_format], SZ_LINE)
+ ndc_textx = ndc_textx - char_width
+ case RIGHT:
+ call strcpy ("h=l;v=c", Memc[label_format], SZ_LINE)
+ call strcpy ("h=l;v=b", Memc[units_format], SZ_LINE)
+ ndc_textx = ndc_textx + char_width
+ }
+
+ # Convert the text position from NDC back to the "unknown"
+ # system.
+ call gctran (WL_GP(wd), ndc_textx, ndc_texty, textx, texty,
+ WL_NDC_WCS(wd), WL_PLOT_WCS(wd))
+
+ # Print the label.
+ if (IN (textx, texty)) {
+ call gtext (WL_GP(wd), textx, texty, Memc[label],
+ Memc[label_format])
+ call gtext (WL_GP(wd), textx, texty, Memc[units],
+ Memc[units_format])
+ }
+
+ }
+
+ # Set the text size back.
+ call gsetr (WL_GP(wd), G_TXSIZE, old_text_size)
+
+ # Release memory.
+ call sfree (sp)
+
+end
+
+
+# Memory management for labels
+
+define LABEL_LIST Memi[labels+$1-1]
+
+# WL_LAB_EDGES -- Place labels along the edges of the window.
+#
+# Description
+# Place labels on the specified side of the graph.
+
+procedure wl_lab_edges (wd, axis, side, offset)
+
+pointer wd # I: the WCSLAB descriptor
+int axis # I: the type of axis being labeled
+int side # I: the side to place the labels
+real offset # O: offset in NDC units for titles
+
+bool do_full
+double angle, tangle
+int i, full_label, nlabels, old_wcs, prec
+pointer sp, labels
+real ndc_textx, ndc_texty, old_text_size, textx, texty
+
+int wl_full_label_position(), wl_find_side()
+double wl_string_angle(), wl_angle()
+int gstati(), wl_precision()
+real gstatr()
+
+begin
+ call smark (sp)
+
+ # All label placement is done in NDC coordinates.
+ old_wcs = gstati (WL_GP(wd), G_WCS)
+ call gseti (WL_GP(wd), G_WCS, WL_NDC_WCS(wd))
+
+ # Set text labelling size.
+ old_text_size = gstatr (WL_GP(wd), G_TXSIZE)
+ call gsetr (WL_GP(wd), G_TXSIZE, WL_LABEL_SIZE(wd))
+
+ # Get the precision of the axis interval.
+ prec = wl_precision (wd, axis)
+
+ # Initialize string size.
+ offset = 0.
+
+ # Build a list of possible labels for this side. The conditions are
+ # that the label should be for the current axis and that it lies on
+ # the current side.
+
+ call salloc (labels, WL_N_LABELS(wd), TY_INT)
+ nlabels = 0
+ for (i = 1; i <= WL_N_LABELS(wd); i = i + 1)
+ if (WL_LABEL_AXIS(wd,i) == axis &&
+ wl_find_side (WL_LABEL_POSITION(wd,i,AXIS1),
+ WL_LABEL_POSITION(wd,i,AXIS2),
+ WL_SCREEN_BOUNDARY(wd,1)) == side) {
+ nlabels = nlabels + 1
+ LABEL_LIST(nlabels) = i
+ }
+
+ # If no labels found, then just forget it. If labels found, well
+ # write them out.
+
+ if (nlabels != 0) {
+
+ # Determine which label should be written out in full.
+ full_label = wl_full_label_position (wd, Memi[labels], nlabels,
+ axis, side, prec)
+
+ # Determine the angle that all the labels will be written at.
+ if ((WL_LABOUT(wd) == NO) && (WL_GRAPH_TYPE(wd) != NORMAL) &&
+ (WL_LABEL_ROTATE(wd) == YES))
+ angle = INDEFR
+ else if ((WL_GRAPH_TYPE(wd) == NORMAL) && ((WL_LABEL_ROTATE(wd) ==
+ YES) || ((WL_LABOUT(wd) == NO) && (WL_MAJ_GRIDON(wd) == YES))))
+ angle = wl_angle (wd, Memi[labels], nlabels)
+ else
+ angle = 0.0
+
+ # Place the labels.
+ for (i = 1; i <= nlabels; i = i + 1) {
+
+ # Save some pertinent information.
+ textx = real (WL_LABEL_POSITION(wd,LABEL_LIST(i),AXIS1))
+ texty = real (WL_LABEL_POSITION(wd,LABEL_LIST(i),AXIS2))
+ do_full = ((LABEL_LIST(i) == full_label) ||
+ (WL_ALWAYS_FULL_LABEL(wd) == YES))
+
+ # Transform the "unknown" coordinate system to a known
+ # coordinate system, NDC, for text placement.
+ call gctran (WL_GP(wd), textx, texty, ndc_textx, ndc_texty,
+ old_wcs, WL_NDC_WCS(wd))
+
+ # If angle is undefined, determine the angle for each label.
+ if (IS_INDEFR(angle))
+ tangle = wl_string_angle (WL_LABEL_ANGLE(wd,
+ LABEL_LIST(i)), WL_LABOUT(wd))
+ else
+ tangle = angle
+
+ # Format and write the label.
+ call wl_write_label (wd, WL_LABEL_VALUE(wd,LABEL_LIST(i)),
+ side, ndc_textx, ndc_texty, tangle, axis, prec, do_full,
+ offset)
+ }
+ }
+
+ # Reset the graphics WCS.
+ call gsetr (WL_GP(wd), G_TXSIZE, old_text_size)
+ call gseti (WL_GP(wd), G_WCS, old_wcs)
+
+ call sfree (sp)
+end
+
+
+# WL_TITLE - Write the title of the graph.
+
+procedure wl_title (gp, title, side, size, viewport)
+
+pointer gp # I: the graphics descriptor
+char title[ARB] # I: the title to write
+int side # I: which side the title will go
+real size # I: the character size to write the title
+real viewport[N_SIDES] # I: the viewport in NDC to keep the title out of
+
+int old_wcs
+real char_height, char_width, left, right, top, bottom, old_rotation
+real old_text_size, x, y
+int gstati(), strlen()
+real ggetr(), gstatr()
+
+begin
+ # Make sure there is a title to write. If not, then punt.
+ if (strlen (title) <= 0)
+ return
+
+ # Get/Set pertinent graphics info.
+ call ggview (gp, left, right, bottom, top)
+
+ old_text_size = gstatr (gp, G_TXSIZE)
+ call gsetr (gp, G_TXSIZE, size)
+ old_rotation = gstatr (gp, G_TXUP)
+
+ char_height = ggetr (gp, "ch") * size
+ char_width = ggetr (gp, "cw") * size
+
+ old_wcs = gstati (gp, G_WCS)
+ call gseti (gp, G_WCS, NDC_WCS)
+
+ # Depending on side, set text position and rotation.
+ switch (side) {
+ case TOP:
+ call gsetr (gp, G_TXUP, 90.)
+ x = (right + left) / 2.
+ y = viewport[TOP] + (2 * char_height)
+ viewport[TOP] = y + (char_height / 2.)
+ case BOTTOM:
+ call gsetr (gp, G_TXUP, 90.)
+ x = (right + left) / 2.
+ y = viewport[BOTTOM] - (2 * char_height)
+ viewport[BOTTOM] = y - (char_height / 2.)
+ case RIGHT:
+ call gsetr (gp, G_TXUP, 180.)
+ x = viewport[RIGHT] + (2 * char_width)
+ y = (top + bottom) / 2.
+ viewport[RIGHT] = x + (char_width / 2.)
+ case LEFT:
+ call gsetr (gp, G_TXUP, 180.)
+ x = viewport[LEFT] - (2 * char_width)
+ y = (top + bottom) / 2.
+ viewport[LEFT] = x - (char_width / 2.)
+ }
+
+ # Write the puppy out.
+ call gtext (gp, x, y, title, "h=c;v=c")
+
+ # Set the graphics state back.
+ call gseti (gp, G_WCS, old_wcs)
+ call gsetr (gp, G_TXSIZE, old_text_size)
+ call gsetr (gp, G_TXUP, old_rotation)
+end
+
+
+# WL_PRECISION -- Determine the precision of the interval.
+
+int procedure wl_precision (wd, axis)
+
+pointer wd # I: the WCSLAB descriptor
+int axis # I: which axis is being examined ?
+
+int prec
+
+begin
+ # Handle the sky coordinates.
+ if (WL_SYSTEM_TYPE(wd) == RA_DEC)
+
+ if (axis == AXIS1) {
+ if (WL_MAJOR_INTERVAL(wd,AXIS1) >= STTODEG (3600.0D0))
+ prec = HOUR
+ else if (WL_MAJOR_INTERVAL(wd,AXIS1) >= STTODEG (60.0D0))
+ prec = MINUTE
+ else if (WL_MAJOR_INTERVAL(wd,AXIS1) >= STTODEG (1.0D0))
+ prec = SECOND
+ else if (WL_MAJOR_INTERVAL(wd,AXIS1) >= STTODEG (.01D0))
+ prec = SUBSEC_LOW
+ else
+ prec = SUBSEC_HIGH
+ } else {
+ if (WL_MAJOR_INTERVAL(wd,AXIS2) >= SATODEG (3600.0D0))
+ prec = DEGREE
+ else if (WL_MAJOR_INTERVAL(wd,AXIS2) >= SATODEG (60.0D0))
+ prec = MINUTE
+ else if (WL_MAJOR_INTERVAL(wd,AXIS2) >= SATODEG (1.0D0))
+ prec = SECOND
+ else if (WL_MAJOR_INTERVAL(wd,AXIS2) >= SATODEG (.01D0))
+ prec = SUBSEC_LOW
+ else
+ prec = SUBSEC_HIGH
+ }
+
+ # Handle other coordinate types.
+ else
+ prec = INDEFI
+
+ return (prec)
+
+end
+
+
+# Define some value constraints.
+
+define LOW_ACCURACY .01
+define HIGH_ACCURACY .0001
+
+# WL_HMS -- Convert value to number in hours, minutes, and seconds.
+
+procedure wl_hms (rarad, hms, units, maxch, precision, all)
+
+double rarad # I: the value to format into a string (degrees)
+char hms[ARB] # O: string containing formatted value
+char units[ARB] # O: string containing formatted units
+int maxch # I: the maximum number of characters allowed
+int precision # I: how precise the output should be
+bool all # I: true if all relevent fields should be formatted
+
+double accuracy, fraction
+int sec, h, m, s
+pointer sp, temp_hms, temp_units
+
+begin
+ # Get some memory.
+ call smark (sp)
+ call salloc (temp_hms, maxch, TY_CHAR)
+ call salloc (temp_units, maxch, TY_CHAR)
+
+ units[1] = EOS
+ hms[1] = EOS
+
+ # Define how close to zero is needed.
+ accuracy = LOW_ACCURACY
+ if (precision == SUBSEC_HIGH)
+ accuracy = HIGH_ACCURACY
+
+ # Seconds of time.
+ fraction = double (abs(DEGTOST (rarad)))
+ if (precision == SUBSEC_LOW || precision == SUBSEC_HIGH) {
+ sec = int (fraction)
+ fraction = fraction - double (sec)
+ } else {
+ sec = int (fraction + 0.5)
+ fraction = 0.
+ }
+
+ # Range: 0 to 24 hours.
+ if (sec < 0)
+ sec = sec + STPERDAY
+ else if (sec >= STPERDAY)
+ sec = mod (sec, STPERDAY)
+
+ # Separater fields.
+ s = mod (sec, 60)
+ m = mod (sec / 60, 60)
+ h = sec / 3600
+
+ # Format fields.
+
+ # Subseconds.
+ if (precision == SUBSEC_LOW || precision == SUBSEC_HIGH) {
+ fraction = s + fraction
+ if (precision == SUBSEC_LOW) {
+ call sprintf (hms, 6, "%05.2f")
+ call pargd (fraction)
+ call strcpy (" s ", units, maxch)
+ } else {
+ call sprintf (hms, 8, "%07.4f")
+ call pargd (fraction)
+ call strcpy (" s ", units, maxch)
+ }
+ if (!all)
+ all = (fraction < accuracy)
+
+ # Seconds
+ } else if (precision == SECOND) {
+
+ # NOTE: The all is not part of the if statement because if
+ # SUBSEC's have been printed, then seconds have already been
+ # dealt with. If SUBSEC's have not been dealt with, then this
+ # is the first field to be checked anyways.
+
+ call sprintf (hms, 3, "%02d ")
+ call pargi (s)
+ call strcpy (" s", units, maxch)
+ if (! all)
+ all = (s == 0)
+ }
+
+ # Minutes.
+ if (precision == MINUTE || (precision > MINUTE && all)) {
+ if (all) {
+ call strcpy (hms, Memc[temp_hms], maxch)
+ call strcpy (units, Memc[temp_units], maxch)
+ }
+ call sprintf (hms, 3, "%02d ")
+ call pargi (m)
+ call strcpy (" m", units, maxch)
+ if (all) {
+ call strcat (Memc[temp_hms], hms, maxch)
+ call strcat (Memc[temp_units], units, maxch)
+ } else
+ all = (m == 0)
+ }
+
+ # Non-zero hours.
+ if (precision == HOUR || all) {
+ if (all) {
+ call strcpy (hms, Memc[temp_hms], maxch)
+ call strcpy (units, Memc[temp_units], maxch)
+ }
+ call sprintf (hms, 3, "%2.2d ")
+ call pargi (h)
+ call strcpy(" h", units, maxch)
+ if (all) {
+ call strcat (Memc[temp_hms], hms, maxch)
+ call strcat (Memc[temp_units], units, maxch)
+ }
+ }
+
+ # Release memory
+ call sfree (sp)
+end
+
+
+# WL_DMS - Convert value to number in degrees, minutes, and seconds.
+
+procedure wl_dms (arcrad, dms, units, maxch, precision, all)
+
+double arcrad # I: the value to format into a string (degrees)
+char dms[ARB] # O: string containing formatted value
+char units[ARB] # O: string containing formatted units
+int maxch # I: the maximum number of characters allowed
+int precision # I: how precise the output should be ?
+bool all # I: true if all relavent fields should be formatted
+
+double accuracy, fraction
+int sec, h, m, s
+pointer sp, temp_dms, temp_units
+int strlen()
+
+begin
+ # Get some memory.
+ call smark (sp)
+ call salloc (temp_dms, maxch, TY_CHAR)
+ call salloc (temp_units, maxch, TY_CHAR)
+
+ units[1] = EOS
+ dms[1] = EOS
+
+ # Define how close to zero is needed.
+ accuracy = LOW_ACCURACY
+ if (precision == SUBSEC_HIGH)
+ accuracy = HIGH_ACCURACY
+
+ # Seconds of time.
+ fraction = double (abs (DEGTOSA (arcrad)))
+ if (precision == SUBSEC_LOW || precision == SUBSEC_HIGH) {
+ sec = int (fraction)
+ fraction = fraction - double (sec)
+ } else {
+ sec = nint (fraction)
+ fraction = 0.
+ }
+
+ # Separater fields.
+ s = mod (abs(sec), 60)
+ m = mod (abs(sec) / 60, 60)
+ h = abs(sec) / 3600
+
+ # Format fields
+ #
+ # Subseconds.
+ if (precision == SUBSEC_LOW || precision == SUBSEC_HIGH) {
+
+ fraction = s + fraction
+ call strcpy (dms, Memc[temp_dms], maxch)
+ call strcpy (units, Memc[temp_units], maxch)
+ if (precision == SUBSEC_LOW) {
+ call sprintf (dms, 6, "%05.2f\"")
+ call pargd (fraction)
+ call strcpy (" ", units, maxch)
+ } else {
+ call sprintf (dms, 8, "%07.4f\"")
+ call pargd (fraction)
+ call strcpy (" ", units, maxch)
+ }
+ if (! all)
+ all = (fraction < accuracy)
+ call strcat (Memc[temp_dms], dms, maxch)
+ call strcat (Memc[temp_units], units, maxch)
+
+ # Seconds
+ } else if (precision == SECOND) {
+
+ # NOTE: The all is not part of the if statement because if
+ # SUBSEC's have been printed, then seconds have already been
+ # dealt with. If SUBSEC's have not been dealt with, then this
+ # is the first field to be checked anyways.
+
+ call strcpy (dms, Memc[temp_dms], maxch)
+ call strcpy (units, Memc[temp_units], maxch)
+ call sprintf (dms, 3, "%02d\"")
+ call pargi (s)
+ call strcpy (" ", units, maxch)
+ if (! all)
+ all = (s == 0)
+ call strcat (Memc[temp_dms], dms, maxch)
+ call strcat (Memc[temp_units], units, maxch)
+ }
+
+ # Minutes.
+ if (precision == MINUTE || (precision > MINUTE && all)) {
+ call strcpy (dms, Memc[temp_dms], maxch)
+ call strcpy (units, Memc[temp_units], maxch)
+ call sprintf (dms, 3, "%02d'")
+ call pargi (m)
+ call strcpy (" ", units, maxch)
+ call strcat (Memc[temp_dms], dms, maxch)
+ call strcat (Memc[temp_units], units, maxch)
+ if (! all)
+ all = (m == 0)
+ }
+
+ # Hours.
+ if (precision == DEGREE || all) {
+ call strcpy (dms, Memc[temp_dms], maxch)
+ call strcpy (units, Memc[temp_units], maxch)
+ if (sec + fraction < accuracy)
+ call strcpy (" 0 ", dms, maxch)
+ else if (arcrad < 0.) {
+ call sprintf (dms, 4, "-%d ")
+ call pargi (h)
+ } else {
+ call sprintf (dms, 4, "+%d ")
+ call pargi (h)
+ }
+ call sprintf(units, 4, "%*wo")
+ call pargi (strlen (dms) - 1)
+ call strcat (Memc[temp_dms], dms, maxch)
+ call strcat (Memc[temp_units], units, maxch)
+ }
+
+ # Release memory.
+ call sfree (sp)
+end
+
+
+# WL_FULL_LABEL_POSTION -- Find the position where the full label should be.
+#
+# Description
+# This routine returns the index to the label that should be printed
+# in its full form, regardless of its value. This is so there is always
+# at least one labelled point with the full information. This point is
+# choosen by examining which label is the closest to the passed point
+# (usually one of the four corners of the display).
+#
+# Returns
+# Index into the labell arrays of the label to be fully printed.
+# If the return index is 0, then there are no labels for the given
+# side.
+
+int procedure wl_full_label_position (wd, labels, nlabels, axis, side,
+ precision)
+
+pointer wd # I: the WCSLAB descriptor
+int labels[nlabels] # I: array of indexes of labels to be printed
+int nlabels # I: the number of labels in labels
+int axis # I: the axis being dealt with
+int side # I: the side being dealt with
+int precision # I: precision of the label
+
+bool all
+double cur_dist, dist
+int i, cur_label, xside, yside
+pointer sp, temp1
+double wl_distanced()
+
+begin
+ # Allocate some working space.
+ call smark (sp)
+ call salloc (temp1, SZ_LINE, TY_CHAR)
+
+ # Initialize.
+ xside = INDEFI
+ yside = INDEFI
+
+ # Determine which corner will have the full label.
+ if (side == TOP || side == BOTTOM) {
+ yside = side
+ if (axis == AXIS1) {
+ if (WL_LABEL_SIDE(wd,RIGHT,AXIS2))
+ xside = RIGHT
+ if (WL_LABEL_SIDE(wd,LEFT,AXIS2))
+ xside = LEFT
+ } else {
+ if (WL_LABEL_SIDE(wd,RIGHT,AXIS1))
+ xside = RIGHT
+ if (WL_LABEL_SIDE(wd,LEFT,AXIS1))
+ xside = LEFT
+ }
+ if (IS_INDEFI (xside))
+ xside = LEFT
+ } else {
+ xside = side
+ if (axis == AXIS1) {
+ if (WL_LABEL_SIDE(wd,TOP,AXIS2))
+ yside = TOP
+ if (WL_LABEL_SIDE(wd,BOTTOM,AXIS2))
+ yside = BOTTOM
+ } else {
+ if (WL_LABEL_SIDE(wd,TOP,AXIS1))
+ yside = TOP
+ if (WL_LABEL_SIDE(wd,BOTTOM,AXIS1))
+ yside = BOTTOM
+ }
+ if (IS_INDEFI (yside))
+ yside = BOTTOM
+ }
+
+ # Find the full label.
+ cur_label = labels[1]
+ cur_dist = wl_distanced (WL_SCREEN_BOUNDARY(wd,xside),
+ WL_SCREEN_BOUNDARY(wd,yside),
+ WL_LABEL_POSITION(wd,cur_label,AXIS1),
+ WL_LABEL_POSITION(wd,cur_label,AXIS2))
+
+ # Now go through the rest of the labels to find a closer label.
+ for (i = 2; i <= nlabels; i = i + 1) {
+
+ # Check to see if the label would be written in full anyways.
+ all = false
+ if (WL_SYSTEM_TYPE(wd) == RA_DEC) {
+ if (WL_LABEL_AXIS(wd, labels[i]) == LONGITUDE)
+ call wl_hms (WL_LABEL_VALUE(wd, labels[i]),
+ Memc[temp1], Memc[temp1], SZ_LINE, precision, all)
+ else
+ call wl_dms (WL_LABEL_VALUE(wd, labels[i]),
+ Memc[temp1], Memc[temp1], SZ_LINE, precision, all)
+ }
+
+ # If so, don't figure out which label should be full, there
+ # will be one someplace.
+ if (all) {
+ cur_label = INDEFI
+ break
+ }
+
+ dist = wl_distanced (WL_SCREEN_BOUNDARY(wd,xside),
+ WL_SCREEN_BOUNDARY(wd,yside),
+ WL_LABEL_POSITION(wd,labels[i],AXIS1),
+ WL_LABEL_POSITION(wd,labels[i],AXIS2))
+ if (dist < cur_dist) {
+ cur_dist = dist
+ cur_label = labels[i]
+ }
+ }
+
+ # Release memory.
+ call sfree (sp)
+
+ # Return the label index.
+ return (cur_label)
+end
+
+
+# WL_WRITE_LABEL - Write the label in the format specified by the WCS type.
+
+procedure wl_write_label (wd, value, side, x, y, angle, axis, precision,
+ do_full, offset)
+
+pointer wd # I: the WCSLAB descriptor
+double value # I: the value to use as the label
+int side # I: the side the label is going on
+real x, y # I: position of the label in NDC coordinates
+double angle # I: the angle the text should be written at
+int axis # I: which axis is being labelled
+int precision # I: level of precision for labels
+bool do_full # I: true if the full label should be printed
+real offset # I/O: offset for titles in NDC units
+
+int tside
+pointer sp, label, label_format, units, units_format
+real char_height, char_width, in_off_x, in_off_y, length
+real lx, ly, new_offset, rx, ry, text_angle
+real unit_off_x, unit_off_y, ux, uy
+
+bool fp_equalr()
+double wl_string_angle()
+int wl_opposite_side(), strlen()
+real ggetr(), gstatr()
+
+begin
+ # Get some memory.
+ call smark (sp)
+ call salloc (label, SZ_LINE, TY_CHAR)
+ call salloc (units, SZ_LINE, TY_CHAR)
+ call salloc (label_format, SZ_LINE, TY_CHAR)
+ call salloc (units_format, SZ_LINE, TY_CHAR)
+
+ # Get character size. This info is used to move the character string
+ # by the appropriate amounts.
+
+ char_height = ggetr (WL_GP(wd), "ch") * gstatr (WL_GP(wd), G_TXSIZE)
+ char_width = ggetr (WL_GP(wd), "cw") * gstatr (WL_GP(wd), G_TXSIZE)
+
+ # Determine the "corrected" angle to write text in.
+ text_angle = wl_string_angle (angle, WL_LABOUT(wd))
+
+ # Determine the units offset.
+ call wl_rotate (0., char_height / 2., 1, text_angle - 90., unit_off_x,
+ unit_off_y)
+
+ # If the labels are to appear inside the graph and the major grid lines
+ # have been drawn, then determine the necessary offset to get the label
+ # off the line.
+
+ if ((WL_LABOUT(wd) == NO) && (WL_MAJ_GRIDON(wd) == YES))
+ call wl_rotate (0., 0.75 * char_height, 1, text_angle - 90.,
+ in_off_x, in_off_y)
+ else {
+ in_off_x = 0.
+ in_off_y = 0.
+ }
+
+ # Decode the coordinate into a text string.
+ switch (WL_SYSTEM_TYPE(wd)) {
+ case RA_DEC:
+ if (axis == LONGITUDE)
+ call wl_hms (value, Memc[label], Memc[units], SZ_LINE,
+ precision, do_full)
+ else
+ call wl_dms (value, Memc[label], Memc[units], SZ_LINE,
+ precision, do_full)
+ default:
+ call sprintf (Memc[label], SZ_LINE, "%.2g")
+ call pargd (value)
+ }
+
+ # Set the text justification.
+ call sprintf (Memc[label_format], SZ_LINE, "h=c;v=c;u=%f")
+ call pargr (text_angle)
+ call sprintf (Memc[units_format], SZ_LINE, "h=c;v=c;u=%f")
+ call pargr (text_angle)
+
+ # Determine offset needed to rotate text about the point of placement.
+ # NOTE: The STDGRAPH kernel messes up rotate text placement. Try to
+ # accomodate with extra offset.
+
+ length = .5 * char_width * (2 + strlen (Memc[label]))
+ call wl_rotate (length, 0., 1, text_angle - 90., rx, ry)
+ rx = abs (rx)
+ ry = abs (ry)
+
+ # If labels are to appear inside the graph, then justification should
+ # appear as if it were done for the opposite side.
+ if (WL_LABOUT(wd) == YES)
+ tside = side
+ else
+ tside = wl_opposite_side (side)
+
+ # Now add the offsets appropriately.
+ switch (tside) {
+ case TOP:
+ ly = y + ry + in_off_y + unit_off_y
+ if (fp_equalr (text_angle, 90.)) {
+ lx = x
+ ly = ly + unit_off_y
+ } else if (text_angle < 90.)
+ lx = x - rx
+ else
+ lx = x + rx
+ lx = lx + in_off_x
+ new_offset = ry + ry
+
+ case BOTTOM:
+ ly = y - ry - in_off_y - unit_off_y
+ if (fp_equalr (text_angle, 90.)) {
+ lx = x
+ ly = ly - unit_off_y
+ } else if (text_angle < 90.)
+ lx = x + rx
+ else
+ lx = x - rx
+ lx = lx - in_off_x
+ new_offset = ry + ry
+
+ case LEFT:
+ lx = x - rx - abs (unit_off_x)
+ if (text_angle < 90.) {
+ ly = y + ry - in_off_y
+ lx = lx - in_off_x
+ } else {
+ ly = y - ry + in_off_y
+ lx = lx + in_off_x
+ }
+ new_offset = rx + rx + abs (unit_off_x)
+
+ case RIGHT:
+ lx = x + rx + abs (unit_off_x)
+ if (text_angle < 90.) {
+ ly = y - ry + in_off_y
+ lx = lx + in_off_x
+ } else {
+ ly = y + ry - in_off_y
+ lx = lx - in_off_x
+ }
+ new_offset = rx + rx + abs (unit_off_x)
+ }
+
+ lx = lx - (unit_off_x / 2.)
+ ly = ly - (unit_off_y / 2.)
+ ux = lx + unit_off_x
+ uy = ly + unit_off_y
+
+ # Print the label.
+ call gtext (WL_GP(wd), lx, ly, Memc[label], Memc[label_format])
+
+ # Print the units (if appropriate).
+ if (WL_SYSTEM_TYPE(wd) == RA_DEC)
+ call gtext (WL_GP(wd), ux, uy, Memc[units], Memc[units_format])
+
+ # Determine new maximum string size.
+ if ((WL_LABOUT(wd) == YES) && (abs (offset) < new_offset))
+ if (side == LEFT || side == BOTTOM)
+ offset = -new_offset
+ else
+ offset = new_offset
+
+ # Release memory.
+ call sfree (sp)
+end
+
+
+# WL_STRING_ANGLE -- Produce the angle that a label string should be written to.
+#
+# Description
+# Fixes the input angle so that the output angle is in the range 0 to 180.
+#
+# Returns
+# the angle that the label should be written as.
+
+double procedure wl_string_angle (angle, right_to_up)
+
+double angle # I: the input angle in degrees
+int right_to_up # I: true if angle near horizontal/vertical are fixed
+
+double output_angle
+
+begin
+ # Try to ensure that the angle is "upright", i.e. the string will not
+ # be printed upside-down.
+
+ output_angle = angle
+ if (output_angle > QUARTER_CIRCLE)
+ output_angle = output_angle - HALF_CIRCLE
+ if (output_angle < -QUARTER_CIRCLE)
+ output_angle = output_angle + HALF_CIRCLE
+
+ # If the angle is close to parallel with one of the axis, then just
+ # print it normally.
+
+ if ((right_to_up == YES) && ((mod (abs (output_angle),
+ QUARTER_CIRCLE) < MIN_ANGLE) || (QUARTER_CIRCLE -
+ mod (abs (output_angle), QUARTER_CIRCLE) < MIN_ANGLE)))
+ output_angle = 0.
+
+ # Return the angle modified for the idiocincracy of GIO text angle
+ # specification.
+
+ return (output_angle + QUARTER_CIRCLE)
+end
+
+
+# WL_ANGLE -- Return the average angle of the labels in the list.
+#
+# Returns
+# Average angle
+#
+# Description
+# So that labels on a side are uniform (in some sense), the average angle
+# of all the labels is taken and is defined as the angle that all the labels
+# will be printed at.
+
+double procedure wl_angle (wd, labels, nlabels)
+
+pointer wd # I: the WCSLAB descriptor
+int labels[nlabels] # I: the indexes of the labels to be printed out
+int nlabels # I: the number of indexes in the list
+
+double total, average
+int i
+
+begin
+ total = 0.0
+ for (i = 1; i <= nlabels; i = i + 1)
+ total = total + WL_LABEL_ANGLE(wd,labels[i])
+ average = real (total / nlabels)
+
+ return (average)
+end
diff --git a/pkg/utilities/nttools/stxtools/wcslab/wlsetup.x b/pkg/utilities/nttools/stxtools/wcslab/wlsetup.x
new file mode 100644
index 00000000..c37e24ca
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/wcslab/wlsetup.x
@@ -0,0 +1,1000 @@
+include <gset.h>
+include <mach.h>
+include <math.h>
+include <math/curfit.h>
+include "wcslab.h"
+include "wcs_desc.h"
+
+# WL_SETUP -- Determine all the basic characteristics of the plot.
+#
+# Description
+# Determine basic characteristics of the plot at hand. This involved
+# "discovering" what part of the world system covers the screen, the
+# orientation of the world to logical systems, what type of graph will
+# be produced, etc. Many of the parameters determined here can be
+# over-ridden by user-specified values.
+
+procedure wl_setup (wd)
+
+pointer wd # I: the WCSLAB descriptor
+
+bool north
+double array[N_EDGES,N_DIM], max_value[N_DIM], min_value[N_DIM]
+double range[N_DIM], pole_position[N_DIM], view_edge[N_EDGES,N_DIM]
+double wl_coord_rotation()
+pointer mw_sctran()
+string logtran "logical"
+string wrldtran "world"
+
+begin
+ # Calculate the transformations from the Logical (pixel space) system
+ # to the World (possibly anything) system and back.
+ WL_LWCT(wd) = mw_sctran (WL_MW(wd), logtran, wrldtran, AXIS)
+ WL_WLCT(wd) = mw_sctran (WL_MW(wd), wrldtran, logtran, AXIS)
+
+ # Indicate whether the center of the transformation is north.
+ if (WL_SYSTEM_TYPE(wd) == RA_DEC)
+ north = (WL_WORLD_CENTER(wd,LATITUDE) > 0.0D0)
+
+ # Determine the poles position.
+ if (WL_SYSTEM_TYPE(wd) == RA_DEC)
+ call wl_pole_position (WL_WLCT(wd), WL_AXIS_FLIP(wd),
+ WL_WORLD_CENTER(wd,LONGITUDE), north, WL_SYSTEM_TYPE(wd),
+ pole_position)
+
+ # Determine graph type based on the system type.
+ call wl_determine_graph_type (WL_SYSTEM_TYPE(wd), pole_position,
+ WL_SCREEN_BOUNDARY(wd,1), WL_GRAPH_TYPE(wd))
+
+ # Now find the extent of the WCS the window views, by constructing
+ # x,y vectors containing evenly spaced points around the edges of
+ # the viewing window.
+
+ call wl_construct_edge_vectors (WL_SCREEN_BOUNDARY(wd,1),
+ view_edge[1,X_DIM], view_edge[1,Y_DIM], N_EDGES)
+
+ # Find the range of the axes over the graphics viewport.
+ call wl_l2wd (WL_LWCT(wd), WL_AXIS_FLIP(wd), view_edge[1,X_DIM],
+ view_edge[1,Y_DIM], array[1,AXIS1], array[1,AXIS2], N_EDGES)
+ call alimd (array[1,AXIS1], N_EDGES, min_value[AXIS1], max_value[AXIS1])
+ call alimd (array[1,AXIS2], N_EDGES, min_value[AXIS2], max_value[AXIS2])
+ range[AXIS1] = abs (max_value[AXIS1] - min_value[AXIS1])
+ range[AXIS2] = abs (max_value[AXIS2] - min_value[AXIS2])
+
+ # The above isn't good enough for the sky projections. Deal with those.
+ if (WL_SYSTEM_TYPE(wd) == RA_DEC)
+ call wl_sky_extrema (wd, array[1,AXIS1], N_EDGES, pole_position,
+ north, min_value[AXIS1], max_value[AXIS1], range[AXIS1],
+ min_value[AXIS2], max_value[AXIS2], range[AXIS2])
+
+ # Determine the rotation between the systems.
+ WL_ROTA(wd) = wl_coord_rotation (WL_WLCT(wd), WL_AXIS_FLIP(wd),
+ WL_WORLD_CENTER(wd,AXIS1), max_value[AXIS2],
+ WL_WORLD_CENTER(wd,AXIS1), min_value[AXIS2])
+
+ # Round the intervals. This is done to make the labelling "nice" and
+ # to smooth edge effects.
+ if (IS_INDEFD (WL_MAJOR_INTERVAL(wd,AXIS1)) ||
+ IS_INDEFD (WL_BEGIN(wd,AXIS1)) || IS_INDEFD (WL_END(wd,AXIS1)))
+ call wl_round_axis (wd, AXIS1, min_value[AXIS1], max_value[AXIS1],
+ range[AXIS1])
+
+ if (IS_INDEFD (WL_MAJOR_INTERVAL(wd,AXIS2)) ||
+ IS_INDEFD (WL_BEGIN(wd,AXIS2)) || IS_INDEFD (WL_END(wd,AXIS2)))
+ call wl_round_axis (wd, AXIS2, min_value[AXIS2], max_value[AXIS2],
+ range[AXIS2])
+end
+
+
+# WL_POLE_POSITION -- Determine logical coordinates of a pole.
+#
+# Description
+# Calculate the pole's position in the Logical system.
+#
+# Bugs
+# Can only deal with Right Ascension/Declination.
+
+procedure wl_pole_position (wlct, flip, longitude, north, system_type,
+ pole_position)
+
+pointer wlct # I: the world-to-logical transformation
+int flip # I: true if the axes are transposed
+double longitude # I: the longitude to determine latitude
+bool north # I: true if the pole is in the north
+int system_type # I: type of system being examined
+double pole_position[N_DIM] # O: the pole's logical coordinates
+
+double sgn
+
+begin
+ switch (system_type) {
+
+ # For Right Ascension/Declination, the pole is at any longitude but
+ # at only 90 degrees (north) or -90 degrees (south) latitude.
+ case RA_DEC:
+ if (north)
+ sgn = NORTH_POLE_LATITUDE
+ else
+ sgn = SOUTH_POLE_LATITUDE
+ call wl_w2ld (wlct, flip, longitude, sgn, pole_position[X_DIM],
+ pole_position[Y_DIM], 1)
+ }
+
+ # Sanity check on the pole position. It is very likely that there is
+ # no valid position in pixel space for the pole. This is checked for
+ # by looking for extremely large numbers.
+ if (abs (pole_position[X_DIM]) > abs (double (MAX_INT)))
+ pole_position[X_DIM] = real (MAX_INT)
+ if (abs (pole_position[Y_DIM]) > abs (double (MAX_INT)))
+ pole_position[Y_DIM] = real (MAX_INT)
+end
+
+
+# How close can the pole be to the center of the screen to be near-polar.
+define HOW_CLOSE 3.
+
+# WL_DETERMINE_GRAPH_TYPE -- Determine the actual graph type.
+
+procedure wl_determine_graph_type (system_type, pole_position,
+ screen_boundary, graph_type)
+
+int system_type # I: the type of WCS being dealt with
+double pole_position[N_DIM] # I: the location of the pole
+double screen_boundary[N_SIDES] # I: the edges of the display
+int graph_type # O: the graph type
+
+double max_dist, pole_dist, xcen, ycen
+
+begin
+ # Determine graph type based on axis type.
+ switch (system_type) {
+
+ # If the pole is on the graph then force a graph_type of polar.
+ case RA_DEC:
+
+ xcen = (screen_boundary[LEFT] + screen_boundary[RIGHT]) / 2.
+ ycen = (screen_boundary[BOTTOM] + screen_boundary[TOP]) / 2.
+ max_dist = min ((screen_boundary[LEFT] - xcen) ** 2,
+ (screen_boundary[TOP] - ycen)**2)
+ pole_dist = (pole_position[X_DIM] - xcen) ** 2 +
+ (pole_position[Y_DIM] - ycen) ** 2
+
+ # Check to see whether the graph is "polar", "near_polar"
+ # or "normal". If the pole lies within middle part of the
+ # viewport, then the graph is "polar". If the pole is within
+ # a certain maximum distance then it is "near_polar".
+ # Otherwise it is normal.
+
+ switch (graph_type) {
+ case NORMAL:
+ # do nothing
+ case POLAR:
+ # do nothing
+ case NEAR_POLAR:
+ # do nothing
+ default:
+ if (pole_dist < max_dist)
+ graph_type = POLAR
+ else if (pole_dist < HOW_CLOSE * max_dist)
+ graph_type = NEAR_POLAR
+ else
+ graph_type = NORMAL
+ }
+
+ # For all other cases, explicitely set this to normal.
+ default:
+ graph_type = NORMAL
+ }
+end
+
+
+# WL_CONSTRUCT_EDGE_VECTORS -- Construct vectors of values along window's edge.
+#
+# Description
+# This routines filles two arrays, with the x-values and y-values of
+# evenly spaced points along the edges of the screen. This is used to
+# make transformation of the logical edges into the world system
+# more convenient.
+
+procedure wl_construct_edge_vectors (screen_boundary, x, y, vector_size)
+
+double screen_boundary[N_SIDES] # I: the side values
+double x[vector_size], y[vector_size] # O: the edge vector points
+int vector_size # I: the number of edge vector points
+
+double current, interval
+int i, left_over, offset1, offset2, side_length
+
+begin
+ # Divide the vectors into equal amounts for each side.
+ side_length = vector_size / N_SIDES
+ left_over = mod (vector_size, N_SIDES)
+
+ # Calculate the horizontal components.
+ interval = (screen_boundary[RIGHT] - screen_boundary[LEFT]) /
+ side_length
+ current = screen_boundary[LEFT]
+ offset1 = side_length
+ for (i = 1; i <= side_length; i = i + 1) {
+ x[i] = current + interval
+ y[i] = screen_boundary[BOTTOM]
+ x[i+offset1] = current
+ y[i+offset1] = screen_boundary[TOP]
+ current = current + interval
+ }
+
+ # Calculate the verticle components.
+ interval = (screen_boundary[TOP] - screen_boundary[BOTTOM]) /
+ side_length
+ current = screen_boundary[BOTTOM]
+ offset1 = 2 * side_length
+ offset2 = 3 * side_length
+ for (i = 1; i <= side_length; i = i + 1) {
+ x[i+offset1] = screen_boundary[LEFT]
+ y[i+offset1] = current
+ x[i+offset2] = screen_boundary[RIGHT]
+ y[i+offset2] = current + interval
+ current = current + interval
+ }
+
+ # Fill in the left over with a single point.
+ offset1 = 4 * side_length
+ for (i = 1; i <= left_over; i = i + 1) {
+ x[i+offset1] = screen_boundary[LEFT]
+ y[i+offset1] = screen_boundary[BOTTOM]
+ }
+
+end
+
+
+# WL_SKY_EXTREMA -- Determine what range the view window covers in the sky.
+# This routine is only called if the WCS RA,DEC.
+#
+# Description
+# Because of the different graph types and the fact that axis 1 usually
+# wraps, more work needs to be done to determine what part of the sky
+# is covered by the viewing window.
+
+procedure wl_sky_extrema (wd, ax1_array, n_points, pole_position, north,
+ ax1min, ax1max, ax1ran, ax2min, ax2max, ax2ran)
+
+pointer wd # I: the WCSLAB descriptor
+double ax1_array[n_points] # I: the axis 1 edge vector
+int n_points # I: the length of the edge vector
+double pole_position[N_DIM] # I: the pole position
+bool north # I: is the pole in the north ?
+double ax1min, ax1max, ax1ran # I/O: the minimum, maximum, range in axis 1
+double ax2min, ax2max, ax2ran # I/O: the minimum, maximum, range in axis 2
+
+bool is_pole
+double nx, ny, xcen, ycen
+int wl_direction_from_axis1(), wl_find_side(), wl_opposite_side()
+
+begin
+ # Is the pole on the graph ?
+ if ((pole_position[X_DIM] < WL_SCREEN_BOUNDARY(wd,LEFT)) ||
+ (pole_position[X_DIM] > WL_SCREEN_BOUNDARY(wd,RIGHT)) ||
+ (pole_position[Y_DIM] < WL_SCREEN_BOUNDARY(wd,BOTTOM)) ||
+ (pole_position[Y_DIM] > WL_SCREEN_BOUNDARY(wd,TOP)))
+ is_pole = false
+ else
+ is_pole = true
+
+ # If so adjust the RA and DEC ranges appropriately.
+ if (is_pole) {
+
+ # Set the RA range.
+ ax1min = 0.0D0
+ ax1max = 359.9D0
+ ax1ran = 360.0D0
+
+ # Set the dec range.
+ if (north)
+ ax2max = NORTH_POLE_LATITUDE - ((NORTH_POLE_LATITUDE -
+ ax2min) * DISTANCE_TO_POLE )
+ else
+ ax2min = SOUTH_POLE_LATITUDE + ((NORTH_POLE_LATITUDE +
+ ax2max) * DISTANCE_TO_POLE)
+ ax2ran = abs (ax2max - ax2min)
+
+ # Mark the pole.
+ call gmark (WL_GP(wd), real (pole_position[X_DIM]),
+ real (pole_position[Y_DIM]), POLE_MARK_SHAPE, POLE_MARK_SIZE,
+ POLE_MARK_SIZE)
+
+ } else {
+ # Only the RA range needs adjusting.
+ call wl_ra_range (ax1_array, n_points, ax1min, ax1max, ax1ran)
+ }
+
+ # Adjust the labelling characteristics appropritatley for various
+ # types of graphs.
+
+ if (WL_GRAPH_TYPE(wd) == POLAR) {
+
+ # Determine which direction the axis 2's will be labeled on polar
+ # graphs.
+ if (IS_INDEFD (WL_POLAR_LABEL_POSITION(wd))) {
+ call wl_get_axis2_label_direction (WL_LWCT(wd),
+ WL_AXIS_FLIP(wd), pole_position, WL_SCREEN_BOUNDARY(wd,1),
+ WL_POLAR_LABEL_POSITION(wd), WL_BAD_LABEL_SIDE(wd))
+ } else {
+ WL_BAD_LABEL_SIDE(wd) = wl_direction_from_axis1 (WL_WLCT(wd),
+ WL_AXIS_FLIP(wd), pole_position, north,
+ WL_POLAR_LABEL_POSITION(wd), WL_BEGIN(wd,AXIS2),
+ WL_END(wd,AXIS2), WL_SCREEN_BOUNDARY(wd,1))
+ if (IS_INDEFI (WL_BAD_LABEL_SIDE(wd)))
+ WL_BAD_LABEL_SIDE(wd) = BOTTOM
+ }
+
+ # If the graph type is polar, then determine how to justify
+ # the labels.
+
+ if (IS_INDEFI (WL_POLAR_LABEL_DIRECTION(wd)))
+ WL_POLAR_LABEL_DIRECTION(wd) =
+ wl_opposite_side (WL_BAD_LABEL_SIDE(wd))
+
+ # If the graph_type is near-polar, then handle the directions a bit
+ # differently.
+ } else if (WL_GRAPH_TYPE(wd) == NEAR_POLAR) {
+
+ # Find the side that the pole is on.
+ xcen = (WL_SCREEN_BOUNDARY(wd,LEFT) +
+ WL_SCREEN_BOUNDARY(wd,RIGHT)) / 2.
+ ycen = (WL_SCREEN_BOUNDARY(wd,BOTTOM) +
+ WL_SCREEN_BOUNDARY(wd,TOP)) / 2.
+ call wl_axis_on_line (xcen, ycen, pole_position[X_DIM],
+ pole_position[Y_DIM], WL_SCREEN_BOUNDARY(wd,1), nx, ny)
+
+ if (IS_INDEFD(nx) || IS_INDEFD(ny)) {
+ WL_BAD_LABEL_SIDE(wd) = BOTTOM
+ WL_POLAR_LABEL_DIRECTION(wd) = LEFT
+ } else {
+ WL_BAD_LABEL_SIDE(wd) = wl_find_side (nx, ny,
+ WL_SCREEN_BOUNDARY(wd,1))
+ if (WL_BAD_LABEL_SIDE(wd) == LEFT || WL_BAD_LABEL_SIDE(wd) ==
+ RIGHT)
+ if (abs (ny - WL_SCREEN_BOUNDARY(wd,BOTTOM)) <
+ abs (ny - WL_SCREEN_BOUNDARY(wd,TOP)))
+ WL_POLAR_LABEL_DIRECTION(wd) = BOTTOM
+ else
+ WL_POLAR_LABEL_DIRECTION(wd) = TOP
+ else
+ if (abs (nx - WL_SCREEN_BOUNDARY(wd,LEFT)) <
+ abs (nx - WL_SCREEN_BOUNDARY(wd,RIGHT)))
+ WL_POLAR_LABEL_DIRECTION(wd) = LEFT
+ else
+ WL_POLAR_LABEL_DIRECTION(wd) = RIGHT
+ }
+
+ }
+end
+
+
+# WL_COORD_ROTATION -- Determine "rotation" between the coordinate systems.
+#
+# Description
+# This routine takes the world-to-logical coordinate transformation and
+# two points in the world system which should define the positive verticle
+# axis in the world system. These points are translated into the logical
+# system and the angle between the logical vector and its positive verticle
+# vector is calculated and returned. The rotation angle is returned
+# in degrees and is always positive.
+
+double procedure wl_coord_rotation (wlct, flip, wx1, wy1, wx2, wy2)
+
+pointer wlct # I: the world-to-logical transformation
+int flip # I: true if the coordinates are transposed
+double wx1, wy1, wx2, wy2 # I: points in world space to figure rotation from
+
+double delx, dely, rota, x1, y1, x2, y2
+bool fp_equald()
+
+begin
+ # Transform the points to the logical system.
+ call wl_w2ld (wlct, flip, wx1, wy1, x1, y1, 1)
+ call wl_w2ld (wlct, flip, wx2, wy2, x2, y2, 1)
+
+ # Determine the rotation.
+ delx = x2 - x1
+ dely = y2 - y1
+ if (fp_equald (delx, 0.0D0) && fp_equald (dely, 0.0D0))
+ rota = 0.
+ else
+ rota = RADTODEG (atan2 (dely, delx))
+
+ if (rota < 0.0D0)
+ rota = rota + FULL_CIRCLE
+
+ return (rota)
+end
+
+
+# Define how many axis one should go for.
+
+define RA_NUM_TRY 6
+define DEC_NUM_TRY 6
+define DEC_POLAR_NUM_TRY 4
+
+# WL_ROUND_AXIS - Round values for the axis.
+
+procedure wl_round_axis (wd, axis, minimum, maximum, range)
+
+pointer wd # I: the WCSLAB descriptor
+int axis # I: the axis being worked on
+double minimum, maximum, range # I: raw values to be rounded
+
+int num_try
+
+begin
+ # Depending on axis type, round the values.
+ switch (WL_SYSTEM_TYPE(wd)) {
+ case RA_DEC:
+ if (axis == LONGITUDE)
+ call wl_round_ra (minimum, maximum, range, RA_NUM_TRY,
+ WL_BEGIN(wd,LONGITUDE), WL_END(wd,LONGITUDE),
+ WL_MAJOR_INTERVAL(wd,LONGITUDE))
+ else {
+ if (WL_GRAPH_TYPE(wd) == POLAR)
+ num_try = DEC_POLAR_NUM_TRY
+ else
+ num_try = DEC_NUM_TRY
+ call wl_round_dec (minimum, maximum, range, num_try,
+ WL_BEGIN(wd,LATITUDE), WL_END(wd,LATITUDE),
+ WL_MAJOR_INTERVAL(wd,LATITUDE))
+ }
+
+ default:
+ call wl_generic_round (minimum, maximum, range, WL_BEGIN(wd,axis),
+ WL_END(wd,axis), WL_MAJOR_INTERVAL(wd,axis))
+ }
+
+end
+
+
+# WL_GET_AXIS2_LABEL_DIRECTION -- Dertermine label direction for latitides.
+#
+# Description
+# Determine from which edge of the graph the axis 2 labels are to
+# appear. This (in general) is the opposite edge from which the pole
+# is nearest to. Move the pole to the closest edges, determine which
+# side it is, then chose the direction as the opposite. Also determines
+# the Axis 1 at which the Axis 2 labels will appear.
+
+procedure wl_get_axis2_label_direction (lwct, flip, pole_position,
+ screen_boundary, pole_label_position, bad_label_side)
+
+pointer lwct # I: logical-to-world transformation
+int flip # I: true if the axis are transposed
+double pole_position[N_DIM] # I: the position of the pole
+double screen_boundary[N_SIDES] # I: the edges of the screen
+double pole_label_position # O: the axis 1 that axis 2 labels should
+ # appear for polar|near-polar graphs
+int bad_label_side # O: side not to place axis 1 labels
+
+double dif, tdif, dummy
+
+begin
+ # Determine which direction, up or down, the axis 2's will be labelled.
+ dif = abs (screen_boundary[TOP] - pole_position[AXIS2])
+ bad_label_side= TOP
+ tdif = abs (screen_boundary[BOTTOM] - pole_position[AXIS2])
+ if (tdif < dif) {
+ dif = tdif
+ bad_label_side = BOTTOM
+ }
+
+ # Determine at what value of Axis 1 the Axis 2 labels should appear.
+ switch (bad_label_side) {
+ case TOP:
+ call wl_l2wd (lwct, flip, pole_position[AXIS1],
+ screen_boundary[BOTTOM], pole_label_position, dummy, 1)
+ case BOTTOM:
+ call wl_l2wd (lwct, flip, pole_position[AXIS1],
+ screen_boundary[TOP], pole_label_position, dummy, 1)
+ case LEFT:
+ call wl_l2wd (lwct, flip, screen_boundary[RIGHT],
+ pole_position[AXIS2], pole_label_position, dummy, 1)
+ case RIGHT:
+ call wl_l2wd (lwct, flip, screen_boundary[LEFT],
+ pole_position[AXIS2], pole_label_position, dummy, 1)
+ }
+
+end
+
+
+# WL_DIRECTION_FROM_AXIS1 -- Determine axis 2 label direction from axis 1.
+#
+# Function Returns
+# This returns the side where Axis 1 should not be labelled.
+
+int procedure wl_direction_from_axis1 (wlct, flip, pole_position, north,
+ polar_label_position, lbegin, lend, screen_boundary)
+
+pointer wlct # I: world-to-logical transformation
+int flip # I: true if the axes are transposed
+double pole_position[N_DIM] # I: the pole position
+bool north # I: true if the pole is the north pole
+double polar_label_position # I: the axis 1 where axis 2 will be
+ # marked
+double lbegin # I: low end of axis 2
+double lend # I: high end of axis 2
+double screen_boundary[N_SIDES] # I: the window boundary
+
+double nx, ny, cx, cy
+int wl_find_side()
+
+begin
+ # Determine the point in logical space where the axis 1 and the
+ # minimum axis 2 meet.
+
+ if (north)
+ call wl_w2ld (wlct, flip, polar_label_position, lbegin, nx, ny, 1)
+ else
+ call wl_w2ld (wlct, flip, polar_label_position, lend, nx, ny, 1)
+
+ # This line should cross a window boundary. Find that point.
+
+ call wl_axis_on_line (pole_position[X_DIM], pole_position[Y_DIM],
+ screen_boundary, nx, ny, cx, cy)
+
+ # Get the side that the crossing point is. This is the axis 2 labelling
+ # direction.
+
+ if (IS_INDEFD(cx) || IS_INDEFD(cy))
+ return (INDEFI)
+ else
+ return (wl_find_side (cx, cy, screen_boundary))
+end
+
+
+# WL_OPPOSITE_SIDE - Return the opposite of the given side.
+#
+# Returns
+# The opposite side of the specified side as follows:
+# RIGHT -> LEFT
+# LEFT -> RIGHT
+# TOP -> BOTTOM
+# BOTTOM -> TOP
+
+int procedure wl_opposite_side (side)
+
+int side # I: the side to find the opposite of
+
+int new_side
+
+begin
+ switch (side) {
+ case LEFT:
+ new_side = RIGHT
+ case RIGHT:
+ new_side = LEFT
+ case TOP:
+ new_side = BOTTOM
+ case BOTTOM:
+ new_side = TOP
+ }
+
+ return (new_side)
+end
+
+
+# Define whether things are on the screen boundary or on them.
+
+define IN (($1>=screen_boundary[LEFT])&&($1<=screen_boundary[RIGHT])&&($2>=screen_boundary[BOTTOM])&&($2<=screen_boundary[TOP]))
+
+
+# WL_AXIS_ON_LINE - Determine intersection of line and a screen boundary.
+#
+# Description
+# Return the point where the line defined by the two input points
+# crosses a screen boundary. The boundary is choosen by determining
+# which one is between the two points.
+
+procedure wl_axis_on_line (x0, y0, x1, y1, screen_boundary, nx, ny)
+
+double x0, y0, x1, y1 # I: random points in space
+double screen_boundary[N_SIDES] # I: sides of the window
+double nx, ny # O: the closest point on a window boundary
+
+double x_val[N_SIDES], y_val[N_SIDES], tx0, ty0, tx1, ty1, w[2]
+int i
+pointer cvx, cvy
+double dcveval()
+
+begin
+ # Get the line parameters.
+ x_val[1] = x0
+ x_val[2] = x1
+ y_val[1] = y0
+ y_val[2] = y1
+
+ iferr (call dcvinit (cvx, CHEBYSHEV, 2, min (x0, x1), max (x0, x1)))
+ cvx = NULL
+ else {
+ call dcvfit (cvx, x_val, y_val, w, 2, WTS_UNIFORM, i)
+ if (i != OK)
+ call error (i, "wlaxie: Error solving on X")
+ }
+
+ iferr (call dcvinit (cvy, CHEBYSHEV, 2, min (y0, y1), max (y0, y1)))
+ cvy = NULL
+ else {
+ call dcvfit (cvy, y_val, x_val, w, 2, WTS_UNIFORM, i)
+ if (i != OK)
+ call error (i, "wlaxie: Error solving on Y")
+ }
+
+ # Solve for each side.
+ x_val[LEFT] = screen_boundary[LEFT]
+ if (cvx == NULL)
+ y_val[LEFT] = screen_boundary[LEFT]
+ else
+ y_val[LEFT] = dcveval (cvx, x_val[LEFT])
+
+ x_val[RIGHT] = screen_boundary[RIGHT]
+ if (cvx == NULL )
+ y_val[RIGHT] = screen_boundary[RIGHT]
+ else
+ y_val[RIGHT] = dcveval (cvx, x_val[RIGHT])
+
+ y_val[TOP] = screen_boundary[TOP]
+ if (cvy == NULL)
+ x_val[TOP] = screen_boundary[TOP]
+ else
+ x_val[TOP] = dcveval (cvy, y_val[TOP])
+
+ y_val[BOTTOM] = screen_boundary[BOTTOM]
+ if (cvy == NULL)
+ x_val[BOTTOM] = screen_boundary[BOTTOM]
+ else
+ x_val[BOTTOM] = dcveval (cvy, y_val[BOTTOM])
+
+ # Rearrange the input points to be in ascending order.
+ if (x0 < x1) {
+ tx0 = x0
+ tx1 = x1
+ } else {
+ tx0 = x1
+ tx1 = x0
+ }
+
+ if (y0 < y1) {
+ ty0 = y0
+ ty1 = y1
+ } else {
+ ty0 = y1
+ ty1 = y0
+ }
+
+ # Now find which point is between the two given points and is within
+ # the viewing area.
+ # NOTE: Conversion to real for the check- if two points are so close
+ # for double, any of them would serve as the correct answer.
+
+ nx = INDEFD
+ ny = INDEFD
+ for (i = 1; i <= N_SIDES; i = i + 1)
+ if (real (tx0) <= real (x_val[i]) &&
+ real (x_val[i]) <= real (tx1) &&
+ real (ty0) <= real (y_val[i]) &&
+ real (y_val[i]) <= real (ty1) &&
+ IN (x_val[i], y_val[i]) ) {
+ nx = x_val[i]
+ ny = y_val[i]
+ }
+
+ # Release the curve fit descriptors.
+ if (cvx != NULL)
+ call dcvfree (cvx)
+ if (cvy != NULL)
+ call dcvfree (cvy)
+end
+
+
+# WL_FIND_SIDE -- Return the side that the given point is lying on.
+#
+# Function Returns
+# Return the side, TOP, BOTTOM, LEFT, or RIGHT, that the specified
+# point is lying on. One of the coordinates must be VERY CLOSE to one of
+# the sides or INDEFI will be returned.
+
+int procedure wl_find_side (x, y, screen_boundary)
+
+double x, y # I: the point to inquire about
+double screen_boundary[N_SIDES] # I: the edges of the screen
+
+double dif, ndif
+int side
+
+begin
+ dif = abs (x - screen_boundary[LEFT])
+ side = LEFT
+
+ ndif = abs (x - screen_boundary[RIGHT])
+ if (ndif < dif) {
+ side = RIGHT
+ dif = ndif
+ }
+
+ ndif = abs (y - screen_boundary[BOTTOM])
+ if (ndif < dif) {
+ side = BOTTOM
+ dif = ndif
+ }
+
+ ndif = abs (y - screen_boundary[TOP])
+ if (ndif < dif)
+ side = TOP
+
+ return (side)
+end
+
+
+# WL_RA_RANGE -- Determine the range in RA given a list of possible values.
+#
+# Description
+# Determine the largest range in RA from the provided list of values.
+# The problem here is that it is unknown which way the graph is oriented.
+# To simplify the problem, it is assume that the graph range does not extend
+# beyond a hemisphere and that all distances in RA is less than a hemisphere.
+# This assumption is needed to decide when the 0 hour is on the graph.
+
+procedure wl_ra_range (ra, n_values, min, max, diff)
+
+double ra[ARB] # I: the possible RA values
+int n_values # I: the number of possible RA values
+double min # I/O: the minimum RA
+double max # I/O: the maximum RA
+double diff # I/O: the difference between minimum and maximum
+
+bool wrap
+int i, j, n_diffs
+pointer sp, max_array, min_array, ran_array
+int wl_max_element_array()
+
+begin
+ call smark (sp)
+ call salloc (max_array, n_values * n_values, TY_DOUBLE)
+ call salloc (min_array, n_values * n_values, TY_DOUBLE)
+ call salloc (ran_array, n_values * n_values, TY_DOUBLE)
+
+ # Check whether the RA is wrapped or not.
+ n_diffs = 0
+ do i = 1, n_values {
+ if (ra[i] >= min && ra[i] <= max)
+ next
+ n_diffs = n_diffs + 1
+ }
+ if (n_diffs > 0)
+ wrap = true
+ else
+ wrap = false
+
+ n_diffs = 0
+ for (i = 1; i <= n_values; i = i + 1) {
+ for (j = i + 1; j <= n_values; j = j + 1) {
+ n_diffs = n_diffs + 1
+ call wl_getradif (ra[i], ra[j], Memd[min_array+n_diffs-1],
+ Memd[max_array+n_diffs-1], Memd[ran_array+n_diffs-1],
+ wrap)
+ }
+ }
+
+ i = wl_max_element_array (Memd[ran_array], n_diffs)
+ min = Memd[min_array+i-1]
+ max = Memd[max_array+i-1]
+ diff = Memd[ran_array+i-1]
+
+ call sfree (sp)
+end
+
+
+# WL_GETRADIFF -- Get differences in RA based on degrees.
+#
+# Description
+# This procedure determines, given two values in degrees, the minimum,
+# maximum, and difference of those values. The assumption is that no
+# difference should be greater than half a circle. Based on this assumption,
+# a difference is found and the minimum and maximum are determined. The
+# maximum can be greater than 360 degrees.
+
+procedure wl_getradif (val1, val2, min, max, diff, wrap)
+
+double val1, val2 # I: the RA values
+double min, max # O: the min RA and max RA (possibly > 360.0)
+double diff # O: the min, max difference
+bool wrap # I: is the ra wrapped ?
+
+begin
+ if (! wrap && (abs (val1 - val2) > HALF_CIRCLE))
+ if (val1 < val2) {
+ min = val2
+ max = val1 + FULL_CIRCLE
+ } else {
+ min = val1
+ max = val2 + FULL_CIRCLE
+ }
+ else
+ if (val1 < val2) {
+ min = val1
+ max = val2
+ } else {
+ min = val2
+ max = val1
+ }
+ diff = max - min
+end
+
+
+define NRAGAP 26
+
+# WL_ROUND_RA -- Modify the RA limits and calculate an interval to label.
+#
+# Description
+# The RA limits determine by just the extremes of the window ususally do
+# not fall on "reasonable" boundaries; i.e. essentially they are random
+# numbers. However, for labelling purposes, it is nice to have grids and
+# tick marks for "rounded" numbers- For RA, this means values close to
+# whole hours, minutes, or seconds. For example, if the span across the
+# plot is a few hours, the marks and labels should represent simply whole
+# hours. This routine determines new RA limits based on this and some
+# interval to produce marks between the newly revised limits.
+
+procedure wl_round_ra (longmin, longmax, longran, num_try, minimum, maximum,
+ major_interval)
+
+double longmin # I: longitude minimum
+double longmax # I: longitude maximum
+double longran # I: longitude range
+int num_try # I: the number of intervals to try for
+double minimum # O: the minimum RA value (in degrees)
+double maximum # O: the maximum RA value (in degrees)
+double major_interval # O: the appropriate interval (in degrees) for the
+ # major line marks.
+
+double ragap[NRAGAP]
+double wl_check_arrayd(), wl_round_upd()
+data ragap / 1.0D-4, 2.0D-4, 5.0D-4, 1.0D-3, 2.0D-3, 5.0D-3,
+ 0.01D0, 0.02D0, 0.05D0, 0.1D0, 0.2D0, 0.5D0, 1.0D0,
+ 2.0D0, 5.0D0, 10.0D0, 20.0D0, 30.0D0, 60.0D0, 120.0D0,
+ 300.0D0, 600.0D0, 1.2D3, 1.8D3, 3.6D3, 7.2D3 /
+
+
+begin
+ major_interval = wl_check_arrayd (DEGTOST (longran) / num_try,
+ ragap, NRAGAP)
+ minimum = STTODEG (wl_round_upd (DEGTOST (longmin), major_interval) -
+ major_interval)
+ maximum = STTODEG (wl_round_upd (DEGTOST (longmax), major_interval))
+ major_interval = STTODEG (major_interval)
+end
+
+
+define NDECGAP 28
+
+# WL_ROUND_DEC -- Modify the DEC limits and calculate an interval to label.
+#
+# Description
+# The DEC limits determine by just the extremes of the window ususally do
+# not fall on "reasonable" boundaries; i.e. essentially they are random
+# numbers. However, for labelling purposes, it is nice to have grids and
+# tick marks for "rounded" numbers- For DEC, this means values close to
+# whole degrees, minutes, or seconds. For example, if the span across the
+# plot is a few degrees, the marks and labels should represent simply whole
+# degrees. This routine determines new DEC limits based on this and some
+# interval to produce marks between the newly revised limits.
+
+procedure wl_round_dec (latmin, latmax, latran, num_try, minimum, maximum,
+ major_interval)
+
+double latmin # I: the latitude minimum
+double latmax # I: the latitude maximum
+double latran # I: the latitude range
+int num_try # I: number of intervals to try for
+double minimum # O: the DEC minimum
+double maximum # O: the DEC maximum
+double major_interval # O: the labelling interval to use for major lines
+
+double decgap[NDECGAP]
+double wl_check_arrayd(), wl_round_upd()
+data decgap / 1.0D-4, 2.0D-4, 5.0D-4, 1.0D-3, 2.0D-3, 5.0D-3,
+ 0.01D0, 0.02D0, 0.05D0, 0.1D0, 0.2D0, 0.5D0, 1.0D0,
+ 2.0D0, 5.0D0, 10.0D0,20.0D0, 30.0D0, 60.0D0, 120.0d0,
+ 300.0D0, 600.0D0, 1.2D3, 1.8D3, 3.6D3, 7.2D3, 1.8D4, 3.6D4 /
+
+begin
+ major_interval = wl_check_arrayd (DEGTOSA (latran) / num_try,
+ decgap, NDECGAP)
+ minimum = SATODEG (wl_round_upd (DEGTOSA (latmin), major_interval) -
+ major_interval)
+ maximum = SATODEG (wl_round_upd (DEGTOSA (latmax), major_interval))
+ major_interval = SATODEG (major_interval)
+
+ # Make sure that the grid marking does not include the pole.
+ maximum = min (maximum, NORTH_POLE_LATITUDE - major_interval)
+ minimum = max (minimum, SOUTH_POLE_LATITUDE + major_interval)
+end
+
+
+# WL_GENERIC_ROUND -- Round the values (if possible).
+#
+# History
+# 7Feb91 - Created by Jonathan D. Eisenhamer, STScI.
+
+procedure wl_generic_round (minimum, maximum, range, lbegin, lend, interval)
+
+double minimum, maximum, range # I: the raw input values
+double lbegin, lend # O: the begin and end label points
+double interval # O: the major label interval
+
+double amant, diff
+int iexp, num
+double wl_round_upd()
+
+begin
+ diff = log10 (abs (range) / 4.D0)
+ iexp = int (diff)
+ if (diff < 0)
+ iexp = iexp - 1
+
+ amant = diff - double (iexp)
+ if (amant < 0.15D0)
+ num = 1
+ else if (amant < 0.50D0)
+ num = 2
+ else if (amant < 0.85D0)
+ num = 5
+ else
+ num = 10
+
+ interval = double (num) * 10.0D0 ** iexp
+ lbegin = wl_round_upd (minimum, interval) - interval
+ lend = wl_round_upd (maximum, interval)
+end
+
+
+# WL_ROUND_UPD -- Round X up to nearest whole multiple of Y.
+
+double procedure wl_round_upd (x, y)
+
+double x # I: value to be rounded
+double y # I: multiple of X is to be rounded up in
+
+double z, r
+
+begin
+ if (x < 0.0D0)
+ z = 0.0D0
+ else
+ z = y
+ r = y * double (int ((x + z) / y))
+
+ return (r)
+end
+
+
+
+# WL_CHECK_ARRAYD -- Check proximity of array elements to each other.
+#
+# Description
+# Returns the element of the array arr(n) which is closest to an exact
+# value EX.
+
+double procedure wl_check_arrayd (ex, arr, n)
+
+double ex # I: the exact value
+double arr[ARB] # I: the array of rounded values
+int n # I: dimension of array of rounded values
+
+int j
+
+begin
+ for (j = 1; j < n && (ex - arr[j]) > 0.0D0; j = j + 1)
+ ;
+ if (j > 1 && j < n)
+ if (abs (ex - arr[j-1]) < abs (ex - arr[j]))
+ j = j - 1
+
+ return (arr[j])
+end
diff --git a/pkg/utilities/nttools/stxtools/wcslab/wlutil.x b/pkg/utilities/nttools/stxtools/wcslab/wlutil.x
new file mode 100644
index 00000000..c79b8f5e
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/wcslab/wlutil.x
@@ -0,0 +1,390 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imio.h>
+include <imhdr.h>
+include <gset.h>
+include <math.h>
+
+# WL_IMD_VIEWPORT -- Map the viewport and window of the image display.
+
+procedure wl_imd_viewport (frame, im, c1, c2, l1, l2, vl, vr, vb, vt)
+
+int frame # I: display frame to be overlayed
+pointer im # I: pointer to the input image
+real c1, c2, l1, l2 # I/O: input/output window
+real vl, vr, vb, vt # I/O: input/output viewport
+
+int wcs_status, dim1, dim2, step1, step2
+pointer sp, frimage, frim, iw
+real x1, x2, y1, y2, fx1, fx2, fy1, fy2, junkx, junky
+real vx1, vx2, vy1, vy2, nx1, nx2, ny1, ny2
+pointer imd_mapframe(), iw_open()
+
+
+begin
+ # If all of the viewport parameters were defined by the user
+ # use the default viewport and window.
+ if (! IS_INDEFR(vl) && ! IS_INDEFR(vr) && ! IS_INDEFR(vb) &&
+ ! IS_INDEFR(vt))
+ return
+
+ # Allocate some memory.
+ call smark (sp)
+ call salloc (frimage, SZ_FNAME, TY_CHAR)
+
+ # Open the requested display frame and get the loaded image name.
+ # If this name is blank, use the default viewport and window.
+
+ frim = imd_mapframe (frame, READ_ONLY, YES)
+ iw = iw_open (frim, frame, Memc[frimage], SZ_FNAME, wcs_status)
+ if (Memc[frimage] == EOS || wcs_status == ERR) {
+ call iw_close (iw)
+ call imunmap (frim)
+ call sfree (sp)
+ return
+ }
+
+ # Find the beginning and end points of the requested image section.
+ # We already know at this point that the input logical image is
+ # 2-dimensional. However this 2-dimensional section may be part of
+ # n-dimensional image.
+
+ # X dimension.
+ dim1 = IM_VMAP(im,1)
+ step1 = IM_VSTEP(im,1)
+ if (step1 >= 0) {
+ x1 = IM_VOFF(im,dim1) + 1
+ x2 = x1 + IM_LEN(im,1) - 1
+ } else {
+ x1 = IM_VOFF(im,dim1) - 1
+ x2 = x1 - IM_LEN(im,1) + 1
+ }
+
+ # Y dimension.
+ dim2 = IM_VMAP(im,2)
+ step2 = IM_VSTEP(im,2)
+ if (step2 >= 0) {
+ y1 = IM_VOFF(im,dim2) + 1
+ y2 = y1 + IM_LEN(im,2) - 1
+ } else {
+ y1 = IM_VOFF(im,dim2) - 1
+ y2 = y1 - IM_LEN(im,2) + 1
+ }
+
+ # Get the frame buffer coordinates corresponding to the lower left
+ # and upper right corners of the image section.
+
+ call iw_im2fb (iw, x1, y1, fx1, fy1)
+ call iw_im2fb (iw, x2, y2, fx2, fy2)
+ if (fx1 > fx2) {
+ junkx = fx1
+ fx1 = fx2
+ fx2 = junkx
+ }
+ if (fy1 > fy2) {
+ junky = fy1
+ fy1 = fy2
+ fy2 = junky
+ }
+
+ # Check that some portion of the input image is in the display.
+ # If not select the default viewport and window coordinates.
+ if (fx1 > IM_LEN(frim,1) || fx2 < 1.0 || fy1 > IM_LEN(frim,2) ||
+ fy2 < 1.0) {
+ call iw_close (iw)
+ call imunmap (frim)
+ call sfree (sp)
+ return
+ }
+
+ # Compute a new viewport and window for X.
+ if (fx1 >= 1.0) {
+ vx1 = max (0.0, min (1.0, (fx1 - 0.5) / IM_LEN(frim,1)))
+ nx1 = 1.0
+ } else {
+ vx1 = 0.0
+ call iw_fb2im (iw, 1.0, 1.0, junkx, junky)
+ if (step1 >= 0)
+ nx1 = max (1.0, junkx - x1 + 1.0)
+ else
+ nx2 = max (1.0, junkx - x2 + 1.0)
+ }
+ if (fx2 <= IM_LEN(frim,1)) {
+ vx2 = max (0.0, min (1.0, (fx2 + 0.5) / IM_LEN(frim,1)))
+ nx2 = IM_LEN(im,1)
+ } else {
+ vx2 = 1.0
+ call iw_fb2im (iw, real(IM_LEN(frim,1)), real (IM_LEN(frim,2)),
+ junkx, junky)
+ if (step1 >= 0)
+ nx2 = min (real (IM_LEN(im,1)), junkx - x1 + 1.0)
+ else
+ nx1 = min (real (IM_LEN(im,1)), junkx - x2 + 1.0)
+ }
+
+ # Compute a new viewport and window for Y.
+ if (fy1 >= 1.0) {
+ vy1 = max (0.0, min (1.0, (fy1 - 0.5) / IM_LEN(frim,2)))
+ ny1 = 1.0
+ } else {
+ vy1 = 0.0
+ call iw_fb2im (iw, 1.0, 1.0, junkx, junky)
+ if (step2 >= 0)
+ ny1 = max (1.0, junky - y1 + 1)
+ else
+ ny2 = max (1.0, junky - y2 + 1)
+ }
+ if (fy2 <= IM_LEN(frim,2)) {
+ vy2 = max (0.0, min (1.0, (fy2 + 0.5) / IM_LEN(frim,2)))
+ ny2 = IM_LEN(im,2)
+ } else {
+ vy2 = 1.0
+ call iw_fb2im (iw, real (IM_LEN(frim,1)), real (IM_LEN(frim,2)),
+ junkx, junky)
+ if (step2 >= 0)
+ ny2 = min (real (IM_LEN(im,2)), junky - y1 + 1.0)
+ else
+ ny1 = min (real (IM_LEN(im,2)), junky - y2 + 1.0)
+ }
+
+ # Define a the new viewport and window.
+ if (IS_INDEFR(vl)) {
+ vl = vx1
+ c1 = nx1
+ }
+ if (IS_INDEFR(vr)) {
+ vr = vx2
+ c2 = nx2
+ }
+ if (IS_INDEFR(vb)) {
+ vb = vy1
+ l1 = ny1
+ }
+ if (IS_INDEFR(vt)) {
+ vt = vy2
+ l2 = ny2
+ }
+
+ # Clean up.
+ call iw_close (iw)
+ call imunmap (frim)
+ call sfree (sp)
+end
+
+
+define EDGE1 0.1
+define EDGE2 0.9
+define EDGE3 0.12
+define EDGE4 0.92
+
+# WL_MAP_VIEWPORT -- Set device viewport wcslab plots. If not specified by
+# user, a default viewport centered on the device is used.
+
+procedure wl_map_viewport (gp, c1, c2, l1, l2, ux1, ux2, uy1, uy2, fill)
+
+pointer gp # I: pointer to graphics descriptor
+real c1, c2, l1, l2 # I: the column and line limits
+real ux1, ux2, uy1, uy2 # I/O: NDC coordinates of requested viewort
+bool fill # I: fill viewport (vs preserve aspect ratio)
+
+int ncols, nlines
+real xcen, ycen, ncolsr, nlinesr, ratio, aspect_ratio
+real x1, x2, y1, y2, ext, xdis, ydis
+bool fp_equalr()
+real ggetr()
+data ext /0.0625/
+
+begin
+ ncols = nint (c2 - c1) + 1
+ ncolsr = real (ncols)
+ nlines = nint (l2 - l1) + 1
+ nlinesr = real (nlines)
+
+ # Determine the standard window sizes.
+ if (fill) {
+ x1 = 0.0; x2 = 1.0
+ y1 = 0.0; y2 = 1.0
+ } else {
+ x1 = EDGE1; x2 = EDGE2
+ y1 = EDGE3; y2 = EDGE4
+ }
+
+ # If any values were specified, then replace them here.
+ if (! IS_INDEFR(ux1))
+ x1 = ux1
+ if (! IS_INDEFR(ux2))
+ x2 = ux2
+ if (! IS_INDEFR(uy1))
+ y1 = uy1
+ if (! IS_INDEFR(uy2))
+ y2 = uy2
+
+ # Calculate optimum viewport, as in NCAR's conrec, hafton.
+ if (! fill) {
+ ratio = min (ncolsr, nlinesr) / max (ncolsr, nlinesr)
+ if (ratio >= ext) {
+ if (ncols > nlines)
+ y2 = (y2 - y1) * nlinesr / ncolsr + y1
+ else
+ x2 = (x2 - x1) * ncolsr / nlinesr + x1
+ }
+ }
+
+ xdis = x2 - x1
+ ydis = y2 - y1
+ xcen = (x2 + x1) / 2.
+ ycen = (y2 + y1) / 2.
+
+ # So far, the viewport has been calculated so that equal numbers of
+ # image pixels map to equal distances in NDC space, regardless of
+ # the aspect ratio of the device. If the parameter "fill" has been
+ # set to no, the user wants to compensate for a non-unity aspect
+ # ratio and make equal numbers of image pixels map to into the same
+ # physical distance on the device, not the same NDC distance.
+
+ if (! fill) {
+ aspect_ratio = ggetr (gp, "ar")
+ if (fp_equalr (aspect_ratio, 0.0))
+ aspect_ratio = 1.0
+
+ if (aspect_ratio < 1.0)
+ # Landscape
+ xdis = xdis * aspect_ratio
+ else if (aspect_ratio > 1.0)
+ # Portrait
+ ydis = ydis / aspect_ratio
+ }
+
+ ux1 = xcen - (xdis / 2.0)
+ ux2 = xcen + (xdis / 2.0)
+ uy1 = ycen - (ydis / 2.0)
+ uy2 = ycen + (ydis / 2.0)
+
+ call gsview (gp, ux1, ux2, uy1, uy2)
+ call gswind (gp, c1, c2, l1, l2)
+end
+
+
+# WL_W2LD -- Transform world coordinates to logical coordinates.
+
+procedure wl_w2ld (wlct, flip, wx, wy, lx, ly, npts)
+
+pointer wlct # I: the MWCS coordinate transformation descriptor
+int flip # I: true if the axes are transposed
+double wx[npts], wy[npts] # I: the world coordinates
+double lx[npts], ly[npts] # O: the logical coordinates
+int npts # I: the number of points to translate
+
+begin
+ if (flip == YES)
+ call mw_v2trand (wlct, wx, wy, ly, lx, npts)
+ else
+ call mw_v2trand (wlct, wx, wy, lx, ly, npts)
+end
+
+
+# WL_L2WD -- Transform logical coordinates to world coordinates.
+
+procedure wl_l2wd (lwct, flip, lx, ly, wx, wy, npts)
+
+pointer lwct # I: the MWCS coordinate transformation descriptor
+int flip # I: true if the axes are transposed
+double lx[npts], ly[npts] # I: the logical coordinates
+double wx[npts], wy[npts] # O: the world coordinates
+int npts # I: the number of points to translate
+
+begin
+ if (flip == YES)
+ call mw_v2trand (lwct, ly, lx, wx, wy, npts)
+ else
+ call mw_v2trand (lwct, lx, ly, wx, wy, npts)
+end
+
+
+# WL_MAX_ELEMENT_ARRAY -- Return the index of the maximum array element.
+#
+# Description
+# This function returns the index of the maximum value of the input array.
+
+int procedure wl_max_element_array (array, npts)
+
+double array[ARB] # I: the array to look through for the maximum
+int npts # I: the number of points in the array
+
+int i, maximum
+
+begin
+ maximum = 1
+ for (i = 2; i <= npts; i = i + 1)
+ if (array[i] > array[maximum])
+ maximum = i
+
+ return (maximum)
+end
+
+
+# WL_DISTANCED - Determine the distance between two points.
+
+double procedure wl_distanced (x1, y1, x2, y2)
+
+double x1, y1 # I: coordinates of point 1
+double x2, y2 # I: coordinates of point 2
+
+double a, b
+
+begin
+ a = x1 - x2
+ b = y1 - y2
+ return (sqrt ((a * a) + (b * b)))
+end
+
+
+# WL_DISTANCER -- Determine the distance between two points.
+
+real procedure wl_distancer (x1, y1, x2, y2)
+
+real x1, y1 # I: coordinates of point 1
+real x2, y2 # I: coordinates of point 2
+
+real a, b
+
+begin
+ a = x1 - x2
+ b = y1 - y2
+ return (sqrt ((a * a) + (b * b)))
+end
+
+
+# The dimensionality.
+define N_DIM 2
+
+# Define some memory management.
+define ONER Memr[$1+$2-1]
+
+# WL_ROTATE -- Rotate a vector.
+
+procedure wl_rotate (x, y, npts, angle, nx, ny)
+
+real x[npts], y[npts] # I: the vectors to rotate
+int npts # I: the number of points in the vectors
+real angle # I: the angle to rotate (radians)
+real nx[npts], ny[npts] # O: the transformed vectors
+
+pointer sp, center, mw
+pointer mw_open(), mw_sctran()
+
+begin
+ # Get some memory.
+ call smark (sp)
+ call salloc (center, N_DIM, TY_REAL)
+
+ mw = mw_open (NULL, N_DIM)
+ ONER(center,1) = 0.
+ ONER(center,2) = 0.
+ call mw_rotate (mw, -DEGTORAD( angle ), ONER(center,1), 3b)
+ call mw_v2tranr (mw_sctran (mw, "physical", "logical", 3b),
+ x, y, nx, ny, npts)
+
+ call mw_close (mw)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/stxtools/wcslab/wlwcslab.x b/pkg/utilities/nttools/stxtools/wcslab/wlwcslab.x
new file mode 100644
index 00000000..156c9a8a
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/wcslab/wlwcslab.x
@@ -0,0 +1,181 @@
+include <gio.h>
+include <gset.h>
+include "wcslab.h"
+include "wcs_desc.h"
+
+# Define the memory structure for saving the graphics wcs.
+define SAVE_BLOCK_SIZE 16
+define OLD_NDC_VIEW Memr[wcs_save_block-1+$1]
+define OLD_NDC_WIND Memr[wcs_save_block+3+$1]
+define OLD_PLT_VIEW Memr[wcs_save_block+7+$1]
+define OLD_PLT_WIND Memr[wcs_save_block+11+$1]
+
+# WL_WCSLAB -- Label using a defined wcs.
+#
+# Description
+# This routine uses the information in the WCSLAB descriptor to perform
+# labelling.
+#
+# Before this routine can be called, several things must have already
+# occured. They are as follows:
+# 1 A call to wl_create must be made to create the WCSLAB descriptor.
+# 2 The WCS_MW component must be set to the MWCS object of the
+# desired transformations.
+# 3 A call to wl_get_system_type must be made.
+# 4 The graphics device must have been opened and the window defined.
+# The WCS_GP component of the WCSLAB descriptor must be set to the
+# graphics window descriptor.
+#
+# When done with this routine, the WL_GP and WL_MW components must be
+# deallocated seperately. Then only wlab_destroy need be called to
+# remove the WCSLAB descriptor.
+#
+#---------------------------------------------------------------------------
+
+procedure wl_wcslab (wd)
+
+pointer wd # I: the WCSLAB descriptor
+
+int old_clip, old_pltype, old_txquality, old_wcs
+pointer sp, wcs_save_block
+real old_plwidth, old_txsize, old_txup
+int gstati()
+real gstatr()
+
+begin
+ # Allocate working space.
+ call smark(sp)
+ call salloc(wcs_save_block, SAVE_BLOCK_SIZE, TY_STRUCT)
+
+ # Store certain graphics parameters.
+ old_plwidth = gstatr (WL_GP(wd), G_PLWIDTH)
+ old_txsize = gstatr (WL_GP(wd), G_TXSIZE)
+ old_txup = gstatr (WL_GP(wd), G_TXUP)
+ old_clip = gstati (WL_GP(wd), G_CLIP)
+ old_pltype = gstati (WL_GP(wd), G_PLTYPE)
+ old_txquality= gstati (WL_GP(wd), G_TXQUALITY)
+ old_wcs = gstati (WL_GP(wd), G_WCS)
+
+ # Choose two other graphics wcs' for internal use. Save the wcs for
+ # later restoration.
+ if( old_wcs < MAX_WCS - 2 ) {
+ WL_NDC_WCS(wd) = old_wcs + 1
+ WL_PLOT_WCS(wd) = WL_NDC_WCS(wd) + 1
+ } else {
+ WL_NDC_WCS(wd) = old_wcs - 1
+ WL_PLOT_WCS(wd) = WL_NDC_WCS(wd) - 1
+ }
+ call gseti(WL_GP(wd), G_WCS, WL_NDC_WCS(wd))
+ call ggview(WL_GP(wd), OLD_NDC_VIEW(LEFT), OLD_NDC_VIEW(RIGHT),
+ OLD_NDC_VIEW(BOTTOM), OLD_NDC_VIEW(TOP))
+ call ggwind(WL_GP(wd), OLD_NDC_WIND(LEFT), OLD_NDC_WIND(RIGHT),
+ OLD_NDC_WIND(BOTTOM), OLD_NDC_WIND(TOP))
+ call gseti(WL_GP(wd), G_WCS, WL_PLOT_WCS(wd))
+ call ggview(WL_GP(wd), OLD_PLT_VIEW(LEFT), OLD_PLT_VIEW(RIGHT),
+ OLD_PLT_VIEW(BOTTOM), OLD_PLT_VIEW(TOP))
+ call ggwind(WL_GP(wd), OLD_PLT_WIND(LEFT), OLD_PLT_WIND(RIGHT),
+ OLD_PLT_WIND(BOTTOM), OLD_PLT_WIND(TOP))
+
+ # Set the graphics device the way wcslab requires it.
+ call gseti (WL_GP(wd), G_WCS, old_wcs)
+ call wl_graphics (wd)
+
+ # Determine basic characteristics of the plot.
+ call wl_setup (wd)
+
+ # Plot the grid lines.
+ call wl_grid (wd)
+
+ # Put the grid labels on the lines.
+ if (WL_LABON(wd) == YES)
+ call wl_label (wd)
+
+ # Restore the original graphics wcs.
+ call gseti(WL_GP(wd), G_WCS, WL_NDC_WCS(wd))
+ call gsview(WL_GP(wd), OLD_NDC_VIEW(LEFT), OLD_NDC_VIEW(RIGHT),
+ OLD_NDC_VIEW(BOTTOM), OLD_NDC_VIEW(TOP))
+ call gswind(WL_GP(wd), OLD_NDC_WIND(LEFT), OLD_NDC_WIND(RIGHT),
+ OLD_NDC_WIND(BOTTOM), OLD_NDC_WIND(TOP))
+ call gseti(WL_GP(wd), G_WCS, WL_PLOT_WCS(wd))
+ call gsview(WL_GP(wd), OLD_PLT_VIEW(LEFT), OLD_PLT_VIEW(RIGHT),
+ OLD_PLT_VIEW(BOTTOM), OLD_PLT_VIEW(TOP))
+ call gswind(WL_GP(wd), OLD_PLT_WIND(LEFT), OLD_PLT_WIND(RIGHT),
+ OLD_PLT_WIND(BOTTOM), OLD_PLT_WIND(TOP))
+
+ # Restore original graphics state.
+ call gsetr (WL_GP(wd), G_PLWIDTH, old_plwidth)
+ call gsetr (WL_GP(wd), G_TXSIZE, old_txsize)
+ call gsetr (WL_GP(wd), G_TXUP, old_txup)
+ call gseti (WL_GP(wd), G_CLIP, old_clip)
+ call gseti (WL_GP(wd), G_PLTYPE, old_pltype)
+ call gseti (WL_GP(wd), G_TXQUALITY, old_txquality)
+ call gseti (WL_GP(wd), G_WCS, old_wcs)
+
+ call sfree (sp)
+end
+
+
+# WL_GRAPHICS -- Setup the graphics device appropriate for the occasion.
+
+procedure wl_graphics (wd)
+
+pointer wd # I: the WCSLAB descriptor
+
+real relative_size, vl, vr, vb, vt
+real ggetr()
+
+begin
+ # Setup a graphics WCS that mimics the NDC coordinate WCS,
+ # but with clipping.
+ call ggview (WL_GP(wd), vl, vr, vb, vt)
+ call gseti (WL_GP(wd), G_WCS, WL_NDC_WCS(wd))
+ call gsview (WL_GP(wd), vl, vr, vb, vt)
+ call gswind (WL_GP(wd), vl, vr, vb, vt)
+ call gseti (WL_GP(wd), G_CLIP, YES)
+
+ # Setup the initial viewport.
+ WL_NEW_VIEW(wd,LEFT) = vl
+ WL_NEW_VIEW(wd,RIGHT) = vr
+ WL_NEW_VIEW(wd,BOTTOM) = vb
+ WL_NEW_VIEW(wd,TOP) = vt
+
+ # Setup some parameters.
+ call gseti (WL_GP(wd), G_PLTYPE, GL_SOLID)
+ call gsetr (WL_GP(wd), G_PLWIDTH, LINE_SIZE)
+
+ # Draw the edges of the viewport.
+ call gamove (WL_GP(wd), vl, vb)
+ call gadraw (WL_GP(wd), vr, vb)
+ call gadraw (WL_GP(wd), vr, vt)
+ call gadraw (WL_GP(wd), vl, vt)
+ call gadraw (WL_GP(wd), vl, vb)
+
+ # Determine the tick mark size.
+ relative_size = max (abs (vr - vl), abs (vt - vb ))
+ WL_MAJ_TICK_SIZE(wd) = relative_size * WL_MAJ_TICK_SIZE(wd)
+ WL_MIN_TICK_SIZE(wd) = relative_size * WL_MIN_TICK_SIZE(wd)
+
+ # Determine various character sizes.
+ WL_TITLE_SIZE(wd) = WL_TITLE_SIZE(wd) * relative_size
+ WL_AXIS_TITLE_SIZE(wd) = WL_AXIS_TITLE_SIZE(wd) * relative_size
+ WL_LABEL_SIZE(wd) = WL_LABEL_SIZE(wd) * relative_size
+
+ # Now setup the general plotting WCS.
+ call gseti (WL_GP(wd), G_WCS, WL_PLOT_WCS(WD))
+ call gsview (WL_GP(wd), vl, vr, vb, vt)
+ vl = real (WL_SCREEN_BOUNDARY(wd,LEFT))
+ vr = real (WL_SCREEN_BOUNDARY(wd,RIGHT))
+ vb = real (WL_SCREEN_BOUNDARY(wd,BOTTOM))
+ vt = real (WL_SCREEN_BOUNDARY(wd,TOP))
+ call gswind (WL_GP(wd), vl, vr, vb, vt)
+ call gseti (WL_GP(wd), G_CLIP, YES)
+
+ # Set some characteristics of the graphics device.
+ call gseti (WL_GP(wd), G_TXQUALITY, GT_HIGH)
+ call gseti (WL_GP(wd), G_CLIP, YES)
+ call gsetr (WL_GP(wd), G_PLWIDTH, LINE_SIZE)
+
+ # Determine the number of segments a "line" should consist of.
+ WL_LINE_SEGMENTS(wd) = int (min (ggetr (WL_GP(wd), "xr"),
+ ggetr (WL_GP(wd), "yr")) / 5)
+end
diff --git a/pkg/utilities/nttools/stxtools/word.x b/pkg/utilities/nttools/stxtools/word.x
new file mode 100644
index 00000000..c6b33191
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/word.x
@@ -0,0 +1,229 @@
+# Definition of delimeters used in parsing words
+
+define IS_DELIM (($1) <= ' ' || ($1) == ',')
+define NOT_DELIM (($1) > ' ' && ($1) != ',')
+
+.help
+.nf_________________________________________________________________________
+
+The procedures in this file perform simple processing on lists of
+words. These procedures count the number of words in a list, fetch
+the next word in a list, find the n-th word in a list, check for an
+exact match between a word and a list of words. A word is any group
+of contiguous characters which are neither whitespace or commas. The
+definition of whitespace is anomalous, it includes any character whose
+integer value is less than or equal to a blank. Note that words cannot
+be delimeted by quotes and that escape processing is not done.
+
+.endhelp____________________________________________________________________
+
+#______________________________HISTORY______________________________________
+#
+# B.Simon 20-Apr-1990 Modified versions of CDBS routines adb_*tok.x
+#
+#___________________________________________________________________________
+
+# WORD_COUNT -- Return the number of words in a list of words
+
+int procedure word_count (list)
+
+char list[ARB] # i: List of words
+#--
+char ch
+int count, ic
+
+begin
+
+ # The absolute value of count is the number of the current
+ # word of the list, count is negative if we are currently
+ # between words.
+
+ count = 0
+
+ # Loop over all characters in the list
+
+ for (ic = 1 ; list[ic] != EOS; ic = ic + 1) {
+ ch = list[ic]
+
+ if (count > 0) {
+ if (IS_DELIM(ch))
+ count = - count
+
+ } else if (NOT_DELIM(ch)) {
+ count = - count + 1
+ }
+ }
+
+ return (abs(count))
+end
+
+# WORD_FETCH -- Retrieve next word from string
+
+int procedure word_fetch (str, ic, word, maxch)
+
+char str[ARB] # i: String containing words
+int ic # io: Index of starting character
+char word[ARB] # o: Word string
+int maxch # i: Declared length of output string
+#--
+char ch
+int jc
+
+begin
+ # Skip leading whitespace or commas. Don't go past string terminator.
+
+ for (ch = str[ic]; IS_DELIM(ch); ch = str[ic]) {
+ if (ch == EOS)
+ break
+ ic = ic + 1
+ }
+
+ # Copy characters to word. End when maxch is reached, or
+ # when commas, whitespace, or EOS is found
+
+ for (jc = 1; jc <= maxch; jc = jc + 1) {
+ if (IS_DELIM(ch))
+ break
+
+ word[jc] = ch
+ ic = ic + 1
+ ch = str[ic]
+ }
+ word[jc] = EOS
+
+ # If loop is terminated because of maxch, eat remaining characters
+ # in field
+
+ while (NOT_DELIM(ch)) {
+ ic = ic + 1
+ ch = str[ic]
+ }
+
+ # Return number of characters in word
+
+ return (jc - 1)
+
+end
+
+# WORD_FIND -- Find the i-th word in a list of words
+
+int procedure word_find (index, list, word, maxch)
+
+int index # i: Index to word within list
+char list[ARB] # i: List of words
+char word[ARB] # o: Word returned by this procedure
+int maxch # i: Declared length of output string
+#--
+char ch
+int count, ic, jc
+
+begin
+ # The absolute value of count is the number of the current
+ # word of the list, count is negative if we are currently
+ # between words
+
+ count = 0
+
+ # Loop until i-th word is reached in list
+
+ for (ic = 1 ; count < index && list[ic] != EOS; ic = ic + 1) {
+ ch = list[ic]
+
+ if (count > 0) {
+ if (IS_DELIM(ch))
+ count = - count
+
+ } else if (NOT_DELIM(ch)) {
+ count = - count + 1
+ }
+ }
+
+ # If index is out of bounds, return zero
+
+ if (index < 0 || index > count)
+ return (0)
+
+ jc = 1
+ for (ic = ic - 1; NOT_DELIM(list[ic]); ic = ic + 1) {
+ if (jc > maxch)
+ break
+
+ word[jc] = list[ic]
+ jc = jc + 1
+ }
+ word[jc] = EOS
+
+ # Return number of characters in word
+
+ return (jc - 1)
+end
+
+# WORD_MATCH -- Return number of the word in the list which matches the word
+
+int procedure word_match (word, list)
+
+char word[ARB] # i: Word to be matched
+char list[ARB] # i: List of words
+#--
+char ch
+int match, inword, ic, jc
+
+begin
+ # The absolute value of inword is the number of the current
+ # word of the list, inword is negative if we are currently
+ # between words in the list
+
+ jc = 1
+ match = 0
+ inword = 0
+
+ # Loop over all characters in the list
+
+ for (ic = 1 ; list[ic] != EOS; ic = ic + 1) {
+ ch = list[ic]
+
+ # First case: current character is within a word
+
+ if (inword > 0) {
+
+ # Check for conversion to second case
+
+ if (IS_DELIM(ch)) {
+ inword = - inword
+
+ # Simultaneous end of word in list and word
+ # means a match has been found
+
+ if (match != 0 && word[jc] == EOS)
+ break
+ else
+ match = 0
+
+ } else if (match != 0) {
+
+ # Check for match between list and word
+
+ if (ch == word[jc])
+ jc = jc + 1
+ else
+ match = 0
+ }
+
+ # Second case: current character is between words
+ # Check for conversion to first case
+
+ } else if (NOT_DELIM(ch)) {
+ jc = 1
+ ic = ic - 1
+ inword = - inword + 1
+ match = inword
+ }
+ }
+
+ # If list ended before word, there was no match
+
+ if (word[jc] != EOS)
+ match = 0
+
+ return (match)
+end
diff --git a/pkg/utilities/nttools/stxtools/xtwcs.x b/pkg/utilities/nttools/stxtools/xtwcs.x
new file mode 100644
index 00000000..aa8b2798
--- /dev/null
+++ b/pkg/utilities/nttools/stxtools/xtwcs.x
@@ -0,0 +1,1286 @@
+include <imhdr.h>
+include <math.h>
+
+# This file contains the following high-level routines for converting
+# between world coordinates and pixel coordinates:
+#
+# xt_wcs_init initialize struct for world coordinate system
+# xt_wcs_init_c initialize from input cdelt, crota, etc
+# xt_wcs_init_cd initialize from input CD matrix, etc
+# xt_wcs_free deallocate wcs struct
+# xt_wc_pix convert from world coordinates to pixel coordinates
+# xt_pix_wc convert from pixel coordinates to world coordinates
+#
+# Phil Hodge, 27-Sept-1988 Created, based on code by Nelson & Zolt.
+# Phil Hodge, 6-April-1990 CD matrix mult. was transposed in xt_pix_wc.
+# Phil Hodge, 26-July-1991 In xt_e_ctype, change GBS to GLS (global sine).
+
+define LEN_WCS 136 # size of wcs struct for naxis <= 7
+
+define W_VALID Memi[$1] # coordinates valid, YES or NO?
+define W_NAXIS Memi[$1+1] # number of axes
+define W_RA_AX Memi[$1+2] # which axis is RA? zero if none
+define W_DEC_AX Memi[$1+3] # which axis is Dec? zero if none
+define W_PROJECTION Memi[$1+4] # projection type
+
+# 6 is currently not used
+
+# 7 - 55: full CD matrix (7x7); units = e.g. degrees
+# 56 - 104: LU decomposition of CD matrix
+# 105 - 111: index returned by ludcmp for use by lubksb
+# 112 - 118: reference pixel location
+# 119 - 122: cosine & sine of declination at the reference pixel
+# 123 - 136: coordinates at crpix; units = e.g. degrees
+
+define W_CD Memr[P2R($1+6 +($2-1)+($3-1)*7)]
+define W_CDLU Memr[P2R($1+55 +($2-1)+($3-1)*7)]
+define W_CDINDX Memr[P2R($1+104)] # this is an array of 7
+define W_CRPIX Memr[P2R($1+110+$2)]
+define W_COSDEC Memd[P2D($1+118)]
+define W_SINDEC Memd[P2D($1+120)]
+define W_CRVAL Memd[P2D($1+120)+$2]
+
+# Projection types.
+
+define W_LINEAR 0
+define W_GNOMONIC 1 # TAN
+define W_SINE 2 # SIN
+define W_ARC 3 # ARC
+define W_NORTH_POLAR 4 # NCP, north celestial pole (Westerbork)
+define W_STEREOGRAPHIC 5 # STG (conformal)
+define W_AITOFF 6 # AIT (equal-area)
+define W_GLOBAL_SINE 7 # GLS (equal-area)
+define W_MERCATOR 8 # MER (conformal)
+
+
+# xt_wcs_init -- initialize wcs struct
+# This routine allocates space for a structure describing the world
+# coordinate system for an image, fills in the values or defaults, and
+# returns a pointer to that structure.
+
+procedure xt_wcs_init (im, wcs)
+
+pointer im # i: pointer to image descriptor
+pointer wcs # o: pointer to world coord system struct
+#--
+real dummy # returned by ludcmp and ignored
+int ira, idec # index of RA, Dec axes
+int j, k # loop indexes
+errchk xt_load_ctstruct
+
+begin
+ call calloc (wcs, LEN_WCS, TY_STRUCT)
+
+ W_VALID(wcs) = YES # initial value
+ W_NAXIS(wcs) = IM_NDIM(im)
+
+ call xt_load_wcsstruct (im, wcs) # get CRVAL, etc from image
+
+ if (W_NAXIS(wcs) >= 2) {
+
+ ira = W_RA_AX(wcs)
+ idec = W_DEC_AX(wcs)
+
+ if (idec > 0) {
+ W_COSDEC(wcs) = cos (DEGTORAD(W_CRVAL(wcs,idec)))
+ W_SINDEC(wcs) = sin (DEGTORAD(W_CRVAL(wcs,idec)))
+ } else {
+ W_COSDEC(wcs) = 1.d0
+ W_SINDEC(wcs) = 0.d0
+ }
+
+ # Copy the CD matrix to W_CDLU, and do the LU decomposition
+ # on W_CDLU in-place.
+ do k = 1, IM_MAXDIM
+ do j = 1, IM_MAXDIM
+ W_CDLU(wcs,j,k) = W_CD(wcs,j,k)
+
+ iferr {
+ call ludcmp (W_CDLU(wcs,1,1), W_NAXIS(wcs), IM_MAXDIM,
+ W_CDINDX(wcs), dummy)
+ } then {
+ call mfree (wcs, TY_STRUCT)
+ call error (0, "xt_wcs_init: cd matrix is singular")
+ }
+ }
+end
+
+
+# xt_wcs_free -- deallocate wcs struct
+# This routine deallocates space for a wcs structure.
+
+procedure xt_wcs_free (wcs)
+
+pointer wcs # io: pointer to world coord system struct
+#--
+
+begin
+ if (wcs != NULL)
+ call mfree (wcs, TY_STRUCT)
+end
+
+
+# xt_wcs_init_c -- initialize wcs struct
+# xt_wcs_init_c and xt_wcs_init_cd allocate space for a structure
+# describing the world coordinate system for an image, fill in the values
+# or defaults, and return a pointer to that structure. They differ from
+# xt_wcs_init in that these take the coordinate parameters as arguments
+# rather than getting them from the image.
+# xt_wcs_init_c takes cdelt & crota, and xt_wcs_init_cd takes the CD matrix.
+
+procedure xt_wcs_init_c (crval, crpix, cdelt, crota, ctype, naxis, wcs)
+
+double crval[naxis] # i: coordinate values at reference pixel
+real crpix[naxis] # i: reference pixel
+real cdelt[naxis] # i: pixel spacing
+real crota # i: rotation angle (if 2-D)
+char ctype[SZ_CTYPE,naxis] # i: e.g. "RA---TAN"
+int naxis # i: size of arrays
+pointer wcs # o: pointer to world coord system struct
+#--
+real dummy # returned by ludcmp and ignored
+int ira, idec # index of RA, Dec axes
+int j, k # loop indexes
+errchk ludcmp
+
+begin
+ do k = 1, naxis
+ if (cdelt[k] == 0.)
+ call error (0, "xt_wcs_init_c: zero value of CDELT")
+
+ call calloc (wcs, LEN_WCS, TY_STRUCT)
+
+ W_NAXIS(wcs) = naxis
+ W_VALID(wcs) = YES # initial value
+
+ # Examine ctype to get ira, idec, proj_type.
+ call xt_e_ctype (ctype, naxis, ira, idec, W_PROJECTION(wcs))
+ W_RA_AX(wcs) = ira
+ W_DEC_AX(wcs) = idec
+
+ do k = 1, naxis {
+ W_CRVAL(wcs,k) = crval[k]
+ W_CRPIX(wcs,k) = crpix[k]
+ }
+ do k = naxis+1, IM_MAXDIM {
+ W_CRVAL(wcs,k) = 0.d0
+ W_CRPIX(wcs,k) = 1.
+ }
+
+ if (naxis == 1) {
+
+ W_CD(wcs,1,1) = cdelt[1]
+
+ } else if (naxis >= 2) {
+
+ if (idec > 0) {
+ W_COSDEC(wcs) = cos (DEGTORAD(W_CRVAL(wcs,idec)))
+ W_SINDEC(wcs) = sin (DEGTORAD(W_CRVAL(wcs,idec)))
+ } else {
+ W_COSDEC(wcs) = 1.d0
+ W_SINDEC(wcs) = 0.d0
+ }
+
+ # Convert cdelt & crota to the CD matrix.
+ call xt_to_cd (wcs, cdelt, crota, naxis)
+
+ # Copy the CD matrix, and do the LU decomposition on W_CDLU.
+ do k = 1, IM_MAXDIM
+ do j = 1, IM_MAXDIM
+ W_CDLU(wcs,j,k) = W_CD(wcs,j,k)
+
+ call ludcmp (W_CDLU(wcs,1,1), naxis, IM_MAXDIM,
+ W_CDINDX(wcs), dummy)
+ }
+end
+
+
+# xt_wcs_init_cd -- initialize wcs struct (CD)
+
+procedure xt_wcs_init_cd (crval, crpix, cd, ctype, naxis, wcs)
+
+double crval[naxis] # i: coordinate values at reference pixel
+real crpix[naxis] # i: reference pixel
+real cd[naxis,naxis] # i: CD matrix
+char ctype[SZ_CTYPE,naxis] # i: e.g. "RA---TAN"
+int naxis # i: size of arrays
+pointer wcs # o: pointer to world coord system struct
+#--
+real dummy # returned by ludcmp and ignored
+int ira, idec # index of RA, Dec axes
+int j, k # loop indexes
+
+begin
+ call calloc (wcs, LEN_WCS, TY_STRUCT)
+
+ W_NAXIS(wcs) = naxis
+ W_VALID(wcs) = YES # initial value
+
+ # Examine ctype to get ira, idec, proj_type.
+ call xt_e_ctype (ctype, naxis, ira, idec, W_PROJECTION(wcs))
+ W_RA_AX(wcs) = ira
+ W_DEC_AX(wcs) = idec
+
+ do k = 1, naxis {
+ W_CRVAL(wcs,k) = crval[k]
+ W_CRPIX(wcs,k) = crpix[k]
+ }
+ do k = naxis+1, IM_MAXDIM {
+ W_CRVAL(wcs,k) = 0.d0
+ W_CRPIX(wcs,k) = 1.
+ }
+
+ if (naxis == 1) {
+
+ W_CD(wcs,1,1) = cd[1,1]
+
+ } else if (naxis >= 2) {
+
+ if (idec > 0) {
+ W_COSDEC(wcs) = cos (DEGTORAD(W_CRVAL(wcs,idec)))
+ W_SINDEC(wcs) = sin (DEGTORAD(W_CRVAL(wcs,idec)))
+ } else {
+ W_COSDEC(wcs) = 1.d0
+ W_SINDEC(wcs) = 0.d0
+ }
+
+ # Assign initial values to the CD matrix.
+ do k = 1, IM_MAXDIM {
+ do j = 1, IM_MAXDIM {
+ if (j == k) {
+ W_CD(wcs,k,k) = 1.
+ W_CDLU(wcs,k,k) = 1.
+ } else {
+ W_CD(wcs,j,k) = 0.
+ W_CDLU(wcs,j,k) = 0.
+ }
+ }
+ }
+
+ # Copy the CD matrix, and do the LU decomposition on W_CDLU.
+ do k = 1, naxis {
+ do j = 1, naxis {
+ W_CD(wcs,j,k) = cd[j,k]
+ W_CDLU(wcs,j,k) = cd[j,k]
+ }
+ }
+
+ iferr {
+ call ludcmp (W_CDLU(wcs,1,1), naxis, IM_MAXDIM,
+ W_CDINDX(wcs), dummy)
+ } then {
+ call mfree (wcs, TY_STRUCT)
+ call error (0, "xt_wcs_init_cd: cd matrix is singular")
+ }
+ }
+end
+
+# xt_to_cd -- from cdelt & crota to cd matrix
+# This routine computes the CD matrix from CDELT and CROTA.
+
+procedure xt_to_cd (wcs, cdelt, crota, naxis)
+
+pointer wcs # i: pointer to world coord system struct
+real cdelt[naxis] # i: pixel spacing
+real crota # i: rotation angle (if 2-D)
+int naxis # i: size of arrays
+#--
+real cosrota, sinrota # cosine & sine of crota
+real sign_cdelt[2] # one, with sign of cdelt1 or cdelt2
+int ira, idec # index of RA, Dec axes
+int j, k # loop indexes
+
+begin
+ ira = W_RA_AX(wcs)
+ idec = W_DEC_AX(wcs)
+
+ if ( ! IS_INDEFD(crota) ) {
+ cosrota = cos (DEGTORAD(crota))
+ sinrota = sin (DEGTORAD(crota))
+ } else {
+ cosrota = 1.d0
+ sinrota = 0.d0
+ }
+
+ # Initial values for CD matrix.
+ do k = 1, IM_MAXDIM {
+ do j = 1, IM_MAXDIM {
+ if (j == k)
+ W_CD(wcs,k,k) = 1.
+ else
+ W_CD(wcs,j,k) = 0.
+ }
+ }
+ do k = 1, naxis
+ W_CD(wcs,k,k) = cdelt[k]
+
+ if (ira > 0 && idec > 0) {
+
+ if (cdelt[ira] >= 0.)
+ sign_cdelt[1] = 1.
+ else
+ sign_cdelt[1] = -1.
+
+ if (cdelt[idec] >= 0.)
+ sign_cdelt[2] = 1.
+ else
+ sign_cdelt[2] = -1.
+
+ W_CD(wcs,ira,ira) = cdelt[ira] * cosrota
+ W_CD(wcs,ira,idec) = abs (cdelt[idec]) * sign_cdelt[1] * sinrota
+ W_CD(wcs,idec,ira) = -abs (cdelt[ira]) * sign_cdelt[2] * sinrota
+ W_CD(wcs,idec,idec) = cdelt[idec] * cosrota
+ }
+end
+
+# xt_e_ctype -- examine ctype
+# Examine each element of the ctype array to find which axes (if any)
+# are RA & Dec (or glon & glat, etc). Also get the projection type,
+# such as gnomonic, if this was specified in ctype.
+
+procedure xt_e_ctype (ctype, naxis, ra_axis, dec_axis, proj_type)
+
+char ctype[SZ_CTYPE,naxis] # i: coordinate type, e.g. "RA---TAN"
+int naxis # i: dimension
+int ra_axis # o: which axis is RA (or glon, etc)?
+int dec_axis # o: which axis is Dec (or glat, etc)?
+int proj_type # o: type of projection
+#--
+char lctype[SZ_CTYPE] # local copy of an element of ctype
+char dash # '-'
+int k
+int index # index of '-' in ctype
+int strncmp(), strldx()
+
+begin
+ # Assign defaults.
+ ra_axis = 0
+ dec_axis = 0
+ if (naxis == 1)
+ proj_type = W_LINEAR
+ else
+ proj_type = W_GNOMONIC
+
+ # Search for "RA", "DEC", etc.
+ do k = 1, naxis {
+ # Make a local copy of ctype & make sure it's upper case.
+ call strcpy (ctype[1,k], lctype, SZ_CTYPE)
+ call strupr (lctype)
+
+ if (strncmp (lctype, "RA", 2) == 0)
+ ra_axis = k
+ else if (strncmp (lctype, "DEC", 3) == 0)
+ dec_axis = k
+
+ else if (strncmp (lctype, "GLON", 4) == 0)
+ ra_axis = k
+ else if (strncmp (lctype, "LL", 2) == 0)
+ ra_axis = k
+ else if (strncmp (lctype, "UU", 2) == 0)
+ ra_axis = k
+ else if (strncmp (lctype, "ELON", 4) == 0)
+ ra_axis = k
+
+ else if (strncmp (lctype, "GLAT", 4) == 0)
+ dec_axis = k
+ else if (strncmp (lctype, "MM", 2) == 0)
+ dec_axis = k
+ else if (strncmp (lctype, "VV", 2) == 0)
+ dec_axis = k
+ else if (strncmp (lctype, "ELAT", 4) == 0)
+ dec_axis = k
+ }
+
+ if (ra_axis > 0)
+ k = ra_axis
+ else if (dec_axis > 0)
+ k = dec_axis
+ else
+ k = 0
+
+ # If at least one of the axes is like RA or Dec, check to see
+ # whether a projection type was specified.
+ if (k > 0) {
+ dash = '-'
+ index = strldx (dash, lctype)
+ if (index > 0) {
+ index = index + 1
+ if (strncmp (lctype[index], "TAN", 3) == 0)
+ proj_type = W_GNOMONIC
+ else if (strncmp (lctype[index], "SIN", 3) == 0)
+ proj_type = W_SINE
+ else if (strncmp (lctype[index], "ARC", 3) == 0)
+ proj_type = W_ARC
+ else if (strncmp (lctype[index], "NCP", 3) == 0)
+ proj_type = W_NORTH_POLAR
+ else if (strncmp (lctype[index], "STG", 3) == 0)
+ proj_type = W_STEREOGRAPHIC
+ else if (strncmp (lctype[index], "AIT", 3) == 0)
+ proj_type = W_AITOFF
+ else if (strncmp (lctype[index], "GLS", 3) == 0)
+ proj_type = W_GLOBAL_SINE
+ else if (strncmp (lctype[index], "MER", 3) == 0)
+ proj_type = W_MERCATOR
+ }
+ }
+end
+
+
+define SZ_PNAME 8
+
+# xt_load_wcsstruct -- load coordinate information
+# Get the coordinate information from the image, and load
+# that info into the wcs structure.
+
+procedure xt_load_wcsstruct (im, wcs)
+
+pointer im # i: pointer to image header struct
+pointer wcs # i: pointer to world coord system struct
+#--
+char pname[SZ_PNAME]
+char ctype[SZ_CTYPE,IM_MAXDIM]
+int naxis, iax # dimension of image; loop index for axis
+bool cdm_found # true if CD matrix present in image
+int imaccf()
+double imgetd()
+real imgetr()
+errchk imgstr, imgetd, imgetr, xt_g_cd_matrix, xt_c_cd_matrix
+
+begin
+ naxis = IM_NDIM(im)
+
+ # Get the coordinate info. If anything is missing set W_VALID to NO.
+ do iax = 1, naxis {
+
+ # CTYPE for each axis.
+ call sprintf (pname, SZ_PNAME, "ctype%d")
+ call pargi (iax)
+ if (imaccf (im, pname) == YES) {
+ call imgstr (im, pname, ctype[1,iax], SZ_CTYPE)
+ } else {
+ call strcpy ("PIXEL", ctype[1,iax], SZ_CTYPE)
+ W_VALID(wcs) = NO
+ }
+
+ # CRVAL for each axis
+ call sprintf (pname, SZ_PNAME, "crval%d")
+ call pargi (iax)
+ if (imaccf (im, pname) == YES) {
+ W_CRVAL(wcs,iax) = imgetd (im, pname)
+ } else {
+ W_CRVAL(wcs,iax) = 0.d0
+ W_VALID(wcs) = NO
+ }
+
+ # CRPIX for each axis
+ call sprintf (pname, SZ_PNAME, "crpix%d")
+ call pargi (iax)
+ if (imaccf (im, pname) == YES) {
+ W_CRPIX(wcs,iax) = imgetr (im, pname)
+ } else {
+ W_CRPIX(wcs,iax) = 1.
+ W_VALID(wcs) = NO
+ }
+ }
+ # Assign reasonable values to the unused elements.
+ do iax = naxis+1, IM_MAXDIM {
+ W_CRVAL(wcs,iax) = 0.d0
+ W_CRPIX(wcs,iax) = 1.
+ }
+
+ # Examine ctype array.
+ call xt_e_ctype (ctype, naxis,
+ W_RA_AX(wcs), W_DEC_AX(wcs), W_PROJECTION(wcs))
+
+ # First try to get the CD matrix, and if it isn't there
+ # get CDELT and CROTA and convert to CD.
+
+ call xt_g_cd_matrix (im, wcs, naxis, cdm_found)
+
+ if ( ! cdm_found )
+ call xt_c_cd_matrix (im, wcs, naxis)
+end
+
+
+# xt_g_cd_matrix -- get CD matrix
+# If the CD matrix is present, get the values and place them into the
+# wcs structure. Note that we assume that if *any* of the CD matrix
+# parameters are there, they are *all* there.
+
+define TOLER 1.e-5
+
+procedure xt_g_cd_matrix (im, wcs, naxis, cdm_found)
+
+pointer im # i: image pointer
+pointer wcs # i: pointer to wcs structure
+int naxis # i: number of axes in image
+bool cdm_found # o: true if CD matrix found
+#--
+real cd_matrix[IM_MAXDIM,IM_MAXDIM] # the CD matrix
+char pname[SZ_PNAME]
+int i, j
+int imaccf()
+real imgetr()
+errchk imgetr
+
+begin
+ # This is reset below if any element of the CD matrix is found.
+ cdm_found = false
+
+ # Assign default values.
+ do j = 1, IM_MAXDIM
+ do i= 1, IM_MAXDIM
+ if (i == j)
+ cd_matrix[i,j] = 1.
+ else
+ cd_matrix[i,j] = 0.
+
+ # Get each element of the CD matrix.
+ do j = 1, naxis {
+ do i = 1, naxis {
+ call sprintf (pname, SZ_PNAME, "cd%d_%d")
+ call pargi (i)
+ call pargi (j)
+ if (imaccf (im, pname) == YES) {
+ cd_matrix[i,j] = imgetr (im, pname)
+ cdm_found = true
+ }
+ }
+ }
+
+ # Copy to the wcs structure.
+ do j = 1, IM_MAXDIM
+ do i = 1, IM_MAXDIM
+ W_CD(wcs,i,j) = cd_matrix[i,j]
+end
+
+
+# xt_c_cd_matrix -- create CD matrix
+# If the CD matrix is not present, get the values of CDELT & CROTA,
+# convert to the CD matrix, and store the values in the wcs structure.
+# Since this is called after trying unsuccessfully to get the CD matrix,
+# if cdelt or crota is not present W_VALID will be reset to NO.
+
+procedure xt_c_cd_matrix (im, wcs, naxis)
+
+pointer im # i: image pointer
+pointer wcs # i: pointer to wcs structure
+int naxis # i: number of axes in image
+#--
+char pname[SZ_PNAME] # parameter name (e.g. "cdelt1")
+real cdelt[IM_MAXDIM] # pixel spacing
+real crota # rotation angle in degrees
+int k # loop index for axis
+int imaccf()
+real imgetr()
+errchk imgetr
+
+begin
+ do k = 1, naxis {
+
+ # CDELT for each axis.
+ call sprintf (pname, SZ_PNAME, "cdelt%d")
+ call pargi (k)
+ if (imaccf (im, pname) == YES) {
+ cdelt[k] = imgetr (im, pname)
+ if (cdelt[k] == 0.)
+ call error (0, "xt_c_cd_matrix: cdelt is zero")
+ } else {
+ cdelt[k] = 1.
+ W_VALID(wcs) = NO
+ }
+ }
+
+ # For a 1-D image, assign CD1_1 and return.
+ if (naxis == 1) {
+ W_CD(wcs,1,1) = cdelt[1]
+ return
+ }
+
+ # CROTA (only one).
+ call strcpy ("crota1", pname, SZ_PNAME)
+ if (imaccf (im, pname) == YES) {
+ crota = imgetr (im, pname)
+ } else {
+ crota = 0.
+ W_VALID(wcs) = NO
+ }
+
+ # Compute CD matrix from CDELT & CROTA.
+ call xt_to_cd (wcs, cdelt, crota, naxis)
+end
+
+
+# xt_wc_pix -- wcs to pixels
+# This routine converts world coordinates to pixel coordinates.
+#
+# In the 1-D case, CRVAL is subtracted from the coordinate, the
+# result is divided by CDELT (same as CD1_1), and CRPIX is added.
+#
+# For 2-D or higher dimension, if two of the axes are like RA and Dec,
+# the input coordinates are converted to standard coordinates Xi
+# and Eta. The (Xi, Eta) vector is then multiplied on the left by
+# the inverse of the CD matrix, and CRPIX is added.
+# The units for axes like Ra & Dec are degrees, not hours or radians.
+# For linear axes the conversion is the same as for 1-D.
+
+procedure xt_wc_pix (wcs, phys, pix, naxis)
+
+pointer wcs # i: pointer to world coord system struct
+double phys[naxis] # i: physical (world) coordinates (e.g. degrees)
+real pix[naxis] # o: pixel coordinates
+int naxis # i: size of arrays
+#--
+double delta_ra # RA of object - RA at reference pixel
+double dra_r, dec_r # delta_ra & declination in radians
+double xi_r, eta_r # xi & eta in radians
+real dphys[IM_MAXDIM] # phys coord - reference coord
+int ira, idec # index of RA, Dec axes
+int k # loop index
+errchk xt_wp_ncp, xt_wp_mer
+
+begin
+ do k = 1, naxis
+ dphys[k] = phys[k] - W_CRVAL(wcs,k)
+
+ if (naxis == 1) {
+
+ pix[1] = dphys[1] / W_CD(wcs,1,1) + W_CRPIX(wcs,1)
+
+ } else {
+
+ ira = W_RA_AX(wcs)
+ idec = W_DEC_AX(wcs)
+
+ # Convert RA & Dec to Xi & Eta (standard coordinates).
+ if (ira > 0 && idec > 0) {
+
+ delta_ra = phys[ira] - W_CRVAL(wcs,ira) # double prec
+ dra_r = DEGTORAD (delta_ra)
+ dec_r = DEGTORAD (phys[idec])
+
+ switch (W_PROJECTION(wcs)) {
+ case W_GNOMONIC:
+ call xt_wp_tan (wcs, dra_r, dec_r, xi_r, eta_r)
+ case W_SINE:
+ call xt_wp_sin (wcs, dra_r, dec_r, xi_r, eta_r)
+ case W_ARC:
+ call xt_wp_arc (wcs, dra_r, dec_r, xi_r, eta_r)
+ case W_NORTH_POLAR:
+ call xt_wp_ncp (wcs, dra_r, dec_r, xi_r, eta_r)
+ case W_STEREOGRAPHIC:
+ call xt_wp_stg (wcs, dra_r, dec_r, xi_r, eta_r)
+ case W_AITOFF:
+ call xt_wp_ait (wcs, dra_r, dec_r, xi_r, eta_r)
+ case W_GLOBAL_SINE:
+ call xt_wp_gls (wcs, dra_r, dec_r, xi_r, eta_r)
+ case W_MERCATOR:
+ call xt_wp_mer (wcs, dra_r, dec_r, xi_r, eta_r)
+ }
+
+ dphys[ira] = RADTODEG (xi_r) # xi, eta in degrees
+ dphys[idec] = RADTODEG (eta_r)
+ }
+
+ # Use LU backsubstitution to get pixel coords from physical coords.
+ call lubksb (W_CDLU(wcs,1,1), naxis, IM_MAXDIM,
+ W_CDINDX(wcs), dphys) # dphys is modified in-place
+ do k = 1, naxis
+ pix[k] = dphys[k] + W_CRPIX(wcs,k) # copy to output
+ }
+end
+
+
+# xt_pix_wc -- pixels to wcs
+# This routine converts pixel coordinates to world coordinates.
+#
+# In the 1-D case, CRPIX is subtracted from the pixel coordinate,
+# the result is multiplied by CDELT (same as CD1_1), and CRVAL is added.
+#
+# For 2-D or higher dimension, CRPIX is subtracted, and the result is
+# multiplied on the left by the CD matrix. If two of the axes are like
+# RA and Dec, the pixel coordinates are converted to standard coordinates
+# Xi and Eta. The (xi, eta) vector is then converted to differences
+# between RA and Dec and CRVAL, and then CRVAL is added to each coordinate.
+
+procedure xt_pix_wc (wcs, pix, phys, naxis)
+
+pointer wcs # i: pointer to world coord system struct
+real pix[naxis] # i: pixel coordinates
+double phys[naxis] # o: physical (world) coordinates
+int naxis # i: size of arrays
+#--
+double dpix[IM_MAXDIM] # pix coord - crpix
+double sum # for matrix multiplication
+double dra_r, dec_r # delta_ra & declination in radians
+double xi_r, eta_r # xi & eta in radians
+int ira, idec # index of RA, Dec axes
+int j, k # loop indexes
+
+begin
+ do k = 1, naxis
+ dpix[k] = pix[k] - W_CRPIX(wcs,k)
+
+ if (naxis == 1) {
+
+ phys[1] = dpix[1] * W_CD(wcs,1,1) + W_CRVAL(wcs,1)
+
+ } else {
+
+ do j = 1, naxis {
+ sum = 0.d0
+ do k = 1, naxis
+ sum = sum + W_CD(wcs,j,k) * dpix[k]
+ phys[j] = sum
+ }
+
+ ira = W_RA_AX(wcs)
+ idec = W_DEC_AX(wcs)
+
+ # Convert Xi & Eta (standard coordinates) to RA & Dec.
+ if (ira > 0 && idec > 0) {
+ xi_r = DEGTORAD (phys[ira])
+ eta_r = DEGTORAD (phys[idec])
+
+ switch (W_PROJECTION(wcs)) {
+ case W_GNOMONIC:
+ call xt_pw_tan (wcs, xi_r, eta_r, dra_r, dec_r)
+ case W_SINE:
+ call xt_pw_sin (wcs, xi_r, eta_r, dra_r, dec_r)
+ case W_ARC:
+ call xt_pw_arc (wcs, xi_r, eta_r, dra_r, dec_r)
+ case W_NORTH_POLAR:
+ call xt_pw_ncp (wcs, xi_r, eta_r, dra_r, dec_r)
+ case W_STEREOGRAPHIC:
+ call xt_pw_stg (wcs, xi_r, eta_r, dra_r, dec_r)
+ case W_AITOFF:
+ call xt_pw_ait (wcs, xi_r, eta_r, dra_r, dec_r)
+ case W_GLOBAL_SINE:
+ call xt_pw_gls (wcs, xi_r, eta_r, dra_r, dec_r)
+ case W_MERCATOR:
+ call xt_pw_mer (wcs, xi_r, eta_r, dra_r, dec_r)
+ }
+
+ phys[idec] = RADTODEG (dec_r)
+ phys[ira] = RADTODEG (dra_r) + W_CRVAL(wcs,ira)
+ if (phys[ira] < 0.d0)
+ phys[ira] = phys[ira] + 360.d0
+ }
+ do k = 1, naxis
+ if (k != ira && k != idec)
+ phys[k] = phys[k] + W_CRVAL(wcs,k)
+ }
+end
+
+
+# xt_wp_tan -- convert from ra & dec using gnomonic projection
+
+procedure xt_wp_tan (wcs, dra_r, dec_r, xi_r, eta_r)
+
+pointer wcs # i: pointer to world coord system struct
+double dra_r # i: RA of object - RA at reference pixel (radians)
+double dec_r # i: declination of object (radians)
+double xi_r # o: standard coordinate (radians)
+double eta_r # o: standard coordinate (radians)
+#--
+double cosdra, sindra # cos & sin of dra_r
+double cosdec, sindec # cos & sin of object declination
+double cosdist # cos of dist from ref pixel to object
+
+begin
+ cosdra = cos (dra_r)
+ sindra = sin (dra_r)
+
+ cosdec = cos (dec_r)
+ sindec = sin (dec_r)
+
+ cosdist = sindec * W_SINDEC(wcs) + cosdec * W_COSDEC(wcs) * cosdra
+
+ xi_r = cosdec * sindra / cosdist
+ eta_r = (sindec * W_COSDEC(wcs) -
+ cosdec * W_SINDEC(wcs) * cosdra) / cosdist
+end
+
+
+# xt_pw_tan -- convert to ra & dec using gnomonic projection
+# In rectangular coordinates the vector (1, xi, eta) points toward
+# the object; the origin is the observer's location, the x-axis points
+# toward the reference pixel, the y-axis is in the direction of increasing
+# right ascension, and the z-axis is in the direction of increasing
+# declination. The coordinate system is then rotated by the declination so
+# the x-axis passes through the equator at the RA of the reference pixel;
+# the components of the vector in this coordinate system are used to
+# compute (RA - reference_RA) and declination.
+
+procedure xt_pw_tan (wcs, xi_r, eta_r, dra_r, dec_r)
+
+pointer wcs # i: pointer to world coord system struct
+double xi_r # i: standard coordinate (radians)
+double eta_r # i: standard coordinate (radians)
+double dra_r # o: RA of object - RA at reference pixel (radians)
+double dec_r # o: declination of object (radians)
+#--
+double x, y, z # vector (not unit length) pointing toward object
+
+begin
+ # Rotate the rectangular coordinate system of the vector (1, xi, eta)
+ # by the declination so the x-axis will pass through the equator.
+ x = W_COSDEC(wcs) - eta_r * W_SINDEC(wcs)
+ y = xi_r
+ z = W_SINDEC(wcs) + eta_r * W_COSDEC(wcs)
+
+ if (x == 0.d0 && y == 0.d0)
+ dra_r = 0.d0
+ else
+ dra_r = atan2 (y, x)
+ dec_r = atan2 (z, sqrt (x*x + y*y))
+end
+
+
+# xt_wp_sin -- convert from ra & dec using sine projection
+#
+# Reference: AIPS Memo No. 27 by Eric W. Greisen
+
+procedure xt_wp_sin (wcs, dra_r, dec_r, xi_r, eta_r)
+
+pointer wcs # i: pointer to world coord system struct
+double dra_r # i: RA of object - RA at reference pixel (radians)
+double dec_r # i: declination of object (radians)
+double xi_r # o: standard coordinate (radians)
+double eta_r # o: standard coordinate (radians)
+#--
+double cosdra, sindra # cos & sin of delta_ra
+double cosdec, sindec # cos & sin of object declination
+
+begin
+ cosdra = cos (dra_r)
+ sindra = sin (dra_r)
+
+ cosdec = cos (dec_r)
+ sindec = sin (dec_r)
+
+ xi_r = cosdec * sindra
+ eta_r = sindec * W_COSDEC(wcs) - cosdec * W_SINDEC(wcs) * cosdra
+end
+
+
+# xt_pw_sin -- convert to ra & dec using sine projection
+# In rectangular coordinates the vector (v1, xi, eta), where
+# v1 = sqrt (1 - xi**2 - eta**2), is the location of the object on the
+# unit celestial sphere. The x-axis points toward the reference pixel,
+# the y-axis is in the direction of increasing right ascension, and the
+# z-axis is in the direction of increasing declination. The coordinate
+# system is then rotated (around the y-axis) by the declination so the
+# x-axis passes through the equator at the RA of the reference pixel;
+# the components of the vector in this coordinate system are used to
+# compute (RA - reference_RA) and declination.
+
+procedure xt_pw_sin (wcs, xi_r, eta_r, dra_r, dec_r)
+
+pointer wcs # i: pointer to world coord system struct
+double xi_r # i: standard coordinate (radians)
+double eta_r # i: standard coordinate (radians)
+double dra_r # o: RA of object - RA at reference pixel (radians)
+double dec_r # o: declination of object (radians)
+#--
+double v1 # x component of unit vector
+double x, y, z # unit vector with x[1] pointing toward equator
+
+begin
+ v1 = sqrt (1.d0 - xi_r*xi_r - eta_r*eta_r)
+
+ # Rotate the rectangular coordinate system of the vector (v1, xi, eta)
+ # by the declination so the x-axis will pass through the equator.
+ x = v1 * W_COSDEC(wcs) - eta_r * W_SINDEC(wcs)
+ y = xi_r
+ z = v1 * W_SINDEC(wcs) + eta_r * W_COSDEC(wcs)
+
+ if (x == 0.d0 && y == 0.d0)
+ dra_r = 0.d0
+ else
+ dra_r = atan2 (y, x)
+ dec_r = atan2 (z, sqrt (x*x + y*y))
+end
+
+
+# xt_wp_arc -- convert from ra & dec using arc projection
+#
+# Reference: AIPS Memo No. 27 by Eric W. Greisen
+
+procedure xt_wp_arc (wcs, dra_r, dec_r, xi_r, eta_r)
+
+pointer wcs # i: pointer to world coord system struct
+double dra_r # i: RA of object - RA at reference pixel (radians)
+double dec_r # i: declination of object (radians)
+double xi_r # o: standard coordinate (radians)
+double eta_r # o: standard coordinate (radians)
+#--
+double cosdra, sindra # cos & sin of delta_ra
+double cosdec, sindec # cos & sin of object declination
+double theta # distance (radians) from ref pixel to object
+double r # theta / sin (theta)
+
+begin
+ cosdra = cos (dra_r)
+ sindra = sin (dra_r)
+
+ cosdec = cos (dec_r)
+ sindec = sin (dec_r)
+
+ theta = acos (sindec * W_SINDEC(wcs) + cosdec * W_COSDEC(wcs) * cosdra)
+ if (theta == 0.d0)
+ r = 1.d0
+ else
+ r = theta / sin (theta)
+
+ xi_r = r * cosdec * sindra
+ eta_r = r * (sindec * W_COSDEC(wcs) - cosdec * W_SINDEC(wcs) * cosdra)
+end
+
+
+# xt_pw_arc -- convert to ra & dec using arc projection
+# The rectangular coordinates of the pixel on a unit celestial sphere
+# are computed in a coordinate system such that the x-axis points toward
+# the reference pixel, the y-axis is in the direction of increasing right
+# ascension, and the z-axis is in the direction of increasing declination.
+# The coordinate system is then rotated (around the y-axis) by the
+# declination so the x-axis passes through the equator at the RA of the
+# reference pixel; the components of the vector in this coordinate system
+# are used to compute (RA - reference_RA) and declination.
+
+procedure xt_pw_arc (wcs, xi_r, eta_r, dra_r, dec_r)
+
+pointer wcs # i: pointer to world coord system struct
+double xi_r # i: standard coordinate (radians)
+double eta_r # i: standard coordinate (radians)
+double dra_r # o: RA of object - RA at reference pixel (radians)
+double dec_r # o: declination of object (radians)
+#--
+double theta # arc length, i.e. sqrt (xi**2 + eta**2)
+double v[3] # unit vector with v[1] pointing toward ref pixel
+double x, y, z # vector with x[1] pointing toward equator
+
+begin
+ theta = sqrt (xi_r*xi_r + eta_r*eta_r)
+ if (theta == 0.d0) {
+ v[1] = 1.d0
+ v[2] = 0.d0
+ v[3] = 0.d0
+ } else {
+ v[1] = cos (theta)
+ v[2] = sin (theta) / theta * xi_r
+ v[3] = sin (theta) / theta * eta_r
+ }
+
+ # Rotate the rectangular coordinate system of the vector v by the
+ # declination so the x-axis will pass through the equator.
+ x = v[1] * W_COSDEC(wcs) - v[3] * W_SINDEC(wcs)
+ y = v[2]
+ z = v[1] * W_SINDEC(wcs) + v[3] * W_COSDEC(wcs)
+
+ if (x == 0.d0 && y == 0.d0)
+ dra_r = 0.d0
+ else
+ dra_r = atan2 (y, x)
+ dec_r = atan2 (z, sqrt (x*x + y*y))
+end
+
+
+# xt_wp_ncp -- convert from ra & dec using ncp projection
+#
+# References:
+# AIPS Memo No. 27 by Eric W. Greisen
+# Data Processing for the Westerbork Synthesis Radio Telescope
+# by W. N. Brouw
+
+procedure xt_wp_ncp (wcs, dra_r, dec_r, xi_r, eta_r)
+
+pointer wcs # i: pointer to world coord system struct
+double dra_r # i: RA of object - RA at reference pixel (radians)
+double dec_r # i: declination of object (radians)
+double xi_r # o: standard coordinate (radians)
+double eta_r # o: standard coordinate (radians)
+#--
+double cosdra, sindra # cos & sin of delta_ra
+double cosdec # cos of object declination
+
+begin
+ if (W_SINDEC(wcs) == 0.)
+ call error (1, "NCP projection: dec is zero")
+
+ cosdra = cos (dra_r)
+ sindra = sin (dra_r)
+
+ cosdec = cos (dec_r)
+
+ xi_r = - cosdec * sindra
+ eta_r = (W_COSDEC(wcs) - cosdec * cosdra) / W_SINDEC(wcs)
+end
+
+
+# xt_pw_ncp -- convert to ra & dec using ncp projection
+#
+# References:
+# AIPS Memo No. 27 by Eric W. Greisen
+# Data Processing for the Westerbork Synthesis Radio Telescope
+# by W. N. Brouw
+
+procedure xt_pw_ncp (wcs, xi_r, eta_r, dra_r, dec_r)
+
+pointer wcs # i: pointer to world coord system struct
+double xi_r # i: standard coordinate (radians)
+double eta_r # i: standard coordinate (radians)
+double dra_r # o: RA of object - RA at reference pixel (radians)
+double dec_r # o: declination of object (radians)
+#--
+double temp
+
+begin
+ temp = W_COSDEC(wcs) - eta_r * W_SINDEC(wcs)
+
+ dra_r = atan2 (-xi_r, temp)
+ dec_r = acos (temp / cos (dra_r))
+ if (W_SINDEC(wcs) < 0)
+ dec_r = -dec_r
+end
+
+
+# xt_wp_gls -- convert from ra & dec using global-sine projection
+#
+# Reference: AIPS Memo No. 46 by Eric W. Greisen
+
+procedure xt_wp_gls (wcs, dra_r, dec_r, xi_r, eta_r)
+
+pointer wcs # i: pointer to world coord system struct
+double dra_r # i: RA of object - RA at reference pixel (radians)
+double dec_r # i: declination of object (radians)
+double xi_r # o: standard coordinate (radians)
+double eta_r # o: standard coordinate (radians)
+#--
+double cosdec # cos of object declination
+double temp # delta RA
+int idec # which axis is declination axis
+
+begin
+ cosdec = cos (dec_r)
+ idec = W_DEC_AX(wcs)
+
+ temp = dra_r
+
+ # Put dra_r on the interval (-180,+180] degrees.
+ if (temp <= -PI)
+ temp = temp + TWOPI
+ if (temp > PI)
+ temp = temp - TWOPI
+
+ xi_r = temp * cosdec
+
+ if (idec > 0)
+ eta_r = dec_r - DEGTORAD (W_CRVAL(wcs,idec))
+ else
+ eta_r = dec_r
+end
+
+
+# xt_pw_gls -- convert to ra & dec using global-sine projection
+#
+# Reference: AIPS Memo No. 46 by Eric W. Greisen
+
+procedure xt_pw_gls (wcs, xi_r, eta_r, dra_r, dec_r)
+
+pointer wcs # i: pointer to world coord system struct
+double xi_r # i: standard coordinate (radians)
+double eta_r # i: standard coordinate (radians)
+double dra_r # o: RA of object - RA at reference pixel (radians)
+double dec_r # o: declination of object (radians)
+#--
+double cosdec # cosine of object declination
+int idec # which axis is declination axis
+
+begin
+ idec = W_DEC_AX(wcs)
+ if (idec > 0)
+ dec_r = eta_r + DEGTORAD (W_CRVAL(wcs,idec))
+ else
+ dec_r = eta_r
+
+ cosdec = cos (dec_r)
+ if (cosdec > 0.d0)
+ dra_r = xi_r / cosdec
+ else
+ dra_r = 0.d0
+end
+
+# xt_wp_stg -- convert from ra & dec using stereographic projection
+#
+# Reference: AIPS Memo No. 46 by Eric W. Greisen
+
+procedure xt_wp_stg (wcs, dra_r, dec_r, xi_r, eta_r)
+
+pointer wcs # i: pointer to world coord system struct
+double dra_r # i: RA of object - RA at reference pixel (radians)
+double dec_r # i: declination of object (radians)
+double xi_r # o: standard coordinate (radians)
+double eta_r # o: standard coordinate (radians)
+#--
+double cosdra, sindra # cos & sin of dra_r
+double cosdec, sindec # cos & sin of object declination
+double cosdist # cos of dist from ref pixel to object
+double sincos # sin (theta) * cos (phi)
+
+begin
+ cosdra = cos (dra_r)
+ sindra = sin (dra_r)
+
+ cosdec = cos (dec_r)
+ sindec = sin (dec_r)
+
+ cosdist = sindec * W_SINDEC(wcs) + cosdec * W_COSDEC(wcs) * cosdra
+ sincos = sindec * W_COSDEC(wcs) - cosdec * W_SINDEC(wcs) * cosdra
+
+ xi_r = 2.d0 * cosdec * sindra / (1.d0 + cosdist)
+ eta_r = 2.d0 * sincos / (1.d0 + cosdist)
+end
+
+
+# xt_pw_stg -- convert to ra & dec using stereographic projection
+
+procedure xt_pw_stg (wcs, xi_r, eta_r, dra_r, dec_r)
+
+pointer wcs # i: pointer to world coord system struct
+double xi_r # i: standard coordinate (radians)
+double eta_r # i: standard coordinate (radians)
+double dra_r # o: RA of object - RA at reference pixel (radians)
+double dec_r # o: declination of object (radians)
+#--
+double rho2 # square of distance from reference pixel
+double scale # factor to reduce xi, eta to y, z
+double x, y, z # unit vector toward object
+double temp
+
+begin
+ rho2 = xi_r * xi_r + eta_r * eta_r
+
+ x = (4.d0 - rho2) / (4.d0 + rho2)
+ scale = (x + 1.d0) / 2.d0
+
+ y = xi_r * scale
+ z = eta_r * scale
+
+ temp = x * W_COSDEC(wcs) - z * W_SINDEC(wcs)
+ z = x * W_SINDEC(wcs) + z * W_COSDEC(wcs)
+ x = temp
+
+ if (x == 0.d0 && y == 0.d0)
+ dra_r = 0.d0
+ else
+ dra_r = atan2 (y, x)
+ dec_r = atan2 (z, sqrt (x*x + y*y))
+end
+
+
+# xt_wp_ait -- convert from ra & dec using Aitoff projection
+#
+# Note that the declination at the reference pixel is ignored and is
+# assumed to be zero. The algorithms given in the AIPS reference do
+# allow for a non-zero declination at the reference pixel.
+#
+# Reference: AIPS Memo No. 46 by Eric W. Greisen
+
+procedure xt_wp_ait (wcs, dra_r, dec_r, xi_r, eta_r)
+
+pointer wcs # i: pointer to world coord system struct
+double dra_r # i: RA of object - RA at reference pixel (radians)
+double dec_r # i: declination of object (radians)
+double xi_r # o: standard coordinate (radians)
+double eta_r # o: standard coordinate (radians)
+#--
+double z # temp variable
+double cosdec # cosine of declination
+
+begin
+ cosdec = cos (dec_r)
+ z = sqrt ((1.d0 + cosdec * cos (dra_r/2.d0)) / 2.d0)
+
+ xi_r = 2.d0 * cosdec * sin (dra_r/2.d0) / z
+ eta_r = sin (dec_r) / z
+end
+
+
+# xt_pw_ait -- convert to ra & dec using Aitoff projection
+#
+# Note that the declination at the reference pixel is ignored and is
+# assumed to be zero. The algorithms given in the AIPS reference do
+# allow for a non-zero declination at the reference pixel.
+#
+# Reference: AIPS Memo No. 46 by Eric W. Greisen
+
+procedure xt_pw_ait (wcs, xi_r, eta_r, dra_r, dec_r)
+
+pointer wcs # i: pointer to world coord system struct
+double xi_r # i: standard coordinate (radians)
+double eta_r # i: standard coordinate (radians)
+double dra_r # o: RA of object - RA at reference pixel (radians)
+double dec_r # o: declination of object (radians)
+#--
+double z # temp variable
+double cosdec # cosine of declination
+
+begin
+ z = sqrt (1.d0 - xi_r*xi_r/16.d0 - eta_r*eta_r/4.d0)
+
+ dec_r = asin (eta_r * z)
+ cosdec = cos (dec_r)
+
+ if (cosdec > 0.d0) {
+ dra_r = 2.d0 * asin (xi_r * z / (2.d0 * cosdec))
+ } else {
+ dra_r = 0.d0
+ }
+end
+
+
+# xt_wp_mer -- convert from ra & dec using Mercator projection
+#
+# Note that the declination at the reference pixel is ignored and is
+# assumed to be zero. The algorithms given in the AIPS reference do
+# allow for a non-zero declination at the reference pixel.
+#
+# Reference: AIPS Memo No. 46 by Eric W. Greisen
+
+procedure xt_wp_mer (wcs, dra_r, dec_r, xi_r, eta_r)
+
+pointer wcs # i: pointer to world coord system struct
+double dra_r # i: RA of object - RA at reference pixel (radians)
+double dec_r # i: declination of object (radians)
+double xi_r # o: standard coordinate (radians)
+double eta_r # o: standard coordinate (radians)
+#--
+double temp
+
+begin
+ xi_r = dra_r
+ temp = (dec_r + HALFPI) / 2.d0
+ if (temp >= HALFPI || temp <= 0.d0)
+ call error (1, "invalid declination for Mercator projection")
+ eta_r = log (tan (temp))
+end
+
+
+# xt_pw_mer -- convert to ra & dec using Mercator projection
+#
+# Reference: AIPS Memo No. 46 by Eric W. Greisen
+
+procedure xt_pw_mer (wcs, xi_r, eta_r, dra_r, dec_r)
+
+pointer wcs # i: pointer to world coord system struct
+double xi_r # i: standard coordinate (radians)
+double eta_r # i: standard coordinate (radians)
+double dra_r # o: RA of object - RA at reference pixel (radians)
+double dec_r # o: declination of object (radians)
+#--
+
+begin
+ dra_r = xi_r
+ dec_r = 2.d0 * atan (exp (eta_r)) - HALFPI
+end
diff --git a/pkg/utilities/nttools/tabim.par b/pkg/utilities/nttools/tabim.par
new file mode 100644
index 00000000..f7188f5f
--- /dev/null
+++ b/pkg/utilities/nttools/tabim.par
@@ -0,0 +1,11 @@
+intable,s,a,"",,,"input table"
+output,s,a,"",,,"output image"
+colname,s,a,"",,,"column name"
+ndim,i,a,1,0,7,"dimension of image"
+n1,i,a,1,1,,"size of first axis"
+n2,i,a,1,1,,"size of second axis"
+n3,i,a,1,1,,"size of third axis"
+n4,i,a,1,1,,"size of fourth axis"
+n5,i,a,1,1,,"size of fifth axis"
+n6,i,a,1,1,,"size of sixth axis"
+mode,s,h,"al"
diff --git a/pkg/utilities/nttools/tabkey.par b/pkg/utilities/nttools/tabkey.par
new file mode 100644
index 00000000..57168a7b
--- /dev/null
+++ b/pkg/utilities/nttools/tabkey.par
@@ -0,0 +1,7 @@
+table,f,a,"",,,"Name of table"
+column,s,a,"",,,"Name of column"
+row,i,a,,1,,"Number of row"
+output,f,a,"",,,"Name of file containing header keyword"
+keyword,s,a,"",,,"Name of header keyword"
+add,b,h,no,,,"Is it OK to create a new keyword?"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/tabpar.par b/pkg/utilities/nttools/tabpar.par
new file mode 100644
index 00000000..496ec498
--- /dev/null
+++ b/pkg/utilities/nttools/tabpar.par
@@ -0,0 +1,7 @@
+table,f,a,"",,,"Name of table"
+column,s,a,"",,,"Name of column"
+row,i,a,,1,,"Number of row"
+format,b,h,yes,,,"Format the value using table print format?"
+value,s,h,"",,,"Value of table element"
+undef,b,h,,,,"Is table element undefined?"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/tabvar.com b/pkg/utilities/nttools/tabvar.com
new file mode 100644
index 00000000..417e75d4
--- /dev/null
+++ b/pkg/utilities/nttools/tabvar.com
@@ -0,0 +1,9 @@
+# TCALC.COM -- Common block used for comunicating btw tcalc and tabvar
+
+double nullval # Substituted for null columns in expressions
+pointer tabptr # Table descriptor
+int firstrow # First row to evaluate
+int lastrow # Last row to evaluate
+
+common /tcalc/ nullval, tabptr, firstrow, lastrow
+
diff --git a/pkg/utilities/nttools/taextract.par b/pkg/utilities/nttools/taextract.par
new file mode 100644
index 00000000..ca8a6704
--- /dev/null
+++ b/pkg/utilities/nttools/taextract.par
@@ -0,0 +1,10 @@
+intable,s,a,"",,,"name of input table"
+outtable,s,a,"",,,"name of output table"
+row,i,a,,1,,"input row number"
+column,s,a,"",,,"column name"
+outcolumn,s,a,"",,,"name to use for column in output table"
+datatype,s,h,"",,,"data type for new column"
+colunits,s,h,"",,,"units for new column"
+colfmt,s,h,"",,,"print format for new column"
+Version,s,h,"30Jan1998",,,"date of installation"
+mode,s,h,"al"
diff --git a/pkg/utilities/nttools/tainsert.par b/pkg/utilities/nttools/tainsert.par
new file mode 100644
index 00000000..d6b24194
--- /dev/null
+++ b/pkg/utilities/nttools/tainsert.par
@@ -0,0 +1,11 @@
+intable,s,a,"",,,"name of input table"
+outtable,s,a,"",,,"name of output table"
+row,i,a,-1,,,"output row number"
+column,s,a,"",,,"column name"
+outcolumn,s,a,"",,,"name to use for column in output table"
+size,i,h,INDEF,,,"length of array in output table"
+datatype,s,h,"",,,"data type for new column"
+colunits,s,h,"",,,"units for new column"
+colfmt,s,h,"",,,"print format for new column"
+Version,s,h,"30Jan1998",,,"date of installation"
+mode,s,h,"al"
diff --git a/pkg/utilities/nttools/tcalc.par b/pkg/utilities/nttools/tcalc.par
new file mode 100644
index 00000000..b3ae6977
--- /dev/null
+++ b/pkg/utilities/nttools/tcalc.par
@@ -0,0 +1,7 @@
+table,f,a,,,,"Input table"
+outcol,s,a,,,,"Output column name"
+equals,s,a,,"",,"Arithmetic expression"
+datatype,s,h,"real","real|double|short|int",,"Output column data type, if new column"
+colunits,s,h,"",,,"Units for output column"
+colfmt,s,h,"",,,"Display format for output column"
+mode,s,h,al
diff --git a/pkg/utilities/nttools/tcalc/mkpkg b/pkg/utilities/nttools/tcalc/mkpkg
new file mode 100644
index 00000000..d2fa96b9
--- /dev/null
+++ b/pkg/utilities/nttools/tcalc/mkpkg
@@ -0,0 +1,11 @@
+# Update the tcalc application code in the ttools package library
+# Author: Bernie Simon, 04-Nov-91
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ tcalc.x "../tabvar.com" <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/tcalc/tcalc.x b/pkg/utilities/nttools/tcalc/tcalc.x
new file mode 100644
index 00000000..854df2e3
--- /dev/null
+++ b/pkg/utilities/nttools/tcalc/tcalc.x
@@ -0,0 +1,132 @@
+include <tbset.h>
+define HARMLESS 0.1d0
+define MAXROWS 10000
+
+# T_TCALC -- perform arithmetic operation on columns of a table
+#
+# B.Simon 03-May-91 Original
+# B.Simon 24-Jun-97 Long columns done in pieces
+# B.Simon 16-Jul-97 Error message for string columns
+# B.Simon 30-Mar-00 Allow wild cards in table names
+
+procedure t_tcalc()
+
+#--
+pointer table # input/output table name
+pointer outcol # output column
+pointer equals # expression
+pointer colunits # output col units
+pointer colfmt # output col format
+pointer datatype # output col datatype
+
+include "../tabvar.com"
+
+bool done
+double nil
+pointer sp, tp, list, buffer, colptr, code
+int nrows, nbuf, coltype, exptype
+
+string badtype "Invalid data type for output column"
+
+int tbnget(), tbpsta(), tbcigi()
+pointer tbnopenp(), tbtopn(), vex_compile()
+
+extern tabvar
+
+begin
+ call smark (sp)
+ call salloc (table, SZ_FNAME, TY_CHAR)
+ call salloc (outcol, SZ_FNAME, TY_CHAR)
+ call salloc (equals, SZ_FNAME, TY_CHAR)
+ call salloc (datatype, SZ_FNAME, TY_CHAR)
+ call salloc (colunits, SZ_FNAME, TY_CHAR)
+ call salloc (colfmt, SZ_FNAME, TY_CHAR)
+
+ list = tbnopenp ("table")
+ call clgstr ("outcol", Memc[outcol], SZ_FNAME)
+ call clgstr ("equals", Memc[equals], SZ_FNAME)
+
+ code = vex_compile (Memc[equals])
+
+ while (tbnget (list, Memc[table], SZ_FNAME) != EOF) {
+ tp = tbtopn (Memc[table], READ_WRITE, 0)
+ nrows = tbpsta (tp, TBL_NROWS)
+
+ call tbcfnd (tp, Memc[outcol], colptr, 1)
+ if (colptr != NULL) {
+ coltype = tbcigi (colptr, TBL_COL_DATATYPE)
+
+ } else {
+ call clgstr ("datatype", Memc[datatype], SZ_FNAME)
+ call clgstr ("colunits", Memc[colunits], SZ_FNAME)
+ call clgstr ("colfmt" , Memc[colfmt], SZ_FNAME)
+
+ switch (Memc[datatype]) {
+ case 'r':
+ coltype = TY_REAL
+ case 'd':
+ coltype = TY_DOUBLE
+ case 's':
+ coltype = TY_SHORT
+ case 'i':
+ coltype = TY_INT
+ default:
+ call tbtclo (tp)
+ call error (1, badtype)
+ }
+
+ call tbbftp (Memc[colfmt], Memc[colfmt])
+ call tbcdef (tp, colptr, Memc[outcol], Memc[colunits],
+ Memc[colfmt], coltype, 1, 1)
+ }
+
+ # Initialize common block used by tabvar()
+
+ tabptr = tp
+ firstrow = 1
+ lastrow = MAXROWS
+ nullval = HARMLESS
+
+ done = false
+ nil = HARMLESS
+
+ repeat {
+ if (lastrow >= nrows) {
+ done = true
+ lastrow = nrows
+ }
+
+ nbuf = (lastrow - firstrow) + 1
+ call vex_eval (code, tabvar, nil, exptype)
+
+ switch (coltype) {
+ case TY_SHORT, TY_INT, TY_LONG:
+ call malloc (buffer, nbuf, TY_INT)
+ call vex_copyi (code, INDEFI, Memi[buffer], nbuf)
+ call tbcpti (tp, colptr, Memi[buffer], firstrow, lastrow)
+ call mfree (buffer, TY_INT)
+ case TY_REAL:
+ call malloc (buffer, nbuf, TY_REAL)
+ call vex_copyr (code, INDEFR, Memr[buffer], nbuf)
+ call tbcptr (tp, colptr, Memr[buffer], firstrow, lastrow)
+ call mfree (buffer, TY_REAL)
+ case TY_DOUBLE:
+ call malloc (buffer, nbuf, TY_DOUBLE)
+ call vex_copyd (code, INDEFD, Memd[buffer], nbuf)
+ call tbcptd (tp, colptr, Memd[buffer], firstrow, lastrow)
+ call mfree (buffer, TY_DOUBLE)
+ default:
+ call tbtclo (tp)
+ call error (1, badtype)
+ }
+
+ firstrow = firstrow + MAXROWS
+ lastrow = lastrow + MAXROWS
+ } until (done)
+
+ call tbtclo(tp)
+ }
+
+ call vex_free (code)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tchcol.par b/pkg/utilities/nttools/tchcol.par
new file mode 100644
index 00000000..9dc14a99
--- /dev/null
+++ b/pkg/utilities/nttools/tchcol.par
@@ -0,0 +1,7 @@
+table,s,a,"",,,"tables to be modified in-place"
+oldname,s,a,"",,,"current column name"
+newname,s,a,"",,,"new column name, or null"
+newfmt,s,a,"",,,"new print format for column, or null"
+newunits,s,a,"",,,"new column units, or null"
+verbose,b,h,yes,,,"print operations performed?"
+mode,s,h,"al"
diff --git a/pkg/utilities/nttools/tchcol/mkpkg b/pkg/utilities/nttools/tchcol/mkpkg
new file mode 100644
index 00000000..dce427be
--- /dev/null
+++ b/pkg/utilities/nttools/tchcol/mkpkg
@@ -0,0 +1,20 @@
+# MKPKG file for the tchcol task
+# Author: J.-C. Hsu 08-Dec-87
+#
+# Special keywords recognized by standard SDAS mkpkg files:
+#
+# mkpkg debug=yes link ttools executable with the debugger
+# mkpkg linkonly skip ttools library update and just link
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+linkonly:
+ $call linkonly@..
+ ;
+
+libpkg.a:
+ tchcol.x <ctype.h> <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/tchcol/tchcol.x b/pkg/utilities/nttools/tchcol/tchcol.x
new file mode 100644
index 00000000..c7a1c985
--- /dev/null
+++ b/pkg/utilities/nttools/tchcol/tchcol.x
@@ -0,0 +1,162 @@
+include <ctype.h> # for IS_WHITE
+include <tbset.h>
+
+# tchcol -- change column information
+# This task can be used to change the name, print format, and/or units
+# for one column of a list of tables. If any of the new values is null
+# or blank, the value will not be changed. If the value is "default"
+# for format or units, the value will be changed to the default.
+# For units the default is null.
+#
+# J.-C. HSU, 11-Jul-1987 design and coding
+# Phil Hodge, 15-Mar-1989 rewrite in spp
+# Phil Hodge, 10-Apr-1990 change SZ_COLNAME to SZ_FNAME, etc for clgstr
+# Phil Hodge, 10-May-1991 allow multiple input tables;
+# use "default" to set format or units to the default
+# Phil Hodge, 18-Jun-1993 preserve case of newfmt to allow e.g. %12.1H
+# Phil Hodge, 11-Aug-1993 print warning if text table and user has
+# requested a change of column name or units
+# Phil Hodge, 3-Oct-1995 Modify to use tbn instead of fnt.
+# Phil Hodge, 7-Jun-1999 Delete warning messages for text tables
+# (this undoes the change made on 11-Aug-1993).
+# Phil Hodge, 30-Sep-1999 Remove trailing blanks from new name, units, format.
+
+procedure tchcol()
+
+pointer tp # pointer to table descriptor
+pointer cp # pointer to column descriptor
+pointer ilist # for list of tables to change
+char table[SZ_FNAME] # table name
+char oldname[SZ_COLNAME] # column name before being changed
+char newname[SZ_COLNAME] # new column name or ""
+char oldfmt[SZ_COLFMT] # print format before being changed
+char newfmt[SZ_COLFMT] # new column print format or "default"
+char newf[SZ_COLFMT] # new spp style print format or ""
+char oldunits[SZ_COLUNITS] # column units before being changed
+char newunits[SZ_COLUNITS] # new column units or "default"
+char newu[SZ_COLUNITS] # new column units or ""
+char newval[SZ_COLUNITS] # actual new value of format or units in table
+bool verbose # if true, tell user what's happening
+int i, strlen() # for stripping off trailing blanks
+pointer tbtopn()
+pointer tbnopenp()
+int tbnget()
+bool clgetb(), streq()
+
+begin
+ ilist = tbnopenp ("table")
+ call clgstr ("oldname", oldname, SZ_COLNAME)
+ call clgstr ("newname", newname, SZ_COLNAME)
+ call clgstr ("newfmt", newfmt, SZ_COLFMT)
+ call clgstr ("newunits", newunits, SZ_COLUNITS)
+ verbose = clgetb ("verbose")
+
+ # Remove leading whitespace from new values.
+ call xt_stripwhite (newname)
+ call xt_stripwhite (newfmt)
+ call xt_stripwhite (newunits)
+
+ # Remove trailing whitespace from new values.
+ do i = strlen (newname), 1, -1 {
+ if (IS_WHITE(newname[i]))
+ newname[i] = EOS
+ else
+ break
+ }
+ do i = strlen (newfmt), 1, -1 {
+ if (IS_WHITE(newfmt[i]))
+ newfmt[i] = EOS
+ else
+ break
+ }
+ do i = strlen (newunits), 1, -1 {
+ if (IS_WHITE(newunits[i]))
+ newunits[i] = EOS
+ else
+ break
+ }
+
+ if (newname[1] == EOS && newfmt[1] == EOS && newunits[1] == EOS) {
+ call eprintf ("no change specified\n")
+ call tbnclose (ilist)
+ return
+ }
+
+ # Check for "default" for format or units, and copy to newf & newu.
+
+ call strcpy (newfmt, newf, SZ_COLFMT)
+ call strlwr (newf) # preserve case of newfmt
+ if (streq (newf, "default"))
+ newf[1] = EOS
+ else
+ call tbbftp (newfmt, newf) # convert from Fortran style
+
+ call strcpy (newunits, newu, SZ_COLUNITS)
+ call strlwr (newu)
+ if (streq (newu, "default"))
+ newu[1] = EOS
+ else
+ call strcpy (newunits, newu, SZ_COLUNITS) # preserve case
+
+ # Process all the tables in the list.
+ while (tbnget (ilist, table, SZ_FNAME) != EOF) {
+
+ if (verbose) {
+ call printf ("table %s\n")
+ call pargstr (table)
+ }
+
+ tp = tbtopn (table, READ_WRITE, NULL)
+
+ call tbcfnd (tp, oldname, cp, 1)
+ if (cp == NULL) {
+ call tbtclo (tp)
+ if ( ! verbose ) {
+ call printf ("table %s\n")
+ call pargstr (table)
+ }
+ call printf (" warning: column `%s' not found\n")
+ call pargstr (oldname)
+ next
+ }
+
+ if (newname[1] != EOS) {
+ call tbcnam (tp, cp, newname)
+ if (verbose) {
+ call printf (" column name changed from `%s' to `%s'\n")
+ call pargstr (oldname)
+ call pargstr (newname)
+ }
+ }
+
+ # newf may be EOS even if newfmt is not.
+ if (newfmt[1] != EOS) {
+ call tbcigt (cp, TBL_COL_FMT, oldfmt, SZ_COLFMT)
+ call tbcfmt (tp, cp, newf)
+ if (verbose) {
+ call tbcigt (cp, TBL_COL_FMT, newval, SZ_COLUNITS)
+ call printf (" print format changed from `%s' to `%s'\n")
+ call pargstr (oldfmt)
+ call pargstr (newval)
+ }
+ }
+
+ # newu may be EOS even if newunits is not.
+ if (newunits[1] != EOS) {
+ call tbcigt (cp, TBL_COL_UNITS, oldunits, SZ_COLUNITS)
+ call tbcnit (tp, cp, newu)
+ if (verbose) {
+ call tbcigt (cp, TBL_COL_UNITS, newval, SZ_COLUNITS)
+ call printf (" column units changed from `%s' to `%s'\n")
+ call pargstr (oldunits)
+ call pargstr (newval)
+ }
+ }
+
+ call tbtclo (tp)
+
+ if (verbose) # added 8/11/93
+ call flush (STDOUT)
+ }
+ call tbnclose (ilist)
+end
diff --git a/pkg/utilities/nttools/tcheck.par b/pkg/utilities/nttools/tcheck.par
new file mode 100644
index 00000000..4304221c
--- /dev/null
+++ b/pkg/utilities/nttools/tcheck.par
@@ -0,0 +1,3 @@
+input,s,a,,,,Table name(s)
+chkfile,s,a,,,,Text file containing consistency checks
+mode, s, h, 'a',,,
diff --git a/pkg/utilities/nttools/tcheck/cmdsplit.x b/pkg/utilities/nttools/tcheck/cmdsplit.x
new file mode 100644
index 00000000..7fa7e714
--- /dev/null
+++ b/pkg/utilities/nttools/tcheck/cmdsplit.x
@@ -0,0 +1,57 @@
+include "tcheck.h"
+
+# CMDSPLIT -- Split a command into keyword and expression strings
+
+procedure cmdsplit (command, keystart, cmdstart)
+
+char command[ARB] # io: Command line
+int keystart # o: Start of keyword substring
+int cmdstart # o: Start of command substring
+#--
+char comment
+int ic, jc
+pointer sp, keyword
+
+data comment / '#' /
+
+string noexpress "No expression following when"
+
+bool streq()
+int stridx(), word_fetch()
+
+begin
+ call smark (sp)
+ call salloc (keyword, SZ_FNAME, TY_CHAR)
+
+ # Strip comments from command line
+
+ ic = stridx (comment, command)
+ if (ic > 0)
+ command[ic] = EOS
+
+ # Set output variables to default values
+
+ keystart = 1
+ cmdstart = 0
+
+ # Find location of "when" in command and split the line there
+
+ ic = 1
+ jc = 0
+ while (word_fetch (command, ic, Memc[keyword], SZ_FNAME) > 0) {
+ if (jc > 0 && streq (Memc[keyword], "when")) {
+ command[jc] = EOS
+ cmdstart = ic
+ break
+ }
+ jc = ic
+ }
+
+ # Exit with error if no expression was found
+
+ if (cmdstart == 0 && jc > 0)
+ call error (SYNTAX, noexpress)
+
+ call sfree (sp)
+end
+
diff --git a/pkg/utilities/nttools/tcheck/mkpkg b/pkg/utilities/nttools/tcheck/mkpkg
new file mode 100644
index 00000000..a5a0812b
--- /dev/null
+++ b/pkg/utilities/nttools/tcheck/mkpkg
@@ -0,0 +1,13 @@
+# Update the tcheck application code in the ttools package library
+# Author: B.Simon, 22-AUG-1990
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ cmdsplit.x "tcheck.h"
+ tcheck.x <tbset.h> "tcheck.h"
+ wrtcheck.x
+ ;
diff --git a/pkg/utilities/nttools/tcheck/tcheck.h b/pkg/utilities/nttools/tcheck/tcheck.h
new file mode 100644
index 00000000..6f08cede
--- /dev/null
+++ b/pkg/utilities/nttools/tcheck/tcheck.h
@@ -0,0 +1,4 @@
+# TCHECK.H -- Symbolic constants used by tcheck
+
+define SYNTAX 1 # Syntax errors in evexpr
+
diff --git a/pkg/utilities/nttools/tcheck/tcheck.x b/pkg/utilities/nttools/tcheck/tcheck.x
new file mode 100644
index 00000000..e23408e0
--- /dev/null
+++ b/pkg/utilities/nttools/tcheck/tcheck.x
@@ -0,0 +1,91 @@
+include <tbset.h>
+include "tcheck.h"
+
+# TCHECK -- Perform a consistency check on the rows of a table
+#
+# B.Simon 20-Aug-90 Original
+# B.Simon 29-Jul-92 Fixed bug occuring when irow > nrow
+# Phil Hodge 4-Oct-95 Use table name template routines tbnopenp, etc.
+
+procedure tcheck ()
+
+#--
+pointer input # Table file name template
+pointer chkfile # Text file containing consistency checks
+
+bool title
+int fd, iline, nc
+int keystart, cmdstart, irow, jrow, nrow
+pointer sp, tabname, errmsg, command, tp
+
+string badexpr "Syntax error: %s"
+
+int open(), tbnget(), getlongline()
+int tbpsta(), strlen(), tbl_search()
+pointer tbnopenp(), tbtopn()
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (chkfile, SZ_FNAME, TY_CHAR)
+ call salloc (tabname, SZ_FNAME, TY_CHAR)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+ call salloc (command, SZ_COMMAND, TY_CHAR)
+
+ # Read the task parameters
+
+ input = tbnopenp ("input")
+ call clgstr ("chkfile", Memc[chkfile], SZ_FNAME)
+
+ fd = open (Memc[chkfile], READ_ONLY, TEXT_FILE)
+
+ # Check each table
+
+ while (tbnget (input, Memc[tabname], SZ_FNAME) != EOF) {
+ call seek (fd, BOF)
+ tp = tbtopn (Memc[tabname], READ_ONLY, NULL)
+ nrow = tbpsta (tp, TBL_NROWS)
+ title = true
+
+ # Get each line from the command file
+
+ repeat {
+ nc = getlongline (fd, Memc[command], SZ_COMMAND, iline)
+ if (nc <= 0)
+ break
+
+ Memc[command+nc-1] = EOS
+ call cmdsplit (Memc[command], keystart, cmdstart)
+ if (cmdstart > 0) {
+ irow = 1
+ while (irow <= nrow) {
+ jrow = tbl_search (tp, Memc[command+cmdstart-1],
+ irow, nrow)
+ if (jrow == 0) {
+ break
+
+ } else if (jrow == ERR) {
+ call xer_reset
+ if (strlen (Memc[command+cmdstart-1]) > 60)
+ call strcat (" ...", Memc[command+cmdstart+60],
+ SZ_COMMAND)
+
+ call sprintf (Memc[errmsg], SZ_LINE, badexpr)
+ call pargstr (Memc[command+cmdstart-1])
+ call error (SYNTAX, Memc[errmsg])
+
+ } else {
+ call wrt_check (tp, jrow, Memc[command+keystart-1],
+ Memc[command+cmdstart-1], title)
+ irow = jrow + 1
+ }
+ }
+ }
+ }
+ call tbtclo (tp)
+ }
+
+ call tbnclose (input)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tcheck/wrtcheck.x b/pkg/utilities/nttools/tcheck/wrtcheck.x
new file mode 100644
index 00000000..b14ec542
--- /dev/null
+++ b/pkg/utilities/nttools/tcheck/wrtcheck.x
@@ -0,0 +1,61 @@
+# WRT_CHECK -- Write the table values that pass the check
+
+procedure wrt_check (tp, irow, keylist, command, title)
+
+pointer tp # i: Table descriptor
+int irow # i: Table row number
+char keylist[ARB] # i: List of keywords to print
+char command[ARB] # io: Expression used in check
+bool title # io: Print title?
+#--
+int ic
+pointer sp, tabname, ldir, keyword, newcmd, value, root, col
+
+int fnldir(), gstrcpy(), word_fetch()
+
+begin
+ call smark (sp)
+ call salloc (tabname, SZ_FNAME, TY_CHAR)
+ call salloc (ldir, SZ_FNAME, TY_CHAR)
+ call salloc (keyword, SZ_FNAME, TY_CHAR)
+ call salloc (newcmd, SZ_FNAME, TY_CHAR)
+ call salloc (value, SZ_LINE, TY_CHAR)
+
+ # Print title if this is the first error found in this table
+
+ if (title) {
+ title = false
+ call tbtnam (tp, Memc[tabname], SZ_FNAME)
+ root = tabname + fnldir (Memc[tabname], Memc[ldir], SZ_FNAME)
+
+ call printf ("#\n#%11t%-60s\n#\n")
+ call pargstr (Memc[root])
+ }
+
+ # Truncate command to 60 characters
+
+ if (gstrcpy (command, Memc[newcmd], 60) == 60)
+ call strcat (" ...", Memc[newcmd], SZ_FNAME)
+
+ # Print each keyword name, value, and associated command
+
+ ic = 1
+ while (word_fetch (keylist, ic, Memc[keyword], SZ_FNAME) > 0) {
+ call tbcfnd (tp, Memc[keyword], col, 1)
+ if (col != NULL) {
+ call tbegtt (tp, col, irow, Memc[value], SZ_LINE)
+
+ call printf ("%-5d%-20s%-20s%-30s\n")
+ call pargi (irow)
+ call pargstr (Memc[keyword])
+ call pargstr (Memc[value])
+ call pargstr (Memc[newcmd])
+
+ } else {
+ call printf ("%-5d%-20s missing\n")
+ call pargi (irow)
+ call pargstr (Memc[keyword])
+ }
+ }
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tchsize.par b/pkg/utilities/nttools/tchsize.par
new file mode 100644
index 00000000..24e1d013
--- /dev/null
+++ b/pkg/utilities/nttools/tchsize.par
@@ -0,0 +1,8 @@
+intable,s,a,"",,,"input tables"
+outtable,s,a,"",,,"output tables or directory"
+maxpar,i,a,-1,,,"new maximum number of header parameters"
+maxcols,i,a,-1,,,"new maximum space for column descriptors"
+rowlen,i,a,-1,,,"new row length"
+allrows,i,a,-1,,,"new allocated number of rows"
+verbose,b,h,yes,,,"print operations performed?"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/tchsize/mkpkg b/pkg/utilities/nttools/tchsize/mkpkg
new file mode 100644
index 00000000..3459a3f5
--- /dev/null
+++ b/pkg/utilities/nttools/tchsize/mkpkg
@@ -0,0 +1,11 @@
+# Update the tchsize application code in the ttools package library
+# Author: HODGE, 2-FEB-1988
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ tchsize.x <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/tchsize/tchsize.x b/pkg/utilities/nttools/tchsize/tchsize.x
new file mode 100644
index 00000000..89a53293
--- /dev/null
+++ b/pkg/utilities/nttools/tchsize/tchsize.x
@@ -0,0 +1,173 @@
+include <tbset.h>
+
+# tchsize -- Change size of table(s)
+
+# The input tables are given by an filename template list. The output
+# is either a matching list of tables or a directory. The number of
+# input tables may be either one or match the number of output tables.
+# This is based on the t_imcopy procedure.
+#
+# NOTE: If task is used on a FITS table, it will be skipped.
+#
+# Phil Hodge, 28-Aug-1987 Task created.
+# Phil Hodge, 7-Sep-1988 Change parameter names for tables.
+# Phil Hodge, 26-Mar-1992 Remove calls to tbtext.
+# Phil Hodge, 3-Oct-1995 Modify to use tbn instead of fnt; check for FITS.
+# Phil hodge, 16-Apr-1999 Call tbttyp instead of tbparse.
+
+procedure tchsize()
+
+char tablist1[SZ_LINE] # Input table list
+char tablist2[SZ_LINE] # Output table list
+bool verbose # Print operations?
+int maxpar # new max number of user (header) parameters
+int maxcols # new max space for column descriptors
+int rowlen # new row length (for row-ordered tables)
+int allrows # new allocated number of rows (for col-ordered)
+#--
+int ttype, exists, tbttyp() # to check for a FITS table (exists is ignored)
+
+pointer tp # Pointer to table descriptor
+char table1[SZ_PATHNAME] # Input table name
+char table2[SZ_PATHNAME] # Output table name
+char dirname1[SZ_PATHNAME] # Directory name
+char dirname2[SZ_PATHNAME] # Directory name
+
+pointer list1, list2
+int root_len
+
+pointer tbtopn()
+pointer tbnopen()
+int tbnget(), tbnlen()
+int fnldir(), isdirectory()
+int clgeti()
+bool clgetb(), streq()
+
+begin
+ # Get input and output table template lists.
+ call clgstr ("intable", tablist1, SZ_LINE)
+ call clgstr ("outtable", tablist2, SZ_LINE)
+
+ # Get new values of table size parameters.
+ maxpar = clgeti ("maxpar")
+ maxcols = clgeti ("maxcols")
+ rowlen = clgeti ("rowlen") * SZ_REAL
+ allrows = clgeti ("allrows")
+
+ verbose = clgetb ("verbose")
+
+ # Check whether the output string is blank.
+ if (tablist2[1] == EOS) {
+
+ # Expand the input table list, and change the sizes in-place.
+ list1 = tbnopen (tablist1)
+
+ while (tbnget (list1, table1, SZ_PATHNAME) != EOF) {
+
+ # Check for a FITS table.
+ ttype = tbttyp (table1, exists)
+ if (ttype == TBL_TYPE_FITS) {
+ call eprintf ("Skipping FITS table %s\n")
+ call pargstr (table1)
+ next
+ }
+
+ if (verbose) {
+ call printf ("%s\n")
+ call pargstr (table1)
+ call flush (STDOUT)
+ }
+ # Open the table, change its size, and close it.
+ tp = tbtopn (table1, READ_WRITE, 0)
+ call tbtchs (tp, maxpar, maxcols, rowlen, allrows)
+ call tbtclo (tp)
+ }
+ call tbnclose (list1)
+
+ # Check whether the output string is a directory.
+ } else if (isdirectory (tablist2, dirname2, SZ_PATHNAME) > 0) {
+
+ list1 = tbnopen (tablist1)
+ while (tbnget (list1, table1, SZ_PATHNAME) != EOF) {
+
+ ttype = tbttyp (table1, exists)
+ if (ttype == TBL_TYPE_FITS) {
+ call eprintf ("Skipping FITS table %s\n")
+ call pargstr (table1)
+ next
+ }
+
+ # Place the input table name without a directory in
+ # string dirname1.
+
+ call get_root (table1, table2, SZ_PATHNAME)
+ root_len = fnldir (table2, dirname1, SZ_PATHNAME)
+ call strcpy (table2[root_len + 1], dirname1, SZ_PATHNAME)
+
+ call strcpy (dirname2, table2, SZ_PATHNAME)
+ call strcat (dirname1, table2, SZ_PATHNAME)
+
+ if (verbose) {
+ call printf ("%s -> %s\n")
+ call pargstr (table1)
+ call pargstr (table2)
+ call flush (STDOUT)
+ }
+ # Copy the table, open it, change its size, and close it.
+ call tbtcpy (table1, table2)
+ tp = tbtopn (table2, READ_WRITE, 0)
+ call tbtchs (tp, maxpar, maxcols, rowlen, allrows)
+ call tbtclo (tp)
+ }
+ call tbnclose (list1)
+
+ } else {
+
+ # Expand the input and output table lists.
+
+ list1 = tbnopen (tablist1)
+ list2 = tbnopen (tablist2)
+
+ if (tbnlen (list1) != tbnlen (list2)) {
+ call tbnclose (list1)
+ call tbnclose (list2)
+ call error (1, "Number of input and output tables not the same")
+ }
+
+ # Change each table in the list.
+
+ while ((tbnget (list1, table1, SZ_PATHNAME) != EOF) &&
+ (tbnget (list2, table2, SZ_PATHNAME) != EOF)) {
+
+ ttype = tbttyp (table1, exists)
+ if (ttype == TBL_TYPE_FITS) {
+ call eprintf ("Skipping FITS table: %s --> %s\n")
+ call pargstr (table1)
+ call pargstr (table2)
+ next
+ }
+
+ if (streq (table1, table2)) {
+ # Same input and output names; no need to copy the table.
+ if (verbose) {
+ call eprintf ("%s\n")
+ call pargstr (table1)
+ }
+ } else {
+ # Different input & output names, so copy the table.
+ if (verbose) {
+ call eprintf ("%s -> %s\n")
+ call pargstr (table1)
+ call pargstr (table2)
+ }
+ call tbtcpy (table1, table2)
+ }
+ # Open the table, change its size, and close it.
+ tp = tbtopn (table2, READ_WRITE, 0)
+ call tbtchs (tp, maxpar, maxcols, rowlen, allrows)
+ call tbtclo (tp)
+ }
+ call tbnclose (list1)
+ call tbnclose (list2)
+ }
+end
diff --git a/pkg/utilities/nttools/tcopy.par b/pkg/utilities/nttools/tcopy.par
new file mode 100644
index 00000000..89059199
--- /dev/null
+++ b/pkg/utilities/nttools/tcopy.par
@@ -0,0 +1,4 @@
+intable,s,a,"",,,"input tables"
+outtable,s,a,"",,,"output tables or directory"
+verbose,b,h,yes,,,"print operations performed?"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/tcopy/iswholetab.x b/pkg/utilities/nttools/tcopy/iswholetab.x
new file mode 100644
index 00000000..a2a981ed
--- /dev/null
+++ b/pkg/utilities/nttools/tcopy/iswholetab.x
@@ -0,0 +1,24 @@
+# IS_WHOLETAB -- Return true if table name has no extension
+
+bool procedure is_wholetab (table)
+
+char table[ARB] # i: table name
+#--
+bool wholetab
+int nc, hdu
+pointer sp, fname, extname
+
+int tbparse()
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+ call salloc (extname, SZ_FNAME, TY_CHAR)
+
+ nc = tbparse (table, Memc[fname], Memc[extname], SZ_FNAME, hdu)
+
+ wholetab = Memc[extname] == EOS
+
+ call sfree (sp)
+ return (wholetab)
+end
diff --git a/pkg/utilities/nttools/tcopy/mkpkg b/pkg/utilities/nttools/tcopy/mkpkg
new file mode 100644
index 00000000..69ef0524
--- /dev/null
+++ b/pkg/utilities/nttools/tcopy/mkpkg
@@ -0,0 +1,13 @@
+# Update the tcopy application code in the ttools package library
+# Author: HODGE, 2-FEB-1988
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ iswholetab.x
+ tcopy.x <error.h> <tbset.h>
+ tdelete.x <error.h>
+ ;
diff --git a/pkg/utilities/nttools/tcopy/tcopy.x b/pkg/utilities/nttools/tcopy/tcopy.x
new file mode 100644
index 00000000..20713f26
--- /dev/null
+++ b/pkg/utilities/nttools/tcopy/tcopy.x
@@ -0,0 +1,283 @@
+include <error.h>
+include <fset.h> # used to check whether input or output is redirected
+include <tbset.h>
+
+# tcopy -- Copy table(s)
+
+# The input tables are given by an filename template list. The output
+# is either a matching list of tables or a directory. The number of
+# input tables may be either one or match the number of output tables.
+# This is based on the t_imcopy procedure.
+#
+# Phil Hodge, 21-Aug-1987 Task created.
+# Phil Hodge, 7-Sep-1988 Change parameter names for tables.
+# Phil Hodge, 28-Dec-1989 Use iferr with call to tbtcpy.
+# Phil Hodge, 26-Mar-1992 Remove calls to tbtext.
+# Phil Hodge, 1-Jul-1995 Modify for FITS tables.
+# Phil Hodge, 19-Jul-1995 Replace fnt calls with tbn.
+# B.Simon 9-May-1997 Add code similar to trename
+# Phil Hodge, 8-Apr-1999 In one_copy, call tbfpri.
+# Phil hodge, 16-Apr-1999 Remove ttype from calling sequence of tbparse;
+# use tbttyp to get table type; ext_type is not called.
+# Phil Hodge, 7-Jun-1999 If input or output is redirected, set to STDIN
+# or STDOUT without getting the cl parameter.
+# Phil Hodge, 29-Jun-1999 In one_copy, don't call tbtacc if oldfile is STDIN.
+# Phil Hodge, 2-Jan-2001 Check $nargs to see whether input & output were
+# specified, rather than relying exclusively on F_REDIR.
+# Phil Hodge, 28-Feb-2002 Add a call to sfree at the end of tcopy.
+
+procedure tcopy()
+
+pointer tablist1 # input table list
+pointer tablist2 # output table list
+bool verbose # print file names?
+#--
+pointer sp
+pointer table1 # input table name
+pointer fname1 # input file name (i.e. without brackets)
+pointer cdfname # input CDF name or EXTNAME
+pointer table2 # output table name
+pointer dir1 # input directory name
+pointer dir2 # output directory name
+
+pointer list1, list2, tp
+int root_len # number of char in input directory name
+int numout # number of names in output list
+bool fitsout # is the output just one FITS file?
+
+char src[SZ_FNAME], extn[SZ_FNAME]
+
+int nargs # number of command-line arguments
+bool in_redir, out_redir # is input or output redirected?
+
+pointer tbnopen(), tbtopn()
+int tbnget(), tbnlen()
+int fstati()
+int fnldir(), isdirectory(), strncmp()
+int junk, hdu, tbparse(), exists, tbttyp()
+int clgeti()
+bool clgetb(), streq()
+
+begin
+ call smark (sp)
+ call salloc (tablist1, SZ_LINE, TY_CHAR)
+ call salloc (tablist2, SZ_LINE, TY_CHAR)
+ call salloc (table1, SZ_LINE, TY_CHAR)
+ call salloc (fname1, SZ_LINE, TY_CHAR)
+ call salloc (cdfname, SZ_LINE, TY_CHAR)
+ call salloc (table2, SZ_LINE, TY_CHAR)
+ call salloc (dir1, SZ_LINE, TY_CHAR)
+ call salloc (dir2, SZ_LINE, TY_CHAR)
+
+ # Get input and output table template lists. What we do with the
+ # command-line arguments depends on how many there are and what
+ # (input, output, or both) has been redirected.
+
+ nargs = clgeti ("$nargs")
+ in_redir = fstati (STDIN, F_REDIR) == YES
+ out_redir = fstati (STDOUT, F_REDIR) == YES
+
+ if (in_redir || out_redir) {
+
+ if (nargs >= 2) {
+
+ if (in_redir) {
+ call strcpy ("STDIN", Memc[tablist1], SZ_LINE)
+ call clpstr ("intable", "STDIN") # update par file
+ } else {
+ call clgstr ("intable", Memc[tablist1], SZ_LINE)
+ }
+ call clgstr ("outtable", Memc[tablist2], SZ_LINE)
+
+ } else if (nargs == 1) {
+
+ if (in_redir) { # output may also have been redirected
+ # The cl thinks the argument is intable, but it's actually
+ # outtable, so assign the value to tablist2.
+ call strcpy ("STDIN", Memc[tablist1], SZ_LINE)
+ call clgstr ("intable", Memc[tablist2], SZ_LINE)
+ # update par file
+ call clpstr ("intable", "STDIN")
+ call clpstr ("outtable", Memc[tablist2])
+ } else { # only output was redirected
+ call clgstr ("intable", Memc[tablist1], SZ_LINE)
+ call strcpy ("STDOUT", Memc[tablist2], SZ_LINE)
+ }
+
+ } else if (nargs == 0) {
+
+ if (in_redir)
+ call strcpy ("STDIN", Memc[tablist1], SZ_LINE)
+ else
+ call clgstr ("intable", Memc[tablist1], SZ_LINE)
+
+ if (out_redir)
+ call strcpy ("STDOUT", Memc[tablist2], SZ_LINE)
+ else
+ call clgstr ("outtable", Memc[tablist2], SZ_LINE)
+ }
+
+ } else {
+
+ call clgstr ("intable", Memc[tablist1], SZ_LINE)
+ call clgstr ("outtable", Memc[tablist2], SZ_LINE)
+ }
+
+ verbose = clgetb ("verbose")
+
+ # Check if the output string is a directory.
+
+ if (isdirectory (Memc[tablist2], Memc[dir2], SZ_LINE) > 0 &&
+ !streq (Memc[tablist2], "STDOUT")) {
+
+ list1 = tbnopen (Memc[tablist1])
+
+ while (tbnget (list1, Memc[table1], SZ_LINE) != EOF) {
+
+ # Memc[fname1] is the name without any brackets. We need to
+ # remove brackets because they confuse fnldir, which we use
+ # to get the length of any directory prefix.
+
+ junk = tbparse (Memc[table1], Memc[fname1], Memc[cdfname],
+ SZ_LINE, hdu)
+ root_len = fnldir (Memc[fname1], Memc[dir1], SZ_LINE)
+
+ # Copy the output directory name to table2, and concatenate
+ # the input file name (without directory prefix and without
+ # the bracket suffix).
+
+ call strcpy (Memc[dir2], Memc[table2], SZ_LINE)
+ call strcat (Memc[fname1+root_len], Memc[table2], SZ_LINE)
+
+ call one_copy (Memc[table1], Memc[table2], verbose)
+ }
+
+ call tbnclose (list1)
+
+ } else {
+
+ # Dummy open of the old file in case it's a URL.
+ if (strncmp (Memc[tablist1], "http://", 7) == 0) {
+ tp = tbtopn (Memc[tablist1], READ_ONLY, NULL)
+ call tbtclo (tp)
+ }
+
+ # Expand the input and output table lists.
+ list1 = tbnopen (Memc[tablist1])
+ list2 = tbnopen (Memc[tablist2])
+
+ numout = tbnlen (list2)
+ fitsout = false # initial value
+ if (numout == 1) {
+ # See if the output is a FITS file. It's OK to have many
+ # input tables with just one output FITS file.
+ junk = tbnget (list2, Memc[table2], SZ_LINE)
+ call tbnrew (list2)
+ if (tbttyp (Memc[table2], exists) == TBL_TYPE_FITS)
+ fitsout = true
+ }
+
+ if (tbnlen (list1) != numout) {
+ if (!fitsout) {
+ call tbnclose (list1)
+ call tbnclose (list2)
+ call error (1,
+ "Number of input and output tables are not the same.")
+ }
+ }
+
+ # Copy each table.
+ while (tbnget (list1, Memc[table1], SZ_LINE) != EOF) {
+ if (!fitsout)
+ junk = tbnget (list2, Memc[table2], SZ_LINE)
+
+ call one_copy (Memc[table1], Memc[table2], verbose)
+ }
+
+ call tbnclose (list1)
+ call tbnclose (list2)
+ }
+
+ call sfree (sp)
+end
+
+# ONE_COPY -- Copy a single table
+
+procedure one_copy (oldfile, newfile, verbose)
+
+char oldfile[ARB] # i: current file name
+char newfile[ARB] # i: new file name
+bool verbose # i: print informational message
+#--
+bool done
+int phu_copied # set by tbfpri and ignored
+pointer sp, oldname, newname, tp
+
+bool use_fcopy # true if we should copy the file with fcopy
+
+pointer tbtopn()
+bool streq(), is_wholetab()
+int tbtacc(), exists, tbttyp() # exists is ignored
+errchk tbfpri, tbtcpy, tbtopn
+
+begin
+ call smark (sp)
+ call salloc (oldname, SZ_FNAME, TY_CHAR)
+ call salloc (newname, SZ_FNAME, TY_CHAR)
+
+ # Check to make sure the copy is legal
+
+ done = false
+ use_fcopy = false
+ if (streq (oldfile, newfile)) {
+ call eprintf ("Cannot copy table to itself: %s\n")
+ call pargstr (oldfile)
+
+ if (streq (oldfile, "STDIN")) {
+ use_fcopy = true
+
+ } else if (tbtacc (oldfile) == YES) {
+ use_fcopy = true
+
+ } else {
+ call eprintf ("Can only copy tables with tcopy: `%s'\n")
+ call pargstr (oldfile)
+ }
+
+ if (use_fcopy) {
+ call tbtext (oldfile, Memc[oldname], SZ_FNAME)
+ call tbtext (newfile, Memc[newname], SZ_FNAME)
+
+ iferr (call fcopy (Memc[oldname], Memc[newname])) {
+ call erract (EA_WARN)
+ } else {
+ done = true
+ }
+ }
+
+ } else {
+ # Table extensions are copied by the table
+ # library function tbtcpy
+
+ iferr {
+ call tbfpri (oldfile, newfile, phu_copied)
+ call tbtcpy (oldfile, newfile)
+ } then {
+ call erract (EA_WARN)
+ } else {
+ done = true
+ }
+ }
+
+ # Print verbose message
+
+ if (done && verbose) {
+ call printf ("# %s -> %s\n")
+ call pargstr (oldfile)
+ call pargstr (newfile)
+ call flush (STDOUT)
+ }
+
+ call sfree (sp)
+ return
+end
diff --git a/pkg/utilities/nttools/tcopy/tdelete.x b/pkg/utilities/nttools/tcopy/tdelete.x
new file mode 100644
index 00000000..87258d06
--- /dev/null
+++ b/pkg/utilities/nttools/tcopy/tdelete.x
@@ -0,0 +1,126 @@
+include <error.h>
+
+# tdelete -- Delete a list of tables. If table cannot be deleted, warn the
+# user but do not abort. Verify before deleting each table if user wishes.
+# This is based on the t_imdelete procedure.
+#
+# Phil Hodge, 24-Aug-1987 Task created.
+# Phil Hodge, 7-Sep-1988 Change parameter name for table.
+# Phil Hodge, 16-Mar-1992 Include check to prevent deleting text files.
+# Phil Hodge, 26-Mar-1992 Remove call to tbtext.
+# Phil Hodge, 19-Jul-1995 Replace fnt calls with tbn.
+# B.Simon 5-May-1995 Call delete if deleting an entire table
+procedure tdelete()
+
+pointer list
+bool verify
+pointer sp, tablename, tablist
+
+pointer tbnopen()
+int tbnget()
+bool clgetb()
+
+begin
+ call smark (sp)
+ call salloc (tablename, SZ_PATHNAME, TY_CHAR)
+ call salloc (tablist, SZ_LINE, TY_CHAR)
+
+ call clgstr ("table", Memc[tablist], SZ_LINE)
+ list = tbnopen (Memc[tablist])
+ verify = clgetb ("verify")
+
+ while (tbnget (list, Memc[tablename], SZ_PATHNAME) != EOF)
+ call one_delete (Memc[tablename], verify)
+
+ # Reset the go_ahead parameter, overriding learn mode, in case tdelete
+ # is subsequently called from the background.
+
+ if (verify)
+ call clputb ("go_ahead", true)
+
+ call tbnclose (list)
+ call sfree (sp)
+end
+
+# ONE_DELETE -- Delete a single table
+
+procedure one_delete (file, verify)
+
+char file[ARB] # i: current file name
+bool verify # i: ask user for confirmation
+#--
+bool doit
+pointer sp, fname
+
+bool clgetb(), is_wholetab()
+int access(), tbtacc(), strncmp()
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+
+ # Check to make sure the deletion is OK
+
+ if (strncmp ("http:", file, 5) == 0) {
+ call eprintf ("Cannot delete URL `%s'\n")
+ call pargstr (file)
+ call sfree (sp)
+ return
+ }
+
+ if (verify) {
+ if (tbtacc (file) == NO) {
+ # If table does not exist, warn user
+ # (since verify mode is in effect).
+ doit = false
+ call eprintf ("Cannot delete nonexistent table `%s'\n")
+ call pargstr (file)
+ }
+
+ # Set default action of verify prompt (override learning of
+ # most recent response).
+
+ call clputb ("go_ahead", clgetb ("default_action"))
+ call printf ("delete table `%s'")
+ call pargstr (file)
+
+ doit = clgetb ("go_ahead")
+
+ } else {
+ if (access (file, 0, TEXT_FILE) == YES) {
+ # We don't want users to be able to delete text files
+ # with tdelete if verify = false.
+
+ doit = false
+ call eprintf ("Cannot delete text file with tdelete: `%s'\n")
+ call pargstr (file)
+
+ } else {
+ doit = true
+ }
+ }
+
+ # Do the deletion
+
+ if (doit) {
+ if (is_wholetab (file)) {
+ # Entire files are deleted with the fio delete
+
+ call tbtext (file, Memc[fname], SZ_FNAME)
+ iferr (call delete (Memc[fname])) {
+ call erract (EA_WARN)
+ }
+
+ } else {
+ # Table extensions are deleted by the table
+ # library function tbtdel
+
+ iferr (call tbtdel (file)) {
+ call erract (EA_WARN)
+ }
+ }
+ }
+
+ call sfree (sp)
+ return
+end
diff --git a/pkg/utilities/nttools/tcopy/trename.x b/pkg/utilities/nttools/tcopy/trename.x
new file mode 100644
index 00000000..c4273b0b
--- /dev/null
+++ b/pkg/utilities/nttools/tcopy/trename.x
@@ -0,0 +1,185 @@
+include <error.h>
+
+# trename -- Rename table(s)
+
+# The input tables are given by an filename template list. The output
+# is either a matching list of tables or a directory. The number of
+# input tables may be either one or match the number of output tables.
+# This is based on the t_imcopy procedure.
+#
+# Phil Hodge, 21-Aug-1987 Task created.
+# Phil Hodge, 7-Sep-1988 Change parameter names for tables.
+# Phil Hodge, 28-Dec-1989 Use iferr with call to tbtren.
+# Phil Hodge, 16-Mar-1992 Include check to prevent renaming text files.
+# Phil Hodge, 1-Jul-1995 Modify for FITS tables.
+# Phil Hodge, 19-Jul-1995 Replace fnt calls with tbn.
+# B.Simon 5-May-1997 Call rename if renaming entire table
+# B.Simon 9-May-1997 Add table type check
+
+procedure trename()
+
+pointer tablist1 # input table list
+pointer tablist2 # output table list
+bool verbose # print operations?
+#--
+pointer sp
+pointer table1 # input table name
+pointer fname1 # input file name (i.e. without brackets)
+pointer cdfname # input CDF name or EXTNAME
+pointer table2 # output table name
+pointer dir1 # input directory name
+pointer dir2 # output directory name
+
+pointer list1, list2
+int root_len # number of char in input directory name
+
+pointer tbnopen()
+int tbnget(), tbnlen()
+int fnldir(), isdirectory()
+int junk, ttype, hdu, tbparse()
+bool clgetb(), streq()
+
+begin
+ call smark (sp)
+ call salloc (tablist1, SZ_LINE, TY_CHAR)
+ call salloc (tablist2, SZ_LINE, TY_CHAR)
+ call salloc (table1, SZ_LINE, TY_CHAR)
+ call salloc (fname1, SZ_LINE, TY_CHAR)
+ call salloc (cdfname, SZ_LINE, TY_CHAR)
+ call salloc (table2, SZ_LINE, TY_CHAR)
+ call salloc (dir1, SZ_LINE, TY_CHAR)
+ call salloc (dir2, SZ_LINE, TY_CHAR)
+
+ # Get input and output table template lists.
+ call clgstr ("intable", Memc[tablist1], SZ_LINE)
+ call clgstr ("outtable", Memc[tablist2], SZ_LINE)
+
+ verbose = clgetb ("verbose")
+
+ # Check if the output string is a directory.
+
+ if (isdirectory (Memc[tablist2], Memc[dir2], SZ_LINE) > 0 &&
+ !streq (Memc[tablist2], "STDOUT")) {
+
+ list1 = tbnopen (Memc[tablist1])
+
+ while (tbnget (list1, Memc[table1], SZ_LINE) != EOF) {
+
+ # Memc[fname1] is the name without any brackets. We need to
+ # remove brackets because they confuse fnldir, which we use
+ # to get the length of any directory prefix.
+
+ junk = tbparse (Memc[table1], Memc[fname1], Memc[cdfname],
+ SZ_LINE, ttype, hdu)
+ root_len = fnldir (Memc[fname1], Memc[dir1], SZ_LINE)
+
+ # Copy the output directory name to table2, and concatenate
+ # the input file name (without directory prefix and without
+ # the bracket suffix).
+
+ call strcpy (Memc[dir2], Memc[table2], SZ_LINE)
+ call strcat (Memc[fname1+root_len], Memc[table2], SZ_LINE)
+
+ call one_rename (Memc[table1], Memc[table2], verbose)
+ }
+
+ call tbnclose (list1)
+
+ } else {
+
+ # Expand the input and output table lists.
+ list1 = tbnopen (Memc[tablist1])
+ list2 = tbnopen (Memc[tablist2])
+
+ if (tbnlen (list1) != tbnlen (list2)) {
+ call tbnclose (list1)
+ call tbnclose (list2)
+ call error (1, "Number of input and output tables not the same")
+ }
+
+ # Rename each table.
+
+ while ((tbnget (list1, Memc[table1], SZ_LINE) != EOF) &&
+ (tbnget (list2, Memc[table2], SZ_LINE) != EOF)) {
+
+ call one_rename (Memc[table1], Memc[table2], verbose)
+ }
+
+ call tbnclose (list1)
+ call tbnclose (list2)
+ }
+end
+
+# ONE_RENAME -- Rename a single table
+
+procedure one_rename (oldfile, newfile, verbose)
+
+char oldfile[ARB] # i: current file name
+char newfile[ARB] # i: new file name
+bool verbose # i: print informational message
+#--
+bool done
+pointer sp, oldname, newname
+
+bool streq(), is_wholetab()
+int access(), tbtacc(), ext_type()
+
+begin
+ call smark (sp)
+ call salloc (oldname, SZ_FNAME, TY_CHAR)
+ call salloc (newname, SZ_FNAME, TY_CHAR)
+
+ # Check to make sure the copy is legal
+
+ done = false
+ if (streq (oldfile, newfile)) {
+ call eprintf ("Cannot rename table to itself: %s\n")
+ call pargstr (oldfile)
+
+ } else if (access (oldfile, 0, TEXT_FILE) == YES) {
+ call eprintf ("Cannot rename text file with trename: `%s'\n")
+ call pargstr (oldfile)
+
+ } else if (is_wholetab (oldfile) && is_wholetab (newfile) &&
+ ext_type (oldfile) == ext_type (newfile)) {
+
+ # Entire files of the same type are renamed with the fio rename
+
+ if (tbtacc (oldfile) == NO) {
+ call eprintf ("Can only rename tables with trename: `%s'\n")
+ call pargstr (oldfile)
+
+ } else {
+ call tbtext (oldfile, Memc[oldname], SZ_FNAME)
+ call tbtext (newfile, Memc[newname], SZ_FNAME)
+
+ iferr (call rename (Memc[oldname], Memc[newname])) {
+ call erract (EA_WARN)
+ } else {
+ done = true
+ }
+ }
+
+ } else {
+ # Table extensions are renamed by the table
+ # library function tbtren
+
+ iferr (call tbtren (oldfile, newfile)) {
+ call erract (EA_WARN)
+ } else {
+ done = true
+ }
+ }
+
+ # Print verbose message
+
+ if (done && verbose) {
+ call printf ("%s -> %s\n")
+ call pargstr (oldfile)
+ call pargstr (newfile)
+ call flush (STDOUT)
+ }
+
+ call sfree (sp)
+ return
+end
diff --git a/pkg/utilities/nttools/tcreate.par b/pkg/utilities/nttools/tcreate.par
new file mode 100644
index 00000000..4a95daf8
--- /dev/null
+++ b/pkg/utilities/nttools/tcreate.par
@@ -0,0 +1,12 @@
+table,s,a,"",,,"name of table to be created"
+cdfile,s,a,"STDIN",,,"name of file containing column descriptions"
+datafile,s,a,"STDIN",,,"name of file containing data"
+uparfile,s,h,"",,,"name of file containing header parameters"
+nskip,i,h,0,0,,"number of header lines to skip in data file"
+nlines,i,h,0,0,,"number of lines in data file per row in table"
+nrows,i,h,0,0,,"number of rows [zero for all]"
+hist,b,h,yes,,,"add a history record with creation date?"
+extrapar,i,h,5,0,,"extra space for header parameters"
+tbltype,s,h,"default","default|row|column|text",,"type of table"
+extracol,i,h,0,0,,"number of extra columns to allocate"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/tcreate/gnextl.x b/pkg/utilities/nttools/tcreate/gnextl.x
new file mode 100644
index 00000000..42da95e4
--- /dev/null
+++ b/pkg/utilities/nttools/tcreate/gnextl.x
@@ -0,0 +1,152 @@
+include <chars.h>
+include <ctype.h>
+
+# g_next_l -- get next line from text file
+# This routine calls getlline (get long line) to get a line from a text file.
+# A flag is set to true if the line is a comment rather than a data line.
+# The returned line will be terminated by EOS rather than by '\n'.
+# If the line is a comment, the line will be skipped. In-line comments
+# are stripped off. A '#' which is enclosed in quotes (single or double)
+# or preceded by '\' will not be
+# counted as a comment character. A newline terminates the string regardless
+# of what precedes or follows it; a newline within a string is an error,
+# though. The function value is the number of characters preceding the EOS,
+# or EOF is returned when the end of file is reached.
+# The linenum I/O parameter is incremented each time a line is read,
+# regardless of whether the line is data, a comment, or blank.
+#
+# The buffer is scanned to be sure it contains a '\n'. If not, we haven't
+# read the entire line (i.e. it's longer than maxch); we regard that as
+# a serious error.
+#
+# Phil Hodge, 22-May-1992 Function created based on tbzlin.
+# Phil Hodge, 10-May-1993 Include line number in error messages.
+
+int procedure g_next_l (fd, buf, maxch, linenum)
+
+int fd # i: fd for the file
+char buf[ARB] # o: buffer to receive the line that was read
+int maxch # i: size of line buffer
+int linenum # io: line number counter
+#--
+pointer sp
+pointer errmes # scratch for error message
+char ch # a character from the string which was read
+int ip # counter for a character in the string
+int nchar # number of char read by getlline
+bool done # flag for terminating loop
+bool comment # is current line commented out?
+bool at_end # true when we reach the end of the line ('\n')
+bool odd_squotes # true if current character is within quoted string
+bool odd_dquotes # true if current char is within double quoted string
+int getlline()
+
+begin
+ done = false
+ # This loop is terminated by EOF or by reading a line that
+ # is not a comment or blank.
+ while ( !done ) {
+
+ nchar = getlline (fd, buf, maxch)
+ if (nchar == EOF)
+ return (EOF) # end of file reached
+
+ linenum = linenum + 1 # increment line number counter
+
+ # If there's no newline, we haven't read the entire line.
+ at_end = false
+ do ip = 1, maxch {
+ if (buf[ip] == EOS) {
+ break
+ } else if (buf[ip] == '\n') {
+ at_end = true # we've read entire line
+ break
+ }
+ }
+ if (!at_end) {
+ call smark (sp)
+ call salloc (errmes, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[errmes], SZ_LINE,
+ "Input line %d is too long.")
+ call pargi (linenum)
+ call error (1, Memc[errmes])
+ }
+
+ ip = 1
+ while (IS_WHITE(buf[ip]) && ip < maxch)
+ ip = ip + 1
+
+ # Blank up through maxch? Treat it as a comment.
+ if (ip >= maxch) {
+ comment = true
+
+ } else if (buf[ip] == NEWLINE || buf[ip] == '#' || buf[ip] == EOS) {
+ comment = true
+
+ } else {
+ comment = false
+
+ # The current line is not a comment or blank;
+ # replace '\n' or '#' by EOS. First check whether the
+ # first non-blank character begins a quoted string.
+ if (buf[ip] == SQUOTE)
+ odd_squotes = true
+ else
+ odd_squotes = false
+ if (buf[ip] == DQUOTE)
+ odd_dquotes = true
+ else
+ odd_dquotes = false
+
+ ip = ip + 1
+ at_end = false
+ while ( !at_end ) {
+ ch = buf[ip]
+ # Check for end of buffer or newline or in-line comment.
+ if (ch == NEWLINE) {
+ buf[ip] = EOS
+ at_end = true
+ } else if (ch == SQUOTE) {
+ # Toggle flag for in/out of quoted string.
+ odd_squotes = !odd_squotes
+ ip = ip + 1
+ } else if (ch == DQUOTE) {
+ odd_dquotes = !odd_dquotes
+ ip = ip + 1
+ } else if (ch == '#') {
+ # '#' is not a comment if it's in a quoted string
+ if (odd_squotes || odd_dquotes) {
+ ip = ip + 1
+ # ... or if it's escaped.
+ } else if (buf[ip-1] == ESCAPE) {
+ ip = ip + 1
+ } else { # it's an in-line comment
+ buf[ip] = EOS
+ at_end = true
+ }
+ } else if (ch == EOS) {
+ at_end = true # (can't get here)
+ } else if (ip >= maxch) { # end of buffer reached
+ at_end = true # (can't get here)
+ buf[maxch+1] = EOS
+ } else {
+ ip = ip + 1
+ }
+ }
+ if (odd_squotes || odd_dquotes) {
+ call smark (sp)
+ call salloc (errmes, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[errmes], SZ_LINE,
+ "Unbalanced quotes in line %d.")
+ call pargi (linenum)
+ call error (1, Memc[errmes])
+ }
+ nchar = ip - 1
+ }
+
+ # If the line is a comment (or blank), read another line.
+ if (!comment)
+ done = true
+ }
+ return (nchar)
+end
diff --git a/pkg/utilities/nttools/tcreate/mkpkg b/pkg/utilities/nttools/tcreate/mkpkg
new file mode 100644
index 00000000..5a14c82c
--- /dev/null
+++ b/pkg/utilities/nttools/tcreate/mkpkg
@@ -0,0 +1,12 @@
+# Update the tcreate application code in the ttools package library
+# Author: HODGE, 2-FEB-1988
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ tcreate.x <time.h> <fset.h> <ctype.h> <tbset.h>
+ gnextl.x <chars.h> <ctype.h>
+ ;
diff --git a/pkg/utilities/nttools/tcreate/tcreate.x b/pkg/utilities/nttools/tcreate/tcreate.x
new file mode 100644
index 00000000..6febb642
--- /dev/null
+++ b/pkg/utilities/nttools/tcreate/tcreate.x
@@ -0,0 +1,958 @@
+include <error.h> # for EA_ERROR
+include <time.h> # this defines SZ_TIME
+include <fset.h> # defines F_REDIR
+include <ctype.h> # defines IS_WHITE
+include <tbset.h>
+
+define SZ_LONG_LINE (8192+SZ_LINE) # allows input line up to 8192 char
+define SZ_FMT 17 # size of string containing print format
+define SZ_DTYPE 29 # size of string for data type
+define CPSPACE 21 # size of increment in space for col descr ptrs
+define T_MAXDIM 7 # maximum dimension for an array in a table
+
+# These three macros are for dim, the pointer to an array of pointers to
+# dimension info.
+# for column i:
+# dimension is TCR_NDIM (dim, i)
+# length of axis j is TCR_AXLEN (dim, i, j)
+define LEN_DIM_INFO T_MAXDIM + 1 # unit = SZ_INT32
+define TCR_NDIM Memi[Memi[$1+$2-1]] # dimension of array
+define TCR_AXLEN Memi[Memi[$1+$2-1]+$3] # length of an axis
+
+# tcreate -- Program to create a table from data in an ASCII file.
+#
+# Phil Hodge, 22-Jul-1987 Task created
+# Phil Hodge, 11-Aug-1987 Modify mk_new_cols for datatype=-n for char string.
+# Phil Hodge, 8-Sep-1987 Change name from tcreat.
+# Phil Hodge, 15-Oct-1987 Use tbcigi instead of COL_DTYPE.
+# Phil Hodge, 20-Sep-1988 Print warning if file does not exist.
+# Phil Hodge, 9-Mar-1989 Change data type in call to tbhanp from char to int.
+# Phil Hodge, 17-May-1989 Add history record to table giving creation date.
+# Phil Hodge, 22-May-1992 Allow input lines up to 1024 char; print warning
+# if entire line of data file is not read;
+# print prompt if input is STDIN and not redirected.
+# Phil Hodge, 11-Jan-1993 In mk_new_cols, move "ncols = ncols + 1" to just
+# before the call to tbcdef.
+# Phil Hodge, 10-May-1993 In row_copy, include TY_SHORT.
+# Phil Hodge, 11-Aug-1993 Add tcr_ctoi, which calls ctoi after skipping over
+# leading whitespace and/or a "+" sign; call in row_copy.
+# Phil Hodge, 18-Nov-1994 Add option of creating columns of arrays.
+# Phil Hodge, 19-Jul-1995 Add tp to calling sequence of tbcisa.
+# Phil Hodge, 20-Jul-1998 In cp_upar_tbl, call tbfres for a FITS table.
+# Phil Hodge, 18-Jun-1999 Add option to create a text table with explicit
+# column definitions.
+# Phil Hodge, 29-Jul-1999 In tcr_ctoi, check that the value in the data file
+# has no fractional part. linenum was added to the calling
+# sequence of tcr_ctoi for a possible error message.
+# Phil Hodge, 12-Nov-2001 Allow input lines up to 8192 characters in length.
+# Phil Hodge, 24-Dec-2003 Move the call to tbcisa from mk_new_cols to a
+# point after the call to tbtcre. This had to be done because
+# tbcisa sets the value of a header keyword, and the table file
+# doesn't exist until after tbtcre has been called. Add the
+# three routines dim_alloc, dim_set, and dim_free. Also change
+# the data type of cptr from TY_INT to TY_POINTER.
+# Phil Hodge, 20-Dec-2004 Check cdname, dname, pname for " ".
+
+procedure tcreate()
+
+pointer sp
+pointer tname # scratch for name of table to be created
+pointer cdname # scratch for name of file of column definitions
+pointer dname # scratch for name of file for table data
+pointer pname # scratch for name of file of header parameters
+pointer ttype # scratch for table type (e.g. "row")
+pointer tp # pointer to descriptor for output table
+pointer cptr # pointer to array of column pointers
+pointer dim # pointer to array of column dimension info
+int uparfd # fd for input file of header parameters
+int nskip # number of lines to skip at beg of data file
+int nlines # number of lines in file per row in table
+int npar # number of header parameters
+int nrows, ncols # number of rows and columns in table
+int extracol # number of extra columns to allocate
+int extrapar # extra space to allocate for header parameters
+int maxcols # size of arrays for column info
+bool histflag # add a history record with creation date?
+pointer tbtopn()
+int clgeti()
+bool clgetb()
+bool isblank()
+
+begin
+ call smark (sp)
+ call salloc (tname, SZ_FNAME, TY_CHAR)
+ call salloc (cdname, SZ_FNAME, TY_CHAR)
+ call salloc (dname, SZ_FNAME, TY_CHAR)
+ call salloc (pname, SZ_FNAME, TY_CHAR)
+ call salloc (ttype, SZ_FNAME, TY_CHAR)
+
+ call clgstr ("table", Memc[tname], SZ_FNAME)
+ call clgstr ("cdfile", Memc[cdname], SZ_FNAME)
+ call clgstr ("datafile", Memc[dname], SZ_FNAME)
+ call clgstr ("uparfile", Memc[pname], SZ_FNAME)
+ nskip = clgeti ("nskip")
+ nlines = clgeti ("nlines")
+ nrows = clgeti ("nrows")
+ histflag = clgetb ("hist")
+ extrapar = clgeti ("extrapar")
+ call clgstr ("tbltype", Memc[ttype], SZ_FNAME)
+
+ # The user might have given the name as " " instead of EOS (""); check
+ # for this, and in this case make sure the value is EOS to simplify
+ # checking elsewhere in this file.
+ if (isblank (Memc[cdname]))
+ Memc[cdname] = EOS
+ if (isblank (Memc[dname]))
+ Memc[dname] = EOS
+ if (isblank (Memc[pname]))
+ Memc[pname] = EOS
+
+ tp = tbtopn (Memc[tname], NEW_FILE, 0)
+
+ if (Memc[ttype] == 'r') { # row-ordered stsdas format
+ call tbpset (tp, TBL_WHTYPE, TBL_TYPE_S_ROW)
+ extracol = clgeti ("extracol")
+ } else if (Memc[ttype] == 'c') { # column-ordered stsdas format
+ if (nrows <= 0)
+ call error (1, "must specify nrows>0 for column-ordered table")
+ call tbpset (tp, TBL_WHTYPE, TBL_TYPE_S_COL)
+ call tbpset (tp, TBL_ALLROWS, nrows)
+ extracol = 0
+ } else if (Memc[ttype] == 't') { # text table
+ # not a simple text table, one with explicit column definitions
+ call tbpset (tp, TBL_WHTYPE, TBL_TYPE_TEXT)
+ call tbpset (tp, TBL_SUBTYPE, TBL_SUBTYPE_EXPLICIT)
+ } else { # default type
+ extracol = clgeti ("extracol")
+ }
+
+ # Read column descriptions, and create columns; ncols = 0 is OK.
+ call mk_new_cols (Memc[cdname], tp, cptr, dim, ncols, maxcols)
+
+ # Increase allocation of space for columns.
+ if (extracol > 0)
+ call tbpset (tp, TBL_INCR_ROWLEN, extracol)
+
+ # Open the (optional) file containing header parameters, and count how
+ # many there are. If npar = 0 the input file will not be left open.
+ if (Memc[pname] != EOS) {
+ call c_user_par (Memc[pname], uparfd, npar)
+ } else {
+ npar = 0 # there is no upar file
+ uparfd = NULL
+ }
+ if (histflag)
+ npar = npar + 1
+
+ # Specify how much space to allocate for header parameters.
+ call tbpset (tp, TBL_MAXPAR, npar+extrapar)
+
+ # Open (create) the table.
+ call tbtcre (tp)
+
+ # Assign column dimension info, if appropriate.
+ call dim_set (tp, Memi[cptr], dim, ncols)
+
+ # Copy header parameters to table, and close the uparfile.
+ call cp_upar_tbl (tp, uparfd, histflag)
+
+ # Read from data file and write to table.
+ if (ncols > 0)
+ call cp_dat_tbl (Memc[dname], tp, Memi[cptr], nskip, nlines, nrows)
+
+ call tbtclo (tp)
+ if (cptr != NULL)
+ call mfree (cptr, TY_POINTER)
+ call dim_free (dim, maxcols)
+
+ call sfree (sp)
+end
+
+
+# mk_new_cols -- make new columns
+# This routine reads column descriptions from an input ASCII file
+# and defines those columns in the table.
+
+procedure mk_new_cols (cdname, tp, cptr, dim, ncols, maxcols)
+
+char cdname[ARB] # i: name of column-definitions file
+pointer tp # i: pointer to table descriptor
+pointer cptr # o: pointer to array of column descriptors
+pointer dim # o: pointer to array of column dimension info
+int ncols # o: number of columns created (may be zero)
+int maxcols # o: size of arrays for column info
+#--
+pointer sp
+pointer lbuf # buffer for reading lines from col descr file
+char colname[SZ_COLNAME] # column name
+char colunits[SZ_COLUNITS] # column units
+char colfmt[SZ_COLFMT] # print format for column
+char chdtype[SZ_DTYPE] # column data type expressed as a char string
+int fd # for input ASCII file
+int linenum # line number counter (ignored)
+int datatype # column data type expressed as an int
+int nelem # array length
+int ip # index in line of text from input file
+int access(), open(), g_next_l(), ctowrd(), fstati()
+bool streq()
+
+begin
+ ncols = 0 # initial values
+ cptr = NULL
+ dim = NULL
+
+ if (cdname[1] == EOS) {
+ call eprintf ("No cdfile; an empty table will be created.\n")
+ return
+ } else if (access (cdname, 0, 0) == NO) {
+ call eprintf ("WARNING: can't read file %s;\n")
+ call pargstr (cdname)
+ call eprintf (" ... an empty table will be created.\n")
+ return
+ } else if (streq (cdname, "STDIN")) {
+ # Print a prompt if the input is not redirected.
+ if (fstati (STDIN, F_REDIR) == NO) {
+ call printf (
+ "Give column definitions (name, datatype, print format, units)\n")
+ call printf (" ... then newline & EOF to finish.\n")
+ call flush (STDOUT)
+ }
+ }
+
+ fd = open (cdname, READ_ONLY, TEXT_FILE)
+
+ call smark (sp)
+ call salloc (lbuf, SZ_LONG_LINE, TY_CHAR)
+
+ maxcols = CPSPACE
+ call calloc (cptr, maxcols, TY_POINTER)
+ call dim_alloc (dim, ncols, maxcols)
+
+ # While get next non-comment line ...
+ linenum = 0
+ while (g_next_l (fd, Memc[lbuf], SZ_LONG_LINE, linenum) != EOF) {
+ ip = 1
+ if (ctowrd (Memc[lbuf], ip, colname, SZ_COLNAME) < 1)
+ call error (1, "could not read column name")
+ if (ncols+1 > maxcols) {
+ maxcols = maxcols + CPSPACE
+ call realloc (cptr, maxcols, TY_POINTER)
+ call dim_alloc (dim, ncols, maxcols)
+ }
+ if (ctowrd (Memc[lbuf], ip, chdtype, SZ_DTYPE) < 1) {
+ call strcpy ("r", chdtype, SZ_DTYPE) # default is real
+ colfmt[1] = EOS
+ colunits[1] = EOS
+ } else if (ctowrd (Memc[lbuf], ip, colfmt, SZ_COLFMT) < 1) {
+ colfmt[1] = EOS
+ colunits[1] = EOS
+ } else if (ctowrd (Memc[lbuf], ip, colunits, SZ_COLUNITS) < 1) {
+ colunits[1] = EOS
+ }
+
+ # Convert the format from Fortran style to SPP style.
+ call tbbftp (colfmt, colfmt)
+
+ iferr {
+ # Convert data type to an integer. Use ncols+1 because
+ # ncols hasn't been incremented yet.
+ call tcr_nelem (chdtype,
+ TCR_NDIM (dim, ncols+1), TCR_AXLEN (dim, ncols+1, 1),
+ T_MAXDIM, nelem, datatype)
+ } then {
+ call erract (EA_WARN)
+ call eprintf ("column `%s' ignored\n")
+ call pargstr (colname)
+ } else {
+ # Create the column.
+ ncols = ncols + 1 # bug fix 1/11/93
+ call tbcdef (tp, Memi[cptr+ncols-1],
+ colname, colunits, colfmt, datatype, nelem, 1)
+ }
+ }
+ call close (fd) # done with column descriptions file
+ call sfree (sp)
+end
+
+# Allocate or reallocate memory for the array of column dimensions.
+
+procedure dim_alloc (dim, ncols, maxcols)
+
+pointer dim # io: allocate (or reallocate) this buffer
+int ncols # i: current number of columns
+int maxcols # i: new number of elements for dim
+#--
+int i, k # loop indices
+
+begin
+ if (dim == NULL)
+ call malloc (dim, maxcols, TY_POINTER)
+ else
+ call realloc (dim, maxcols, TY_POINTER)
+
+ # Assign initial values. These may be updated later.
+ do i = ncols+1, maxcols { # zero indexed
+ call malloc (Memi[dim+i-1], LEN_DIM_INFO, TY_INT)
+ TCR_NDIM (dim, i) = 1
+ do k = 1, T_MAXDIM
+ TCR_AXLEN (dim, i, k) = 1
+ }
+end
+
+# For each column of multi-dimensional arrays, call the routine to assign
+# the keyword giving the length of each axis.
+
+procedure dim_set (tp, cp, dim, ncols)
+
+pointer tp # i: pointer to table descriptor
+pointer cp[ARB] # i: array of column descriptors
+pointer dim # i: pointer to array of column dimension info
+int ncols # i: current number of columns
+#--
+int i # loop index
+
+begin
+ do i = 1, ncols {
+ if (TCR_NDIM (dim, i) > 1)
+ call tbcisa (tp, cp[i], TCR_NDIM(dim,i), TCR_AXLEN(dim,i,1))
+ }
+end
+
+# Free memory for the array of column dimensions.
+
+procedure dim_free (dim, maxcols)
+
+pointer dim # io: pointer to array of column dimension info
+int maxcols # i: new number of elements for dim
+#--
+int i # loop index
+
+begin
+ if (dim == NULL)
+ return
+
+ do i = 1, maxcols { # zero indexed
+ if (Memi[dim+i-1] != NULL)
+ call mfree (Memi[dim+i-1], TY_INT)
+ }
+ call mfree (dim, TY_POINTER)
+end
+
+# c_user_par -- count header parameters
+# This routine opens an input ASCII file containing header parameters
+# and counts the number of such parameters. If the input file exists
+# and does contain parameters, the file will be left open; otherwise,
+# the input file will be closed, and both npar and uparfd will be set
+# to zero.
+# Blank and comment lines are ignored.
+
+procedure c_user_par (pname, uparfd, npar)
+
+char pname[ARB] # i: name of file of header parameters
+int uparfd # o: fd for input file of header parameters
+int npar # o: number of header parameters in file
+#--
+pointer sp
+pointer lbuf # scratch for input line buffer
+int linenum # line number counter (ignored)
+int access(), open(), g_next_l()
+
+begin
+ uparfd = NULL # initial values
+ npar = 0
+
+ if (pname[1] == EOS) {
+ return
+ } else if (access (pname, 0, 0) == NO) {
+ call eprintf ("WARNING: can't read file %s.\n")
+ call pargstr (pname)
+ return
+ }
+ uparfd = open (pname, READ_ONLY, TEXT_FILE)
+
+ call smark (sp)
+ call salloc (lbuf, SZ_LONG_LINE, TY_CHAR)
+
+ linenum = 0
+ while (g_next_l (uparfd, Memc[lbuf], SZ_LONG_LINE, linenum) != EOF)
+ npar = npar + 1
+
+ call sfree (sp)
+ if (npar <= 0) {
+ call close (uparfd)
+ uparfd = NULL
+ }
+end
+
+
+# cp_upar_tbl -- copy header parameters to table
+# This routine reads header parameters (keyword, type, value) from an
+# ASCII file and writes them to the table. The input file is then closed.
+# If uparfd is zero then it is assumed that the file does not exist.
+
+procedure cp_upar_tbl (tp, uparfd, histflag)
+
+pointer tp # i: pointer to table descriptor
+int uparfd # io: fd for file of header parameters
+bool histflag # i: add a history record with current date?
+#--
+pointer sp
+pointer lbuf # scratch for input line buffer
+pointer datetime # scratch for date and time
+pointer history # scratch for history record
+char keyword[SZ_KEYWORD] # keyword for parameter
+char chdtype[SZ_DTYPE] # column data type expressed as a char string
+long old_time, new_time # zero; current clock time
+int datatype # data type: TY_CHAR, etc
+int linenum # line number counter (ignored)
+int ip # counter for indexing in line buffer
+int parnum # parameter number (ignored)
+int tbltype # table type, to check for fits type
+int g_next_l(), ctowrd()
+int tbpsta(), tbfres()
+long clktime()
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LONG_LINE, TY_CHAR)
+
+ tbltype = tbpsta (tp, TBL_WHTYPE)
+
+ # If there is a file of header parameters, read them and add to the
+ # table header.
+ if (uparfd != NULL) {
+
+ call seek (uparfd, BOF) # rewind to beginning of file
+ linenum = 0
+ while (g_next_l (uparfd, Memc[lbuf], SZ_LONG_LINE,
+ linenum) != EOF) {
+ ip = 1
+ # Read: keyword datatype value comment
+ if (ctowrd (Memc[lbuf], ip, keyword, SZ_KEYWORD) <= 0) {
+ call eprintf ("line is `%s'\n")
+ call pargstr (Memc[lbuf])
+ call error (1, "bad line in 'uparfile'")
+ }
+ if (tbltype == TBL_TYPE_FITS && tbfres (keyword) == YES)
+ next # skip reserved keywords if FITS table
+ if (ctowrd (Memc[lbuf], ip, chdtype, SZ_DTYPE) <= 0) {
+ call eprintf ("line is `%s'\n")
+ call pargstr (Memc[lbuf])
+ call error (1, "bad line in 'uparfile'")
+ }
+ call strlwr (chdtype)
+ datatype = chdtype[1]
+ switch (datatype) {
+ case 'r':
+ datatype = TY_REAL
+ case 'i':
+ datatype = TY_INT
+ case 'd':
+ datatype = TY_DOUBLE
+ case 'b':
+ datatype = TY_BOOL
+ default:
+ datatype = TY_CHAR
+ }
+ while (IS_WHITE(Memc[lbuf+ip-1]))
+ ip = ip + 1
+ call tbhanp (tp, keyword, datatype, Memc[lbuf+ip-1], parnum)
+ }
+ # Close the input ASCII file containing header parameters.
+ call close (uparfd)
+ }
+
+ if (histflag) {
+
+ call salloc (datetime, SZ_TIME, TY_CHAR)
+ call salloc (history, SZ_LINE, TY_CHAR)
+
+ old_time = 0
+ new_time = clktime (old_time)
+ call cnvtime (new_time, Memc[datetime], SZ_TIME)
+ call strcpy ("Created ", Memc[history], SZ_LINE)
+ call strcat (Memc[datetime], Memc[history], SZ_LINE)
+
+ call tbhadt (tp, "history", Memc[history])
+ }
+
+ call sfree (sp)
+end
+
+
+# cp_dat_tbl -- copy data to table
+# This routine reads from an ASCII data file and writes the values to
+# the table. A subroutine is called to do the actual copying for each row.
+
+procedure cp_dat_tbl (dname, tp, cptr, nskip, nlines, nrows)
+
+char dname[ARB] # i: name of file containing table data
+pointer tp # i: pointer to table descriptor
+pointer cptr[ARB] # i: array of pointers to column descriptors
+int nskip # i: number of lines to skip at beginning
+int nlines # i: number of lines per data file record
+int nrows # i: upper limit on number of rows (if > 0)
+#--
+pointer sp
+pointer linebuf # scratch for skipping header lines
+int fd # file descriptor for ASCII data file
+int rownum # row number
+int linenum # line number counter
+int k # loop index
+int stat
+bool done
+int access(), open(), getlline(), fstati()
+bool streq()
+
+begin
+ if (dname[1] == EOS) {
+ return
+ } else if (access (dname, 0, 0) == NO) {
+ call eprintf ("WARNING: file `%s' does not exist;\n")
+ call pargstr (dname)
+ call eprintf (" ... an empty table will be created.\n")
+ return
+ } else if (streq (dname, "STDIN")) {
+ # Print a prompt if the input is not redirected.
+ if (fstati (STDIN, F_REDIR) == NO) {
+ call printf (
+ "Give table data ... then newline & EOF to finish.\n")
+ call flush (STDOUT)
+ }
+ }
+ fd = open (dname, READ_ONLY, TEXT_FILE)
+
+ # Skip "header" lines.
+ if (nskip > 0) {
+ call smark (sp)
+ call salloc (linebuf, SZ_LONG_LINE, TY_CHAR)
+ do k = 1, nskip
+ stat = getlline (fd, Memc[linebuf], SZ_LONG_LINE)
+ call sfree (sp) # done with scratch space
+ }
+
+ # Read each record (which may be more than one line) from the
+ # data file, and write the values to the output row in the table.
+ rownum = 1
+ linenum = nskip # number of lines read so far
+ done = false
+ while ( !done ) {
+ call row_copy (tp, fd, cptr, rownum, nlines, linenum, done)
+ rownum = rownum + 1
+ if (nrows > 0 && rownum > nrows)
+ done = true
+ }
+ call close (fd)
+end
+
+
+
+# row_copy -- copy to a row of the table
+# This routine reads one or more records from data file and writes
+# a single row to the table.
+
+procedure row_copy (tp, fd, cptr, rownum, nlines, linenum, done)
+
+pointer tp # i: pointer to table descriptor
+pointer cptr[ARB] # i: array of pointers to column descriptors
+int fd # i: file descriptor for input data file
+int rownum # i: row number in table
+int nlines # i: number of lines per data file record
+int linenum # io: line number counter
+bool done # io: set to true when finished
+#--
+pointer sp
+pointer lbuf # buffer for reading from data file
+int ncols # number of columns in table
+int col # loop index (column number)
+int k # loop index for skipping lines
+int dtype # data type of a column (-n for char)
+int nelem # number of elements in array
+int i # loop index for element number
+int n # counter for number of lines per table row
+int ip # index in line buffer lbuf
+int nchar # number of char in text string
+int stat
+pointer str # buffer for value to be put in table
+double dval # "
+int ival # "
+bool bval
+int tbpsta(), tbcigi(), g_next_l(), tcr_ctoi(), ctod(), ctowrd()
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call salloc (lbuf, SZ_LONG_LINE, TY_CHAR)
+
+ ncols = tbpsta (tp, TBL_NCOLS)
+
+ n = 1
+ if (g_next_l (fd, Memc[lbuf], SZ_LONG_LINE, linenum) == EOF) {
+ done = true
+ return
+ }
+ ip = 1
+ for (col=1; col<=ncols; col=col+1) {
+ dtype = tbcigi (cptr[col], TBL_COL_DATATYPE)
+ nelem = tbcigi (cptr[col], TBL_COL_LENDATA)
+ switch (dtype) {
+ case TY_REAL,TY_DOUBLE:
+ do i = 1, nelem {
+ if (ctod (Memc[lbuf], ip, dval) < 1) {
+ if (nlines > 0 && n >= nlines)
+ return # ignore any remaining columns
+
+ # Print warning if we're not really at the end of line.
+ call tcr_check_eol (Memc[lbuf+ip-1], linenum)
+
+ if (g_next_l (fd, Memc[lbuf], SZ_LONG_LINE,
+ linenum) == EOF) {
+ done = true
+ return
+ }
+ n = n + 1
+ ip = 1
+ if (ctod (Memc[lbuf], ip, dval) < 1) {
+ call sprintf (Memc[str], SZ_LINE,
+ "badly out of synch in line %d in data file\n")
+ call pargi (linenum)
+ call error (1, Memc[str])
+ }
+ }
+ call tbaptd (tp, cptr[col], rownum, dval, i, 1)
+ }
+
+ case TY_INT,TY_SHORT:
+ do i = 1, nelem {
+ if (tcr_ctoi (Memc[lbuf], ip, ival, linenum) < 1) {
+ if (nlines > 0 && n >= nlines)
+ return # ignore any remaining columns
+
+ call tcr_check_eol (Memc[lbuf+ip-1], linenum)
+
+ if (g_next_l (fd, Memc[lbuf], SZ_LONG_LINE,
+ linenum) == EOF) {
+ done = true
+ return
+ }
+ n = n + 1
+ ip = 1
+ if (tcr_ctoi (Memc[lbuf], ip, ival, linenum) < 1) {
+ call sprintf (Memc[str], SZ_LINE,
+ "badly out of synch in line %d in data file\n")
+ call pargi (linenum)
+ call error (1, Memc[str])
+ }
+ }
+ call tbapti (tp, cptr[col], rownum, ival, i, 1)
+ }
+
+ case TY_BOOL:
+ do i = 1, nelem {
+ if (ctowrd (Memc[lbuf], ip, Memc[str], SZ_LINE) < 1) {
+ if (nlines > 0 && n >= nlines)
+ return # ignore any remaining columns
+
+ call tcr_check_eol (Memc[lbuf+ip-1], linenum)
+
+ if (g_next_l (fd, Memc[lbuf], SZ_LONG_LINE,
+ linenum) == EOF) {
+ done = true
+ return
+ }
+ n = n + 1
+ ip = 1
+ if (ctowrd (Memc[lbuf], ip, Memc[str], SZ_LINE) < 1) {
+ call sprintf (Memc[str], SZ_LINE,
+ "badly out of synch in line %d in data file\n")
+ call pargi (linenum)
+ call error (1, Memc[str])
+ }
+ }
+ call strlwr (Memc[str])
+ if (Memc[str] == 'y' || Memc[str] == 't') # yes or true
+ bval = true
+ else if (Memc[str] == 'n' || Memc[str] == 'f') # no or false
+ bval = false
+ else {
+ call strcat (" is not a valid Boolean value",
+ Memc[str], SZ_LINE)
+ call error (1, Memc[str])
+ }
+ call tbaptb (tp, cptr[col], rownum, bval, i, 1)
+ }
+
+ default:
+ if (dtype >= 0)
+ call error (1, "invalid data type got past tbbtyp")
+
+ do i = 1, nelem {
+ # Be careful to distinguish between a value of "" at the
+ # end of a line and actually reaching the end of the line;
+ # ctowrd returns 0 in both cases. First skip whitespace.
+ while (IS_WHITE(Memc[lbuf+ip-1]))
+ ip = ip + 1
+ if (Memc[lbuf+ip-1] == '\n' || Memc[lbuf+ip-1] == EOS) {
+ if (nlines > 0 && n >= nlines)
+ return # ignore any remaining columns
+ if (g_next_l (fd, Memc[lbuf], SZ_LONG_LINE,
+ linenum) == EOF) {
+ done = true
+ return
+ }
+ n = n + 1
+ ip = 1
+ }
+ nchar = ctowrd (Memc[lbuf], ip, Memc[str], SZ_LINE)
+ if (nchar > 0)
+ call tbaptt (tp, cptr[col], rownum,
+ Memc[str], nchar, i, 1)
+ }
+ }
+ }
+ # Skip extra lines if all columns gotten in fewer than nlines lines.
+ do k = n+1, nlines {
+ iferr (stat = g_next_l (fd, Memc[lbuf], SZ_LONG_LINE, linenum))
+ break
+ }
+
+ call sfree (sp)
+end
+
+# tcr_check_eol -- check for end of data
+# This routine checks whether the remainder of the line contains anything
+# other than whitespace and comments. If it does, a warning is printed.
+
+procedure tcr_check_eol (lbuf, linenum)
+
+char lbuf[ARB] # i: input line
+int linenum # i: line number for warning message
+#--
+int ip # loop index into lbuf
+bool line_empty # true if the line is empty
+bool done # loop termination flag
+
+begin
+ line_empty = false
+
+ ip = 1
+ done = false
+ while (!done) {
+ if (lbuf[ip] == ' ' || lbuf[ip] == '\t') { # skip whitespace
+ ip = ip + 1
+ } else if (lbuf[ip] == '\n' || lbuf[ip] == EOS) {
+ line_empty = true
+ done = true
+ } else if (lbuf[ip] == '#') {
+ line_empty = true
+ done = true
+ } else {
+ line_empty = false
+ done = true
+ }
+ }
+
+ if (!line_empty) {
+ call eprintf ("out of synch or extra data in line %d\n")
+ call pargi (linenum)
+ }
+end
+
+# tcr_nelem -- separate array length from data type
+# This routine takes a character string as input and returns the data
+# type, total array length, dimension of array, and length of each axis.
+# The syntax for axis lengths is numbers separated by commas, enclosed in
+# brackets or parentheses, following the data type. For example, a 3-D
+# array of 8-byte character strings with axis lengths of 30, 70, and 5
+# would be specified as ch*8[30,70,5]. The first axis is the most rapidly
+# varying (i.e. Fortran notation).
+#
+# The output data type is the usual integer code, e.g. TY_REAL, except
+# that for a character string of length N the code is -N. This is the
+# data type that would be given as input to tbcdef. The default data
+# type is real (TY_REAL).
+
+procedure tcr_nelem (chdtype, ndim, axlen, maxdim, nelem, dtype)
+
+char chdtype[ARB] # i: data type and dimensions
+int ndim # o: dimension of array
+int axlen[maxdim] # o: length of each axis of array
+int maxdim # i: size of array axlen
+int nelem # o: total number of elements in array
+int dtype # o: data type of column for input to tbcdef
+#--
+char temp[SZ_DTYPE] # scratch for copy of chdtype
+char lbracket # '['
+char lparen # '('
+char endchar # ']' or ')', as appropriate
+int indexb, indexp # locations of '[' and '(' in chdtype
+int ip, ctoi()
+int i, length # current dimension and axis length
+bool done # to stop loop over dimensions
+int stridx()
+string errmessage "data type `%s':\n"
+
+begin
+ lparen = '('
+ lbracket = '['
+
+ ndim = 1 # initial values
+ nelem = 1
+ do i = 1, maxdim
+ axlen[i] = 1
+
+ if (chdtype[1] == EOS) {
+ dtype = TY_REAL # default
+ return
+ }
+
+ call strcpy (chdtype, temp, SZ_DTYPE)
+ indexb = stridx (lbracket, chdtype) # "[" found?
+ indexp = stridx (lparen, chdtype) # "(" found?
+ done = false
+ if (indexb > 0 && indexp > 0) {
+ call eprintf (errmessage)
+ call pargstr (chdtype)
+ call error (1, "can't include both '[' and '('")
+ } else if (indexb > 0) {
+ endchar = ']'
+ ip = indexb
+ temp[ip] = EOS # now temp is just the data type
+ } else if (indexp > 0) {
+ endchar = ')'
+ ip = indexp
+ temp[ip] = EOS
+ } else {
+ done = true # don't try to extract array size
+ }
+
+ # Convert the string to integer code (e.g. "r" --> TY_REAL).
+ iferr {
+ call tbbtyp (temp, dtype)
+ } then {
+ call eprintf (errmessage)
+ call pargstr (chdtype)
+ call erract (EA_ERROR)
+ }
+
+ # Read axis lengths from brackets, if given.
+ i = 0
+ ip = ip + 1 # skip over '['
+ while (!done) {
+
+ if (ctoi (chdtype, ip, length) < 1) {
+ call eprintf (errmessage)
+ call pargstr (chdtype)
+ call error (1, "syntax error")
+
+ }
+
+ i = i + 1 # increment dimension
+ if (i > maxdim) {
+ call eprintf (errmessage)
+ call pargstr (chdtype)
+ call error (1, "dimension is too high")
+ }
+
+ if (length <= 0) {
+ call eprintf (errmessage)
+ call pargstr (chdtype)
+ call error (1, "axis lengths must be positive")
+ }
+
+ ndim = i
+ axlen[ndim] = length
+ nelem = nelem * length
+
+ if (chdtype[ip] == ',') { # separator between dimensions
+ ip = ip + 1
+ } else if (chdtype[ip] == endchar) { # ']' or ')'
+ done = true
+ } else if (chdtype[ip] == EOS) {
+ call eprintf (errmessage)
+ call pargstr (chdtype)
+ call eprintf ("info: missing `%c' assumed\n")
+ call pargc (endchar)
+ done = true
+ }
+ }
+end
+
+# tcr_ctoi -- ctoi, ignoring "+" sign
+# This calls ctoi after skipping over any whitespace and/or a plus sign.
+# Note that we allow whitespace after the sign as well as before. This
+# is reasonable because we know (from the cdfile) that we're getting an
+# integer rather than an arbitrary character string.
+#
+# After reading an integer value, if the next character in the input
+# string is not whitespace and not the end of the line, the word will be
+# reread from the input string as a double. If the value is actually
+# an integer, even though the string may contain a decimal point or an
+# exponent (e.g. "5." or "1.e2"), the integer will be returned as the
+# value of n. If the value has a fractional part, that's an error.
+
+int procedure tcr_ctoi (input, ip, n, linenum)
+
+char input[ARB] # i: input string
+int ip # io: starting/ending index in INPUT
+int n # o: value read from string
+int linenum # i: line number for possible error message
+#--
+pointer sp, word # in case value is floating point
+int i # local copy of integer value from string
+int nvals # value returned by ctoi
+bool positive # true if value is positive
+int ctoi(), ctod(), ctowrd()
+int ip_save # so we can call ctod() or ctowrd()
+double x
+
+begin
+ positive = true # initial value
+
+ while (IS_WHITE(input[ip])) # skip leading whitespace
+ ip = ip + 1
+
+ if (input[ip] == '+') # ignore "+" sign
+ ip = ip + 1
+
+ if (input[ip] == '-') { # make note of "-" sign
+ ip = ip + 1
+ positive = false
+ }
+
+ ip_save = ip
+
+ nvals = ctoi (input, ip, i)
+
+ # Allow for the possibility that the buffer contains a floating
+ # point value.
+ if (!IS_WHITE(input[ip]) && input[ip] != EOS) {
+
+ # Conversion to int was terminated before the end of the word.
+ ip = ip_save
+ nvals = ctod (input, ip, x)
+ if (nvals > 0) {
+ i = int (x)
+ if (x != double(i)) {
+ # There is a fractional part; this is an error.
+ call smark (sp)
+ call salloc (word, SZ_FNAME, TY_CHAR)
+ ip = ip_save
+ nvals = ctowrd (input, ip, Memc[word], SZ_FNAME)
+ call eprintf ("`%s' in line %d is not an integer\n")
+ call pargstr (Memc[word])
+ call pargi (linenum)
+ call error (1, "data type conflict with cdfile")
+ }
+ }
+ }
+
+ if (nvals < 1)
+ n = INDEFI
+ else if (positive)
+ n = i
+ else
+ n = -i
+
+ return (nvals)
+end
diff --git a/pkg/utilities/nttools/tdelete.par b/pkg/utilities/nttools/tdelete.par
new file mode 100644
index 00000000..1397c29a
--- /dev/null
+++ b/pkg/utilities/nttools/tdelete.par
@@ -0,0 +1,5 @@
+table,s,a,"",,,"list of tables to be deleted"
+verify,b,h,no,,,verify operation before deleting each table?
+default_action,b,h,yes,,,default delete action for verify query
+go_ahead,b,q,yes,,," ?"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/tdiffer.par b/pkg/utilities/nttools/tdiffer.par
new file mode 100644
index 00000000..b97ba246
--- /dev/null
+++ b/pkg/utilities/nttools/tdiffer.par
@@ -0,0 +1,6 @@
+intable1,f,a,,,,name of the first table
+intable2,f,a,,,,name of the second table
+outtable,s,a,,,,name of output table
+colnam1,s,a,,,,name of columns in first table
+colnam2,s,a,,,,name of columns in second table
+mode,s,h,"a",,,
diff --git a/pkg/utilities/nttools/tdiffer/mkpkg b/pkg/utilities/nttools/tdiffer/mkpkg
new file mode 100644
index 00000000..93240165
--- /dev/null
+++ b/pkg/utilities/nttools/tdiffer/mkpkg
@@ -0,0 +1,12 @@
+# Update the tdiffer application code in the ttools package library
+# Author: B.Simon, 14-JUN-88
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ tbldiff.x <tbset.h>
+ tdiffer.x <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/tdiffer/tbldiff.x b/pkg/utilities/nttools/tdiffer/tbldiff.x
new file mode 100644
index 00000000..b6ee7db4
--- /dev/null
+++ b/pkg/utilities/nttools/tdiffer/tbldiff.x
@@ -0,0 +1,99 @@
+include <tbset.h>
+
+# TBL_DIFF -- Find rows in the first table which are not in the second
+#
+# B.Simon 15-Jun-88 First Code
+# B.Simon 05-Feb-90 Revised to use tbtsrt and tbrcmp
+
+procedure tbl_diff (tp1, tp2, otp, nptr, col1, col2)
+
+pointer tp1 # i: Table descriptor of first input table
+pointer tp2 # i: Table descriptor of second input table
+pointer otp # i: Output table descriptor
+int nptr # i: Number of column pointers
+pointer col1[ARB] # i: Array of column pointers for first table
+pointer col2[ARB] # i: Array of column pointers for second table
+#--
+bool fold
+int irow1, irow2, nrow1, nrow2, order, orow, iptr
+pointer sp, colname, row1, row2, ocol
+
+int tbrcmp()
+
+begin
+ # Allocate dynamic memory for column name
+
+ call smark (sp)
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+
+ # Sort the array on the selected columns.
+
+ fold = false
+ call allrows (tp1, nrow1, row1)
+ call allrows (tp2, nrow2, row2)
+
+ call tbtsrt (tp1, nptr, col1, fold, nrow1, Memi[row1])
+ call tbtsrt (tp2, nptr, col2, fold, nrow2, Memi[row2])
+
+ # Get the column pointers to compare on in the output tables
+
+ call malloc (ocol, nptr, TY_INT)
+ do iptr = 1, nptr {
+ call tbcigt (col1[iptr], TBL_COL_NAME, Memc[colname], SZ_COLNAME)
+ call tbcfnd (otp, Memc[colname], Memi[ocol+iptr-1], 1)
+ }
+
+ # Search for rows in first table which are not in the second
+
+ orow = 1
+ irow1 = 0
+ irow2 = 0
+
+ while (irow1 < nrow1 && irow2 < nrow2) {
+
+ # Copy rows from both tables into output table
+
+ call tbrcpy (tp1, otp, Memi[row1+irow1], orow)
+ call tbrcsc (tp2, otp, col2, Memi[ocol], Memi[row2+irow2],
+ orow+1, nptr)
+
+ # Update row indices and add row1 to output table
+ # if it is not in the second table
+
+ order = tbrcmp (otp, nptr, Memi[ocol], fold, orow, orow+1)
+
+ switch (order) {
+ case -1:
+ irow1 = irow1 + 1
+ orow = orow + 1
+ case 0:
+ irow1 = irow1 + 1
+ case 1:
+ irow2 = irow2 + 1
+ }
+ }
+
+ # Delete extra rows from output table
+
+ if (order < 0)
+ call tbrdel (otp, orow, orow)
+ else
+ call tbrdel (otp, orow, orow+1)
+
+ # Add remaining rows of first table to output table
+
+ while (irow1 < nrow1) {
+ call tbrcpy (tp1, otp, Memi[row1+irow1], orow)
+ irow1 = irow1 + 1
+ orow = orow + 1
+ }
+
+
+ # Free dynamic memory
+
+ call mfree (row1, TY_INT)
+ call mfree (row2, TY_INT)
+ call mfree (ocol, TY_INT)
+ call sfree (sp)
+
+end
diff --git a/pkg/utilities/nttools/tdiffer/tdiffer.x b/pkg/utilities/nttools/tdiffer/tdiffer.x
new file mode 100644
index 00000000..9c30e82f
--- /dev/null
+++ b/pkg/utilities/nttools/tdiffer/tdiffer.x
@@ -0,0 +1,92 @@
+include <tbset.h>
+
+define SYNTAX 1
+
+# TDIFFER -- Create a new table which is the difference of two old tables
+#
+# B.Simon 14-Jun-1988 First Code
+# Phil Hodge 7-Sep-1988 Change parameter names for tables.
+# Phil Hodge 8-Apr-1999 Call tbfpri.
+
+procedure t_tdiffer()
+
+pointer tab1 # First table
+pointer tab2 # Second table
+pointer outtab # Output table
+pointer colnam1 # Columns to match in first table
+pointer colnam2 # Columns to match in second table
+#--
+int nptr1, nptr2, ncol1, ncol2
+int phu_copied # set by tbfpri and ignored
+pointer sp, tp1, tp2, otp, col1, col2
+
+string notfound "Column(s) not found in table"
+string colnumerr "Number of columns do not agree"
+
+int tbpsta()
+pointer tbtopn()
+
+begin
+ # Allocate stack memory for strings
+
+ call smark (sp)
+ call salloc (tab1, SZ_FNAME, TY_CHAR)
+ call salloc (tab2, SZ_FNAME, TY_CHAR)
+ call salloc (outtab, SZ_FNAME, TY_CHAR)
+ call salloc (colnam1, SZ_LINE, TY_CHAR)
+ call salloc (colnam2, SZ_LINE, TY_CHAR)
+
+ # Read the task parameters
+
+ call clgstr ("intable1", Memc[tab1], SZ_LINE)
+ call clgstr ("intable2", Memc[tab2], SZ_LINE)
+ call clgstr ("outtable", Memc[outtab], SZ_LINE)
+ call clgstr ("colnam1", Memc[colnam1], SZ_LINE)
+ call clgstr ("colnam2", Memc[colnam2], SZ_LINE)
+
+ # Open the tables and create column arrays
+
+ tp1 = tbtopn (Memc[tab1], READ_ONLY, NULL)
+ ncol1 = tbpsta (tp1, TBL_NCOLS)
+ call malloc (col1, ncol1, TY_INT)
+
+ tp2 = tbtopn (Memc[tab2], READ_ONLY, NULL)
+ ncol2 = tbpsta (tp2, TBL_NCOLS)
+ call malloc (col2, ncol2, TY_INT)
+
+ # Open output table and copy header(s) from first table
+
+ call tbfpri (Memc[tab1], Memc[outtab], phu_copied)
+ otp = tbtopn (Memc[outtab], NEW_COPY, tp1)
+ call tbtcre (otp)
+ call tbhcal (tp1, otp)
+
+ # Create two arrays of column pointers from the column templates
+
+ call tctexp (tp1, Memc[colnam1], ncol1, nptr1, Memi[col1])
+ if (nptr1 == 0)
+ call error (SYNTAX, notfound)
+
+ call tctexp (tp2, Memc[colnam2], ncol2, nptr2, Memi[col2])
+ if (nptr2 == 0)
+ call error (SYNTAX, notfound)
+
+ if (nptr1 != nptr2)
+ call error (SYNTAX, colnumerr)
+
+ # Retrieve the indices of the rows of the first table which are
+ # not in the second table
+
+ call tbl_diff (tp1, tp2, otp, nptr1, Memi[col1], Memi[col2])
+
+ # Close the tables and free dynamic memory
+
+ call tbtclo (tp1)
+ call tbtclo (tp2)
+ call tbtclo (otp)
+
+ call mfree (col1, TY_INT)
+ call mfree (col2, TY_INT)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tdump.par b/pkg/utilities/nttools/tdump.par
new file mode 100644
index 00000000..f7e5814a
--- /dev/null
+++ b/pkg/utilities/nttools/tdump.par
@@ -0,0 +1,8 @@
+table,s,a,"",,,"name of table to dump"
+cdfile,s,h,"STDOUT",,,"output file for column definitions"
+pfile,s,h,"STDOUT",,,"output file for header parameters"
+datafile,s,h,"STDOUT",,,"output file for table data"
+columns,s,h,"",,,"list of columns to be dumped"
+rows,s,h,"-",,,"range of rows to print"
+pwidth,i,h,-1,-1,,"output page width"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/tedit.par b/pkg/utilities/nttools/tedit.par
new file mode 100644
index 00000000..97f705e5
--- /dev/null
+++ b/pkg/utilities/nttools/tedit.par
@@ -0,0 +1,6 @@
+table,f,a,,,,Input table
+columns,s,h," ",,,List of columns to edit
+silent,b,h,no,,,Don't ring bell?
+rdonly,b,h,no,,,Edit table read only?
+inplace,b,h,no,,,Edit table in place?
+mode,s,h,al
diff --git a/pkg/utilities/nttools/tedit/bell.x b/pkg/utilities/nttools/tedit/bell.x
new file mode 100644
index 00000000..dd939e4e
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/bell.x
@@ -0,0 +1,19 @@
+# RING_BELL -- Ring the bell to wake up the user
+
+procedure ring_bell ()
+
+bool silent # i: do not ring bell
+#--
+bool ring # variable used to hold the value of silent
+
+begin
+ if (ring)
+ call ps_beep
+ return
+
+ entry init_bell (silent)
+
+ ring = ! silent
+ return
+
+end
diff --git a/pkg/utilities/nttools/tedit/command.com b/pkg/utilities/nttools/tedit/command.com
new file mode 100644
index 00000000..391c025e
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/command.com
@@ -0,0 +1,6 @@
+# COMMAND.COM -- Global variables used by commands
+
+int direction # Search direction
+char search_exp[SZ_LINE] # Search expression
+
+common /search/ direction, search_exp
diff --git a/pkg/utilities/nttools/tedit/command.h b/pkg/utilities/nttools/tedit/command.h
new file mode 100644
index 00000000..5e4956f1
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/command.h
@@ -0,0 +1,21 @@
+# COMMAND.H -- Commands which can be executed from the prompt line
+
+define TED_CMDLIST "|add|copy|delete|exit|find|goto|help|insert|lower|next|\
+quit|set|substitute|upper|"
+
+define TED_ADD 1
+define TED_COPY 2
+define TED_DELETE 3
+define TED_EXIT 4
+define TED_FIND 5
+define TED_GOTO 6
+define TED_HELP 7
+define TED_INSERT 8
+define TED_LOWER 9
+define TED_NEXT 10
+define TED_QUIT 11
+define TED_SET 12
+define TED_SUBSTITUTE 13
+define TED_UPPER 14
+
+
diff --git a/pkg/utilities/nttools/tedit/command.x b/pkg/utilities/nttools/tedit/command.x
new file mode 100644
index 00000000..185ad103
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/command.x
@@ -0,0 +1,1458 @@
+include <tbset.h>
+include "screen.h"
+include "table.h"
+include "paste.h"
+include "field.h"
+include "command.h"
+
+define BLANK ' '
+define SQUOTE '\''
+define DQUOTE '"'
+define HARMLESS 0.11
+define MAXROWS 10000
+
+# ADD_CMD -- Add a column or row to the table
+
+procedure add_cmd (scr, nargs, arglist)
+
+pointer scr # i: Current screen descriptor
+int nargs # i: Number of arguments
+char arglist[ARB] # i: Argument list
+#--
+int which, iarg
+pointer sp, what, tab
+
+string options "|row|column|"
+string notadded "Cannot add column to table"
+
+int strdic(), option_cmd()
+
+begin
+ call smark (sp)
+ call salloc (what, SZ_LINE, TY_CHAR)
+
+ tab = TED_TABLE(scr)
+
+ # Determine whether a row or column should be added
+
+ which = option_cmd (options, nargs, arglist)
+
+ while (which == 0) {
+ iarg = nargs + 1
+ call getstr_cmd ("Add row or column", iarg, nargs, arglist,
+ Memc[what], SZ_LINE)
+ which = strdic (Memc[what], Memc[what], SZ_LINE, options)
+ }
+
+ # Call the appropriate routine
+
+ if (which == 1) {
+ call addrow_cmd (scr, nargs, arglist)
+
+ } else if (TED_ALLCOLS(tab) == YES) {
+ call addcol_cmd (scr, nargs, arglist)
+
+ } else {
+ call warn1_prompt (scr, notadded)
+ }
+
+ call sfree (sp)
+end
+
+# ADDCOL_CMD -- Add a new column to the table
+
+procedure addcol_cmd (scr, nargs, arglist)
+
+pointer scr # i: Current screen descriptor
+int nargs # i: Number of arguments
+char arglist[ARB] # i: Argument list
+#--
+int iarg, type, icol, ncol, code, clen
+pointer sp, cname, cunits, ftnfmt, sppfmt, ctype, errmsg
+pointer tab, paste, tp, cp
+
+string nowrite "Cannot change read only table"
+string nullcol "No column added to table"
+string nocolumn "Cannot add column"
+string nopaste "Could not add column to paste table"
+
+int errget(), tbcigi(), strlen()
+pointer tbcnum()
+
+begin
+ # Check for read only table
+
+ tab = TED_TABLE(scr)
+ if (TED_READONLY(tab) == YES) {
+ call warn1_prompt (scr, nowrite)
+ return
+ }
+
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (cname, SZ_COLNAME, TY_CHAR)
+ call salloc (cunits, SZ_COLUNITS, TY_CHAR)
+ call salloc (ftnfmt, SZ_COLFMT, TY_CHAR)
+ call salloc (sppfmt, SZ_COLFMT, TY_CHAR)
+ call salloc (ctype, SZ_FNAME, TY_CHAR)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ # Get table descriptors from screen structure
+
+ paste = TED_PASTE(scr)
+ tp = TED_TABPTR(tab)
+
+ # Get parameters defining new column
+
+ call getstr_cmd ("Column name", 2, nargs, arglist,
+ Memc[cname], SZ_COLNAME)
+
+ if (Memc[cname] == EOS) {
+ call write_prompt (scr, NO, nullcol)
+ return
+ }
+
+ iarg = 3
+ repeat {
+ call getstr_cmd ("Column type (r,d,i,s,b,ch*n)", iarg, nargs,
+ arglist, Memc[ctype], SZ_FNAME)
+
+ iferr (call tbbtyp (Memc[ctype], type)) {
+ iarg = nargs + 1
+ call ring_bell
+ } else {
+ break
+ }
+ }
+
+ iarg = 4
+ repeat {
+ call getstr_cmd ("Column print format", iarg, nargs, arglist,
+ Memc[ftnfmt], SZ_COLFMT)
+ call tbbftp (Memc[ftnfmt], Memc[sppfmt])
+
+ if (Memc[sppfmt] == EOS && Memc[ftnfmt] != EOS) {
+ iarg = nargs + 1
+ call ring_bell
+ } else {
+ break
+ }
+ }
+
+ call getstr_cmd ("Column units", 5, nargs, arglist,
+ Memc[cunits], SZ_COLUNITS)
+
+ # Add new column to paste table
+
+ if (paste != NULL) {
+ iferr {
+ call tbcdef (TED_PSTPTR(paste), cp, Memc[cname], Memc[cunits],
+ Memc[sppfmt], type, 1, 1)
+ } then {
+ call warn1_prompt (scr, nopaste)
+ return
+ }
+ }
+
+ # Add new column to table
+
+ iferr {
+ call tbcdef (tp, cp, Memc[cname], Memc[cunits],
+ Memc[sppfmt], type, 1, 1)
+ } then {
+ code = errget (Memc[errmsg], SZ_LINE)
+ call warn2_prompt (scr, nocolumn, Memc[errmsg])
+ return
+ }
+
+ # Free old arrays containing table info and create new ones
+
+ ncol = TED_NCOLS(tab) + 1
+ call mfree (TED_COLARY(tab), TY_INT)
+ call mfree (TED_TYPARY(tab), TY_INT)
+ call mfree (TED_LENARY(tab), TY_INT)
+
+ call malloc (TED_COLARY(tab), ncol, TY_INT)
+ call malloc (TED_TYPARY(tab), ncol, TY_INT)
+ call malloc (TED_LENARY(tab), ncol, TY_INT)
+
+ # Load new column info into arrays
+
+ TED_DIRTY(tab) = YES
+ TED_NCOLS(tab) = ncol
+ do icol = 1, ncol {
+ cp = tbcnum (tp, icol)
+ TED_COLPTR(tab, icol) = cp
+ TED_COLTYPE (tab,icol) = tbcigi (cp, TBL_COL_DATATYPE)
+ clen = tbcigi (cp, TBL_COL_FMTLEN)
+ call tbcigt (cp, TBL_COL_NAME, Memc[cname], SZ_COLNAME)
+ TED_COLLEN(tab,icol) = max (clen, strlen(Memc[cname]))
+ }
+
+ # Redraw screen
+
+ call move_screen (scr, LEFT, YES)
+ call sfree (sp)
+end
+
+# ADDROW_CMD -- Add null rows to the table
+
+procedure addrow_cmd (scr, nargs, arglist)
+
+pointer scr # i: Current screen descriptor
+int nargs # i: Number of arguments
+char arglist[ARB] # i: Argument list
+#--
+int nrow, row, numadd
+pointer tab, tptr
+
+string nowrite "Cannot change read only table"
+
+int tbpsta()
+
+begin
+ # Check for read only table
+
+ tab = TED_TABLE(scr)
+ if (TED_READONLY(tab) == YES) {
+ call warn1_prompt (scr, nowrite)
+ return
+ }
+
+ # Get current number of rows in the table
+
+ tptr = TED_TABPTR(tab)
+ nrow = tbpsta (tptr ,TBL_NROWS)
+
+ # Read command parameters
+
+ call getint_cmd ("Add after row", 2, nargs, arglist,
+ TED_CURROW(scr), 0, nrow, row)
+
+ call getint_cmd ("Number of rows to add", 3, nargs, arglist,
+ 1, 0, INDEFI, numadd)
+
+ # Return if number of rows to add is zero
+
+ if (numadd == 0)
+ return
+
+ # Add null rows to table
+
+ TED_DIRTY(tab) = YES
+ if (row == nrow) {
+ call tbtwer (tptr, row+numadd)
+
+ } else {
+ call tbrsft (tptr, row, numadd)
+ call tbrnll (tptr, row+1, row+numadd)
+ }
+
+ # Reset label width if table has grown a lot
+
+ TED_LABWIDTH(tab) = log10 (real(nrow + numadd + 1000)) + 1.0
+ TED_LABWIDTH(tab) = max (6, TED_LABWIDTH(tab))
+
+ # Redraw screen
+
+ if (row <= TED_HIROW(scr))
+ call move_screen (scr, LEFT, YES)
+
+end
+
+# COPY_CMD -- Copy a range of lines to the paste buffer
+
+procedure copy_cmd (scr, nargs, arglist)
+
+pointer scr # i: Current screen descriptor
+int nargs # i: Number of arguments
+char arglist[ARB] # i: Argument list
+#--
+bool append
+int nrow, first, last, irow, orow, ncopy
+pointer tab, paste
+
+int tbpsta(), option_cmd()
+pointer opn_paste()
+
+begin
+ tab = TED_TABLE(scr)
+ paste = TED_PASTE(scr)
+ nrow = tbpsta (TED_TABPTR(tab) ,TBL_NROWS)
+
+ # Open paste buffer if not yet open
+
+ if (paste == NULL) {
+ paste = opn_paste (scr)
+ if (paste == NULL)
+ return
+ }
+
+ # Read copy command parameters
+
+ append = option_cmd ("|append|", nargs, arglist) != 0
+
+ call getint_cmd ("First row to copy", 2, nargs, arglist,
+ TED_CURROW(scr), 1, nrow, first)
+ call getint_cmd ("Last row to copy", 3, nargs, arglist,
+ TED_CURROW(scr), 1, nrow, last)
+
+ if (first < last) {
+ irow = first
+ ncopy = last - first + 1
+ } else {
+ irow = last
+ ncopy = first - last + 1
+ }
+
+ if (append) {
+ orow = TED_PSTROWS(paste) + 1
+ TED_PSTROWS(paste) = TED_PSTROWS(paste) + ncopy
+ } else {
+ orow = 1
+ TED_PSTROWS(paste) = ncopy
+ }
+
+ call move_paste (TED_TABPTR(tab), TED_PSTPTR(paste), irow, orow, ncopy)
+
+end
+
+# COUNT_CMD -- Count the number of words in a string
+
+int procedure count_cmd (str)
+
+char str[ARB] # i: String containing words
+#--
+char ch
+int count, ic
+
+begin
+ # The absolute value of count is the number of the current
+ # word of the string, count is negative if we are currently
+ # between words.
+
+ count = 0
+
+ # Loop over all characters in the string
+
+ for (ic = 1 ; str[ic] != EOS; ic = ic + 1) {
+ ch = str[ic]
+
+ if (count > 0) {
+ if (ch <= ' ')
+ count = - count
+
+ } else if (ch > ' ') {
+ count = - count + 1
+ }
+ }
+
+ return (abs(count))
+end
+
+# DELETE_CMD -- Delete a range of lines, copy them to the paste buffer
+
+procedure delete_cmd (scr, nargs, arglist)
+
+pointer scr # i: Current screen descriptor
+int nargs # i: Number of arguments
+char arglist[ARB] # i: Argument list
+#--
+bool append
+int nrow, first, last, irow, orow, ncopy
+pointer tab, tptr, paste
+
+string nowrite "Cannot change read only table"
+
+int tbpsta(), option_cmd()
+pointer opn_paste()
+
+begin
+ # Check for read only table
+
+ tab = TED_TABLE(scr)
+ tptr = TED_TABPTR(tab)
+ if (TED_READONLY(tab) == YES) {
+ call warn1_prompt (scr, nowrite)
+ return
+ }
+
+ # Get paste table
+
+ paste = TED_PASTE(scr)
+ nrow = tbpsta (tptr ,TBL_NROWS)
+
+ if (paste == NULL) {
+ paste = opn_paste (scr)
+ if (paste == NULL)
+ return
+ }
+
+ # Read command parameters
+
+ append = option_cmd ("|append|", nargs, arglist) != 0
+
+ call getint_cmd ("First row to delete", 2, nargs, arglist,
+ TED_CURROW(scr), 1, nrow, first)
+ call getint_cmd ("Last row to delete", 3, nargs, arglist,
+ TED_CURROW(scr), 1, nrow, last)
+
+ if (first < last) {
+ irow = first
+ } else {
+ irow = last
+ last = first
+ first = irow
+ }
+
+ # Copy deleted rows to paste table, then delete from original table
+
+ ncopy = last - first + 1
+
+ if (append) {
+ orow = TED_PSTROWS(paste) + 1
+ TED_PSTROWS(paste) = TED_PSTROWS(paste) + ncopy
+ } else {
+ orow = 1
+ TED_PSTROWS(paste) = ncopy
+ }
+
+ call move_paste (tptr, TED_PSTPTR(paste), irow, orow, ncopy)
+ call tbrdel (tptr, first, last)
+ TED_DIRTY(tab) = YES
+
+ # Add single blank row if all rows were deleted
+
+ nrow = nrow - ncopy
+ if (nrow < 1) {
+ nrow = 1
+ call tbtwer (tptr, 1)
+ }
+
+ # Set current row number and redraw screen
+
+ if (TED_CURROW(scr) >= first && TED_CURROW(scr) <= last)
+ TED_CURROW(scr) = max (1, first-1)
+
+ TED_CURROW(scr) = min (TED_CURROW(scr), nrow)
+
+ if (first <= TED_HIROW(scr))
+ call move_screen (scr, LEFT, YES)
+
+end
+
+# EXIT_CMD -- Process the exit command
+
+procedure exit_cmd (scr, nargs, arglist)
+
+pointer scr # i: Current screen descriptor
+int nargs # i: Number of arguments
+char arglist[ARB] # i: Argument list
+#--
+int iscr
+pointer scr2
+
+int get_window()
+
+begin
+ for (iscr = 1; get_window (iscr, scr2) != EOF; iscr = iscr + 1)
+ call del_screen (scr2, YES)
+
+end
+
+# FIND_CMD -- Find the row which makes the expression true
+
+procedure find_cmd (scr, nargs, arglist)
+
+pointer scr # i: Current screen descriptor
+int nargs # i: Number of arguments
+char arglist[ARB] # i: Argument list
+#--
+include "command.com"
+
+int first, last, row
+pointer tab
+
+string badexpr "Syntax error"
+string blankexp "No expression given"
+string notfound "No rows matched expression"
+
+int tbpsta(), option_cmd(), count_cmd(), tbl_search()
+
+begin
+ tab = TED_TABLE(scr)
+
+ # Get arguments of find command
+
+ direction = option_cmd ("|forward|backwards|", nargs, arglist)
+ if (direction == 0)
+ direction = 1
+
+ call getstr_cmd ("Find expression", 2, nargs, arglist,
+ search_exp, SZ_LINE)
+
+ if (count_cmd (search_exp) == 0) {
+ call warn1_prompt (scr, blankexp)
+ search_exp[1] = EOS
+ return
+ }
+
+ # Set limits for search
+
+ if (direction == 2) {
+ first = TED_CURROW(scr)
+ last = 1
+ } else {
+ first = TED_CURROW(scr)
+ last = tbpsta (TED_TABPTR(tab) ,TBL_NROWS)
+ }
+
+ # Perform search and report results
+
+ row = tbl_search (TED_TABPTR(tab), search_exp, first, last)
+
+ if (row == ERR) { # syntax error
+ # Redraw screen to hide error message from evexpr()
+ call move_screen (scr, LEFT, YES)
+ call warn2_prompt (scr, badexpr, search_exp)
+ search_exp[1] = EOS
+
+ } else if (row == 0) { # row not found
+ call write_prompt (scr, NO, notfound)
+
+ } else { # row found, update screen descriptor
+ TED_CURROW(scr) = row
+ }
+
+end
+
+# FUNC_CMD -- Change a single column using a function
+
+procedure func_cmd (scr, nargs, arglist, func)
+
+pointer scr # i: Current screen descriptor
+int nargs # i: Number of arguments
+char arglist[ARB] # i: Argument list
+extern func # i: Function which modifies a string in place
+#--
+int col, irow, nrow, len
+pointer sp, defcol, colstr, tab, cptr, tptr
+
+string nowrite "Cannot change read only table"
+string numeric "Cannot change numeric column"
+
+int tbpsta()
+
+begin
+ # Check for read only table
+
+ tab = TED_TABLE(scr)
+ if (TED_READONLY(tab) == YES) {
+ call warn1_prompt (scr, nowrite)
+ return
+ }
+
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (defcol, SZ_COLNAME, TY_CHAR)
+
+ # Get name of column
+
+ cptr = TED_COLPTR(tab, TED_CURCOL(scr))
+ call tbcigt (cptr, TBL_COL_NAME, Memc[defcol], SZ_COLNAME)
+
+ call getcol_cmd ("Column to change", 2, nargs, arglist, tab,
+ Memc[defcol], col)
+
+ # Make sure it's a string column
+
+ if (TED_COLTYPE(tab,col) > 0) {
+ call warn1_prompt (scr, numeric)
+
+ } else {
+
+ # Allocate array to hold field
+
+ len = - TED_COLTYPE(tab,col)
+ call salloc (colstr, len, TY_CHAR)
+
+ # Get current number of rows in the table
+
+ tptr = TED_TABPTR(tab)
+ cptr = TED_COLPTR(tab, col)
+ nrow = tbpsta (tptr ,TBL_NROWS)
+
+ # Retrieve each field and convert case
+
+ TED_DIRTY(tab) = YES
+ do irow = 1, nrow {
+ call tbegtt (tptr, cptr, irow, Memc[colstr], len)
+ call func (Memc[colstr])
+ call tbeptt (tptr, cptr, irow, Memc[colstr])
+ }
+ }
+
+ # Redraw screen if column is displayed
+
+ if (col >= TED_LOCOL(scr) && col <= TED_HICOL(scr))
+ call move_screen (scr, LEFT, YES)
+
+ call sfree (sp)
+
+end
+
+# GETCOL_CMD -- Get a column name from the argument list
+
+procedure getcol_cmd (argname, index, nargs, arglist, tab, defcol, icol)
+
+char argname[ARB] # i: Argument name (used as prompt if not found)
+int index # i: Index to string within argument list
+int nargs # i: Number of arguments in list
+char arglist[ARB] # i: List of arguments, separated by EOS characters
+pointer tab # i: Table descriptor
+char defcol[ARB] # i: Default column name (or EOS)
+int icol # o: Column number
+#--
+int ic, ncol, jcol, iarg, junk
+pointer sp, cname, cprompt, colptr[1]
+
+int ctoi()
+
+begin
+ # Allocate memory for temporary strings
+
+ call smark (sp)
+ call salloc (cname, SZ_COLNAME, TY_CHAR)
+ call salloc (cprompt, SZ_LINE, TY_CHAR)
+
+ # Get the string containing the column name
+
+ if (defcol[1] == EOS) {
+ call strcpy (argname, Memc[cprompt], SZ_LINE)
+ } else {
+ call sprintf (Memc[cprompt], SZ_LINE, "%s (%s)")
+ call pargstr (argname)
+ call pargstr (defcol)
+ }
+
+ call getstr_cmd (Memc[cprompt], index, nargs, arglist,
+ Memc[cname], SZ_COLNAME)
+
+ if (Memc[cname] == EOS)
+ call strcpy (defcol, Memc[cname], SZ_COLNAME)
+
+ # Loop until valid column name found
+
+ icol = 0
+ while (icol == 0) {
+ colptr[1] = NULL
+ Memc[cprompt] = EOS
+
+ # Get a column pointer from the column template
+
+ iferr {
+ call tctexp (TED_TABPTR(tab), Memc[cname], 1, ncol, colptr)
+ } then {
+ # More than one column matches the name
+ call strcpy ("Ambiguous column name. ", Memc[cprompt], SZ_LINE)
+
+ } else {
+ # If one name matched, check against list of column pointers
+
+ if (ncol == 1) {
+ for (jcol = 1; jcol <= TED_NCOLS(tab); jcol = jcol + 1) {
+ if (colptr[1] == TED_COLPTR(tab,jcol)) {
+ icol = jcol
+ break
+ }
+ }
+ }
+
+ # Convert name to number, see if number is within range
+
+ if (icol == 0) {
+ ic = 1
+ junk = ctoi (Memc[cname], ic, icol)
+
+ if (Memc[cname+ic-1] != EOS)
+ icol = 0
+ else if (icol < 1 || icol > TED_NCOLS(tab))
+ icol = 0
+ }
+
+ if (icol == 0)
+ call strcpy ("Column not found. ", Memc[cprompt], SZ_LINE)
+ }
+
+ # If column not matched, read new name interactively
+
+ if (icol == 0) {
+ iarg = nargs + 1
+ call strcat (argname, Memc[cprompt], SZ_LINE)
+
+ call getstr_cmd (Memc[cprompt], iarg, nargs, arglist,
+ Memc[cname], SZ_FNAME)
+
+ if (Memc[cname] == EOS)
+ call strcpy (defcol, Memc[cname], SZ_COLNAME)
+ }
+ }
+
+ call sfree (sp)
+end
+
+# GETINT_CMD -- Get an integer from the argument list
+
+procedure getint_cmd (argname, index, nargs, arglist, defval,
+ minval, maxval, value)
+
+char argname # i: Argument name (used as prompt if not found)
+int index # i: Index to string within argument list
+int nargs # i: Number of arguments in list
+char arglist[ARB] # i: List of arguments, separated by EOS characters
+int defval # i: Default legal value (or INDEFI)
+int minval # i: Minimum legal value (or INDEFI)
+int maxval # i: Maximum legal value (or INDEFI)
+int value # o: Output value
+#--
+int ic, iarg, junk
+pointer sp, valstr, prompt
+
+string typemsg "Please enter a number. "
+string rangemsg "Out of range (%d - %d). "
+
+int ctoi()
+
+begin
+ # Allocate memory for temporary strings
+
+ call smark (sp)
+ call salloc (valstr, SZ_FNAME, TY_CHAR)
+ call salloc (prompt, SZ_LINE, TY_CHAR)
+
+ # Get the string representing the value
+
+ if (IS_INDEFI (defval)) {
+ call strcpy (argname, Memc[prompt], SZ_LINE)
+ } else {
+ call sprintf (Memc[prompt], SZ_LINE, "%s (%d)")
+ call pargstr (argname)
+ call pargi (defval)
+ }
+
+ call getstr_cmd (Memc[prompt], index, nargs, arglist,
+ Memc[valstr], SZ_FNAME)
+
+ if (Memc[valstr] == EOS) {
+ value = defval
+ } else {
+ ic = 1
+ junk = ctoi (Memc[valstr], ic, value)
+ if (Memc[valstr+ic-1] != EOS)
+ value = INDEFI
+ }
+
+ # Loop until valid value is found
+
+ repeat {
+ if (IS_INDEFI(value)) {
+ call strcpy (typemsg, Memc[prompt], SZ_LINE)
+
+ } else if ((value < minval && ! IS_INDEFI (minval)) ||
+ (value > maxval && ! IS_INDEFI (maxval)) ) {
+ call sprintf (Memc[prompt], SZ_LINE, rangemsg)
+ call pargi (minval)
+ call pargi (maxval)
+
+ } else {
+ break
+ }
+
+ # If the string was not valid, get the value interactively
+
+ iarg = nargs + 1
+ call strcat (argname, Memc[prompt], SZ_LINE)
+
+ call getstr_cmd (Memc[prompt], iarg, nargs, arglist,
+ Memc[valstr], SZ_FNAME)
+
+ ic = 1
+ junk = ctoi (Memc[valstr], ic, value)
+ if (Memc[valstr+ic-1] != EOS)
+ value = INDEFI
+ }
+
+ call sfree (sp)
+end
+
+# GETSTR_CMD -- Get a string from the command argument list
+
+procedure getstr_cmd (argname, index, nargs, arglist, str, maxch)
+
+char argname # i: Argument name (used as prompt if not found)
+int index # i: Index to string within argument list
+int nargs # i: Number of arguments in list
+char arglist[ARB] # i: List of arguments, separated by EOS characters
+char str[ARB] # o: Output string
+int maxch # i: Maximum length of output string
+#--
+int ic, jc, iarg
+pointer sp, prompt
+
+string nullarg "getstr_cmd: null argument found in argument list"
+
+begin
+ # Allocate dynamic memory for prompt
+
+ call smark (sp)
+ call salloc (prompt, SZ_LINE, TY_CHAR)
+
+ # Read the argument interactively if not supplied by the user
+ # Otherwise, copy from the argument list string
+
+ if (index > nargs) {
+ call strcpy (argname, Memc[prompt], SZ_LINE)
+ call strcat ("?", Memc[prompt], SZ_LINE)
+
+ call read_prompt (Memc[prompt], str, maxch)
+
+ } else {
+ # Skip over leading arguments
+
+ ic = 1
+ for (iarg = 1; iarg < index; iarg = iarg + 1) {
+ if (arglist[ic] == EOS)
+ call err1_prompt (nullarg)
+
+ while (arglist[ic] != EOS)
+ ic = ic + 1
+ ic = ic + 1
+ }
+
+ # Copy into output string
+
+ for (jc = 1; jc <= maxch && arglist[ic] != EOS; jc = jc + 1) {
+ str[jc] = arglist[ic]
+ ic = ic + 1
+ }
+ str[jc] = EOS
+ }
+
+ call sfree (sp)
+end
+
+# GOTO_CMD -- Process the goto command
+
+procedure goto_cmd (scr, nargs, arglist)
+
+pointer scr # i: Current screen descriptor
+int nargs # i: Number of arguments
+char arglist[ARB] # i: Argument list
+#--
+int nrow, row, col
+pointer sp, defcol, tab, cptr
+
+int tbpsta()
+
+string notable "No table associated with this screen"
+
+begin
+ # Allocate dynamic memory for column name
+
+ call smark (sp)
+ call salloc (defcol, SZ_COLNAME, TY_CHAR)
+
+ # Get number of rows in table
+
+ tab = TED_TABLE(scr)
+ if (tab == NULL)
+ call err1_prompt (notable)
+ else
+ nrow = tbpsta (TED_TABPTR(tab), TBL_NROWS)
+
+ cptr = TED_COLPTR(tab, TED_CURCOL(scr))
+ call tbcigt (cptr, TBL_COL_NAME, Memc[defcol], SZ_COLNAME)
+
+ # Get the row and column numbers
+
+ call getint_cmd ("Go to row", 2, nargs, arglist,
+ TED_CURROW(scr), 1, nrow, row)
+ call getcol_cmd ("Go to column", 3, nargs, arglist, tab,
+ Memc[defcol], col)
+
+ # Update screen descriptor
+
+ TED_CURROW(scr) = row
+ TED_CURCOL(scr) = col
+
+ call sfree (sp)
+end
+
+# HELP_CMD -- Process the help command
+
+procedure help_cmd (scr, nargs, arglist)
+
+pointer scr # i: Current screen descriptor
+int nargs # i: Number of arguments
+char arglist[ARB] # i: Argument list
+#--
+
+begin
+ call help_screen (TED_WINDOW(scr))
+
+end
+
+# INIT_CMD -- Initialize the global variables used by commands
+
+procedure init_cmd(silent)
+
+bool silent # i: do not ring bell when error occurs
+#--
+include "command.com"
+
+begin
+ direction = 1
+ search_exp[1] = EOS
+ call init_bell (silent)
+end
+
+# INSERT_CMD -- Process an insert command
+
+procedure insert_cmd (scr, nargs, arglist)
+
+pointer scr # i: Current screen descriptor
+int nargs # i: Number of arguments
+char arglist[ARB] # i: Argument list
+#--
+int irow, nrow
+pointer tab, paste
+
+string nowrite "Cannot change read only table"
+string nopaste "Paste buffer is empty"
+
+int tbpsta()
+pointer opn_paste()
+
+begin
+ # Check for read only table
+
+ tab = TED_TABLE(scr)
+ if (TED_READONLY(tab) == YES) {
+ call warn1_prompt (scr, nowrite)
+ return
+ }
+
+ paste = TED_PASTE(scr)
+ nrow = tbpsta (TED_TABPTR(tab) ,TBL_NROWS)
+
+ if (paste == NULL) {
+ paste = opn_paste (scr)
+ if (paste == NULL)
+ return
+ }
+
+ # Get insert command parameters
+
+ call getint_cmd ("Insert after row number", 2, nargs, arglist,
+ TED_CURROW(scr), 0, nrow, irow)
+
+ # Check to see if there is something to insert
+
+ if (TED_PSTROWS(paste) <= 0) {
+ call warn1_prompt (scr, nopaste)
+ return
+ }
+
+ TED_DIRTY(tab) = YES
+ if (irow < nrow)
+ call tbrsft (TED_TABPTR(tab), irow+1, TED_PSTROWS(paste))
+
+ call move_paste (TED_PSTPTR(paste), TED_TABPTR(tab),
+ 1, irow+1, TED_PSTROWS(paste))
+
+ if (irow <= TED_HIROW(scr))
+ call move_screen (scr, LEFT, YES)
+
+end
+
+# LOWER_CMD -- Convert a column to lower cse
+
+procedure lower_cmd (scr, nargs, arglist)
+
+pointer scr # i: Current screen descriptor
+int nargs # i: Number of arguments
+char arglist[ARB] # i: Argument list
+#--
+extern strlwr
+
+begin
+ # A common routine handle both the lower and upper case
+ # commands, since they are so similar
+
+ call func_cmd (scr, nargs, arglist, strlwr)
+end
+
+# NEXT_CMD -- Repeat the search for an expression
+
+procedure next_cmd (scr, nargs, arglist)
+
+pointer scr # i: Current screen descriptor
+int nargs # i: Number of arguments
+char arglist[ARB] # i: Argument list
+#--
+include "command.com"
+
+int dir, nrow, first, last, row
+pointer tab
+
+string nofind "No previous find command"
+string badexpr "Syntax error"
+string notfound "No rows matched expression"
+
+int tbpsta(), option_cmd(), tbl_search()
+
+begin
+ tab = TED_TABLE(scr)
+ nrow = tbpsta (TED_TABPTR(tab) ,TBL_NROWS)
+
+ # Make sure there was a previous find command
+
+ if (search_exp[1] == EOS) {
+ call warn1_prompt (scr, nofind)
+ return
+ }
+
+ # Get the command option
+
+ dir = option_cmd ("|forward|backwards|", nargs, arglist)
+ if (dir != 0)
+ direction = dir
+
+ # Set limits for search
+
+ if (direction == 2) {
+ first = max (TED_CURROW(scr)-1, 1)
+ last = 1
+ } else {
+ first = min (TED_CURROW(scr)+1, nrow)
+ last = nrow
+ }
+
+ # Perform search and report results
+
+ row = tbl_search (TED_TABPTR(tab), search_exp, first, last)
+
+ if (row == ERR) { # syntax error
+ call warn2_prompt (scr, badexpr, search_exp)
+ search_exp[1] = EOS
+
+ } else if (row == 0) { # row not found
+ call write_prompt (scr, NO, notfound)
+
+ } else { # row found, update screen descriptor
+ TED_CURROW(scr) = row
+ }
+
+end
+
+# OPTION_CMD -- Get the command option
+
+int procedure option_cmd (optlist, nargs, arglist)
+
+char optlist[ARB] # i: List of legal options
+int nargs # u: Number of command arguments
+char arglist[ARB] # u: Argument list
+#--
+int option, iarg, ic, jc, last[2]
+pointer sp, arg1, arg2
+
+int strdic()
+
+begin
+ # No option if number of arguments < 2
+ if (nargs < 2)
+ return (0)
+
+ # Allocate dynamic memory for optional argument
+
+ call smark (sp)
+ call salloc (arg1, SZ_LINE, TY_CHAR)
+ call salloc (arg2, SZ_LINE, TY_CHAR)
+
+ # Read optional argument, match against list of options
+
+ call getstr_cmd ("Option", 2, nargs, arglist, Memc[arg1], SZ_LINE)
+ option = strdic (Memc[arg1], Memc[arg2], SZ_LINE, optlist)
+
+ # If matched, remove option from argument list
+
+ if (option != 0) {
+ ic = 1
+ do iarg = 1, 2 {
+ while (arglist[ic] != EOS)
+ ic = ic + 1
+ last[iarg] = ic
+ ic = ic + 1
+ }
+
+ ic = last[1]
+ jc = last[2]
+ repeat {
+ ic = ic + 1
+ jc = jc + 1
+ arglist[ic] = arglist[jc]
+ } until (arglist[jc] == EOS && arglist[jc-1] == EOS)
+
+ nargs = nargs - 1
+ }
+
+ call sfree (sp)
+ return (option)
+
+end
+
+# PARSE_CMD -- Parse a command string
+
+procedure parse_cmd (command, code, nargs, arglist, maxch)
+
+char command[ARB] # i: Command to be parsed
+int code # o: Command code (0 if unknown command)
+int nargs # o: Number of arguments (including command name)
+char arglist[ARB] # o: Array of arguments, packed into one string
+int maxch # i: Declared length of arglist
+#--
+int ic, jc, delim
+pointer sp, temp
+
+string cmdlist TED_CMDLIST
+
+int strdic()
+
+begin
+ # Allocate temporary string for full command name
+
+ call smark (sp)
+ call salloc (temp, SZ_FNAME, TY_CHAR)
+
+ # Break command string into arguements
+ # Count the number of arguements
+
+ jc = 1
+ nargs = 0
+ delim = EOS
+ for (ic = 1; command[ic] != EOS && jc <= maxch; ic = ic + 1) {
+ if (delim == EOS) {
+ if (command[ic] > BLANK) {
+ nargs = nargs + 1
+ if (command[ic] == SQUOTE) {
+ delim = SQUOTE
+ } else if (command[ic] == DQUOTE) {
+ delim = DQUOTE
+ } else {
+ ic = ic - 1 # push back non-blank character
+ delim = BLANK
+ }
+ }
+
+ } else if (delim == BLANK) {
+ if (command[ic] <= BLANK) {
+ arglist[jc] = EOS
+ jc = jc + 1
+ delim = EOS
+
+ } else {
+ arglist[jc] = command[ic]
+ jc = jc + 1
+ }
+
+ } else {
+ if (command[ic] == delim) {
+ arglist[jc] = EOS
+ jc = jc + 1
+ delim = EOS
+
+ } else {
+ arglist[jc] = command[ic]
+ jc = jc + 1
+ }
+ }
+ }
+ arglist[jc] = EOS
+
+ # Get the code which corresponds to the first arguement
+ # (the command name)
+
+ if (nargs == 0) {
+ code = 0
+ } else {
+ code = strdic (arglist, Memc[temp], SZ_FNAME, cmdlist)
+ }
+
+ call sfree (temp)
+end
+
+# QUIT_CMD -- Quit the editor without saving files
+
+procedure quit_cmd (scr, nargs, arglist)
+
+pointer scr # i: Current screen descriptor
+int nargs # i: Number of arguments
+char arglist[ARB] # i: Argument list
+#--
+int iscr
+pointer scr2
+
+int get_window()
+
+begin
+ for (iscr = 1; get_window (iscr, scr2) != EOF; iscr = iscr + 1)
+ call del_screen (scr2, NO)
+
+end
+
+# SET_CMD -- Set a column to the value of an expression
+
+procedure set_cmd (scr, nargs, arglist)
+
+pointer scr # i: Current screen descriptor
+int nargs # i: Number of arguments
+char arglist[ARB] # i: Argument list
+#--
+include "../tabvar.com"
+
+bool done
+int col, irow, nrow, nbuf, coltype, exptype
+pointer sp, defcol, expr, buffer, tab, cptr, tptr, code
+
+string nowrite "Cannot change read only table"
+string syntax "Syntax error in expression"
+
+extern tabvar
+int tbpsta()
+pointer vex_compile()
+
+begin
+ # Check for read only table
+
+ tab = TED_TABLE(scr)
+ if (TED_READONLY(tab) == YES) {
+ call warn1_prompt (scr, nowrite)
+ return
+ }
+
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (defcol, SZ_COLNAME, TY_CHAR)
+ call salloc (expr, SZ_LINE, TY_CHAR)
+
+ # Get name of column
+
+ cptr = TED_COLPTR(tab, TED_CURCOL(scr))
+ call tbcigt (cptr, TBL_COL_NAME, Memc[defcol], SZ_COLNAME)
+
+ call getcol_cmd ("Column to change", 2, nargs, arglist, tab,
+ Memc[defcol], col)
+
+ call getstr_cmd ("Expression", 3, nargs, arglist,
+ Memc[expr], SZ_LINE)
+
+ # Get table info
+
+ tptr = TED_TABPTR(tab)
+ cptr = TED_COLPTR(tab, col)
+ nrow = tbpsta (tptr, TBL_NROWS)
+
+ coltype = TED_COLTYPE(tab,col)
+ if (coltype < 0) {
+ # String columns copy the expression verbatim
+
+ TED_DIRTY(tab) = YES
+ do irow = 1, nrow
+ call tbeptt (tptr, cptr, irow, Memc[expr])
+
+ } else {
+ # Numeric columns use the expression evaluator
+
+ iferr {
+ code = vex_compile (Memc[expr])
+ } then {
+ call warn2_prompt (scr, syntax, Memc[expr])
+ call sfree (sp)
+ return
+ }
+
+ # Initialize common block used by tabvar()
+
+ tabptr = tptr
+ firstrow = 1
+ lastrow = MAXROWS
+
+ done = false
+ nullval = HARMLESS
+
+ repeat {
+ if (lastrow >= nrow) {
+ done = true
+ lastrow = nrow
+ }
+
+ iferr {
+ call vex_eval (code, tabvar, nullval, exptype)
+ } then {
+ call warn2_prompt (scr, syntax, Memc[expr])
+ call sfree (sp)
+ return
+ }
+
+ nbuf = (lastrow - firstrow) + 1
+
+ # Copy results to column
+
+ switch (coltype) {
+ case TY_BOOL, TY_SHORT, TY_INT, TY_LONG:
+ call malloc (buffer, nbuf, TY_INT)
+ call vex_copyi (code, INDEFI, Memi[buffer], nbuf)
+ call tbcpti (tptr, cptr, Memi[buffer], firstrow, lastrow)
+ call mfree (buffer, TY_INT)
+ case TY_REAL:
+ call malloc (buffer, nbuf, TY_REAL)
+ call vex_copyr (code, INDEFR, Memr[buffer], nbuf)
+ call tbcptr (tptr, cptr, Memr[buffer], firstrow, lastrow)
+ call mfree (buffer, TY_REAL)
+ case TY_DOUBLE:
+ call malloc (buffer, nbuf, TY_DOUBLE)
+ call vex_copyd (code, INDEFD, Memd[buffer], nbuf)
+ call tbcptd (tptr, cptr, Memd[buffer], firstrow, lastrow)
+ call mfree (buffer, TY_DOUBLE)
+ }
+
+ firstrow = firstrow + MAXROWS
+ lastrow = lastrow + MAXROWS
+ } until (done)
+
+ TED_DIRTY(tab) = YES
+ call vex_free (code)
+ }
+
+ # Redraw screen if column is displayed
+
+ if (col >= TED_LOCOL(scr) && col <= TED_HICOL(scr))
+ call move_screen (scr, LEFT, YES)
+
+ call sfree (sp)
+
+end
+
+# SUB_CMD -- Substitute strings in a single column
+
+procedure sub_cmd (scr, nargs, arglist)
+
+pointer scr # i: Current screen descriptor
+int nargs # i: Number of arguments
+char arglist[ARB] # i: Argument list
+#--
+int col, irow, nrow, len
+pointer sp, defcol, from, to, colstr, tab, cptr, tptr
+
+string nowrite "Cannot change read only table"
+string numeric "Cannot change numeric column"
+
+bool substitute()
+int tbpsta()
+
+begin
+ # Check for read only table
+
+ tab = TED_TABLE(scr)
+ if (TED_READONLY(tab) == YES) {
+ call warn1_prompt (scr, nowrite)
+ return
+ }
+
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (defcol, SZ_COLNAME, TY_CHAR)
+ call salloc (from, SZ_LINE, TY_CHAR)
+ call salloc (to, SZ_LINE, TY_CHAR)
+
+ # Get name of column. Make sure it's a string column
+
+ cptr = TED_COLPTR(tab, TED_CURCOL(scr))
+ call tbcigt (cptr, TBL_COL_NAME, Memc[defcol], SZ_COLNAME)
+
+ call getcol_cmd ("Column to change", 2, nargs, arglist, tab,
+ Memc[defcol], col)
+
+ if (TED_COLTYPE(tab,col) > 0) {
+ call warn1_prompt (scr, numeric)
+ call sfree (sp)
+ return
+ }
+
+ # Get target string
+
+ call getstr_cmd ("Search string", 3, nargs, arglist,
+ Memc[from], SZ_LINE)
+
+ if (Memc[from] == EOS) {
+ call sfree (sp)
+ return
+ }
+
+ # Get replacement string
+
+ call getstr_cmd ("Replacement string", 4, nargs, arglist,
+ Memc[to], SZ_LINE)
+
+ # Allocate array to hold field
+
+ len = - TED_COLTYPE(tab,col)
+ call salloc (colstr, len, TY_CHAR)
+
+ # Get current number of rows in the table
+
+ tptr = TED_TABPTR(tab)
+ cptr = TED_COLPTR(tab, col)
+ nrow = tbpsta (tptr ,TBL_NROWS)
+
+ # Retrieve each field and perform substitution
+
+ do irow = 1, nrow {
+ call tbegtt (tptr, cptr, irow, Memc[colstr], len)
+
+ if (substitute (Memc[from], Memc[to], Memc[colstr], len)) {
+ TED_DIRTY(tab) = YES
+ call tbeptt (tptr, cptr, irow, Memc[colstr])
+ }
+ }
+
+ # Redraw screen if column is displayed
+
+ if (col >= TED_LOCOL(scr) && col <= TED_HICOL(scr))
+ call move_screen (scr, LEFT, YES)
+
+ call sfree (sp)
+
+end
+
+# UPPER_CMD -- Convert a column to upper cse
+
+procedure upper_cmd (scr, nargs, arglist)
+
+pointer scr # i: Current screen descriptor
+int nargs # i: Number of arguments
+char arglist[ARB] # i: Argument list
+#--
+extern strupr
+
+begin
+ # A common routine handle both the lower and upper case
+ # commands, since they are so similar
+
+ call func_cmd (scr, nargs, arglist, strupr)
+end
+
diff --git a/pkg/utilities/nttools/tedit/display/curses.h b/pkg/utilities/nttools/tedit/display/curses.h
new file mode 100644
index 00000000..ea12d7f5
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses.h
@@ -0,0 +1,86 @@
+# CURSES.H -- Macros used by the curses subroutines
+
+# Window which covers terminal screen
+
+define STDSCR 1
+
+# The following string defines the set of commands read from the edcap file
+
+define CMDSTR "|MOVE_UP|MOVE_DOWN|MOVE_RIGHT|MOVE_LEFT|NEXT_WORD|PREV_WORD\
+|NEXT_PAGE|PREV_PAGE|MOVE_START|MOVE_END|MOVE_BOL|MOVE_EOL|DEL_CHAR|DEL_LEFT\
+|DEL_WORD|DEL_LINE|UNDEL_CHAR|UNDEL_WORD|UNDEL_LINE|GET_HELP|REPAINT\
+|EXIT_UPDATE|"
+
+# The following values are returned when
+# the corresponding escape sequence is entered
+
+define K_BASE 256 # Smallest value
+
+define K_UP 256 # Move up one row
+define K_DOWN 257 # Move down one row
+define K_RIGHT 258 # Move right one column
+define K_LEFT 259 # Move left one column
+define K_NEXTW 260 # Move forwards one word
+define K_PREVW 261 # Move backwards one word
+define K_NEXTP 262 # Move forwards one window
+define K_PREVP 263 # Move backwards one window
+define K_HOME 264 # Move to first row
+define K_END 265 # Move to last row
+define K_BOL 266 # Move to first column in row
+define K_EOL 267 # Move to last column in row
+define K_DEL 268 # Delete character underneath cursor
+define K_BS 269 # Delete character to left of cursor
+define K_DWORD 270 # Delete previous word
+define K_DLINE 271 # Delete entire line
+define K_UNDCHR 272 # Undelete character
+define K_UNDWRD 273 # Undelete word
+define K_UNDLIN 274 # Undelete line
+define K_HELP 275 # Display help window
+define K_PAINT 276 # Force window redraw
+define K_EXIT 277 # Exit procedure
+
+# Codes used by winstat to retrieve window fields
+
+define W_TOP 1 # Window's top row
+define W_LEFT 2 # Window's leftmost column
+define W_BOT 3 # Window's bottom row
+define W_RIGHT 4 # Window's rightmost column
+define W_CURROW 5 # Cursor row relative to window
+define W_CURCOL 6 # Cursor column relative to window
+define W_CLEAR 7 # Redraw window when refreshed
+define W_LEAVE 8 # Leave cursor after redraw
+define W_SCROLL 9 # Window will scroll
+define W_HIDDEN 10 # Window is hidden
+define W_BOXED 11 # Window is boxed
+define W_ATRIB 12 # Character attribute of window
+
+# Direction to move rectangle used by ps_slide and wslide
+
+define DIR_UP 0
+define DIR_DOWN 1
+define DIR_LEFT 2
+define DIR_RIGHT 3
+
+# Character attributes
+
+define A_NORM 0
+define A_STANDOUT 128
+
+# Definition of rectangle
+
+define RSIZE 4
+define RTOP $1[1]
+define RLEFT $1[2]
+define RBOT $1[3]
+define RRIGHT $1[4]
+
+# Macros used to manipulate rectangles
+
+define RWIDTH ($1[4] - $1[2] + 1)
+define RHEIGHT ($1[3] - $1[1] + 1)
+define RASG {$1[1] = $2; $1[2] = $3; $1[3] = $4; $1[4] = $5}
+define RCPY {$1[1]=$2[1]; $1[2]=$2[2]; $1[3]=$2[3]; $1[4]=$2[4]}
+
+# Constant used to create a rectangle much greater than screen size
+
+define GIANT 9999
diff --git a/pkg/utilities/nttools/tedit/display/curses/README b/pkg/utilities/nttools/tedit/display/curses/README
new file mode 100644
index 00000000..67220c91
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/README
@@ -0,0 +1,387 @@
+The procedures in this directory are an implementation of the Unix
+curses library, with a few deletions and extensions. The procedures
+have been modified to work in an SPP environment instead of a C
+environment. Unlike the C routines, they do not return an error status
+as a function value. In fact, very few of the procedures call error,
+instead they try to do the most reasonable thing. The mv macros are
+not implemented, instead the program should call move() followed by
+the appropriate procedure. Formatted reads and writes to windows are
+not supported, all reading and writing is done using strings.
+Subwindows are also not supported. The user program does not have
+direct access to the window structure, the function winstat() is
+provided to read fields from the structure. In order to make
+customization of windows easier, each window can have an input
+function and data structure bound to it. The functions bindstruct()
+and getstruct() are provided for this purpose. The forms directory
+gives several examples of binding functions and data structures to a
+window. Two other procedures hidewin() and showwin() are provided to
+hide a window which is currently displayed on the terminal and to
+redisplay it.
+
+The procedure initscr() should be called before using any of the
+procedures in the curses directory. It initializes the terminal and
+creates the first window (referred to as STDSCR), which covers the
+terminal scrren. The procedure endwin() should be called at the end of
+the user program. It closes any windows which are still open and
+resets the terminal. Windows are created by calling newwin() and
+destroyed by calling delwin(). The terminal cursor is moved by the
+procedure move(). Text is written into a window by the procedures
+addch() and addstr(). Text is read from the keyboard and displayed in
+the window by the procedures getch() and getstr(). Changes to the
+window are not displayed until refresh() is called. Fuller
+explanations of these and the other curses procedures is given below.
+
+Many procedures in this directory exist in two forms. The first form
+uses the default window, STDSCR. This window is created when initscr()
+is called and covers the entire screen. The second form uses any
+window and has an extra argument to specify which window to use. The
+names of the two forms are the same, except that the second has the
+letter "w" as the first character. For example, addch() adds a
+character to STDSCR, while waddch() adds a character to any window.
+The macro STDSCR is defined in <curses.h>, so it can be used by your
+program. Many of the procedures in this library operate relative to
+the current cursor position in that window. To set the cursor
+position, the program should call move() or wmove() first. Window
+coordinates are passed row first, column second. The upper left corner
+of a window is (1,1).
+
+procedure addch (ch)
+procedure waddch (win, ch)
+
+pointer win # i: Window descriptor
+char ch # i: Character to add
+
+This procedure adds a single character at the current cursor position.
+The character currently at that position is overwritten. A linefeed
+character clears the rest of the line and moves the cursor to the next
+row. A tab character inserts the apropriate number of spaces at the
+current position. A carriage return moves the cursor to the first
+character on the current line. A backspace moves the cursor one column
+left unless the cursor is in the first column of the window.
+
+procedure addstr (str)
+procedure waddstr (win, str)
+
+int win # i: Window descriptor
+char str[ARB] # i: String to add to window
+
+This procedure adds a string at the current cursor position. If part
+of the string extends beyond the right edge of the window, it will be
+truncated. Special characters have the same meaning as those in addch().
+The window will scroll if scrolling is enabled.
+
+procedure bindstruct (func, structure)
+procedure wbindstruct (win, func, structure)
+
+int win # i: Window descriptor
+extern func # i: Input function
+pointer structure # i: Data structure
+
+This procedure binds an input function and a data structure to a
+window. The data structure is used by the input function to maintain
+the window's state. The input function is called by getch() and
+getstr() to process keyboard input instead of the default procedure,
+editfn(). The input function should have the following calling sequence.
+
+procedure func (win, str, maxch)
+
+int win # i: Window descriptor
+char str[ARB] # io: String containing line
+int maxch # i: Maximum line length
+
+When writing this procedure, the default procedure, editfn() should be
+used as a guide. The procedure should update the terminal screen,
+string, and data structure appropriately. When the procedure gets a
+character indicating input is complete, the character should be pushed
+back on the input stream with the procedure k_pushbk(). Then the
+procedure should return the string to the calling program. The calling
+program can also call getstruct() to retrieve the contents of the data
+structure.
+
+procedure box (win, vert, hor)
+
+int win # i: Window descriptor
+char vert # i: Character used for vertical side of window
+char hor # i: Character used for horizontal side of window
+
+This procedure draws a box around a window. The box is inside the
+original area of the window, which is then reduced so that subsequent
+writes to the window will not overwrite the box.
+
+procedure clear ()
+procedure wclear (win)
+
+int win # i: Window descriptor
+
+This procedure clears a window. It is equivalent to calling clearok()
+with flag set to true, followed by calling erase().
+
+procedure clearok (win, flag)
+
+int win # i: Window descriptor
+bool flag # i: Flag value
+
+This procedure sets the clear flag for a window. If the clear flag is
+true, the entire window will be redrawn when refresh is called.
+
+procedure clrtobot ()
+procedure wclrtobot (win)
+
+int win # i: Window descriptor
+
+This procedure clears a window from the current cursor position to the
+end of the window.
+
+procedure clrtoeol ()
+procedure wclrtoeol (win)
+
+int win # i: Window descriptor
+
+This procedure clears a window from the current cursor position to the
+end of the line.
+
+procedure delch ()
+procedure wdelch (win)
+
+pointer win # i: Window descriptor
+
+This procedure deletes the character at the current cursor poisition
+in the window. Subsequent characters on the line are moved to the left
+by one.
+
+procedure deleteln ()
+procedure wdeleteln (win)
+
+pointer win # i: Window descriptor
+
+This procedure deletes the current line in the window. Subsequent
+lines in the window slide up by one and the last line is left blank.
+
+procedure delwin (win)
+
+This procedure deletes a window created by newwin(). The terminal area
+that was under the window before it was created is redisplayed. The
+data structure associated with the window is freed, including the data
+structure bound by bindstruct(). STDSCR cannot be deleted by this
+procedure, it is deleted by endwin().
+
+procedure echo ()
+procedure noecho ()
+
+These procedures turn character echoing on and off. Character echoing
+is on when the terminal is initialized. If character ecoing is off,
+procedures addch() and addstr() will return immediately after being
+called.
+
+procedure endwin ()
+
+This procedure should be called at the end of a program which uses the
+curses library. It deletes all windows that are still open (including
+STDSCR) and resets the terminal.
+
+procedure erase ()
+procedure werase (win)
+
+int win # i: Window descriptor
+
+This procedure erases a window, filling it with blanks.
+
+int procedure getch ()
+int procedure wgetch (win)
+
+This procedure reads a single character from the keyboard and adds it
+to the window at the current cursor position. If an input function
+has been bound to the window by bindstruct(), the input procedure is
+called to process the character. The procedure returns after calling
+the input function once, regardless of the value of done. The returned
+character is the first character in the string output by the input
+function.
+
+procedure getstr (str, maxch)
+procedure wgetstr (win, str, maxch)
+
+pointer win # i: Window descriptor
+char str[ARB] # o: String that was read from the keyboard
+int maxch # i: Maximum string length
+
+This procedure reads a string from the keyboard and displays it in the
+window at the current cursor position. Editing keys are recognized;
+however, editing is limited to a single line and keys which change the
+current line cause the procedure to exit. The default behaviour of
+this procedure can be modified by binding an input function to the
+window with bindstruct().
+
+procedure getstruct (structure)
+procedure wgetstruct (win, structure)
+
+int win # i: Window descriptor
+pointer structure # o: Data structure
+
+This procedure returns a pointer to the data structure that was bound
+to the window by bindstruct().
+
+procedure getyx (win, row, col)
+
+int win # i: Window descriptor
+int row # o: Cursor row
+int col # o: Cursor column
+
+This procedure returns the location of the cursor in a window. The
+top left corner of a window is (1,1).
+
+procedure hidewin (win)
+
+int win # i: Window descriptor
+
+This procedure hides a window that is currently displayed on the
+screen. The terminal area under the window is displayed after the
+window is hidden. The window can be redisplayed by calling showwin().
+
+char procedure inch ()
+char procedure winch (win)
+
+pointer win # i: Window descriptor
+
+This procedure returns the character at the current cursor location in
+the window.
+
+procedure initscr ()
+
+This procedure initializes the terminal and creates the default
+window, STDSCR. It should be called before any other procedure in the
+curses library is called.
+
+procedure insch (ch)
+procedure winsch (win, ch)
+
+pointer win # i: Window descriptor
+char ch # i: Character to insert
+
+This procedure inserts a character at the current cursor position.
+
+procedure insertln ()
+procedure winsertln (win)
+
+pointer win # i: Window descriptor
+
+This procedure inserts a blank line on the current row. The current
+line and subsequent lines move down by one and the last line in the
+window is deleted.
+
+procedure leaveok (win, flag)
+
+int win # i: Window descriptor
+bool flag # i: Flag value
+
+This procedure sets the leave flag for a window. If the leave flag
+is true, procedures that modify the screen will not move the terminal
+cursor to the window's current cursor position when the window is
+modified. If it is false, the terminal cursor position will be moved
+when the window is updated. When a window is created, the leave flag
+is set to false.
+
+procedure move (row, col)
+procedure wmove (win, row, col)
+
+int win # i: Window descriptor
+int row # i: Cursor row
+int col # i: Cursor column
+
+This procedure moves the cursor position in a window. Coordinates are
+relative to those of the window, and the top left corner of a window
+has the coordinates (1,1)
+
+procedure mvwin (win, row, col)
+
+int win # i: Window descriptor
+int row # i: New top row of window
+int col # i: New left column of window
+
+This position moves the position of a window on the screen. The
+position of a window is the position of the top left corner on the
+terminal screen. If the new corrdinates would place part of the window
+off the screen, the coordinates are modified so that the window stays
+on the screen.
+
+int procedure newwin (nrows, ncols, row, col)
+
+int nrows # i: Window height
+int ncols # i: Window width
+int row # i: Top row of window
+int col # i: Leftmost column of window
+
+This procedure creates a new window. The returned value is the window
+descriptor, which is used as an argument to the other window
+functions. The window position is relative to the top left corner of
+the terminal, which has the coordinates (1,1). If part of the window
+is off the terminal screen, it will be placed and sized so that the
+entire window fits on the screen.
+
+procedure refresh ()
+procedure wrefresh (win)
+
+int win # i: Window descriptor
+
+This procedure causes all changes to a window that have been made by
+other calls in this library to be displayed on the terminal screen. If
+the clear flag has been set to yes by clearok(), the window will be
+cleared and redrawn.
+
+procedure savewin ()
+procedure nosavewin ()
+
+These procedures set and unset the save flag. If the save flag is set,
+whenever a window is created, the area on the terminal screen under is
+saved in a buffer so it can be restored when the window is hidden or
+deleted. If a window will exist throughout the life of a program, the
+save flag can be unset by calling nosavewin() before creating the
+window so that the memory used to hold the buffer will not be wasted.
+The save flag is initially set to yes so that all windows have
+associated screen buffers by default.
+
+procedure scrollok (win, flag)
+
+int win # i: Window descriptor
+bool flag # i: Flag value
+
+If the scroll flag is set to true, a window will scroll when an
+attempt is made to write beyond the last line of a window. If the
+scroll flag is false, the last line of the window will be overwritten.
+When a new window is created, the scroll flag is set to false.
+
+procedure showwin (win)
+
+int win # i: Window descriptor
+
+This procedure shows a window that was previously hidden by a call to
+hidewin(). If the window is not hidden, this procedure has no effect.
+
+procedure standout ()
+procedure standend ()
+procedure wstandout (win)
+procedure wstandend (win)
+
+int win # i: Window descriptor
+
+These procedures modify the character attribute of a window. Calling
+standout() causes all characters written to the window after the call
+to be written in standout mode. Calling standend() causes all
+characacters to be written in normal mode. When a window is created,
+the character attribute of the window is normal.
+
+procedure wdimen (win, nrows, ncols)
+
+int win # i: Window descriptor
+int nrows # o: Window height
+int ncols # o: Window width
+
+This procedure returns the height and width of a window.
+
+int procedure winstat (win, what)
+
+int win # i: Window descriptor
+int what # i: Field to retrieve
+
+This procedure returns a field from the window descriptor. The field
+to retrieve is given by a symbolic constant. These constants are
+listed in the include file <curses.h>.
diff --git a/pkg/utilities/nttools/tedit/display/curses/addch.x b/pkg/utilities/nttools/tedit/display/curses/addch.x
new file mode 100644
index 00000000..f08085e4
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/addch.x
@@ -0,0 +1,30 @@
+include "../curses.h"
+
+# ADDCH -- Add a character to the standard screen
+#
+# B.Simon 01-Oct-90 Original
+
+procedure addch (ch)
+
+char ch # i: Character to add
+#--
+char str[1]
+
+begin
+ str[1] = ch
+ str[2] = EOS
+ call waddstr (STDSCR, str)
+end
+
+procedure waddch (win, ch)
+
+int win # i: Window descriptor
+char ch # i: Character to add
+#--
+char str[1]
+
+begin
+ str[1] = ch
+ str[2] = EOS
+ call waddstr (win, str)
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/addstr.x b/pkg/utilities/nttools/tedit/display/curses/addstr.x
new file mode 100644
index 00000000..f675d151
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/addstr.x
@@ -0,0 +1,157 @@
+include <ctype.h>
+include "../curses.h"
+include "window.h"
+
+define TABSTOP 8
+
+# ADDSTR -- Add a string to a window
+#
+# B.Simon 02-Oct-90 Original
+
+procedure addstr (str)
+
+char str[ARB] # i: String to add to window
+#--
+
+begin
+ call waddstr (STDSCR, str)
+end
+
+procedure waddstr (win, str)
+
+int win # i: Window descriptor
+char str[ARB] # i: String to add to window
+#--
+include "window.com"
+
+bool moved
+int row, col, nrows, ncols, ic, jc, mxchar, itab
+pointer sp, line, pwin
+
+begin
+ pwin = warray[win]
+
+ # Don't print anything if echoing is turned off
+
+ if (echoed == NO)
+ return
+
+ # Allocate an array to hold the string to print
+
+ call smark (sp)
+ call salloc (line, SZ_LINE, TY_CHAR)
+
+ # Get the current cursor position and window size
+
+ row = WIN_CURROW(pwin)
+ col = WIN_CURCOL(pwin)
+ ncols = WIN_WIDTH(pwin)
+ nrows = WIN_HEIGHT(pwin)
+
+ ic = 0
+ jc = 0
+ moved = false
+
+ repeat {
+ ic = ic + 1
+
+ # If the character is printable, just copy it to the array
+ # The array will be printed when the EOS is read
+
+ if (IS_PRINT(str[ic])) {
+ col = col + 1
+ Memc[line+jc] = str[ic]
+ jc = jc + 1
+
+ } else {
+ # Print any characters in the array before handling
+ # the non-printing character
+
+ Memc[line+jc] = EOS
+ if (jc > 0) {
+ jc = 0
+
+ mxchar = ncols - WIN_CURCOL(pwin) + 1
+ call ps_write (WIN_TOP(pwin)+WIN_CURROW(pwin)-1,
+ WIN_LEFT(pwin)+WIN_CURCOL(pwin)-1,
+ mxchar, Memc[line], WIN_ATRIB(pwin))
+
+ WIN_CURCOL(pwin) = col
+ WIN_CURROW(pwin) = row
+
+ # Check for writing past the edge of the window
+ # and scrolling
+
+ if (col > ncols) {
+ col = 1
+ row = row + 1
+ moved = true
+
+ if (row > nrows) {
+ row = nrows
+ if (WIN_SCROLL(pwin) == YES)
+ call wslide (WIN_RECT(pwin), DIR_UP, 1)
+ }
+ }
+ }
+
+ # Some non-printing characters require special action
+ # Others are mapped to printing characters and written
+ # to the array
+
+ switch (str[ic]) {
+ case EOS:
+ ;
+
+ case '\n':
+ call wclrtoeol (win)
+ col = 1
+ row = row + 1
+ moved = true
+
+ # Scroll window if we've hit the last row
+
+ if (row > nrows) {
+ row = nrows
+ if (WIN_SCROLL(pwin) == YES)
+ call wslide (WIN_RECT(pwin), DIR_UP, 1)
+ }
+
+ case '\t':
+ do itab = 1, TABSTOP - mod (col, TABSTOP) {
+ Memc[line+jc] = ' '
+ jc = jc + 1
+ col = col + 1
+ }
+
+ case '\r':
+ if (col > 1) {
+ col = 1
+ moved = true
+ }
+
+ case '\010':
+ if (col > 1) {
+ col = col - 1
+ moved = true
+ }
+
+ default:
+ Memc[line+jc] = ' '
+ col = col + 1
+ jc = jc + 1
+ }
+ }
+
+ # Move cursor, as required
+
+ if (moved) {
+ moved = false
+ call wmove (win, row, col)
+ }
+
+ } until (str[ic] == EOS)
+
+ call sfree (sp)
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/bindstruct.x b/pkg/utilities/nttools/tedit/display/curses/bindstruct.x
new file mode 100644
index 00000000..f9502c3d
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/bindstruct.x
@@ -0,0 +1,35 @@
+include "../curses.h"
+include "window.h"
+
+# BINDSTRUCT -- Bind a data structure and function to a window
+
+procedure bindstruct (func, structure)
+
+extern func # i: Input function
+pointer structure # i: Data structure
+#--
+
+begin
+ call wbindstruct (STDSCR, func, structure)
+end
+
+procedure wbindstruct (win, func, structure)
+
+int win # i: Window descriptor
+extern func # i: Input function
+pointer structure # i: Data structure
+#--
+include "window.com"
+
+pointer pwin
+pointer locpr()
+
+begin
+ pwin = warray[win]
+ if (WIN_DATA(pwin) != NULL)
+ call mfree (WIN_DATA(pwin), TY_STRUCT)
+
+ WIN_FUNC(pwin) = locpr (func)
+ WIN_DATA(pwin) = structure
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/box.x b/pkg/utilities/nttools/tedit/display/curses/box.x
new file mode 100644
index 00000000..06eadbcd
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/box.x
@@ -0,0 +1,56 @@
+include "../curses.h"
+include "window.h"
+
+# BOX -- Draw a box around a window
+#
+# B.Simon 01-Oct-90 Original
+
+procedure box (win, vert, hor)
+
+int win # i: Window descriptor
+char vert # i: Character used for vertical side of window
+char hor # i: Character used for horizontal side of window
+#--
+include "window.com"
+
+int vcode, hcode, rect[RSIZE]
+pointer pwin
+
+begin
+ # Don't box window if either dimension < 3 or window is already boxed
+
+ pwin = warray[win]
+ if (WIN_HEIGHT(pwin) < 3 || WIN_WIDTH(pwin) < 3 ||
+ WIN_BOXED(pwin) == YES)
+ return
+
+ # Draw box
+
+ vcode = vert
+ hcode = hor
+
+ RASG(rect, WIN_TOP(pwin), WIN_LEFT(pwin),
+ WIN_TOP(pwin), WIN_RIGHT(pwin))
+ call ps_fill (rect, hcode, WIN_ATRIB(pwin))
+
+ RASG(rect, WIN_BOT(pwin), WIN_LEFT(pwin),
+ WIN_BOT(pwin), WIN_RIGHT(pwin))
+ call ps_fill (rect, hcode, WIN_ATRIB(pwin))
+
+ RASG(rect, WIN_TOP(pwin), WIN_LEFT(pwin),
+ WIN_BOT(pwin), WIN_LEFT(pwin))
+ call ps_fill (rect, vcode, WIN_ATRIB(pwin))
+
+ RASG(rect, WIN_TOP(pwin), WIN_RIGHT(pwin),
+ WIN_BOT(pwin), WIN_RIGHT(pwin))
+ call ps_fill (rect, vcode, WIN_ATRIB(pwin))
+
+ # Reduce size of window's rectangle and mark as boxed
+
+ WIN_TOP(pwin) = WIN_TOP(pwin) + 1
+ WIN_LEFT(pwin) = WIN_LEFT(pwin) + 1
+ WIN_BOT(pwin) = WIN_BOT(pwin) - 1
+ WIN_RIGHT(pwin) = WIN_RIGHT(pwin) - 1
+ WIN_BOXED(pwin) = YES
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/clear.x b/pkg/utilities/nttools/tedit/display/curses/clear.x
new file mode 100644
index 00000000..7b69f63d
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/clear.x
@@ -0,0 +1,35 @@
+include "../curses.h"
+include "window.h"
+
+# CLEAR -- Clear window and force a redraw of the screen
+#
+# B.Simon 01-Oct-90 Original
+
+procedure clear ()
+
+#--
+include "window.com"
+
+pointer pwin
+
+begin
+ pwin = warray[STDSCR]
+ WIN_CLEAR(pwin) = YES
+
+ call werase (STDSCR)
+end
+
+procedure wclear (win)
+
+int win # i: Window descriptor
+#--
+include "window.com"
+
+pointer pwin
+
+begin
+ pwin = warray[win]
+ WIN_CLEAR(pwin) = YES
+
+ call werase (win)
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/clearok.x b/pkg/utilities/nttools/tedit/display/curses/clearok.x
new file mode 100644
index 00000000..9d3372a9
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/clearok.x
@@ -0,0 +1,21 @@
+include "window.h"
+
+# CLEAROK -- Set the clear flag for a window
+#
+# B.Simon 01-Oct-90 Original
+
+procedure clearok (win, flag)
+
+int win # i: Window descriptor
+bool flag # i: Flag value
+#--
+include "window.com"
+
+pointer pwin
+int btoi()
+
+begin
+ pwin = warray[win]
+ WIN_CLEAR(pwin) = btoi (flag)
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/clrtobot.x b/pkg/utilities/nttools/tedit/display/curses/clrtobot.x
new file mode 100644
index 00000000..da60b805
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/clrtobot.x
@@ -0,0 +1,56 @@
+include "../curses.h"
+include "window.h"
+
+# CLRTOBOT -- Clear window to bottom
+#
+# B.Simon 28-Sep-90 Original
+
+procedure clrtobot ()
+
+#--
+
+begin
+ call wclrtobot (STDSCR)
+end
+
+procedure wclrtobot (win)
+
+int win # i: Window descriptor
+#--
+include "window.com"
+
+int blank, rect[RSIZE]
+pointer pwin
+
+data blank / ' ' /
+
+begin
+ pwin = warray[win]
+
+ # First line may be partial, so it must be handled separately
+
+ if (WIN_CURCOL(pwin) == 1) {
+ RTOP(rect) = WIN_TOP(pwin) + WIN_CURROW(pwin) - 1
+ } else {
+ RTOP(rect) = WIN_TOP(pwin) + WIN_CURROW(pwin) - 1
+ RLEFT(rect) = WIN_LEFT(pwin) + WIN_CURCOL(pwin) - 1
+ RBOT(rect) = RTOP(rect)
+ RRIGHT(rect) = WIN_RIGHT(pwin)
+ call ps_fill (rect, blank, WIN_ATRIB(pwin))
+
+ RTOP(rect) = min (RBOT(rect), RTOP(rect)+1)
+ }
+
+ # Remaining lines form a rectangle
+
+ RLEFT(rect) = WIN_LEFT(pwin)
+ RBOT(rect) = WIN_BOT(pwin)
+ RRIGHT(rect) = WIN_RIGHT(pwin)
+
+ call ps_fill (rect, blank, WIN_ATRIB(pwin))
+ if (WIN_LEAVE(pwin) == NO) {
+ call ps_setcur (WIN_TOP(pwin)+WIN_CURROW(pwin)-1,
+ WIN_LEFT(pwin)+WIN_CURCOL(pwin)-1)
+ }
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/clrtoeol.x b/pkg/utilities/nttools/tedit/display/curses/clrtoeol.x
new file mode 100644
index 00000000..2c42a64e
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/clrtoeol.x
@@ -0,0 +1,45 @@
+include "../curses.h"
+include "window.h"
+
+# CLRTOEOL -- Clear window to end of current line
+#
+# B.Simon 01-Oct-90 Original
+
+procedure clrtoeol ()
+
+#--
+
+begin
+ call wclrtoeol (STDSCR)
+end
+
+procedure wclrtoeol (win)
+
+int win # i: Window descriptor
+#--
+include "window.com"
+
+int blank, rect[RSIZE]
+pointer pwin
+
+data blank / ' ' /
+
+begin
+ pwin = warray[win]
+
+ # Construct the rectangle consisting of the remainder of the
+ # current line and fill with blanks
+
+ RTOP(rect) = WIN_TOP(pwin) + WIN_CURROW(pwin) - 1
+ RLEFT(rect) = WIN_LEFT(pwin) + WIN_CURCOL(pwin) - 1
+ RBOT(rect) = RTOP(rect)
+ RRIGHT(rect) = WIN_RIGHT(pwin)
+ call ps_fill (rect, blank, WIN_ATRIB(pwin))
+
+ # Move the cursor to the new end of the line
+
+ if (WIN_LEAVE(pwin) == NO)
+ call ps_setcur (WIN_TOP(pwin)+WIN_CURROW(pwin)-1,
+ WIN_LEFT(pwin)+WIN_CURCOL(pwin)-1)
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/delch.x b/pkg/utilities/nttools/tedit/display/curses/delch.x
new file mode 100644
index 00000000..a58ed17d
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/delch.x
@@ -0,0 +1,41 @@
+include "../curses.h"
+include "window.h"
+
+# DELCH -- Delete a character from the window
+
+procedure delch ()
+
+# B.Simon 01-Oct-90 Original
+
+#--
+
+begin
+ call wdelch (STDSCR)
+end
+
+procedure wdelch (win)
+
+pointer win # i: Window descriptor
+#--
+include "window.com"
+
+int rect[RSIZE]
+pointer pwin
+
+begin
+ pwin = warray[win]
+
+ # Construct rectangle to slide
+
+ RTOP(rect) = WIN_TOP(pwin) + WIN_CURROW(pwin) - 1
+ RLEFT(rect) = WIN_LEFT(pwin) + WIN_CURCOL(pwin)
+ RBOT(rect) = RTOP(rect)
+ RRIGHT(rect) = WIN_RIGHT(pwin)
+
+ call wslide (rect, DIR_LEFT, 1)
+
+ if (WIN_LEAVE(pwin) == NO)
+ call ps_setcur (WIN_TOP(pwin)+WIN_CURROW(pwin)-1,
+ WIN_LEFT(pwin)+WIN_CURCOL(pwin)-1)
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/deleteln.x b/pkg/utilities/nttools/tedit/display/curses/deleteln.x
new file mode 100644
index 00000000..f5afa1dd
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/deleteln.x
@@ -0,0 +1,41 @@
+include "../curses.h"
+include "window.h"
+
+# DELETELN -- Delete a line from the window
+#
+# B.Simon 01-Oct-90 Original
+
+procedure deleteln ()
+
+#--
+
+begin
+ call wdeleteln (STDSCR)
+end
+
+procedure wdeleteln (win)
+
+pointer win # i: Window descriptor
+#--
+include "window.com"
+
+int rect[RSIZE]
+pointer pwin
+
+begin
+ pwin = warray[win]
+
+ # Construct rectangle to slide
+
+ RTOP(rect) = WIN_TOP(pwin) + WIN_CURROW(pwin) - 1
+ RLEFT(rect) = WIN_LEFT(pwin)
+ RBOT(rect) = WIN_BOT(pwin)
+ RRIGHT(rect) = WIN_RIGHT(pwin)
+
+ call wslide (rect, DIR_UP, 1)
+
+ if (WIN_LEAVE(pwin) == NO)
+ call ps_setcur (WIN_TOP(pwin)+WIN_CURROW(pwin)-1,
+ WIN_LEFT(pwin)+WIN_CURCOL(pwin)-1)
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/delwin.x b/pkg/utilities/nttools/tedit/display/curses/delwin.x
new file mode 100644
index 00000000..5b0db192
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/delwin.x
@@ -0,0 +1,42 @@
+include "../curses.h"
+include "window.h"
+
+# DELWIN --Delete a window
+#
+# B.Simon 28-Sep-90 Original
+
+procedure delwin (win)
+
+int win # i: Window descriptor
+#--
+include "window.com"
+
+int rect[RSIZE]
+pointer pwin
+
+begin
+ # Can't free the standard screen
+
+ if (win == STDSCR)
+ return
+
+ pwin = warray[win]
+
+ # Copy the screen under the window back to the terminal
+ # and then free the buffer which held it
+
+ if (WIN_BUFFER(pwin) != NULL) {
+ call wrect (win, YES, rect)
+ call putscreen (rect, WIN_BUFFER(pwin))
+ call freescreen (WIN_BUFFER(pwin))
+ }
+
+ # Free any data structure associated with the window
+
+ if (WIN_DATA(pwin) != NULL)
+ call mfree (WIN_DATA(pwin), TY_STRUCT)
+
+ call mfree (pwin, TY_STRUCT)
+ warray[win] = NULL
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/echo.x b/pkg/utilities/nttools/tedit/display/curses/echo.x
new file mode 100644
index 00000000..8152aff6
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/echo.x
@@ -0,0 +1,23 @@
+include "window.h"
+
+# ECHO -- Turn character echoing on
+#
+# B.Simon 02-Oct-90 Original
+
+procedure echo ()
+
+#--
+include "window.com"
+
+begin
+ echoed = YES
+end
+
+procedure noecho ()
+
+#--
+include "window.com"
+
+begin
+ echoed = NO
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/endwin.x b/pkg/utilities/nttools/tedit/display/curses/endwin.x
new file mode 100644
index 00000000..87a6c826
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/endwin.x
@@ -0,0 +1,34 @@
+include "window.h"
+
+# ENDWIN -- Finish up window routines
+#
+# B.Simon 28-Sep-90 Original
+
+procedure endwin ()
+
+#--
+include "window.com"
+
+int win
+pointer pwin
+
+begin
+ # Release windows that are still active
+
+ do win = 1, MAXWIN {
+ pwin = warray[win]
+ if (pwin != NULL) {
+ if (WIN_BUFFER(pwin) != NULL)
+ call freescreen (WIN_BUFFER(pwin))
+ if (WIN_DATA(pwin) != NULL)
+ call mfree (WIN_DATA(pwin), TY_STRUCT)
+ call mfree (pwin, TY_STRUCT)
+ }
+ }
+
+ # Reset terminal
+
+ call k_end
+ call ps_end
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/erase.x b/pkg/utilities/nttools/tedit/display/curses/erase.x
new file mode 100644
index 00000000..86b529a8
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/erase.x
@@ -0,0 +1,37 @@
+include "../curses.h"
+include "window.h"
+
+# ERASE -- Erase window
+#
+# B.Simon 28-Sep-90 Original
+
+procedure erase ()
+
+#--
+
+begin
+ call werase (STDSCR)
+end
+
+procedure werase (win)
+
+int win # i: Window descriptor
+#--
+include "window.com"
+
+int blank
+pointer pwin
+
+data blank / ' ' /
+
+begin
+ pwin = warray[win]
+ call ps_fill (WIN_RECT(pwin), blank, WIN_ATRIB(pwin))
+
+ if (WIN_LEAVE(pwin) == NO) {
+ call ps_setcur (WIN_TOP(pwin), WIN_LEFT(pwin))
+ WIN_CURROW(pwin) = 1
+ WIN_CURCOL(pwin) = 1
+ }
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/freescreen.x b/pkg/utilities/nttools/tedit/display/curses/freescreen.x
new file mode 100644
index 00000000..66321451
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/freescreen.x
@@ -0,0 +1,13 @@
+# FREESCREEN -- Free a window's buffer
+#
+# B.Simon 26-Sep-90 Original
+
+procedure freescreen (buffer)
+
+pointer buffer # i: Buffer allocated by wgetscr
+#--
+
+begin
+ if (buffer != NULL)
+ call mfree (buffer, TY_CHAR)
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/getch.x b/pkg/utilities/nttools/tedit/display/curses/getch.x
new file mode 100644
index 00000000..9d69c11f
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/getch.x
@@ -0,0 +1,53 @@
+include "../curses.h"
+include "window.h"
+
+# GETCH -- Get a character and display it in the window
+
+int procedure getch ()
+
+# B.Simon 01-Oct-90 Original
+
+#--
+int wgetch()
+
+begin
+ return (wgetch (STDSCR))
+end
+
+int procedure wgetch (win)
+
+pointer win # i: Window descriptor
+#--
+include "window.com"
+
+char str[1]
+int ch
+pointer pwin
+
+int k_get()
+
+begin
+ str[1] = EOS
+ str[2] = EOS
+ pwin = warray[win]
+
+ if (WIN_FUNC(pwin) == NULL) {
+ call ps_synch
+ ch = k_get ()
+
+ if (ch < K_BASE) {
+ str[1] = ch
+ call waddstr (win, str)
+ }
+
+ } else {
+ call zcall3 (WIN_FUNC(pwin), win, str, 1)
+ if (str[1] == EOS) {
+ ch = k_get () # get pushed back character
+ } else {
+ ch = str[1]
+ }
+ }
+
+ return (ch)
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/getscreen.x b/pkg/utilities/nttools/tedit/display/curses/getscreen.x
new file mode 100644
index 00000000..58020c3f
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/getscreen.x
@@ -0,0 +1,48 @@
+include "../curses.h"
+
+# GETSCREEN -- Retrieve screen contents into a window's buffer
+#
+# B.Simon 26-Sep-90 Original
+
+procedure getscreen (source, buffer)
+
+int source[RSIZE] # i: Rectangle to be retrieved
+pointer buffer # o: Buffer (allocated by this routine)
+#--
+
+int dest[RSIZE]
+int maxcol, maxrow, ncols, nrows, irow
+pointer buf, scr
+
+bool ps_intersect()
+int ps_width(), ps_height()
+pointer ps_screen()
+
+begin
+ # Clip the rectangle to the screen boundary
+ # If the rectangle is entirely off the screen, return
+
+ buffer = NULL
+ maxcol = ps_width ()
+ maxrow = ps_height ()
+ if (! ps_intersect (source, maxrow, maxcol, dest))
+ return
+
+ # Allocate buffer to hold screen contents
+
+ ncols = RWIDTH(dest)
+ nrows = RHEIGHT(dest)
+ call malloc (buffer, ncols*nrows, TY_CHAR)
+
+ # Copy screen contents to buffer
+
+ buf = buffer
+ scr = ps_screen (RTOP(dest), RLEFT(dest))
+
+ do irow = RTOP(dest), RBOT(dest) {
+ call amovc (Memc[scr], Memc[buf], ncols)
+ scr = scr + maxcol
+ buf = buf + ncols
+ }
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/getstr.x b/pkg/utilities/nttools/tedit/display/curses/getstr.x
new file mode 100644
index 00000000..6c1d38e6
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/getstr.x
@@ -0,0 +1,317 @@
+include <ctype.h>
+include "../curses.h"
+include "window.h"
+
+# GETSTR -- Get a string from the keyboard and display it in the window
+#
+# B.Simon 12-Dec-90 Original
+# B.Simon 21-Mar-91 Add several new commands
+
+procedure getstr (str, maxch)
+
+char str[ARB] # o: String that was read from the keyboard
+int maxch # i: Maximum string length
+#--
+int ch
+
+int k_get()
+
+begin
+ str[1] = EOS
+ call weditstr (STDSCR, str, maxch)
+
+ ch = k_get () # discard pushed back character
+end
+
+procedure wgetstr (win, str, maxch)
+
+pointer win # i: Window descriptor
+char str[ARB] # o: String that was read from the keyboard
+int maxch # i: Maximum string length
+#--
+int ch
+
+int k_get()
+
+begin
+ str[1] = EOS
+ call weditstr (win, str, maxch)
+
+ ch = k_get () # discard pushed back character
+end
+
+# EDITSTR -- Edit a string while displaying it in the window
+
+procedure editstr (str, maxch)
+
+char str[ARB] # u: String to edit
+int maxch # i: Maximum string length
+#--
+
+begin
+ call weditstr (STDSCR, str, maxch)
+end
+
+procedure weditstr (win, str, maxch)
+
+pointer win # i: Window descriptor
+char str[ARB] # u: String to edit
+int maxch # i: Maximum string length
+#--
+include "window.com"
+
+pointer pwin
+
+begin
+ # NOTE: It is the reponsibility of the calling program
+ # to make sure that the current window contents and the
+ # string passed to this procedure are in agreement before
+ # this procedure is called.
+
+ pwin = warray[win]
+
+ if (WIN_FUNC(pwin) == NULL) {
+ call editfn (win, str, maxch)
+ } else {
+ call zcall3 (WIN_FUNC(pwin), win, str, maxch)
+ }
+
+end
+
+# EDITFN -- Default function to process window input
+
+procedure editfn (win, str, maxch)
+
+int win # i: Window descriptor
+char str[ARB] # u: String containing line
+int maxch # i: Maximum line length
+#--
+int row, col, ch, ic, jc, mc, nc
+pointer sp, buffer
+
+int strlen(), k_get(), winstat()
+
+begin
+ ic = 0
+ nc = strlen (str)
+
+ row = winstat (win, W_CURROW)
+ col = winstat (win, W_CURCOL)
+
+ call smark (sp)
+ call salloc (buffer, SZ_LINE, TY_CHAR)
+ Memc[buffer] = EOS
+
+ while (nc < maxch) {
+
+ # Read character from keyboard
+
+ call ps_synch
+ ch = k_get ()
+
+ # Check for carriage return
+
+ if (ch == '\r')
+ break
+
+ if (IS_PRINT(ch)) {
+ ic = ic + 1
+ nc = nc + 1
+
+ if (ic == nc) {
+ str[ic] = ch
+ str[ic+1] = EOS
+ call waddstr (win, str[ic])
+
+ } else {
+ call amovc (str[ic], str[ic+1], nc-ic+1)
+
+ str[ic] = ch
+ call winsch (win, str[ic])
+ }
+
+ } else {
+ switch (ch) {
+ case K_UP: # Move up one field
+ break
+
+ case K_DOWN: # Move down one field
+ break
+
+ case K_RIGHT: # Move right one column
+ if (ic < nc) {
+ ic = ic + 1
+ call wmove (win, row, col+ic)
+ }
+
+ case K_LEFT: # Move left one column
+ if (ic > 0) {
+ ic = ic - 1
+ call wmove (win, row, col+ic)
+ }
+
+ case K_NEXTW: # Move forwards one word
+ call mvword_next (str, ic, jc)
+
+ if (jc > ic) {
+ ic = jc
+ call wmove (win, row, col+ic)
+ }
+
+ case K_PREVW: # Move backwards one word
+ call mvword_prev (str, ic, jc)
+
+ if (jc < ic) {
+ ic = jc
+ call wmove (win, row, col+ic)
+ }
+
+ case K_NEXTP: # Move forwards one screen
+ break
+
+ case K_PREVP: # Move backwards one screen
+ break
+
+ case K_HOME: # Move to first field
+ break
+
+ case K_END: # Move to last field
+ break
+
+ case K_BOL: # Move to first column in line
+ if (ic > 0) {
+ ic = 0
+ call wmove (win, row, col)
+ }
+
+ case K_EOL: # Move to last column in line
+ if (ic < nc) {
+ ic = nc
+ call wmove (win, row, col+ic)
+ }
+
+ case K_DEL: # Delete character underneath cursor
+ if (ic < nc) {
+ mc = strlen (Memc[buffer])
+
+ Memc[buffer+mc] = str[ic+1]
+ Memc[buffer+mc+1] = EOS
+
+ call amovc (str[ic+2], str[ic+1], nc-ic)
+
+ call wdelch (win)
+ nc = nc - 1
+ }
+
+ case K_BS: # Delete character to left of cursor
+ if (ic > 0) {
+ mc = strlen (Memc[buffer])
+
+ call amovc (Memc[buffer], Memc[buffer+1], mc+1)
+ Memc[buffer] = str[ic]
+
+ ic = ic - 1
+ call amovc (str[ic+2], str[ic+1], nc-ic)
+
+ call wmove (win, row, col+ic)
+ call wdelch (win)
+ nc = nc - 1
+ }
+
+ case K_DWORD: # Delete next word
+ call mvword_next (str, ic, jc)
+
+ if (jc > ic) {
+ mc = strlen (Memc[buffer])
+ call strcpy (str[ic+1], Memc[buffer+mc], jc-ic)
+ call amovc (str[jc+1], str[ic+1], nc-jc+1)
+
+ call wclrtoeol (win)
+ call waddstr (win, str[ic+1])
+ call wmove (win, row, col+ic)
+ nc = nc - (jc - ic)
+ }
+
+ case K_DLINE: # Delete entire line
+ if (nc > 0) {
+ call strcpy (str[ic+1], Memc[buffer], nc-ic)
+ str[ic+1] = EOS
+
+ call wclrtoeol (win)
+ nc = ic
+ }
+
+ case K_UNDCHR: # Undelete a character
+ mc = strlen (Memc[buffer])
+ if (mc > 0) {
+ call amovc (str[ic+1], str[ic+2], nc-ic+1)
+ str[ic+1] = Memc[buffer+mc-1]
+
+ Memc[buffer+mc-1] = EOS
+ call winsch (win, str[ic+1])
+
+ ic = ic + 1
+ nc = nc + 1
+ }
+
+ case K_UNDWRD: # Undelete a word
+ mc = strlen (Memc[buffer])
+ call mvword_prev (Memc[buffer], mc, jc)
+
+ mc = mc - jc
+ if (mc > 0) {
+ call amovc (str[ic+1], str[ic+mc+1], nc-ic+1)
+ call amovc (Memc[buffer+jc], str[ic+1], mc)
+
+ Memc[buffer+jc] = EOS
+ call wclrtoeol (win)
+ call waddstr (win, str[ic+1])
+
+ ic = ic + mc
+ nc = nc + mc
+ call wmove (win, row, col+ic)
+ }
+
+ case K_UNDLIN: # Undelete a line
+ mc = strlen (Memc[buffer])
+ if (mc > 0) {
+ call amovc (str[ic+1], str[ic+mc+1], nc-ic+1)
+ call amovc (Memc[buffer], str[ic+1], mc)
+
+ Memc[buffer] = EOS
+ call wclrtoeol (win)
+ call waddstr (win, str[ic+1])
+
+ ic = ic + mc
+ nc = nc + mc
+ call wmove (win, row, col+ic)
+ }
+
+ case K_HELP: # Display help screen
+ break
+
+ case K_PAINT: # Redraw the screen
+ call clearok (STDSCR, true)
+ call wrefresh (STDSCR)
+ call wmove (win, row, col+ic)
+
+ case K_EXIT: # Exit procedure
+ break
+
+ default: # Any other character
+ break
+ }
+ }
+ }
+
+ # Terminate string with EOS and push back character
+ # that terminated input
+
+ if (nc >= maxch)
+ ch = EOS
+
+ str[nc+1] = EOS
+ call k_pushbk (ch)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/getstruct.x b/pkg/utilities/nttools/tedit/display/curses/getstruct.x
new file mode 100644
index 00000000..9fbce77e
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/getstruct.x
@@ -0,0 +1,27 @@
+include "../curses.h"
+include "window.h"
+
+# GETSTRUCT -- Get the data structure associated with a window
+
+procedure getstruct (structure)
+
+pointer structure # o: Data structure
+#--
+
+begin
+ call wgetstruct (STDSCR, structure)
+end
+
+procedure wgetstruct (win, structure)
+
+int win # i: Window descriptor
+pointer structure # o: Data structure
+#--
+include "window.com"
+
+pointer pwin
+
+begin
+ pwin = warray[win]
+ structure = WIN_DATA(pwin)
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/getyx.x b/pkg/utilities/nttools/tedit/display/curses/getyx.x
new file mode 100644
index 00000000..d25b9b46
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/getyx.x
@@ -0,0 +1,22 @@
+include "window.h"
+
+# GETYX -- Get the current cursor position
+#
+# B.Simon 02-Oct-90 Original
+
+procedure getyx (win, row, col)
+
+int win # i: Window descriptor
+int row # o: Cursor row
+int col # o: Cursor column
+#--
+include "window.com"
+
+pointer pwin
+
+begin
+ pwin = warray[win]
+
+ row = WIN_CURROW(pwin)
+ col = WIN_CURCOL(pwin)
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/hidewin.x b/pkg/utilities/nttools/tedit/display/curses/hidewin.x
new file mode 100644
index 00000000..f116cffd
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/hidewin.x
@@ -0,0 +1,40 @@
+include "../curses.h"
+include "window.h"
+
+# HIDEWIN -- Hide a window
+#
+# B.Simon 28-Sep-90 Original
+
+procedure hidewin (win)
+
+int win # i: Window descriptor
+#--
+include "window.com"
+
+int rect[RSIZE]
+pointer pwin, buffer
+
+begin
+ pwin = warray[win]
+
+ # Don't do anything if the screen under the window wasn't
+ # saved or the window is already hidden
+
+ if (WIN_BUFFER(pwin) == NULL || WIN_HIDDEN(pwin) == YES)
+ return
+
+ # Save the current window contents in a buffer,
+ # and restore the screen under the window
+
+ call wrect (win, YES, rect)
+ call getscreen (rect, buffer)
+ call putscreen (rect, WIN_BUFFER(pwin))
+
+ # Place the window contents in its own buffer and
+ # mark the window as hidden
+
+ call freescreen (WIN_BUFFER(pwin))
+ WIN_BUFFER(pwin) = buffer
+ WIN_HIDDEN(pwin) = YES
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/inch.x b/pkg/utilities/nttools/tedit/display/curses/inch.x
new file mode 100644
index 00000000..9d80df3b
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/inch.x
@@ -0,0 +1,49 @@
+include "../curses.h"
+include "window.h"
+
+# INCH -- Get character at current cursor position
+#
+# B.Simon 02-Oct-90 Original
+
+char procedure inch ()
+
+#--
+char winch()
+
+begin
+ return (winch (STDSCR))
+end
+
+char procedure winch (win)
+
+pointer win # i: Window descriptor
+#--
+include "window.com"
+
+char ch
+int rect[RSIZE]
+pointer pwin, buf
+
+begin
+ pwin = warray[win]
+
+ # Create a box containing the character
+
+ if (WIN_BOXED(pwin) == NO) {
+ RTOP(rect) = WIN_TOP(pwin) + WIN_CURROW(pwin) - 1
+ RLEFT(rect) = WIN_LEFT(pwin) + WIN_CURCOL(pwin) - 1
+ } else {
+ RTOP(rect) = WIN_TOP(pwin) + WIN_CURROW(pwin)
+ RLEFT(rect) = WIN_LEFT(pwin) + WIN_CURCOL(pwin)
+ }
+ RBOT(rect) = RTOP(rect)
+ RRIGHT(rect) = RLEFT(rect)
+
+ # Get the character under the cursor
+
+ call getscreen (rect, buf)
+ ch = Memc[buf]
+ call freescreen (buf)
+
+ return (ch)
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/initscr.x b/pkg/utilities/nttools/tedit/display/curses/initscr.x
new file mode 100644
index 00000000..caa6b9fb
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/initscr.x
@@ -0,0 +1,33 @@
+include "../curses.h"
+include "window.h"
+
+# INITSCR -- Initialize curses routines
+
+procedure initscr ()
+
+#--
+include "window.com"
+
+int stdscr
+string cmdlist CMDSTR
+
+int newwin()
+
+begin
+ # Initialize global variables
+
+ saved = NO
+ echoed = YES
+ call aclri (warray, MAXWIN)
+
+ # Initialize terminal
+
+ call ps_begin
+ call k_begin (cmdlist)
+
+ # Create standard screen (STDSCR)
+
+ stdscr = newwin (GIANT, GIANT, 1, 1)
+ saved = YES
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/insch.x b/pkg/utilities/nttools/tedit/display/curses/insch.x
new file mode 100644
index 00000000..67dc9a7b
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/insch.x
@@ -0,0 +1,51 @@
+include "../curses.h"
+include "window.h"
+
+# INSCH -- Insert a character in the window
+#
+# B.Simon 02-Oct-90 Original
+
+procedure insch (ch)
+
+char ch # i: Character to insert
+#--
+
+begin
+ call winsch (STDSCR, ch)
+end
+
+procedure winsch (win, ch)
+
+pointer win # i: Window descriptor
+char ch # i: Character to insert
+#--
+include "window.com"
+
+char str[1]
+int rect[RSIZE]
+pointer pwin
+
+begin
+
+ pwin = warray[win]
+
+ # Construct rectangle to slide
+
+ RTOP(rect) = WIN_TOP(pwin) + WIN_CURROW(pwin) - 1
+ RLEFT(rect) = WIN_LEFT(pwin) + WIN_CURCOL(pwin) - 1
+ RBOT(rect) = RTOP(rect)
+ RRIGHT(rect) = WIN_RIGHT(pwin)
+
+ # Slide rectangle
+
+ call wslide (rect, DIR_RIGHT, 1)
+ call ps_setcur (WIN_TOP(pwin)+WIN_CURROW(pwin)-1,
+ WIN_LEFT(pwin)+WIN_CURCOL(pwin)-1)
+
+ # Write new character
+
+ str[1] = ch
+ str[2] = EOS
+ call waddstr (win, str)
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/insertln.x b/pkg/utilities/nttools/tedit/display/curses/insertln.x
new file mode 100644
index 00000000..604d860d
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/insertln.x
@@ -0,0 +1,41 @@
+include "../curses.h"
+include "window.h"
+
+# INSERTLN -- Insert a blank line in the window
+#
+# B.Simon 02-Oct-90 Original
+
+procedure insertln ()
+
+#--
+
+begin
+ call winsertln (STDSCR)
+end
+
+procedure winsertln (win)
+
+pointer win # i: Window descriptor
+#--
+include "window.com"
+
+int rect[RSIZE]
+pointer pwin
+
+begin
+ pwin = warray[win]
+
+ # Construct rectangle to slide
+
+ RTOP(rect) = WIN_TOP(pwin) + WIN_CURROW(pwin) - 1
+ RLEFT(rect) = WIN_LEFT(pwin)
+ RBOT(rect) = WIN_BOT(pwin)
+ RRIGHT(rect) = WIN_RIGHT(pwin)
+
+ call wslide (rect, DIR_DOWN, 1)
+
+ if (WIN_LEAVE(pwin) == NO)
+ call ps_setcur (WIN_TOP(pwin)+WIN_CURROW(pwin)-1,
+ WIN_LEFT(pwin)+WIN_CURCOL(pwin)-1)
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/leaveok.x b/pkg/utilities/nttools/tedit/display/curses/leaveok.x
new file mode 100644
index 00000000..3ce0f208
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/leaveok.x
@@ -0,0 +1,21 @@
+include "window.h"
+
+# LEAVEOK -- Set the leave flag for a window
+#
+# B.Simon 02-Oct-90 Original
+
+procedure leaveok (win, flag)
+
+int win # i: Window descriptor
+bool flag # i: Flag value
+#--
+include "window.com"
+
+pointer pwin
+int btoi()
+
+begin
+ pwin = warray[win]
+ WIN_LEAVE(pwin) = btoi (flag)
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/mkpkg b/pkg/utilities/nttools/tedit/display/curses/mkpkg
new file mode 100644
index 00000000..7708de04
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/mkpkg
@@ -0,0 +1,49 @@
+# Update the display library.
+# Author: B.Simon 01-APR-91
+
+$checkout libpkg.a ../../
+$update libpkg.a
+$checkin libpkg.a ../../
+$exit
+
+libpkg.a:
+ addch.x "../curses.h"
+ addstr.x <ctype.h> "../curses.h" "window.h" "window.com"
+ bindstruct.x "../curses.h" "window.h" "window.com"
+ box.x "../curses.h" "window.h" "window.com"
+ clear.x "../curses.h" "window.h" "window.com"
+ clearok.x "window.h" "window.com"
+ clrtobot.x "../curses.h" "window.h" "window.com"
+ clrtoeol.x "../curses.h" "window.h" "window.com"
+ delch.x "../curses.h" "window.h" "window.com"
+ deleteln.x "../curses.h" "window.h" "window.com"
+ delwin.x "../curses.h" "window.h" "window.com"
+ echo.x "window.h" "window.com"
+ endwin.x "window.h" "window.com"
+ erase.x "../curses.h" "window.h" "window.com"
+ freescreen.x
+ getch.x "../curses.h" "window.h" "window.com"
+ getscreen.x "../curses.h"
+ getstr.x "../curses.h" "window.h" "window.com"
+ getstruct.x "../curses.h" "window.h" "window.com"
+ getyx.x "window.h" "window.com"
+ hidewin.x "../curses.h" "window.h" "window.com"
+ inch.x "../curses.h" "window.h" "window.com"
+ initscr.x "../curses.h" "window.h" "window.com"
+ insch.x "../curses.h" "window.h" "window.com"
+ insertln.x "../curses.h" "window.h" "window.com"
+ leaveok.x "window.h" "window.com"
+ move.x "../curses.h" "window.h" "window.com"
+ mvwin.x "../curses.h" "window.h" "window.com"
+ mvword.x
+ newwin.x "../curses.h" "window.h" "window.com"
+ putscreen.x "../curses.h"
+ refresh.x "../curses.h" "window.h" "window.com"
+ savewin.x "window.h" "window.com"
+ scrollok.x "window.h" "window.com"
+ showwin.x "../curses.h" "window.h" "window.com"
+ standout.x "../curses.h" "window.h" "window.com"
+ wdimen.x "../curses.h" "window.h" "window.com"
+ winstat.x "../curses.h" "window.h" "window.com"
+ wslide.x "../curses.h"
+ ;
diff --git a/pkg/utilities/nttools/tedit/display/curses/move.x b/pkg/utilities/nttools/tedit/display/curses/move.x
new file mode 100644
index 00000000..ba3725f7
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/move.x
@@ -0,0 +1,39 @@
+include "../curses.h"
+include "window.h"
+
+# MOVE -- Move the cursor coordinates
+#
+# B.Simon 02-Oct-90 Original
+
+procedure move (row, col)
+
+int row # i: Cursor row
+int col # i: Cursor column
+#--
+
+begin
+ call wmove (STDSCR, row, col)
+end
+
+procedure wmove (win, row, col)
+
+int win # i: Window descriptor
+int row # i: Cursor row
+int col # i: Cursor column
+#--
+include "window.com"
+
+pointer pwin
+
+begin
+ pwin = warray[win]
+
+ WIN_CURROW(pwin) = max (1, row)
+ WIN_CURROW(pwin) = min (WIN_CURROW(pwin), WIN_HEIGHT(pwin))
+
+ WIN_CURCOL(pwin) = max (1, col)
+ WIN_CURCOL(pwin) = min (WIN_CURCOL(pwin), WIN_WIDTH(pwin))
+
+ call ps_setcur (WIN_TOP(pwin)+WIN_CURROW(pwin)-1,
+ WIN_LEFT(pwin)+WIN_CURCOL(pwin)-1)
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/mvwin.x b/pkg/utilities/nttools/tedit/display/curses/mvwin.x
new file mode 100644
index 00000000..dd7b9d73
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/mvwin.x
@@ -0,0 +1,63 @@
+include "../curses.h"
+include "window.h"
+
+# MVWIN -- Move home position of a window
+#
+# B.Simon 28-Sep-90 Original
+
+procedure mvwin (win, row, col)
+
+int win # i: Window descriptor
+int row # i: New top row of window
+int col # i: New left column of window
+#--
+include "window.com"
+
+bool shown
+int rect[RSIZE]
+int maxrow, maxcol, drow, dcol
+pointer pwin
+
+int ps_width(), ps_height()
+
+begin
+ pwin = warray[win]
+
+ # Compute new rectangle containing window
+ # Make sure it is confined to the current screen
+
+ maxrow = ps_height ()
+ maxcol = ps_width ()
+
+ drow = WIN_HEIGHT(pwin) - 1
+ dcol = WIN_WIDTH(pwin) - 1
+
+ RTOP(rect) = max (1, row)
+ if (RTOP(rect) + drow > maxrow)
+ RTOP(rect) = maxrow - drow
+
+ RLEFT(rect) = max (1, col)
+ if (RLEFT(rect) + dcol > maxcol)
+ RLEFT(rect) = maxcol - dcol
+
+ RBOT(rect) = RTOP(rect) + drow
+ RRIGHT(rect) = RLEFT(rect) + dcol
+
+ # Move the window by hiding it at its old location
+ # and showing it at the new location
+
+ if (RTOP(rect) != WIN_TOP(pwin) || RLEFT(rect) != WIN_LEFT(pwin)) {
+ shown = WIN_HIDDEN(pwin) == NO
+ if (shown)
+ call hidewin (win)
+
+ WIN_TOP(pwin) = RTOP(rect)
+ WIN_LEFT(pwin) = RLEFT(rect)
+ WIN_BOT(pwin) = RBOT(rect)
+ WIN_RIGHT(pwin) = RRIGHT(rect)
+
+ if (shown)
+ call showwin (win)
+ }
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/mvword.x b/pkg/utilities/nttools/tedit/display/curses/mvword.x
new file mode 100644
index 00000000..6a606e0d
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/mvword.x
@@ -0,0 +1,56 @@
+# MVWORD -- Move one word over in a string
+#
+# B.Simon 20-Mar-91 Original
+
+procedure mvword_next (str, ic, jc)
+
+char str[ARB] # i: String containing words
+int ic # i: Starting character (0 to strlen(str))
+int jc # o: Character before start of next word
+#--
+int nc
+int strlen()
+
+begin
+ # Find next blank
+
+ nc = strlen (str)
+ for (jc = min (ic+1, nc); jc < nc; jc = jc + 1) {
+ if (str[jc] <= ' ')
+ break
+ }
+
+ # Find first non-blank character after blank
+
+ for ( ; jc < nc; jc = jc + 1) {
+ if (str[jc] > ' ') {
+ jc = jc - 1 # back up to previous blank
+ break
+ }
+ }
+
+end
+
+procedure mvword_prev (str, ic, jc)
+
+char str[ARB] # i: String containing words
+int ic # i: Starting character (0 to strlen(str))
+int jc # o: Character before start of next word
+#--
+
+begin
+ # Find previous nonblank character
+
+ for (jc = max (ic-1, 0); jc > 0; jc = jc - 1) {
+ if (str[jc] > ' ')
+ break
+ }
+
+ # Find blank preceding non-blank character
+
+ for ( ; jc > 0; jc = jc - 1) {
+ if (str[jc] <= ' ')
+ break
+ }
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/newwin.x b/pkg/utilities/nttools/tedit/display/curses/newwin.x
new file mode 100644
index 00000000..f2195309
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/newwin.x
@@ -0,0 +1,83 @@
+include "../curses.h"
+include "window.h"
+
+# NEWWIN -- Create a new window
+#
+# B.Simon 28-Sep-90 Original
+
+int procedure newwin (nrows, ncols, row, col)
+
+int nrows # i: Window height
+int ncols # i: Window width
+int row # i: Top row of window
+int col # i: Leftmost column of window
+#--
+include "window.com"
+
+int win, maxrow, maxcol
+pointer pwin
+
+int ps_height(), ps_width()
+
+begin
+ # Find an empty slot in the window array and allocate a window
+
+ for (win = 1; win <= MAXWIN; win = win + 1) {
+ if (warray[win] == NULL)
+ break
+ }
+
+ if (win > MAXWIN)
+ call error (1, "Cannot create window")
+
+ call malloc (pwin, LEN_WINSTRUCT, TY_STRUCT)
+ warray[win] = pwin
+
+ # Compute the window's rectangle, making sure it is on the screen
+
+ maxrow = ps_height ()
+ maxcol = ps_width ()
+
+ if (row + nrows - 1 > maxrow)
+ WIN_TOP(pwin) = maxrow - nrows + 1
+ else
+ WIN_TOP(pwin) = row
+ WIN_TOP(pwin) = max (1, WIN_TOP(pwin))
+
+ if (col + ncols - 1 > maxcol)
+ WIN_LEFT(pwin) = maxcol - ncols + 1
+ else
+ WIN_LEFT(pwin) = col
+ WIN_LEFT(pwin) = max (1, WIN_LEFT(pwin))
+
+ WIN_BOT(pwin) = min (maxrow, WIN_TOP(pwin) + nrows - 1)
+ WIN_RIGHT(pwin) = min (maxcol, WIN_LEFT(pwin) + ncols - 1)
+
+ # Set the remaining fields of the window
+
+ WIN_CURROW(pwin) = 1
+ WIN_CURCOL(pwin) = 1
+ WIN_CLEAR(pwin) = NO
+ WIN_LEAVE(pwin) = NO
+ WIN_SCROLL(pwin) = NO
+ WIN_HIDDEN(pwin) = NO
+ WIN_BOXED(pwin) = NO
+ WIN_ATRIB(pwin) = A_NORM
+
+ if (saved == NO) {
+ WIN_BUFFER(pwin) = NULL
+ } else {
+ call getscreen (WIN_RECT(pwin), WIN_BUFFER(pwin))
+ }
+
+ WIN_FUNC(pwin) = NULL
+ WIN_DATA(pwin) = NULL
+
+ # Erase the window
+
+ call werase (win)
+
+ # Return window number
+
+ return (win)
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/omkpkg b/pkg/utilities/nttools/tedit/display/curses/omkpkg
new file mode 100644
index 00000000..21c3c249
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/omkpkg
@@ -0,0 +1,65 @@
+
+# Update the newdisp library.
+# Author: B.Simon 26-SEP-90
+
+$set XFLAGS = "-fgq $(XFLAGS)"
+$call default
+$exit
+
+debug:
+ $set XFLAGS = "-fgq $(XFLAGS)"
+ $call default
+ ;
+
+strip:
+ $delete newdisp.a
+ $call default
+ ;
+
+update:
+default:
+ $checkout newdisp.a ../../
+ $update newdisp.a
+ $checkin newdisp.a ../../
+ ;
+
+newdisp.a:
+ addch.x <curses.h>
+ addstr.x <ctype.h> <curses.h> "window.h" "window.com"
+ bindstruct.x <curses.h> "window.h" "window.com"
+ box.x <curses.h> "window.h" "window.com"
+ clear.x <curses.h> "window.h" "window.com"
+ clearok.x "window.h" "window.com"
+ clrtobot.x <curses.h> "window.h" "window.com"
+ clrtoeol.x <curses.h> "window.h" "window.com"
+ delch.x <curses.h> "window.h" "window.com"
+ deleteln.x <curses.h> "window.h" "window.com"
+ delwin.x <curses.h> "window.h" "window.com"
+ echo.x "window.h" "window.com"
+ endwin.x "window.h" "window.com"
+ erase.x <curses.h> "window.h" "window.com"
+ freescreen.x
+ getch.x <curses.h> "window.h" "window.com"
+ getscreen.x <curses.h>
+ getstr.x <curses.h> "window.h" "window.com"
+ getstruct.x <curses.h> "window.h" "window.com"
+ getyx.x "window.h" "window.com"
+ hidewin.x <curses.h> "window.h" "window.com"
+ inch.x <curses.h> "window.h" "window.com"
+ initscr.x <curses.h> "window.h" "window.com"
+ insch.x <curses.h> "window.h" "window.com"
+ insertln.x <curses.h> "window.h" "window.com"
+ leaveok.x "window.h" "window.com"
+ move.x <curses.h> "window.h" "window.com"
+ mvwin.x <curses.h> "window.h" "window.com"
+ newwin.x <curses.h> "window.h" "window.com"
+ putscreen.x <curses.h>
+ refresh.x <curses.h> "window.h" "window.com"
+ savewin.x "window.h" "window.com"
+ scrollok.x "window.h" "window.com"
+ showwin.x <curses.h> "window.h" "window.com"
+ standout.x <curses.h> "window.h" "window.com"
+ wdimen.x <curses.h> "window.h" "window.com"
+ winstat.x <curses.h> "window.h" "window.com"
+ wslide.x <curses.h>
+ ;
diff --git a/pkg/utilities/nttools/tedit/display/curses/putscreen.x b/pkg/utilities/nttools/tedit/display/curses/putscreen.x
new file mode 100644
index 00000000..83bb4966
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/putscreen.x
@@ -0,0 +1,84 @@
+include "../curses.h"
+
+# PUTSCREEN -- Copy buffer back onto screen
+#
+# B.Simon 27-Sep-90 Original
+
+procedure putscreen (source, buffer)
+
+int source[RSIZE] # i: Rectangle to be restored
+pointer buffer # i: Buffer
+#--
+
+bool clear
+int blank, dest[RSIZE]
+int maxcol, maxrow, ncols, nrows, icol, jcol, irow
+pointer sp, buf, ptr, scr
+
+data blank / ' ' /
+
+bool ps_intersect()
+int ps_width(), ps_height()
+pointer ps_screen()
+
+begin
+ # Clip rectangle at screen boundary
+
+ maxcol = ps_width ()
+ maxrow = ps_height ()
+ if (! ps_intersect (source, maxrow, maxcol, dest))
+ return
+
+ call smark (sp)
+ ncols = RWIDTH(dest)
+ nrows = RHEIGHT(dest)
+
+ # If the buffer pointer is null,
+ # copy the current screen contents instead
+
+ if (buffer != NULL) {
+ buf = buffer
+ } else {
+ call salloc (buf, nrows*ncols, TY_CHAR)
+
+ ptr = buf
+ scr = ps_screen (RTOP(dest), RLEFT(dest))
+ do irow = 1, nrows {
+ call amovc (Memc[scr], Memc[ptr], ncols)
+ scr = scr + maxcol
+ ptr = ptr + ncols
+ }
+ }
+
+ # See if clearing the screen first would be faster
+ # if so, do it
+
+ clear = ncols == maxcol
+ if (clear)
+ call ps_fill (dest, blank, A_NORM)
+
+ # Copy buffer to screen using ps_wrtcells
+
+ do irow = RTOP(dest), RBOT(dest) {
+ icol = 1
+ jcol = ncols
+
+ # If the screen has been cleared, don't write blanks
+
+ if (clear) {
+ while (icol <= ncols && Memc[buf+icol-1] == blank)
+ icol = icol + 1
+ while (jcol >= icol && Memc[buf+jcol-1] == blank)
+ jcol = jcol - 1
+ }
+
+ if (jcol >= icol) {
+ call ps_wrtcells (irow, RLEFT(dest)+icol-1,
+ Memc[buf+icol-1], jcol-icol+1)
+ }
+
+ buf = buf + ncols
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/refresh.x b/pkg/utilities/nttools/tedit/display/curses/refresh.x
new file mode 100644
index 00000000..b65885d8
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/refresh.x
@@ -0,0 +1,42 @@
+include "../curses.h"
+include "window.h"
+
+# REFRESH -- Bring the terminal screen up to date
+#
+# B.Simon 02-Oct-90 Original
+
+procedure refresh ()
+
+#--
+
+begin
+ call wrefresh (STDSCR)
+end
+
+procedure wrefresh (win)
+
+int win # i: Window descriptor
+#--
+include "window.com"
+
+int rect[RSIZE]
+pointer pwin
+
+begin
+ pwin = warray[win]
+
+ # If the clear flag is set, redraw the contents of the window
+
+ if (WIN_CLEAR(pwin) == YES) {
+ WIN_CLEAR(pwin) = NO
+ call wrect (win, YES, rect)
+ call putscreen (rect, NULL)
+
+ if (WIN_LEAVE(pwin) == NO) {
+ call ps_setcur (WIN_TOP(pwin)+WIN_CURROW(pwin)-1,
+ WIN_LEFT(pwin)+WIN_CURCOL(pwin)-1)
+ }
+ }
+
+ call ps_synch
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/savewin.x b/pkg/utilities/nttools/tedit/display/curses/savewin.x
new file mode 100644
index 00000000..6be4bc72
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/savewin.x
@@ -0,0 +1,23 @@
+include "window.h"
+
+# SAVEWIN -- Save characters under window when a window is created
+#
+# B.Simon 18-Oct-90 Original
+
+procedure savewin ()
+
+#--
+include "window.com"
+
+begin
+ saved = YES
+end
+
+procedure nosavewin ()
+
+#--
+include "window.com"
+
+begin
+ saved = NO
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/scrollok.x b/pkg/utilities/nttools/tedit/display/curses/scrollok.x
new file mode 100644
index 00000000..dfbb3317
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/scrollok.x
@@ -0,0 +1,21 @@
+include "window.h"
+
+# SCROLLOK -- Set the scroll flag for a window
+#
+# B.Simon 02-Oct-90 Original
+
+procedure scrollok (win, flag)
+
+int win # i: Window descriptor
+bool flag # i: Flag value
+#--
+include "window.com"
+
+pointer pwin
+int btoi()
+
+begin
+ pwin = warray[win]
+ WIN_SCROLL(pwin) = btoi (flag)
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/showwin.x b/pkg/utilities/nttools/tedit/display/curses/showwin.x
new file mode 100644
index 00000000..66d4c866
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/showwin.x
@@ -0,0 +1,39 @@
+include "../curses.h"
+include "window.h"
+
+# SHOWWIN -- Show a previously hidden window
+#
+# B.Simon 28-Sep-90 Original
+
+procedure showwin (win)
+
+int win # i: Window descriptor
+#--
+include "window.com"
+
+int rect[RSIZE]
+pointer pwin, buffer
+
+begin
+ pwin = warray[win]
+
+ # Don't do anything if the window is already visible
+
+ if (WIN_HIDDEN(pwin) == NO)
+ return
+
+ # Save the screen under the window in a buffer
+ # and display the window's contents
+
+ call wrect (win, YES, rect)
+ call getscreen (rect, buffer)
+ call putscreen (rect, WIN_BUFFER(pwin))
+
+ # Copy the screen buffer into the window's buffer and
+ # mark the window as visible
+
+ call freescreen (WIN_BUFFER(pwin))
+ WIN_BUFFER(pwin) = buffer
+ WIN_HIDDEN(pwin) = NO
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/standout.x b/pkg/utilities/nttools/tedit/display/curses/standout.x
new file mode 100644
index 00000000..855dab58
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/standout.x
@@ -0,0 +1,48 @@
+include "../curses.h"
+include "window.h"
+
+# STANDOUT -- Put the window in standout mode
+#
+# B.Simon 02-Oct-90 Original
+
+procedure standout ()
+
+#--
+
+begin
+ call wstandout (STDSCR)
+end
+
+procedure wstandout (win)
+
+int win # i: Window descriptor
+#--
+include "window.com"
+
+pointer pwin
+
+begin
+ pwin = warray[win]
+ WIN_ATRIB(pwin) = A_STANDOUT
+end
+
+procedure standend ()
+
+#--
+
+begin
+ call wstandend (STDSCR)
+end
+
+procedure wstandend (win)
+
+int win # i: Window descriptor
+#--
+include "window.com"
+
+pointer pwin
+
+begin
+ pwin = warray[win]
+ WIN_ATRIB(pwin) = A_NORM
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/wdimen.x b/pkg/utilities/nttools/tedit/display/curses/wdimen.x
new file mode 100644
index 00000000..55d5a6cf
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/wdimen.x
@@ -0,0 +1,45 @@
+include "../curses.h"
+include "window.h"
+
+# WDIMEN -- Return dimensions of a window
+#
+# B.Simon 11-Oct-90 Original
+
+procedure wdimen (win, nrows, ncols)
+
+int win # i: Window descriptor
+int nrows # o: Window height
+int ncols # o: Window width
+#--
+int rect[RSIZE]
+
+begin
+ call wrect (win, NO, rect)
+
+ nrows = RHEIGHT(rect)
+ ncols = RWIDTH(rect)
+end
+
+# WRECT -- Get the rectangle containing the window
+
+procedure wrect (win, border, rect)
+
+int win # i: Window descriptor
+int border # i: Include border in dimensions?
+int rect[RSIZE] # o: Rectangle containing window dimensions
+#--
+include "window.com"
+
+pointer pwin
+
+begin
+ pwin = warray[win]
+ if (border == NO || WIN_BOXED(pwin) == NO) {
+ RASG(rect, WIN_TOP(pwin), WIN_LEFT(pwin),
+ WIN_BOT(pwin), WIN_RIGHT(pwin))
+
+ } else {
+ RASG(rect, WIN_TOP(pwin)-1, WIN_LEFT(pwin)-1,
+ WIN_BOT(pwin)+1, WIN_RIGHT(pwin)+1)
+ }
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/window.com b/pkg/utilities/nttools/tedit/display/curses/window.com
new file mode 100644
index 00000000..74b0a38c
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/window.com
@@ -0,0 +1,7 @@
+# WINDOW.COM -- Global variables used by the curses subroutines
+
+int saved # Save rectangle under window when creating
+int echoed # Echo characters
+pointer warray[MAXWIN] # Array holding window descriptors
+
+common /window/ saved, echoed, warray
diff --git a/pkg/utilities/nttools/tedit/display/curses/window.h b/pkg/utilities/nttools/tedit/display/curses/window.h
new file mode 100644
index 00000000..41141580
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/window.h
@@ -0,0 +1,28 @@
+# WINDOW.H -- Window structure definitions and macros
+
+define MAXWIN 50 # Maximum number of windows
+define LEN_WINSTRUCT 15 # Length of window structure
+
+# definition of window structure
+
+define WIN_TOP Memi[$1] # Window's top row
+define WIN_LEFT Memi[$1+1] # Window's leftmost column
+define WIN_BOT Memi[$1+2] # Window's bottom row
+define WIN_RIGHT Memi[$1+3] # Window's rightmost column
+define WIN_CURROW Memi[$1+4] # Cursor row relative to window
+define WIN_CURCOL Memi[$1+5] # Cursor column relative to window
+define WIN_CLEAR Memi[$1+6] # Redraw window when refreshed
+define WIN_LEAVE Memi[$1+7] # Leave cursor after redraw
+define WIN_SCROLL Memi[$1+8] # Window will scroll
+define WIN_HIDDEN Memi[$1+9] # Window is hidden
+define WIN_BOXED Memi[$1+10] # Window is boxed
+define WIN_ATRIB Memi[$1+11] # Character attribute of window
+define WIN_BUFFER Memi[$1+12] # Holds characters under the window
+define WIN_FUNC Memi[$1+13] # Function bound to window
+define WIN_DATA Memi[$1+14] # Data structure bound to window
+
+# Macros used to manipulate rectangle
+
+define WIN_RECT Memi[$1]
+define WIN_WIDTH (WIN_RIGHT($1) - WIN_LEFT($1) + 1)
+define WIN_HEIGHT (WIN_BOT($1) - WIN_TOP($1) + 1)
diff --git a/pkg/utilities/nttools/tedit/display/curses/winstat.x b/pkg/utilities/nttools/tedit/display/curses/winstat.x
new file mode 100644
index 00000000..e89e3ca6
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/winstat.x
@@ -0,0 +1,51 @@
+include "../curses.h"
+include "window.h"
+
+# WINSTAT -- Retrieve a field from a window structure
+
+int procedure winstat (win, what)
+
+int win # i: Window descriptor
+int what # i: Field to retrieve
+#--
+include "window.com"
+
+int value
+pointer pwin
+
+string badcode "Unrecognized argument to winstat"
+
+begin
+ pwin = warray[win]
+
+ switch (what) {
+ case W_TOP:
+ value = WIN_TOP(pwin)
+ case W_LEFT:
+ value = WIN_LEFT(pwin)
+ case W_BOT:
+ value = WIN_BOT(pwin)
+ case W_RIGHT:
+ value = WIN_RIGHT(pwin)
+ case W_CURROW:
+ value = WIN_CURROW(pwin)
+ case W_CURCOL:
+ value = WIN_CURCOL(pwin)
+ case W_CLEAR:
+ value = WIN_CLEAR(pwin)
+ case W_LEAVE:
+ value = WIN_LEAVE(pwin)
+ case W_SCROLL:
+ value = WIN_SCROLL(pwin)
+ case W_HIDDEN:
+ value = WIN_HIDDEN(pwin)
+ case W_BOXED:
+ value = WIN_BOXED(pwin)
+ case W_ATRIB:
+ value = WIN_ATRIB(pwin)
+ default:
+ call error (1, badcode)
+ }
+
+ return (value)
+end
diff --git a/pkg/utilities/nttools/tedit/display/curses/wslide.x b/pkg/utilities/nttools/tedit/display/curses/wslide.x
new file mode 100644
index 00000000..b57f68da
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/curses/wslide.x
@@ -0,0 +1,91 @@
+include "../curses.h"
+
+# WSLIDE -- Slide a window's rectangle on the screen
+#
+# B.Simon 25-Sep-90 Original
+
+procedure wslide (source, dir, dist)
+
+int source[RSIZE] # i: Rectangle
+int dir # i: Direction (from display.h)
+int dist # i: Distance (> 0)
+#--
+int blank, dest[RSIZE], rect[RSIZE]
+int maxcol, maxrow, ncols, irow, icol
+pointer sp, buffer, oldscr
+
+data blank / ' ' /
+
+bool ps_slide(), ps_intersect()
+int ps_width(), ps_height()
+pointer ps_screen()
+
+begin
+ # First try to slide the rectangle with ps_slide
+ # (move by using insert and delete control sequences)
+
+ if (ps_slide (source, dir, dist))
+ return
+
+ # If this doesn't work, redraw the rectangle from
+ # the screen buffer using ps_wrtcells and ps_fill
+
+ # The left and write scrolls must first be written
+ # to a buffer to avoid the problem with array overlap
+ # when updating the screen buffer
+
+ maxcol = ps_width ()
+ maxrow = ps_height ()
+ if (! ps_intersect (source, maxrow, maxcol, dest))
+ return
+
+ call smark(sp)
+ ncols = RWIDTH(dest)
+ call salloc (buffer, ncols+dist, TY_CHAR)
+
+ switch (dir) {
+ case DIR_UP:
+ oldscr = ps_screen (RTOP(dest), RLEFT(dest))
+ do irow = RTOP(dest), RBOT(dest)-dist {
+ call ps_wrtcells (irow-dist, RLEFT(dest), Memc[oldscr], ncols)
+ oldscr = oldscr + maxcol
+ }
+
+ RASG (rect, max(RTOP(dest), RBOT(dest)-dist+1), RLEFT(dest),
+ RBOT(dest), RRIGHT(dest))
+ call ps_fill (rect, blank, A_NORM)
+
+ case DIR_DOWN:
+ oldscr = ps_screen (RBOT(dest), RLEFT(dest))
+ do irow = RBOT(dest), RTOP(dest)+dist, -1 {
+ call ps_wrtcells (irow+dist, RLEFT(dest), Memc[oldscr], ncols)
+ oldscr = oldscr - maxcol
+ }
+
+ RASG (rect, RTOP(dest), RLEFT(dest),
+ min(RBOT(dest), RTOP(dest)+dist-1), RRIGHT(dest))
+ call ps_fill (rect, blank, A_NORM)
+
+ case DIR_LEFT:
+ icol = RLEFT(dest) - dist
+ oldscr = ps_screen (RTOP(dest), RLEFT(dest))
+ do irow = RTOP(dest), RBOT(dest) {
+ call amovc (Memc[oldscr], Memc[buffer], ncols)
+ call amovkc (blank, Memc[buffer+ncols], ncols-dist)
+
+ call ps_wrtcells (irow, icol, Memc[buffer], ncols)
+ oldscr = oldscr + maxcol
+ }
+ case DIR_RIGHT:
+ icol = RLEFT(dest) + dist
+ oldscr = ps_screen (RTOP(dest), RLEFT(dest))
+ do irow = RTOP(dest), RBOT(dest) {
+ call amovc (Memc[oldscr], Memc[buffer], ncols)
+
+ call ps_wrtcells (irow, icol, Memc[buffer], ncols)
+ oldscr = oldscr + maxcol
+ }
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tedit/display/forms/README b/pkg/utilities/nttools/tedit/display/forms/README
new file mode 100644
index 00000000..cd5feeca
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/forms/README
@@ -0,0 +1,115 @@
+The forms procedures give an example of a display handling library
+built on top of the curses routines. The forms procedures divide the
+terminal screen into two windows, the form and prompt window. The
+form window contains the form fields. Each field in the form occupies
+one line on the screen with the field name on the left side of the
+line and the field value on the right side separated by an equals
+sign. If the number of fields in the form exceed the number of lines
+in the form window, a portion of the fields will be displayed, which
+the user can scroll through. The prompt window is used to read user
+input and display messages. The first line contains a message,
+typically used to list the possible commands, and the second line
+contains the user input.
+
+The following two procedures are used to initialize and terminate the
+form handling. The first procedure, fm_begin, calls the keyboard and
+screen initialization routines, and initializes some global variables.
+The second procedure, fm_end, calls the keyboard and screen
+termination routines.
+
+procedure fm_begin ()
+procedure fm_end ()
+
+The next three procedures handle the form window of the screen. The
+first procedure, fm_mkform(), associates a form with a window. The
+second procedure, fm_getform(), gets user input from the form. The
+third procedure, fm_endform(), frees the data structure associated
+with the form.
+
+The first procedure has the following calling sequence:
+
+procedure fm_mkform (win, nfield, lenname, lenvalue, title, ftype, fname)
+
+int win # i: Window descriptor
+int nfield # i: Number of fields in form
+int lenname # i: Declared length of field name
+int lenvalue # i: Declared length of field value
+char title[ARB] # i: Form title
+int ftype[ARB] # i: Data types of fields
+char fname[lenname,ARB] # i: Names of fields
+
+The first argument, win, is the window descriptor. It is created by
+calling newwin(), the curses procedure which creates windows. The next
+three arguments are used to compute the size of the structure which
+holds the form. The number of fields can be greater than the height of
+the window, as the window will scroll up and down. But the combined
+length of the field name and value must be less than the width of the
+window, as it will not scroll side to side. The title is a string that
+is printed on the title bar, which is the bottom row of the form. The
+title bar also contains the help key escape sequence. Three items of
+information are associated with each field: a type, a name, and a
+value. The type is an integer with the same meaning used by the table
+interface: a negative number if the field is a string whose magnitude
+is equal to the maximum string length or a positive integer equal to
+the spp type code if the field is not a string. The type is used to
+check the field value, the procedure will not let the user enter a
+value of a different type. Each field name is printed on a separate
+line of the form followed by an equals sign.
+
+The second procedure, fm_getform, is used to read or display the
+values associated with the fields of the form. It has the following
+calling sequence:
+
+procedure fm_getform (win, redraw, lenvalue, fvalue)
+
+int win # i: Window descriptor
+bool redraw # i: Redraw screen?
+int lenvalue # i: Declared length of field value
+char fvalue[lenvalue,ARB] # u: Values in fields
+
+The first argument is the window descriptor of the window associated
+with the form. If the second argument, redraw is set to true, the
+window is redrawn when the procedure begins, otherwise the window is
+unchanged. Redraw should set to true the first time this procedure is
+called. The last argument, fvalue, contains the values that are
+displayed on the form. The user updates these values by editing the
+form on the screen. When the user has finished updating the values,
+the modified values are returned to the calling procedure.
+
+The third procedure frees the form data structure. After freeing the
+data structure, the window should be closed by calling delwin. This
+procedure has the following calling sequence:
+
+procedure fm_clsform (win)
+
+int win # i: Window descriptor
+
+
+The next procedure, fm_prompt, handles the prompt window on the screen.
+It has the following calling sequence:
+
+int procedure fm_prompt (commands, message)
+
+char commands[ARB] # i: List of commands
+char message[ARB] # i: Message to print in prompt area
+
+The list of commands is a string containing the possible commands. This
+string is formatted like the dictionary in strdic: the first character
+in the string is a command separator which appears between the commands
+in the string. The message is displayed on the top line of the prompt
+area. If the message is a null string, the command string is displayed
+instead. The user enters one of the commands and presses carriage
+return. The procedure returns the number of the command that the user
+entered if the command is legal, or beeps and displays the list of
+commands if it is not. If the list of commands is a null string, the
+procedure displays the message in the prompt area and returns a value
+of zero without looking for user input.
+
+The last procedure displays the help window. This window covers the
+entire screen. Its argument is the currently active window. It is
+passed so that the cursor can be restored to its previous position
+when the procedure is finished.
+
+procedure fm_help (win)
+
+int win # i: Window which currently is active
diff --git a/pkg/utilities/nttools/tedit/display/forms/fmbegin.x b/pkg/utilities/nttools/tedit/display/forms/fmbegin.x
new file mode 100644
index 00000000..8cf78aba
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/forms/fmbegin.x
@@ -0,0 +1,20 @@
+# FM_BEGIN -- Initialize form handler
+#
+# B.Simon 25-Jan-88 Original
+# B.Simon 11-Oct-90 Rewritten to use curses
+
+procedure fm_begin ()
+
+#--
+include "forms.com"
+
+begin
+ # Initialize curses
+
+ call initscr
+
+ # Initialize global variables
+
+ helpwin = 0
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/forms/fmcheck.x b/pkg/utilities/nttools/tedit/display/forms/fmcheck.x
new file mode 100644
index 00000000..d7fa95d4
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/forms/fmcheck.x
@@ -0,0 +1,98 @@
+include <lexnum.h>
+include <ctype.h>
+include <mach.h>
+
+# FM_CHECK -- Check a string against a data type
+#
+# B.Simon 28-Mar-91 Modified to check INDEF correctly
+
+bool procedure fm_check (datatype, str)
+
+int datatype # i: Datatype to check
+char str[ARB] # i: String to be checked
+#--
+bool match
+double strval
+int ic, nc, lextype, strtype
+pointer sp, temp
+
+string yorn "|yes|no|"
+
+bool streq()
+int strlen(), lexnum(), ctod(), strdic()
+
+begin
+ # Don't check null strings
+
+ if (str[1] == EOS)
+ return (true)
+
+ call smark (sp)
+ call salloc (temp, SZ_LINE, TY_CHAR)
+
+ if (datatype < 0)
+
+ # The only check on string types is that they not exceed their
+ # maximum length
+
+ match = strlen (str) <= -(datatype)
+
+ else {
+
+ # Get the data type of the string
+ # Reduce this to character, integer or real
+ # Get the value of the string if it is not character
+
+ if (streq (str, "INDEF")) {
+ strtype = datatype
+ strval = 0.0
+
+ } else {
+ ic = 1
+ lextype = lexnum (str, ic, nc)
+
+ for (ic = ic + nc; IS_WHITE(str[ic]); ic = ic + 1)
+ ;
+ if (str[ic] != EOS)
+ lextype = LEX_NONNUM
+
+ if (lextype == LEX_HEX || lextype == LEX_NONNUM) {
+ strtype = TY_CHAR
+ strval = 0.0
+ } else {
+ if (lextype == LEX_REAL)
+ strtype = TY_REAL
+ else
+ strtype = TY_INT
+
+ ic = 1
+ nc = ctod (str, ic, strval)
+ strval = abs (strval)
+ }
+ }
+
+ # See if the string matches the expected datatype
+
+ switch (datatype) {
+ case TY_BOOL:
+ match = strdic (str, Memc[temp], SZ_LINE, yorn) > 0
+ case TY_CHAR:
+ match = strlen (str) <= 1
+ case TY_SHORT:
+ match = strtype == TY_INT && strval <= MAX_SHORT
+ case TY_INT:
+ match = strtype == TY_INT && strval <= MAX_INT
+ case TY_LONG:
+ match = strtype == TY_INT && strval <= MAX_LONG
+ case TY_REAL:
+ match = strtype != TY_CHAR && strval <= MAX_REAL
+ case TY_DOUBLE:
+ match = strtype != TY_CHAR && strval <= MAX_DOUBLE
+ default:
+ match = true
+ }
+ }
+
+ call sfree (sp)
+ return (match)
+end
diff --git a/pkg/utilities/nttools/tedit/display/forms/fmend.x b/pkg/utilities/nttools/tedit/display/forms/fmend.x
new file mode 100644
index 00000000..353ebfe0
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/forms/fmend.x
@@ -0,0 +1,12 @@
+# FM_END -- Terminate form handler
+#
+# B.Simon 25-Jan-89 Original
+# B.Simon 11-Oct-90 Rewritten to use curses
+
+procedure fm_end ()
+
+#--
+
+begin
+ call endwin
+end
diff --git a/pkg/utilities/nttools/tedit/display/forms/fmgetform.x b/pkg/utilities/nttools/tedit/display/forms/fmgetform.x
new file mode 100644
index 00000000..ebc6d143
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/forms/fmgetform.x
@@ -0,0 +1,89 @@
+include "../curses.h"
+include "formfn.h"
+
+# FM_GETFORM -- Get user input from a form
+#
+# B.Simon 27-Jan-89 Original
+# B.Simon 12-Dec-90 Rewritten to use curses
+
+procedure fm_getform (win, redraw, lenvalue, fvalue)
+
+int win # i: Window descriptor
+bool redraw # i: Redraw screen?
+int lenvalue # i: Declared length of field value
+char fvalue[lenvalue,ARB] # u: Values in fields
+#--
+bool draw
+int ifield, curfield, topfield, botfield, ch
+pointer data, value
+
+bool fm_check()
+int k_get()
+
+begin
+ # Get pointer to form data structure
+
+ call wgetstruct (win, data)
+
+ # Initialize data structure
+
+ FM_FIELD(data) = 1
+ FM_CHANGE(data) = NO
+
+ # Copy values to data structure
+
+ value = FM_VALARY(data)
+ do ifield = 1, FM_NFIELD(data) {
+ call strcpy (fvalue[1,ifield], Memc[value], lenvalue)
+ value = value + FM_LENVAL(data) + 1
+ }
+
+ # Let user update form
+
+ draw = redraw
+
+ curfield = 1
+ topfield = 1
+ botfield = min (FM_NFIELD(data), topfield + FM_NPAGE(data) - 1)
+
+ repeat {
+
+ # Redraw form and move cursor
+
+ if (draw) {
+ topfield = max (1, curfield - FM_NPAGE(data) / 2)
+ botfield = min (FM_NFIELD(data), topfield + FM_NPAGE(data) - 1)
+ call fm_redraw (win, topfield)
+ }
+
+ call wmove (win, curfield-topfield+1, FM_LENNAM(data)+4)
+
+ value = FM_VALPTR(data,curfield)
+ call weditstr (win, Memc[value], FM_LENVAL(data))
+
+ ch = k_get ()
+
+ if (FM_CHANGE(data) == YES) {
+ if (! fm_check (FM_TYPE(data,curfield),
+ Memc[FM_VALPTR(data,curfield)])) {
+ call ps_beep
+ ch = EOS
+ next
+ }
+ }
+
+ curfield = FM_FIELD(data)
+ FM_CHANGE(data) = NO
+ draw = curfield < topfield || curfield > botfield
+
+ } until (ch == K_EXIT)
+
+ # Copy form values to output array
+
+ value = FM_VALARY(data)
+ do ifield = 1, FM_NFIELD(data) {
+ call strcpy (Memc[value], fvalue[1,ifield], lenvalue)
+ value = value + FM_LENVAL(data) + 1
+ }
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/forms/fmhelp.x b/pkg/utilities/nttools/tedit/display/forms/fmhelp.x
new file mode 100644
index 00000000..8615c031
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/forms/fmhelp.x
@@ -0,0 +1,132 @@
+include "../curses.h"
+
+define COLWIDTH 40
+define LABEL_FLAG 1
+define NAME_FLAG 2
+
+# FM_HELP -- Display help window for function key sequences
+
+procedure fm_help (win)
+
+int win # i: Window which currently is active
+#--
+include "forms.com"
+
+int key, row, col
+int k_get(), winstat()
+
+begin
+ # If the help screen was created on a previous call,
+ # display it, otherwise make a new help screen
+
+ if (helpwin != 0) {
+ call showwin (helpwin)
+ } else {
+ call fm_hmake (helpwin)
+ }
+
+ # Display help screen and wait for keystroke to hide window
+
+ call refresh
+ key = k_get ()
+
+ # Hide the help window and restore cursor to current window
+
+ call hidewin (helpwin)
+
+ row = winstat (win, W_CURROW)
+ col = winstat (win, W_CURCOL)
+ call wmove (win, row, col)
+
+end
+
+procedure fm_hmake (hwin)
+
+pointer hwin # o: help window
+#--
+int ic, nrows, ncols, irow, icol, flag
+pointer sp, label, name, hline, text, ch
+
+string htitle "Editing Commands"
+string hfooter "(Press any key to continue)"
+string hformat "%4w%-12.12s = %-12.12s"
+
+int newwin(), strlen()
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (label, COLWIDTH, TY_CHAR)
+ call salloc (name, COLWIDTH, TY_CHAR)
+ call salloc (hline, COLWIDTH, TY_CHAR)
+
+ # Create help message
+
+ hwin = newwin (GIANT, GIANT, 1, 1)
+
+ # Write help screen title
+
+ call wdimen (hwin, nrows, ncols)
+ icol = (ncols - strlen(htitle)) / 2
+ call wmove (hwin, 1, icol)
+ call wstandout (hwin)
+ call waddstr (hwin, htitle)
+ call wstandend (hwin)
+
+ ic = 0
+ icol = 0
+ irow = 3
+ flag = LABEL_FLAG
+ call k_help (text)
+
+ # Write each (label=name) pair to the help screen
+
+ for (ch = text; Memc[ch] != EOS; ch = ch + 1) {
+ switch (flag) {
+ case LABEL_FLAG:
+ if (Memc[ch] != '=') {
+ Memc[label+ic] = Memc[ch]
+ ic = ic + 1
+ } else {
+ Memc[label+ic] = EOS
+ flag = NAME_FLAG
+ ic = 0
+ }
+ case NAME_FLAG:
+ if (Memc[ch] != '\n') {
+ Memc[name+ic] = Memc[ch]
+ ic = ic + 1
+ } else {
+ Memc[name+ic] = EOS
+ flag = LABEL_FLAG
+ ic = 0
+
+ # Reformat label/name pair for window
+
+ call sprintf (Memc[hline], COLWIDTH, hformat)
+ call pargstr (Memc[label])
+ call pargstr (Memc[name])
+
+ # Write string to window
+
+ call wmove (hwin, irow, icol * COLWIDTH + 1)
+ call waddstr (hwin, Memc[hline])
+
+ # Calculate next string position
+
+ icol = icol + 1
+ if (icol == 2) {
+ icol = 0
+ irow = irow + 1
+ }
+ }
+ }
+ }
+
+ # Write help screen footer
+
+ call wmove (hwin, nrows, 1)
+ call waddstr (hwin, hfooter)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tedit/display/forms/fmmkform.x b/pkg/utilities/nttools/tedit/display/forms/fmmkform.x
new file mode 100644
index 00000000..00bc8106
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/forms/fmmkform.x
@@ -0,0 +1,82 @@
+include "formfn.h"
+
+# FM_MKFORM -- Create a form and bind it to a window
+#
+# B.Simon 27-Jan-89 Original
+# B.Simon 15-Oct-90 Rewritten to use curses
+
+procedure fm_mkform (win, nfield, lenname, lenvalue, title, ftype, fname)
+
+int win # i: Window descriptor
+int nfield # i: Number of fields in form
+int lenname # i: Declared length of field name
+int lenvalue # i: Declared length of field value
+char title[ARB] # i: Form title
+int ftype[ARB] # i: Data types of fields
+char fname[lenname,ARB] # i: Names of fields
+#--
+extern formfn
+int nrows, ncols, ifield
+pointer data, name, value, type
+
+begin
+ # Get the dimensions of the form
+
+ call wdimen (win, nrows, ncols)
+
+ # Allocate data structure
+
+ call malloc (data, LEN_FMSTRUCT, TY_STRUCT)
+ call malloc (FM_NAMARY(data), (lenname+1)*nfield, TY_CHAR)
+ call malloc (FM_VALARY(data), (lenvalue+1)*nfield, TY_CHAR)
+ call malloc (FM_TTLPTR(data), SZ_LINE, TY_CHAR)
+ call malloc (FM_TYPARY(data), nfield, TY_INT)
+
+ # Initialize data structure
+
+ FM_FIELD(data) = 1
+ FM_NFIELD(data) = nfield
+ FM_NPAGE(data) = nrows - 1
+ FM_CHANGE(data) = NO
+ FM_LENNAM(data) = lenname
+ FM_LENVAL(data) = lenvalue
+ call strcpy (title, FM_TITLE(data), SZ_LINE)
+
+ name = FM_NAMARY(data)
+ value = FM_VALARY(data)
+ type = FM_TYPARY(data)
+
+ do ifield = 1, nfield {
+ call strcpy(fname[1,ifield], Memc[name], lenname)
+ name = name + lenname + 1
+ Memc[value] = EOS
+ value = value + lenvalue + 1
+ Memi[type] = ftype[ifield]
+ type = type + 1
+ }
+
+ # Bind data structure and function to window
+
+ call wbindstruct (win, formfn, data)
+
+end
+
+procedure fm_clsform (win)
+
+int win # i: Window descriptor
+#--
+pointer data
+
+begin
+ # Get the structure pointer
+
+ call wgetstruct (win, data)
+
+ # Free the substructures hanging off the main structure
+
+ call mfree (FM_NAMARY(data), TY_CHAR)
+ call mfree (FM_VALARY(data), TY_CHAR)
+ call mfree (FM_TTLPTR(data), TY_CHAR)
+ call mfree (FM_TYPARY(data), TY_INT)
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/forms/fmprompt.x b/pkg/utilities/nttools/tedit/display/forms/fmprompt.x
new file mode 100644
index 00000000..b93ef450
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/forms/fmprompt.x
@@ -0,0 +1,70 @@
+# FM_PROMPT -- Get user input from a prompt window
+#
+# B.Simon 30-Jan-89 Original
+# B.Simon 12-Dec-90 Rewritten to use curses
+
+int procedure fm_prompt (win, commands, message)
+
+int win # i: Prompt window
+char commands[ARB] # i: List of commands
+char message[ARB] # i: Message to print in prompt area
+#--
+char newline
+int option
+pointer sp, response, temp
+
+data newline / '\n' /
+
+int strdic()
+
+begin
+ # Print the message in the window
+
+ call werase (win)
+ call wmove (win, 1, 1)
+ if (message[1] == EOS) {
+ call waddstr (win, commands)
+ call waddch (win, newline)
+ } else {
+ call waddstr (win, message)
+ call waddch (win, newline)
+ }
+
+ # Return if no user response is needed
+
+ if (commands[1] == EOS) {
+ call wrefresh (win)
+ return (0)
+ }
+
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (response, SZ_LINE, TY_CHAR)
+ call salloc (temp, SZ_LINE, TY_CHAR)
+
+ # Get the user response
+
+ repeat {
+ call wgetstr (win, Memc[response], SZ_LINE)
+
+ # Check response against list of commands
+
+ option = strdic (Memc[response], Memc[temp], SZ_LINE, commands)
+ if (option > 0)
+ break
+
+ # Try again if response was not valid
+
+ call werase (win)
+ call wmove (win, 1, 1)
+ call waddstr (win , commands)
+ call waddch (win, newline)
+ call ps_beep
+ }
+
+ # Return the option number
+
+ call sfree (sp)
+ return (option)
+end
diff --git a/pkg/utilities/nttools/tedit/display/forms/fmredraw.x b/pkg/utilities/nttools/tedit/display/forms/fmredraw.x
new file mode 100644
index 00000000..71e5b781
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/forms/fmredraw.x
@@ -0,0 +1,69 @@
+include "formfn.h"
+define SZ_ESCSEQ 20
+
+# FM_REDRAW -- Redraw the form
+
+procedure fm_redraw (win, topfield)
+
+int win # i: Window descriptor
+int topfield # i: Top field on the form to draw
+#--
+int nrows, ncols, botfield, ifield
+pointer sp, field, footer, escseq, data, name, value
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (field, SZ_LINE, TY_CHAR)
+ call salloc (footer, SZ_LINE, TY_CHAR)
+ call salloc (escseq, SZ_ESCSEQ, TY_CHAR)
+
+ # Get form data structure
+
+ call wgetstruct (win, data)
+
+ # Get the dimensions of the form
+
+ call wdimen (win, nrows, ncols)
+
+ # Clear screen
+
+ call werase (win)
+
+ # Write the form
+
+ name = FM_NAMPTR(data,topfield)
+ value = FM_VALPTR(data,topfield)
+ botfield = min (FM_NFIELD(data), topfield + FM_NPAGE(data) - 1)
+
+ call wmove (win, 1, 1)
+ do ifield = topfield, botfield {
+ call sprintf (Memc[field], SZ_LINE, "%*s = %s\n")
+ call pargi (FM_LENNAM(data))
+ call pargstr (Memc[name])
+ call pargstr (Memc[value])
+
+ call waddstr (win, Memc[field])
+
+ name = name + FM_LENNAM(data) + 1
+ value = value + FM_LENVAL(data) + 1
+ }
+
+ # Write the footer line
+
+ call k_eseq ("GET_HELP", Memc[escseq], SZ_ESCSEQ)
+
+ call sprintf (Memc[footer], ncols, "%4w%s%*tHelp: %s%*t")
+ call pargstr (FM_TITLE(data))
+ call pargi (ncols-SZ_ESCSEQ)
+ call pargstr (Memc[escseq])
+ call pargi (ncols+1)
+
+ call wmove (win, nrows, 1)
+ call wstandout (win)
+ call waddstr (win, Memc[footer])
+ call wstandend (win)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tedit/display/forms/formfn.h b/pkg/utilities/nttools/tedit/display/forms/formfn.h
new file mode 100644
index 00000000..b3afbc75
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/forms/formfn.h
@@ -0,0 +1,20 @@
+# FORMFN.H -- Data structure used by formfn()
+
+define LEN_FMSTRUCT 10
+
+define FM_FIELD Memi[$1] # Current field
+define FM_NFIELD Memi[$1+1] # Number of fields on form
+define FM_NPAGE Memi[$1+2] # Number of fields in window
+define FM_CHANGE Memi[$1+3] # Has field been changed ?
+define FM_LENNAM Memi[$1+4] # Length of name field
+define FM_LENVAL Memi[$1+5] # Length of value field
+define FM_NAMARY Memi[$1+6] # Array of field names
+define FM_VALARY Memi[$1+7] # Array of field values
+define FM_TTLPTR Memi[$1+8] # Title array
+define FM_TYPARY Memi[$1+9] # Array of field types
+
+define FM_NAMPTR FM_NAMARY($1)+(($2)-1)*(FM_LENNAM($1)+1)
+define FM_VALPTR FM_VALARY($1)+(($2)-1)*(FM_LENVAL($1)+1)
+
+define FM_TITLE Memc[FM_TTLPTR($1)]
+define FM_TYPE Memi[FM_TYPARY($1)+($2)-1]
diff --git a/pkg/utilities/nttools/tedit/display/forms/formfn.x b/pkg/utilities/nttools/tedit/display/forms/formfn.x
new file mode 100644
index 00000000..b060a87c
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/forms/formfn.x
@@ -0,0 +1,278 @@
+include <ctype.h>
+include "../curses.h"
+include "formfn.h"
+
+# FORMFN -- Function that processes form input
+#
+# B.Simon 12-Dec-90 Original
+
+procedure formfn (win, str, maxch)
+
+int win # i: Window descriptor
+char str[ARB] # u: String containing line
+int maxch # i: Maximum line length
+#--
+int row, col, ch, ic, jc, mc, nc
+pointer sp, data, buffer
+
+int strlen(), k_get(), winstat()
+
+begin
+ ic = 0
+ nc = strlen (str)
+
+ call wgetstruct (win, data)
+ row = winstat (win, W_CURROW)
+ col = winstat (win, W_CURCOL)
+
+ call smark (sp)
+ call salloc (buffer, SZ_LINE, TY_CHAR)
+ Memc[buffer] = EOS
+
+ while (nc < maxch) {
+
+ # Read character from keyboard
+
+ call ps_synch
+ ch = k_get ()
+
+ # Check for carriage return
+
+ if (ch == '\r') {
+ if (FM_FIELD(data) < FM_NFIELD(data)) {
+ FM_FIELD(data) = FM_FIELD(data) + 1
+ break
+ }
+ }
+
+ if (IS_PRINT(ch)) {
+ ic = ic + 1
+ nc = nc + 1
+ FM_CHANGE(data) = YES
+
+ if (ic == nc) {
+ str[ic] = ch
+ str[ic+1] = EOS
+ call waddstr (win, str[ic])
+
+ } else {
+ do jc = nc-1, ic, -1
+ str[jc+1] = str[jc]
+
+ str[ic] = ch
+ call winsch (win, str[ic])
+ }
+
+ } else {
+ switch (ch) {
+ case K_UP: # Move up one field
+ if (FM_FIELD(data) > 1) {
+ FM_FIELD(data) = FM_FIELD(data) - 1
+ break
+ }
+
+ case K_DOWN: # Move down one field
+ if (FM_FIELD(data) < FM_NFIELD(data)) {
+ FM_FIELD(data) = FM_FIELD(data) + 1
+ break
+ }
+
+ case K_RIGHT: # Move right one column
+ if (ic < nc) {
+ ic = ic + 1
+ call wmove (win, row, col+ic)
+ }
+
+ case K_LEFT: # Move left one column
+ if (ic > 0) {
+ ic = ic - 1
+ call wmove (win, row, col+ic)
+ }
+
+ case K_NEXTW: # Move forwards one word
+ call mvword_next (str, ic, jc)
+
+ if (jc > ic) {
+ ic = jc
+ call wmove (win, row, col+ic)
+ }
+
+
+ case K_PREVW: # Move backwards one word
+ call mvword_prev (str, ic, jc)
+
+ if (jc < ic) {
+ ic = jc
+ call wmove (win, row, col+ic)
+ }
+
+
+ case K_NEXTP: # Move forwards one screen
+ if (FM_FIELD(data) < FM_NFIELD(data)) {
+ FM_FIELD(data) = min (FM_FIELD(data) + FM_NPAGE(data),
+ FM_NFIELD(data))
+ break
+ }
+
+ case K_PREVP: # Move backwards one screen
+ if (FM_FIELD(data) > 1) {
+ FM_FIELD(data) = max (FM_FIELD(data) - FM_NPAGE(data),
+ 1)
+ break
+ }
+
+ case K_HOME: # Move to first field
+ if (FM_FIELD(data) > 1) {
+ FM_FIELD(data) = 1
+ break
+ }
+
+ case K_END: # Move to last field
+ if (FM_FIELD(data) < FM_NFIELD(data)) {
+ FM_FIELD(data) = FM_NFIELD(data)
+ break
+ }
+
+ case K_BOL: # Move to first column in line
+ if (ic > 0) {
+ ic = 0
+ call wmove (win, row, col)
+ }
+
+ case K_EOL: # Move to last column in line
+ if (ic < nc) {
+ ic = nc
+ call wmove (win, row, col+ic)
+ }
+
+ case K_DEL: # Delete character underneath cursor
+ if (ic < nc) {
+ FM_CHANGE(data) = YES
+ mc = strlen (Memc[buffer])
+
+ Memc[buffer+mc] = str[ic+1]
+ Memc[buffer+mc+1] = EOS
+
+ call amovc (str[ic+2], str[ic+1], nc-ic)
+
+ call wdelch (win)
+ nc = nc - 1
+ }
+
+ case K_BS: # Delete character to left of cursor
+ if (ic > 0) {
+ FM_CHANGE(data) = YES
+ mc = strlen (Memc[buffer])
+
+ call amovc (Memc[buffer], Memc[buffer+1], mc+1)
+ Memc[buffer] = str[ic]
+
+ ic = ic - 1
+ call amovc (str[ic+2], str[ic+1], nc-ic)
+
+ call wmove (win, row, col+ic)
+ call wdelch (win)
+ nc = nc - 1
+ }
+
+ case K_DWORD: # Delete one word
+ call mvword_next (str, ic, jc)
+
+ if (jc > ic) {
+ FM_CHANGE(data) = YES
+ mc = strlen (Memc[buffer])
+
+ call strcpy (str[ic+1], Memc[buffer+mc], jc-ic)
+ call amovc (str[jc+1], str[ic+1], nc-jc+1)
+
+ call wclrtoeol (win)
+ call waddstr (win, str[ic+1])
+ call wmove (win, row, col+ic)
+ nc = nc - (jc - ic)
+ }
+
+ case K_DLINE: # Delete entire line
+ if (nc > 0) {
+ FM_CHANGE(data) = YES
+
+ call strcpy (str[ic+1], Memc[buffer], nc-ic)
+ str[ic+1] = EOS
+
+ call wclrtoeol (win)
+ nc = ic
+ }
+
+ case K_UNDCHR: # Undelete a character
+ mc = strlen (Memc[buffer])
+ if (mc > 0) {
+ call amovc (str[ic+1], str[ic+2], nc-ic+1)
+ str[ic+1] = Memc[buffer+mc-1]
+
+ Memc[buffer+mc-1] = EOS
+ call winsch (win, str[ic+1])
+
+ ic = ic + 1
+ nc = nc + 1
+ }
+
+ case K_UNDWRD: # Undelete a word
+ mc = strlen (Memc[buffer])
+ call mvword_prev (Memc[buffer], mc, jc)
+
+ mc = mc - jc
+ if (mc > 0) {
+ call amovc (str[ic+1], str[ic+mc+1], nc-ic+1)
+ call amovc (Memc[buffer+jc], str[ic+1], mc)
+
+ Memc[buffer+jc] = EOS
+ call wclrtoeol (win)
+ call waddstr (win, str[ic+1])
+
+ ic = ic + mc
+ nc = nc + mc
+ call wmove (win, row, col+ic)
+ }
+
+ case K_UNDLIN: # Undelete a line
+ mc = strlen (Memc[buffer])
+ if (mc > 0) {
+ call amovc (str[ic+1], str[ic+mc+1], nc-ic+1)
+ call amovc (Memc[buffer], str[ic+1], mc)
+
+ Memc[buffer] = EOS
+ call wclrtoeol (win)
+ call waddstr (win, str[ic+1])
+
+ ic = ic + mc
+ nc = nc + mc
+ call wmove (win, row, col+ic)
+ }
+
+ case K_HELP: # Display help screen
+ call fm_help (win)
+
+ case K_PAINT: # Redraw the screen
+ call clearok (STDSCR, true)
+ call wrefresh (STDSCR)
+ call wmove (win, row, col+ic)
+
+ case K_EXIT: # Exit procedure
+ break
+
+ default: # Any other character
+ call ps_beep
+ }
+ }
+ }
+
+ # Terminate string with EOS and push back character
+ # that terminated input
+
+ if (nc >= maxch)
+ ch = EOS
+
+ str[nc+1] = EOS
+ call k_pushbk (ch)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tedit/display/forms/forms.com b/pkg/utilities/nttools/tedit/display/forms/forms.com
new file mode 100644
index 00000000..2e948a0c
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/forms/forms.com
@@ -0,0 +1,5 @@
+# FORMS.COM -- Global variables used by forms procedures
+
+int helpwin # Function key help window
+
+common /form/ helpwin
diff --git a/pkg/utilities/nttools/tedit/display/forms/linefn.h b/pkg/utilities/nttools/tedit/display/forms/linefn.h
new file mode 100644
index 00000000..c263dfce
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/forms/linefn.h
@@ -0,0 +1,8 @@
+# LINEFN.H -- Data structure associated with linefn()
+
+define LEN_LINSTRUCT 4
+
+define LIN_ROW Memi[$1] # Cursor row
+define LIN_COL Memi[$1+1] # Cursor column
+define LIN_ICHAR Memi[$1+2] # Index to current character
+define LIN_LAST Memi[$1+3] # Character which caused return
diff --git a/pkg/utilities/nttools/tedit/display/forms/linefn.x b/pkg/utilities/nttools/tedit/display/forms/linefn.x
new file mode 100644
index 00000000..c122795a
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/forms/linefn.x
@@ -0,0 +1,134 @@
+include "../curses.h"
+include "linefn.h"
+
+# LINEFN -- Function that processes a line of input in a window
+
+procedure linefn (win, ch, maxch, str, data, done)
+
+int win # i: Window descriptor
+int ch # i: Keyboard character
+int maxch # i: Maximum line length
+char str[ARB] # io: String containing line
+pointer data # io: Line data structure
+bool done # o: Flag indicating line is done
+#--
+int ic, jc, nc
+int strlen()
+
+begin
+ done = false
+ if (LIN_ROW(data) == 0 || LIN_COL(data) == 0)
+ call getyx (win, LIN_ROW(data), LIN_COL(data))
+
+ if (ch < K_BASE) {
+ LIN_ICHAR(data) = LIN_ICHAR(data) + 1
+ LIN_COL(data) = LIN_COL(data) + 1
+ ic = LIN_ICHAR(data)
+
+ if (str[ic] == EOS) {
+ if (ic > maxch) {
+ done = true
+ LIN_LAST(data) = EOS
+ } else {
+ str[ic] = ch
+ str[ic+1] = EOS
+ call waddstr (win, str[ic])
+ }
+ } else {
+ nc = strlen (str)
+ if (nc >= maxch) {
+ done = true
+ LIN_LAST(data) = EOS
+ } else {
+ do jc = nc+1, ic, -1
+ str[jc+1] = str[jc]
+
+ str[ic] = ch
+ call winsch (win, str[ic])
+ }
+ }
+
+ if (ch == '\r') {
+ done = true
+ LIN_LAST(data) = '\n'
+ }
+
+ } else {
+ ic = LIN_ICHAR(data)
+ switch (ch) {
+ case K_RIGHT: # Move right one column
+ if (str[ic] == EOS) {
+ done = true
+ LIN_LAST(data) = EOS
+ } else {
+ LIN_ICHAR(data) = LIN_ICHAR(data) + 1
+ LIN_COL(data) = LIN_COL(data) + 1
+ call wmove (win, LIN_ROW(data), LIN_COL(data))
+ }
+
+ case K_LEFT: # Move left one column
+ if (ic == 1) {
+ done = true
+ LIN_LAST(data) = EOS
+ } else {
+ LIN_ICHAR(data) = LIN_ICHAR(data) - 1
+ LIN_COL(data) = LIN_COL(data) - 1
+ call wmove (win, LIN_ROW(data), LIN_COL(data))
+ }
+
+ case K_BOL: # Move to first column in line
+ if (ic > 1) {
+ LIN_ICHAR(data) = 1
+ LIN_COL(data) = LIN_COL(data) - ic + 1
+ call wmove (win, LIN_ROW(data), LIN_COL(data))
+ }
+
+ case K_EOL: # Move to last column in line
+ if (str[ic] != EOS) {
+ LIN_ICHAR(data) = strlen (str) + 1
+ LIN_COL(data) = LIN_COL(data) + LIN_ICHAR(data) - ic
+ call wmove (win, LIN_ROW(data), LIN_COL(data))
+ }
+
+ case K_DEL: # Delete character underneath cursor
+ if (str[ic] != EOS) {
+ while (str[ic] != EOS) {
+ str[ic] = str[ic+1]
+ ic = ic + 1
+ }
+
+ call wdelch (win)
+ }
+
+ case K_BS: # Delete character to left of cursor
+ if (ic > 1) {
+ LIN_ICHAR(data) = LIN_ICHAR(data) - 1
+ LIN_COL(data) = LIN_COL(data) - 1
+
+ ic = ic - 1
+ while (str[ic] != EOS) {
+ str[ic] = str[ic+1]
+ ic = ic + 1
+ }
+
+ call wmove (win, LIN_ROW(data), LIN_COL(data))
+ call wdelch (win)
+ }
+
+ case K_DWORD: # Delete entire line
+ if (str[1] != EOS) {
+ LIN_ICHAR(data) = 1
+ LIN_COL(data) = LIN_COL(data) - ic + 1
+
+ for (ic = 1; str[ic] != EOS; ic = ic + 1)
+ str[ic] = ' '
+ call addstr (win, str)
+ str[1] = EOS
+ }
+
+ default:
+ done = true
+ LIN_LAST(data) = ch
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/tedit/display/forms/mkpkg b/pkg/utilities/nttools/tedit/display/forms/mkpkg
new file mode 100644
index 00000000..e23071d5
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/forms/mkpkg
@@ -0,0 +1,19 @@
+# Update the display library.
+# Author: B.Simon 01-APR-91
+
+$checkout libpkg.a ../../
+$update libpkg.a
+$checkin libpkg.a ../../
+$exit
+
+libpkg.a:
+ fmbegin.x "forms.com"
+ fmcheck.x <lexnum.h> <ctype.h> <mach.h>
+ fmend.x
+ fmhelp.x "../curses.h" "forms.com"
+ fmgetform.x "formfn.h"
+ fmmkform.x "formfn.h"
+ fmprompt.x
+ fmredraw.x "formfn.h"
+ formfn.x "../curses.h" "formfn.h"
+ ;
diff --git a/pkg/utilities/nttools/tedit/display/forms/promptfn.h b/pkg/utilities/nttools/tedit/display/forms/promptfn.h
new file mode 100644
index 00000000..48aba6b4
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/forms/promptfn.h
@@ -0,0 +1,7 @@
+# PROMPTFN.H -- Data structure associated with promptfn()
+
+define LEN_PRSTRUCT 3
+
+define PR_START Memi[$1] # Start flag
+define PR_ROW Memi[$1+1] # Cursor row
+define PR_COL Memi[$1+2] # Cursor column
diff --git a/pkg/utilities/nttools/tedit/display/forms/promptfn.x b/pkg/utilities/nttools/tedit/display/forms/promptfn.x
new file mode 100644
index 00000000..c270aabb
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/forms/promptfn.x
@@ -0,0 +1,134 @@
+include "../curses.h"
+include "promptfn.h"
+
+# PROMPTFN -- Function that processes the prompt input
+
+procedure promptfn (win, ch, maxch, str, data, done)
+
+int win # i: Window descriptor
+int ch # i: Keyboard character
+int maxch # i: Maximum line length
+char str[ARB] # io: String containing line
+pointer data # io: Line data structure
+bool done # o: Flag indicating line is done
+#--
+int nrows, ncols, ic, jc, nc
+int strlen()
+
+begin
+ # Check for carriage return
+
+ if (ch == '\r') {
+ done = true
+ return
+ } else {
+ done = false
+ }
+
+ # Initialize data structure on first pass through
+
+ if (PR_START(data) == YES) {
+ call wdimen (win, nrows, ncols)
+ if (nrows == 1)
+ call werase (win)
+
+ PR_START(data) = NO
+ PR_ROW(data) = min (2, nrows)
+ PR_COL(data) = 1
+ }
+
+ if (ch < K_BASE) {
+ ic = PR_COL(data)
+
+ if (str[ic] == EOS) {
+ if (ic <= maxch) {
+ str[ic] = ch
+ str[ic+1] = EOS
+ call waddstr (win, str[ic])
+ }
+ } else {
+ nc = strlen (str)
+ if (nc < maxch) {
+ do jc = nc+1, ic, -1
+ str[jc+1] = str[jc]
+
+ str[ic] = ch
+ call winsch (win, str[ic])
+ }
+ }
+ PR_COL(data) = PR_COL(data) + 1
+
+ } else {
+ ic = PR_COL(data)
+ switch (ch) {
+ case K_RIGHT: # Move right one column
+ if (str[ic] != EOS) {
+ PR_COL(data) = PR_COL(data) + 1
+ call wmove (win, PR_ROW(data), PR_COL(data))
+ }
+
+ case K_LEFT: # Move left one column
+ if (ic != 1) {
+ PR_COL(data) = PR_COL(data) - 1
+ call wmove (win, PR_ROW(data), PR_COL(data))
+ }
+
+ case K_BOL: # Move to first column in line
+ if (ic > 1) {
+ PR_COL(data) = 1
+ call wmove (win, PR_ROW(data), PR_COL(data))
+ }
+
+ case K_EOL: # Move to last column in line
+ if (str[ic] != EOS) {
+ PR_COL(data) = strlen (str) + 1
+ call wmove (win, PR_ROW(data), PR_COL(data))
+ }
+
+ case K_DEL: # Delete character underneath cursor
+ if (str[ic] != EOS) {
+ while (str[ic] != EOS) {
+ str[ic] = str[ic+1]
+ ic = ic + 1
+ }
+
+ call wdelch (win)
+ }
+
+ case K_BS: # Delete character to left of cursor
+ if (ic > 1) {
+ PR_COL(data) = PR_COL(data) - 1
+
+ ic = ic - 1
+ while (str[ic] != EOS) {
+ str[ic] = str[ic+1]
+ ic = ic + 1
+ }
+
+ call wmove (win, PR_ROW(data), PR_COL(data))
+ call wdelch (win)
+ }
+
+ case K_DWORD: # Delete entire line
+ if (str[1] != EOS) {
+ PR_COL(data) = 1
+
+ for (ic = 1; str[ic] != EOS; ic = ic + 1)
+ str[ic] = ' '
+ call addstr (win, str)
+ str[1] = EOS
+ }
+
+ case K_HELP: # Display help screen
+ call fm_help
+
+ case K_PAINT: # Redraw the screen
+ call clearok (STDSCR, true)
+ call wrefresh (STDSCR)
+ call wmove (win, PR_ROW(data), PR_COL(data))
+
+ default:
+ call ps_beep
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/tedit/display/mkpkg b/pkg/utilities/nttools/tedit/display/mkpkg
new file mode 100644
index 00000000..322177b4
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/mkpkg
@@ -0,0 +1,14 @@
+
+# Update the display library.
+# Author: B.Simon 01-APR-91
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ @curses
+ @forms
+ @screen
+ ;
diff --git a/pkg/utilities/nttools/tedit/display/screen/README b/pkg/utilities/nttools/tedit/display/screen/README
new file mode 100644
index 00000000..6a29f82f
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/README
@@ -0,0 +1,211 @@
+The procedures in this directory implement the lowest level of the
+screen handling routines in the display library. Procedures not
+described in this file are not part of the public interface and should
+not be called by user programs. All the capabilities of the curses
+procedures are layered on top of the procedures in this directory.
+These procedures provide less functionality than the curses routines,
+but can be faster, at the expense of more complications in the user
+program. The procedures in this directory are portable. They are
+written in SPP and they do all their I/O through the IRAF VOS. They
+use the termcap and edcap files so that this library can be used with
+a variety of terminals and the editing commands can be tailored to the
+user's preferences. There are two sets of subroutines in this
+directory. The first set is the keyboard subroutines, prefixed by the
+letter "k", which read the keyboard and translate control key
+sequences to a single character. The second set is the screen
+sunroutines, prefixed by the letters "ps", which write to the
+terminal.
+
+The keyboard subroutines read input from the keyboard, translating
+command key sequences into a single number. The command key sequences
+are read from the edcap file. This is a file located either in the
+user's home directory or the dev$ directory whose name is the value of
+the editor environment variable with an extension of ".ed". See the
+files in the dev$ directory for an example of the file format. The
+keyboard subroutines are initialized by a call to the following
+subroutine:
+
+procedure k_begin (cmdlist)
+
+char cmdlist[ARB] # i: List of editing commands
+
+This subroutine puts the terminal in raw mode, reads the edcap file,
+and sends the keyboard initialization sequence to the terminal. Its
+argument is a list of command names taken from the edcap file that you
+want your program to recognize. The first character in the string is a
+command separator, used to separate the commands in the string. The
+macro CMDSTR in <curses.h> defines the list of commands used by the
+curses routines. The screen initialization routine, ps_begin, must be
+called before k_begin is called. To terminate the keyboard interface,
+call the following subroutine:
+
+procedure k_end ()
+
+This procedure ends raw mode and sends the keyboard termination sequence
+to the terminal. The screen termination routine, ps_end, should be
+called after this routine is called. The following subroutine reads a
+single character from the terminal:
+
+int procedure k_get ()
+
+Command key sequences that were named in the command list passed to
+k_begin are returned as a single number. The value returned by the
+first command key sequence in the command list is K_BASE, the value
+returned by the second sequence is K_BASE+1, and so on. The macro
+K_BASE is defined in <curses.h>.
+
+The next keyboard subroutine returns a pointer to a character string
+containing the help text for the keyboard commands:
+
+procedure k_help (text)
+
+pointer text # o: Help text
+
+The help text string is formatted as a series of command descriptions.
+Each description starts with the name of the edcap command , followed
+by an equals sign, followed by the ascii representation of the key
+sequence which executes the command, and terminated by a newline
+character.The string is formatted as a series of command descriptions.
+Each description starts with the name of the edcap command , followed
+by an equals sign, followed by the ascii representation of the key
+sequence which executes the command, and terminated by a newline
+character.
+
+The following routine copies one of the command descriptions from the
+help text to an output string:
+
+procedure k_eseq (name, eseq, maxch)
+
+char name[ARB] # i: Name bound to command sequence
+char eseq[ARB] # o: String representation of command sequence
+int maxch # i: Maximum length of command sequence
+
+The input parameters are the name of the command sequence and the
+length of the output string. The name of the sequence should be
+the name passed as part of the command string to k_begin(). The output
+is the ascii represntation of the escape sequence of that command.
+
+The screen subroutines are used to send output to the terminal. They
+are based on the subroutines in Marc Rochkind's book, "Advanced C
+Programs for Displays". Several conventions are followed by these
+subroutines. The first is that while strings are passed as arrays of
+characters, individual characters are passed as integers. The second is
+that screen coordinates are passed row first, column second and that the
+coordinates of the upper left corner of the screen are (1, 1). The
+third is that areas on the screen are passed as rectangles, which are
+represented as arrays of four elements, where the four elements are the
+(top, left, bottom, right) corners of the rectangle. The initialization
+and termination routines for the screen subroutines are:
+
+procedure ps_begin ()
+procedure ps_end ()
+
+The first subroutine opens the terminal for I/O and reads the termcap
+file, the second closes the terminal. The calling program get the size
+of the screen by calling the subroutines:
+
+int procedure ps_height ()
+int procedure ps_width ()
+
+These subroutines return the number of screen rows and columns,
+respectively. The following subroutine flushes the output buffer:
+
+procedure ps_synch ()
+
+The user will not see any output sent by these subroutine to the
+terminal until this subroutine is called. To ring the terminal's bell,
+call the following subroutine:
+
+procedure ps_beep ()
+
+To move the cursor on the screen call the following subroutine:
+
+procedure ps_setcur (row, col)
+
+int row # i: Cursor row
+int col # i: Cursor column
+
+To write a string to the screen call the following subroutine:
+
+procedure ps_write (row, col, ncols, str, att)
+
+int row # i: Starting row
+int col # i: Starting column
+int ncols # i: Number of columns to write
+char str[ARB] # i: String to write
+int att # i: Attribute
+
+The number of columns is an upper limit on the number of characters to
+write, if the string is shorter than this, the actual number of
+characters on the screen will be displayed. If the string does not lie
+entirely on the screen, the string will be clipped at the screen boundary.
+The attribute determines whether the string is printed normally or in
+standout mode. The value should be set to either A_NORM or A_STANDOUT,
+which is defined in display.h. To write a string where the screen
+attribute may change from character to characater call the following
+subroutine:
+
+procedure ps_wrtcells (row, col, vector, ncols)
+
+int row # i: Starting row
+int col # i: Starting column
+char vector[ARB] # i: Vector to write
+int ncols # i: Number of columns to write
+
+The string to be written must be at least ncols long and each character
+to be displayed in standout mode should have A_STANDOUT added to its
+ascii code. This subroutine is used when the calling program keeps an
+array whose contents corresponds to the current screen display. To fill
+an area on the screen with a single character call the following
+subroutine:
+
+procedure ps_fill (source, ch, att)
+
+int source[RSIZE] # i: Rectangle
+int ch # i: Fill character
+int att # i: Fill attribute
+
+This subroutine can be used to clear part or all of the screen by
+setting the fill character to blank and the fill attribute to A_NORM.
+The macro RSIZE is equal to 4 and is defined in display.h. To move an
+area of the screen in any of the four directions call the following
+subroutine:
+
+bool procedure ps_slide (source, dir, dist)
+
+int source[RSIZE] # i: Rectangle
+int dir # i: Direction (from display.h)
+int dist # i: Distance (> 0)
+
+This subroutine can be used to scroll the screen up or down, delete one
+or more characters from a line, or move a line over so that a new
+character can be inserted. The direction is given as one of the four
+macros DIR_UP, DIR_DOWN, DIR_LEFT, and DIR_RIGHT, defined in <curses.h>.
+This subroutine may or may not be able to move the screen, depending on
+the capabilities defined in the terminal's termcap file. If the
+subroutine can move the area, it returns true and if it cannot, it
+returns false. In the latter case, it is the responsibility of the
+calling program to redraw the affected area of the screen in order to
+move the area.
+
+The include file display.h contains several macros the can be used to
+manipulate the rectangles passed to the screen subroutines. In order to
+access the elements of a rectangle the following macros can be used:
+
+RTOP(rect) # Top row of a rectangle
+RLEFT(rect) # Left column of a rectangle
+RBOT(rect) # Bottom row of a rectangle
+RRIGHT(rect) # Right column of a rectangle
+
+The dimensions of a rectangle can be computed by the following macros:
+
+RWIDTH(rect) # Number of columns in a rectangle
+RHEIGHT(rect) # Number of rows in a rectangle
+
+A program can set the elements in a rectangle with the following macros:
+
+RASG(newrect, top, left, bottom, right)
+RCPY(newrect, oldrect)
+
+The first macro assigns four scalars to the elements of a rectangle and
+the second macro copies the elements of one rectangle to another.
diff --git a/pkg/utilities/nttools/tedit/display/screen/kbegin.x b/pkg/utilities/nttools/tedit/display/screen/kbegin.x
new file mode 100644
index 00000000..0be12ab6
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/kbegin.x
@@ -0,0 +1,40 @@
+include <fset.h>
+include "../curses.h"
+
+# K_BEGIN -- Initialize keyboard
+#
+# B.Simon 23-Jan-89 Original
+
+procedure k_begin (cmdlist)
+
+char cmdlist[ARB] # i: List of editing commands
+#--
+include "screen.com"
+
+int klen
+int strlen()
+
+extern k_error
+
+begin
+ # NOTE: ps_begin must be called before calling this procedure
+
+ # Put terminal in raw mode
+
+ call fseti (ttyin, F_RAW, YES)
+
+ # Set up error exit routine
+
+ call onerror (k_error)
+
+ # Set up function key table and help screen
+
+ call k_compile (cmdlist)
+
+ # Send initialize keypad sequence to terminal
+
+ klen = strlen (ks)
+ if (klen > 0)
+ call ttywrite (ttyout, term, ks, klen, 1)
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/kcompile.x b/pkg/utilities/nttools/tedit/display/screen/kcompile.x
new file mode 100644
index 00000000..9ad162ec
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/kcompile.x
@@ -0,0 +1,148 @@
+include <ctype.h>
+include "../curses.h"
+
+define SYNTAX 1
+define K_CMDLEN 7
+
+# K_COMPILE -- Compile a file of editing key definitions (edcap)
+#
+# B.Simon 23-Jan-89 Original
+
+procedure k_compile (cmdlist)
+
+char cmdlist[ARB] # i: List of commands
+#--
+include "screen.com"
+
+char sep
+int ic, maxcmd, nkey, maxkey
+int hlength, hwidth, hstart, hleft, fd, tag
+pointer sp, label, escape, name
+
+bool streq()
+int k_capfile(), ps_width(), fscan(), nscan(), strdic(), gstrcpy()
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (label, SZ_FNAME, TY_CHAR)
+ call salloc (escape, SZ_FNAME, TY_CHAR)
+ call salloc (name, SZ_FNAME, TY_CHAR)
+
+ # Count the number of editing commands
+
+ maxcmd = 0
+ sep = cmdlist[1]
+ for (ic = 1; cmdlist[ic] != EOS; ic = ic + 1) {
+ if (cmdlist[ic] == sep && cmdlist[ic+1] != EOS)
+ maxcmd = maxcmd + 1
+ }
+
+ # Allocate dynamic memory for the function key table
+
+ nkey = 0
+ maxkey = K_CMDLEN * maxcmd
+ call calloc (keytab, 4*maxkey, TY_INT)
+
+ # Set up help text
+
+ hwidth = ps_width() / 2
+ hlength = maxcmd * hwidth
+ call calloc (htext, hlength+1, TY_CHAR)
+ hstart = htext
+ hleft = hlength
+
+ # Add each line from the edcap file to the table of function
+ # key sequences and the help screen
+
+ fd = k_capfile ()
+ while (fscan (fd) != EOF) {
+ call gargwrd (Memc[label], SZ_FNAME)
+ call gargwrd (Memc[escape], SZ_FNAME)
+ call gargwrd (Memc[name], SZ_FNAME)
+
+ # Proceess line only if all three elements of command are present
+ # and command is found in command list
+
+ if (nscan () == 3) {
+
+ if (streq (Memc[label], "EDIT_INIT"))
+ call k_convert (Memc[escape], ks, K_CMDLEN)
+ else if (streq (Memc[label], "EDIT_TERM"))
+ call k_convert (Memc[escape], ke, K_CMDLEN)
+
+ tag = strdic (Memc[label], Memc[label], SZ_FNAME, cmdlist)
+ if (tag > 0) {
+ tag = tag + K_BASE - 1
+
+ # Add escape sequence to function key table
+
+ call k_doline (Memc[escape], tag, maxkey,
+ nkey, Memi[keytab])
+
+ # Add label and name to help text
+
+ if (hleft > hwidth) {
+ hstart = gstrcpy (Memc[label], Memc[hstart], hleft) +
+ hstart
+
+ Memc[hstart] = '='
+ hstart = hstart + 1
+
+ hstart = gstrcpy (Memc[name], Memc[hstart], hleft) +
+ hstart
+
+ Memc[hstart] = '\n'
+ hstart = hstart + 1
+ hleft = hlength - (hstart - htext)
+ }
+ }
+ }
+ }
+
+ Memc[hstart] = EOS
+ call close (fd)
+ call sfree (sp)
+end
+
+# K_CAPFILE -- Open the editing capabilities file (edcap)
+
+int procedure k_capfile ()
+
+#--
+int fd
+pointer sp, editor, edcap
+
+int envgets(), access(), open()
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (editor, SZ_FNAME, TY_CHAR)
+ call salloc (edcap, SZ_FNAME, TY_CHAR)
+
+ # Get the name of the edcap file and open it
+
+ if (envgets ("editor", Memc[editor], SZ_FNAME) <= 0)
+ call error (SYNTAX, "Editor not found")
+
+ call sprintf (Memc[edcap], SZ_FNAME, "home$%s.ed")
+ call pargstr (Memc[editor])
+
+ if (access (Memc[edcap], READ_ONLY, 0) == NO) {
+
+ call sprintf (Memc[edcap], SZ_FNAME, "dev$%s.ed")
+ call pargstr (Memc[editor])
+
+ if (access (Memc[edcap], READ_ONLY, 0) == NO)
+ call error (SYNTAX, "Edcap file not found")
+
+ }
+
+ fd = open (Memc[edcap], READ_ONLY, TEXT_FILE)
+ call sfree (sp)
+
+ return (fd)
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/kconvert.x b/pkg/utilities/nttools/tedit/display/screen/kconvert.x
new file mode 100644
index 00000000..11e283fa
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/kconvert.x
@@ -0,0 +1,61 @@
+include <ctype.h>
+
+# K_CONVERT -- Convert a string with coded escape sequences to the real thing
+#
+# B.Simon 23-Jan-89 Original
+
+procedure k_convert (escstr, escseq, maxch)
+
+char escstr[ARB] # i: Escape sequence string
+char escseq[ARB] # o: Escape key sequence
+int maxch # i: Declared length of key sequence
+#--
+int ic, jc, index, num
+
+string echars "befnrt"
+string ecodes "\010\033\f\n\r\t"
+
+int stridx()
+
+begin
+ ic = 1
+ for (jc = 1; jc <= maxch; jc = jc + 1) {
+
+ # Exit when all characters in escape string have been processed
+
+ if (escstr[ic] == EOS)
+ break
+
+ # Convert escape sequence
+
+ if (escstr[ic] == '\\') {
+ ic = ic + 1
+ index = stridx (escstr[ic], echars)
+ if (index > 0) {
+ escseq[jc] = ecodes[index]
+ } else if (IS_DIGIT(escstr[ic])) {
+ for (num = 0; IS_DIGIT(escstr[ic]); ic = ic + 1)
+ num = 8 * num + TO_DIGIT(escstr[ic])
+ ic = ic - 1
+ escseq[jc] = num
+ } else {
+ escseq[jc] = escstr[ic]
+ }
+
+ # Convert control sequence
+
+ } else if (escstr[ic] == '^') {
+ ic = ic + 1
+ escseq[jc] = mod (int(escstr[ic]), 32)
+
+ # Copy ordinary character
+
+ } else {
+ escseq[jc] = escstr[ic]
+ }
+
+ ic = ic + 1
+ }
+
+ escseq[jc] = EOS
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/kdoline.x b/pkg/utilities/nttools/tedit/display/screen/kdoline.x
new file mode 100644
index 00000000..bcdf4a72
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/kdoline.x
@@ -0,0 +1,96 @@
+include <ctype.h>
+
+define SYNTAX 1
+define BOUNDS 2
+
+# K_DOLINE -- Add a line containing an escape sequence to the key table
+#
+# B.Simon 23-Jan-89 Original
+
+procedure k_doline (escstr, tag, maxtab, ntab, table)
+
+char escstr[ARB] # i: Key sequence
+int tag # i: Key tag
+int maxtab # i: Maximum number of entries
+int ntab # io: Current number of entries
+int table[4,ARB] # io: Key sequence table
+#--
+int ic, link, new, old
+pointer sp, escseq
+
+int strlen()
+
+string notctrl "Key sequence must begin with a control character"
+string isambig "Ambiguous key sequence"
+string toomany "Too many key definitions"
+
+begin
+ # Convert escape sequence
+
+ call smark (sp)
+ call salloc (escseq, SZ_FNAME, TY_CHAR)
+ call k_convert (escstr, Memc[escseq], SZ_FNAME)
+
+ # Don't process null sequences
+
+ if (Memc[escseq] == EOS)
+ return
+
+ # Check to see if escape sequence is valid
+
+ if (IS_PRINT(Memc[escseq]))
+ call error (SYNTAX, notctrl)
+
+ # Find first character in key sequence that is new
+
+ ic = 0
+ link = 0
+ for (new = 1; new != 0; new = table[link,old]) {
+ old = new
+ if (link == 1)
+ ic = ic + 1
+ if (Memc[escseq+ic] == table[3,old])
+ link = 1
+ else
+ link = 2
+ }
+
+ if (link == 1) {
+
+ # Redefinition of existing sequence
+
+ if (Memc[escseq+ic] != EOS)
+ call error (SYNTAX, isambig)
+ table[4,old] = tag
+
+ } else {
+
+ # New sequence
+
+ if (Memc[escseq+ic] == EOS)
+ call error (SYNTAX, isambig)
+
+ # Check for table overflow
+
+ if (strlen (Memc[escseq+ic]) + ntab > maxtab)
+ call error (BOUNDS, toomany)
+
+ # Insert remainder of key sequence in table
+
+ table[2,old] = ntab + 1
+ while (Memc[escseq+ic] != EOS) {
+ ntab = ntab + 1
+ table[1,ntab] = ntab + 1
+ table[2,ntab] = 0
+ table[3,ntab] = Memc[escseq+ic]
+ table[4,ntab] = 0
+ ic = ic + 1
+ }
+ table[1,ntab] = 0
+ table[4,ntab] = tag
+
+ }
+
+ call sfree (sp)
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/kend.x b/pkg/utilities/nttools/tedit/display/screen/kend.x
new file mode 100644
index 00000000..57130052
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/kend.x
@@ -0,0 +1,49 @@
+include <fset.h>
+
+# K_END -- Terminate keyboard
+#
+# B.Simon 23-Jan-89 Original
+
+procedure k_end ()
+
+#--
+include "screen.com"
+
+int klen
+int strlen()
+
+begin
+ # Restore keyboard to original state and end raw mode
+
+ if (ttyin != NULL) {
+ if (term != NULL) {
+ klen = strlen (ke)
+ if (klen > 0)
+ call ttywrite (ttyout, term, ke, klen, 1)
+ }
+ call fseti (ttyin, F_RAW, NO)
+ }
+
+ # Release dynamic memory
+
+ if (keytab != NULL)
+ call mfree (keytab, TY_INT)
+
+ if (htext != NULL)
+ call mfree (htext, TY_CHAR)
+
+end
+
+# K_ERROR -- Procedure called on error exit
+
+procedure k_error (status)
+
+int status # i: Error status
+#--
+
+begin
+ if (status != OK) {
+ call k_end
+ call ps_end
+ }
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/kget.x b/pkg/utilities/nttools/tedit/display/screen/kget.x
new file mode 100644
index 00000000..61364f9e
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/kget.x
@@ -0,0 +1,96 @@
+include <ctype.h>
+
+define CAN_ABORT NO
+define ABORT '\003'
+
+# K_GET -- Read a character, translating function keys
+
+int procedure k_get ()
+
+#--
+include "screen.com"
+
+int ch
+
+int first
+int k_cget(), k_lookup()
+
+string abortmsg "Task aborted by ^C"
+
+begin
+ if (keych != EOF) {
+ # Check for a pushed back character, returning it if found
+
+ ch = keych
+ keych = EOF
+
+ } else {
+ # Check character to see if it is the start of a control sequence
+ # If not, return the character without searching the table
+
+ first = k_cget ()
+
+ if (IS_PRINT(first))
+ ch = first
+ else if ((CAN_ABORT == YES) && (first == ABORT))
+ call error (1, abortmsg)
+ else
+ ch = k_lookup (first, Memi[keytab])
+ }
+
+ return (ch)
+
+end
+
+# K_LOOKUP -- Look up a function key sequence in a table
+
+int procedure k_lookup (first, table)
+
+int first # i: First character in the sequence
+int table[4,ARB] # i: Table of function key sequences
+#--
+include "screen.com"
+
+int key, new, old, link
+int k_cget()
+
+begin
+ # Search the table for the control sequence
+
+ link = 0
+ key = first
+
+ for (new = 1; new != 0; new = table[link,old]) {
+ old = new
+ if (link == 1)
+ key = k_cget ()
+ if (key == table[3,old])
+ link = 1
+ else
+ link = 2
+ }
+
+ # Return the control sequence tag if the sequence was found,
+ # otherwise return the first unrecognized key
+
+ if (link == 1)
+ key = table[4,old]
+
+ return (key)
+
+end
+
+# K_CGET -- Read a single character from the terminal
+
+int procedure k_cget ()
+
+#--
+include "screen.com"
+
+int ch
+int and(), getci()
+
+begin
+ ch = getci (ttyin, ch)
+ return (and (ch, 177B))
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/khelp.x b/pkg/utilities/nttools/tedit/display/screen/khelp.x
new file mode 100644
index 00000000..4b075f8a
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/khelp.x
@@ -0,0 +1,61 @@
+include <fset.h>
+
+# K_HELP -- Retrieve help text for function key sequences
+
+procedure k_help (text)
+
+pointer text # o: Help text
+#--
+include "screen.com"
+
+begin
+ text = htext
+end
+
+procedure k_eseq (name, eseq, maxch)
+
+char name[ARB] # i: Name bound to escape sequence
+char eseq[ARB] # o: String representation of escape sequence
+int maxch # i: Maximum length of escape sequence
+#--
+include "screen.com"
+
+bool match, in_name
+int ic
+pointer ch
+
+begin
+ ic = 1
+ match = true
+ in_name = true
+
+ for (ch = htext; Memc[ch] != EOS; ch = ch + 1) {
+ if (in_name) {
+ if (Memc[ch] == '=') {
+ match = match && name[ic] == EOS
+ in_name = false
+ ic = 1
+ } else if (match) {
+ if (Memc[ch] == name[ic]) {
+ ic = ic + 1
+ } else {
+ match = false
+ }
+ }
+
+ } else {
+ if (Memc[ch] == '\n') {
+ if (match)
+ break
+ ic = 1
+ match = true
+ in_name = true
+ } else if (match && ic <= maxch) {
+ eseq[ic] = Memc[ch]
+ ic = ic + 1
+ }
+ }
+ }
+ eseq[ic] = EOS
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/kpushbk.x b/pkg/utilities/nttools/tedit/display/screen/kpushbk.x
new file mode 100644
index 00000000..6e9c05c2
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/kpushbk.x
@@ -0,0 +1,11 @@
+# K_PUSHBK -- Push back a single character read from the keyboard
+
+procedure k_pushbk (ch)
+
+int ch # i: character to be pushed back
+#--
+include "screen.com"
+
+begin
+ keych = ch
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/mkpkg b/pkg/utilities/nttools/tedit/display/screen/mkpkg
new file mode 100644
index 00000000..dc062ae4
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/mkpkg
@@ -0,0 +1,32 @@
+# Update the display library.
+# Author: B.Simon 01-APR-91
+
+$checkout libpkg.a ../../
+$update libpkg.a
+$checkin libpkg.a ../../
+$exit
+
+libpkg.a:
+ kbegin.x <fset.h> "../curses.h" "screen.com"
+ kcompile.x <ctype.h> "../curses.h" "screen.com"
+ kconvert.x <ctype.h>
+ kdoline.x <ctype.h>
+ kend.x <fset.h> "screen.com"
+ kget.x <ctype.h> "screen.com"
+ khelp.x "screen.com"
+ kpushbk.x "screen.com"
+ psbegin.x <ttyset.h> "screen.com"
+ psbeep.x
+ psend.x "screen.com"
+ psfill.x <ctype.h> "../curses.h" "screen.com"
+ psheight.x "screen.com"
+ psintersect.x "../curses.h"
+ psscreen.x "screen.com"
+ pssendcap.x "screen.com"
+ pssetcur.x "screen.com"
+ psslide.x "../curses.h" "screen.com"
+ pssynch.x "screen.com"
+ pswidth.x "screen.com"
+ pswrite.x <ctype.h> "../curses.h" "screen.com"
+ pswrtcells.x <ctype.h> "../curses.h" "screen.com"
+ ;
diff --git a/pkg/utilities/nttools/tedit/display/screen/psbeep.x b/pkg/utilities/nttools/tedit/display/screen/psbeep.x
new file mode 100644
index 00000000..252991ba
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/psbeep.x
@@ -0,0 +1,9 @@
+# PS_BEEP -- Sound the bell
+#
+# B.Simon 19-Jan-89 Original
+
+procedure ps_beep ()
+
+begin
+ call ps_sendcap ("bl", 1)
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/psbegin.x b/pkg/utilities/nttools/tedit/display/screen/psbegin.x
new file mode 100644
index 00000000..2bf702cf
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/psbegin.x
@@ -0,0 +1,59 @@
+include <ttyset.h>
+include "../curses.h"
+
+# PS_BEGIN -- Initialize physical screen display
+#
+# B.Simon 18-Jan-89 Original
+# B.Simon 26-Sep-90 Updated to use screen buffer
+
+procedure ps_begin ()
+
+#--
+include "screen.com"
+
+char ch
+data ch / EOS /
+
+string nomove "Terminal does not support cursor movement (cm)"
+
+bool ttygetb()
+int ttopen(), ttystati()
+pointer ttyodes()
+
+begin
+ # Initialize global variables
+
+ ks[1] = EOS
+ ke[1] = EOS
+ keych = EOF
+
+ currow = GIANT
+ curcol = GIANT
+
+ keytab = NULL
+ termscr = NULL
+ htext = NULL
+
+ term = ttyodes ("terminal")
+ lines = ttystati (term, TTY_NLINES)
+ cols = ttystati (term, TTY_NCOLS)
+
+ if (! ttygetb (term, "cm")) {
+ call ttyclose (term)
+ call error (1, nomove)
+ }
+
+ ttyin = ttopen ("dev$tty", READ_ONLY)
+ ttyout = ttopen ("dev$tty", APPEND)
+
+ # Allocate memory for screen and fill with EOS
+
+ call malloc (termscr, lines*cols, TY_CHAR)
+ call amovkc (ch, Memc[termscr], lines*cols)
+
+ # Initialize display
+
+ call ps_sendcap ("ti", 1)
+ call ps_sendcap ("vs", 1)
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/psend.x b/pkg/utilities/nttools/tedit/display/screen/psend.x
new file mode 100644
index 00000000..1d86e6df
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/psend.x
@@ -0,0 +1,48 @@
+# PS_END -- Terminate physical display package
+#
+# B.Simon 18-Jan-89 Original
+# B.Simon 26-Sep-90 Updated to use screen buffer
+
+procedure ps_end()
+
+#--
+include "screen.com"
+
+char newline
+data newline / '\n' /
+
+begin
+ # Restore terminal to original state and release termcap structure
+
+ if (term != NULL) {
+ call ps_sendcap ("ve", 1)
+ call ps_sendcap ("te", 1)
+
+ if (ttyout != NULL) {
+ call ttygoto (ttyout, term, 1, lines)
+ call putc (ttyout, newline)
+ }
+ call ttyclose (term)
+ term = NULL
+ }
+
+ # Release screen memory
+
+ if (termscr != NULL) {
+ call mfree (termscr, TY_CHAR)
+ termscr = NULL
+ }
+
+ # Close terminal descriptor
+
+ if (ttyin != NULL) {
+ call close (ttyin)
+ ttyin = NULL
+ }
+
+ if (ttyout != NULL) {
+ call close (ttyout)
+ ttyout = NULL
+ }
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/psfill.x b/pkg/utilities/nttools/tedit/display/screen/psfill.x
new file mode 100644
index 00000000..2ceee221
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/psfill.x
@@ -0,0 +1,135 @@
+include <ctype.h>
+include "../curses.h"
+
+# PS_FILL -- Fill a rectangle with a single character and attribute
+#
+# B.Simon 19-Jan-89 Original
+# B.Simon 26-Sep-90 Updated to use screen buffer
+# B.Simon 31-Oct-90 Changed to skip correct lines
+
+procedure ps_fill (source, ch, att)
+
+int source[RSIZE] # i: Rectangle
+int ch # i: Fill character
+int att # i: Fill attribute
+#--
+include "screen.com"
+
+bool canclear, bufflag
+char blank, fill, cell
+int dest[RSIZE]
+int ncols, nrows, irow, icol
+pointer sp, buf, scr
+
+data blank / ' ' /
+
+bool ps_intersect(), ttygetb()
+pointer ps_screen()
+
+begin
+ # Clip the rectangle to the screen boundary
+ # If the rectangle is entirely off the screen, return
+
+ if (! ps_intersect (source, lines, cols, dest))
+ return
+
+
+ # Check for the special cases:
+ # Clear entire screen (cl) and clear to end of screen (cd)
+
+ canclear = (ch == ' ' && att == A_NORM)
+ ncols = RWIDTH(dest)
+ nrows = RHEIGHT(dest)
+
+ if (canclear && ncols == cols && nrows == lines) {
+ if (ttygetb (term, "cl")) {
+ call ps_updcur (1, 1)
+ call ps_sendcap ("cl", nrows)
+ call amovkc (blank, Memc[termscr], lines*cols)
+ return
+ }
+ }
+
+ if (canclear && ncols == cols && RBOT(dest) == lines) {
+ if (ttygetb (term, "cd")) {
+ call ps_setcur (RTOP(dest), 1)
+ call ps_sendcap ("cd", nrows)
+ scr = ps_screen (RTOP(dest), 1)
+ call amovkc (blank, Memc[scr], nrows*cols)
+ return
+ }
+ }
+
+ # Write the rectangle a line at a time
+
+ call smark (sp)
+ call salloc (buf, cols, TY_CHAR)
+
+ if (IS_PRINT(ch))
+ fill = ch
+ else
+ fill = blank
+
+ cell = fill + att
+ bufflag = false
+
+ canclear = canclear && ttygetb (term, "ce")
+
+ do irow = RTOP(dest), RBOT(dest) {
+
+ # Check to see if line is already correct
+ # If so, skip to the next line
+
+ scr = ps_screen (irow, RLEFT(dest))
+
+ for (icol = 1; icol <= ncols; icol = icol + 1) {
+ if (Memc[scr+icol-1] != cell)
+ break
+ }
+
+ if (icol > ncols)
+ next
+
+ # Move cursor to beginning of line and set attribute
+
+ call ps_setcur (irow, RLEFT(dest))
+
+ if (att != A_NORM)
+ call ps_sendcap ("so", 1)
+
+ # Special case: clear to end of line
+
+ if (canclear && RRIGHT(dest) == cols) {
+ call ps_sendcap ("ce", 1)
+ call amovkc (blank, Memc[scr], ncols)
+
+ } else {
+
+ # Fill buffer with character and write to terminal
+
+ if (! bufflag) {
+ bufflag = true
+ call amovkc (fill, Memc[buf], ncols)
+ }
+
+ # Don't write to lower right corner if screen will scroll
+
+ if (irow == lines && RRIGHT(dest) == cols) {
+ if (ttygetb (term, "am"))
+ ncols = ncols - 1
+ }
+
+ call write (ttyout, Memc[buf], ncols)
+ call amovkc (cell, Memc[scr], ncols)
+ call ps_updcur (irow, RRIGHT(dest) + 1)
+ }
+
+ # Set attribute back to normal
+
+ if (att != A_NORM)
+ call ps_sendcap ("se", 1)
+
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/psheight.x b/pkg/utilities/nttools/tedit/display/screen/psheight.x
new file mode 100644
index 00000000..8350e773
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/psheight.x
@@ -0,0 +1,12 @@
+# PS_HEIGHT -- Get height of physical screen
+#
+# B.Simon 18-Jan-89 Original
+
+int procedure ps_height ()
+
+#--
+include "screen.com"
+
+begin
+ return (lines)
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/psintersect.x b/pkg/utilities/nttools/tedit/display/screen/psintersect.x
new file mode 100644
index 00000000..93c11f0f
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/psintersect.x
@@ -0,0 +1,27 @@
+include "../curses.h"
+
+# PS_INTERSECT -- Intersection between two rectangles
+#
+# B.Simon 18-Jan-89 Original
+
+bool procedure ps_intersect (source, maxrow, maxcol, dest)
+
+int source[RSIZE] # i: Source rectangle
+int maxrow # i: Max row of clipping rectangle
+int maxcol # i: Max column of clipping rectangle
+int dest[RSIZE] # o: Destination rectangle
+#--
+
+begin
+ # Clip source rectangle to (1,1) and (maxrow,maxcol)
+
+ RTOP(dest) = max (1, RTOP(source))
+ RLEFT(dest) = max (1, RLEFT(source))
+ RBOT(dest) = min (maxrow, RBOT(source))
+ RRIGHT(dest) = min (maxcol, RRIGHT(source))
+
+ # Return true if intersection is non-empty
+
+ return (RTOP(dest) <= RBOT(dest) && RLEFT(dest) <= RRIGHT(dest))
+end
+
diff --git a/pkg/utilities/nttools/tedit/display/screen/psscreen.x b/pkg/utilities/nttools/tedit/display/screen/psscreen.x
new file mode 100644
index 00000000..afdd7b8d
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/psscreen.x
@@ -0,0 +1,14 @@
+# PS_SCREEN -- Return a pointer to a given character on the screen
+#
+# B.Simon 28-Sep-90 Original
+
+pointer procedure ps_screen (row, col)
+
+int row # i: Screen line
+int col # i: Screen column
+#--
+include "screen.com"
+
+begin
+ return (termscr+cols*(row-1)+(col-1))
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/pssendcap.x b/pkg/utilities/nttools/tedit/display/screen/pssendcap.x
new file mode 100644
index 00000000..295a6cff
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/pssendcap.x
@@ -0,0 +1,74 @@
+# PS_SENDCAP -- Send a termcap command to the terminal
+#
+# B.Simon 18-Jan-89 Original
+
+procedure ps_sendcap (cap, affcnt)
+
+char cap[ARB] # i: Termcap capability name
+int affcnt # i: Number of lines affected by the command
+#--
+include "screen.com"
+
+int nchar
+pointer sp, capstr
+
+int ttygets()
+
+begin
+ call smark (sp)
+ call salloc (capstr, SZ_FNAME, TY_CHAR)
+
+ # Retrieve the termcap capability string given its name
+ # If it is found, write it to the terminal
+
+ nchar = ttygets (term, cap, Memc[capstr], SZ_FNAME)
+ if (nchar > 0) {
+ call ttywrite (ttyout, term, Memc[capstr], nchar, affcnt)
+ ## call ps_debugcap (cap, Memc[capstr], nchar)
+ }
+
+ call sfree (sp)
+end
+
+# PS_DEBUGCAP -- Print a termcap string for debugging purposes
+
+procedure ps_debugcap (capname, capstr, nchar)
+
+char capname[ARB] # i: Termcap capability name
+char capstr[ARB] # i: Termcap capability string
+int nchar # i: Number of characters in string
+#--
+include "screen.com"
+
+char ch
+int ic, jc
+pointer sp, out
+
+begin
+ # Allocate memory for strings
+
+ call smark (sp)
+ call salloc (out, SZ_LINE, TY_CHAR)
+
+ jc = 0
+ do ic = 1, nchar {
+ ch = capstr[ic]
+ if (ch < ' ') {
+ Memc[out+jc] = '^'
+ jc = jc + 1
+ ch = ch + '@'
+ }
+ Memc[out+jc] = ch
+ jc = jc + 1
+ }
+ Memc[out+jc] = EOS
+
+ # Write string to STDOUT and flush
+
+ call fprintf (ttyout, "%s = %s\n")
+ call pargstr (capname)
+ call pargstr (Memc[out])
+ call flush (ttyout)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/pssetcur.x b/pkg/utilities/nttools/tedit/display/screen/pssetcur.x
new file mode 100644
index 00000000..a6954da3
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/pssetcur.x
@@ -0,0 +1,117 @@
+define ABSOLUTE YES # disable relative cursor motion if YES
+
+# PS_SETCUR -- Set the cursor position
+#
+# B.Simon 19-Jan-89 Original
+# B.Simon 19-Dec-90 Rewritten to speed cursor motion
+# B.Simon 10-Apr-91 Add switch to disable relative motion
+
+procedure ps_setcur (row, col)
+
+int row # i: Cursor row
+int col # i: Cursor column
+#--
+include "screen.com"
+
+bool moved
+int newrow, newcol, dr, dc
+
+bool ttygetb()
+
+begin
+ newrow = min (lines, max (1, row))
+ newcol = min (cols, max (1, col))
+
+ moved = true
+ dr = newrow - currow
+ dc = newcol - curcol
+
+ if (ABSOLUTE == YES) {
+ if (dr != 0 || dc != 0)
+ moved = false
+
+ } else if (dr == 0) {
+ if (dc == 0) { # no move
+ return
+
+ } else if (dc == 1) { # move right by one
+ if (ttygetb (term, "nd"))
+ call ps_sendcap ("nd", 1)
+ else
+ moved = false
+
+ } else if (dc == -1) { # move left by one
+ if (ttygetb (term, "le"))
+ call ps_sendcap ("le", 1)
+ else
+ moved = false
+
+ } else {
+ moved = false
+ }
+
+ } else if (dr == 1) {
+ if (dc == 0) { # move down by one
+ if (ttygetb (term, "do"))
+ call ps_sendcap ("do", 1)
+ else
+ moved = false
+
+ } else {
+ moved = false
+ }
+
+ } else if (dr == -1) {
+ if (dc == 0) { # move up by one
+ if (ttygetb (term, "up"))
+ call ps_sendcap ("up", 1)
+ else
+ moved = false
+ } else {
+ moved = false
+ }
+
+ } else {
+ moved = false
+ }
+
+ if (! moved) # must use absolute move
+ call ttygoto (ttyout, term, newcol, newrow)
+
+ # Update current cursor position
+
+ currow = newrow
+ curcol = newcol
+end
+
+# PS_UPDCUR -- Update the cursor position
+
+procedure ps_updcur (row, col)
+
+int row # i: New cursor row
+int col # i: New cursor column
+#--
+include "screen.com"
+
+bool ttygetb()
+
+begin
+ if (row >= lines) {
+ currow = lines
+ } else {
+ currow = row
+ }
+
+ if (col >= cols) {
+ if (ttygetb (term, "am")) {
+ currow = min (row + 1, lines)
+ curcol = 1
+ } else {
+ curcol = cols
+ }
+
+ } else {
+ curcol = col
+ }
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/psslide.x b/pkg/utilities/nttools/tedit/display/screen/psslide.x
new file mode 100644
index 00000000..5ad0bc5d
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/psslide.x
@@ -0,0 +1,182 @@
+include "../curses.h"
+
+# PS_SLIDE -- Slide a rectangle on the screen
+#
+# B.Simon 19-Jan-89 Original
+# B.Simon 26-Sep-90 Updated to use screen buffer
+# B.Simon 22-Mar-91 Fix error in left & right slides
+
+bool procedure ps_slide (source, dir, dist)
+
+int source[RSIZE] # i: Rectangle
+int dir # i: Direction (from curses.h)
+int dist # i: Distance (> 0)
+#--
+include "screen.com"
+
+char blank
+int dest[RSIZE]
+int nrows, ncols, irow, icol
+pointer oldscr, newscr, linscr
+
+data blank / ' ' /
+
+bool ps_intersect(), ttygetb()
+pointer ps_screen()
+
+begin
+ if (! ps_intersect (source, lines, cols, dest))
+ return (true)
+
+ ncols = RWIDTH(dest)
+ nrows = RHEIGHT(dest)
+
+ switch (dir) {
+ case DIR_UP:
+ if (RLEFT(dest) != 1 || RRIGHT(dest) != cols)
+ return (false)
+ if ( !(ttygetb (term, "al") && ttygetb (term, "dl")))
+ return (false)
+
+ call ps_setcur (max (1, RTOP(dest)-dist), 1)
+ do irow = 1, dist
+ call ps_sendcap ("dl", lines - RTOP(dest) + dist)
+
+ if (RBOT(dest) < lines) {
+ call ps_setcur (RBOT(dest) + 1, 1)
+ do irow = 1, dist
+ call ps_sendcap ("al", lines - RBOT(dest))
+ }
+
+ oldscr = ps_screen (RTOP(dest), 1)
+ newscr = ps_screen (RTOP(dest)-dist, 1)
+ do irow = 1, nrows-dist {
+ if (newscr >= termscr)
+ call amovc (Memc[oldscr], Memc[newscr], ncols)
+ oldscr = oldscr + cols
+ newscr = newscr + cols
+ }
+ do irow = 1, dist {
+ if (newscr < (termscr + lines * cols))
+ call amovkc (blank, Memc[newscr], ncols)
+ newscr = newscr + cols
+ }
+
+ case DIR_DOWN:
+ if (RLEFT(dest) != 1 || RRIGHT(dest) != cols)
+ return (false)
+ if ( !(ttygetb (term, "al") && ttygetb (term, "dl")))
+ return (false)
+
+ call ps_setcur (min (lines, RBOT(dest)+1), 1)
+ do irow = 1, dist
+ call ps_sendcap ("dl", lines - RBOT(dest))
+
+ call ps_setcur (RTOP(dest), 1)
+ do irow = 1, dist
+ call ps_sendcap ("al", lines - RTOP(dest))
+
+ oldscr = ps_screen (RBOT(dest), 1)
+ newscr = ps_screen (RBOT(dest)+dist, 1)
+ do irow = 1, nrows-dist {
+ if (newscr < (termscr + lines * cols))
+ call amovc (Memc[oldscr], Memc[newscr], ncols)
+ oldscr = oldscr - cols
+ newscr = newscr - cols
+ }
+ do irow = 1, dist {
+ if (newscr >= termscr)
+ call amovkc (blank, Memc[newscr], ncols)
+ newscr = newscr - cols
+ }
+
+ case DIR_LEFT:
+ if (! ((ttygetb (term, "ic") || ttygetb (term, "im")) &&
+ ttygetb (term, "dc")))
+ return (false)
+
+ do irow = RTOP(dest), RBOT(dest) {
+
+ call ps_setcur (irow, max (1, RLEFT(dest)-dist))
+ call ps_sendcap ("dm", 1)
+ do icol = 1, dist
+ call ps_sendcap ("dc", 1)
+ call ps_sendcap ("ed", 1)
+
+ if (RRIGHT(dest) < cols) {
+ call ps_setcur (irow, RRIGHT(dest) - dist + 1)
+ call ps_sendcap ("im", 1)
+ do icol = 1, dist {
+ call ps_sendcap ("ic", 1)
+ call ps_sendcap ("ip", 1)
+ call putc (ttyout, blank)
+ }
+ call ps_sendcap ("ei", 1)
+ call ps_updcur (irow, RRIGHT(dest) + 1)
+ }
+
+ linscr = ps_screen (irow,1)
+ oldscr = ps_screen (irow,RLEFT(dest))
+ newscr = oldscr - dist
+
+ do icol = 1, ncols-dist+1 {
+ if (newscr >= linscr)
+ Memc[newscr] = Memc[oldscr]
+ oldscr = oldscr + 1
+ newscr = newscr + 1
+ }
+
+ do icol = 1, dist {
+ if (newscr < linscr + cols)
+ Memc[newscr] = blank
+ newscr = newscr + 1
+ }
+ }
+ case DIR_RIGHT:
+ if (! ((ttygetb (term, "ic") || ttygetb (term, "im")) &&
+ ttygetb (term, "dc")))
+ return (false)
+
+ do irow = RTOP(dest), RBOT(dest) {
+
+ if (RRIGHT(dest) < cols - 1) {
+ call ps_setcur (irow, RRIGHT(dest) + 1)
+ call ps_sendcap ("dm", 1)
+ do icol = 1, dist
+ call ps_sendcap ("dc", 1)
+ call ps_sendcap ("ed", 1)
+ }
+
+ call ps_setcur (irow, RLEFT(dest))
+ call ps_sendcap ("im", 1)
+ do icol = 1, dist {
+ call ps_sendcap ("ic", 1)
+ call ps_sendcap ("ip", 1)
+ call putc (ttyout, blank)
+ }
+ call ps_sendcap ("ei", 1)
+ call ps_updcur (irow, RLEFT(dest) + dist)
+
+ linscr = ps_screen (irow,1)
+ oldscr = ps_screen (irow,RRIGHT(dest))
+ newscr = oldscr + dist
+
+ do icol = 1, ncols-dist+1 {
+ if (newscr < linscr + cols)
+ Memc[newscr] = Memc[oldscr]
+ oldscr = oldscr - 1
+ newscr = newscr - 1
+ }
+
+ do icol = 1, dist {
+ if (newscr >= linscr)
+ Memc[newscr] = blank
+ newscr = newscr - 1
+ }
+ }
+ default:
+ return (false)
+ }
+
+ return (true)
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/pssynch.x b/pkg/utilities/nttools/tedit/display/screen/pssynch.x
new file mode 100644
index 00000000..a91474c8
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/pssynch.x
@@ -0,0 +1,12 @@
+# PS_SYNCH -- Bring screen up to date
+#
+# B.Simon 18-Jan-89 Original
+
+procedure ps_synch ()
+
+#--
+include "screen.com"
+
+begin
+ call flush (ttyout)
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/pswidth.x b/pkg/utilities/nttools/tedit/display/screen/pswidth.x
new file mode 100644
index 00000000..d06a190c
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/pswidth.x
@@ -0,0 +1,12 @@
+# PS_WIDTH -- Get width of physical screen
+#
+# B.Simon 18-Jan-89 Original
+
+int procedure ps_width ()
+
+#--
+include "screen.com"
+
+begin
+ return (cols)
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/pswrite.x b/pkg/utilities/nttools/tedit/display/screen/pswrite.x
new file mode 100644
index 00000000..ea8de0af
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/pswrite.x
@@ -0,0 +1,79 @@
+include <ctype.h>
+include "../curses.h"
+
+# PS_WRITE -- Write a string on the physical screen
+#
+# B.Simon 18-Jan-89 Original
+# B.Simon 26-Sep-90 Updated to use screen buffer
+
+procedure ps_write (row, col, ncols, str, att)
+
+int row # i: Starting row
+int col # i: Starting column
+int ncols # i: Number of columns to write
+char str[ARB] # i: String to write
+int att # i: Attribute
+#--
+include "screen.com"
+
+char blank
+int colstart, colend, idxstart, idxend, idx
+pointer scr
+
+data blank / ' ' /
+
+bool ttygetb()
+int strlen()
+pointer ps_screen()
+
+begin
+ # Don't try to print if string is entirely off the screen
+
+ if (row < 1 || row > lines || col > cols)
+ return
+
+ # Compute the portion of the string that is on the screen
+
+ colstart = max (col, 1)
+ colend = min (ncols, strlen(str)) + col - 1
+ colend = min (colend, cols)
+
+ if (colend == cols && row == lines) {
+ if (ttygetb (term, "am"))
+ colend = colend - 1
+ }
+
+ if (colend < colstart)
+ return
+
+ idxstart = colstart - col + 1
+ idxend = colend - col + 1
+
+ # Move the cursor to the position of the first printed character
+
+ call ps_setcur (row, colstart)
+
+ # Print the string with the proper attribute
+ # All non-printing characters are printed as blanks
+
+ if (att != A_NORM)
+ call ps_sendcap ("so", 1)
+
+ scr = ps_screen (row, colstart)
+ do idx = idxstart, idxend {
+ if (IS_PRINT(str[idx])) {
+ call putc (ttyout, str[idx])
+ Memc[scr] = str[idx] + att
+ } else {
+ call putc (ttyout, blank)
+ Memc[scr] = blank + att
+ }
+ scr = scr + 1
+ }
+
+ if (att != A_NORM)
+ call ps_sendcap ("se", 1)
+
+ call ps_updcur (row, colend + 1)
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/pswrtcells.x b/pkg/utilities/nttools/tedit/display/screen/pswrtcells.x
new file mode 100644
index 00000000..0e080121
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/pswrtcells.x
@@ -0,0 +1,114 @@
+include <ctype.h>
+include "../curses.h"
+
+# PS_WRTCELLS -- Write a vector of cells
+#
+# B.Simon 19-Jan-89 Original
+# B.Simon 26-Sep-90 Updated to use screen buffer
+
+procedure ps_wrtcells (row, col, vector, ncols)
+
+int row # i: Starting row
+int col # i: Starting column
+char vector[ARB] # i: Vector to write
+int ncols # i: Number of columns to write
+#--
+include "screen.com"
+
+char blank, att, ch
+int colstart, colend, idxstart, idxend, idx
+pointer scr
+
+data blank / ' ' /
+
+bool ttygetb()
+pointer ps_screen()
+
+begin
+ # Don't try to print if vector is entirely off the screen
+
+ if (row < 1 || row > lines || col > cols)
+ return
+
+ # Compute the portion of the vector that is on the screen
+
+ colstart = max (col, 1)
+ colend = min (ncols + col - 1, cols)
+
+ if (colend == cols && row == lines) {
+ if (ttygetb (term, "am"))
+ colend = colend - 1
+ }
+
+ idxstart = colstart - col + 1
+ idxend = colend - col + 1
+
+ # Adjust string start and end so that portions that
+ # duplicate the current screen contents are not printed
+
+ scr = ps_screen (row, colend)
+ while (idxend >= idxstart) {
+ if (vector[idxend] != Memc[scr])
+ break
+
+ colend = colend - 1
+ idxend = idxend - 1
+ scr = scr - 1
+ }
+
+ scr = ps_screen (row, colstart)
+ while (idxstart <= idxend) {
+ if (vector[idxstart] != Memc[scr])
+ break
+
+ colstart = colstart + 1
+ idxstart = idxstart + 1
+ scr = scr + 1
+ }
+
+ if (colend < colstart)
+ return
+
+ # Move the cursor to the position of the first printed character
+
+ call ps_setcur (row, colstart)
+
+ # Print the vector
+
+ att = 0
+ do idx = idxstart, idxend {
+
+ # Set the proper attribute
+
+ if (vector[idx] < A_STANDOUT) {
+ ch = vector[idx]
+ if (att != 0) {
+ att = 0
+ call ps_sendcap ("se", 1)
+ }
+ } else {
+ ch = vector[idx] - A_STANDOUT
+ if (att == 0) {
+ att = vector[idx] - ch
+ call ps_sendcap ("so", 1)
+ }
+ }
+
+ # Print non-printing character as blank
+
+ if (IS_PRINT(ch)) {
+ call putc (ttyout, ch)
+ Memc[scr] = ch + att
+ } else {
+ call putc (ttyout, blank)
+ Memc[scr] = blank + att
+ }
+ scr = scr + 1
+ }
+
+ if (att != 0)
+ call ps_sendcap ("se", 1)
+
+ call ps_updcur (row, colend + 1)
+
+end
diff --git a/pkg/utilities/nttools/tedit/display/screen/screen.com b/pkg/utilities/nttools/tedit/display/screen/screen.com
new file mode 100644
index 00000000..5a13cd02
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/display/screen/screen.com
@@ -0,0 +1,18 @@
+# SCREEN.COM -- Global variables used by the screen routines
+
+pointer keytab # Table of function key sequences
+pointer termscr # Copy of terminal screen contents
+pointer htext # Function key help text
+pointer term # The termcap data structure
+int ttyin # Input file descriptor for the terminal
+int ttyout # Output file descriptor for the terminal
+int lines # The number of lines on the screen
+int cols # The number of columns on the screen
+int currow # Cursor row
+int curcol # Cursor column
+int keych # Pushed back keyboard character
+char ks[7] # Initialize keypad sequence
+char ke[7] # Terminate keypad sequence
+
+common /screen/ keytab, termscr, htext, ttyin, ttyout, term,
+ lines, cols, currow, curcol, keych, ks, ke
diff --git a/pkg/utilities/nttools/tedit/edit.x b/pkg/utilities/nttools/tedit/edit.x
new file mode 100644
index 00000000..8fe14a87
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/edit.x
@@ -0,0 +1,70 @@
+include "command.h"
+
+# EDIT -- Main procedure of table editor
+
+procedure edit (table, columns, silent, rdonly, inplace)
+
+char table[ARB] # i: SDAS table name
+char columns[ARB] # i: list of columns to edit
+bool silent # i: don't ring bell when error occurs
+bool rdonly # i: edit table read only
+bool inplace # i: edit table in place
+#--
+int nargs, code
+pointer sp, scr, command, arglist
+
+begin
+ call smark (sp)
+ call salloc (command, SZ_LINE, TY_CHAR)
+ call salloc (arglist, SZ_LINE, TY_CHAR)
+
+ call init_cmd (silent)
+ call init_screen (table, columns, rdonly, inplace, scr)
+ call help_prompt (scr, NO)
+
+ repeat {
+ call edit_screen (scr)
+ call read_prompt ("Command:", Memc[command], SZ_LINE)
+ call parse_cmd (Memc[command], code, nargs, Memc[arglist], SZ_LINE)
+
+ if (nargs > 0) {
+ switch (code) {
+ case TED_ADD:
+ call add_cmd (scr, nargs, Memc[arglist])
+ case TED_COPY:
+ call copy_cmd (scr, nargs, Memc[arglist])
+ case TED_DELETE:
+ call delete_cmd (scr, nargs, Memc[arglist])
+ case TED_EXIT:
+ call exit_cmd (scr, nargs, Memc[arglist])
+ break
+ case TED_FIND:
+ call find_cmd (scr, nargs, Memc[arglist])
+ case TED_GOTO:
+ call goto_cmd (scr, nargs, Memc[arglist])
+ case TED_HELP:
+ call help_cmd (scr, nargs, Memc[arglist])
+ case TED_INSERT:
+ call insert_cmd (scr, nargs, Memc[arglist])
+ case TED_LOWER:
+ call lower_cmd (scr, nargs, Memc[arglist])
+ case TED_NEXT:
+ call next_cmd (scr, nargs, Memc[arglist])
+ case TED_QUIT:
+ call quit_cmd (scr, nargs, Memc[arglist])
+ break
+ case TED_SET:
+ call set_cmd (scr, nargs, Memc[arglist])
+ case TED_SUBSTITUTE:
+ call sub_cmd (scr, nargs, Memc[arglist])
+ case TED_UPPER:
+ call upper_cmd (scr, nargs, Memc[arglist])
+ default:
+ call help_prompt (scr, YES)
+ }
+ }
+ }
+
+ call end_screen
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tedit/field.h b/pkg/utilities/nttools/tedit/field.h
new file mode 100644
index 00000000..4a74799c
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/field.h
@@ -0,0 +1,23 @@
+# FIELD.H -- Tedit field descriptor
+
+define TED_FLDLEN 11 # field descriptor length
+
+define TED_FSCREEN Memi[$1] # screen associated with field
+define TED_RDOFLD Memi[$1+1] # is this a read only field?
+define TED_PGSIZE Memi[$1+2] # number of rows on screen
+define TED_LSTROW Memi[$1+3] # last row in table
+define TED_LSTCOL Memi[$1+4] # last column in table
+define TED_NXTROW Memi[$1+5] # next row to edit
+define TED_NXTCOL Memi[$1+6] # next column to edit
+define TED_DIRECT Memi[$1+7] # direction of motion
+define TED_FINDEX Memi[$1+8] # column index
+define TED_MRKFLD Memi[$1+9] # has this field been changed?
+define TED_COMMAND Memi[$1+10] # has command key been pressed?
+
+define SZ_FIELD 512 # Maximum length of a single field
+
+# The following are the legal alignments (used by align_field and move_field)
+
+define LEFT 1
+define CENTER 2
+define RIGHT 3
diff --git a/pkg/utilities/nttools/tedit/field.x b/pkg/utilities/nttools/tedit/field.x
new file mode 100644
index 00000000..5fecad11
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/field.x
@@ -0,0 +1,749 @@
+include <tbset.h>
+include <lexnum.h>
+include <mach.h>
+include <ctype.h>
+include "display/curses.h"
+include "screen.h"
+include "table.h"
+include "field.h"
+
+# FIELD -- Procedures which manipulate a single field (table element)
+
+# ADD_FIELD -- Add a new field to the table and screen
+
+procedure add_field (scr, tabrow, tabcol)
+
+pointer scr # u: screen descriptor
+int tabrow # i: new table row
+int tabcol # i: new table column
+#--
+char blank
+int win, nrows, ncols, row, col, irow, icol, junk, hitab, ic
+pointer tab, tptr, sp, line, temp
+
+data blank / ' ' /
+
+int tbpsta(), itoc()
+
+begin
+ # Get window and table pointers from screen descriptor
+
+ win = TED_WINDOW(scr)
+ tab = TED_TABLE(scr)
+ tptr = TED_TABPTR(tab)
+
+ # Get dimensions of window and table
+
+ call wdimen (win, nrows, ncols)
+ call pos_field (scr, 1, row, col)
+ hitab = tbpsta (tptr, TBL_NROWS)
+
+ # Add new row to table
+
+ call tbtwer (tptr, tabrow)
+ TED_DIRTY(tab) = YES
+
+ # Update current row and column
+
+ TED_CURROW(scr) = tabrow
+ TED_CURCOL(scr) = tabcol
+
+ # If new row is off screen, redraw screen
+
+ if (row >= nrows || col >= ncols) {
+ call move_screen (scr, LEFT, YES)
+ return
+ }
+
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (line, ncols+1,TY_CHAR)
+ call salloc (temp, SZ_LINE, TY_CHAR)
+
+ # Copy table elements to text line
+ # and write the line on the screen
+
+ call wmove (win, row+1, 1)
+ do irow = hitab+1, tabrow {
+ junk = itoc (irow, Memc[temp], SZ_LINE)
+ call align_field (RIGHT, blank, Memc[temp],
+ Memc[line], TED_LABWIDTH(tab))
+
+ ic = TED_LABWIDTH(tab)
+ do icol = TED_LOCOL(scr), TED_HICOL(scr) {
+ Memc[line+ic] = ' '
+ ic = ic + 1
+
+ call tbegtt (tptr, TED_COLPTR(tab,icol), irow,
+ Memc[temp], SZ_LINE)
+
+ call align_field (LEFT, blank, Memc[temp], Memc[line+ic],
+ TED_COLLEN(tab,icol))
+ ic = ic + TED_COLLEN(tab,icol)
+ }
+
+ Memc[line+ic] = '\n'
+ Memc[line+ic+1] = EOS
+ call waddstr (win, Memc[line])
+ }
+
+ # Move cursor to current field and refresh window
+
+ TED_HIROW(scr) = tabrow
+ call move_field (scr)
+
+ call wrefresh (win)
+ call sfree (sp)
+
+end
+
+# ALIGN_FIELD -- Align a string within a larger field
+
+procedure align_field (align, fill, instr, outstr, outlen)
+
+int align # i: alignment of output string
+char fill # i: fill character
+char instr[ARB] # i: input string
+char outstr[ARB] # o: output string
+int outlen # i: length of output string
+#--
+int ibeg, iend, inlen, jbeg, jend, ic, jc, kc
+
+begin
+ # Get the first and last characters in the string
+ # which are not fill characters
+
+ ibeg = 0
+ iend = 0
+ for (ic = 1; instr[ic] != EOS; ic = ic + 1) {
+ if (instr[ic] != fill) {
+ if (ibeg == 0)
+ ibeg = ic
+ iend = ic
+ }
+ }
+ ibeg = max (ibeg, 1)
+ inlen = (iend - ibeg) + 1
+
+ # Check the length of the input string to see
+ # if the alignment problem is trivial
+
+ if (inlen >= outlen) {
+ call strcpy (instr[ibeg], outstr, outlen)
+ return
+ }
+
+ # Calculate the number of fill characters to add at
+ # the beginning and end of the string
+
+ switch (align) {
+ case LEFT:
+ jbeg = 0
+ jend = outlen - inlen
+
+ case CENTER:
+ jbeg = (outlen - inlen) / 2
+ jend = outlen - inlen - jbeg
+
+ case RIGHT:
+ jbeg = outlen - inlen
+ jend = 0
+ }
+
+ # Create the output string
+
+ for (jc = 1; jc <= jbeg; jc = jc + 1)
+ outstr[jc] = fill
+
+ for (ic = ibeg; ic <= iend; ic = ic + 1) {
+ outstr[jc] = instr[ic]
+ jc = jc + 1
+ }
+
+ for (kc = 1; kc <= jend; kc = kc + 1) {
+ outstr[jc] = fill
+ jc = jc + 1
+ }
+
+ outstr[jc] = EOS
+end
+
+# CHECK_FIELD -- Check string to see if it has the correct data type
+
+bool procedure check_field (datatype, field)
+
+int datatype # i: Datatype to check
+char field[ARB] # i: String to be checked
+#--
+bool match
+double fieldval
+int ic, nc, lextype, fieldtype
+pointer sp, temp
+
+string yorn "|yes|no|"
+
+bool streq()
+int strlen(), lexnum(), ctod(), strdic()
+
+begin
+ call smark (sp)
+ call salloc (temp, SZ_LINE, TY_CHAR)
+
+ if (datatype < 0)
+
+ # The only check on string types is that they not exceed their
+ # maximum length
+
+ match = strlen (field) <= -(datatype)
+
+ else {
+
+ # Get the data type of the string
+ # Reduce this to character, integer or real
+ # Get the value of the string if it is not character
+
+ if (streq (field, "INDEF")) {
+ fieldtype = datatype
+ fieldval = 0.0
+
+ } else {
+ ic = 1
+ lextype = lexnum (field, ic, nc)
+
+ for (ic = ic + nc; IS_WHITE(field[ic]); ic = ic + 1)
+ ;
+ if (field[ic] != EOS)
+ lextype = LEX_NONNUM
+
+ if (lextype == LEX_HEX || lextype == LEX_NONNUM) {
+ fieldtype = TY_CHAR
+ fieldval = 0.0
+ } else {
+ if (lextype == LEX_REAL)
+ fieldtype = TY_REAL
+ else
+ fieldtype = TY_INT
+
+ ic = 1
+ nc = ctod (field, ic, fieldval)
+ fieldval = abs (fieldval)
+ }
+ }
+
+ # See if the string matches the expected datatype
+
+ switch (datatype) {
+ case TY_BOOL:
+ match = strdic (field, Memc[temp], SZ_LINE, yorn) > 0
+ case TY_CHAR:
+ match = strlen (field) <= 1
+ case TY_SHORT:
+ match = fieldtype == TY_INT && fieldval <= MAX_SHORT
+ case TY_INT:
+ match = fieldtype == TY_INT && fieldval <= MAX_INT
+ case TY_LONG:
+ match = fieldtype == TY_INT && fieldval <= MAX_LONG
+ case TY_REAL:
+ match = fieldtype != TY_CHAR && fieldval <= MAX_REAL
+ case TY_DOUBLE:
+ match = fieldtype != TY_CHAR && fieldval <= MAX_DOUBLE
+ default:
+ match = true
+ }
+ }
+
+ call sfree (sp)
+ return (match)
+end
+
+# DRAW_FIELD -- Draw a single field on the screen
+
+procedure draw_field (scr)
+
+pointer scr # i: screen descriptor
+#--
+char blank
+pointer sp, value, field, tab
+int win, tabrow, tabcol, row, col, orow, ocol
+
+data blank / ' ' /
+
+int winstat()
+
+begin
+ # Allocate dynamic memory to hold string
+
+ call smark (sp)
+ call salloc (value, SZ_FIELD, TY_CHAR)
+ call salloc (field, SZ_FIELD, TY_CHAR)
+
+ # Get current value
+
+ win = TED_WINDOW(scr)
+ tab = TED_TABLE(scr)
+
+ tabrow = TED_CURROW(scr)
+ tabcol = TED_CURCOL(scr)
+
+ call tbegtt (TED_TABPTR(tab), TED_COLPTR(tab,tabcol),
+ tabrow, Memc[value], SZ_FIELD)
+
+ call align_field (LEFT, blank, Memc[value],
+ Memc[field], TED_COLLEN(tab,tabcol))
+
+ # Redraw field and reposition cursor
+
+ orow = winstat (win, W_CURROW)
+ ocol = winstat (win, W_CURCOL)
+
+ call pos_field (scr, 1, row, col)
+ call wmove (win, row, col)
+
+ call waddstr (win, Memc[field])
+ call wmove (win, orow, ocol)
+
+ call sfree (sp)
+end
+
+# EDIT_FIELD -- Interactively edit a table field
+
+procedure edit_field (win, field, maxch)
+
+int win # i: Window descriptor
+char field[ARB] # u: Table field
+int maxch # i: Maximum line length
+#--
+int row, col, ch, ic, jc, mc, nc
+pointer sp, data, buffer
+
+string nowrite "Cannot change field: table is read only"
+string fullfld "Cannot undelete word: not enough room in field"
+
+int strlen(), k_get(), winstat()
+
+begin
+ call wgetstruct (win, data)
+
+ nc = strlen (field)
+ ic = min (TED_FINDEX(data) - 1, nc)
+
+ row = winstat (win, W_CURROW)
+ col = winstat (win, W_CURCOL) - ic
+
+ call smark (sp)
+ call salloc (buffer, SZ_FIELD, TY_CHAR)
+ Memc[buffer] = EOS
+
+ TED_COMMAND(data) = NO
+
+ repeat {
+
+ # Read character from keyboard
+
+ call ps_synch
+ ch = k_get ()
+
+ if (ch < K_BASE) {
+ # Move to next field down
+
+ if (ch == '\r') {
+ TED_DIRECT(data) = LEFT
+ TED_NXTROW(data) = TED_NXTROW(data) + 1
+ break
+
+ # Move to next field across
+
+ } else if (ch == '\t') {
+ if (TED_NXTCOL(data) < TED_LSTCOL(data)) {
+ TED_DIRECT(data) = LEFT
+ TED_NXTCOL(data) = TED_NXTCOL(data) + 1
+ break
+ }
+
+ # Insert character at current position
+
+ } else if (TED_RDOFLD(data) == NO) {
+
+ # Check to see if field is full, if so, truncate
+
+ if (nc >= maxch) {
+ nc = maxch - 1
+ field[nc+1] = EOS
+ if (ic > nc) {
+ ic = nc
+ call wmove (win, row, col+ic)
+ }
+ }
+
+ ic = ic + 1
+ nc = nc + 1
+ TED_MRKFLD(data) = YES
+
+ if (ic == nc) {
+ field[ic] = ch
+ field[ic+1] = EOS
+ call waddstr (win, field[ic])
+
+ } else {
+ do jc = nc, ic, -1
+ field[jc+1] = field[jc]
+
+ field[ic] = ch
+ call waddstr (win, field[ic])
+ call wmove (win, row, col+ic)
+ }
+
+ # Print warning message, read_only field
+
+ } else {
+ call warn1_prompt (TED_FSCREEN(data), nowrite)
+ }
+
+ } else {
+ switch (ch) {
+ case K_UP: # Move up one field
+ if (TED_NXTROW(data) > 1) {
+ TED_DIRECT(data) = CENTER
+ TED_NXTROW(data) = TED_NXTROW(data) - 1
+ break
+ }
+
+ case K_DOWN: # Move down one field
+ if (TED_NXTROW(data) < TED_LSTROW(data)) {
+ TED_DIRECT(data) = CENTER
+ TED_NXTROW(data) = TED_NXTROW(data) + 1
+ break
+ }
+ case K_RIGHT: # Move right one column
+ if (ic < nc) {
+ ic = ic + 1
+ call wmove (win, row, col+ic)
+
+ } else if (TED_NXTCOL(data) < TED_LSTCOL(data)) {
+ TED_DIRECT(data) = LEFT
+ TED_NXTCOL(data) = TED_NXTCOL(data) + 1
+ break
+ }
+
+ case K_LEFT: # Move left one column
+ if (ic > 0) {
+ ic = ic - 1
+ call wmove (win, row, col+ic)
+
+ } else if (TED_NXTCOL(data) > 1) {
+ TED_DIRECT(data) = RIGHT
+ TED_NXTCOL(data) = TED_NXTCOL(data) - 1
+ break
+ }
+
+ case K_NEXTW: # Move forwards one field
+ if (TED_NXTCOL(data) < TED_LSTCOL(data)) {
+ TED_DIRECT(data) = LEFT
+ TED_NXTCOL(data) = TED_NXTCOL(data) + 1
+ break
+ }
+
+ case K_PREVW: # Move backwards one field
+ if (TED_NXTCOL(data) > 1) {
+ TED_DIRECT(data) = LEFT
+ TED_NXTCOL(data) = TED_NXTCOL(data) - 1
+ break
+ }
+
+ case K_NEXTP: # Move forwards one screen
+ if (TED_NXTROW(data) < TED_LSTROW(data)) {
+ TED_DIRECT(data) = LEFT
+ TED_NXTROW(data) = min (TED_LSTROW(data),
+ TED_NXTROW(data) + TED_PGSIZE(data))
+ break
+ }
+
+ case K_PREVP: # Move backwards one page
+ if (TED_NXTROW(data) > 1) {
+ TED_DIRECT(data) = LEFT
+ TED_NXTROW(data) = max (1,
+ TED_NXTROW(data) - TED_PGSIZE(data))
+ break
+ }
+
+ case K_HOME: # Move to first row
+ if (TED_NXTROW(data) > 1) {
+ TED_DIRECT(data) = LEFT
+ TED_NXTROW(data) = 1
+ break
+ }
+
+ case K_END: # Move to last row and column
+ if (TED_NXTROW(data) < TED_LSTROW(data)) {
+ TED_DIRECT(data) = LEFT
+ TED_NXTROW(data) = TED_LSTROW(data)
+ break
+ }
+
+ case K_BOL: # Move to first column in table
+ if (TED_NXTCOL(data) == 1) {
+ ic = 0
+ call wmove (win, row, col)
+
+ } else {
+ TED_DIRECT(data) = LEFT
+ TED_NXTCOL(data) = 1
+ break
+ }
+
+ case K_EOL: # Move to last column in table
+ if (TED_NXTCOL(data) == TED_LSTCOL(data)) {
+ ic = nc
+ call wmove (win, row, col+ic)
+
+ } else {
+ TED_DIRECT(data) = RIGHT
+ TED_NXTCOL(data) = TED_LSTCOL(data)
+ break
+ }
+
+ case K_DEL: # Delete character underneath cursor
+ if (TED_RDOFLD(data) == NO) {
+ if (ic < nc) {
+ TED_MRKFLD(data) = YES
+ mc = strlen (Memc[buffer])
+
+ Memc[buffer+mc] = field[ic+1]
+ Memc[buffer+mc+1] = EOS
+
+
+ do jc = ic+1, nc
+ field[jc] = field[jc+1]
+ field[nc] = ' '
+ field[nc+1] = EOS
+
+ call waddstr (win, field[ic+1])
+ field[nc] = EOS
+ nc = nc - 1
+
+ call wmove (win, row, col+ic)
+ }
+ } else {
+ call warn1_prompt (TED_FSCREEN(data), nowrite)
+ }
+
+ case K_BS: # Delete character to left of cursor
+ if (TED_RDOFLD(data) == NO) {
+ if (ic > 0) {
+ TED_MRKFLD(data) = YES
+ mc = strlen (Memc[buffer])
+
+ do jc = mc, 0, -1
+ Memc[buffer+jc+1] = Memc[buffer+jc]
+ Memc[buffer] = field[ic]
+
+ ic = ic - 1
+ call wmove (win, row, col+ic)
+
+ do jc = ic+1, nc
+ field[jc] = field[jc+1]
+ field[nc] = ' '
+ field[nc+1] = EOS
+
+ call waddstr (win, field[ic+1])
+ field[nc] = EOS
+ nc = nc - 1
+
+ call wmove (win, row, col+ic)
+ }
+ } else {
+ call warn1_prompt (TED_FSCREEN(data), nowrite)
+ }
+
+ case K_DWORD: # Delete entire field
+ if (TED_RDOFLD(data) == NO) {
+ if (nc > 0) {
+ TED_MRKFLD(data) = YES
+ call strcpy (field[ic+1], Memc[buffer], nc-ic)
+
+ do jc = ic+1, nc
+ field[jc] = ' '
+ field[nc+1] = EOS
+
+ call wmove (win, row, col+ic)
+ call waddstr (win, field[ic+1])
+
+ field[ic+1] = EOS
+ nc = ic
+
+ call wmove (win, row, col+ic)
+ }
+ } else {
+ call warn1_prompt (TED_FSCREEN(data), nowrite)
+ }
+
+ case K_DLINE: # Delete entire line (not supported)
+ call ring_bell
+
+ case K_UNDCHR: # Undelete a character
+ mc = strlen (Memc[buffer])
+ if (mc > 0) {
+ do jc = nc+1, ic+1, -1
+ field[jc+1] = field[jc]
+
+ field[ic+1] = Memc[buffer+mc-1]
+ Memc[buffer+mc-1] = EOS
+
+ call waddstr (win, field[ic+1])
+
+ ic = ic + 1
+ nc = nc + 1
+ call wmove (win, row, col+ic)
+ }
+
+ case K_UNDWRD: # Undelete a word
+ mc = strlen (Memc[buffer])
+ if ((mc + nc) > maxch) {
+ call warn1_prompt (TED_FSCREEN(data), fullfld)
+
+ } else if (mc > 0) {
+ call amovc (field[ic+1], field[ic+mc+1], nc-ic+1)
+ call amovc (Memc[buffer], field[ic+1], mc)
+
+ Memc[buffer] = EOS
+ call waddstr (win, field[ic+1])
+
+ ic = ic + mc
+ nc = nc + mc
+ call wmove (win, row, col+ic)
+ }
+
+ case K_UNDLIN: # Undelete a line (not supported)
+ call ring_bell
+
+ case K_HELP: # Display help screen
+ call help_screen (win)
+
+ case K_PAINT: # Force screen redraw
+ call clearok (STDSCR, true)
+ call wrefresh (STDSCR)
+ call focus_window (win)
+
+ case K_EXIT: # Exit procedure
+ TED_COMMAND(data) = YES
+ break
+
+ default:
+ call ring_bell
+ }
+ }
+ }
+
+ # Terminate field with EOS and push back character
+ # that terminated input
+
+ if (nc >= maxch)
+ ch = EOS
+
+ field[nc+1] = EOS
+ call k_pushbk (ch)
+
+ TED_FINDEX(data) = ic + 1
+
+end
+
+procedure move_field (scr)
+
+pointer scr # i: screen descriptor
+#--
+int row, col
+
+begin
+ # Calculate the screen row and column and move the cursor there
+
+ call pos_field (scr, TED_SCRIDX(scr), row, col)
+ call wmove (TED_WINDOW(scr), row, col)
+
+end
+
+# POS_FIELD -- Find the cursor position in a field
+
+procedure pos_field (scr, index, row, col)
+
+pointer scr # i: screen descriptor
+int index # i: index of character in current field
+int row # o: window row
+int col # o: window column
+#--
+int icol
+pointer tab
+
+begin
+ # Get the table assoicated with this screen
+
+ tab = TED_TABLE(scr)
+
+ # Calculate the screen row and column
+
+ row = TED_LABHEIGHT(tab) + 1 + TED_CURROW(scr) - TED_LOROW(scr)
+
+ col = TED_LABWIDTH(tab) + 1
+ do icol = TED_LOCOL(scr), TED_CURCOL(scr) - 1
+ col = col + TED_COLLEN(tab,icol) + 1
+
+ col = col + index
+end
+
+# TRIM_FIELD -- Remove leading and trailing blanks from field
+
+procedure trim_field (scr, rdonly, coltype, collen, field)
+
+pointer scr # i: screen descriptor
+int rdonly # i: read only table
+int coltype # i: column type
+int collen # i: column length
+char field[ARB] # u: field to trim
+#--
+int ibeg, iend, ic, jc
+
+string toolong "Field too long to display, editing will cause loss of data"
+int strlen()
+
+begin
+ if (coltype < 0) {
+ # Get the start and end of the string
+
+ ibeg = 1
+ iend = strlen (field)
+ if (iend > collen) {
+ iend = collen
+ if (rdonly == NO)
+ call write_prompt (scr, NO, toolong)
+ }
+
+ } else {
+ # Get the first and last characters in the string
+ # which are not blank
+
+ ibeg = 0
+ iend = 0
+ for (ic = 1; field[ic] != EOS; ic = ic + 1) {
+ if (field[ic] != ' ') {
+ if (ibeg == 0)
+ ibeg = ic
+ iend = ic
+ }
+ }
+ }
+
+ # Trim the field to the correct length
+
+ if (ibeg <= 1) {
+ jc = iend + 1
+ } else {
+ jc = 1
+ for (ic = ibeg; ic <= iend; ic = ic + 1) {
+ field[jc] = field[ic]
+ jc = jc + 1
+ }
+ }
+
+ field[jc] = EOS
+
+end
diff --git a/pkg/utilities/nttools/tedit/mkpkg b/pkg/utilities/nttools/tedit/mkpkg
new file mode 100644
index 00000000..6b187882
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/mkpkg
@@ -0,0 +1,27 @@
+# Update the tedit application code in the ttools package library.
+# Author: BSIMON, 1-APR-91
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ @display
+
+ bell.x
+ command.x "command.com" "command.h" "field.h" "paste.h" \
+ "table.h" "screen.h" <tbset.h>
+ edit.x "command.h"
+ field.x "field.h" "table.h" "screen.h" "display/curses.h" \
+ <ctype.h> <mach.h> <lexnum.h> <tbset.h>
+ paste.x "paste.h" "table.h" "screen.h" <tbset.h>
+ prompt.x "screen.h" "display/curses.h"
+ screen.x "field.h" "table.h" "screen.h" \
+ "display/curses.h" <tbset.h>
+ substitute.x <ctype.h>
+ table.x "field.h" "table.h" "screen.h" <tbset.h>
+ tedit.x
+ tread.x
+ window.x "window.com" "screen.h" "display/curses.h"
+ ;
diff --git a/pkg/utilities/nttools/tedit/paste.h b/pkg/utilities/nttools/tedit/paste.h
new file mode 100644
index 00000000..92d47fbd
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/paste.h
@@ -0,0 +1,6 @@
+# PASTE.H -- Tedit paste table descriptor
+
+define TED_PSTLEN 2 # paste descriptor length
+
+define TED_PSTPTR Memi[$1] # paste table pointer
+define TED_PSTROWS Memi[$1+1] # number of rows in paste table
diff --git a/pkg/utilities/nttools/tedit/paste.x b/pkg/utilities/nttools/tedit/paste.x
new file mode 100644
index 00000000..f4c9735d
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/paste.x
@@ -0,0 +1,142 @@
+include <tbset.h>
+include "screen.h"
+include "table.h"
+include "paste.h"
+
+define char_ 90 # goto label
+define EXTRA_SPACE 20 # extra row length & col descr space
+
+# CLS_PASTE -- Close the paste table and free the descriptor
+
+procedure cls_paste (scr)
+
+pointer scr # u: Screen descriptor
+#--
+pointer sp, fname, paste
+
+string nodelete "Could not delete paste table"
+
+begin
+ paste = TED_PASTE(scr)
+ if (paste == NULL)
+ return
+
+ call smark (sp)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+
+ call tbtnam (TED_PSTPTR(paste), Memc[fname], SZ_FNAME)
+ call tbtclo (TED_PSTPTR(paste))
+
+ iferr (call delete (Memc[fname]))
+ call warn2_prompt (scr, nodelete, Memc[fname])
+
+ call mfree (paste, TY_STRUCT)
+ TED_PASTE(scr) = NULL
+ call sfree (sp)
+
+end
+
+# MOVE_PASTE -- Move rows to or from the paste table
+
+procedure move_paste (itp, otp, irow, orow, ncopy)
+
+pointer itp # i: pointer to descriptor for input table
+pointer otp # i: pointer to descriptor for output table
+int irow # i: first row of input table to be copied
+int orow # i: row number of first output row
+int ncopy # i: number of rows to copy
+#--
+int jrow, krow
+
+begin
+ krow = orow
+ do jrow = irow, irow+ncopy-1 {
+ call tbrcpy (itp, otp, jrow, krow)
+ krow = krow + 1
+ }
+end
+
+# OPN_PASTE -- Open the paste table
+
+pointer procedure opn_paste (scr)
+
+pointer scr # u: Screen descriptor
+pointer paste # o: Paste descriptor
+#--
+int try, junk, ncol
+pointer sp, oldtab, newtab, newdir, tab, tp, pp
+pointer fname
+
+int tbpsta(), tbparse()
+pointer fnldir(), tbtopn()
+
+string nopaste "Cannot create paste table. Command aborted."
+
+begin
+ # Allocate dynamic memory for file names
+
+ call smark (sp)
+ call salloc (oldtab, SZ_FNAME, TY_CHAR)
+ call salloc (newtab, SZ_FNAME, TY_CHAR)
+ call salloc (newdir, SZ_FNAME, TY_CHAR)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+
+ # Get table name (used to build paste table name)
+
+ tab = TED_TABLE(scr)
+ tp = TED_TABPTR(tab)
+
+ call tbtnam (tp, Memc[oldtab], SZ_FNAME)
+ junk = tbparse (Memc[oldtab], Memc[fname], Memc[newdir], SZ_FNAME,
+ junk) # added by PEH, 1998 Apr 15
+ junk = fnldir (Memc[fname], Memc[newdir], SZ_FNAME)
+
+ # Try to open the paste table in the same directory as the
+ # temporary table. If this doesn't work, try the tmp$ directory
+
+ pp = NULL
+ do try = 1, 2 {
+ call strcat ("paste", Memc[newdir], SZ_FNAME)
+ call mktemp (Memc[newdir], Memc[newtab], SZ_FNAME)
+
+ ifnoerr (pp = tbtopn (Memc[newtab], NEW_COPY, tp))
+ break
+
+ call strcpy ("tmp$", Memc[newdir], SZ_FNAME)
+ }
+
+ if (pp == NULL) {
+ call warn1_prompt (scr, nopaste)
+ TED_PASTE(scr) = NULL
+ return (NULL)
+ }
+
+ # Set the parameters of the paste table, then create it
+
+ ncol = tbpsta (tp, TBL_MAXCOLS)
+
+ call tbpset (pp, TBL_WHTYPE, TBL_TYPE_S_ROW)
+ call tbpset (pp, TBL_INCR_ROWLEN, EXTRA_SPACE)
+ call tbpset (pp, TBL_MAXCOLS, ncol + EXTRA_SPACE)
+ call tbpset (pp, TBL_MAXPAR, 0) # no header parameters
+
+ iferr (call tbtcre (pp)) {
+ call warn1_prompt (scr, nopaste)
+ TED_PASTE(scr) = NULL
+ return (NULL)
+ }
+
+ # Create paste table descriptor
+
+ call malloc (paste, TED_PSTLEN, TY_STRUCT)
+ TED_PSTPTR(paste) = pp
+ TED_PSTROWS(paste) = 0
+
+ # Update the screen structure and return the paste descriptor
+
+ TED_PASTE(scr) = paste
+
+ call sfree (sp)
+ return (paste)
+
+end
diff --git a/pkg/utilities/nttools/tedit/prompt.x b/pkg/utilities/nttools/tedit/prompt.x
new file mode 100644
index 00000000..24d2be70
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/prompt.x
@@ -0,0 +1,225 @@
+include "display/curses.h"
+include "screen.h"
+
+# BOOL_PROMPT -- Get a yes or no response from the user
+
+bool procedure bool_prompt (msg)
+
+char msg[ARB] # i: message to print in the prompt area
+#--
+int index
+pointer sp, resp, msg2
+
+string yorn "|yes|no|"
+
+int strdic()
+
+begin
+ # Allocate memory for temporary strings
+
+ call smark (sp)
+ call salloc (resp, SZ_FNAME, TY_CHAR)
+ call salloc (msg2, SZ_LINE, TY_CHAR)
+
+ # Prompt the user for a response
+
+ call read_prompt (msg, Memc[resp], SZ_FNAME)
+ call strlwr (Memc[resp])
+
+ # See if the response is yes or no,
+ # if it isn't, keep asking
+
+ index = strdic (Memc[resp], Memc[resp], SZ_FNAME, yorn)
+ while (index == 0) {
+ call strcpy ("Please answer yes or no. ", Memc[msg2], SZ_LINE)
+ call strcat (msg, Memc[msg2], SZ_LINE)
+
+ call read_prompt (Memc[msg2], Memc[resp], SZ_FNAME)
+ call strlwr (Memc[resp])
+
+ index = strdic (Memc[resp], Memc[resp], SZ_FNAME, yorn)
+ }
+
+ # Convert result into boolean value
+
+ call sfree (sp)
+ return (index == 1)
+end
+
+# CLEAR_PROMPT -- Clear the prompt window
+
+procedure clear_prompt (scr)
+
+pointer scr # i: Currently active screen
+#--
+int win
+
+int prompt_window()
+
+begin
+ win = prompt_window ()
+ call werase (win)
+
+ if (scr != NULL)
+ call focus_window (TED_WINDOW(scr))
+
+end
+
+# ERR1_PROMPT -- Write an error message in the prompt area of the screen
+
+procedure err1_prompt (msg)
+
+char msg[ARB] # i: Message to write
+#--
+
+begin
+ call eprintf ("\r\n")
+ call error (1, msg)
+end
+
+# ERR2_PROMPT -- Write two error messages in the prompt area of the screen
+
+procedure err2_prompt (msg1, msg2)
+
+char msg1[ARB] # i: First message to write
+char msg2[ARB] # i: Second message to write
+#--
+pointer msg
+
+begin
+ call salloc (msg, SZ_LINE, TY_CHAR)
+
+ call sprintf (Memc[msg], SZ_LINE, "%s (%s)")
+ call pargstr (msg1)
+ call pargstr (msg2)
+
+ call eprintf ("\r\n")
+ call error (1, Memc[msg])
+
+end
+
+# HELP_PROMPT -- Write help message in prompt area
+
+procedure help_prompt (scr, bell)
+
+pointer scr # i: Screen descriptor
+int bell # i: Ring the bell after printing message?
+#--
+pointer sp, exit, msg
+
+string helpfmt "Type %s quit to leave editor, %s help for help."
+
+begin
+ call smark (sp)
+ call salloc (exit, SZ_FNAME, TY_CHAR)
+ call salloc (msg, SZ_LINE, TY_CHAR)
+
+ call k_eseq ("EXIT_UPDATE", Memc[exit], SZ_FNAME)
+
+ call sprintf (Memc[msg], SZ_LINE, helpfmt)
+ call pargstr (Memc[exit])
+ call pargstr (Memc[exit])
+
+ call write_prompt (scr, bell, Memc[msg])
+ call sfree (sp)
+end
+
+# READ_PROMPT -- Read a string from the prompt area of the screen
+
+procedure read_prompt (msg, str, maxch)
+
+char msg[ARB] # i: Prompt message
+char str[ARB] # o: Output string
+int maxch[ARB] # i: Maximum length of output string
+#--
+char blank
+int win
+
+data blank / ' ' /
+
+int prompt_window()
+
+begin
+ # Write message in prompt window
+
+ win = prompt_window ()
+
+ call werase (win)
+ call wmove (win, 2, 1)
+ call waddstr (win, msg)
+ call waddch (win, blank)
+
+ # Read string from prompt window
+
+ call wgetstr (win, str, maxch)
+ call werase (win)
+
+end
+
+# WARN1_PROMPT -- Write a warning message in the prompt area of the screen
+
+procedure warn1_prompt (scr, msg)
+
+pointer scr # i: Currently active screen
+char msg[ARB] # i: Message to write
+#--
+
+begin
+ call write_prompt (scr, YES, msg)
+end
+
+# WARN2_PROMPT -- Write two warning messages in the prompt area of the screen
+
+procedure warn2_prompt (scr, msg1, msg2)
+
+pointer scr # i: Currently active screen
+char msg1[ARB] # i: First message to write
+char msg2[ARB] # i: Second message to write
+#--
+pointer sp, msg
+
+begin
+ call smark (sp)
+ call salloc (msg, SZ_LINE, TY_CHAR)
+
+ call sprintf (Memc[msg], SZ_LINE, "%s (%s)")
+ call pargstr (msg1)
+ call pargstr (msg2)
+
+ call write_prompt (scr, YES, Memc[msg])
+
+ call sfree (sp)
+end
+
+# WRITE_PROMPT -- Write a message in the prompt area of the screen
+
+procedure write_prompt (scr, bell, msg)
+
+pointer scr # i: Currently active screen
+int bell # i: Ring bell after writing message?
+char msg[ARB] # i: Message to write
+#--
+int win
+
+int prompt_window()
+
+begin
+ # Write message in prompt window
+
+ win = prompt_window ()
+
+ call werase (win)
+ call wmove (win, 2, 1)
+ call waddstr (win, msg)
+
+ # Ring the bell to wake up the user
+
+ if (bell == YES)
+ call ring_bell
+
+ # Restore cursor to original screen position
+
+ if (scr != NULL)
+ call focus_window (TED_WINDOW(scr))
+
+end
diff --git a/pkg/utilities/nttools/tedit/screen.h b/pkg/utilities/nttools/tedit/screen.h
new file mode 100644
index 00000000..ec9c6fe4
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/screen.h
@@ -0,0 +1,18 @@
+# SCREEN.H -- Tedit screen descriptor
+
+define MAXSCR 10 # maximum number of screens
+
+define TED_SCRLEN 10 # screen descriptor length
+
+define TED_WINDOW Memi[$1] # window descriptor
+define TED_TABLE Memi[$1+1] # table descriptor (or NULL)
+define TED_PASTE Memi[$1+2] # paste table descriptor (or NULL)
+define TED_LOROW Memi[$1+3] # lowest row on screen
+define TED_HIROW Memi[$1+4] # highest row on screen
+define TED_LOCOL Memi[$1+5] # lowest column on screen
+define TED_HICOL Memi[$1+6] # highest column on the screen
+define TED_CURROW Memi[$1+7] # current row on the screen
+define TED_CURCOL Memi[$1+8] # current column on the screen
+define TED_SCRIDX Memi[$1+9] # current character within the field
+
+
diff --git a/pkg/utilities/nttools/tedit/screen.x b/pkg/utilities/nttools/tedit/screen.x
new file mode 100644
index 00000000..5fa3e892
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/screen.x
@@ -0,0 +1,699 @@
+include <tbset.h>
+include "display/curses.h"
+include "screen.h"
+include "table.h"
+include "field.h"
+
+define HELP_FILE "ttools$tedit/tedit.key"
+
+# SCREEN -- Procedures which manipulate screens
+
+# ADD_SCREEN -- Add a new screen
+
+procedure add_screen (scr, table, columns, rdonly, inplace)
+
+pointer scr # u: Screen descriptor
+char table[ARB] # i: SDAS table name
+char columns[ARB] # i: list of columns to edit
+bool rdonly # i: edit table read only
+bool inplace # i: edit table in place
+#--
+extern edit_field
+int iscr, jscr
+pointer oldscr, tab, win, field
+
+bool streq()
+int get_window()
+pointer map_table()
+
+begin
+ # See if the table is already bound to a screen
+
+ jscr = 0
+ for (iscr = 1; get_window (iscr, oldscr) != EOF; iscr = iscr + 1) {
+ tab = TED_TABLE(oldscr)
+ if (tab != NULL) {
+ if (streq (TED_TABNAME(tab), table)) {
+ jscr = iscr
+ break
+ }
+ }
+ }
+
+ # Get table structure from old screen, or create new structure
+
+ if (jscr != 0) {
+ TED_TABLE(scr) = TED_TABLE(oldscr)
+
+ TED_LOROW(scr) = TED_LOROW(oldscr)
+ TED_HIROW(scr) = TED_HIROW(oldscr)
+
+ TED_LOCOL(scr) = TED_LOCOL(oldscr)
+ TED_HICOL(scr) = TED_HICOL(oldscr)
+
+ TED_CURROW(scr) = TED_CURROW(oldscr)
+ TED_CURCOL(scr) = TED_CURCOL(oldscr)
+
+ } else {
+ TED_TABLE(scr) = map_table (scr, table, columns, rdonly, inplace)
+
+ TED_LOROW(scr) = 1
+ TED_HIROW(scr) = 1
+
+ TED_LOCOL(scr) = 1
+ TED_HICOL(scr) = 1
+
+ TED_CURROW(scr) = 1
+ TED_CURCOL(scr) = 1
+ }
+
+ TED_SCRIDX(scr) = 1
+ TED_PASTE(scr) = NULL
+
+ # Draw the new screen
+
+ call move_screen (scr, LEFT, YES)
+
+ # Create field structure and bind to window
+
+ call malloc (field, TED_FLDLEN, TY_STRUCT)
+
+ win = TED_WINDOW(scr)
+ call wbindstruct (win, edit_field, field)
+
+end
+
+# DEL_SCREEN -- Delete screen
+
+procedure del_screen (scr, force)
+
+pointer scr # i: Screen descriptor
+int force # i: Force table to be written
+#--
+int iscr, jscr
+pointer sp, msg, tab1, tab2, scr2, tptr
+
+bool bool_prompt()
+int get_window()
+
+begin
+ # Allocate dynamic memory for message
+
+ call smark (sp)
+ call salloc (msg, SZ_LINE, TY_CHAR)
+
+ # Close the paste table
+
+ call cls_paste (scr)
+
+ # Take no further action if no table is associated with this screen
+
+ if (TED_TABLE(scr) == NULL)
+ return
+
+ # See if this screen's table is associated with any other screen
+
+ jscr = 0
+ tab1 = TED_TABLE(scr)
+ tptr = TED_TABPTR(tab1)
+ TED_TABLE(scr) = NULL
+
+ jscr = 0
+ for (iscr = 1; get_window (iscr, scr2) != EOF; iscr = iscr + 1) {
+ tab2 = TED_TABLE(scr2)
+ if (tab2 != NULL && scr != scr2) {
+ if (tptr == TED_TABPTR(tab2)) {
+ jscr = iscr
+ break
+ }
+ }
+ }
+
+ # If not, close the table
+
+ if (jscr == 0) {
+ if (force == YES) {
+ call wrt_table (scr, tab1)
+
+ } else if (TED_DIRTY(tab1) == YES){
+ call sprintf (Memc[msg], SZ_LINE, "Write %s?")
+ call pargstr (TED_TABNAME(tab1))
+
+ if (bool_prompt (Memc[msg]))
+ call wrt_table (scr, tab1)
+ }
+
+ call unmap_table (scr, tab1, force)
+ }
+
+ call sfree (sp)
+end
+
+# DRAW_SCREEN -- Draw the screen on the terminal
+
+procedure draw_screen (scr)
+
+pointer scr # i: Screen descriptor
+#--
+char blank, uscore
+int height, width, ic, icol, irow, junk
+pointer sp, win, tab, tptr, line, temp
+
+data blank / ' ' /
+data uscore / '_' /
+
+string notable "No table associated with this screen"
+
+int gstrcpy(), itoc()
+
+begin
+ win = TED_WINDOW(scr)
+ call wdimen (win, height, width)
+
+ if (TED_TABLE(scr) == NULL)
+ call err1_prompt (notable)
+
+ tab = TED_TABLE(scr)
+ tptr = TED_TABPTR(tab)
+
+ call smark (sp)
+ call salloc (line, width+1,TY_CHAR)
+ call salloc (temp, SZ_LINE, TY_CHAR)
+
+ # Erase screen window and move cursor to start of window
+
+ call werase (win)
+ call wmove (win, 1, 1)
+
+ # Write top line of screen label
+
+ ic = gstrcpy ("Column", Memc[line], TED_LABWIDTH(tab))
+ do icol = TED_LOCOL(scr), TED_HICOL(scr) {
+ Memc[line+ic] = ' '
+ ic = ic + 1
+
+ junk = itoc (icol, Memc[temp], SZ_LINE)
+ call align_field (CENTER, blank, Memc[temp],
+ Memc[line+ic], TED_COLLEN(tab,icol))
+ ic = ic + TED_COLLEN(tab,icol)
+ }
+
+ Memc[line+ic] = '\n'
+ Memc[line+ic+1] = EOS
+ call waddstr (win, Memc[line])
+
+ # Write second line of screen label
+
+ ic = gstrcpy ("Label ", Memc[line], TED_LABWIDTH(tab))
+ do icol = TED_LOCOL(scr), TED_HICOL(scr) {
+ Memc[line+ic] = ' '
+ ic = ic + 1
+
+ call tbcigt (TED_COLPTR(tab,icol), TBL_COL_NAME,
+ Memc[temp], SZ_LINE)
+
+ call align_field (CENTER, uscore, Memc[temp],
+ Memc[line+ic], TED_COLLEN(tab,icol))
+ ic = ic + TED_COLLEN(tab,icol)
+ }
+
+ Memc[line+ic] = '\n'
+ Memc[line+ic+1] = EOS
+ call waddstr (win, Memc[line])
+
+ # Write the table elements a row at a time
+
+ do irow = TED_LOROW(scr), TED_HIROW(scr) {
+ junk = itoc (irow, Memc[temp], SZ_LINE)
+ call align_field (RIGHT, blank, Memc[temp],
+ Memc[line], TED_LABWIDTH(tab))
+
+ ic = TED_LABWIDTH(tab)
+ do icol = TED_LOCOL(scr), TED_HICOL(scr) {
+ Memc[line+ic] = ' '
+ ic = ic + 1
+
+ call tbegtt (tptr, TED_COLPTR(tab,icol), irow,
+ Memc[temp], SZ_LINE)
+
+ call align_field (LEFT, blank, Memc[temp], Memc[line+ic],
+ TED_COLLEN(tab,icol))
+ ic = ic + TED_COLLEN(tab,icol)
+ }
+
+ Memc[line+ic] = '\n'
+ Memc[line+ic+1] = EOS
+ call waddstr (win, Memc[line])
+
+ }
+
+ # Clear the prompt window
+
+ call clear_prompt (NULL)
+
+ # Move cursor to current field and refresh window
+
+ call move_field (scr)
+ call wrefresh (win)
+ call sfree (sp)
+end
+
+# EDIT_SCREEN -- Interactively edit the table bound to this screen
+
+procedure edit_screen (scr)
+
+pointer scr # i: Screen descriptor
+#--
+int win, row, col, ch
+pointer sp, field, tab, data
+
+string notable "No table associated with this screen"
+string badtype "Illegal data type for this field"
+string notadded "Cannot add row to read only table"
+
+bool check_field()
+int tbpsta(), strlen(), k_get()
+
+begin
+ # Allocate dynamic memory for table field
+
+ call smark (sp)
+ call salloc (field, SZ_FIELD, TY_CHAR)
+ Memc[field] = EOS
+
+ # Get window and table associated with screen
+
+ if (TED_TABLE(scr) == NULL)
+ call err1_prompt (notable)
+
+ win = TED_WINDOW(scr)
+ tab = TED_TABLE(scr)
+
+ # Initialize the field data structure
+
+ call wgetstruct (win, data)
+ TED_FSCREEN(data) = scr
+ TED_RDOFLD(data) = TED_READONLY(tab)
+ TED_PGSIZE(data) = TED_HIROW(scr) - TED_LOROW(scr) + 1
+ TED_LSTROW(data) = tbpsta (TED_TABPTR(tab), TBL_NROWS)
+ TED_LSTCOL(data) = TED_NCOLS(tab)
+ TED_NXTROW(data) = TED_CURROW(scr)
+ TED_NXTCOL(data) = TED_CURCOL(scr)
+ TED_DIRECT(data) = LEFT
+ TED_FINDEX(data) = 1
+ TED_MRKFLD(data) = NO
+ TED_COMMAND(data) = NO
+
+ # Edit fields until user presses the command key
+
+ while (TED_COMMAND(data) == NO) {
+
+ # Read the new field from the table
+
+ row = TED_NXTROW(data)
+ col = TED_NXTCOL(data)
+
+ call tbegtt (TED_TABPTR(tab), TED_COLPTR(tab,col), row,
+ Memc[field], SZ_FIELD)
+ call trim_field (scr, TED_READONLY(tab), TED_COLTYPE(tab,col),
+ TED_COLLEN(tab,col), Memc[field])
+
+ # Set the current row, column, and character
+
+ TED_CURROW(scr) = row
+ TED_CURCOL(scr) = col
+ if (TED_DIRECT(data) == LEFT)
+ TED_SCRIDX(scr) = 1
+ else if (TED_DIRECT(data) == RIGHT)
+ TED_SCRIDX(scr) = strlen(Memc[field]) + 1
+ else
+ TED_SCRIDX(scr) = min (TED_FINDEX(data),
+ strlen(Memc[field]) + 1)
+
+ call move_screen (scr, TED_DIRECT(data), NO)
+
+ # Get the new field value
+
+ TED_MRKFLD(data) = NO
+ TED_FINDEX(data) = TED_SCRIDX(scr)
+ call weditstr (win, Memc[field], TED_COLLEN(tab,col))
+
+ ch = k_get ()
+
+ # If the field has changed, check it and write it to the table
+
+ if (TED_MRKFLD(data) == YES) {
+
+ TED_DIRTY(tab) = YES
+ call tbeptt (TED_TABPTR(tab), TED_COLPTR(tab,col),
+ row, Memc[field])
+
+ # Redraw the field if it does not match the data type
+
+ if (! check_field (TED_COLTYPE(tab,col), Memc[field]))
+ call draw_field (scr)
+
+ }
+
+ # If the cursor has moved beyond the end of the table,
+ # add new rows
+
+ if (TED_NXTROW(data) > TED_LSTROW(data)) {
+ # Check for read only table
+ if (TED_READONLY(tab) == NO) {
+ call add_field (scr, TED_NXTROW(data), TED_NXTCOL(data))
+ TED_LSTROW(data) = TED_NXTROW(data)
+
+ } else {
+ call warn1_prompt (scr, notadded)
+
+ TED_NXTROW(data) = row
+ TED_NXTCOL(data) = col
+ TED_DIRECT(data) = LEFT
+ }
+ }
+ }
+
+ call sfree (sp)
+
+end
+
+# END_SCREEN -- Free all screens and their associated windows
+
+procedure end_screen ()
+
+#--
+
+begin
+ call endwin
+end
+
+# HELP_SCREEN -- Display the help screen
+
+procedure help_screen (win)
+
+int win # i: window that currently contains the cursor
+#--
+bool flag
+int fd, ic, helpwin, nrows, ncols, row, ihelp, key
+pointer sp, ch, eseq, label, name, msg, text
+
+int open(), getline(), newwin(), k_get()
+
+string title1 "The following commands are available after typing %s\n\n"
+string title2 "The following editing commands are available\n\n"
+string footer1 "\nPress any key to continue displaying commands\n"
+string footer2 "\nPress any key to resume editing\n"
+string hformat "%4w%-12.12s = %-12.12s"
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (eseq, SZ_FNAME, TY_CHAR)
+ call salloc (label, SZ_LINE/2, TY_CHAR)
+ call salloc (name, SZ_LINE/2, TY_CHAR)
+ call salloc (msg, SZ_LINE, TY_CHAR)
+
+ # Create help window
+
+ helpwin = newwin (GIANT, GIANT, 1, 1)
+ call wdimen (helpwin, nrows, ncols)
+
+ # Display list of commands
+
+ ifnoerr {
+ fd = open (HELP_FILE, READ_ONLY, TEXT_FILE)
+
+ } then {
+ call k_eseq ("EXIT_UPDATE", Memc[eseq], SZ_FNAME)
+ call sprintf (Memc[msg], SZ_LINE, title1)
+ call pargstr (Memc[eseq])
+
+ call waddstr (helpwin, Memc[msg])
+
+ # Read a line at a time from the file, pausing
+ # to page after a window full of information
+ # has been displayed
+
+ row = 3
+ while (getline (fd, Memc[msg]) != EOF) {
+ row = row + 1
+ if (row > nrows - 2) {
+ call waddstr (helpwin, footer1)
+
+ row = 1
+ call refresh
+ key = k_get ()
+ call werase (helpwin)
+ }
+ call waddstr (helpwin, Memc[msg])
+ }
+ call close (fd)
+
+ call waddstr (helpwin, footer1)
+ call refresh
+ key = k_get ()
+ }
+
+ # Construct the list of editing commands
+
+ call k_help (text)
+
+ call werase (helpwin)
+ call waddstr (helpwin, title2)
+
+ row = 3
+ ihelp = 0
+ flag = true
+
+ # Retrieve the command name and control sequence from the help
+ # structure. Write the information to the help window.
+
+ for (ch = text; Memc[ch] != EOS; ch = ch + 1) {
+ if (flag) {
+ if (Memc[ch] != '=') {
+ Memc[label+ic] = Memc[ch]
+ ic = ic + 1
+ } else {
+ Memc[label+ic] = EOS
+ flag = false
+ ic = 0
+ }
+ } else {
+ if (Memc[ch] != '\n') {
+ Memc[name+ic] = Memc[ch]
+ ic = ic + 1
+ } else {
+ Memc[name+ic] = EOS
+ ihelp = ihelp + 1
+ flag = true
+ ic = 0
+
+ call sprintf (Memc[msg], SZ_LINE, hformat)
+ call pargstr (Memc[label])
+ call pargstr (Memc[name])
+
+ call waddstr (helpwin, Memc[msg])
+
+ if (mod (ihelp, 2) == 0) {
+ call waddstr (helpwin, "\n")
+
+ row = row + 1
+ if (row >= nrows - 2) {
+ call waddstr (helpwin, footer1)
+
+ row = 1
+ call refresh
+ key = k_get ()
+ call werase (helpwin)
+ }
+ }
+ }
+ }
+ }
+
+ if (mod (ihelp, 2) == 1)
+ call waddstr (helpwin, "\n")
+ call waddstr (helpwin, footer2)
+
+ call refresh
+ key = k_get ()
+
+ # Delete the help window and restore cursor to current window
+
+ call delwin (helpwin)
+ call focus_window (win)
+
+ call sfree (sp)
+end
+
+# INIT_SCREEN -- Initialize the screen handling routines
+
+procedure init_screen (table, columns, rdonly, inplace, scr)
+
+char table[ARB] # i: SDAS table name
+char columns[ARB] # i: list of columns to edit
+bool rdonly # i: edit table read only
+bool inplace # i: edit table in place
+pointer scr # o: initial screen
+#--
+
+begin
+ # Initialize the window handling routines
+
+ call initscr
+
+ # Create the first (and default) screen
+
+ call init_window (scr)
+ call add_screen (scr, table, columns, rdonly, inplace)
+
+end
+
+# JOIN_SCREEN -- Remove this screen from the terminal display
+
+procedure join_screen (scr, force)
+
+pointer scr # u: Screen descriptor
+int force # i: Force screen to be written
+#--
+
+int count_window()
+
+begin
+ if (count_window () < 2)
+ return
+
+ call del_screen (scr, force)
+ call join_window (scr)
+
+end
+
+# MOVE_SCREEN -- Move the table (scroll) within the screen
+
+procedure move_screen (scr, align, force)
+
+pointer scr # i: screen descriptor
+int align # i: column alignment
+int force # i: force redraw
+#--
+int row, col, tabrows, tabcols, nrows, ncols, newrow, newcol, icol
+pointer sp, tab, errmsg
+
+string notable "No table associated with this screen"
+string badsize "Screen size error: t= %d b= %d l= %d r= %d"
+
+int tbpsta()
+
+begin
+ call smark (sp)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ if (TED_TABLE(scr) == NULL)
+ call err1_prompt (notable)
+
+ # First check whether field is currently on the screen
+
+ row = TED_CURROW(scr)
+ col = TED_CURCOL(scr)
+
+ if (row >= TED_LOROW(scr) && row <= TED_HIROW(scr) &&
+ col >= TED_LOCOL(scr) && col <= TED_HICOL(scr) && force == NO) {
+ call move_field (scr)
+ return
+ }
+
+ # Get dimensions of table and window
+
+ tab = TED_TABLE(scr)
+ tabrows = tbpsta (TED_TABPTR(tab), TBL_NROWS)
+ call wdimen (TED_WINDOW(scr), nrows, ncols)
+
+ if (row < TED_LOROW(scr) || row > TED_HIROW(scr)) {
+ newrow = max (1, row - (nrows - TED_LABHEIGHT(tab))/ 2)
+ } else {
+ newrow = TED_LOROW(scr)
+ }
+
+ if (col < TED_LOCOL(scr) || col > TED_HICOL(scr)) {
+ newcol = col
+ } else if (align == LEFT) {
+ newcol = TED_LOCOL(scr)
+ } else {
+ newcol = TED_HICOL(scr)
+ }
+
+ # Update screen descriptor
+
+ TED_LOROW(scr) = max (newrow, 1)
+ TED_HIROW(scr) = (nrows - TED_LABHEIGHT(tab)) + (newrow - 1)
+ TED_HIROW(scr) = min (TED_HIROW(scr), tabrows)
+
+ tabcols = TED_LABWIDTH(tab)
+ if (align == LEFT) {
+ TED_LOCOL(scr) = max (newcol, 1)
+ TED_HICOL(scr) = TED_NCOLS(tab)
+ do icol = newcol, TED_NCOLS(tab) {
+ tabcols = tabcols + TED_COLLEN(tab,icol) + 1
+ if (tabcols >= ncols) {
+ TED_HICOL(scr) = icol - 1
+ break
+ }
+ }
+
+ } else {
+ TED_LOCOL(scr) = 1
+ TED_HICOL(scr) = min (newcol, TED_NCOLS(tab))
+ do icol = newcol, 1, -1 {
+ tabcols = tabcols + TED_COLLEN(tab,icol) + 1
+ if (tabcols >= ncols) {
+ TED_LOCOL(scr) = icol + 1
+ break
+ }
+ }
+ }
+
+ # Sanity check for new descriptor values
+
+ if (TED_LOROW(scr) > TED_HIROW(scr) ||
+ TED_LOCOL(scr) > TED_HICOL(scr) ) {
+
+ call sprintf (Memc[errmsg], SZ_LINE, badsize)
+ call pargi (TED_LOROW(scr))
+ call pargi (TED_HIROW(scr))
+ call pargi (TED_LOCOL(scr))
+ call pargi (TED_HICOL(scr))
+
+ call err1_prompt (Memc[errmsg])
+ }
+
+ # Redraw screen
+
+ call draw_screen (scr)
+ call sfree (sp)
+end
+
+procedure split_screen (scr1, scr2, table, columns, rdonly, inplace)
+
+pointer scr1 # u: current screen
+pointer scr2 # o: new screen
+char table[ARB] # i: SDAS table name
+char columns[ARB] # i: list of columns to edit
+bool rdonly # i: edit table read only
+bool inplace # i: edit table in place
+#--
+
+begin
+ # Create new window
+
+ call split_window (scr1, scr2)
+ if (scr2 == NULL)
+ return
+
+ # Fill in the descriptor fields
+
+ call add_screen (scr2, table, columns, rdonly, inplace)
+
+end
+
diff --git a/pkg/utilities/nttools/tedit/substitute.x b/pkg/utilities/nttools/tedit/substitute.x
new file mode 100644
index 00000000..963d2786
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/substitute.x
@@ -0,0 +1,372 @@
+.help substitute
+.nf____________________________________________________________________________
+
+This procedure searches for and replaces text patterns in a string.
+The text patterns are passed to the procedure as arguments, so this
+procedure can be used to perform a variety of text processing tasks.
+The procedure has four arguments: a target pattern string (from), a
+replacement pattern string (to), the string to be modified (str), and
+a maximum length for this string (maxch). The syntax for the target
+and replacement pattern strings largely follows that used in the
+substitute command by the Unix text editors `ed' and `ex'. The pattern
+consists of a sequence of ordinary characters, which match themselves,
+and metacharacters, which match a set of characters. A metacharacter
+can be matched as if it were an ordinary character by preceding it
+with the escape character, `\'. For example, the escape character
+itself is indicated in a pattern by `\\'. The metacharacters which can
+be used in the target pattern are:
+
+ beginning of string ^ end of string $
+ white space # escape character \
+ ignore case { end ignore case }
+ begin character class [ end character class ]
+ not, in char class ^ range, in char class -
+ one character ? zero or more occurences *
+ begin tagged string \( end tagged string \)
+
+
+A set of characters is indicated in the target string by the character
+class construct. For example, punctuation could be indicated by
+`[,;.!]'. A range of characters contiguous in the underlying
+character set can be abbreviated by the range construct. For example,
+`[a-z]' matches any lower case character. The complement of a
+character set is indicated by making `^' the first character in a
+class. For example, `[^0-9]' matches any non-digit. Repetition of a
+character or character class is indicated by the following it with the
+`*' metacharacter. Thus, zero or more occurences of a lower case
+character is indicated by `[a-z]*'. The tagged string metacharacters
+have no effect on the match, they only serve to identify portions of
+the matched string for the replacement pattern. The metacharacters
+which are used in the replacement pattern are the following:
+
+ entire string & tagged string \n
+ capitalize \u upper case \U
+ lower case \L end case conversion \e \E
+
+The ditto metacharacter, `&', indicates that the entire portion of the
+string that was matched by the target pattern. The tag metacharacter
+indicates that the n-th tagged string. For example, `\1' indicates
+the first tagged string and `\2' the second. The remaining
+metacharacters affect the case of the output string. The
+capitalization metacharacter only affects the immediately following
+metacharacter, but the upper and lower case metacharacters must be
+turned off explicitly with `\e' or `\E'. The following are a few
+examples of the results that can be obtained with this subroutine:
+
+ from to action
+ ---- -- ------
+ IRAF SDAS convert all mentions
+ of IRAF to SDAS
+ [a-z][A-Za-z]* \u& capitalize all words
+ "\([^"]*\)" '\1' convert double quoted
+ strings to single
+ quoted strings
+ \([^,]*\),\(?*\) \2,\1 reverse two fields
+ separated by commas
+
+.endhelp_______________________________________________________________________
+
+include <ctype.h>
+
+define DITTO -1 # substitute matched expression
+define TAG -2 # substitute tagged part of matched expression
+define CAP -3 # capitalize next char
+define UCASE -4 # convert to upper case
+define LCASE -5 # convert to lower case
+define ENDCASE -6 # end case conversion
+
+define CH_ESCAPE '\\'
+define CH_DITTO '&'
+define CH_LTAG '('
+define CH_RTAG ')'
+define CH_INDEX '%'
+
+#* HISTORY *
+#* B.Simon 08-Dec-87 First code
+#* B.Simon 05-Jan-93 Modified for substitute command
+
+# SUBSTITUTE -- Substitute characters in second pattern for first pattern
+
+bool procedure substitute (from, to, str, maxch)
+
+char from[ARB] # i: Target pattern
+char to[ARB] # i: Replacement pattern
+char str[ARB] # u: String to be modified
+int maxch # i: Maximum length of string
+#--
+bool match
+int maxpat, ic, jc, nc
+pointer sp, pat, sub, temp
+
+int pat_amatch()
+
+begin
+ # Allocate memory for temporary strings
+
+ maxpat = maxch + SZ_LINE
+
+ call smark (sp)
+ call salloc (pat, maxpat, TY_CHAR)
+ call salloc (sub, maxpat, TY_CHAR)
+ call salloc (temp, maxch, TY_CHAR)
+
+ # Encode target and replacement patterns
+
+ call code_pat (from, Memc[pat], maxpat)
+ call code_sub (to, Memc[sub], maxpat)
+
+ # Perform an anchored match at each character of the string.
+ # If there is a match, substitute the replacement pattern for
+ # the target. Otherwise move the character to the output unchanged
+
+ ic = 1
+ jc = 1
+ match = false
+
+ while (str[ic] != EOS) {
+ nc = pat_amatch (str, ic, Memc[pat])
+ if (nc > 0) {
+ match = true
+ call make_sub (Memc[pat], Memc[sub], str, ic, ic+nc-1,
+ Memc[temp], jc, maxch)
+
+ } else {
+ nc = 1
+ if (jc <= maxch) {
+ Memc[temp+jc-1] = str[ic]
+ jc = jc + 1
+ }
+ }
+
+ ic = ic + nc
+ }
+
+ # Copy from temporary output string back to the original string
+
+ Memc[temp+jc-1] = EOS
+ call strcpy (Memc[temp], str, maxch)
+
+ # Return status indicates if there were any matches
+
+ call sfree (sp)
+ return (match)
+
+end
+
+# CODE_PAT -- Encode the target pattern
+
+procedure code_pat (from, pat, maxch)
+
+char from[ARB] # i: Target string
+char pat[ARB] # o: Encoded target pattern
+int maxch # i: Maximum length of pattern
+#--
+char ch
+int ic, jc, nc
+pointer sp, temp
+
+int patmake()
+
+begin
+ # Allocate memory for temporary string
+
+ call smark (sp)
+ call salloc (temp, maxch, TY_CHAR)
+
+ # Convert target string to a form acceptable to the IRAF pattern
+ # matcher by converting tagged strings to index characters. Also
+ # escape any index characters which might already be in the string.
+
+ ic = 1
+ jc = 1
+ while (from[ic] != EOS) {
+ if (from[ic] == CH_ESCAPE) {
+ if (from[ic+1] == CH_LTAG || from[ic+1] == CH_RTAG) {
+ ch = CH_INDEX
+ ic = ic + 1
+ } else {
+ ch = from[ic]
+ }
+
+ } else if (from[ic] == CH_INDEX) {
+ if (jc <= maxch) {
+ Memc[temp+jc-1] = CH_ESCAPE
+ jc = jc + 1
+ }
+ ch = from[ic]
+
+ } else {
+ ch = from[ic]
+ }
+
+ if (jc <= maxch) {
+ Memc[temp+jc-1] = ch
+ jc = jc + 1
+ }
+
+ ic = ic + 1
+ }
+
+ # Call the IRAF pattern encoder to encode the converted string
+
+ Memc[temp+jc-1] = EOS
+ nc = patmake (Memc[temp], pat, maxch)
+
+ call sfree (sp)
+end
+
+# CODE_SUB -- Encode the replacement pattern
+
+procedure code_sub (to, sub, maxch)
+
+char to[ARB] # i: Replacement string
+char sub[ARB] # o: Encoded replacement pattern
+int maxch # i: Maximum length of encoded pattern
+#--
+char ch
+int ic, jc
+
+int cctoc()
+
+begin
+ # Convert special characters in replacement pattern to codes
+ # Also convert escape sequences to single characters
+
+ ic = 1
+ jc = 1
+
+ while (to[ic] != EOS) {
+ if (to[ic] == CH_DITTO) {
+ ch = DITTO
+
+ } else if (to[ic] == CH_ESCAPE) {
+ switch (to[ic+1]) {
+ case 'u':
+ ch = CAP
+ ic = ic + 1
+ case 'U':
+ ch = UCASE
+ ic = ic + 1
+ case 'L':
+ ch = LCASE
+ ic = ic + 1
+ case 'e', 'E':
+ ch = ENDCASE
+ ic = ic + 1
+ default:
+ if (IS_DIGIT(to[ic+1])) {
+ if (jc <= maxch) {
+ sub[jc] = TAG
+ jc = jc + 1
+ }
+ ch = TO_INTEG(to[ic+1])
+ ic = ic + 1
+
+ } else if (cctoc (to, ic, ch) == 1) {
+ ch = to[ic]
+
+ } else {
+ ic = ic - 1
+ }
+ }
+
+ } else {
+ ch = to[ic]
+ }
+
+ if (jc <= maxch) {
+ sub[jc] = ch
+ jc = jc + 1
+ }
+
+ ic = ic + 1
+ }
+
+ sub[jc] = EOS
+
+end
+
+# COPY_SUB -- Move input characters to the output string
+
+procedure copy_sub (str1, first, last, caseflag, str2, len, maxch)
+
+char str1[ARB] # i: Input string
+int first # i: First character to be moved
+int last # i: Last character to be moved
+int caseflag # u: Case conversion flag
+char str2[ARB] # u: Output string
+int len # u: Length of output string
+int maxch # i: Maximum length of output string
+#--
+char ch
+int ic
+
+begin
+ do ic = first, last {
+ switch (caseflag) {
+ case ENDCASE:
+ ch = str1[ic]
+ case LCASE:
+ ch = str1[ic]
+ if (IS_UPPER (ch))
+ ch = TO_LOWER (ch)
+ case UCASE,CAP:
+ ch = str1[ic]
+ if (IS_LOWER (ch))
+ ch = TO_UPPER (ch)
+ default:
+ ch = str1[ic]
+ }
+
+ if (len <= maxch) {
+ str2[len] = ch
+ len = len + 1
+ }
+
+ if (caseflag == CAP)
+ caseflag = ENDCASE
+ }
+end
+
+# MAKE_SUB Substitute for the chars matched by the target pattern
+
+procedure make_sub (pat, sub, in, first, last, out, oc, maxch)
+
+char pat[ARB] # i: Target pattern
+char sub[ARB] # i: Replacement pattern
+char in[ARB] # i: Input string
+int first # i: First character matched in input string
+int last # i: Last character matched in input string
+char out[ARB] # u: Output string
+int oc # u: Last character in output string
+int maxch # i: Maximum length of output string
+#--
+int caseflag, ic, index, ltag, rtag
+
+int patindex()
+
+begin
+ caseflag = ENDCASE
+ for (ic = 1; sub[ic] != EOS; ic = ic + 1) {
+ switch (sub[ic]) {
+ case ENDCASE:
+ caseflag = ENDCASE
+ case LCASE:
+ caseflag = LCASE
+ case UCASE:
+ caseflag = UCASE
+ case CAP:
+ caseflag = CAP
+ case TAG:
+ ic = ic + 1
+ index = (sub[ic] - 1) * 2 + 1
+ ltag = patindex (pat, index)
+ rtag = patindex (pat, index+1) - 1
+ call copy_sub (in, ltag, rtag, caseflag, out, oc, maxch)
+ case DITTO:
+ call copy_sub (in, first, last, caseflag, out, oc, maxch)
+ default:
+ call copy_sub (sub, ic, ic, caseflag, out, oc, maxch)
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/tedit/table.h b/pkg/utilities/nttools/tedit/table.h
new file mode 100644
index 00000000..ed6bebd5
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/table.h
@@ -0,0 +1,22 @@
+# TABLE.H -- Tedit table descriptor
+
+define TED_TABLEN 13 # table descriptor length
+
+define TED_READONLY Memi[$1] # is table read only?
+define TED_NEWTAB Memi[$1+1] # is this a new table?
+define TED_INPLACE Memi[$1+2] # edit table in place?
+define TED_ALLCOLS Memi[$1+3] # editing all columns?
+define TED_DIRTY Memi[$1+4] # has table been modified?
+define TED_TABPTR Memi[$1+5] # table pointer
+define TED_NAMEPTR Memi[$1+6] # ptr to original table name
+define TED_NCOLS Memi[$1+7] # number of columns
+define TED_LABWIDTH Memi[$1+8] # label width
+define TED_LABHEIGHT Memi[$1+9] # label height
+define TED_COLARY Memi[$1+10] # array of column pointers
+define TED_TYPARY Memi[$1+11] # array of column types
+define TED_LENARY Memi[$1+12] # array of column lengths
+
+define TED_TABNAME Memc[TED_NAMEPTR($1)] # original table name
+define TED_COLPTR Memi[TED_COLARY($1)+($2)-1] # column pointer
+define TED_COLTYPE Memi[TED_TYPARY($1)+($2)-1] # column type
+define TED_COLLEN Memi[TED_LENARY($1)+($2)-1] # column length
diff --git a/pkg/utilities/nttools/tedit/table.x b/pkg/utilities/nttools/tedit/table.x
new file mode 100644
index 00000000..9312a340
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/table.x
@@ -0,0 +1,312 @@
+include <tbset.h>
+include "screen.h"
+include "table.h"
+include "field.h"
+
+# CREATE_TABLE -- Create a new table
+
+procedure create_table (name, tptr)
+
+char name[ARB] # i: Table name
+pointer tptr # o: Table pointer
+#--
+int code, type
+pointer sp, cp, cname, cunits, ftnfmt, sppfmt, ctype, errmsg
+
+string newtable "Table does not exist. Create it?"
+string notable "Task exit. Table does not exist."
+string nocreate "Could not create table"
+string nocolumn "Could not create column"
+string colprompt "Column name? (Press return to exit)"
+
+bool bool_prompt()
+int errget()
+pointer tbtopn()
+
+begin
+ if (! bool_prompt (newtable))
+ call err1_prompt (notable)
+
+ call smark (sp)
+ call salloc (cname, SZ_COLNAME, TY_CHAR)
+ call salloc (cunits, SZ_COLUNITS, TY_CHAR)
+ call salloc (ftnfmt, SZ_COLFMT, TY_CHAR)
+ call salloc (sppfmt, SZ_COLFMT, TY_CHAR)
+ call salloc (ctype, SZ_FNAME, TY_CHAR)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ iferr {
+ tptr = tbtopn (name, NEW_FILE, NULL)
+ } then {
+ code = errget (Memc[errmsg], SZ_LINE)
+ call err2_prompt (nocreate, Memc[errmsg])
+ }
+
+ # Get parameters defining each column
+
+ repeat {
+ call read_prompt (colprompt, Memc[cname], SZ_COLNAME)
+ if (Memc[cname] == EOS)
+ break
+
+ repeat {
+ call read_prompt ("Column type? (r,d,i,b,ch*n)",
+ Memc[ctype], SZ_FNAME)
+
+ iferr (call tbbtyp (Memc[ctype], type)) {
+ call ring_bell
+ } else {
+ break
+ }
+ }
+
+ repeat {
+ call read_prompt ("Column format?", Memc[ftnfmt], SZ_COLFMT)
+ call tbbftp (Memc[ftnfmt], Memc[sppfmt])
+
+ if (Memc[sppfmt] == EOS && Memc[ftnfmt] != EOS) {
+ call ring_bell
+ } else {
+ break
+ }
+ }
+
+ call read_prompt ("Column units?", Memc[cunits], SZ_COLUNITS)
+
+ # Add new column to table
+
+ iferr {
+ call tbcdef (tptr, cp, Memc[cname], Memc[cunits],
+ Memc[sppfmt], type, 1, 1)
+ } then {
+ code = errget (Memc[errmsg], SZ_LINE)
+ call err2_prompt (nocolumn, Memc[errmsg])
+ }
+ }
+
+ iferr {
+ call tbtcre (tptr)
+ } then {
+ code = errget (Memc[errmsg], SZ_LINE)
+ call err2_prompt (nocreate, Memc[errmsg])
+ }
+
+ # Add an empty row to the table
+
+ call tbtwer (tptr, 1)
+ call sfree (sp)
+end
+
+# MAP_TABLE -- Map a table into a descriptor so that it can be edited
+
+pointer procedure map_table (scr, table, columns, rdonly, inplace)
+
+pointer scr # i: Screen descriptor
+char table[ARB] # i: SDAS table name
+char columns[ARB] # i: list of columns to edit
+bool rdonly # i: edit table read only
+bool inplace # i: edit table in place
+#--
+bool place, new
+int dirty, numcol, numrow, numptr, iptr
+int height, width, maxcol, clen
+pointer sp, tabname, filename, ext, cname, tptr, tab
+
+string notable "Table does not exist"
+string nowrite "No write access to table"
+string nocols "Column names not found in table"
+string emptytab "Table is empty"
+
+int access(), tbtacc(), tbpsta()
+int tbcigi(), strlen(), btoi()
+
+begin
+ # Allocate dynamic memory for temporary names
+
+ call smark (sp)
+ call salloc (tabname, SZ_FNAME, TY_CHAR)
+ call salloc (filename, SZ_FNAME, TY_CHAR)
+ call salloc (ext, SZ_COLNAME, TY_CHAR)
+ call salloc (cname, SZ_COLNAME, TY_CHAR)
+
+ # Get filename from table name
+
+ call tbfile (table, Memc[tabname], Memc[filename], Memc[ext], SZ_FNAME)
+
+ # Check table permissions
+
+ if (tbtacc (table) == NO) {
+ dirty = YES
+ place = true
+ new = true
+ call create_table (table, tptr)
+ call strcpy (table, Memc[filename], SZ_FNAME)
+
+ } else {
+ dirty = NO
+ place = inplace
+ new = false
+
+ if (access (Memc[filename], READ_WRITE, 0) == NO && ! rdonly)
+ call err2_prompt (nowrite, table)
+
+ call tu_open (table, "ted", rdonly, inplace,
+ tptr, Memc[filename], SZ_FNAME)
+ }
+
+ # Allocate descriptor
+
+ numcol = tbpsta (tptr, TBL_NCOLS)
+ numrow = tbpsta (tptr, TBL_NROWS)
+
+ call malloc (tab, TED_TABLEN, TY_STRUCT)
+ call malloc (TED_NAMEPTR(tab), SZ_FNAME, TY_CHAR)
+ call malloc (TED_COLARY(tab), numcol, TY_INT)
+ call malloc (TED_TYPARY(tab), numcol, TY_INT)
+ call malloc (TED_LENARY(tab), numcol, TY_INT)
+
+ # Fill in scalar fields
+
+ TED_READONLY(tab) = btoi (rdonly)
+ TED_NEWTAB(tab) = btoi (new)
+ TED_INPLACE(tab) = btoi (place)
+ TED_DIRTY(tab) = dirty
+ TED_TABPTR(tab) = tptr
+
+ # Set the width and height of the label area surrounding
+ # the table display
+
+ TED_LABWIDTH(tab) = log10 (real(numrow + 1000)) + 1.0
+ TED_LABWIDTH(tab) = max (6, TED_LABWIDTH(tab))
+ TED_LABHEIGHT(tab) = 2
+
+ call strcpy (Memc[filename], TED_TABNAME(tab), SZ_FNAME)
+
+ # Get vector fields (column pointers, types, and lengths)
+
+ call tctexp (tptr, columns, numcol, numptr, TED_COLPTR(tab,1))
+
+ TED_NCOLS(tab) = numptr
+ if (numptr == 0) {
+ call err2_prompt (nocols, columns)
+ } else if (numcol == numptr) {
+ TED_ALLCOLS(tab) = YES
+ } else {
+ TED_ALLCOLS(tab) = NO
+ }
+
+ call wdimen (TED_WINDOW(scr), height, width)
+ maxcol = width - (TED_LABWIDTH(tab) + 2)
+
+ do iptr = 1, numptr {
+ TED_COLTYPE(tab,iptr) = tbcigi (TED_COLPTR(tab,iptr),
+ TBL_COL_DATATYPE)
+
+ clen = tbcigi (TED_COLPTR(tab,iptr), TBL_COL_FMTLEN)
+ call tbcigt (TED_COLPTR(tab,iptr), TBL_COL_NAME,
+ Memc[cname], SZ_COLNAME)
+
+ TED_COLLEN(tab,iptr) = min (maxcol, max (clen,
+ strlen (Memc[cname])))
+ }
+
+ # Check to see if table is empty
+ # Write a single blank row unless table is read only
+
+ if (numrow < 1 ) {
+ if (rdonly) {
+ call err2_prompt (emptytab, table)
+ } else {
+ TED_DIRTY(tab) = YES
+ call tbtwer (tptr, 1)
+ }
+ }
+
+ # Return pointer to descriptor
+
+ call sfree (sp)
+ return (tab)
+ end
+
+# UNMAP_TABLE -- Release table descriptor
+
+procedure unmap_table (scr, tab, force)
+
+pointer scr # i: Currently active screen
+pointer tab # i: Table descriptor
+int force # i: Force unmap if table is dirty
+#--
+bool quit
+pointer sp, table
+
+begin
+ # Allocate memory for strings
+
+ call smark (sp)
+ call salloc (table, SZ_FNAME, TY_CHAR)
+
+ # Close table if still open and delete if
+ # it was a new table that was not written or not in place
+
+ if (TED_TABPTR(tab) != NULL) {
+ quit = TED_NEWTAB(tab) == YES || TED_INPLACE(tab) == NO
+ call tbtnam (TED_TABPTR(tab), Memc[table], SZ_FNAME)
+
+ call tu_close (TED_TABPTR(tab), TED_INPLACE(tab),
+ quit, Memc[table])
+ }
+
+ # Free descriptor
+
+ call mfree (TED_NAMEPTR(tab), TY_CHAR)
+ call mfree (TED_COLARY(tab), TY_INT)
+ call mfree (TED_TYPARY(tab), TY_INT)
+ call mfree (TED_LENARY(tab), TY_INT)
+
+ call mfree (tab, TY_STRUCT)
+ call sfree (sp)
+end
+
+# WRT_TABLE -- Close table and write back to original file
+
+procedure wrt_table (scr, tab)
+
+pointer scr # i: Currently active screen
+pointer tab # i: Table descriptor
+#--
+bool quit
+pointer sp, table
+
+string noname "Could not rename new table, it has this temporary name"
+
+begin
+ # Return if table already written
+
+ if (TED_TABPTR(tab) == NULL)
+ return
+
+ # Allocate memory for strings
+
+ call smark (sp)
+ call salloc (table, SZ_FNAME, TY_CHAR)
+
+ # Get current file name, then close table
+
+ quit = TED_INPLACE(tab) == NO && TED_DIRTY(tab) == NO
+ call strcpy (TED_TABNAME(tab), Memc[table], SZ_FNAME)
+
+ iferr {
+ call tu_close (TED_TABPTR(tab), TED_INPLACE(tab),
+ quit, Memc[table])
+ } then {
+ call warn2_prompt (scr, noname, Memc[table])
+ TED_INPLACE(tab) = YES
+ }
+
+ # Set table pointer to NULL and set newtab to NO, to mark it as written
+
+ TED_TABPTR(tab) = NULL
+ TED_NEWTAB(tab) = NO
+ call sfree (sp)
+end
+
diff --git a/pkg/utilities/nttools/tedit/tedit.key b/pkg/utilities/nttools/tedit/tedit.key
new file mode 100644
index 00000000..6e2f358d
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/tedit.key
@@ -0,0 +1,23 @@
+All commands may be abbreviated to any unique abbreviation
+
+add column add a new column to the table
+add row add new rows to the table
+copy copy rows to paste buffer, deleting current buffer
+copy append copy rows to paste buffer, saving current buffer
+delete delete rows, add to paste buffer, deleting current buffer
+delete append delete rows, add to paste buffer, saving current buffer
+exit leave table editor after saving changes
+find find next row which makes search expression true
+find forward (same as find)
+find backwards find previous row which makes search expression true
+goto go to row and column in table
+help display this file
+insert insert lines from paste buffer into table
+lower convert a string column to lower case
+next repeat previous find command in current direction
+next forward repeat previous find command in forward direction
+next backwards repeat previous find command in backwards direction
+quit leave table editor without saving changes
+set set a column equal to an expression
+substitute substitute one string for another
+upper convert a string column to upper case
diff --git a/pkg/utilities/nttools/tedit/tedit.x b/pkg/utilities/nttools/tedit/tedit.x
new file mode 100644
index 00000000..c3ced90f
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/tedit.x
@@ -0,0 +1,33 @@
+# TEDIT -- Table editor
+
+procedure t_tedit ()
+
+#--
+pointer table # SDAS table name
+pointer columns # list of columns to edit
+bool silent # don't ring bell when error occurs
+bool rdonly # edit table read only
+bool inplace # edit table in place
+
+pointer sp
+
+bool clgetb()
+
+begin
+ call smark (sp)
+ call salloc (table, SZ_FNAME, TY_CHAR)
+ call salloc (columns, SZ_FNAME, TY_CHAR)
+
+ call clgstr ("table", Memc[table], SZ_FNAME)
+ call clgstr ("columns", Memc[columns], SZ_FNAME)
+
+ silent = clgetb ("silent")
+ rdonly = clgetb ("rdonly")
+ inplace = clgetb ("inplace")
+ inplace = inplace || rdonly
+
+ call edit (Memc[table], Memc[columns], silent, rdonly, inplace)
+ call sfree (sp)
+
+end
+
diff --git a/pkg/utilities/nttools/tedit/tread.x b/pkg/utilities/nttools/tedit/tread.x
new file mode 100644
index 00000000..620c203a
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/tread.x
@@ -0,0 +1,31 @@
+# T_TREAD -- Read only table editor
+
+procedure t_tread ()
+
+#--
+pointer table # SDAS table name
+pointer columns # list of columns to edit
+bool silent # don't ring bell when error occurs
+
+bool rdonly,inplace
+pointer sp
+
+bool clgetb()
+
+begin
+ call smark (sp)
+ call salloc (table, SZ_FNAME, TY_CHAR)
+ call salloc (columns, SZ_FNAME, TY_CHAR)
+
+ call clgstr ("table", Memc[table], SZ_FNAME)
+ call clgstr ("columns", Memc[columns], SZ_FNAME)
+
+ silent = clgetb ("silent")
+ rdonly = true
+ inplace = true
+
+ call edit (Memc[table], Memc[columns], silent, rdonly, inplace)
+ call sfree (sp)
+
+end
+
diff --git a/pkg/utilities/nttools/tedit/window.com b/pkg/utilities/nttools/tedit/window.com
new file mode 100644
index 00000000..20ab1f11
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/window.com
@@ -0,0 +1,8 @@
+# WINDOW.COM -- Tracks windows associated with table editor
+
+int wprompt # The prompt window
+int nscreens # Number of screens currently displayed
+int scrlist[MAXSCR] # List of screens, from top to bottom
+
+common /tedwin/ wprompt, nscreens, scrlist
+
diff --git a/pkg/utilities/nttools/tedit/window.x b/pkg/utilities/nttools/tedit/window.x
new file mode 100644
index 00000000..829bb21b
--- /dev/null
+++ b/pkg/utilities/nttools/tedit/window.x
@@ -0,0 +1,246 @@
+include "display/curses.h"
+include "screen.h"
+
+define MAXSCR 10
+define MIN_HEIGHT 4
+
+# COUNT_WINDOW -- Return number of windows
+
+int procedure count_window ()
+
+#--
+include "window.com"
+
+begin
+ return (nscreens)
+end
+
+# FOCUS_WINDOW -- Move the cursor to its current position in a window
+
+procedure focus_window (win)
+
+pointer win # i: window descriptor
+#--
+int row, col
+
+int winstat()
+
+begin
+ row = winstat (win, W_CURROW)
+ col = winstat (win, W_CURCOL)
+
+ call wmove (win, row, col)
+end
+
+# GET_WINDOW -- Get a window from the list of screens
+
+int procedure get_window (iscr, scr)
+
+int iscr # i: index into list of screens
+pointer scr # o: screen descriptor
+#--
+include "window.com"
+
+begin
+ # Return EOF if this is the last screen on the list
+
+ if (iscr > nscreens) {
+ scr = scrlist[1]
+ return (EOF)
+ } else {
+ scr = scrlist[iscr]
+ return (OK)
+ }
+end
+
+# INIT_WINDOW -- Create the initial set of windows
+
+procedure init_window (scr)
+
+pointer scr # o: initial screen
+#--
+include "window.com"
+
+int nrows, ncols
+
+int newwin()
+
+begin
+ # Get size of terminal screen
+
+ call wdimen (STDSCR, nrows, ncols)
+
+ # Create the initial screen
+
+ call malloc (scr, TED_SCRLEN, TY_STRUCT)
+ TED_WINDOW(scr) = newwin (nrows-2, ncols, 1, 1)
+ TED_TABLE(scr) = NULL
+
+ # Create the prompt window
+
+ wprompt = newwin (2, ncols, nrows-1, 1)
+
+ # Initialze the global variables
+
+ nscreens = 1
+ scrlist[1] = scr
+
+end
+
+# JOIN_WINDOW -- Join screen window with the adjacent window
+
+procedure join_window (scr)
+
+pointer scr # i: screen descriptor
+#--
+include "window.com"
+
+int win1, win2
+int iscr, jscr, top, left, row1, col1, row2, col2
+pointer scr2
+
+string notnull "join_window: table was not closed"
+string notfound "join_window: could not find screen"
+
+int winstat(), newwin()
+
+begin
+ # Cannot join single screen or screen that is still open
+
+ if (nscreens == 1 || TED_TABLE(scr) != NULL)
+ call err1_prompt (notnull)
+
+ # Find the screen and its adjacent screen
+ # Pay attention to which screen is on top
+
+ jscr = 0
+ do iscr = 1, nscreens {
+ if (scrlist[iscr] == scr) {
+ jscr = iscr
+ if (jscr == 1) {
+ win1 = TED_WINDOW(scrlist[1])
+ win2 = TED_WINDOW(scrlist[2])
+ scr2 = scrlist[2]
+ } else {
+ win1 = TED_WINDOW(scrlist[jscr-1])
+ win2 = TED_WINDOW(scrlist[jscr])
+ scr2 = scrlist[jscr-1]
+ }
+ break
+ }
+ }
+
+ if (jscr == 0) {
+ call err1_prompt (notfound)
+
+ } else {
+ # Get dimensions of windows, delete them
+
+ top = winstat (win1, W_TOP)
+ left = winstat (win1, W_LEFT)
+
+ call wdimen (win1, row1, col1)
+ call delwin (win1)
+
+ call wdimen (win2, row2, col2)
+ call delwin (win2)
+
+ # Create new window, assign to adjacent screen
+
+ TED_WINDOW(scr2) = newwin (row1+row2, col2, top, left)
+
+ # Delete screen and remove from list of screens
+
+ call mfree (scr, TY_STRUCT)
+ nscreens = nscreens - 1
+
+ do iscr= jscr, nscreens
+ scrlist[iscr] = scrlist[iscr+1]
+ }
+end
+
+# PROMPT_WINDOW -- Return the prompt window
+
+int procedure prompt_window ()
+
+#--
+include "window.com"
+
+begin
+ return (wprompt)
+end
+
+# SPLIT_WINDOW -- Split window into two windows
+
+procedure split_window (scr1, scr2)
+
+pointer scr1 # u: current screen
+pointer scr2 # o: new screen (or NULL)
+#--
+include "window.com"
+
+int win1
+int iscr, jscr, top, left, row1, col1, row2, col2
+
+string noroom "Screen is too small to split"
+string notfound "split_window: could not find screen"
+
+int winstat(), newwin()
+
+begin
+ # Find screen in list of screens
+
+ jscr = 0
+ do iscr = 1, nscreens {
+ if (scr1 == scrlist[iscr]) {
+ jscr = iscr
+ break
+ }
+ }
+
+ if (jscr == 0) {
+ call err1_prompt (notfound)
+
+ } else {
+ # Get dimensions of current window
+
+ win1 = TED_WINDOW(scr1)
+
+ top = winstat (win1, W_TOP)
+ left = winstat (win1, W_LEFT)
+
+ call wdimen (win1, row1, col1)
+
+ row2 = row1 / 2
+ col2 = col1
+ row1 = row1 - row2
+
+ # Don't split window if it is too small
+
+ if (row2 <= MIN_HEIGHT) {
+ call warn1_prompt (scr1, noroom)
+ scr2 = NULL
+
+ } else {
+ # Delete current window and create new half-size window
+
+ call delwin (win1)
+ TED_WINDOW(scr1) = newwin (row1, col1, top, left)
+
+ # Create new screen and its window
+
+ call malloc (scr2, TED_SCRLEN, TY_STRUCT)
+ TED_WINDOW(scr2) = newwin (row2, col2, top+row1, left)
+ TED_TABLE(scr2) = NULL
+
+ # Add to list of screens
+
+ do iscr = jscr+1, nscreens
+ scrlist[iscr+1] = scrlist[iscr]
+
+ scrlist[jscr+1] = scr2
+ nscreens = nscreens + 1
+ }
+ }
+
+end
diff --git a/pkg/utilities/nttools/texpand.par b/pkg/utilities/nttools/texpand.par
new file mode 100644
index 00000000..17d6a35d
--- /dev/null
+++ b/pkg/utilities/nttools/texpand.par
@@ -0,0 +1,6 @@
+input,s,a,,,,"Input SDAS table name"
+output,s,a,,,,"Output SDAS table name"
+rbase,s,a,,,,"File containing expansion rules"
+debug,s,h,"",,,"File for debug output"
+verbose,b,h,no,,,"Print table names?"
+mode,s,h,"a",,,
diff --git a/pkg/utilities/nttools/texpand/dbgrules.x b/pkg/utilities/nttools/texpand/dbgrules.x
new file mode 100644
index 00000000..eeffb8e0
--- /dev/null
+++ b/pkg/utilities/nttools/texpand/dbgrules.x
@@ -0,0 +1,164 @@
+include <tbset.h>
+
+define INT_DEFLEN 10
+define REAL_DEFLEN 14
+define DBL_DEFLEN 24
+
+# DBGRULES -- Write the non-null rows in a table to a debug file
+#
+# B.Simon 25-Apr-88 Original
+
+procedure dbg_rules (tp, title, row1, row2, dbg)
+
+pointer tp # i: Table descriptor
+char title[ARB] # i: Title to print above table
+int row1 # i: First row to print
+int row2 # i: Last row to print
+int dbg # i: File descriptor of debug file
+#--
+bool nullflg
+double dblval
+int pwidth, ncol, irow, icol, jcol, collen, totlen, intval
+pointer sp, col,strval, colname, colptr, typptr, lenptr
+real realval
+
+int tbpsta(), tbcnum(), tbcigi(), envgeti(), strlen()
+
+begin
+ # First, make sure there is something to print
+
+ if (row2 < row1 || dbg == NULL)
+ return
+
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (strval, SZ_LINE, TY_CHAR)
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+
+ # Allocate dynamic memory for column arrays
+
+ ncol = tbpsta (tp, TBL_NCOLS)
+ call salloc (typptr, ncol, TY_INT)
+ call salloc (colptr, ncol, TY_INT)
+ call salloc (lenptr, ncol, TY_INT)
+
+ # Get width of terminal screen
+
+ pwidth = envgeti ("ttyncols")
+
+ # Print title
+
+ call fprintf (dbg, "%s\n")
+ call pargstr (title)
+
+ # Compute width of each column in output
+
+ jcol = 0
+ totlen = 0
+ do icol = 1, ncol {
+
+ # Check to see if this column is excluded from the output
+
+ col = tbcnum (tp, icol)
+ call tbrgtt (tp, col, Memc[strval], nullflg, SZ_LINE, 1, row1)
+
+ if (row1 != row2 || ! nullflg) {
+ jcol = jcol + 1
+
+ call tbcigt (col, TBL_COL_NAME, Memc[colname], SZ_COLNAME)
+ Memi[colptr+jcol-1] = col
+ Memi[typptr+jcol-1] = tbcigi (col, TBL_COL_DATATYPE)
+
+ # Set column width to default for its type
+
+ switch (Memi[typptr+jcol-1]) {
+ case TY_SHORT, TY_INT, TY_LONG:
+ collen = INT_DEFLEN
+ case TY_REAL:
+ collen = REAL_DEFLEN
+ case TY_DOUBLE:
+ collen = DBL_DEFLEN
+ default:
+ collen = - Memi[typptr+jcol-1]
+ }
+
+ # Adjust width to allow room for column titles
+
+ collen = max (collen, strlen (Memc[colname]))
+ totlen = totlen + collen + 1
+
+ # Write the column titles
+
+ if (jcol > 1 && totlen > pwidth)
+ call fprintf (dbg, "\n")
+
+ if (Memi[typptr+jcol-1] > 0) {
+ call fprintf (dbg, " %*s")
+ call pargi (collen)
+ } else {
+ call fprintf (dbg, " %*s")
+ call pargi (-collen)
+ }
+ call strupr (Memc[colname])
+ call pargstr (Memc[colname])
+
+ # Set sign to indicate start of new line
+
+ if (jcol > 1 && totlen > pwidth) {
+ totlen = collen + 1
+ Memi[lenptr+jcol-2] = - Memi[lenptr+jcol-2]
+ }
+
+ Memi[lenptr+jcol-1] = collen
+ }
+ }
+
+ # Recompute number of columns and force newline at end of title row
+
+ ncol = jcol
+ if (ncol > 0)
+ Memi[lenptr+ncol-1] = - Memi[lenptr+ncol-1]
+ call fprintf (dbg, "\n")
+
+ # Read the data from the database and write the data to STDOUT
+
+ do irow = row1, row2 {
+ do jcol = 1, ncol {
+
+ col = Memi[colptr+jcol-1]
+ collen = abs (Memi[lenptr+jcol-1])
+
+ switch(Memi[typptr+jcol-1]) {
+ case TY_SHORT, TY_INT, TY_LONG:
+ call tbegti (tp, col, irow, intval)
+ call fprintf (dbg, " %*d")
+ call pargi (collen)
+ call pargi (intval)
+ case TY_REAL:
+ call tbegtr (tp, col, irow, realval)
+ call fprintf (dbg, " %*.7g")
+ call pargi (collen)
+ call pargr (realval)
+ case TY_DOUBLE:
+ call tbegtd (tp, col, irow, dblval)
+ call fprintf (dbg, " %*.16g")
+ call pargi (collen)
+ call pargd (dblval)
+ default:
+ call tbegtt (tp, col, irow, Memc[strval], SZ_LINE)
+ call fprintf (dbg, " %*s")
+ call pargi (-collen)
+ call pargstr (Memc[strval])
+ }
+
+ if (Memi[lenptr+jcol-1] < 0)
+ call fprintf (dbg, "\n")
+
+ }
+ }
+
+ call fprintf (dbg, "\n\n")
+ call sfree (sp)
+
+end
diff --git a/pkg/utilities/nttools/texpand/lexer.x b/pkg/utilities/nttools/texpand/lexer.x
new file mode 100644
index 00000000..cb4d5d7c
--- /dev/null
+++ b/pkg/utilities/nttools/texpand/lexer.x
@@ -0,0 +1,114 @@
+include "lexoper.h"
+
+define start_ 90
+
+# LEXER -- Lexically analyze a rule base
+#
+# B.Simon 25-Apr-88 Original
+
+procedure lexer (rb, oper, value, maxch)
+
+pointer rb # i: Pointer to descriptor of rule base
+int oper # o: Operator type found
+char value[ARB] # o: Text of operator
+int maxch # i: Maximum length of string
+#--
+char dic_text[2]
+int junk, old_index, dic_index, dic_oper[5]
+pointer sp, ch, blanks
+
+data dic_oper /SEPOPR, IMPOPR, OROPR, ANDOPR, EQOPR/
+string dict "/;/=>/||/&&/=/"
+
+bool streq()
+int getline(), ctowrd(), span(), nospan(), strdic()
+
+begin
+ # Allocate an array to hold whitespace
+
+ call smark (sp)
+ call salloc (blanks, SZ_LINE, TY_CHAR)
+
+ # Skip over leading whitespace
+
+start_ junk = span (" \t", RB_LINE(rb), RB_INDEX(rb), Memc[blanks], SZ_LINE)
+
+ # Branch on first non-white character
+
+ ch = RB_CHARPTR(rb)
+
+ # End of line or beginning of comment
+
+ if (Memc[ch] == '\n' || Memc[ch] == '#' || Memc[ch] == EOS) {
+ if (getline (RB_FILE(rb), RB_LINE(rb)) == EOF) {
+ oper = ENDOPR
+ value[1] = EOS
+ } else {
+ RB_NLINE(rb) = RB_NLINE(rb) + 1
+ RB_INDEX(rb) = 1
+ goto start_
+ }
+
+ # Quoted identifier
+
+ } else if (Memc[ch] == '\'' || Memc[ch] == '"') {
+ junk = ctowrd (RB_LINE(rb), RB_INDEX(rb), value, maxch)
+ oper = IDOPR
+
+ # Unquoted identifier
+
+ } else if (nospan ("=&|; \t\n", RB_LINE(rb), RB_INDEX(rb),
+ value, maxch) > 0 ) {
+ oper = IDOPR
+
+ # Other operator
+
+ } else {
+ old_index = RB_INDEX(rb)
+ junk = span ("=>&|;", RB_LINE(rb), RB_INDEX(rb), value, 2)
+ dic_index = strdic (value, dic_text, 2, dict)
+ if (dic_index > 0 && streq (value, dic_text)) {
+ oper = dic_oper[dic_index]
+ } else {
+ RB_INDEX(rb) = old_index
+ junk = ctowrd (RB_LINE(rb), RB_INDEX(rb), value, maxch)
+ oper = IDOPR
+ }
+ }
+
+ call sfree (sp)
+end
+
+# LEXINIT -- Initialize the lexical analyzer
+
+procedure lexinit (rbase, rb)
+
+char rbase[ARB] # i: Name of rule base file
+pointer rb # o: Pointer to rule base descriptor
+#--
+
+int open()
+errchk calloc, open
+
+begin
+ call malloc (rb, RB_LENGTH, TY_INT)
+
+ RB_FILE(rb) = open (rbase, READ_ONLY, TEXT_FILE)
+ RB_INDEX(rb) = 1
+ RB_NLINE(rb) = 0
+ RB_LINE(rb) = EOS
+end
+
+#LEXCLOSE -- Close the lexical analyzer
+
+procedure lexclose (rb)
+
+pointer rb # i: Pointer to rule base descriptor
+#--
+
+errchk close, mfree
+
+begin
+ call close (RB_FILE(rb))
+ call mfree (rb, TY_INT)
+end
diff --git a/pkg/utilities/nttools/texpand/lexoper.h b/pkg/utilities/nttools/texpand/lexoper.h
new file mode 100644
index 00000000..a4011143
--- /dev/null
+++ b/pkg/utilities/nttools/texpand/lexoper.h
@@ -0,0 +1,29 @@
+
+# LEXOPER.H -- Operators and identifiers used by the lexical analyzer
+
+# The value of the operator type is also its priority
+
+define ENDOPR 1
+define SEPOPR 2
+define IMPOPR 3
+define OROPR 4
+define ANDOPR 5
+define EQOPR 6
+define IDOPR 7
+
+# Pseudo-identifiers placed on the id stack
+
+define NAME 1 # Any identifier
+define NO_IDENT 0 # No identifier on stack
+define PHRASE -1 # idents joined by equals or ands
+define CLAUSE -2 # idents joined by equals, ands, or ors
+
+# Rule base data structure
+
+define RB_LENGTH (SZ_LINE / SZ_INT32 + 5)
+
+define RB_FILE Memi[$1]
+define RB_NLINE Memi[$1+1]
+define RB_INDEX Memi[$1+2]
+define RB_LINE Memc[P2C($1+3)]
+define RB_CHARPTR (P2C($1+3) + RB_INDEX($1) - 1)
diff --git a/pkg/utilities/nttools/texpand/mkpkg b/pkg/utilities/nttools/texpand/mkpkg
new file mode 100644
index 00000000..241203bf
--- /dev/null
+++ b/pkg/utilities/nttools/texpand/mkpkg
@@ -0,0 +1,21 @@
+# Update the texpand application code in the ttools package library
+# Author: B.Simon, 20-APR-1989
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ dbgrules.x <tbset.h>
+ lexer.x "lexoper.h"
+ mkrules.x
+ movelem.x <tbset.h>
+ movtbrow.x <tbset.h>
+ parser.x "lexoper.h"
+ pushstack.x <tbset.h>
+ span.x
+ texpand.x
+ userules.x <tbset.h>
+ ;
+
diff --git a/pkg/utilities/nttools/texpand/mkrules.x b/pkg/utilities/nttools/texpand/mkrules.x
new file mode 100644
index 00000000..c1dd3aad
--- /dev/null
+++ b/pkg/utilities/nttools/texpand/mkrules.x
@@ -0,0 +1,48 @@
+define SZ_COLVAL SZ_LINE
+
+# MKRULES -- Add a new rule to the target and action tables
+#
+# B.Simon 25-Apr-88 Original
+
+procedure mkrules (work, target, action)
+
+pointer work # i: Table containing parser results
+pointer target # i: Table containing patterns to be matched
+pointer action # i: Table containing possible expansions
+#--
+int nwork, naction, ntarget, iwork, iaction
+
+int numstack()
+
+errchk movtbrow, putstacki
+
+begin
+ # Check for null rules
+
+ nwork = numstack (work)
+ if (nwork <= 0)
+ return
+
+ # Move the first row from the work table to the target table
+
+ call pushstack (target)
+ naction = numstack (action)
+ ntarget = numstack (target)
+
+ call movtbrow (work, 1, target, ntarget)
+ call putstacki (target, "_FIRST", naction+1)
+ call putstacki (target, "_LAST", naction+nwork-1)
+ call putstacki (target, "_USED", NO)
+
+ # Move the remaining rows to the action table
+
+ iaction = naction
+ do iwork = 2, nwork {
+ call pushstack (action)
+ iaction = iaction + 1
+ call movtbrow (work, iwork, action, iaction)
+ }
+
+ call tbrdel (work, 1, nwork)
+
+end
diff --git a/pkg/utilities/nttools/texpand/movelem.x b/pkg/utilities/nttools/texpand/movelem.x
new file mode 100644
index 00000000..e9d1f8b4
--- /dev/null
+++ b/pkg/utilities/nttools/texpand/movelem.x
@@ -0,0 +1,113 @@
+include <tbset.h>
+
+# MOV_ELEM -- Move an element in one row from one table to another
+#
+# B.Simon 15-Jan-99 Original
+# B.Simon 27-Jan-99 Renamed
+
+procedure mov_elem (rtp, rcp, rrow, wtp, wcp, wrow)
+
+pointer rtp # i: Table descriptor of table read from
+pointer rcp # i: Column descriptor of column read from
+int rrow # i: Row number of table read from
+pointer wtp # i: Table descriptor of table written to
+pointer wcp # i: Column descriptor of column written to
+int wrow # i: Row number of table written to
+#--
+int type, nelem, sz_elem, nlen
+pointer sp, buf
+
+int tbcigi(), tbagtb(), tbagtt(), tbagti(), tbagtr(), tbagtd(), tbagts()
+
+begin
+ # First, get the type and number of elements in the column
+
+ nelem = tbcigi (rcp, TBL_COL_LENDATA)
+ type = tbcigi (rcp, TBL_COL_DATATYPE)
+
+ if (type < 0) {
+ sz_elem = - type
+ type = TY_CHAR
+ } else {
+ sz_elem = 0
+ }
+
+ # Allocate buffer to hold values passed between tables
+
+ call smark (sp)
+ call salloc (buf, nelem*(sz_elem+1), type)
+
+ # Copy the values according to their actual type
+
+ if (nelem == 1) {
+ # Do not copy null scalar values
+
+ switch (type) {
+ case TY_BOOL:
+ call tbegtb (rtp, rcp, rrow, Memb[buf])
+ call tbeptb (wtp, wcp, wrow, Memb[buf])
+
+ case TY_CHAR:
+ call tbegtt (rtp, rcp, rrow, Memc[buf], sz_elem)
+ if (Memc[buf] != EOS)
+ call tbeptt (wtp, wcp, wrow, Memc[buf])
+
+ case TY_SHORT:
+ call tbegts (rtp, rcp, rrow, Mems[buf])
+ if (! IS_INDEFS (Mems[buf]))
+ call tbepts (wtp, wcp, wrow, Mems[buf])
+
+ case TY_INT, TY_LONG:
+ call tbegti (rtp, rcp, rrow, Memi[buf])
+ if (! IS_INDEFI (Memi[buf]))
+ call tbepti (wtp, wcp, wrow, Memi[buf])
+
+ case TY_REAL:
+ call tbegtr (rtp, rcp, rrow, Memr[buf])
+ if (! IS_INDEFR (Memr[buf]))
+ call tbeptr (wtp, wcp, wrow, Memr[buf])
+
+ case TY_DOUBLE:
+ call tbegtd (rtp, rcp, rrow, Memd[buf])
+ if (! IS_INDEFD (Memd[buf]))
+ call tbeptd (wtp, wcp, wrow, Memd[buf])
+ }
+
+ } else {
+ # Don't copy zero length arrays
+
+ switch (type) {
+ case TY_BOOL:
+ nlen = tbagtb (rtp, rcp, rrow, Memb[buf], 1, nelem)
+ call tbaptb (wtp, wcp, wrow, Memb[buf], 1, nlen)
+
+ case TY_CHAR:
+ nlen = tbagtt (rtp, rcp, rrow, Memc[buf], sz_elem, 1, nelem)
+ if (Memc[buf] != EOS)
+ call tbaptt (wtp, wcp, wrow, Memc[buf], sz_elem, 1, nlen)
+
+ case TY_SHORT:
+ nlen = tbagts (rtp, rcp, rrow, Mems[buf], 1, nelem)
+ if (! IS_INDEFS (Mems[buf]))
+ call tbapts (wtp, wcp, wrow, Mems[buf], 1, nlen)
+
+ case TY_INT, TY_LONG:
+ nlen = tbagti (rtp, rcp, rrow, Memi[buf], 1, nelem)
+ if (! IS_INDEFI (Memi[buf]))
+ call tbapti (wtp, wcp, wrow, Memi[buf], 1, nlen)
+
+ case TY_REAL:
+ nlen = tbagtr (rtp, rcp, rrow, Memr[buf], 1, nelem)
+ if (! IS_INDEFR (Memr[buf]))
+ call tbaptr (wtp, wcp, wrow, Memr[buf], 1, nlen)
+
+ case TY_DOUBLE:
+ nlen = tbagtd (rtp, rcp, rrow, Memd[buf], 1, nelem)
+ if (! IS_INDEFD (Memd[buf]))
+ call tbaptd (wtp, wcp, wrow, Memd[buf], 1, nlen)
+ }
+ }
+
+ call sfree (sp)
+end
+
diff --git a/pkg/utilities/nttools/texpand/movtbrow.x b/pkg/utilities/nttools/texpand/movtbrow.x
new file mode 100644
index 00000000..9f9bb3f1
--- /dev/null
+++ b/pkg/utilities/nttools/texpand/movtbrow.x
@@ -0,0 +1,43 @@
+include <tbset.h>
+
+# MOVTBROW -- Move columns from one table to another where not null
+#
+# B.Simon 25-Apr-88 Original
+# B.Simon 15-Jan-99 now calls mov_elem
+
+procedure movtbrow (rtp, rrow, wtp, wrow)
+
+pointer rtp # i: Table descriptor of table read from
+int rrow # i: Row number of table read from
+pointer wtp # i: Table descriptor of table written to
+int wrow # i: Row number of table written to
+#--
+int ncol, icol
+pointer sp, rcp, wcp, colname
+
+pointer tbpsta(), tbcnum()
+
+begin
+ call smark (sp)
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+
+ ncol = tbpsta (rtp, TBL_NCOLS)
+ do icol = 1, ncol {
+
+ rcp = tbcnum (rtp, icol)
+ call tbcigt (rcp, TBL_COL_NAME, Memc[colname], SZ_COLNAME)
+ call tbcfnd (wtp, Memc[colname], wcp, 1)
+
+# Column names beginning with an underscore are for internal
+# use by the program and do not contain actual data
+
+ if (Memc[colname] != '_' && wcp != NULL) {
+
+ # Copy the row and column in its native type
+
+ call mov_elem (rtp, rcp, rrow, wtp, wcp, wrow)
+ }
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/texpand/parser.com b/pkg/utilities/nttools/texpand/parser.com
new file mode 100644
index 00000000..6dba2f6c
--- /dev/null
+++ b/pkg/utilities/nttools/texpand/parser.com
@@ -0,0 +1,6 @@
+# PARSER.COM -- Common block containing pointer to temporary tables
+
+common / stkptr / ptgt, pact, pwrk
+
+pointer ptgt, pact, pwrk
+
diff --git a/pkg/utilities/nttools/texpand/parser.x b/pkg/utilities/nttools/texpand/parser.x
new file mode 100644
index 00000000..2dcba75e
--- /dev/null
+++ b/pkg/utilities/nttools/texpand/parser.x
@@ -0,0 +1,283 @@
+include <tbset.h>
+include "lexoper.h"
+
+define MAXSTACK 100
+define SZ_VALSTACK 3*SZ_LINE
+
+# PARSER -- Parse a rule base file
+#
+# This procedure uses a simple operator precedence parser. Every token
+# retrieved from the file is either an identifier or an operator.
+# Identifiers are pushed onto an identifier stack. Operators are
+# pushed onto a separate operator stack. When an operator is read
+# whose priority is less than that of the operator on top of the
+# operator stack, the operator on the stack is popped and passed to
+# a procedure which performs the appropriate action, using the
+# identifiers on the identifier stack. This continues until all
+# operators of higher priority have been processed, or the stack is
+# empty. Syntax checking is done by checking that the identifier
+# stack contains the correct number and type of identifier and that
+# identifiers and operators alternate in the input. The priority of
+# each operator is implicit in the integer which is used to represent
+# it. For more information on operator precedence parsers, see "Writing
+# Interactive Compilers and Interpreters" by P.J Brown, pp. 149-151.
+#
+# B.Simon 25-Apr-88 Original
+# B.Simon 15-Jan-99 Skip rules with columns not in table
+
+procedure parser (rbase, itp, dbg, target, action)
+
+char rbase[ARB] # i: Rule base name
+pointer itp # i: Input table descriptor
+int dbg # i: Debug file descriptor
+pointer target # o: Target table descriptor
+pointer action # o: Action table descriptor
+#--
+include "parser.com"
+
+bool done, expect_id
+int idtop, optop, oper, tabtop, missing
+int opstack[MAXSTACK]
+pointer sp, rb, work, value, valstack, nxtval, colname, colval
+pointer idstack[MAXSTACK]
+
+string find_error "Column name or type mismatch"
+string stack_error "Stack overflow"
+string oper_error "Operator expected"
+string ident_error "Identifier expected"
+
+string wrkname "The parser changed the work table to the following:"
+
+int gstrcpy(), putstackt(), numstack()
+pointer initstack()
+
+errchk initstack, lexinit, lexer, lexclose, syntax, typecheck, mkrules
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (value, SZ_LINE, TY_CHAR)
+ call salloc (valstack, SZ_VALSTACK, TY_CHAR)
+
+ # Initialize the lexical analyzer
+
+ call lexinit (rbase, rb)
+
+ # Create tables used by parser
+
+ target = initstack (itp, "_FIRST,_LAST,_USED")
+ action = initstack (itp, "")
+ work = initstack (itp, "")
+
+ # Save copy of table pointers in common block
+
+ ptgt = target
+ pact = action
+ pwrk = work
+
+ # Initialize stack pointers
+
+ idtop = 0
+ optop = 0
+ nxtval = valstack
+
+ missing = NO
+ done = false
+ expect_id = true
+
+ repeat {
+
+ # Get next operator from rule base
+
+ call lexer (rb, oper, Memc[value], SZ_LINE)
+
+ # First case: operator is identifier, push on id stack
+
+ if (oper == IDOPR) {
+ if (expect_id) {
+ idtop = idtop + 1
+ if (idtop > MAXSTACK)
+ call syntax (rb, stack_error)
+
+ idstack[idtop] = nxtval
+ nxtval = gstrcpy (Memc[value], Memc[nxtval], SZ_LINE) +
+ nxtval + 1
+ } else {
+ call syntax (rb, oper_error)
+ }
+
+ # Second case: operator is not identifier
+
+ } else {
+ if (oper != ENDOPR && expect_id)
+ call syntax (rb, ident_error)
+
+ # Process all operators whose priorities are >=
+ # the operator just read from the rule base
+
+ repeat {
+ if (optop == 0)
+ break
+ if (oper > opstack[optop])
+ break
+
+ # Perform semantic actions associated with operators
+
+ switch (opstack[optop]) {
+ case ENDOPR:
+ call typecheck (rb, idstack, idtop, NO_IDENT, NO_IDENT)
+ done = true
+ case SEPOPR:
+ call typecheck (rb, idstack, idtop, NO_IDENT, NO_IDENT)
+ case IMPOPR:
+ call typecheck (rb, idstack, idtop, PHRASE, CLAUSE)
+ if (missing == NO) {
+ call mkrules (work, target, action)
+ } else {
+ missing = NO
+ tabtop = numstack (work)
+ call tbrdel (work, 1, tabtop)
+ }
+ idtop = idtop - 2
+ case OROPR:
+ call typecheck (rb, idstack, idtop, CLAUSE, CLAUSE)
+ idtop = idtop - 1
+ idstack[idtop] = CLAUSE
+ case ANDOPR:
+ call typecheck (rb, idstack, idtop, PHRASE, PHRASE)
+ if (missing == NO)
+ call andstack (work)
+
+ idtop = idtop - 1
+ idstack[idtop] = PHRASE
+ case EQOPR:
+ call typecheck (rb, idstack, idtop, NAME, NAME)
+ colval = idstack[idtop]
+ colname = idstack[idtop-1]
+ nxtval = colname
+ call pushstack (work)
+ if (putstackt (work, Memc[colname], Memc[colval])== NO)
+ missing = YES
+
+ idtop = idtop - 1
+ idstack[idtop] = PHRASE
+ }
+
+ optop = optop - 1
+
+ # Debug prints
+
+ tabtop = numstack (work)
+ call dbg_rules (work, wrkname, 1, tabtop, dbg)
+
+ } until (done)
+
+ # Push the operator just read on the operator stack
+
+ optop = optop + 1
+ if (optop > MAXSTACK)
+ call syntax (rb, stack_error)
+ opstack[optop] = oper
+ }
+
+ # Operators and identifiers should alternate in the input
+
+ expect_id = ! expect_id
+
+ } until (done)
+
+ call freestack (work)
+ call lexclose (rb)
+ call sfree (sp)
+end
+
+# TYPECHECK -- Check the number and type of identifiers on the stack
+
+procedure typecheck (rb, idstack, idtop, type1, type2)
+
+pointer rb # i: Rule base descriptor
+pointer idstack[ARB] # i: Identifier stack
+int idtop # i: Top of identifier stack
+pointer type1 # i: Type expected for one below stack top
+pointer type2 # i: Type expected for stack top
+#--
+int itype
+pointer id, type[2]
+
+string bad_type "Operator out of order"
+string too_few "Missing identifier"
+string too_many "Unexpected end of rule"
+
+begin
+ type[1] = type1
+ type[2] = type2
+
+ do itype = 1, 2 {
+ switch (type[itype]) {
+ case CLAUSE:
+
+ if (idtop < itype)
+ call syntax (rb, too_few)
+ id = idstack[idtop+itype-2]
+
+ # a phrase is also a clause
+
+ if (!(id == PHRASE || id == CLAUSE))
+ call syntax (rb, bad_type)
+
+ case PHRASE:
+
+ if (idtop < itype)
+ call syntax (rb, too_few)
+ id = idstack[idtop+itype-2]
+ if (id != PHRASE)
+ call syntax (rb, bad_type)
+
+ case NO_IDENT:
+
+ if (idtop >= itype)
+ call syntax (rb, too_many)
+
+ case NAME:
+
+ if (idtop < itype)
+ call syntax (rb, too_few)
+ id = idstack[idtop+itype-2]
+ if (id <= 0)
+ call syntax (rb, bad_type)
+
+ }
+ }
+
+end
+
+# SYNTAX -- Print a syntax error message
+
+procedure syntax (rb, errmsg)
+
+pointer rb # i: Rule base descriptor
+char errmsg[ARB] # i: Error message
+#--
+include "parser.com"
+
+begin
+ # Remove temporary tables
+
+ call freestack (ptgt)
+ call freestack (pact)
+ call freestack (pwrk)
+
+ # Print the line where the error was detected
+
+ call eprintf ("Syntax error on line %d\n%s%*t^\n")
+ call pargi (RB_NLINE(rb))
+ call pargstr (RB_LINE(rb))
+ call pargi (RB_INDEX(rb))
+
+ # Close the rules file and send the error message
+
+ call lexclose (rb)
+ call error (ERR, errmsg)
+
+end
diff --git a/pkg/utilities/nttools/texpand/pushstack.x b/pkg/utilities/nttools/texpand/pushstack.x
new file mode 100644
index 00000000..58d8b797
--- /dev/null
+++ b/pkg/utilities/nttools/texpand/pushstack.x
@@ -0,0 +1,226 @@
+include <tbset.h>
+
+define SZ_COLVAL SZ_LINE
+
+# The following procedures treat a table as if it were a stack, that is,
+# all reading and writing is done at the end of the table. The end of the
+# table is indicated by TB_NROWS.
+#
+# B.Simon 25-Apr-88 Original
+# B.Simon 27-Jan-98 Drop temporary tables
+
+# PUSHSTACK -- Push a null row on the top of a table stack
+
+procedure pushstack (tp)
+
+pointer tp # i: Table descriptor
+#--
+int top
+int tbpsta()
+
+begin
+ top = tbpsta (tp, TBL_NROWS) + 1
+ call tbtwer (tp, top)
+end
+
+# POPSTACK -- Pop the top row from a table stack
+
+procedure popstack (tp)
+
+pointer tp # i: Table descriptor
+#--
+int top
+int tbpsta()
+
+begin
+ top = tbpsta (tp, TBL_NROWS)
+ if (top > 0)
+ call tbrdel (tp, top, top)
+end
+
+# NUMSTACK -- Return the number of rows in a table stack
+
+int procedure numstack (tp)
+
+pointer tp # i: Table descriptor
+#--
+int tbpsta()
+
+begin
+ return (tbpsta (tp, TBL_NROWS))
+end
+
+# INITSTACK -- Initialize a table stack and return its descriptor
+
+pointer procedure initstack (tp, extra)
+
+pointer tp # i: Table to use as a template for the table stack
+char extra[ARB] # i: Extra columns to add to the table stack
+#--
+char comma
+int ic, jc
+pointer sp, cp, stack, colname, colunits, colfmt, tmproot, tmpfile
+
+int stridx()
+pointer tbtopn()
+
+errchk tbtopn, tbtcre
+
+begin
+ # Set up arrays in dynamic memory
+
+ call smark (sp)
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+ call salloc (colunits, SZ_COLUNITS, TY_CHAR)
+ call salloc (colfmt, SZ_COLFMT, TY_CHAR)
+ call salloc (tmproot, SZ_FNAME, TY_CHAR)
+ call salloc (tmpfile, SZ_FNAME, TY_CHAR)
+
+ # Create the stack table
+
+ call mktemp ("tmp$stk", Memc[tmproot], SZ_FNAME)
+ call tbtext (Memc[tmproot], Memc[tmpfile], SZ_FNAME)
+ stack = tbtopn (Memc[tmpfile], NEW_COPY, tp)
+
+ # Set up column information that will not vary across columns
+
+ Memc[colunits] = EOS
+ Memc[colfmt] = EOS
+
+ # Add column names from the extra string
+
+ ic = 1
+ comma = ','
+ repeat {
+
+ # Copy the next comma delimeted column name
+
+ jc = stridx (comma, extra[ic])
+ if (jc == 0)
+ call strcpy (extra[ic], Memc[colname], SZ_COLNAME)
+ else
+ call strcpy (extra[ic], Memc[colname], jc-1)
+ ic = ic + jc
+
+ # Create the new column
+
+ if (Memc[colname] != EOS)
+ call tbcdef (stack, cp, Memc[colname], Memc[colunits],
+ Memc[colfmt], TY_INT, 1, 1)
+
+ } until (jc == 0)
+
+ # Return the stack table descriptor
+
+ call tbtcre (stack)
+ call sfree (sp)
+
+ return (stack)
+end
+
+# FREESTACK -- Close and delete a table stack
+
+procedure freestack (tp)
+
+pointer tp # i: Table descriptor
+#--
+pointer sp, table
+
+begin
+ call smark (sp)
+ call salloc (table, SZ_FNAME, TY_CHAR)
+
+ call tbtnam (tp, Memc[table], SZ_FNAME)
+ call tbtclo (tp)
+
+ call delete (Memc[table])
+ call sfree (sp)
+end
+
+# PUTSTACKT -- Put a text string in the top row of a table stack
+
+int procedure putstackt (tp, colname, colval)
+
+pointer tp # i: Table descriptor
+char colname[ARB] # i: Column name
+char colval[ARB] # i: Column value
+#--
+int top, found
+pointer cp
+
+int tbpsta()
+
+begin
+ top = tbpsta (tp, TBL_NROWS)
+ call tbcfnd (tp, colname, cp, 1)
+
+ found = NO
+ if (cp != NULL) {
+ ifnoerr {
+ call tbrptt (tp, cp, colval, ARB, 1, top)
+ } then {
+ found = YES
+ }
+ }
+
+ return (found)
+end
+
+# PUTSTACKI -- Put an integer in the top row of a table stack
+
+procedure putstacki (tp, colname, colval)
+
+pointer tp # i: Table descriptor
+char colname[ARB] # i: Column name
+int colval # i: Column value
+#--
+int top
+pointer cp
+
+int tbpsta()
+
+begin
+ top = tbpsta (tp, TBL_NROWS)
+
+ call tbcfnd (tp, colname, cp, 1)
+ call tbepti (tp, cp, top, colval)
+
+end
+
+# ANDSTACK -- Combine the top two rows of the table stack
+
+procedure andstack (tp)
+
+pointer tp # i: Table descriptor
+#--
+int top
+int tbpsta()
+
+begin
+ top = tbpsta (tp, TBL_NROWS)
+
+ call movtbrow (tp, top, tp, top-1)
+ call tbrdel (tp, top, top)
+end
+
+# MOVSTACK -- Move the top row of one table stack to another
+
+procedure movstack (rtp, wtp)
+
+pointer rtp # i: Table descriptor of table read from
+pointer wtp # i: Table descriptor of table written to
+#--
+int rtop, wtop
+
+int tbpsta()
+
+begin
+ call pushstack (wtp)
+
+ rtop = tbpsta (rtp, TBL_NROWS)
+ wtop = tbpsta (wtp, TBL_NROWS)
+
+ call movtbrow (rtp, rtop, wtp, wtop)
+ call tbrdel (rtp, rtop, rtop)
+
+end
diff --git a/pkg/utilities/nttools/texpand/span.x b/pkg/utilities/nttools/texpand/span.x
new file mode 100644
index 00000000..b8d69141
--- /dev/null
+++ b/pkg/utilities/nttools/texpand/span.x
@@ -0,0 +1,97 @@
+# SPAN -- Copy characters while they match a set
+#
+# B.Simon 25-Apr-88 Original
+
+int procedure span (set, str, ic, outstr, maxch)
+
+char set[ARB] # i: Set of characters used in matching
+char str[ARB] # i: Input string
+int ic # io: Index to input string character
+char outstr[ARB] # o: Output string
+int maxch # i: Maximum length of output string
+#--
+bool match
+int jc, kc, setlen
+
+int strlen()
+
+begin
+ # Loop over characters in the input string
+
+ setlen = strlen (set)
+ for (jc = 1; str[ic] != EOS && jc <= maxch; ic = ic + 1) {
+
+ # See if the current character in the input string
+ # matches the characters in the set
+
+ match = false
+ do kc = 1, setlen {
+ if (str[ic] == set[kc]) {
+ match = true
+ break
+ }
+ }
+
+ # Copy character to the output string if it matches
+
+ if (! match)
+ break
+
+ outstr[jc] = str[ic]
+ jc = jc + 1
+
+ }
+
+ # Return number of characters in output string
+
+ outstr[jc] = EOS
+ return (jc - 1)
+end
+
+# NOSPAN -- Copy characters while they do not match a set
+
+int procedure nospan (set, str, ic, outstr, maxch)
+
+char set[ARB] # i: Set of characters used in matching
+char str[ARB] # i: Input string
+int ic # io: Index to input string character
+char outstr[ARB] # o: Output string
+int maxch # i: Maximum length of output string
+#--
+bool match
+int jc, kc, setlen
+
+int strlen()
+
+begin
+ # Loop over characters in the input string
+
+ setlen = strlen (set)
+ for (jc = 1; str[ic] != EOS && jc <= maxch; ic = ic + 1) {
+
+ # See if the current character in the input string
+ # matches the characters in the set
+
+ match = false
+ do kc = 1, setlen {
+ if (str[ic] == set[kc]) {
+ match = true
+ break
+ }
+ }
+
+ # Copy character to the output string if it does not match
+
+ if (match)
+ break
+
+ outstr[jc] = str[ic]
+ jc = jc + 1
+
+ }
+
+ # Return number of characters in output string
+
+ outstr[jc] = EOS
+ return (jc - 1)
+end
diff --git a/pkg/utilities/nttools/texpand/texpand.x b/pkg/utilities/nttools/texpand/texpand.x
new file mode 100644
index 00000000..c89075c1
--- /dev/null
+++ b/pkg/utilities/nttools/texpand/texpand.x
@@ -0,0 +1,94 @@
+include <fset.h>
+
+# TEXPAND -- Expand the rows of a table according to a set of rules
+#
+# B.Simon 25-Apr-88 Original
+# Phil Hodge 4-Oct-95 Use table name template routines tbnopenp, etc.
+
+procedure texpand ()
+
+#--
+pointer ilist # Input file name template
+pointer olist # Output file name template
+pointer rbase # Name of file containing expansion rules
+pointer debug # Debug file name
+bool verbose # Diagnostic message flag
+
+int junk, dbg
+pointer sp, itp, otp, input, output, target, action
+
+bool clgetb()
+int open(), tbnlen(), tbnget()
+pointer tbnopenp(), tbtopn()
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (input, SZ_FNAME, TY_CHAR)
+ call salloc (output, SZ_FNAME, TY_CHAR)
+ call salloc (rbase, SZ_FNAME, TY_CHAR)
+ call salloc (debug, SZ_FNAME, TY_CHAR)
+
+ # Read the parameter file
+
+ ilist = tbnopenp ("input")
+ olist = tbnopenp ("output")
+ call clgstr ("rbase", Memc[rbase], SZ_FNAME)
+ call clgstr ("debug", Memc[debug], SZ_FNAME)
+ verbose = clgetb ("verbose")
+
+ # Open debug file
+
+ if (Memc[debug] == ' ' || Memc[debug] == EOS)
+ dbg = NULL
+ else
+ dbg = open (Memc[debug], NEW_FILE, TEXT_FILE)
+
+ # Check to see that input & output templates
+ # have same number of files
+
+ if (tbnlen (ilist) != tbnlen (olist))
+ call error (ERR, "Number of input and output tables do not match")
+
+ while (tbnget (ilist, Memc[input], SZ_FNAME) != EOF) {
+
+ junk = tbnget (olist, Memc[output], SZ_FNAME)
+
+ # Open input and output tables
+
+ itp = tbtopn (Memc[input], READ_ONLY, NULL)
+ otp = tbtopn (Memc[output], NEW_COPY, itp)
+ call tbtcre (otp)
+ call tbhcal (itp, otp)
+
+ # Create target and action tables from the rule base
+
+ call parser (Memc[rbase], itp, dbg, target, action)
+
+ # Expand the rows of the input table using the rules
+ # encoded in the target and action tables
+
+ call use_rules (itp, otp, target, action, dbg, verbose)
+
+ # Print diagnostic message and close tables
+
+ if (verbose) {
+ call tbtnam (itp, Memc[input], SZ_FNAME)
+ call tbtnam (otp, Memc[output], SZ_FNAME)
+
+ call printf ("%s -> %s\n")
+ call pargstr (Memc[input])
+ call pargstr (Memc[output])
+ call flush (STDOUT)
+ }
+
+ call tbtclo (itp)
+ call tbtclo (otp)
+ }
+
+ call close (dbg)
+ call tbnclose (ilist)
+ call tbnclose (olist)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/texpand/userules.x b/pkg/utilities/nttools/texpand/userules.x
new file mode 100644
index 00000000..6195b148
--- /dev/null
+++ b/pkg/utilities/nttools/texpand/userules.x
@@ -0,0 +1,286 @@
+include <tbset.h>
+
+# USE_RULES -- Use the rules to expand the input table rows
+#
+# B.Simon 25-Apr-88 Original
+# B.Simon 21-Jan-99 Modified to handle empty target tables
+
+procedure use_rules (itp, otp, target, action, dbg, verbose)
+
+pointer itp # i: Input table
+pointer otp # i: Output table
+pointer target # u: Table of rule targets
+pointer action # u: Table of rule actions
+int dbg # i: Debug file descriptor
+bool verbose # i: Print diagnostic message
+#--
+int top, nrow, irow
+pointer work
+
+int tbpsta()
+int initstack(), numstack(), find_rule(), apply_rule()
+
+string tgtname "The following is the target table:"
+string actname "The following is the action table:"
+string isstart "The following row is read from the input table:"
+string isdone "The following row is moved to the output table:"
+
+begin
+ # Do straight copy if target table is empty
+
+ top = numstack (target)
+ if (top == 0) {
+ call no_rule (itp, otp)
+ return
+ }
+
+ # Print target and action tables
+
+ call dbg_rules (target, tgtname, 1, top, dbg)
+
+ top = numstack (action)
+ call dbg_rules (action, actname, 1, top, dbg)
+
+ # Create a work table, which is used to store
+ # intermediate results
+
+ work = initstack (itp, "_TARGET,_INDEX")
+
+ # Loop over each row in the input table
+
+ nrow = tbpsta (itp, TBL_NROWS)
+ do irow = 1, nrow {
+
+ call dbg_rules (itp, isstart, irow, irow, dbg)
+
+ # Push the next row from the input table
+ # into the work table. If it does not match
+ # any rule, write it to the output table.
+
+ call pushstack (work)
+ call movtbrow (itp, irow, work, 1)
+ if (find_rule (target, work) == 0) {
+ top = numstack (work)
+ call dbg_rules (work, isdone, top, top, dbg)
+ call movstack (work, otp)
+ }
+
+ # Apply the next instance of the rule to the
+ # row on top of the stack. If the result of the
+ # application of the rule does not match any other
+ # rule, write it to the output table.
+
+ while (numstack (work) > 0) {
+ if (apply_rule (target, action, work, dbg) == 0) {
+ top = numstack (work)
+ call dbg_rules (work, isdone, top, top, dbg)
+ call movstack (work, otp)
+ if (verbose && mod (numstack (otp), 25) == 0) {
+ call printf ("\r%d rows written to output table")
+ call pargi (numstack (otp))
+ call flush (STDOUT)
+ }
+ }
+ }
+ }
+
+ if (verbose) {
+ call printf ("\r%39w\r")
+ call flush (STDOUT)
+ }
+
+ call freestack (target)
+ call freestack (action)
+ call freestack (work)
+end
+
+# APPLY_RULE -- Expand the top work table row according to a rule
+
+int procedure apply_rule (target, action, work, dbg)
+
+pointer target # i: Table of rule targets
+pointer action # i: Table of rule actions
+pointer work # i: Table of intermediate results
+int dbg # i: Debug file descriptor
+#--
+int wrow, trow, arow, last, rule
+pointer tgt_ptr, idx_ptr, lst_ptr, use_ptr
+
+string isrule "The following rule is applied:"
+string notdone "To produce the row:"
+
+int numstack(), find_rule()
+
+begin
+ # Get column pointers of special columns
+
+ call tbcfnd (work, "_TARGET", tgt_ptr, 1)
+ call tbcfnd (work, "_INDEX", idx_ptr, 1)
+ call tbcfnd (target, "_LAST", lst_ptr, 1)
+
+ # Get the current row numbers for the work, target,
+ # and action tables
+
+ wrow = numstack (work)
+ call tbegti (work, tgt_ptr, wrow, trow)
+ call tbegti (work, idx_ptr, wrow, arow)
+ call tbegti (target, lst_ptr, trow, last)
+
+ # If the action row number is greater than the last action
+ # associated with the target, all the expansions for this
+ # rule have been performed. Pop the work table and mark the
+ # target row as unused.
+
+ if (arow > last) {
+ call popstack (work)
+ call tbcfnd (target, "_USED", use_ptr, 1)
+ call tbepti (target, use_ptr, trow, NO)
+ rule = trow
+
+ # Otherwise, duplicate the top row of the work table and
+ # overwrite the appropriate columns with the values stored
+ # in the action row. Increment the action row for next time.
+ # Initialize the special columns in the new row of the work
+ # table.
+
+ } else {
+ call pushstack (work)
+ call movtbrow (work, wrow, work, wrow+1)
+ call movtbrow (action, arow, work, wrow+1)
+ call tbepti (work, idx_ptr, wrow, arow+1) ## should be wrow+1 ??
+ call dbg_rules (target, isrule, trow, trow, dbg)
+ call dbg_rules (work, notdone, wrow+1, wrow+1, dbg)
+ rule = find_rule (target, work)
+ }
+
+ return (rule)
+end
+
+# FIND_RULE -- Find the target row which matches the top work table row
+
+int procedure find_rule (target, work)
+
+pointer target # i: Table of rule targets
+pointer work # i: Table of intermediate results
+#--
+bool match, nullflg
+int icol, jcol, tcol, wcol, trow, irow, wrow, used, first
+pointer sp, tarptr, wrkptr, colname, tarval, wrkval
+pointer use_ptr, fst_ptr, tgt_ptr, idx_ptr, iw
+
+bool strne()
+int tbpsta(), strlen()
+pointer tbcnum(), numstack()
+
+begin
+ # Get number of columns in tables
+
+ tcol = tbpsta (target, TBL_NCOLS)
+ wcol = tbpsta (work, TBL_NCOLS)
+
+ # Allocate dynamic memory
+
+ call smark (sp)
+ call salloc (tarptr, tcol, TY_INT)
+ call salloc (wrkptr, tcol, TY_INT)
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+ call salloc (tarval, SZ_LINE, TY_CHAR)
+ call salloc (wrkval, SZ_LINE, TY_CHAR)
+
+ # Create arrays of corresponding column pointers
+ # in the target and work tables
+
+ jcol = 0
+ do icol = 1, tcol {
+ Memi[tarptr+jcol] = tbcnum (target, icol)
+ call tbcigt (Memi[tarptr+jcol), TBL_COL_NAME,
+ Memc[colname], SZ_COLNAME)
+ call tbcfnd (work, Memc[colname], Memi[wrkptr+jcol], 1)
+ if (Memc[colname] != '_' && Memi[wrkptr+jcol] != NULL)
+ jcol = jcol + 1
+ }
+
+ # Get pointers to special columns
+
+ call tbcfnd (target, "_USED", use_ptr, 1)
+ call tbcfnd (target, "_FIRST", fst_ptr, 1)
+ call tbcfnd (work, "_TARGET", tgt_ptr,1)
+ call tbcfnd (work, "_INDEX", idx_ptr, 1)
+
+ # Search for a match in the target table
+ # with the top row of the work table
+
+ match = false
+ wrow = numstack (work)
+ trow = tbpsta (target, TBL_NROWS)
+ do irow = 1, trow {
+
+ call tbegti (target, use_ptr, irow, used)
+ if (used == NO) {
+
+ # Compare each non-null column of the target row
+ # to the work row
+
+ match = true
+ do icol = 1, jcol {
+ call tbrgtt (target, Memi[tarptr+icol-1], Memc[tarval],
+ nullflg, SZ_LINE, 1, irow)
+
+ if (! nullflg) {
+ call tbegtt (work, Memi[wrkptr+icol-1], wrow,
+ Memc[wrkval], SZ_LINE)
+
+ iw = strlen (Memc[wrkval]) + wrkval - 1
+ while (Memc[iw] == ' ')
+ iw = iw - 1
+ Memc[iw+1] = EOS
+
+ if (strne (Memc[tarval], Memc[wrkval])) {
+ match = false
+ break
+ }
+ }
+ }
+
+ # If the rows match, mark the target row as used
+ # and initialize the special columns in the work row
+
+ if (match) {
+
+ call tbepti (target, use_ptr, irow, YES)
+
+ call tbegti (target, fst_ptr, irow, first)
+ call tbepti (work, idx_ptr, wrow, first)
+ call tbepti (work, tgt_ptr, wrow, irow)
+
+ break
+ }
+ }
+ }
+
+ call sfree (sp)
+
+ # If a match was found, return the target row number matched
+
+ if (match)
+ return (irow)
+ else
+ return (0)
+end
+
+# NO_RULE -- Do a straight copy when ther are no expansion rules
+
+procedure no_rule (itp, otp)
+
+pointer itp # i: Input table
+pointer otp # i: Output table
+#--
+int irow, nrow
+int tbpsta()
+
+begin
+ nrow = tbpsta (itp, TBL_NROWS)
+
+ do irow = 1, nrow
+ call tbrcpy (itp,otp, irow, irow)
+end
diff --git a/pkg/utilities/nttools/texpand/x_texpand.x b/pkg/utilities/nttools/texpand/x_texpand.x
new file mode 100644
index 00000000..37d7f51e
--- /dev/null
+++ b/pkg/utilities/nttools/texpand/x_texpand.x
@@ -0,0 +1,3 @@
+# X_TEXPAND -- Dummy main routine for texpand
+
+task texpand = texpand
diff --git a/pkg/utilities/nttools/thedit.par b/pkg/utilities/nttools/thedit.par
new file mode 100644
index 00000000..fe981799
--- /dev/null
+++ b/pkg/utilities/nttools/thedit.par
@@ -0,0 +1,7 @@
+table,s,a,"",,,tables to be edited
+keywords,s,a,"",,,keywords to be edited
+value,s,a,".",,,value expression
+delete,b,h,no,,,delete rather than edit keywords?
+show,b,h,yes,,,print record of each edit operation?
+Version,s,h,"8Sept2000",,,"date of installation"
+mode,s,h,"al"
diff --git a/pkg/utilities/nttools/thedit/mkpkg b/pkg/utilities/nttools/thedit/mkpkg
new file mode 100644
index 00000000..5b9e150a
--- /dev/null
+++ b/pkg/utilities/nttools/thedit/mkpkg
@@ -0,0 +1,13 @@
+# Update thedit in the ttools package library.
+# Author: HODGE, 10-MAY-2000
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ t_thedit.x <error.h> <evexpr.h> <ctype.h> <lexnum.h> <tbset.h>
+ t_thselect.x <error.h> <evexpr.h> <ctype.h> <tbset.h>
+ tkw.x <ctype.h> <finfo.h> <time.h> <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/thedit/t_thedit.x b/pkg/utilities/nttools/thedit/t_thedit.x
new file mode 100644
index 00000000..3fac69de
--- /dev/null
+++ b/pkg/utilities/nttools/thedit/t_thedit.x
@@ -0,0 +1,833 @@
+include <error.h>
+include <evexpr.h>
+include <ctype.h>
+include <lexnum.h>
+include <tbset.h>
+
+define SZ_TABLENAME (SZ_FNAME) # max size of a table name
+define SZ_KEYWORDNAME 31 # max size of a keyword name
+
+define OP_EDIT 1 # hedit opcodes
+define OP_DELETE 2
+define OP_PRINT 3
+
+
+# thedit -- Edit or view selected keywords of a table header or headers. This
+# editor performs a single edit operation upon a relation, e.g., upon a set
+# of keywords of a set of tables. Templates and expressions may be used to
+# automatically select the tables and keywords to be edited, and to compute
+# the new value of each keyword.
+#
+# Phil Hodge, 10-May-2000 Task created, based on hedit.
+# Phil Hodge, 26-May-2000 When adding a keyword, check for invalid characters.
+# Phil Hodge, 31-May-2000 Add "keywords" i_nrows, etc.
+# Phil Hodge, 19-Jul-2000 In he_getop, call tkw_special before tbhgtt,
+# rather than explicitly checking for $I.
+# Phil Hodge, 8-Sep-2000 Require value = "\." or "\," in order to actually
+# set a keyword value to "." or ",". ("\," is for protection
+# against accidentally typing "," instead of ".".)
+# In he_add_keyword, include the new value in the message
+# (if show=yes). In he_put_keyword, include both the old and
+# new values in the message.
+# Phil Hodge, 4-Mar-2002 Call xev_freeop to free memory allocated by evexpr.
+# Phil Hodge, 1-Apr-2003 Fix incorrect calling sequence for tkw_open
+# in he_delete.
+
+procedure t_thedit()
+
+pointer keywords # template listing keywords to be processed
+pointer valexpr # the value expression (if op=edit|add)
+
+pointer tnt
+pointer sp, s_valexpr, table, template, buf
+pointer tp # pointer to table struct
+pointer kw # pointer to table keyword struct
+pointer vip # for deleting whitespace in valexpr
+pointer newval # valexpr after evaluation
+int operation, show
+int ip, ctowrd()
+int nkw, tkw_len() # number of keywords that match the template
+int dtype # data type of expression
+
+pointer tbtopn()
+pointer tkw_open()
+bool clgetb(), streq()
+bool tbhisc()
+int btoi(), tbnopenp(), tbnget()
+int i, strlen()
+errchk he_print, he_delete, he_add_keyword, he_put_keyword, he_evaluate
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_FNAME, TY_CHAR)
+ call salloc (table, SZ_FNAME, TY_CHAR)
+ call salloc (keywords, SZ_LINE, TY_CHAR)
+ call salloc (template, SZ_FNAME, TY_CHAR)
+ call salloc (s_valexpr, SZ_LINE, TY_CHAR)
+ call salloc (newval, SZ_LINE, TY_CHAR)
+
+ # Get the list of table names.
+ tnt = tbnopenp ("table")
+
+ # Determine type of operation to be performed. The default operation
+ # is edit.
+
+ operation = OP_EDIT
+ if (clgetb ("delete"))
+ operation = OP_DELETE
+
+ # Get list of keywords to be edited, added, or deleted.
+ call clgstr ("keywords", Memc[keywords], SZ_LINE)
+ do i = 1, strlen (Memc[keywords]) {
+ if (Memc[keywords+i-1] == ',')
+ Memc[keywords+i-1] = ' ' # replace comma with blank
+ }
+
+ # The value expression parameter is not used for the delete operation.
+ if (operation != OP_DELETE) {
+ call clgstr ("value", Memc[s_valexpr], SZ_LINE)
+ for (vip=s_valexpr; IS_WHITE (Memc[vip]); vip=vip+1)
+ ;
+ valexpr = vip
+ while (Memc[vip] != EOS)
+ vip = vip + 1
+ while (vip > valexpr && IS_WHITE (Memc[vip-1]))
+ vip = vip - 1
+ Memc[vip] = EOS
+ } else {
+ Memc[s_valexpr] = EOS
+ valexpr = s_valexpr
+ }
+ # Check for value = ",", which could be a typo.
+ if (streq (Memc[valexpr], ",")) {
+ call error (1,
+ "In order to set a keyword value to ',' you must use value='\,'")
+ } else if (streq (Memc[valexpr], "\,")) {
+ call strcpy (",", Memc[valexpr], SZ_LINE)
+ }
+
+ # Get switches. If the expression value is ".", meaning print value
+ # rather than edit, then we do not use the switches.
+
+ if (streq (Memc[valexpr], ".")) {
+ operation = OP_PRINT
+ show = NO
+ } else {
+ show = btoi (clgetb ("show"))
+ }
+
+ # In order to set the keyword value to ".", specify value="\.".
+ if (streq (Memc[valexpr], "\."))
+ call strcpy (".", Memc[valexpr], SZ_LINE)
+
+ # Main processing loop. A table is processed in each pass through
+ # the loop.
+
+ while (tbnget (tnt, Memc[table], SZ_FNAME) != EOF) {
+
+ # Open the current table.
+ iferr {
+ if (operation == OP_PRINT)
+ tp = tbtopn (Memc[table], READ_ONLY, NULL)
+ else
+ tp = tbtopn (Memc[table], READ_WRITE, NULL)
+ } then {
+ call erract (EA_WARN)
+ next
+ }
+
+ # Get a list of all the keywords in the header.
+ kw = tkw_open (tp)
+
+ # for each keyword or template in blank-separated list ...
+ ip = 1
+ while (ctowrd (Memc[keywords], ip, Memc[template], SZ_FNAME) > 0) {
+
+ # Find all keywords that match the current keyword template.
+ call tkw_find (tp, kw, Memc[template])
+ nkw = tkw_len (kw)
+
+ if (operation == OP_PRINT) {
+
+ call he_print (tp, kw, Memc[table], Memc[template])
+
+ } else if (operation == OP_DELETE) {
+
+ call he_delete (tp, kw, Memc[table], Memc[template], show)
+
+ } else {
+
+ # interpret the value string
+ call he_getopsettable (tp, Memc[table], Memc[template])
+ call he_evaluate (Memc[valexpr],
+ Memc[newval], SZ_LINE, dtype)
+
+ # No keywords match the template, or the keyword is
+ # history or comment?
+ if (nkw == 0 || tbhisc (Memc[template])) {
+
+ # Add a new keyword.
+ call he_add_keyword (tp, Memc[table], Memc[template],
+ Memc[newval], dtype, show)
+
+ } else {
+
+ call he_put_keyword (tp, kw, Memc[table],
+ Memc[template], Memc[newval], dtype, show)
+ }
+ }
+ }
+
+ # Close the keyword list and the table.
+ call tkw_close (kw)
+ call tbtclo (tp)
+
+ call flush (STDOUT)
+ }
+
+ call tbnclose (tnt)
+ call sfree (sp)
+end
+
+
+# This routine prints the value of the keyword or keywords that match
+# the template.
+
+procedure he_print (tp, kw, table, template)
+
+pointer tp # i: pointer to table struct
+pointer kw # i: pointer to keyword struct
+char table[ARB] # i: table name
+char template[ARB] # i: keyword name or template (for warning message)
+#--
+pointer sp
+pointer value, comment
+char keyword[SZ_KEYWORD] # keyword name
+int nkw # number of keywords
+int k
+int tkw_len()
+
+begin
+ nkw = tkw_len (kw)
+
+ if (nkw == 0) {
+ call eprintf ("Warning: keyword(s) `%s' not found.\n")
+ call pargstr (template)
+ } else {
+ call smark (sp)
+ call salloc (value, SZ_FNAME, TY_CHAR)
+ call salloc (comment, SZ_FNAME, TY_CHAR)
+ do k = 1, nkw {
+ call he_gval (tp, kw, k,
+ keyword, Memc[value], Memc[comment], SZ_FNAME)
+ call printf ("%s,%s = %s")
+ call pargstr (table)
+ call pargstr (keyword)
+ call he_pargstr (Memc[value])
+ if (Memc[comment] != EOS) {
+ call printf (" / %s")
+ call pargstr (Memc[comment])
+ }
+ call printf ("\n")
+ }
+ call sfree (sp)
+ }
+end
+
+procedure he_gval (tp, kw, k, keyword, value, comment, maxch)
+
+pointer tp # i: pointer to table struct
+pointer kw # i: pointer to keyword struct
+int k # i: index in list of matched keywords
+char keyword[SZ_KEYWORD] # o: keyword name
+char value[ARB] # o: value of keyword
+char comment[ARB] # o: comment, or null
+int maxch # i: size of value and comment strings
+#--
+pointer sp
+pointer sval
+int i
+int keynum # index in list of all keywords in header
+int dtype # data type of keyword
+bool tbhisc()
+errchk tbhgnp, tbhgcm, tkw_special
+
+begin
+ call smark (sp)
+ call salloc (sval, SZ_FNAME, TY_CHAR)
+
+ call tkw_getkw (kw, k, keynum, keyword, SZ_KEYWORD)
+
+ if (keynum > 0) {
+
+ call tbhgnp (tp, keynum, keyword, dtype, Memc[sval])
+
+ # Delete leading whitespace.
+ do i = 0, SZ_FNAME-1 {
+ if (Memc[sval+i] == EOS)
+ break
+ if (!IS_WHITE(Memc[sval+i]))
+ break
+ }
+ call strcpy (Memc[sval+i], value, maxch)
+
+ if (tbhisc (keyword))
+ comment[1] = EOS
+ else
+ call tbhgcm (tp, keyword, comment, maxch)
+
+ } else {
+
+ call tkw_special (tp, keyword, value, maxch)
+ comment[1] = EOS
+ }
+
+ call sfree (sp)
+end
+
+# This routine deletes one or more keywords from the header.
+# The list of all keywords in the header and the list of keywords that
+# match the template will be reassigned after deleting.
+
+procedure he_delete (tp, kw, table, template, show)
+
+pointer tp # i: pointer to table struct
+pointer kw # io: pointer to keyword struct
+char table[ARB] # i: table name
+char template[ARB] # i: keyword name or template
+int show # i: print info?
+#--
+char keyword[SZ_KEYWORD] # keyword name
+int nkw # number of keywords
+int keynum # index in list of all keywords in header
+int k
+pointer tkw_open()
+int tkw_len()
+errchk tbhdel
+
+begin
+ nkw = tkw_len (kw)
+
+ if (nkw == 0) {
+ call eprintf ("Warning: keyword(s) `%s' not found.\n")
+ call pargstr (template)
+ } else {
+
+ do k = nkw, 1, -1 {
+ call tkw_getkw (kw, k, keynum, keyword, SZ_KEYWORD)
+ if (keynum <= 0) {
+ call eprintf (
+ "Warning: can't delete special keyword %s.\n")
+ call pargstr (keyword)
+ next
+ }
+ call tbhdel (tp, keynum)
+ if (show == YES) {
+ call printf ("%s,%s deleted\n")
+ call pargstr (table)
+ call pargstr (keyword)
+ }
+ }
+
+ # Update the list of the current keywords, since we've deleted some.
+ call tkw_close (kw)
+ kw = tkw_open (tp)
+ }
+end
+
+# This routine adds a new keyword to the header.
+
+procedure he_add_keyword (tp, table, keyword, newval, dtype, show)
+
+pointer tp # i: pointer to table struct
+char table[ARB] # i: table name
+char keyword[ARB] # i: keyword name or template
+char newval[ARB] # i: value to assign to keyword
+int dtype # i: data type of newval
+int show # i: print info?
+#--
+int i
+bool bval
+int ival
+real rval
+double dval
+int nscan()
+errchk tbhadd, tbhadr, tbhadi, tbhadb, tbhadt
+
+begin
+ # Check that the keyword name is valid.
+ do i = 1, SZ_KEYWORD {
+
+ if (keyword[i] == EOS)
+ break
+
+ if (keyword[i] == '*' || keyword[i] == '?') {
+ call eprintf (
+ "Warning: keyword `%s' doesn't match any keyword in the header;\n")
+ call pargstr (keyword)
+ call eprintf (" this keyword template will be ignored.\n")
+ return
+ }
+
+ # All the following are OK:
+ if (IS_UPPER(keyword[i]))
+ next
+ if (IS_LOWER(keyword[i]))
+ next
+ if (IS_DIGIT(keyword[i]))
+ next
+ if (keyword[i] == '_' || keyword[i] == '-')
+ next
+
+ # If we get here, the character is invalid.
+ call eprintf ("Warning: invalid character `%c' in keyword `%s';\n")
+ call pargc (keyword[i])
+ call pargstr (keyword)
+ call eprintf (" this keyword will not be added to the header.\n")
+ return
+ }
+
+ switch (dtype) {
+ case TY_DOUBLE:
+ call sscan (newval)
+ call gargd (dval)
+ if (nscan() < 1) {
+ call eprintf ("can't interpret %s as a floating point value\n")
+ call pargstr (newval)
+ call error (1, "")
+ }
+ call tbhadd (tp, keyword, dval)
+
+ case TY_REAL:
+ call sscan (newval)
+ call gargr (rval)
+ if (nscan() < 1) {
+ call eprintf ("can't interpret %s as a floating point value\n")
+ call pargstr (newval)
+ call error (1, "")
+ }
+ call tbhadr (tp, keyword, rval)
+
+ case TY_INT:
+ call sscan (newval)
+ call gargi (ival)
+ if (nscan() < 1) {
+ call eprintf ("can't interpret %s as an integer\n")
+ call pargstr (newval)
+ call error (1, "")
+ }
+ call tbhadi (tp, keyword, ival)
+
+ case TY_BOOL:
+ call sscan (newval)
+ call gargb (bval)
+ if (nscan() < 1) { # shouldn't happen
+ call eprintf ("can't interpret %s as a boolean value\n")
+ call pargstr (newval)
+ call error (1, "")
+ }
+ call tbhadb (tp, keyword, bval)
+
+ default:
+ call tbhadt (tp, keyword, newval)
+ }
+
+ if (show == YES) {
+ call printf ("add %s,%s = %s\n")
+ call pargstr (table)
+ call pargstr (keyword)
+ call he_pargstr (newval)
+ }
+end
+
+procedure he_put_keyword (tp, kw, table, template, newval, dtype, show)
+
+pointer tp # i: pointer to table struct
+pointer kw # i: pointer to keyword struct
+char table[ARB] # i: table name
+char template[ARB] # i: keyword name or template
+char newval[ARB] # i: value to assign to keyword
+int dtype # i: data type of newval
+int show # i: print info?
+#--
+bool bval
+int ival
+real rval
+double dval
+char oldval[SZ_FNAME] # current value of keyword (if show is YES)
+char keyword[SZ_KEYWORD] # name of current keyword
+int keynum # index in list of all keywords in header
+int k
+int nkw, tkw_len()
+int nscan()
+errchk tbhptd, tbhptr, tbhpti, tbhptb, tbhptt
+
+begin
+ nkw = tkw_len (kw)
+
+ # for each keyword that matches the template ...
+ do k = 1, nkw {
+
+ call tkw_getkw (kw, k, keynum, keyword, SZ_KEYWORD)
+ if (keynum <= 0) {
+ call eprintf ("Warning: can't modify special keyword %s.\n")
+ call pargstr (keyword)
+ next
+ }
+
+ if (show == YES) { # get the current value
+ call tbhgtt (tp, keyword, oldval, SZ_FNAME)
+ }
+
+ switch (dtype) {
+ case TY_DOUBLE:
+ call sscan (newval)
+ call gargd (dval)
+ if (nscan() < 1) {
+ call eprintf (
+ "can't interpret %s as a floating point value\n")
+ call pargstr (newval)
+ call error (1, "")
+ }
+ call tbhptd (tp, keyword, dval)
+
+ case TY_REAL:
+ call sscan (newval)
+ call gargr (rval)
+ if (nscan() < 1) {
+ call eprintf (
+ "can't interpret %s as a floating point value\n")
+ call pargstr (newval)
+ call error (1, "")
+ }
+ call tbhptr (tp, keyword, rval)
+
+ case TY_INT:
+ call sscan (newval)
+ call gargi (ival)
+ if (nscan() < 1) {
+ call eprintf ("can't interpret %s as an integer\n")
+ call pargstr (newval)
+ call error (1, "")
+ }
+ call tbhadi (tp, keyword, ival)
+
+ case TY_BOOL:
+ call sscan (newval)
+ call gargb (bval)
+ if (nscan() < 1) { # shouldn't happen
+ call eprintf ("can't interpret %s as a boolean value\n")
+ call pargstr (newval)
+ call error (1, "")
+ }
+ call tbhadb (tp, keyword, bval)
+
+ default:
+ call tbhptt (tp, keyword, newval)
+ }
+
+ if (show == YES) {
+ call printf ("%s,%s updated: %s -> %s\n")
+ call pargstr (table)
+ call pargstr (keyword)
+ call he_pargstr (oldval)
+ call he_pargstr (newval)
+ }
+ }
+end
+
+# This routine copies the value from valexpr to newval and interprets
+# the data type of the result. If valexpr begins with "(", it will be
+# passed to evexpr to evaluate it, and the resulting string will be
+# returned as newval.
+
+procedure he_evaluate (valexpr, newval, maxch, dtype)
+
+char valexpr[ARB] # i: value expression
+char newval[ARB] # o: value
+int maxch # i: size of newval
+int dtype # o: data type of expression
+#--
+pointer o # evexpr pointer
+pointer evexpr()
+int locpr()
+bool streq()
+int he_dtype()
+extern he_getop()
+
+begin
+ if (streq (valexpr, ".")) {
+
+ call strcpy (valexpr, newval, maxch)
+ dtype = TY_CHAR # irrelevant
+
+ } else if (valexpr[1] == '(') {
+
+ # Evaluate the expression given in parentheses.
+ o = evexpr (valexpr, locpr (he_getop), 0)
+
+ switch (O_TYPE(o)) { # evexpr only supports these data types
+ case TY_BOOL:
+ dtype = TY_BOOL
+ call sprintf (newval, maxch, "%b")
+ call pargb (O_VALB(o))
+ case TY_CHAR:
+ dtype = TY_CHAR
+ call sprintf (newval, maxch, "%s")
+ call pargstr (O_VALC(o))
+ case TY_INT:
+ dtype = TY_INT
+ call sprintf (newval, maxch, "%d")
+ call pargi (O_VALI(o))
+ case TY_REAL:
+ dtype = TY_REAL
+ call sprintf (newval, maxch, "%g")
+ call pargr (O_VALR(o))
+ default:
+ call error (1, "unknown expression datatype")
+ }
+ call xev_freeop (o)
+ call mfree (o, TY_STRUCT)
+
+ } else {
+
+ # Interpret the data type, and copy the string from valexpr to
+ # newval.
+ dtype = he_dtype (valexpr, newval, maxch)
+ }
+end
+
+# This function returns the data type of value, and it copies value to
+# newval. If the data type is boolean, don't complain if the user gave
+# the value in a nonstandard form, such as "T" or "F", but then assign
+# the standard "yes" or "no" to newval (that's the reason for copying
+# value to newval).
+
+int procedure he_dtype (value, newval, maxch)
+
+char value[ARB] # i: the value encoded as a string
+char newval[ARB] # o: same as lower case value, unless type is boolean
+int maxch # i: max size of newval
+#--
+int dtype # the data type, to be returned
+bool numeric
+int tok_type, ip, numlen
+int lexnum()
+int strlen()
+bool streq()
+
+begin
+ # Use newval for scratch, to convert to lower case for the
+ # tests on boolean data type.
+ call strcpy (value, newval, maxch)
+ call strlwr (newval)
+
+ if (streq (newval, "yes") ||
+ streq (newval, "true") ||
+ streq (newval, "t")) {
+
+ dtype = TY_BOOL
+
+ call strcpy ("yes", newval, maxch)
+
+ } else if (streq (newval, "no") ||
+ streq (newval, "false") ||
+ streq (newval, "f")) {
+
+ dtype = TY_BOOL
+
+ call strcpy ("no", newval, maxch)
+
+ } else {
+
+ ip = 1
+ tok_type = lexnum (value, ip, numlen)
+ numeric = (tok_type != LEX_NONNUM && numlen == strlen (value))
+
+ if (numeric) {
+ if (tok_type == LEX_OCTAL || tok_type == LEX_DECIMAL ||
+ tok_type == LEX_HEX) {
+ dtype = TY_INT
+ } else if (tok_type == LEX_REAL) {
+ dtype = TY_DOUBLE
+ } else {
+ dtype = TY_CHAR # shouldn't happen
+ }
+ } else {
+ dtype = TY_CHAR
+ }
+
+ call strcpy (value, newval, maxch)
+ }
+
+ return (dtype)
+end
+
+# HE_GETOP -- Satisfy an operand request from EVEXPR. The value of the
+# current keyword is gotten from the table header.
+#
+# Note that HE_GETOPSETTABLE must first have been called to save the
+# table pointer and keyword name in the common block.
+
+procedure he_getop (operand, o)
+
+char operand[ARB] # operand name
+pointer o # operand (output)
+
+pointer sp
+pointer keyword # scratch for current keyword name
+pointer value # scratch for value
+pointer newvalue # value in lower case; "yes" or "no" for bool value
+int dtype # data type of keyword
+pointer h_tp # getop common
+char h_table[SZ_TABLENAME]
+char h_keyword[SZ_KEYWORDNAME]
+common /hegop2/ h_tp, h_table, h_keyword
+int he_dtype()
+bool streq()
+errchk tbhgtt
+
+begin
+ call smark (sp)
+ call salloc (value, SZ_FNAME, TY_CHAR)
+ call salloc (newvalue, SZ_FNAME, TY_CHAR)
+ call salloc (keyword, SZ_KEYWORDNAME, TY_CHAR)
+
+ if (streq (operand, "$"))
+ call strcpy (h_keyword, Memc[keyword], SZ_KEYWORDNAME)
+ else
+ call strcpy (operand, Memc[keyword], SZ_KEYWORDNAME)
+
+ # Get the value and interpret its data type.
+ iferr {
+ call tkw_special (h_tp, Memc[keyword], Memc[value], SZ_FNAME)
+ } then {
+ call tbhgtt (h_tp, Memc[keyword], Memc[value], SZ_FNAME)
+ }
+
+ dtype = he_dtype (Memc[value], Memc[newvalue], SZ_FNAME)
+
+ switch (dtype) {
+ case TY_BOOL:
+ call xev_initop (o, 0, TY_BOOL)
+ O_VALB(o) = (streq (Memc[newvalue], "yes"))
+
+ case TY_SHORT, TY_INT, TY_LONG:
+ call xev_initop (o, 0, TY_INT)
+ call sscan (Memc[value])
+ call gargi (O_VALI(o))
+
+ case TY_REAL, TY_DOUBLE, TY_COMPLEX:
+ call xev_initop (o, 0, TY_REAL)
+ call sscan (Memc[value])
+ call gargr (O_VALR(o))
+
+ default:
+ call xev_initop (o, SZ_LINE, TY_CHAR)
+ call strcpy (Memc[value], O_VALC(o), SZ_LINE)
+ }
+
+ call sfree (sp)
+end
+
+
+# HE_GETOPSETTABLE -- Copy the table pointer, table name, and keyword name
+# to a common block in preparation for a getop call by EVEXPR.
+
+procedure he_getopsettable (tp, table, keyword)
+
+pointer tp # table descriptor of table to be edited
+char table[ARB] # name of table to be edited
+char keyword[ARB] # name of keyword to be edited
+
+pointer h_tp # getop common
+char h_table[SZ_TABLENAME]
+char h_keyword[SZ_KEYWORDNAME]
+common /hegop2/ h_tp, h_table, h_keyword
+
+begin
+ h_tp = tp
+ call strcpy (table, h_table, SZ_TABLENAME)
+ call strcpy (keyword, h_keyword, SZ_KEYWORDNAME)
+end
+
+
+# HE_ENCODEOP -- Encode an operand as returned by EVEXPR as a string. EVEXPR
+# operands are restricted to the datatypes bool, int, real, and string.
+
+procedure he_encodeop (o, outstr, maxch)
+
+pointer o # operand to be encoded
+char outstr[ARB] # output string
+int maxch # max chars in outstr
+
+begin
+ switch (O_TYPE(o)) {
+ case TY_BOOL:
+ call sprintf (outstr, maxch, "%b")
+ call pargb (O_VALB(o))
+ case TY_CHAR:
+ call sprintf (outstr, maxch, "%s")
+ call pargstr (O_VALC(o))
+ case TY_INT:
+ call sprintf (outstr, maxch, "%d")
+ call pargi (O_VALI(o))
+ case TY_REAL:
+ call sprintf (outstr, maxch, "%g")
+ call pargr (O_VALR(o))
+ default:
+ call error (1, "unknown expression datatype")
+ }
+end
+
+
+# HE_PARGSTR -- Pass a string to a printf statement, enclosing the string
+# in quotes if it contains any whitespace.
+
+procedure he_pargstr (str)
+
+char str[ARB] # string to be printed
+int ip
+bool quoteit
+pointer sp, op, buf
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+
+ op = buf
+ Memc[op] = '"'
+ op = op + 1
+
+ # Copy string to scratch buffer, enclosed in quotes. Check for
+ # embedded whitespace.
+
+ quoteit = false
+ for (ip=1; str[ip] != EOS; ip=ip+1) {
+ if (IS_WHITE(str[ip])) { # detect whitespace
+ quoteit = true
+ Memc[op] = str[ip]
+ } else if (str[ip] == '\n') { # prettyprint newlines
+ Memc[op] = '\\'
+ op = op + 1
+ Memc[op] = 'n'
+ } else # normal characters
+ Memc[op] = str[ip]
+
+ if (ip < SZ_LINE)
+ op = op + 1
+ }
+
+ # If whitespace was seen pass the quoted string, otherwise pass the
+ # original input string.
+
+ if (quoteit) {
+ Memc[op] = '"'
+ op = op + 1
+ Memc[op] = EOS
+ call pargstr (Memc[buf])
+ } else
+ call pargstr (str)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/thedit/t_thselect.x b/pkg/utilities/nttools/thedit/t_thselect.x
new file mode 100644
index 00000000..db6f9077
--- /dev/null
+++ b/pkg/utilities/nttools/thedit/t_thselect.x
@@ -0,0 +1,150 @@
+include <error.h>
+include <evexpr.h>
+include <ctype.h>
+include <tbset.h>
+
+define SZ_TABLENAME (SZ_FNAME) # max size of a table name
+define SZ_KEYWORDNAME 31 # max size of a keyword name
+
+
+# thselect -- Print table keyword values, if the specified expression is true.
+#
+# Phil Hodge, 19-Jul-2000 Task created, based on hselect.
+# Phil Hodge, 4-Mar-2002 Free memory allocated by evexpr.
+
+procedure t_thselect()
+
+pointer keywords # template listing keywords to be processed
+pointer expr # boolean expression to be evaluated
+
+pointer tnt
+pointer sp, table
+pointer tp # pointer to table struct
+int i
+
+pointer tbtopn()
+int tbnopenp(), tbnget()
+int strlen()
+errchk he_select
+
+begin
+ call smark (sp)
+ call salloc (table, SZ_FNAME, TY_CHAR)
+ call salloc (keywords, SZ_LINE, TY_CHAR)
+ call salloc (expr, SZ_LINE, TY_CHAR)
+
+ # Get the list of table names.
+ tnt = tbnopenp ("table")
+
+ # Get the list of keyword names.
+ call clgstr ("keywords", Memc[keywords], SZ_LINE)
+ do i = 1, strlen (Memc[keywords]) {
+ if (Memc[keywords+i-1] == ',')
+ Memc[keywords+i-1] = ' ' # replace comma with blank
+ }
+
+ # Get the boolean expression.
+ call clgstr ("expr", Memc[expr], SZ_LINE)
+
+ # Main processing loop. A table is processed in each pass through
+ # the loop.
+
+ while (tbnget (tnt, Memc[table], SZ_FNAME) != EOF) {
+
+ # Open the current table.
+ iferr {
+ tp = tbtopn (Memc[table], READ_ONLY, NULL)
+ } then {
+ call erract (EA_WARN)
+ next
+ }
+
+ # Get the full table name (including extension if FITS).
+ call tbtnam (tp, Memc[table], SZ_FNAME)
+
+ call he_getopsettable (tp, Memc[table], Memc[keywords])
+
+ iferr {
+ call hs_select (tp, Memc[table], Memc[keywords], Memc[expr])
+ } then {
+ call erract (EA_WARN)
+ call tbtclo (tp)
+ next
+ }
+
+ call tbtclo (tp)
+ }
+
+ call tbnclose (tnt)
+ call sfree (sp)
+end
+
+procedure hs_select (tp, table, keywords, expr)
+
+pointer tp # i: pointer to table struct
+char table[ARB] # i: name of current table
+char keywords[ARB] # i: blank-separated list of keyword names
+char expr[ARB] # i: boolean expression
+#--
+pointer sp
+pointer template # one keyword name (may include wildcard characters)
+pointer value, comment
+char keyword[SZ_KEYWORD] # current keyword name
+pointer o
+pointer evexpr()
+int locpr()
+extern he_getop()
+pointer kw, tkw_open()
+int ip, ctowrd()
+int nkw # number of keywords
+int k # loop index in list of matched keywords
+int tkw_len()
+bool first # true if first keyword (template) in keywords
+errchk evexpr
+
+begin
+ call smark (sp)
+ call salloc (template, SZ_FNAME, TY_CHAR)
+ call salloc (value, SZ_FNAME, TY_CHAR)
+ call salloc (comment, SZ_FNAME, TY_CHAR)
+
+ # Evaluate the boolean expression.
+ o = evexpr (expr, locpr(he_getop), 0)
+ if (O_TYPE(o) != TY_BOOL)
+ call error (1, "expression must be boolean")
+
+ # Print the values of the listed keywords if the expression is true.
+ if (O_VALB(o)) {
+
+ # Get a list of all the keywords in the header.
+ kw = tkw_open (tp)
+
+ # for each keyword or template in blank-separated list ...
+ ip = 1
+ first = true
+ while (ctowrd (keywords, ip, Memc[template], SZ_FNAME) > 0) {
+
+ # Find all keywords that match the current keyword template.
+ call tkw_find (tp, kw, Memc[template])
+ nkw = tkw_len (kw)
+
+ # Get and print the keyword values.
+ do k = 1, nkw {
+ call he_gval (tp, kw, k,
+ keyword, Memc[value], Memc[comment], SZ_FNAME)
+ if (!first)
+ call printf ("\t")
+ call printf ("%s")
+ call he_pargstr (Memc[value])
+ first = false
+ }
+ }
+ call printf ("\n")
+ call flush (STDOUT)
+ call tkw_close (kw)
+ }
+
+ call xev_freeop (o)
+ call mfree (o, TY_STRUCT)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/thedit/tkw.x b/pkg/utilities/nttools/thedit/tkw.x
new file mode 100644
index 00000000..9cb9d371
--- /dev/null
+++ b/pkg/utilities/nttools/thedit/tkw.x
@@ -0,0 +1,405 @@
+include <ctype.h>
+include <finfo.h> # for file creation or modification time
+include <time.h>
+include <tbset.h>
+
+# This file contains a set of routines for finding header keywords in a
+# table.
+#
+# kw = tkw_open (tp)
+# call tkw_close (kw)
+# call tkw_find (tp, kw, keyword)
+# nkw = tkw_len (kw)
+# call tkw_reopen (tp, kw, keyword)
+# call tkw_getkw (kw, k, keynum, keyword, maxch)
+# call tkw_special (tp, keyword, value, maxch)
+#
+# Phil Hodge, 10-May-2000 Subroutines created.
+# Phil Hodge, 31-May-2000 Add "keywords" i_nrows, etc.
+# Phil Hodge, 19-Jul-2000 Add support for $I (equivalent to i_table).
+# Phil Hodge, 15-Jul-2009 Remove ttype from calling sequence for tbparse.
+
+define NUM_SPECIAL 7 # number of keywords such as i_nrows
+define N_I_TABLE 1 # index number for i_table
+define N_I_FILE 2 # index number for i_file
+define N_I_CTIME 3
+define N_I_NROWS 4
+define N_I_NCOLS 5
+define N_I_NPAR 6
+define N_I_TYPE 7
+
+define SZ_KW_LIST 5
+define SZ_KW_SPACING (SZ_KEYWORD+2) # spacing of keywords in KW_NAME
+
+define NUM_KEYWORDS Memi[$1] # total number of keywords
+define NUM_MATCH Memi[$1+1] # number of keywords that match template
+define KW_NAME_PTR Memi[$1+2] # list of keyword names
+define KW_TYPE_PTR Memi[$1+3] # list of keyword data types
+define KW_MATCH_PTR Memi[$1+4] # indexes of keywords matching template
+define KW_NAME Memc[KW_NAME_PTR($1) + ($2-1)*SZ_KW_SPACING]
+define KW_TYPE Memi[KW_TYPE_PTR($1) + $2-1]
+define KW_MATCH Memi[KW_MATCH_PTR($1) + $2-1]
+
+# get list of all keywords in header
+
+pointer procedure tkw_open (tp)
+
+pointer tp # i: pointer to table struct
+#--
+pointer kw # o: pointer to keyword list struct
+char keyword[SZ_KEYWORD] # current keyword
+int dtype # data type of current keyword
+char value[SZ_PARREC] # value of current keyword
+int i
+int npar # number of keywords excluding i_nrows, etc
+int keynum # index for keyword number
+int tbpsta()
+errchk tbhgnp
+
+begin
+ call malloc (kw, SZ_KW_LIST, TY_POINTER)
+
+ npar = tbpsta (tp, TBL_NPAR)
+
+ NUM_KEYWORDS(kw) = NUM_SPECIAL + npar
+ NUM_MATCH(kw) = 0 # initial value
+
+ call calloc (KW_NAME_PTR(kw),
+ SZ_KW_SPACING * NUM_KEYWORDS(kw), TY_CHAR)
+
+ call calloc (KW_TYPE_PTR(kw), NUM_KEYWORDS(kw), TY_INT)
+ call calloc (KW_MATCH_PTR(kw), NUM_KEYWORDS(kw), TY_INT)
+
+ # First assign names for the special keywords i_nrows, etc.
+ # This list must agree with those in tkw_special, and the
+ # number of such keywords must be no larger than NUM_SPECIAL.
+
+ call strcpy ("i_table", KW_NAME(kw,N_I_TABLE), SZ_KEYWORD)
+ KW_TYPE(kw,N_I_TABLE) = TY_CHAR
+
+ call strcpy ("i_file", KW_NAME(kw,N_I_FILE), SZ_KEYWORD)
+ KW_TYPE(kw,N_I_FILE) = TY_INT
+
+ call strcpy ("i_ctime", KW_NAME(kw,N_I_CTIME), SZ_KEYWORD)
+ KW_TYPE(kw,N_I_CTIME) = TY_INT
+
+ call strcpy ("i_nrows", KW_NAME(kw,N_I_NROWS), SZ_KEYWORD)
+ KW_TYPE(kw,N_I_NROWS) = TY_INT
+
+ call strcpy ("i_ncols", KW_NAME(kw,N_I_NCOLS), SZ_KEYWORD)
+ KW_TYPE(kw,N_I_NCOLS) = TY_INT
+
+ call strcpy ("i_npar", KW_NAME(kw,N_I_NPAR), SZ_KEYWORD)
+ KW_TYPE(kw,N_I_NPAR) = TY_INT
+
+ call strcpy ("i_type", KW_NAME(kw,N_I_TYPE), SZ_KEYWORD)
+ KW_TYPE(kw,N_I_TYPE) = TY_CHAR
+
+ keynum = 1
+ do i = NUM_SPECIAL+1, NUM_KEYWORDS(kw) {
+
+ call tbhgnp (tp, keynum, keyword, dtype, value)
+ call strcpy (keyword, KW_NAME(kw,i), SZ_KEYWORD)
+ KW_TYPE(kw,i) = dtype
+ keynum = keynum + 1
+ }
+
+ return (kw)
+end
+
+# free memory for keyword list
+
+procedure tkw_close (kw)
+
+pointer kw # io: pointer to keyword list struct
+
+begin
+ if (kw != NULL) {
+ call mfree (KW_NAME_PTR (kw), TY_CHAR)
+ call mfree (KW_TYPE_PTR (kw), TY_INT)
+ call mfree (KW_MATCH_PTR (kw), TY_INT)
+ call mfree (kw, TY_POINTER)
+ kw = NULL
+ }
+end
+
+# expand template for current keyword
+# This can be called repeatedly after tkw_open. Each time it is called,
+# the previous list will be overwritten.
+
+procedure tkw_find (tp, kw, keyword)
+
+pointer tp # i: pointer to table struct
+pointer kw # i: pointer to keyword list struct
+char keyword[ARB] # i: keyword name template
+#--
+pointer sp
+pointer template # keyword converted to upper case, etc
+char pat[SZ_FNAME] # encoded pattern
+int lenpat
+int k # counter for keywords that match template
+int i, nmatch
+int strlen()
+int patmake(), pat_amatch()
+errchk uc_template, patmake, pat_amatch
+
+begin
+ call smark (sp)
+ call salloc (template, SZ_FNAME, TY_CHAR)
+
+ # Convert the keyword to upper case (except for special keywords).
+ call uc_template (keyword, Memc[template], SZ_FNAME)
+
+ lenpat = patmake (Memc[template], pat, SZ_FNAME)
+
+ k = 0
+ do i = 1, NUM_KEYWORDS(kw) {
+
+ if (strlen (KW_NAME(kw,i)) < 1) # ignore blank keywords
+ next
+
+ nmatch = pat_amatch (KW_NAME(kw,i), 1, pat)
+ if (nmatch == strlen (KW_NAME(kw,i))) {
+ k = k + 1
+ KW_MATCH(kw,k) = i
+ }
+ }
+ NUM_MATCH(kw) = k
+
+ call sfree (sp)
+end
+
+# get all current keywords and expand template again
+
+procedure tkw_reopen (tp, kw, keyword)
+
+pointer tp # i: pointer to table struct
+pointer kw # io: pointer to keyword list struct
+char keyword[ARB] # i: keyword name template
+#--
+pointer tkw_open()
+
+begin
+ call tkw_close (kw)
+ kw = tkw_open (tp)
+ call tkw_find (tp, kw, keyword)
+end
+
+# This routine converts the keyword template to upper case (except for
+# special keywords) and replaces "*" with "?*" for use with patmake.
+
+procedure uc_template (keyword, template, maxch)
+
+char keyword[ARB] # i: keyword template
+char template[ARB] # o: template converted to upper case
+int maxch # i: max length of template string
+#--
+char ch
+int ip, op
+int strncmp()
+bool streq()
+
+begin
+ # Make "$I" equivalent to i_table.
+ if (streq (keyword, "$I")) {
+ call strcpy ("i_table", template, maxch)
+ return
+ }
+
+ # Copy special keywords to output without change.
+ if (strncmp (keyword, "i_", 2) == 0) {
+ call strcpy (keyword, template, maxch)
+ return
+ }
+
+ ip = 1
+ op = 1
+ ch = keyword[ip]
+
+ while (ch != EOS) {
+
+ # Map "*" into "?*".
+ if (ch == '*' && ip > 1) {
+ template[op] = '?'
+ op = op + 1
+ }
+
+ if (op > maxch)
+ call error (1, "keyword template string is too long")
+
+ if (IS_LOWER(ch))
+ template[op] = TO_UPPER(ch)
+ else
+ template[op] = ch
+
+ op = op + 1
+ ip = ip + 1
+ ch = keyword[ip]
+ }
+ template[op] = EOS
+end
+
+# This function returns the number of keywords that matched the template,
+# i.e. after calling tkw_find.
+
+int procedure tkw_len (kw)
+
+pointer kw # i: pointer to keyword list struct
+
+begin
+ return (NUM_MATCH(kw))
+end
+
+# This routine can be used to loop through the list of matched keywords,
+# returning the keyword number and name. k is the index in the list of
+# keywords that match the template, and keynum is the index of the keyword
+# in the header. k runs from 1 to tkw_len. keynum can be passed to
+# tbhgnp to get a keyword or to tbhdel to delete a keyword.
+
+procedure tkw_getkw (kw, k, keynum, keyword, maxch)
+
+pointer kw # i: pointer to keyword list struct
+int k # i: index of keyword in list of match keywords
+int keynum # o: keyword number in header
+char keyword[ARB] # o: keyword name
+int maxch # i: max length of keyword string
+#--
+int knum
+
+begin
+ if (k < 1 || k > NUM_MATCH(kw))
+ call error (1, "tkw_getkw: index is out of range")
+
+ knum = KW_MATCH(kw,k)
+ keynum = knum - NUM_SPECIAL
+
+ call strcpy (KW_NAME(kw,knum), keyword, maxch)
+end
+
+# This routine returns the value of one of the special keywords.
+
+procedure tkw_special (tp, keyword, value, maxch)
+
+pointer tp # i: pointer to table struct
+char keyword[ARB] # i: current keyword
+char value[ARB] # o: value of keyword
+int maxch # i: size of value string
+#--
+pointer sp
+pointer tablename # name of table
+pointer filename # name of table without brackets
+pointer hduname # returned by tbparse and ignored
+int hdu # ignored
+int junk, tbparse()
+long ostruct[LEN_FINFO] # contains info about file
+long ctime # creation or modification time
+char datestr[SZ_TIME] # ctime converted to a string
+int finfo()
+int tbltype, tbl_subtype
+int tbpsta()
+bool streq()
+
+begin
+ call smark (sp)
+
+ if (streq (keyword, "$I") || streq (keyword, "i_table")) {
+
+ # The table name.
+ call tbtnam (tp, value, maxch)
+
+ } else if (streq (keyword, "i_file")) {
+
+ # The name of the file containing the table.
+ call salloc (tablename, SZ_FNAME, TY_CHAR)
+ call salloc (filename, SZ_FNAME, TY_CHAR)
+ call salloc (hduname, SZ_FNAME, TY_CHAR)
+
+ call tbtnam (tp, Memc[tablename], SZ_FNAME)
+ junk = tbparse (Memc[tablename], Memc[filename],
+ Memc[hduname], SZ_FNAME, hdu)
+ call strcpy (Memc[filename], value, maxch)
+
+ } else if (streq (keyword, "i_ctime")) {
+
+ # The time the file was created (or last modified).
+ call salloc (tablename, SZ_FNAME, TY_CHAR)
+ call salloc (filename, SZ_FNAME, TY_CHAR)
+ call salloc (hduname, SZ_FNAME, TY_CHAR)
+
+ # Get file name.
+ call tbtnam (tp, Memc[tablename], SZ_FNAME)
+ junk = tbparse (Memc[tablename], Memc[filename],
+ Memc[hduname], SZ_FNAME, hdu)
+
+ if (finfo (Memc[filename], ostruct) == ERR)
+ call error (1, "Can't get info about file")
+
+ ctime = FI_CTIME(ostruct)
+ call cnvtime (ctime, datestr, SZ_TIME)
+ call strcpy (datestr, value, maxch)
+
+ } else if (streq (keyword, "i_nrows")) {
+
+ # The number of rows in the table.
+ call sprintf (value, maxch, "%d")
+ call pargi (tbpsta (tp, TBL_NROWS))
+
+ } else if (streq (keyword, "i_ncols")) {
+
+ # The number of columns in the table.
+ call sprintf (value, maxch, "%d")
+ call pargi (tbpsta (tp, TBL_NCOLS))
+
+ } else if (streq (keyword, "i_npar")) {
+
+ # The number of header keywords in the table.
+ call sprintf (value, maxch, "%d")
+ call pargi (tbpsta (tp, TBL_NPAR))
+
+ } else if (streq (keyword, "i_type")) {
+
+ # The type of the table.
+ tbltype = tbpsta (tp, TBL_WHTYPE)
+ tbl_subtype = tbpsta (tp, TBL_SUBTYPE)
+
+ if (tbltype == TBL_TYPE_TEXT) {
+
+ if (tbl_subtype == TBL_SUBTYPE_SIMPLE)
+ call strcpy ("text", value, maxch)
+ else if (tbl_subtype == TBL_SUBTYPE_EXPLICIT)
+ call strcpy ("text with explicit column definitions",
+ value, maxch)
+ else
+ call strcpy ("text", value, maxch)
+
+ } else if (tbltype == TBL_TYPE_FITS) {
+
+ if (tbl_subtype == TBL_SUBTYPE_ASCII)
+ call strcpy ("fits ascii", value, maxch)
+ else if (tbl_subtype == TBL_SUBTYPE_BINTABLE)
+ call strcpy ("fits binary", value, maxch)
+ else if (tbl_subtype == TBL_SUBTYPE_IMAGE)
+ call strcpy ("fits primary header", value, maxch)
+ else
+ call strcpy ("fits", value, maxch)
+
+ } else if (tbltype == TBL_TYPE_S_ROW) {
+
+ call strcpy ("stsdas row ordered", value, maxch)
+
+ } else if (tbltype == TBL_TYPE_S_COL) {
+
+ call strcpy ("stsdas column ordered", value, maxch)
+
+ } else {
+ call strcpy ("unknown", value, maxch)
+ }
+
+ } else {
+
+ call sfree (sp)
+ call error (1, "not a special keyword")
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/thistogram.par b/pkg/utilities/nttools/thistogram.par
new file mode 100644
index 00000000..ce34cd34
--- /dev/null
+++ b/pkg/utilities/nttools/thistogram.par
@@ -0,0 +1,14 @@
+intable,s,a,"",,,"input tables"
+outtable,s,a,"STDOUT",,,"output tables or STDOUT"
+column,s,a,"",,,"column in input tables"
+nbins,i,h,100,1,,"total number of bins"
+lowval,r,h,INDEF,,,"lower limit for histogram"
+highval,r,h,INDEF,,,"upper limit for histogram"
+dx,r,h,INDEF,,,"bin width"
+clow,r,h,INDEF,,,"center of first bin"
+chigh,r,h,INDEF,,,"center of last bin"
+rows,s,h,"-",,,"range of rows to use for histogram"
+outcolx,s,h,"value",,,"column name for bin centers"
+outcoly,s,h,"counts",,,"column name for histogram values"
+Version,s,h,"18March1994",,,"date of installation"
+mode,s,h,"al"
diff --git a/pkg/utilities/nttools/threed/doc/selectors.hlp b/pkg/utilities/nttools/threed/doc/selectors.hlp
new file mode 100644
index 00000000..fd5390a7
--- /dev/null
+++ b/pkg/utilities/nttools/threed/doc/selectors.hlp
@@ -0,0 +1,91 @@
+.help selectors Nov96 tables
+.ih
+NAME
+selectors -- Table row/column selector syntax.
+.ih
+BASIC SYNTAX
+Selectors are appended to table names using a bracket notation. The
+construct "[c:......]" appended to a table name tells that a column
+selector exists. In a similar way, the construct "[r:......]" indicates
+a row selector.
+.ih
+COLUMN SELECTOR
+The basic structure of a column selector is a list of column patterns
+separated by commas. The column pattern is either a column name, a file
+name containing a list of column names, or a pattern using the usual IRAF
+pattern matching syntax. For example, the string
+.nf
+ [c:a[1-9], b, time*, @column.lis]
+.fi
+
+would be expanded as the column names a1 through a9, b, any column
+name beginning with "time", and all the column names in the file
+column.lis. If the column list is entirely whitespace, all columns are
+selected. If the first non-white character is the negation character (~),
+the selected columns will include all columns not matched by the list.
+The negation character only has this meaning at the beginning of the list.
+.ih
+ROW SELECTOR
+Rows are selected according to a qpoe filter. The filter is evaluated
+at each table row, and the row is selected if the filter is true.
+
+For sake of an example, suppose we have a star catalog with the
+columns Name, Ra, Dec, V, B-V, and U-B. The simplest sort of filter is
+the equality test. The name of the column appears on the left of an
+equals sign and the column value appears on the right. For example,
+[name=eta_uma]. (The brackets in this and the following example are
+not actually part of the filter.) Column numbers can be used in place
+of the column name. This is especially useful for ascii
+tables. Values can be either numbers or strings. It is usually not
+necessary to place strings in quotes. However, any string (including
+a column name) contains embedded blanks or characters significant to
+the qpoe filter, such a equal signs, commas, or colons, it should be
+placed in quotes.
+
+Ranges of values can be specified by giving the endpoints of the
+ranges separated by a colon. For example, [r:v=10:15] selects all rows
+with visual magnitude between 10 and 15. Ranges include their
+endpoints. Ranges can also be used with strings as well as
+numbers. Ranges can also be one sided. The filter [r:dec=80:] selects
+all rows with declination greater than or equal to eighty degress and
+the filter [r:dec=:-40] selects all declinations less than or equal to
+forty degrees south. A filter can contain a list of single values and
+ranges. The values in the list should be enclosed in parentheses. For
+example, [r:name=(eta_uma,alpha_lyr)] or [r:b-v=(-1:0,0.5:1)].
+
+Individual values or ranges can be negated by placing a ! in front of
+them. For example, [r:name=!eta_uma] selects every row except the star
+named eta_uma and [r:ra=!0:6] selects all rows except those with right
+ascension between zero and six hours. An entire list can be negated by
+placing a ! in front of the column name or the parentheses enclosing
+the list. The filters [r:!name=(eta_uma,alpha_lyr)] and
+[r:name=!(eta_uma,alpha_lyr)] and [r:name=(!eta_uma,!alpha_lyr)] are all
+equivalent.
+
+Filters can test more than one column in a table. The individual tests
+are separated by commas or semicolons. All tests in the filter must
+succeed for the filter to be accepted. For example,
+[r:ra=1.3:1.4,dec=40:42] selects a rectangular region in the catalog. A
+range of row numbers can also be selected by placing the word row on
+the left side of the equals sign. For example, [r:row=10:20] selects
+rows from ten to twenty inclusive and [r:row=50:] selects all rows from
+fifty on. Row selection can be combined with any other test in a
+filter. A filter, can also be placed in an include file, for example
+[r:@filter.lis]. Include files can be a part of a larger expression
+and include files can contain other files, up to seven levels deep.
+.ih
+EXAMPLES
+.nf
+1. "[c:WAVELENGTH,FLUX]" selects columns named "WAVELENGTH" and
+ "FLUX"
+
+2. "[r:WAVELENGTH=(4000:5000)]" selects all rows in which the WAVELENGTH
+ column assumes values in between 4000 and
+ 5000.
+
+3. "[c:FLUX][r:row=(25:30)]" selects column FLUX and all rows from 25
+ to 30.
+.fi
+.ih
+SEE ALSO
+.endhelp
diff --git a/pkg/utilities/nttools/threed/doc/tiimage.hlp b/pkg/utilities/nttools/threed/doc/tiimage.hlp
new file mode 100644
index 00000000..1319d2e0
--- /dev/null
+++ b/pkg/utilities/nttools/threed/doc/tiimage.hlp
@@ -0,0 +1,108 @@
+.help tiimage Jan97 tables
+.ih
+NAME
+tiimage -- Inserts images into rows of a 3-D table.
+.ih
+USAGE
+tiimage input outtable
+.ih
+DESCRIPTION
+This task performs the inverse operation of task tximage: it inserts one or
+more images into rows of a 3-D table The input may be a filename template,
+including wildcard characters, or the name of a file (preceded by an @ sign)
+containing image names. The output is a single 3-D table name.
+Each image in the input list is inserted as an array into a single cell at
+the specified row in the output table. Any dimensionality information existent
+in the input image is lost in the process, that is, the image will be always
+inserted as a 1-D array, regardless of its number of axis.
+
+If the output table exists, insertion will be done in place. Alternatively,
+the task can create a 3-D table from information taken either from a template
+3-D table, or, if this table is not supplied, from the input images themselves.
+This task supports a column selector in table names. This selector may be
+used to select a single column in the table. If no selector is used, all
+columns will be processed. Type 'help selectors' to see a description of
+the selector syntax.
+
+If the output table exists, insertion may take place in two ways. If the
+output table name contains a column selector that selects a single column
+in the table, all input images will be inserted in that column, starting
+at the row pointed by task parameter "row".
+If "row" is negative or INDEF the task will look for the ORIG_ROW
+keyword in the image header and use that keyword value for row number.
+The second mode of insertion in an existing table is used if no matching
+column selector is found in the output table name. In this case the task
+will look for the columnar information written in the input image header by
+task tximage, and use that information to place the image in the proper
+column. If no columnar information exists in the header, or if the column
+name in there does not match any column in the output table, the image is
+skipped and the user warned. The "row" parameter processing works the same
+way in this second mode.
+
+If the output table does not exist, the task will look for a template table
+where to take column information from. If the template exists, the insertion
+operation will be performed in an analogous way as above. Notice that the
+result may be a single-column table if the template has a valid (matching)
+column selector in its name, or a sparse table if not, because only the
+actual input images will be stored in an otherwise empty table (the template
+data is not copied into the output, only the column descriptors).
+
+If the template is missing, the task will attempt to retrieve columnar
+information from the input image headers and build the output table with
+enough columns and rows to fit all images in the list. Only images that
+have columnar information in their headers can be processed, though. If
+no images are found with the proper header keywords, no output takes place.
+
+NOTE: Both the output and template table names must always be supplied
+complete, including their extension. Otherwise the task may get confused
+on the existence of an already existing table.
+
+The column matching criterion is based on the column name. An error results
+when data types in input image and output column do not agree.
+
+If the maximum array size in a target column in the output 3-D table is
+larger than the number of pixels in the input image, the array will be filled
+up starting from its first element, and the empty elements at the end will
+be set to INDEF. If the maximum array size is smaller than the number of
+pixels, insertion begins by the first pixel up to the maximum allowable size,
+the remaining pixels being ignored.
+.ih
+PARAMETERS
+.ls input [image name list/template]
+A list of one or more images to be inserted.
+.le
+.ls outtable [table name]
+Name of 3-D output table, including extension. No support exists for
+"STDOUT" (ASCII output).
+.le
+.ls (template = "") [table name]
+Name of 3-D table to be used as template when creating a new output table.
+.le
+.ls (row = INDEF) [int]
+Row where insertion begins. If set to INDEF or a negative value, the row
+number will be looked for in the input image header.
+.le
+.ls (verbose = yes) [boolean]
+Display names as files are processed ?
+.le
+.ih
+EXAMPLES
+Insert images into a 3-D table at column named FLUX:
+
+.nf
+cl> tiimage flux*.hhh "otable.tab[c:FLUX]"
+.fi
+.ih
+BUGS
+The output and template table names must be supplied in full, including
+the extension (e.g. ".tab"). If the output table name is not typed in full,
+the task will create a new table in place of the existing one, with only
+the rows actually inserted. This behavior relates to the way the underlying
+"access" routine in IRAF's fio library works.
+.ih
+REFERENCES
+This task was written by I. Busko.
+.ih
+SEE ALSO
+tximage, selectors
+.endhelp
diff --git a/pkg/utilities/nttools/threed/doc/titable.hlp b/pkg/utilities/nttools/threed/doc/titable.hlp
new file mode 100644
index 00000000..f0479b6b
--- /dev/null
+++ b/pkg/utilities/nttools/threed/doc/titable.hlp
@@ -0,0 +1,100 @@
+.help titable Mar97 tables
+.ih
+NAME
+titable -- Inserts 2-D tables into rows of a 3-D table.
+.ih
+USAGE
+titable intable outtable
+.ih
+DESCRIPTION
+This task performs the inverse operation of task txtable: it inserts one or
+more 2-D tables into rows of a 3-D table The input may be a filename
+template, including wildcard characters, or the name of a file (preceded by
+an @ sign) containing table names. The output is a single 3-D table name.
+If the output table exists, insertion will be done in place. If the output
+table does not exist, it will be created. The input and output tables must
+not be the same.
+
+This task supports row/column selectors in the input table names. These
+may be used to select subsets of both rows and columns from the input table.
+If no selectors are used, all columns and rows will be processed,
+Type 'help selectors' to see a description of the selector syntax.
+
+When creating a new output table, the information describing its columns
+can be taken from two sources. If parameter 'template' has the name of an
+existing 3-D table, the column descriptions, including maximum array sizes,
+will be taken from that table. If 'template' has an invalid or null ("")
+value, the column-defining information will be take from the first table
+in the input list, where its number of rows will define the maximum array
+size allowed in the table being created. Column selectors are allowed in
+the template table.
+
+NOTE: Both the output and template table names must always be supplied
+complete, including their extension. Otherwise the task may get confused
+on the existence of an already existing table.
+
+Insertion is performed by first verifying if column names in both input
+and output tables match. If a match is found, values taken from that column
+and all selected rows from the input table will be stored as a 1-dimensional
+array in a single cell in the corresponding column in the output 3-D table.
+The row in this table where the insertion takes place is selected by the
+"row" task parameter. It points to the row where the first table in the input
+list will be inserted, subsequent tables in the list will be inserted into
+subsequent rows. This mechanism is superseded if the "row" parameter is set
+to INDEF or a negative value, and the keyword "ORIG_ROW" is found in the
+header of the input table. This keyword is created by task txtable and its
+value supersedes the row counter in the task.
+
+If the maximum array size in a target column in the output 3-D table is
+larger than the number of selected input rows, the array will be filled
+up starting from its first element, and the empty elements at the end will
+be set to INDEF (or "" if it is a character string column). If the maximum
+array size is smaller than the number of selected rows, insertion begins by
+the first selected row up to the maximum allowable size, the remaining rows
+being ignored.
+
+This task correctly handles scalars stored in the input table header
+by task txtable. Since the selector mechanism does not work with these
+scalars, the task will always insert them into the output table, provided
+there is a match in column names.
+.ih
+PARAMETERS
+.ls intable [file name list/template]
+A list of one or more tables to be inserted. Row/column selectors are supported.
+.le
+.ls outtable [table name]
+Name of 3-D output table, including extension. No support exists for
+"STDOUT" (ASCII output).
+.le
+.ls (template = "") [table name]
+Name of 3-D table to be used as template when creating a new output table.
+.le
+.ls (row = INDEF) [int]
+Row where insertion begins. If set to INDEF or a negative value, the row
+number will be looked for in the input table header.
+.le
+.ls (verbose = yes) [boolean]
+Display names of input and output tables as files are processed ?
+.le
+.ih
+EXAMPLES
+Insert columns named FLUX and WAVELENGTH from input tables into a 3-D table:
+
+.nf
+cl> titable "itable*.tab[c:FLUX,WAVELENGTH]" otable.tab
+.fi
+
+.ih
+BUGS
+The output and template table names must be supplied in full, including
+the extension (e.g. ".tab"). If the output table name is not typed in full,
+the task will create a new table in place of the existing one, with only the
+rows actually inserted. This behavior relates to the way the underlying
+"access" routine in IRAF's fio library works.
+.ih
+REFERENCES
+This task was written by I. Busko.
+.ih
+SEE ALSO
+txtable, selectors
+.endhelp
diff --git a/pkg/utilities/nttools/threed/doc/tscopy.hlp b/pkg/utilities/nttools/threed/doc/tscopy.hlp
new file mode 100644
index 00000000..144b483a
--- /dev/null
+++ b/pkg/utilities/nttools/threed/doc/tscopy.hlp
@@ -0,0 +1,94 @@
+.help tscopy Nov96 tables
+.ih
+NAME
+tscopy -- Copy tables.
+.ih
+USAGE
+tscopy intable outtable
+.ih
+DESCRIPTION
+This task is used to copy tables. The input may be a filename
+template, including wildcard characters or the name of a file (preceded
+by an @ sign) containing table names. The output may be either a directory
+specification or a list of table names. If the output is a list of tables
+then there must be the same number of names in the input and output lists,
+and the names are taken in pairs, one from input and one from output.
+The input and output tables must not be the same.
+
+This task supports row/column selectors in the input table name. These
+may be used to select subsets of both rows and columns from the input table.
+Type 'help selectors' to see a description of the selector syntax.
+
+NOTE: Be careful when using a wildcard for the extension.
+If you have the files 'table.tab' and 'table.lis' in the current directory,
+for example, then the command "tscopy tab* test/" would copy both files to the subdirectory
+'test'.
+.ih
+PARAMETERS
+.ls intable [file name template]
+A list of one or more tables to be copied. Row/column selectors are supported.
+.le
+.ls outtable [file name template]
+Either a directory name or a list of output table names. The standard
+value "STDOUT" generates ASCII output that can be redirected to a file.
+.le
+.ls (verbose = yes) [boolean]
+Display names of input and output tables as files are copied?
+.le
+.ih
+EXAMPLES
+1. To simply copy a table:
+
+.nf
+ cl> tscopy table tablecopy
+.fi
+
+2. To copy a table into an ASCII table:
+
+.nf
+ cl> tscopy table STDOUT > table.txt
+.fi
+
+3. To copy several tables:
+
+.nf
+ cl> tscopy table1,table2,tab67 a,b,c
+ cl> tscopy tab*.tab a,b,c
+.fi
+In the latter case the extension is given explicitly in case there
+are other files beginning with "tab" that are not tables; there must
+be exactly three tables beginning with "tab" because the output list
+has three names.
+
+4. To copy a set of tables to a new directory:
+
+.nf
+ cl> tscopy table*.tab directory
+ or
+ cl> tscopy table*.tab directory$
+ or
+ cl> tscopy table*.tab osdirectory
+.fi
+
+where "directory" is an IRAF environment variable for a directory name,
+and "osdirectory" is an operating system directory name
+(e.g., "/user/me/" in UNIX).
+
+5. To copy a subset of rows and columns:
+
+.nf
+ cl> tscopy "table.tab[c:wave,flux][r:wave=(4000:5000)]" tableout
+.fi
+
+This command will copy only columns named "wave" and "flux" from the input
+table to the output. It will also select and copy only the rows in which
+the "wave" value lies between 4000 and 5000.
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by Bernie Simon.
+.ih
+SEE ALSO
+selectors
+.endhelp
diff --git a/pkg/utilities/nttools/threed/doc/tximage.hlp b/pkg/utilities/nttools/threed/doc/tximage.hlp
new file mode 100644
index 00000000..9f331958
--- /dev/null
+++ b/pkg/utilities/nttools/threed/doc/tximage.hlp
@@ -0,0 +1,85 @@
+.help tximage Jan97 tables
+.ih
+NAME
+tximage -- Extract 1-D images from cells of a 3-D table.
+.ih
+USAGE
+tximage intable output
+.ih
+DESCRIPTION
+This task extracts one or more 1-D images from cells of a 3-D table.
+The input may be a filename template, including wildcard characters,
+or the name of a file (preceded by an @ sign) containing table names.
+The output may be either a directory specification or a list of image names.
+If the output is a list of images then there must be the same number of names
+in the input and output lists, and the names are taken in pairs, one from
+input and one from output.
+
+Images can be extracted only from a single column in the input table.
+That column must be designated by an appropriate column selector appended to
+the table name. Type 'help selectors' to get more information on row/column
+selector syntax.
+
+Row selectors may be used to select subsets of rows from the input table.
+If no row selector is used, all rows will be extracted, and the number
+of output images will be the number of rows in the input table.
+
+Since one input table may generate several output images, the task adopts
+the following naming scheme for these output images: their names are
+built by appending a suffix to the name given in parameter "output".
+The suffix has the form "_rXXXX", where XXXX stands for the row number
+in the input table. The suffix is appended before the file name extension.
+The task recognizes as valid image name extensions the values ".??h",
+".fits" and ".fit". Any other extension is assumed to be part of the root
+file name. If only one row is extracted, no suffixing takes place.
+
+NOTE: Be careful when using a wildcard for the extension.
+If you have the files "table.tab" and "table.lis" in the current directory,
+for example, then the command "tximage tab* test/" would expand both files
+to the subdirectory "test".
+
+Basic column information describing the column where the image came from
+is written into the image header in the "COLDATA" keyword. This information
+can be used later by task 'tiimage' to re-insert the image into a cell of
+a 3-D table.
+
+The task does not propagate array dimensionality when extracting arrays
+into images. If dimensionality information exists in the 3-D table, that
+information is lost, that is, the table cell from the input table is written
+as a structureless, plain 1-D image.
+
+The input row number is written to the header of the output image in
+keyword ORIG_ROW. This allows 'tiimage' to put the data back where
+'tximage' got them from.
+.ih
+PARAMETERS
+.ls intable [file name list/template]
+A list of one or more tables to be expanded. A column selector selecting
+a single column is mandatory. Row selectors are supported as well.
+.le
+.ls output [file name template]
+Either a directory name or a list of output image names.
+.le
+.ls (verbose = yes) [boolean]
+Display names of input and output files ?
+.le
+.ih
+EXAMPLES
+Extract 1-D images from a column named FLUX from rows 11 to 13 of a 3-D
+table:
+
+.nf
+cl> tximage "table.tab[c:FLUX][r:row=(11:13)]" image
+.fi
+
+This will generate three images named "image_r0011", "image_r0012"
+and "image_r0013".
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by I. Busko.
+.ih
+SEE ALSO
+tiimage, selectors
+.endhelp
diff --git a/pkg/utilities/nttools/threed/doc/txtable.hlp b/pkg/utilities/nttools/threed/doc/txtable.hlp
new file mode 100644
index 00000000..462b8b95
--- /dev/null
+++ b/pkg/utilities/nttools/threed/doc/txtable.hlp
@@ -0,0 +1,89 @@
+.help txtable Jan97 tables
+.ih
+NAME
+txtable -- Extract rows from a 3-D table into separate 2-D tables.
+.ih
+USAGE
+txtable intable outtable
+.ih
+DESCRIPTION
+This task extracts one or more rows from a 3-D table and writes each row
+as a 2-D table. The input may be a filename template, including
+wildcard characters, or the name of a file (preceded by an @ sign) containing
+table names. The output may be either a directory specification or a list
+of table names. If the output is a list of tables then there must be the same
+number of names in the input and output lists, and the names are taken in
+pairs, one from input and one from output. The input and output tables must
+not be the same.
+
+This task supports row/column selectors in the input table name. These
+may be used to select subsets of both rows and columns from the input table.
+If no selectors are used, all columns will be extracted, and the number
+of output tables will be the number of rows in the input table.
+Type 'help selectors' to see a description of the selector syntax.
+
+Since one input table may generate several output tables, the task adopts
+the following naming scheme for these output tables: their names are
+built by appending a suffix to the name given in parameter "outtable".
+The suffix has the form "_rXXXX", where XXXX stands for the row number
+in the input table. The suffix is appended before the file name extension.
+The task recognizes as valid table name extensions the values ".tab",
+".fits" and ".fit". Any other extension is assumed to be part of the root
+file name. If only one row is extracted, or in case of ASCII output, no
+suffixing takes place.
+
+NOTE: Be careful when using a wildcard for the extension.
+If you have the files "table.tab" and "table.lis" in the current directory,
+for example, then the command "txtable tab* test/" would expand both files
+to the subdirectory "test".
+
+There are two forms of handling scalar columns in the input table. If
+task parameter "compact" is set to 'no', the corresponding column in the
+output table will have the scalar value in its first row, and all other
+rows will be filled with INDEF. If parameter "compact" is set to 'yes',
+scalar columns will be written into the header as a set of header keywords.
+These keywords can be used later by task 'titable' to re-insert the
+scalars as cell elements of a 3-D table.
+
+The task does not propagate array dimensionality when extracting arrays
+into columns in the output table. If dimensionality information exists
+in the 3-D table, that information is lost, that is, the table cell from
+the input table is written as a structureless, plain table column.
+
+The input row number is written to the header of the output table in
+keyword ORIG_ROW. This allows 'titable' to put the data back where
+'txtable' got them from.
+.ih
+PARAMETERS
+.ls intable [file name list/template]
+A list of one or more tables to be expanded. Row/column selectors are supported.
+.le
+.ls outtable [file name template]
+Either a directory name or a list of output table names. The standard
+value "STDOUT" generates ASCII output that can be redirected to a file.
+.le
+.ls (compact = yes) [boolean]
+Write scalars as header keywords ?
+.le
+.ls (verbose = yes) [boolean]
+Display names of input and output tables as files are processed ?
+.le
+.ih
+EXAMPLES
+Extract columns named FLUX and WAVELENGTH from rows 11 to 13 of a 3-D table:
+
+.nf
+cl> txtable "table.tab[c:FLUX,WAVELENGTH][r:row=(11:13)]" tableout
+.fi
+
+This will generate three tables named "tableout_r0011", "tableout_r0012"
+and "tableout_r0013".
+.ih
+BUGS
+.ih
+REFERENCES
+This task was written by I. Busko.
+.ih
+SEE ALSO
+titable, selectors
+.endhelp
diff --git a/pkg/utilities/nttools/threed/mkpkg b/pkg/utilities/nttools/threed/mkpkg
new file mode 100644
index 00000000..ee093810
--- /dev/null
+++ b/pkg/utilities/nttools/threed/mkpkg
@@ -0,0 +1,25 @@
+# Make the threed package
+# I.Busko, 21-Nov-1996
+#
+# Special keywords recognized by IRAF mkpkg files:
+#
+# mkpkg relink update object library and link
+# mkpkg linkonly skip object library updates and just link
+# mkpkg install move executable to lib$
+# mkpkg update update object library, link, and move to lib$
+
+
+$call libpkg.a
+$exit
+
+libpkg.a:
+ $call generic@tiimage
+ $call generic@titable
+ $call generic@txtable
+
+ @tscopy
+ @txtable
+ @tximage
+ @titable
+ @tiimage
+ ;
diff --git a/pkg/utilities/nttools/threed/tblerr.h b/pkg/utilities/nttools/threed/tblerr.h
new file mode 100644
index 00000000..cbf6ac36
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tblerr.h
@@ -0,0 +1,27 @@
+# tblerr.h -- error codes for table I/O routines
+#
+# Phil Hodge, 30-Sep-87 Change numbers and reorganize.
+# Phil Hodge, 2-Jun-89 Remove 4867 from error numbers.
+
+define ER_TBNAMTOOLONG 01 # file name (incl extension) is too long
+define ER_TBBADMODE 02 # I/O mode is not supported for a table
+define ER_TBREADONLY 03 # attempt to modify a readonly table
+
+define ER_TBTOOLATE 31 # too late, table is already open
+define ER_TBNOTOPEN 32 # table must be open for this option
+define ER_TBBADOPTION 33 # invalid option for tbpset
+define ER_TBUNKPARAM 34 # unknown parameter for tbpsta
+
+define ER_TBCOLEXISTS 41 # column already exists
+define ER_TBBADTYPE 42 # invalid data type for a table column
+
+define ER_TBBEYONDEOF 51 # requested row is beyond EOF
+
+define ER_TBPARNOTFND 61 # header parameter not found
+define ER_TBMUSTADD 62 # new parameter must be added, not put
+define ER_TBDTYPECONFLICT 63 # can't put numeric parameter as comment
+
+define ER_TBCORRUPTED 81 # table or memory is corrupted
+define ER_TBCOLBADTYP 82 # bad data type (memory corrupted?)
+define ER_TBFILEMPTY 83 # table data file is empty
+define ER_TBCINFMISSING 84 # EOF while reading column info
diff --git a/pkg/utilities/nttools/threed/tbtables.h b/pkg/utilities/nttools/threed/tbtables.h
new file mode 100644
index 00000000..60e79159
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tbtables.h
@@ -0,0 +1,123 @@
+# tbtables.h -- Internal definitions for the table I/O package.
+
+# Software version number.
+# Version 0 corresponds to STSDAS and TABLES versions 1.2.3 and earlier.
+# The row length was restricted to integral multiples of the size of a
+# real number.
+# Version 1 begins with STSDAS and TABLES version 1.3. Short integer
+# datatype was introduced, and character strings were rounded up to a
+# multiple of the number of bytes in a char. The row length is allowed
+# to be any integral multiple of SZ_CHAR.
+# Version 2 allows header parameters to have comments.
+# This change was made after TABLES version 1.3.3 was released.
+define TBL_CURRENT_VERSION 2
+
+# Default maximum number of user parameters. The current value is TB_MAXPAR.
+define DEFMAXPAR 5
+
+# Default maximum number of columns. The current value is TB_MAXCOLS.
+define DEFMAXCOLS 5
+
+# This section describes the size information record.
+define LEN_SIZINFO 12 # unit = SZ_INT32
+define SZ_SIZINFO (LEN_SIZINFO * SZ_INT32)
+define S_NPAR $1[1] # Number of user parameters
+define S_MAXPAR $1[2] # Max number of user parameters
+define S_NROWS $1[3] # Number of rows
+define S_ALLROWS $1[4] # Number of rows allocated
+define S_NCOLS $1[5] # Number of columns defined
+define S_MAXCOLS $1[6] # Current max number of columns
+define S_COLUSED $1[7] # Chars used by defined columns
+define S_ROWLEN $1[8] # Total row length alloc (chars)
+define S_TYPE $1[9] # Type (row or column ordered)
+define S_VERSION $1[10] # Software version number
+
+# This is the size of the table-descriptor structure.
+define LEN_TBLSTRUCT (28)
+
+# General descriptive information. (R) means relevant only for row-ordered
+# tables, while (C) means relevant only for column-ordered tables.
+define TB_TYPE Memi[$1] # what type of table
+define TB_NPAR Memi[$1+1] # number of user paramters
+define TB_MAXPAR Memi[$1+2] # max number of user paramters
+define TB_NROWS Memi[$1+3] # number of rows
+define TB_ALLROWS Memi[$1+4] # (C) allocated number of rows
+define TB_NCOLS Memi[$1+5] # number of columns
+define TB_MAXCOLS Memi[$1+6] # current max number of columns
+define TB_COLUSED Memi[$1+7] # (R) chars used by columns
+define TB_ROWLEN Memi[$1+8] # (R) row length = chars alloc
+define TB_VERSION Memi[$1+9] # Software version number
+define TB_BOD Meml[$1+10] # L beg of data (in SZ_CHAR)
+define TB_IOMODE Memi[$1+11] # I/O mode
+
+# Flags
+define TB_IS_OPEN Memb[$1+12] # Table is open?
+define TB_READONLY Memb[$1+13] # Readonly?
+define TB_MODIFIED Memb[$1+14] # Actually been changed?
+
+# File descriptor for the table file
+define TB_FILE Memi[$1+15]
+
+# Pointers. TB_INDEF is only used for row-ordered tables.
+define TB_INDEF Memi[$1+16] # Pointer to indef record buffer
+define TB_COLPTR Memi[$1+17] # Ptr to array of column ptrs
+
+# These are for tables in CDF files or FITS files.
+define TB_F_TYPE Memi[$1+18] # CDF, FITS, or ordinary file
+define TB_HDU Memi[$1+19] # number of HDU in FITS file
+define TB_EXTVER Memi[$1+20] # version number
+define TB_OVERWRITE Memi[$1+21] # +1 --> yes, 0 --> no
+define TB_HDUTYPE Memi[$1+22] # 1--> ascii; 2 --> binary
+define TB_CD Memi[$1+23] # returned by cd_open()
+define TB_EXTNAME_PTR Memi[$1+24] # pointer to CDF name or EXTNAME
+define TB_EXTNAME Memc[TB_EXTNAME_PTR($1)]
+
+# These two are for text tables.
+define TB_COMMENT Memi[$1+25] # pointer to comment string
+define TB_SZ_COMMENT Memi[$1+26] # size of comment string
+
+# Table name
+define TB_NAME_PTR Memi[$1+27] # pointer to table name string
+define TB_NAME Memc[TB_NAME_PTR($1)]
+
+
+# Array of pointers to column information. This array can be reallocated
+# to allow more columns; the current size at any time is TB_MAXCOLS.
+define TB_COLINFO Memi[TB_COLPTR($1)+$2-1]
+
+
+
+# Column information structure.
+define LEN_COLSTRUCT 16 # unit = SZ_STRUCT
+define SZ_COLSTRUCT (LEN_COLSTRUCT * SZ_STRUCT)
+
+define COL_NUMBER Memi[$1] # Column number
+define COL_OFFSET Memi[$1+1] # Offset from start of row
+define COL_LEN Memi[$1+2] # Chars for data element
+define COL_DTYPE Memi[$1+3] # Data type
+define COL_NAME Memc[P2C($1+4)] # Column name 19
+define COL_UNITS Memc[P2C($1+9)] # Units 19
+define COL_FMT Memc[P2C($1+14)] # Print format 7
+# Next available field is ($1 + 16).
+
+
+# Definitions of data types. These agree with iraf.h.
+define TBL_TY_BOOL 1
+define TBL_TY_CHAR 2
+define TBL_TY_SHORT 3
+define TBL_TY_INT 4
+define TBL_TY_REAL 6
+define TBL_TY_DOUBLE 7
+
+# Undefined double for tables. This agrees with the pre-IRAF 2.11 INDEFD.
+define TBL_INDEFD 1.6d38
+define TBL_IS_INDEFD (($1)==TBL_INDEFD)
+
+# These two (which are in tbset.h) are used for the file type TB_F_TYPE
+# as well as table type TB_TYPE.
+# (moved) define TBL_TYPE_FITS 14 # FITS table
+# (moved) define TBL_TYPE_CDF 15 # common datafile format
+# These two are modifiers for the table type in case it's a FITS table.
+# They are the value of TB_HDUTYPE.
+define TBL_FITS_ASCII 1 # FITS ASCII table
+define TBL_FITS_BINARY 2 # FITS BINTABLE
diff --git a/pkg/utilities/nttools/threed/tiimage.par b/pkg/utilities/nttools/threed/tiimage.par
new file mode 100644
index 00000000..27b9c861
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage.par
@@ -0,0 +1,7 @@
+input,s,a,"",,,">Input images"
+outtable,s,a,"",,,">Output table"
+template,s,h,"",,,">Template table"
+row,i,h,INDEF,,,">Begin insertion in row"
+verbose,b,h,yes,,,">Print operations performed ?"
+version,s,h,"30Jan97",,,
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/threed/tiimage/design1.txt b/pkg/utilities/nttools/threed/tiimage/design1.txt
new file mode 100644
index 00000000..8726f475
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/design1.txt
@@ -0,0 +1,353 @@
+
+
+ Design of 3-D table translator for image insertion
+ --------------------------------------------------
+
+
+ Author: I. Busko
+
+
+ Revision history:
+ 01/16/97 - First version.
+
+
+
+1. Specifications / requirements:
+
+This task will perform the inverse operation performed by task tximage.
+It will insert (in the tainsert task sense) one or more 1-D images into
+rows of an existing 3-D table. Alternatively, it will create a 3-D table
+from information taken either from a template 3-D table, or, if this table
+is not supplied, from the input images themselves. Each image in the input
+list is inserted as an array into a single cell at the specified row in the output table.
+
+Actions necessary to process the most complicated cases (e.g. when the
+image length does not match the table array size) will be similar to the
+ones described for task titable.
+
+If the output table does exist, insertion may take place in two ways. If the
+output table name contains a column selector that selects a single column
+in the table, all input images will be inserted in that column, starting
+at the row pointed by task parameter "row". In a similar way as in task
+titable, if "row" is negative or INDEF the task will look for the ORIG_ROW
+keyword in the image header and use that keyword value for row number.
+The second mode of insertion in an existing table is used if no matching
+column selector is found in the output table name. In this case the task
+will look for the columnar information written in the input image header by
+task tximage, and use that information to place the image in the proper
+column. If no columnar information exists in the header, or if the column
+name in there does not match any column in the output table, the image is
+skipped and the user warned. The "row" parameter processing works the same
+way in this second mode.
+
+If the output table does not exist, the task will look for a template table
+where to take column information from. If the template exists, the insertion
+operation will be performed in an analogous way as above. Notice that the
+result may be a single-column table if the template has a valid (matching)
+column selector in its name, or a sparse table if not, because only the
+actual input images will be stored in an otherwise empty table (the template
+data is not copied into the output, only the column descriptors).
+
+If the template is missing, the task will attempt to retrieve columnar
+information from the input image headers and build the output table with
+enough columns and rows to fit all images in the list. Only images that
+have columnar information in their headers can be processed, though. If
+no images are found with the proper header keywords, no output takes place.
+Notice that this task will not be able to handle the most generic case in
+which a number of unspecified 1-D images with no proper header keywords
+are input to create a 3-D table from scratch (without a template).
+
+The basic matching criterion is based on the column name. An error results
+when datatypes in input image and output column do not agree.
+
+The task will be named "tiimage" following a former proposal for naming
+the 3-D table utilities.
+
+
+
+2. Language:
+
+SPP, to allow the use of the generic datatype compiling facility, and to
+reuse significant amounts of code already developed for other tasks in this
+suite.
+
+
+
+3. Task parameters:
+
+Name Type What
+
+input image list/template list of 1D image names
+outtable file name 3-D table name with optional column selector
+ (modified in place or created from scratch).
+template file name template 3-D table name with optional column
+ selector
+row int row in output table where to begin insertion.
+
+
+
+4. Data structures:
+
+The main data structure is a pointer-type column descriptor array. This
+array is filled by information taken from the several possible sources
+described above, and used by the tbtables routines to create and fill up
+the output.
+
+
+
+5. Code structure:
+
+MAIN PROCEDURE:
+- Read task parameters (clget).
+- Decide which mode to use: mode = TMMODE (output name, template name)
+- SWITCH mode
+- CASE 1, 2: Output table exists.
+ - Break output table name into bracketed selectors (rdselect).
+ - Open output table (tbtopn with root name, READ_WRITE).
+ - Create array with either the single selected column pointer or all
+ column pointers (malloc, tcs_open).
+ - Alloc array of column pointers for output table.
+ - LOOP over all matched columns in tcs_ column array
+ - Translate pointer from tcs_ format to tbtables format (tcs_column)
+ - ENDLOOP
+ - TMLOOP (table pointer, column pointer array, rowpar, image list, mode).
+ - Close output table (tbtclo)
+ - Free array (mfree)
+- END CASE
+- CASE 3, 4: Output table does not exist but template table does exist.
+ - Break output table name into bracketed selectors (rdselect).
+ - Open output table (tbtopn with root name, NEW_FILE).
+ - Break template table name into bracketed selectors (rdselect).
+ - Open template table (tbtopn with root name, READ_ONLY).
+ - Create array with either the single selected column pointer or all
+ column pointers from template table (malloc, tcs_open).
+ - Alloc array of column pointers for output table.
+ - LOOP over all matched columns in template tcs_ column array
+ - Create column in output table (tcs_column, tbcinf, tbcdef)
+ - ENDLOOP
+ - Create output table (tbtcre).
+ - TMLOOP (table pointer, column pointer array, rowpar, image list, mode)
+ - Close template table (tbtclo)
+ - Close output table (tbtclo)
+ - Free arrays (mfree)
+- CASE 5: Neither output nor template table exist.
+ - Alloc memory for strings.
+ - Alloc memory for column pointer array, assuming the worst case of each
+ input image in the list belonging to a separate, independent column.
+ - Open output table (tbtopn with root name, NEW_FILE).
+ - IFNOTERROR TMSCAN (table pointer, column pointer array, image list)
+ - Set mode = 2 to force TMLOOP to read column data from headers.
+ - Create output table (tbtcre).
+ - TMLOOP (table pointer, column pointer array, rowpar, image list, mode)
+ - ENDIF
+ - Close output table (tbtclo)
+ - Free arrays (mfree)
+- END CASE
+- CASE -1
+ - Print error msg.
+ - Abort.
+- END SWITCH
+END MAIN
+
+
+
+PROCEDURE TMMODE: Detect mode of operation.
+ Input parameters: file name, template name (in full)
+ Return value: mode
+
+ - IF output exists (access)
+ - mode = TMM1 (output file name, output type)
+ - IF mode == -1
+ - Print error msg.
+ - return mode = -1 (error)
+ - ENDIF
+ - ELSE IF template does exist (access)
+ - mode = TMM1 (template file name, template type)
+ - IF mode == -1
+ - Print error msg.
+ - return mode = -1 (error)
+ - ENDIF
+ - ELSE
+ mode = 5
+ - ENDIF
+ return mode
+END PROCEDURE
+
+
+
+PROCEDURE TMM1: Verify status of file and column selector.
+ Input parameters: file name, file type (output or template)
+ Return value: mode
+
+ - IF file is not a table (whatfile).
+ - return mode = -1 (error)
+ - ENDIF
+ - Get bracket selector from file name (rdselect).
+ - Open table (tbtopn with root name, READ_ONLY).
+ - Get its total number of columns (tbpsta).
+ - Create array of column pointers from column selector (malloc, tcs_open).
+ - Close output table (tbtclo)
+ - Free array (mfree)
+ - IF output file type
+ - IF one column matched
+ - return mode = 1
+ - ELSE
+ - return mode = 2
+ - ENDIF
+ - ELSE IF template file type
+ - IF one column matched
+ - return mode = 3
+ - ELSE
+ - return mode = 4
+ - ENDIF
+ - ENDIF
+ return mode = -1 (error)
+END PROCEDURE
+
+
+
+PROCEDURE TMLOOP: Scan input list and insert each image in turn.
+ Input parameters: table pointer, column pointer array,row, image list,mode
+
+ - Initialize row counter.
+ - Initialize successful image counter.
+ - Open input list (imtopen)
+ - LOOP over input list (imtlen).
+ - Get image name (imtgetim).
+ - IFERROR Open input image (immap).
+ - Warn user.
+ - Skip image.
+ - ENDIF
+ - IF mode == 2 or mode == 4, look into image header for columnar info
+ and do the copy.
+ - IFERROR TMHC (table pointer, column pointer array, row, rowpar,
+ imio pointer)
+ - Close and skip image.
+ - ENDIF
+ - bump row and image counters.
+ - ELSE IF mode == 1 or mode == 3, just copy into single, fixed column.
+ - IFERROR TMCOPY (table pointer, column pointer, row, rowpar,
+ imio pointer)
+ - Warn user.
+ - Close and skip image.
+ - ENDIF
+ - bump row and image counters.
+ - ENDIF
+ - Close image (imunmap)
+ - ENDLOOP
+ - IF successful image counter == 0
+ - Print error msg.
+ - ENDIF
+ - Close input list (imtclose)
+END PROCEDURE
+
+
+
+PROCEDURE TMSCAN: Scan input list and create column pointer array from
+ information stored in image headers.
+ Input parameters: table pointer, column pointer array, its size, image list
+ Output parameter: actual number of matched columns.
+
+ - Initialize column counter.
+ - Open input list (imtopen)
+ - LOOP over input list (imtlen).
+ - Get image name (imtgetim).
+ - IFERROR Open input image (immap).
+ - Warn user.
+ - Skip image.
+ - ENDIF
+ - IFERROR TMHEADER (imio pointer, column name, units, fmt, datatype,
+ lendata
+ - Warn user.
+ - Skip image.
+ - ENDIF
+ - IF there are defined columns (column counter > 0):
+ - match = false
+ - LOOP over defined columns
+ - Get column name (tbcinf)
+ - IF column name from table matches column name from header:
+ - match = true
+ - break
+ - ENDIF
+ - ENDLOOP
+ - IF no match, this is a new column:
+ - Define new column in array (tbcdef)
+ - Bump column counter
+ - ENDIF
+ - ELSE
+ - Define first new column in array (tbcdef)
+ - Bump column counter
+ - ENDIF
+ - ENDLOOP
+ - Close input list (imtclose)
+ - IF column counter == 0
+ - Error.
+ - Create output table (tbtcre).
+END PROCEDURE
+
+
+
+PROCEDURE TMHC: Get column name from image header and copy image into table.
+ Input parameters: table pointer, column pointer array, row, rowpar,
+ imio pointer
+
+ - salloc space for column name.
+ - IFERROR TMHEADER (imio pointer, column name, etc.)
+ - Warn, return
+ - ENDIF
+ - match = false
+ - LOOP over table columns.
+ - IF column names match:
+ - IFERROR TMCOPY (table pointer, column pointer, row, rowpar,
+ imio pointer)
+ - Warn, return.
+ - ENDIF
+ - match = true
+ - ENDIF
+ - ENDLOOP
+ - IF no match
+ - Warn, return.
+ - ENDIF
+ - sfree
+END PROCEDURE
+
+
+
+PROCEDURE TMCOPY: Copy image into designated row/column.
+ Input parameters: table pointer, column pointer, row, rowpar, imio pointer
+
+ - Get table (tbcigi) and image (IM_PIXTYPE) pixel type.
+ - IF pixel type mismatch:
+ - Warn, return
+ - ENDIF
+ - Look for ORIG_ROW keyword (imaccf, imgeti). If found, and if "row"
+ parameter is negative or INDEF, supersede row counter.
+ - Get column array size (tbcinf) and image size (IM_NDIM, IM_LEN).
+ - Choose the minimum of these as the array size to be written to table.
+ - Read pixels in buffer (imgl1$t). ^
+ - Write buffer into designated row/column (tbapt$t). |
+ - IF image is larger than array: | This goes into
+ - Warn user. | a generic data
+ - ELSE IF image is smaller than array: | type procedure
+ - Set remaining elements to INDEF (tbapt$t). |
+ - Warn user. |
+ - ENDIF v
+END PROCEDURE
+
+
+
+PROCEDURE TMHEADER: Decode column info in image header.
+ Input parameter: imio pointer
+ Output parameter: column name, units, fmt, datatype, lendata
+
+ - Look for COLDATA keyword (imaccf, imgstr).
+ - IF not found:
+ return error.
+ - ENDIF
+ - Parse and get parameters (sscan, gargwrd, gargi)
+ - IF error in nscan value:
+ return error.
+ - ENDIF
+END PROCEDURE
+
+
diff --git a/pkg/utilities/nttools/threed/tiimage/generic/mkpkg b/pkg/utilities/nttools/threed/tiimage/generic/mkpkg
new file mode 100644
index 00000000..51bd24bb
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/generic/mkpkg
@@ -0,0 +1,14 @@
+# Update the generic routines.
+
+default:
+ $checkout libpkg.a ../../
+ $update libpkg.a
+ $checkin libpkg.a ../../
+$exit
+
+libpkg.a:
+ tmcp1s.x
+ tmcp1i.x
+ tmcp1r.x
+ tmcp1d.x
+ ;
diff --git a/pkg/utilities/nttools/threed/tiimage/generic/tmcp1d.x b/pkg/utilities/nttools/threed/tiimage/generic/tmcp1d.x
new file mode 100644
index 00000000..9670c6a6
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/generic/tmcp1d.x
@@ -0,0 +1,54 @@
+
+# TM_CP1 -- Fill pixel buffer and copy into table.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+
+
+procedure tm_cp1d (im, tp, cp, row, lena, leni)
+
+pointer im # imio pointer
+pointer tp # table pointer
+pointer cp # column pointer
+int row # row where to begin insertion
+int lena # array length
+int leni # image length
+#--
+pointer buf
+double undefd
+real undefr
+int undefi, i, len
+short undefs
+
+pointer imgl1d()
+
+begin
+ # Read pixels into buffer.
+ buf = imgl1d (im)
+
+ # Choose the minimum between image and table array
+ # lengths as the array size to be written to table.
+ len = min (lena, leni)
+
+ # Write buffer into array cell element.
+ call tbaptd (tp, cp, row, Memd[buf], 1, len)
+
+ # If image is smaller than array, set
+ # remaining elements to INDEF.
+ if (leni < lena) {
+ undefd = INDEFD
+ undefr = INDEFR
+ undefi = INDEFI
+ undefs = INDEFS
+ do i = len+1, lena
+ call tbaptd (tp, cp, row, undefd, i, 1)
+ }
+end
+
+
+
+
diff --git a/pkg/utilities/nttools/threed/tiimage/generic/tmcp1i.x b/pkg/utilities/nttools/threed/tiimage/generic/tmcp1i.x
new file mode 100644
index 00000000..7e271952
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/generic/tmcp1i.x
@@ -0,0 +1,54 @@
+
+# TM_CP1 -- Fill pixel buffer and copy into table.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+
+
+procedure tm_cp1i (im, tp, cp, row, lena, leni)
+
+pointer im # imio pointer
+pointer tp # table pointer
+pointer cp # column pointer
+int row # row where to begin insertion
+int lena # array length
+int leni # image length
+#--
+pointer buf
+double undefd
+real undefr
+int undefi, i, len
+short undefs
+
+pointer imgl1i()
+
+begin
+ # Read pixels into buffer.
+ buf = imgl1i (im)
+
+ # Choose the minimum between image and table array
+ # lengths as the array size to be written to table.
+ len = min (lena, leni)
+
+ # Write buffer into array cell element.
+ call tbapti (tp, cp, row, Memi[buf], 1, len)
+
+ # If image is smaller than array, set
+ # remaining elements to INDEF.
+ if (leni < lena) {
+ undefd = INDEFD
+ undefr = INDEFR
+ undefi = INDEFI
+ undefs = INDEFS
+ do i = len+1, lena
+ call tbapti (tp, cp, row, undefi, i, 1)
+ }
+end
+
+
+
+
diff --git a/pkg/utilities/nttools/threed/tiimage/generic/tmcp1r.x b/pkg/utilities/nttools/threed/tiimage/generic/tmcp1r.x
new file mode 100644
index 00000000..00594521
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/generic/tmcp1r.x
@@ -0,0 +1,54 @@
+
+# TM_CP1 -- Fill pixel buffer and copy into table.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+
+
+procedure tm_cp1r (im, tp, cp, row, lena, leni)
+
+pointer im # imio pointer
+pointer tp # table pointer
+pointer cp # column pointer
+int row # row where to begin insertion
+int lena # array length
+int leni # image length
+#--
+pointer buf
+double undefd
+real undefr
+int undefi, i, len
+short undefs
+
+pointer imgl1r()
+
+begin
+ # Read pixels into buffer.
+ buf = imgl1r (im)
+
+ # Choose the minimum between image and table array
+ # lengths as the array size to be written to table.
+ len = min (lena, leni)
+
+ # Write buffer into array cell element.
+ call tbaptr (tp, cp, row, Memr[buf], 1, len)
+
+ # If image is smaller than array, set
+ # remaining elements to INDEF.
+ if (leni < lena) {
+ undefd = INDEFD
+ undefr = INDEFR
+ undefi = INDEFI
+ undefs = INDEFS
+ do i = len+1, lena
+ call tbaptr (tp, cp, row, undefr, i, 1)
+ }
+end
+
+
+
+
diff --git a/pkg/utilities/nttools/threed/tiimage/generic/tmcp1s.x b/pkg/utilities/nttools/threed/tiimage/generic/tmcp1s.x
new file mode 100644
index 00000000..3d308f13
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/generic/tmcp1s.x
@@ -0,0 +1,54 @@
+
+# TM_CP1 -- Fill pixel buffer and copy into table.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+
+
+procedure tm_cp1s (im, tp, cp, row, lena, leni)
+
+pointer im # imio pointer
+pointer tp # table pointer
+pointer cp # column pointer
+int row # row where to begin insertion
+int lena # array length
+int leni # image length
+#--
+pointer buf
+double undefd
+real undefr
+int undefi, i, len
+short undefs
+
+pointer imgl1s()
+
+begin
+ # Read pixels into buffer.
+ buf = imgl1s (im)
+
+ # Choose the minimum between image and table array
+ # lengths as the array size to be written to table.
+ len = min (lena, leni)
+
+ # Write buffer into array cell element.
+ call tbapts (tp, cp, row, Mems[buf], 1, len)
+
+ # If image is smaller than array, set
+ # remaining elements to INDEF.
+ if (leni < lena) {
+ undefd = INDEFD
+ undefr = INDEFR
+ undefi = INDEFI
+ undefs = INDEFS
+ do i = len+1, lena
+ call tbapts (tp, cp, row, undefs, i, 1)
+ }
+end
+
+
+
+
diff --git a/pkg/utilities/nttools/threed/tiimage/list.tex b/pkg/utilities/nttools/threed/tiimage/list.tex
new file mode 100644
index 00000000..05eb3592
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/list.tex
@@ -0,0 +1,789 @@
+\documentstyle{article}
+\topmargin -30mm
+\textheight 250mm
+\oddsidemargin -5mm
+\evensidemargin -5mm
+\textwidth 170mm
+
+\begin{document}
+
+\tableofcontents
+
+\newpage
+
+\addcontentsline{toc}{section}{loc.txt}
+\begin{verbatim}
+
+Filename Total Blanks Comments Help Execute Nonexec
+============================================================================
+ tiimage.h 9 1 0 0 0 8
+ tiimage.x 141 36 31 0 53 21
+ tmloop.x 96 23 15 0 40 18
+ tmmode.x 108 24 24 0 30 30
+ tmscan.x 92 21 15 0 38 18
+ tmheader.x 59 19 8 0 19 13
+ tmhc.x 54 16 9 0 15 14
+ tmcopy.x 63 18 9 0 23 13
+ tmcp1.gx 53 17 11 0 10 15
+TOTAL 834 226 155 0 258 195
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{tiimage.h}
+\begin{verbatim}
+
+define OUTPUT_TYPE 1 # Output-type file
+define TEMPLATE_TYPE 2 # Template-type file
+
+define MODE_OUT_SINGLE 1 # Output with single column
+define MODE_OUT_ALL 2 # Output with all columns
+define MODE_TEM_SINGLE 3 # Template with single column
+define MODE_TEM_ALL 4 # Template with all columns
+define MODE_SCRATCH 5 # No output nor template, create from scratch
+define MODE_ERROR -1
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{tiimage.x}
+\begin{verbatim}
+
+include <tbset.h>
+include "tiimage.h"
+
+# TIIMAGE -- Insert 1D images into 3D table rows.
+#
+# Input images are given by a filename template list. The output is a
+# 3D table with optional column selector.
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+
+
+procedure t_tiimage()
+
+char imlist[SZ_LINE] # Input image list
+char output[SZ_PATHNAME] # Output table name
+char template[SZ_PATHNAME] # Template table name
+int row # Row where to begin insertion
+bool verbose # Print operations ?
+#--
+char root[SZ_FNAME] # String storage areas used
+char rs[SZ_FNAME] # by row/column selector
+char cs[SZ_FNAME] # mechanism
+char cn[SZ_COLNAME]
+char cu[SZ_COLUNITS]
+char cf[SZ_COLFMT]
+pointer sp, otp, ttp, ocp, tcp, newocp, tempp, list
+int nocp, mode, numcol, dtyp, lend, lenf, cnum, i
+
+pointer tbtopn(), tcs_column(), imtopen()
+int clgeti(), tbpsta(), tm_mode(), imtlen()
+bool clgetb(), streq()
+
+begin
+ # Get task parameters.
+ call clgstr ("input", imlist, SZ_LINE)
+ call clgstr ("outtable", output, SZ_PATHNAME)
+ call clgstr ("template", template, SZ_PATHNAME)
+ row = clgeti ("row")
+ verbose = clgetb ("verbose")
+
+ # Abort if invalid output name.
+ if (streq (output, "STDOUT"))
+ call error (1, "Invalid output file name.")
+
+ # Decide which mode to use.
+ mode = tm_mode (output, template, root, rs, cs, cn, cu, cf)
+
+ call smark (sp)
+ switch (mode) {
+
+ case MODE_OUT_SINGLE,MODE_OUT_ALL:
+
+ # Break output table name into bracketed selectors.
+ call rdselect (output, root, rs, cs, SZ_PATHNAME)
+
+ # Open output table.
+ otp = tbtopn (root, READ_WRITE, 0)
+
+ # Create arrays with selected column pointer(s).
+ numcol = tbpsta (otp, TBL_NCOLS)
+ call salloc (ocp, numcol, TY_INT)
+ call salloc (newocp, numcol, TY_INT)
+ call tcs_open (otp, cs, Memi[ocp], nocp, numcol)
+
+ # Translate pointer to tbtables-compatible format.
+ do i = 1, nocp
+ Memi[newocp+i-1] = tcs_column (Memi[ocp+i-1])
+
+ # Do the insertion by looping over all input images.
+ call tm_loop (otp, newocp, nocp, row, imlist, mode, output,
+ verbose)
+
+ # Close output table.
+ call tbtclo (otp)
+
+ case MODE_TEM_SINGLE,MODE_TEM_ALL:
+
+ # Get output table root name and open it.
+ call rdselect (output, root, rs, cs, SZ_PATHNAME)
+ otp = tbtopn (root, NEW_FILE, 0)
+
+ # Break template table name into bracketed
+ # selectors and open it.
+ call rdselect (template, root, rs, cs, SZ_PATHNAME)
+ ttp = tbtopn (root, READ_ONLY, 0)
+
+ # Create arrays with selected column pointer(s).
+ numcol = tbpsta (ttp, TBL_NCOLS)
+ call salloc (tcp, numcol, TY_INT)
+ call salloc (newocp, numcol, TY_INT)
+ call tcs_open (ttp, cs, Memi[tcp], nocp, numcol)
+
+ # Copy column info from template to output table.
+ do i = 1, nocp {
+ tempp = tcs_column (Memi[tcp+i-1])
+ call tbcinf (tempp, cnum, cn, cu, cf, dtyp, lend, lenf)
+ call tbcdef (otp, tempp, cn, cu, cf, dtyp, lend, 1)
+ Memi[newocp+i-1] = tempp
+ }
+
+ # Create output and close template.
+ call tbtcre (otp)
+ call tbtclo (ttp)
+
+ # Do the insertion by looping over all input images.
+ call tm_loop (otp, newocp, nocp, row, imlist, mode, output,
+ verbose)
+
+ # Close output table.
+ call tbtclo (otp)
+
+ case MODE_SCRATCH:
+
+ # Alloc memory for column pointer array, assuming
+ # the worst case of each input image in the list
+ # belonging to a separate column.
+ list = imtopen (imlist)
+ numcol = imtlen (list)
+ call imtclose (list)
+ call salloc (newocp, numcol, TY_INT)
+
+ # Open output table.
+ call rdselect (output, root, rs, cs, SZ_PATHNAME)
+ otp = tbtopn (root, NEW_FILE, 0)
+
+ # Build column descriptor array from info in image headers.
+ ifnoerr (call tm_scan (otp, newocp, numcol, nocp, imlist)) {
+
+ # Pretend that template table exists and do the insertion.
+ mode = MODE_TEM_ALL
+ call tm_loop (otp, newocp, nocp, row, imlist, mode, output,
+ verbose)
+ }
+
+ # Close output table.
+ call tbtclo (otp)
+
+ case MODE_ERROR:
+ call error (1, "Cannot process.")
+ }
+
+ call sfree (sp)
+end
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{tmloop.x}
+\begin{verbatim}
+
+include <error.h>
+include "tiimage.h"
+
+# TM_LOOP -- Scan input list and insert each image in turn.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+
+
+procedure tm_loop (tp, cp, ncp, row, imlist, mode, outname, verbose)
+
+pointer tp # table pointer
+pointer cp # column pointer array
+int ncp # size of column pointer array
+int row # row where to begin insertion
+char imlist[ARB] # input image list
+int mode # operating mode
+char outname[ARB] # output table name (for listing only)
+bool verbose # print info ?
+#--
+pointer sp, im, list, fname
+int i, rowc, imc, image
+bool rflag
+
+errchk immap, tm_hc, tm_copy
+
+pointer immap(), imtopen()
+int imtlen(), imtgetim()
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_PATHNAME, TY_CHAR)
+
+ # Initialize row counter.
+ rowc = row
+ rflag = false
+ if (rowc <= 0 || IS_INDEFI(rowc)) rflag = true
+
+ # Initialize successful image counter.
+ imc = 0
+
+ # Open input list.
+ list = imtopen (imlist)
+
+ # Loop over input list.
+ do image = 1, imtlen(list) {
+
+ # Get input image name and open it. Skip if error.
+ i = imtgetim (list, Memc[fname], SZ_PATHNAME)
+ iferr (im = immap (Memc[fname], READ_ONLY, 0)) {
+ call erract (EA_WARN)
+ next
+ }
+ if (verbose) {
+ call printf ("%s ")
+ call pargstr (Memc[fname])
+ call flush (STDOUT)
+ }
+
+ # Look into image header for columnar info and do the copy.
+ if (mode == MODE_OUT_ALL || mode == MODE_TEM_ALL) {
+ iferr (call tm_hc (tp, cp, ncp, rowc, rflag, im)) {
+ call erract (EA_WARN)
+ call imunmap (im)
+ next
+ }
+
+ # Bump row and image counters.
+ rowc = rowc + 1
+ imc = imc + 1
+
+ # Just copy into single column.
+ } else if (mode == MODE_OUT_SINGLE || mode == MODE_TEM_SINGLE) {
+ iferr (call tm_copy (tp, Memi[cp], rowc, rflag, im)) {
+ call erract (EA_WARN)
+ call imunmap (im)
+ next
+ }
+
+ # Bump row and image counters.
+ rowc = rowc + 1
+ imc = imc + 1
+ }
+
+ if (verbose) {
+ call printf ("-> %s row=%d \n")
+ call pargstr (outname)
+ call pargi (rowc-1)
+ call flush (STDOUT)
+ }
+
+ # Close current image.
+ call imunmap (im)
+ }
+
+ call imtclose (list)
+ call sfree (sp)
+ if (imc == 0)
+ call error (1, "No images were inserted.")
+end
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{tmmode.x}
+\begin{verbatim}
+
+include <tbset.h>
+include "../whatfile.h"
+include "tiimage.h"
+
+# TM_MODE -- Detect mode of operation.
+#
+# There are five possible modes:
+# 1 - Output table exists and one column was selected.
+# 2 - Output table exists and no valid column was selected.
+# 3 - Output table does not exist but template exists and one column was
+# selected.
+# 4 - Output table does not exist but template exists and no valid column
+# was selected.
+# 5 - New table has to be created from scratch.
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+
+
+int procedure tm_mode (output, template, root, rs, cs, cn, cu, cf)
+
+char output[SZ_PATHNAME]
+char template[SZ_PATHNAME]
+char root[SZ_FNAME]
+char rs[SZ_FNAME]
+char cs[SZ_FNAME]
+char cn[SZ_COLNAME]
+char cu[SZ_COLUNITS]
+char cf[SZ_COLFMT]
+#-
+int mode
+
+int access(), tm_m1()
+
+begin
+ # Process output name. Notice that routine access() must be
+ # supplied with only the root name in order to succeed.
+ call rdselect (output, root, rs, cs, SZ_PATHNAME)
+ if (access (root, READ_WRITE, 0) == YES) {
+ mode = tm_m1 (OUTPUT_TYPE, root,rs,cs,cn,cu,cf)
+ if (mode == MODE_ERROR)
+ call error (1, "Cannot use output file.")
+
+ # If no valid output, try with template name.
+ } else {
+ call rdselect (template, root, rs, cs, SZ_PATHNAME)
+ if (access (root, READ_ONLY, 0) == YES) {
+ mode = tm_m1 (TEMPLATE_TYPE, root, rs, cs, cn, cu, cf)
+ if (mode == MODE_ERROR)
+ call error (1, "Cannot use template file.")
+ } else {
+ mode = MODE_SCRATCH
+ }
+ }
+
+ return (mode)
+end
+
+
+# TM_M1 -- Verify status of file and column selector.
+
+int procedure tm_m1 (type, root, rs, cs, cn, cu, cf)
+
+int type
+char root[SZ_FNAME]
+char rs[SZ_FNAME]
+char cs[SZ_FNAME]
+char cn[SZ_COLNAME]
+char cu[SZ_COLUNITS]
+char cf[SZ_COLFMT]
+#-
+pointer tp, cp
+int numcol, ncp
+
+pointer tbtopn()
+int whatfile(), tbpsta()
+
+begin
+ # Test if it is a valid table.
+ if (whatfile (root) != IS_TABLE)
+ return (MODE_ERROR)
+
+ # Open table
+ tp = tbtopn (root, READ_ONLY)
+
+ # Get its total number of columns.
+ numcol = tbpsta (tp, TBL_NCOLS)
+
+ # Create array of column pointers from column selector.
+ # This is just to get the actual number of selected columns.
+ call malloc (cp, numcol, TY_INT)
+ call tcs_open (tp, cs, Memi[cp], ncp, numcol)
+ call tbtclo (tp)
+ call mfree (cp)
+
+ # Decide mode.
+ if (type == OUTPUT_TYPE) {
+ if (ncp == 1)
+ return (MODE_OUT_SINGLE)
+ else
+ return (MODE_OUT_ALL)
+ } else if (type == TEMPLATE_TYPE) {
+ if (ncp == 1)
+ return (MODE_TEM_SINGLE)
+ else
+ return (MODE_TEM_ALL)
+ }
+ return (MODE_ERROR)
+end
+
+
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{tmscan.x}
+\begin{verbatim}
+
+include <error.h>
+include <imhdr.h>
+include <tbset.h>
+
+# TM_SCAN -- Scan input image list and create column pointer array
+# and table from information stored in image headers.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+
+
+procedure tm_scan (otp, ocp, ocpsize, nocp, imlist)
+
+pointer otp # i: output table pointer
+pointer ocp # io: output table column pointer array
+int ocpsize # i: size of above array
+int nocp # o: actual number of columns in array
+char imlist[ARB] # i: input image list
+#--
+pointer sp, im, list
+pointer imname, cn, cn1, cu, cf, duma
+int image, column, lendata, dumi, i
+bool match
+
+errchk tm_header
+
+pointer imtopen(), immap()
+int imtlen(), imtgetim()
+bool streq()
+
+begin
+ call smark (sp)
+ call salloc (imname, SZ_PATHNAME, TY_CHAR)
+ call salloc (cn, SZ_COLNAME, TY_CHAR)
+ call salloc (cn1, SZ_COLNAME, TY_CHAR)
+ call salloc (cu, SZ_COLUNITS, TY_CHAR)
+ call salloc (cf, SZ_COLFMT, TY_CHAR)
+ call salloc (duma, max(SZ_COLUNITS,SZ_COLFMT),TY_CHAR)
+
+ # Open input list and initialize number of columns.
+ list = imtopen (imlist)
+ nocp = 0
+
+ # Scan input list.
+ do image = 1, imtlen(list) {
+
+ # Open image.
+ i = imtgetim (list, Memc[imname], SZ_PATHNAME)
+ iferr (im = immap (Memc[imname], READ_ONLY, 0)) {
+ call erract (EA_WARN)
+ next
+ }
+
+ # Get column data from image header.
+ iferr (call tm_header (im, Memc[cn], Memc[cu], Memc[cf])) {
+ call erract (EA_WARN)
+ next
+ }
+
+ # Array size is full image size.
+ lendata = 0
+ do i = 1, IM_NDIM(im)
+ lendata = lendata + IM_LEN(im,i)
+
+ if (nocp > 0) {
+
+ # See if column name from header matches any name
+ # already stored in column pointer array.
+ match = false
+ do column = 1, nocp {
+ call tbcinf (Memi[ocp+column-1], dumi, Memc[cn1],
+ Memc[duma], Memc[duma], dumi, dumi, dumi)
+ if (streq (Memc[cn1], Memc[cn])) {
+ match = true
+ break
+ }
+ }
+ if (!match) {
+
+ # No names matched, efine new column.
+ call tbcdef (otp, Memi[ocp+nocp], Memc[cn], Memc[cu],
+ Memc[cf], IM_PIXTYPE(im), lendata, 1)
+ nocp = nocp + 1
+ }
+ } else {
+
+ # Array is empty, define first column.
+ call tbcdef (otp, Memi[ocp], Memc[cn], Memc[cu], Memc[cf],
+ IM_PIXTYPE(im), lendata, 1)
+ nocp = 1
+ }
+ }
+
+ call imtclose (list)
+ call sfree (sp)
+ if (nocp == 0)
+ call error (1, "No images with column data in header.")
+ call tbtcre (otp)
+end
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{tmheader.x}
+\begin{verbatim}
+
+include <tbset.h>
+
+# TM_HEADER -- Decode column info in image header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+
+
+procedure tm_header (im, colname, colunits, colfmt)
+
+pointer im # image pointer
+char colname[SZ_COLNAME] # column name
+char colunits[SZ_COLUNITS] # column units
+char colfmt[SZ_COLFMT] # column print format
+#--
+pointer sp, kwval
+int colnum
+
+string corrupt "Corrupted header in input image."
+
+bool streq()
+int imaccf(), nscan()
+
+begin
+ if (imaccf (im, "COLDATA") == NO)
+ call error (1, "No column information in image header.")
+
+ call smark (sp)
+ call salloc (kwval, SZ_LINE, TY_CHAR)
+
+ # Get keyword value.
+ call imgstr (im, "COLDATA", Memc[kwval], SZ_LINE)
+
+ # Read fields.
+ call sscan (Memc[kwval])
+ call gargi (colnum)
+ if (nscan() < 1) call error (1, corrupt)
+ call gargwrd (colname, SZ_COLNAME)
+ if (nscan() < 1) call error (1, corrupt)
+ call gargwrd (colunits, SZ_COLUNITS)
+ if (nscan() < 1) call error (1, corrupt)
+ call gargwrd (colfmt, SZ_COLFMT)
+ if (nscan() < 1) call error (1, corrupt)
+
+ # Decode custom-encoded values.
+ if (streq (colunits, "default"))
+ call strcpy ("", colunits, SZ_COLUNITS)
+ if (streq (colfmt, "default"))
+ call strcpy ("", colfmt, SZ_COLFMT)
+
+ call sfree (sp)
+end
+
+
+
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{tmhc.x}
+\begin{verbatim}
+
+include <tbset.h>
+
+# TM_HC -- Get column name from image header and copy image into table.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+
+
+procedure tm_hc (tp, cp, ncp, row, rflag, im)
+
+pointer tp # table pointer
+pointer cp # column pointer array
+int ncp # size of column pointer array
+int row # row where to begin insertion
+bool rflag # use row number in header ?
+pointer im # image pointer
+#--
+pointer sp, colname, cn, duma
+int i, dumi
+bool match
+
+errchk tm_header, tm_copy
+
+bool streq()
+
+begin
+ call smark (sp)
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+ call salloc (cn, SZ_COLNAME, TY_CHAR)
+ call salloc (duma, max(SZ_COLUNITS,SZ_COLFMT),TY_CHAR)
+
+ # Get column name from image header.
+ call tm_header (im, Memc[colname], Memc[duma], Memc[duma])
+
+ # Loop over table columns.
+ match = false
+ do i = 1, ncp {
+
+ # Get column name from table.
+ call tbcinf (Memi[cp+i-1], dumi, Memc[cn], Memc[duma],
+ Memc[duma], dumi, dumi, dumi)
+
+ # Copy array if names match.
+ if (streq (Memc[colname], Memc[cn])) {
+ call tm_copy (tp, Memi[cp+i-1], row, rflag, im)
+ match = true
+ }
+ }
+ if (!match)
+ call error (1, "No column matched.")
+
+ call sfree (sp)
+end
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{tmcopy.x}
+\begin{verbatim}
+
+include <imhdr.h>
+include <tbset.h>
+
+# TM_COPY -- Copy image into designated row/column.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+
+
+procedure tm_copy (tp, cp, row, rflag, im)
+
+pointer tp # table pointer
+pointer cp # column pointer
+int row # row where to begin insertion
+bool rflag # use row number in image header ?
+pointer im # imio pointer
+#--
+pointer sp, duma
+int i, lena, leni, dumi
+
+int tbcigi(), imgeti(), imaccf()
+
+begin
+ # See if table and image pixel types match.
+ if (tbcigi (tp, TBL_COL_DATATYPE) == IM_PIXTYPE(im))
+ call error (1, "Pixel type mismatch.")
+
+ # Look for row information in image header.
+ if (imaccf (im, "ORIG_ROW") == YES) {
+ if (rflag)
+ row = imgeti (im, "ORIG_ROW")
+ }
+
+ # Get column array size and image size.
+ call smark (sp)
+ call salloc (duma, max(max(SZ_COLNAME,SZ_COLUNITS),SZ_COLFMT),TY_CHAR)
+ call tbcinf (cp, dumi, Memc[duma], Memc[duma], Memc[duma], dumi,
+ lena, dumi)
+ call sfree (sp)
+ leni = 0
+ do i = 1, IM_NDIM(im)
+ leni = leni + IM_LEN(im,i)
+
+ # Copy.
+ switch (IM_PIXTYPE(im)) {
+ case TY_SHORT:
+ call tm_cp1s (im, tp, cp, row, lena, leni)
+ case TY_INT:
+ call tm_cp1i (im, tp, cp, row, lena, leni)
+ case TY_REAL:
+ call tm_cp1r (im, tp, cp, row, lena, leni)
+ case TY_DOUBLE:
+ call tm_cp1d (im, tp, cp, row, lena, leni)
+ default:
+ call error (1, "Non-supported data type.")
+ }
+
+end
+
+
+
+
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{tmcp1.gx}
+\begin{verbatim}
+
+
+# TM_CP1 -- Fill pixel buffer and copy into table.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+
+
+procedure tm_cp1$t (im, tp, cp, row, lena, leni)
+
+pointer im # imio pointer
+pointer tp # table pointer
+pointer cp # column pointer
+int row # row where to begin insertion
+int lena # array length
+int leni # image length
+#--
+pointer buf
+double undefd
+real undefr
+int undefi, i, len
+short undefs
+
+pointer imgl1$t()
+
+begin
+ # Read pixels into buffer.
+ buf = imgl1$t (im)
+
+ # Choose the minimum between image and table array
+ # lengths as the array size to be written to table.
+ len = min (lena, leni)
+
+ # Write buffer into array cell element.
+ call tbapt$t (tp, cp, row, Mem$t[buf], 1, len)
+
+ # If image is smaller than array, set
+ # remaining elements to INDEF.
+ if (leni < lena) {
+ undefd = INDEFD
+ undefr = INDEFR
+ undefi = INDEFI
+ undefs = INDEFS
+ do i = len+1, lena
+ call tbapt$t (tp, cp, row, undef$t, i, 1)
+ }
+end
+
+
+
+
+\end{verbatim}
+\newpage
+\end{document}
diff --git a/pkg/utilities/nttools/threed/tiimage/list.toc b/pkg/utilities/nttools/threed/tiimage/list.toc
new file mode 100644
index 00000000..06d86919
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/list.toc
@@ -0,0 +1,10 @@
+\contentsline {section}{loc.txt}{2}
+\contentsline {section}{tiimage.h}{3}
+\contentsline {section}{tiimage.x}{4}
+\contentsline {section}{tmloop.x}{7}
+\contentsline {section}{tmmode.x}{9}
+\contentsline {section}{tmscan.x}{11}
+\contentsline {section}{tmheader.x}{13}
+\contentsline {section}{tmhc.x}{15}
+\contentsline {section}{tmcopy.x}{16}
+\contentsline {section}{tmcp1.gx}{18}
diff --git a/pkg/utilities/nttools/threed/tiimage/loc.txt b/pkg/utilities/nttools/threed/tiimage/loc.txt
new file mode 100644
index 00000000..43db97fc
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/loc.txt
@@ -0,0 +1,12 @@
+Filename Total Blanks Comments Help Execute Nonexec
+============================================================================
+ tiimage.h 9 1 0 0 0 8
+ tiimage.x 141 36 31 0 53 21
+ tmloop.x 96 23 15 0 40 18
+ tmmode.x 108 24 24 0 30 30
+ tmscan.x 92 21 15 0 38 18
+ tmheader.x 59 19 8 0 19 13
+ tmhc.x 54 16 9 0 15 14
+ tmcopy.x 63 18 9 0 23 13
+ tmcp1.gx 53 17 11 0 10 15
+TOTAL 834 226 155 0 258 195
diff --git a/pkg/utilities/nttools/threed/tiimage/mkpkg b/pkg/utilities/nttools/threed/tiimage/mkpkg
new file mode 100644
index 00000000..6a3588af
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/mkpkg
@@ -0,0 +1,29 @@
+# Update the tiimage application code in the threed package library.
+# Author: I.Busko, 30-Jan-1997
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+# This module is called from the threed mkpkg.
+generic:
+ $ifnfile (generic/tmcp1i.x)
+ $generic -k -p generic/ -t sird tmcp1.gx
+ $endif
+ $ifolder (generic/tmcp1i.x, tmcp1.gx)
+ $generic -k -p generic/ -t sird tmcp1.gx
+ $endif
+ ;
+
+libpkg.a:
+ @generic
+ tiimage.x <tbset.h> tiimage.h
+ tmcopy.x <imhdr.h> <tbset.h>
+ tmhc.x <tbset.h>
+ tmheader.x <tbset.h>
+ tmloop.x <error.h> tiimage.h
+ tmmode.x <tbset.h> tiimage.h
+ tmscan.x <error.h> <imhdr.h> <tbset.h>
+ ;
+
diff --git a/pkg/utilities/nttools/threed/tiimage/tiimage.h b/pkg/utilities/nttools/threed/tiimage/tiimage.h
new file mode 100644
index 00000000..86e0d000
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/tiimage.h
@@ -0,0 +1,9 @@
+define OUTPUT_TYPE 1 # Output-type file
+define TEMPLATE_TYPE 2 # Template-type file
+
+define MODE_OUT_SINGLE 1 # Output with single column
+define MODE_OUT_ALL 2 # Output with all columns
+define MODE_TEM_SINGLE 3 # Template with single column
+define MODE_TEM_ALL 4 # Template with all columns
+define MODE_SCRATCH 5 # No output nor template, create from scratch
+define MODE_ERROR -1
diff --git a/pkg/utilities/nttools/threed/tiimage/tiimage.x b/pkg/utilities/nttools/threed/tiimage/tiimage.x
new file mode 100644
index 00000000..85aab676
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/tiimage.x
@@ -0,0 +1,147 @@
+include <tbset.h>
+include "tiimage.h"
+
+# TIIMAGE -- Insert 1D images into 3D table rows.
+#
+# Input images are given by a filename template list. The output is a
+# 3D table with optional column selector.
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+
+
+procedure t_tiimage()
+
+char imlist[SZ_LINE] # Input image list
+char output[SZ_PATHNAME] # Output table name
+char template[SZ_PATHNAME] # Template table name
+int row # Row where to begin insertion
+bool verbose # Print operations ?
+#--
+char root[SZ_FNAME] # String storage areas used
+char rs[SZ_FNAME] # by row/column selector
+char cs[SZ_FNAME] # mechanism
+char cn[SZ_COLNAME]
+char cu[SZ_COLUNITS]
+char cf[SZ_COLFMT]
+pointer sp, otp, ttp, ocp, tcp, newocp, tempp, list
+int nocp, mode, numcol, dtyp, lend, lenf, cnum, i
+
+pointer tbtopn(), tcs_column(), imtopen()
+int clgeti(), tbpsta(), tm_mode(), imtlen()
+bool clgetb(), streq()
+
+begin
+ # Get task parameters.
+ call clgstr ("input", imlist, SZ_LINE)
+ call clgstr ("outtable", output, SZ_PATHNAME)
+ call clgstr ("template", template, SZ_PATHNAME)
+ row = clgeti ("row")
+ verbose = clgetb ("verbose")
+
+ # Abort if invalid output name.
+ if (streq (output, "STDOUT"))
+ call error (1, "Invalid output file name.")
+
+ # Decide which mode to use.
+ mode = tm_mode (output, template, root, rs, cs, cn, cu, cf)
+
+ call smark (sp)
+ switch (mode) {
+
+ case MODE_OUT_SINGLE,MODE_OUT_ALL:
+
+ # Break output table name into bracketed selectors.
+ call rdselect (output, root, rs, cs, SZ_PATHNAME)
+
+ # Open output table.
+ otp = tbtopn (root, READ_WRITE, 0)
+
+ # Create arrays with selected column pointer(s).
+ numcol = tbpsta (otp, TBL_NCOLS)
+ call salloc (ocp, numcol, TY_INT)
+ call salloc (newocp, numcol, TY_INT)
+ call tcs_open (otp, cs, Memi[ocp], nocp, numcol)
+
+ # Translate pointer to tbtables-compatible format.
+ do i = 1, nocp
+ Memi[newocp+i-1] = tcs_column (Memi[ocp+i-1])
+
+ # Do the insertion by looping over all input images.
+ call tm_loop (otp, newocp, nocp, row, imlist, mode, output,
+ verbose)
+
+ # Close output table.
+ call tbtclo (otp)
+
+ case MODE_TEM_SINGLE,MODE_TEM_ALL:
+
+ # Get output table root name and open it.
+ call rdselect (output, root, rs, cs, SZ_PATHNAME)
+ otp = tbtopn (root, NEW_FILE, 0)
+
+ # Break template table name into bracketed
+ # selectors and open it.
+ call rdselect (template, root, rs, cs, SZ_PATHNAME)
+ ttp = tbtopn (root, READ_ONLY, 0)
+
+ # Create arrays with selected column pointer(s).
+ numcol = tbpsta (ttp, TBL_NCOLS)
+ call salloc (tcp, numcol, TY_INT)
+ call salloc (newocp, numcol, TY_INT)
+ call tcs_open (ttp, cs, Memi[tcp], nocp, numcol)
+
+ # Copy column info from template to output table.
+ do i = 1, nocp {
+ tempp = tcs_column (Memi[tcp+i-1])
+ call tbcinf (tempp, cnum, cn, cu, cf, dtyp, lend, lenf)
+ call tbcdef (otp, tempp, cn, cu, cf, dtyp, lend, 1)
+ Memi[newocp+i-1] = tempp
+ }
+
+ # Create output and close template.
+ call tbtcre (otp)
+ call tbtclo (ttp)
+
+ # Do the insertion by looping over all input images.
+ call tm_loop (otp, newocp, nocp, row, imlist, mode, output,
+ verbose)
+
+ # Close output table.
+ call tbtclo (otp)
+
+ case MODE_SCRATCH:
+
+ # Alloc memory for column pointer array, assuming
+ # the worst case of each input image in the list
+ # belonging to a separate column.
+ list = imtopen (imlist)
+ numcol = imtlen (list)
+ call imtclose (list)
+ call salloc (newocp, numcol, TY_INT)
+
+ # Open output table.
+ call rdselect (output, root, rs, cs, SZ_PATHNAME)
+ otp = tbtopn (root, NEW_FILE, 0)
+
+ # Build column descriptor array from info in image headers.
+ ifnoerr (call tm_scan (otp, newocp, numcol, nocp, imlist)) {
+
+ # Pretend that template table exists and do the insertion.
+ mode = MODE_TEM_ALL
+ call tm_loop (otp, newocp, nocp, row, imlist, mode, output,
+ verbose)
+ }
+
+ # Close output table.
+ call tbtclo (otp)
+
+ case MODE_ERROR:
+ call error (1, "Cannot process.")
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/threed/tiimage/tmcopy.x b/pkg/utilities/nttools/threed/tiimage/tmcopy.x
new file mode 100644
index 00000000..8d2673c5
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/tmcopy.x
@@ -0,0 +1,67 @@
+include <imhdr.h>
+include <tbset.h>
+
+# TM_COPY -- Copy image into designated row/column.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+# 21-May-97 - Changes from code review (IB)
+
+
+procedure tm_copy (tp, cp, row, rflag, im)
+
+pointer tp # table pointer
+pointer cp # column pointer
+int row # row where to begin insertion
+bool rflag # use row number in image header ?
+pointer im # imio pointer
+#--
+pointer sp, duma
+int i, lena, leni, dumi
+
+int tbcigi(), imgeti(), imaccf()
+
+begin
+ # See if table and image pixel types match.
+ if (tbcigi (tp, TBL_COL_DATATYPE) == IM_PIXTYPE(im))
+ call error (1, "Pixel type mismatch.")
+
+ # Look for row information in image header.
+ if (imaccf (im, "ORIG_ROW") == YES) {
+ if (rflag)
+ row = imgeti (im, "ORIG_ROW")
+ }
+
+ # Get column array size and image size.
+ call smark (sp)
+ call salloc (duma, max(max(SZ_COLNAME,SZ_COLUNITS),SZ_COLFMT),TY_CHAR)
+ call tbcinf (cp, dumi, Memc[duma], Memc[duma], Memc[duma], dumi,
+ lena, dumi)
+ call sfree (sp)
+ leni = 1
+ do i = 1, IM_NDIM(im)
+ leni = leni * IM_LEN(im,i)
+
+ # Copy.
+ switch (IM_PIXTYPE(im)) {
+ case TY_SHORT:
+ call tm_cp1s (im, tp, cp, row, lena, leni)
+ case TY_INT:
+ call tm_cp1i (im, tp, cp, row, lena, leni)
+ case TY_REAL:
+ call tm_cp1r (im, tp, cp, row, lena, leni)
+ case TY_DOUBLE:
+ call tm_cp1d (im, tp, cp, row, lena, leni)
+ default:
+ call error (1, "Non-supported data type.")
+ }
+
+end
+
+
+
+
diff --git a/pkg/utilities/nttools/threed/tiimage/tmcp1.gx b/pkg/utilities/nttools/threed/tiimage/tmcp1.gx
new file mode 100644
index 00000000..b90ca406
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/tmcp1.gx
@@ -0,0 +1,54 @@
+
+# TM_CP1 -- Fill pixel buffer and copy into table.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+
+
+procedure tm_cp1$t (im, tp, cp, row, lena, leni)
+
+pointer im # imio pointer
+pointer tp # table pointer
+pointer cp # column pointer
+int row # row where to begin insertion
+int lena # array length
+int leni # image length
+#--
+pointer buf
+double undefd
+real undefr
+int undefi, i, len
+short undefs
+
+pointer imgl1$t()
+
+begin
+ # Read pixels into buffer.
+ buf = imgl1$t (im)
+
+ # Choose the minimum between image and table array
+ # lengths as the array size to be written to table.
+ len = min (lena, leni)
+
+ # Write buffer into array cell element.
+ call tbapt$t (tp, cp, row, Mem$t[buf], 1, len)
+
+ # If image is smaller than array, set
+ # remaining elements to INDEF.
+ if (leni < lena) {
+ undefd = INDEFD
+ undefr = INDEFR
+ undefi = INDEFI
+ undefs = INDEFS
+ do i = len+1, lena
+ call tbapt$t (tp, cp, row, undef$t, i, 1)
+ }
+end
+
+
+
+
diff --git a/pkg/utilities/nttools/threed/tiimage/tmhc.x b/pkg/utilities/nttools/threed/tiimage/tmhc.x
new file mode 100644
index 00000000..30ad4eb3
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/tmhc.x
@@ -0,0 +1,57 @@
+include <tbset.h>
+
+# TM_HC -- Get column name from image header and copy image into table.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+
+
+procedure tm_hc (tp, cp, ncp, row, rflag, im)
+
+pointer tp # table pointer
+pointer cp # column pointer array
+int ncp # size of column pointer array
+int row # row where to begin insertion
+bool rflag # use row number in header ?
+pointer im # image pointer
+#--
+pointer sp, colname, cn, duma
+int i, dumi
+bool match
+
+errchk tm_header, tm_copy
+
+bool streq()
+
+begin
+ call smark (sp)
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+ call salloc (cn, SZ_COLNAME, TY_CHAR)
+ call salloc (duma, max(SZ_COLUNITS,SZ_COLFMT),TY_CHAR)
+
+ # Get column name from image header.
+ call tm_header (im, Memc[colname], Memc[duma], Memc[duma])
+
+ # Loop over table columns.
+ match = false
+ do i = 1, ncp {
+
+ # Get column name from table.
+ call tbcinf (Memi[cp+i-1], dumi, Memc[cn], Memc[duma],
+ Memc[duma], dumi, dumi, dumi)
+
+ # Copy array if names match.
+ if (streq (Memc[colname], Memc[cn])) {
+ call tm_copy (tp, Memi[cp+i-1], row, rflag, im)
+ match = true
+ }
+ }
+ if (!match)
+ call error (1, "No column matched.")
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/threed/tiimage/tmheader.x b/pkg/utilities/nttools/threed/tiimage/tmheader.x
new file mode 100644
index 00000000..b6481fa4
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/tmheader.x
@@ -0,0 +1,60 @@
+include <tbset.h>
+
+# TM_HEADER -- Decode column info in image header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+# 21-May-97 - Changes from code review (IB)
+
+
+procedure tm_header (im, colname, colunits, colfmt)
+
+pointer im # image pointer
+char colname[SZ_COLNAME] # column name
+char colunits[SZ_COLUNITS] # column units
+char colfmt[SZ_COLFMT] # column print format
+#--
+pointer sp, kwval
+int colnum
+
+string corrupt "Corrupted header in input image."
+
+bool streq()
+int imaccf(), nscan()
+
+begin
+ if (imaccf (im, "COLDATA") == NO)
+ call error (1, "No column information in image header.")
+
+ call smark (sp)
+ call salloc (kwval, SZ_LINE, TY_CHAR)
+
+ # Get keyword value.
+ call imgstr (im, "COLDATA", Memc[kwval], SZ_LINE)
+
+ # Read fields.
+ call sscan (Memc[kwval])
+ call gargi (colnum)
+ if (nscan() < 1) call error (1, corrupt)
+ call gargwrd (colname, SZ_COLNAME)
+ if (nscan() < 1) call error (1, corrupt)
+ call gargwrd (colunits, SZ_COLUNITS)
+ if (nscan() < 1) call error (1, corrupt)
+ call gargwrd (colfmt, SZ_COLFMT)
+ if (nscan() < 1) call error (1, corrupt)
+
+ # Decode custom-encoded values.
+ if (streq (colunits, "default"))
+ colunits[1] = EOS
+ if (streq (colfmt, "default"))
+ colfmt[1] = EOS
+
+ call sfree (sp)
+end
+
+
+
diff --git a/pkg/utilities/nttools/threed/tiimage/tmloop.x b/pkg/utilities/nttools/threed/tiimage/tmloop.x
new file mode 100644
index 00000000..e99d8e8b
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/tmloop.x
@@ -0,0 +1,104 @@
+include <error.h>
+include "tiimage.h"
+
+# TM_LOOP -- Scan input list and insert each image in turn.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+
+
+procedure tm_loop (tp, cp, ncp, row, imlist, mode, outname, verbose)
+
+pointer tp # table pointer
+pointer cp # column pointer array
+int ncp # size of column pointer array
+int row # row where to begin insertion
+char imlist[ARB] # input image list
+int mode # operating mode
+char outname[ARB] # output table name (for listing only)
+bool verbose # print info ?
+#--
+pointer sp, im, list, fname
+int i, rowc, imc, image
+bool rflag
+
+errchk immap, tm_hc, tm_copy
+
+pointer immap(), imtopen()
+int imtlen(), imtgetim()
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_PATHNAME, TY_CHAR)
+
+ # Initialize row counter.
+ rowc = row
+ rflag = false
+ if (rowc <= 0 || IS_INDEFI(rowc)) rflag = true
+
+ # Initialize successful image counter.
+ imc = 0
+
+ # Open input list.
+ list = imtopen (imlist)
+
+ # Loop over input list.
+ do image = 1, imtlen(list) {
+
+ # Get input image name and open it. Skip if error.
+ i = imtgetim (list, Memc[fname], SZ_PATHNAME)
+ iferr (im = immap (Memc[fname], READ_ONLY, 0)) {
+ call erract (EA_WARN)
+ next
+ }
+ if (verbose) {
+ call printf ("%s ")
+ call pargstr (Memc[fname])
+ call flush (STDOUT)
+ }
+
+ # Look into image header for columnar info and do the copy.
+ if (mode == MODE_OUT_ALL || mode == MODE_TEM_ALL) {
+ iferr (call tm_hc (tp, cp, ncp, rowc, rflag, im)) {
+ call erract (EA_WARN)
+ call imunmap (im)
+ next
+ }
+
+ # Bump row and image counters.
+ rowc = rowc + 1
+ imc = imc + 1
+
+ # Just copy into single column.
+ } else if (mode == MODE_OUT_SINGLE || mode == MODE_TEM_SINGLE) {
+ iferr (call tm_copy (tp, Memi[cp], rowc, rflag, im)) {
+ call erract (EA_WARN)
+ call imunmap (im)
+ next
+ }
+
+ # Bump row and image counters.
+ rowc = rowc + 1
+ imc = imc + 1
+ }
+
+ if (verbose) {
+ call printf ("-> %s row=%d \n")
+ call pargstr (outname)
+ call pargi (rowc-1)
+ call flush (STDOUT)
+ }
+
+ # Close current image.
+ call imunmap (im)
+ }
+
+ call imtclose (list)
+ call sfree (sp)
+ if (imc == 0)
+ call error (1, "No images were inserted.")
+end
diff --git a/pkg/utilities/nttools/threed/tiimage/tmmode.x b/pkg/utilities/nttools/threed/tiimage/tmmode.x
new file mode 100644
index 00000000..0f159763
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/tmmode.x
@@ -0,0 +1,108 @@
+include <tbset.h>
+include "tiimage.h"
+
+# TM_MODE -- Detect mode of operation.
+#
+# There are five possible modes:
+# 1 - Output table exists and one column was selected.
+# 2 - Output table exists and no valid column was selected.
+# 3 - Output table does not exist but template exists and one column was
+# selected.
+# 4 - Output table does not exist but template exists and no valid column
+# was selected.
+# 5 - New table has to be created from scratch.
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+# 8-Apr-02 - Remove the call to whatfile (P. Hodge)
+
+
+int procedure tm_mode (output, template, root, rs, cs, cn, cu, cf)
+
+char output[SZ_PATHNAME]
+char template[SZ_PATHNAME]
+char root[SZ_FNAME]
+char rs[SZ_FNAME]
+char cs[SZ_FNAME]
+char cn[SZ_COLNAME]
+char cu[SZ_COLUNITS]
+char cf[SZ_COLFMT]
+#-
+int mode
+
+int access(), tm_m1()
+
+begin
+ # Process output name. Notice that routine access() must be
+ # supplied with only the root name in order to succeed.
+ call rdselect (output, root, rs, cs, SZ_PATHNAME)
+ if (access (root, READ_WRITE, 0) == YES) {
+ mode = tm_m1 (OUTPUT_TYPE, root,rs,cs,cn,cu,cf)
+ if (mode == MODE_ERROR)
+ call error (1, "Cannot use output file.")
+
+ # If no valid output, try with template name.
+ } else {
+ call rdselect (template, root, rs, cs, SZ_PATHNAME)
+ if (access (root, READ_ONLY, 0) == YES) {
+ mode = tm_m1 (TEMPLATE_TYPE, root, rs, cs, cn, cu, cf)
+ if (mode == MODE_ERROR)
+ call error (1, "Cannot use template file.")
+ } else {
+ mode = MODE_SCRATCH
+ }
+ }
+
+ return (mode)
+end
+
+
+# TM_M1 -- Verify status of file and column selector.
+
+int procedure tm_m1 (type, root, rs, cs, cn, cu, cf)
+
+int type
+char root[SZ_FNAME]
+char rs[SZ_FNAME]
+char cs[SZ_FNAME]
+char cn[SZ_COLNAME]
+char cu[SZ_COLUNITS]
+char cf[SZ_COLFMT]
+#-
+pointer tp, cp
+int numcol, ncp
+
+pointer tbtopn()
+int tbpsta()
+
+begin
+ # Open table
+ tp = tbtopn (root, READ_ONLY, 0)
+
+ # Get its total number of columns.
+ numcol = tbpsta (tp, TBL_NCOLS)
+
+ # Create array of column pointers from column selector.
+ # This is just to get the actual number of selected columns.
+ call malloc (cp, numcol, TY_INT)
+ call tcs_open (tp, cs, Memi[cp], ncp, numcol)
+ call tbtclo (tp)
+ call mfree (cp, TY_INT)
+
+ # Decide mode.
+ if (type == OUTPUT_TYPE) {
+ if (ncp == 1)
+ return (MODE_OUT_SINGLE)
+ else
+ return (MODE_OUT_ALL)
+ } else if (type == TEMPLATE_TYPE) {
+ if (ncp == 1)
+ return (MODE_TEM_SINGLE)
+ else
+ return (MODE_TEM_ALL)
+ }
+ return (MODE_ERROR)
+end
diff --git a/pkg/utilities/nttools/threed/tiimage/tmscan.x b/pkg/utilities/nttools/threed/tiimage/tmscan.x
new file mode 100644
index 00000000..31af8c02
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tiimage/tmscan.x
@@ -0,0 +1,96 @@
+include <error.h>
+include <imhdr.h>
+include <tbset.h>
+
+# TM_SCAN -- Scan input image list and create column pointer array
+# and table from information stored in image headers.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 30-Jan-97 - Task created (I.Busko)
+# 21-May-97 - Changes from code review (IB)
+
+
+procedure tm_scan (otp, ocp, ocpsize, nocp, imlist)
+
+pointer otp # i: output table pointer
+pointer ocp # io: output table column pointer array
+int ocpsize # i: size of above array
+int nocp # o: actual number of columns in array
+char imlist[ARB] # i: input image list
+#--
+pointer sp, im, list
+pointer imname, cn, cn1, cu, cf, duma
+int image, column, lendata, dumi, i
+bool match
+
+errchk tm_header
+
+pointer imtopen(), immap()
+int imtlen(), imtgetim()
+bool streq()
+
+begin
+ call smark (sp)
+ call salloc (imname, SZ_PATHNAME, TY_CHAR)
+ call salloc (cn, SZ_COLNAME, TY_CHAR)
+ call salloc (cn1, SZ_COLNAME, TY_CHAR)
+ call salloc (cu, SZ_COLUNITS, TY_CHAR)
+ call salloc (cf, SZ_COLFMT, TY_CHAR)
+ call salloc (duma, max(SZ_COLUNITS,SZ_COLFMT),TY_CHAR)
+
+ # Open input list and initialize number of columns.
+ list = imtopen (imlist)
+ nocp = 0
+
+ # Scan input list.
+ do image = 1, imtlen(list) {
+
+ # Open image.
+ i = imtgetim (list, Memc[imname], SZ_PATHNAME)
+ iferr (im = immap (Memc[imname], READ_ONLY, 0)) {
+ call erract (EA_WARN)
+ next
+ }
+
+ # Get column data from image header.
+ iferr (call tm_header (im, Memc[cn], Memc[cu], Memc[cf])) {
+ call erract (EA_WARN)
+ next
+ }
+
+ # Array size is full image size.
+ lendata = 1
+ do i = 1, IM_NDIM(im)
+ lendata = lendata * IM_LEN(im,i)
+
+
+ # See if column name from header matches any name
+ # already stored in column pointer array.
+ match = false
+ do column = 1, nocp {
+ call tbcinf (Memi[ocp+column-1], dumi, Memc[cn1],
+ Memc[duma], Memc[duma], dumi, dumi, dumi)
+ if (streq (Memc[cn1], Memc[cn])) {
+ match = true
+ break
+ }
+ }
+ if (!match) {
+
+ # No names matched, define new column.
+ call tbcdef (otp, Memi[ocp+nocp], Memc[cn], Memc[cu],
+ Memc[cf], IM_PIXTYPE(im), lendata, 1)
+ nocp = nocp + 1
+ }
+ }
+
+ call imtclose (list)
+ call sfree (sp)
+ if (nocp == 0)
+ call error (1, "No images with column data in header.")
+ call tbtcre (otp)
+end
diff --git a/pkg/utilities/nttools/threed/titable.par b/pkg/utilities/nttools/threed/titable.par
new file mode 100644
index 00000000..41ae759a
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable.par
@@ -0,0 +1,7 @@
+intable,s,a,"",,,"Input tables"
+outtable,s,a,"",,,"Output table"
+template,s,h,"",,,"Template table"
+row,i,h,INDEF,,,"Begin insertion in row"
+verbose,b,h,yes,,,"Print operations performed ?"
+version,s,h,"7Feb2000",,,
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/threed/titable/design1.txt b/pkg/utilities/nttools/threed/titable/design1.txt
new file mode 100644
index 00000000..a4040192
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/design1.txt
@@ -0,0 +1,224 @@
+
+
+ Design of 3-D table insertion task
+ ----------------------------------
+
+
+ Author: I. Busko
+
+
+ Revision history:
+ 12/16/96 - First version.
+
+
+
+
+1. Specifications / requirements:
+
+This task will perform the inverse operation performed by task txtable.
+It will insert (in the tainsert task sense) one or more 2-D tables into
+rows of a 3-D table. Alternatively, it will create a 3-D table from the
+2-D input tables. Each column in the input 2-D table is inserted as an
+array into a single cell at the specified row in the output table.
+Additional scalar columns, stored in the headers of the input table by
+txtable, will also be processed.
+
+This design proposes a first, non-sophisticated version of the task. The
+emphasis is on simplicity rather than providing support for all possible
+situations. For instance, what to do if the size of a given column in one
+of the input tables is larger than the corresponding array size in an
+existing output table ? Throw away extra elements ? Resize output table ?
+But what rules to follow in order to fill back the now resized arrays ? This
+design will solve problems like these by resorting to the simplest (from the
+code viewpoint) solution (in this case, just ignore the extra elements).
+
+If the output table does not exist, the first input table in the list
+will define both the column information for the output table, as well as
+its maximum array size. Columns in the input and output table will be
+matched by column name. If a given column in an input table does not exist
+in a previously existing output table, it will be ignored.
+
+The task will be named "titable" following a former proposal for naming
+the 3-D table utilities.
+
+
+
+2. Language:
+
+SPP, to allow the use of the generic datatype compiling facility, and to
+reuse significant amounts of code already developed for txtable, tximage
+and tainsert.
+
+
+
+3. Task parameters:
+
+Name Type What
+
+input file list/template list of 2D table names with optional
+ row/column bracket selectors.
+output file name 3-D table name with no row/column selectors
+ (modified in place or created from scratch).
+row int row in output table where to begin insertion.
+
+
+
+4. Data structures:
+
+The main data structures are two pointer-type column descriptor arrays, in
+the sense defined by the tcs_ routines in the selector library. One array
+is associated with the output table, and the other array is associated
+with the current input table.
+
+The output table array is sized to store column information from both the
+actual columnar data in the input tables, as well as any scalar data
+stored in the input table headers by the txtable task. If the output table
+already exists, it will define the array size and contents completely.
+If it is being created by the task, the first input table in the list will
+define the size and content of the output descriptor array. Thus if other
+tables in the input list have additional columns (both physical or in the
+form of header-stored scalars), these additional columns will be ignored.
+
+
+
+5. Code structure:
+
+The listing below shows only the most important subroutines; lower-level
+functions such as decoding header keywords are not explicited.
+
+The first section deals with creating the main column descriptor array
+for the output table. If the table does not exist, column information
+must be read from the input table columns themselves AND from eventual
+scalar columns stored in the header by txtable.
+
+The second section scans the input list and performs the actual insertion
+operation. Again, a separate piece of code exists for the cases where a
+physical column exists in the input table, or an header-stored scalar
+instead. The innermost loop takes care of reading only the selected rows
+from the input table.
+
+- Read task parameters (clget).
+- Alloc work memory (malloc, calloc).
+- Strip output name from eventual bracket selectors (rdselect).
+- Open input list (imtopen).
+- If output table already exists (access).
+ **> Procedure TIUPDATE:
+ - Open output table (tbtopn).
+ - Create array of column pointers from output table (malloc, tcs_open).
+ **> End TIUPDATE.
+- Else
+ **> Procedure TINEW:
+ - Get first table name from input list (imtgetim).
+ - Check if it is a table (whatfile). Exit if not.
+ - Break name into bracketed selectors (rdselect).
+ - Open input table (tbtopn).
+ - Get its total (selected and unselected) number of rows (tbpsta).
+
+ - Scalars in input table are signaled by TCTOTAL keyword in input table
+ header. Look for it (tbhfkr) and increase number of output columns by
+ the value of TCTOTAL.
+
+ - Create array of column pointers from input column selector and TCTOTAL
+ info (malloc, tcs_open).
+ - If no columns were matched, and no TCTOTAL keyword was found, exit.
+ - Open output table (no STDOUT allowed) (tbtopn).
+ **> Procedure TISETC:
+ - Loop over input column pointer array, if it exists.
+ - Copy column information from input to output (tbcinf, tbcdef),
+ setting the output array size to be the input number of rows.
+ - End loop.
+ - Loop over all possible keyword sets (from 1 to TCTOTAL).
+ - Look for TCD_xxx keyword (tbhfkr).
+ - If found:
+ - Decode TCD keyword into column data (name, datatype, format)
+ - Create scalar column in output table's column array (tbcdef).
+ - End if.
+ - End loop.
+ **> End TISETC:
+ - Create output table (tbtcre).
+ - Close input table (tbtclo).
+ - Rewind input list (imtrew).
+ **> End TINEW:
+- End if.
+- Initialize row counter with "row" parameter value (clgeti). Set flag if row
+ parameter is negative or INDEF.
+**> Procedure TINSERT:
+ - Loop over input list (imtlen).
+ - Get table name (imtgetim).
+ - Check if it is a table (whatfile). Skip and warn user if not.
+ - Break name into bracketed selectors (rdselect).
+ - Open input table (tbtopn).
+ - Look for ORIG_ROW keyword (tbhfkr). If found, and if "row" parameter
+ is negative or INDEF, supersede row counter with keyword value.
+ - Find how many rows were requested by row selector (trsopen, trseval,
+ trsclose).
+ - Create array of column pointers from column selector. If no columns
+ were matched, exit (malloc, tcs_open).
+ **> Procedure TICOPY:
+ - Loop over output table column pointers.
+ - Get column info from output table (tcs_column, tbcinf)
+ - loop over input table column pointers.
+ - Get column info from input table (tcs_column, tbcinf)
+ - If column names match:
+ **> Procedure TICC:
+ - Get output array size (tcs_totsize).
+ - Choose the minimum in between this array size and the
+ number of rows selected from input table. If less rows
+ than array elements, warn user.
+ - Get data types of both input and output columns
+ (tcs_intinfo).
+ If character-type, get string size too.
+ **> Procedure TIROWS (generic data type):
+ - Alloc buffer of appropriate type and with size
+ given by the minimum size computed above (malloc).
+ - Copy selected rows from input table into buffer
+ (trsopen, trseval, tbcgt, trsclose).
+ - Copy buffer into designated row/column (tbapt).
+ - If output exists and array is larger than buffer:
+ - Set remaining elements to INDEF.
+ - End if.
+ - Free buffer (mfree).
+ **> End TIROWS.
+ **> End TICC.
+ - Else (no match), look for scalar data in input header:
+ **> Procedure TIHC:
+ - Look for TCTOTAL keyword (tbhfkr). If found:
+ - Loop over all possible keyword sets (from 1 to
+ TCTOTAL).
+ - Look for TCD_xxx keyword (tbhfkr).
+ - Decode TCD keyword to extract column name.
+ - If column name from header matches with output
+ column name:
+ - Look for TCV_xxx keyword (tbhfkr). If found:
+ **> Procedure TIWRSC (generic data type):
+ - Write scalar data (tbcpt).
+ **> End TIWRSC.
+ - Else
+ - Warn user that input table header is
+ corrupted.
+ - End if.
+ - End if.
+ - End loop.
+ - End if.
+ **> End TIHC.
+ - End if.
+ - End loop.
+ - End loop.
+ **> End TICOPY.
+ - Free input table's array of column pointers (tcs_close, mfree).
+ - Close input table (tbtclo).
+ - Bump output row counter.
+ - End loop.
+**> End TINSERT:
+- Free output table's array of column pointers (tcs_close, mfree).
+- Close output table (tbtclo).
+- Close input list (imtclose).
+- Free work memory (mfree).
+
+
+
+
+
+
+
+
diff --git a/pkg/utilities/nttools/threed/titable/design2.txt b/pkg/utilities/nttools/threed/titable/design2.txt
new file mode 100644
index 00000000..99ceb57f
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/design2.txt
@@ -0,0 +1,244 @@
+
+
+ Design of 3-D table insertion task
+ ----------------------------------
+
+
+ Author: I. Busko
+
+
+ Revision history:
+ 12/16/96 - First version.
+ 01/15/97 - Revised after design review.
+ 01/20/97 - Matches version 1.0 of code.
+
+ Revision content:
+ 01/20/97: (i) internal flow control of TICOPY routine; (ii) the two main
+ data structures now store "regular" column pointers (in the
+ tbtable sense) instead of column pointers in the tcs_ sense;
+ (iii) inclusion of a template table.
+
+
+
+1. Specifications / requirements:
+
+This task will perform the inverse operation performed by task txtable.
+It will insert (in the tainsert task sense) one or more 2-D tables into
+rows of a 3-D table. Alternatively, it will create a 3-D table from the
+2-D input tables. Each column in the input 2-D table is inserted as an
+array into a single cell at the specified row in the output table.
+Additional scalar columns, stored in the headers of the input table by
+txtable, will also be processed. Row/column selectors in the input table
+names will be supported.
+
+This design proposes a first, non-sophisticated version of the task. The
+emphasis is on simplicity rather than providing support for all possible
+situations. For instance, what to do if the size of a given column in one
+of the input tables is larger than the corresponding array size in an
+existing output table ? Throw away the extra elements ? Resize output table ?
+But what rules to follow in order to fill back the now resized arrays ? This
+design will solve problems like these by resorting to the simplest (from the
+code viewpoint) solution (in this case, just ignore the extra elements).
+
+If the output table does not exist, the first input table in the list
+will define both the column information for the output table, as well as
+its maximum array size. Columns in the input and output table will be
+matched by column name. If a given column in an input table does not exist
+in a previously existing output table, it will be ignored.
+
+From design review: an existing table can be used as a template when creating
+a new 3-D output table. If no template is supplied, the first table in the
+input list becomes the template.
+
+Because the selector mechanism does not work with scalars stored in the
+input tables' headers by task txtable, these scalars, if existent, will
+be always inserted in the output table, provided column names match.
+
+An error results when:
+- an array is found in a cell in any of the input tables,
+- datatypes in input and output columns do not agree.
+
+The task will be named "titable" following a former proposal for naming
+the 3-D table utilities.
+
+
+
+2. Language:
+
+SPP, to allow the use of the generic datatype compiling facility, and to
+reuse significant amounts of code already developed for txtable, tximage
+and tainsert.
+
+
+
+3. Task parameters:
+
+Name Type What
+
+input file list/template list of 2D table names with optional
+ row/column bracket selectors.
+output file name 3-D table name with no row/column selectors
+ (modified in place or created from scratch).
+template file name 3-D template table with column selectors
+row int row in output table where to begin insertion.
+
+
+
+4. Data structures:
+
+The main data structures are two pointer-type column descriptor arrays.
+One array is associated with the output table, and the other array is
+associated with the current input table.
+
+The output table array is sized to store column information from both the
+actual columnar data in the input tables, as well as any scalar data
+stored in the input table headers by the txtable task. If the output table
+already exists, it will define the array size and contents completely.
+If it is being created by the task, the first input table in the list will
+define the size and content of the output descriptor array. Thus if other
+tables in the input list have additional columns (both physical or in the
+form of header-stored scalars), these additional columns will be ignored.
+
+
+
+5. Code structure:
+
+The listing below shows only the most important subroutines; lower-level
+functions such as decoding header keywords are not explicited.
+
+The first section deals with creating the main column descriptor array
+for the output table. If the table does not exist, column information
+must be read from the input table columns themselves AND from eventual
+scalar columns stored in the header by txtable.
+
+The second section scans the input list and performs the actual insertion
+operation. Again, a separate piece of code exists for the cases where a
+physical column exists in the input table, or an header-stored scalar
+instead. The innermost loop takes care of reading only the selected rows
+from the input table.
+
+- Read task parameters (clget).
+- Alloc work memory (malloc, calloc).
+- Strip output name from eventual bracket selectors (rdselect).
+- Open input list (imtopen).
+- If output table already exists (access).
+ **> Procedure TIUPDATE:
+ - Open output table (tbtopn).
+ - Create array of column pointers from output table (malloc, tcs_open).
+ - Get column pointers from tcs structure.
+ **> End TIUPDATE.
+- Else
+ **> Procedure TINEW:
+ - If template table is not valid:
+ - Get first table name from input list (imtgetim).
+ - End if.
+ - Check if it is a table (whatfile). Exit if not.
+ - Break name into bracketed selectors (rdselect).
+ - Open template table (tbtopn).
+ - Get its total (selected and unselected) number of rows (tbpsta).
+ - Scalars in input table are signaled by TCTOTAL keyword in input table
+ header. Look for it (tbhfkr) and increase number of output columns.
+ - Create array of column pointers from input column selector and TCTOTAL
+ info (malloc, tcs_open).
+ - If no columns were matched, and no TCTOTAL keyword was found, exit.
+ - Open output table (no STDOUT allowed) (tbtopn).
+ **> Procedure TISETC:
+ - Loop over input column pointer array, if it exists.
+ - Copy column information from input to output (tbcinf, tbcdef),
+ setting the output array size to be the input number of rows
+ in the case of a 2-D template, or keeping it the same size
+ in the case of a 3-D template.
+ - End loop.
+ - Loop over all possible keyword sets (from 1 to TCTOTAL).
+ - Look for TCD_xxx keyword (tbhfkr).
+ - If found:
+ - Decode TCD keyword into column data (name, datatype, format)
+ - Create scalar column in output table's column array (tbcdef).
+ - End if.
+ - End loop.
+ **> End TISETC:
+ - Create output table (tbtcre).
+ - Close input table (tbtclo).
+ - Rewind input list (imtrew).
+ **> End TINEW:
+- End if.
+- Initialize row counter with "row" parameter value (clgeti). Set flag if row
+ parameter is negative or INDEF.
+**> Procedure TINSERT:
+ - Loop over input list (imtlen).
+ - Get table name (imtgetim).
+ - Check if it is a table (whatfile). Skip and warn user if not.
+ - Break name into bracketed selectors (rdselect).
+ - Open input table (tbtopn).
+ - Look for ORIG_ROW keyword (tbhfkr). If found, and if "row" parameter
+ is negative or INDEF, supersede row counter with keyword value.
+ - Find how many rows were requested by row selector (trsopen, trseval,
+ trsclose).
+ - Create array of column pointers from column selector (malloc,tcs_open).
+ **> Procedure TICOPY:
+ - Loop over output table column pointers.
+ - Get column info from output table (tbcinf)
+ - Choose the minimum in between this array size and the number
+ of rows selected from input table (tbalen).
+ - If there are matched columns, loop over input table column
+ pointers.
+ - Get column info from input table (tcs_column, tbcinf)
+ - If column names match:
+ - If data types do not match, abort.
+ **> Procedure TICC:
+ - If character-type, get string size.
+ given by the minimum size computed above (malloc).
+ **> Procedure TIROWS (generic data type):
+ - Alloc buffer of appropriate type and with size
+ - Copy selected rows from input table into buffer
+ (trsopen, trseval, tbcgt, trsclose).
+ - Copy buffer into designated row/column (tbapt).
+ - If output exists and array is larger than buffer:
+ - Set remaining elements to INDEF.
+ - End if.
+ **> End TIROWS.
+ **> End TICC.
+ - Else (no match), look for scalar data in input header:
+ - Look for TCTOTAL keyword (tbhfkr). If found:
+ - Loop over all possible keyword sets (from 1 to
+ TCTOTAL).
+ - Look for TCD_xxx keyword (tbhfkr).
+ - Decode TCD keyword to extract column name.
+ - If column name from header matches with output
+ column name:
+ **> Procedure TICH (generic datatype):
+ - Look for TCV_xxx keyword (tbhfkr). If found:
+ - Read value.
+ - Write scalar data (tbcpt).
+ - Else
+ - Warn user that input table header is
+ corrupted.
+ - End if.
+ **> End TICH.
+ - End if.
+ - End loop.
+ - End if.
+ - End if (Notice that a no-match case, both from columns and
+ header scalars, is not an error since the output or
+ template table may have columns that do not exist
+ among the selected columns in the input table).
+ - End loop.
+ - End loop.
+ **> End TICOPY.
+ - Free input table's array of column pointers (tcs_close, mfree).
+ - Close input table (tbtclo).
+ - Bump output row counter.
+ - End loop.
+**> End TINSERT:
+- Free output table's array of column pointers (tcs_close, mfree).
+- Close output table (tbtclo).
+- Close input list (imtclose).
+- Free work memory (mfree).
+
+
+
+
+
+
+
+
diff --git a/pkg/utilities/nttools/threed/titable/generic/mkpkg b/pkg/utilities/nttools/threed/titable/generic/mkpkg
new file mode 100644
index 00000000..f65f2f1c
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/generic/mkpkg
@@ -0,0 +1,22 @@
+# Update the generic routines.
+
+default:
+ $checkout libpkg.a ../../
+ $update libpkg.a
+ $checkin libpkg.a ../../
+$exit
+
+libpkg.a:
+ tirowsb.x <tbset.h>
+ tirowsc.x <tbset.h>
+ tirowsd.x <tbset.h>
+ tirowsi.x <tbset.h>
+ tirowsr.x <tbset.h>
+ tirowss.x <tbset.h>
+ tichb.x <tbset.h>
+ tichc.x <tbset.h>
+ tichd.x <tbset.h>
+ tichi.x <tbset.h>
+ tichr.x <tbset.h>
+ tichs.x <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/threed/titable/generic/tichb.x b/pkg/utilities/nttools/threed/titable/generic/tichb.x
new file mode 100644
index 00000000..895c6aab
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/generic/tichb.x
@@ -0,0 +1,52 @@
+include <tbset.h>
+
+# TICH -- Copy data from input header into scalar cell in output.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+
+
+procedure tichb (itp, ihc, otp, ocp, orow)
+
+pointer itp # i: input table descriptor
+int ihc # i: header keyword index
+pointer otp # i: output table descriptor
+pointer ocp # i: output column descriptor
+int orow # i: row where to insert
+#--
+bool buf
+pointer sp, kwname, kwval
+int datatype, parnum
+
+string corrupt "Corrupted header in input table."
+
+int nscan()
+
+begin
+ call smark (sp)
+ call salloc (kwname, SZ_LINE, TY_CHAR)
+ call salloc (kwval, SZ_PARREC, TY_CHAR)
+
+ # Build keyword name and look for it.
+ call sprintf (Memc[kwname], SZ_LINE, "TCV_%03d")
+ call pargi (ihc)
+ call tbhfkr (itp, Memc[kwname], datatype, Memc[kwval], parnum)
+
+ # Parse and read value. We assume that the keyword existence
+ # was confirmed by previously finding the paired TCD_ keyword.
+ if (parnum > 0) {
+ call sscan (Memc[kwval])
+ call gargb (buf)
+ if (nscan() < 1) call error (1, corrupt)
+ } else
+ call error (1, corrupt)
+
+ # Write value into scalar cell.
+ call tbcptb (otp, ocp, buf, orow, orow)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/threed/titable/generic/tichc.x b/pkg/utilities/nttools/threed/titable/generic/tichc.x
new file mode 100644
index 00000000..0685918e
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/generic/tichc.x
@@ -0,0 +1,54 @@
+include <tbset.h>
+
+# TICH -- Copy data from input header into scalar cell in output.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+
+
+procedure ticht (itp, ihc, otp, ocp, orow, maxch)
+
+pointer itp # i: input table descriptor
+int ihc # i: header keyword index
+pointer otp # i: output table descriptor
+pointer ocp # i: output column descriptor
+int orow # i: row where to insert
+int maxch
+#--
+pointer buf
+pointer sp, kwname, kwval
+int datatype, parnum
+
+string corrupt "Corrupted header in input table."
+
+int nscan()
+
+begin
+ call smark (sp)
+ call salloc (buf, maxch + 1, TY_CHAR)
+ call salloc (kwname, SZ_LINE, TY_CHAR)
+ call salloc (kwval, SZ_PARREC, TY_CHAR)
+
+ # Build keyword name and look for it.
+ call sprintf (Memc[kwname], SZ_LINE, "TCV_%03d")
+ call pargi (ihc)
+ call tbhfkr (itp, Memc[kwname], datatype, Memc[kwval], parnum)
+
+ # Parse and read value. We assume that the keyword existence
+ # was confirmed by previously finding the paired TCD_ keyword.
+ if (parnum > 0) {
+ call sscan (Memc[kwval])
+ call gargwrd (buf, maxch)
+ if (nscan() < 1) call error (1, corrupt)
+ } else
+ call error (1, corrupt)
+
+ # Write value into scalar cell.
+ call tbcptt (otp, ocp, buf, maxch, orow, orow)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/threed/titable/generic/tichd.x b/pkg/utilities/nttools/threed/titable/generic/tichd.x
new file mode 100644
index 00000000..331b9813
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/generic/tichd.x
@@ -0,0 +1,52 @@
+include <tbset.h>
+
+# TICH -- Copy data from input header into scalar cell in output.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+
+
+procedure tichd (itp, ihc, otp, ocp, orow)
+
+pointer itp # i: input table descriptor
+int ihc # i: header keyword index
+pointer otp # i: output table descriptor
+pointer ocp # i: output column descriptor
+int orow # i: row where to insert
+#--
+double buf
+pointer sp, kwname, kwval
+int datatype, parnum
+
+string corrupt "Corrupted header in input table."
+
+int nscan()
+
+begin
+ call smark (sp)
+ call salloc (kwname, SZ_LINE, TY_CHAR)
+ call salloc (kwval, SZ_PARREC, TY_CHAR)
+
+ # Build keyword name and look for it.
+ call sprintf (Memc[kwname], SZ_LINE, "TCV_%03d")
+ call pargi (ihc)
+ call tbhfkr (itp, Memc[kwname], datatype, Memc[kwval], parnum)
+
+ # Parse and read value. We assume that the keyword existence
+ # was confirmed by previously finding the paired TCD_ keyword.
+ if (parnum > 0) {
+ call sscan (Memc[kwval])
+ call gargd (buf)
+ if (nscan() < 1) call error (1, corrupt)
+ } else
+ call error (1, corrupt)
+
+ # Write value into scalar cell.
+ call tbcptd (otp, ocp, buf, orow, orow)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/threed/titable/generic/tichi.x b/pkg/utilities/nttools/threed/titable/generic/tichi.x
new file mode 100644
index 00000000..fe01a4ac
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/generic/tichi.x
@@ -0,0 +1,52 @@
+include <tbset.h>
+
+# TICH -- Copy data from input header into scalar cell in output.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+
+
+procedure tichi (itp, ihc, otp, ocp, orow)
+
+pointer itp # i: input table descriptor
+int ihc # i: header keyword index
+pointer otp # i: output table descriptor
+pointer ocp # i: output column descriptor
+int orow # i: row where to insert
+#--
+int buf
+pointer sp, kwname, kwval
+int datatype, parnum
+
+string corrupt "Corrupted header in input table."
+
+int nscan()
+
+begin
+ call smark (sp)
+ call salloc (kwname, SZ_LINE, TY_CHAR)
+ call salloc (kwval, SZ_PARREC, TY_CHAR)
+
+ # Build keyword name and look for it.
+ call sprintf (Memc[kwname], SZ_LINE, "TCV_%03d")
+ call pargi (ihc)
+ call tbhfkr (itp, Memc[kwname], datatype, Memc[kwval], parnum)
+
+ # Parse and read value. We assume that the keyword existence
+ # was confirmed by previously finding the paired TCD_ keyword.
+ if (parnum > 0) {
+ call sscan (Memc[kwval])
+ call gargi (buf)
+ if (nscan() < 1) call error (1, corrupt)
+ } else
+ call error (1, corrupt)
+
+ # Write value into scalar cell.
+ call tbcpti (otp, ocp, buf, orow, orow)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/threed/titable/generic/tichr.x b/pkg/utilities/nttools/threed/titable/generic/tichr.x
new file mode 100644
index 00000000..b81dd97b
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/generic/tichr.x
@@ -0,0 +1,52 @@
+include <tbset.h>
+
+# TICH -- Copy data from input header into scalar cell in output.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+
+
+procedure tichr (itp, ihc, otp, ocp, orow)
+
+pointer itp # i: input table descriptor
+int ihc # i: header keyword index
+pointer otp # i: output table descriptor
+pointer ocp # i: output column descriptor
+int orow # i: row where to insert
+#--
+real buf
+pointer sp, kwname, kwval
+int datatype, parnum
+
+string corrupt "Corrupted header in input table."
+
+int nscan()
+
+begin
+ call smark (sp)
+ call salloc (kwname, SZ_LINE, TY_CHAR)
+ call salloc (kwval, SZ_PARREC, TY_CHAR)
+
+ # Build keyword name and look for it.
+ call sprintf (Memc[kwname], SZ_LINE, "TCV_%03d")
+ call pargi (ihc)
+ call tbhfkr (itp, Memc[kwname], datatype, Memc[kwval], parnum)
+
+ # Parse and read value. We assume that the keyword existence
+ # was confirmed by previously finding the paired TCD_ keyword.
+ if (parnum > 0) {
+ call sscan (Memc[kwval])
+ call gargr (buf)
+ if (nscan() < 1) call error (1, corrupt)
+ } else
+ call error (1, corrupt)
+
+ # Write value into scalar cell.
+ call tbcptr (otp, ocp, buf, orow, orow)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/threed/titable/generic/tichs.x b/pkg/utilities/nttools/threed/titable/generic/tichs.x
new file mode 100644
index 00000000..5dbce604
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/generic/tichs.x
@@ -0,0 +1,52 @@
+include <tbset.h>
+
+# TICH -- Copy data from input header into scalar cell in output.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+
+
+procedure tichs (itp, ihc, otp, ocp, orow)
+
+pointer itp # i: input table descriptor
+int ihc # i: header keyword index
+pointer otp # i: output table descriptor
+pointer ocp # i: output column descriptor
+int orow # i: row where to insert
+#--
+short buf
+pointer sp, kwname, kwval
+int datatype, parnum
+
+string corrupt "Corrupted header in input table."
+
+int nscan()
+
+begin
+ call smark (sp)
+ call salloc (kwname, SZ_LINE, TY_CHAR)
+ call salloc (kwval, SZ_PARREC, TY_CHAR)
+
+ # Build keyword name and look for it.
+ call sprintf (Memc[kwname], SZ_LINE, "TCV_%03d")
+ call pargi (ihc)
+ call tbhfkr (itp, Memc[kwname], datatype, Memc[kwval], parnum)
+
+ # Parse and read value. We assume that the keyword existence
+ # was confirmed by previously finding the paired TCD_ keyword.
+ if (parnum > 0) {
+ call sscan (Memc[kwval])
+ call gargs (buf)
+ if (nscan() < 1) call error (1, corrupt)
+ } else
+ call error (1, corrupt)
+
+ # Write value into scalar cell.
+ call tbcpts (otp, ocp, buf, orow, orow)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/threed/titable/generic/tirowsb.x b/pkg/utilities/nttools/threed/titable/generic/tirowsb.x
new file mode 100644
index 00000000..f87a0861
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/generic/tirowsb.x
@@ -0,0 +1,71 @@
+include <tbset.h>
+
+#
+# TIROWS -- Expand row selector into array and copy it into output
+# table cell.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-1997 - Task created (I.Busko)
+# 7-Feb-2000 - For datatype = 'c', make buf an array of strings (P.Hodge)
+
+
+procedure tirowsb (itp, icp, otp, ocp, rowsel, orow, len, buf)
+
+pointer itp # i: input table descriptor
+pointer icp # i: input column descriptor
+pointer otp # i: output table descriptor
+pointer ocp # i: output column descriptor
+char rowsel[ARB] # i: row selector
+int orow # i: row in output table where to write into
+int len # i: buffer length
+bool buf[ARB]
+#--
+double undefd
+real undefr
+pointer pcode
+int undefi, i, nelem, irow, numrow, alength
+short undefs
+
+pointer trsopen()
+int tbpsta(), tbalen()
+bool trseval()
+
+begin
+ # Loop over selected rows on input table.
+ pcode = trsopen (itp, rowsel)
+ numrow = tbpsta (itp, TBL_NROWS)
+ nelem = 0
+ do irow = 1, numrow {
+ if (trseval (itp, irow, pcode)) {
+ nelem = nelem + 1
+ if (nelem > len) {
+ nelem = len
+ break
+ }
+ # Get element and store in buffer.
+ call tbegtb (itp, icp, irow, buf[nelem])
+ }
+ }
+ call trsclose (pcode)
+
+ # Write buffer into array cell element.
+ call tbaptb (otp, ocp, orow, buf, 1, nelem)
+
+ # If number of selected rows in current input table
+ # is smaller than output table array length, fill
+ # remaining array elements with INDEF.
+ alength = tbalen (ocp)
+ if (alength > nelem) {
+ undefd = INDEFD
+ undefr = INDEFR
+ undefi = INDEFI
+ undefs = INDEFS
+ do i = nelem+1, alength {
+ call tbaptb (otp, ocp, orow, false, i, 1)
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/threed/titable/generic/tirowsc.x b/pkg/utilities/nttools/threed/titable/generic/tirowsc.x
new file mode 100644
index 00000000..01d11000
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/generic/tirowsc.x
@@ -0,0 +1,72 @@
+include <tbset.h>
+
+#
+# TIROWS -- Expand row selector into array and copy it into output
+# table cell.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-1997 - Task created (I.Busko)
+# 7-Feb-2000 - For datatype = 'c', make buf an array of strings (P.Hodge)
+
+
+procedure tirowst (itp, icp, otp, ocp, rowsel, orow, maxch, len, buf)
+
+pointer itp # i: input table descriptor
+pointer icp # i: input column descriptor
+pointer otp # i: output table descriptor
+pointer ocp # i: output column descriptor
+char rowsel[ARB] # i: row selector
+int orow # i: row in output table where to write into
+int maxch # i: max length of string
+int len # i: buffer length
+char buf[maxch,ARB] # i: work buffer
+#--
+double undefd
+real undefr
+pointer pcode
+int undefi, i, nelem, irow, numrow, alength
+short undefs
+
+pointer trsopen()
+int tbpsta(), tbalen()
+bool trseval()
+
+begin
+ # Loop over selected rows on input table.
+ pcode = trsopen (itp, rowsel)
+ numrow = tbpsta (itp, TBL_NROWS)
+ nelem = 0
+ do irow = 1, numrow {
+ if (trseval (itp, irow, pcode)) {
+ nelem = nelem + 1
+ if (nelem > len) {
+ nelem = len
+ break
+ }
+ # Get element and store in buffer.
+ call tbegtt (itp, icp, irow, buf[1,nelem], maxch)
+ }
+ }
+ call trsclose (pcode)
+
+ # Write buffer into array cell element.
+ call tbaptt (otp, ocp, orow, buf, maxch, 1, nelem)
+
+ # If number of selected rows in current input table
+ # is smaller than output table array length, fill
+ # remaining array elements with INDEF.
+ alength = tbalen (ocp)
+ if (alength > nelem) {
+ undefd = INDEFD
+ undefr = INDEFR
+ undefi = INDEFI
+ undefs = INDEFS
+ do i = nelem+1, alength {
+ call tbaptt (otp, ocp, orow, "", maxch, i, 1)
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/threed/titable/generic/tirowsd.x b/pkg/utilities/nttools/threed/titable/generic/tirowsd.x
new file mode 100644
index 00000000..3af5468c
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/generic/tirowsd.x
@@ -0,0 +1,71 @@
+include <tbset.h>
+
+#
+# TIROWS -- Expand row selector into array and copy it into output
+# table cell.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-1997 - Task created (I.Busko)
+# 7-Feb-2000 - For datatype = 'c', make buf an array of strings (P.Hodge)
+
+
+procedure tirowsd (itp, icp, otp, ocp, rowsel, orow, len, buf)
+
+pointer itp # i: input table descriptor
+pointer icp # i: input column descriptor
+pointer otp # i: output table descriptor
+pointer ocp # i: output column descriptor
+char rowsel[ARB] # i: row selector
+int orow # i: row in output table where to write into
+int len # i: buffer length
+double buf[ARB]
+#--
+double undefd
+real undefr
+pointer pcode
+int undefi, i, nelem, irow, numrow, alength
+short undefs
+
+pointer trsopen()
+int tbpsta(), tbalen()
+bool trseval()
+
+begin
+ # Loop over selected rows on input table.
+ pcode = trsopen (itp, rowsel)
+ numrow = tbpsta (itp, TBL_NROWS)
+ nelem = 0
+ do irow = 1, numrow {
+ if (trseval (itp, irow, pcode)) {
+ nelem = nelem + 1
+ if (nelem > len) {
+ nelem = len
+ break
+ }
+ # Get element and store in buffer.
+ call tbegtd (itp, icp, irow, buf[nelem])
+ }
+ }
+ call trsclose (pcode)
+
+ # Write buffer into array cell element.
+ call tbaptd (otp, ocp, orow, buf, 1, nelem)
+
+ # If number of selected rows in current input table
+ # is smaller than output table array length, fill
+ # remaining array elements with INDEF.
+ alength = tbalen (ocp)
+ if (alength > nelem) {
+ undefd = INDEFD
+ undefr = INDEFR
+ undefi = INDEFI
+ undefs = INDEFS
+ do i = nelem+1, alength {
+ call tbaptd (otp, ocp, orow, undefd, i, 1)
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/threed/titable/generic/tirowsi.x b/pkg/utilities/nttools/threed/titable/generic/tirowsi.x
new file mode 100644
index 00000000..6cf4b069
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/generic/tirowsi.x
@@ -0,0 +1,71 @@
+include <tbset.h>
+
+#
+# TIROWS -- Expand row selector into array and copy it into output
+# table cell.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-1997 - Task created (I.Busko)
+# 7-Feb-2000 - For datatype = 'c', make buf an array of strings (P.Hodge)
+
+
+procedure tirowsi (itp, icp, otp, ocp, rowsel, orow, len, buf)
+
+pointer itp # i: input table descriptor
+pointer icp # i: input column descriptor
+pointer otp # i: output table descriptor
+pointer ocp # i: output column descriptor
+char rowsel[ARB] # i: row selector
+int orow # i: row in output table where to write into
+int len # i: buffer length
+int buf[ARB]
+#--
+double undefd
+real undefr
+pointer pcode
+int undefi, i, nelem, irow, numrow, alength
+short undefs
+
+pointer trsopen()
+int tbpsta(), tbalen()
+bool trseval()
+
+begin
+ # Loop over selected rows on input table.
+ pcode = trsopen (itp, rowsel)
+ numrow = tbpsta (itp, TBL_NROWS)
+ nelem = 0
+ do irow = 1, numrow {
+ if (trseval (itp, irow, pcode)) {
+ nelem = nelem + 1
+ if (nelem > len) {
+ nelem = len
+ break
+ }
+ # Get element and store in buffer.
+ call tbegti (itp, icp, irow, buf[nelem])
+ }
+ }
+ call trsclose (pcode)
+
+ # Write buffer into array cell element.
+ call tbapti (otp, ocp, orow, buf, 1, nelem)
+
+ # If number of selected rows in current input table
+ # is smaller than output table array length, fill
+ # remaining array elements with INDEF.
+ alength = tbalen (ocp)
+ if (alength > nelem) {
+ undefd = INDEFD
+ undefr = INDEFR
+ undefi = INDEFI
+ undefs = INDEFS
+ do i = nelem+1, alength {
+ call tbapti (otp, ocp, orow, undefi, i, 1)
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/threed/titable/generic/tirowsr.x b/pkg/utilities/nttools/threed/titable/generic/tirowsr.x
new file mode 100644
index 00000000..c6754eaf
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/generic/tirowsr.x
@@ -0,0 +1,71 @@
+include <tbset.h>
+
+#
+# TIROWS -- Expand row selector into array and copy it into output
+# table cell.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-1997 - Task created (I.Busko)
+# 7-Feb-2000 - For datatype = 'c', make buf an array of strings (P.Hodge)
+
+
+procedure tirowsr (itp, icp, otp, ocp, rowsel, orow, len, buf)
+
+pointer itp # i: input table descriptor
+pointer icp # i: input column descriptor
+pointer otp # i: output table descriptor
+pointer ocp # i: output column descriptor
+char rowsel[ARB] # i: row selector
+int orow # i: row in output table where to write into
+int len # i: buffer length
+real buf[ARB]
+#--
+double undefd
+real undefr
+pointer pcode
+int undefi, i, nelem, irow, numrow, alength
+short undefs
+
+pointer trsopen()
+int tbpsta(), tbalen()
+bool trseval()
+
+begin
+ # Loop over selected rows on input table.
+ pcode = trsopen (itp, rowsel)
+ numrow = tbpsta (itp, TBL_NROWS)
+ nelem = 0
+ do irow = 1, numrow {
+ if (trseval (itp, irow, pcode)) {
+ nelem = nelem + 1
+ if (nelem > len) {
+ nelem = len
+ break
+ }
+ # Get element and store in buffer.
+ call tbegtr (itp, icp, irow, buf[nelem])
+ }
+ }
+ call trsclose (pcode)
+
+ # Write buffer into array cell element.
+ call tbaptr (otp, ocp, orow, buf, 1, nelem)
+
+ # If number of selected rows in current input table
+ # is smaller than output table array length, fill
+ # remaining array elements with INDEF.
+ alength = tbalen (ocp)
+ if (alength > nelem) {
+ undefd = INDEFD
+ undefr = INDEFR
+ undefi = INDEFI
+ undefs = INDEFS
+ do i = nelem+1, alength {
+ call tbaptr (otp, ocp, orow, undefr, i, 1)
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/threed/titable/generic/tirowss.x b/pkg/utilities/nttools/threed/titable/generic/tirowss.x
new file mode 100644
index 00000000..91c678c3
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/generic/tirowss.x
@@ -0,0 +1,71 @@
+include <tbset.h>
+
+#
+# TIROWS -- Expand row selector into array and copy it into output
+# table cell.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-1997 - Task created (I.Busko)
+# 7-Feb-2000 - For datatype = 'c', make buf an array of strings (P.Hodge)
+
+
+procedure tirowss (itp, icp, otp, ocp, rowsel, orow, len, buf)
+
+pointer itp # i: input table descriptor
+pointer icp # i: input column descriptor
+pointer otp # i: output table descriptor
+pointer ocp # i: output column descriptor
+char rowsel[ARB] # i: row selector
+int orow # i: row in output table where to write into
+int len # i: buffer length
+short buf[ARB]
+#--
+double undefd
+real undefr
+pointer pcode
+int undefi, i, nelem, irow, numrow, alength
+short undefs
+
+pointer trsopen()
+int tbpsta(), tbalen()
+bool trseval()
+
+begin
+ # Loop over selected rows on input table.
+ pcode = trsopen (itp, rowsel)
+ numrow = tbpsta (itp, TBL_NROWS)
+ nelem = 0
+ do irow = 1, numrow {
+ if (trseval (itp, irow, pcode)) {
+ nelem = nelem + 1
+ if (nelem > len) {
+ nelem = len
+ break
+ }
+ # Get element and store in buffer.
+ call tbegts (itp, icp, irow, buf[nelem])
+ }
+ }
+ call trsclose (pcode)
+
+ # Write buffer into array cell element.
+ call tbapts (otp, ocp, orow, buf, 1, nelem)
+
+ # If number of selected rows in current input table
+ # is smaller than output table array length, fill
+ # remaining array elements with INDEF.
+ alength = tbalen (ocp)
+ if (alength > nelem) {
+ undefd = INDEFD
+ undefr = INDEFR
+ undefi = INDEFI
+ undefs = INDEFS
+ do i = nelem+1, alength {
+ call tbapts (otp, ocp, orow, undefs, i, 1)
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/threed/titable/help.txt b/pkg/utilities/nttools/threed/titable/help.txt
new file mode 100644
index 00000000..77289bc5
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/help.txt
@@ -0,0 +1,117 @@
+TITABLE (Jan97) threed TITABLE (Jan97)
+
+
+
+NAME
+ titable -- Inserts 2-D tables into rows of a 3-D table.
+
+
+USAGE
+ titable intable outtable
+
+
+DESCRIPTION
+ This task performs the inverse operation of task txtable: it
+ inserts one or more 2-D tables into rows of a 3-D table The input
+ may be a filename template, including wildcard characters, or the
+ name of a file (preceded by an @ sign) containing table names. The
+ output is a single 3-D table name. If the output table exists,
+ insertion will be done in place. If the output table does not
+ exist, it will be created. The input and output tables must not be
+ the same.
+
+ This task supports row/column selectors in the input table names.
+ These may be used to select subsets of both rows and columns from
+ the input table. If no selectors are used, all columns and rows
+ will be processed, Type 'help selectors' to see a description of
+ the selector syntax.
+
+ When creating a new output table, the information describing its
+ columns can be taken from two sources. If parameter 'template' has
+ the name of an existing 3-D table, the column descriptions,
+ including maximum array sizes, will be taken from that table. If
+ 'template' has an invalid or null ("") value, the column-defining
+ information will be take from the first table in the input list,
+ where its number of rows will define the maximum array size allowed
+ in the table being created. Column selectors are allowed in the
+ template table.
+
+ NOTE: Both the output and template table names must always be
+ supplied complete, including their extension. Otherwise the task
+ may get confused on the existence of an already existing table.
+
+ Insertion is performed by first verifying if column names in both
+ input and output tables match. If a match is found, values taken
+ from that column and all selected rows from the input table will be
+ stored as a 1-dimensional array in a single cell in the
+ corresponding column in the output 3-D table. The row in this
+ table where the insertion takes place is selected by the "row" task
+ parameter. It points to the row where the first table in the input
+ list will be inserted, subsequent tables in the list will be
+ inserted into subsequent rows. This mechanism is superseded if the
+ "row" parameter is set to INDEF or a negative value, and the
+ keyword "ORIG_ROW" is found in the header of the input table. This
+ keyword is created by task txtable and its value supersedes the row
+ counter in the task.
+ If the maximum array size in a target column in the output 3-D
+ table is larger than the number of selected input rows, the array
+ will be filled up starting from its first element, and the empty
+ elements at the end will be set to INDEF (or "" if it is a
+ character string column). If the maximum array size is smaller than
+ the number of selected rows, insertion begins by the first selected
+ row up to the maximum allowable size, the remaining rows being
+ ignored.
+
+ This task correctly handles scalars stored in the input table header
+ by task txtable. Since the selector mechanism does not work with
+ these scalars, the task will always insert them into the output
+ table, provided there is a match in column names.
+
+
+PARAMETERS
+
+ intable [file name list/template]
+ A list of one or more tables to be inserted. Row/column
+ selectors are supported.
+
+ outtable [table name]
+ Name of 3-D output table, including extension. No support
+ exists for "STDOUT" (ASCII output).
+
+ (template = "") [table name]
+ Name of 3-D table to be used as template when creating a new
+ output table.
+
+ (row = INDEF) [int]
+ Row where insertion begins. If set to INDEF or a negative
+ value, the row number will be looked for in the input table
+ header.
+
+ (verbose = yes) [boolean]
+ Display names of input and output tables as files are processed
+ ?
+
+
+EXAMPLES
+ Insert columns named FLUX and WAVELENGTH from input tables into a
+ 3-D table:
+
+ cl> titable itable*.tab[c:FLUX,WAVELENGTH] otable.tab
+
+
+
+BUGS
+ The output and template table names must be supplied in full,
+ including the extension (e.g. ".tab"). If the output table name is
+ not typed in full, the task will create a new table in place of the
+ existing one, with only the rows actually inserted. This behavior
+ relates to the way the underlying "access" routine in IRAF's fio
+ library works.
+
+
+REFERENCES
+ This task was written by I. Busko.
+
+
+SEE ALSO
+ txtable, selectors
diff --git a/pkg/utilities/nttools/threed/titable/list.tex b/pkg/utilities/nttools/threed/titable/list.tex
new file mode 100644
index 00000000..4b78ed5d
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/list.tex
@@ -0,0 +1,979 @@
+\documentstyle{article}
+\topmargin -30mm
+\textheight 250mm
+\oddsidemargin -5mm
+\evensidemargin -5mm
+\textwidth 170mm
+
+\begin{document}
+
+\tableofcontents
+
+\newpage
+
+\addcontentsline{toc}{section}{help.txt}
+\begin{verbatim}
+
+TITABLE (Jan97) threed TITABLE (Jan97)
+
+
+
+NAME
+ titable -- Inserts 2-D tables into rows of a 3-D table.
+
+
+USAGE
+ titable intable outtable
+
+
+DESCRIPTION
+ This task performs the inverse operation of task txtable: it
+ inserts one or more 2-D tables into rows of a 3-D table The input
+ may be a filename template, including wildcard characters, or the
+ name of a file (preceded by an @ sign) containing table names. The
+ output is a single 3-D table name. If the output table exists,
+ insertion will be done in place. If the output table does not
+ exist, it will be created. The input and output tables must not be
+ the same.
+
+ This task supports row/column selectors in the input table names.
+ These may be used to select subsets of both rows and columns from
+ the input table. If no selectors are used, all columns and rows
+ will be processed, Type 'help selectors' to see a description of
+ the selector syntax.
+
+ When creating a new output table, the information describing its
+ columns can be taken from two sources. If parameter 'template' has
+ the name of an existing 3-D table, the column descriptions,
+ including maximum array sizes, will be taken from that table. If
+ 'template' has an invalid or null ("") value, the column-defining
+ information will be take from the first table in the input list,
+ where its number of rows will define the maximum array size allowed
+ in the table being created. Column selectors are allowed in the
+ template table.
+
+ NOTE: Both the output and template table names must always be
+ supplied complete, including their extension. Otherwise the task
+ may get confused on the existence of an already existing table.
+
+ Insertion is performed by first verifying if column names in both
+ input and output tables match. If a match is found, values taken
+ from that column and all selected rows from the input table will be
+ stored as a 1-dimensional array in a single cell in the
+ corresponding column in the output 3-D table. The row in this
+ table where the insertion takes place is selected by the "row" task
+ parameter. It points to the row where the first table in the input
+ list will be inserted, subsequent tables in the list will be
+ inserted into subsequent rows. This mechanism is superseded if the
+ "row" parameter is set to INDEF or a negative value, and the
+ keyword "ORIG_ROW" is found in the header of the input table. This
+ keyword is created by task txtable and its value supersedes the row
+ counter in the task.
+ If the maximum array size in a target column in the output 3-D
+ table is larger than the number of selected input rows, the array
+ will be filled up starting from its first element, and the empty
+ elements at the end will be set to INDEF (or "" if it is a
+ character string column). If the maximum array size is smaller than
+ the number of selected rows, insertion begins by the first selected
+ row up to the maximum allowable size, the remaining rows being
+ ignored.
+
+ This task correctly handles scalars stored in the input table header
+ by task txtable. Since the selector mechanism does not work with
+ these scalars, the task will always insert them into the output
+ table, provided there is a match in column names.
+
+
+PARAMETERS
+
+ intable [file name list/template]
+ A list of one or more tables to be inserted. Row/column
+ selectors are supported.
+
+ outtable [table name]
+ Name of 3-D output table, including extension. No support
+ exists for "STDOUT" (ASCII output).
+
+ (template = "") [table name]
+ Name of 3-D table to be used as template when creating a new
+ output table.
+
+ (row = INDEF) [int]
+ Row where insertion begins. If set to INDEF or a negative
+ value, the row number will be looked for in the input table
+ header.
+
+ (verbose = yes) [boolean]
+ Display names of input and output tables as files are processed
+ ?
+
+
+EXAMPLES
+ Insert columns named FLUX and WAVELENGTH from input tables into a
+ 3-D table:
+
+ cl> titable itable*.tab[c:FLUX,WAVELENGTH] otable.tab
+
+
+
+BUGS
+ The output and template table names must be supplied in full,
+ including the extension (e.g. ".tab"). If the output table name is
+ not typed in full, the task will create a new table in place of the
+ existing one, with only the rows actually inserted. This behavior
+ relates to the way the underlying "access" routine in IRAF's fio
+ library works.
+
+
+REFERENCES
+ This task was written by I. Busko.
+
+
+SEE ALSO
+ txtable, selectors
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{loc.txt}
+\begin{verbatim}
+
+Filename Total Blanks Comments Help Execute Nonexec
+============================================================================
+ titable.x 81 18 16 0 23 24
+ tiupdate.x 42 13 11 0 7 11
+ tinew.x 96 24 21 0 30 21
+ tinsert.x 104 23 17 0 41 23
+ tisetc.x 70 17 14 0 20 19
+ ticopy.x 107 23 16 0 45 23
+ ticc.x 53 11 7 0 22 13
+ tiheader.x 189 57 27 0 62 43
+TOTAL 742 186 129 0 250 177
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{titable.x}
+\begin{verbatim}
+
+include <tbset.h>
+
+# TITABLE -- Insert 2D tables into 3D table rows.
+#
+# Input tables are given by a filename template list. All row/column
+# selection on input tables is performed by bracket-enclosed selectors
+# appended to the file name. The output is a 3-D table with no row/column
+# selectors.
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+
+
+procedure t_titable()
+
+char tablist[SZ_LINE] # Input table list
+char output[SZ_PATHNAME] # Output table name
+char template[SZ_PATHNAME] # Template table name
+int row # Row where to begin insertion
+bool verbose # Print operations ?
+#--
+char root[SZ_FNAME]
+char rowselect[SZ_FNAME]
+char colselect[SZ_FNAME]
+char colname[SZ_COLNAME]
+char colunits[SZ_COLUNITS]
+char colfmt[SZ_COLFMT]
+pointer cpo
+pointer otp, list
+int ncpo, rowc
+bool rflag
+
+string nocols "Column name not found (%s)"
+string nofile "Input file is not a table (%s)"
+
+pointer imtopen()
+int clgeti(), access()
+bool clgetb(), streq()
+
+begin
+ # Get task parameters.
+
+ call clgstr ("intable", tablist, SZ_LINE)
+ call clgstr ("outtable", output, SZ_PATHNAME)
+ call clgstr ("template", template, SZ_PATHNAME)
+ row = clgeti ("row")
+ verbose = clgetb ("verbose")
+
+ # Abort if invalid output name..
+ if (streq (output, "STDOUT"))
+ call error (1, "Invalid output file name.")
+ call rdselect (output, root, rowselect, colselect, SZ_FNAME)
+ if (rowselect[1] != EOS || colselect[1] != EOS)
+ call error (1, "Sections not permitted on output table name.")
+
+ # Open input list.
+ list = imtopen (tablist)
+
+ # Open/create the output table.
+ if (access (output, READ_WRITE, 0) == YES)
+ call tiupdate (root, otp, cpo, ncpo)
+ else
+ call tinew (template, list, root, rowselect, colselect, colname,
+ colunits, colfmt, otp, cpo, ncpo)
+
+ # Initialize row counter.
+ rowc = row
+ rflag = false
+ if (rowc <= 0 || IS_INDEF(rowc)) rflag = true
+
+ # Do the insertion.
+ call tinsert (list, output, otp, cpo, ncpo, rowc, rflag, verbose,
+ rowselect, colselect, colname, colunits, colfmt)
+
+ # Cleanup. The cpo array was allocated by tiupdate/tinew.
+ call tcs_close (Memi[cpo], ncpo)
+ call mfree (cpo, TY_INT)
+ call tbtclo (otp)
+ call imtclose (list)
+end
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{tiupdate.x}
+\begin{verbatim}
+
+include <tbset.h>
+
+# TIUPDATE -- Opens an already existing output table for update.
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+
+
+procedure tiupdate (output, otp, cpo, ncpo)
+
+char output[ARB] # i: table name
+pointer otp # o: table descriptor
+pointer cpo # o: column descriptor
+int ncpo # o: number of columns
+#--
+int i, dummy
+
+errchk tbtopn
+
+pointer tbtopn(), tcs_column()
+int tbpsta()
+
+begin
+ # Open table and get its size.
+ otp = tbtopn (output, READ_WRITE, NULL)
+ ncpo = tbpsta (otp, TBL_NCOLS)
+
+ # Alloc column descriptor array. This
+ # must be freed by caller.
+ call malloc (cpo, ncpo, TY_INT)
+
+ # Fill array with column info. The empty string
+ # forces the opening of all columns.
+ call tcs_open (otp, "", Memi[cpo], dummy, ncpo)
+
+ # Get column pointers from tcs structure.
+ do i = 1, ncpo
+ Memi[cpo+i-1] = tcs_column (Memi[cpo+i-1])
+end
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{tinew.x}
+\begin{verbatim}
+
+include <tbset.h>
+include "../whatfile.h"
+
+# TINEW -- Opens and creates a new output table.
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+
+
+procedure tinew (template, list, output, rowsel, colsel, colname, colunits,
+ colfmt, otp, cpo, ncpo)
+
+char template[ARB] # i: template table name
+pointer list # i: input list
+char output[ARB] # i: output table name
+char rowsel[ARB] # i: work array for row selectors
+char colsel[ARB] # i: work array for column selectors
+char colname[ARB] # i: work array for column names
+char colunits[ARB] # i: work array for column units
+char colfmt[ARB] # i: work array for column format
+pointer otp # o: table descriptor
+pointer cpo # o: column descriptor
+int ncpo # o: number of columns
+#--
+pointer sp, itp, newcpo, root
+int nrows, ncols, nscalar
+bool is_temp
+
+errchk tbtopen, tisetc
+
+pointer tbtopn()
+int tbpsta(), whatfile(), imtgetim(), tihnsc(), access()
+
+begin
+ call smark (sp)
+ call salloc (root, SZ_PATHNAME, TY_CHAR)
+
+ # See if there is a template table.
+ is_temp = true
+ if (access (template, READ_ONLY, 0) == NO) {
+
+ # Get first table in input list as the template.
+ if (imtgetim (list, template, SZ_PATHNAME) == EOF)
+ call error (1, "Input list is empty.")
+ call imtrew (list)
+ is_temp = false
+ }
+
+ if (whatfile (template) != IS_TABLE)
+ call error (1, "Template/input file is not a table.")
+
+ # Break template file name into bracketed selectors.
+ call rdselect (template, Memc[root], rowsel, colsel, SZ_FNAME)
+
+ # Open template table and get some info.
+ itp = tbtopn (Memc[root], READ_ONLY, NULL)
+ nrows = tbpsta (itp, TBL_NROWS)
+ ncols = tbpsta (itp, TBL_NCOLS)
+
+ # There might be header-stored scalars that don't show up
+ # with tbpsta, if the template is coming from the input list.
+ # Examine the header to find how many of them there are and
+ # increment number of output columns.
+ nscalar = tihnsc (itp)
+ ncols = ncols + nscalar
+
+ # Create arrays with colum info. Must be freed by caller.
+ call malloc (cpo, ncols, TY_INT)
+ call malloc (newcpo, ncols, TY_INT)
+ call tcs_open (itp, colsel, Memi[cpo], ncpo, ncols)
+
+ # Exit if no column matches and no scalars.
+ if (ncpo == 0 && nscalar == 0)
+ call error (1, "No columns selected.")
+
+ # Open output table.
+ otp = tbtopn (output, NEW_FILE, 0)
+
+ # Copy column information from input to output.
+ call tisetc (cpo, newcpo, ncpo, nscalar, itp, otp, colname, colunits,
+ colfmt, nrows, is_temp)
+
+ # Point to new column array.
+ call mfree (cpo, TY_INT)
+ cpo = newcpo
+
+ # Number of columns now is (selected columns from input) + scalars.
+ ncpo = ncpo + nscalar
+
+ # Create output table.
+ call tbtcre (otp)
+
+ # Cleanup.
+ call tbtclo (itp)
+ call sfree (sp)
+end
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{tinsert.x}
+\begin{verbatim}
+
+include <tbset.h>
+include "../whatfile.h"
+
+# TINSERT -- Perform the actual insertion.
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+
+
+procedure tinsert (list, output, otp, cpo, ncpo, row, rflag, verbose,
+ rowsel, colsel, colname, colunits, colfmt)
+
+pointer list # i: input list
+char output[ARB] # i: output table name
+pointer otp # i: output table descriptor
+pointer cpo # i: output column descriptors
+int ncpo # i: output number of columns
+int row # i: row where to begin insertion
+bool rflag # i: read row from header ?
+bool verbose # i: print info ?
+char rowsel[ARB] # i: work string for row selector
+char colsel[ARB] # i: work string for column selector
+char colname[ARB] # i: work string for column names
+char colunits[ARB] # i: work string for column units
+char colfmt[ARB] # i: work string for column formats
+#--
+pointer sp, itp, fname, root, pcode, cpi
+int i, file, hrow, numrow, numcol, nrows, ncpi
+
+errchk ticopy
+
+pointer trsopen(), tbtopn()
+int imtgetim(), imtlen(), whatfile(), tihrow(), tbpsta()
+bool trseval()
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_PATHNAME, TY_CHAR)
+ call salloc (root, SZ_FNAME, TY_CHAR)
+
+ # Loop over input list.
+ do file = 1, imtlen(list) {
+
+ # Get input table name and validate file type.
+ i = imtgetim (list, Memc[fname], SZ_PATHNAME)
+ if (whatfile (Memc[fname]) != IS_TABLE) {
+ call eprintf ("Input file is not a table (%s)\n")
+ call pargstr (Memc[fname])
+ call flush (STDERR)
+ break
+ }
+
+ # Break input file name into bracketed selectors.
+ call rdselect (Memc[fname], Memc[root], rowsel, colsel, SZ_FNAME)
+
+ # Open input table and get some info.
+ itp = tbtopn (Memc[fname], READ_ONLY, NULL)
+ numrow = tbpsta (itp, TBL_NROWS)
+ numcol = tbpsta (itp, TBL_NCOLS)
+
+ # See if original row information is stored in header.
+ # If so, and user asked for, use it.
+ hrow = tihrow (itp)
+ if (rflag) {
+ if (hrow > 0)
+ row = hrow
+ else
+ call error (1, "No valid row.")
+ }
+
+ # Find how many rows were requested by row selector.
+ nrows = 0
+ pcode = trsopen (itp, rowsel)
+ do i = 1, numrow {
+ if (trseval (itp, i, pcode))
+ nrows = nrows + 1
+ }
+ call trsclose (pcode)
+
+ # Create array of column pointers from column selector.
+ call malloc (cpi, numcol, TY_INT)
+ call tcs_open (itp, colsel, Memi[cpi], ncpi, numcol)
+
+ if (verbose) {
+ call printf ("%s -> %s row=%d \n")
+ call pargstr (Memc[fname])
+ call pargstr (output)
+ call pargi (row)
+ call flush (STDOUT)
+ }
+
+ # Copy current input table into current row of output table.
+ call ticopy (itp, cpi, ncpi, otp, cpo, ncpo, rowsel, row, nrows,
+ colname, colunits, colfmt)
+
+ # Free input table's array of column pointers.
+ call tcs_close (Memi[cpi], ncpi)
+ call mfree (cpi, TY_INT)
+
+ # Close input table.
+ call tbtclo (itp)
+
+ # Bump row counter.
+ row = row + 1
+ }
+
+ call sfree (sp)
+end
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{tisetc.x}
+\begin{verbatim}
+
+
+# TISETC -- Set column info in new output table.
+#
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+
+
+procedure tisetc (cpo, newcpo, ncpo, nscalar, itp, otp, colname, colunits,
+ colfmt, csize, template)
+
+pointer cpo # i: array of column descriptors
+pointer newcpo # io: new array of column descriptors
+int ncpo # i: number of columns matched by selector
+int nscalar # i: number of scalar columns
+char colname[ARB] # i: work array for column names
+char colunits[ARB] # i: work array for column units
+char colfmt[ARB] # i: work array for column format
+pointer itp,otp # io: template and output table descriptors
+int csize # i: cell size in output table
+bool template # i: is there a template ?
+#--
+pointer ocp
+int i, j, colnum, ntot
+int datatype, lendata, lenfmt
+
+errchk tihdec
+
+pointer tcs_column()
+int tihmax()
+bool tihdec()
+
+begin
+ # First copy column information from template/input
+ # table into output table.
+ if (ncpo > 0) {
+ do i = 1, ncpo {
+ ocp = tcs_column (Memi[cpo+i-1])
+ if (!template) {
+
+ # Template wasn't supplied; copy column info from 2-D
+ # input table into 3-D output table, taking care of
+ # resetting the array size.
+ call tbcinf (ocp, colnum, colname, colunits, colfmt,
+ datatype, lendata, lenfmt)
+ if (lendata > 1)
+ call error (1, "Input table has array element !")
+ call tbcdef (otp, ocp, colname, colunits, colfmt,
+ datatype, csize, 1)
+ } else {
+
+ # Copy with same array size configuration, since
+ # template is supposedly a 3-D table.
+ call tbcinf (ocp, colnum, colname, colunits, colfmt,
+ datatype, lendata, lenfmt)
+ call tbcdef (otp, ocp, colname, colunits, colfmt,
+ datatype, lendata, 1)
+ }
+
+ # Save column pointer.
+ Memi[newcpo+i-1] = ocp
+ }
+ }
+
+ # If header-stored scalars exist, define new columns for them.
+ if (nscalar > 0) {
+ ntot = tihmax (itp)
+ i = ncpo
+ do j = 1, ntot {
+ if (tihdec (itp, j, colname, colunits, colfmt, datatype,
+ lenfmt)) {
+ call tbcdef (otp, ocp, colname, colunits, colfmt,
+ datatype, 1, 1)
+ Memi[newcpo+i] = ocp
+ i = i + 1
+ }
+ }
+ }
+end
+
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{ticopy.x}
+\begin{verbatim}
+
+include <tbset.h>
+
+# TICOPY -- Copy input table into row of output table
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+
+
+procedure ticopy (itp, cpi, ncpi, otp, cpo, ncpo, rowsel, row, nrows,
+ coln, colu, colf)
+
+pointer itp # i: input table descriptor
+pointer cpi # i: input column descriptor array
+int ncpi # i: input number of columns
+pointer otp # i: output table descriptor
+pointer cpo # i: output column descriptor array
+int ncpo # i: output number of columns
+char rowsel[ARB] # i: work string for row selector
+int row # i: row where to begin insertion
+int nrows # i: number of selected rows
+char coln[ARB] # i: work string for column names
+char colu[ARB] # i: work string for column units
+char colf[ARB] # i: work string for column formats
+#--
+pointer sp, coln2, colu2, colf2, icp, ocp
+int icpi, icpo, dum, dtypi, dtypo, maxlen
+int ihc, maxhc
+bool found
+
+errchk ticc
+
+pointer tcs_column()
+int tbalen(), tihmax()
+bool streq(), tihdec()
+
+begin
+ call smark (sp)
+ call salloc (coln2, SZ_COLNAME, TY_CHAR)
+ call salloc (colu2, SZ_COLUNITS, TY_CHAR)
+ call salloc (colf2, SZ_COLFMT, TY_CHAR)
+
+ # Loop over output table column pointers.
+ do icpo = 1, ncpo {
+
+ # Get column name and data type from output table.
+ ocp = Memi[cpo+icpo-1]
+ call tbcinf (ocp, dum, coln, colu, colf, dtypo, dum, dum)
+
+ # Array length must be the minimum in between table array
+ # size and the number of rows selected from input table.
+ maxlen = min (tbalen(ocp), nrows)
+
+ # If there are matched columns, loop over
+ # input table column pointers.
+ found = false
+ if (ncpi > 0) {
+ do icpi = 1, ncpi {
+
+ # Get column name and data type from input table.
+ icp = tcs_column (Memi[cpi+icpi-1])
+ call tbcinf (icp,dum,Memc[coln2],colu,colf,dtypi,dum,dum)
+
+ # If column names match, copy from table to table.
+ if (streq (coln, Memc[coln2])) {
+ # For now, abort if datatypes do not match.
+ if (dtypo != dtypi)
+ call error (1, "Data types do not match.")
+ call ticc (itp,icp,otp,ocp,dtypo,maxlen,rowsel,row)
+ found = true
+ }
+ }
+ }
+
+ # If column was not found, look into header.
+ if (!found) {
+ maxhc = tihmax (itp)
+ if (maxhc > 0) {
+ do ihc = 1, maxhc {
+ if (tihdec (itp, ihc, Memc[coln2], Memc[colu2],
+ Memc[colf2], dtypi, dum)) {
+ if (streq (coln, Memc[coln2])) {
+
+ # For now, abort if datatypes do not match.
+ if (dtypo != dtypi)
+ call error (1, "Data types do not match.")
+ if (dtypo < 0)
+ dtypo = TY_CHAR
+
+ switch (dtypo) {
+ case TY_CHAR:
+ call ticht (itp, ihc, otp, ocp, row, -dtypi)
+ case TY_BOOL:
+ call tichb (itp, ihc, otp, ocp, row)
+ case TY_SHORT:
+ call tichs (itp, ihc, otp, ocp, row)
+ case TY_INT,TY_LONG:
+ call tichi (itp, ihc, otp, ocp, row)
+ case TY_REAL:
+ call tichr (itp, ihc, otp, ocp, row)
+ case TY_DOUBLE:
+ call tichd (itp, ihc, otp, ocp, row)
+ default:
+ call error (1, "Non-supported data type.")
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ call sfree (sp)
+end
+
+
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{ticc.x}
+\begin{verbatim}
+
+
+# TICC -- Copy data from column in input to cell array in output.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+
+
+procedure ticc (itp, icp, otp, ocp, dtype, maxlen, rowsel, row)
+
+pointer itp # i: input table descriptor
+pointer icp # i: input column descriptor
+pointer otp # i: output table descriptor
+pointer ocp # i: output column descriptor
+int dtype # i: data type of both input and output columns
+int maxlen # i: array length
+char rowsel[ARB] # i: work string for row selector
+int row # i: row where to insert
+#--
+pointer sp, buf
+int maxch
+
+begin
+ # Alloc buffer of apropriate length and type.
+ maxch = 1
+ if (dtype < 0) {
+ maxch = - dtype
+ dtype = TY_CHAR
+ }
+ call smark (sp)
+ call salloc (buf, maxlen*(maxch + 1), dtype)
+
+ # Copy.
+ switch (dtype) {
+ case TY_CHAR:
+ call tirowst (itp, icp, otp, ocp, rowsel, row, maxch, maxlen,
+ Memc[buf])
+ case TY_BOOL:
+ call tirowsb (itp, icp, otp, ocp, rowsel, row, maxlen, Memb[buf])
+ case TY_SHORT:
+ call tirowss (itp, icp, otp, ocp, rowsel, row, maxlen, Mems[buf])
+ case TY_INT, TY_LONG:
+ call tirowsi (itp, icp, otp, ocp, rowsel, row, maxlen, Memi[buf])
+ case TY_REAL:
+ call tirowsr (itp, icp, otp, ocp, rowsel, row, maxlen, Memr[buf])
+ case TY_DOUBLE:
+ call tirowsd (itp, icp, otp, ocp, rowsel, row, maxlen, Memd[buf])
+ default:
+ call error (1, "Non-supported data type.")
+ }
+
+ call sfree (sp)
+end
+\end{verbatim}
+\newpage
+\addcontentsline{toc}{section}{tiheader.x}
+\begin{verbatim}
+
+include <tbset.h>
+
+# TIHEADER -- Routines for retrieving header-stored scalars.
+#
+# Details such as keyword names and encoding are defined by the
+# way task txtable creates the same keywords.
+#
+#
+#
+# TIHKI -- Look for keyword and return integer value, or 0 if not found.
+# TIHMAX -- Return maximum number of header-stored scalars.
+# TIHNSC -- Return actual number of scalars in header.
+# TIHROW -- Return original row value stored by txtable task.
+# TIHDEC -- Decode column description in header keyword.
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+
+
+
+# TIHMAX -- Return maximum number of header-stored scalars.
+
+int procedure tihmax (tp)
+
+pointer tp # table pointer
+
+int tihki()
+
+begin
+ return (tihki (tp, "TCTOTAL"))
+end
+
+
+
+
+# TIHROW -- Return original row value (stored by txtable task).
+
+int procedure tihrow (tp)
+
+pointer tp # table pointer
+
+int tihki()
+
+begin
+ return (tihki (tp, "ORIG_ROW"))
+end
+
+
+
+
+# TIHNSC -- Return actual number of scalars in header.
+
+int procedure tihnsc (tp)
+
+pointer tp # table pointer
+#--
+pointer sp, kwname, kwval
+int dtype, parnum
+int i, ntot, nscalar
+
+int tihmax()
+
+begin
+ call smark (sp)
+ call salloc (kwval, SZ_PARREC, TY_CHAR)
+ call salloc (kwname, SZ_LINE, TY_CHAR)
+ nscalar = 0
+
+ ntot = tihmax (tp)
+ if (ntot > 0) {
+ do i = 1, ntot {
+ call sprintf (kwname, SZ_LINE, "TCD_%03d")
+ call pargi (i)
+ call tbhfkr (tp, kwname, dtype, kwval, parnum)
+ if (parnum > 0)
+ nscalar = nscalar + 1
+ }
+ }
+
+ call sfree (sp)
+ return (nscalar)
+end
+
+
+
+
+
+# TIHDEC -- Decode column description in header keyword. The detailed
+# format depends on how task txtable does the encoding.
+
+bool procedure tihdec (tp, kn, colname, colunits, colfmt, datatype, lenfmt)
+
+pointer tp # i: table pointer
+int kn # i: keyword number
+char colname[ARB] # o: column name
+char colunits[ARB] # o: column units
+char colfmt[ARB] # o: column print format
+int datatype # o: column data type
+int lenfmt # o: format lenght
+#--
+pointer sp, kwname, kwval, dtype
+int parnum
+bool found
+
+string corrupt "Corrupted header in input table."
+
+int nscan(), strncmp()
+bool streq()
+
+begin
+ call smark (sp)
+ call salloc (kwval, SZ_PARREC, TY_CHAR)
+ call salloc (kwname, SZ_LINE, TY_CHAR)
+ call salloc (dtype, SZ_LINE, TY_CHAR)
+
+ # Build column description keyword name.
+ call sprintf (Memc[kwname], SZ_LINE, "TCD_%03d")
+ call pargi (kn)
+
+ # Look for it.
+ call tbhfkr (tp, Memc[kwname], datatype, Memc[kwval], parnum)
+
+ if (parnum > 0) {
+
+ # Found; parse the 5 fields.
+ call sscan (Memc[kwval])
+ call gargwrd (colname, SZ_COLNAME)
+ if (nscan() < 1) call error (1, corrupt)
+ call gargwrd (colunits, SZ_COLUNITS)
+ if (nscan() < 1) call error (1, corrupt)
+ call gargwrd (colfmt, SZ_COLFMT)
+ if (nscan() < 1) call error (1, corrupt)
+ call gargwrd (Memc[dtype], SZ_LINE)
+ if (nscan() < 1) call error (1, corrupt)
+ call gargi (lenfmt)
+ if (nscan() < 1) call error (1, corrupt)
+
+ # Translate from human-readable encoding to sdas table encoding.
+ if (streq (colunits, "default"))
+ call strcpy ("", colunits, SZ_COLUNITS)
+ if (streq (colfmt, "default"))
+ call strcpy ("", colfmt, SZ_COLFMT)
+ if (streq (Memc[dtype], "boolean")) datatype = TY_BOOL
+ if (streq (Memc[dtype], "short")) datatype = TY_SHORT
+ if (streq (Memc[dtype], "integer")) datatype = TY_INT
+ if (streq (Memc[dtype], "long")) datatype = TY_LONG
+ if (streq (Memc[dtype], "real")) datatype = TY_REAL
+ if (streq (Memc[dtype], "double")) datatype = TY_DOUBLE
+ if (strncmp (Memc[dtype], "character_", 10) == 0) {
+ call sscan (Memc[dtype+10])
+ call gargi (datatype)
+ datatype = -datatype
+ }
+ found = true
+ } else
+ found = false
+
+ call sfree (sp)
+ return (found)
+end
+
+
+
+
+# TIHKI -- Look for keyword and return integer value, or 0 if not found.
+# Zero is never expected as a valid result because this routine
+# is used to retrieve either the maximum number of header-stored
+# scalars (zero means no scalars) or the original table row number.
+
+int procedure tihki (tp, keyword)
+
+pointer tp # table pointer
+char keyword[ARB] # keyword
+#--
+pointer sp, kwval
+int dtype, parnum, par
+
+int tbhgti()
+
+begin
+ call smark (sp)
+ call salloc (kwval, SZ_PARREC, TY_CHAR)
+ call tbhfkr (tp, keyword, dtype, kwval, parnum)
+ if (parnum > 0)
+ par = tbhgti (tp, keyword)
+ else
+ par = 0
+ call sfree (sp)
+ return (par)
+end
+\end{verbatim}
+\newpage
+\end{document}
diff --git a/pkg/utilities/nttools/threed/titable/loc.txt b/pkg/utilities/nttools/threed/titable/loc.txt
new file mode 100644
index 00000000..1621316e
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/loc.txt
@@ -0,0 +1,11 @@
+Filename Total Blanks Comments Help Execute Nonexec
+============================================================================
+ titable.x 81 18 16 0 23 24
+ tiupdate.x 42 13 11 0 7 11
+ tinew.x 96 24 21 0 30 21
+ tinsert.x 104 23 17 0 41 23
+ tisetc.x 70 17 14 0 20 19
+ ticopy.x 107 23 16 0 45 23
+ ticc.x 53 11 7 0 22 13
+ tiheader.x 189 57 27 0 62 43
+TOTAL 742 186 129 0 250 177
diff --git a/pkg/utilities/nttools/threed/titable/mkpkg b/pkg/utilities/nttools/threed/titable/mkpkg
new file mode 100644
index 00000000..c84da84b
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/mkpkg
@@ -0,0 +1,36 @@
+# Update the titable application code in the threed package library.
+# Author: I.Busko, 14-Jan-1997
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+# This module is called from the threed mkpkg.
+generic:
+ $ifnfile (generic/tirowsi.x)
+ $generic -k -p generic/ -t bcsird tirows.gx
+ $endif
+ $ifolder (generic/tirowsi.x, tirows.gx)
+ $generic -k -p generic/ -t bcsird tirows.gx
+ $endif
+ $ifnfile (generic/tichi.x)
+ $generic -k -p generic/ -t bcsird tich.gx
+ $endif
+ $ifolder (generic/tichi.x, tich.gx)
+ $generic -k -p generic/ -t bcsird tich.gx
+ $endif
+ ;
+
+libpkg.a:
+ @generic
+ ticc.x
+ ticopy.x <tbset.h>
+ tiheader.x <tbset.h>
+ tinew.x <tbset.h>
+ tinsert.x <tbset.h>
+ tisetc.x
+ titable.x <tbset.h>
+ tiupdate.x <tbset.h>
+ ;
+
diff --git a/pkg/utilities/nttools/threed/titable/ticc.x b/pkg/utilities/nttools/threed/titable/ticc.x
new file mode 100644
index 00000000..81283904
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/ticc.x
@@ -0,0 +1,56 @@
+
+# TICC -- Copy data from column in input to cell array in output.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+
+
+procedure ticc (itp, icp, otp, ocp, dtype, maxlen, rowsel, row)
+
+pointer itp # i: input table descriptor
+pointer icp # i: input column descriptor
+pointer otp # i: output table descriptor
+pointer ocp # i: output column descriptor
+int dtype # i: data type of both input and output columns
+int maxlen # i: array length
+char rowsel[ARB] # i: work string for row selector
+int row # i: row where to insert
+#--
+pointer sp, buf
+int maxch
+
+begin
+ # Alloc buffer of apropriate length and type.
+ maxch = 1
+ if (dtype < 0) {
+ maxch = - dtype
+ dtype = TY_CHAR
+ }
+ call smark (sp)
+ call salloc (buf, maxlen*(maxch + 1), dtype)
+
+ # Copy.
+ switch (dtype) {
+ case TY_CHAR:
+ call tirowst (itp, icp, otp, ocp, rowsel, row, maxch, maxlen,
+ Memc[buf])
+ case TY_BOOL:
+ call tirowsb (itp, icp, otp, ocp, rowsel, row, maxlen, Memb[buf])
+ case TY_SHORT:
+ call tirowss (itp, icp, otp, ocp, rowsel, row, maxlen, Mems[buf])
+ case TY_INT, TY_LONG:
+ call tirowsi (itp, icp, otp, ocp, rowsel, row, maxlen, Memi[buf])
+ case TY_REAL:
+ call tirowsr (itp, icp, otp, ocp, rowsel, row, maxlen, Memr[buf])
+ case TY_DOUBLE:
+ call tirowsd (itp, icp, otp, ocp, rowsel, row, maxlen, Memd[buf])
+ default:
+ call error (1, "Non-supported data type.")
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/threed/titable/tich.gx b/pkg/utilities/nttools/threed/titable/tich.gx
new file mode 100644
index 00000000..bcc83fef
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/tich.gx
@@ -0,0 +1,74 @@
+include <tbset.h>
+
+# TICH -- Copy data from input header into scalar cell in output.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+
+
+$if (datatype == c)
+procedure ticht (itp, ihc, otp, ocp, orow, maxch)
+$else
+procedure tich$t (itp, ihc, otp, ocp, orow)
+$endif
+
+pointer itp # i: input table descriptor
+int ihc # i: header keyword index
+pointer otp # i: output table descriptor
+pointer ocp # i: output column descriptor
+int orow # i: row where to insert
+$if (datatype == c)
+int maxch
+$endif
+#--
+$if (datatype == c)
+pointer buf
+$else
+PIXEL buf
+$endif
+pointer sp, kwname, kwval
+int datatype, parnum
+
+string corrupt "Corrupted header in input table."
+
+int nscan()
+
+begin
+ call smark (sp)
+ $if (datatype == c)
+ call salloc (buf, maxch + 1, TY_CHAR)
+ $endif
+ call salloc (kwname, SZ_LINE, TY_CHAR)
+ call salloc (kwval, SZ_PARREC, TY_CHAR)
+
+ # Build keyword name and look for it.
+ call sprintf (Memc[kwname], SZ_LINE, "TCV_%03d")
+ call pargi (ihc)
+ call tbhfkr (itp, Memc[kwname], datatype, Memc[kwval], parnum)
+
+ # Parse and read value. We assume that the keyword existence
+ # was confirmed by previously finding the paired TCD_ keyword.
+ if (parnum > 0) {
+ call sscan (Memc[kwval])
+ $if (datatype == c)
+ call gargwrd (buf, maxch)
+ $else
+ call garg$t (buf)
+ $endif
+ if (nscan() < 1) call error (1, corrupt)
+ } else
+ call error (1, corrupt)
+
+ # Write value into scalar cell.
+ $if (datatype == c)
+ call tbcptt (otp, ocp, buf, maxch, orow, orow)
+ $else
+ call tbcpt$t (otp, ocp, buf, orow, orow)
+ $endif
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/threed/titable/ticopy.x b/pkg/utilities/nttools/threed/titable/ticopy.x
new file mode 100644
index 00000000..505a80ce
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/ticopy.x
@@ -0,0 +1,116 @@
+include <tbset.h>
+
+# TICOPY -- Copy input table into row of output table
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+# 17-Mar-97 - Revised after code review (IB)
+
+
+procedure ticopy (itp, cpi, ncpi, otp, cpo, ncpo, rowsel, row, nrows,
+ coln, colu, colf)
+
+pointer itp # i: input table descriptor
+pointer cpi # i: input column descriptor array
+int ncpi # i: input number of columns
+pointer otp # i: output table descriptor
+pointer cpo # i: output column descriptor array
+int ncpo # i: output number of columns
+char rowsel[ARB] # i: work string for row selector
+int row # i: row where to begin insertion
+int nrows # i: number of selected rows
+char coln[ARB] # i: work string for column names
+char colu[ARB] # i: work string for column units
+char colf[ARB] # i: work string for column formats
+#--
+pointer sp, coln2, colu2, colf2, icp, ocp
+int icpi, icpo, dum, dtypi, dtypo, maxlen
+int ihc, maxhc
+bool found
+
+errchk ticc
+
+pointer tcs_column()
+int tbalen(), tihmax()
+bool streq(), tihdec()
+
+begin
+ call smark (sp)
+ call salloc (coln2, SZ_COLNAME, TY_CHAR)
+ call salloc (colu2, SZ_COLUNITS, TY_CHAR)
+ call salloc (colf2, SZ_COLFMT, TY_CHAR)
+
+ # Loop over output table column pointers.
+ do icpo = 1, ncpo {
+
+ # Get column name and data type from output table.
+ ocp = Memi[cpo+icpo-1]
+ call tbcinf (ocp, dum, coln, colu, colf, dtypo, dum, dum)
+
+ # Array length must be the minimum in between table array
+ # size and the number of rows selected from input table.
+ maxlen = min (tbalen(ocp), nrows)
+
+ # If there are matched columns, loop over
+ # input table column pointers.
+ found = false
+ do icpi = 1, ncpi {
+
+ # Get column name and data type from input table.
+ icp = tcs_column (Memi[cpi+icpi-1])
+ call tbcinf (icp,dum,Memc[coln2],colu,colf,dtypi,dum,dum)
+
+ # If column names match, copy from table to table.
+ if (streq (coln, Memc[coln2])) {
+ # For now, abort if datatypes do not match.
+ if (dtypo != dtypi)
+ call error (1, "Data types do not match.")
+ call ticc (itp,icp,otp,ocp,dtypo,maxlen,rowsel,row)
+ found = true
+ }
+ }
+
+ # If column was not found, look into header.
+ if (!found) {
+ maxhc = tihmax (itp)
+ do ihc = 1, maxhc {
+ if (tihdec (itp, ihc, Memc[coln2], Memc[colu2],
+ Memc[colf2], dtypi, dum)) {
+ if (streq (coln, Memc[coln2])) {
+
+ # For now, abort if datatypes do not match.
+ if (dtypo != dtypi)
+ call error (1, "Data types do not match.")
+ if (dtypo < 0)
+ dtypo = TY_CHAR
+
+ switch (dtypo) {
+ case TY_CHAR:
+ call ticht (itp, ihc, otp, ocp, row, -dtypi)
+ case TY_BOOL:
+ call tichb (itp, ihc, otp, ocp, row)
+ case TY_SHORT:
+ call tichs (itp, ihc, otp, ocp, row)
+ case TY_INT,TY_LONG:
+ call tichi (itp, ihc, otp, ocp, row)
+ case TY_REAL:
+ call tichr (itp, ihc, otp, ocp, row)
+ case TY_DOUBLE:
+ call tichd (itp, ihc, otp, ocp, row)
+ default:
+ call error (1, "Non-supported data type.")
+ }
+ }
+ }
+ }
+ }
+ }
+
+ call sfree (sp)
+end
+
+
diff --git a/pkg/utilities/nttools/threed/titable/tiheader.x b/pkg/utilities/nttools/threed/titable/tiheader.x
new file mode 100644
index 00000000..4918b625
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/tiheader.x
@@ -0,0 +1,192 @@
+include <tbset.h>
+
+# TIHEADER -- Routines for retrieving header-stored scalars.
+#
+# Details such as keyword names and encoding are defined by the
+# way task txtable creates the same keywords.
+#
+#
+#
+# TIHKI -- Look for keyword and return integer value, or 0 if not found.
+# TIHMAX -- Return maximum number of header-stored scalars.
+# TIHNSC -- Return actual number of scalars in header.
+# TIHROW -- Return original row value stored by txtable task.
+# TIHDEC -- Decode column description in header keyword.
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+# 17-Mar-97 - Revised after code review (IB)
+
+
+
+# TIHMAX -- Return maximum number of header-stored scalars.
+
+int procedure tihmax (tp)
+
+pointer tp # table pointer
+
+int tihki()
+
+begin
+ return (tihki (tp, "TCTOTAL"))
+end
+
+
+
+
+# TIHROW -- Return original row value (stored by txtable task).
+
+int procedure tihrow (tp)
+
+pointer tp # table pointer
+
+int tihki()
+
+begin
+ return (tihki (tp, "ORIG_ROW"))
+end
+
+
+
+
+# TIHNSC -- Return actual number of scalars in header.
+
+int procedure tihnsc (tp)
+
+pointer tp # table pointer
+#--
+pointer sp, kwname, kwval
+int dtype, parnum
+int i, ntot, nscalar
+
+int tihmax()
+
+begin
+ call smark (sp)
+ call salloc (kwval, SZ_PARREC, TY_CHAR)
+ call salloc (kwname, SZ_LINE, TY_CHAR)
+ nscalar = 0
+
+ ntot = tihmax (tp)
+ do i = 1, ntot {
+ call sprintf (kwname, SZ_LINE, "TCD_%03d")
+ call pargi (i)
+ call tbhfkr (tp, kwname, dtype, kwval, parnum)
+ if (parnum > 0)
+ nscalar = nscalar + 1
+ }
+
+ call sfree (sp)
+ return (nscalar)
+end
+
+
+
+
+
+# TIHDEC -- Decode column description in header keyword. The detailed
+# format depends on how task txtable does the encoding.
+
+bool procedure tihdec (tp, kn, colname, colunits, colfmt, datatype, lenfmt)
+
+pointer tp # i: table pointer
+int kn # i: keyword number
+char colname[ARB] # o: column name
+char colunits[ARB] # o: column units
+char colfmt[ARB] # o: column print format
+int datatype # o: column data type
+int lenfmt # o: format lenght
+#--
+pointer sp, kwname, kwval, dtype
+int parnum
+bool found
+
+string corrupt "Corrupted header in input table."
+
+int nscan(), strncmp()
+bool streq()
+
+begin
+ call smark (sp)
+ call salloc (kwval, SZ_PARREC, TY_CHAR)
+ call salloc (kwname, SZ_LINE, TY_CHAR)
+ call salloc (dtype, SZ_LINE, TY_CHAR)
+
+ # Build column description keyword name.
+ call sprintf (Memc[kwname], SZ_LINE, "TCD_%03d")
+ call pargi (kn)
+
+ # Look for it.
+ call tbhfkr (tp, Memc[kwname], datatype, Memc[kwval], parnum)
+
+ if (parnum > 0) {
+
+ # Found; parse the 5 fields.
+ call sscan (Memc[kwval])
+ call gargwrd (colname, SZ_COLNAME)
+ if (nscan() < 1) call error (1, corrupt)
+ call gargwrd (colunits, SZ_COLUNITS)
+ if (nscan() < 1) call error (1, corrupt)
+ call gargwrd (colfmt, SZ_COLFMT)
+ if (nscan() < 1) call error (1, corrupt)
+ call gargwrd (Memc[dtype], SZ_LINE)
+ if (nscan() < 1) call error (1, corrupt)
+ call gargi (lenfmt)
+ if (nscan() < 1) call error (1, corrupt)
+
+ # Translate from human-readable encoding to sdas table encoding.
+ if (streq (colunits, "default"))
+ call strcpy ("", colunits, SZ_COLUNITS)
+ if (streq (colfmt, "default"))
+ call strcpy ("", colfmt, SZ_COLFMT)
+ if (streq (Memc[dtype], "boolean")) datatype = TY_BOOL
+ if (streq (Memc[dtype], "short")) datatype = TY_SHORT
+ if (streq (Memc[dtype], "integer")) datatype = TY_INT
+ if (streq (Memc[dtype], "long")) datatype = TY_LONG
+ if (streq (Memc[dtype], "real")) datatype = TY_REAL
+ if (streq (Memc[dtype], "double")) datatype = TY_DOUBLE
+ if (strncmp (Memc[dtype], "character_", 10) == 0) {
+ call sscan (Memc[dtype+10])
+ call gargi (datatype)
+ datatype = -datatype
+ }
+ found = true
+ } else
+ found = false
+
+ call sfree (sp)
+ return (found)
+end
+
+
+
+
+# TIHKI -- Look for keyword and return integer value, or 0 if not found.
+# Zero is never expected as a valid result because this routine
+# is used to retrieve either the maximum number of header-stored
+# scalars (zero means no scalars) or the original table row number.
+
+int procedure tihki (tp, keyword)
+
+pointer tp # table pointer
+char keyword[ARB] # keyword
+#--
+pointer sp, kwval
+int dtype, parnum, par
+
+int tbhgti()
+
+begin
+ call smark (sp)
+ call salloc (kwval, SZ_PARREC, TY_CHAR)
+ call tbhfkr (tp, keyword, dtype, kwval, parnum)
+ if (parnum > 0)
+ par = tbhgti (tp, keyword)
+ else
+ par = 0
+ call sfree (sp)
+ return (par)
+end
diff --git a/pkg/utilities/nttools/threed/titable/tinew.x b/pkg/utilities/nttools/threed/titable/tinew.x
new file mode 100644
index 00000000..afc63bcb
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/tinew.x
@@ -0,0 +1,101 @@
+include <tbset.h>
+
+# TINEW -- Opens and creates a new output table.
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-1997 - Task created (I.Busko)
+# 8-Apr-1999 - Call tbfpri (Phil Hodge)
+# 8-Apr-2002 - Remove the call to whatfile (P. Hodge)
+# 8-Dec-2003 - Call tcs_close for cpo.
+
+
+procedure tinew (template, list, output, rowsel, colsel, colname, colunits,
+ colfmt, otp, cpo, ncpo)
+
+char template[ARB] # i: template table name
+pointer list # i: input list
+char output[ARB] # i: output table name
+char rowsel[ARB] # i: work array for row selectors
+char colsel[ARB] # i: work array for column selectors
+char colname[ARB] # i: work array for column names
+char colunits[ARB] # i: work array for column units
+char colfmt[ARB] # i: work array for column format
+pointer otp # o: table descriptor
+pointer cpo # o: column descriptor
+int ncpo # o: number of columns
+#--
+pointer sp, itp, newcpo, root
+int nrows, ncols, nscalar
+int phu_copied # set by tbfpri and ignored
+bool is_temp
+
+errchk tbfpri, tbtopn, tisetc
+
+pointer tbtopn()
+int tbpsta(), imtgetim(), tihnsc(), access()
+
+begin
+ call smark (sp)
+ call salloc (root, SZ_PATHNAME, TY_CHAR)
+
+ # See if there is a template table.
+ is_temp = true
+ if (access (template, READ_ONLY, 0) == NO) {
+
+ # Get first table in input list as the template.
+ if (imtgetim (list, template, SZ_PATHNAME) == EOF)
+ call error (1, "Input list is empty.")
+ call imtrew (list)
+ is_temp = false
+ }
+
+ # Break template file name into bracketed selectors.
+ call rdselect (template, Memc[root], rowsel, colsel, SZ_FNAME)
+
+ # Open template table and get some info.
+ itp = tbtopn (Memc[root], READ_ONLY, NULL)
+ nrows = tbpsta (itp, TBL_NROWS)
+ ncols = tbpsta (itp, TBL_NCOLS)
+
+ # There might be header-stored scalars that don't show up
+ # with tbpsta, if the template is coming from the input list.
+ # Examine the header to find how many of them there are and
+ # increment number of output columns.
+ nscalar = tihnsc (itp)
+ ncols = ncols + nscalar
+
+ # Create arrays with colum info. Must be freed by caller.
+ call malloc (cpo, ncols, TY_INT)
+ call malloc (newcpo, ncols, TY_INT)
+ call tcs_open (itp, colsel, Memi[cpo], ncpo, ncols)
+
+ # Exit if no column matches and no scalars.
+ if (ncpo == 0 && nscalar == 0)
+ call error (1, "No columns selected.")
+
+ # Open output table.
+ call tbfpri (Memc[root], output, phu_copied)
+ otp = tbtopn (output, NEW_FILE, 0)
+
+ # Copy column information from input to output.
+ call tisetc (cpo, newcpo, ncpo, nscalar, itp, otp, colname, colunits,
+ colfmt, nrows, is_temp)
+
+ # Point to new column array.
+ call tcs_close (Memi[cpo], ncpo)
+ call mfree (cpo, TY_INT)
+ cpo = newcpo
+
+ # Number of columns now is (selected columns from input) + scalars.
+ ncpo = ncpo + nscalar
+
+ # Create output table.
+ call tbtcre (otp)
+
+ # Cleanup.
+ call tbtclo (itp)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/threed/titable/tinsert.x b/pkg/utilities/nttools/threed/titable/tinsert.x
new file mode 100644
index 00000000..9580a66b
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/tinsert.x
@@ -0,0 +1,99 @@
+include <tbset.h>
+
+# TINSERT -- Perform the actual insertion.
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+# 17-Mar-97 - Added selrows function (IB)
+# 8-Apr-02 - Remove the call to whatfile (P. Hodge)
+
+
+procedure tinsert (list, output, otp, cpo, ncpo, row, rflag, verbose,
+ rowsel, colsel, colname, colunits, colfmt)
+
+pointer list # i: input list
+char output[ARB] # i: output table name
+pointer otp # i: output table descriptor
+pointer cpo # i: output column descriptors
+int ncpo # i: output number of columns
+int row # i: row where to begin insertion
+bool rflag # i: read row from header ?
+bool verbose # i: print info ?
+char rowsel[ARB] # i: work string for row selector
+char colsel[ARB] # i: work string for column selector
+char colname[ARB] # i: work string for column names
+char colunits[ARB] # i: work string for column units
+char colfmt[ARB] # i: work string for column formats
+#--
+pointer sp, itp, fname, root, cpi
+int i, file, hrow, numrow, numcol, nrows, ncpi
+
+errchk ticopy
+
+pointer tbtopn()
+int imtgetim(), imtlen(), tihrow(), tbpsta(), selrows()
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_PATHNAME, TY_CHAR)
+ call salloc (root, SZ_FNAME, TY_CHAR)
+
+ # Loop over input list.
+ do file = 1, imtlen(list) {
+
+ # Get input table name.
+ i = imtgetim (list, Memc[fname], SZ_PATHNAME)
+
+ # Break input file name into bracketed selectors.
+ call rdselect (Memc[fname], Memc[root], rowsel, colsel, SZ_FNAME)
+
+ # Open input table and get some info.
+ itp = tbtopn (Memc[fname], READ_ONLY, NULL)
+ numrow = tbpsta (itp, TBL_NROWS)
+ numcol = tbpsta (itp, TBL_NCOLS)
+
+ # See if original row information is stored in header.
+ # If so, and user asked for, use it.
+ hrow = tihrow (itp)
+ if (rflag) {
+ if (hrow > 0)
+ row = hrow
+ else
+ call error (1, "No valid row.")
+ }
+
+ # Find how many rows were requested by row selector.
+ nrows = selrows (itp, rowsel)
+
+ # Create array of column pointers from column selector.
+ call malloc (cpi, numcol, TY_INT)
+ call tcs_open (itp, colsel, Memi[cpi], ncpi, numcol)
+
+ if (verbose) {
+ call printf ("%s -> %s row=%d \n")
+ call pargstr (Memc[fname])
+ call pargstr (output)
+ call pargi (row)
+ call flush (STDOUT)
+ }
+
+ # Copy current input table into current row of output table.
+ call ticopy (itp, cpi, ncpi, otp, cpo, ncpo, rowsel, row, nrows,
+ colname, colunits, colfmt)
+
+ # Free input table's array of column pointers.
+ call tcs_close (Memi[cpi], ncpi)
+ call mfree (cpi, TY_INT)
+
+ # Close input table.
+ call tbtclo (itp)
+
+ # Bump row counter.
+ row = row + 1
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/threed/titable/tirows.gx b/pkg/utilities/nttools/threed/titable/tirows.gx
new file mode 100644
index 00000000..161b39ce
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/tirows.gx
@@ -0,0 +1,98 @@
+include <tbset.h>
+
+#
+# TIROWS -- Expand row selector into array and copy it into output
+# table cell.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-1997 - Task created (I.Busko)
+# 7-Feb-2000 - For datatype = 'c', make buf an array of strings (P.Hodge)
+
+
+$if (datatype == c)
+procedure tirowst (itp, icp, otp, ocp, rowsel, orow, maxch, len, buf)
+$else
+procedure tirows$t (itp, icp, otp, ocp, rowsel, orow, len, buf)
+$endif
+
+pointer itp # i: input table descriptor
+pointer icp # i: input column descriptor
+pointer otp # i: output table descriptor
+pointer ocp # i: output column descriptor
+char rowsel[ARB] # i: row selector
+int orow # i: row in output table where to write into
+$if (datatype == c)
+int maxch # i: max length of string
+$endif
+int len # i: buffer length
+$if (datatype == c)
+char buf[maxch,ARB] # i: work buffer
+$else
+PIXEL buf[ARB]
+$endif
+#--
+double undefd
+real undefr
+pointer pcode
+int undefi, i, nelem, irow, numrow, alength
+short undefs
+
+pointer trsopen()
+int tbpsta(), tbalen()
+bool trseval()
+
+begin
+ # Loop over selected rows on input table.
+ pcode = trsopen (itp, rowsel)
+ numrow = tbpsta (itp, TBL_NROWS)
+ nelem = 0
+ do irow = 1, numrow {
+ if (trseval (itp, irow, pcode)) {
+ nelem = nelem + 1
+ if (nelem > len) {
+ nelem = len
+ break
+ }
+ # Get element and store in buffer.
+ $if (datatype == c)
+ call tbegtt (itp, icp, irow, buf[1,nelem], maxch)
+ $else
+ call tbegt$t (itp, icp, irow, buf[nelem])
+ $endif
+ }
+ }
+ call trsclose (pcode)
+
+ # Write buffer into array cell element.
+ $if (datatype == c)
+ call tbaptt (otp, ocp, orow, buf, maxch, 1, nelem)
+ $else
+ call tbapt$t (otp, ocp, orow, buf, 1, nelem)
+ $endif
+
+ # If number of selected rows in current input table
+ # is smaller than output table array length, fill
+ # remaining array elements with INDEF.
+ alength = tbalen (ocp)
+ if (alength > nelem) {
+ undefd = INDEFD
+ undefr = INDEFR
+ undefi = INDEFI
+ undefs = INDEFS
+ do i = nelem+1, alength {
+ $if (datatype == c)
+ call tbaptt (otp, ocp, orow, "", maxch, i, 1)
+ $endif
+ $if (datatype == b)
+ call tbaptb (otp, ocp, orow, false, i, 1)
+ $endif
+ $if (datatype == dris)
+ call tbapt$t (otp, ocp, orow, undef$t, i, 1)
+ $endif
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/threed/titable/tisetc.x b/pkg/utilities/nttools/threed/titable/tisetc.x
new file mode 100644
index 00000000..38acd306
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/tisetc.x
@@ -0,0 +1,83 @@
+
+# TISETC -- Set column info in new output table.
+#
+#
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+# 17-Mar-97 - Revised after code review (IB)
+
+
+procedure tisetc (cpo, newcpo, ncpo, nscalar, itp, otp, colname, colunits,
+ colfmt, csize, template)
+
+pointer cpo # i: array of column descriptors
+pointer newcpo # io: new array of column descriptors
+int ncpo # i: number of columns matched by selector
+int nscalar # i: number of scalar columns
+char colname[ARB] # i: work array for column names
+char colunits[ARB] # i: work array for column units
+char colfmt[ARB] # i: work array for column format
+pointer itp,otp # io: template and output table descriptors
+int csize # i: cell size in output table
+bool template # i: is there a template ?
+#--
+pointer ocp
+int i, j, colnum, ntot
+int datatype, lendata, lenfmt
+
+errchk tihdec
+
+pointer tcs_column()
+int tihmax()
+bool tihdec()
+
+begin
+ # First copy column information from template/input
+ # table into output table.
+ do i = 1, ncpo {
+ ocp = tcs_column (Memi[cpo+i-1])
+ if (!template) {
+
+ # Template wasn't supplied; copy column info from 2-D
+ # input table into 3-D output table, taking care of
+ # resetting the array size.
+ call tbcinf (ocp, colnum, colname, colunits, colfmt,
+ datatype, lendata, lenfmt)
+ if (lendata > 1)
+ call error (1, "Input table has array element !")
+ call tbcdef (otp, ocp, colname, colunits, colfmt,
+ datatype, csize, 1)
+ } else {
+
+ # Copy with same array size configuration, since
+ # template is supposedly a 3-D table.
+ call tbcinf (ocp, colnum, colname, colunits, colfmt,
+ datatype, lendata, lenfmt)
+ call tbcdef (otp, ocp, colname, colunits, colfmt,
+ datatype, lendata, 1)
+ }
+
+ # Save column pointer.
+ Memi[newcpo+i-1] = ocp
+ }
+
+ # If header-stored scalars exist, define new columns for them.
+ if (nscalar > 0) {
+ ntot = tihmax (itp)
+ i = ncpo
+ do j = 1, ntot {
+ if (tihdec (itp, j, colname, colunits, colfmt, datatype,
+ lenfmt)) {
+ call tbcdef (otp, ocp, colname, colunits, colfmt,
+ datatype, 1, 1)
+ Memi[newcpo+i] = ocp
+ i = i + 1
+ }
+ }
+ }
+end
+
diff --git a/pkg/utilities/nttools/threed/titable/titable.x b/pkg/utilities/nttools/threed/titable/titable.x
new file mode 100644
index 00000000..476f00ef
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/titable.x
@@ -0,0 +1,83 @@
+include <tbset.h>
+
+# TITABLE -- Insert 2D tables into 3D table rows.
+#
+# Input tables are given by a filename template list. All row/column
+# selection on input tables is performed by bracket-enclosed selectors
+# appended to the file name. The output is a 3-D table with no row/column
+# selectors.
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+# 17-Mar-97 - Revised after code review (IB)
+# 8-Apr-02 - Remove the unused strings for error messages (P. Hodge)
+# 8-Dec-03 - Use tbtacc() instead of access() to test for a new table;
+# use mfree instead of tcs_close for cpo.
+
+
+procedure t_titable()
+
+char tablist[SZ_LINE] # Input table list
+char output[SZ_PATHNAME] # Output table name
+char template[SZ_PATHNAME] # Template table name
+int row # Row where to begin insertion
+bool verbose # Print operations ?
+#--
+char root[SZ_FNAME]
+char rowselect[SZ_FNAME]
+char colselect[SZ_FNAME]
+char colname[SZ_COLNAME]
+char colunits[SZ_COLUNITS]
+char colfmt[SZ_COLFMT]
+pointer cpo
+pointer otp, list
+int ncpo, rowc
+bool rflag
+
+pointer imtopen()
+int clgeti(), tbtacc()
+bool clgetb(), streq()
+
+begin
+ # Get task parameters.
+
+ call clgstr ("intable", tablist, SZ_LINE)
+ call clgstr ("outtable", output, SZ_PATHNAME)
+ call clgstr ("template", template, SZ_PATHNAME)
+ row = clgeti ("row")
+ verbose = clgetb ("verbose")
+
+ # Abort if invalid output name..
+ if (streq (output, "STDOUT"))
+ call error (1, "Invalid output file name.")
+ call rdselect (output, root, rowselect, colselect, SZ_FNAME)
+ if (rowselect[1] != EOS || colselect[1] != EOS)
+ call error (1, "Sections not permitted on output table name.")
+
+ # Open input list.
+ list = imtopen (tablist)
+
+ # Open/create the output table.
+ if (tbtacc (output) == YES)
+ call tiupdate (root, otp, cpo, ncpo)
+ else
+ call tinew (template, list, root, rowselect, colselect, colname,
+ colunits, colfmt, otp, cpo, ncpo)
+
+ # Initialize row counter.
+ rowc = row
+ rflag = false
+ if (rowc <= 0 || IS_INDEFI(rowc)) rflag = true
+
+ # Do the insertion.
+ call tinsert (list, output, otp, cpo, ncpo, rowc, rflag, verbose,
+ rowselect, colselect, colname, colunits, colfmt)
+
+ # Cleanup. The cpo array was allocated by tiupdate/tinew.
+ call mfree (cpo, TY_INT)
+ call tbtclo (otp)
+ call imtclose (list)
+end
diff --git a/pkg/utilities/nttools/threed/titable/tiupdate.x b/pkg/utilities/nttools/threed/titable/tiupdate.x
new file mode 100644
index 00000000..ebfe9b75
--- /dev/null
+++ b/pkg/utilities/nttools/threed/titable/tiupdate.x
@@ -0,0 +1,39 @@
+include <tbset.h>
+
+# TIUPDATE -- Opens an already existing output table for update.
+#
+#
+#
+# Revision history:
+# ----------------
+# 20-Jan-97 - Task created (I.Busko)
+# 17-Mar-97 - Replaced code by tbcnum call (IB)
+
+
+procedure tiupdate (output, otp, cpo, ncpo)
+
+char output[ARB] # i: table name
+pointer otp # o: table descriptor
+pointer cpo # o: column descriptor
+int ncpo # o: number of columns
+#--
+int i
+
+errchk tbtopn
+
+pointer tbtopn(), tbcnum()
+int tbpsta()
+
+begin
+ # Open table and get its size.
+ otp = tbtopn (output, READ_WRITE, NULL)
+ ncpo = tbpsta (otp, TBL_NCOLS)
+
+ # Alloc column descriptor array. This
+ # must be freed by caller.
+ call malloc (cpo, ncpo, TY_INT)
+
+ # Fill array with column info.
+ do i = 1, ncpo
+ Memi[cpo+i-1] = tbcnum (otp, i)
+end
diff --git a/pkg/utilities/nttools/threed/tscopy.par b/pkg/utilities/nttools/threed/tscopy.par
new file mode 100644
index 00000000..d365da3e
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tscopy.par
@@ -0,0 +1,5 @@
+intable,s,a,"",,,"input tables"
+outtable,s,a,"",,,"output tables or directory"
+verbose,b,h,yes,,,"print operations performed?"
+version,s,h,"test",,,
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/threed/tscopy/mkpkg b/pkg/utilities/nttools/threed/tscopy/mkpkg
new file mode 100644
index 00000000..21136d98
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tscopy/mkpkg
@@ -0,0 +1,14 @@
+# Update the tcopy application code in the threed package library.
+# Author: I.Busko, 21-Nov-1996
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ tscopy.x <error.h>
+ tcpyone.x <tbset.h>
+ tcpyrow.x <tbset.h>
+ ;
+
diff --git a/pkg/utilities/nttools/threed/tscopy/tbracket.x b/pkg/utilities/nttools/threed/tscopy/tbracket.x
new file mode 100644
index 00000000..5c9364c4
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tscopy/tbracket.x
@@ -0,0 +1,105 @@
+#* HISTORY *
+#* B.Simon 07-Nov-94 original
+
+# TBRACKET -- Break a table name into bracket delimeted substrings
+
+procedure tbracket (table, root, rowselect, colselect, maxch)
+
+char table[ARB] # i: Table name
+char root[ARB] # o: Name minus bracketed sections
+char rowselect[ARB] # o: Row selector section
+char colselect[ARB] # o: Column selector section
+int maxch # i: Maximum length of output strings
+#--
+bool found
+char eq
+int ic, nc
+
+data eq / '=' /
+
+errchk tsplitter
+bool tsplitter()
+int stridx()
+
+begin
+ # Search for the first unescaped bracket
+
+ for (ic = 1; table[ic] != EOS; ic = ic + 1) {
+ if (table[ic] == '\\' && table[ic+1] != EOS) {
+ ic = ic + 1
+ } else if (table[ic] == '['){
+ break
+ }
+ }
+
+ nc = min (ic-1, maxch)
+ call strcpy (table, root, nc)
+
+ # Get bracketed sections from table name. If there is only
+ # a single section, disambiguate by looking for an equals
+ # sign, which indicates a row selector.
+
+ found = tsplitter (table, ic, rowselect, maxch)
+
+ if (! tsplitter (table, ic, colselect, maxch)) {
+ if (stridx (eq, rowselect) == 0) {
+ call strcpy (rowselect, colselect, maxch)
+ rowselect[1] = EOS
+ }
+ }
+
+end
+
+# TSPLITTER -- Splits table filename into sections
+
+bool procedure tsplitter (table, ic, section, maxch)
+
+char table[ARB] # i: table name
+int ic # u: index to char within name
+char section[ARB] # o: section extracted from name
+int maxch # i: maximum length of section
+#--
+int jc, level
+pointer sp, errmsg
+
+string badsect "No closing bracket (%s)"
+
+begin
+ if (table[ic] != '[') {
+ section[1] = EOS
+ return (false)
+ } else {
+ level = 1
+ ic = ic + 1
+ }
+
+ call smark (sp)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ jc = 1
+ while (level > 0 && table[ic] != EOS) {
+ if (table[ic] == '[' && table[ic-1] != '\\') {
+ level = level + 1
+ } else if (table[ic] == ']' && table[ic-1] != '\\') {
+ level = level - 1
+ }
+
+ if (level > 0 && jc <= maxch) {
+ section[jc] = table[ic]
+ jc = jc + 1
+ }
+
+ ic = ic + 1
+ }
+
+ section[jc] = EOS
+
+ if (level > 0) {
+ call sprintf (Memc[errmsg], SZ_LINE, badsect)
+ call pargstr (table)
+ call error (1, Memc[errmsg])
+ }
+
+ call sfree (sp)
+ return (true)
+end
diff --git a/pkg/utilities/nttools/threed/tscopy/tcpyone.x b/pkg/utilities/nttools/threed/tscopy/tcpyone.x
new file mode 100644
index 00000000..23c86316
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tscopy/tcpyone.x
@@ -0,0 +1,141 @@
+include <tbset.h>
+
+#* HISTORY *
+#* B.Simon 07-Nov-1994 original
+# Phil Hodge 8-Apr-1999 call tbfpri
+
+# TCPYONE -- Copy a single table to the output table
+
+procedure tcpyone (input, output)
+
+char input[ARB] # i: input table name
+char output[ARB] # i: output table name
+#--
+int numrow, numcol, numptr, type, iptr, irow, jrow
+int colnum, datatype, lendata, lenfmt
+int phu_copied # returned by tbfpri and ignored
+pointer sp, root, extend, rowselect, colselect, colname, colunits, colfmt
+pointer errmsg, icp, ocp, itp, otp, colptr, newcol, pcode
+
+string nosect "Sections not permitted on output table name (%s)"
+string nocols "Column names not found (%s)"
+
+errchk tbfpri, tbtopn, tctexp, tbracket, trsopen, trseval
+
+bool trseval(), streq()
+int tbpsta(), tcs_totsize()
+pointer tbtopn(), tcs_column, trsopen()
+
+begin
+ # Allocate memory for temporary strings
+
+ call smark (sp)
+ call salloc (root, SZ_FNAME, TY_CHAR)
+ call salloc (extend, SZ_FNAME, TY_CHAR)
+ call salloc (rowselect, SZ_FNAME, TY_CHAR)
+ call salloc (colselect, SZ_FNAME, TY_CHAR)
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+ call salloc (colunits, SZ_COLUNITS, TY_CHAR)
+ call salloc (colfmt, SZ_COLFMT, TY_CHAR)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ # Check output table name for sections
+
+# call getsects (output, Memc[root], Memc[extend], Memc[rowselect],
+# Memc[colselect], SZ_FNAME)
+
+call rdselect (output, Memc[root], Memc[rowselect], Memc[colselect], SZ_FNAME)
+
+ if (Memc[rowselect] != EOS || Memc[colselect] != EOS) {
+ call sprintf (Memc[errmsg], SZ_LINE, nosect)
+ call pargstr (output)
+ call error (1, Memc[errmsg])
+ }
+
+ # Break input file names into bracketed sections
+
+# call getsects (input, Memc[root], Memc[extend], Memc[rowselect],
+# Memc[colselect], SZ_FNAME)
+
+call rdselect (input, Memc[root], Memc[rowselect], Memc[colselect], SZ_FNAME)
+
+ if (Memc[rowselect] == EOS && Memc[colselect] == EOS) {
+ # Perform straight file copy if no sections on input name
+
+ call tbfpri (input, output, phu_copied)
+ call tbtcpy (input, output)
+
+ } else {
+ # Open the tables and set output table type
+
+# call strcat (Memc[extend], Memc[root], SZ_FNAME)
+
+ itp = tbtopn (Memc[root], READ_ONLY, NULL)
+ call tbfpri (Memc[root], output, phu_copied)
+ otp = tbtopn (output, NEW_FILE, NULL)
+
+ type = tbpsta (itp, TBL_WHTYPE)
+ # Support for ASCII output (11/20/96, IB)
+ if (streq (output, "STDOUT"))
+ type = TBL_TYPE_TEXT
+ call tbpset (otp, TBL_WHTYPE, type)
+
+ # Create an array of column pointers from the column template
+
+ numrow = tbpsta (itp, TBL_NROWS)
+ numcol = tbpsta (itp, TBL_NCOLS)
+
+ call salloc (colptr, numcol, TY_INT)
+ call salloc (newcol, numcol, TY_INT)
+
+ call tcs_open (itp, Memc[colselect], Memi[colptr], numptr, numcol)
+
+ # Take an error exit if no columns were matched
+
+ if (numptr == 0) {
+ call sprintf (Memc[errmsg], SZ_LINE, nocols)
+ call pargstr (input)
+ call error (1, Memc[errmsg])
+ }
+
+ # Copy column information from the input table to the output table
+
+ do iptr = 1, numptr {
+ icp = tcs_column (Memi[colptr+iptr-1])
+ call tbcinf (icp, colnum, Memc[colname], Memc[colunits],
+ Memc[colfmt], datatype, lendata, lenfmt)
+
+ if (lendata > 1)
+ lendata = tcs_totsize (Memi[colptr+iptr-1])
+
+ call tbcdef (otp, ocp, Memc[colname], Memc[colunits],
+ Memc[colfmt], datatype, lendata, 1)
+ Memi[newcol+iptr-1] = ocp
+ }
+
+ # Copy header keywords
+
+ call tbtcre (otp)
+ call tbhcal (itp, otp)
+
+ # Copy selected rows from input to output table
+
+ jrow = 1
+ pcode = trsopen (itp, Memc[rowselect])
+
+ do irow = 1, numrow {
+ if (trseval (itp, irow, pcode)) {
+ call tcpyrow (itp, otp, Memi[colptr], Memi[newcol],
+ irow, jrow, numptr)
+ jrow = jrow + 1
+ }
+ }
+
+ call trsclose (pcode)
+ call tcs_close (Memi[colptr], numptr)
+ call tbtclo (itp)
+ call tbtclo (otp)
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/threed/tscopy/tcpyrow.x b/pkg/utilities/nttools/threed/tscopy/tcpyrow.x
new file mode 100644
index 00000000..3eeb8c99
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tscopy/tcpyrow.x
@@ -0,0 +1,79 @@
+include <tbset.h>
+
+# TCPYROW -- Copy a single row from the input to output table
+
+procedure tcpyrow (itp, otp, icp, ocp, irow, orow, ncols)
+
+pointer itp # i: pointer to descriptor of input table
+pointer otp # i: pointer to descriptor of output table
+pointer icp[ncols] # i: array of pointers for input columns
+pointer ocp[ncols] # i: array of pointers for output columns
+int irow # i: row number in input table
+int orow # i: row number in output table
+int ncols # i: number of columns to be copied
+#--
+int icol, dlen, dtype, maxch, nbuf
+pointer sp, buf, errmsg, colname
+
+string badtype "Unsupported column data type (%s)"
+
+int tcs_intinfo(), tcs_totsize()
+
+begin
+ do icol = 1, ncols {
+ # Determine the length and datatype of the table column
+ # and allocate a buffer to match
+
+ dlen = tcs_totsize (icp[icol])
+ dtype = tcs_intinfo (icp[icol], TBL_COL_DATATYPE)
+
+ maxch = 1
+ if (dtype < 0) {
+ maxch = - dtype
+ dtype = TY_CHAR
+ }
+
+ call smark (sp)
+ call salloc (buf, dlen*(maxch + 1), dtype)
+
+ # Read the data from the input table and write it
+ # to the output table
+
+ switch (dtype) {
+ case TY_BOOL:
+ call tcs_rdaryb (itp, icp[icol], irow, dlen, nbuf, Memb[buf])
+ call tbaptb (otp, ocp[icol], orow, Memb[buf], 1, nbuf)
+ case TY_CHAR:
+ call tcs_rdaryt (itp, icp[icol], irow, maxch, dlen,
+ nbuf, Memc[buf])
+ call tbaptt (otp, ocp[icol], orow, Memc[buf], maxch, 1, nbuf)
+ case TY_SHORT:
+ call tcs_rdarys (itp, icp[icol], irow, dlen, nbuf, Mems[buf])
+ call tbapts (otp, ocp[icol], orow, Mems[buf], 1, nbuf)
+ case TY_INT, TY_LONG:
+ call tcs_rdaryi (itp, icp[icol], irow, dlen, nbuf, Memi[buf])
+ call tbapti (otp, ocp[icol], orow, Memi[buf], 1, nbuf)
+ case TY_REAL:
+ call tcs_rdaryr (itp, icp[icol], irow, dlen, nbuf, Memr[buf])
+ call tbaptr (otp, ocp[icol], orow, Memr[buf], 1, nbuf)
+ case TY_DOUBLE:
+ call tcs_rdaryd (itp, icp[icol], irow, dlen, nbuf, Memd[buf])
+ call tbaptd (otp, ocp[icol], orow, Memd[buf], 1, nbuf)
+ default:
+ # Unsupported type, write error message
+
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ call tcs_txtinfo (icp[icol], TBL_COL_NAME,
+ Memc[colname], SZ_COLNAME)
+
+ call sprintf (Memc[errmsg], SZ_LINE, badtype)
+ call pargstr (Memc[colname])
+
+ call error (1, Memc[errmsg])
+ }
+
+ call sfree (sp)
+ }
+end
diff --git a/pkg/utilities/nttools/threed/tscopy/tscopy.x b/pkg/utilities/nttools/threed/tscopy/tscopy.x
new file mode 100644
index 00000000..30629f6c
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tscopy/tscopy.x
@@ -0,0 +1,110 @@
+include <error.h>
+
+# tcopy -- Copy table(s)
+
+# The input tables are given by an filename template list. The output
+# is either a matching list of tables or a directory. The number of
+# input tables may be either one or match the number of output tables.
+# This is based on the t_imcopy procedure.
+#
+# Phil Hodge, 21-Aug-87 Task created.
+# Phil Hodge, 7-Sep-88 Change parameter names for tables.
+# Phil Hodge, 28-Dec-89 Use iferr with call to tbtcpy.
+# Phil Hodge, 26-Mar-92 Remove calls to tbtext.
+# B.Simon, 04-Nov-94 Replace call to tbtcpy with tcpyone
+# I.Busko, 20-Nov-95 Add support for ASCII output.
+
+procedure t_tcopy()
+
+char tablist1[SZ_LINE] # Input table list
+char tablist2[SZ_LINE] # Output table list
+bool verbose # Print operations?
+
+char table1[SZ_PATHNAME] # Input table name
+char table2[SZ_PATHNAME] # Output table name
+char dirname1[SZ_PATHNAME] # Directory name
+char dirname2[SZ_PATHNAME] # Directory name
+
+int list1, list2, root_len
+pointer sp
+
+int imtopen(), imtgetim(), imtlen()
+int fnldir(), isdirectory()
+bool clgetb(), streq()
+
+begin
+ # Get input and output table template lists.
+
+ call clgstr ("intable", tablist1, SZ_LINE)
+ call clgstr ("outtable", tablist2, SZ_LINE)
+ verbose = clgetb ("verbose")
+
+ # Check if the output string is a directory.
+
+ if (isdirectory (tablist2, dirname2, SZ_PATHNAME) > 0 &&
+ !streq (tablist2, "STDOUT")) {
+ list1 = imtopen (tablist1)
+ while (imtgetim (list1, table1, SZ_PATHNAME) != EOF) {
+ call smark (sp)
+
+ # Place the input table name without a directory in
+ # string dirname1.
+
+ call get_root (table1, table2, SZ_PATHNAME)
+ root_len = fnldir (table2, dirname1, SZ_PATHNAME)
+ call strcpy (table2[root_len + 1], dirname1, SZ_PATHNAME)
+
+ call strcpy (dirname2, table2, SZ_PATHNAME)
+ call strcat (dirname1, table2, SZ_PATHNAME)
+
+ if (verbose) {
+ call eprintf ("%s -> %s\n")
+ call pargstr (table1)
+ call pargstr (table2)
+ }
+ iferr (call tcpyone (table1, table2))
+ call erract (EA_WARN)
+
+ call sfree (sp)
+ }
+ call imtclose (list1)
+
+ } else {
+ # Expand the input and output table lists.
+
+ list1 = imtopen (tablist1)
+ list2 = imtopen (tablist2)
+
+ if (imtlen (list1) != imtlen (list2)) {
+ call imtclose (list1)
+ call imtclose (list2)
+ call error (1, "Number of input and output tables not the same")
+ }
+
+ # Copy each table.
+
+ while ((imtgetim (list1, table1, SZ_PATHNAME) != EOF) &&
+ (imtgetim (list2, table2, SZ_PATHNAME) != EOF)) {
+
+ call smark (sp)
+
+ if (streq (table1, table2)) {
+ call eprintf ("can't copy table to itself: %s\n")
+ call pargstr (table1)
+ next
+ }
+ if (verbose) {
+ call eprintf ("%s -> %s\n")
+ call pargstr (table1)
+ call pargstr (table2)
+ }
+ iferr (call tcpyone (table1, table2))
+ call erract (EA_WARN)
+
+ call sfree (sp)
+ }
+
+ call imtclose (list1)
+ call imtclose (list2)
+ }
+end
diff --git a/pkg/utilities/nttools/threed/tximage.par b/pkg/utilities/nttools/threed/tximage.par
new file mode 100644
index 00000000..e27bebd5
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tximage.par
@@ -0,0 +1,5 @@
+intable,s,a,"",,,">Input tables"
+output,s,a,"",,,">Output images or directory"
+verbose,b,h,yes,,,">Print operations performed ?"
+version,s,h,"03Jan97",,,
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/threed/tximage/mkpkg b/pkg/utilities/nttools/threed/tximage/mkpkg
new file mode 100644
index 00000000..bc108e8a
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tximage/mkpkg
@@ -0,0 +1,15 @@
+# Update the tximage application code in the threed package library.
+# Author: I.Busko, 26-Nov-1996
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ tximage.x <error.h>
+ txione.x <imhdr.h> <tbset.h>
+ txicpy.x <tbset.h>
+ txihc.x
+ ;
+
diff --git a/pkg/utilities/nttools/threed/tximage/txicpy.x b/pkg/utilities/nttools/threed/tximage/txicpy.x
new file mode 100644
index 00000000..1428ee9e
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tximage/txicpy.x
@@ -0,0 +1,61 @@
+include <tbset.h>
+
+# TXICPY -- Copy data from single row and column in 3D table to
+# 1-D image.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 26-Nov-96 - Task created (I.Busko)
+
+procedure txicpy (itp, im, irow, icp, datatype, size)
+
+pointer itp # i: pointer to descriptor of input table
+pointer im # i: pointer to output image
+int irow # i: row in input table
+pointer icp # i: array of pointers for input columns
+int datatype # i: data type
+int size # i: array size
+#--
+int nbuf
+pointer sp, bufin, bufout, errmsg, colname
+
+string badtype "Unsupported column data type (%s)"
+
+pointer impl1s(), impl1i(), impl1r(), impl1d()
+begin
+ call smark (sp)
+ call salloc (bufin, size, datatype)
+
+ switch (datatype) {
+ case TY_SHORT:
+ call tcs_rdarys (itp, icp, irow, size, nbuf, Mems[bufin])
+ bufout = impl1s (im)
+ call amovs (Mems[bufin], Mems[bufout], size)
+ case TY_INT,TY_LONG:
+ call tcs_rdaryi (itp, icp, irow, size, nbuf, Memi[bufin])
+ bufout = impl1i (im)
+ call amovi (Memi[bufin], Memi[bufout], size)
+ case TY_REAL:
+ call tcs_rdaryr (itp, icp, irow, size, nbuf, Memr[bufin])
+ bufout = impl1r (im)
+ call amovr (Memr[bufin], Memr[bufout], size)
+ case TY_DOUBLE:
+ call tcs_rdaryd (itp, icp, irow, size, nbuf, Memd[bufin])
+ bufout = impl1d (im)
+ call amovd (Memd[bufin], Memd[bufout], size)
+ default:
+ # Unsupported type, write error message
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+ call tcs_txtinfo (icp, TBL_COL_NAME, Memc[colname], SZ_COLNAME)
+ call sprintf (Memc[errmsg], SZ_LINE, badtype)
+ call pargstr (Memc[colname])
+ call error (1, Memc[errmsg])
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/threed/tximage/txihc.x b/pkg/utilities/nttools/threed/tximage/txihc.x
new file mode 100644
index 00000000..0f546b43
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tximage/txihc.x
@@ -0,0 +1,53 @@
+#
+# TXIHC -- Write basic column info into image header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 26-Nov-96 - Task created (I.Busko)
+# 03-Jan-97 - Revised after code review (IB)
+
+
+procedure txihc (im, colnum, colname, colunits, colfmt, lenfmt)
+
+pointer im # i: pointer to image
+int colnum # i: column number in input table
+char colname[ARB] # i: column name
+char colunits[ARB] # i: column units
+char colfmt[ARB] # i: column format
+int lenfmt # i: length of format string
+#--
+pointer sp, cu, cf, text
+
+begin
+ call smark (sp)
+ call salloc (text, SZ_LINE, TY_CHAR)
+ call salloc (cu, SZ_LINE, TY_CHAR)
+ call salloc (cf, SZ_LINE, TY_CHAR)
+
+ # Empty units or format string are encoded as "default".
+ if (colunits[1] == EOS)
+ call strcpy ("default", Memc[cu], SZ_LINE)
+ else
+ call strcpy (colunits, Memc[cu], SZ_LINE)
+ if (colfmt[1] == EOS)
+ call strcpy ("default", Memc[cf], SZ_LINE)
+ else
+ call strcpy (colfmt, Memc[cf], SZ_LINE)
+
+ # Assemble keyword value.
+ call sprintf (Memc[text], SZ_LINE, "%d %s %s %s %d")
+ call pargi (colnum)
+ call pargstr (colname)
+ call pargstr (Memc[cu])
+ call pargstr (Memc[cf])
+ call pargi (lenfmt)
+
+ # Write keyword into header.
+ call imastr (im, "COLDATA", Memc[text])
+ call sfree (sp)
+end
+
diff --git a/pkg/utilities/nttools/threed/tximage/tximage.x b/pkg/utilities/nttools/threed/tximage/tximage.x
new file mode 100644
index 00000000..c8575950
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tximage/tximage.x
@@ -0,0 +1,117 @@
+include <error.h>
+
+# TXIMAGE -- Extract image from 3D table row.
+
+# Input tables are given by a filename template list. All row/column
+# selection on input tables is performed by bracket-enclosed selectors
+# appended to the file name. The output is either a matching list of
+# images or a directory. Since one input table specification can generate
+# multiple output images, a naming scheme for these is defined as follows:
+#
+# - if output name is a directory:
+# output image names are built from input table names appended with
+# a _rXXX suffix, where XXX is the row number in the input file
+# where the data comes from.
+#
+# - if output image name comes from a paired root file name list:
+# same suffixing scheme as above, but using the root file name
+# extracted from the list.
+#
+# - if only one row is selected:
+# no suffixing takes place.
+#
+#
+# This code is a re-use of B.Simon's 04-Nov-94 version of tcopy.
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 26-Nov-96 - Task created (I.Busko)
+# 03-Jan-97 - Revised after code review (IB)
+
+
+procedure t_tximage()
+
+char tablist1[SZ_LINE] # Input table list
+char imlist2[SZ_LINE] # Output image list
+bool verbose # Print operations ?
+
+char table1[SZ_PATHNAME] # Input table name
+char image2[SZ_PATHNAME] # Output table name
+char rootname[SZ_PATHNAME] # Root name
+char dirname[SZ_PATHNAME] # Directory name
+
+int list1, list2, root_len
+pointer sp
+
+int imtopen(), imtgetim(), imtlen()
+int fnldir(), isdirectory()
+bool clgetb(), streq()
+
+begin
+ # Get input and output table template lists.
+
+ call clgstr ("intable", tablist1, SZ_LINE)
+ call clgstr ("output", imlist2, SZ_LINE)
+ verbose = clgetb ("verbose")
+
+ # Check if the output string is a directory.
+
+ if (isdirectory (imlist2, dirname, SZ_PATHNAME) > 0) {
+ list1 = imtopen (tablist1)
+ while (imtgetim (list1, table1, SZ_PATHNAME) != EOF) {
+ call smark (sp)
+
+ # Place the input table name without a directory in
+ # string rootname.
+
+ call get_root (table1, image2, SZ_PATHNAME)
+ root_len = fnldir (image2, rootname, SZ_PATHNAME)
+ call strcpy (image2[root_len + 1], rootname, SZ_PATHNAME)
+
+ call strcpy (dirname, image2, SZ_PATHNAME)
+ call strcat (rootname, image2, SZ_PATHNAME)
+
+ iferr (call txione (table1, image2, verbose))
+ call erract (EA_WARN)
+
+ call sfree (sp)
+ }
+ call imtclose (list1)
+
+ } else {
+ # Expand the input and output table lists.
+
+ list1 = imtopen (tablist1)
+ list2 = imtopen (imlist2)
+
+ if (imtlen (list1) != imtlen (list2)) {
+ call imtclose (list1)
+ call imtclose (list2)
+ call error (1, "Number of input and output files not the same")
+ }
+
+ # Expand each table.
+
+ while ((imtgetim (list1, table1, SZ_PATHNAME) != EOF) &&
+ (imtgetim (list2, image2, SZ_PATHNAME) != EOF)) {
+
+ call smark (sp)
+
+ if (streq (table1, image2)) {
+ call eprintf ("can't expand table to itself: %s\n")
+ call pargstr (table1)
+ next
+ }
+ iferr (call txione (table1, image2, verbose))
+ call erract (EA_WARN)
+
+ call sfree (sp)
+ }
+
+ call imtclose (list1)
+ call imtclose (list2)
+ }
+end
diff --git a/pkg/utilities/nttools/threed/tximage/txione.x b/pkg/utilities/nttools/threed/tximage/txione.x
new file mode 100644
index 00000000..fa03714d
--- /dev/null
+++ b/pkg/utilities/nttools/threed/tximage/txione.x
@@ -0,0 +1,214 @@
+include <tbset.h>
+include <imhdr.h>
+
+# TXIONE -- Extract images from a single input 3D table.
+#
+#
+#
+# This code is adapted from B.Simon's 04-Nov-94 version of tcopy.
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-96 - Task created (I.Busko)
+# 16-Dec-96 - Add ORIG_ROW keyword (IB).
+# 03-Jan-97 - Revised after code review (IB)
+# 17-Mar-97 - Added selrows call (IB)
+# 8-Apr-02 - Remove the call to whatfile (P. Hodge)
+
+
+procedure txione (input, output, verbose)
+
+char input[ARB] # i: input table name
+char output[ARB] # i: output table name
+bool verbose # i: print operations ?
+#--
+int numrow, numcol, numptr, irow, nrows
+int colnum, datatype, lendata, lenfmt
+pointer sp, root, extend, rowselect, colselect, colname, colunits, colfmt
+pointer errmsg, icp, itp, im, colptr, pcode
+pointer newname
+bool suffix
+
+string noarray "No valid image data in %s"
+string nocols "Column name not found (%s)"
+string manycols "Too many columns (%s)"
+
+errchk tbtopn, trsopen, trseval
+
+bool trseval()
+int tbpsta(), tcs_totsize(), selrows()
+pointer tbtopn(), tcs_column, trsopen(), immap()
+
+begin
+ # Allocate memory for temporary strings.
+ call smark (sp)
+ call salloc (root, SZ_FNAME, TY_CHAR)
+ call salloc (newname, SZ_FNAME, TY_CHAR)
+ call salloc (extend, SZ_FNAME, TY_CHAR)
+ call salloc (rowselect, SZ_FNAME, TY_CHAR)
+ call salloc (colselect, SZ_FNAME, TY_CHAR)
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+ call salloc (colunits, SZ_COLUNITS, TY_CHAR)
+ call salloc (colfmt, SZ_COLFMT, TY_CHAR)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ # Break input file name into bracketed selectors.
+ call rdselect (input, Memc[root], Memc[rowselect],
+ Memc[colselect], SZ_FNAME)
+
+ # Open input table and get some info about it.
+ itp = tbtopn (Memc[root], READ_ONLY, NULL)
+ numrow = tbpsta (itp, TBL_NROWS)
+ numcol = tbpsta (itp, TBL_NCOLS)
+
+ # Find how many rows were requested by row selector.
+ # If only one, turn off suffixing.
+ nrows = selrows (itp, Memc[rowselect])
+ if (nrows == 1)
+ suffix = false
+ else
+ suffix = true
+
+ # Create array of column pointers from column selector.
+ # This is necessary to avoid segv in case more than one
+ # column selector is passed to the task.
+ call malloc (colptr, numcol, TY_INT)
+ call tcs_open (itp, Memc[colselect], Memi[colptr], numptr, numcol)
+
+ # Take an error exit if either no columns were matched or
+ # more than one column was matched.
+ if (numptr == 0) {
+ call sprintf (Memc[errmsg], SZ_LINE, nocols)
+ call pargstr (input)
+ call error (1, Memc[errmsg])
+ } else if (numptr != 1) {
+ call sprintf (Memc[errmsg], SZ_LINE, manycols)
+ call pargstr (input)
+ call error (1, Memc[errmsg])
+ }
+
+ # Loop over selected rows on input table,
+ # creating an image for each row.
+ pcode = trsopen (itp, Memc[rowselect])
+ do irow = 1, numrow {
+ if (trseval (itp, irow, pcode)) {
+
+ # Append suffix to output name.
+ if (suffix)
+ call txisuff (output, Memc[newname], irow)
+ else
+ call strcpy (output, Memc[newname], SZ_FNAME)
+
+ if (verbose) {
+ call eprintf ("%s row=%d -> %s\n")
+ call pargstr (input)
+ call pargi (irow)
+ call pargstr (Memc[newname])
+ }
+
+ # Get column information.
+ icp = tcs_column (Memi[colptr])
+ call tbcinf (icp, colnum, Memc[colname], Memc[colunits],
+ Memc[colfmt], datatype, lendata, lenfmt)
+
+ # Take error exit if scalar or invalid type.
+ if ((lendata < 2) || (datatype < 0) || (datatype == TY_BOOL)){
+ call sprintf (Memc[errmsg], SZ_LINE, noarray)
+ call pargstr (input)
+ call error (1, Memc[errmsg])
+ }
+
+ # Open output image
+ im = immap (Memc[newname], NEW_IMAGE, NULL)
+ IM_NDIM(im) = 1
+
+ # Copy array to image.
+ IM_LEN(im,1) = tcs_totsize (Memi[colptr])
+ IM_PIXTYPE(im) = datatype
+ call txicpy (itp, im, irow, Memi[colptr], datatype,
+ IM_LEN(im,1))
+
+ # Write column data into header.
+ call txihc (im, colnum, Memc[colname], Memc[colunits],
+ Memc[colfmt], lenfmt)
+
+ # Write row number into header.
+ call imaddi (im, "ORIG_ROW", irow)
+
+ # Close output.
+ call imunmap (im)
+ }
+ }
+
+ # Free memory associated with columns.
+ call tcs_close (Memi[colptr], numptr)
+ call mfree (colptr, TY_INT)
+
+ # Close row selector structure and input table.
+ call trsclose (pcode)
+ call tbtclo (itp)
+
+ call sfree (sp)
+end
+
+
+
+
+# Appends sufix to output image name.
+
+procedure txisuff (filename, newname, row)
+
+char filename[ARB] # i: output image name
+char newname[ARB] # o: output image name with suffix
+int row # i: row number
+
+pointer sp, ext, suffix
+int dot, i, j
+
+int strcmp(), strldxs(), strlen()
+
+begin
+ call smark (sp)
+ call salloc (suffix, SZ_LINE, TY_CHAR)
+ call salloc (ext, SZ_LINE, TY_CHAR)
+
+ # Get rid of any appendages except the extension.
+ call imgcluster (filename, newname, SZ_FNAME)
+
+ # Valid extensions are .??h, .fit and .fits
+ # Everything else is part of the root file name.
+
+ # Detect extension.
+ Memc[ext] = EOS
+ dot = strldxs (".", newname)
+ if (dot != 0) {
+ i = dot
+ j = 0
+ while (newname[i] != EOS) {
+ Memc[ext+j] = newname[i]
+ j = j + 1
+ i = i + 1
+ }
+ Memc[ext+j] = EOS
+ }
+
+ # If valid extension, remove it from name.
+ if ( ((strlen (Memc[ext]) == 4) && (Memc[ext+3] == 'h')) ||
+ (strcmp (Memc[ext], ".fit") == 0) ||
+ (strcmp (Memc[ext], ".fits") == 0) )
+ newname[dot] = EOS
+ else
+ Memc[ext] = EOS
+
+ # Build suffix.
+ call sprintf (Memc[suffix], SZ_LINE, "_r%04d")
+ call pargi (row)
+
+ # Append suffix and extension to root name.
+ call strcat (Memc[suffix], newname, SZ_FNAME)
+ call strcat (Memc[ext], newname, SZ_FNAME)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/threed/txtable.par b/pkg/utilities/nttools/threed/txtable.par
new file mode 100644
index 00000000..5f784362
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable.par
@@ -0,0 +1,6 @@
+intable,s,a,"",,,"Input tables"
+outtable,s,a,"",,,"Output tables or directory"
+compact,b,h,yes,,,"Write scalars into header ?"
+verbose,b,h,yes,,,"Print operations performed ?"
+version,s,h,"7Feb2000",,,
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/threed/txtable/generic/mkpkg b/pkg/utilities/nttools/threed/txtable/generic/mkpkg
new file mode 100644
index 00000000..d82c36d2
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/generic/mkpkg
@@ -0,0 +1,22 @@
+# Update the generic routines.
+
+default:
+ $checkout libpkg.a ../../
+ $update libpkg.a
+ $checkin libpkg.a ../../
+$exit
+
+libpkg.a:
+ txtcptb.x
+ txtcptc.x
+ txtcptd.x
+ txtcpti.x
+ txtcptr.x
+ txtcpts.x
+ txthvb.x
+ txthvc.x
+ txthvd.x
+ txthvi.x
+ txthvr.x
+ txthvs.x
+ ;
diff --git a/pkg/utilities/nttools/threed/txtable/generic/txtcptb.x b/pkg/utilities/nttools/threed/txtable/generic/txtcptb.x
new file mode 100644
index 00000000..6bed2c52
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/generic/txtcptb.x
@@ -0,0 +1,34 @@
+#
+# TXTCPT -- Copy data to output table. If array, copy into column.
+# If scalar, either write as column or write into header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-1996 - Task created (I.Busko)
+# 7-Feb-2000 - For datatype = 'c', make buf an array of strings (P.Hodge)
+
+procedure txtcptb (otp, ocp, buf, start, nbuf, icol, compact)
+
+pointer otp # i: table descriptor
+pointer ocp # i: column descriptor
+bool buf[ARB]
+int start # i: starting row in output table
+int nbuf # i: number of elements to write into output
+int icol # i: column number in input table
+bool compact # i: write scalars as header keywords ?
+#--
+
+begin
+ if (ocp != NULL) {
+
+ call tbcptb (otp, ocp, buf, start, nbuf)
+
+ } else if (compact) {
+
+ call txthvb (otp, icol, buf[1])
+ }
+end
diff --git a/pkg/utilities/nttools/threed/txtable/generic/txtcptc.x b/pkg/utilities/nttools/threed/txtable/generic/txtcptc.x
new file mode 100644
index 00000000..10cdc4cb
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/generic/txtcptc.x
@@ -0,0 +1,35 @@
+#
+# TXTCPT -- Copy data to output table. If array, copy into column.
+# If scalar, either write as column or write into header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-1996 - Task created (I.Busko)
+# 7-Feb-2000 - For datatype = 'c', make buf an array of strings (P.Hodge)
+
+procedure txtcptt (otp, ocp, buf, maxch, start, nbuf, icol, compact)
+
+pointer otp # i: table descriptor
+pointer ocp # i: column descriptor
+char buf[maxch,ARB] # i: array of values
+int maxch # i: max length of string
+int start # i: starting row in output table
+int nbuf # i: number of elements to write into output
+int icol # i: column number in input table
+bool compact # i: write scalars as header keywords ?
+#--
+
+begin
+ if (ocp != NULL) {
+
+ call tbcptt (otp, ocp, buf, maxch, start, nbuf)
+
+ } else if (compact) {
+
+ call txthvt (otp, icol, buf)
+ }
+end
diff --git a/pkg/utilities/nttools/threed/txtable/generic/txtcptd.x b/pkg/utilities/nttools/threed/txtable/generic/txtcptd.x
new file mode 100644
index 00000000..3af0d7ac
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/generic/txtcptd.x
@@ -0,0 +1,34 @@
+#
+# TXTCPT -- Copy data to output table. If array, copy into column.
+# If scalar, either write as column or write into header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-1996 - Task created (I.Busko)
+# 7-Feb-2000 - For datatype = 'c', make buf an array of strings (P.Hodge)
+
+procedure txtcptd (otp, ocp, buf, start, nbuf, icol, compact)
+
+pointer otp # i: table descriptor
+pointer ocp # i: column descriptor
+double buf[ARB]
+int start # i: starting row in output table
+int nbuf # i: number of elements to write into output
+int icol # i: column number in input table
+bool compact # i: write scalars as header keywords ?
+#--
+
+begin
+ if (ocp != NULL) {
+
+ call tbcptd (otp, ocp, buf, start, nbuf)
+
+ } else if (compact) {
+
+ call txthvd (otp, icol, buf[1])
+ }
+end
diff --git a/pkg/utilities/nttools/threed/txtable/generic/txtcpti.x b/pkg/utilities/nttools/threed/txtable/generic/txtcpti.x
new file mode 100644
index 00000000..552e1e7a
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/generic/txtcpti.x
@@ -0,0 +1,34 @@
+#
+# TXTCPT -- Copy data to output table. If array, copy into column.
+# If scalar, either write as column or write into header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-1996 - Task created (I.Busko)
+# 7-Feb-2000 - For datatype = 'c', make buf an array of strings (P.Hodge)
+
+procedure txtcpti (otp, ocp, buf, start, nbuf, icol, compact)
+
+pointer otp # i: table descriptor
+pointer ocp # i: column descriptor
+int buf[ARB]
+int start # i: starting row in output table
+int nbuf # i: number of elements to write into output
+int icol # i: column number in input table
+bool compact # i: write scalars as header keywords ?
+#--
+
+begin
+ if (ocp != NULL) {
+
+ call tbcpti (otp, ocp, buf, start, nbuf)
+
+ } else if (compact) {
+
+ call txthvi (otp, icol, buf[1])
+ }
+end
diff --git a/pkg/utilities/nttools/threed/txtable/generic/txtcptr.x b/pkg/utilities/nttools/threed/txtable/generic/txtcptr.x
new file mode 100644
index 00000000..956bc45e
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/generic/txtcptr.x
@@ -0,0 +1,34 @@
+#
+# TXTCPT -- Copy data to output table. If array, copy into column.
+# If scalar, either write as column or write into header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-1996 - Task created (I.Busko)
+# 7-Feb-2000 - For datatype = 'c', make buf an array of strings (P.Hodge)
+
+procedure txtcptr (otp, ocp, buf, start, nbuf, icol, compact)
+
+pointer otp # i: table descriptor
+pointer ocp # i: column descriptor
+real buf[ARB]
+int start # i: starting row in output table
+int nbuf # i: number of elements to write into output
+int icol # i: column number in input table
+bool compact # i: write scalars as header keywords ?
+#--
+
+begin
+ if (ocp != NULL) {
+
+ call tbcptr (otp, ocp, buf, start, nbuf)
+
+ } else if (compact) {
+
+ call txthvr (otp, icol, buf[1])
+ }
+end
diff --git a/pkg/utilities/nttools/threed/txtable/generic/txtcpts.x b/pkg/utilities/nttools/threed/txtable/generic/txtcpts.x
new file mode 100644
index 00000000..d8b805fa
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/generic/txtcpts.x
@@ -0,0 +1,34 @@
+#
+# TXTCPT -- Copy data to output table. If array, copy into column.
+# If scalar, either write as column or write into header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-1996 - Task created (I.Busko)
+# 7-Feb-2000 - For datatype = 'c', make buf an array of strings (P.Hodge)
+
+procedure txtcpts (otp, ocp, buf, start, nbuf, icol, compact)
+
+pointer otp # i: table descriptor
+pointer ocp # i: column descriptor
+short buf[ARB]
+int start # i: starting row in output table
+int nbuf # i: number of elements to write into output
+int icol # i: column number in input table
+bool compact # i: write scalars as header keywords ?
+#--
+
+begin
+ if (ocp != NULL) {
+
+ call tbcpts (otp, ocp, buf, start, nbuf)
+
+ } else if (compact) {
+
+ call txthvs (otp, icol, buf[1])
+ }
+end
diff --git a/pkg/utilities/nttools/threed/txtable/generic/txthvb.x b/pkg/utilities/nttools/threed/txtable/generic/txthvb.x
new file mode 100644
index 00000000..eb7af9ad
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/generic/txthvb.x
@@ -0,0 +1,30 @@
+#
+# TXTHV -- Write scalar value into header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-96 - Task created (I.Busko)
+
+procedure txthvb (otp, col, buf)
+
+pointer otp # i: table descriptor
+int col # i: column number in input table
+bool buf
+#--
+pointer keyword
+
+begin
+ # Use original column number to build keyword name.
+ call malloc (keyword, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[keyword], SZ_LINE, "TCV_%03d")
+ call pargi (col)
+
+ call tbhadb (otp, Memc[keyword], buf)
+
+ call mfree (keyword, TY_CHAR)
+end
+
diff --git a/pkg/utilities/nttools/threed/txtable/generic/txthvc.x b/pkg/utilities/nttools/threed/txtable/generic/txthvc.x
new file mode 100644
index 00000000..6ffb3773
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/generic/txthvc.x
@@ -0,0 +1,30 @@
+#
+# TXTHV -- Write scalar value into header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-96 - Task created (I.Busko)
+
+procedure txthvt (otp, col, buf)
+
+pointer otp # i: table descriptor
+int col # i: column number in input table
+char buf[ARB] # i: value to be written
+#--
+pointer keyword
+
+begin
+ # Use original column number to build keyword name.
+ call malloc (keyword, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[keyword], SZ_LINE, "TCV_%03d")
+ call pargi (col)
+
+ call tbhadt (otp, Memc[keyword], buf)
+
+ call mfree (keyword, TY_CHAR)
+end
+
diff --git a/pkg/utilities/nttools/threed/txtable/generic/txthvd.x b/pkg/utilities/nttools/threed/txtable/generic/txthvd.x
new file mode 100644
index 00000000..a074396a
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/generic/txthvd.x
@@ -0,0 +1,30 @@
+#
+# TXTHV -- Write scalar value into header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-96 - Task created (I.Busko)
+
+procedure txthvd (otp, col, buf)
+
+pointer otp # i: table descriptor
+int col # i: column number in input table
+double buf
+#--
+pointer keyword
+
+begin
+ # Use original column number to build keyword name.
+ call malloc (keyword, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[keyword], SZ_LINE, "TCV_%03d")
+ call pargi (col)
+
+ call tbhadd (otp, Memc[keyword], buf)
+
+ call mfree (keyword, TY_CHAR)
+end
+
diff --git a/pkg/utilities/nttools/threed/txtable/generic/txthvi.x b/pkg/utilities/nttools/threed/txtable/generic/txthvi.x
new file mode 100644
index 00000000..9df4ae94
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/generic/txthvi.x
@@ -0,0 +1,30 @@
+#
+# TXTHV -- Write scalar value into header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-96 - Task created (I.Busko)
+
+procedure txthvi (otp, col, buf)
+
+pointer otp # i: table descriptor
+int col # i: column number in input table
+int buf
+#--
+pointer keyword
+
+begin
+ # Use original column number to build keyword name.
+ call malloc (keyword, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[keyword], SZ_LINE, "TCV_%03d")
+ call pargi (col)
+
+ call tbhadi (otp, Memc[keyword], buf)
+
+ call mfree (keyword, TY_CHAR)
+end
+
diff --git a/pkg/utilities/nttools/threed/txtable/generic/txthvr.x b/pkg/utilities/nttools/threed/txtable/generic/txthvr.x
new file mode 100644
index 00000000..17c4693e
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/generic/txthvr.x
@@ -0,0 +1,30 @@
+#
+# TXTHV -- Write scalar value into header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-96 - Task created (I.Busko)
+
+procedure txthvr (otp, col, buf)
+
+pointer otp # i: table descriptor
+int col # i: column number in input table
+real buf
+#--
+pointer keyword
+
+begin
+ # Use original column number to build keyword name.
+ call malloc (keyword, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[keyword], SZ_LINE, "TCV_%03d")
+ call pargi (col)
+
+ call tbhadr (otp, Memc[keyword], buf)
+
+ call mfree (keyword, TY_CHAR)
+end
+
diff --git a/pkg/utilities/nttools/threed/txtable/generic/txthvs.x b/pkg/utilities/nttools/threed/txtable/generic/txthvs.x
new file mode 100644
index 00000000..847fbceb
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/generic/txthvs.x
@@ -0,0 +1,30 @@
+#
+# TXTHV -- Write scalar value into header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-96 - Task created (I.Busko)
+
+procedure txthvs (otp, col, buf)
+
+pointer otp # i: table descriptor
+int col # i: column number in input table
+short buf
+#--
+pointer keyword
+
+begin
+ # Use original column number to build keyword name.
+ call malloc (keyword, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[keyword], SZ_LINE, "TCV_%03d")
+ call pargi (col)
+
+ call tbhadi (otp, Memc[keyword], int(buf))
+
+ call mfree (keyword, TY_CHAR)
+end
+
diff --git a/pkg/utilities/nttools/threed/txtable/mkpkg b/pkg/utilities/nttools/threed/txtable/mkpkg
new file mode 100644
index 00000000..b6c5e53a
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/mkpkg
@@ -0,0 +1,34 @@
+# Update the txtable application code in the threed package library.
+# Author: I.Busko, 22-Nov-1996
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+# This module is called from the threed mkpkg.
+generic:
+ $ifnfile (generic/txthvi.x)
+ $generic -k -p generic/ -t bcsird txthv.gx
+ $endif
+ $ifolder (generic/txthvi.x, txthv.gx)
+ $generic -k -p generic/ -t bcsird txthv.gx
+ $endif
+ $ifnfile (generic/txtcpti.x)
+ $generic -k -p generic/ -t bcsird txtcpt.gx
+ $endif
+ $ifolder (generic/txtcpti.x, txtcpt.gx)
+ $generic -k -p generic/ -t bcsird txtcpt.gx
+ $endif
+ ;
+
+libpkg.a:
+ @generic
+ txtable.x <error.h>
+ txtone.x <tbset.h>
+ txtcpy.x <tbset.h>
+ txtcpyco.x
+ txtcpysc.x
+ txthc.x
+ ;
+
diff --git a/pkg/utilities/nttools/threed/txtable/txtable.x b/pkg/utilities/nttools/threed/txtable/txtable.x
new file mode 100644
index 00000000..f56db247
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/txtable.x
@@ -0,0 +1,121 @@
+include <error.h>
+
+# TXTABLE -- Extract 2D tables from 3D table rows.
+
+# Input tables are given by a filename template list. All row/column
+# selection on input tables is performed by bracket-enclosed selectors
+# appended to the file name. The output is either a matching list of
+# tables or a directory. Output table names cannot have row/column
+# selectors. Since one input table specification can generate multiple
+# output tables, a naming scheme for these is defined as follows:
+#
+# - if output name is a directory:
+# output table names are built from input table names appended with
+# a _rXXX suffix, where XXX is the row number in the input file
+# where the data comes from.
+#
+# - if output file name comes from a paired root file name list:
+# same suffixing scheme as above, but using the root file name
+# extracted from the list.
+#
+# - if only one row is selected:
+# no suffixing takes place.
+#
+#
+# This code is a re-use of B.Simon's 04-Nov-94 version of tcopy.
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-96 - Task created (I.Busko)
+# 03-Jan-97 - Revised after code review (IB)
+
+
+procedure t_txtable()
+
+char tablist1[SZ_LINE] # Input table list
+char tablist2[SZ_LINE] # Output table list
+bool compact # Put scalars in header ?
+bool verbose # Print operations ?
+
+char table1[SZ_PATHNAME] # Input table name
+char table2[SZ_PATHNAME] # Output table name
+char rootname[SZ_PATHNAME] # Root name
+char dirname[SZ_PATHNAME] # Directory name
+
+int list1, list2, root_len
+pointer sp
+
+int imtopen(), imtgetim(), imtlen()
+int fnldir(), isdirectory()
+bool clgetb(), streq()
+
+begin
+ # Get input and output table template lists.
+
+ call clgstr ("intable", tablist1, SZ_LINE)
+ call clgstr ("outtable", tablist2, SZ_LINE)
+ compact = clgetb ("compact")
+ verbose = clgetb ("verbose")
+
+ # Check if the output string is a directory.
+
+ if (isdirectory (tablist2, dirname, SZ_PATHNAME) > 0 &&
+ !streq (tablist2, "STDOUT")) {
+ list1 = imtopen (tablist1)
+ while (imtgetim (list1, table1, SZ_PATHNAME) != EOF) {
+ call smark (sp)
+
+ # Place the input table name without a directory in
+ # string rootname.
+
+ call get_root (table1, table2, SZ_PATHNAME)
+ root_len = fnldir (table2, rootname, SZ_PATHNAME)
+ call strcpy (table2[root_len + 1], rootname, SZ_PATHNAME)
+
+ call strcpy (dirname, table2, SZ_PATHNAME)
+ call strcat (rootname, table2, SZ_PATHNAME)
+
+ iferr (call txtone (table1, table2, verbose, compact))
+ call erract (EA_WARN)
+
+ call sfree (sp)
+ }
+ call imtclose (list1)
+
+ } else {
+ # Expand the input and output table lists.
+
+ list1 = imtopen (tablist1)
+ list2 = imtopen (tablist2)
+
+ if (imtlen (list1) != imtlen (list2)) {
+ call imtclose (list1)
+ call imtclose (list2)
+ call error (1, "Number of input and output tables not the same")
+ }
+
+ # Expand each table.
+
+ while ((imtgetim (list1, table1, SZ_PATHNAME) != EOF) &&
+ (imtgetim (list2, table2, SZ_PATHNAME) != EOF)) {
+
+ call smark (sp)
+
+ if (streq (table1, table2)) {
+ call eprintf ("can't expand table to itself: %s\n")
+ call pargstr (table1)
+ next
+ }
+ iferr (call txtone (table1, table2, verbose, compact))
+ call erract (EA_WARN)
+
+ call sfree (sp)
+ }
+
+ call imtclose (list1)
+ call imtclose (list2)
+ }
+end
diff --git a/pkg/utilities/nttools/threed/txtable/txtcpt.gx b/pkg/utilities/nttools/threed/txtable/txtcpt.gx
new file mode 100644
index 00000000..9a8ae930
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/txtcpt.gx
@@ -0,0 +1,53 @@
+#
+# TXTCPT -- Copy data to output table. If array, copy into column.
+# If scalar, either write as column or write into header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-1996 - Task created (I.Busko)
+# 7-Feb-2000 - For datatype = 'c', make buf an array of strings (P.Hodge)
+
+$if (datatype == c)
+procedure txtcptt (otp, ocp, buf, maxch, start, nbuf, icol, compact)
+$else
+procedure txtcpt$t (otp, ocp, buf, start, nbuf, icol, compact)
+$endif
+
+pointer otp # i: table descriptor
+pointer ocp # i: column descriptor
+$if (datatype == c)
+char buf[maxch,ARB] # i: array of values
+$else
+PIXEL buf[ARB]
+$endif
+$if (datatype == c)
+int maxch # i: max length of string
+$endif
+int start # i: starting row in output table
+int nbuf # i: number of elements to write into output
+int icol # i: column number in input table
+bool compact # i: write scalars as header keywords ?
+#--
+
+begin
+ if (ocp != NULL) {
+
+ $if (datatype == c)
+ call tbcptt (otp, ocp, buf, maxch, start, nbuf)
+ $else
+ call tbcpt$t (otp, ocp, buf, start, nbuf)
+ $endif
+
+ } else if (compact) {
+
+ $if (datatype == c)
+ call txthvt (otp, icol, buf)
+ $else
+ call txthv$t (otp, icol, buf[1])
+ $endif
+ }
+end
diff --git a/pkg/utilities/nttools/threed/txtable/txtcpy.x b/pkg/utilities/nttools/threed/txtable/txtcpy.x
new file mode 100644
index 00000000..9a54898a
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/txtcpy.x
@@ -0,0 +1,94 @@
+include <tbset.h>
+
+# TXTCPY -- Copy data from single row in 3D table to columns
+# in the output 2D table.
+#
+#
+# This code is adapted from B.Simon's 04-Nov-94 version of tcopy.
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-96 - Task created (I.Busko)
+
+
+procedure txtcpy (itp, otp, irow, icp, ocp, ncols, compact)
+
+pointer itp # i: pointer to descriptor of input table
+pointer otp # i: pointer to descriptor of output table
+int irow # i: row in input table
+pointer icp[ncols] # i: array of pointers for input columns
+pointer ocp[ncols] # i: array of pointers for output columns
+int ncols # i: number of columns in input table
+bool compact # i: write scalars as header keywords ?
+#--
+int icol, dlen, dtype, maxlen, maxch, nbuf
+pointer sp, buf, errmsg, colname
+
+string badtype "Unsupported column data type (%s)"
+
+int tcs_intinfo(), tcs_totsize()
+
+begin
+ # Number of rows in output table must match the
+ # largest array size in input table.
+ maxlen = 0
+ do icol = 1, ncols {
+ dlen = tcs_totsize (icp[icol])
+ if (dlen > maxlen)
+ maxlen = dlen
+ }
+
+ # Main loop: process each column.
+ do icol = 1, ncols {
+
+ # Determine datatype of table column
+ # and allocate a buffer to match.
+ dtype = tcs_intinfo (icp[icol], TBL_COL_DATATYPE)
+ maxch = 1
+ if (dtype < 0) {
+ maxch = - dtype
+ dtype = TY_CHAR
+ }
+ call smark (sp)
+ call salloc (buf, maxlen*(maxch + 1), dtype)
+
+ # Read data from input table and
+ # write it to output table.
+ switch (dtype) {
+ case TY_BOOL:
+ call tcs_rdaryb (itp, icp[icol], irow, maxlen, nbuf, Memb[buf])
+ call txtcptb (otp, ocp[icol], Memb[buf], 1, nbuf, icol, compact)
+ case TY_CHAR:
+ call tcs_rdaryt (itp, icp[icol], irow, maxch, maxlen,
+ nbuf, Memc[buf])
+ call txtcptt (otp, ocp[icol], Memc[buf], maxch, 1, nbuf,
+ icol, compact)
+ case TY_SHORT:
+ call tcs_rdarys (itp, icp[icol], irow, maxlen, nbuf, Mems[buf])
+ call txtcpts (otp, ocp[icol], Mems[buf], 1, nbuf, icol, compact)
+ case TY_INT, TY_LONG:
+ call tcs_rdaryi (itp, icp[icol], irow, maxlen, nbuf, Memi[buf])
+ call txtcpti (otp, ocp[icol], Memi[buf], 1, nbuf, icol, compact)
+ case TY_REAL:
+ call tcs_rdaryr (itp, icp[icol], irow, maxlen, nbuf, Memr[buf])
+ call txtcptr (otp, ocp[icol], Memr[buf], 1, nbuf, icol, compact)
+ case TY_DOUBLE:
+ call tcs_rdaryd (itp, icp[icol], irow, maxlen, nbuf, Memd[buf])
+ call txtcptd (otp, ocp[icol], Memd[buf], 1, nbuf, icol, compact)
+ default:
+ # Unsupported type, write error message
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+ call tcs_txtinfo (icp[icol], TBL_COL_NAME,
+ Memc[colname], SZ_COLNAME)
+ call sprintf (Memc[errmsg], SZ_LINE, badtype)
+ call pargstr (Memc[colname])
+ call error (1, Memc[errmsg])
+ }
+
+ call sfree (sp)
+ }
+end
diff --git a/pkg/utilities/nttools/threed/txtable/txtcpyco.x b/pkg/utilities/nttools/threed/txtable/txtcpyco.x
new file mode 100644
index 00000000..c74943d4
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/txtcpyco.x
@@ -0,0 +1,45 @@
+
+# TXTCPYCO -- Copy column information
+#
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 03-Jan-97 - Implemented after code review (IB)
+
+
+procedure txtcpyco (otp, colptr, newcol, numptr, colname, colunits, colfmt,
+ compact)
+
+pointer otp, colptr, newcol, colname, colunits, colfmt
+int numptr
+bool compact
+#--
+pointer ocp
+int iptr, colnum, datatype, lendata, lenfmt
+
+pointer tcs_column()
+
+begin
+ do iptr = 1, numptr {
+ ocp = tcs_column (Memi[colptr+iptr-1])
+ call tbcinf (ocp, colnum, Memc[colname], Memc[colunits],
+ Memc[colfmt], datatype, lendata, lenfmt)
+
+ # All columns in output are scalar-type !
+ # Column info for input scalars depends on compact mode.
+ # If compact=no, just leave output column as scalar.
+ # If compact=yes, signal input scalar by setting column
+ # pointer to NULL.
+ if (compact && (lendata == 1)) {
+ Memi[newcol+iptr-1] = NULL
+ } else {
+ call tbcdef (otp, ocp, Memc[colname], Memc[colunits],
+ Memc[colfmt], datatype, 1, 1)
+ Memi[newcol+iptr-1] = ocp
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/threed/txtable/txtcpysc.x b/pkg/utilities/nttools/threed/txtable/txtcpysc.x
new file mode 100644
index 00000000..f35f7c54
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/txtcpysc.x
@@ -0,0 +1,34 @@
+
+# TXTCPYSC -- Copy scalar columns in compact mode
+#
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 03-Jan-97 - Implemented after code review (IB)
+
+
+procedure txtcpysc (otp, colptr, newcol, numptr, colname, colunits, colfmt)
+
+pointer otp, colptr, newcol, colname, colunits, colfmt
+int numptr
+
+pointer icp
+int iptr, colnum, datatype, lendata, lenfmt
+
+pointer tcs_column
+
+begin
+ do iptr = 1, numptr {
+ if (Memi[newcol+iptr-1] == NULL) {
+ icp = tcs_column (Memi[colptr+iptr-1])
+ call tbcinf (icp, colnum, Memc[colname], Memc[colunits],
+ Memc[colfmt], datatype, lendata, lenfmt)
+ call txthc (otp, colnum, Memc[colname], Memc[colunits],
+ Memc[colfmt], datatype, lenfmt)
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/threed/txtable/txthc.x b/pkg/utilities/nttools/threed/txtable/txthc.x
new file mode 100644
index 00000000..3e6f8555
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/txthc.x
@@ -0,0 +1,85 @@
+#
+# TXTHC -- Write basic column info into header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 25-Nov-96 - Task created (I.Busko)
+# 03-Jan-97 - Revised after code review (IB)
+
+
+procedure txthc (otp, colnum, colname, colunits, colfmt,
+ datatype, lenfmt)
+
+pointer otp # i: pointer to descriptor of output table
+int colnum # i: column number in input table
+char colname[ARB] # i: column name
+char colunits[ARB] # i: column units
+char colfmt[ARB] # i: column format
+int datatype # i: data type
+int lenfmt # i: length of format string
+#--
+pointer sp, cu, cf, keyword, text, dtype
+int lenstr
+
+begin
+ call smark (sp)
+ call salloc (keyword, SZ_LINE, TY_CHAR)
+ call salloc (text, SZ_LINE, TY_CHAR)
+ call salloc (dtype, SZ_LINE, TY_CHAR)
+ call salloc (cu, SZ_LINE, TY_CHAR)
+ call salloc (cf, SZ_LINE, TY_CHAR)
+
+ # Use original column number to build keyword name.
+ call sprintf (Memc[keyword], SZ_LINE, "TCD_%03d")
+ call pargi (colnum)
+
+ # Data type is encoded as a human-readable character string.
+ if (datatype < 0) {
+ lenstr = -datatype
+ datatype = TY_CHAR
+ }
+ switch (datatype) {
+ case TY_BOOL:
+ call strcpy ("boolean", Memc[dtype], SZ_LINE)
+ case TY_SHORT:
+ call strcpy ("short", Memc[dtype], SZ_LINE)
+ case TY_INT:
+ call strcpy ("integer", Memc[dtype], SZ_LINE)
+ case TY_LONG:
+ call strcpy ("long", Memc[dtype], SZ_LINE)
+ case TY_REAL:
+ call strcpy ("real", Memc[dtype], SZ_LINE)
+ case TY_DOUBLE:
+ call strcpy ("double", Memc[dtype], SZ_LINE)
+ case TY_CHAR:
+ call sprintf (Memc[dtype], SZ_LINE, "character_%d")
+ call pargi (lenstr)
+ }
+
+ # Empty units or format string are encoded as "default".
+ if (colunits[1] == EOS)
+ call strcpy ("default", Memc[cu], SZ_LINE)
+ else
+ call strcpy (colunits, Memc[cu], SZ_LINE)
+ if (colfmt[1] == EOS)
+ call strcpy ("default", Memc[cf], SZ_LINE)
+ else
+ call strcpy (colfmt, Memc[cf], SZ_LINE)
+
+ # Assemble keyword value.
+ call sprintf (Memc[text], SZ_LINE, "%s %s %s %s %d")
+ call pargstr (colname)
+ call pargstr (Memc[cu])
+ call pargstr (Memc[cf])
+ call pargstr (Memc[dtype])
+ call pargi (lenfmt)
+
+ # Write keyword into header.
+ call tbhadt (otp, Memc[keyword], Memc[text])
+ call sfree (sp)
+end
+
diff --git a/pkg/utilities/nttools/threed/txtable/txthv.gx b/pkg/utilities/nttools/threed/txtable/txthv.gx
new file mode 100644
index 00000000..d965f704
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/txthv.gx
@@ -0,0 +1,55 @@
+#
+# TXTHV -- Write scalar value into header.
+#
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-96 - Task created (I.Busko)
+
+$if (datatype == c)
+procedure txthvt (otp, col, buf)
+$else
+procedure txthv$t (otp, col, buf)
+$endif
+
+pointer otp # i: table descriptor
+int col # i: column number in input table
+$if (datatype == c)
+char buf[ARB] # i: value to be written
+$else
+PIXEL buf
+$endif
+#--
+pointer keyword
+
+begin
+ # Use original column number to build keyword name.
+ call malloc (keyword, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[keyword], SZ_LINE, "TCV_%03d")
+ call pargi (col)
+
+ $if (datatype == c)
+ call tbhadt (otp, Memc[keyword], buf)
+ $endif
+ $if (datatype == i)
+ call tbhadi (otp, Memc[keyword], buf)
+ $endif
+ $if (datatype == s)
+ call tbhadi (otp, Memc[keyword], int(buf))
+ $endif
+ $if (datatype == b)
+ call tbhadb (otp, Memc[keyword], buf)
+ $endif
+ $if (datatype == r)
+ call tbhadr (otp, Memc[keyword], buf)
+ $endif
+ $if (datatype == d)
+ call tbhadd (otp, Memc[keyword], buf)
+ $endif
+
+ call mfree (keyword, TY_CHAR)
+end
+
diff --git a/pkg/utilities/nttools/threed/txtable/txtone.x b/pkg/utilities/nttools/threed/txtable/txtone.x
new file mode 100644
index 00000000..d286523d
--- /dev/null
+++ b/pkg/utilities/nttools/threed/txtable/txtone.x
@@ -0,0 +1,227 @@
+include <tbset.h>
+
+# TXTONE -- Extract 2D tables from a single input 3D table.
+#
+#
+# This code is adapted from B.Simon's 04-Nov-94 version of tcopy.
+#
+#
+#
+# Revision history:
+# ----------------
+#
+# 22-Nov-1996 - Task created (I.Busko)
+# 16-Dec-1996 - Add ORIG_ROW keyword (IB).
+# 03-Jan-1997 - Revised after code review (IB)
+# 17-Mar-1997 - Added selrows call (IB)
+# 8-Apr-1999 - Call tbfpri (Phil Hodge)
+# 8-Apr-2002 - Remove the call to whatfile (P. Hodge)
+
+
+procedure txtone (input, output, verbose, compact)
+
+char input[ARB] # i: input table name
+char output[ARB] # i: output table name
+bool compact # i: put scalars in header ?
+bool verbose # i: print operations ?
+#--
+int numrow, numcol, numptr, type, irow, nrows
+int phu_copied # set by tbfpri and ignored
+pointer sp, root, extend, rowselect, colselect, colname, colunits, colfmt
+pointer errmsg, itp, otp, colptr, newcol, pcode
+pointer newname
+bool suffix
+
+string nosect "Sections not permitted on output table name (%s)"
+string nocols "Column names not found (%s)"
+
+errchk tbfpri, tbtopn, tctexp, tbracket, trsopen, trseval
+
+bool trseval(), streq()
+int tbpsta(), selrows()
+pointer tbtopn(), trsopen()
+
+begin
+ # Allocate memory for temporary strings.
+ call smark (sp)
+ call salloc (root, SZ_FNAME, TY_CHAR)
+ call salloc (newname, SZ_FNAME, TY_CHAR)
+ call salloc (extend, SZ_FNAME, TY_CHAR)
+ call salloc (rowselect, SZ_FNAME, TY_CHAR)
+ call salloc (colselect, SZ_FNAME, TY_CHAR)
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+ call salloc (colunits, SZ_COLUNITS, TY_CHAR)
+ call salloc (colfmt, SZ_COLFMT, TY_CHAR)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ # Selectors are forbbiden on output.
+ call rdselect (output, Memc[root], Memc[rowselect],
+ Memc[colselect], SZ_FNAME)
+ if (Memc[rowselect] != EOS || Memc[colselect] != EOS) {
+ call sprintf (Memc[errmsg], SZ_LINE, nosect)
+ call pargstr (output)
+ call error (1, Memc[errmsg])
+ }
+
+ # Break input file name into bracketed selectors.
+ call rdselect (input, Memc[root], Memc[rowselect],
+ Memc[colselect], SZ_FNAME)
+
+ # Open input table and get some info about it.
+ itp = tbtopn (Memc[root], READ_ONLY, NULL)
+ numrow = tbpsta (itp, TBL_NROWS)
+ numcol = tbpsta (itp, TBL_NCOLS)
+
+ # Find how many rows were requested by row selector.
+ # If only one, turn off suffixing. Also do it in case
+ # ASCII output was requested.
+ nrows = selrows (itp, Memc[rowselect])
+ if (nrows == 1)
+ suffix = false
+ else
+ suffix = true
+ if (streq (output, "STDOUT"))
+ suffix = false
+
+ # Create array of column pointers from column selector.
+ call malloc (colptr, numcol, TY_INT)
+ call malloc (newcol, numcol, TY_INT)
+ call tcs_open (itp, Memc[colselect], Memi[colptr], numptr, numcol)
+
+ # Take an error exit if no columns were matched.
+ if (numptr == 0) {
+ call sprintf (Memc[errmsg], SZ_LINE, nocols)
+ call pargstr (input)
+ call error (1, Memc[errmsg])
+ }
+
+ # Loop over selected rows on input table, creating
+ # a 2D output table for each row.
+ pcode = trsopen (itp, Memc[rowselect])
+ do irow = 1, numrow {
+ if (trseval (itp, irow, pcode)) {
+
+ # Append suffix to output name.
+ if (suffix)
+ call txtsuff (output, Memc[newname], irow)
+ else
+ call strcpy (output, Memc[newname], SZ_FNAME)
+
+ if (verbose) {
+ call printf ("%s row=%d -> %s\n")
+ call pargstr (input)
+ call pargi (irow)
+ call pargstr (Memc[newname])
+ call flush (STDOUT)
+ }
+
+ # Open output table and set its type.
+ call tbfpri (Memc[root], Memc[newname], phu_copied)
+ otp = tbtopn (Memc[newname], NEW_FILE, NULL)
+ type = tbpsta (itp, TBL_WHTYPE)
+ if (streq (output, "STDOUT")) # ASCII output.
+ type = TBL_TYPE_TEXT
+ call tbpset (otp, TBL_WHTYPE, type)
+
+ # Copy column information from input to output.
+ call txtcpyco (otp, colptr, newcol, numptr, colname,
+ colunits, colfmt, compact)
+
+ # Create table and copy header.
+ call tbtcre (otp)
+ call tbhcal (itp, otp)
+
+ # Copy row number into header.
+ call tbhadi (otp, "ORIG_ROW", irow)
+
+ # Copy scalar columns into header.
+ if (compact)
+ call txtcpysc (otp, colptr, newcol, numptr, colname,
+ colunits, colfmt)
+
+ # Copy number of columns into header. This is used
+ # by task that reads back 2D tables into 3D format.
+ if (compact)
+ call tbhadi (otp, "TCTOTAL", numptr)
+
+ # Copy data to output table.
+ call txtcpy (itp, otp, irow, Memi[colptr], Memi[newcol],
+ numptr, compact)
+
+ # Close output.
+ call tbtclo (otp)
+ }
+ }
+
+ # Free arrays associated with columns.
+ call tcs_close (Memi[colptr], numptr)
+ call mfree (newcol, TY_INT)
+ call mfree (colptr, TY_INT)
+
+ # Close row selector structure and input table.
+ call trsclose (pcode)
+ call tbtclo (itp)
+
+ call sfree (sp)
+end
+
+
+
+
+# Appends sufix to output file name.
+
+procedure txtsuff (filename, newname, row)
+
+char filename[ARB] # i: output table name
+char newname[ARB] # o: output table name with suffix
+int row # i: row number
+
+pointer sp, ext, suffix
+int dot, i, j
+
+int strcmp(), strldxs()
+
+begin
+ call smark (sp)
+ call salloc (suffix, SZ_LINE, TY_CHAR)
+ call salloc (ext, SZ_LINE, TY_CHAR)
+
+ # Get rid of any appendages except the extension.
+ call imgcluster (filename, newname, SZ_FNAME)
+
+ # Valid extensions are .tab, .fit and .fits
+ # Everything else is part of the root file name.
+
+ # Detect extension.
+ Memc[ext] = EOS
+ dot = strldxs (".", newname)
+ if (dot != 0) {
+ i = dot
+ j = 0
+ while (newname[i] != EOS) {
+ Memc[ext+j] = newname[i]
+ j = j + 1
+ i = i + 1
+ }
+ Memc[ext+j] = EOS
+ }
+
+ # If valid extension, remove it from name.
+ if ( (strcmp (Memc[ext], ".tab") == 0) ||
+ (strcmp (Memc[ext], ".fit") == 0) ||
+ (strcmp (Memc[ext], ".fits") == 0) )
+ newname[dot] = EOS
+ else
+ Memc[ext] = EOS
+
+ # Build suffix.
+ call sprintf (Memc[suffix], SZ_LINE, "_r%04d")
+ call pargi (row)
+
+ # Append suffix and extension to root name.
+ call strcat (Memc[suffix], newname, SZ_FNAME)
+ call strcat (Memc[ext], newname, SZ_FNAME)
+
+ call sfree (sp)
+end
+
diff --git a/pkg/utilities/nttools/threed/x_threed.x b/pkg/utilities/nttools/threed/x_threed.x
new file mode 100644
index 00000000..ed67f6b7
--- /dev/null
+++ b/pkg/utilities/nttools/threed/x_threed.x
@@ -0,0 +1,5 @@
+task tscopy = t_tcopy,
+ txtable = t_txtable,
+ tximage = t_tximage,
+ titable = t_titable,
+ tiimage = t_tiimage
diff --git a/pkg/utilities/nttools/thselect.par b/pkg/utilities/nttools/thselect.par
new file mode 100644
index 00000000..a2eb2fc4
--- /dev/null
+++ b/pkg/utilities/nttools/thselect.par
@@ -0,0 +1,5 @@
+table,s,a,"",,,input tables
+keywords,s,a,"",,,keywords to be listed
+expr,s,a,"yes",,,boolean expression governing selection
+Version,s,h,"21July2000",,,"date of installation"
+mode,s,h,"al"
diff --git a/pkg/utilities/nttools/tinfo.par b/pkg/utilities/nttools/tinfo.par
new file mode 100644
index 00000000..9f65e296
--- /dev/null
+++ b/pkg/utilities/nttools/tinfo.par
@@ -0,0 +1,15 @@
+# parameter file for tinfo
+table,s,a,"",,,"name of table"
+ttout,b,h,y,,,"display values on terminal?"
+nrows,i,h,0,,,"number of rows written to table"
+ncols,i,h,0,,,"number of columns defined"
+npar,i,h,0,,,"number of header parameters written to table"
+rowlen,r,h,0,,,"row length in units of SZ_REAL"
+rowused,r,h,0,,,"amount of row length used in units of SZ_REAL"
+allrows,i,h,0,,,"number of allocated rows"
+maxpar,i,h,0,,,"space allocated for header parameters"
+maxcols,i,h,0,,,"space allocated for column descriptors"
+tbltype,s,h,"",,,"table type"
+subtype,s,h,"",,,"table subtype"
+tblversion,i,h,0,,,"version of software that created the table"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/tinfo/mkpkg b/pkg/utilities/nttools/tinfo/mkpkg
new file mode 100644
index 00000000..dd50f0f1
--- /dev/null
+++ b/pkg/utilities/nttools/tinfo/mkpkg
@@ -0,0 +1,12 @@
+# Update the tinfo application code in the ttools package library
+# Author: HODGE, 2-FEB-1988
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ tinfo.x <error.h> <tbset.h>
+ tlcol.x <error.h> <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/tinfo/tinfo.x b/pkg/utilities/nttools/tinfo/tinfo.x
new file mode 100644
index 00000000..a90fa1be
--- /dev/null
+++ b/pkg/utilities/nttools/tinfo/tinfo.x
@@ -0,0 +1,179 @@
+include <error.h>
+include <fset.h> # used to check whether input is redirected
+include <tbset.h>
+
+# tinfo -- get information about a table
+# This task displays such information as the number of rows and columns
+# in a table. The values are also put into parameters for the task.
+#
+# Phil Hodge, 22-Jul-1987 Task created
+# Phil Hodge, 11-Aug-1987 Delete call to tbtext.
+# Phil Hodge, 28-Aug-1987 Include maxcols, change name allpar-->maxpar
+# Phil Hodge, 7-Sep-1988 Change parameter name for table.
+# Phil Hodge, 9-Dec-1988 Input can be a list of tables.
+# Phil Hodge, 10-May-1991 Use clpopns instead of clpopnu.
+# Phil Hodge, 23-Aug-1991 Change "user" to "header" in output.
+# Phil Hodge, 16-Mar-1992 Include text table type.
+# Phil Hodge, 26-Mar-1992 Remove call to tbtext; use tbtnam instead.
+# Phil Hodge, 8-Apr-1993 Also write software version number to par file.
+# Phil Hodge, 6-Aug-1993 Change "version" to "tblversion".
+# Phil Hodge, 21-Dec-1994 Change rowlen and rowused from int to real.
+# Phil Hodge, 1-Jul-1995 Modify for FITS tables.
+# Phil Hodge, 3-Oct-1995 Modify to use tbn instead of fnt.
+# Phil Hodge, 9-Jun-1999 Print table subtype, and save to new cl parameter;
+# if input is redirected, set input to STDIN without getting cl param.
+# Change "row" & "column" to subtypes of table type "stsdas".
+# Phil Hodge, 22-Feb-2002 For image subtype, change what is printed from
+# "primary header" to "image", since it can now be an image extension.
+
+procedure tinfo()
+
+pointer tlist # for list of input table names
+pointer tp # pointer to table descriptor
+pointer sp
+pointer tname # scratch for table name
+pointer ttype # scratch for table type
+pointer tsubtype # scratch for table subtype
+bool ttout # true if the user wants output to the terminal
+int nrows # number of rows written to the table
+int ncols # number of columns defined
+int npar # number of header parameters written to the table
+real rowlen # (r) row length (unit = SZ_REAL)
+real rowused # (r) portion of row length used by the defined columns
+int allrows # (c) number of rows allocated
+int maxpar # space allocated for header parameters
+int maxcols # space allocated for column descriptors
+int tbltype # table type
+int tbl_subtype # table subtype
+int tblversion # version number of software that created the table
+pointer tbtopn()
+int tbpsta()
+bool clgetb()
+int fstati()
+pointer tbnopenp(), tbnopen()
+int tbnget()
+
+begin
+ call smark (sp)
+ call salloc (tname, SZ_FNAME, TY_CHAR)
+ call salloc (ttype, SZ_FNAME, TY_CHAR)
+ call salloc (tsubtype, SZ_FNAME, TY_CHAR)
+ Memc[ttype] = EOS
+ Memc[tsubtype] = EOS
+
+ if (fstati (STDIN, F_REDIR) == YES)
+ tlist = tbnopen ("STDIN")
+ else
+ tlist = tbnopenp ("table")
+
+ ttout = clgetb ("ttout")
+
+ # Do for each table in the input list.
+ while (tbnget (tlist, Memc[tname], SZ_FNAME) != EOF) {
+
+ iferr {
+ tp = tbtopn (Memc[tname], READ_ONLY, 0)
+ } then {
+ call eprintf ("can't open %s\n")
+ call pargstr (Memc[tname])
+ call erract (EA_WARN)
+ next
+ }
+
+ nrows = tbpsta (tp, TBL_NROWS)
+ ncols = tbpsta (tp, TBL_NCOLS)
+ npar = tbpsta (tp, TBL_NPAR)
+ rowlen = real (tbpsta (tp, TBL_ROWLEN_CHAR)) / SZ_REAL
+ rowused = real (tbpsta (tp, TBL_ROWLEN_CHAR_USED)) / SZ_REAL
+ allrows = tbpsta (tp, TBL_ALLROWS)
+ maxpar = tbpsta (tp, TBL_MAXPAR)
+ maxcols = tbpsta (tp, TBL_MAXCOLS)
+ tbltype = tbpsta (tp, TBL_WHTYPE)
+ tbl_subtype = tbpsta (tp, TBL_SUBTYPE)
+ tblversion = tbpsta (tp, TBL_VERSION)
+
+ # Express the table type as a string.
+ if (tbltype == TBL_TYPE_S_ROW)
+ call strcpy ("stsdas", Memc[ttype], SZ_FNAME)
+ else if (tbltype == TBL_TYPE_S_COL)
+ call strcpy ("stsdas", Memc[ttype], SZ_FNAME)
+ else if (tbltype == TBL_TYPE_TEXT)
+ call strcpy ("text", Memc[ttype], SZ_FNAME)
+ else if (tbltype == TBL_TYPE_FITS)
+ call strcpy ("fits", Memc[ttype], SZ_FNAME)
+ else
+ call strcpy ("unknown", Memc[ttype], SZ_FNAME)
+
+ # Express the subtype as a string.
+ if (tbltype == TBL_TYPE_TEXT) {
+ if (tbl_subtype == TBL_SUBTYPE_SIMPLE)
+ call strcpy ("simple", Memc[tsubtype], SZ_FNAME)
+ else if (tbl_subtype == TBL_SUBTYPE_EXPLICIT)
+ call strcpy ("explicit column definitions",
+ Memc[tsubtype], SZ_FNAME)
+ } else if (tbltype == TBL_TYPE_FITS) {
+ if (tbl_subtype == TBL_SUBTYPE_ASCII)
+ call strcpy ("ascii", Memc[tsubtype], SZ_FNAME)
+ else if (tbl_subtype == TBL_SUBTYPE_BINTABLE)
+ call strcpy ("binary", Memc[tsubtype], SZ_FNAME)
+ else if (tbl_subtype == TBL_SUBTYPE_IMAGE)
+ call strcpy ("image", Memc[tsubtype], SZ_FNAME)
+ } else if (tbltype == TBL_TYPE_S_ROW) {
+ call strcpy ("row ordered", Memc[tsubtype], SZ_FNAME)
+ } else if (tbltype == TBL_TYPE_S_COL) {
+ call strcpy ("column ordered", Memc[tsubtype], SZ_FNAME)
+ } else {
+ call strcpy ("N/A", Memc[tsubtype], SZ_FNAME)
+ }
+
+ if (ttout) {
+ call tbtnam (tp, Memc[tname], SZ_FNAME) # get full name
+ call printf ("# %s\n")
+ call pargstr (Memc[tname])
+ call printf ("%4d rows written to table\n")
+ call pargi (nrows)
+ call printf ("%4d columns defined\n")
+ call pargi (ncols)
+ call printf ("%4d header parameters written to table\n")
+ call pargi (npar)
+ if (tbltype == TBL_TYPE_S_ROW) {
+ call printf ("%6.1f row length in units of SZ_REAL\n")
+ call pargr (rowlen)
+ call printf ("%6.1f amount of row length used\n")
+ call pargr (rowused)
+ } else if (tbltype == TBL_TYPE_S_COL) {
+ call printf ("%4d rows allocated\n")
+ call pargi (allrows)
+ }
+ call printf ("%4d records allocated for header parameters\n")
+ call pargi (maxpar)
+ call printf ("%4d space allocated for column descriptors\n")
+ call pargi (maxcols)
+ call printf ("table type: %s")
+ call pargstr (Memc[ttype])
+ if (tbl_subtype != TBL_SUBTYPE_SIMPLE &&
+ tbl_subtype != TBL_SUBTYPE_BINTABLE &&
+ tbltype != TBL_TYPE_S_ROW) {
+ call printf (" %s")
+ call pargstr (Memc[tsubtype])
+ }
+ call printf ("\n") # after table type and subtype
+ }
+ call tbtclo (tp)
+ }
+
+ call clputi ("nrows", nrows)
+ call clputi ("ncols", ncols)
+ call clputi ("npar", npar)
+ call clputr ("rowlen", rowlen)
+ call clputr ("rowused", rowused)
+ call clputi ("allrows", allrows)
+ call clputi ("maxpar", maxpar)
+ call clputi ("maxcols", maxcols)
+ call clpstr ("tbltype", Memc[ttype])
+ call clpstr ("subtype", Memc[tsubtype])
+ call clputi ("tblversion", tblversion)
+
+ call tbnclose (tlist)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tinfo/tlcol.x b/pkg/utilities/nttools/tinfo/tlcol.x
new file mode 100644
index 00000000..c5bc2b97
--- /dev/null
+++ b/pkg/utilities/nttools/tinfo/tlcol.x
@@ -0,0 +1,128 @@
+include <error.h>
+include <fset.h> # used to check whether input is redirected
+include <tbset.h>
+
+define T_MAXDIM 7 # maximum dimension of array
+define SZ_DTYPE 29 # size of string containing column data type
+
+# tlcol -- list column information
+# This task writes information about the columns in a table. At least
+# the column names will be listed, and the data types, formats, and units
+# may also be listed. The column name and units are allowed (at least
+# by this program) to contain embedded blanks, in which case they will
+# be printed enclosed in double quotes.
+#
+# Phil Hodge, 23-Jul-1987 Task created
+# Phil Hodge, 11-Aug-1987 Modify for change in datatype for char string to -n
+# and change in calling sequence of inquotes.
+# Phil Hodge, 3-Feb-1988 Left-justify info except for print format.
+# Phil Hodge, 7-Sep-1988 Change parameter name for table.
+# Phil Hodge, 9-Dec-1988 Input can be a list of tables.
+# Phil Hodge, 10-May-1991 Use clpopns instead of clpopnu.
+# Phil Hodge, 26-Mar-1992 Remove call to tbtext; use tbtnam instead.
+# Phil Hodge, 1-Apr-1993 Include short datatype.
+# Phil Hodge, 6-Jun-1994 Call erract if error opening table; flush STDOUT.
+# Phil Hodge, 18-Nov-1994 Print array size combined with data type;
+# increase SZ_DTYPE from 9 to 29; increase width of
+# field for printing data type from 6 to 8.
+# Phil Hodge, 13-Jan-1995 Change calling sequence of inquotes.
+# Phil Hodge, 19-Jul-1995 Add tp to calling sequence of tl_dtype.
+# Phil Hodge, 3-Oct-1995 Modify to use tbn instead of fnt.
+# Phil Hodge, 7-Jun-1999 If input is redirected, set input to STDIN without
+# getting cl param.
+
+procedure tlcol()
+
+pointer tlist # for list of input table names
+pointer tp # pointer to descriptor for input table
+pointer cp # pointer to column descriptor
+pointer sp
+pointer tname # pointer to scratch space for table name
+pointer cname, cunits, cfmt # pointers to scratch space for column info
+char chartyp[SZ_DTYPE] # data type expressed as a string
+int datatype # column data type
+int nelem, lenfmt # length of array; width of format
+int ncols # number of columns in table
+int nlist # number of items to list (from one to four)
+int k # loop index
+int colnum # column number (ignored)
+pointer tbtopn(), tbpsta(), tbcnum()
+int clgeti()
+int fstati()
+pointer tbnopenp(), tbnopen()
+int tbnget()
+
+begin
+ call smark (sp)
+ call salloc (tname, SZ_LINE, TY_CHAR)
+ call salloc (cname, SZ_LINE, TY_CHAR)
+ call salloc (cunits, SZ_LINE, TY_CHAR)
+ call salloc (cfmt, SZ_COLFMT, TY_CHAR)
+
+ if (fstati (STDIN, F_REDIR) == YES)
+ tlist = tbnopen ("STDIN")
+ else
+ tlist = tbnopenp ("table")
+ nlist = clgeti ("nlist")
+
+ # Do for each table in the input list.
+ while (tbnget (tlist, Memc[tname], SZ_LINE) != EOF) {
+
+ iferr {
+ tp = tbtopn (Memc[tname], READ_ONLY, 0)
+ } then {
+ call eprintf ("# %s\n")
+ call pargstr (Memc[tname])
+ call erract (EA_WARN)
+ next
+ }
+
+ call tbtnam (tp, Memc[tname], SZ_LINE) # get full name
+ call printf ("# %s\n")
+ call pargstr (Memc[tname])
+
+ ncols = tbpsta (tp, TBL_NCOLS)
+
+ do k = 1, ncols {
+ cp = tbcnum (tp, k)
+ call tbcinf (cp,
+ colnum, Memc[cname], Memc[cunits], Memc[cfmt],
+ datatype, nelem, lenfmt)
+
+ # Enclose column name in quotes if it contains embedded
+ # or trailing blanks.
+ call inquotes (Memc[cname], Memc[cname], SZ_LINE, YES)
+ call printf ("%-16s") # but name can be longer
+ call pargstr (Memc[cname])
+
+ if (nlist > 1) { # also print data type
+
+ # Convert integer data type code to a character string,
+ # and append info about array size if > 1.
+ call tl_dtype (tp, cp, datatype, nelem, chartyp, SZ_DTYPE)
+
+ call printf (" %-8s")
+ call pargstr (chartyp)
+
+ if (nlist > 2) { # also print format for display
+ call printf (" %8s")
+ call pargstr (Memc[cfmt])
+
+ if (nlist > 3) { # also print column units
+ # The "NO" means ignore trailing blanks.
+ call inquotes (Memc[cunits], Memc[cunits],
+ SZ_LINE, NO)
+ call printf (" %-16s") # but can be longer
+ call pargstr (Memc[cunits])
+ }
+ }
+ }
+ call printf ("\n") # end of line for each column
+ }
+ call flush (STDOUT)
+ call tbtclo (tp)
+ }
+
+ call tbnclose (tlist)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tintegrate.par b/pkg/utilities/nttools/tintegrate.par
new file mode 100644
index 00000000..1165ac29
--- /dev/null
+++ b/pkg/utilities/nttools/tintegrate.par
@@ -0,0 +1,6 @@
+table,f,a,,,,"input table"
+integrand,s,a,"",,,"integrand"
+independent,s,a,"",,,"independent variable - integrate col1 wrt col2"
+integral,r,h,0.0,,,"Result of integration"
+ptsused,i,h,0,,,"Number of data points used"
+mode,s,h,al
diff --git a/pkg/utilities/nttools/tintegrate/mkpkg b/pkg/utilities/nttools/tintegrate/mkpkg
new file mode 100644
index 00000000..cfe87a34
--- /dev/null
+++ b/pkg/utilities/nttools/tintegrate/mkpkg
@@ -0,0 +1,11 @@
+# Update the tintegrate application code in the ttools package library
+# Author: GIARETTA, 7-DEC-1987
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ tintegrate.x <error.h> <ctype.h> <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/tintegrate/tintegrate.x b/pkg/utilities/nttools/tintegrate/tintegrate.x
new file mode 100644
index 00000000..3f01fd67
--- /dev/null
+++ b/pkg/utilities/nttools/tintegrate/tintegrate.x
@@ -0,0 +1,155 @@
+include <error.h>
+include <fset.h> # to check whether input is redirected
+include <ctype.h>
+include <tbset.h>
+
+# T_INTEGRATE -- integrate one column of a table wrt another
+# using simple trapezoid rule, ignoring INDEF values
+#
+# D. Giaretta, 01-Aug-1987 Original SPP version
+# Phil Hodge, 7-Sep-1988 Change parameter name for table.
+# Phil Hodge, 26-Jan-1996 Add option to just sum the values.
+# Phil hodge, 8-Jun-1999 Set input to STDIN if redirected;
+# open the table READ_ONLY, not READ_WRITE.
+
+procedure t_tintegrate()
+
+char inname[SZ_FNAME] # input table name
+char col1[SZ_COLNAME] # integrand
+char col2[SZ_COLNAME] # independent var.
+#--
+pointer sp
+pointer pt1, pt2, nullpt1, nullpt2
+pointer tp
+pointer colptr1, colptr2
+int i
+long numrows
+long numused
+long lastgood, firstgood # zero indexed
+double integ
+int fstati()
+int tbpsta()
+pointer tbtopn()
+bool isblank()
+
+errchk tbtopn, clgstr, tbpsta, clputr, clputl
+
+begin
+
+ call smark(sp)
+
+ integ = 0.0d0
+ numused = 0
+ lastgood = -1
+ firstgood = -1
+
+ if (fstati (STDIN, F_REDIR) == YES)
+ call strcpy ("STDIN", inname, SZ_FNAME)
+ else
+ call clgstr ("table", inname, SZ_FNAME)
+
+ tp = tbtopn( inname, READ_ONLY, 0)
+ numrows = tbpsta(tp, TBL_NROWS)
+
+ call clgstr( "integrand", col1, SZ_COLNAME)
+ call clgstr( "independent", col2, SZ_COLNAME)
+
+ call tbcfnd( tp, col1, colptr1, 1)
+ if (colptr1 == NULL)
+ call error (0, "integrand not found in table")
+
+ if (isblank (col2)) {
+ colptr2 = NULL
+ } else {
+ call tbcfnd( tp, col2, colptr2, 1)
+ if (colptr2 == NULL)
+ call error (0, "independent variable not found in table")
+ }
+
+ # Get dependent variable values.
+ call salloc( pt1, numrows, TY_DOUBLE)
+ call salloc( nullpt1, numrows, TY_BOOL)
+ call tbcgtd(tp, colptr1, Memd[pt1], Memb[nullpt1], 1, numrows)
+
+ # Get independent variable values.
+ if (colptr2 != NULL) {
+ call salloc( pt2, numrows, TY_DOUBLE)
+ call salloc( nullpt2, numrows, TY_BOOL)
+ call tbcgtd(tp, colptr2, Memd[pt2], Memb[nullpt2], 1, numrows)
+ }
+
+ # Find first non-INDEF row.
+ if (colptr2 == NULL) {
+ do i = 0, numrows-1 {
+ if (!Memb[nullpt1+i]) {
+ firstgood = i
+ break
+ }
+ }
+ } else {
+ do i = 0, numrows-1 {
+ if ( !Memb[nullpt1+i] && !Memb[nullpt2+i] ) {
+ firstgood = i
+ break
+ }
+ }
+ }
+ if (firstgood == -1) {
+ call tbtclo (tp)
+ call error (1, "no data in table")
+ }
+ lastgood = firstgood
+
+ # apply simple trapezoid rule -
+ # ignore INDEF values, in other words linearly interpolate
+ # between adjacent good values
+ # note also that the independent must be non-decreasing
+
+ if (colptr2 == NULL) {
+
+ # No independent variable; just sum the values.
+ numused = 0
+ do i= firstgood, numrows-1 {
+ if ( !Memb[nullpt1+i] ) {
+ integ = integ + Memd[pt1+i]
+ lastgood = i
+ numused = numused + 1
+ }
+ }
+
+ } else {
+
+ # Integrate with respect to an independent variable.
+ numused = 1
+ do i= firstgood+1, numrows-1 {
+ if ( !Memb[nullpt1+i] && !Memb[nullpt2+i] ) {
+ if ( Memd[pt2+i] < Memd[pt2+lastgood] )
+ call error(0, "independent variable not increasing")
+ integ = integ +
+ 0.5*(Memd[pt1+i] + Memd[pt1+lastgood]) *
+ (Memd[pt2+i] - Memd[pt2+lastgood])
+ lastgood = i
+ numused = numused + 1
+ }
+ }
+ }
+
+ # output integral both as parameter and to STDOUT
+ # also record the number of good points used
+
+ if (numused < 2) {
+ call printf (" integral = INDEF, at least 2 good points required")
+ call clputd ("integral", INDEFD)
+ } else {
+ call printf (" integral= %g using %d points\n")
+ call pargd (integ)
+ call pargi (numused)
+ call clputd ("integral", integ)
+ }
+
+ call clputl ("ptsused", numused)
+
+ call tbtclo (tp)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tjoin.par b/pkg/utilities/nttools/tjoin.par
new file mode 100644
index 00000000..eb078f69
--- /dev/null
+++ b/pkg/utilities/nttools/tjoin.par
@@ -0,0 +1,9 @@
+intable1,f,a,,,,name of the first table to be joined
+intable2,f,a,,,,name of the second table to be joined
+outtable,s,a,,,,name of output table
+column1,s,a,,,,name of columns to join in first table
+column2,s,a,,,,name of columns to join in second table
+extrarows,s,h,neither,neither|first|both,,add unmatched rows from which table?
+tolerance,s,h,0.0,,,tolerance used in testing for equality
+casesens,b,h,yes,,,Case sensitivity flag
+mode,s,h,"a",,,
diff --git a/pkg/utilities/nttools/tjoin/closeiotab.x b/pkg/utilities/nttools/tjoin/closeiotab.x
new file mode 100644
index 00000000..8d9ff7df
--- /dev/null
+++ b/pkg/utilities/nttools/tjoin/closeiotab.x
@@ -0,0 +1,22 @@
+include "tjoin.h"
+
+# B.Simon 16-Apr-99 first code
+
+# CLOSE_IOTAB -- Close table and release data structure describing it
+
+procedure close_iotab (tj)
+
+pointer tj # i: Data structure describing table
+#--
+
+begin
+ call tbtclo (TJ_TAB(tj))
+
+ if (TJ_JPTR(tj) != NULL)
+ call mfree (TJ_JPTR(tj), TY_INT)
+
+ if (TJ_DPTR(tj) != NULL)
+ call mfree (TJ_DPTR(tj), TY_INT)
+
+ call mfree (tj, TY_INT)
+end
diff --git a/pkg/utilities/nttools/tjoin/dojoin.x b/pkg/utilities/nttools/tjoin/dojoin.x
new file mode 100644
index 00000000..133a2721
--- /dev/null
+++ b/pkg/utilities/nttools/tjoin/dojoin.x
@@ -0,0 +1,97 @@
+include <tbset.h>
+include "tjoin.h"
+
+# DOJOIN -- Compute the relational join of two tables
+#
+# B.Simon 03-Nov-87 First Code
+# B.Simon 16-Dec-87 Changed to handle table subsets
+# B.Simon 06-Feb-90 Changed to use tbtsrt
+# B.Simon 06-Feb-90 Revised to do outer joins
+
+procedure dojoin (tj1, tj2, tjo, tol, extra, casesens)
+
+pointer tj1 # i: Table info descriptor for first input table
+pointer tj2 # i: Table info descriptor for second input table
+pointer tjo # i: Table info descriptor for output table
+pointer tol # i: Descriptor of vector of tolerance values
+int extra # i: Include non-joined columns in output
+bool casesens # i: Join is case sensitive
+#--
+int nrow1, nrow2, irow, jrow, krow
+pointer match1, match2
+
+bool is_same()
+int tbpsta()
+
+begin
+ # Allocate arrays to hold unmatched rows
+ # in case extrarows is set
+
+ nrow1 = tbpsta (TJ_TAB(tj1), TBL_NROWS)
+ nrow2 = tbpsta (TJ_TAB(tj2), TBL_NROWS)
+
+ if (extra > 0) {
+ call calloc (match1, nrow1, TY_INT)
+ call calloc (match2, nrow2, TY_INT)
+ }
+
+ # Naive approach to join compares every row in first table
+ # to second. This is slower than sorting first (N^2 vs. N log N)
+ # but the code is much simpler, especially with the extra
+ # problem of joining on row number and supporting inner and
+ # outer joins.
+
+ krow = 1
+ do irow = 1, nrow1 {
+ do jrow = 1, nrow2 {
+ # Equality test includes case insensitive string matches
+ # and fuzzy matching for numbers
+
+ if (is_same (tj1, tj2, irow, jrow, tol, casesens)) {
+ # If match, write rows to output table
+
+ call tbrcsc (TJ_TAB(tj1), TJ_TAB(tjo), TJ_DCOL(tj1,1),
+ TJ_DCOL(tjo,1), irow, krow, TJ_DNUM(tj1))
+ call tbrcsc (TJ_TAB(tj2), TJ_TAB(tjo), TJ_DCOL(tj2,1),
+ TJ_DCOL(tjo,TJ_DNUM(tj1)+1), jrow, krow,
+ TJ_DNUM(tj2))
+
+ if (extra > 0) {
+ Memi[match1+irow-1] = jrow
+ Memi[match2+jrow-1] = irow
+ }
+
+ krow = krow + 1
+ }
+ }
+ }
+
+ # Write the extra rows to the output table
+
+ if (extra >= 1) {
+ do irow = 1, nrow1 {
+ if (Memi[match1+irow-1] == 0) {
+ call tbrcsc (TJ_TAB(tj1), TJ_TAB(tjo), TJ_DCOL(tj1,1),
+ TJ_DCOL(tjo,1), irow, krow, TJ_DNUM(tj1))
+ krow = krow + 1
+ }
+ }
+ }
+
+ if (extra == 2) {
+ do jrow = 1, nrow2 {
+ if (Memi[match2+jrow-1] == 0) {
+ call tbrcsc (TJ_TAB(tj2), TJ_TAB(tjo), TJ_DCOL(tj2,1),
+ TJ_DCOL(tjo,TJ_DNUM(tj1)+1), jrow, krow,
+ TJ_DNUM(tj2))
+ krow = krow + 1
+ }
+ }
+ }
+
+ if (extra > 0) {
+ call mfree (match1, TY_INT)
+ call mfree (match2, TY_INT)
+ }
+
+end
diff --git a/pkg/utilities/nttools/tjoin/freetol.x b/pkg/utilities/nttools/tjoin/freetol.x
new file mode 100644
index 00000000..45857c73
--- /dev/null
+++ b/pkg/utilities/nttools/tjoin/freetol.x
@@ -0,0 +1,15 @@
+include "tjoin.h"
+
+# B.Simon 16-Apr-99 first code
+
+# FREE_TOL -- Free the structure containing tolerance values
+
+procedure free_tol (tol)
+
+pointer tol # i: Vector of tolerance values
+#--
+
+begin
+ call mfree (TOL_PTR(tol), TY_DOUBLE)
+ call mfree (tol, TY_INT)
+end
diff --git a/pkg/utilities/nttools/tjoin/isnumber.x b/pkg/utilities/nttools/tjoin/isnumber.x
new file mode 100644
index 00000000..3efb0dba
--- /dev/null
+++ b/pkg/utilities/nttools/tjoin/isnumber.x
@@ -0,0 +1,35 @@
+include <ctype.h>
+include <lexnum.h>
+
+# B.Simon 16-Apr-99 first code
+
+# IS_NUMBER -- Test string to see if it represents a number
+
+bool procedure is_number (str)
+
+char str[ARB] # i: String to be tested
+#--
+int ic, nc, type
+int lexnum()
+
+begin
+ # Use lexnum to determine string type
+
+ ic = 1
+ type = lexnum (str, ic, nc)
+
+ # Any non-white characters after the number
+ # indicate this is not a number
+
+ ic = ic + nc
+ while (str[ic] != EOS) {
+ if (! IS_WHITE(str[ic]))
+ return (false)
+
+ ic = ic + 1
+ }
+
+ # Test for numeric types and return result of test
+
+ return (type == LEX_OCTAL || type == LEX_DECIMAL || type == LEX_REAL)
+end
diff --git a/pkg/utilities/nttools/tjoin/issame.x b/pkg/utilities/nttools/tjoin/issame.x
new file mode 100644
index 00000000..89ea221d
--- /dev/null
+++ b/pkg/utilities/nttools/tjoin/issame.x
@@ -0,0 +1,127 @@
+include "tjoin.h"
+
+# B.Simon 16-Apr-99 first code
+
+# IS_SAME -- See if two values in different tables are the same
+
+bool procedure is_same (tj1, tj2, irow, jrow, tol, casesens)
+
+pointer tj1 # i: Table info descriptor for first input table
+pointer tj2 # i: Table info descriptor for second input table
+int irow # i: Row number of element in first table
+int jrow # i: Row number of element in second table
+pointer tol # i: Descriptor of vecor of tolerance values
+bool casesens # i: Join is case sensitive
+#--
+bool same
+double dval1, dval2
+int icol, dtype1, dtype2, ival1, ival2
+pointer sp, str1, str2
+
+string badtol "Tolerance must be zero for joins on non-numeric columns"
+string badtype "Type mismatch on join columns"
+
+bool streq()
+int spp_type()
+
+begin
+ # Allocate memory for table strings
+
+ call smark (sp)
+ call salloc (str1, SZ_LINE, TY_CHAR)
+ call salloc (str2, SZ_LINE, TY_CHAR)
+
+ same = true
+ do icol = 1, TJ_JNUM(tj1) {
+ if (! same)
+ break
+
+ # Get column data types
+
+ dtype1 = spp_type (TJ_JCOL(tj1,icol))
+ dtype2 = spp_type (TJ_JCOL(tj2,icol))
+
+ # Comparison depends on data type
+
+ if (dtype1 == TY_CHAR && dtype2 == TY_CHAR) {
+ # Nonzero tolerance illegal on string columns
+
+ if (TOL_VAL(tol,icol) != 0.0)
+ call error (1, badtol)
+
+ call tbegtt (TJ_TAB(tj1), TJ_JCOL(tj1,icol), irow,
+ Memc[str1], SZ_LINE)
+ call tbegtt (TJ_TAB(tj2), TJ_JCOL(tj2,icol), jrow,
+ Memc[str2], SZ_LINE)
+
+ # Convert to lower case for case insensitive match
+
+ if (! casesens) {
+ call strlwr (Memc[str1])
+ call strlwr (Memc[str2])
+ }
+
+ # Test for undefined values first, which never match
+
+ if (Memc[str1] == EOS || Memc[str2] == EOS) {
+ same = false
+ } else {
+ same = streq (Memc[str1], Memc[str2])
+ }
+
+ } else if (dtype1 == TY_BOOL && dtype2 == TY_BOOL) {
+ # Nonzero tolerance illegal on boolean column
+
+ if (TOL_VAL(tol,icol) != 0.0)
+ call error (1, badtol)
+
+ # Read boolean as integer so we can detect undefined values
+
+ call tbegti (TJ_TAB(tj1), TJ_JCOL(tj1,icol), irow, ival1)
+ call tbegti (TJ_TAB(tj2), TJ_JCOL(tj2,icol), jrow, ival2)
+
+ # Undefined values never match anything
+
+ if (IS_INDEFI(ival1) || IS_INDEFI(ival2)) {
+ same = false
+ } else {
+ same = ival1 == ival2
+ }
+
+ } else if (dtype1 == TY_CHAR || dtype1 == TY_BOOL ||
+ dtype2 == TY_BOOL || dtype2 == TY_BOOL) {
+
+ # Catch comparison of numeric and non-numeric values
+
+ call error (1, badtype)
+
+ } else {
+ # Null column pointer indicates the join is done on row number
+
+ if (TJ_JCOL(tj1,icol) == NULL) {
+ dval1 = irow
+ } else {
+ call tbegtd (TJ_TAB(tj1), TJ_JCOL(tj1,icol), irow, dval1)
+ }
+
+ if (TJ_JCOL(tj2,icol) == NULL) {
+ dval2 = jrow
+ } else {
+ call tbegtd (TJ_TAB(tj2), TJ_JCOL(tj2,icol), jrow, dval2)
+ }
+
+ # Undefined values never match
+ # Numeric values must be checked to see if the
+ # difference is smaller than the tolerance
+
+ if (IS_INDEFD(dval1) || IS_INDEFD(dval2)) {
+ same = false
+ } else {
+ same = abs (dval2 - dval1) <= TOL_VAL(tol,icol)
+ }
+ }
+ }
+
+ call sfree (sp)
+ return (same)
+end
diff --git a/pkg/utilities/nttools/tjoin/mkjoin.x b/pkg/utilities/nttools/tjoin/mkjoin.x
new file mode 100644
index 00000000..46667b3e
--- /dev/null
+++ b/pkg/utilities/nttools/tjoin/mkjoin.x
@@ -0,0 +1,106 @@
+include <tbset.h>
+
+# MKJOIN -- Create a table that will hold the join of two other tables
+#
+# B.Simon 04-Nov-87 First Code
+# B.Simon 31-Mar-92 Set output table type from input tables
+# B.Simon 14-Apr-99 Extracted code that creates table
+
+pointer procedure mkjoin (tol, tp1, cp1, tp2, cp2, outtable, otp,
+ cpvec1, cpvec2, cpveco, ncol1, ncol2)
+
+double tol # i: Tolerance used in testing for equality
+pointer tp1 # i: Table descriptor of first table
+pointer cp1 # i: Descriptor of merged column in first table
+pointer tp2 # i: Table descriptor of second table
+pointer cp2 # i: Descriptor of merged column in second table
+char outtable[ARB] # i: Name of output table
+pointer otp # i: Table descriptor of output table
+pointer cpvec1[ARB] # i: Vector of columns in first input table
+pointer cpvec2[ARB] # i: Vector of columns in second input table
+pointer cpveco[ARB] # i: Vector of columns in output table
+int ncol1 # i: Number of columns in first input table
+int ncol2 # u: Number of columns in second input table
+#--
+int icol, jcol, numcol, type1, type2
+int colnum[1], datatype[1], lendata[1], lenfmt[1]
+pointer sp, icp, ocp, oldcol, newcol
+pointer colname, colunits, colfmt
+
+int tbpsta(), tbcnum(), tbcigi()
+pointer tbtopn()
+
+begin
+ # Set up arrays in dynamic memory
+
+ call smark (sp)
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+ call salloc (colunits, SZ_COLUNITS, TY_CHAR)
+ call salloc (colfmt, SZ_COLFMT, TY_CHAR)
+
+ # Copy column pointers to old column array. If the tolerance is
+ # zero, the join column in the second table is not copied
+
+ numcol = ncol1 + ncol2
+
+ do icol = 1, ncol1
+ cpvec1[icol] = tbcnum (tp1, icol)
+
+ do icol = 1, ncol2
+ cpvec2[icol] = tbcnum (tp2, icol)
+
+ if (tol == 0.0 && cp1 != NULL && cp2 != NULL) {
+ jcol = tbcigi (cp2, TBL_COL_NUMBER)
+ ncol2 = ncol2 - 1
+ numcol = numcol - 1
+ do icol = jcol+1, ncol2
+ cpvec2[icol-1] = cpvec2[icol]
+ }
+
+ # Set type of output table
+
+ otp = tbtopn (outtable, NEW_FILE, NULL)
+
+ type1 = tbpsta (tp1, TBL_WHTYPE)
+ type2 = tbpsta (tp2, TBL_WHTYPE)
+ if (type1 == type2)
+ call tbpset (otp, TBL_WHTYPE, type1)
+
+ # Copy column information from the input tables to the output table
+
+ do icol = 1, ncol1 {
+ icp = cpvec1[icol]
+ call tbcinf (icp, colnum, Memc[colname], Memc[colunits],
+ Memc[colfmt], datatype[1], lendata[1], lenfmt[1])
+
+ call newcolnam (numcol, Memi[oldcol], icol,
+ Memc[colname], SZ_COLNAME)
+
+ call tbcdef (otp, ocp, Memc[colname], Memc[colunits], Memc[colfmt],
+ datatype[1], lendata[1], 1)
+ cpveco[icol] = ocp
+ }
+
+ do icol = 1, ncol2 {
+ icp = cpvec2[icol]
+ call tbcinf (icp, colnum, Memc[colname], Memc[colunits],
+ Memc[colfmt], datatype[1], lendata[1], lenfmt[1])
+ call newcolnam (numcol, Memi[oldcol], icol,
+ Memc[colname], SZ_COLNAME)
+ call tbcdef (otp, ocp, Memc[colname], Memc[colunits], Memc[colfmt],
+ datatype[1], lendata[1], 1)
+ cpveco[ncol1+icol] = ocp
+ }
+
+ # Copy the table columns a row at a time
+
+ call tbtcre (otp)
+ call tbhcal (tp2, otp)
+ call tbhcal (tp1, otp)
+
+ call mfree (oldcol, TY_INT)
+ call mfree (newcol, TY_INT)
+ call sfree (sp)
+
+ return (otp)
+end
diff --git a/pkg/utilities/nttools/tjoin/mkpkg b/pkg/utilities/nttools/tjoin/mkpkg
new file mode 100644
index 00000000..e421c190
--- /dev/null
+++ b/pkg/utilities/nttools/tjoin/mkpkg
@@ -0,0 +1,23 @@
+# Update the tjoin application code in the ttools package library
+# Author: B.Simon, 25-NOV-1987
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ closeiotab.x "tjoin.h"
+ dojoin.x <tbset.h> "tjoin.h"
+ freetol.x "tjoin.h"
+ isnumber.x <ctype.h> <lexnum.h>
+ issame.x "tjoin.h"
+ mkjoin.x <tbset.h>
+ openitab.x <tbset.h> "tjoin.h"
+ openotab.x <tbset.h> "tjoin.h"
+ readtol.x "tjoin.h"
+ removejcol.x "tjoin.h"
+ renamecol.x <ctype.h> <tbset.h> "tjoin.h"
+ spptype.x <tbset.h>
+ tjoin.x <tbset.h> "tjoin.h"
+ ;
diff --git a/pkg/utilities/nttools/tjoin/openitab.x b/pkg/utilities/nttools/tjoin/openitab.x
new file mode 100644
index 00000000..ebdbcf97
--- /dev/null
+++ b/pkg/utilities/nttools/tjoin/openitab.x
@@ -0,0 +1,82 @@
+include <tbset.h>
+include "tjoin.h"
+
+# B.Simon 16-Apr-99 first code
+
+# OPEN_ITAB -- Open one of the input tables used in the join
+
+pointer procedure open_itab (intable, column)
+
+char intable[ARB] # i: Input table name
+char column[ARB] # i: List of join columns
+#--
+int ic, icol
+pointer tj, sp, cname, errtxt
+
+string nojoincol "No column supplied as join column"
+string badcolnam "Column name not found in table (%s[c:%s])"
+string notopen "Could not open table (%s)"
+
+bool strne()
+int tbpsta(), tbcnum(), word_count(), word_fetch()
+pointer tbtopn()
+
+begin
+ # Allocate memory for temporary strings
+
+ call smark (sp)
+ call salloc (cname, SZ_COLNAME, TY_CHAR)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ # Allocate memory for data structure
+
+ call calloc (tj, LEN_TJSTRUCT, TY_INT)
+
+ # Open table and put descriptor in structure
+
+ iferr {
+ TJ_TAB(tj) = tbtopn (intable, READ_ONLY, NULL)
+ } then {
+ call sprintf (Memc[errtxt], SZ_LINE, notopen)
+ call pargstr (intable)
+ call error (1, Memc[errtxt])
+ }
+
+ # Create array of data columns
+
+ TJ_DNUM(tj) = tbpsta (TJ_TAB(tj), TBL_NCOLS)
+ call malloc (TJ_DPTR(tj), TJ_DNUM(tj), TY_INT)
+
+ do icol = 1, TJ_DNUM(tj)
+ TJ_DCOL(tj,icol) = tbcnum (TJ_TAB(tj), icol)
+
+ # Create array of join columns
+
+ TJ_JNUM(tj) = word_count (column)
+ if (TJ_JNUM(tj) == 0)
+ call error (1, nojoincol)
+
+ call malloc (TJ_JPTR(tj), TJ_JNUM(tj), TY_INT)
+
+ ic = 1
+ icol = 1
+ while (word_fetch (column, ic, Memc[cname], SZ_COLNAME) > 0) {
+ call tbcfnd (TJ_TAB(tj), Memc[cname], TJ_JCOL(tj,icol), 1)
+
+ if (TJ_JCOL(tj,icol) == NULL) {
+ if (strne (Memc[cname], ROWNAME)) {
+ call sprintf (Memc[errtxt], SZ_LINE, badcolnam)
+ call pargstr (intable)
+ call pargstr (Memc[cname])
+ call error (1, Memc[errtxt])
+ }
+ }
+
+ icol = icol + 1
+ }
+
+ # Free temporary memory and return descriptor of new structure
+
+ call sfree (sp)
+ return (tj)
+end
diff --git a/pkg/utilities/nttools/tjoin/openotab.x b/pkg/utilities/nttools/tjoin/openotab.x
new file mode 100644
index 00000000..bd84ca6a
--- /dev/null
+++ b/pkg/utilities/nttools/tjoin/openotab.x
@@ -0,0 +1,91 @@
+include <tbset.h>
+include "tjoin.h"
+
+# B.Simon 16-Apr-99 first code
+
+# OPEN_OTAB -- Open the output table
+
+pointer procedure open_otab (outtable, tj1, tj2)
+
+char outtable[ARB] # i: Output table name
+pointer tj1 # i: First input table descriptor
+pointer tj2 # i: Second input table descriptor
+#--
+int type1, type2, icol, jcol, itab, tji[2]
+int colnum, datatype, lendata, lenfmt
+pointer tjo, sp, colname, colunits, colfmt, errtxt
+
+string notopen "Could not open table (%s)"
+
+int tbpsta()
+pointer tbtopn()
+
+begin
+ # Allocate memory for temporary strings
+
+ call smark (sp)
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+ call salloc (colunits, SZ_COLUNITS, TY_CHAR)
+ call salloc (colfmt, SZ_COLFMT, TY_CHAR)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ # Allocate memory for data structure
+
+ call malloc (tjo, LEN_TJSTRUCT, TY_INT)
+
+ # Open table and put descriptor in structure
+
+ iferr {
+ TJ_TAB(tjo) = tbtopn (outtable, NEW_FILE, NULL)
+ } then {
+ call sprintf (Memc[errtxt], SZ_LINE, notopen)
+ call pargstr (outtable)
+ call error (1, Memc[errtxt])
+ }
+
+ # Set table type based on input tables
+
+ type1 = tbpsta (TJ_TAB(tj1), TBL_WHTYPE)
+ type2 = tbpsta (TJ_TAB(tj2), TBL_WHTYPE)
+ if (type1 == type2)
+ call tbpset (TJ_TAB(tjo), TBL_WHTYPE, type1)
+
+ # No join columns are used for output table
+
+ TJ_JNUM(tjo) = 0
+ TJ_JPTR(tjo) = NULL
+
+ # Allocate array to hold output table data columns
+
+ TJ_DNUM(tjo) = TJ_DNUM(tj1) + TJ_DNUM(tj2)
+ call malloc (TJ_DPTR(tjo), TJ_DNUM(tjo), TY_INT)
+
+ # Copy column information from the input tables to the output table
+
+ tji[1] = tj1
+ tji[2] = tj2
+
+ jcol = 1
+ do itab = 1, 2 {
+ do icol = 1, TJ_DNUM(tji[itab]) {
+ call tbcinf (TJ_DCOL(tji[itab],icol), colnum, Memc[colname],
+ Memc[colunits], Memc[colfmt], datatype,
+ lendata, lenfmt)
+
+ call renamecol (tji, itab, icol, Memc[colname], SZ_COLNAME)
+
+ call tbcdef (TJ_TAB(tjo), TJ_DCOL(tjo,jcol), Memc[colname],
+ Memc[colunits], Memc[colfmt], datatype,
+ lendata, 1)
+
+ jcol = jcol + 1
+ }
+ }
+
+ call tbtcre (TJ_TAB(tjo))
+ call tbhcal (TJ_TAB(tj1), TJ_TAB(tjo))
+ call tbhcal (TJ_TAB(tj2), TJ_TAB(tjo))
+
+ call sfree (sp)
+ return (tjo)
+end
diff --git a/pkg/utilities/nttools/tjoin/readtol.x b/pkg/utilities/nttools/tjoin/readtol.x
new file mode 100644
index 00000000..4b35f522
--- /dev/null
+++ b/pkg/utilities/nttools/tjoin/readtol.x
@@ -0,0 +1,55 @@
+include "tjoin.h"
+define SZ_VALUE 30
+
+# B.Simon 16-Apr-99 first code
+
+# READ_TOL -- Parse the string containing the vector of tolerance values
+
+pointer procedure read_tol (tolerance)
+
+char tolerance[ARB] # i: Comma separated string of tolerance values
+#--
+int ic, jc, nc, ival
+pointer sp, value, errtxt, tol
+
+string badvalue "Invalid value in tolerance (%s)"
+string negvalue "Negative value in tolerance (%g)"
+
+bool is_number()
+int word_count(), word_fetch(), ctod()
+
+begin
+ call smark (sp)
+ call salloc (value, SZ_VALUE, TY_CHAR)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ call malloc (tol, LEN_TOLSTRUCT, TY_INT)
+
+ TOL_NUM(tol) = word_count (tolerance)
+ call malloc (TOL_PTR(tol), TOL_NUM(tol), TY_DOUBLE)
+
+ ic = 1
+ ival = 1
+ while (word_fetch (tolerance, ic, Memc[value], SZ_VALUE) > 0) {
+ if (! is_number (Memc[value])) {
+ call sprintf (Memc[errtxt], SZ_LINE, badvalue)
+ call pargstr (Memc[value])
+ call error (1, Memc[errtxt])
+ }
+
+ jc = 1
+ nc = ctod (Memc[value], jc, TOL_VAL(tol,ival))
+
+ if (TOL_VAL(tol,ival) < 0.0) {
+ call sprintf (Memc[errtxt], SZ_LINE, negvalue)
+ call pargd (TOL_VAL(tol,ival))
+ call error (1, Memc[errtxt])
+ }
+
+ ival = ival + 1
+ }
+
+ call sfree (sp)
+ return (tol)
+end
+
diff --git a/pkg/utilities/nttools/tjoin/removejcol.x b/pkg/utilities/nttools/tjoin/removejcol.x
new file mode 100644
index 00000000..1578021b
--- /dev/null
+++ b/pkg/utilities/nttools/tjoin/removejcol.x
@@ -0,0 +1,43 @@
+include "tjoin.h"
+
+# B.Simon 16-Apr-99 first code
+
+# REMOVE_JCOL -- Remove join columns from list of data columns
+
+procedure remove_jcol (tj, tol)
+
+pointer tj # i: Descriptor of table information
+pointer tol # i: Vector of tolerances used in equality test
+#--
+bool match
+int icol, jcol, kcol
+
+begin
+ kcol = 0
+ do icol = 1, TJ_DNUM(tj) {
+ # Determine if this column is a join column
+ # with strict equality testing
+
+ match = false
+ do jcol = 1, TJ_JNUM(tj) {
+ if (TJ_DCOL(tj,icol) == TJ_JCOL(tj,jcol) &&
+ TOL_VAL(tol,jcol) == 0.0) {
+ match = true
+ break
+ }
+ }
+
+ # Don't copy these columns as they duplicate the values
+ # in the join column in the other table. Also don't copy
+ # if icol == kcol in order to save time
+
+ if (! match) {
+ kcol = kcol + 1
+ if (kcol < icol)
+ TJ_DCOL(tj,kcol) = TJ_DCOL(tj,icol)
+ }
+ }
+
+ TJ_DNUM(tj) = kcol
+end
+
diff --git a/pkg/utilities/nttools/tjoin/renamecol.x b/pkg/utilities/nttools/tjoin/renamecol.x
new file mode 100644
index 00000000..03d87041
--- /dev/null
+++ b/pkg/utilities/nttools/tjoin/renamecol.x
@@ -0,0 +1,109 @@
+include <ctype.h>
+include <tbset.h>
+include "tjoin.h"
+
+# RENAMECOL -- Rename a column to make its name unique
+#
+# If the name of the column pointed to by that index is unique, it is output
+# as the new name. If it is not unique, a suffix of the form "_i" is appended
+# to the name, where i is a digit which (hopefully) makes the name unique.
+#
+# B.Simon 03-Nov-87 first code
+# B.Simon 04-Sep-90 Replaced call to strncmp with streq
+# B.Simon 16-Apr-99 Revised version to work with tjoin
+
+procedure renamecol (tji, jtab, jcol, colname, maxch)
+
+pointer tji[2] # i: Array of table info descriptors
+int jtab # i: Index of table containing column
+int jcol # i: Index of column within table
+char colname # u: Column name
+int maxch # i: Max length of column name
+#--
+bool before
+int olen, nmatch, nbefore, itab, icol
+pointer sp, oldnam, tmpnam, errtxt
+
+string notuniq "Cannot create a unique column name (%s)"
+
+bool streq()
+int strlen()
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (oldnam, SZ_COLNAME, TY_CHAR)
+ call salloc (tmpnam, SZ_COLNAME, TY_CHAR)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ # Copy name to temporrary variable
+
+ call strcpy (colname, Memc[oldnam], SZ_COLNAME)
+ call strupr (Memc[oldnam])
+
+ # See if the name is unique, and if not, how many columns with
+ # the same name precede this one
+
+ nmatch = 0
+ nbefore = 0
+ before = true
+
+ do itab = 1, 2 {
+ do icol = 1, TJ_DNUM(tji[itab]) {
+ call tbcigt (TJ_DCOL(tji[itab],icol), TBL_COL_NAME,
+ Memc[tmpnam], SZ_COLNAME)
+ call strupr (Memc[tmpnam])
+
+ if (streq (Memc[tmpnam], Memc[oldnam])) {
+ nmatch = nmatch + 1
+
+ if (before)
+ nbefore = nbefore + 1
+ }
+
+ if (itab == jtab && icol == jcol)
+ before = false
+ }
+ }
+
+ # If the name is not unique, add a suffix of the form "_i"
+
+ if (nmatch > 1) {
+
+ # Check for ridiculous values of maxch
+
+ olen = min (maxch-2, strlen(Memc[oldnam]))
+ if (olen < 1) {
+ call sprintf (Memc[errtxt], SZ_LINE, notuniq)
+ call pargstr (Memc[oldnam])
+ call error (1, Memc[errtxt])
+ }
+
+ # Add the suffix
+
+ Memc[oldnam+olen] = '_'
+ Memc[oldnam+olen+1] = TO_DIGIT (nbefore)
+ Memc[oldnam+olen+2] = EOS
+
+ # Make sure it is unique
+
+ do itab = 1, 2 {
+ do icol = 1, TJ_DNUM(tji[itab]) {
+ call tbcigt (TJ_DCOL(tji[itab],icol), TBL_COL_NAME,
+ Memc[tmpnam], SZ_COLNAME)
+
+ if (streq (Memc[oldnam], Memc[tmpnam])) {
+ call sprintf (Memc[errtxt], SZ_LINE, notuniq)
+ call pargstr (Memc[oldnam])
+ call error (1, Memc[errtxt])
+ }
+ }
+ }
+ }
+
+ # Copy to the output string
+
+ call strcpy (Memc[oldnam], colname, maxch)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tjoin/spptype.x b/pkg/utilities/nttools/tjoin/spptype.x
new file mode 100644
index 00000000..e454c9ba
--- /dev/null
+++ b/pkg/utilities/nttools/tjoin/spptype.x
@@ -0,0 +1,29 @@
+include <tbset.h>
+
+# B.Simon 16-Apr-99 first code
+
+# SPP_TYPE -- Retrieve the spp type of a table column
+
+int procedure spp_type (cp)
+
+pointer cp # i: Column pointer
+#--
+int dtype
+int tbcigi()
+
+begin
+ if (cp == NULL) {
+ # Null column pointer indicates row number
+
+ dtype = TY_INT
+
+ } else {
+ # Table data types store strings as negative values
+
+ dtype = tbcigi (cp, TBL_COL_DATATYPE)
+ if (dtype < 0)
+ dtype = TY_CHAR
+ }
+
+ return (dtype)
+end
diff --git a/pkg/utilities/nttools/tjoin/tjoin.h b/pkg/utilities/nttools/tjoin/tjoin.h
new file mode 100644
index 00000000..2e7155b0
--- /dev/null
+++ b/pkg/utilities/nttools/tjoin/tjoin.h
@@ -0,0 +1,27 @@
+# TJOIN.H -- Constants and data structures used by tjoin
+
+define ROWNAME "row" # string that indicates row number
+ # as join column
+
+# Structure used to hold information about tables
+
+define LEN_TJSTRUCT 7
+
+define TJ_TAB Memi[$1] # Table descriptor
+define TJ_JNUM Memi[$1+1] # Number of join columns
+define TJ_DNUM Memi[$1+2] # Number of data columns
+define TJ_JPTR Memi[$1+3] # Pointer to array of join columns
+define TJ_DPTR Memi[$1+4] # Pointer to array of data colomns
+
+define TJ_JCOL Memi[TJ_JPTR($1)+$2-1]
+define TJ_DCOL Memi[TJ_DPTR($1)+$2-1]
+
+# Structure used to hold tolerance vector
+
+define LEN_TOLSTRUCT 2
+
+define TOL_NUM Memi[$1] # Number of tolerance values
+define TOL_PTR Memi[$1+1] # Pointer to array of tolerance values
+
+define TOL_VAL Memd[TOL_PTR($1)+$2-1]
+
diff --git a/pkg/utilities/nttools/tjoin/tjoin.x b/pkg/utilities/nttools/tjoin/tjoin.x
new file mode 100644
index 00000000..39963721
--- /dev/null
+++ b/pkg/utilities/nttools/tjoin/tjoin.x
@@ -0,0 +1,124 @@
+include <tbset.h>
+include "tjoin.h"
+
+define SYNTAX 1
+define BIG_TABLE 5000
+
+# TJOIN -- Join two tables on the basis of equality in a common column
+#
+# B.Simon 03-Nov-1987 First Code
+# Phil Hodge 08-Apr-1999 Call tbfpri.
+# B.Simon 16-Apr-1999 Support outer join and multiple join columns
+# Phil Hodge 21-Jun-2001 Realloc TOL_PTR before copying tolerance value
+
+procedure t_tjoin()
+
+pointer intable1 # Names of the first table to be joined
+pointer intable2 # Names of the second table to be joined
+pointer outtable # Name of output table
+pointer column1 # Name of columns to join in first table
+pointer column2 # Name of columns to join in second table
+pointer extrarows # Include unmatched rows from which table?
+pointer tolerance # Tolerance used in testing for equality
+bool casesens # Case sensitivity flag
+#--
+int phu_copied # set by tbfpri and ignored
+int extra, ival
+pointer sp, errtxt, tj1, tj2, tjo, tol
+
+string extraopt "|neither|first|both|"
+string badextra "Illegal value for extrarows"
+string badjnum "Number of join columns do not match"
+string badtolnum "Number of tolereances and join columns do not match"
+string badcolnam "Column name not found in table (%s)"
+
+bool clgetb()
+int strdic()
+pointer read_tol(), open_itab(), open_otab()
+
+begin
+ # Allocate stack memory for strings
+
+ call smark (sp)
+ call salloc (intable1, SZ_FNAME, TY_CHAR)
+ call salloc (column1, SZ_COLNAME, TY_CHAR)
+ call salloc (intable2, SZ_FNAME, TY_CHAR)
+ call salloc (column2, SZ_COLNAME, TY_CHAR)
+ call salloc (outtable, SZ_FNAME, TY_CHAR)
+ call salloc (extrarows, SZ_FNAME, TY_CHAR)
+ call salloc (tolerance, SZ_FNAME, TY_CHAR)
+ call salloc (errtxt, SZ_LINE, TY_CHAR)
+
+ # Read the task parameters
+
+ call clgstr ("intable1", Memc[intable1], SZ_FNAME)
+ call clgstr ("intable2", Memc[intable2], SZ_FNAME)
+ call clgstr ("outtable", Memc[outtable], SZ_FNAME)
+
+ call clgstr ("column1", Memc[column1], SZ_COLNAME)
+ call clgstr ("column2", Memc[column2], SZ_COLNAME)
+
+ call clgstr ("extrarows", Memc[extrarows], SZ_FNAME)
+ call clgstr ("tolerance", Memc[tolerance], SZ_FNAME)
+ casesens = clgetb ("casesens")
+
+ # Check value of extrarows
+
+ extra = strdic (Memc[extrarows], Memc[extrarows], SZ_FNAME, extraopt)
+
+ if (extra == 0) {
+ call sprintf (Memc[errtxt], SZ_LINE, badextra)
+ call pargstr (Memc[extrarows])
+ call error (SYNTAX, Memc[errtxt])
+ }
+
+ extra = extra - 1
+
+ # Parse the string of tolerance values
+
+ tol = read_tol (Memc[tolerance])
+
+ # Open the input tables and get the column pointers
+
+ tj1 = open_itab (Memc[intable1], Memc[column1])
+ tj2 = open_itab (Memc[intable2], Memc[column2])
+
+ # Check the number of join columns and tolerances for agreement
+
+ if (TJ_JNUM(tj1) != TJ_JNUM(tj2))
+ call error (1, badjnum)
+
+ if (TJ_JNUM(tj1) != TOL_NUM(tol)) {
+ if (TOL_NUM(tol) == 1) {
+ TOL_NUM(tol) = TJ_JNUM(tj1)
+ call realloc (TOL_PTR(tol), TOL_NUM(tol), TY_DOUBLE)
+ do ival = 2, TJ_JNUM(tj1)
+ TOL_VAL(tol,ival) = TOL_VAL(tol,1)
+ } else {
+ call error (1, badtolnum)
+ }
+ }
+
+ # Remove data columns from second table which are also
+ # join columns in the first table
+
+ call remove_jcol (tj2, tol)
+
+ # Create the output table
+
+ call tbfpri (Memc[intable1], Memc[outtable], phu_copied)
+ tjo = open_otab (Memc[outtable], tj1, tj2)
+
+ # Compute the join of the two tables
+
+ call dojoin (tj1, tj2, tjo, tol, extra, casesens)
+
+ # Close the tables and free dynamic memory
+
+ call free_tol (tol)
+
+ call close_iotab (tj1)
+ call close_iotab (tj2)
+ call close_iotab (tjo)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tlcol.par b/pkg/utilities/nttools/tlcol.par
new file mode 100644
index 00000000..c4ba900a
--- /dev/null
+++ b/pkg/utilities/nttools/tlcol.par
@@ -0,0 +1,4 @@
+# parameter file for the tlcol task
+table,s,a,"",,,"name of table"
+nlist,i,h,4,1,4,"number of items to list"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/tlinear.par b/pkg/utilities/nttools/tlinear.par
new file mode 100644
index 00000000..b05d2843
--- /dev/null
+++ b/pkg/utilities/nttools/tlinear.par
@@ -0,0 +1,10 @@
+intable,s,a,"",,,"input tables"
+outtable,s,a,"STDOUT",,,"output tables or STDOUT"
+xcol,s,a,"",,,"x column in input tables"
+ycol,s,a,"",,,"y column in input tables"
+wcol,s,h,"",,,"weight column in input tables"
+scol,s,h,"",,,"standard deviation column in input tables"
+rows,s,h,"-",,,"range of rows to use for fit"
+outcoly,s,h,"yfit",,,"column name for fitted y values"
+outcolr,s,h,"yres",,,"column name for residual values"
+mode,s,h,"al"
diff --git a/pkg/utilities/nttools/tlinear/mkpkg b/pkg/utilities/nttools/tlinear/mkpkg
new file mode 100644
index 00000000..0957be91
--- /dev/null
+++ b/pkg/utilities/nttools/tlinear/mkpkg
@@ -0,0 +1,11 @@
+# Update tlinear in the ttools package library.
+# Author: STOBIE, 15-FEB-1989
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ tlinear.x <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/tlinear/tlinear.x b/pkg/utilities/nttools/tlinear/tlinear.x
new file mode 100644
index 00000000..c7af6131
--- /dev/null
+++ b/pkg/utilities/nttools/tlinear/tlinear.x
@@ -0,0 +1,468 @@
+include <fset.h> # to check whether input or output is redirected
+include <tbset.h>
+define MAX_RANGES (SZ_LINE/2) # max number of ranges of row numbers
+
+# tlinear -- first order fit to y or x and y columns by linear regression
+#
+# E.B. Stobie 15-Feb-1989 Task created.
+# Phil Hodge 4-Oct-1995 Use table name template routines tbnopen, etc.
+# Phil Hodge 24-Sep-1997 Replace IS_INDEF with IS_INDEFD.
+# Phil Hodge 8-Apr-1999 Call tbfpri.
+# Phil Hodge 8-Jun-1999 Set input/output to STDIN/STDOUT if redirected.
+# Phil Hodge 38-Aug-2000 Completely exclude points with weight of zero.
+
+procedure tlinear()
+
+pointer inlist, outlist # scr for input & output lists of names
+char xcol[SZ_COLNAME] # x column name
+char ycol[SZ_COLNAME] # y column name
+char wcol[SZ_COLNAME] # weight column name
+char scol[SZ_COLNAME] # standard deviations column name
+char outcoly[SZ_COLNAME] # column name for fitted y values
+char outcolr[SZ_COLNAME] # column name for y residual values
+char cyu[SZ_COLUNITS] # column units for y
+char cxu[SZ_COLUNITS] # column units for x
+char cwu[SZ_COLUNITS] # column units for w
+char csu[SZ_COLUNITS] # column units for s
+char cyf[SZ_COLFMT] # column format for y
+char cxf[SZ_COLFMT] # column format for x
+char cwf[SZ_COLFMT] # column format for w
+char csf[SZ_COLFMT] # column format for s
+#--
+pointer sp
+pointer list1, list2 # for lists of input and output tables
+pointer itp, otp # ptr to table descriptor
+pointer xcptr # ptr to x column descriptor
+pointer ycptr # ptr to y column descriptor
+pointer wcptr # ptr to weighting column descriptor
+pointer scptr # ptr to standard deviations
+pointer ocpx, ocpy # ptr to output x and y columns
+pointer ocpw, ocps # ptr to output w and s columns
+pointer ocpf, ocpr # ptr to col descr for output columns
+pointer intab, outtab # scr for names of input & output tables
+pointer range_string # string which gives ranges of row numbers
+pointer points # ptr to valid points array
+pointer as, bs, chi2s # storage for fitted results
+pointer siga2s, sigb2s # storage for errors
+pointer nptss, nrowss # storage for no pts
+pointer srms, rmss # storage for rms and mean of residuals
+
+double s, sx, sy # intermediate variables for fit
+double xval, yval # x and y values to be fitted
+double wval, sval # weighting values
+double fval, rval # fitted values and residuals
+double wgt, xpt, ypt # actual values used in fit
+double a, b, siga2, sigb2 # coefficients and their sigmas
+double chi2, sigdat # chi squared
+double avx, t, st2 # intermediate values used in fit
+double sr, sr2, srx # intermediate values for rms
+double rms, srm # mean and rms of residuals
+double yres # individual fitted y values and residuals
+
+int junk, i
+int nrows, count # number of rows, number of tables
+int nvalues, stat
+int row, npts
+int maxtab # maximum number of tables in input list
+int ranges[3,MAX_RANGES]
+int cxn, cyn, cwn, csn # column number
+int cxl, cyl, cwl, csl # lendata
+int cxdt, cydt, cwdt, csdt # datatype
+int cxfl, cyfl, cwfl, csfl # length of format
+int phu_copied # set by tbfpri and ignored
+
+bool listout # is the output ASCII rather than a table?
+bool done, point
+bool xpoint, weight, stdev
+
+int fstati()
+pointer tbtopn(), tbnopen()
+int tbnget(), tbnlen()
+int decode_ranges(), get_next_number()
+int tbpsta()
+bool streq()
+
+begin
+ # Allocate scratch for lists of names and for table names.
+ call smark (sp)
+ call salloc (inlist, SZ_FNAME, TY_CHAR)
+ call salloc (outlist, SZ_FNAME, TY_CHAR)
+ call salloc (intab, SZ_FNAME, TY_CHAR)
+ call salloc (outtab, SZ_FNAME, TY_CHAR)
+ call salloc (range_string, SZ_FNAME, TY_CHAR)
+
+ # Get task parameters.
+
+ if (fstati (STDIN, F_REDIR) == YES)
+ call strcpy ("STDIN", Memc[inlist], SZ_FNAME)
+ else
+ call clgstr ("intable", Memc[inlist], SZ_FNAME)
+
+ if (fstati (STDOUT, F_REDIR) == YES)
+ call strcpy ("STDOUT", Memc[outlist], SZ_FNAME)
+ else
+ call clgstr ("outtable", Memc[outlist], SZ_FNAME)
+
+ call clgstr ("xcol", xcol, SZ_COLNAME)
+ call clgstr ("ycol", ycol, SZ_COLNAME)
+ call clgstr ("wcol", wcol, SZ_COLNAME)
+ call clgstr ("scol", scol, SZ_COLNAME)
+ call clgstr ("rows", Memc[range_string], SZ_FNAME)
+
+ listout = streq (Memc[outlist], "STDOUT") # ASCII output?
+ if ( ! listout ) {
+ call clgstr ("outcoly", outcoly, SZ_COLNAME)
+ call clgstr ("outcolr", outcolr, SZ_COLNAME)
+ }
+
+ # Expand the input table list.
+ list1 = tbnopen (Memc[inlist])
+
+ if ( ! listout ) {
+ # Expand the output table list.
+ list2 = tbnopen (Memc[outlist])
+ if (tbnlen (list1) != tbnlen (list2)) {
+ call tbnclose (list1)
+ call tbnclose (list2)
+ call error (1,
+ "Number of input and output tables not the same")
+ }
+ }
+
+ # allocate arrays for results
+ count = 0
+ maxtab = 200
+ call malloc (as, maxtab, TY_DOUBLE)
+ call malloc (bs, maxtab, TY_DOUBLE)
+ call malloc (chi2s, maxtab, TY_DOUBLE)
+ call malloc (siga2s, maxtab, TY_DOUBLE)
+ call malloc (sigb2s, maxtab, TY_DOUBLE)
+ call malloc (srms, maxtab, TY_DOUBLE)
+ call malloc (rmss, maxtab, TY_DOUBLE)
+ call malloc (nrowss, maxtab, TY_INT)
+ call malloc (nptss, maxtab, TY_INT)
+
+ # Do for each input table.
+ while (tbnget (list1, Memc[intab], SZ_FNAME) != EOF) {
+
+ itp = tbtopn (Memc[intab], READ_ONLY, NULL)
+ call tbcfnd (itp, ycol, ycptr, 1)
+ if (ycptr == NULL) {
+ call tbtclo (itp)
+ call eprintf ("column not found in %s\n")
+ call pargstr (Memc[intab])
+ if ( ! listout ) # skip next output table
+ junk = tbnget (list2, Memc[outtab], SZ_FNAME)
+ next
+ }
+
+ call tbcfnd (itp, xcol, xcptr, 1)
+ if (xcptr != NULL) xpoint = true
+ else xpoint = false
+
+ call tbcfnd (itp, wcol, wcptr, 1)
+ if (wcptr != NULL ) {
+ weight = true
+ stdev = false
+
+ }
+ else {
+ weight = false
+ call tbcfnd (itp, scol, scptr, 1)
+ if (scptr != NULL ) stdev = true
+ else stdev = false
+ }
+
+ if (decode_ranges (Memc[range_string], ranges, MAX_RANGES, nvalues)
+ != OK)
+ call error (1, "bad range of row numbers")
+ # Create scratch for fitted values and residuals
+ nrows = tbpsta (itp, TBL_NROWS)
+ call malloc (points, nrows, TY_BOOL)
+
+ # xpoint = true use xcolumn, else use row for x
+ # weight = true use weights
+ # stdev = true (only if weight = false) use standard deviations
+
+ do i = 1, nrows {
+ Memb[points+i-1] = false
+ }
+
+ row = 0
+ npts = 0
+ s = 0.
+ sx = 0.
+ sy = 0.
+
+ stat = get_next_number (ranges, row)
+ done = (stat == EOF) || (row > nrows)
+
+ while (! done) {
+
+ wgt = 1.
+ xpt = row
+ call tbegtd (itp, ycptr, row, yval)
+
+ if (!IS_INDEFD(yval)) {
+ point = true
+ ypt = yval
+
+ if (xpoint) {
+ call tbegtd (itp, xcptr, row, xval)
+ if (!IS_INDEFD(xval)) xpt = xval
+ else point = false
+ }
+
+ if (weight) {
+ call tbegtd (itp, wcptr, row, wval)
+ if (!IS_INDEFD(wval)) wgt = wval
+ else point = false
+ if (wgt == 0.d0)
+ point = false
+ }
+
+ if (stdev) {
+ call tbegtd (itp, scptr, row, sval)
+ if (!IS_INDEFD(sval)) wgt = 1./(sval*sval)
+ else point = false
+ }
+ }
+ else point = false
+
+ if (point) {
+
+ Memb[points+row-1] = true
+ npts = npts + 1
+ s = s + wgt
+ sx = sx + xpt * wgt
+ sy = sy + ypt * wgt
+ }
+
+ stat=get_next_number(ranges,row)
+ done=(stat == EOF) || (row > nrows)
+ }
+
+ if (npts > 1) {
+
+ avx = sx/s
+ t = 0.
+ st2 = 0.
+ b = 0.
+
+ do i = 1, nrows {
+
+ if (Memb[points+i-1]) {
+ row = i
+ xpt = i
+ wgt = 1.
+
+ call tbegtd (itp, ycptr, row, ypt)
+ if (xpoint) {
+ call tbegtd (itp, xcptr, row, xval)
+ xpt = xval
+ }
+ if (weight) {
+ call tbegtd (itp, wcptr, row, wval)
+ wgt = wval
+ }
+ if (stdev) {
+ call tbegtd (itp, scptr, row, sval)
+ wgt = 1. / (sval*sval)
+ }
+
+ t = xpt - avx
+ st2 = st2 + t * t * wgt
+ b = b + t * ypt * wgt
+ }
+ }
+
+ if (st2 > 0.) {
+
+ b = b / st2
+ a = (sy - sx * b) / s
+ siga2 = sqrt ((1. + (sx*sx) / (s * st2)) / s)
+ sigb2 = sqrt (1. / st2)
+ chi2 = 0.
+ sr = 0.
+ sr2 = 0.
+
+ do i = 1, nrows {
+
+ if (Memb[points+i-1]) {
+ row = i
+ xpt = i
+ wgt = 1.
+
+ call tbegtd (itp, ycptr, row, ypt)
+ if (xpoint) {
+ call tbegtd (itp, xcptr, row, xval)
+ xpt = xval
+ }
+ if (weight) {
+ call tbegtd (itp, wcptr, row, wval)
+ wgt = wval
+ }
+ if (stdev) {
+ call tbegtd (itp, scptr, row, sval)
+ wgt = 1. / (sval*sval)
+ }
+ yres = ypt - (a + b * xpt)
+ chi2 = chi2 + yres * yres * wgt
+ sr = sr + yres
+ sr2 = sr2 + yres * yres
+ }
+ }
+
+ sigdat = 1.
+ if (!weight && !stdev) sigdat = sqrt (chi2 / (npts - 2))
+ siga2 = siga2 * sigdat
+ sigb2 = sigb2 * sigdat
+
+ srm = sr / npts
+ srx = sr2 - (sr*sr)/npts
+ rms = sqrt (srx / (npts - 1))
+
+ # Save fit values
+ Memd[as+count] = a
+ Memd[bs+count] = b
+ Memd[chi2s+count] = chi2
+ Memd[siga2s+count] = siga2
+ Memd[sigb2s+count] = sigb2
+ Memd[srms+count] = srm
+ Memd[rmss+count] = rms
+ Memi[nptss+count] = npts
+ Memi[nrowss+count] = nrows
+ count = count + 1
+
+ if (! listout) {
+
+ # Create output table & define columns.
+ junk = tbnget (list2, Memc[outtab], SZ_FNAME)
+ call tbfpri (Memc[intab], Memc[outtab], phu_copied)
+ otp = tbtopn (Memc[outtab], NEW_FILE, NULL)
+ if (xpoint) {
+ call tbcinf (xcptr, cxn, xcol, cxu, cxf, cxdt, cxl,
+ cxfl)
+ call tbcdef (otp, ocpx, xcol, cxu, cxf, cxdt, cxl, 1)
+ }
+ call tbcinf (ycptr, cyn, ycol, cyu, cyf, cydt, cyl, cyfl)
+ call tbcdef (otp, ocpy, ycol, cyu, cyf, cydt, cyl, 1)
+ if (weight) {
+ call tbcinf (wcptr, cwn, wcol, cwu, cwf, cwdt, cwl,
+ cwfl)
+ call tbcdef (otp, ocpw, wcol, cwu, cwf, cwdt, cwl, 1)
+ }
+ if (stdev) {
+ call tbcinf (scptr, csn, scol, csu, csf, csdt, csl,
+ csfl)
+ call tbcdef (otp, ocps, scol, csu, csf, csdt, csl, 1)
+ }
+ call tbcdef (otp, ocpf,
+ outcoly, "", "", TY_DOUBLE, 1, 1)
+ call tbcdef (otp, ocpr,
+ outcolr, "", "", TY_DOUBLE, 1, 1)
+ call tbtcre (otp)
+
+ # Put info records in the header.
+ call tbhadt (otp, "intable", Memc[intab])
+ if (xpoint) call tbhadt (otp, "xcol", xcol)
+ call tbhadt (otp, "ycol", ycol)
+ if (weight) call tbhadt (otp, "wcol", wcol)
+ if (stdev) call tbhadt (otp, "scol", scol)
+ call tbhadi (otp, "nrows", nrows)
+
+ call tbhadd (otp, "a", a)
+ call tbhadd (otp, "b", b)
+ call tbhadd (otp, "siga2", siga2)
+ call tbhadd (otp, "sigb2", sigb2)
+ call tbhadd (otp, "chi2", chi2)
+
+ # Write the values into the output table, and close it.
+ do i = 1, nrows {
+
+ point = true
+ row = i
+ xpt = i
+ if (xpoint) {
+ call tbegtd (itp, xcptr, row, xval)
+ call tbeptd (otp, ocpx, row, xval)
+ if (IS_INDEFD (xval)) point = false
+ else xpt = xval
+ }
+ if (point) {
+ fval = a + b * xpt
+ call tbeptd (otp, ocpf, row, fval)
+ call tbegtd (itp, ycptr, row, yval)
+ call tbeptd (otp, ocpy, row, yval)
+ if (!IS_INDEFD (yval)) {
+ rval = yval - fval
+ call tbeptd (otp, ocpr, row, rval)
+ }
+ if (weight) {
+ call tbegtd (itp, wcptr, row, wval)
+ call tbeptd (otp, ocpw, row, wval)
+ }
+ if (stdev) {
+ call tbegtd (itp, scptr, row, sval)
+ call tbeptd (otp, ocps, row, sval)
+ }
+ }
+
+ }
+ call tbtclo (otp)
+ }
+ }
+ else {
+ call printf("Must have at least 2 unique x values.")
+ call printf(" Cannot fit!\n")
+ }
+ }
+ call mfree (points, TY_BOOL)
+ call tbtclo (itp)
+ }
+ call tbnclose (list1)
+ if ( ! listout )
+ call tbnclose (list2)
+
+ if (count > 0) {
+ call printf ("# Fit by linear regression (y = a + bx)\n")
+ call printf (" \n")
+ call printf ("# Table pts in row pts in fit a")
+ call printf (" b\n")
+ call printf (" \n")
+
+ do i = 1, count {
+ call printf ("%6d %10d %13d %18.8g %18.8g\n")
+ call pargi (i)
+ call pargi (Memi[nrowss+i-1])
+ call pargi (Memi[nptss+i-1])
+ call pargd (Memd[as+i-1])
+ call pargd (Memd[bs+i-1])
+ }
+ call printf (" \n")
+ call printf (" \n")
+
+ call printf("# Table siga2 sigb2 chi2")
+ call printf(" residual rms residual mean\n")
+ call printf (" \n")
+ do i = 1, count {
+ call printf (" %d %13.7g %13.7g %13.7g %13.7g %13.7g\n")
+ call pargi (i)
+ call pargd (Memd[siga2s+i-1])
+ call pargd (Memd[sigb2s+i-1])
+ call pargd (Memd[chi2s+i-1])
+ call pargd (Memd[rmss+i-1])
+ call pargd (Memd[srms+i-1])
+ }
+ }
+ call mfree (as, TY_DOUBLE)
+ call mfree (bs, TY_DOUBLE)
+ call mfree (chi2s, TY_DOUBLE)
+ call mfree (siga2s, TY_DOUBLE)
+ call mfree (sigb2s, TY_DOUBLE)
+ call mfree (srms, TY_DOUBLE)
+ call mfree (rmss, TY_DOUBLE)
+ call mfree (nptss, TY_INT)
+ call mfree (nrowss, TY_INT)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tmatch.par b/pkg/utilities/nttools/tmatch.par
new file mode 100644
index 00000000..5cbb516f
--- /dev/null
+++ b/pkg/utilities/nttools/tmatch.par
@@ -0,0 +1,18 @@
+input1,s,a,,,,First input table
+input2,s,a,,,,Second input table
+output,s,a,,,,Output table
+match1,s,a,,,,Columns to match in first table
+match2,s,a,,,,Columns to match in second table
+maxnorm,r,a,,0.0,,Maximum distance for allowed match
+incol1,s,h," ",,,Columns copied to output from first table
+incol2,s,h," ",,,Columns copied to output from second table
+factor,s,h," ",,,Weighting factors used in computing distance
+diagfile,s,h," ",,,Diagnostic output file
+nmcol1,s,h," ",,,ID columns in diagnostic output from first table
+nmcol2,s,h," ",,,ID columns in diagnostic output from second table
+sphere,b,h,no,,,Apply spherical correction?
+
+
+
+
+
diff --git a/pkg/utilities/nttools/tmatch/getmatch.x b/pkg/utilities/nttools/tmatch/getmatch.x
new file mode 100644
index 00000000..083d4156
--- /dev/null
+++ b/pkg/utilities/nttools/tmatch/getmatch.x
@@ -0,0 +1,101 @@
+#* HISTORY *
+#* B.Simon 24-Aug-94 Original
+#* B.Simon 18-Sep-00 Revised search termination criterion
+
+# GETMATCH -- Find rows in second table witch match rows in first
+
+procedure getmatch (in1, in2, ncol, col1, col2, weight, nrow1, index1,
+ nrow2, index2, maxnorm, sphere, closest, dist)
+
+pointer in1 # i: first table descriptor
+pointer in2 # i: second table descriptor
+int ncol # i: number of match columns
+pointer col1[ARB] # i: match columns in first table
+pointer col2[ARB] # i: match columns in second table
+double weight[ARB] # i: weights used in computing norm
+int nrow1 # i: number of rows in first table
+int index1[ARB] # i: sorted row indices for first table
+int nrow2 # i: number of rows in second table
+int index2[ARB] # i: sorted row indices for second table
+double maxnorm # i: maximum norm used in match
+bool sphere # i: apply spherical correction to first column?
+int closest[ARB] # o: closest match in second table to first
+double dist[ARB] # o: distance between matched rows
+#--
+double sqnorm, proj, abnorm, norm, minabnorm, minnorm
+int idx, jdx, irow, jrow, krow, jlast
+
+begin
+ jlast = 1
+ sqnorm = maxnorm * maxnorm
+
+ # Find the row in the second table which minimizes the norm for
+ # each row of the first table
+
+
+ do idx = 1, nrow1 {
+ irow = index1[idx]
+ jrow = index2[jlast]
+
+ # The initial guess is the row which matched last time
+
+ call getnorm (in1, in2, ncol, col1, col2, irow, jrow,
+ weight, sphere, proj, abnorm, norm)
+
+ minabnorm = abnorm
+ minnorm = norm
+ krow = jrow
+
+ # Search backwards for a row which minimizes the norm
+ # Terminate the search when the first dimension of the norm (proj)
+ # is greater than the minimum norm, as all subsequent rows have
+ # norms that must be greater than the minimum
+
+ do jdx = jlast-1, 1, -1 {
+ jrow = index2[jdx]
+
+ call getnorm (in1, in2, ncol, col1, col2, irow, jrow,
+ weight, sphere, proj, abnorm, norm)
+
+ if (proj > minabnorm)
+ break
+
+ if (norm < minnorm) {
+ minabnorm = abnorm
+ minnorm = norm
+ krow = jrow
+ }
+ }
+
+ # Search forwards for a row that minimizes the norm
+ # Use the same termination condition as for the forwards search
+
+ do jdx = jlast+1, nrow2 {
+ jrow = index2[jdx]
+
+ call getnorm (in1, in2, ncol, col1, col2, irow, jrow,
+ weight, sphere, proj, abnorm, norm)
+
+ if (proj > minabnorm)
+ break
+
+ if (norm < minnorm) {
+ minabnorm = abnorm
+ minnorm = norm
+ krow = jrow
+ }
+ }
+
+ if (minnorm > sqnorm) {
+ dist[irow] = maxnorm
+ closest[irow] = 0
+ } else {
+ dist[irow] = sqrt (minnorm)
+ closest[irow] = krow
+ }
+
+ jlast = krow
+ }
+
+end
+
diff --git a/pkg/utilities/nttools/tmatch/getnorm.x b/pkg/utilities/nttools/tmatch/getnorm.x
new file mode 100644
index 00000000..fed277c6
--- /dev/null
+++ b/pkg/utilities/nttools/tmatch/getnorm.x
@@ -0,0 +1,67 @@
+include <math.h>
+
+#* HISTORY *
+#* B.Simon 24-Aug-94 original
+#* B.Simon 18-Sep-00 Revised computation of proj and added abnorm
+
+# GETNORM -- Compute the squared norm between two table rows
+
+procedure getnorm (in1, in2, ncol, col1, col2, row1, row2, weight, sphere,
+ proj, abnorm, norm)
+
+pointer in1 # i: first table descriptor
+pointer in2 # i: second table descriptor
+int ncol # i: number of match columns
+pointer col1[ARB] # i: match columns in first table
+pointer col2[ARB] # i: match columns in second table
+int row1 # i: row number in first table
+int row2 # i: row number in second table
+double weight[ARB] # i: weights used in computing norm
+bool sphere # i: apply spherical correction to first column?
+double proj # o: projection of norm on first axis
+double abnorm # o: norm, possibly without spherical correction
+double norm # o: norm (distance) between rows in two tables
+#--
+int i
+double val1, val2, dif
+
+begin
+ # Calculate first component of norm
+
+ call tbegtd (in1, col1[1], row1, val1)
+ call tbegtd (in2, col2[1], row2, val2)
+
+ dif = weight[1] * (val1 - val2)
+ proj = dif * dif
+ abnorm = proj
+
+ # Apply correction for spherical coordinates
+
+ if (sphere) {
+ if (dif > 180) {
+ dif = dif - 360
+ } else if (dif < -180) {
+ dif = dif + 360
+ }
+
+ call tbegtd (in1, col1[2], row1, val1)
+ call tbegtd (in2, col2[2], row2, val2)
+
+ val1 = 0.5 * weight[2] * (val1 + val2)
+ dif = dif * cos (DEGTORAD(val1))
+ }
+
+ # Compute remaining components
+
+ norm = dif * dif
+ do i = 2, ncol {
+ call tbegtd (in1, col1[i], row1, val1)
+ call tbegtd (in2, col2[i], row2, val2)
+
+ dif = weight[i] * (val1 - val2)
+ abnorm = abnorm + dif * dif
+ norm = norm + dif * dif
+ }
+
+end
+
diff --git a/pkg/utilities/nttools/tmatch/getweight.x b/pkg/utilities/nttools/tmatch/getweight.x
new file mode 100644
index 00000000..ef8b9204
--- /dev/null
+++ b/pkg/utilities/nttools/tmatch/getweight.x
@@ -0,0 +1,96 @@
+include <math.h>
+include <tbset.h>
+
+#* HISTORY *
+#* B.Simon 24-Aug-94 original
+
+# GETWEIGHT -- Get array of weights from list of factors or tables
+
+procedure getweight (ncol, col1, col2, factor, weight)
+
+int ncol # i: number of match columns
+pointer col1[ARB] # i: match columns from first table
+pointer col2[ARB] # i: match columns from second table
+char factor[ARB] # i: list of factors
+double weight[ARB] # o: array of weights
+#--
+double unitval[6]
+int invert[6]
+int ic, jc, nc, icol, jcol, type1, type2, item
+pointer sp, value, unit1, unit2, errmsg
+
+
+data unitval / 1.0, 3600.0, 60.0, 1.0, 15.0, RADIAN /
+data invert / NO, YES, YES, NO, NO, NO /
+
+string unitlist "|seconds|minutes|degrees|hours|radians|"
+string badvalue "Value in factor string is not a number (%s)"
+string badunits "Units mismatch in column %d of tables"
+
+int ctod(), word_fetch(), strdic()
+
+begin
+ # Allocate memory for temporary strings
+
+ call smark (sp)
+ call salloc (value, SZ_FNAME, TY_CHAR)
+ call salloc (unit1, SZ_FNAME, TY_CHAR)
+ call salloc (unit2, SZ_FNAME, TY_CHAR)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ # Get each string from the list and convert to a number
+
+ ic = 1
+ icol = 0
+ while (word_fetch (factor, ic, Memc[value], SZ_FNAME) > 0) {
+ icol = icol + 1
+
+ jc = 1
+ nc = ctod (Memc[value], jc, weight[icol])
+ if (Memc[value+jc-1] != EOS) {
+ call sprintf (Memc[errmsg], SZ_LINE, badvalue)
+ call pargstr (Memc[value])
+
+ call error (1, Memc[errmsg])
+ }
+ }
+
+ # Set remaining weights according to column units
+
+ do jcol = icol+1, ncol {
+ # Read units from table
+
+ call tbcigt (col1[jcol], TBL_COL_UNITS, Memc[unit1], SZ_FNAME)
+ call tbcigt (col2[jcol], TBL_COL_UNITS, Memc[unit2], SZ_FNAME)
+
+ # Search for units in dictionary
+
+ call strlwr (Memc[unit1])
+ call strlwr (Memc[unit2])
+
+ type1 = strdic (Memc[unit1], Memc[unit1], SZ_FNAME, unitlist)
+ type2 = strdic (Memc[unit2], Memc[unit2], SZ_FNAME, unitlist)
+
+ # Take exit if units do not match
+
+ if (type1 != type2) {
+ call sprintf (Memc[errmsg], SZ_LINE, badunits)
+ call pargi (jcol)
+
+ call error (1, Memc[errmsg])
+ }
+
+ # Read corresponding weight from unit value array
+ # The first weight (1.0) is for missing or unknown units
+
+ item = type1 + 1
+
+ if (invert[item] == NO) {
+ weight[jcol] = unitval[item]
+ } else {
+ weight[jcol] = 1.0 / unitval[item]
+ }
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tmatch/infomatch.x b/pkg/utilities/nttools/tmatch/infomatch.x
new file mode 100644
index 00000000..d90f89a8
--- /dev/null
+++ b/pkg/utilities/nttools/tmatch/infomatch.x
@@ -0,0 +1,219 @@
+include <tbset.h>
+
+#* HISTORY *
+#* B.Simon 25-Aug-94 original
+
+# INFOMATCH -- Print diagnostic information for tmatch
+
+procedure infomatch (diagfile, in1, in2, nmcol1, nmcol2, maxnorm,
+ nclosest, closest, dist)
+
+char diagfile[ARB] # i: diagnostic output file
+pointer in1 # i: first table's descriptor
+pointer in2 # i: second table's descriptor
+char nmcol1[ARB] # i: name columns in first table
+char nmcol2[ARB] # i: name columns in second table
+double maxnorm # i: maximum allowed distance between matched rows
+int nclosest # i: length of closest array
+int closest[ARB] # i: array of closest matches between tables
+double dist[ARB] # i: distance between matched rows
+#--
+bool first, same
+int fd, namelen, mxcol1, mxcol2, ncol1, ncol2, idx, jdx, irow, jrow
+pointer sp, index, name, col1, col2
+
+string ziptitle "\nThe following objects were not matched:\n"
+string duptitle "\nThe following objects matched the same object:\n"
+string bigtitle "\nThe following objects have the largest norms:\n"
+string normfmt "Norm = %0.7g\n"
+string rowformat "%d:%d %s\n"
+
+bool is_blank()
+int open(), envgeti(), tbpsta()
+
+begin
+ # Open the diagnostics file
+
+ if (is_blank (diagfile))
+ return
+
+ fd = open (diagfile, WRITE_ONLY, TEXT_FILE)
+
+ # Get maximum length of diagnostic string
+
+ iferr {
+ namelen = envgeti ("ttyncols") - 10
+ } then {
+ namelen = 70
+ }
+
+ # Allocate dynamic memory
+
+ call smark (sp)
+ call salloc (index, nclosest, TY_INT)
+ call salloc (name, namelen, TY_CHAR)
+
+ # Get column descriptors for name columns
+
+ mxcol1 = tbpsta (in1, TBL_NCOLS)
+ mxcol2 = tbpsta (in2, TBL_NCOLS)
+
+ call salloc (col1, mxcol1, TY_INT)
+ call salloc (col2, mxcol2, TY_INT)
+
+ if (is_blank (nmcol1)) {
+ ncol1 = 0
+ } else {
+ call tctexp (in1, nmcol1, mxcol1, ncol1, Memi[col1])
+ }
+
+ if (is_blank (nmcol2)) {
+ ncol2 = 0
+ } else {
+ call tctexp (in2, nmcol2, mxcol2, ncol2, Memi[col2])
+ }
+
+ # Sort the closest array
+
+ call setindex (Memi[index], nclosest)
+ call sortclose (nclosest, closest, Memi[index])
+
+ # Print the objects that were not matched
+
+ first = true
+ do idx = 1, nclosest {
+ irow = Memi[index+idx-1]
+ if (closest[irow] != 0)
+ break
+
+ if (first) {
+ first = false
+ call fprintf (fd, ziptitle)
+ }
+
+ call rowname (in1, irow, ncol1, Memi[col1], Memc[name], namelen)
+ call fprintf (fd, rowformat)
+ call pargi (1)
+ call pargi (irow)
+ call pargstr (Memc[name])
+ }
+
+ # Print the objects which are matched more than once
+
+ same = false
+ first = true
+ do idx = 2, nclosest {
+ irow = Memi[index+idx-1]
+ jrow = Memi[index+idx-2]
+
+ if (closest[irow] == 0)
+ next
+
+ if (closest[irow] == closest[jrow]) {
+ same = true
+
+ if (first) {
+ first = false
+ call fprintf (fd, duptitle)
+ }
+
+ call rowname (in1, jrow, ncol1, Memi[col1],
+ Memc[name], namelen)
+
+ call fprintf (fd, rowformat)
+ call pargi (1)
+ call pargi (jrow)
+ call pargstr (Memc[name])
+
+ } else if (same) {
+ same = false
+
+ call rowname (in1, jrow, ncol1, Memi[col1],
+ Memc[name], namelen)
+
+ call fprintf (fd, rowformat)
+ call pargi (1)
+ call pargi (jrow)
+ call pargstr (Memc[name])
+
+ call rowname (in2, closest[jrow], ncol2, Memi[col2],
+ Memc[name], namelen)
+
+ call fprintf (fd, rowformat)
+ call pargi (2)
+ call pargi (closest[jrow])
+ call pargstr (Memc[name])
+
+ call fprintf (fd, "\n")
+ }
+ }
+
+ if (same) {
+ same = false
+ irow = Memi[index+nclosest-1]
+
+ call rowname (in1, irow, ncol1, Memi[col1],
+ Memc[name], namelen)
+
+ call fprintf (fd, rowformat)
+ call pargi (1)
+ call pargi (irow)
+ call pargstr (Memc[name])
+
+ call rowname (in2, closest[irow], ncol2, Memi[col2],
+ Memc[name], namelen)
+
+ call fprintf (fd, rowformat)
+ call pargi (2)
+ call pargi (closest[irow])
+ call pargstr (Memc[name])
+
+ call fprintf (fd, "\n")
+ }
+
+ # Sort the dist array
+
+ call setindex (Memi[index], nclosest)
+ call sortdist (nclosest, dist, Memi[index])
+
+ # Print the ten objects with the largest norms
+
+ jdx = 0
+ do idx = nclosest, 1, -1 {
+ irow = Memi[index+idx-1]
+ if (dist[irow] == maxnorm)
+ next
+
+ if (jdx == 0)
+ call fprintf (fd, bigtitle)
+
+ jdx = jdx + 1
+ if (jdx > 10)
+ break
+
+ call fprintf (fd, normfmt)
+ call pargd (dist[irow])
+
+ call rowname (in1, irow, ncol1, Memi[col1],
+ Memc[name], namelen)
+
+ call fprintf (fd, rowformat)
+ call pargi (1)
+ call pargi (irow)
+ call pargstr (Memc[name])
+
+ call rowname (in2, closest[irow], ncol2, Memi[col2],
+ Memc[name], namelen)
+
+ call fprintf (fd, rowformat)
+ call pargi (2)
+ call pargi (closest[irow])
+ call pargstr (Memc[name])
+
+ call fprintf (fd, "\n")
+
+ }
+
+ call close (fd)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tmatch/mkpkg b/pkg/utilities/nttools/tmatch/mkpkg
new file mode 100644
index 00000000..b6e6be18
--- /dev/null
+++ b/pkg/utilities/nttools/tmatch/mkpkg
@@ -0,0 +1,20 @@
+# Update the tmatch application code in the ttools package library
+# Author: B.Simon, 30-Aug-94
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ getmatch.x
+ getnorm.x <math.h>
+ getweight.x <math.h> <tbset.h>
+ infomatch.x <tbset.h>
+ putmatch.x <tbset.h>
+ rowname.x
+ setindex.x
+ sortclose.x
+ sortdist.x
+ tmatch.x <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/tmatch/putmatch.x b/pkg/utilities/nttools/tmatch/putmatch.x
new file mode 100644
index 00000000..27407107
--- /dev/null
+++ b/pkg/utilities/nttools/tmatch/putmatch.x
@@ -0,0 +1,102 @@
+include <tbset.h>
+
+#* HISTORY *
+# B.Simon 25-Aug-94 Original
+
+# PUTMATCH -- Write matched rows in input as a single row in output table
+
+procedure putmatch (output, incol1, incol2, in1, in2, nclosest, closest)
+
+char output[ARB] # i: output table name
+char incol1[ARB] # i: list of columns to copy from first table
+char incol2[ARB] # i: list of columns to copy from second table
+pointer in1 # i: first table's descriptor
+pointer in2 # i: second table's descriptor
+int nclosest # i: length of closest array
+int closest[ARB] # i: indices of rows in second table closest to first
+#--
+int mxcol1, mxcol2, maxcol, ncol1, ncol2, ncol, type1, type2
+pointer colnum, datatype, lendata, lenfmt, icol, irow, jrow
+pointer sp, colname, colunits, colfmt, oldcol, newcol,out
+
+string nomatch "WARNING: No rows matched between tables, output \
+table is empty\n"
+
+int tbpsta()
+pointer tbtopn()
+
+begin
+ # Allocate memory for temporary strings
+
+ call smark (sp)
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+ call salloc (colunits, SZ_COLUNITS, TY_CHAR)
+ call salloc (colfmt, SZ_COLFMT, TY_CHAR)
+
+ # Get column descriptors from input tables
+
+ mxcol1 = tbpsta (in1, TBL_NCOLS)
+ mxcol2 = tbpsta (in2, TBL_NCOLS)
+ maxcol = mxcol1 + mxcol2
+
+ call salloc (oldcol, maxcol, TY_INT)
+ call salloc (newcol, maxcol, TY_INT)
+
+ call tctexp (in1, incol1, mxcol1, ncol1, Memi[oldcol])
+ call tctexp (in2, incol2, mxcol2, ncol2, Memi[oldcol+ncol1])
+ ncol = ncol1 + ncol2
+
+ # Create output table
+
+ out = tbtopn (output, NEW_FILE, NULL)
+
+ # Set type (text, row ordered, column ordered)
+
+ type1 = tbpsta (in1, TBL_WHTYPE)
+ type2 = tbpsta (in2, TBL_WHTYPE)
+ if (type1 == type2)
+ call tbpset (out, TBL_WHTYPE, type1)
+
+ # Create columns in output table
+
+ do icol = 1, ncol {
+ call tbcinf (Memi[oldcol+icol-1], colnum, Memc[colname],
+ Memc[colunits], Memc[colfmt], datatype,
+ lendata, lenfmt)
+
+ call newcolnam (ncol, Memi[oldcol], icol,
+ Memc[colname], SZ_COLNAME)
+
+ call tbcdef (out, Memi[newcol+icol-1], Memc[colname],
+ Memc[colunits], Memc[colfmt], datatype, lendata, 1)
+ }
+
+ # Copy header keywords from first input table
+
+ call tbtcre (out)
+ call tbhcal (in1, out)
+
+ # Copy rows from input table to output
+
+ jrow = 0
+ do irow = 1, nclosest {
+ if (closest[irow] == 0)
+ next
+
+ jrow = jrow + 1
+ call tbrcsc (in1, out, Memi[oldcol], Memi[newcol],
+ irow, jrow, ncol1)
+ call tbrcsc (in2, out, Memi[oldcol+ncol1], Memi[newcol+ncol1],
+ closest[irow], jrow, ncol2)
+ }
+
+ # Write warning message if no rows matched
+
+ if (jrow == 0)
+ call eprintf (nomatch)
+
+ # Clean up
+
+ call tbtclo (out)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tmatch/rowname.x b/pkg/utilities/nttools/tmatch/rowname.x
new file mode 100644
index 00000000..484fcd75
--- /dev/null
+++ b/pkg/utilities/nttools/tmatch/rowname.x
@@ -0,0 +1,61 @@
+#* HISTORY *
+#* B.Simon 26-Aug-94
+
+# ROWNAME -- Create name for table row by concatenating column values
+
+procedure rowname (in, irow, ncol, col, name, namelen)
+
+pointer in # i: table descriptor
+int irow # i: table row number
+int ncol # i: number of table columns
+pointer col[ARB] # i: table column pointers
+char name[ARB] # o: concatenated values of columns
+int namelen # i: maximum name length
+#--
+int ic, jc, icol
+pointer sp, value
+
+begin
+ # Allocate memory for column buffer
+
+ call smark (sp)
+ call salloc (value, SZ_LINE, TY_CHAR)
+
+ # Concatenate column values into name string
+
+ jc = 0
+ icol = 0
+ for (ic = 1; ic <= namelen; ic = ic + 1) {
+
+ # A value of zero is a flag to read the next coumn
+
+ if (jc == 0) {
+ icol = icol + 1
+ if (icol > ncol) {
+ if (ic > 1)
+ ic = ic - 1 # remove trailing blank
+
+ break
+ }
+
+ call tbegtt (in, col[icol], irow, Memc[value], SZ_LINE)
+ }
+
+ # Copy a single character from the buffer to the output string
+ # until the buffer is exhausted. At this point we copy a blank
+ # as a spacer and set the value of jc as a flag to read the
+ # next column.
+
+ if (Memc[value+jc] == EOS) {
+ name[ic] = ' '
+ jc = 0
+ } else {
+ name[ic] = Memc[value+jc]
+ jc = jc + 1
+ }
+ }
+
+ name[ic] = EOS
+ call sfree (sp)
+end
+
diff --git a/pkg/utilities/nttools/tmatch/setindex.x b/pkg/utilities/nttools/tmatch/setindex.x
new file mode 100644
index 00000000..9640f1cd
--- /dev/null
+++ b/pkg/utilities/nttools/tmatch/setindex.x
@@ -0,0 +1,13 @@
+# SETINDEX -- Initialize an index array
+
+procedure setindex (index, len)
+
+int index[ARB] # o: index rray
+int len # i: array length
+#--
+int i
+
+begin
+ do i = 1, len
+ index[i] = i
+end
diff --git a/pkg/utilities/nttools/tmatch/sortclose.x b/pkg/utilities/nttools/tmatch/sortclose.x
new file mode 100644
index 00000000..303ac250
--- /dev/null
+++ b/pkg/utilities/nttools/tmatch/sortclose.x
@@ -0,0 +1,50 @@
+#* HISTORY *
+#* B.Simon 25-Aug-94 original
+# Phil Hodge 12-Jul-2005 in sortclose, add 'int cmpclose()'
+
+# SORTCLOSE -- Sort the closest array
+
+procedure sortclose (nclosest, closest, index)
+
+int nclosest # i: length of closest and index arrays
+int closest[ARB] # i: indices of second table rows matching first
+int index[ARB] # u: indices of first table rows, in sort order on exit
+#--
+int cmpclose()
+extern cmpclose
+pointer sp, close2
+
+begin
+ call smark (sp)
+ call salloc (close2, nclosest, TY_INT)
+
+ call amovi (closest, Memi[close2], nclosest)
+ call gqsort (index, nclosest, cmpclose, close2)
+
+ call sfree (sp)
+end
+
+# CMPCLOSE -- Compare two elements in the close array
+
+int procedure cmpclose (closest, ielem, jelem)
+
+pointer closest # address of the closest array
+int ielem # first element
+int jelem # second element
+#--
+int order
+
+begin
+ if (Memi[closest+ielem-1] < Memi[closest+jelem-1]) {
+ order = -1
+ } else if (Memi[closest+ielem-1] > Memi[closest+jelem-1]) {
+ order = 1
+ } else if (ielem < jelem) {
+ order = -1
+ } else if (ielem < jelem) {
+ order = 1
+ } else {
+ order = 0
+ }
+ return (order)
+end
diff --git a/pkg/utilities/nttools/tmatch/sortdist.x b/pkg/utilities/nttools/tmatch/sortdist.x
new file mode 100644
index 00000000..b0745676
--- /dev/null
+++ b/pkg/utilities/nttools/tmatch/sortdist.x
@@ -0,0 +1,50 @@
+#* HISTORY *
+#* B.Simon 25-Aug-94 original
+# Phil Hodge 28-Sept-2005 in sortdist, add 'int cmpdist()'
+
+# SORTDIST -- Sort the dist array
+
+procedure sortdist (ndist, dist, index)
+
+int ndist # i: length of dist and index arrays
+double dist[ARB] # i: indices of second table rows matching first
+int index[ARB] # u: indices of first table rows, in sort order on exit
+#--
+int cmpdist()
+extern cmpdist
+pointer sp, dist2
+
+begin
+ call smark (sp)
+ call salloc (dist2, ndist, TY_DOUBLE)
+
+ call amovd (dist, Memd[dist2], ndist)
+ call gqsort (index, ndist, cmpdist, dist2)
+
+ call sfree (sp)
+end
+
+# CMPDIST -- Compare two elements in the dist array
+
+int procedure cmpdist (dist, ielem, jelem)
+
+pointer dist # address of the dist array
+int ielem # first element
+int jelem # second element
+#--
+int order
+
+begin
+ if (Memd[dist+ielem-1] < Memd[dist+jelem-1]) {
+ order = -1
+ } else if (Memd[dist+ielem-1] > Memd[dist+jelem-1]) {
+ order = 1
+ } else if (ielem < jelem) {
+ order = -1
+ } else if (ielem < jelem) {
+ order = 1
+ } else {
+ order = 0
+ }
+ return (order)
+end
diff --git a/pkg/utilities/nttools/tmatch/tmatch.x b/pkg/utilities/nttools/tmatch/tmatch.x
new file mode 100644
index 00000000..2d3ea22d
--- /dev/null
+++ b/pkg/utilities/nttools/tmatch/tmatch.x
@@ -0,0 +1,138 @@
+include <tbset.h>
+
+#* HISTORY *
+#* B.Simon 24-Aug-1994 original
+# Phil Hodge 8-Apr-1999 Call tbfpri.
+
+# TMATCH -- Find closest matching rows between two tables
+
+procedure tmatch ()
+
+#--
+pointer input1 # First input table
+pointer input2 # Second input table
+pointer output # Output table
+pointer match1 # Columns from first table used to match
+pointer match2 # Columns from second table used to match
+double maxnorm # Maximum value of norm for allowed match
+pointer incol1 # Columns from first table copied to output
+pointer incol2 # Columns from second table copied to output
+pointer factor # Multiplicative factors used in computing norm
+pointer diagfile # Diagnostic output file
+pointer nmcol1 # Columns from first table in diagnostic output
+pointer nmcol2 # Columns from second table in diagnostic output
+bool sphere # Apply spherical correction to first column?
+
+bool fold
+int mxcol1, mxcol2, ncol1, ncol2, nrow1, nrow2
+int phu_copied # set by tbfpri and ignored
+pointer sp, in1, in2, col1, col2, index1, index2, weight, dist, closest
+
+data fold / false /
+
+string mismatch "Both lists of match columns must have same length"
+string nomatch "Match columns not found in table"
+
+bool clgetb()
+double clgetd()
+int tbpsta()
+pointer tbtopn()
+
+begin
+ # Allocate memory for strings
+
+ call smark (sp)
+ call salloc (input1, SZ_FNAME, TY_CHAR)
+ call salloc (input2, SZ_FNAME, TY_CHAR)
+ call salloc (output, SZ_FNAME, TY_CHAR)
+ call salloc (match1, SZ_FNAME, TY_CHAR)
+ call salloc (match2, SZ_FNAME, TY_CHAR)
+ call salloc (incol1, SZ_FNAME, TY_CHAR)
+ call salloc (incol2, SZ_FNAME, TY_CHAR)
+ call salloc (factor, SZ_FNAME, TY_CHAR)
+ call salloc (diagfile, SZ_FNAME, TY_CHAR)
+ call salloc (nmcol1, SZ_FNAME, TY_CHAR)
+ call salloc (nmcol2, SZ_FNAME, TY_CHAR)
+
+ # Read task parameters
+
+ call clgstr ("input1", Memc[input1], SZ_FNAME)
+ call clgstr ("input2", Memc[input2], SZ_FNAME)
+ call clgstr ("output", Memc[output], SZ_FNAME)
+ call clgstr ("match1", Memc[match1], SZ_FNAME)
+ call clgstr ("match2", Memc[match2], SZ_FNAME)
+ maxnorm = clgetd ("maxnorm")
+
+ call clgstr ("incol1", Memc[incol1], SZ_FNAME)
+ call clgstr ("incol2", Memc[incol2], SZ_FNAME)
+ call clgstr ("factor", Memc[factor], SZ_FNAME)
+ call clgstr ("diagfile", Memc[diagfile], SZ_FNAME)
+ call clgstr ("nmcol1", Memc[nmcol1], SZ_FNAME)
+ call clgstr ("nmcol2", Memc[nmcol2], SZ_FNAME)
+ sphere = clgetb ("sphere")
+
+ # Open input tables and get list of match colums
+
+ in1 = tbtopn (Memc[input1], READ_ONLY, NULL)
+ in2 = tbtopn (Memc[input2], READ_ONLY, NULL)
+
+ mxcol1 = tbpsta (in1, TBL_NCOLS)
+ mxcol2 = tbpsta (in2, TBL_NCOLS)
+
+ call salloc (col1, mxcol1, TY_INT)
+ call salloc (col2, mxcol2, TY_INT)
+
+ call tctexp (in1, Memc[match1], mxcol1, ncol1, Memi[col1])
+ call tctexp (in2, Memc[match2], mxcol2, ncol2, Memi[col2])
+
+ if (ncol1 != ncol2)
+ call error (1, mismatch)
+
+ if (ncol1 == 0)
+ call error (1, nomatch)
+
+ if (ncol1 < 2)
+ sphere = false
+
+ # Sort input tables
+
+ call allrows (in1, nrow1, index1)
+ call allrows (in2, nrow2, index2)
+
+ call tbtsrt (in1, ncol1, Memi[col1], fold, nrow1, Memi[index1])
+ call tbtsrt (in2, ncol2, Memi[col2], fold, nrow2, Memi[index2])
+
+ call salloc (weight, ncol1, TY_DOUBLE)
+ call salloc (dist, nrow1, TY_DOUBLE)
+ call salloc (closest, nrow1, TY_INT)
+
+ # Compute weights from list of factors or table column units
+
+ call getweight (ncol1, Memi[col1], Memi[col2],
+ Memc[factor], Memd[weight])
+
+ # Compute closest match between the two tables
+
+ call getmatch (in1, in2, ncol1, Memi[col1], Memi[col2], Memd[weight],
+ nrow1, Memi[index1], nrow2, Memi[index2], maxnorm,
+ sphere, Memi[closest], Memd[dist])
+
+ # Write output table
+
+ call tbfpri (Memc[input1], Memc[output], phu_copied)
+ call putmatch (Memc[output], Memc[incol1], Memc[incol2], in1, in2,
+ nrow1, Memi[closest])
+
+ # Write diagnostic info
+
+ call infomatch (Memc[diagfile], in1, in2, Memc[nmcol1], Memc[nmcol2],
+ maxnorm, nrow1, Memi[closest], Memd[dist])
+
+ # Clean up
+
+ call mfree (index1, TY_INT)
+ call mfree (index2, TY_INT)
+ call tbtclo (in1)
+ call tbtclo (in2)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tmerge.par b/pkg/utilities/nttools/tmerge.par
new file mode 100644
index 00000000..826e5e2c
--- /dev/null
+++ b/pkg/utilities/nttools/tmerge.par
@@ -0,0 +1,9 @@
+# par file for the tmerge task
+intable,s,a,"",,,"list of tables"
+outtable,s,a,"",,,"name of output table"
+option,s,a,"merge","merge|append",,"merge or append?"
+allcols,b,h,yes,,,"columns from all input tables?"
+tbltype,s,h,"default","row|column|text|default",,"type of output table"
+allrows,i,h,100,1,,"number of rows to allocate"
+extracol,i,h,0,0,,"number of extra columns to allocate"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/tmerge/mkpkg b/pkg/utilities/nttools/tmerge/mkpkg
new file mode 100644
index 00000000..e42cba65
--- /dev/null
+++ b/pkg/utilities/nttools/tmerge/mkpkg
@@ -0,0 +1,20 @@
+# MKPKG file for the tmerge task
+# Author: P.E. Hodge, 14-Sep-87
+#
+# Special keywords recognized by standard SDAS mkpkg files:
+#
+# mkpkg debug=yes link ttools executable with the debugger
+# mkpkg linkonly skip ttools library update and just link
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+linkonly:
+ $call linkonly@..
+ ;
+
+libpkg.a:
+ tmerge.x <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/tmerge/tmerge.x b/pkg/utilities/nttools/tmerge/tmerge.x
new file mode 100644
index 00000000..b489abe2
--- /dev/null
+++ b/pkg/utilities/nttools/tmerge/tmerge.x
@@ -0,0 +1,425 @@
+include <tbset.h>
+
+define TM_MERGE 1 # option = merge
+define TM_APPEND 2 # option = append rows
+
+# tmerge -- Merge or append tables
+#
+# Two or more input tables are combined into one output table.
+#
+# If the option is to append then there will be a separate output row for
+# each row of each input table. Columns with the same name in different
+# input tables will be written into the same output column, but no data
+# will be overwritten because they are written into different rows.
+#
+# If the option is to merge then each input table is written beginning
+# with row one of the output table. There will be as many output rows as
+# the largest number of rows in the input tables. If there are columns
+# with the same name in different input tables then values will be over-
+# written as they are put into the output table. The exception to this
+# is text tables if the option allcols=yes; in this case the original
+# column names "c1", "c2", etc. will be ignored, and new names will be
+# created consisting of the column number in the _output_ table.
+#
+# Phil Hodge, 2-Sep-1987 Task created.
+# Phil Hodge, 7-Sep-1988 Change parameter name for input table.
+# Phil Hodge, 16-Mar-1992 Include text as a valid table type.
+# Phil Hodge, 16-Apr-1992 Only call tbcdef if column does not exist.
+# Phil Hodge, 29-Jun-1992 Allow tbltype = default.
+# Phil Hodge, 25-Feb-1993 Create new column names for text tables if
+# allcols=yes; in tm_cp_col, use tbcigi & tbcigt instead of
+# tbcinf, and get data type from output table instead of input.
+# Phil Hodge, 2-Apr-1993 In tm_cp_col, include short datatype.
+# Phil Hodge, 10-Nov-1993 In tm_mkname, use strcat instead of sprintf.
+# Phil Hodge, 29-Aug-1994 Modify to use tbrcsc instead of copying columns.
+# Phil Hodge, 3-Oct-1995 Modify for FITS tables.
+# Phil Hodge, 28-May-1996 Rewrite tm_mkname to use parts of dir, table name.
+# Phil Hodge, 8-Apr-1999 In tm_create, call tbfpri.
+# Phil hodge, 16-Apr-1999 In tm_create, use tbttyp instead of tbparse.
+# Phil hodge, 18-Jun-1999 Change the way column names are created for
+# text tables: use c<N>, N = column number in output table;
+# tm_mkname was rewritten; tm_ch_colnames was eliminated.
+
+procedure tmerge()
+
+pointer otp # output table descriptor
+pointer sp
+pointer tablist # scratch for input list of table names
+pointer outtbl # scratch for output table name
+pointer ttype # scratch for table type ("row" or "column")
+pointer s_option # scratch for "append" or "merge"
+int option # TM_MERGE or TM_APPEND
+pointer list # filename template list
+pointer n_outcols # cumulative number of output columns numbers
+bool allcols # no ==> take col def only from first input tbl
+pointer tbnopen()
+int tbnlen()
+bool clgetb()
+
+begin
+ call smark (sp)
+ call salloc (tablist, SZ_LINE, TY_CHAR)
+ call salloc (outtbl, SZ_LINE, TY_CHAR)
+ call salloc (ttype, SZ_LINE, TY_CHAR)
+ call salloc (s_option, SZ_LINE, TY_CHAR)
+
+ call clgstr ("intable", Memc[tablist], SZ_LINE)
+ call clgstr ("outtable", Memc[outtbl], SZ_LINE)
+
+ call clgstr ("option", Memc[s_option], SZ_FNAME)
+ if (Memc[s_option] == 'm')
+ option = TM_MERGE
+ else if (Memc[s_option] == 'a')
+ option = TM_APPEND
+ else
+ call error (1, "unrecognized 'option'")
+ allcols = clgetb ("allcols")
+ call clgstr ("tbltype", Memc[ttype], SZ_FNAME)
+
+ list = tbnopen (Memc[tablist])
+
+ # For input table i, n_outcols[i] will be the number of columns
+ # defined in the output table prior to processing table i.
+ call calloc (n_outcols, tbnlen (list), TY_INT)
+
+ # Create output table.
+ call tm_create (list, Memc[outtbl], option, allcols, Memc[ttype],
+ otp, Memi[n_outcols])
+
+ # Copy contents of all input tables to output table.
+ call tm_copy (list, otp, Memi[n_outcols], option, allcols)
+
+ call tbtclo (otp)
+ call tbnclose (list)
+ call sfree (sp)
+end
+
+
+# tm_create -- create output table
+# This routine opens (and then closes) each input table in order to
+# count header parameters and rows, and define columns. The output table
+# is initialized, parameters are set, and the table is created.
+
+procedure tm_create (list, outtbl, option, allcols, ttype,
+ otp, n_outcols)
+
+pointer list # i: filename template descriptor
+char outtbl[ARB] # i: name of output table
+char ttype[ARB] # i: "row" or "column" ordered
+int option # i: merge or append
+bool allcols # i: use all input columns?
+pointer otp # o: output table pointer
+int n_outcols[ARB] # o: cumulative count of output column numbers
+#--
+pointer itp # input table descriptor
+pointer sp
+pointer intbl # scratch for name of an input table
+pointer scratch
+int num_par # number of header parameters
+int itab # input table number
+int nrows # sum of number of rows in each input table
+int ncols # cumulative number of columns in output table
+int allrows # number of rows to allocate in output
+int extracol # space for extra columns to allocate in output
+int exttype # type of output table implied by extension
+int exists, tbttyp() # exists is ignored
+int phu_copied # set by tbfpri and ignored
+pointer tbtopn()
+int clgeti(), tbnget(), tbpsta()
+
+begin
+ call smark (sp)
+ call salloc (intbl, SZ_PATHNAME, TY_CHAR)
+ call salloc (scratch, SZ_PATHNAME, TY_CHAR)
+
+ call tbnrew (list) # rewind list
+ if (tbnget (list, Memc[intbl], SZ_PATHNAME) == EOF) # first name
+ call error (1, "no input")
+ # If the input and output names are the same post an error.
+ call tm_same_name (Memc[intbl], outtbl)
+ itp = tbtopn (Memc[intbl], READ_ONLY, 0) # open first input table
+ call tbfpri (Memc[intbl], outtbl, phu_copied) # copy primary header
+ otp = tbtopn (outtbl, NEW_COPY, itp) # open output table
+
+ # Count header parameters and rows, then close first input table.
+ num_par = tbpsta (itp, TBL_NPAR)
+ nrows = tbpsta (itp, TBL_NROWS)
+ call tbtclo (itp)
+
+ # Set parameters.
+
+ call tbpset (otp, TBL_MAXPAR, num_par)
+
+ # Check whether the extension of the output file implies a FITS
+ # file, while tbltype implies another type.
+ exttype = tbttyp (outtbl, exists)
+ if (exttype == TBL_TYPE_FITS) {
+ if (ttype[1] == 'r' || ttype[1] == 'c' || ttype[1] == 't') {
+ call eprintf (
+ "warning: Extension of output name implies a FITS file,\n")
+ call eprintf (
+ "but tbltype specifies `%s'; output will be FITS.\n")
+ call pargstr (ttype)
+ }
+ }
+
+ if (exttype != TBL_TYPE_FITS) {
+
+ if (ttype[1] == 'r') { # row-ordered stsdas format
+ call tbpset (otp, TBL_WHTYPE, TBL_TYPE_S_ROW)
+ extracol = clgeti ("extracol")
+ # Increase allocation of space for columns.
+ if (extracol > 0)
+ call tbpset (otp, TBL_INCR_ROWLEN, extracol)
+ } else if (ttype[1] == 'c') { # column-ordered stsdas format
+ call tbpset (otp, TBL_WHTYPE, TBL_TYPE_S_COL)
+ allrows = clgeti ("allrows")
+ allrows = max (allrows, nrows) # user may want more rows
+ call tbpset (otp, TBL_ALLROWS, allrows)
+ } else if (ttype[1] == 't') { # text table
+ call tbpset (otp, TBL_WHTYPE, TBL_TYPE_TEXT)
+ } else if (ttype[1] == 'd') { # default -- don't set type
+ extracol = clgeti ("extracol")
+ if (extracol > 0)
+ call tbpset (otp, TBL_INCR_ROWLEN, extracol)
+ }
+ }
+
+ # Open each of the other input tables, define columns, count
+ # header parameters and rows, and close the table.
+ itab = 1 # we've opened the first input table already
+ n_outcols[1] = 0 # no output columns prior to first input table
+ while (tbnget (list, Memc[intbl], SZ_PATHNAME) != EOF) {
+
+ call tm_same_name (Memc[intbl], outtbl) # check names
+ itp = tbtopn (Memc[intbl], READ_ONLY, 0)
+ itab = itab + 1 # increment input table counter
+ ncols = tbpsta (otp, TBL_NCOLS) # ncols in output table, so far
+ n_outcols[itab] = n_outcols[itab-1] + ncols
+ if (allcols)
+ call tm_def_col (itp, otp, n_outcols[itab])
+ num_par = num_par + tbpsta (itp, TBL_NPAR)
+ if (option == TM_MERGE)
+ nrows = max (nrows, tbpsta (itp, TBL_NROWS))
+ else # append
+ nrows = nrows + tbpsta (itp, TBL_NROWS)
+ call tbtclo (itp)
+ }
+
+ # Create the output table.
+ call tbtcre (otp)
+ call sfree (sp)
+end
+
+
+# tm_copy -- copy contents of tables
+# This routine opens each of the input tables one at a time, copies
+# the header parameters to the output table, copies the data contents,
+# and closes each input table.
+
+procedure tm_copy (list, otp, n_outcols, option, allcols)
+
+pointer list # i: filename template descriptor
+pointer otp # i: output table descriptor
+int n_outcols[ARB] # i: cumulative count of output column numbers
+int option # i: merge or append
+bool allcols # i: passed to tm_cp_col (for text tables)
+#--
+pointer itp # input table descriptor
+pointer sp
+pointer intbl # scratch for name of an input table
+pointer icp # pointer to column descriptor in input table
+pointer ocp # pointer to one column descriptor in output
+pointer icptr # array of pointers to col descr in input
+pointer ocptr # array of pointers to col descr in output
+char colname[SZ_COLNAME] # column name
+int itab # input table number
+int nrows # number of rows in input table
+int irow, orow # loop index for row numbers in input, output
+int firstrow # first row to write in output table
+int ncols # number of columns in input table
+int nc # number of columns to copy to output table
+int colnum # loop index for column number
+bool simple_text_table # input is a simple text table (no col def)?
+pointer tbtopn(), tbcnum()
+int tbnget(), tbpsta()
+
+begin
+ call smark (sp)
+ call salloc (intbl, SZ_PATHNAME, TY_CHAR)
+
+ firstrow = 1 # initial values
+ itab = 0
+ call tbnrew (list) # rewind list
+
+ while (tbnget (list, Memc[intbl], SZ_PATHNAME) != EOF) {
+
+ itp = tbtopn (Memc[intbl], READ_ONLY, 0)
+ itab = itab + 1 # increment input table counter
+ call tbhcal (itp, otp) # copy all header parameters
+ nrows = tbpsta (itp, TBL_NROWS)
+ ncols = tbpsta (itp, TBL_NCOLS)
+
+ simple_text_table = false # initial value
+ if (tbpsta (itp, TBL_WHTYPE) == TBL_TYPE_TEXT) {
+ if (tbpsta (itp, TBL_SUBTYPE) == TBL_SUBTYPE_SIMPLE) {
+ simple_text_table = true
+ }
+ }
+
+ if (nrows > 0) {
+
+ # Column descriptors for output table.
+ call malloc (icptr, ncols, TY_POINTER)
+ call malloc (ocptr, ncols, TY_POINTER)
+
+ # For each column in the input table, use the column number
+ # to get its name. Using its name, look for it in the
+ # current output table. If it is there, save its column
+ # descriptor in the array; otherwise, ignore the column.
+ nc = 0 # no columns found yet
+ do colnum = 1, ncols {
+
+ icp = tbcnum (itp, colnum)
+ call tbcigt (icp, TBL_COL_NAME, colname, SZ_COLNAME)
+
+ # For a text table, if we're taking values from all
+ # columns, assign a new column name.
+ if (allcols && simple_text_table) {
+ call tm_mkname (n_outcols[itab] + colnum,
+ colname, SZ_COLNAME)
+ }
+ call tbcfnd (otp, colname, ocp, 1)
+ if (ocp != NULL) {
+ nc = nc + 1
+ Memi[icptr+nc-1] = icp # nc, not colnum
+ Memi[ocptr+nc-1] = ocp
+ }
+ }
+
+ # Copy each row.
+ orow = firstrow # initial value
+ do irow = 1, nrows {
+ call tbrcsc (itp, otp, Memi[icptr], Memi[ocptr],
+ irow, orow, nc)
+ orow = orow + 1
+ }
+ # Free memory for column descriptors.
+ call mfree (ocptr, TY_POINTER)
+ call mfree (icptr, TY_POINTER)
+
+ if (option == TM_APPEND) # else keep firstrow = 1
+ firstrow = firstrow + nrows
+ }
+ call tbtclo (itp)
+ }
+ call sfree (sp)
+end
+
+
+# tm_same_name -- call error if same names
+# This routine appends the default extension and then compares the
+# two names to make sure they are different. An error is posted if
+# the names are the same.
+
+procedure tm_same_name (tbl1, tbl2)
+
+char tbl1[ARB], tbl2[ARB] # i: the names to be compared
+#--
+pointer name1, name2 # scratch for names including extension
+pointer sp
+bool streq()
+
+begin
+ call smark (sp)
+ call salloc (name1, SZ_PATHNAME, TY_CHAR)
+ call salloc (name2, SZ_PATHNAME, TY_CHAR)
+ call tbtext (tbl1, Memc[name1], SZ_PATHNAME)
+ call tbtext (tbl2, Memc[name2], SZ_PATHNAME)
+ if (streq (Memc[name1], Memc[name2]))
+ call error (1, "input and output names must be different")
+ call sfree (sp)
+end
+
+
+# tm_def_col -- define columns
+# All columns in the input table are defined in the output table.
+# It is not an error for a column to have been previously defined.
+# (Note that this routine is only called if allcols is true.)
+
+procedure tm_def_col (itp, otp, prev_ncols)
+
+pointer itp, otp # i: descriptors for input and output tables
+int prev_ncols # i: previous number of output columns
+#--
+pointer colptr, cp # column descriptors for input & output
+char colname[SZ_COLNAME] # column name
+char colunits[SZ_COLUNITS] # units for column
+char colfmt[SZ_COLFMT] # print format for column
+int dtype[1] # data type of column
+int lendata[1] # number of elements (one)
+int lenfmt # length of print format (ignored)
+int ncols # number of columns in input table
+int colnum, cn # column number; cn is ignored
+int duplicate # count of duplicate columns for text input
+bool simple_text_table # input is a simple text table (no col def)?
+pointer tbcnum()
+int tbpsta()
+
+begin
+ ncols = tbpsta (itp, TBL_NCOLS)
+
+ simple_text_table = false # initial value
+ if (tbpsta (itp, TBL_WHTYPE) == TBL_TYPE_TEXT) {
+ if (tbpsta (itp, TBL_SUBTYPE) == TBL_SUBTYPE_SIMPLE) {
+ simple_text_table = true
+ }
+ }
+
+ duplicate = 0 # initial value
+
+ do colnum = 1, ncols {
+ colptr = tbcnum (itp, colnum)
+ call tbcinf (colptr,
+ cn, colname, colunits, colfmt,
+ dtype, lendata, lenfmt)
+
+ # For a simple text table, assign a column name based on the
+ # number of the column we're about to create in the output table.
+ if (simple_text_table)
+ call tm_mkname (prev_ncols+colnum, colname, SZ_COLNAME)
+
+ # Check whether the column already exists ...
+ call tbcfnd (otp, colname, cp, 1)
+ # ... and if not then create it.
+ if (cp == NULL)
+ call tbcdef (otp, cp, colname, colunits, colfmt,
+ dtype, lendata, 1)
+ else if (simple_text_table)
+ duplicate = duplicate + 1
+ }
+
+ if (duplicate > 0) {
+ call eprintf (
+ "warning: %d duplicate column names from text table\n")
+ call pargi (duplicate)
+ }
+end
+
+
+# tm_mkname -- create a column name
+# This routine constructs a new name for a column of a text table.
+# The name will be "c" followed by the number of the column in the
+# output table.
+
+procedure tm_mkname (outcol, colname, maxch)
+
+int outcol # i: number of column in output table
+char colname[maxch] # o: column name
+int maxch # i: size of colname
+#--
+
+begin
+ call sprintf (colname, maxch, "c%d")
+ call pargi (outcol)
+end
diff --git a/pkg/utilities/nttools/tprint.par b/pkg/utilities/nttools/tprint.par
new file mode 100644
index 00000000..48df6a5c
--- /dev/null
+++ b/pkg/utilities/nttools/tprint.par
@@ -0,0 +1,16 @@
+table,s,a,"",,,"list of tables to print"
+prparam,b,h,no,,,"print user parameters?"
+prdata,b,h,yes,,,"print data?"
+pwidth,i,h,80,40,,"page width if output redirected"
+plength,i,h,0,0,,"lines of data per page"
+showrow,b,h,yes,,,"print row numbers?"
+orig_row,b,h,yes,,,"row numbers are those in underlying table?"
+showhdr,b,h,yes,,,"print column names, etc?"
+showunits,b,h,yes,,,"print column units?"
+columns,s,h,"",,,"list of columns to print"
+rows,s,h,"-",,,"range of rows to print"
+option,s,h,"plain","plain|html|latex|tex",,"output format option"
+align,b,h,yes,,,"increase column width to align with header?"
+sp_col,s,h,"",,,"print blank line when this column changes"
+lgroup,i,h,0,0,,"print blank line after this many lines"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/tprint/mkpkg b/pkg/utilities/nttools/tprint/mkpkg
new file mode 100644
index 00000000..8134ff5b
--- /dev/null
+++ b/pkg/utilities/nttools/tprint/mkpkg
@@ -0,0 +1,15 @@
+# Update tprint and tdump in the ttools package library.
+# Author: HODGE, 2-FEB-1988
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ tdump.x <tbset.h>
+ tprint.x <time.h> <finfo.h> <tbset.h>
+ tprhtml.x <tbset.h> tprint.h
+ tprplain.x <tbset.h> tprint.h
+ tprlatex.x <tbset.h> tprint.h
+ ;
diff --git a/pkg/utilities/nttools/tprint/notes b/pkg/utilities/nttools/tprint/notes
new file mode 100644
index 00000000..2e6f9ff0
--- /dev/null
+++ b/pkg/utilities/nttools/tprint/notes
@@ -0,0 +1,40 @@
+ Structure chart for tprint: 1988 Jan 21
+
+tprint:
+ (tbtopn)
+ tpr_fm_date:
+ (finfo)
+ tpr_param_pr:
+ (tbhgnp)
+ tpr_data_pr:
+ (tctexp)
+ tpr_plain_pr:
+ (decode_ranges)
+ get_page:
+ (tbcigi)
+ tpr_pfmt:
+ (tbcigt)
+ tpr_cnames_pr:
+ (tbcigt)
+ (get_next_number)
+ prt_row
+ (tbcigi)
+ (tbegt[])
+ tpr_latex_pr:
+ (decode_ranges)
+ tpr_pfmt:
+ (tbcigt)
+ tpr_beg_doc
+ tpr_def
+ tpr_begin_tbl
+ tpr_cnames_pr_l:
+ tpr_w_colsep
+ (tbcigt)
+ (get_next_number)
+ tpr_end_tbl
+ prt_row_l:
+ tpr_w_colsep
+ (tbcigi)
+ (tbegt[])
+ tpr_end_doc
+ (tbtclo)
diff --git a/pkg/utilities/nttools/tprint/tdump.x b/pkg/utilities/nttools/tprint/tdump.x
new file mode 100644
index 00000000..54658d58
--- /dev/null
+++ b/pkg/utilities/nttools/tprint/tdump.x
@@ -0,0 +1,486 @@
+include <tbset.h>
+
+# tdump -- Program to dump a table.
+# This differs from tprint in several ways: column names and row numbers
+# are not printed, and all columns for a given row are printed (possibly on
+# several lines) before moving on to the next row. Also, g format is used
+# for floating-point numbers (%15.7g for real, %24.16g for double) regardless
+# of the format specification for the column. This is to prevent loss of
+# precision.
+#
+# Phil Hodge, 31-Jul-1987 Task created
+# Phil Hodge, 11-Aug-1987 Modify d_gt_col_ptr for datatype=-n for char string.
+# Phil Hodge, 30-Dec-1987 Use tctexp for column names.
+# Phil Hodge, 7-Sep-1988 Change parameter name for table.
+# Phil Hodge, 21-Dec-1988 Also print column descrip; use g format for data.
+# Phil Hodge, 9-Mar-1989 Change type of dtype in tbhgnp from char to int.
+# Phil Hodge, 9-Jul-1991 Rename parameter pagwidth to pwidth.
+# Phil Hodge, 2-Apr-1993 Include short datatype in td_col_def.
+# Phil Hodge, 2-Jun-1994 In td_col_ptr, include newline in warning message.
+# Phil Hodge, 12-Dec-1994 Include array size in column definitions;
+# increase SZ_DTYPE from 9 to 29;
+# dump all elements if column is an array.
+# Phil Hodge, 15-Dec-1994 Increase size of file names from SZ_FNAME to SZ_LINE.
+# Phil Hodge, 13-Jan-1995 Change calling sequence of inquotes.
+# Phil Hodge, 19-Jul-1995 Add tp to calling sequence of tl_dtype in td_col_def.
+# Phil Hodge, 4-Apr-1996 In td_p_data, start each array at beginning of line;
+# change formats for real & double to %13.7g, %22.16g.
+# Phil Hodge, 5-Jun-1997 If keywords are to be printed, also print comments.
+# Phil Hodge, 20-Jul-1998 Print '' instead of blank for null keywords.
+# Phil Hodge, 22-Jul-1998 Left justify strings and boolean elements.
+# Phil Hodge, 2-Nov-2000 Use pwidth < 1 to disable the test on page width.
+# Phil Hodge, 15-May-2002 Use a specific format for int and short columns;
+# this was needed because for x or o format the printed
+# values could be misleading.
+
+define SZ_FMT 16 # size of string containing print format
+define FMT_REAL "%13.7g" # format for printing a real
+define SPACE_REAL 13 # space required for printing a real
+define FMT_DBL "%22.16g" # format for printing a double
+define SPACE_DBL 22 # space required for printing a double
+define FMT_INT "%11d" # format for printing an int
+define SPACE_INT 11 # space required for printing an int
+define FMT_SHORT "%5d" # format for printing a short
+define SPACE_SHORT 5 # space required for printing a short
+define MAX_RANGES (SZ_LINE/2) # max number of ranges of row numbers
+define SZ_DTYPE 29 # size of string containing column data type
+define SZ_LBUF 2 * SZ_LINE + 1
+
+procedure tdump()
+#--
+pointer tp # pointer to input table descr
+pointer cptr # scratch for array of column pointers
+pointer tname # scratch for table name
+pointer cname, pname, dname # scratch for names of output files
+pointer upar # scratch for header keyword value
+pointer comment # scratch for header keyword comment
+pointer datatype # scr for array of data types of columns
+pointer nelem # scr for array of array lengths of columns
+pointer len_fmt # scr for array of lengths of print formats
+pointer pformat # scratch for array of print formats
+pointer columns # list of columns to be dumped
+pointer r_str # string which gives ranges of row numbers
+char keyword[SZ_KEYWORD] # buffer for user parameter keyword
+char char_type # data type as a letter (t, b, i, r, d)
+pointer sp # stack pointer
+int fd # file descr for output user param, data
+int n # loop index for user parameters
+int dtype # data type (TY_CHAR, etc)
+int npar # number of user parameters
+int nrows, ncols # number of rows and columns in table
+int nprint # number of columns to print (may be < ncols)
+int pagewidth # page width
+bool prcoldef # print column definitions?
+bool prparam, prdata # print user parameters? data?
+pointer tbtopn()
+int open(), clgeti(), tbpsta()
+
+begin
+ call smark (sp)
+ call salloc (tname, SZ_LINE, TY_CHAR)
+ call salloc (cname, SZ_LINE, TY_CHAR)
+ call salloc (pname, SZ_LINE, TY_CHAR)
+ call salloc (dname, SZ_LINE, TY_CHAR)
+ call clgstr ("table", Memc[tname], SZ_LINE)
+
+ # Get the names of the output files. If a name is null, don't
+ # write the corresponding portion of the table.
+ call clgstr ("cdfile", Memc[cname], SZ_LINE)
+ call clgstr ("pfile", Memc[pname], SZ_LINE)
+ call clgstr ("datafile", Memc[dname], SZ_LINE)
+ prcoldef = (Memc[cname] != EOS)
+ prparam = (Memc[pname] != EOS)
+ prdata = (Memc[dname] != EOS)
+ if (!prcoldef && !prparam && !prdata) {
+ call sfree (sp) # nothing to do
+ return
+ }
+
+ tp = tbtopn (Memc[tname], READ_ONLY, 0)
+
+ if (prcoldef || prdata) {
+
+ # If we are to print column definitions and/or data,
+ # allocate memory and get list of columns.
+
+ call salloc (columns, SZ_LINE, TY_CHAR)
+ call clgstr ("columns", Memc[columns], SZ_LINE)
+ ncols = tbpsta (tp, TBL_NCOLS)
+
+ # Allocate enough scratch space for printing all columns.
+ call salloc (cptr, ncols, TY_POINTER)
+ call salloc (len_fmt, ncols, TY_INT)
+ call salloc (datatype, ncols, TY_INT)
+ call salloc (nelem, ncols, TY_INT)
+ }
+
+ if (prcoldef) {
+
+ # Open the output file for the column definitions.
+ fd = open (Memc[cname], NEW_FILE, TEXT_FILE)
+
+ # Print column definitions.
+ call td_col_def (tp, fd, Memc[columns], Memi[cptr])
+
+ call close (fd) # column definitions have been written
+ }
+
+ if (prparam) {
+
+ # Print header parameters.
+ npar = tbpsta (tp, TBL_NPAR)
+ if (npar > 0) {
+ fd = open (Memc[pname], NEW_FILE, TEXT_FILE)
+ call salloc (upar, SZ_PARREC, TY_CHAR)
+ call salloc (comment, SZ_PARREC, TY_CHAR)
+ do n = 1, npar {
+ # Get the Nth user parameter, and print it.
+ call tbhgnp (tp, n, keyword, dtype, Memc[upar])
+ call tbhgcm (tp, keyword, Memc[comment], SZ_PARREC)
+ switch (dtype) {
+ case TY_REAL:
+ char_type = 'r'
+ case TY_INT:
+ char_type = 'i'
+ case TY_DOUBLE:
+ char_type = 'd'
+ case TY_BOOL:
+ char_type = 'b'
+ default:
+ char_type = 't'
+ }
+ if (keyword[1] == EOS) {
+ call fprintf (fd, "'' ")
+ } else {
+ call fprintf (fd, "%-8s")
+ call pargstr (keyword)
+ }
+ call fprintf (fd, " %c")
+ call pargc (char_type)
+ if (Memc[comment] == EOS) {
+ call fprintf (fd, " %s\n")
+ call pargstr (Memc[upar])
+ } else { # also print comment
+ if (char_type == 't') {
+ call fprintf (fd, " '%s'") # enclose text in quotes
+ call pargstr (Memc[upar])
+ } else {
+ call fprintf (fd, " %s") # no quotes needed
+ call pargstr (Memc[upar])
+ }
+ call fprintf (fd, " %s\n")
+ call pargstr (Memc[comment])
+ }
+ }
+ call close (fd) # header parameters have been written
+ }
+ }
+
+ if (prdata) {
+
+ # Print data portion of table.
+ nrows = tbpsta (tp, TBL_NROWS)
+
+ if ((nrows < 1) || (ncols < 1)) {
+ call eprintf ("table is empty\n")
+ call tbtclo (tp)
+ call sfree (sp)
+ return # nothing more to do
+ }
+ # Open the output file for the table data.
+ fd = open (Memc[dname], NEW_FILE, TEXT_FILE)
+
+ call salloc (r_str, SZ_LINE, TY_CHAR)
+ call clgstr ("rows", Memc[r_str], SZ_LINE)
+
+ pagewidth = clgeti ("pwidth")
+ if (IS_INDEF(pagewidth))
+ pagewidth = -1 # no limit on page width
+
+ # Get column pointers, formats, etc for all columns that are
+ # to be printed.
+ call td_col_ptr (tp, Memc[columns], pagewidth, Memi[cptr],
+ Memi[len_fmt], Memi[datatype], Memi[nelem], nprint)
+
+ if (nprint > 0) {
+ # Allocate scratch space for print format. (one char for EOS)
+ call salloc (pformat, (SZ_FMT+1)*nprint, TY_CHAR)
+ # Print the values in the table.
+ call td_p_data (tp, fd, Memi[cptr], Memc[r_str],
+ Memi[len_fmt], Memi[datatype], Memi[nelem],
+ Memc[pformat], pagewidth, nprint)
+ }
+ call close (fd) # data values have been printed
+ }
+ call tbtclo (tp)
+ call sfree (sp)
+end
+
+
+
+# td_col_def -- print column definitions
+# This routine prints the column name, data type, print format, and units
+# for all columns that were specified by the user.
+
+procedure td_col_def (tp, fd, columns, cptr)
+
+pointer tp # i: pointer to table descriptor
+int fd # i: fd for output file
+char columns[ARB] # i: list of columns to be dumped
+pointer cptr[ARB] # o: array of pointers to column descriptors
+#--
+pointer sp
+pointer cname, cunits, cfmt # pointers to scratch space for column info
+char chartyp[SZ_DTYPE] # data type expressed as a string
+int ncols # the total number of columns in the table
+int nprint # number of columns to print
+int dtype # data type of a column
+int nelem # array length
+int lenformat # (ignored)
+int colnum # column number (ignored)
+int k # loop index
+int tbpsta()
+
+begin
+ call smark (sp)
+ call salloc (cname, SZ_FNAME, TY_CHAR)
+ call salloc (cunits, SZ_FNAME, TY_CHAR)
+ call salloc (cfmt, SZ_COLFMT, TY_CHAR)
+
+ ncols = tbpsta (tp, TBL_NCOLS)
+
+ # Get column pointers for all columns that are to be dumped.
+ call tctexp (tp, columns, ncols, nprint, cptr)
+
+ # Do for each column that is to be printed.
+ do k = 1, nprint {
+ call tbcinf (cptr[k],
+ colnum, Memc[cname], Memc[cunits], Memc[cfmt],
+ dtype, nelem, lenformat)
+
+ # Enclose column name in quotes if it contains embedded
+ # or trailing blanks.
+ call inquotes (Memc[cname], Memc[cname], SZ_FNAME, YES)
+ call fprintf (fd, "%-16s") # but name can be longer
+ call pargstr (Memc[cname])
+
+ # Print data type. First convert integer data type code to a
+ # character string, and append info about array size if > 1.
+ call tl_dtype (tp, cptr[k], dtype, nelem, chartyp, SZ_DTYPE)
+ call fprintf (fd, " %-8s")
+ call pargstr (chartyp)
+
+ # Print the format for display.
+ call fprintf (fd, " %8s")
+ call pargstr (Memc[cfmt])
+
+ # Print column units. Ignore trailing blanks.
+ call inquotes (Memc[cunits], Memc[cunits], SZ_FNAME, NO)
+ call fprintf (fd, " %s")
+ call pargstr (Memc[cunits])
+ call fprintf (fd, "\n") # end of line for each column
+ }
+ call sfree (sp)
+end
+
+
+# td_col_ptr -- get column pointers
+# This routine gets an array of pointers to the descriptors of those
+# columns that are to be printed, plus other info.
+
+procedure td_col_ptr (tp, columns, pagewidth,
+ cptr, len_fmt, datatype, nelem, nprint)
+
+pointer tp # i: pointer to table descriptor
+char columns[ARB] # i: list of columns to be dumped
+int pagewidth # i: page width (to make sure it's wide enough)
+pointer cptr[ARB] # o: array of pointers to column descriptors
+int len_fmt[ARB] # o: length of print format for each column
+int datatype[ARB] # o: data type for each column
+int nelem[ARB] # o: array length of each column
+int nprint # o: number of columns to print
+#--
+char colname[SZ_COLNAME] # column name for possible error message
+int ncols # total number of columns in the table
+int k # loop index
+int tbpsta(), tbcigi()
+
+begin
+ ncols = tbpsta (tp, TBL_NCOLS)
+
+ # Get column pointers for all columns that are to be dumped.
+ call tctexp (tp, columns, ncols, nprint, cptr)
+
+ # For each column that is to be printed, get the length of the print
+ # format, and if the column type is string then increase the length
+ # of the print format by two for possible enclosing quotes.
+ do k = 1, nprint {
+
+ datatype[k] = tbcigi (cptr[k], TBL_COL_DATATYPE)
+ nelem[k] = tbcigi (cptr[k], TBL_COL_LENDATA)
+
+ if (datatype[k] == TY_REAL)
+ len_fmt[k] = SPACE_REAL
+ else if (datatype[k] == TY_DOUBLE)
+ len_fmt[k] = SPACE_DBL
+ else if (datatype[k] == TY_INT)
+ len_fmt[k] = SPACE_INT
+ else if (datatype[k] == TY_SHORT)
+ len_fmt[k] = SPACE_SHORT
+ else
+ len_fmt[k] = tbcigi (cptr[k], TBL_COL_FMTLEN)
+
+ if (datatype[k] < 0) # char string column
+ len_fmt[k] = len_fmt[k] + 2
+
+ if (pagewidth > 0 && len_fmt[k] > pagewidth) {
+ call tbcigt (cptr[k], TBL_COL_NAME, colname, SZ_COLNAME)
+ call eprintf ("Page width is too small for column `%s'.\n")
+ call pargstr (colname)
+ }
+ }
+end
+
+
+# td_p_data -- print the contents of the table
+# The data in the table are printed one row at a time.
+
+procedure td_p_data (tp, fd, cptr, range_string,
+ len_fmt, datatype, nelem,
+ pformat, pagewidth, nprint)
+
+pointer tp # i: pointer to table descriptor
+int fd # i: fd for output file
+pointer cptr[nprint] # i: array of pointers to column descriptors
+char range_string[ARB] # i: string which gives ranges of row numbers
+int datatype[nprint] # i: array of flags: true if column is a string
+int nelem[ARB] # i: array length of each column
+int len_fmt[nprint] # i: array of lengths of print formats
+char pformat[SZ_FMT,nprint] # io: scratch space for print formats
+int pagewidth # i: page width
+int nprint # i: number of columns to print
+#--
+pointer sp
+pointer lbuf # scratch space for line buffer
+double dbuf # buffer for double-precision value
+real rbuf # buffer for single-precision value
+int ibuf # buffer for integer value
+short sbuf # buffer for short value
+int nrows # number of rows in the table
+int rownum, k # loop indices for row, column
+int j # loop index for array element
+int line_len # current line length
+int ranges[3,MAX_RANGES] # ranges of row numbers
+int nvalues # returned by decode_ranges and ignored
+int stat # returned by get_next_number
+bool done # flag for terminating loop
+int decode_ranges(), get_next_number()
+int tbpsta(), tbagtr(), tbagtd(), tbagti(), tbagts(), tbagtt()
+string MISSING "error reading data from table"
+
+begin
+ nrows = tbpsta (tp, TBL_NROWS)
+
+ if (decode_ranges (range_string, ranges, MAX_RANGES, nvalues) != 0) {
+ call eprintf ("bad range of row numbers\n")
+ return
+ }
+
+ call smark (sp)
+ call salloc (lbuf, SZ_LBUF, TY_CHAR)
+
+ # This section gets the print format for each column. The
+ # format is just "%Ns" or "%-Ns".
+ do k = 1, nprint {
+ pformat[1,k] = '%'
+ if (datatype[k] < 0 || datatype[k] == TY_BOOL) {
+ call sprintf (pformat[2,k], SZ_FMT-1, "-%ds") # left justify
+ call pargi (len_fmt[k])
+ } else {
+ call sprintf (pformat[2,k], SZ_FMT-1, "%ds")
+ call pargi (len_fmt[k])
+ }
+ }
+
+ # This section prints the data.
+ rownum = 0 # initialize get_next_number
+ line_len = 0
+ done = false
+ while ( !done ) {
+
+ stat = get_next_number (ranges, rownum)
+ if ((stat == EOF) || (rownum > nrows)) {
+ done = true
+
+ } else {
+
+ # Print values in current row. The loop on k is for each
+ # column that is to be printed.
+ do k = 1, nprint {
+
+ # If the current column contains arrays, print each
+ # element, and start at the beginning of the line.
+ if (nelem[k] > 1 && line_len > 0) {
+ call fprintf (fd, "\n")
+ line_len = 0 # reset after newline
+ }
+ do j = 1, nelem[k] {
+
+ # If we have previously printed something on the
+ # current line, print either a space or newline,
+ # depending on how close we are to the end of the line.
+ if (line_len > 1) {
+ if (pagewidth > 0 &&
+ line_len + len_fmt[k] >= pagewidth) {
+ # need to start a new line
+ call fprintf (fd, "\n")
+ line_len = 0
+ } else {
+ # continue on current line
+ call fprintf (fd, " ")
+ line_len = line_len + 1
+ }
+ }
+
+ if (datatype[k] == TY_REAL) {
+ if (tbagtr (tp, cptr[k], rownum, rbuf, j, 1) < 1)
+ call error (1, MISSING)
+ call sprintf (Memc[lbuf], SZ_LBUF, FMT_REAL)
+ call pargr (rbuf)
+ } else if (datatype[k] == TY_DOUBLE) {
+ if (tbagtd (tp, cptr[k], rownum, dbuf, j, 1) < 1)
+ call error (1, MISSING)
+ call sprintf (Memc[lbuf], SZ_LBUF, FMT_DBL)
+ call pargd (dbuf)
+ } else if (datatype[k] == TY_INT) {
+ if (tbagti (tp, cptr[k], rownum, ibuf, j, 1) < 1)
+ call error (1, MISSING)
+ call sprintf (Memc[lbuf], SZ_LBUF, FMT_INT)
+ call pargi (ibuf)
+ } else if (datatype[k] == TY_SHORT) {
+ if (tbagts (tp, cptr[k], rownum, sbuf, j, 1) < 1)
+ call error (1, MISSING)
+ call sprintf (Memc[lbuf], SZ_LBUF, FMT_SHORT)
+ call pargs (sbuf)
+ } else {
+ if (tbagtt (tp, cptr[k], rownum,
+ Memc[lbuf], SZ_LBUF, j, 1) < 1)
+ call error (1, MISSING)
+ }
+ # If the value is a string, enclose in quotes if
+ # there are embedded blanks (ignore trailing blanks).
+ if (datatype[k] < 0)
+ call inquotes (Memc[lbuf], Memc[lbuf], SZ_LINE, NO)
+ call fprintf (fd, pformat[1,k])
+ call pargstr (Memc[lbuf])
+
+ # Add width of current column.
+ line_len = line_len + len_fmt[k]
+ }
+ }
+ call fprintf (fd, "\n") # end of current row
+ line_len = 0
+ }
+ }
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tprint/tprhtml.x b/pkg/utilities/nttools/tprint/tprhtml.x
new file mode 100644
index 00000000..6aecd26a
--- /dev/null
+++ b/pkg/utilities/nttools/tprint/tprhtml.x
@@ -0,0 +1,592 @@
+include <ctype.h> # for IS_WHITE
+include <tbset.h>
+include "tprint.h"
+
+define ALIGN_LEFT -1
+define ALIGN_CENTER 0 # currently not used
+define ALIGN_RIGHT 1
+
+# This file contains subroutines for printing header keywords and/or
+# table data in html table format.
+# The high-level subroutines are:
+#
+# tpr_html_begin
+# tpr_html_end
+# tpr_html_param print header keywords
+# tpr_html_pr print table data
+#
+# Phil Hodge, 9-Aug-1999 Subroutine created
+
+procedure tpr_html_begin()
+
+begin
+ call printf ("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n")
+ call printf ("<HTML>\n")
+end
+
+procedure tpr_html_end()
+
+begin
+ call printf ("</HTML>\n")
+end
+
+# tpr_html_pr -- print contents of table
+# This version prints the table data in html format.
+
+procedure tpr_html_pr (tp, colptr, ncp, s_cp, lgroup,
+ range_string, pagelength,
+ showrow, orig_row, showhdr, showunits)
+
+pointer tp # i: pointer to table descriptor
+pointer colptr[ncp] # i: array of pointers to column descriptors
+int ncp # i: number of columns to print
+pointer s_cp # i: pointer to column to control spacing
+int lgroup # i: print blank line after this many lines
+char range_string[ARB] # i: string which gives ranges of row numbers
+int pagelength # i: number of data lines before printing header
+bool showrow # i: true if row number is to be printed
+bool orig_row # i: show row number from underlying table?
+bool showhdr # i: print column names, etc?
+bool showunits # i: print column units?
+#--
+pointer sp
+pointer buf # for a table entry; also for table info
+pointer nelem # array length for each column
+pointer align # array of flags for column alignment
+int max_nelem # maximum of array lengths
+bool has_arrays # true if any column contains arrays
+bool has_scalars # true if not all columns contain arrays
+char rowspan[SZ_FNAME] # string possibly containing ROWSPAN=max_nelem
+int nspan # alternate ROWSPAN=nspan, if extra spacing
+int linenum # number of lines of data printed
+int tmp_linenum # temporary value for linenum
+int line_on_page # number of data lines printed on current page
+int nrows # number of rows in table
+int rownum # row number
+int row # row number to be printed
+int cn # loop index for column number
+int element # loop index for element within array
+int ranges[3,MAX_RANGES] # ranges of row numbers
+int nvalues # returned by decode_ranges and ignored
+int stat # returned by get_next_number
+int s_flag # YES if we should add a line for spacing
+int s_nelem # array size of s_cp column, or one
+bool done # flag for terminating while loop on rows
+int decode_ranges(), get_next_number()
+int tbpsta(), tbcigi(), tbagtt()
+errchk tbsirow
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+ call salloc (nelem, ncp, TY_INT)
+ call salloc (align, ncp, TY_INT)
+
+ # Get info for each column.
+ max_nelem = 1 # initial values
+ if (showrow)
+ has_scalars = true # row number is a scalar
+ else
+ has_scalars = false
+
+ if (s_cp == NULL)
+ s_nelem = 1
+ else
+ s_nelem = tbcigi (s_cp, TBL_COL_LENDATA)
+
+ do cn = 1, ncp {
+
+ # array length
+ Memi[nelem+cn-1] = tbcigi (colptr[cn], TBL_COL_LENDATA)
+ if (Memi[nelem+cn-1] > max_nelem)
+ max_nelem = Memi[nelem+cn-1]
+ if (Memi[nelem+cn-1] == 1)
+ has_scalars = true
+
+ # left or right alignment, depending on print format
+ call tbcigt (colptr[cn], TBL_COL_FMT, Memc[buf], SZ_LINE)
+ if (Memc[buf+1] == '-') # e.g. %-12s
+ Memi[align+cn-1] = ALIGN_LEFT
+ else
+ Memi[align+cn-1] = ALIGN_RIGHT
+ }
+ if (max_nelem > 1) {
+ has_arrays = true
+ nspan = max_nelem # initial value
+ if (lgroup > 1) {
+ nspan = nspan + max_nelem / (lgroup - 1)
+ if (max_nelem / (lgroup - 1) * (lgroup - 1) == max_nelem)
+ nspan = nspan - 1 # one entire line will be blank
+ }
+ call sprintf (rowspan, SZ_FNAME, "ROWSPAN=%d")
+ call pargi (nspan)
+ } else {
+ has_arrays = false
+ rowspan[1] = EOS
+ }
+
+ call tbtnam (tp, Memc[buf], SZ_LINE)
+
+ call printf ("\n")
+ call printf ("<HEAD><TITLE>tprint of %s</TITLE></HEAD>\n")
+ call pargstr (Memc[buf])
+ call printf ("<BODY>\n")
+ call printf ("\n")
+
+ call printf ("<TABLE BORDER=2>\n")
+ call printf ("<CAPTION ALIGN=TOP>\n")
+ call printf ("<B>Table data: %s</B>\n")
+ call pargstr (Memc[buf])
+ call printf ("</CAPTION>\n")
+ call printf ("\n")
+
+ nrows = tbpsta (tp, TBL_NROWS)
+
+ if (showhdr) {
+ call tpr_h_header (tp, colptr, ncp, showrow, showunits,
+ Memc[buf], SZ_LINE)
+ }
+
+ if (decode_ranges (range_string, ranges, MAX_RANGES, nvalues) != OK)
+ call error (1, "bad range of row numbers")
+
+ # Print each row that is to be printed.
+ linenum = 0 # initialize line counters
+ line_on_page = 0
+ rownum = 0 # initialize get_next_number
+ stat = get_next_number (ranges, rownum) # get first row number
+ done = (stat == EOF) || (rownum > nrows)
+
+ while ( !done ) {
+
+ # If we need to insert extra lines for spacing within a column
+ # that contains arrays, find out the total number of lines
+ # we'll need to print. Then set ROWSPAN to this new value.
+ if (s_nelem > 1) {
+ # Count the total number of elements we'll span.
+ nspan = max_nelem # initial value
+ tmp_linenum = linenum
+ do element = 1, max_nelem {
+ call tpr_h_space (tp, s_cp, s_nelem, lgroup,
+ rownum, element, max_nelem, tmp_linenum, nspan)
+ tmp_linenum = tmp_linenum + 1
+ }
+ # Overwrite original value of rowspan string.
+ call sprintf (rowspan, SZ_FNAME, "ROWSPAN=%d")
+ call pargi (nspan)
+ }
+
+ # If all columns contain arrays, print a blank line.
+ if (!has_scalars && rownum > 1)
+ call tpr_h_blank_line (ncp, showrow)
+
+ # Loop over the number of elements in the longest array.
+ do element = 1, max_nelem {
+
+ # Check whether we should print a blank line.
+ # (Set pagelength to zero for this call; in tpr_space,
+ # blocking into groups of lines is reset at the top of
+ # each page, but we don't do that with html output.)
+ call tpr_space (tp, s_cp, lgroup,
+ rownum, element, max_nelem, 0, linenum, s_flag)
+
+ if (s_flag == YES) {
+ # Print a blank line.
+ if (has_arrays && element > 1) {
+ # Print a blank field for each array column.
+ call printf (" <TR>\n")
+ do cn = 1, ncp {
+ if (Memi[nelem+cn-1] > 1)
+ call printf (" <TD>&nbsp;</TD>\n")
+ }
+ call printf (" </TR>\n")
+ } else {
+ call tpr_h_blank_line (ncp, showrow)
+ }
+ linenum = linenum + 1
+ line_on_page = line_on_page + 1
+ }
+
+ # Print column names again, if appropriate.
+ if (showhdr && element == 1 && pagelength > 0) {
+ if (line_on_page >= pagelength) {
+ call tpr_h_header (tp, colptr, ncp, showrow, showunits,
+ Memc[buf], SZ_LINE)
+ line_on_page = 0
+ }
+ }
+
+ call printf (" <TR>\n")
+
+ if (element == 1 && showrow) {
+ if (orig_row)
+ call tbsirow (tp, rownum, row)
+ else
+ row = rownum
+ if (has_arrays) {
+ call printf (" <TD ALIGN=RIGHT %s>%d</TD>\n")
+ call pargstr (rowspan)
+ call pargi (row)
+ } else {
+ call printf (" <TD ALIGN=RIGHT>%d</TD>\n")
+ call pargi (row)
+ }
+ }
+
+ # Print each column.
+ do cn = 1, ncp {
+
+ # Does the current column contain arrays?
+ if (Memi[nelem+cn-1] > 1) {
+
+ if (element <= Memi[nelem+cn-1]) {
+ if (tbagtt (tp, colptr[cn], rownum,
+ Memc[buf], SZ_LINE, element, 1) < 1)
+ call error (1, "can't read array element")
+ call tpr_cell (Memc[buf], Memi[align+cn-1],
+ false, "")
+ } else {
+ call printf (" <TD>&nbsp;</TD>\n")
+ }
+
+ } else if (element == 1) {
+
+ call tbegtt (tp, colptr[cn], rownum,
+ Memc[buf], SZ_LINE)
+ if (has_arrays) {
+ call tpr_cell (Memc[buf], Memi[align+cn-1],
+ true, rowspan)
+ } else {
+ call tpr_cell (Memc[buf], Memi[align+cn-1],
+ false, "")
+ }
+ }
+ }
+
+ call printf (" </TR>\n")
+ linenum = linenum + 1
+ line_on_page = line_on_page + 1
+ }
+
+ stat = get_next_number (ranges, rownum)
+ done = (stat == EOF) || (rownum > nrows)
+ }
+
+ # Print column names at the end of the document, if appropriate.
+ if (showhdr && pagelength > 0) {
+ if (line_on_page >= pagelength) {
+ call tpr_h_header (tp, colptr, ncp, showrow, showunits,
+ Memc[buf], SZ_LINE)
+ }
+ }
+
+ call printf ("</TABLE>\n")
+ call printf ("</BODY>\n")
+ call flush (STDOUT)
+
+ call sfree (sp)
+end
+
+procedure tpr_h_blank_line (ncp, showrow)
+
+int ncp # i: number of columns to print
+bool showrow # i: true if we also print row numbers
+#--
+int nspan # number of columns to span
+
+begin
+ if (showrow)
+ nspan = ncp + 1
+ else
+ nspan = ncp
+
+ call printf (" <TR>\n")
+ call printf (" <TD COLSPAN=%d>&nbsp;</TD>\n")
+ call pargi (nspan)
+ call printf (" </TR>\n")
+end
+
+# This is a simplified version of tpr_space which just increments the count
+# of the number of elements to be spanned in a ROWSPAN tag.
+#
+# We can't just call tpr_space to do this, because each time it examines
+# a row, it saves the current value as 'previous'. We need this routine
+# in order to have a separate 'previous' variable.
+#
+# We don't need to increment linenum if nspan is incremented, because we
+# only use this routine for spacing in arrays, and it's the element number
+# that we care about for that case.
+
+procedure tpr_h_space (tp, s_cp, s_nelem, lgroup,
+ rownum, element, max_nelem, linenum, nspan)
+
+pointer tp # i: pointer to table descriptor
+pointer s_cp # i: pointer to column to control spacing
+int s_nelem # i: array size of s_cp column
+int lgroup # i: print blank after this many lines
+int rownum # i: number of current row
+int element # i: array element number
+int max_nelem # i: max value for element
+int linenum # i: number of lines that have been printed
+int nspan # io: incremented if we should increment ROWSPAN
+#--
+pointer sp
+pointer current # scratch for value of column in current row
+int lpage # number of line we would print
+int s_flag # YES if we would print a line for spacing
+char previous[SZ_LINE] # value of column in previous row
+bool do_compare # true if we should compare column values
+bool strne()
+int junk, tbagtt()
+errchk tbegtt, tbagtt
+
+begin
+ s_flag = NO # may be changed later
+
+ # linenum is the number of lines that have already been printed.
+ # lpage is the current line number.
+ lpage = linenum + 1
+
+ # If this is the first line, get the current value of the column
+ # and save it as "previous". That's all.
+ if (lpage == 1) {
+ junk = tbagtt (tp, s_cp, rownum, previous, SZ_LINE, element, 1)
+ return
+ }
+
+ # Have we printed a group of lines? If so, set the flag to indicate
+ # that we should print a blank line.
+ if (lgroup > 1) {
+ if (max_nelem > 1) {
+ if (lpage > 1) {
+ if (lgroup == 2)
+ s_flag = YES
+ else if (mod (element, lgroup-1) == 1)
+ s_flag = YES
+ }
+ } else if (mod (lpage, lgroup) == 0) {
+ s_flag = YES
+ }
+ }
+
+ # Check the value in the column.
+ if (element <= s_nelem) {
+ if (s_flag == YES) {
+ # Since we already know we need to print a space, we don't
+ # have to compare current and previous values, but we still
+ # must save current value as "previous".
+ junk = tbagtt (tp, s_cp, rownum, previous, SZ_LINE,
+ element, 1)
+ } else {
+ # Get current value, and compare it with previous value.
+ call smark (sp)
+ call salloc (current, SZ_LINE, TY_CHAR)
+ do_compare = true # may be reset
+ junk = tbagtt (tp, s_cp, rownum, Memc[current], SZ_LINE,
+ element, 1)
+ if (do_compare && strne (Memc[current], previous)) {
+ # Set flag; save current value as previous value.
+ s_flag = YES
+ call strcpy (Memc[current], previous, SZ_LINE)
+ }
+ call sfree (sp)
+ }
+ }
+
+ # If we should print a line before the first element of an array,
+ # we'll print a full line, rather than adding one to ROWSPAN; this
+ # is why we include the test on element.
+ if (s_flag == YES && element > 1)
+ nspan = nspan + 1
+end
+
+# This routine trims trailing blanks from the input buffer (in-place),
+# and it sets ip to the index of the first non-blank character. If
+# the entire field is blank, the string "&nbsp;" is assigned to the
+# input buffer.
+
+procedure tpr_deblank (buf, ip)
+
+char buf[ARB] # io: input string (trailing blanks will be truncted)
+int ip # o: first non-blank character in buf
+#--
+int strlen()
+
+begin
+ ip = strlen (buf)
+ while (ip >= 1 && IS_WHITE(buf[ip])) { # trim trailing blanks
+ buf[ip] = EOS
+ ip = ip - 1
+ }
+ ip = 1
+ while (IS_WHITE(buf[ip])) # trim leading blanks
+ ip = ip + 1
+ if (buf[ip] == EOS) {
+ call strcpy ("&nbsp;", buf, SZ_LINE)
+ ip = 1
+ }
+end
+
+# This routine prints one table element.
+
+procedure tpr_cell (buf, align, print_rowspan, rowspan)
+
+char buf[ARB] # io: input string (trailing blanks will be truncted)
+int align # i: ALIGN_LEFT or ALIGN_RIGHT
+bool print_rowspan # i: true --> print rowspan string
+char rowspan[ARB] # i: ROWSPAN=<n>
+#--
+int ip # first non-blank character in buf
+
+begin
+ call tpr_deblank (buf, ip)
+
+ if (print_rowspan) {
+
+ if (align == ALIGN_LEFT) {
+ call printf (" <TD ALIGN=LEFT %s>%s</TD>\n")
+ call pargstr (rowspan)
+ call pargstr (buf[ip])
+ } else {
+ call printf (" <TD ALIGN=RIGHT %s>%s</TD>\n")
+ call pargstr (rowspan)
+ call pargstr (buf[ip])
+ }
+
+ } else {
+
+ if (align == ALIGN_LEFT) {
+ call printf (" <TD ALIGN=LEFT>%s</TD>\n")
+ call pargstr (buf[ip])
+ } else {
+ call printf (" <TD ALIGN=RIGHT>%s</TD>\n")
+ call pargstr (buf[ip])
+ }
+ }
+end
+
+procedure tpr_h_header (tp, colptr, ncp, showrow, showunits, buf, maxch)
+
+pointer tp # i: pointer to table descriptor
+pointer colptr[ncp] # i: array of pointers to column descriptors
+int ncp # i: number of columns to print
+bool showrow # i: true if row number is to be printed
+bool showunits # i: print column units?
+char buf[ARB] # o: scratch space
+int maxch # i: size of buf
+#--
+int cn # loop index for column number
+
+begin
+ call printf (" <TR>\n")
+
+ if (showrow)
+ call printf (" <TH ALIGN=RIGHT>(row)</TH>\n")
+
+ do cn = 1, ncp {
+ call tbcigt (colptr[cn], TBL_COL_NAME, buf, SZ_LINE)
+ call printf (" <TH>%s</TH>\n")
+ call pargstr (buf)
+ }
+ call printf (" </TR>\n")
+
+ if (showunits) {
+ call printf (" <TR>\n")
+ if (showrow)
+ call printf (" <TH>&nbsp;</TH>\n")
+ do cn = 1, ncp {
+ call tbcigt (colptr[cn], TBL_COL_UNITS, buf, SZ_LINE)
+ if (buf[1] == EOS) {
+ call printf (" <TH>&nbsp;</TH>\n")
+ } else {
+ call printf (" <TH>%s</TH>\n")
+ call pargstr (buf)
+ }
+ }
+ call printf (" </TR>\n")
+ }
+end
+
+# This routine prints all the header keywords for a table.
+
+procedure tpr_html_param (tp)
+
+pointer tp # i: pointer to table descriptor
+#--
+pointer sp
+pointer buf # for a keyword value
+pointer comment # keyword comment
+int npar # number of header parameters
+char keyword[SZ_KEYWORD] # keyword name
+int n # loop index for keyword number
+int dtype # returned by tbhgnp and ignored
+int tbpsta()
+
+begin
+ npar = tbpsta (tp, TBL_NPAR)
+ if (npar <= 0)
+ return
+
+ call smark (sp)
+ call salloc (buf, SZ_FNAME, TY_CHAR)
+ call salloc (comment, SZ_FNAME, TY_CHAR)
+
+ call tbtnam (tp, Memc[buf], SZ_LINE)
+
+ call printf ("\n")
+ call printf ("<HEAD><TITLE>tprint of %s</TITLE></HEAD>\n")
+ call pargstr (Memc[buf])
+ call printf ("<BODY>\n")
+ call printf ("\n")
+
+ call printf ("<TABLE BORDER=2>\n")
+ call printf ("<CAPTION ALIGN=TOP>\n")
+ call printf ("<B>Table keywords: %s</B>\n")
+ call pargstr (Memc[buf])
+ call printf ("</CAPTION>\n")
+ call printf ("\n")
+
+ call printf (" <TR>\n")
+ call printf (" <TH>keyword</TH>\n")
+ call printf (" <TH>value</TH>\n")
+ call printf (" <TH>comment</TH>\n")
+ call printf (" </TR>\n")
+
+ do n = 1, npar {
+
+ call printf (" <TR>\n")
+
+ # Get the Nth header parameter and comment.
+ call tbhgnp (tp, n, keyword, dtype, Memc[buf])
+ call tbhgcm (tp, keyword, Memc[comment], SZ_FNAME)
+
+ if (keyword[1] == EOS) {
+ call printf (" <TD>&nbsp;</TD>\n")
+ } else {
+ call printf (" <TD>%s</TD>\n")
+ call pargstr (keyword)
+ }
+
+ if (Memc[buf] == EOS) {
+ call printf (" <TD>&nbsp;</TD>\n")
+ } else {
+ call printf (" <TD>%s</TD>\n")
+ call pargstr (Memc[buf])
+ }
+
+ if (Memc[comment] == EOS) {
+ call printf (" <TD>&nbsp;</TD>\n")
+ } else {
+ call printf (" <TD>%s</TD>\n")
+ call pargstr (Memc[comment])
+ }
+
+ call printf (" </TR>\n")
+ }
+
+ call printf ("</TABLE>\n")
+ call printf ("</BODY>\n")
+ call flush (STDOUT)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tprint/tprint.h b/pkg/utilities/nttools/tprint/tprint.h
new file mode 100644
index 00000000..d0781b1c
--- /dev/null
+++ b/pkg/utilities/nttools/tprint/tprint.h
@@ -0,0 +1,5 @@
+define MAXCOLS 52 # maximum number of columns per page
+define SZ_FMT 17 # size of string containing print format
+define MAX_RANGES (SZ_LINE/2) # max number of ranges of row numbers
+define SHORT_STRING 11 # size of short text strings
+define SZ_ROW_HDR 5 # size of header for row number: "# row"
diff --git a/pkg/utilities/nttools/tprint/tprint.x b/pkg/utilities/nttools/tprint/tprint.x
new file mode 100644
index 00000000..65c2d09d
--- /dev/null
+++ b/pkg/utilities/nttools/tprint/tprint.x
@@ -0,0 +1,535 @@
+include <time.h> # defines SZ_TIME for datestr
+include <error.h> # defines EA_WARN
+include <finfo.h> # used by tpr_fm_date
+include <fset.h> # used to check whether output is redirected
+include <tbset.h>
+include "tprint.h"
+
+# tprint -- Program to print tables.
+#
+# Phil Hodge, 31-Jul-1987 Task created
+# Phil Hodge, 11-Aug-1987 Delete call to tbtext.
+# Phil Hodge, 28-Aug-1987 Write date that table was last modified.
+# Phil Hodge, 12-Oct-1987 Include LaTeX/TeX option.
+# Phil Hodge, 30-Dec-1987 Filename template; tctexp for column names.
+# Phil Hodge, 12-Feb-1988 Include option to align columns if format is small.
+# Phil Hodge, 30-Mar-1988 Page width = ttyncols; get sp_col & lgroup.
+# Phil Hodge, 7-Sep-1988 Change parameter name for table.
+# Phil Hodge, 10-May-1991 Use clpopns instead of clpopnu.
+# Phil Hodge, 26-Mar-1992 Remove call to tbtext; use tbtnam instead.
+# Phil Hodge, 28-Oct-1992 Set align=false if showhdr=false.
+# Phil Hodge, 5-Jul-1993 Include option to print column units.
+# Phil Hodge, 3-Feb-1994 Set showunits to false for a text table.
+# Phil Hodge, 15-Dec-1994 Increase size of table name from SZ_FNAME to SZ_LINE.
+# Phil Hodge, 16-Feb-1995 In tpr_param_pr, print "#" before header lines.
+# Phil Hodge, 6-Mar-1995 In tpr_param_pr, print comment for header parameter.
+# Phil Hodge, 23-Jun-1995 In tpr_fm_date, get file name using tbparse.
+# Phil Hodge, 3-Oct-1995 Replace clgfil calls with tbn... .
+# Phil Hodge, 9-Apr-1996 Error check tbtopn and tpr_data_pr;
+# call error if number of columns to print is zero (i.e. if no
+# column was found); flush STDOUT.
+# Phil Hodge, 5-Jun-1997 Use single instead of double quotes for keyword
+# text value, if there's an associated comment.
+# Phil Hodge, 26-Mar-1998 Add orig_row to par file, to show row number in
+# underlying table in case a row selector was used.
+# Phil Hodge, 7-Jun-1999 Allow showunits to be true for a text table;
+# this overrides the change made on 3-Feb-1994;
+# if input is redirected, set input to STDIN without getting cl param.
+# Phil Hodge, 9-Aug-1999 Add option = html; modify tpr_space to handle
+# arrays and to just set a flag, rather than actually printing the space.
+# Phil Hodge, 3-Jul-2000 In tpr_param_pr, delete leading blanks from the
+# value and comment.
+# Phil Hodge, 15-Jul-2009 In tpr_fm_date, remove ttype from the call to
+# tbparse.
+
+procedure tprint()
+
+pointer tp # pointer to input table descr
+pointer sp # stack pointer
+pointer tname # scratch for table name
+pointer columns # scratch for list of column names
+pointer range_string # string which gives ranges of row numbers
+pointer tlist # for list of input table names
+int pagewidth # max number of char in line length
+int pagelength # number of data lines (excl header) per page
+int lgroup # number of lines to group together on output
+bool prparam, prdata # print header parameters? data?
+bool showrow # show row number on output?
+bool orig_row # show row number from underlying table?
+bool showhdr # show table name, column names, etc on output?
+bool showunits # show column units on output?
+bool align # override print fmt to align col & name?
+char prt_option[SHORT_STRING] # "plain", "latex", "tex"
+char sp_cname[SZ_COLNAME] # name of column to control spacing
+bool first_table # false ==> print line to separate tables
+int clgeti(), fstati(), envgeti()
+bool clgetb()
+pointer tbnopenp(), tbnopen()
+int tbnget()
+pointer tbtopn()
+
+begin
+ call smark (sp)
+ call salloc (tname, SZ_LINE, TY_CHAR)
+ call salloc (columns, SZ_LINE, TY_CHAR)
+
+ if (fstati (STDIN, F_REDIR) == YES)
+ tlist = tbnopen ("STDIN")
+ else
+ tlist = tbnopenp ("table")
+
+ # Find out which portions of the table the user wants to print.
+ prparam = clgetb ("prparam")
+ prdata = clgetb ("prdata")
+ if (!prparam && !prdata) {
+ call sfree (sp)
+ return
+ }
+
+ if (prdata) {
+ # Get parameters relevant to printing data portion of table.
+
+ call salloc (range_string, SZ_LINE, TY_CHAR)
+
+ # Get page width from ttyncols unless output is redirected.
+ if (fstati (STDOUT, F_REDIR) == YES)
+ pagewidth = clgeti ("pwidth")
+ else
+ pagewidth = envgeti ("ttyncols")
+ pagelength = clgeti ("plength")
+ showrow = clgetb ("showrow")
+ orig_row = clgetb ("orig_row")
+ call clgstr ("columns", Memc[columns], SZ_LINE)
+ call clgstr ("rows", Memc[range_string], SZ_LINE)
+ align = clgetb ("align")
+
+ call clgstr ("sp_col", sp_cname, SZ_COLNAME)
+ lgroup = clgeti ("lgroup") + 1 # add one for the space
+ }
+
+ call clgstr ("option", prt_option, SHORT_STRING)
+ showhdr = clgetb ("showhdr")
+ if (showhdr) {
+ showunits = clgetb ("showunits")
+ } else {
+ # There's no need to align columns with their names if the names
+ # are not printed.
+ align = false
+ showunits = false
+ }
+
+ if (prt_option[1] == 'h') # HTML
+ call tpr_html_begin()
+
+ # Loop over all table names in the file name template.
+ first_table = true
+ while (tbnget (tlist, Memc[tname], SZ_LINE) != EOF) {
+
+ if ( ! first_table ) {
+ call printf ("\n") # blank line between tables
+ call flush (STDOUT)
+ }
+ first_table = false
+
+ # Open the table.
+ iferr {
+ tp = tbtopn (Memc[tname], READ_ONLY, 0)
+ } then {
+ call erract (EA_WARN)
+ next
+ }
+
+ # Get the full table name (for use by tpr_fm_date),
+ call tbtnam (tp, Memc[tname], SZ_LINE)
+
+ # Print the name of the table and the date that the table was
+ # last modified.
+ if (showhdr)
+ call tpr_fm_date (Memc[tname], prt_option)
+
+ if (prparam) # print header parameters
+ call tpr_param_pr (tp, prt_option, prdata)
+
+ if (prdata) { # print data portion of table
+ iferr {
+ call tpr_data_pr (tp, pagewidth, pagelength,
+ showrow, orig_row, showhdr, showunits,
+ align, sp_cname, lgroup,
+ Memc[columns], Memc[range_string], prt_option)
+ } then {
+ call tbtclo (tp)
+ call erract (EA_WARN)
+ next
+ }
+ }
+
+ call tbtclo (tp)
+ }
+ if (prt_option[1] == 'h') # HTML
+ call tpr_html_end()
+
+ call tbnclose (tlist)
+ call sfree (sp)
+end
+
+
+
+# tpr_fm_date -- Get date of file
+# This procedure gets the date that a table was last modified and writes
+# the table name and date to STDOUT.
+
+procedure tpr_fm_date (tablename, prt_option)
+
+char tablename[ARB] # i: name of table
+char prt_option[ARB] # i: "plain", "latex", or "tex"
+#--
+pointer sp
+pointer filename # name of table without brackets
+pointer cdfname # returned by tbparse and ignored
+int hdu # ignored
+long ostruct[LEN_FINFO] # contains info about file
+long mtime
+char datestr[SZ_TIME] # date that table was last modified
+char percent # the % character
+int junk, tbparse()
+int finfo()
+
+begin
+ if (prt_option[1] == 'h') # HTML
+ return
+
+ call smark (sp)
+ call salloc (filename, SZ_FNAME, TY_CHAR)
+ call salloc (cdfname, SZ_FNAME, TY_CHAR)
+
+ # Get file name from table name.
+ junk = tbparse (tablename, Memc[filename],
+ Memc[cdfname], SZ_FNAME, hdu)
+
+ percent = '%'
+
+ if (finfo (Memc[filename], ostruct) != ERR) {
+ mtime = FI_MTIME(ostruct)
+ call cnvtime (mtime, datestr, SZ_TIME)
+
+ if (prt_option[1] == 'p') { # plain print
+ call printf ("# Table %s %s\n")
+ call pargstr (tablename)
+ call pargstr (datestr)
+ } else { # LaTeX or TeX
+ call printf ("%c")
+ call pargc (percent) # comment
+ call printf (" Table %s %s\n")
+ call pargstr (tablename)
+ call pargstr (datestr)
+ }
+ call printf ("\n")
+ }
+ call flush (STDOUT)
+
+ call sfree (sp)
+end
+
+
+
+# tpr_param_pr -- Print header parameters
+# This procedure prints the header parameters on STDOUT.
+#
+# Phil Hodge, 5-Oct-1987 Subroutine created
+# Phil Hodge, 30-Dec-1987 If latex or tex, print % prefix.
+# Phil hodge, 9-Mar-1989 Change type of dtype in tbhgnp from char to int.
+
+procedure tpr_param_pr (tp, prt_option, prdata)
+
+pointer tp # i: pointer to table descriptor
+char prt_option[ARB] # i: "plain", "latex", or "tex"
+bool prdata # i: print data? (not here, though)
+#--
+pointer sp
+pointer value # scratch for value of parameter (string)
+pointer comment # scratch for comment for parameter
+int dtype # data type (TY_CHAR, etc)
+int npar # number of header parameters
+int n # loop index for parameter number
+int ipp, ipc # offsets for skipping leading blanks
+char keyword[SZ_KEYWORD] # buffer for header parameter keyword
+char percent # the % character
+int tbpsta()
+
+begin
+ if (prt_option[1] == 'h') { # HTML
+ call tpr_html_param (tp)
+ return
+ }
+
+ percent = '%'
+ npar = tbpsta (tp, TBL_NPAR)
+ if (npar > 0) {
+ call smark (sp)
+ call salloc (value, SZ_PARREC, TY_CHAR)
+ call salloc (comment, SZ_PARREC, TY_CHAR)
+ do n = 1, npar {
+
+ # Get the Nth header parameter and comment.
+ call tbhgnp (tp, n, keyword, dtype, Memc[value])
+ call tbhgcm (tp, keyword, Memc[comment], SZ_PARREC)
+ ipp = 0
+ while (Memc[value+ipp] == ' ')
+ ipp = ipp + 1
+ ipc = 0
+ while (Memc[comment+ipc] == ' ')
+ ipc = ipc + 1
+
+ if (prt_option[1] != 'p') { # LaTeX or TeX, not plain
+ call printf ("%c")
+ call pargc (percent) # comment
+ } else if (prdata) { # plain output, with data
+ call printf ("#K ") # comment
+ }
+
+ # Print the keyword and value, and possibly a comment.
+ if (Memc[comment+ipc] == EOS) { # no comment to print
+
+ call printf ("%-8s %s\n")
+ call pargstr (keyword)
+ call pargstr (Memc[value+ipp])
+
+ } else if (dtype == TY_CHAR) {
+
+ # Enclose value in quotes to distinguish from comment.
+ call printf ("%-8s '%s' %s\n")
+ call pargstr (keyword)
+ call pargstr (Memc[value+ipp])
+ call pargstr (Memc[comment+ipc])
+
+ } else {
+
+ # Numeric; no quotes needed.
+ call printf ("%-8s %s %s\n")
+ call pargstr (keyword)
+ call pargstr (Memc[value+ipp])
+ call pargstr (Memc[comment+ipc])
+ }
+ }
+ call sfree (sp)
+ call printf ("\n")
+ }
+ call flush (STDOUT)
+end
+
+
+
+# tpr_data_pr -- Print table data
+# This procedure prints the data portion of a table on STDOUT.
+#
+# Phil Hodge, 5-Oct-1987 Subroutine created
+# Phil Hodge, 12-Feb-1988 Include option to align columns if format is small.
+# Phil Hodge, 30-Mar-1988 Get column to control spacing of printout.
+
+procedure tpr_data_pr (tp, pagewidth, pagelength,
+ showrow, orig_row, showhdr, showunits,
+ align, sp_cname, lgroup,
+ columns, range_string, prt_option)
+
+pointer tp # i: pointer to table descriptor
+int pagewidth # i: page width
+int pagelength # i: number of lines of table per page
+bool showrow # i: print row number?
+bool orig_row # i: show row number from underlying table?
+bool showhdr # i: print column names, etc?
+bool showunits # i: print column units?
+bool align # i: override print fmt to align col & name?
+char sp_cname[SZ_COLNAME] # i: column to control spacing
+int lgroup # i: print blank line after this many lines
+char columns[ARB] # i: list of names of columns to be printed
+char range_string[ARB] # i: range of row numbers to print
+char prt_option[ARB] # i: "plain", "latex", or "tex"
+#--
+pointer sp
+pointer cptr # scratch for array of column pointers
+pointer s_cp # pointer to column to control spacing
+int nrows, ncols # number of rows and columns in table
+int ncp # number of columns to print (may be < ncols)
+int k # loop index
+int tbpsta()
+
+begin
+ nrows = tbpsta (tp, TBL_NROWS)
+ ncols = tbpsta (tp, TBL_NCOLS)
+
+ if ((nrows < 1) || (ncols < 1)) {
+ call eprintf ("table is empty\n")
+ return # nothing more to do
+ }
+
+ # Allocate enough space for storing a descriptor for each column.
+ call smark (sp)
+ call salloc (cptr, ncols, TY_POINTER)
+
+ # Get column pointers for all columns that are to be printed.
+ call tctexp (tp, columns, ncols, ncp, Memi[cptr])
+
+ # Check whether there is a column to control spacing.
+ k = 1
+ while ((sp_cname[k] == ' ' || sp_cname[k] == '\t') &&
+ (sp_cname[k] != EOS) && (k <= SZ_COLNAME))
+ k = k + 1
+ if (sp_cname[k] != EOS) {
+ call tbcfnd1 (tp, sp_cname[k], s_cp)
+ if (s_cp == NULL) {
+ call eprintf ("WARNING: column `%s' for spacing not found\n")
+ call pargstr (sp_cname)
+ }
+ } else {
+ s_cp = NULL
+ }
+
+ if (ncp > 0) {
+ # Print the values in the table.
+ if (prt_option[1] == 'p') { # plain printing
+ call tpr_plain_pr (tp, Memi[cptr], ncp, s_cp, lgroup,
+ range_string, pagewidth, pagelength,
+ showrow, orig_row, showhdr, showunits, align)
+ } else if (prt_option[1] == 'h') { # html table
+ call tpr_html_pr (tp, Memi[cptr], ncp, s_cp, lgroup,
+ range_string, pagelength,
+ showrow, orig_row, showhdr, showunits)
+ } else { # LaTeX or TeX
+ call tpr_latex_pr (tp, Memi[cptr], ncp, s_cp, lgroup,
+ range_string, pagewidth, pagelength,
+ showrow, orig_row, showhdr, showunits, prt_option)
+ }
+ call flush (STDOUT)
+ } else {
+ call error (1, "column not found")
+ }
+ call sfree (sp)
+end
+
+
+
+# tpr_space -- print line separator
+# Check whether we should print a blank line (or other line separator) if
+# the value in the designated column has changed since the last call to
+# this routine or if a group of lgroup lines has been printed.
+# The groups of lines are counted starting at the beginning of each
+# page; this makes a difference if lgroup does not divide pagelength.
+# If any column being printed contains arrays, then lgroup is applied
+# to element number, not to line number.
+#
+# If lgroup is one then it will be ignored; if s_cp is NULL then
+# the column values will be ignored.
+# When linenum is zero, the "previous" column value is initialized
+# with the current value.
+
+procedure tpr_space (tp, s_cp, lgroup,
+ rownum, element, max_nelem, pagelength, linenum, s_flag)
+
+pointer tp # i: pointer to table descriptor
+pointer s_cp # i: pointer to column to control spacing
+int lgroup # i: print blank after this many lines
+int rownum # i: number of current row
+int element # i: array element number
+int max_nelem # i: max value for element
+int pagelength # i: number of data lines per page
+int linenum # i: number of lines that have been printed
+int s_flag # o: YES if we should print a line for spacing
+#--
+pointer sp
+pointer current # scratch for value of column in current row
+int lpage # number of lines already printed on this page
+char previous[SZ_LINE] # value of column in previous row
+bool do_compare # true if we should compare column values
+bool strne()
+int nelem, tbcigi(), junk, tbagtt()
+errchk tbegtt, tbagtt
+
+begin
+ s_flag = NO # may be changed later
+
+ if (lgroup <= 1 && s_cp == NULL)
+ return
+
+ if (pagelength > 0)
+ lpage = mod (linenum, pagelength) + 1
+ else
+ lpage = linenum + 1
+
+ if (s_cp != NULL)
+ nelem = tbcigi (s_cp, TBL_COL_LENDATA)
+ else
+ nelem = 1
+
+ # If we're at the beginning of a page, get the current value
+ # of the column and save it as "previous". That's all.
+ if (lpage == 1) {
+ if (s_cp != NULL) {
+ if (nelem > 1) {
+ if (element <= nelem) {
+ junk = tbagtt (tp, s_cp, rownum, previous, SZ_LINE,
+ element, 1)
+ }
+ } else {
+ call tbegtt (tp, s_cp, rownum, previous, SZ_LINE)
+ }
+ }
+ return
+ }
+
+ # Have we printed a group of lines? If so, set the flag to indicate
+ # that we should print a blank line.
+ # If we're printing arrays, apply lgroup to the array elements instead
+ # of to the rows, but in this case also print a space between each row
+ # (i.e. when element is one), except at the top of a page.
+ # Note: The value of lgroup is one more than the parameter value,
+ # so that it can be used with mod on linenum, because linenum gets
+ # incremented when a blank line is printed. But here we want to use
+ # lgroup with element, which doesn't get incremented. That's why
+ # we subtract one from lgroup in "mod (element, lgroup-1)".
+ if (lgroup > 1) {
+ if (max_nelem > 1) {
+ if (lpage > 1) {
+ if (lgroup == 2)
+ s_flag = YES
+ else if (mod (element, lgroup-1) == 1)
+ s_flag = YES
+ }
+ } else if (mod (lpage, lgroup) == 0) {
+ s_flag = YES
+ }
+ }
+
+ # Check the value in the column.
+ if (s_cp != NULL) {
+ if (s_flag == YES) {
+ # If we already know we need to print a space, we don't have
+ # to compare current and previous values, but we still must
+ # save current value as "previous".
+ if (nelem > 1 && element <= nelem) {
+ junk = tbagtt (tp, s_cp, rownum, previous, SZ_LINE,
+ element, 1)
+ } else if (element == 1) {
+ call tbegtt (tp, s_cp, rownum, previous, SZ_LINE)
+ } # else we already have the value
+ } else {
+ # Get current value, and compare it with previous value.
+ call smark (sp)
+ call salloc (current, SZ_LINE, TY_CHAR)
+ do_compare = true # may be reset
+ if (nelem > 1 && element <= nelem) {
+ junk = tbagtt (tp, s_cp, rownum, Memc[current], SZ_LINE,
+ element, 1)
+ } else if (element == 1) {
+ call tbegtt (tp, s_cp, rownum, Memc[current], SZ_LINE)
+ } else {
+ do_compare = false
+ }
+ if (do_compare && strne (Memc[current], previous)) {
+ # Set flag; save current value as previous value.
+ s_flag = YES
+ call strcpy (Memc[current], previous, SZ_LINE)
+ }
+ call sfree (sp)
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/tprint/tprlatex.x b/pkg/utilities/nttools/tprint/tprlatex.x
new file mode 100644
index 00000000..2875caa8
--- /dev/null
+++ b/pkg/utilities/nttools/tprint/tprlatex.x
@@ -0,0 +1,579 @@
+include <tbset.h>
+include "tprint.h"
+
+# tpr_latex_pr -- print contents of table
+# This version prints the table data in a form suitable for input to
+# TeX or LaTeX. The corresponding procedure that prints in plain text
+# format is tpr_plain_pr.
+#
+# Phil Hodge, 7-Oct-1987 Subroutine created
+# Phil Hodge, 12-Feb-1988 Call tpr_pfmt_l instead of tpr_pfmt
+# Phil Hodge, 30-Mar-1988 Use a column to control spacing of printout.
+# Phil Hodge, 6-Jan-1989 tpr_break_l for new page, also after tpr_cnames_pr.
+# Phil Hodge, 2-Apr-1993 In prt_row_l, include short datatype.
+# Phil Hodge, 5-Jul-1993 Include option to print column units.
+# Phil Hodge, 26-Mar-1998 Add orig_row to calling sequence, use in prt_row_l;
+# in tpr_break_l, the calling sequence of tpr_end_tbl
+# had an extra argument.
+# Phil Hodge, 9-Aug-1999 Change the calling sequence of tpr_space.
+
+procedure tpr_latex_pr (tp, colptr, ncp, s_cp, lgroup,
+ range_string, pagewidth, pagelength,
+ showrow, orig_row, showhdr, showunits, prt_option)
+
+pointer tp # i: pointer to table descriptor
+pointer colptr[ncp] # i: array of pointers to column descriptors
+int ncp # i: number of columns to print
+pointer s_cp # i: pointer to column to control spacing
+int lgroup # i: print a blank line after this many lines
+char range_string[ARB] # i: string which gives ranges of row numbers
+int pagewidth # i: page width
+int pagelength # i: number of data lines per page
+bool showrow # i: true if row number is to be printed
+bool orig_row # i: show row number from underlying table?
+bool showhdr # i: print column names, etc?
+bool showunits # i: print column units?
+char prt_option[ARB] # i: "latex" or "tex"
+#--
+pointer sp
+pointer data_fmt # print formats for column data values
+pointer j_flag # left or right justification
+char rn_fmt[SZ_FMT] # format for printing row numbers
+char rn_name[SZ_ROW_HDR] # row number header: "(row)"
+char percent # a percent sign (comment for TeX)
+int nrows # total number of rows in table
+int element # loop index for array element number
+int max_nelem # max number of elements
+int rn_width # width needed for printing row number
+int lenfmt[MAXCOLS] # lengths of print fmt for cols on current page
+int rownum # row number
+int linenum # number of lines of data printed
+int ranges[3,MAX_RANGES] # ranges of row numbers
+int nvalues # returned by decode_ranges and ignored
+int stat # returned by get_next_number
+int k # loop index
+int s_flag # YES if we should add a line for spacing
+bool done # flag for terminating while loop on rows
+int decode_ranges(), get_next_number(), tbpsta(), tbcigi()
+
+begin
+ percent = '%'
+
+ # Allocate space for format strings for printing column names
+ # and values.
+ call smark (sp)
+ call salloc (data_fmt, (SZ_FMT+1)*ncp, TY_CHAR)
+ call salloc (j_flag, ncp, TY_INT)
+
+ if (ncp > MAXCOLS) {
+ call eprintf ("maximum number of columns is %d\n")
+ call pargi (MAXCOLS)
+ call error (1, "")
+ }
+
+ nrows = tbpsta (tp, TBL_NROWS)
+
+ if (decode_ranges (range_string, ranges, MAX_RANGES, nvalues) != OK)
+ call error (1, "bad range of row numbers")
+
+ # These three values (rn_name, rn_fmt, rn_width) must be consistent.
+ call strcpy ("(row)", rn_name, SHORT_STRING)
+ call strcpy ("%5d", rn_fmt, SZ_FMT)
+ if (showrow)
+ rn_width = SZ_ROW_HDR # space for printing row number
+ else
+ rn_width = 0
+
+ # Get length of print format for each column.
+ do k = 1, ncp
+ lenfmt[k] = tbcigi (colptr[k], TBL_COL_FMTLEN)
+
+ # Fill array of print formats for column names and for data.
+ call tpr_pfmt_l (colptr, lenfmt, Memc[data_fmt],
+ Memi[j_flag], ncp)
+
+ if (showhdr) {
+ # Print the \begin{document} string.
+ call tpr_beg_doc (prt_option)
+
+ # Print the default \def or \newcommand for column separators
+ # and \eol, and print the begin-table string and column names.
+ call tpr_def (prt_option, ncp, showrow)
+ call tpr_begin_tbl (prt_option, Memi[j_flag], ncp, showrow)
+ call tpr_cnames_pr_l (colptr, ncp, showrow, showunits, rn_name)
+ }
+
+ # Print each row that is to be printed.
+ linenum = 0 # initialize line counter
+ rownum = 0 # initialize get_next_number
+ stat = get_next_number (ranges, rownum) # get first row number
+ done = (stat == EOF) || (rownum > nrows)
+
+ element = 1 # not used yet
+ max_nelem = 1
+
+ while ( !done ) {
+
+ # Print a page break if appropriate.
+ call tpr_break_l (linenum, pagelength, showhdr, showunits,
+ prt_option, Memi[j_flag],
+ colptr, ncp, showrow, rn_name)
+
+ # Print a blank line if the column value has changed or if
+ # a group of lgroup lines have been printed.
+ call tpr_space (tp, s_cp, lgroup,
+ rownum, element, max_nelem, pagelength, linenum, s_flag)
+ if (s_flag == YES) {
+ call printf ("\\extline\n")
+ linenum = linenum + 1
+ # Check whether we should also print a page break.
+ call tpr_break_l (linenum, pagelength, showhdr, showunits,
+ prt_option, Memi[j_flag],
+ colptr, ncp, showrow, rn_name)
+ }
+
+ # Print % as row separator (for readability); print current row.
+ call printf ("%c\n")
+ call pargc (percent)
+ call prt_row_l (tp, colptr, Memc[data_fmt], ncp, rownum,
+ lenfmt, pagewidth, showrow, orig_row, rn_fmt, rn_width)
+ linenum = linenum + 1
+ stat = get_next_number (ranges, rownum)
+ done = (stat == EOF) || (rownum > nrows)
+ }
+
+ if (showhdr) {
+ # Print end-table string.
+ call tpr_end_tbl (prt_option)
+ }
+ if (showhdr)
+ # Write \end{document} string.
+ call tpr_end_doc (prt_option)
+
+ call sfree (sp)
+end
+
+# tpr_break_l -- print a page break
+# This routine prints the "end table" and "begin table" strings, if
+# appropriate. If pagelength is zero we're not printing page breaks
+# anyway, and if linenum is zero we've already printed the header, so
+# nothing is done. Otherwise, if linenum is zero mod pagelength
+# print a page break, and if showhdr print the column names.
+
+procedure tpr_break_l (linenum, pagelength, showhdr, showunits,
+ prt_option, just_flag,
+ colptr, ncp, showrow, rn_name)
+
+int linenum # io: number of lines of data printed
+int pagelength # i: number of data lines per page
+bool showhdr # i: print column names?
+bool showunits # i: print column units?
+char prt_option[ARB] # i: "latex" or "tex"
+int just_flag[ARB] # i: -1, 0, +1 for left, center, right just.
+pointer colptr[ARB] # i: array of column pointers
+int ncp # i: number of columns to print
+bool showrow # i: print row number?
+char rn_name[ARB] # i: column header for row number
+#--
+
+begin
+ if (pagelength > 0) {
+ if (linenum > 0) {
+ if (mod (linenum, pagelength) == 0) {
+ # Print end table, begin table, and column names.
+ call tpr_end_tbl (prt_option)
+ call tpr_begin_tbl (prt_option, just_flag, ncp,
+ showrow)
+ if (showhdr)
+ call tpr_cnames_pr_l (colptr, ncp,
+ showrow, showunits, rn_name)
+ }
+ }
+ }
+end
+
+
+# tpr_pfmt_l -- Get print formats
+# This procedure fills an array with print formats for printing the
+# column values. An array of flags specifying whether each column is
+# to be left or right justified is also returned.
+
+procedure tpr_pfmt_l (colptr, lenfmt, data_fmt, just_flag, ncp)
+
+pointer colptr[ncp] # i: array of column pointers
+int lenfmt[ncp] # i: array of lengths of print formats
+char data_fmt[SZ_FMT,ncp] # o: array of print formats for data
+int just_flag[ncp] # o: -1 or +1 for left, right justification
+int ncp # i: number of columns to print
+#--
+int cn # loop index for column number
+
+begin
+ do cn = 1, ncp { # do for each column to print
+
+ call tbcigt (colptr[cn], TBL_COL_FMT, data_fmt[1,cn], SZ_FMT)
+ if (data_fmt[2,cn] == '-')
+ just_flag[cn] = -1 # left justification
+ else
+ just_flag[cn] = 1 # right justification
+ }
+end
+
+
+
+# tpr_beg_doc -- Print begin-document strings
+# This procedure prints strings for LaTeX or for TeX that begin
+# a document. (Nothing is written for TeX.)
+
+procedure tpr_beg_doc (prt_option)
+
+char prt_option[ARB] # i: "latex" or "tex"
+
+begin
+ if (prt_option[1] == 'l') { # LaTeX
+ call printf ("\\documentstyle{article}\n")
+ call printf ("\\begin{document}\n")
+ }
+end
+
+
+
+# tpr_end_doc -- Print end-document strings
+# This procedure prints strings for LaTeX or for TeX that end
+# a document.
+
+procedure tpr_end_doc (prt_option)
+
+char prt_option[ARB] # i: "latex" or "tex"
+
+begin
+ if (prt_option[1] == 'l') # LaTeX
+ call printf ("\\end{document}\n")
+ else if (prt_option[1] == 't') # TeX
+ call printf ("\\end\n")
+end
+
+
+# tpr_def -- Print newcommand strings
+# This procedure prints strings for LaTeX or for TeX that define
+# macros for column separators and for the end-of-line string.
+#
+# Phil Hodge, 1-Apr-88 \extline added
+
+procedure tpr_def (prt_option, ncp, showrow)
+
+char prt_option[ARB] # i: "latex" or "tex"
+int ncp # i: number of columns to print
+bool showrow # i: print row number?
+#--
+int k # loop index
+char new_cmd[SHORT_STRING] # "\newcommand" or "\def"
+char n_str[SHORT_STRING] # "{\null}"
+char latex_eol[SHORT_STRING] # "\eol{\\}"
+char tex_eol[SHORT_STRING] # "\eol{\cr}"
+
+begin
+ if (prt_option[1] == 'l') # LaTeX
+ call strcpy ("\\newcommand", new_cmd, SHORT_STRING)
+ else if (prt_option[1] == 't') # TeX
+ call strcpy ("\\def", new_cmd, SHORT_STRING)
+ call strcpy ("{\\null}", n_str, SHORT_STRING)
+ call strcpy ("\\eol{\\\\}", latex_eol, SHORT_STRING)
+ call strcpy ("\\eol{\\cr}", tex_eol, SHORT_STRING)
+
+ if (showrow)
+ k = 0
+ else
+ k = 1
+
+ # Define either \colzero or \cola, depending on showrow.
+ call printf ("%s")
+ call pargstr (new_cmd)
+ call tpr_w_colsep (k)
+ call printf ("%s\n")
+ call pargstr (n_str)
+
+ # Define the rest of the column-separators, if any.
+ k = k + 1
+ while (k <= ncp) {
+ call printf ("%s")
+ call pargstr (new_cmd)
+ call tpr_w_colsep (k)
+ call printf ("{&}\n")
+ k = k + 1
+ }
+
+ # Define \eol.
+ call printf ("%s")
+ call pargstr (new_cmd)
+ if (prt_option[1] == 'l') { # LaTeX
+ call printf ("%s\n")
+ call pargstr (latex_eol)
+ } else if (prt_option[1] == 't') { # TeX
+ call printf ("%s\n")
+ call pargstr (tex_eol)
+ }
+
+ # Define \extline for writing blank lines.
+ call printf ("%s\\extline{")
+ call pargstr (new_cmd)
+ do k = 1, ncp-1
+ call printf ("&")
+ if (showrow)
+ call printf ("&")
+ call printf ("\\eol}\n")
+
+ call printf ("\n")
+end
+
+
+
+# tpr_begin_tbl -- Print begin-table string
+# This procedure prints a begin-table string for LaTeX or for TeX.
+
+procedure tpr_begin_tbl (prt_option, just_flag, ncp, showrow)
+
+char prt_option[ARB] # i: "latex" or "tex"
+int just_flag[ARB] # i: -1, 0, +1 for left, center, right just.
+int ncp # i: number of columns to print
+bool showrow # i: print row number?
+#--
+int k # loop index
+char tex_cr[SHORT_STRING] # "\cr"
+
+begin
+ if (prt_option[1] == 'l') { # LaTeX
+
+ call printf ("\\begin{tabular}{")
+ if (showrow)
+ call printf ("r") # right justify row number
+ do k = 1, ncp {
+ if (just_flag[k] == -1)
+ call printf ("l") # left justify
+ else if (just_flag[k] == 1)
+ call printf ("r") # right justify
+ else
+ call printf ("c") # center
+ }
+ call printf ("}\n")
+
+ } else if (prt_option[1] == 't') { # TeX
+
+ call strcpy ("\\cr", tex_cr, SHORT_STRING)
+
+ if (showrow) {
+ call printf ("\\halign{\\hfil#") # row number
+ call printf ("\n&\\quad")
+ } else {
+ call printf ("\\halign{")
+ }
+
+ # First column.
+ if (just_flag[1] == -1)
+ call printf ("#\\hfil") # left
+ else if (just_flag[1] == 1)
+ call printf ("\\hfil#") # right
+ else
+ call printf ("\\hfil#\\hfil") # center
+
+ do k = 2, ncp {
+ if (just_flag[k] == -1)
+ call printf ("\n&\\quad#\\hfil")
+ else if (just_flag[k] == 1)
+ call printf ("\n&\\quad\\hfil#")
+ else
+ call printf ("\n&\\quad\\hfil#\\hfil")
+ }
+ call printf ("%s\n\n") # can't use \eol here
+ call pargstr (tex_cr)
+ }
+end
+
+
+# tpr_end_tbl -- Print end-table string
+# This procedure prints an end-table string for LaTeX (or TeX).
+
+procedure tpr_end_tbl (prt_option)
+
+char prt_option[ARB] # i: "latex" or "tex"
+#--
+
+begin
+ if (prt_option[1] == 'l') # LaTeX
+ call printf ("\\end{tabular}\n\n")
+ else if (prt_option[1] == 't') # TeX
+ call printf ("}\n\n")
+end
+
+
+
+# tpr_cnames_pr_l -- Print column names
+# This procedure prints the column names followed by a blank line.
+# (TeX or LaTeX only)
+
+procedure tpr_cnames_pr_l (colptr, ncp, showrow, showunits, rn_name)
+
+pointer colptr[ncp] # i: array of column pointers
+int ncp # i: number of columns on current page
+bool showrow # i: true if row number is to be printed
+bool showunits # i: print column units?
+char rn_name[ARB] # i: column header for row number
+#--
+int cn # loop index for column number
+char colname[SZ_COLNAME] # column name
+char colunits[SZ_COLUNITS] # column units
+
+begin
+ if (showrow) {
+ call tpr_w_colsep (0)
+ call printf (rn_name)
+ }
+ do cn = 1, ncp { # do for each column on page
+ call tpr_w_colsep (cn)
+ call tbcigt (colptr[cn], TBL_COL_NAME, colname, SZ_COLNAME)
+ call printf ("%s") # trim extra blanks
+ call pargstr (colname)
+ }
+ call printf ("\\eol\n")
+
+ # Also print column units?
+ if (showunits) {
+ if (showrow) {
+ call tpr_w_colsep (0)
+ }
+ do cn = 1, ncp {
+ call tpr_w_colsep (cn)
+ call tbcigt (colptr[cn], TBL_COL_UNITS, colunits, SZ_COLUNITS)
+ call printf ("%s")
+ call pargstr (colunits)
+ }
+ call printf ("\\eol\n")
+ }
+ call printf ("\\extline\n")
+end
+
+
+# prt_row_l -- print a row
+# This procedure prints the contents of one row. This LaTeX (or TeX)
+# version differs from the plain-print version in the following ways:
+# character-string values are printed using %s so that extra blanks
+# will not be printed, the column-separators may differ from one column
+# to the next, and an end-of-line string is printed.
+
+procedure prt_row_l (tp, colptr, data_fmt, ncp, rownum,
+ lenfmt, pagewidth, showrow, orig_row, rn_fmt, rn_width)
+
+pointer tp # i: pointer to table descriptor
+pointer colptr[ncp] # i: array of pointers to column descriptors
+char data_fmt[SZ_FMT,ncp] # i: print format for each column
+int ncp # i: number of columns on current page
+int rownum # i: row number
+int lenfmt[ncp] # i: array of lengths of print formats
+int pagewidth # i: page width
+bool showrow # i: print row number?
+bool orig_row # i: show row number from underlying table?
+char rn_fmt[ARB] # i: format for printing row number
+int rn_width # i: space for printing row number
+#--
+pointer sp
+pointer cbuf # scratch for character-string buffer
+double dbuf # buffer for double-precision elements
+real rbuf # buffer for single-precision elements
+int ibuf # buffer for integer elements
+short sbuf
+bool bbuf # buffer for boolean elements
+int cn # loop index for column number
+int datatype # data type of column
+int lentotal # for determining when to print \n
+int colsep_width # space needed to print column-separator string
+int underlying_row # row number in underlying table
+int tbcigi()
+errchk tbsirow
+
+begin
+ call smark (sp)
+ call salloc (cbuf, SZ_LINE, TY_CHAR)
+
+ colsep_width = 6 # e.g. "\cola "
+
+ if (showrow) {
+ call tpr_w_colsep (0)
+ if (orig_row) {
+ call tbsirow (tp, rownum, underlying_row)
+ call printf (rn_fmt)
+ call pargi (underlying_row)
+ } else {
+ call printf (rn_fmt)
+ call pargi (rownum) # write row number
+ }
+ lentotal = colsep_width + rn_width
+ } else {
+ lentotal = 0
+ }
+
+ do cn = 1, ncp {
+
+ if (lentotal + lenfmt[cn] > pagewidth) {
+ call printf ("\n")
+ lentotal = 0
+ }
+ call tpr_w_colsep (cn) # write column-separator string
+
+ datatype = tbcigi (colptr[cn], TBL_COL_DATATYPE)
+ switch (datatype) {
+ case (TY_REAL):
+ call tbegtr (tp, colptr[cn], rownum, rbuf)
+ call printf (data_fmt[1,cn])
+ call pargr (rbuf)
+ case (TY_DOUBLE):
+ call tbegtd (tp, colptr[cn], rownum, dbuf)
+ call printf (data_fmt[1,cn])
+ call pargd (dbuf)
+ case (TY_INT):
+ call tbegti (tp, colptr[cn], rownum, ibuf)
+ call printf (data_fmt[1,cn])
+ call pargi (ibuf)
+ case (TY_SHORT):
+ call tbegts (tp, colptr[cn], rownum, sbuf)
+ call printf (data_fmt[1,cn])
+ call pargs (sbuf)
+ case (TY_BOOL):
+ call tbegtb (tp, colptr[cn], rownum, bbuf)
+ call printf (data_fmt[1,cn])
+ call pargb (bbuf)
+ default:
+ if (datatype < 0 || datatype == TY_CHAR) {
+ call tbegtt (tp, colptr[cn], rownum, Memc[cbuf], SZ_LINE)
+ call printf ("%s") # trim blanks
+ call pargstr (Memc[cbuf])
+ } else {
+ call error (1, "bad data type; table corrupted?")
+ }
+ }
+ lentotal = lentotal + colsep_width + lenfmt[cn]
+ }
+ call printf ("\\eol\n")
+
+ call sfree (sp)
+end
+
+
+# tpr_w_colsep -- Write column-separator string
+# This procedure writes a string of the form "\cola ", "\colb ", etc
+# for n = 1, 2, etc. The case n = 0 gives "\colzero " which is used
+# for the row number column.
+
+procedure tpr_w_colsep (n)
+
+int n # i: column number or zero
+#--
+string alphabet "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
+begin
+ if (n <= 0) {
+ call printf ("\\colzero ")
+ } else {
+ call printf ("\\col%c ")
+ call pargc (alphabet[n])
+ }
+end
diff --git a/pkg/utilities/nttools/tprint/tprplain.x b/pkg/utilities/nttools/tprint/tprplain.x
new file mode 100644
index 00000000..c40217d7
--- /dev/null
+++ b/pkg/utilities/nttools/tprint/tprplain.x
@@ -0,0 +1,530 @@
+include <ctype.h> # for IS_WHITE
+include <tbset.h>
+include "tprint.h"
+
+# tpr_plain_pr -- print contents of table
+# This version simply prints the table data. The corresponding procedure
+# that prints in TeX/LaTeX format is tpr_latex_pr.
+# It may be that all the columns that are to be printed will not fit
+# on one page, in which case they are printed in sections: all the rows
+# are printed for the first set of columns, then all the rows for the next
+# set, etc.
+#
+# Phil Hodge, 5-Oct-1987 Subroutine created
+# Phil Hodge, 7-Oct-1987 prt_row: use different buffer for each data type.
+# Phil Hodge, 12-Feb-1988 Include option to align columns with header
+# Phil Hodge, 30-Mar-1988 Use a column to control spacing of printout.
+# Phil Hodge, 6-Jan-1989 Call tpr_break for new page, also after tpr_cnames_pr
+# Phil Hodge, 2-Apr-1993 In prt_row, include short datatype.
+# Phil Hodge, 5-Jul-1993 Include option to print column units.
+# Phil Hodge, 16-Feb-1995 Print "#" before header lines to comment them out.
+# Phil Hodge, 26-Mar-1998 Add orig_row to calling sequence, use in prt_row;
+# remove showrow from calling sequences of
+# tpr_break and tpr_cnames_pr.
+# Phil Hodge, 18-Jan-1999 Get boolean as string, to preserve indef values.
+# Phil Hodge, 30-Mar-1999 Delete declaration of bbuf from prt_row.
+# Phil Hodge, 9-Aug-1999 Print all array elements;
+# move code for printing blank lines into prt_row;
+# change the calling sequence of tpr_space;
+# delete data_fmt and subroutine tpr_g_fmt.
+# Phil Hodge, 3-Jul-2000 In tpr_pfmt, use "%-s" format for the last column
+# on a page, if the column should be left justified.
+# Phil Hodge, 2-Nov-2000 Remove the restriction that no more than MAXCOLS
+# columns can be printed on one page.
+
+procedure tpr_plain_pr (tp, cptr, nprint, s_cp, lgroup,
+ range_string, pagewidth, pagelength,
+ showrow, orig_row, showhdr, showunits, align)
+
+pointer tp # i: pointer to table descriptor
+pointer cptr[nprint] # i: array of pointers to column descriptors
+int nprint # i: number of columns to print
+pointer s_cp # i: pointer to column to control spacing
+int lgroup # i: print blank line after this many lines
+char range_string[ARB] # i: string which gives ranges of row numbers
+int pagewidth # i: page width
+int pagelength # i: number of data lines per page
+bool showrow # i: true if row number is to be printed
+bool orig_row # i: show row number from underlying table?
+bool showhdr # i: print column names?
+bool showunits # i: print column units?
+bool align # i: override print fmt to align col & name?
+#--
+pointer sp
+pointer colptr # ptr to descriptors for columns on current page
+pointer lenfmt # ptr to lengths of print fmt for cols on page
+pointer cn_fmt # formats for printing column values
+char rn_fmt[SZ_FMT] # format for printing row numbers
+char rn_name[SZ_ROW_HDR] # row number header: "# row"
+char rn_units[SZ_ROW_HDR] # "# " printed in the line for units
+char percent # '%'
+int nrows # total number of rows in table
+int rn_width # width needed for printing row number
+int lcp # column number of leftmost column on page
+int ncp # number of columns on current page
+int rownum # row number
+int linenum # number of lines of data printed
+int ranges[3,MAX_RANGES] # ranges of row numbers
+int nvalues # returned by decode_ranges and ignored
+int stat # returned by get_next_number
+bool done # flag for terminating while loop on rows
+int decode_ranges(), get_next_number(), tbpsta()
+
+begin
+ # Allocate space for format strings for printing column names and
+ # values. Allocate arrays for pointers to column descriptors and
+ # the ascii width of each column. Allow enough space to print all
+ # columns on one page.
+ call smark (sp)
+ call salloc (cn_fmt, (SZ_FMT+1)*nprint, TY_CHAR)
+ call salloc (colptr, nprint, TY_POINTER)
+ call salloc (lenfmt, nprint, TY_POINTER)
+
+ nrows = tbpsta (tp, TBL_NROWS)
+
+ if (decode_ranges (range_string, ranges, MAX_RANGES, nvalues) != OK)
+ call error (1, "bad range of row numbers")
+
+ # rn_name, rn_units, rn_fmt and rn_width must be consistent.
+ if (showrow) {
+ # These two strings are printed above the row number
+ # in the line for column names and in the line for column units.
+ call strcpy ("# row", rn_name, SZ_ROW_HDR)
+ call strcpy ("# ", rn_units, SZ_ROW_HDR)
+ rn_width = SZ_ROW_HDR # space for printing row number
+ } else if (showhdr) {
+ call strcpy ("#", rn_name, SZ_ROW_HDR)
+ call strcpy ("#", rn_units, SZ_ROW_HDR)
+ rn_width = 1 # space for "#"
+ } else {
+ rn_name[1] = EOS # no header printed
+ rn_units[1] = EOS
+ rn_width = 0
+ }
+ percent = '%'
+ call sprintf (rn_fmt, SZ_FMT, "%c%dd") # --> %5d
+ call pargc (percent)
+ call pargi (SZ_ROW_HDR)
+
+ lcp = 1 # initialize
+ while (lcp <= nprint) { # do for each page
+
+ # Get column pointers for current page
+ call get_page (tp, cptr, lcp, nprint, pagewidth-rn_width,
+ align, showunits, Memi[colptr], Memi[lenfmt], ncp)
+
+ # Fill array of print formats.
+ call tpr_pfmt (Memi[colptr], Memi[lenfmt], align, Memc[cn_fmt], ncp)
+
+ # Print a form feed if this is not the first page and the user
+ # has requested page breaks.
+ if (lcp > 1) {
+ if (pagelength > 0)
+ call printf ("\f\n")
+ else
+ call printf ("\n")
+ }
+ # Print column names.
+ if (showhdr)
+ call tpr_cnames_pr (Memi[colptr], Memc[cn_fmt], ncp,
+ showunits, rn_name, rn_units)
+
+ # Print each row that is to be printed.
+ linenum = 0 # initialize line counter
+ rownum = 0 # initialize get_next_number
+ stat = get_next_number (ranges, rownum) # get first row number
+ done = (stat == EOF) || (rownum > nrows)
+
+ while ( !done ) {
+
+ # Print values in current row.
+ call prt_row (tp, Memi[colptr], Memc[cn_fmt], ncp,
+ linenum, pagelength, s_cp, lgroup,
+ rn_fmt, rn_name, rn_units,
+ rownum, showrow, orig_row, showhdr, showunits)
+
+ # Get next row number.
+ stat = get_next_number (ranges, rownum)
+ done = (stat == EOF) || (rownum > nrows)
+ }
+
+ lcp = lcp + ncp # next set of columns to be printed
+ }
+ call sfree (sp)
+end
+
+# tpr_break -- print a page break
+# This routine prints a form feed ('\f') if appropriate. If pagelength
+# is zero we're not printing page breaks anyway, and if linenum is zero
+# we've already printed the header, so nothing is done. Otherwise,
+# if linenum is zero mod pagelength print a page break, and if showhdr
+# print the header.
+
+procedure tpr_break (linenum, pagelength, showhdr, showunits,
+ colptr, cn_fmt, ncp, rn_name, rn_units)
+
+int linenum # io: number of lines of data printed
+int pagelength # i: number of data lines per page
+bool showhdr # i: print column names?
+bool showunits # i: also print column units?
+pointer colptr[ARB] # i: array of column pointers
+char cn_fmt[SZ_FMT,ARB] # i: array of print formats
+int ncp # i: number of columns on current page
+char rn_name[ARB] # i: column header for row number
+char rn_units[ARB] # i: printed below rn_name
+#--
+
+begin
+ if (pagelength > 0) {
+ if (linenum > 0) {
+ if (mod (linenum, pagelength) == 0) {
+ call printf ("\f\n")
+ if (showhdr) # print column names
+ call tpr_cnames_pr (colptr, cn_fmt, ncp,
+ showunits, rn_name, rn_units)
+ }
+ }
+ }
+end
+
+
+# get_page -- get columns for page
+# This procedure determines which columns will fit on the current page.
+# Each column is assumed to begin with a column separator which is a
+# single space.
+
+procedure get_page (tp, cptr, lcp, nprint, pagewidth, align,
+ showunits, colptr, lenfmt, ncp)
+
+pointer tp # i: pointer to table descriptor
+pointer cptr[nprint] # i: array of pointers to all column descr
+int lcp # i: column number of leftmost column on page
+int nprint # i: number of columns to print
+int pagewidth # i: page width available for writing
+bool align # i: override print fmt to align col & name?
+bool showunits # i: also print column units?
+pointer colptr[ARB] # o: pointers for columns on current page
+int lenfmt[ARB] # o: length of print format for each col
+int ncp # o: number of columns on current page
+#--
+char colname[SZ_COLNAME] # column name for error message
+int lentotal # sum of lenfmt plus a space for each column
+int nextc # column counter
+int tpr_lenfmt()
+
+begin
+ # Assume we can print at least one column, truncated if necessary.
+ ncp = 1
+ colptr[1] = cptr[lcp]
+ # Get width for printing column.
+ lenfmt[1] = tpr_lenfmt (colptr[1], align, showunits)
+ if (lenfmt[1] > pagewidth-1) {
+ call tbcigt (colptr[1], TBL_COL_NAME, colname, SZ_COLNAME)
+ call eprintf ("caution: column %s will be truncated\n")
+ call pargstr (colname)
+ lenfmt[1] = pagewidth-1
+ }
+
+ lentotal = lenfmt[1] + 1 # add one for leading space
+
+ # The loop continuation conditions are:
+ # the columns fit on the page,
+ # there are still columns that have not been included.
+ while (lentotal < pagewidth && lcp+ncp-1 < nprint) {
+ nextc = ncp + 1
+ colptr[nextc] = cptr[lcp+nextc-1]
+ # get lenfmt
+ lenfmt[nextc] = tpr_lenfmt (colptr[nextc], align, showunits)
+ lentotal = lentotal + lenfmt[nextc] + 1 # one for leading space
+ if (lentotal <= pagewidth)
+ ncp = nextc # = ncp + 1
+ }
+end
+
+
+
+# tpr_lenfmt -- get length of print format
+# This function returns the length of the print format for a column.
+# If align is true then the column name will be gotten, and the length
+# of the print format that is returned will be at least as large as
+# the length of the column name. The length will also be at least five,
+# since that is the length of the word INDEF.
+
+int procedure tpr_lenfmt (cptr, align, showunits)
+
+pointer cptr # i: pointer to column descriptor
+bool align # i: true ==> may increase length of print fmt
+bool showunits # i: also print column units?
+#--
+char colname[SZ_COLNAME] # name of column
+char colunits[SZ_COLUNITS] # column units
+int lenfmt # length of print format
+int len_name # length of column name
+int len_units # length of column units
+int tbcigi(), strlen()
+
+begin
+ lenfmt = tbcigi (cptr, TBL_COL_FMTLEN)
+
+ if ( align ) {
+
+ call tbcigt (cptr, TBL_COL_NAME, colname, SZ_COLNAME)
+ len_name = strlen (colname)
+
+ # Length >= length of column name or the word "INDEF".
+ lenfmt = max (lenfmt, len_name, 5)
+
+ if (showunits) {
+ call tbcigt (cptr, TBL_COL_UNITS, colunits, SZ_COLUNITS)
+ len_units = strlen (colunits)
+ lenfmt = max (lenfmt, len_units)
+ }
+ }
+ return (lenfmt)
+end
+
+
+
+# tpr_pfmt -- Get print formats
+# This procedure fills an array with print formats of the form %ws.
+# These can be used for printing the column names, units and data values.
+
+procedure tpr_pfmt (colptr, lenfmt, align, cn_fmt, ncp)
+
+pointer colptr[ncp] # i: array of column pointers
+int lenfmt[ncp] # i: array of lengths of print formats
+bool align # i: override print fmt to align col & name?
+char cn_fmt[SZ_FMT,ncp] # o: array of print formats
+int ncp # i: number of columns on current page
+#--
+char fmt[SZ_COLFMT] # unmodified print format as gotten from table
+int cn # loop index for column number
+
+begin
+ do cn = 1, ncp { # do for each column on page
+
+ # Get print format for current column.
+ call tbcigt (colptr[cn], TBL_COL_FMT, fmt, SZ_COLFMT)
+
+ cn_fmt[1,cn] = '%'
+ if (fmt[2] == '-') { # left justification
+ if (cn == ncp) {
+ call sprintf (cn_fmt[2,cn], SZ_FMT-1, "-s")
+ } else {
+ call sprintf (cn_fmt[2,cn], SZ_FMT-1, "-%ds")
+ call pargi (lenfmt[cn])
+ }
+ } else { # right justification
+ call sprintf (cn_fmt[2,cn], SZ_FMT-1, "%ds")
+ call pargi (lenfmt[cn])
+ }
+ }
+end
+
+
+# tpr_cnames_pr -- Print column names
+# This procedure prints the column names and units and an extra blank line.
+# A comment character ("#") is printed at the beginning of the line; this
+# is new as of 1995 Feb 16.
+
+procedure tpr_cnames_pr (colptr, cn_fmt, ncp,
+ showunits, rn_name, rn_units)
+
+pointer colptr[ncp] # i: array of column pointers
+char cn_fmt[SZ_FMT,ncp] # i: array of print formats
+int ncp # i: number of columns on current page
+bool showunits # i: also print column units?
+char rn_name[ARB] # i: column header for row number
+char rn_units[ARB] # i: printed below rn_name
+#--
+char colname[SZ_COLNAME] # column name
+char colunits[SZ_COLUNITS] # column units
+int cn # loop index for column number
+
+begin
+ call printf (rn_name) # "# row" or "#"
+
+ do cn = 1, ncp { # do for each column on page
+ call printf (" ")
+ call tbcigt (colptr[cn], TBL_COL_NAME, colname, SZ_COLNAME)
+ call printf (cn_fmt[1,cn])
+ call pargstr (colname)
+ }
+ call printf ("\n")
+
+ # Also print column units?
+ if (showunits) {
+ call printf (rn_units) # "# " or "#"
+ do cn = 1, ncp {
+ call printf (" ")
+ call tbcigt (colptr[cn], TBL_COL_UNITS, colunits, SZ_COLUNITS)
+ call printf (cn_fmt[1,cn])
+ call pargstr (colunits)
+ }
+ call printf ("\n")
+ }
+
+ call printf ("\n")
+end
+
+
+# prt_row -- print a row
+# This procedure prints the contents of one row.
+
+procedure prt_row (tp, colptr, cn_fmt, ncp,
+ linenum, pagelength, s_cp, lgroup,
+ rn_fmt, rn_name, rn_units,
+ rownum, showrow, orig_row, showhdr, showunits)
+
+pointer tp # i: pointer to table descriptor
+pointer colptr[ncp] # i: array of pointers to column descriptors
+char cn_fmt[SZ_FMT,ncp] # i: array of print formats
+int ncp # i: number of columns on current page
+int linenum # io: number of lines of data printed
+int pagelength # i: number of data lines per page
+pointer s_cp # i: pointer to column to control spacing
+int lgroup # i: print blank line after this many lines
+char rn_fmt[ARB] # i: format for printing row number
+char rn_name[ARB] # i: row number header: "# row"
+char rn_units[ARB] # i: "# " printed in the line for units
+int rownum # i: row number
+bool showrow # i: print row number?
+bool orig_row # i: show row number from underlying table?
+bool showhdr # i: was a header printed?
+bool showunits # i: print column units?
+#--
+pointer sp
+pointer cbuf # scratch for character-string buffer
+pointer nelem # array length for each column
+int max_nelem # maximum of array lengths
+bool has_arrays # true if any column contains arrays
+bool has_scalars # true if not all columns contain arrays
+int cn # loop index for column number
+int element # loop index for array element number
+int underlying_row # row number in underlying table
+int ip # first non-blank character in cbuf
+int s_flag # YES if we should print a line for spacing
+int tbcigi(), tbagtt()
+errchk tbsirow
+
+begin
+ call smark (sp)
+ call salloc (cbuf, SZ_LINE, TY_CHAR)
+ call salloc (nelem, ncp, TY_INT)
+
+ # Get the array length for each column.
+ max_nelem = 1 # initial values
+ if (showrow)
+ has_scalars = true # row number is a scalar
+ else
+ has_scalars = false
+
+ do cn = 1, ncp {
+ Memi[nelem+cn-1] = tbcigi (colptr[cn], TBL_COL_LENDATA)
+ if (Memi[nelem+cn-1] > max_nelem)
+ max_nelem = Memi[nelem+cn-1]
+ if (Memi[nelem+cn-1] == 1)
+ has_scalars = true
+ }
+ has_arrays = (max_nelem > 1)
+
+ # If all columns contain arrays, print a blank line as a separator.
+ if (!has_scalars && rownum > 1)
+ call printf ("\n")
+
+ # Loop over the number of elements in the longest array.
+ do element = 1, max_nelem {
+
+ # Print a page break if appropriate.
+ call tpr_break (linenum, pagelength, showhdr, showunits,
+ colptr, cn_fmt, ncp, rn_name, rn_units)
+
+ # Print a blank line if the value in the column has changed
+ # or if a group of lgroup lines has been printed.
+ call tpr_space (tp, s_cp, lgroup,
+ rownum, element, max_nelem, pagelength, linenum, s_flag)
+ if (s_flag == YES) {
+ call printf ("\n")
+ linenum = linenum + 1
+ # Check whether we should also print a page break.
+ call tpr_break (linenum, pagelength, showhdr, showunits,
+ colptr, cn_fmt, ncp, rn_name, rn_units)
+ }
+
+ if (showrow) {
+ if (element == 1) {
+ if (orig_row) {
+ call tbsirow (tp, rownum, underlying_row)
+ call printf (rn_fmt)
+ call pargi (underlying_row)
+ } else {
+ call printf (rn_fmt)
+ call pargi (rownum)
+ }
+ } else {
+ call printf (" ") # SZ_ROW_HDR blanks
+ }
+ } else if (showhdr) {
+ # Corresponds to the "#" at the beginning of header lines.
+ call printf (" ")
+ }
+
+ do cn = 1, ncp {
+
+ # Even if no row number is printed, start with a space.
+ call printf (" ") # space between columns
+
+ # Does the current column contain arrays?
+ if (Memi[nelem+cn-1] > 1) {
+
+ if (element <= Memi[nelem+cn-1]) {
+ if (tbagtt (tp, colptr[cn], rownum,
+ Memc[cbuf], SZ_LINE, element, 1) < 1)
+ call error (1, "can't read array element")
+ call tpr_noblank (Memc[cbuf], ip)
+ } else {
+ Memc[cbuf] = EOS
+ ip = 1
+ }
+ call printf (cn_fmt[1,cn])
+ call pargstr (Memc[cbuf+ip-1])
+
+ } else if (element == 1) {
+
+ # This is a scalar column.
+ call tbegtt (tp, colptr[cn], rownum, Memc[cbuf], SZ_LINE)
+ call tpr_noblank (Memc[cbuf], ip)
+ call printf (cn_fmt[1,cn])
+ call pargstr (Memc[cbuf+ip-1])
+
+ } else {
+
+ # Print a blank field for a scalar column to match array
+ # element > 1 for array column(s).
+ call printf (cn_fmt[1,cn])
+ call pargstr ("")
+ }
+ }
+ call printf ("\n")
+ linenum = linenum + 1
+ }
+ call sfree (sp)
+end
+
+procedure tpr_noblank (buf, ip)
+
+char buf[ARB] # io: input string (trailing blanks will be truncted)
+int ip # o: first non-blank character in buf
+#--
+int strlen()
+
+begin
+ ip = strlen (buf)
+ while (ip >= 1 && IS_WHITE(buf[ip])) { # trim trailing blanks
+ buf[ip] = EOS
+ ip = ip - 1
+ }
+ ip = 1
+ while (IS_WHITE(buf[ip])) # trim leading blanks
+ ip = ip + 1
+end
diff --git a/pkg/utilities/nttools/tproduct.par b/pkg/utilities/nttools/tproduct.par
new file mode 100644
index 00000000..4159aac9
--- /dev/null
+++ b/pkg/utilities/nttools/tproduct.par
@@ -0,0 +1,4 @@
+intable1,f,a,,,,the first input table
+intable2,f,a,,,,the second input table
+outtable,s,a,,,,the output table
+mode,s,h,"a",,,
diff --git a/pkg/utilities/nttools/tproduct/mkpkg b/pkg/utilities/nttools/tproduct/mkpkg
new file mode 100644
index 00000000..408be9e5
--- /dev/null
+++ b/pkg/utilities/nttools/tproduct/mkpkg
@@ -0,0 +1,11 @@
+# Update the tproduct application code in the ttools package library
+# Author: B.Simon, 25-NOV-1987
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ tproduct.x <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/tproduct/tproduct.x b/pkg/utilities/nttools/tproduct/tproduct.x
new file mode 100644
index 00000000..e9ec3ba8
--- /dev/null
+++ b/pkg/utilities/nttools/tproduct/tproduct.x
@@ -0,0 +1,113 @@
+include <tbset.h>
+
+# TPRODUCT -- Form the cartesian product of two tables
+#
+# B.Simon 05-Nov-1987 First Code
+# B.Simon 31-Mar-1992 Set output table type from input tables
+# Phil Hodge 8-Apr-1999 Call tbfpri.
+
+procedure t_product()
+
+pointer intable1 # Names of the first table to be joined
+pointer intable2 # Names of the second table to be joined
+pointer outtable # Name of output table
+#--
+int idx, jdx, kdx, icol, ncol1, ncol2, nrow1, nrow2, numcol, type1, type2
+int phu_copied # set by tbfpri and ignored
+int colnum[1], datatype[1], lendata[1], lenfmt[1]
+pointer sp, tp1, tp2, otp, icp, ocp, oldcol, newcol
+pointer colname, colunits, colfmt
+
+int tbpsta(), tbcnum()
+pointer tbtopn()
+
+begin
+ # Allocate stack memory for strings
+
+ call smark (sp)
+ call salloc (intable1, SZ_FNAME, TY_CHAR)
+ call salloc (intable2, SZ_FNAME, TY_CHAR)
+ call salloc (outtable, SZ_FNAME, TY_CHAR)
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+ call salloc (colunits, SZ_COLUNITS, TY_CHAR)
+ call salloc (colfmt, SZ_COLFMT, TY_CHAR)
+
+ # Read the task parameters
+
+ call clgstr ("intable1", Memc[intable1], SZ_FNAME)
+ call clgstr ("intable2", Memc[intable2], SZ_FNAME)
+ call clgstr ("outtable", Memc[outtable], SZ_FNAME)
+
+ # Open the tables
+
+ tp1 = tbtopn (Memc[intable1], READ_ONLY, NULL)
+ tp2 = tbtopn (Memc[intable2], READ_ONLY, NULL)
+ call tbfpri (Memc[intable1], Memc[outtable], phu_copied)
+ otp = tbtopn (Memc[outtable], NEW_FILE, NULL)
+
+ # Set type of output table
+
+ type1 = tbpsta (tp1, TBL_WHTYPE)
+ type2 = tbpsta (tp2, TBL_WHTYPE)
+ if (type1 == type2)
+ call tbpset (otp, TBL_WHTYPE, type1)
+
+ # Get the number of columns and allocate arrays to hold column pointers
+
+ ncol1 = tbpsta (tp1, TBL_NCOLS)
+ ncol2 = tbpsta (tp2, TBL_NCOLS)
+ nrow1 = tbpsta (tp1, TBL_NROWS)
+ nrow2 = tbpsta (tp2, TBL_NROWS)
+
+ numcol = ncol1 + ncol2
+ call malloc (oldcol, numcol, TY_INT)
+ call malloc (newcol, numcol, TY_INT)
+
+ # Copy column pointers to old column array.
+
+ do icol = 1, ncol1
+ Memi[oldcol+icol-1] = tbcnum (tp1, icol)
+
+ do icol = 1, ncol2
+ Memi[oldcol+ncol1+icol-1] = tbcnum (tp2, icol)
+
+ # Copy column information from the input tables to the output table
+
+ do icol = 1, numcol {
+ icp = Memi[oldcol+icol-1]
+ call tbcinf (icp, colnum, Memc[colname], Memc[colunits],
+ Memc[colfmt], datatype[1], lendata[1], lenfmt[1])
+ call newcolnam (numcol, Memi[oldcol], icol,
+ Memc[colname], SZ_COLNAME)
+ call tbcdef (otp, ocp, Memc[colname], Memc[colunits], Memc[colfmt],
+ datatype[1], lendata[1], 1)
+ Memi[newcol+icol-1] = ocp
+ }
+
+ # Copy the table columns a row at a time
+
+ call tbtcre (otp)
+ call tbhcal (tp2, otp)
+ call tbhcal (tp1, otp)
+
+ kdx = 0
+ do idx = 1, nrow1 {
+ do jdx = 1, nrow2 {
+ kdx = kdx + 1
+ call tbrcsc (tp1, otp, Memi[oldcol], Memi[newcol],
+ idx, kdx, ncol1)
+ call tbrcsc (tp2, otp, Memi[oldcol+ncol1], Memi[newcol+ncol1],
+ jdx, kdx, ncol2)
+ }
+ }
+
+ # Close the tables and free dynamic memory
+
+ call tbtclo (tp1)
+ call tbtclo (tp2)
+ call tbtclo (otp)
+
+ call mfree (oldcol, TY_INT)
+ call mfree (newcol, TY_INT)
+
+end
diff --git a/pkg/utilities/nttools/tproject.par b/pkg/utilities/nttools/tproject.par
new file mode 100644
index 00000000..4edb65b2
--- /dev/null
+++ b/pkg/utilities/nttools/tproject.par
@@ -0,0 +1,5 @@
+intable,s,a,,,,"Input tables"
+outtable,s,a,,,,"Output tables"
+columns,s,a,,,,"Column names"
+uniq,b,h,no,,,"Unique rows?"
+mode,s,h,"a",,,
diff --git a/pkg/utilities/nttools/tproject/mkpkg b/pkg/utilities/nttools/tproject/mkpkg
new file mode 100644
index 00000000..f7c30ad4
--- /dev/null
+++ b/pkg/utilities/nttools/tproject/mkpkg
@@ -0,0 +1,13 @@
+# Update the tproject application code in the ttools package library
+# Author: B.Simon, 25-NOV-1987
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ nextuniq.x <tbset.h>
+ tproject.x <tbset.h>
+ wproject.x <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/tproject/nextuniq.x b/pkg/utilities/nttools/tproject/nextuniq.x
new file mode 100644
index 00000000..2a2b8e8d
--- /dev/null
+++ b/pkg/utilities/nttools/tproject/nextuniq.x
@@ -0,0 +1,39 @@
+include <tbset.h>
+
+# NEXTUNIQ -- Retrieve the next unique row from a table
+
+procedure nextuniq (tp, numptr, colptr, irow)
+
+pointer tp # i: Table descriptor
+int numptr # i: Number of column pointers
+pointer colptr[ARB] # i: Array of column pointers
+int irow # u: Current unique row
+#--
+bool fold
+int jrow, krow, nrow
+
+data fold / false /
+
+int tbpsta(), tbrcmp()
+
+begin
+ # Get number of rows in table
+
+ nrow = tbpsta (tp, TBL_NROWS)
+
+ # Loop until a row that does not match the preceding rows is found
+
+ for (jrow = irow+1; jrow <= nrow; jrow = jrow + 1) {
+ for (krow = 1; krow < jrow; krow = krow + 1) {
+ if (tbrcmp (tp, numptr, colptr, fold, jrow, krow) == 0)
+ break
+ }
+
+ if (krow == jrow)
+ break
+ }
+
+ # Set irow to the first row that does not match any preceding row
+
+ irow = jrow
+end
diff --git a/pkg/utilities/nttools/tproject/tproject.x b/pkg/utilities/nttools/tproject/tproject.x
new file mode 100644
index 00000000..6f74e272
--- /dev/null
+++ b/pkg/utilities/nttools/tproject/tproject.x
@@ -0,0 +1,100 @@
+include <fset.h> # for F_REDIR
+include <tbset.h>
+
+# T_PROJECT -- Create a new table from selected columns of an old table
+#
+# B.Simon 20-Oct-1987 First Code
+# Phil Hodge 07-Sep-1988 Change parameter names for tables.
+# B.Simon 31-Mar-1992 Set output table type from input table
+# Phil Hodge 4-Oct-1995 Use table name template routines tbnopenp, etc.
+# Phil Hodge 8-Apr-1999 Call tbfpri.
+# B.Simon 30-Apr-1999 Replace call to unique with nextuniq
+# Phil Hodge 9-Jun-1999 Set input/output to STDIN/STDOUT if redirected.
+
+procedure t_project()
+
+pointer ilist # Input table name template
+pointer olist # Output table name template
+pointer columns # Table column template
+bool uniq # Should output rows be unique?
+#--
+int junk, numcol, numptr, type
+int phu_copied # set by tbfpri and ignored
+pointer sp, itp, otp, intable, outtable, colptr
+
+string nomatch "Number of input tables must match output tables"
+string notfound "Column(s) not found in table"
+
+bool clgetb()
+int fstati()
+int tbnget(), tbnlen(), tbpsta()
+pointer tbtopn(), tbnopenp(), tbnopen()
+
+begin
+ # Allocate stack memory for strings
+
+ call smark (sp)
+ call salloc (intable, SZ_FNAME, TY_CHAR)
+ call salloc (outtable, SZ_FNAME, TY_CHAR)
+ call salloc (columns, SZ_LINE, TY_CHAR)
+
+ # Read the task parameters
+
+ if (fstati (STDIN, F_REDIR) == YES)
+ ilist = tbnopen ("STDIN")
+ else
+ ilist = tbnopenp ("intable")
+
+ if (fstati (STDOUT, F_REDIR) == YES)
+ olist = tbnopen ("STDOUT")
+ else
+ olist = tbnopenp ("outtable")
+
+ call clgstr ("columns", Memc[columns], SZ_LINE)
+ uniq = clgetb ("uniq")
+
+ # Loop over all table names in the input file name template
+
+ if (tbnlen (ilist) != tbnlen (olist))
+ call error (1, nomatch)
+
+ while (tbnget (ilist, Memc[intable], SZ_FNAME) != EOF) {
+
+ junk = tbnget (olist, Memc[outtable], SZ_FNAME)
+
+ # Open the tables and set output table type
+
+ itp = tbtopn (Memc[intable], READ_ONLY, NULL)
+ call tbfpri (Memc[intable], Memc[outtable], phu_copied)
+ otp = tbtopn (Memc[outtable], NEW_FILE, NULL)
+
+ type = tbpsta (itp, TBL_WHTYPE)
+ call tbpset (otp, TBL_WHTYPE, type)
+
+ # Create an array of column pointers from the column template
+
+ numcol = tbpsta (itp, TBL_NCOLS)
+ call malloc (colptr, numcol, TY_INT)
+
+ call tctexp (itp, Memc[columns], numcol, numptr, Memi[colptr])
+
+ if (numptr == 0)
+ call error (1, notfound)
+
+ # Copy header and selected columns to output table
+
+ call wproject (itp, otp, numptr, Memi[colptr], uniq)
+
+ # Close the tables and free dynamic memory
+
+ call tbtclo (itp)
+ call tbtclo (otp)
+ call mfree (colptr, TY_INT)
+ }
+
+ # Close the filename template lists
+
+ call tbnclose (ilist)
+ call tbnclose (olist)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tproject/wproject.x b/pkg/utilities/nttools/tproject/wproject.x
new file mode 100644
index 00000000..176032ab
--- /dev/null
+++ b/pkg/utilities/nttools/tproject/wproject.x
@@ -0,0 +1,64 @@
+include <tbset.h>
+
+# WPROJECT -- Copy selected columns and rows to output table
+#
+# B.Simon 19-Oct-87 First Code
+# B.Simon 30-Apr-1999 Replace call to unique with nextuniq
+
+procedure wproject (itp, otp, numptr, colptr, uniq)
+
+pointer itp # i: Input table descriptor
+pointer otp # i: Output table descriptor
+int numptr # i: Number of column pointers
+pointer colptr[ARB] # i: Array of column pointers
+bool uniq # i: Only output unique rows?
+#--
+int iptr, irow, jrow, nrow
+int colnum[1], datatype[1], lendata[1], lenfmt[1]
+pointer sp, ocp, newcol, colname, colunits, colfmt
+
+int tbpsta()
+
+begin
+ # Set up arrays in dynamic memory
+
+ call smark (sp)
+ call salloc (newcol, numptr, TY_INT)
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+ call salloc (colunits, SZ_COLUNITS, TY_CHAR)
+ call salloc (colfmt, SZ_COLFMT, TY_CHAR)
+
+
+ # Copy column information from the input table to the output table
+
+ do iptr = 1, numptr {
+ call tbcinf (colptr[iptr], colnum, Memc[colname], Memc[colunits],
+ Memc[colfmt], datatype[1], lendata[1], lenfmt[1])
+ call tbcdef (otp, ocp, Memc[colname], Memc[colunits], Memc[colfmt],
+ datatype[1], lendata[1], 1)
+ Memi[newcol+iptr-1] = ocp
+ }
+
+ # Copy the table columns a row at a time
+
+ call tbtcre (otp)
+ call tbhcal (itp, otp)
+
+ irow = 1
+ jrow = 1
+ nrow = tbpsta (itp, TBL_NROWS)
+
+ while (irow <= nrow) {
+ call tbrcsc (itp, otp, colptr, Memi[newcol], irow, jrow, numptr)
+
+ if (uniq) {
+ call nextuniq (itp, numptr, colptr, irow)
+ } else {
+ irow = irow + 1
+ }
+
+ jrow = jrow + 1
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tquery.par b/pkg/utilities/nttools/tquery.par
new file mode 100644
index 00000000..927b5872
--- /dev/null
+++ b/pkg/utilities/nttools/tquery.par
@@ -0,0 +1,9 @@
+intable,s,a,,,,"Input tables"
+outtable,s,a,,,,"Output tables"
+expr,s,a," ",,,"Expression used for selection"
+columns,s,a," ",,,"Column names"
+sort,s,a," ",,,"Columns to sort on"
+uniq,b,h,no,,,"Unique rows?"
+ascend,b,h,yes,,,"Ascending order?"
+casesens,b,h,yes,,,"Case sensitive sort?"
+mode,s,h,"a",,,
diff --git a/pkg/utilities/nttools/tquery/doquery.x b/pkg/utilities/nttools/tquery/doquery.x
new file mode 100644
index 00000000..8dfc4cd4
--- /dev/null
+++ b/pkg/utilities/nttools/tquery/doquery.x
@@ -0,0 +1,72 @@
+define SYNTAX 1
+
+# DOQUERY -- Perform a query on a table and return row and column arrays
+#
+# B.Simon 18-Dec-1987 First Code
+# B.Simon 10-Aug-1992 Fixed calling sequence to tbl_sort
+# Phil Hodge 18-Aug-2003 Call select before calling unique.
+
+procedure doquery (tp, expr, columns, sort, uniq, ascend, casesens,
+ numcol, colptr, nindex, index)
+
+int tp # i: Input table descriptor
+char expr[ARB] # i: Expression used to select rows
+char columns[ARB] # i: Table column template
+char sort[ARB] # i: Sort columns template
+bool uniq # i: Should output rows be unique?
+bool ascend # i: Ascending sort flag
+bool casesens # i: Case sensitivity flag
+int numcol # io: Number of column pointers
+pointer colptr[ARB] # io: Array of column pointers
+int nindex # io: Number of row indices
+int index[ARB] # io: Array of row indices
+#--
+int numptr, numsort
+pointer sortptr
+
+string nocolumn "Column names not found in table"
+string nosort "Sort column not found in table"
+
+bool isblank()
+
+begin
+
+ # Create an array of column pointers from the column template
+
+ call tctexp (tp, columns, numcol, numptr, colptr)
+
+ if (numptr == 0)
+ call error (SYNTAX, nocolumn)
+
+ # Select rows according to expression
+
+ if (! isblank(expr)) {
+ call select (tp, expr, nindex, index)
+ }
+
+ # Remove duplicate rows from table
+
+ if (uniq)
+ call unique (tp, numptr, colptr, nindex, index)
+
+ # Sort the array of indices
+
+ if (! isblank(sort)) {
+
+ # Create an array of sort column pointers from the sort template
+
+ call malloc (sortptr, numcol, TY_INT)
+ call tctexp (tp, sort, numcol, numsort, Memi[sortptr])
+
+ if (numsort == 0)
+ call error (SYNTAX, nosort)
+
+ call tbl_sort (ascend, casesens, tp, numsort, Memi[sortptr],
+ nindex, index)
+
+ call mfree (sortptr, TY_INT)
+ }
+
+ numcol = numptr
+
+end
diff --git a/pkg/utilities/nttools/tquery/mkpkg b/pkg/utilities/nttools/tquery/mkpkg
new file mode 100644
index 00000000..ca5773d7
--- /dev/null
+++ b/pkg/utilities/nttools/tquery/mkpkg
@@ -0,0 +1,13 @@
+# Update the tquery application code in the ttools package library
+# Author: B.Simon, 21-DEC-87
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ doquery.x
+ tquery.x <tbset.h>
+ wquery.x <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/tquery/tquery.x b/pkg/utilities/nttools/tquery/tquery.x
new file mode 100644
index 00000000..b7fc91b4
--- /dev/null
+++ b/pkg/utilities/nttools/tquery/tquery.x
@@ -0,0 +1,113 @@
+include <fset.h> # to check for I/O redirection
+include <tbset.h>
+
+define SYNTAX 1
+
+# TQUERY -- Create a new table from selected rows and columns of an old table
+#
+# B.Simon 18-Dec-1987 First Code
+# Phil Hodge 07-Sep-1988 Change parameter names for tables.
+# B.Simon 31-Mar-1992 Set output table type from input table
+# Phil Hodge 4-Oct-1995 Use table name template routines tbnopenp, etc.
+# Phil Hodge 8-Apr-1999 Call tbfpri.
+# Phil Hodge 9-Jun-1999 Set input/output to STDIN/STDOUT if redirected.
+
+procedure t_tquery()
+
+pointer ilist # Input table name template
+pointer olist # Output table name template
+pointer expr # Expression used to select rows
+pointer columns # Table column template
+pointer sort # Sort columns template
+bool uniq # Should output rows be unique?
+bool ascend # Ascending sort flag
+bool casesens # Case sensitivity flag
+#--
+int junk, nindex, numcol, type
+int phu_copied # set by tbfpri and ignored
+pointer sp, itp, otp, intable, outtable, index, colptr
+
+string nomatch "Number of input tables must match output tables"
+
+bool clgetb()
+int fstati()
+int tbnget(), tbnlen(), tbpsta()
+pointer tbtopn(), tbnopenp(), tbnopen()
+
+begin
+ # Allocate stack memory for strings
+
+ call smark (sp)
+ call salloc (intable, SZ_FNAME, TY_CHAR)
+ call salloc (outtable, SZ_FNAME, TY_CHAR)
+ call salloc (expr, SZ_LINE, TY_CHAR)
+ call salloc (columns, SZ_LINE, TY_CHAR)
+ call salloc (sort, SZ_LINE, TY_CHAR)
+
+ # Read the task parameters
+
+ if (fstati (STDIN, F_REDIR) == YES)
+ ilist = tbnopen ("STDIN")
+ else
+ ilist = tbnopenp ("intable")
+
+ if (fstati (STDOUT, F_REDIR) == YES)
+ olist = tbnopen ("STDOUT")
+ else
+ olist = tbnopenp ("outtable")
+
+ call clgstr ("expr", Memc[expr], SZ_LINE)
+ call clgstr ("columns", Memc[columns], SZ_LINE)
+ call clgstr ("sort", Memc[sort], SZ_LINE)
+ uniq = clgetb ("uniq")
+ ascend = clgetb ("ascend")
+ casesens = clgetb ("casesens")
+
+ # Loop over all table names in the input file name template
+
+ if (tbnlen (ilist) != tbnlen (olist))
+ call error (SYNTAX, nomatch)
+
+ while (tbnget (ilist, Memc[intable], SZ_FNAME) != EOF) {
+
+ junk = tbnget (olist, Memc[outtable], SZ_FNAME)
+
+ # Open the tables and set output table type
+
+ itp = tbtopn (Memc[intable], READ_ONLY, NULL)
+ call tbfpri (Memc[intable], Memc[outtable], phu_copied)
+ otp = tbtopn (Memc[outtable], NEW_FILE, NULL)
+
+ type = tbpsta (itp, TBL_WHTYPE)
+ call tbpset (otp, TBL_WHTYPE, type)
+
+ # Create index arrays
+
+ call allrows (itp, nindex, index)
+ call allcols (itp, numcol, colptr)
+
+ # Do the query, returning an array of column pointers
+ # and row indices
+
+ call doquery (itp, Memc[expr], Memc[columns], Memc[sort],
+ uniq, ascend, casesens,
+ numcol, Memi[colptr], nindex, Memi[index])
+
+ # Copy header and selected rows and columns to output table
+
+ call wquery (itp, otp, numcol, Memi[colptr], nindex, Memi[index])
+
+ # Close the tables and free dynamic memory
+
+ call tbtclo (itp)
+ call tbtclo (otp)
+ call mfree (colptr, TY_INT)
+ call mfree (index, TY_INT)
+ }
+
+ # Close the filename template lists
+
+ call tbnclose (ilist)
+ call tbnclose (olist)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tquery/wquery.x b/pkg/utilities/nttools/tquery/wquery.x
new file mode 100644
index 00000000..33cc25ff
--- /dev/null
+++ b/pkg/utilities/nttools/tquery/wquery.x
@@ -0,0 +1,50 @@
+include <tbset.h>
+
+# WQUERY -- Copy selected columns and rows to output table
+#
+# B.Simon 19-Oct-87 First Code
+
+procedure wquery (itp, otp, numcol, colptr, nindex, index)
+
+pointer itp # i: Input table descriptor
+pointer otp # i: Output table descriptor
+int numcol # i: Number of column pointers
+pointer colptr[ARB] # i: Array of column pointers
+int nindex # i: Size of index array
+int index[ARB] # i: Array of row indices
+#--
+int iptr, idx, jdx
+int colnum[1], datatype[1], lendata[1], lenfmt[1]
+pointer sp, ocp, newcol, colname, colunits, colfmt
+
+begin
+ # Set up arrays in dynamic memory
+
+ call smark (sp)
+ call salloc (newcol, numcol, TY_INT)
+ call salloc (colname, SZ_COLNAME, TY_CHAR)
+ call salloc (colunits, SZ_COLUNITS, TY_CHAR)
+ call salloc (colfmt, SZ_COLFMT, TY_CHAR)
+
+
+ # Copy column information from the input table to the output table
+
+ do iptr = 1, numcol {
+ call tbcinf (colptr[iptr], colnum, Memc[colname], Memc[colunits],
+ Memc[colfmt], datatype[1], lendata[1], lenfmt[1])
+ call tbcdef (otp, ocp, Memc[colname], Memc[colunits], Memc[colfmt],
+ datatype[1], lendata[1], 1)
+ Memi[newcol+iptr-1] = ocp
+ }
+
+ # Copy the table columns a row at a time
+
+ call tbtcre (otp)
+ call tbhcal (itp, otp)
+ do idx = 1, nindex {
+ jdx = index[idx]
+ call tbrcsc (itp, otp, colptr, Memi[newcol], jdx, idx, numcol)
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tread.par b/pkg/utilities/nttools/tread.par
new file mode 100644
index 00000000..3a9a0000
--- /dev/null
+++ b/pkg/utilities/nttools/tread.par
@@ -0,0 +1,4 @@
+table,f,a,,,,Input table
+columns,s,h," ",,,List of columns to edit
+silent,b,h,no,,,Don't ring bell?
+mode,s,h,al
diff --git a/pkg/utilities/nttools/trebin.par b/pkg/utilities/nttools/trebin.par
new file mode 100644
index 00000000..d2f08d2c
--- /dev/null
+++ b/pkg/utilities/nttools/trebin.par
@@ -0,0 +1,14 @@
+intable,s,a,"",,,"input tables"
+outtable,s,a,"",,,"output tables or directory"
+column,s,a,"",,,"name of independent variable column"
+start,r,a,,,,"first output value of independent variable"
+end,r,a,,,,"last value of independent variable"
+step,r,a,,,,"increment in independent variable"
+xtable,s,h,"",,,"tables of indep var values for output"
+function,s,h,"linear","nearest|linear|poly3|spline",,"interpolation function"
+extrapolate,b,h,no,,,"extrapolate if out of bounds?"
+value,r,h,INDEF,,,"value to use if out of bounds"
+padvalue,r,h,INDEF,,,"value to ignore at end of indep var array"
+verbose,b,h,yes,,,"print operations performed?"
+Version,s,h,"4May2000",,,"date of installation"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/trebin/mkpkg b/pkg/utilities/nttools/trebin/mkpkg
new file mode 100644
index 00000000..7b1e83c3
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/mkpkg
@@ -0,0 +1,27 @@
+# Update the trebin application code in the ttools package library
+# Author: Phil Hodge, 2-DEC-1988
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ tnamcls.x
+ tnamgio.x
+ tnaminit.x
+ trebin.x <error.h> <tbset.h>
+ tucspl.f
+ tudcol.x <tbset.h>
+ tugcol.x <error.h> <tbset.h>
+ tugetput.x <tbset.h>
+ tuhunt.f
+ tuiep3.f
+ tuifit.x trebin.h
+ tuinterp.x <error.h> <tbset.h>
+ tuiset.x trebin.h
+ tuispl.f
+ tuival.x trebin.h
+ tutrim.x
+ tuxget.x <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/trebin/tnamcls.x b/pkg/utilities/nttools/trebin/tnamcls.x
new file mode 100644
index 00000000..80ded94f
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/tnamcls.x
@@ -0,0 +1,24 @@
+# tnam_cls -- close input & output fnt
+# Close the file name templates.
+#
+# Phil Hodge, 15-Apr-1988 Subroutine created.
+# Phil Hodge, 4-Oct-1995 Modify to use tbn instead of fnt.
+# Phil Hodge, 25-Apr-2000 Add xin_t to calling sequence, and remove dir_only.
+
+procedure tnam_cls (in_t, xin_t, out_t)
+
+pointer in_t # io: fnt pointer for input tables
+pointer xin_t # io: fnt pointer for tables of output indep var
+pointer out_t # io: fnt pointer for output tables
+#--
+
+begin
+ if (in_t != NULL)
+ call tbnclose (in_t)
+
+ if (xin_t != NULL)
+ call tbnclose (xin_t)
+
+ if (out_t != NULL)
+ call tbnclose (out_t)
+end
diff --git a/pkg/utilities/nttools/trebin/tnamgio.x b/pkg/utilities/nttools/trebin/tnamgio.x
new file mode 100644
index 00000000..a3d29af5
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/tnamgio.x
@@ -0,0 +1,79 @@
+# tnam_gio -- get input & output names
+# Get the next input and output table names.
+#
+# Phil Hodge, 15-Apr-1988 Task created.
+# Phil Hodge, 4-Oct-1995 Modify to use tbn instead of fnt; use tbparse.
+# Phil hodge, 16-Apr-1999 Remove ttype from calling sequence of tbparse.
+# Phil Hodge, 25-Apr-2000 Add xin_t, xtable, maxch to calling sequence,
+# and remove dir_only.
+
+int procedure tnam_gio (in_t, xin_t, out_t, outdir,
+ intable, xtable, outtable, maxch)
+
+pointer in_t # i: fnt pointer for input tables
+pointer xin_t # i: fnt pointer for tables of output X
+pointer out_t # i: fnt pointer for output tables
+char outdir[ARB] # i: name of output directory
+char intable[ARB] # o: name of next input table
+char xtable[ARB] # o: name of next table for output X
+char outtable[ARB] # o: name of next output table
+int maxch # i: size of table name strings
+#--
+pointer sp
+pointer filename # name of table file, without brackets
+pointer scratch
+int nchar # value of tbnget for intable
+int junk, hdu, tbparse()
+int dir_len # length of root portion of table name
+int tbnget(), tbnlen(), fnldir()
+errchk tbparse
+
+begin
+ # Get the next input table name.
+ nchar = tbnget (in_t, intable, SZ_LINE)
+ if (nchar == EOF)
+ return (EOF)
+
+ # Get the next table for output independent variable values.
+ if (xin_t != NULL) {
+ if (tbnlen (xin_t) == 1) # only one xtable?
+ call tbnrew (xin_t)
+ if (tbnget (xin_t, xtable, SZ_LINE) == EOF)
+ return (EOF)
+ } else {
+ xtable[1] = EOS
+ }
+
+ if (out_t != NULL) {
+
+ # Get the next output table name.
+ if (tbnget (out_t, outtable, SZ_LINE) == EOF)
+ return (EOF)
+
+ } else { # output is a directory name
+
+ call smark (sp)
+ call salloc (filename, SZ_LINE, TY_CHAR)
+ call salloc (scratch, SZ_LINE, TY_CHAR)
+
+ # Copy the portion of the table name without brackets to
+ # Memc[filename]; we need to get rid of the brackets because
+ # they confuse fnldir.
+ junk = tbparse (intable, Memc[filename], Memc[scratch],
+ SZ_LINE, hdu)
+
+ # Get the length of the directory prefix.
+ dir_len = fnldir (Memc[filename], Memc[scratch], SZ_LINE)
+
+ # Copy the output directory name to outtable.
+ call strcpy (outdir, outtable, SZ_LINE)
+
+ # Append the name of the input file (without directory prefix
+ # and without any bracket suffix) to the output directory.
+ call strcat (Memc[filename+dir_len], outtable, SZ_LINE)
+
+ call sfree (sp)
+ }
+
+ return (nchar)
+end
diff --git a/pkg/utilities/nttools/trebin/tnaminit.x b/pkg/utilities/nttools/trebin/tnaminit.x
new file mode 100644
index 00000000..9e5ef686
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/tnaminit.x
@@ -0,0 +1,75 @@
+include <fset.h> # to check whether input or output is redirected
+
+# tnam_init -- initialize for input & output names
+# Get the input and output table name lists. If the output is just a
+# directory name, the name will be copied to outdir; otherwise, the
+# number of names in the input and output lists must be the same.
+#
+# Phil Hodge, 14-Apr-1988 Task created.
+# Phil Hodge, 17-Jun-1993 Change YES to NO in calls to fntopnb.
+# Phil Hodge, 4-Oct-1995 Modify to use tbn instead of fnt.
+# Phil Hodge, 22-Apr-1999 Include explicit test for STDOUT, since
+# isdirectory thinks STDOUT is a directory.
+# Phil Hodge, 8-Jun-1999 Set input/output to STDIN/STDOUT if redirected.
+# Phil Hodge, 25-Apr-2000 Get inlist, xlist, outlist in trebin, and add
+# those three and xin_t to the calling sequence.
+
+procedure tnam_init (inlist, xlist, outlist,
+ in_t, xin_t, out_t, outdir, maxch)
+
+char inlist[ARB] # i: list of input table names
+char xlist[ARB] # i: list of table names for output indep var
+char outlist[ARB] # i: list of output table names
+pointer in_t # o: fnt pointer for input tables
+pointer xin_t # o: fnt pointer for tables of output X
+pointer out_t # o: fnt pointer for output tables
+char outdir[ARB] # o: if dir_only, name of output directory
+int maxch # i: size of outdir string
+#--
+int n_in, n_xin, n_out # number of tables in each list
+bool dir_only # output just a directory name?
+pointer tbnopen()
+int isdirectory(), tbnlen()
+bool strne()
+
+begin
+ dir_only = false
+ if (isdirectory (outlist, outdir, SZ_LINE) > 0 &&
+ strne (outlist, "STDOUT"))
+ dir_only = true
+
+ in_t = tbnopen (inlist)
+ xin_t = tbnopen (xlist)
+
+ n_in = tbnlen (in_t)
+ n_xin = tbnlen (xin_t)
+ if (n_xin < 1) {
+ call tbnclose (xin_t)
+ xin_t = NULL
+ }
+
+ if (dir_only) {
+ out_t = NULL
+ n_out = 0
+ } else {
+ out_t = tbnopen (outlist)
+ n_out = tbnlen (out_t)
+ }
+
+ if (xin_t != NULL) {
+ # It's OK to have just one xtable for all intables.
+ if (n_in != n_xin && n_xin != 1) {
+ call tnam_cls (in_t, xin_t, out_t)
+ call error (1,
+ "intable and xtable lists are not the same length")
+ }
+ }
+
+ if (out_t != NULL) {
+ if (n_in != n_out) {
+ call tnam_cls (in_t, xin_t, out_t)
+ call error (1,
+ "intable and outtable lists are not the same length")
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/trebin/trebin.h b/pkg/utilities/nttools/trebin/trebin.h
new file mode 100644
index 00000000..0164ab3e
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/trebin.h
@@ -0,0 +1,5 @@
+# Codes for interpolating functions.
+define I_NEAREST 1 # nearest neighbor
+define I_LINEAR 2 # linear interpolation
+define I_POLY3 3 # four-point polynomial interpolation
+define I_SPLINE 4 # cubic spline interpolation
diff --git a/pkg/utilities/nttools/trebin/trebin.x b/pkg/utilities/nttools/trebin/trebin.x
new file mode 100644
index 00000000..873f3b05
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/trebin.x
@@ -0,0 +1,136 @@
+include <error.h>
+include <tbset.h>
+include "trebin.h"
+
+# trebin -- resample to uniform spacing
+# This task resamples a table or list of tables to uniformly spaced
+# values of the independent variable.
+#
+# Phil Hodge, 14-Apr-1988 Task created.
+# Phil Hodge, 30-Jan-1992 Delete inlist, outlist.
+# Phil Hodge, 16-Jun-1993 Set the sign of 'step' based on 'start' and 'end'.
+# Phil Hodge, 4-Oct-1995 Modify to use tbn instead of fnt.
+# Phil Hodge, 21-May-1996 Include extrapolate and ext_value.
+# Phil Hodge, 22-Apr-1999 Get 'step' even if 'start' and 'end' are the same.
+# Phil Hodge, 25-Apr-2000 Get inlist, outlist, xlist in this routine
+# instead of in tnam_init; also get padvalue.
+# Phil Hodge, 4-Nov-2000 It is an error if step = 0, unless start = end
+
+procedure trebin()
+
+pointer sp
+pointer inlist # scratch for list of input table names
+pointer outlist # scratch for list of output table names
+pointer xlist # scratch for list of table names for X
+pointer intable # scratch for name of input table
+pointer outtable # scratch for name of output table
+pointer outdir # scratch for name of output directory
+pointer xtable # scratch for name of indep var table
+double iv_start # starting value of independent variable
+double iv_end # ending value of independent variable
+double iv_step # increment in independent variable
+bool extrapolate # true means extrapolate if out of bounds
+double ext_value # value to use when out of bounds
+double padvalue # value at end of input indep. var. to ignore
+char iv_col[SZ_COLNAME] # name of independent variable column
+char func[SZ_FNAME] # interpolation function
+int i_func # interpolation function
+pointer in_t, xin_t, out_t # fn template pointers for input & output lists
+bool verbose # print file names?
+double clgetd()
+bool clgetb()
+int tnam_gio()
+
+begin
+ # Get input and output table template lists.
+ call smark (sp)
+ call salloc (inlist, SZ_LINE, TY_CHAR)
+ call salloc (outlist, SZ_LINE, TY_CHAR)
+ call salloc (xlist, SZ_LINE, TY_CHAR)
+ call salloc (intable, SZ_FNAME, TY_CHAR)
+ call salloc (outtable, SZ_FNAME, TY_CHAR)
+ call salloc (xtable, SZ_FNAME, TY_CHAR)
+ call salloc (outdir, SZ_FNAME, TY_CHAR)
+
+ call clgstr ("intable", Memc[inlist], SZ_LINE)
+ call clgstr ("outtable", Memc[outlist], SZ_LINE)
+ call clgstr ("column", iv_col, SZ_COLNAME)
+ call clgstr ("xtable", Memc[xlist], SZ_LINE)
+
+ # Open the input & output lists of table names.
+ call tnam_init (Memc[inlist], Memc[xlist], Memc[outlist],
+ in_t, xin_t, out_t, Memc[outdir], SZ_FNAME)
+
+ if (xin_t == NULL) {
+
+ # Get parameters for linearly spaced output independent variable.
+ iv_start = clgetd ("start")
+ iv_end = clgetd ("end")
+ iv_step = clgetd ("step")
+ if (iv_step == 0.d0 && iv_start != iv_end)
+ call error (1, "step = 0 is invalid")
+
+ # Set the sign of 'step', rather than expecting the user
+ # to set it correctly.
+ if (iv_start < iv_end)
+ iv_step = abs (iv_step)
+ else if (iv_start > iv_end)
+ iv_step = -abs (iv_step)
+
+ } else {
+
+ iv_start = 0.d0
+ iv_end = 0.d0
+ iv_step = 0.d0
+ }
+
+ call clgstr ("function", func, SZ_FNAME)
+ extrapolate = clgetb ("extrapolate")
+ if (extrapolate)
+ ext_value = INDEFD # not used
+ else
+ ext_value = clgetd ("value")
+
+ padvalue = clgetd ("padvalue")
+
+ verbose = clgetb ("verbose")
+
+ call tuiset (func, i_func) # set interpolator type
+
+ # Process each table.
+ while (tnam_gio (in_t, xin_t, out_t, Memc[outdir],
+ Memc[intable], Memc[xtable], Memc[outtable], SZ_FNAME) != EOF) {
+
+ if (verbose) {
+ if (Memc[xtable] != EOS) {
+ call printf ("%s, %s --> %s\n")
+ call pargstr (Memc[intable])
+ call pargstr (Memc[xtable])
+ call pargstr (Memc[outtable])
+ } else {
+ call printf ("%s --> %s\n")
+ call pargstr (Memc[intable])
+ call pargstr (Memc[outtable])
+ }
+ call flush (STDOUT)
+ }
+
+ iferr {
+ call tuinterp (Memc[intable], Memc[xtable], Memc[outtable],
+ i_func, iv_col, iv_start, iv_end, iv_step,
+ extrapolate, ext_value, padvalue, verbose)
+ } then {
+ call erract (EA_WARN)
+ if (verbose) {
+ call eprintf ("This table will be skipped.\n")
+ } else {
+ call eprintf ("Table %s will be skipped.\n")
+ call pargstr (Memc[intable])
+ }
+ next
+ }
+ }
+
+ call tnam_cls (in_t, xin_t, out_t)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/trebin/tucspl.f b/pkg/utilities/nttools/trebin/tucspl.f
new file mode 100644
index 00000000..511211b8
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/tucspl.f
@@ -0,0 +1,52 @@
+ subroutine tucspl (xa, ya, n, work, y2)
+C
+C Compute the second derivative of YA at each point in the array.
+C This is the initialization needed in preparation for interpolating
+C using cubic splines by the subroutine TUISPL. Input and output
+C are all double precision.
+C
+C This routine was copied with slight modifications from the SPLINE
+C subroutine in Numerical Recipes by Press, Flannery, Teukolsky and
+C Vetterling.
+C
+C N i: number of elements in each array
+C XA i: array of independent-variable values
+C YA i: array of dependent-variable values
+C WORK io: scratch array used for work space
+C Y2 o: second derivative of YA at each point
+C
+CH Phil Hodge, 14-Apr-1988 Subroutine copied from Numerical Recipes SPLINE.
+C
+ integer n
+ double precision xa(n), ya(n), work(n), y2(n)
+C--
+ integer i
+ double precision p, sig
+
+C These values (and y2(n) = 0) are for a "natural" spline.
+ y2(1) = 0.
+ work(1) = 0.
+C
+C This is the decomposition loop of the tridiagonal algorithm.
+C Y2 and WORK are used for temporary storage of the decomposed factors.
+C
+ do 10 i = 2, n-1
+ sig = (xa(i) - xa(i-1)) / (xa(i+1) - xa(i-1))
+ p = sig * y2(i-1) + 2.
+ y2(i) = (sig - 1.) / p
+ work(i) = (6. * ((ya(i+1) - ya(i)) / (xa(i+1) - xa(i))
+ + - (ya(i) - ya(i-1)) / (xa(i) - xa(i-1))) /
+ + (xa(i+1) - xa(i-1)) - sig * work(i-1)) / p
+ 10 continue
+
+C "natural" spline
+ y2(n) = 0.
+C
+C This is the backsubstitution loop of the tridiagonal algorithm.
+C
+ do 20 i = n-1, 1, -1
+ y2(i) = y2(i) * y2(i+1) + work(i)
+ 20 continue
+
+ return
+ end
diff --git a/pkg/utilities/nttools/trebin/tudcol.x b/pkg/utilities/nttools/trebin/tudcol.x
new file mode 100644
index 00000000..8a6d1300
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/tudcol.x
@@ -0,0 +1,140 @@
+include <tbset.h>
+
+# tudcol -- get column pointers
+# Get pointers to input and output dependent variable columns, define
+# columns in output table.
+# The arrays icp & ocp of column pointers are of the same length,
+# which will be less than the total number of columns because they
+# do not include the independent variable column.
+#
+# Columns of type text or boolean will not be copied to the output table.
+# If the independent variable column contains arrays, scalar columns will
+# be copied to output without interpolation; array columns must be the same
+# length as the independent variable column.
+# If the independent variable column contains scalars, array columns will
+# not be copied to output.
+# If verbose is true, a message will be printed regarding skipped columns.
+#
+# Phil Hodge, 26-Apr-2000 Subroutine created, based on previous tugcol.
+
+procedure tudcol (itp, otp, iv_colname, outrows,
+ iv_icp, iv_ocp, icp, ocp, ncols, array, verbose)
+
+pointer itp # i: pointer to input table descriptor
+pointer otp # i: pointer to output table descriptor
+char iv_colname[ARB] # i: name of indep var column
+int outrows # i: array length for output array columns
+pointer iv_icp # o: ptr to descr for input indep var column
+pointer iv_ocp # o: ptr to descr for output indep var column
+pointer icp[ARB] # o: ptr to column descr for input table
+pointer ocp[ARB] # o: ptr to column descr for output table
+int ncols # o: number of dependent variable columns
+bool array # o: true if indep var column contains arrays
+bool verbose # i: print info?
+#--
+pointer sp
+pointer why # note regarding why a column is skipped
+bool skip_this # true if column will not be copied to output
+pointer cp # a column pointer
+char cname[SZ_COLNAME] # a column name
+char cunits[SZ_COLUNITS] # units for a column
+char cfmt[SZ_COLFMT] # print format for a column
+int dtype # data type of a column
+int xnelem # number of input elements for indep var column
+int iv_nelem # number of output elements for indep var column
+int nelem # number of elements
+int lenfmt # length of print format
+int incols # number of columns in input table
+int k # loop index
+int cnum # column number (ignored)
+pointer tbcnum()
+int tbpsta()
+
+begin
+ call smark (sp)
+ call salloc (why, SZ_FNAME, TY_CHAR)
+
+ incols = tbpsta (itp, TBL_NCOLS)
+
+ call tbcfnd1 (itp, iv_colname, iv_icp)
+ if (iv_icp == NULL)
+ call error (1, "independent variable column not found")
+
+ # Get info about indep var column in input table.
+ call tbcinf (iv_icp, cnum, cname, cunits, cfmt, dtype, xnelem, lenfmt)
+
+ # Note that this test is based on the independent variable column.
+ array = (xnelem > 1)
+
+ # The indep var column in the output table may contain arrays;
+ # iv_nelem will be used in the loop below when defining the output
+ # column of independent variable values.
+ if (array)
+ iv_nelem = outrows
+ else
+ iv_nelem = 1
+
+ if (verbose && array) {
+ call printf ("note: array columns in each row will be rebinned\n")
+ call flush (STDOUT)
+ }
+
+ # Define the columns in the output table.
+ ncols = 0
+ do k = 1, incols {
+
+ skip_this = false # initial value
+ cp = tbcnum (itp, k)
+
+ call tbcinf (cp, cnum, cname, cunits, cfmt, dtype, nelem, lenfmt)
+
+ # Indep var column.
+ if (cp == iv_icp) {
+ call tbcdef1 (otp, iv_ocp, cname, cunits, cfmt, dtype, iv_nelem)
+ next
+ }
+
+ if (array) {
+ if (nelem > 1 && nelem != xnelem) { # not the same size
+ skip_this = true
+ call strcpy ("array size is not the same",
+ Memc[why], SZ_FNAME)
+ }
+ } else {
+ if (nelem > 1) { # skip array columns
+ skip_this = true
+ call strcpy ("column contains arrays", Memc[why], SZ_FNAME)
+ }
+ if (dtype <= 0 || dtype == TY_CHAR || dtype == TY_BOOL) {
+ skip_this = true
+ if (dtype == TY_BOOL) {
+ call strcpy ("data type is boolean",
+ Memc[why], SZ_FNAME)
+ } else {
+ call strcpy ("data type is text string",
+ Memc[why], SZ_FNAME)
+ }
+ }
+ }
+
+ if (skip_this) {
+ if (verbose) {
+ call printf (" skipping column `%s' (%s)\n")
+ call pargstr (cname)
+ call pargstr (Memc[why])
+ call flush (STDOUT)
+ }
+ next
+ }
+
+ # Define output column; save pointers for input & output.
+ ncols = ncols + 1
+ if (array && nelem > 1)
+ nelem = outrows
+ icp[ncols] = cp
+ call tbcdef1 (otp, ocp[ncols],
+ cname, cunits, cfmt, dtype, nelem)
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/trebin/tugcol.x b/pkg/utilities/nttools/trebin/tugcol.x
new file mode 100644
index 00000000..6d9dd10d
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/tugcol.x
@@ -0,0 +1,87 @@
+include <error.h>
+include <tbset.h>
+
+# tugcol -- get input X values
+# Get input independent variable column and check it to make
+# sure it is either monotonically increasing or decreasing.
+#
+# Phil Hodge, 18-Apr-1988 Subroutine created
+# Phil Hodge, 30-Jan-1992 Check independent variables more carefully.
+# Phil Hodge, 27-Apr-2000 Move most of this routine to tudcol;
+# rewrite to allow either array or scalar column.
+
+procedure tugcol (itp, iv_icp, row, xin, xnelem, padvalue, array)
+
+pointer itp # i: pointer to input table descriptor
+pointer iv_icp # i: ptr to descr for input indep var column
+int row # i: row number, if input column contains arrays
+double xin[ARB] # o: input independent variable values
+int xnelem # o: actual number of elements in xin array
+double padvalue # i: ignore this value at end of xin array
+bool array # i: true if input column contains arrays
+#--
+pointer sp
+pointer temp # scratch for checking indep var for duplicates
+int nelem # array size
+int nvals # number of elements actually gotten
+int nrows # number of rows in input table
+int i # loop index
+int op # index in temp
+int tbcigi(), tbpsta(), tbagtd()
+string NOT_MONOTONIC "input independent variable is not monotonic"
+
+begin
+ if (array) {
+
+ nelem = tbcigi (iv_icp, TBL_COL_LENDATA)
+ nvals = tbagtd (itp, iv_icp, row, xin, 1, nelem)
+ if (nvals != nelem) {
+ call eprintf (
+ "Not all input independent variable data were gotten from row %d\n")
+ call pargi (row)
+ call error (1, "")
+ }
+ xnelem = nvals
+
+ } else {
+
+ nrows = tbpsta (itp, TBL_NROWS)
+ do i = 1, nrows
+ call tbegtd (itp, iv_icp, i, xin[i])
+ xnelem = nrows
+ }
+
+ # Trim trailing INDEF and pad values by reducing xnelem.
+ call tu_trim (xin, xnelem, padvalue)
+
+ call smark (sp)
+ call salloc (temp, xnelem, TY_DOUBLE)
+
+ # Copy the independent variable data to scratch, skipping embedded
+ # INDEF values.
+ op = 0
+ do i = 1, xnelem {
+ if (!IS_INDEFD(xin[i])) {
+ Memd[temp+op] = xin[i] # op is zero indexed at this point
+ op = op + 1
+ }
+ }
+
+ if (op > 1) {
+ # Check the independent variable values to make sure they're
+ # monotonically increasing or decreasing.
+ if (Memd[temp+1] > Memd[temp]) { # increasing
+ do i = 2, op { # one indexed
+ if (Memd[temp+i-1] <= Memd[temp+i-2])
+ call error (1, NOT_MONOTONIC)
+ }
+ } else { # decreasing
+ do i = 2, op {
+ if (Memd[temp+i-1] >= Memd[temp+i-2])
+ call error (1, NOT_MONOTONIC)
+ }
+ }
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/trebin/tugetput.x b/pkg/utilities/nttools/trebin/tugetput.x
new file mode 100644
index 00000000..e1359929
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/tugetput.x
@@ -0,0 +1,142 @@
+include <tbset.h>
+
+# tu_getput -- do the interpolation
+# This routine reads the independent and dependent variable values,
+# does the interpolation, and writes the results to the output table.
+#
+# Phil Hodge, 24-April-2000 subroutine created
+
+procedure tu_getput (itp, otp, iv_icp, iv_ocp,
+ icp, ocp, ncols,
+ xout, outrows, iv_step,
+ i_func, extrapolate, ext_value, padvalue, array, verbose)
+
+pointer itp, otp # i: descr of input & output tables
+pointer iv_icp # i: column descr for input indep var column
+pointer iv_ocp # i: column descr for output indep var column
+pointer icp[ncols] # i: column descriptors for input table
+pointer ocp[ncols] # i: column descriptors for output table
+int ncols # i: number of columns to copy
+double xout[ARB] # i: output indep var values
+int outrows # i: size of xout
+double iv_step # i: increment in independent variable
+int i_func # i: interpolation function code
+bool extrapolate # i: true means don't use ext_value
+double ext_value # i: value to assign to extrapolated points
+double padvalue # i: value at end of input indep. var. to ignore
+bool array # i: true if indep var column contains arrays
+bool verbose # i: print info?
+#--
+pointer sp
+pointer xin # scratch for input indep var values
+pointer yin # scratch for input data values
+pointer y2 # scratch for second derivatives (spline only)
+pointer xa # scratch for non-indef indep var values
+pointer ya # scratch for non-indef dep var values
+pointer yout # array of interpolated values
+double dbuf # one interpolated value
+int inrows # number of rows in input table
+int xnelem # number of elements in xin, INDEF & padvalue trimmed
+int nelem # allocated number of elements in array
+int nvals # number of array elements actually gotten
+int n # size of xa, ya, y2 (counting only non-INDEF values)
+int row, col # loop indices
+int i
+int tbpsta(), tbcigi(), tbagtd()
+errchk tugcol, tbagtd, tbaptd, tbegtd, tbeptd, tbrcsc
+
+begin
+ call smark (sp)
+
+ inrows = tbpsta (itp, TBL_NROWS)
+
+ if (array)
+ nelem = tbcigi (iv_icp, TBL_COL_LENDATA)
+ else
+ nelem = inrows
+ call salloc (xin, nelem, TY_DOUBLE)
+ call salloc (yin, nelem, TY_DOUBLE)
+ call salloc (y2, nelem, TY_DOUBLE)
+ call salloc (xa, nelem, TY_DOUBLE)
+ call salloc (ya, nelem, TY_DOUBLE)
+
+ if (array) {
+
+ call salloc (yout, outrows, TY_DOUBLE)
+
+ # for each row in the input table ...
+ do row = 1, inrows {
+
+ # Get input independent variable array from current row.
+ call tugcol (itp, iv_icp, row, Memd[xin], xnelem,
+ padvalue, array)
+
+ # Put output indep var values into current row.
+ call tbaptd (otp, iv_ocp, row, xout, 1, outrows)
+
+ # for each column to be interpolated ...
+ do col = 1, ncols {
+ nelem = tbcigi (icp[col], TBL_COL_LENDATA)
+ if (nelem == 1) {
+ # just copy scalar column
+ call tbrcsc (itp, otp, icp[col], ocp[col], row, row, 1)
+ } else {
+ nvals = tbagtd (itp, icp[col], row, Memd[yin], 1, nelem)
+ call tuifit (i_func, Memd[xin], Memd[yin], xnelem,
+ Memd[xa], Memd[ya], Memd[y2], n)
+ if (n > 0) {
+ do i = 1, outrows {
+ # interpolate
+ call tuival (i_func,
+ Memd[xa], Memd[ya], Memd[y2], n,
+ extrapolate, ext_value, xout,
+ i, outrows, iv_step, Memd[yout+i-1])
+ }
+ # put the result
+ call tbaptd (otp, ocp[col], row,
+ Memd[yout], 1, outrows)
+ } else if (verbose && row == 1) {
+ call printf ("not enough data for interpolation\n")
+ call flush (STDOUT)
+ }
+ }
+ }
+ }
+
+ } else {
+
+ # Get input independent variable column.
+ row = 1
+ call tugcol (itp, iv_icp, row, Memd[xin], xnelem, padvalue, array)
+
+ # Put output independent variable values into output table column.
+ do row = 1, outrows
+ call tbeptd (otp, iv_ocp, row, xout[row])
+
+ # for each column to be interpolated ...
+ do col = 1, ncols {
+
+ do row = 1, inrows
+ call tbegtd (itp, icp[col], row, Memd[yin+row-1])
+
+ # xnelem will be less than or equal to inrows.
+ call tuifit (i_func, Memd[xin], Memd[yin], xnelem,
+ Memd[xa], Memd[ya], Memd[y2], n)
+
+ if (n > 0) {
+ do row = 1, outrows {
+ # interpolate, and put the result
+ call tuival (i_func, Memd[xa], Memd[ya], Memd[y2], n,
+ extrapolate, ext_value,
+ xout, row, outrows, iv_step, dbuf)
+ call tbeptd (otp, ocp[col], row, dbuf)
+ }
+ } else if (verbose) {
+ call printf ("not enough data for interpolation\n")
+ call flush (STDOUT)
+ }
+ }
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/trebin/tuhunt.f b/pkg/utilities/nttools/trebin/tuhunt.f
new file mode 100644
index 00000000..3d8df648
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/tuhunt.f
@@ -0,0 +1,103 @@
+ subroutine tuhunt (xa, n, x, klo)
+C
+C The array XA is searched for an element KLO such that
+C xa(klo) <= x <= xa(klo+1)
+C If X < XA(1) then KLO is set to zero; if X > XA(N) then KLO is set to N.
+C That is, KLO = 0 or N is a flag indicating X is out of bounds.
+C
+C KLO must be set to an initial guess on input; it will then be replaced
+C by the correct value on output.
+C
+C This routine was copied with some modifications from the HUNT
+C subroutine in Numerical Recipes by Press, Flannery, Teukolsky and
+C Vetterling.
+C
+C N i: number of elements in each array
+C XA i: array of independent-variable values
+C X i: the value to be bracketed by elements in XA
+C KLO io: the lower index in XA that brackets X
+C
+CH Phil Hodge, 14-Apr-1988 Subroutine copied from Numerical Recipes HUNT.
+CH Phil Hodge, 21-May-1996 Don't flag endpoints of XA as out of bounds.
+C
+ integer n, klo
+ double precision xa(n), x
+C--
+ integer inc, km, khi
+ logical ascnd
+
+C Set ASCND, and check for X out of bounds.
+
+ if (xa(n).gt.xa(1)) then
+ ascnd = .true.
+ if (x .lt. xa(1)) then
+ klo = 0
+ return
+ else if (x .gt. xa(n)) then
+ klo = n
+ return
+ end if
+ else
+ ascnd = .false.
+ if (x .gt. xa(1)) then
+ klo = 0
+ return
+ else if (x .lt. xa(n)) then
+ klo = n
+ return
+ end if
+ end if
+
+ if ((klo .le. 0) .or. (klo .gt. n)) then
+ klo = 1
+ khi = n
+ go to 3
+ endif
+
+ inc = 1
+ if ((x.ge.xa(klo) .and. ascnd) .or.
+ + (x.lt.xa(klo) .and. .not.ascnd)) then
+1 khi = klo + inc
+ if (khi .gt. n) then
+ khi = n + 1
+ else if ((x.ge.xa(khi) .and. ascnd) .or.
+ + (x.lt.xa(khi) .and. .not.ascnd)) then
+ klo = khi
+ inc = inc + inc
+ go to 1
+ endif
+ else
+ khi = klo
+2 klo = khi - inc
+ if (klo .lt. 1) then
+ klo = 0
+ else if ((x.lt.xa(klo) .and. ascnd) .or.
+ + (x.ge.xa(klo) .and. .not.ascnd)) then
+ khi = klo
+ inc = inc + inc
+ go to 2
+ endif
+ endif
+
+3 continue
+C Before we return, make sure we don't return a value of KLO that
+C implies X is out of bounds. We know it isn't because we checked
+C at the beginning.
+ if (khi-klo .eq. 1) then
+ klo = max (klo, 1)
+ klo = min (klo, n-1)
+ return
+ end if
+
+ km = (khi + klo) / 2
+
+ if ((x .gt. xa(km) .and. ascnd) .or.
+ + (x .le. xa(km) .and. .not.ascnd)) then
+ klo = km
+ else
+ khi = km
+ endif
+
+ go to 3
+
+ end
diff --git a/pkg/utilities/nttools/trebin/tuiep3.f b/pkg/utilities/nttools/trebin/tuiep3.f
new file mode 100644
index 00000000..58f81a99
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/tuiep3.f
@@ -0,0 +1,71 @@
+ subroutine tuiep3 (xa, ya, x, y, dy)
+C
+C Evaluate a cubic polynomial interpolation function at X.
+C xa(klo) <= x <= xa(klo+1)
+C This routine was copied with slight modifications from the POLINT
+C subroutine in Numerical Recipes by Press, Flannery, Teukolsky and
+C Vetterling.
+C
+C XA i: array of four independent-variable values
+C YA i: array of four dependent-variable values
+C X i: the independent variable
+C Y o: the result of interpolations
+C DY o: an estimate of the error of interpolation
+C
+CH Phil Hodge, 18-Apr-1988 Subroutine copied from Numerical Recipes POLINT.
+C
+ double precision xa(4), ya(4), x, y, dy
+C--
+ integer n
+C four-point interpolation
+ parameter (n = 4)
+
+ double precision c(n), d(n), dif, dift, den
+ double precision ho, hp, w
+ integer i, m, ns
+
+ do 10 i = 1, n
+ if (x .eq. xa(i)) then
+ y = ya(i)
+ return
+ endif
+ 10 continue
+
+ ns = 1
+ dif = abs (x - xa(1))
+
+ do 20 i = 1, n
+ dift = abs (x - xa(i))
+ if (dift .lt. dif) then
+ ns = i
+ dif = dift
+ endif
+ c(i) = ya(i)
+ d(i) = ya(i)
+ 20 continue
+
+ y = ya(ns)
+ ns = ns - 1
+
+ do 40 m = 1, n-1
+
+ do 30 i = 1, n-m
+ ho = xa(i) - x
+ hp = xa(i+m) - x
+ w = c(i+1) - d(i)
+ den = w / (ho - hp)
+ d(i) = hp * den
+ c(i) = ho * den
+ 30 continue
+
+ if (2*ns .lt. n-m) then
+ dy = c(ns+1)
+ else
+ dy = d(ns)
+ ns = ns - 1
+ endif
+ y = y + dy
+ 40 continue
+
+ return
+ end
diff --git a/pkg/utilities/nttools/trebin/tuifit.x b/pkg/utilities/nttools/trebin/tuifit.x
new file mode 100644
index 00000000..2f3a2d84
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/tuifit.x
@@ -0,0 +1,63 @@
+include "trebin.h"
+
+# tuifit -- initialize or fit
+# The input arrays of independent and dependent variable values are copied
+# to output arrays, skipping indef values. The number of good values
+# (i.e. not indef) is checked to make sure there are enough for the type
+# of interpolation specified. In the case of spline interpolation, the
+# array y2 of second derivatives is computed.
+#
+# Phil Hodge, 18-Apr-1988 Subroutine created
+# Phil Hodge, 17-Jun-1993 Require at least two values for linear interpolation.
+
+procedure tuifit (i_func, xin, yin, inrows,
+ xa, ya, y2, n)
+
+int i_func # i: interpolation function code
+double xin[ARB] # i: array of independent-variable values
+double yin[ARB] # i: array of dependent-variable values
+int inrows # i: size of xin, yin arrays
+double xa[ARB] # o: array of independent-variable values
+double ya[ARB] # o: array of dependent-variable values
+double y2[ARB] # o: used only by spline interpolation
+int n # o: size of xa, ya, y2 arrays
+#--
+pointer sp
+pointer work # scratch for spline fit
+int k # loop index
+
+begin
+ n = 0 # initial value
+
+ do k = 1, inrows {
+ if ( ! IS_INDEFD(xin[k]) && ! IS_INDEFD(yin[k])) {
+ n = n + 1
+ xa[n] = xin[k]
+ ya[n] = yin[k]
+ }
+ }
+
+ switch (i_func) {
+ case I_NEAREST:
+ if (n < 1)
+ n = 0 # flag it as bad
+
+ case I_LINEAR:
+ if (n < 2)
+ n = 0
+
+ case I_POLY3:
+ if (n < 4)
+ n = 0
+
+ case I_SPLINE:
+ if (n >= 4) {
+ call smark (sp)
+ call salloc (work, n, TY_DOUBLE)
+ call tucspl (xa, ya, n, Memd[work], y2)
+ call sfree (sp)
+ } else {
+ n = 0
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/trebin/tuinterp.x b/pkg/utilities/nttools/trebin/tuinterp.x
new file mode 100644
index 00000000..3a3b1d89
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/tuinterp.x
@@ -0,0 +1,139 @@
+include <error.h>
+include <tbset.h>
+include "trebin.h"
+
+# tuinterp -- interpolate to regrid a table
+# Open the input & output tables, interpolate to uniformly spaced values
+# of the independent variable, and close the tables.
+#
+# Phil Hodge, 15-Apr-1988 Subroutine created
+# Phil Hodge, 12-May-1989 Include check for not enough data to interpolate.
+# Phil Hodge, 12-Jun-1989 Also copy header parameters.
+# Phil Hodge, 30-Jan-1992 Call tbtclo instead of close.
+# Phil Hodge, 16-Jun-1993 Check number of rows for interpolation function.
+# Phil Hodge, 4-Apr-1994 Errchk tbtopn, and use iferr for tbtcre.
+# Phil Hodge, 20-May-1996 Pass extrapolate and ext_value to tuival.
+# Phil Hodge, 29-Jul-1998 Add iv_step to calling sequence of tuival.
+# Phil Hodge, 8-Apr-1999 Call tbfpri.
+# Phil Hodge, 22-Apr-1999 Don't set output table type if outtable = STDOUT.
+# Phil Hodge, 25-Apr-2000 Add xtable, padvalue, verbose to calling sequence.
+# Phil Hodge, 30-Oct-2001 Delete just the output table, not the whole file,
+# if there's an error.
+# Phil Hodge, 2-Jan-2002 Remove the statements to delete the output table
+# in case the input table is not monotonic (because
+# calling tbtclo for a text table caused the error
+# message to be replaced by a misleading message).
+
+procedure tuinterp (intable, xtable, outtable,
+ i_func, iv_colname, iv_start, iv_end, iv_step,
+ extrapolate, ext_value, padvalue, verbose)
+
+char intable[ARB] # i: name of input table
+char xtable[ARB] # i: table of output indep var values
+char outtable[ARB] # i: name of output table
+int i_func # i: interpolation function code
+char iv_colname[SZ_COLNAME] # i: name of independent variable column
+double iv_start # i: starting value of independent variable
+double iv_end # i: ending value of independent variable
+double iv_step # i: increment in independent variable
+bool extrapolate # i: true means don't use ext_value
+double ext_value # i: value to assign to extrapolated points
+double padvalue # i: value at end of input indep. var. to ignore
+bool verbose # i: print info?
+#--
+pointer sp
+pointer itp, otp # descr of input & output tables
+pointer iv_icp # descr for input indep var column
+pointer iv_ocp # descr for output indep var column
+pointer icpp, ocpp # column descr for i & o tables
+pointer xout # scratch for output indep var values
+int ttype # indicates row- or column-ordered
+int ncols # number of dependent variable columns
+int incols # total number of input columns
+int outrows # number of rows in output table
+int phu_copied # set by tbfpri and ignored
+bool array # true if indep var column contains arrays
+pointer tbtopn()
+int tbpsta()
+bool strne()
+errchk tbfpri, tbtopn, tbtdel, tudcol, tuxget, tu_getput
+
+begin
+ call smark (sp)
+
+ itp = tbtopn (intable, READ_ONLY, 0)
+ incols = tbpsta (itp, TBL_NCOLS)
+
+ # Either read or compute the values of the independent variable
+ # at which we will interpolate the values from the input table.
+ iferr {
+ call tuxget (xtable, iv_start, iv_end, iv_step, padvalue,
+ xout, outrows)
+ } then {
+ call tbtclo (itp)
+ call erract (EA_ERROR)
+ }
+
+ iferr {
+ call tbfpri (intable, outtable, phu_copied)
+ otp = tbtopn (outtable, NEW_FILE, NULL)
+ } then {
+ call mfree (xout, TY_DOUBLE)
+ call tbtclo (itp)
+ call erract (EA_ERROR)
+ }
+
+ call salloc (icpp, incols, TY_POINTER)
+ call salloc (ocpp, incols, TY_POINTER)
+
+ # Define output columns, and get column pointers.
+ iferr {
+ call tudcol (itp, otp, iv_colname, outrows,
+ iv_icp, iv_ocp, Memi[icpp], Memi[ocpp], ncols, array, verbose)
+ } then {
+ call mfree (xout, TY_DOUBLE)
+ call tbtclo (itp)
+ call tbtclo (otp)
+ call erract (EA_ERROR)
+ }
+
+ # Output table should be same type as input table.
+ if (strne (outtable, "STDOUT")) {
+ ttype = tbpsta (itp, TBL_WHTYPE)
+ call tbpset (otp, TBL_WHTYPE, ttype)
+ if (ttype == TBL_TYPE_S_COL) {
+ call tbpset (otp, TBL_ALLROWS,
+ max (outrows, tbpsta (itp, TBL_ALLROWS)))
+ }
+ }
+
+ iferr {
+ call tbtcre (otp) # create output table
+ } then {
+ call mfree (xout, TY_DOUBLE)
+ call tbtclo (itp)
+ call tbtclo (otp)
+ call erract (EA_ERROR)
+ }
+
+ call tbhcal (itp, otp) # copy all header parameters
+
+ # For each column, get the data, do the interpolation,
+ # write the results.
+ iferr {
+ call tu_getput (itp, otp, iv_icp, iv_ocp,
+ Memi[icpp], Memi[ocpp], ncols,
+ Memd[xout], outrows, iv_step,
+ i_func, extrapolate, ext_value, padvalue, array, verbose)
+ } then {
+ call mfree (xout, TY_DOUBLE)
+ call tbtclo (itp)
+ call erract (EA_ERROR)
+ }
+
+ call mfree (xout, TY_DOUBLE)
+ call sfree (sp)
+
+ call tbtclo (itp)
+ call tbtclo (otp)
+end
diff --git a/pkg/utilities/nttools/trebin/tuiset.x b/pkg/utilities/nttools/trebin/tuiset.x
new file mode 100644
index 00000000..427df021
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/tuiset.x
@@ -0,0 +1,26 @@
+include "trebin.h"
+
+# tuiset -- set interpolation type
+#
+#
+# P.E. Hodge, 18-Apr-88 Subroutine created
+
+procedure tuiset (func, i_func)
+
+char func[ARB] # i: interpolation function
+int i_func # o: interpolation function code
+#--
+int strncmp()
+
+begin
+ if (func[1] == 'n')
+ i_func = I_NEAREST
+ else if (func[1] == 'l')
+ i_func = I_LINEAR
+ else if (strncmp (func, "poly3", 5) == 0)
+ i_func = I_POLY3
+ else if (func[1] == 's')
+ i_func = I_SPLINE
+ else
+ call error (1, "unknown interpolation function")
+end
diff --git a/pkg/utilities/nttools/trebin/tuispl.f b/pkg/utilities/nttools/trebin/tuispl.f
new file mode 100644
index 00000000..2f4c68b8
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/tuispl.f
@@ -0,0 +1,32 @@
+ subroutine tuispl (xa, ya, y2, x, y)
+C
+C Interpolate at point X using cubic splines. The array Y2 must have
+C previously been computed by calling TUCSPL. Note that XA, YA, Y2
+C are two-element subarrays of the arrays with the same names elsewhere.
+C Input and output are all double precision.
+C This routine was copied with slight modifications from the SPLINT
+C subroutine in Numerical Recipes by Press, Flannery, Teukolsky and
+C Vetterling.
+C
+C XA i: pair of independent-variable values
+C YA i: pair of dependent-variable values
+C Y2 i: second derivatives of YA at each point
+C X i: value at which spline is to be computed
+C Y o: interpolated value at X
+C
+CH Phil Hodge, 14-Apr-1988 Subroutine copied from Numerical Recipes SPLINT.
+C
+ double precision xa(2), ya(2), y2(2), x, y
+C--
+ double precision h, a, b
+
+ h = xa(2) - xa(1)
+
+ a = (xa(2) - x) / h
+ b = (x - xa(1)) / h
+ y = a * ya(1) + b * ya(2) +
+ + ((a**3 - a) * y2(1) + (b**3 - b) * y2(2))
+ + * h * h / 6.
+
+ return
+ end
diff --git a/pkg/utilities/nttools/trebin/tuival.x b/pkg/utilities/nttools/trebin/tuival.x
new file mode 100644
index 00000000..20354a5d
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/tuival.x
@@ -0,0 +1,272 @@
+include "trebin.h"
+
+# tuival -- interpolate
+# Interpolate to get one value.
+# A zero value of iv_step means that the output independent-variable values
+# may not be uniformly spaced, so the interval x1,x2 must be gotten from
+# the xout array. (This is relevant for linear interpolation only.)
+#
+# Phil Hodge, 18-Apr-1988 Subroutine created
+# Phil Hodge, 20-May-1996 Include extrapolate and ext_value for extrapolation.
+# Phil Hodge, 29-Jul-1998 For 1-D, fit a line instead of interpolating,
+# add iv_step to calling sequence, add subroutines
+# tu_range and tu_fit1.
+# Phil Hodge, 22-Apr-1999 The test on whether x is outside the range of
+# the data did not consider that xa could be decreasing.
+# Phil Hodge, 25-Apr-2000 Change calling sequence: x --> xout, j, outrows;
+# this is to support the option of a nonuniformly spaced output
+# independent variable array.
+
+procedure tuival (i_func, xa, ya, y2, n,
+ extrapolate, ext_value, xout, j, outrows, iv_step, y)
+
+int i_func # i: interpolation function code
+double xa[n] # i: input independent-variable values
+double ya[n] # i: input dependent-variable values
+double y2[n] # i: used only by spline interpolation
+int n # i: size of xa, ya, y2 arrays
+bool extrapolate # i: extrapolate rather than use ext_value?
+double ext_value # i: value to assign if x is out of bounds
+double xout[ARB] # i: output independent variable array
+int j # i: current element of xout
+int outrows # i: size of xout array
+double iv_step # i: spacing of x values (can be negative)
+double y # o: the interpolated value
+#--
+double x # independent variable
+double x1, x2 # beginning and end of output pixel
+double dy # an estimate of the error of interpolation
+int klo, khi # indexes within xa that bracket x
+int npts # number of points in interval
+
+begin
+ x = xout[j]
+
+ # Initial guess for klo; we want xa[klo] <= x <= xa[klo+1].
+ klo = (n + 1) / 2
+ khi = klo
+
+ # If x falls outside the range of the data, either extrapolate
+ # (below) or assign a fixed value ext_value.
+ if (!extrapolate && n > 1) {
+ if (xa[1] < xa[2] && (x < xa[1] || x > xa[n])) { # increasing
+ y = ext_value
+ return
+ }
+ if (xa[1] > xa[2] && (x > xa[1] || x < xa[n])) { # decreasing
+ y = ext_value
+ return
+ }
+ }
+
+ switch (i_func) {
+ case I_NEAREST:
+
+ # Find klo such that xa[klo] <= x <= xa[klo+1], starting from
+ # current klo.
+ call tuhunt (xa, n, x, klo)
+ klo = max (klo, 1)
+ klo = min (klo, n)
+ khi = min (klo+1, n)
+ if (abs (x - xa[klo]) < abs (x - xa[khi]))
+ y = ya[klo]
+ else
+ y = ya[khi]
+
+ case I_LINEAR:
+
+ # Get x1 and x2.
+ call tu_x1x2 (xout, j, outrows, iv_step, x1, x2)
+
+ # Get klo, khi, and npts.
+ call tu_range (xa, ya, n, x1, x2, klo, khi, npts)
+ if (npts > 1) {
+ # Fit a line to the data from klo to khi inclusive.
+ call tu_fit1 (xa, ya, x, klo, khi, y)
+ } else {
+ # Interpolate.
+ klo = klo - 1
+ call tuhunt (xa, n, x, klo)
+ klo = max (klo, 1)
+ klo = min (klo, n-1)
+ call tuiep1 (xa[klo], ya[klo], x, y)
+ }
+
+ case I_POLY3:
+
+ call tuhunt (xa, n, x, klo)
+ klo = max (klo, 2)
+ klo = min (klo, n-2)
+ # Pass tuiep3 the four points at klo-1, klo, klo+1, klo+2.
+ call tuiep3 (xa[klo-1], ya[klo-1], x, y, dy)
+
+ case I_SPLINE:
+
+ call tuhunt (xa, n, x, klo)
+ klo = max (klo, 1)
+ klo = min (klo, n-1)
+ call tuispl (xa[klo], ya[klo], y2[klo], x, y)
+ }
+end
+
+# This routine gets the endpoints x1,x2 of the current output pixel.
+# If the output independent variable array is uniformly spaced, x1 and x2
+# will just be the current pixel xout[j] - or + iv_step/2. If the output
+# independent variable array is (or may be) nonuniformly spaced, indicated
+# by iv_step being zero, then x1 and x2 will be the midpoints of intervals
+# adjacent to xout[j] on the left and right.
+#
+# x1 may be less than, equal to, or greater than x2.
+
+procedure tu_x1x2 (xout, j, outrows, iv_step, x1, x2)
+
+double xout[ARB] # i: output independent variable array
+int j # i: current element of xout
+int outrows # i: size of xout array
+double iv_step # i: spacing of x values (can be negative)
+double x1, x2 # o: endpoints of output pixel
+
+begin
+ if (iv_step != 0) {
+ # output is uniformly spaced
+ x1 = xout[j] - iv_step / 2.d0
+ x2 = xout[j] + iv_step / 2.d0
+ } else {
+ if (outrows == 1) {
+ x1 = xout[1]
+ x2 = xout[1]
+ } else if (j == 1) {
+ x2 = (xout[1] + xout[2]) / 2.d0
+ x1 = xout[1] - (x2 - xout[1])
+ } else if (j == outrows) {
+ x1 = (xout[outrows-1] + xout[outrows]) / 2.d0
+ x2 = xout[outrows] + (xout[outrows] - x1)
+ } else {
+ x1 = (xout[j-1] + xout[j]) / 2.d0
+ x2 = (xout[j] + xout[j+1]) / 2.d0
+ }
+ }
+end
+
+# tu_range -- find range of indexes
+# This routine finds the range of indexes in xa and ya corresponding to
+# the interval x1 to x2. The range is klo to khi; klo will be less than
+# or equal to khi, even though xa can be either increasing or decreasing.
+# klo and khi will also be within the range 1 to n inclusive, even if
+# x1 to x2 is outside the range xa[1] to xa[n]. npts will be set to
+# the actual number of elements of xa within the interval x1 to x2;
+# thus, npts can be zero.
+#
+# x1 and x2 will be interchanged, if necessary, so that the array index
+# in xa corresponding to x1 will be smaller than the array index corresponding
+# to x2, i.e. so klo will be smaller than khi.
+#
+# Note that klo is used as an initial value when hunting for a value in xa,
+# so klo must have been initialized to a reasonable value before calling
+# this routine.
+
+procedure tu_range (xa, ya, n, x1, x2, klo, khi, npts)
+
+double xa[n] # i: array of independent-variable values
+double ya[n] # i: array of dependent-variable values
+int n # i: size of xa, ya, y2 arrays
+double x1, x2 # io: endpoints of output pixel
+int klo, khi # io: range of indices in xa within x1,x2
+int npts # o: number of elements in xa within x1,x2
+#--
+double temp # for swapping x1 and x2, if appropriate
+int k1, k2
+
+begin
+ # Swap x1 and x2 if necessary, so that klo will be less than or
+ # equal to khi.
+ if (xa[1] <= xa[2]) { # input X is increasing
+ if (x1 > x2) {
+ temp = x1; x1 = x2; x2 = temp
+ }
+ } else { # input X is decreasing
+ if (x1 < x2) {
+ temp = x1; x1 = x2; x2 = temp
+ }
+ }
+
+ k1 = klo
+ call tuhunt (xa, n, x1, k1)
+ k1 = k1 + 1 # next point
+ klo = k1
+ klo = min (klo, n)
+
+ k2 = k1
+ call tuhunt (xa, n, x2, k2)
+ khi = max (k2, 1)
+ khi = min (khi, n)
+
+ # npts can be different from khi - klo + 1, and it can be zero.
+ npts = k2 - k1 + 1
+end
+
+# tu_fit1 -- fit a line (1-D) to data
+# This routine fits a straight line to (xa[k],ya[k]) for k = klo to khi
+# inclusive. The fit is then evaluated at x, and the result is returned
+# as y. There must be at least two points, i.e. khi > klo.
+
+procedure tu_fit1 (xa, ya, x, klo, khi, y)
+
+double xa[ARB] # i: array of independent-variable values
+double ya[ARB] # i: array of dependent-variable values
+double x # i: independent variable
+int klo, khi # i: range of indices in xa covered by iv_step
+double y # o: value of fit at x
+#--
+double sumx, sumy, sumxy, sumx2
+double xmean, ymean
+double slope, intercept
+int k
+
+begin
+ sumx = 0.d0
+ sumy = 0.d0
+ do k = klo, khi {
+ sumx = sumx + xa[k]
+ sumy = sumy + ya[k]
+ }
+ xmean = sumx / (khi - klo + 1)
+ ymean = sumy / (khi - klo + 1)
+
+ sumxy = 0.d0
+ sumx2 = 0.d0
+ do k = klo, khi {
+ sumxy = sumxy + (xa[k] - xmean) * (ya[k] - ymean)
+ sumx2 = sumx2 + (xa[k] - xmean)**2
+ }
+ slope = sumxy / sumx2
+ intercept = (ymean - slope * xmean)
+
+ y = intercept + slope * x
+end
+
+
+# tuiep1 -- linear interpolation
+# Interpolate to get one value. X is supposed to be between xa[1] and
+# xa[2], but it is not an error if x is outside that interval. Note
+# that xa, ya are subarrays of the arrays with the same names elsewhere.
+
+procedure tuiep1 (xa, ya, x, y)
+
+double xa[2] # i: pair of independent-variable values
+double ya[2] # i: pair of dependent-variable values
+double x # i: independent variable
+double y # o: the interpolated value
+#--
+double p # fraction of distance between indep var val
+
+begin
+ if (x == xa[1]) {
+ y = ya[1]
+ } else if (x == xa[2]) {
+ y = ya[2]
+ } else {
+ p = (x - xa[1]) / (xa[2] - xa[1])
+ y = p * ya[2] + (1.-p) * ya[1]
+ }
+end
diff --git a/pkg/utilities/nttools/trebin/tutrim.x b/pkg/utilities/nttools/trebin/tutrim.x
new file mode 100644
index 00000000..e792c37a
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/tutrim.x
@@ -0,0 +1,43 @@
+# This routine trims elements from the end of the xout array by
+# decrementing nelem. Values are trimmed if they are INDEF or
+# equal to padvalue (and padvalue itself is not INDEF). Trimming
+# starts at the end and stops with the first value that is not
+# INDEF and not equal to padvalue.
+#
+# Phil Hodge, 26-Apr-2000
+
+procedure tu_trim (xout, nelem, padvalue)
+
+double xout[ARB] # i: independent variable values
+int nelem # io: size of xout array
+double padvalue # i: trim these values at end of xout array
+#--
+int curr_nelem # current value of nelem
+int i
+
+begin
+ curr_nelem = nelem
+
+ if (!IS_INDEFD(padvalue)) {
+
+ # Check for either INDEF or padvalue.
+ do i = curr_nelem, 1, -1 {
+ if (IS_INDEFD(xout[i]))
+ nelem = nelem - 1
+ else if (xout[i] == padvalue)
+ nelem = nelem - 1
+ else # neither INDEF nor a pad value
+ break
+ }
+
+ } else {
+
+ # Just check for INDEF.
+ do i = curr_nelem, 1, -1 {
+ if (IS_INDEFD(xout[i]))
+ nelem = nelem - 1
+ else # not INDEF
+ break
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/trebin/tuxget.x b/pkg/utilities/nttools/trebin/tuxget.x
new file mode 100644
index 00000000..9b890bb4
--- /dev/null
+++ b/pkg/utilities/nttools/trebin/tuxget.x
@@ -0,0 +1,134 @@
+include <tbset.h>
+
+# The values of the independent variable for the output table can be
+# read either from an input table (xtable), or they can be assigned
+# from the start, increment, and end values.
+#
+# Phil Hodge, 25-Apr-2000 Subroutine created.
+# Phil Hodge, 12-May-2004 errchk the procedures that are called.
+
+procedure tuxget (xtable, iv_start, iv_end, iv_step, padvalue,
+ xout, outrows)
+
+char xtable[ARB] # i: table of output indep var values
+double iv_start # i: starting value of independent variable
+double iv_end # i: ending value of independent variable
+double iv_step # i: increment in independent variable
+double padvalue # i: value at end of indep var array to ignore
+pointer xout # o: pointer to output indep var values
+int outrows # o: number of output rows (size of xout)
+#--
+pointer tp, cp
+int row, nrows
+int i
+int nelem # array size, or number of table rows
+int nvals # number of elements read from column if it's an array
+double dbuf
+double direction # indicates increasing or decreasing data
+double previous # for comparing current and previous values
+pointer tbtopn(), tbcnum()
+int tbpsta(), tbcigi(), tbagtd()
+errchk tbtopn, tbpsta, tbcnum, tbcigi, tbtclo, tbagtd, tbegtd, tu_trim
+
+begin
+ if (xtable[1] != EOS) {
+
+ tp = tbtopn (xtable, READ_ONLY, NULL)
+ if (tbpsta (tp, TBL_NCOLS) < 1) {
+ call tbtclo (tp)
+ call error (1, "No data in xtable")
+ }
+ if (tbpsta (tp, TBL_NCOLS) > 1) {
+ call tbtclo (tp)
+ call eprintf ("xtable %s contains more than one column;\n")
+ call pargstr (xtable)
+ call eprintf (
+ "use a column selector [c:<colname>] to specify which column.\n")
+ call error (1, "")
+ }
+
+ nrows = tbpsta (tp, TBL_NROWS)
+ cp = tbcnum (tp, 1)
+ nelem = tbcigi (cp, TBL_COL_LENDATA)
+
+ if (nelem > 1 && nrows > 1) {
+ call tbtclo (tp)
+ call eprintf ("xtable %s contains more than one row,\n")
+ call pargstr (xtable)
+ call eprintf ("and the column contains arrays;\n")
+ call eprintf (
+ "use a row selector [c:row=<rownum>] to specify which row.\n")
+ call error (1, "")
+ }
+
+ if (nelem == 1)
+ nelem = nrows
+ call malloc (xout, nelem, TY_DOUBLE)
+
+ # Read the data from the table.
+ if (nrows == 1) {
+ row = 1
+ nvals = tbagtd (tp, cp, row, Memd[xout], 1, nelem)
+ if (nvals < nelem) {
+ call tbtclo (tp)
+ call error (1, "not all elements read from xtable")
+ }
+ } else {
+ do row = 1, nrows
+ call tbegtd (tp, cp, row, Memd[xout+row-1])
+ }
+
+ call tbtclo (tp)
+
+ # Trim trailing garbage by decrementing outrows.
+ outrows = nelem
+ call tu_trim (Memd[xout], outrows, padvalue)
+
+ # Check for embedded INDEF values, and make sure the values
+ # are monotonically increasing or decreasing.
+ if (outrows > 1) {
+
+ do i = 1, outrows {
+ if (IS_INDEFD(Memd[xout+i-1])) {
+ call eprintf (
+ "xtable %s contains embedded INDEF values\n")
+ call pargstr (xtable)
+ call eprintf ("(i.e. not just trailing INDEFs)\n")
+ call error (1, "")
+ }
+ }
+
+ if (Memd[xout+1] >= Memd[xout])
+ direction = 1.d0
+ else
+ direction = -1.d0
+ previous = Memd[xout] - direction
+ do i = 1, outrows {
+ if (direction * (Memd[xout+i-1] - previous) <= 0.d0) {
+ call eprintf (
+ "Values in xtable %s are not monotonic\n")
+ call pargstr (xtable)
+ call error (1, "")
+ }
+ previous = Memd[xout+i-1]
+ }
+ }
+
+ } else { # no xtable
+
+ # Find out how many rows the output table should have.
+ if (iv_start == iv_end)
+ outrows = 1
+ else
+ outrows = nint ((iv_end - iv_start) / iv_step + 1.0)
+
+ call malloc (xout, outrows, TY_DOUBLE)
+
+ # Compute the independent variable values for the output table.
+ dbuf = iv_start
+ do i = 1, outrows {
+ Memd[xout+i-1] = dbuf
+ dbuf = dbuf + iv_step
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/tselect.par b/pkg/utilities/nttools/tselect.par
new file mode 100644
index 00000000..a4e9368f
--- /dev/null
+++ b/pkg/utilities/nttools/tselect.par
@@ -0,0 +1,4 @@
+intable,s,a,,,,"Input tables"
+outtable,s,a,,,,"Output tables"
+expr,s,a,,,,"Expression used for selection"
+mode,s,h,"a",,,
diff --git a/pkg/utilities/nttools/tselect/mkpkg b/pkg/utilities/nttools/tselect/mkpkg
new file mode 100644
index 00000000..69d01d6c
--- /dev/null
+++ b/pkg/utilities/nttools/tselect/mkpkg
@@ -0,0 +1,12 @@
+# Update the tselect application code in the ttools package library
+# Author: B.Simon, 25-NOV-1987
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ subset.x <tbset.h>
+ tselect.x
+ ;
diff --git a/pkg/utilities/nttools/tselect/subset.x b/pkg/utilities/nttools/tselect/subset.x
new file mode 100644
index 00000000..06f574a3
--- /dev/null
+++ b/pkg/utilities/nttools/tselect/subset.x
@@ -0,0 +1,83 @@
+include <tbset.h>
+define SYNTAX 1
+
+# SUBSET -- Select subset of table rows
+#
+# This procedure evaluates a boolean expession for selected rows in a table.
+# If the expression is true, it is written to the output table
+#
+# B.Simon 7-Oct-87 First Code
+# B.Simon 16-Dec-87 Changed to handle table subsets
+# B.Simon 06-Jan-93 Changed to use ftnexpr
+# B.Simon 25-Aug-98 Changed to write directly to output table
+
+procedure subset (itp, otp, expr)
+
+pointer itp # i: Input table descriptor
+pointer otp # o: Output table descriptor
+char expr[ARB] # i: Algebraic expression used in subset
+#--
+char nl
+pointer sp, newexp, ch
+int fd, sd, ic, irow, orow, first, last
+
+int open(), stropen(), stridx(), tbpsta(), tbl_search()
+
+data nl / '\n' /
+string badtype "Expression is not valid"
+
+errchk open, stropen, tbl_search
+
+begin
+ # Allocate dynamic memory for strings
+
+ call smark (sp)
+ call salloc (newexp, SZ_COMMAND, TY_CHAR)
+
+ # Check to see if the expression is a file name
+
+ if (expr[1] != '@') {
+ # Copy the expression into string
+
+ call strcpy (expr, Memc[newexp], SZ_COMMAND)
+
+ } else {
+ # Copy the file into a string
+
+ fd = open (expr[2], READ_ONLY, TEXT_FILE)
+ sd = stropen (Memc[newexp], SZ_COMMAND, WRITE_ONLY)
+ call fcopyo (fd, sd)
+ call close (fd)
+ call strclose (sd)
+
+ # Replace the newlines with blanks
+
+ ch = newexp
+ repeat {
+ ic = stridx (nl, Memc[ch])
+ if (ic == 0)
+ break
+ ch = ch + ic
+ Memc[ch-1] = ' '
+ }
+ }
+
+ orow = 1
+ first = 1
+ last = tbpsta (itp, TBL_NROWS)
+
+ while (first <= last) {
+ irow = tbl_search (itp, Memc[newexp], first, last)
+ if (irow < 1)
+ break
+
+ call tbrcpy (itp, otp, irow, orow)
+ first = irow + 1
+ orow = orow + 1
+ }
+
+ if (irow == ERR)
+ call error (SYNTAX, badtype)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tselect/tselect.x b/pkg/utilities/nttools/tselect/tselect.x
new file mode 100644
index 00000000..266753c5
--- /dev/null
+++ b/pkg/utilities/nttools/tselect/tselect.x
@@ -0,0 +1,83 @@
+include <fset.h> # to check whether I/O is redirected
+
+define SYNTAX 1
+
+# TSELECT -- Create a new table from selected rows of an old table
+#
+# B.Simon 7-Oct-1987 First Code
+# Phil Hodge 7-Sep-1988 Change parameter names for tables.
+# Phil Hodge 4-Oct-1995 Use table name template routines tbnopenp, etc.
+# B.Simon 25-Aug-1998 Changed to write directly to output table
+# Phil Hodge 8-Apr-1999 Call tbfpri.
+# Phil Hodge 9-Jun-1999 Set input/output to STDIN/STDOUT if redirected.
+
+procedure t_tselect()
+
+pointer ilist # Input table name template
+pointer olist # Output table name template
+pointer expr # Expression used to select rows
+#--
+int junk
+int phu_copied # set by tbfpri and ignored
+pointer sp, itp, otp, intable, outtable
+
+string nomatch "Number of input tables must match output tables"
+
+int fstati()
+int tbnget(), tbnlen()
+pointer tbtopn(), tbnopenp(), tbnopen()
+
+begin
+ # Allocate stack memory for strings
+
+ call smark (sp)
+ call salloc (intable, SZ_FNAME, TY_CHAR)
+ call salloc (outtable, SZ_FNAME, TY_CHAR)
+ call salloc (expr, SZ_LINE, TY_CHAR)
+
+ # Read the task parameters
+
+ if (fstati (STDIN, F_REDIR) == YES)
+ ilist = tbnopen ("STDIN")
+ else
+ ilist = tbnopenp ("intable")
+
+ if (fstati (STDOUT, F_REDIR) == YES)
+ olist = tbnopen ("STDOUT")
+ else
+ olist = tbnopenp ("outtable")
+
+ call clgstr ("expr", Memc[expr], SZ_LINE)
+
+ # Loop over all table names in the input file name template
+
+ if (tbnlen (ilist) != tbnlen (olist))
+ call error (SYNTAX, nomatch)
+
+ while (tbnget (ilist, Memc[intable], SZ_FNAME) != EOF) {
+ junk = tbnget (olist, Memc[outtable], SZ_FNAME)
+
+ # Open the tables
+
+ itp = tbtopn (Memc[intable], READ_ONLY, NULL)
+ call tbfpri (Memc[intable], Memc[outtable], phu_copied)
+ otp = tbtopn (Memc[outtable], NEW_COPY, itp)
+
+ # Copy header and selected rows to output table
+
+ call tbtcre (otp)
+ call tbhcal (itp, otp)
+ call subset (itp, otp, Memc[expr])
+
+ # Close the tables
+
+ call tbtclo (itp)
+ call tbtclo (otp)
+ }
+
+ # Close the filename template lists
+
+ call tbnclose (ilist)
+ call tbnclose (olist)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tsort.par b/pkg/utilities/nttools/tsort.par
new file mode 100644
index 00000000..b1656bba
--- /dev/null
+++ b/pkg/utilities/nttools/tsort.par
@@ -0,0 +1,5 @@
+table,s,a,,,,"Tables to sort"
+columns,s,a,,,,"Columns to sort on"
+ascend,b,h,yes,,,"Ascending order?"
+casesens,b,h,yes,,,"Case sensitive sort?"
+mode,s,h,"a",,,
diff --git a/pkg/utilities/nttools/tsort/mkpkg b/pkg/utilities/nttools/tsort/mkpkg
new file mode 100644
index 00000000..7e918942
--- /dev/null
+++ b/pkg/utilities/nttools/tsort/mkpkg
@@ -0,0 +1,14 @@
+# Update the tsort application code in the ttools package library
+# Author: B.Simon, 25-NOV-1987
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ tblextsort.x <tbset.h>
+ tblintsort.x
+ tblmaxrow.x <tbset.h> <mach.h>
+ tsort.x <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/tsort/tblextsort.x b/pkg/utilities/nttools/tsort/tblextsort.x
new file mode 100644
index 00000000..48981179
--- /dev/null
+++ b/pkg/utilities/nttools/tsort/tblextsort.x
@@ -0,0 +1,496 @@
+include <tbset.h>
+
+define MERGEORDER 15
+
+# TBL_EXTSORT -- External table sort based on Software Tools
+#
+# B.Simon 21-Feb-91 First Code
+# B.Simon 15-Mar-00 Modified to speed up code
+# Phil Hodge 10-Sep-04 Add new procedure tut_replace, and call it
+# instead of tbtdel/tbtren; use tbrcsc instead
+# of tbrcpy in tut_cpytab.
+# Phil Hodge 15-Sep-04 Make 'heap' an array of one, because it is
+# declared to be an array in tut_deltab.
+# Copy the original table one set of rows at a
+# time to an "srt_cpy" temp table, and generate
+# the sorted index array from that; this is to
+# work around a file I/O buffer problem when
+# sorting an STSDAS-format table.
+# Phil Hodge 6-Oct-05 Find column pointers in heap table, instead
+# of using colptr.
+# Remove tp from calling sequence of tut_opntab.
+
+procedure tbl_extsort (tp, numptr, colptr, maxrow, casesens, ascend)
+
+pointer tp # u: Table descriptor
+int numptr # i: Number of columns to sort on (size of colptr)
+pointer colptr[ARB] # i: Array of column descriptors
+int maxrow # i: Maximum number of rows to sort at one time
+bool casesens # i: Sort is case sensitive
+bool ascend # i: Sort in ascending order
+#--
+bool fold
+int irow, mrow, nrow, ntab
+int low, high, limit
+pointer sp, index, tmproot, tmpname, tabname
+pointer otp, heap[1], itp[MERGEORDER]
+# These are for a copy of a portion of the original table.
+pointer cpyname, tp_cpy[1]
+pointer cp_cpy # column descriptors in srt_cpy temporary table
+pointer cp_heap # column descriptors in heap temporary table
+
+pointer tbtopn(), tut_maktab()
+int tbpsta()
+
+begin
+ # Allocate dynamic memory for temporary strings
+
+ call smark (sp)
+ call salloc (tmproot, SZ_FNAME, TY_CHAR)
+ call salloc (tmpname, SZ_FNAME, TY_CHAR)
+ call salloc (tabname, SZ_FNAME, TY_CHAR)
+ call salloc (cpyname, SZ_FNAME, TY_CHAR) # the srt_cpy table
+
+ call salloc (cp_cpy, numptr, TY_POINTER)
+ call salloc (cp_heap, numptr, TY_POINTER)
+
+ # Initialize variables for external sort
+
+ high = 0
+ fold = ! casesens
+ call malloc (index, maxrow, TY_INT)
+
+ # This root name is used only for the srt_cpy temporary table.
+ # Create the srt_cpy temporary table, and find the pointers to
+ # column descriptors corresponding to colptr.
+ call mktemp ("tmp$srt_cpy", Memc[tmproot], SZ_FNAME)
+ tp_cpy[1] = tut_maktab (Memc[tmproot], 0, tp)
+ call tut_fndcol (colptr, tp_cpy, Memi[cp_cpy], numptr)
+
+ # This rootname is used for all the other temporary tables.
+ call mktemp ("tmp$srt", Memc[tmproot], SZ_FNAME)
+
+ # Extract one buffer's worth of rows from original table to the
+ # srt_cpy temporary table, generate a sorted index array, and
+ # copy/sort to another temporary table.
+
+ nrow = tbpsta (tp, TBL_NROWS)
+ for (irow = 1; irow <= nrow; irow = irow + maxrow) {
+
+ mrow = min (maxrow, nrow-irow+1)
+
+ # Extract rows to the srt_cpy table, without changing the order.
+ call tut_setidx (irow, mrow, Memi[index])
+ call tut_cpytab (tp, tp_cpy[1], true, mrow, Memi[index])
+ call tbtflu (tp_cpy[1]) # flush so we can read the table
+
+ # Generate the index array for the srt_cpy table.
+ call tut_setidx (1, mrow, Memi[index])
+ call tbtsrt (tp_cpy[1], numptr, Memi[cp_cpy],
+ fold, mrow, Memi[index])
+
+ # Copy (in sorted order) the srt_cpy table to a temporary table.
+ high = high + 1
+ otp = tut_maktab (Memc[tmproot], high, tp)
+ call tut_cpytab (tp_cpy[1], otp, ascend, mrow, Memi[index])
+ call tbtclo (otp)
+ }
+ call tut_deltab (tp_cpy, 1) # done with the srt_cpy table
+
+ # Merge the temporary tables into a single sorted table
+
+ heap[1] = tut_maktab (Memc[tmproot], 0, tp)
+ call tut_fndcol (colptr, heap[1], Memi[cp_heap], numptr)
+
+ for (low = 1; low < high; low = low + MERGEORDER) {
+ limit = min (low+MERGEORDER-1, high)
+ ntab = limit - low + 1
+
+ call tut_opntab (Memc[tmproot], low, limit, itp)
+ high = high + 1
+
+ otp = tut_maktab (Memc[tmproot], high, tp)
+ call tut_mrgtab (itp, ntab, numptr,
+ fold, ascend, heap[1], Memi[cp_heap], otp)
+
+ call tut_deltab (itp, ntab)
+ # We really only need the name of the last table created.
+ call tbtnam (otp, Memc[tmpname], SZ_FNAME)
+ call tbtclo (otp)
+ }
+ call tut_deltab (heap, 1)
+
+ call tbtnam (tp, Memc[tabname], SZ_FNAME)
+
+ # Copy sorted temporary table to original table, and delete
+ # temporary table
+ otp = tbtopn (Memc[tmpname], READ_ONLY, NULL)
+ call tut_replace (otp, tp)
+ call tbtclo (tp)
+ call tbtclo (otp)
+ call tbtdel (Memc[tmpname])
+
+ # Free dynamic memory
+
+ call mfree (index, TY_INT)
+ call sfree (sp)
+end
+
+
+#-----------------------------------------------------------------------#
+# #
+# These procedures are utility routines used by tbl_extsort() #
+# They should not be called by other routines #
+# #
+#-----------------------------------------------------------------------#
+
+# TUT_FNDCOL -- Get pointers to column descriptors
+
+# Get the pointers to column descriptors for the srt_cpy temporary table.
+# Use the column name rather than number for the original table to allow
+# for the possibility that the column numbers are not the same in both
+# tables, e.g. if a column selector was used with the original table name.
+
+procedure tut_fndcol (colptr, tp_cpy, cp_cpy, numptr)
+
+pointer colptr[ARB] # i: Array of column descriptors in original table
+pointer tp_cpy # i: Descriptor for the srt_cpy temporary table
+pointer cp_cpy[ARB] # o: Array of column descriptors in tp_cpy table
+int numptr # i: Number of columns in colptr and cp_cpy arrays
+#--
+char colname[SZ_COLNAME]
+int colnum
+
+begin
+ do colnum = 1, numptr {
+ call tbcigt (colptr[colnum], TBL_COL_NAME, colname, SZ_COLNAME)
+ call tbcfnd1 (tp_cpy, colname, cp_cpy[colnum])
+ }
+end
+
+# TUT_CPYTAB -- Copy sorted rows to temporary table
+
+procedure tut_cpytab (tp, otp, ascend, nrow, index)
+
+pointer tp # i: Input table descriptor
+pointer otp # i: Output table descriptor
+bool ascend # i: Write output in ascending sort order?
+int nrow # i: Number of rows to write
+int index[ARB] # i: Array of row indices
+#--
+char colname[SZ_COLNAME]
+pointer cp, ocp
+int ncols, colnum
+int irow
+pointer tbcnum()
+int tbpsta()
+
+begin
+ # Number of columns in temporary table
+ ncols = tbpsta (otp, TBL_NCOLS)
+ call malloc (cp, ncols, TY_POINTER)
+ call malloc (ocp, ncols, TY_POINTER)
+
+ # Get pointers to column descriptors
+ do colnum = 1, ncols {
+ Memi[ocp+colnum-1] = tbcnum (otp, colnum)
+ call tbcigt (Memi[ocp+colnum-1], TBL_COL_NAME, colname, SZ_COLNAME)
+ call tbcfnd1 (tp, colname, Memi[cp+colnum-1])
+ }
+
+ if (ascend) {
+ do irow = 1, nrow {
+ call tbrcsc (tp, otp, Memi[cp], Memi[ocp],
+ index[irow], irow, ncols)
+ }
+ } else {
+ do irow = nrow, 1, -1 {
+ call tbrcsc (tp, otp, Memi[cp], Memi[ocp],
+ index[irow], nrow-irow+1, ncols)
+ }
+ }
+
+ call mfree (cp, TY_POINTER)
+ call mfree (ocp, TY_POINTER)
+end
+
+# TUT_REPLACE -- Copy sorted rows to temporary table
+# This copies each row to the original table, without first deleting
+# the original table.
+
+procedure tut_replace (otp, tp_orig)
+
+pointer otp # i: Descriptor for sorted temporary table
+pointer tp_orig # i: Descriptor for original table
+#--
+pointer sp
+pointer ocp, cp_orig
+char colname[SZ_COLNAME]
+int nrows, ncols
+int row, colnum
+pointer tbcnum()
+int tbpsta()
+
+begin
+ call smark (sp)
+
+ ncols = tbpsta (otp, TBL_NCOLS)
+ call salloc (ocp, ncols, TY_POINTER)
+ call salloc (cp_orig, ncols, TY_POINTER)
+
+ # Get the pointers to column descriptors for the sorted and original
+ # tables.
+ do colnum = 1, ncols {
+ Memi[ocp+colnum-1] = tbcnum (otp, colnum)
+ call tbcigt (Memi[ocp+colnum-1], TBL_COL_NAME, colname, SZ_COLNAME)
+ call tbcfnd1 (tp_orig, colname, Memi[cp_orig+colnum-1])
+ }
+
+ nrows = tbpsta (otp, TBL_NROWS)
+ do row = 1, nrows {
+ call tbrcsc (otp, tp_orig, Memi[ocp], Memi[cp_orig],
+ row, row, ncols)
+ }
+
+ call sfree (sp)
+end
+
+# TUT_DELTAB -- Delete a group of temporary tables
+
+procedure tut_deltab (itp, ntab)
+
+pointer itp[ARB] # i: Array of table descriptors
+int ntab # i: Number of tables to delete
+#--
+int itab
+pointer sp, tmpname
+
+begin
+ call smark (sp)
+ call salloc (tmpname, SZ_FNAME, TY_CHAR)
+
+ do itab = 1, ntab {
+ call tbtnam (itp[itab], Memc[tmpname], SZ_FNAME)
+ call tbtclo (itp[itab])
+ call tbtdel (Memc[tmpname])
+ }
+
+ call sfree (sp)
+end
+
+# TUT_MAKNAM -- Construct a table name by appending a suffix to the root
+
+procedure tut_maknam (tmproot, index, tmpname, maxch)
+
+char tmproot[ARB] # i: Table name root
+int index # i: Number to use as suffix
+char tmpname[ARB] # o: Full table name
+int maxch # i: Declared length of table name
+#--
+int ic
+
+int gstrcpy(), itoc()
+
+begin
+ ic = gstrcpy (tmproot, tmpname, maxch) + 1
+ ic = itoc (index, tmpname[ic], maxch-ic) + ic
+ ic = gstrcpy (".tab", tmpname[ic], maxch-ic) +ic
+ tmpname[ic] = EOS
+end
+
+# TUT_MAKTAB -- Create a table for temporary storage
+
+pointer procedure tut_maktab (tmproot, index, tp)
+
+char tmproot[ARB] # i: Table name root
+int index # i: Number to use as suffix
+pointer tp # i: Table to use as template
+#--
+pointer sp, otp, tmpname
+
+pointer tbtopn()
+
+begin
+ call smark (sp)
+ call salloc (tmpname, SZ_FNAME, TY_CHAR)
+
+ call tut_maknam (tmproot, index, Memc[tmpname], SZ_FNAME)
+
+ iferr {
+ otp = tbtopn (Memc[tmpname], NEW_COPY, tp)
+ call tbpset (otp, TBL_WHTYPE, TBL_TYPE_S_ROW)
+ call tbtcre (otp)
+ call tbpset (otp, TBL_ADVICE, SEQUENTIAL)
+ } then {
+ call error (1, "Can't create temporary table used for sorting")
+ }
+
+ call sfree (sp)
+ return (otp)
+end
+
+# TUT_MRGTAB -- Merge a set of tables into a single table
+
+procedure tut_mrgtab (itp, ntab, numptr, fold, ascend, heap, cp, otp)
+
+pointer itp[ARB] # i: Array of input table descriptors
+int ntab # i: Number of input tables
+int numptr # i: Number of columns to merge on
+bool fold # i: Fold case when merging?
+bool ascend # i: Merge in ascending order?
+pointer heap # i: Heap array descriptor
+pointer cp[ARB] # i: Array of column descriptors in heap table
+pointer otp # i: Output table descriptor
+#--
+int nindex, itab, idx, jdx, temp
+int irow[MERGEORDER], nrow[MERGEORDER], index[MERGEORDER]
+
+int tbpsta()
+
+begin
+ # Create heap by copying one row from each table
+
+ nindex = 0
+ do itab = 1, ntab {
+ irow[itab] = 1
+ nrow[itab] = tbpsta (itp[itab], TBL_NROWS)
+
+ if (nrow[itab] > 0) {
+ call tbrcpy (itp[itab], heap, 1, itab)
+ nindex = nindex + 1
+ index[nindex] = itab
+ }
+ }
+
+ # Put the heap in sort order
+
+ call tbtsrt (heap, numptr, cp, fold, nindex, index)
+ if (!ascend) {
+ idx = 1
+ jdx = nindex
+ while (idx < jdx) {
+ temp = index[idx]
+ index[idx] = index[jdx]
+ index[jdx] = temp
+ idx = idx + 1
+ jdx = jdx - 1
+ }
+ }
+
+ # Copy a row from the heap, replacing it by a new row
+
+ for (idx = 1; nindex > 0; idx = idx + 1) {
+ itab = index[1]
+ call tbrcpy (heap, otp, itab, idx)
+
+ if (irow[itab] < nrow[itab]) {
+ irow[itab] = irow[itab] + 1
+ call tbrcpy (itp[itab], heap, irow[itab], itab)
+ } else {
+ index[1] = index[nindex]
+ nindex = nindex - 1
+ }
+
+ call tut_reheap (heap, numptr, cp, fold, ascend,
+ nindex, index)
+ }
+end
+
+# TUT_OPNTAB -- Open a group of temporary tables
+
+procedure tut_opntab (tmproot, low, limit, itp)
+
+char tmproot[ARB] # i: Temporary file name root
+int low # i: First table to open
+int limit # i: Last table to open
+pointer itp[ARB] # o: Array of table descriptors
+#--
+int itab
+pointer sp, tmpname
+
+int tbtopn()
+
+begin
+ call smark (sp)
+ call salloc (tmpname, SZ_FNAME, TY_CHAR)
+
+ do itab = 1, limit-low+1 {
+ call tut_maknam (tmproot, low+itab-1, Memc[tmpname], SZ_FNAME)
+ iferr (itp[itab] = tbtopn (Memc[tmpname], READ_ONLY, NULL))
+ call error (1, "Can't open temporary table used for sorting")
+ }
+
+ call sfree (sp)
+end
+
+# TUT_REHEAP -- Restore heap to sort order
+
+procedure tut_reheap (heap, numptr, cp, fold, ascend, nindex, index)
+
+pointer heap # i: Heap table descriptor
+int numptr # i: Number of columns to sort on
+pointer cp[ARB] # i: Array of column descriptors in heap table
+bool fold # i: Fold case together?
+bool ascend # i: Put head in ascending order?
+int nindex # i: Number of elements in index array
+int index[ARB] # io: Array of head table indices in sort order
+#--
+int order, irow, jrow, temp
+
+int tbrcmp()
+
+begin
+ # Set the sort order
+
+ if (ascend)
+ order = 1
+ else
+ order = -1
+
+ # A heap is organized as a binary tree. The heap is partially
+ # sorted so that a parent is in sort order with respect to its
+ # children. However, siblings are not necessarily in sort order.
+ # The children of index[irow] are at index[2*irow] and
+ # index[2*irow+1].
+
+ for (irow = 1; 2*irow <= nindex; irow = jrow) {
+
+ # Find the smaller (larger) of the two children
+
+ jrow = 2 * irow
+ if (jrow < nindex) {
+ if (tbrcmp (heap, numptr, cp, fold,
+ index[jrow], index[jrow+1]) == order)
+ jrow = jrow + 1
+ }
+
+ # If child is smaller (larger) than parent,
+ # exhange their indices
+
+ if (tbrcmp (heap, numptr, cp, fold,
+ index[irow], index[jrow]) != order) {
+ break
+
+ } else {
+ temp = index[irow]
+ index[irow] = index[jrow]
+ index[jrow] = temp
+ }
+ }
+
+end
+
+# TUT_SETIDX -- Set up the index array
+
+procedure tut_setidx (irow, nrow, index)
+
+int irow # i: starting value
+int nrow # i: number of rows in index array
+int index[ARB] # o: index array
+#--
+int jrow
+
+begin
+ do jrow = 1, nrow
+ index[jrow] = irow + jrow - 1
+end
diff --git a/pkg/utilities/nttools/tsort/tblintsort.x b/pkg/utilities/nttools/tsort/tblintsort.x
new file mode 100644
index 00000000..100f17c1
--- /dev/null
+++ b/pkg/utilities/nttools/tsort/tblintsort.x
@@ -0,0 +1,48 @@
+# TBL_INTSORT -- Internal table sort for small tables
+#
+# B.Simon 21-Feb-91 First Code
+# B.Simon 30-Jan-96 Close table in this routine
+
+procedure tbl_intsort (tp, numptr, colptr, casesens, ascend)
+
+pointer tp # u: Table descriptor
+int numptr # i: Number of columns to sort on
+pointer colptr[ARB] # i: Array of column descriptors
+bool casesens # i: Sort is case sensitive
+bool ascend # i: Sort in ascending order
+#--
+bool fold
+int nindex, idx, jdx, temp
+pointer index
+
+begin
+ # Call the sort routine in the table library
+
+ fold = ! casesens
+ call allrows (tp, nindex, index)
+ call tbtsrt (tp, numptr, colptr, fold, nindex, Memi[index])
+
+ # Reorder the index array if ascend is false
+
+ if (! ascend) {
+ idx = 1
+ jdx = nindex
+ while (idx < jdx) {
+ temp = Memi[index+idx-1]
+ Memi[index+idx-1] = Memi[index+jdx-1]
+ Memi[index+jdx-1] = temp
+ idx = idx + 1
+ jdx = jdx - 1
+ }
+ }
+
+ # Reorder the table according to the values in the index array
+
+ call reorder (tp, nindex, Memi[index])
+
+ # Close the table and free dynamic memory
+
+ call tbtclo (tp)
+ call mfree (index, TY_INT)
+
+end
diff --git a/pkg/utilities/nttools/tsort/tblmaxrow.x b/pkg/utilities/nttools/tsort/tblmaxrow.x
new file mode 100644
index 00000000..28206ff6
--- /dev/null
+++ b/pkg/utilities/nttools/tsort/tblmaxrow.x
@@ -0,0 +1,39 @@
+include <tbset.h>
+
+# TBL_MAXROW -- Compute the number of rows that fit in a buffer
+#
+# B.Simon 06-Mar-91 First Code
+# B.Simon 15-Mar-00 Revised calculation of maxrow
+# B.Simon 24-May-00 Temporary patch to avoid fits problem
+# B.Simon 26-May-00 Restored old version after fix to fits problem
+# Phil Hodge 10-Sep-04 Set lower limit of 5 on maxrow, because it
+# could be unreasonably small (even zero, due
+# to truncation).
+# Phil Hodge 15-Sep-04 Reduce buffer size (maxsize) for STSDAS-format
+# table, because actual buffer size appears to
+# be smaller than the value returned by tbpsta().
+
+int procedure tbl_maxrow (tp)
+
+pointer tp # i: table pointer
+#--
+int tabtype, maxsize, maxrow
+int tbpsta()
+
+begin
+ tabtype = tbpsta (tp, TBL_WHTYPE)
+
+ if (tabtype == TBL_TYPE_S_COL || tabtype == TBL_TYPE_TEXT) {
+
+ maxrow = tbpsta (tp, TBL_NROWS)
+
+ } else {
+ maxsize = tbpsta (tp, TBL_BUFSIZE)
+ if (tabtype == TBL_TYPE_S_ROW)
+ maxsize = maxsize / 2
+ maxrow = maxsize / tbpsta (tp, TBL_ROWLEN_CHAR)
+ maxrow = max (maxrow, 5)
+ }
+
+ return (maxrow)
+end
diff --git a/pkg/utilities/nttools/tsort/tsort.x b/pkg/utilities/nttools/tsort/tsort.x
new file mode 100644
index 00000000..81851631
--- /dev/null
+++ b/pkg/utilities/nttools/tsort/tsort.x
@@ -0,0 +1,98 @@
+include <tbset.h>
+define SYNTAX 1
+
+# TSORT -- Sort a table on several columns at once
+#
+# This task sorts an SDAS format table. The column or columns to sort on are
+# given by the parameter columns, which is a list of column names or column
+# name patterns separated by commas. The most significant column name is the
+# first in the list, subsequent columns are used to break ties. There are two
+# flags, ascend and casesens. If ascend is true, the first row in the output
+# table holds the smallest value if the sorted column is numeric or the first
+# string in alpahabetic order if the sorted column is a character string. If
+# casesens is true, upper case characters precede lower case charaters in sort
+# order. Otherwise, case is not significant in determining the sort order.
+#
+# B.Simon 25-Sep-87 First Code
+# B.Simon 15-Jul-88 Set buffer size to max
+# Phil Hodge 7-Sep-88 Change parameter name for table.
+# Phil Hodge 14-Nov-88 Set advice to sequential instead of
+# setting buffer size.
+# B.Simon 05-Feb-90 Use new internal sort routine
+# B.Simon 21-Feb-91 Use external sort routine
+# Phil Hodge 4-Oct-95 Use table name template routines tbnopenp, etc.
+
+procedure t_tsort()
+
+pointer table # Names of the tables to be sorted
+pointer columns # Column name template
+int maxrow # Maximum number of rows to sort internally
+bool ascend # Ascending sort flag
+bool casesens # Case sensitivity flag
+#--
+int numcol, nrow, numptr
+pointer sp, tp, colptr, list
+
+bool clgetb()
+int tbnget()
+pointer tbnopenp()
+int tbpsta()
+int tbl_maxrow()
+pointer tbtopn()
+
+begin
+ # Allocate stack memory for strings
+
+ call smark (sp)
+ call salloc (table, SZ_FNAME, TY_CHAR)
+ call salloc (columns, SZ_LINE, TY_CHAR)
+
+ # Read the task parameters
+
+ list = tbnopenp ("table")
+ call clgstr ("columns", Memc[columns], SZ_LINE)
+ ascend = clgetb ("ascend")
+ casesens = clgetb ("casesens")
+
+ # Loop over all table names in the file name template
+
+ while (tbnget (list, Memc[table], SZ_FNAME) != EOF) {
+
+ # Open the table
+
+ tp = tbtopn (Memc[table], READ_WRITE, NULL)
+
+ # Set buffer size to a larger value.
+
+ call tbpset (tp, TBL_ADVICE, SEQUENTIAL)
+
+ # Create an array of column pointers from the column template
+
+ numcol = tbpsta (tp, TBL_NCOLS)
+ nrow = tbpsta (tp, TBL_NROWS)
+
+ call malloc (colptr, numcol, TY_INT)
+ call tctexp (tp, Memc[columns], numcol, numptr, Memi[colptr])
+
+ if (numptr == 0)
+ call error (SYNTAX, "Column(s) not found in table")
+
+ # Choose between the internal and external sort routines
+ # Table is closed by sort routine
+
+ maxrow = tbl_maxrow (tp)
+ if (nrow <= maxrow)
+ call tbl_intsort (tp, numptr, Memi[colptr], casesens, ascend)
+ else
+ call tbl_extsort (tp, numptr, Memi[colptr], maxrow,
+ casesens, ascend)
+
+ call mfree (colptr, TY_INT)
+
+ }
+
+ # Close the filename template list
+
+ call tbnclose (list)
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tstat.par b/pkg/utilities/nttools/tstat.par
new file mode 100644
index 00000000..ad947bda
--- /dev/null
+++ b/pkg/utilities/nttools/tstat.par
@@ -0,0 +1,21 @@
+intable,s,a,"",,,"input tables"
+column,s,a,"",,,"column in input tables"
+outtable,s,h,"STDOUT",,,"output table or STDOUT"
+lowlim,r,h,INDEF,,,"values below this are ignored"
+highlim,r,h,INDEF,,,"values above this are ignored"
+rows,s,h,"-",,,"range of rows to use for statistics"
+n_tab,s,h,"table",,,"column name for name of input table"
+n_nam,s,h,"column",,,"column name for name of input column"
+n_nrows,s,h,"nrows",,,"column name for number of good rows"
+n_mean,s,h,"mean",,,"column name for mean"
+n_stddev,s,h,"stddev",,,"column name for standard deviation"
+n_median,s,h,"median",,,"column name for median"
+n_min,s,h,"min",,,"column name for minimum"
+n_max,s,h,"max",,,"column name for maximum"
+nrows,i,h,,,,"number of rows"
+mean,r,h,,,,"mean value"
+stddev,r,h,,,,"standard deviation"
+median,r,h,,,,"median value"
+vmin,r,h,,,,"minimum"
+vmax,r,h,,,,"maximum"
+mode,s,h,"al"
diff --git a/pkg/utilities/nttools/tstat/mkpkg b/pkg/utilities/nttools/tstat/mkpkg
new file mode 100644
index 00000000..f708c769
--- /dev/null
+++ b/pkg/utilities/nttools/tstat/mkpkg
@@ -0,0 +1,13 @@
+# Update the thistogram application code in the ttools package library
+# Author: Phil Hodge, 2-DEC-1988
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ thistogram.x <error.h> <tbset.h> "thistogram.h"
+ thoptions.x "thistogram.h"
+ tstat.x <tbset.h>
+ ;
diff --git a/pkg/utilities/nttools/tstat/thistogram.h b/pkg/utilities/nttools/tstat/thistogram.h
new file mode 100644
index 00000000..5c2c0910
--- /dev/null
+++ b/pkg/utilities/nttools/tstat/thistogram.h
@@ -0,0 +1,8 @@
+# thistogram.h
+define NPAR 6 # there are six parameters altogether
+define NBINS 1 # got[NBINS] = true means we have a value for nbins
+define VLOW 2
+define VHIGH 3
+define DX 4
+define CLOW 5
+define CHIGH 6
diff --git a/pkg/utilities/nttools/tstat/thistogram.x b/pkg/utilities/nttools/tstat/thistogram.x
new file mode 100644
index 00000000..7470e1a5
--- /dev/null
+++ b/pkg/utilities/nttools/tstat/thistogram.x
@@ -0,0 +1,348 @@
+include <error.h> # defines EA_WARN
+include <fset.h> # to check whether input or output is redirected
+include <tbset.h>
+include "thistogram.h" # defines NPAR, etc.
+
+define MAX_RANGES (SZ_LINE/2) # max number of ranges of row numbers
+
+# thistogram -- make a histogram of a table column
+#
+# Phil Hodge, 2-Dec-1988 Task created.
+# Phil Hodge, 12-Jan-1989 th_mk_hist: ignore values that are out of range
+# Phil Hodge, 17-Mar-1994 Include parameters dx, clow, chigh.
+# Phil Hodge, 3-Oct-1995 Modify to use tbn instead of fnt.
+# Phil Hodge, 8-Apr-1999 Call tbfpri.
+# Phil Hodge, 8-Jun-1999 Set input/output to STDIN/STDOUT if redirected.
+
+procedure thistogram()
+
+pointer inlist, outlist # scr for input & output lists of names
+char colname[SZ_COLNAME] # column name
+int t_nbins # number of bins
+double t_vlow, t_vhigh # lower & upper limits for histogram
+double t_dx # bin width
+double t_clow, t_chigh # centers of first and last bins
+char outcolx[SZ_COLNAME] # column name for indep var for histogram
+char outcoly[SZ_COLNAME] # column name for dependent var for histogram
+#--
+pointer sp
+pointer itp, otp # ptr to table descriptor
+pointer cptr # ptr to column descriptor
+pointer ocpx, ocpy # ptr to col descr for output columns
+pointer intab, outtab # scr for names of input & output tables
+pointer range_string # string which gives ranges of row numbers
+pointer val, counts # scr for histogram: indep & dep var
+
+# These six parameters are copied from t_... in each loop.
+int nbins
+double vlow, vhigh, dx, clow, chigh
+
+pointer list1, list2
+int i, junk
+int nrows # number of rows included and not INDEF
+int phu_copied # set by tbfpri and ignored
+bool listout # is the output ASCII rather than a table?
+bool got[NPAR] # flags to specify what we have got
+bool find_datamin # true if we need to find minimum data value
+bool find_datamax # true if we need to find maximum data value
+pointer tbtopn()
+double clgetd()
+int fstati()
+pointer tbnopen()
+int clgeti(), tbnget(), tbnlen()
+bool streq()
+
+begin
+ # Allocate scratch for lists of names and for table names.
+ call smark (sp)
+ call salloc (inlist, SZ_FNAME, TY_CHAR)
+ call salloc (outlist, SZ_FNAME, TY_CHAR)
+ call salloc (intab, SZ_FNAME, TY_CHAR)
+ call salloc (outtab, SZ_FNAME, TY_CHAR)
+ call salloc (range_string, SZ_FNAME, TY_CHAR)
+
+ # Get task parameters.
+
+ if (fstati (STDIN, F_REDIR) == YES)
+ call strcpy ("STDIN", Memc[inlist], SZ_FNAME)
+ else
+ call clgstr ("intable", Memc[inlist], SZ_FNAME)
+
+ if (fstati (STDOUT, F_REDIR) == YES)
+ call strcpy ("STDOUT", Memc[outlist], SZ_FNAME)
+ else
+ call clgstr ("outtable", Memc[outlist], SZ_FNAME)
+
+ call clgstr ("column", colname, SZ_COLNAME)
+
+ # Some of these six parameters may be INDEF. The "t_" prefix
+ # means these are task parameters; they are assigned to variables
+ # (same name but without the "t_") in the loop over tables, and
+ # those variables may be modified within the loop.
+ t_nbins = clgeti ("nbins")
+ t_vlow = clgetd ("lowval")
+ t_vhigh = clgetd ("highval")
+ t_dx = clgetd ("dx")
+ t_clow = clgetd ("clow")
+ t_chigh = clgetd ("chigh")
+
+ call clgstr ("rows", Memc[range_string], SZ_FNAME)
+
+ listout = streq (Memc[outlist], "STDOUT") # ASCII output?
+ if ( ! listout ) {
+ call clgstr ("outcolx", outcolx, SZ_COLNAME)
+ call clgstr ("outcoly", outcoly, SZ_COLNAME)
+ }
+
+ if (!IS_INDEF(t_dx))
+ if (t_dx <= 0.d0)
+ call error (1, "dx must not be less than or equal to zero")
+
+ # These parameters are interdependent, so compute what was not
+ # specified from those that were, as far as we can.
+ call th_options (t_nbins, t_vlow, t_vhigh, t_dx, t_clow, t_chigh,
+ got, find_datamin, find_datamax)
+
+ # Expand the input table list.
+ list1 = tbnopen (Memc[inlist])
+
+ if ( ! listout ) {
+ # Expand the output table list.
+ list2 = tbnopen (Memc[outlist])
+ if (tbnlen (list1) != tbnlen (list2)) {
+ call tbnclose (list1)
+ call tbnclose (list2)
+ call error (1,
+ "Number of input and output tables not the same")
+ }
+ }
+
+ # Do for each input table.
+ while (tbnget (list1, Memc[intab], SZ_FNAME) != EOF) {
+
+ # These may be modified within this loop by th_limits.
+ nbins = t_nbins
+ vlow = t_vlow
+ vhigh = t_vhigh
+ dx = t_dx
+ clow = t_clow
+ chigh = t_chigh
+
+ itp = tbtopn (Memc[intab], READ_ONLY, NULL)
+ call tbcfnd (itp, colname, cptr, 1)
+ if (cptr == NULL) {
+ call tbtclo (itp)
+ call eprintf ("column not found in %s\n")
+ call pargstr (Memc[intab])
+ if ( ! listout ) # skip next output table
+ junk = tbnget (list2, Memc[outtab], SZ_FNAME)
+ next
+ }
+
+ # Get lower & upper limits for the histogram.
+ iferr {
+ call th_limits (itp, cptr, Memc[range_string],
+ nbins, vlow, vhigh, dx, clow, chigh,
+ got, find_datamin, find_datamax)
+ } then {
+ call erract (EA_WARN)
+ call eprintf ("Table `%s' will be skipped.\n")
+ call pargstr (Memc[intab])
+ call tbtclo (itp)
+ next
+ }
+
+ # Get scratch space for the histogram.
+ call malloc (val, nbins, TY_DOUBLE)
+ call malloc (counts, nbins, TY_INT)
+
+ # Make the histogram.
+ call th_mk_hist (itp, cptr, nbins, vlow, vhigh, dx,
+ Memc[range_string], Memd[val], Memi[counts], nrows)
+
+ if ( listout ) {
+ call printf ("# %d rows %s\n")
+ call pargi (nrows)
+ call pargstr (Memc[intab])
+ do i = 1, nbins {
+ call printf ("%15.7g %8d\n")
+ call pargd (Memd[val+i-1])
+ call pargi (Memi[counts+i-1])
+ }
+ } else {
+
+ # Create output table & define columns.
+ junk = tbnget (list2, Memc[outtab], SZ_FNAME)
+ call tbfpri (Memc[intab], Memc[outtab], phu_copied)
+ otp = tbtopn (Memc[outtab], NEW_FILE, NULL)
+ call tbcdef (otp, ocpx,
+ outcolx, "", "", TY_DOUBLE, 1, 1)
+ call tbcdef (otp, ocpy,
+ outcoly, "histogram", "", TY_INT, 1, 1)
+ call tbtcre (otp)
+
+ # Put info records in the header.
+ call tbhadt (otp, "intable", Memc[intab])
+ call tbhadt (otp, "colname", colname)
+ call tbhadi (otp, "nrows", nrows)
+
+ # Write the values into the output table, and close it.
+ call tbcptd (otp, ocpx, Memd[val], 1, nbins)
+ call tbcpti (otp, ocpy, Memi[counts], 1, nbins)
+ call tbtclo (otp)
+ }
+ call tbtclo (itp)
+
+ call mfree (counts, TY_INT)
+ call mfree (val, TY_DOUBLE)
+ }
+ call tbnclose (list1)
+ if ( ! listout )
+ call tbnclose (list2)
+ call sfree (sp)
+end
+
+# th_limits -- get limits for histogram
+# This routine determines the lower and upper limits of data values for
+# making a histogram. If either of the input values v1 or v2 is not INDEF
+# (i.e. if it was specified by the user), then that value is returned as
+# vlow or vhigh respectively. If either or both are INDEF the minimum and
+# maximum values in the table column are gotten, and the minimum and maximum
+# are extended a little to ensure that the endpoints are included in the
+# histogram. The range is extended by (max - min) / (nbins - 1) / 2
+# on each end. The parameters nbins, vlow, vhigh, and dx may be updated.
+
+procedure th_limits (tp, cptr, range_str,
+ nbins, vlow, vhigh, dx, clow, chigh,
+ got, find_datamin, find_datamax)
+
+pointer tp # i: ptr to table descriptor
+pointer cptr # i: ptr to column descriptor
+char range_str[ARB] # i: range of row numbers
+int nbins # io: number of bins
+double vlow, vhigh # io: lower and upper limits
+double dx # io: bin width
+double clow, chigh # i: centers of low and high bins
+bool got[NPAR] # i: flags to specify what we have got
+bool find_datamin # i: true if we need to find minimum data value
+bool find_datamax # i: true if we need to find maximum data value
+#--
+double value # an element gotten from the table
+double vmin, vmax # min & max values in the column
+int nrows # number of rows in table
+int row # row number
+int ranges[3,MAX_RANGES] # ranges of row numbers
+int nvalues # returned by decode_ranges and ignored
+int stat # returned by get_next_number
+bool done
+int decode_ranges(), get_next_number(), tbpsta()
+
+begin
+ if (find_datamin || find_datamax) {
+
+ # We must determine either the minimum or maximum or both.
+
+ if (decode_ranges (range_str, ranges, MAX_RANGES, nvalues) != OK)
+ call error (1, "bad range of row numbers")
+ nrows = tbpsta (tp, TBL_NROWS)
+
+ # First get initial values for min & max in column. We can't just
+ # take the first value because it might be INDEF.
+ row = 0 # initialize get_next_number
+ stat = get_next_number (ranges, row) # get first row number
+ done = (stat == EOF) || (row > nrows)
+ while ( ! done ) {
+ call tbegtd (tp, cptr, row, value)
+ if ( IS_INDEFD(value) ) {
+ # get next row number
+ stat = get_next_number (ranges, row)
+ if ((stat == EOF) || (row > nrows))
+ call error (1, "all values are INDEF")
+ } else {
+ vmin = value
+ vmax = value
+ done = true
+ }
+ }
+
+ # Update min & max values.
+ stat = get_next_number (ranges, row) # get next row number
+ done = (stat == EOF) || (row > nrows)
+ while ( ! done ) {
+ call tbegtd (tp, cptr, row, value)
+ if ( !IS_INDEFD(value) ) {
+ if (value < vmin)
+ vmin = value
+ if (value > vmax)
+ vmax = value
+ }
+ stat = get_next_number (ranges, row) # get next row number
+ if ((stat == EOF) || (row > nrows))
+ done = true
+ }
+
+ # Update parameter values.
+ call th_update (vmin, vmax, nbins, vlow, vhigh, dx, clow, chigh,
+ got, find_datamin, find_datamax)
+ }
+end
+
+# th_mk_hist -- make the histogram
+
+procedure th_mk_hist (tp, cptr, nbins, vlow, vhigh, dx, range_str,
+ val, counts, nrows)
+
+pointer tp # i: ptr to table descriptor
+pointer cptr # i: ptr to column descriptor
+int nbins # i: number of bins
+double vlow # i: min value for histogram
+double vhigh # i: max value for histogram
+double dx # i: bin width
+char range_str[ARB] # i: range of row numbers
+double val[nbins] # o: array of values at center of bins
+int counts[nbins] # o: the histogram, array of counts within bins
+int nrows # o: number of rows in range_str and value within limits
+#--
+double value # an element gotten from the table
+int bin # bin number for output
+int totalrows # total number of rows in table
+int row # row number
+int i
+int ranges[3,MAX_RANGES] # ranges of row numbers
+int nvalues # returned by decode_ranges and ignored
+int stat # returned by get_next_number
+bool done
+int decode_ranges(), get_next_number(), tbpsta()
+
+begin
+ totalrows = tbpsta (tp, TBL_NROWS)
+
+ # Initialize the range of row numbers.
+ if (decode_ranges (range_str, ranges, MAX_RANGES, nvalues) != OK)
+ call error (1, "bad range of row numbers")
+
+ do i = 1, nbins {
+ val[i] = vlow + (i - 0.5d0) * dx # value at center of bin
+ counts[i] = 0 # initialize histogram
+ }
+
+ nrows = 0 # initialize counter
+ row = 0 # initialize get_next_number
+ stat = get_next_number (ranges, row) # get first row number
+ done = (stat == EOF) || (row > totalrows)
+ while ( ! done ) {
+ call tbegtd (tp, cptr, row, value)
+ if ( ! IS_INDEF(value) ) {
+ if (value >= vlow && value < vhigh) {
+ if (dx > 0.d0)
+ bin = int ((value - vlow) / dx) + 1
+ else
+ bin = 1
+ counts[bin] = counts[bin] + 1
+ nrows = nrows + 1
+ }
+ }
+ stat = get_next_number (ranges, row) # get next row number
+ done = (stat == EOF) || (row > totalrows)
+ }
+end
diff --git a/pkg/utilities/nttools/tstat/thoptions.x b/pkg/utilities/nttools/tstat/thoptions.x
new file mode 100644
index 00000000..5b9ce639
--- /dev/null
+++ b/pkg/utilities/nttools/tstat/thoptions.x
@@ -0,0 +1,343 @@
+include "thistogram.h" # defines NPAR, etc.
+
+# This file contains th_options and th_update.
+#
+# Phil Hodge, 18-Mar-1994 Subroutines created.
+
+# th_options -- different options for specifying limits
+# There are different ways to specify the limits and bin spacing. This
+# routine computes some parameters given others, based on the following:
+#
+# dx = (vhigh - vlow) / nbins
+# dx = (chigh - clow) / (nbins - 1)
+# clow = vlow + dx / 2
+# chigh = vhigh - dx / 2
+#
+# Note that vlow and vhigh correspond to task parameters lowval and highval.
+
+procedure th_options (nbins, vlow, vhigh, dx, clow, chigh,
+ got, find_datamin, find_datamax)
+
+int nbins # io: number of bins
+double vlow, vhigh # io: lower and upper limits
+double dx # io: bin width
+double clow, chigh # io: centers of low and high bins
+bool got[NPAR] # o: flags to specify what we have got
+bool find_datamin # o: true if we need to find minimum data value
+bool find_datamax # o: true if we need to find maximum data value
+#--
+bool fp_equald()
+
+begin
+ # These flags will be reset below if we determine the values.
+ got[NBINS] = !IS_INDEFI(nbins)
+ got[VLOW] = !IS_INDEFD(vlow)
+ got[VHIGH] = !IS_INDEFD(vhigh)
+ got[DX] = !IS_INDEFD(dx)
+ got[CLOW] = !IS_INDEFD(clow)
+ got[CHIGH] = !IS_INDEFD(chigh)
+
+ # Check whether low value is greater than high value.
+ if (got[VLOW] && got[VHIGH])
+ if (vlow > vhigh)
+ call error (1, "lowval must not be larger than highval")
+ if (got[CLOW] && got[CHIGH])
+ if (clow > chigh)
+ call error (1, "clow must not be larger than chigh")
+
+ # Further checking.
+ if (got[VLOW] && got[CLOW])
+ if (vlow > clow)
+ call error (1, "lowval must not be larger than clow")
+ if (got[CHIGH] && got[VHIGH])
+ if (chigh > vhigh)
+ call error (1, "chigh must not be larger than highval")
+ if (got[VLOW] && got[CHIGH])
+ if (vlow > chigh)
+ call error (1, "lowval must not be larger than chigh")
+ if (got[CLOW] && got[VHIGH])
+ if (clow > vhigh)
+ call error (1, "clow must not be larger than highval")
+
+ # Set flags to specify what (if anything) we must get from the data.
+ # These may be reset below.
+ find_datamin = (!got[VLOW] && !got[CLOW])
+ find_datamax = (!got[VHIGH] && !got[CHIGH])
+
+ if (got[DX]) {
+
+ # Was the lower limit specified by the user?
+ if (got[CLOW]) {
+ if (got[VLOW]) {
+ if (!fp_equald (clow, vlow + dx/2.d0))
+ call error (1, "values of dx, clow, lowval conflict")
+ } else {
+ vlow = clow - dx / 2.d0
+ got[VLOW] = true
+ }
+ } else if (got[VLOW]) {
+ clow = vlow + dx / 2.d0
+ got[CLOW] = true
+ }
+
+ # Was the upper limit specified?
+ if (got[CHIGH]) {
+ if (got[VHIGH]) {
+ if (!fp_equald (chigh, vhigh - dx/2.d0))
+ call error (1, "values of dx, chigh, highval conflict")
+ } else {
+ vhigh = chigh + dx / 2.d0
+ got[VHIGH] = true
+ }
+ } else if (got[VHIGH]) {
+ chigh = vhigh - dx / 2.d0
+ got[CHIGH] = true
+ }
+
+ # Was the number of bins specified?
+ if (got[NBINS]) {
+ if (got[VLOW] && got[VHIGH]) {
+ if (!fp_equald (vhigh - vlow, dx * nbins))
+ call error (1, "specified values for limits conflict")
+ } else if (got[VLOW]) {
+ vhigh = vlow + dx * nbins
+ chigh = vhigh - dx / 2.d0
+ got[VHIGH] = true
+ got[CHIGH] = true
+ find_datamax = false
+ } else if (got[VHIGH]) {
+ vlow = vhigh - dx * nbins
+ clow = vlow + dx / 2.d0
+ got[VLOW] = true
+ got[CLOW] = true
+ find_datamin = false
+ }
+
+ } else if (got[VLOW] && got[VHIGH]) {
+ nbins = nint ((vhigh - vlow) / dx)
+ if (nbins * dx < vhigh - vlow)
+ nbins = nbins + 1 # round up
+ got[NBINS] = true
+ }
+
+ } else if (got[NBINS]) { # but we don't have dx
+
+ if (nbins == 1) {
+ if (!got[VLOW] && !got[VHIGH] && (got[CLOW] || got[CHIGH])) {
+ call eprintf (
+ "nbins = 1, clow or chigh was specified, but dx was not.\n")
+ call error (1, "must specify dx for this case")
+ }
+ }
+
+ if (got[VLOW] && got[VHIGH]) {
+
+ dx = (vhigh - vlow) / double(nbins)
+ got[DX] = true
+ if (got[CLOW]) {
+ if (!fp_equald (clow, vlow + dx/2.d0))
+ call error (1, "clow conflicts with other parameters")
+ } else {
+ clow = vlow + dx / 2.d0
+ got[CLOW] = true
+ }
+ if (got[CHIGH]) {
+ if (!fp_equald (chigh, vhigh - dx/2.d0))
+ call error (1, "chigh conflicts with other parameters")
+ } else {
+ chigh = vhigh - dx / 2.d0
+ got[CHIGH] = true
+ }
+
+ } else if (got[CLOW] && got[CHIGH]) {
+
+ if (nbins == 1) {
+ if (!fp_equald (clow, chigh))
+ call error (1, "nbins = 1, but clow != chigh")
+ } else {
+ dx = (chigh - clow) / (double(nbins) - 1.d0)
+ got[DX] = true
+ if (got[VLOW]) {
+ if (!fp_equald (vlow, clow - dx/2.d0))
+ call error (1,
+ "lowval conflicts with other parameters")
+ } else {
+ vlow = clow - dx / 2.d0
+ got[VLOW] = true
+ }
+ if (got[VHIGH]) {
+ if (!fp_equald (vhigh, chigh + dx/2.d0))
+ call error (1,
+ "highval conflicts with other parameters")
+ } else {
+ vhigh = chigh + dx / 2.d0
+ got[VHIGH] = true
+ }
+ }
+
+ } else if (got[CLOW] && got[VLOW]) {
+
+ dx = (clow - vlow) * 2.d0
+ vhigh = vlow + dx * nbins
+ chigh = vhigh - dx / 2.d0
+ got[DX] = true
+ got[VHIGH] = true
+ got[CHIGH] = true
+ find_datamax = false
+
+ } else if (got[CHIGH] && got[VHIGH]) {
+
+ dx = (vhigh - chigh) * 2.d0
+ vlow = vhigh - dx * nbins
+ clow = vlow + dx / 2.d0
+ got[DX] = true
+ got[VLOW] = true
+ got[CLOW] = true
+ find_datamin = false
+
+ } else if (got[CLOW] && got[VHIGH]) {
+
+ dx = (vhigh - clow) / (double(nbins) - 0.5d0)
+ vlow = vhigh - dx * nbins
+ chigh = vhigh - dx / 2.d0
+ got[DX] = true
+ got[VLOW] = true
+ got[CHIGH] = true
+
+ } else if (got[VLOW] && got[CHIGH]) {
+
+ dx = (chigh - vlow) / (double(nbins) - 0.5d0)
+ clow = vlow + dx / 2.d0
+ vhigh = vlow + dx * nbins
+ got[DX] = true
+ got[CLOW] = true
+ got[VHIGH] = true
+
+ }
+
+ } else if (got[CLOW] && got[VLOW]) { # but neither dx nor nbins
+
+ dx = (clow - vlow) * 2.d0
+ got[DX] = true
+
+ } else if (got[CHIGH] && got[VHIGH]) { # but neither dx nor nbins
+
+ dx = (vhigh - chigh) * 2.d0
+ got[DX] = true
+
+ } else {
+ call error (1, "you must specify either nbins or dx (or both)")
+ }
+end
+
+# th_update -- update the limits
+# We now have the minimum and maximum data values from the table,
+# so we can fill in the values that the user did not specify.
+# We need nbins, vlow, vhigh, and dx. The values of clow and chigh
+# are not modified, even if they are still INDEF; the array of flags
+# (got) must not be modified, as these flags are used for different
+# tables if there is more than one in the input list.
+
+procedure th_update (vmin, vmax, nbins, vlow, vhigh, dx, clow, chigh,
+ got, find_datamin, find_datamax)
+
+double vmin, vmax # i: min and max data values for current table
+int nbins # io: number of bins
+double vlow, vhigh # io: lower and upper limits
+double dx # io: bin width
+double clow, chigh # i: centers of low and high bins
+bool got[NPAR] # i: flags that specify what parameters we already have
+bool find_datamin # i: true if we had to find minimum data value
+bool find_datamax # i: true if we had to find maximum data value
+#--
+double delta # for expanding the range to include endpoints
+
+begin
+ if (find_datamin && find_datamax) {
+
+ # Center the data within the range. We do have either
+ # dx or nbins or both.
+ if (got[DX] && got[NBINS]) {
+ delta = (dx * nbins - (vmax - vmin)) / 2.d0
+ } else if (got[NBINS]) {
+ if (nbins == 1)
+ delta = (vmax - vmin) / 100.d0 # 100 is arbitrary
+ else
+ delta = (vmax - vmin) / (nbins - 1.d0) / 2.d0
+ } else if (got[DX]) {
+ nbins = nint ((vmax - vmin) / dx)
+ if (nbins * dx <= vmax - vmin)
+ nbins = nbins + 1 # round up
+ delta = (dx * nbins - (vmax - vmin)) / 2.d0
+ }
+ vlow = vmin - delta
+ vhigh = vmax + delta
+ if (!got[DX])
+ dx = (vhigh - vlow) / nbins
+
+ } else if (find_datamin) {
+
+ # We don't have both dx and nbins. If we did, we would have
+ # calculated vlow from vhigh, dx, and nbins.
+ if (got[DX]) {
+
+ nbins = nint ((vhigh - vmin) / dx) # vhigh is known
+ if (nbins * dx <= vhigh - vmin)
+ nbins = nbins + 1 # round up
+ vlow = vhigh - dx * nbins
+
+ } else if (got[NBINS]) {
+
+ if (got[VHIGH]) {
+ if (nbins == 1)
+ delta = (vhigh - vmin) / 100.d0 # 100 is arbitrary
+ else
+ delta = (vhigh - vmin) / (nbins - 1.d0) / 2.d0
+ vlow = vmin - delta
+ dx = (vhigh - vlow) / nbins
+ } else { # we have chigh but not vhigh
+ if (nbins == 1) {
+ vlow = vmin # this case doesn't make sense
+ vhigh = chigh + (chigh - vmin)
+ dx = vhigh - vlow
+ } else { # set clow = vmin
+ dx = (chigh - vmin) / (nbins - 1.d0)
+ vlow = vmin - dx / 2.d0
+ vhigh = chigh + dx / 2.d0
+ }
+ }
+ }
+
+ } else if (find_datamax) {
+
+ # For this case as well, we don't have both dx and nbins.
+ if (got[DX]) {
+
+ nbins = nint ((vmax - vlow) / dx) # vlow is known
+ if (nbins * dx <= vmax - vlow)
+ nbins = nbins + 1 # round up
+ vhigh = vlow + dx * nbins
+
+ } else if (got[NBINS]) {
+
+ if (got[VLOW]) {
+ if (nbins == 1)
+ delta = (vmax - vlow) / 100.d0 # 100 is arbitrary
+ else
+ delta = (vmax - vlow) / (nbins - 1.d0) / 2.d0
+ vhigh = vmax + delta
+ dx = (vhigh - vlow) / nbins
+ } else { # we have clow but not vlow
+ if (nbins == 1) {
+ vhigh = vmax # this case doesn't make sense
+ vlow = clow - (vmax - clow)
+ dx = vhigh - vlow
+ } else { # set chigh = vmax
+ dx = (vmax - clow) / (nbins - 1.d0)
+ vlow = vmin - dx / 2.d0
+ vhigh = chigh + dx / 2.d0
+ }
+ }
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/tstat/tstat.x b/pkg/utilities/nttools/tstat/tstat.x
new file mode 100644
index 00000000..5ef2b435
--- /dev/null
+++ b/pkg/utilities/nttools/tstat/tstat.x
@@ -0,0 +1,465 @@
+include <error.h>
+include <fset.h> # to check whether input or output is redirected
+include <tbset.h>
+
+define MAX_RANGES (SZ_LINE/2) # max number of ranges of row numbers
+define NUM_COL 8 # number of output columns
+
+# tstat -- get statistics for a table column
+# This task gets the mean, standard deviation, median, and minimum &
+# maximum values for a table column.
+#
+# Phil Hodge, 8-Dec-1988 Task created.
+# Phil Hodge, 14-Mar-1989 Also compute the median; fix bug in std dev.
+# Phil Hodge, 27-May-1992 Print INDEF if no values in range.
+# Phil Hodge, 31-Jul-1992 Print column name after table name.
+# Phil Hodge, 11-Jan-1992 Use asrtd instead of asokd for median if nr is even.
+# Phil Hodge, 3-Oct-1995 Modify to use tbn instead of fnt.
+# Phil Hodge, 25-Apr-1997 Use asrtd instead of asokd regardless of nr.
+# Phil Hodge, 26-Mar-1998 Get all elements of array columns; ignore the
+# column parameter if an input table has only one column.
+# Phil Hodge, 8-Jun-1999 Set input/output to STDIN/STDOUT if redirected.
+# Phil Hodge, 2-Jan-2001 If the input was redirected, and one command-line
+# argument was specified, take that argument to be the
+# column name rather than the table name.
+
+procedure tstat()
+
+pointer inlist # scratch for list of input table names
+char cl_colname[SZ_COLNAME] # column name gotten from cl parameter
+double lowlim # lower & upper limits for histogram
+double highlim # lower & upper limits for histogram
+pointer range_string # string which gives ranges of row numbers
+char nam_table[SZ_FNAME] # column name for table name
+char nam_name[SZ_COLNAME] # column name for column name
+char nam_mean[SZ_COLNAME] # column name for mean
+char nam_stddev[SZ_COLNAME] # column name for standard deviation
+char nam_med[SZ_COLNAME] # column name for median
+char nam_min[SZ_COLNAME] # column name for minimum
+char nam_max[SZ_COLNAME] # column name for maximum
+char nam_nrows[SZ_COLNAME] # column name for number of good rows
+#--
+pointer list1 # for list of input tables
+pointer sp
+pointer itp, otp # ptr to table descriptor
+pointer cptr # ptr to column descriptor
+pointer ocp[NUM_COL] # ptrs to col descriptors for output columns
+pointer intab, outtab # scr for names of input & output tables
+char colname[SZ_COLNAME] # column name
+double vmean # mean value
+double vstddev # standard deviation of values
+double vmedian # median value
+double vmin, vmax # minimum & maximum values
+int row # output row number
+int nrows # number of rows included and not INDEF
+int ntables # number of tables in input list
+bool listout # ASCII output?
+bool tabout # table output?
+bool new_table # true if output table does not already exist
+int nargs # number of command-line arguments
+bool in_redir # is input redirected?
+int clgeti()
+double clgetd()
+int fstati()
+pointer tbnopen()
+int tbnget(), tbnlen()
+pointer tbtopn()
+pointer tbcnum()
+int tbtacc(), tbpsta()
+bool streq()
+
+begin
+ # Allocate scratch for lists of names and for table names.
+ call smark (sp)
+ call salloc (inlist, SZ_LINE, TY_CHAR)
+ call salloc (intab, SZ_LINE, TY_CHAR)
+ call salloc (outtab, SZ_LINE, TY_CHAR)
+ call salloc (range_string, SZ_LINE, TY_CHAR)
+
+ # Get task parameters.
+
+ nargs = clgeti ("$nargs")
+ in_redir = fstati (STDIN, F_REDIR) == YES
+
+ if (in_redir)
+ call strcpy ("STDIN", Memc[inlist], SZ_LINE)
+ else
+ call clgstr ("intable", Memc[inlist], SZ_LINE)
+
+ if (fstati (STDOUT, F_REDIR) == YES)
+ call strcpy ("STDOUT", Memc[outtab], SZ_LINE)
+ else
+ call clgstr ("outtable", Memc[outtab], SZ_LINE)
+
+ cl_colname[1] = EOS # initial value
+ lowlim = clgetd ("lowlim") # these limits may be INDEF
+ highlim = clgetd ("highlim")
+ call clgstr ("rows", Memc[range_string], SZ_LINE)
+
+ # ASCII output? table output? create a new output table?
+ listout = streq (Memc[outtab], "STDOUT")
+ if ( listout || (Memc[outtab] == EOS) ) {
+ tabout = false
+ } else {
+ tabout = true
+ new_table = (tbtacc (Memc[outtab]) == NO)
+ }
+
+ if (tabout) {
+ call clgstr ("n_tab", nam_table, SZ_FNAME)
+ call clgstr ("n_nam", nam_name, SZ_COLNAME)
+ call clgstr ("n_nrows", nam_nrows, SZ_COLNAME)
+ call clgstr ("n_mean", nam_mean, SZ_COLNAME)
+ call clgstr ("n_stddev", nam_stddev, SZ_COLNAME)
+ call clgstr ("n_median", nam_med, SZ_COLNAME)
+ call clgstr ("n_min", nam_min, SZ_COLNAME)
+ call clgstr ("n_max", nam_max, SZ_COLNAME)
+ }
+
+ # Expand the input table list.
+ list1 = tbnopen (Memc[inlist])
+
+ ntables = tbnlen (list1)
+
+ if (listout) {
+ row = 0 # just to have a definite value
+ if (ntables > 1) {
+ call printf ("# nrows")
+ call printf (" mean stddev median")
+ call printf (" min max\n\n")
+ }
+ } else if (tabout) {
+ # Create output table (or open existing table) & define columns.
+ if (new_table)
+ otp = tbtopn (Memc[outtab], NEW_FILE, NULL)
+ else
+ otp = tbtopn (Memc[outtab], READ_WRITE, NULL)
+
+ call tbcfnd (otp, nam_table, ocp[1], 1)
+ call tbcfnd (otp, nam_name, ocp[2], 1)
+ call tbcfnd (otp, nam_nrows, ocp[3], 1)
+ call tbcfnd (otp, nam_mean, ocp[4], 1)
+ call tbcfnd (otp, nam_stddev, ocp[5], 1)
+ call tbcfnd (otp, nam_med, ocp[6], 1)
+ call tbcfnd (otp, nam_min, ocp[7], 1)
+ call tbcfnd (otp, nam_max, ocp[8], 1)
+
+ if (ocp[1] == NULL)
+ call tbcdef (otp, ocp[1],
+ nam_table, "", "", -SZ_FNAME, 1, 1)
+ if (ocp[2] == NULL)
+ call tbcdef (otp, ocp[2],
+ nam_name, "", "", -SZ_COLNAME, 1, 1)
+ if (ocp[3] == NULL)
+ call tbcdef (otp, ocp[3],
+ nam_nrows, "", "", TY_INT, 1, 1)
+ if (ocp[4] == NULL)
+ call tbcdef (otp, ocp[4],
+ nam_mean, "", "", TY_DOUBLE, 1, 1)
+ if (ocp[5] == NULL)
+ call tbcdef (otp, ocp[5],
+ nam_stddev, "", "", TY_DOUBLE, 1, 1)
+ if (ocp[6] == NULL)
+ call tbcdef (otp, ocp[6],
+ nam_med, "", "", TY_DOUBLE, 1, 1)
+ if (ocp[7] == NULL)
+ call tbcdef (otp, ocp[7],
+ nam_min, "", "", TY_DOUBLE, 1, 1)
+ if (ocp[8] == NULL)
+ call tbcdef (otp, ocp[8],
+ nam_max, "", "", TY_DOUBLE, 1, 1)
+ if (new_table)
+ call tbtcre (otp)
+
+ row = tbpsta (otp, TBL_NROWS) # append to whatever is there
+ }
+
+ # Do for each input table.
+ while (tbnget (list1, Memc[intab], SZ_LINE) != EOF) {
+
+ itp = tbtopn (Memc[intab], READ_ONLY, NULL)
+ if (tbpsta (itp, TBL_NCOLS) == 1) {
+ cptr = tbcnum (itp, 1)
+ call tbcigt (cptr, TBL_COL_NAME, colname, SZ_COLNAME)
+ } else {
+ if (cl_colname[1] == EOS) {
+ if (nargs == 1 && in_redir) {
+ # in this case, the one argument should be column name
+ call clgstr ("intable", cl_colname, SZ_COLNAME)
+ # update par file
+ call clpstr ("intable", "STDIN")
+ call clpstr ("column", cl_colname)
+ } else {
+ call clgstr ("column", cl_colname, SZ_COLNAME)
+ }
+ }
+ call strcpy (cl_colname, colname, SZ_COLNAME)
+ call tbcfnd (itp, colname, cptr, 1)
+ }
+ if (cptr == NULL) {
+ call tbtclo (itp)
+ call eprintf ("column %s not found in %s\n")
+ call pargstr (colname)
+ call pargstr (Memc[intab])
+ next
+ }
+ row = row + 1
+
+ if (listout) {
+ call printf ("# %s %s\n")
+ call pargstr (Memc[intab])
+ call pargstr (colname)
+ if (ntables == 1) {
+ call printf ("# nrows")
+ call printf (" mean stddev median")
+ call printf (" min max\n")
+ }
+ }
+
+ # Get statistics.
+ iferr {
+ call ts_values (itp, cptr, Memc[range_string], lowlim, highlim,
+ vmean, vstddev, vmedian, vmin, vmax, nrows)
+ } then {
+ call erract (EA_WARN)
+ next
+ }
+
+ if (listout) {
+
+ call printf ("%5d %17.10g %13.6g %13.6g %13.6g %13.6g\n")
+ call pargi (nrows)
+ call pargd (vmean)
+ call pargd (vstddev)
+ call pargd (vmedian)
+ call pargd (vmin)
+ call pargd (vmax)
+
+ } else if (tabout) {
+
+ # Write the values into the output table.
+ call tbeptt (otp, ocp[1], row, Memc[intab])
+ call tbeptt (otp, ocp[2], row, colname)
+ call tbepti (otp, ocp[3], row, nrows)
+ call tbeptd (otp, ocp[4], row, vmean)
+ call tbeptd (otp, ocp[5], row, vstddev)
+ call tbeptd (otp, ocp[6], row, vmedian)
+ call tbeptd (otp, ocp[7], row, vmin)
+ call tbeptd (otp, ocp[8], row, vmax)
+ }
+
+ call tbtclo (itp) # close current input table
+ }
+
+ # Close the output table. It may be that nothing was written to it.
+ if (tabout)
+ call tbtclo (otp)
+
+ # Save the results (from the last input table) in cl parameters.
+ call clputi ("nrows", nrows)
+ call clputd ("mean", vmean)
+ call clputd ("stddev", vstddev)
+ call clputd ("median", vmedian)
+ call clputd ("vmin", vmin)
+ call clputd ("vmax", vmax)
+
+ call tbnclose (list1)
+ call sfree (sp)
+end
+
+# ts_values -- get statistics for a table column
+# This routine gets the mean, standard deviation, minimum and maximum
+# values for a table column. If lower and/or upper cutoff limits were
+# specified (i.e. are not INDEF) then values outside that range will not
+# be included in the statistics. INDEF values are also not included.
+
+procedure ts_values (tp, cptr, range_str, lowlim, highlim,
+ vmean, vstddev, vmedian, vmin, vmax, nrows)
+
+pointer tp # i: ptr to table descriptor
+pointer cptr # i: ptr to column descriptor
+char range_str[ARB] # i: range of row numbers
+double lowlim # i: lower cutoff of values to be included
+double highlim # i: upper cutoff of values to be included
+double vmean # o: mean value
+double vstddev # o: standard deviation of values
+double vmedian # o: median value
+double vmin # o: minimum value
+double vmax # o: maximum value
+int nrows # o: number of rows included in the statistics
+#--
+pointer sp
+pointer val # scratch for array of values (for median)
+pointer descrip # column selector descriptor
+double value # an element gotten from the table
+double sum, sumsq # for accumulating sums
+double smin, smax # temp min & max
+double diff # current value minus first good value
+int all_elem # total number of elements in column
+int selrows # number of selected rows
+int nelem # number of elements in one cell
+int nret # number returned (ignored)
+int nr # current number of rows
+int row # row number
+int ranges[3,MAX_RANGES] # ranges of row numbers
+int nvalues # returned by decode_ranges and ignored
+int stat # returned by get_next_number
+int i, j # loop indexes
+bool chklow, chkhi # were low (high) limits specified?
+bool val_ok # is current value within limits?
+bool done # loop-termination flag
+int decode_ranges(), get_next_number()
+int tbagtd()
+errchk tbagtd, tbegtd, tcs_rdaryd
+
+begin
+ if (decode_ranges (range_str, ranges, MAX_RANGES, nvalues) != OK) {
+ call eprintf ("rows = `%s'\n")
+ call pargstr (range_str)
+ call error (1, "Range of row numbers is invalid.")
+ }
+
+ # Get the number of elements per table cell and the number of
+ # rows selected using row-selector syntax (as opposed to using
+ # the 'rows' task parameter).
+ call tbcnel1 (tp, cptr, descrip, nelem, selrows)
+
+ # Find out how many rows there are in the table, restricted by
+ # either a row selector or the 'rows' task parameter, or both.
+ if (range_str[1] == '-' || range_str[1] == EOS) {
+ all_elem = selrows * nelem
+ } else {
+ # Count the number of rows specified.
+ i = 0 # count of row numbers
+ row = 0 # initialize get_next_number
+ done = false
+ while (!done) {
+ stat = get_next_number (ranges, row)
+ if (stat == EOF || row > selrows)
+ done = true
+ else
+ i = i + 1
+ }
+ all_elem = i * nelem
+ }
+
+ # Allocate scratch space to hold an entire column.
+ call smark (sp)
+ call salloc (val, all_elem, TY_DOUBLE)
+
+ row = 0 # reinitialize get_next_number
+ stat = get_next_number (ranges, row)
+ done = (stat == EOF || row > selrows)
+
+ # Get the data.
+ i = 1
+ while (!done) {
+
+ if (descrip == NULL) {
+ if (nelem == 1)
+ call tbegtd (tp, cptr, row, Memd[val+i-1])
+ else
+ nret = tbagtd (tp, cptr, row, Memd[val+i-1], 1, nelem)
+ } else {
+ call tcs_rdaryd (tp, descrip, row, all_elem-i+1,
+ nret, Memd[val+i-1])
+ }
+
+ i = i + nelem
+
+ stat = get_next_number (ranges, row)
+ done = (stat == EOF || row > selrows)
+ }
+ if (all_elem != i - 1)
+ call error (1, "not all elements read from column")
+
+ chklow = ! IS_INDEFD(lowlim)
+ chkhi = ! IS_INDEFD(highlim)
+
+ # Check which values to include.
+ sum = 0.d0
+ nr = 0
+ do i = 0, all_elem-1 { # zero indexed
+ value = Memd[val+i]
+ if (!IS_INDEFD(value)) {
+ val_ok = true # an initial value
+ if (chkhi && (value > highlim)) {
+ val_ok = false
+ Memd[val+i] = INDEFD
+ }
+ if (chklow && (value < lowlim)) {
+ val_ok = false
+ Memd[val+i] = INDEFD
+ }
+ if (val_ok) {
+ nr = nr + 1
+ sum = sum + value
+ }
+ }
+ }
+
+ if (nr < 1) {
+ # No rows with valid data, so set the output to INDEF.
+ nrows = 0
+ vmean = INDEFD
+ vstddev = INDEFD
+ vmedian = INDEFD
+ vmin = INDEFD
+ vmax = INDEFD
+ return
+ } else {
+ # Assign two of the output values.
+ nrows = nr
+ vmean = sum / double(nr)
+ }
+
+ # Move good data to the beginning of the array.
+ if (nr < all_elem) {
+ j = 0
+ do i = 0, all_elem-1 { # zero indexed
+ if (!IS_INDEFD(Memd[val+i])) {
+ Memd[val+j] = Memd[val+i]
+ j = j + 1
+ }
+ }
+ }
+
+ # Find the min, max, standard deviation of the good values.
+ sumsq = 0.d0
+ smin = Memd[val]
+ smax = Memd[val]
+ do i = 0, nr-1 { # zero indexed
+ value = Memd[val+i]
+ diff = value - vmean
+ sumsq = sumsq + diff * diff
+ if (value < smin)
+ smin = value
+ if (value > smax)
+ smax = value
+ }
+
+ # Assign output values.
+
+ vmin = smin
+ vmax = smax
+
+ if (nr > 1)
+ vstddev = sqrt (sumsq / double(nr-1))
+ else
+ vstddev = INDEFD
+
+ # Determine the median. If there are an even number of values, the
+ # middle two are averaged.
+ if (nr < 3) {
+ vmedian = vmean
+ } else {
+ call asrtd (Memd[val], Memd[val], nr)
+ if (nr / 2 * 2 == nr) { # even number of values?
+ vmedian = (Memd[val+nr/2-1] + Memd[val+nr/2]) / 2.d0
+ } else {
+ vmedian = Memd[val+nr/2]
+ }
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/ttranspose.par b/pkg/utilities/nttools/ttranspose.par
new file mode 100644
index 00000000..843b5890
--- /dev/null
+++ b/pkg/utilities/nttools/ttranspose.par
@@ -0,0 +1,6 @@
+intable,s,a,"",,,"input tables"
+outtable,s,a,"",,,"output tables"
+action,s,a,"t",,,"operations (t,h,v) to perform"
+verbose,b,h,yes,,,"print table names?"
+Version,s,h,"30Nov94",,,"date of installation"
+mode,s,h,"al"
diff --git a/pkg/utilities/nttools/ttranspose/mkpkg b/pkg/utilities/nttools/ttranspose/mkpkg
new file mode 100644
index 00000000..6118a47e
--- /dev/null
+++ b/pkg/utilities/nttools/ttranspose/mkpkg
@@ -0,0 +1,11 @@
+# Update the ttranspose application code in the ttools package library
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ ttranspose.x <error.h> <tbset.h>
+ ttrflip.x
+ ;
diff --git a/pkg/utilities/nttools/ttranspose/ttranspose.x b/pkg/utilities/nttools/ttranspose/ttranspose.x
new file mode 100644
index 00000000..1bf99d9e
--- /dev/null
+++ b/pkg/utilities/nttools/ttranspose/ttranspose.x
@@ -0,0 +1,419 @@
+include <error.h> # for EA_WARN
+include <fset.h> # to check whether input or output is redirected
+include <tbset.h>
+
+# ttranspose -- transpose or flip a table
+# This task can be used to transpose a table so that input rows become
+# output columns and input columns become output rows. Another option
+# is to flip the table horizontally, that is, the first input column is
+# the last output column. Finally, the table can be flipped vertically,
+# i.e., the first input row is the last output row. Any combination of
+# these operations may be performed.
+#
+# Phil Hodge, 30-Nov-1994 Task created.
+# Phil Hodge, 4-Oct-1995 Modify to use tbn instead of fnt.
+# Phil Hodge, 12-Jun-1998 Initialize maxwidth using tbcftl in ttr_compare.
+# Phil Hodge, 8-Apr-1999 Call tbfpri.
+# Phil Hodge, 8-Jun-1999 Set input/output to STDIN/STDOUT if redirected.
+
+procedure ttranspose()
+
+pointer innames # scratch for names of input tables
+pointer outnames # scratch for names of output tables
+pointer action # scratch for operations to perform
+bool verbose # print table names?
+#--
+pointer sp
+pointer ilist, olist # tbn pointers for input & output lists
+pointer intable # scratch for name of an input table
+pointer outtable # scratch for name of an output table
+pointer itp, otp # pointers to input & output table structs
+pointer icp, ocp # pointers to arrays of column descriptors
+int op[2] # mapping of (columns,rows) from input to output
+int dtype # data type of columns
+int nelem # number of elements in array
+int irows, orows # number of rows in input, output tables
+int icols, ocols # number of columns in input, output tables
+int i # loop index
+int junk
+int num_out # number of output table names
+int phu_copied # set by tbfpri and ignored
+bool transpose # true if table will be transposed, not just flipped
+bool to_stdout # true if output is to STDOUT
+bool clgetb(), streq()
+int fstati()
+pointer tbnopen()
+int tbnlen(), tbnget()
+pointer tbtopn(), tbcnum()
+int tbpsta()
+errchk ttr_compare, tbfpri, ttr_create, ttr_trans, ttr_flip
+string SKIP "Table %s will be skipped:\n"
+
+begin
+ call smark (sp)
+ call salloc (innames, SZ_LINE, TY_CHAR)
+ call salloc (outnames, SZ_LINE, TY_CHAR)
+ call salloc (intable, SZ_LINE, TY_CHAR)
+ call salloc (outtable, SZ_LINE, TY_CHAR)
+ call salloc (action, SZ_LINE, TY_CHAR)
+
+ if (fstati (STDIN, F_REDIR) == YES)
+ call strcpy ("STDIN", Memc[innames], SZ_LINE)
+ else
+ call clgstr ("intable", Memc[innames], SZ_LINE)
+
+ if (fstati (STDOUT, F_REDIR) == YES)
+ call strcpy ("STDOUT", Memc[outnames], SZ_LINE)
+ else
+ call clgstr ("outtable", Memc[outnames], SZ_LINE)
+
+ call clgstr ("action", Memc[action], SZ_LINE)
+ verbose = clgetb ("verbose")
+
+ # Interpret the list of operations.
+ call ttr_opcode (Memc[action], op, transpose)
+
+ ilist = tbnopen (Memc[innames])
+ olist = tbnopen (Memc[outnames])
+
+ to_stdout = false # may be updated below
+ num_out = tbnlen (olist)
+ # Get the first output name now, and then rewind the list.
+ junk = tbnget (olist, Memc[outtable], SZ_LINE)
+ call tbnrew (olist)
+
+ if (tbnlen (ilist) != num_out) {
+ if (num_out == 1 && streq (Memc[outtable], "STDOUT")) {
+ # It's OK to have multiple input tables and just one output
+ # if the latter is STDOUT.
+ to_stdout = true
+ } else {
+ call tbnclose (olist)
+ call tbnclose (ilist)
+ call error (1, "Input and output lists not the same length.")
+ }
+ }
+
+ # Do for each table in the list.
+ while (tbnget (ilist, Memc[intable], SZ_LINE) != EOF) {
+ if (num_out > 1)
+ junk = tbnget (olist, Memc[outtable], SZ_LINE)
+
+ # Open input table and get number of rows and columns.
+ itp = tbtopn (Memc[intable], READ_ONLY, NULL)
+ irows = tbpsta (itp, TBL_NROWS)
+ icols = tbpsta (itp, TBL_NCOLS)
+ call tbtnam (itp, Memc[intable], SZ_LINE) # get full table name
+
+ # Allocate space for pointers to column descriptors.
+ call malloc (icp, icols, TY_POINTER)
+
+ # Get column pointers for input table.
+ do i = 1, icols
+ Memi[icp+i-1] = tbcnum (itp, i)
+
+ iferr {
+ # Check that data types of columns are all the same.
+ call ttr_compare (itp, Memi[icp], icols,
+ transpose, dtype, nelem)
+
+ # Create output table.
+ call tbfpri (Memc[intable], Memc[outtable], phu_copied)
+ call ttr_create (itp, otp, Memi[icp], ocp, Memc[outtable],
+ op, transpose, irows, icols, orows, ocols, dtype, nelem)
+ } then {
+ call mfree (icp, TY_POINTER)
+ call tbtclo (itp)
+ call eprintf (SKIP)
+ call pargstr (Memc[intable])
+ call erract (EA_WARN)
+ next
+ }
+
+ if (verbose) {
+ call printf ("%s --> %s\n")
+ call pargstr (Memc[intable])
+ call pargstr (Memc[outtable])
+ call flush (STDOUT)
+ }
+
+ # Copy table data.
+ iferr {
+ if (transpose) {
+ call ttr_trans (itp, otp, Memi[icp], Memi[ocp],
+ irows, icols, orows, ocols, op, dtype, nelem)
+ } else {
+ call ttr_flip (itp, otp, Memi[icp], Memi[ocp],
+ irows, icols, op)
+ }
+ } then {
+ call mfree (ocp, TY_POINTER)
+ call mfree (icp, TY_POINTER)
+ call tbtclo (otp)
+ call tbtclo (itp)
+ call tbtdel (Memc[outtable])
+ call eprintf (SKIP)
+ call pargstr (Memc[intable])
+ call erract (EA_WARN)
+ next
+ }
+
+ call mfree (ocp, TY_POINTER)
+ call mfree (icp, TY_POINTER)
+ iferr {
+ call tbtclo (otp)
+ } then {
+ call eprintf (SKIP)
+ call pargstr (Memc[intable])
+ call erract (EA_WARN)
+ }
+ call tbtclo (itp)
+ }
+
+ call tbnclose (olist)
+ call tbnclose (ilist)
+ call sfree (sp)
+end
+
+procedure ttr_opcode (action, op, transpose)
+
+char action[ARB] # i: list of operations to perform
+int op[2] # o: combined operations
+bool transpose # o: true if table will be transposed, not just flipped
+#--
+int i
+int prev[2] # previous op
+int slen # length of string
+int strlen()
+
+begin
+ slen = strlen (action)
+
+ prev[1] = 1 # initial values
+ prev[2] = 2
+
+ do i = 1, slen {
+ if (action[i] == 't' || action[i] == '/') {
+ # transpose
+ op[1] = prev[2]
+ op[2] = prev[1]
+ } else if (action[i] == 'h' || action[i] == '-') {
+ # flip horizontally, i.e. first column <--> last col
+ op[1] = -prev[1]
+ op[2] = prev[2]
+ } else if (action[i] == 'v' || action[i] == '|') {
+ # flip vertically, i.e. first row <--> last row
+ op[1] = prev[1]
+ op[2] = -prev[2]
+ } else if (action[i] == ',' || action[i] == ' ') {
+ ;
+ } else {
+ call error (1, "'action' must use only t, h, v")
+ }
+ prev[1] = op[1] # save for next loop
+ prev[2] = op[2]
+ }
+
+ # After all the operations, will we actually transpose the table,
+ # or just flip it?
+ transpose = (abs (op[1]) == 2)
+end
+
+# ttr_compare -- compare data types and array lengths
+
+procedure ttr_compare (itp, icp, icols, transpose, dtype, nelem)
+
+pointer itp # i: pointer to input table struct
+pointer icp[icols] # i: array of pointers to input column descriptors
+int icols # i: number of columns in input table
+bool transpose # i: true if table will be transposed, not just flipped
+int dtype # o: data type of columns
+int nelem # o: length of array stored at each row,column
+#--
+int dtype2, nelem2 # data type and array length of column to compare
+int width # width of a particular column
+int maxwidth # max width of column in text table
+int i
+int tbpsta(), tbcigi()
+
+begin
+ # Get info about first column so we can compare with other columns.
+ dtype = tbcigi (icp[1], TBL_COL_DATATYPE)
+ nelem = tbcigi (icp[1], TBL_COL_LENDATA)
+ if (dtype == TY_CHAR) { # old style, change it
+ dtype = -nelem
+ nelem = 1
+ }
+
+ # We don't need to check column data types if we're not actually
+ # transposing the table.
+ if (!transpose)
+ return
+
+ if (tbpsta (itp, TBL_WHTYPE) == TBL_TYPE_TEXT) {
+
+ # For a text table, we can permit different input data types
+ # if we set the output type to text.
+
+ call tbcftl (icp[1], maxwidth) # maxwidth updated in loop
+ do i = 2, icols {
+
+ call tbcftl (icp[i], width) # get width of current column
+ maxwidth = max (maxwidth, width)
+
+ dtype2 = tbcigi (icp[i], TBL_COL_DATATYPE)
+ if (dtype > 0 && dtype != dtype2) {
+ # They're not the same; change to char data type.
+ dtype = -maxwidth
+ }
+ }
+ if (dtype < 0)
+ dtype = -maxwidth
+
+ } else { # not a text table
+
+ # Compare first column with subsequent columns.
+ do i = 2, icols {
+
+ dtype2 = tbcigi (icp[i], TBL_COL_DATATYPE)
+ nelem2 = tbcigi (icp[i], TBL_COL_LENDATA)
+ if (dtype2 == TY_CHAR) {
+ dtype2 = -nelem2
+ nelem2 = 1
+ }
+
+ if (dtype < 0) {
+ # For character columns, allow different lengths for
+ # input, but change to maximum length for output.
+ dtype = min (dtype, dtype2) # max absolute value
+
+ } else if (dtype != dtype2) {
+
+ # Promote real to double, short to int, and bool to
+ # any other type.
+ if (dtype == TY_REAL && dtype2 == TY_DOUBLE ||
+ dtype == TY_DOUBLE && dtype2 == TY_REAL) {
+ dtype = TY_DOUBLE
+ } else if (dtype == TY_INT && dtype2 == TY_SHORT ||
+ dtype == TY_SHORT && dtype2 == TY_INT) {
+ dtype = TY_INT
+ } else if (dtype == TY_BOOL) {
+ dtype = dtype2 # promote to other type
+ } else if (dtype2 == TY_BOOL) {
+ ; # OK to convert to any type
+ } else {
+ call error (1, "columns are not all the same data type")
+ }
+ }
+
+ if (nelem != nelem2)
+ call error (1, "column array lengths are not all the same")
+ }
+ }
+end
+
+# ttr_create -- create output table
+# This routine creates the output table, defines output columns,
+# and copies header parameters.
+#
+# Note the following, which can be a bit confusing. In the case that
+# the table is to be flipped horizontally but not transposed, columns are
+# defined in the output table in the reverse order from the corresponding
+# columns in the input table, but the column pointers themselves are stored
+# in their arrays in the same order. That is, icp[i] refers to the same
+# column as Memi[ocp+i-1], except of course that icp[i] is in the input
+# table and Memi[ocp+i-1] is in the output table. "Same column" means
+# that the column descriptions and contents are the same, but the column
+# number will in general be different; icp[1] is the first column in the
+# input table, Memi[ocp] is the last column in the output table, and they
+# will have the same name, etc.
+
+procedure ttr_create (itp, otp, icp, ocp, outtable,
+ op, transpose, irows, icols, orows, ocols, dtype, nelem)
+
+pointer itp # i: pointer to input table struct
+pointer otp # o: pointer to output table struct
+pointer icp[icols] # i: array of pointers to input column descriptors
+pointer ocp # o: pointer to array of pointers to output col descr
+char outtable[ARB] # io: name of output table (extension may be appended)
+int op[2] # i: operation code
+bool transpose # i: true if table will be transposed, not just flipped
+int irows # i: number of rows in input table
+int icols # i: number of columns in input table
+int orows # o: number of rows in output table
+int ocols # o: number of columns in output table
+int dtype # i: data type of columns
+int nelem # i: length of array stored at each row,column
+#--
+char colname[SZ_COLNAME] # name of current column
+char colunits[SZ_COLUNITS] # units for current column
+char colfmt[SZ_COLFMT] # print format for current column
+int datatype # data type of current column
+int lenarray # number of elements for current column
+int lenfmt # space required to print column
+int colnum # column number
+int i # loop index
+int i_start, i_end, i_incr # loop limits for index i
+int maxpar # space allocated for header parameters
+pointer tbtopn()
+int tbpsta()
+
+begin
+ # Allocate space for array of column pointers for output table.
+ if (transpose) {
+ orows = icols
+ ocols = irows
+ } else { # don't transpose
+ orows = irows
+ ocols = icols
+ }
+ call malloc (ocp, ocols, TY_POINTER)
+
+ # Create output table.
+ otp = tbtopn (outtable, NEW_FILE, NULL)
+ if (tbpsta (itp, TBL_WHTYPE) == TBL_TYPE_TEXT)
+ call tbpset (otp, TBL_WHTYPE, TBL_TYPE_TEXT)
+
+ # Set enough space for all header parameters from input.
+ maxpar = tbpsta (itp, TBL_MAXPAR)
+ call tbpset (otp, TBL_MAXPAR, maxpar)
+
+ # Create output columns.
+ if (transpose) {
+
+ # Assign dummy column names, with null units and default format.
+ do i = 1, ocols {
+ call sprintf (colname, SZ_COLNAME, "c%d")
+ call pargi (i)
+ call tbcdef (otp, Memi[ocp+i-1],
+ colname, "", "", dtype, nelem, 1)
+ }
+
+ } else {
+
+ # We're not transposing, so retain column names, etc.
+ if (op[1] > 0) {
+ # retain order of columns
+ i_start = 1
+ i_end = icols
+ i_incr = 1
+ } else {
+ # flip by defining last column first
+ i_start = icols
+ i_end = 1
+ i_incr = -1
+ }
+
+ do i = i_start, i_end, i_incr {
+ call tbcinf (icp[i], colnum, colname, colunits, colfmt,
+ datatype, lenarray, lenfmt)
+ call tbcdef (otp, Memi[ocp+i-1],
+ colname, colunits, colfmt, datatype, lenarray, 1)
+ }
+ }
+ call tbtcre (otp)
+ call tbtnam (otp, outtable, SZ_LINE) # get full table name
+
+ # Copy all header parameters from input to output.
+ call tbhcal (itp, otp)
+end
diff --git a/pkg/utilities/nttools/ttranspose/ttrflip.x b/pkg/utilities/nttools/ttranspose/ttrflip.x
new file mode 100644
index 00000000..3c008f68
--- /dev/null
+++ b/pkg/utilities/nttools/ttranspose/ttrflip.x
@@ -0,0 +1,266 @@
+# This file contains ttr_trans and ttr_flip. The former copies data
+# from one table to another and transposes rows and columns, while the
+# latter copies data without transposing. Either routine may also flip
+# rows and/or columns, i.e. first input row to last output row, or first
+# input column to last input column.
+#
+# Phil Hodge, 30-Nov-1994 Subroutines created.
+
+# ttr_trans -- copy data from input to output
+# This routine transposes a table.
+
+procedure ttr_trans (itp, otp, icp, ocp,
+ irows, icols, orows, ocols, op, dtype, nelem)
+
+pointer itp # i: pointer to input table struct
+pointer otp # i: pointer to output table struct
+pointer icp[icols] # i: array of pointers to input column descriptors
+pointer ocp[irows] # i: array of pointers to output column descriptors
+int irows # i: number of rows in input table
+int icols # i: number of columns in input table
+int orows # i: number of rows in output table
+int ocols # i: number of columns in output table
+int op[2] # i: mapping of (columns,rows) from input to output
+int dtype # i: data type of column
+int nelem # i: length of array stored at each row,column
+#--
+pointer sp
+pointer buf # scratch for copying array entries
+int clen # length of char string (= -dtype)
+int i, j # loop indices for input table
+int oi, oj # loop indices for output table
+int oj_start # starting value for oj
+int oi_incr, oj_incr # increments in oi, oj
+
+# buffers for copying one element:
+pointer cbuf
+double dbuf
+real rbuf
+int ibuf
+short sbuf
+bool bbuf
+
+int nret # number of array elements actually read and written
+int tbagtd(), tbagtr(), tbagti(), tbagts(), tbagtb(), tbagtt()
+errchk tbegtd, tbegtr, tbegti, tbegts, tbegtb, tbegtt,
+ tbeptd, tbeptr, tbepti, tbepts, tbeptb, tbeptt,
+ tbagtd, tbagtr, tbagti, tbagts, tbagtb, tbagtt,
+ tbaptd, tbaptr, tbapti, tbapts, tbaptb, tbaptt
+
+begin
+ call smark (sp)
+
+ # Assign values for the beginning and increment for the loops
+ # on oi and oj.
+ if (op[1] > 0) {
+ oi = 1
+ oi_incr = 1
+ } else {
+ oi = ocols # = irows
+ oi_incr = -1
+ }
+ if (op[2] > 0) {
+ oj_start = 1
+ oj_incr = 1
+ } else {
+ oj_start = orows # = icols
+ oj_incr = -1
+ }
+
+ if (dtype < 0)
+ clen = -dtype
+
+ if (nelem == 1) {
+
+ if (dtype == TY_REAL) {
+ do j = 1, irows {
+ oj = oj_start # oj, not oi, because we're transposing
+ do i = 1, icols {
+ call tbegtr (itp, icp[i], j, rbuf)
+ call tbeptr (otp, ocp[oi], oj, rbuf)
+ oj = oj + oj_incr
+ }
+ oi = oi + oi_incr
+ }
+ } else if (dtype == TY_DOUBLE) {
+ do j = 1, irows {
+ oj = oj_start
+ do i = 1, icols {
+ call tbegtd (itp, icp[i], j, dbuf)
+ call tbeptd (otp, ocp[oi], oj, dbuf)
+ oj = oj + oj_incr
+ }
+ oi = oi + oi_incr
+ }
+ } else if (dtype == TY_INT) {
+ do j = 1, irows {
+ oj = oj_start
+ do i = 1, icols {
+ call tbegti (itp, icp[i], j, ibuf)
+ call tbepti (otp, ocp[oi], oj, ibuf)
+ oj = oj + oj_incr
+ }
+ oi = oi + oi_incr
+ }
+ } else if (dtype == TY_SHORT) {
+ do j = 1, irows {
+ oj = oj_start
+ do i = 1, icols {
+ call tbegts (itp, icp[i], j, sbuf)
+ call tbepts (otp, ocp[oi], oj, sbuf)
+ oj = oj + oj_incr
+ }
+ oi = oi + oi_incr
+ }
+ } else if (dtype == TY_BOOL) {
+ do j = 1, irows {
+ oj = oj_start
+ do i = 1, icols {
+ call tbegtb (itp, icp[i], j, bbuf)
+ call tbeptb (otp, ocp[oi], oj, bbuf)
+ oj = oj + oj_incr
+ }
+ oi = oi + oi_incr
+ }
+ } else if (dtype < 0) {
+ call salloc (cbuf, SZ_LINE, TY_CHAR)
+ do j = 1, irows {
+ oj = oj_start
+ do i = 1, icols {
+ call tbegtt (itp, icp[i], j, Memc[cbuf], SZ_LINE)
+ call tbeptt (otp, ocp[oi], oj, Memc[cbuf])
+ oj = oj + oj_incr
+ }
+ oi = oi + oi_incr
+ }
+ } else {
+ call error (1, "invalid data type")
+ }
+
+ } else { # each entry is an array
+
+ if (dtype > 0)
+ call salloc (buf, nelem, dtype)
+
+ if (dtype == TY_REAL) {
+ do j = 1, irows {
+ oj = oj_start
+ do i = 1, icols {
+ nret = tbagtr (itp, icp[i], j, Memr[buf], 1, nelem)
+ call tbaptr (otp, ocp[oi], oj, Memr[buf], 1, nret)
+ oj = oj + oj_incr
+ }
+ oi = oi + oi_incr
+ }
+ } else if (dtype == TY_DOUBLE) {
+ do j = 1, irows {
+ oj = oj_start
+ do i = 1, icols {
+ nret = tbagtd (itp, icp[i], j, Memd[buf], 1, nelem)
+ call tbaptd (otp, ocp[oi], oj, Memd[buf], 1, nret)
+ oj = oj + oj_incr
+ }
+ oi = oi + oi_incr
+ }
+ } else if (dtype == TY_INT) {
+ do j = 1, irows {
+ oj = oj_start
+ do i = 1, icols {
+ nret = tbagti (itp, icp[i], j, Memi[buf], 1, nelem)
+ call tbapti (otp, ocp[oi], oj, Memi[buf], 1, nret)
+ oj = oj + oj_incr
+ }
+ oi = oi + oi_incr
+ }
+ } else if (dtype == TY_SHORT) {
+ do j = 1, irows {
+ oj = oj_start
+ do i = 1, icols {
+ nret = tbagts (itp, icp[i], j, Mems[buf], 1, nelem)
+ call tbapts (otp, ocp[oi], oj, Mems[buf], 1, nret)
+ oj = oj + oj_incr
+ }
+ oi = oi + oi_incr
+ }
+ } else if (dtype == TY_BOOL) {
+ do j = 1, irows {
+ oj = oj_start
+ do i = 1, icols {
+ nret = tbagtb (itp, icp[i], j, Memb[buf], 1, nelem)
+ call tbaptb (otp, ocp[oi], oj, Memb[buf], 1, nret)
+ oj = oj + oj_incr
+ }
+ oi = oi + oi_incr
+ }
+ } else if (dtype < 0) {
+ call salloc (buf, (clen+1) * nelem, TY_CHAR) # add 1 for EOS
+ do j = 1, irows {
+ oj = oj_start
+ do i = 1, icols {
+ nret = tbagtt (itp, icp[i], j, Memc[buf], clen,
+ 1, nelem)
+ call tbaptt (otp, ocp[oi], oj, Memc[buf], clen, 1, nret)
+ oj = oj + oj_incr
+ }
+ oi = oi + oi_incr
+ }
+ } else {
+ call error (1, "invalid data type")
+ }
+ }
+
+ call sfree (sp)
+end
+
+# ttr_flip -- copy data from input to output
+# This routine copies a table without transposing.
+# irows and icols are the numbers of rows and columns in both the
+# input and output tables.
+# Note that if we are reversing the order of the columns (horizontal flip),
+# the last column of the input table was defined first, so the flip in
+# column order is taken care of by the relative order of the elements of
+# the arrays icp and ocp.
+
+procedure ttr_flip (itp, otp, icp, ocp, irows, icols, op)
+
+pointer itp # i: pointer to input table struct
+pointer otp # i: pointer to output table struct
+pointer icp[icols] # i: array of pointers to input column descriptors
+pointer ocp[ARB] # i: array of pointers to output column descriptors
+int irows # i: number of rows in input table
+int icols # i: number of columns in input table
+int op[2] # i: mapping of (columns,rows) from input to output
+#--
+int j # loop index for input row number
+int oj, oj_incr # loop index and increment for output row number
+errchk tbrcpy, tbrcsc
+
+begin
+ # Assign values for the beginning and increment for the loop
+ # on output row number.
+ if (op[2] > 0) {
+ oj = 1
+ oj_incr = 1
+ } else {
+ oj = irows
+ oj_incr = -1
+ }
+
+ # Copy the data from input to output.
+ if (op[1] > 0) {
+
+ # Retain column order.
+ do j = 1, irows {
+ call tbrcpy (itp, otp, j, oj)
+ oj = oj + oj_incr
+ }
+
+ } else { # op[1] < 0
+
+ # Reverse column order.
+ do j = 1, irows {
+ call tbrcsc (itp, otp, icp, ocp, j, oj, icols)
+ oj = oj + oj_incr
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/tunits.par b/pkg/utilities/nttools/tunits.par
new file mode 100644
index 00000000..3d112987
--- /dev/null
+++ b/pkg/utilities/nttools/tunits.par
@@ -0,0 +1,8 @@
+table,f,a,,,,"Table name"
+column,s,a,,,,"Column name"
+newunits,s,a,,,,"New column units"
+oldunits,s,h," ",,,"Old column units"
+abrevtab,f,h,"ttools$tunits/abrev.tab",,,"Table of unit abbreviations"
+unittab,f,h,"ttools$tunits/units.tab",,,"Table of unit conversions"
+verbose,b,h,no,,,"Print diagnostic messages?"
+mode,s,h,al
diff --git a/pkg/utilities/nttools/tunits/abrev.tab b/pkg/utilities/nttools/tunits/abrev.tab
new file mode 100644
index 00000000..90b8b58c
--- /dev/null
+++ b/pkg/utilities/nttools/tunits/abrev.tab
@@ -0,0 +1,62 @@
+# Abbreviation table for tunits task
+#
+# Many units have more than one name or abbreviation. This table lists
+# the standard abbreviation for each set of units. The abbreviation is
+# used internally when computing the conversion factor. Case is not
+# significant in names and regular plurals (made by adding an "s") are
+# converted to the singular. Names should contain only alphabetic characters.
+# Blanks, underscores and digits are not allowed.
+#
+# name abbreviation
+#----------------------------
+meter m
+centimeter cm
+kilometer km
+millimeter mm
+micrometer um
+micron um
+nanometer nm
+metre m
+centimetre cm
+kilometre km
+millimetre mm
+micrometre um
+nanometre nm
+kilogram kg
+gram g
+gm g
+milligram mg
+second s
+sec s
+minute min
+hour hr
+year yr
+radian rad
+degree deg
+arcminute amin
+arcmin amin
+arcsecond asec
+arcsec asec
+angstrom a
+parsec pc
+kiloparsec kpc
+megaparsec mpc
+hertz hz
+kilohertz khz
+megahertz mhz
+gigahertz ghz
+lightyear ly
+newton n
+joule j
+watt w
+calorie c
+kilocalorie kc
+inch in
+inches in
+foot ft
+feet ft
+ounce oz
+pound lb
+liter l
+jansky jy
+millijansky mjy
diff --git a/pkg/utilities/nttools/tunits/abrev.x b/pkg/utilities/nttools/tunits/abrev.x
new file mode 100644
index 00000000..f40ca944
--- /dev/null
+++ b/pkg/utilities/nttools/tunits/abrev.x
@@ -0,0 +1,113 @@
+include <tbset.h>
+include "tunits.h"
+
+#* HISTORY *
+#* B.Simon 07-Jan-99 Original
+
+# FIND_ABREV -- Find the abbreviation for a units string
+
+int procedure find_abrev (ab, units, abrev, maxch)
+
+pointer ab # i: abbreviation hash table descriptor
+char units[ARB] # i: units string
+char abrev[ARB] # o: abbreviation string
+int maxch # i: maximum length of abbreviation string
+#--
+int status
+pointer ptr
+
+int get_unhash()
+
+begin
+ status = get_unhash (ab, units, ptr)
+ if (status == NO) {
+ abrev[1] = EOS
+ } else {
+ call strcpy (Memc[ptr], abrev, maxch)
+ }
+
+ return (status)
+end
+
+# FREE_ABREV -- Free the abbreviation hash table
+
+procedure free_abrev (ab)
+
+pointer ab # i: abbreviation hash table descriptor
+#--
+int index
+pointer sp, keyword, value
+
+int each_unhash()
+
+begin
+ call smark (sp)
+ call salloc (keyword, LEN_UNIT, TY_CHAR)
+
+ index = 0
+ while (each_unhash (ab, index, Memc[keyword],
+ value, LEN_UNIT) != EOF) {
+ if (value != NULL)
+ call mfree (value, TY_CHAR)
+ }
+
+
+ call free_unhash (ab)
+ call sfree (sp)
+end
+
+# READ_ABREV -- Read abbreviations from a table and load into a hash
+
+pointer procedure read_abrev (abrevtab)
+
+char abrevtab[ARB] # i: abbreviation table name
+#--
+int irow, nrow
+pointer tp, c1, c2, sp, units, abrev, ab
+
+string nocolumn "The abbreviation table must have two coulmns"
+
+int tbpsta()
+pointer tbtopn(), tbcnum(), new_unhash()
+
+begin
+ # Dynamic memory for strings
+
+ call smark (sp)
+ call salloc (units, LEN_UNIT, TY_CHAR)
+
+ # Refer to columns numerically because
+ # this is supposed to be a text file
+
+ tp = tbtopn (abrevtab, READ_ONLY, NULL)
+ c1 = tbcnum (tp, 1)
+ c2 = tbcnum (tp, 2)
+
+ if (c1 == NULL || c2 == NULL)
+ call tuniterr (nocolumn, abrevtab)
+
+ # Create hash
+
+ nrow = tbpsta (tp, TBL_NROWS)
+ ab = new_unhash (nrow, LEN_UNIT)
+
+ # Read each row into hash
+
+ do irow = 1, nrow {
+ call malloc (abrev, LEN_UNIT, TY_CHAR)
+
+ call tbegtt (tp, c1, irow, Memc[units], LEN_UNIT)
+ call tbegtt (tp, c2, irow, Memc[abrev], LEN_UNIT)
+
+ call strlwr (Memc[units])
+ call strlwr (Memc[abrev])
+
+ call add_unhash (ab, Memc[units], abrev)
+ }
+
+ # Close table and free memory
+
+ call tbtclo (tp)
+ call sfree (sp)
+ return (ab)
+end
diff --git a/pkg/utilities/nttools/tunits/convertcol.x b/pkg/utilities/nttools/tunits/convertcol.x
new file mode 100644
index 00000000..976ea888
--- /dev/null
+++ b/pkg/utilities/nttools/tunits/convertcol.x
@@ -0,0 +1,68 @@
+include <tbset.h>
+
+#* HISTORY *
+#* B.Simon 07-Jan-99 Original
+
+# CONVERT_COL -- Convert the units of a table column
+
+procedure convert_col (tp, cp, newunits, factor)
+
+pointer tp # i: table descriptor
+pointer cp # i: column descriptor
+char newunits[ARB] # i: new column units
+double factor # i: conversion factor
+#--
+double value
+int nrow, nelem, irow, nlen, ilen
+pointer sp, buffer
+
+int tbpsta(), tbcigi(), tbagtd()
+
+begin
+ # Change column units
+
+ call tbcnit (tp, cp, newunits)
+
+ # Get column dimensions
+
+ nrow = tbpsta (tp, TBL_NROWS)
+ nelem = tbcigi (cp, TBL_COL_LENDATA)
+
+ # Allocate buffer to hold array elements
+
+ call smark (sp)
+ call salloc (buffer, nelem, TY_DOUBLE)
+
+ # Multiply column values by conversion factor
+
+ if (nelem == 1) {
+ # Scalar column, use element get and put
+
+ do irow = 1, nrow {
+ call tbegtd (tp, cp, irow, value)
+ if (! IS_INDEFD (value)) {
+ value = factor * value
+ call tbeptd (tp, cp, irow, value)
+ }
+ }
+
+ } else {
+ # Array element, use array get and put
+
+ do irow = 1, nrow {
+ nlen = tbagtd (tp, cp, irow, Memd[buffer], 1, nelem)
+
+ do ilen = 0, nlen-1 {
+ if (! IS_INDEFD (Memd[buffer+ilen])) {
+ Memd[buffer+ilen] = factor * Memd[buffer+ilen]
+ }
+ }
+
+ call tbaptd (tp, cp, irow, Memd[buffer], 1, nlen)
+ }
+ }
+
+ call sfree (sp)
+end
+
+
diff --git a/pkg/utilities/nttools/tunits/factor.x b/pkg/utilities/nttools/tunits/factor.x
new file mode 100644
index 00000000..3c9a91ac
--- /dev/null
+++ b/pkg/utilities/nttools/tunits/factor.x
@@ -0,0 +1,125 @@
+include "tunits.h"
+
+#* HISTORY *
+#* B.Simon 07-Jan-99 Original
+
+# FIND_FACTOR -- Find conversion factor between two sets of units
+
+double procedure find_factor (ut, punit1, punit2, verbose)
+
+pointer ut # i: units hash descriptor
+pointer punit1 # i: old set of units
+pointer punit2 # i: new set of units
+bool verbose # i: diagnostic message flag
+#--
+double factor
+pointer punit3, punit4, punit5
+
+string noconvert "The old and new units are not compatible"
+
+pointer reduce_factor(), div_unstr()
+
+begin
+ # Reduce old and new units to a common form
+
+ punit3 = reduce_factor (ut, punit1, verbose)
+ punit4 = reduce_factor (ut, punit2, verbose)
+
+ # The conversion factor is the ratio of
+ # the two sets of units when in common form
+
+ punit5 = div_unstr (punit3, punit4)
+
+ # Check to make sure units actually have a common form
+
+ if (TUN_UNPTR(punit5,1) != NULL)
+ call error (1, noconvert)
+
+ factor = TUN_FACTOR (punit5)
+
+ # Print conversion factor
+ if (verbose) {
+ call eprintf ("The conversion factor is %g\n")
+ call pargd (factor)
+ }
+
+ # Free temporary units descriptors
+
+ call free_unstr (punit3)
+ call free_unstr (punit4)
+ call free_unstr (punit5)
+
+ return (factor)
+end
+
+# REDUCE_FACTOR -- Reduce units descriptor to a common set of units (mks)
+
+pointer procedure reduce_factor (ut, punit, verbose)
+
+pointer ut # i: Units hash descriptor
+pointer punit # i: Units string descriptor
+bool verbose # i: diagnostic message flag
+#--
+bool done
+int idx
+pointer sp, units, punit1, punit2, punit3, punit4
+
+int find_units()
+pointer copy_unstr(), pow_unstr(), mul_unstr()
+
+begin
+ # Allocate memory for units string
+
+ call smark (sp)
+ call salloc (units, SZ_FNAME, TY_CHAR)
+
+ # Loop until no more reductions can be performed
+
+ punit1 = copy_unstr (punit)
+
+ repeat {
+ if (verbose) {
+ call str_unstr (punit1, Memc[units], SZ_FNAME)
+ call eprintf ("%s")
+ call pargstr (Memc[units])
+ }
+
+ # Search for a reduction for any term
+
+ done = true
+ do idx = 1, MAXUNIT {
+ if (TUN_UNPTR(punit1,idx) == NULL)
+ break
+
+ if (find_units (ut, TUN_UNITS(punit1,idx), punit2) ==YES) {
+ # Reduction found. Raise conversion factor to
+ # degree of term in descriptor and then multiply
+ # the units by it
+
+ punit3 = pow_unstr (punit2, TUN_POWER(punit1,idx))
+ punit4 = mul_unstr (punit1, punit3)
+
+ call free_unstr (punit1)
+ call free_unstr (punit3)
+
+ punit1 = punit4
+ done = false
+ break
+ }
+ }
+
+ if (verbose) {
+ if (done) {
+ call eprintf ("\n")
+ } else {
+ call eprintf (" is \n")
+ }
+ }
+ } until (done)
+
+ if (verbose)
+ call eprintf ("\n")
+
+ call sfree (sp)
+ return (punit1)
+end
diff --git a/pkg/utilities/nttools/tunits/mkpkg b/pkg/utilities/nttools/tunits/mkpkg
new file mode 100644
index 00000000..3ec0d98b
--- /dev/null
+++ b/pkg/utilities/nttools/tunits/mkpkg
@@ -0,0 +1,19 @@
+# Update the tunits task in the ttools package library
+# Author: Bernie Simon, 11-jan-99
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ abrev.x <tbset.h> "tunits.h"
+ convertcol.x <tbset.h>
+ factor.x "tunits.h"
+ parseunits.x <ctype.h> "parseunits.com"
+ tuniterr.x
+ tunits.x <tbset.h> "tunits.h"
+ unhash.x
+ units.x <tbset.h> "tunits.h"
+ unstr.x "tunits.h"
+ ;
diff --git a/pkg/utilities/nttools/tunits/parseunits.com b/pkg/utilities/nttools/tunits/parseunits.com
new file mode 100644
index 00000000..d5c5bf48
--- /dev/null
+++ b/pkg/utilities/nttools/tunits/parseunits.com
@@ -0,0 +1,9 @@
+# PARSEUNITS.COM -- Global variables used by parse_units
+
+common / parse / tun, abrev, tokbuf, nxttok, debug
+
+pointer tun # descriptor containing results of parse
+pointer abrev # hash table of unit abbreviations
+pointer tokbuf # buffer holding tokens parsed from units string
+int nxttok # index to next free space in token buffer
+int debug # debugging message flag
diff --git a/pkg/utilities/nttools/tunits/parseunits.x b/pkg/utilities/nttools/tunits/parseunits.x
new file mode 100644
index 00000000..1a420785
--- /dev/null
+++ b/pkg/utilities/nttools/tunits/parseunits.x
@@ -0,0 +1,624 @@
+include <ctype.h>
+
+#* B.Simon ?? original
+# Phil Hodge 12-Jul-2005 add 'bool yydebug' and 'int get_token()' to
+# parse_units
+
+define YYMAXDEPTH 32
+define YYOPLEN 1
+define yyparse unit_parse
+
+define SZ_SHORTSTR 31
+
+define Y_WRONG 257
+define Y_DONE 258
+define Y_LPAR 259
+define Y_RPAR 260
+define Y_CU 261
+define Y_SQ 262
+define Y_ID 263
+define Y_NUM 264
+define Y_DIV 265
+define Y_MUL 266
+define Y_POW 267
+define yyclearin yychar = -1
+define yyerrok yyerrflag = 0
+define YYMOVE call amovi (Memi[$1], Memi[$2], YYOPLEN)
+define YYERRCODE 256
+
+# line 159 "parseunits.y"
+
+
+# PARSE_UNITS -- Parse a units string into the internal format
+
+pointer procedure parse_units (ab, units)
+
+pointer ab # i: abbreviation hash table
+char units[ARB] # i: expression to be parsed
+#--
+include "parseunits.com"
+
+int len, fd
+pointer sp
+
+string syntax "Syntax error in units"
+
+bool yydebug
+int strlen(), stropen(), yyparse()
+int get_token()
+extern get_token
+
+begin
+ len = strlen (units) + 1
+ fd = stropen (units, len, READ_ONLY)
+
+ call smark (sp)
+ call salloc (tokbuf, SZ_FNAME, TY_CHAR)
+
+ debug = NO
+ yydebug = (debug == YES)
+ nxttok = 0
+ abrev = ab
+ tun = NULL
+
+ if (yyparse (fd, yydebug, get_token) == ERR)
+ call tuniterr (syntax, units)
+
+ call close (fd)
+ call sfree (sp)
+ return (tun)
+end
+
+# GET_TOKEN -- Retrieve next token from units string
+
+int procedure get_token (fd, value)
+
+int fd # i: File containing expression to be lexed
+pointer value # o: Address on parse stack to store token
+#--
+include "parseunits.com"
+
+char ch
+int type, index, powers[4]
+pointer sp, typename, token
+
+string pownames "sq,square,cu,cubic"
+data powers / Y_SQ, Y_SQ, Y_CU, Y_CU /
+
+bool streq()
+int getc(), word_match()
+
+begin
+ call smark (sp)
+ call salloc (typename, SZ_FNAME, TY_CHAR)
+
+ token = tokbuf + nxttok
+ Memi[value] = token
+
+ repeat {
+ ch = getc (fd, ch)
+ } until (ch != ' ' && ch != '\t')
+
+ if (ch == EOF) {
+ type = Y_DONE
+ call strcpy ("END", Memc[typename], SZ_FNAME)
+
+ } else if (IS_ALPHA (ch)) {
+ type = Y_ID
+ call strcpy ("IDENT", Memc[typename], SZ_FNAME)
+
+ while (IS_ALPHA (ch)) {
+ Memc[tokbuf+nxttok] = ch
+ nxttok = nxttok + 1
+ ch = getc (fd, ch)
+ }
+ call ungetc (fd, ch)
+
+ Memc[tokbuf+nxttok] = EOS
+ index = word_match (Memc[token], pownames)
+
+ if (index > 0) {
+ type = powers[index]
+ call strcpy ("POWER", Memc[typename], SZ_FNAME)
+
+ } else if (streq (Memc[token], "per")) {
+ type = Y_DIV
+ call strcpy ("DIV", Memc[typename], SZ_FNAME)
+ }
+
+ } else if (ch == '-' || IS_DIGIT (ch)) {
+ type = Y_NUM
+ call strcpy ("NUMBER", Memc[typename], SZ_FNAME)
+
+ Memc[tokbuf+nxttok] = ch
+ nxttok = nxttok + 1
+ ch = getc (fd, ch)
+
+ while (IS_DIGIT (ch)) {
+ Memc[tokbuf+nxttok] = ch
+ nxttok = nxttok + 1
+ ch = getc (fd, ch)
+ }
+ call ungetc (fd, ch)
+
+ } else {
+ Memc[tokbuf+nxttok] = ch
+ nxttok = nxttok + 1
+
+ switch (ch) {
+ case '*':
+ ch = getc (fd, ch)
+ if (ch == '*') {
+ type = Y_POW
+ call strcpy ("EXPON", Memc[typename], SZ_FNAME)
+
+ Memc[tokbuf+nxttok] = ch
+ nxttok = nxttok + 1
+ } else {
+ type = Y_MUL
+ call strcpy ("MUL", Memc[typename], SZ_FNAME)
+
+ call ungetc (fd, ch)
+ }
+
+ case '/':
+ type = Y_DIV
+ call strcpy ("DIV", Memc[typename], SZ_FNAME)
+
+ case '^':
+ type = Y_POW
+ call strcpy ("EXPON", Memc[typename], SZ_FNAME)
+
+ default:
+ type = Y_WRONG
+ call strcpy ("ERROR", Memc[typename], SZ_FNAME)
+ }
+ }
+
+ Memc[tokbuf+nxttok] = EOS
+ nxttok = nxttok + 1
+
+ if (debug == YES) {
+ call eprintf ("Token is %s [%s]\n")
+ if (Memc[token] == EOS) {
+ call pargstr ("EOS")
+ } else {
+ call pargstr (Memc[token])
+ }
+ call pargstr (Memc[typename])
+ }
+
+ call sfree (sp)
+ return (type)
+end
+define YYNPROD 15
+define YYLAST 43
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# Parser for yacc output, translated to the IRAF SPP language. The contents
+# of this file form the bulk of the source of the parser produced by Yacc.
+# Yacc recognizes several macros in the yaccpar input source and replaces
+# them as follows:
+# A user suppled "global" definitions and declarations
+# B parser tables
+# C user supplied actions (reductions)
+# The remainder of the yaccpar code is not changed.
+
+define yystack_ 10 # statement labels for gotos
+define yynewstate_ 20
+define yydefault_ 30
+define yyerrlab_ 40
+define yyabort_ 50
+
+define YYFLAG (-1000) # defs used in user actions
+define YYERROR goto yyerrlab_
+define YYACCEPT return (OK)
+define YYABORT return (ERR)
+
+
+# YYPARSE -- Parse the input stream, returning OK if the source is
+# syntactically acceptable (i.e., if compilation is successful),
+# otherwise ERR. The parameters YYMAXDEPTH and YYOPLEN must be
+# supplied by the caller in the %{ ... %} section of the Yacc source.
+# The token value stack is a dynamically allocated array of operand
+# structures, with the length and makeup of the operand structure being
+# application dependent.
+
+int procedure yyparse (fd, yydebug, yylex)
+
+int fd # stream to be parsed
+bool yydebug # print debugging information?
+int yylex() # user-supplied lexical input function
+extern yylex()
+
+short yys[YYMAXDEPTH] # parser stack -- stacks tokens
+pointer yyv # pointer to token value stack
+pointer yyval # value returned by action
+pointer yylval # value of token
+int yyps # token stack pointer
+pointer yypv # value stack pointer
+int yychar # current input token number
+int yyerrflag # error recovery flag
+int yynerrs # number of errors
+
+short yyj, yym # internal variables
+pointer yysp, yypvt
+short yystate, yyn
+int yyxi, i
+errchk salloc, yylex
+
+
+include "parseunits.com"
+
+char units[SZ_FNAME]
+
+int num_unstr()
+pointer mul_unstr(), div_unstr(), pow_unstr(), set_unstr()
+
+short yyexca[6]
+data (yyexca(i),i= 1, 6) / -1, 1, 0, -1, -2, 0/
+short yyact[43]
+data (yyact(i),i= 1, 8) / 23, 10, 11, 13, 13, 12, 11, 13/
+data (yyact(i),i= 9, 16) / 12, 11, 13, 17, 3, 24, 16, 4/
+data (yyact(i),i= 17, 24) / 22, 8, 9, 7, 4, 19, 8, 9/
+data (yyact(i),i= 25, 32) / 7, 8, 9, 7, 18, 2, 6, 5/
+data (yyact(i),i= 33, 40) / 1, 0, 14, 0, 15, 0, 0, 0/
+data (yyact(i),i= 41, 43) / 0, 20, 21/
+short yypact[25]
+data (yypact(i),i= 1, 8) /-244,-1000,-257,-1000,-239,-236,-1000,-253/
+data (yypact(i),i= 9, 16) /-235,-242,-1000,-239,-239,-248,-260,-1000/
+data (yypact(i),i= 17, 24) /-251,-1000,-1000,-1000,-263,-264,-1000,-1000/
+data (yypact(i),i= 25, 25) /-1000/
+short yypgo[5]
+data (yypgo(i),i= 1, 5) / 0, 32, 29, 31, 30/
+short yyr1[15]
+data (yyr1(i),i= 1, 8) / 0, 1, 1, 2, 2, 2, 2, 2/
+data (yyr1(i),i= 9, 15) / 3, 3, 4, 4, 4, 4, 4/
+short yyr2[15]
+data (yyr2(i),i= 1, 8) / 0, 2, 1, 3, 3, 3, 3, 1/
+data (yyr2(i),i= 9, 15) / 2, 1, 3, 2, 2, 2, 1/
+short yychk[25]
+data (yychk(i),i= 1, 8) /-1000, -1, -2, 256, 259, -3, -4, 263/
+data (yychk(i),i= 9, 16) / 261, 262, 258, 266, 265, 267, -2, -4/
+data (yychk(i),i= 17, 24) / 267, 264, 263, 263, -2, -2, 264, 260/
+data (yychk(i),i= 25, 25) / 264/
+short yydef[25]
+data (yydef(i),i= 1, 8) / 0, -2, 0, 2, 0, 7, 9, 14/
+data (yydef(i),i= 9, 16) / 0, 0, 1, 0, 0, 0, 0, 8/
+data (yydef(i),i= 17, 24) / 0, 11, 12, 13, 4, 5, 6, 3/
+data (yydef(i),i= 25, 25) / 10/
+
+begin
+ call smark (yysp)
+ call salloc (yyv, (YYMAXDEPTH+2) * YYOPLEN, TY_STRUCT)
+
+ # Initialization. The first element of the dynamically allocated
+ # token value stack (yyv) is used for yyval, the second for yylval,
+ # and the actual stack starts with the third element.
+
+ yystate = 0
+ yychar = -1
+ yynerrs = 0
+ yyerrflag = 0
+ yyps = 0
+ yyval = yyv
+ yylval = yyv + YYOPLEN
+ yypv = yylval
+
+yystack_
+ # SHIFT -- Put a state and value onto the stack. The token and
+ # value stacks are logically the same stack, implemented as two
+ # separate arrays.
+
+ if (yydebug) {
+ call printf ("state %d, char 0%o\n")
+ call pargs (yystate)
+ call pargi (yychar)
+ }
+ yyps = yyps + 1
+ yypv = yypv + YYOPLEN
+ if (yyps > YYMAXDEPTH) {
+ call sfree (yysp)
+ call eprintf ("yacc stack overflow\n")
+ return (ERR)
+ }
+ yys[yyps] = yystate
+ YYMOVE (yyval, yypv)
+
+yynewstate_
+ # Process the new state.
+ yyn = yypact[yystate+1]
+
+ if (yyn <= YYFLAG)
+ goto yydefault_ # simple state
+
+ # The variable "yychar" is the lookahead token.
+ if (yychar < 0) {
+ yychar = yylex (fd, yylval)
+ if (yychar < 0)
+ yychar = 0
+ }
+ yyn = yyn + yychar
+ if (yyn < 0 || yyn >= YYLAST)
+ goto yydefault_
+
+ yyn = yyact[yyn+1]
+ if (yychk[yyn+1] == yychar) { # valid shift
+ yychar = -1
+ YYMOVE (yylval, yyval)
+ yystate = yyn
+ if (yyerrflag > 0)
+ yyerrflag = yyerrflag - 1
+ goto yystack_
+ }
+
+yydefault_
+ # Default state action.
+
+ yyn = yydef[yystate+1]
+ if (yyn == -2) {
+ if (yychar < 0) {
+ yychar = yylex (fd, yylval)
+ if (yychar < 0)
+ yychar = 0
+ }
+
+ # Look through exception table.
+ yyxi = 1
+ while ((yyexca[yyxi] != (-1)) || (yyexca[yyxi+1] != yystate))
+ yyxi = yyxi + 2
+ for (yyxi=yyxi+2; yyexca[yyxi] >= 0; yyxi=yyxi+2) {
+ if (yyexca[yyxi] == yychar)
+ break
+ }
+
+ yyn = yyexca[yyxi+1]
+ if (yyn < 0) {
+ call sfree (yysp)
+ return (OK) # ACCEPT -- all done
+ }
+ }
+
+
+ # SYNTAX ERROR -- resume parsing if possible.
+
+ if (yyn == 0) {
+ switch (yyerrflag) {
+ case 0, 1, 2:
+ if (yyerrflag == 0) { # brand new error
+ call eprintf ("syntax error\n")
+yyerrlab_
+ yynerrs = yynerrs + 1
+ # fall through...
+ }
+
+ # case 1:
+ # case 2: incompletely recovered error ... try again
+ yyerrflag = 3
+
+ # Find a state where "error" is a legal shift action.
+ while (yyps >= 1) {
+ yyn = yypact[yys[yyps]+1] + YYERRCODE
+ if ((yyn >= 0) && (yyn < YYLAST) &&
+ (yychk[yyact[yyn+1]+1] == YYERRCODE)) {
+ # Simulate a shift of "error".
+ yystate = yyact[yyn+1]
+ goto yystack_
+ }
+ yyn = yypact[yys[yyps]+1]
+
+ # The current yyps has no shift on "error", pop stack.
+ if (yydebug) {
+ call printf ("error recovery pops state %d, ")
+ call pargs (yys[yyps])
+ call printf ("uncovers %d\n")
+ call pargs (yys[yyps-1])
+ }
+ yyps = yyps - 1
+ yypv = yypv - YYOPLEN
+ }
+
+ # ABORT -- There is no state on the stack with an error shift.
+yyabort_
+ call sfree (yysp)
+ return (ERR)
+
+
+ case 3: # No shift yet; clobber input char.
+
+ if (yydebug) {
+ call printf ("error recovery discards char %d\n")
+ call pargi (yychar)
+ }
+
+ if (yychar == 0)
+ goto yyabort_ # don't discard EOF, quit
+ yychar = -1
+ goto yynewstate_ # try again in the same state
+ }
+ }
+
+
+ # REDUCE -- Reduction by production yyn.
+
+ if (yydebug) {
+ call printf ("reduce %d\n")
+ call pargs (yyn)
+ }
+ yyps = yyps - yyr2[yyn+1]
+ yypvt = yypv
+ yypv = yypv - yyr2[yyn+1] * YYOPLEN
+ YYMOVE (yypv + YYOPLEN, yyval)
+ yym = yyn
+
+ # Consult goto table to find next state.
+ yyn = yyr1[yyn+1]
+ yyj = yypgo[yyn+1] + yys[yyps] + 1
+ if (yyj >= YYLAST)
+ yystate = yyact[yypgo[yyn+1]+1]
+ else {
+ yystate = yyact[yyj+1]
+ if (yychk[yystate+1] != -yyn)
+ yystate = yyact[yypgo[yyn+1]+1]
+ }
+
+ # Perform action associated with the grammar rule, if any.
+ switch (yym) {
+
+case 1:
+# line 28 "parseunits.y"
+{
+ # Normal exit. Return pointer to units structure
+ if (debug == YES)
+ call eprintf ("\n")
+
+ tun = Memi[yypvt-YYOPLEN]
+ return (OK)
+ }
+case 2:
+# line 36 "parseunits.y"
+{
+ # Syntax error
+ if (debug == YES)
+ call eprintf ("\n")
+
+ return (ERR)
+ }
+case 3:
+# line 45 "parseunits.y"
+{
+ # Parenthesized expression
+ Memi[yyval] = Memi[yypvt-2*YYOPLEN]
+ }
+case 4:
+# line 49 "parseunits.y"
+{
+ # Multiply two units expressions
+ Memi[yyval] = mul_unstr (Memi[yypvt-2*YYOPLEN], Memi[yypvt])
+ call free_unstr (Memi[yypvt-2*YYOPLEN])
+ call free_unstr (Memi[yypvt])
+
+ if (debug == YES) {
+ call str_unstr (Memi[yyval], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ }
+case 5:
+# line 61 "parseunits.y"
+{
+ # Divide two units expressions
+ Memi[yyval] = div_unstr (Memi[yypvt-2*YYOPLEN], Memi[yypvt])
+ call free_unstr (Memi[yypvt-2*YYOPLEN])
+ call free_unstr (Memi[yypvt])
+
+ if (debug == YES) {
+ call str_unstr (Memi[yyval], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ }
+case 6:
+# line 73 "parseunits.y"
+{
+ # Raise expression to a power
+ Memi[yyval] = pow_unstr (Memi[yypvt-2*YYOPLEN], num_unstr (Memc[Memi[yypvt]]))
+ call free_unstr (Memi[yypvt-2*YYOPLEN])
+
+ if (debug == YES) {
+ call str_unstr (Memi[yyval], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ }
+case 7:
+# line 84 "parseunits.y"
+{
+ # List of terms
+ Memi[yyval] = Memi[yypvt]
+ }
+case 8:
+# line 89 "parseunits.y"
+{
+ # Implicit multiplication
+ Memi[yyval] = mul_unstr (Memi[yypvt-YYOPLEN], Memi[yypvt])
+ call free_unstr (Memi[yypvt-YYOPLEN])
+ call free_unstr (Memi[yypvt])
+
+ if (debug == YES) {
+ call str_unstr (Memi[yyval], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ }
+case 9:
+# line 101 "parseunits.y"
+{
+ # Simple term
+ Memi[yyval] = Memi[yypvt]
+ }
+case 10:
+# line 106 "parseunits.y"
+{
+ # Raise units to a power
+ Memi[yyval] = set_unstr (abrev, Memc[Memi[yypvt-2*YYOPLEN]],
+ num_unstr (Memc[Memi[yypvt]]))
+
+ if (debug == YES) {
+ call str_unstr (Memi[yyval], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ }
+case 11:
+# line 117 "parseunits.y"
+{
+ # Implicitly raise to a power
+ Memi[yyval] = set_unstr (abrev, Memc[Memi[yypvt-YYOPLEN]],
+ num_unstr (Memc[Memi[yypvt]]))
+
+ if (debug == YES) {
+ call str_unstr (Memi[yyval], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ }
+case 12:
+# line 128 "parseunits.y"
+{
+ # Cubic prefix
+ Memi[yyval] = set_unstr (abrev, Memc[Memi[yypvt]], 3)
+
+ if (debug == YES) {
+ call str_unstr (Memi[yyval], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ }
+case 13:
+# line 138 "parseunits.y"
+{
+ # Square prefix
+ Memi[yyval] = set_unstr (abrev, Memc[Memi[yypvt]], 2)
+
+ if (debug == YES) {
+ call str_unstr (Memi[yyval], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ }
+case 14:
+# line 148 "parseunits.y"
+{
+ # Simple name
+ Memi[yyval] = set_unstr (abrev, Memc[Memi[yypvt]], 1)
+
+ if (debug == YES) {
+ call str_unstr (Memi[yyval], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ } }
+
+ goto yystack_ # stack new state and value
+end
diff --git a/pkg/utilities/nttools/tunits/parseunits.y b/pkg/utilities/nttools/tunits/parseunits.y
new file mode 100644
index 00000000..088395ac
--- /dev/null
+++ b/pkg/utilities/nttools/tunits/parseunits.y
@@ -0,0 +1,322 @@
+%{
+include <ctype.h>
+
+define YYMAXDEPTH 32
+define YYOPLEN 1
+define yyparse unit_parse
+
+define SZ_SHORTSTR 31
+
+%L
+include "parseunits.com"
+
+char units[SZ_FNAME]
+
+int num_unstr()
+pointer mul_unstr(), div_unstr(), pow_unstr(), set_unstr()
+
+%}
+
+%token Y_WRONG Y_DONE Y_LPAR Y_RPAR Y_CU Y_SQ Y_ID Y_NUM
+
+%left Y_DIV
+%left Y_MUL
+%right Y_POW
+
+%%
+
+unit : expr Y_DONE {
+ # Normal exit. Return pointer to units structure
+ if (debug == YES)
+ call eprintf ("\n")
+
+ tun = Memi[$1]
+ return (OK)
+ }
+ | error {
+ # Syntax error
+ if (debug == YES)
+ call eprintf ("\n")
+
+ return (ERR)
+ }
+ ;
+
+expr : Y_LPAR expr Y_RPAR {
+ # Parenthesized expression
+ Memi[$$] = Memi[$1]
+ }
+ | expr Y_MUL expr {
+ # Multiply two units expressions
+ Memi[$$] = mul_unstr (Memi[$1], Memi[$3])
+ call free_unstr (Memi[$1])
+ call free_unstr (Memi[$3])
+
+ if (debug == YES) {
+ call str_unstr (Memi[$$], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ }
+ | expr Y_DIV expr {
+ # Divide two units expressions
+ Memi[$$] = div_unstr (Memi[$1], Memi[$3])
+ call free_unstr (Memi[$1])
+ call free_unstr (Memi[$3])
+
+ if (debug == YES) {
+ call str_unstr (Memi[$$], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ }
+ | expr Y_POW Y_NUM {
+ # Raise expression to a power
+ Memi[$$] = pow_unstr (Memi[$1], num_unstr (Memc[Memi[$3]]))
+ call free_unstr (Memi[$1])
+
+ if (debug == YES) {
+ call str_unstr (Memi[$$], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ }
+ | termlist {
+ # List of terms
+ Memi[$$] = Memi[$1]
+ }
+ ;
+termlist: termlist term {
+ # Implicit multiplication
+ Memi[$$] = mul_unstr (Memi[$1], Memi[$2])
+ call free_unstr (Memi[$1])
+ call free_unstr (Memi[$2])
+
+ if (debug == YES) {
+ call str_unstr (Memi[$$], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ }
+ | term {
+ # Simple term
+ Memi[$$] = Memi[$1]
+ }
+ ;
+term : Y_ID Y_POW Y_NUM {
+ # Raise units to a power
+ Memi[$$] = set_unstr (abrev, Memc[Memi[$1]],
+ num_unstr (Memc[Memi[$3]]))
+
+ if (debug == YES) {
+ call str_unstr (Memi[$$], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ }
+ | Y_ID Y_NUM {
+ # Implicitly raise to a power
+ Memi[$$] = set_unstr (abrev, Memc[Memi[$1]],
+ num_unstr (Memc[Memi[$2]]))
+
+ if (debug == YES) {
+ call str_unstr (Memi[$$], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ }
+ | Y_CU Y_ID {
+ # Cubic prefix
+ Memi[$$] = set_unstr (abrev, Memc[Memi[$2]], 3)
+
+ if (debug == YES) {
+ call str_unstr (Memi[$$], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ }
+ | Y_SQ Y_ID {
+ # Square prefix
+ Memi[$$] = set_unstr (abrev, Memc[Memi[$2]], 2)
+
+ if (debug == YES) {
+ call str_unstr (Memi[$$], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ }
+ | Y_ID {
+ # Simple name
+ Memi[$$] = set_unstr (abrev, Memc[Memi[$1]], 1)
+
+ if (debug == YES) {
+ call str_unstr (Memi[$$], units, SZ_FNAME)
+ call eprintf ("Units are %s\n")
+ call pargstr (units)
+ }
+ }
+ ;
+%%
+
+# PARSE_UNITS -- Parse a units string into the internal format
+
+pointer procedure parse_units (ab, units)
+
+pointer ab # i: abbreviation hash table
+char units[ARB] # i: expression to be parsed
+#--
+include "parseunits.com"
+
+int len, fd
+pointer sp
+
+string syntax "Syntax error in units"
+
+bool yydebug
+int strlen(), stropen(), yyparse()
+int get_token()
+extern get_token
+
+begin
+ len = strlen (units) + 1
+ fd = stropen (units, len, READ_ONLY)
+
+ call smark (sp)
+ call salloc (tokbuf, SZ_FNAME, TY_CHAR)
+
+ debug = NO
+ yydebug = (debug == YES)
+ nxttok = 0
+ abrev = ab
+ tun = NULL
+
+ if (yyparse (fd, yydebug, get_token) == ERR)
+ call tuniterr (syntax, units)
+
+ call close (fd)
+ call sfree (sp)
+ return (tun)
+end
+
+# GET_TOKEN -- Retrieve next token from units string
+
+int procedure get_token (fd, value)
+
+int fd # i: File containing expression to be lexed
+pointer value # o: Address on parse stack to store token
+#--
+include "parseunits.com"
+
+char ch
+int type, index, powers[4]
+pointer sp, typename, token
+
+string pownames "sq,square,cu,cubic"
+data powers / Y_SQ, Y_SQ, Y_CU, Y_CU /
+
+bool streq()
+int getc(), word_match()
+
+begin
+ call smark (sp)
+ call salloc (typename, SZ_FNAME, TY_CHAR)
+
+ token = tokbuf + nxttok
+ Memi[value] = token
+
+ repeat {
+ ch = getc (fd, ch)
+ } until (ch != ' ' && ch != '\t')
+
+ if (ch == EOF) {
+ type = Y_DONE
+ call strcpy ("END", Memc[typename], SZ_FNAME)
+
+ } else if (IS_ALPHA (ch)) {
+ type = Y_ID
+ call strcpy ("IDENT", Memc[typename], SZ_FNAME)
+
+ while (IS_ALPHA (ch)) {
+ Memc[tokbuf+nxttok] = ch
+ nxttok = nxttok + 1
+ ch = getc (fd, ch)
+ }
+ call ungetc (fd, ch)
+
+ Memc[tokbuf+nxttok] = EOS
+ index = word_match (Memc[token], pownames)
+
+ if (index > 0) {
+ type = powers[index]
+ call strcpy ("POWER", Memc[typename], SZ_FNAME)
+
+ } else if (streq (Memc[token], "per")) {
+ type = Y_DIV
+ call strcpy ("DIV", Memc[typename], SZ_FNAME)
+ }
+
+ } else if (ch == '-' || IS_DIGIT (ch)) {
+ type = Y_NUM
+ call strcpy ("NUMBER", Memc[typename], SZ_FNAME)
+
+ Memc[tokbuf+nxttok] = ch
+ nxttok = nxttok + 1
+ ch = getc (fd, ch)
+
+ while (IS_DIGIT (ch)) {
+ Memc[tokbuf+nxttok] = ch
+ nxttok = nxttok + 1
+ ch = getc (fd, ch)
+ }
+ call ungetc (fd, ch)
+
+ } else {
+ Memc[tokbuf+nxttok] = ch
+ nxttok = nxttok + 1
+
+ switch (ch) {
+ case '*':
+ ch = getc (fd, ch)
+ if (ch == '*') {
+ type = Y_POW
+ call strcpy ("EXPON", Memc[typename], SZ_FNAME)
+
+ Memc[tokbuf+nxttok] = ch
+ nxttok = nxttok + 1
+ } else {
+ type = Y_MUL
+ call strcpy ("MUL", Memc[typename], SZ_FNAME)
+
+ call ungetc (fd, ch)
+ }
+
+ case '/':
+ type = Y_DIV
+ call strcpy ("DIV", Memc[typename], SZ_FNAME)
+
+ case '^':
+ type = Y_POW
+ call strcpy ("EXPON", Memc[typename], SZ_FNAME)
+
+ default:
+ type = Y_WRONG
+ call strcpy ("ERROR", Memc[typename], SZ_FNAME)
+ }
+ }
+
+ Memc[tokbuf+nxttok] = EOS
+ nxttok = nxttok + 1
+
+ if (debug == YES) {
+ call eprintf ("Token is %s [%s]\n")
+ if (Memc[token] == EOS) {
+ call pargstr ("EOS")
+ } else {
+ call pargstr (Memc[token])
+ }
+ call pargstr (Memc[typename])
+ }
+
+ call sfree (sp)
+ return (type)
+end
diff --git a/pkg/utilities/nttools/tunits/tuniterr.x b/pkg/utilities/nttools/tunits/tuniterr.x
new file mode 100644
index 00000000..25a750c5
--- /dev/null
+++ b/pkg/utilities/nttools/tunits/tuniterr.x
@@ -0,0 +1,24 @@
+#* HISTORY *
+#* B.Simon 07-Jan-99 Original
+
+# TUNITERR -- Print error message for tunits
+
+procedure tuniterr (errstr, errval)
+
+char errstr[ARB] # i: error message string
+char errval[ARB] # i: value which caused error
+#--
+pointer sp, errmsg
+
+begin
+ call smark (sp)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ call sprintf (Memc[errmsg], SZ_LINE, "%s (%s)")
+ call pargstr (errstr)
+ call pargstr (errval)
+
+ call error (1, Memc[errmsg])
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tunits/tunits.h b/pkg/utilities/nttools/tunits/tunits.h
new file mode 100644
index 00000000..f5c2162a
--- /dev/null
+++ b/pkg/utilities/nttools/tunits/tunits.h
@@ -0,0 +1,14 @@
+# TUNITS.H -- Structure and constants used by tunits
+
+define MAXUNIT 8
+define LEN_UNIT 15
+
+define LEN_TUNSTRUCT (SZ_DOUBLE+2*MAXUNIT)
+
+define TUN_FACTOR Memd[P2D($1)] # conversion factor
+define TUN_UNPTR Memi[$1+SZ_DOUBLE+$2] # ptr to units string
+define TUN_POWER Memi[$1+SZ_DOUBLE+MAXUNIT+$2] # units power
+
+define TUN_UNITS Memc[TUN_UNPTR($1,$2)] # units string
+
+define FINALS "m,kg,s,rad,hz"
diff --git a/pkg/utilities/nttools/tunits/tunits.x b/pkg/utilities/nttools/tunits/tunits.x
new file mode 100644
index 00000000..526bca11
--- /dev/null
+++ b/pkg/utilities/nttools/tunits/tunits.x
@@ -0,0 +1,112 @@
+include <tbset.h>
+include "tunits.h"
+
+#* HISTORY *
+#* B.Simon 07-Jan-99 Original
+
+# TUNITS -- Convert table column from one set of units to another
+
+procedure tunits ()
+
+#--
+pointer table # table name
+pointer column # column name
+pointer newunits # new column units
+pointer oldunits # old column units
+pointer abrevtab # table of unit abbreviations
+pointer unittab # table of unit conversions
+bool verbose # print diagnostic messages
+
+double factor
+int type
+pointer sp, tp, cp, ab, ut, punit1, punit2
+
+string nocolumn "Column not found"
+string unitblank "Units parameter is blank"
+string notfloat "Table column is not floating point"
+
+bool clgetb(), isblank()
+double find_factor()
+int tbcigi()
+pointer tbtopn(), read_abrev(), read_units(), parse_units()
+
+begin
+ # Allocate memory for temporary strings
+
+ call smark (sp)
+ call salloc (table, SZ_FNAME, TY_CHAR)
+ call salloc (column, SZ_FNAME, TY_CHAR)
+ call salloc (newunits, SZ_FNAME, TY_CHAR)
+ call salloc (oldunits, SZ_FNAME, TY_CHAR)
+ call salloc (abrevtab, SZ_FNAME, TY_CHAR)
+ call salloc (unittab, SZ_FNAME, TY_CHAR)
+
+ # Read required task parameters
+
+ call clgstr ("table", Memc[table], SZ_FNAME)
+ call clgstr ("column", Memc[column], SZ_FNAME)
+ call clgstr ("newunits", Memc[newunits], SZ_FNAME)
+ call clgstr ("oldunits", Memc[oldunits], SZ_FNAME)
+ call clgstr ("abrevtab", Memc[abrevtab], SZ_FNAME)
+ call clgstr ("unittab", Memc[unittab], SZ_FNAME)
+ verbose = clgetb ("verbose")
+
+ # Open table, find column
+
+ tp = tbtopn (Memc[table], READ_WRITE, NULL)
+ call tbcfnd (tp, Memc[column], cp, 1)
+ if (cp == NULL)
+ call tuniterr (nocolumn, Memc[column])
+
+ # Read column units if old units are blank
+
+ if (isblank (Memc[oldunits]))
+ call tbcigt (cp, TBL_COL_UNITS, Memc[oldunits], SZ_FNAME)
+
+ call strlwr (Memc[oldunits])
+ call strlwr (Memc[newunits])
+
+ # Check to see if units are not blank
+
+ if (isblank (Memc[oldunits]))
+ call tuniterr (unitblank, "oldunits")
+
+ if (isblank (Memc[newunits]))
+ call tuniterr (unitblank, "newunits")
+
+ # Check to see if column is floating point
+
+ type = tbcigi (cp, TBL_COL_DATATYPE)
+ if (type != TY_REAL && type != TY_DOUBLE)
+ call tuniterr (notfloat, Memc[column])
+
+ # Read units and abbreviation tables into hashes
+
+ ab = read_abrev (Memc[abrevtab])
+ ut = read_units (ab, Memc[unittab])
+
+ # Convert units to internal form
+
+ punit1 = parse_units (ab, Memc[oldunits])
+ punit2 = parse_units (ab, Memc[newunits])
+
+ # Find conversion factor between units
+
+ factor = find_factor (ut, punit1, punit2, verbose)
+
+ # Apply conversion factor to table column
+
+ call convert_col (tp, cp, Memc[newunits], factor)
+
+ # Close table and free allocated memory
+
+ call tbtclo (tp)
+
+ call free_abrev (ab)
+ call free_units (ut)
+
+ call free_unstr (punit1)
+ call free_unstr (punit2)
+
+ call sfree (sp)
+end
diff --git a/pkg/utilities/nttools/tunits/unhash.x b/pkg/utilities/nttools/tunits/unhash.x
new file mode 100644
index 00000000..3ae9c24e
--- /dev/null
+++ b/pkg/utilities/nttools/tunits/unhash.x
@@ -0,0 +1,212 @@
+# A set of procedures that implement a generic hash table. The hash table
+# stores the key, plus a pointer to the value structure. It should be
+# wrapped in a more specific set of calls that can read the value structure
+
+define LEN_UNHSTRUCT 5
+
+define UNH_SIZE Memi[$1]
+define UNH_NEXT Memi[$1+1]
+define UNH_KEYBUF Memi[$1+2]
+define UNH_VALBUF Memi[$1+3]
+define UNH_STRBUF Memi[$1+4]
+
+define UNH_KEY Memi[UNH_KEYBUF($1)+$2]
+define UNH_VALUE Memi[UNH_VALBUF($1)+$2]
+
+#* HISTORY *
+#* B.Simon 07-Jan-99 Original
+
+# ADD_UNHASH -- Add a new keyword and value to the hash table
+
+procedure add_unhash (hash, keyword, value)
+
+pointer hash # i: Descriptor of hash table
+char keyword[ARB] # i: Keyword to add to hash table
+pointer value # i: Value descriptor
+#--
+int index, nc
+
+string duplicate "Cannot add duplicate keyword to hash table"
+
+int gstrcpy(), loc_unhash()
+
+begin
+ # Find where keyword should be inserted
+
+ index = loc_unhash (hash, keyword)
+
+ # Adding duplicate keywords is not allowed
+
+ if (UNH_KEY(hash,index) != NULL) {
+ call tuniterr (duplicate, keyword)
+
+ } else {
+ UNH_KEY(hash,index) = UNH_NEXT(hash)
+ UNH_VALUE(hash,index) = value
+
+ nc = gstrcpy (keyword, Memc[UNH_NEXT(hash)], ARB)
+ UNH_NEXT(hash) = UNH_NEXT(hash) + nc + 1
+ }
+end
+
+# CALC_UNHASH -- Calculate hash index and step size from keyword
+
+procedure calc_unhash (hash, keyword, index, step)
+
+pointer hash # i: Descriptor of hash table
+char keyword[ARB] # i: Keyword to search for in hash table
+int index # o: Location to place keyword at in hash
+int step # o: Step size in case location is filled
+#--
+int ic
+
+begin
+ # Standard hash table function based on munging characters
+
+ index = 0
+ step = 0
+
+ for (ic = 1; keyword[ic] != EOS; ic = ic + 1) {
+ index = 2 * index + keyword[ic]
+ step = step + keyword[ic]
+ }
+
+ # This line ensures the step size is odd
+
+ step = step - mod (step, 2) + 1
+end
+
+# EACH_UNHASH -- Retrieve values from hash table serially
+
+int procedure each_unhash (hash, index, keyword, value, maxch)
+
+pointer hash # i: Descriptor of hash table
+int index # u: Index of next slot in hash table to examine
+char keyword[ARB] # o: Keyword name
+pointer value # o: Keyword value
+int maxch # i: Maximum length of keyword
+#--
+
+begin
+ while (index < UNH_SIZE(hash)) {
+ if (UNH_KEY(hash,index) != NULL) {
+ call strcpy (Memc[UNH_KEY(hash,index)], keyword, maxch)
+ value = UNH_VALUE(hash,index)
+ index = index + 1
+ return (OK)
+ }
+
+ index = index + 1
+ }
+
+ return (EOF)
+end
+
+# FREE_UNHASH -- Free a hash table
+
+procedure free_unhash (hash)
+
+pointer hash # i: hash table descriptor
+#--
+
+begin
+ # This code assumes that all memory associated
+ # with the values has already been freed
+
+ call mfree (UNH_STRBUF(hash), TY_CHAR)
+ call mfree (UNH_VALBUF(hash), TY_INT)
+ call mfree (UNH_KEYBUF(hash), TY_INT)
+ call mfree (hash, TY_INT)
+end
+
+# GET_UNHASH -- Return a keyword's value from a hash
+
+int procedure get_unhash (hash, keyword, value)
+
+pointer hash # i: Descriptor of hash table
+char keyword[ARB] # i: Keyword to add to hash table
+pointer value # o: pointer to hash table value
+#--
+int index, status
+
+int loc_unhash ()
+
+begin
+ # The keyword is found if its slot is not null
+
+ index = loc_unhash (hash, keyword)
+
+ if (UNH_KEY(hash,index) == NULL) {
+ value = NULL
+ status = NO
+ } else {
+ value = UNH_VALUE(hash,index)
+ status = YES
+ }
+
+ return (status)
+end
+
+# LOC_UNHASH -- Return index of location where a key should be inserted
+
+int procedure loc_unhash (hash, keyword)
+
+pointer hash # i: Descriptor of hash table
+char keyword[ARB] # i: Keyword to add to hash table
+#--
+int index, step
+
+bool streq()
+
+begin
+ # Calculate initial guess at position in hash table
+ # and step size in case guessed position is already filled
+
+ call calc_unhash (hash, keyword, index, step)
+ index = mod (index, UNH_SIZE(hash))
+
+ # Loop until an empty slot is found or the keyword is matched
+
+ repeat {
+ if (UNH_KEY(hash,index) == NULL) {
+ break
+
+ } else if (streq (Memc[UNH_KEY(hash,index)], keyword)) {
+ break
+ }
+
+ index = mod (index + step, UNH_SIZE(hash))
+ }
+
+ return (index)
+end
+
+# NEW_UNHASH -- Create a new hash table
+
+pointer procedure new_unhash (nkey, keysize)
+
+int nkey # i: number of keywords in the hash
+int keysize # i: maximum length of a key
+#--
+int size
+pointer hash
+
+begin
+ # Find a power of two greater than the number of keywords
+
+ for (size = 1; size < 2 * nkey; size = 2 * size)
+ ;
+
+ # Allocate structure for hash and set initial values
+
+ call malloc (hash, LEN_UNHSTRUCT, TY_INT)
+ call calloc (UNH_KEYBUF(hash), size, TY_INT)
+ call calloc (UNH_VALBUF(hash), size, TY_INT)
+ call malloc (UNH_STRBUF(hash), size*(keysize+1), TY_CHAR)
+
+ UNH_SIZE(hash) = size
+ UNH_NEXT(hash) = UNH_STRBUF(hash)
+
+ return (hash)
+end
+
diff --git a/pkg/utilities/nttools/tunits/units.tab b/pkg/utilities/nttools/tunits/units.tab
new file mode 100644
index 00000000..4d2c1f9c
--- /dev/null
+++ b/pkg/utilities/nttools/tunits/units.tab
@@ -0,0 +1,60 @@
+# Conversion factors for tunits task
+#
+# Read this table as "There are <factor> <from> in a <to>."
+# For example, "There are 100 centimeters in a meter."
+# The last column, swap, does not change the sense of the sentence
+# but does change the direction that the conversion is applied,
+# For example, "60 seconds in a minute" is actually a conversion
+# from minutes to seconds because swap is yes. Unit conversions
+# should set swap to yes when the desired conversion is not an exact
+# value, but its inverse is. Only one conversion is allowed per
+# unit, which simplifies the program logic considerably. Conversions
+# should be chosen so that they ultimately resolve to MKS units. To
+# prevent endless loops conversions from the fundamental units are
+# checked for and forbidden. However, the program does not check for
+# other loops, so be careful when adding new conversions!
+#
+# factor from to swap?
+#----------------------------------------------------
+100 centimeter meter no
+1e-3 kilometer meter no
+1e3 millimeter meter no
+1e6 micron meter no
+1e9 nanometer meter no
+1e10 angstrom meter no
+1e3 gram kilogram no
+1e6 milligram kilogram no
+60 second minute yes
+60 minute hour yes
+24 hour day yes
+365.2421897 day year yes
+57.2957795131 degree radian no
+60 arcminute degree no
+60 arcsecond arcminute no
+1.4959787066e11 meter au yes
+206264.806247 au parsec yes
+1e3 parsec kiloparsec yes
+1e6 parsec megaparsec yes
+9.46073047e15 meter lightyear yes
+1e3 liter m^3 no
+1 newton kg*m/s^2 no
+1 joule kg*m^2/s^2 no
+1 watt kg*m^2/s^3 no
+1 dyne gm*cm/s^2 no
+1 erg gm*cm^2/s^2 no
+2.54 centimeter inch yes
+12 inch foot yes
+5280 foot mile yes
+16 ounce pound no
+0.45359237 pound kilogram no
+1054.4 btu joule no
+4.184 calorie joule no
+1e-3 kilocalorie calorie no
+6.24150648e18 ev joule no
+1e-3 kev ev no
+1e-6 mev ev no
+1e23 jansky erg/s*cm^2*hz no
+1e3 millijansky jansky no
+1e-3 kilohertz hertz no
+1e-6 megahertz hertz no
+1e-9 gigahertz hertz no
diff --git a/pkg/utilities/nttools/tunits/units.x b/pkg/utilities/nttools/tunits/units.x
new file mode 100644
index 00000000..6f4374df
--- /dev/null
+++ b/pkg/utilities/nttools/tunits/units.x
@@ -0,0 +1,162 @@
+include <tbset.h>
+include "tunits.h"
+
+#* HISTORY *
+#* B.Simon 07-Jan-99 Original
+
+# FIND_UNITS -- Find the conversion factor for a set of units
+
+int procedure find_units (ut, units, punit)
+
+pointer ut # i: units hash table descriptor
+char units[ARB] # i: units string
+pointer punit # o: conversion factor as units structure
+#--
+int get_unhash()
+
+begin
+ return (get_unhash (ut, units, punit))
+end
+
+# FREE_UNITS -- Free the abbreviation hash table
+
+procedure free_units (ut)
+
+pointer ut # i: units hash table descriptor
+#--
+int index
+pointer sp, units, punit
+
+int each_unhash()
+
+begin
+ call smark (sp)
+ call salloc (units, LEN_UNIT, TY_CHAR)
+
+ index = 0
+ while (each_unhash (ut, index, Memc[units],
+ punit, LEN_UNIT) != EOF) {
+ if (punit != NULL)
+ call free_unstr (punit)
+ }
+
+ call free_unhash (ut)
+ call sfree (sp)
+end
+
+# READ_UNITS -- Read units conversions from a table and load into a hash
+
+pointer procedure read_units (ab, unittab)
+
+pointer ab # i: abbreviation table descriptor
+char unittab[ARB] # i: units conversion table name
+#--
+bool swap, verbose
+double factor
+int irow, nrow
+pointer sp, temp, oldunits, newunits
+pointer tp, c1, c2, c3, c4
+pointer ut, punit1, punit2, punit3
+
+data verbose / false /
+
+string nocolumn "The units conversion table must have four columns"
+string badfactor "Error in units table: factor must be greater than zero"
+string nofinal "Error in units table: conversion from final units not allowed"
+
+int tbpsta(), word_match()
+pointer tbtopn(), tbcnum(), new_unhash()
+pointer parse_units(), div_unstr()
+
+begin
+ # Dynamic memory for strings
+
+ call smark (sp)
+ call salloc (temp, SZ_FNAME, TY_CHAR)
+ call salloc (oldunits, SZ_FNAME, TY_CHAR)
+ call salloc (newunits, SZ_FNAME, TY_CHAR)
+
+ # Refer to columns numerically because
+ # this is supposed to be a text file
+
+ tp = tbtopn (unittab, READ_ONLY, NULL)
+ c1 = tbcnum (tp, 1)
+ c2 = tbcnum (tp, 2)
+ c3 = tbcnum (tp, 3)
+ c4 = tbcnum (tp, 4)
+
+ if (c1 == NULL || c2 == NULL || c3 == NULL || c4 == NULL)
+ call tuniterr (nocolumn, unittab)
+
+ # Create hash
+
+ nrow = tbpsta (tp, TBL_NROWS)
+ ut = new_unhash (nrow, LEN_UNIT)
+
+ # Read each row into hash
+
+ do irow = 1, nrow {
+ # Read table columns
+
+ call tbegtd (tp, c1, irow, factor)
+ call tbegtt (tp, c2, irow, Memc[oldunits], SZ_FNAME)
+ call tbegtt (tp, c3, irow, Memc[newunits], SZ_FNAME)
+ call tbegtb (tp, c4, irow, swap)
+
+ # Check conversion factor
+
+ if (factor <= 0.0)
+ call tuniterr (badfactor, Memc[oldunits])
+
+ # Swap the units string and the conversion factor
+
+ if (swap) {
+ call strcpy (Memc[oldunits], Memc[temp], SZ_FNAME)
+ call strcpy (Memc[newunits], Memc[oldunits], SZ_FNAME)
+ call strcpy (Memc[temp], Memc[newunits], SZ_FNAME)
+ }
+
+ # Check to see that old units aren't one of the final forms
+
+ if (word_match (Memc[oldunits], FINALS) != 0)
+ call tuniterr (nofinal, Memc[oldunits])
+
+ # Parse the old and new units strings
+
+ call strlwr (Memc[newunits])
+ punit1 = parse_units (ab, Memc[newunits])
+
+ call strlwr (Memc[oldunits])
+ punit2 = parse_units (ab, Memc[oldunits])
+
+ # The conversion factor is ratio of the two sets of units
+
+ punit3 = div_unstr (punit1, punit2)
+ if (swap) {
+ TUN_FACTOR(punit3) = factor
+ } else {
+ TUN_FACTOR(punit3) = 1.0 / factor
+ }
+
+ if (verbose) {
+ call str_unstr (punit3, Memc[temp], SZ_FNAME)
+
+ call eprintf ("The conversion factor is %s\n\n")
+ call pargstr (Memc[temp])
+ }
+
+ # Add it to the hash
+
+ call abrev_unstr (ab, Memc[oldunits], Memc[temp], SZ_FNAME)
+ call add_unhash (ut, Memc[temp], punit3)
+
+ call free_unstr (punit1)
+ call free_unstr (punit2)
+ }
+
+ # Close table and free memory
+
+ call tbtclo (tp)
+ call sfree (sp)
+ return (ut)
+end
diff --git a/pkg/utilities/nttools/tunits/unstr.x b/pkg/utilities/nttools/tunits/unstr.x
new file mode 100644
index 00000000..80bd65ba
--- /dev/null
+++ b/pkg/utilities/nttools/tunits/unstr.x
@@ -0,0 +1,381 @@
+include "tunits.h"
+
+#* HISTORY *
+#* B.Simon 07-Jan-99 Original
+
+# ABREV_UNSTR -- Replace units string with its abbreviation
+
+procedure abrev_unstr (ab, instr, outstr, maxch)
+
+pointer ab # i: abbreviation hash descriptor
+char instr[ARB] # i: string to be abbreviated
+char outstr[ARB] # o: abbreviated string
+int maxch # i: max length of abbreviated string
+#--
+int nc
+pointer sp, temp
+
+int gstrcpy(), find_abrev ()
+
+begin
+ if (find_abrev (ab, instr, outstr, maxch) == YES)
+ return
+
+ call smark (sp)
+ call salloc (temp, LEN_UNIT, TY_CHAR)
+
+ nc = gstrcpy (instr, Memc[temp], LEN_UNIT)
+ if (nc == 1 || instr[nc] != 's') {
+ call strcpy (instr, outstr, maxch)
+
+ } else {
+ Memc[temp+nc-1] = EOS
+ if (find_abrev (ab, Memc[temp], outstr, maxch) == NO)
+ call strcpy (Memc[temp], outstr, maxch)
+ }
+
+ call sfree (sp)
+end
+
+# COPY_UNSTR -- Copy a units descriptor
+
+pointer procedure copy_unstr (punit1)
+
+pointer punit1 # i: units descriptor to be copied
+#--
+int idx
+pointer punit2
+
+begin
+ # Allocate structure to hold units
+
+ call calloc (punit2, LEN_TUNSTRUCT, TY_INT)
+
+ # Copy numeric factor
+
+ TUN_FACTOR(punit2) = TUN_FACTOR(punit1)
+
+ # Copy units and their powers
+
+ do idx = 1, MAXUNIT {
+ if (TUN_UNPTR(punit1,idx) == NULL)
+ break
+
+ call malloc (TUN_UNPTR(punit2,idx), LEN_UNIT, TY_CHAR)
+ call strcpy (TUN_UNITS(punit1,idx), TUN_UNITS(punit2,idx),
+ LEN_UNIT)
+
+ TUN_POWER(punit2,idx) = TUN_POWER(punit1,idx)
+ }
+
+ return (punit2)
+end
+# DIV_UNSTR -- Divide one set of units by another
+
+pointer procedure div_unstr (punit1, punit2)
+
+pointer punit1 # i: descriptor for first set of units
+pointer punit2 # i: descriptor for second set of units
+#--
+int idx, jdx, kdx, power
+pointer punit3
+
+int find_unstr()
+
+begin
+ # Allocate structure to hold units
+
+ call calloc (punit3, LEN_TUNSTRUCT, TY_INT)
+
+ # Compute the new factor
+
+ TUN_FACTOR(punit3) = TUN_FACTOR(punit1) / TUN_FACTOR(punit2)
+
+ # Find units in both descriptors and subtract their powers
+
+ jdx = 1
+ do idx = 1, MAXUNIT {
+ if (TUN_UNPTR(punit1,idx) == NULL)
+ break
+
+ kdx = find_unstr (punit2, TUN_UNITS(punit1, idx))
+ if (kdx == 0)
+ next
+
+ power = TUN_POWER(punit1,idx) - TUN_POWER(punit2,kdx)
+ if (power == 0)
+ next
+
+ call malloc (TUN_UNPTR(punit3,jdx), LEN_UNIT, TY_CHAR)
+ call strcpy (TUN_UNITS(punit1,idx), TUN_UNITS(punit3,jdx),
+ LEN_UNIT)
+
+ TUN_POWER(punit3,jdx) = power
+ jdx = jdx + 1
+
+ }
+
+ # Find units only in a single descriptor and add them to the
+ # new descriptor
+
+ do idx = 1, MAXUNIT {
+ if (TUN_UNPTR(punit1,idx) == NULL)
+ break
+
+ if (find_unstr (punit2, TUN_UNITS(punit1, idx)) == 0) {
+ call malloc (TUN_UNPTR(punit3,jdx), LEN_UNIT, TY_CHAR)
+ call strcpy (TUN_UNITS(punit1,idx), TUN_UNITS(punit3,jdx),
+ LEN_UNIT)
+
+ TUN_POWER(punit3,jdx) = TUN_POWER(punit1,idx)
+ jdx = jdx + 1
+ }
+ }
+
+ do idx = 1, MAXUNIT {
+ if (TUN_UNPTR(punit2,idx) == NULL)
+ break
+
+ if (find_unstr (punit1, TUN_UNITS(punit2, idx)) == 0) {
+ call malloc (TUN_UNPTR(punit3,jdx), LEN_UNIT, TY_CHAR)
+ call strcpy (TUN_UNITS(punit2,idx), TUN_UNITS(punit3,jdx),
+ LEN_UNIT)
+
+ TUN_POWER(punit3,jdx) = - TUN_POWER(punit2,idx)
+ jdx = jdx + 1
+ }
+ }
+
+ return (punit3)
+end
+
+# FIND_UNSTR -- Find location of units string in descriptor
+
+int procedure find_unstr (punit, units)
+
+pointer punit # i: units descriptor
+char units[ARB] # i: units string to search for
+#--
+int idx
+bool streq()
+
+begin
+ do idx = 1, MAXUNIT {
+ if (TUN_UNPTR(punit,idx) == NULL)
+ break
+
+ if (streq (TUN_UNITS(punit,idx), units))
+ return (idx)
+ }
+
+ return (0)
+end
+
+# FREE_UNSTR -- Release memory used by a units descriptor
+
+procedure free_unstr (punit)
+
+pointer punit # i: units descriptor
+#--
+int idx
+
+begin
+ do idx = 1, MAXUNIT {
+ if (TUN_UNPTR(punit,idx) == NULL)
+ break
+
+ call mfree (TUN_UNPTR(punit,idx), TY_CHAR)
+ }
+
+ call mfree (punit, TY_INT)
+end
+
+# MUL_UNSTR -- Multiply two sets of units together
+
+pointer procedure mul_unstr (punit1, punit2)
+
+pointer punit1 # i: descriptor for first set of units
+pointer punit2 # i: descriptor for second set of units
+#--
+int idx, jdx, kdx, power
+pointer punit3
+
+int find_unstr()
+
+begin
+ # Allocate structure to hold units
+
+ call calloc (punit3, LEN_TUNSTRUCT, TY_INT)
+
+ # Compute the new factor
+
+ TUN_FACTOR(punit3) = TUN_FACTOR(punit1) * TUN_FACTOR(punit2)
+
+ # Find units in both descriptors and add their powers
+
+ jdx = 1
+ do idx = 1, MAXUNIT {
+ if (TUN_UNPTR(punit1,idx) == NULL)
+ break
+
+ kdx = find_unstr (punit2, TUN_UNITS(punit1, idx))
+ if (kdx == 0)
+ next
+
+ power = TUN_POWER(punit1,idx) + TUN_POWER(punit2,kdx)
+ if (power == 0)
+ next
+
+ call malloc (TUN_UNPTR(punit3,jdx), LEN_UNIT, TY_CHAR)
+ call strcpy (TUN_UNITS(punit1,idx), TUN_UNITS(punit3,jdx),
+ LEN_UNIT)
+
+ TUN_POWER(punit3,jdx) = power
+ jdx = jdx + 1
+
+ }
+
+ # Find units only in a single descriptor and add them to the
+ # new descriptor
+
+ do idx = 1, MAXUNIT {
+ if (TUN_UNPTR(punit1,idx) == NULL)
+ break
+
+ if (find_unstr (punit2, TUN_UNITS(punit1, idx)) == 0) {
+ call malloc (TUN_UNPTR(punit3,jdx), LEN_UNIT, TY_CHAR)
+ call strcpy (TUN_UNITS(punit1,idx), TUN_UNITS(punit3,jdx),
+ LEN_UNIT)
+
+ TUN_POWER(punit3,jdx) = TUN_POWER(punit1,idx)
+ jdx = jdx + 1
+ }
+ }
+
+ do idx = 1, MAXUNIT {
+ if (TUN_UNPTR(punit2,idx) == NULL)
+ break
+
+ if (find_unstr (punit1, TUN_UNITS(punit2, idx)) == 0) {
+ call malloc (TUN_UNPTR(punit3,jdx), LEN_UNIT, TY_CHAR)
+ call strcpy (TUN_UNITS(punit2,idx), TUN_UNITS(punit3,jdx),
+ LEN_UNIT)
+
+ TUN_POWER(punit3,jdx) = TUN_POWER(punit2,idx)
+ jdx = jdx + 1
+ }
+ }
+
+ return (punit3)
+end
+
+# NUM_UNSTR -- Convert a token to an integer
+
+int procedure num_unstr (value)
+
+char value[ARB] # i: string containing token value
+#--
+int ic, nc, num
+
+int ctoi()
+
+begin
+ ic = 1
+ nc = ctoi (value, ic, num)
+ return (num)
+end
+
+# POW_UNSTR -- Raise a set of units to an integer power
+
+pointer procedure pow_unstr (punit1, power)
+
+pointer punit1 # i: units descriptor to be raised to power
+int power
+#--
+int idx
+pointer punit2
+
+begin
+ # Allocate structure to hold units
+
+ call calloc (punit2, LEN_TUNSTRUCT, TY_INT)
+
+ # Compute the new factor
+
+ TUN_FACTOR(punit2) = TUN_FACTOR(punit1) ** power
+
+ # Find units in both descriptors and add their powers
+
+ if (power != 0) {
+ for (idx = 1; idx <= MAXUNIT; idx = idx + 1) {
+ if (TUN_UNPTR(punit1,idx) == NULL)
+ break
+
+ call malloc (TUN_UNPTR(punit2,idx), LEN_UNIT, TY_CHAR)
+ call strcpy (TUN_UNITS(punit1,idx), TUN_UNITS(punit2,idx),
+ LEN_UNIT)
+
+ TUN_POWER(punit2,idx) = TUN_POWER(punit1,idx) * power
+ }
+ }
+
+ return (punit2)
+end
+
+# SET_UNSTR -- Make a new units description from a units string and its power
+
+pointer procedure set_unstr (ab, units, power)
+
+pointer ab # i: hash of units abbreviations
+char units[ARB] # i: units string
+int power # i: power of the units
+#--
+pointer punit
+
+begin
+ # Allocate structure to hold units
+
+ call calloc (punit, LEN_TUNSTRUCT, TY_INT)
+ call malloc (TUN_UNPTR(punit,1), LEN_UNIT, TY_CHAR)
+
+ # Set the first slot in the structure to hold the string
+ # and power passed to this procedure
+
+ TUN_FACTOR(punit) = 1.0
+ TUN_POWER(punit,1) = power
+ call abrev_unstr (ab, units, TUN_UNITS(punit,1), LEN_UNIT)
+
+ return (punit)
+end
+
+# STR_UNSTR -- Convert units structure into a string
+
+procedure str_unstr (punit, str, maxch)
+
+pointer punit # i: units descriptor
+char str[ARB] # o: string representation of units
+int maxch # i: max length of string
+#--
+int ic, idx
+
+int strlen(), gstrcpy(), itoc()
+
+begin
+ call sprintf (str, maxch, "%g")
+ call pargd (TUN_FACTOR(punit))
+
+ ic = strlen (str) + 1
+
+ do idx = 1, MAXUNIT {
+ if (TUN_UNPTR(punit,idx) == NULL)
+ break
+
+ ic = ic + gstrcpy ("*", str[ic], maxch-ic+1)
+ ic = ic + gstrcpy (TUN_UNITS(punit,idx), str[ic], maxch+ic-1)
+
+ if (TUN_POWER(punit,idx) != 1) {
+ ic = ic + gstrcpy ("^", str[ic], maxch-ic+1)
+ ic = ic + itoc (TUN_POWER(punit,idx), str[ic], maxch-ic+1)
+ }
+ }
+end
diff --git a/pkg/utilities/nttools/tupar.par b/pkg/utilities/nttools/tupar.par
new file mode 100644
index 00000000..ae3f77de
--- /dev/null
+++ b/pkg/utilities/nttools/tupar.par
@@ -0,0 +1,9 @@
+table,s,a,"",,,"list of tables"
+same,b,h,no,,,"apply same instructions to all tables?"
+verbose,b,h,yes,,,"print name of each table?"
+readonly,b,h,no,,,"open tables readonly?"
+inplace,b,h,no,,,"edit tables inplace?"
+quit_default,b,h,no,,,"default action for quit vs exit"
+delete_default,b,h,yes,,,"default action for delete or replace"
+go_ahead,b,q,no,,," ?"
+mode,s,h,"al",,,
diff --git a/pkg/utilities/nttools/tupar/mkpkg b/pkg/utilities/nttools/tupar/mkpkg
new file mode 100644
index 00000000..10371af4
--- /dev/null
+++ b/pkg/utilities/nttools/tupar/mkpkg
@@ -0,0 +1,12 @@
+# Update the tupar application code in the ttools package library
+# Author: HODGE, 2-FEB-1988
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ tupar.x <fset.h> <error.h> <tbset.h> "tupar.h"
+ tuinstr.x <ctype.h> <tbset.h> "tupar.h"
+ ;
diff --git a/pkg/utilities/nttools/tupar/tuinstr.x b/pkg/utilities/nttools/tupar/tuinstr.x
new file mode 100644
index 00000000..32adf46d
--- /dev/null
+++ b/pkg/utilities/nttools/tupar/tuinstr.x
@@ -0,0 +1,971 @@
+include <ctype.h> # defines IS_WHITE
+include <tbset.h>
+include "tupar.h" # defines TUPAR_EXIT & TUPAR_QUIT
+
+# tu_instr -- execute edit instruction
+# Execute one instruction regarding header parameters for a table:
+# get, put, delete, replace, type, or list.
+# The flag DONE will be set to true if the instruction is 'q' or
+# if the user's response to a prompt is EOF. Prompting is turned
+# off if the input is redirected.
+#
+# Phil Hodge, 28-Mar-1988 Subroutine created
+# Phil Hodge, 9-Sep-1988 Prompt changed for delete & replace
+# Phil Hodge, 9-Mar-1989 Change data type of header parm from char to int.
+# Phil Hodge, 23-Aug-1991 Include eq_flag, allowing quit without saving changes
+# Phil Hodge, 9-Jul-1993 Set modified=true if header was changed.
+# Phil Hodge, 7-Mar-1995 In tu_putpar, also put a comment, if present.
+# Phil Hodge, 17-May-1995 In tu_putpar, allow ' as well as " as delimiter.
+# Phil Hodge, 22-May-1996 Add "k" instruction.
+# Phil Hodge, 5-Jun-1997 In tu_getpar and tu_listpar, also print comments
+# Phil Hodge, 2-Jul-1998 In tu_putpar, check for "true" or "t" for a boolean
+# parameter; get data type from existing parameter;
+# in tu_listpar, print boolean as "yes" or "no".
+# Ellyne Kinney, 2-Feb-1999 Testing Automatic updates of IRAFRA under CVS
+# 13th try.
+
+procedure tu_instr (tp, linebuf, readonly, prompt, from_stdin,
+ iredir, save_instr, isbuf, bufsize, ibp,
+ modified, eq_flag, done, istat)
+
+pointer tp # i: pointer to table descriptor
+char linebuf[ARB] # o: scratch for input line
+bool readonly # i: was table opened readonly?
+bool prompt # i: prompt for input?
+bool from_stdin # i: get input from STDIN (or from buffer)
+bool iredir # i: input redirected?
+bool save_instr # i: save instruction?
+pointer isbuf # io: pointer to instruction buffer
+int bufsize # io: current size of instruction buffer
+int ibp # io: current index in instruction buffer
+bool modified # io: set to true if the header was modified
+int eq_flag # o: exit or quit
+bool done # o: set to true if done with current table
+int istat # o: > 0 if put or delete but table is readonly
+#--
+char instr[11] # instruction from user: q, g, p, etc.
+int ip # index in linebuf
+int clen # length of command (to check for "!")
+bool verify # verify before delete or replace?
+bool incl_num # include par numbers when listing keywords?
+int ctowrd(), tu_gline(), tu_rd_instr()
+int strlen()
+errchk tu_getpar, tu_putpar, tu_delpar, tu_replpar, tu_ch_name
+
+begin
+ # default value in case user finishes by giving an EOF
+ eq_flag = TUPAR_EXIT
+
+ istat = 0
+ done = false
+
+ if (from_stdin) {
+ # Read an instruction from STDIN into linebuf.
+ if (prompt) {
+ call eprintf (":")
+ call flush (STDOUT)
+ call flush (STDERR)
+ }
+ if (tu_gline (STDIN, linebuf) == EOF)
+ done = true
+ } else {
+ # Read an instruction from buffer into linebuf.
+ if (tu_rd_instr (Memc[isbuf], ibp, linebuf) == EOF)
+ done = true
+ }
+ if ( done )
+ return
+
+ ip = 1
+ if (ctowrd (linebuf, ip, instr, 11) <= 0) # a blank line
+ return
+ if (instr[1] == '#') # a comment line
+ return
+
+ if (instr[1] == 'e') {
+ eq_flag = TUPAR_EXIT
+ done = true
+
+ } else if (instr[1] == 'q') {
+ clen = strlen (instr)
+ if (instr[clen] == '!')
+ eq_flag = TUPAR_QUIT_NC
+ else
+ eq_flag = TUPAR_QUIT
+ done = true
+
+ } else if (instr[1] == 'g') {
+
+ call tu_getpar (tp, linebuf, ip, instr,
+ save_instr, isbuf, bufsize, ibp)
+
+ } else if (instr[1] == 'p') {
+
+ if (readonly) {
+ istat = 1
+ return
+ }
+ call tu_putpar (tp, linebuf, ip, instr,
+ save_instr, isbuf, bufsize, ibp)
+ modified = true
+
+ } else if (instr[1] == 'd') {
+
+ # Delete a header parameter specified by name or by number.
+
+ if (readonly) {
+ istat = 1
+ return
+ }
+ verify = ( ! iredir ) && (instr[2] != '!')
+ call tu_delpar (tp, linebuf, ip, verify,
+ save_instr, isbuf, bufsize, ibp, modified)
+
+ } else if (instr[1] == 'r') {
+
+ # Replace a header parameter specified by name or by number.
+
+ if (readonly) {
+ istat = 1
+ return
+ }
+ verify = ( ! iredir ) && (instr[2] != '!')
+ call tu_replpar (tp, linebuf, ip, prompt, from_stdin,
+ verify, save_instr, isbuf, bufsize, ibp,
+ modified, done)
+
+ } else if (instr[1] == 'k') {
+
+ # Change keyword name.
+
+ if (readonly) {
+ istat = 1
+ return
+ }
+ call tu_ch_name (tp, linebuf, ip,
+ save_instr, isbuf, bufsize, ibp,
+ modified)
+
+ } else if (instr[1] == 't' || instr[1] == 'l') {
+
+ # Type or list parameters; list means include keyword number.
+
+ incl_num = instr[1] == 'l' # list rather than type
+ call tu_listpar (tp, linebuf, ip, incl_num,
+ save_instr, isbuf, bufsize, ibp)
+
+ } else {
+ call eprintf ("The options are:\n")
+ call eprintf (
+ " e, q, g, p, d, r, t, l\n")
+ call eprintf (
+ " (exit, quit, get, put, delete, replace, type, list)\n")
+ call eprintf (
+ " e exit the task, saving changes\n")
+ call eprintf (
+ " q quit the task WITHOUT saving any changes\n")
+ call eprintf (
+ " g keyword get parameter with keyword `keyword'\n")
+ call eprintf (
+ " p keyword value put parameter `keyword'\n")
+ call eprintf (
+ " d keyword delete parameter `keyword'\n")
+ call eprintf (
+ " r keyword replace parameter `keyword'\n")
+ call eprintf (
+ " k oldkey newkey change keyword name\n")
+ call eprintf (
+ " t type the parameters\n")
+ call eprintf (
+ " l list parameters and show par numbers\n")
+ call eprintf (
+ " see help for further info about these instructions\n")
+ }
+end
+
+
+# tu_getpar -- get a parameter
+# The value of a parameter specified by name (not by number) will be gotten
+# and displayed. If the keyword is not found in the header, nothing will
+# be displayed (i.e. no error message). If the keyword is HISTORY, COMMENT,
+# or a blank, then all keywords of that type will be displayed.
+
+procedure tu_getpar (tp, linebuf, ip, instr,
+ save_instr, isbuf, bufsize, ibp)
+
+pointer tp # i: pointer to table descriptor
+char linebuf[ARB] # i: input line
+int ip # io: index in linebuf
+char instr[ARB] # i: the instruction (needed for data type)
+bool save_instr # i: save instruction?
+pointer isbuf # io: pointer to instruction buffer
+int bufsize # io: current size of instruction buffer
+int ibp # io: current index in instruction buffer
+#--
+char keyword[SZ_KEYWORD] # keyword for parameter
+char kwrd[SZ_KEYWORD] # keyword returned by tbhgnp
+char text[SZ_PARREC] # buffer for value of parameter
+char comment[SZ_PARREC] # buffer for comment, if any
+int dtype # data type (TY_CHAR, etc)
+double dblval
+real realval
+int intval
+bool boolval
+int npar # current number of parameters
+int k # loop index
+double tbhgtd()
+real tbhgtr()
+int tbhgti(), tbpsta()
+bool tbhgtb()
+int ctowrd()
+bool streq()
+
+begin
+ npar = tbpsta (tp, TBL_NPAR)
+
+ if (ctowrd (linebuf, ip, keyword, SZ_KEYWORD) <= 0) {
+ call eprintf ("syntax: g keyword\n")
+ return # get next instruction
+ }
+ call strupr (keyword)
+
+ # Get comment, if it exists.
+ iferr (call tbhgcm (tp, keyword, comment, SZ_PARREC))
+ comment[1] = EOS
+
+ if (instr[2] == 'r') {
+ ifnoerr (realval = tbhgtr (tp, keyword)) {
+ call printf ("%s = %g")
+ call pargstr (keyword)
+ call pargr (realval)
+ if (comment[1] == EOS) {
+ call printf ("\n")
+ } else {
+ call printf (" %s\n")
+ call pargstr (comment)
+ }
+ }
+ } else if (instr[2] == 'd') {
+ ifnoerr (dblval = tbhgtd (tp, keyword)) {
+ call printf ("%s = %g")
+ call pargstr (keyword)
+ call pargd (dblval)
+ if (comment[1] == EOS) {
+ call printf ("\n")
+ } else {
+ call printf (" %s\n")
+ call pargstr (comment)
+ }
+ }
+ } else if (instr[2] == 'i') {
+ ifnoerr (intval = tbhgti (tp, keyword)) {
+ call printf ("%s = %d")
+ call pargstr (keyword)
+ call pargi (intval)
+ if (comment[1] == EOS) {
+ call printf ("\n")
+ } else {
+ call printf (" %s\n")
+ call pargstr (comment)
+ }
+ }
+ } else if (instr[2] == 'b') {
+ ifnoerr (boolval = tbhgtb (tp, keyword)) {
+ call printf ("%s = %b")
+ call pargstr (keyword)
+ call pargb (boolval)
+ if (comment[1] == EOS) {
+ call printf ("\n")
+ } else {
+ call printf (" %s\n")
+ call pargstr (comment)
+ }
+ }
+ } else {
+ if (streq (keyword, "HISTORY") || streq (keyword, "COMMENT") ||
+ keyword[1] == EOS) {
+ # Print all history or comment or blank-keyword records.
+ do k = 1, npar {
+ call tbhgnp (tp, k, kwrd, dtype, text)
+ if (streq (keyword, kwrd)) {
+ call printf ("%s = %s\n")
+ call pargstr (keyword)
+ call pargstr (text)
+ }
+ }
+ } else {
+ ifnoerr (call tbhgtt (tp, keyword, text, SZ_PARREC)) {
+ if (comment[1] == EOS) {
+ call printf ("%s = %s\n")
+ call pargstr (keyword)
+ call pargstr (text)
+ } else {
+ call printf ("%s = '%s' %s\n")
+ call pargstr (keyword)
+ call pargstr (text)
+ call pargstr (comment)
+ }
+ }
+ }
+ }
+
+ if (save_instr)
+ call tu_save_instr (linebuf, isbuf, bufsize, ibp)
+end
+
+
+# tu_putpar -- add or replace a parameter
+# A parameter specified by name (not by number) is put into the table.
+# If the parameter already exists it will be replaced (and the data type
+# may be changed); otherwise, it will be added.
+
+procedure tu_putpar (tp, linebuf, ip, instr,
+ save_instr, isbuf, bufsize, ibp)
+
+pointer tp # i: pointer to table descriptor
+char linebuf[ARB] # i: input line
+int ip # io: index in linebuf
+char instr[ARB] # i: the instruction (needed for data type)
+bool save_instr # i: save instruction?
+pointer isbuf # io: pointer to instruction buffer
+int bufsize # io: current size of instruction buffer
+int ibp # io: current index in instruction buffer
+#--
+pointer sp
+pointer value # scratch for a string value
+char keyword[SZ_KEYWORD] # keyword for parameter
+int dtype # data type code for parameter
+bool found # parameter already in header? (ignored)
+double dblval
+real realval
+int intval
+bool boolval
+int npar # current number of parameters
+int tbpsta()
+int nchar, ctowrd(), ctod(), ctoi(), nscan(), strlen()
+bool streq()
+
+begin
+ npar = tbpsta (tp, TBL_NPAR)
+
+ if (ctowrd (linebuf, ip, keyword, SZ_KEYWORD) <= 0) {
+ call eprintf ("syntax: p keyword value\n")
+ return
+ }
+
+ call smark (sp)
+ call salloc (value, SZ_FNAME, TY_CHAR)
+
+ # Set the data type. If the user specified a type, use that.
+ # If none was specified, find out whether the parameter is
+ # already in the header, and if so, use the existing type.
+ if (instr[2] == 'r')
+ dtype = TY_REAL
+ else if (instr[2] == 'd')
+ dtype = TY_DOUBLE
+ else if (instr[2] == 'i')
+ dtype = TY_INT
+ else if (instr[2] == 'b')
+ dtype = TY_BOOL
+ else if (instr[2] == 't')
+ dtype = TY_CHAR
+ else
+ call tu_partype (tp, keyword, dtype, found)
+
+ # In each section, we use ctowrd or ctod (or something), not only
+ # to extract the value but also to skip past it so we can check for
+ # a comment.
+ if (dtype == TY_REAL) {
+ if (ctod (linebuf, ip, dblval) > 0)
+ realval = dblval
+ else
+ realval = INDEFR
+ call tbhadr (tp, keyword, realval)
+ } else if (dtype == TY_DOUBLE) {
+ if (ctod (linebuf, ip, dblval) < 1)
+ dblval = INDEFD
+ call tbhadd (tp, keyword, dblval)
+ } else if (dtype == TY_INT) {
+ if (ctoi (linebuf, ip, intval) < 1)
+ intval = INDEFI
+ call tbhadi (tp, keyword, intval)
+ } else if (dtype == TY_BOOL) {
+ nchar = ctowrd (linebuf, ip, Memc[value], SZ_FNAME)
+ call strlwr (Memc[value])
+ call sscan (Memc[value])
+ call gargb (boolval)
+ if (nscan() < 1) {
+ if (streq (Memc[value], "true") || streq (Memc[value], "t") ||
+ streq (Memc[value], "1"))
+ boolval = true
+ else
+ boolval = false
+ }
+ call tbhadb (tp, keyword, boolval)
+
+ } else {
+
+ while (IS_WHITE(linebuf[ip]))
+ ip = ip + 1
+
+ if (linebuf[ip] == '"' || linebuf[ip] == '\'') {
+ nchar = ctowrd (linebuf, ip, Memc[value], SZ_FNAME)
+ call tbhadt (tp, keyword, Memc[value])
+ } else {
+ call tbhadt (tp, keyword, linebuf[ip])
+ # Set ip to point to end of line because there's no comment.
+ ip = strlen (linebuf) + 1
+ }
+ }
+
+ # Check for a comment.
+ while (IS_WHITE(linebuf[ip]))
+ ip = ip + 1
+ if (linebuf[ip] != EOS)
+ call tbhpcm (tp, keyword, linebuf[ip])
+
+ if (save_instr)
+ call tu_save_instr (linebuf, isbuf, bufsize, ibp)
+
+ call sfree (sp)
+end
+
+
+# tu_delpar -- delete a parameter
+# A parameter is to be deleted. The user will be prompted for confirmation
+# if the input is not redirected and the instruction was not 'q!'.
+
+procedure tu_delpar (tp, linebuf, ip, verify,
+ save_instr, isbuf, bufsize, ibp, modified)
+
+pointer tp # i: pointer to table descriptor
+char linebuf[ARB] # i: input line
+int ip # i: index in linebuf
+bool verify # i: ask for verification before deleting?
+bool save_instr # i: save instruction?
+pointer isbuf # io: pointer to instruction buffer
+int bufsize # io: current size of instruction buffer
+int ibp # io: current index in instruction buffer
+bool modified # io: set to true if parameter was deleted
+#--
+char keyword[SZ_KEYWORD] # keyword for parameter
+char text[SZ_PARREC] # buffer for value of parameter
+char char_type # data type as a letter
+int dtype # data type
+int par1, par2 # range of par numbers to delete
+int i # loop index
+int parnum # keyword number
+int ctowrd()
+bool clgetb()
+
+begin
+ i = ip
+
+ if (ctowrd (linebuf, i, keyword, SZ_KEYWORD) <= 0) {
+ call eprintf ("syntax: d keyword (or d parnum)\n")
+ return
+ }
+
+ # Get the parameter numbers; = 0,-1 if not found.
+ call tu_parnum (tp, linebuf[ip], par1, par2)
+
+ # Delete in increasing numerical order. That means that if we
+ # delete every one, it will be the same par number each time.
+ # Whenever we don't delete one, we increment parnum.
+ parnum = par1
+ do i = par1, par2 {
+ # Get parameter by number.
+ call tbhgnp (tp, parnum, keyword, dtype, text)
+ if (dtype == 0)
+ call error (1, "tu_delpar: keyword miscount")
+
+ if ( verify ) {
+ # Change data type to a char.
+ switch (dtype) {
+ case TY_REAL:
+ char_type = 'r'
+ case TY_INT:
+ char_type = 'i'
+ case TY_DOUBLE:
+ char_type = 'd'
+ case TY_BOOL:
+ char_type = 'b'
+ default:
+ char_type = 't'
+ }
+ # Ask for confirmation before deleting.
+ call clputb ("go_ahead", clgetb ("delete_default"))
+ call eprintf (
+ "The following parameter is to be deleted:\n")
+ call eprintf ("%-8s %c %s\n")
+ call pargstr (keyword)
+ call pargc (char_type)
+ call pargstr (text)
+ call eprintf (" ... OK to delete")
+ call flush (STDERR)
+ if (clgetb ("go_ahead")) {
+ call tbhdel (tp, parnum) # delete it
+ modified = true
+ } else {
+ parnum = parnum + 1 # point to next parameter
+ }
+ } else {
+ # Delete without asking for confirmation.
+ call tbhdel (tp, parnum)
+ modified = true
+ }
+ }
+
+ # Note that we may save this instruction even if the parameter
+ # was not found in the current table.
+ if (save_instr)
+ call tu_save_instr (linebuf, isbuf, bufsize, ibp)
+end
+
+
+# tu_replpar -- replace a parameter
+# Replace an existing parameter, specified either by name or by number.
+# The instruction and the replacement string will be saved in the instruction
+# buffer if appropriate. Neither will be saved, however, if the keyword is
+# not found in the first table. (This is in contrast to the behavior of the
+# delete instruction.) The user will be prompted for confirmation if the
+# input is not redirected and the instruction was not 'r!'.
+
+procedure tu_replpar (tp, linebuf, ip, prompt, from_stdin,
+ verify, save_instr, isbuf, bufsize, ibp,
+ modified, done)
+
+pointer tp # i: pointer to table descriptor
+char linebuf[ARB] # i: input line
+int ip # i: index in linebuf
+bool prompt # i: prompt for input?
+bool from_stdin # i: get instructions from STDIN?
+bool verify # i: ask for verification before deleting?
+bool save_instr # i: save instruction?
+pointer isbuf # io: pointer to instruction buffer
+int bufsize # io: current size of instruction buffer
+int ibp # io: current index in instruction buffer
+bool modified # io: set to true if parameter was replaced
+bool done # io: set to false if done with current table
+#--
+char keyword[SZ_KEYWORD] # keyword for parameter
+char text[SZ_PARREC] # buffer for value of parameter
+char rtext[SZ_PARREC] # replacement value for a parameter
+char char_type # data type as a letter
+int dtype # data type (TY_CHAR, etc)
+int par1, par2 # range of keywords to replace
+int i # loop index for keyword number
+int ctowrd(), tu_gline(), tu_rd_instr()
+bool clgetb()
+
+begin
+ i = ip
+
+ if (ctowrd (linebuf, i, keyword, SZ_KEYWORD) <= 0) {
+ call eprintf ("syntax: r keyword (or r parnum)\n")
+ return
+ }
+
+ # Save the instruction; the replacement value(s) will be
+ # saved within the loop over keyword number.
+ if (save_instr)
+ call tu_save_instr (linebuf, isbuf, bufsize, ibp)
+
+ # Get the parameter numbers, 0,-1 if not found.
+ call tu_parnum (tp, linebuf[ip], par1, par2)
+
+ do i = par1, par2 {
+ # Get parameter by number.
+ call tbhgnp (tp, i, keyword, dtype, text)
+ if (dtype == 0)
+ call error (1, "tu_replpar: keyword miscount")
+
+ # Change data type to a char.
+ switch (dtype) {
+ case TY_REAL:
+ char_type = 'r'
+ case TY_INT:
+ char_type = 'i'
+ case TY_DOUBLE:
+ char_type = 'd'
+ case TY_BOOL:
+ char_type = 'b'
+ default:
+ char_type = 't'
+ }
+
+ if (prompt) {
+ # Display current value.
+ call eprintf (
+ "keyword %s, type %c; give replacement value:\n")
+ call pargstr (keyword)
+ call pargc (char_type)
+ call eprintf ("%s\n")
+ call pargstr (text)
+ }
+ # Read replacement text, either from STDIN or from instr buffer.
+ if (from_stdin) {
+ if (tu_gline (STDIN, rtext) == EOF) {
+ done = true
+ return
+ }
+ } else {
+ if (tu_rd_instr (Memc[isbuf], ibp, rtext) == EOF) {
+ done = true
+ return
+ }
+ }
+
+ # Tab is saved in the instruction buffer to mean that the
+ # value should not be changed. This allows replacing a value
+ # with blanks.
+ if (rtext[1] == EOS) {
+ call eprintf ("no action taken\n")
+ call strcpy ("\t", rtext, SZ_PARREC)
+
+ } else if (rtext[1] == '\t') {
+ ;
+
+ } else if (verify) {
+ # Prompt for confirmation.
+ call clputb ("go_ahead", clgetb ("delete_default"))
+ call eprintf ("Current parameter and its replacement are:\n")
+ call eprintf ("%-8s %c %s\n")
+ call pargstr (keyword)
+ call pargc (char_type)
+ call pargstr (text)
+ call eprintf ("%-8s %c %s\n")
+ call pargstr (keyword)
+ call pargc (char_type)
+ call pargstr (rtext)
+ call eprintf (" ... OK to replace")
+ call flush (STDERR)
+ if (clgetb ("go_ahead")) {
+ call tbhpnp (tp, i, keyword, dtype, rtext) # replace it
+ modified = true
+ } else {
+ call eprintf ("not replaced\n")
+ }
+
+ } else {
+ # Replace the value without prompting.
+ call tbhpnp (tp, i, keyword, dtype, rtext)
+ modified = true
+ }
+
+ # Save the replacement value.
+ if (save_instr)
+ call tu_save_instr (rtext, isbuf, bufsize, ibp)
+ }
+end
+
+# tu_ch_name -- change keyword name
+# Replace the name of an existing keyword without changing either the
+# value or comment.
+# The instruction and the replacement string will be saved in the instruction
+# buffer if appropriate. Neither will be saved, however, if the keyword is
+# not found in the first table. The user will be prompted for confirmation
+# if the input is not redirected and the instruction was not 'k!'.
+
+procedure tu_ch_name (tp, linebuf, ip,
+ save_instr, isbuf, bufsize, ibp,
+ modified)
+
+pointer tp # i: pointer to table descriptor
+char linebuf[ARB] # i: input line
+int ip # i: index in linebuf
+bool save_instr # i: save instruction?
+pointer isbuf # io: pointer to instruction buffer
+int bufsize # io: current size of instruction buffer
+int ibp # io: current index in instruction buffer
+bool modified # io: set to true if parameter was replaced
+#--
+char oldkey[SZ_KEYWORD] # current keyword
+char newkey[SZ_KEYWORD+1] # new keyword; extra space for testing length
+int i
+int parnum # parameter specified by number (zero)
+bool insufficient_input # true if not enough input was given
+int ctowrd(), strlen()
+errchk tbhckn
+
+begin
+ i = ip
+
+ insufficient_input = false # initial value
+
+ if (ctowrd (linebuf, i, oldkey, SZ_KEYWORD) <= 0)
+ insufficient_input = true
+ if (ctowrd (linebuf, i, newkey, SZ_KEYWORD+1) <= 0)
+ insufficient_input = true
+
+ if (insufficient_input) {
+ call eprintf ("syntax: k oldkey newkey\n")
+ return
+ }
+
+ if (strlen (newkey) > SZ_KEYWORD) {
+ call eprintf ("new keyword name is too long; limit is %d\n")
+ call pargi (SZ_KEYWORD)
+ return
+ }
+
+ # Save the instruction.
+ if (save_instr)
+ call tu_save_instr (linebuf, isbuf, bufsize, ibp)
+
+ # Replace the keyword name.
+ parnum = 0
+ call tbhckn (tp, oldkey, parnum, newkey)
+ modified = true
+end
+
+
+# tu_listpar -- list parameters
+# Either all parameters or a range of parameters specified by number
+# may be displayed. The parameter numbers may optionally be displayed.
+
+procedure tu_listpar (tp, linebuf, ip, incl_num,
+ save_instr, isbuf, bufsize, ibp)
+
+pointer tp # i: pointer to table descriptor
+char linebuf[ARB] # i: input line
+int ip # io: index in linebuf
+bool incl_num # i: include number when listing parameters?
+bool save_instr # i: save instruction?
+pointer isbuf # io: pointer to instruction buffer
+int bufsize # io: current size of instruction buffer
+int ibp # io: current index in instruction buffer
+#--
+char keyword[SZ_KEYWORD] # keyword for parameter
+char text[SZ_PARREC] # buffer for value of parameter
+char comment[SZ_PARREC] # buffer for comment, if any
+char char_type # data type as a letter
+int dtype # data type (a character constant)
+int j1, j2 # loop bounds: first & last par numbers
+int npar # current number of parameters
+int k # loop index
+int tbpsta()
+int ctoi()
+
+begin
+ npar = tbpsta (tp, TBL_NPAR)
+
+ # Get the range of keywords to list.
+ if (ctoi (linebuf, ip, j1) <= 0) {
+ j1 = 1
+ j2 = npar
+ } else if (ctoi (linebuf, ip, j2) <= 0) {
+ j2 = j1
+ }
+ if (j2 < j1) {
+ k = j1 # swap j1, j2
+ j1 = j2
+ j2 = k
+ }
+ if (j1 > npar || j2 < 1) {
+ call eprintf ("out of range; max is %d\n")
+ call pargi (npar)
+ j1 = 1 # so loop will not be executed
+ j2 = 0
+ }
+ j1 = max (j1, 1)
+ j2 = min (j2, npar)
+ do k = j1, j2 {
+ call tbhgnp (tp, k, keyword, dtype, text)
+ call tbhgcm (tp, keyword, comment, SZ_PARREC)
+ # Change data type to a char.
+ switch (dtype) {
+ case TY_REAL:
+ char_type = 'r'
+ case TY_INT:
+ char_type = 'i'
+ case TY_DOUBLE:
+ char_type = 'd'
+ case TY_BOOL:
+ char_type = 'b'
+ default:
+ char_type = 't'
+ }
+ if (incl_num) { # include keyword number
+ call printf ("%2d ")
+ call pargi (k)
+ }
+ call printf ("%-8s %c")
+ call pargstr (keyword)
+ call pargc (char_type)
+ if (comment[1] == EOS) {
+ if (dtype == TY_BOOL && text[1] == '1') {
+ call printf (" yes\n")
+ } else if (dtype == TY_BOOL && text[1] == '0') {
+ call printf (" no\n")
+ } else {
+ call printf (" %s\n")
+ call pargstr (text)
+ }
+ } else { # also print comment
+ if (char_type == 't') {
+ call printf (" '%s'") # enclose text in quotes
+ call pargstr (text)
+ } else if (dtype == TY_BOOL) {
+ if (text[1] == '1') {
+ call printf (" yes")
+ } else if (text[1] == '0') {
+ call printf (" no")
+ } else {
+ call printf (" %s")
+ call pargstr (text)
+ }
+ } else {
+ call printf (" %s") # no quotes needed
+ call pargstr (text)
+ }
+ call printf (" %s\n")
+ call pargstr (comment)
+ }
+ }
+
+ if (save_instr)
+ call tu_save_instr (linebuf, isbuf, bufsize, ibp)
+end
+
+
+# tu_gline -- getline without newline
+# Read a line using getline, and replace the newline character with EOS.
+# Either EOF or the number of char read before the newline will be returned.
+
+int procedure tu_gline (fd, linebuf)
+
+int fd # i: identifies input file
+char linebuf[ARB] # o: output buffer for text that was read
+#--
+int istat
+int k
+int getline()
+
+begin
+ istat = getline (fd, linebuf)
+ if (istat == EOF)
+ return (istat)
+
+ k = 1
+ while (linebuf[k] != EOS) {
+ if (linebuf[k] == '\n') {
+ linebuf[k] = EOS
+ break
+ }
+ k = k + 1
+ }
+ return (k-1)
+end
+
+
+# tu_parnum -- get parameter number
+# Either one or a pair of keywords may be given as input in the string
+# 'keyword', and each may be specified either by name or by number.
+# This routine reads the numbers and/or names and converts keyword
+# names to numbers. If the parameter (or either of two) is not found, or
+# if the number is larger than the number of header keywords, par1
+# will be set to 0 and par2 to -1. If only one keyword is given, par2
+# will be set equal to par1.
+
+procedure tu_parnum (tp, keyword, par1, par2)
+
+pointer tp # i: pointer to table descriptor
+char keyword[ARB] # i: keyword name or number
+int par1 # o: number of first parameter to delete
+int par2 # o: number of last parameter to delete
+#--
+char key1[SZ_KEYWORD], key2[SZ_KEYWORD]
+int ip # counter within keyword
+int ipi # counter in key1 or key2
+int temp # for swapping par1 & par2
+int npar # total number of header parameters
+int nchar
+int ctowrd(), ctoi(), tbpsta()
+
+begin
+ npar = tbpsta (tp, TBL_NPAR)
+ # Default values so a loop from par1 to par2 will not execute.
+ par1 = 0
+ par2 = -1
+
+ # Extract the first (and possibly only) word.
+ ip = 1
+ nchar = ctowrd (keyword, ip, key1, SZ_KEYWORD)
+ if (nchar < 1)
+ return # nothing given
+
+ # Interpret the first word as a number or name. First try to
+ # read it as an integer. If it's not an integer, or if there's
+ # something after an integer part (e.g. key1 = "37test"), then
+ # treat it as a keyword name.
+ ipi = 1
+ nchar = ctoi (key1, ipi, par1)
+ if ( (nchar <= 0) || (key1[ipi] != EOS) )
+ call tbhfkw (tp, key1, par1) # get the par number
+
+ if (par1 < 1) {
+ call eprintf ("warning: keyword `%s' not found\n")
+ call pargstr (key1)
+ return
+ }
+
+ nchar = ctowrd (keyword, ip, key2, SZ_KEYWORD) # read second word
+ if (nchar < 1) {
+ par2 = par1 # there was only one word
+ } else {
+ ipi = 1
+ nchar = ctoi (key2, ipi, par2)
+ if ( (nchar <= 0) || (key2[ipi] != EOS) )
+ call tbhfkw (tp, key2, par2)
+ if (par2 < 1) {
+ call eprintf ("warning: keyword `%s' not found\n")
+ call pargstr (key2)
+ return
+ }
+ if (par1 > par2) {
+ temp = par2
+ par2 = par1
+ par1 = temp
+ }
+ }
+
+ if (par1 > npar || par2 > npar) {
+ call eprintf (
+ "there are only %d header parameters; no action taken\n")
+ call pargi (npar)
+ par1 = 0
+ par2 = -1
+ }
+end
+
+
+# tu_partype -- get data type of parameter
+# This routine looks for the given keyword in the header. If it is found,
+# the data type (integer code) is returned as dtype. If not, dtype is set
+# to the default TY_CHAR, and found is set to false.
+
+procedure tu_partype (tp, keyword, dtype, found)
+
+pointer tp # i: pointer to table descriptor
+char keyword[ARB] # i: keyword name
+int dtype # o: data type (TY_INT, TY_CHAR, ...)
+bool found # o: true if keyword was found in header.
+#--
+char kwrd[SZ_KEYWORD] # keyword returned by tbhgnp
+char value[SZ_PARREC] # buffer for value of parameter
+int parnum
+
+begin
+ # Get the keyword number, or zero if it isn't in the header.
+ call tbhfkw (tp, keyword, parnum)
+
+ # Get the data type, ignoring the value.
+ if (parnum > 0) {
+ call tbhgnp (tp, parnum, kwrd, dtype, value)
+ found = true
+ } else {
+ dtype = TY_CHAR # default
+ found = false
+ }
+end
diff --git a/pkg/utilities/nttools/tupar/tupar.h b/pkg/utilities/nttools/tupar/tupar.h
new file mode 100644
index 00000000..959fa6c1
--- /dev/null
+++ b/pkg/utilities/nttools/tupar/tupar.h
@@ -0,0 +1,3 @@
+define TUPAR_EXIT 1 # exit, saving changes to table
+define TUPAR_QUIT 2 # quit without saving changes
+define TUPAR_QUIT_NC 3 # quit, and don't ask for confirmation
diff --git a/pkg/utilities/nttools/tupar/tupar.x b/pkg/utilities/nttools/tupar/tupar.x
new file mode 100644
index 00000000..b4cf35e3
--- /dev/null
+++ b/pkg/utilities/nttools/tupar/tupar.x
@@ -0,0 +1,260 @@
+include <fset.h> # used to check whether I/O is redirected
+include <error.h>
+include <tbset.h>
+include "tupar.h" # defines TUPAR_EXIT, TUPAR_QUIT
+
+# tupar -- edit header parameters
+# This task may be used to list, add to, replace, or delete header
+# parameters in a table or list of tables.
+#
+# Phil Hodge, 22-Jul-1987 Task created
+# Phil Hodge, 11-Aug-1987 Call tbhad[] instead of tbhpt[].
+# Phil Hodge, 18-Mar-1988 Rewrite, allowing a list of tables.
+# Phil Hodge, 7-Sep-1988 Change parameter name for table.
+# Phil Hodge, 23-Aug-1991 Allow quit or exit.
+# Phil Hodge, 9-Jul-1993 Allow quit without verification if nothing changed.
+# Phil Hodge, 29-Jun-1995 Modify for FITS tables; modify tu_open and tu_close.
+# Phil Hodge, 3-Oct-1995 Use tbn instead of fnt.
+# Phil Hodge, 22-May-1996 Use iferr when calling tu_instr.
+
+define LEN_ISBUF 1000 # length or increment for instruction buffer
+
+procedure tupar()
+
+pointer tlist # for list of input table names
+bool same_for_all # same set of instructions for all tables?
+bool verbose # print name of each table?
+bool readonly # open tables readonly?
+#--
+pointer tp # pointer to table descriptor
+pointer sp
+pointer tname # scratch for table name
+pointer tabname # scratch for full name of table (incl [...])
+pointer lbuf # scratch for input buffer
+pointer isbuf # buffer for saving instructions
+int bufsize # allocated size of Memc[isbuf]
+int ibp # index in Memc[isbuf]
+int eq_flag # exit or quit
+int istat # set by tu_ex_instr; > 0 implies error
+bool inplace # open tables inplace?
+bool modified # true if the header was modified
+bool from_stdin # get input from STDIN?
+bool save_instr # save instruction in buffer?
+bool iredir # is input redirected?
+bool oredir # is output redirected?
+bool prompt # prompt user for input?
+bool alldone # done with all tables?
+bool done # done with current table?
+bool quit # true if we should delete temp table
+bool clgetb()
+int fstati()
+pointer tbnopenp()
+int tbnget(), tbnlen()
+
+begin
+ call smark (sp)
+ call salloc (tname, SZ_LINE, TY_CHAR)
+ call salloc (tabname, SZ_LINE, TY_CHAR)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+
+ tlist = tbnopenp ("table")
+
+ same_for_all = clgetb ("same")
+ verbose = clgetb ("verbose")
+ readonly = clgetb ("readonly")
+ if (readonly)
+ inplace = true
+ else
+ inplace = clgetb ("inplace")
+
+ from_stdin = true
+
+ # Is input or output redirected?
+ iredir = (fstati (STDIN, F_REDIR) == YES)
+ oredir = (fstati (STDOUT, F_REDIR) == YES)
+ prompt = !iredir # prompt if input is not redirected
+
+ save_instr = (same_for_all && (tbnlen (tlist) > 1))
+ if (save_instr) {
+ bufsize = LEN_ISBUF
+ call malloc (isbuf, bufsize, TY_CHAR)
+ Memc[isbuf] = EOS
+ } else {
+ bufsize = 0
+ isbuf = NULL
+ }
+
+ # Loop over all table names in the file name template.
+ alldone = (tbnget (tlist, Memc[tname], SZ_LINE) == EOF)
+ while (!alldone) {
+
+ iferr {
+ # Open the table (or a copy of it).
+ call tu_open (Memc[tname], "tupar", readonly, inplace,
+ tp, Memc[tabname], SZ_LINE)
+ } then {
+ call eprintf ("can't open %s\n")
+ call pargstr (Memc[tname])
+ alldone = (tbnget (tlist, Memc[tname], SZ_LINE) == EOF)
+ call erract (EA_WARN)
+ next # ignore this table
+ }
+
+ if (verbose) {
+ if (oredir) {
+ call eprintf ("%s\n")
+ call pargstr (Memc[tabname])
+ }
+ call printf ("%s\n")
+ call pargstr (Memc[tabname])
+ }
+
+ # Edit header parameters in current table.
+ ibp = 1 # may be incremented in loop
+ modified = false # may be reset within tu_instr
+ done = false
+ while ( ! done ) {
+ # Get an instruction, execute it, and possibly save it
+ # for use again.
+ iferr {
+ call tu_instr (tp, Memc[lbuf], readonly, prompt, from_stdin,
+ iredir, save_instr, isbuf, bufsize, ibp,
+ modified, eq_flag, done, istat)
+ } then {
+ call erract (EA_WARN)
+ }
+ if (istat > 0)
+ call eprintf ("table was opened readonly\n")
+
+ if (inplace && !readonly &&
+ (eq_flag == TUPAR_QUIT || eq_flag == TUPAR_QUIT_NC)) {
+ call eprintf (
+"can't quit without saving changes because you edited the table inplace\n")
+ done = false
+ } else if (eq_flag == TUPAR_QUIT && modified && !readonly) {
+ # Ask for verification before quitting.
+ call clputb ("go_ahead", clgetb ("quit_default"))
+ call eprintf ("quit without saving changes")
+ call flush (STDERR)
+ if (! clgetb ("go_ahead"))
+ done = false # no, don't quit
+ }
+ }
+
+ # Reset flags after processing first table.
+ if (same_for_all) {
+ prompt = false
+ from_stdin = false
+ }
+ save_instr = false
+
+ # Close the table, renaming the temp table back to the
+ # original if we are saving our changes.
+ quit = (eq_flag == TUPAR_QUIT || eq_flag == TUPAR_QUIT_NC)
+ iferr {
+ call tu_close (tp, inplace, quit, Memc[tabname])
+ } then {
+ alldone = (tbnget (tlist, Memc[tname], SZ_LINE) == EOF)
+ call erract (EA_WARN)
+ next # ignore this table
+ }
+
+ # Get the name of the next file in the list.
+ alldone = (tbnget (tlist, Memc[tname], SZ_LINE) == EOF)
+
+ # If the user modified the table but then decided to quit,
+ # then abort without opening the rest of the tables.
+ if (eq_flag != TUPAR_EXIT && modified && same_for_all)
+ alldone = true
+ }
+ if (isbuf != NULL)
+ call mfree (isbuf, TY_CHAR)
+ call tbnclose (tlist)
+ call sfree (sp)
+end
+
+
+# tu_save_instr -- save edit instruction
+# Save the current instruction in the instruction buffer. The entries
+# are separated by '\n', and the entire set of entries is terminated
+# by EOS.
+# If the buffer would overflow, it will be reallocated.
+
+procedure tu_save_instr (lbuf, isbuf, bufsize, ibp)
+
+char lbuf[ARB] # i: line buffer containing instruction
+pointer isbuf # io: buffer for saving instructions
+int bufsize # io: current allocated size of Memc[isbuf]
+int ibp # io: current index in Memc[isbuf]
+#--
+int k # loop index
+bool done # loop-termination flag
+int leni # length of lbuf
+int strlen()
+
+begin
+ leni = strlen (lbuf)
+ if (ibp + leni >= bufsize) {
+ bufsize = bufsize + LEN_ISBUF
+ call realloc (isbuf, bufsize, TY_CHAR)
+ }
+
+ done = false
+ k = 1
+ while ( ! done ) {
+ if ((lbuf[k] == EOS) || (lbuf[k] == '\n')) {
+ done = true
+ } else {
+ Memc[isbuf+ibp-1] = lbuf[k]
+ ibp = ibp + 1
+ }
+ k = k + 1
+ }
+ Memc[isbuf+ibp-1] = '\n'
+ Memc[isbuf+ibp] = EOS
+ ibp = ibp + 1 # so ibp points to EOS
+end
+
+
+# tu_rd_instr -- read edit instruction
+# Read an instruction from the instruction buffer. When EOS is reached
+# in the buffer, an EOF will be returned; otherwise, the number of char
+# in the current instruction will be returned.
+
+int procedure tu_rd_instr (isbuf, ibp, lbuf)
+
+char isbuf[ARB] # i: buffer containing instructions
+int ibp # io: current index in isbuf
+char lbuf[ARB] # o: buffer to receive instruction
+#--
+int k # loop index
+bool done # loop-termination flag
+
+begin
+ done = false
+ k = 0
+ while ( ! done ) {
+
+ if (isbuf[ibp] == '\n') {
+
+ if (k > 0) # skip past adjacent '\n'
+ done = true
+ ibp = ibp + 1
+
+ } else if (isbuf[ibp] == EOS) {
+
+ done = true # leave ibp pointing to EOS
+
+ } else {
+
+ k = k + 1
+ lbuf[k] = isbuf[ibp]
+ ibp = ibp + 1
+ }
+ }
+ lbuf[k+1] = EOS
+
+ if (k <= 0)
+ k = EOF
+ return (k)
+end
diff --git a/pkg/utilities/nttools/x_nttools.x b/pkg/utilities/nttools/x_nttools.x
new file mode 100644
index 00000000..5fe2c2c7
--- /dev/null
+++ b/pkg/utilities/nttools/x_nttools.x
@@ -0,0 +1,50 @@
+task taextract,
+ tainsert,
+ keypar = t_keypar,
+ keytab = t_keytab,
+ gtedit = t_gtedit,
+ parkey = t_parkey,
+ partab = t_partab,
+ tabkey = t_tabkey,
+ tabpar = t_tabpar,
+ imtab,
+ tabim,
+ tcalc = t_tcalc,
+ tchcol,
+ tcheck,
+ tchsize,
+ tcopy,
+ tcreate,
+ tdelete,
+ tdiffer = t_tdiffer,
+ tdump,
+ tedit = t_tedit,
+ texpand,
+ thedit = t_thedit,
+ thistogram,
+ thselect = t_thselect,
+ tinfo,
+ tintegrate = t_tintegrate,
+ tjoin = t_tjoin,
+ tlcol,
+ tlinear,
+ tmatch,
+ tmerge,
+ tprint,
+ tproduct = t_product,
+ tproject = t_project,
+ tquery = t_tquery,
+ tread = t_tread,
+ trebin,
+ tselect = t_tselect,
+ tsort = t_tsort,
+ tstat,
+ ttranspose,
+ tunits,
+ tupar,
+ tscopy = t_tcopy,
+ txtable = t_txtable,
+ tximage = t_tximage,
+ titable = t_titable,
+ tiimage = t_tiimage
+
diff --git a/pkg/utilities/nttools/zz.xml b/pkg/utilities/nttools/zz.xml
new file mode 100644
index 00000000..59005749
--- /dev/null
+++ b/pkg/utilities/nttools/zz.xml
@@ -0,0 +1,3427 @@
+<?xml version="1.0"?>
+<VOTABLE version="1.2"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://www.ivoa.net/xml/VOTable/v1.2"
+ xsi:SchemaLocation="http://www.ivoa.net/xml/VOTable/v1.2"
+ xmlns:stc="http://www.ivoa.net/xml/STC/v1.30">
+<RESOURCE name="CSC">
+<TABLE name="RA:83.8221,DEC:-5.39111,SR:0.016666,VERB:2,TIME:2012/10/18_16:39:23">
+<DESCRIPTION>
+Chandra Source Catalog VO Cone Search Service
+</DESCRIPTION>
+ <GROUP utype="stc:AstroCoordSystem" ID="ICRS">
+ <DESCRIPTION>ICRS Coordinate System</DESCRIPTION>
+ <GROUP utype="stc:AstroCoordSystem.TimeFrame">
+ <PARAM name="TimeScale" datatype="char" arraysize="*"
+ utype="stc:AstroCoordSystem.TimeFrame.TimeScale" value="TT"/>
+ <PARAM name="TimeRefPosition" datatype="char" arraysize="*"
+ utype="stc:AstroCoordSystem.TimeFrame.ReferencePosition"
+ value="TOPOCENTER"/>
+ </GROUP>
+ <GROUP utype="stc:AstroCoordSystem.SpaceFrame">
+ <PARAM name="SpaceRefFrame" datatype="char" arraysize="*"
+ utype="stc:AstroCoordSystem.SpaceFrame.SpaceRefFrame"
+ value="ICRS"/>
+ <PARAM name="SpaceRefPosition" datatype="char" arraysize="*"
+ utype="stc:AstroCoordSystem.SpaceFrame.ReferencePosition"
+ value="TOPOCENTER"/>
+ </GROUP>
+ <GROUP utype="stc:AstroCoordSystem.SpectralFrame">
+ <PARAM name="SpectralRefPosition" datatype="char" arraysize="*"
+ utype="stc:AstroCoordSystem.SpectralFrame.ReferencePosition"
+ value="TOPOCENTER"/>
+ </GROUP>
+ </GROUP>
+ <GROUP ID="ICRScoords" utype="stc:AstroCoords">
+ <DESCRIPTION>ICRS coordinates</DESCRIPTION>
+ <PARAM datatype="char" arraysize="*" ucd="pos.frame" name="cooframe"
+ utype="stc:AstroCoords.coord_system_id" value="ICRS"/>
+ <FIELDref ref="col1"/>
+ <FIELDref ref="col2"/>
+ <FIELDref ref="col3"/>
+ </GROUP>
+<FIELD ID="col0" arraysize="*" datatype="char" name="name" ucd="meta.id;meta.main" width="20">
+<DESCRIPTION>Source name in the format 'CXO Jhhmmss.s +/- ddmmss'</DESCRIPTION>
+</FIELD>
+<FIELD ID="col1" datatype="double" name="ra" precision="F5" ref="ICRScoords" ucd="pos.eq.ra;meta.main" utype="stc:AstroCoords.Position2D.Value2.C1" width="9">
+<DESCRIPTION>Source position, ICRS right ascension</DESCRIPTION>
+</FIELD>
+<FIELD ID="col2" datatype="double" name="dec" precision="F5" ref="ICRScoords" ucd="pos.eq.dec;meta.main" utype="stc:AstroCoords.Position2D.Value2.C2" width="9">
+<DESCRIPTION>Source position, ICRS declination</DESCRIPTION>
+</FIELD>
+<FIELD ID="col3" datatype="double" name="err_ellipse_r0" precision="F2" ref="ICRScoords" ucd="phys.angSize.smaj;pos.errorEllipse" unit="arcsec" utype="stc:AstroCoords.Position2D.Error2.C1" width="7">
+<DESCRIPTION>Major radius of the 95% confidence level error ellipse</DESCRIPTION>
+</FIELD>
+<FIELD ID="col4" datatype="char" name="conf_flag" ucd="meta.code" width="5">
+<DESCRIPTION>Source regions overlap (source is confused)</DESCRIPTION>
+</FIELD>
+<FIELD ID="col5" datatype="char" name="extent_flag" ucd="meta.code;phys.angSize" width="5">
+<DESCRIPTION>Deconvolved source extent is inconsistent with a point source at the 90% confidence level</DESCRIPTION>
+</FIELD>
+<FIELD ID="col6" datatype="char" name="sat_src_flag" ucd="meta.code.qual;instr.saturation" width="5">
+<DESCRIPTION>Source is saturated in all observations; source properties are unreliable</DESCRIPTION>
+</FIELD>
+<FIELD ID="col7" datatype="double" name="flux_aper_b" precision="E3" ucd="phot.flux;src.net;em.X-ray" unit="erg/s*cm^2" width="9">
+<DESCRIPTION>Aperture-corrected net energy flux inferred from the source region aperture, calculated by counting X-ray events; ACIS broad energy band</DESCRIPTION>
+</FIELD>
+<FIELD ID="col8" datatype="double" name="flux_aper_lolim_b" precision="E3" ucd="stat.error;phot.flux;src.net;stat.min;em.X-ray" unit="erg/s*cm^2" width="9">
+<DESCRIPTION>Aperture-corrected net energy flux inferred from the source region aperture, calculated by counting X-ray events (68% lower confidence limit); ACIS broad energy band</DESCRIPTION>
+</FIELD>
+<FIELD ID="col9" datatype="double" name="flux_aper_hilim_b" precision="E3" ucd="stat.error;phot.flux;src.net;stat.max;em.X-ray" unit="erg/s*cm^2" width="9">
+<DESCRIPTION>Aperture-corrected net energy flux inferred from the source region aperture, calculated by counting X-ray events (68% upper confidence limit); ACIS broad energy band</DESCRIPTION>
+</FIELD>
+<FIELD ID="col10" datatype="double" name="flux_aper_w" precision="E3" ucd="phot.flux;src.net;em.X-ray" unit="erg/s*cm^2" width="9">
+<DESCRIPTION>Aperture-corrected net energy flux inferred from the source region aperture, calculated by counting X-ray events; HRC wide energy band</DESCRIPTION>
+</FIELD>
+<FIELD ID="col11" datatype="double" name="flux_aper_lolim_w" precision="E3" ucd="stat.error;phot.flux;src.net;stat.min;em.X-ray" unit="erg/s*cm^2" width="9">
+<DESCRIPTION>Aperture-corrected net energy flux inferred from the source region aperture, calculated by counting X-ray events (68% lower confidence limit); HRC wide energy band</DESCRIPTION>
+</FIELD>
+<FIELD ID="col12" datatype="double" name="flux_aper_hilim_w" precision="E3" ucd="stat.error;phot.flux;src.net;stat.max;em.X-ray" unit="erg/s*cm^2" width="9">
+<DESCRIPTION>Aperture-corrected net energy flux inferred from the source region aperture, calculated by counting X-ray events (68% upper confidence limit); HRC wide energy band</DESCRIPTION>
+</FIELD>
+<FIELD ID="col13" datatype="double" name="significance" precision="F2" ucd="stat.snr" width="7">
+<DESCRIPTION>Highest source flux significance across all observations</DESCRIPTION>
+</FIELD>
+<FIELD ID="col14" datatype="double" name="hard_hm" precision="F4" ucd="phot.color;em.X-ray" width="9">
+<DESCRIPTION>Spectral hardness ratio measured between ACIS energy bands 'h' and 'm'; hard_hm = (flux_aper_h - flux_aper_m)/flux_aper_b</DESCRIPTION>
+</FIELD>
+<FIELD ID="col15" datatype="double" name="hard_hm_lolim" precision="F4" ucd="stat.error;phot.color;stat.min;em.X-ray" width="9">
+<DESCRIPTION>Spectral hardness ratio measured between ACIS energy bands 'h' and 'm'; hard_hm = (flux_aper_h - flux_aper_m)/flux_aper_b (68% lower confidence limit)</DESCRIPTION>
+</FIELD>
+<FIELD ID="col16" datatype="double" name="hard_hm_hilim" precision="F4" ucd="stat.error;phot.color;stat.max;em.X-ray" width="9">
+<DESCRIPTION>Spectral hardness ratio measured between ACIS energy bands 'h' and 'm'; hard_hm = (flux_aper_h - flux_aper_m)/flux_aper_b (68% upper confidence limit)</DESCRIPTION>
+</FIELD>
+<FIELD ID="col17" datatype="double" name="hard_ms" precision="F4" ucd="phot.color;em.X-ray" width="9">
+<DESCRIPTION>Spectral hardness ratio measured between ACIS energy bands 'm' and 's'; hard_ms = (flux_aper_m - flux_aper_s)/flux_aper_b</DESCRIPTION>
+</FIELD>
+<FIELD ID="col18" datatype="double" name="hard_ms_lolim" precision="F4" ucd="stat.error;phot.color;stat.min;em.X-ray" width="9">
+<DESCRIPTION>Spectral hardness ratio measured between ACIS energy bands 'm' and 's'; hard_ms = (flux_aper_m - flux_aper_s)/flux_aper_b (68% lower confidence limit)</DESCRIPTION>
+</FIELD>
+<FIELD ID="col19" datatype="double" name="hard_ms_hilim" precision="F4" ucd="stat.error;phot.color;stat.max;em.X-ray" width="9">
+<DESCRIPTION>Spectral hardness ratio measured between ACIS energy bands 'm' and 's'; hard_ms = (flux_aper_m - flux_aper_s)/flux_aper_b (68% upper confidence limit)</DESCRIPTION>
+</FIELD>
+<FIELD ID="col20" datatype="short" name="var_intra_index_b" ucd="src.var.index;em.X-ray" width="6">
+<DESCRIPTION>Intra-observation Gregory-Loredo variability index in the range [0, 10] (highest value across all observations); ACIS broad energy band</DESCRIPTION>
+<VALUES null='-32768'/>
+</FIELD>
+<FIELD ID="col21" datatype="short" name="var_intra_index_w" ucd="src.var.index;em.X-ray" width="6">
+<DESCRIPTION>Intra-observation Gregory-Loredo variability index in the range [0, 10] (highest value across all observations); HRC wide energy band</DESCRIPTION>
+<VALUES null='-32768'/>
+</FIELD>
+<FIELD ID="col22" datatype="short" name="var_inter_index_b" ucd="src.var.index;em.X-ray" width="6">
+<DESCRIPTION>Inter-observation variability index in the range [0, 10]; indicates whether the source region photon flux is constant between observations; ACIS broad energy band</DESCRIPTION>
+<VALUES null='-32768'/>
+</FIELD>
+<FIELD ID="col23" datatype="short" name="var_inter_index_w" ucd="src.var.index;em.X-ray" width="6">
+<DESCRIPTION>Inter-observation variability index in the range [0, 10]; indicates whether the source region photon flux is constant between observations; HRC wide energy band</DESCRIPTION>
+<VALUES null='-32768'/>
+</FIELD>
+<DATA>
+<TABLEDATA>
+ <TR>
+ <TD>CXO J053513.4-052340</TD>
+ <TD>83.80601567</TD>
+ <TD>-5.39448431</TD>
+ <TD>0.14563</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.97894E-14</TD>
+ <TD>6.85624E-14</TD>
+ <TD>7.10287E-14</TD>
+ <TD>5.88765E-14</TD>
+ <TD>5.56953E-14</TD>
+ <TD>6.20898E-14</TD>
+ <TD>25.9701</TD>
+ <TD>-0.0822159</TD>
+ <TD>-0.103467</TD>
+ <TD>-0.0608849</TD>
+ <TD>-0.33969</TD>
+ <TD>-0.370832</TD>
+ <TD>-0.308476</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053513.5-052330</TD>
+ <TD>83.80637907</TD>
+ <TD>-5.39185304</TD>
+ <TD>0.14712</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.78161E-14</TD>
+ <TD>6.65089E-14</TD>
+ <TD>6.91366E-14</TD>
+ <TD>3.03441E-14</TD>
+ <TD>2.80268E-14</TD>
+ <TD>3.26849E-14</TD>
+ <TD>28.5808</TD>
+ <TD>0.0105262</TD>
+ <TD>-0.0109229</TD>
+ <TD>0.0322564</TD>
+ <TD>-0.326373</TD>
+ <TD>-0.353819</TD>
+ <TD>-0.299148</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053513.9-052319</TD>
+ <TD>83.80801443</TD>
+ <TD>-5.3888603</TD>
+ <TD>0.21491</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.27045E-15</TD>
+ <TD>4.80761E-15</TD>
+ <TD>5.73796E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>11.0835</TD>
+ <TD>-0.161814</TD>
+ <TD>-0.22216</TD>
+ <TD>-0.103899</TD>
+ <TD>-0.290804</TD>
+ <TD>-0.363042</TD>
+ <TD>-0.21809</TD>
+ <TD>2</TD>
+ <TD>-32768</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.0-052338</TD>
+ <TD>83.8085595</TD>
+ <TD>-5.3939577</TD>
+ <TD>0.14728</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.66661E-14</TD>
+ <TD>5.54982E-14</TD>
+ <TD>5.78459E-14</TD>
+ <TD>2.97063E-14</TD>
+ <TD>2.74026E-14</TD>
+ <TD>3.20332E-14</TD>
+ <TD>30.9082</TD>
+ <TD>-0.0350682</TD>
+ <TD>-0.0573876</TD>
+ <TD>-0.0129662</TD>
+ <TD>-0.176479</TD>
+ <TD>-0.203986</TD>
+ <TD>-0.149003</TD>
+ <TD>10</TD>
+ <TD>7</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.2-052304</TD>
+ <TD>83.80953052</TD>
+ <TD>-5.38444889</TD>
+ <TD>0.15885</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.45327E-14</TD>
+ <TD>5.33644E-14</TD>
+ <TD>5.57128E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>24.4025</TD>
+ <TD>0.91049</TD>
+ <TD>0.895018</TD>
+ <TD>0.925368</TD>
+ <TD>0.0411119</TD>
+ <TD>0.0336484</TD>
+ <TD>0.0488612</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.3-052308</TD>
+ <TD>83.80962741</TD>
+ <TD>-5.38557712</TD>
+ <TD>0.14858</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>6.64955E-14</TD>
+ <TD>6.54639E-14</TD>
+ <TD>6.75375E-14</TD>
+ <TD>1.05285E-14</TD>
+ <TD>9.11164E-15</TD>
+ <TD>1.19597E-14</TD>
+ <TD>45.2756</TD>
+ <TD>0.354199</TD>
+ <TD>0.33561</TD>
+ <TD>0.372553</TD>
+ <TD>0.195498</TD>
+ <TD>0.182312</TD>
+ <TD>0.208292</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.3-052317</TD>
+ <TD>83.80969326</TD>
+ <TD>-5.38810981</TD>
+ <TD>0.16924</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>2.56431E-14</TD>
+ <TD>2.47535E-14</TD>
+ <TD>2.65417E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>17.4034</TD>
+ <TD>0.985171</TD>
+ <TD>0.978543</TD>
+ <TD>0.990966</TD>
+ <TD>-0.00698975</TD>
+ <TD>-0.0128563</TD>
+ <TD>-0.00214212</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.3-052253</TD>
+ <TD>83.8098206</TD>
+ <TD>-5.3816407</TD>
+ <TD>0.16466</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.05176E-14</TD>
+ <TD>1.98107E-14</TD>
+ <TD>2.12316E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>15.0649</TD>
+ <TD>0.560934</TD>
+ <TD>0.511123</TD>
+ <TD>0.609698</TD>
+ <TD>0.210821</TD>
+ <TD>0.186294</TD>
+ <TD>0.235778</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.4-052322</TD>
+ <TD>83.8099784</TD>
+ <TD>-5.38966568</TD>
+ <TD>0.23553</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>4.66587E-15</TD>
+ <TD>4.28105E-15</TD>
+ <TD>5.05458E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>12.1756</TD>
+ <TD>-0.0756736</TD>
+ <TD>-0.135332</TD>
+ <TD>-0.0170884</TD>
+ <TD>-0.114952</TD>
+ <TD>-0.183403</TD>
+ <TD>-0.0450814</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.3-052333</TD>
+ <TD>83.80998065</TD>
+ <TD>-5.39261156</TD>
+ <TD>0.14702</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>4.8023E-14</TD>
+ <TD>4.70178E-14</TD>
+ <TD>4.90384E-14</TD>
+ <TD>1.46049E-14</TD>
+ <TD>1.29563E-14</TD>
+ <TD>1.62703E-14</TD>
+ <TD>27.6562</TD>
+ <TD>-0.0825775</TD>
+ <TD>-0.106809</TD>
+ <TD>-0.0578608</TD>
+ <TD>-0.124551</TD>
+ <TD>-0.156265</TD>
+ <TD>-0.092763</TD>
+ <TD>9</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.5-052315</TD>
+ <TD>83.81056936</TD>
+ <TD>-5.38772233</TD>
+ <TD>0.17135</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.34289E-14</TD>
+ <TD>1.27463E-14</TD>
+ <TD>1.41184E-14</TD>
+ <TD>8.55561E-15</TD>
+ <TD>7.21816E-15</TD>
+ <TD>9.90657E-15</TD>
+ <TD>12.055</TD>
+ <TD>0.98062</TD>
+ <TD>0.972117</TD>
+ <TD>0.987105</TD>
+ <TD>-0.00429089</TD>
+ <TD>-0.00957531</TD>
+ <TD>-3.08654E-4</TD>
+ <TD>2</TD>
+ <TD>9</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.5-052407</TD>
+ <TD>83.81072267</TD>
+ <TD>-5.40217119</TD>
+ <TD>0.2283</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>9.1153E-15</TD>
+ <TD>8.44146E-15</TD>
+ <TD>9.79595E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>8.8595</TD>
+ <TD>0.968181</TD>
+ <TD>0.95185</TD>
+ <TD>0.981924</TD>
+ <TD>-0.00693137</TD>
+ <TD>-0.0183943</TD>
+ <TD>0.00208314</TD>
+ <TD>1</TD>
+ <TD>-32768</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.6-052328</TD>
+ <TD>83.81100284</TD>
+ <TD>-5.39122647</TD>
+ <TD>0.43437</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.78192E-15</TD>
+ <TD>3.14545E-15</TD>
+ <TD>4.42482E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>5.92101</TD>
+ <TD>-0.0631104</TD>
+ <TD>-0.177637</TD>
+ <TD>0.0523516</TD>
+ <TD>-0.190031</TD>
+ <TD>-0.324285</TD>
+ <TD>-0.0557797</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.6-052301</TD>
+ <TD>83.81109487</TD>
+ <TD>-5.38379019</TD>
+ <TD>0.14849</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>7.39896E-14</TD>
+ <TD>7.29582E-14</TD>
+ <TD>7.50313E-14</TD>
+ <TD>9.53745E-15</TD>
+ <TD>8.13605E-15</TD>
+ <TD>1.0953E-14</TD>
+ <TD>65.3124</TD>
+ <TD>0.170492</TD>
+ <TD>0.157044</TD>
+ <TD>0.183882</TD>
+ <TD>0.180409</TD>
+ <TD>0.16915</TD>
+ <TD>0.191544</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.6-052249</TD>
+ <TD>83.81120139</TD>
+ <TD>-5.38033176</TD>
+ <TD>0.18087</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.32936E-14</TD>
+ <TD>1.2721E-14</TD>
+ <TD>1.38719E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>13.9585</TD>
+ <TD>0.48944</TD>
+ <TD>0.433017</TD>
+ <TD>0.544177</TD>
+ <TD>0.235406</TD>
+ <TD>0.206246</TD>
+ <TD>0.2648</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.7-052412</TD>
+ <TD>83.81128448</TD>
+ <TD>-5.40343355</TD>
+ <TD>0.19978</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>7.71247E-15</TD>
+ <TD>7.15899E-15</TD>
+ <TD>8.27154E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6.14947</TD>
+ <TD>0.370567</TD>
+ <TD>0.259466</TD>
+ <TD>0.47732</TD>
+ <TD>-0.138487</TD>
+ <TD>-0.2424</TD>
+ <TD>-0.0347654</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.7-052322</TD>
+ <TD>83.81133486</TD>
+ <TD>-5.38964017</TD>
+ <TD>0.14839</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.01776E-14</TD>
+ <TD>4.92056E-14</TD>
+ <TD>5.11593E-14</TD>
+ <TD>5.23879E-14</TD>
+ <TD>4.93591E-14</TD>
+ <TD>5.54472E-14</TD>
+ <TD>29.5509</TD>
+ <TD>0.28267</TD>
+ <TD>0.251908</TD>
+ <TD>0.312992</TD>
+ <TD>0.289408</TD>
+ <TD>0.271314</TD>
+ <TD>0.307682</TD>
+ <TD>10</TD>
+ <TD>9</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.8-052406</TD>
+ <TD>83.81170941</TD>
+ <TD>-5.40185359</TD>
+ <TD>0.20687</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.95425E-14</TD>
+ <TD>1.8482E-14</TD>
+ <TD>2.06138E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>10.0425</TD>
+ <TD>0.972371</TD>
+ <TD>0.95999</TD>
+ <TD>0.983311</TD>
+ <TD>0.00443213</TD>
+ <TD>-0.0011769</TD>
+ <TD>0.0108282</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.8-052346</TD>
+ <TD>83.8117676</TD>
+ <TD>-5.39615671</TD>
+ <TD>0.15213</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.9664E-14</TD>
+ <TD>1.88916E-14</TD>
+ <TD>2.04442E-14</TD>
+ <TD>1.26507E-14</TD>
+ <TD>1.10556E-14</TD>
+ <TD>1.4262E-14</TD>
+ <TD>12.2048</TD>
+ <TD>-0.16864</TD>
+ <TD>-0.213904</TD>
+ <TD>-0.123749</TD>
+ <TD>-0.213757</TD>
+ <TD>-0.285474</TD>
+ <TD>-0.140922</TD>
+ <TD>8</TD>
+ <TD>0</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.8-052315</TD>
+ <TD>83.81177012</TD>
+ <TD>-5.38770869</TD>
+ <TD>0.17193</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>9.85838E-15</TD>
+ <TD>9.45421E-15</TD>
+ <TD>1.02666E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>15.2939</TD>
+ <TD>-0.126347</TD>
+ <TD>-0.166511</TD>
+ <TD>-0.0858136</TD>
+ <TD>-0.278406</TD>
+ <TD>-0.332037</TD>
+ <TD>-0.223733</TD>
+ <TD>2</TD>
+ <TD>-32768</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.8-052304</TD>
+ <TD>83.81193361</TD>
+ <TD>-5.38466425</TD>
+ <TD>0.17267</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.03975E-14</TD>
+ <TD>1.97508E-14</TD>
+ <TD>2.10508E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>20.2447</TD>
+ <TD>0.317345</TD>
+ <TD>0.27384</TD>
+ <TD>0.360055</TD>
+ <TD>0.283514</TD>
+ <TD>0.257743</TD>
+ <TD>0.309727</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.9-052412</TD>
+ <TD>83.81217858</TD>
+ <TD>-5.40351021</TD>
+ <TD>0.14801</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.3239E-14</TD>
+ <TD>5.22719E-14</TD>
+ <TD>5.4216E-14</TD>
+ <TD>1.58719E-14</TD>
+ <TD>1.41828E-14</TD>
+ <TD>1.75781E-14</TD>
+ <TD>34.7523</TD>
+ <TD>0.0465175</TD>
+ <TD>0.0256984</TD>
+ <TD>0.0675352</TD>
+ <TD>-0.107479</TD>
+ <TD>-0.131671</TD>
+ <TD>-0.0835884</TD>
+ <TD>10</TD>
+ <TD>1</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.9-052328</TD>
+ <TD>83.81220892</TD>
+ <TD>-5.39133275</TD>
+ <TD>0.16083</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>4.68217E-15</TD>
+ <TD>4.2982E-15</TD>
+ <TD>5.07002E-15</TD>
+ <TD>3.58725E-15</TD>
+ <TD>2.70965E-15</TD>
+ <TD>4.46036E-15</TD>
+ <TD>7.89055</TD>
+ <TD>-0.254059</TD>
+ <TD>-0.369787</TD>
+ <TD>-0.139728</TD>
+ <TD>0.369802</TD>
+ <TD>0.257663</TD>
+ <TD>0.481755</TD>
+ <TD>1</TD>
+ <TD>0</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.9-052338</TD>
+ <TD>83.81228445</TD>
+ <TD>-5.39416969</TD>
+ <TD>0.14232</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.49754E-13</TD>
+ <TD>1.48202E-13</TD>
+ <TD>1.51322E-13</TD>
+ <TD>2.82477E-13</TD>
+ <TD>2.75562E-13</TD>
+ <TD>2.89463E-13</TD>
+ <TD>54.1441</TD>
+ <TD>-0.0472355</TD>
+ <TD>-0.0585613</TD>
+ <TD>-0.0359605</TD>
+ <TD>-0.150355</TD>
+ <TD>-0.16636</TD>
+ <TD>-0.134227</TD>
+ <TD>10</TD>
+ <TD>6</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.0-052354</TD>
+ <TD>83.81265915</TD>
+ <TD>-5.39841906</TD>
+ <TD>0.59443</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.93214E-15</TD>
+ <TD>2.99955E-15</TD>
+ <TD>4.86489E-15</TD>
+ <TD>4.16316</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>2</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.1-052304</TD>
+ <TD>83.81297046</TD>
+ <TD>-5.38451569</TD>
+ <TD>0.45384</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.88649E-15</TD>
+ <TD>9.06494E-16</TD>
+ <TD>2.8637E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.05328</TD>
+ <TD>0.83723</TD>
+ <TD>0.715803</TD>
+ <TD>0.933967</TD>
+ <TD>-0.0320696</TD>
+ <TD>-0.118798</TD>
+ <TD>0.0293079</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.1-052346</TD>
+ <TD>83.81314399</TD>
+ <TD>-5.39621512</TD>
+ <TD>0.2003</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>4.39873E-15</TD>
+ <TD>3.92166E-15</TD>
+ <TD>4.88063E-15</TD>
+ <TD>4.00059E-15</TD>
+ <TD>3.0109E-15</TD>
+ <TD>4.9949E-15</TD>
+ <TD>5.6963</TD>
+ <TD>-0.0285843</TD>
+ <TD>-0.102898</TD>
+ <TD>0.0406812</TD>
+ <TD>-0.249534</TD>
+ <TD>-0.381015</TD>
+ <TD>-0.102094</TD>
+ <TD>6</TD>
+ <TD>0</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.1-052254</TD>
+ <TD>83.81329418</TD>
+ <TD>-5.38172473</TD>
+ <TD>0.14462</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.64113E-13</TD>
+ <TD>1.62452E-13</TD>
+ <TD>1.65791E-13</TD>
+ <TD>1.6316E-14</TD>
+ <TD>1.43274E-14</TD>
+ <TD>1.83248E-14</TD>
+ <TD>52.0892</TD>
+ <TD>0.450876</TD>
+ <TD>0.436926</TD>
+ <TD>0.464947</TD>
+ <TD>0.137764</TD>
+ <TD>0.126999</TD>
+ <TD>0.148264</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.1-052318</TD>
+ <TD>83.81330006</TD>
+ <TD>-5.3885408</TD>
+ <TD>0.47766</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>3.49507E-15</TD>
+ <TD>2.3225E-15</TD>
+ <TD>4.65674E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.82159</TD>
+ <TD>0.854749</TD>
+ <TD>0.753011</TD>
+ <TD>0.937876</TD>
+ <TD>-0.0355204</TD>
+ <TD>-0.115613</TD>
+ <TD>0.0224368</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.2-052256</TD>
+ <TD>83.81360368</TD>
+ <TD>-5.38242218</TD>
+ <TD>0.1999</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.03202E-12</TD>
+ <TD>1.02837E-12</TD>
+ <TD>1.03571E-12</TD>
+ <TD>2.6702E-13</TD>
+ <TD>2.60158E-13</TD>
+ <TD>2.73951E-13</TD>
+ <TD>130.522</TD>
+ <TD>0.0704777</TD>
+ <TD>0.0644488</TD>
+ <TD>0.0764034</TD>
+ <TD>-0.0717052</TD>
+ <TD>-0.0779943</TD>
+ <TD>-0.0655273</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.3-052333</TD>
+ <TD>83.81407441</TD>
+ <TD>-5.39255272</TD>
+ <TD>0.14553</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>2.25803E-14</TD>
+ <TD>2.19797E-14</TD>
+ <TD>2.31869E-14</TD>
+ <TD>1.93736E-14</TD>
+ <TD>1.7427E-14</TD>
+ <TD>2.134E-14</TD>
+ <TD>20.1199</TD>
+ <TD>-0.137472</TD>
+ <TD>-0.170874</TD>
+ <TD>-0.103627</TD>
+ <TD>-0.149193</TD>
+ <TD>-0.192213</TD>
+ <TD>-0.105697</TD>
+ <TD>9</TD>
+ <TD>2</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.4-052345</TD>
+ <TD>83.81434295</TD>
+ <TD>-5.39590645</TD>
+ <TD>0.14712</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.51555E-14</TD>
+ <TD>5.41834E-14</TD>
+ <TD>5.61375E-14</TD>
+ <TD>9.9547E-15</TD>
+ <TD>8.51468E-15</TD>
+ <TD>1.14093E-14</TD>
+ <TD>42.4107</TD>
+ <TD>0.0862415</TD>
+ <TD>0.0712833</TD>
+ <TD>0.10104</TD>
+ <TD>-0.00267428</TD>
+ <TD>-0.0218673</TD>
+ <TD>0.0166436</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.4-052248</TD>
+ <TD>83.8145085</TD>
+ <TD>-5.38011504</TD>
+ <TD>0.14676</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.04415E-13</TD>
+ <TD>1.03206E-13</TD>
+ <TD>1.05635E-13</TD>
+ <TD>8.82286E-15</TD>
+ <TD>7.076E-15</TD>
+ <TD>1.05874E-14</TD>
+ <TD>41.8304</TD>
+ <TD>-0.0174547</TD>
+ <TD>-0.0354158</TD>
+ <TD>8.28379E-4</TD>
+ <TD>-0.0411823</TD>
+ <TD>-0.0614385</TD>
+ <TD>-0.0209821</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.4-052337</TD>
+ <TD>83.81455127</TD>
+ <TD>-5.39376129</TD>
+ <TD>0.45111</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.41203E-15</TD>
+ <TD>9.77813E-16</TD>
+ <TD>1.84263E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>4.3122</TD>
+ <TD>-0.0434585</TD>
+ <TD>-0.229319</TD>
+ <TD>0.140449</TD>
+ <TD>0.18419</TD>
+ <TD>0.00217075</TD>
+ <TD>0.367231</TD>
+ <TD>1</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.5-052246</TD>
+ <TD>83.81473478</TD>
+ <TD>-5.37948293</TD>
+ <TD>0.31051</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.67177E-14</TD>
+ <TD>1.5583E-14</TD>
+ <TD>1.78639E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>12.1993</TD>
+ <TD>0.937694</TD>
+ <TD>0.910339</TD>
+ <TD>0.963317</TD>
+ <TD>0.0114968</TD>
+ <TD>-0.00399962</TD>
+ <TD>0.0268677</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.6-052402</TD>
+ <TD>83.81504651</TD>
+ <TD>-5.40078793</TD>
+ <TD>0.15306</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.91504E-14</TD>
+ <TD>1.83643E-14</TD>
+ <TD>1.99445E-14</TD>
+ <TD>5.66629E-14</TD>
+ <TD>5.35161E-14</TD>
+ <TD>5.98415E-14</TD>
+ <TD>17.7872</TD>
+ <TD>-0.178473</TD>
+ <TD>-0.224961</TD>
+ <TD>-0.131402</TD>
+ <TD>-0.295806</TD>
+ <TD>-0.362798</TD>
+ <TD>-0.227692</TD>
+ <TD>5</TD>
+ <TD>9</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.6-052256</TD>
+ <TD>83.81514589</TD>
+ <TD>-5.3823026</TD>
+ <TD>0.1784</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>8.55289E-13</TD>
+ <TD>8.52034E-13</TD>
+ <TD>8.58577E-13</TD>
+ <TD>2.02006E-12</TD>
+ <TD>2.00158E-12</TD>
+ <TD>2.03873E-12</TD>
+ <TD>129.732</TD>
+ <TD>0.0612033</TD>
+ <TD>0.0551543</TD>
+ <TD>0.06729</TD>
+ <TD>-0.0245866</TD>
+ <TD>-0.0308778</TD>
+ <TD>-0.0182808</TD>
+ <TD>10</TD>
+ <TD>8</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.7-052339</TD>
+ <TD>83.815411</TD>
+ <TD>-5.3941811</TD>
+ <TD>0.39841</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.05992E-14</TD>
+ <TD>1.74398E-14</TD>
+ <TD>2.37906E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6.29874</TD>
+ <TD>0.607113</TD>
+ <TD>0.500276</TD>
+ <TD>0.707773</TD>
+ <TD>0.160863</TD>
+ <TD>0.106058</TD>
+ <TD>0.219275</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.7-052411</TD>
+ <TD>83.81562914</TD>
+ <TD>-5.403203640000001</TD>
+ <TD>0.642673</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.80835E-16</TD>
+ <TD>2.06299E-16</TD>
+ <TD>5.56111E-16</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.93135</TD>
+ <TD>-0.147377</TD>
+ <TD>-0.27926</TD>
+ <TD>-0.0136489</TD>
+ <TD>-0.32344</TD>
+ <TD>-0.508552</TD>
+ <TD>-0.129011</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.7-052338</TD>
+ <TD>83.8157219</TD>
+ <TD>-5.39390552</TD>
+ <TD>0.45063</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>3.18339E-14</TD>
+ <TD>2.77075E-14</TD>
+ <TD>3.60019E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>7.27452</TD>
+ <TD>0.822639</TD>
+ <TD>0.75431</TD>
+ <TD>0.88682</TD>
+ <TD>0.0525613</TD>
+ <TD>0.0151042</TD>
+ <TD>0.090596</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.7-052309</TD>
+ <TD>83.81574739</TD>
+ <TD>-5.38606832</TD>
+ <TD>0.40301</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>3.03573E-12</TD>
+ <TD>3.029E-12</TD>
+ <TD>3.04254E-12</TD>
+ <TD>1.87491E-12</TD>
+ <TD>1.85709E-12</TD>
+ <TD>1.89291E-12</TD>
+ <TD>202.738</TD>
+ <TD>0.274577</TD>
+ <TD>0.270827</TD>
+ <TD>0.27825</TD>
+ <TD>-0.0459597</TD>
+ <TD>-0.0495455</TD>
+ <TD>-0.0423645</TD>
+ <TD>8</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052305</TD>
+ <TD>83.81588895</TD>
+ <TD>-5.38485094</TD>
+ <TD>0.48598</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>9.31635E-15</TD>
+ <TD>8.2033E-15</TD>
+ <TD>1.04407E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>9.11467</TD>
+ <TD>-0.137899</TD>
+ <TD>-0.205363</TD>
+ <TD>-0.0699988</TD>
+ <TD>-0.283179</TD>
+ <TD>-0.370767</TD>
+ <TD>-0.191045</TD>
+ <TD>2</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052313</TD>
+ <TD>83.815963</TD>
+ <TD>-5.38726978</TD>
+ <TD>0.40057</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.77082E-12</TD>
+ <TD>2.76452E-12</TD>
+ <TD>2.77719E-12</TD>
+ <TD>1.01992E-12</TD>
+ <TD>1.00666E-12</TD>
+ <TD>1.0333E-12</TD>
+ <TD>197.573</TD>
+ <TD>0.259373</TD>
+ <TD>0.255483</TD>
+ <TD>0.263164</TD>
+ <TD>-0.04572</TD>
+ <TD>-0.0494406</TD>
+ <TD>-0.0419462</TD>
+ <TD>9</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052245</TD>
+ <TD>83.81598875</TD>
+ <TD>-5.37934237</TD>
+ <TD>0.15512</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.5406E-14</TD>
+ <TD>1.492E-14</TD>
+ <TD>1.5897E-14</TD>
+ <TD>3.40691E-15</TD>
+ <TD>2.32026E-15</TD>
+ <TD>4.49824E-15</TD>
+ <TD>21.9792</TD>
+ <TD>-0.0994224</TD>
+ <TD>-0.130616</TD>
+ <TD>-0.0679763</TD>
+ <TD>-0.14147</TD>
+ <TD>-0.181277</TD>
+ <TD>-0.1021</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052322</TD>
+ <TD>83.81610029</TD>
+ <TD>-5.38953689</TD>
+ <TD>0.43705</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.97845E-14</TD>
+ <TD>1.67432E-14</TD>
+ <TD>2.28564E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>5.33178</TD>
+ <TD>0.644325</TD>
+ <TD>0.523345</TD>
+ <TD>0.765435</TD>
+ <TD>-0.140958</TD>
+ <TD>-0.260161</TD>
+ <TD>-0.0220717</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052318</TD>
+ <TD>83.81611207</TD>
+ <TD>-5.38856486</TD>
+ <TD>0.44418</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.13066E-14</TD>
+ <TD>9.23675E-15</TD>
+ <TD>1.33974E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>5.95239</TD>
+ <TD>-0.0905449</TD>
+ <TD>-0.179506</TD>
+ <TD>5.26605E-4</TD>
+ <TD>-0.431631</TD>
+ <TD>-0.554358</TD>
+ <TD>-0.304264</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052301</TD>
+ <TD>83.81612461</TD>
+ <TD>-5.38382611</TD>
+ <TD>0.23917</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>8.45856E-15</TD>
+ <TD>7.64832E-15</TD>
+ <TD>9.277E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>7.90999</TD>
+ <TD>-0.0861684</TD>
+ <TD>-0.170009</TD>
+ <TD>-0.00161331</TD>
+ <TD>-0.158934</TD>
+ <TD>-0.263449</TD>
+ <TD>-0.0489787</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052233</TD>
+ <TD>83.81613303</TD>
+ <TD>-5.37585042</TD>
+ <TD>0.37078</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.7933E-15</TD>
+ <TD>1.4194E-15</TD>
+ <TD>2.16863E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>5.23268</TD>
+ <TD>-0.474765</TD>
+ <TD>-0.592407</TD>
+ <TD>-0.354312</TD>
+ <TD>0.260458</TD>
+ <TD>0.102338</TD>
+ <TD>0.417331</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052310</TD>
+ <TD>83.81619</TD>
+ <TD>-5.3863028</TD>
+ <TD>0.48816</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>4.64943E-13</TD>
+ <TD>4.5283E-13</TD>
+ <TD>4.77179E-13</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>37.321</TD>
+ <TD>0.248112</TD>
+ <TD>0.226014</TD>
+ <TD>0.27041</TD>
+ <TD>0.135802</TD>
+ <TD>0.117704</TD>
+ <TD>0.153639</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.9-052417</TD>
+ <TD>83.8162912</TD>
+ <TD>-5.40491845</TD>
+ <TD>0.6885</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.78186E-15</TD>
+ <TD>2.91713E-15</TD>
+ <TD>4.65E-15</TD>
+ <TD>4.3122</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>2</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.9-052349</TD>
+ <TD>83.81647584</TD>
+ <TD>-5.39713268</TD>
+ <TD>0.14102</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>3.87473E-13</TD>
+ <TD>3.85092E-13</TD>
+ <TD>3.89878E-13</TD>
+ <TD>1.89669E-13</TD>
+ <TD>1.83958E-13</TD>
+ <TD>1.95437E-13</TD>
+ <TD>73.5294</TD>
+ <TD>0.0642011</TD>
+ <TD>0.0629523</TD>
+ <TD>0.0654531</TD>
+ <TD>0.0222816</TD>
+ <TD>0.0111647</TD>
+ <TD>0.0333233</TD>
+ <TD>10</TD>
+ <TD>7</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052352</TD>
+ <TD>83.81675305</TD>
+ <TD>-5.39801365</TD>
+ <TD>0.14462</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.00513E-13</TD>
+ <TD>9.911E-14</TD>
+ <TD>1.0193E-13</TD>
+ <TD>1.48552E-14</TD>
+ <TD>1.31388E-14</TD>
+ <TD>1.65889E-14</TD>
+ <TD>35.6626</TD>
+ <TD>0.157734</TD>
+ <TD>0.135077</TD>
+ <TD>0.180105</TD>
+ <TD>0.0436772</TD>
+ <TD>0.0221774</TD>
+ <TD>0.0652125</TD>
+ <TD>10</TD>
+ <TD>1</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052253</TD>
+ <TD>83.81698406</TD>
+ <TD>-5.38164426</TD>
+ <TD>0.16235</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.26789E-14</TD>
+ <TD>3.18198E-14</TD>
+ <TD>3.35468E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>25.1492</TD>
+ <TD>0.865571</TD>
+ <TD>0.846684</TD>
+ <TD>0.883593</TD>
+ <TD>0.0654986</TD>
+ <TD>0.056393</TD>
+ <TD>0.0749912</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052306</TD>
+ <TD>83.81701311</TD>
+ <TD>-5.38522135</TD>
+ <TD>0.14238</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.76855E-13</TD>
+ <TD>1.75356E-13</TD>
+ <TD>1.7837E-13</TD>
+ <TD>5.32069E-14</TD>
+ <TD>4.98546E-14</TD>
+ <TD>5.65931E-14</TD>
+ <TD>68.6943</TD>
+ <TD>0.0638425</TD>
+ <TD>0.0529115</TD>
+ <TD>0.0748212</TD>
+ <TD>-0.0784673</TD>
+ <TD>-0.0903596</TD>
+ <TD>-0.0663197</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052325</TD>
+ <TD>83.8170161</TD>
+ <TD>-5.39040007</TD>
+ <TD>0.42036</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.00543E-14</TD>
+ <TD>9.06073E-15</TD>
+ <TD>1.10579E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>11.0945</TD>
+ <TD>-0.125453</TD>
+ <TD>-0.17706</TD>
+ <TD>-0.0731745</TD>
+ <TD>-0.344981</TD>
+ <TD>-0.416858</TD>
+ <TD>-0.272662</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052411</TD>
+ <TD>83.8170323</TD>
+ <TD>-5.4031178</TD>
+ <TD>0.18202</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>2.25929E-14</TD>
+ <TD>2.13907E-14</TD>
+ <TD>2.38072E-14</TD>
+ <TD>3.44264E-15</TD>
+ <TD>2.59187E-15</TD>
+ <TD>4.29976E-15</TD>
+ <TD>12.9669</TD>
+ <TD>-0.0641377</TD>
+ <TD>-0.121644</TD>
+ <TD>-0.00538426</TD>
+ <TD>-0.016818</TD>
+ <TD>-0.0841843</TD>
+ <TD>0.0495484</TD>
+ <TD>7</TD>
+ <TD>2</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052322</TD>
+ <TD>83.81705333</TD>
+ <TD>-5.3896635</TD>
+ <TD>0.1439</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>8.06604E-14</TD>
+ <TD>7.93614E-14</TD>
+ <TD>8.19725E-14</TD>
+ <TD>9.51118E-15</TD>
+ <TD>6.51756E-15</TD>
+ <TD>1.25222E-14</TD>
+ <TD>35.9128</TD>
+ <TD>0.575093</TD>
+ <TD>0.55627</TD>
+ <TD>0.594211</TD>
+ <TD>-0.0963508</TD>
+ <TD>-0.113819</TD>
+ <TD>-0.0786152</TD>
+ <TD>8</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.1-052313</TD>
+ <TD>83.81720052</TD>
+ <TD>-5.38708875</TD>
+ <TD>0.29045</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.17102E-14</TD>
+ <TD>1.06569E-14</TD>
+ <TD>1.27741E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6.71341</TD>
+ <TD>0.179113</TD>
+ <TD>0.0907505</TD>
+ <TD>0.272076</TD>
+ <TD>-0.316139</TD>
+ <TD>-0.42591</TD>
+ <TD>-0.203308</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.1-052309</TD>
+ <TD>83.8172558</TD>
+ <TD>-5.38598655</TD>
+ <TD>0.44726</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>3.83267E-15</TD>
+ <TD>2.89841E-15</TD>
+ <TD>4.77108E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.4279</TD>
+ <TD>-0.0114393</TD>
+ <TD>-0.200116</TD>
+ <TD>0.16813</TD>
+ <TD>-0.0802978</TD>
+ <TD>-0.310341</TD>
+ <TD>0.173881</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.1-052237</TD>
+ <TD>83.81744498</TD>
+ <TD>-5.37702105</TD>
+ <TD>0.16304</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.24777E-14</TD>
+ <TD>1.20505E-14</TD>
+ <TD>1.29091E-14</TD>
+ <TD>3.88118E-15</TD>
+ <TD>2.96665E-15</TD>
+ <TD>4.78877E-15</TD>
+ <TD>15.5503</TD>
+ <TD>0.0888785</TD>
+ <TD>0.0359265</TD>
+ <TD>0.141431</TD>
+ <TD>0.109917</TD>
+ <TD>0.0587091</TD>
+ <TD>0.16105</TD>
+ <TD>7</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.2-052318</TD>
+ <TD>83.81746865</TD>
+ <TD>-5.38854714</TD>
+ <TD>0.29102</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.7293E-14</TD>
+ <TD>1.62498E-14</TD>
+ <TD>1.83469E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>11.8731</TD>
+ <TD>-0.0821205</TD>
+ <TD>-0.134065</TD>
+ <TD>-0.0290845</TD>
+ <TD>-0.217927</TD>
+ <TD>-0.288334</TD>
+ <TD>-0.144648</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ <TD>4</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.2-052316</TD>
+ <TD>83.8178479</TD>
+ <TD>-5.38786385</TD>
+ <TD>0.15414</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>3.32569E-14</TD>
+ <TD>3.24069E-14</TD>
+ <TD>3.41155E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>16.9568</TD>
+ <TD>0.214185</TD>
+ <TD>0.171584</TD>
+ <TD>0.256628</TD>
+ <TD>-0.0273673</TD>
+ <TD>-0.0745624</TD>
+ <TD>0.0207458</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.3-052403</TD>
+ <TD>83.81822268</TD>
+ <TD>-5.40086482</TD>
+ <TD>0.14238</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.65119E-13</TD>
+ <TD>5.60431E-13</TD>
+ <TD>5.69854E-13</TD>
+ <TD>1.1893E-13</TD>
+ <TD>1.14403E-13</TD>
+ <TD>1.23504E-13</TD>
+ <TD>66.1461</TD>
+ <TD>0.120421</TD>
+ <TD>0.108076</TD>
+ <TD>0.132924</TD>
+ <TD>0.0565306</TD>
+ <TD>0.0445626</TD>
+ <TD>0.0685104</TD>
+ <TD>8</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.4-052329</TD>
+ <TD>83.81859564</TD>
+ <TD>-5.39142135</TD>
+ <TD>0.43656</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.33598E-14</TD>
+ <TD>1.16336E-14</TD>
+ <TD>1.51034E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>8.24052</TD>
+ <TD>-0.107666</TD>
+ <TD>-0.166067</TD>
+ <TD>-0.0482851</TD>
+ <TD>-0.560076</TD>
+ <TD>-0.642993</TD>
+ <TD>-0.475082</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.4-052331</TD>
+ <TD>83.81861877</TD>
+ <TD>-5.39200198</TD>
+ <TD>0.4145</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>4.70839E-15</TD>
+ <TD>3.72184E-15</TD>
+ <TD>5.70217E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.95451</TD>
+ <TD>0.10125</TD>
+ <TD>-0.0473853</TD>
+ <TD>0.247861</TD>
+ <TD>-0.213178</TD>
+ <TD>-0.403455</TD>
+ <TD>-0.00761378</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.4-052322</TD>
+ <TD>83.81863682</TD>
+ <TD>-5.38964395</TD>
+ <TD>0.16555</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>3.15953E-12</TD>
+ <TD>3.15334E-12</TD>
+ <TD>3.16578E-12</TD>
+ <TD>1.93706E-11</TD>
+ <TD>1.93136E-11</TD>
+ <TD>1.94281E-11</TD>
+ <TD>335.79</TD>
+ <TD>-0.0574404</TD>
+ <TD>-0.0603554</TD>
+ <TD>-0.054598</TD>
+ <TD>-0.179857</TD>
+ <TD>-0.183533</TD>
+ <TD>-0.176244</TD>
+ <TD>7</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.4-052256</TD>
+ <TD>83.81868061</TD>
+ <TD>-5.38231438</TD>
+ <TD>0.25375</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>9.13394E-15</TD>
+ <TD>8.46442E-15</TD>
+ <TD>9.81021E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>10.1085</TD>
+ <TD>0.532591</TD>
+ <TD>0.460216</TD>
+ <TD>0.603536</TD>
+ <TD>0.219955</TD>
+ <TD>0.183953</TD>
+ <TD>0.256889</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.4-052234</TD>
+ <TD>83.81869862</TD>
+ <TD>-5.37637281</TD>
+ <TD>0.16109</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.71057E-14</TD>
+ <TD>1.66378E-14</TD>
+ <TD>1.75782E-14</TD>
+ <TD>3.92169E-15</TD>
+ <TD>2.98105E-15</TD>
+ <TD>4.87032E-15</TD>
+ <TD>23.0625</TD>
+ <TD>-0.110707</TD>
+ <TD>-0.140501</TD>
+ <TD>-0.0809267</TD>
+ <TD>-0.146559</TD>
+ <TD>-0.184692</TD>
+ <TD>-0.107592</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.5-052405</TD>
+ <TD>83.81907688</TD>
+ <TD>-5.40160715</TD>
+ <TD>0.14862</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.17377E-14</TD>
+ <TD>6.00346E-14</TD>
+ <TD>6.34581E-14</TD>
+ <TD>2.21828E-14</TD>
+ <TD>2.01516E-14</TD>
+ <TD>2.42345E-14</TD>
+ <TD>20.473</TD>
+ <TD>-0.0114133</TD>
+ <TD>-0.0482004</TD>
+ <TD>0.0240581</TD>
+ <TD>-0.0682099</TD>
+ <TD>-0.110431</TD>
+ <TD>-0.0262589</TD>
+ <TD>9</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.6-052315</TD>
+ <TD>83.81916799</TD>
+ <TD>-5.38771941</TD>
+ <TD>0.2965</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.38905E-14</TD>
+ <TD>2.24716E-14</TD>
+ <TD>2.53237E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>11.2343</TD>
+ <TD>0.459388</TD>
+ <TD>0.394276</TD>
+ <TD>0.524993</TD>
+ <TD>-0.0552914</TD>
+ <TD>-0.12419</TD>
+ <TD>0.0178639</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.7-052231</TD>
+ <TD>83.81971948</TD>
+ <TD>-5.37529756</TD>
+ <TD>0.15804</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.06851E-14</TD>
+ <TD>4.98874E-14</TD>
+ <TD>5.14908E-14</TD>
+ <TD>5.06829E-15</TD>
+ <TD>4.00493E-15</TD>
+ <TD>6.13022E-15</TD>
+ <TD>44.5636</TD>
+ <TD>0.0310784</TD>
+ <TD>0.0149852</TD>
+ <TD>0.0471353</TD>
+ <TD>-0.0098311</TD>
+ <TD>-0.0287303</TD>
+ <TD>0.00904038</TD>
+ <TD>10</TD>
+ <TD>1</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.7-052316</TD>
+ <TD>83.81979918</TD>
+ <TD>-5.38783323</TD>
+ <TD>0.15457</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>5.41387E-14</TD>
+ <TD>5.31441E-14</TD>
+ <TD>5.51433E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>42.0005</TD>
+ <TD>0.34389</TD>
+ <TD>0.324476</TD>
+ <TD>0.363242</TD>
+ <TD>0.137474</TD>
+ <TD>0.120154</TD>
+ <TD>0.155026</TD>
+ <TD>10</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.7-052327</TD>
+ <TD>83.81985651</TD>
+ <TD>-5.39106185</TD>
+ <TD>0.15396</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>3.1808E-14</TD>
+ <TD>3.10464E-14</TD>
+ <TD>3.25773E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>19.3821</TD>
+ <TD>-0.173608</TD>
+ <TD>-0.219488</TD>
+ <TD>-0.128308</TD>
+ <TD>0.353016</TD>
+ <TD>0.30927</TD>
+ <TD>0.397048</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.7-052404</TD>
+ <TD>83.81985811</TD>
+ <TD>-5.40112096</TD>
+ <TD>0.14189</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>6.14592E-13</TD>
+ <TD>6.09573E-13</TD>
+ <TD>6.19661E-13</TD>
+ <TD>1.20933E-13</TD>
+ <TD>1.16357E-13</TD>
+ <TD>1.25557E-13</TD>
+ <TD>62.3506</TD>
+ <TD>0.076646</TD>
+ <TD>0.0642906</TD>
+ <TD>0.0891912</TD>
+ <TD>-0.0215484</TD>
+ <TD>-0.0345894</TD>
+ <TD>-0.0083578</TD>
+ <TD>10</TD>
+ <TD>1</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.9-052248</TD>
+ <TD>83.82067804</TD>
+ <TD>-5.38003602</TD>
+ <TD>0.26011</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.40385E-15</TD>
+ <TD>3.02903E-15</TD>
+ <TD>3.78245E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6.5724</TD>
+ <TD>-0.209941</TD>
+ <TD>-0.311983</TD>
+ <TD>-0.106149</TD>
+ <TD>0.20857</TD>
+ <TD>0.0992621</TD>
+ <TD>0.315503</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.9-052300</TD>
+ <TD>83.82072056</TD>
+ <TD>-5.38354443</TD>
+ <TD>0.1809</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>4.38438E-15</TD>
+ <TD>3.98639E-15</TD>
+ <TD>4.7864E-15</TD>
+ <TD>2.73814E-15</TD>
+ <TD>1.91129E-15</TD>
+ <TD>3.55782E-15</TD>
+ <TD>8.92446</TD>
+ <TD>0.0812748</TD>
+ <TD>-0.0200644</TD>
+ <TD>0.181062</TD>
+ <TD>0.304217</TD>
+ <TD>0.24567</TD>
+ <TD>0.364153</TD>
+ <TD>6</TD>
+ <TD>2</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.9-052336</TD>
+ <TD>83.82074477</TD>
+ <TD>-5.39357858</TD>
+ <TD>0.1656</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.65737E-15</TD>
+ <TD>6.25524E-15</TD>
+ <TD>7.06356E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>9.30035</TD>
+ <TD>0.379074</TD>
+ <TD>0.28605</TD>
+ <TD>0.470226</TD>
+ <TD>0.118246</TD>
+ <TD>0.0287847</TD>
+ <TD>0.205374</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.0-052232</TD>
+ <TD>83.82085444</TD>
+ <TD>-5.37579242</TD>
+ <TD>0.14172</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>5.12055E-13</TD>
+ <TD>5.09571E-13</TD>
+ <TD>5.14564E-13</TD>
+ <TD>1.51166E-13</TD>
+ <TD>1.46086E-13</TD>
+ <TD>1.56297E-13</TD>
+ <TD>104.461</TD>
+ <TD>0.0419094</TD>
+ <TD>0.0347495</TD>
+ <TD>0.0490269</TD>
+ <TD>-0.0550702</TD>
+ <TD>-0.0631752</TD>
+ <TD>-0.0471308</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.0-052339</TD>
+ <TD>83.82106838</TD>
+ <TD>-5.39432294</TD>
+ <TD>0.14281</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.18657E-14</TD>
+ <TD>6.09481E-14</TD>
+ <TD>6.27926E-14</TD>
+ <TD>1.1665E-13</TD>
+ <TD>1.1214E-13</TD>
+ <TD>1.21206E-13</TD>
+ <TD>32.3985</TD>
+ <TD>-0.0297006</TD>
+ <TD>-0.0531671</TD>
+ <TD>-0.00677787</TD>
+ <TD>-0.0486834</TD>
+ <TD>-0.0749776</TD>
+ <TD>-0.0224945</TD>
+ <TD>10</TD>
+ <TD>10</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.0-052333</TD>
+ <TD>83.82109826</TD>
+ <TD>-5.39273815</TD>
+ <TD>0.1631</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.02987E-12</TD>
+ <TD>1.02531E-12</TD>
+ <TD>1.03447E-12</TD>
+ <TD>8.75803E-14</TD>
+ <TD>8.36184E-14</TD>
+ <TD>9.15822E-14</TD>
+ <TD>127.499</TD>
+ <TD>0.630809</TD>
+ <TD>0.625237</TD>
+ <TD>0.636334</TD>
+ <TD>0.164965</TD>
+ <TD>0.161863</TD>
+ <TD>0.168062</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.1-052249</TD>
+ <TD>83.82131869</TD>
+ <TD>-5.38053261</TD>
+ <TD>0.19466</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>4.86951E-15</TD>
+ <TD>4.52284E-15</TD>
+ <TD>5.21969E-15</TD>
+ <TD>3.98751E-15</TD>
+ <TD>3.07147E-15</TD>
+ <TD>4.89601E-15</TD>
+ <TD>12.7202</TD>
+ <TD>-0.143314</TD>
+ <TD>-0.192783</TD>
+ <TD>-0.0933213</TD>
+ <TD>-0.259469</TD>
+ <TD>-0.324615</TD>
+ <TD>-0.193064</TD>
+ <TD>7</TD>
+ <TD>1</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.2-052316</TD>
+ <TD>83.82189417</TD>
+ <TD>-5.38789001</TD>
+ <TD>0.14245</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>5.88682E-14</TD>
+ <TD>5.81311E-14</TD>
+ <TD>5.96127E-14</TD>
+ <TD>8.88455E-14</TD>
+ <TD>8.48444E-14</TD>
+ <TD>9.2887E-14</TD>
+ <TD>38.8741</TD>
+ <TD>-0.106269</TD>
+ <TD>-0.113609</TD>
+ <TD>-0.0990529</TD>
+ <TD>-0.77797</TD>
+ <TD>-0.792073</TD>
+ <TD>-0.76355</TD>
+ <TD>0</TD>
+ <TD>0</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.2-052423</TD>
+ <TD>83.82196154</TD>
+ <TD>-5.40666165</TD>
+ <TD>0.21976</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>2.62389E-15</TD>
+ <TD>2.3843E-15</TD>
+ <TD>2.8659E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>7.6888</TD>
+ <TD>-0.19058</TD>
+ <TD>-0.261001</TD>
+ <TD>-0.121977</TD>
+ <TD>-0.414758</TD>
+ <TD>-0.517638</TD>
+ <TD>-0.308909</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.3-052235</TD>
+ <TD>83.82228078</TD>
+ <TD>-5.37653942</TD>
+ <TD>0.20984</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.84579E-15</TD>
+ <TD>5.32199E-15</TD>
+ <TD>6.37489E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>7.45895</TD>
+ <TD>0.699469</TD>
+ <TD>0.607403</TD>
+ <TD>0.789528</TD>
+ <TD>0.114261</TD>
+ <TD>0.0656462</TD>
+ <TD>0.162743</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.3-052245</TD>
+ <TD>83.82234198</TD>
+ <TD>-5.37931217</TD>
+ <TD>0.22014</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.80224E-15</TD>
+ <TD>6.2389E-15</TD>
+ <TD>7.37126E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6.6703</TD>
+ <TD>0.396609</TD>
+ <TD>0.282738</TD>
+ <TD>0.50787</TD>
+ <TD>0.268918</TD>
+ <TD>0.209931</TD>
+ <TD>0.329087</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.3-052304</TD>
+ <TD>83.82237467</TD>
+ <TD>-5.38461745</TD>
+ <TD>0.42463</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>9.77684E-15</TD>
+ <TD>8.70144E-15</TD>
+ <TD>1.08631E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>9.49126</TD>
+ <TD>-0.0447789</TD>
+ <TD>-0.143927</TD>
+ <TD>0.0521108</TD>
+ <TD>0.394111</TD>
+ <TD>0.311405</TD>
+ <TD>0.47619</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.3-052400</TD>
+ <TD>83.8224061</TD>
+ <TD>-5.40002211</TD>
+ <TD>0.18139</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.85293E-14</TD>
+ <TD>1.74155E-14</TD>
+ <TD>1.96543E-14</TD>
+ <TD>3.45141E-15</TD>
+ <TD>2.58232E-15</TD>
+ <TD>4.31257E-15</TD>
+ <TD>9.24279</TD>
+ <TD>0.755474</TD>
+ <TD>0.695403</TD>
+ <TD>0.810355</TD>
+ <TD>0.0939339</TD>
+ <TD>0.0661719</TD>
+ <TD>0.1257</TD>
+ <TD>8</TD>
+ <TD>1</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.3-052413</TD>
+ <TD>83.82244801</TD>
+ <TD>-5.40381331</TD>
+ <TD>0.19226</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>4.69414E-15</TD>
+ <TD>4.36344E-15</TD>
+ <TD>5.02817E-15</TD>
+ <TD>2.84905E-15</TD>
+ <TD>2.06367E-15</TD>
+ <TD>3.63713E-15</TD>
+ <TD>7.67701</TD>
+ <TD>-0.186065</TD>
+ <TD>-0.262651</TD>
+ <TD>-0.104858</TD>
+ <TD>-0.0730942</TD>
+ <TD>-0.173102</TD>
+ <TD>0.029691</TD>
+ <TD>2</TD>
+ <TD>1</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.4-052320</TD>
+ <TD>83.82275909</TD>
+ <TD>-5.38913778</TD>
+ <TD>0.14305</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.19418E-14</TD>
+ <TD>6.10112E-14</TD>
+ <TD>6.28819E-14</TD>
+ <TD>9.46104E-14</TD>
+ <TD>9.05153E-14</TD>
+ <TD>9.87468E-14</TD>
+ <TD>33.9473</TD>
+ <TD>-0.120336</TD>
+ <TD>-0.139946</TD>
+ <TD>-0.100275</TD>
+ <TD>-0.173029</TD>
+ <TD>-0.198721</TD>
+ <TD>-0.147012</TD>
+ <TD>8</TD>
+ <TD>2</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.4-052251</TD>
+ <TD>83.82278772</TD>
+ <TD>-5.38085618</TD>
+ <TD>0.26154</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.59443E-14</TD>
+ <TD>1.48174E-14</TD>
+ <TD>1.70825E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>10.3217</TD>
+ <TD>0.967824</TD>
+ <TD>0.948424</TD>
+ <TD>0.983472</TD>
+ <TD>-0.0020122</TD>
+ <TD>-0.0129</TD>
+ <TD>0.00778932</TD>
+ <TD>10</TD>
+ <TD>-32768</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.4-052417</TD>
+ <TD>83.8228207</TD>
+ <TD>-5.40476643</TD>
+ <TD>0.17747</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.73012E-15</TD>
+ <TD>6.40928E-15</TD>
+ <TD>7.0542E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>12.4071</TD>
+ <TD>-0.134308</TD>
+ <TD>-0.178341</TD>
+ <TD>-0.0910805</TD>
+ <TD>-0.39546</TD>
+ <TD>-0.458828</TD>
+ <TD>-0.332525</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.5-052256</TD>
+ <TD>83.82316819</TD>
+ <TD>-5.38239764</TD>
+ <TD>0.15331</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.83102E-14</TD>
+ <TD>2.76496E-14</TD>
+ <TD>2.89775E-14</TD>
+ <TD>7.30177E-15</TD>
+ <TD>6.08289E-15</TD>
+ <TD>8.53297E-15</TD>
+ <TD>22.5382</TD>
+ <TD>0.210574</TD>
+ <TD>0.174935</TD>
+ <TD>0.245433</TD>
+ <TD>0.0311087</TD>
+ <TD>-0.00287664</TD>
+ <TD>0.0657481</TD>
+ <TD>10</TD>
+ <TD>1</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.7-052230</TD>
+ <TD>83.82394082</TD>
+ <TD>-5.37517547</TD>
+ <TD>0.492273</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>2.57352E-15</TD>
+ <TD>2.04402E-15</TD>
+ <TD>3.10329E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>4.97905</TD>
+ <TD>0.435106</TD>
+ <TD>0.290564</TD>
+ <TD>0.573409</TD>
+ <TD>0.166767</TD>
+ <TD>0.0640562</TD>
+ <TD>0.265173</TD>
+ <TD>2</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.7-052342</TD>
+ <TD>83.82403421</TD>
+ <TD>-5.39507242</TD>
+ <TD>0.2641</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.22294E-14</TD>
+ <TD>2.09875E-14</TD>
+ <TD>2.34839E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>14.6498</TD>
+ <TD>0.393985</TD>
+ <TD>0.336088</TD>
+ <TD>0.450833</TD>
+ <TD>0.236858</TD>
+ <TD>0.205778</TD>
+ <TD>0.268504</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.7-052344</TD>
+ <TD>83.82408397</TD>
+ <TD>-5.39556838</TD>
+ <TD>0.15493</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>4.40876E-14</TD>
+ <TD>4.30497E-14</TD>
+ <TD>4.5136E-14</TD>
+ <TD>6.16894E-15</TD>
+ <TD>5.06292E-15</TD>
+ <TD>7.28614E-15</TD>
+ <TD>24.0684</TD>
+ <TD>-0.0935179</TD>
+ <TD>-0.125494</TD>
+ <TD>-0.0616643</TD>
+ <TD>0.012234</TD>
+ <TD>-0.0249415</TD>
+ <TD>0.0495115</TD>
+ <TD>9</TD>
+ <TD>1</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.8-052315</TD>
+ <TD>83.82422327</TD>
+ <TD>-5.38761097</TD>
+ <TD>0.14969</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.14931E-14</TD>
+ <TD>2.09499E-14</TD>
+ <TD>2.20418E-14</TD>
+ <TD>5.5013E-15</TD>
+ <TD>4.37611E-15</TD>
+ <TD>6.62636E-15</TD>
+ <TD>21.7772</TD>
+ <TD>-0.0485423</TD>
+ <TD>-0.0781495</TD>
+ <TD>-0.0186874</TD>
+ <TD>-0.238534</TD>
+ <TD>-0.27681</TD>
+ <TD>-0.200386</TD>
+ <TD>9</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.8-052302</TD>
+ <TD>83.82443905</TD>
+ <TD>-5.38414023</TD>
+ <TD>0.15408</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>2.47255E-14</TD>
+ <TD>2.41076E-14</TD>
+ <TD>2.53496E-14</TD>
+ <TD>3.99183E-15</TD>
+ <TD>3.06073E-15</TD>
+ <TD>4.9291E-15</TD>
+ <TD>19.745</TD>
+ <TD>0.0294182</TD>
+ <TD>-0.0120983</TD>
+ <TD>0.0706036</TD>
+ <TD>0.152762</TD>
+ <TD>0.111578</TD>
+ <TD>0.19379</TD>
+ <TD>8</TD>
+ <TD>0</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.9-052245</TD>
+ <TD>83.82479363</TD>
+ <TD>-5.37929955</TD>
+ <TD>0.40131</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.34246E-12</TD>
+ <TD>2.33673E-12</TD>
+ <TD>2.34825E-12</TD>
+ <TD>7.72945E-13</TD>
+ <TD>7.61515E-13</TD>
+ <TD>7.8449E-13</TD>
+ <TD>192.113</TD>
+ <TD>0.176657</TD>
+ <TD>0.172692</TD>
+ <TD>0.180645</TD>
+ <TD>-0.017412</TD>
+ <TD>-0.021351</TD>
+ <TD>-0.0134155</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.9-052335</TD>
+ <TD>83.82483373</TD>
+ <TD>-5.39311699</TD>
+ <TD>0.159</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.0092E-15</TD>
+ <TD>4.57792E-15</TD>
+ <TD>5.44484E-15</TD>
+ <TD>6.66509E-15</TD>
+ <TD>5.48228E-15</TD>
+ <TD>7.85984E-15</TD>
+ <TD>7.34797</TD>
+ <TD>-0.194774</TD>
+ <TD>-0.261407</TD>
+ <TD>-0.128891</TD>
+ <TD>-0.309379</TD>
+ <TD>-0.418885</TD>
+ <TD>-0.197315</TD>
+ <TD>0</TD>
+ <TD>0</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.9-052240</TD>
+ <TD>83.82493994</TD>
+ <TD>-5.37799385</TD>
+ <TD>0.46551</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>4.98307E-15</TD>
+ <TD>4.215E-15</TD>
+ <TD>5.75889E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6.08887</TD>
+ <TD>0.0498089</TD>
+ <TD>-0.0437402</TD>
+ <TD>0.140453</TD>
+ <TD>-0.46677</TD>
+ <TD>-0.579925</TD>
+ <TD>-0.351098</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.0-052402</TD>
+ <TD>83.82516072</TD>
+ <TD>-5.40081854</TD>
+ <TD>0.15291</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>4.64651E-14</TD>
+ <TD>4.5185E-14</TD>
+ <TD>4.77582E-14</TD>
+ <TD>7.56507E-15</TD>
+ <TD>6.29819E-15</TD>
+ <TD>8.84474E-15</TD>
+ <TD>17.849</TD>
+ <TD>0.336557</TD>
+ <TD>0.286851</TD>
+ <TD>0.385379</TD>
+ <TD>0.252672</TD>
+ <TD>0.224712</TD>
+ <TD>0.280702</TD>
+ <TD>9</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.0-052400</TD>
+ <TD>83.82528688</TD>
+ <TD>-5.40027107</TD>
+ <TD>0.14991</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>4.04349E-14</TD>
+ <TD>3.94916E-14</TD>
+ <TD>4.13877E-14</TD>
+ <TD>1.52375E-14</TD>
+ <TD>1.35145E-14</TD>
+ <TD>1.6978E-14</TD>
+ <TD>29.5094</TD>
+ <TD>-0.0313176</TD>
+ <TD>-0.0572702</TD>
+ <TD>-0.00540553</TD>
+ <TD>-0.028688</TD>
+ <TD>-0.057877</TD>
+ <TD>4.73572E-4</TD>
+ <TD>9</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.2-052335</TD>
+ <TD>83.82583666</TD>
+ <TD>-5.39324991</TD>
+ <TD>0.14673</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.27032E-14</TD>
+ <TD>6.15475E-14</TD>
+ <TD>6.38706E-14</TD>
+ <TD>1.45277E-14</TD>
+ <TD>1.28904E-14</TD>
+ <TD>1.61815E-14</TD>
+ <TD>40.8634</TD>
+ <TD>0.339068</TD>
+ <TD>0.319449</TD>
+ <TD>0.358484</TD>
+ <TD>0.0682079</TD>
+ <TD>0.0523278</TD>
+ <TD>0.0839731</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.2-052315</TD>
+ <TD>83.82596286</TD>
+ <TD>-5.38760267</TD>
+ <TD>0.34924</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>2.1647E-15</TD>
+ <TD>1.51151E-15</TD>
+ <TD>2.81364E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.55219</TD>
+ <TD>-0.0952553</TD>
+ <TD>-0.219541</TD>
+ <TD>0.0294111</TD>
+ <TD>-0.273004</TD>
+ <TD>-0.45569</TD>
+ <TD>-0.066292</TD>
+ <TD>2</TD>
+ <TD>-32768</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.3-052241</TD>
+ <TD>83.82636223</TD>
+ <TD>-5.37814958</TD>
+ <TD>0.52516</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>4.78337E-15</TD>
+ <TD>4.06288E-15</TD>
+ <TD>5.51113E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6.91727</TD>
+ <TD>-0.01251</TD>
+ <TD>-0.0998448</TD>
+ <TD>0.0765684</TD>
+ <TD>-0.32761</TD>
+ <TD>-0.437286</TD>
+ <TD>-0.213264</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.3-052404</TD>
+ <TD>83.82637823</TD>
+ <TD>-5.40130088</TD>
+ <TD>0.15454</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.50312E-14</TD>
+ <TD>1.4616E-14</TD>
+ <TD>1.54506E-14</TD>
+ <TD>9.74068E-15</TD>
+ <TD>8.39717E-15</TD>
+ <TD>1.10978E-14</TD>
+ <TD>18.2882</TD>
+ <TD>-0.0170644</TD>
+ <TD>-0.0451244</TD>
+ <TD>0.0113308</TD>
+ <TD>-0.496462</TD>
+ <TD>-0.534808</TD>
+ <TD>-0.457924</TD>
+ <TD>10</TD>
+ <TD>2</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.3-052237</TD>
+ <TD>83.82655004</TD>
+ <TD>-5.37707075</TD>
+ <TD>0.4015</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.51757E-12</TD>
+ <TD>1.51311E-12</TD>
+ <TD>1.52209E-12</TD>
+ <TD>4.8168E-13</TD>
+ <TD>4.72606E-13</TD>
+ <TD>4.90845E-13</TD>
+ <TD>156.029</TD>
+ <TD>0.0817165</TD>
+ <TD>0.0766781</TD>
+ <TD>0.0867794</TD>
+ <TD>-0.0223465</TD>
+ <TD>-0.02765</TD>
+ <TD>-0.0171189</TD>
+ <TD>10</TD>
+ <TD>9</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.4-052406</TD>
+ <TD>83.82694247</TD>
+ <TD>-5.40191265</TD>
+ <TD>0.16124</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.37515E-14</TD>
+ <TD>1.33676E-14</TD>
+ <TD>1.41392E-14</TD>
+ <TD>2.62695E-15</TD>
+ <TD>1.92102E-15</TD>
+ <TD>3.45326E-15</TD>
+ <TD>20.2619</TD>
+ <TD>-0.147293</TD>
+ <TD>-0.177667</TD>
+ <TD>-0.116693</TD>
+ <TD>-0.254688</TD>
+ <TD>-0.297129</TD>
+ <TD>-0.212164</TD>
+ <TD>9</TD>
+ <TD>2</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.5-052329</TD>
+ <TD>83.82710603</TD>
+ <TD>-5.39139544</TD>
+ <TD>0.29924</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.55482E-15</TD>
+ <TD>3.07533E-15</TD>
+ <TD>4.03916E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>5.19601</TD>
+ <TD>0.0224992</TD>
+ <TD>-0.0885241</TD>
+ <TD>0.133507</TD>
+ <TD>0.0140313</TD>
+ <TD>-0.100449</TD>
+ <TD>0.13251</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.6-052313</TD>
+ <TD>83.82775602</TD>
+ <TD>-5.3871475</TD>
+ <TD>0.1553</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.06073E-14</TD>
+ <TD>4.95229E-14</TD>
+ <TD>5.17026E-14</TD>
+ <TD>2.48157E-15</TD>
+ <TD>1.74615E-15</TD>
+ <TD>3.21853E-15</TD>
+ <TD>20.3047</TD>
+ <TD>0.711247</TD>
+ <TD>0.680913</TD>
+ <TD>0.740575</TD>
+ <TD>0.0977837</TD>
+ <TD>0.0822936</TD>
+ <TD>0.113861</TD>
+ <TD>8</TD>
+ <TD>1</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.7-052256</TD>
+ <TD>83.82792335</TD>
+ <TD>-5.38241003</TD>
+ <TD>0.14563</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>8.38129E-14</TD>
+ <TD>8.2714E-14</TD>
+ <TD>8.49229E-14</TD>
+ <TD>2.00977E-14</TD>
+ <TD>1.81923E-14</TD>
+ <TD>2.20222E-14</TD>
+ <TD>40.7387</TD>
+ <TD>0.0572374</TD>
+ <TD>0.03632</TD>
+ <TD>0.0779274</TD>
+ <TD>0.156319</TD>
+ <TD>0.136481</TD>
+ <TD>0.175857</TD>
+ <TD>10</TD>
+ <TD>6</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.8-052306</TD>
+ <TD>83.8285511</TD>
+ <TD>-5.38520688</TD>
+ <TD>0.38307</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.13434E-15</TD>
+ <TD>2.6248E-15</TD>
+ <TD>3.64903E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>4.10098</TD>
+ <TD>0.517024</TD>
+ <TD>0.387492</TD>
+ <TD>0.647882</TD>
+ <TD>0.136221</TD>
+ <TD>0.0452547</TD>
+ <TD>0.223087</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ <TD>3</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.8-052328</TD>
+ <TD>83.82863504</TD>
+ <TD>-5.39130935</TD>
+ <TD>0.18426</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>7.80936E-15</TD>
+ <TD>7.34268E-15</TD>
+ <TD>8.28074E-15</TD>
+ <TD>3.41606E-15</TD>
+ <TD>2.54272E-15</TD>
+ <TD>4.2936E-15</TD>
+ <TD>13.5089</TD>
+ <TD>0.148336</TD>
+ <TD>0.0862114</TD>
+ <TD>0.209109</TD>
+ <TD>0.116938</TD>
+ <TD>0.0606527</TD>
+ <TD>0.17337</TD>
+ <TD>8</TD>
+ <TD>0</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.8-052417</TD>
+ <TD>83.82870493</TD>
+ <TD>-5.40479945</TD>
+ <TD>0.2054</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>2.02885E-15</TD>
+ <TD>1.8429E-15</TD>
+ <TD>2.21669E-15</TD>
+ <TD>2.54071E-15</TD>
+ <TD>1.81143E-15</TD>
+ <TD>3.27084E-15</TD>
+ <TD>7.47107</TD>
+ <TD>-0.111318</TD>
+ <TD>-0.206769</TD>
+ <TD>-0.0157024</TD>
+ <TD>-0.105823</TD>
+ <TD>-0.217557</TD>
+ <TD>0.0062841</TD>
+ <TD>7</TD>
+ <TD>1</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.9-052321</TD>
+ <TD>83.82900851</TD>
+ <TD>-5.38938879</TD>
+ <TD>0.18377</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.29657E-15</TD>
+ <TD>5.91494E-15</TD>
+ <TD>6.68206E-15</TD>
+ <TD>3.93679E-15</TD>
+ <TD>3.03809E-15</TD>
+ <TD>4.84281E-15</TD>
+ <TD>9.75966</TD>
+ <TD>-0.197391</TD>
+ <TD>-0.257914</TD>
+ <TD>-0.136809</TD>
+ <TD>-0.0810207</TD>
+ <TD>-0.173516</TD>
+ <TD>0.0124436</TD>
+ <TD>8</TD>
+ <TD>2</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.0-052349</TD>
+ <TD>83.82943179</TD>
+ <TD>-5.39707745</TD>
+ <TD>0.18362</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.26527E-14</TD>
+ <TD>1.19883E-14</TD>
+ <TD>1.33238E-14</TD>
+ <TD>2.50362E-15</TD>
+ <TD>1.77341E-15</TD>
+ <TD>3.23775E-15</TD>
+ <TD>9.53704</TD>
+ <TD>0.525423</TD>
+ <TD>0.46124</TD>
+ <TD>0.588078</TD>
+ <TD>0.0552625</TD>
+ <TD>0.0168023</TD>
+ <TD>0.0953571</TD>
+ <TD>3</TD>
+ <TD>0</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.0-052307</TD>
+ <TD>83.82947555</TD>
+ <TD>-5.38538553</TD>
+ <TD>0.60007</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.06568E-15</TD>
+ <TD>2.35388E-15</TD>
+ <TD>3.77334E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.37258</TD>
+ <TD>0.551788</TD>
+ <TD>0.364172</TD>
+ <TD>0.730936</TD>
+ <TD>0.0525947</TD>
+ <TD>-0.0788357</TD>
+ <TD>0.180734</TD>
+ <TD>1</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.1-052326</TD>
+ <TD>83.82965729</TD>
+ <TD>-5.39079219</TD>
+ <TD>0.149</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>4.70476E-14</TD>
+ <TD>4.6041E-14</TD>
+ <TD>4.80644E-14</TD>
+ <TD>3.13813E-14</TD>
+ <TD>2.90203E-14</TD>
+ <TD>3.37661E-14</TD>
+ <TD>29.1204</TD>
+ <TD>-0.0186874</TD>
+ <TD>-0.0455405</TD>
+ <TD>0.00832042</TD>
+ <TD>0.0217701</TD>
+ <TD>-0.00797979</TD>
+ <TD>0.0513939</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.2-052250</TD>
+ <TD>83.83003508</TD>
+ <TD>-5.38069248</TD>
+ <TD>0.14563</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>7.71165E-14</TD>
+ <TD>7.6122E-14</TD>
+ <TD>7.8121E-14</TD>
+ <TD>2.18413E-14</TD>
+ <TD>1.98589E-14</TD>
+ <TD>2.38437E-14</TD>
+ <TD>35.1845</TD>
+ <TD>0.0103539</TD>
+ <TD>-0.0123992</TD>
+ <TD>0.033453</TD>
+ <TD>0.0622218</TD>
+ <TD>0.03835</TD>
+ <TD>0.0862733</TD>
+ <TD>8</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.3-052306</TD>
+ <TD>83.83073658</TD>
+ <TD>-5.38508642</TD>
+ <TD>0.20406</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.86105E-15</TD>
+ <TD>3.52179E-15</TD>
+ <TD>4.20375E-15</TD>
+ <TD>1.51947E-14</TD>
+ <TD>1.35327E-14</TD>
+ <TD>1.68735E-14</TD>
+ <TD>9.03109</TD>
+ <TD>0.70885</TD>
+ <TD>0.64733</TD>
+ <TD>0.762836</TD>
+ <TD>0.118635</TD>
+ <TD>0.0899835</TD>
+ <TD>0.149562</TD>
+ <TD>8</TD>
+ <TD>2</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.6-052357</TD>
+ <TD>83.83170407</TD>
+ <TD>-5.3992085</TD>
+ <TD>0.14599</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.65477E-14</TD>
+ <TD>5.57404E-14</TD>
+ <TD>5.73631E-14</TD>
+ <TD>1.58911E-14</TD>
+ <TD>1.41853E-14</TD>
+ <TD>1.76143E-14</TD>
+ <TD>33.2056</TD>
+ <TD>-0.0563964</TD>
+ <TD>-0.0777684</TD>
+ <TD>-0.0345916</TD>
+ <TD>-0.0881097</TD>
+ <TD>-0.114265</TD>
+ <TD>-0.0616321</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.6-052303</TD>
+ <TD>83.83180325</TD>
+ <TD>-5.38429503</TD>
+ <TD>0.28673</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.38795E-14</TD>
+ <TD>3.25298E-14</TD>
+ <TD>3.52428E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>24.1923</TD>
+ <TD>0.521923</TD>
+ <TD>0.490019</TD>
+ <TD>0.552917</TD>
+ <TD>0.168157</TD>
+ <TD>0.148041</TD>
+ <TD>0.187617</TD>
+ <TD>10</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053520.1-052308</TD>
+ <TD>83.83405767</TD>
+ <TD>-5.38565134</TD>
+ <TD>0.17176</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.6732E-14</TD>
+ <TD>1.60671E-14</TD>
+ <TD>1.74036E-14</TD>
+ <TD>8.91914E-15</TD>
+ <TD>7.62577E-15</TD>
+ <TD>1.02256E-14</TD>
+ <TD>16.7378</TD>
+ <TD>0.704872</TD>
+ <TD>0.667655</TD>
+ <TD>0.74077</TD>
+ <TD>0.0802904</TD>
+ <TD>0.0564153</TD>
+ <TD>0.103995</TD>
+ <TD>9</TD>
+ <TD>8</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053520.4-052329</TD>
+ <TD>83.83524928</TD>
+ <TD>-5.39157915</TD>
+ <TD>0.14495</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.48294E-13</TD>
+ <TD>1.46302E-13</TD>
+ <TD>1.50305E-13</TD>
+ <TD>6.19981E-14</TD>
+ <TD>5.87156E-14</TD>
+ <TD>6.53138E-14</TD>
+ <TD>37.6376</TD>
+ <TD>-0.0342289</TD>
+ <TD>-0.0543452</TD>
+ <TD>-0.0144118</TD>
+ <TD>-0.0400774</TD>
+ <TD>-0.0630867</TD>
+ <TD>-0.0171071</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053520.6-052353</TD>
+ <TD>83.83613982</TD>
+ <TD>-5.39807062</TD>
+ <TD>0.14505</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.22974E-13</TD>
+ <TD>1.21659E-13</TD>
+ <TD>1.24301E-13</TD>
+ <TD>3.53667E-14</TD>
+ <TD>3.28387E-14</TD>
+ <TD>3.79203E-14</TD>
+ <TD>51.6767</TD>
+ <TD>-0.0736723</TD>
+ <TD>-0.0873284</TD>
+ <TD>-0.0601008</TD>
+ <TD>-0.114096</TD>
+ <TD>-0.131036</TD>
+ <TD>-0.0970645</TD>
+ <TD>10</TD>
+ <TD>8</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053520.9-052321</TD>
+ <TD>83.83713079</TD>
+ <TD>-5.38937613</TD>
+ <TD>0.17294</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.27352E-14</TD>
+ <TD>1.22038E-14</TD>
+ <TD>1.32719E-14</TD>
+ <TD>4.79489E-15</TD>
+ <TD>3.76627E-15</TD>
+ <TD>5.82531E-15</TD>
+ <TD>15.092</TD>
+ <TD>-0.00451392</TD>
+ <TD>-0.0506769</TD>
+ <TD>0.0414142</TD>
+ <TD>-0.143189</TD>
+ <TD>-0.198027</TD>
+ <TD>-0.0872535</TD>
+ <TD>9</TD>
+ <TD>1</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053521.0-052348</TD>
+ <TD>83.83769663</TD>
+ <TD>-5.39690299</TD>
+ <TD>0.16319</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>9.62079E-13</TD>
+ <TD>9.58324E-13</TD>
+ <TD>9.65871E-13</TD>
+ <TD>4.11609E-13</TD>
+ <TD>4.032E-13</TD>
+ <TD>4.20101E-13</TD>
+ <TD>120.381</TD>
+ <TD>0.0273304</TD>
+ <TD>0.0211311</TD>
+ <TD>0.0335637</TD>
+ <TD>-0.0775369</TD>
+ <TD>-0.0845064</TD>
+ <TD>-0.070693</TD>
+ <TD>10</TD>
+ <TD>5</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+</TABLEDATA>
+</DATA>
+</TABLE>
+</RESOURCE>
+</VOTABLE>
diff --git a/pkg/utilities/nttools/zz_bad.xml b/pkg/utilities/nttools/zz_bad.xml
new file mode 100644
index 00000000..def62363
--- /dev/null
+++ b/pkg/utilities/nttools/zz_bad.xml
@@ -0,0 +1,3427 @@
+<?xml version="1.0"?>
+<VOTABLE version="1.2"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://www.ivoa.net/xml/VOTable/v1.2"
+ xsi:SchemaLocation="http://www.ivoa.net/xml/VOTable/v1.2"
+ xmlns:stc="http://www.ivoa.net/xml/STC/v1.30">
+<RESOURCE name="CSC">
+<TABLE name="RA:83.8221,DEC:-5.39111,SR:0.016666,VERB:2,TIME:2012/10/18_16:39:23">
+<DESCRIPTION>
+Chandra Source Catalog VO Cone Search Service
+</DESCRIPTION>
+ <GROUP utype="stc:AstroCoordSystem" ID="ICRS">
+ <DESCRIPTION>ICRS Coordinate System</DESCRIPTION>
+ <GROUP utype="stc:AstroCoordSystem.TimeFrame">
+ <PARAM name="TimeScale" datatype="char" arraysize="*"
+ utype="stc:AstroCoordSystem.TimeFrame.TimeScale" value="TT"/>
+ <PARAM name="TimeRefPosition" datatype="char" arraysize="*"
+ utype="stc:AstroCoordSystem.TimeFrame.ReferencePosition"
+ value="TOPOCENTER"/>
+ </GROUP>
+ <GROUP utype="stc:AstroCoordSystem.SpaceFrame">
+ <PARAM name="SpaceRefFrame" datatype="char" arraysize="*"
+ utype="stc:AstroCoordSystem.SpaceFrame.SpaceRefFrame"
+ value="ICRS"/>
+ <PARAM name="SpaceRefPosition" datatype="char" arraysize="*"
+ utype="stc:AstroCoordSystem.SpaceFrame.ReferencePosition"
+ value="TOPOCENTER"/>
+ </GROUP>
+ <GROUP utype="stc:AstroCoordSystem.SpectralFrame">
+ <PARAM name="SpectralRefPosition" datatype="char" arraysize="*"
+ utype="stc:AstroCoordSystem.SpectralFrame.ReferencePosition"
+ value="TOPOCENTER"/>
+ </GROUP>
+ </GROUP>
+ <GROUP ID="ICRScoords" utype="stc:AstroCoords">
+ <DESCRIPTION>ICRS coordinates</DESCRIPTION>
+ <PARAM datatype="char" arraysize="*" ucd="pos.frame" name="cooframe"
+ utype="stc:AstroCoords.coord_system_id" value="ICRS"/>
+ <FIELDref ref="col1"/>
+ <FIELDref ref="col2"/>
+ <FIELDref ref="col3"/>
+ </GROUP>
+<FIELD ID="col0" arraysize="*" datatype="char" name="name" ucd="meta.id;meta.main" width="20">
+<DESCRIPTION>Source name in the format 'CXO Jhhmmss.s +/- ddmmss'</DESCRIPTION>
+</FIELD>
+<FIELD ID="col1" datatype="double" name="ra" precision="F5" ref="ICRScoords" ucd="pos.eq.ra;meta.main" utype="stc:AstroCoords.Position2D.Value2.C1" width="9">
+<DESCRIPTION>Source position, ICRS right ascension</DESCRIPTION>
+</FIELD>
+<FIELD ID="col2" datatype="double" name="dec" precision="F5" ref="ICRScoords" ucd="pos.eq.dec;meta.main" utype="stc:AstroCoords.Position2D.Value2.C2" width="9">
+<DESCRIPTION>Source position, ICRS declination</DESCRIPTION>
+</FIELD>
+<FIELD ID="col3" datatype="double" name="err_ellipse_r0" precision="F2" ref="ICRScoords" ucd="phys.angSize.smaj;pos.errorEllipse" unit="arcsec" utype="stc:AstroCoords.Position2D.Error2.C1" width="7">
+<DESCRIPTION>Major radius of the 95% confidence level error ellipse</DESCRIPTION>
+</FIELD>
+<FIELD ID="col4" datatype="boolean" name="conf_flag" ucd="meta.code" width="5">
+<DESCRIPTION>Source regions overlap (source is confused)</DESCRIPTION>
+</FIELD>
+<FIELD ID="col5" datatype="boolean" name="extent_flag" ucd="meta.code;phys.angSize" width="5">
+<DESCRIPTION>Deconvolved source extent is inconsistent with a point source at the 90% confidence level</DESCRIPTION>
+</FIELD>
+<FIELD ID="col6" datatype="boolean" name="sat_src_flag" ucd="meta.code.qual;instr.saturation" width="5">
+<DESCRIPTION>Source is saturated in all observations; source properties are unreliable</DESCRIPTION>
+</FIELD>
+<FIELD ID="col7" datatype="double" name="flux_aper_b" precision="E3" ucd="phot.flux;src.net;em.X-ray" unit="erg/s*cm^2" width="9">
+<DESCRIPTION>Aperture-corrected net energy flux inferred from the source region aperture, calculated by counting X-ray events; ACIS broad energy band</DESCRIPTION>
+</FIELD>
+<FIELD ID="col8" datatype="double" name="flux_aper_lolim_b" precision="E3" ucd="stat.error;phot.flux;src.net;stat.min;em.X-ray" unit="erg/s*cm^2" width="9">
+<DESCRIPTION>Aperture-corrected net energy flux inferred from the source region aperture, calculated by counting X-ray events (68% lower confidence limit); ACIS broad energy band</DESCRIPTION>
+</FIELD>
+<FIELD ID="col9" datatype="double" name="flux_aper_hilim_b" precision="E3" ucd="stat.error;phot.flux;src.net;stat.max;em.X-ray" unit="erg/s*cm^2" width="9">
+<DESCRIPTION>Aperture-corrected net energy flux inferred from the source region aperture, calculated by counting X-ray events (68% upper confidence limit); ACIS broad energy band</DESCRIPTION>
+</FIELD>
+<FIELD ID="col10" datatype="double" name="flux_aper_w" precision="E3" ucd="phot.flux;src.net;em.X-ray" unit="erg/s*cm^2" width="9">
+<DESCRIPTION>Aperture-corrected net energy flux inferred from the source region aperture, calculated by counting X-ray events; HRC wide energy band</DESCRIPTION>
+</FIELD>
+<FIELD ID="col11" datatype="double" name="flux_aper_lolim_w" precision="E3" ucd="stat.error;phot.flux;src.net;stat.min;em.X-ray" unit="erg/s*cm^2" width="9">
+<DESCRIPTION>Aperture-corrected net energy flux inferred from the source region aperture, calculated by counting X-ray events (68% lower confidence limit); HRC wide energy band</DESCRIPTION>
+</FIELD>
+<FIELD ID="col12" datatype="double" name="flux_aper_hilim_w" precision="E3" ucd="stat.error;phot.flux;src.net;stat.max;em.X-ray" unit="erg/s*cm^2" width="9">
+<DESCRIPTION>Aperture-corrected net energy flux inferred from the source region aperture, calculated by counting X-ray events (68% upper confidence limit); HRC wide energy band</DESCRIPTION>
+</FIELD>
+<FIELD ID="col13" datatype="double" name="significance" precision="F2" ucd="stat.snr" width="7">
+<DESCRIPTION>Highest source flux significance across all observations</DESCRIPTION>
+</FIELD>
+<FIELD ID="col14" datatype="double" name="hard_hm" precision="F4" ucd="phot.color;em.X-ray" width="9">
+<DESCRIPTION>Spectral hardness ratio measured between ACIS energy bands 'h' and 'm'; hard_hm = (flux_aper_h - flux_aper_m)/flux_aper_b</DESCRIPTION>
+</FIELD>
+<FIELD ID="col15" datatype="double" name="hard_hm_lolim" precision="F4" ucd="stat.error;phot.color;stat.min;em.X-ray" width="9">
+<DESCRIPTION>Spectral hardness ratio measured between ACIS energy bands 'h' and 'm'; hard_hm = (flux_aper_h - flux_aper_m)/flux_aper_b (68% lower confidence limit)</DESCRIPTION>
+</FIELD>
+<FIELD ID="col16" datatype="double" name="hard_hm_hilim" precision="F4" ucd="stat.error;phot.color;stat.max;em.X-ray" width="9">
+<DESCRIPTION>Spectral hardness ratio measured between ACIS energy bands 'h' and 'm'; hard_hm = (flux_aper_h - flux_aper_m)/flux_aper_b (68% upper confidence limit)</DESCRIPTION>
+</FIELD>
+<FIELD ID="col17" datatype="double" name="hard_ms" precision="F4" ucd="phot.color;em.X-ray" width="9">
+<DESCRIPTION>Spectral hardness ratio measured between ACIS energy bands 'm' and 's'; hard_ms = (flux_aper_m - flux_aper_s)/flux_aper_b</DESCRIPTION>
+</FIELD>
+<FIELD ID="col18" datatype="double" name="hard_ms_lolim" precision="F4" ucd="stat.error;phot.color;stat.min;em.X-ray" width="9">
+<DESCRIPTION>Spectral hardness ratio measured between ACIS energy bands 'm' and 's'; hard_ms = (flux_aper_m - flux_aper_s)/flux_aper_b (68% lower confidence limit)</DESCRIPTION>
+</FIELD>
+<FIELD ID="col19" datatype="double" name="hard_ms_hilim" precision="F4" ucd="stat.error;phot.color;stat.max;em.X-ray" width="9">
+<DESCRIPTION>Spectral hardness ratio measured between ACIS energy bands 'm' and 's'; hard_ms = (flux_aper_m - flux_aper_s)/flux_aper_b (68% upper confidence limit)</DESCRIPTION>
+</FIELD>
+<FIELD ID="col20" datatype="short" name="var_intra_index_b" ucd="src.var.index;em.X-ray" width="6">
+<DESCRIPTION>Intra-observation Gregory-Loredo variability index in the range [0, 10] (highest value across all observations); ACIS broad energy band</DESCRIPTION>
+<VALUES null='-32768'/>
+</FIELD>
+<FIELD ID="col21" datatype="short" name="var_intra_index_w" ucd="src.var.index;em.X-ray" width="6">
+<DESCRIPTION>Intra-observation Gregory-Loredo variability index in the range [0, 10] (highest value across all observations); HRC wide energy band</DESCRIPTION>
+<VALUES null='-32768'/>
+</FIELD>
+<FIELD ID="col22" datatype="short" name="var_inter_index_b" ucd="src.var.index;em.X-ray" width="6">
+<DESCRIPTION>Inter-observation variability index in the range [0, 10]; indicates whether the source region photon flux is constant between observations; ACIS broad energy band</DESCRIPTION>
+<VALUES null='-32768'/>
+</FIELD>
+<FIELD ID="col23" datatype="short" name="var_inter_index_w" ucd="src.var.index;em.X-ray" width="6">
+<DESCRIPTION>Inter-observation variability index in the range [0, 10]; indicates whether the source region photon flux is constant between observations; HRC wide energy band</DESCRIPTION>
+<VALUES null='-32768'/>
+</FIELD>
+<DATA>
+<TABLEDATA>
+ <TR>
+ <TD>CXO J053513.4-052340</TD>
+ <TD>83.80601567</TD>
+ <TD>-5.39448431</TD>
+ <TD>0.14563</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.97894E-14</TD>
+ <TD>6.85624E-14</TD>
+ <TD>7.10287E-14</TD>
+ <TD>5.88765E-14</TD>
+ <TD>5.56953E-14</TD>
+ <TD>6.20898E-14</TD>
+ <TD>25.9701</TD>
+ <TD>-0.0822159</TD>
+ <TD>-0.103467</TD>
+ <TD>-0.0608849</TD>
+ <TD>-0.33969</TD>
+ <TD>-0.370832</TD>
+ <TD>-0.308476</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053513.5-052330</TD>
+ <TD>83.80637907</TD>
+ <TD>-5.39185304</TD>
+ <TD>0.14712</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.78161E-14</TD>
+ <TD>6.65089E-14</TD>
+ <TD>6.91366E-14</TD>
+ <TD>3.03441E-14</TD>
+ <TD>2.80268E-14</TD>
+ <TD>3.26849E-14</TD>
+ <TD>28.5808</TD>
+ <TD>0.0105262</TD>
+ <TD>-0.0109229</TD>
+ <TD>0.0322564</TD>
+ <TD>-0.326373</TD>
+ <TD>-0.353819</TD>
+ <TD>-0.299148</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053513.9-052319</TD>
+ <TD>83.80801443</TD>
+ <TD>-5.3888603</TD>
+ <TD>0.21491</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.27045E-15</TD>
+ <TD>4.80761E-15</TD>
+ <TD>5.73796E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>11.0835</TD>
+ <TD>-0.161814</TD>
+ <TD>-0.22216</TD>
+ <TD>-0.103899</TD>
+ <TD>-0.290804</TD>
+ <TD>-0.363042</TD>
+ <TD>-0.21809</TD>
+ <TD>2</TD>
+ <TD>-32768</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.0-052338</TD>
+ <TD>83.8085595</TD>
+ <TD>-5.3939577</TD>
+ <TD>0.14728</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.66661E-14</TD>
+ <TD>5.54982E-14</TD>
+ <TD>5.78459E-14</TD>
+ <TD>2.97063E-14</TD>
+ <TD>2.74026E-14</TD>
+ <TD>3.20332E-14</TD>
+ <TD>30.9082</TD>
+ <TD>-0.0350682</TD>
+ <TD>-0.0573876</TD>
+ <TD>-0.0129662</TD>
+ <TD>-0.176479</TD>
+ <TD>-0.203986</TD>
+ <TD>-0.149003</TD>
+ <TD>10</TD>
+ <TD>7</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.2-052304</TD>
+ <TD>83.80953052</TD>
+ <TD>-5.38444889</TD>
+ <TD>0.15885</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.45327E-14</TD>
+ <TD>5.33644E-14</TD>
+ <TD>5.57128E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>24.4025</TD>
+ <TD>0.91049</TD>
+ <TD>0.895018</TD>
+ <TD>0.925368</TD>
+ <TD>0.0411119</TD>
+ <TD>0.0336484</TD>
+ <TD>0.0488612</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.3-052308</TD>
+ <TD>83.80962741</TD>
+ <TD>-5.38557712</TD>
+ <TD>0.14858</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>6.64955E-14</TD>
+ <TD>6.54639E-14</TD>
+ <TD>6.75375E-14</TD>
+ <TD>1.05285E-14</TD>
+ <TD>9.11164E-15</TD>
+ <TD>1.19597E-14</TD>
+ <TD>45.2756</TD>
+ <TD>0.354199</TD>
+ <TD>0.33561</TD>
+ <TD>0.372553</TD>
+ <TD>0.195498</TD>
+ <TD>0.182312</TD>
+ <TD>0.208292</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.3-052317</TD>
+ <TD>83.80969326</TD>
+ <TD>-5.38810981</TD>
+ <TD>0.16924</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>2.56431E-14</TD>
+ <TD>2.47535E-14</TD>
+ <TD>2.65417E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>17.4034</TD>
+ <TD>0.985171</TD>
+ <TD>0.978543</TD>
+ <TD>0.990966</TD>
+ <TD>-0.00698975</TD>
+ <TD>-0.0128563</TD>
+ <TD>-0.00214212</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.3-052253</TD>
+ <TD>83.8098206</TD>
+ <TD>-5.3816407</TD>
+ <TD>0.16466</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.05176E-14</TD>
+ <TD>1.98107E-14</TD>
+ <TD>2.12316E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>15.0649</TD>
+ <TD>0.560934</TD>
+ <TD>0.511123</TD>
+ <TD>0.609698</TD>
+ <TD>0.210821</TD>
+ <TD>0.186294</TD>
+ <TD>0.235778</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.4-052322</TD>
+ <TD>83.8099784</TD>
+ <TD>-5.38966568</TD>
+ <TD>0.23553</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>4.66587E-15</TD>
+ <TD>4.28105E-15</TD>
+ <TD>5.05458E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>12.1756</TD>
+ <TD>-0.0756736</TD>
+ <TD>-0.135332</TD>
+ <TD>-0.0170884</TD>
+ <TD>-0.114952</TD>
+ <TD>-0.183403</TD>
+ <TD>-0.0450814</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.3-052333</TD>
+ <TD>83.80998065</TD>
+ <TD>-5.39261156</TD>
+ <TD>0.14702</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>4.8023E-14</TD>
+ <TD>4.70178E-14</TD>
+ <TD>4.90384E-14</TD>
+ <TD>1.46049E-14</TD>
+ <TD>1.29563E-14</TD>
+ <TD>1.62703E-14</TD>
+ <TD>27.6562</TD>
+ <TD>-0.0825775</TD>
+ <TD>-0.106809</TD>
+ <TD>-0.0578608</TD>
+ <TD>-0.124551</TD>
+ <TD>-0.156265</TD>
+ <TD>-0.092763</TD>
+ <TD>9</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.5-052315</TD>
+ <TD>83.81056936</TD>
+ <TD>-5.38772233</TD>
+ <TD>0.17135</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.34289E-14</TD>
+ <TD>1.27463E-14</TD>
+ <TD>1.41184E-14</TD>
+ <TD>8.55561E-15</TD>
+ <TD>7.21816E-15</TD>
+ <TD>9.90657E-15</TD>
+ <TD>12.055</TD>
+ <TD>0.98062</TD>
+ <TD>0.972117</TD>
+ <TD>0.987105</TD>
+ <TD>-0.00429089</TD>
+ <TD>-0.00957531</TD>
+ <TD>-3.08654E-4</TD>
+ <TD>2</TD>
+ <TD>9</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.5-052407</TD>
+ <TD>83.81072267</TD>
+ <TD>-5.40217119</TD>
+ <TD>0.2283</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>9.1153E-15</TD>
+ <TD>8.44146E-15</TD>
+ <TD>9.79595E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>8.8595</TD>
+ <TD>0.968181</TD>
+ <TD>0.95185</TD>
+ <TD>0.981924</TD>
+ <TD>-0.00693137</TD>
+ <TD>-0.0183943</TD>
+ <TD>0.00208314</TD>
+ <TD>1</TD>
+ <TD>-32768</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.6-052328</TD>
+ <TD>83.81100284</TD>
+ <TD>-5.39122647</TD>
+ <TD>0.43437</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.78192E-15</TD>
+ <TD>3.14545E-15</TD>
+ <TD>4.42482E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>5.92101</TD>
+ <TD>-0.0631104</TD>
+ <TD>-0.177637</TD>
+ <TD>0.0523516</TD>
+ <TD>-0.190031</TD>
+ <TD>-0.324285</TD>
+ <TD>-0.0557797</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.6-052301</TD>
+ <TD>83.81109487</TD>
+ <TD>-5.38379019</TD>
+ <TD>0.14849</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>7.39896E-14</TD>
+ <TD>7.29582E-14</TD>
+ <TD>7.50313E-14</TD>
+ <TD>9.53745E-15</TD>
+ <TD>8.13605E-15</TD>
+ <TD>1.0953E-14</TD>
+ <TD>65.3124</TD>
+ <TD>0.170492</TD>
+ <TD>0.157044</TD>
+ <TD>0.183882</TD>
+ <TD>0.180409</TD>
+ <TD>0.16915</TD>
+ <TD>0.191544</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.6-052249</TD>
+ <TD>83.81120139</TD>
+ <TD>-5.38033176</TD>
+ <TD>0.18087</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.32936E-14</TD>
+ <TD>1.2721E-14</TD>
+ <TD>1.38719E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>13.9585</TD>
+ <TD>0.48944</TD>
+ <TD>0.433017</TD>
+ <TD>0.544177</TD>
+ <TD>0.235406</TD>
+ <TD>0.206246</TD>
+ <TD>0.2648</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.7-052412</TD>
+ <TD>83.81128448</TD>
+ <TD>-5.40343355</TD>
+ <TD>0.19978</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>7.71247E-15</TD>
+ <TD>7.15899E-15</TD>
+ <TD>8.27154E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6.14947</TD>
+ <TD>0.370567</TD>
+ <TD>0.259466</TD>
+ <TD>0.47732</TD>
+ <TD>-0.138487</TD>
+ <TD>-0.2424</TD>
+ <TD>-0.0347654</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.7-052322</TD>
+ <TD>83.81133486</TD>
+ <TD>-5.38964017</TD>
+ <TD>0.14839</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.01776E-14</TD>
+ <TD>4.92056E-14</TD>
+ <TD>5.11593E-14</TD>
+ <TD>5.23879E-14</TD>
+ <TD>4.93591E-14</TD>
+ <TD>5.54472E-14</TD>
+ <TD>29.5509</TD>
+ <TD>0.28267</TD>
+ <TD>0.251908</TD>
+ <TD>0.312992</TD>
+ <TD>0.289408</TD>
+ <TD>0.271314</TD>
+ <TD>0.307682</TD>
+ <TD>10</TD>
+ <TD>9</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.8-052406</TD>
+ <TD>83.81170941</TD>
+ <TD>-5.40185359</TD>
+ <TD>0.20687</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.95425E-14</TD>
+ <TD>1.8482E-14</TD>
+ <TD>2.06138E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>10.0425</TD>
+ <TD>0.972371</TD>
+ <TD>0.95999</TD>
+ <TD>0.983311</TD>
+ <TD>0.00443213</TD>
+ <TD>-0.0011769</TD>
+ <TD>0.0108282</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.8-052346</TD>
+ <TD>83.8117676</TD>
+ <TD>-5.39615671</TD>
+ <TD>0.15213</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.9664E-14</TD>
+ <TD>1.88916E-14</TD>
+ <TD>2.04442E-14</TD>
+ <TD>1.26507E-14</TD>
+ <TD>1.10556E-14</TD>
+ <TD>1.4262E-14</TD>
+ <TD>12.2048</TD>
+ <TD>-0.16864</TD>
+ <TD>-0.213904</TD>
+ <TD>-0.123749</TD>
+ <TD>-0.213757</TD>
+ <TD>-0.285474</TD>
+ <TD>-0.140922</TD>
+ <TD>8</TD>
+ <TD>0</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.8-052315</TD>
+ <TD>83.81177012</TD>
+ <TD>-5.38770869</TD>
+ <TD>0.17193</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>9.85838E-15</TD>
+ <TD>9.45421E-15</TD>
+ <TD>1.02666E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>15.2939</TD>
+ <TD>-0.126347</TD>
+ <TD>-0.166511</TD>
+ <TD>-0.0858136</TD>
+ <TD>-0.278406</TD>
+ <TD>-0.332037</TD>
+ <TD>-0.223733</TD>
+ <TD>2</TD>
+ <TD>-32768</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.8-052304</TD>
+ <TD>83.81193361</TD>
+ <TD>-5.38466425</TD>
+ <TD>0.17267</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.03975E-14</TD>
+ <TD>1.97508E-14</TD>
+ <TD>2.10508E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>20.2447</TD>
+ <TD>0.317345</TD>
+ <TD>0.27384</TD>
+ <TD>0.360055</TD>
+ <TD>0.283514</TD>
+ <TD>0.257743</TD>
+ <TD>0.309727</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.9-052412</TD>
+ <TD>83.81217858</TD>
+ <TD>-5.40351021</TD>
+ <TD>0.14801</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.3239E-14</TD>
+ <TD>5.22719E-14</TD>
+ <TD>5.4216E-14</TD>
+ <TD>1.58719E-14</TD>
+ <TD>1.41828E-14</TD>
+ <TD>1.75781E-14</TD>
+ <TD>34.7523</TD>
+ <TD>0.0465175</TD>
+ <TD>0.0256984</TD>
+ <TD>0.0675352</TD>
+ <TD>-0.107479</TD>
+ <TD>-0.131671</TD>
+ <TD>-0.0835884</TD>
+ <TD>10</TD>
+ <TD>1</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.9-052328</TD>
+ <TD>83.81220892</TD>
+ <TD>-5.39133275</TD>
+ <TD>0.16083</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>4.68217E-15</TD>
+ <TD>4.2982E-15</TD>
+ <TD>5.07002E-15</TD>
+ <TD>3.58725E-15</TD>
+ <TD>2.70965E-15</TD>
+ <TD>4.46036E-15</TD>
+ <TD>7.89055</TD>
+ <TD>-0.254059</TD>
+ <TD>-0.369787</TD>
+ <TD>-0.139728</TD>
+ <TD>0.369802</TD>
+ <TD>0.257663</TD>
+ <TD>0.481755</TD>
+ <TD>1</TD>
+ <TD>0</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.9-052338</TD>
+ <TD>83.81228445</TD>
+ <TD>-5.39416969</TD>
+ <TD>0.14232</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.49754E-13</TD>
+ <TD>1.48202E-13</TD>
+ <TD>1.51322E-13</TD>
+ <TD>2.82477E-13</TD>
+ <TD>2.75562E-13</TD>
+ <TD>2.89463E-13</TD>
+ <TD>54.1441</TD>
+ <TD>-0.0472355</TD>
+ <TD>-0.0585613</TD>
+ <TD>-0.0359605</TD>
+ <TD>-0.150355</TD>
+ <TD>-0.16636</TD>
+ <TD>-0.134227</TD>
+ <TD>10</TD>
+ <TD>6</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.0-052354</TD>
+ <TD>83.81265915</TD>
+ <TD>-5.39841906</TD>
+ <TD>0.59443</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.93214E-15</TD>
+ <TD>2.99955E-15</TD>
+ <TD>4.86489E-15</TD>
+ <TD>4.16316</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>2</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.1-052304</TD>
+ <TD>83.81297046</TD>
+ <TD>-5.38451569</TD>
+ <TD>0.45384</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.88649E-15</TD>
+ <TD>9.06494E-16</TD>
+ <TD>2.8637E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.05328</TD>
+ <TD>0.83723</TD>
+ <TD>0.715803</TD>
+ <TD>0.933967</TD>
+ <TD>-0.0320696</TD>
+ <TD>-0.118798</TD>
+ <TD>0.0293079</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.1-052346</TD>
+ <TD>83.81314399</TD>
+ <TD>-5.39621512</TD>
+ <TD>0.2003</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>4.39873E-15</TD>
+ <TD>3.92166E-15</TD>
+ <TD>4.88063E-15</TD>
+ <TD>4.00059E-15</TD>
+ <TD>3.0109E-15</TD>
+ <TD>4.9949E-15</TD>
+ <TD>5.6963</TD>
+ <TD>-0.0285843</TD>
+ <TD>-0.102898</TD>
+ <TD>0.0406812</TD>
+ <TD>-0.249534</TD>
+ <TD>-0.381015</TD>
+ <TD>-0.102094</TD>
+ <TD>6</TD>
+ <TD>0</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.1-052254</TD>
+ <TD>83.81329418</TD>
+ <TD>-5.38172473</TD>
+ <TD>0.14462</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.64113E-13</TD>
+ <TD>1.62452E-13</TD>
+ <TD>1.65791E-13</TD>
+ <TD>1.6316E-14</TD>
+ <TD>1.43274E-14</TD>
+ <TD>1.83248E-14</TD>
+ <TD>52.0892</TD>
+ <TD>0.450876</TD>
+ <TD>0.436926</TD>
+ <TD>0.464947</TD>
+ <TD>0.137764</TD>
+ <TD>0.126999</TD>
+ <TD>0.148264</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.1-052318</TD>
+ <TD>83.81330006</TD>
+ <TD>-5.3885408</TD>
+ <TD>0.47766</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>3.49507E-15</TD>
+ <TD>2.3225E-15</TD>
+ <TD>4.65674E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.82159</TD>
+ <TD>0.854749</TD>
+ <TD>0.753011</TD>
+ <TD>0.937876</TD>
+ <TD>-0.0355204</TD>
+ <TD>-0.115613</TD>
+ <TD>0.0224368</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.2-052256</TD>
+ <TD>83.81360368</TD>
+ <TD>-5.38242218</TD>
+ <TD>0.1999</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.03202E-12</TD>
+ <TD>1.02837E-12</TD>
+ <TD>1.03571E-12</TD>
+ <TD>2.6702E-13</TD>
+ <TD>2.60158E-13</TD>
+ <TD>2.73951E-13</TD>
+ <TD>130.522</TD>
+ <TD>0.0704777</TD>
+ <TD>0.0644488</TD>
+ <TD>0.0764034</TD>
+ <TD>-0.0717052</TD>
+ <TD>-0.0779943</TD>
+ <TD>-0.0655273</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.3-052333</TD>
+ <TD>83.81407441</TD>
+ <TD>-5.39255272</TD>
+ <TD>0.14553</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>2.25803E-14</TD>
+ <TD>2.19797E-14</TD>
+ <TD>2.31869E-14</TD>
+ <TD>1.93736E-14</TD>
+ <TD>1.7427E-14</TD>
+ <TD>2.134E-14</TD>
+ <TD>20.1199</TD>
+ <TD>-0.137472</TD>
+ <TD>-0.170874</TD>
+ <TD>-0.103627</TD>
+ <TD>-0.149193</TD>
+ <TD>-0.192213</TD>
+ <TD>-0.105697</TD>
+ <TD>9</TD>
+ <TD>2</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.4-052345</TD>
+ <TD>83.81434295</TD>
+ <TD>-5.39590645</TD>
+ <TD>0.14712</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.51555E-14</TD>
+ <TD>5.41834E-14</TD>
+ <TD>5.61375E-14</TD>
+ <TD>9.9547E-15</TD>
+ <TD>8.51468E-15</TD>
+ <TD>1.14093E-14</TD>
+ <TD>42.4107</TD>
+ <TD>0.0862415</TD>
+ <TD>0.0712833</TD>
+ <TD>0.10104</TD>
+ <TD>-0.00267428</TD>
+ <TD>-0.0218673</TD>
+ <TD>0.0166436</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.4-052248</TD>
+ <TD>83.8145085</TD>
+ <TD>-5.38011504</TD>
+ <TD>0.14676</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.04415E-13</TD>
+ <TD>1.03206E-13</TD>
+ <TD>1.05635E-13</TD>
+ <TD>8.82286E-15</TD>
+ <TD>7.076E-15</TD>
+ <TD>1.05874E-14</TD>
+ <TD>41.8304</TD>
+ <TD>-0.0174547</TD>
+ <TD>-0.0354158</TD>
+ <TD>8.28379E-4</TD>
+ <TD>-0.0411823</TD>
+ <TD>-0.0614385</TD>
+ <TD>-0.0209821</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.4-052337</TD>
+ <TD>83.81455127</TD>
+ <TD>-5.39376129</TD>
+ <TD>0.45111</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.41203E-15</TD>
+ <TD>9.77813E-16</TD>
+ <TD>1.84263E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>4.3122</TD>
+ <TD>-0.0434585</TD>
+ <TD>-0.229319</TD>
+ <TD>0.140449</TD>
+ <TD>0.18419</TD>
+ <TD>0.00217075</TD>
+ <TD>0.367231</TD>
+ <TD>1</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.5-052246</TD>
+ <TD>83.81473478</TD>
+ <TD>-5.37948293</TD>
+ <TD>0.31051</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.67177E-14</TD>
+ <TD>1.5583E-14</TD>
+ <TD>1.78639E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>12.1993</TD>
+ <TD>0.937694</TD>
+ <TD>0.910339</TD>
+ <TD>0.963317</TD>
+ <TD>0.0114968</TD>
+ <TD>-0.00399962</TD>
+ <TD>0.0268677</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.6-052402</TD>
+ <TD>83.81504651</TD>
+ <TD>-5.40078793</TD>
+ <TD>0.15306</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.91504E-14</TD>
+ <TD>1.83643E-14</TD>
+ <TD>1.99445E-14</TD>
+ <TD>5.66629E-14</TD>
+ <TD>5.35161E-14</TD>
+ <TD>5.98415E-14</TD>
+ <TD>17.7872</TD>
+ <TD>-0.178473</TD>
+ <TD>-0.224961</TD>
+ <TD>-0.131402</TD>
+ <TD>-0.295806</TD>
+ <TD>-0.362798</TD>
+ <TD>-0.227692</TD>
+ <TD>5</TD>
+ <TD>9</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.6-052256</TD>
+ <TD>83.81514589</TD>
+ <TD>-5.3823026</TD>
+ <TD>0.1784</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>8.55289E-13</TD>
+ <TD>8.52034E-13</TD>
+ <TD>8.58577E-13</TD>
+ <TD>2.02006E-12</TD>
+ <TD>2.00158E-12</TD>
+ <TD>2.03873E-12</TD>
+ <TD>129.732</TD>
+ <TD>0.0612033</TD>
+ <TD>0.0551543</TD>
+ <TD>0.06729</TD>
+ <TD>-0.0245866</TD>
+ <TD>-0.0308778</TD>
+ <TD>-0.0182808</TD>
+ <TD>10</TD>
+ <TD>8</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.7-052339</TD>
+ <TD>83.815411</TD>
+ <TD>-5.3941811</TD>
+ <TD>0.39841</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.05992E-14</TD>
+ <TD>1.74398E-14</TD>
+ <TD>2.37906E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6.29874</TD>
+ <TD>0.607113</TD>
+ <TD>0.500276</TD>
+ <TD>0.707773</TD>
+ <TD>0.160863</TD>
+ <TD>0.106058</TD>
+ <TD>0.219275</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.7-052411</TD>
+ <TD>83.81562914</TD>
+ <TD>-5.403203640000001</TD>
+ <TD>0.642673</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.80835E-16</TD>
+ <TD>2.06299E-16</TD>
+ <TD>5.56111E-16</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.93135</TD>
+ <TD>-0.147377</TD>
+ <TD>-0.27926</TD>
+ <TD>-0.0136489</TD>
+ <TD>-0.32344</TD>
+ <TD>-0.508552</TD>
+ <TD>-0.129011</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.7-052338</TD>
+ <TD>83.8157219</TD>
+ <TD>-5.39390552</TD>
+ <TD>0.45063</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>3.18339E-14</TD>
+ <TD>2.77075E-14</TD>
+ <TD>3.60019E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>7.27452</TD>
+ <TD>0.822639</TD>
+ <TD>0.75431</TD>
+ <TD>0.88682</TD>
+ <TD>0.0525613</TD>
+ <TD>0.0151042</TD>
+ <TD>0.090596</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.7-052309</TD>
+ <TD>83.81574739</TD>
+ <TD>-5.38606832</TD>
+ <TD>0.40301</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>3.03573E-12</TD>
+ <TD>3.029E-12</TD>
+ <TD>3.04254E-12</TD>
+ <TD>1.87491E-12</TD>
+ <TD>1.85709E-12</TD>
+ <TD>1.89291E-12</TD>
+ <TD>202.738</TD>
+ <TD>0.274577</TD>
+ <TD>0.270827</TD>
+ <TD>0.27825</TD>
+ <TD>-0.0459597</TD>
+ <TD>-0.0495455</TD>
+ <TD>-0.0423645</TD>
+ <TD>8</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052305</TD>
+ <TD>83.81588895</TD>
+ <TD>-5.38485094</TD>
+ <TD>0.48598</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>9.31635E-15</TD>
+ <TD>8.2033E-15</TD>
+ <TD>1.04407E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>9.11467</TD>
+ <TD>-0.137899</TD>
+ <TD>-0.205363</TD>
+ <TD>-0.0699988</TD>
+ <TD>-0.283179</TD>
+ <TD>-0.370767</TD>
+ <TD>-0.191045</TD>
+ <TD>2</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052313</TD>
+ <TD>83.815963</TD>
+ <TD>-5.38726978</TD>
+ <TD>0.40057</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.77082E-12</TD>
+ <TD>2.76452E-12</TD>
+ <TD>2.77719E-12</TD>
+ <TD>1.01992E-12</TD>
+ <TD>1.00666E-12</TD>
+ <TD>1.0333E-12</TD>
+ <TD>197.573</TD>
+ <TD>0.259373</TD>
+ <TD>0.255483</TD>
+ <TD>0.263164</TD>
+ <TD>-0.04572</TD>
+ <TD>-0.0494406</TD>
+ <TD>-0.0419462</TD>
+ <TD>9</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052245</TD>
+ <TD>83.81598875</TD>
+ <TD>-5.37934237</TD>
+ <TD>0.15512</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.5406E-14</TD>
+ <TD>1.492E-14</TD>
+ <TD>1.5897E-14</TD>
+ <TD>3.40691E-15</TD>
+ <TD>2.32026E-15</TD>
+ <TD>4.49824E-15</TD>
+ <TD>21.9792</TD>
+ <TD>-0.0994224</TD>
+ <TD>-0.130616</TD>
+ <TD>-0.0679763</TD>
+ <TD>-0.14147</TD>
+ <TD>-0.181277</TD>
+ <TD>-0.1021</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052322</TD>
+ <TD>83.81610029</TD>
+ <TD>-5.38953689</TD>
+ <TD>0.43705</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.97845E-14</TD>
+ <TD>1.67432E-14</TD>
+ <TD>2.28564E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>5.33178</TD>
+ <TD>0.644325</TD>
+ <TD>0.523345</TD>
+ <TD>0.765435</TD>
+ <TD>-0.140958</TD>
+ <TD>-0.260161</TD>
+ <TD>-0.0220717</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052318</TD>
+ <TD>83.81611207</TD>
+ <TD>-5.38856486</TD>
+ <TD>0.44418</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.13066E-14</TD>
+ <TD>9.23675E-15</TD>
+ <TD>1.33974E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>5.95239</TD>
+ <TD>-0.0905449</TD>
+ <TD>-0.179506</TD>
+ <TD>5.26605E-4</TD>
+ <TD>-0.431631</TD>
+ <TD>-0.554358</TD>
+ <TD>-0.304264</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052301</TD>
+ <TD>83.81612461</TD>
+ <TD>-5.38382611</TD>
+ <TD>0.23917</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>8.45856E-15</TD>
+ <TD>7.64832E-15</TD>
+ <TD>9.277E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>7.90999</TD>
+ <TD>-0.0861684</TD>
+ <TD>-0.170009</TD>
+ <TD>-0.00161331</TD>
+ <TD>-0.158934</TD>
+ <TD>-0.263449</TD>
+ <TD>-0.0489787</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052233</TD>
+ <TD>83.81613303</TD>
+ <TD>-5.37585042</TD>
+ <TD>0.37078</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.7933E-15</TD>
+ <TD>1.4194E-15</TD>
+ <TD>2.16863E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>5.23268</TD>
+ <TD>-0.474765</TD>
+ <TD>-0.592407</TD>
+ <TD>-0.354312</TD>
+ <TD>0.260458</TD>
+ <TD>0.102338</TD>
+ <TD>0.417331</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052310</TD>
+ <TD>83.81619</TD>
+ <TD>-5.3863028</TD>
+ <TD>0.48816</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>4.64943E-13</TD>
+ <TD>4.5283E-13</TD>
+ <TD>4.77179E-13</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>37.321</TD>
+ <TD>0.248112</TD>
+ <TD>0.226014</TD>
+ <TD>0.27041</TD>
+ <TD>0.135802</TD>
+ <TD>0.117704</TD>
+ <TD>0.153639</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.9-052417</TD>
+ <TD>83.8162912</TD>
+ <TD>-5.40491845</TD>
+ <TD>0.6885</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.78186E-15</TD>
+ <TD>2.91713E-15</TD>
+ <TD>4.65E-15</TD>
+ <TD>4.3122</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>2</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.9-052349</TD>
+ <TD>83.81647584</TD>
+ <TD>-5.39713268</TD>
+ <TD>0.14102</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>3.87473E-13</TD>
+ <TD>3.85092E-13</TD>
+ <TD>3.89878E-13</TD>
+ <TD>1.89669E-13</TD>
+ <TD>1.83958E-13</TD>
+ <TD>1.95437E-13</TD>
+ <TD>73.5294</TD>
+ <TD>0.0642011</TD>
+ <TD>0.0629523</TD>
+ <TD>0.0654531</TD>
+ <TD>0.0222816</TD>
+ <TD>0.0111647</TD>
+ <TD>0.0333233</TD>
+ <TD>10</TD>
+ <TD>7</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052352</TD>
+ <TD>83.81675305</TD>
+ <TD>-5.39801365</TD>
+ <TD>0.14462</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.00513E-13</TD>
+ <TD>9.911E-14</TD>
+ <TD>1.0193E-13</TD>
+ <TD>1.48552E-14</TD>
+ <TD>1.31388E-14</TD>
+ <TD>1.65889E-14</TD>
+ <TD>35.6626</TD>
+ <TD>0.157734</TD>
+ <TD>0.135077</TD>
+ <TD>0.180105</TD>
+ <TD>0.0436772</TD>
+ <TD>0.0221774</TD>
+ <TD>0.0652125</TD>
+ <TD>10</TD>
+ <TD>1</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052253</TD>
+ <TD>83.81698406</TD>
+ <TD>-5.38164426</TD>
+ <TD>0.16235</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.26789E-14</TD>
+ <TD>3.18198E-14</TD>
+ <TD>3.35468E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>25.1492</TD>
+ <TD>0.865571</TD>
+ <TD>0.846684</TD>
+ <TD>0.883593</TD>
+ <TD>0.0654986</TD>
+ <TD>0.056393</TD>
+ <TD>0.0749912</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052306</TD>
+ <TD>83.81701311</TD>
+ <TD>-5.38522135</TD>
+ <TD>0.14238</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.76855E-13</TD>
+ <TD>1.75356E-13</TD>
+ <TD>1.7837E-13</TD>
+ <TD>5.32069E-14</TD>
+ <TD>4.98546E-14</TD>
+ <TD>5.65931E-14</TD>
+ <TD>68.6943</TD>
+ <TD>0.0638425</TD>
+ <TD>0.0529115</TD>
+ <TD>0.0748212</TD>
+ <TD>-0.0784673</TD>
+ <TD>-0.0903596</TD>
+ <TD>-0.0663197</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052325</TD>
+ <TD>83.8170161</TD>
+ <TD>-5.39040007</TD>
+ <TD>0.42036</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.00543E-14</TD>
+ <TD>9.06073E-15</TD>
+ <TD>1.10579E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>11.0945</TD>
+ <TD>-0.125453</TD>
+ <TD>-0.17706</TD>
+ <TD>-0.0731745</TD>
+ <TD>-0.344981</TD>
+ <TD>-0.416858</TD>
+ <TD>-0.272662</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052411</TD>
+ <TD>83.8170323</TD>
+ <TD>-5.4031178</TD>
+ <TD>0.18202</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>2.25929E-14</TD>
+ <TD>2.13907E-14</TD>
+ <TD>2.38072E-14</TD>
+ <TD>3.44264E-15</TD>
+ <TD>2.59187E-15</TD>
+ <TD>4.29976E-15</TD>
+ <TD>12.9669</TD>
+ <TD>-0.0641377</TD>
+ <TD>-0.121644</TD>
+ <TD>-0.00538426</TD>
+ <TD>-0.016818</TD>
+ <TD>-0.0841843</TD>
+ <TD>0.0495484</TD>
+ <TD>7</TD>
+ <TD>2</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052322</TD>
+ <TD>83.81705333</TD>
+ <TD>-5.3896635</TD>
+ <TD>0.1439</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>8.06604E-14</TD>
+ <TD>7.93614E-14</TD>
+ <TD>8.19725E-14</TD>
+ <TD>9.51118E-15</TD>
+ <TD>6.51756E-15</TD>
+ <TD>1.25222E-14</TD>
+ <TD>35.9128</TD>
+ <TD>0.575093</TD>
+ <TD>0.55627</TD>
+ <TD>0.594211</TD>
+ <TD>-0.0963508</TD>
+ <TD>-0.113819</TD>
+ <TD>-0.0786152</TD>
+ <TD>8</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.1-052313</TD>
+ <TD>83.81720052</TD>
+ <TD>-5.38708875</TD>
+ <TD>0.29045</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.17102E-14</TD>
+ <TD>1.06569E-14</TD>
+ <TD>1.27741E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6.71341</TD>
+ <TD>0.179113</TD>
+ <TD>0.0907505</TD>
+ <TD>0.272076</TD>
+ <TD>-0.316139</TD>
+ <TD>-0.42591</TD>
+ <TD>-0.203308</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.1-052309</TD>
+ <TD>83.8172558</TD>
+ <TD>-5.38598655</TD>
+ <TD>0.44726</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>3.83267E-15</TD>
+ <TD>2.89841E-15</TD>
+ <TD>4.77108E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.4279</TD>
+ <TD>-0.0114393</TD>
+ <TD>-0.200116</TD>
+ <TD>0.16813</TD>
+ <TD>-0.0802978</TD>
+ <TD>-0.310341</TD>
+ <TD>0.173881</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.1-052237</TD>
+ <TD>83.81744498</TD>
+ <TD>-5.37702105</TD>
+ <TD>0.16304</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.24777E-14</TD>
+ <TD>1.20505E-14</TD>
+ <TD>1.29091E-14</TD>
+ <TD>3.88118E-15</TD>
+ <TD>2.96665E-15</TD>
+ <TD>4.78877E-15</TD>
+ <TD>15.5503</TD>
+ <TD>0.0888785</TD>
+ <TD>0.0359265</TD>
+ <TD>0.141431</TD>
+ <TD>0.109917</TD>
+ <TD>0.0587091</TD>
+ <TD>0.16105</TD>
+ <TD>7</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.2-052318</TD>
+ <TD>83.81746865</TD>
+ <TD>-5.38854714</TD>
+ <TD>0.29102</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.7293E-14</TD>
+ <TD>1.62498E-14</TD>
+ <TD>1.83469E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>11.8731</TD>
+ <TD>-0.0821205</TD>
+ <TD>-0.134065</TD>
+ <TD>-0.0290845</TD>
+ <TD>-0.217927</TD>
+ <TD>-0.288334</TD>
+ <TD>-0.144648</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ <TD>4</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.2-052316</TD>
+ <TD>83.8178479</TD>
+ <TD>-5.38786385</TD>
+ <TD>0.15414</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>3.32569E-14</TD>
+ <TD>3.24069E-14</TD>
+ <TD>3.41155E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>16.9568</TD>
+ <TD>0.214185</TD>
+ <TD>0.171584</TD>
+ <TD>0.256628</TD>
+ <TD>-0.0273673</TD>
+ <TD>-0.0745624</TD>
+ <TD>0.0207458</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.3-052403</TD>
+ <TD>83.81822268</TD>
+ <TD>-5.40086482</TD>
+ <TD>0.14238</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.65119E-13</TD>
+ <TD>5.60431E-13</TD>
+ <TD>5.69854E-13</TD>
+ <TD>1.1893E-13</TD>
+ <TD>1.14403E-13</TD>
+ <TD>1.23504E-13</TD>
+ <TD>66.1461</TD>
+ <TD>0.120421</TD>
+ <TD>0.108076</TD>
+ <TD>0.132924</TD>
+ <TD>0.0565306</TD>
+ <TD>0.0445626</TD>
+ <TD>0.0685104</TD>
+ <TD>8</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.4-052329</TD>
+ <TD>83.81859564</TD>
+ <TD>-5.39142135</TD>
+ <TD>0.43656</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.33598E-14</TD>
+ <TD>1.16336E-14</TD>
+ <TD>1.51034E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>8.24052</TD>
+ <TD>-0.107666</TD>
+ <TD>-0.166067</TD>
+ <TD>-0.0482851</TD>
+ <TD>-0.560076</TD>
+ <TD>-0.642993</TD>
+ <TD>-0.475082</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.4-052331</TD>
+ <TD>83.81861877</TD>
+ <TD>-5.39200198</TD>
+ <TD>0.4145</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>4.70839E-15</TD>
+ <TD>3.72184E-15</TD>
+ <TD>5.70217E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.95451</TD>
+ <TD>0.10125</TD>
+ <TD>-0.0473853</TD>
+ <TD>0.247861</TD>
+ <TD>-0.213178</TD>
+ <TD>-0.403455</TD>
+ <TD>-0.00761378</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.4-052322</TD>
+ <TD>83.81863682</TD>
+ <TD>-5.38964395</TD>
+ <TD>0.16555</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>3.15953E-12</TD>
+ <TD>3.15334E-12</TD>
+ <TD>3.16578E-12</TD>
+ <TD>1.93706E-11</TD>
+ <TD>1.93136E-11</TD>
+ <TD>1.94281E-11</TD>
+ <TD>335.79</TD>
+ <TD>-0.0574404</TD>
+ <TD>-0.0603554</TD>
+ <TD>-0.054598</TD>
+ <TD>-0.179857</TD>
+ <TD>-0.183533</TD>
+ <TD>-0.176244</TD>
+ <TD>7</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.4-052256</TD>
+ <TD>83.81868061</TD>
+ <TD>-5.38231438</TD>
+ <TD>0.25375</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>9.13394E-15</TD>
+ <TD>8.46442E-15</TD>
+ <TD>9.81021E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>10.1085</TD>
+ <TD>0.532591</TD>
+ <TD>0.460216</TD>
+ <TD>0.603536</TD>
+ <TD>0.219955</TD>
+ <TD>0.183953</TD>
+ <TD>0.256889</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.4-052234</TD>
+ <TD>83.81869862</TD>
+ <TD>-5.37637281</TD>
+ <TD>0.16109</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.71057E-14</TD>
+ <TD>1.66378E-14</TD>
+ <TD>1.75782E-14</TD>
+ <TD>3.92169E-15</TD>
+ <TD>2.98105E-15</TD>
+ <TD>4.87032E-15</TD>
+ <TD>23.0625</TD>
+ <TD>-0.110707</TD>
+ <TD>-0.140501</TD>
+ <TD>-0.0809267</TD>
+ <TD>-0.146559</TD>
+ <TD>-0.184692</TD>
+ <TD>-0.107592</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.5-052405</TD>
+ <TD>83.81907688</TD>
+ <TD>-5.40160715</TD>
+ <TD>0.14862</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.17377E-14</TD>
+ <TD>6.00346E-14</TD>
+ <TD>6.34581E-14</TD>
+ <TD>2.21828E-14</TD>
+ <TD>2.01516E-14</TD>
+ <TD>2.42345E-14</TD>
+ <TD>20.473</TD>
+ <TD>-0.0114133</TD>
+ <TD>-0.0482004</TD>
+ <TD>0.0240581</TD>
+ <TD>-0.0682099</TD>
+ <TD>-0.110431</TD>
+ <TD>-0.0262589</TD>
+ <TD>9</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.6-052315</TD>
+ <TD>83.81916799</TD>
+ <TD>-5.38771941</TD>
+ <TD>0.2965</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.38905E-14</TD>
+ <TD>2.24716E-14</TD>
+ <TD>2.53237E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>11.2343</TD>
+ <TD>0.459388</TD>
+ <TD>0.394276</TD>
+ <TD>0.524993</TD>
+ <TD>-0.0552914</TD>
+ <TD>-0.12419</TD>
+ <TD>0.0178639</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.7-052231</TD>
+ <TD>83.81971948</TD>
+ <TD>-5.37529756</TD>
+ <TD>0.15804</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.06851E-14</TD>
+ <TD>4.98874E-14</TD>
+ <TD>5.14908E-14</TD>
+ <TD>5.06829E-15</TD>
+ <TD>4.00493E-15</TD>
+ <TD>6.13022E-15</TD>
+ <TD>44.5636</TD>
+ <TD>0.0310784</TD>
+ <TD>0.0149852</TD>
+ <TD>0.0471353</TD>
+ <TD>-0.0098311</TD>
+ <TD>-0.0287303</TD>
+ <TD>0.00904038</TD>
+ <TD>10</TD>
+ <TD>1</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.7-052316</TD>
+ <TD>83.81979918</TD>
+ <TD>-5.38783323</TD>
+ <TD>0.15457</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>5.41387E-14</TD>
+ <TD>5.31441E-14</TD>
+ <TD>5.51433E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>42.0005</TD>
+ <TD>0.34389</TD>
+ <TD>0.324476</TD>
+ <TD>0.363242</TD>
+ <TD>0.137474</TD>
+ <TD>0.120154</TD>
+ <TD>0.155026</TD>
+ <TD>10</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.7-052327</TD>
+ <TD>83.81985651</TD>
+ <TD>-5.39106185</TD>
+ <TD>0.15396</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>3.1808E-14</TD>
+ <TD>3.10464E-14</TD>
+ <TD>3.25773E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>19.3821</TD>
+ <TD>-0.173608</TD>
+ <TD>-0.219488</TD>
+ <TD>-0.128308</TD>
+ <TD>0.353016</TD>
+ <TD>0.30927</TD>
+ <TD>0.397048</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.7-052404</TD>
+ <TD>83.81985811</TD>
+ <TD>-5.40112096</TD>
+ <TD>0.14189</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>6.14592E-13</TD>
+ <TD>6.09573E-13</TD>
+ <TD>6.19661E-13</TD>
+ <TD>1.20933E-13</TD>
+ <TD>1.16357E-13</TD>
+ <TD>1.25557E-13</TD>
+ <TD>62.3506</TD>
+ <TD>0.076646</TD>
+ <TD>0.0642906</TD>
+ <TD>0.0891912</TD>
+ <TD>-0.0215484</TD>
+ <TD>-0.0345894</TD>
+ <TD>-0.0083578</TD>
+ <TD>10</TD>
+ <TD>1</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.9-052248</TD>
+ <TD>83.82067804</TD>
+ <TD>-5.38003602</TD>
+ <TD>0.26011</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.40385E-15</TD>
+ <TD>3.02903E-15</TD>
+ <TD>3.78245E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6.5724</TD>
+ <TD>-0.209941</TD>
+ <TD>-0.311983</TD>
+ <TD>-0.106149</TD>
+ <TD>0.20857</TD>
+ <TD>0.0992621</TD>
+ <TD>0.315503</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.9-052300</TD>
+ <TD>83.82072056</TD>
+ <TD>-5.38354443</TD>
+ <TD>0.1809</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>4.38438E-15</TD>
+ <TD>3.98639E-15</TD>
+ <TD>4.7864E-15</TD>
+ <TD>2.73814E-15</TD>
+ <TD>1.91129E-15</TD>
+ <TD>3.55782E-15</TD>
+ <TD>8.92446</TD>
+ <TD>0.0812748</TD>
+ <TD>-0.0200644</TD>
+ <TD>0.181062</TD>
+ <TD>0.304217</TD>
+ <TD>0.24567</TD>
+ <TD>0.364153</TD>
+ <TD>6</TD>
+ <TD>2</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.9-052336</TD>
+ <TD>83.82074477</TD>
+ <TD>-5.39357858</TD>
+ <TD>0.1656</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.65737E-15</TD>
+ <TD>6.25524E-15</TD>
+ <TD>7.06356E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>9.30035</TD>
+ <TD>0.379074</TD>
+ <TD>0.28605</TD>
+ <TD>0.470226</TD>
+ <TD>0.118246</TD>
+ <TD>0.0287847</TD>
+ <TD>0.205374</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.0-052232</TD>
+ <TD>83.82085444</TD>
+ <TD>-5.37579242</TD>
+ <TD>0.14172</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>5.12055E-13</TD>
+ <TD>5.09571E-13</TD>
+ <TD>5.14564E-13</TD>
+ <TD>1.51166E-13</TD>
+ <TD>1.46086E-13</TD>
+ <TD>1.56297E-13</TD>
+ <TD>104.461</TD>
+ <TD>0.0419094</TD>
+ <TD>0.0347495</TD>
+ <TD>0.0490269</TD>
+ <TD>-0.0550702</TD>
+ <TD>-0.0631752</TD>
+ <TD>-0.0471308</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.0-052339</TD>
+ <TD>83.82106838</TD>
+ <TD>-5.39432294</TD>
+ <TD>0.14281</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.18657E-14</TD>
+ <TD>6.09481E-14</TD>
+ <TD>6.27926E-14</TD>
+ <TD>1.1665E-13</TD>
+ <TD>1.1214E-13</TD>
+ <TD>1.21206E-13</TD>
+ <TD>32.3985</TD>
+ <TD>-0.0297006</TD>
+ <TD>-0.0531671</TD>
+ <TD>-0.00677787</TD>
+ <TD>-0.0486834</TD>
+ <TD>-0.0749776</TD>
+ <TD>-0.0224945</TD>
+ <TD>10</TD>
+ <TD>10</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.0-052333</TD>
+ <TD>83.82109826</TD>
+ <TD>-5.39273815</TD>
+ <TD>0.1631</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.02987E-12</TD>
+ <TD>1.02531E-12</TD>
+ <TD>1.03447E-12</TD>
+ <TD>8.75803E-14</TD>
+ <TD>8.36184E-14</TD>
+ <TD>9.15822E-14</TD>
+ <TD>127.499</TD>
+ <TD>0.630809</TD>
+ <TD>0.625237</TD>
+ <TD>0.636334</TD>
+ <TD>0.164965</TD>
+ <TD>0.161863</TD>
+ <TD>0.168062</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.1-052249</TD>
+ <TD>83.82131869</TD>
+ <TD>-5.38053261</TD>
+ <TD>0.19466</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>4.86951E-15</TD>
+ <TD>4.52284E-15</TD>
+ <TD>5.21969E-15</TD>
+ <TD>3.98751E-15</TD>
+ <TD>3.07147E-15</TD>
+ <TD>4.89601E-15</TD>
+ <TD>12.7202</TD>
+ <TD>-0.143314</TD>
+ <TD>-0.192783</TD>
+ <TD>-0.0933213</TD>
+ <TD>-0.259469</TD>
+ <TD>-0.324615</TD>
+ <TD>-0.193064</TD>
+ <TD>7</TD>
+ <TD>1</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.2-052316</TD>
+ <TD>83.82189417</TD>
+ <TD>-5.38789001</TD>
+ <TD>0.14245</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>5.88682E-14</TD>
+ <TD>5.81311E-14</TD>
+ <TD>5.96127E-14</TD>
+ <TD>8.88455E-14</TD>
+ <TD>8.48444E-14</TD>
+ <TD>9.2887E-14</TD>
+ <TD>38.8741</TD>
+ <TD>-0.106269</TD>
+ <TD>-0.113609</TD>
+ <TD>-0.0990529</TD>
+ <TD>-0.77797</TD>
+ <TD>-0.792073</TD>
+ <TD>-0.76355</TD>
+ <TD>0</TD>
+ <TD>0</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.2-052423</TD>
+ <TD>83.82196154</TD>
+ <TD>-5.40666165</TD>
+ <TD>0.21976</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>2.62389E-15</TD>
+ <TD>2.3843E-15</TD>
+ <TD>2.8659E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>7.6888</TD>
+ <TD>-0.19058</TD>
+ <TD>-0.261001</TD>
+ <TD>-0.121977</TD>
+ <TD>-0.414758</TD>
+ <TD>-0.517638</TD>
+ <TD>-0.308909</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.3-052235</TD>
+ <TD>83.82228078</TD>
+ <TD>-5.37653942</TD>
+ <TD>0.20984</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.84579E-15</TD>
+ <TD>5.32199E-15</TD>
+ <TD>6.37489E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>7.45895</TD>
+ <TD>0.699469</TD>
+ <TD>0.607403</TD>
+ <TD>0.789528</TD>
+ <TD>0.114261</TD>
+ <TD>0.0656462</TD>
+ <TD>0.162743</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.3-052245</TD>
+ <TD>83.82234198</TD>
+ <TD>-5.37931217</TD>
+ <TD>0.22014</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.80224E-15</TD>
+ <TD>6.2389E-15</TD>
+ <TD>7.37126E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6.6703</TD>
+ <TD>0.396609</TD>
+ <TD>0.282738</TD>
+ <TD>0.50787</TD>
+ <TD>0.268918</TD>
+ <TD>0.209931</TD>
+ <TD>0.329087</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.3-052304</TD>
+ <TD>83.82237467</TD>
+ <TD>-5.38461745</TD>
+ <TD>0.42463</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>9.77684E-15</TD>
+ <TD>8.70144E-15</TD>
+ <TD>1.08631E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>9.49126</TD>
+ <TD>-0.0447789</TD>
+ <TD>-0.143927</TD>
+ <TD>0.0521108</TD>
+ <TD>0.394111</TD>
+ <TD>0.311405</TD>
+ <TD>0.47619</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.3-052400</TD>
+ <TD>83.8224061</TD>
+ <TD>-5.40002211</TD>
+ <TD>0.18139</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.85293E-14</TD>
+ <TD>1.74155E-14</TD>
+ <TD>1.96543E-14</TD>
+ <TD>3.45141E-15</TD>
+ <TD>2.58232E-15</TD>
+ <TD>4.31257E-15</TD>
+ <TD>9.24279</TD>
+ <TD>0.755474</TD>
+ <TD>0.695403</TD>
+ <TD>0.810355</TD>
+ <TD>0.0939339</TD>
+ <TD>0.0661719</TD>
+ <TD>0.1257</TD>
+ <TD>8</TD>
+ <TD>1</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.3-052413</TD>
+ <TD>83.82244801</TD>
+ <TD>-5.40381331</TD>
+ <TD>0.19226</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>4.69414E-15</TD>
+ <TD>4.36344E-15</TD>
+ <TD>5.02817E-15</TD>
+ <TD>2.84905E-15</TD>
+ <TD>2.06367E-15</TD>
+ <TD>3.63713E-15</TD>
+ <TD>7.67701</TD>
+ <TD>-0.186065</TD>
+ <TD>-0.262651</TD>
+ <TD>-0.104858</TD>
+ <TD>-0.0730942</TD>
+ <TD>-0.173102</TD>
+ <TD>0.029691</TD>
+ <TD>2</TD>
+ <TD>1</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.4-052320</TD>
+ <TD>83.82275909</TD>
+ <TD>-5.38913778</TD>
+ <TD>0.14305</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.19418E-14</TD>
+ <TD>6.10112E-14</TD>
+ <TD>6.28819E-14</TD>
+ <TD>9.46104E-14</TD>
+ <TD>9.05153E-14</TD>
+ <TD>9.87468E-14</TD>
+ <TD>33.9473</TD>
+ <TD>-0.120336</TD>
+ <TD>-0.139946</TD>
+ <TD>-0.100275</TD>
+ <TD>-0.173029</TD>
+ <TD>-0.198721</TD>
+ <TD>-0.147012</TD>
+ <TD>8</TD>
+ <TD>2</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.4-052251</TD>
+ <TD>83.82278772</TD>
+ <TD>-5.38085618</TD>
+ <TD>0.26154</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.59443E-14</TD>
+ <TD>1.48174E-14</TD>
+ <TD>1.70825E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>10.3217</TD>
+ <TD>0.967824</TD>
+ <TD>0.948424</TD>
+ <TD>0.983472</TD>
+ <TD>-0.0020122</TD>
+ <TD>-0.0129</TD>
+ <TD>0.00778932</TD>
+ <TD>10</TD>
+ <TD>-32768</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.4-052417</TD>
+ <TD>83.8228207</TD>
+ <TD>-5.40476643</TD>
+ <TD>0.17747</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.73012E-15</TD>
+ <TD>6.40928E-15</TD>
+ <TD>7.0542E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>12.4071</TD>
+ <TD>-0.134308</TD>
+ <TD>-0.178341</TD>
+ <TD>-0.0910805</TD>
+ <TD>-0.39546</TD>
+ <TD>-0.458828</TD>
+ <TD>-0.332525</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.5-052256</TD>
+ <TD>83.82316819</TD>
+ <TD>-5.38239764</TD>
+ <TD>0.15331</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.83102E-14</TD>
+ <TD>2.76496E-14</TD>
+ <TD>2.89775E-14</TD>
+ <TD>7.30177E-15</TD>
+ <TD>6.08289E-15</TD>
+ <TD>8.53297E-15</TD>
+ <TD>22.5382</TD>
+ <TD>0.210574</TD>
+ <TD>0.174935</TD>
+ <TD>0.245433</TD>
+ <TD>0.0311087</TD>
+ <TD>-0.00287664</TD>
+ <TD>0.0657481</TD>
+ <TD>10</TD>
+ <TD>1</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.7-052230</TD>
+ <TD>83.82394082</TD>
+ <TD>-5.37517547</TD>
+ <TD>0.492273</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>2.57352E-15</TD>
+ <TD>2.04402E-15</TD>
+ <TD>3.10329E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>4.97905</TD>
+ <TD>0.435106</TD>
+ <TD>0.290564</TD>
+ <TD>0.573409</TD>
+ <TD>0.166767</TD>
+ <TD>0.0640562</TD>
+ <TD>0.265173</TD>
+ <TD>2</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.7-052342</TD>
+ <TD>83.82403421</TD>
+ <TD>-5.39507242</TD>
+ <TD>0.2641</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.22294E-14</TD>
+ <TD>2.09875E-14</TD>
+ <TD>2.34839E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>14.6498</TD>
+ <TD>0.393985</TD>
+ <TD>0.336088</TD>
+ <TD>0.450833</TD>
+ <TD>0.236858</TD>
+ <TD>0.205778</TD>
+ <TD>0.268504</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.7-052344</TD>
+ <TD>83.82408397</TD>
+ <TD>-5.39556838</TD>
+ <TD>0.15493</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>4.40876E-14</TD>
+ <TD>4.30497E-14</TD>
+ <TD>4.5136E-14</TD>
+ <TD>6.16894E-15</TD>
+ <TD>5.06292E-15</TD>
+ <TD>7.28614E-15</TD>
+ <TD>24.0684</TD>
+ <TD>-0.0935179</TD>
+ <TD>-0.125494</TD>
+ <TD>-0.0616643</TD>
+ <TD>0.012234</TD>
+ <TD>-0.0249415</TD>
+ <TD>0.0495115</TD>
+ <TD>9</TD>
+ <TD>1</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.8-052315</TD>
+ <TD>83.82422327</TD>
+ <TD>-5.38761097</TD>
+ <TD>0.14969</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.14931E-14</TD>
+ <TD>2.09499E-14</TD>
+ <TD>2.20418E-14</TD>
+ <TD>5.5013E-15</TD>
+ <TD>4.37611E-15</TD>
+ <TD>6.62636E-15</TD>
+ <TD>21.7772</TD>
+ <TD>-0.0485423</TD>
+ <TD>-0.0781495</TD>
+ <TD>-0.0186874</TD>
+ <TD>-0.238534</TD>
+ <TD>-0.27681</TD>
+ <TD>-0.200386</TD>
+ <TD>9</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.8-052302</TD>
+ <TD>83.82443905</TD>
+ <TD>-5.38414023</TD>
+ <TD>0.15408</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>2.47255E-14</TD>
+ <TD>2.41076E-14</TD>
+ <TD>2.53496E-14</TD>
+ <TD>3.99183E-15</TD>
+ <TD>3.06073E-15</TD>
+ <TD>4.9291E-15</TD>
+ <TD>19.745</TD>
+ <TD>0.0294182</TD>
+ <TD>-0.0120983</TD>
+ <TD>0.0706036</TD>
+ <TD>0.152762</TD>
+ <TD>0.111578</TD>
+ <TD>0.19379</TD>
+ <TD>8</TD>
+ <TD>0</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.9-052245</TD>
+ <TD>83.82479363</TD>
+ <TD>-5.37929955</TD>
+ <TD>0.40131</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>2.34246E-12</TD>
+ <TD>2.33673E-12</TD>
+ <TD>2.34825E-12</TD>
+ <TD>7.72945E-13</TD>
+ <TD>7.61515E-13</TD>
+ <TD>7.8449E-13</TD>
+ <TD>192.113</TD>
+ <TD>0.176657</TD>
+ <TD>0.172692</TD>
+ <TD>0.180645</TD>
+ <TD>-0.017412</TD>
+ <TD>-0.021351</TD>
+ <TD>-0.0134155</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.9-052335</TD>
+ <TD>83.82483373</TD>
+ <TD>-5.39311699</TD>
+ <TD>0.159</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.0092E-15</TD>
+ <TD>4.57792E-15</TD>
+ <TD>5.44484E-15</TD>
+ <TD>6.66509E-15</TD>
+ <TD>5.48228E-15</TD>
+ <TD>7.85984E-15</TD>
+ <TD>7.34797</TD>
+ <TD>-0.194774</TD>
+ <TD>-0.261407</TD>
+ <TD>-0.128891</TD>
+ <TD>-0.309379</TD>
+ <TD>-0.418885</TD>
+ <TD>-0.197315</TD>
+ <TD>0</TD>
+ <TD>0</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.9-052240</TD>
+ <TD>83.82493994</TD>
+ <TD>-5.37799385</TD>
+ <TD>0.46551</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>4.98307E-15</TD>
+ <TD>4.215E-15</TD>
+ <TD>5.75889E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6.08887</TD>
+ <TD>0.0498089</TD>
+ <TD>-0.0437402</TD>
+ <TD>0.140453</TD>
+ <TD>-0.46677</TD>
+ <TD>-0.579925</TD>
+ <TD>-0.351098</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.0-052402</TD>
+ <TD>83.82516072</TD>
+ <TD>-5.40081854</TD>
+ <TD>0.15291</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>4.64651E-14</TD>
+ <TD>4.5185E-14</TD>
+ <TD>4.77582E-14</TD>
+ <TD>7.56507E-15</TD>
+ <TD>6.29819E-15</TD>
+ <TD>8.84474E-15</TD>
+ <TD>17.849</TD>
+ <TD>0.336557</TD>
+ <TD>0.286851</TD>
+ <TD>0.385379</TD>
+ <TD>0.252672</TD>
+ <TD>0.224712</TD>
+ <TD>0.280702</TD>
+ <TD>9</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.0-052400</TD>
+ <TD>83.82528688</TD>
+ <TD>-5.40027107</TD>
+ <TD>0.14991</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>4.04349E-14</TD>
+ <TD>3.94916E-14</TD>
+ <TD>4.13877E-14</TD>
+ <TD>1.52375E-14</TD>
+ <TD>1.35145E-14</TD>
+ <TD>1.6978E-14</TD>
+ <TD>29.5094</TD>
+ <TD>-0.0313176</TD>
+ <TD>-0.0572702</TD>
+ <TD>-0.00540553</TD>
+ <TD>-0.028688</TD>
+ <TD>-0.057877</TD>
+ <TD>4.73572E-4</TD>
+ <TD>9</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.2-052335</TD>
+ <TD>83.82583666</TD>
+ <TD>-5.39324991</TD>
+ <TD>0.14673</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.27032E-14</TD>
+ <TD>6.15475E-14</TD>
+ <TD>6.38706E-14</TD>
+ <TD>1.45277E-14</TD>
+ <TD>1.28904E-14</TD>
+ <TD>1.61815E-14</TD>
+ <TD>40.8634</TD>
+ <TD>0.339068</TD>
+ <TD>0.319449</TD>
+ <TD>0.358484</TD>
+ <TD>0.0682079</TD>
+ <TD>0.0523278</TD>
+ <TD>0.0839731</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.2-052315</TD>
+ <TD>83.82596286</TD>
+ <TD>-5.38760267</TD>
+ <TD>0.34924</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>2.1647E-15</TD>
+ <TD>1.51151E-15</TD>
+ <TD>2.81364E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.55219</TD>
+ <TD>-0.0952553</TD>
+ <TD>-0.219541</TD>
+ <TD>0.0294111</TD>
+ <TD>-0.273004</TD>
+ <TD>-0.45569</TD>
+ <TD>-0.066292</TD>
+ <TD>2</TD>
+ <TD>-32768</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.3-052241</TD>
+ <TD>83.82636223</TD>
+ <TD>-5.37814958</TD>
+ <TD>0.52516</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>4.78337E-15</TD>
+ <TD>4.06288E-15</TD>
+ <TD>5.51113E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6.91727</TD>
+ <TD>-0.01251</TD>
+ <TD>-0.0998448</TD>
+ <TD>0.0765684</TD>
+ <TD>-0.32761</TD>
+ <TD>-0.437286</TD>
+ <TD>-0.213264</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.3-052404</TD>
+ <TD>83.82637823</TD>
+ <TD>-5.40130088</TD>
+ <TD>0.15454</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.50312E-14</TD>
+ <TD>1.4616E-14</TD>
+ <TD>1.54506E-14</TD>
+ <TD>9.74068E-15</TD>
+ <TD>8.39717E-15</TD>
+ <TD>1.10978E-14</TD>
+ <TD>18.2882</TD>
+ <TD>-0.0170644</TD>
+ <TD>-0.0451244</TD>
+ <TD>0.0113308</TD>
+ <TD>-0.496462</TD>
+ <TD>-0.534808</TD>
+ <TD>-0.457924</TD>
+ <TD>10</TD>
+ <TD>2</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.3-052237</TD>
+ <TD>83.82655004</TD>
+ <TD>-5.37707075</TD>
+ <TD>0.4015</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.51757E-12</TD>
+ <TD>1.51311E-12</TD>
+ <TD>1.52209E-12</TD>
+ <TD>4.8168E-13</TD>
+ <TD>4.72606E-13</TD>
+ <TD>4.90845E-13</TD>
+ <TD>156.029</TD>
+ <TD>0.0817165</TD>
+ <TD>0.0766781</TD>
+ <TD>0.0867794</TD>
+ <TD>-0.0223465</TD>
+ <TD>-0.02765</TD>
+ <TD>-0.0171189</TD>
+ <TD>10</TD>
+ <TD>9</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.4-052406</TD>
+ <TD>83.82694247</TD>
+ <TD>-5.40191265</TD>
+ <TD>0.16124</TD>
+ <TD>T</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.37515E-14</TD>
+ <TD>1.33676E-14</TD>
+ <TD>1.41392E-14</TD>
+ <TD>2.62695E-15</TD>
+ <TD>1.92102E-15</TD>
+ <TD>3.45326E-15</TD>
+ <TD>20.2619</TD>
+ <TD>-0.147293</TD>
+ <TD>-0.177667</TD>
+ <TD>-0.116693</TD>
+ <TD>-0.254688</TD>
+ <TD>-0.297129</TD>
+ <TD>-0.212164</TD>
+ <TD>9</TD>
+ <TD>2</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.5-052329</TD>
+ <TD>83.82710603</TD>
+ <TD>-5.39139544</TD>
+ <TD>0.29924</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.55482E-15</TD>
+ <TD>3.07533E-15</TD>
+ <TD>4.03916E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>5.19601</TD>
+ <TD>0.0224992</TD>
+ <TD>-0.0885241</TD>
+ <TD>0.133507</TD>
+ <TD>0.0140313</TD>
+ <TD>-0.100449</TD>
+ <TD>0.13251</TD>
+ <TD>9</TD>
+ <TD>-32768</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.6-052313</TD>
+ <TD>83.82775602</TD>
+ <TD>-5.3871475</TD>
+ <TD>0.1553</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.06073E-14</TD>
+ <TD>4.95229E-14</TD>
+ <TD>5.17026E-14</TD>
+ <TD>2.48157E-15</TD>
+ <TD>1.74615E-15</TD>
+ <TD>3.21853E-15</TD>
+ <TD>20.3047</TD>
+ <TD>0.711247</TD>
+ <TD>0.680913</TD>
+ <TD>0.740575</TD>
+ <TD>0.0977837</TD>
+ <TD>0.0822936</TD>
+ <TD>0.113861</TD>
+ <TD>8</TD>
+ <TD>1</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.7-052256</TD>
+ <TD>83.82792335</TD>
+ <TD>-5.38241003</TD>
+ <TD>0.14563</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>8.38129E-14</TD>
+ <TD>8.2714E-14</TD>
+ <TD>8.49229E-14</TD>
+ <TD>2.00977E-14</TD>
+ <TD>1.81923E-14</TD>
+ <TD>2.20222E-14</TD>
+ <TD>40.7387</TD>
+ <TD>0.0572374</TD>
+ <TD>0.03632</TD>
+ <TD>0.0779274</TD>
+ <TD>0.156319</TD>
+ <TD>0.136481</TD>
+ <TD>0.175857</TD>
+ <TD>10</TD>
+ <TD>6</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.8-052306</TD>
+ <TD>83.8285511</TD>
+ <TD>-5.38520688</TD>
+ <TD>0.38307</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.13434E-15</TD>
+ <TD>2.6248E-15</TD>
+ <TD>3.64903E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>4.10098</TD>
+ <TD>0.517024</TD>
+ <TD>0.387492</TD>
+ <TD>0.647882</TD>
+ <TD>0.136221</TD>
+ <TD>0.0452547</TD>
+ <TD>0.223087</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ <TD>3</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.8-052328</TD>
+ <TD>83.82863504</TD>
+ <TD>-5.39130935</TD>
+ <TD>0.18426</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>7.80936E-15</TD>
+ <TD>7.34268E-15</TD>
+ <TD>8.28074E-15</TD>
+ <TD>3.41606E-15</TD>
+ <TD>2.54272E-15</TD>
+ <TD>4.2936E-15</TD>
+ <TD>13.5089</TD>
+ <TD>0.148336</TD>
+ <TD>0.0862114</TD>
+ <TD>0.209109</TD>
+ <TD>0.116938</TD>
+ <TD>0.0606527</TD>
+ <TD>0.17337</TD>
+ <TD>8</TD>
+ <TD>0</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.8-052417</TD>
+ <TD>83.82870493</TD>
+ <TD>-5.40479945</TD>
+ <TD>0.2054</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>2.02885E-15</TD>
+ <TD>1.8429E-15</TD>
+ <TD>2.21669E-15</TD>
+ <TD>2.54071E-15</TD>
+ <TD>1.81143E-15</TD>
+ <TD>3.27084E-15</TD>
+ <TD>7.47107</TD>
+ <TD>-0.111318</TD>
+ <TD>-0.206769</TD>
+ <TD>-0.0157024</TD>
+ <TD>-0.105823</TD>
+ <TD>-0.217557</TD>
+ <TD>0.0062841</TD>
+ <TD>7</TD>
+ <TD>1</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.9-052321</TD>
+ <TD>83.82900851</TD>
+ <TD>-5.38938879</TD>
+ <TD>0.18377</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>6.29657E-15</TD>
+ <TD>5.91494E-15</TD>
+ <TD>6.68206E-15</TD>
+ <TD>3.93679E-15</TD>
+ <TD>3.03809E-15</TD>
+ <TD>4.84281E-15</TD>
+ <TD>9.75966</TD>
+ <TD>-0.197391</TD>
+ <TD>-0.257914</TD>
+ <TD>-0.136809</TD>
+ <TD>-0.0810207</TD>
+ <TD>-0.173516</TD>
+ <TD>0.0124436</TD>
+ <TD>8</TD>
+ <TD>2</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.0-052349</TD>
+ <TD>83.82943179</TD>
+ <TD>-5.39707745</TD>
+ <TD>0.18362</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.26527E-14</TD>
+ <TD>1.19883E-14</TD>
+ <TD>1.33238E-14</TD>
+ <TD>2.50362E-15</TD>
+ <TD>1.77341E-15</TD>
+ <TD>3.23775E-15</TD>
+ <TD>9.53704</TD>
+ <TD>0.525423</TD>
+ <TD>0.46124</TD>
+ <TD>0.588078</TD>
+ <TD>0.0552625</TD>
+ <TD>0.0168023</TD>
+ <TD>0.0953571</TD>
+ <TD>3</TD>
+ <TD>0</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.0-052307</TD>
+ <TD>83.82947555</TD>
+ <TD>-5.38538553</TD>
+ <TD>0.60007</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.06568E-15</TD>
+ <TD>2.35388E-15</TD>
+ <TD>3.77334E-15</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3.37258</TD>
+ <TD>0.551788</TD>
+ <TD>0.364172</TD>
+ <TD>0.730936</TD>
+ <TD>0.0525947</TD>
+ <TD>-0.0788357</TD>
+ <TD>0.180734</TD>
+ <TD>1</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.1-052326</TD>
+ <TD>83.82965729</TD>
+ <TD>-5.39079219</TD>
+ <TD>0.149</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>4.70476E-14</TD>
+ <TD>4.6041E-14</TD>
+ <TD>4.80644E-14</TD>
+ <TD>3.13813E-14</TD>
+ <TD>2.90203E-14</TD>
+ <TD>3.37661E-14</TD>
+ <TD>29.1204</TD>
+ <TD>-0.0186874</TD>
+ <TD>-0.0455405</TD>
+ <TD>0.00832042</TD>
+ <TD>0.0217701</TD>
+ <TD>-0.00797979</TD>
+ <TD>0.0513939</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.2-052250</TD>
+ <TD>83.83003508</TD>
+ <TD>-5.38069248</TD>
+ <TD>0.14563</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>7.71165E-14</TD>
+ <TD>7.6122E-14</TD>
+ <TD>7.8121E-14</TD>
+ <TD>2.18413E-14</TD>
+ <TD>1.98589E-14</TD>
+ <TD>2.38437E-14</TD>
+ <TD>35.1845</TD>
+ <TD>0.0103539</TD>
+ <TD>-0.0123992</TD>
+ <TD>0.033453</TD>
+ <TD>0.0622218</TD>
+ <TD>0.03835</TD>
+ <TD>0.0862733</TD>
+ <TD>8</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.3-052306</TD>
+ <TD>83.83073658</TD>
+ <TD>-5.38508642</TD>
+ <TD>0.20406</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.86105E-15</TD>
+ <TD>3.52179E-15</TD>
+ <TD>4.20375E-15</TD>
+ <TD>1.51947E-14</TD>
+ <TD>1.35327E-14</TD>
+ <TD>1.68735E-14</TD>
+ <TD>9.03109</TD>
+ <TD>0.70885</TD>
+ <TD>0.64733</TD>
+ <TD>0.762836</TD>
+ <TD>0.118635</TD>
+ <TD>0.0899835</TD>
+ <TD>0.149562</TD>
+ <TD>8</TD>
+ <TD>2</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.6-052357</TD>
+ <TD>83.83170407</TD>
+ <TD>-5.3992085</TD>
+ <TD>0.14599</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>5.65477E-14</TD>
+ <TD>5.57404E-14</TD>
+ <TD>5.73631E-14</TD>
+ <TD>1.58911E-14</TD>
+ <TD>1.41853E-14</TD>
+ <TD>1.76143E-14</TD>
+ <TD>33.2056</TD>
+ <TD>-0.0563964</TD>
+ <TD>-0.0777684</TD>
+ <TD>-0.0345916</TD>
+ <TD>-0.0881097</TD>
+ <TD>-0.114265</TD>
+ <TD>-0.0616321</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.6-052303</TD>
+ <TD>83.83180325</TD>
+ <TD>-5.38429503</TD>
+ <TD>0.28673</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>3.38795E-14</TD>
+ <TD>3.25298E-14</TD>
+ <TD>3.52428E-14</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>24.1923</TD>
+ <TD>0.521923</TD>
+ <TD>0.490019</TD>
+ <TD>0.552917</TD>
+ <TD>0.168157</TD>
+ <TD>0.148041</TD>
+ <TD>0.187617</TD>
+ <TD>10</TD>
+ <TD>-32768</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053520.1-052308</TD>
+ <TD>83.83405767</TD>
+ <TD>-5.38565134</TD>
+ <TD>0.17176</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.6732E-14</TD>
+ <TD>1.60671E-14</TD>
+ <TD>1.74036E-14</TD>
+ <TD>8.91914E-15</TD>
+ <TD>7.62577E-15</TD>
+ <TD>1.02256E-14</TD>
+ <TD>16.7378</TD>
+ <TD>0.704872</TD>
+ <TD>0.667655</TD>
+ <TD>0.74077</TD>
+ <TD>0.0802904</TD>
+ <TD>0.0564153</TD>
+ <TD>0.103995</TD>
+ <TD>9</TD>
+ <TD>8</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053520.4-052329</TD>
+ <TD>83.83524928</TD>
+ <TD>-5.39157915</TD>
+ <TD>0.14495</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>1.48294E-13</TD>
+ <TD>1.46302E-13</TD>
+ <TD>1.50305E-13</TD>
+ <TD>6.19981E-14</TD>
+ <TD>5.87156E-14</TD>
+ <TD>6.53138E-14</TD>
+ <TD>37.6376</TD>
+ <TD>-0.0342289</TD>
+ <TD>-0.0543452</TD>
+ <TD>-0.0144118</TD>
+ <TD>-0.0400774</TD>
+ <TD>-0.0630867</TD>
+ <TD>-0.0171071</TD>
+ <TD>10</TD>
+ <TD>0</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053520.6-052353</TD>
+ <TD>83.83613982</TD>
+ <TD>-5.39807062</TD>
+ <TD>0.14505</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.22974E-13</TD>
+ <TD>1.21659E-13</TD>
+ <TD>1.24301E-13</TD>
+ <TD>3.53667E-14</TD>
+ <TD>3.28387E-14</TD>
+ <TD>3.79203E-14</TD>
+ <TD>51.6767</TD>
+ <TD>-0.0736723</TD>
+ <TD>-0.0873284</TD>
+ <TD>-0.0601008</TD>
+ <TD>-0.114096</TD>
+ <TD>-0.131036</TD>
+ <TD>-0.0970645</TD>
+ <TD>10</TD>
+ <TD>8</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053520.9-052321</TD>
+ <TD>83.83713079</TD>
+ <TD>-5.38937613</TD>
+ <TD>0.17294</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>F</TD>
+ <TD>1.27352E-14</TD>
+ <TD>1.22038E-14</TD>
+ <TD>1.32719E-14</TD>
+ <TD>4.79489E-15</TD>
+ <TD>3.76627E-15</TD>
+ <TD>5.82531E-15</TD>
+ <TD>15.092</TD>
+ <TD>-0.00451392</TD>
+ <TD>-0.0506769</TD>
+ <TD>0.0414142</TD>
+ <TD>-0.143189</TD>
+ <TD>-0.198027</TD>
+ <TD>-0.0872535</TD>
+ <TD>9</TD>
+ <TD>1</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053521.0-052348</TD>
+ <TD>83.83769663</TD>
+ <TD>-5.39690299</TD>
+ <TD>0.16319</TD>
+ <TD>F</TD>
+ <TD>T</TD>
+ <TD>F</TD>
+ <TD>9.62079E-13</TD>
+ <TD>9.58324E-13</TD>
+ <TD>9.65871E-13</TD>
+ <TD>4.11609E-13</TD>
+ <TD>4.032E-13</TD>
+ <TD>4.20101E-13</TD>
+ <TD>120.381</TD>
+ <TD>0.0273304</TD>
+ <TD>0.0211311</TD>
+ <TD>0.0335637</TD>
+ <TD>-0.0775369</TD>
+ <TD>-0.0845064</TD>
+ <TD>-0.070693</TD>
+ <TD>10</TD>
+ <TD>5</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+</TABLEDATA>
+</DATA>
+</TABLE>
+</RESOURCE>
+</VOTABLE>
diff --git a/pkg/utilities/nttools/zz_rewrite.xml b/pkg/utilities/nttools/zz_rewrite.xml
new file mode 100644
index 00000000..d3e2b883
--- /dev/null
+++ b/pkg/utilities/nttools/zz_rewrite.xml
@@ -0,0 +1,1191 @@
+<?xml version='1.0'?>
+<VOTABLE version="1.1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.ivoa.net/xml/VOTable/v1.1 http://www.ivoa.net/xml/VOTable/v1.1"
+ xmlns="http://www.ivoa.net/xml/VOTable/v1.1">
+<!--
+ ! VOTable written by STIL version 3.0-3 (uk.ac.starlink.votable.VOTableWriter)
+ ! at 2012-11-13T19:40:48
+ !-->
+<RESOURCE>
+<TABLE name="RA:83.8221,DEC:-5.39111,SR:0.01666,VERB:2,TIME:2012/10/18_10:31:06" nrows="127">
+<DESCRIPTION>
+Chandra Source Catalog VO Cone Search Service
+</DESCRIPTION>
+<PARAM arraysize="2" datatype="char" name="TimeScale" utype="stc:AstroCoordSystem.TimeFrame.TimeScale" value="TT"/>
+<PARAM arraysize="10" datatype="char" name="TimeRefPosition" utype="stc:AstroCoordSystem.TimeFrame.ReferencePosition" value="TOPOCENTER"/>
+<PARAM arraysize="4" datatype="char" name="SpaceRefFrame" utype="stc:AstroCoordSystem.SpaceFrame.SpaceRefFrame" value="ICRS"/>
+<PARAM arraysize="10" datatype="char" name="SpaceRefPosition" utype="stc:AstroCoordSystem.SpaceFrame.ReferencePosition" value="TOPOCENTER"/>
+<PARAM arraysize="10" datatype="char" name="SpectralRefPosition" utype="stc:AstroCoordSystem.SpectralFrame.ReferencePosition" value="TOPOCENTER"/>
+<PARAM arraysize="4" datatype="char" name="cooframe" ucd="pos.frame" utype="stc:AstroCoords.coord_system_id" value="ICRS"/>
+<FIELD ID="col0" arraysize="*" datatype="char" name="name" ucd="meta.id;meta.main" width="20">
+<DESCRIPTION>Source name in the format 'CXO Jhhmmss.s +/- ddmmss'</DESCRIPTION>
+</FIELD>
+<FIELD ID="col1" arraysize="*" datatype="double" name="ra" precision="F5" ref="ICRScoords" ucd="pos.eq.ra;meta.main" utype="stc:AstroCoords.Position2D.Value2.C1" width="9">
+<DESCRIPTION>Source position, ICRS right ascension</DESCRIPTION>
+</FIELD>
+<FIELD ID="col2" arraysize="*" datatype="double" name="dec" precision="F5" ref="ICRScoords" ucd="pos.eq.dec;meta.main" utype="stc:AstroCoords.Position2D.Value2.C2" width="9">
+<DESCRIPTION>Source position, ICRS declination</DESCRIPTION>
+</FIELD>
+<FIELD ID="col10" arraysize="*" datatype="double" name="flux_aper_w" precision="E3" ucd="phot.flux;src.net;em.X-ray" unit="erg/s*cm^2" width="9">
+<DESCRIPTION>Aperture-corrected net energy flux inferred from the source region aperture, calculated by counting X-ray events; HRC wide energy band</DESCRIPTION>
+</FIELD>
+<FIELD ID="col11" arraysize="*" datatype="double" name="flux_aper_lolim_w" precision="E3" ucd="stat.error;phot.flux;src.net;stat.min;em.X-ray" unit="erg/s*cm^2" width="9">
+<DESCRIPTION>Aperture-corrected net energy flux inferred from the source region aperture, calculated by counting X-ray events (68% lower confidence limit); HRC wide energy band</DESCRIPTION>
+</FIELD>
+<FIELD ID="col22" arraysize="*" datatype="short" name="var_inter_index_b" ucd="src.var.index;em.X-ray" width="6">
+<DESCRIPTION>Inter-observation variability index in the range [0, 10]; indicates whether the source region photon flux is constant between observations; ACIS broad energy band</DESCRIPTION>
+</FIELD>
+<FIELD ID="col23" arraysize="*" datatype="short" name="var_inter_index_w" ucd="src.var.index;em.X-ray" width="6">
+<DESCRIPTION>Inter-observation variability index in the range [0, 10]; indicates whether the source region photon flux is constant between observations; HRC wide energy band</DESCRIPTION>
+</FIELD>
+<DATA>
+<TABLEDATA>
+ <TR>
+ <TD>CXO J053513.4-052340</TD>
+ <TD>83.80601567</TD>
+ <TD>-5.39448431</TD>
+ <TD>5.88765E-14</TD>
+ <TD>5.56953E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053513.5-052330</TD>
+ <TD>83.80637907</TD>
+ <TD>-5.39185304</TD>
+ <TD>3.03441E-14</TD>
+ <TD>2.80268E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053513.9-052319</TD>
+ <TD>83.80801443</TD>
+ <TD>-5.3888603</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.0-052338</TD>
+ <TD>83.8085595</TD>
+ <TD>-5.3939577</TD>
+ <TD>2.97063E-14</TD>
+ <TD>2.74026E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.2-052304</TD>
+ <TD>83.80953052</TD>
+ <TD>-5.38444889</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.3-052308</TD>
+ <TD>83.80962741</TD>
+ <TD>-5.38557712</TD>
+ <TD>1.05285E-14</TD>
+ <TD>9.11164E-15</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.3-052317</TD>
+ <TD>83.80969326</TD>
+ <TD>-5.38810981</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.3-052253</TD>
+ <TD>83.8098206</TD>
+ <TD>-5.3816407</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.4-052322</TD>
+ <TD>83.8099784</TD>
+ <TD>-5.38966568</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.3-052333</TD>
+ <TD>83.80998065</TD>
+ <TD>-5.39261156</TD>
+ <TD>1.46049E-14</TD>
+ <TD>1.29563E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.5-052315</TD>
+ <TD>83.81056936</TD>
+ <TD>-5.38772233</TD>
+ <TD>8.55561E-15</TD>
+ <TD>7.21816E-15</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.5-052407</TD>
+ <TD>83.81072267</TD>
+ <TD>-5.40217119</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.6-052328</TD>
+ <TD>83.81100284</TD>
+ <TD>-5.39122647</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.6-052301</TD>
+ <TD>83.81109487</TD>
+ <TD>-5.38379019</TD>
+ <TD>9.53745E-15</TD>
+ <TD>8.13605E-15</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.6-052249</TD>
+ <TD>83.81120139</TD>
+ <TD>-5.38033176</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.7-052412</TD>
+ <TD>83.81128448</TD>
+ <TD>-5.40343355</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.7-052322</TD>
+ <TD>83.81133486</TD>
+ <TD>-5.38964017</TD>
+ <TD>5.23879E-14</TD>
+ <TD>4.93591E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.8-052406</TD>
+ <TD>83.81170941</TD>
+ <TD>-5.40185359</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.8-052346</TD>
+ <TD>83.8117676</TD>
+ <TD>-5.39615671</TD>
+ <TD>1.26507E-14</TD>
+ <TD>1.10556E-14</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.8-052315</TD>
+ <TD>83.81177012</TD>
+ <TD>-5.38770869</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.8-052304</TD>
+ <TD>83.81193361</TD>
+ <TD>-5.38466425</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.9-052412</TD>
+ <TD>83.81217858</TD>
+ <TD>-5.40351021</TD>
+ <TD>1.58719E-14</TD>
+ <TD>1.41828E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.9-052328</TD>
+ <TD>83.81220892</TD>
+ <TD>-5.39133275</TD>
+ <TD>3.58725E-15</TD>
+ <TD>2.70965E-15</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053514.9-052338</TD>
+ <TD>83.81228445</TD>
+ <TD>-5.39416969</TD>
+ <TD>2.82477E-13</TD>
+ <TD>2.75562E-13</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.0-052354</TD>
+ <TD>83.81265915</TD>
+ <TD>-5.39841906</TD>
+ <TD>3.93214E-15</TD>
+ <TD>2.99955E-15</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.1-052304</TD>
+ <TD>83.81297046</TD>
+ <TD>-5.38451569</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.1-052346</TD>
+ <TD>83.81314399</TD>
+ <TD>-5.39621512</TD>
+ <TD>4.00059E-15</TD>
+ <TD>3.0109E-15</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.1-052254</TD>
+ <TD>83.81329418</TD>
+ <TD>-5.38172473</TD>
+ <TD>1.6316E-14</TD>
+ <TD>1.43274E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.1-052318</TD>
+ <TD>83.81330006</TD>
+ <TD>-5.3885408</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.2-052256</TD>
+ <TD>83.81360368</TD>
+ <TD>-5.38242218</TD>
+ <TD>2.6702E-13</TD>
+ <TD>2.60158E-13</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.3-052333</TD>
+ <TD>83.81407441</TD>
+ <TD>-5.39255272</TD>
+ <TD>1.93736E-14</TD>
+ <TD>1.7427E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.4-052345</TD>
+ <TD>83.81434295</TD>
+ <TD>-5.39590645</TD>
+ <TD>9.9547E-15</TD>
+ <TD>8.51468E-15</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.4-052248</TD>
+ <TD>83.8145085</TD>
+ <TD>-5.38011504</TD>
+ <TD>8.82286E-15</TD>
+ <TD>7.076E-15</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.4-052337</TD>
+ <TD>83.81455127</TD>
+ <TD>-5.39376129</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.5-052246</TD>
+ <TD>83.81473478</TD>
+ <TD>-5.37948293</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.6-052402</TD>
+ <TD>83.81504651</TD>
+ <TD>-5.40078793</TD>
+ <TD>5.66629E-14</TD>
+ <TD>5.35161E-14</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.6-052256</TD>
+ <TD>83.81514589</TD>
+ <TD>-5.3823026</TD>
+ <TD>2.02006E-12</TD>
+ <TD>2.00158E-12</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.7-052339</TD>
+ <TD>83.815411</TD>
+ <TD>-5.3941811</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.7-052411</TD>
+ <TD>83.81562914</TD>
+ <TD>-5.403203640000001</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.7-052338</TD>
+ <TD>83.8157219</TD>
+ <TD>-5.39390552</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.7-052309</TD>
+ <TD>83.81574739</TD>
+ <TD>-5.38606832</TD>
+ <TD>1.87491E-12</TD>
+ <TD>1.85709E-12</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052305</TD>
+ <TD>83.81588895</TD>
+ <TD>-5.38485094</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052313</TD>
+ <TD>83.815963</TD>
+ <TD>-5.38726978</TD>
+ <TD>1.01992E-12</TD>
+ <TD>1.00666E-12</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052245</TD>
+ <TD>83.81598875</TD>
+ <TD>-5.37934237</TD>
+ <TD>3.40691E-15</TD>
+ <TD>2.32026E-15</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052322</TD>
+ <TD>83.81610029</TD>
+ <TD>-5.38953689</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052318</TD>
+ <TD>83.81611207</TD>
+ <TD>-5.38856486</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052301</TD>
+ <TD>83.81612461</TD>
+ <TD>-5.38382611</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052233</TD>
+ <TD>83.81613303</TD>
+ <TD>-5.37585042</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.8-052310</TD>
+ <TD>83.81619</TD>
+ <TD>-5.3863028</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.9-052417</TD>
+ <TD>83.8162912</TD>
+ <TD>-5.40491845</TD>
+ <TD>3.78186E-15</TD>
+ <TD>2.91713E-15</TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053515.9-052349</TD>
+ <TD>83.81647584</TD>
+ <TD>-5.39713268</TD>
+ <TD>1.89669E-13</TD>
+ <TD>1.83958E-13</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052352</TD>
+ <TD>83.81675305</TD>
+ <TD>-5.39801365</TD>
+ <TD>1.48552E-14</TD>
+ <TD>1.31388E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052253</TD>
+ <TD>83.81698406</TD>
+ <TD>-5.38164426</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052306</TD>
+ <TD>83.81701311</TD>
+ <TD>-5.38522135</TD>
+ <TD>5.32069E-14</TD>
+ <TD>4.98546E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052325</TD>
+ <TD>83.8170161</TD>
+ <TD>-5.39040007</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052411</TD>
+ <TD>83.8170323</TD>
+ <TD>-5.4031178</TD>
+ <TD>3.44264E-15</TD>
+ <TD>2.59187E-15</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.0-052322</TD>
+ <TD>83.81705333</TD>
+ <TD>-5.3896635</TD>
+ <TD>9.51118E-15</TD>
+ <TD>6.51756E-15</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.1-052313</TD>
+ <TD>83.81720052</TD>
+ <TD>-5.38708875</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.1-052309</TD>
+ <TD>83.8172558</TD>
+ <TD>-5.38598655</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.1-052237</TD>
+ <TD>83.81744498</TD>
+ <TD>-5.37702105</TD>
+ <TD>3.88118E-15</TD>
+ <TD>2.96665E-15</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.2-052318</TD>
+ <TD>83.81746865</TD>
+ <TD>-5.38854714</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>4</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.2-052316</TD>
+ <TD>83.8178479</TD>
+ <TD>-5.38786385</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.3-052403</TD>
+ <TD>83.81822268</TD>
+ <TD>-5.40086482</TD>
+ <TD>1.1893E-13</TD>
+ <TD>1.14403E-13</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.4-052329</TD>
+ <TD>83.81859564</TD>
+ <TD>-5.39142135</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.4-052331</TD>
+ <TD>83.81861877</TD>
+ <TD>-5.39200198</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.4-052322</TD>
+ <TD>83.81863682</TD>
+ <TD>-5.38964395</TD>
+ <TD>1.93706E-11</TD>
+ <TD>1.93136E-11</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.4-052256</TD>
+ <TD>83.81868061</TD>
+ <TD>-5.38231438</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.4-052234</TD>
+ <TD>83.81869862</TD>
+ <TD>-5.37637281</TD>
+ <TD>3.92169E-15</TD>
+ <TD>2.98105E-15</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.5-052405</TD>
+ <TD>83.81907688</TD>
+ <TD>-5.40160715</TD>
+ <TD>2.21828E-14</TD>
+ <TD>2.01516E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.6-052315</TD>
+ <TD>83.81916799</TD>
+ <TD>-5.38771941</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.7-052231</TD>
+ <TD>83.81971948</TD>
+ <TD>-5.37529756</TD>
+ <TD>5.06829E-15</TD>
+ <TD>4.00493E-15</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.7-052316</TD>
+ <TD>83.81979918</TD>
+ <TD>-5.38783323</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.7-052327</TD>
+ <TD>83.81985651</TD>
+ <TD>-5.39106185</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.7-052404</TD>
+ <TD>83.81985811</TD>
+ <TD>-5.40112096</TD>
+ <TD>1.20933E-13</TD>
+ <TD>1.16357E-13</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.9-052248</TD>
+ <TD>83.82067804</TD>
+ <TD>-5.38003602</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.9-052300</TD>
+ <TD>83.82072056</TD>
+ <TD>-5.38354443</TD>
+ <TD>2.73814E-15</TD>
+ <TD>1.91129E-15</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053516.9-052336</TD>
+ <TD>83.82074477</TD>
+ <TD>-5.39357858</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.0-052232</TD>
+ <TD>83.82085444</TD>
+ <TD>-5.37579242</TD>
+ <TD>1.51166E-13</TD>
+ <TD>1.46086E-13</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.0-052339</TD>
+ <TD>83.82106838</TD>
+ <TD>-5.39432294</TD>
+ <TD>1.1665E-13</TD>
+ <TD>1.1214E-13</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.0-052333</TD>
+ <TD>83.82109826</TD>
+ <TD>-5.39273815</TD>
+ <TD>8.75803E-14</TD>
+ <TD>8.36184E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.1-052249</TD>
+ <TD>83.82131869</TD>
+ <TD>-5.38053261</TD>
+ <TD>3.98751E-15</TD>
+ <TD>3.07147E-15</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.2-052316</TD>
+ <TD>83.82189417</TD>
+ <TD>-5.38789001</TD>
+ <TD>8.88455E-14</TD>
+ <TD>8.48444E-14</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.2-052423</TD>
+ <TD>83.82196154</TD>
+ <TD>-5.40666165</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.3-052235</TD>
+ <TD>83.82228078</TD>
+ <TD>-5.37653942</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.3-052245</TD>
+ <TD>83.82234198</TD>
+ <TD>-5.37931217</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.3-052304</TD>
+ <TD>83.82237467</TD>
+ <TD>-5.38461745</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.3-052400</TD>
+ <TD>83.8224061</TD>
+ <TD>-5.40002211</TD>
+ <TD>3.45141E-15</TD>
+ <TD>2.58232E-15</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.3-052413</TD>
+ <TD>83.82244801</TD>
+ <TD>-5.40381331</TD>
+ <TD>2.84905E-15</TD>
+ <TD>2.06367E-15</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.4-052320</TD>
+ <TD>83.82275909</TD>
+ <TD>-5.38913778</TD>
+ <TD>9.46104E-14</TD>
+ <TD>9.05153E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.4-052251</TD>
+ <TD>83.82278772</TD>
+ <TD>-5.38085618</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.4-052417</TD>
+ <TD>83.8228207</TD>
+ <TD>-5.40476643</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.5-052256</TD>
+ <TD>83.82316819</TD>
+ <TD>-5.38239764</TD>
+ <TD>7.30177E-15</TD>
+ <TD>6.08289E-15</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.7-052230</TD>
+ <TD>83.82394082</TD>
+ <TD>-5.37517547</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.7-052342</TD>
+ <TD>83.82403421</TD>
+ <TD>-5.39507242</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.7-052344</TD>
+ <TD>83.82408397</TD>
+ <TD>-5.39556838</TD>
+ <TD>6.16894E-15</TD>
+ <TD>5.06292E-15</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.8-052315</TD>
+ <TD>83.82422327</TD>
+ <TD>-5.38761097</TD>
+ <TD>5.5013E-15</TD>
+ <TD>4.37611E-15</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.8-052302</TD>
+ <TD>83.82443905</TD>
+ <TD>-5.38414023</TD>
+ <TD>3.99183E-15</TD>
+ <TD>3.06073E-15</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.9-052245</TD>
+ <TD>83.82479363</TD>
+ <TD>-5.37929955</TD>
+ <TD>7.72945E-13</TD>
+ <TD>7.61515E-13</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.9-052335</TD>
+ <TD>83.82483373</TD>
+ <TD>-5.39311699</TD>
+ <TD>6.66509E-15</TD>
+ <TD>5.48228E-15</TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053517.9-052240</TD>
+ <TD>83.82493994</TD>
+ <TD>-5.37799385</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.0-052402</TD>
+ <TD>83.82516072</TD>
+ <TD>-5.40081854</TD>
+ <TD>7.56507E-15</TD>
+ <TD>6.29819E-15</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.0-052400</TD>
+ <TD>83.82528688</TD>
+ <TD>-5.40027107</TD>
+ <TD>1.52375E-14</TD>
+ <TD>1.35145E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.2-052335</TD>
+ <TD>83.82583666</TD>
+ <TD>-5.39324991</TD>
+ <TD>1.45277E-14</TD>
+ <TD>1.28904E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.2-052315</TD>
+ <TD>83.82596286</TD>
+ <TD>-5.38760267</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.3-052241</TD>
+ <TD>83.82636223</TD>
+ <TD>-5.37814958</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.3-052404</TD>
+ <TD>83.82637823</TD>
+ <TD>-5.40130088</TD>
+ <TD>9.74068E-15</TD>
+ <TD>8.39717E-15</TD>
+ <TD>6</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.3-052237</TD>
+ <TD>83.82655004</TD>
+ <TD>-5.37707075</TD>
+ <TD>4.8168E-13</TD>
+ <TD>4.72606E-13</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.4-052406</TD>
+ <TD>83.82694247</TD>
+ <TD>-5.40191265</TD>
+ <TD>2.62695E-15</TD>
+ <TD>1.92102E-15</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.5-052329</TD>
+ <TD>83.82710603</TD>
+ <TD>-5.39139544</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>0</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.6-052313</TD>
+ <TD>83.82775602</TD>
+ <TD>-5.3871475</TD>
+ <TD>2.48157E-15</TD>
+ <TD>1.74615E-15</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.7-052256</TD>
+ <TD>83.82792335</TD>
+ <TD>-5.38241003</TD>
+ <TD>2.00977E-14</TD>
+ <TD>1.81923E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.8-052306</TD>
+ <TD>83.8285511</TD>
+ <TD>-5.38520688</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>3</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.8-052328</TD>
+ <TD>83.82863504</TD>
+ <TD>-5.39130935</TD>
+ <TD>3.41606E-15</TD>
+ <TD>2.54272E-15</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.8-052417</TD>
+ <TD>83.82870493</TD>
+ <TD>-5.40479945</TD>
+ <TD>2.54071E-15</TD>
+ <TD>1.81143E-15</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053518.9-052321</TD>
+ <TD>83.82900851</TD>
+ <TD>-5.38938879</TD>
+ <TD>3.93679E-15</TD>
+ <TD>3.03809E-15</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.0-052349</TD>
+ <TD>83.82943179</TD>
+ <TD>-5.39707745</TD>
+ <TD>2.50362E-15</TD>
+ <TD>1.77341E-15</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.0-052307</TD>
+ <TD>83.82947555</TD>
+ <TD>-5.38538553</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>-32768</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.1-052326</TD>
+ <TD>83.82965729</TD>
+ <TD>-5.39079219</TD>
+ <TD>3.13813E-14</TD>
+ <TD>2.90203E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.2-052250</TD>
+ <TD>83.83003508</TD>
+ <TD>-5.38069248</TD>
+ <TD>2.18413E-14</TD>
+ <TD>1.98589E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.3-052306</TD>
+ <TD>83.83073658</TD>
+ <TD>-5.38508642</TD>
+ <TD>1.51947E-14</TD>
+ <TD>1.35327E-14</TD>
+ <TD>5</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.6-052357</TD>
+ <TD>83.83170407</TD>
+ <TD>-5.3992085</TD>
+ <TD>1.58911E-14</TD>
+ <TD>1.41853E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053519.6-052303</TD>
+ <TD>83.83180325</TD>
+ <TD>-5.38429503</TD>
+ <TD></TD>
+ <TD></TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053520.1-052308</TD>
+ <TD>83.83405767</TD>
+ <TD>-5.38565134</TD>
+ <TD>8.91914E-15</TD>
+ <TD>7.62577E-15</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053520.4-052329</TD>
+ <TD>83.83524928</TD>
+ <TD>-5.39157915</TD>
+ <TD>6.19981E-14</TD>
+ <TD>5.87156E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053520.6-052353</TD>
+ <TD>83.83613982</TD>
+ <TD>-5.39807062</TD>
+ <TD>3.53667E-14</TD>
+ <TD>3.28387E-14</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053520.9-052321</TD>
+ <TD>83.83713079</TD>
+ <TD>-5.38937613</TD>
+ <TD>4.79489E-15</TD>
+ <TD>3.76627E-15</TD>
+ <TD>7</TD>
+ <TD>-32768</TD>
+ </TR>
+ <TR>
+ <TD>CXO J053521.0-052348</TD>
+ <TD>83.83769663</TD>
+ <TD>-5.39690299</TD>
+ <TD>4.11609E-13</TD>
+ <TD>4.032E-13</TD>
+ <TD>8</TD>
+ <TD>-32768</TD>
+ </TR>
+</TABLEDATA>
+</DATA>
+</TABLE>
+</RESOURCE>
+</VOTABLE>