aboutsummaryrefslogtreecommitdiff
path: root/pkg/system
diff options
context:
space:
mode:
authorJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
committerJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
commit40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch)
tree4464880c571602d54f6ae114729bf62a89518057 /pkg/system
downloadiraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'pkg/system')
-rw-r--r--pkg/system/README5
-rw-r--r--pkg/system/bench.cl143
-rw-r--r--pkg/system/chkupdate.par5
-rw-r--r--pkg/system/chkupdate.x178
-rw-r--r--pkg/system/cmdstr.par2
-rw-r--r--pkg/system/cmdstr.x157
-rw-r--r--pkg/system/concatenate.par4
-rw-r--r--pkg/system/concatenate.x73
-rw-r--r--pkg/system/copy.par3
-rw-r--r--pkg/system/copy.x62
-rw-r--r--pkg/system/count.par1
-rw-r--r--pkg/system/count.x131
-rw-r--r--pkg/system/delete.par6
-rw-r--r--pkg/system/delete.x74
-rw-r--r--pkg/system/devices.cl3
-rw-r--r--pkg/system/directory.par6
-rw-r--r--pkg/system/directory.x561
-rw-r--r--pkg/system/doc/Sys.hlp349
-rw-r--r--pkg/system/doc/Sys_intro.hlp137
-rw-r--r--pkg/system/doc/allocate.hlp52
-rw-r--r--pkg/system/doc/bench.hlp56
-rw-r--r--pkg/system/doc/chkupdate.hlp72
-rw-r--r--pkg/system/doc/concatenate.hlp82
-rw-r--r--pkg/system/doc/copy.hlp47
-rw-r--r--pkg/system/doc/count.hlp44
-rw-r--r--pkg/system/doc/deallocate.hlp34
-rw-r--r--pkg/system/doc/delete.hlp57
-rw-r--r--pkg/system/doc/devstatus.hlp57
-rw-r--r--pkg/system/doc/directory.hlp148
-rw-r--r--pkg/system/doc/diskspace.hlp33
-rw-r--r--pkg/system/doc/fcache.hlp140
-rw-r--r--pkg/system/doc/files.hlp72
-rw-r--r--pkg/system/doc/gripes.hlp67
-rw-r--r--pkg/system/doc/head.hlp39
-rw-r--r--pkg/system/doc/help.hlp599
-rw-r--r--pkg/system/doc/lprint.hlp65
-rw-r--r--pkg/system/doc/match.hlp77
-rw-r--r--pkg/system/doc/mkdir.hlp34
-rw-r--r--pkg/system/doc/mkscript.hlp161
-rw-r--r--pkg/system/doc/movefiles.hlp38
-rw-r--r--pkg/system/doc/netstatus.hlp44
-rw-r--r--pkg/system/doc/news.hlp58
-rw-r--r--pkg/system/doc/page.hlp146
-rw-r--r--pkg/system/doc/pathnames.hlp42
-rw-r--r--pkg/system/doc/phelp.hlp61
-rw-r--r--pkg/system/doc/protect.hlp36
-rw-r--r--pkg/system/doc/references.hlp78
-rw-r--r--pkg/system/doc/rename.hlp69
-rw-r--r--pkg/system/doc/rewind.hlp36
-rw-r--r--pkg/system/doc/sort.hlp62
-rw-r--r--pkg/system/doc/spy.hlp26
-rw-r--r--pkg/system/doc/tail.hlp50
-rw-r--r--pkg/system/doc/tee.hlp36
-rw-r--r--pkg/system/doc/touch.hlp71
-rw-r--r--pkg/system/doc/type.hlp43
-rw-r--r--pkg/system/doc/unprotect.hlp27
-rw-r--r--pkg/system/doc/urlget.hlp84
-rw-r--r--pkg/system/fcache.par9
-rw-r--r--pkg/system/files.par2
-rw-r--r--pkg/system/files.x32
-rw-r--r--pkg/system/hdbexamine.par2
-rw-r--r--pkg/system/head.par2
-rw-r--r--pkg/system/head.x56
-rw-r--r--pkg/system/help.par31
-rw-r--r--pkg/system/help/README12
-rw-r--r--pkg/system/help/design.hlp500
-rw-r--r--pkg/system/help/filetemp.x28
-rw-r--r--pkg/system/help/getoption.x52
-rw-r--r--pkg/system/help/hbgetblk.x195
-rw-r--r--pkg/system/help/hdbexamine.hlp55
-rw-r--r--pkg/system/help/help.h115
-rw-r--r--pkg/system/help/helpdb.x1203
-rw-r--r--pkg/system/help/helpdir.h34
-rw-r--r--pkg/system/help/helpdir.x775
-rw-r--r--pkg/system/help/hinput.x274
-rw-r--r--pkg/system/help/houtput.x147
-rw-r--r--pkg/system/help/lroff/breakline.obin0 -> 2788 bytes
-rw-r--r--pkg/system/help/lroff/breakline.x99
-rw-r--r--pkg/system/help/lroff/center.obin0 -> 1480 bytes
-rw-r--r--pkg/system/help/lroff/center.x32
-rw-r--r--pkg/system/help/lroff/dols.obin0 -> 2792 bytes
-rw-r--r--pkg/system/help/lroff/dols.x108
-rw-r--r--pkg/system/help/lroff/getarg.obin0 -> 944 bytes
-rw-r--r--pkg/system/help/lroff/getarg.x35
-rw-r--r--pkg/system/help/lroff/indent.obin0 -> 948 bytes
-rw-r--r--pkg/system/help/lroff/indent.x17
-rw-r--r--pkg/system/help/lroff/input.obin0 -> 2608 bytes
-rw-r--r--pkg/system/help/lroff/input.x123
-rw-r--r--pkg/system/help/lroff/justify.obin0 -> 2064 bytes
-rw-r--r--pkg/system/help/lroff/justify.x63
-rw-r--r--pkg/system/help/lroff/lroff.com24
-rw-r--r--pkg/system/help/lroff/lroff.h41
-rw-r--r--pkg/system/help/lroff/lroff.hlp258
-rw-r--r--pkg/system/help/lroff/lroff.obin0 -> 5952 bytes
-rw-r--r--pkg/system/help/lroff/lroff.x220
-rw-r--r--pkg/system/help/lroff/lroff2html.c1381
-rw-r--r--pkg/system/help/lroff/lroff2html.x781
-rw-r--r--pkg/system/help/lroff/lroff2ps.x460
-rw-r--r--pkg/system/help/lroff/mkpkg27
-rw-r--r--pkg/system/help/lroff/nextcmd.x56
-rw-r--r--pkg/system/help/lroff/nofill.x45
-rw-r--r--pkg/system/help/lroff/output.x190
-rw-r--r--pkg/system/help/lroff/rawcopy.x26
-rw-r--r--pkg/system/help/lroff/section.x224
-rw-r--r--pkg/system/help/lroff/skiplines.x19
-rw-r--r--pkg/system/help/lroff/textlen.x20
-rw-r--r--pkg/system/help/lroff/textout.x140
-rw-r--r--pkg/system/help/lroff/words.com9
-rw-r--r--pkg/system/help/manout.x330
-rw-r--r--pkg/system/help/mkhelpdb.hlp75
-rw-r--r--pkg/system/help/mkpkg36
-rw-r--r--pkg/system/help/modlist.x200
-rw-r--r--pkg/system/help/modtemp.x190
-rw-r--r--pkg/system/help/prblkhdr.x80
-rw-r--r--pkg/system/help/prdir.x108
-rw-r--r--pkg/system/help/prfile.x84
-rw-r--r--pkg/system/help/prfnames.x69
-rw-r--r--pkg/system/help/prhelp.x144
-rw-r--r--pkg/system/help/prhlpblk.x154
-rw-r--r--pkg/system/help/prmodname.x35
-rw-r--r--pkg/system/help/prsummary.x95
-rw-r--r--pkg/system/help/t_hdbexamine.x35
-rw-r--r--pkg/system/help/t_help.x290
-rw-r--r--pkg/system/help/t_lroff.x35
-rw-r--r--pkg/system/help/t_mkhelpdb.x76
-rw-r--r--pkg/system/help/tlist.x406
-rw-r--r--pkg/system/help/xhelp/help.gui3027
-rw-r--r--pkg/system/help/xhelp/mkpkg28
-rw-r--r--pkg/system/help/xhelp/xhcmds.x185
-rw-r--r--pkg/system/help/xhelp/xhdir.x567
-rw-r--r--pkg/system/help/xhelp/xhelp.h89
-rw-r--r--pkg/system/help/xhelp/xhelp.x167
-rw-r--r--pkg/system/help/xhelp/xhfiles.x89
-rw-r--r--pkg/system/help/xhelp/xhhelp.x276
-rw-r--r--pkg/system/help/xhelp/xhinit.x77
-rw-r--r--pkg/system/help/xhelp/xhofile.x188
-rw-r--r--pkg/system/help/xhelp/xhpkg.x192
-rw-r--r--pkg/system/help/xhelp/xhprint.x151
-rw-r--r--pkg/system/help/xhelp/xhqref.x250
-rw-r--r--pkg/system/help/xhelp/xhroot.x73
-rw-r--r--pkg/system/help/xhelp/xhsave.x184
-rw-r--r--pkg/system/help/xhelp/xhsearch.x185
-rw-r--r--pkg/system/help/xhelp/xhsort.x223
-rw-r--r--pkg/system/help/xhelp/zzdebug.x59
-rw-r--r--pkg/system/lprint.par5
-rw-r--r--pkg/system/lprint.x213
-rw-r--r--pkg/system/lroff.par4
-rw-r--r--pkg/system/match.par5
-rw-r--r--pkg/system/match.x96
-rw-r--r--pkg/system/mkdir.par1
-rw-r--r--pkg/system/mkdir.x12
-rw-r--r--pkg/system/mkhelpdb.par3
-rw-r--r--pkg/system/mkpkg53
-rw-r--r--pkg/system/mkscript.cl79
-rw-r--r--pkg/system/mkscript.par17
-rw-r--r--pkg/system/movefiles.par3
-rw-r--r--pkg/system/movefiles.x52
-rw-r--r--pkg/system/mtclean.par3
-rw-r--r--pkg/system/mtclean.x25
-rw-r--r--pkg/system/netstatus.x9
-rw-r--r--pkg/system/news.cl5
-rw-r--r--pkg/system/page.par6
-rw-r--r--pkg/system/page.x41
-rw-r--r--pkg/system/pathnames.par2
-rw-r--r--pkg/system/pathnames.x55
-rw-r--r--pkg/system/phelp.cl41
-rw-r--r--pkg/system/protect.par1
-rw-r--r--pkg/system/protect.x23
-rw-r--r--pkg/system/references.cl50
-rw-r--r--pkg/system/rename.par3
-rw-r--r--pkg/system/rename.x176
-rw-r--r--pkg/system/rewind.par2
-rw-r--r--pkg/system/rewind.x14
-rw-r--r--pkg/system/sort.com10
-rw-r--r--pkg/system/sort.par5
-rw-r--r--pkg/system/sort.x434
-rw-r--r--pkg/system/system.cl55
-rw-r--r--pkg/system/system.hd47
-rw-r--r--pkg/system/system.men39
-rw-r--r--pkg/system/system.par5
-rw-r--r--pkg/system/t_fcache.x118
-rw-r--r--pkg/system/t_urlget.x96
-rw-r--r--pkg/system/tail.par2
-rw-r--r--pkg/system/tail.x107
-rw-r--r--pkg/system/tee.par3
-rw-r--r--pkg/system/tee.x58
-rw-r--r--pkg/system/touch.par7
-rw-r--r--pkg/system/touch.x193
-rw-r--r--pkg/system/type.par3
-rw-r--r--pkg/system/type.x68
-rw-r--r--pkg/system/unprotect.par1
-rw-r--r--pkg/system/unprotect.x23
-rw-r--r--pkg/system/urlget.par6
-rw-r--r--pkg/system/x_system.x36
194 files changed, 23532 insertions, 0 deletions
diff --git a/pkg/system/README b/pkg/system/README
new file mode 100644
index 00000000..5567ce8b
--- /dev/null
+++ b/pkg/system/README
@@ -0,0 +1,5 @@
+
+This directory contains all CL-callable routines for the "system" package.
+Included are routines for file manipulation, date and time, device access,
+and so on. Certain of these routines are machine dependent; search for
+the string "MACHDEP" to identify such files.
diff --git a/pkg/system/bench.cl b/pkg/system/bench.cl
new file mode 100644
index 00000000..e8de1036
--- /dev/null
+++ b/pkg/system/bench.cl
@@ -0,0 +1,143 @@
+#{
+# BENCH.CL
+#
+# A rough benchmark script for testing IRAF on different systems.
+#
+
+procedure bench ()
+
+begin
+
+ string dum1, dum2, time1, time2
+ real t0, t1, t2, t3, t4, tf, tsec, tmake, tproc, tcomb, tmed
+
+
+ # Load the needed tasks (if necessary) BEFORE timer starts.
+ if (!defpac("noao.artdata")) {
+ artdata
+ }
+
+ reset imdir = "HDR$pix/"
+
+
+ print(" ")
+ time() | scan (dum1, time1, dum2)
+ print("Bench started at ",time1)
+ time() | scan (dum1, t0, dum2)
+ print(" ")
+
+ print ("=====> Making images...")
+ print (" Making zero...")
+ mknoise ("zimage",
+ output="", title="zero image", ncols=2048, nlines=2048,
+ header="artdata$stdheader.dat", background=0., gain=1., rdnoise=2.,
+ poisson=no, seed=1, cosrays="", ncosrays=100, energy=30000., radius=0.5,
+ pa=0., comments=yes)
+
+ print (" Making flat...")
+ mknoise ("fimage",
+ output="", title="flat image", ncols=2048, nlines=2048,
+ header="artdata$stdheader.dat", background=30000., gain=1., rdnoise=1.,
+ poisson=no, seed=1, cosrays="", ncosrays=0, energy=30000., radius=0.5,
+ pa=0., comments=yes)
+
+ print (" Making 3 objs...")
+ mknoise ("o1image",
+ output="", title="obj image", ncols=2048, nlines=2048,
+ header="artdata$stdheader.dat", background=500., gain=1., rdnoise=5.,
+ poisson=no, seed=1, cosrays="", ncosrays=100, energy=30000., radius=0.5,
+ pa=0., comments=yes)
+
+ mknoise ("o2image",
+ output="", title="obj image", ncols=2048, nlines=2048,
+ header="artdata$stdheader.dat", background=500., gain=1., rdnoise=5.,
+ poisson=no, seed=1, cosrays="", ncosrays=100, energy=30000., radius=0.5,
+ pa=0., comments=yes)
+
+ mknoise ("o3image",
+ output="", title="obj image", ncols=2048, nlines=2048,
+ header="artdata$stdheader.dat", background=500., gain=1., rdnoise=5.,
+ poisson=no, seed=1, cosrays="", ncosrays=100, energy=30000., radius=0.5,
+ pa=0., comments=yes)
+
+ time() | scan (dum1, t1, dum2)
+
+
+ # PROC SIMULATION SECTION
+ #
+ # Flat normalization is usually done realtime in memory in ccdproc,
+ # but writing the image might be similar to the temp image in ccdproc
+
+ print(" ")
+ print(" ")
+ print ("=====> Normalizing flat...")
+ imarith ("fimage",
+ "/", "30000.", "fimage", title="", divzero=1., hparams="", pixtype="",
+ calctype="", verbose=yes, noact=no)
+
+ print(" ")
+ print(" ")
+ print ("=====> Subtracting zero from 3 images...")
+ imarith ("o1image,o2image,o3image",
+ "-", "zimage", "o1image,o2image,o3image", title="",
+ divzero=0., hparams="", pixtype="", calctype="", verbose=yes, noact=no)
+
+ print(" ")
+ print(" ")
+ print ("=====> Dividing flat into 3 images...")
+ imarith ("o1image,o2image,o3image",
+ "/", "fimage", "o1image,o2image,o3image", title="", divzero=0.,
+ hparams="", pixtype="", calctype="", verbose=yes, noact=no)
+
+ # END of PROC SIMULATION SECTION
+
+ time() | scan (dum1, t2, dum2)
+
+ print(" ")
+ print(" ")
+ printf ("=====> Combining 3 images...")
+ imcombine ("o1image,o2image,o3image",
+ "ocimage", sigma="", logfile="STDOUT", combine="average",
+ reject="crreject", project=no, outtype="real", offsets="none",
+ masktype="none", maskvalue=0., blank=0., scale="none", zero="none",
+ weight="none", statsec="", expname="", lthreshold=INDEF,
+ hthreshold=INDEF, nlow=1, nhigh=1, nkeep=1, mclip=yes, lsigma=3.,
+ hsigma=3., rdnoise="5", gain="1", snoise="0.", sigscale=0.1,
+ pclip=-0.5, grow=0)
+
+ time() | scan (dum1, t3, dum2)
+
+ print(" ")
+ print(" ")
+ print ("=====> Median filtering image...")
+ median ("ocimage",
+ "omimage", 9, 9, zloreject=INDEF, zhireject=INDEF, boundary="nearest",
+ constant=0., verbose=yes)
+
+ time() | scan (dum1, t4, dum2)
+
+ print(" ")
+ print ("=====> Deleting all images...")
+ imdel ("o1image,o2image,o3image,ocimage,omimage,zimage,fimage",
+ yes, verify=no, default_acti=yes)
+
+ time() | scan (dum1, tf, dum2)
+ time() | scan (dum1, time2, dum2)
+ print(" ")
+ print("Bench started at ",time1)
+ print("Bench ended at ",time2)
+ print(" ")
+
+ tsec = (tf - t0) * 3600.
+ tmake = (t1 - t0) * 3600.
+ tproc = (t2 - t1) * 3600.
+ tcomb = (t3 - t2) * 3600.
+ tmed = (t4 - t3) * 3600.
+
+
+ printf ("Total execution time = %7.1f seconds\n",tsec)
+ printf (" Total time Make 5 imgs Proc 3 imgs Combine 3 imgs Median 1 img\n")
+ printf (" %7.1f %7.1f %7.1f %7.1f %7.1f\n",
+ tsec, tmake, tproc, tcomb, tmed)
+
+end
diff --git a/pkg/system/chkupdate.par b/pkg/system/chkupdate.par
new file mode 100644
index 00000000..f6800a8d
--- /dev/null
+++ b/pkg/system/chkupdate.par
@@ -0,0 +1,5 @@
+interval,i,h,0,,,Days between update checks (-1 to disable or 0 for always)
+ref_file,s,h,"iraf$.release_date",,,reference file for times
+release,s,h,)_.release,,,IRAF release version
+baseurl,s,h,"http://iraf.noao.edu/ftp",,,base URL to release timestamp directory
+verbose,b,h,yes,,,verbose output flag
diff --git a/pkg/system/chkupdate.x b/pkg/system/chkupdate.x
new file mode 100644
index 00000000..a45c6d44
--- /dev/null
+++ b/pkg/system/chkupdate.x
@@ -0,0 +1,178 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <fio.h>
+include <fset.h>
+include <finfo.h>
+include <time.h>
+include <syserr.h>
+
+
+
+# CHKUPDATE -- Check to see whether the current IRAF system is up to date
+# relative to what's available on the NOAO server.
+
+
+procedure t_chkupdate ()
+
+
+char version[SZ_FNAME], baseurl[SZ_FNAME], chkfile[SZ_LINE]
+char netpath[SZ_LINE], arch[SZ_FNAME], tmpfile[SZ_FNAME]
+char host[SZ_LINE], ref_file[SZ_LINE], release[SZ_LINE]
+char buf[SZ_LINE]
+pointer reply
+bool verbose
+long last, reldate, ndays, info[LEN_FINFO]
+int ip, op, fd, nread, interval, tm[LEN_TMSTRUCT]
+
+int clgeti(), envgets(), access(), open(), url_get()
+int strlen(), getline(), finfo()
+bool clgetb()
+long clktime(), ctol()
+
+define done_ 99
+
+begin
+ # Initialize strings.
+ call aclrc (baseurl, SZ_LINE)
+ call aclrc (release, SZ_LINE)
+ call aclrc (ref_file, SZ_LINE)
+ call aclrc (chkfile, SZ_LINE)
+ call aclrc (tmpfile, SZ_FNAME)
+ call aclrc (arch, SZ_FNAME)
+ call aclrc (version, SZ_FNAME)
+
+ call strcpy ("uparm$update", chkfile, SZ_LINE)
+ call mktemp ("tmp$url", tmpfile, SZ_FNAME)
+ if (envgets ("arch", arch, SZ_FNAME) == ERR) {
+ if (verbose)
+ call eprintf ("Error: cannot get architecture.\n")
+ return
+ }
+
+
+ # Get the task parameters.
+ call clgstr ("ref_file", ref_file, SZ_LINE)
+ call clgstr ("release", release, SZ_LINE)
+ call clgstr ("baseurl", baseurl, SZ_FNAME)
+ verbose = clgetb ("verbose")
+ interval = clgeti ("interval")
+
+
+ # See whether we're doing an update check. If the interval is less
+ # than zero it means the update is disabled. A zero value means we
+ # check at each login, otherwise we've specified the number of days
+ # since our last check. The check time is kept in the uparm$update
+ # file which is created the first time we run, and updated after each
+ # check.
+ if (interval < 0) {
+ return # nothing to do
+
+ } else if (interval >= 0) {
+ # See if current time is more than N interval days since last
+ # check.
+ if (access (chkfile, 0, 0) == NO) {
+ # No update file found, create one and check for updates.
+ fd = open (chkfile, NEW_FILE, TEXT_FILE)
+ call fprintf (fd, "%d\n")
+ call pargl (clktime (0))
+ call close (fd)
+ } else {
+ call aclrc (buf, SZ_LINE)
+ fd = open (chkfile, READ_ONLY, TEXT_FILE)
+ if (getline (fd, buf) != EOF) {
+ ip = 1
+ if (ctol (buf, ip, last) > 0) {
+ ndays = (clktime(0) - last) / 86400
+ if (ndays < interval) {
+ call close (fd)
+ return # too recent
+ }
+ }
+ }
+ call close (fd)
+ }
+ }
+
+
+ # Transform the CL version string to one we can use in the URL.
+ version[1] = 'v' ; op = 2
+ for (ip=1; release[ip] != NULL && ip < SZ_LINE; ip=ip+1) {
+ if (release[ip] != '.') {
+ version[op] = release[ip]
+ op = op + 1
+ }
+ }
+
+ # Create the URL to the release timestamp file.
+ call sprintf (netpath, SZ_LINE, "%s/%s/releases/%s")
+ call pargstr (baseurl)
+ call pargstr (version)
+ call pargstr (arch[2])
+
+
+ # Access the URL and get the reply.
+ call calloc (reply, SZ_LINE, TY_CHAR)
+
+ if (url_get (netpath, tmpfile, reply) > 0) {
+ call aclrc (buf, SZ_LINE)
+ fd = open (tmpfile, READ_ONLY, TEXT_FILE)
+ if (getline (fd, buf) != EOF) {
+ ip = 1
+ if (ctol (buf, ip, reldate) > 0) {
+ if (access (ref_file, 0, 0) == NO) {
+ if (verbose)
+ call eprintf ("Error: no release file\n")
+ call close (fd)
+ goto done_
+ }
+ if (access (ref_file, 0, 0) == YES &&
+ finfo (ref_file, info) != ERR) {
+
+ call brktime (reldate, tm)
+ call printf (" *** Checking update status... ")
+
+ # Add a 1-day offset to the release date to ensure
+ # the ref_file timestamp is less than the URL file,
+ # both of which are created during the packaging of
+ # a release. This avoids a case where we would
+ # *always* get an update notification.
+ reldate = reldate + 86400
+
+ if (FI_CTIME(info) < reldate) {
+
+ call aclrc (release, SZ_LINE)
+ call strcpy (buf[ip+1], release, SZ_LINE)
+ release[strlen(release)] = NULL
+
+ call printf (
+ "IRAF %s update available on %d/%d/%d\n")
+ call pargstr (release)
+ call pargi (TM_MONTH(tm))
+ call pargi (TM_MDAY(tm))
+ call pargi (TM_YEAR(tm))
+ call close (fd)
+ goto done_
+ } else {
+ call printf ("Your IRAF system is up to date\n")
+ }
+ }
+ }
+ }
+ call close (fd)
+
+ } else
+ ; # got a HTTP error code, quit
+
+
+ # Write the current check time to the update file to reset the
+ # interval.
+ fd = open (chkfile, READ_WRITE, TEXT_FILE)
+ call fprintf (fd, "%d\n")
+ call pargl (clktime (0))
+ call close (fd)
+
+ # Clean up.
+done_ call mfree (reply, TY_CHAR)
+ if (access (tmpfile, 0, 0) == YES)
+ call delete (tmpfile)
+end
diff --git a/pkg/system/cmdstr.par b/pkg/system/cmdstr.par
new file mode 100644
index 00000000..ba046633
--- /dev/null
+++ b/pkg/system/cmdstr.par
@@ -0,0 +1,2 @@
+task,s,a,,,,Task name
+hidden,b,h,no,,,Print hidden parameters
diff --git a/pkg/system/cmdstr.x b/pkg/system/cmdstr.x
new file mode 100644
index 00000000..be4e965e
--- /dev/null
+++ b/pkg/system/cmdstr.x
@@ -0,0 +1,157 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+
+define SZ_CMDSTR 4096
+
+# CMDSTR -- Read the output of LPARAM and format a command string giving
+# the values of all parameters.
+
+procedure t_cmdstr()
+
+bool hidden, hparam
+pointer sp, ltask, pname, ibuf, obuf, ip, op, pp, nl, last
+int getline(), gstrcpy(), strncmp()
+bool clgetb()
+
+begin
+ call smark (sp)
+ call salloc (ltask, SZ_FNAME, TY_CHAR)
+ call salloc (pname, SZ_FNAME, TY_CHAR)
+ call salloc (ibuf, SZ_LINE, TY_CHAR)
+ call salloc (obuf, SZ_CMDSTR, TY_CHAR)
+
+ # Get the task name and whether to print hidden parameters.
+ call clgstr ("task", Memc[ltask], SZ_FNAME)
+ hidden = clgetb ("hidden")
+
+ op = obuf + gstrcpy (Memc[ltask], Memc[obuf], SZ_CMDSTR)
+ Memc[op] = ' '; op = op + 1
+ Memc[op] = '('; op = op + 1
+
+ last = NULL
+ nl = NULL
+
+ while (getline (STDIN, Memc[ibuf]) != EOF) {
+ ip = ibuf
+
+ # Skip white space.
+ while (IS_WHITE (Memc[ip]))
+ ip = ip + 1
+
+ # Check if the parameter is hidden and skip it if desired.
+ if (Memc[ip] == '(') {
+ if (!hidden)
+ next
+ hparam = true
+ ip = ip + 1
+ } else
+ hparam = false
+
+ # Check if parameter name is "mode" and skip it.
+ if (strncmp (Memc[ip], "mode =", 6) == 0)
+ next
+
+ # Copy or skip parameter name.
+ pp = pname
+ while (!IS_WHITE (Memc[ip])) {
+ if (hparam) {
+ Memc[op] = Memc[ip]
+ op = op + 1
+ }
+ Memc[pp] = Memc[ip]
+ pp = pp + 1
+ ip = ip + 1
+ }
+ Memc[pp] = EOS
+
+ # Copy or skip = and skip whitespace.
+ if (hparam) {
+ Memc[op] = '='
+ op = op + 1
+ }
+ ip = ip + 3
+
+ # Copy parameter value. It is an error if there is no value.
+ if (IS_WHITE (Memc[ip]) || (Memc[ip] == ')' && Memc[ip+1] != '_')) {
+ call sprintf (Memc[obuf], SZ_CMDSTR,
+ "Undefined parameter value (%s.%s)")
+ call pargstr (Memc[ltask])
+ call pargstr (Memc[pname])
+ call error (1, Memc[obuf])
+ }
+
+ # If the parameter is a quoted string copy until the closing quote,
+ # otherwise copy until whitespace or ).
+
+ if (Memc[ip] == '"') {
+ Memc[op] = Memc[ip]
+ ip = ip + 1
+ op = op + 1
+ while (Memc[ip] != '"') {
+ Memc[op] = Memc[ip]
+ ip = ip + 1
+ op = op + 1
+ }
+ Memc[op] = Memc[ip]
+ ip = ip + 1
+ op = op + 1
+
+ } else if (Memc[ip] == ')' && Memc[ip+1] == '_') {
+ # If the value is a redirection, e.g. ")_.foo", add quotes
+ # around the value and copy as a special case.
+ Memc[op] = '"'
+ op = op + 1
+
+ # Copy the opening paren.
+ Memc[op] = Memc[ip]
+ op = op + 1
+ ip = ip + 1
+
+ # Copy the rest of the string.
+ while (!IS_WHITE(Memc[ip]) && (Memc[ip] != ')')) {
+ Memc[op] = Memc[ip]
+ ip = ip + 1
+ op = op + 1
+ }
+
+ # Add the closing quote.
+ Memc[op] = '"'
+ op = op + 1
+
+ } else {
+ while (!IS_WHITE(Memc[ip]) && (Memc[ip] != ')')) {
+ Memc[op] = Memc[ip]
+ ip = ip + 1
+ op = op + 1
+ }
+ }
+
+ # Add a comma and a space.
+ Memc[op] = ','
+ op = op + 1
+ Memc[op] = ' '
+ op = op + 1
+
+ # Replace the last break with a new line if the line exceeds max.
+ if ((op - nl > 80) && (last > 0)) {
+ Memc[last] = '\n'
+ nl = last
+ }
+ last = op - 1
+ }
+
+ # Replace last comma and space by a parenthesis and EOS.
+ if (Memc[op-2] == ',')
+ op = op - 2
+
+ Memc[op] = ')'
+ op = op + 1
+ Memc[op] = EOS
+
+ # Print the command string and finish up.
+ call putline (STDOUT, Memc[obuf])
+ call putci (STDOUT, '\n')
+
+ call sfree (sp)
+end
diff --git a/pkg/system/concatenate.par b/pkg/system/concatenate.par
new file mode 100644
index 00000000..533461dd
--- /dev/null
+++ b/pkg/system/concatenate.par
@@ -0,0 +1,4 @@
+input_files,s,a,,,,list of files to be concatenated
+output_file,f,a,,,,name of output file
+out_type,s,h,"in_type",,,output file type (text|binary)
+append,b,h,no,,,append to output file?
diff --git a/pkg/system/concatenate.x b/pkg/system/concatenate.x
new file mode 100644
index 00000000..7732150b
--- /dev/null
+++ b/pkg/system/concatenate.x
@@ -0,0 +1,73 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# CONCATENATE -- Concatenate the named input files (or the standard input) to
+# produce the output file. The input files must all be of the same type.
+# The type of the output file (text|binary) defaults to the type of the first
+# input file, or to text if reading from the standard input. The hidden
+# parameter "out_type" may be used to force the file type of the copy operation.
+
+procedure t_concatenate()
+
+char infile[SZ_FNAME], outfile[SZ_FNAME]
+char out_type_string[SZ_FNAME]
+int in, out, list, out_type
+
+int clpopni(), clgfil()
+int open(), access(), strmatch(), clgeti()
+bool clgetb()
+
+begin
+ # Open the input file list, and read in the name of the first file
+ # (used to determine type of output file later).
+
+ list = clpopni ("input_files")
+ if (clgfil (list, infile, SZ_FNAME) == EOF) {
+ call clpcls (list)
+ return
+ }
+
+ # Determine whether the output file is text or binary, and open
+ # the file.
+
+ call clgstr ("out_type", out_type_string, SZ_FNAME)
+ out_type = NULL
+ if (strmatch (out_type_string, "^#{b}") > 0)
+ out_type = BINARY_FILE
+ else if (strmatch (out_type_string, "^#{t}") > 0)
+ out_type = TEXT_FILE
+
+ # Default to std output if output file not given on cmd line.
+
+ if (clgeti ("$nargs") <= 1)
+ call strcpy ("STDOUT", outfile, SZ_FNAME)
+ else
+ call clgstr ("output_file", outfile, SZ_FNAME)
+
+ # If the output file type has been specified (param "out_type"),
+ # use it, otherwise use type of first input file.
+
+ if (out_type == NULL) {
+ if (strmatch (infile, "STDIN") > 0)
+ out_type = TEXT_FILE
+ else if (access (infile, 0, TEXT_FILE) == YES)
+ out_type = TEXT_FILE
+ else
+ out_type = BINARY_FILE
+ }
+
+ # Finally, open the output file.
+ if (clgetb ("append"))
+ out = open (outfile, APPEND, out_type)
+ else
+ out = open (outfile, NEW_FILE, out_type)
+
+ # Append the input files to the output file.
+ repeat {
+ in = open (infile, READ_ONLY, out_type)
+ call fcopyo (in, out)
+ call close (in)
+ } until (clgfil (list, infile, SZ_FNAME) == EOF)
+
+ call close (out)
+ call clpcls (list)
+end
diff --git a/pkg/system/copy.par b/pkg/system/copy.par
new file mode 100644
index 00000000..eb33a234
--- /dev/null
+++ b/pkg/system/copy.par
@@ -0,0 +1,3 @@
+input,s,a,,,,input file or file template
+output,s,a,,,,output file or destination directory
+verbose,b,h,no,,,print names of files as they are copied
diff --git a/pkg/system/copy.x b/pkg/system/copy.x
new file mode 100644
index 00000000..2a021516
--- /dev/null
+++ b/pkg/system/copy.x
@@ -0,0 +1,62 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+
+# COPY -- Copy a file, or copy a list of files to another directory.
+# The number of input files is variable, but there can be only a single
+# output file. If the output file is a directory, we copy the input files
+# to that directory without changing their names. Otherwise there can
+# be only one input file, and a copy is made with the new name.
+
+procedure t_copy()
+
+int list, root_len
+bool verbose
+pointer sp, infile, destination, outfile, junkstr, dirname
+bool clgetb()
+int clpopni(), clgfil(), clplen(), fnldir(), isdirectory()
+
+begin
+ call smark (sp)
+ call salloc (infile, SZ_FNAME, TY_CHAR)
+ call salloc (outfile, SZ_FNAME, TY_CHAR)
+ call salloc (destination, SZ_FNAME, TY_CHAR)
+ call salloc (dirname, SZ_PATHNAME, TY_CHAR)
+ call salloc (junkstr, SZ_FNAME, TY_CHAR)
+
+ list = clpopni ("input")
+ call clgstr ("output", Memc[destination], SZ_FNAME)
+ verbose = clgetb ("verbose")
+
+ # If the destination file is a directory, copy each file in the input
+ # list to the destination directory, else just copy the file and check
+ # that there is only one file in the input list.
+
+ if (isdirectory (Memc[destination], Memc[dirname], SZ_PATHNAME) > 0) {
+
+ while (clgfil (list, Memc[infile], SZ_FNAME) != EOF) {
+ call strcpy (Memc[dirname], Memc[outfile], SZ_PATHNAME)
+ root_len = fnldir (Memc[infile], Memc[junkstr], SZ_FNAME)
+ call strcat (Memc[infile+root_len], Memc[outfile], SZ_PATHNAME)
+
+ if (verbose) {
+ call eprintf ("%s -> %s\n")
+ call pargstr (Memc[infile])
+ call pargstr (Memc[outfile])
+ }
+
+ iferr (call fcopy (Memc[infile], Memc[outfile]))
+ call erract (EA_WARN)
+ }
+
+ } else if (clgfil (list, Memc[infile], SZ_FNAME) != EOF) {
+ if (clplen (list) > 1) {
+ call clpcls (list)
+ call error (2, "cannot copy several files to a single file")
+ }
+ call fcopy (Memc[infile], Memc[destination])
+ }
+
+ call clpcls (list)
+ call sfree (sp)
+end
diff --git a/pkg/system/count.par b/pkg/system/count.par
new file mode 100644
index 00000000..bc78c6ef
--- /dev/null
+++ b/pkg/system/count.par
@@ -0,0 +1 @@
+files,s,a,,,,list of files to be counted
diff --git a/pkg/system/count.x b/pkg/system/count.x
new file mode 100644
index 00000000..9f9ef51c
--- /dev/null
+++ b/pkg/system/count.x
@@ -0,0 +1,131 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include <chars.h>
+include <error.h>
+
+define SZ_LUT 256 # "whitespace" lookup table
+define CC_WHITE 1 # "white" character class
+define CC_NONWHITE 0 # "word" character
+
+# COUNT -- Count the number of lines, words, and characters in the named text
+# files, or in the standard input. Print the results on the standard output.
+#
+# output format (single file):
+#
+# nlines nwords nchars
+#
+# output format (several files):
+#
+# nlines nwords nchars filename1
+# nlines nwords nchars filename2
+# nlines nwords nchars Total
+
+procedure t_count()
+
+char fname[SZ_FNAME]
+long nlines, nwords, nchars
+long totlines, totwords, totchars
+int nfiles, list
+int clpopni(), clgfil()
+
+begin
+ totlines = 0
+ totwords = 0
+ totchars = 0
+ nfiles = 0
+
+ list = clpopni ("files")
+
+ while (clgfil (list, fname, SZ_FNAME) != EOF) {
+ iferr (call count_file (fname, nlines, nwords, nchars))
+ call erract (EA_WARN)
+ else {
+ call print_stats (STDOUT, nlines, nwords, nchars, fname)
+ call flush (STDOUT)
+ }
+
+ totlines = totlines + nlines
+ totwords = totwords + nwords
+ totchars = totchars + nchars
+ nfiles = nfiles + 1
+ }
+
+ call clpcls (list)
+
+ if (nfiles > 1)
+ call print_stats (STDOUT, totlines, totwords, totchars, "Total")
+end
+
+
+# COUNT_FILE -- Open a file and count the number of lines, words, and
+# characters in the file.
+
+procedure count_file (fname, nlines, nwords, nchars)
+
+char fname[SZ_FNAME], lbuf[SZ_LINE], ch, class[SZ_LUT]
+long nlines, nwords, nchars
+int first_time, state, fd, ip, open(), getline()
+errchk open, getline
+data first_time /YES/
+
+begin
+ # Initialize the lookup table, used to count words. In this case,
+ # NEWLINE is considered to be whitespace.
+
+ if (first_time == YES) {
+ do ip = 1, SZ_LUT
+ class[ip] = CC_NONWHITE
+
+ class[BLANK] = CC_WHITE
+ class[TAB] = CC_WHITE
+ class[NEWLINE] = CC_WHITE
+
+ first_time = NO
+ }
+
+ fd = open (fname, READ_ONLY, TEXT_FILE)
+
+ nwords = 0
+ nchars = 0
+ state = CC_WHITE
+
+ # Increment word count at the beginning of every word. A "word"
+ # is defined as a sequence of characters delimited by whitespace.
+ # COUNT does not know anything about quoted strings.
+
+ for (nlines=0; getline (fd, lbuf) != EOF; ) {
+ do ip = 1, SZ_LINE {
+ ch = lbuf[ip]
+ if (ch == EOS)
+ break
+ else if (class[ch] != state) {
+ nwords = nwords + state
+ state = class[ch]
+ }
+ }
+ nchars = nchars + ip - 1
+ if (lbuf[ip-1] == '\n')
+ nlines = nlines + 1
+ }
+
+ call close (fd)
+end
+
+
+# PRINT_STATS -- Format the COUNT statistics summary line and print it on
+# the named file.
+
+procedure print_stats (fd, nlines, nwords, nchars, fname)
+
+int fd
+long nlines, nwords, nchars
+char fname[ARB]
+
+begin
+ call fprintf (fd, "%7d %7d %7d %s\n")
+ call pargl (nlines)
+ call pargl (nwords)
+ call pargl (nchars)
+ call pargstr (fname)
+end
diff --git a/pkg/system/delete.par b/pkg/system/delete.par
new file mode 100644
index 00000000..a33ed606
--- /dev/null
+++ b/pkg/system/delete.par
@@ -0,0 +1,6 @@
+files,s,a,,,,list of files to be deleted
+verify,b,h,no,,,verify operation before deleting each file?
+default_action,b,h,yes,,,default delete action for verify query
+allversions,b,h,yes,,,delete all versions of each file
+subfiles,b,h,yes,,,delete any subfiles of each file
+go_ahead,b,q,yes,,," ?"
diff --git a/pkg/system/delete.x b/pkg/system/delete.x
new file mode 100644
index 00000000..0c15a2c4
--- /dev/null
+++ b/pkg/system/delete.x
@@ -0,0 +1,74 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+
+# DELETE -- Delete a list of files. If file cannot be deleted, warn but do
+# not abort. Verify before deleting each file if user wishes.
+
+procedure t_delete()
+
+bool verify # verify before deleting
+bool allversions # delete all versions of each file
+bool subfiles # delete any subfiles of a file
+char fname[SZ_FNAME]
+int list
+pointer tty
+
+bool clgetb()
+int clpopns(), clgfil(), access(), btoi(), strncmp()
+pointer ttyodes()
+
+begin
+ list = clpopns ("files")
+ verify = clgetb ("verify")
+ allversions = clgetb ("allversions")
+ subfiles = clgetb ("subfiles")
+ if (verify)
+ tty = ttyodes ("terminal")
+
+ while (clgfil (list, fname, SZ_FNAME) != EOF) {
+ if (verify) {
+ # If file does not exist, warn user (since verify mode is
+ # in effect).
+ if (access (fname, 0, 0) == NO) {
+ call eprintf ("Warning: Nonexistent file '%s'\n")
+ call pargstr (fname)
+ next
+ }
+
+ # Set default action of verify prompt (override learning of
+ # most recent response).
+
+ call flush (STDOUT)
+ call clputb ("go_ahead", clgetb ("default_action"))
+ call eprintf ("Delete file ")
+ call ttyso (STDERR, tty, YES)
+ call eprintf ("'%s'")
+ call pargstr (fname)
+ call ttyso (STDERR, tty, NO)
+ call flush (STDERR)
+
+ if (!clgetb ("go_ahead"))
+ next
+ }
+
+ if (strncmp ("http:", fname, 5) == 0) {
+ call eprintf ("Cannot delete URL `%s'\n")
+ call pargstr (fname)
+ next
+ }
+
+ iferr (call deletefg (fname, btoi(allversions), btoi(subfiles)))
+ call erract (EA_WARN)
+ }
+
+ # Reset the go_ahead parameter, overiding learn mode, in case delete
+ # is subsequently called from the background. Close tty descriptor.
+
+ if (verify) {
+ call clputb ("go_ahead", true)
+ call ttycdes (tty)
+ }
+
+ call clpcls (list)
+end
diff --git a/pkg/system/devices.cl b/pkg/system/devices.cl
new file mode 100644
index 00000000..660c91ec
--- /dev/null
+++ b/pkg/system/devices.cl
@@ -0,0 +1,3 @@
+# DEVICES -- Print information on the locally available devices.
+
+help devices
diff --git a/pkg/system/directory.par b/pkg/system/directory.par
new file mode 100644
index 00000000..444fe325
--- /dev/null
+++ b/pkg/system/directory.par
@@ -0,0 +1,6 @@
+files,s,a,,,,files or directory to be listed
+long,b,h,no,,,long format listing
+ncols,i,h,0,0,,number of columns if multicolumn format
+maxch,i,h,18,,,max filename chars to show if multicolumn format
+sort,b,h,yes,,,sort the file list
+all,b,h,no,,,list hidden files too
diff --git a/pkg/system/directory.x b/pkg/system/directory.x
new file mode 100644
index 00000000..37a1c397
--- /dev/null
+++ b/pkg/system/directory.x
@@ -0,0 +1,561 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <diropen.h>
+include <protect.h>
+include <finfo.h>
+include <chars.h>
+include <ctype.h>
+include <fset.h>
+include <time.h>
+
+# DIRECTORY -- List the files matching the given template. If no template is
+# given list the contents of the current directory. Only existing files are
+# listed, i.e., "dir file" may be used to test if "file" exists. There are
+# two types of file listings:
+#
+# tabular multicolumn listing, "ncolumns" columns (default)
+# long long form listing; prints more info for each file
+#
+# The template may be either the name of a file or directory, or a true
+# filename template containing pattern matching metacharacters.
+
+define DEF_MAXFILES 256 # initial max file limit
+define DEF_SZSBUF 4096 # initial string buffer size
+define DEF_SCREENWIDTH 80 # default screen width if envgeti fails
+define DEF_NCOLS 4 # default number of columns in table
+define NLINES_FLUSH 4 # nlines flushed out at a time (quick)
+define PATCHARS "*?["
+
+define LEN_FLDES 6 # file list descriptor
+define FL_NFILES Memi[$1] # number of files in list
+define FL_NEXTOFF Memi[$1+1] # next offset in sbuf
+define FL_OFFBP Memi[$1+2] # pointer to list of offsets
+define FL_SBUFP Memi[$1+3] # pointer to string buffer
+define FL_MAXFILES Memi[$1+4] # current length of offset array
+define FL_SZSBUF Memi[$1+5] # current string buffer size
+
+define FL_OFFSET Memi[FL_OFFBP($1)+($2)-1]
+define FL_FNAME Memc[FL_SBUFP($1)+(FL_OFFSET($1,$2))-1]
+
+
+# T_DIRECTORY -- CL callable main routine for the directory program.
+
+procedure t_directory()
+
+pointer sp, files, fname, dirname, patp, fp, ip, op, ep
+int ncols, maxch, dirmode, fd, n, i, patlen, len_dir
+bool long_format, is_template, is_pattern, is_dir, sort_list, match_extension
+
+bool clgetb(), strne()
+int clgeti(), fntopnb(), fntgfnb()
+int diropen(), getline(), stridx(), strlen(), strncmp(), stridxs()
+int isdirectory(), access(), envgeti(), btoi()
+string patchars PATCHARS
+define template_ 91
+define done_ 92
+
+begin
+ call smark (sp)
+ call salloc (files, SZ_LINE, TY_CHAR)
+ call salloc (fname, SZ_PATHNAME, TY_CHAR)
+ call salloc (dirname, SZ_PATHNAME, TY_CHAR)
+
+ # If directory is called without any arguments, list the contents
+ # of the current directory. Otherwise read in the file template.
+
+ if (clgeti ("$nargs") == 0)
+ call strcpy (".", Memc[files], SZ_LINE)
+ else
+ call clgstr ("files", Memc[files], SZ_LINE)
+
+ # Determine whether a long format listing is desired.
+ long_format = clgetb ("long")
+
+ # If not long format listing, determine the number of columns for
+ # the multicolumn format listing.
+
+ if (!long_format)
+ ncols = clgeti ("ncols")
+
+ # Max chars of each filename to be shown.
+ maxch = clgeti ("maxch")
+
+ # Sort files?
+ sort_list = clgetb ("sort")
+
+ # Show hidden files?
+ if (clgetb ("all"))
+ dirmode = PASS_HIDDEN_FILES
+ else
+ dirmode = SKIP_HIDDEN_FILES
+
+ # Allocate and initialize storage for the file list descriptor and
+ # assocated array storage.
+
+ call calloc (fp, LEN_FLDES, TY_STRUCT)
+ call malloc (FL_OFFBP(fp), DEF_MAXFILES, TY_INT)
+ call malloc (FL_SBUFP(fp), DEF_SZSBUF, TY_CHAR)
+
+ FL_MAXFILES(fp) = DEF_MAXFILES
+ FL_SZSBUF(fp) = DEF_SZSBUF
+ FL_NEXTOFF(fp) = 1
+
+ # The template is considered a filename template if it contains any
+ # of the metacharacters "*?[],", i.e., any string containing a comma
+ # is considered a filename template, since we don't want to mess with
+ # parsing comma delimited lists here.
+
+ is_template = false
+ is_pattern = false
+
+ for (ip=files; Memc[ip] != EOS; ip=ip+1)
+ if (IS_ALPHA (Memc[ip])) {
+ next
+ } else if (stridx (Memc[ip], patchars) > 0) {
+ if (ip == files || Memc[ip-1] != '\\')
+ is_pattern = true
+ } else if (Memc[ip] == ',' || Memc[ip] == '%')
+ if (ip == files || Memc[ip-1] != '\\')
+ is_template = true
+
+ # Set IS_DIR flag, and get directory name if not fancy template.
+
+ if (is_template) {
+ is_dir = false
+
+ } else if (is_pattern) {
+ is_dir = true
+ patp = NULL
+ ep = NULL
+
+ # Search for a valid directory prefix.
+ op = dirname
+ for (ip=files; Memc[ip] != EOS; ip=ip+1) {
+ Memc[op] = Memc[ip]
+ if (Memc[op] == FNLDIR_CHAR || Memc[op] == '//')
+ if (op == dirname || Memc[op-1] != '\\') {
+ patp = ip + 1
+ ep = op + 1
+ }
+ op = op + 1
+ }
+
+ # Must set patp and dirname before exiting.
+ if (patp == NULL) {
+ patp = files
+ call strcpy ("./", Memc[dirname], SZ_PATHNAME)
+ len_dir = 0
+ } else {
+ Memc[ep] = EOS
+ len_dir = strlen (Memc[dirname])
+ }
+
+ } else
+ is_dir = (isdirectory (Memc[files],Memc[dirname],SZ_PATHNAME) > 0)
+
+ # If sorting is not desired and we either don't have a template, or
+ # a simple unary match-pattern template, we can list the directory
+ # directly to the standard output as it is read. This is the fastest
+ # possible type of of directory listing, and is particularly useful
+ # for listing very large directories.
+
+ if (is_dir && !sort_list && !long_format && !is_template) {
+ fd = diropen (Memc[dirname], dirmode)
+ call dir_quicklist (STDOUT, fd, Memc[patp], is_pattern, ncols)
+ call close (fd)
+ goto done_
+ }
+
+ # If `files' is a template, expand the template and read the file
+ # names into memory. If `files' is not a filename template, determine
+ # if it is the name of (or pathname to) a directory. If so, open the
+ # directory directly and read the file list into memory. If `files' is
+ # neither a template nor a directory, it must be a filename, so merely
+ # put its name in the file list.
+
+ if (!is_template && is_dir) {
+ # Read file list from the named directory.
+
+ # Set up the pattern matching code. We recognize selecting all
+ # files with a particular extension as a special case, since this
+ # case is very common and can be done more efficiently if we don't
+ # use the general pattern matching code.
+
+ if (is_pattern) {
+ match_extension = (strncmp (Memc[patp], "*.", 2) == 0 &&
+ stridxs (patchars, Memc[patp+2]) <= 0)
+ if (match_extension)
+ patlen = strlen (Memc[patp])
+ else
+ goto template_
+ }
+
+ fd = diropen (Memc[dirname], dirmode)
+
+ # Accumulate the file list in memory.
+ n = 0
+ while (n != EOF) {
+ n = getline (fd, Memc[fname])
+ if (n <= 1)
+ break
+ n = n - 1
+ Memc[fname+n] = EOS # clobber the \n
+
+ # Check if file matches the given pattern.
+ if (is_pattern) {
+ if (n < patlen)
+ next
+ ep = fname + n - 1
+ for (ip=patp+patlen-1; ip > patp+1; ip=ip-1) {
+ if (Memc[ep] != Memc[ip])
+ break
+ ep = ep - 1
+ }
+ if (Memc[ip] != '.' || Memc[ep] != '.')
+ next
+ }
+
+ call dir_putstr (fp, Memc[fname], n)
+ }
+
+ call close (fd)
+ if (sort_list && FL_NFILES(fp) > 1)
+ call strsrt (FL_OFFSET(fp,1), Memc[FL_SBUFP(fp)], FL_NFILES(fp))
+
+ } else {
+ # Expand the given filename template and read the file list into
+ # memory. This also handles the cases of a single filename or
+ # a simple list of filenames.
+template_
+ fd = fntopnb (Memc[files], btoi(sort_list))
+
+ n = fntgfnb (fd, Memc[fname], SZ_PATHNAME)
+ while (n != EOF) {
+ ip = fname
+ if (!is_template && is_pattern)
+ ip = fname + len_dir;
+ if (is_pattern)
+ call dir_putstr (fp, Memc[ip], n)
+ else if (access (Memc[fname],0,0) == YES)
+ call dir_putstr (fp, Memc[ip], n)
+ n = fntgfnb (fd, Memc[fname], SZ_PATHNAME)
+ }
+
+ call fntclsb (fd)
+ }
+
+ # All done if no files were found.
+ if (FL_NFILES(fp) == 0) {
+ call printf ("no files found\n")
+ goto done_
+ }
+
+ # Format and output the file list in either long format (verbose)
+ # or in multicolumn format. A one column file list is treated as
+ # a special case of the multifile format.
+
+ if (long_format || ncols == 1) {
+ for (i=1; i <= FL_NFILES(fp); i=i+1) {
+ # Get filename.
+ if (is_dir && strne (Memc[dirname], "./")) {
+ call sprintf (Memc[fname], SZ_PATHNAME, "%s%s")
+ call pargstr (Memc[dirname])
+ call pargstr (FL_FNAME(fp,i))
+ } else
+ call strcpy (FL_FNAME(fp,i), Memc[fname], SZ_PATHNAME)
+
+ if (long_format) {
+ # Long format output, one line per file.
+ call dir_pfiledata (Memc[fname], STDOUT)
+ } else {
+ call printf ("%s\n")
+ call pargstr (Memc[fname])
+ }
+ }
+
+ } else {
+ # Print nice multicolumn table.
+ call strtbl (STDOUT, Memc[FL_SBUFP(fp)], FL_OFFSET(fp,1),
+ FL_NFILES(fp), 1, envgeti ("ttyncols"), maxch, ncols)
+ }
+done_
+ call mfree (FL_OFFBP(fp), TY_INT)
+ call mfree (FL_SBUFP(fp), TY_CHAR)
+ call mfree (fp, TY_STRUCT)
+ call sfree (sp)
+end
+
+
+# DIR_QUICKLIST -- List the directory directly to the standard output, without
+# first reading and sorting the entire directory. This is the best type of
+# listing algorithm for very large directories.
+
+procedure dir_quicklist (out, fd, pat, have_pattern, a_ncols)
+
+int out # output file
+int fd # fd of directory being listed
+char pat[ARB] # selection pattern, if any
+bool have_pattern # do we have a pattern?
+int a_ncols # number of columns out
+
+bool flushlines, match_extension
+pointer sp, fname, obuf, patbuf, op, ep
+int colwidth, patlen, ip, col, maxch, junk, lastch
+int scrwidth, ncols, nfiles, nchars, nblanks, nlines, nflush
+int fstati(), getline(), envgeti(), patmake(), patmatch()
+int strncmp(), stridxs(), strlen()
+errchk getline, ungetline, putline
+
+begin
+ call smark (sp)
+ call salloc (obuf, SZ_LINE, TY_CHAR)
+ call salloc (fname, SZ_PATHNAME, TY_CHAR)
+ call salloc (patbuf, SZ_LINE, TY_CHAR)
+
+ # Initialization.
+ flushlines = (out == STDOUT && fstati (out, F_REDIR) == NO)
+ iferr (scrwidth = envgeti ("ttyncols"))
+ scrwidth = DEF_SCREENWIDTH
+
+ ncols = a_ncols
+ if (ncols <= 0)
+ ncols = DEF_NCOLS
+ maxch = scrwidth / ncols
+
+ nfiles = 0
+ nchars = 0
+ nlines = 0
+ nflush = 1
+
+ # Set up the pattern matching code. We recognize selecting all files
+ # with a particular extension as a special case, since this case is
+ # very common and can be done much more efficiently if we don't use
+ # the general pattern matching code.
+
+ if (have_pattern) {
+ match_extension = (strncmp (pat, "*.", 2) == 0 &&
+ stridxs (PATCHARS, pat[3]) <= 0)
+ if (match_extension)
+ patlen = strlen (pat)
+ else {
+ # Convert file matching pattern into general pattern string.
+ Memc[fname] = '^'
+ op = fname + 1
+ lastch = 0
+ for (ip=1; pat[ip] != EOS; ip=ip+1) {
+ if (pat[ip] == '*' && lastch != '?' && lastch != ']') {
+ Memc[op] = '?'
+ op = op + 1
+ }
+ lastch = pat[ip]
+ Memc[op] = lastch
+ op = op + 1
+ }
+ Memc[op] = '$'
+ op = op + 1
+ Memc[op] = EOS
+
+ # Compile the pattern.
+ junk = patmake (Memc[fname], Memc[patbuf], SZ_LINE)
+ }
+ }
+
+ # List the directory.
+
+ while (nchars != EOF) {
+ # Compose the next line of the directory listing.
+ op = obuf
+ for (col=1; col <= ncols; ) {
+ nchars = getline (fd, Memc[fname])
+ if (nchars <= 1)
+ break
+
+ # Cancel the newline.
+ nchars = nchars - 1
+ Memc[fname+nchars] = EOS
+
+ # Check if file matches the given pattern.
+ if (have_pattern)
+ if (match_extension) {
+ if (nchars < patlen)
+ next
+ ep = fname + nchars - 1
+ for (ip=patlen; ip > 2; ip=ip-1) {
+ if (Memc[ep] != pat[ip])
+ break
+ ep = ep - 1
+ }
+ if (pat[ip] != '.' || Memc[ep] != '.')
+ next
+ } else if (patmatch (Memc[fname], Memc[patbuf]) <= 0)
+ next
+
+ if (op-obuf + nchars > scrwidth && col > 1) {
+ # Filename too long to fit in remainder of line.
+ call ungetline (fd, Memc[fname])
+ break
+
+ } else {
+ # Append filename to output line.
+ nfiles = nfiles + 1
+ nchars = min (nchars, scrwidth - (op - obuf))
+
+ # Copy the filename.
+ do ip = 1, nchars {
+ Memc[op] = Memc[fname+ip-1]
+ op = op + 1
+ }
+
+ # Advance to the next column.
+ colwidth = maxch
+ while (col < ncols) {
+ nblanks = colwidth - nchars
+ if (nblanks < 1) {
+ col = col + 1 # grab another column
+ colwidth = colwidth + maxch
+ } else {
+ do ip = 1, nblanks {
+ Memc[op] = ' '
+ op = op + 1
+ }
+ break
+ }
+ }
+ }
+
+ col = col + 1
+ }
+
+ # Output one line of the directory listing.
+ if (op > obuf) {
+ Memc[op] = '\n'
+ op = op + 1
+ Memc[op] = EOS
+
+ call putline (out, Memc[obuf])
+
+ nlines = nlines + 1
+ if (flushlines && nlines >= nflush) {
+ call flush (out)
+ nflush = min (NLINES_FLUSH, nflush + 1)
+ nlines = 0
+ }
+ }
+ }
+
+ # Was the directory empty?
+ if (nfiles == 0)
+ call printf ("no files found\n")
+
+ call sfree (sp)
+end
+
+
+# DIR_PUTSTR -- Put a string (filename) into the file list. If the buffer
+# fills up allocate a larger buffer.
+
+procedure dir_putstr (fp, fname, nchars)
+
+pointer fp # file list pointer
+char fname[ARB] # file name to be put in list
+int nchars # nchars in file name
+
+int op
+int fileno
+
+begin
+ # Increment file count.
+ fileno = FL_NFILES(fp) + 1
+ FL_NFILES(fp) = fileno
+
+ # Increase size of file list if it overflows.
+ if (fileno >= FL_MAXFILES(fp)) {
+ FL_MAXFILES(fp) = FL_MAXFILES(fp) * 2
+ call realloc (FL_OFFBP(fp), FL_MAXFILES(fp), TY_INT)
+ }
+
+ op = FL_NEXTOFF(fp)
+ FL_OFFSET(fp,fileno) = op
+
+ # Increase size of string buffer if it overflows.
+ if (op + nchars + 1 >= FL_SZSBUF(fp)) {
+ FL_SZSBUF(fp) = FL_SZSBUF(fp) * 2
+ call realloc (FL_SBUFP(fp), FL_SZSBUF(fp), TY_CHAR)
+ }
+
+ call strcpy (fname, FL_FNAME(fp,fileno), nchars)
+ FL_NEXTOFF(fp) = op + nchars + 1
+end
+
+
+# DIR_PFILEDATA -- Print file info in a UNIX like long directory format, on
+# the output file OUT. Format, e.g.,: "-t-rwr-r- tody 5117 May 15 19:29 fio.x"
+
+procedure dir_pfiledata (fname, out)
+
+char fname[ARB] # file name
+int out # output file
+
+pointer sp, date
+long fi[LEN_FINFO]
+int protected, ftypes[4], i
+int finfo(), access(), bitupk(), protect()
+data ftypes /'-', 'd', 'x', 's'/
+
+begin
+ call smark (sp)
+ call salloc (date, SZ_DATE, TY_CHAR)
+
+ # Get file directory information.
+ if (finfo (fname, fi) != OK) {
+ call eprintf ("Cannot get info on file `%s'\n")
+ call pargstr (fname)
+ call sfree (sp)
+ return
+ }
+
+ # Query file protection.
+ protected = protect (fname, QUERY_PROTECTION)
+
+ # Output file mode bit flags.
+ call dir_putci (out, ftypes[FI_TYPE(fi)], '-', YES)
+ call dir_putci (out, 't', 'b', access (fname,0,TEXT_FILE))
+ call dir_putci (out, 'p', '-', protected)
+
+ # Output user,group,world protections bit flags.
+ do i = 1, 5, 2 {
+ call dir_putci (out, 'r', '-', bitupk (int(FI_PERM(fi)),i,1))
+ call dir_putci (out, 'w', '-', bitupk (int(FI_PERM(fi)),i+1,1))
+ }
+
+ # Output file owner, size, date, and name.
+ call cnvdate (FI_MTIME(fi), Memc[date], SZ_DATE)
+ call fprintf (out, " %-8.8s%8d %12.12s %-32.32s\n")
+ call pargstr (FI_OWNER(fi))
+ call pargl (FI_SIZE(fi))
+ call pargstr (Memc[date])
+ call pargstr (fname)
+
+ # This is slow so flush the output after each file to give the user
+ # some immediate gratification.
+
+ call flush (out)
+ call sfree (sp)
+end
+
+
+# DIR_PUTCI -- Handy procedure used to generate --rw-r-r- type strings.
+
+procedure dir_putci (fd, ch_t, ch_f, condition)
+
+int fd # output file
+int ch_t # character to output if condition is true
+int ch_f # character to output if condition is false
+int condition
+
+begin
+ if (condition == NO)
+ call putci (fd, ch_f)
+ else
+ call putci (fd, ch_t)
+end
diff --git a/pkg/system/doc/Sys.hlp b/pkg/system/doc/Sys.hlp
new file mode 100644
index 00000000..89d66d7f
--- /dev/null
+++ b/pkg/system/doc/Sys.hlp
@@ -0,0 +1,349 @@
+.help utilities Oct83 "IRAF System Utilities"
+.sh
+Description of the Standard Utility Routines
+
+ Most of the system utilities are set up to read from either the
+standard input or a list of files. If not reading from the standard
+input, and the input file template is not given on the command line,
+a prompt will be issued for the input file list. If the output is a
+single file or directory, and output is not redirected, a prompt will
+be issued for the output file.
+
+.ks
+.ls 4 ALLOCATE device
+
+Allocate a device (i.e., a tape drive). Some devices must be allocated
+before they can be accessed for i/o. Deallocation occurs automatically
+upon logoff, or upon execution of DEALLOCATE. The following devices may
+be allocated:
+
+.nf
+Devices:
+ mta Magtape unit A.
+ mtb Magtape unit B.
+ ima Image display unit A.
+ imb Image display unit B.
+.fi
+.le
+.ke
+
+.ks
+.ls BEEP
+Beep the terminal bell. Used as in "> munch;beep" to signal when a
+lengthy command has finished. Otherwise, an IRAF program will only
+ring the terminal bell when an error has occurred.
+.le
+.ke
+
+.ks
+.ls CLEAR
+
+Clear the terminal screen.
+.le
+.ke
+
+.ks
+.ls CONCATENATE files [,output_file]
+
+Concatenate the named input files to the standard output or to the named
+output file if given. All input files should be of the same type (text or
+binary). The default type of the output file is the same as that of the
+first input file; this may be overridden by setting the hidden parameter
+"out_type". The standard input is assumed to be a text file unless overridden
+by setting out_type. If no output file is given on the command line, the
+standard output is assumed.
+
+.nf
+Hidden Parameters:
+ out_type string = "in_type" Output file type (text|binary)
+ append bool = no Append to output file
+.fi
+.le
+.ke
+
+.ks
+.ls COPY file|files, output_file|directory
+
+Copy the input file to the output file, or copy each file in the input list
+to the directory given as the second argument.
+.le
+.ke
+
+.ks
+.ls COUNT files
+
+Count the number of lines, words, and characters in each file
+in the input list. Print the totals for each file and for all files.
+.le
+.ke
+
+.ks
+.ls DEALLOCATE device
+
+Deallocate a previously allocated device (e.g., a tape drive). Devices
+are automatically deallocated upon logoff if not explicitly deallocated
+with the deallocate command.
+.le
+.ke
+
+.ks
+.ls DELETE files
+
+Delete the named files. A warning message is printed if a file
+cannot be deleted. It is not considered an error to attempt to
+delete a file which does not exist. Protected files cannot be
+deleted without first removing their protection.
+
+.nf
+Hidden Parameters:
+ verify bool = no Generate query to verify that each
+ file should indeed be deleted.
+.fi
+.le
+.ke
+
+.ks
+.ls DEVSTATUS device
+
+Print status information (i.e., is the device allocated, to whom, etc.)
+for the named device.
+.le
+.ke
+
+.ks
+.ls DIRECTORY [files] [,op=string]
+
+Tabulate information on all files matching the template given as the
+first argument on the standard output. If no template is given, the
+contents of the current directory are displayed. The "long" format
+gives file protection status, type (text, binary, directory, or executable),
+access modes (owner, group, world), owner name, size in bytes, date of
+last modify, and the file name.
+
+.nf
+Hidden Parameters:
+ option string = "m" 1 one-column format
+ a use time of last access
+ c use time of creation
+ l long format
+ m multicolumn format (default)
+ s add size in Kb
+ t time sort
+ r reverse sort
+
+e.g.: > dir op=l (show current directory, long form)
+ > dir "*.x",op=lt (all ".x" files in current directory, long form)
+.fi
+.le
+.ke
+
+.ks
+.ls DISKSPACE
+
+Summarize the amount of disk space available on the local system.
+This command and its output are machine dependent. This command
+may not be available on all systems.
+.le
+.ke
+
+.ks
+.ls HEAD files
+
+Print the first few lines of each of the named files on the standard
+output. If more than one file is printed, a brief header is printed to
+identify each file.
+
+.nf
+hidden params:
+ nlines int = 12 number of lines to print
+.fi
+.le
+.ke
+
+.ks
+.ls LPRINT files
+
+The named text files (or the standard input) are printed on the standard
+line printer device. If several files are to be printed, each file is
+printed starting on a new page, and file pages are broken and printed
+with numbered headers. If reading from the standard input, the input
+stream is copied to the printer without pagination, though pages may still
+be broken by embedding formfeed characters in the text. The map_cc
+option may be used to turn off all control character mapping, if binary
+data is to be sent to the printer.
+
+.nf
+Hidden Parameters:
+ map_cc bool = yes Map control characters into a printable
+ sequence (^L, etc.)
+.fi
+.le
+.ke
+
+.ks
+.ls MATCH pattern, files
+
+Search each text file for the given pattern. Copy a line to the standard
+output if the pattern can be matched. Match against the standard input
+if no files are named.
+
+.nf
+Hidden Parameters:
+ stop bool = no Stop matched lines and pass unmatched
+ lines to the output instead.
+.fi
+.le
+.ke
+
+.ks
+.ls NEWS
+
+Page through the system news file, starting with the most recent entries.
+The system news file is a sort of electronic bulletin board, used to
+post announcements and notes of general interest.
+.le
+.ke
+
+.ks
+.ls PAGE files
+
+The named text files (or the standard input) are displayed a page at a
+time on the standard output. If there is more than one input file,
+a brief header is printed at the beginning of each file.
+
+.nf
+Hidden Parameters:
+ map_cc bool = yes Map control characters into a printable
+ sequence (^L, etc.)
+.fi
+.le
+.ke
+
+.ks
+.ls PROTECT files
+
+Protect the named files from deletion or clobber, accidental or otherwise.
+It is not considered an error to attempt to protect a file which is already
+protected. Protecting a file prevents only deletion or clobber of the entire
+file: the contents of the file may still be overwritten.
+.le
+.ke
+
+.ks
+.ls RENAME file|files, output_file|directory
+
+Rename a file, or move each file in the input list to the directory
+given as the second argument.
+.le
+.ke
+
+.ks
+.ls SORT files
+
+Sort and/or merge the text files named in the list, or sort the standard
+input if no list. Sorting is by line or column, alphabetically or
+numerically, in forward or reverse order.
+
+.nf
+Hidden Parameters:
+ numeric_sort bool = no Sort numerically instead of
+ alphabetically, if datum is
+ a number.
+ reverse_sort bool = no Reverse the sense of the sort.
+ column int = 0 If 0, sort the entire line, else
+ sort the indicated column.
+ ignore_whitespace bool = yes Ignore leading whitespace if
+ sorting full lines.
+ merge bool = no Merge the input files, which are
+ assumed to already have been
+ sorted.
+.fi
+.le
+.ke
+
+.ks
+.ls SPY
+
+Get information on who is using the system, what they are up to, how
+much cpu time, etc., they have used, and so on. This command, and the
+information it gives, are machine dependent. This command may not be
+available on all systems.
+
+.nf
+Hidden Parameters:
+ verbose bool = no Give more detailed information.
+.fi
+.le
+.ke
+
+.ks
+.ls STTY [terminal]
+
+Identify the type of terminal being used, if different than the system
+default. This is necessary to tell the system the control sequence to
+be used to clear the screen, the dimensions of the screen, etc. If no
+arguments are given, the current terminal status is given.
+
+.nf
+Hidden Parameters:
+ baud int = 0 If nonzero, the system takes the
+ argument as the new baud rate.
+ ncols int = 0 If nonzero, the argument becomes
+ the number of columns per screen.
+ nlines int = 0 If nonzero, the argument becomes
+ the number of lines per screen.
+.fi
+.le
+.ke
+
+.ks
+.ls TAIL files
+
+Print the last few lines of each of the named text files on the
+standard output.
+
+.nf
+Hidden Parameters:
+ nlines int = 12 Number of lines to print.
+.fi
+.le
+.ke
+
+.ks
+.ls TEE file
+
+Copy the standard input to the standard output, as well as to the named
+output file.
+
+.nf
+Hidden Parameters:
+ out_type string = "text" Type of output file (text|binary).
+ append bool = no Append to the output file.
+.fi
+.le
+.ke
+
+.ks
+.ls TIME
+
+Print the current time and date.
+.le
+.ke
+
+.ks
+.ls TYPE files
+
+Copy the named text files to the standard output. If more than one file is
+to be typed, a brief header is printed at the beginning of each file,
+identifying the file.
+.le
+.ke
+
+.ks
+.ls UNPROTECT files
+
+Remove delete protection from the named files. It is not considered
+an error to attempt to remove protection from a file which is not protected.
+.le
+.ke
+.endhelp
diff --git a/pkg/system/doc/Sys_intro.hlp b/pkg/system/doc/Sys_intro.hlp
new file mode 100644
index 00000000..03d7e797
--- /dev/null
+++ b/pkg/system/doc/Sys_intro.hlp
@@ -0,0 +1,137 @@
+.help system May83 "General Aspects of the System Package"
+.sh
+Basic IRAF System Utilities
+
+ A number of standard utilities are available as part of the IRAF
+user interface. These utilities, most of which operate on files, are
+summarized later in this document. A general discussion of files in
+the IRAF system follows. The reader is assumed to have some familiarity
+with the IRAF command language (CL).
+
+
+.sh
+Virtual File Names
+
+ File names may be specified in a machine independent fashion, or with
+OS dependent pathnames. A Virtual File Name (VFN) has the following form:
+
+
+.nf
+ ldir$root.extn
+
+where
+
+ ldir logical directory or device name
+ root root or base file name
+ extn extension denoting the type of file
+.fi
+
+
+The LDIR and EXTN fields are optional. The ROOT and EXTN fields may contain
+up to 20 characters selected from the set [a-zA-Z0-9_.+-#]. The EXTN field
+may not exceed three characters. The EXTN field is separated from the ROOT
+by the character "." (dot). If the ROOT field contains one or more occurrences
+of the dot character, the final dot delimited field is understood to be
+the extension.
+
+Logical directories are defined in the CL, using the SET command to associate
+an OS dependent pathname with a keyword in the environment table. Logical
+directory prefixes are recursively expanded.
+
+A number of standard logical directories and devices are defined by the CL
+at startup time. Additional logical directories are defined by applications
+packages upon entry, and become undefined when dictionary space is reclaimed
+on exit from the package. The user may override environment definitions at
+will, by issuing SET commands to redefine environment variables.
+
+
+.sh
+File List Templates
+
+ Whenever it makes sense, the IRAF utilities are set up to process a list
+of files, rather than a single file. In the descriptions of the standard
+utilities in the next section, "files" is a template or pattern specifying
+a list of files to be processed in some way. The template is a string type
+parameter to the CL, which is expanded by a procedure (CLGFIL) in the
+compiled systems or applications task into an EOF terminated list of files.
+
+A template may consist of one or more file names, directory names,
+list file names, or patterns. List elements are delimited by commas.
+A list file is denoted by prepending the character "@" to the pathname
+of the list file. A pattern may be applied to the contents of either
+a list file or a directory. The pattern is separated from the list file
+or directory name by the character "$". A pattern all by itself is
+applied to the current directory. Either logical or OS dependent
+pathnames may be used.
+
+A list element may refer only to a single directory. Thus, one cannot
+specify a pattern such as "*/*.x", as is possible in UNIX.
+
+Some examples of templates follow:
+
+.nf
+ file
+ "file1, file2"
+ "*.x"
+ "[A-Z]*, *.com, ../$, ../fio/$*.x, lib$*.h, file, @list$*.vs"
+ "sia1:[iraf.lib]$*.h, uparm$cl_*.par"
+.fi
+
+The magic filenames "STDIN", "STDOUT", and "STDERR" have a special
+meaning. Passing one of these special filenames to a task causes
+the named stream to be "reopened", transparently to the applications
+program. Thus, for example, one can reference "STDIN" in a template,
+and the applications program will read from the standard input when
+it opens the corresponding file in the template.
+
+For example,
+
+ cl> concat "file1, @STDIN, STDIN, file2", > ofile
+
+concatenates the file "file1", the contents of the files named in the
+standard input (until the first EOF), the contents of the standard input
+itself (until the second EOF), and the contents of the file "file2",
+placing the output in the file "ofile".
+
+
+.sh
+File Protection and Clobber
+
+ The IRAF file interface (FIO) provides file protection and synchronization
+facilities, under control of user definable environment variables.
+
+File "clobber" refers to the overwriting of an existing file when a new
+file of the same name is created as an output file. If "clobber" is
+defined as "no" in the environment, an IRAF task will abort if a new file
+would clobber an existing file. If file clobber is enabled, FIO will try
+to overwrite the old file, and will abort if it cannot do so.
+
+ cl> set clobber = "yes"
+
+More explicit file protection is provided by the CL commands PROTECT and
+UNPROTECT. A protected file cannot be deleted, accidentally or otherwise,
+until the protection has been removed with the UNPROTECT command or system
+call.
+
+A final form of file protection is provided to prevent a file from being
+clobbered which is already open by a task. Thus, "COPY file,file" will
+abort when FIO discovers that "file" is already opened for reading. This
+holds even if file clobber is enabled.
+
+
+.sh
+File Synchronization
+
+ File synchronization is useful when a process requires exclusive access
+to a file which is already open for exclusive access by another process.
+When this situation occurs, the second task may abort with a message stating
+that it cannot access the file, or the task may wait for the file to become
+available. File waiting is especially important for batch processes.
+
+ cl> set file_wait = "yes"
+
+The file wait option is controlled by the "file_wait" variable in the
+environment. If file waiting is enabled, and a process finds that it
+has to wait to access a file, a warning message will be printed on the
+standard error output before the affected process goes to sleep.
+.endhelp
diff --git a/pkg/system/doc/allocate.hlp b/pkg/system/doc/allocate.hlp
new file mode 100644
index 00000000..66d3353f
--- /dev/null
+++ b/pkg/system/doc/allocate.hlp
@@ -0,0 +1,52 @@
+.help allocate Jan86 system
+.ih
+NAME
+allocate -- allocate a device
+.ih
+USAGE
+allocate device
+.ih
+PARAMETERS
+.ls device
+The device to be allocated.
+.le
+.ih
+DESCRIPTION
+\fBAllocate\fR allocates a device for exclusive access by one user, and
+readies the device for i/o by some other program. A list of the devices
+available on the local system is maintained in the file \fBdev$tapecap\fR
+which needs to be configured by the site manager before it can be used.
+The status of given device may be obtained by calling \fIdevstatus\fR.
+.ih
+EXAMPLES
+
+1. Print a list of the allocatable devices. The logical device names are
+given at the left in the output text; ignore the information to the right.
+\fBNote\fR: The dev$devices file should be configured by the site manager
+when new tape devices are installed. Beginning with V2.9 it is used for
+informational purposes only.
+.ks
+.nf
+ cl> type dev$devices
+ mta ...
+ mtb ...
+ mtc ...
+ iis ...
+.fi
+.ke
+
+
+2. Allocate a tape drive after checking its status.
+
+.ks
+.nf
+ cl> devstatus mtb
+ device mtb is not currently allocated
+ cl>
+ cl> allocate mtb
+.fi
+.ke
+.ih
+SEE ALSO
+deallocate, devstatus
+.endhelp
diff --git a/pkg/system/doc/bench.hlp b/pkg/system/doc/bench.hlp
new file mode 100644
index 00000000..1e8b373e
--- /dev/null
+++ b/pkg/system/doc/bench.hlp
@@ -0,0 +1,56 @@
+.help bench Dec2010 system
+.ih
+NAME
+bench -- simple benchmark tool
+.ih
+USAGE
+bench
+.ih
+DESCRIPTION
+The BENCH task provides a simple benchmark meant to simulate CCD processing
+of three images. The tasks used exercise both disk- and CPU-intensive
+applications and offer a crude comparison of performance between machines,
+but it is not intended to be a comprehensive benchmark. There are no
+parameters.
+.ih
+EXAMPLES
+1. Run the benchmark:
+
+.nf
+ ecl> bench
+
+ Bench started at 09:45:58
+
+ =====> Making images...
+ Making zero...
+ Making flat...
+ Making 3 objs...
+
+ =====> Normalizing flat...
+ :
+
+ =====> Subtracting zero from 3 images...
+ :
+
+ =====> Dividing flat into 3 images...
+ :
+
+ =====> Combining 3 images...
+ :
+
+ =====> Median filtering image...
+ :
+
+ =====> Deleting all images...
+
+ Bench started at 09:45:58
+ Bench ended at 09:46:56
+
+ Total execution time = 58.0 seconds
+ Total time Make 5 imgs Proc 3 imgs Combine 3 imgs Median 1 img
+ 58.0 25.0 10.0 4.0 19.0
+.fi
+
+.ih
+SEE ALSO
+.endhelp
diff --git a/pkg/system/doc/chkupdate.hlp b/pkg/system/doc/chkupdate.hlp
new file mode 100644
index 00000000..c4209753
--- /dev/null
+++ b/pkg/system/doc/chkupdate.hlp
@@ -0,0 +1,72 @@
+.help chkupdate Oct13 system
+.ih
+NAME
+chkupdate - Check for an available IRAF update
+.ih
+USAGE
+chkupdate
+.ih
+PARAMETERS
+.ls interval = 0
+Number of days between updates checks. A value less than zero will disable
+the checks entirely, a value of zero will cause a check to be made with
+each login.
+.le
+.ls ref_file = "iraf$.release_date"
+.le
+.ls release = ")_.release"
+Current IRAF release version. This value is inherited from the CL 'release'
+parameter by default.
+.le
+.ls baseurl = "http://iraf.noao.edu/ftp"
+Base URL to the IRAF release timestamp directory.
+.le
+.ls verbose = yes
+Print verbose output?
+.le
+.ih
+DESCRIPTION
+This task compares the currently installed IRAF version with what is
+available from the NOAO servers and will indicate whether an update is
+available. The task is executed from the login.cl each time you login
+to the CL, however the comparison is only done if 1) the uparm$update
+file used to indicate the time of last check does not exist, 2) the
+\fIinterval\fR parameter is zero to indicate the check should be done
+with each login, or 3) more than \fIinterval\fR days have passed since
+the last time the servers were contacted. An \fIinterval\fR value less
+that zero may be used to disable the version updates entirely.
+
+The update check is done by comparing the file timestamp of the file
+named in the \fIref_file\fR parameter with a distribution timestamp file
+on the NOAO servers. The URL to this file is constructed from the
+\fIbaseurl\fR and \fIrelease\fR parameters in addition to the \fIarch\fR
+environment value, yielding a unique URL for each version and each platform.
+If the contents of the file contain a timestamp more recent than the
+timestamp of the \fIref_file\fR value, a message is printed to indicate
+an update is available, otherwise a message is printed indicating the
+installed system is current.
+.ih
+EXAMPLES
+
+1. Check whether an IRAF update is available, regardless of when we last
+checked.
+
+.nf
+ cl> chkupdate interval=0
+.fi
+
+2. Check for an IRAF update once a month.
+
+.nf
+ cl> chkupdate.interval = 30
+.fi
+
+.ih
+NOTES
+This task is called automatically from the login.cl file at startup.
+
+Modifying the timestamp information of the \fIref_file\fR parameter, e.g.
+by moving the IRAF tree, may invalidate the output.
+.ih
+SEE ALSO
+.endhelp
diff --git a/pkg/system/doc/concatenate.hlp b/pkg/system/doc/concatenate.hlp
new file mode 100644
index 00000000..e3cd4fdc
--- /dev/null
+++ b/pkg/system/doc/concatenate.hlp
@@ -0,0 +1,82 @@
+.help concatenate Nov84 system
+.ih
+NAME
+concatenate -- connect files together into one big file
+.ih
+USAGE
+concatenate files [output_file]
+.ih
+PARAMETERS
+.ls files
+The list of input files. The standard input, STDIN, may be specified to
+interactively enter a few lines of text rather than read from a disk file.
+All input files should be of the same type (binary or text).
+.le
+.ls output_file
+The name of the output file. If no file is explicitly specified the
+standard output (STDOUT) is used.
+.le
+.ls out_type = in_type
+The output file type is forced if this parameter is defined as "binary"
+or "text". If "out_type" does not begin with a "b" (or "B"), or a
+"t" ("T"), then the output type is either "text", if the output file is
+the standard output, or is determined from the type of the first input file.
+.le
+.ls append = no
+If set to "yes", "files" are appended to "output_file".
+.le
+.ih
+DESCRIPTION
+Each file in the input file list is appended to the output file.
+If "output_file" is not the standard output, and if output redirection (">")
+was not specified on the command line, the resulting stream of data is placed
+in a file. The input can be STDIN, which makes for an easy way to enter a
+few lines of text into a file (but \fItype\fR is usually more convenient).
+If entering data via the standard input, type the end of file character,
+e.g., <ctrl/z>, to terminate the input sequence.
+.ih
+EXAMPLES
+
+1. Write out file1, followed by file2, to the terminal screen. Note that
+there must be no space after the comma.
+
+.nf
+ cl> concatenate file1,file2
+.fi
+
+2. Write out files file1 and file2 into the new file "outfile".
+
+.nf
+ cl> concatenate file1,file2 outfile
+.fi
+
+3. Copy what you type (up to the end-of-file character) into the file junk.
+
+.nf
+ cl> concatenate STDIN junk
+.fi
+
+4. Write out the contents of each of the files whose names are given in "list",
+one per line, and append this data to "junk".
+
+.nf
+ cl> concatenate @list junk append+
+.fi
+
+5. Concatenation is also possible using \fItype\fR, e.g., the following
+command will append the contents of "file" to the file "outfile", which will
+be created if it does not already exist.
+
+ cl> type file >> outfile
+
+The redirect-append operator ">>" may be used to append the output of any
+task to a file.
+
+.ih
+NOTES
+All input files should be of the same type, either all "text" or all
+"binary".
+.ih
+SEE ALSO
+copy, type
+.endhelp
diff --git a/pkg/system/doc/copy.hlp b/pkg/system/doc/copy.hlp
new file mode 100644
index 00000000..9c58566d
--- /dev/null
+++ b/pkg/system/doc/copy.hlp
@@ -0,0 +1,47 @@
+.help copy Nov84 system
+.ih
+NAME
+copy -- copy a file, or a set of files to a directory
+.ih
+USAGE
+copy input output
+.ih
+PARAMETERS
+.ls input
+The input file or list of files to be copied.
+.le
+.ls output
+The (new) output file when copying one file to another, or the destination
+directory when copying a set of files.
+.le
+.ls verbose = no
+If set to "yes", a line of the type " from -> to " is printed on the
+terminal for each file copied to a directory. This parameter is not
+used when copying one file to another.
+.le
+.ih
+DESCRIPTION
+Copy makes a copy of a single file, or it copies a set of files to a different
+directory.
+.ih
+EXAMPLES
+
+1. Copy all files in the current directory with extension ".x" to the
+directory "home$src". As each copy is made, the user is informed.
+
+ cl> copy *.x home$src ver+
+
+2. Make a copy "fred.BAK" of the file "fred".
+
+ cl> copy fred fred.BAK
+
+3. Copy the "graphcap" file from the remote node "lyra" to the current node,
+without changing the name of the file. Note that "." is a synonym for the
+current directory.
+
+ cl> copy lyra!dev$graphcap .
+
+.ih
+SEE ALSO
+concatenate, movefiles
+.endhelp
diff --git a/pkg/system/doc/count.hlp b/pkg/system/doc/count.hlp
new file mode 100644
index 00000000..09601019
--- /dev/null
+++ b/pkg/system/doc/count.hlp
@@ -0,0 +1,44 @@
+.help count Nov84 system
+.ih
+NAME
+count -- determine number of lines, words and characters in a file
+.ih
+USAGE
+count files
+.ih
+PARAMETERS
+.ls files
+A template specifying the files to be examined.
+.le
+.ih
+DESCRIPTION
+For each file, count determines the number of lines, words, and
+characters in the file. A word is defined as a sequence of characters
+delimited by one or more blanks or tabs, or by the end of a line.
+If \fIcount\fR is run on more than one file, each output line is identified
+by the file name, and a final output line gives the total number
+of lines, words, and characters in all files.
+.ih
+EXAMPLES
+
+1. Count the number of lines, words and characters in all files in the
+current directory with the extensions ".x" and ".h".
+
+ cl> count *.[xh]
+
+2. Count the number of .x files in the current directory.
+
+ cl> dir *.x op=1 | count
+
+3. Count the number of \fIset\fR environment definitions.
+
+ cl> set | count
+
+4. Count the number of references to the READ function in all .x files in
+the current directory.
+
+ cl> match "read#(" *.x | count
+.ih
+SEE ALSO
+directory
+.endhelp
diff --git a/pkg/system/doc/deallocate.hlp b/pkg/system/doc/deallocate.hlp
new file mode 100644
index 00000000..803c9d6a
--- /dev/null
+++ b/pkg/system/doc/deallocate.hlp
@@ -0,0 +1,34 @@
+.help deallocate Jan86 system
+.ih
+NAME
+deallocate -- deallocate a device
+.ih
+USAGE
+deallocate device
+.ih
+PARAMETERS
+.ls device
+The device to be deallocated.
+.le
+.ls rewind = yes
+Rewind the device before deallocating?
+Ignored for devices other than magtape.
+.le
+.ih
+DESCRIPTION
+Deallocate a previously allocated device. The CL will print an error
+message if one attempts to logout while devices are still allocated,
+but if \fIlogout\fR is typed several times you will be allowed to logout
+with the devices still allocated. The CL does not automatically
+deallocate devices upon logout.
+.ih
+EXAMPLES
+
+1. Deallocate logical magtape drive B.
+
+ cl> dealloc mtb
+
+.ih
+SEE ALSO
+allocate, devstatus, file dev$devices, dev$tapecap
+.endhelp
diff --git a/pkg/system/doc/delete.hlp b/pkg/system/doc/delete.hlp
new file mode 100644
index 00000000..78ac7df3
--- /dev/null
+++ b/pkg/system/doc/delete.hlp
@@ -0,0 +1,57 @@
+.help delete Nov84 system
+.ih
+NAME
+delete -- delete a file or files
+.ih
+USAGE
+delete files
+.ih
+PARAMETERS
+.ls files
+The list of files to be deleted.
+.le
+.ls verify = no
+Check with the user before deleting a file. If verify is enabled the file
+name is printed and the user is queried before the default action is taken.
+.le
+.ls default_action = yes
+This is the default action to take when operating in "verify" mode.
+For example, if the default action is "yes", one need only type RETURN in
+response to the verify prompt to delete the file.
+.le
+.ls allversions = yes
+Delete all versions of a file. This parameter has no effect on systems like
+UNIX which do not support multiple file versions.
+.le
+.ls subfiles = yes
+Delete subfiles. Not currently used.
+.le
+.ih
+DESCRIPTION
+\fIDelete\fR destroys a file or files and returns the space they occupied to
+the host system, to be reused for other files. Once a file has been deleted,
+it is gone forever (unless a copy exists somewhere). Enabling \fIverify\fR
+gives one the opportunity to say yes or no before each file is deleted; this
+is particularly useful when \fIfiles\fR is a template. Note that
+\fIprotect\fR can be used to protect files from deletion, accidental or
+otherwise. Imagefiles are automatically protected by the system to remind
+the user to use \fIimdelete\fR to delete images (this is necessary because
+an image is stored in more than one physical file).
+.ih
+EXAMPLES
+
+1. Delete all files with extension ".x", verifying each file deletion before
+it is performed.
+
+ cl> delete *.x ver+
+
+2. List all files in the current directory, deleting only those files for
+which the user responds to the verify prompt with "yes" or "y". Note that
+"delete *" is a very dangerous operation.
+
+ cl> delete * ver+ def=no
+
+.ih
+SEE ALSO
+protect, unprotect, imdelete
+.endhelp
diff --git a/pkg/system/doc/devstatus.hlp b/pkg/system/doc/devstatus.hlp
new file mode 100644
index 00000000..bccd7ffe
--- /dev/null
+++ b/pkg/system/doc/devstatus.hlp
@@ -0,0 +1,57 @@
+.help devstatus Jan86 system
+.ih
+NAME
+devstatus -- print status information for a device
+.ih
+USAGE
+devstatus device
+.ih
+PARAMETERS
+.ls device
+The device for which status information is requested.
+.le
+.ls verbose = no
+Print additional system dependent device information (may not be implemented
+on all systems).
+.le
+.ih
+DESCRIPTION
+\fBDevstatus\fR tells whether the named device has been allocated.
+In the case of a magtape drive allocated to the current user, additional
+information is printed noting the tape position and the type of operation
+last performed. If the device is not currently allocated, i.e., available
+for allocation, or if the device has already been allocated by another user,
+one of the following messages is printed:
+
+.nf
+ device is not currently allocated
+ device is allocated to XXXX
+.fi
+
+A list of the allocatable devices, including the host system names for the
+devices, can be obtained by paging the file \fBdev$devices\fR providing
+that file has been properly configure by the Site Manager at installation
+time. The dev$tapecap file is used to define the tape devices available
+on the system.
+.ih
+EXAMPLES
+
+1. Get status information for the logical tape drive "mta", which we have
+just allocated. Note that the tape position is printed only if we are the
+owner of the drive.
+
+.nf
+ cl> dev mtb
+ # Magtape unit `mta' allocated to `smith' Fri 12:04:16 07-Jan-86
+ file = 1
+ record = 1
+ unit just allocated: no i/o has yet occurred
+.fi
+
+.ih
+BUGS
+Information can only be requested for a single device at a time.
+.ih
+SEE ALSO
+allocate, deallocate
+.endhelp
diff --git a/pkg/system/doc/directory.hlp b/pkg/system/doc/directory.hlp
new file mode 100644
index 00000000..8c4382e9
--- /dev/null
+++ b/pkg/system/doc/directory.hlp
@@ -0,0 +1,148 @@
+.help directory Mar87 system
+.ih
+NAME
+directory -- list the contents of a file directory
+.ih
+USAGE
+directory [files]
+.ih
+PARAMETERS
+.ls files
+A file template specifying the files to be listed, or the name of the directory
+whose contents are to be listed. If omitted entirely, the contents of the
+current directory are listed.
+.le
+.ls long = no
+Long format listing. The long format listing lists each file on a separate
+line, noting the file permissions, file type, file size, modify date, owner,
+etc. of each file.
+.le
+.ls ncols = 0
+If nonzero, the number of columns of output in multicolumn format.
+.le
+.ls maxch = 18
+The maximum number of characters to be displayed in each filename.
+Truncation may be desirable when listing a directory containing one or two
+files with very long filenames.
+.le
+.ls sort = yes
+Sort the file list alphabetically. If sorting is disabled the directory
+program lists the files in the order in which they are read from the
+directory, which may or may not be sorted. The directory listing is produced
+line by line as files are read from the directory, rather than accumulating
+the entire file list in memory before composing the table, hence this is the
+fastest method of listing a directory, particularly if the directory is very
+large.
+.le
+.ls all = no
+List all files, including the hidden ("." prefixed) files, and files with
+reserved filename extensions used internally by the VOS.
+.le
+.ih
+DESCRIPTION
+The \fBdirectory\fR task lists or prints information describing some subset
+of the files in a directory or directories. If no name template is given,
+"." is assumed, i.e., all files in the current directory are listed.
+
+The long format listing gives a file type string, followed by
+the name of the owner of the file, the file size, date and time at which
+the file was last modified, and lastly the file name.
+The file type string has fields noting if the file is a directory file (d),
+an executable file (x), a text or binary file (t or b), a protected file (p),
+and summarizing the file permissions (read or write, r or b) for the owner,
+the group, and the rest of the world. A minus sign indicates that the file
+does not have that particular attribute.
+
+All file names are printed in the IRAF virtual filename syntax, which is the
+same on all host machines. IRAF filenames may be up to 32 characters in
+length, may contain any combination of alphanumeric characters, underscore,
+or period, and are case sensitive. Some of the common filename extensions
+are listed below; these are mapped to and from the host filename extensions
+when a file is accessed, a directory is listed, or a filename template is
+expanded.
+
+.nf
+ .a object library
+ .c C source file
+ .cl CL source file
+ .e executable (runnable) file
+ .f Fortran source file
+ .gX generic source file (X=[cx])
+ .h global header file
+ .hlp help file
+ .o object file
+ .par CL parameter file
+ .s assembler source file
+ .x SPP source file
+.fi
+
+When listing large directories, the time required to accumulate and sort the
+entire directory in memory before producing the output listing may become
+significant (i.e., more than a few seconds). If this happens, try setting
+the \fIsort\fR option to \fIno\fR, and the directory listing should appear
+immediately.
+.ih
+EXAMPLES
+
+1. List all the files in the current directory in tabular format.
+
+ cl> dir
+
+2. Print detailed information on all files in the current directory.
+
+.nf
+ cl> dir l+
+ -t-rwr-r- iraf 269 Oct 16 1983 README
+ dt-rwrwr- iraf 1024 Feb 7 12:48 doc
+ -t-rwr-r- iraf 60 Jan 30 1984 files.par
+ -t-rwr-r- iraf 420 Jan 30 1984 files.x
+ -b-rwrwr- system 187338 Jan 29 19:27 libpkg.a
+ xb-rwr-r- iraf 363520 Jan 29 19:29 x_system.e
+ -b-rwrwr- system 5037 Jan 19 22:15 x_system.o
+ -t-rwr-r- iraf 633 Jan 19 22:01 x_system.x
+.fi
+
+3. Print a single column listing of all the files with extension ".h"
+in the logical directory "lib$".
+
+.nf
+ cl> dir lib$*.h l+
+ lib$chars.h
+ lib$clio.h
+ lib$clpopn.h
+ (etc)
+.fi
+
+4. While in the "system" directory, print the contents of the parallel
+directory "dataio".
+
+.nf
+ cl> cd pkg$system
+ cl> dir ../dataio
+.fi
+
+5. Test if the file "alpha" exists in the current directory. In the example,
+the output given indicates that the file was not found.
+
+.nf
+ cl> dir alpha
+ no files found
+.fi
+
+6. Print the contents of the directory USR$2:[IRAF.LOCAL] on the remote VMS
+node "draco" (requires IRAF network access to the remote node).
+
+.nf
+ cl> dir draco!usr\$2:\[iraf.local]
+.fi
+.ih
+BUGS
+There is no provision for wildcarding directories, e.g., "dir */*.x".
+The long format listing can currently only be sorted by filename (although
+the \fIsort\fR program may be used in a pipe). The file existence test will
+not be performed if individual files are named as list elements within
+a filename template.
+.ih
+SEE ALSO
+files, pathnames
+.endhelp
diff --git a/pkg/system/doc/diskspace.hlp b/pkg/system/doc/diskspace.hlp
new file mode 100644
index 00000000..538f308d
--- /dev/null
+++ b/pkg/system/doc/diskspace.hlp
@@ -0,0 +1,33 @@
+.help diskspace Feb85 system
+.ih
+NAME
+diskspace -- summarize disk space utilization
+.ih
+USAGE
+diskspace
+.ih
+DESCRIPTION
+\fIDiskspace\fR lists the disk devices available on the host system,
+giving the name, capacity, and free space available on each device.
+The format and contents of the output are host system dependent.
+.ih
+EXAMPLE
+
+1. Print the available diskspace (UNIX host).
+
+.nf
+ cl> disk
+ Filesystem kbytes used avail capacity Mounted on
+ /dev/hp0a 7421 5312 1366 80% /
+ /dev/hp0g 38430 5340 29246 15% /tmp
+ /dev/hp0h 51598 38848 7590 84% /usr
+ /dev/ra0a 8007 5657 1549 79% /mnt
+ /dev/ra0d 88179 46043 33318 58% /u1
+ /dev/ra0e 54382 46694 2248 95% /local
+ /dev/ra0f 145435 93733 37158 72% /u2
+ /dev/ra0g 28720 350 25497 1% /usr/spool
+ /dev/ra0h 79798 41696 30122 58% /iraf
+ /dev/ra1h 397102 306688 50702 86% /tmp2
+ /dev/ra2h 397102 275010 82380 77% /tmp3
+.fi
+.endhelp
diff --git a/pkg/system/doc/fcache.hlp b/pkg/system/doc/fcache.hlp
new file mode 100644
index 00000000..b5230307
--- /dev/null
+++ b/pkg/system/doc/fcache.hlp
@@ -0,0 +1,140 @@
+.help fcache Jun2011 system
+.ih
+NAME
+fcache -- list, clean or manipulate the file cache
+.ih
+USAGE
+fcache cmd
+.ih
+PARAMETERS
+.ls cmd
+Cache command to execute. A description of each command is given below.
+.le
+.ls pattern = "*"
+Filename substring pattern to match when initializing the cache with
+the \fIinit\fR command.
+.le
+.ls src = ""
+Source string used to generate the cache filename. This is typically
+the full path to a local file being cached or a URL.
+.le
+.ls fname = ""
+Name of the file in the cache.
+.le
+.ls extn = ""
+Cache filename extension.
+.le
+.ls age = -1
+Age of the file (in days) to be purged with the \fIpurge\fR command. A value
+less than zero means that the \fIcache_age\fR environment variable should
+is used to set the age, a value of zero means to delete all files in the
+cache (same as the \fIinit\fR command), a value greater than zero means
+that files older than this age will be deleted.
+.le
+.ls verbose = no
+Print status information as the task processes the command.
+.le
+.ls wait = yes
+Block on operation? If 'yes' then the task will block until the requested
+file becomes available in the cache.
+.le
+.ls cache = "cache$"
+Cache directory to be used.
+.le
+
+.ih
+DESCRIPTION
+The \fIFCACHE\fR command is used to list or manage the system file cache
+named by the \fIcache\fR parameter. If the \fIcache\fR directory does not
+exist, it will be created when required. The \fIcache_age\fR environment
+variable determines the default maximum age of files in the cache, older
+files are automatically removed by the login.cl as part of the startup
+process.
+
+The IRAF file cache is used primarily to cache local copies of URLs in the
+system to prevent repeated downloads when accessing URLs from tasks. This
+allows a URL to be passed to multiple tasks without explicitly requiring
+the user to create a named (temporary) file themselves.
+
+The \fIcmd\fR parameter determines the action to take, other parameters are
+used as needed depending on the command according to the following table:
+
+.nf
+ Command Input Pars Output Pars Action
+ ------- ---------- ----------- ------
+ init pattern Initialize the cache
+ purge age Purge old files
+ destroy Destroy the cache
+ list List cache contents
+ lookup src fname,extn Lookup a file in the cache
+ access src Is file in cache?
+ add src extn fname Add file to the cache
+ delete src fname Delete file from cache
+ wait src Wait for access to file
+.fi
+
+The \fIlookup\fR command works in two ways: If a \fIsrc\fR string is
+provided then the \fIfname\fR parameter will contain the matching cached
+file (and \fIextn\fR will contain the optional extension), if the \fIfanme\fR
+parameter is specified then on output \fIsrc\fR will contain the original
+filename/URL.
+
+.ih
+EXAMPLES
+
+1. Remove all "url" files from the cache.
+.nf
+ cl> fcache init pattern="url"
+.fi
+
+2. List the contents of the file cache.
+.nf
+ cl> fcache list
+.fi
+
+3. Destroy a cache directory (i.e. remove it entirely).
+.nf
+ cl> fcache destroy cache="/tmp/cache"
+.fi
+
+4. Purge all cache files older than 7 days:
+.nf
+ cl> fcache purge age=7
+.fi
+
+5. Determine if a URL is already in the cache:
+.nf
+ cl> fcache add src="/tmp/dpix.fits"
+ cl> fcache list
+ f1128531670 1 /tmp/dpix.fits
+ f789045894 1 http://iraf.noao.edu/vao/dpix.fits
+ cl> fcache access src="/tmp/dpix.fits"
+ yes
+ cl> fcache access src="http://iraf.noao.edu/vao/dpix.fits"
+ yes
+.fi
+
+6. Delete a cached URL:
+.nf
+ cl> fcache delete src="http://iraf.noao.edu/vao/dpix.fits"
+.fi
+
+7. Add a local file to the cache, then look it up:
+.nf
+ cl> fcache add src="/tmp/test.fits"
+ cl> fcache lookup src="/tmp/test.fits"
+ cl> =fcache.fname
+ f1295587026
+ cl> fcache lookup fname="f1295587026"
+ cl> =fcache.src
+ /tmp/test.fits
+.fi
+
+
+.ih
+BUGS
+
+.ih
+SEE ALSO
+head
+.endhelp
diff --git a/pkg/system/doc/files.hlp b/pkg/system/doc/files.hlp
new file mode 100644
index 00000000..f2a0996f
--- /dev/null
+++ b/pkg/system/doc/files.hlp
@@ -0,0 +1,72 @@
+.help files Jun86 system
+.ih
+NAME
+files -- expand a file name template into a list of files
+.ih
+USAGE
+files template
+.ih
+PARAMETERS
+.ls template
+A file name template specifying the set of files to be listed.
+.le
+.ls sort = "yes"
+Sort the file list.
+.le
+.ih
+DESCRIPTION
+\fIFiles\fR lists all files matching the given template. The existence of
+the listed files is checked only if pattern matching is used, hence \fIfiles\fR
+may also be used to parse a comma delimited list of strings which are not
+necessarily filenames. \fIFiles\fR performs the same function as "dir l+"
+but is simpler and more convenient to use when generating file lists.
+
+The \fIfiles\fR task and all other tasks which operate upon groups of files
+use the \fBfile template\fR facility to specify the set of files to be
+operated upon. This should not be confused with the \fBimage template\fR
+facility, used by tasks which operate upon sets of images and which is
+documented in the manual page for the \fIsections\fR task.
+
+Pattern matching in a file template is provided by the usual pattern matching
+meta-characters "*?[]", documented in the CL User's Guide. Pattern matching
+is used to select files from one or more directories. In addition, the
+filename template notation provides two operators for generating new filenames
+from the matched filenames. These are the \fBconcatenation\fR operator "//",
+and the \fBstring substitution\fR operator "%chars%newchars%".
+The concatenation operator concatenates either a prefix to a filename,
+or a suffix to the root of a filename. The string substitution operator
+uses the "chars" to match filenames, and then replaces the "chars" by the
+"newchars" to generate the final output filename. Either string may be null
+length to insert into or delete characters from a filename.
+.ih
+EXAMPLES
+
+1. Generate a single column list of files in the current directory,
+sorted in ASCII collating sequence.
+
+ cl> files
+
+2. Generate an unsorted single column list of files in logical directory
+"lib$". Each entry in the output list is of the form "lib$...".
+
+ cl> files lib$ sort-
+
+3. Generate a file list to be used to make a set of new files. The new file
+names will be the old file names with "_1" concatenated to the root, e.g.,
+"root.x" would map to "root_1.x" and so on.
+
+ cl> files root.*//_1
+
+4. Generate a file list similar to that in [3], adding a directory prefix
+to each filename.
+
+ cl> files dir$//root.*
+
+5. Use string substitution to change the filename extension of a set of files
+to ".y".
+
+ cl> files root.%*%y%
+.ih
+SEE ALSO
+directory, pathnames, images.sections
+.endhelp
diff --git a/pkg/system/doc/gripes.hlp b/pkg/system/doc/gripes.hlp
new file mode 100644
index 00000000..3938e1ea
--- /dev/null
+++ b/pkg/system/doc/gripes.hlp
@@ -0,0 +1,67 @@
+.help gripes Mar86 system
+.ih
+NAME
+gripes -- send gripes or suggestions to the system
+.ih
+USAGE
+gripes subject
+.ih
+PARAMETERS
+.ls subject
+The subject of the gripe; any string, usually the name of package or task
+to which the gripe refers.
+.le
+.ls verbose = yes
+Print instructions on how to enter text whenever \fIgripes\fR is run.
+.le
+.ih
+DESCRIPTION
+The \fBgripes\fR task is used to post complaints, suggestions, or any other
+formal or informal comments regarding the IRAF system. Each gripe is
+appended to the system gripesfile "hlib$gripesfile", a public file which
+can be read by anyone by simply typing "page hlib$gripesfile" within IRAF.
+Use \fBtail\fR instead of \fBpage\fR to read only the most recent gripes.
+A copy of each gripe is also sent immediately to one or members of the IRAF
+group via electronic mail, to insure that the gripe gets read promptly (this
+feature is not available on all host systems).
+
+Gripe text is read from the standard input. A line containing only a period
+terminates the gripe, as does the end of file character (e.g., <ctrl/z>).
+If the line containing only "~e" is entered a text editor will be called up
+to edit the text of the gripe.
+
+Users are encouraged to use the gripe facility at will. Be assured that
+someone will at least read the gripe, although there is no guarantee that
+any action will be taken. In many cases there will be no response from the
+system, but nonetheless the gripe will be seen and it may well influence
+the direction in which the system evolves. Do not avoid posting gripes for
+fear that you do not understand something about the system; if enough users
+find some aspect of the system or a program confusing then that is more
+than sufficient reason for a gripe.
+.ih
+EXAMPLES
+
+1. The user has discovered some nasty features of the \fIimdelete\fR task
+and enters the following gripe. Note the use of the "." to terminate
+the text.
+
+.nf
+ cl> gripe
+ Subject: image deletion
+ Enter text of gripe. Type <eof> or '.' to quit:
+
+ IMDEL * will delete non image files as well as images!
+ It should be possible to delete images with the normal
+ DELETE command.
+ .
+ cl>
+.fi
+.ih
+BUGS
+There is currently no provision for communicating gripes from a remote site
+back to the site that wrote the software, unless some person manually mails
+a gripe (or the accumulated gripesfile).
+.ih
+SEE ALSO
+news
+.endhelp
diff --git a/pkg/system/doc/head.hlp b/pkg/system/doc/head.hlp
new file mode 100644
index 00000000..0b2f6393
--- /dev/null
+++ b/pkg/system/doc/head.hlp
@@ -0,0 +1,39 @@
+.help head Nov84 system
+.ih
+NAME
+head -- print the first few lines of the specified files
+.ih
+USAGE
+head files
+.ih
+PARAMETERS
+.ls files
+The list of files to be dealt with, quite possibly given as
+a template, such a "image*".
+.le
+.ls nlines = 12
+The number of lines to be printed.
+.le
+.ih
+DESCRIPTION
+\fIHead\fR prints, on the standard output, the first \fInlines\fR of each
+file that matches the given file list. If the file list has more than one
+name in it, a short header precedes each listing.
+.ih
+EXAMPLES
+
+1. Print the first 12 lines of each help file in the current directory.
+
+ cl> head *.hlp
+
+2. Print the first line of each help file.
+
+ cl> head *.hlp nl=1
+
+3. Print the most recently defined \fIset\fR environment definitions.
+
+ cl> set | head
+.ih
+SEE ALSO
+tail, page
+.endhelp
diff --git a/pkg/system/doc/help.hlp b/pkg/system/doc/help.hlp
new file mode 100644
index 00000000..74a53917
--- /dev/null
+++ b/pkg/system/doc/help.hlp
@@ -0,0 +1,599 @@
+.help help Oct01 system
+.ih
+NAME
+help -- print online documentation for the named modules or packages
+.ih
+USAGE
+help [template]
+.ih
+PARAMETERS
+.ls template
+A string listing the modules or packages for which help is desired.
+Each list element may be a simple name or a pattern matching template.
+Abbreviations are permitted. If \fItemplate\fR is omitted a long format
+menu will be printed for the current package, listing each task (or
+subpackage) and describing briefly what it is.
+.le
+.ls file_template = no
+If this switch is set the template is interpreted as a filename matching
+template, and all help blocks found in the named files are output. The help
+database is not searched, hence manual pages can be printed or documents
+may be formatted without entering the files into a help database.
+In other words, "help file.hlp fi+" makes it possible to use \fIhelp\fR as
+a conventional text formatter.
+.le
+.ls all = no
+Print help for all help modules matching \fItemplate\fR, rather than only the
+first one found.
+.le
+.ls parameter = "all"
+If the value of this parameter is not "all", only the help text
+for the given parameter will be printed.
+.le
+.ls section = "all"
+If the value of this parameter is not "all", only the help text for the
+given section (e.g. "usage", "description", "examples") will be printed.
+.le
+.ls option = help
+The option parameter specifies the type of help desired, chosen from
+the following:
+.ls help
+Print the full help block for the named module.
+.le
+.ls source
+Print the source code for the module (which often contains additional
+detailed comments).
+.le
+.ls sysdoc
+Print the technical system documentation for the named module.
+.le
+.ls directory
+Print a directory of all help blocks available for the named package.
+.le
+.ls alldoc
+Print all help blocks in the file containing the help block for
+the named procedure (i.e., both the user and system documentation).
+.le
+.ls files
+Print the names of all help files associated with the named modules or
+packages.
+.le
+.ls summary
+Print only the titles and sizes of help blocks in referenced help files.
+The contents of the blocks are skipped. Titles are printed for \fIall\fR
+help blocks found in the file containing the help block for the named module.
+.le
+.le
+.ls page = yes
+Pause after every page of output text. Turning this off for large documents
+speeds up output considerably.
+.le
+.ls nlpp = 59
+The number of lines per page if output is redirected, e.g., to \fIlprint\fR.
+.le
+.ls lmargin = 1
+Left margin on output.
+.le
+.ls rmargin = 72
+Right margin on output.
+.le
+.ls search = no
+If enabled the
+.hr #l_template template
+is interpreted as a search string and the task
+is started with the search panel open with the results of the search. The
+.hr #l_file_template file_template
+parameter is ignored with search turned on.
+.le
+.ls home = ""
+The home page for the task. If not set and no
+.hr #l_template template
+is specified
+the task will start with the online help in the main window, otherwise it
+may be set to a filename to be displayed when the task starts. This file
+may contain a text help block which will be formatted before display, or
+it may be a valid HTML file. See below for a description of the format of
+a homepage file which provides links to tasks.
+.le
+.ls printer = "printer"
+Default hardcopy printer name. If the \fIvalue\fR of the parameter is the
+reserved string "printer", the actual device is the value of the CL
+environment variable \fIprinter\fR.
+.le
+.ls showtype = no
+Add task-type suffix in package menus?
+.le
+.ls quickref = "uparm$quick.ref"
+Name of the quick-reference file used for searching. This file is created
+the first time the task is run in GUI mode or whenever it doesn't exist,
+or when any help database file has been updated.
+.le
+.ls uifname = "lib$scr/help.gui"
+The user interface file. This file is what defines the look and behavior
+of all the graphical user interface elements. Experts may create variants
+of this file.
+.le
+.ls helpdb = "helpdb"
+The filename of the help database to be searched. If the \fIvalue\fR of the
+parameter is the reserved string "helpdb", the actual filename is the value
+of the CL environment variable \fIhelpdb\fR.
+.le
+.ls device = "terminal"
+Output device if the standard output is not redirected. Allowable values
+include:
+.ls terminal
+If the \fIvalue\fR of
+the parameter is the reserved string "terminal", the actual device name is
+the value of the CL environment variable \fIterminal\fR.
+.le
+.ls text
+Output the formatted help page as plain text.
+.le
+.ls gui
+Invoke the GUI for browsing the help system. This option will only work if
+the \fIstdgraph\fR environment variable is set the \fIxgterm\fR, and the
+user is running IRAF from an \fIXGterm\fR window.
+.le
+.ls html
+Output the formatted help page as HTML text.
+.le
+.ls ps (or postscript)
+Output the formatted help page as postscript.
+.le
+.le
+.ih
+BASIC USAGE
+Despite the complex appearing hidden parameters, \fBhelp\fR is easy to use
+for simple tasks. \fBHelp\fR is most commonly used to get help on the current
+package, and to get help on a program named in a CL menu. To get help on
+the current package one need only type \fBhelp\fR without any arguments.
+For example, if the current package is \fBplot\fR, the command and its output
+might appear as follows:
+
+.nf
+ pl> help
+ contour - Make a contour plot of an image
+ graph - Graph one or more image sections or lists
+ pcol - Plot a column of an image
+ pcols - Plot the average of a range of image columns
+ prow - Plot a line (row) of an image
+ prows - Plot the average of a range of image lines
+ surface - Make a surface plot of an image
+ pl>
+.fi
+
+To get help on a module one supplies the module name as an argument,
+
+ pl> help graph
+
+and the manual page for the \fBplot.graph\fR program will be printed on the
+terminal. To get a hardcopy of the manual page on the printer, the output
+may be redirected to the line printer, as follows:
+
+ pl> help graph | lprint
+.ih
+DESCRIPTION
+The function of the \fBhelp\fR program is to perform a depth first search
+of the help database \fIhelpdb\fR, printing help for all packages and modules
+matching the template. By default the standard IRAF help database is searched,
+but any other help database may be searched if desired. A help database is
+precompiled with the \fBmkhelpdb\fR program to speed up runtime searches for
+help modules. The standard IRAF help database contains the documentation and
+source for all CL programs and system and math library procedures installed
+in IRAF.
+
+A help template is a string type parameter to the CL. The form of a template
+is a list of patterns delimited by commas, i.e.,
+
+ "pattern1, pattern2, ..., patternN"
+
+The form of a pattern is
+
+ package_pattern.module_pattern
+
+If the "." is omitted \fImodule_pattern\fR is assumed. The standard pattern
+matching meta-characters, i.e., "*?[]", are permitted in patterns.
+Simple patterns are assumed to be abbreviations.
+
+.ih
+GUI OPERATION
+
+The GUI component of the task is a front-end to the IRAF
+.hr system.help \fBhelp\fR
+task which provides on-the-fly conversion of help documents to HTML for
+presentation in the GUI or formatted PostScript for hardcopy.
+The GUI is started by setting the
+.hr #l_device \fIdevice\fR
+parameter to the special value \fIgui\fR, it is only available when using
+an XGterm window to start IRAF and assuming the \fIstdgraph\fR environment
+variable is set to \fRxgterm\fR.
+
+Help pages may be loaded on the command line, through use of a
+file browser, or by navigating the help databases using a familiar CL
+package menu scheme. It also features a search capability similar to the
+.hr system.references \fBreferences\fR
+task and a complete history mechanism.
+
+When invoked with no command line arguments the task starts as a browser
+and the user is presented with a GUI that has the toplevel CL package menu
+in the upper navigation window. The main display window below will contain
+any help page specified in the
+.hr #l_template template
+parameter or loaded on
+the command line by specifying the
+.hr #l_template template
+and
+.hr #l_file_template file_template
+parameters. If the
+.hr #l_search search
+parameter is enabled the
+.hr #l_template template
+is taken to be a search phrase and the database is searched for tasks
+matching the keyword and the GUI will appear with the search panel mapped
+so the user can select the task help to
+view. When no
+.hr #l_template template
+is given the main display window will start with the page specified by the
+.hr #l_home home
+parameter, this can be a user-defined HTML file giving links to specific tasks
+(see below for details) or if
+.hr #l_home home
+is empty the display will contain the online help for the task.
+
+The first time the task is run, or whenever the help database is updated,
+a quick reference file (specified by the task
+.hr #l_quickref quickref
+parameter) and package menu file will be created in the user's \fIuparm\fR
+directory to speed up help searching and subsequent startups of the task.
+
+.ih
+NAVIGATING THE HELP SYSTEM
+When run as a GUI browser \fIHELP\fR works very much like any WWW browser.
+The top panel is a list widget that will always contain a CL package listing,
+at startup this will be the toplevel \fI"Home"\fR package menu one would see
+when first logging into the CL containing the core system packages, NOAO
+package, and any site-specific external package, or in the case of starting
+with a specific task it will be the parent package for the task. Additionally,
+system documents for the
+.hr os \fBos\fR
+HSI routines and the
+.hr sys.imfort \fBimfort\fR
+and
+.hr math \fBmath\fR
+interfaces will be available in the \fIHome\fR package although
+these are programmatic interfaces and not tasks which can be executed.
+
+New packages or task help pages are loaded by selecting an item from the
+package menu list using the left mouse button. If the requested item is a
+package, the menu listing will change as though the package were loaded in
+the CL, and the help display panel will contain a listing of the package
+tasks with a one-line description for each task such as would be seen with
+a \fI"help <package>"\fR command using the standard task. New items may then
+be selected using either the menu list or links in the display panel. If the
+item is a task, the help page for the task will appear in the display panel.
+In either case new pages may be selected from the menu listing.
+
+Specific help documents may also be requested by entering the task/package
+name in the \fBTopic\fR text widget above the menu list. As when selecting
+from the package menu list, items selected this way will cause the menu
+list to change to the package menu for the parent package if the item is a
+task (displaying the help page in the display panel) or the package menu
+if the item is a package (displaying the one-liner package listing in the
+display panel).
+
+Using the \fBBack\fR button will revert to the previous page in the history
+list which will either be the previously loaded package or help page.
+Similarly, selecting the \fBForward\fR button will move the next page further
+down in the history list, either button will become insensitive when the
+end of the list on either end is reached. Selecting the \fBUp\fR button will
+cause the browser to immediately jump up the previous package, skipping
+over any help pages that were loaded in between. The \fBHome\fR button will
+cause the default homepage (either the user-defined page if specified by the
+task \fIhome\fR parameter or the online help) to be displayed. Browsing
+in this way can also be done using the navigation menu created by hitting
+the right mouse button while in the main display panel.
+
+Users can also jump to specific pages in the history list using the
+\fBHistory\fR button on the main menubar. The right column of the menu
+will indicate whether the item is a task, package, internal link or a text
+file. The history list is truncated at about 40 entries in the menu but
+the user may work back incrementally by selecting the last item of the
+menu, after which the History button will display the previous 40 entries.
+The history list may be cleared except for the current page by selecting
+the \fIClear History\fR menu item.
+
+.ih
+BROWSING A HELP DOCUMENT
+Once a help page is loaded the middle menubar above the display panel
+will change to activate widgets based on the position within the history
+list and options available for a particular page. The left-most group
+of buttons are the standard navigation buttons described above.
+The middle group of buttons contains the \fBSections\fR and
+\fBParameters\fR buttons which are used to browse within a help document.
+The \fISections\fR button is a menu listing all of the sections found
+within a help page, allowing the user to jump to a specific section
+rather than scrolling through the entire document. The \fISections\fR
+menu is also available using the middle mouse button from the
+main display area. The \fIParameters\fR button is similarly a menu
+listing of all task parameter help sections found within the document.
+Both or either of these buttons will become insensitive when no section
+or parameter information is found in the document.
+
+The right-most group of buttons represent the various help options available
+for each page. The default is to get the task help, however help pages
+may have an associated \fBsource\fR file or \fBsysdoc\fR (e.g. if the task is
+a CL script there may be a pointer to the script source itself, or a package
+may have a general overview document listed as the system document). Once
+a help page is loaded these buttons will change become sensitive if that option
+is available, simply select the button to view the option. Selecting the
+\fBFiles\fR button will bring up a panel listing all the files associated
+with a particular help topic. When a help topic is selected and an option is
+defined but the file does not exist, the options button will display a yellow
+diamond icon even if the button is insensitive, a green icon indicates the
+currently selected option. This feature may be disabled by selecting the
+"Show missing files" item from the main menubar \fBOptions\fR menu.
+
+.ih
+SEARCHING
+Searching the help database is done by selecting the \fBSearch\fR button
+from the main menubar to bring up the search panel. Users may then enter
+one or more keywords into the \fBTopic\fR field at the bottom of the panel
+and initiate the search with either a carriage return or hitting the
+\fISearch\fR button just beside it. The panel will then show a list of all
+tasks and packages which match the search phrase along with a one-line
+description of the task. Help pages may be displayed by selecting either the
+task or package link with the left mouse button, in both case the package
+menu list on the main help window will be updated to list the package
+contents allowing other tasks from that package to be selected in the normal
+way.
+
+By default the exact phrase entered in the topic window will be used for the
+search. This can be relaxed by toggling the "Require exact match" button
+at the top of the panel. For example, to search for all tasks matching
+\fIeither\fR the keyword "flat" or "field" turn off the exact match
+toggle and the search will return not only tasks matching "flat field" but
+also any task description containing only one of the words such as the
+VELVECT task which plots velocity \fIfield\fRs.
+
+Within a help document itself one can search for a string by selecting
+the \fBFind\fR button from the main menubar to bring up a panel used to
+enter the search string. When the text is entered the main display
+window will reposition itself and highlight the text found within the
+document. Searches can be repeated and will wrap around the document
+automatically, searches can be done either forward or backward through
+the text and may be case insensitive.
+
+.ih
+USER_DEFINED HOME PAGES
+By default the \fIhelp\fR GUI will start with the online help page displayed
+in the main help window. The user can change this by setting the task
+\fBhome\fR parameter to be a path to any valid file. This file may be plain
+text, a help document in LROFF format which will be converted to HTML for
+display, or a native HTML document.
+
+HTML files may contain URLs of the form
+.nf
+ \fB<a href=\fI[package.]task\fB>\fIurl_text\fB</a>
+.fi
+
+where \fIurl_text\fR is the text to appear in the window and the URL itself
+consists of an optional package and task name delimited by a period. For
+example, to create a link to the
+.hr onedspec.splot \fBsplot\fR
+task in a document one would use the URL
+.nf
+ \fB<a href=onedspec.splot>splot</a>\fR
+.fi
+
+In this way users can create a homepage which serves as a \fI"bookmark"\fR
+file or index of shortcuts to the most commonly accessed help pages.
+
+.ih
+LOADING FILES
+Text files may be loaded on the command line when starting the task by
+specifying the filename and setting the
+.hr #l_file_template file_template
+task parameter. The named file
+will be searched for a \fI.help\fR LROFF directing indicating it contains
+a help block that will be converted to HTML for display. If no help
+block is found the file will be displayed as-is, meaning existing
+HTML documents can be loaded and will be formatted correctly.
+
+Once the task is running users may load a file by selecting the \fBOpen
+File...\fR menu item from the main menubar \fBFile\fR menu or the
+right-mouse-button menu from within the main display area. This will
+open a file browser allowing users to change directories by using the
+navigation buttons at the top of the panel, or selecting items from the
+leftmost directory listing. Selecting a file on the rightmost list will
+cause it to be loaded and automatically formatted if it contains a help
+block. The file list may be filtered to select only those files matching
+a particular template by changing the \fBFilter\fR box at the top of
+the panel. Filenames or directories may be entered directly using the
+\fBSelection\fR box at the bottom of the panel.
+
+.ih
+SAVING FILES
+Once a file has been loaded in the browser it may be saved to disk as
+either \fIsource\fR (i.e. the original LROFF file if that was converted
+for the display, or whatever file is currently displayed regardless of
+format), \fItext\fR to save formatted plain text such as that produced
+by the standard \fBhelp\fR task, \fIHTML\fR to save the converted HTML
+used in the display, or \fIPostScript\fR to save formatted PostScript of
+the document such as that sent to the printer using the \fBPrint\fR
+button. Not all options will be available depending on the format of the
+input text, unavailable options will be insensitive in the GUI.
+
+The \fBSave\fR panel is opened by selecting the \fBSave As...\fR menu
+item from the main menubar \fBFile\fR menu or the right-mouse-button
+menu from within the main display area. The file browser operates the
+same as when loading images, the only difference is that file selection
+simply defines the filename to be used and does not cause the save to
+occur automatically. Users can overwrite existing files by selecting the
+\fIOptions\fR toggle at the bottom of the panel.
+
+.ih
+HARDCOPY OUTPUT AND SAVING DISK FILES.
+Help pages may be output to any configured IRAF printer by selecting the
+main menubar \fBPrint\fR button to bring up the print panel. Task help pages
+will be converted to formatted PostScript and may be sent to either a
+printer or saved to disk depending on the selection made in the printer
+panel. If the printer name is set to the special value \fI"printer"\fR then
+the device named by the CL \fIprinter\fR environment variable will be used.
+When saving to disk files the default action is to save to a filename whose
+name is the task name plus a ".ps" extension. Either of these are changeable
+within the GUI as is the default page size to be used when generating the
+PostScript.
+
+The main menubar \fBFile\fR button can also be used to bring up the file
+browser in order to save the current document to disk. Help pages may be
+saved as either the origin LROFF source for the file, formatted text as you
+would get from the standard help task, HTML as is displayed in the GUI, or
+formatted PostScript. The choice of formats is dictated by the type of file
+being displayed (e.g. you cannot save PostScript of a program source).
+
+.ih
+LROFF DIRECTIVE EXTENSIONS FOR HTML
+To better support HTML links within documents and to other help pages two
+new directives have been added to the LROFF text formatter. These are
+\fB.hr\fR to specify a link (an HTML \fIHREF\fR directive) and \fB.hn\fR
+to specify a name (an HTML \fINAME\fR directive). The syntax for these are
+as follows:
+.nf
+
+ \fB.hn\fI <name>\fR
+ \fB.hr\fI <link> <text> \fR
+.fi
+
+where \fI<name>\fR is the destination name of an internal link, \fI<link>\fR
+is the URL of the link to be created, and \fI<text>\fR is the text to be
+displayed in the HTML. The URL syntax is either a '#' character followed
+by a destination name, a simple \fItask\fR name or \fIpackage\fR name,
+or a \fIpackage.task\fR pair giving a more precise task. For internal links
+the current document is repositioned so the name is at the top of the display,
+for task help links new help pages will be loaded in the browser.
+
+These directives are ignored when converting the LROFF to either formatted
+plain text or PostScript.
+
+.hn examples_target
+.ih
+GUI EXAMPLES
+1) Start \fIhelp\fR as a GUI browser:
+.nf
+
+ cl> help dev=gui
+.fi
+
+2) Begin by searching for the phrase 'gauss', tasks and packages may be
+selected from the search panel which will appear when the task starts:
+.nf
+
+ cl> help gauss dev=gui search+
+.fi
+
+3) Load an LROFF help page in the browser at startup
+.nf
+
+ cl> help mytask.hlp dev=gui file+
+.fi
+
+.ih
+EXAMPLES
+
+1. Print the help text for the program \fIdelete\fR in the package
+\fIsystem\fR (output will be directed to the terminal):
+
+.nf
+ cl> help system.delete
+or
+ cl> help delete
+or
+ cl> help del
+.fi
+
+2. Print the help text on the line printer:
+.nf
+
+ cl> help delete | lprint
+.fi
+
+3. Print help for the current package:
+.nf
+
+ cl> help
+.fi
+
+4. Print the usage section of all modules in the package \fBimages\fR:
+.nf
+
+ cl> help images.* section=usage
+.fi
+
+5. Print a directory of all help blocks in the packages \fBclpackage\fR
+and \fBclio\fR (and any others whose names begin with the string "cl"):
+.nf
+
+ cl> help cl* op=dir
+.fi
+
+6. Print a directory of each package in the database (useful for getting an
+overview of the contents of a help database):
+.nf
+
+ cl> help * op=dir
+.fi
+
+7. Print the source for all of the string utilities in the system library
+package \fBfmtio\fR:
+.nf
+
+ cl> help fmtio.str* op=source
+.fi
+
+8. Find all tasks that delete something:
+.nf
+
+ cl> help * | match delete
+.fi
+
+9. Print the manual pages for the \fIhelp\fR and \fIlprint\fR tasks on the
+default printer device:
+.nf
+
+ cl> help help,lprint | lpr
+.fi
+
+10. Capture the manual page for task \fIhedit\fR in a text file, in a form
+suitable for printing on any device.
+.nf
+
+ cl> help hedit dev=text > hedit.txt
+.fi
+
+11. Print the manual page for task \fIhedit\fR as a Postscript file.
+.nf
+
+ cl> help hedit dev=ps | lprint
+.fi
+
+.ih
+BUGS
+On some systems, typing the next command keystroke before the end-of-page
+prompt is printed may result in the character being echoed (messing up the
+output) and then ignored when raw mode is enabled for the prompt.
+
+.ih
+SEE ALSO
+.hr system.references references
+,
+.hr system.phelp phelp
+,
+.hr system.mkhelpdb mkhelpdb
+,
+.hr system.hdbexamine hdbexamine
+,
+.hr system.mkmanpage mkmanpage
+,
+.hr system.lroff lroff
+, the online task help documents.
+.endhelp
diff --git a/pkg/system/doc/lprint.hlp b/pkg/system/doc/lprint.hlp
new file mode 100644
index 00000000..33997b0e
--- /dev/null
+++ b/pkg/system/doc/lprint.hlp
@@ -0,0 +1,65 @@
+.help lprint Nov84 system
+.ih
+NAME
+lprint -- print a file or files
+.ih
+USAGE
+lprint files
+.ih
+PARAMETERS
+.ls files
+A filename template specifying the files to be printed.
+.le
+.ls device = "printer"
+The output device. If the value of \fIdevice\fR is the reserved string
+"printer", the name of the actual printer device is taken from the value
+of the environment variable "printer".
+.le
+.ls map_cc = yes
+If set to "yes", any unprintable characters embedded in the text are printed
+in the form "^X", where ^A is <ctrl/A> (ASCII 1), and so on.
+.le
+.ls paginate = "auto"
+If \fIpaginate\fR is set to "auto" and the standard input is not redirected,
+pages are broken and a header is printed at the top of each page.
+If \fIpaginate\fR is set to "auto" and the standard input \fIis\fR redirected,
+the input text is not paginated, allowing proper operation when \fIlprint\fR
+is used in a pipe, e.g., taking input from \fIhelp\fR.
+If "paginate" is set to "yes", pages are broken even if the input text
+is being read from STDIN.
+.le
+.ls label = "STDIN"
+If displaying a header with input from the standard input, use the
+"label" string where the filename would appear in a normal header.
+.le
+.ih
+DESCRIPTION
+The named files, or the standard input, are printed on the standard
+line printer device. Each file is printed starting at the top of a new
+page, with a header giving the page number and the date of last modification
+for the file. Pagination and headers are normally suppressed when reading
+input from the standard input, but may be enabled if desired.
+.ih
+EXAMPLES
+
+1. Print all files with an extension of either ".x" or ".h", followed by
+all files with the extension ".com". Note that filename sorting occurs only
+within a comma delimited field of the filename template, hence the "*.[xh]"
+files are printed in sort order, followed by the ".com" files.
+
+ cl> lprint *.[xh],*.com
+
+2. Print the output of the \fIimstat\fR task on the versatec printer,
+paginating the output with the given label on each page. Note that the
+command may be broken after the "pipe" character without need for
+explicit backslash continuation.
+
+.nf
+ cl> imstat nite1.* |
+ >>> lprint pag+ label="Image Statistics" device=versatec
+.fi
+
+.ih
+SEE ALSO
+type
+.endhelp
diff --git a/pkg/system/doc/match.hlp b/pkg/system/doc/match.hlp
new file mode 100644
index 00000000..3338af3d
--- /dev/null
+++ b/pkg/system/doc/match.hlp
@@ -0,0 +1,77 @@
+.help match Nov84 system
+.ih
+NAME
+match -- match a pattern against the lines in a file or files
+.ih
+USAGE
+match pattern files
+.ih
+PARAMETERS
+.ls pattern
+The pattern to be matched. A pattern may contain any of the
+pattern matching \fImeta-characters\fR described below.
+.le
+.ls files
+A template specifying the file or files to be searched. Omitted if the
+standard input is redirected.
+.le
+.ls meta-characters = yes
+Set to "no" to disable the pattern matching meta-characters, e.g., when
+you want to explicitly match one of the meta-characters as a regular character.
+.le
+.ls stop = no
+If \fIstop\fR is enabled, lines with match the pattern are "stopped" (not
+passed to the output), otherwise only those lines with match the pattern
+are output.
+.le
+.ls print_file_names = yes
+If more than one file is being searched, preface each printed line
+with the "file_name: ".
+.le
+.ih
+DESCRIPTION
+The listed files are searched for the given pattern, copying each line that
+matches to the standard output. If "stop" is set the action is reversed,
+i.e., all lines are passed on to the output except those which match the
+pattern. If no files are named text is read from the standard input.
+The pattern matching meta-characters are described in the table below.
+
+.nf
+ ^ matches the beginning of a line
+ $ matches the end of a line
+ ? matches any single character
+ * matches zero or more of whatever is at the left
+ [12345] matches any single character in the given set
+ [1-5] matches any single character in a range
+ [^a-z] matches any character NOT in the range/set
+ # matches whitespace
+ {chars} turns off case sensitivity inside the braces
+ \ used to include a meta-character in the pattern
+.fi
+
+If more than one file is being searched, each output line is prefixed
+with its file name.
+.ih
+EXAMPLES
+
+1. From all the lines displayed by "set", print only those that have
+the string "tty" somewhere in them.
+
+ cl> set | match tty
+
+2. Find all tasks that delete something.
+
+ cl> help * | match delete
+
+3. Delete all the "red" objects from the list file "catalog".
+
+ cl> match red catalog stop+ > newcatalog
+
+4. Type out the file "spool", omitting all lines that end in a colon,
+and paginating the output.
+
+ cl> match ":$" spool stop+ | page
+.ih
+SEE ALSO
+lcase, ucase, translit, sort, unique
+.endhelp
diff --git a/pkg/system/doc/mkdir.hlp b/pkg/system/doc/mkdir.hlp
new file mode 100644
index 00000000..de7a03c4
--- /dev/null
+++ b/pkg/system/doc/mkdir.hlp
@@ -0,0 +1,34 @@
+.help mkdir May85 system
+.ih
+NAME
+mkdir -- make a new directory
+.ih
+USAGE
+mkdir newdir
+.ih
+PARAMETERS
+.ls newdir
+New directory or subdirectory to be made.
+.le
+.ih
+DESCRIPTION
+\fIMkdir\fR creates a new directory with the given name.
+\fINewdir\fR may be an IRAF virtual directory name (not a logical name)
+or a host directory name.
+.ih
+EXAMPLES
+
+1. Make a subdirectory named "sub1".
+
+ cl> mkdir sub1
+
+2. Make a subdirectory "sub2" below "sub1". The subdirectory "sub1" must
+already exist.
+
+ cl> mkdir sub1/sub2
+
+3. Make a directory "blue" at the same level in the directory hierarchy as
+the current directory (".." is a synonym for the previous directory).
+
+ cl> mkdir ../blue
+.endhelp
diff --git a/pkg/system/doc/mkscript.hlp b/pkg/system/doc/mkscript.hlp
new file mode 100644
index 00000000..5aa33204
--- /dev/null
+++ b/pkg/system/doc/mkscript.hlp
@@ -0,0 +1,161 @@
+.help mkscript Nov85 system
+.ih
+NAME
+mkscript -- make a script for a command sequence to be run in batch
+.ih
+USAGE
+mkscript script task submit
+.ih
+PARAMETERS
+.ls script
+Script file name. Commands will be successively added to this file.
+.le
+.ls task
+Task name of command to be added to the script. If given on the command
+line then only commands for this task may be added to the script.
+If not given on the command line then the task will query for a task
+name for each new command. Currently the task name must not be abbreviated.
+.le
+.ls submit
+Submit the completed script as a background job as the last act of the task?
+If not given on the command line the task will query before submitting the
+script.
+.le
+.ls append = no
+Append new commands to an existing script file?
+If no the file will be deleted first. If \fIverify\fR = yes
+the user will be asked to confirm the deletion.
+.le
+.ls hidden = yes
+Include hidden parameters in each command?
+.le
+.ls verify = yes
+Verify each command, any file deletions, and the final script?
+.le
+.ls logfile = "script.log"
+Script log file name. When the script is submitted as a background job
+by this task any command and error output is directed to this file.
+.le
+.ih
+DESCRIPTION
+A command script is created consisting of a number of commands to be
+executed sequentially. The task assumes the responsibility of formatting
+the command and placing it in the script file. The user sets the
+parameter values using the parameter editor \fBeparam\fR. As an optional
+final stage the task will optionally submit the script as a background job.
+
+The sequence of steps are outline as follows:
+.ls (1)
+If the script already exists and \fIappend\fR = no the script file
+is deleted. When \fIverify\fR = yes the deletion is verified with the
+user.
+.le
+.ls (2)
+If the task is not specified on the command line then the user
+is queried for a task name.
+.ls (2a)
+The task must be loaded. If it has not been loaded a message is printed
+and the task query is repeated.
+.le
+.le
+.ls (3)
+\fBEparam\fR is now invoked to allow the user to set the task
+parameters.
+.le
+.ls (4)
+If \fIverify\fR = yes the command is printed and the user is asked if the
+command is ok. If ok the command is added to the script.
+.le
+.ls (5)
+The user is asked if another command is to be added to the script. While
+the response is yes steps 2 to 5 are repeated.
+.le
+.ls (6)
+If \fIverify\fR = yes the script is paged and the user is asked if the
+script is ok. If not ok the script is deleted, with user confirmation,
+and steps 2 to 6 are repeated.
+.le
+.ls (7)
+If the submit parameter is not specified on the command line the user
+is asked if the script should be submitted as a background job.
+.le
+
+The parameter \fIhidden\fR is important for the following reason. If
+the hidden parameters are not explicitly included in the script commands
+then the values of the hidden parameters will be those in the parameter
+file at the time of execution. Thus, in changes in the hidden parameters
+with \fBeparam\fR or explicit changes may produce unexpected results.
+However, if the hidden parameters are never changed then the commands
+are more readable when the hidden parameters are not included.
+.ih
+EXAMPLES
+One of the most common usages in data reductions is to create repeated
+commands with different input data or parameters.
+
+.nf
+cl> mkscript script.cl transform
+
+[\fIeparam\fR is called to set the parameter values for \fItransform\fR]
+
+transform ("n1r.008", "n1r.008a", "disp012,distort,disp013",
+database="identify.db", interptype="spline3", x1=1., x2=256., dx=1.,
+nx=256., xlog=no, y1=4300., y2=6300., dy=INDEF, ny=800., ylog=no,
+flux=yes, logfiles="STDOUT,logfile")
+
+Is the command ok? (yes):
+Add another command? (yes):
+
+[\fIeparam\fR is called again for task \fItransform\fR]
+
+transform ("n1r.010", "n1r.010a", "disp013,distort",
+database="identify.db", interptype="spline3", x1=1., x2=256., dx=1.,
+nx=256., xlog=no, y1=4300., y2=6300., dy=INDEF, ny=800., ylog=no,
+flux=yes, logfiles="STDOUT,logfile")
+
+Is the command ok? (yes):
+Add another command? (yes): no
+
+[The script is paged]
+
+Is the script ok? (yes):
+Submit the script as a background job? (yes):
+Script script.cl submitted at:
+Fri 10:32:57 01-Nov-85
+[1]
+.fi
+
+To combine several tasks:
+
+.nf
+cl> mkscript script.cl ver- sub- hid-
+Task name of command to be added to script: response
+
+[\fIeparam\fR is called for \fIresponse\fR and parameter values are set]
+
+Add another command? (yes):
+Task name of command to be added to script: imarith
+...
+Add another command? (yes): no
+.fi
+
+To run the command script as a foreground job:
+
+cl> cl < script.cl
+
+To run the command script as a background job:
+
+cl> cl < script.cl >& logfile &
+
+Note that the output including possible error output is redirected to a logfile.
+.ih
+BUGS
+The current implementation is preliminary. It is done with a script which
+makes it seem somewhat slow. The most important bug is that the command
+formatter is based on the output of \fBlparam\fR. If a task parameter
+name exceeds 12 characters it is truncated by \fBlparam\fR and is then
+also truncated by the command formatter. The script will then fail when
+executed! Also the task name may not be abbreviated.
+.ih
+SEE ALSO
+eparam
+.endhelp
diff --git a/pkg/system/doc/movefiles.hlp b/pkg/system/doc/movefiles.hlp
new file mode 100644
index 00000000..73374474
--- /dev/null
+++ b/pkg/system/doc/movefiles.hlp
@@ -0,0 +1,38 @@
+.help movefiles Nov84 system
+.ih
+NAME
+movefiles -- move files to a directory
+.ih
+USAGE
+movefiles files directory
+.ih
+PARAMETERS
+.ls files
+A template specifying the file or files to be moved.
+.le
+.ls directory
+The directory to which the files are to be moved.
+.le
+.ls verbose = no
+If set to "yes", tell user as each file is moved.
+.le
+.ih
+DESCRIPTION
+This routine moves the specified files to the named directory.
+If a subdirectory and a logical directory both exist with the same
+name as the destination directory, the subdirectory is used.
+.ih
+EXAMPLES
+
+1. Move all files whose names start with `im' and end with `ab' to
+the directory `dir'. Since "verbose" defaults to "no", do the work silently.
+
+ cl> movefiles im*ab dir
+
+2. Move all files in the current directory into the directory one level up.
+
+ cl> move * ..
+.ih
+SEE ALSO
+copy, rename
+.endhelp
diff --git a/pkg/system/doc/netstatus.hlp b/pkg/system/doc/netstatus.hlp
new file mode 100644
index 00000000..059f6819
--- /dev/null
+++ b/pkg/system/doc/netstatus.hlp
@@ -0,0 +1,44 @@
+.help netstatus Feb86 system
+.ih
+NAME
+netstatus -- print the status of the local network
+.ih
+USAGE
+netstatus
+.ih
+PARAMETERS
+None.
+.ih
+DESCRIPTION
+\fINetstatus\fR prints the status of the local network as perceived by the
+system process x_system.e (the network status may differ for each subprocess).
+The status output identifies the local node, lists all nodes in the local
+network, and lists all the aliases (recognized names) for each node.
+A message will be printed if networking is disabled on the local machine.
+The local network is defined by the table files "dev$hosts", "dev$uhosts",
+and "dev$hostlogin".
+.ih
+EXAMPLES
+
+.nf
+cl> netstatus
+Local node `draco' (5), default node `draco', 12 nodes in local network
+
+ NODE SERVER NREFS STATUS ALIASES
+ 1 0 0 00000 aquila vax1 a 1 class1 plot print
+ 2 0 0 00000 lyra vax2 b 2 class2
+ 3 0 0 00000 vela vax3 3 v class3
+ 4 0 0 00000 carina vax5 c 5 class5
+ 5 0 0 00000 draco vax6 6 d class6 0
+ 6 0 0 00000 tucana sun1 t
+ 7 0 0 00000 hydra sun2 h
+ 8 0 0 00000 mensa pc1 m
+ 9 0 0 00000 pictor pc2
+ 10 0 0 00000 octans sun3 o
+ 11 0 0 00000 pavo mvax1 p
+ 12 0 0 00000 volans lsi1
+.fi
+
+.ih
+SEE ALSO
+.endhelp
diff --git a/pkg/system/doc/news.hlp b/pkg/system/doc/news.hlp
new file mode 100644
index 00000000..1b12f24c
--- /dev/null
+++ b/pkg/system/doc/news.hlp
@@ -0,0 +1,58 @@
+.help news Mar90 system
+.ih
+NAME
+news -- print the revisions summary for the current IRAF version
+.ih
+USAGE
+news
+.ih
+DESCRIPTION
+The \fInews\fR task uses the standard IRAF file pager to review a formatted
+summary of the system revisions for the version of IRAF being run.
+The revisions summaries for older versions of the system are also provided:
+use the \fIN\fR and \fIP\fR pager keys to display the next or previous
+system revisions summary. The revisions summary is given in the file
+"doc$newsfile".
+
+For reasons of brevity, only the revisions summary is printed. For detailed
+information on the revisions made to a particular science package, type
+
+ cl> help <pkg>.revisions op=sys
+
+where "pkg" is the name of the CL package for which revisions information
+is desired. For detailed information on the revisions to the system
+software and programming interfaces, examine the system notes file,
+given in the file "notes.*" in the directory "iraf$local". The system
+notes files for older versions of the system will be found in the "doc"
+directory.
+.ih
+BUGS
+The revisions summary is often lengthy and may be easier to read if a
+printed copy is made.
+
+Redirecting the output of \fInews\fR, e.g., to \fIlprint\fR, doesn't work
+at present.
+.ih
+EXAMPLES
+1. Page the revisions summary for the current IRAF release.
+
+ cl> news
+
+2. Print the revisions summary.
+
+ cl> lprint doc$newsfile
+
+3. Page the system notes file. Anyone who develops software for IRAF
+should review this file with each new release, to see what has changed.
+Documentation for new system facilities is often given in the system
+notesfile.
+
+ cl> page iraf$local/notes.*
+
+4. Review the revisions summary for the IMAGES package.
+
+ cl> phelp images.revisions op=sys
+.ih
+SEE ALSO
+help, phelp, page
+.endhelp
diff --git a/pkg/system/doc/page.hlp b/pkg/system/doc/page.hlp
new file mode 100644
index 00000000..92cfd105
--- /dev/null
+++ b/pkg/system/doc/page.hlp
@@ -0,0 +1,146 @@
+.help page Nov86 system
+.ih
+NAME
+page -- display a file or files one page at a time
+.ih
+USAGE
+page files
+.ih
+PARAMETERS
+.ls files
+The list of files. If omitted, text is read from the standard input.
+.le
+.ls map_cc = yes
+Map non-printing control characters into printable form, e.g., BEL
+(ctrl/G, ASCII 7) is printed as "^G".
+.le
+.ls clear_screen = no
+If set, the screen is cleared before each page is written.
+.le
+.ls first_page = 1
+The first page to be printed. Pages are defined by form feed characters
+embedded in the text.
+.le
+.ls prompt = ""
+Optional prompt string for the end-of-page prompt. If no prompt string is
+given the name of the file being paged is used.
+.le
+.ls device = "terminal"
+The output device. The special device \fItext\fR may be specified to
+represent standout mode with upper case rather than reverse video characters.
+.le
+.ih
+DESCRIPTION
+\fIPage\fR displays a file on the terminal, one page of text at a time,
+pausing between successive pages of output until a key is typed on the
+terminal. Pages are normally broken when the screen fills, but may also
+be delimited by form feed characters embedded in the input text.
+A prompt is printed after each page of text naming the current file,
+showing the percentage of the file which has been displayed, and the numeric
+order of the file within the file list if a file template was given.
+
+When the end of page prompt is displayed any of the following command
+keystrokes may be entered. Command keystrokes are input in raw mode,
+i.e., no carriage return is required to pass the command to the program.
+
+.ks
+.nf
+ . go to the beginning of the current file [BOF]
+ : colon escape (see below)
+ ? display a one-line command summary
+ G go to the end of the current file [EOF]
+ N,<ctrl/n> go to the next file
+ P,<ctrl/p> go back to the previous file
+ b back up one page
+ d scroll down half a page of text
+ e edit the current file
+ f,space advance to the next page
+ j,return scroll down one line
+ k back up one line
+ n search for the next occurrence of a pattern
+ q quit
+ u back up half a screen
+
+ <ctrl/c> quit (interrupt)
+ <ctrl/z> quit (EOF)
+ <ctrl/d> quit (EOF)
+.fi
+.ke
+
+If an unrecognized keystroke is entered the terminal will beep. The following
+colon commands are recognized in addition to the single keystroke commands
+described above.
+
+.ks
+.nf
+ :!<clcmd> send a command to the CL (:!! for host command)
+ :/<pattern> advance to line matching the given pattern
+ :file <fname> display file "fname" (may be abbreviated)
+ :help print summary of colon commands
+ :line [+/-]N goto line N (relative move if +/- given)
+ :spool <fname> spool output to the named file
+.fi
+.ke
+
+The \fI:clcmd\fR facility is used to send commands to the CL from within
+the context of the pager. For example, ":!cl" will temporarily suspend the
+pager, allowing CL commands to be entered until the command "bye" is entered,
+causing execution of the pager to resume. Note that since the \fIpage\fR
+task resides in the system process \fIx_system.e\fR, it will be necessary
+for the CL to connect a second system process if the command issued calls
+another task in the system package, since the first system process will
+still be running, i.e., executing the \fIpage\fR task. This is harmless,
+but the second process may be removed from the process cache with
+\fIflprcache\fR if desired, after exiting the original \fIpage\fR task.
+
+The sequence ":/" followed by a pattern will cause the current input stream
+to be searched for the next occurrence of the pattern given. A pattern once
+entered is retained indefinitely and may be used in subsequent searches by
+typing the single keystroke `n', without need to reenter the pattern.
+Searching stops at the end of the current file, requiring a `.' to wrap back
+around to the beginning of the file, or a `N' to advance to the next file.
+
+The \fI:file\fR command is used to change the current position within the
+file list specified by \fIfiles\fR, and may not be used to page a file not
+specified in the initial template. Note that the filename may be abbreviated,
+and that searching stops with the first file lexically greater than or equal
+to the given string (hence ":file x" might return file "y").
+
+The \fI:line N\fR command may be used to randomly position to the indicated line
+within the current file. If the line number argument N is preceded by a plus
+or minus the argument is taken to be an offset from the current position.
+
+The \fI:spool\fR command is used to spool output to a file. Each time a
+file line is printed on the screen, it is appended to the named file as well.
+One can interactively position to the desired line of the file and then turn
+on spooling to extract a portion of the file or stream being displayed.
+A subsequent \fI:spool\fR command with no filename will turn spooling off.
+Issuing a \fI:spool\fR to begin spooling on a new file when already spooling
+to some other file will cause the old spool file to be closed.
+.ih
+EXAMPLES
+
+1. Page through all of the files in the directory "lib" which have
+the extension ".h".
+
+ cl> page lib$*.h
+
+2. Use \fIhelp\fR to format the text in the file "doc$spp.hlp", displaying
+the formatted document beginning on page 5 (the entire document has to be
+formatted first so it takes a minute or so to get any output).
+
+ cl> help doc$spp.hlp fi+ | page first=5
+
+3. Run \fIrfits\fR to print a long format listing of the headers of a series
+of FITS images from a magnetic tape, directing the output through \fIpage\fR
+so that it does not flash by when you aren't looking.
+
+ cl> rfits mta make- long+ | page
+.ih
+BUGS
+Since \fIpage\fR does not currently buffer any input text, backwards motions
+and absolute line positioning are not permitted when paging the standard input.
+.ih
+SEE ALSO
+type, match, head, tail
+.endhelp
diff --git a/pkg/system/doc/pathnames.hlp b/pkg/system/doc/pathnames.hlp
new file mode 100644
index 00000000..3719fe28
--- /dev/null
+++ b/pkg/system/doc/pathnames.hlp
@@ -0,0 +1,42 @@
+.help pathnames Nov84 system
+.ih
+NAME
+pathnames -- print the host pathnames for a set of files
+.ih
+USAGE
+pathnames [template]
+.ih
+PARAMETERS
+.ls template
+A filename template specifying the set of files for which pathnames
+are desired. If omitted, the pathname of the current working or default
+directory is printed. The list of file names can come from the standard input.
+.le
+.ls sort = yes
+Sort the output in ASCII collating sequence.
+.le
+.ih
+DESCRIPTION
+\fIPathnames\fR converts a list of IRAF virtual file names into their host
+system equivalents. When called with no arguments, the function of
+\fIpathnames\fR is to print the current default directory.
+.ih
+EXAMPLES
+
+1. Print the pathname of the current default directory (sample output for
+a VMS host system).
+
+.nf
+ cl> path
+ draco!DRB1:[IRAF.SYS.FIO]
+.fi
+
+2. Translate the file "vfiles", containing a list of virtual filenames, into
+the equivalent list of host system filenames, e.g., for use as input to a
+foreign task.
+
+ cl> path @vfiles > hfiles
+.ih
+SEE ALSO
+directory, files
+.endhelp
diff --git a/pkg/system/doc/phelp.hlp b/pkg/system/doc/phelp.hlp
new file mode 100644
index 00000000..2230eb29
--- /dev/null
+++ b/pkg/system/doc/phelp.hlp
@@ -0,0 +1,61 @@
+.help phelp Mar90 system
+.ih
+NAME
+phelp -- page the output of the HELP task
+.ih
+USAGE
+phelp template
+.ih
+PARAMETERS
+The \fIphelp\fR parameters are the same as for \fIhelp\fR except that
+the \fIpage\fR and \fInlpp\fR parameters are omitted.
+.ih
+DESCRIPTION
+The \fIphelp\fR task is a front end to \fIhelp\fR which spools the output
+of \fIhelp\fR in a scratch file, then calls the file pager \fIpage\fR to
+view the output text. The advantage is that while \fIhelp\fR pages its
+output, one can only move forward through the output text. By using
+\fIphelp\fR it is possible to randomly scan the spooled help text, e.g.,
+skipping forward to get a quick overview and then backing up to read the
+details more carefully. This capability is especially useful when viewing
+large multipage help pages, or when viewing a number of related help pages
+all at once.
+.ih
+EXAMPLES
+1. Page the help page for the \fImkpkg\fR task.
+
+ cl> phelp mkpkg
+
+2. View the help pages for all the tasks in the IMAGES package.
+
+ cl> phelp images.*
+
+When viewing multiple help pages as in this last example, note that the
+'N' and 'P' keystrokes in the pager may be used to move to the next or
+previous help page. "." will return to the first help page (the start
+of the spooled help text) and 'G' will skip to the end of file. Type '?'
+while in the pager to get a summary of the most often used keystrokes.
+
+3. Format and page the Lroff (IRAF HELP) format document "MWCS.hlp" in
+the system directory "mwcs".
+
+.nf
+ cl> cd mwcs
+ cl> phelp MWCS.hlp fi+
+.fi
+
+In this case the text being viewed is not part of the on-line help system,
+but is a technical document describing one of the IRAF programming interfaces.
+Any .hlp file may be viewed in this way.
+.ih
+TIME REQUIREMENTS
+\fIphelp\fR is not quite as fast as \fIhelp\fR since it must fully format
+the help text into a temporary file before the file can be viewed. For
+small help pages, or to view only the first few screens of a help page,
+the \fIhelp\fR task will be faster.
+.ih
+BUGS
+.ih
+SEE ALSO
+page, help, references
+.endhelp
diff --git a/pkg/system/doc/protect.hlp b/pkg/system/doc/protect.hlp
new file mode 100644
index 00000000..6a0049e4
--- /dev/null
+++ b/pkg/system/doc/protect.hlp
@@ -0,0 +1,36 @@
+.help protect Nov84 system
+.ih
+NAME
+protect -- protect files from deletion
+.ih
+USAGE
+protect files
+.ih
+PARAMETERS
+.ls files
+A template specifying the file or files to be protected.
+.le
+.ih
+DESCRIPTION
+\fIProtect\fR asserts protection from deletion for the specified files.
+A protected file can be deleted only by first "unprotecting" it.
+File protection is preserved when a file is copied or renamed,
+even when copied or renamed to a remote network node,
+but may be lost when a file is backed up on tape and later restored
+(depending upon what utility one uses). Note that imagefiles are
+automatically protected to prevent accidental deletion of the header
+file, leaving a "zombie" pixel file somewhere on disk.
+.ih
+EXAMPLES
+
+1. Protect the file "paper.ms" from deletion, accidental or otherwise.
+
+ cl> protect paper.ms
+
+2. Protect all the ".ms" files from deletion.
+
+ cl> protect *.ms
+.ih
+SEE ALSO
+unprotect, delete
+.endhelp
diff --git a/pkg/system/doc/references.hlp b/pkg/system/doc/references.hlp
new file mode 100644
index 00000000..a67b4182
--- /dev/null
+++ b/pkg/system/doc/references.hlp
@@ -0,0 +1,78 @@
+.help references Jun89 system
+.ih
+NAME
+references -- find all help database references to a given topic
+.ih
+USAGE
+references topic
+.ih
+PARAMETERS
+.ls topic
+The topic for which help is desired, i.e., a keyword, phrase, or pattern
+which the help database or quick-reference file is to be searched for.
+.le
+.ls quickref = "uparm$quick.ref"
+The name of the optional quick-reference file.
+.le
+.ls updquick = no
+Create or update the quick-reference file, e.g., because new packages
+have been added to the global help database. Updating the quick-reference
+file automatically enables \fIusequick\fR, discussed below.
+.le
+.ls usequick = no
+Use the quick-reference file. By default, a runtime search of all the package
+menus in the full help database is performed, which ensures that all packages
+are searched, but which is comparatively slow.
+.le
+.ih
+DESCRIPTION
+The \fIreferences\fR task is used to search the help database for all tasks
+or other help modules pertaining to the given topic, where \fItopic\fR may be
+a keyword, phrase, or any general pattern as would be input to the \fImatch\fR
+task. By default the full help database will be searched. If desired,
+the "one-liner" information used for topic searching may be extracted and
+used to prepare a quick-reference file to speed further searches.
+This is not done by default because the help database is too dynamic, e.g.,
+new external packages may be installed at any time, by any user, or new
+tasks may be added to existing packages at any time.
+
+References to tasks (or other objects) are printed in the form
+
+.nf
+ keyword1 - one line description
+ keyword2 - one line description
+.fi
+
+and so on. To determine the \fIpackage pathname\fR of each named task,
+get \fIhelp\fR on the named \fIkeyword\fR and the pathname will be seen at
+the top of the help screen, followed by additional information about the
+referenced object. If there are multiple objects with the same name,
+a "help <keyword> \fIall+\fR" may be required to locate a particular one.
+.ih
+EXAMPLES
+1. Find all help on CCDs.
+
+ cl> ref ccd
+
+2. Create or update your private quick-reference file.
+
+ cl> ref upd+
+
+3. Examine the quick-reference file to get a summary of all the tasks
+or other help modules in the help database.
+
+ cl> page (ref.quickref)
+.ih
+TIME REQUIREMENTS
+If a quick-reference file is used searching takes seconds, otherwise it
+might take a minute or so for the typical large help database containing
+all help modules for the core system and several external, layered packages.
+.ih
+BUGS
+Only the one-liner (NAME) field describing each help module is used for
+the searches. With a little work searching could be made much more
+comprehensive as well as faster.
+.ih
+SEE ALSO
+help, match
+.endhelp
diff --git a/pkg/system/doc/rename.hlp b/pkg/system/doc/rename.hlp
new file mode 100644
index 00000000..226045da
--- /dev/null
+++ b/pkg/system/doc/rename.hlp
@@ -0,0 +1,69 @@
+.help rename Aug97 system
+.ih
+NAME
+rename -- rename a file or set of files
+.ih
+USAGE
+rename file newname
+.ih
+PARAMETERS
+.ls file
+A template specifying the file or files to be renamed.
+.le
+.ls newname
+If a single file is being renamed, the new filename, else the new name of
+the field being renamed in a set of filenames. If \fInewname\fR is a
+directory the input files will be moved to this directory with the same
+name.
+.le
+.ls field = all
+If set to "all" the file name remains unchanged and the \fInewname\fR is
+assumed to be a destination directory in the case of multiple input files,
+or the new filename (which may contain a new directory path) in the case of
+a single input file. If set to \fIldir\fR the \fInewname\fR value is taken
+to be a destination directory and the file is moved to this directory.
+Setting to \fIroot\fR will rename only the root portion of the filename,
+a value of \fIextn\fR will change or append the extension. \fInewname\fR
+cannot contain a directory path when changing the root or extn field.
+.le
+.ih
+DESCRIPTION
+\fIRename\fR renames either a single file to "newname", or a set of files,
+changing either the ldir, root or the extension part of each name.
+If \fInewname\fR is a directory or \fIfield\fR is "ldir" the input files
+are moved to this directory and the filenames remain the same. When
+modifying the root or extension part of the filename \fInewname\fR is the
+new root or extension name for the input files, an extension will be added
+to the file name if it doesn't already exist and the extension field is being
+modified. For multiple input files it is assumed
+that \fInewname\fR is a directory if the value of \fIfield\fR is "all",
+otherwise an error is generated to prevent overwriting files.
+.ih
+EXAMPLES
+
+1. Rename file "fred" to "jay".
+
+ cl> rename fred jay
+
+2. Change the root name of a set of files from "out" to "pkout".
+
+ cl> rename out.x,out.o,out.par pkout field=root
+
+3. Change the extension of all ".f77" files from ".f77" to ".f".
+
+ cl> rename *.f77 f field=extn
+
+4. Move all files with a ".dat" extension to a new directory.
+
+ cl> rename *.dat data$
+ cl> rename *.dat /data/user
+
+5. Add a ".fits" extension to all files in a directory.
+
+ cl> rename im00* fits field=extn
+.ih
+BUGS
+.ih
+SEE ALSO
+movefiles, copy
+.endhelp
diff --git a/pkg/system/doc/rewind.hlp b/pkg/system/doc/rewind.hlp
new file mode 100644
index 00000000..0519f81c
--- /dev/null
+++ b/pkg/system/doc/rewind.hlp
@@ -0,0 +1,36 @@
+.help rewind Apr92 system
+.ih
+NAME
+rewind -- rewind a previously allocated device
+.ih
+USAGE
+rewind device
+.ih
+PARAMETERS
+.ls device
+The device to be rewound.
+.le
+.ls initcache = yes
+Initialize the magtape device position cache for the device. This causes
+the magtape i/o system to "forget" what it thinks it knows about things
+like the number of files on the tape, the amount of tape used, and so on.
+.le
+.ih
+DESCRIPTION
+\fIRewind\fR rewinds the specified device, which is most likely
+a magnetic tape, and which has been previously allocated to the user.
+
+By default \fIrewind\fR will initialize the device position cache. When
+changing tapes, one should always either rewind or deallocate and reallocate
+the device, to force the magtape system to recompute the number of files
+on the tape and to ensure that the tape is left in a defined position.
+.ih
+EXAMPLES
+
+1. Rewind logical tape drive a.
+
+ cl> rewind mta
+.ih
+SEE ALSO
+allocate, deallocate, devstatus
+.endhelp
diff --git a/pkg/system/doc/sort.hlp b/pkg/system/doc/sort.hlp
new file mode 100644
index 00000000..7d89657b
--- /dev/null
+++ b/pkg/system/doc/sort.hlp
@@ -0,0 +1,62 @@
+.help sort Mar87 system
+.ih
+NAME
+sort -- sort a file or the standard input
+.ih
+USAGE
+sort input_file
+.ih
+PARAMETERS
+.ls input_file
+The text file to be sorted. If the standard input is redirected the standard
+input is sorted.
+.le
+.ls column = 0
+If 0, sort entire text lines, else sort based on data/text starting
+in the specified column. Columns are delimited by whitespace. Thus,
+.nf
+ 12 abc 34 56
+.fi
+has four columns, "abc" being in the second.
+.le
+.ls ignore_whitespace = no
+Ignore leading whitespace. Useful only when column = 0 and the sort is
+non-numeric.
+.le
+.ls numeric_sort = no
+If set, make numerical (rather than ASCII text) comparisons.
+.le
+.ls reverse_sort = no
+If set, sort in reverse text/numeric order.
+.le
+.ih
+DESCRIPTION
+\fISort\fR sorts the contents of the given text file, or the
+standard input, either on a textual (based on the ASCII collating
+sequence), or on a numeric basis. If a numeric sort is requested,
+and either field in any comparison is non-numeric, a string (ASCII)
+comparison will be made instead.
+.ih
+EXAMPLES
+
+1. Sort the output of the set command into alphabetic (ASCII collating)
+order.
+
+ cl> set | sort
+
+2. Sort the contents of "file", in reverse ASCII order, ignoring the
+contents of columns 1 through 4.
+
+ cl> sort file rev+ col=5
+
+3. Print a long form directory listing with the files sorted by size,
+largest files first.
+
+ cl> dir | sort num+ rev+ col=3
+.ih
+BUGS
+Only one file can be sorted per call, and only one column or all columns can
+be used for the sort. The current program is inefficient for large numeric
+sorting tasks because the same numeric field may be decoded into its
+corresponding binary value many times.
+.endhelp
diff --git a/pkg/system/doc/spy.hlp b/pkg/system/doc/spy.hlp
new file mode 100644
index 00000000..33ffa52c
--- /dev/null
+++ b/pkg/system/doc/spy.hlp
@@ -0,0 +1,26 @@
+.help spy Feb85 system
+.ih
+NAME
+spy -- tell who is logged in and what they are doing
+.ih
+USAGE
+spy [v]
+.ih
+DESCRIPTION
+\fISpy\fR prints a summary of who is on the system and what they are doing.
+The optional argument \fIv\fR (short for \fIverbose\fR) causes more detailed
+information to be given. The operation of this task is machine dependent,
+as is the quantity and format of the information returned.
+.ih
+EXAMPLES
+.nf
+cl> spy
+ 4:36pm up 24 days, 5:42, 2 users, load average: 0.29, 0.15, 0.18
+User tty login@ idle JCPU PCPU what
+roger ttyh8 4:21pm 15 8 5 -csh
+alice ttyh9 4:26pm 44 27 w
+.fi
+.ih
+SEE ALSO
+diskspace
+.endhelp
diff --git a/pkg/system/doc/tail.hlp b/pkg/system/doc/tail.hlp
new file mode 100644
index 00000000..bd91e617
--- /dev/null
+++ b/pkg/system/doc/tail.hlp
@@ -0,0 +1,50 @@
+.help tail Nov84 system
+.ih
+NAME
+tail -- print the last few lines of the specified files
+.ih
+USAGE
+tail files
+.ih
+PARAMETERS
+.ls files
+A template specifying the files to be listed.
+.le
+.ls nlines = 12
+The number of lines to be printed. If negative, the number
+of lines to be skipped, counting from the beginning of the file.
+.le
+.ih
+DESCRIPTION
+For each file in the input file list, \fItail\fR copies the last \fInlines\fR
+of the file to the standard output. If there is more than one file in the
+input file list, as one line header is printed before each file.
+If "nlines" is negative, then abs(nlines) lines are skipped, and the rest
+of the file is printed, i.e., the tail of the file is still printed, but
+the offset is measured from the beginning of the file rather than the end.
+.ih
+EXAMPLES
+
+1. Prints the last 12 lines of each help file in the current directory.
+
+ cl> tail *.hlp
+
+2. Print the last line of each help file.
+
+ cl> tail *.hlp nl=1
+
+3. Prints the third through fifth lines of "file". The same thing
+might be done (at least conceptually) by "head file,nlines=5"
+piped into "tail ,nlines=3". However, \fItail\fR does not work on STDIN.
+
+.nf
+ cl> tail file nl=-2 | head nl=3
+.fi
+.ih
+BUGS
+\fITail\fR does not presently work on standard input, and therefore cannot
+be used in pipes.
+.ih
+SEE ALSO
+head
+.endhelp
diff --git a/pkg/system/doc/tee.hlp b/pkg/system/doc/tee.hlp
new file mode 100644
index 00000000..466b3751
--- /dev/null
+++ b/pkg/system/doc/tee.hlp
@@ -0,0 +1,36 @@
+.help tee Nov84 system
+.ih
+NAME
+tee -- tee the standard output to a file
+.ih
+USAGE
+tee file
+.ih
+PARAMETERS
+.ls file
+The name of the output file.
+.le
+.ls out_type = "text"
+The type of output file to be created, either "text" or "binary".
+.le
+.ls append = no
+If set, append to an existing file, otherwise create a new file.
+.le
+.ih
+DESCRIPTION
+\fITee\fR copies its input to both the standard output and the named file.
+Its primary use is in pipes where one wants to capture some intermediate output.
+.ih
+EXAMPLES
+
+1. The results of the \fIset\fR command are captured in the file "temp",
+and are also passed on to the "match" command. The result is
+a "temp" file of perhaps 100 lines, with the output to the screen
+only around 5 lines.
+
+ cl> set | tee temp | match tty
+.ih
+BUGS
+Since the processes in an IRAF pipe execute serially rather than concurrently,
+the teed output will not appear until all tasks to the left have completed.
+.endhelp
diff --git a/pkg/system/doc/touch.hlp b/pkg/system/doc/touch.hlp
new file mode 100644
index 00000000..aedb35a0
--- /dev/null
+++ b/pkg/system/doc/touch.hlp
@@ -0,0 +1,71 @@
+.help touch Jan04 system
+.ih
+NAME
+touch -- change file access and modification times
+.ih
+USAGE
+touch files
+.ih
+PARAMETERS
+.ls files
+List of files to be created or touched.
+.le
+.ls create = yes
+If enabled, the file will be created as a zero-length text file if it doesn't
+already exist.
+.le
+.ls atime = yes
+Change the access time of the file. Will not change the modification time
+unless \fImtime\fR is also set.
+.le
+.ls mtime = yes
+Change the modification time of the file. Will not change the access time
+unless \fIatime\fR is also set.
+.le
+.ls time = ""
+Time and date to set for the file. The format of this string may be any
+of DD/MM/YY or CCYY-MM-DD (in which case time is assumed to be midnight of
+that day), or CCYY-MM-DDTHH:MM:SS[.SSS...] to specify both date and time.
+If not specified, the current system time is used unless the \fIref_file\fR
+parameter is set. If specified, \fIref_file\fR will be ignored.
+.le
+.ls ref_file = ""
+Use the corresponding times of the specified file for modifying the
+times of the \fIinput_files\fR. If not specified, the current time is
+used unless the \fItime\fR parameter is set.
+.le
+.ls verbose = no
+Print verbose output of the files and times being reset.
+.le
+.ih
+DESCRIPTION
+The \fItouch\fR task sets the access and modification times of each file
+in the \fIfiles\fR list. The file will be created if it does not already
+exist when the \fIcreate\fR parameter is set. The time used can be
+specified by \fItime\fR parameter or by the corresponding fields of the
+file specified by \fIref_file\fR, otherwise the current system time will
+be used. The task will update both the modification and access times of
+the file unless disabled by the \fIatime\fR or \fImtime\fR parameter.
+
+.ih
+EXAMPLES
+
+1. Update the times of all SPP source files in the current directory:
+
+ cl> touch *.x
+
+2. Create an empty file on a remode node:
+
+ cl> touch ursa!/data/trigger_file
+
+3. Reset the file modification time to 2:33:45 pm on June 5, 2003:
+
+ cl> touch nite1.fits time="2003-06-05T14:23:45"
+
+4. Reset the file modification time to match dev$hosts:
+
+ cl> touch nite1.fits ref_file=dev$hosts
+
+.ih
+SEE ALSO
+.endhelp
diff --git a/pkg/system/doc/type.hlp b/pkg/system/doc/type.hlp
new file mode 100644
index 00000000..f8af91cd
--- /dev/null
+++ b/pkg/system/doc/type.hlp
@@ -0,0 +1,43 @@
+.help type Nov84 system
+.ih
+NAME
+type -- type a file or files on the standard output
+.ih
+USAGE
+type input_files
+.ih
+PARAMETERS
+.ls input_files
+A template specifying the file or files to be typed.
+.le
+.ls map_cc = yes
+If set, output any non-printing control characters in the input text in
+a printable form, e.g., ctrl/c (ASCII 3) would be output as ^C.
+.le
+.ls device = "terminal"
+The output device, defaulting to the user's terminal. If the special device
+"text" is named, any standout mode control characters embedded in the text
+will cause the enclosed text to be output in upper case.
+.le
+.ih
+DESCRIPTION
+\fIType\fR copies the named files (or the files selected by
+the file template) to the standard output.
+If there is more than one file in the input list, a header naming the file
+to be printed will precede each output file.
+.ih
+EXAMPLES
+
+1. Type all files in the current directory with the extension ".x" on the
+standard output. Do not pause between files or pages (unlike \fIpage\fR).
+
+ cl> type *.x
+
+2. Capture the manual page for task \fIhedit\fR in a text file, in a form
+suitable for printing on any device.
+
+ cl> help hedit | type dev=text > hedit.doc
+.ih
+SEE ALSO
+page, head, tail, concatenate, lprint
+.endhelp
diff --git a/pkg/system/doc/unprotect.hlp b/pkg/system/doc/unprotect.hlp
new file mode 100644
index 00000000..99120c07
--- /dev/null
+++ b/pkg/system/doc/unprotect.hlp
@@ -0,0 +1,27 @@
+.help unprotect Nov84 system
+.ih
+NAME
+unprotect -- remove file protection
+.ih
+USAGE
+unprotect files
+.ih
+PARAMETERS
+.ls files
+A template specifying the file or files from which delete protection is
+to be removed.
+.le
+.ih
+DESCRIPTION
+\fIUnprotect\fR removes delete protection from the named files.
+A "protected" file cannot be deleted or clobbered.
+.ih
+EXAMPLES
+
+1. Remove file protection from the listed files.
+
+ cl> unprotect alpha,beta,gamma.x,*.db
+.ih
+SEE ALSO
+protect, delete
+.endhelp
diff --git a/pkg/system/doc/urlget.hlp b/pkg/system/doc/urlget.hlp
new file mode 100644
index 00000000..da6ede83
--- /dev/null
+++ b/pkg/system/doc/urlget.hlp
@@ -0,0 +1,84 @@
+.help urlget Sep2011 system
+.ih
+NAME
+urlget -- Get a (http) URL to the named file
+.ih
+USAGE
+urlget url fname
+.ih
+PARAMETERS
+.ls url
+The URL to download.
+.le
+.ls fname
+The name of the file to create containing the URL contents. If not
+specified, the trailing part of the URL is used as the filename.
+.le
+.ls use_cache = yes
+Use the system file cache? If 'yes' and the file already exists in the
+cache, the cached file will be copied to the output filename.
+If 'no' then the URL will be downloaded again.
+.le
+.ls extn = ""
+Optional filename extension to put on the cached filename. This can be
+used to force files to be saved as a particular type in the cache.
+.le
+.ls verbose = no
+Print verbose output?
+.le
+.ls cache = "cache$"
+Logical cache directory name.
+.le
+
+.ih
+DESCRIPTION
+The \fIURLGET\fR task is used to download a URL (HTTP protocol only) to a
+local file named by the \fIfname\fR parameter. If no \fIfname\fR is given,
+a filename is constructed from the last part of the URL (i.e.
+characters trailing any of the '?', '/', or '&' delimiters). Because
+the URL may not point to a static file, use of the \fIfname\fR parameter
+is recommended.
+
+If the \fIuse_cache\fR parameter is set, the URL will only be downloaded if
+it does not already exist in the file cache pointed to by the \fIcache\fR
+parameter, otherwise the cached file will be copied to the output filename.
+The \fIextn\fR parameter may be to used to force a specific file extension
+to be appended to the filename in the cache, this allows a URL to be passed
+to a task and treated as if it were a file of a specific type.
+
+.ih
+EXAMPLES
+
+1. Download a FITS image from a URL (these are equivalent):
+
+.nf
+ cl> urlget http://iraf.noao.edu/foo.fits
+ cl> urlget http://iraf.noao.edu/foo.fits foo.fits
+.fi
+
+2. Force a URL to be downloaded again:
+.nf
+ cl> urlget http://iraf.noao.edu/foo.fits use_cache=no
+.fi
+
+3. Download a URL with special characters:
+.nf
+ cl> urlget http://iraf.noao.edu/scripts/tget?f=foo.fits
+or
+ cl> s1 = "http://iraf.noao.edu/scripts/tget?f=foo.fits"
+ cl> urlget(s1)
+or
+ cl> s1 = "http://iraf.noao.edu/scripts/tget?f=foo.fits&d=/iraf/web"
+ cl> urlget(s1,"foo.fits",verbose+)
+.fi
+
+Escaping special characters isn't required from the commandline since the
+URL is assumed to be whitespace or comma delimited.
+
+.ih
+BUGS
+
+.ih
+SEE ALSO
+
+.endhelp
diff --git a/pkg/system/fcache.par b/pkg/system/fcache.par
new file mode 100644
index 00000000..0c69ba6f
--- /dev/null
+++ b/pkg/system/fcache.par
@@ -0,0 +1,9 @@
+cmd,s,a,,,,cache command
+pattern,s,h,"*",,,filename pattern
+src,s,h,"",,,file or url to cache
+fname,s,h,"",,,cache filename
+extn,s,h,"",,,cache filename extension
+age,i,h,-1,,,file age (in days) to purge
+verbose,b,h,no,,,print verbose output?
+wait,b,h,yes,,,block on operation?
+cache,s,h,"cache$",,,cache directory
diff --git a/pkg/system/files.par b/pkg/system/files.par
new file mode 100644
index 00000000..20e6a230
--- /dev/null
+++ b/pkg/system/files.par
@@ -0,0 +1,2 @@
+template,s,a,,,,file template
+sort,b,h,yes,,,sort file list
diff --git a/pkg/system/files.x b/pkg/system/files.x
new file mode 100644
index 00000000..9bd94f91
--- /dev/null
+++ b/pkg/system/files.x
@@ -0,0 +1,32 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# FILES -- Expand a file name template into a list of file names on the
+# standard output.
+
+procedure t_files()
+
+int list
+pointer sp, template, fname
+
+bool clgetb()
+int fntopnb(), fntgfnb(), clgeti(), btoi()
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+ call salloc (template, SZ_LINE, TY_CHAR)
+
+ if (clgeti ("$nargs") > 0)
+ call clgstr ("template", Memc[template], SZ_LINE)
+ else
+ call strcpy ("*", Memc[template], SZ_LINE)
+
+ list = fntopnb (Memc[template], btoi(clgetb("sort")))
+ while (fntgfnb (list, Memc[fname], SZ_FNAME) != EOF) {
+ call printf ("%s\n")
+ call pargstr (Memc[fname])
+ }
+
+ call fntclsb (list)
+ call sfree (sp)
+end
diff --git a/pkg/system/hdbexamine.par b/pkg/system/hdbexamine.par
new file mode 100644
index 00000000..9ef63b4a
--- /dev/null
+++ b/pkg/system/hdbexamine.par
@@ -0,0 +1,2 @@
+helpdb,s,h,"helpdb",,,"name of help database to be examined"
+verbose,b,h,no,,,"long form output"
diff --git a/pkg/system/head.par b/pkg/system/head.par
new file mode 100644
index 00000000..2379807e
--- /dev/null
+++ b/pkg/system/head.par
@@ -0,0 +1,2 @@
+input_files,s,a,,,,list of files to be printed
+nlines,i,h,12,0,,number of lines to be printed from each file
diff --git a/pkg/system/head.x b/pkg/system/head.x
new file mode 100644
index 00000000..71b6db2b
--- /dev/null
+++ b/pkg/system/head.x
@@ -0,0 +1,56 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+
+# HEAD -- Print the head (first few lines) of each of the named text files on
+# the standard output. If more than one file is to be printed, a brief header
+# is printed for each file.
+#
+# Params:
+# input_files file matching template
+# nlines [h,8] number of lines to be printed
+
+procedure t_head()
+
+char fname[SZ_FNAME]
+bool multiple_files
+int nlines, list
+int clpopni(), clplen(), clgfil(), clgeti()
+
+begin
+ list = clpopni ("input_files")
+ multiple_files = (clplen (list) > 1)
+ nlines = clgeti ("nlines")
+
+ while (clgfil (list, fname, SZ_FNAME) != EOF)
+ iferr (call print_head (STDOUT, fname, nlines, multiple_files))
+ call erract (EA_WARN)
+
+ call clpcls (list)
+end
+
+
+# PRINT_HEAD -- Print the first few lines of a file on the output stream given
+# as the first argument, optionally plus a header.
+
+procedure print_head (out, fname, nlines, print_file_name)
+
+int out, nlines
+bool print_file_name
+char fname[SZ_FNAME], lbuf[SZ_LINE]
+int in, line, open(), getline()
+errchk open, getline, putline
+
+begin
+ in = open (fname, READ_ONLY, TEXT_FILE)
+
+ if (print_file_name) {
+ call fprintf (out, "\n\n===> %s <===\n")
+ call pargstr (fname)
+ }
+
+ for (line=1; line <= nlines && getline(in,lbuf) != EOF; line=line+1)
+ call putline (out, lbuf)
+
+ call close (in)
+end
diff --git a/pkg/system/help.par b/pkg/system/help.par
new file mode 100644
index 00000000..ef6f2060
--- /dev/null
+++ b/pkg/system/help.par
@@ -0,0 +1,31 @@
+# Parameter file for the HELP task
+
+template,s,a,"",,,"Module name or package.module style template"
+
+file_template,b,h,no,,,"Template is a filename matching template"
+option,s,h,"help",,,"Type of help (help,source,sysdoc,files,summary,etc)"
+device,s,h,"terminal","terminal|gui|text|html|postscript|ps",,"output device"
+
+# Output parameters.
+all,b,h,no,,,"print help for all modules matching template"
+parameter,s,h,"all",,,"parameter for which help is desired"
+section,s,h,"all",,,"section for which help is desired"
+
+# Terminal display parameters.
+page,b,h,yes,,,"paginate output"
+nlpp,i,h,59,1,,"number of lines per page if output redirected"
+lmargin,i,h,1,1,,"left margin"
+rmargin,i,h,72,2,,"right margin"
+
+# GUI parameters
+search,b,h,no,,,"Search database for help topic?"
+home,s,h,"",,,"Homepage to be used"
+printer,s,h,"printer",,,"Printer name"
+showtype,b,h,no,,,"Indicate packages in list?"
+quickref,s,h,"uparm$quick.ref",,,"Quick-reference file"
+uifname,s,h,"lib$scr/help.gui",,,"User interface filename"
+coords,*gcur,h,"",,,"Cursor"
+
+# Help Parameters.
+helpdb,s,h,"helpdb",,,"Help database to be used"
+curpack,s,h,"AskCL",,,"current package"
diff --git a/pkg/system/help/README b/pkg/system/help/README
new file mode 100644
index 00000000..a448779b
--- /dev/null
+++ b/pkg/system/help/README
@@ -0,0 +1,12 @@
+The HELP package -- online documentation utilties. This directory contains
+the source and documtation for the HELP utility. The subdirectory lroff
+contains the source for the Lroff text formatter, called by HELP to format
+help blocks.
+
+Jul84 Added the help database facility, i.e., pre-compilation of the help
+ directories to produce a binary database. Numerous other improvements.
+ See the revs file for additional details.
+
+Note: The TASK declaration for HELP is in pkg$system/system.cl.
+ The TASK declarations for MKHELPDB and HDBEXAMINE are in the softools
+ package, file pkg$softools/softools.cl.
diff --git a/pkg/system/help/design.hlp b/pkg/system/help/design.hlp
new file mode 100644
index 00000000..9d236da6
--- /dev/null
+++ b/pkg/system/help/design.hlp
@@ -0,0 +1,500 @@
+.helpsys help Mar84 "Detailed Design of the Help Utility"
+.nh
+The Help Database
+
+ Help has to know where to find help files and sources for modules.
+This information is stored in two types of files. The package list file,
+maintained in lib$ by the system manager, contains an entry for each
+installed package. The module list file, maintained in the package
+directory by the programmer, contains the same information for each
+module in the package. The format of a help list file is as follows:
+
+.nf
+ $defdir = pathname|ldir
+ $ldir1 = pathname|ldir
+ $ldir2 = pathname|ldir
+ ...
+
+ name1 hlp=file, src=file, sys=file, pkg=file
+ name2 hlp=file, src=file, sys=file, pkg=file
+ ...
+.fi
+
+Logical directories may be defined in the header area of the helpdir file
+as shown above. These may be omitted if the package directory is already
+defined in the CL environment. The "defdir" prefix will be added to any
+file name that does not contain an explicit logical or OS directory
+specification. The default directory may be an OS pathname or a logical
+directory guaranteed to be defined in the CL environment at the time that
+\fBhelp\fR is run. There should be no OS dependent file names in the
+module lists.
+
+Each module entry consists of a number of keyword equals value type
+fields. The fields are optional and may be given in any order. If the
+last character on the line is a comma, the list is assumed to be continued
+on the next line. The \fBhlp\fR field is the name of the file containing the
+help block. The \fBsrc\fR file contains the source for the named module.
+The \fBsys\fR file contains the system documentation. The \fBpkg\fR field,
+present only in the package helpdir file, is the name of the module helpdir
+file for the package. Although the help database is organized by
+package, the package list is linear, not a tree.
+
+If multiple entries are given for a module, the entry nearest the tail
+of the list is used.
+
+.nh
+Program Structure
+
+ If no args, print help block for the current package, otherwise expand
+the template into a list of package.module elements. Process the help
+text for each module. In general, the \fBlroff\fR text formatter is called
+to process all help text. \fBLroff\fR is called with the names of two external
+procedures used to get lines of text from the input and put formatted text
+to the output.
+
+\fBLroff\fR is essentially a numerical procedure which effects a
+format conversion on a list of text lines. Additional specialized processing
+is carried out in the input and output procedures. Thus, when processing
+only the help text for a single section, the input procedure skips input
+lines until the desired section is detected, and returns EOF to \fBlroff\fR
+when the end of the input section is detected. Similarly, the output
+procedure handles all the details of paginating the output on the user
+terminal.
+
+.nf
+t_help
+ clio to get params
+ salloc ctrl structure
+ ttyodes
+ get_option [match option]
+ process_template
+ hd_open [open helpdir]
+ open,getline,close
+ hd_putldiry
+ hd_getc
+ hd_putstr
+ realloc
+ hd_putmodule
+ hd_getc
+ hd_putstr
+ realloc
+ getline
+ hd_sort_modules
+ expand_template [encode pat ]
+ malloc
+ patmake
+ read_template [get modname ]
+ hd_getname
+ hd_getldir
+ patmatch
+ print_help [do a module ]
+ hd_findmod
+ hd_getname
+ hd_getldir
+ pr_filenames
+ hd_findmod
+ hd_getname
+ hd_getldir
+ output
+ nomore
+ clgetb
+ ttyputline
+ putline
+ pr_sourcefile
+ hd_findmod
+ hd_getname
+ hd_getldir
+ input
+ getline
+ output
+ ...
+ pr_summary
+ hd_findmod
+ hd_getname
+ hd_getldir
+ getline
+ output
+ ...
+ pr_helpblock [default help]
+ find_help_block
+ getline
+ strmatch
+ pr_header
+ ttyclear
+ LROFF [format text ]
+ input
+ getline
+ output
+ ...
+ close_template
+ mfree
+ hd_close
+ mfree
+.fi
+
+.nh
+Data Structures
+
+ For simplicity, helpdir files are read into an internal buffer in
+one operation, and searching for modules, file name extraction, etc. is
+thereafter done on the buffered helpdir. The helpdir is represented
+in memory by the following structures.
+
+.nf
+struct helpdir {
+ char *hd_sbuf # string buffer
+ int hd_nextch # index of next char in sbuf
+ int hd_szsbuf # size of string buffer
+ int hd_defdir # index of defdir str
+ int hd_nldirs # number of ldirs
+ int hd_nmodules # number of modules
+ int hd_ldir[MAX_LDIR] # indices of ldirs
+ struct module hd_module[MAX_MODULES] # module names, files
+}
+
+
+struct module {
+ int m_name # index of module name
+ int m_hlp # index of help file name
+ int m_sys # sys help file
+ int m_src # source file
+ int m_pkg # package helpdir file
+}
+.fi
+
+All character strings are stored in the string buffer, which is initially
+allocated with malloc, and which is reallocated with realloc if it fills
+up while the helpdir is being read. The maximum number of logical
+directory definitions and module entries are fixed when \fBhelp\fR is
+compiled. All strings are referred to by an integer index into the
+string buffer (if the string buffer is moved by realloc, the integer
+offset does not change, whereas a char pointer would).
+
+.nh
+Semicode
+
+HELP -- The main procedure. Expand the module list, determine the
+type of help desired, fetch the names of the doc files and call the
+appropriate routine to process the help text.
+
+.nf
+procedure help
+
+begin
+ # Get control parameters.
+ fetch and decode option string
+ if (option "param")
+ fetch parameter name
+ fetch margin params, pagination flag, open tty descriptor,
+ set up "ctrl" structure
+
+ # Get module template: "mod", "pack.mod", "pack.", etc. If no
+ # args or template is null, default to "curpack.".
+
+ if (we were called with no positional arguments)
+ template = null
+ else
+ fetch template from cl
+
+ # Format and output the help text. The template list consists
+ # of a series of templates delimited by commas.
+
+ for (each subtemplate in the template list)
+ call process_template (template, ctrl)
+end
+.fi
+
+
+PROCESS_TEMPLATE -- Called with a template defining the packages and
+modules for which help is desired, and the control parameters defining
+the type of help desired. Expand the template into a list of packages
+and modules and process the help for each module.
+
+.nf
+procedure process_template (template, ctrl)
+
+begin
+ # Open the system help directory; gives help files and name of
+ # package help directories for the individual packages.
+
+ hp_sys = hd_open (system helpdir)
+
+ # If null template, print hlp for current package. If template
+ # not null, but no package named, make package list the current
+ # CL package search path. Otherwise the template contains all
+ # necessary information.
+
+ if (entire template is null) {
+ set package template to the name of the current package
+ set module template to null
+ } else {
+ extract package part of template, delimited by "."
+ if (null package template)
+ set package template to CL package search path
+ }
+
+ # By the time we get here we always have a non-null template.
+ paklist = expand_template (hp_sys, pak_template)
+
+ # If package help is desired, print help on the package as if
+ # it were a module. Otherwise, expand module template for
+ # the package and process help on each module.
+
+ while (read_template (paklist, pakname) != EOF)
+ if (null module template)
+ call print_help (hp_sys, pakname, ctrl)
+ else {
+ hp_pak = hd_open (package helpdir)
+ modlist = expand_template (hp_pak, mod_template)
+ while (read_template (modlist, modname) != EOF)
+ call print_help (hp_pak, modname, ctrl)
+ close_template (modlist)
+ hd_close (hp_pak)
+ }
+
+ close_template (paklist)
+ hl_close (hp_sys)
+end
+.fi
+
+
+EXPAND_TEMPLATE -- Expand a template into a list of module names,
+given a help directory defining the pattern matching domain.
+The permissible complexity of a help template is somewhat less than
+that of a file template. A template consists of a list of patterns;
+there is nothing corresponding to the logical directories and list
+files used in file templates. Examples of templates include
+
+.nf
+ (null) package-help for the current package
+ cl. package-help clpackage
+ cl.* all tasks in clpackage
+ * all tasks in the current package
+ alpha module alpha
+.fi
+
+The simple alphanumeric string is a special type of pattern. The string
+"cl", for example, is equivalent to "cl*" or "cl?*". Thus template
+expansion is a simple matter of scanning through the module list of
+a help directory and extracting all names which match the pattern.
+
+
+.nf
+pointer procedure expand_template (hp, template)
+
+hp: helpdir descriptor
+
+begin
+ allocate template descriptor, containing space for the encoded
+ pattern, hp, and the module index.
+
+ save hp
+ encode template into descriptor; turn "*" meta-characters
+ into "?*" if not following character class
+ set module index to zero
+
+ return (pointer to template descriptor)
+end
+.fi
+
+
+READ_TEMPLATE -- Get next module name from help directory matching the
+encoded pattern. Return EOF when directory is exhausted.
+
+.nf
+int procedure read_template (template_descriptor, module_name)
+
+begin
+ for (index+=1; hp_getname (hp, module_name) != 0; index+=1) {
+ if (pattern matches module name)
+ return
+ }
+ return (EOF)
+end
+.fi
+
+
+PRINT_HELP -- Print help documentation for the named module or parameter.
+We are called with the name of a single module; all fiddling with packages
+and templates has been performed by the time we are called. The help
+directory is open and contains the names of the files containing the help
+source for the module. Our main task is to determine what kind of help
+is desired and call the appropriate routine.
+
+Recall that the principal options are
+
+.nf
+ \fBoption\fR \fBmeaning\fR \fBfile\fR
+
+ help print help block for module hlp
+ param print help for single param hlp
+ section print a single section hlp
+ files print file names ...
+ source print source file src
+ sysdoc print system documentation sys
+ alldoc print all documentation hlp,sys
+ summary print help block titles hlp,sys
+.fi
+
+
+.nf
+procedure print_help (hp, modname, ctrl)
+
+begin
+ # Handle options which do not access a help file.
+ if (option == files) {
+ pr_filenames (hp, modname, ctrl)
+ return
+ } else if (option == source) {
+ get source file name from hp_getname
+ pr_sourcefile (sourcefile, ctrl)
+ return
+ } else if (option == summary) {
+ # Scan hlp file and print summary of help blocks.
+ get helpfile name from hp_getname
+ pr_summary (helpfile, ctrl)
+ return
+ }
+
+ # Process help block. Processing is controlled by the
+ # "ctrl" structure.
+
+ if (option == help or alldoc) {
+ get helpfile name from hp_getname
+ pr_helpblock (helpfile, module, ctrl)
+ if (option == sysdoc or alldoc) {
+ get sysdocfile name from hp_getname
+ pr_helpblock (sysdocfile, module, ctrl)
+ }
+end
+.fi
+
+
+PR_HELPBLOCK -- Format and print a help block. Open the help file and search
+for the named module. Interpret block header and print help title.
+Process the remainder of the help block with lroff.
+
+.nf
+procedure pr_helpblock (helpfile, module, ctrl)
+
+begin
+ iferr (in = open help file)
+ print warning message
+ if (find_help_block (in, module, lbuf) == not found)
+ cannot find help block for module 'modname'
+
+ clear EOF flag in ctrl
+ initialize line counter
+
+ if (not printing just single param or section)
+ pr_header (lbuf, ctrl)
+ if (lroff (input, ctrl, output, ctrl, ...) == ERR)
+ print warning message
+ close help file
+end
+.fi
+
+
+INPUT -- Lroff line input procedure. Called by Lroff to get lines of
+input text. Function varies slightly depending on the Help option.
+If printing only single param or single section, our job is to eat all
+input which is not part of the indicated section of the help block.
+A parameter block begins with ".ls paramname" and ends with a matching
+".le" or ".ih", if the text is formatted. Similarly, the single section
+begins with a ".ih" followed by the section name on the next line.
+
+.nf
+int procedure input (ctrl, outbuf)
+
+ctrl: Control structure. Contains fd of input file, and the EOF
+ flag which may be set by the \fBoutput\fR procedure if we are
+ called interactively.
+
+begin
+ # Eof flag is set after param block has been fully input,
+ # but normally before the actual end of file.
+ if (eof flag was set by user interaction)
+ return (EOF)
+ else if (processing full help block)
+ return (getline (infile, outbuf))
+
+ # We get here only if special processing is required to
+ # filter out all but a section of the help text.
+
+ if (first call for new file) {
+ # Determine whether or not the help block is formatted.
+ get first line of help block
+ if (line is an Lroff directive)
+ formatted = true
+ else
+ formatted = false
+ return, passing line to Lroff
+ }
+
+ if (second call for new file) {
+ if (single param mode) {
+ if (formatted) {
+ eat input lines until a ".ls" directive is
+ found which contains the param name as
+ a substring.
+ } else {
+ eat input lines until a line beginning with
+ the parameter name is found.
+ }
+ } else if (print a single section) {
+ if (formatted) {
+ eat input lines until ".ih\nSECNAME" is found
+ } else {
+ eat input lines until a line beginning with the
+ parameter name or SECNAME is found.
+ }
+ put a section indent directive into line buffer
+ }
+ return, passing line to Lroff
+ }
+
+ # By the time we get here we are in the parameter or single
+ # section.
+ get input line
+ if (line is a .ih directive)
+ set EOF flag
+ else if (in single param mode and have a matching .le)
+ set EOF flag
+
+ return, passing line to Lroff
+end
+.fi
+
+
+OUTPUT -- Output a line of text to the "out" file. If the standard output
+is redirected, put lines out as is with \fBputline\fR. Otherwise put lines out
+to the interactive terminal with \fBttyputline\fR, which processes standout
+mode etc. Count lines and pause between pages, if enabled by control
+flag. Pause is implemented as a request for a CL query mode boolean
+parameter, just as in the \fBpage\fR utility.
+
+.nf
+procedure output (dev, linebuf)
+dev: The "ctrlpar" structure, containing output file descriptor,
+ pagination flag, TTY descriptor pointer, left and right
+ margins, flag if output is redirected, and so on.
+
+begin
+ if (output is redirected) {
+ call putline to output line without further processing
+ return
+ }
+
+ call ttyputline to output line
+ bump line counter
+
+ # The NOMORE procedure produces a query on the user terminal,
+ # giving the user a chance to continue when they have finished
+ # reading the current screen, or of terminating the help block
+ # currently being processed.
+
+ if (output page is full)
+ if (nomore)
+ set EOF flag for input procedure
+end
+.fi
diff --git a/pkg/system/help/filetemp.x b/pkg/system/help/filetemp.x
new file mode 100644
index 00000000..1270abe2
--- /dev/null
+++ b/pkg/system/help/filetemp.x
@@ -0,0 +1,28 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include "help.h"
+
+# DO_FILE_TEMPLATE -- Called with a template matching a list of files containing
+# help blocks. All help blocks therein are processed and output.
+
+procedure do_file_template (template, ctrl)
+
+char template[ARB] # filename matching template
+pointer ctrl # Help control structure
+
+char fname[SZ_FNAME]
+int option
+pointer list
+pointer fntopn()
+int fntgfn()
+
+begin
+ list = fntopn (template)
+ option = H_OPTION(ctrl)
+
+ while (fntgfn (list, fname, SZ_FNAME) != EOF)
+ call pr_helpblock (fname, "", "", NULL, ctrl)
+
+ call fntcls (list)
+end
diff --git a/pkg/system/help/getoption.x b/pkg/system/help/getoption.x
new file mode 100644
index 00000000..a7504531
--- /dev/null
+++ b/pkg/system/help/getoption.x
@@ -0,0 +1,52 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include "help.h"
+
+# GET_OPTION -- Map the possibly abbreviated option string into an integer
+# option code. It is an error if the abbreviation is not unique.
+
+define EQUAL 0
+
+int procedure get_option (opstr)
+
+char opstr[ARB] # option string, always lower case
+int keycode[MAX_OPTIONS]
+int oplen, key, ip, match
+int strlen(), strncmp()
+
+string keywords "help|sources|sysdoc|alldoc|files|summary|directory|references"
+data keycode /O_HELP,O_SOURCE,O_SYSDOC,O_ALLDOC,O_FILES,O_SUMMARY,O_DIR,
+ O_REFERENCES/
+
+begin
+ oplen = strlen (opstr)
+ ip = 1
+ match = 0
+
+ # Search the keyword table. If the option string matches a keyword,
+ # it is either an exact match (oplen = keyword length) or a legal
+ # abbreviation. If an abbreviation matches two keywords it is
+ # ambiguous and an error.
+
+ for (key=1; keywords[ip] != EOS; key=key+1) {
+ if (strncmp (keywords[ip], opstr, oplen) == EQUAL) {
+ if (keywords[ip+oplen] == '|')
+ return (keycode[key]) # exact match
+ else {
+ if (match != 0)
+ call error (1, "ambiguous help option abbreviation")
+ else
+ match = key
+ }
+ }
+ repeat {
+ ip = ip + 1
+ } until (keywords[ip-1] == '|' || keywords[ip] == EOS)
+ }
+
+ if (match == 0)
+ call error (2, "unknown help option")
+ else
+ return (keycode[match])
+end
diff --git a/pkg/system/help/hbgetblk.x b/pkg/system/help/hbgetblk.x
new file mode 100644
index 00000000..a39db034
--- /dev/null
+++ b/pkg/system/help/hbgetblk.x
@@ -0,0 +1,195 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include "help.h"
+
+.help hb_getnextblk
+.nf ___________________________________________________________________________
+HB_GETNEXTBLK -- Scan a file for the next help block, i.e., block of lines
+delimited by ".help" and ".endhelp". The syntax of a help block header is
+as follows:
+
+ .help[typestr] key1,key2,...,keyN section title
+
+Whitespace is NOT permitted in the keyword list unless it is quoted. Quotes
+are optional for each of the three strings. If the line ends with the
+backslash character or a comma we assume that the header is continued on the
+next line. The typestr, denoting the type of help block, is optional.
+If absent it defaults to "hlp". System help blocks are of type "sys".
+
+We keep track of the file line number when searching for a help block. The
+line number is updated in the HB structure. For this number to be accurate,
+the caller must see that it is initialized before we are called.
+.endhelp ______________________________________________________________________
+
+define SZ_SBUF (MAX_KEYS * SZ_KEY)
+define IS_KEYWCHAR (IS_ALNUM($1) || $1 == '_' || $1 == '$')
+define exit_ 90
+
+
+int procedure hb_getnextblk (hb, ctrl)
+
+pointer hb
+pointer ctrl
+
+bool at_eof
+char key[SZ_KEY]
+int fd, n, ip, op, junk
+pointer sp, lbuf, sbuf, p
+int hb_getstr(), strmatch(), getline(), strlen()
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+ call salloc (sbuf, SZ_SBUF, TY_CHAR)
+
+ # Search forward for the next help block.
+ fd = H_IN(ctrl)
+ at_eof = true
+
+ while (getline (fd, Memc[lbuf]) != EOF) {
+ HB_LINENO(hb) = HB_LINENO(hb) + 1
+ if (strmatch (Memc[lbuf], "^.{help}") > 0) {
+ at_eof = false
+ break
+ }
+ }
+
+ if (at_eof) {
+ call sfree (sp)
+ return (EOF)
+ }
+
+ # Initialize everything in case of an early exit.
+ HB_TYPE(hb) = TY_UNKNOWN
+ HB_NKEYS(hb) = 0
+ HB_TYPESTR(hb) = EOS
+ HB_SECTION(hb) = EOS
+ HB_TITLE(hb) = EOS
+
+ # Decode help block into the HB structure. First step is to
+ # get the type suffix string, if any.
+
+ ip = strlen (".help") + 1
+ p = lbuf + ip - 1
+ if (IS_ALPHA (Memc[p])) {
+ for (n=0; IS_ALNUM (Memc[p+n]); n=n+1)
+ ;
+ call strcpy (Memc[p], HB_TYPESTR(hb), min(n,SZ_TYPESTR))
+ if ( strmatch (HB_TYPESTR(hb), "{sys}") > 0)
+ HB_TYPE(hb) = TY_SYS
+ else if (strmatch (HB_TYPESTR(hb), "{hlp}") > 0)
+ HB_TYPE(hb) = TY_HLP
+ else
+ HB_TYPE(hb) = TY_UNKNOWN
+ } else {
+ HB_TYPE(hb) = TY_HLP
+ n = 0
+ }
+ ip = ip + n
+
+ # Now get the keyword string, and break the keywords out into
+ # the keyword list.
+
+ if (hb_getstr (fd, Memc[lbuf], ip, Memc[sbuf], SZ_SBUF,
+ HB_LINENO(hb)) == 0)
+ goto exit_
+
+ p = sbuf
+ while (IS_WHITE (Memc[p]) || Memc[p] == ',')
+ p = p + 1
+ for (n=1; n <= MAX_KEYS && Memc[p] != EOS; n=n+1) {
+ for (op=1; IS_KEYWCHAR (Memc[p]); op=op+1) {
+ key[op] = Memc[p]
+ p = p + 1
+ }
+ key[op] = EOS
+ call strcpy (key, HB_KEY(hb,n), SZ_KEY)
+ while (IS_WHITE (Memc[p]) || Memc[p] == ',')
+ p = p + 1
+ }
+ HB_NKEYS(hb) = n - 1
+
+ # Fetch section label string and title string.
+
+ if (hb_getstr (fd, Memc[lbuf], ip, HB_SECTION(hb), SZ_SECTION,
+ HB_LINENO(hb)) == 0)
+ goto exit_
+ junk = hb_getstr (fd, Memc[lbuf], ip, HB_TITLE(hb), SZ_TITLE,
+ HB_LINENO(hb))
+
+exit_ call sfree (sp)
+ return (HB_LINENO(hb))
+end
+
+
+# HB_GETSTR -- Fetch a string (optionally quoted) from the line buffer.
+# Handle everything having to do with continuation.
+
+int procedure hb_getstr (fd, lbuf, ip, outstr, maxch, lineno)
+
+int fd
+char lbuf[ARB]
+int ip
+char outstr[ARB]
+int maxch
+int lineno
+
+char ch
+int op, dstart
+int stridx(), getline()
+string delim " \t'\""
+
+begin
+ while (IS_WHITE (lbuf[ip]))
+ ip = ip + 1
+ op = 1
+
+ # If quoted string, only a quote can end the string.
+ dstart = 1
+ if (lbuf[ip] == '\'' || lbuf[ip] == '"') {
+ ip = ip + 1
+ dstart = 3
+ }
+
+ # Fetch the string.
+ for (ch=lbuf[ip]; stridx (ch, delim[dstart]) == 0; ch=lbuf[ip]) {
+ if (op >= maxch)
+ break
+
+ switch (ch) {
+ case '\\', ',':
+ if (lbuf[ip+1] == '\n' || lbuf[ip+1] == EOS) {
+ # Continue on next line.
+ if (getline (fd, lbuf) == EOF)
+ lbuf[1] = EOS
+ else
+ lineno = lineno + 1
+ ip = 1
+ if (ch == '\\')
+ next
+ } else
+ ip = ip + 1
+ outstr[op] = ch
+ op = op + 1
+
+ case '\n', EOS:
+ if (delim[dstart] == '\'') {
+ call eprintf ("Missing right quote in helpfile, line %d\n")
+ call pargi (lineno)
+ }
+ break
+
+ default:
+ outstr[op] = ch
+ op = op + 1
+ ip = ip + 1
+ }
+ }
+
+ if (ch != EOS)
+ ip = ip + 1
+ outstr[op] = EOS
+
+ return (op - 1)
+end
diff --git a/pkg/system/help/hdbexamine.hlp b/pkg/system/help/hdbexamine.hlp
new file mode 100644
index 00000000..a7498c23
--- /dev/null
+++ b/pkg/system/help/hdbexamine.hlp
@@ -0,0 +1,55 @@
+.help hdbexamine Feb86 softools
+.ih
+NAME
+hdbexamine -- examine a help database
+.ih
+USAGE
+hdbexamine
+.ih
+PARAMETERS
+.ls helpdb = "helpdb"
+The filename of the help database to be examined. The reserved name "helpdb"
+causes the actual filename to be taken from the environment variable of
+the same name.
+.le
+.ls verbose = no
+If this switch is enabled, \fIhdbexamine\fR will print a detailed description
+of the help database listing the modules in each package, the date the entry
+for the package was last modified, and other information. A more concise
+summary listing only the packages and the number of help modules in each
+package is printed by default.
+.le
+.ih
+DESCRIPTION
+The \fIhdbexamine\fR task is used to examine the contents of a help
+database. By default the standard IRAF help database is examined.
+Examining the help database with \fIhdbexamine\fR verifies that it can
+be read by \fIhelp\fR, and may be useful as a diagnostic in the event
+that an invalid help directory file (".hd") somewhere in the help
+directory tree, causes the database to be compiled incorrectly.
+.ih
+EXAMPLES
+1. Print a concise summary of the contents and structure of the standard
+help database.
+
+.nf
+cl> hdbexamine
+Help database dev$help.db created Feb 14 21:34 by tody
+Database contains 794 modules in 43 packages, file size 105460 bytes
+
+_clpackage Nov 4 1984 tody clpackage$_clpackage.hd
+clpackage May 29 17:44 rooke clpackage$clpackage.hd
+os Feb 13 11:06 tody host$os/doc/os.hd
+root Nov 4 1984 tody lib$root.hd
+_math Apr 1 13:38 tody math$_math.hd
+curfit Jan 6 16:23 tody math$curfit/doc/curfit.hd
+gsurfit Jan 2 14:46 davis math$gsurfit/doc/gsurfit.hd
+iminterp Aug 6 16:31 davis math$iminterp/doc/iminterp.hd
+bias Dec 17 8:53 valdes pkg$imred/bias/bias.hd
+coude Dec 31 14:38 valdes pkg$imred/coude/coude.hd
+vtel Jan 22 8:36 lytle pkg$imred/vtel/vtel.hd
+plot Jan 28 14:04 hammond pkg$plot/plot.hd
+.fi
+.ih
+SEE ALSO
+mkhelpdb, help
diff --git a/pkg/system/help/help.h b/pkg/system/help/help.h
new file mode 100644
index 00000000..e1ec7070
--- /dev/null
+++ b/pkg/system/help/help.h
@@ -0,0 +1,115 @@
+# Help Definitions.
+
+# Control Structure. Contains all control parameters. Pointer to structure
+# is passed to Lroff and on by Lroff to the input and output procedures.
+# With the exceptions of H_EOF and H_NLINES, the control parameters are
+# read only outside the main routine.
+
+define LEN_CTRLSTRUCT 220
+define SZ_CURPACK 39 # current package
+define SZ_SECNAME 39 # section name, single section mode
+define SZ_PARNAME 39 # parameter name
+define SZ_TEMPLATE 79 # the original modules template
+define SZ_HELPDB 1024 # max chars in helpdb file list
+
+define H_IN Memi[$1] # input file descriptor
+define H_OUT Memi[$1+1] # output file descriptor
+define H_OPTION Memi[$1+2] # option code (see below)
+define H_TTY Memi[$1+3] # TTY device descriptor
+define H_LMARGIN Memi[$1+4] # permanent left margin for Lroff
+define H_RMARGIN Memi[$1+5] # permanent right margin for Lroff
+define H_RAWIN Memi[$1+6] # if YES, do not look at input
+define H_RAWOUT Memi[$1+7] # if YES, do not process output
+define H_FILTER_INPUT Memi[$1+8] # if YES, filter out part of input
+define H_PAGINATE Memi[$1+9] # paginate output?
+define H_MANPAGE Memi[$1+10] # manpage style output?
+define H_NLPP Memi[$1+11] # number of lines per manual page
+define H_NLINES Memi[$1+12] # number of output lines on page
+define H_STATE Memi[$1+13] # input state, hinput()
+define H_EOF Memi[$1+14] # input should return EOF to Lroff
+define H_QUIT Memi[$1+15] # stop program
+define H_LENTL Memi[$1+16] # length of the TL template list
+define H_ALLMODULES Memi[$1+17] # process all modules matching template
+define H_FORMAT Memi[$1+18] # output format type
+define H_SOFLAG Memi[$1+19] # standout flags
+ # (extra space)
+define H_CURPACK Memc[P2C($1+20)] # current package
+define H_SECNAME Memc[P2C($1+60)] # section name
+define H_PARNAME Memc[P2C($1+100)] # parameter name
+define H_TEMPLATE Memc[P2C($1+140)] # module name template
+
+# The nomore flag is set whenever the user responds negatively to the more?
+# query. A nomore at the beginning of a help block or two nomores in a row
+# stop the program.
+
+define NOMORE (-1)
+
+# Option codes. Max_options is used by the get_option keyword recognizer,
+# which handles abbreviations.
+
+define O_HELP 1 # print full help block
+define O_SOURCE 2 # print source code
+define O_SYSDOC 3 # print technical system documentation
+define O_ALLDOC 4 # print all documentation (!source)
+define O_FILES 5 # print file names
+define O_SUMMARY 6 # summarize contents of help file
+define O_DIR 7 # print directory of help blocks
+define O_REFERENCES 8 # keyword search output format
+define MAX_OPTIONS 8
+
+define O_PARAM 7 # output text for single parameter
+define O_SECTION 8 # output text for single section
+define O_MENU 9 # print package menu
+
+# Type codes for filenames. Passed to hd_getname to fetch the module name
+# or a filename from a help directory.
+
+define TY_MODNAME 0
+define TY_HLP 1
+define TY_SYS 2
+define TY_SRC 3
+define TY_PKG 4
+define TY_MEN 5
+define TY_UNKNOWN 6
+
+# Format codes. This is used to determine whether we output formatted
+# text, HTML or Postscript.
+
+define HF_DEVICES "|terminal|text|gui|html|postscript|ps|"
+define HF_TERMINAL 1
+define HF_TEXT 2
+define HF_GUI 3
+define HF_HTML 4
+define HF_POSTSCRIPT 5
+define HF_PS 6
+
+# Help block header structure. A ".help" directive is decoded into this
+# structure. The line number counter should be zeroed when the structure
+# is allocated.
+
+define LEN_HBSTRUCT 1124
+define MAX_KEYS 50
+define SZ_TYPESTR 9 # help block type string
+define SZ_KEY 19 # max size of a key
+define SZ_SECTION 39 # section label, i.e., (Mar84)
+define SZ_TITLE 63 # block title
+
+define HB_TYPE Memi[$1] # type of block (default TY_HLP)
+define HB_LINENO Memi[$1+1] # line number within file
+define HB_NKEYS Memi[$1+2] # number of keys
+define HB_TYPESTR Memc[P2C($1+10)] # blk type string
+define HB_KEY Memc[P2C($1+20+($2-1)*20)] # keys
+define HB_SECTION Memc[P2C($1+1020)] # section label
+define HB_TITLE Memc[P2C($1+1060)] # block title
+
+# Pagination Control Codes. The pagination directives BP, TP, KS, and KE
+# are ignored when output is directed to the terminal, but are important
+# when output is piped to the printer. When the line input routine HINPUT sees
+# one of these directives in the input it places a control code in the
+# data stream read by Lroff. Lroff passes control codes on to the output,
+# i.e., to HOUTPUT, where pagination takes place.
+
+define BREAK_PAGE 1 # .bp
+define TEST_PAGE 2 # .tp n
+define START_KEEP 3 # .ks
+define END_KEEP 4 # .ke
diff --git a/pkg/system/help/helpdb.x b/pkg/system/help/helpdb.x
new file mode 100644
index 00000000..04af40db
--- /dev/null
+++ b/pkg/system/help/helpdb.x
@@ -0,0 +1,1203 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <syserr.h>
+include <error.h>
+include <finfo.h>
+include <fset.h>
+include <time.h>
+include <mii.h>
+include "help.h"
+include "helpdir.h"
+
+.help helpdb
+.nf ___________________________________________________________________________
+HELPDB -- Code to manage the help database. The help database is a set of
+compiled package help directories. Each help directory file is compiled with
+HD_OPEN and the resultant structure is saved in the database, indexed by the
+name of the directory file. At run time, instead of opening and interpreting
+multiple help directory files to expand templates, we merely read in the
+compiled database and search the index for the entry for the named package,
+returning a pointer to the compiled help directory structure for the package.
+The help database must be recompiled with HDB_COMPILE whenever the system help
+directory or a package help directory is modified.
+
+ hdb_compile (root_helpdir_filename, database_filename)
+
+ db = hdb_open (database)
+ hdb_close (db)
+ hp = hdb_load (db, help_directory_file)
+ hdb_free (db, hp)
+
+There is no provision for updating the database; the whole thing must be
+recompiled with HDB_COMPILE. At HELP time the root help directory is opened
+with HDB_OPEN, naming either a raw root help directory file or a compiled
+help database file. Normally a precompiled help database is used, but if
+desired the help directory files will be accessed directly. The directory
+for an individual package is accessed with HDB_LOAD, which is functionally
+equivalent to HD_OPEN (helpdir.x). HDB_FREE is functionally equivalent to
+HD_CLOSE.
+
+Currently the entire database is read into memory to speed up database
+searches. In the future this implementation should be changed to use the
+DBIO faciltities if the database becomes large.
+.endhelp ______________________________________________________________________
+
+define DATA_OFFSET 513 # offset to data area, chars
+define MAX_ENTRIES 100 # initial max db entries
+define INC_ENTRIES 50 # increment if overflow
+define MAX_DEPTH 20 # max nesting of packages
+define MAX_MENUSIZE 500 # max modules in a table
+define MAX_NAMELEN 20 # max chars in a module name in table
+define FIRST_COL 6 # indentation of tables
+
+# Help database header structure. Stored at the beginning of a help
+# database file.
+
+define LEN_HDBHEADER 14
+define HDB_MAGICVAL 110104B
+
+define HDB_MAGIC Memi[$1] # helpdb file type code
+define HDB_RAW Memi[$1+1] # access compiled or raw database
+define HDB_RHD Memi[$1+2] # if raw, HP of root help directory
+define HDB_INDEX Memi[$1+3] # index of root help directory
+define HDB_CRDATE Meml[$1+4] # creation date
+define HDB_NENTRIES Memi[$1+5] # number of help directories in db
+define HDB_MAXENTRIES Memi[$1+6] # maximum no. of help directories in db
+define HDB_NMODULES Memi[$1+7] # count of the total number of modules
+define HDB_INDEXOFFSET Meml[$1+8] # file offset of index, chars
+define HDB_INDEXPTR Memi[$1+9] # pointer to loaded index, ty_struct
+define HDB_INDEXLEN Memi[$1+10] # length of index structure, su
+define HDB_DATAOFFSET Meml[$1+11] # file offset of data area, chars
+define HDB_DATAPTR Memi[$1+12] # pointer to loaded data area, ty_struct
+define HDB_DATALEN Memi[$1+13] # length of data area, struct units
+
+# Index structure. Identifies the contents of the database and tells where
+# they are stored. There is one index entry for each help directory, i.e.,
+# for each package.
+
+define LEN_HDBINDEX 34
+define SZ_DBIKEY 63
+define LEN_DBIDATA 2
+
+define DBI_KEY Memc[P2C($1)] # entry name
+define DBI_OFFSET Memi[$1+32] # offset of entry into data area, su
+define DBI_MTIME Meml[$1+33] # modification date of entry
+
+
+# HDB_COMPILE -- Compile a set of help directories to produce a new help
+# database. The root help directory is read first and entered into
+# the database, followed by each subdirectory named in the root help
+# directory.
+
+procedure hdb_compile (root_helpdir_file, helpdb_file, verbose)
+
+char root_helpdir_file[ARB] # name of root help directory file
+char helpdb_file[ARB] # name of new database file
+bool verbose # print informative messages
+
+pointer db, index, p1, p2, ix
+bool no_entries_interchanged
+int fd, temp[LEN_HDBINDEX], i
+
+int open()
+bool strgt(), streq()
+long clktime(), note(), fstatl()
+errchk open, note, seek, hdb_compile_rhd, mii_writec, mii_writei
+
+begin
+ # Open the output database file.
+ fd = open (helpdb_file, NEW_FILE, BINARY_FILE)
+
+ # Allocate and initialize the database header and index structures.
+ # The data area begins at a fixed offset and will be written out
+ # as we go. The index and db header are written out after all
+ # help directories have been processed.
+
+ call calloc (db, LEN_HDBHEADER, TY_STRUCT)
+ call calloc (index, MAX_ENTRIES * LEN_HDBINDEX, TY_STRUCT)
+
+ HDB_MAGIC(db) = HDB_MAGICVAL
+ HDB_MAXENTRIES(db) = MAX_ENTRIES
+ HDB_CRDATE(db) = clktime (long(0))
+
+ # Write zeros into the header area of the file, so that the next
+ # sequential write will place the first data record at the offset
+ # DATA_OFFSET. We assume that the empty index is larger than the
+ # header area.
+
+ call write (fd, Memi[index], DATA_OFFSET - 1)
+ HDB_DATAOFFSET(db) = note (fd)
+
+ # Compile root directory followed by all subdirectories.
+ # The root directory is expanded into a set of package help
+ # directories which are compiled and written into the data
+ # area of the database. The database descriptor and index
+ # structures are returned.
+
+ call hdb_compile_rhd (fd, root_helpdir_file, db, index, verbose)
+
+ # Sort the index and append it to the database file. A simple
+ # interchange sort is sufficient here; we have assumed that the
+ # database is small in this implementation of helpdb.
+
+ if (HDB_NENTRIES(db) > 1)
+ repeat {
+ no_entries_interchanged = true
+ do i = 1, HDB_NENTRIES(db) - 1 {
+ p1 = index + (i - 1) * LEN_HDBINDEX
+ p2 = p1 + LEN_HDBINDEX
+ if (strgt (DBI_KEY(p1), DBI_KEY(p2))) {
+ call amovi (Memi[p1], temp, LEN_HDBINDEX)
+ call amovi (Memi[p2], Memi[p1], LEN_HDBINDEX)
+ call amovi (temp, Memi[p2], LEN_HDBINDEX)
+ no_entries_interchanged = false
+ }
+ }
+ } until (no_entries_interchanged)
+
+ HDB_INDEXOFFSET(db) = note (fd)
+ HDB_INDEXLEN(db) = HDB_NENTRIES(db) * LEN_HDBINDEX
+ HDB_MAXENTRIES(db) = HDB_NENTRIES(db)
+
+ # Get the offset into the index of the "_index" help directory
+ # (package name list).
+
+ do i = 1, HDB_NENTRIES(db) {
+ ix = index + (i - 1) * LEN_HDBINDEX
+ if (streq (DBI_KEY(ix), "_index")) {
+ HDB_INDEX(db) = i
+ break
+ }
+ }
+ if (HDB_INDEX(db) == 0)
+ call eprintf ("Help warning: cannot find _index\n")
+
+ # Write the index structure to the database file.
+ do i = 1, HDB_NENTRIES(db) {
+ ix = index + (i - 1) * LEN_HDBINDEX
+ call mii_writec (fd, DBI_KEY(ix), SZ_DBIKEY + 1)
+ call mii_writei (fd, DBI_OFFSET(ix), LEN_DBIDATA)
+ }
+
+ # Update the database file header.
+ call seek (fd, BOFL)
+ call mii_writei (fd, Memi[db], LEN_HDBHEADER)
+
+ call printf ("\nTotal of %d help modules in %d packages, ")
+ call pargi (HDB_NMODULES(db))
+ call pargi (HDB_NENTRIES(db) - 1)
+ call printf ("file size %d bytes\n")
+ call pargl (fstatl (fd, F_FILESIZE) * SZB_CHAR)
+
+ # All done; close files and deallocate buffers.
+ call close (fd)
+ call mfree (index, TY_STRUCT)
+ call mfree (db, TY_STRUCT)
+end
+
+
+# HDB_COMPILE_RHD -- Compile the root help directory and all subdirectories
+# into the database. The package structure is hierarchical but the database
+# is linear. Subdirectories (subpackages) are recursively expanded starting
+# with all packages in the root help directory. Each subdirectory is entered
+# into the database as it is found. We end up with an inverted index keyed
+# by the filename of the help directory file for each package. Since the
+# key is a filename each key is guaranteed to be unique.
+
+procedure hdb_compile_rhd (fd, root_helpdir_file, db, index, verbose)
+
+int fd # database file, written sequentially
+char root_helpdir_file[ARB] # name of root help directory file
+pointer db # database descriptor
+pointer index # database index
+bool verbose # print notes on structure of database
+
+bool found_a_subpackage
+pointer hp_stk[MAX_DEPTH] # help directory pointer stack
+int pk_stk[MAX_DEPTH] # subpackage index stack
+char fname[SZ_FNAME] # helpdir filename
+
+int sp, pk, len_index
+pointer ix, hp, modname, data, sv_sbuf
+long mtime, fi[LEN_FINFO], savepos
+
+long note(), clktime()
+int hd_getname(), finfo()
+pointer hd_open(), hdb_make_rhd()
+errchk finfo, seek, note, mii_writei
+errchk hd_getname, hdb_make_rhd, hdb_getdata
+
+begin
+ # Initialize the stacks and open the next help directory file to be
+ # processed, i.e., the root directory file.
+
+ sp = 0
+ pk = 1
+ call strcpy (root_helpdir_file, fname, SZ_FNAME)
+
+ iferr (hp = hd_open (root_helpdir_file))
+ call error (2, "cannot open root help directory file")
+ if (finfo (root_helpdir_file, fi) == ERR)
+ call error (3, "cannot get finfo on root help directory file")
+ mtime = FI_MTIME(fi)
+
+ # We enter the compile loop ready to scan the next help directory file,
+ # which has been pushed onto the top of the stack. The help directory
+ # file is first entered into the database, then we scan the directory
+ # until a subdirectory is found. If a subdirectory is found it is
+ # opened and pushed onto the stack and the process repeats (hd_open
+ # does not leave the physical file open so running out of file
+ # descriptors is not a problem). When the end of a directory is
+ # reached the stack is popped, closing the current directory, and
+ # we continue to scan the previous directory until another subdirectory
+ # is found.
+
+ repeat {
+ # Append the current compiled package help directory to the
+ # database. Update index; make index larger if it overflows.
+
+ HDB_NMODULES(db) = HDB_NMODULES(db) + HD_NMODULES(hp)
+ HDB_NENTRIES(db) = HDB_NENTRIES(db) + 1
+
+ if (HDB_NENTRIES(db) > HDB_MAXENTRIES(db)) {
+ HDB_MAXENTRIES(db) = HDB_MAXENTRIES(db) + INC_ENTRIES
+ len_index = HDB_MAXENTRIES(db) * LEN_HDBINDEX
+ iferr (call realloc (index, len_index, TY_STRUCT))
+ call fatal (1, "cannot reallocate index buffer")
+ }
+ ix = index + ((HDB_NENTRIES(db) - 1) * LEN_HDBINDEX)
+
+ # Prepare the index entry for the help directory file.
+ call strcpy (fname, DBI_KEY(ix), SZ_DBIKEY)
+ DBI_MTIME(ix) = mtime
+ DBI_OFFSET(ix) = HDB_DATALEN(db)
+
+ # Write the compiled help directory structure to the database
+ # file. The directory structure consists of the HD structure
+ # and a string buffer. We write out the HD structure followed
+ # by the string buffer. Each must be aligned to TY_STRUCT.
+ # The offset of the string buffer from the start of the helpdir
+ # struct is saved in the HD_NEXTCH field of the HD structure,
+ # to be used when loaded and referenced to compute a pointer to
+ # the buffer.
+
+ HD_NEXTCH(hp) = HD_LENHD(hp)
+ sv_sbuf = HD_SBUF(hp)
+ HD_SBUF(hp) = 0
+ call mii_writei (fd, Memi[hp], HD_LENHD(hp))
+ HD_SBUF(hp) = sv_sbuf
+ call mii_writec (fd, Memc[HD_SBUF(hp)], HD_SZSBUF(hp))
+
+ # Keep track of the amount of struct storage that will be
+ # required later to hold the UNPACKED helpdir data.
+
+ #HDB_DATALEN(db) = HDB_DATALEN(db) +
+ # HD_LENHD(hp) + ((HD_SZSBUF(hp) + SZ_STRUCT-1) / SZ_STRUCT)
+ HDB_DATALEN(db) = HDB_DATALEN(db) +
+ HD_LENHD(hp) + ((HD_SZSBUF(hp) + SZ_STRUCT32-1) / SZ_STRUCT32)
+
+ call printf ("%3d %15s (%s): %d help modules\n")
+ call pargi (sp + 1)
+ if (HD_PAKNAME(hp) != NULL)
+ call pargstr (Memc[HD_SBUF(hp)+HD_PAKNAME(hp)])
+ else
+ call pargstr ("")
+ call pargstr (fname)
+ call pargi (HD_NMODULES(hp))
+ call flush (STDOUT)
+
+ # Now scan the directory for subdirectories. If one is found,
+ # open it and push it on the stack, otherwise pop the stack and
+ # resume scanning the previous directory.
+
+ repeat {
+ # Search for a module which is a subpackage.
+ found_a_subpackage = false
+ for (; pk <= HD_NMODULES(hp); pk=pk+1) {
+ if (verbose) {
+ modname = M_NAME(HD_MODULE(hp,pk))
+ call printf ("\t\t[%d.%02d] %s\n")
+ call pargi (sp + 1)
+ call pargi (pk)
+ call pargstr (Memc[HD_SBUF(hp) + modname])
+ }
+ if (hd_getname (hp, pk, TY_PKG, fname, SZ_FNAME) > 0) {
+ found_a_subpackage = true
+ break
+ }
+ }
+
+ if (found_a_subpackage) {
+ if (finfo (fname, fi) == ERR) {
+ call eprintf ("\t\t%4w(cannot access `%s')\n")
+ call pargstr (fname)
+ # ...and continue searching the current helpdir
+ pk = pk + 1
+
+ } else {
+ # Got one; push it on the stack. Bump PK so that we
+ # resume scanning the package with the module following
+ # the subpackage.
+ sp = sp + 1
+ if (sp > MAX_DEPTH)
+ call fatal (3, "packages nested too deeply")
+ hp_stk[sp] = hp
+ pk_stk[sp] = pk + 1
+ iferr (hp = hd_open (fname)) {
+ hp = hp_stk[sp]
+ sp = sp - 1
+ call eprintf ("cannot open helpdir `%s'\n")
+ call pargstr (fname)
+ next
+ }
+ pk = 1
+ mtime = FI_MTIME(fi)
+ break # go process new helpdir
+ }
+
+ } else {
+ # Helpdir has been exhausted. Close it and pop the
+ # stack, continue scanning on the previous helpdir.
+
+ call hd_close (hp)
+ if (sp > 0) {
+ hp = hp_stk[sp]
+ pk = pk_stk[sp]
+ sp = sp - 1
+ if (verbose)
+ call printf ("\t\t\t[end of package]\n")
+
+ } else if (sp == 0) {
+ # Root helpdir file has been fully expanded. Scan
+ # all compiled helpdirs and produce a master helpdir
+ # containing an entry for each package in the database.
+ # This is similar to the root helpdir, but contains
+ # entries for packages at all levels, not just at the
+ # root. Note that we must save and restore the file
+ # position since hdb_make_rhd accesses the file.
+
+ call flush (fd)
+ savepos = note (fd)
+
+ # Load the database into memory.
+
+ call seek (fd, HDB_DATAOFFSET(db))
+ call calloc (data, 4*HDB_DATALEN(db), TY_STRUCT)
+ call hdb_getdata (fd, data, HDB_DATALEN(db))
+
+ hp = hdb_make_rhd (db, data, index)
+ pk = HD_NMODULES(hp) + 1
+ call strcpy ("_index", fname, SZ_FNAME)
+ mtime = clktime (long (0))
+ sp = -1
+
+ call mfree (data, TY_STRUCT)
+ call seek (fd, savepos)
+ break
+
+ } else
+ return # ALL DONE
+ }
+ call flush (STDOUT)
+ }
+ }
+end
+
+
+# HDB_MAKE_RHD -- Make a dummy root help directory for the database. This
+# entry looks just like any other compiled help directory, but serves as an
+# index to all packages in the database. Each module in root is a package,
+# and every package in the system, regardless of its level in the package
+# hierarchy, has an entry in root. We could also use the database index
+# for this purpose, but it is keyed by filename not package name, and the
+# help code considers the root help directory to be conceptually just another
+# package help directory (the db index is in the wrong format). The root
+# directory is equivalent to the compiled lib$root.hd, except that it
+# contains entries for all subpackages as well.
+#
+# We purposely do NOT sort the package list, because the list is accessed
+# sequentially when templates are expanded, hence the order determines the
+# search order for the database. Since the order in which packages are
+# entered into the database is determined by the order in which they are
+# encountered in a depth first search of the package hierarchy, the order of
+# the packages in the root help directory determines the search order.
+# It is desirable to search those packages most visible to the user (e.g.,
+# clpackage) before the more technical packages (e.g., sys).
+#
+# N.B.: This procedure is functionally similar to HD_OPEN and the HD_CLOSE
+# procedure may be used to close the HD structure returned by either.
+
+pointer procedure hdb_make_rhd (db, data, index)
+
+pointer db #I database descriptor
+pointer data #I data buffer (compiled help directories)
+pointer index #I database index
+
+int i, j, len_modlist, pos
+pointer hp, o_hp, mp, ix, sbuf, o_mp, c_modlist, hdfile
+
+bool streq()
+pointer coerce()
+int hd_putstr(), strncmp()
+errchk hdb_putmodule
+
+begin
+ # Allocate and initialize descriptor and string buffer. Must init
+ # nextch to 1 because 0 is the null index.
+
+ call calloc (hp, LEN_HDSTRUCT, TY_STRUCT)
+ call calloc (sbuf, SZ_SBUF, TY_CHAR)
+
+ HD_SBUF(hp) = sbuf
+ HD_DEFDIR(hp) = NULL
+ HD_NEXTCH(hp) = 1
+ HD_SZSBUF(hp) = SZ_SBUF
+ HD_LENHD(hp) = LEN_HDSTRUCT
+ HD_MAXMODULES(hp) = MAX_MODULES
+
+ # The root help directory is the first module. Since the root is
+ # not a subpackage of any other package we cannot enter it in the
+ # loop below. We must handcraft this first entry.
+
+ HD_NMODULES(hp) = 1
+ mp = HD_MODULE(hp,1)
+ call aclri (Memi[mp], LEN_MODSTRUCT)
+ M_NAME(mp) = hd_putstr (hp, "_root")
+ M_PKG(mp) = hd_putstr (hp, DBI_KEY(index))
+
+ # Examine each compiled helpdir for subpackages. Add each subpackage
+ # found to the current directory. Do not add the index entries
+ # themselves because they are already referenced in the help
+ # directories.
+
+ for (i=1; i <= HDB_NENTRIES(db); i=i+1) {
+ ix = index + (i - 1) * LEN_HDBINDEX
+ if (strncmp (DBI_KEY(ix), "_index", 6) == 0)
+ next
+
+ o_hp = data + DBI_OFFSET(ix)
+ HD_SBUF(o_hp) = coerce (o_hp + HD_NEXTCH(o_hp), TY_STRUCT, TY_CHAR)
+
+ for (j=1; j <= HD_NMODULES(o_hp); j=j+1) {
+ mp = HD_MODULE(o_hp,j)
+ if (M_PKG(mp) != NULL)
+ call hdb_putmodule (hp, o_hp, j)
+ }
+ }
+
+ # Our procedure for building the _index module list has changed the
+ # ordering of the packages from the depth first order of the database
+ # index. We want the depth first order to be our search order so
+ # we must reorder the module list to agree with the DBI index.
+ # Make a copy of the modlist, then write a new one, overwriting the
+ # old, looking up each package in the index to determine its order
+ # in the new modlist.
+
+ len_modlist = HD_NMODULES(hp) * LEN_MODSTRUCT
+ call calloc (c_modlist, len_modlist, TY_STRUCT)
+ call amovi (Memi[HD_MODULE(hp,1)], Memi[c_modlist], len_modlist)
+
+ pos = 0
+ do j = 1, HDB_NENTRIES(db) {
+ # Find next valid index entry.
+ ix = index + (j - 1) * LEN_HDBINDEX
+ if (strncmp (DBI_KEY(ix), "_index", 6) == 0)
+ next
+
+ # Locate corresponding helpdir entry, if any.
+ do i = 1, HD_NMODULES(hp) {
+ o_mp = c_modlist + (i - 1) * LEN_MODSTRUCT
+ hdfile = HD_SBUF(hp) + M_PKG(o_mp)
+ if (Memc[hdfile] == EOS)
+ next
+ else if (streq (DBI_KEY(ix), Memc[hdfile])) {
+ # Append entry to output helpdir.
+ pos = pos + 1
+ call amovi (Memi[o_mp], Memi[HD_MODULE(hp,pos)],
+ LEN_MODSTRUCT)
+ }
+ }
+ }
+
+ call mfree (c_modlist, TY_STRUCT)
+ HD_NMODULES(hp) = pos
+
+ # Return any unused space in string buffer.
+ call realloc (HD_SBUF(hp), HD_NEXTCH(hp), TY_CHAR)
+ HD_SZSBUF(hp) = HD_NEXTCH(hp)
+
+ # Return any unused module descriptors.
+ HD_LENHD(hp) = HD_LENHD(hp) -
+ LEN_MODSTRUCT * (HD_MAXMODULES(hp) - HD_NMODULES(hp))
+ call realloc (hp, HD_LENHD(hp), TY_STRUCT)
+ HD_MAXMODULES(hp) = HD_NMODULES(hp)
+
+ return (hp)
+end
+
+
+# HDB_OPEN -- Open the help database. We can either read the precompiled
+# help database or the distributed, raw help database (.hd textfiles).
+# If the precompiled database is to be used access will be faster, but
+# packages and modules added since the database was compiled with not be
+# accessible. To use the precompiled database we read the database index
+# into memory; the actual help files are accessed via this index at runtime.
+# If multiple compiled databases are specified they are combined to form one
+# large database.
+
+pointer procedure hdb_open (database)
+
+char database[ARB] #I name of database to be opened
+
+bool no_entries_interchanged
+pointer sp, fname, files, hp, db, d_op, i_op, ix, p1, p2, db_save
+int nfiles, nints, list, fd, d_len, i_len, i, temp[LEN_HDBINDEX]
+
+long clktime()
+bool streq(), strgt()
+pointer hd_open(), hdb_make_rhd()
+int open(), mii_readi(), mii_readc()
+int envgets(), access(), fntopnb(), fntgfnb()
+errchk calloc, realloc, open, seek, syserrs
+errchk hd_open, fntopnb, fntgfnb, hdb_make_rhd, hdb_getdata
+define rejectfile_ 91
+define readerr_ 92
+
+begin
+ call smark (sp)
+ call salloc (files, SZ_HELPDB, TY_CHAR)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+ call salloc (hp, LEN_HDBHEADER, TY_STRUCT)
+ call salloc (db_save, LEN_HDBHEADER, TY_STRUCT)
+
+ # Allocate database descriptor.
+ call calloc (db, LEN_HDBHEADER, TY_STRUCT)
+
+ # If the database name is "helpdir", raw access is desired and the
+ # name of the root help directory file is given by the environment
+ # variable "helpdir". If the database name is "helpdb", the
+ # precompiled database is to be used and the name of the database
+ # file or files is given by the environment variable "helpdb".
+ # Otherwise the database name is assumed to be the name of a raw or
+ # precompiled database file.
+
+ if (streq (database, "helpdir")) {
+ HDB_RAW(db) = YES
+ if (envgets ("helpdir", Memc[files], SZ_HELPDB) <= 0)
+ call syserrs (SYS_ENVNF, "helpdir")
+ } else if (streq (database, "helpdb")) {
+ HDB_RAW(db) = NO
+ if (envgets ("helpdb", Memc[files], SZ_HELPDB) <= 0)
+ call syserrs (SYS_ENVNF, "helpdb")
+ } else {
+ HDB_RAW(db) = access (database, 0, TEXT_FILE)
+ call strcpy (database, Memc[files], SZ_HELPDB)
+ }
+
+ # We now have the filename or file list; if it is a raw help directory
+ # file, open it with HD_OPEN and we are all done for now. Otherwise
+ # read the helpdb files and construct the help database index.
+
+ if (HDB_RAW(db) == YES) {
+ iferr (HDB_RHD(db) = hd_open (Memc[files]))
+ call fatal (1, "cannot open root help directory file")
+
+ call sfree (sp)
+ return (db)
+ }
+
+ # Allocate and initialize empty database header and index structures.
+ HDB_MAGIC(db) = HDB_MAGICVAL
+ HDB_CRDATE(db) = clktime (long(0))
+
+ HDB_NENTRIES(db) = 0
+ HDB_MAXENTRIES(db) = MAX_ENTRIES
+ HDB_NMODULES(db) = 0
+ HDB_DATAPTR(db) = NULL
+ HDB_DATALEN(db) = 0
+ HDB_INDEXPTR(db) = NULL
+ HDB_INDEXLEN(db) = 0
+ HDB_MAXENTRIES(db) = HDB_NENTRIES(db)
+
+ # Link a binary help database; open each precompiled database and
+ # link it into the full runtime database.
+
+ list = fntopnb (Memc[files], YES)
+ nfiles = 0
+
+ while (fntgfnb (list, Memc[fname], SZ_FNAME) != EOF) {
+ iferr (fd = open (Memc[fname], READ_ONLY, BINARY_FILE)) {
+ call eprintf ("Cannot open help database file %s\n")
+ call pargstr (Memc[fname])
+ next
+ }
+
+ # Save descriptor in case we cannot read this file.
+ call amovi (Memi[db], Memi[db_save], LEN_HDBHEADER)
+
+ # Read the database file header.
+ nints = LEN_HDBHEADER
+ if (mii_readi (fd, Memi[hp], nints) < nints) {
+ call eprintf ("Cannot read help database file header (%s)\n")
+ call pargstr (Memc[fname])
+ goto rejectfile_
+ }
+
+ # Verify the file type.
+ if (HDB_MAGIC(hp) != HDB_MAGICVAL) {
+ call eprintf ("Not a help database file (%s)\n")
+ call pargstr (Memc[fname])
+ goto rejectfile_
+ }
+
+ # Merge the headers.
+ HDB_NENTRIES(db) = HDB_NENTRIES(db) + HDB_NENTRIES(hp)
+ HDB_NMODULES(db) = HDB_NMODULES(db) + HDB_NMODULES(hp)
+ HDB_MAXENTRIES(db) = HDB_NENTRIES(db)
+
+ d_len = HDB_DATALEN(db)
+ i_len = HDB_INDEXLEN(db)
+
+ # Make room for the new data and index entries.
+ iferr {
+ HDB_DATALEN(db) = HDB_DATALEN(db) + HDB_DATALEN(hp)
+ call realloc (HDB_DATAPTR(db), HDB_DATALEN(db), TY_STRUCT)
+ HDB_INDEXLEN(db) = HDB_INDEXLEN(db) + HDB_INDEXLEN(hp)
+ call realloc (HDB_INDEXPTR(db), HDB_INDEXLEN(db), TY_STRUCT)
+ } then
+ call erract (EA_WARN)
+
+ d_op = HDB_DATAPTR(db) + d_len
+ i_op = HDB_INDEXPTR(db) + i_len
+
+ # Append the data area of the new database file to the end of
+ # the data buffer.
+
+ call seek (fd, HDB_DATAOFFSET(hp))
+ call hdb_getdata (fd, d_op, HDB_DATALEN(hp))
+
+ # Append the index area of the new database file to the end of
+ # the index buffer.
+
+ nints = HDB_INDEXLEN(hp)
+ call seek (fd, HDB_INDEXOFFSET(hp))
+
+ do i = 1, HDB_NENTRIES(hp) {
+ ix = i_op + (i - 1) * LEN_HDBINDEX
+ if (mii_readc (fd, DBI_KEY(ix), SZ_DBIKEY + 1) < SZ_DBIKEY + 1)
+ goto readerr_
+ if (mii_readi (fd, DBI_OFFSET(ix), LEN_DBIDATA) < LEN_DBIDATA) {
+readerr_ call eprintf ("Cannot read database index (%s)\n")
+ call pargstr (Memc[fname])
+ goto rejectfile_
+ }
+
+ # Patch the index entry to reflect the new offset of the
+ # directory entry in the data buffer. Rename the _index
+ # entries in the old (input) databases, since we will be
+ # building a new _index for the final composite database.
+
+ DBI_OFFSET(ix) = DBI_OFFSET(ix) + d_len
+ if (streq (DBI_KEY(ix), "_index")) {
+ call sprintf (DBI_KEY(ix), SZ_DBIKEY, "_index.%s")
+ call pargstr (Memc[fname])
+ }
+ }
+
+ nfiles = nfiles + 1
+ call close (fd)
+ next
+rejectfile_
+ # Could not read file; restore the descriptor to the state it
+ # was in before we tried to read the file, to repair any damage.
+
+ d_op = HDB_DATAPTR(db); i_op = HDB_INDEXPTR(db)
+ call amovi (Memi[db_save], Memi[db], LEN_HDBHEADER)
+ HDB_DATAPTR(db) = d_op; HDB_INDEXPTR(db) = i_op
+
+ call close (fd)
+ }
+
+ # Verify that there was at least one valid file in the list.
+ if (nfiles <= 0)
+ call error (5, "invalid help database file list")
+
+ # Build the package name index (root helpdir) for the new database.
+ hp = hdb_make_rhd (db, HDB_DATAPTR(db), HDB_INDEXPTR(db))
+
+ # Append the compiled package help directory to the database.
+ HDB_NMODULES(db) = HDB_NMODULES(db) + HD_NMODULES(hp)
+ HDB_NENTRIES(db) = HDB_NENTRIES(db) + 1
+
+ # Append the compiled _index helpdir and associated string buffer
+ # to the database data buffer, as if these data structures had been
+ # read from the help database file (all helpdir access codes assume
+ # this structure).
+
+ d_len = HDB_DATALEN(db)
+ nints = HD_LENHD(hp) + (HD_SZSBUF(hp) + SZ_STRUCT32-1) / SZ_STRUCT32
+ HDB_DATALEN(db) = HDB_DATALEN(db) + nints
+ call realloc (HDB_DATAPTR(db), HDB_DATALEN(db), TY_STRUCT)
+ d_op = HDB_DATAPTR(db) + d_len
+
+ HD_NEXTCH(hp) = HD_LENHD(hp)
+ call amovi (Memi[hp], Memi[d_op], HD_LENHD(hp))
+ call amovc (Memc[HD_SBUF(hp)], Memi[d_op+HD_LENHD(hp)], HD_SZSBUF(hp))
+
+ # Add an index entry for the _index helpdir.
+ if (HDB_NENTRIES(db) > HDB_MAXENTRIES(db)) {
+ HDB_MAXENTRIES(db) = HDB_MAXENTRIES(db) + 1
+ nints = HDB_MAXENTRIES(db) * LEN_HDBINDEX
+ iferr (call realloc (HDB_INDEXPTR(db), nints, TY_STRUCT))
+ call fatal (1, "cannot reallocate index buffer")
+ }
+
+ ix = HDB_INDEXPTR(db) + (HDB_NENTRIES(db) - 1) * LEN_HDBINDEX
+ call strcpy ("_index", DBI_KEY(ix), SZ_DBIKEY)
+ DBI_MTIME(ix) = clktime (long(0))
+ DBI_OFFSET(ix) = d_op - HDB_DATAPTR(db)
+
+ # Free dedicated hp/sbuf, since descriptor is in data buffer now.
+ call hd_close (hp)
+
+ # Sort the index; a crude sort is adequate here.
+ if (HDB_NENTRIES(db) > 1) {
+ repeat {
+ no_entries_interchanged = true
+ do i = 1, HDB_NENTRIES(db) - 1 {
+ p1 = HDB_INDEXPTR(db) + (i - 1) * LEN_HDBINDEX
+ p2 = p1 + LEN_HDBINDEX
+ if (strgt (DBI_KEY(p1), DBI_KEY(p2))) {
+ call amovi (Memi[p1], temp, LEN_HDBINDEX)
+ call amovi (Memi[p2], Memi[p1], LEN_HDBINDEX)
+ call amovi (temp, Memi[p2], LEN_HDBINDEX)
+ no_entries_interchanged = false
+ }
+ }
+ } until (no_entries_interchanged)
+ }
+
+ # Get the index offset of the NEW "_index" help directory.
+ HDB_INDEX(db) = 0
+ do i = 1, HDB_NENTRIES(db) {
+ ix = HDB_INDEXPTR(db) + (i - 1) * LEN_HDBINDEX
+ if (streq (DBI_KEY(ix), "_index")) {
+ HDB_INDEX(db) = i
+ break
+ }
+ }
+ if (HDB_INDEX(db) == 0)
+ call eprintf ("Help warning: cannot find _index")
+
+ call fntclsb (list)
+ call sfree (sp)
+
+ return (db)
+end
+
+
+# HDB_CLOSE -- Close the help database. If raw database is being accessed,
+# this means close root help directory and free DB struct. If precompiled,
+# deallocate all buffers used by the database.
+
+procedure hdb_close (db)
+
+pointer db # database descriptor
+
+begin
+ if (HDB_RAW(db) == YES)
+ call hd_close (HDB_RHD(db))
+ else {
+ call mfree (HDB_DATAPTR(db), TY_STRUCT)
+ call mfree (HDB_INDEXPTR(db), TY_STRUCT)
+ }
+ call mfree (db, TY_STRUCT)
+end
+
+
+# HDB_LOAD -- Load the named help directory. Help directories are referred
+# to by the name of the directory file, and the database is keyed by the name
+# of the file. If the database is being accessed raw, we open and compile
+# the named file directly, otherwise we look up the compiled directory in the
+# database. In either case we return a HD pointer to the compiled directory.
+# The directory "_index" is special, being the package index directory for the
+# entire database.
+
+pointer procedure hdb_load (db, helpdir)
+
+pointer db # database descriptor
+char helpdir[ARB] # help directory to be accessed.
+
+bool index
+pointer hp, ix, sp, errmsg
+
+bool streq()
+int hdb_search()
+pointer hd_open(), coerce()
+errchk hdb_open
+
+begin
+ call smark (sp)
+ call salloc (errmsg, SZ_LINE, TY_CHAR)
+
+ index = (streq (helpdir, "_index") || streq (helpdir, "_root"))
+
+ if (HDB_RAW(db) == YES) {
+ if (index)
+ hp = HDB_RHD(db)
+ else
+ hp = hd_open (helpdir)
+
+ } else {
+ # Compute and return pointer to compiled HD. Fix up pointer to
+ # the string buffer sbuf, since the pointer value depends on the
+ # value of the pointer to the newly allocated data area. If not
+ # found, return NULL pointer.
+
+ if (index) {
+ ix = HDB_INDEXPTR(db) + (HDB_INDEX(db) - 1) * LEN_HDBINDEX
+
+ } else if (hdb_search (db, helpdir, ix) == ERR) {
+ # There should be a better way to do this... Format error
+ # message and pass to the error handling code, then restore
+ # stack before taking the error action.
+
+ call sprintf (Memc[errmsg], SZ_LINE,
+ "help directory `%s' not found")
+ call pargstr (helpdir)
+ iferr (call error (6, Memc[errmsg])) {
+ call sfree (sp)
+ call erract (EA_ERROR)
+ return (NULL)
+ }
+ }
+
+ hp = HDB_DATAPTR(db) + DBI_OFFSET(ix)
+ HD_SBUF(hp) = coerce (hp + HD_NEXTCH(hp), TY_STRUCT, TY_CHAR)
+ }
+
+ call sfree (sp)
+ return (hp)
+end
+
+
+# HDB_FREE -- Free space for a help directory loaded with HDB_LOAD. If we are
+# using raw access, we let the helpdir package free what ever it wants to since
+# it did the allocating. If we are accessing the compiled database then there
+# is nothing to free, since everything is maintained in memory.
+
+procedure hdb_free (db, hp)
+
+pointer db # database descriptor
+pointer hp # help directory
+
+begin
+ if (HDB_RAW(db) == YES)
+ call hd_close (hp)
+end
+
+
+# HDB_SEARCH -- Search the database index for the given key. Since the index
+# has been sorted we can use a binary search. If the key is found we return
+# a pointer to the associated index as an output argument, and OK as the
+# function value.
+
+int procedure hdb_search (db, key, ix)
+
+pointer db # database descriptor
+char key[ARB] # filename key to be located
+pointer ix # pointer to index entry (output)
+
+int low, high, pos
+pointer ixoff
+bool strle(), streq()
+
+begin
+ ixoff = HDB_INDEXPTR(db)
+ low = 1
+ high = HDB_NENTRIES(db)
+
+ # Cut range of search in half until range is narrowed to two values (if
+ # we go until HIGH-LOW >= 1 an infinite loop can occur).
+
+ while (high - low > 1) {
+ pos = (high + low) / 2
+ if (strle (key, DBI_KEY(ixoff + (pos-1) * LEN_HDBINDEX)))
+ high = pos
+ else
+ low = pos
+ }
+
+ ix = ixoff + (high - 1) * LEN_HDBINDEX
+ if (streq (key, DBI_KEY(ix)))
+ return (high)
+ ix = ixoff + (low - 1) * LEN_HDBINDEX
+ if (streq (key, DBI_KEY(ix)))
+ return (low)
+
+ return (ERR)
+end
+
+
+# HDB_EXAMINE -- Examine the structure of the compiled database. A description
+# of the contents is printed on the output file.
+
+procedure hdb_examine (fd, helpdb, verbose)
+
+int fd # output file
+char helpdb[ARB] # filename of database to be examined
+bool verbose # print menus as well
+
+int list, i
+long fi[LEN_FINFO]
+pointer sp, fname, date, db, ixoff, ix
+
+bool strne()
+pointer hdb_open()
+int finfo(), fntopnb(), fntgfnb()
+errchk hdb_open, hdb_printpack, fntopnb, fntgfnb
+
+begin
+ call smark (sp)
+ call salloc (date, SZ_DATE, TY_CHAR)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+
+ db = hdb_open (helpdb)
+ ixoff = HDB_INDEXPTR(db)
+
+ call cnvdate (HDB_CRDATE(db), Memc[date], SZ_DATE)
+
+ list = fntopnb (helpdb, YES)
+ while (fntgfnb (list, Memc[fname], SZ_FNAME) != EOF) {
+ if (finfo (Memc[fname], fi) == ERR) {
+ call eprintf ("Cannot get info on file `%s'\n")
+ call pargstr (Memc[fname])
+ next
+ }
+
+ call fprintf (fd, "Help database %s created %s by %s, size=%d\n")
+ call pargstr (Memc[fname])
+ call pargstr (Memc[date])
+ call pargstr (FI_OWNER(fi))
+ call pargl (FI_SIZE(fi))
+ }
+ call fntclsb (list)
+
+ call fprintf (fd, "Total of %d modules in %d packages\n")
+ call pargi (HDB_NMODULES(db))
+ call pargi (HDB_NENTRIES(db) - 1)
+
+ do i = 1, HDB_NENTRIES(db) {
+ ix = ixoff + (i - 1) * LEN_HDBINDEX
+ if (strne (DBI_KEY(ix), "_index"))
+ call hdb_printpack (fd, db, ix, verbose)
+ }
+
+ call hdb_close (db)
+ call sfree (sp)
+end
+
+
+# HDB_PRINTPACK -- Print a description of a single package on the output
+# file.
+
+procedure hdb_printpack (fd, db, ix, verbose)
+
+int fd # output file
+pointer db # database descriptor
+pointer ix # database index descriptor of package
+bool verbose # print menus
+
+int m
+pointer sp, hp, paknames, date
+long fi[LEN_FINFO]
+int hd_getname(), envgeti(), finfo()
+pointer hdb_load()
+errchk hd_getname
+
+begin
+ call smark (sp)
+ call salloc (paknames, MAX_MENUSIZE, TY_POINTER)
+ call salloc (date, SZ_DATE, TY_CHAR)
+
+ iferr (hp = hdb_load (db, DBI_KEY(ix))) {
+ call erract (EA_WARN)
+ call sfree (sp)
+ return
+ }
+
+ call cnvdate (DBI_MTIME(ix), Memc[date], SZ_DATE)
+ if (finfo (DBI_KEY(ix), fi) == ERR)
+ FI_OWNER(fi) = EOS
+
+ if (verbose)
+ call fprintf (fd, "\n%s %s %s %s\n")
+ else
+ call fprintf (fd, "%-12s %s %-8s %s\n")
+
+ if (HD_PAKNAME(hp) != 0)
+ call pargstr (Memc[HD_SBUF(hp) + HD_PAKNAME(hp)])
+ else
+ call pargstr ("")
+ call pargstr (Memc[date])
+ call pargstr (FI_OWNER(fi))
+ call pargstr (DBI_KEY(ix))
+
+ if (verbose) {
+ # Extract the names of the modules in the package. Save the
+ # pointers in an array for the table print routine.
+
+ for (m=0; m < MAX_MENUSIZE; m=m+1) {
+ call salloc (Memi[paknames+m], MAX_NAMELEN, TY_CHAR)
+ if (hd_getname (hp, m+1, TY_MODNAME, Memc[Memi[paknames+m]],
+ MAX_NAMELEN) <= 0)
+ break
+ }
+
+ # Now print the table. It is not necessary to sort the table,
+ # because the "helpdir" code (which reads the help directory) has
+ # already done so.
+
+ call strtbl (fd, Memc, Memi[paknames], m, FIRST_COL,
+ envgeti ("ttyncols"), MAX_NAMELEN, 0)
+ }
+
+ call hdb_free (db, hp)
+ call sfree (sp)
+end
+
+
+# HDB_PUTMODULE -- Put a module (subpackage) into the root help directory.
+# Add new entry, increasing space if necessary. Expand all filenames to
+# remove help ldir references and place filenames in our string buffer,
+# sbuf offsets into module descriptor. Increase size of sbuf if it fills.
+
+procedure hdb_putmodule (hp, o_hp, pk)
+
+pointer hp # new help directory being extended
+pointer o_hp # old help directory
+int pk # module number in old directory
+
+int firstch, m
+pointer sp, fname, sbuf, o_sbuf, mp, o_mp, pakname
+int hd_getname(), hd_putstr()
+bool streq()
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+
+ sbuf = HD_SBUF(hp)
+ o_sbuf = HD_SBUF(o_hp)
+ o_mp = HD_MODULE(o_hp,pk)
+ pakname = o_sbuf + M_NAME(o_mp)
+
+ # Check if this is a redefinition of a module already defined.
+ # If so, warn user that new package does not have a unique name,
+ # and omit package.
+
+ firstch = Memc[pakname]
+ for (m=1; m <= HD_NMODULES(hp); m=m+1) {
+ mp = HD_MODULE(hp,m)
+ if (Memc[sbuf+M_NAME(mp)] == firstch)
+ if (streq (Memc[sbuf+M_NAME(mp)], Memc[pakname])) {
+ call eprintf ("package name `%s' (hd=%s) is not unique\n")
+ call pargstr (Memc[pakname])
+ call pargstr (Memc[o_sbuf+M_PKG(o_mp)])
+ call sfree (sp)
+ return
+ }
+ }
+
+ # If we are out of space for modules, increase the descriptor
+ # structure size to allow more module descriptors.
+
+ if (m > HD_NMODULES(hp)) {
+ if (m > HD_MAXMODULES(hp)) {
+ HD_LENHD(hp) = HD_LENHD(hp) + (INC_MODULES * LEN_MODSTRUCT)
+ call realloc (hp, HD_LENHD(hp), TY_STRUCT)
+ HD_MAXMODULES(hp) = HD_MAXMODULES(hp) + INC_MODULES
+ }
+ HD_NMODULES(hp) = m
+ }
+
+ mp = HD_MODULE(hp,m)
+ call aclri (Memi[mp], LEN_MODSTRUCT)
+
+ # Put module name in string buffer and save index of string in module
+ # descriptor.
+
+ M_NAME(mp) = hd_putstr (hp, Memc[pakname])
+
+ # Extract all filenames and move into string buffer. Call hd_getname to
+ # extract filenames from old directory, so that help-ldir references
+ # are expanded.
+
+ if (hd_getname (o_hp, pk, TY_HLP, Memc[fname], SZ_FNAME) > 0)
+ M_HLP(mp) = hd_putstr (hp, Memc[fname])
+ if (hd_getname (o_hp, pk, TY_SYS, Memc[fname], SZ_FNAME) > 0)
+ M_SYS(mp) = hd_putstr (hp, Memc[fname])
+ if (hd_getname (o_hp, pk, TY_SRC, Memc[fname], SZ_FNAME) > 0)
+ M_SRC(mp) = hd_putstr (hp, Memc[fname])
+ if (hd_getname (o_hp, pk, TY_PKG, Memc[fname], SZ_FNAME) > 0)
+ M_PKG(mp) = hd_putstr (hp, Memc[fname])
+ if (hd_getname (o_hp, pk, TY_MEN, Memc[fname], SZ_FNAME) > 0)
+ M_MEN(mp) = hd_putstr (hp, Memc[fname])
+
+ call sfree (sp)
+end
+
+
+# HDB_GETDATA -- Read a stored series of compiled help directories, stored
+# externally in a machine independent format, into the given data buffer.
+# Each stored help directory consists of a fixed sized MII-32 header followed
+# by a MII byte packed string buffer of arbitrary length. Reading begins
+# at the current file position.
+
+procedure hdb_getdata (fd, obuf, buflen)
+
+int fd #I input file
+pointer obuf #O receives unpacked helpdir data
+int buflen #O max su out
+
+int i, nelem, nr, sz_mii_struct
+pointer op, hp
+int mii_readi(), mii_readc()
+errchk mii_readi, mii_readc
+define readerr_ 91
+
+begin
+ nr = 0
+ for (op=obuf; nr < buflen; ) {
+ hp = op
+
+ # Get fixed size helpdir header.
+ if (mii_readi (fd, Memi[op], LEN_BASEHD) < LEN_BASEHD)
+ goto readerr_
+ nr = nr + LEN_BASEHD
+
+ # Get module entries.
+ op = op + LEN_BASEHD
+ nelem = HD_LENHD(hp) - LEN_BASEHD
+ if (mii_readi (fd, Memi[op], nelem) < nelem)
+ goto readerr_
+ nr = nr + nelem
+
+ # Get string buffer.
+ op = op + nelem
+ nelem = HD_SZSBUF(hp) # / (SZ_INT / SZ_INT32)
+ if (mii_readc (fd, Memi[op], nelem) < nelem)
+ goto readerr_
+
+ nr = nr + ((nelem + SZ_STRUCT32-1) / SZ_STRUCT32)
+ sz_mii_struct = MII_INT / NBITS_BYTE / SZB_CHAR
+ op = op + ((nelem + sz_mii_struct-1) / sz_mii_struct)
+ }
+
+ return
+
+readerr_
+ # Common read error code.
+ call error (1, "Cannot read help database data\n")
+end
diff --git a/pkg/system/help/helpdir.h b/pkg/system/help/helpdir.h
new file mode 100644
index 00000000..89b851a7
--- /dev/null
+++ b/pkg/system/help/helpdir.h
@@ -0,0 +1,34 @@
+# Size limiting definitions.
+
+define MAX_LDIRS 50 # maximum ldirs for package
+define MAX_MODULES 100 # initial maximum no. modules
+define INC_MODULES 50 # increment if overflow
+define SZ_SBUF 2048 # initial size string buffer
+define INC_SZSBUF 1024 # increment if overflow
+
+define LEN_HDSTRUCT (10+MAX_LDIRS+MAX_MODULES*LEN_MODSTRUCT)
+define LEN_BASEHD 10
+define LEN_MODSTRUCT 6
+
+# Helpdir descriptor structure.
+
+define HD_SBUF Memi[$1] # string buffer
+define HD_NEXTCH Memi[$1+1] # index of next char in sbuf
+define HD_SZSBUF Memi[$1+2] # size of string buffer
+define HD_DEFDIR Memi[$1+3] # offset to defdir
+define HD_NLDIRS Memi[$1+4] # number of logical directories
+define HD_NMODULES Memi[$1+5] # number of modules in package
+define HD_MAXMODULES Memi[$1+6] # max no. of modules in package
+define HD_LENHD Memi[$1+7] # length of this structure
+define HD_PAKNAME Memi[$1+8] # offset of package name string
+define HD_LDIR Memi[$1+10+$2-1] # indices of ldir strings
+define HD_MODULE ($1+60+($2-1)*6) # module descriptors
+
+# Module descriptor structure.
+
+define M_NAME Memi[$1] # module name index
+define M_HLP Memi[$1+1] # help file index
+define M_SYS Memi[$1+2] # system docs file index
+define M_SRC Memi[$1+3] # source code file index
+define M_PKG Memi[$1+4] # pkg helpdir file index
+define M_MEN Memi[$1+5] # package menu file index
diff --git a/pkg/system/help/helpdir.x b/pkg/system/help/helpdir.x
new file mode 100644
index 00000000..38a2e12c
--- /dev/null
+++ b/pkg/system/help/helpdir.x
@@ -0,0 +1,775 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include <error.h>
+include "help.h"
+include "helpdir.h"
+
+.help helpdir
+.nf ___________________________________________________________________________
+HELPDIR -- Routines for accessing helpdir files. A helpdir lists the
+modules in a package, as well as the files containing the help text and
+source for each module. There are two kinds of helpdir files: the 'packhelp'
+file lists the packages, and each package has its own helpdir file listing
+the modules within that package. The following functions are required to
+access help module lists:
+
+ hp = hd_open (fname)
+ hd_close (hp)
+
+ modnum = hd_findmod (hp, modname)
+ nchars = hd_getname (hp, modnum, field, outstr, maxch)
+ hd_debug (hp, out)
+
+The HD_OPEN function opens the helpdir file and decodes the contents, producing
+a binary structure pointed to by hp. HD_FINDMOD searches for a module by name,
+returning the module number within the helpdir. HD_GETNAME fetches either
+the module name (field "mod") or a file name (fields "hlp", "sys", etc.).
+File names are returned as OS pathnames, with logical directory expansion taking
+place within the helpdir package.
+
+Helpdir files have the following structure:
+
+ $defdir = pathname|ldir
+ $ldir1 = pathname|ldir
+ $ldir2 = pathname|ldir
+ ...
+ $ldirN = pathname|ldir
+
+ module1 hlp=file, sys=file, src=file, pkg=file, men=file
+ module2 hlp=file, etc.
+ ...
+ moduleN hlp=file, etc.
+
+The dollar signs are required to make it easy to distinguish logical directory
+declarations from module entries. Logical directories defined local to the
+help directory file are not expanded recursively. If the last nonwhite char
+on a line is a comma, the file list is assumed to be continued on the next
+line. If two or more files in a module list are the same, all but the first
+may be set to ".." and the last file name given will be used. Quotes are
+optional. All file assignments are optional, and they may occur in any order.
+.endhelp _______________________________________________________________________
+
+
+# HD_OPEN -- Open the helpdir file, allocate descriptor and decode file
+# into descriptor. Sort module list when done, unless sorting is disabled
+# by inclusion of the directive ".nosort" in the text. Ignore comment lines and
+# blank lines. Ldir declarations and module entries may be given in any
+# order.
+
+pointer procedure hd_open (helpdir_file)
+
+char helpdir_file[ARB]
+bool sort_modules
+pointer sp, hp, ip, lbuf, defdir, word
+int fd, junk
+
+bool streq()
+int open(), getline(), fnroot(), fnldir(), ctowrd()
+int hd_putstr()
+errchk salloc, open, calloc, getline, hd_putstr
+errchk hd_putldiry, hd_putmodule, hd_sort_modules
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+ call salloc (defdir, SZ_PATHNAME, TY_CHAR)
+ call salloc (word, SZ_FNAME, TY_CHAR)
+
+ # If helpdir file is not yet installed, print warning message
+ # and return the NULL pointer, indicating that the help directory
+ # could not be loaded.
+
+ iferr (fd = open (helpdir_file, READ_ONLY, TEXT_FILE)) {
+ call sfree (sp)
+ call erract (EA_ERROR)
+ return (NULL)
+ }
+
+ # Allocate and initialize descriptor and string buffer. Must init
+ # nextch to 1 because 0 is the null index.
+
+ call calloc (hp, LEN_HDSTRUCT, TY_STRUCT)
+ call calloc (HD_SBUF(hp), SZ_SBUF, TY_CHAR)
+ HD_DEFDIR(hp) = NULL
+ HD_NEXTCH(hp) = 1
+ HD_SZSBUF(hp) = SZ_SBUF
+ HD_MAXMODULES(hp) = MAX_MODULES
+ HD_LENHD(hp) = LEN_HDSTRUCT
+ sort_modules = true
+
+ # Extract package name into string buffer. The package name is assumed
+ # to be the root of the filename.
+
+ junk = fnroot (helpdir_file, Memc[lbuf], SZ_LINE)
+ HD_PAKNAME(hp) = hd_putstr (hp, Memc[lbuf])
+
+ # Extract directory prefix of the package help directory file. Make
+ # it the default directory prefix for all filenames in the directory.
+
+ if (fnldir (helpdir_file, Memc[defdir], SZ_PATHNAME) == 0) {
+ call fpathname (helpdir_file, Memc[lbuf], SZ_LINE)
+ junk = fnldir (Memc[lbuf], Memc[defdir], SZ_PATHNAME)
+ }
+ call sprintf (Memc[lbuf], SZ_LINE, "defdir = %s\n")
+ call pargstr (Memc[defdir])
+ call hd_putldiry (hp, Memc[lbuf])
+
+ # Compile the file, processing all logical directory definitions,
+ # set option statments, and module declarations. Ignore blank lines
+ # and comment lines.
+
+ while (getline (fd, Memc[lbuf]) != EOF) {
+ for (ip=lbuf; IS_WHITE (Memc[ip]); ip=ip+1)
+ ;
+ if (Memc[ip] == '#' || Memc[ip] == '\n' || Memc[ip] == EOS)
+ next
+
+ # A leading dollar sign denotes a logical directory declaration.
+ # A leading period denotes a compiler directive.
+ # Anything else is a module entry.
+
+ if (Memc[ip] == '$') {
+ call hd_putldiry (hp, Memc[ip+1])
+ } else if (Memc[ip] == '.') {
+ ip = ip + 1
+ if (ctowrd (Memc, ip, Memc[word], SZ_FNAME) <= 0)
+ next
+ # The directive ".nosort" disables sorting of the module list.
+ # There are no other such directives at present, but they are
+ # easy to add.
+ if (streq (Memc[word], "nosort"))
+ sort_modules = false
+ else {
+ call eprintf ("Warning: unknown directive %s in helpdir\n")
+ call pargstr (Memc[word])
+ }
+ next
+ } else
+ call hd_putmodule (hp, fd, Memc[lbuf])
+ }
+
+ # We are all done with the helpdir file, so close it. Sort module
+ # list alphabetically by name.
+
+ call close (fd)
+ if (sort_modules && HD_NMODULES(hp) > 1)
+ call hd_sort_modules (hp)
+
+ # Return any unused space in string buffer.
+ call realloc (HD_SBUF(hp), HD_NEXTCH(hp), TY_CHAR)
+ HD_SZSBUF(hp) = HD_NEXTCH(hp)
+
+ # Return any unused module descriptors.
+ HD_LENHD(hp) = HD_LENHD(hp) -
+ LEN_MODSTRUCT * (HD_MAXMODULES(hp) - HD_NMODULES(hp))
+ HD_MAXMODULES(hp) = HD_NMODULES(hp)
+ call realloc (hp, HD_LENHD(hp), TY_STRUCT)
+
+ call sfree (sp)
+ return (hp)
+end
+
+
+# HD_CLOSE -- Close the helpdir descriptor. The helpdir file has already
+# been closed; all we need do is return the string buffer and the helpdir
+# descriptor structure.
+
+procedure hd_close (hp)
+
+pointer hp
+
+begin
+ if (hp != NULL) {
+ call mfree (HD_SBUF(hp), TY_CHAR)
+ call mfree (hp, TY_STRUCT)
+ }
+end
+
+
+# HD_PUTLDIRY -- Decode a logical directory declaration and store it away
+# in the descriptor. We are passed the declaration minus the leading
+# dollar sign. Format: "variable = string".
+
+procedure hd_putldiry (hp, decl)
+
+pointer hp
+char decl[ARB]
+
+int ip, nldir, strp
+pointer sp, buf, op
+char hd_getc()
+int strncmp(), hd_putstr()
+errchk salloc, hd_getc, hd_putstr
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+
+ # Do nothing if null declaration.
+ for (ip=1; IS_WHITE(decl[ip]); ip=ip+1)
+ ;
+ if (decl[ip] == '\n' || decl[ip] == EOS || decl[ip] == '#') {
+ call sfree (sp)
+ return
+ }
+
+ # Extract "ldir=string", eliminating all whitespace, and deleting
+ # the newline at the end of the statement. Quotes around the string
+ # are optional and are deleted in hl_getc.
+
+ for (op=buf; hd_getc (decl, ip, Memc[op]) != EOS; op=op+1)
+ if (Memc[op] == '\n')
+ op = op - 1
+
+ # Deposit the "ldir=string" in the string buffer, and set the
+ # appropriate pointers for either defdir or a new ldir.
+
+ strp = hd_putstr (hp, Memc[buf])
+ if (strncmp (Memc[buf], "defdir", 6) == 0)
+ HD_DEFDIR(hp) = strp
+ else {
+ nldir = HD_NLDIRS(hp) + 1
+ if (nldir > MAX_LDIRS)
+ call error (8, "Too many ldir declarations in helpdir")
+ HD_NLDIRS(hp) = nldir
+ HD_LDIR(hp,nldir) = strp
+ }
+
+ call sfree (sp)
+end
+
+
+# HD_PUTMODULE -- Put a module declaration into the helpdir descriptor.
+# Start new entry; save module name; process file names. If line ends
+# in a comma, get a new line. Print warning if an unknown file type
+# keyword is encountered.
+
+procedure hd_putmodule (hp, fd, lbuf)
+
+pointer hp
+int fd
+char lbuf[ARB]
+
+char ch
+int ip, junk, m, ftype, strp
+pointer sp, buf, op, sbuf, mp
+
+bool streq()
+char hd_getc(), hd_peekc()
+int getline(), ctowrd(), hd_putstr()
+errchk salloc, getline, hd_putstr, hd_getc
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+ sbuf = HD_SBUF(hp)
+
+ # Fetch module name. Cannot be null or line is blank and we would
+ # not have been called.
+ ip = 1
+ junk = ctowrd (lbuf, ip, Memc[buf], SZ_LINE)
+
+ # Check if this is a redefinition of a module already defined.
+ # If so, overwrite descriptor of earlier module, else allocate
+ # a new descriptor.
+
+ for (m=1; m <= HD_NMODULES(hp); m=m+1) {
+ mp = HD_MODULE(hp,m)
+ if (streq (Memc[buf], Memc[sbuf+M_NAME(mp)]))
+ break
+ }
+
+ if (m > HD_NMODULES(hp)) {
+ # If we are out of space for modules, increase the descriptor
+ # structure size to allow more module descriptors.
+ if (m > HD_MAXMODULES(hp)) {
+ HD_LENHD(hp) = HD_LENHD(hp) + (INC_MODULES * LEN_MODSTRUCT)
+ call realloc (hp, HD_LENHD(hp), TY_STRUCT)
+ HD_MAXMODULES(hp) = HD_MAXMODULES(hp) + INC_MODULES
+ }
+ HD_NMODULES(hp) = m
+ }
+
+ mp = HD_MODULE(hp,m)
+ call aclri (Memi[mp], LEN_MODSTRUCT)
+
+ # Put module name in string buffer and save index of string in descr.
+ M_NAME(mp) = hd_putstr (hp, Memc[buf])
+
+ # Process file name fields, if any. Unrecognized file type keywords
+ # cause a warning to be issued. Redundant entires overwrite old
+ # entries. Order makes no diff, absence is ok.
+
+ op = buf
+ ftype = TY_UNKNOWN
+ strp = 0
+
+ repeat {
+ ch = hd_getc (lbuf, ip, ch)
+
+ switch (ch) {
+ case '=':
+ # Buffer contains the code word for the file being set.
+ Memc[op] = EOS
+ call strlwr (Memc[buf])
+ if ( streq (Memc[buf], "hlp"))
+ ftype = TY_HLP
+ else if (streq (Memc[buf], "sys"))
+ ftype = TY_SYS
+ else if (streq (Memc[buf], "src"))
+ ftype = TY_SRC
+ else if (streq (Memc[buf], "pkg"))
+ ftype = TY_PKG
+ else if (streq (Memc[buf], "men"))
+ ftype = TY_MEN
+ else {
+ ftype = TY_UNKNOWN
+ call eprintf ("Warning: bad file type `%s' in helpdir\n")
+ call pargstr (Memc[buf])
+ }
+ op = buf
+
+ case ',', '\n', EOS:
+ # Buffer contains the file name string. Put it in the string
+ # buffer and save pointer in appropriate field of module
+ # descriptor.
+
+ Memc[op] = EOS
+
+ # If filename is "..", i.e., "sys=..", the filename is identical
+ # to that last specified. Use the file name pointer.
+
+ if (streq (Memc[buf], "..")) {
+ if (strp == 0)
+ call error (9, "helpdir: `..' reference, no prev file")
+ } else
+ strp = hd_putstr (hp, Memc[buf])
+
+ switch (ftype) {
+ case TY_HLP:
+ M_HLP(mp) = strp
+ case TY_SYS:
+ M_SYS(mp) = strp
+ case TY_SRC:
+ M_SRC(mp) = strp
+ case TY_PKG:
+ M_PKG(mp) = strp
+ case TY_MEN:
+ M_MEN(mp) = strp
+ }
+ op = buf
+
+ if (ch == '\n' || ch == EOS)
+ break # end of statement
+ else {
+ # Check for continuation on next line. Read a new line into
+ # the buffer if end of line follows comma.
+
+ if (hd_peekc(lbuf,ip) == '\n' || hd_peekc(lbuf,ip) == EOS) {
+ if (getline (fd, lbuf) == EOF) {
+ call eprintf ("Unexpected EOF in helpdir file\n")
+ call sfree (sp)
+ return
+ }
+ ip = 1
+ }
+ }
+
+ default:
+ # Regular character. Deposit in buffer.
+ if (op >= buf+SZ_LINE)
+ call error (10, "helpdir: buffer overflow reading modspec")
+ Memc[op] = ch
+ op = op + 1
+ }
+ }
+
+ call sfree (sp)
+end
+
+
+# HD_GETC -- Get next nonwhite character from the input line. Leave pointer
+# pointing to next character. Ignore quotes, so that file name strings can
+# be quoted without penalty.
+
+char procedure hd_getc (lbuf, ip, ch)
+
+char lbuf[ARB]
+int ip
+char ch
+char hd_peekc()
+
+begin
+ ch = hd_peekc (lbuf, ip)
+ if (ch != EOS)
+ ip = ip + 1
+
+ return (ch)
+end
+
+
+# HD_PEEKC -- Peek at the next nonwhite character on a line, but do not
+# advance the input pointer past the character. Ignore quote characters
+# and comments.
+
+char procedure hd_peekc (lbuf, ip)
+
+char lbuf[ARB]
+int ip
+char ch
+
+begin
+ for (ch=lbuf[ip]; ch != EOS; ch=lbuf[ip])
+ if (IS_WHITE(ch) || ch == '\'' || ch == '"') {
+ ip = ip + 1
+ } else if (ch == '#') {
+ while (lbuf[ip] != '\n' && lbuf[ip] != EOS)
+ ip = ip + 1
+ } else
+ break
+
+ return (ch)
+end
+
+
+# HD_PUTSTR -- Put a string (incl EOS) in the string buffer at nextch.
+# If there is not enough space in the buffer, reallocate a larger buffer.
+# Return the index of the string in the string buffer.
+
+int procedure hd_putstr (hp, str)
+
+pointer hp
+char str[ARB]
+int nextch, nchars, strlen()
+errchk realloc
+
+begin
+ # Null strings are not stored and cause a null index to be returned.
+ nchars = strlen (str)
+ if (nchars == 0)
+ return (0)
+
+ nextch = HD_NEXTCH(hp)
+ if (nextch + nchars + 1 > HD_SZSBUF(hp)) {
+ HD_SZSBUF(hp) = HD_SZSBUF(hp) + INC_SZSBUF
+ call realloc (HD_SBUF(hp), HD_SZSBUF(hp), TY_CHAR)
+ }
+
+ call strcpy (str, Memc[HD_SBUF(hp) + nextch], ARB)
+ HD_NEXTCH(hp) = nextch + nchars + 1
+
+ return (nextch)
+end
+
+
+# HD_SORT_MODULES -- Sort the module list alphabetically by name.
+# A simple exchange sort is ok because the sort time is negligible
+# compared to all the file accesses, Lroff etc.
+
+procedure hd_sort_modules (hp)
+
+pointer hp
+
+bool sorted
+int nmodules, m, mlen, i, temp
+pointer sbuf, mp1, mp2
+bool strgt()
+
+begin
+ nmodules = HD_NMODULES(hp)
+ sbuf = HD_SBUF(hp)
+ mlen = LEN_MODSTRUCT
+ if (nmodules < 2)
+ return
+
+ repeat {
+ sorted = true
+ do m = 1, nmodules-1 {
+ mp1 = HD_MODULE(hp,m)
+ mp2 = mp1 + mlen
+ if (strgt (Memc[sbuf+M_NAME(mp1)], Memc[sbuf+M_NAME(mp2)])) {
+ do i = 0, mlen-1 {
+ temp = Memi[mp1+i]
+ Memi[mp1+i] = Memi[mp2+i]
+ Memi[mp2+i] = temp
+ }
+ sorted = false
+ }
+ }
+ } until (sorted)
+end
+
+
+# HD_FINDMOD -- Search for the named module and return the module number
+# if found. Abbreviations are permitted. An ambiguous abbreviation is
+# an error.
+
+int procedure hd_findmod (hp, modname)
+
+pointer hp
+char modname[ARB]
+int m, namelen, module
+pointer mp, sbuf
+int strlen(), strncmp()
+
+begin
+ namelen = strlen (modname)
+ if (namelen == 0)
+ return (0)
+ module = 0
+ sbuf = HD_SBUF(hp)
+
+ for (m=1; m <= HD_NMODULES(hp); m=m+1) {
+ mp = HD_MODULE(hp,m)
+
+ if (strncmp (Memc[sbuf+M_NAME(mp)], modname, namelen) == 0) {
+ if (strlen (Memc[sbuf+M_NAME(mp)]) == namelen) {
+ return (m) # exact match
+ } else if (module != 0) {
+ call eprintf ("\n--> %s <--\n")
+ call pargstr (modname)
+ call error (11, "Ambiguous module name abbreviation")
+ } else
+ module = m
+ }
+ }
+
+ return (module)
+end
+
+
+# HD_GETNAME -- Get the module name or a filename. If a filename is requested,
+# check if filename contains a logical directory reference. If yes, try to
+# satisfy the reference from the local list of ldirs (but no recursive refs
+# permitted here). If no, prepend the defdir string.
+
+define nullstr_ 91
+define nodefdir_ 92
+
+int procedure hd_getname (hp, m, field, outstr, maxch)
+
+pointer hp
+int m # module number
+int field # field code
+char outstr[ARB]
+int maxch
+
+int len_ldir, op
+pointer mp, sp, ldir, sbuf, fname_ptr, ip, subdir
+int strncmp(), gstrcpy(), hd_getldir(), fnldir()
+errchk salloc, hd_getldir
+
+begin
+ call smark (sp)
+ call salloc (ldir, SZ_PATHNAME, TY_CHAR)
+ call salloc (subdir, SZ_FNAME, TY_CHAR)
+
+ if (hp == NULL)
+ call error (12, "hd_getname: bad helpdir descriptor")
+
+ if (m < 1 || m > HD_NMODULES(hp)) {
+nullstr_ call sfree (sp)
+ outstr[1] = EOS
+ return (0)
+ }
+
+ mp = HD_MODULE(hp,m)
+ sbuf = HD_SBUF(hp)
+
+ switch (field) {
+ case TY_MODNAME:
+ call sfree (sp)
+ return (gstrcpy (Memc[sbuf+M_NAME(mp)], outstr, maxch))
+ case TY_HLP:
+ fname_ptr = M_HLP(mp)
+ case TY_SYS:
+ fname_ptr = M_SYS(mp)
+ case TY_SRC:
+ fname_ptr = M_SRC(mp)
+ case TY_PKG:
+ fname_ptr = M_PKG(mp)
+ case TY_MEN:
+ fname_ptr = M_MEN(mp)
+ default:
+ goto nullstr_
+ }
+
+ # If index is zero, no filename was given.
+ if (fname_ptr == 0)
+ goto nullstr_
+
+ # Get ldir substring, if any, from filename. If no ldir, prepend
+ # defdir and quit. Otherwise lookup ldir in local list. If found,
+ # prepend value. Otherwise the ldir is a CL global one, and return
+ # filename without modification. If the given ldir string begins
+ # with "./", substitute the value of defdir for the ".".
+
+ len_ldir = fnldir (Memc[sbuf+fname_ptr], Memc[ldir], SZ_PATHNAME)
+
+ if (len_ldir == 0) {
+ if (HD_DEFDIR(hp) == 0)
+ goto nodefdir_
+ for (ip = sbuf + HD_DEFDIR(hp); Memc[ip] != '='; ip=ip+1)
+ ;
+ op = gstrcpy (Memc[ip+1], outstr, maxch) + 1
+ ip = sbuf + fname_ptr
+ } else if (hd_getldir (hp, Memc[ldir], Memc[subdir], SZ_FNAME) == 0) {
+ op = 1
+ ip = sbuf + fname_ptr
+ } else {
+ if (strncmp (Memc[subdir], "./", 2) == 0) {
+ if (HD_DEFDIR(hp) == 0)
+nodefdir_ call error (13, "Default directory omitted in helpdir")
+ for (ip = sbuf + HD_DEFDIR(hp); Memc[ip] != '='; ip=ip+1)
+ ;
+ op = gstrcpy (Memc[ip+1], outstr, maxch) + 1
+ ip = subdir + 2
+ } else {
+ op = 1
+ ip = subdir
+ }
+ op = op + gstrcpy (Memc[ip], outstr[op], maxch - op + 1)
+ ip = sbuf + fname_ptr + len_ldir
+ }
+
+ call sfree (sp)
+ return (gstrcpy (Memc[ip], outstr[op], maxch - op + 1))
+end
+
+
+# HD_GETLDIR -- Search the logical directory list for the package helpdir
+# file for the given ldir name. Return value in output string if found.
+
+int procedure hd_getldir (hp, ldir, outstr, maxch)
+
+pointer hp
+char ldir[ARB]
+char outstr[ARB]
+int maxch
+
+int i
+pointer sp, ip, op, sbuf, envvar, filvar
+bool streq()
+int gstrcpy()
+
+begin
+ call smark (sp)
+ call salloc (envvar, SZ_FNAME, TY_CHAR)
+ call salloc (filvar, SZ_FNAME, TY_CHAR)
+
+ sbuf = HD_SBUF(hp)
+
+ # Ldir string has the form "ldir$". Extract the ldir name into the
+ # filvar buffer, omitting the $ delimiter.
+ i = 1
+ for (op=filvar; ldir[i] != '$' && ldir[i] != EOS; op=op+1) {
+ Memc[op] = ldir[i]
+ i = i + 1
+ }
+ Memc[op] = EOS
+
+ for (i=1; i <= HD_NLDIRS(hp); i=i+1) {
+ # Extract the helpdir env variable name into the envvar buffer,
+ # stopping when the '=' is reached.
+
+ ip = sbuf + HD_LDIR(hp,i)
+ for (op=envvar; Memc[ip] != '='; op=op+1) {
+ if (Memc[ip] == EOS)
+ call error (14, "helpdir: missing '=' in ldir declaration")
+ Memc[op] = Memc[ip]
+ ip = ip + 1
+ }
+ Memc[op] = EOS
+
+ # Return whatever follows the '=' if we have a match. The input
+ # pointer is left pointing at the '='.
+
+ if (streq (Memc[filvar], Memc[envvar])) {
+ call sfree (sp)
+ return (gstrcpy (Memc[ip+1], outstr, maxch))
+ }
+ }
+
+ outstr[1] = EOS
+ call sfree (sp)
+ return (0)
+end
+
+
+# HD_DEBUG -- Dump a compiled helpdir structure to the given output file.
+
+procedure hd_debug (hd, out)
+
+pointer hd #I compiled helpdir
+int out #O output file
+
+int i
+pointer sbuf, mp
+
+begin
+ sbuf = HD_SBUF(hd)
+
+ # General header stuff.
+ call fprintf (out,
+ "pakname=%d(%s), nmodules=%d, maxmodules=%d, lenhd=%d\n")
+ call pargi (HD_PAKNAME(hd))
+ call pargstr (Memc[sbuf+HD_PAKNAME(hd)])
+ call pargi (HD_NMODULES(hd))
+ call pargi (HD_MAXMODULES(hd))
+ call pargi (HD_LENHD(hd))
+ call fprintf (out, "defdir=%d(%s)\n")
+ call pargi (HD_DEFDIR(hd))
+ call pargstr (Memc[sbuf+HD_DEFDIR(hd)])
+ call fprintf (out, "sbuf=%x, szsbuf=%d, nextch=%d\n")
+ call pargi (HD_SBUF(hd))
+ call pargi (HD_SZSBUF(hd))
+ call pargi (HD_NEXTCH(hd))
+
+ # List of defined logical directories.
+ if (HD_NLDIRS(hd) > 0) {
+ call fprintf (out, "nldirs=%d:\n")
+ call pargi (HD_NLDIRS(hd))
+ do i = 1, HD_NLDIRS(hd) {
+ call fprintf (out, "%7d %s\n")
+ call pargi (i)
+ call pargstr (Memc[sbuf+HD_LDIR(hd,i)])
+ }
+ }
+
+ # List the modules.
+ if (HD_NMODULES(hd) > 0) {
+ call fprintf (out, "modules:\n")
+ do i = 1, HD_NMODULES(hd) {
+ mp = HD_MODULE(hd,i)
+ call fprintf (out, "%7d %20s\n")
+ call pargi (i)
+ call pargstr (Memc[sbuf+M_NAME(mp)])
+ if (M_HLP(mp) > 0) {
+ call fprintf (out, "\t\t\t\tHLP=%d(%s)\n")
+ call pargi (M_HLP(mp))
+ call pargstr (Memc[sbuf+M_HLP(mp)])
+ }
+ if (M_SYS(mp) > 0) {
+ call fprintf (out, "\t\t\t\tSYS=%d(%s)\n")
+ call pargi (M_SYS(mp))
+ call pargstr (Memc[sbuf+M_SYS(mp)])
+ }
+ if (M_SRC(mp) > 0) {
+ call fprintf (out, "\t\t\t\tSRC=%d(%s)\n")
+ call pargi (M_SRC(mp))
+ call pargstr (Memc[sbuf+M_SRC(mp)])
+ }
+ if (M_PKG(mp) > 0) {
+ call fprintf (out, "\t\t\t\tPKG=%d(%s)\n")
+ call pargi (M_PKG(mp))
+ call pargstr (Memc[sbuf+M_PKG(mp)])
+ }
+ if (M_MEN(mp) > 0) {
+ call fprintf (out, "\t\t\t\tMEN=%d(%s)\n")
+ call pargi (M_MEN(mp))
+ call pargstr (Memc[sbuf+M_MEN(mp)])
+ }
+ }
+ }
+end
diff --git a/pkg/system/help/hinput.x b/pkg/system/help/hinput.x
new file mode 100644
index 00000000..c47716e8
--- /dev/null
+++ b/pkg/system/help/hinput.x
@@ -0,0 +1,274 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include "help.h"
+
+.help hinput
+.nf __________________________________________________________________________
+HINPUT -- Lroff line input procedure. Called by Lroff to get lines of
+input text. Function varies slightly depending on the Help option.
+If printing only single param or single section, our job is to eat all
+input which is not part of the indicated section of the help block.
+A parameter block begins with ".ls paramname" and ends with a matching
+".le" or ".ih", if the text is formatted. Similarly, the single section
+begins with a ".ih" followed by the section name on the next line.
+.endhelp ______________________________________________________________________
+
+define SEARCHING 1
+define IN_BLOCK 2
+define MAXPAT 10
+
+
+# HINPUT -- Get next input line from the help block.
+
+int procedure hinput (ctrl, lbuf)
+
+pointer ctrl
+char lbuf[ARB]
+
+bool formatted
+int fd, level, status, ip
+int getline(), strmatch(), gstrcpy(), stridxs()
+int h_findparam(), h_findsection()
+errchk getline, h_findparam, h_findsection
+define findsec_ 91
+
+begin
+ fd = H_IN(ctrl)
+
+ # EOF flag is set after param block has been fully input,
+ # but normally before the actual end of file.
+
+ if (H_EOF(ctrl) == YES || H_QUIT(ctrl) == YES)
+ return (EOF)
+ else if (H_RAWIN(ctrl) == YES || H_FILTER_INPUT(ctrl) == NO)
+ return (getline (fd, lbuf))
+
+ # We get here only if special processing is required to
+ # filter out all but a section of the help text.
+
+ switch (H_STATE(ctrl)) {
+ case BOF:
+ # Determine whether or not the help block is formatted.
+ # Read in first line but save it for later and return a
+ # dummy line to Lroff, telling it whether or not the help
+ # block is formatted.
+
+ repeat {
+ if (getline (fd, lbuf) == EOF)
+ return (EOF)
+ for (ip=1; IS_WHITE(lbuf[ip]); ip=ip+1)
+ ;
+ } until (lbuf[ip] != '\n')
+ call ungetline (fd, lbuf)
+
+ if (lbuf[1] == '.') {
+ formatted = true
+ status = gstrcpy (".in 4\n", lbuf, SZ_LINE)
+ } else {
+ formatted = false
+ status = gstrcpy (".nf\n", lbuf, SZ_LINE)
+ }
+ H_STATE(ctrl) = SEARCHING
+
+ case SEARCHING:
+ status = getline (fd, lbuf)
+ if (H_PARNAME(ctrl) != EOS) {
+ status = h_findparam (fd, lbuf, formatted, H_PARNAME(ctrl))
+ level = 1
+ } else if (H_SECNAME(ctrl) != EOS)
+findsec_ status = h_findsection (fd, lbuf, formatted, H_SECNAME(ctrl))
+ H_STATE(ctrl) = IN_BLOCK
+
+ case IN_BLOCK:
+ # By the time we get here we are in the parameter or single
+ # section.
+ status = getline (fd, lbuf)
+
+ if (lbuf[1] == '.') {
+ if (strmatch (lbuf, "^.{ih}") > 0) {
+ if (stridxs ("|", H_SECNAME(ctrl)) > 0)
+ goto findsec_
+ status = EOF
+ } else if (H_PARNAME(ctrl) != EOS) {
+ if (strmatch (lbuf, "^.{ls}") > 0)
+ level = level + 1
+ else if (strmatch (lbuf, "^.{le}") > 0) {
+ level = level - 1
+ if (level == 0)
+ status = EOF
+ }
+ }
+ }
+
+ default:
+ call error (15, "hinput: unknown input state encountered")
+ }
+
+ return (status)
+end
+
+
+# H_FINDPARAM -- If text contains format directives, eat input lines until
+# a ".ls" directive is found which contains the param name as a substring.
+# If the text is not formatted, search for a line beginning with the pattern.
+# We are called with the first line of the file in lbuf.
+
+int procedure h_findparam (fd, lbuf, formatted, param)
+
+int fd
+char lbuf
+bool formatted
+char param[ARB]
+
+bool match_found
+pointer sp, pattern
+int getline(), strmatch(), strlen()
+errchk getline
+
+begin
+ call smark (sp)
+ call salloc (pattern, SZ_FNAME, TY_CHAR)
+
+ match_found = false
+
+ if (formatted) {
+ call sprintf (Memc[pattern], SZ_FNAME, "{%s}")
+ call pargstr (param)
+ repeat {
+ if (strmatch (lbuf, "^.{ls}") > 0)
+ if (strmatch (lbuf, Memc[pattern]) > 0) {
+ match_found = true
+ break
+ }
+ } until (getline (fd, lbuf) == EOF)
+
+ } else {
+ call sprintf (Memc[pattern], SZ_FNAME, "^#{%s}")
+ call pargstr (param)
+ repeat {
+ if (strmatch (lbuf, Memc[pattern]) > 0) {
+ match_found = true
+ break
+ }
+ } until (getline (fd, lbuf) == EOF)
+ }
+
+ call sfree (sp)
+ if (match_found)
+ return (strlen (lbuf))
+ else
+ return (EOF)
+end
+
+
+# H_FINDSECTION -- If text contains format directives, eat input lines until
+# a ".ih" directive is found for the named section. If the text is not
+# formatted, search for a line beginning with the section name.
+# We are called with the first line of the file in lbuf.
+
+int procedure h_findsection (fd, lbuf, formatted, sections)
+
+int fd # input file
+char lbuf # line buffer
+bool formatted # is help block formatted
+char sections[ARB] # list of sections "a|b|c"
+
+bool match_found
+int npat, ip
+pointer sp, patbuf, patoff[MAXPAT], op
+bool h_match()
+int getline(), strmatch(), gstrcpy()
+errchk getline
+
+begin
+ call smark (sp)
+ call salloc (patbuf, SZ_LINE, TY_CHAR)
+
+ # Process the list of sections into patbuf and patoff, i.e., into a
+ # list of EOS delimited strings in the string buffer patbuf. Each
+ # section name or abbreviation is delimited by '|' (or).
+
+ npat = 1
+ op = patbuf
+ patoff[1] = op
+
+ for (ip=1; sections[ip] != EOS; ip=ip+1)
+ switch (sections[ip]) {
+ case '|':
+ Memc[op] = EOS
+ op = op + 1
+ npat = min (MAXPAT, npat + 1)
+ patoff[npat] = op
+ default:
+ Memc[op] = sections[ip]
+ op = op + 1
+ }
+ Memc[op] = EOS
+
+ match_found = false
+
+ if (formatted) {
+ repeat {
+ if (strmatch (lbuf, "^.{ih}") > 0)
+ if (getline (fd, lbuf) != EOF) {
+ match_found = h_match (lbuf, patoff, npat)
+ if (match_found)
+ break
+ }
+ } until (getline (fd, lbuf) == EOF)
+
+ } else {
+ repeat {
+ match_found = h_match (lbuf, patoff, npat)
+ if (match_found)
+ break
+ } until (getline (fd, lbuf) == EOF)
+ }
+
+
+ # If only one section is to be printed, skip the section name, otherwise
+ # pass the .ih secname on to the text formatter.
+
+ call sfree (sp)
+ if (match_found) {
+ if (npat == 1)
+ return (getline (fd, lbuf))
+ else {
+ call ungetline (fd, lbuf)
+ return (gstrcpy (".ih\n", lbuf, SZ_LINE))
+ }
+ } else
+ return (EOF)
+end
+
+
+# H_MATCH -- Match a set of patterns against a line of test, matching only
+# at the beginning of line in either case.
+
+bool procedure h_match (lbuf, patoff, npat)
+
+char lbuf[ARB] # line of text
+pointer patoff[npat] # pointers to pattern strings
+int npat # number of patterns
+
+int pat
+pointer sp, pattern
+int strmatch()
+
+begin
+ call smark (sp)
+ call salloc (pattern, SZ_FNAME, TY_CHAR)
+
+ for (pat=1; pat <= npat; pat=pat+1) {
+ call sprintf (Memc[pattern], SZ_FNAME, "^{%s}")
+ call pargstr (Memc[patoff[pat]])
+ if (strmatch (lbuf, Memc[pattern]) > 0) {
+ call sfree (sp)
+ return (true)
+ }
+ }
+
+ call sfree (sp)
+ return (false)
+end
diff --git a/pkg/system/help/houtput.x b/pkg/system/help/houtput.x
new file mode 100644
index 00000000..499e4292
--- /dev/null
+++ b/pkg/system/help/houtput.x
@@ -0,0 +1,147 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ttyset.h>
+include <chars.h>
+include <fset.h>
+include "help.h"
+
+define HELP "[q=quit,d=downhalf,f|sp=downfull,j|cr=downline,N=next]"
+define QUIT 'q'
+define FWD_SCREEN 'f'
+define SCROLL_DOWN 'd'
+define NEXT_LINE 'j'
+define NEXT_FILE 'N'
+define NEXT_FILE_ALT 'n'
+define REDRAW '\014'
+
+
+# HOUTPUT -- The help line output procedure. Count output lines and paginate
+# output if enabled. If manpage format is desired pass output lines to manpage
+# filter.
+
+procedure houtput (ctrl, lbuf)
+
+pointer ctrl
+char lbuf[ARB]
+bool formfeed, query_enabled
+int map_cc, maxlines, nlines, ip, cmd
+int envgeti(), ho_getcmd()
+data map_cc /YES/
+
+begin
+ if (H_RAWOUT(ctrl) == YES) {
+ call putline (H_OUT(ctrl), lbuf)
+ return
+ } else if (H_MANPAGE(ctrl) == YES) {
+ call man_output (H_OUT(ctrl), lbuf, H_NLPP(ctrl),
+ H_LMARGIN(ctrl), H_RMARGIN(ctrl))
+ return
+ } else if (H_EOF(ctrl) == YES)
+ return
+
+ # Check for end of page (either full or formfeed in line)
+ # before processing the output line, because we want to
+ # pause to let the user read the screen before paging.
+
+ ip = 1
+ formfeed = (lbuf[1] == '\f')
+ if (formfeed)
+ ip = 2
+
+ iferr (maxlines = envgeti ("ttynlines") - 1)
+ maxlines = 24
+
+ # Help blocks and files are preceded by a form feed and a header.
+ # The "more" query is issued between blocks and files to give the
+ # user a chance to read the previous page before the screen is cleared.
+ # The query is disabled for the first block or file by initialization
+ # of nlines to -1 in the main help routine.
+
+ query_enabled = (H_NLINES(ctrl) > 0)
+ nlines = max (0, H_NLINES(ctrl))
+
+ if (H_PAGINATE(ctrl) == YES) {
+ if (formfeed || nlines >= maxlines) {
+ if (query_enabled) {
+ # Pause to give the user a chance to read the output, and
+ # to indicate whether they wish to continue.
+
+ repeat {
+ cmd = ho_getcmd (H_TTY(ctrl))
+
+ switch (cmd) {
+ case FWD_SCREEN, BLANK, REDRAW:
+ nlines = 0
+ case SCROLL_DOWN:
+ nlines = (maxlines + 1) / 2
+ case NEXT_LINE, CR, LF:
+ nlines = maxlines - 1
+ case NEXT_FILE, NEXT_FILE_ALT:
+ H_EOF(ctrl) = YES
+ nlines = 0
+ case QUIT:
+ H_QUIT(ctrl) = YES
+ H_EOF(ctrl) = YES
+ default:
+ call eprintf ("\07")
+ call flush (STDERR)
+ cmd = ERR
+ }
+ } until (cmd > 0)
+ }
+
+ if (formfeed && H_QUIT(ctrl) == NO) {
+ call ttyclear (H_OUT(ctrl), H_TTY(ctrl))
+ nlines = 0
+ }
+ }
+ }
+
+ # Do not output the line if the user just said to quit.
+ if (H_EOF(ctrl) == NO)
+ if (lbuf[ip] != EOS) {
+ call ttyputline (H_OUT(ctrl), H_TTY(ctrl), lbuf[ip], map_cc)
+ nlines = nlines + 1
+ }
+
+ H_NLINES(ctrl) = nlines
+end
+
+
+# HO_GETCMD -- Query the user for a single character command keystroke.
+
+int procedure ho_getcmd (tty)
+
+pointer tty # tty descriptor
+
+int key
+char strval[1]
+int clgkey()
+
+begin
+ # Ensure synchronization with the standard output.
+ call flush (STDOUT)
+
+ # Print query in standout mode.
+ call ttyso (STDERR, tty, YES)
+ call eprintf (HELP)
+ call ttyso (STDERR, tty, NO)
+ call flush (STDERR)
+
+ call fseti (STDIN, F_SETREDRAW, REDRAW)
+
+ # Read the command keystroke in raw mode.
+ if (clgkey ("cl.ukey", key, strval, 1) == EOF)
+ key = QUIT
+ else if (key == INTCHAR)
+ key = QUIT
+
+ call fseti (STDIN, F_SETREDRAW, 0)
+
+ # Erase the prompt and return.
+ call eprintf ("\r")
+ call ttyclearln (STDERR, tty)
+ call flush (STDERR)
+
+ return (key)
+end
diff --git a/pkg/system/help/lroff/breakline.o b/pkg/system/help/lroff/breakline.o
new file mode 100644
index 00000000..d0dceee2
--- /dev/null
+++ b/pkg/system/help/lroff/breakline.o
Binary files differ
diff --git a/pkg/system/help/lroff/breakline.x b/pkg/system/help/lroff/breakline.x
new file mode 100644
index 00000000..2be9f5a1
--- /dev/null
+++ b/pkg/system/help/lroff/breakline.x
@@ -0,0 +1,99 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include "lroff.h"
+
+define LEFT 1
+define RIGHT 2
+
+# BREAKLINE -- Break the current output line and output with or without
+# justification. The "current output line" is the set of NWORDS words
+# pointed to by the WORDS array of word pointers. Copy the NWORDS words
+# into the output buffer; do nothing if the word buffer is empty. If the
+# OUTPUT buffer is not empty, append a newline, causing the buffer to be
+# flushed. Breakline is called by textout() when enough words have been
+# collected to fill an output line, or whenever it is desired to flush
+# the output buffer. If both the word buffer and the output buffer are
+# empty, breakline is essentially a nop.
+
+procedure breakline (out, justify_flag)
+
+extern out()
+int justify_flag
+
+int w, i, end_to_fill_from, next_output_column
+int nholes, nfill, n_per_hole, nextra, hole1, hole2
+errchk outstr, outc
+include "lroff.com"
+include "words.com"
+
+begin
+ if (wbuf == NULL || words == NULL)
+ call error (1, "No Lroff word buffer allocated")
+
+ # First we flush the word buffer.
+ if (nwords > 0) {
+ # Strip any trailing whitespace from the line.
+ for (wp=wp-2; Memc[wp] == BLANK && wp > wbuf; wp=wp-1)
+ wcols = wcols - 1
+ wp = wp + 1
+ Memc[wp] = EOS
+ wp = wp + 1
+
+ # If justification is disabled or if there is only one word on
+ # the line, do not add spaces to right justify.
+
+ if (justify_flag == NJ || justify == NO || nwords <= 1) {
+ for (w=1; w <= nwords; w=w+1)
+ call outstr (out, Memc[Memi[words+w-1]])
+
+ } else {
+ # To justify the line, determine the number of extra spaces
+ # needed to right justify the last character on the line.
+ # Determine the number of holes between words, and how many
+ # spaces to add to each.
+
+ nholes = nwords - 1
+ nfill = max (0, right_margin - left_margin + 1 - wcols)
+ n_per_hole = nfill / nholes
+ nextra = nfill - (n_per_hole * nholes)
+
+ # Determine where the extra spaces need to be added. Add
+ # extra spaces from the left and then the right on succesive
+ # lines.
+ if (end_to_fill_from == LEFT) {
+ hole1 = 1
+ hole2 = nextra
+ end_to_fill_from = RIGHT
+ } else {
+ hole1 = nwords - nextra
+ hole2 = nholes
+ end_to_fill_from = LEFT
+ }
+
+ # Fill the output line. Move the word and then add the
+ # requisite number of blanks per hole, plus an extra if in
+ # the range hole1 to hole2 (at left or right).
+
+ do w = 1, nwords {
+ call outstr (out, Memc[Memi[words+w-1]])
+ do i = 1, n_per_hole
+ call outc (out, BLANK)
+ if (w >= hole1 && w <= hole2)
+ call outc (out, BLANK)
+ }
+ }
+ }
+
+
+ # If there is anything in the output buffer, append a newline, flushing
+ # the buffer.
+
+ call getoutcol (next_output_column)
+ if (next_output_column > left_margin)
+ call outc (out, '\n')
+
+ wp = wbuf # clear the word buffer
+ nwords = 0
+ wcols = 0
+end
diff --git a/pkg/system/help/lroff/center.o b/pkg/system/help/lroff/center.o
new file mode 100644
index 00000000..6e3442d3
--- /dev/null
+++ b/pkg/system/help/lroff/center.o
Binary files differ
diff --git a/pkg/system/help/lroff/center.x b/pkg/system/help/lroff/center.x
new file mode 100644
index 00000000..b3581f3a
--- /dev/null
+++ b/pkg/system/help/lroff/center.x
@@ -0,0 +1,32 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include "lroff.h"
+
+# CENTER_TEXT -- Center and output the next input line within the current
+# left and right margins. The optional argument specifies the column
+# (measured from the left margin) at which the text is to be centered.
+
+procedure center_text (in, out, linebuf, ip)
+
+extern in(), out()
+char linebuf[ARB]
+int ip
+
+int len_inputline, center_column, nblanks, i
+int in(), input(), lgetarg()
+errchk breakline, input, outc, outline
+include "lroff.com"
+
+begin
+ call breakline (out, NJ)
+ center_column = lgetarg (linebuf, ip, (left_margin + right_margin) / 2)
+ len_inputline = input (in, linebuf) - 1
+
+ if (len_inputline != EOF) {
+ nblanks = center_column - (len_inputline / 2) - left_margin
+ for (i=1; i <= nblanks; i=i+1)
+ call outc (out, BLANK)
+ call outline (out, linebuf)
+ }
+end
diff --git a/pkg/system/help/lroff/dols.o b/pkg/system/help/lroff/dols.o
new file mode 100644
index 00000000..55b5fbcd
--- /dev/null
+++ b/pkg/system/help/lroff/dols.o
Binary files differ
diff --git a/pkg/system/help/lroff/dols.x b/pkg/system/help/lroff/dols.x
new file mode 100644
index 00000000..26ba165b
--- /dev/null
+++ b/pkg/system/help/lroff/dols.x
@@ -0,0 +1,108 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include <error.h>
+include "lroff.h"
+
+# DO_LS -- Depending on the action, push an LS block (print label and indent
+# one level), or pop an LS block (restore the previous indent level). INIT_LS
+# clears the LS stack. Called with the LS command line in "lbuf", minus
+# the ".ls". The command line may consist of an argument specifying the number
+# of spaces to indent, the label string, both, or neither.
+# If the label string is shorter than the amount by which the block is indented,
+# the text block will begin on the same line as the label, otherwise the line
+# is broken and the text block begins on the following line.
+
+procedure do_LS (out, lbuf, action, last_command)
+
+extern out()
+char lbuf[ARB] # ".ls [arg] [text]"
+int action # LS or LE
+int last_command
+
+int indent[MAX_NLS]
+int n, ip, next_output_column
+int lgetarg(), strlen()
+errchk skiplines, outstr, outc, breakline
+include "lroff.com"
+
+begin
+ switch (action) {
+ case LS:
+ # We normally skip a line when beginning an LS block. If two or
+ # more LS directives are given in a row, however, only skip a
+ # single line.
+
+ call breakline (out, NJ)
+ if (last_command != LS)
+ call skiplines (out, 1)
+ call testpage (out, 3)
+
+ # Push new LS block on stack.
+ nls = nls + 1
+ if (nls > MAX_NLS) {
+ iferr (call error (1, "LS blocks nested too deep"))
+ call erract (EA_WARN)
+ nls = MAX_NLS
+ }
+
+ # Get number of spaces to indent, if given. If arg is negative,
+ # do not remember the argument, otherwise make it the new default.
+ ip = 1
+ n = lgetarg (lbuf, ip, ls_indent)
+ if (n < 0)
+ indent[nls] = -n
+ else {
+ ls_indent = n
+ indent[nls] = ls_indent
+ }
+
+ # Copy the label, if any, into the output buffer. We must do this
+ # before we change the left margin since the label is not indented.
+
+ call outstr (out, lbuf[ip])
+
+ # Try to adjust the left margin by the indicated amount. Save the
+ # actual indentation level for restoration by LE.
+
+ indent[nls] = max (perm_left_margin, min (right_margin,
+ left_margin + indent[nls])) - left_margin
+ left_margin = left_margin + indent[nls]
+
+ # If the length of the label string plus one blank does not leave
+ # space to start the first line of the text block on the same line,
+ # we must break the line and start the block on the next line.
+ # Otherwise, output spaces until the new left margin is reached.
+
+ if (strlen (lbuf[ip]) >= indent[nls])
+ call outc (out, '\n')
+ else {
+ call getoutcol (next_output_column)
+ while (next_output_column < left_margin) {
+ call outc (out, BLANK)
+ call getoutcol (next_output_column)
+ }
+ }
+
+ case LE: # end LS block
+ call breakline (out, NJ)
+ if (nls >= 1) {
+ left_margin = left_margin - indent[nls]
+ nls = nls - 1
+ }
+
+ default:
+ call error (1, "do_LS")
+ }
+end
+
+
+# INIT_LS -- Set or clear any LS indentation.
+
+procedure init_ls()
+
+include "lroff.com"
+
+begin
+ nls = 0
+end
diff --git a/pkg/system/help/lroff/getarg.o b/pkg/system/help/lroff/getarg.o
new file mode 100644
index 00000000..fcfc8fd9
--- /dev/null
+++ b/pkg/system/help/lroff/getarg.o
Binary files differ
diff --git a/pkg/system/help/lroff/getarg.x b/pkg/system/help/lroff/getarg.x
new file mode 100644
index 00000000..b85c5462
--- /dev/null
+++ b/pkg/system/help/lroff/getarg.x
@@ -0,0 +1,35 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include "lroff.h"
+
+.help lgetarg
+.nf _________________________________________________________________________
+LGETARG -- Get an integer argument to a directive. If no argument is found,
+return the default value. We are called with IP pointing to the start of
+the argument field to be searched. Leave IP pointing to the next argument
+field.
+.endhelp ____________________________________________________________________
+
+int procedure lgetarg (input_line, ip, default_value)
+
+char input_line[ARB]
+int ip, default_value
+int argument
+int ctoi()
+
+begin
+ if (ctoi (input_line, ip, argument) == 0)
+ argument = default_value
+
+ # Eat comma argument delimiter, if multiple arguments. Also eat
+ # trailing whitespace, in case a string argument follows.
+ while (input_line[ip] == BLANK)
+ ip = ip + 1
+ if (input_line[ip] == ',')
+ ip = ip + 1
+ while (input_line[ip] == BLANK)
+ ip = ip + 1
+
+ return (argument)
+end
diff --git a/pkg/system/help/lroff/indent.o b/pkg/system/help/lroff/indent.o
new file mode 100644
index 00000000..b2f75a10
--- /dev/null
+++ b/pkg/system/help/lroff/indent.o
Binary files differ
diff --git a/pkg/system/help/lroff/indent.x b/pkg/system/help/lroff/indent.x
new file mode 100644
index 00000000..6857e315
--- /dev/null
+++ b/pkg/system/help/lroff/indent.x
@@ -0,0 +1,17 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "lroff.h"
+
+# INDENT_LEFT_MARGIN -- Execute a relative indent of the left margin.
+
+procedure indent_left_margin (in, out, number_of_spaces)
+
+extern in(), out()
+int in(), number_of_spaces
+include "lroff.com"
+
+begin
+ call breakline (out, NJ)
+ left_margin = max (perm_left_margin, min (right_margin,
+ left_margin + number_of_spaces))
+end
diff --git a/pkg/system/help/lroff/input.o b/pkg/system/help/lroff/input.o
new file mode 100644
index 00000000..80ef4865
--- /dev/null
+++ b/pkg/system/help/lroff/input.o
Binary files differ
diff --git a/pkg/system/help/lroff/input.x b/pkg/system/help/lroff/input.x
new file mode 100644
index 00000000..908bd81d
--- /dev/null
+++ b/pkg/system/help/lroff/input.x
@@ -0,0 +1,123 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include <chars.h>
+include "lroff.h"
+
+.help input
+.nf ___________________________________________________________________________
+INPUT -- Read a line of text into the user supplied input buffer. Convert
+any tabs therein to spaces to simplify further processing. If generation
+of standout mode control chars is enabled, map "\f[BIR]" sequences into the
+appropriate control chars (defined in <chars.h>), otherwise delete any such
+sequences found (these control chars are later mapped by HELP, PAGE, LPRINT
+etc. into whatever sequence the actual output device requires). Return the
+number of PRINTABLE chars in the input line. Control characters are not
+counted, but are copied to the output line. The trailing newline is stripped;
+Lroff deals mainly with words, not lines. Only printable characters are made
+to "stand out", i.e., standout mode is always turned off between words and at
+the end of a line.
+.endhelp ______________________________________________________________________
+
+int procedure input (in, userbuf)
+
+extern in()
+char userbuf[ARB]
+
+bool standout_mode_in_effect
+char ch
+int len_inputline, ocol
+pointer sp, lbuf, ip, op
+int stridx(), in()
+errchk salloc, in
+include "lroff.com"
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_IBUF, TY_CHAR)
+
+ # Get input line and deal with any tab characters therein.
+ if (in (in_magic_arg, Memc[lbuf]) == EOF) {
+ call sfree (sp)
+ return (EOF)
+ }
+
+ standout_mode_in_effect = false
+ len_inputline = 0
+ ip = lbuf
+ op = 1
+ ocol = 0
+
+ # Process the input buffer, converting any "\f?" font escape sequences
+ # found. Terminate when newline is reached. Delete the newline.
+ # Expand all tabs.
+
+ for (ch=Memc[ip]; ch != '\n' && ch != EOS; ch=Memc[ip]) {
+ if (ch == '\\')
+ if (Memc[ip+1] == 'f' && stridx (Memc[ip+2], "BIR") > 0) {
+ # Turn standout mode on or off. Can only be turned on
+ # if "soflag" is YES.
+ switch (Memc[ip+2]) {
+ case 'B', 'I': # bold, italic
+ if (soflag == YES)
+ standout_mode_enabled = true
+ case 'R': # roman
+ if (standout_mode_in_effect) {
+ userbuf[op] = SO_OFF
+ op = op + 1
+ standout_mode_in_effect = false
+ }
+ standout_mode_enabled = false
+ }
+ ip = ip + 3 # \f? = 3
+ next
+ }
+
+ # Only make alphanumeric chars "stand out".
+
+ if (IS_ALNUM(ch)) {
+ len_inputline = len_inputline + 1
+ ocol = ocol + 1
+ if (standout_mode_enabled && !standout_mode_in_effect) {
+ userbuf[op] = SO_ON
+ op = op + 1
+ standout_mode_in_effect = true
+ }
+
+ } else if (ch == '\t') {
+ repeat {
+ userbuf[op] = ' '
+ op = op + 1
+ ocol = ocol + 1
+ len_inputline = len_inputline + 1
+ } until (ocol > 1 && mod (ocol, TABSIZE) == 0)
+ ip = ip + 1
+ next
+
+ } else {
+ if (IS_PRINT(ch)) {
+ len_inputline = len_inputline + 1
+ ocol = ocol + 1
+ }
+ if (standout_mode_in_effect) {
+ userbuf[op] = SO_OFF
+ op = op + 1
+ standout_mode_in_effect = false
+ }
+ }
+
+ userbuf[op] = ch
+ op = op + 1
+ ip = ip + 1
+ }
+
+ if (standout_mode_in_effect) {
+ userbuf[op] = SO_OFF
+ op = op + 1
+ standout_mode_in_effect = false
+ }
+ userbuf[op] = EOS
+
+ call sfree (sp)
+ return (len_inputline)
+end
diff --git a/pkg/system/help/lroff/justify.o b/pkg/system/help/lroff/justify.o
new file mode 100644
index 00000000..db814dfb
--- /dev/null
+++ b/pkg/system/help/lroff/justify.o
Binary files differ
diff --git a/pkg/system/help/lroff/justify.x b/pkg/system/help/lroff/justify.x
new file mode 100644
index 00000000..8085ca6b
--- /dev/null
+++ b/pkg/system/help/lroff/justify.x
@@ -0,0 +1,63 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include "lroff.h"
+
+# RIGHT_JUSTIFY -- Right justify the text string argument in LINEBUF on the
+# next input line, and write to the output.
+
+procedure right_justify (in, out, linebuf, ip)
+
+extern in(), out()
+char linebuf[ARB]
+int ip
+pointer sp, rjbuf
+int in(), input()
+errchk salloc, breakline, input, rjline
+include "lroff.com"
+
+begin
+ call smark (sp)
+ call salloc (rjbuf, SZ_IBUF, TY_CHAR)
+
+ call breakline (out, NJ)
+ if (input (in, Memc[rjbuf]) != EOF)
+ call rjline (out, Memc[rjbuf], linebuf[ip])
+
+ call sfree (sp)
+end
+
+
+
+# RJLINE -- Right justify a text string on an unfilled input line and
+# send it out.
+
+procedure rjline (out, input_line, rjtext)
+
+extern out()
+char input_line[ARB] # unfilled input line
+char rjtext[ARB] # string to be right justified on same line
+
+int i, nblanks, len_rjtext, next_output_column
+int textlen()
+errchk outstr, outc, outline
+include "lroff.com"
+
+begin
+ # Breakline should already have been called by the time we get here.
+ # Output the input line at the left margin without filling.
+
+ call outstr (out, input_line)
+
+ # Determine the (printable) length of the rjtext string, and space
+ # over so that it comes out right justified. Always output at least
+ # one space. Exceed the right margin if necessary.
+
+ call getoutcol (next_output_column)
+ len_rjtext = textlen (rjtext)
+ nblanks = max (1, right_margin - (next_output_column + len_rjtext) + 1)
+ do i = 1, nblanks
+ call outc (out, BLANK)
+
+ call outline (out, rjtext)
+end
diff --git a/pkg/system/help/lroff/lroff.com b/pkg/system/help/lroff/lroff.com
new file mode 100644
index 00000000..1e64173c
--- /dev/null
+++ b/pkg/system/help/lroff/lroff.com
@@ -0,0 +1,24 @@
+# Common for the Lroff text formatter.
+
+int right_margin # working margins
+int left_margin
+int perm_right_margin # permanent margins
+int perm_left_margin
+int in_magic_arg # magic args for in/out procedures
+int out_magic_arg
+int soflag # if YES, output standout mode chars
+int foflag # if YES, output forms mode chars
+int justify # right justify text
+int nls # .LS nesting level
+int ls_indent # .LS, def number of spaces to indent
+int sh_nskip # .SH, def nlines to skip
+int ih_nskip # .IH, def nlines to skip
+int ih_indent # .IH, def nspaces to indent
+int nh_nskip # .NH, def nlines to skip
+int nh_level[MAX_NHLEVEL] # .NH, section level numbers
+bool standout_mode_enabled # see input()
+
+common /lrfcom/ right_margin, left_margin, perm_right_margin,
+ perm_left_margin, in_magic_arg, out_magic_arg, soflag,
+ foflag, justify, nls, ls_indent, sh_nskip, ih_nskip, ih_indent,
+ nh_nskip, nh_level, standout_mode_enabled
diff --git a/pkg/system/help/lroff/lroff.h b/pkg/system/help/lroff/lroff.h
new file mode 100644
index 00000000..5111fcd0
--- /dev/null
+++ b/pkg/system/help/lroff/lroff.h
@@ -0,0 +1,41 @@
+# Input buffer must allow space for tab expansion and standout mode control
+# characters. Word and output buffer dimensions depend on margins.
+
+define SZ_IBUF (2*SZ_LINE)
+define MAX_NLS 20 # nesting level for LS
+define MAX_NHLEVEL 10 # max level for numbered sections
+
+# Default formatter parameters.
+define DEF_IHINDENT 4 # .ih indent level
+define DEF_LSINDENT 4 # .ls indent level
+define DEF_IHNSKIP 2 # .ih number of lines to skip
+define DEF_NHNSKIP 2 # .nh number of lines to skip
+define DEF_SHNSKIP 2 # .sh number of lines to skip
+define DEF_TPNLINES 2 # .tp nlines left on page
+
+define TABSIZE 8
+define INVISIBLE ($1 < BLANK)
+
+# Lroff Directive Opcodes.
+define FI 1 # enter fill mode
+define NF 2 # leave fill mode (nofill)
+define JU 3 # enter line justification mode
+define NJ 4 # leave line justification mode
+define RJ 5 # right justify text on nf,nj line
+define SH 6 # section heading
+define IH 7 # indented section heading
+define NH 8 # numbered section heading
+define BR 9 # break line
+define CE 10 # center next line
+define SP 11 # break, space N spaces on output
+define IN 12 # indent +/- N spaces
+define LS 13 # begin labelled section
+define LE 14 # end labelled section
+define BP 15 # break page
+define TP 16 # test space left on page
+define KS 17 # start floating keep
+define KE 18 # end floating keep
+define HR 19 # HTML href tag
+define HN 20 # HTML name tag
+define ENDHELP 21 # end of help block
+define HELP 22 # start of help block
diff --git a/pkg/system/help/lroff/lroff.hlp b/pkg/system/help/lroff/lroff.hlp
new file mode 100644
index 00000000..6607977b
--- /dev/null
+++ b/pkg/system/help/lroff/lroff.hlp
@@ -0,0 +1,258 @@
+.help lroff Nov83 "Online Help Utilities"
+.ih
+NAME
+\fBlroff\fR -- line oriented text formatter
+.ih
+PURPOSE
+\fBLroff\fR is a simple text formatter used by the IRAF on-line Help command,
+and other utilities (MANPAGE, LIST), to format text.
+\fBLroff\fR style documentation text may be embedded in program source files.
+\fBlroff\fR is line oriented, rather than page oriented,
+and is implemented as a library procedure rather than as a task.
+.ih
+USAGE
+status = lroff (input, output, left_margin, right_margin)
+.ih
+PARAMETERS
+.ls input
+An integer procedure, called by \fBlroff\fR to get lines of input,
+which takes the \fBlroff\fR input buffer as an argument,
+and which returns EOF upon End of File (like GETLINE).
+Each line of input must be terminated by a newline and an EOS
+(End Of String marker).
+.le
+.ls output
+A procedure, called by \fBlroff\fR to output formatted lines of text,
+which takes the \fBlroff\fR output buffer as an argument ("output (buffer)").
+.le
+.ls left_margin
+The first column to be filled (>= 1).
+.le
+.ls right_margin
+The last column to be filled.
+.le
+.ls status
+ERR is returned if meaningless margins are specified, or if an unrecoverable
+error occurs during processing.
+.le
+.ih
+DESCRIPTION
+\fBLroff\fR input may be bracketed by ".help" and ".endhelp" directives in
+the actual source file of the program being documented (if intended as input
+to the \fBhelp\fR utility), or may be in a separate file.
+The input text consists
+of a mixture of lines of text and \fBlroff\fR directives.
+\fBLroff\fR recognizes only a few directives,
+summarized in the "Request Summary" below. Whenever a directive
+performs the same function as a UNIX TROFF directive, the name is the same.
+Unrecognized directives are ignored, and are not passed on to the output.
+Directives must be left justified and preceeded by a period.
+
+Help text need not be formatted unless desired. Filling and justification
+are NOT ENABLED unless a legal directive (other than ".nf") is given on the
+line immediately following the ".help" directive.
+
+While filling, embedded whitespace in text IS significant to \fBlroff\fR,
+except at the end of a line.
+\fBlroff\fR recognizes no special characters.
+Blank lines cause a break, and are passed on to the output (a blank line
+is equivalent to ".sp").
+Case is not significant in command directives.
+Control characters embedded in text will be passed on to the output.
+
+Since both whitespace and blank lines are significant, \fBlroff\fR will properly
+format ordinary paragraphs of text, and single line section headers,
+without need for embedded directives.
+
+Since the i/o routines used by \fBlroff\fR are parameterized, pagination can be
+achieved by having the user supplied OUTPUT procedure count output lines.
+Similarly, pagination control directives can be added to the list of
+\fBlroff\fR directives, to be intercepted by the user supplied INPUT procedure.
+See the Manpage command for an example.
+
+
+DIRECTIVES
+
+Most of the \fBlroff\fR directives function the same as in the UNIX text
+formatters. For the benefit of readers without experience with UNIX,
+"filling" means collecting words of text until an output line has been
+filled, and "justification" refers to adding extra spaces between words
+to cause the output line to be both left and right justified (as in this
+paragraph). Filling is disabled with NF, and resumes following a FI.
+While filling is disabled, only the control directives FI and RJ will be
+recognized. Justification is enabled with JU, and disabled with NJ.
+The filling of an output line may be stopped, and the line output, with BR.
+SP (or a blank line) does the same thing, outputting one or more blank
+lines as well. CE causes the current line to be broken, and outputs the
+next line of input, centered.
+
+The directive ".rj text" breaks the current line, and outputs the next
+line of input, unfilled, with "text" right justified on the same line.
+RJ is especially useful for numbering equations. The RJ directive is
+recognized whether or not filling is in effect.
+
+SH and IH may be used for section headers. Both cause a break, followed
+by a couple blank lines, followed by the next line of input,
+left justified on the output line. The left margin is reset to its
+initial value. If IH is used, the text following the section header will
+be indented one level in from the left margin.
+The number of lines of blank lines before the heading,
+and the amount of indentation, are optional arguments.
+The default values are shown in the request summary below. If values
+other than the defaults are desired, they need only be supplied as arguments
+once. Succeeding calls will continue to use the new values.
+
+The IH and LS directives are especially useful in help text (manual pages).
+LS with a label string is useful for parameter lists,
+as shown in the example below.
+LS without a label string is used for relative indenting.
+A following LE restores the previous level of indentation.
+
+The LS directive has the form ".ls [n] [stuff]", where "n" (optional)
+is the amount by which the following text is to be indented,
+and "stuff" is the (optional) label for the indented text block.
+LS causes a break, followed by one blank line, then the label string (if given),
+left justified.
+If the length of "stuff" is less than N-1 characters, the text
+block will start filling on the same line, otherwise on the next line.
+The indented text block may contain anything, including additional LS
+directives if nesting is desired. A matching LE eventually terminates the
+block, restoring the previous level of indentation.
+
+The LS directive takes the most recent argument as the new default
+indentation, allowing the argument to be omitted in subsequent calls.
+To keep the current default value from being changed, use a negative
+argument.
+
+.ih
+EXAMPLE
+.sp
+Many examples of the use of the \fBlroff\fR command directives in help text
+can be found by browsing about in source listings.
+A brief example is included here for convenient reference.
+.sp
+The ".help" directive, used to mark the beginning
+of a block of help text, is used by HELP and MANPAGE rather than \fBlroff\fR.
+The (optional) arguments to ".help" are the keyword name of the help
+text block, and two strings.
+The keyword argument may be a list of the form ".help keyw1,
+keyw2, ..., keywn", if more than one keyword is appropriate.
+The first keyword in the list is placed in the header of a manual page,
+followed by the first string, in parenthesis. The second string,
+if given, is centered in the header line. The strings need not be
+delimited unless they contain whitespace.
+.sp
+The \fBlroff\fR-format help text fragment
+.sp
+.ls
+.nf
+.help stcopy 2 "string utilities"
+.ih
+NAME
+stcopy -- copy a string.
+.ih
+PURPOSE
+Stcopy is used to copy an EOS delimited character
+string. The EOS delimiter MUST be present.
+.ih
+USAGE
+stcopy (from, to, maxchar)
+.ih
+PARAMETERS
+.ls from
+The input string.
+.le
+.ls to
+The output string, of length no less than "maxchar"
+characters (excluding the EOS).
+.le
+.ls maxchar
+The maximum number of characters to be copied.
+Note that "maxchar" does not include the EOS.
+Thus, the destination string must contain storage
+for at least (maxchar + 1) characters.
+.le
+.ih
+DESCRIPTION
+.fi
+.sp 2
+.le
+would be converted by \fBlroff\fR (as called from Help) into something like
+the following. Remember that the margins are runtime arguments to \fBlroff\fR.
+Help does not print a header line, or break pages.
+.sp 2
+.in 8
+NAME
+.in 5
+stcopy -- copy a string.
+.in -5
+.sp 2
+PURPOSE
+.in 5
+Stcopy is used to copy an EOS delimited character
+string. The EOS delimiter MUST be present.
+.in -5
+.sp 2
+USAGE
+.in 5
+stcopy (from, to, maxchar)
+.in -5
+.sp 2
+PARAMETERS
+.in 5
+.ls from
+The input string.
+.le
+.ls to
+The output string, of length no less than "maxchar"
+characters (excluding the EOS).
+.le
+.ls maxchar
+The maximum number of characters to be copied.
+Note that "maxchar" does not include the EOS.
+Thus, the destination string must contain storage
+for at least (maxchar + 1) characters.
+.le
+.in -5
+.sp 2
+DESCRIPTION
+.sp
+.ih
+SEE ALSO
+help
+
+The reader should note that MANPAGE, which is page oriented,
+recognizes the following directives in addition to those recognized
+by \fBlroff\fR: BP (break page), and KS, KE (start and end keep). MANPAGE also
+omits blank lines at the top of a page. These directives may safely
+be included in \fBlroff\fR text, as they will be ignored by \fBlroff\fR if not
+intercepted by the procedure calling \fBlroff\fR.
+
+.ih
+REQUEST SUMMARY
+.sp
+.nf
+Request Initial Default Break Meaning
+
+ .fi yes yes Begin filling output lines.
+ .nf no yes Stop filling output lines.
+ .ju yes no Right justify output lines.
+ .nj no no Don't right justify.
+ .rj text yes Rt justify text on next line.
+ .sh n n=2 yes Skip n lines, start section.
+ .ih m n m=2,n=5 yes Like SH, but indent n spaces.
+ .br yes Stop filling current line.
+ .ce yes Center following line.
+ .sp n n=1 yes Space "n" lines.
+ .in n n=0 n=0 yes Set left margin to "current+n".
+ .ls n label n=8 yes Begin labeled text block.
+ .le yes End labeled text block.
+
+additional directives provided by MANPAGE:
+
+ .bp yes Start a new page of output.
+ .tp n n=4 yes Break page if < n lines left.
+ .ks yes Begin saving output.
+ .ke yes Output saved text all on one page.
+.fi
+.endhelp
diff --git a/pkg/system/help/lroff/lroff.o b/pkg/system/help/lroff/lroff.o
new file mode 100644
index 00000000..4151c327
--- /dev/null
+++ b/pkg/system/help/lroff/lroff.o
Binary files differ
diff --git a/pkg/system/help/lroff/lroff.x b/pkg/system/help/lroff/lroff.x
new file mode 100644
index 00000000..e9624827
--- /dev/null
+++ b/pkg/system/help/lroff/lroff.x
@@ -0,0 +1,220 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include <ctype.h>
+include "lroff.h"
+
+.help lroff
+.nf ___________________________________________________________________________
+Source for the LROFF line-oriented text formatter. LROFF is a simple text
+formatter patterned after the NROFF formatter of UNIX. LROFF is unusual in
+that it is a "numerical" library procedure which does not directly do any
+i/o (except for buffer allocation and use of ERROR).
+
+LROFF -- The main entry point. Lroff reads lines with the input procedure,
+performs the format conversion, and writes lines with the output procedure,
+both of which are passed as arguments. Conversion proceeds until the .endhelp
+directive or EOF is reached. The calling sequences for the input and output
+procedures are as follows:
+
+ stat = inproc (inarg, linebuf)
+ outproc (outarg, linebuf)
+
+where "inarg" and "outarg" are magic integer arguments which Lroff merely
+passes on to the input and output procedures when they are called.
+
+Other arguments to Lroff include PLM and PRM, the permanent left and right
+margins for the output text, and SOFLAG, set to YES if "standout mode" control
+chars are permitted in the output text.
+
+The forms control directives BP, TP, KS, and KE are ignored unless forms mode
+is enabled (foflag=YES). If forms control is enabled these directives cause
+a breakline followed by output of a special control character forms directive,
+used to control the layout of text on a page. When forms mode is in effect
+the section header directives also cause output of a TP (test page) directive
+before the section. Processing of forms control characters is left to the
+program that reads lroff output.
+.endhelp ______________________________________________________________________
+
+procedure lroff (in, in_arg, out, out_arg, plm, prm, soflag_val, foflag_val)
+
+extern in() # called to get lines of input text
+int in_arg # magic argument for in()
+extern out() # called to output formatted lines of text
+int out_arg # magic argument for out()
+int plm, prm # permanent left and right margins
+int soflag_val # output standout mode control chars?
+int foflag_val # output form control chars?
+
+char ctrlstr[2]
+pointer sp, ibuf
+int ip, command, last_command
+int in(), nextcmd(), lgetarg(), input(), nofill()
+
+errchk input, textout, nofill, rawcopy, skiplines, breakline, right_justify
+errchk salloc, new_section, new_indented_section, center_text, init_ls
+errchk init_nh, indent_left_margin, do_LS, textout, set_wordbuf, set_outbuf
+include "lroff.com"
+
+define text_ 98
+
+begin
+ call smark (sp)
+ call salloc (ibuf, SZ_IBUF, TY_CHAR)
+
+ if (plm > prm || plm < 1)
+ call error (1, "Lroff called with invalid margins")
+
+ # General initialization. Set up the Lroff common. Call the various
+ # initialization procedures to initialize the directives and to
+ # set up the word buffer and output buffer, the size of which depends
+ # on the margins.
+
+ justify = YES
+ perm_left_margin = plm
+ perm_right_margin = prm
+ left_margin = plm
+ right_margin = prm
+ last_command = NULL
+ in_magic_arg = in_arg
+ out_magic_arg = out_arg
+ soflag = soflag_val
+ foflag = foflag_val
+ standout_mode_enabled = false
+
+ ls_indent = DEF_LSINDENT
+ ih_indent = DEF_IHINDENT
+ sh_nskip = DEF_SHNSKIP
+ nh_nskip = DEF_NHNSKIP
+ ih_nskip = DEF_IHNSKIP
+
+ call init_ls()
+ call init_nh()
+ call set_wordbuf (prm - plm + 2)
+ call set_outbuf (max (SZ_LINE, 2 * (prm - plm + 1)))
+
+ # If the first line of text is not an Lroff directive, we copy the
+ # input to the output without modification, except for moving the text
+ # to the desired left margin, stopping only at EOF or .endhelp.
+ # If any directive is given, the default mode is justify+fill.
+
+ if (input (in, Memc[ibuf]) == EOF) {
+ call sfree (sp)
+ return
+ } else if (nextcmd (Memc[ibuf], ip) < 0) {
+ call rawcopy (in, out, Memc[ibuf])
+ call sfree (sp)
+ return
+ }
+
+
+ # The main Lroff interpreter loop. Get input line: if directive,
+ # execute directive; else call textout() to process a line of text.
+ # The basic idea is to break the input stream up into words, saving
+ # these until we have one more than needed to fill the output line.
+ # The words are then copied into the output line, starting at the left
+ # margin, adding spaces as needed to right justify the line. Many
+ # commands cause the "current output line" to be broken, forcing
+ # whatever has been accumulated out without right justification.
+
+ repeat {
+ command = nextcmd (Memc[ibuf], ip)
+ switch (command) {
+ case FI:
+ call breakline (out, NJ)
+ case NF:
+ call breakline (out, NJ)
+ if (nofill (in, out, Memc[ibuf]) == ENDHELP)
+ break
+ case JU:
+ justify = YES
+ case NJ:
+ justify = NO
+ case RJ:
+ call right_justify (in, out, Memc[ibuf], ip)
+ case SH:
+ call new_section (in, out, Memc[ibuf], ip)
+ case IH:
+ call new_indented_section (in, out, Memc[ibuf], ip)
+ case NH:
+ call new_numbered_section (in, out, Memc[ibuf], ip)
+ case BR:
+ call breakline (out, NJ)
+ case CE:
+ call center_text (in, out, Memc[ibuf], ip)
+ case SP:
+ call skiplines (out, lgetarg(Memc[ibuf],ip,1))
+ case IN:
+ call indent_left_margin (in, out, lgetarg(Memc[ibuf],ip,0))
+ case LS, LE:
+ call do_LS (out, Memc[ibuf+ip-1], command, last_command)
+
+ case HR:
+ # HTML href target of the form ".hr <href> <text>", we skip
+ # ahead to the <text> and process as a normal line.
+ while (IS_WHITE(Memc[ibuf+ip])) # skip space
+ ip = ip + 1
+ while (!IS_WHITE(Memc[ibuf+ip])) # skip <href>
+ ip = ip + 1
+ call amovc (Memc[ibuf+ip+1], Memc[ibuf], SZ_IBUF)
+ ip = 0
+ goto text_
+
+ case HN:
+ # HTML name target of the form ".hn <name>", ignore.
+ next
+
+ # The following cases are for forms control.
+ case BP:
+ call breakline (out, NJ)
+ if (foflag == YES)
+ call outcc (out, FC_BREAKPAGE)
+ case TP:
+ call breakline (out, NJ)
+ if (foflag == YES) {
+ ctrlstr[1] = FC_TESTPAGE
+ ctrlstr[2] = lgetarg (Memc[ibuf], ip, DEF_TPNLINES)
+ ctrlstr[3] = EOS
+ call out (out_magic_arg, ctrlstr)
+ }
+ case KS:
+ call breakline (out, NJ)
+ if (foflag == YES)
+ call outcc (out, FC_STARTKEEP)
+ case KE:
+ call breakline (out, NJ)
+ if (foflag == YES)
+ call outcc (out, FC_ENDKEEP)
+
+ case ENDHELP: # normal exit point
+ break
+
+ default: # ordinary line of text
+text_ if (Memc[ibuf] == '.') {
+ # Ignore unrecognized directives.
+ next
+ } else {
+ # Determine if line is blank; skip a line if so, otherwise
+ # process a normal line of text.
+ for (ip=0; Memc[ibuf+ip] == BLANK; ip=ip+1)
+ ;
+ if (Memc[ibuf+ip] == EOS)
+ call skiplines (out, 1)
+ else if (Memc[ibuf] == '\\')
+ call textout (out, Memc[ibuf+1])
+ else
+ call textout (out, Memc[ibuf])
+ }
+ }
+
+ last_command = command
+
+ } until (input (in, Memc[ibuf]) == EOF)
+
+
+99 call breakline (out, NJ)
+ call set_wordbuf (0)
+ call set_outbuf (0)
+
+ call sfree (sp)
+end
diff --git a/pkg/system/help/lroff/lroff2html.c b/pkg/system/help/lroff/lroff2html.c
new file mode 100644
index 00000000..26cf8227
--- /dev/null
+++ b/pkg/system/help/lroff/lroff2html.c
@@ -0,0 +1,1381 @@
+/* lroff2html.x -- translated by f2c (version 20100827).
+ You must link the resulting object file with libf2c:
+ on Microsoft Windows system, link with libf2c.lib;
+ on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+ or, if you install libf2c.a in a standard place, with -lf2c -lm
+ -- in that order, at the end of the command line, as in
+ cc *.o -lf2c -lm
+ Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+ http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#include "f2c.h"
+
+/* Common Block Declarations */
+
+struct {
+ doublereal memd[1];
+} mem_;
+
+#define mem_1 mem_
+
+struct {
+ integer rightn, leftmn, permrn, permln, inmagg, outmag, soflag, foflag,
+ justiy, nls, lsindt, shnskp, ihnskp, ihindt, nhnskp, nhlevl[10];
+ logical standd;
+} lrfcom_;
+
+#define lrfcom_1 lrfcom_
+
+struct {
+ logical xerflg, xerpad[84];
+} xercom_;
+
+#define xercom_1 xercom_
+
+/* Table of constant values */
+
+static integer c__2046 = 2046;
+static integer c__2 = 2;
+static integer c__1023 = 1023;
+static integer c__255 = 255;
+static integer c__256 = 256;
+static integer c__9 = 9;
+static integer c__0 = 0;
+static integer c__10 = 10;
+static integer c__1 = 1;
+static logical c_true = TRUE_;
+static integer c__3 = 3;
+
+/* Subroutine */ int lroffl_(in, out, module, parstr, center, lsblok, sectin)
+integer *in, *out;
+shortint *module, *parstr, *center, *lsblok, *sectin;
+{
+ /* Initialized data */
+
+ static shortint st0003[5] = { 60,80,62,10,0 };
+ static shortint st0004[7] = { 94,46,104,101,108,112,0 };
+ static shortint st0005[8] = { 60,47,80,82,69,62,10,0 };
+ static shortint st0006[7] = { 60,80,82,69,62,10,0 };
+ static shortint st0007[13] = { 60,47,68,68,62,10,60,47,68,76,62,10,0 };
+ static shortint st0008[13] = { 60,47,68,68,62,10,60,47,68,76,62,10,0 };
+ static shortint st0009[2] = { 124,0 };
+ static shortint st0010[13] = { 60,47,68,68,62,10,60,47,68,76,62,10,0 };
+ static shortint st0011[25] = { 60,67,69,78,84,69,82,62,37,115,60,47,67,69,
+ 78,84,69,82,62,60,66,82,62,10,0 };
+ static shortint st0012[6] = { 60,66,82,62,10,0 };
+ static shortint st0013[6] = { 60,66,82,62,10,0 };
+ static shortint st0014[6] = { 60,66,82,62,10,0 };
+ static shortint st0015[13] = { 60,68,76,62,10,60,68,84,62,60,66,62,0 };
+ static shortint st0016[22] = { 60,65,32,78,65,77,69,61,34,108,95,37,115,
+ 34,62,37,115,60,47,65,62,0 };
+ static shortint st0017[11] = { 60,47,66,62,60,47,68,84,62,10,0 };
+ static shortint st0018[46] = { 60,33,32,83,101,99,61,37,115,32,76,101,118,
+ 101,108,61,37,100,32,76,97,98,101,108,61,39,37,115,39,32,76,105,
+ 110,101,61,39,37,115,39,62,10,60,68,68,62,0 };
+ static shortint st0019[5] = { 78,111,110,101,0 };
+ static shortint st0020[2] = { 32,0 };
+ static shortint st0021[13] = { 60,47,68,68,62,10,60,47,68,76,62,10,0 };
+ static shortint st0022[21] = { 60,65,32,72,82,69,70,61,34,37,115,34,62,37,
+ 115,60,47,65,62,10,0 };
+ static shortint st0023[19] = { 60,65,32,78,65,77,69,61,34,37,115,34,62,60,
+ 47,65,62,10,0 };
+ static shortint st0024[7] = { 60,80,82,69,62,10,0 };
+ static shortint st0025[8] = { 60,47,80,82,69,62,10,0 };
+ static shortint st0026[5] = { 39,37,115,39,0 };
+ static shortint st0027[7] = { 60,47,85,76,62,10,0 };
+ static shortint st0028[22] = { 60,33,32,69,110,100,83,101,99,116,105,111,
+ 110,58,32,32,32,37,115,62,10,0 };
+ static shortint st0029[32] = { 60,72,50,62,60,65,32,78,65,77,69,61,34,115,
+ 95,37,115,34,62,37,115,60,47,65,62,60,47,72,50,62,10,0 };
+ static shortint st0030[35] = { 60,72,50,62,60,65,32,78,65,77,69,61,34,115,
+ 95,37,115,34,62,37,115,32,37,115,60,47,65,62,60,47,72,50,62,10,0 }
+ ;
+ static shortint st0031[24] = { 60,33,32,66,101,103,105,110,83,101,99,116,
+ 105,111,110,58,32,39,37,115,39,62,10,0 };
+ static shortint st0032[6] = { 60,85,76,62,10,0 };
+ static shortint st0033[3] = { 37,115,0 };
+ static shortint st0034[30] = { 60,47,85,76,62,10,60,33,32,69,110,100,83,
+ 101,99,116,105,111,110,58,32,32,32,32,37,115,62,10,10,0 };
+ static shortint st0035[14] = { 60,33,32,67,111,110,116,101,110,116,115,58,
+ 32,0 };
+ static shortint st0036[4] = { 37,115,32,0 };
+ static shortint st0037[5] = { 32,62,10,10,0 };
+ static shortint st0038[17] = { 60,47,66,79,68,89,62,10,60,47,72,84,77,76,
+ 62,10,0 };
+ static shortint st0001[24] = { 60,84,73,84,76,69,62,37,115,60,47,84,73,84,
+ 76,69,62,10,60,85,76,62,10,0 };
+ static shortint st0002[2] = { 32,0 };
+
+ /* System generated locals */
+ integer i__1;
+
+ /* Local variables */
+ static integer i__, ip, sp, cmd, arg;
+#define memb ((logical *)&mem_1)
+#define memc ((shortint *)&mem_1)
+ static integer name__, ibuf;
+#define memi ((integer *)&mem_1)
+ static integer nsec;
+#define meml ((integer *)&mem_1)
+ static integer sw0001, sw0002;
+#define memr ((real *)&mem_1)
+#define mems ((shortint *)&mem_1)
+#define memx ((complex *)&mem_1)
+ static integer font, sptr;
+ extern /* Subroutine */ int aclrc_(), pargi_(), sfree_();
+ static integer level, unesc;
+ extern /* Subroutine */ int smark_();
+ static integer indend;
+ extern integer lgetag_();
+ extern /* Subroutine */ int lhesce_();
+ static logical formad;
+ extern integer getlie_(), lhfink_(), lhfinn_();
+ extern /* Subroutine */ int salloc_(), lhmkne_();
+ static integer lastle;
+ static logical format, quitae, quitah;
+ extern integer nextcd_(), strmah_();
+ static integer lslevl;
+ extern integer strids_();
+ extern /* Subroutine */ int amovki_(), ungete_(), lhprog_(), fprinf_(),
+ pargsr_(), lhsetl_(), sprinf_(), xffluh_(), zzepro_();
+ extern integer xstrln_();
+ extern /* Subroutine */ int xstrcy_();
+
+ /* Parameter adjustments */
+ --sectin;
+ --lsblok;
+ --center;
+ --parstr;
+ --module;
+
+ /* Function Body */
+ smark_(&sp);
+ salloc_(&ibuf, &c__2046, &c__2);
+ salloc_(&unesc, &c__2046, &c__2);
+ salloc_(&name__, &c__1023, &c__2);
+ salloc_(&level, &c__255, &c__2);
+ salloc_(&sptr, &c__256, &c__9);
+ aclrc_(&memc[ibuf - 1], &c__2046);
+ aclrc_(&memc[name__ - 1], &c__1023);
+ aclrc_(&memc[unesc - 1], &c__2046);
+ aclrc_(&memc[level - 1], &c__255);
+ lastle = 3;
+ font = 1;
+ indend = 1;
+ nsec = 0;
+ lslevl = 0;
+ format = TRUE_;
+ quitae = FALSE_;
+ quitah = FALSE_;
+ formad = FALSE_;
+ amovki_(&c__0, lrfcom_1.nhlevl, &c__10);
+L110:
+ if (! (getlie_(in, &memc[ibuf - 1]) == -2)) {
+ goto L120;
+ }
+ goto L98;
+L120:
+ ip = 1;
+L130:
+ if (! (memc[ibuf + ip - 2] == 32 || memc[ibuf + ip - 2] == 9)) {
+ goto L132;
+ }
+/* L131: */
+ ++ip;
+ goto L130;
+L132:
+/* L111: */
+ if (! (memc[ibuf + ip - 2] != 10)) {
+ goto L110;
+ }
+/* L112: */
+ ungete_(in, &memc[ibuf - 1]);
+ if (! (memc[ibuf - 1] == 46)) {
+ goto L140;
+ }
+ formad = TRUE_;
+L140:
+ if (! (sectin[1] != 0)) {
+ goto L150;
+ }
+ if (! (lhfinn_(in, &formad, &sectin[1]) == -2)) {
+ goto L160;
+ }
+ goto L98;
+L160:
+ goto L151;
+L150:
+ if (! (lsblok[1] != 0)) {
+ goto L170;
+ }
+ if (! (lhfink_(in, &formad, &lsblok[1]) == -2)) {
+ goto L180;
+ }
+ goto L98;
+L180:
+ quitae = TRUE_;
+L170:
+L151:
+ lhprog_(out, &module[1], &parstr[1], &center[1]);
+ fprinf_(out, st0001);
+ if (! (lsblok[1] != 0)) {
+ goto L190;
+ }
+ pargsr_(&lsblok[1]);
+ goto L191;
+L190:
+ if (! (sectin[1] != 0)) {
+ goto L200;
+ }
+ pargsr_(&sectin[1]);
+ goto L201;
+L200:
+ if (! (module[1] != 0)) {
+ goto L210;
+ }
+ pargsr_(&module[1]);
+ goto L211;
+L210:
+ pargsr_(st0002);
+L211:
+L201:
+L191:
+L220:
+ if (! (getlie_(in, &memc[ibuf - 1]) != -2)) {
+ goto L221;
+ }
+ memc[ibuf + xstrln_(&memc[ibuf - 1]) - 2] = 0;
+ xstrcy_(&memc[ibuf - 1], &memc[unesc - 1], &c__1023);
+ lhesce_(&memc[ibuf - 1], &font, &format, &c__0, &c__1023);
+ sw0001 = memc[ibuf - 1];
+ goto L230;
+L240:
+ fprinf_(out, st0003);
+ goto L231;
+L250:
+ if (! (strmah_(&memc[ibuf - 1], st0004) > 0)) {
+ goto L260;
+ }
+ goto L220;
+L260:
+ ip = 1;
+ lastle = 3;
+ cmd = nextcd_(&memc[ibuf - 1], &ip);
+L270:
+ if (! (memc[ibuf + ip - 1] == 32 || memc[ibuf + ip - 1] == 9)) {
+ goto L271;
+ }
+ ++ip;
+ goto L270;
+L271:
+ sw0002 = cmd;
+ goto L280;
+L290:
+ fprinf_(out, st0005);
+ format = TRUE_;
+ goto L281;
+L300:
+ fprinf_(out, st0006);
+ format = FALSE_;
+ goto L281;
+L310:
+ goto L220;
+L320:
+ goto L220;
+L330:
+ goto L220;
+L340:
+ if (! (lslevl > 0)) {
+ goto L350;
+ }
+ fprinf_(out, st0007);
+ lslevl = 0;
+L350:
+ lastle = 1;
+ memc[level - 1] = 0;
+ goto L220;
+L360:
+ if (! (lslevl > 0)) {
+ goto L370;
+ }
+ fprinf_(out, st0008);
+ lslevl = 0;
+L370:
+ lastle = 1;
+ memc[level - 1] = 0;
+ if (! quitah) {
+ goto L380;
+ }
+ if (! (strids_(st0009, &sectin[1]) > 0)) {
+ goto L390;
+ }
+ quitah = FALSE_;
+ ungete_(in, &memc[ibuf - 1]);
+ if (! (lhfinn_(in, &formad, &sectin[1]) == -2)) {
+ goto L400;
+ }
+ goto L221;
+L400:
+ goto L391;
+L390:
+ goto L221;
+L391:
+L380:
+ goto L220;
+L410:
+ if (! (lslevl > 0)) {
+ goto L420;
+ }
+ fprinf_(out, st0010);
+ lslevl = 0;
+L420:
+ i__1 = lgetag_(&memc[ibuf - 1], &ip, &c__1);
+ lhsetl_(&i__1, &memc[level - 1]);
+ lastle = 1;
+ goto L220;
+L430:
+ if (! (getlie_(in, &memc[ibuf - 1]) == -2)) {
+ goto L440;
+ }
+ goto L221;
+L440:
+ lhesce_(&memc[ibuf - 1], &font, &c_true, &c__0, &c__1023);
+ fprinf_(out, st0011);
+ pargsr_(&memc[ibuf - 1]);
+/* L441: */
+ goto L281;
+L450:
+ fprinf_(out, st0012);
+ goto L281;
+L460:
+ arg = lgetag_(&memc[ibuf - 1], &ip, &c__1);
+ fprinf_(out, st0013);
+ i__ = 1;
+L470:
+ if (! (i__ < arg)) {
+ goto L472;
+ }
+ fprinf_(out, st0014);
+/* L471: */
+ ++i__;
+ goto L470;
+L472:
+ goto L281;
+L480:
+ goto L220;
+L490:
+ arg = lgetag_(&memc[ibuf - 1], &ip, &c__0);
+ if (! (arg == 0)) {
+ goto L500;
+ }
+ ip = 5;
+L500:
+ xstrcy_(&memc[ibuf + ip - 2], &memc[name__ - 1], &c__1023);
+ i__ = 0;
+L510:
+ if (! (memc[name__ + i__ - 1] >= 65 && memc[name__ + i__ - 1] <= 90 ||
+ memc[name__ + i__ - 1] >= 97 && memc[name__ + i__ - 1] <= 122 ||
+ memc[name__ + i__ - 1] >= 48 && memc[name__ + i__ - 1] <= 57 ||
+ memc[name__ + i__ - 1] == 95)) {
+ goto L512;
+ }
+/* L511: */
+ ++i__;
+ goto L510;
+L512:
+ memc[name__ + i__ - 1] = 0;
+ memc[ibuf + ip + xstrln_(&memc[ibuf + ip - 1]) - 2] = 0;
+ fprinf_(out, st0015);
+ fprinf_(out, st0016);
+ pargsr_(&memc[name__ - 1]);
+ pargsr_(&memc[ibuf + ip - 2]);
+ fprinf_(out, st0017);
+ lhesce_(&memc[unesc + ip - 2], &font, &c_true, &c__1, &c__1023);
+ memc[unesc + xstrln_(&memc[unesc - 1]) - 2] = 0;
+ fprinf_(out, st0018);
+ if (! (nsec > 0)) {
+ goto L520;
+ }
+ pargsr_(&memc[memi[sptr + nsec - 2] - 1]);
+ goto L521;
+L520:
+ pargsr_(st0019);
+L521:
+ pargi_(&lslevl);
+ pargsr_(&memc[name__ - 1]);
+ if (! (memc[unesc + ip - 2] == 10)) {
+ goto L530;
+ }
+ pargsr_(st0020);
+ goto L531;
+L530:
+ pargsr_(&memc[unesc + ip - 2]);
+L531:
+ ++lslevl;
+ goto L281;
+L540:
+ fprinf_(out, st0021);
+ --lslevl;
+ if (! quitae) {
+ goto L550;
+ }
+ goto L221;
+L550:
+ goto L281;
+L560:
+ memc[ibuf + ip + xstrln_(&memc[ibuf + ip - 1]) - 2] = 0;
+ i__ = 0;
+L570:
+ if (memc[ibuf + ip - 1] == 32 || memc[ibuf + ip - 1] == 9) {
+ goto L572;
+ }
+ memc[name__ + i__ - 1] = memc[ibuf + ip - 1];
+ ++i__;
+/* L571: */
+ ++ip;
+ goto L570;
+L572:
+ memc[name__ + i__ - 1] = 0;
+ fprinf_(out, st0022);
+ pargsr_(&memc[name__ - 1]);
+ pargsr_(&memc[ibuf + ip]);
+ goto L281;
+L580:
+ memc[ibuf + ip + xstrln_(&memc[ibuf + ip - 1]) - 2] = 0;
+ fprinf_(out, st0023);
+ pargsr_(&memc[ibuf + ip - 1]);
+ goto L281;
+L590:
+ goto L220;
+L600:
+ goto L220;
+L610:
+ fprinf_(out, st0024);
+ format = FALSE_;
+ goto L281;
+L620:
+ fprinf_(out, st0025);
+ format = TRUE_;
+ goto L281;
+L630:
+ goto L221;
+L280:
+ if (sw0002 < 1 || sw0002 > 21) {
+ goto L281;
+ }
+ switch ((int)sw0002) {
+ case 1: goto L290;
+ case 2: goto L300;
+ case 3: goto L310;
+ case 4: goto L320;
+ case 5: goto L330;
+ case 6: goto L340;
+ case 7: goto L360;
+ case 8: goto L410;
+ case 9: goto L450;
+ case 10: goto L430;
+ case 11: goto L460;
+ case 12: goto L480;
+ case 13: goto L490;
+ case 14: goto L540;
+ case 15: goto L590;
+ case 16: goto L600;
+ case 17: goto L610;
+ case 18: goto L620;
+ case 19: goto L560;
+ case 20: goto L580;
+ case 21: goto L630;
+ }
+L281:
+ goto L231;
+L640:
+ if (! (lastle == 1)) {
+ goto L650;
+ }
+ salloc_(&memi[sptr + nsec - 1], &c__1023, &c__2);
+ aclrc_(&memc[memi[sptr + nsec - 1] - 1], &c__1023);
+ memc[ibuf + xstrln_(&memc[ibuf - 1]) - 2] = 0;
+ sprinf_(&memc[memi[sptr + nsec - 1] - 1], &c__1023, st0026);
+ pargsr_(&memc[ibuf - 1]);
+ if (! (indend == 1)) {
+ goto L660;
+ }
+ fprinf_(out, st0027);
+L660:
+ if (! (nsec > 0)) {
+ goto L670;
+ }
+ fprinf_(out, st0028);
+ pargsr_(&memc[memi[sptr + nsec - 2] - 1]);
+L670:
+ lhmkne_(&memc[ibuf - 1], &memc[name__ - 1]);
+ if (! (memc[level - 1] == 0)) {
+ goto L680;
+ }
+ fprinf_(out, st0029);
+ pargsr_(&memc[name__ - 1]);
+ pargsr_(&memc[ibuf - 1]);
+ goto L681;
+L680:
+ fprinf_(out, st0030);
+ pargsr_(&memc[name__ - 1]);
+ pargsr_(&memc[level - 1]);
+ pargsr_(&memc[ibuf - 1]);
+ memc[level - 1] = 0;
+L681:
+ fprinf_(out, st0031);
+ pargsr_(&memc[ibuf - 1]);
+ if (! (indend == 1)) {
+ goto L690;
+ }
+ fprinf_(out, st0032);
+L690:
+ lastle = 2;
+ ++nsec;
+ if (! (sectin[1] != 0)) {
+ goto L700;
+ }
+ quitah = TRUE_;
+L700:
+ goto L651;
+L650:
+/* L99: */
+ fprinf_(out, st0033);
+ pargsr_(&memc[ibuf - 1]);
+ lastle = 3;
+L651:
+ goto L231;
+L230:
+ if (sw0001 == 10) {
+ goto L240;
+ }
+ if (sw0001 == 46) {
+ goto L250;
+ }
+ goto L640;
+L231:
+ aclrc_(&memc[ibuf - 1], &c__2046);
+ aclrc_(&memc[unesc - 1], &c__2046);
+ aclrc_(&memc[name__ - 1], &c__1023);
+ goto L220;
+L221:
+ if (! (nsec > 0)) {
+ goto L710;
+ }
+ fprinf_(out, st0034);
+ pargsr_(&memc[memi[sptr + nsec - 2] - 1]);
+L710:
+ fprinf_(out, st0035);
+ i__ = 0;
+L720:
+ if (! (i__ < nsec)) {
+ goto L722;
+ }
+ fprinf_(out, st0036);
+ pargsr_(&memc[memi[sptr + i__ - 1] - 1]);
+/* L721: */
+ ++i__;
+ goto L720;
+L722:
+ fprinf_(out, st0037);
+ fprinf_(out, st0038);
+ xffluh_(out);
+L98:
+ sfree_(&sp);
+/* L100: */
+ zzepro_();
+ return 0;
+} /* lroffl_ */
+
+#undef memx
+#undef mems
+#undef memr
+#undef meml
+#undef memi
+#undef memc
+#undef memb
+
+
+/* Subroutine */ int lhprog_(fd, mod, date, title)
+integer *fd;
+shortint *mod, *date, *title;
+{
+ /* Initialized data */
+
+ static shortint st0001[15] = { 60,72,84,77,76,62,10,60,66,79,68,89,62,10,
+ 0 };
+ static shortint st0002[36] = { 60,84,65,66,76,69,32,87,73,68,84,72,61,34,
+ 49,48,48,37,37,34,32,66,79,82,68,69,82,61,48,62,60,84,82,62,10,0 }
+ ;
+ static shortint st0003[30] = { 60,84,68,32,65,76,73,71,78,61,76,69,70,84,
+ 62,60,70,79,78,84,32,83,73,90,69,61,52,62,10,0 };
+ static shortint st0004[10] = { 60,66,62,37,115,60,47,66,62,0 };
+ static shortint st0005[15] = { 60,66,62,37,115,32,40,37,115,41,60,47,66,
+ 62,0 };
+ static shortint st0006[14] = { 60,47,70,79,78,84,62,60,47,84,68,62,10,0 };
+ static shortint st0007[32] = { 60,84,68,32,65,76,73,71,78,61,67,69,78,84,
+ 69,82,62,60,70,79,78,84,32,83,73,90,69,61,52,62,10,0 };
+ static shortint st0008[11] = { 60,66,62,37,115,60,47,66,62,10,0 };
+ static shortint st0009[14] = { 60,47,70,79,78,84,62,60,47,84,68,62,10,0 };
+ static shortint st0010[31] = { 60,84,68,32,65,76,73,71,78,61,82,73,71,72,
+ 84,62,60,70,79,78,84,32,83,73,90,69,61,52,62,10,0 };
+ static shortint st0011[10] = { 60,66,62,37,115,60,47,66,62,0 };
+ static shortint st0012[15] = { 60,66,62,37,115,32,40,37,115,41,60,47,66,
+ 62,0 };
+ static shortint st0013[14] = { 60,47,70,79,78,84,62,60,47,84,68,62,10,0 };
+ static shortint st0014[18] = { 60,47,84,82,62,60,47,84,65,66,76,69,62,60,
+ 80,62,10,0 };
+
+ extern /* Subroutine */ int fprinf_(), pargsr_(), zzepro_();
+
+ /* Parameter adjustments */
+ --title;
+ --date;
+ --mod;
+
+ /* Function Body */
+ fprinf_(fd, st0001);
+ if (! (date[1] == 0 && title[1] == 0)) {
+ goto L110;
+ }
+ goto L100;
+L110:
+ fprinf_(fd, st0002);
+ fprinf_(fd, st0003);
+ if (! (date[1] == 0)) {
+ goto L120;
+ }
+ fprinf_(fd, st0004);
+ pargsr_(&mod[1]);
+ goto L121;
+L120:
+ fprinf_(fd, st0005);
+ pargsr_(&mod[1]);
+ pargsr_(&date[1]);
+L121:
+ fprinf_(fd, st0006);
+ if (! (title[1] != 0)) {
+ goto L130;
+ }
+ fprinf_(fd, st0007);
+ fprinf_(fd, st0008);
+ pargsr_(&title[1]);
+ fprinf_(fd, st0009);
+L130:
+ fprinf_(fd, st0010);
+ if (! (date[1] == 0)) {
+ goto L140;
+ }
+ fprinf_(fd, st0011);
+ pargsr_(&mod[1]);
+ goto L141;
+L140:
+ fprinf_(fd, st0012);
+ pargsr_(&mod[1]);
+ pargsr_(&date[1]);
+L141:
+ fprinf_(fd, st0013);
+ fprinf_(fd, st0014);
+L100:
+ zzepro_();
+ return 0;
+} /* lhprog_ */
+
+/* Subroutine */ int lhesce_(str, font, format, speciy, maxch)
+shortint *str;
+integer *font;
+logical *format;
+integer *speciy, *maxch;
+{
+ /* Initialized data */
+
+ static shortint st0013[5] = { 60,47,66,62,0 };
+ static shortint st0014[4] = { 60,73,62,0 };
+ static shortint st0015[5] = { 60,47,66,62,0 };
+ static shortint st0016[5] = { 60,47,73,62,0 };
+ static shortint st0017[5] = { 60,47,66,62,0 };
+ static shortint st0018[5] = { 60,47,73,62,0 };
+ static shortint st0019[5] = { 60,66,82,62,0 };
+ static shortint st0020[3] = { 10,0,0 };
+ static shortint st0001[4] = { 60,62,38,0 };
+ static shortint st0002[5] = { 38,108,116,59,0 };
+ static shortint st0003[5] = { 38,103,116,59,0 };
+ static shortint st0004[6] = { 38,97,109,112,59,0 };
+ static shortint st0005[5] = { 60,84,84,62,0 };
+ static shortint st0006[6] = { 60,47,84,84,62,0 };
+ static shortint st0007[5] = { 60,84,84,62,0 };
+ static shortint st0008[6] = { 60,47,84,84,62,0 };
+ static shortint st0009[7] = { 60,47,84,84,62,34,0 };
+ static shortint st0010[6] = { 34,60,84,84,62,0 };
+ static shortint st0011[5] = { 60,47,73,62,0 };
+ static shortint st0012[4] = { 60,66,62,0 };
+
+ /* Local variables */
+ static integer i__, ip, sp, buf;
+#define memb ((logical *)&mem_1)
+#define memc ((shortint *)&mem_1)
+#define memi ((integer *)&mem_1)
+#define meml ((integer *)&mem_1)
+ static integer sw0001;
+#define memr ((real *)&mem_1)
+#define mems ((shortint *)&mem_1)
+#define memx ((complex *)&mem_1)
+ extern /* Subroutine */ int aclrc_(), sfree_(), amovc_(), smark_(),
+ salloc_();
+ static integer keywod;
+ extern integer gstrcy_(), stridx_();
+ extern /* Subroutine */ int zzepro_();
+
+ /* Parameter adjustments */
+ --str;
+
+ /* Function Body */
+ smark_(&sp);
+ salloc_(&buf, maxch, &c__2);
+ salloc_(&keywod, maxch, &c__2);
+ aclrc_(&memc[buf - 1], maxch);
+ aclrc_(&memc[keywod - 1], maxch);
+ ip = buf;
+ i__ = 1;
+L110:
+ if (! (str[i__] != 0 && i__ <= *maxch)) {
+ goto L112;
+ }
+ if (! (*speciy == 1 && stridx_(&str[i__], st0001) == 0)) {
+ goto L120;
+ }
+ goto L90;
+L120:
+ sw0001 = str[i__];
+ goto L130;
+L140:
+ ip += gstrcy_(st0002, &memc[ip - 1], &c__1023);
+ goto L131;
+L150:
+ ip += gstrcy_(st0003, &memc[ip - 1], &c__1023);
+ goto L131;
+L160:
+ ip += gstrcy_(st0004, &memc[ip - 1], &c__1023);
+ goto L131;
+L170:
+ if (! (str[i__ + 2] == 39)) {
+ goto L180;
+ }
+ ip += gstrcy_(st0005, &memc[ip - 1], &c__1023);
+ ip += gstrcy_(&str[i__], &memc[ip - 1], &c__3);
+ ip += gstrcy_(st0006, &memc[ip - 1], &c__1023);
+ i__ += 2;
+ goto L181;
+L180:
+ goto L90;
+L181:
+ goto L131;
+L190:
+ if (! (str[i__ + 2] == 96 || str[i__ + 2] == 39)) {
+ goto L200;
+ }
+ ip += gstrcy_(st0007, &memc[ip - 1], &c__1023);
+ ip += gstrcy_(&str[i__], &memc[ip - 1], &c__3);
+ ip += gstrcy_(st0008, &memc[ip - 1], &c__1023);
+ i__ += 2;
+ goto L201;
+L200:
+ goto L90;
+L201:
+ goto L131;
+L210:
+ if (! (*format && str[i__ + 1] != 47 && str[i__ + 2] != 47)) {
+ goto L220;
+ }
+ if (! (*font == 5)) {
+ goto L230;
+ }
+ ip += gstrcy_(st0009, &memc[ip - 1], &c__1023);
+ *font = 1;
+ goto L231;
+L230:
+ if (! (*font == 1)) {
+ goto L240;
+ }
+ ip += gstrcy_(st0010, &memc[ip - 1], &c__1023);
+ *font = 5;
+ goto L241;
+L240:
+ goto L90;
+L241:
+L231:
+ goto L221;
+L220:
+ goto L90;
+L221:
+ goto L131;
+L250:
+ if (! (str[i__ + 1] == 102)) {
+ goto L260;
+ }
+ if (! (str[i__ + 2] == 66)) {
+ goto L270;
+ }
+ if (! (*font == 3)) {
+ goto L280;
+ }
+ goto L111;
+L280:
+ if (! (*font == 2)) {
+ goto L290;
+ }
+ ip += gstrcy_(st0011, &memc[ip - 1], &c__1023);
+L290:
+ ip += gstrcy_(st0012, &memc[ip - 1], &c__1023);
+ *font = 3;
+ goto L271;
+L270:
+ if (! (str[i__ + 2] == 73)) {
+ goto L300;
+ }
+ if (! (*font == 2)) {
+ goto L310;
+ }
+ goto L111;
+L310:
+ if (! (*font == 3)) {
+ goto L320;
+ }
+ ip += gstrcy_(st0013, &memc[ip - 1], &c__1023);
+L320:
+ ip += gstrcy_(st0014, &memc[ip - 1], &c__1023);
+ *font = 2;
+ goto L301;
+L300:
+ if (! (str[i__ + 2] == 82)) {
+ goto L330;
+ }
+ if (! (*font == 3)) {
+ goto L340;
+ }
+ ip += gstrcy_(st0015, &memc[ip - 1], &c__1023);
+ goto L341;
+L340:
+ if (! (*font == 2)) {
+ goto L350;
+ }
+ ip += gstrcy_(st0016, &memc[ip - 1], &c__1023);
+L350:
+L341:
+ *font = 1;
+ goto L331;
+L330:
+ if (! (str[i__ + 2] == 80)) {
+ goto L360;
+ }
+ if (! (*font == 3)) {
+ goto L370;
+ }
+ ip += gstrcy_(st0017, &memc[ip - 1], &c__1023);
+ goto L371;
+L370:
+ if (! (*font == 2)) {
+ goto L380;
+ }
+ ip += gstrcy_(st0018, &memc[ip - 1], &c__1023);
+L380:
+L371:
+ *font = 1;
+L360:
+L331:
+L301:
+L271:
+ i__ += 2;
+ goto L261;
+L260:
+ if (! (str[i__ + 1] == 10 || str[i__ + 1] == 0)) {
+ goto L390;
+ }
+ memc[ip - 1] = str[i__];
+ ++ip;
+ ++i__;
+ ip += gstrcy_(st0019, &memc[ip - 1], &c__1023);
+ goto L391;
+L390:
+ goto L90;
+L391:
+L261:
+ goto L131;
+L400:
+L90:
+ memc[ip - 1] = str[i__];
+ ++ip;
+ goto L131;
+L130:
+ if (sw0001 == 34) {
+ goto L210;
+ }
+ if (sw0001 == 38) {
+ goto L160;
+ }
+ if (sw0001 == 39) {
+ goto L170;
+ }
+ if (sw0001 == 60) {
+ goto L140;
+ }
+ if (sw0001 == 62) {
+ goto L150;
+ }
+ if (sw0001 == 92) {
+ goto L250;
+ }
+ if (sw0001 == 96) {
+ goto L190;
+ }
+ goto L400;
+L131:
+L111:
+ ++i__;
+ goto L110;
+L112:
+ ip += gstrcy_(st0020, &memc[ip - 1], &c__1023);
+ amovc_(&memc[buf - 1], &str[1], maxch);
+ sfree_(&sp);
+/* L100: */
+ zzepro_();
+ return 0;
+} /* lhesce_ */
+
+#undef memx
+#undef mems
+#undef memr
+#undef meml
+#undef memi
+#undef memc
+#undef memb
+
+
+/* Subroutine */ int lhsetl_(n, level)
+integer *n;
+shortint *level;
+{
+ /* Initialized data */
+
+ static shortint st0001[4] = { 37,100,46,0 };
+
+ /* System generated locals */
+ integer i__1;
+
+ /* Local variables */
+ static integer i__;
+ extern /* Subroutine */ int pargi_(), amovki_(), sprinf_(), zzepro_();
+ extern integer xstrln_();
+
+ /* Parameter adjustments */
+ --level;
+
+ /* Function Body */
+ ++lrfcom_1.nhlevl[(60 + (0 + (*n - 1 << 2)) - 60) / 4];
+ i__1 = 10 - *n;
+ amovki_(&c__0, &lrfcom_1.nhlevl[*n], &i__1);
+ level[1] = 0;
+ i__1 = *n;
+ for (i__ = 1; i__ <= i__1; ++i__) {
+ sprinf_(&level[xstrln_(&level[1]) + 1], &c__2046, st0001);
+ pargi_(&lrfcom_1.nhlevl[i__ - 1]);
+/* L110: */
+ }
+/* L111: */
+ if (! (*n > 1 && level[xstrln_(&level[1])] == 46)) {
+ goto L120;
+ }
+ level[xstrln_(&level[1])] = 0;
+L120:
+/* L100: */
+ zzepro_();
+ return 0;
+} /* lhsetl_ */
+
+integer lhfink_(fd, formad, param)
+integer *fd;
+logical *formad;
+shortint *param;
+{
+ /* Initialized data */
+
+ static shortint st0001[5] = { 123,37,115,125,0 };
+ static shortint st0002[7] = { 94,46,123,108,115,125,0 };
+ static shortint st0003[7] = { 94,35,123,37,115,125,0 };
+
+ /* System generated locals */
+ integer ret_val;
+
+ /* Local variables */
+ static integer sp, len;
+#define memb ((logical *)&mem_1)
+#define memc ((shortint *)&mem_1)
+#define memi ((integer *)&mem_1)
+ static integer lbuf;
+#define meml ((integer *)&mem_1)
+#define memr ((real *)&mem_1)
+#define mems ((shortint *)&mem_1)
+#define memx ((complex *)&mem_1)
+ extern /* Subroutine */ int sfree_(), smark_();
+ static logical matchd;
+ extern integer getlie_();
+ extern /* Subroutine */ int salloc_(), ungete_();
+ static integer patten;
+ extern integer strmah_();
+ extern /* Subroutine */ int pargsr_(), sprinf_(), zzepro_();
+ extern integer xstrln_();
+
+ /* Parameter adjustments */
+ --param;
+
+ /* Function Body */
+ smark_(&sp);
+ salloc_(&patten, &c__255, &c__2);
+ salloc_(&lbuf, &c__1023, &c__2);
+ matchd = FALSE_;
+ if (! (getlie_(fd, &memc[lbuf - 1]) == -2) && ! xercom_1.xerflg) {
+ goto L110;
+ }
+ if (xercom_1.xerflg) {
+ goto L100;
+ }
+ goto L90;
+L110:
+ if (! (*formad)) {
+ goto L120;
+ }
+ sprinf_(&memc[patten - 1], &c__255, st0001);
+ pargsr_(&param[1]);
+L130:
+ if (! (strmah_(&memc[lbuf - 1], st0002) > 0)) {
+ goto L140;
+ }
+ if (! (strmah_(&memc[lbuf - 1], &memc[patten - 1]) > 0)) {
+ goto L150;
+ }
+ matchd = TRUE_;
+ goto L132;
+L150:
+L140:
+/* L131: */
+ if (! (getlie_(fd, &memc[lbuf - 1]) == -2) && ! xercom_1.xerflg) {
+ goto L130;
+ }
+ if (xercom_1.xerflg) {
+ goto L100;
+ }
+L132:
+ goto L121;
+L120:
+ sprinf_(&memc[patten - 1], &c__255, st0003);
+ pargsr_(&param[1]);
+L160:
+ if (! (strmah_(&memc[lbuf - 1], &memc[patten - 1]) > 0)) {
+ goto L170;
+ }
+ matchd = TRUE_;
+ goto L162;
+L170:
+/* L161: */
+ if (! (getlie_(fd, &memc[lbuf - 1]) == -2) && ! xercom_1.xerflg) {
+ goto L160;
+ }
+ if (xercom_1.xerflg) {
+ goto L100;
+ }
+L162:
+L121:
+ ungete_(fd, &memc[lbuf - 1]);
+L90:
+ len = xstrln_(&memc[lbuf - 1]);
+ sfree_(&sp);
+ if (! matchd) {
+ goto L180;
+ }
+ ret_val = len;
+ goto L100;
+L180:
+ ret_val = -2;
+ goto L100;
+/* L181: */
+L100:
+ zzepro_();
+ return ret_val;
+} /* lhfink_ */
+
+#undef memx
+#undef mems
+#undef memr
+#undef meml
+#undef memi
+#undef memc
+#undef memb
+
+
+integer lhfinn_(fd, formad, sectis)
+integer *fd;
+logical *formad;
+shortint *sectis;
+{
+ /* Initialized data */
+
+ static shortint st0001[7] = { 94,46,123,105,104,125,0 };
+ static shortint st0002[5] = { 46,105,104,10,0 };
+
+ /* System generated locals */
+ integer ret_val, i__1, i__2;
+
+ /* Local variables */
+ static integer ip, op, sp;
+#define memb ((logical *)&mem_1)
+#define memc ((shortint *)&mem_1)
+#define memi ((integer *)&mem_1)
+ static shortint lbuf[1024];
+#define meml ((integer *)&mem_1)
+ static integer sw0001;
+#define memr ((real *)&mem_1)
+#define mems ((shortint *)&mem_1)
+ static integer npat;
+#define memx ((complex *)&mem_1)
+ extern /* Subroutine */ int sfree_(), smark_();
+ static logical matchd;
+ extern integer getlie_();
+ extern logical lhmath_();
+ static integer patoff[10];
+ extern /* Subroutine */ int salloc_();
+ static integer patbuf;
+ extern /* Subroutine */ int ungete_();
+ extern integer strmah_();
+ extern /* Subroutine */ int zzepro_();
+
+ /* Parameter adjustments */
+ --sectis;
+
+ /* Function Body */
+ smark_(&sp);
+ salloc_(&patbuf, &c__1023, &c__2);
+ npat = 1;
+ op = patbuf;
+ patoff[0] = op;
+ if (! (getlie_(fd, lbuf) == -2) && ! xercom_1.xerflg) {
+ goto L110;
+ }
+ if (xercom_1.xerflg) {
+ goto L100;
+ }
+ goto L91;
+L110:
+ ip = 1;
+L120:
+ if (! (sectis[ip] != 0)) {
+ goto L122;
+ }
+ sw0001 = sectis[ip];
+ goto L130;
+L140:
+ memc[op - 1] = 0;
+ ++op;
+/* Computing MIN */
+ i__1 = 10, i__2 = npat + 1;
+ npat = min(i__1,i__2);
+ patoff[npat - 1] = op;
+ goto L131;
+L150:
+ memc[op - 1] = sectis[ip];
+ ++op;
+ goto L131;
+L130:
+ if (sw0001 == 124) {
+ goto L140;
+ }
+ goto L150;
+L131:
+/* L121: */
+ ++ip;
+ goto L120;
+L122:
+ memc[op - 1] = 0;
+ matchd = FALSE_;
+ if (! (*formad)) {
+ goto L160;
+ }
+L170:
+ if (! (strmah_(lbuf, st0001) > 0)) {
+ goto L180;
+ }
+ if (! (getlie_(fd, lbuf) != -2) && ! xercom_1.xerflg) {
+ goto L190;
+ }
+ if (xercom_1.xerflg) {
+ goto L100;
+ }
+ matchd = lhmath_(lbuf, patoff, &npat);
+ if (! matchd) {
+ goto L200;
+ }
+ goto L172;
+L200:
+L190:
+L180:
+/* L171: */
+ if (! (getlie_(fd, lbuf) == -2) && ! xercom_1.xerflg) {
+ goto L170;
+ }
+ if (xercom_1.xerflg) {
+ goto L100;
+ }
+L172:
+ ungete_(fd, lbuf);
+ ungete_(fd, st0002);
+ goto L161;
+L160:
+L210:
+ matchd = lhmath_(lbuf, patoff, &npat);
+ if (! matchd) {
+ goto L220;
+ }
+ goto L212;
+L220:
+/* L211: */
+ if (! (getlie_(fd, lbuf) == -2) && ! xercom_1.xerflg) {
+ goto L210;
+ }
+ if (xercom_1.xerflg) {
+ goto L100;
+ }
+L212:
+ ungete_(fd, lbuf);
+L161:
+L91:
+ sfree_(&sp);
+ if (! matchd) {
+ goto L230;
+ }
+ ret_val = 0;
+ goto L100;
+L230:
+ ret_val = -2;
+ goto L100;
+/* L231: */
+L100:
+ zzepro_();
+ return ret_val;
+} /* lhfinn_ */
+
+#undef memx
+#undef mems
+#undef memr
+#undef meml
+#undef memi
+#undef memc
+#undef memb
+
+
+logical lhmath_(lbuf, patoff, npat)
+shortint *lbuf;
+integer *patoff, *npat;
+{
+ /* Initialized data */
+
+ static shortint st0001[6] = { 94,123,37,115,125,0 };
+
+ /* System generated locals */
+ logical ret_val;
+
+ /* Local variables */
+ static integer sp, pat;
+#define memb ((logical *)&mem_1)
+#define memc ((shortint *)&mem_1)
+#define memi ((integer *)&mem_1)
+#define meml ((integer *)&mem_1)
+#define memr ((real *)&mem_1)
+#define mems ((shortint *)&mem_1)
+#define memx ((complex *)&mem_1)
+ extern /* Subroutine */ int sfree_(), smark_(), salloc_();
+ static integer patten;
+ extern integer strmah_();
+ extern /* Subroutine */ int pargsr_(), sprinf_(), zzepro_();
+
+ /* Parameter adjustments */
+ --lbuf;
+ --patoff;
+
+ /* Function Body */
+ smark_(&sp);
+ salloc_(&patten, &c__255, &c__2);
+ pat = 1;
+L110:
+ if (! (pat <= *npat)) {
+ goto L112;
+ }
+ sprinf_(&memc[patten - 1], &c__255, st0001);
+ pargsr_(&memc[patoff[pat] - 1]);
+ if (! (strmah_(&lbuf[1], &memc[patten - 1]) > 0)) {
+ goto L120;
+ }
+ sfree_(&sp);
+ ret_val = TRUE_;
+ goto L100;
+L120:
+/* L111: */
+ ++pat;
+ goto L110;
+L112:
+ sfree_(&sp);
+ ret_val = FALSE_;
+ goto L100;
+L100:
+ zzepro_();
+ return ret_val;
+} /* lhmath_ */
+
+#undef memx
+#undef mems
+#undef memr
+#undef meml
+#undef memi
+#undef memc
+#undef memb
+
+
+/* Subroutine */ int lhmkne_(instr, outstr)
+shortint *instr, *outstr;
+{
+ static integer i__;
+ extern /* Subroutine */ int zzepro_(), xstrcy_(), strlwr_();
+
+ /* Parameter adjustments */
+ --outstr;
+ --instr;
+
+ /* Function Body */
+ xstrcy_(&instr[1], &outstr[1], &c__1023);
+ strlwr_(&outstr[1]);
+ i__ = 1;
+L110:
+ if (! (i__ < 1023)) {
+ goto L112;
+ }
+ if (! (outstr[i__] == 0 || outstr[i__] == 10)) {
+ goto L120;
+ }
+ goto L112;
+L120:
+ if (outstr[i__] >= 65 && outstr[i__] <= 90 || outstr[i__] >= 97 && outstr[
+ i__] <= 122 || outstr[i__] >= 48 && outstr[i__] <= 57) {
+ goto L130;
+ }
+ outstr[i__] = 95;
+L130:
+/* L121: */
+/* L111: */
+ ++i__;
+ goto L110;
+L112:
+/* L100: */
+ zzepro_();
+ return 0;
+} /* lhmkne_ */
+
diff --git a/pkg/system/help/lroff/lroff2html.x b/pkg/system/help/lroff/lroff2html.x
new file mode 100644
index 00000000..1e3815ae
--- /dev/null
+++ b/pkg/system/help/lroff/lroff2html.x
@@ -0,0 +1,781 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include "lroff.h"
+
+define DIRECTIVE 1 # processing codes
+define NAME 2
+define TEXT 3
+
+define F_ROMAN 1 # font changes
+define F_ITALIC 2
+define F_BOLD 3
+define F_PREVIOUS 4
+define F_TELETYPE 5 # HTML-specific font
+
+define SPTR Memi[$1+$2]
+define SECTION Memc[SPTR($1,$2)]
+define MAX_SECTIONS 256
+
+
+# LROFF2HTML -- Convert LROFF text to HTML. By default we process the
+# entire file however we allow for the printing of only a particular section
+# or labelled text block to be compatible with the HELP task options.
+# If a section name is given that section will be printed and and .ls
+# block request will be ignored.
+
+procedure lroff2html (in, out, module, parstr, center, ls_block, section)
+
+int in #I input file descriptor
+int out #I output file descriptor
+char module[ARB] #I .help module name
+char parstr[ARB] #I .help optional keyword 2
+char center[ARB] #I .help optional keyword 3
+char ls_block[ARB] #I .ls block to search for
+char section[ARB] #I section to print
+
+pointer sp, ip, sptr
+pointer ibuf, unesc, name, level
+int lastline, font, indented, ls_level
+int i, arg, nsec, cmd
+bool format, quit_at_le, quit_at_ih, formatted
+
+int lh_findsection(), lh_findblock(), nextcmd()
+int stridxs(), getline(), strlen(), strmatch(), lgetarg()
+
+define text_ 99
+define err_ 98
+
+include "lroff.com"
+
+begin
+ call smark (sp)
+ call salloc (ibuf, SZ_IBUF, TY_CHAR)
+ call salloc (unesc, SZ_IBUF, TY_CHAR)
+ call salloc (name, SZ_LINE, TY_CHAR)
+ call salloc (level, SZ_FNAME, TY_CHAR)
+ call salloc (sptr, MAX_SECTIONS, TY_POINTER)
+
+ call aclrc (Memc[ibuf], SZ_IBUF)
+ call aclrc (Memc[name], SZ_LINE)
+ call aclrc (Memc[unesc], SZ_IBUF)
+ call aclrc (Memc[level], SZ_FNAME)
+
+ # Initialize.
+ lastline = TEXT
+ font = F_ROMAN
+ indented = YES
+ nsec = 0
+ ls_level = 0
+ format = true
+ quit_at_le = false
+ quit_at_ih = false
+ formatted = false
+
+ # Initialize the section numbering.
+ call amovki (0, nh_level, MAX_NHLEVEL)
+
+ # Determine whether or not the text is formatted.
+ repeat {
+ if (getline (in, Memc[ibuf]) == EOF)
+ goto err_
+ for (ip=1; IS_WHITE(Memc[ibuf+ip-1]); ip=ip+1)
+ ;
+ } until (Memc[ibuf+ip-1] != '\n')
+ call ungetline (in, Memc[ibuf])
+ if (Memc[ibuf] == '.')
+ formatted = true
+
+ # Scan forward if searching for and item.
+ if (section[1] != EOS) {
+ if (lh_findsection (in, formatted, section) == EOF)
+ goto err_
+ } else if (ls_block[1] != EOS) {
+ if (lh_findblock (in, formatted, ls_block) == EOF)
+ goto err_
+ quit_at_le = true
+ }
+
+ # Begin the output.
+ call lh_prolog (out, module, parstr, center)
+ call fprintf (out, "<TITLE>%s</TITLE>\n<UL>\n")
+ if (ls_block[1] != EOS)
+ call pargstr (ls_block)
+ else if (section[1] != EOS)
+ call pargstr (section)
+ else if (module[1] != EOS)
+ call pargstr (module)
+ else
+ call pargstr (" ")
+
+
+ # Process the file.
+ while (getline (in, Memc[ibuf]) != EOF) {
+
+ # Make a copy of the raw line minus the newline char, we may need
+ # this to extract comments later.
+ Memc[ibuf+strlen(Memc[ibuf])-1] = EOS
+ call strcpy (Memc[ibuf], Memc[unesc], SZ_LINE)
+
+
+ # Escape problem chars for HTML and handle font changes. Changes
+ # are done in-place.
+ call lh_escape (Memc[ibuf], font, format, NO, SZ_LINE)
+
+ switch (Memc[ibuf]) {
+ case '\n':
+ call fprintf (out, "<P>\n")
+
+ case '.':
+ # Swallow any help strings if present.
+ if (strmatch (Memc[ibuf], "^.help") > 0)
+ next
+
+ ip = 1
+ lastline = TEXT
+
+ # Process the directive, position the ip at the beginning
+ # of any argument.
+ cmd = nextcmd (Memc[ibuf], ip)
+ while (IS_WHITE(Memc[ibuf+ip])) # skip spaces
+ ip = ip + 1
+
+ switch (cmd) {
+ case FI: # enter fill mode
+ call fprintf (out, "</PRE>\n")
+ format = true
+ case NF: # leave fill mode (nofill)
+ call fprintf (out, "<PRE>\n")
+ format = false
+ case JU: # enter line justification mode
+ # no-op
+ next
+ case NJ: # leave line justification mode
+ # no-op
+ next
+ case RJ: # right justify text on nf,nj line
+ # no-op
+ next
+
+ case SH: # section heading
+ if (ls_level > 0) { # for missing .le statements
+ call fprintf (out, "</DD>\n</DL>\n")
+ ls_level = 0
+ }
+ lastline = DIRECTIVE
+ Memc[level] = EOS
+ next
+ case IH: # indented section heading
+ if (ls_level > 0) { # for missing .le statements
+ call fprintf (out, "</DD>\n</DL>\n")
+ ls_level = 0
+ }
+ lastline = DIRECTIVE
+ Memc[level] = EOS
+ if (quit_at_ih)
+ if (stridxs ("|", section) > 0) {
+ quit_at_ih = false
+ call ungetline (in, Memc[ibuf])
+ if (lh_findsection (in, formatted, section) == EOF)
+ break
+ } else
+ break
+ next
+ case NH: # numbered section heading
+ if (ls_level > 0) { # for missing .le statements
+ call fprintf (out, "</DD>\n</DL>\n")
+ ls_level = 0
+ }
+ call lh_set_level (lgetarg(Memc[ibuf],ip,1), Memc[level])
+ lastline = DIRECTIVE
+ next
+
+ case CE: # center next line
+ if (getline (in, Memc[ibuf]) == EOF)
+ break
+ else {
+ call lh_escape (Memc[ibuf], font, true, NO, SZ_LINE)
+ call fprintf (out, "<CENTER>%s</CENTER><BR>\n")
+ call pargstr (Memc[ibuf])
+ }
+
+ case BR: # break line
+ call fprintf (out, "<BR>\n")
+ case SP: # break, space N spaces on output
+ arg = lgetarg (Memc[ibuf], ip, 1)
+ call fprintf (out, "<BR>\n")
+ for (i=1; i < arg; i = i + 1)
+ call fprintf (out, "<BR>\n")
+ case IN: # indent +/- N spaces
+ # no-op
+ next
+
+ case LS: # begin labelled section
+ arg = lgetarg (Memc[ibuf], ip, 0)
+ if (arg == 0)
+ ip = 5
+
+ # Generate a HREF of the label, we use only the first word.
+ call strcpy (Memc[ibuf+ip-1], Memc[name], SZ_LINE)
+ for (i=0; IS_ALNUM(Memc[name+i]) ||
+ Memc[name+i] == '_'; i=i+1)
+ ;
+ Memc[name+i] = EOS
+ Memc[ibuf+ip+strlen(Memc[ibuf+ip])-1] = EOS
+
+ call fprintf (out, "<DL>\n<DT><B>")
+ call fprintf (out,"<A NAME=\"l_%s\">%s</A>")
+ call pargstr (Memc[name])
+ call pargstr (Memc[ibuf+ip-1])
+ call fprintf (out, "</B></DT>\n")
+
+ # Write out a comment line for the GUI to use.
+ call lh_escape(Memc[unesc+ip-1], font, true, YES, SZ_LINE)
+ Memc[unesc+strlen(Memc[unesc])-1] = EOS
+ call fprintf (out,
+ "<! Sec=%s Level=%d Label=\'%s\' Line=\'%s\'>\n<DD>")
+ if (nsec > 0)
+ call pargstr (SECTION(sptr, nsec-1))
+ else
+ call pargstr ("None")
+ call pargi (ls_level)
+ call pargstr (Memc[name])
+ if (Memc[unesc+ip-1] == '\n')
+ call pargstr (" ")
+ else
+ call pargstr (Memc[unesc+ip-1])
+ ls_level = ls_level + 1
+
+ case LE: # end labelled section
+ call fprintf (out, "</DD>\n</DL>\n")
+ ls_level = ls_level - 1
+ if (quit_at_le)
+ break
+
+ case HR: # HREF anchor
+ # HTML href anchor of the form ".hr <href> <anch_text>",
+ # we skip ahead to the <text> and process as a normal line.
+ Memc[ibuf+ip+strlen(Memc[ibuf+ip])-1] = EOS
+ for (i=0; !IS_WHITE(Memc[ibuf+ip]); ip=ip+1) {
+ Memc[name+i] = Memc[ibuf+ip]
+ i = i + 1
+ }
+ Memc[name+i] = EOS
+
+ call fprintf (out, "<A HREF=\"%s\">%s</A>\n")
+ call pargstr (Memc[name])
+ call pargstr (Memc[ibuf+ip+1])
+
+ case HN: # NAME target
+ # HTML name target of the form ".hn <name>", strip the
+ # newline added in the escape routine.
+ Memc[ibuf+ip+strlen(Memc[ibuf+ip])-1] = EOS
+ call fprintf (out, "<A NAME=\"%s\"></A>\n")
+ call pargstr (Memc[ibuf+ip])
+
+ case BP: # break page
+ # no-op
+ next
+ case TP: # test space left on page
+ # no-op
+ next
+ case KS: # start floating keep
+ call fprintf (out, "<PRE>\n")
+ format = false
+ case KE: # end floating keep
+ call fprintf (out, "</PRE>\n")
+ format = true
+ case ENDHELP: # end of help block
+ break
+ }
+
+ default:
+ if (lastline == DIRECTIVE) {
+
+ # Section directive name. For certain standard sections
+ # we'll force an indention to make the output look better,
+ # everything else gets written normally.
+
+ # Save the section name.
+ call salloc (SPTR(sptr,nsec), SZ_LINE, TY_CHAR)
+ call aclrc (SECTION(sptr,nsec), SZ_LINE)
+ Memc[ibuf+strlen(Memc[ibuf])-1] = EOS
+ call sprintf (SECTION(sptr,nsec), SZ_LINE, "\'%s\'")
+ call pargstr (Memc[ibuf])
+
+ if (indented == YES)
+ call fprintf (out, "</UL>\n")
+ if (nsec > 0) {
+ call fprintf (out, "<! EndSection: %s>\n")
+ call pargstr (SECTION(sptr,nsec-1))
+ }
+
+ # Make the section name a URL target.
+ call lh_mkname (Memc[ibuf], Memc[name])
+ if (Memc[level] == EOS) {
+ call fprintf (out, "<H2><A NAME=\"s_%s\">%s</A></H2>\n")
+ call pargstr (Memc[name])
+ call pargstr (Memc[ibuf])
+ } else {
+ call fprintf (out,
+ "<H2><A NAME=\"s_%s\">%s %s</A></H2>\n")
+ call pargstr (Memc[name])
+ call pargstr (Memc[level])
+ call pargstr (Memc[ibuf])
+ Memc[level] = EOS
+ }
+
+ call fprintf (out, "<! BeginSection: \'%s\'>\n")
+ call pargstr (Memc[ibuf])
+ if (indented == YES)
+ call fprintf (out, "<UL>\n")
+
+ lastline = NAME
+ nsec = nsec + 1
+ if (section[1] != EOS)
+ quit_at_ih = true
+
+ } else {
+ # Ordinary text line.
+text_ call fprintf (out, "%s")
+ call pargstr (Memc[ibuf])
+ lastline = TEXT
+ }
+ }
+
+ call aclrc (Memc[ibuf], SZ_IBUF)
+ call aclrc (Memc[unesc], SZ_IBUF)
+ call aclrc (Memc[name], SZ_LINE)
+ }
+
+ # Close the last section.
+ if (nsec > 0) {
+ call fprintf (out, "</UL>\n<! EndSection: %s>\n\n")
+ call pargstr (SECTION(sptr,nsec-1))
+ }
+
+ # Write out an HTML comment giving the document section names.
+ call fprintf (out, "<! Contents: ")
+ for (i=0; i < nsec; i=i+1) {
+ call fprintf (out, "%s ")
+ call pargstr (SECTION(sptr,i))
+ }
+ call fprintf (out, " >\n\n")
+ call fprintf (out, "</BODY>\n</HTML>\n")
+
+ call flush (out)
+err_ call sfree (sp)
+end
+
+
+# LH_PROLOG -- Begin the HTML output, print the header table for a help
+# page if we have the information.
+
+procedure lh_prolog (fd, mod, date, title)
+
+int fd #I output file descriptor
+char mod[ARB] #I .help module name
+char date[ARB] #I .help keyword 2
+char title[ARB] #I .help keyword 3
+
+begin
+ call fprintf (fd, "<HTML>\n<BODY>\n")
+
+ # If we only have the module name don't bother with header.
+ if (date[1] == EOS && title[1] == EOS)
+ return
+
+ # Begin the HTML output prolog.
+ call fprintf (fd, "<TABLE WIDTH=\"100%%\" BORDER=0><TR>\n")
+
+ # Left side page header.
+ call fprintf (fd, "<TD ALIGN=LEFT><FONT SIZE=4>\n")
+ if (date[1] == EOS) {
+ call fprintf (fd, "<B>%s</B>")
+ call pargstr (mod)
+ } else {
+ call fprintf (fd, "<B>%s (%s)</B>")
+ call pargstr (mod)
+ call pargstr (date)
+ }
+ call fprintf (fd, "</FONT></TD>\n")
+
+ # Center page header.
+ if (title[1] != EOS) {
+ call fprintf (fd, "<TD ALIGN=CENTER><FONT SIZE=4>\n")
+ call fprintf (fd, "<B>%s</B>\n")
+ call pargstr (title)
+ call fprintf (fd, "</FONT></TD>\n")
+ }
+
+ # Right side page header.
+ call fprintf (fd, "<TD ALIGN=RIGHT><FONT SIZE=4>\n")
+ if (date[1] == EOS) {
+ call fprintf (fd, "<B>%s</B>")
+ call pargstr (mod)
+ } else {
+ call fprintf (fd, "<B>%s (%s)</B>")
+ call pargstr (mod)
+ call pargstr (date)
+ }
+ call fprintf (fd, "</FONT></TD>\n")
+
+ call fprintf (fd, "</TR></TABLE><P>\n")
+end
+
+
+# LH_ESCAPE -- Escape any HTML problem characters in the line ('<','>','&')
+# as well as the font changes.
+
+procedure lh_escape (str, font, format, special_only, maxch)
+
+char str[ARB] #I string to edit
+int font #U current font
+bool format #I formatting flag
+int special_only #I escape only special chars?
+int maxch #I max length of string
+
+pointer sp, ip, buf, keyword
+int i, gstrcpy(), stridx()
+
+define copy_ 90
+
+begin
+ call smark (sp)
+ call salloc (buf, maxch, TY_CHAR)
+ call salloc (keyword, maxch, TY_CHAR)
+ call aclrc (Memc[buf], maxch)
+ call aclrc (Memc[keyword], maxch)
+
+ ip = buf
+ for (i=1; str[i] != EOS && i <= maxch; i = i + 1) {
+
+ if (special_only == YES && stridx (str[i], "<>&") == 0)
+ goto copy_
+
+ switch (str[i]) {
+
+ # Handle special chars.
+ case '<':
+ ip = ip + gstrcpy ("&lt;", Memc[ip], SZ_LINE)
+ case '>':
+ ip = ip + gstrcpy ("&gt;", Memc[ip], SZ_LINE)
+ case '&':
+ ip = ip + gstrcpy ("&amp;", Memc[ip], SZ_LINE)
+
+ # Quoted single chars and strings get a special font.
+ case '\'':
+ if (str[i+2] == '\'') {
+ ip = ip + gstrcpy ("<TT>", Memc[ip], SZ_LINE)
+ ip = ip + gstrcpy (str[i], Memc[ip], 3)
+ ip = ip + gstrcpy ("</TT>", Memc[ip], SZ_LINE)
+ i = i + 2
+ } else
+ goto copy_
+ case '`':
+ if (str[i+2] == '`' || str[i+2] == '\'') {
+ ip = ip + gstrcpy ("<TT>", Memc[ip], SZ_LINE)
+ ip = ip + gstrcpy (str[i], Memc[ip], 3)
+ ip = ip + gstrcpy ("</TT>", Memc[ip], SZ_LINE)
+ i = i + 2
+ } else
+ goto copy_
+ case '"':
+ if (format && str[i+1] != '/' && str[i+2] != '/') {
+ if (font == F_TELETYPE) {
+ # Do a closing quote.
+ ip = ip + gstrcpy ("</TT>\"", Memc[ip], SZ_LINE)
+ font = F_ROMAN
+ } else if (font == F_ROMAN) {
+ # Do an opening quote.
+ ip = ip + gstrcpy ("\"<TT>", Memc[ip], SZ_LINE)
+ font = F_TELETYPE
+ } else
+ goto copy_
+ } else
+ goto copy_
+
+ # Process font changes.
+ case '\\':
+ if (str[i+1] == 'f') {
+ if (str[i+2] == 'B') {
+ if (font == F_BOLD)
+ next
+ if (font == F_ITALIC)
+ ip = ip + gstrcpy ("</I>", Memc[ip], SZ_LINE)
+ ip = ip + gstrcpy ("<B>", Memc[ip], SZ_LINE)
+ font = F_BOLD
+
+ } else if (str[i+2] == 'I') {
+ if (font == F_ITALIC)
+ next
+ if (font == F_BOLD)
+ ip = ip + gstrcpy ("</B>", Memc[ip], SZ_LINE)
+ ip = ip + gstrcpy ("<I>", Memc[ip], SZ_LINE)
+ font = F_ITALIC
+
+ } else if (str[i+2] == 'R') {
+ if (font == F_BOLD)
+ ip = ip + gstrcpy ("</B>", Memc[ip], SZ_LINE)
+ else if (font == F_ITALIC)
+ ip = ip + gstrcpy ("</I>", Memc[ip], SZ_LINE)
+ font = F_ROMAN
+
+ } else if (str[i+2] == 'P') {
+ if (font == F_BOLD) {
+ ip = ip + gstrcpy ("</B>", Memc[ip], SZ_LINE)
+ } else if (font == F_ITALIC) {
+ ip = ip + gstrcpy ("</I>", Memc[ip], SZ_LINE)
+ }
+ font = F_ROMAN
+ }
+ i = i + 2
+ } else if (str[i+1] == '\n' || str[i+1] == EOS) {
+ Memc[ip] = str[i]
+ ip = ip + 1
+ i = i + 1
+ ip = ip + gstrcpy ("<BR>", Memc[ip], SZ_LINE)
+ } else
+ goto copy_
+
+ default:
+copy_ Memc[ip] = str[i]
+ ip = ip + 1
+ }
+ }
+
+ # Add the trailing newline we stripped above.
+ ip = ip + gstrcpy ("\n\0", Memc[ip], SZ_LINE)
+
+ # Move the string back.
+ call amovc (Memc[buf], str, maxch)
+
+ call sfree (sp)
+end
+
+
+# LH_SET_LEVEL -- Increment the level number of a numbered header.
+
+procedure lh_set_level (n, level)
+
+int n #I level number
+char level[ARB] #U level string
+
+int i, strlen()
+include "lroff.com"
+
+begin
+ # Increment the desired section number; zero all higher
+ # numbered section counters.
+ nh_level[n] = nh_level[n] + 1
+ call amovki (0, nh_level[n+1], MAX_NHLEVEL - n)
+
+ # Output the section number followed by a blank and then
+ # the section label.
+ level[1] = EOS
+ do i = 1, n {
+ call sprintf (level[strlen(level)+1], SZ_IBUF, "%d.")
+ call pargi (nh_level[i])
+ }
+
+ # Cancel the final "." if subsection heading. Add a blank.
+ if (n > 1 && level[strlen(level)] == '.')
+ level[strlen(level)] = EOS
+end
+
+
+# LH_FINDBLOCK -- If text contains format directives, eat input lines until
+# a ".ls" directive is found which contains the block name as a substring.
+# If the text is not formatted, search for a line beginning with the pattern.
+
+int procedure lh_findblock (fd, formatted, param)
+
+int fd
+bool formatted
+char param[ARB]
+
+bool match_found
+pointer sp, lbuf, pattern
+int len
+int getline(), strmatch(), strlen()
+errchk getline
+
+define err_ 90
+
+begin
+ call smark (sp)
+ call salloc (pattern, SZ_FNAME, TY_CHAR)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+
+ match_found = false
+
+ # Get the first line.
+ if (getline (fd, Memc[lbuf]) == EOF)
+ goto err_
+
+ if (formatted) {
+ call sprintf (Memc[pattern], SZ_FNAME, "{%s}")
+ call pargstr (param)
+ repeat {
+ if (strmatch (Memc[lbuf], "^.{ls}") > 0)
+ if (strmatch (Memc[lbuf], Memc[pattern]) > 0) {
+ match_found = true
+ break
+ }
+ } until (getline (fd, Memc[lbuf]) == EOF)
+
+ } else {
+ call sprintf (Memc[pattern], SZ_FNAME, "^#{%s}")
+ call pargstr (param)
+ repeat {
+ if (strmatch (Memc[lbuf], Memc[pattern]) > 0) {
+ match_found = true
+ break
+ }
+ } until (getline (fd, Memc[lbuf]) == EOF)
+ }
+ call ungetline (fd, Memc[lbuf])
+
+err_ len = strlen (Memc[lbuf])
+ call sfree (sp)
+ if (match_found)
+ return (len)
+ else
+ return (EOF)
+end
+
+
+# LH_FINDSECTION -- If text contains format directives, eat input lines until
+# a ".ih" directive is found for the named section. If the text is not
+# formatted, search for a line beginning with the section name.
+
+define MAXPAT 10
+
+int procedure lh_findsection (fd, formatted, sections)
+
+int fd # input file
+bool formatted # is help block formatted
+char sections[ARB] # list of sections "a|b|c"
+
+bool match_found
+int npat, ip
+pointer sp, patbuf, patoff[MAXPAT], op
+char lbuf[SZ_LINE]
+
+bool lh_match()
+int getline(), strmatch()
+errchk getline
+
+define err_ 91
+
+begin
+ call smark (sp)
+ call salloc (patbuf, SZ_LINE, TY_CHAR)
+
+ # Process the list of sections into patbuf and patoff, i.e., into a
+ # list of EOS delimited strings in the string buffer patbuf. Each
+ # section name or abbreviation is delimited by '|' (or).
+
+ npat = 1
+ op = patbuf
+ patoff[1] = op
+
+ # Get the first line.
+ if (getline (fd, lbuf) == EOF)
+ goto err_
+
+ for (ip=1; sections[ip] != EOS; ip=ip+1)
+ switch (sections[ip]) {
+ case '|':
+ Memc[op] = EOS
+ op = op + 1
+ npat = min (MAXPAT, npat + 1)
+ patoff[npat] = op
+ default:
+ Memc[op] = sections[ip]
+ op = op + 1
+ }
+ Memc[op] = EOS
+
+ match_found = false
+
+ if (formatted) {
+ repeat {
+ if (strmatch (lbuf, "^.{ih}") > 0)
+ if (getline (fd, lbuf) != EOF) {
+ match_found = lh_match (lbuf, patoff, npat)
+ if (match_found)
+ break
+ }
+ } until (getline (fd, lbuf) == EOF)
+ call ungetline (fd, lbuf)
+ call ungetline (fd, ".ih\n")
+
+ } else {
+ repeat {
+ match_found = lh_match (lbuf, patoff, npat)
+ if (match_found)
+ break
+ } until (getline (fd, lbuf) == EOF)
+ call ungetline (fd, lbuf)
+ }
+
+err_ call sfree (sp)
+ if (match_found)
+ return (OK)
+ else
+ return (EOF)
+end
+
+
+# LH_MATCH -- Match a set of patterns against a line of test, matching only
+# at the beginning of line in either case.
+
+bool procedure lh_match (lbuf, patoff, npat)
+
+char lbuf[ARB] # line of text
+pointer patoff[npat] # pointers to pattern strings
+int npat # number of patterns
+
+int pat
+pointer sp, pattern
+int strmatch()
+
+begin
+ call smark (sp)
+ call salloc (pattern, SZ_FNAME, TY_CHAR)
+
+ for (pat=1; pat <= npat; pat=pat+1) {
+ call sprintf (Memc[pattern], SZ_FNAME, "^{%s}")
+ call pargstr (Memc[patoff[pat]])
+ if (strmatch (lbuf, Memc[pattern]) > 0) {
+ call sfree (sp)
+ return (true)
+ }
+ }
+
+ call sfree (sp)
+ return (false)
+end
+
+
+# LH_MKNAME -- Given a string make it suitable for use as an HREF name.
+
+procedure lh_mkname (instr, outstr)
+
+char instr[ARB]
+char outstr[ARB]
+
+int i
+
+begin
+ # Make it a URL. First convert the section name to a
+ # lower-case string and replace the blanks.
+ call strcpy (instr, outstr, SZ_LINE)
+ call strlwr (outstr)
+ for (i=1; i < SZ_LINE; i=i+1)
+ if (outstr[i] == EOS || outstr[i] == '\n')
+ break
+ else if (!IS_ALNUM(outstr[i]))
+ outstr[i] = '_'
+end
diff --git a/pkg/system/help/lroff/lroff2ps.x b/pkg/system/help/lroff/lroff2ps.x
new file mode 100644
index 00000000..a782ca21
--- /dev/null
+++ b/pkg/system/help/lroff/lroff2ps.x
@@ -0,0 +1,460 @@
+include <syserr.h>
+include <ctype.h>
+include <psset.h>
+include "lroff.h"
+
+
+define DIRECTIVE 1 # processing codes
+define NAME 2
+define TEXT 3
+define NEWLINE 4
+
+define INDENT 5 # size of indentitudedness
+
+
+# LROFF2PS -- Convert LROFF text to Postscript. By default we process the
+# entire file however we allow for the printing of only a particular section
+# or labelled text block to be compatible with the HELP task options.
+# If a section name is given that section will be printed and and .ls
+# block request will be ignored.
+
+procedure lroff2ps (in, out, psptr, ls_block, section)
+
+int in #i input file descriptor
+int out #i output file descriptor
+pointer psptr #i PSIO pointer
+char ls_block[ARB] #i .ls block to search for
+char section[ARB] #i section to print
+
+pointer sp, ip, ps
+pointer ibuf, line, level
+int lastline, font, indent, ls_level
+int i, arg, nsec, cmd, last_cmd
+bool format, quit_at_le, quit_at_ih, formatted
+
+pointer ps_open()
+int lh_findsection(), lh_findblock(), nextcmd()
+int stridxs(), getline(), strlen(), strmatch(), lgetarg()
+
+define text_ 99
+define err_ 98
+
+include "lroff.com"
+
+begin
+ call smark (sp)
+ call salloc (ibuf, SZ_IBUF, TY_CHAR)
+ call salloc (line, SZ_LINE, TY_CHAR)
+ call salloc (level, SZ_FNAME, TY_CHAR)
+
+ call aclrc (Memc[ibuf], SZ_LINE)
+ call aclrc (Memc[line], SZ_LINE)
+ call aclrc (Memc[level], SZ_LINE)
+
+ # Initialize.
+ lastline = TEXT
+ font = F_ROMAN
+ indent = 0
+ nsec = 0
+ ls_level = 0
+ format = true
+ quit_at_le = false
+ quit_at_ih = false
+ formatted = false
+
+ # Initialize the section numbering.
+ call amovki (0, nh_level, MAX_NHLEVEL)
+
+ # Determine whether or not the text is formatted.
+ repeat {
+ if (getline (in, Memc[ibuf]) == EOF)
+ goto err_
+ for (ip=1; IS_WHITE(Memc[ibuf+ip-1]); ip=ip+1)
+ ;
+ } until (Memc[ibuf+ip-1] != '\n')
+ call ungetline (in, Memc[ibuf])
+ if (Memc[ibuf] == '.')
+ formatted = true
+
+ # Scan forward if searching for and item.
+ if (section[1] != EOS) {
+ if (lh_findsection (in, formatted, section) == EOF)
+ goto err_
+ } else if (ls_block[1] != EOS) {
+ if (lh_findblock (in, formatted, ls_block) == EOF)
+ goto err_
+ quit_at_le = true
+ }
+
+ # Begin the output is we aren't passed a pointer that may have
+ # already set up headers, page parameters, etc.
+ if (psptr == NULL)
+ ps = ps_open (out, YES)
+ else
+ ps = psptr
+ call ps_write_prolog (ps)
+
+ # Process the file.
+ while (getline (in, Memc[ibuf]) != EOF) {
+
+ # Escape the line, inserting special font changes for quotes
+ # chars and strings.
+ call lp_escape (Memc[ibuf], font, format, SZ_LINE)
+
+ switch (Memc[ibuf]) {
+ case '\n':
+ if (lastline != NEWLINE)
+ call ps_linebreak (ps, NO)
+ call ps_newline (ps)
+ lastline = NEWLINE
+
+ case '.':
+ # Swallow any help strings if present.
+ if (strmatch (Memc[ibuf], "^.{help}") > 0)
+ next
+
+ # Stomp the newline.
+ Memc[ibuf+strlen(Memc[ibuf])-1] = EOS
+
+ # Process the directive, position the ip at the beginning
+ # of any argument.
+ ip = 1
+ cmd = nextcmd (Memc[ibuf], ip)
+ while (IS_WHITE(Memc[ibuf+ip])) # skip spaces
+ ip = ip + 1
+
+ switch (cmd) {
+ case FI, KE: # enter fill mode
+ call ps_setfont (ps, F_ROMAN)
+ call ps_set_justify (ps, YES)
+ lastline = NEWLINE
+ format = true
+ case NF, KS: # leave fill mode (nofill)
+ if (lastline != NEWLINE && last_cmd != KS && last_cmd != NF)
+ call ps_linebreak (ps, NO)
+ call ps_setfont (ps, F_TELETYPE)
+ call ps_set_justify (ps, NO)
+ lastline = NEWLINE
+ format = false
+ case JU: # enter line justification mode
+ call ps_set_justify (ps, YES)
+ next
+ case NJ: # leave line justification mode
+ call ps_set_justify (ps, NO)
+ next
+ case RJ: # right justify text on next line
+ call ps_linebreak (ps, NO)
+ call strcpy (Memc[ibuf+4], Memc[line], SZ_FNAME)
+ Memc[line+strlen(Memc[line])-1] = EOS
+ if (getline (in, Memc[ibuf]) != EOF) {
+ call ps_output (ps, Memc[ibuf], NO)
+ call ps_rightjustify (ps, Memc[line])
+ }
+ next
+
+ case SH: # section heading
+ if (ls_level > 0) { # for missing .le statements
+ ls_level = 0
+ indent = 0
+ }
+ if (nsec > 0) {
+ call ps_linebreak (ps, NO)
+ call ps_linebreak (ps, NO)
+ }
+ lastline = DIRECTIVE
+ Memc[level] = EOS
+ next
+ case IH: # indented section heading
+ if (ls_level > 0) { # for missing .le statements
+ ls_level = 0
+ indent = 0
+ }
+
+ if (nsec > 0)
+ call ps_linebreak (ps, NO)
+ if (lastline == TEXT)
+ call ps_linebreak (ps, NO)
+ lastline = DIRECTIVE
+ Memc[level] = EOS
+ if (quit_at_ih)
+ if (stridxs ("|", section) > 0) {
+ quit_at_ih = false
+ call ungetline (in, Memc[ibuf])
+ if (lh_findsection (in, formatted, section) == EOF)
+ break
+ } else
+ break
+ next
+ case NH: # numbered section heading
+ if (ls_level > 0) { # for missing .le statements
+ ls_level = 0
+ indent = 0
+ }
+ call lh_set_level (lgetarg(Memc[ibuf],ip,1), Memc[level])
+ if (nsec > 0) {
+ call ps_linebreak (ps, NO)
+ call ps_linebreak (ps, NO)
+ }
+ lastline = DIRECTIVE
+ next
+
+ case CE: # center next line
+ if (getline (in, Memc[ibuf]) != EOF) {
+ call lp_escape (Memc[ibuf], font, true, SZ_LINE)
+ call ps_linebreak (ps, NO)
+ call ps_center (ps, Memc[ibuf])
+ }
+
+ case BR: # break line
+ call ps_linebreak (ps, NO)
+ case SP: # break, space N spaces on output
+ arg = lgetarg (Memc[ibuf], ip, 1)
+ call ps_linebreak (ps, NO)
+ for (i=1; i < arg; i = i + 1)
+ call ps_linebreak (ps, NO)
+ case IN: # indent +/- N spaces
+ arg = lgetarg (Memc[ibuf], ip, 0)
+ call ps_indent (ps, arg)
+ next
+
+ case LS: # begin labelled section
+ arg = lgetarg (Memc[ibuf], ip, INDENT)
+ if (arg == 0)
+ ip = 5
+
+ if (lastline == TEXT)
+ call ps_linebreak (ps, NO)
+ call ps_testpage (ps, 2)
+ if (ls_level < 1 || (last_cmd == LS && lastline == TEXT))
+ call ps_linebreak (ps, NO)
+ call ps_spfont (ps, F_BOLD)
+ call ps_output (ps, Memc[ibuf+ip-1], NO)
+ if (strlen (Memc[ibuf+ip-1]) > (INDENT-1))
+ call ps_linebreak (ps, NO)
+ call ps_spfont (ps, NULL)
+ call ps_setfont (ps, F_ROMAN)
+
+ indent = max (0, indent + INDENT)
+ call ps_indent (ps, indent)
+ ls_level = ls_level + 1
+
+ case LE: # end labelled section
+ if (last_cmd != LE || (last_cmd == LE && lastline == TEXT))
+ call ps_linebreak (ps, NO)
+ indent = max (0, indent - INDENT)
+ call ps_indent (ps, indent)
+ ls_level = ls_level - 1
+ lastline = NEWLINE
+ if (quit_at_le)
+ break
+
+ case HR: # HREF anchor
+ # HTML href anchor of the form ".hr <href> <anch_text>",
+ # we skip ahead to the <text> and process as a normal line.
+ for (i=0; !IS_WHITE(Memc[ibuf+ip]); ip=ip+1)
+ i = i + 1
+ call ps_deposit (ps, Memc[ibuf+ip+1])
+
+ case HN: # NAME target
+ # HTML name target of the form ".hn <name>".
+ # no-op
+
+ case BP: # break page
+ call ps_linebreak (ps, NO)
+ call ps_pagebreak (ps)
+ next
+ case TP: # test space left on page
+ # no-op
+ next
+ case ENDHELP: # end of help block
+ break
+ }
+ last_cmd = cmd
+
+ default:
+ # Stomp the newline.
+ Memc[ibuf+strlen(Memc[ibuf])-1] = EOS
+
+ if (lastline == DIRECTIVE) {
+
+ # Section directive name. For certain standard sections
+ # we'll force an indention to make the output look better,
+ # everything else gets written normally.
+
+ indent = max (0, indent - INDENT)
+ call ps_indent (ps, indent)
+
+ call ps_setfont (ps, F_BOLD)
+ call ps_testpage (ps, 3)
+ if (Memc[level] == EOS) {
+ call ps_output (ps, Memc[ibuf], NO)
+ } else {
+ call sprintf (Memc[line], SZ_LINE, "%s %s")
+ call pargstr (Memc[level])
+ call pargstr (Memc[ibuf])
+
+ call ps_output (ps, Memc[line], NO)
+ Memc[level] = EOS
+ }
+ call ps_setfont (ps, F_ROMAN)
+ call ps_linebreak (ps, NO)
+
+ indent = max (0, indent + INDENT)
+ call ps_indent (ps, indent)
+
+ lastline = NAME
+ nsec = nsec + 1
+ if (section[1] != EOS)
+ quit_at_ih = true
+
+ } else {
+ # Ordinary text line.
+text_ if (format) {
+ call ps_deposit (ps, Memc[ibuf])
+ } else {
+ call lp_strdetab (Memc[ibuf], Memc[line], SZ_LINE)
+ call ps_output (ps, Memc[line], NO)
+ call ps_linebreak (ps, NO)
+ }
+ lastline = TEXT
+ }
+ }
+
+ call aclrc (Memc[ibuf], SZ_LINE)
+ call aclrc (Memc[line], SZ_LINE)
+ }
+
+ # Close the last section.
+ call ps_linebreak (ps, NO)
+ call ps_close (ps)
+
+ call flush (out)
+err_ call sfree (sp)
+end
+
+
+# LP_ESCAPE -- Escape any HTML problem characters in the line ('<','>','&')
+# as well as the font changes.
+
+procedure lp_escape (str, font, format, maxch)
+
+char str[ARB] #i string to edit
+int font #u current font
+bool format #i formatting flag
+int maxch #i max length of string
+
+pointer sp, ip, buf, keyword
+int i, strmatch(), gstrcpy()
+bool is_ls
+
+define copy_ 90
+
+begin
+ call smark (sp)
+ call salloc (buf, maxch, TY_CHAR)
+ call salloc (keyword, maxch, TY_CHAR)
+ call aclrc (Memc[buf], maxch)
+ call aclrc (Memc[keyword], maxch)
+
+ ip = buf
+ is_ls = FALSE
+ if (strmatch (str, "^.{ls}") > 0)
+ is_ls = TRUE
+
+ for (i=1; str[i] != EOS && i <= maxch; i = i + 1) {
+
+ switch (str[i]) {
+
+ # Quoted single chars and strings get a special font.
+ case '\'', '`':
+ if (str[i+2] == '`' || str[i+2] == '\'') {
+ if (format)
+ ip = ip + gstrcpy ("\\fT", Memc[ip], SZ_LINE)
+ ip = ip + gstrcpy (str[i], Memc[ip], 3)
+ if (format) {
+ if (is_ls)
+ ip = ip + gstrcpy ("\\fB", Memc[ip], SZ_LINE)
+ else {
+ switch (font) {
+ case F_ROMAN:
+ ip = ip + gstrcpy ("\\fR", Memc[ip], SZ_LINE)
+ case F_BOLD:
+ ip = ip + gstrcpy ("\\fB", Memc[ip], SZ_LINE)
+ case F_ITALIC:
+ ip = ip + gstrcpy ("\\fI", Memc[ip], SZ_LINE)
+ case F_TELETYPE:
+ ip = ip + gstrcpy ("\\fT", Memc[ip], SZ_LINE)
+ default:
+ ip = ip + gstrcpy ("\\fR", Memc[ip], SZ_LINE)
+ }
+ }
+ }
+ i = i + 2
+ } else
+ goto copy_
+ case '"':
+ if (format && str[i+1] != '/' && str[i+2] != '/') {
+ if (font == F_TELETYPE) {
+ # Do a closing quote.
+ if (format) {
+ if (is_ls)
+ ip = ip + gstrcpy ("\"\\fB", Memc[ip], SZ_LINE)
+ else
+ ip = ip + gstrcpy ("\"\\fR", Memc[ip], SZ_LINE)
+ }
+ font = F_ROMAN
+ } else if (font == F_ROMAN) {
+ # Do an opening quote.
+ if (format)
+ ip = ip + gstrcpy ("\\fT\"", Memc[ip], SZ_LINE)
+ font = F_TELETYPE
+ } else
+ goto copy_
+ } else
+ goto copy_
+
+ default:
+copy_ Memc[ip] = str[i]
+ ip = ip + 1
+ }
+ }
+
+ # Add the trailing newline we stripped above.
+ ip = ip + gstrcpy ("\n\0", Memc[ip], SZ_LINE)
+
+ # Move the string back.
+ call amovc (Memc[buf], str, maxch)
+
+ call sfree (sp)
+end
+
+
+# LP_STRDETAB -- Procedure to remove tabs from a line of text.
+
+procedure lp_strdetab (line, outline, maxch)
+
+char line[ARB], outline[ARB]
+int maxch
+
+int ip, op
+
+begin
+ ip = 1
+ op = 1
+
+ while (line[ip] != EOS && op <= maxch) {
+ if (line[ip] == '\t') {
+ repeat {
+ outline[op] = ' '
+ op = op + 1
+ } until (mod(op,8) == 0 || op > maxch)
+ ip = ip + 1
+ } else {
+ outline[op] = line [ip]
+ ip = ip + 1
+ op = op + 1
+ }
+ }
+
+ outline[op] = EOS
+end
diff --git a/pkg/system/help/lroff/mkpkg b/pkg/system/help/lroff/mkpkg
new file mode 100644
index 00000000..73a157d4
--- /dev/null
+++ b/pkg/system/help/lroff/mkpkg
@@ -0,0 +1,27 @@
+# Make the LROFF line-oriented text formatter.
+
+$checkout libpkg.a ../../
+$update libpkg.a
+$checkin libpkg.a ../../
+$exit
+
+libpkg.a:
+ breakline.x lroff.com lroff.h words.com <chars.h>
+ center.x lroff.com lroff.h <chars.h>
+ dols.x lroff.com lroff.h <chars.h> <error.h>
+ getarg.x lroff.h <chars.h>
+ indent.x lroff.com lroff.h
+ input.x lroff.com lroff.h <chars.h> <ctype.h>
+ justify.x lroff.com lroff.h <chars.h>
+ lroff.x lroff.com lroff.h <chars.h> <ctype.h>
+ lroff2html.x lroff.com lroff.h <ctype.h>
+ lroff2ps.x lroff.com lroff.h <psset.h> <ctype.h>
+ nextcmd.x lroff.h <ctype.h>
+ nofill.x lroff.com lroff.h
+ output.x lroff.com lroff.h <chars.h> <mach.h>
+ rawcopy.x lroff.com lroff.h
+ section.x lroff.com lroff.h <chars.h> <ctype.h>
+ skiplines.x lroff.h
+ textlen.x lroff.h <chars.h>
+ textout.x lroff.com lroff.h words.com <chars.h>
+ ;
diff --git a/pkg/system/help/lroff/nextcmd.x b/pkg/system/help/lroff/nextcmd.x
new file mode 100644
index 00000000..d4b09f44
--- /dev/null
+++ b/pkg/system/help/lroff/nextcmd.x
@@ -0,0 +1,56 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include "lroff.h"
+
+.help nextcmd
+.nf ________________________________________________________________________
+NEXTCMD -- Examine the input line; if it is an Lroff directive, return
+the integer code of the directive, otherwise NULL. Leave IP pointing
+to the argument field if a command, otherwise leave it pointing at the
+first char of the text line. Note that the "directives" string must
+match the opcode definitions given in lroff.h
+.endhelp ___________________________________________________________________
+
+define SZ_OPCODE 2
+
+int procedure nextcmd (linebuf, ip)
+
+char linebuf[ARB]
+int ip, op
+char opcode[SZ_OPCODE]
+int command, kwp, strmatch(), strncmp()
+string directives "finfjunjrjshihnhbrcespinlslebptpkskehrhn"
+
+begin
+ if (linebuf[1] != '.') # not a command line?
+ return (NULL)
+ if (strmatch (linebuf, "^.endhelp") > 0)
+ return (ENDHELP)
+ ip = 2 # skip the '.'
+
+ # Directives may be either upper or lower case.
+ for (op=1; op <= SZ_OPCODE; op=op+1) {
+ opcode[op] = linebuf[ip]
+ if (IS_UPPER (opcode[op]))
+ opcode[op] = TO_LOWER (opcode[op])
+ ip = ip + 1
+ }
+
+ # Just in case a directive happens to be longer than 2 chars, make
+ # sure IP points past the directive name.
+ while (IS_ALPHA (linebuf[ip]))
+ ip = ip + 1
+
+ # Lookup directive, return opcode number if found.
+ command = NULL
+ for (kwp=1; directives[kwp] != EOS; kwp=kwp+SZ_OPCODE)
+ if (strncmp (opcode, directives[kwp], SZ_OPCODE) == 0) {
+ command = (kwp+1) / SZ_OPCODE
+ break
+ }
+
+ if (command == NULL) # unrecognized directive
+ ip = 1
+ return (command)
+end
diff --git a/pkg/system/help/lroff/nofill.x b/pkg/system/help/lroff/nofill.x
new file mode 100644
index 00000000..f81b0d88
--- /dev/null
+++ b/pkg/system/help/lroff/nofill.x
@@ -0,0 +1,45 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "lroff.h"
+
+.help nofill
+.nf __________________________________________________________________________
+NOFILL -- Copy a block of text in ".nf" (nofill) mode, leaving the text
+alone except for left justification. The only directives recognized in
+a nofill block are FI (resume filling) and RJ (right justify).
+.endhelp _____________________________________________________________________
+
+int procedure nofill (in, out, linebuf)
+
+extern in(), out()
+char linebuf[ARB]
+int ip, command
+pointer sp, rjbuf
+int in(), input(), nextcmd()
+errchk salloc, breakline, input, rjline, outline
+include "lroff.com"
+
+begin
+ call smark (sp)
+ call salloc (rjbuf, SZ_IBUF, TY_CHAR)
+
+ call breakline (out, NJ)
+
+ while (input (in, linebuf) != EOF) {
+ command = nextcmd (linebuf, ip)
+ switch (command) {
+ case FI, ENDHELP:
+ call sfree (sp)
+ return (command)
+ case RJ: # right justify text
+ if (input (in, Memc[rjbuf]) == EOF)
+ break
+ call rjline (out, Memc[rjbuf], linebuf[ip])
+ default:
+ call outline (out, linebuf)
+ }
+ }
+
+ call sfree (sp)
+ return (ENDHELP)
+end
diff --git a/pkg/system/help/lroff/output.x b/pkg/system/help/lroff/output.x
new file mode 100644
index 00000000..84ebea0d
--- /dev/null
+++ b/pkg/system/help/lroff/output.x
@@ -0,0 +1,190 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <chars.h>
+include "lroff.h"
+
+.help outstr, outc, getoutcol, set_outbuf
+.nf __________________________________________________________________________
+OUTSTR, OUTC, OUTCOL -- Routines for buffering the output line. An output
+line is built up with calls to OUTPUT to pass strings, and to OUTC to pass
+characters. OUTCOL may be called to determine the index of the PRINTABLE
+column at which the next character will be deposited (this is unaffected by
+control chars in the output stream).
+
+The output buffer is flushed when OUTC is called to deposit a newline
+character, by calling the user supplied output procedure. The output column
+pointer is reset to the CURRENT left margin when the first character of the
+new line is deposited. Any changes to the left margin made after the first
+character is deposited do not take effect until the next line. OUTCOL returns
+the value of the current left margin if called when the buffer is empty.
+
+NOTE: set_outbuf() must be called during Lroff startup and shutdown to
+allocate the output buffer, the size of which depends on the maximum output
+line length.
+.endhelp _____________________________________________________________________
+
+
+# SET_OUTBUF -- Allocate and initialize the output buffer.
+
+procedure set_outbuf (outbuf_size)
+
+int outbuf_size # new buffer size in chars
+
+include "lroff.com"
+errchk malloc, out
+bool first_time
+data first_time /true/
+
+pointer obuf, op, otop
+int col, old_left_margin, buffer_empty
+common /lroout/ obuf, op, otop, col, old_left_margin, buffer_empty
+
+begin
+ if (first_time) {
+ obuf = NULL
+ buffer_empty = YES
+ first_time = false
+ }
+
+ if (outbuf_size <= 0 && obuf != NULL)
+ call mfree (obuf, TY_CHAR)
+ else {
+ call malloc (obuf, outbuf_size, TY_CHAR)
+ otop = obuf + outbuf_size - 1
+ op = obuf
+ buffer_empty = YES
+ old_left_margin = 1
+ }
+end
+
+
+# OUTC -- Output a single character. Note that the character value is
+# passed as an integer.
+
+procedure outc (out, ch)
+
+extern out() # user line output procedure
+int ch # character to be output
+
+char text[1]
+data text[1] /EOS/
+
+begin
+ text[1] = ch
+ call outstr (out, text)
+end
+
+
+# OUTSTR -- Output a text string.
+
+procedure outstr (out, text)
+
+extern out() # user line output procedure
+char text[ARB] # text string to be output
+
+int ch, ip, i
+pointer obuf, op, otop
+int col, old_left_margin, buffer_empty
+common /lroout/ obuf, op, otop, col, old_left_margin, buffer_empty
+include "lroff.com"
+
+begin
+ for (ip=1; text[ip] != EOS; ) {
+ if (buffer_empty == YES) {
+ if (obuf == NULL)
+ call error (1, "No Lroff output buffer allocated")
+
+ # If left margin has been moved inward, blank out the unused
+ # columns.
+
+ if (left_margin != old_left_margin) {
+ for (i=old_left_margin; i < left_margin; i=i+1)
+ Memc[obuf+i-1] = BLANK
+ old_left_margin = left_margin
+ }
+
+ op = obuf + left_margin - 1
+ col = left_margin
+ buffer_empty = NO
+ }
+
+ # Move the text string into the buffer. The string may contain
+ # more than one line of text.
+
+ for (; text[ip] != EOS; ip=ip+1) {
+ ch = text[ip]
+ Memc[op] = ch
+ op = op + 1
+
+ if (INVISIBLE(ch) || op > otop) {
+ if (ch == '\r' || ch == '\n') {
+ # Flush the buffer.
+ Memc[op] = EOS
+ call out (out_magic_arg, Memc[obuf])
+ buffer_empty = YES
+
+ # If all text data has not been copied (buffer overflow
+ # or newline embedded in the text), we must reinit the
+ # buffer and copy the remaining data. Otherwise we must
+ # return without calling the buffer_empty code to give
+ # the caller a chance to change the left margin.
+
+ if (text[ip+1] == EOS)
+ return
+ }
+ } else
+ col = col + 1
+ }
+ }
+end
+
+
+# GETOUTCOL -- Return the index of the next column of output.
+
+procedure getoutcol (next_column)
+
+int next_column # next col to be written (output)
+pointer obuf, op, otop
+int col, old_left_margin, buffer_empty
+common /lroout/ obuf, op, otop, col, old_left_margin, buffer_empty
+include "lroff.com"
+
+begin
+ if (buffer_empty == YES)
+ next_column = left_margin
+ else
+ next_column = col
+end
+
+
+# OUTCC -- Output a control sequence, i.e., a forms control sequence.
+# Called only after a line has already been output. Does not interfere
+# with output buffer. Sequence is not newline terminated.
+
+procedure outcc (out, ctrlchar)
+
+extern out() # user supplied line output procedure
+int ctrlchar # character to be output (INT)
+char ctrlstr[1]
+include "lroff.com"
+
+begin
+ ctrlstr[1] = ctrlchar
+ ctrlstr[2] = EOS
+ call out (out_magic_arg, ctrlstr)
+end
+
+
+# OUTLINE -- Output a string and append a newline to flush the output buffer.
+
+procedure outline (out, text)
+
+extern out()
+char text[ARB]
+errchk outstr
+
+begin
+ call outstr (out, text)
+ call outc (out, '\n')
+end
diff --git a/pkg/system/help/lroff/rawcopy.x b/pkg/system/help/lroff/rawcopy.x
new file mode 100644
index 00000000..d303b96e
--- /dev/null
+++ b/pkg/system/help/lroff/rawcopy.x
@@ -0,0 +1,26 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "lroff.h"
+
+.help rawcopy
+.nf ________________________________________________________________________
+RAWCOPY -- Copy an unformatted help block without modification, except
+for moving to the desired left margin. Stop only when the .endhelp
+directive is seen, or at EOF. Ignore all other directives.
+.endhelp ___________________________________________________________________
+
+procedure rawcopy (in, out, linebuf)
+
+extern in(), out()
+char linebuf[ARB]
+int ip, in(), input(), nextcmd()
+errchk input, outline
+include "lroff.com"
+
+begin
+ while (input (in, linebuf) != EOF)
+ if (nextcmd (linebuf, ip) == ENDHELP)
+ break
+ else
+ call outline (out, linebuf)
+end
diff --git a/pkg/system/help/lroff/section.x b/pkg/system/help/lroff/section.x
new file mode 100644
index 00000000..3df732c8
--- /dev/null
+++ b/pkg/system/help/lroff/section.x
@@ -0,0 +1,224 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include <ctype.h>
+include "lroff.h"
+
+# NEW_SECTION -- Begin a section heading. Argument is the number of lines
+# to skip. Output section heading string given on next input line. Reset left
+# margin and cancel out any LS indents.
+
+procedure new_section (in, out, linebuf, ip)
+
+extern in(), out()
+char linebuf[ARB]
+int ip
+
+int inbold(), in(), lgetarg()
+errchk skiplines, inbold, outline
+include "lroff.com"
+
+begin
+ sh_nskip = lgetarg (linebuf, ip, sh_nskip)
+ call skiplines (out, sh_nskip)
+ left_margin = perm_left_margin
+ call testpage (out, DEF_TPNLINES)
+
+ if (inbold (in, linebuf) != EOF)
+ call outline (out, linebuf)
+
+ call init_ls()
+end
+
+
+# NEW_NUMBERED_SECTION -- Begin a numbered section heading. Arguments are
+# the number of lines to skip and the section level to be incremented (default
+# is 1). If only one arg is given, we assume it is the section level.
+# Output section number followed by section heading string given on next input
+# line. Reset left margin and cancel out any LS indents.
+
+procedure new_numbered_section (in, out, linebuf, ip)
+
+extern in(), out()
+char linebuf[ARB]
+int ip
+
+int i, n
+int inbold(), in(), lgetarg(), strlen()
+errchk skiplines, sprintf, pargi, outstr, outc, inbold, outline
+include "lroff.com"
+
+begin
+ # Get level, nskip arguments.
+ n = max (1, min (MAX_NHLEVEL, lgetarg (linebuf, ip, 1)))
+ nh_nskip = lgetarg (linebuf, ip, nh_nskip)
+
+ call skiplines (out, nh_nskip)
+ left_margin = perm_left_margin
+ call testpage (out, DEF_TPNLINES)
+
+ # Increment the desired section number; zero all higher numbered
+ # section counters.
+
+ nh_level[n] = nh_level[n] + 1
+ call amovki (0, nh_level[n+1], MAX_NHLEVEL - n)
+
+ # Output the section number followed by a blank and then the section
+ # label.
+
+ linebuf[1] = EOS
+ do i = 1, n {
+ call sprintf (linebuf[strlen(linebuf)+1], SZ_IBUF, "%d.")
+ call pargi (nh_level[i])
+ }
+
+ # Cancel the final "." if subsection heading. Add a blank.
+ if (n > 1 && linebuf[strlen(linebuf)] == '.')
+ linebuf[strlen(linebuf)] = EOS
+ call outstr (out, linebuf)
+ call outc (out, BLANK)
+
+ # Get section label from next input line, write that out on the same
+ # line in standout mode, then terminate the line.
+
+ if (inbold (in, linebuf) != EOF)
+ call outline (out, linebuf)
+
+ call init_ls()
+end
+
+
+# INIT_NH -- Initialize section numbering.
+
+procedure init_nh()
+
+include "lroff.com"
+
+begin
+ call amovki (0, nh_level, MAX_NHLEVEL)
+end
+
+
+# NEW_INDENTED_SECTION -- Begin an indented section heading. Optional
+# arguments are the number of spaces to indent subsequent text and the number
+# of lines to skip. Output section heading string given on next input line.
+# Reset left margin and cancel out any LS indents.
+
+procedure new_indented_section (in, out, linebuf, ip)
+
+extern in(), out()
+char linebuf[ARB]
+int ip
+
+int inbold(), in(), lgetarg()
+errchk skiplines, inbold, outline
+include "lroff.com"
+
+begin
+ ih_indent = lgetarg (linebuf, ip, ih_indent)
+ ih_nskip = lgetarg (linebuf, ip, ih_nskip)
+
+ call skiplines (out, ih_nskip)
+ left_margin = perm_left_margin
+ call testpage (out, DEF_TPNLINES)
+
+ # Read in and output the section heading in boldface.
+ if (inbold (in, linebuf) != EOF)
+ call outline (out, linebuf)
+
+ # Reset the left margin and cancel out any LS indents.
+ left_margin = max (perm_left_margin, min (right_margin,
+ perm_left_margin + ih_indent))
+
+ call init_ls()
+end
+
+
+# INBOLD -- Input a line in standout mode. If the line is already all in
+# upper case, do not use standout mode. The input procedure processes
+# all font escape sequences. We must get the raw input line by calling the
+# user input procedure, then pass it on to input() enclosed in \fB...\fR
+# font escape sequences, to enable standout mode.
+
+int procedure inbold (in, user_linebuf)
+
+extern in()
+int in()
+char user_linebuf[ARB]
+
+pointer sp, ip, lbuf, first
+int save_in_magic_arg, status
+int stropen(), input()
+extern getline()
+errchk salloc, stropen, input
+include "lroff.com"
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LINE + 3 + 3, TY_CHAR)
+
+ # Deposit escape sequence to turn bold on.
+ call strcpy ("\\fB", Memc[lbuf], ARB)
+
+ # Read in the input line after the three char escape sequence.
+ if (in (in_magic_arg, Memc[lbuf+3]) == EOF) {
+ call sfree (sp)
+ return (EOF)
+ }
+
+ # Scan the line to see if there are any lower case characters.
+ # If all upper case, omit the mode control sequences (this procedure
+ # becomes equivalent to input()).
+
+ first = lbuf + 3
+ for (ip=lbuf+3; Memc[ip] != EOS; ip=ip+1)
+ if (IS_LOWER (Memc[ip])) {
+ first = lbuf
+ break
+ }
+
+ # Step on the newline if there is one, then add the \fR
+ # sequence to turn bold off.
+ if (first == lbuf) {
+ for (ip=lbuf; Memc[ip] != EOS; ip=ip+1)
+ ;
+ if (Memc[ip-1] == '\n')
+ Memc[ip-1] = EOS
+ call strcat ("\\fR\n", Memc[lbuf], ARB)
+ }
+
+ # Now open the string as a file and call input to process it
+ # into our caller's buffer. We must save and restore the input
+ # magic argument, set to the fd of the string file when input is
+ # called. This is a good example of the disadvantages of commons...
+
+ save_in_magic_arg = in_magic_arg
+ in_magic_arg = stropen (Memc[first], ARB, READ_ONLY)
+ status = input (getline, user_linebuf)
+ call close (in_magic_arg)
+ in_magic_arg = save_in_magic_arg
+
+ call sfree (sp)
+ return (status)
+end
+
+
+# TESTPAGE -- If forms mode is enabled, output the control code for a test
+# page followed by the number of lines to test for. Test page tests if the
+# specified number of lines are left on a page, and breaks the page if not.
+
+procedure testpage (out, nlines)
+
+extern out()
+int nlines
+char ctrlstr[2]
+include "lroff.com"
+
+begin
+ if (foflag == YES) {
+ ctrlstr[1] = FC_TESTPAGE
+ ctrlstr[2] = nlines
+ ctrlstr[3] = EOS
+ call out (out_magic_arg, ctrlstr)
+ }
+end
diff --git a/pkg/system/help/lroff/skiplines.x b/pkg/system/help/lroff/skiplines.x
new file mode 100644
index 00000000..0449dc50
--- /dev/null
+++ b/pkg/system/help/lroff/skiplines.x
@@ -0,0 +1,19 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "lroff.h"
+
+# SKIPLINES -- Skip one or more lines on the output, i.e., break the current
+# output line and add a few empty lines.
+
+procedure skiplines (out, nlines)
+
+extern out()
+int nlines, i
+errchk breakline, outc
+
+begin
+ call breakline (out, NJ)
+
+ do i = 1, nlines
+ call outc (out, '\n')
+end
diff --git a/pkg/system/help/lroff/textlen.x b/pkg/system/help/lroff/textlen.x
new file mode 100644
index 00000000..e192314f
--- /dev/null
+++ b/pkg/system/help/lroff/textlen.x
@@ -0,0 +1,20 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include "lroff.h"
+
+# TEXTLEN -- Return the number of printable characters in a text string.
+
+int procedure textlen (text_string)
+
+char text_string[ARB]
+int ip, nchars
+
+begin
+ nchars = 0
+ for (ip=1; text_string[ip] != EOS; ip=ip+1)
+ if (!INVISIBLE (text_string[ip]))
+ nchars = nchars + 1
+
+ return (nchars)
+end
diff --git a/pkg/system/help/lroff/textout.x b/pkg/system/help/lroff/textout.x
new file mode 100644
index 00000000..663bccc8
--- /dev/null
+++ b/pkg/system/help/lroff/textout.x
@@ -0,0 +1,140 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include "lroff.h"
+
+# TEXTOUT -- Process a line of text. Move words from the text buffer into
+# the word buffer WBUF, maintaining an array of pointers to the words, until
+# an output line has been filled. Leading whitespace is part of the word,
+# if it is the first word on a line (thus we get paragraph indents).
+# Thereafter only trailing whitespace is included in the word. The last word
+# on a line gets one trailing space, unless the last char is a period, in which
+# case it gets two. Otherwise whitespace at the end of the input text line is
+# stripped. BREAKLINE is subsequently called to reassemble the words to form
+# an output line.
+#
+# WBUF is the word buffer (a set of strings separated by EOS markers). WP is
+# a pointer to the next available char in WBUF. NWORDS is the number of words
+# in the buffer. WORDS is a pointer to the array of word pointers. We do not
+# check for word buffer overflow because the word buffer is allocated large
+# enough to accommodate the worst case (the buffer is flushed when an output
+# line is filled, which always happens before the buffer overflows). WCOLS is
+# the number of printable characters in the word buffer. The word buffer
+# variables are all stored in the "words" common for use by TEXTOUT and
+# BREAKLINE. Set_wordbuf() must be called upon startup and shutdown to
+# allocate/deallocate the word buffer.
+
+procedure set_wordbuf (max_words)
+
+int max_words #I output word buffer size
+
+int word_buffer_size
+errchk malloc
+
+include "lroff.com"
+include "words.com"
+
+begin
+ word_buffer_size = (max_words * 2) + SZ_LINE # worst case
+ if (max_words <= 0 && words != NULL) {
+ call mfree (wbuf, TY_CHAR)
+ call mfree (words, TY_POINTER)
+ } else {
+ call malloc (wbuf, word_buffer_size, TY_CHAR)
+ call malloc (words, max_words, TY_POINTER)
+ wp = wbuf
+ nwords = 0
+ wcols = 0
+ }
+end
+
+
+# TEXTOUT -- Output a newline delimited line of text.
+
+procedure textout (out, text)
+
+extern out()
+char text[1]
+
+char ch
+int ip_save, wcols_save, ip
+errchk breakline
+include "lroff.com"
+include "words.com"
+
+begin
+ if (wbuf == NULL || words == NULL)
+ call error (1, "No Lroff word buffer allocated")
+
+ for (ip=1; text[ip] != EOS; ) {
+ # Set up descriptors of new word. Save the input pointer in case
+ # the output line fills and we have to "put the word back".
+
+ Memi[words+nwords] = wp # word pointer
+ ip_save = ip
+ wcols_save = wcols
+
+ # The following is a nop except at the beginning of a line.
+ for (; text[ip] == BLANK; ip=ip+1) {
+ Memc[wp] = BLANK
+ wp = wp + 1
+ wcols = wcols + 1
+ }
+
+ # Copy the word itself.
+ for (ch=text[ip]; ch != BLANK && ch != EOS; ch=text[ip]) {
+ Memc[wp] = ch
+ wp = wp + 1
+ if (!INVISIBLE (ch))
+ wcols = wcols + 1
+ ip = ip + 1
+ }
+
+ # And then any trailing whitespace.
+ for (; text[ip] == BLANK; ip=ip+1) {
+ Memc[wp] = BLANK
+ wp = wp + 1
+ wcols = wcols + 1
+ }
+
+ # End of word string.
+ Memc[wp] = EOS
+ wp = wp + 1
+
+ # If line has been filled, call breakline to format output line
+ # and send it out. Put word which caused break back for next line.
+ # Do not put word back if it is the first word, or we will have
+ # an infinite loop.
+ if (wcols > (right_margin - left_margin + 1) && nwords > 0) {
+ ip = ip_save
+ wcols = wcols_save
+ wp = Memi[words+nwords]
+ call breakline (out, JU)
+ } else
+ nwords = nwords + 1
+ }
+
+ # Strip trailing whitespace at the end of an input line. If input
+ # line ends with a period, assume it is a sentence and add a blank.
+ # Otherwise add a blank to separate words when output line is filled.
+ # If a sentence ends within a line, the user is responsible for placing
+ # two spaces after the period.
+
+ if (nwords > 0) {
+ for (wp=wp-2; Memc[wp] == BLANK && wp > wbuf; wp=wp-1)
+ wcols = wcols - 1
+ if (Memc[wp] == '.') {
+ wp = wp + 1
+ Memc[wp] = BLANK
+ wcols = wcols + 1
+ }
+ wp = wp + 1 # point to next avail
+
+ Memc[wp] = BLANK # need at least one
+ wp = wp + 1
+ wcols = wcols + 1
+
+ Memc[wp] = EOS
+ wp = wp + 1
+ }
+end
diff --git a/pkg/system/help/lroff/words.com b/pkg/system/help/lroff/words.com
new file mode 100644
index 00000000..d0c220da
--- /dev/null
+++ b/pkg/system/help/lroff/words.com
@@ -0,0 +1,9 @@
+# Common for Textout()/Breakline().
+
+pointer wbuf # the word buffer, a string buffer
+pointer wp # pointer to next available char in word buffer
+pointer words # array of word pointers
+int nwords # number of words in word buffer
+int wcols # number of printable columns in word buffer
+
+common /wrdcom/ wbuf, wp, words, nwords, wcols
diff --git a/pkg/system/help/manout.x b/pkg/system/help/manout.x
new file mode 100644
index 00000000..b81abc8b
--- /dev/null
+++ b/pkg/system/help/manout.x
@@ -0,0 +1,330 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include <ctype.h>
+include "help.h"
+
+.help man_output, man_close
+.nf ___________________________________________________________________________
+Process a stream of output lines containing forms control codes. This mode is
+used when manual page format is desired. Input is a sequence of manual pages.
+A manual page consists of a formfeed, a two line page header, and then an
+arbitrary number of lines of text. Pages are broken every H_NLPP lines,
+the page header is printed at the top of each page, and the page number is
+printed at the bottom of each page. The following special directives may
+be inserted in the text as control character forms codes; the forms code must
+be the first character in a line but may be followed by text.
+
+ FC_BREAKPAGE Start a new page, unless already at the
+ top of a page.
+
+ FC_TESTPAGE n Test if there are at least N (binary code)
+ lines left on the page. If no, break the
+ page before more text is output.
+
+ FC_STARTKEEP Start spooling lines into an internal buffer.
+ Try to output the keep block all on one page.
+
+ FC_ENDKEEP Stop spooling and output the keep block.
+
+MAN_CLOSE should be called at program termination to return buffer space and
+reinit variables.
+.endhelp ______________________________________________________________________
+
+define LEN_HEADER 2
+define LEN_FOOTER 3
+define LEN_KEEP 1024
+define SZ_PAGELABEL 6
+define SZ_HEADER_GAP 2
+
+define IN_HEADER 1
+define IN_TEXT 2
+define IN_KEEP 3
+define FLUSH_KEEP 4
+
+
+# MAN_OUTPUT -- Output a line, optionally preceded by one or more forms control
+# characters. Start a new manual page, save lines in header, save lines in keep
+# buffer, or write line to output.
+
+procedure man_output (fd, lbuf, nlines_per_page, lmargin, rmargin)
+
+int fd # output file
+char lbuf[ARB] # next output line
+int nlines_per_page
+int lmargin, rmargin
+
+char end_keep_chars[3]
+int ip, mode, max_lineno, i
+
+int nlines_in_keep, nlines_in_header, init
+int lineno, pageno, center_col, nlpp
+pointer header_lines[LEN_HEADER], keep_lines[LEN_KEEP]
+common /hlpman/ lineno, pageno, nlpp, center_col, init,
+ nlines_in_header, nlines_in_keep, header_lines, keep_lines
+
+int stridx()
+pointer man_putstr()
+data end_keep_chars /FC_STARTKEEP, FC_BREAKPAGE, '\f', EOS/
+
+begin
+ if (init == YES) {
+ # Initialize internal variables.
+ lineno = 0
+ pageno = 0
+ mode = IN_TEXT
+ nlines_in_header = 0
+ nlines_in_keep = 0
+ nlpp = nlines_per_page
+ max_lineno = max(1, min(LEN_KEEP, nlpp - LEN_FOOTER))
+ center_col = (lmargin + rmargin) / 2
+ init = NO
+ }
+
+ for (ip=1; lbuf[ip] != EOS; ) {
+ switch (mode) {
+
+ case IN_HEADER:
+ # Just started a new manual page; still accumulating header
+ # lines. Forms control chars not recognized in header area.
+ # Output header to start new page as soon as we have all the
+ # lines.
+
+ nlines_in_header = nlines_in_header + 1
+ header_lines[nlines_in_header] = man_putstr (lbuf[ip])
+ if (nlines_in_header == LEN_HEADER) {
+ mode = IN_TEXT
+ call man_breakpage (fd, header_lines, nlines_in_header,
+ lineno, pageno, nlpp, center_col)
+ pageno = 1
+ }
+ break
+
+ case IN_KEEP:
+ # Any forms control character in a keep ends the keep, in case
+ # the KE is missing. Don't bump input pointer unless sentinel
+ # is ENDKEEP, else forms control character will be skipped.
+
+ if (lbuf[ip] == FC_ENDKEEP) {
+ mode = FLUSH_KEEP
+ ip = ip + 1
+ } else if (stridx (lbuf[ip], end_keep_chars) > 0) {
+ mode = FLUSH_KEEP
+ } else if (lineno + nlines_in_keep > max_lineno) {
+ mode = FLUSH_KEEP
+ } else {
+ # Put line in keep buffer.
+ nlines_in_keep = nlines_in_keep + 1
+ keep_lines[nlines_in_keep] = man_putstr (lbuf[ip])
+ break
+ }
+
+ case FLUSH_KEEP:
+ # Break page and output header if insufficient room left on
+ # page.
+ if (lineno + nlines_in_keep > max_lineno)
+ call man_breakpage (fd, header_lines, nlines_in_header,
+ lineno, pageno, nlpp, center_col)
+
+ # Output contents of keep buffer and return buffer space.
+ for (i=1; i <= nlines_in_keep; i=i+1) {
+ call putline (fd, Memc[keep_lines[i]])
+ call mfree (keep_lines[i], TY_CHAR)
+ lineno = lineno + 1
+ }
+ nlines_in_keep = 0
+ mode = IN_TEXT
+
+ case IN_TEXT:
+ # Not in any special mode. Check for forms chars and loop if
+ # one is found. Otherwise output line and bump line pointer.
+ # Break page when it fills.
+
+ switch (lbuf[ip]) {
+ case FC_BREAKPAGE:
+ call man_breakpage (fd, header_lines, nlines_in_header,
+ lineno, pageno, nlpp, center_col)
+ ip = ip + 1
+
+ case FC_TESTPAGE:
+ # The first char following the testpage forms control char
+ # is the number of lines to test for, in binary.
+
+ if (lineno + lbuf[ip+1] > max_lineno)
+ call man_breakpage (fd, header_lines, nlines_in_header,
+ lineno, pageno, nlpp, center_col)
+ ip = ip + 2
+
+ case FC_STARTKEEP:
+ mode = IN_KEEP
+ ip = ip + 1
+ case FC_ENDKEEP:
+ ip = ip + 1
+
+ case '\f':
+ # Start accumulating new header. Page cannot be broken
+ # until we have the header.
+
+ for (i=1; i <= nlines_in_header; i=i+1)
+ call mfree (header_lines[i], TY_CHAR)
+ nlines_in_header = 0
+ mode = IN_HEADER
+ ip = ip + 1
+
+ default:
+ # This is the case that gets called most often; output an
+ # ordinary line, not in any special mode. Eat blank lines
+ # at top of page.
+
+ if (lineno <= nlines_in_header + SZ_HEADER_GAP + 1) {
+ for (i=ip; IS_WHITE (lbuf[i]); i=i+1)
+ ;
+ if (lbuf[i] == '\n' || lbuf[i] == EOS)
+ break
+ }
+ call putline (fd, lbuf[ip])
+ lineno = lineno + 1
+ if (lineno > max_lineno)
+ call man_breakpage (fd, header_lines, nlines_in_header,
+ lineno, pageno, nlpp, center_col)
+ break
+ }
+ }
+ }
+end
+
+
+# MAN_INIT -- Called to initialize the manpage internal data structures.
+
+procedure man_init()
+
+int i
+bool first_time
+data first_time /true/
+
+int nlines_in_keep, nlines_in_header, init
+int lineno, pageno, center_col, nlpp
+pointer header_lines[LEN_HEADER], keep_lines[LEN_KEEP]
+common /hlpman/ lineno, pageno, nlpp, center_col, init,
+ nlines_in_header, nlines_in_keep, header_lines, keep_lines
+
+begin
+ # Clean up in the event of an interrupt.
+ if (!first_time) {
+ for (i=1; i <= nlines_in_header; i=i+1)
+ call mfree (header_lines[i], TY_CHAR)
+ for (i=1; i <= nlines_in_keep; i=i+1)
+ call mfree (keep_lines[i], TY_CHAR)
+ }
+
+ init = YES
+ first_time = false
+end
+
+
+# MAN_CLOSE -- Called at program termination to write the page number at the
+# bottom of the last manual page.
+
+procedure man_close (fd)
+
+int fd
+int nlines_in_keep, nlines_in_header, i
+int lineno, pageno, center_col, nlpp, init
+pointer header_lines[LEN_HEADER], keep_lines[LEN_KEEP]
+common /hlpman/ lineno, pageno, nlpp, center_col, init,
+ nlines_in_header, nlines_in_keep, header_lines, keep_lines
+
+begin
+ if (init == YES)
+ return
+
+ # Trash any data in keep buffer if missing the KE by the time we are
+ # called (at program termination).
+
+ call man_breakpage (fd, header_lines, 0, lineno, pageno, nlpp,
+ center_col)
+
+ for (i=1; i <= nlines_in_header; i=i+1)
+ call mfree (header_lines[i], TY_CHAR)
+ for (i=1; i <= nlines_in_keep; i=i+1)
+ call mfree (keep_lines[i], TY_CHAR)
+
+ nlines_in_header = 0
+ nlines_in_keep = 0
+ init = YES
+end
+
+
+# MAN_BREAKPAGE -- Advance to bottom of page, print page number, bump page
+# number, init line counter, formfeed, output page header of new page.
+
+procedure man_breakpage (fd, header_lines, nlines_in_header, lineno, pageno,
+ nlines_per_page, center_col)
+int fd
+pointer header_lines[ARB]
+int nlines_in_header
+int lineno, pageno
+int nlines_per_page
+int center_col
+
+char pagelabel[SZ_PAGELABEL]
+int i, destcol
+int strlen()
+
+begin
+ # Output page footer if there is anything on the page and if there
+ # was a page header.
+
+ if (lineno > 0 && nlines_in_header > 0) {
+ while (lineno <= nlines_per_page - 1) {
+ call putline (fd, "\n")
+ lineno = lineno + 1
+ }
+
+ call sprintf (pagelabel, SZ_PAGELABEL, "-%d-")
+ call pargi (pageno)
+
+ destcol = max (1, center_col - strlen (pagelabel) / 2)
+ for (i=1; i < destcol; i=i+1)
+ call putci (fd, ' ')
+ call putline (fd, pagelabel)
+ call putci (fd, '\n')
+ }
+
+ # Break page and output page header if there are any header lines.
+ # Leave two blank lines between header and first line of text.
+
+ if (nlines_in_header > 0) {
+ if (pageno > 0)
+ call putci (fd, '\f')
+ lineno = 1
+ pageno = pageno + 1
+
+ for (i=1; i <= nlines_in_header; i=i+1) {
+ call putline (fd, Memc[header_lines[i]])
+ lineno = lineno + 1
+ }
+ for (i=1; i <= SZ_HEADER_GAP; i=i+1) {
+ call putline (fd, "\n")
+ lineno = lineno + 1
+ }
+ }
+end
+
+
+# MAN_PUTSTR -- Save a string on the heap and return a pointer to the string.
+
+pointer procedure man_putstr (str)
+
+char str[ARB]
+int nchars
+pointer bp
+int strlen()
+
+begin
+ nchars = strlen (str)
+ call malloc (bp, nchars, TY_CHAR)
+ call strcpy (str, Memc[bp], nchars)
+
+ return (bp)
+end
diff --git a/pkg/system/help/mkhelpdb.hlp b/pkg/system/help/mkhelpdb.hlp
new file mode 100644
index 00000000..d3534cf6
--- /dev/null
+++ b/pkg/system/help/mkhelpdb.hlp
@@ -0,0 +1,75 @@
+.help mkhelpdb Feb89 softools
+.ih
+NAME
+mkhelpdb -- update the help database
+.ih
+USAGE
+mkhelpdb helpdir helpdb
+.ih
+PARAMETERS
+.ls helpdir = "lib$root.hd"
+The filename of the root help directory file (".hd" file) defining the
+help tree to be updated. By convention this is \fIroot.hd\fR in some
+directory.
+.le
+.ls helpdb = "lib$helpdb.mip"
+The filename of the help database file to be written. By convention this
+is \fIhelpdb.mip\fR in some directory (the ".mip" signifies that the file
+format is machine independent).
+.le
+.ls verbose = no
+If this switch is enabled, \fImkhelpdb\fR will print a detailed description
+of the help database as it is being compiled. A more concise summary listing
+only the packages and the number of help modules in each package is printed
+by default.
+.le
+.ih
+DESCRIPTION
+The \fImkhelpdb\fR task descends a tree of help directory (".hd") files and
+compiles a binary help database from the information therein. The help
+database is used to speed global searches when help is requested for a
+module, the ".hlp" file for which might be anywhere in the system.
+The help database defines the packages and modules in the help database,
+and stores the filenames of the associated help files. No actual help text
+is stored in the help database, only sufficient index information to find
+the help files when the \fIhelp\fR task is run. The help directory files
+are text files which define the packages and modules in the help database.
+The format of these files is self explanatory hence is documented by example
+only.
+
+By default, \fImkhelpdb\fR recompiles the standard IRAF help database,
+although any other similar database may be recompiled by changing the values
+of the parameters \fIhelpdir\fR and \fIhelpdb\fR. The standard
+IRAF help database is rooted in the file \fBlib$root.hd\fR.
+
+The help database must be updated whenever a new help module (e.g., manual
+page) is added, deleted, or renamed. It is also necessary for sites receiving
+a source only version of IRAF to run \fImkhelpdb\fR to rebuild the help
+database once the system is up, since the database is a binary file and
+is not included in a source only distribution. It is not necessary to rerun
+\fImkhelpdb\fR when an existing manual page is edited, since only index
+information is stored in the database.
+
+The \fIhelp\fR utilities make use of the following types of files. Examples
+of these files will be found throughout the IRAF directories.
+
+.nf
+ .hd help directory file (tree structured)
+ .hlp manual page
+ .men package menu (module listing)
+.fi
+.ih
+EXAMPLES
+1. Update the standard IRAF help database.
+
+.nf
+ cl> softools
+ so> mkhelpdb helpdir=lib$root.hd helpdb=lib$helpdb.mip
+.fi
+
+2. Update the NOAO package help database.
+
+ so> mkhelpdb helpdir=noao$lib/root.hd helpdb=noao$lib/helpdb.mip
+.ih
+SEE ALSO
+hdbexamine, help
diff --git a/pkg/system/help/mkpkg b/pkg/system/help/mkpkg
new file mode 100644
index 00000000..3cb437ec
--- /dev/null
+++ b/pkg/system/help/mkpkg
@@ -0,0 +1,36 @@
+# Make the HELP and LROFF library modules.
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ @lroff
+ @xhelp
+
+ filetemp.x help.h <ctype.h>
+ getoption.x help.h <ctype.h>
+ hbgetblk.x help.h <ctype.h>
+ helpdb.x help.h helpdir.h <error.h> <finfo.h> <fset.h> <mach.h>\
+ <time.h>
+ helpdir.x help.h helpdir.h <ctype.h> <error.h>
+ hinput.x help.h <ctype.h>
+ houtput.x help.h <ttyset.h> <chars.h> <fset.h>
+ manout.x help.h <chars.h> <ctype.h>
+ modlist.x help.h helpdir.h <ctype.h> <error.h>
+ modtemp.x help.h <ctype.h>
+ prblkhdr.x help.h
+ prdir.x help.h <error.h> <ttyset.h>
+ prfile.x help.h <finfo.h> <time.h> <ctype.h>
+ prfnames.x help.h helpdir.h
+ prhelp.x help.h helpdir.h <error.h>
+ prhlpblk.x help.h <error.h>
+ prmodname.x help.h
+ prsummary.x help.h
+ t_hdbexamine.x help.h <error.h>
+ t_help.x help.h <error.h> <fset.h> <finfo.h>
+ t_lroff.x
+ t_mkhelpdb.x <error.h>
+ tlist.x help.h <ctype.h>
+ ;
diff --git a/pkg/system/help/modlist.x b/pkg/system/help/modlist.x
new file mode 100644
index 00000000..dce63f59
--- /dev/null
+++ b/pkg/system/help/modlist.x
@@ -0,0 +1,200 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include <error.h>
+include "help.h"
+include "helpdir.h"
+
+.help modlist
+.nf ___________________________________________________________________________
+MODLIST -- Routines for expanding a template into a list of module names,
+and accessing successive elements of the list, given a template and a help
+directory defining the pattern matching domain as input.
+
+The permissible complexity of a help template is somewhat less than that of
+a file template; we do not have to deal with logical directories, virtual
+file names, and list files. The class of characters permitted in a CL
+module name is fairly limited. By the time we are called, the template
+list will already have been expanded into a list of templates, wherein
+each list element has a full package name (the package field has already
+been expanded). Our job is to process a single template.
+
+ * all modules
+ im* all modules whose names start with 'im'
+ [a-z]?* all modules beg. with lowercase letter
+ alpha all modules alpha*
+
+Note that a simple alphanumeric name like 'alpha' is treated as an
+abbreviation, i.e., as 'alpha?*'. All occurrences of the closure metacharacter
+* are converted to ?*, except after a character class.
+
+Entry points in this package include:
+
+ ml_open set up to match and extract module names
+ ml_read get next module name which matches pattern
+ ml_close called when done to return buffers
+.endhelp ______________________________________________________________________
+
+define LEN_MLSTRUCT 165 # module list structure
+define SZ_PATBUF 159
+
+define ML_HP Memi[$1] # help directory
+define ML_INDEX Memi[$1+1] # index of next module in helpdir
+define ML_SIMPAT Memi[$1+2] # pattern is simple (no metacharacters)
+define ML_PATBUF Memc[P2C($1+5)] # encoded pattern buffer
+
+
+# ML_OPEN -- Set up to read module names from a directory which match
+# a certain pattern. Allocate descriptor, save pointer to directory,
+# encode pattern, rewind module index.
+
+pointer procedure ml_open (hp, template)
+
+pointer hp # help directory
+char template[ARB] # "alpha", "*", etc.
+
+bool metachars
+int ip
+pointer ml, sp, pat, op
+int patmake()
+
+begin
+ call smark (sp)
+ call salloc (pat, SZ_LINE, TY_CHAR)
+
+ iferr (call calloc (ml, LEN_MLSTRUCT, TY_STRUCT))
+ call erract (EA_FATAL)
+ ML_INDEX(ml) = 1
+ ML_HP(ml) = hp
+
+ # Match only at beginning of module name. Remember to scrap this
+ # metacharacter if matching a SIMPAT simple pattern.
+
+ Memc[pat] = '^'
+ op = pat + 1
+
+ # If no metacharacters present in pattern set SIMPAT flag so that we
+ # can use a more efficient pattern matching algorithm. If closure
+ # metacharacter is present and it does not follow ], replace it with ?*.
+
+ metachars = false
+ for (ip=1; template[ip] != EOS && op-pat < SZ_LINE; ip=ip+1) {
+ switch (template[ip]) {
+ case '?', '[', ']':
+ metachars = true
+ case '*':
+ metachars = true
+ if (ip == 1 || (ip > 1 && template[ip-1] != ']')) {
+ Memc[op] = '?'
+ op = op + 1
+ }
+ }
+ Memc[op] = template[ip]
+ op = op + 1
+ }
+ Memc[op] = EOS
+
+ if (!metachars) {
+ ML_SIMPAT(ml) = YES
+ # Copy pattern string, stripping off the leading '^'.
+ call strcpy (Memc[pat+1], ML_PATBUF(ml), SZ_PATBUF)
+ } else {
+ ML_SIMPAT(ml) = NO
+ if (patmake (Memc[pat], ML_PATBUF(ml), SZ_PATBUF) == ERR)
+ call error (16, "Cannot encode help pattern")
+ }
+
+ call sfree (sp)
+ return (ml)
+end
+
+
+# ML_READ -- Get next module name from help directory matching the
+# encoded pattern. Return EOF when directory is exhausted. We directly
+# access the HD structure for efficiency.
+
+int procedure ml_read (ml, modnum, module, maxch)
+
+pointer ml # pointer to module list descriptor
+int modnum # module number (output)
+char module[ARB] # module name (output)
+int maxch
+
+bool match_found
+char first_char
+int m
+pointer hp, sbuf, mp, modname
+int patmatch(), ml_patmatch(), gstrcpy()
+errchk patmatch
+
+begin
+ if (ml == NULL)
+ call error (17, "help.ml_read called with null descriptor")
+ hp = ML_HP(ml)
+ sbuf = HD_SBUF(hp)
+ first_char = ML_PATBUF(ml)
+ m = ML_INDEX(ml)
+ match_found = false
+
+ # Scan down the list of modules in the package, returning the name
+ # of each matching the pattern in successive calls. Return EOF when
+ # the list is exhausted.
+
+ while (m <= HD_NMODULES(hp)) {
+ mp = HD_MODULE(hp, m)
+ modname = sbuf + M_NAME(mp)
+ m = m + 1
+ if (ML_SIMPAT(ml) == YES) {
+ if (Memc[modname] == first_char)
+ if (ml_patmatch (Memc[modname], ML_PATBUF(ml)) > 0) {
+ match_found = true
+ break
+ }
+ } else if (patmatch (Memc[modname], ML_PATBUF(ml)) > 0) {
+ match_found = true
+ break
+ }
+ }
+
+ ML_INDEX(ml) = m
+ modnum = m - 1
+
+ # If no modules were found matching the template then we can only be
+ # at the end of the list.
+
+ if (match_found)
+ return (gstrcpy (Memc[modname], module, maxch))
+ else {
+ module[1] = EOS
+ return (EOF)
+ }
+end
+
+
+# ML_PATMATCH -- Determine if a SIMPAT simple pattern is an abbreviation of
+# a module name. The pattern is simple, i.e., contains no metacharacters.
+
+int procedure ml_patmatch (module, pattern)
+
+char module[ARB] # module name to be compared to pattern
+char pattern[ARB] # pattern of the form "^abbrev"
+int ip
+
+begin
+ for (ip=1; pattern[ip] != EOS; ip=ip+1)
+ if (pattern[ip] != module[ip])
+ return (0)
+
+ return (1)
+end
+
+
+# ML_CLOSE -- Return buffers allocated by open_template.
+
+procedure ml_close (ml)
+
+pointer ml
+
+begin
+ call mfree (ml, TY_STRUCT)
+end
diff --git a/pkg/system/help/modtemp.x b/pkg/system/help/modtemp.x
new file mode 100644
index 00000000..d539a2f2
--- /dev/null
+++ b/pkg/system/help/modtemp.x
@@ -0,0 +1,190 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include <syserr.h>
+include "help.h"
+
+# DO_MODULE_TEMPLATE -- Called with a template defining the packages and
+# modules for which help is desired, and the control parameters defining
+# the type of help desired. Expand the template into a list of packages
+# and modules and process the help for each module.
+#
+# Most of the work here is done by HD_LOAD, which opens and interprets a
+# help directory, and TL_OPEN/TL_READ, which expand the template list.
+# Each element of the template list is a module matching pattern for a
+# single package. When this is expanded we get the names of the individual
+# modules and call PRINT_HELP to print the help text for a single module
+# of a particular package. In the worst case (template "*.*"), we might
+# process all modules in the help database.
+
+procedure do_module_template (db, tlist, ctrl)
+
+pointer db # help database to be used
+char tlist[ARB] # template list ("a.*,b.*,...")
+pointer ctrl # Help control structure
+
+int m, pk
+bool no_matches, matchall
+pointer sp, fname, template, module, pakname, modtemp, curmod
+pointer hp_sys, hp_pak, tl, ip, op, modlist
+
+bool strne()
+int tl_read(), ml_read(), print_help()
+int stridxs(), ml_patmatch(), hd_findmod(), hd_getname()
+pointer hdb_load(), tl_open(), ml_open()
+errchk tl_read, hd_findmod, hd_getname, ml_read, hdb_load
+errchk tl_open, ml_open, print_help
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+ call salloc (template, SZ_LINE, TY_CHAR)
+ call salloc (module, SZ_FNAME, TY_CHAR)
+ call salloc (pakname, SZ_FNAME, TY_CHAR)
+ call salloc (modtemp, SZ_FNAME, TY_CHAR)
+ call salloc (curmod, SZ_FNAME, TY_CHAR)
+
+ # The help database contains the package names and references to
+ # all help modules in the package. Load the help database index
+ # ("_index") which contains a list of all packages in the database.
+
+ hp_sys = hdb_load (db, "_index")
+
+ # Expand the template list into a list of simple "pak.mod"
+ # templates, where the package name is spelled out and only
+ # the module template remains to be expanded. The null
+ # template list gets turned into "curpack.".
+
+ tl = tl_open (db, hp_sys, tlist, ctrl)
+ Memc[curmod] = EOS
+ no_matches = true
+ matchall = (H_ALLMODULES(ctrl) == YES)
+
+ # Process each "package_name.module_template" element of the TL
+ # list. The package_name field is always valid. If the module
+ # field is null, package help is desired, so print help on the
+ # package as if it were a module. Otherwise, expand the module
+ # template for the package and process help on each module.
+
+ while (tl_read (tl, Memc[template], SZ_FNAME) != EOF) {
+ # Extract package name.
+ op = pakname
+ for (ip=template; IS_WHITE(Memc[ip]); ip=ip+1)
+ ;
+ for (; Memc[ip] != '.' && Memc[ip] != EOS; ip=ip+1) {
+ Memc[op] = Memc[ip]
+ op = op + 1
+ }
+ Memc[op] = EOS
+
+ # Extract module template.
+ op = modtemp
+ if (Memc[ip] == '.')
+ ip = ip + 1
+ for (; Memc[ip] != EOS; ip=ip+1) {
+ Memc[op] = Memc[ip]
+ op = op + 1
+ }
+ Memc[op] = EOS
+
+ # The following is used to count the number of matches for a module
+ # (used to generate the "No help available" message). The
+ # template list will typically contain sequences like "curpak.mod",
+ # "paki.", "pakj.", "pak1.mod", "pak2.mod", and so on (where the
+ # pak[ij] are the full names of packages matched by an ambiguous
+ # template). Reset no_matches whenever the module name changes.
+ # If the module name disappears, i.e., if the template is a package
+ # name, then we have a match if the old module name is an
+ # abbreviation for the package.
+
+ if (Memc[curmod] == EOS || strne(Memc[modtemp],Memc[curmod])) {
+ if (Memc[modtemp] == EOS) {
+ if (ml_patmatch (Memc[pakname], Memc[modtemp]) > 0)
+ no_matches = false
+ } else {
+ if (no_matches && Memc[curmod] != EOS) {
+ call eprintf ("No help available for `%s'\n")
+ call pargstr (Memc[curmod])
+ }
+ no_matches = true
+ call strcpy (Memc[modtemp], Memc[curmod], SZ_FNAME)
+ }
+ }
+
+ # Search system help directory for the named package. If it
+ # cannot be found it is not an error if the original template
+ # was ambiguous (did not have a "."). A package reference is
+ # always generated for an ambiguous template because we do not
+ # know what the user wants help for.
+
+ pk = hd_findmod (hp_sys, Memc[pakname])
+ if (pk == 0) {
+ if (Memc[modtemp] == EOS)
+ if (stridxs (".", tlist) != 0) {
+ call eprintf ("Package `%s' not in Help database\n")
+ call pargstr (Memc[pakname])
+ }
+ next
+ }
+
+ # If module template is null, user wants help on the package
+ # itself; print help on the package as a module of hp_sys.
+ # Otherwise expand the module template and print help on each
+ # module.
+
+ if (Memc[modtemp] == EOS) {
+ if (print_help (db, hp_sys, Memc[pakname], pk, ctrl) == ERR) {
+ call eprintf ("No help available for package `%s'\n")
+ call pargstr (Memc[pakname])
+ }
+ } else {
+ # Get name of package helpdir for package `pk'.
+ if (hd_getname (hp_sys,pk,TY_PKG,Memc[fname],SZ_FNAME) == 0) {
+ call eprintf ("No help available for package `%s'\n")
+ call pargstr (Memc[pakname])
+ next
+ }
+
+ # Open the help directory for the package, then open the
+ # template.
+
+ iferr (hp_pak = hdb_load (db, Memc[fname]))
+ next
+ modlist = ml_open (hp_pak, Memc[modtemp])
+
+ # Process each module matching the module template. The QUIT
+ # flag is set if the user responds no to the "more" query
+ # between help blocks or files.
+
+ while (ml_read (modlist, m, Memc[module], SZ_FNAME) != EOF) {
+ if (print_help (db, hp_pak, Memc[module], m, ctrl) == OK) {
+ no_matches = false
+ if (!matchall)
+ break
+ }
+ if (H_QUIT(ctrl) == YES)
+ break
+ }
+
+ call ml_close (modlist)
+ call hdb_free (db, hp_pak)
+ }
+
+ if (H_QUIT(ctrl) == YES)
+ break
+ else if (!matchall && !no_matches)
+ break
+ }
+
+ # A final check for no matches is necessary for the last module in
+ # the template list.
+
+ if (no_matches && Memc[curmod] != EOS) {
+ call eprintf ("No help available for `%s'\n")
+ call pargstr (Memc[curmod])
+ }
+
+ call tl_close (tl)
+ call hdb_free (db, hp_sys)
+ call sfree (sp)
+end
diff --git a/pkg/system/help/prblkhdr.x b/pkg/system/help/prblkhdr.x
new file mode 100644
index 00000000..168965ab
--- /dev/null
+++ b/pkg/system/help/prblkhdr.x
@@ -0,0 +1,80 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "help.h"
+
+# PR_BLOCK_HEADER -- Print the help block header. Clear screen first if
+# enabled. Print header in the form
+#
+# MODNAME (section) title MODNAME (section)
+#
+# followed by a blank line.
+
+procedure pr_block_header (hb, modname, ctrl)
+
+pointer hb # encode help block header
+char modname[ARB] # module name
+pointer ctrl # help control block
+
+char blank
+int n, center, offset, lmargin, rmargin
+pointer sp, lbuf, edge, op, hbuf
+int strlen(), gstrcpy()
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+ call salloc (edge, SZ_LINE, TY_CHAR)
+ call salloc (hbuf, SZ_LINE, TY_CHAR)
+
+ # Clear screen.
+ if (H_FORMAT(ctrl) == HF_TEXT) {
+ if (H_SOFLAG(ctrl) == YES)
+ call houtput (ctrl, "\f")
+ } else {
+ call sfree (sp)
+ return
+ }
+
+ lmargin = H_LMARGIN(ctrl)
+ rmargin = min (H_RMARGIN(ctrl), SZ_LINE-1)
+
+ # Initialize the output line to blanks.
+ blank = ' '
+ call amovkc (blank, Memc[lbuf], SZ_LINE)
+
+ n = strlen (HB_TITLE(hb))
+ center = (lmargin + rmargin) / 2
+ offset = max (lmargin, center - n/2)
+
+ # Center help block title in output line.
+ call amovc (HB_TITLE(hb), Memc[lbuf+offset], min(n,rmargin-offset))
+
+ # Format the MODNAME (section) into the "edge" buffer. MODNAME is the
+ # module name (one of the keys), transformed to upper case.
+
+ if (HB_NKEYS(hb) >= 1) {
+ op = edge + gstrcpy (modname, Memc[edge], SZ_LINE)
+ call strupr (Memc[edge])
+ } else {
+ Memc[edge] = EOS
+ op = edge
+ }
+
+ if (HB_SECTION(hb) != EOS) {
+ call sprintf (Memc[op], SZ_LINE-SZ_KEY, " (%s)")
+ call pargstr (HB_SECTION(hb))
+ }
+
+ n = strlen (Memc[edge])
+ call amovc (Memc[edge], Memc[lbuf+lmargin-1], n)
+ call amovc (Memc[edge], Memc[lbuf + rmargin - n], n)
+
+ Memc[lbuf+rmargin] = '\n'
+ Memc[lbuf+rmargin+1] = EOS
+
+ # Write out the header line, followed by a blank line.
+ call houtput (ctrl, Memc[lbuf])
+ call houtput (ctrl, "\n")
+
+ call sfree (sp)
+end
diff --git a/pkg/system/help/prdir.x b/pkg/system/help/prdir.x
new file mode 100644
index 00000000..08322522
--- /dev/null
+++ b/pkg/system/help/prdir.x
@@ -0,0 +1,108 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ttyset.h>
+include <error.h>
+include "help.h"
+
+# PR_DIRECTORY -- Print a directory of the help blocks for a package.
+# Extract the names of all the modules therein into a string buffer
+# and print it as a table.
+
+define SZ_OBUF 2048 # buffer for directory
+define MAX_MODULES 500 # max modules that can be sorted
+define MAX_NAMELEN 20 # max chars in a module name
+define FIRST_COL 6
+define exit_ 90
+
+
+procedure pr_directory (db, hp, pakname, paknum, ctrl)
+
+pointer db # help database descriptor
+pointer hp # root help directory
+char pakname[ARB] # name of package
+int paknum # package number in root directory
+pointer ctrl # help control params
+
+bool multiple_directories
+int m, fd
+pointer sp, indices, hdr, fname, hp_pak, lbuf, obuf
+
+int hd_getname(), ttystati(), stropen(), getline()
+pointer hdb_load()
+errchk hd_getname, ttystati
+
+begin
+ call smark (sp)
+ call salloc (indices, MAX_MODULES, TY_POINTER)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+ call salloc (hdr, SZ_FNAME, TY_CHAR)
+ call salloc (obuf, SZ_OBUF, TY_CHAR)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+
+ # Get the filename of the help directory for the package.
+ if (hd_getname (hp,paknum,TY_PKG,Memc[fname],SZ_FNAME) == 0) {
+ call eprintf ("No help available for package `%s'\n")
+ call pargstr (pakname)
+ goto exit_
+ }
+
+ # Open the help directory for the package.
+ iferr (hp_pak = hdb_load (db, Memc[fname])) {
+ call sfree (sp)
+ call erract (EA_WARN)
+ goto exit_
+ }
+
+ # Extract the names of the modules in the package. Save the pointers
+ # in an array for the table print routine.
+
+ for (m=0; m < MAX_MODULES; m=m+1) {
+ call salloc (Memi[indices+m], MAX_NAMELEN, TY_CHAR)
+ if (hd_getname (hp_pak, m+1, TY_MODNAME, Memc[Memi[indices+m]],
+ MAX_NAMELEN) == 0)
+ break
+ }
+
+ # If the template supplied by the user specified more than a single
+ # package, print the name of the package.
+
+ multiple_directories = (H_LENTL(ctrl) > 1)
+
+ # We may have been called with any legal abbreviation of the package
+ # name; fetch the full name from the system package directory.
+
+ if (multiple_directories) {
+ call houtput (ctrl, "\n")
+ if (hd_getname (hp, paknum, TY_MODNAME, Memc[hdr], SZ_FNAME) != 0) {
+ call strcat (":\n", Memc[hdr], SZ_FNAME)
+ call houtput (ctrl, Memc[hdr])
+ }
+ }
+
+ # Now print the table. It is not necessary to sort the table,
+ # because the "helpdir" code (which reads the help directory) has
+ # already done so. The directory is written into a string buffer
+ # and then output line by line with houtput, since there is no
+ # easy way to make STRTBL call houtput.
+
+ # Format the table into the buffer. A blank line marks the end of
+ # the table.
+
+ fd = stropen (Memc[obuf], SZ_OBUF, NEW_FILE)
+ call strtbl (fd, Memc, Memi[indices], m, FIRST_COL,
+ ttystati (H_TTY(ctrl), TTY_NCOLS), MAX_NAMELEN, 0)
+ call putline (fd, "\n")
+ call close (fd)
+
+ # Copy lines from the buffer to the HELP output. Do not read off
+ # end of buffer or FIO will file fault and abort.
+
+ fd = stropen (Memc[obuf], SZ_OBUF, READ_ONLY)
+ while (getline (fd, Memc[lbuf]) > 1)
+ call houtput (ctrl, Memc[lbuf])
+ call close (fd)
+
+ call hdb_free (db, hp_pak)
+exit_
+ call sfree (sp)
+end
diff --git a/pkg/system/help/prfile.x b/pkg/system/help/prfile.x
new file mode 100644
index 00000000..8ecf1af1
--- /dev/null
+++ b/pkg/system/help/prfile.x
@@ -0,0 +1,84 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <finfo.h>
+include <time.h>
+include <ctype.h>
+include "help.h"
+
+# PR_FILE -- Print a file. Called to print menu files and source files.
+# Do not print block header, but do page output if enabled by user.
+
+procedure pr_file (fname, ctrl, pakname)
+
+char fname[ARB]
+pointer ctrl
+char pakname[ARB]
+
+int center_col, ip
+long fi[LEN_FINFO]
+pointer sp, lbuf, time
+int open(), hinput(), strlen(), finfo()
+errchk houtput, open, hinput
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+ call salloc (time, SZ_TIME, TY_CHAR)
+
+ H_EOF(ctrl) = NO
+ H_RAWIN(ctrl) = YES
+ center_col = (H_LMARGIN(ctrl) + H_RMARGIN(ctrl)) / 2
+
+ # Clear screen and print filename if printing source file.
+ # Filename is printed centered between left and right margins.
+ # Note header must be two lines for man_output().
+
+ if (H_OPTION(ctrl) == O_SOURCE) {
+ if (finfo (fname, fi) == ERR) {
+ call sprintf (Memc[lbuf], SZ_LINE, "%s `%s'")
+ call pargstr ("Cannot get file info for file")
+ call pargstr (fname)
+ call error (20, Memc[lbuf])
+ }
+ call cnvtime (FI_MTIME(fi), Memc[time], SZ_TIME)
+
+ # Header format: "FILE date FILE".
+ call sprintf (Memc[lbuf], SZ_LINE, "%*t%s %*t%s %*t%s\n")
+ call pargi (H_LMARGIN(ctrl))
+ call pargstr (fname)
+ call pargi (center_col - strlen(Memc[time]) / 2)
+ call pargstr (Memc[time])
+ call pargi (H_RMARGIN(ctrl) - strlen (fname) + 1)
+ call pargstr (fname)
+
+ call houtput (ctrl, "\f")
+ call houtput (ctrl, Memc[lbuf])
+ call houtput (ctrl, "\n")
+ }
+
+ # Use hinput/houtput to read and print file so that output is
+ # paginated.
+ H_IN(ctrl) = open (fname, READ_ONLY, TEXT_FILE)
+
+ while (hinput (ctrl, Memc[lbuf]) != EOF) {
+ if (H_OPTION(ctrl) == O_REFERENCES) {
+ # Replace the newline character.
+ ip = strlen (Memc[lbuf]) - 1
+ Memc[lbuf+ip] = ' '
+
+ # Append the package name.
+ call strcat (" [", Memc[lbuf], SZ_LINE)
+ call strcat (pakname, Memc[lbuf], SZ_LINE)
+ call strcat ("]\n", Memc[lbuf], SZ_LINE)
+
+ # Strip leading whitespace.
+ for (ip=0; IS_WHITE(Memc[lbuf+ip]); ip=ip+1)
+ ;
+ call houtput (ctrl, Memc[lbuf+ip])
+ } else
+ call houtput (ctrl, Memc[lbuf])
+ }
+
+ call close (H_IN(ctrl))
+ call sfree (sp)
+end
diff --git a/pkg/system/help/prfnames.x b/pkg/system/help/prfnames.x
new file mode 100644
index 00000000..f4e42205
--- /dev/null
+++ b/pkg/system/help/prfnames.x
@@ -0,0 +1,69 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "help.h"
+include "helpdir.h"
+
+# PR_FILENAMES -- Print file names associated with module.
+
+define NFILES 5
+
+procedure pr_filenames (hp, module, modnum, ctrl)
+
+pointer hp
+char module[ARB]
+int modnum
+pointer ctrl
+
+int i, nfiles, ftype[NFILES]
+pointer sp, lbuf, pakname, modname, fname[NFILES]
+int hd_getname()
+errchk hd_getname, houtput
+data ftype /TY_HLP, TY_SYS, TY_SRC, TY_PKG, TY_MEN/
+string fcode "hlpsyssrcpkgmen"
+
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+ call salloc (pakname, SZ_FNAME, TY_CHAR)
+ call salloc (modname, SZ_FNAME, TY_CHAR)
+
+ do i = 1, NFILES
+ call salloc (fname[i], SZ_PATHNAME, TY_CHAR)
+
+ nfiles = 0
+ do i = 1, NFILES
+ if (hd_getname (hp, modnum, ftype[i], Memc[fname[i]],
+ SZ_PATHNAME) > 0)
+ nfiles = nfiles + 1
+
+ if (nfiles > 0) {
+ # Get the package and module names. If there is no package name
+ # in the help directory, it is root help directory, and the module
+ # name is actually the name of a package.
+
+ if (HD_PAKNAME(hp) == 0) {
+ call strcpy (module, Memc[pakname], SZ_FNAME)
+ Memc[modname] = EOS
+ } else {
+ call strcpy (Memc[HD_SBUF(hp) + HD_PAKNAME(hp)],
+ Memc[pakname], SZ_FNAME)
+ call strcpy (module, Memc[modname], SZ_FNAME)
+ }
+
+ # Print "pakname.modname".
+ if (H_LENTL(ctrl) > 1)
+ call pr_modname (ctrl, Memc[pakname], Memc[modname])
+
+ # List the names of the help files.
+ do i = 1, NFILES
+ if (Memc[fname[i]] != EOS) {
+ call sprintf (Memc[lbuf], SZ_LINE, "\t%0.3s = %s\n")
+ call pargstr (fcode[(i-1)*3+1])
+ call pargstr (Memc[fname[i]])
+ call houtput (ctrl, Memc[lbuf])
+ }
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/system/help/prhelp.x b/pkg/system/help/prhelp.x
new file mode 100644
index 00000000..7fba611d
--- /dev/null
+++ b/pkg/system/help/prhelp.x
@@ -0,0 +1,144 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include "help.h"
+include "helpdir.h"
+
+.help print_help
+.nf __________________________________________________________________________
+PRINT_HELP -- Print help documentation for the named module or parameter.
+We are called with the name of a single module; all fiddling with packages
+and templates has been performed by the time we are called. The help
+directory is open and contains the names of the files containing the help
+source for the module. Our main task is to determine what kind of help
+is desired and call the appropriate routine.
+
+Recall that the principal options are
+
+ option meaning file
+
+ help print help block for module hlp
+ param print help for single param hlp
+ section print a single section hlp
+ files print file names ...
+ source print source file src
+ sysdoc print system documentation sys
+ alldoc print all documentation hlp,sys
+ summary print help block titles hlp,sys
+.endhelp ______________________________________________________________________
+
+define exit_ 90
+
+
+# PRINT_HELP -- Print the indicated type of help text for the named module.
+# If we are called the module exists in the package, but the type of help
+# information indicated may not exist. Return OK if help is printed, ERR
+# otherwise.
+
+int procedure print_help (db, hp, module, modnum, ctrl)
+
+pointer db # help database descriptor
+pointer hp # help directory for package
+char module[ARB] # name of module for which help is desired
+int modnum # module number within package directory
+pointer ctrl # help control parameters
+
+bool not_found
+int option
+pointer sp, fname, pakname, modname
+int hd_getname()
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_PATHNAME, TY_CHAR)
+ call salloc (pakname, SZ_FNAME, TY_CHAR)
+ call salloc (modname, SZ_FNAME, TY_CHAR)
+
+ # Handle options which do not access a help file.
+ option = H_OPTION(ctrl)
+ H_STATE(ctrl) = BOF
+ not_found = true
+
+ if (option == O_MENU) {
+ if (hd_getname (hp, modnum, TY_MEN, Memc[fname], SZ_PATHNAME) == 0)
+ goto exit_
+ iferr (call pr_file (Memc[fname], ctrl, "test"))
+ call erract (EA_WARN)
+ else
+ not_found = false
+
+ } else if (option == O_FILES) {
+ # Print names of all files associated with module.
+ ifnoerr (call pr_filenames (hp, module, modnum, ctrl))
+ not_found = false
+
+ } else if (option == O_DIR) {
+ # Print a directory of all help blocks for the named package.
+ ifnoerr (call pr_directory (db, hp, module, modnum, ctrl))
+ not_found = false
+
+ } else if (option == O_SOURCE) {
+ # Print source file, if given.
+ if (hd_getname (hp, modnum, TY_SRC, Memc[fname], SZ_PATHNAME) == 0)
+ goto exit_
+ iferr (call pr_file (Memc[fname], ctrl, "test"))
+ call erract (EA_WARN)
+ else
+ not_found = false
+
+ } else if (option == O_SUMMARY) {
+ # Scan hlp file and print summary of help blocks.
+ if (hd_getname (hp, modnum, TY_HLP, Memc[fname], SZ_PATHNAME) == 0)
+ goto exit_
+ iferr (call pr_summary (Memc[fname], ctrl))
+ call erract (EA_WARN)
+ else
+ not_found = false
+
+ } else {
+ # Get the package and module names. If there is no package name
+ # in the help directory, it is root help directory, and the module
+ # name is actually the name of a package.
+
+ if (HD_PAKNAME(hp) == 0) {
+ call strcpy (module, Memc[pakname], SZ_FNAME)
+ Memc[modname] = EOS
+ } else {
+ call strcpy (Memc[HD_SBUF(hp) + HD_PAKNAME(hp)],
+ Memc[pakname], SZ_FNAME)
+ call strcpy (module, Memc[modname], SZ_FNAME)
+ }
+
+ # Print full helpblock (default action).
+ if (option == O_HELP || option == O_ALLDOC ||
+ option == O_REFERENCES) {
+
+ if (hd_getname (hp,modnum,TY_HLP,Memc[fname],SZ_PATHNAME) > 0) {
+ ifnoerr {
+ call pr_helpblock (Memc[fname],
+ Memc[pakname], Memc[modname], TY_HLP, ctrl)
+ } then
+ not_found = false
+ }
+ }
+
+ # Print system documentation.
+ if (option == O_SYSDOC || option == O_ALLDOC) {
+ if (hd_getname (hp,modnum,TY_SYS,Memc[fname],SZ_PATHNAME) > 0) {
+ ifnoerr {
+ call pr_helpblock (Memc[fname],
+ Memc[pakname], Memc[modname], TY_HLP, ctrl)
+ } then
+ not_found = false
+ }
+ }
+ }
+
+exit_
+ call flush (H_OUT(ctrl))
+ call sfree (sp)
+ if (not_found)
+ return (ERR)
+ else
+ return (OK)
+end
diff --git a/pkg/system/help/prhlpblk.x b/pkg/system/help/prhlpblk.x
new file mode 100644
index 00000000..833cc09b
--- /dev/null
+++ b/pkg/system/help/prhlpblk.x
@@ -0,0 +1,154 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include "help.h"
+
+# PR_HELPBLOCK -- Print a normal helpblock. Open the help file and search
+# for the named help block. If found and not printing single section or
+# parameter, print manpage title. Process helpblock through Lroff.
+
+procedure pr_helpblock (fname, pakname, modname, blktype, ctrl)
+
+char fname[ARB]
+char pakname[ARB]
+char modname[ARB]
+int blktype
+pointer ctrl
+
+bool block_found, help_file, at_eof
+int fd, lmarg, rmarg, soflag, foflag, i, nblocks
+pointer sp, hb, block_name, ps
+
+bool streq()
+int open(), hb_getnextblk()
+pointer ps_open()
+extern hinput(), houtput()
+errchk hb_getnextblk, pr_block_header
+
+begin
+ call smark (sp)
+ call salloc (hb, LEN_HBSTRUCT, TY_STRUCT)
+ call salloc (block_name, SZ_FNAME, TY_CHAR)
+
+ iferr (fd = open (fname, READ_ONLY, TEXT_FILE)) {
+ call sfree (sp)
+ call erract (EA_ERROR)
+ return
+ }
+
+ # Search through the help file for the named help block, of type
+ # help or system. Decode the help block header into the HB struct.
+
+ H_IN(ctrl) = fd
+ HB_LINENO(hb) = 0
+ H_EOF(ctrl) = NO
+ lmarg = H_LMARGIN(ctrl)
+ rmarg = H_RMARGIN(ctrl)
+ at_eof = false
+ help_file = false
+ nblocks = 0
+ call strcpy (modname, Memc[block_name], SZ_FNAME)
+
+ # Output standout mode control chars (soflag) only if told to do so.
+ # Only output forms mode control chars if using Manpage format output
+ # filter.
+
+ soflag = H_SOFLAG(ctrl)
+ foflag = H_MANPAGE(ctrl)
+
+ # Process all help blocks in the file which list the current key
+ # (modname) in their title block, and which are of the desired
+ # type, i.e., hlp or sys.
+
+ while (!at_eof && H_QUIT(ctrl) != YES) {
+ block_found = false
+ repeat {
+ at_eof = (hb_getnextblk (hb, ctrl) == EOF)
+ if (!at_eof) {
+ help_file = true
+
+ if (HB_TYPE(hb) == blktype || blktype == NULL) {
+ # Search keyword list for the module name. If no
+ # module name was given, match anything.
+
+ if (modname[1] == EOS) {
+ block_found = true
+ nblocks = nblocks + 1
+ } else {
+ for (i=1; i <= HB_NKEYS(hb); i=i+1)
+ if (streq (HB_KEY(hb,i), modname)) {
+ block_found = true
+ nblocks = nblocks + 1
+ break
+ }
+ }
+
+ # If no module name, use first key as help block name.
+ if (modname[1] == EOS)
+ call strcpy (HB_KEY(hb,1), Memc[block_name],
+ SZ_FNAME)
+ }
+ }
+ } until (block_found || at_eof)
+
+ if (at_eof) {
+ # If cannot find block, something is wrong, because the
+ # help directory said there was a block of the desired
+ # type in this file. If no help blocks at all were found
+ # in the file, the best thing we can do is to simply print
+ # the file; hopefully it contains unformatted text. If the
+ # file contains help blocks, but none with the correct key
+ # and type, then we print a warning message.
+
+ if (!help_file) {
+ call close (fd)
+ # Print header only if there is more than a single list
+ # element.
+ if (H_LENTL(ctrl) > 1 && H_OPTION(ctrl) != O_REFERENCES)
+ call pr_modname (ctrl, pakname, modname)
+ call pr_file (fname, ctrl, pakname)
+ call sfree (sp)
+ return
+ } else if (nblocks == 0) {
+ call eprintf ("Cannot find help block for `%s' in `%s'\n")
+ call pargstr (modname)
+ call pargstr (fname)
+ break
+ } else
+ break
+ }
+
+ # Clear the screen and print the block header, if not printing a
+ # single section or parameter.
+
+ H_EOF(ctrl) = NO
+ if (H_SECNAME(ctrl) == EOS && H_PARNAME(ctrl) == EOS)
+ call pr_block_header (hb, Memc[block_name], ctrl)
+
+
+ # Finally!! Call Lroff to format the help text.
+ iferr {
+ if (H_FORMAT(ctrl) == HF_TEXT) {
+ call lroff (hinput, ctrl, houtput, ctrl, lmarg, rmarg,
+ soflag, foflag)
+ } else if (H_FORMAT(ctrl) == HF_HTML) {
+ call lroff2html (H_IN(ctrl), H_OUT(ctrl), Memc[block_name],
+ HB_SECTION(hb), HB_TITLE(hb), H_PARNAME(ctrl),
+ H_SECNAME(ctrl))
+ } else if (H_FORMAT(ctrl) == HF_PS) {
+ ps = ps_open (H_OUT(ctrl), YES)
+ call sprintf (Memc[block_name], SZ_LINE, "%s (%s)")
+ call pargstr (Memc[block_name])
+ call pargstr (HB_SECTION(hb))
+ call ps_header (ps, Memc[block_name], HB_TITLE(hb),
+ Memc[block_name])
+ call lroff2ps (H_IN(ctrl), H_OUT(ctrl), ps,
+ H_PARNAME(ctrl), H_SECNAME(ctrl))
+ }
+ } then
+ call erract (EA_WARN)
+ }
+
+ call close (fd)
+ call sfree (sp)
+end
diff --git a/pkg/system/help/prmodname.x b/pkg/system/help/prmodname.x
new file mode 100644
index 00000000..dbf2b939
--- /dev/null
+++ b/pkg/system/help/prmodname.x
@@ -0,0 +1,35 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "help.h"
+
+# PR_MODNAME -- Print the module name header "pakname.modname". Omit the
+# package name if it begins with an underscore, unless there is no module
+# name.
+
+procedure pr_modname (ctrl, pakname, modname)
+
+pointer ctrl # help control parameters
+char pakname[ARB] # package name
+char modname[ARB] # module name
+
+pointer sp, lbuf
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+
+ if (pakname[1] != EOS || modname[1] != EOS) {
+ call houtput (ctrl, "\n")
+ if (pakname[1] == '_' && modname[1] != EOS) {
+ call sprintf (Memc[lbuf], SZ_LINE, "%s:\n")
+ call pargstr (modname)
+ } else {
+ call sprintf (Memc[lbuf], SZ_LINE, "%s.%s:\n")
+ call pargstr (pakname)
+ call pargstr (modname)
+ }
+ call houtput (ctrl, Memc[lbuf])
+ }
+
+ call sfree (sp)
+end
diff --git a/pkg/system/help/prsummary.x b/pkg/system/help/prsummary.x
new file mode 100644
index 00000000..d030842d
--- /dev/null
+++ b/pkg/system/help/prsummary.x
@@ -0,0 +1,95 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "help.h"
+
+# PR_SUMMARY -- Print a summary of the headers of all help blocks in a
+# helpfile. Open the help file and search for the successive blocks.
+# Print nice diagnostics describing the contents of the file.
+
+define TABSTOP 50
+
+procedure pr_summary (fname, ctrl)
+
+char fname[ARB]
+pointer ctrl
+
+int fd, i, n, nlines
+pointer sp, hb, lbuf
+int open(), gstrcat(), hb_getnextblk(), strlen(), getline(), strmatch()
+
+begin
+ call smark (sp)
+ call salloc (hb, LEN_HBSTRUCT, TY_STRUCT)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+
+ iferr (fd = open (fname, READ_ONLY, TEXT_FILE)) {
+ call eprintf ("Cannot open helpfile `%s'\n")
+ call pargstr (fname)
+ call sfree (sp)
+ return
+ }
+ HB_LINENO(hb) = 0
+ H_IN(ctrl) = fd
+
+ # Search through the help file for the named help block, of type
+ # help or system. Decode the help block header into the HB struct.
+
+ call houtput (ctrl, "\n")
+ call sprintf (Memc[lbuf], SZ_LINE, "==> %s <==\n")
+ call pargstr (fname)
+ call houtput (ctrl, Memc[lbuf])
+
+ while (H_EOF(ctrl) != EOF && hb_getnextblk (hb, ctrl) != EOF) {
+ # Describe help block.
+ call sprintf (Memc[lbuf], SZ_LINE, "%6d ")
+ call pargi (HB_LINENO(hb))
+
+ # Print keyword names.
+ if (HB_NKEYS(hb) > 0)
+ n = gstrcat (HB_KEY(hb,1), Memc[lbuf], SZ_LINE)
+ else
+ n = strlen (Memc[lbuf])
+
+ for (i=2; i <= HB_NKEYS(hb); i=i+1) {
+ n = gstrcat (", ", Memc[lbuf], SZ_LINE)
+ n = gstrcat (HB_KEY(hb,i), Memc[lbuf], SZ_LINE)
+ }
+
+ # Advance to tabstop and print section label.
+ repeat {
+ Memc[lbuf+n] = ' '
+ n = n + 1
+ } until (n >= TABSTOP)
+ Memc[lbuf+n] = EOS
+
+ n = gstrcat (HB_SECTION(hb), Memc[lbuf], SZ_LINE)
+ if (HB_TYPE(hb) != TY_HLP) {
+ call sprintf (Memc[lbuf+n], SZ_LINE-n, " (%s)")
+ call pargstr (HB_TYPESTR(hb))
+ }
+
+ call strcat ("\n", Memc[lbuf], SZ_LINE)
+ call houtput (ctrl, Memc[lbuf])
+
+ # Print block title, if any, on next line.
+ if (strlen (HB_TITLE(hb)) > 0) {
+ call sprintf (Memc[lbuf], SZ_LINE, " %s\n")
+ call pargstr (HB_TITLE(hb))
+ call houtput (ctrl, Memc[lbuf])
+ }
+
+ # Count and print number of lines in help block.
+ for (nlines=0; getline (fd, Memc[lbuf]) != EOF; nlines=nlines+1)
+ if (strmatch (Memc[lbuf], "^.{endhelp}") > 0)
+ break
+ call sprintf (Memc[lbuf], SZ_LINE, " block size %d lines\n")
+ call pargi (nlines)
+
+ call houtput (ctrl, Memc[lbuf])
+ call houtput (ctrl, "\n")
+ HB_LINENO(hb) = HB_LINENO(hb) + nlines + 1
+ }
+
+ call close (fd)
+ call sfree (sp)
+end
diff --git a/pkg/system/help/t_hdbexamine.x b/pkg/system/help/t_hdbexamine.x
new file mode 100644
index 00000000..8046848e
--- /dev/null
+++ b/pkg/system/help/t_hdbexamine.x
@@ -0,0 +1,35 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <syserr.h>
+include <error.h>
+include "help.h"
+
+
+# HDBEXAMINE -- Examine the help database.
+
+procedure t_hdbexamine()
+
+pointer sp, helpdb
+bool streq(), clgetb()
+int envgets()
+string s_helpdb "helpdb"
+
+begin
+ call smark (sp)
+ call salloc (helpdb, SZ_HELPDB, TY_CHAR)
+
+ # Fetch the name of the help database file to be examined. If the
+ # name is "helpdb", the filename is taken from the environment.
+
+ call clgstr (s_helpdb, Memc[helpdb], SZ_HELPDB)
+ if (streq (Memc[helpdb], s_helpdb))
+ if (envgets (s_helpdb, Memc[helpdb], SZ_HELPDB) <= 0)
+ call syserrs (SYS_ENVNF, s_helpdb)
+
+ # Examine the structure and contents of the database, printing the
+ # results on the standard output.
+
+ call hdb_examine (STDOUT, Memc[helpdb], clgetb ("verbose"))
+
+ call sfree (sp)
+end
diff --git a/pkg/system/help/t_help.x b/pkg/system/help/t_help.x
new file mode 100644
index 00000000..2f840fb0
--- /dev/null
+++ b/pkg/system/help/t_help.x
@@ -0,0 +1,290 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <syserr.h>
+include <finfo.h>
+include <fset.h>
+include <error.h>
+include "help.h"
+
+.help help
+.nf __________________________________________________________________________
+HELP -- Print help documentation for the named modules (tasks, packages,
+or library procedures). Given the package name and module name, the help
+database is used to locate the file(s) containing the desired help text.
+Documentation is organized by package, and is maintained in the package
+directory. The Lroff text formatter is used to process help text containing
+formatting directives. Text is output via the TTY interface, which processes
+standout mode control sequences, and clears the screen between pages.
+If the standard output is redirected, output is via putline, and pagination
+is disabled. See Help.hlp for detailed documentation.
+.endhelp _____________________________________________________________________
+
+define SZ_TEMPBUF SZ_HELPDB
+
+
+# HELP -- The main procedure. Fetch all parameters, decode the option
+# string, set up the control structure, and finally call process_template
+# to expand the module template and process the help text for each module.
+
+procedure t_help()
+
+int ncols, nlines, list, out_device
+long fi[LEN_FINFO], db_ctime
+char helpdb[SZ_HELPDB], device[SZ_FNAME]
+bool output_is_not_redirected, file_template
+pointer sp, ctrl, option, tempbuf, db, tty, fname, tempdev
+
+long clktime()
+pointer ttyodes(), hdb_open()
+bool strne(), streq(), clgetb()
+int btoi(), stridxs(), finfo(), fntopnb(), fntgfnb(), strdic()
+int clgeti(), get_option(), fstati(), envgets(), envgeti()
+
+data tty /NULL/, db_ctime /0/
+string s_helpdb "helpdb"
+define forms_ 91
+
+begin
+ call smark (sp)
+ call salloc (ctrl, LEN_CTRLSTRUCT, TY_STRUCT)
+ call salloc (option, SZ_FNAME, TY_CHAR)
+ call salloc (tempbuf, SZ_TEMPBUF, TY_CHAR)
+ call salloc (tempdev, SZ_FNAME, TY_CHAR)
+ call salloc (fname, SZ_PATHNAME, TY_CHAR)
+
+ # If we were called without any arguments, do not query for the
+ # template, just set it to null and help will be given for the
+ # current package.
+
+ call aclri (Memi[ctrl], LEN_CTRLSTRUCT)
+ if (clgeti ("$nargs") == 0) {
+ H_OPTION(ctrl) = O_MENU
+ H_TEMPLATE(ctrl) = EOS
+ H_PARNAME(ctrl) = EOS
+ H_SECNAME(ctrl) = EOS
+ } else
+ call clgstr ("template", H_TEMPLATE(ctrl), SZ_LINE)
+
+ # get the output device type. If the device is 'gui' pass off to
+ # the XHELP code to execute the GUI, otherwise process the device
+ # type once we set up the normal HELP task structure.
+
+ call aclrc (Memc[tempdev], SZ_TEMPBUF)
+ call clgstr ("device", Memc[tempdev], SZ_FNAME)
+ out_device = strdic (Memc[tempdev], device, SZ_FNAME, HF_DEVICES)
+ if (out_device == HF_GUI) {
+ call xhelp (H_TEMPLATE(ctrl))
+ call sfree (sp)
+ return
+ }
+
+ # Determine whether the template is a module name template or a
+ # file matching template.
+
+ file_template = clgetb ("file_template")
+ if (file_template) {
+ H_OPTION(ctrl) = O_HELP
+ goto forms_
+ }
+
+ # Fetch the name of the help database, i.e., "helpdb", "helpdir",
+ # or the name of a file. The first time the process runs we open
+ # and read in the database. The database remains in memory between
+ # calls to HELP, provided the process does not shutdown, provided
+ # the name of the database to be used does not change, and provided
+ # a new help database is not created.
+
+ call aclrc (Memc[tempbuf], SZ_TEMPBUF)
+ call clgstr (s_helpdb, Memc[tempbuf], SZ_TEMPBUF)
+ if (streq (Memc[tempbuf], s_helpdb))
+ if (envgets (s_helpdb, Memc[tempbuf], SZ_TEMPBUF) <= 0)
+ call syserrs (SYS_ENVNF, s_helpdb)
+
+ # Check to see if any of the files in the list are newer than the
+ # time of the last hdb_open.
+
+ if (db_ctime > 0) {
+ list = fntopnb (Memc[tempbuf], YES)
+ while (fntgfnb (list, Memc[fname], SZ_PATHNAME) != EOF) {
+ if (finfo (Memc[fname], fi) == ERR) {
+ call eprintf ("Cannot access help database file `%s'\n")
+ call pargstr (Memc[fname])
+ } else if (db != NULL && FI_CTIME(fi) > db_ctime) {
+ call hdb_close (db)
+ db = NULL
+ break
+ }
+ }
+ call fntclsb (list)
+ } else
+ db = NULL
+
+ # Reopen the help database if in-core copy is out of date.
+ if (db == NULL || strne (Memc[tempbuf], helpdb)) {
+ call strcpy (Memc[tempbuf], helpdb, SZ_HELPDB)
+ if (db != NULL)
+ call hdb_close (db)
+ db = hdb_open (helpdb)
+ db_ctime = clktime (long(0))
+ }
+
+ # Fetch the value of the ALL switch. This determines whether help
+ # will stop after processing the first module matching the template,
+ # or process all modules in the database which match the template.
+ # Explicit use of a pattern matching character anywhere in the template
+ # enable allmodoules.
+
+ if (stridxs ("*?[],", H_TEMPLATE(ctrl)) > 0)
+ H_ALLMODULES(ctrl) = YES
+ else
+ H_ALLMODULES(ctrl) = btoi (clgetb ("all"))
+
+ # If the FILTER_INPUT flag is set, only part of the input text will be
+ # processed. Filtering is only done if printing a single section or
+ # parameter.
+
+ H_FILTER_INPUT(ctrl) = NO
+
+ # Determine whether or not text for a single section or parameter
+ # is to be output. If the value of one of these strings is "all",
+ # all sections or all parameters are to be output. If the "all"
+ # default is in effect, null the string as a flag to lower level
+ # code that all help text is to be processed.
+
+ if (H_OPTION(ctrl) == NULL) {
+ call clgstr ("section", H_SECNAME(ctrl), SZ_SECNAME)
+ if (streq (H_SECNAME(ctrl), "all")) {
+ H_SECNAME(ctrl) = EOS
+ call clgstr ("parameter", H_PARNAME(ctrl), SZ_PARNAME)
+ if (streq (H_PARNAME(ctrl), "all"))
+ H_PARNAME(ctrl) = EOS
+ }
+ if (H_SECNAME(ctrl) != EOS || H_PARNAME(ctrl) != EOS)
+ H_FILTER_INPUT(ctrl) = YES
+ }
+
+ # Fetch and decode option string; abbreviations are permitted.
+ if (H_OPTION(ctrl) != O_MENU) {
+ call clgstr ("option", Memc[option], SZ_FNAME)
+ call strlwr (Memc[option])
+ iferr (H_OPTION(ctrl) = get_option (Memc[option])) {
+ call erract (EA_WARN)
+ H_OPTION(ctrl) = O_HELP
+ }
+ }
+forms_
+ # Pause between screens of output text only if the standard output
+ # is not redirected, and if enabled by the user.
+
+ H_IN(ctrl) = ERR
+ H_OUT(ctrl) = STDOUT
+ H_NLINES(ctrl) = -1
+ H_STATE(ctrl) = BOF
+ H_EOF(ctrl) = NO
+ H_QUIT(ctrl) = NO
+
+ # If the standard output is not redirected, i.e., if writing to the
+ # terminal, determine whether or not output is to be paginated (pause
+ # between pages). If output is redirected, the pagination flag
+ # and help option controls whether or not manpage style output is
+ # enabled. Manpage output formatting is desirable only when formatting
+ # help text or printing named files.
+
+ H_RAWOUT(ctrl) = NO
+ H_MANPAGE(ctrl) = NO
+ H_PAGINATE(ctrl) = NO
+ output_is_not_redirected = (fstati (STDOUT, F_REDIR) == NO)
+
+ if (out_device < HF_GUI) {
+ if (output_is_not_redirected && out_device == HF_TERMINAL) {
+ if (clgetb ("page")) {
+ H_PAGINATE(ctrl) = YES
+ call xttysize (ncols, nlines)
+ }
+ } else {
+ if (clgetb ("page")) {
+ switch (H_OPTION(ctrl)) {
+ case O_HELP, O_SOURCE, O_SYSDOC, O_ALLDOC:
+ H_MANPAGE(ctrl) = YES
+ H_NLPP(ctrl) = clgeti ("nlpp")
+ call man_init()
+ default:
+ H_RAWOUT(ctrl) = YES
+ }
+ } else
+ H_RAWOUT(ctrl) = YES
+ }
+ }
+
+ # Get the current package. Normally this is specified as the null
+ # string or "AskCL", which causes a runtime query of the CL for the
+ # current package when a help template is expanded. The reason for
+ # providing this parameter is to allow this query to be disabled
+ # (by setting the value to the name of an actual package such as
+ # system or clpackage) so that, e.g., the help task can be called
+ # as a host level task.
+
+ iferr (call clgstr ("curpack", H_CURPACK(ctrl), SZ_CURPACK))
+ call strcpy ("AskCL", H_CURPACK(ctrl), SZ_CURPACK)
+
+ # Get output device (normally "terminal"), open TTY descriptor for
+ # the device. The TTY descriptor is left open between calls to HELP
+ # provided the process does not shutdown and the device name or page
+ # size does not change.
+
+ if (out_device == HF_TERMINAL) {
+ if (tty == NULL || strne (Memc[tempdev], device)) {
+ call strcpy (Memc[tempdev], device, SZ_FNAME)
+ if (tty != NULL)
+ call ttycdes (tty)
+ tty = ttyodes (device)
+ }
+ }
+
+ if (out_device == HF_HTML) {
+ H_FORMAT(ctrl) = HF_HTML
+ H_RAWOUT(ctrl) = YES
+ H_SOFLAG(ctrl) = NO
+ H_MANPAGE(ctrl) = NO
+ tty = NULL
+ } else if (out_device == HF_PS || out_device == HF_POSTSCRIPT) {
+ H_FORMAT(ctrl) = HF_PS
+ H_RAWOUT(ctrl) = YES
+ H_SOFLAG(ctrl) = NO
+ H_MANPAGE(ctrl) = NO
+ tty = NULL
+ } else if (out_device == HF_TEXT) {
+ H_FORMAT(ctrl) = HF_TEXT
+ H_SOFLAG(ctrl) = NO
+ } else {
+ H_FORMAT(ctrl) = HF_TEXT
+ H_SOFLAG(ctrl) = YES
+ }
+ H_TTY(ctrl) = tty
+
+ # Get left and right margins for output text. Make sure right margin
+ # does not exceed screen width of output device.
+
+ if (H_FORMAT(ctrl) == HF_TEXT) {
+ H_LMARGIN(ctrl) = max (1, clgeti ("lmargin"))
+ H_RMARGIN(ctrl) = max (H_LMARGIN(ctrl) + 1, clgeti ("rmargin"))
+ if (streq (device, "terminal"))
+ H_RMARGIN(ctrl) = min (H_RMARGIN(ctrl), envgeti ("ttyncols"))
+ }
+
+ # Initialization is completed, control structure is completed.
+ # Format and output the help text. If we have a module name template
+ # process the template against the help database, otherwise work
+ # directly out of the named files.
+
+ if (file_template)
+ call do_file_template (H_TEMPLATE(ctrl), ctrl)
+ else
+ call do_module_template (db, H_TEMPLATE(ctrl), ctrl)
+
+ # Finish last page and return buffer space if writing manpages.
+ if (H_MANPAGE(ctrl) == YES)
+ call man_close (H_OUT(ctrl))
+
+ call sfree (sp)
+end
diff --git a/pkg/system/help/t_lroff.x b/pkg/system/help/t_lroff.x
new file mode 100644
index 00000000..9df65d43
--- /dev/null
+++ b/pkg/system/help/t_lroff.x
@@ -0,0 +1,35 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# LROFF -- Text process a file.
+
+procedure t_lroff()
+
+char fname[SZ_FNAME]
+char line[SZ_LINE]
+char format[SZ_FNAME]
+int fd, lmargin, rmargin
+int open(), getline(), strmatch(), clgeti()
+extern getline(), putline()
+
+begin
+ call clgstr ("input_file", fname, SZ_FNAME)
+ fd = open (fname, READ_ONLY, TEXT_FILE)
+
+ lmargin = clgeti ("lmargin")
+ rmargin = clgeti ("rmargin")
+ call clgstr ("format", format, SZ_FNAME)
+
+ while (getline (fd, line) != EOF) {
+ if (strmatch (line, "^.help") > 0) {
+ if (format[1] == 't')
+ call lroff (getline, fd, putline, STDOUT, lmargin, rmargin,
+ YES, NO)
+ else if (format[1] == 'h')
+ call lroff2html (fd, STDOUT, fname, "", "", "", "")
+ else if (format[1] == 'p')
+ call lroff2ps (fd, STDOUT, NULL, "", "")
+ }
+ }
+
+ call close (fd)
+end
diff --git a/pkg/system/help/t_mkhelpdb.x b/pkg/system/help/t_mkhelpdb.x
new file mode 100644
index 00000000..b4cff7a7
--- /dev/null
+++ b/pkg/system/help/t_mkhelpdb.x
@@ -0,0 +1,76 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <syserr.h>
+include <error.h>
+
+# MKHELPDB -- Make (compile) the help database. The root help directory
+# is compiled, along with all sub help directories in the package hierarchy.
+# Each package in the system, including both CL packages and library packages,
+# has an associated help directory file. Despite the fact that the package
+# structure is hierarchical, package names must be distinct because packages
+# are indexed in the database in a linear structure.
+
+procedure t_mkhelpdb()
+
+bool verbose
+pointer sp, helpdir, helpdb, tempname
+int envgets(), access()
+bool streq(), clgetb()
+string s_helpdir "helpdir"
+string s_helpdb "helpdb"
+
+begin
+ call smark (sp)
+ call salloc (helpdir, SZ_FNAME, TY_CHAR)
+ call salloc (helpdb, SZ_FNAME, TY_CHAR)
+ call salloc (tempname, SZ_FNAME, TY_CHAR)
+
+ # Fetch the names of the root help directory file and the new database
+ # file. If the names are "helpdir" or "helpdb", the filenames are
+ # taken from the environment.
+
+ call clgstr (s_helpdir, Memc[helpdir], SZ_FNAME)
+ if (streq (Memc[helpdir], s_helpdir))
+ if (envgets (s_helpdir, Memc[helpdir], SZ_FNAME) <= 0)
+ call syserrs (SYS_ENVNF, s_helpdir)
+
+ call clgstr (s_helpdb, Memc[helpdb], SZ_FNAME)
+ if (streq (Memc[helpdb], s_helpdb))
+ if (envgets (s_helpdb, Memc[helpdb], SZ_FNAME) <= 0)
+ call syserrs (SYS_ENVNF, s_helpdb)
+
+ verbose = clgetb ("verbose")
+ if (verbose) {
+ call printf ("helpdir = %s\n")
+ call pargstr (Memc[helpdir])
+ call printf ("helpdb = %s\n")
+ call pargstr (Memc[helpdb])
+ }
+
+ # The database is compiled into a temporary file to protect the current
+ # database in the event the compile is aborted. When the compile has
+ # successfully completed we will delete the original and replace it
+ # with the new database. This also has the advantage that the switch
+ # takes very little time, making it less likely that anyone will notice
+ # when the database is updated.
+
+ call mktemp ("tmp$hdb", Memc[tempname], SZ_FNAME)
+
+ # Perform the compilation.
+ call hdb_compile (Memc[helpdir], Memc[tempname], verbose)
+
+ # Now attempt to delete the old database and replace it with the new.
+ # By default, the help database flle is maintained in dev$, a directory
+ # with global write permission, so that anyone can delete the file.
+ # If the old file cannot be deleted we delete the new database and
+ # abort.
+
+ if (access (Memc[helpdb],0,0) == YES)
+ iferr (call delete (Memc[helpdb])) {
+ call delete (Memc[tempname])
+ call erract (EA_ERROR)
+ }
+
+ call rename (Memc[tempname], Memc[helpdb])
+ call sfree (sp)
+end
diff --git a/pkg/system/help/tlist.x b/pkg/system/help/tlist.x
new file mode 100644
index 00000000..5bd61ab1
--- /dev/null
+++ b/pkg/system/help/tlist.x
@@ -0,0 +1,406 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include "help.h"
+
+.help tlist
+.nf __________________________________________________________________________
+TLIST -- Routines for processing the template list.
+Functions:
+ tl_open Expand the template list into a list
+ of unambiguous templates.
+ tl_read Fetch next template from the list.
+ tl_close Close the list.
+
+Do not confuse these routines with those used to expand and read from the
+template for a single package. Our main function is to pass through the
+template list, adding package names where they were left out by the user.
+If no package name is given all packages in the database are searched.
+.endhelp ______________________________________________________________________
+
+define SZ_TLSBUF 1024 # local string buffer
+define INC_SZTLSBUF 512 # increment if overflow
+define SZ_CURPACK 31 # allocation for curpack name string
+
+define LEN_TLSTRUCT 7
+define TL_CTRL Memi[$1] # string buffer
+define TL_SBUF Memi[$1+1] # string buffer
+define TL_SZSBUF Memi[$1+2] # size of string buffer
+define TL_NEXTCH Memi[$1+3] # index of next char in sbuf
+define TL_LISTPTR Memi[$1+4] # for fetching list elements
+define TL_CURPACK Memi[$1+5] # offset of name of current package
+define TL_LISTLEN Memi[$1+6] # number of elements in list
+
+
+# TL_OPEN -- Take the template list supplied by the user and produce as
+# output a list wherein each element has an explicit package name. If an
+# element is a module name or a module matching template, it gets replaced
+# by a set of such templates, one for each package in the database.
+# If a package matching template is given, it is expanded into a list of
+# packages.
+
+pointer procedure tl_open (db, hp, tlist, ctrl)
+
+pointer db # database descriptor
+pointer hp # system package directory
+char tlist[ARB] # template list string
+pointer ctrl
+
+int ip, junk
+pointer sp, op, tl, sbuf, template, pakstr, modstr
+int tl_fetchelem(), tl_matchpak(), tl_putstr(), tl_getcurpack()
+errchk tl_getcurpack, tl_ambiguous, tl_matchpak
+define paknotfound_ 91
+
+begin
+ call smark (sp)
+ call salloc (template, SZ_LINE, TY_CHAR)
+ call salloc (pakstr, SZ_FNAME, TY_CHAR)
+ call salloc (modstr, SZ_FNAME, TY_CHAR)
+
+ call calloc (tl, LEN_TLSTRUCT, TY_STRUCT)
+ call malloc (sbuf, SZ_TLSBUF, TY_CHAR)
+
+ TL_CTRL(tl) = ctrl
+ TL_SBUF(tl) = sbuf
+ TL_SZSBUF(tl) = SZ_TLSBUF
+ TL_NEXTCH(tl) = SZ_CURPACK + 2
+ TL_LISTPTR(tl) = SZ_CURPACK + 2
+ TL_LISTLEN(tl) = 0
+
+ # If null template list, set to "curpack.". This will cause the
+ # help for the current package to be printed. Otherwise expand
+ # the template. Template expansion can produce a very big list.
+
+ for (ip=1; IS_WHITE (tlist[ip]); ip=ip+1)
+ ;
+
+ if (tlist[ip] == EOS) {
+ # Put current package name into list.
+ op = template + tl_getcurpack (tl, Memc[template], SZ_LINE)
+ Memc[op] = '.'
+ Memc[op+1] = EOS
+ junk = tl_putstr (tl, Memc[template])
+
+ } else {
+ # Expand nonnull template list. Each time through the loop
+ # processes the next comma delimited template.
+
+ while (tl_fetchelem (tlist,ip,Memc[pakstr],Memc[modstr]) > 0) {
+ if (Memc[pakstr] == EOS) {
+ if (H_OPTION(ctrl) == O_DIR) {
+ # User wants to print a help directory, but left out
+ # the "." in the package name. Assume the package
+ # name is an abbreviation and all all packages which
+ # match to the list.
+
+ if (tl_matchpak (tl, hp, Memc[modstr], "") == 0)
+ goto paknotfound_
+ } else
+ call tl_ambiguous (tl, db, hp, Memc[modstr])
+
+ } else if (tl_matchpak (tl,hp,Memc[pakstr],Memc[modstr]) == 0) {
+ # Explicit package template was given by user, but no
+ # matches were made to packages installed in the system
+ # help directory. Inform user.
+paknotfound_
+ call eprintf ("Cannot find help for package `%s'\n")
+ call pargstr (Memc[pakstr])
+ }
+ }
+ }
+
+ # Return unused space in string buffer. Copy length of list to
+ # the main help structure.
+
+ call realloc (TL_SBUF(tl), TL_NEXTCH(tl), TY_CHAR)
+ TL_SZSBUF(tl) = TL_NEXTCH(tl)
+ H_LENTL(ctrl) = TL_LISTLEN(tl)
+
+ call sfree (sp)
+ return (tl)
+end
+
+
+# TL_CLOSE -- Close a template list opened with TL_OPEN.
+
+procedure tl_close (tl)
+
+pointer tl
+
+begin
+ call mfree (TL_SBUF(tl), TY_CHAR)
+ call mfree (tl, TY_STRUCT)
+end
+
+
+# TL_READ -- Get the next template from the template list.
+# Returns EOF when end of list is reached, else nchars in template.
+
+int procedure tl_read (tl, outstr, maxch)
+
+pointer tl
+char outstr[ARB]
+int maxch
+int offset, nchars
+int gstrcpy()
+
+begin
+ if (TL_LISTPTR(tl) >= TL_NEXTCH(tl))
+ return (EOF)
+
+ offset = TL_LISTPTR(tl)
+ nchars = gstrcpy (Memc[TL_SBUF(tl)+offset], outstr, maxch)
+ TL_LISTPTR(tl) = offset + nchars + 1
+
+ return (nchars)
+end
+
+
+# TL_MATCHPACK -- Match package name against the system package list,
+# add each package matched to the list.
+
+int procedure tl_matchpak (tl, hp, package, module)
+
+pointer tl
+pointer hp
+char package[ARB]
+char module[ARB]
+
+int paklen, junk, ngen, modnum
+pointer sp, template, op, ml
+int tl_putstr(), ml_read()
+pointer ml_open()
+errchk ml_open, ml_read, tl_putstr
+
+begin
+ call smark (sp)
+ call salloc (template, SZ_LINE, TY_CHAR)
+
+ ngen = 0
+ ml = ml_open (hp, package)
+
+ repeat {
+ paklen = ml_read (ml, modnum, Memc[template], SZ_LINE)
+ if (paklen == EOF)
+ break
+ op = template + paklen
+ Memc[op] = '.'
+ call strcpy (module, Memc[op+1], SZ_LINE-paklen-1)
+ junk = tl_putstr (tl, Memc[template])
+ ngen = ngen + 1
+ }
+
+ call ml_close (ml)
+ call sfree (sp)
+ return (ngen)
+end
+
+
+# TL_AMBIGUOUS -- Called to expand an ambiguous template, i.e., one which did
+# not include the "." delimiter to denote the package and module fields.
+# We handle this by generating a series of module matching templates, one for
+# each package in the database, starting with the current package. If the
+# ambiguous pattern contains any pattern matching metacharacters we match only
+# against the modules in the current package. Otherwise (completely ambiguous
+# template) we match against:
+#
+# [1] all modules in the current package
+# [2] all modules in all packages, except the current package
+#
+# For example, "alpha" might be expanded into the list
+# curpack.alpha, pak1.alpha, pak2.alpha, ...
+#
+# The search [2] is a depth-first search of all packages in the root. Since
+# each non-root package is a module of some other package, this search will
+# find all non-root packages as well as modules. For the root packages to be
+# found they must reference themselves as modules, but NOT as subpackages,
+# otherwise recursion will occur.
+
+procedure tl_ambiguous (tl, db, hp, module)
+
+pointer tl # template list descriptor
+pointer db # database descriptor
+pointer hp # package directory
+char module[ARB] # module template
+
+int paklen, junk, ip, pk
+pointer sp, curpack, template, op
+bool streq()
+int tl_putstr(), stridx(), tl_getcurpack(), hd_getname()
+errchk tl_putstr, tl_getcurpack, hd_getname
+
+begin
+ call smark (sp)
+ call salloc (template, SZ_LINE, TY_CHAR)
+ call salloc (curpack, SZ_FNAME, TY_CHAR)
+
+ # Output the template for the current package. Save the name of
+ # the current package for later use.
+
+ op = template + tl_getcurpack (tl, Memc[template], SZ_LINE)
+ call strcpy (Memc[template], Memc[curpack], SZ_FNAME)
+ Memc[op] = '.'
+ call strcpy (module, Memc[op+1], SZ_LINE-(op-template)-1)
+ junk = tl_putstr (tl, Memc[template])
+
+ # Check for pattern matching metacharacters. If present we match
+ # only against the current package, hence we are all done.
+
+ for (ip=1; module[ip] != EOS; ip=ip+1)
+ if (stridx (module[ip], "*?[]") > 0) {
+ call sfree (sp)
+ return
+ }
+
+ # Output a template for each remaining package in the database,
+ # excluding the current package which gets searched first and has
+ # already been put in the list. Template is "pakname.module".
+
+ pk = 1
+ repeat {
+ paklen = hd_getname (hp, pk, TY_MODNAME, Memc[template], SZ_LINE)
+ pk = pk + 1
+ if (paklen <= 0)
+ break
+ if (streq (Memc[template], Memc[curpack]))
+ next
+ op = template + paklen
+ Memc[op] = '.'
+ call strcpy (module, Memc[op+1], SZ_LINE-paklen-1)
+ junk = tl_putstr (tl, Memc[template])
+ }
+
+ call sfree (sp)
+end
+
+
+# TL_FETCHELEM -- Extract next element from template list. An element
+# consists of the package pattern, module pattern, both, or either.
+# Set output strings to the null string if field not present. Return
+# the number of chars in the full element, zero when EOS is reached on
+# the template list.
+
+int procedure tl_fetchelem (tlist, ip, pakstr, modstr)
+
+char tlist[ARB]
+int ip
+char pakstr[SZ_FNAME]
+char modstr[SZ_FNAME]
+
+bool package_seen
+char ch
+int op, ip_save
+
+begin
+ package_seen = false
+ pakstr[1] = EOS
+
+ # Skip whitespace, the comma delimiters between list elements,
+ # and any null list elements (i.e. ",,").
+
+ while (IS_WHITE (tlist[ip]) || tlist[ip] == ',')
+ ip = ip + 1
+ ip_save = ip
+
+ # Extract the first field. If period is seen, this is the package
+ # field, copy it to pakstr. Remainder is the module name.
+ op = 1
+ ch = tlist[ip]
+ while (ch != ',' && ch != '\n' && ch != EOS) {
+ modstr[op] = ch
+ if (ch == '.') {
+ if (package_seen)
+ call error (18, "Too many '.' delims in help template")
+ package_seen = true
+ modstr[op] = EOS
+ call strcpy (modstr, pakstr, SZ_FNAME)
+ op = 1
+ } else
+ op = op + 1
+ ip = ip + 1
+ ch = tlist[ip]
+ }
+ modstr[op] = EOS
+
+ return (ip - ip_save)
+end
+
+
+# TL_GETCURPACK -- Get the name of the current package. The hidden CL command
+# "_curpack" prints the name of the current package.
+
+int procedure tl_getcurpack (tl, pakname, maxch)
+
+pointer tl # template list
+char pakname[maxch] # package name (output)
+int maxch
+
+pointer ctrl
+int nchars, junk
+int gstrcpy(), fscan()
+bool strne()
+errchk clcmd
+
+begin
+ # The current package is read only once for each tlist expansion.
+ # The following uses the CL global parameter "list" to read the
+ # package list. The CL interface is violated by sending an explicit
+ # command to the CL. Poor practice, but the query can be disabled
+ # by setting the help.curpack parameter, if this causes a problem.
+
+ if (TL_CURPACK(tl) == NULL) {
+ # Was the current package set via a help task parameter?
+ ctrl = TL_CTRL(tl)
+ if (H_CURPACK(ctrl) != EOS)
+ if (strne (H_CURPACK(ctrl), "AskCL")) {
+ call strcpy (H_CURPACK(ctrl),
+ Memc[TL_SBUF(tl)+1], SZ_CURPACK)
+ TL_CURPACK(tl) = 1
+ }
+
+ if (TL_CURPACK(tl) == NULL) {
+ # Send "_curpack" command to the CL, read the response (a single
+ # line) from CLIN.
+
+ call clcmd ("_curpack")
+ junk = fscan (CLIN)
+ call gargwrd (Memc[TL_SBUF(tl)+1], SZ_CURPACK)
+ TL_CURPACK(tl) = 1
+ }
+ }
+
+ nchars = gstrcpy (Memc[TL_SBUF(tl) + TL_CURPACK(tl)], pakname, maxch)
+ return (nchars)
+end
+
+
+# TL_PUTSTR -- Put a string (incl EOS) in the string buffer at nextch.
+# If there is not enough space in the buffer, reallocate a larger buffer.
+# Return the index of the string in the string buffer.
+
+int procedure tl_putstr (tl, str)
+
+pointer tl
+char str[ARB]
+int nextch, nchars, strlen()
+errchk realloc
+
+begin
+ # Null strings are not stored and cause a null index to be returned.
+ nchars = strlen (str)
+ if (nchars == 0)
+ return (0)
+
+ nextch = TL_NEXTCH(tl)
+ if (nextch + nchars + 1 > TL_SZSBUF(tl)) {
+ TL_SZSBUF(tl) = TL_SZSBUF(tl) + INC_SZTLSBUF
+ call realloc (TL_SBUF(tl), TL_SZSBUF(tl), TY_CHAR)
+ }
+
+ call strcpy (str, Memc[TL_SBUF(tl) + nextch], ARB)
+ TL_NEXTCH(tl) = nextch + nchars + 1
+ TL_LISTLEN(tl) = TL_LISTLEN(tl) + 1
+
+ return (nextch)
+end
diff --git a/pkg/system/help/xhelp/help.gui b/pkg/system/help/xhelp/help.gui
new file mode 100644
index 00000000..b3f21c07
--- /dev/null
+++ b/pkg/system/help/xhelp/help.gui
@@ -0,0 +1,3027 @@
+# XHELP.GUI -- Graphics user interface for the IRAF help browser.
+
+reset-server
+appInitialize xhelp XHelp {
+
+XHelp*objects:\
+ toplevel Layout helpLayout\
+ helpLayout Group menubarGroup\
+ helpLayout Paned helpPanes\
+ menubarGroup Layout menubarLayout\
+ menubarLayout MenuButton fileButton\
+ menubarLayout MenuButton optionsButton\
+ menubarLayout Command printButton\
+ menubarLayout Command findButton\
+ menubarLayout Command searchButton\
+ menubarLayout MenuButton historyButton\
+ menubarLayout Command helpButton\
+ menubarLayout Command quitButton\
+\
+ helpPanes Group topicGroup\
+ topicGroup Layout topicLayout\
+ topicLayout Label topicLabel\
+ topicLayout Command reloadButton\
+ topicLayout Frame topicFrame\
+ topicFrame AsciiText topicEntry\
+ topicLayout Command topicClear\
+ topicLayout Frame listFrame\
+ listFrame Viewport listView\
+ listView List topicList\
+\
+ helpPanes Group outputGroup\
+ outputGroup Layout outputLayout\
+ outputLayout Command htbButton\
+ outputLayout Command htfButton\
+ outputLayout Command htuButton\
+ outputLayout Command hthButton\
+ outputLayout MenuButton secButton\
+ outputLayout MenuButton parButton\
+ outputLayout TextToggle hlpOpt\
+ outputLayout TextToggle srcOpt\
+ outputLayout TextToggle sysOpt\
+ outputLayout TextToggle filOpt\
+ outputLayout Frame helpFrame\
+ helpFrame HTML helpText\
+\
+\
+ toplevel TopLevelShell printShell\
+ printShell Layout prntLayout\
+ prntLayout Group printGroup\
+ prntLayout Group printCmdGroup\
+\
+ printGroup Layout printLayout\
+ printLayout Label toLabel\
+ printLayout TextToggle toPrinter\
+ printLayout TextToggle toFile\
+ printLayout Label printLabel\
+ printLayout Frame printFrame\
+ printFrame AsciiText printEntry\
+ printLayout Label pageLabel\
+ printLayout TextToggle pageLetter\
+ printLayout TextToggle pageLegal\
+ printLayout TextToggle pageA4\
+ printLayout TextToggle pageB5\
+\
+ printCmdGroup Layout printCmdLayout\
+ printCmdLayout Command printOkay\
+ printCmdLayout Command printDismiss\
+\
+\
+ toplevel TopLevelShell searchShell\
+ searchShell Group searchGroup\
+ searchGroup Layout searchLayout\
+ searchLayout Label resLabel\
+ searchLayout Frame resFrame\
+ resFrame HTML resList\
+ searchLayout Label searchLabel\
+ searchLayout Frame searchFrame\
+ searchFrame AsciiText searchEntry\
+ searchLayout Command searchClear\
+ searchLayout Command searchOkay\
+ searchLayout Label searchStatus\
+ searchLayout TextToggle exactMatch\
+ searchLayout Command searchHelp\
+ searchLayout Command searchDismiss\
+\
+\
+ toplevel TransientShell findShell\
+ findShell Layout fsLayout\
+ fsLayout Group findGroup\
+ fsLayout Group findCmdGroup\
+\
+ findGroup Layout findLayout\
+ findLayout Label findLabel\
+ findLayout Frame findFrame\
+ findFrame AsciiText findEntry\
+ findLayout TextToggle findDir\
+ findLayout TextToggle findCase\
+\
+ findCmdGroup Layout findCmdLayout\
+ findCmdLayout Command findOkay\
+ findCmdLayout Command findClear\
+ findCmdLayout Command findDismiss\
+\
+\
+ toplevel TopLevelShell fileShell\
+ fileShell Layout flist\
+ flist Group flGroup\
+ flGroup Layout flFrame\
+ flFrame Label flistLabel\
+ flFrame Frame flistFrame\
+ flistFrame AsciiText flistText\
+ flFrame Label flpkgLabel\
+ flFrame Label flpkgVal\
+ flFrame Command flDismiss\
+\
+\
+ toplevel TopLevelShell fileBrowser\
+ fileBrowser Layout fbLayout\
+ fbLayout Group fnavGroup\
+ fbLayout Group fbCmdGroup\
+ fbLayout Parameter directory\
+\
+ fnavGroup Layout fnavLayout\
+ fnavLayout Command fnavHome\
+ fnavLayout Command fnavUp\
+ fnavLayout Command fnavRoot\
+ fnavLayout Command fnavRescan\
+ fnavLayout Label filterLabel\
+ fnavLayout Frame filterFrame\
+ filterFrame AsciiText filterEntry\
+ fnavLayout Command filterClear\
+ fnavLayout Group dirGroup\
+ dirGroup Frame dirFrame\
+ dirFrame Viewport dirView\
+ dirView List dirList\
+ fnavLayout Group fileGroup\
+ fileGroup Frame fgFrame\
+ fgFrame Viewport fileView\
+ fileView List fileList\
+ fnavLayout Label curdirLabel\
+ fnavLayout Label curdirVal\
+ fnavLayout Label fnameLabel\
+ fnavLayout Frame fnameFrame\
+ fnameFrame AsciiText fnameEntry\
+ fnavLayout Command fnameClear\
+\
+ fnavLayout Group fmtGroup\
+ fmtGroup Layout fmtLayout\
+ fmtLayout Label fmtLabel\
+ fmtLayout TextToggle fmtSrc\
+ fmtLayout TextToggle fmtText\
+ fmtLayout TextToggle fmtHTML\
+ fmtLayout TextToggle fmtPS\
+ fmtLayout Label owLabel\
+ fmtLayout TextToggle overwrite\
+\
+ fbCmdGroup Layout fbCmdLayout\
+ fbCmdLayout Command fbcOkay\
+ fbCmdLayout Command fbcHelp\
+ fbCmdLayout Command fbcDismiss\
+\
+\
+ toplevel TopLevelShell doc_source\
+ doc_source Layout srcLayout\
+ srcLayout Frame srcMenuFrame\
+ srcMenuFrame Layout srcMenuBar\
+ srcMenuBar Command srcDismiss\
+ srcLayout Frame srcFrame\
+ srcFrame AsciiText srcText\
+\
+\
+ toplevel TopLevelShell hlpShell\
+ hlpShell Layout hlpLayout\
+ hlpLayout Group hlpMenuGroup\
+ hlpMenuGroup Layout hlpMenu\
+ hlpMenu Command hlpBack\
+ hlpMenu Command hlpForward\
+ hlpMenu Command hlpHome\
+ hlpMenu Command hlpTutorial\
+ hlpMenu Command hlpDismiss\
+ hlpLayout Frame hlpTextFrame\
+ hlpTextFrame HTML hlpText\
+ hlpLayout Label hfLabel\
+ hlpLayout Frame hfFrame\
+ hfFrame AsciiText hfEntry\
+ hlpLayout Command hfFind\
+ hlpLayout Command hfClear\
+ hlpLayout TextToggle hfDir\
+ hlpLayout TextToggle hfCase\
+ hlpShell Parameter help\
+\
+\
+ toplevel TransientShell warning\
+ warning Layout warn\
+ warn Frame warnFrame\
+ warnFrame Layout WFlayout\
+ WFlayout Icon warnIcon\
+ WFlayout TextBox warnText\
+ warn Frame warnBtnFrame\
+ warnBtnFrame Command warnDismiss\
+\
+\
+ toplevel TopLevelShell tclShell\
+ tclShell Layout tclLayout\
+ tclLayout Group tclCmdGroup\
+ tclCmdGroup Layout tclCmd\
+ tclCmd Command tclClear\
+ tclCmd Command tclExecute\
+ tclCmd Toggle tclLogging\
+ tclCmd Command tclDismiss\
+ tclLayout Frame tclFrame\
+ tclFrame AsciiText tclEntry\
+\
+\
+ toplevel Parameter xhelp\
+ xhelp Parameter textout\
+ xhelp Parameter alert\
+ xhelp Parameter apropos\
+ xhelp Parameter pkglist\
+ xhelp Parameter helpres\
+ xhelp Parameter helpfiles\
+ xhelp Parameter printer\
+ xhelp Parameter curpack\
+ xhelp Parameter curtask\
+ xhelp Parameter history\
+ xhelp Parameter showtype\
+ xhelp Parameter type
+
+
+
+ !-------------------------------------------------------
+ ! Define some global resources for the main menu panels.
+ !-------------------------------------------------------
+ *shadowWidth: 1
+ *background: gray75
+ *Arrow.width: 16
+ *Arrow.height: 25
+ *Text*height: 21
+ *Command.height: 21
+ *Command.highlightThickness: 1
+ *Command.internalHeight: 4
+ *MenuButton.height: 21
+ *MenuButton.highlightThickness: 1
+ *Label.borderWidth: 0
+ *Label.shadowWidth: 0
+ *TextButton.shadowWidth: 0
+ *TextButton.highlightThickness: 1
+ *TextToggle*borderWidth: 0
+ *TextToggle.highlightThickness: 0
+ *Toggle.highlightThickness: 1
+ *Group.shrinkToFit: True
+
+ *Arrow.foreground: gray72
+ *Arrow.background: gray72
+ *Text*background: gray72
+ *AsciiText*background: gray72
+ *TextBox.background: gray72
+ *MultiList*background: gray72
+ *List*background: gray72
+ *Slider2d*thumbColor: gray75
+
+
+ !-------------------------------------------------------------
+ ! Define resources to take advantage of the 3D scrollbar look.
+ !-------------------------------------------------------------
+ *Scrollbar*background: gray75
+ *Scrollbar*width: 15
+ *Scrollbar*height: 15
+ *Scrollbar*shadowWidth: 1
+ *Scrollbar*cursorName: top_left_arrow
+ *Scrollbar*pushThumb: true
+
+
+ !----------------------------------------
+ ! Menu resources giving a shadow effect.
+ !----------------------------------------
+ *SmeBSB.leftMargin: 10
+ *SmeBSB.rightMargin: 5
+ *SmeBSB.shadowWidth: 2
+ *SmeBSB*background: SteelBlue
+ *SimpleMenu*background: gray77
+ *SimpleMenu.borderWidth: 2
+ *SimpleMenu.borderColor: Black
+ *SimpleMenu.shadowWidth: 2
+ *SimpleMenu.line1.foreground: gray51
+ *SimpleMenu.line2.foreground: gray91
+ *SimpleMenu.line3.foreground: gray51
+ *SimpleMenu.line4.foreground: gray91
+ *SimpleMenu.line5.foreground: gray51
+ *SimpleMenu.line6.foreground: gray91
+ *SimpleMenu.line7.foreground: gray51
+ *SimpleMenu.line8.foreground: gray91
+ *SimpleMenu.line9.foreground: gray51
+ *SimpleMenu.line10.foreground: gray91
+ *SimpleMenu.line11.foreground: gray51
+ *SimpleMenu.line12.foreground: gray91
+ *SimpleMenu.line13.foreground: gray51
+ *SimpleMenu.line14.foreground: gray91
+ *SimpleMenu.line15.foreground: gray51
+ *SimpleMenu.line16.foreground: gray91
+ *SimpleMenu.line17.foreground: gray51
+ *SimpleMenu.line18.foreground: gray91
+ *SimpleMenu.line19.foreground: gray51
+ *SimpleMenu.line20.foreground: gray91
+ *SimpleMenu.line21.foreground: gray51
+ *SimpleMenu.line22.foreground: gray91
+ *SimpleMenu.line23.foreground: gray51
+ *SimpleMenu.line24.foreground: gray91
+ *SimpleMenu.line25.foreground: gray51
+ *SimpleMenu.line26.foreground: gray91
+ *SimpleMenu.line27.foreground: gray51
+ *SimpleMenu.line28.foreground: gray91
+ *SimpleMenu.line29.foreground: gray51
+ *SimpleMenu.line30.foreground: gray91
+
+
+ !----------------------------------------
+ ! Define the default fonts to be used.
+ !----------------------------------------
+ *font: -adobe-times-medium-r-normal-*-14-*-*-*
+ *Command.font: -adobe-times-bold-i-normal-*-12-*-*-*
+ *MenuButton.font: -adobe-times-bold-i-normal-*-12-*-*-*
+ *Toggle.font: -adobe-times-bold-i-normal-*-12-*-*-*
+ *Label.font: -adobe-times-bold-i-normal-*-12-*-*-*
+ *TextToggle.font: -adobe-times-bold-i-normal-*-12-*-*-*
+ *Group*SimpleMenu*font: 7x13
+ *HTML*SimpleMenu*font: 7x13
+
+ *HTML.plainFont: -*-fixed-medium-r-*-*-13-*-*-*
+ *HTML.listingFont: -*-fixed-medium-r-*-*-13-*-*-*
+ *HTML.font: -adobe-times-medium-r-normal-*-14-*-*-*
+ *HTML.boldFont: -adobe-times-bold-r-normal-*-14-*-*-*
+ *HTML.plainboldFont: -adobe-times-bold-r-normal-*-14-*-*-*
+ *HTML.fixedboldFont: -adobe-times-bold-r-normal-*-14-*-*-*
+ *HTML.header1Font: -adobe-times-bold-r-normal-*-18-*-*-*
+ *HTML.header2Font: -adobe-times-bold-r-normal-*-14-*-*-*
+ *HTML.header3Font: -adobe-times-bold-r-normal-*-14-*-*-*
+ *HTML.header4Font: -adobe-times-bold-r-normal-*-14-*-*-*
+ *HTML.header5Font: -adobe-times-medium-i-normal-*-12-*-*-*
+ *HTML.header6Font: -adobe-times-bold-r-normal-*-10-*-*-*
+ *HTML.anchorUnderlines: 0
+ *HTML.visitedAnchorUnderlines: 0
+ *HTML.anchorColor: blue
+ *HTML.visitedAnchorColor: red3
+ *HTML*background: gray72
+ *HTML*Scrollbar.background: gray75
+ *HTML*Scrollbar*width: 15
+ *HTML*Scrollbar*height: 15
+
+
+ !---------------------------
+ ! Set the default resources.
+ !---------------------------
+ *xhelp.title: IRAF Help Browser V1.0 - DEV
+ *xhelp.geometry: +0+0
+ *xhelp.width: 625
+ *xhelp.minWidth: 580
+ *xhelp.minheight: 450
+ *xhelp.height: 850
+
+ *helpLayout.geometry: 600x700+0+0
+ *helpLayout*borderWidth: 0
+ *helpLayout*Group.shrinkToFit: True
+ *helpLayout*Frame.frameType: sunken
+ *helpLayout*Frame.frameWidth: 1
+ *helpLayout*Command.internalHeight: 2
+ *helpLayout*MenuButton.internalHeight: 2
+ *helpLayout*Label*highlightThickness: 0
+ *helpLayout*List*shadeSurplus: False
+ *helpLayout*List.internalWidth: 10
+ *helpLayout*Viewport.allowVert: True
+ *helpLayout*Viewport.forceBars: True
+ *helpLayout.width: 600
+ *helpLayout.layout: vertical { \
+ menubarGroup < +inf -inf * > \
+ -1 \
+ horizontal { \
+ -1 \
+ helpPanes < +inf -inf * +inf -inf > \
+ -1 \
+ } \
+ -1 \
+ }
+ *helpLayout*SimpleMenu.shadowWidth: 2
+ *helpLayout*SimpleMenu.borderColor: Black
+ *helpLayout*SimpleMenu.borderWidth: 2
+
+ *menubarGroup.label:
+ *menubarGroup.outerOffset: 0
+ *menubarGroup.innerOffset: 5
+ *menubarGroup.frameType: raised
+ *menubarGroup.frameWidth: 2
+ *menubarGroup*Command.shadowWidth: 0
+ *menubarGroup*MenuButton.shadowWidth: 0
+ *menubarLayout.layout: horizontal { \
+ fileButton 5 \
+ optionsButton 5 \
+ printButton 5 \
+ findButton 5 \
+ searchButton 5 \
+ historyButton 5 \
+ 10 < +inf -inf > \
+ helpButton 5 \
+ quitButton \
+ }
+ *fileButton.label: File
+ *fileButton.menuName: fileMenu
+ *optionsButton.label: Options
+ *optionsButton.menuName: optsMenu
+ *printButton.label: Print
+ *findButton.label: Find
+ *searchButton.label: Search
+ *historyButton.label: History
+ *historyButton.menuName: historyMenu
+ *helpButton.label: Help
+ *quitButton.label: Quit
+
+ *topicGroup.label:
+ *topicGroup.outerOffset: 2
+ *topicGroup.innerOffset: 2
+ *topicGroup*frameType: chiseled
+ *topicGroup.frameWidth: 2
+ *topicGroup*Label.shadowWidth: 0
+ *topicGroup*Label.borderWidth: 1
+ *topicGroup*Label.highlightThickness: 1
+ *topicGroup*Viewport.useRight: True
+ *topicGroup*Viewport.useBottom: True
+ *topicLayout.layout: vertical { \
+ 2 < +2 -2 > \
+ horizontal { \
+ 3 < +3 -3 > \
+ topicLabel 2 topicFrame < +inf * > \
+ 2 \
+ topicClear 5 reloadButton \
+ 1 \
+ } \
+ 4 \
+ horizontal { \
+ vertical { \
+ -1 \
+ listFrame < +inf -inf * +inf -inf > \
+ -1 \
+ } \
+ } \
+ 2 < +2 -2 > \
+ }
+ *reloadButton.label: Reload
+ *topicLabel.label: Topic:
+ *topicLabel.justify: right
+ *topicEntry*width: 100
+ *topicEntry*editType: edit
+ *topicEntry*font: 7x13
+ *topicEntry*displayCaret: True
+ *topicClear.label: Clear
+
+ *topicList.font: 7x13
+ *topicList.width: 500
+ *topicList.height: 100
+ *topicList.columnSpacing: 20
+ *topicList.verticalList: True
+ !*topicList.defaultColumns: 6
+ !*topicList.forceColumns: True
+
+ *outputGroup.label:
+ *outputGroup.outerOffset: 2
+ *outputGroup.innerOffset: 2
+ *outputGroup*frameType: chiseled
+ *outputGroup.frameWidth: 2
+ *outputGrout*TextToggle*on: 0
+ *outputGroup*TextToggle.frameWidth: 2
+ *outputGroup*TextToggle.frameType: chiseled
+ *outputGroup*TextToggle.location: 0 0 65 25
+ *outputGroup*TextToggle.leftMargin: 4
+ *outputLayout.layout: vertical { \
+ 2 \
+ horizontal { \
+ 5 \
+ htbButton 2 htfButton 2 htuButton 2 hthButton 2 \
+ 10 < +inf -10 > \
+ secButton 2 parButton \
+ 10 < +inf -10 > \
+ hlpOpt -2 srcOpt -2 sysOpt 4 filOpt \
+ 5 \
+ } \
+ 2 \
+ horizontal { \
+ 2 \
+ helpFrame < +inf -inf * +inf -inf > \
+ 2 \
+ } \
+ }
+ *htbButton.label: Back
+ *htbButton.sensitive: False
+ *htfButton.label: Forward
+ *htfButton.sensitive: False
+ *htuButton.label: Up
+ *htuButton.sensitive: False
+ *hthButton.label: Home
+ *printButton.label: Print
+ *secButton.label: Sections
+ *secButton.menuName: secMenu
+ *parButton.label: Parameters
+ *parButton.menuName: parMenu
+ *hlpOpt*label: Help
+ *hlpOpt*on: 1
+ *hlpOpt*onIcon: diamond1s
+ *hlpOpt*offIcon: diamond0s
+ *hlpOpt*highlightColor: green
+ *srcOpt*label: Source
+ *srcOpt*on: 0
+ *srcOpt*onIcon: diamond1s
+ *srcOpt*offIcon: diamond0s
+ *srcOpt*highlightColor: green
+ *sysOpt*label: Sysdoc
+ *sysOpt*on: 0
+ *sysOpt*onIcon: diamond1s
+ *sysOpt*offIcon: diamond0s
+ *sysOpt*highlightColor: green
+ *filOpt*label: Files
+ *filOpt*on: 0
+ *filOpt*onIcon: square1s
+ *filOpt*offIcon: square0s
+ *filOpt*highlightColor: yellow
+
+ *helpText.width: 650
+ *helpText.height: 620
+ *helpText.anchorUnderlines: 1
+ *helpText.visitedAnchorUnderlines: 1
+ *helpText.verticalScrollOnRight: true
+ *helpText.translations: \
+ <Btn2Down>: popup(secMenu) \n\
+ <Btn2Up>: popdown(secMenu) \n\
+ <Btn3Down>: popup(navMenu) \n\
+ <Btn3Up>: popdown(navMenu) \n
+
+ *helpText*navMenu.foreground: Black
+ *helpText*navMenu.background: gray75
+ *helpText*secMenu.foreground: Black
+ *helpText*secMenu.background: gray75
+
+
+ !--------------------------+
+ ! Printer Shell resources. |
+ !--------------------------+
+ *printShell.title: Printer Selection
+ *printShell.width: 300
+ *printShell.height: 177
+ *printShell.minHeight: 177
+ *printShell.maxHeight: 177
+ *printShell*borderWidth: 0
+ *printShell*Group.frameType: chiseled
+ *printShell*Group.frameWidth: 2
+ *printShell*Group.innerOffset: 5
+ *printShell*Group.outerOffset: 2
+ *printShell*Command.internalheight: 4
+ *printShell*Text*editType: edit
+ *printShell*Text*height: 25
+ *printShell*TextToggle.frameWidth: 0
+ *printShell*Group.label:
+ *prntLayout.layout: vertical { \
+ printGroup < +inf -inf * > \
+ printCmdGroup < +inf -inf * > \
+ }
+
+ *printLayout*location: 0 0 70 25
+ *printLayout*offIcon: diamond0s
+ *printLayout*onIcon: diamond1s
+ *printLayout*highlightColor: yellow
+ *printLayout*Label.height: 35
+ *printLayout*Label.justify: right
+ *printLayout*TextToggle.frameWidth: 0
+ *printLayout*TextToggle.leftMargin: 8
+ *printLayout*TextToggle*highlightColor: yellow
+ *printLayout*TextToggle*onIcon: square1s
+ *printLayout*TextToggle*offIcon: square0s
+ *printLayout*TextToggle*alignment: left
+ *printLayout.layout: vertical { \
+ 0 < +0 >\
+ horizontal { toLabel 10 toPrinter 10 toFile 10 } \
+ 5 < +inf -5 > \
+ horizontal { \
+ printLabel 5 printFrame < +inf -inf * > -1 \
+ } \
+ 5 < +inf -5 > \
+ horizontal { \
+ vertical { pageLabel 10 } \
+ 12 \
+ horizontal { \
+ vertical { pageLetter -3 pageLegal } \
+ 10 \
+ vertical { pageA4 -3 pageB5 } \
+ } \
+ } \
+ 0 < +0 >\
+ }
+ *toLabel.label: Print to:
+ *toPrinter.label: Printer
+ *toPrinter.on: True
+ *toFile.label: File
+ *printLabel.label: Printer:
+ *printFrame.frameType: sunken
+ *printFrame.frameWidth: 1
+ *printEntry*string: printer
+ *pageLabel.label: Page Size:
+ *pageLetter.label: Letter
+ *pageLetter.on: 1
+ *pageLegal.label: Legal
+ *pageA4.label: A4
+ *pageB5.label: B5
+
+ *printCmdLayout.layout: horizontal { \
+ 3 \
+ printOkay 20 < +inf -20 > printDismiss \
+ 3 \
+ }
+ *printOkay.label: Print
+ *printDismiss.label: Dismiss
+
+
+ !-------------------------+
+ ! File Browser resources. |
+ !-------------------------+
+ *fileBrowser.width: 450
+ *fileBrowser.height: 375
+ *fileBrowser.title: Open a New File...
+ *fileBrowser*borderWidth: 0
+ *fileBrowser*Group.frameType: chiseled
+ *fileBrowser*Group.frameWidth: 2
+ *fileBrowser*Group.innerOffset: 3
+ *fileBrowser*Group.outerOffset: 3
+ *fileBrowser*Group.label:
+
+ *fbLayout.layout: vertical { \
+ 2 \
+ fnavGroup < +inf -inf * +inf -inf > \
+ -2 \
+ horizontal { \
+ -5 \
+ fbCmdGroup < +inf -inf * > \
+ -5 } \
+ -3 \
+ }
+
+ *fnavGroup*Frame.frameType: sunken
+ *fnavGroup*Frame.frameWidth: 1
+ *fnavGroup*Text*editType: edit
+ *fnavGroup*Text*height: 25
+ *fnavGroup*Text*font: 7x13
+ *fnavGroup*List.verticalList: True
+ *fnavGroup*List.defaultColumns: 1
+ *fnavGroup*List.forceColumns: True
+ *fnavGroup*List.font: 7x13
+ *fnavGroup*Label.justify: left
+ *fnavGroup*Viewport.allowVert: True
+ *fnavGroup*Viewport.allowHoriz: False
+ *fnavGroup*Viewport.forceBars: True
+ *fnavGroup*Viewport.useRight: True
+ *fnavGroup*Group.outerOffset: 7
+ *fnavGroup*Group.innerOffset: 3
+ *fnavLayout.layout: vertical { \
+ 5 \
+ vertical { \
+ -1 \
+ horizontal { \
+ 5 \
+ fnavHome < +inf -inf * > 2 \
+ fnavUp < +inf -inf * > 2 \
+ fnavRoot < +inf -inf * > 2 \
+ fnavRescan < +inf -inf * > \
+ 10 \
+ filterLabel 2 filterFrame < +inf -inf * > \
+ 2 \
+ filterClear \
+ 5 \
+ } \
+ 3 \
+ } \
+ 5 \
+ horizontal { \
+ -5 \
+ dirGroup < +inf -inf * +inf - inf > \
+ -8 \
+ fileGroup < +inf -inf * +inf - inf > \
+ -5 \
+ } \
+ -3 \
+ horizontal { \
+ curdirLabel 5 curdirVal < +inf -inf * > 5 } \
+ 5 \
+ horizontal { \
+ fnameLabel 2 fnameFrame < +inf -inf * > 2 fnameClear 5\
+ } \
+ 7 \
+ fmtGroup < +inf -inf * > \
+ -3 \
+ }
+ *fileBrowser*fnavGroup*dirGroup.label: Directories
+ *fileBrowser*fnavGroup*fileGroup.label: Files
+ *fileBrowser*fnavGroup*dirGroup.innerOffset: 3
+ *fileBrowser*fnavGroup*fileGroup.innerOffset: 3
+ *fileBrowser*fnavGroup*dirGroup.outerOffset: 7
+ *fileBrowser*fnavGroup*fileGroup.outerOffset: 7
+ *fileBrowser*fnavGroup*dirGroup.font: 7x13bold
+ *fileBrowser*fnavGroup*fileGroup.font: 7x13bold
+
+ *filterLabel.label: Filter
+ *filterClear.label: Clear
+ *curdirLabel.label: Directory:
+ *curdirVal.label:
+ *curdirVal.font: 7x13
+ *fnameLabel.label: Selection\ \
+ *fnameClear.label: Clear
+ *fnavHome.label: Home
+ *fnavUp.label: Up
+ *fnavRoot.label: Root
+ *fnavRescan.label: Rescan
+
+ *fmtGroup*Group.outerOffset: 3
+ *fmtGroup*Group.innerOffset: 3
+ *fmtLayout*TextToggle.frameWidth: 0
+ *fmtLayout*TextToggle.leftMargin: 4
+ *fmtLayout*TextToggle.alignment: left
+ *fmtLayout*TextToggle*highlightColor: yellow
+ *fmtLayout*TextToggle*onIcon: square1s
+ *fmtLayout*TextToggle*offIcon: square0s
+ *fmtLayout.layout: vertical { \
+ horizontal { 5 fmtLabel 10 fmtSrc 3 fmtText 3 fmtHTML 3 fmtPS 5 } \
+ horizontal { 50 owLabel 10 overwrite 5 < +inf > } \
+ }
+ *fmtLabel.label: Save As Format:
+ *fmtSrc.label: Source
+ *fmtSrc.on: 1
+ *fmtSrc.location: 0 0 65 22
+ *fmtText.label: Text
+ *fmtText.location: 0 0 65 22
+ *fmtHTML.label: HTML
+ *fmtHTML.location: 0 0 65 22
+ *fmtPS.label: PostScript
+ *fmtPS.location: 0 0 100 22
+ *owLabel.label: Options:
+ *overwrite.label: Allow overwrite of existing files?
+ *overwrite.location: 0 0 200 22
+
+ *fbCmdLayout.outerOffset: 0
+ *fbCmdLayout.layout: horizontal { \
+ 5 \
+ vertical { 2 fbcOkay 2 } \
+ 20 < +inf -20 > \
+ vertical { 2 fbcHelp 2 } \
+ 2 \
+ vertical { 2 fbcDismiss 2 } \
+ 5 \
+ }
+ *fbcOkay.label: Okay
+ *fbcHelp.label: Help
+ *fbcDismiss.label: Dismiss
+
+
+ !-----------------------+
+ ! Find Shell resources. |
+ !-----------------------+
+ *findShell.title: Find within a document...
+ *findShell.width: 365
+ *findShell.height: 130
+ *findShell*borderWidth: 0
+ *findShell*Group.frameType: chiseled
+ *findShell*Group.frameWidth: 2
+ *findShell*Group.innerOffset: 5
+ *findShell*Group.outerOffset: 2
+ *findShell*Command.internalheight: 4
+ *findShell*Text*editType: edit
+ *findShell*Text*height: 25
+ *findShell*TextToggle.frameWidth: 0
+ *findShell*Group.label:
+ *fsLayout.layout: vertical { \
+ findGroup < +inf -inf * > \
+ findCmdGroup < +inf -inf * > \
+ }
+
+ *findLayout*location: 0 0 120 25
+ *findLayout*offIcon: diamond0s
+ *findLayout*onIcon: diamond1s
+ *findLayout*highlightColor: yellow
+ *findLayout*Label.height: 35
+ *findLayout*Label.justify: right
+ *findLayout*TextToggle.frameWidth: 0
+ *findLayout*TextToggle.leftMargin: 4
+ *findLayout*TextToggle*highlightColor: yellow
+ *findLayout*TextToggle*onIcon: square1s
+ *findLayout*TextToggle*offIcon: square0s
+ *findLayout.layout: vertical { \
+ 5 \
+ horizontal { \
+ findLabel 7 findFrame < +inf -inf * > -1 \
+ } \
+ 5 \
+ horizontal { \
+ 20 < +inf -20 > \
+ findDir 10 findCase \
+ 20 < +inf -20 > \
+ } \
+ }
+ *findLabel.label: Find:
+ *findFrame.frameType: sunken
+ *findFrame.frameWidth: 1
+ *findEntry*string:
+ *findDir.label: Find Backwards
+ *findCase.label: Case Sensitive
+
+ *findCmdLayout.layout: horizontal { \
+ 3 \
+ findOkay \
+ 20 < +inf -20 > \
+ findClear \
+ 20 < +inf -20 > \
+ findDismiss \
+ 3 \
+ }
+ *findOkay.label: Find
+ *findClear.label: Clear
+ *findDismiss.label: Dismiss
+
+
+ !-------------------------------------------+
+ ! Set the document source viewer resources. |
+ !-------------------------------------------+
+ *doc_source.title: Page source
+ *doc_source.width: 575
+ *doc_source.height: 450
+ *srcLayout*borderWidth: 0
+ *srcLayout.layout: vertical { \
+ srcMenuFrame < +inf -inf * > \
+ -2 \
+ srcFrame < +inf -inf * +inf -inf > \
+ -2 \
+ }
+
+ *srcMenuBar.layout: horizontal { 50 < +inf -inf > srcDismiss 5 }
+ *srcMenuFrame.height: 40
+ *srcMenuFrame.outerOffset: 0
+ *srcMenuFrame.innerOffset: 5
+ *srcMenuFrame.frameType: chiseled
+ *srcMenuFrame.frameWidth: 2
+ *srcFrame.frameType: sunken
+ *srcFrame.frameWidth: 1
+ *srcFrame.outerOffset: 5
+ *srcText*scrollVertical: always
+ *srcText*scrollHorizontal: always
+ *srcText*Scrollbar.width: 15
+ *srcText*Scrollbar.height: 15
+ *srcText*background: gray75
+ *srcText*font: 7x13
+ *srcText*editType: read
+ *srcText*displayCaret: False
+ *srcDismiss.label: Dismiss
+ *srcDismiss.width: 150
+
+
+ !-------------------------+
+ ! Search Shell resources. |
+ !-------------------------+
+ *searchShell.title: Search for a topic...
+ *searchShell.width: 600
+ *searchShell.height: 250
+ *searchShell*borderWidth: 0
+ *searchShell*Viewport.allowVert: True
+ *searchShell*Viewport.allowHoriz: True
+ *searchShell*Viewport.useBottom: True
+ *searchShell*Viewport.useRight: False
+ *searchShell*Viewport.forceBars: True
+ *searchGroup.frameType: chiseled
+ *searchGroup.frameWidth: 2
+ *searchGroup.innerOffset: 7
+ *searchGroup.outerOffset: 7
+ *searchGroup.highlightThickness: 0
+ *searchGroup.label:
+ *searchLayout.layout: vertical { \
+ horizontal { \
+ 45 < +45 -45 > \
+ resLabel < +inf -inf * > \
+ 5 < +inf -inf > \
+ exactMatch \
+ } \
+ 2 < +2 - 2 > \
+ resFrame < +inf -inf * +inf -inf > \
+ 5 < +5 - 5 > \
+ horizontal { \
+ searchLabel 5 searchFrame \
+ 5 \
+ searchClear 2 searchOkay \
+ 5 < +inf -inf > \
+ searchStatus \
+ 5 < +inf -inf > \
+ searchHelp 2 searchDismiss \
+ } \
+ }
+ *resLabel.label: Task Package Description
+ *resLabel.justify: left
+ *resFrame.frameType: sunken
+ *resFrame.frameWidth: 1
+ *resList.font: 7x13
+ *resList.width: 100
+ *resList.height: 100
+ *resList.marginWidth: 5
+ *resList.marginHeight: 5
+
+ *searchLabel.label: Topic:
+ *searchFrame.frameType: sunken
+ *searchFrame.frameWidth: 1
+ *searchEntry*font: 7x13
+ *searchEntry*displayCaret: True
+ *searchEntry*editType: edit
+ *searchEntry*height: 25
+ *searchEntry*width: 150
+ *searchClear.label: Clear
+ *searchOkay.label: Search
+ *searchStatus.label:
+ *exactMatch.label: Require Exact Match
+ *exactMatch*on: 1
+ *exactMatch*onIcon: diamond1s
+ *exactMatch*offIcon: diamond0s
+ *exactMatch*highlightColor: green
+ *exactMatch.frameWidth: 2
+ *exactMatch.frameType: chiseled
+ *exactMatch.location: 0 0 150 25
+ *exactMatch.leftMargin: 4
+ *searchHelp.label: Help
+ *searchDismiss.label: Dismiss
+
+
+ !----------------
+ ! Help Window.
+ !----------------
+ *hlpShell.title: Help
+ *hlpShell.width: 500
+ *hlpShell.height: 620
+ *hlpLayout*borderWidth: 0
+ *hlpLayout*Frame*frameType: sunken
+ *hlpLayout*Frame*frameWidth: 1
+
+ *hlpMenuGroup.label:
+ *hlpMenuGroup.outerOffset: 0
+ *hlpMenuGroup.innerOffset: 0
+ *hlpLayout.layout: vertical { \
+ hlpMenuGroup < +inf -inf * > \
+ -3 \
+ hlpTextFrame < +inf -inf * +inf -inf > \
+ horizontal { \
+ 5 \
+ hfLabel 5 hfFrame < +inf -inf *> \
+ 2 \
+ hfFind 2 hfClear 5 hfDir 5 hfCase \
+ 5 \
+ } \
+ 2 \
+ }
+ *hlpLayout*TextToggle*location: 0 0 90 25
+ *hlpLayout*TextToggle*offIcon: diamond0s
+ *hlpLayout*TextToggle*onIcon: diamond1s
+ *hlpLayout*TextToggle*highlightColor: yellow
+ *hlpLayout*TextToggle*frameType: chiseled
+ *hlpLayout*TextToggle*frameWidth: 2
+ *hfEntry*editType: edit
+ *hfEntry*font: 7x13
+ *hfEntry*displayCaret: True
+ *hfLabel.label: Find:
+ *hfFind.label: Find
+ *hfClear.label: Clear
+ *hfDir.label: Backwards
+ *hfCase.label: Caseless
+ *hfCase.on: true
+
+ *hlpMenu*Command.internalHeight: 4
+ *hlpMenu*Command.highlightThickness: 1
+ *hlpMenu*Command.height: 20
+ *hlpMenu.layout: vertical { \
+ 5 \
+ horizontal { \
+ 5 \
+ hlpBack 2 hlpForward 2 hlpHome 2 hlpTutorial \
+ 20 < +inf -20 > \
+ hlpDismiss \
+ 5 \
+ } \
+ 5 \
+ }
+ *hlpBack.label: Back
+ *hlpBack.sensitive: False
+ *hlpForward.label: Forward
+ *hlpHome.label: Home
+ *hlpTutorial.label: Tutorial
+ *hlpTutorial.sensitive: false
+ *hlpDismiss.label: Dismiss
+
+ *hlpTextFrame.outerOffset: 2
+ *hlpText.width: 500
+ *hlpText.height: 500
+ *hlpText.anchorUnderlines: 1
+ *hlpText.visitedAnchorUnderlines: 1
+ *hlpText.verticalScrollOnRight: true
+
+
+ !------------------+
+ ! File List dialog.
+ !------------------+
+ *fileShell.title: Help Files
+ *fileShell.geometry: 500x165
+ *fileShell*borderWidth: 0
+ *fileShell*Command.width: 90
+ *fileShell*Command.height: 30
+ *fileShell*Frame.frameType: sunken
+ *fileShell*Frame.frameWidth: 1
+ *fileShell*Frame.innerOffset: 1
+ *fileShell*Text*font: 7x13
+ *flist.layout: vertical { \
+ 1 \
+ horizontal { 1 flGroup < +inf -inf * +inf -inf> 1 } \
+ 1 \
+ }
+
+ *flGroup.frameType: chiseled
+ *flGroup.frameWidth: 2
+ *flGroup.innerOffset: 5
+ *flGroup.outerOffset: 5
+ *flGroup.label:
+ *flFrame.layout: vertical { \
+ 5 \
+ horizontal { \
+ 13 \
+ flistLabel < +inf -inf * > \
+ 5 < +inf -5 > \
+ } \
+ 2 \
+ horizontal { 1 flistFrame < +inf -inf * +inf -inf > 1 } \
+ 7 \
+ horizontal { \
+ 5 \
+ flpkgLabel 2 flpkgVal < +inf -inf * > \
+ 5 < +inf -5 > \
+ flDismiss \
+ 5 \
+ } \
+ }
+ *flDismiss.label: Dismiss
+ *flistLabel.label: Option Status Filename
+ *flistLabel.justify: left
+ *flpkgLabel.label: Task:
+ *flpkgLabel.justify: left
+ *flpkgVal.label: (Undefined)
+ *flpkgVal.justify: left
+ *flpkgVal*font: 7x13
+ *flistText.label:
+ *flistText.scrollVertical: Never
+ *flistText.scrollHorizontal: whenNeeded
+ *flistText*displayCaret: False
+ *flistText*editType: edit
+
+
+ !----------------+
+ ! WARNING dialog.
+ !----------------+
+ *warning.geometry: +400+300
+ *warning*borderWidth: 0
+ *warning*TextBox.frameWidth: 0
+ *warning*Command.width: 90
+ *warning*Command.height: 30
+ *warning*Frame.frameType: sunken
+ *warning*Frame.frameWidth: 1
+ *warning*Frame.innerOffset: 3
+ *warn.layout: vertical { \
+ 5 \
+ horizontal { \
+ 5 \
+ warnFrame < +inf * +inf > \
+ 5 \
+ } \
+ 5 \
+ horizontal { \
+ 5 < +inf -5 > \
+ warnBtnFrame \
+ 5 < +inf -5 > \
+ } \
+ 5 \
+ }
+
+ *WFlayout.layout: horizontal { \
+ 5 \
+ vertical { \
+ 5 < +inf -5 > \
+ warnIcon \
+ 5 < +inf -5 > \
+ } \
+ 5 \
+ warnText < +inf -inf * +inf -inf > \
+ 5 \
+ }
+ *warnIcon.location: 0 0 40 40
+ *warnIcon.image: WARNING
+ *warnText.label: generic warning text
+ *warnText.width: 270
+ *warnText.height: 60
+ *warnText*background: gray75
+ *warnDismiss.label: Dismiss
+
+ !--------------------------
+ ! Define a Debug Tcl shell.
+ !--------------------------
+ *tclShell.width: 550
+ *tclShell.height: 180
+ *tclShell.title: TCL Command Entry Shell
+ *tclLayout*borderWidth: 0
+ *tclLayout*Frame.frameType: sunken
+ *tclLayout*Frame.frameWidth: 1
+ *tclLayout.layout: vertical { \
+ tclCmdGroup < +inf -inf * > \
+ tclFrame < +inf -inf * +inf -inf> \
+ }
+ *tclEntry*editType: edit
+ *tclEntry*type: string
+ *tclEntry*scrollVertical: Always
+ *tclEntry*scrollHorizontal: whenNeeded
+
+ *tclCmdGroup.label:
+ *tclCmdGroup.outerOffset: 0
+ *tclCmdGroup.innerOffset: 0
+ *tclCmd.layout: vertical { \
+ 5 \
+ horizontal { \
+ 5 \
+ tclClear 3 tclExecute \
+ 10 < +inf -10> \
+ tclLogging 3 tclDismiss \
+ 5 \
+ } \
+ 5 \
+ }
+ *tclClear.label: Clear
+ *tclExecute.label: Execute
+ *tclLogging.label: Enable Logging
+ *tclDismiss.label: Dismiss
+}
+
+
+
+################################################################################
+
+createObjects
+
+# Define Bitmaps and Pixmaps to be used.
+createBitmap null 16 16 {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+
+createBitmap check 16 16 {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x60,
+ 0x00, 0x30, 0x00, 0x18, 0x00, 0x0c, 0x08, 0x06, 0x18, 0x03, 0xb0, 0x01,
+ 0xe0, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}
+
+createBitmap arrow 16 16 {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x14, 0xf8, 0x27,
+ 0x08, 0x40, 0xf8, 0x27, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+
+activate
+
+################################################################################
+
+
+################################################################################
+# Global variables. |
+################################################################################
+set version "IRAF Help GUI V1.0" ;# version string
+set curpack "" ;# current values
+set curtask ""
+set helpType "package" ;# type of help to get
+set helpOption "help" ;# help option param
+set fileManaged 0 ;# is fileShell mapped?
+set pkgList { }
+set visited(0) empty
+
+set listOrient 1 ;# options
+set showType 0
+set showFiles 1
+set exactMatch 1
+
+set MAX_MENU_SIZE 40 ;# what it says it is
+
+# History array initialization.
+set HPkg(0) {Home} ;# package
+set HOpt(0) {help} ;# option
+set HTask(0) {Home} ;# task
+set HUrl(0) {} ;# url
+set HType(0) {task} ;# type (task|package|file)
+set HFile(0) {} ;# filename
+set htop 0 ;# top of array
+set hcurrent 0 ;# current page
+
+# Panel mapping flags.
+set search_mapped 0 ;# searchShell mapped?
+
+
+################################################################################
+# Utility Callbacks
+################################################################################
+
+# Procedures for sending client cursor commands.
+proc GKey { key args } { send client gkey $key }
+proc GCmd { args } { send client gcmd $args }
+
+# Procedures to test True/False strings in resources.
+proc true { v } \
+ { expr { $v=="true" || $v=="True" || $v=="TRUE" || $v==1 || $v=="yes" } }
+proc false { v } \
+ { expr { $v=="false" || $v=="False" || $v=="FALSE" || $v==0 || $v=="no" } }
+
+# No-op procedure for text widgets with no callbacks to swallow newline.
+proc noop { args } { }
+
+# Common functions.
+proc min { a b } { expr {($a < $b) ? $a : $b} }
+proc max { a b } { expr {($a > $b) ? $a : $b} }
+
+
+#--------------------+
+# Debugging options. |
+#--------------------+
+set debug 0 ;# debug flag
+send tclLogging set state [min 1 $debug]
+
+
+################################################################################
+# Initialize. |
+################################################################################
+proc Init args {
+ global history curpack curtask debug
+ global secMenuDescription parMenuDescription
+ global HPkg HTask HUrl HOpt HFile HType
+
+ if {$debug == 1} { send tclShell map }
+
+ # Reinitialize global vars in case of a restart.
+ set curpack ""
+ set curtask ""
+ set helpType "package"
+ set helpOption "help"
+
+ # Initialize the entry strings.
+ send printEntry set string ""
+ send topicEntry set string ""
+
+ # Initialize the various lists.
+ send topicList setList "{ }" resize
+
+ send secButton set sensitive False
+ send parButton set sensitive False
+ editMenu secMenu secButton $secMenuDescription
+ editMenu parMenu parButton $parMenuDescription
+
+} ; #send server postActivateCallback Init
+
+
+
+# Create the Navigation Menu.
+set navMenuDescription {
+ { "Back " f.exec { Back }
+ sensitive {([send htbButton isSensitive]==1) ? "true" : "false" }
+ }
+ { "Forward " f.exec { Forward }
+ sensitive {([send htfButton isSensitive]==1) ? "true" : "false" }
+ }
+ { "Up " f.exec { Up }
+ sensitive {([send htuButton isSensitive]==1) ? "true" : "false" }
+ }
+ { "Home " f.exec { Home } }
+ { f.dblline }
+ { "Reload " f.exec { Reload } }
+ { "Open File... " f.exec { Open } }
+ { "Save As... " f.exec { SaveAs } }
+ { "View Page Source " f.exec { srcOpen } }
+ { f.dblline }
+ { "Find... " f.exec { Find } }
+ { "Search... " f.exec { Search } }
+ { "Print... " f.exec { Print } }
+} ; createMenu navMenu helpText $navMenuDescription
+
+# Create the default Section Menu.
+set secMenuDescription {
+ { " Top of Page " f.exec { send helpText gotoId 0 } }
+ { f.dblline }
+ { " " f.exec { noop } }
+ { " No Sections Found " f.exec { noop } }
+ { " " f.exec { noop } }
+} ; createMenu secMenu secButton $secMenuDescription
+
+# Create the default Parameter Menu.
+set parMenuDescription {
+ { " No Parameters Found" f.exec { noop } }
+} ; createMenu parMenu parButton $parMenuDescription
+
+
+# Initialize.
+Init
+
+
+################################################################################
+# Menubar command callbacks.
+################################################################################
+
+# File Menu
+set fileMenuDescription {
+ { " Open File... " f.exec { Open } }
+ { " Save As... " f.exec { SaveAs } }
+ { " Print... " f.exec { Print } }
+ { f.dblline }
+ { " Reload... " f.exec { Reload } }
+ { " View Page Source " f.exec { srcOpen } }
+ { " Search... " f.exec { Search } }
+ { " Find... " f.exec { Find } }
+ { f.dblline }
+ { " Help " f.exec { Help } }
+ { " Quit " f.exec { Quit } }
+} ; createMenu fileMenu fileButton $fileMenuDescription
+
+
+# History Menu
+set historyMenuDescription {
+ { " Back " f.exec { Back }
+ sensitive {([send htbButton isSensitive]==1) ? "true" : "false" }
+ }
+ { " Forward " f.exec { Forward }
+ sensitive {([send htfButton isSensitive]==1) ? "true" : "false" }
+ }
+ { " Up " f.exec { Up }
+ sensitive {([send htuButton isSensitive]==1) ? "true" : "false" }
+ }
+ { " Home " f.exec { Home } }
+ { f.dblline }
+ { " Clear History" f.exec { histClear } }
+ { f.dblline }
+} ; createMenu historyMenu historyButton $historyMenuDescription
+
+
+# Options Menu
+set optsMenuDescription {
+ { " Show task type " f.exec { setOpts showType }
+ bitmap {($showType==1)? "check" : "null"} }
+ { " Show missing files " f.exec { setOpts showFiles }
+ bitmap {($showFiles==1)? "check" : "null"} }
+ { f.dblline }
+ { " Vertical task listing " f.exec { setOpts verticalList True }
+ bitmap {($listOrient==1)? "check" : "null"}
+ }
+ { " Horizontal task listing " f.exec { setOpts verticalList False }
+ bitmap {($listOrient==0)? "check" : "null"}
+ }
+ { f.dblline }
+ { " Tcl Command Shell " f.exec { tclOpen } }
+} ; createMenu optsMenu optionsButton $optsMenuDescription
+
+
+proc setOpts { opt args } {
+ global optsMenuDescription
+ global listOrient showType showFiles
+ global HTask HPkg HOpt hcurrent
+
+ switch $opt {
+ showType { set showType [expr { ($showType == 1) ? 0 : 1 } ]
+ GCmd type $showType
+ set h $hcurrent
+ GCmd help $HTask($h) $HPkg($h) $HOpt($h)
+ }
+ showFiles { set showFiles [expr { ($showFiles == 1) ? 0 : 1 } ]
+ }
+ verticalList { set listOrient [expr { ($args == "False") ? 0 : 1 } ]
+ send topicList set verticalList $args
+ }
+ }
+ editMenu optsMenu optionsButton $optsMenuDescription
+}
+
+proc Print args {
+ send printShell map
+} ; send printButton addCallback Print
+
+proc Find { args } {
+ send findShell popup
+} ; send findButton addCallback Find
+
+proc Search { args } {
+ global search_mapped
+
+ send searchShell map
+ set search_mapped 1
+} ; send searchButton addCallback Search
+
+proc Reload args {
+ global HPkg HType HUrl HOpt HTask HFile hcurrent
+
+ if { $HType($hcurrent) == "file"} {
+ if {[info exists HFile($hcurrent)] == 1} {
+ GCmd directory open $HFile($hcurrent)
+ } else {
+ setAlert param old [format "HFile param at %d not found" $hcurrent]
+ }
+ } else {
+ loadHistItem $hcurrent $HPkg($hcurrent) $HTask($hcurrent) \
+ $HOpt($hcurrent) $HType($hcurrent) $HUrl($hcurrent)
+ }
+} ; send reloadButton addCallback Reload
+
+proc Help args {
+ send hlpShell map
+} ; send helpButton addCallback Help
+
+proc Open args {
+ send fmtGroup unmap
+ send fmtGroup set height 0
+ send fbcOkay set label Load
+ send fileBrowser map
+}
+
+proc SaveAs args {
+ global format
+
+ # Reset the default format every time we open.
+ send $format set on 0
+ set format fmtSrc
+ send $format set on 1
+
+ # If there's no filename specified set one as a default.
+ setDefaultFname
+
+ send fmtGroup map
+ send fmtGroup set height 65
+ send fbcOkay set label Save
+ send fileBrowser map
+}
+
+proc Quit args {
+ GCmd quit
+ deactivate unmap
+}; send quitButton addCallback Quit
+
+
+
+################################################################################
+# Callbacks for client state variables (UI parameter objects). When the
+# client's state changes it updates a UI parameter to reflect the change.
+# This produces a callback to one or more of the callbacks defined below,
+# used to update the GUI to reflect the changing state of the client.
+################################################################################
+
+proc setShowType { param old new } {
+ global showType listOrient showFiles optsMenuDescription
+ set showType $new
+ editMenu optsMenu optionsButton $optsMenuDescription
+}; send showtype addCallback setShowType
+
+proc setTopics { param old new } {
+ global pkgList
+ set pkgList $new
+ send topicList setList $new resize
+}; send pkglist addCallback setTopics
+
+proc appendHist { param old new } {
+ global helpType helpOption curtask curpack
+
+ if {$new == "package"} {
+ #addHistRecord $curpack $curpack "" $helpOption "" $helpType
+ addHistRecord $curpack $curpack "" $helpOption "" "package"
+ } elseif {$new == "append"} {
+ # We've got a result of some kind and all of the values have been
+ # set, so create a history record.
+ if {$curpack != "" && $curtask != ""} {
+ addHistRecord $curpack $curtask "" $helpOption "" $helpType
+ }
+ }
+}; send history addCallback appendHist
+
+proc setCurpack { param old new } {
+ global curpack
+
+ if { $new != [getPkgName $curpack] } {
+ if { $curpack != "" && \
+ $curpack != "clpackage" && \
+ [string match "root*" $new] != 1} {
+ set curpack [ format "%s.%s" $curpack $new]
+ send htuButton set sensitive true
+ } else {
+ set curpack $new
+ }
+ }
+}; send curpack addCallback setCurpack
+
+
+proc setCurtask { param old new } {
+ global curtask curpack helpType
+
+ if {$helpType == "package"} {
+ send topicEntry set string $curpack
+ } else {
+ send topicEntry set string [ format "%s.%s" $curpack $new ]
+ }
+
+ # Update the printer dialog so the filename defaults to the curtask.
+ if { [send toFile get on] } {
+ if {$HType($hcurrent) == "file" || [send srcOpt get on] == 1} {
+ send printEntry set string [format "%s" [fileSource] ]
+ } else {
+ send printEntry set string [format "%s.ps" $new]
+ }
+ } else {
+ send printEntry set string "printer"
+ }
+ set curtask $new
+}; send curtask addCallback setCurtask
+
+
+proc getPkgName { pkg } {
+ set last [ string last "." $pkg ]
+ if { $last > -1 } {
+ return [ string range $pkg [incr last] end ]
+ } else {
+ return $pkg
+ }
+}
+
+proc getParentName { pkg } {
+ set last [ string last "." $pkg ]
+ if { $last > -1 } {
+ set root [ string range $pkg 0 [incr last -1] ]
+ } else {
+ set root $pkg
+ }
+ return [getPkgName $root]
+}
+
+
+# Topic list selection callback.
+proc topicSelect { widget event args } {
+ global htop hcurrent curpack curtask helpOption helpType
+ global visited
+
+ # If we're currently positioned somewhere in the middle of the
+ # history menu, push the current page to the history list before
+ # getting the next result.
+ if {$htop != $hcurrent} {
+ addHistRecord $curpack $curtask "" $helpOption "" $helpType
+ send htbButton set sensitive True
+ send htuButton set sensitive True
+ }
+
+ set item [string trimright [send topicList getItem itemno] "."]
+ send topicList getItem itemno
+ if { $itemno != "none" } {
+ GCmd help $item $curpack $helpOption
+ set visited($item) 1
+ }
+} ; send topicList addEventHandler topicSelect buttonReleaseMask
+
+proc listViewResize { args } {
+ global pkglist
+ send topicList setList $pkglist resize
+} ; send listView addEventHandler listViewResize ResizeRedirectMask
+
+
+# Get help for a specific topic from the topic entry widget.
+proc getTopicHelp { widget mode topic args } {
+ global curpack helpOption
+
+ if { [string match "*\.*" $topic] == 1} {
+ set pkglist [ split $topic "." ]
+ set pack [lindex $pkglist [expr {[llength $pkglist] - 2}] ]
+ set task [lindex $pkglist [expr {[llength $pkglist] - 1}] ]
+ set curpack $pack
+ GCmd help $task $curpack $helpOption
+ } else {
+ set curtask ""
+ set curpack ""
+ GCmd help $topic $curpack $helpOption
+ }
+} ; send topicEntry addCallback getTopicHelp
+
+proc topicClear { args } {
+ send topicEntry set string ""
+} ; send topicClear addCallback topicClear
+
+
+
+################################################################################
+# Help text and HTML processing procedures.
+################################################################################
+
+proc setHelpResult { param old new } {
+ global helpType helpOption curtask curpack
+ global secMenuDescription parMenuDescription
+ global pkgList debug
+
+ # Debug status
+ if {$debug == 1} {
+ send tclEntry append \
+ [format "helpres: type=%1.1s opt=%4.4s curtask=%s curpack=%s\n" \
+ $helpType $helpOption $curtask $curpack ]
+ print [format "helpres: type=%1.1s opt=%4.4s curtask=%s curpack=%s\n" \
+ $helpType $helpOption $curtask $curpack ]
+ }
+
+ if { [string match "*<HTML>*" $new] == 1} {
+ # Strip the header table.
+ if {[ string match "*TABLE*" $new] == 1 } {
+ set new_start [expr [string first "</TABLE>" $new] + 12]
+ set text [ filterBraces [string range $new $new_start end] ]
+ } else {
+ set text [ filterBraces $new ]
+ }
+
+ # Got HTML directly from the client.
+ send helpText setText [format "<HTML><BODY>\n%s" $text ]
+
+ # Save the source for the viewer
+ set docSrc \
+ [ format "<HTML><BODY>\n%s\n</BODY></HTML>\n" $text]
+
+ # Parse the file for menu items.
+ setSectionMenu $new
+ setParameterMenu $new
+
+ } else {
+ # Disable help page content buttons for plain text.
+ send parButton set sensitive False
+ send secButton set sensitive False
+ editMenu secMenu secButton $secMenuDescription
+ editMenu parMenu parButton $parMenuDescription
+
+ # Filter plaintext .men files into something with links, otherwise
+ # unescape the curly braces used to pass the text through Tcl.
+ if {$helpType == "package"} {
+ set str [ filterLinks [ filterTcl $new ] ]
+ } else {
+ set str [ filterTcl $new ]
+ }
+
+ # Load the results
+ send helpText setText "<HTML><BODY><PRE>\n$str\n</PRE></BODY></HTML>"
+
+ # Save the source for the viewer
+ set docSrc \
+ [ format "<HTML><BODY><PRE>\n%s\n</PRE></BODY></HTML>\n" $str]
+ }
+ send helpText retestAnchors
+ send srcText set string $docSrc
+
+ # See which files associated with this topic are available. We turn off
+ # the option toggles first so they can be reset as needed by the client.
+ if {$helpOption != "sysdoc"} {send sysOpt "set sensitive False ; set on 0" }
+ if {$helpOption != "source"} {send srcOpt "set sensitive False ; set on 0" }
+
+ if {$helpType == "package"} {
+ set parent [getParentName $curpack]
+ if {$parent == "clpackage" || [string match "root*" $parent] == 1} {
+ GCmd files $curtask "clpackage"
+ } else {
+ GCmd files $curtask $parent
+ }
+ } else {
+ GCmd files $curtask [string range $curpack \
+ [expr {[string last "." $curpack ] + 1}] end]
+ }
+
+ # Highlight the package list item.
+ for {set i 0} {$i < [llength $pkgList]} {incr i} {
+ if {[lindex $pkgList $i] == $curtask } {
+ send topicList highlight $i
+ break
+ }
+ }
+ printHistStack "helpres "
+
+}; send helpres addCallback setHelpResult
+
+
+# Set an arbitrary TextToggle widget highlight color.
+proc setOptColor { widget color args } {
+ send $widget "set on 1 ; \
+ set offIcon diamond0s ; \
+ set highlightColor $color ; \
+ set background gray75 ; \
+ set onIcon diamond1s ; \
+ set highlightColor $color ; \
+ set background gray75"
+}
+
+
+# Set the file options for the files that were found to be valid (i.e.
+# they're listed in the files output and actually exist).
+proc setHelpFileOpts { param old new } {
+ global helpType helpOption curtask curpack
+ global showFiles
+
+ set opt [lindex $new 0]
+ set val [lindex $new 1]
+ if {$opt != "file"} { set stat [lindex $new 2] }
+
+ # Set the option toggles according to valid files.
+ if {$opt == "sys" && $stat == 0} {
+ send sysOpt set sensitive True
+ } elseif {$opt == "sys" && $stat == 1 && $showFiles == 1} {
+ setOptColor sysOpt yellow
+ }
+ if {$opt == "src" && $stat == 0} {
+ send srcOpt set sensitive True
+ } elseif {$opt == "src" && $stat == 1 && $showFiles == 1} {
+ setOptColor srcOpt yellow
+ }
+
+ # Update the help files panel text.
+ if {$opt == "file"} {
+ set pkg [ string trimright $val ":"]
+ send flpkgVal set label [ format "%s" $pkg ]
+ send toplevel set title [format "XHelp: %s" $pkg ]
+ send flistText set string ""
+ } else {
+ send flistText append [ format " %5.5s %-7.7s %s\n" \
+ $opt \
+ [ expr { ($stat == 0) ? "Okay" : "Error" }] \
+ $val]
+ }
+
+} ; send helpfiles addCallback setHelpFileOpts
+
+
+# Process an HREF link selection. URLs are assumed to be of the form
+#
+# <pkgname>.<task>
+# <task>
+# '#'<hname>
+#
+# If an internal link is found as in the last case we ignore any defined
+# package/task given, otherwise load the selected page.
+
+proc textAnchorSelected {widget cbtype event text href args} {
+ global HPkg HType HUrl HOpt HTask HFile hcurrent htop
+ global curpack helpOption visited
+
+ set visited($href) 1
+ send helpText retestAnchors
+
+ if {[string match "*#*" $href] == 1} {
+ set link [string range $href [expr [string first "#" $href] + 1] end ]
+ set HUrl($hcurrent) $link
+ send helpText gotoId [ send helpText anchorToId $link ]
+ } else {
+ if { [string match "*\.*" $href] == 1} {
+ set pack [lindex [split $href "."] 0]
+ set task [lindex [split $href "."] 1]
+ set curpack $pack
+ GCmd help $task $curpack $helpOption
+
+ } else {
+ GCmd help $href $curpack $helpOption
+ }
+ }
+
+ if {$hcurrent <= $htop} {
+ set h $hcurrent
+ addHistRecord $HPkg($h) $HTask($h) $HUrl($h) $HOpt($h) \
+ HFile($h) $HType($h)
+ }
+
+}; send helpText addCallback textAnchorSelected anchor
+
+
+# Remove only the escaped curly braces. Used to filter HTML text passed to
+# the GUI with escapes in it.
+
+proc filterBraces { istr args } {
+ if {$istr != ""} {
+ regsub -all {(\\\{)} $istr "\{" v1
+ regsub -all {(\\\})} $v1 "\}" results
+ return $results
+ }
+}
+
+# Remove the backslash escapes from source files, escape special chars for
+# presentation on an HTML widget.
+
+proc filterTcl { istr args } {
+ if {$istr != ""} {
+ regsub -all {(\\\{)} $istr "\{" v1
+ regsub -all {(\\\})} $v1 "\}" v2
+ regsub -all {(\<)} $v2 "\\&lt;" v3
+ regsub -all {(\>)} $v3 "\\&gt;" results
+ return $results
+ }
+}
+
+
+# Scan a plaintext doc to see if maybe this is a package help menu. We use
+# some assumption that most of the lines will be of the form "task '-' desc"
+# then parse the file resetting all of the 'task' names as HREFs for other
+# tasks.
+
+proc filterLinks { istr args } {
+
+ set lines [split $istr "\n"]
+ set blank " "
+ set results { }
+ lappend results ""
+ foreach i $lines {
+ set line [string trimleft [detab $i] ]
+ if {[regexp {(^[a-zA-Z0-9\ \_\(\)]+[\+|\-]*)} $line arg] == 1 &&
+ ([string match "*\-*" $arg] == 1 ||
+ [string first "\*" $line] > 0 ||
+ [string match "*\+*" $arg] == 1) } {
+
+ set task [string trim [string trimright $arg "-+"] ]
+ set l [string first "-" $line]
+ if {$l == -1} {
+ set l [string first "+" $line]
+ if {$l == -1} {
+ set l [string first "\*" $line]
+ }
+ }
+ set desc [ string range $line $l end ]
+
+ # We now have the task name and the description string, format
+ # on output with the HREF defined.
+ set nblanks [expr 13 - [string length $task] ]
+ set fmtstr [format "%%%ds<A HREF=\"%%s\">%%s</A> %%s\n" $nblanks ]
+ set ostr [format $fmtstr $blank $task $task $desc]
+
+ lappend results $ostr
+
+ } elseif {[regexp {(^[a-zA-Z0-9\_]+\.[a-zA-Z0-9\_]+\:$)} $i val] == 1} {
+
+ # Break out the task and package names.
+ regsub -all {[\.:]} $i " " val
+ scan $val "%s %s" parent child
+
+ # Format a URL and append the results.
+ if { [ string match "*root*" $parent] == 0} {
+ set ref [format "<A HREF=\"%s\">%s</A>.<A HREF=\"%s\">%s</A>:\n"\
+ $parent $parent $child $child ]
+ } else {
+ set ref [format "%s.<A HREF=\"%s\">%s</A>:\n"\
+ $parent $child $child ]
+ }
+ lappend results $ref
+
+ } else {
+ set nblanks [expr [string length $i] - [string length $line] ]
+ set fmtstr [format "%%%ds%%s\n" $nblanks ]
+ lappend results [format $fmtstr $blank $line ]
+ }
+ }
+ return [ join $results ]
+}
+
+
+# Generated a list of the lines and create the section menu.
+
+proc setSectionMenu { text args } {
+ global secMenuDescription
+
+ # Break out the table of contents from the string. Note we're hard-
+ # wired here into the form of the comment string used to contain the
+ # section name.
+ set l [expr [string first "<! Contents: " $text] + 12]
+ if {$l == 0} { return }
+ set s [string range $text $l end]
+ set r [expr [string first ">" $s] - 4]
+ set t [string range $s 0 $r]
+ set lst [split $t '\'']
+
+ # Now take the list generated and create the menu.
+ set items { }
+ lappend items " \"Top of Page\" f.exec \{ send helpText gotoId 0 \}"
+ lappend items " f.dblline "
+ foreach i $lst {
+ if {$i != " "} {
+ set i [ string trimright $i ]
+ regsub -all {[ ,.():;]} [string tolower $i] _ url
+ lappend items " \" $i \" f.exec \{ jumpToName #s_$url \}"
+ }
+ }
+
+ if { [llength $items] == 3 } {
+ send secButton set sensitive False
+ editMenu secMenu secButton $secMenuDescription
+ } else {
+ editMenu secMenu secButton $items
+ send secButton set sensitive True
+ }
+}
+
+
+# Generated a list of the lines and create the parameter menu.
+proc setParameterMenu { text args } {
+ global parMenuDescription
+ set items { }
+ foreach i [split $text "\n"] {
+ if {[string match "\<\! Sec*PARAMETERS*Level=0*" $i] == 1} {
+ set l [expr [string first "Line='" $i] + 6]
+ set s [string range $i $l end]
+ set r [expr [string first "\'" $s] - 1]
+ set t [string range $s 0 $r]
+ regsub -all {[\ ]} $t " " d ;# remove tabs
+ regsub -all {[\"]} $d "\\\"" entry
+
+ set l [expr [string first "Label='" $i] + 7]
+ set s [string range $i $l end]
+ set r [expr [string first "\'" $s] - 1]
+ set t [string range $s 0 $r]
+
+ lappend items " \"$entry\" f.exec \{ jumpToName #l_$t \}"
+ }
+ }
+
+ if { [llength $items] == 0 } {
+ send parButton set sensitive False
+ editMenu parMenu parButton $parMenuDescription
+ } else {
+ editMenu parMenu parButton $items
+ send parButton set sensitive True
+ }
+}
+
+
+# Position the page to the requested href name.
+proc jumpToName { name } {
+ global curtask curpack helpType helpOption
+
+ send helpText gotoId [send helpText anchorToId $name]
+ send helpText retestAnchors
+
+ # Now add a history record for the jump
+ addHistRecord $curpack $curtask $name $helpOption "" $helpType
+}
+
+
+# Utility routine to 'detab' a line and preserve format.
+proc detab {str {tablen 8}} {
+ set a 0
+ set i [string first "\t" $str]
+ while {$i != -1} {
+ set m { }
+ set j $i
+ while {[incr j] % $tablen} { append m { } }
+ set str [string range $str $a \
+ [expr {$i-1}]]$m[string range $str [incr i] end]
+ set i [string first "\t" $str]
+ }
+ return $str
+}
+
+
+################################################################################
+# Navigation and History Callbacks
+################################################################################
+
+# Go back one page.
+proc Back args {
+ global curtask curpack helpType helpOption
+ global HPkg HType HUrl HOpt HTask HFile htop hcurrent
+
+ incr hcurrent -1
+ if {$hcurrent >= 0} {
+ set item $HTask($hcurrent)
+ set pkg $HPkg($hcurrent)
+ set type $HType($hcurrent)
+ set h $hcurrent
+
+ if { $item == "Home" } {
+ loadHomePage
+ } else {
+ if { $HType($h) == "file"} {
+ if {[info exists HFile($h)] == 1} {
+ loadHistItem $h pkg $HFile($h) help file
+ } else {
+ setAlert param old \
+ [format "HFile param at %d not found" $hcurrent]
+ }
+ } else {
+ loadHistItem $h $HPkg($h) $HTask($h) $HOpt($h) \
+ $HType($h) $HUrl($h)
+ }
+ }
+
+ if {$hcurrent == 0} {
+ send htbButton set sensitive False
+ send htuButton set sensitive False
+ }
+ if {$hcurrent >= 0} {
+ send htfButton set sensitive True
+ send htuButton set sensitive True
+ }
+ } else {
+ set hcurrent 0
+ }
+ editHistoryMenu
+ printHistStack "Back "
+} ; send htbButton addCallback Back
+
+
+# Go forward one page.
+proc Forward args {
+ global curtask curpack helpType helpOption
+ global HPkg HType HUrl HOpt HTask HFile htop hcurrent
+
+ incr hcurrent
+ if {$hcurrent <= $htop} {
+ set item $HTask($hcurrent)
+ set pkg $HPkg($hcurrent)
+ set type $HType($hcurrent)
+ set h $hcurrent
+
+ if { $item == "Home" } {
+ loadHomePage
+ } else {
+ if { $HType($h) == "file"} {
+ if {[info exists HFile($h)] == 1} {
+ loadHistItem $h pkg $HFile($h) help file
+ } else {
+ setAlert param old \
+ [format "HFile param at %d not found" $hcurrent]
+ }
+ } else {
+ loadHistItem $h $HPkg($h) $HTask($h) $HOpt($h) \
+ $HType($h) $HUrl($h)
+ }
+ }
+
+ if {$hcurrent == $htop } {
+ send htfButton set sensitive False
+ send htbButton set sensitive True
+ } else {
+ send htbButton set sensitive True
+ }
+ } else {
+ incr hcurrent -1
+ }
+ editHistoryMenu
+ printHistStack "Forward "
+} ; send htfButton addCallback Forward
+
+
+# Go up to previous package, skipping over pages inbetween.
+proc Up args {
+ global curtask curpack helpType helpOption
+ global HPkg HType HUrl HOpt HTask htop hcurrent
+
+ # From the current page go back until we find a package
+ if {$HType($hcurrent) == "package"} {
+ set i [expr {$hcurrent-1} ]
+ } else {
+ set i $hcurrent
+ }
+ while {$HType($i) != "package" && $i >= 0} {
+ incr i -1
+ }
+
+ # Found package, go get it.
+ set hcurrent $i
+ if {$i == 0} {
+ loadHomePage ;# push a history record??
+ } else {
+ GCmd load $HTask($i) [getPkgName $HPkg($i)] $HOpt($i)
+ }
+
+ set curtask $HTask($hcurrent) ;# update the state of things
+ set curpack $HPkg($hcurrent)
+ set helpOption $HOpt($hcurrent)
+ set helpType $HType($hcurrent)
+
+ send topicEntry set string $curpack ;# update topic entry string
+
+ if {$hcurrent == 0} { ;# adjust navigation buttons
+ send htbButton set sensitive False
+ send htuButton set sensitive False
+ }
+ if {$hcurrent >= 0} {
+ send htfButton set sensitive True
+ send htuButton set sensitive True
+ }
+ editHistoryMenu
+ printHistStack "Forward "
+} ; send htuButton addCallback Up
+
+
+# Go straight to the homepage.
+proc Home args {
+ global curtask curpack helpType helpOption
+ global HPkg HType HUrl HOpt HTask HFile htop hcurrent
+
+ # Load the homepage.
+ loadHomePage
+
+ # A Home command jumps over everything in the history list but we
+ # need to push a history record for it anyway.
+ addHistRecord $HPkg(0) $HTask(0) $HUrl(0) $HOpt(0) $HFile(0) $HType(0)
+
+ send topicEntry set string ""
+ set curtask ""
+ set curpack ""
+ set helpType "package"
+ set helpType "help"
+} ; send hthButton addCallback Home
+
+
+# Load the homepage.
+proc loadHomePage { args } {
+ global curtask curpack version showType
+
+ GCmd help Home
+
+ # Clean up.
+ set curtask ""
+ set curpack ""
+ send topicEntry set string ""
+ send toplevel set title $version
+}
+
+# Clear all the history information.
+proc histClear args {
+ global HPkg HType HUrl HOpt HTask HFile htop hcurrent
+ global visited
+
+ # Clear the visited anchors list.
+ foreach i [array names visited] {
+ unset visited($i)
+ }
+
+ # Clear the history stack.
+ for { set i [expr {$htop -1}] } { $i >= 0 } { incr i -1 } {
+ catch {
+ unset HType($i)
+ unset HOpt($i)
+ unset HTask($i)
+ unset HPkg($i)
+ unset HUrl($i)
+ unset HFile($i)
+ }
+ }
+
+ # Reinitialize, but save the current page as the new history stack.
+ catch {
+ set HPkg(0) $HPkg($htop) ;# package
+ set HOpt(0) $HOpt($htop) ;# option
+ set HTask(0) $HTask($htop) ;# task
+ set HUrl(0) $HUrl($htop) ;# url
+ set HType(0) $HType($htop) ;# type
+ set HFile(0) $HFile($htop) ;# filename
+ }
+ set htop 0
+ set hcurrent 0
+
+ # Update navigation options and history menu.
+ send htbButton set sensitive False
+ send htfButton set sensitive False
+ send htuButton set sensitive False
+ editHistoryMenu
+}
+
+
+# Push an item on the history stack.
+proc addHistRecord { pkg task url opt file type } {
+ global HPkg HType HUrl HOpt HTask HFile htop hcurrent
+ global helpType helpOption
+ global historyMenuDescription
+
+ # Push a new history record to the top of the stack and make that the
+ # current record.
+ incr htop
+ set HPkg($htop) $pkg
+ set HTask($htop) $task
+ set HUrl($htop) $url
+ set HOpt($htop) $opt
+ set HFile($htop) [ expr {($file == "") ? "none" : $file } ]
+ set HType($htop) $type
+ set hcurrent $htop
+
+ # Activate the Back button.
+ if {$hcurrent == 1} {
+ send htbButton set sensitive True
+ if {$type == "package"} {
+ send htuButton set sensitive True
+ }
+ }
+
+ # Edit the history menu.
+ editHistoryMenu
+ printHistStack "addHistRecord"
+}
+
+
+# Edit the history menu to reflect the current state.
+proc editHistoryMenu { args } {
+ global HPkg HType HUrl HOpt HTask htop hcurrent
+ global helpType helpOption
+ global historyMenuDescription
+ global navMenuDescription
+ global MAX_MENU_SIZE
+
+ set items $historyMenuDescription
+ set nitems 0
+ if {$htop > $MAX_MENU_SIZE} {
+ set nstart [ min $htop [expr {$hcurrent + 3}] ]
+ } else {
+ set nstart $htop
+ }
+ for { set i $nstart } { $i >= 0 } { incr i -1 } {
+ set pkg $HPkg($i)
+ set task $HTask($i)
+ set type $HType($i)
+ set opt $HOpt($i)
+ set url $HUrl($i)
+ if {$pkg != "" || $type == "file"} {
+ if {$type == "task"} {
+ if {$url == ""} {
+ set entry [format "%-22.22s %4s" $task \
+ [menuItemType $type $url $opt ] ]
+ } else {
+ set entry [format "%-22.22s %4s" \
+ [ format "%s (%s)" $task [string trimleft $url "#"] ] \
+ [menuItemType $type $url $opt ] ]
+ }
+ } elseif {$type == "package"} {
+ set entry [format "%-22.22s %4s" [getPkgName $pkg] \
+ [menuItemType $type $url $opt ] ]
+ } elseif {$type == "file"} {
+ upvar #0 HFile file
+ set entry [format "%s" $file($i) ]
+ } else {
+ setAlert param old [format "Unknown help type: %s" $type]
+ }
+
+ if {$type == "file"} {
+ lappend items " \" $entry \" f.exec \{ \
+ loadHistItem $i pkg $entry help file \} \
+ bitmap \{\($i==$hcurrent\) ? \"arrow\" : \"null\" \} "
+ } else {
+ lappend items " \" $entry \" f.exec \{ \
+ loadHistItem $i [getPkgName $pkg] $task $opt $type $url \} \
+ bitmap \{\($i==$hcurrent\) ? \"arrow\" : \"null\" \} "
+ }
+ }
+
+ incr nitems 1
+ if {$nitems > $MAX_MENU_SIZE} {
+ lappend items "f.dblline"
+ lappend items " \" History truncated... \" f.exec \{ \} "
+ break
+ }
+ }
+ editMenu historyMenu historyButton $items
+
+ # Edit the navigation menu to get the sensitivities right for
+ # the current state.
+ editMenu navMenu helpText $navMenuDescription
+}
+
+
+# Utility routine to set the history item entry type.
+proc menuItemType { type url opt } {
+ if {$url != ""} {
+ return [format "Link"]
+ }
+
+ switch $opt {
+ "help" { return [format "%s" [expr {($type=="task")?"Task":"Pkg"} ]] }
+ "source" { return [format "(src)"] }
+ "sysdoc" { return [format "(sys)"] }
+ }
+}
+
+
+# Load a particular page/link from the history list.
+proc loadHistItem { itemno pkg task opt type args } {
+ global HPkg HType HUrl HOpt HTask htop hcurrent
+ global curtask curpack helpType helpOption hcurrent
+ global version
+
+ # Load the requested page. Check whether we just need to jump to
+ # the current page.
+ if {$task == "Home"} {
+ loadHomePage
+
+ } elseif {$type == "file"} {
+ GCmd directory open $task
+
+ } elseif {$itemno == $hcurrent || \
+ ($pkg != $curpack || \
+ $task != $curtask || \
+ $type != $helpType || \
+ $opt != $helpOption) } {
+ GCmd load $task $pkg $opt
+ }
+
+ # If the history item included an internal link, jump to it. The
+ # 'args' value will either be the URL or an empty string.
+ if {$args != ""} {
+ send helpText gotoId [send helpText anchorToId $args]
+ send helpText retestAnchors
+ }
+
+ # Update the topic entry string.
+ if { $type == "task" } {
+ send topicEntry set string [ format "%s.%s" $pkg $task ]
+ } elseif { $type == "file" } {
+ send topicEntry set string $task
+ } else {
+ send topicEntry set string $pkg
+ }
+
+ # Change the options button if needed.
+ if {$HOpt($itemno) != $helpOption} {
+ send [ getOptWidget $helpOption ] set on 0
+ setOptColor [ getOptWidget $HOpt($itemno) ] green
+ }
+
+ # Update the current entry.
+ set hcurrent $itemno
+
+ if { $type != "file" } {
+ set curtask $HTask($hcurrent)
+ set curpack $HPkg($hcurrent)
+ set helpOption $HOpt($hcurrent)
+ set helpType $HType($hcurrent)
+ } else {
+ set helpOption "help"
+ set helpType "file"
+ }
+
+ # Tweak the navigation buttons.
+ if {$hcurrent == 0} {
+ send htbButton set sensitive False
+ send htuButton set sensitive False
+ }
+ if {$hcurrent >= 0} {
+ send htfButton set sensitive True
+ send htuButton set sensitive True
+ }
+ if {$hcurrent == $htop } {
+ send htfButton set sensitive False
+ send htbButton set sensitive True
+ }
+
+ # Edit the history menu.
+ editHistoryMenu
+}
+
+# Initialize the history menu.
+editHistoryMenu
+
+# Given the option type return the widget name.
+proc getOptWidget { opt } {
+ switch $opt {
+ "help" { return "hlpOpt" }
+ "source" { return "srcOpt" }
+ "sysdoc" { return "sysOpt" }
+ }
+}
+
+# Debug utility to print the history stack.
+proc printHistStack { where args } {
+ global HPkg HType HUrl HOpt HTask HFile htop hcurrent
+ global debug
+
+ # Print the stack...
+ if {$debug > 0} {
+ print "_______________________________________________________________"
+ print $where
+ for { set i $htop } { $i >= 0 } { incr i -1 } {
+ if {$HType($i) == "file"} {
+ upvar #0 HFile file
+ print [format "%3s%d: type=%1.1s file=%s\n"\
+ [ expr {($i==$hcurrent) ? ">>>" : "---"} ] \
+ $i $HType($i) $file($i) ]
+ } else {
+ print [format "%3s%d: type=%1.1s opt=%4.4s task=%s pack=%s\n"\
+ [ expr {($i==$hcurrent) ? ">>>" : "---"} ] \
+ $i $HType($i) $HOpt($i) $HTask($i) $HPkg($i) $HUrl($i) ]
+ }
+ }
+ }
+}
+
+# Test whether an anchor has been visited.
+proc testAnchor {widget cbtype href} {
+ global visited
+ return [info exists visited($href)]
+}
+send hlpText addCallback testAnchor testAnchor
+send helpText addCallback testAnchor testAnchor
+send resList addCallback testAnchor testAnchor
+
+
+################################################################################
+# Options Menu
+################################################################################
+
+proc setType { param old new } {
+ global helpType
+ set helpType [string tolower $new ]
+} ; send type addCallback setType
+
+proc selectOption { widget type value args } {
+ global curtask curpack helpOption
+
+ if { $curtask != "" } {
+ foreach i { hlpOpt srcOpt sysOpt } { send $i set on 0 }
+ setOptColor $widget green
+ send $widget set on 1
+ switch $widget {
+ hlpOpt { set helpOption help
+ send fmtText setSensitive true
+ send fmtPS setSensitive true
+ }
+ srcOpt { set helpOption source
+ send fmtText setSensitive false
+ send fmtPS setSensitive false
+ }
+ sysOpt { set helpOption sysdoc
+ send fmtText setSensitive true
+ send fmtPS setSensitive true
+ }
+ }
+ GCmd help $curtask [getParentName $curpack] $helpOption
+ }
+}; foreach i {hlpOpt srcOpt sysOpt } { send $i addCallback selectOption }
+
+proc toggleFileOption { args } {
+ if { [ send filOpt get on] == 1 } {
+ send fileShell map
+ } else {
+ send fileShell unmap
+ }
+} ; send filOpt addCallback toggleFileOption
+
+send flDismiss addCallback "send fileShell unmap ; send filOpt set on 0"
+
+
+################################################################################
+# Procedure used by the printer prompt box.
+################################################################################
+
+proc setPrinterName { param old new } {
+ send printEntry set string $new
+}; send printer addCallback setPrinterName
+
+set page_size pageLetter
+
+proc pageRadio { widget type state args } {
+ global page_size
+
+ if {$state == 0} {
+ # Don't allow a button to be turned off.
+ send $widget set on 1
+ } else {
+ send $page_size set on 0
+ set page_size $widget
+ }
+}
+foreach w {pageLetter pageLegal pageA4 pageB5} { send $w addCallback pageRadio }
+
+proc toPrinterToggle args {
+ global curtask HType hcurrent
+ if { [send toPrinter get on] } {
+ send toFile set on False
+ send printLabel set label "Printer: "
+ send printEntry set string "printer"
+ } else {
+ send toFile set on True
+ send printLabel set label "File Name: "
+ if {$HType($hcurrent) == "file" || [send srcOpt get on] == 1} {
+ send printEntry set string [format "%s" [fileSource] ]
+ } else {
+ send printEntry set string [format "%s.ps" $curtask]
+ }
+ }
+} ; send toPrinter addCallback toPrinterToggle
+
+proc toFileToggle args {
+ global curtask HType hcurrent
+ if { [send toFile get on] } {
+ send toPrinter set on False
+ send printLabel set label "File Name: "
+ if {$HType($hcurrent) == "file" || [send srcOpt get on] == 1} {
+ send printEntry set string [format "%s" [fileSource] ]
+ } else {
+ send printEntry set string [format "%s.ps" $curtask]
+ }
+ } else {
+ send toPrinter set on True
+ send printLabel set label "Printer: "
+ send printEntry set string "printer"
+ }
+} ; send toFile addCallback toFileToggle
+
+proc doPrintOkay { args } {
+ global curtask curpack HType hcurrent
+
+ set device [ send printEntry get string ]
+ if { [send toPrinter get on] } {
+ GCmd print $curtask $curpack $device
+ } else {
+ if {$HType($hcurrent) == "file" || [send srcOpt get on] == 1} {
+ GCmd directory save [fileSource] $fname 1 source
+ } else {
+ GCmd directory save [fileSource] $fname 1 postscript
+ }
+ }
+ send printShell unmap
+}
+send printOkay addCallback doPrintOkay
+send printEntry addCallback doPrintOkay
+
+send printDismiss addCallback "send printShell unmap "
+
+
+################################################################################
+# Procedures used by the fileBrowser.
+################################################################################
+
+# File browsing globals
+set curdir "" ;# current directory
+set pattern "*" ;# filename template
+set format "fmtSrc" ;# SaveAs format
+
+
+# Browser selection callback.
+proc browserSelect { widget event args } {
+ global curdir helpOption
+
+ set opt [expr {$widget == "dirList" ? "dirlist" : "loadfile"}]
+ set item [send $widget getItem itemno]
+ send $widget getItem itemno
+ set mode [send fbcOkay get label]
+
+ if { $itemno != "none" } {
+ if { $mode == "Load"} {
+ if {$opt != "dirlist"} {
+ addHistRecord "" "" "" help [format "%s%s" $curdir $item] "file"
+ }
+ GCmd directory $opt $item
+ send flistText set string [format " file Okay %s%s\n" \
+ $curdir $item]
+ } else {
+ if {$opt == "dirlist"} {
+ GCmd directory $opt $item
+ } else {
+ send fnameEntry set string [format "%s%s" $curdir $item]
+ }
+ }
+ }
+}
+send dirList addEventHandler browserSelect buttonReleaseMask
+send fileList addEventHandler browserSelect buttonReleaseMask
+
+
+# Client callback.
+proc browserListing { param old new } {
+ global curdir pattern
+
+ set option [ lindex $new 0 ]
+ switch $option {
+ dirlist { set list [lindex $new 1]
+ send dirList setList $list resize
+ }
+ filelist { set list [lindex $new 1]
+ send fileList setList $list resize
+ }
+ template { set pattern [lindex $new 1]
+ send filterEntry set string $pattern
+ }
+ curdir { set curdir [lindex $new 1]
+ send curdirVal set label $curdir
+ }
+ selection { send fnameEntry set string [lindex $new 1] }
+ }
+} ; send directory addCallback browserListing
+
+
+# Set the filename matching template.
+proc setTemplate { widget mode pattern args } {
+ GCmd directory template $pattern
+} ; send filterEntry addCallback setTemplate
+
+
+# get the filename of the currently displayed page.
+proc fileSource { args } {
+ global helpOption
+
+ set str [ send flistText get string ]
+
+ set fname ""
+ for {set i 0} {$i < [llength $str]} {incr i 3} {
+ set j [expr {$i + 2} ]
+ if {($helpOption == "source" && [lindex $str $i] == "src") ||
+ ($helpOption == "sysdoc" && [lindex $str $i] == "sys") ||
+ ($helpOption == "help" && [lindex $str $i] == "hlp") ||
+ ($helpOption == "file" && [lindex $str $i] == "file")} {
+ set fname [lindex $str $j]
+ break
+ }
+ }
+ return $fname
+}
+
+# Open a specific file, either to load a new page or save the current page.
+proc openFile { widget args } {
+ global curdir helpOption
+
+ set fname [send fnameEntry get string]
+
+ if {$fname == ""} {
+ setAlert param old "No filename specified"
+ } else {
+ if { [send fbcOkay get label] == "Load"} {
+ addHistRecord "" "" "" "" [format "%s%s" $curdir $fname] "file"
+ GCmd directory open $fname
+ send flistText set string [format " file Okay %s\n" $fname]
+ } else {
+ set page [fileSource]
+ set ow [send overwrite get on]
+ if {[send fmtSrc get on] == 1} {
+ GCmd directory save $page $fname $ow source
+ } elseif {[send fmtText get on] == 1} {
+ GCmd directory save $page $fname $ow text
+ } elseif {[send fmtHTML get on] == 1} {
+ GCmd directory save $page $fname $ow html
+ } elseif {[send fmtPS get on] == 1} {
+ GCmd directory save $page $fname $ow postscript
+ }
+ }
+ }
+} ; send fbcOkay addCallback openFile
+
+
+# Make the SaveAs formats a radio box.
+proc fmtRadio { widget type state args } {
+ global format
+
+ if {$state == 0} {
+ # Don't allow a button to be turned off.
+ send $widget set on 1
+ } else {
+ send $format set on 0
+ set format $widget
+ }
+
+ # If there's no filename specified set one as a default.
+ setDefaultFname
+
+} ; foreach w {fmtSrc fmtText fmtHTML fmtPS} { send $w addCallback fmtRadio }
+
+
+# Set a default filename based on the selected format and task name
+proc setDefaultFname args {
+ global format curtask curdir
+
+ set fname [send fnameEntry get string]
+ if {$curtask != ""} {
+ switch $format {
+ fmtSrc { send fnameEntry \
+ set string [format "%s%s" $curdir $curtask] }
+ fmtText { send fnameEntry \
+ set string [format "%s%s.txt" $curdir $curtask] }
+ fmtHTML { send fnameEntry \
+ set string [format "%s%s.html" $curdir $curtask] }
+ fmtPS { send fnameEntry \
+ set string [format "%s%s.ps" $curdir $curtask] }
+ }
+ }
+}
+
+proc browserHelp args {
+ if { [send fbcOkay get label] == "Load"} {
+ showHelp lfiles
+ } else {
+ showHelp sfiles
+ }
+} ; send fbcHelp addCallback browserHelp
+
+send fnavHome addCallback "GCmd directory home"
+send fnavUp addCallback "GCmd directory up"
+send fnavRoot addCallback "GCmd directory root"
+send fnavRescan addCallback "GCmd directory rescan"
+send fnameClear addCallback "send fnameEntry set string \"\""
+send filterClear addCallback "send filterEntry set string \"\""
+send fbcDismiss addCallback "send fileBrowser unmap"
+
+
+
+################################################################################
+# Procedures used by the find box.
+################################################################################
+
+proc doFindOkay args {
+ set dir forward
+ set case caseless
+ set phrase [send findEntry get string]
+
+ if { $phrase != "" } {
+ if { [send findDir get on] } { set dir backward }
+ if { [send findCase get on] } { set case caseSensitive }
+
+ if { [send helpText searchText $phrase start end $dir $case] > 0 } {
+ set elid [lindex [lindex $start 0] 0]
+ set id [max 1 [expr $elid - 10] ]
+
+ send helpText gotoId $id
+ send helpText setSelection $start $end
+ } else {
+ send warnText set label "Search string not found."
+ send warning map
+ }
+ } else {
+ send warnText set label "Warning: No search phrase entered."
+ send warning map
+ }
+} ; foreach w { findOkay findEntry } { send $w addCallback doFindOkay }
+
+send findClear addCallback { send findEntry set string "" }
+send findDismiss addCallback { send findShell popdown }
+
+
+################################################################################
+# Procedures used by the apropos prompt box.
+################################################################################
+
+proc doSearchOkay args {
+ set phrase [send searchEntry get string]
+ if { $phrase != "" } {
+ send searchStatus set label "Searching..."
+ GCmd search [send exactMatch get on] $phrase
+ } else {
+ send warnText set label "Warning: No search phrase entered."
+ send warning map
+ }
+} ; foreach w { searchOkay searchEntry } { send $w addCallback doSearchOkay }
+
+proc searchResults { param old new } {
+ global search_mapped
+
+ if {$search_mapped == 0} {
+ Search
+ }
+ send resList setText $new
+ send resList retestAnchors
+ send searchStatus set label ""
+} ; send apropos addCallback searchResults
+
+# Selection callback.
+proc searchAnchorSelected {widget cbtype event text href args} {
+ global helpOption helpType curpack curtask
+ global visited
+
+ # Break out the task and package names.
+ set pack [lindex [split $href "."] 0]
+ set task [lindex [split $href "."] 1]
+
+ # Set the state and load the page.
+ if {$helpOption != "help"} {
+ send [getOptWidget $helpOption] set on 0
+ setOptColor hlpOpt green
+ }
+ set curtask $task
+ set curpack $pack
+ set helpOption "help"
+ set helpType [expr {($pack == $task) ? "package" : "task"}]
+ GCmd load $curtask $curpack $helpOption
+
+ # Add the history record, one for the package and one for the task.
+ addHistRecord $curpack $curpack "" $helpOption "" "package"
+ if {$pack != $task} {
+ addHistRecord $curpack $curtask "" $helpOption "" "task"
+ }
+ send htbButton set sensitive True
+ send htuButton set sensitive True
+ editHistoryMenu
+ printHistStack "searchAnchorSelected"
+
+ # Update the topic entry string.
+ if { $task == $pack } {
+ send topicEntry set string $pack
+ } else {
+ send topicEntry set string [ format "%s.%s" $pack $task ]
+ }
+
+ set visited($href) 1
+ send resList retestAnchors
+
+} ; send resList addCallback searchAnchorSelected anchor
+
+proc doSearchClear args {
+ send searchEntry set string ""
+} ; send searchClear addCallback doSearchClear
+
+proc doSearchDismiss args {
+ global search_mapped
+
+ set search_mapped 0
+ send searchShell unmap
+} ; send searchDismiss addCallback doSearchDismiss
+
+send searchHelp addCallback { showHelp search }
+
+
+################################################################################
+# Define procedures for the help panel
+################################################################################
+
+# Stuff for keeping track of visited anchors.
+set h_links { 0 }
+set h_linkIndex 0
+
+proc getHelpText { param old new } {
+ send hlpText setText $new
+}; send help addCallback getHelpText
+
+proc anchorSelected {widget cbtype event text href args} {
+ global visited h_links h_linkIndex
+ set anchID [send hlpText anchorToId $href]
+ set visited($href) 1
+ if {$h_linkIndex == 0} {
+ send hlpBack set sensitive True
+ if {[lindex $h_links 1] != $anchID} {
+ set h_links { 0 }
+ send hlpForward set sensitive False
+ }
+ }
+ if {$h_linkIndex > 0 && \
+ [lindex $h_links [expr $h_linkIndex + 1]] != $anchID} {
+ #set h_links [lrange $h_links 0 $h_linkIndex]
+ set pos [send hlpText positionToId 0 0]
+ set h_links [lreplace $h_links $h_linkIndex end $pos]
+ }
+ if {[lindex $h_links [expr $h_linkIndex + 1]] != $anchID} {
+ lappend h_links $anchID
+ incr h_linkIndex
+ } else {
+ send hlpForward set sensitive False
+ incr h_linkIndex
+ }
+ if {$h_linkIndex == [expr [llength $h_links] - 1]} {
+ send hlpForward set sensitive False
+ }
+ send hlpText gotoId $anchID
+ send hlpText retestAnchors
+}; send hlpText addCallback anchorSelected anchor
+
+
+# Callbacks to position forwards and backwards in link list.
+proc hlpForward args {
+ global h_links h_linkIndex
+ incr h_linkIndex
+ if {$h_linkIndex <= [llength $h_links]} {
+ set anchID [lindex $h_links $h_linkIndex]
+ send hlpText gotoId $anchID
+ send hlpText retestAnchors
+ if {$h_linkIndex == [expr [llength $h_links] - 1]} {
+ send hlpForward set sensitive False
+ send hlpBack set sensitive True
+ } else {
+ send hlpBack set sensitive True
+ }
+ } else {
+ incr h_linkIndex -1
+ }
+}; send hlpForward addCallback hlpForward
+
+proc hlpBack args {
+ global h_links h_linkIndex
+ incr h_linkIndex -1
+ if {$h_linkIndex >= 0} {
+ set anchID [lindex $h_links $h_linkIndex]
+ send hlpText gotoId $anchID
+ send hlpText retestAnchors
+ if {$h_linkIndex == 0} { send hlpBack set sensitive False }
+ if {$h_linkIndex >= 0} { send hlpForward set sensitive True }
+ } else {
+ incr h_linkIndex 1
+ }
+}; send hlpBack addCallback hlpBack
+
+proc hlpHome args {
+ global h_links h_linkIndex
+ set h_links { 0 }
+ set h_linkIndex 0
+ send hlpText gotoId 0
+ send hlpForward set sensitive False
+ send hlpBack set sensitive False
+}; send hlpHome addCallback hlpHome
+
+proc hlpTutorial args {
+ showHelp tutorial
+}; send hlpTutorial addCallback hlpTutorial
+send hlpTutorial unmap ;# NO TUTORIAL AT THE MOMENT
+
+proc showHelp {name args} {
+ anchorSelected widget cbtype event text #$name
+ send hlpShell map
+}
+
+proc hlpFind args {
+ set phrase [send hfEntry get string]
+ set dir forward
+ set case caseless
+
+ if { $phrase != "" } {
+ if { [send hfDir get on] } { set dir backward }
+ if { [send hfCase get on] } { set case caseSensitive }
+ if {[send hlpText searchText $phrase start end $dir $case ] > 0} {
+ set elid [lindex [lindex $start 0] 0]
+ set id [max 1 [expr $elid - 10] ]
+ send hlpText gotoId $id
+ send hlpText setSelection $start $end
+ } else {
+ send warnText set label "Search string not found."
+ send warning map
+ }
+ } else {
+ send warnText set label "Warning: No search phrase entered."
+ send warning map
+ }
+} ; foreach w { hfEntry hfFind } { send $w addCallback hlpFind }
+
+send hfClear addCallback { send hfEntry set string "" }
+
+send hlpDismiss addCallback "send hlpShell unmap"
+
+
+################################################################################
+# Document source viewer procedures.
+################################################################################
+
+proc srcOpen { args } { send doc_source map }
+send srcDismiss addCallback "send doc_source unmap"
+
+
+################################################################################
+# Define some TCL debug procedures
+################################################################################
+
+proc tclOpen {} { send tclShell map }
+
+proc tclCommandClear { widget args } {
+ send tclEntry set string ""
+} ; send tclClear addCallback tclCommandClear
+
+proc tclCommandExecute { widget args } { \
+ send server [send tclEntry {get string}]
+} ; send tclExecute addCallback tclCommandExecute
+
+proc tclCommand { widget mode command args } {
+ send server $command
+} ; send tclEntry addCallback tclCommand
+
+proc tclToggleLogging args {
+ global debug
+ if { [ send tclLogging get state] } {
+ set debug 1
+ send tclLogging set label "Disable Logging"
+ } else {
+ set debug 0
+ send tclLogging set label "Enable Logging"
+ }
+} ; tclToggleLogging
+send tclLogging addCallback tclToggleLogging
+
+send tclDismiss addCallback "send tclShell unmap"
+
+# Connect the 'textout' parameter so it appends messages from
+# the client to the Tcl text window.
+proc tclLogMessages { param old new } {
+ global debug
+ if {$debug == 1} { send tclEntry append [format "%s\n" $new ] }
+} ; send textout addCallback tclLogMessages
+
+
+################################################################################
+# Warning dialog. This pops up a dialog box with the given warning message.
+################################################################################
+
+proc warnOkay {widget args} {
+ global curpack curtask
+
+ set label [send warnText get label]
+ if {[string match "No*" $label ] == 1} {
+ set topic [send topicEntry get string]
+ set last [string last "." $topic ]
+ send topicEntry set string [ string range $topic 0 [ incr last -1 ] ]
+ }
+ send warning unmap
+}; send warnDismiss addCallback warnOkay
+
+
+# The parameter "alert" is used to forward alerts from the client. The
+# special 'dismiss' value can be used to shut down the alert from the
+# client, the special "pop" value pops the last history elements from the
+# stack (used in case of an error loading a file).
+
+proc setAlert {param old new} {
+ global HPkg HType HUrl HOpt HTask HFile htop hcurrent
+
+ if {$new == "dismiss"} {
+ send warning unmap
+ } elseif {$new == "pop"} {
+ catch {
+ unset HType($hcurrent)
+ unset HOpt($hcurrent)
+ unset HTask($hcurrent)
+ unset HPkg($hcurrent)
+ unset HUrl($hcurrent)
+ unset HFile($hcurrent)
+ }
+ incr hcurrent -1
+ } else {
+ send searchStatus set label ""
+ send warnText set label $new
+ send warning map
+ }
+}; send alert addCallback setAlert
+
+
diff --git a/pkg/system/help/xhelp/mkpkg b/pkg/system/help/xhelp/mkpkg
new file mode 100644
index 00000000..a12b2788
--- /dev/null
+++ b/pkg/system/help/xhelp/mkpkg
@@ -0,0 +1,28 @@
+# Make the GUI part of the HELP task.
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+zzdebug:
+ $omake zzdebug.x
+ $link zzdebug.o -l xtools
+ ;
+
+libpkg.a:
+ xhelp.x ../help.h xhelp.h
+ xhcmds.x ../help.h xhelp.h
+ xhdir.x xhelp.h <ctype.h> <diropen.h> <finfo.h>
+ xhfiles.x ../help.h xhelp.h <ctype.h> <fset.h>
+ xhhelp.x ../help.h xhelp.h <error.h> <finfo.h> <fset.h>
+ xhinit.x xhelp.h
+ xhofile.x xhelp.h <fset.h>
+ xhpkg.x <error.h> <fset.h> ../helpdir.h ../help.h xhelp.h
+ xhprint.x xhelp.h ../help.h <ctype.h> <error.h> <ttyset.h>
+ xhqref.x ../help.h xhelp.h <ctype.h> <finfo.h>
+ xhroot.x xhelp.h
+ xhsave.x ../help.h xhelp.h <ctype.h>
+ xhsearch.x xhelp.h <ctype.h> <fset.h>
+ xhsort.x xhelp.h <ctype.h>
+ ;
diff --git a/pkg/system/help/xhelp/xhcmds.x b/pkg/system/help/xhelp/xhcmds.x
new file mode 100644
index 00000000..2c98af79
--- /dev/null
+++ b/pkg/system/help/xhelp/xhcmds.x
@@ -0,0 +1,185 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <syserr.h>
+include "../help.h"
+include "xhelp.h"
+
+
+# XHELP callback commands.
+define XC_COMMANDS "|help|load|print|quit|search|files|directory|type|package|"
+define CMD_HELP 1
+define CMD_LOAD 2
+define CMD_PRINT 3
+define CMD_QUIT 4
+define CMD_SEARCH 5
+define CMD_FILES 6
+define CMD_DIRECTORY 7
+define CMD_TYPE 8
+define CMD_PACKAGE 9
+
+
+# XH_COMMAND_LOOP -- Process the GUI command loop.
+
+procedure xh_command_loop (xh)
+
+pointer xh #I task descriptor
+
+pointer sp, cmd, name, pkg, pat, opt, dev
+real x, y
+int wcs, key, exact_match
+char str[SZ_FNAME]
+
+bool streq()
+int strdic(), clgcur()
+int xh_pkglist()
+
+begin
+ call smark (sp)
+ call salloc (name, SZ_FNAME, TY_CHAR)
+ call salloc (pkg, SZ_FNAME, TY_CHAR)
+ call salloc (opt, SZ_FNAME, TY_CHAR)
+ call salloc (dev, SZ_FNAME, TY_CHAR)
+ call salloc (cmd, SZ_FNAME, TY_CHAR)
+ call salloc (pat, SZ_FNAME, TY_CHAR)
+
+
+ # Enter the command loop.
+ while (clgcur ("coords", x, y, wcs, key, str, SZ_FNAME) != EOF) {
+
+ # Skip any non-colon commands.
+ if (key != ':')
+ next
+
+ # Get the colon command string.
+ call sscan (str)
+ call gargwrd (Memc[cmd], SZ_FNAME)
+
+ switch (strdic (Memc[cmd], Memc[cmd], SZ_FNAME, XC_COMMANDS)) {
+ case CMD_HELP:
+ call gargwrd (Memc[name], SZ_FNAME)
+
+ # Get help on the requested topic, updates package list
+ # if necesary.
+ if (streq(Memc[name],"Home")) {
+ call xh_init (xh, NO, YES)
+ } else {
+ call gargwrd (Memc[pkg], SZ_FNAME) # curpack
+ call gargwrd (Memc[opt], SZ_FNAME) # option
+ call xh_cmd_help (xh, Memc[name], Memc[pkg], Memc[opt])
+ }
+
+ case CMD_FILES:
+ call gargwrd (Memc[name], SZ_FNAME) # task name
+ call gargwrd (Memc[pkg], SZ_FNAME) # parent package
+ call xh_files (xh, Memc[name], Memc[pkg])
+
+ case CMD_LOAD:
+ # Load a requested page from the history.
+ call gargwrd (Memc[name], SZ_FNAME) # task name
+ call gargwrd (Memc[pkg], SZ_FNAME) # curpack
+ call gargwrd (Memc[opt], SZ_FNAME) # help option
+ if (xh_pkglist (xh, Memc[name], HELPDB(xh), LIST(xh)) != 0)
+ call gmsg (XH_GP(xh), "pkglist", LIST(xh))
+ call xh_help (xh, Memc[name], Memc[pkg], Memc[opt])
+
+ case CMD_PRINT:
+ # Print the current results.
+ call gargwrd (Memc[name], SZ_FNAME) # task name
+ call gargwrd (Memc[pkg], SZ_FNAME) # curpack
+ call gargwrd (Memc[dev], SZ_FNAME) # printer name
+ call xh_print_help (xh, Memc[name], Memc[pkg], Memc[dev])
+
+ case CMD_QUIT:
+ # Quit the task.
+ break
+
+ case CMD_SEARCH:
+ # Get the results of the keyword search.
+ call gargi (exact_match)
+ call gargstr (Memc[pat], SZ_FNAME)
+ call xh_search (xh, exact_match, Memc[pat])
+
+ case CMD_DIRECTORY:
+ # Process the directory browsing command.
+ call gargwrd (Memc[opt], SZ_FNAME)
+ call xh_directory (xh, Memc[opt])
+
+ case CMD_TYPE:
+ # Get the showtype value from the GUI
+ call gargi (XH_SHOWTYPE(xh))
+
+ case CMD_PACKAGE:
+ # For the given item return the package in which it
+ # was found. [DEBUG ROUTINE.]
+ call gargwrd (Memc[name], SZ_FNAME)
+ call xh_pkgpath (xh, Memc[name], CURPACK(xh), Memc[pkg])
+ call printf ("%s => %s\n")
+ call pargstr (Memc[name])
+ call pargstr (Memc[pkg])
+ call flush(STDOUT)
+ }
+ }
+
+ call sfree (sp)
+end
+
+
+# XH_CMD_HELP -- Process a help command.
+
+procedure xh_cmd_help (xh, topic, curpack, option)
+
+pointer xh # task descriptor
+char topic[ARB] # requested topic
+char curpack[ARB] # current package
+char option[ARB] # option (help|source|sysdoc)
+
+int len
+
+bool streq()
+int strncmp()
+int xh_pkgname(), xh_pkglist()
+
+begin
+ if (streq (option, "help")) {
+ # No package name given, find one and load it.
+ if (streq (curpack, "{}")) {
+ curpack[1] = EOS
+ len = 0
+ if (xh_pkgname (xh, topic, curpack) == OK)
+ len = xh_pkglist (xh, curpack, HELPDB(xh), LIST(xh))
+
+ if (len != 0 &&
+ strncmp(curpack, "root", 4) != 0 &&
+ strncmp(curpack, "clpack", 6) != 0) {
+ call gmsg (XH_GP(xh), "pkglist", LIST(xh))
+ call strcpy (curpack, CURPACK(xh), SZ_FNAME)
+ call gmsg (XH_GP(xh), "curpack", curpack)
+ call gmsg (XH_GP(xh), "history", "package")
+ }
+ }
+
+ if (xh_pkglist (xh, topic, HELPDB(xh), LIST(xh)) != 0) {
+ # Got a package listing....
+ call gmsg (XH_GP(xh), "pkglist", LIST(xh))
+ call strcpy (topic, CURPACK(xh), SZ_FNAME)
+ call gmsg (XH_GP(xh), "curpack", topic)
+ }
+ }
+
+ if (streq (topic, CURPACK(xh))) {
+ call gmsg (XH_GP(xh), "type", "package")
+ call gmsg (XH_GP(xh), "curtask", topic)
+ if (streq (option, "help"))
+ call xh_help (xh, "", CURPACK(xh), option)
+ else
+ call xh_help (xh, topic, curpack, option)
+ call strcpy (CURPACK(xh), CURTASK(xh), SZ_FNAME)
+
+ } else {
+ call gmsg (XH_GP(xh), "type", "task")
+ call gmsg (XH_GP(xh), "curtask", topic)
+ call xh_help (xh, topic, CURPACK(xh), option)
+ call strcpy (topic, CURTASK(xh), SZ_FNAME)
+ }
+ call gmsg (XH_GP(xh), "history", "append")
+end
diff --git a/pkg/system/help/xhelp/xhdir.x b/pkg/system/help/xhelp/xhdir.x
new file mode 100644
index 00000000..3c951afa
--- /dev/null
+++ b/pkg/system/help/xhelp/xhdir.x
@@ -0,0 +1,567 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <diropen.h>
+include <ctype.h>
+include <finfo.h>
+
+include "xhelp.h"
+
+
+# Pattern matching definitions.
+define PATCHARS "*?["
+
+# Browsing command dictionary.
+define DIR_CMDS "|dirlist|loadfile|open|template|home|up|root|rescan|save|"
+define DIRLIST 1 # get the directory listing
+define LOADFILE 2 # load the requested file
+define OPEN 3 # load the requested file
+define TEMPLATE 4 # filename matching template
+define HOME 5 # goto the user's home$
+define UP 6 # go up one directory
+define ROOT 7 # go to the root directory
+define RESCAN 8 # rescan current directory
+define SAVE 9 # save to the requested file
+
+
+# XH_DIRECTORY -- Process the directory browsing command.
+
+procedure xh_directory (xh, command)
+
+pointer xh #i task descriptor
+char command[ARB] #i command option
+
+pointer sp, dir, file, pattern, path, fmt
+pointer task, pkg, opt, type
+int ncmd, overwrite
+int strdic(), strcmp(), envgets()
+
+begin
+ # Allocate working space and clear it.
+ call smark (sp)
+ call salloc (dir, SZ_PATHNAME, TY_CHAR)
+ call salloc (path, SZ_PATHNAME, TY_CHAR)
+ call salloc (file, SZ_FNAME, TY_CHAR)
+ call salloc (pattern, SZ_FNAME, TY_CHAR)
+ call salloc (fmt, SZ_FNAME, TY_CHAR)
+ call salloc (task, SZ_FNAME, TY_CHAR)
+ call salloc (pkg, SZ_FNAME, TY_CHAR)
+ call salloc (opt, SZ_FNAME, TY_CHAR)
+ call salloc (type, SZ_FNAME, TY_CHAR)
+
+ call aclrc (Memc[dir], SZ_FNAME)
+ call aclrc (Memc[path], SZ_FNAME)
+ call aclrc (Memc[file], SZ_FNAME)
+ call aclrc (Memc[fmt], SZ_FNAME)
+ call aclrc (Memc[pattern], SZ_FNAME)
+ call aclrc (Memc[task], SZ_FNAME)
+ call aclrc (Memc[pkg], SZ_FNAME)
+ call aclrc (Memc[opt], SZ_FNAME)
+ call aclrc (Memc[type], SZ_FNAME)
+
+ ncmd = strdic (command, command, SZ_LINE, DIR_CMDS)
+ switch (ncmd) {
+ case DIRLIST:
+ call gargwrd (Memc[dir], SZ_PATHNAME) # get the dirname
+ if (strcmp ("../", Memc[dir]) == 0) {
+ call xh_updir (xh)
+ } else {
+ call sprintf (Memc[path], SZ_PATHNAME, "%s%s")
+ call pargstr (CURDIR(xh))
+ call pargstr (Memc[dir])
+ call xh_set_curdir (xh, Memc[path])
+ call xh_dirlist (xh, CURDIR(xh), PATTERN(xh))
+ call xh_selection (xh, CURDIR(xh))
+ }
+
+ case LOADFILE:
+ call gargwrd (Memc[file], SZ_FNAME) # get the filename
+ call sprintf (Memc[path], SZ_PATHNAME, "%s%s")
+ call pargstr (CURDIR(xh))
+ call pargstr (Memc[file])
+ call xh_open_file (xh, "helpres", Memc[path], YES, YES)
+ call xh_selection (xh, Memc[path])
+
+ case OPEN:
+ call gargwrd (Memc[file], SZ_FNAME) # get the filename
+ call xh_ldfile (xh, Memc[file])
+
+ case TEMPLATE:
+ call gargwrd (Memc[pattern], SZ_FNAME) # set the template
+ call xh_set_pattern (xh, Memc[pattern])
+ call xh_dirlist (xh, CURDIR(xh), PATTERN(xh))
+
+ case HOME:
+ if (envgets ("home", Memc[dir], SZ_PATHNAME) != EOF) {
+ call xh_set_curdir (xh, Memc[dir])
+ call xh_dirlist (xh, CURDIR(xh), PATTERN(xh))
+ }
+
+ case UP:
+ call xh_updir (xh)
+
+ case ROOT:
+ call xh_set_curdir (xh, "/")
+ call xh_dirlist (xh, CURDIR(xh), PATTERN(xh))
+
+ case RESCAN:
+ call xh_dirlist (xh, CURDIR(xh), PATTERN(xh))
+
+ case SAVE:
+ call gargwrd (Memc[path], SZ_FNAME) # get the filename
+ call gargwrd (Memc[file], SZ_FNAME) # get the output fname
+ call gargi (overwrite) # get the overwrite flag
+ call gargwrd (Memc[fmt], SZ_FNAME) # get the save format
+ call xh_save_file (xh, Memc[path], Memc[file], Memc[fmt],
+ overwrite)
+ }
+
+ call sfree (sp)
+end
+
+
+# XH_DIRLIST -- Given the directory name and a file template return the
+# directory contents.
+
+procedure xh_dirlist (xh, directory, pattern)
+
+pointer xh #i task descriptor
+char directory[ARB] #i directory to read
+char pattern[ARB] #i matching template
+
+pointer sp, path, fname, patbuf
+pointer dp, fp, ip, op, ep, sym
+bool match_extension
+int dd, n, patlen
+int nfiles, ndirs, lastch
+
+pointer stopen(), stenter()
+int diropen(), xh_isdir(), strncmp(), stridxs()
+int patmake(), patmatch(), strlen(), getline()
+
+begin
+ call smark (sp)
+ call salloc (path, SZ_PATHNAME, TY_CHAR)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+ call salloc (patbuf, SZ_LINE, TY_CHAR)
+
+ call aclrc (Memc[patbuf], SZ_LINE)
+
+ # If this isn't a directory just return silently.
+ if (xh_isdir (directory, Memc[path], SZ_PATHNAME) == 0) {
+ call sfree (sp)
+ return
+ }
+
+ # Open the requested directory
+ dd = diropen (directory, PASS_HIDDEN_FILES)
+
+ # Set up the pattern matching code. We recognize selecting all files
+ # with a particular extension as a special case, since this case is
+ # very common and can be done much more efficiently if we don't use
+ # the general pattern matching code. If we have no pattern set the
+ # length to zero to indicate that everything will match.
+
+ if (pattern[1] == EOS) {
+ patlen = 0
+ } else {
+ match_extension = (strncmp (pattern, "*.", 2) == 0 &&
+ stridxs (PATCHARS, pattern[3]) <= 0)
+ if (match_extension)
+ patlen = strlen (pattern)
+ else {
+ # Convert file matching pattern into general pattern string.
+ Memc[fname] = '^'
+ op = fname + 1
+ lastch = 0
+ for (ip=1; pattern[ip] != EOS; ip=ip+1) {
+ if (pattern[ip] == '*' && lastch != '?' && lastch != ']') {
+ Memc[op] = '?'
+ op = op + 1
+ }
+ lastch = pattern[ip]
+ Memc[op] = lastch
+ op = op + 1
+ }
+ Memc[op] = '$'
+ op = op + 1
+ Memc[op] = EOS
+
+ # Compile the pattern.
+ patlen = patmake (pattern, Memc[patbuf], SZ_LINE)
+ }
+ }
+
+ # Initialize counters.
+ ndirs = 0
+ nfiles = 0
+ dp = NULL
+ fp = NULL
+
+ # Accumulate the contents into the directory and files lists. We
+ # match files against the given template, all directories are
+ # matched regardless.
+ for (n=0; n != EOF; ) {
+ n = getline (dd, Memc[fname])
+ if (n < 1)
+ break
+ n = n - 1
+ Memc[fname+n] = EOS # stomp the newline
+
+ # See if this is a directory.
+ call sprintf (Memc[path], SZ_PATHNAME, "%s%s")
+ call pargstr (CURDIR(xh))
+ call pargstr (Memc[fname])
+ if (xh_isdir (Memc[path], Memc[path], SZ_PATHNAME) > 0) {
+ ndirs = ndirs + 1
+
+ # If this is the first directory initialize the symbol table.
+ if (ndirs == 1)
+ dp = stopen ("dirlist", LEN_INDEX, LEN_STAB, SZ_SBUF)
+
+ # Enter the directory name into the symbol table.
+ call strcat ("/", Memc[fname], SZ_FNAME)
+ sym = stenter (dp, Memc[fname], strlen(Memc[fname])+1)
+
+ } else {
+ # Check if the file matches the given pattern.
+ if (patlen > 0) {
+ if (match_extension) {
+ if (n < patlen)
+ next
+ ep = fname + n - 1
+ for (ip=patlen; ip > 2; ip=ip-1) {
+ if (Memc[ep] != pattern[ip])
+ break
+ ep = ep - 1
+ }
+ if (pattern[ip] != '.' || Memc[ep] != '.')
+ next
+ } else if (patmatch (Memc[fname], Memc[patbuf]) <= 0)
+ next
+ }
+
+ # We have a match.
+ nfiles = nfiles + 1
+
+ # If this is the first file initialize the symbol table.
+ if (nfiles == 1)
+ fp = stopen ("filelist", LEN_INDEX, LEN_STAB, SZ_SBUF)
+
+ # Enter the directory name into the symbol table.
+ sym = stenter (fp, Memc[fname], strlen(Memc[fname])+1)
+ }
+ }
+
+ # Send the results to the GUI.
+ call xh_putlist (xh, dp, "directory", "dirlist")
+ call xh_putlist (xh, fp, "directory", "filelist")
+
+ # Clean up.
+ if (dp != NULL)
+ call stclose (dp)
+ if (fp != NULL)
+ call stclose (fp)
+ call close (dd)
+ call sfree (sp)
+end
+
+
+# XH_PUTLIST -- Given the symtab for the directory contents construct a
+# list suitable for a message to the GUI. The 'arg' parameter is passed
+# to indicate which type of list this is.
+
+procedure xh_putlist (xh, stp, param, arg)
+
+pointer xh #i task descriptor
+pointer stp #i symtab ptr for list
+char param[ARB] #i GUI param to notify
+char arg[ARB] #i GUI param arg
+
+pointer sp, list, msg, sym, name, ip
+int nchars
+
+pointer sthead(), stnext(), stname()
+int stsize(), gstrcpy(), strcmp(), strlen()
+
+begin
+ # Return if there is no symtab information.
+ if (stp == NULL) {
+ call smark (sp)
+ call salloc (msg, SZ_FNAME , TY_CHAR)
+ call sprintf (Memc[msg], SZ_FNAME, "%s { }")
+ call pargstr (arg)
+
+ call gmsg (XH_GP(xh), param, Memc[msg]) # send it to the GUI
+ call gflush (XH_GP(xh))
+ call sfree (sp)
+ return
+ }
+
+ # Allocate space for the list.
+ nchars = stsize (stp) + 1
+
+ call smark (sp)
+ call salloc (list, nchars , TY_CHAR)
+ call aclrc (Memc[list], nchars)
+ ip = list
+
+ # Build the list from the symtab.
+ for (sym = sthead (stp); sym != NULL; sym = stnext (stp,sym)) {
+ name = stname(stp,sym)
+ if (strcmp (Memc[name], "./") != 0) {
+ ip = ip + gstrcpy (Memc[name], Memc[ip], SZ_FNAME)
+ ip = ip + gstrcpy (" ", Memc[ip], SZ_FNAME)
+ }
+ }
+
+ # Sort the list.
+ call xh_sort_list (Memc[list])
+
+ # Allocate space for the message buffer. The "+ 6" is space for
+ # the brackets around the list in the message created below.
+ nchars = nchars + strlen (arg) + 6
+ call salloc (msg, nchars, TY_CHAR)
+ call aclrc (Memc[msg], nchars)
+ ip = msg
+
+ # Begin the message by adding the arg and make a Tcl list of the
+ # contents.
+ call sprintf (Memc[msg], nchars, "%s { ")
+ call pargstr (arg)
+ call strcat (Memc[list], Memc[msg], nchars)
+ call strcat (" }", Memc[msg], nchars)
+
+ # Finally, send it to the GUI.
+ call gmsg (XH_GP(xh), param, Memc[msg])
+ call gflush (XH_GP(xh))
+
+ call sfree (sp)
+end
+
+
+# XH_LDFILE -- Load the requested file. If this is a file display it's
+# contents and update the browser with it's directory, otherwise if it's
+# a directory jump the browser to that directory.
+
+procedure xh_ldfile (xh, file)
+
+pointer xh #i task descriptor
+char file[ARB] #i requested file/dir
+
+pointer sp, ip, dir, parent, path
+int nchars
+int access(), strlen(), xh_isdir()
+
+begin
+ call smark (sp)
+ call salloc (dir, SZ_PATHNAME, TY_CHAR)
+ call salloc (path, SZ_PATHNAME, TY_CHAR)
+ call salloc (parent, SZ_PATHNAME, TY_CHAR)
+
+ # Expand the current directory to a host path.
+ call fdirname (file, Memc[dir], SZ_PATHNAME)
+
+ if (xh_isdir (Memc[dir], Memc[path], SZ_PATHNAME) > 0) {
+ # Set the curdir and load it's contents.
+ call xh_set_curdir (xh, Memc[path])
+ call xh_dirlist (xh, CURDIR(xh), PATTERN(xh))
+ call xh_selection (xh, Memc[path])
+ }
+
+ if (access(file,0,0) == YES &&
+ xh_isdir (file, Memc[path], SZ_PATHNAME) == 0) {
+ # Work backwards to the parent '/', be sure to skip the trailing
+ # backslash already in the dirname.
+ ip = dir + strlen (Memc[dir]) - 2
+ while (Memc[ip] != '/' && ip > dir)
+ ip = ip - 1
+
+ nchars = ip - dir
+ if (nchars > 0)
+ call strcpy (Memc[dir], Memc[parent], nchars)
+ else
+ call strcpy ("/", Memc[parent], nchars)
+
+ # Set the parent dir and load it's contents.
+ call xh_set_curdir (xh, Memc[parent])
+ call xh_dirlist (xh, CURDIR(xh), PATTERN(xh))
+
+ # Now load the file itself.
+ call xh_open_file (xh, "helpres", file, YES, YES)
+ call xh_selection (xh, file)
+ }
+
+ call sfree (sp)
+end
+
+
+# XH_UPDIR -- Go up to the parent directory and return contents.
+
+procedure xh_updir (xh)
+
+pointer xh #i task descriptor
+
+pointer sp, ip, dir, parent
+int nchars, strlen()
+
+begin
+ call smark (sp)
+ call salloc (dir, SZ_PATHNAME, TY_CHAR)
+ call salloc (parent, SZ_PATHNAME, TY_CHAR)
+
+ # Expand the current directory to a host path.
+ call fdirname (CURDIR(xh), Memc[dir], SZ_PATHNAME)
+
+ # Work backwards to the parent '/', be sure to skip the trailing
+ # backslash already in the dirname.
+ ip = dir + strlen (Memc[dir]) - 2
+ while (Memc[ip] != '/' && ip > dir)
+ ip = ip - 1
+
+ nchars = ip - dir
+ if (nchars > 0)
+ call strcpy (Memc[dir], Memc[parent], nchars)
+ else
+ call strcpy ("/", Memc[parent], nchars)
+
+ # Set the parent dir and load it's contents.
+ call xh_set_curdir (xh, Memc[parent])
+ call xh_dirlist (xh, CURDIR(xh), PATTERN(xh))
+ call xh_selection (xh, CURDIR(xh))
+
+ call sfree (sp)
+end
+
+
+# XH_SET_CURDIR -- Set the filename matching template pattern.
+
+procedure xh_set_curdir (xh, dir)
+
+pointer xh #i task descriptor
+char dir[ARB] #i current directory
+
+pointer sp, dirbuf
+int strlen()
+
+begin
+ call smark (sp)
+ call salloc (dirbuf, SZ_PATHNAME, TY_CHAR)
+
+ call strcpy (dir, CURDIR(xh), SZ_PATHNAME)
+ if (dir[strlen(dir)] != '/')
+ call strcat ("/", CURDIR(xh), SZ_PATHNAME)
+
+ call sprintf (Memc[dirbuf], SZ_PATHNAME, "curdir %s")
+ call pargstr (CURDIR(xh))
+
+ call gmsg (XH_GP(xh), "directory", Memc[dirbuf])
+ call gflush (XH_GP(xh))
+
+ call sfree (sp)
+end
+
+
+# XH_SET_PATTERN -- Set the filename matching template pattern.
+
+procedure xh_set_pattern (xh, pattern)
+
+pointer xh #i task descriptor
+char pattern[ARB] #i template pattern
+
+pointer sp, patbuf
+
+begin
+ call smark (sp)
+ call salloc (patbuf, SZ_FNAME, TY_CHAR)
+
+ call sprintf (Memc[patbuf], SZ_FNAME, "template %s")
+ call pargstr (pattern)
+
+ call strcpy (pattern, PATTERN(xh), SZ_FNAME)
+ call gmsg (XH_GP(xh), "directory", Memc[patbuf])
+ call gflush (XH_GP(xh))
+
+ call sfree (sp)
+end
+
+
+# XH_SELECTION -- Set the selected filename.
+
+procedure xh_selection (xh, selection)
+
+pointer xh #i task descriptor
+char selection[ARB] #i selection
+
+pointer sp, buf
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_FNAME, TY_CHAR)
+
+ call sprintf (Memc[buf], SZ_FNAME, "selection %s")
+ call pargstr (selection)
+
+ call gmsg (XH_GP(xh), "directory", Memc[buf])
+ call gflush (XH_GP(xh))
+ call sfree (sp)
+end
+
+
+# XH_ISDIR -- Test whether the named file is a directory. Check first to
+# see if it is a subdirectory of the current directory. If VFN is a directory,
+# return the OS pathname of the directory in pathname, and the number of
+# chars in the pathname as the function value. Otherwise return 0.
+
+int procedure xh_isdir (vfn, pathname, maxch)
+
+char vfn[ARB] # name to be tested
+char pathname[ARB] # receives path of directory
+int maxch # max chars out
+
+bool isdir
+pointer sp, fname, op
+int ip, fd, nchars, ch
+long file_info[LEN_FINFO]
+int finfo(), diropen(), gstrcpy(), strlen()
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_PATHNAME, TY_CHAR)
+
+ # Copy the VFN string, minus any whitespace on either end.
+ op = fname
+ for (ip=1; vfn[ip] != EOS; ip=ip+1) {
+ ch = vfn[ip]
+ if (!IS_WHITE (ch)) {
+ Memc[op] = ch
+ op = op + 1
+ }
+ }
+ Memc[op] = EOS
+
+ isdir = false
+ if (finfo (Memc[fname], file_info) != ERR) {
+ isdir = (FI_TYPE(file_info) == FI_DIRECTORY)
+
+ if (isdir) {
+ call fdirname (Memc[fname], pathname, maxch)
+ nchars = strlen (pathname)
+ }
+
+ } else {
+ # If we get here, the VFN is the name of a new file.
+ ifnoerr (fd = diropen (Memc[fname], 0)) {
+ call close (fd)
+ isdir = true
+ }
+ nchars = gstrcpy (Memc[fname], pathname, maxch)
+ }
+
+ call sfree (sp)
+ if (isdir)
+ return (nchars)
+ else {
+ pathname[1] = EOS
+ return (0)
+ }
+end
diff --git a/pkg/system/help/xhelp/xhelp.h b/pkg/system/help/xhelp/xhelp.h
new file mode 100644
index 00000000..24bffc71
--- /dev/null
+++ b/pkg/system/help/xhelp/xhelp.h
@@ -0,0 +1,89 @@
+# XHELP.H -- Include file for the XHELP GUI task.
+
+# Help database header structure. Stored at the beginning of a help
+# database file. This information is taken from the help$helpdb.x source.
+
+define LEN_HDBHEADER 14
+define HDB_MAGICVAL 110104B
+
+define HDB_MAGIC Memi[$1] # helpdb file type code
+define HDB_RAW Memi[$1+1] # access compiled or raw database
+define HDB_RHD Memi[$1+2] # if raw, HP of root help directory
+define HDB_INDEX Memi[$1+3] # index of root help directory
+define HDB_CRDATE Meml[$1+4] # creation date
+define HDB_NENTRIES Memi[$1+5] # number of help directories in db
+define HDB_MAXENTRIES Memi[$1+6] # maximum no. of help directories in db
+define HDB_NMODULES Memi[$1+7] # count of the total number of modules
+define HDB_INDEXOFFSET Meml[$1+8] # file offset of index, chars
+define HDB_INDEXPTR Memi[$1+9] # pointer to loaded index, ty_struct
+define HDB_INDEXLEN Memi[$1+10] # length of index structure, su
+define HDB_DATAOFFSET Meml[$1+11] # file offset of data area, chars
+define HDB_DATAPTR Memi[$1+12] # pointer to loaded data area, ty_struct
+define HDB_DATALEN Memi[$1+13] # length of data area, struct units
+
+# Index structure. Identifies the contents of the database and tells where
+# they are stored. There is one index entry for each help directory, i.e.,
+# for each package.
+
+define LEN_HDBINDEX 34
+define SZ_DBIKEY 63
+define LEN_DBIDATA 2
+
+define DBI_KEY Memc[P2C($1)] # entry name
+define DBI_OFFSET Memi[$1+32] # offset of entry into data area, su
+define DBI_MTIME Meml[$1+33] # modification date of entry
+
+define MAX_ENTRIES 100 # initial max db entries
+define INC_ENTRIES 50 # increment if overflow
+define MAX_DEPTH 20 # max nesting of packages
+define MAX_MENUSIZE 500 # max modules in a table
+define MAX_NAMELEN 20 # max chars in a module name in table
+
+
+# XHELP Macro definitions.
+define SZ_HELPLIST 20480
+define SZ_XHELPSTRUCT 45
+
+define XH_GP Memi[$1] # graphics descriptor
+define XH_LPTR Memi[$1+1] # ptr for pkg list
+define XH_TEMPLATE Memi[$1+2] # initial help topic
+define XH_OPTION Memi[$1+3] # help option
+define XH_PRINTER Memi[$1+4] # printer name
+define XH_CURTASK Memi[$1+5] # current task name
+define XH_CURPACK Memi[$1+6] # current package name
+define XH_QUICKREF Memi[$1+7] # quick-reference filen
+define XH_HOMEPAGE Memi[$1+8] # startup page
+define XH_CURDIR Memi[$1+9] # current directory
+define XH_PATTERN Memi[$1+10] # current filename template
+define XH_HELPDB Memi[$1+11] # help database string
+define XH_SHOWTYPE Memi[$1+12] # indicate packages in list
+define XH_STP Memi[$1+13] # package list symtab ptr
+
+# Helpful macros
+define LIST Memc[XH_LPTR($1)]
+define TEMPLATE Memc[XH_TEMPLATE($1)]
+define OPTION Memc[XH_OPTION($1)]
+define PRINTER Memc[XH_PRINTER($1)]
+define CURTASK Memc[XH_CURTASK($1)]
+define CURPACK Memc[XH_CURPACK($1)]
+define QUICKREF Memc[XH_QUICKREF($1)]
+define HOMEPAGE Memc[XH_HOMEPAGE($1)]
+define CURDIR Memc[XH_CURDIR($1)]
+define PATTERN Memc[XH_PATTERN($1)]
+define HELPDB Memc[XH_HELPDB($1)]
+
+define WIDE_PAGE 100 # needed by the print routines
+define SZ_DDSTR 256
+
+
+# Filenames.
+define HELP "lib$scr/help.html" # default help file
+define PKGFILE "uparm$help.pkgs" # default package list symtab
+define QREFFILE "uparm$quick.ref" # default references file
+
+
+# Symbol table definitions.
+define LEN_INDEX 10 # length of symtab index
+define LEN_STAB 32 # initial length of symtab
+define SZ_SBUF 32 # initial size of symtab string buffer
+
diff --git a/pkg/system/help/xhelp/xhelp.x b/pkg/system/help/xhelp/xhelp.x
new file mode 100644
index 00000000..95a2f250
--- /dev/null
+++ b/pkg/system/help/xhelp/xhelp.x
@@ -0,0 +1,167 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <syserr.h>
+include "../help.h"
+include "xhelp.h"
+
+
+# XHELP -- The main task procedure. XHELP is a GUI client program for
+# browsing the IRAF help system. As much as possible it uses the existing
+# help database code but provides a friendlier interface, allowing users to
+# browse packages for help pages in the same way they would browse packages
+# in the CL. It provides an HTML converter for LROFF sources for better
+# presentation in the GUI, as well as Postscript generation for better
+# looking hardcopy. XHelp acts as a server for the help system, merely
+# returning any output that the GUI has requested. Navigation is done in
+# the GUI code, this program maintains just the state of the last page
+# returned and knows nothing about how it got there. See the xhelp.hlp for
+# detailed documentation.
+
+procedure xhelp (topic)
+
+char topic[ARB] #I help template
+
+pointer xh
+char uifname[SZ_FNAME]
+int search, template
+
+pointer xh_open(), gopenui()
+bool clgetb()
+int btoi()
+
+begin
+ # Open structure and allocate pointers.
+ xh = xh_open ()
+ call strcpy (topic, TEMPLATE(xh), SZ_FNAME)
+
+ # Load the task parameters.
+ call clgstr ("option", OPTION(xh), SZ_FNAME)
+ call clgstr ("printer", PRINTER(xh), SZ_FNAME)
+ call clgstr ("quickref", QUICKREF(xh), SZ_FNAME)
+ XH_SHOWTYPE(xh) = btoi (clgetb("showtype"))
+ search = btoi (clgetb("search"))
+ template = btoi (clgetb("file_template"))
+
+ # Fetch the name of the help database.
+ call xh_ghelpdb (xh)
+
+ # Open the GUI.
+ call clgstr ("uifname", uifname, SZ_FNAME)
+ XH_GP(xh) = gopenui ("stdgraph", NEW_FILE, uifname, STDGRAPH)
+ call gflush (XH_GP(xh))
+
+ # Initialize the task and send topic list to the GUI.
+ call xh_init (xh, template, search)
+
+ # Initialize the task and send topic list to the GUI.
+ call xh_command_loop (xh)
+
+ # Clean up.
+ call gclose (XH_GP(xh))
+ call xh_close (xh)
+end
+
+
+# XH_OPEN -- Open and allocate the XHELP task structure.
+
+pointer procedure xh_open ()
+
+pointer xh # task descriptor
+errchk calloc
+
+begin
+ iferr (call calloc (xh, SZ_XHELPSTRUCT, TY_STRUCT))
+ call error (0, "Error opening task structure.")
+
+ iferr {
+ call calloc (XH_LPTR(xh), SZ_HELPLIST, TY_CHAR)
+ call calloc (XH_TEMPLATE(xh), SZ_FNAME, TY_CHAR)
+ call calloc (XH_OPTION(xh), SZ_FNAME, TY_CHAR)
+ call calloc (XH_PRINTER(xh), SZ_FNAME, TY_CHAR)
+ call calloc (XH_CURTASK(xh), SZ_FNAME, TY_CHAR)
+ call calloc (XH_CURPACK(xh), SZ_FNAME, TY_CHAR)
+ call calloc (XH_QUICKREF(xh), SZ_FNAME, TY_CHAR)
+ call calloc (XH_HOMEPAGE(xh), SZ_FNAME, TY_CHAR)
+ call calloc (XH_CURDIR(xh), SZ_PATHNAME, TY_CHAR)
+ call calloc (XH_PATTERN(xh), SZ_FNAME, TY_CHAR)
+ call calloc (XH_HELPDB(xh), SZ_HELPDB, TY_CHAR)
+ } then
+ call error (0, "Error allocating structure pointers.")
+
+ return (xh)
+end
+
+
+# XH_CLOSE -- Close the XHELP task structure.
+
+procedure xh_close (xh)
+
+pointer xh # task descriptor
+
+begin
+ call mfree (XH_TEMPLATE(xh), TY_CHAR)
+ call mfree (XH_OPTION(xh), TY_CHAR)
+ call mfree (XH_PRINTER(xh), TY_CHAR)
+ call mfree (XH_CURTASK(xh), TY_CHAR)
+ call mfree (XH_CURPACK(xh), TY_CHAR)
+ call mfree (XH_QUICKREF(xh), TY_CHAR)
+ call mfree (XH_HOMEPAGE(xh), TY_CHAR)
+ call mfree (XH_CURDIR(xh), TY_CHAR)
+ call mfree (XH_PATTERN(xh), TY_CHAR)
+ call mfree (XH_HELPDB(xh), TY_CHAR)
+ call mfree (XH_LPTR(xh), TY_CHAR)
+
+ call mfree (xh, TY_STRUCT)
+end
+
+
+# XH_GHELPDB -- Fetch the name of the help database, i.e., "helpdb",
+# "helpdir", or the name of a file. If the helpdb string is a list check
+# for the existance of each file in the list to ensure the final list
+# contains only valid help databases.
+
+procedure xh_ghelpdb (xh)
+
+pointer xh # task descriptor
+
+pointer sp, hdb, hdbstr, name
+int list
+int fntopnb(), fntgfnb()
+int access(), envgets()
+bool streq()
+
+begin
+ call smark (sp)
+ call salloc (name, SZ_FNAME, TY_CHAR)
+ call salloc (hdb, SZ_HELPDB, TY_CHAR)
+ call salloc (hdbstr, SZ_HELPDB, TY_CHAR)
+
+ # Clear the working memory.
+ call aclrc (Memc[name], SZ_FNAME)
+ call aclrc (Memc[hdb], SZ_HELPDB)
+ call aclrc (Memc[hdbstr], SZ_HELPDB)
+
+ # Get the parameter value.
+ call clgstr ("helpdb", Memc[hdbstr], SZ_HELPDB)
+ if (streq (Memc[hdbstr], "helpdb"))
+ if (envgets ("helpdb", Memc[hdbstr], SZ_HELPDB) <= 0)
+ call syserrs (SYS_ENVNF, "helpdb")
+
+ # Open the list.
+ list = fntopnb (Memc[hdbstr], YES)
+
+ # Copy each of the existing files in the list to the output database
+ # string to be used by the task.
+ while (fntgfnb(list, Memc[name], SZ_FNAME) != EOF) {
+ if (access (Memc[name], 0, 0) == YES) {
+ if (Memc[hdb] != EOS)
+ call strcat (",", Memc[hdb], SZ_HELPDB)
+ call strcat (Memc[name], Memc[hdb], SZ_HELPDB)
+ }
+ }
+ call strcpy (Memc[hdb], HELPDB(xh), SZ_HELPDB)
+
+ # Clean up.
+ call fntclsb (list)
+ call sfree (sp)
+end
diff --git a/pkg/system/help/xhelp/xhfiles.x b/pkg/system/help/xhelp/xhfiles.x
new file mode 100644
index 00000000..53597eda
--- /dev/null
+++ b/pkg/system/help/xhelp/xhfiles.x
@@ -0,0 +1,89 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <fset.h>
+include <ctype.h>
+include "../help.h"
+include "xhelp.h"
+
+
+# XH_FILES -- Get the files associated with the requested help topic,
+# i.e. do a "help <topic> opt=files" request.
+
+procedure xh_files (xh, topic, curpack)
+
+pointer xh #i task struct pointer
+char topic[ARB] #i help topic
+char curpack[ARB] #i current package
+
+pointer sp, bp, buf
+pointer opt, val, line
+int fd
+long fsize
+char fname[SZ_FNAME]
+
+long fstatl()
+int getline(), access(), open(), stridxs(), strlen()
+
+begin
+ if (topic[1] == EOS && curpack[1] == EOS)
+ return
+
+ call smark (sp)
+ call salloc (line, SZ_LINE, TY_CHAR)
+ call salloc (buf, SZ_FNAME, TY_CHAR)
+ call salloc (opt, SZ_FNAME, TY_CHAR)
+ call salloc (val, SZ_FNAME, TY_CHAR)
+
+ # Get a temp file name.
+ call mktemp ("tmp$xhelpi", fname, SZ_FNAME)
+
+ # Open a temp file with the help information found.
+ fd = open (fname, NEW_FILE, TEXT_FILE)
+ call xh_get_help (fd, topic, curpack, "", HF_HTML, HELPDB(xh),
+ "all", "files")
+ call close (fd)
+
+ # Open the results file for reading.
+ fd = open (fname, READ_ONLY, TEXT_FILE)
+ fsize = fstatl (fd, F_FILESIZE)
+
+ # If we got a result parse the lines for "opt=file" information.
+ if (fsize != 0) {
+
+ while (getline (fd, Memc[line]) != EOF) {
+
+ # Stomp the newline.
+ Memc[line+strlen(Memc[line])-1] = EOS
+
+ # Extract the option type and filename.
+ if (stridxs ("=", Memc[line]) > 0) {
+ for (bp=line; IS_WHITE(Memc[bp]); bp=bp+1)
+ ;
+ call strcpy (Memc[bp], Memc[opt], 3)
+ for (; Memc[bp] != '='; bp=bp+1)
+ ;
+ call strcpy (Memc[bp+1], Memc[val], SZ_FNAME)
+
+ # See if the file exists.
+ call sprintf (Memc[buf], SZ_FNAME, "%s %s \0")
+ call pargstr (Memc[opt])
+ call pargstr (Memc[val])
+ if (access (Memc[val],0,0) == YES)
+ call strcat (" 0", Memc[buf], SZ_FNAME)
+ else
+ call strcat (" 1", Memc[buf], SZ_FNAME)
+ call gmsg (XH_GP(xh), "helpfiles", Memc[buf])
+
+ } else if (stridxs (":", Memc[line]) > 0) {
+ call xh_pkgpath (xh, topic, curpack, Memc[line])
+ call sprintf (Memc[buf], SZ_FNAME, "file %s")
+ call pargstr (Memc[line])
+ call gmsg (XH_GP(xh), "helpfiles", Memc[buf])
+ }
+ }
+ }
+
+ call close (fd) # clean up
+ call delete (fname)
+ call sfree (sp)
+end
diff --git a/pkg/system/help/xhelp/xhhelp.x b/pkg/system/help/xhelp/xhhelp.x
new file mode 100644
index 00000000..708a00ce
--- /dev/null
+++ b/pkg/system/help/xhelp/xhhelp.x
@@ -0,0 +1,276 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <fset.h>
+include <finfo.h>
+include <error.h>
+include "../help.h"
+include "xhelp.h"
+
+
+# XH_HELP -- Get the requested help topic and send the result to the GUI.
+
+procedure xh_help (xh, topic, curpack, opt)
+
+pointer xh #i task struct pointer
+char topic[ARB] #i help topic
+char curpack[ARB] #i current package
+char opt[ARB] #i help option
+
+pointer helpstr
+int ip, fdi
+long fsize
+char ch, fname[SZ_FNAME], err[SZ_LINE]
+
+long fstatl()
+char getc()
+int open()
+bool strne()
+
+begin
+ # Get a temp file name.
+ call mktemp ("tmp$xhelpi", fname, SZ_FNAME)
+
+ # Open a temp file with the help information found.
+ fdi = open (fname, NEW_FILE, TEXT_FILE)
+ call xh_get_help (fdi, topic, curpack, "", HF_HTML, HELPDB(xh),
+ "all", opt)
+ call close (fdi)
+
+ # Open the results file for reading.
+ fdi = open (fname, READ_ONLY, TEXT_FILE)
+ fsize = fstatl (fdi, F_FILESIZE)
+
+ # If no results try using the topic name as a curpack param.
+ if (fsize == 0) {
+ call close (fdi) # clean up from before
+ call delete (fname)
+
+ # Open a temp file with the help information found.
+ fdi = open (fname, NEW_FILE, TEXT_FILE)
+ call xh_get_help (fdi, topic, topic, "", HF_HTML, HELPDB(xh),
+ "all", opt)
+ call close (fdi)
+
+ # Open the results file for reading.
+ fdi = open (fname, READ_ONLY, TEXT_FILE)
+ fsize = fstatl (fdi, F_FILESIZE)
+
+ # If we still have nothing then punt...
+ if (fsize == 0 && topic[1] != EOS) {
+ if (strne (opt, "help")) {
+ call sprintf (err, SZ_LINE,
+ "No '%s' option help available\n for `%s'.")
+ call pargstr (opt)
+ call pargstr (topic)
+ } else {
+ call sprintf (err, SZ_LINE, "No help available for\n`%s'.")
+ call pargstr (topic)
+ }
+ call gmsg (XH_GP(xh), "alert", err)
+ call close (fdi)
+ call delete (fname)
+ return
+ }
+ }
+
+ # Now filter the file to escape the curly braces so they pass thru
+ # to the Tcl cleanly. Put the result in the string sent to the GUI.
+ call calloc (helpstr, fsize + SZ_LINE, TY_CHAR)
+ ip = helpstr
+ repeat {
+ ch = getc (fdi, ch)
+ if (ch == '{' || ch == '}') {
+ Memc[ip] = '\\'
+ ip = ip + 1
+ }
+ Memc[ip] = ch
+ ip = ip + 1
+ } until (ch == EOF)
+ Memc[ip-1] = EOS
+
+ # Clean up.
+ call close (fdi)
+ call delete (fname)
+
+ # Send the help text to the GUI who will display it.
+ call gmsg (XH_GP(xh), "helpres", Memc[helpstr])
+ call mfree (helpstr, TY_CHAR)
+end
+
+
+# XH_GET_HELP -- The main work procedure, i.e. a rip-off of the t_help()
+# procedure. Decode the option string, set up the control structure, and
+# finally call process_template to expand the module template and process
+# the help text for each module. The output is written to a temp file
+# opened by the calling procedure which may optionally sort it or display
+# it as is.
+
+procedure xh_get_help (fd, topic, curpack, file, format, helpdb, section, opt)
+
+int fd #i file descriptor of result
+char topic[ARB] #i topic
+char curpack[ARB] #i current package
+char file[ARB] #i file template
+int format #i output format (text|html|ps)
+char helpdb[ARB] #i help database
+char section[ARB] #i section on which to get help
+char opt[ARB] #i type of help
+
+int list
+long fi[LEN_FINFO], db_ctime
+pointer sp, ctrl, optn, db, fname
+
+long clktime()
+pointer hdb_open()
+bool strne(), streq()
+int stridxs(), finfo(), fntopnb(), fntgfnb(), get_option()
+
+errchk hdb_open
+
+data db_ctime /0/
+define forms_ 91
+
+begin
+ call smark (sp)
+ call salloc (ctrl, LEN_CTRLSTRUCT, TY_STRUCT)
+ call salloc (optn, SZ_FNAME, TY_CHAR)
+ call salloc (fname, SZ_PATHNAME, TY_CHAR)
+
+ # If we were called without any arguments, do not query for the
+ # template, just set it to null and help will be given for the
+ # current package.
+
+ call aclri (Memi[ctrl], LEN_CTRLSTRUCT)
+ if (topic[1] == EOS) {
+ if (file[1] == EOS) {
+ H_OPTION(ctrl) = O_MENU
+ H_TEMPLATE(ctrl) = EOS
+ H_PARNAME(ctrl) = EOS
+ H_SECNAME(ctrl) = EOS
+ } else
+ call strcpy (file, H_TEMPLATE(ctrl), SZ_LINE)
+ } else {
+ call strcpy (topic, H_TEMPLATE(ctrl), SZ_LINE)
+ }
+
+
+ # Check to see if any of the files in the list are newer than the
+ # time of the last hdb_open. The first time the process runs we open
+ # and read in the database. The database remains in memory between
+ # calls to HELP, provided the process does not shutdown, provided
+ # the name of the database to be used does not change, and provided
+ # a new help database is not created.
+
+ if (db_ctime > 0) {
+ list = fntopnb (helpdb, YES)
+ while (fntgfnb (list, Memc[fname], SZ_PATHNAME) != EOF) {
+ if (finfo (Memc[fname], fi) != ERR) {
+ if (db != NULL && FI_CTIME(fi) > db_ctime) {
+ call hdb_close (db)
+ db = NULL
+ break
+ }
+ }
+ }
+ call fntclsb (list)
+ } else
+ db = NULL
+
+ # Reopen the help database if in-core copy is out of date.
+ if (db == NULL) {
+ db = hdb_open (helpdb)
+ db_ctime = clktime (long(0))
+ }
+
+ # Fetch the value of the ALL switch. This determines whether help
+ # will stop after processing the first module matching the template,
+ # or process all modules in the database which match the template.
+ # Explicit use of a pattern matching character anywhere in the template
+ # enable allmodoules.
+
+ if (stridxs ("*?[],", H_TEMPLATE(ctrl)) > 0)
+ H_ALLMODULES(ctrl) = YES
+ else
+ H_ALLMODULES(ctrl) = NO
+
+ # If the FILTER_INPUT flag is set, only part of the input text will be
+ # processed. Filtering is only done if printing a single section or
+ # parameter.
+
+ H_FILTER_INPUT(ctrl) = NO
+
+ # Determine whether or not text for a single section or parameter
+ # is to be output. If the value of one of these strings is "all",
+ # all sections or all parameters are to be output. If the "all"
+ # default is in effect, null the string as a flag to lower level
+ # code that all help text is to be processed.
+
+ if (H_OPTION(ctrl) == NULL) {
+ call strcpy (section, H_SECNAME(ctrl), SZ_SECNAME)
+ if (streq (H_SECNAME(ctrl), "all")) {
+ H_SECNAME(ctrl) = EOS
+ H_PARNAME(ctrl) = EOS
+ }
+ if (H_SECNAME(ctrl) != EOS || H_PARNAME(ctrl) != EOS)
+ H_FILTER_INPUT(ctrl) = YES
+ }
+
+ # Fetch and decode option string; abbreviations are permitted.
+ if (H_OPTION(ctrl) != O_MENU) {
+ call strcpy (opt, Memc[optn], SZ_FNAME)
+ call strlwr (Memc[optn])
+ iferr (H_OPTION(ctrl) = get_option (Memc[optn])) {
+ H_OPTION(ctrl) = O_HELP
+ call erract (EA_WARN)
+ }
+ }
+
+forms_
+ # Pause between screens of output text only if the standard output
+ # is not redirected, and if enabled by the user.
+
+ H_IN(ctrl) = ERR
+ H_OUT(ctrl) = fd
+ H_NLINES(ctrl) = -1
+ H_STATE(ctrl) = BOF
+ H_EOF(ctrl) = NO
+ H_QUIT(ctrl) = NO
+
+ # If the standard output is not redirected, i.e., if writing to the
+ # terminal, determine whether or not output is to be paginated (pause
+ # between pages). If output is redirected, the pagination flag
+ # and help option controls whether or not manpage style output is
+ # enabled. Manpage output formatting is desirable only when formatting
+ # help text or printing named files.
+
+ H_RAWOUT(ctrl) = YES
+ H_MANPAGE(ctrl) = NO
+ H_PAGINATE(ctrl) = NO
+ H_SOFLAG(ctrl) = NO
+ H_FORMAT(ctrl) = format
+
+ # We don't produce output to a screen so shut off the tty.
+
+ H_TTY(ctrl) = NULL
+
+ # Set left and right margins for output text format.
+
+ H_LMARGIN(ctrl) = 1
+ H_RMARGIN(ctrl) = 72
+
+ # Copy the current package to the control struct.
+ if (strne(curpack,"Home") && strne(curpack,""))
+ call strcpy (curpack, H_CURPACK(ctrl), SZ_CURPACK)
+
+ # Initialization is completed, control structure is completed.
+ # Format and output the help text. If we have a module name template
+ # process the template against the help database, otherwise work
+ # directly out of the named files.
+
+ if (file[1] == EOS)
+ call do_module_template (db, H_TEMPLATE(ctrl), ctrl)
+ else
+ call do_file_template (H_TEMPLATE(ctrl), ctrl)
+
+ call sfree (sp)
+end
diff --git a/pkg/system/help/xhelp/xhinit.x b/pkg/system/help/xhelp/xhinit.x
new file mode 100644
index 00000000..41ff5b65
--- /dev/null
+++ b/pkg/system/help/xhelp/xhinit.x
@@ -0,0 +1,77 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "xhelp.h"
+
+
+# XH_INIT -- Initialize the task and the GUI.
+
+procedure xh_init (xh, file_template, search)
+
+pointer xh #i task struct pointer
+int file_template #i is topic a file template?
+int search #i doing a search?
+
+char curdir[SZ_FNAME]
+int fd
+
+pointer strestore()
+int envgets(), open()
+bool streq()
+errchk open
+
+begin
+ # Update the quickref file.
+ call xh_updt_quickref (xh)
+
+ # If starting up with a search, get that information first.
+ if (search == YES && TEMPLATE(xh) != EOS) {
+ call xh_search (xh, NO, TEMPLATE(xh))
+ call strcpy ("", TEMPLATE(xh), SZ_FNAME)
+ call strcpy ("", LIST(xh), SZ_LINE)
+ }
+
+ # Create the root package and send the results to the GUI.
+ call xh_root_pkg (xh)
+ call gmsg (XH_GP(xh), "pkglist", LIST(xh))
+
+ # Initialize the package list symtab.
+ iferr (fd = open (PKGFILE, READ_ONLY, BINARY_FILE))
+ call error (0, "Cannot open package list symtab")
+ XH_STP(xh) = strestore (fd)
+ call close (fd)
+ call gmsgi (XH_GP(xh), "showtype", XH_SHOWTYPE(xh))
+
+
+ if (TEMPLATE(xh) != EOS && file_template == NO) {
+ # If we're given an initial help topic, get the page and load it.
+ #call xh_help (xh, TEMPLATE(xh), TEMPLATE(xh), OPTION(xh))
+ call xh_cmd_help (xh, TEMPLATE(xh), "{}", OPTION(xh))
+ call strcpy ("", TEMPLATE(xh), SZ_FNAME)
+
+ } else if (TEMPLATE(xh) != EOS && file_template == YES) {
+ # Load a user defined page.
+ call xh_open_file (xh, "helpres", TEMPLATE(xh), YES, YES)
+ call strcpy ("", TEMPLATE(xh), SZ_FNAME)
+
+ } else {
+ # Load either a user defined homepage or the task help.
+ call clgstr ("home", HOMEPAGE(xh), SZ_FNAME)
+ if (streq ("", HOMEPAGE(xh)))
+ call strcpy (HELP, HOMEPAGE(xh), SZ_FNAME)
+ call xh_open_file (xh, "helpres", HOMEPAGE(xh), NO, YES)
+ }
+
+ # Set the printer to be used.
+ call gmsg (XH_GP(xh), "printer", PRINTER(xh))
+
+ # Initialize the online help doc.
+ call xh_open_file (xh, "help", HELP, NO, YES)
+
+ # Initialize the file browsing parameters. Since we can't
+ # get the current directory for the session use home$.
+ if (envgets ("home", curdir, SZ_FNAME) != EOF) {
+ call xh_set_pattern (xh, "*")
+ call xh_set_curdir (xh, curdir)
+ call xh_dirlist (xh, CURDIR(xh), PATTERN(xh))
+ }
+end
diff --git a/pkg/system/help/xhelp/xhofile.x b/pkg/system/help/xhelp/xhofile.x
new file mode 100644
index 00000000..c12ea7d3
--- /dev/null
+++ b/pkg/system/help/xhelp/xhofile.x
@@ -0,0 +1,188 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <fset.h>
+include "xhelp.h"
+
+
+# XH_OPEN_FILE -- Open the named file and send it to the GUI. If this is
+# a help document (i.e. it contains a ".help" block) we first convert it
+# to HTML, otherwise send it as is.
+
+procedure xh_open_file (xh, parameter, filename, check_for_help, warn)
+
+pointer xh # task descriptor
+char parameter[ARB] # GUI parameter to notify
+char filename[ARB] # file to open
+int check_for_help # check file for help block?
+int warn # warn if not present?
+
+pointer sp, ip, buf, out, text
+int fdi, fdo
+long fsize
+bool has_help
+
+int access(), open(), getline()
+int strmatch(), gstrcpy()
+long fstatl()
+errchk open
+
+define err_ 99
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+ call salloc (out, SZ_FNAME, TY_CHAR)
+
+ # Make sure the file exists.
+ if (access (filename, 0, 0) == NO) {
+ if (warn == YES) {
+ call sprintf (Memc[buf], SZ_LINE, "File does not exist:\n`%s'.")
+ call pargstr (filename)
+ call gmsg (XH_GP(xh), "alert", Memc[buf])
+ }
+ goto err_
+ } else if (access (filename, 0, BINARY_FILE) == YES) {
+ if (warn == YES) {
+ call sprintf (Memc[buf], SZ_LINE,
+ "Attempt to load binary file:\n`%s'.")
+ call pargstr (filename)
+ call gmsg (XH_GP(xh), "alert", "pop")
+ call gmsg (XH_GP(xh), "alert", Memc[buf])
+ }
+ goto err_
+ }
+
+ # If we're told not to look for help simply open the file and send
+ # it to the GUI (e.g. used for homepage and online help).
+ if (check_for_help == NO) {
+ call xh_load_file (xh, parameter, filename)
+ call sfree (sp)
+ return
+ }
+
+ # Open the file.
+ iferr (fdi = open (filename, READ_ONLY, TEXT_FILE)) {
+ if (warn == YES) {
+ call sprintf (Memc[buf], SZ_LINE, "Cannot open file\n`%s'.")
+ call pargstr (filename)
+ call gmsg (XH_GP(xh), "alert", Memc[buf])
+ }
+ goto err_
+ }
+
+ # Allocate an array the length of the file, if this isn't a help file
+ # we use this as the message buffer and send it to the GUI.
+ fsize = fstatl (fdi, F_FILESIZE)
+ call salloc (text, fsize+1, TY_CHAR)
+ call aclrc (Memc[text], fsize+1)
+
+ # See whether this is a help file
+ has_help = FALSE
+ ip = text
+ while (getline (fdi, Memc[buf]) != EOF) {
+ if (strmatch (Memc[buf], "^.help") > 0) {
+ has_help = TRUE
+ break
+ }
+ ip = ip + gstrcpy (Memc[buf], Memc[ip], SZ_LINE)
+ }
+ Memc[ip] = EOS
+
+
+ # If the file was found to have a .help block we're positioned at
+ # the beginning of the block. Convert the remainder to an HTML
+ # temp file and send that to the GUI, otherwise we already have the
+ # contents of the file in the text buffer so send that.
+ if (has_help) {
+ # Create an output filename and open it for writing.
+ call mktemp ("tmp$xhelpi", Memc[out], SZ_FNAME)
+ fdo = open (Memc[out], NEW_FILE, TEXT_FILE)
+
+ # Convert the remainder to HTML and send it to the GUI.
+ if (fdo != ERR) {
+ call lroff2html (fdi, fdo, filename, "", "", "", "")
+ call close (fdo)
+
+ call xh_load_file (xh, "helpres", Memc[out])
+ call delete (Memc[out])
+ }
+
+ } else {
+ # No help was found, send the contents straight to the display.
+ call xh_text_msg (XH_GP(xh), "helpres", Memc[text])
+ }
+
+
+err_ if (fdi != ERR)
+ call close (fdi)
+ call sfree (sp)
+end
+
+
+# XH_LOAD_FILE -- Load the named file in the GUI.
+
+procedure xh_load_file (xh, parameter, filename)
+
+pointer xh # task descriptor
+char parameter[ARB] # GUI parameter to notify
+char filename[ARB] # file to display
+
+pointer sp, ip, line, text
+int fd, open(), getline(), gstrcpy()
+long fsize, fstatl()
+errchk open
+
+begin
+ call smark (sp)
+ call salloc (line, SZ_LINE, TY_CHAR)
+
+ # Open the file and send it to the display.
+ fd = open (filename, READ_ONLY, TEXT_FILE)
+ if (fd != ERR) {
+ fsize = fstatl (fd, F_FILESIZE)
+ call salloc (text, fsize+1, TY_CHAR)
+ call aclrc (Memc[text], fsize+1)
+
+ for (ip=text; getline (fd, Memc[line]) != EOF; )
+ ip = ip + gstrcpy (Memc[line], Memc[ip], SZ_LINE)
+
+ Memc[ip] = EOS
+ call close (fd)
+
+ call xh_text_msg (XH_GP(xh), parameter, Memc[text])
+ }
+
+ call sfree (sp)
+end
+
+
+# XH_TEXT_MSG -- Send a text message to a named UI parameter but first
+# escape all curly braces so it passes through the Tcl correctly.
+
+procedure xh_text_msg (gp, param, msg)
+
+pointer gp
+char param[ARB], msg[ARB]
+
+pointer buf, ip
+int i, nchars
+int strlen()
+
+begin
+ nchars = strlen (msg)
+ call calloc (buf, nchars + SZ_LINE, TY_CHAR)
+
+ ip = buf
+ for (i=1; i < nchars; i=i+1) {
+ if (msg[i] == '{' || msg[i] == '}') {
+ Memc[ip] = '\\'
+ ip = ip + 1
+ }
+ Memc[ip] = msg[i]
+ ip = ip + 1
+ }
+
+ call gmsg (gp, "type", "file")
+ call gmsg (gp, param, Memc[buf])
+ call mfree (buf, TY_CHAR)
+end
diff --git a/pkg/system/help/xhelp/xhpkg.x b/pkg/system/help/xhelp/xhpkg.x
new file mode 100644
index 00000000..44580f15
--- /dev/null
+++ b/pkg/system/help/xhelp/xhpkg.x
@@ -0,0 +1,192 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <fset.h>
+include <error.h>
+include "../help.h"
+include "../helpdir.h"
+include "xhelp.h"
+
+
+# XH_GPKGLIST -- Get the requested package list as a sorted array of pointers.
+# This is essentially a "help <pkg>" request, the caller passes the sorted
+# list returned in 'pkglist" required.
+
+int procedure xh_pkglist (xh, topic, helpdb, pkglist)
+
+pointer xh #i task descriptor pointer
+char topic[ARB] #i search key
+char helpdb[ARB] #i filename of database to be examined
+char pkglist[ARB] #o package list
+
+int i, m
+pointer sp, pknm, hp, pp, sym
+pointer db, ixoff, ix
+
+bool strne()
+int gstrcpy(), strsearch(), hd_getname()
+pointer hdb_open(), hdb_load(), stfind()
+errchk hdb_open, hdb_printpack, hdb_load
+
+begin
+ call smark (sp)
+ call salloc (pknm, MAX_MENUSIZE, TY_POINTER)
+
+ db = hdb_open (helpdb)
+ ixoff = HDB_INDEXPTR(db)
+ pp = NULL
+
+ # Search for the right topic.
+ do i = 1, HDB_NENTRIES(db) {
+ ix = ixoff + (i - 1) * LEN_HDBINDEX
+ if (strne (DBI_KEY(ix), "_index") &&
+ strsearch (DBI_KEY(ix),topic) != 0) {
+
+ iferr (hp = hdb_load (db, DBI_KEY(ix))) {
+ call sfree (sp)
+ call erract (EA_WARN)
+ return (0)
+ }
+
+ # If this isn't the package we're after then move on.
+ if (HD_PAKNAME(hp) == 0 ||
+ strne (topic, Memc[HD_SBUF(hp)+HD_PAKNAME(hp)]))
+ next
+
+ # Extract the names of the modules in the package. Save the
+ # pointers in an array for the table print routine.
+
+ pp = 1
+ for (m=0; m < MAX_MENUSIZE; m=m+1) {
+ call salloc (Memi[pknm+m], MAX_NAMELEN, TY_CHAR)
+ if (hd_getname (hp, m+1, TY_MODNAME, Memc[Memi[pknm+m]],
+ MAX_NAMELEN) <= 0)
+ break
+
+ # Copy the names to the output array.
+ pp = pp + gstrcpy (Memc[Memi[pknm+m]], pkglist[pp], ARB)
+ if (XH_SHOWTYPE(xh) == YES && XH_STP(xh) != NULL) {
+ sym = stfind (XH_STP(xh), Memc[Memi[pknm+m]])
+ if (sym != NULL)
+ pp = pp + gstrcpy (".", pkglist[pp], ARB)
+ }
+ pp = pp + gstrcpy (" ", pkglist[pp], ARB)
+ }
+ break
+ }
+ }
+ if (pp != NULL)
+ pkglist[pp] = EOS
+
+ call hdb_free (db, hp)
+ call hdb_close (db)
+ call sfree (sp)
+ return (pp)
+end
+
+
+# XH_PKGPATH -- Get the package path associated with a particular task.
+# If we're given a parent package follow it back so we get the correct
+# path for a task that may be defined multiple places (e.g. SPLOT).
+
+procedure xh_pkgpath (xh, topic, curpack, path)
+
+pointer xh #i task struct pointer
+char topic[ARB] #i help topic
+char curpack[ARB] #i help topic
+char path[ARB] #o package path
+
+pointer sp, pkg, task, buf
+int strncmp(), xh_pkgname()
+bool streq()
+
+begin
+ call smark (sp)
+ call salloc (pkg, SZ_FNAME, TY_CHAR)
+ call salloc (task, SZ_FNAME, TY_CHAR)
+ call salloc (buf, SZ_FNAME, TY_CHAR)
+
+ if (curpack[1] == EOS ||
+ streq (topic, curpack) ||
+ strncmp ("root", curpack, 4) == 0 ||
+ streq ("clpackage", curpack)) {
+ call strcpy (topic, Memc[task], SZ_FNAME)
+ call strcpy (topic, path, SZ_FNAME)
+ } else {
+ call strcpy (curpack, Memc[task], SZ_FNAME)
+ call sprintf (path, SZ_PATHNAME, "%s.%s")
+ call pargstr (curpack)
+ call pargstr (topic)
+ }
+
+ Memc[pkg] = EOS
+ while (xh_pkgname (xh, Memc[task], Memc[pkg]) == OK) {
+ if (strncmp ("root", Memc[pkg], 4) == 0 ||
+ streq (Memc[task], Memc[pkg]) ||
+ streq ("clpackage", Memc[pkg]))
+ break
+ else {
+ call sprintf (Memc[buf], SZ_PATHNAME, "%s.%s")
+ call pargstr (Memc[pkg])
+ call pargstr (path)
+ call strcpy (Memc[buf], path, SZ_PATHNAME)
+ }
+ call strcpy (Memc[pkg], Memc[task], SZ_FNAME)
+ Memc[pkg] = EOS
+ }
+
+ call sfree (sp)
+end
+
+
+# XH_PKGNAME -- Get the package name associated with a particular task.
+
+int procedure xh_pkgname (xh, topic, pack)
+
+pointer xh #i task struct pointer
+char topic[ARB] #i help topic
+char pack[ARB] #o package
+
+pointer sp, line, fname
+long fsize, fstatl()
+int fd, status, getline(), open(), stridxs()
+
+begin
+ call smark (sp)
+ call salloc (line, SZ_LINE, TY_CHAR)
+ call salloc (fname, SZ_LINE, TY_CHAR)
+
+ status = ERR
+
+ # Get a temp file name.
+ call mktemp ("tmp$xhelpi", Memc[fname], SZ_FNAME)
+
+ # Open a temp file with the help information found.
+ fd = open (Memc[fname], NEW_FILE, TEXT_FILE)
+ call xh_get_help (fd, topic, "", "", HF_HTML, HELPDB(xh),
+ "all", "files")
+ call close (fd)
+
+ # Open the results file for reading.
+ fd = open (Memc[fname], READ_ONLY, TEXT_FILE)
+ fsize = fstatl (fd, F_FILESIZE)
+
+ # Search the results for the package line.
+ if (fsize != 0) {
+ status = OK
+ while (getline (fd, Memc[line]) != EOF) {
+
+ # Extract the package name.
+ if (stridxs (":", Memc[line]) > 0) {
+ Memc[line+stridxs(".",Memc[line])-1] = EOS
+ call strcpy (Memc[line], pack, SZ_FNAME)
+ break
+ }
+ }
+ }
+
+ call close (fd) # clean up
+ call delete (Memc[fname])
+ call sfree (sp)
+
+ return (status)
+end
diff --git a/pkg/system/help/xhelp/xhprint.x b/pkg/system/help/xhelp/xhprint.x
new file mode 100644
index 00000000..4e273848
--- /dev/null
+++ b/pkg/system/help/xhelp/xhprint.x
@@ -0,0 +1,151 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <syserr.h>
+include <error.h>
+include <ctype.h>
+include <ttyset.h>
+include "../help.h"
+include "xhelp.h"
+
+
+# XH_PRINT_HELP -- Print the requested help topic.
+
+procedure xh_print_help (xh, topic, curpack, name)
+
+pointer xh #i task struct pointer
+char topic[ARB] #i help topic
+char curpack[ARB] #i current package
+char name[ARB] #i printer name
+
+int fd
+char fname[SZ_FNAME]
+
+int open()
+errchk open
+
+begin
+ # Open a temp file with the help information.
+ call mktemp ("tmp$xhelpi", fname, SZ_FNAME)
+ fd = open (fname, NEW_FILE, TEXT_FILE)
+ call xh_get_help (fd, topic, curpack, "", HF_PS, HELPDB(xh),
+ "all", OPTION(xh))
+ call close (fd)
+
+ call strcpy (name, PRINTER(xh), SZ_FNAME)
+ call xh_lprint (fname, PRINTER(xh))
+
+ # Clean up.
+ call delete (fname)
+end
+
+
+# XH_LPRINT -- Print a file or files on the lineprinter. TTYPUTLINE is used
+# to output lines to the printer file, so that formfeeds, standout mode, etc.,
+# may be properly translated for the indicated device.
+
+procedure xh_lprint (fname, device)
+
+char fname[ARB]
+char device[ARB]
+
+int out
+pointer sp, lp, ddstr
+
+pointer ttyodes()
+bool streq()
+int envgets(), lpopen(), ttygets()
+string printer "printer"
+errchk clgfil, xh_print_file
+
+begin
+ call smark (sp)
+ call salloc (ddstr, SZ_DDSTR, TY_CHAR)
+
+ # Get device name. Default is "printer", which means that the actual
+ # device name is given by the environment variable "printer".
+
+ if (streq (device, printer))
+ if (envgets (printer, device, SZ_FNAME) <= 0)
+ call syserrs (SYS_ENVNF, printer)
+
+ # Open TTY descriptor and printer file. We deal only with character
+ # data, so open printer as a text file. Output the files to the line
+ # printer device.
+
+ lp = ttyodes (device)
+ if (ttygets (lp, "DD", Memc[ddstr], SZ_DDSTR) <= 0)
+ call error (1, "missing 'DD' parameter in termcap entry")
+
+ out = lpopen (Memc[ddstr], APPEND, TEXT_FILE)
+
+ # Output file, followed by a form feed.
+ iferr {
+ call xh_print_file (out, lp, fname)
+ call flush (out)
+ } then
+ call erract (EA_WARN)
+
+ call close (out)
+ call ttycdes (lp)
+ call sfree (sp)
+end
+
+
+# XH_PRINT_FILE -- Open and print the named text file on the output file,
+# under control of the tty device descriptor LP. Print a header on each
+# page if enabled, and formfeed at the end of the file. The number of lines
+# per page is given by the tty descriptor.
+
+procedure xh_print_file (out, lp, fname)
+
+int out
+pointer lp
+char fname[ARB]
+
+bool one_tab_in
+int lineno, maxlines, status, in
+pointer sp, ip, lbuf
+int open(), getline(), ttystati()
+errchk salloc, open, ttystati, getline, ttyputline
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LINE+1, TY_CHAR)
+
+ in = open (fname, READ_ONLY, TEXT_FILE)
+ maxlines = ttystati (lp, TTY_NLINES)
+
+ # If printer page is very wide, set page in one tabstop from left
+ # margin.
+
+ one_tab_in = (ttystati (lp, TTY_NCOLS) > WIDE_PAGE)
+ if (one_tab_in) {
+ Memc[lbuf] = '\t'
+ ip = lbuf + 1
+ } else
+ ip = lbuf
+
+
+ # Format and write each page of output. If headers are enabled,
+ # output formfeed and header between pages.
+
+ status = OK
+ while (status != EOF) {
+ # Output one page of text. Each output line is processed by
+ # ttyputline to expand tabs, underline, etc.
+
+ for (lineno=1; lineno <= maxlines; lineno=lineno+1) {
+ status = getline (in, Memc[ip])
+ if (status == EOF)
+ break
+ if (Memc[ip] == '\f') {
+ call ttyputline (out, lp, "\f", YES)
+ call strcpy (Memc[ip+1], Memc[ip], SZ_LINE)
+ }
+ call ttyputline (out, lp, Memc[lbuf], YES)
+ }
+ }
+
+ call close (in)
+ call sfree (sp)
+end
diff --git a/pkg/system/help/xhelp/xhqref.x b/pkg/system/help/xhelp/xhqref.x
new file mode 100644
index 00000000..51912169
--- /dev/null
+++ b/pkg/system/help/xhelp/xhqref.x
@@ -0,0 +1,250 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <syserr.h>
+include <finfo.h>
+include <ctype.h>
+include "../help.h"
+include "xhelp.h"
+
+define MAX_PKGS 200
+define SZ_PKG 32
+define EXTPKG "hlib$extern.pkg"
+
+
+# XH_UPDT_QUICKREF -- Update a quick reference file for the help database
+# if needed.
+
+procedure xh_updt_quickref (xh)
+
+pointer xh
+
+long fiq[LEN_FINFO], fie[LEN_FINFO]
+
+int access()
+long finfo()
+errchk access, finfo
+
+begin
+ # If the quickref file exists, and it is older than the
+ # hlib$extern.pkg file which defines the helpdb rebuild
+ # the quickref file so we're current, otherwise rebuild
+ # the quickref file anyway.
+ if ((access (QUICKREF(xh), 0, 0) == NO) ||
+ (access (PKGFILE, 0, 0) == NO)) {
+ call xh_make_quickref (xh, QUICKREF(xh))
+ } else {
+ if (finfo (QUICKREF(xh), fiq) == ERR)
+ call filerr (QUICKREF(xh), SYS_FOPNNEXFIL)
+ if (finfo (EXTPKG, fie) == ERR)
+ call filerr (EXTPKG, SYS_FOPNNEXFIL)
+
+ if (FI_MTIME[fie] > FI_MTIME[fiq]) {
+ call delete (QUICKREF(xh))
+ call xh_make_quickref (xh, QUICKREF(xh))
+ }
+ }
+end
+
+
+# XH_MAKE_QUICKREF -- Make a quick reference file for the help database.
+
+procedure xh_make_quickref (xh, quickref)
+
+pointer xh #i task struct pointer
+char quickref[ARB] #i quickref filename
+
+pointer pkglist, pp
+int fdi, fdo, fd_err
+int sz_pbuf, npkgs
+char fname[SZ_FNAME], efname[SZ_FNAME]
+char pkg[SZ_PKG], lastpkg[SZ_PKG], line[SZ_LINE]
+
+int open(), access(), getline(), gstrcpy(), strsearch(), strcmp()
+errchk open
+
+begin
+ # Tell the GUI we're actually busy doing something....
+ call gmsg (XH_GP(xh), "alert",
+ "Please wait,\ngenerating QuickRef file...")
+ call gflush (XH_GP(xh))
+
+ # Open the STDERR stream onto a dummy file to catch any
+ # "no help available" messages that may interfere with the
+ # textout GUI parameter.
+ call mktemp ("tmp$xerr", efname, SZ_FNAME)
+ fd_err = open (efname, NEW_FILE, TEXT_FILE)
+ call frediro (STDERR, fd_err)
+
+ # Open a temp file with the raw search information.
+ call mktemp ("tmp$xhelpq", fname, SZ_FNAME)
+ fdi = open (fname, NEW_FILE, TEXT_FILE)
+
+ call xh_get_help (fdi, "[a-z]*.", "", "", HF_HTML, HELPDB(xh), "help",
+ "references")
+ call close (fdi)
+
+ # Close the error file, swap back the descriptors first and delete it.
+ call fswapfd (STDERR, fd_err)
+ call close (fd_err)
+ call delete (efname)
+
+ # Delete existing files.
+ if (access (quickref, 0, 0) == YES)
+ call delete (quickref)
+
+ # Open the references file.
+ iferr (fdo = open (quickref, NEW_FILE, TEXT_FILE)) {
+ call sprintf (line, SZ_LINE, "Cannot create quickref file `%s'.")
+ call pargstr (quickref)
+ call error (0, line)
+ }
+ fdi = open (fname, READ_ONLY, TEXT_FILE)
+
+ # Initialize for the package list.
+ pkg[1] = EOS
+ lastpkg[1] = EOS
+ npkgs = 0
+ sz_pbuf = MAX_PKGS * SZ_PKG
+ call malloc (pkglist, sz_pbuf, TY_CHAR)
+ pp = pkglist
+
+ # Loop over the lines in the file, save the ones that are the
+ # descriptions. Descriptions are assumed to contain a '-' since
+ # this is standard for .men files, to be safe we also required
+ # the bracketed package name generated with a 'references' query.
+ # The package name is used to create the package list symtab we
+ # use to show the item as a task or package.
+
+ while (getline(fdi,line) != EOF) {
+ if (strsearch (line, " - ") != 0 && strsearch (line, "[") != 0) {
+ call putline (fdo, line)
+
+ # Extract the package name. The results aren't sorted at
+ # this point so we see whether this package is the same as
+ # the last before adding it to the package list. This
+ # gives us a unique list of unsorted package names.
+
+ call xh_gname (line, pkg)
+ if (lastpkg[1] == EOS)
+ call strcpy (pkg, lastpkg, SZ_PKG)
+ if (strcmp (pkg, lastpkg) != 0) {
+ npkgs = npkgs + 1
+
+ # Protect against overflowing the buffer.
+ if ((pp - pkglist) > sz_pbuf)
+ call error (1, "Package buffer overflow.")
+
+ pp = pp + gstrcpy (pkg, Memc[pp], SZ_PKG)
+ pp = pp + gstrcpy (" ", Memc[pp], SZ_PKG)
+ call strcpy (pkg, lastpkg, SZ_PKG)
+ }
+ }
+ }
+ Memc[pp] = EOS
+
+ # Close the new references file.
+ call close (fdo)
+
+ # Close and delete the references temp files.
+ call close (fdi)
+ call delete (fname)
+
+ # Sort the lines of the references file.
+ call xh_file_sort (quickref)
+
+ # Now send the package list off to be stored for the next time.
+ call xh_make_pkglist (Memc[pkglist])
+
+ call mfree (pkglist, TY_CHAR)
+
+ # Tell the GUI we're done.
+ call gmsg (XH_GP(xh), "alert", "dismiss")
+ call gflush (XH_GP(xh))
+end
+
+
+# XH_MAKE_PKGLIST -- Update the package symtab file. We are only called
+# when updating the quickref database so delete any existing file before
+# writing the new one.
+
+procedure xh_make_pkglist (list)
+
+char list[ARB] #i package list
+
+pointer sp, err, pkg
+pointer stp, sym
+int i, ip, fd
+
+pointer stopen(), stenter()
+int open(), access(), strlen()
+errchk open
+
+begin
+ call smark (sp)
+ call salloc (err, SZ_LINE, TY_CHAR)
+ call salloc (pkg, SZ_FNAME, TY_CHAR)
+
+ # Delete existing files.
+ if (access(PKGFILE,0,0) == YES)
+ call delete (PKGFILE)
+
+ # Open the package symtab file.
+ iferr (fd = open (PKGFILE, NEW_FILE, BINARY_FILE)) {
+ call sprintf (Memc[err], SZ_LINE, "Can't create pkg symtab `%s'.")
+ call pargstr (PKGFILE)
+ call error (0, Memc[err])
+ }
+
+ # Sort the list before making the symtab.
+ call xh_sort_list (list)
+
+ # Open the symtab.
+ stp = stopen ("package list", LEN_INDEX, LEN_STAB, SZ_SBUF)
+
+ # Enter strings in the symtab.
+ i = 0
+ for (ip=1; list[ip] != EOS; ip=ip+1) {
+ if (list[ip] == ' ') {
+ Memc[pkg+i] = EOS
+ sym = stenter (stp, Memc[pkg], strlen (Memc[pkg]) + 1)
+ i = 0
+ ip = ip + 1
+ }
+ Memc[pkg+i] = list[ip]
+ i = i + 1
+ }
+
+ # Save the symtab file.
+ call stsqueeze (stp)
+ call stsave (stp, fd)
+
+ # Clean up.
+ call stclose (stp)
+ call close (fd)
+ call sfree (sp)
+end
+
+
+# XH_GNAME -- Extract the package name from a 'references' line.
+
+procedure xh_gname (line, pkg)
+
+char line[ARB] #i references line
+char pkg[ARB] #o package name in line
+
+int ip, strlen()
+
+begin
+ # Clear trailing whitespace back to the ']' at end of the
+ # package name.
+ for (ip=strlen(line); line[ip] != ']' || IS_WHITE(line[ip]); )
+ ip = ip - 1
+ line[ip] = EOS
+
+ # Move back to starting '[' of package name.
+ while (line[ip] != '[' && ip > 0)
+ ip = ip - 1
+
+ # What's left is the package name, copy it to the output.
+ call strcpy (line[ip+1], pkg, SZ_PKG)
+end
diff --git a/pkg/system/help/xhelp/xhroot.x b/pkg/system/help/xhelp/xhroot.x
new file mode 100644
index 00000000..9559662a
--- /dev/null
+++ b/pkg/system/help/xhelp/xhroot.x
@@ -0,0 +1,73 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "xhelp.h"
+
+
+# XH_ROOT_PKG -- Make the root package. Search the help database and
+# create a package list for all modules found. We add special entries for
+# system modules (imfort/math/os) which are not normally in the help tree
+# but provide documents.
+
+procedure xh_root_pkg (xh)
+
+pointer xh #i struct pointer.
+
+pointer sp, fname, buf, ip, op, lp
+int list
+
+int xh_pkglist()
+int gstrcpy(), fntopnb(), fntgfnb()
+bool strne()
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+ call salloc (buf, SZ_FNAME, TY_CHAR)
+
+ # Set initial packages and help databases. This consists of the
+ # system documentation (in sys$sys.hd), the contents of the
+ # clpackage module and each of the external packages.
+
+ lp = XH_LPTR(xh)
+
+ # Create an entry for seldom-read system docs.
+ if (XH_SHOWTYPE(xh) == YES) {
+ lp = lp + gstrcpy ("imfort. ", Memc[lp], ARB)
+ lp = lp + gstrcpy ("math. ", Memc[lp], ARB)
+ lp = lp + gstrcpy ("os. ", Memc[lp], ARB)
+ } else {
+ lp = lp + gstrcpy ("imfort ", Memc[lp], ARB)
+ lp = lp + gstrcpy ("math ", Memc[lp], ARB)
+ lp = lp + gstrcpy ("os ", Memc[lp], ARB)
+ }
+
+ # Add the external packages to the list.
+ list = fntopnb (HELPDB(xh), YES)
+ while (fntgfnb (list, Memc[fname], SZ_FNAME) != EOF) {
+ op = buf
+ ip = fname
+ while (Memc[ip] != '$' && Memc[ip] != EOS && Memc[ip] != ',') {
+ Memc[op] = Memc[ip]
+ ip = ip + 1
+ op = op + 1
+ }
+ Memc[op] = EOS
+ if (strne(Memc[buf],"lib")) {
+ lp = lp + gstrcpy (Memc[buf], Memc[lp], ARB)
+ if (XH_SHOWTYPE(xh) == YES)
+ lp = lp + gstrcpy (".", Memc[lp], ARB)
+ lp = lp + gstrcpy (" ", Memc[lp], ARB)
+ }
+ }
+
+ # Add the clpackage contents to the list.
+ lp = lp + xh_pkglist (xh, "clpackage", HELPDB(xh), Memc[lp])
+
+ if (lp > (XH_LPTR(xh) + SZ_HELPLIST))
+ call error (1, "Memory error: LIST pointer overflow.")
+
+ # Sort the list so it's presentable.
+ call xh_sort_list (LIST(xh))
+
+ call sfree (sp)
+end
diff --git a/pkg/system/help/xhelp/xhsave.x b/pkg/system/help/xhelp/xhsave.x
new file mode 100644
index 00000000..f280146d
--- /dev/null
+++ b/pkg/system/help/xhelp/xhsave.x
@@ -0,0 +1,184 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include "../help.h"
+include "xhelp.h"
+
+define SZ_EXTN 10
+
+
+# XH_SAVE_FILE -- Save the currently displayed page to the named file in
+# the specified format.
+
+procedure xh_save_file (xh, iname, oname, format, overwrite)
+
+pointer xh #i package descriptor
+char iname[ARB] #i input file
+char oname[ARB] #i output filename
+char format[ARB] #i format
+int overwrite #i overwrite flag
+
+pointer sp, buf
+char extn[SZ_EXTN]
+
+int access(), fnextn(), strlen(), strcmp()
+
+begin
+ if (access (oname, 0, 0) == YES && overwrite == NO) {
+ call smark (sp)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[buf], SZ_LINE,
+ "Operation would overwrite\nexisting file '%s'")
+ call pargstr (oname)
+ call gmsg (XH_GP(xh), "alert", Memc[buf])
+ call sfree (sp)
+ return
+
+ } else if (access (oname, 0, 0) == YES)
+ call delete (oname)
+
+ call aclrc (extn, SZ_EXTN)
+
+ # Strip off any braces around the arguments that were put
+ # in by the Tcl script.
+ if (iname[1] == '{') {
+ call amovc (iname[2], iname, strlen(iname)-2)
+ iname[strlen(iname)-1] = EOS
+ }
+ if (oname[1] == '{') {
+ call amovc (oname[2], oname, strlen(oname)-2)
+ oname[strlen(oname)-1] = EOS
+ }
+
+ switch (format[1]) {
+ case 's': # source
+ call fcopy (iname, oname)
+ case 't': # text
+ if (fnextn(iname, extn, 3) > 0 && strcmp("hlp", extn) == 0)
+ call xh_save_text (xh, iname, oname)
+ else
+ call fcopy (iname, oname)
+ case 'h': # html
+ if (fnextn(iname, extn, 3) > 0 && strcmp("hlp", extn) == 0)
+ call xh_save_html (xh, iname, oname, YES)
+ else
+ call xh_save_html (xh, iname, oname, NO)
+ case 'p': # postscript
+ if (fnextn(iname, extn, 3) > 0 && strcmp("hlp", extn) == 0)
+ call xh_save_ps (xh, iname, oname, YES)
+ else
+ call xh_save_ps (xh, iname, oname, NO)
+ default:
+ call gmsg (XH_GP(xh), "alert", "Invalid format specifier")
+ }
+end
+
+
+# XH_SAVE_TEXT -- Save the page as a formatted text file.
+
+procedure xh_save_text (xh, in, out)
+
+pointer xh #i package descriptor
+char in[ARB], out[ARB] #i file names
+
+char err[SZ_LINE]
+int fdout, open()
+errchk open
+
+begin
+ # Open the output file.
+ iferr (fdout = open (out, NEW_FILE, TEXT_FILE)) {
+ call sprintf (err, SZ_LINE, "Cannot open output file `%s'.")
+ call pargstr (out)
+ call gmsg (XH_GP(xh), "alert", err)
+ return
+ }
+
+ # Format the help as text.
+ call xh_get_help (fdout, "", "", in, HF_TEXT, HELPDB(xh), "all", "help")
+
+ # Close the file.
+ call close (fdout)
+end
+
+
+# XH_SAVE_HTML -- Save the page as an HTML file.
+
+procedure xh_save_html (xh, in, out, ishelp)
+
+pointer xh #i package descriptor
+char in[ARB], out[ARB] #i file names
+int ishelp #i is this a help file?
+
+char err[SZ_LINE]
+int fdout, fdin, open()
+errchk open
+
+begin
+ # Open the output file.
+ iferr (fdout = open (out, NEW_FILE, TEXT_FILE)) {
+ call sprintf (err, SZ_LINE, "Cannot open output file `%s'.")
+ call pargstr (out)
+ call gmsg (XH_GP(xh), "alert", err)
+ return
+ }
+
+ # Format the help as text.
+ if (ishelp == YES) {
+ call xh_get_help (fdout, "", "", in, HF_HTML, HELPDB(xh),
+ "all", "help")
+ } else {
+ # Open the input file.
+ iferr (fdout = open (out, NEW_FILE, TEXT_FILE)) {
+ call sprintf (err, SZ_LINE, "Cannot open output file `%s'.")
+ call pargstr (out)
+ call gmsg (XH_GP(xh), "alert", err)
+ return
+ }
+
+ call fprintf (out, "<HTML><BODY>\n")
+ call fprintf (out, "<TITLE>%s</TITLE>\n")
+ call pargstr (in)
+ call fprintf (out, "<PRE>\n")
+ call fcopyo (in, out)
+ call fprintf (out, "</PRE>\n")
+ call fprintf (out, "</BODY></HTML>\n")
+
+ call close (fdin)
+ }
+
+ # Close the file.
+ call close (fdout)
+end
+
+
+# XH_SAVE_PS -- Save the page as a postscript file.
+
+procedure xh_save_ps (xh, in, out, ishelp)
+
+pointer xh #i package descriptor
+char in[ARB], out[ARB] #i file names
+int ishelp #i is this a help file?
+
+char err[SZ_LINE]
+int fdout, open()
+errchk open
+
+begin
+ if (ishelp == NO)
+ return
+
+ # Open the output file.
+ iferr (fdout = open (out, NEW_FILE, TEXT_FILE)) {
+ call sprintf (err, SZ_LINE, "Cannot open output file `%s'.")
+ call pargstr (out)
+ call gmsg (XH_GP(xh), "alert", err)
+ return
+ }
+
+ # Format the help as text.
+ call xh_get_help (fdout, "", "", in, HF_PS, HELPDB(xh), "all", "help")
+
+ # Close the file.
+ call close (fdout)
+end
diff --git a/pkg/system/help/xhelp/xhsearch.x b/pkg/system/help/xhelp/xhsearch.x
new file mode 100644
index 00000000..18f1aa28
--- /dev/null
+++ b/pkg/system/help/xhelp/xhsearch.x
@@ -0,0 +1,185 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <fset.h>
+include <ctype.h>
+include "xhelp.h"
+
+
+# XH_SEARCH -- Given a search pattern generate a list of tasks matching the
+# pattern.
+
+procedure xh_search (xh, exact_match, pattern)
+
+pointer xh #i task struct pointer
+int exact_match #i require an exact match?
+char pattern[ARB] #i search pattern
+
+pointer sp, lfile, line, helpstr, item
+pointer tp, lp, pat
+char task[SZ_FNAME], pkg[SZ_FNAME], desc[SZ_FNAME]
+int i, ip, fd, fdl
+long fsize
+
+long fstatl()
+int open(), xh_match(), getline(), gstrcpy()
+errchk open, xh_updt_quickref
+
+begin
+ call smark (sp)
+ call salloc (lfile, SZ_FNAME, TY_CHAR)
+ call salloc (line, SZ_LINE, TY_CHAR)
+ call salloc (item, SZ_LINE, TY_CHAR)
+ call salloc (pat, SZ_FNAME, TY_CHAR)
+
+ # Open the quick reference file.
+ iferr (fd = open (QUICKREF(xh), READ_ONLY, TEXT_FILE))
+ call error (0, "Cannot open quick-reference file.")
+
+ # Open the temp file for the matched lines.
+ call mktemp ("tmp$xhelpq", Memc[lfile], SZ_FNAME)
+ fdl = open (Memc[lfile], NEW_FILE, TEXT_FILE)
+
+ # Allocate space for the results string.
+ fsize = fstatl (fd, F_FILESIZE)
+
+ # Check pattern for multi-word searches.
+ call aclrc (Memc[pat], SZ_FNAME)
+ for (ip=1; IS_WHITE(pattern[ip]); ip=ip+1)
+ ;
+ if (pattern[ip] == '{') {
+ ip = ip + 1
+ for (i=0; pattern[ip] != '}'; ip=ip+1) {
+ Memc[pat+i] = pattern[ip]
+ i = i + 1
+ }
+ } else
+ call strcpy (pattern[ip], Memc[pat], SZ_FNAME)
+
+ # Loop over the lines in the file and match the pattern.
+ while (getline(fd,Memc[line]) != EOF) {
+ if (xh_match (Memc[line], Memc[pat], exact_match) != 0)
+ call putline (fdl, Memc[line]) # save it to the file
+ }
+ call close (fdl)
+ call close (fd)
+
+ # Now read back the file to see if we matched anything, and so we
+ # can parse the file for task/package names.
+ fdl = open (Memc[lfile], READ_ONLY, TEXT_FILE)
+ fsize = fstatl (fdl, F_FILESIZE)
+
+ # See whether we got anything, if not return.
+ if (fsize == 0) {
+ call sprintf (Memc[line], SZ_LINE,
+ "No help available for\npattern `%s'.")
+ call pargstr (Memc[pat])
+ call gmsg (XH_GP(xh), "alert", Memc[line])
+
+ call close (fdl)
+ call delete (Memc[lfile])
+ call sfree (sp)
+ return
+ }
+ call calloc (helpstr, 5*fsize, TY_CHAR)
+
+ # Read back the sorted list, separate the task name, package, and
+ # descriptions and format it for the GUI.
+ tp = helpstr
+ tp = tp + gstrcpy ("<HTML><BODY><PRE>", Memc[tp], ARB)
+ while (getline(fdl, Memc[line]) != EOF) {
+ Memc[item] = EOS
+ lp = line
+
+ # Get the task name.
+ for (i=1; !IS_WHITE(Memc[lp]); i=i+1) {
+ task[i] = Memc[lp]
+ lp = lp + 1
+ if (Memc[lp] == EOS || i >= SZ_FNAME)
+ break
+ }
+ task[i] = EOS
+
+ # Skip delimiter.
+ while (IS_WHITE(Memc[lp]) || Memc[lp] == '-')
+ lp = lp + 1
+
+ # Get the description up to the '[' package name.
+ for (i=1; Memc[lp] != '['; i=i+1) {
+ desc[i] = Memc[lp]
+ lp = lp + 1
+ if (Memc[lp] == EOS || i >= SZ_FNAME)
+ break
+ }
+ desc[i] = EOS
+
+ # Get the package name up to the ']' delimiter.
+ if (Memc[lp] != EOS) {
+ lp = lp + 1
+ for (i=1; Memc[lp] != ']'; i=i+1) {
+ pkg[i] = Memc[lp]
+ lp = lp + 1
+ if (Memc[lp] == '\n' || Memc[lp] == EOS || i >= SZ_FNAME)
+ break
+ }
+ }
+ pkg[i] = EOS
+
+ call sprintf(Memc[item], SZ_LINE, "<A HREF=%s.%s>%10.10s</A> ")
+ call pargstr (pkg)
+ call pargstr (task)
+ call pargstr (task)
+ tp = tp + gstrcpy (Memc[item], Memc[tp], ARB)
+ call sprintf(Memc[item], SZ_LINE, "<A HREF=%s.%s>%10.10s</A> ")
+ call pargstr (pkg)
+ call pargstr (pkg)
+ call pargstr (pkg)
+ tp = tp + gstrcpy (Memc[item], Memc[tp], ARB)
+ call sprintf(Memc[item], SZ_LINE, " %s\n")
+ call pargstr (desc)
+ tp = tp + gstrcpy (Memc[item], Memc[tp], ARB)
+ }
+ call strcat ("</PRE></BODY></HTML>\n", Memc[tp], SZ_LINE)
+ Memc[tp] = EOS
+ call close (fdl)
+
+ # Send it to the GUI.
+ call gmsg (XH_GP(xh), "apropos", Memc[helpstr])
+
+ # Clean up.
+ call delete (Memc[lfile])
+ call mfree (helpstr, TY_CHAR)
+ call sfree (sp)
+end
+
+
+# XH_MATCH -- Match any or all words in a pattern against the given line.
+# We can either look for an exact match or just the occurence of one word
+# in the pattern.
+
+int procedure xh_match (line, pattern, exact_match)
+
+char line[ARB] #i line to be matched
+char pattern[ARB] #i pattern words
+int exact_match
+
+char word[SZ_FNAME]
+int i, j
+int strsearch()
+
+begin
+ if (exact_match == YES) {
+ return (strsearch(line, pattern))
+ } else {
+ # See if any word in the pattern matches in the line.
+ for (i=1; pattern[i] != EOS; i=i+1) {
+ for (j=1; pattern[i] != EOS && pattern[i] != ' '; j=j+1) {
+ word[j] = pattern[i]
+ i = i + 1
+ }
+ word[j] = EOS
+ if (strsearch(line, word) != 0)
+ return (YES)
+ }
+ return (NO)
+ }
+end
diff --git a/pkg/system/help/xhelp/xhsort.x b/pkg/system/help/xhelp/xhsort.x
new file mode 100644
index 00000000..b5ccc081
--- /dev/null
+++ b/pkg/system/help/xhelp/xhsort.x
@@ -0,0 +1,223 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include "xhelp.h"
+
+define MAXPTR 20000
+define SZ_LINBUF 300000
+
+
+# XH_SORT_LIST -- Take a list of words (as with a package list) and sort them.
+
+procedure xh_sort_list (list)
+
+char list[ARB] #u list to be sorted
+
+pointer sp, index, buf, ip
+int i, j, count, len
+
+int strlen()
+
+begin
+ len = strlen (list)
+
+ call smark (sp)
+ call salloc (index, SZ_HELPLIST, TY_INT)
+ call salloc (buf, len+2, TY_CHAR)
+
+ # Build up the index array.
+ count = 1
+ Memi[index] = 1
+ for (i=2; i<len; i=i+1) {
+ if (list[i] == ' ') {
+ list[i] = EOS
+ Memi[index+count] = i + 1
+ count = count + 1
+ }
+ }
+
+ # Sort the list.
+ call strsrt (Memi[index], list, count)
+
+ # Restore the list.
+ ip = buf
+ do i = 1, count {
+ for (j=0; list[Memi[index+i-1]+j] != EOS; j=j+1) {
+ Memc[ip] = list[Memi[index+i-1]+j]
+ ip = ip + 1
+ }
+ Memc[ip] = ' '
+ ip = ip + 1
+ }
+ Memc[ip-1] = EOS
+ call strcpy (Memc[buf], list, strlen(Memc[buf]))
+ call sfree (sp)
+end
+
+
+# XH_FILE_SORT -- Sort the lines in the named file.
+
+procedure xh_file_sort (fname)
+
+char fname[SZ_FNAME] #i file to be sorted
+
+pointer linbuf, linptr
+int nlines, fd
+int open()
+
+begin
+ call calloc (linptr, MAXPTR, TY_INT)
+ call calloc (linbuf, SZ_LINBUF, TY_CHAR)
+
+ # Sort the file then write it back out.
+ fd = open (fname, READ_ONLY, TEXT_FILE)
+ call xh_gtext (fd, Memi[linptr], nlines, Memc[linbuf])
+ call close (fd)
+ call delete (fname)
+
+ call xh_quick (Memi[linptr], Memc[linbuf], nlines)
+
+ fd = open (fname, NEW_FILE, TEXT_FILE)
+ call xh_ptext (fd, Memi[linptr], nlines, Memc[linbuf])
+
+ call mfree (linbuf, TY_CHAR)
+ call mfree (linptr, TY_INT)
+ call close (fd)
+end
+
+
+# XH_GTEXT -- Get text lines into linbuf.
+
+procedure xh_gtext (infile, linptr, nlines, linbuf)
+
+int infile, linptr[ARB], nlines
+char linbuf[ARB]
+
+int lbp, len, getline()
+errchk getline
+
+begin
+ nlines = 0
+ lbp = 1
+
+ repeat {
+ len = getline (infile, linbuf[lbp])
+ if (len == EOF)
+ break
+ else if (len == 1)
+ # ignore blank lines
+ else {
+ nlines = nlines + 1
+ linptr[nlines] = lbp
+ lbp = lbp + len + 1 # '1' = room for EOS
+ }
+ } until (lbp >= SZ_LINBUF - SZ_LINE || nlines >= MAXPTR)
+end
+
+
+# XH_PTEXT -- Output text lines from linbuf to outfile.
+
+procedure xh_ptext (outfil, linptr, nlines, linbuf)
+
+int outfil, linptr[ARB], nlines
+char linbuf[ARB]
+int i, j
+errchk putline
+
+begin
+ for (i=1; i <= nlines; i=i+1) {
+ j = linptr[i]
+ call putline (outfil, linbuf[j])
+ }
+end
+
+
+# XH_QUICK -- Quicksort for text data. NOTE -- This algorithm is quadratic in
+# the worst case, i.e., when the data is already sorted. A random method of
+# selecting the pivot should be used to improve the behaviour on sorted arrays.
+
+procedure xh_quick (linptr, linbuf, nlines)
+
+int linptr[ARB] # indices of strings in buffer
+char linbuf[ARB] # string buffer
+int nlines # number of strings
+
+define LOGPTR 32
+define swap {temp=$1;$1=$2;$2=temp}
+
+int i, j, k, temp, lv[LOGPTR], p, pivlin, uv[LOGPTR]
+int xh_compare()
+
+begin
+ lv[1] = 1
+ uv[1] = nlines
+ p = 1
+
+ while (p > 0) {
+ if (lv[p] >= uv[p]) # only one elem in this subset
+ p = p - 1 # pop stack
+ else {
+ # Dummy loop to trigger optimizer.
+ do p = p, ARB {
+ i = lv[p] - 1
+ j = uv[p]
+
+ # Select pivot element at midpoint of interval to avoid
+ # quadratic behavior on a sorted list.
+
+ k = (lv[p] + uv[p]) / 2
+ swap (linptr[j], linptr[k])
+ pivlin = linptr[j]
+
+ while (i < j) {
+ for (i=i+1; xh_compare (linptr[i], pivlin, linbuf) < 0;
+ i=i+1)
+ ;
+ for (j=j-1; j > i; j=j-1)
+ if (xh_compare (linptr[j], pivlin, linbuf) <= 0)
+ break
+ if (i < j) # out of order pair
+ swap (linptr[i], linptr[j])
+ }
+
+ j = uv[p] # move pivot to position i
+ swap (linptr[i], linptr[j])
+
+ if (i-lv[p] < uv[p] - i) { # stack so shorter done first
+ lv[p+1] = lv[p]
+ uv[p+1] = i - 1
+ lv[p] = i + 1
+ } else {
+ lv[p+1] = i + 1
+ uv[p+1] = uv[p]
+ uv[p] = i - 1
+ }
+
+ break
+ }
+
+ p = p + 1 # push onto stack
+ }
+ }
+end
+
+
+# XH_COMPARE -- Compare two strings. Return -1 if str1<str2, 1 if str1>str2,
+# or 0 if the two strings are equal.
+
+int procedure xh_compare (lp1, lp2, linbuf)
+
+int lp1, lp2 # pointers to substrings in linbuf
+char linbuf[ARB] # text buffer
+
+int ip1, ip2, answer
+int strcmp()
+
+begin
+ for (ip1=lp1; IS_WHITE(linbuf[ip1]); ip1=ip1+1)
+ ;
+ for (ip2=lp2; IS_WHITE(linbuf[ip2]); ip2=ip2+1)
+ ;
+ answer = strcmp (linbuf[ip1], linbuf[ip2])
+ return (answer)
+end
diff --git a/pkg/system/help/xhelp/zzdebug.x b/pkg/system/help/xhelp/zzdebug.x
new file mode 100644
index 00000000..70a95d9b
--- /dev/null
+++ b/pkg/system/help/xhelp/zzdebug.x
@@ -0,0 +1,59 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+
+# ZZDEBUG.X -- Debug routines for the help formatting system.
+
+task lroff2html = t_lroff2html,
+ lroff2ps = t_lroff2ps
+
+
+# LROFF2HTML -- Test program to convert an Lroff source file to HTML.
+
+procedure t_lroff2html ()
+
+int fdi, fdo
+char iname[SZ_FNAME], oname[SZ_FNAME]
+
+int open()
+errchk open
+
+begin
+ call clgstr ("input", iname, SZ_FNAME) # get parameters
+ call clgstr ("output", oname, SZ_FNAME)
+
+ fdi = open (iname, READ_ONLY, TEXT_FILE) # open the file
+ fdo = open (oname, NEW_FILE, TEXT_FILE)
+
+ # Process it.
+ call lroff2html (fdi, fdo, iname, "", "", "", "")
+
+ call close (fdi)
+ call close (fdo)
+end
+
+
+# LROFF2PS -- Test program to convert an Lroff source file to Postscript.
+
+procedure t_lroff2ps ()
+
+int fdi, fdo
+char iname[SZ_FNAME], oname[SZ_FNAME]
+
+pointer ps
+int open()
+errchk open
+
+begin
+ call clgstr ("input", iname, SZ_FNAME) # get parameters
+ call clgstr ("output", oname, SZ_FNAME)
+
+ fdi = open (iname, READ_ONLY, TEXT_FILE) # open the files
+ fdo = open (oname, READ_ONLY, TEXT_FILE)
+
+ # Process it.
+ ps = NULL
+ call lroff2ps (fdi, fdo, ps, "", "")
+
+ call close (fdi)
+ call close (fdo)
+end
diff --git a/pkg/system/lprint.par b/pkg/system/lprint.par
new file mode 100644
index 00000000..268ccac1
--- /dev/null
+++ b/pkg/system/lprint.par
@@ -0,0 +1,5 @@
+files,s,a,,,,"list of files to be printed"
+device,s,h,"printer",,,"name of output device"
+map_cc,b,h,yes,,,"make unknown control chars printable"
+paginate,s,h,"auto",,,"break pages (auto, yes, no)"
+label,s,h,"STDIN",,,"file name label if input redirected"
diff --git a/pkg/system/lprint.x b/pkg/system/lprint.x
new file mode 100644
index 00000000..3b61328c
--- /dev/null
+++ b/pkg/system/lprint.x
@@ -0,0 +1,213 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <syserr.h>
+include <error.h>
+include <finfo.h>
+include <time.h>
+include <ttyset.h>
+
+define WIDE_PAGE 100
+define SZ_DDSTR 256
+
+
+# LPRINT -- Print a file or files on the lineprinter. A one line header is
+# printed at the top of each page, unless we are reading from the standard
+# input. If printing multiple files, each file begins on a new page.
+# TTYPUTLINE is used to output lines to the printer file, so that formfeeds,
+# standout mode, etc., may be properly translated for the indicated device.
+
+procedure t_lprint()
+
+int out, list, map_cc
+bool input_redirected, one_file
+bool print_heading, auto_header
+pointer sp, fname, device, label, lp, ddstr
+
+pointer ttyodes()
+bool streq(), clgetb()
+int clpopni(), clplen(), envgets(), lpopen(), clgfil(), ttygets(), btoi()
+string printer "printer"
+errchk clgfil, lp_print_file
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+ call salloc (label, SZ_FNAME, TY_CHAR)
+ call salloc (device, SZ_FNAME, TY_CHAR)
+ call salloc (ddstr, SZ_DDSTR, TY_CHAR)
+
+ # Open list of files to be printed.
+ list = clpopni ("files")
+ one_file = (clplen (list) == 1)
+
+ # Get device name. Default is "printer", which means that the actual
+ # device name is given by the environment variable "printer".
+
+ call clgstr ("device", Memc[device], SZ_FNAME)
+ if (streq (Memc[device], printer))
+ if (envgets (printer, Memc[device], SZ_FNAME) <= 0) {
+ call clpcls (list)
+ call syserrs (SYS_ENVNF, printer)
+ }
+
+ # Map unknown control chars into printable sequences?
+ map_cc = btoi (clgetb ("map_cc"))
+
+ # If automatic pagination is selected, lprint will break pages and
+ # print headers only if the standard input is not redirected.
+ # Otherwise, pagination is disabled unless paginate=yes. The file
+ # name buffer is used as a temporary to hold the value string.
+
+ call clgstr ("paginate", Memc[fname], SZ_FNAME)
+ auto_header = streq (Memc[fname], "auto")
+ if (!auto_header)
+ print_heading = streq (Memc[fname], "yes")
+
+ # Open TTY descriptor and printer file. We deal only with character
+ # data, so open printer as a text file. Output the files to the line
+ # printer device.
+
+ lp = ttyodes (Memc[device])
+ if (ttygets (lp, "DD", Memc[ddstr], SZ_DDSTR) <= 0)
+ call error (1, "missing 'DD' parameter in termcap entry")
+
+ out = lpopen (Memc[ddstr], APPEND, TEXT_FILE)
+
+ while (clgfil (list, Memc[fname], SZ_FNAME) != EOF) {
+ # If only one file and it is the standard input (i.e., reading
+ # from a pipe), and if header printing is not explicitly enabled
+ # or disabled, do not break pages and print headers.
+
+ input_redirected = (one_file && streq (Memc[fname], "STDIN"))
+ if (auto_header)
+ print_heading = !input_redirected
+
+ # Get page header label string. File name is used unless reading
+ # from the standard input.
+
+ if (input_redirected)
+ call clgstr ("label", Memc[label], SZ_FNAME)
+ else
+ call strcpy (Memc[fname], Memc[label], SZ_FNAME)
+
+ # Output file, followed by a form feed.
+ iferr {
+ call lp_print_file (out, lp, Memc[fname], Memc[label], map_cc,
+ print_heading)
+ call flush (out)
+ } then
+ call erract (EA_WARN)
+ }
+
+ call close (out)
+ call clpcls (list)
+ call ttycdes (lp)
+ call sfree (sp)
+end
+
+
+# LP_PRINT_FILE -- Open and print the named text file on the output file,
+# under control of the tty device descriptor LP. Print a header on each
+# page if enabled, and formfeed at the end of the file. The number of lines
+# per page is given by the tty descriptor.
+
+procedure lp_print_file (out, lp, fname, label, map_cc, print_heading)
+
+int out
+pointer lp
+char fname[ARB]
+char label[ARB]
+int map_cc
+bool print_heading
+
+bool one_tab_in, streq()
+int pageno, lineno, maxlines, totlines, status, in
+long fi[LEN_FINFO], time, clktime()
+pointer sp, ip, lbuf, timebuf
+int open(), getline(), finfo(), ttystati()
+errchk salloc, finfo, cnvtime, open, ttystati, getline, ttyputline
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LINE+1, TY_CHAR)
+ call salloc (timebuf, SZ_TIME, TY_CHAR)
+
+ # Get time and date file was last modified.
+ if (print_heading) {
+ if (streq (fname, "STDIN"))
+ time = clktime (long(0))
+ else {
+ if (finfo (fname, fi) == ERR) {
+ call sprintf (Memc[lbuf], SZ_LINE, "%s '%s'\n")
+ call pargstr ("Cannot get info on file")
+ call pargstr (fname)
+ call error (1, Memc[lbuf])
+ } else
+ time = FI_MTIME(fi)
+ }
+ call cnvtime (time, Memc[timebuf], SZ_TIME)
+ }
+
+ in = open (fname, READ_ONLY, TEXT_FILE)
+ maxlines = ttystati (lp, TTY_NLINES)
+
+ # If printer page is very wide, set page in one tabstop from left
+ # margin.
+
+ one_tab_in = (ttystati (lp, TTY_NCOLS) > WIDE_PAGE)
+ if (one_tab_in) {
+ Memc[lbuf] = '\t'
+ ip = lbuf + 1
+ } else
+ ip = lbuf
+
+ # If printing header and breaking pages, allow for the 3 line header
+ # and a three line border at the bottom of the page.
+
+ if (print_heading)
+ maxlines = maxlines - 6
+
+ totlines = 0
+ status = OK
+
+ # Format and write each page of output. If headers are enabled,
+ # output formfeed and header between pages.
+
+ for (pageno=1; status != EOF; pageno=pageno+1) {
+ # Print header, if enabled. We assume that we are already
+ # positioned to the top of a page.
+
+ if (print_heading) {
+ call sprintf (Memc[ip], SZ_LINE, "%s %s Page %d\n\n\n")
+ call pargstr (Memc[timebuf])
+ call pargstr (label)
+ call pargi (pageno)
+ call ttyputline (out, lp, Memc[lbuf], map_cc)
+ totlines = totlines + 3
+ }
+
+ # Output one page of text. Each output line is processed by
+ # ttyputline to expand tabs, underline, etc.
+
+ for (lineno=1; lineno <= maxlines; lineno=lineno+1) {
+ status = getline (in, Memc[ip])
+ if (status == EOF)
+ break
+ if (Memc[ip] == '\f') {
+ call ttyputline (out, lp, "\f", map_cc)
+ call strcpy (Memc[ip+1], Memc[ip], SZ_LINE)
+ }
+ call ttyputline (out, lp, Memc[lbuf], map_cc)
+ totlines = totlines + 1
+ }
+
+ # Output formfeed, leaving printer positioned to top of page.
+ # Do not break pages if headers are disabled.
+
+ if (print_heading && totlines > 0)
+ call ttyputline (out, lp, "\f", map_cc)
+ }
+
+ call close (in)
+ call sfree (sp)
+end
diff --git a/pkg/system/lroff.par b/pkg/system/lroff.par
new file mode 100644
index 00000000..512769eb
--- /dev/null
+++ b/pkg/system/lroff.par
@@ -0,0 +1,4 @@
+input_file,f,a,,,,file containing help text
+lmargin,i,h,1,1,160,left margin
+rmargin,i,h,72,1,160,right margin
+format,s,h,"text","|text|html|ps|postscript|",,format for output
diff --git a/pkg/system/match.par b/pkg/system/match.par
new file mode 100644
index 00000000..fa2670b3
--- /dev/null
+++ b/pkg/system/match.par
@@ -0,0 +1,5 @@
+pattern,s,a,,,,text pattern to be matched
+files,s,a,,,,files to be searched for the pattern
+stop,b,h,no,,,"stop, rather than pass, matched lines?"
+print_file_names,b,h,yes,,,print file names if multiple files?
+metacharacters,b,h,yes,,,recognize pattern matching metacharacters?
diff --git a/pkg/system/match.x b/pkg/system/match.x
new file mode 100644
index 00000000..b9f8feb2
--- /dev/null
+++ b/pkg/system/match.x
@@ -0,0 +1,96 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <pattern.h>
+include <ctype.h>
+
+# MATCH -- Search for the indicated pattern in each line of a file or files,
+# passing or stopping only those lines which contain the pattern.
+
+procedure t_match()
+
+bool stop_matched_lines # pass or stop matched lines?
+char chset[2]
+int fd, list
+pointer sp, ip, line, fname, patbuf, pattern
+bool line_matches, encode_pattern, print_file_names, match_pattern
+bool clgetb()
+int strmatch(), strsearch(), patmatch(), patmake(), stridxs()
+int open(), getline(), clpopni(), clplen(), clgfil()
+
+begin
+ call smark (sp)
+ call salloc (line, SZ_LINE, TY_CHAR)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+ call salloc (patbuf, SZ_LINE, TY_CHAR)
+ call salloc (pattern, SZ_FNAME, TY_CHAR)
+
+ # Get pattern. If it contains either * or [, general pattern
+ # matching with an encoded pattern must be used. If no metacharacters
+ # at all are used, or if metacharacters are disabled, use STRSEARCH
+ # for maximum efficiency.
+
+ call clgstr ("pattern", Memc[pattern], SZ_FNAME)
+ if (clgetb ("metacharacters")) {
+
+ # Check for the tough pattern matching metachars.
+ chset[1] = CH_CLOSURE
+ chset[2] = CH_CCL
+ chset[3] = EOS
+ encode_pattern = (stridxs (chset, Memc[pattern]) > 0)
+
+ # If don't have to use patmatch, see if we have a simple alphanum
+ # string so that we can use strsearch.
+
+ if (!encode_pattern) {
+ for (ip=pattern; IS_ALNUM(Memc[ip]); ip=ip+1)
+ ;
+ match_pattern = (Memc[ip] != EOS)
+ }
+
+ } else {
+ encode_pattern = false
+ match_pattern = false
+ }
+
+ stop_matched_lines = clgetb ("stop")
+ list = clpopni ("files")
+ print_file_names = (clplen(list) > 1) && (clgetb("print_file_names"))
+
+ if (encode_pattern)
+ if (patmake (Memc[pattern], Memc[patbuf], SZ_LINE) == ERR)
+ call error (1, "Pattern is too complex")
+
+ # Search each file in the list, passing a line on to the output
+ # only if the line matches and stop is false, or if the line does
+ # not match and stop is true.
+
+ while (clgfil (list, Memc[fname], SZ_FNAME) != EOF) {
+ fd = open (Memc[fname], READ_ONLY, TEXT_FILE)
+
+ while (getline (fd, Memc[line]) != EOF) {
+ if (encode_pattern)
+ line_matches = (patmatch (Memc[line], Memc[patbuf]) > 0)
+ else if (match_pattern)
+ line_matches = (strmatch (Memc[line], Memc[pattern]) > 0)
+ else
+ line_matches = (strsearch (Memc[line], Memc[pattern]) > 0)
+
+ if ((line_matches && !stop_matched_lines) ||
+ (!line_matches && stop_matched_lines)) {
+
+ if (print_file_names) {
+ call printf ("%s:")
+ call pargstr (Memc[fname])
+ }
+
+ call putline (STDOUT, Memc[line])
+ call flush (STDOUT)
+ }
+ }
+
+ call close (fd)
+ }
+
+ call sfree (sp)
+ call clpcls (list)
+end
diff --git a/pkg/system/mkdir.par b/pkg/system/mkdir.par
new file mode 100644
index 00000000..b2cbe135
--- /dev/null
+++ b/pkg/system/mkdir.par
@@ -0,0 +1 @@
+newdir,s,a,,,,name of the new directory
diff --git a/pkg/system/mkdir.x b/pkg/system/mkdir.x
new file mode 100644
index 00000000..a1711d51
--- /dev/null
+++ b/pkg/system/mkdir.x
@@ -0,0 +1,12 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# MKDIR -- Make a directory. (May be an IRAF VFN or an OS directory spec)
+
+procedure t_mkdir ()
+
+char newdir[SZ_FNAME]
+
+begin
+ call clgstr ("newdir", newdir, SZ_FNAME)
+ call fmkdir (newdir)
+end
diff --git a/pkg/system/mkhelpdb.par b/pkg/system/mkhelpdb.par
new file mode 100644
index 00000000..0c1139f5
--- /dev/null
+++ b/pkg/system/mkhelpdb.par
@@ -0,0 +1,3 @@
+helpdir,s,a,"lib$root.hd",,,"root help directory to be compiled"
+helpdb,s,a,"lib$helpdb.mip",,,"name of help database to be created"
+verbose,b,h,no,,,"detail the structure of the package hierarchy"
diff --git a/pkg/system/mkpkg b/pkg/system/mkpkg
new file mode 100644
index 00000000..1392b3c6
--- /dev/null
+++ b/pkg/system/mkpkg
@@ -0,0 +1,53 @@
+# Make the SYSTEM system utilities package (including HELP)
+
+$call relink
+$exit
+
+update:
+ $call relink
+ $call install
+ ;
+
+relink:
+ $update libpkg.a
+ $omake x_system.x
+ $link x_system.o libpkg.a -o xx_system.e
+ ;
+
+install:
+ $move xx_system.e bin$x_system.e
+ ;
+
+libpkg.a:
+ @help
+
+ cmdstr.x <ctype.h>
+ chkupdate.x <fio.h> <fset.h> <finfo.h> <syserr.h>
+ concatenate.x
+ copy.x <error.h>
+ count.x <chars.h> <ctype.h> <error.h>
+ delete.x <error.h>
+ directory.x <chars.h> <ctype.h> <diropen.h> <finfo.h>\
+ <fset.h> <protect.h> <time.h>
+ files.x
+ head.x <error.h>
+ lprint.x <error.h> <finfo.h> <time.h> <ttyset.h>
+ match.x <ctype.h> <pattern.h>
+ mkdir.x
+ movefiles.x <error.h>
+ mtclean.x
+ netstatus.x
+ page.x <fset.h>
+ pathnames.x
+ protect.x <error.h> <protect.h>
+ rename.x <error.h>
+ rewind.x
+ sort.x sort.com <ctype.h>
+ tail.x <error.h>
+ tee.x <fset.h>
+ touch.x <error.h> <finfo.h> <time.h>
+ type.x <error.h>
+ unprotect.x <error.h> <protect.h>
+ t_fcache.x <error.h>
+ t_urlget.x <error.h> <imhdr.h> <imset.h> <mach.h>
+ ;
diff --git a/pkg/system/mkscript.cl b/pkg/system/mkscript.cl
new file mode 100644
index 00000000..984cdf27
--- /dev/null
+++ b/pkg/system/mkscript.cl
@@ -0,0 +1,79 @@
+#{ MKBATCH -- Make a batch script.
+
+{
+ # Make a copy of the script file query parameter and delete the
+ # file if it exists and not appending.
+
+ scrpt = script
+ if (access (scrpt) && !append)
+ delete (scrpt, verify=verify)
+
+ # Outer loop provides return when the user wants to start over.
+
+ while (YES) {
+
+ # Add commands until the user is done.
+
+ while (YES) {
+
+ # Determine the task name and check that it is loaded.
+
+ ltask = task
+ if (!deftask (ltask)) {
+ print ("Task ", ltask, " not loaded.")
+ next
+ }
+
+ # Edit the task parameters.
+
+ eparam (ltask)
+ print ("")
+
+ # If the user is verifying then display the command.
+
+ if (verify) {
+ lparam (ltask) | cmdstr (ltask, hidden=hidden)
+ cok = YES
+ if (cok) {
+ lparam (ltask) | cmdstr (ltask, hidden=hidden, >> scrpt)
+ print ("", >> scrpt)
+ }
+ } else {
+ lparam (ltask) | cmdstr (ltask, hidden=hidden, >> scrpt)
+ print ("", >> scrpt)
+ }
+
+ # Ask if more commands are to be added to the script.
+
+ more = YES
+ if (!more)
+ break
+ }
+
+ # If verifying page the script and let the user decide to start
+ # over.
+
+ if (verify) {
+ page (scrpt)
+ sok = YES
+ if (sok)
+ break
+ else
+ delete (scrpt, verify=verify)
+ } else
+ break
+ }
+
+ # If the user does not want to submit the script then quit.
+
+ if (!submit)
+ bye
+}
+
+# Submit the script as a background process.
+
+print ("Script ", scrpt, " submitted at:")
+time
+print ("\nScript ", scrpt, " submitted at:", >> logfile)
+time (>> logfile)
+cl (< scrpt, >>& logfile) &
diff --git a/pkg/system/mkscript.par b/pkg/system/mkscript.par
new file mode 100644
index 00000000..46afb1b6
--- /dev/null
+++ b/pkg/system/mkscript.par
@@ -0,0 +1,17 @@
+script,s,a,script.cl,,,Script file name
+task,s,a,,,,Task name of command to be added to script
+submit,b,a,yes,,,Submit the script as a background job?
+
+append,b,h,no,,,Append new to existing script?
+hidden,b,h,yes,,,Include hidden parameters in command?
+verify,b,h,yes,,,Verify each command?
+logfile,f,h,script.log,,,Script log file name
+
+# Script query parameters and variables.
+
+cok,b,a,yes,,,Is the command ok?
+sok,b,a,yes,,,Is the script ok?
+more,b,a,yes,,,Add another command?
+
+scrpt,s,h
+ltask,s,h
diff --git a/pkg/system/movefiles.par b/pkg/system/movefiles.par
new file mode 100644
index 00000000..1aa0cc27
--- /dev/null
+++ b/pkg/system/movefiles.par
@@ -0,0 +1,3 @@
+files,s,a,,,,list of files to be moved
+newdir,f,a,,,,name of destination directory
+verbose,b,h,no,,,print names of files as they are moved
diff --git a/pkg/system/movefiles.x b/pkg/system/movefiles.x
new file mode 100644
index 00000000..32842f61
--- /dev/null
+++ b/pkg/system/movefiles.x
@@ -0,0 +1,52 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+
+# MOVEFILES -- Move a set of files to another directory. If the destination
+# is not a directory it is a fatal error. Ambiguous directory specifications
+# are resolved in favor of subdirectories, rather than logical directories.
+
+procedure t_movefiles()
+
+bool verbose
+int list, root_len
+pointer sp, fname, newdir, pathname, newname, junkstr
+bool clgetb()
+int clpopni(), clgfil(), fnldir(), isdirectory()
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+ call salloc (newdir, SZ_FNAME, TY_CHAR)
+ call salloc (pathname, SZ_PATHNAME, TY_CHAR)
+ call salloc (newname, SZ_PATHNAME, TY_CHAR)
+ call salloc (junkstr, SZ_FNAME, TY_CHAR)
+
+ list = clpopni ("files")
+ call clgstr ("newdir", Memc[newdir], SZ_FNAME)
+ verbose = clgetb ("verbose")
+
+ if (isdirectory (Memc[newdir], Memc[pathname], SZ_PATHNAME) == 0) {
+ call strcat ("$", Memc[newdir], SZ_FNAME)
+ if (isdirectory (Memc[newdir], Memc[pathname], SZ_PATHNAME) == 0)
+ call error (1, "destination is not a directory")
+ }
+
+ while (clgfil (list, Memc[fname], SZ_FNAME) != EOF) {
+ call strcpy (Memc[pathname], Memc[newname], SZ_PATHNAME)
+ root_len = fnldir (Memc[fname], Memc[junkstr], SZ_FNAME)
+ call strcat (Memc[fname+root_len], Memc[newname], SZ_PATHNAME)
+
+ if (verbose) {
+ call eprintf ("%s -> %s\n")
+ call pargstr (Memc[fname])
+ call pargstr (Memc[newname])
+ }
+
+ iferr (call rename (Memc[fname], Memc[newname]))
+ call erract (EA_WARN)
+ }
+
+ call clpcls (list)
+ call sfree (sp)
+end
diff --git a/pkg/system/mtclean.par b/pkg/system/mtclean.par
new file mode 100644
index 00000000..d30e2b82
--- /dev/null
+++ b/pkg/system/mtclean.par
@@ -0,0 +1,3 @@
+all,b,h,no,,,delete all lok files unconditionally
+stale,i,h,3600,,,threshold (seconds) after which old lok files are deleted
+verbose,b,h,no,,,print names of lok files as they are deleted
diff --git a/pkg/system/mtclean.x b/pkg/system/mtclean.x
new file mode 100644
index 00000000..d79359c5
--- /dev/null
+++ b/pkg/system/mtclean.x
@@ -0,0 +1,25 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# MTCLEAN -- Clean the magtape .lok file area, i.e., delete any old .lok files.
+# These files no longer serve any device locking purpose, rather, they are
+# used by the magtape system to store knowledge of the tape position when
+# the drive is not being accessed. The mtclean task is called during CL
+# startup to delete any old .lok files to keep these from being erroneously
+# used to indicate the tape position. In normal use the .lok files are
+# created when a tape is allocated and deleted when the tape is deallocated,
+# but the files can be left behind if the CL is killed without doing a
+# deallocate.
+
+procedure t_mtclean()
+
+int out
+bool clgetb()
+int clgeti(), btoi()
+
+begin
+ out = NULL
+ if (clgetb ("verbose"))
+ out = STDOUT
+
+ call mtclean (btoi(clgetb("all")), clgeti("stale"), out)
+end
diff --git a/pkg/system/netstatus.x b/pkg/system/netstatus.x
new file mode 100644
index 00000000..b7ecb225
--- /dev/null
+++ b/pkg/system/netstatus.x
@@ -0,0 +1,9 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# NETSTATUS -- Print the network status.
+
+procedure t_netstatus()
+
+begin
+ call ki_shownet (STDOUT)
+end
diff --git a/pkg/system/news.cl b/pkg/system/news.cl
new file mode 100644
index 00000000..ee3e88ec
--- /dev/null
+++ b/pkg/system/news.cl
@@ -0,0 +1,5 @@
+#{ NEWS -- Page the system news file.
+
+{
+ page "doc$newsfile"
+}
diff --git a/pkg/system/page.par b/pkg/system/page.par
new file mode 100644
index 00000000..2419bf06
--- /dev/null
+++ b/pkg/system/page.par
@@ -0,0 +1,6 @@
+files,s,a,,,,Files to be paged
+map_cc,b,h,yes,,,Map control characters into printable sequences?
+clear_screen,b,h,yes,,,Clear screen between pages?
+first_page,i,h,1,1,,First page of file to be displayed
+prompt,s,h,"",,,Prompt string if not filename
+device,s,h,"terminal",,,Output device
diff --git a/pkg/system/page.x b/pkg/system/page.x
new file mode 100644
index 00000000..208bb56b
--- /dev/null
+++ b/pkg/system/page.x
@@ -0,0 +1,41 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <fset.h>
+
+# PAGE -- Display a text file or files on the standard output (the user
+# terminal) one screen at a time, pausing after each screen has been filled.
+# The program is keystroke driven in raw mode, and currently recognizes the
+# keystrokes defined above.
+
+procedure t_page()
+
+bool redirin
+pointer sp, device, prompt, files
+int map_cc, clear_screen, first_page
+
+bool clgetb()
+int fstati(), clgeti(), btoi()
+
+begin
+ call smark (sp)
+ call salloc (device, SZ_FNAME, TY_CHAR)
+ call salloc (prompt, SZ_FNAME, TY_CHAR)
+ call salloc (files, SZ_LINE, TY_CHAR)
+
+ redirin = (fstati (STDIN, F_REDIR) == YES)
+ if (redirin)
+ call strcpy ("STDIN", Memc[files], SZ_LINE)
+ else
+ call clgstr ("files", Memc[files], SZ_LINE)
+
+ map_cc = btoi (clgetb ("map_cc"))
+ clear_screen = btoi (clgetb ("clear_screen"))
+ first_page = clgeti ("first_page")
+ call clgstr ("prompt", Memc[prompt], SZ_FNAME)
+ call clgstr ("device", Memc[device], SZ_FNAME)
+
+ call xpagefiles (Memc[files], Memc[device], Memc[prompt],
+ first_page, clear_screen, map_cc)
+
+ call sfree (sp)
+end
diff --git a/pkg/system/pathnames.par b/pkg/system/pathnames.par
new file mode 100644
index 00000000..20e6a230
--- /dev/null
+++ b/pkg/system/pathnames.par
@@ -0,0 +1,2 @@
+template,s,a,,,,file template
+sort,b,h,yes,,,sort file list
diff --git a/pkg/system/pathnames.x b/pkg/system/pathnames.x
new file mode 100644
index 00000000..86ee74f4
--- /dev/null
+++ b/pkg/system/pathnames.x
@@ -0,0 +1,55 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# PATHNAMES -- Convert one or more filenames into OS pathnames. If the input
+# is redirected, filenames are read from the standard input. Otherwise,
+# a file name template is expanded and used as the list of filenames to be
+# transformed. If called without any arguments, return the pathname of the
+# current working directory.
+
+procedure t_pathnames()
+
+int list
+pointer sp, fname, osfname
+bool streq(), clgetb()
+int clgeti(), clpopni(), clpopnu(), clgfil(), fscan()
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_LINE, TY_CHAR)
+ call salloc (osfname, SZ_LINE, TY_CHAR)
+
+ # If no arguments, return the pathame of the current
+ # directory: do not prompt for the template.
+
+ if (clgeti ("$nargs") == 0) {
+ call fpathname ("", Memc[osfname], SZ_LINE)
+ call printf ("%s\n")
+ call pargstr (Memc[osfname])
+ call sfree (sp)
+ return
+ }
+
+ # Expand template, output pathname of each file therein.
+ if (clgetb ("sort"))
+ list = clpopni ("template")
+ else
+ list = clpopnu ("template")
+
+ while (clgfil (list, Memc[fname], SZ_FNAME) != EOF) {
+ if (streq (Memc[fname], "STDIN")) {
+ while (fscan (STDIN) != EOF) {
+ call gargstr (Memc[fname], SZ_LINE)
+ call fpathname (Memc[fname], Memc[osfname], SZ_LINE)
+ call printf ("%s\n")
+ call pargstr (Memc[osfname])
+ }
+ } else {
+ call fpathname (Memc[fname], Memc[osfname], SZ_LINE)
+ call printf ("%s\n")
+ call pargstr (Memc[osfname])
+ }
+ }
+
+ call clpcls (list)
+ call sfree (sp)
+end
diff --git a/pkg/system/phelp.cl b/pkg/system/phelp.cl
new file mode 100644
index 00000000..4de3eab2
--- /dev/null
+++ b/pkg/system/phelp.cl
@@ -0,0 +1,41 @@
+# PHELP -- Paged help.
+
+procedure phelp (template)
+
+string template {prompt="module name template"}
+
+bool file_template=no {prompt="print help file"}
+bool all=yes {prompt="find all modules matching template"}
+string parameter="all" {prompt="parameter for which help is desired"}
+string section="all" {prompt="section for which help is desired"}
+string option="help" {prompt="type of help desired"}
+int lmargin=1 {min=1, prompt="left margin"}
+int rmargin=72 {min=2, prompt="right margin"}
+string helpdb="helpdb" {prompt="help database to be used"}
+
+begin
+ file helptext
+ string s_template
+
+ # Get a temp file to hold help text.
+ helptext = mktemp ("tmp$htx")
+ s_template = template
+
+ # Run HELP, redirecting the output to the temp file.
+ help (s_template, > helptext, page=no,
+ all = all,
+ file_template = file_template,
+ parameter = parameter,
+ section = section,
+ option = option,
+ lmargin = lmargin,
+ rmargin = rmargin,
+ device = "terminal",
+ helpdb = helpdb)
+
+ # Page saved text output.
+ page (helptext, prompt = s_template)
+
+ # Delete temp file.
+ delete (helptext, verify-)
+end
diff --git a/pkg/system/protect.par b/pkg/system/protect.par
new file mode 100644
index 00000000..cb9721ac
--- /dev/null
+++ b/pkg/system/protect.par
@@ -0,0 +1 @@
+files,s,a,,,,list of files to be protected
diff --git a/pkg/system/protect.x b/pkg/system/protect.x
new file mode 100644
index 00000000..4ed12db9
--- /dev/null
+++ b/pkg/system/protect.x
@@ -0,0 +1,23 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <protect.h>
+include <error.h>
+
+# PROTECT -- Protect a list of files.
+
+procedure t_protect()
+
+char fname[SZ_FNAME]
+int list, status
+
+int clpopns(), clgfil(), protect()
+
+begin
+ list = clpopns ("files")
+
+ while (clgfil (list, fname, SZ_FNAME) != EOF)
+ iferr (status = protect (fname, SET_PROTECTION))
+ call erract (EA_WARN)
+
+ call clpcls (list)
+end
diff --git a/pkg/system/references.cl b/pkg/system/references.cl
new file mode 100644
index 00000000..ca93e6a6
--- /dev/null
+++ b/pkg/system/references.cl
@@ -0,0 +1,50 @@
+# REFERENCES -- Search the help database for help on a given subject.
+# By default a runtime search is performed of all the package menus in the
+# help database, but the user may prepare a "quick-reference" file to speed
+# further searches if desired. This cannot easily be done automatically
+# since any set of packages may form the help database.
+#
+# NOTE -- Uses LISTS.
+
+procedure references (topic)
+
+string topic { prompt = "topic to find help for" }
+file quickref = "uparm$quick.ref" { prompt = "quick-reference file" }
+bool updquick = no { prompt = "update quick-reference file" }
+bool usequick = no { prompt = "use quick-reference file" }
+
+begin
+ string pattern
+ file fname
+
+ # Make a quick-search file if so requested.
+ if (updquick) {
+ fname = quickref
+ print ("generating new quick-reference file " // fname // "...")
+ if (access (fname))
+ delete (fname, verify-)
+ help ("[a-z]*.", option="ref", curpack="AsckCL", device="terminal",
+ helpdb="helpdb") |& match ("-", metacharacters=yes) |
+ sort(ignore+) | unique ( > fname)
+ references.quickref = fname
+ references.usequick = yes
+
+ } else {
+ # Ignore case.
+ pattern = ("{" // topic // "}")
+
+ # If the user has prepared a quick-search file (e.g., by running
+ # this task with topic=* and saving the output to make the quick
+ # file), search that if it exists, otherwise perform a runtime
+ # search of the package menu files for the entire help database.
+
+ if (usequick && access (quickref))
+ match (pattern, quickref, metacharacters=yes)
+ else {
+ print ("searching the help database...")
+ help ("[a-z]*.", section="all", option="ref", curpack="AsckCL",
+ device="terminal", helpdb="helpdb") |& sort(ignore+) |
+ unique | match (pattern, metacharacters=yes)
+ }
+ }
+end
diff --git a/pkg/system/rename.par b/pkg/system/rename.par
new file mode 100644
index 00000000..b7e19293
--- /dev/null
+++ b/pkg/system/rename.par
@@ -0,0 +1,3 @@
+files,s,a,,,,list of files to be renamed
+newname,s,a,,,,new file name or field name
+field,s,h,all,"|all|ldir|root|extn|",,field to be modified (all|ldir|root|extn)
diff --git a/pkg/system/rename.x b/pkg/system/rename.x
new file mode 100644
index 00000000..95cf395c
--- /dev/null
+++ b/pkg/system/rename.x
@@ -0,0 +1,176 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+
+define F_ALL 0
+define F_LDIR 1
+define F_ROOT 2
+define F_EXTN 3
+
+
+# RENAME -- Rename a file, or rename a list of files. In the latter case
+# the ldir, root, or extn field in each of the input files is changed to
+# the value of the "output file", which in this case is the value of the
+# specified field of an output file name. Thus,
+#
+# cl> rename task.* newtask
+#
+# would rename task.x as newtask.x, task.cl as newtask.cl, and so on.
+# If 'newtask' is a logical or host directory the input files are moved to
+# this directory with the same name.
+
+procedure t_rename()
+
+bool isdir
+pointer sp, oldfile, newname, field
+pointer o_ldir, o_root, o_extn, n_ldir, n_root, n_extn
+pointer pathname, newfile, junkstr
+int list, len, modfield
+
+bool streq()
+int clpopni(), clgfil(), clplen(), stridxs()
+int access(), fnldir(), fnroot(), fnextn(), isdirectory()
+string s_clobber "Warning: %s would overwrite existing file %s - skipping\n"
+
+begin
+ call smark (sp)
+ call salloc (oldfile, SZ_FNAME, TY_CHAR)
+ call salloc (newname, SZ_PATHNAME, TY_CHAR)
+ call salloc (pathname, SZ_PATHNAME, TY_CHAR)
+ call salloc (newfile, SZ_PATHNAME, TY_CHAR)
+ call salloc (junkstr, SZ_FNAME, TY_CHAR)
+ call salloc (field, SZ_FNAME, TY_CHAR)
+ call salloc (o_ldir, SZ_FNAME, TY_CHAR)
+ call salloc (n_ldir, SZ_FNAME, TY_CHAR)
+ call salloc (o_root, SZ_FNAME, TY_CHAR)
+ call salloc (n_root, SZ_FNAME, TY_CHAR)
+ call salloc (o_extn, SZ_FNAME, TY_CHAR)
+ call salloc (n_extn, SZ_FNAME, TY_CHAR)
+
+ # Open the list of files to be renamed. This is done first so that
+ # the old file name is queried for before the new file name.
+
+ list = clpopni ("files")
+
+ # Get the output file name, or the new name for the field to be
+ # changed.
+
+ call clgstr ("newname", Memc[newname], SZ_PATHNAME)
+ call clgstr ("field", Memc[field], SZ_FNAME)
+
+ if (streq (Memc[field], "ldir"))
+ modfield = F_LDIR
+ else if (streq (Memc[field], "root"))
+ modfield = F_ROOT
+ else if (streq (Memc[field], "extn"))
+ modfield = F_EXTN
+ else if (streq (Memc[field], "all"))
+ modfield = F_ALL
+ else {
+ call clpcls (list)
+ call error (1, "rename: unrecognized filename field code")
+ }
+
+ # See if we're modifying the logical directory, If so, move the input
+ # files to this directory, otherwise do the renaming as we've always
+ # done.
+
+ Memc[pathname] = EOS
+ isdir = (isdirectory (Memc[newname], Memc[pathname], SZ_PATHNAME) > 0)
+
+ if (isdir || modfield == F_LDIR) {
+ # Move each of the files in the list to the destination dir.
+ call fdirname (Memc[newname], Memc[n_ldir], SZ_FNAME)
+
+ while (clgfil (list, Memc[oldfile], SZ_FNAME) != EOF) {
+ if (Memc[pathname] != EOS)
+ call strcpy (Memc[pathname], Memc[newfile], SZ_PATHNAME)
+ else
+ call strcpy (Memc[n_ldir], Memc[newfile], SZ_PATHNAME)
+ len = fnldir (Memc[oldfile], Memc[junkstr], SZ_FNAME)
+ call strcat (Memc[oldfile+len], Memc[newfile], SZ_PATHNAME)
+
+ iferr (call rename (Memc[oldfile], Memc[newfile]))
+ call erract (EA_WARN)
+ }
+
+ } else if (modfield == F_ALL) {
+ # "newname" is the new filename. This makes sense only if there
+ # is a single input filename. Note that the new name may contain
+ # a new logical directory, renaming both the file and moving it # to a new directory.
+
+ if (clplen (list) > 1)
+ call error (2, "rename: `newname' must be a directory")
+
+ # Rename the file.
+ if (clgfil (list, Memc[oldfile], SZ_FNAME) != EOF)
+ iferr (call rename (Memc[oldfile], Memc[newname]))
+ call erract (EA_WARN)
+
+ } else {
+ # We're either modifying the root or the extension. Break out
+ # the ldir, root and extn for the input and output file names
+ # then construct the new name from these components.
+
+ Memc[n_root] = EOS
+ Memc[n_extn] = EOS
+
+ if (modfield == F_ROOT) {
+ call strcpy (Memc[newname], Memc[n_root], SZ_FNAME)
+ if (stridxs ("$/", Memc[n_root]) > 0) {
+ call clpcls (list)
+ call error (3, "rename: bad replacement root field")
+ }
+ }
+ if (modfield == F_EXTN) {
+ call strcpy (Memc[newname], Memc[n_extn], SZ_FNAME)
+ if (stridxs ("$/", Memc[n_extn]) > 0) {
+ call clpcls (list)
+ call error (4, "rename: bad replacement extn field")
+ }
+ }
+
+ # Process the files.
+ while (clgfil (list, Memc[oldfile], SZ_FNAME) != EOF) {
+
+ # Get the ldir, root and extension names of the old filename.
+ len = fnroot (Memc[oldfile], Memc[o_root], SZ_FNAME)
+ len = fnextn (Memc[oldfile], Memc[o_extn], SZ_FNAME)
+ len = fnldir (Memc[oldfile], Memc[o_ldir], SZ_PATHNAME)
+
+ # Start by copying the ldir to the new name.
+ call aclrc (Memc[newname], SZ_PATHNAME)
+ call strcpy (Memc[o_ldir], Memc[newname], SZ_PATHNAME)
+
+ # Build up the new file name.
+ if (modfield == F_ROOT) {
+ call strcat (Memc[n_root], Memc[newname], SZ_FNAME)
+ if (Memc[o_extn] != EOS) {
+ call strcat (".", Memc[newname], SZ_PATHNAME)
+ call strcat (Memc[o_extn], Memc[newname], SZ_FNAME)
+ }
+ } else if (modfield == F_EXTN) {
+ call strcat (Memc[o_root], Memc[newname], SZ_FNAME)
+ call strcat (".", Memc[newname], SZ_PATHNAME)
+ call strcat (Memc[n_extn], Memc[newname], SZ_FNAME)
+ }
+
+ # Check to see if we're going to clobber a file.
+ if (clplen (list) > 1) {
+ if (access (Memc[newname], 0, 0) == YES) {
+ call eprintf (s_clobber)
+ call pargstr (Memc[oldfile])
+ call pargstr (Memc[newname])
+ next
+ }
+ }
+
+ # Rename the file.
+ iferr (call rename (Memc[oldfile], Memc[newname]))
+ call erract (EA_WARN)
+ }
+ }
+
+ call clpcls (list)
+ call sfree (sp)
+end
diff --git a/pkg/system/rewind.par b/pkg/system/rewind.par
new file mode 100644
index 00000000..714a56bf
--- /dev/null
+++ b/pkg/system/rewind.par
@@ -0,0 +1,2 @@
+device,f,a,mta,,,device to be rewound
+initcache,b,h,yes,,,discard cached information on tape contents
diff --git a/pkg/system/rewind.x b/pkg/system/rewind.x
new file mode 100644
index 00000000..9316b212
--- /dev/null
+++ b/pkg/system/rewind.x
@@ -0,0 +1,14 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# REWIND -- Rewind a (previously allocated) magtape device.
+
+procedure t_rewind()
+
+char device[SZ_FNAME]
+bool clgetb()
+int btoi()
+
+begin
+ call clgstr ("device", device, SZ_FNAME)
+ call mtrewind (device, btoi(clgetb("initcache")))
+end
diff --git a/pkg/system/sort.com b/pkg/system/sort.com
new file mode 100644
index 00000000..4b66ac5f
--- /dev/null
+++ b/pkg/system/sort.com
@@ -0,0 +1,10 @@
+# Common for the SORT program.
+
+int column # column to be sorted (if nonzero)
+int ignore_whitespace # ignore leading whitespace
+int numeric_sort # sort numerically rather than alphabetically
+int reverse_sort # reverse the sense of the sort
+int use_strsrt # ok to use standard STRSRT routine?
+
+common /srtcom/ column, ignore_whitespace, numeric_sort, reverse_sort,
+ use_strsrt
diff --git a/pkg/system/sort.par b/pkg/system/sort.par
new file mode 100644
index 00000000..84d721a3
--- /dev/null
+++ b/pkg/system/sort.par
@@ -0,0 +1,5 @@
+input_file,s,a,,,,file to be sorted
+column,i,h,0,,,column to be sorted (if nonzero)
+ignore_whitespace,b,h,no,,,ignore leading whitespace
+numeric_sort,b,h,no,,,sort numerically rather than alphabetically
+reverse_sort,b,h,no,,,reverse the sense of the sort
diff --git a/pkg/system/sort.x b/pkg/system/sort.x
new file mode 100644
index 00000000..e53b5fd8
--- /dev/null
+++ b/pkg/system/sort.x
@@ -0,0 +1,434 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+
+# SORT -- Sort a text file, alphabetically or numerically, in forward or
+# reverse order, by line or by the contents of any column. Derived from
+# Chap. 4 of Software Tools. This is old code, not very pretty.
+
+define MERGEORDER 8
+define MAXPTR 20000
+define SZ_LINBUF 200000
+define LOGPTR 32
+define swap {temp=$1;$1=$2;$2=temp}
+
+
+# SORT -- The main CL callable routine.
+
+procedure t_sort()
+
+pointer linbuf, linptr
+int infil[MERGEORDER], nlines
+char name[SZ_FNAME], source_file[SZ_FNAME]
+int high, lim, low, fd, outfil, t, list, junk
+
+bool clgetb()
+int ss_gtext(), ss_mkfile()
+int open(), clpopni(), clplen(), clgfil(), clgeti(), btoi()
+include "sort.com"
+
+begin
+ list = clpopni ("input_file")
+ if (clplen (list) > 1) {
+ call clpcls (list)
+ call error (1, "Cannot yet sort more than one file at a time")
+ }
+
+ # Determine type of sort to be applied.
+ column = clgeti ("column")
+ numeric_sort = btoi (clgetb ("numeric_sort"))
+ reverse_sort = btoi (clgetb ("reverse_sort"))
+
+ ignore_whitespace = NO
+ if (column == 0 && numeric_sort == NO)
+ if (clgetb ("ignore_whitespace"))
+ ignore_whitespace = YES
+
+ # The standard STRSRT is fastest if we can use it.
+ use_strsrt = NO
+ if (ignore_whitespace == NO && numeric_sort == NO &&
+ reverse_sort == NO && column == 0)
+ use_strsrt = YES
+
+ # Allocate buffer space.
+ call malloc (linbuf, SZ_LINBUF, TY_CHAR)
+ call malloc (linptr, MAXPTR, TY_INT)
+
+ # Perform the sort.
+ junk = clgfil (list, source_file, SZ_FNAME)
+ fd = open (source_file, READ_ONLY, TEXT_FILE)
+
+ # Initial formation of runs.
+ high = 0
+ repeat {
+ t = ss_gtext (fd, Memi[linptr], nlines, Memc[linbuf])
+ if (use_strsrt == YES)
+ call strsrt (Memi[linptr], Memc[linbuf], nlines)
+ else
+ call ss_quick (Memi[linptr], Memc[linbuf], nlines)
+
+ high = high + 1
+ outfil = ss_mkfile (high)
+ call ss_ptext (outfil, Memi[linptr], nlines, Memc[linbuf])
+ call close (outfil)
+
+ } until (t == EOF)
+
+ # Merge sorted chunks.
+ for (low = 1; low < high; low = low + MERGEORDER) {
+ lim = min (low + MERGEORDER - 1, high)
+ call ss_gopen (infil, low, lim)
+ high = high + 1
+ outfil = ss_mkfile (high)
+ call ss_merge (infil, outfil, lim - low + 1)
+ call close (outfil)
+ call ss_gremov (infil, low, lim)
+ }
+
+ call mfree (linbuf, TY_CHAR)
+ call mfree (linptr, TY_INT)
+
+ call ss_gname (high, name) # final cleanup
+ outfil = open (name, READ_ONLY, TEXT_FILE)
+ call fcopyo (outfil, STDOUT)
+ call close (outfil)
+
+ call delete (name)
+ call close (fd)
+end
+
+
+# SS_MKFILE -- Open a temporary file.
+
+int procedure ss_mkfile (n)
+
+int n
+char name[SZ_FNAME]
+int open()
+errchk open, ss_gname
+
+begin
+ call ss_gname (n, name)
+ return (open (name, NEW_FILE, TEXT_FILE))
+end
+
+
+# SS_GNAME -- Quickie routine to generate a temporary file name in tmp$ (the
+# original tools version would put the temp files in the cwd). Make a name
+# of the form "tmp$srtPID_XX", where XX is the file number argument N,
+# and PID is the process pid. The tools sort code requires that the file
+# name be easily reproduced given only N, so we cannot use mktemp.
+
+procedure ss_gname (n, name)
+
+int n
+char name[ARB]
+int pid
+
+begin
+ call zgtpid (pid)
+ call sprintf (name, SZ_FNAME, "tmp$srt%d_%d")
+ call pargi (pid)
+ call pargi (n)
+end
+
+
+# SS_GOPEN -- Open a range of files.
+
+procedure ss_gopen (infil, low, lim)
+
+int infil[ARB], lim, low
+char name[SZ_FNAME]
+int i, open()
+errchk open, ss_gname
+
+begin
+ for (i=1; i <= lim-low+1; i=i+1) {
+ call ss_gname (low+i-1, name)
+ infil[i] = open (name, READ_ONLY, TEXT_FILE)
+ }
+end
+
+
+# SS_GREMOV -- Remove a range of files.
+
+procedure ss_gremov (infil, low, lim)
+
+int infil[ARB], low, lim
+
+int i
+char name[SZ_FNAME]
+errchk ss_gname, delete, close
+
+begin
+ for (i=1; i <= lim-low+1; i=i+1) {
+ call close (infil[i])
+ call ss_gname (low+i-1, name)
+ call delete (name)
+ }
+end
+
+
+# SS_MERGE -- Merge file onto outfil.
+
+procedure ss_merge (infil, outfil, nfiles)
+
+int infil[ARB] # input file numbers
+int outfil # output file number
+int nfiles # number of files to be merged
+
+pointer sp, linbuf
+int linptr[MERGEORDER]
+int i, inf, lbp, lp1, nf
+int getline()
+errchk getline, putline, ss_quick
+include "sort.com"
+
+begin
+ call smark (sp)
+ call salloc (linbuf, MERGEORDER * SZ_LINE, TY_CHAR)
+
+ lbp = 1
+ nf = 0
+
+ # Get one line from each file.
+ for (i=1; i <= nfiles; i=i+1) {
+ if (getline (infil[i], Memc[linbuf+lbp-1]) != EOF) {
+ nf = nf + 1
+ linptr[nf] = lbp
+ lbp = lbp + SZ_LINE
+ }
+ }
+
+ # Make initial heap.
+ if (use_strsrt == YES)
+ call strsrt (linptr, Memc[linbuf], nf)
+ else
+ call ss_quick (linptr, Memc[linbuf], nf)
+
+ while (nf > 0) {
+ lp1 = linptr[1]
+ call putline (outfil, Memc[linbuf+lp1-1])
+ inf = lp1 / SZ_LINE + 1 # compute file index
+ if (getline (infil[inf], Memc[linbuf+lp1-1]) == EOF) {
+ linptr[1] = linptr[nf]
+ nf = nf - 1
+ }
+ call ss_reheap (linptr, Memc[linbuf], nf)
+ }
+
+ call sfree (sp)
+end
+
+
+# SS_REHEAP -- propagate linbuf[linptr[1]] to proper place in heap.
+
+procedure ss_reheap (linptr, linbuf, nf)
+
+int linptr[ARB]
+char linbuf[ARB]
+int nf
+
+int i, j, temp
+int ss_compare()
+
+begin
+ for (i=1; 2 * i <= nf; i=j) {
+ j = 2 * i
+ if (j < nf) # find smaller child
+ if (ss_compare (linptr[j], linptr[j+1], linbuf) > 0)
+ j = j + 1
+ if (ss_compare (linptr[i], linptr[j], linbuf) <= 0)
+ break # proper position found
+
+ swap (linptr[i], linptr[j])
+ }
+end
+
+
+# SS_QUICK -- Quicksort for text data. NOTE -- This algorithm is quadratic in
+# the worst case, i.e., when the data is already sorted. A random method of
+# selecting the pivot should be used to improve the behaviour on sorted arrays.
+
+procedure ss_quick (linptr, linbuf, nlines)
+
+int linptr[ARB] # indices of strings in buffer
+char linbuf[ARB] # string buffer
+int nlines # number of strings
+
+int i, j, k, temp, lv[LOGPTR], p, pivlin, uv[LOGPTR]
+int ss_compare()
+
+begin
+ lv[1] = 1
+ uv[1] = nlines
+ p = 1
+
+ while (p > 0) {
+ if (lv[p] >= uv[p]) # only one elem in this subset
+ p = p - 1 # pop stack
+ else {
+ # Dummy loop to trigger optimizer.
+ do p = p, ARB {
+ i = lv[p] - 1
+ j = uv[p]
+
+ # Select pivot element at midpoint of interval to avoid
+ # quadratic behavior on a sorted list.
+
+ k = (lv[p] + uv[p]) / 2
+ swap (linptr[j], linptr[k])
+ pivlin = linptr[j]
+
+ while (i < j) {
+ for (i=i+1; ss_compare (linptr[i], pivlin, linbuf) < 0;
+ i=i+1)
+ ;
+ for (j=j-1; j > i; j=j-1)
+ if (ss_compare (linptr[j], pivlin, linbuf) <= 0)
+ break
+ if (i < j) # out of order pair
+ swap (linptr[i], linptr[j])
+ }
+
+ j = uv[p] # move pivot to position i
+ swap (linptr[i], linptr[j])
+
+ if (i-lv[p] < uv[p] - i) { # stack so shorter done first
+ lv[p+1] = lv[p]
+ uv[p+1] = i - 1
+ lv[p] = i + 1
+ } else {
+ lv[p+1] = i + 1
+ uv[p+1] = uv[p]
+ uv[p] = i - 1
+ }
+
+ break
+ }
+
+ p = p + 1 # push onto stack
+ }
+ }
+end
+
+
+# SS_COMPARE -- Compare two strings. Return -1 if str1<str2, 1 if str1>str2,
+# or 0 if the two strings are equal.
+
+int procedure ss_compare (lp1, lp2, linbuf)
+
+int lp1, lp2 # pointers to substrings in linbuf
+char linbuf[ARB] # text buffer
+
+double num1, num2
+int ip1, ip2, answer, len1, len2
+int strcmp(), ss_findcolumn(), gctod()
+include "sort.com"
+
+begin
+ if (column != 0) {
+ ip1 = ss_findcolumn (linbuf, lp1, column)
+ ip2 = ss_findcolumn (linbuf, lp2, column)
+ } else if (ignore_whitespace == YES) {
+ for (ip1=lp1; IS_WHITE(linbuf[ip1]); ip1=ip1+1)
+ ;
+ for (ip2=lp2; IS_WHITE(linbuf[ip2]); ip2=ip2+1)
+ ;
+ } else {
+ ip1 = lp1
+ ip2 = lp2
+ }
+
+ if (numeric_sort == YES) {
+ len1 = gctod (linbuf, ip1, num1)
+ len2 = gctod (linbuf, ip2, num2)
+
+ # If fields are nonnumeric, compare as strings.
+ if (len1 == 0 || len2 == 0)
+ answer = strcmp (linbuf[ip1-len1], linbuf[ip2-len2])
+ else if (num1 < num2)
+ answer = -1
+ else if (num1 > num2)
+ answer = 1
+ else
+ answer = 0
+ } else
+ answer = strcmp (linbuf[ip1], linbuf[ip2])
+
+ if (reverse_sort == YES)
+ return (-answer)
+ else
+ return (answer)
+end
+
+
+# SS_FINDCOLUMN -- Determine the offset of the first character in the
+# desired column.
+
+int procedure ss_findcolumn (buf, start, column)
+
+char buf[ARB]
+int start, column
+int ip, col
+
+begin
+ for (ip=start; IS_WHITE(buf[ip]); ip=ip+1)
+ ;
+ for (col=1; col < column; col=col+1) {
+ for (; !IS_WHITE(buf[ip]) && buf[ip] != EOS; ip=ip+1)
+ ;
+ for (; IS_WHITE(buf[ip]); ip=ip+1)
+ ;
+ }
+
+ return (ip)
+end
+
+
+# SS_GTEXT -- Get text lines into linbuf.
+
+int procedure ss_gtext (infile, linptr, nlines, linbuf)
+
+int infile, linptr[ARB], nlines
+char linbuf[ARB]
+
+int lbp, len, getline()
+errchk getline
+
+begin
+ nlines = 0
+ lbp = 1
+
+ repeat {
+ len = getline (infile, linbuf[lbp])
+ if (len == EOF)
+ break
+ else if (len == 1)
+ # ignore blank lines
+ else {
+ nlines = nlines + 1
+ linptr[nlines] = lbp
+ lbp = lbp + len + 1 # '1' = room for EOS
+ }
+ } until (lbp >= SZ_LINBUF - SZ_LINE || nlines >= MAXPTR)
+
+ return (len)
+end
+
+
+# SS_PTEXT -- Output text lines from linbuf to outfile.
+
+procedure ss_ptext (outfil, linptr, nlines, linbuf)
+
+int outfil, linptr[ARB], nlines
+char linbuf[ARB]
+int i, j
+errchk putline
+
+begin
+ for (i=1; i <= nlines; i=i+1) {
+ j = linptr[i]
+ call putline (outfil, linbuf[j])
+ }
+end
diff --git a/pkg/system/system.cl b/pkg/system/system.cl
new file mode 100644
index 00000000..1e114d72
--- /dev/null
+++ b/pkg/system/system.cl
@@ -0,0 +1,55 @@
+lists
+
+#{ SYSTEM.CL -- Package script task for the SYSTEM package. This package is
+# loaded by the CL upon startup, and is always in the search path.
+
+package system
+
+task cmdstr,
+ chkupdate,
+ concatenate,
+ copy,
+ count,
+ delete,
+ directory,
+ files,
+ head,
+ lprint,
+ match,
+ mkdir,
+ movefiles,
+ mtclean,
+ $netstatus,
+ page,
+ pathnames,
+ protect,
+ rename,
+ sort,
+ tail,
+ tee,
+ touch,
+ type,
+ rewind,
+ unprotect,
+ fcache,
+ urlget,
+ help = "system$x_system.e"
+
+task mkscript = "system$mkscript.cl"; hidetask cmdstr
+task $news = "system$news.cl"
+task $bench = "system$bench.cl"
+
+task allocate = "hlib$allocate.cl"
+task gripes = "hlib$gripes.cl"
+task deallocate = "hlib$deallocate.cl"
+task devstatus = "hlib$devstatus.cl"
+task $diskspace = "hlib$diskspace.cl"
+task $spy = "hlib$spy.cl"
+
+task $devices = "system$devices.cl"
+task references = "system$references.cl"
+task phelp = "system$phelp.cl"
+
+hidetask mtclean
+
+keep
diff --git a/pkg/system/system.hd b/pkg/system/system.hd
new file mode 100644
index 00000000..be4b1bbe
--- /dev/null
+++ b/pkg/system/system.hd
@@ -0,0 +1,47 @@
+# Help directory for the SYSTEM package.
+
+$defdir = "system$"
+$doc = "system$doc/"
+$help = "system$help/"
+
+allocate hlp=doc$allocate.hlp, src=hlib$allocate.cl
+concatenate hlp=doc$concatenate.hlp, src=concatenate.x
+chkupdate hlp=doc$chkupdate.hlp, src=chkupdate.x
+copy hlp=doc$copy.hlp, src=copy.x
+count hlp=doc$count.hlp, src=count.x
+deallocate hlp=doc$deallocate.hlp, src=hlib$deallocate.cl
+delete hlp=doc$delete.hlp, src=delete.x
+devices hlp=dev$devices.hlp, src=devices.cl
+devstatus hlp=doc$devstatus.hlp, src=hlib$devstatus.cl
+directory hlp=doc$directory.hlp, src=directory.x
+diskspace hlp=doc$diskspace.hlp, src=hlib$diskspace.cl
+fcache hlp=doc$fcache.hlp, src=t_fcache.x
+files hlp=doc$files.hlp, src=files.x
+gripes hlp=doc$gripes.hlp, src=hlib$gripes.cl
+head hlp=doc$head.hlp, src=head.x
+help hlp=doc$help.hlp, src=help$t_help.x
+lprint hlp=doc$lprint.hlp, src=lprint.x
+match hlp=doc$match.hlp, src=match.x
+mkdir hlp=doc$mkdir.hlp, src=mkdir.x
+mkscript hlp=doc$mkscript.hlp, src=mkscript.cl
+movefiles hlp=doc$movefiles.hlp, src=movefiles.x
+news hlp=doc$news.hlp, src=news.cl
+netstatus hlp=doc$netstatus.hlp, src=netstatus.x
+page hlp=doc$page.hlp, src=page.x
+pathnames hlp=doc$pathnames.hlp, src=pathnames.x
+phelp hlp=doc$phelp.hlp, src=phelp.cl
+protect hlp=doc$protect.hlp, src=protect.x
+references hlp=doc$references.hlp, src=references.cl
+rename hlp=doc$rename.hlp, src=rename.x
+revisions hlp=doc$revisions.hlp, src=revisions.cl
+rewind hlp=doc$rewind.hlp, src=rewind.x
+sleep hlp=doc$sleep.hlp, src=sleep.x
+sort hlp=doc$sort.hlp, src=sort.x
+spy hlp=doc$spy.hlp, src=hlib$spy.cl
+system hlp=doc$system.hlp, src=system.cl
+tail hlp=doc$tail.hlp, src=tail.x
+tee hlp=doc$tee.hlp, src=tee.x
+touch hlp=doc$touch.hlp, src=touch.x
+type hlp=doc$type.hlp, src=type.x
+urlget hlp=doc$urlget.hlp, src=urlget.x
+unprotect hlp=doc$unprotect.hlp, src=unprotect.x
diff --git a/pkg/system/system.men b/pkg/system/system.men
new file mode 100644
index 00000000..b79ae550
--- /dev/null
+++ b/pkg/system/system.men
@@ -0,0 +1,39 @@
+ allocate - Allocate a device, i.e., magtape drive mta, mtb, ...
+ concatenate - Concatenate a list of files
+ chkupdate - Check for an available IRAF update
+ copy - Copy a file or files (use IMCOPY for imagefiles)
+ count - Count the number of lines, words, characters in a text file
+ deallocate - Deallocate a previously allocated device
+ delete - Delete a file or files (use IMDELETE to delete imagefiles)
+ devices - Print information on the locally available devices
+ devstatus - Print the status of a device (mta, mtb, ...)
+ directory - List the files in a directory
+ diskspace - Show how much diskspace is available
+ fcache - List, clean or manipulate the file cache
+ files - Expand a file template into a list of files
+ gripes - Send suggestions, complaints, etc. to the system
+ head - Print the first few lines of a text file
+ help - Print online documentation
+ lprint - Print a file on the line printer device
+ match - Print all lines in a file that match a pattern
+ mkdir - Create a new directory
+ mkscript - Make a command script
+ movefiles - Move files to a directory
+ netstatus - Print the status of the local network
+ news - Page through the system news file
+ page - Page through a file
+ pathnames - Expand a file template into a list of OS pathnames
+ phelp - Paged HELP: collects and pages the output of HELP
+ protect - Protect a file from deletion
+ references - Find all help database references for a given topic
+ rename - Rename a file
+ rewind - Rewind a device (magtape)
+ sort - Sort a text file
+ spy - Show processor status
+ system - Simple benchmarking tool
+ tail - Print the last few lines of a file
+ tee - Tee the standard output into a file
+ touch - Change file access and modification times
+ type - Type a text file on the standard output
+ urlget - Get a (http) URL to a named file
+ unprotect - Remove delete protection from a file
diff --git a/pkg/system/system.par b/pkg/system/system.par
new file mode 100644
index 00000000..238ccfcd
--- /dev/null
+++ b/pkg/system/system.par
@@ -0,0 +1,5 @@
+# Package parameter file for SYSTEM.
+
+version,s,h,"12-Nov-83"
+release,s,h,)cl.release,,,IRAF release version
+mode,s,h,ql
diff --git a/pkg/system/t_fcache.x b/pkg/system/t_fcache.x
new file mode 100644
index 00000000..236c33c4
--- /dev/null
+++ b/pkg/system/t_fcache.x
@@ -0,0 +1,118 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+
+define FC_CMDS "|init|purge|destroy|list|lookup|access|add|delete|wait|help|"
+
+define FC_INIT 1
+define FC_PURGE 2
+define FC_DESTROY 3
+define FC_LIST 4
+define FC_LOOKUP 5
+define FC_ACCESS 6
+define FC_ADD 7
+define FC_DELETE 8
+define FC_WAIT 9
+define FC_HELP 10
+
+
+# FCACHE -- Task interface to the file cache.
+
+procedure t_fcache ()
+
+char cmd[SZ_FNAME], cache[SZ_FNAME], fname[SZ_FNAME]
+char pattern[SZ_FNAME], src[SZ_FNAME], cname[SZ_FNAME], extn[SZ_FNAME]
+bool verbose, in_src, exists
+int age
+
+int strdic(), clgeti(), envgeti()
+bool clgetb(), fcaccess()
+
+begin
+ # Get the common parameters.
+ call clgstr ("cmd", cmd, SZ_FNAME)
+ call clgstr ("cache", cache, SZ_FNAME)
+ verbose = clgetb ("verbose")
+
+ # Process the requested command.
+ switch (strdic (cmd, cmd, SZ_FNAME, FC_CMDS)) {
+ case FC_INIT:
+ call clgstr ("pattern", pattern, SZ_FNAME)
+ call fcinit (cache, pattern)
+
+ case FC_PURGE:
+ age = clgeti ("age")
+ if (age < 0)
+ age = envgeti ("cache_age")
+ call fcpurge (cache, verbose, age)
+
+ case FC_DESTROY:
+ call fcdestroy (cache, verbose)
+
+ case FC_LIST:
+ call fclist (cache, verbose, STDOUT)
+
+ case FC_LOOKUP:
+ call clgstr ("src", src, SZ_FNAME)
+ if (src[1] != EOS) {
+ call fclookup (cache, src, fname, extn, SZ_FNAME)
+ if (verbose) {
+ call printf ("%s\n")
+ call pargstr (fname)
+ }
+ call clpstr ("fname", fname)
+ call clpstr ("extn", extn)
+ } else {
+ call clgstr ("fname", fname, SZ_FNAME)
+ call clgstr ("extn", extn, SZ_FNAME)
+ call fclookup (cache, src, fname, extn, SZ_FNAME)
+ if (verbose) {
+ call printf ("%s\n")
+ call pargstr (src)
+ }
+ call clpstr ("src", src)
+ }
+
+ case FC_ACCESS:
+ call clgstr ("src", src, SZ_FNAME)
+ call clgstr ("extn", extn, SZ_FNAME)
+
+ exists = fcaccess (cache, src, extn)
+ call printf ("%b\n")
+ call pargb (exists)
+
+ case FC_ADD:
+ call clgstr ("src", src, SZ_FNAME)
+ call clgstr ("extn", extn, SZ_FNAME)
+ call fcadd (cache, src, extn, cname, SZ_FNAME)
+ if (verbose) {
+ call eprintf ("%s\n")
+ call pargstr (cname)
+ }
+ call clpstr ("fname", cname)
+ if (clgetb ("wait"))
+ call fcwait (cache, cname)
+
+ case FC_DELETE:
+ call clgstr ("src", src, SZ_FNAME)
+ if (src[1] != EOS) {
+ # Delete by src string.
+ call fclookup (cache, src, fname, extn, SZ_FNAME)
+ call fcdelete (cache, fname)
+ } else {
+ # Delete by cached filename.
+ call clgstr ("fname", fname, SZ_FNAME)
+ call fcdelete (cache, fname)
+ }
+
+ case FC_WAIT:
+ call clgstr ("src", src, SZ_FNAME)
+ call fcwait (cache, src)
+
+ case FC_HELP:
+
+ default:
+ call eprintf ("Unknown command '%s'\n")
+ call pargstr (cmd)
+ }
+end
diff --git a/pkg/system/t_urlget.x b/pkg/system/t_urlget.x
new file mode 100644
index 00000000..d1c234df
--- /dev/null
+++ b/pkg/system/t_urlget.x
@@ -0,0 +1,96 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <syserr.h>
+include <imhdr.h>
+include <imset.h>
+include <mach.h>
+
+
+
+# URLGET -- Do an HTTP GET of a URL to the named file.
+
+procedure t_urlget ()
+
+pointer reply
+char url[SZ_PATHNAME], fname[SZ_PATHNAME], extn[SZ_PATHNAME]
+char cache[SZ_PATHNAME], lfname[SZ_PATHNAME]
+int nread
+bool use_cache, verbose
+
+int nargs, clgeti(), url_get()
+bool clgetb(), fcaccess()
+
+begin
+ # Get the parameters
+ call clgstr ("url", url, SZ_PATHNAME)
+ nargs = clgeti ("$nargs")
+ if (nargs < 2) {
+ # No output name specified, so create one from URL
+ call url_to_name (url, fname, SZ_PATHNAME)
+ } else
+ call clgstr ("fname", fname, SZ_PATHNAME)
+ call clgstr ("extn", extn, SZ_PATHNAME)
+ call clgstr ("cache", cache, SZ_PATHNAME)
+ verbose = clgetb ("verbose")
+ use_cache = clgetb ("use_cache")
+
+
+ # Tell them what we're doing.
+ if (verbose) {
+ call printf ("%s -> %s\n")
+ call pargstr (url)
+ call pargstr (fname)
+ call flush (STDOUT)
+ }
+
+ # Retrieve the URL.
+ if (use_cache) {
+ call aclrc (lfname, SZ_FNAME);
+
+ if (fcaccess (cache, url, "fits")) {
+ call fcname (cache, url, "f", lfname, SZ_PATHNAME)
+ if (extn[1] != EOS) {
+ # Add an extension to the cached file.
+ call strcat (".", lfname, SZ_PATHNAME)
+ call strcat (extn, lfname, SZ_PATHNAME)
+ }
+ } else {
+ # Add it to the cache, also handles the download.
+ call fcadd (cache, url, extn, lfname, SZ_PATHNAME)
+ }
+ call fcopy (lfname, fname)
+
+ } else {
+ # Not in cache, or not using the cache, so force the download.
+ call calloc (reply, SZ_LINE, TY_CHAR)
+ nread = url_get (url, fname, reply)
+ call mfree (reply, TY_CHAR)
+ }
+end
+
+
+# URL_TO_NAME -- Generate a filename from a URL.
+
+procedure url_to_name (url, name, maxch)
+
+char url[ARB] #i URL being accessed
+char name[ARB] #o output name
+int maxch #i max size of output name
+
+int ip, strlen()
+char ch
+
+begin
+ ip = strlen (url)
+ while (ip > 1) {
+ ch = url[ip]
+ if (ch == '/' || ch == '?' || ch == '&' || ch == ';' || ch == '=') {
+ call strcpy (url[ip+1], name, maxch)
+ return
+ }
+ ip = ip - 1
+ }
+
+ call strcpy (url[ip], name, maxch)
+end
diff --git a/pkg/system/tail.par b/pkg/system/tail.par
new file mode 100644
index 00000000..649e66ad
--- /dev/null
+++ b/pkg/system/tail.par
@@ -0,0 +1,2 @@
+input_files,s,a,,,,list of files to be printed
+nlines,i,h,12,,,number of lines to print from each file
diff --git a/pkg/system/tail.x b/pkg/system/tail.x
new file mode 100644
index 00000000..ad4ebae0
--- /dev/null
+++ b/pkg/system/tail.x
@@ -0,0 +1,107 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+
+# TAIL -- Print the tail (last few lines) of each of the named text files on the
+# standard output. If more than one file is to be printed, a brief header is
+# printed for each file.
+#
+# Params:
+# input_files File matching template
+# nlines [h,12] Number of lines at tail of file to be printed
+#
+# If NLINES is negative, its absolute value is the number of lines to skip at
+# head of file.
+
+procedure t_tail()
+
+char fname[SZ_FNAME]
+bool multiple_files
+int nlines, list
+int clpopni(), clplen(), clgfil(), clgeti()
+
+begin
+ list = clpopni ("input_files")
+ nlines = clgeti ("nlines")
+
+ multiple_files = (clplen (list) > 1)
+
+ while (clgfil (list, fname, SZ_FNAME) != EOF)
+ iferr (call print_tail (STDOUT, fname, nlines, multiple_files))
+ call erract (EA_WARN)
+
+ call clpcls (list)
+end
+
+
+# PRINT_TAIL -- Print the last few lines of a file on the output stream
+# given as the first argument, optionally plus a header.
+
+procedure print_tail (out, fname, nlines, print_file_name)
+
+char fname[ARB]
+int out, nlines
+bool print_file_name
+
+pointer sp, offsets, line
+int in, linenum, index, noffsets, nlines_in_file
+int open(), getline()
+long note()
+errchk open, getline, putline, note
+
+begin
+ if (nlines == 0)
+ return
+ else
+ noffsets = abs (nlines) + 1
+
+ call smark (sp)
+ call salloc (line, SZ_LINE, TY_CHAR)
+ call salloc (offsets, noffsets, TY_LONG)
+
+ # Open the file.
+ in = open (fname, READ_ONLY, TEXT_FILE)
+
+ if (print_file_name) {
+ call fprintf (out, "\n\n===> %s <===\n")
+ call pargstr (fname)
+ }
+
+ # If nlines is negative, skip nlines lines at head of file and
+ # print rest of file. If nlines is positive, print nlines lines
+ # at tail of file.
+
+ linenum = 0
+ repeat {
+ linenum = linenum + 1
+ if (nlines < 0 && linenum > -nlines)
+ break
+ else if (nlines > 0) {
+ index = mod (linenum - 1, noffsets)
+ Meml[offsets+index] = note (in)
+ }
+ } until (getline (in, Memc[line]) == EOF)
+
+ nlines_in_file = linenum - 1
+
+ # Seek back to offset of desired line, if not skipping head of file.
+ if (nlines > 0)
+ if (nlines_in_file <= nlines)
+ call seek (in, BOFL)
+ else {
+ index = mod (nlines_in_file - nlines, noffsets)
+ call seek (in, Meml[offsets+index])
+ }
+
+ # If nlines is positive, print nlines lines, otherwise print rest
+ # of file.
+ linenum = 1
+ while ((linenum <= nlines || nlines < 0) &&
+ (getline (in, Memc[line]) != EOF)) {
+ call putline (out, Memc[line])
+ linenum = linenum + 1
+ }
+
+ call sfree (sp)
+ call close (in)
+end
diff --git a/pkg/system/tee.par b/pkg/system/tee.par
new file mode 100644
index 00000000..9e833007
--- /dev/null
+++ b/pkg/system/tee.par
@@ -0,0 +1,3 @@
+tee_file,s,a,,,,name of file into which STDOUT is to be copied
+out_type,s,h,"text",,,type of output file (text|binary)
+append,b,h,no,,,append to output file?
diff --git a/pkg/system/tee.x b/pkg/system/tee.x
new file mode 100644
index 00000000..b22abd32
--- /dev/null
+++ b/pkg/system/tee.x
@@ -0,0 +1,58 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <fset.h>
+
+define SZ_OTSTR 10
+
+# TEE -- Tee the standard output. The type of the output file defaults to
+# text file unless the caller specifies otherwise. Note that this tee
+# writes the entire output all at once.
+
+procedure t_tee()
+
+char tee_file[SZ_FNAME], out_type_string[SZ_OTSTR]
+bool clgetb()
+pointer sp, buf
+int out, sz_buf, out_type, nchars
+int open(), read(), strmatch(), getline(), fstati()
+
+begin
+ # Get params and open the output file.
+ call clgstr ("tee_file", tee_file, SZ_FNAME)
+ call clgstr ("out_type", out_type_string, SZ_OTSTR)
+
+ if (strmatch (out_type_string, "^#{b}") > 0)
+ out_type = BINARY_FILE
+ else
+ out_type = TEXT_FILE
+
+ if (clgetb ("append"))
+ out = open (tee_file, APPEND, out_type)
+ else
+ out = open (tee_file, NEW_FILE, out_type)
+
+
+ # Make a buffer and perform the copy operation.
+ call smark (sp)
+
+ if (out_type == TEXT_FILE) {
+ call salloc (buf, SZ_LINE, TY_CHAR)
+ while (getline (STDIN, Memc[buf]) != EOF) {
+ call putline (STDOUT, Memc[buf])
+ call putline (out, Memc[buf])
+ }
+
+ } else {
+ sz_buf = fstati (STDIN, F_BUFSIZE)
+ call salloc (buf, sz_buf, TY_CHAR)
+
+ while (read (STDIN, Memc[buf], sz_buf) != EOF) {
+ nchars = fstati (STDIN, F_NCHARS)
+ call write (STDOUT, Memc[buf], nchars)
+ call write (out, Memc[buf], nchars)
+ }
+ }
+
+ call sfree (sp)
+ call close (out)
+end
diff --git a/pkg/system/touch.par b/pkg/system/touch.par
new file mode 100644
index 00000000..4adb14b3
--- /dev/null
+++ b/pkg/system/touch.par
@@ -0,0 +1,7 @@
+files,s,a,,,,list of files to be created or touched
+create,b,h,yes,,,create file if it doesn't exist?
+atime,b,h,yes,,,update file access time?
+mtime,b,h,yes,,,update file modification time?
+time,s,h,"",,,time to set (empty for current time)
+ref_file,s,h,"",,,reference file for times
+verbose,b,h,no,,,verbose output flag
diff --git a/pkg/system/touch.x b/pkg/system/touch.x
new file mode 100644
index 00000000..5635dbec
--- /dev/null
+++ b/pkg/system/touch.x
@@ -0,0 +1,193 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <finfo.h>
+include <error.h>
+include <time.h>
+
+
+# TOUCH -- Change file access and modification times, creating an empty
+# file if necessary. File times may come from the current system time,
+# a user-specified string, or a reference file.
+
+procedure t_touch()
+
+pointer list
+char fname[SZ_FNAME], time[SZ_FNAME]
+char ref_file[SZ_PATHNAME]
+char at_str[SZ_TIME], mt_str[SZ_TIME]
+bool create, atime, mtime, verbose
+
+long ref[LEN_FINFO]
+long t_atime, t_mtime, ltime
+
+long clktime()
+int clpopni(), clgfil()
+int finfo(), dtm_ltime()
+bool clgetb()
+
+errchk touch
+
+begin
+ # Initialize.
+ call aclrc (time, SZ_FNAME)
+ call aclrc (ref_file, SZ_PATHNAME)
+
+ # Process the parameters.
+ list = clpopni ("files")
+
+ create = clgetb ("create")
+ atime = clgetb ("atime")
+ mtime = clgetb ("mtime")
+ verbose = clgetb ("verbose")
+ call clgstr ("time", time, SZ_FNAME)
+
+ # Check for error conditions.
+ if (!atime && !mtime) {
+ call eprintf (
+ "ERROR: Must specify at least one of 'atime' or 'mtime'.\n")
+ call clpcls (list)
+ return
+ }
+
+ # Get the time to be set.
+ if (time[1] == EOS) {
+ # No 'time' param, look for a reference file to use.
+ call clgstr ("ref_file", ref_file, SZ_PATHNAME)
+ if (ref_file[1] == EOS) {
+ # No 'ref_file' param, use the current system time.
+ t_atime = clktime (long(0))
+ t_mtime = t_atime
+
+ if (verbose) {
+ call cnvtime (t_atime, at_str, SZ_TIME)
+ call printf ("Modifying to system time: %s\n\n")
+ call pargstr (at_str)
+ }
+
+ } else {
+ # Open the reference file and use those times.
+ if (finfo (ref_file, ref) == ERR) {
+ call eprintf ("Error opening reference file: '%s'\n")
+ call pargstr (ref_file)
+ return
+ }
+ t_atime = FI_ATIME(ref)
+ t_mtime = FI_MTIME(ref)
+
+ if (verbose) {
+ call cnvtime (t_atime, at_str, SZ_TIME)
+ call cnvtime (t_mtime, mt_str, SZ_TIME)
+ call printf ("Modifying to reference time: ")
+ call printf ("%s (atime)\n%30t%s (mtime)\n\n")
+ call pargstr (at_str)
+ call pargstr (mt_str)
+ }
+ }
+
+ } else {
+ # Parse the time parameter to get the modification time.
+ if (dtm_ltime (time, ltime) == ERR) {
+ if (ltime < 0)
+ call eprintf ("Invalid time string: '%s'\n")
+ else
+ call eprintf ("Error parsing time string: '%s'\n")
+ call pargstr (time)
+ return
+ }
+ t_atime = ltime
+ t_mtime = ltime
+
+ if (verbose) {
+ call cnvtime (t_atime, at_str, SZ_TIME)
+ call printf ("Modifying to user-specified time: %s\n\n")
+ call pargstr (at_str)
+ }
+ }
+
+ # Now apply the atime/mtime params to update only what's needed.
+ if (!atime) t_atime = NULL
+ if (!mtime) t_mtime = NULL
+
+
+ # Process the list of input files.
+ while (clgfil (list, fname, SZ_FNAME) != EOF) {
+ iferr (call touch (fname, create, t_atime, t_mtime, verbose))
+ ;
+ }
+
+ # Clean up and close the list.
+ call clpcls (list)
+end
+
+
+# TOUCH -- Touch a file to modify the times.
+
+procedure touch (fname, create, atime, mtime, verbose)
+
+char fname[ARB] #i file name to touch
+bool create #i create file if necessary?
+long atime, mtime #i access and modify time
+bool verbose #i verbose output?
+
+char dir[SZ_PATHNAME], ip
+char vfn[SZ_PATHNAME]
+int fd
+int access(), open(), futime()
+
+begin
+ if (verbose) {
+ call printf ("%s: ")
+ call pargstr (fname)
+ }
+
+ # Check first it the file exists.
+ if (access (fname, 0, 0) == NO) {
+ if (create) {
+
+ call fnldir (fname, vfn, SZ_PATHNAME)
+ call fpathname (vfn, dir, SZ_PATHNAME)
+ if (access (dir, READ_WRITE, 0) == NO) {
+ for (ip=1; dir[ip] != '!'; ip=ip+1)
+ ;
+ call eprintf ("Error: Cannot open directory '%s'\n")
+ call pargstr (dir[ip+1])
+ call erract (EA_ERROR)
+ return;
+ }
+
+ # Create a new empty file.
+ iferr (fd = open (fname, NEW_FILE, TEXT_FILE)) {
+ call eprintf ("Error: Cannot touch file '%s'\n")
+ call pargstr (fname)
+ call erract (EA_ERROR)
+ return;
+ }
+ call close (fd)
+ if (verbose) call printf ("(created) ")
+
+ } else {
+ if (verbose) call printf ("(not created)\n")
+ return
+ }
+ }
+
+ # Update the times.
+ if (futime (fname, atime, mtime) == ERR)
+ call eprintf ("Error processing file\n")
+
+ else if (verbose) {
+ call printf ("(updated %s%s%s)\n")
+ if (atime > 0)
+ call pargstr ("atime")
+ else
+ call pargstr ("")
+ if (atime > 0 && mtime > 0)
+ call pargstr ("/")
+ else
+ call pargstr ("")
+ if (mtime > 0)
+ call pargstr ("mtime")
+ else
+ call pargstr ("")
+ }
+end
diff --git a/pkg/system/type.par b/pkg/system/type.par
new file mode 100644
index 00000000..62ce1380
--- /dev/null
+++ b/pkg/system/type.par
@@ -0,0 +1,3 @@
+input_files,s,a,,,,list of files to be typed
+map_cc,b,h,yes,,,make unknown control chars printable
+device,s,h,"terminal",,,output device
diff --git a/pkg/system/type.x b/pkg/system/type.x
new file mode 100644
index 00000000..156cb5c5
--- /dev/null
+++ b/pkg/system/type.x
@@ -0,0 +1,68 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+
+# TYPE -- Type the named files on the standard output. If more than one
+# file, print a brief header identifying each file.
+
+procedure t_type()
+
+char fname[SZ_FNAME], device[SZ_FNAME]
+bool multiple_files
+int map_cc, list
+pointer tty, ttyodes()
+bool clgetb()
+int clpopni(), clplen(), clgfil(), btoi()
+
+begin
+ list = clpopni ("input_files")
+ multiple_files = (clplen (list) > 1)
+ map_cc = btoi (clgetb ("map_cc"))
+ call clgstr ("device", device, SZ_FNAME)
+ tty = ttyodes (device)
+
+ while (clgfil (list, fname, SZ_FNAME) != EOF)
+ iferr (call type_file (STDOUT, tty, fname, multiple_files, map_cc))
+ call erract (EA_WARN)
+
+ call ttycdes (tty)
+ call clpcls (list)
+end
+
+
+# TYPE_FILE -- Print the named file on the output stream given as the first
+# argument, optionally with a leading header.
+
+procedure type_file (out, tty, fname, print_file_name, map_cc)
+
+int out
+pointer tty
+char fname[ARB]
+bool print_file_name
+int map_cc
+
+int in
+pointer sp, buf
+int open(), getline()
+errchk salloc, open, getline, ttyputline
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+
+ in = open (fname, READ_ONLY, TEXT_FILE)
+
+ if (print_file_name) {
+ call fprintf (out, "===> %s <===\n")
+ call pargstr (fname)
+ }
+
+ while (getline (in, Memc[buf]) != EOF)
+ call ttyputline (out, tty, Memc[buf], map_cc)
+
+ if (print_file_name)
+ call fprintf (out, "\n\n")
+
+ call close (in)
+ call sfree (sp)
+end
diff --git a/pkg/system/unprotect.par b/pkg/system/unprotect.par
new file mode 100644
index 00000000..f57772b3
--- /dev/null
+++ b/pkg/system/unprotect.par
@@ -0,0 +1 @@
+files,s,a,,,,list of files from which protection is to be removed
diff --git a/pkg/system/unprotect.x b/pkg/system/unprotect.x
new file mode 100644
index 00000000..c265bbf8
--- /dev/null
+++ b/pkg/system/unprotect.x
@@ -0,0 +1,23 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <protect.h>
+include <error.h>
+
+# UNPROTECT -- Remove protection from a list of files.
+
+procedure t_unprotect()
+
+char fname[SZ_FNAME]
+int list, status
+
+int clpopns(), clgfil(), protect()
+
+begin
+ list = clpopns ("files")
+
+ while (clgfil (list, fname, SZ_FNAME) != EOF)
+ iferr (status = protect (fname, REMOVE_PROTECTION))
+ call erract (EA_WARN)
+
+ call clpcls (list)
+end
diff --git a/pkg/system/urlget.par b/pkg/system/urlget.par
new file mode 100644
index 00000000..64126be8
--- /dev/null
+++ b/pkg/system/urlget.par
@@ -0,0 +1,6 @@
+url,s,q,"",,,"URL (http) to retrieve"
+fname,s,q,"",,,"Output file name"
+use_cache,b,h,yes,,,"Use previously cached file?"
+extn,s,h,"",,,"Filename extn for cached file"
+verbose,b,h,no,,,"Use verbose output?"
+cache,s,h,"cache$",,,"Cache directory"
diff --git a/pkg/system/x_system.x b/pkg/system/x_system.x
new file mode 100644
index 00000000..0695b0d3
--- /dev/null
+++ b/pkg/system/x_system.x
@@ -0,0 +1,36 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# Process x_system (the executable part of the SYSTEM package).
+
+task chkupdate = t_chkupdate,
+ concatenate = t_concatenate,
+ copy = t_copy,
+ count = t_count,
+ delete = t_delete,
+ directory = t_directory,
+ fcache = t_fcache,
+ files = t_files,
+ head = t_head,
+ match = t_match,
+ mkdir = t_mkdir,
+ movefiles = t_movefiles,
+ mtclean = t_mtclean,
+ netstatus = t_netstatus,
+ page = t_page,
+ pathnames = t_pathnames,
+ protect = t_protect,
+ rename = t_rename,
+ sort = t_sort,
+ tail = t_tail,
+ tee = t_tee,
+ type = t_type,
+ unprotect = t_unprotect,
+ rewind = t_rewind,
+ lprint = t_lprint,
+ help = t_help,
+ lroff = t_lroff,
+ mkhelpdb = t_mkhelpdb,
+ hdbexamine = t_hdbexamine,
+ cmdstr = t_cmdstr,
+ touch = t_touch,
+ urlget = t_urlget