diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
commit | fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch) | |
tree | bdda434976bc09c864f2e4fa6f16ba1952b1e555 /sys/etc | |
download | iraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz |
Initial commit
Diffstat (limited to 'sys/etc')
134 files changed, 10955 insertions, 0 deletions
diff --git a/sys/etc/README b/sys/etc/README new file mode 100644 index 00000000..6a1ebe0a --- /dev/null +++ b/sys/etc/README @@ -0,0 +1,4 @@ +This directory contains miscellaneous parts of the IRAF system code. +These include the error handling facilities, the IRAF Main and associated +routines (the default exception handler, and ONEXIT), environment access +facilities, and time conversion facilities. diff --git a/sys/etc/brktime.x b/sys/etc/brktime.x new file mode 100644 index 00000000..dbd94a7c --- /dev/null +++ b/sys/etc/brktime.x @@ -0,0 +1,79 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <time.h> + +define SECONDS_PER_DAY 86400 +define SECONDS_PER_HOUR 3600 +define SECONDS_PER_MINUTE 60 +define MONDAY 2 + +# BRKTIME -- Break a long integer time (such as returned by GETTIME or FINFO) +# into the fields of the structure defined in <time.h>. The procedure is +# valid from 00:00:00 01-Jan-1980 to 23:23:59 28-Feb-2100. + +procedure brktime (ltime, tm) + +long ltime # seconds since 00:00:00 01-Jan-1980 +int tm[LEN_TMSTRUCT] # broken down time (output struct) + +long temp # working variable +long seconds # seconds in current day +long days # whole days since Monday 00-Jan-1980 +int nights # whole days since 00-Jan of current year + +int year # year counter +int days_per_year # days per year + +int month # month counter +int days_per_month[12] # days per month +data days_per_month/31,0,31,30,31,30,31,31,30,31,30,31/ + +begin + seconds = mod (ltime, SECONDS_PER_DAY) + days = ltime / SECONDS_PER_DAY + 1 + + # Break hours, minutes, seconds. + + TM_HOUR(tm) = seconds / SECONDS_PER_HOUR + temp = seconds - TM_HOUR(tm) * SECONDS_PER_HOUR + TM_MIN(tm) = temp / SECONDS_PER_MINUTE + TM_SEC(tm) = temp - TM_MIN(tm) * SECONDS_PER_MINUTE + + # Break day of week. + + TM_WDAY(tm) = mod (days + MONDAY, 7) + if (TM_WDAY(tm) == 0) + TM_WDAY(tm) = 7 + + # Break year, day of year. + + temp = 0 # whole days since 00-Jan-1980 on last day of last year + year = 1980 + days_per_year = 366 + while (days > temp + days_per_year) { + temp = temp + days_per_year + year = year + 1 + if (mod (year, 4) == 0) + days_per_year = 366 + else + days_per_year = 365 + } + TM_YEAR(tm) = year + TM_YDAY(tm) = days - temp + + # Break month, day of month. + + nights = TM_YDAY(tm) + if (mod (TM_YEAR(tm), 4) == 0) + days_per_month[2] = 29 + else + days_per_month[2] = 28 + temp = 0 # whole days since 00-Jan on last day of last month + month = 1 + while (nights > temp + days_per_month[month]) { + temp = temp + days_per_month[month] + month = month + 1 + } + TM_MONTH(tm) = month + TM_MDAY(tm) = nights - temp +end diff --git a/sys/etc/btoi.x b/sys/etc/btoi.x new file mode 100644 index 00000000..468ba352 --- /dev/null +++ b/sys/etc/btoi.x @@ -0,0 +1,14 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# BTOI -- Convert boolean to integer. + +int procedure btoi (boolean_value) + +bool boolean_value + +begin + if (boolean_value) + return (YES) + else + return (NO) +end diff --git a/sys/etc/clktime.x b/sys/etc/clktime.x new file mode 100644 index 00000000..84155919 --- /dev/null +++ b/sys/etc/clktime.x @@ -0,0 +1,16 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# CLKTIME -- Get the current clock time (local standard time) in units +# of seconds since 00:00:00 01-Jan-80. This can be broken down into days, +# hours, seconds, etc. with BRKTIME, or printed as a date/time string with +# CNVTIME. + +long procedure clktime (old_time) + +long old_time, new_time +long cpu_time + +begin + call zgtime (new_time, cpu_time) + return (new_time - old_time) +end diff --git a/sys/etc/cnvdate.x b/sys/etc/cnvdate.x new file mode 100644 index 00000000..7e2cd4e9 --- /dev/null +++ b/sys/etc/cnvdate.x @@ -0,0 +1,52 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <time.h> + +define SZ_WEEKDAY 3 +define SZ_MONTH 3 + +# CNVDATE -- Convert a time in integer seconds since midnight on Jan 1, 1980 +# into a short string such as "May 15 18:24". The length of the output +# string is given by the parameter SZ_DATE in <time.h>. Note that CNVTIME +# is also available if a longer, more informative string is desired. + +procedure cnvdate (ltime, outstr, maxch) + +long ltime # seconds since 00:00:00 01-Jan-1980 +char outstr[ARB] +int maxch + +long one_year_ago +int fd, tm[LEN_TMSTRUCT] + +long clktime() +int stropen() +string month "JanFebMarAprMayJunJulAugSepOctNovDec" +data one_year_ago /0/ +errchk stropen + +begin + if (one_year_ago == 0) + one_year_ago = clktime (0) - 3600 * 24 * (365 - 31) + + call brktime (ltime, tm) + fd = stropen (outstr, maxch, NEW_FILE) + + call fprintf (fd, "%3.3s %2d ") + call pargstr (month [(TM_MONTH(tm) - 1) * SZ_MONTH + 1]) + call pargi (TM_MDAY(tm)) + + # If time is recent (within the past year), print the time of day, + # otherwise print the year. + + if (ltime > one_year_ago) { + call fprintf (fd, "%2d:%02d") + call pargi (TM_HOUR(tm)) + call pargi (TM_MIN(tm)) + } else { + call fprintf (fd, "%5d") + call pargi (TM_YEAR(tm)) + } + + call strclose (fd) +end diff --git a/sys/etc/cnvtime.x b/sys/etc/cnvtime.x new file mode 100644 index 00000000..372daf03 --- /dev/null +++ b/sys/etc/cnvtime.x @@ -0,0 +1,31 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <time.h> + +define SZ_WEEKDAY 3 +define SZ_MONTH 3 + +# CNVTIME -- Convert a time in integer seconds since midnight on Jan 1, 1980 +# into a string, i.e., "Mon 16:30:05 17-Mar-2001". The maximum length of the +# output string is given by the parameter SZ_TIME in <time.h>. + +procedure cnvtime (ltime, outstr, maxch) + +long ltime # seconds since 00:00:00 01-Jan-1980 +char outstr[ARB] +int maxch +int tm[LEN_TMSTRUCT] # broken down time structure +string weekday "SunMonTueWedThuFriSat" +string month "JanFebMarAprMayJunJulAugSepOctNovDec" + +begin + call brktime (ltime, tm) + call sprintf (outstr, maxch, "%3.3s %02d:%02d:%02d %02d-%3.3s-%04d") + call pargstr (weekday [(TM_WDAY(tm) - 1) * SZ_WEEKDAY + 1]) + call pargi (TM_HOUR(tm)) + call pargi (TM_MIN(tm)) + call pargi (TM_SEC(tm)) + call pargi (TM_MDAY(tm)) + call pargstr (month [(TM_MONTH(tm) - 1) * SZ_MONTH + 1]) + call pargi (TM_YEAR(tm)) +end diff --git a/sys/etc/cputime.x b/sys/etc/cputime.x new file mode 100644 index 00000000..b56b7280 --- /dev/null +++ b/sys/etc/cputime.x @@ -0,0 +1,14 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# CPUTIME -- Return the difference between the current cpu time consumed +# and the argument, in long integer milliseconds. + +long procedure cputime (old_cputime) + +long old_cputime, new_cputime +long clk_time + +begin + call zgtime (clk_time, new_cputime) + return (new_cputime - old_cputime) +end diff --git a/sys/etc/doc/Proc.hlp b/sys/etc/doc/Proc.hlp new file mode 100644 index 00000000..023a5316 --- /dev/null +++ b/sys/etc/doc/Proc.hlp @@ -0,0 +1,22 @@ + Process Control + +Connected Subprocesses + + pid = propen (process, in, out) + stat = prclose (pid) + stat = prgetline (in, lbuf) + prredir (pid, stream, new_fd) + prsignal (pid, signal) + prupdate (message) + + pid = propcpr (process, in, out) + stat = prclcpr (pid) + + + +Detached Processes + + job = propdpr (process, bkgfile) + stat = prcldpr (job) + y/n = prdone (job) + prkill (job) diff --git a/sys/etc/doc/error.hlp b/sys/etc/doc/error.hlp new file mode 100644 index 00000000..7776093f --- /dev/null +++ b/sys/etc/doc/error.hlp @@ -0,0 +1,51 @@ + +.help error, fatal, errchk, erract, iferr 2 "Error Handling Strategy" +.sh +ERROR HANDLING + + A recoverable error condition is asserted with ERROR. An irrecoverable +error condition is asserted with FATAL. Error recovery is implemented +using the IFERR and IFNOERR statements in the preprocessor language. +ERRACT may be called in an IFERR statement to cause a warning to be issued, +or to cause a particular error action to be taken. ERRCODE returns either +OK or the integer code of the posted error. + +Language support includes the IFERR and IFNOERR statements and the ERRCHK +declaration. The IFERR statement is grammatically equivalent to the IF +statement. Note that the condition to be tested in an IFERR statement may +be a procedure call or assignment statement, while the IF statement tests +a boolean expression. + + +.nf + errchk proc1, proc2, ... # errchk declaration + + iferr (procedure call or assignment statement) + <error_action_statement> + + iferr { + <any statements, including IFERR> + } then + <error_action_statement> + + +Library procedures (ERROR and FATAL cause a RETURN): + + error (errcode, error_message) + fatal (errcode, error_message) + erract (severity) + val = errcode () + + +ERRACT severity codes (<error.h>): + + EA_WARN # issue a warning message + EA_ERROR # assert recoverable error + EA_FATAL # assert fatal error +.fi + + +An arithmetic exception (X_ARITH) will be trapped by an IFERR statement, +provided the posted handler(s) return without causing error restart. +X_INT and X_ACV may only be caught by posting an exception handler with +XWHEN. diff --git a/sys/etc/doc/etc.hd b/sys/etc/doc/etc.hd new file mode 100644 index 00000000..759ba4e2 --- /dev/null +++ b/sys/etc/doc/etc.hd @@ -0,0 +1,29 @@ +# Help directory for the ETC (miscellaneous system stuff) package. + +$etc = "sys$etc/" + +brktime hlp = brktime.hlp, src = etc$brktime.x +btoi hlp = btoi.hlp, src = etc$btoi.x +clktime hlp = clktime.hlp, src = etc$clktime.x +cnvdate hlp = cnvdate.hlp, src = etc$cnvdate.x +cnvtime hlp = cnvtime.hlp, src = etc$cnvtime.x +cputime hlp = cputime.hlp, src = etc$cputime.x +envgetb hlp = envget.hlp, src = etc$envgetb.x +envgeti hlp = envget.hlp, src = etc$envgeti.x +envgets hlp = envget.hlp, src = etc$envgets.x +erract hlp = erract.hlp, src = etc$erract.x +errcode hlp = errcode.hlp, src = etc$errcode.x +error hlp = error.hlp, src = etc$error.x +getuid hlp = getuid.hlp, src = etc$getuid.x +itob hlp = itob.hlp, src = etc$itob.x +lpopen hlp = lpopen.hlp, src = etc$lpopen.x +main hlp = main.hlp, src = etc$main.x +onerror hlp = onerror.hlp, src = etc$onerror.x +onexit hlp = onexit.hlp, src = etc$onexit.x +oscmd hlp = oscmd.hlp, src = etc$oscmd.x +qsort hlp = qsort.hlp, src = etc$qsort.x +sys_ptime hlp = sys_ptime.hlp, src = etc$sys_ptime.x +syserr hlp = syserr.hlp, src = etc$syserr.x +tsleep hlp = tsleep.hlp, src = etc$tsleep.x +urand hlp = urand.hlp, src = etc$urand.x +xwhen hlp = xwhen.hlp, src = etc$xwhen.x diff --git a/sys/etc/doc/etc.men b/sys/etc/doc/etc.men new file mode 100644 index 00000000..5ed6f4ad --- /dev/null +++ b/sys/etc/doc/etc.men @@ -0,0 +1,24 @@ + brktime - Convert a long integer time into year, month, day, etc. + btoi - Boolean to integer + clktime - Get the clock time + cnvdate - Convert long integer time to date string (short format) + cnvtime - Convert long integer time to time string (long format) + cputime - Get the CPU time consumed by the process + envget[bis] - Get a boolean, integer, or string valued environment variable + erract - Take an error action for a previously posted error + errcode - Get the error code of the posted error + error - Post an error and take an error action + getuid - Get the name of the runtime user of a program + itob - Convert integer to boolean + lpopen - Open the line printer as a file + main - The IRAF Main + onerror - Post a procedure to be executed if error recovery occurs + onexit - Post a procedure to be executed upon process shutdown + oscmd - Send a command to the host operating system + qsort - General quick sort for any data structure + sys_mtime - Mark the time (for timing programs) + sys_ptime - Print the elapsed time since last mark + syserr - Post a system error and take an error action + tsleep - Delay process execution + urand - Uniform random number generator + xwhen - Post an exception handler diff --git a/sys/etc/doc/psio.doc b/sys/etc/doc/psio.doc new file mode 100644 index 00000000..d0f34c9a --- /dev/null +++ b/sys/etc/doc/psio.doc @@ -0,0 +1,275 @@ +.help pr_psio +.nf __________________________________________________________________________ +PR_PSIO -- Pseudofile i/o for a process. Process an i/o request for the +specified pseudofile stream of the specified process. Called either to read +command input from the CLIN of a process, or to process a read or write +request to a pseudofile of a process. + + +1. Introduction + + Pseudofile i/o in a multiprocess configuration, e.g., for the graphics +streams, is quite complex and difficult to explain briefly. I have tried to +cover the major points here but warn the reader that it is not going to be easy +to understand the flow of data and control involved. The problem is a difficult +one due to the nature of the IPC protocol and the complexity of the three +process architecture required when an external graphics kernel is used. The +discussion herein is not complete but should as least give the reader some +idea of what is going on. + + +2. Pseudofile I/O + + While a task is running the CL will be reading command input from the task. +This read eventually resolves into a call to PR_PSIO on the CLIN for the +process. When pseudofile i/o occurs, e.g., the process writes to STDOUT or +STDERR, an XMIT or XFER directive will be seen in the CLIN input from the +process. If we are directed to XMIT to an ordinary file our task is relatively +easy, i.e., we read the data block from CLIN and write it to the output file. +A directive to read from the standard input is also easy, i.e., we read from +the standard input of the parent (assuming i/o is not redirected) and write +the data block to the CLOUT of the process preceded by a count of the number +of chars. + + +2.1 I/O to a Graphics Stream + + If we are directed to read or write a graphics stream our task is somewhat +more difficult. The standard graphics streams STDGRAPH, STDIMAGE, and STDPLOT +differ from other pseudofiles in that the streams are both readable and +writable, provided all data is used up before switching modes. A graphics +stream may be connected to a file if output is being spooled, to the builtin +STDGRAPH kernel if the graphics device is the graphics terminal, or to a +graphics kernel resident in an external subprocess. + +If a graphics stream is redirected to a spool file we merely copy output to +the file and reading is forbidden. If output is to an external graphics +kernel but is unfiltered (no workstation transformation, e.g., for STDPLOT), +we merely copy data blocks on to the subprocess but the protocol involved +is nontrivial. If output is to the builtin STDGRAPH kernel or to an +external interactive kernel, output must be filtered through GIOTR before +being written to the local or remote graphics kernel. Graphics input is +also possible and is handled similarly but without need to call GIOTR. + +Before reading or writing a graphics stream GIO will send a special directive to +PR_PSIO to connect a kernel to the stream. This directive is passed to PR_PSIO +via an XMIT to the special pseudofile PSIOCONTROL. The data passed in the +XMIT call will be the GKI control instruction to be executed by PSIO. There +are currently three such directives, i.e., OPENWS, SETWCS, and GETWCS. Each +such directive is included in the normal metacode stream as well, but by +writing to a special pseudofile we avoid the need to have PR_PSIO scan each +metacode stream for control instructions, a fairly expensive operation if a +lot of data is involved. + + +2.1.1 Graphics Stream Dataflow + + A frame buffer is associated with each graphics stream in the parent +process. If graphics output (metacode) is being filtered, each output record +is appended to the frame buffer and then GIOTR is called to filter the new +instructions. GIOTR writes the filtered metacode stream either directly to +the builtin kernel or to the graphics output pseudofile stream of the parent +process. + +Output to the builtin kernel is easy to understand: GIOTR merely calls the +kernel to execute the transformed instruction. If output is to an external +kernel we unfortunately cannot simply write to the kernel because we require +that the graphics kernel task be a conventional task callable from either +the CL or by the graphics system, i.e., by PL_PSIO. We must buffer the +transformed output metacode and pass it on to the kernel process only when +requested to do so by an XFER command from the kernel. + +This buffering is done in a somewhat tricky way which makes it look like we +are writing to a simple file, and which allows us to use conventional READ and +WRITE calls to access the graphics stream. GIOTR, if not writing to the +builtin kernel, will write to one of the three graphics streams of the parent +process, i.e., to STDGRAPH, STDIMAGE, or STDPLOT. The graphics stream of the +parent is logically connected to the same stream in the kernel process. We +arrange things such that data may be written or read into the FIO buffer +associated with the stream, but the buffer will never actually be flushed, +since this would cause the contents to appear as garbage on the user terminal. + +The sequence of events for an XMIT to STDGRAPH with an external kernel is as +follows: + + + The parent process (CL) blocks, waiting for a read on the IPC + channel to the graphics task. + + Graphics task writes to stdgraph. + FIO flushes stdgraph buffer through IPC channel. + + PR_PSIO (in the parent) sees XMIT to stdgraph. + Parent reads data record from IPC channel, appending the + data record to the frame buffer for the stream. + + PR_PSIO calls GIOTR to process the new metacode. + GIOTR writes the transformed metacode instructions to the stdgraph + stream of the parent and returns control to PR_PSIO. + + PR_PSIO rewinds the stdgraph buffer in preparation for a read and + stacks the pending XMIT request and directs its command input + to the IPC of the kernel process. + + The kernel process sends zero or more XMIT or XFER requests to + the parent to read or write pseudofile streams other than + stdgraph. + The kernel process sends an XFER request to the parent to read + from stdgraph. + The parent reads the data record from the stdgraph FIO buffer + and passes it on to the kernel, completing the XFER request + of the kernel as well as the original XMIT request of the + graphics task. + + The parent process (CL) blocks, waiting for a read on the IPC + channel to the graphics task. + + +The sequence of operations for an XFER request from the graphics task is +as follows. + + The parent process (CL) blocks, waiting for a read on the IPC + channel to the graphics task. + + The parent receives an XFER request from the graphics task. + If there is any data in the stdgraph buffer the parent returns + that to the graphics task, otherwise the PR_PSIO procedure + pushes an XFER request and redirects its input to the + graphics kernel. + + The kernel process sends zero or more XMIT or XFER requests to + the parent to read or write pseudofile streams other than + stdgraph. + The kernel process sends an XMIT request to the parent to write + to stdgraph. + The parent reads the data block from the IPC channel to the kernel + and writes it to stdgraph, completing the XMIT request. + + The parent pops the XFER request and copies the data in the stdgraph + buffer to the graphics task, completing the original XFER request. + + The parent process (CL) blocks, waiting for a read on the IPC + channel to the graphics task. + + +In summary, the principal data buffers involved in pseudofile i/o to a graphics +stream are the frame buffer, used by GIOTR to spool the metacode instructions +for a graphics frame, and the FIO buffer for the graphics stream, used to +pass data between XMIT/XFER request pairs from cooperating processes at +opposite ends of a graphics stream. + + +3. Summary + + The actual code required to implement all this is probably easier to +understand than the English description. To summarize the justification for +the complexity of the scheme we have adopted: + + [1] The graphics kernel task is a conventional CL callable task with + parameters etc., usable to process metacode from a metafile or from + a pipe as well as callable by PR_PSIO. The conventional IPC protocol + is used in the graphics kernel task. Other tasks may be resident in + the same process, saving disk and memory. + + [2] The graphics kernel may read STDIN and write STDOUT and STDERR while + processing metacode, allowing access to the graphics terminal via the + CL process, output of debugging information during operation, and + output of error messages during operation. +.endhelp ______________________________________________________________________ + + +# PR_PSIO -- Process an i/o request for the specified pseudofile stream +# of the specified process. + +procedure pr_psio (pid, active_fd) + +pid process id +fd process stream for which i/o is requested + +begin + in = pr.clin + fd = active_fd + clear stack + + # Process i/o requests from the subprocess until a request is received + # and processed for pseudofile FD. + + repeat { + while (filbuf (in) != EOF) { + determine type of request and destfd + + if (xmit request to stream destfd) { + if (graphics filtering enabled) { + read data record and append to frame buffer + call giotr to filter output to destfd + } else { + read data record from process + write record to destfd + } + if (destination is a process) { + rewind destfd buffer for read + push (fd) + push (in) + push (xmit) + fd = destfd + in = newpr.clin + next + } + + } else if (xfer request from stream destfd) { + if (destfd is a process and buffer is empty) { + push (fd) + push (in) + push (xfer) + fd = destfd + in = newpr.clin + next + } else { + read data record from destfd + write data record to process + } + + } else if (gio directive) { + if (open workstation) + connect a kernel process to a graphics stream + else if (setwcs) + save wcs for the stream + else if (getwcs) + write wcs data to the process + + } else { + destfd = CLIN + if (fd != CLIN) + error: unsolicited command input from the subprocess + } + + if (destfd == fd) { + if (stack not empty) { + pop (request) + pop (in) + pop (fd) + if (request == xfer) { + read data record from fd + write data record to process owning "in" + } + } else + break + } + } + } until (stack is empty) +end + + + +File routing: + + Each pseudofile in a subprocess is associated with a stream in the parent +process. A subprocess pseudofile may map to a real file or to a parent +pseudofile. When a subprocess is connected as a graphics kernel graphics +i/o will be via any one of the standard graphics streams STDGRAPH etc., +with said graphics stream connected to the same stream in the parent. +The subprocess streams STDIN, STDOUT, and STDERR are by default connected +to the same streams in the parent, allowing the subprocess to access the +terminal, output error messages, and so on. A graphics kernel will be able +to access the standard i/o streams even while connected as a subprocess +to filter GKI metacode. diff --git a/sys/etc/dtmcnv.x b/sys/etc/dtmcnv.x new file mode 100644 index 00000000..63d89a12 --- /dev/null +++ b/sys/etc/dtmcnv.x @@ -0,0 +1,482 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <ctype.h> +include <time.h> + + +# DTMCNV.X -- Date and time conversions. +# +# The file contains the source for only the DTM routines listed below. All +# the related system date and time routines are also summarized so that the +# whole (rather scattered) interface can be viewed at a glance. +# +# FITS-Like Date and Time String Conversions +# +# status = dtm_decode (datestr, y,m,d, h, oldfits) +# nchars = dtm_encode (datestr,maxch, y,m,d, h, precision, flags) +# status = dtm_decode_hms (datestr, y,m,d, h,m,s, oldfits) +# nchars = dtm_encode_hms (datestr,maxch, y,m,d, h,m,s, precision, flags) +# status = dtm_ltime (datestr, ltime) +# +# +# General Date and Time Conversions +# +# cnvdate (ltime, outstr, maxch) +# cnvtime (ltime, outstr, maxch) +# brktime (ltime, tm) +# +# System Time +# +# lval = clktime (old_time) # returns local time +# lval = cputime (old_cputime) # process cpu time, seconds +# gmt = lsttogmt (lst) # lst/gmt are in seconds +# lst = gmttolst (gmt) # lst/gmt are in seconds +# +# sys_mtime (save_time) # mark/print cpu time used +# sys_ptime (fd, opstr, save_time) +# +# +# Kernel Support +# +# zgtime (clktime, cputime) # clock/cpu time in seconds +# zgmtco (gmtcor) # GMT = LST + gmtco (seconds) +# +# LST here means local standard time (clock time), including any correction +# for daylight savings time. + + + +# DTM_DECODE -- Decode the FITS format DATE-OBS string value into year, +# month, day and time fields. OK is returned if the date string is +# successfully decoded, ERR if it is not. The DATE-OBS string value may be +# in any of the following forms: DD/MM/YY (flags = TF_OLDFITS), CCYY-MM-DD +# (flags = 0, time = INDEFD), or CCYY-MM-DDTHH:MM:SS[.SSS...] (flags=0, +# time = double precision number). This routine verifies only the syntax. +# Routines in the SLALIB or ASTUTIL libraries can be used to check for +# valid year, month, day, or time values. + +int procedure dtm_decode (datestr, year, month, day, time, flags) + +char datestr[ARB] #I the input date-obs string +int year #O the output year (INDEFI if undefined) +int month #O the output month (INDEFI if undefined) +int day #O the output day (INDEFI if undefined) +double time #O the output time in hours (INDEFD if undefined) +int flags #O see <time.h> + +double dval +int oldfits, ip, nchars, ival +int ctoi(), ctod() + +begin + # Initialize. + year = INDEFI + month = INDEFI + day = INDEFI + time = INDEFD + flags = 0 + + # Determine whether the format is old or new and get the day or + # month accordingly. + ip = 1 + nchars = ctoi (datestr, ip, ival) + if (nchars == 2) { + flags = or (flags, TF_OLDFITS) + oldfits = YES + day = ival + } else if (nchars == 4) { + flags = and (flags, not(TF_OLDFITS)) + oldfits = NO + year = ival + } else + return (ERR) + + # Check syntax. + if (oldfits == NO && datestr[ip] == '-') + ip = ip + 1 + else if (oldfits == YES && datestr[ip] == '/') + ip = ip + 1 + else + return (ERR) + + # Get the month + nchars = ctoi (datestr, ip, ival) + if (nchars == 2) { + month = ival + } else + return (ERR) + if (oldfits == NO && datestr[ip] == '-') + ip = ip + 1 + else if (oldfits == YES && datestr[ip] == '/') + ip = ip + 1 + else + return (ERR) + + # Get the year or day. + nchars = ctoi (datestr, ip, ival) + if (nchars == 2) { + if (oldfits == YES) + year = 1900 + ival + else + day = ival + } else + return (ERR) + + if (datestr[ip] != 'T' || oldfits == YES) + return (OK) + + # Get the time. + ip = ip + 1 + nchars = ctod (datestr, ip, dval) + if (nchars < 8) + return (ERR) + else + time = dval + + # Check for trailing garbage in the input string. Ignore whitespace. + while (IS_WHITE(datestr[ip])) + ip = ip + 1 + + if (datestr[ip] != EOS) + return (ERR) + else + return (OK) +end + + +# DTM_DECODE_HMS -- Decode a FITS format DATE-OBS string into year, month, +# day, hours, minutes, and seconds fields. OK is returned if the date string +# is successfully decoded, ERR if it is not. The DATE-OBS string value may +# be in any of the following forms: DD/MM/YY (oldfits = YES), CCYY-MM-DD +# (oldfits = NO, hours = INDEFI, minutes = INDEFI, seconds = INDEFD), or +# CCYY-MM-DDTHH:MM:SS[.SSS...] (oldfits = NO, hours = integer, minutes = +# integer, seconds = double precision number). This routine verifies only +# that the syntax is correct. Routines in the SLALIB or ASTUTIL libraries +# can be used to check for valid year, month, day, or time values. + +int procedure dtm_decode_hms (datestr, + year, month, day, hours, minutes, seconds, flags) + +char datestr[ARB] #I the input date-obs string +int year #O the output year (INDEFI if undefined) +int month #O the output month (INDEFI if undefined) +int day #O the output day (INDEFI if undefined) +int hours #O the output hours (INDEFI if undefined) +int minutes #O the output minutes (INDEFI if undefined) +double seconds #O the output seconds (INDEFD if undefined) +int flags #O see <time.h> + +double dval +int oldfits, ip, nchars, ival +int ctoi(), ctod() + +begin + # Initialize. + year = INDEFI + month = INDEFI + day = INDEFI + hours = INDEFI + minutes = INDEFI + seconds = INDEFD + flags = 0 + + # Determine whether the format is old or new and get the day + # or month accordingly. + ip = 1 + nchars = ctoi (datestr, ip, ival) + if (nchars == 2) { + flags = or (flags, TF_OLDFITS) + oldfits = YES + day = ival + } else if (nchars == 4) { + flags = and (flags, not(TF_OLDFITS)) + oldfits = NO + year = ival + } else + return (ERR) + + # Check syntax. + if (oldfits == NO && datestr[ip] == '-') + ip = ip + 1 + else if (oldfits == YES && datestr[ip] == '/') + ip = ip + 1 + else + return (ERR) + + # Get the month. + nchars = ctoi (datestr, ip, ival) + if (nchars == 2) { + month = ival + } else + return (ERR) + if (oldfits == NO && datestr[ip] == '-') + ip = ip + 1 + else if (oldfits == YES && datestr[ip] == '/') + ip = ip + 1 + else + return (ERR) + + # Get the year or day. + nchars = ctoi (datestr, ip, ival) + if (nchars == 2) { + if (oldfits == YES) + year = 1900 + ival + else + day = ival + } else + return (ERR) + + if (datestr[ip] != 'T' || oldfits == YES) + return (OK) + + # Get the hours. + ip = ip + 1 + nchars = ctoi (datestr, ip, ival) + if (nchars == 2) + hours = ival + else + return (ERR) + if (datestr[ip] != ':') + return (ERR) + + # Get the minutes. + ip = ip + 1 + nchars = ctoi (datestr, ip, ival) + if (nchars == 2) + minutes = ival + else + return (ERR) + if (datestr[ip] != ':') + return (ERR) + + # Get the seconds. + ip = ip + 1 + nchars = ctod (datestr, ip, dval) + if (nchars < 2) + return (ERR) + else + seconds = dval + + # Check for trailing garbage in the input string. Ignore whitespace. + while (IS_WHITE(datestr[ip])) + ip = ip + 1 + + if (datestr[ip] != EOS) + return (ERR) + else + return (OK) +end + + +# DTM_ENCODE -- Encode year, month, day and time fields into a valid FITS +# format DATE-OBS string value. The number of characters in the output +# string is returned as the function value. The returned DATE-OBS keyword +# value may be in any of the following formats: DD/MM/YY (oldfits = YES, +# 1900 <= year < 2000), CCYY-MM-DD (oldfits = NO, time = INDEFD), or +# CCYY-MM-DDTHH:MM:SS[.SSS...] (oldfits = NO, time = double precision +# number). This routine formats the string but does not check for valid +# input values. Routines in the SLALIB or ASTUTIL libraries can be used +# to create valid year, month, day, or time values. + +int procedure dtm_encode (datestr, maxch, + year, month, day, time, precision, flags) + +char datestr[ARB] #O the output date string +int maxch #I the maximum length of the output date string +int year #I the input year, e.g. 1999 +int month #I the input month, e.g. 1-12 +int day #I the input day, e.g. 1-31 +double time #I the input time in hours, INDEFD if undefined +int precision #I the precision of the output time field +int flags #I see <time.h> + +int oldfits, field +int strlen(), btoi() + +begin + datestr[1] = EOS + oldfits = btoi (and (flags, TF_OLDFITS) != 0) + + if (oldfits == YES) { + if (year >= 1900 && year < 2000) { + call sprintf (datestr, maxch, "%02d/%02d/%02d") + call pargi (day) + call pargi (month) + call pargi (mod (year, 1900)) + } + } else if (IS_INDEFD(time)) { + call sprintf (datestr, maxch, "%04d-%02d-%02d") + call pargi (year) + call pargi (month) + call pargi (day) + } else { + if (precision <= 0) + field = 8 + else + field = 9 + precision + call sprintf (datestr, maxch, "%04d-%02d-%02dT%0*.*h") + call pargi (year) + call pargi (month) + call pargi (day) + call pargi (field) + call pargi (precision) + call pargd (time) + } + + return (strlen (datestr)) +end + + +# DTM_ENCODE_HMS -- Encode year, month, day, hours, minutes, and seconds +# fields into a valid FITS format DATE-OBS string value. The number of +# characters in the output string is returned as the function value. The +# returned DATE-OBS keyword value may be in any of the following formats: +# DD/MM/YY (oldfits = YES, 1900 <= year < 2000), CCYY-MM-DD (oldfits = NO, +# time = INDEFD), or CCYY-MM-DDTHH:MM:SS[.SSS...] (oldfits = NO, time = +# double precision number). This routine formats the string but does not +# check for valid input values. Routines in the SLALIB or ASTUTIL libraries +# can be used to create valid year, month, day, or time values. + +int procedure dtm_encode_hms (datestr, maxch, + year, month, day, hours, minutes, seconds, precision, flags) +char datestr[ARB] #O the output date string +int maxch #I the maximum length of the output date string + +int year #I the input year, e.g. 1999 +int month #I the input month, e.g. 1-12 +int day #I the input day, e.g. 1-31 +int hours #I the input hours field, INDEFI if undefined +int minutes #I the input minutes field, INDEFI if undefined +double seconds #I the input seconds field, INDEFD if undefined +int precision #I the precision of the output time field +int flags #I see <time.h> + +int oldfits, field +int strlen(), btoi() + +begin + + datestr[1] = EOS + oldfits = btoi (and (flags, TF_OLDFITS) != 0) + + if (oldfits == YES) { + if (year >= 1900 && year < 2000) { + call sprintf (datestr, maxch, "%02d/%02d/%02d") + call pargi (day) + call pargi (month) + call pargi (mod (year, 1900)) + } + } else if (IS_INDEFI(hours) || IS_INDEFI(minutes) || + IS_INDEFD(seconds)) { + call sprintf (datestr, maxch, "%04d-%02d-%02d") + call pargi (year) + call pargi (month) + call pargi (day) + } else { + if (precision <= 0) + field = 2 + else + field = 3 + precision + call sprintf (datestr, maxch, "%04d-%02d-%02dT%02d:%02d:%0*.*f") + call pargi (year) + call pargi (month) + call pargi (day) + call pargi (hours) + call pargi (minutes) + call pargi (field) + call pargi (precision) + call pargd (seconds) + } + + return (strlen (datestr)) +end + + +# DTM_LTIME -- Decode a FITS format DATE-OBS string into the number of +# seconds since 00:00:00 01-Jan-1980. OK is returned if the date string +# is successfully decoded, ERR if it is not or if it is a negative value. +# The 'datestr' string value may be in any of the following forms: DD/MM/YY +# or CCYY-MM-DD (where time is INDEF and assumed to be midnight), or as +# CCYY-MM-DDTHH:MM:SS[.SSS...]. + +int procedure dtm_ltime (datestr, ltime) + +char datestr[ARB] #I the input date string +long ltime #O seconds since 00:00:00 01-Jan-1980 + +double sec +int oldfits, ndays +int hr, min, yr, mon, day + +double dtm_date_to_julday() +int dtm_decode_hms() + +define START_IRAF_EPOCH 2444239.5 # JD of 00:00:00 01-Jan-1980 +define SECONDS_PER_DAY 86400 +define SECONDS_PER_HOUR 3600 +define SECONDS_PER_MINUTE 60 + +begin + ltime = INDEFL # initialize + + if (dtm_decode_hms (datestr, yr,mon,day, hr,min,sec, oldfits) == ERR) + return (ERR) + + # Take care of the assumption that 2-digit years are 1900. + if (oldfits == YES) + yr = yr + 100 + + # If we had a time specified, convert it to the number of seconds + # that day. + if (IS_INDEFI(hr) || IS_INDEFI(min) || IS_INDEFD(sec)) + ltime = 0 + else + ltime = (hr * SECONDS_PER_HOUR) + (min * SECONDS_PER_MINUTE) + sec + + # Compute the number of days since the start of the iraf epoch. + ndays = dtm_date_to_julday (yr, mon, day, 0.0d0) - START_IRAF_EPOCH + + # Convert days to seconds, add to time from before. + ltime = ltime + (ndays * SECONDS_PER_DAY) + + if (ltime >= 0) + return (OK) + else + return (ERR) +end + + +# DTM_DATE_TO_JULDAY -- Convert date to Julian day. Assumes dates after year 99. + +double procedure dtm_date_to_julday (year, month, day, t) + +int year # Year +int month # Month (1-12) +int day # Day of month +double t # Time for date (mean solar day) + +double jd +int y, m, d + +begin + if (year < 100) + y = 1900 + year + else + y = year + + if (month > 2) + m = month + 1 + else { + m = month + 13 + y = y - 1 + } + + jd = int (365.25D0 * y) + int (30.6001 * m) + day + 1720995 + if (day + 31 * (m + 12 * y) >= 588829) { + d = int (y / 100) + m = int (y / 400) + jd = jd + 2 - d + m + } + jd = jd - 0.5 + int (t * 360000. + 0.5) / 360000. / 24. + return (jd) +end diff --git a/sys/etc/envgetb.x b/sys/etc/envgetb.x new file mode 100644 index 00000000..564aa67f --- /dev/null +++ b/sys/etc/envgetb.x @@ -0,0 +1,32 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# ENVGETB -- Check whether the named option is set in the environment. +# Return true only if the option is defined in the environment and either has +# no value string (i.e., the existence of the variable is what is significant) +# or a value string which begins with the character 'y' or 'Y'. + +bool procedure envgetb (varname) + +char varname[ARB] +bool answer +pointer sp, def +int envfind() + +begin + call smark (sp) + call salloc (def, SZ_LINE, TY_CHAR) + + if (envfind (varname, Memc[def], SZ_LINE) < 0) + answer = false + else { + switch (Memc[def]) { + case 'y', 'Y', EOS: + answer = true + default: # abort not justified + answer = false + } + } + + call sfree (sp) + return (answer) +end diff --git a/sys/etc/envgetd.x b/sys/etc/envgetd.x new file mode 100644 index 00000000..749c3aef --- /dev/null +++ b/sys/etc/envgetd.x @@ -0,0 +1,27 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <mach.h> + +# ENVGETD -- Fetch an environment variable and try to interpret its value +# as a double. Abort if variable is not found or cannot be converted to +# a number. + +double procedure envgetd (varname) + +char varname[ARB] + +int ip +double dval +char val[MAX_DIGITS] +int ctod(), envfind() +errchk envfind, syserrs + +begin + ip = 1 + if (envfind (varname, val, MAX_DIGITS) > 0) + if (ctod (val, ip, dval) > 0) + return (dval) + + call syserrs (SYS_ENVNNUM, varname) +end diff --git a/sys/etc/envgeti.x b/sys/etc/envgeti.x new file mode 100644 index 00000000..a3e14190 --- /dev/null +++ b/sys/etc/envgeti.x @@ -0,0 +1,26 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <mach.h> + +# ENVGETI -- Fetch an environment variable and try to interpret its value +# as an integer. Abort if variable is not found or cannot be converted to +# a number. + +int procedure envgeti (varname) + +char varname[ARB] + +int ival, ip +char val[MAX_DIGITS] +int ctoi(), envfind() +errchk envfind, syserrs + +begin + ip = 1 + if (envfind (varname, val, MAX_DIGITS) > 0) + if (ctoi (val, ip, ival) > 0) + return (ival) + + call syserrs (SYS_ENVNNUM, varname) +end diff --git a/sys/etc/envgetr.x b/sys/etc/envgetr.x new file mode 100644 index 00000000..5ec04d58 --- /dev/null +++ b/sys/etc/envgetr.x @@ -0,0 +1,18 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# ENVGETR -- Fetch an environment variable and try to interpret its value +# as a real. Abort if variable is not found or cannot be converted to +# a number. + +real procedure envgetr (varname) + +char varname[ARB] +double val, envgetd() + +begin + val = envgetd (varname) + if (IS_INDEFD(val)) + return (INDEFR) + else + return (val) +end diff --git a/sys/etc/envgets.x b/sys/etc/envgets.x new file mode 100644 index 00000000..969a660d --- /dev/null +++ b/sys/etc/envgets.x @@ -0,0 +1,62 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <knet.h> +include <fset.h> +include "environ.h" + +# ENVGETS -- Search the environment list for the named environment variable +# and return the string value if found. If not found and the process input +# is a terminal (the process is being run interactively in debug mode), generate +# a query on the terminal, read the value of the environment variable, enter +# it into the environment table, and return the value to the caller. + +int procedure envgets (key, value, maxch) + +char key[ARB] # environment variable name +char value[maxch] # string value (output) +int maxch + +char buf[SZ_FNAME] +int nchars, ttydriver, junk, in, out, ip +int gstrcpy(), envfind(), fstati(), strlen(), envputs() +extern zgetty() + +begin + # Search the environment list first. + nchars = envfind (key, value, maxch) + if (nchars >= 0) + return (nchars) + + # Key not found. If the process input CLIN is a terminal, query the + # user for the value of the environment variable. Only low level + # calls are used in the query to avoid the possibity of recursion. + + call zlocpr (zgetty, ttydriver) + iferr { + out = fstati (CLOUT, F_CHANNEL) + in = fstati (CLIN, F_CHANNEL) + } then + return (0) + + if (fstati (CLIN, F_DEVICE) == ttydriver) { + # Issue prompt, format "env.key: " + call zputty (out, "env.", 4, junk) + call zputty (out, key, strlen(key), junk) + call zputty (out, ": ", 2, junk) + call zflsty (out, junk) + + # Get value and enter in envlist, excluding the trailing newline. + + call zgetty (in, buf, SZ_FNAME, nchars) + if (nchars <= 0) + return (0) + for (ip=1; buf[ip] != '\n' && ip <= nchars; ip=ip+1) + ; + buf[ip] = EOS + junk = envputs (key, buf) + + return (gstrcpy (buf, value, maxch)) + + } else + return (0) +end diff --git a/sys/etc/envindir.x b/sys/etc/envindir.x new file mode 100644 index 00000000..48902eee --- /dev/null +++ b/sys/etc/envindir.x @@ -0,0 +1,31 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> + +# ENVINDIR -- Return the name of an environment variable which may be given +# by the value of another environment variable as "@envvar". + +procedure envindir (envvar, outstr, maxch) + +char envvar[ARB] # possibly indirect env. variable name +char outstr[ARB] # receives value of variable +int maxch + +pointer sp, envname +int envfind() +errchk syserrs + +begin + call smark (sp) + call salloc (envname, SZ_FNAME, TY_CHAR) + + call strcpy (envvar, outstr, maxch) + + while (outstr[1] == '@') { + call strcpy (outstr[2], Memc[envname], SZ_FNAME) + if (envfind (Memc[envname], outstr, maxch) <= 0) + call syserrs (SYS_ENVNF, Memc[envname]) + } + + call sfree (sp) +end diff --git a/sys/etc/envinit.x b/sys/etc/envinit.x new file mode 100644 index 00000000..3b58f444 --- /dev/null +++ b/sys/etc/envinit.x @@ -0,0 +1,27 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include "environ.h" + +# ENV_INIT -- Called by the IRAF main to initialize the environment common +# upon process startup. + +procedure env_init() + +bool first_time +int kmalloc() +include "environ.com" +data first_time /true/ + +begin + if (first_time) { + if (kmalloc (envbuf, LEN_ENVBUF, TY_SHORT) == ERR) + call sys_panic (SYS_MFULL, "Out of memory") + + call aclrs (threads, NTHREADS) + len_envbuf = LEN_ENVBUF + last = NULL + top = 1 + first_time = false + } +end diff --git a/sys/etc/environ.com b/sys/etc/environ.com new file mode 100644 index 00000000..4a2fae17 --- /dev/null +++ b/sys/etc/environ.com @@ -0,0 +1,8 @@ +# Common for the environment list package. + +pointer envbuf # buffer containing the environment list +int len_envbuf # length of the envbuf buffer +int last # index of the last list element entered +int top # index of the next list element +short threads[NTHREADS] # hashed threads through list +common /envcom/ envbuf, len_envbuf, last, top, threads diff --git a/sys/etc/environ.h b/sys/etc/environ.h new file mode 100644 index 00000000..ccdc77c8 --- /dev/null +++ b/sys/etc/environ.h @@ -0,0 +1,28 @@ +# ENVIRON.H -- Global defines for the environment list package. + +# Strings may optionally be quoted in SET stmts with either ' or ". +define IS_QUOTE ($1 == '\'' || $1 == '"') + +# Size limiting definitions. + +define NTHREADS 199 # number of hash threads +define MAX_HASHCHARS 18 # max chars to use for hashing +define LEN_ENVBUF 20480 # storage for environment list +define INC_ENVBUF 4096 # increment if overflow occurs +define MAX_SZKEY 32 # max chars in a key +define MIN_SZVALUE 20 # min allocated space for value +define MAX_SZVALUE 4096 # max chars in value string +define MAX_LENLISTELEM (4+(MAX_SZKEY+1+MAX_SZVALUE+1+SZ_SHORT-1)/SZ_SHORT) + +# List element structure, stored in ENVBUF, which is allocated as an array of +# type SHORT integer. Each list element is aligned on a short integer boundary +# within the array. E_NEXT points to the next element in a thread, whereas +# E_LASTELEM points to the last element in the envbuf (which is a stack). + +define E_NEXT Mems[$1] # next element in thread (list) +define E_LASTELEM Mems[$1+1] # next element in envbuf +define E_REDEF Mems[$1+2] # set if element is redefined +define E_LEN Mems[$1+3] # nchars allocated for value string +define E_SETP (($1+4-1)*SZ_SHORT+1) # char pointer to name field +define E_SET Memc[E_SETP($1)] # "name=value" string +define E_SETOFFSET 4 diff --git a/sys/etc/environ.x b/sys/etc/environ.x new file mode 100644 index 00000000..24e6b814 --- /dev/null +++ b/sys/etc/environ.x @@ -0,0 +1,315 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <knet.h> +include "environ.h" + +.help environ +.nf ___________________________________________________________________________ +ENVIRON -- Routines for managing the environment list. The environment list +is global in scope. A process, e.g., the CL, builds up the environment list +and passes it on to a child process when the process is spawned. + + nchars = envgets (name, value, maxch) # get value of envvar + redef = envputs (name, value) # set value of envvar + nchars = envfind (name, value, maxch) # get value of envvar if def + envmark (sp) # mark stack pointer + nredefs = envfree (sp, userfcn) # free back to marked posn + + bool = envgetb (name) # get boolean value of envvar + int = envgeti (name) # get integer value of envvar + envlist (fd, prefix, show_redefs) # print envlist on file + nscan = envscan (input_source) # read SET stmts from a file + + el = env_first (valp) # head of envlist + el = env_next (el, valp, show_redefs) # next element of envlist + +The environment list is maintained as a multi-threaded linked list. This +provides the searching efficiency of a hash table plus stack like semantics +for redefinitions and for freeing blocks of variables. There are two primary +data structures internally, an array of pointers to the heads of the threads, +and a buffer containing the list elements. These data structures are +dynamically allocated and will be automatically reallocated at runtime if +overflow occurs. The number of threads determines the hashing efficiency and +is a compile time parameter. + +The ENVMARK and ENVFREE procedures mark and free storage on the environment +list stack. All environment variables defined or redefined after a call to +ENVMARK will be deleted and storage freed by a call to ENVFREE. If a redef +is freed the next most recent definition becomes current. ENVFREE returns +as its function value the number of redefined variables uncovered by the free +operation. The calling program must mark and free in the correct order or the +environment list may be trashed. + +The ENVLIST procedure prints the environment list on a file. Redefined values +will only be printed if desired. The environment list is printed as a list of +SET statements in most recent first order, i.e., + + set nameN=valueN + set nameM=valueM + ... + set name1=value1 + +The ENVLIST function is used both to inspect the environment list and to pass +the list on to a child process. Redefined variables are omitted when passing +the list on to a child process, hence the order of definition does not matter. +The output format is "prefix name=value", where the prefix string is supplied +by the user. + +The ENVSCAN function parses one or more SET statements, calling ENVPUTS to +enter the SET declarations into the environment list. The argument is either +a SET declaration or a string of the form "set @filename", where "filename" is +the name of a file containing set declarations. +.endhelp ______________________________________________________________________ + + +# ENVFIND -- Search the environment list for the named environment variable +# and return the string value if found. + +int procedure envfind (key, value, maxch) + +char key[ARB] # environment variable name +char value[maxch] # string value (output) +int maxch + +long sum +pointer el, ep +int head, ip, nchars +int envputs(), gstrcpy() +include "environ.com" + +begin + # Get index into envbuf of the first element of the thread. + if (key[1] == EOS) + head = NULL + else { + sum = 0 + do ip = 1, MAX_HASHCHARS { + if (key[ip] == EOS) + break + sum = sum + (sum + key[ip]) + } + head = threads[mod(sum,NTHREADS)+1] + } + + # If thread is not empty search down it for the named key and return + # the value string if found. Note that the value of the E_NEXT pointer + # is given as an integer offset into envbuf to facilitate reallocation + # upon overflow. + + if (head != NULL) + for (el = envbuf + head; el > envbuf; el = envbuf + E_NEXT(el)) { + ep = E_SETP(el) + for (ip=1; key[ip] == Memc[ep]; ip=ip+1) + ep = ep + 1 + if (key[ip] == EOS && Memc[ep] == '=') + return (gstrcpy (Memc[ep+1], value, maxch)) + } + + # Key not found. Ask the host system for the value of the environment + # variable. + + call strpak (key, value, maxch) + call zgtenv (value, value, maxch, nchars) + + if (nchars >= 0) { + call strupk (value, value, maxch) + ip = envputs (key, value) + return (nchars) + } else { + value[1] = EOS + return (ERR) + } +end + + +# ENVPUTS -- Add a new SET definition to the environment list. A SET operation +# is allowed to redefine a previously defined environment variable, but if the +# new definition is a redef we return YES as the function value. If the set +# is a no-op (null key, or redef with the same value as previously) the envlist +# is not modified and NO is returned as the function value. + +int procedure envputs (key, value) + +char key[ARB] # environment variable name +char value[ARB] # string value + +long sum +int head, thread_index, redef, ip +pointer el, op, ep + +bool streq() +pointer coerce() +int gstrcpy(), krealloc() +include "environ.com" + +begin + if (key[1] == EOS) + return (NO) + + # Get index into envbuf of the first element of the thread. + sum = 0 + do ip = 1, MAX_HASHCHARS { + if (key[ip] == EOS) + break + sum = sum + (sum + key[ip]) + } + + thread_index = mod (sum, NTHREADS) + 1 + head = threads[thread_index] + + # If thread is not empty search down it for the named key to see if we + # have a redefinition. If we have a redef but the new value is the + # same as the old, do nothing. Otherwise flag the element being + # redefined as a redefinition (so that ENVLIST can ignore it). + + redef = NO + if (head != NULL) + for (el = envbuf + head; el > envbuf; el = envbuf + E_NEXT(el)) { + ep = E_SETP(el) + for (ip=1; key[ip] == Memc[ep]; ip=ip+1) + ep = ep + 1 + if (key[ip] == EOS && Memc[ep] == '=') + if (streq (Memc[ep+1], value)) + return (NO) + else { + E_REDEF(el) = YES + redef = YES + break + } + } + + # Append the new list element to the end of ENVBUF, increasing the size + # of the buffer if overflow occurs. The list structure must be aligned + # on a short integer boundary. Set the back link pointers for searches. + + if (top + MAX_LENLISTELEM >= len_envbuf) { + len_envbuf = len_envbuf + INC_ENVBUF + if (krealloc (envbuf, len_envbuf, TY_SHORT) == ERR) + call sys_panic (SYS_MFULL, "Out of memory") + } + + el = envbuf + top + E_NEXT(el) = head + E_LASTELEM(el) = last + E_REDEF(el) = NO + + # Deposit the string "key=value" in the E_SET field. At least + # MIN_SZVALUE chars are allocated for the value string, to permit + # the value to be updated via ENVRESET (possibly changing size in + # the process). + + op = E_SETP(el) + op = op + gstrcpy (key, Memc[op], MAX_SZKEY) + Memc[op] = '=' + op = op + 1 + E_LEN(el) = max (MIN_SZVALUE, gstrcpy(value,Memc[op],MAX_SZVALUE)) + op = op + E_LEN(el) + 1 + + last = top + threads[thread_index] = last + top = coerce (op, TY_CHAR, TY_SHORT) - envbuf + + # Update the environment in any connected kernel servers. + call ki_envreset (key, value) + + return (redef) +end + + +# ENVMARK -- Mark the position in the environment list. A subsequent call +# to ENVFREE with the marked position as argument will unset all elements +# set after the marked position. + +procedure envmark (old_top) + +int old_top # top of envbuf stack +include "environ.com" + +begin + old_top = top +end + + +# ENVFREE -- Free all environment list entries set since the matching call +# to ENVMARK. Return as the function value the number of redefined environment +# variables uncovered by the free operation. If the ZLOCPR integer entry point +# address of the user supplied function USERFCN is nonnull the function will +# be called with the name and value of each uncovered redefinition. The calling +# sequence is as follows: subroutine userfcn (name, value) + +int procedure envfree (old_top, userfcn) + +int old_top # top of envbuf stack +int userfcn # epa of function called for uncovered redefs + +int nredefs, head, i, j, t +pointer sp, start, namep, el1, el2, ep1, ep2 +include "environ.com" + +begin + if (old_top < 1 || old_top >= top) + return (0) + + call smark (sp) + call salloc (namep, SZ_FNAME, TY_CHAR) + + nredefs = 0 + + # Clear the redef flags for all list elements that are redefined by + # elements above the new top, and count the number of uncovered redefs. + # Examine only non-empty threads. + + for (t=1; t <= NTHREADS; t=t+1) { + head = threads[t] + if (head != NULL) { + # Examine only list elements in the thread which lie above the + # top we are reverting to. + + for (j = head; j >= old_top; j = E_NEXT(el1)) { + el1 = envbuf + j + + # Scan down the thread to see if this is a redefinition, + # and clear the redef flag if so. + + for (i = j; i != NULL; i = E_NEXT(el2)) { + el2 = envbuf + i + if (E_REDEF(el2) == YES) { + ep1 = E_SETP(el1) + ep2 = E_SETP(el2) + start = ep2 + while (Memc[ep1] == Memc[ep2] && Memc[ep1] != '=') { + ep1 = ep1 + 1 + ep2 = ep2 + 1 + } + if (Memc[ep1] == '=') { + E_REDEF(el2) = NO + nredefs = nredefs + 1 + if (userfcn != NULL) { + call strcpy (Memc[start], Memc[namep], + ep2 - start) + call zcall2 (userfcn, + Memc[namep], Memc[ep2+1]) + } + break + } + } + } + } + + # Set the head of the thread to the first element below + # the new top. + + threads[t] = j + } + } + + # The variable OLD_TOP is the index of a list element. Make it the + # new top. + + top = old_top + last = E_LASTELEM(envbuf+top) + + call sfree (sp) + return (nredefs) +end diff --git a/sys/etc/envlist.x b/sys/etc/envlist.x new file mode 100644 index 00000000..ebd904b6 --- /dev/null +++ b/sys/etc/envlist.x @@ -0,0 +1,25 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include "environ.h" + +# ENVLIST -- Print the environment list on the output file as a sequence of +# SET commands. The commands are given in the reverse of the order in which +# they were originally entered. Printing of redefined variables may be +# inhibited if desired. + +procedure envlist (fd, prefix, print_redefined_variables) + +int fd # output file +char prefix[ARB] # prefix string to be prepended to each line +int print_redefined_variables +pointer el +include "environ.com" + +begin + for (el = envbuf + last; el > envbuf; el = envbuf + E_LASTELEM(el)) + if (E_REDEF(el) == NO || print_redefined_variables == YES) { + call putline (fd, prefix) + call putline (fd, E_SET(el)) + call putci (fd, '\n') + } +end diff --git a/sys/etc/envnext.x b/sys/etc/envnext.x new file mode 100644 index 00000000..80ddf226 --- /dev/null +++ b/sys/etc/envnext.x @@ -0,0 +1,53 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include "environ.h" + +# ENV_FIRST -- Return a pointer to the first (most recently entered) entry +# in the environment list. A pointer to the string definition of the entry +# is returned as the output argument. + +pointer procedure env_first (valp) + +pointer valp # pointer to environment string +pointer el +include "environ.com" + +begin + el = envbuf + last + if (el > envbuf) { + valp = E_SETP(el) + return (el) + } else + return (NULL) +end + + +# ENV_NEXT -- Return a pointer to the next element in the environment list. +# A pointer to the string value of the element is returned as the output +# argument. + +pointer procedure env_next (last_el, valp, show_redefines) + +pointer last_el # pointer to last element returned +pointer valp # receives charp of next element define string +int show_redefines # do not skip redefined elements + +pointer el +include "environ.com" + +begin + el = envbuf + E_LASTELEM(last_el) + + while (el > envbuf) { + if (E_REDEF(el) == NO || show_redefines == YES) + break + else + el = envbuf + E_LASTELEM(el) + } + + if (el > envbuf) { + valp = E_SETP(el) + return (el) + } else + return (NULL) +end diff --git a/sys/etc/envreset.x b/sys/etc/envreset.x new file mode 100644 index 00000000..9ca8c5d7 --- /dev/null +++ b/sys/etc/envreset.x @@ -0,0 +1,66 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <knet.h> +include "environ.h" + +# ENVRESET -- Update the value of the named environment variable in place. +# This is used to permanently change the value of an environment variable, +# unlike ENVPUTS which will create a temporary redefinition which can later +# be discarded via ENVFREE. A fixed amount of string storage is allocated +# for the value string when the environment variable is first defined; if +# the new value won't fit we simply call ENVPUTS to redefine the variable +# at the top of the environment stack. A more sophisticated storage +# mechanism could be devised which could dynamically allocate more storage, +# but the simpler scheme seems adequate at present. + +procedure envreset (key, value) + +char key[ARB] # environment variable name +char value[ARB] # new string value + +long sum +pointer el, ep +int head, ip, junk, maxch +int envputs(), strlen() +include "environ.com" + +begin + # Get index into envbuf of the first element of the thread. + if (key[1] == EOS) + head = NULL + else { + sum = 0 + do ip = 1, MAX_HASHCHARS { + if (key[ip] == EOS) + break + sum = sum + (sum + key[ip]) + } + head = threads[mod(sum,NTHREADS)+1] + } + + # If thread is not empty search down it for the named key; if the key + # is redefined the most recent entry is updated. + + el = NULL + if (head != NULL) + for (el = envbuf + head; el > envbuf; el = envbuf + E_NEXT(el)) { + ep = E_SETP(el) + for (ip=1; key[ip] == Memc[ep]; ip=ip+1) + ep = ep + 1 + if (key[ip] == EOS && Memc[ep] == '=') + break + } + + # If the named key is not found or the new value won't fit add or + # redefine the variable, otherwise set the new value. + + if (el <= envbuf) + junk = envputs (key, value) + else if (strlen(value) > E_LEN(el)) + junk = envputs (key, value) + else { + maxch = E_LEN(el) + call strcpy (value, Memc[ep+1], maxch) + call ki_envreset (key, value) + } +end diff --git a/sys/etc/envscan.x b/sys/etc/envscan.x new file mode 100644 index 00000000..06f7a411 --- /dev/null +++ b/sys/etc/envscan.x @@ -0,0 +1,149 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <ctype.h> +include "environ.h" + +define MAXLEV 8 # max nesting of includes +define SZ_LBUF (SZ_COMMAND+SZ_LINE) # max length SET on a single line + + +# ENVSCAN -- Parse one or more SET or RESET declarations and enter them into +# the environment list. +# +# Syntax: (set|reset) name = value enter a definition +# set @filename scan a file +# +# Comments, blank lines, and lines containing unrecognized statements are +# ignored without warning. + +int procedure envscan (cmd) + +char cmd[ARB] # command text to begin scan + +char ch +int fd, in, nset, lev, sv_fd[MAXLEV] +pointer sp, ip, op, op_top, lbuf, name, value +int open(), stropen(), getlline(), strmatch(), nowhite() +errchk open, stropen, getlline, syserrs +string s_reset "^#reset#" +string s_set "^#set#" +define again_ 91 + +begin + call smark (sp) + call salloc (lbuf, SZ_LBUF, TY_CHAR) + call salloc (name, MAX_SZKEY, TY_CHAR) + call salloc (value, MAX_SZVALUE, TY_CHAR) + + # Position to after the set or reset. + in = strmatch (cmd, s_set) + if (in == 0) { + in = strmatch (cmd, s_reset) + if (in == 0) { + call sfree (sp) + return (0) + } + } + + # Open the input to be scanned. + if (cmd[in] == '@') + fd = open (cmd[in+1], READ_ONLY, TEXT_FILE) + else + fd = stropen (cmd, ARB, READ_ONLY) + + # Process all SET or RESET statements in the file. Ignore all other + # statements. + + nset = 0 + lev = 0 + + repeat { + # Get the next SET statement into lbuf, leave IN at index of first + # char of the name field. + + if (getlline (fd, Memc[lbuf], SZ_LBUF) == EOF) { + if (lev > 0) { + call close (fd) + fd = sv_fd[lev] + lev = lev - 1 + next + } else + break + } else if (Memc[lbuf] == '\n' || Memc[lbuf] == '#') { + next + } else { + in = strmatch (Memc[lbuf], s_set) + if (in == 0) + in = strmatch (Memc[lbuf], s_reset) + + if (in <= 0) + next + else if (Memc[lbuf+in-1] == '@') { + ch = nowhite (Memc[lbuf+in], Memc[lbuf], SZ_LINE) + lev = lev + 1 + if (lev > MAXLEV) + call syserrs (SYS_FOPEN, Memc[lbuf]) + sv_fd[lev] = fd + fd = open (Memc[lbuf], READ_ONLY, TEXT_FILE) + next + } + } + + # Parse the name and value strings and enter into the environment + # list. Ignore optional quotes and whitespace. Ignore rest of + # line following the value field. + + op = name + op_top = name + MAX_SZKEY + ip = lbuf + in - 1 + for (ch=Memc[ip]; ch != '=' && ch != EOS; ch=Memc[ip]) { + if (!IS_QUOTE(ch) && !IS_WHITE(ch)) { + Memc[op] = Memc[ip] + op = min (op_top, op + 1) + } + ip = ip + 1 + } + Memc[op] = EOS + + op = value + if (Memc[ip] == '=') { + ip = ip + 1 + while (IS_WHITE(Memc[ip]) || IS_QUOTE(Memc[ip])) + ip = ip + 1 + op_top = value + MAX_SZVALUE + + for (ch=Memc[ip]; ch != EOS; ch=Memc[ip]) { + if (IS_QUOTE(ch) || ch == '\n') { + break + + } else if (ch == '\\' && Memc[ip+1] == '\n') { +again_ if (getlline (fd, Memc[lbuf], SZ_LBUF) == EOF) + break + + # Skip leading whitespace on the continuation line. + for (ip=lbuf; IS_WHITE(Memc[ip]); ip=ip+1) + ; + # Check for a commented out continuation line. + if (Memc[ip] == '#') + goto again_ + + } else { + Memc[op] = ch + op = min (op_top, op + 1) + ip = ip + 1 + } + } + } + Memc[op] = EOS + + # Enter the SET definition into the environment list. + call envreset (Memc[name], Memc[value]) + nset = nset + 1 + } + + call close (fd) + call sfree (sp) + + return (nset) +end diff --git a/sys/etc/erract.x b/sys/etc/erract.x new file mode 100644 index 00000000..5400544d --- /dev/null +++ b/sys/etc/erract.x @@ -0,0 +1,93 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> +include <error.h> + +.help erract +.nf _________________________________________________________________________ +ERRACT -- Take error action. Called by FATAL, and by ERROR if a handler +is not posted. May be called by a user error handler to pass an error +back up to the handler at the next level, or to change the severity of +an error. Warning messages are posted to the standard error output, +whereas fatal errors result in error recovery followed by transmission of +the ERROR statement to the CL. + +Error restart consists of the following steps: + + (1) The IRAF main is restarted with the error code as argument. + (2) The main goes through error recovery. Error recovery consists + of cleaning up the files system, i.e., closing open files and + deleting NEW_FILES and TEMP_FILES, clearing the stack, and calling + any procedures posted with ONERROR. + (3) The ERROR statement is sent to the CL. An example of the + error statment is "ERROR (501, "Access Violation")". + (4) The main either waits for the next command, or if run from the CL + and the error code is SYS_XINT (a CL kill in response to a keyboard + interrupt), the main returns, shutting the process down. Procedures + posted with ONEXIT are called when the process shuts down. + +Any errors occuring during error restart or while executing the ONEXIT +procedures are fatal and result in immediate process termination, usually +with a panic error message. This is necessary to prevent infinite error +recursion. Also, if we are killed by the CL we should die and not hang up +trying to send error messages to the CL. +.endhelp ____________________________________________________________________ + +procedure erract (severity) + +int severity +int op, jumpbuf[LEN_JUMPBUF] +char wmsg[SZ_LINE] +int gstrcpy() +include "error.com" +common /JUMPCOM/ jumpbuf + +begin + # Clear error restart condition. Called by the IRAF Main + # after successful completion of error recovery. + + if (severity == EA_RESTART) { + err_restart = err_restart + 1 + xerflg = false + return + } else if (severity == OK) { + err_restart = 0 + xerflg = false + return + } + + # Any uncaught errors occuring during error restart are fatal and + # will result in process termination. This is necessary to prevent + # recursion and to ensure that a process killed by the CL dies if + # it cannot complete cleanup and shutdown without errors. If error + # recursion occurs we will be called repeatedly, causing the counter + # to be incremented until a panic abort occurs. + + if (severity != EA_WARN && err_restart > 2) { + call xer_fmterrmsg (xermsg, xermsg, SZ_XERMSG) + call sys_panic (xercod, xermsg) + } + + # If a handler is posted, set flag and return, deferring error + # recovery to the user handler. If warning message, merely put + # message to stderr. Otherwise initiate error recovery by restarting + # the IRAF main. This sounds reentrant, but it is not since it is an + # error restart using ZDOJMP. The ERROR statement is not sent to + # the CL until error recovery has completed. + + if (severity == EA_ERROR && nhandlers > 0) + xerflg = true + else { + call xer_fmterrmsg (xermsg, xermsg, SZ_XERMSG) + if (severity == EA_WARN) { + op = gstrcpy ("Warning: ", wmsg, SZ_LINE) + 1 + op = op + gstrcpy (xermsg, wmsg[op], SZ_LINE - op + 1) + wmsg[op] = '\n' + wmsg[op+1] = EOS + call xer_putline (STDERR, wmsg) + } else { + err_restart = err_restart + 1 + call zdojmp (jumpbuf, xercod) # Restart IRAF main. + } + } +end diff --git a/sys/etc/errcode.x b/sys/etc/errcode.x new file mode 100644 index 00000000..99df994b --- /dev/null +++ b/sys/etc/errcode.x @@ -0,0 +1,18 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <error.h> + +# ERRCODE -- Return the integer code of the last error posted. The error +# code is set to a positive nonnegative integer by a call to ERROR or +# FATAL, and is cleared (set to OK) whenever an IFERR block is entered. +# Note that if we are called from within an error handler (true part of +# an IFERR block), xerflg is false, so we cannot test xerflg to see if +# an error occurred. + +int procedure errcode() + +include "error.com" + +begin + return (xercod) +end diff --git a/sys/etc/errget.x b/sys/etc/errget.x new file mode 100644 index 00000000..e2ba10a9 --- /dev/null +++ b/sys/etc/errget.x @@ -0,0 +1,21 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <error.h> + +# ERRGET -- Return the integer code and descriptive error message string +# of the last error posted. The error code is set to a positive nonnegative +# integer by a call to ERROR or FATAL, and is cleared (set to OK) whenever +# an IFERR block is entered. Note that if we are called from within an error +# handler (true part of an IFERR block), xerflg is false, so we cannot test +# xerflg to see if an error occurred. + +int procedure errget (outstr, maxch) + +char outstr[maxch] # error message +int maxch +include "error.com" + +begin + call xer_fmterrmsg (xermsg, outstr, maxch) + return (xercod) +end diff --git a/sys/etc/error.com b/sys/etc/error.com new file mode 100644 index 00000000..2a7257f1 --- /dev/null +++ b/sys/etc/error.com @@ -0,0 +1,7 @@ + +bool xerflg # set when error is posted +int xercod # error code +int nhandlers # handler nesting level +int err_restart # YES during error restart, NO otherwise +char xermsg[SZ_XERMSG] # error message string +common /xercom/ xerflg,xercod,nhandlers,err_restart,xermsg diff --git a/sys/etc/error.x b/sys/etc/error.x new file mode 100644 index 00000000..42c390b5 --- /dev/null +++ b/sys/etc/error.x @@ -0,0 +1,60 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <error.h> + +# ERROR -- Take an error action. A call to ERROR does not necessarily +# terminate task execution, i.e., if an IFERR error handler is posted it +# will receive control after the procedure call stack is unwound back +# to the procedure containing the error handler. + +procedure error (error_code, message) + +int error_code # positive error code identifying error +char message[ARB] # error message describing error +include "error.com" + +begin + if (xerflg) { # error already posted? + if (max(error_code,1) == xercod) + return # same error again + else + call erract (EA_FATAL) # too many errors + } + + call xeract (error_code, message, EA_ERROR) +end + + +# FATAL -- Called when a fatal (irrecoverable) error occurs. Fatal errors +# cannot be caught by IFERR handlers. The calling task is terminated and +# error recovery is initiated in the IRAF Main. + +procedure fatal (error_code, message) + +int error_code # positive error code identifying error +char message[ARB] # error message describing error + +begin + call xeract (error_code, message, EA_FATAL) +end + + +# XERACT -- Take an error action; called by ERROR or FATAL. + +procedure xeract (error_code, message, severity) + +int error_code # positive error code identifying error +char message[ARB] # error message describing error +int severity # severity of the error +include "error.com" + +begin + xerflg = true # post error + xercod = max (1, error_code) + call strcpy (message, xermsg, SZ_XERMSG) + + if (nhandlers > 0 && severity == EA_ERROR) # is a handler posted? + return + else + call erract (severity) # take error action +end diff --git a/sys/etc/gen/miireadd.x b/sys/etc/gen/miireadd.x new file mode 100644 index 00000000..de15b8c1 --- /dev/null +++ b/sys/etc/gen/miireadd.x @@ -0,0 +1,50 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mii.h> + +# MIIREAD -- Read a block of data stored externally in MII format. +# Data is returned in the format of the local host machine. + +int procedure mii_readd (fd, spp, maxelem) + +int fd #I input file +double spp[ARB] #O receives data +int maxelem # max number of data elements to be read + +pointer sp, bp +int pksize, nchars, nelem +int miipksize(), miinelem(), read() +errchk read() + +long note() + +begin + pksize = miipksize (maxelem, MII_DOUBLE) + nelem = EOF + + if (pksize > maxelem * SZ_DOUBLE) { + # Read data into local buffer and unpack into user buffer. + + call smark (sp) + call salloc (bp, pksize, TY_CHAR) + + nchars = read (fd, Memc[bp], pksize) + if (nchars != EOF) { + nelem = min (maxelem, miinelem (nchars, MII_DOUBLE)) + call miiupkd (Memc[bp], spp, nelem, TY_DOUBLE) + } + + call sfree (sp) + + } else { + # Read data into user buffer and unpack in place. + + nchars = read (fd, spp, pksize) + if (nchars != EOF) { + nelem = min (maxelem, miinelem (nchars, MII_DOUBLE)) + call miiupkd (spp, spp, nelem, TY_DOUBLE) + } + } + + return (nelem) +end diff --git a/sys/etc/gen/miireadi.x b/sys/etc/gen/miireadi.x new file mode 100644 index 00000000..666166e6 --- /dev/null +++ b/sys/etc/gen/miireadi.x @@ -0,0 +1,50 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mii.h> + +# MIIREAD -- Read a block of data stored externally in MII format. +# Data is returned in the format of the local host machine. + +int procedure mii_readi (fd, spp, maxelem) + +int fd #I input file +int spp[ARB] #O receives data +int maxelem # max number of data elements to be read + +pointer sp, bp +int pksize, nchars, nelem +int miipksize(), miinelem(), read() +errchk read() + +long note() + +begin + pksize = miipksize (maxelem, MII_INT) + nelem = EOF + + if (pksize > maxelem * SZ_INT) { + # Read data into local buffer and unpack into user buffer. + + call smark (sp) + call salloc (bp, pksize, TY_CHAR) + + nchars = read (fd, Memc[bp], pksize) + if (nchars != EOF) { + nelem = min (maxelem, miinelem (nchars, MII_INT)) + call miiupki (Memc[bp], spp, nelem, TY_INT) + } + + call sfree (sp) + + } else { + # Read data into user buffer and unpack in place. + + nchars = read (fd, spp, pksize) + if (nchars != EOF) { + nelem = min (maxelem, miinelem (nchars, MII_INT)) + call miiupki (spp, spp, nelem, TY_INT) + } + } + + return (nelem) +end diff --git a/sys/etc/gen/miireadl.x b/sys/etc/gen/miireadl.x new file mode 100644 index 00000000..7a43688c --- /dev/null +++ b/sys/etc/gen/miireadl.x @@ -0,0 +1,50 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mii.h> + +# MIIREAD -- Read a block of data stored externally in MII format. +# Data is returned in the format of the local host machine. + +int procedure mii_readl (fd, spp, maxelem) + +int fd #I input file +long spp[ARB] #O receives data +int maxelem # max number of data elements to be read + +pointer sp, bp +int pksize, nchars, nelem +int miipksize(), miinelem(), read() +errchk read() + +long note() + +begin + pksize = miipksize (maxelem, MII_LONG) + nelem = EOF + + if (pksize > maxelem * SZ_LONG) { + # Read data into local buffer and unpack into user buffer. + + call smark (sp) + call salloc (bp, pksize, TY_CHAR) + + nchars = read (fd, Memc[bp], pksize) + if (nchars != EOF) { + nelem = min (maxelem, miinelem (nchars, MII_LONG)) + call miiupkl (Memc[bp], spp, nelem, TY_LONG) + } + + call sfree (sp) + + } else { + # Read data into user buffer and unpack in place. + + nchars = read (fd, spp, pksize) + if (nchars != EOF) { + nelem = min (maxelem, miinelem (nchars, MII_LONG)) + call miiupkl (spp, spp, nelem, TY_LONG) + } + } + + return (nelem) +end diff --git a/sys/etc/gen/miireadr.x b/sys/etc/gen/miireadr.x new file mode 100644 index 00000000..f3cded45 --- /dev/null +++ b/sys/etc/gen/miireadr.x @@ -0,0 +1,50 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mii.h> + +# MIIREAD -- Read a block of data stored externally in MII format. +# Data is returned in the format of the local host machine. + +int procedure mii_readr (fd, spp, maxelem) + +int fd #I input file +real spp[ARB] #O receives data +int maxelem # max number of data elements to be read + +pointer sp, bp +int pksize, nchars, nelem +int miipksize(), miinelem(), read() +errchk read() + +long note() + +begin + pksize = miipksize (maxelem, MII_REAL) + nelem = EOF + + if (pksize > maxelem * SZ_REAL) { + # Read data into local buffer and unpack into user buffer. + + call smark (sp) + call salloc (bp, pksize, TY_CHAR) + + nchars = read (fd, Memc[bp], pksize) + if (nchars != EOF) { + nelem = min (maxelem, miinelem (nchars, MII_REAL)) + call miiupkr (Memc[bp], spp, nelem, TY_REAL) + } + + call sfree (sp) + + } else { + # Read data into user buffer and unpack in place. + + nchars = read (fd, spp, pksize) + if (nchars != EOF) { + nelem = min (maxelem, miinelem (nchars, MII_REAL)) + call miiupkr (spp, spp, nelem, TY_REAL) + } + } + + return (nelem) +end diff --git a/sys/etc/gen/miireads.x b/sys/etc/gen/miireads.x new file mode 100644 index 00000000..acd7481a --- /dev/null +++ b/sys/etc/gen/miireads.x @@ -0,0 +1,50 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mii.h> + +# MIIREAD -- Read a block of data stored externally in MII format. +# Data is returned in the format of the local host machine. + +int procedure mii_reads (fd, spp, maxelem) + +int fd #I input file +short spp[ARB] #O receives data +int maxelem # max number of data elements to be read + +pointer sp, bp +int pksize, nchars, nelem +int miipksize(), miinelem(), read() +errchk read() + +long note() + +begin + pksize = miipksize (maxelem, MII_SHORT) + nelem = EOF + + if (pksize > maxelem * SZ_SHORT) { + # Read data into local buffer and unpack into user buffer. + + call smark (sp) + call salloc (bp, pksize, TY_CHAR) + + nchars = read (fd, Memc[bp], pksize) + if (nchars != EOF) { + nelem = min (maxelem, miinelem (nchars, MII_SHORT)) + call miiupks (Memc[bp], spp, nelem, TY_SHORT) + } + + call sfree (sp) + + } else { + # Read data into user buffer and unpack in place. + + nchars = read (fd, spp, pksize) + if (nchars != EOF) { + nelem = min (maxelem, miinelem (nchars, MII_SHORT)) + call miiupks (spp, spp, nelem, TY_SHORT) + } + } + + return (nelem) +end diff --git a/sys/etc/gen/miiwrited.x b/sys/etc/gen/miiwrited.x new file mode 100644 index 00000000..0b8d45c1 --- /dev/null +++ b/sys/etc/gen/miiwrited.x @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mii.h> + +# MIIWRITE -- Write a block of data to a file in MII format. +# The input data is in the host system native binary format. + +procedure mii_writed (fd, spp, nelem) + +int fd #I output file +int spp[ARB] #I native format data to be written +int nelem #I number of data elements to be written + +pointer sp, bp +int bufsize +int miipksize() + +begin + call smark (sp) + + bufsize = miipksize (nelem, MII_DOUBLE) + call salloc (bp, bufsize, TY_CHAR) + + call miipakd (spp, Memc[bp], nelem, TY_DOUBLE) + call write (fd, Memc[bp], bufsize) + + call sfree (sp) +end diff --git a/sys/etc/gen/miiwritei.x b/sys/etc/gen/miiwritei.x new file mode 100644 index 00000000..aa52be4a --- /dev/null +++ b/sys/etc/gen/miiwritei.x @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mii.h> + +# MIIWRITE -- Write a block of data to a file in MII format. +# The input data is in the host system native binary format. + +procedure mii_writei (fd, spp, nelem) + +int fd #I output file +int spp[ARB] #I native format data to be written +int nelem #I number of data elements to be written + +pointer sp, bp +int bufsize +int miipksize() + +begin + call smark (sp) + + bufsize = miipksize (nelem, MII_INT) + call salloc (bp, bufsize, TY_CHAR) + + call miipaki (spp, Memc[bp], nelem, TY_INT) + call write (fd, Memc[bp], bufsize) + + call sfree (sp) +end diff --git a/sys/etc/gen/miiwritel.x b/sys/etc/gen/miiwritel.x new file mode 100644 index 00000000..f9b800a5 --- /dev/null +++ b/sys/etc/gen/miiwritel.x @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mii.h> + +# MIIWRITE -- Write a block of data to a file in MII format. +# The input data is in the host system native binary format. + +procedure mii_writel (fd, spp, nelem) + +int fd #I output file +int spp[ARB] #I native format data to be written +int nelem #I number of data elements to be written + +pointer sp, bp +int bufsize +int miipksize() + +begin + call smark (sp) + + bufsize = miipksize (nelem, MII_LONG) + call salloc (bp, bufsize, TY_CHAR) + + call miipakl (spp, Memc[bp], nelem, TY_LONG) + call write (fd, Memc[bp], bufsize) + + call sfree (sp) +end diff --git a/sys/etc/gen/miiwriter.x b/sys/etc/gen/miiwriter.x new file mode 100644 index 00000000..94dcec38 --- /dev/null +++ b/sys/etc/gen/miiwriter.x @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mii.h> + +# MIIWRITE -- Write a block of data to a file in MII format. +# The input data is in the host system native binary format. + +procedure mii_writer (fd, spp, nelem) + +int fd #I output file +int spp[ARB] #I native format data to be written +int nelem #I number of data elements to be written + +pointer sp, bp +int bufsize +int miipksize() + +begin + call smark (sp) + + bufsize = miipksize (nelem, MII_REAL) + call salloc (bp, bufsize, TY_CHAR) + + call miipakr (spp, Memc[bp], nelem, TY_REAL) + call write (fd, Memc[bp], bufsize) + + call sfree (sp) +end diff --git a/sys/etc/gen/miiwrites.x b/sys/etc/gen/miiwrites.x new file mode 100644 index 00000000..ec2f48aa --- /dev/null +++ b/sys/etc/gen/miiwrites.x @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mii.h> + +# MIIWRITE -- Write a block of data to a file in MII format. +# The input data is in the host system native binary format. + +procedure mii_writes (fd, spp, nelem) + +int fd #I output file +int spp[ARB] #I native format data to be written +int nelem #I number of data elements to be written + +pointer sp, bp +int bufsize +int miipksize() + +begin + call smark (sp) + + bufsize = miipksize (nelem, MII_SHORT) + call salloc (bp, bufsize, TY_CHAR) + + call miipaks (spp, Memc[bp], nelem, TY_SHORT) + call write (fd, Memc[bp], bufsize) + + call sfree (sp) +end diff --git a/sys/etc/gen/mkpkg b/sys/etc/gen/mkpkg new file mode 100644 index 00000000..5437d80d --- /dev/null +++ b/sys/etc/gen/mkpkg @@ -0,0 +1,30 @@ +# Make the ETC portion of the system library libsys.a. + +$checkout libsys.a lib$ +$update libsys.a +$checkin libsys.a lib$ +$exit + +libsys.a: + miireadd.x <mii.h> + miireadi.x <mii.h> + miireadl.x <mii.h> + miireadr.x <mii.h> + miireads.x <mii.h> + miiwrited.x <mii.h> + miiwritei.x <mii.h> + miiwritel.x <mii.h> + miiwriter.x <mii.h> + miiwrites.x <mii.h> + + nmireadd.x <nmi.h> + nmireadi.x <nmi.h> + nmireadl.x <nmi.h> + nmireadr.x <nmi.h> + nmireads.x <nmi.h> + nmiwrited.x <nmi.h> + nmiwritei.x <nmi.h> + nmiwritel.x <nmi.h> + nmiwriter.x <nmi.h> + nmiwrites.x <nmi.h> + ; diff --git a/sys/etc/gen/nmireadb.x b/sys/etc/gen/nmireadb.x new file mode 100644 index 00000000..c3c0f75e --- /dev/null +++ b/sys/etc/gen/nmireadb.x @@ -0,0 +1,50 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + +# NMIREAD -- Read a block of data stored externally in NMI format. +# Data is returned in the format of the local host machine. + +int procedure nmi_readb (fd, spp, maxelem) + +int fd #I input file +bool spp[ARB] #O receives data +int maxelem # max number of data elements to be read + +pointer sp, bp +int pksize, nchars, nelem +int nmipksize(), nminelem(), read() +errchk read() + +long note() + +begin + pksize = nmipksize (maxelem, NMI_BOOL) + nelem = EOF + + if (pksize > maxelem * SZ_BOOL) { + # Read data into local buffer and unpack into user buffer. + + call smark (sp) + call salloc (bp, pksize, TY_CHAR) + + nchars = read (fd, Memc[bp], pksize) + if (nchars != EOF) { + nelem = min (maxelem, nminelem (nchars, NMI_BOOL)) + call nmiupkb (Memc[bp], spp, nelem, TY_BOOL) + } + + call sfree (sp) + + } else { + # Read data into user buffer and unpack in place. + + nchars = read (fd, spp, pksize) + if (nchars != EOF) { + nelem = min (maxelem, nminelem (nchars, NMI_BOOL)) + call nmiupkb (spp, spp, nelem, TY_BOOL) + } + } + + return (nelem) +end diff --git a/sys/etc/gen/nmireadd.x b/sys/etc/gen/nmireadd.x new file mode 100644 index 00000000..2d7c086a --- /dev/null +++ b/sys/etc/gen/nmireadd.x @@ -0,0 +1,50 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + +# NMI_READ -- Read a block of data stored externally in NMI format. +# Data is returned in the format of the local host machine. + +int procedure nmi_readd (fd, spp, maxelem) + +int fd #I input file +double spp[ARB] #O receives data +int maxelem # max number of data elements to be read + +pointer sp, bp +int pksize, nchars, nelem +int nmipksize(), nminelem(), read() +errchk read() + +long note() + +begin + pksize = nmipksize (maxelem, NMI_DOUBLE) + nelem = EOF + + if (pksize > maxelem * SZ_DOUBLE) { + # Read data into local buffer and unpack into user buffer. + + call smark (sp) + call salloc (bp, pksize, TY_CHAR) + + nchars = read (fd, Memc[bp], pksize) + if (nchars != EOF) { + nelem = min (maxelem, nminelem (nchars, NMI_DOUBLE)) + call nmiupkd (Memc[bp], spp, nelem, TY_DOUBLE) + } + + call sfree (sp) + + } else { + # Read data into user buffer and unpack in place. + + nchars = read (fd, spp, pksize) + if (nchars != EOF) { + nelem = min (maxelem, nminelem (nchars, NMI_DOUBLE)) + call nmiupkd (spp, spp, nelem, TY_DOUBLE) + } + } + + return (nelem) +end diff --git a/sys/etc/gen/nmireadi.x b/sys/etc/gen/nmireadi.x new file mode 100644 index 00000000..c07d5914 --- /dev/null +++ b/sys/etc/gen/nmireadi.x @@ -0,0 +1,50 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + +# NMI_READ -- Read a block of data stored externally in NMI format. +# Data is returned in the format of the local host machine. + +int procedure nmi_readi (fd, spp, maxelem) + +int fd #I input file +int spp[ARB] #O receives data +int maxelem # max number of data elements to be read + +pointer sp, bp +int pksize, nchars, nelem +int nmipksize(), nminelem(), read() +errchk read() + +long note() + +begin + pksize = nmipksize (maxelem, NMI_INT) + nelem = EOF + + if (pksize > maxelem * SZ_INT) { + # Read data into local buffer and unpack into user buffer. + + call smark (sp) + call salloc (bp, pksize, TY_CHAR) + + nchars = read (fd, Memc[bp], pksize) + if (nchars != EOF) { + nelem = min (maxelem, nminelem (nchars, NMI_INT)) + call nmiupki (Memc[bp], spp, nelem, TY_INT) + } + + call sfree (sp) + + } else { + # Read data into user buffer and unpack in place. + + nchars = read (fd, spp, pksize) + if (nchars != EOF) { + nelem = min (maxelem, nminelem (nchars, NMI_INT)) + call nmiupki (spp, spp, nelem, TY_INT) + } + } + + return (nelem) +end diff --git a/sys/etc/gen/nmireadl.x b/sys/etc/gen/nmireadl.x new file mode 100644 index 00000000..888beedf --- /dev/null +++ b/sys/etc/gen/nmireadl.x @@ -0,0 +1,50 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + +# NMI_READ -- Read a block of data stored externally in NMI format. +# Data is returned in the format of the local host machine. + +int procedure nmi_readl (fd, spp, maxelem) + +int fd #I input file +long spp[ARB] #O receives data +int maxelem # max number of data elements to be read + +pointer sp, bp +int pksize, nchars, nelem +int nmipksize(), nminelem(), read() +errchk read() + +long note() + +begin + pksize = nmipksize (maxelem, NMI_LONG) + nelem = EOF + + if (pksize > maxelem * SZ_LONG) { + # Read data into local buffer and unpack into user buffer. + + call smark (sp) + call salloc (bp, pksize, TY_CHAR) + + nchars = read (fd, Memc[bp], pksize) + if (nchars != EOF) { + nelem = min (maxelem, nminelem (nchars, NMI_LONG)) + call nmiupkl (Memc[bp], spp, nelem, TY_LONG) + } + + call sfree (sp) + + } else { + # Read data into user buffer and unpack in place. + + nchars = read (fd, spp, pksize) + if (nchars != EOF) { + nelem = min (maxelem, nminelem (nchars, NMI_LONG)) + call nmiupkl (spp, spp, nelem, TY_LONG) + } + } + + return (nelem) +end diff --git a/sys/etc/gen/nmireadr.x b/sys/etc/gen/nmireadr.x new file mode 100644 index 00000000..e8338400 --- /dev/null +++ b/sys/etc/gen/nmireadr.x @@ -0,0 +1,50 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + +# NMI_READ -- Read a block of data stored externally in NMI format. +# Data is returned in the format of the local host machine. + +int procedure nmi_readr (fd, spp, maxelem) + +int fd #I input file +real spp[ARB] #O receives data +int maxelem # max number of data elements to be read + +pointer sp, bp +int pksize, nchars, nelem +int nmipksize(), nminelem(), read() +errchk read() + +long note() + +begin + pksize = nmipksize (maxelem, NMI_REAL) + nelem = EOF + + if (pksize > maxelem * SZ_REAL) { + # Read data into local buffer and unpack into user buffer. + + call smark (sp) + call salloc (bp, pksize, TY_CHAR) + + nchars = read (fd, Memc[bp], pksize) + if (nchars != EOF) { + nelem = min (maxelem, nminelem (nchars, NMI_REAL)) + call nmiupkr (Memc[bp], spp, nelem, TY_REAL) + } + + call sfree (sp) + + } else { + # Read data into user buffer and unpack in place. + + nchars = read (fd, spp, pksize) + if (nchars != EOF) { + nelem = min (maxelem, nminelem (nchars, NMI_REAL)) + call nmiupkr (spp, spp, nelem, TY_REAL) + } + } + + return (nelem) +end diff --git a/sys/etc/gen/nmireads.x b/sys/etc/gen/nmireads.x new file mode 100644 index 00000000..190ce28f --- /dev/null +++ b/sys/etc/gen/nmireads.x @@ -0,0 +1,50 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + +# NMI_READ -- Read a block of data stored externally in NMI format. +# Data is returned in the format of the local host machine. + +int procedure nmi_reads (fd, spp, maxelem) + +int fd #I input file +short spp[ARB] #O receives data +int maxelem # max number of data elements to be read + +pointer sp, bp +int pksize, nchars, nelem +int nmipksize(), nminelem(), read() +errchk read() + +long note() + +begin + pksize = nmipksize (maxelem, NMI_SHORT) + nelem = EOF + + if (pksize > maxelem * SZ_SHORT) { + # Read data into local buffer and unpack into user buffer. + + call smark (sp) + call salloc (bp, pksize, TY_CHAR) + + nchars = read (fd, Memc[bp], pksize) + if (nchars != EOF) { + nelem = min (maxelem, nminelem (nchars, NMI_SHORT)) + call nmiupks (Memc[bp], spp, nelem, TY_SHORT) + } + + call sfree (sp) + + } else { + # Read data into user buffer and unpack in place. + + nchars = read (fd, spp, pksize) + if (nchars != EOF) { + nelem = min (maxelem, nminelem (nchars, NMI_SHORT)) + call nmiupks (spp, spp, nelem, TY_SHORT) + } + } + + return (nelem) +end diff --git a/sys/etc/gen/nmiwriteb.x b/sys/etc/gen/nmiwriteb.x new file mode 100644 index 00000000..9e3c19a0 --- /dev/null +++ b/sys/etc/gen/nmiwriteb.x @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + +# NMIWRITE -- Write a block of data to a file in NMI format. +# The input data is in the host system native binary format. + +procedure nmi_writeb (fd, spp, nelem) + +int fd #I output file +int spp[ARB] #I native format data to be written +int nelem #I number of data elements to be written + +pointer sp, bp +int bufsize +int nmipksize() + +begin + call smark (sp) + + bufsize = nmipksize (nelem, NMI_BOOL) + call salloc (bp, bufsize, TY_CHAR) + + call nmipakb (spp, Memc[bp], nelem, TY_BOOL) + call write (fd, Memc[bp], bufsize) + + call sfree (sp) +end diff --git a/sys/etc/gen/nmiwrited.x b/sys/etc/gen/nmiwrited.x new file mode 100644 index 00000000..d357fe4c --- /dev/null +++ b/sys/etc/gen/nmiwrited.x @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + +# NMI_WRITE -- Write a block of data to a file in NMI format. +# The input data is in the host system native binary format. + +procedure nmi_writed (fd, spp, nelem) + +int fd #I output file +int spp[ARB] #I native format data to be written +int nelem #I number of data elements to be written + +pointer sp, bp +int bufsize +int nmipksize() + +begin + call smark (sp) + + bufsize = nmipksize (nelem, NMI_DOUBLE) + call salloc (bp, bufsize, TY_CHAR) + + call nmipakd (spp, Memc[bp], nelem, TY_DOUBLE) + call write (fd, Memc[bp], bufsize) + + call sfree (sp) +end diff --git a/sys/etc/gen/nmiwritei.x b/sys/etc/gen/nmiwritei.x new file mode 100644 index 00000000..98e33f12 --- /dev/null +++ b/sys/etc/gen/nmiwritei.x @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + +# NMI_WRITE -- Write a block of data to a file in NMI format. +# The input data is in the host system native binary format. + +procedure nmi_writei (fd, spp, nelem) + +int fd #I output file +int spp[ARB] #I native format data to be written +int nelem #I number of data elements to be written + +pointer sp, bp +int bufsize +int nmipksize() + +begin + call smark (sp) + + bufsize = nmipksize (nelem, NMI_INT) + call salloc (bp, bufsize, TY_CHAR) + + call nmipaki (spp, Memc[bp], nelem, TY_INT) + call write (fd, Memc[bp], bufsize) + + call sfree (sp) +end diff --git a/sys/etc/gen/nmiwritel.x b/sys/etc/gen/nmiwritel.x new file mode 100644 index 00000000..0772b954 --- /dev/null +++ b/sys/etc/gen/nmiwritel.x @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + +# NMI_WRITE -- Write a block of data to a file in NMI format. +# The input data is in the host system native binary format. + +procedure nmi_writel (fd, spp, nelem) + +int fd #I output file +int spp[ARB] #I native format data to be written +int nelem #I number of data elements to be written + +pointer sp, bp +int bufsize +int nmipksize() + +begin + call smark (sp) + + bufsize = nmipksize (nelem, NMI_LONG) + call salloc (bp, bufsize, TY_CHAR) + + call nmipakl (spp, Memc[bp], nelem, TY_LONG) + call write (fd, Memc[bp], bufsize) + + call sfree (sp) +end diff --git a/sys/etc/gen/nmiwriter.x b/sys/etc/gen/nmiwriter.x new file mode 100644 index 00000000..3f22404b --- /dev/null +++ b/sys/etc/gen/nmiwriter.x @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + +# NMI_WRITE -- Write a block of data to a file in NMI format. +# The input data is in the host system native binary format. + +procedure nmi_writer (fd, spp, nelem) + +int fd #I output file +int spp[ARB] #I native format data to be written +int nelem #I number of data elements to be written + +pointer sp, bp +int bufsize +int nmipksize() + +begin + call smark (sp) + + bufsize = nmipksize (nelem, NMI_REAL) + call salloc (bp, bufsize, TY_CHAR) + + call nmipakr (spp, Memc[bp], nelem, TY_REAL) + call write (fd, Memc[bp], bufsize) + + call sfree (sp) +end diff --git a/sys/etc/gen/nmiwrites.x b/sys/etc/gen/nmiwrites.x new file mode 100644 index 00000000..ed284024 --- /dev/null +++ b/sys/etc/gen/nmiwrites.x @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + +# NMI_WRITE -- Write a block of data to a file in NMI format. +# The input data is in the host system native binary format. + +procedure nmi_writes (fd, spp, nelem) + +int fd #I output file +int spp[ARB] #I native format data to be written +int nelem #I number of data elements to be written + +pointer sp, bp +int bufsize +int nmipksize() + +begin + call smark (sp) + + bufsize = nmipksize (nelem, NMI_SHORT) + call salloc (bp, bufsize, TY_CHAR) + + call nmipaks (spp, Memc[bp], nelem, TY_SHORT) + call write (fd, Memc[bp], bufsize) + + call sfree (sp) +end diff --git a/sys/etc/gethost.x b/sys/etc/gethost.x new file mode 100644 index 00000000..029a9a0d --- /dev/null +++ b/sys/etc/gethost.x @@ -0,0 +1,13 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# GETHOST -- Get the network name of the host machine. + +procedure gethost (outstr, maxch) + +char outstr[maxch] # receives host name string +int maxch + +begin + call zghost (outstr, maxch) + call strupk (outstr, outstr, maxch) +end diff --git a/sys/etc/getpid.x b/sys/etc/getpid.x new file mode 100644 index 00000000..6665a55e --- /dev/null +++ b/sys/etc/getpid.x @@ -0,0 +1,12 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# GETPID -- Get the process id. + +int procedure getpid() + +int pid + +begin + call zgtpid (pid) + return (pid) +end diff --git a/sys/etc/getuid.x b/sys/etc/getuid.x new file mode 100644 index 00000000..3da5bbba --- /dev/null +++ b/sys/etc/getuid.x @@ -0,0 +1,24 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# GETUID -- Get user id, i.e., return the name of the user. We do this by +# creating a temporary file and calling fowner to get the name of the file +# owner. + +procedure getuid (user_name, maxch) + +char user_name[ARB] +int maxch +pointer sp, tempfile +int open() + +begin + call smark (sp) + call salloc (tempfile, SZ_FNAME, TY_CHAR) + + call mktemp ("tmp$uid", Memc[tempfile], SZ_FNAME) + call close (open (Memc[tempfile], NEW_FILE, BINARY_FILE)) + call fowner (Memc[tempfile], user_name, maxch) + call delete (Memc[tempfile]) + + call sfree (sp) +end diff --git a/sys/etc/gmtcnv.x b/sys/etc/gmtcnv.x new file mode 100644 index 00000000..7713c9c0 --- /dev/null +++ b/sys/etc/gmtcnv.x @@ -0,0 +1,35 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# GMTCNV.X -- GMT (Greenwich mean time) to LST (local standard time, or clock +# time) conversions. +# +# gmt = lsttogmt (lst) # lst/gmt are in seconds +# lst = gmttolst (gmt) # lst/gmt are in seconds + + + +# GMTTOLST -- Convert a long integer value in GMT seconds to LST seconds. + +long procedure gmttolst (gmt) + +long gmt # GMT in seconds +int gmtco + +begin + call zgmtco (gmtco) + return (gmt - gmtco) +end + + + +# LSTTOGMT -- Convert a long integer value in LST seconds to GMT seconds. + +long procedure lsttogmt (lst) + +long lst # LST in seconds +int gmtco + +begin + call zgmtco (gmtco) + return (lst + gmtco) +end diff --git a/sys/etc/gqsort.x b/sys/etc/gqsort.x new file mode 100644 index 00000000..8092aa29 --- /dev/null +++ b/sys/etc/gqsort.x @@ -0,0 +1,84 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +define LOGPTR 32 # log2(maxpts) (4e9) + +# GQSORT -- General quicksort for arbitrary objects. X is an integer array +# indexing the array to be sorted. The user supplied COMPARE function is used +# to compare objects indexed by X: +# +# -1,0,1 = compare (arg, x1, x2) +# +# where the value returned by COMPARE has the following significance: +# +# -1 obj[x1] < obj[x2] +# 0 obj[x1] == obj[x2] +# 1 obj[x1] > obj[x2] +# +# The value ARG is private to the compare routine and is merely passed on to +# the compare routine by gqsort. This allows context data to be passed to +# the compare routine without the need for initialization routines or commons. +# QSORT reorders the elements of the X array, which must be of type integer. + +procedure gqsort (x, nelem, compare, arg) + +int x[ARB] #U array to be sorted +int nelem #I number of elements in array +extern compare() #I function to be called to compare elements +int arg #I private data to be passed to compare func + +int i, j, k, lv[LOGPTR], p, pivot, uv[LOGPTR], temp +define swap {temp=$1;$1=$2;$2=temp} +int compare() + +begin + lv[1] = 1 + uv[1] = nelem + 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 the optimizer. + do p = p, ARB { + i = lv[p] - 1 + j = uv[p] + + # Select as the pivot the element at the center of the + # subfile, to avoid quadratic behavior on an already + # sorted list. + + k = (lv[p] + uv[p]) / 2 + swap (x[j], x[k]) + pivot = x[j] # pivot line + + while (i < j) { + for (i=i+1; compare (arg, x[i], pivot) < 0; i=i+1) + ; + for (j=j-1; j > i; j=j-1) + if (compare (arg, x[j], pivot) <= 0) + break + if (i < j) # out of order pair + swap (x[i], x[j]) # interchange elements + } + + j = uv[p] # move pivot to position i + swap (x[i], x[j]) # interchange elements + + 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 diff --git a/sys/etc/intr.x b/sys/etc/intr.x new file mode 100644 index 00000000..e30d610c --- /dev/null +++ b/sys/etc/intr.x @@ -0,0 +1,54 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <xwhen.h> + +define LEN_SAVE 10 + +# INTR_DISABLE, INTR_ENABLE -- Disable interrupts to protect a critical +# section of code. The interrupt handler is saved on a stack and restored +# when interupts are reenabled. + +procedure intr_disable() + +int sp +int save[LEN_SAVE] +common /zintde/ sp, save + +begin + sp = sp + 1 + if (sp > LEN_SAVE) + call sys_panic (1, "interrupt save stack overflow") + + call zxwhen (X_INT, X_IGNORE, save[sp]) +end + + +# INTR_ENABLE -- Reenable interrupts (restore saved interrupt handler). + +procedure intr_enable() + +int junk +int sp +int save[LEN_SAVE] +common /zintde/ sp, save + +begin + if (sp <= 0) + call sys_panic (1, "interrupt save stack underflow") + + call zxwhen (X_INT, save[sp], junk) + sp = sp - 1 +end + + +# INTR_RESET -- Clear the interrupt handler save stack. + +procedure intr_reset() + +int sp +int save[LEN_SAVE] +common /zintde/ sp, save + +begin + sp = 0 +end diff --git a/sys/etc/itob.x b/sys/etc/itob.x new file mode 100644 index 00000000..e01c6302 --- /dev/null +++ b/sys/etc/itob.x @@ -0,0 +1,14 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# ITOB -- Convert integer to boolean. + +bool procedure itob (integer_value) + +int integer_value + +begin + if (integer_value == NO) + return (false) + else + return (true) +end diff --git a/sys/etc/lineoff.x b/sys/etc/lineoff.x new file mode 100644 index 00000000..23fe9050 --- /dev/null +++ b/sys/etc/lineoff.x @@ -0,0 +1,113 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# LINEOFF -- Textfile line offset package. This is a simple little package +# used to keep track of the file offsets of the lines in a text file. +# The entry points are as follows. +# +# lp = lno_open (maxlines) +# lno_close (lp) +# lno_save (lp, line, loffset, tag) +# OK|ERR = lno_fetch (lp, line, loffset, tag) +# +# The SAVE procedure is used to save line offsets in the database, and the +# FETCH procedure is used to look up line offsets, returning ERR if the offset +# of the line is not stored. + +define MIN_NLINES 64 +define LEN_LNODES 5 +define LNO_MAXLINES Memi[$1] # number of lines stored +define LNO_SLOT Memi[$1+1] # cycles around available slots +define LNO_LINENUMP Memi[$1+2] # pointer to array of line numbers +define LNO_LINEOFFP Memi[$1+3] # pointer to array of line offsets +define LNO_LINETAGP Memi[$1+4] # pointer to array of line tags + +# LNO_OPEN -- Open the line offset descriptor. + +pointer procedure lno_open (maxlines) + +int maxlines # max lines to store offsets for +int nlines +pointer lp +errchk calloc, malloc + +begin + nlines = max (MIN_NLINES, maxlines) + + call calloc (lp, LEN_LNODES, TY_STRUCT) + LNO_MAXLINES(lp) = nlines + call calloc (LNO_LINENUMP(lp), nlines, TY_LONG) + call malloc (LNO_LINEOFFP(lp), nlines, TY_LONG) + call malloc (LNO_LINETAGP(lp), nlines, TY_LONG) + + return (lp) +end + + +# LNO_CLOSE -- Return the line offset descriptor. + +procedure lno_close (lp) + +pointer lp # line offset descriptor + +begin + call mfree (LNO_LINENUMP(lp), TY_LONG) + call mfree (LNO_LINEOFFP(lp), TY_LONG) + call mfree (LNO_LINETAGP(lp), TY_LONG) + call mfree (lp, TY_STRUCT) +end + + +# LNO_SAVE -- Save a line number/offset pair in the LNO database. + +procedure lno_save (lp, line, loffset, ltag) + +pointer lp # line offset descriptor +int line # line number +long loffset # line offset from NOTE +long ltag # tag value assoc. with line +int slot + +begin + slot = LNO_SLOT(lp) + 1 + if (slot > LNO_MAXLINES(lp)) + slot = 1 + LNO_SLOT(lp) = slot + + Memi[LNO_LINENUMP(lp)+slot-1] = line + Meml[LNO_LINEOFFP(lp)+slot-1] = loffset + Meml[LNO_LINETAGP(lp)+slot-1] = ltag +end + + +# LNO_FETCH -- Search the LNO database for an entry for the indicated line and +# return its file offset if found. No assumptions are made about the ordering +# of the data since lines could have been entered in any order. ERR is +# returned if the line is not found in the database. A simple linear search +# is sufficient given that the applications using this package are not expected +# to look up a line often. + +int procedure lno_fetch (lp, line, loffset, ltag) + +pointer lp # line offset descriptor +int line # line number to search for +long loffset # receives line offset if entry for line is found +long ltag # receives tag value assoc. with line + +int maxl, i +pointer nump, offp, tagp + +begin + maxl = LNO_MAXLINES(lp) - 1 + nump = LNO_LINENUMP(lp) + offp = LNO_LINEOFFP(lp) + tagp = LNO_LINETAGP(lp) + + do i = 0, maxl + if (Memi[nump+i] == line) { + loffset = Meml[offp+i] + ltag = Meml[tagp+i] + return (OK) + } + + return (ERR) +end diff --git a/sys/etc/locpr.x b/sys/etc/locpr.x new file mode 100644 index 00000000..3af66d1d --- /dev/null +++ b/sys/etc/locpr.x @@ -0,0 +1,14 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# LOCPR -- Return the entry point address of a procedure, suitable for input +# to a ZCALL prcocedure to call the target procedure indirectly. + +int procedure locpr (proc) + +extern proc() # external procedure +int epa + +begin + call zlocpr (proc, epa) + return (epa) +end diff --git a/sys/etc/locva.x b/sys/etc/locva.x new file mode 100644 index 00000000..d3cc3bea --- /dev/null +++ b/sys/etc/locva.x @@ -0,0 +1,13 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# LOCVA -- Return the address (in CHAR units) of a variable. + +int procedure locva (variable) + +int variable # data object to be addressed +int address + +begin + call zlocva (variable, address) + return (address) +end diff --git a/sys/etc/lpopen.x b/sys/etc/lpopen.x new file mode 100644 index 00000000..4754e779 --- /dev/null +++ b/sys/etc/lpopen.x @@ -0,0 +1,118 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <knet.h> +include <mach.h> + +define LP_INACTIVE 0 +define LP_READ 1 +define LP_WRITE 2 +define (LPCOM, common /lprcom/ lp_type, lp_nbytes) + +# LPOPEN -- Open the line printer device as a text or binary file. If opened +# as a text file, we arrange for the chars to be packed upon output, but in all +# cases the printer device appears to be a streaming binary file to FIO. +# If the printer device is opened as a binary file, the data stream is passed +# directly on to the device without modification. To simplify things a little +# we permit only one printer to be open at a time; this restriction can easily +# be removed should it prove desirable. + +int procedure lpopen (device, mode, type) + +char device[ARB] +int mode, type + +int fd +int lp_type, lp_nbytes +bool streq() +int fopnbf() +extern zopnlp(), lp_zaread(), lp_zawrite(), lp_zawait(), zsttlp(), zclslp() +LPCOM + +begin + # The TEXT device is special; it has a termcap entry and is used to + # format text for an ASCII textfile rather than a printer. + + if (streq (device, "text")) + fd = STDOUT + else { + lp_type = type + lp_nbytes = ERR + fd = fopnbf (device, mode, + zopnlp, lp_zaread, lp_zawrite, lp_zawait, zsttlp, zclslp) + } + + return (fd) +end + + +# LP_ZAREAD -- FIO z-aread routine for the line printer device. FIO calls +# us with the size of the buffer in bytes. If the printer is opened as a +# text file, we read a factor of SZB_CHAR less than that from the lowest +# level, then unpack the data inplace in the FIO buffer. + +procedure lp_zaread (chan, buf, maxbytes, offset) + +int chan +char buf[ARB] +int maxbytes +long offset # ignore, since lp is streaming device + +int nbytes +int lp_type, lp_nbytes +LPCOM + +begin + nbytes = maxbytes + if (lp_type == TEXT_FILE) + nbytes = nbytes / SZB_CHAR + + call zardlp (chan, buf, nbytes, offset) + call zawtlp (chan, lp_nbytes) + + if (lp_nbytes > 0 && lp_type == TEXT_FILE) + call chrupk (buf, 1, buf, 1, lp_nbytes) +end + + +# LP_ZAWRITE -- FIO z-awrite routine for the line printer device. FIO calls +# us with the size of the buffer in bytes. If the printer is opened as a +# text file, we first pack the data inplace in the FIO buffer, then write it +# out to the device. It is ok to modify the data directly in the FIO buffer +# since the device is a streaming device (no seeks). + +procedure lp_zawrite (chan, buf, nbytes, offset) + +int chan +char buf[ARB] +int nbytes +long offset # ignore, since lp is streaming device + +int nbytes_to_write +int lp_type, lp_nbytes +LPCOM + +begin + nbytes_to_write = nbytes + if (lp_type == TEXT_FILE) { + nbytes_to_write = nbytes_to_write / SZB_CHAR + call chrpak (buf, 1, buf, 1, nbytes_to_write) + } + + call zawrlp (chan, buf, nbytes_to_write, offset) + call zawtlp (chan, lp_nbytes) +end + + +# LP_ZAWAIT -- Wait for i/o to the line printer to complete. We do not bother +# with truely asynchronous i/o for line printer devices. + +procedure lp_zawait (chan, nbytes) + +int chan +int nbytes +int lp_type, lp_nbytes +LPCOM + +begin + nbytes = lp_nbytes +end diff --git a/sys/etc/maideh.x b/sys/etc/maideh.x new file mode 100644 index 00000000..d0850deb --- /dev/null +++ b/sys/etc/maideh.x @@ -0,0 +1,76 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <xwhen.h> +include <syserr.h> +include <fset.h> + +define SZ_ERRMSG SZ_LINE + +# MA_IDEH -- Iraf Main routine which installs the default exception handler. +# A single handler processes all exceptions. + +procedure ma_ideh() + +extern xstdexh() +int junk, i, epa_standard_handler +int exception[4] +data exception /X_ACV, X_INT, X_ARITH, X_IPC/ + +begin + call zlocpr (xstdexh, epa_standard_handler) + do i = 1, 4 + call xwhen (exception[i], epa_standard_handler, junk) + + # Initialize the critical section protection stack. + call intr_reset() +end + + +# XSTDEXH -- Standard exception handler. Unless the user code posts a handler +# for a particular exception, this handler will gain control. + +procedure xstdexh (exception, next_handler) + +int exception # code for exception +int next_handler # EPA of next handler to be called + +char os_errmsg[SZ_ERRMSG] +int os_errcode + +begin + # Get OS description of the exception. + call zxgmes (os_errcode, os_errmsg, SZ_ERRMSG) + call strupk (os_errmsg, os_errmsg, SZ_ERRMSG) + + # Cancel any output and resync awaits. + call fseti (STDOUT, F_CANCEL, OK) + call fseti (CLOUT, F_CANCEL, OK) + call fseti (CLIN, F_CANCEL, OK) + + # Set this here as error() will return immediately if it comes back. + next_handler = X_IGNORE + + # Take error action. + switch (exception) { + case X_ACV: + if (os_errcode > 0) + call fatal (SYS_XACV, os_errmsg) + else + call fatal (SYS_XACV, "Access violation") + case X_ARITH: + if (os_errcode > 0) + call fatal (SYS_XARITH, os_errmsg) + else + call fatal (SYS_XARITH, "Arithmetic exception") + case X_INT: + if (os_errcode > 0) + call fatal (SYS_XINT, os_errmsg) + else + call fatal (SYS_XINT, "Keyboard interrupt") + case X_IPC: + call fatal (SYS_XIPC, "Write to IPC with no reader") + + default: + call fatal (ERR, "Unknown exception") + } +end diff --git a/sys/etc/main.x b/sys/etc/main.x new file mode 100644 index 00000000..db6937bc --- /dev/null +++ b/sys/etc/main.x @@ -0,0 +1,908 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> +include <error.h> +include <syserr.h> +include <clset.h> +include <fset.h> +include <ctype.h> +include <printf.h> +include <xwhen.h> +include <knet.h> + +.help iraf_main +.nf __________________________________________________________________________ +The IRAF MAIN + + Task resident interpreter for interface to CL. Supervises process startup +and shutdown, error restart, and task execution. A process may contain any +number of tasks, which need not be related. The iraf main allows a process to +be run either directly (interactively or in batch) or from the CL. A brief +description of the operation of the Main is given here; additional documentation +is given in the System Interface Reference Manual. + + +EXECUTION + +[1] The process containing the IRAF Main is run. The PROCESS MAIN, a machine + dependent code segment, gains control initially. The process main + determines whether the task is being run from as a connected subprocess, + as a detached process, or as a host process, and opens the process + standard i/o channels. The process main then calls the IRAF Main, i.e., us. + +[2] The IRAF Main performs the initialization associated with process startup + and then enters the interpreter loop waiting for a command. A number of + special commands are implemented, e.g.: + + ? print menu + bye shutdown process + chdir change directory + set set environment variable or variables + + Any other command is assumed to be the name of a task. The syntax of a + task invocation statement is as follows: + + [$]task [<[fname]], ([[stream[(T|B)]]>[fname]])|([[stream]>>[fname]]) + + Everything but the task name is optional. A leading $ enables printing of + the cpu time and clock time consumed by the process at termination. Any + combination of the standard i/o streams may be redirected on the command + line into a file. If the stream is redirected at the CL level redirection + is shown on the command line but the filename is omitted. + +[3] The communications protocol during task execution varies depending on + whether or not we are talking to the CL. If talking directly to the user, + the interpreter generates a prompt, and the standard input and output is + not blocked into XMIT and XFER commands. Interactive parameter requests + have the form "paramname: response" while CL/IPC requests have the form + "paramname=\nresponse", where "response" is the value entered by the user. + +[4] Task termination is indicated in interactive mode by generation of a prompt + for the next command and in CL/IPC mode by transmission of the command + "bye" to the parent process. If a task terminates abnormally the command + "error" is sent to the parent process or the terminal, and the Main reenters + the interpreter loop. + +A unique SYS_RUNTASK procedure is generated for each process at compile time by +performing string substitution on a TASK statement appearing in the source code. +The SYS_RUNTASK procedure contains the task dictionary, CALL statements for +each task, plus the special task "?". The main itself, i.e. this file, is a +precompiled library procedure which has no direct knowledge of the commands +to be run. + + +ERROR RECOVERY + + If a task terminates abnormally two things can happen: [1] a panic abort +occurs, causing immediate shutdown of the process (rare), or [2] the IRAF Main +is reentered at the ZSVJMP statement by a corresponding call to ZDOJMP from +elsewhere in the system, e.g., ERRACT in the error handling code. + +Error restart consists of the following steps: + + (1) The IRAF main is reentered at the point just after the ZDOJMP statement, + with a nonzero error code identifying the error in STATUS. + (2) The main performs error recovery, cleaning up the files system (deleting + NEW_FILES and TEMP_FILES), clearing the stack, and calling any + procedures posted with ONERROR. At present the error recovery code does + not free heap buffers or clear posted exception handlers. + (3) The ERROR statement is sent to the CL. An example of the + error statment is "ERROR (501, "Access Violation")". + (4) The main reenters the interpreter loop awaiting the next command from + the CL. + +Any error occuring during error restart is fatal and results in immediate +process termination, usually with a panic error message. This is necessary +to prevent infinite error recursion. + + +SHUTDOWN + + The process does not shutdown when interrupted by the CL or during error +recovery, unless a panic occurs. In normal operation shutdown only occurs when +the command BYE is received from the parennt process, or when EOF is read from +the process standard input. Procedures posted during execution with ONEXIT +will be called during process shutdown. Any error occuring while executing +an ONEXIT procedure is fatal and will result in a panic abort of the process. +.endhelp _____________________________________________________________________ + +define SZ_VALSTR SZ_COMMAND +define SZ_CMDBUF (SZ_COMMAND+1024) +define SZ_TASKNAME 32 +define TIMEIT_CHAR '$' +define MAXFD 5 # max redirectable fd's +define STARTUP 0 # stages of execution +define SHUTDOWN 1 +define IDLE 2 +define EXECUTING 3 +define DUMMY finit # any procedure will do + + +# IRAF_MAIN -- Execute commands read from the standard input until the special +# command "bye" is received, initiating process shutdown. The arguments tell +# the process type (connected, detached, or host) and identify the process +# standard i/o channels and device driver to be used. + +int procedure iraf_main (a_cmd, a_inchan, a_outchan, a_errchan, + a_driver, a_devtype, prtype, bkgfile, jobcode, sys_runtask, onentry) + +char a_cmd[ARB] # command to be executed or null string +int a_inchan # process standard input +int a_outchan # process standard output +int a_errchan # process standard error output +int a_driver # ZLOCPR address of device driver +int a_devtype # device type (text or binary) +int prtype # process type (connected, detached, host) +char bkgfile[ARB] # packed filename of bkg file if detached +int jobcode # jobcode if detached process +extern sys_runtask() # client task execution procedure +extern onentry() # client onentry procedure + +bool networking +int inchan, outchan, errchan, driver, devtype +char cmd[SZ_CMDBUF], taskname[SZ_TASKNAME], bkgfname[SZ_FNAME] +char irafinit[SZ_LINE] +int arglist_offset, timeit, junk, interactive, builtin_task, cmdin +int jumpbuf[LEN_JUMPBUF], status, errstat, state, interpret, i +long save_time[2] +pointer sp + +bool streq() +extern DUMMY() +int sys_getcommand(), sys_runtask(), oscmd() +int access(), envscan(), onentry(), stropen(), envgets() +errchk xonerror, fio_cleanup +common /JUMPCOM/ jumpbuf +string nullfile "dev$null" +data networking /KNET/ +define shutdown_ 91 + +# The following common is required on VMS systems to defeat the Fortran +# optimizer, which would otherwise produce optimizations that would cause +# a future return from ZSVJMP to fail. Beware that this trick may fail on +# other systems with clever optimizers. + +common /zzfakecom/ state + +begin + # The following initialization code is executed upon process + # startup only. + + errstat = OK + state = STARTUP + call mio_init() + call zsvjmp (jumpbuf, status) + if (status != OK) + call sys_panic (EA_FATAL, "fatal error during process startup") + + # Install the standard exception handlers, but if we are a connected + # subprocess do not enable interrupts until process startup has + # completed. + + call ma_ideh() + if (prtype == PR_CONNECTED) + call intr_disable() + + inchan = a_inchan + outchan = a_outchan + errchan = a_errchan + driver = a_driver + devtype = a_devtype + + # If the system is configured with networking initialize the network + # interface and convert the input channel codes and device driver + # code to their network equivalents. + + if (networking) + call ki_init (inchan, outchan, errchan, driver, devtype) + + # Other initializations. + call env_init() + call fmt_init (FMT_INITIALIZE) # init printf + call xer_reset() # init error checking + call erract (OK) # init error handling + call onerror (DUMMY) # init onerror + call onexit (DUMMY) # init onexit + call finit() # initialize FIO + call clopen (inchan, outchan, errchan, driver, devtype) + call clseti (CL_PRTYPE, prtype) + call clc_init() # init param cache + call strupk (bkgfile, bkgfname, SZ_FNAME) + + # If we are running as a host process (no IRAF parent process) look + # for the file "zzsetenv.def" in the current directory and then in + # the system library, and initialize the environment from this file + # if found. This works because the variable "iraf$" is defined at + # the ZGTENV level. + + interactive = NO + if (prtype == PR_HOST) { + interactive = YES + if (access ("zzsetenv.def",0,0) == YES) { + iferr (junk = envscan ("set @zzsetenv.def")) + ; + } else if (access ("hlib$zzsetenv.def",0,0) == YES) { + iferr (junk = envscan ("set @hlib$zzsetenv.def")) + ; + } else if (access ("host$hlib/zzsetenv.def",0,0) == YES) { + iferr (junk = envscan ("set @host$hlib/zzsetenv.def")) + ; + } + + # Allow the 'irafinit' environment variable to point to a file + # that may partially override the system zzsetenv.def file. + if (envgets ("irafinit", irafinit, SZ_LINE) > 0) { + if (access (irafinit, 0, 0) == YES) { + call sprintf (cmd, SZ_CMDBUF, "set @%s") + call pargstr (cmd) + iferr (junk = envscan (cmd)) + ; + } + } + } + + # Save context for error restart. If an error occurs execution + # resumes just past the ZSVJMP statement with a nonzero status. + + call smark (sp) + call zsvjmp (jumpbuf, status) + + if (status != OK) { + errstat = status + + # Give up if error occurs during shutdown. + if (state == SHUTDOWN) + call sys_panic (errstat, "fatal error during process shutdown") + + # Tell error handling package that an error restart is in + # progress (necessary to avoid recursion). + + call erract (EA_RESTART) + + iferr { + # Call user cleanup routines and then clean up files system. + # Make sure that user cleanup routines are called FIRST. + + call xonerror (status) + call ma_ideh() + call flush (STDERR) + do i = CLIN, STDPLOT + call fseti (i, F_CANCEL, OK) + call fio_cleanup (status) + call fmt_init (FMT_INITIALIZE) + call sfree (sp) + } then + call erract (EA_FATAL) # panic abort + + # Send ERROR statement to the CL, telling the CL that the task + # has terminated abnormally. The CL will either kill us, resulting + # in error restart with status=SYS_XINT, or send us another command + # to execute. If we are connected but idle, do not send the ERROR + # statement because the CL will not read it until it executes the + # next task (which it will then mistakenly think has aborted). + + if (!(prtype == PR_CONNECTED && state == IDLE)) + call xer_send_error_statement_to_cl (status) + + # Inform error handling code that error restart has completed, + # or next error call will result in a panic shutdown. + + call erract (OK) + call xer_reset () + status = OK + } + + # During process startup and shutdown the parent is not listening to + # us, hence we dump STDOUT and STDERR into the null file. If this is + # not done and we write to CLOUT, deadlock may occur. During startup + # we also call the ONENTRY procedure. This is a no-op for connected + # and host subprocesses unless a special procedure is linked by the + # user (for detached processes the standard ONENTRY procedure opens + # the bkgfile as CLIN). The return value of ONENTRY determines whether + # the interpreter loop is entered. Note that ONENTRY permits complete + # bypass of the standard interpreter loop by an application (e.g. the + # IRAF CL). + + if (state == STARTUP) { + # Redirect stderr and stdout to the null file. + if (prtype == PR_CONNECTED) { + call fredir (STDOUT, nullfile, WRITE_ONLY, TEXT_FILE) + call fredir (STDERR, nullfile, WRITE_ONLY, TEXT_FILE) + } + + # Call the custom or default ONENTRY procedure. The lowest bit + # of the return value contains the PR_EXIT/PR_NOEXIT flag, higher + # bits may contain a more meaningful 7-bit status code which will + # be returned to the shell. + + i = onentry (prtype, bkgfname, a_cmd) + if (mod(i, 2) == PR_EXIT) { + interpret = NO + errstat = i / 2 + goto shutdown_ + } else + interpret = YES + + # Open the command input stream. If a command string was given on + # the command line then we read commands from that, otherwise we + # take commands from CLIN. + + for (i=1; IS_WHITE(a_cmd[i]) || a_cmd[i] == '\n'; i=i+1) + ; + if (a_cmd[i] != EOS) { + cmdin = stropen (a_cmd, ARB, READ_ONLY) + call fseti (cmdin, F_KEEP, YES) + interpret = NO + interactive = NO + } else + cmdin = CLIN + } + + # Interpreter loop of the IRAF Main. Execute named tasks until the + # command "bye" is received, or EOF is read on the process standard + # input (CLIN). Prompts and other perturbations in the CL/IPC protocol + # are generated if we are being run directly as a host process. + + while (sys_getcommand (cmdin, cmd, taskname, arglist_offset, + timeit, prtype) != EOF) { + + builtin_task = NO + if (streq (taskname, "bye")) { + # Initiate process shutdown. + break + } else if (streq (taskname, "set") || streq (taskname, "reset")) { + builtin_task = YES + } else if (streq (taskname, "cd") || streq (taskname, "chdir")) { + builtin_task = YES + } else if (prtype == PR_CONNECTED && streq (taskname, "_go_")) { + # Restore the normal standard output streams, following + # completion of process startup. Reenable interrupts. + call close (STDOUT) + call close (STDERR) + call intr_enable() + state = IDLE + next + } else if (taskname[1] == '!') { + # Send a command to the host system. + junk = oscmd (cmd[arglist_offset], "", "", "") + next + } else + state = EXECUTING + + if (builtin_task == NO) { + if (timeit == YES) + call sys_mtime (save_time) + + # Clear the parameter cache. + call clc_init() + + # Set the name of the root pset. + call clc_newtask (taskname) + + # Process the argument list, consisting of any mixture of + # parameter=value directives and i/o redirection directives. + + call sys_scanarglist (cmdin, cmd[arglist_offset]) + } + + # Call sys_runtask (the code for which was generated automatically + # by the preprocessor in place of the TASK statement) to search + # the dictionary and run the named task. + + errstat = OK + call mem_init (taskname) + if (sys_runtask (taskname,cmd,arglist_offset,interactive) == ERR) { + call flush (STDOUT) + call sprintf (cmd, SZ_CMDBUF, + "ERROR (0, \"Iraf Main: Unknown task name (%s)\")\n") + call pargstr (taskname) + call putline (CLOUT, cmd) + call flush (CLOUT) + state = IDLE + next + } + call mem_fini (taskname) + + # Cleanup after successful termination of command. Flush the + # standard output, cancel any unread standard input so the next + # task won't try to read it, print elapsed time if enabled, + # check for an incorrect error handler, call any user posted + # termination procedures, close open files, close any redirected + # i/o and restore the normal standard i/o streams. + + if (builtin_task == NO) { + + call flush (STDOUT) + call fseti (STDIN, F_CANCEL, OK) + + if (timeit == YES) + call sys_ptime (STDERR, taskname, save_time) + + call xer_verify() + call xonerror (OK) + call fio_cleanup (OK) + + if (prtype == PR_CONNECTED) { + call putline (CLOUT, "bye\n") + call flush (CLOUT) + } + if (state != STARTUP) + state = IDLE + } + } + + # The interpreter has exited after receipt of "bye" or EOF. Redirect + # stdout and stderr to the null file (since the parent is no longer + # listening to us), call the user exit procedures if any, and exit. + +shutdown_ + state = SHUTDOWN + if (prtype == PR_CONNECTED) { + call fredir (STDOUT, nullfile, WRITE_ONLY, TEXT_FILE) + call fredir (STDERR, nullfile, WRITE_ONLY, TEXT_FILE) + } else if (prtype == PR_HOST && cmd[1] == EOS && interpret == YES) { + call putci (CLOUT, '\n') + call flush (CLOUT) + } + + call xonexit (OK) + call fio_cleanup (OK) + call clclose() + + return (errstat) +end + + +# SYS_GETCOMMAND -- Get the next command from the input file. Ignore blank +# lines and comment lines. Parse the command and return the components as +# output arguments. EOF is returned as the function value when eof file is +# reached on the input file. + +int procedure sys_getcommand (fd, cmd, taskname, arglist_offset, timeit, prtype) + +int fd #I command input file +char cmd[SZ_CMDBUF] #O command line +char taskname[SZ_TASKNAME] #O extracted taskname, lower case +int arglist_offset #O offset into CMD of first argument +int timeit #O if YES, time the command +int prtype #I process type code + +int ip, op +int getlline(), stridx() + +begin + repeat { + # Get command line. Issue prompt first if process is being run + # interactively. + + if (prtype == PR_HOST && fd == CLIN) { + call putline (CLOUT, "> ") + call flush (CLOUT) + } + if (getlline (fd, cmd, SZ_CMDBUF) == EOF) + return (EOF) + + # Check for timeit character and advance to first character of + # the task name. + + timeit = NO + for (ip=1; cmd[ip] != EOS; ip=ip+1) { + if (cmd[ip] == TIMEIT_CHAR && timeit == NO) + timeit = YES + else if (!IS_WHITE (cmd[ip])) + break + } + + # Skip blank lines and comment lines. + switch (cmd[ip]) { + case '#', '\n', EOS: + next + case '?', '!': + taskname[1] = cmd[ip] + taskname[2] = EOS + arglist_offset = ip + 1 + return (OK) + } + + # Extract task name. + op = 1 + while (IS_ALNUM (cmd[ip]) || stridx (cmd[ip], "_.$") > 0) { + taskname[op] = cmd[ip] + ip = ip + 1 + op = min (SZ_TASKNAME + 1, op + 1) + } + taskname[op] = EOS + + # Determine index of argument list. + while (IS_WHITE (cmd[ip])) + ip = ip + 1 + arglist_offset = ip + + # Get rid of the newline. + for (; cmd[ip] != EOS; ip=ip+1) + if (cmd[ip] == '\n') { + cmd[ip] = EOS + break + } + + return (OK) + } +end + + +# SYS_SCANARGLIST -- Parse the argument list of a task. At the level of the +# iraf main the command syntax is very simple. There are two types of +# arguments, parameter assignments (including switches) and i/o redirection +# directives. All param assignments are of the form "param=value", where +# PARAM must start with a lower case alpha and where VALUE is either quoted or +# is delimited by one of the metacharacters [ \t\n<>\\]. A redirection argument +# is anything which is not a parameter set argument, i.e., any argument which +# does not start with a lower case alpha. + +procedure sys_scanarglist (cmdin, i_args) + +int cmdin # command input stream +char i_args[ARB] # (first part of) argument list + +int fd +char ch +bool skip +pointer sp, fname, args, ip, op +int getlline() + +begin + call smark (sp) + call salloc (args, SZ_CMDBUF, TY_CHAR) + call salloc (fname, SZ_FNAME, TY_CHAR) + + call strcpy (i_args, Memc[args], SZ_CMDBUF) + + # Do not skip whitespace for param=value args on the command line. + skip = false + + # Inform FIO that all standard i/o streams are unredirected (overridden + # below if redirected by an argument). + + for (fd=1; fd < FIRST_FD; fd=fd+1) + call fseti (fd, F_REDIR, NO) + + # Process each argument in the argument list. If the command line ends + # with an escaped newline then continuation is assumed. Arguments are + # delimited by whitespace. + + for (ip=args; Memc[ip] != '\n' && Memc[ip] != EOS; ) { + # Advance to the next argument. + while (IS_WHITE (Memc[ip])) + ip = ip + 1 + + # Check for continuation. + ch = Memc[ip] + if (ch == '\\' && (Memc[ip+1] == '\n' || Memc[ip+1] == EOS)) { + if (getlline (cmdin, Memc[args], SZ_CMDBUF) == EOF) { + call sfree (sp) + return + } + ip = args + next + } else if (ch == '\n' || ch == EOS) + break + + # If the argument begins with an alpha, _, or $ (e.g., $nargs) + # then it is a param=value argument, otherwise it must be a redir. + # The form @filename causes param=value pairs to be read from + # the named file. + + if (ch == '@') { + op = fname + for (ip=ip+1; Memc[ip] != EOS; ip=ip+1) + if (IS_WHITE (Memc[ip]) || Memc[ip] == '\n') + break + else if (Memc[ip] == '\\' && Memc[ip+1] == '\n') + break + else { + Memc[op] = Memc[ip] + op = op + 1 + } + Memc[op] = EOS + call sys_getpars (Memc[fname]) + + } else if (IS_ALPHA(ch) || ch == '_' || ch == '$') { + call sys_paramset (Memc, ip, skip) + } else + call sys_redirect (Memc, ip) + } + + call sfree (sp) +end + + +# SYS_GETPARS -- Read a sequence of param=value parameter assignments from +# the named file and enter them into the CLIO cache for the task. + +procedure sys_getpars (fname) + +char fname # pset file + +bool skip +int lineno, fd +pointer sp, lbuf, ip +int open(), getlline() +errchk open, getlline + +begin + call smark (sp) + call salloc (lbuf, SZ_CMDBUF, TY_CHAR) + + fd = open (fname, READ_ONLY, TEXT_FILE) + + # Skip whitespace for param = value args in a par file. + skip = true + + lineno = 0 + while (getlline (fd, Memc[lbuf], SZ_CMDBUF) != EOF) { + lineno = lineno + 1 + for (ip=lbuf; IS_WHITE (Memc[ip]); ip=ip+1) + ; + if (Memc[ip] == '#' || Memc[ip] == '\n') + next + iferr (call sys_paramset (Memc, ip, skip)) { + for (; Memc[ip] != EOS && Memc[ip] != '\n'; ip=ip+1) + ; + Memc[ip] = EOS + call eprintf ("Bad param assignment, line %d: `%s'\n") + call pargi (lineno) + call pargstr (Memc[lbuf]) + } + } + + call close (fd) + call sfree (sp) +end + + +# SYS_PARAMSET -- Extract the param and value substrings from a param=value +# or switch argument and enter them into the CL parameter cache. (see also +# clio.clcache). + +procedure sys_paramset (args, ip, skip) + +char args[ARB] # argument list +int ip # pointer to first char of argument +bool skip # skip whitespace within "param=value" args + +pointer sp, param, value, op +int stridx() + +begin + call smark (sp) + call salloc (param, SZ_FNAME, TY_CHAR) + call salloc (value, SZ_VALSTR, TY_CHAR) + + # Extract the param field. + op = param + while (IS_ALNUM (args[ip]) || stridx (args[ip], "_.$") > 0) { + Memc[op] = args[ip] + op = op + 1 + ip = ip + 1 + } + Memc[op] = EOS + + # Advance to the switch character or assignment operator. + while (IS_WHITE (args[ip])) + ip = ip + 1 + + switch (args[ip]) { + case '+': + # Boolean switch "yes". + ip = ip + 1 + call strcpy ("yes", Memc[value], SZ_VALSTR) + + case '-': + # Boolean switch "no". + ip = ip + 1 + call strcpy ("no", Memc[value], SZ_VALSTR) + + case '=': + # Extract the value field. This is either a quoted string or a + # string delimited by any of the metacharacters listed below. + + ip = ip + 1 + if (skip) { + while (IS_WHITE (args[ip])) + ip = ip + 1 + } + call sys_gstrarg (args, ip, Memc[value], SZ_VALSTR) + + default: + call error (1, "IRAF Main: command syntax error") + } + + # Enter the param=value pair into the CL parameter cache. + call clc_enter (Memc[param], Memc[value]) + + call sfree (sp) +end + + +# SYS_REDIRECT -- Process a single redirection argument. The syntax of an +# argument to redirect the standard input is +# +# < [fname] +# +# If the filename is omitted it is understood that STDIN has been redirected +# in the CL. The syntax to redirect a standard output stream is +# +# [45678][TB](>|>>)[fname] +# +# where [4567] is the FD number of a standard output stream (STDOUT, STDERR, +# STDGRAPH, STDIMAGE, or STDPLOT), and [TB] indicates if the file is text or +# binary. If the stream is redirected at the CL level the output filename +# will be given as `$', serving only to indicate that the stream is redirected. + +procedure sys_redirect (args, ip) + +char args[ARB] # argument list +int ip # pointer to first char of redir arg + +pointer sp, fname +int fd, mode, type +int ctoi() +define badredir_ 91 +errchk fredir, fseti + +begin + call smark (sp) + call salloc (fname, SZ_FNAME, TY_CHAR) + + # Get number of stream (0 if not given). + if (ctoi (args, ip, fd) <= 0) + fd = 0 + + # Get file type (optional). + while (IS_WHITE (args[ip])) + ip = ip + 1 + + switch (args[ip]) { + case 'T', 't': + type = TEXT_FILE + ip = ip + 1 + case 'B', 'b': + type = BINARY_FILE + ip = ip + 1 + default: + type = 0 + } + + # Check for "<", ">", or ">>". + while (IS_WHITE (args[ip])) + ip = ip + 1 + + switch (args[ip]) { + case '<': + ip = ip + 1 + mode = READ_ONLY + if (fd == 0) + fd = STDIN + else if (fd != STDIN || fd != CLIN) + goto badredir_ + + case '>': + ip = ip + 1 + if (args[ip] == '>') { + ip = ip + 1 + mode = APPEND + } else + mode = NEW_FILE + + if (fd == 0) + fd = STDOUT + else { + switch (fd) { + case CLOUT, STDOUT, STDERR, STDGRAPH, STDIMAGE, STDPLOT: + ; + default: + goto badredir_ + } + } + + default: + # Not a redirection argument. + call error (1, "IRAF Main: command syntax error") + } + + # Set default file type for given stream if no type specified. + if (type == 0) + switch (fd) { + case CLIN, CLOUT, STDIN, STDOUT, STDERR: + type = TEXT_FILE + default: + type = BINARY_FILE + } + + # Extract the filename, if any. If the CL has redirected the output + # and is merely using the redirection syntax to inform us of this, + # the metafilename "$" is given. + + while (IS_WHITE (args[ip])) + ip = ip + 1 + + if (args[ip] == '$') { + Memc[fname] = EOS + ip = ip + 1 + } else + call sys_gstrarg (args, ip, Memc[fname], SZ_FNAME) + + # At this point we have FD, FNAME, MODE and TYPE. If no file is + # named the stream has already been redirected by the parent and + # all we need to is inform FIO that the stream has been redirected. + # Otherwise we redirect the stream in the local process. A locally + # redirected stream will be closed and the normal direction restored + # during FIO cleanup, at program termination or during error + # recovery. + + if (Memc[fname] != EOS) + call fredir (fd, Memc[fname], mode, type) + else + call fseti (fd, F_REDIR, YES) + + call sfree (sp) + return + +badredir_ + call error (2, "IRAF Main: illegal redirection") +end + + +# SYS_GSTRARG -- Extract a string field. This is either a quoted string or a +# string delimited by any of the metacharacters " \t\n<>\\". + +procedure sys_gstrarg (args, ip, outstr, maxch) + +char args[ARB] # input string +int ip # pointer into input string +char outstr[maxch] # receives string field +int maxch + +char delim, ch +int op +int stridx() + +begin + op = 1 + if (args[ip] == '"' || args[ip] == '\'') { + # Quoted value string. + + delim = args[ip] + for (ip=ip+1; args[ip] != delim && args[ip] != EOS; ip=ip+1) { + if (args[ip] == '\n') { + break + } else if (args[ip] == '\\' && args[ip+1] == delim) { + outstr[op] = delim + op = op + 1 + ip = ip + 1 + } else { + outstr[op] = args[ip] + op = op + 1 + } + } + + } else { + # Nonquoted value string. + + for (delim=-1; args[ip] != EOS; ip=ip+1) { + ch = args[ip] + if (ch == '\\' && (args[ip+1] == '\n' || args[ip+1] == EOS)) + break + else if (stridx (ch, " \t\n<>\\") > 0) + break + else { + outstr[op] = ch + op = op + 1 + } + } + } + + outstr[op] = EOS + if (args[ip] == delim) + ip = ip + 1 +end diff --git a/sys/etc/miiread.gx b/sys/etc/miiread.gx new file mode 100644 index 00000000..a3efff2d --- /dev/null +++ b/sys/etc/miiread.gx @@ -0,0 +1,50 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mii.h> + +# MIIREAD -- Read a block of data stored externally in MII format. +# Data is returned in the format of the local host machine. + +int procedure mii_read$t (fd, spp, maxelem) + +int fd #I input file +PIXEL spp[ARB] #O receives data +int maxelem # max number of data elements to be read + +pointer sp, bp +int pksize, nchars, nelem +int miipksize(), miinelem(), read() +errchk read() + +long note() + +begin + pksize = miipksize (maxelem, MII_PIXEL) + nelem = EOF + + if (pksize > maxelem * SZ_PIXEL) { + # Read data into local buffer and unpack into user buffer. + + call smark (sp) + call salloc (bp, pksize, TY_CHAR) + + nchars = read (fd, Memc[bp], pksize) + if (nchars != EOF) { + nelem = min (maxelem, miinelem (nchars, MII_PIXEL)) + call miiupk$t (Memc[bp], spp, nelem, TY_PIXEL) + } + + call sfree (sp) + + } else { + # Read data into user buffer and unpack in place. + + nchars = read (fd, spp, pksize) + if (nchars != EOF) { + nelem = min (maxelem, miinelem (nchars, MII_PIXEL)) + call miiupk$t (spp, spp, nelem, TY_PIXEL) + } + } + + return (nelem) +end diff --git a/sys/etc/miireadc.x b/sys/etc/miireadc.x new file mode 100644 index 00000000..9354307c --- /dev/null +++ b/sys/etc/miireadc.x @@ -0,0 +1,50 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mii.h> + +# MIIREADC -- Read a block of character data stored externally in MII format. +# Data is returned in the machine independent character format. + +int procedure mii_readc (fd, spp, maxchars) + +int fd # input file +int spp[ARB] # receives data +int maxchars # max number of chars to be read + +pointer sp, bp +int pksize, nchars +int miipksize(), miinelem(), read() +errchk read() + +long note() + +begin + pksize = miipksize (maxchars, MII_BYTE) + nchars = max (maxchars, pksize) + + if (nchars > maxchars) { + # Read data into local buffer and unpack into user buffer. + + call smark (sp) + call salloc (bp, nchars, TY_CHAR) + + nchars = read (fd, Memc[bp], pksize) + if (nchars != EOF) { + nchars = min (maxchars, miinelem (nchars, MII_BYTE)) + call miiupk8 (Memc[bp], spp, nchars, TY_CHAR) + } + + call sfree (sp) + + } else { + # Read data into user buffer and unpack in place. + + nchars = read (fd, spp, pksize) + if (nchars != EOF) { + nchars = min (maxchars, miinelem (nchars, MII_BYTE)) + call miiupk8 (spp, spp, nchars, TY_CHAR) + } + } + + return (nchars) +end diff --git a/sys/etc/miiwrite.gx b/sys/etc/miiwrite.gx new file mode 100644 index 00000000..0bfce225 --- /dev/null +++ b/sys/etc/miiwrite.gx @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mii.h> + +# MIIWRITE -- Write a block of data to a file in MII format. +# The input data is in the host system native binary format. + +procedure mii_write$t (fd, spp, nelem) + +int fd #I output file +int spp[ARB] #I native format data to be written +int nelem #I number of data elements to be written + +pointer sp, bp +int bufsize +int miipksize() + +begin + call smark (sp) + + bufsize = miipksize (nelem, MII_PIXEL) + call salloc (bp, bufsize, TY_CHAR) + + call miipak$t (spp, Memc[bp], nelem, TY_PIXEL) + call write (fd, Memc[bp], bufsize) + + call sfree (sp) +end diff --git a/sys/etc/miiwritec.x b/sys/etc/miiwritec.x new file mode 100644 index 00000000..bdc20818 --- /dev/null +++ b/sys/etc/miiwritec.x @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mii.h> + +# MIIWRITEC -- Write a block of character data to a file in MII format. +# The input data is assumed to be in a machine independent format. + +procedure mii_writec (fd, spp, nchars) + +int fd # output file +int spp[ARB] # data to be written +int nchars # number of chars units to be written + +pointer sp, bp +int bufsize +int miipksize() + +begin + call smark (sp) + + bufsize = miipksize (nchars, MII_BYTE) + call salloc (bp, bufsize, TY_CHAR) + + call miipak8 (spp, Memc[bp], nchars, TY_CHAR) + call write (fd, Memc[bp], bufsize) + + call sfree (sp) +end diff --git a/sys/etc/mkpkg b/sys/etc/mkpkg new file mode 100644 index 00000000..578c290b --- /dev/null +++ b/sys/etc/mkpkg @@ -0,0 +1,125 @@ +# Make the ETC portion of the system library libsys.a. + +$checkout libsys.a lib$ +$update libsys.a +$checkin libsys.a lib$ +$exit + +generic: + $ifolder (gen/miireadi.x, miiread.gx) + $generic -k -p gen/ -t silrd miiread.gx + $endif + $ifolder (gen/miiwritei.x, miiwrite.gx) + $generic -k -p gen/ -t silrd miiwrite.gx + $endif + $ifolder (gen/nmireadi.x, nmiread.gx) + $generic -k -p gen/ -t silrd nmiread.gx + $endif + $ifolder (gen/nmiwritei.x, nmiwrite.gx) + $generic -k -p gen/ -t silrd nmiwrite.gx + $endif + ; + +libsys.a: + $ifeq (USE_GENERIC, yes) $call generic $endif + @gen + + brktime.x <time.h> + btoi.x + clktime.x + cnvdate.x <time.h> + cnvtime.x <time.h> + cputime.x + dtmcnv.x <time.h> <ctype.h> + envgetb.x + envgetd.x <mach.h> + envgeti.x <mach.h> + envgetr.x + envgets.x environ.h <fset.h> <knet.h> + envindir.x + envinit.x environ.com environ.h + environ.x environ.com environ.h <knet.h> + envlist.x environ.com environ.h + envnext.x environ.com environ.h + envreset.x environ.com environ.h <knet.h> + envscan.x environ.h <ctype.h> + erract.x error.com <config.h> <error.h> + errcode.x error.com <error.h> + errget.x error.com <error.h> + error.x error.com <error.h> + gethost.x + getpid.x + getuid.x + gmtcnv.x + gqsort.x + intr.x <xwhen.h> + itob.x + lineoff.x + locpr.x + locva.x + lpopen.x <knet.h> <mach.h> + maideh.x <fset.h> <xwhen.h> + main.x <clset.h> <config.h> <ctype.h> <error.h> <fset.h>\ + <knet.h> <printf.h> <xwhen.h> + miireadc.x <mii.h> + miiwritec.x <mii.h> + nmireadb.x <nmi.h> + nmireadc.x <nmi.h> + nmiwriteb.x <nmi.h> + nmiwritec.x <nmi.h> + onentry.x <clset.h> <error.h> <fset.h> <knet.h> + onerror.x <config.h> <error.h> + onexit.x <config.h> <error.h> + oscmd.x <clset.h> <ctype.h> <error.h> <knet.h> + pagefiles.x <chars.h> <ctype.h> <error.h> <finfo.h> <fset.h>\ + <mach.h> <ttyset.h> + prchdir.x + prclcpr.x prc.com <config.h> + prcldpr.x prd.com <config.h> <knet.h> + prclose.x prc.com <config.h> <prstat.h> + prdone.x prd.com <config.h> + prenvfree.x + prenvset.x + prfilbuf.x prc.com <config.h> <fio.h> + prfindpr.x prc.com <config.h> + prgline.x prc.com <config.h> <ctype.h> <fset.h> + prgredir.x prc.com <config.h> + prkill.x prd.com <config.h> <knet.h> + propcpr.x prc.com <config.h> <fset.h> <knet.h> <prstat.h>\ + <xwhen.h> + propdpr.x prd.com <config.h> <knet.h> + propen.x <knet.h> + proscmd.x prc.com <config.h> + prpsio.x prc.com <chars.h> <config.h> <error.h> <fio.com>\ + <fio.h> <fset.h> <gio.h> + prpsload.x prc.com <config.h> + prredir.x prc.com <config.h> + prseti.x prc.com <config.h> <prstat.h> + prsignal.x prc.com <config.h> <knet.h> + prstati.x prc.com <config.h> <prstat.h> + prupdate.x prc.com <config.h> <error.h> <prstat.h> + psioisxt.x <ctype.h> <gio.h> + psioxfer.x + qsort.x + sttyco.x <ctype.h> <error.h> <ttset.h> <ttyset.h> + syserr.x + sysid.x + syspanic.x + sysptime.x <ctype.h> + tsleep.x + ttopen.x <fset.h> + urlget.x <ctype.h> <fset.h> <mach.h> + votable.x + xalloc.x <ctype.h> <knet.h> <xalloc.h> + xerfmt.x <ctype.h> + xerpop.x error.com <error.h> + xerpue.x <config.h> <fio.com> <fio.h> <mach.h> + xerreset.x error.com <error.h> + xerstmt.x error.com <ctype.h> <error.h> + xerverify.x error.com <error.h> + xgdevlist.x <xalloc.h> + xisatty.x <clset.h> <fset.h> + xmjbuf.x <config.h> + xttysize.x <clset.h> + xwhen.x + ; diff --git a/sys/etc/nmiread.gx b/sys/etc/nmiread.gx new file mode 100644 index 00000000..401f1c2c --- /dev/null +++ b/sys/etc/nmiread.gx @@ -0,0 +1,50 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + +# NMI_READ -- Read a block of data stored externally in NMI format. +# Data is returned in the format of the local host machine. + +int procedure nmi_read$t (fd, spp, maxelem) + +int fd #I input file +PIXEL spp[ARB] #O receives data +int maxelem # max number of data elements to be read + +pointer sp, bp +int pksize, nchars, nelem +int nmipksize(), nminelem(), read() +errchk read() + +long note() + +begin + pksize = nmipksize (maxelem, NMI_PIXEL) + nelem = EOF + + if (pksize > maxelem * SZ_PIXEL) { + # Read data into local buffer and unpack into user buffer. + + call smark (sp) + call salloc (bp, pksize, TY_CHAR) + + nchars = read (fd, Memc[bp], pksize) + if (nchars != EOF) { + nelem = min (maxelem, nminelem (nchars, NMI_PIXEL)) + call nmiupk$t (Memc[bp], spp, nelem, TY_PIXEL) + } + + call sfree (sp) + + } else { + # Read data into user buffer and unpack in place. + + nchars = read (fd, spp, pksize) + if (nchars != EOF) { + nelem = min (maxelem, nminelem (nchars, NMI_PIXEL)) + call nmiupk$t (spp, spp, nelem, TY_PIXEL) + } + } + + return (nelem) +end diff --git a/sys/etc/nmireadb.x b/sys/etc/nmireadb.x new file mode 100644 index 00000000..dc23866c --- /dev/null +++ b/sys/etc/nmireadb.x @@ -0,0 +1,32 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + + +# NMI_READB -- Read a block of data stored externally in NMI format. +# Data is returned in the format of the local host machine. + +int procedure nmi_readb (fd, spp, maxelem) + +int fd #I input file +bool spp[ARB] #O receives data +int maxelem # max number of data elements to be read + +pointer sp, bp +int pksize, nchars, nelem +int nminelem(), read() +errchk read() + +long note() + +begin + pksize = nminelem (maxelem, NMI_INT) + nelem = EOF + + # Read data into user buffer and unpack in place. + nchars = read (fd, spp, pksize) + if (nchars != EOF) + nelem = min (maxelem, pksize) + + return (nelem) +end diff --git a/sys/etc/nmireadc.x b/sys/etc/nmireadc.x new file mode 100644 index 00000000..be65b9dd --- /dev/null +++ b/sys/etc/nmireadc.x @@ -0,0 +1,50 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + +# NMIREADC -- Read a block of character data stored externally in NMI format. +# Data is returned in the native machine character format. + +int procedure nmi_readc (fd, spp, maxchars) + +int fd # input file +int spp[ARB] # receives data +int maxchars # max number of chars to be read + +pointer sp, bp +int pksize, nchars +int nmipksize(), nminelem(), read() +errchk read() + +long note() + +begin + pksize = nmipksize (maxchars, NMI_BYTE) + nchars = max (maxchars, pksize) + + if (nchars > maxchars) { + # Read data into local buffer and unpack into user buffer. + + call smark (sp) + call salloc (bp, nchars, TY_CHAR) + + nchars = read (fd, Memc[bp], pksize) + if (nchars != EOF) { + nchars = min (maxchars, nminelem (nchars, NMI_BYTE)) + call nmiupk8 (Memc[bp], spp, nchars, TY_CHAR) + } + + call sfree (sp) + + } else { + # Read data into user buffer and unpack in place. + + nchars = read (fd, spp, pksize) + if (nchars != EOF) { + nchars = min (maxchars, nminelem (nchars, NMI_BYTE)) + call nmiupk8 (spp, spp, nchars, TY_CHAR) + } + } + + return (nchars) +end diff --git a/sys/etc/nmiwrite.gx b/sys/etc/nmiwrite.gx new file mode 100644 index 00000000..1efc4e45 --- /dev/null +++ b/sys/etc/nmiwrite.gx @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + +# NMI_WRITE -- Write a block of data to a file in NMI format. +# The input data is in the host system native binary format. + +procedure nmi_write$t (fd, spp, nelem) + +int fd #I output file +int spp[ARB] #I native format data to be written +int nelem #I number of data elements to be written + +pointer sp, bp +int bufsize +int nmipksize() + +begin + call smark (sp) + + bufsize = nmipksize (nelem, NMI_PIXEL) + call salloc (bp, bufsize, TY_CHAR) + + call nmipak$t (spp, Memc[bp], nelem, TY_PIXEL) + call write (fd, Memc[bp], bufsize) + + call sfree (sp) +end diff --git a/sys/etc/nmiwriteb.x b/sys/etc/nmiwriteb.x new file mode 100644 index 00000000..2819d1e8 --- /dev/null +++ b/sys/etc/nmiwriteb.x @@ -0,0 +1,21 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + + +# NMI_WRITEB -- Write a block of data to a file in NMI format. +# The input data is in the host system native binary format. + +procedure nmi_writeb (fd, spp, nelem) + +int fd #I output file +int spp[ARB] #I native format data to be written +int nelem #I number of data elements to be written + +int bufsize +int nminelem() + +begin + bufsize = nminelem (nelem, NMI_INT) + call write (fd, spp, bufsize) +end diff --git a/sys/etc/nmiwritec.x b/sys/etc/nmiwritec.x new file mode 100644 index 00000000..16dc572c --- /dev/null +++ b/sys/etc/nmiwritec.x @@ -0,0 +1,28 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <nmi.h> + +# NMIWRITEC -- Write a block of character data to a file in NMI format. +# The input data is assumed to be in a native machine format. + +procedure nmi_writec (fd, spp, nchars) + +int fd # output file +int spp[ARB] # data to be written +int nchars # number of chars units to be written + +pointer sp, bp +int bufsize +int nmipksize() + +begin + call smark (sp) + + bufsize = nmipksize (nchars, NMI_BYTE) + call salloc (bp, bufsize, TY_CHAR) + + call nmipak8 (spp, Memc[bp], nchars, TY_CHAR) + call write (fd, Memc[bp], bufsize) + + call sfree (sp) +end diff --git a/sys/etc/onentry.x b/sys/etc/onentry.x new file mode 100644 index 00000000..6a2e823d --- /dev/null +++ b/sys/etc/onentry.x @@ -0,0 +1,65 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <knet.h> +include <error.h> +include <clset.h> +include <fset.h> + +define NFD 2 + +# ONENTRY -- Default procedure called by the IRAF Main during process startup, +# before entering the interpreter loop. If desired the user can supply their +# own ONENTRY procedure; this will be used instead of the system default if +# specified on the link line before the iraf libraries are searched. +# This procedure is a no-op for a connected or host process. For a detached +# process the default action is to redirect the standard input to the bkgfile, +# which is assumed to be a text file containing commands to be executed by +# the Main. +# +# The basic host calling sequence for an iraf process is as follows: +# +# x_file.e [-c | -d bkgfile ] [ command ] +# +# This is parsed by the zmain (host level main), returning the process type +# in PRTYPE, the bkgfile string in BKGFILE if the process type is detached, +# and anything remaining on the command line in CMD. If a custom onentry +# procedure is used CMD can be anything; all the iraf main does is concatenate +# the arguments into a string and pass it to the onentry procedure as CMD. + +int procedure onentry (prtype, bkgfile, cmd) + +int prtype #I process type (connected, detached, host) +char bkgfile[ARB] #I osfn of bkg file, if detached process +char cmd[ARB] #I command argument string, if any + +char osfn[SZ_FNAME] +int chan, loc_zgettx, i, fd[NFD] +data fd[1] /CLIN/, fd[2] /STDIN/ +extern zgettx() + +begin + if (prtype == PR_DETACHED) { + # Open the bkgfile and connect it to CLIN and STDIN. The stdin + # supplied by the process main is not used in this mode. + # We assume that no i/o has yet occurred on either file. Note + # that we do not wish to use FREDIR as that would preclude + # redirection on the command line. + + call strpak (bkgfile, osfn, SZ_FNAME) + call zopntx (osfn, READ_ONLY, chan) + if (chan == ERR) + call sys_panic (EA_FATAL, "Cannot open bkgfile") + call zlocpr (zgettx, loc_zgettx) + + do i = 1, NFD { + call fseti (fd[i], F_CHANNEL, chan) + call fseti (fd[i], F_DEVICE, loc_zgettx) + call fseti (fd[i], F_TYPE, TEXT_FILE) + } + } + + # If PR_EXIT is returned the interpreter loop is bypassed and process + # shutdown occurs immediately. + + return (PR_NOEXIT) +end diff --git a/sys/etc/onerror.x b/sys/etc/onerror.x new file mode 100644 index 00000000..d8bd36f3 --- /dev/null +++ b/sys/etc/onerror.x @@ -0,0 +1,96 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> +include <syserr.h> +include <error.h> + +# ONERROR -- Give system the EPA of a procedure to be executed when task +# termination occurs (either normal task termination or task termination +# via error recovery). Each procedure will be called with the task termination +# status, i.e., OK for normal termination, else the ERRCODE argument to ERROR. + +procedure onerror (user_proc) + +extern user_proc() #I procedure to be posted + +int epa, i +bool first_time +int proc_list[MAX_ONERROR], nprocs +common /onercm/ nprocs, proc_list +data first_time /true/ + +begin + # The first call is by the IRAF main at process startup time, with + # a dummy argument. + + if (first_time) { + nprocs = 0 + first_time = false + return + } + + call zlocpr (user_proc, epa) + + # Ignore the call if the procedure has already been posted. + # Otherwise tack address of proc onto list and return. + + for (i=1; i <= nprocs; i=i+1) + if (epa == proc_list[i]) + return + + nprocs = nprocs + 1 + if (nprocs > MAX_ONERROR) + iferr (call syserr (SYS_SONERROVFL)) + call erract (EA_WARN) + + proc_list[nprocs] = epa +end + + +# ONERROR_REMOVE -- Remove a previously posted ONERROR procedure. + +procedure onerror_remove (user_proc) + +extern user_proc() #I procedure to be posted + +int epa, i +int proc_list[MAX_ONERROR], nprocs +common /onercm/ nprocs, proc_list + +begin + call zlocpr (user_proc, epa) + for (i=1; i <= nprocs; i=i+1) + if (proc_list[i] == epa) + proc_list[i] = 0 +end + + +# XONERROR -- Called at task termination by the IRAF Main to execute each of +# the posted user error cleanup procedures (if any). Procedures are executed +# in the order in which they were posted. The task termination status is +# passed to the called procedure as the single argument to the procedure. +# The list of termination handlers is cleared when finished. + +procedure xonerror (status) + +int status #I task termination status (OK or error code) + +int nprocs_to_execute, i +int proc_list[MAX_ONERROR], nprocs +common /onercm/ nprocs, proc_list +errchk zcall1 + +begin + # Clear "nprocs" before calling user procedures, to ensure that + # a reentrant call does not lead to an infinite loop (i.e., in the + # event of an error during execution of a cleanup procedure). + # In principle this should not be necessary, since an error occurring + # during error restart should result in a panic abort. + + nprocs_to_execute = nprocs + nprocs = 0 + + for (i=1; i <= nprocs_to_execute; i=i+1) + if (proc_list[i] != 0) + call zcall1 (proc_list[i], status) +end diff --git a/sys/etc/onexit.x b/sys/etc/onexit.x new file mode 100644 index 00000000..44212cf1 --- /dev/null +++ b/sys/etc/onexit.x @@ -0,0 +1,88 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> +include <syserr.h> +include <error.h> + +# ONEXIT -- Give system the EPA of a procedure to be executed when process +# shutdown occurs. + +procedure onexit (user_proc) + +extern user_proc() #I procedure to be posted +bool first_time +int epa, i +int proc_list[MAX_ONEXIT], nprocs +common /onexcm/ nprocs, proc_list +data first_time /true/ + +begin + # The first call is by the IRAF main at process startup time, with + # a dummy argument. + + if (first_time) { + nprocs = 0 + first_time = false + return + } + + call zlocpr (user_proc, epa) + + # Ignore the call if the procedure has already been posted. + # Otherwise tack address of proc onto list and return. + + for (i=1; i <= nprocs; i=i+1) + if (epa == proc_list[i]) + return + + nprocs = nprocs + 1 + if (nprocs > MAX_ONEXIT) + iferr (call syserr (SYS_SONEXITOVFL)) + call erract (EA_WARN) + + proc_list[nprocs] = epa +end + + +# ONEXIT_REMOVE -- Remove a previously posted ONEXIT procedure. + +procedure onexit_remote (user_proc) + +extern user_proc() #I procedure to be posted + +int epa, i +int proc_list[MAX_ONERROR], nprocs +common /onexcm/ nprocs, proc_list + +begin + call zlocpr (user_proc, epa) + for (i=1; i <= nprocs; i=i+1) + if (proc_list[i] == epa) + proc_list[i] = 0 +end + + +# XONEXIT -- Called at process shutdown time by the IRAF main to execute +# each posted user exit procedure. Exit procedures are called in the order +# in which they were posted. Try to survive errors so that all exit +# procedures may be called. Do not take an error action or issue a warning +# message, since by the time we are called the CL has stopped listening to +# us (it might possibly be safer to panic). + +procedure xonexit (exit_code) + +int exit_code #I passed to exit handlers +int nprocs_to_execute, i +int proc_list[MAX_ONEXIT], nprocs +common /onexcm/ nprocs, proc_list +errchk zcall1 + +begin + nprocs_to_execute = nprocs + nprocs = 0 + + for (i=1; i <= nprocs_to_execute; i=i+1) + if (proc_list[i] != 0) + iferr (call zcall1 (proc_list[i], exit_code)) + ; +end diff --git a/sys/etc/oscmd.x b/sys/etc/oscmd.x new file mode 100644 index 00000000..78b723c2 --- /dev/null +++ b/sys/etc/oscmd.x @@ -0,0 +1,116 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <ctype.h> +include <clset.h> +include <error.h> +include <knet.h> + +# OSCMD -- Send a (machine dependent) command to the host operating system. +# Try to spool the standard output and error output in the named files if +# nonnull names for the files are given. OK is returned if the command +# executes successfully. + +int procedure oscmd (cmd, infile, outfile, errfile) + +char cmd[ARB] # host command +char infile[ARB] # name of host command input file +char outfile[ARB] # name of file to receive output +char errfile[ARB] # name of file to receive error output + +int status, ip, ch +pointer sp, cmdbuf, osin, osout, oserr, ostmp, op +errchk fmapfn, mktemp, fclobber, flush, putline +int clstati(), getci() +bool fnullfile() + +begin + call smark (sp) + call salloc (cmdbuf, SZ_COMMAND, TY_CHAR) + call salloc (osin, SZ_PATHNAME, TY_CHAR) + call salloc (osout, SZ_PATHNAME, TY_CHAR) + call salloc (oserr, SZ_PATHNAME, TY_CHAR) + call salloc (ostmp, SZ_PATHNAME, TY_CHAR) + + # If we are called from the root process, e.g., the CL, the ZOSCMD + # primitive is called directly to transmit the host command, otherwise + # the OS command is sent up to the parent (root) process which calls + # ZOSCMD. This is necessary because the ZOSCMD primitive will not + # work from a subprocess on some systems, due to difficulties trying + # to spawn the host command interpreter. + + if (clstati (CL_PRTYPE) != PR_CONNECTED) { + # Root process: send command directly to the host command + # interpreter. + + # Pack command string and get OS versions of the filenames. + call strpak (cmd, Memc[cmdbuf], SZ_COMMAND) + if (infile[1] == EOS) + call strpak ("", Memc[osin], SZ_PATHNAME) + else + call fmapfn (infile, Memc[osin], SZ_PATHNAME) + + # If output is directed to dev$null, save in temp file and delete. + if (fnullfile(outfile) || fnullfile(errfile)) + call mktemp ("tmp$null", Memc[ostmp], SZ_PATHNAME) + else + Memc[ostmp] = EOS + + if (outfile[1] == EOS) + call strpak ("", Memc[osout], SZ_PATHNAME) + else if (fnullfile (outfile)) + call fmapfn (Memc[ostmp], Memc[osout], SZ_PATHNAME) + else { + call fclobber (outfile) + call fmapfn (outfile, Memc[osout], SZ_PATHNAME) + } + + if (errfile[1] == EOS) + call strpak ("", Memc[oserr], SZ_PATHNAME) + else if (fnullfile (errfile)) + call fmapfn (Memc[ostmp], Memc[oserr], SZ_PATHNAME) + else { + call fclobber (errfile) + call fmapfn (errfile, Memc[oserr], SZ_PATHNAME) + } + + # Execute the command and wait for completion. + call zoscmd (Memc[cmdbuf], Memc[osin], Memc[osout], Memc[oserr], + status) + + # Discard output directed to dev$null. + if (Memc[ostmp] != EOS) + iferr (call delete (Memc[ostmp])) + call erract (EA_WARN) + + } else { + # Connected subprocess. Send the command to the parent process to + # be processed as a system directive by the pseudofile i/o system + # in the parent process. Synchronous execution is desired, so wait + # for a status return from the parent process before returning. + # The redirection files are ignored in this mode. + + call flush (CLOUT) + + # Send command. + Memc[cmdbuf] = '!' + op = cmdbuf + 1 + for (ip=1; cmd[ip] != EOS && cmd[ip] != '\n'; ip=ip+1) { + Memc[op] = cmd[ip] + op = op + 1 + } + Memc[op] = '\n' + Memc[op+1] = EOS + call putline (CLOUT, Memc[cmdbuf]) + call flush (CLOUT) + + # Get the return status, encoded as a nonnegative decimal integer. + for (status=0; getci (CLIN, ch) != EOF; ) + if (ch == '\n') + break + else + status = status * 10 + TO_INTEG(ch) + } + + call sfree (sp) + return (status) +end diff --git a/sys/etc/pagefiles.x b/sys/etc/pagefiles.x new file mode 100644 index 00000000..22ef4840 --- /dev/null +++ b/sys/etc/pagefiles.x @@ -0,0 +1,1140 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <ttyset.h> +include <error.h> +include <ctype.h> +include <chars.h> +include <mach.h> +include <finfo.h> +include <fset.h> + +# PAGEFILES.X -- Page through a file or set of files. Both backwards and +# forwards traversals of files and file lists are supported, but not +# (currently) backwards paging of a pipe. +# +# This program is a hack as it was coded starting from the original PAGE +# program, which was much simpler. TODO: Add upscrolling and the ability +# to buffer input and scoll backwards on a pipe. The present program is +# monolithic and should be restructured if these features are added. + +define CC_PREFIX '^' +define MAKE_PRINTABLE ($1+'A'-1) +define SZ_QUERYMSG 80 +define SZ_KEYSTR 80 +define LNO_MAXLINES 2048 +define SZ_LONGLINE 4096 +define MAX_PAGE 100 +define MAX_PBCMD 100 +define UKEYS "ukey" # CL parameter for keyboard input + +# Command keystrokes. + +define HELPTXT "[q=quit,e=edit,d=dn,u=up,f|sp=fpg,b=bpg,j|cr=dnln,k=upln,.=bof,N=nfile,P=pfile]" + +define HELP '?' # print helptxt +define QUIT 'q' # return to CL +define EDIT 'e' # edit current file +define FWD_SCREEN 'f' # forward one full screen +define BACK_SCREEN 'b' # back one full screen +define SCROLL_DOWN 'd' # forward half a screen +define SCROLL_UP 'u' # back half a screen +define PREV_LINE 'k' # back one line +define NEXT_LINE 'j' # forward one line +define TO_BOF '.' # to beginning of file +define TO_EOF 'G' # to end of file +define TO_EOF_ALT 'g' # to end of file +define SEARCH 'n' # search for next occurrence of pattern +define REDRAW '\014' # redraw screen + +define NEXT_FILE 'N' # goto next file in list +define PREV_FILE 'P' # goto previous file in list +define NEXT_FILE_ALT '\016' # <ctrl/n> +define PREV_FILE_ALT '\020' # <ctrl/p> + +define LCMD ':' # colon commands +define TO_FILE 'F' # ":file filename" + + +# PAGEFILES -- 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. +# +# If map_cc is enabled, all unknown control characters will be converted into +# printable sequences. The following control character sequences have a +# special significance in IRAF textfiles: FF=formfeed, SO=set standout mode, +# SI=clear standout mode. These sequences are mapped into whatever the output +# device requires upon output by the TTY subroutines. + +procedure pagefiles (files) + +char files[ARB] # file template + +string device "terminal" +string prompt "" +int first_page +int clear_screen +int map_cc + +begin + first_page = 1 + clear_screen = YES + map_cc = YES + + call xpagefiles (files, device, + prompt, first_page, clear_screen, map_cc) +end + + +# PAGEFILE -- Page a single file; an alternate entry point to the more general +# routine. A prompt string different than the filename may be specified and +# the screen is not cleared when scrolling downward. + +procedure pagefile (fname, prompt) + +char fname[ARB] # name of file to be paged +char prompt[ARB] # prompt string, if different than fname + +string device "terminal" +int first_page +int clear_screen +int map_cc + +begin + first_page = 1 + clear_screen = NO + map_cc = YES + + call xpagefiles (fname, device, + prompt, first_page, clear_screen, map_cc) +end + + +# XPAGEFILES -- Generalized file pager. + +procedure xpagefiles (files, device, prompt, first_page, clear_screen, map_cc) + +char files[ARB] # file template +char device[ARB] # output device name +char prompt[ARB] # prompt string (filename if null) +int first_page # first page to be displayed +int clear_screen # clear screen between pages +int map_cc # map control chars on output + +bool redirin, useroot +pointer sp, fname, newfname, tty, lbuf +int spoolfd, list, nfiles, cmd, i, j, n, o + +pointer ttyodes() +bool ttygetb() +int strncmp(), strlen() +int fntopnb(), fntrfnb(), fntlenb(), fnldir() +int pg_getcmd(), pg_pagefile(), fstati() +errchk fntopnb, ttyodes, ttygetb, fntrfnb, pg_pagefile, pg_getcmd +define err_ 91 + +begin + call smark (sp) + call salloc (newfname, SZ_FNAME, TY_CHAR) + call salloc (fname, SZ_FNAME, TY_CHAR) + call salloc (lbuf, SZ_LINE, TY_CHAR) + + list = fntopnb (files, YES) + nfiles = fntlenb (list) + spoolfd = NULL + + tty = ttyodes (device) + redirin = (fstati (STDIN, F_REDIR) == YES) + + # If terminal cannot scroll, set clear_screen to true regardless of the + # value given above. + + if (ttygetb (tty, "ns")) + clear_screen = YES + + cmd = NEXT_FILE + for (i=1; i <= nfiles && cmd != QUIT; i=i+1) { + # Get next filename. + if (fntrfnb (list, i, Memc[fname], SZ_FNAME) == EOF) + break + + # Page the file. + cmd = pg_pagefile (tty, Memc[fname], Memc[newfname], prompt, + clear_screen, first_page, map_cc, i, nfiles, redirin, spoolfd) + + # Decide what to do next. + while (cmd != QUIT) { + switch (cmd) { + case NEXT_FILE, BLANK, NEXT_LINE, CR, LF: + if (i >= nfiles) + cmd = pg_getcmd (tty, "no more files", 0,0,0,i,nfiles) + else + break + case PREV_FILE: + if (i <= 1) + cmd = pg_getcmd (tty, "at first file", 0,0,0,i,nfiles) + else { + i = i - 2 + break + } + + case TO_FILE: + # Position within the file list. If the user specified a + # logical directory in the filename, perform the compares + # on the raw filenames in the list, otherwise use only the + # root filename. + + useroot = (fnldir(Memc[newfname],Memc[fname],SZ_FNAME) <= 0) + n = strlen (Memc[newfname]) + + for (j=1; j <= nfiles; j=j+1) + if (fntrfnb (list, j, Memc[lbuf], SZ_FNAME) > 0) { + if (useroot) + o = fnldir (Memc[lbuf], Memc[fname], SZ_FNAME) + else + o = 0 + if (strncmp (Memc[lbuf+o], Memc[newfname], n) >= 0) + break + } + + if (j > nfiles) + i = nfiles - 1 + else + i = j - 1 + break + + case LCMD: + # Colon escape. Only :file is recognized at this level. + + call pg_getstr (Memc[newfname], SZ_FNAME) + cmd = TO_FILE + + case HELP: + cmd = pg_getcmd (tty, HELPTXT, 0,0,0,0,0) + + default: +err_ if (!redirin) { + call eprintf ("\07") + call flush (STDERR) + i = i - 1 # redisplay current file + } + break + } + } + } + + if (spoolfd != NULL) + call close (spoolfd) + + call fntclsb (list) + call sfree (sp) +end + + +# PG_PAGEFILE -- Display the named file on the standard output, page by +# page, pausing for user response between pages. + +int procedure pg_pagefile (tty, fname, newfname, u_prompt, clear_screen, + first_page, map_cc, fileno, nfiles, redirin, spoolfd) + +pointer tty +char fname[ARB] # file to be paged +char newfname[ARB] # next file to be page (ret. by :file) +char u_prompt[ARB] # prompt string, if not same as filename +int clear_screen # clear screen between pages? +int first_page # first page of file to be displayed +int map_cc # map control characters? +int fileno # current file number +int nfiles # number of files to be paged +bool redirin # reading from the standard input +int spoolfd # fd if spooling output in a file + +char patbuf[SZ_LINE] +int nlines, ncols, maxlines, maxcols +long fi[LEN_FINFO], nchars, totchars, loffset +pointer sp, lbuf, prompt, token, cmdbuf, ip, op, lp +long pgoff[MAX_PAGE], pgnch[MAX_PAGE], pglno[MAX_PAGE] +int fd, lineno, linelen, nleft, destline, toklen, lnout, i +bool ateof, first_call, redirout, pushback, upline, upline_ok +int o_loffset, o_nchars, o_lineno, o_pageno, junk, pageno, cmd, ch, n + +long note() +pointer lno_open() +bool streq(), ttygetb() +int pg_getcmd(), ctoi(), strncmp(), patmake(), patmatch(), pg_peekcmd() +int open(), finfo(), strlen(), pg_getline(), getci() +int lno_fetch(), fstati(), ttyctrl() +data first_call /true/ + +define err_ 91 +define quit_ 92 +define search_ 93 +define destline_ 94 + +begin + call smark (sp) + call salloc (lbuf, SZ_LONGLINE, TY_CHAR) + call salloc (cmdbuf, SZ_LINE, TY_CHAR) + call salloc (prompt, SZ_FNAME, TY_CHAR) + call salloc (token, SZ_FNAME, TY_CHAR) + + if (first_call) { + # The pattern buffer is retained indefinitely. + patbuf[1] = EOS + spoolfd = NULL + first_call = false + } + + call pg_setprompt (Memc[prompt], u_prompt, fname) + call xttysize (ncols, nlines) + maxlines = nlines - 1 + maxcols = ncols + + redirout = (fstati (STDOUT, F_REDIR) == YES) + upline_ok = (!redirout && ttygetb(tty,"cm") && ttygetb(tty,"al")) + call pg_pushcmd (NULL) + + # Get file size for (xx%) info in nomore. If reading from the + # standard input, file size is not known. + + nchars = 0 + if (streq (fname, "STDIN")) { + totchars = -1 + } else if (finfo (fname, fi) == ERR) { + call sprintf (Memc[lbuf], SZ_LINE, "Cannot access file `%s'") + call pargstr (fname) + cmd = pg_getcmd (tty, Memc[lbuf], 0, 0, 0, fileno, nfiles) + call sfree (sp) + return (cmd) + } else + totchars = FI_SIZE(fi) + + # If file is empty, return immediately without clearing screen. + if (totchars == 0) { + call sprintf (Memc[lbuf], SZ_LINE, "Null length file `%s'") + call pargstr (fname) + cmd = pg_getcmd (tty, Memc[lbuf], 0, 0, 0, fileno, nfiles) + call sfree (sp) + return (cmd) + } + + # Open the file. + iferr (fd = open (fname, READ_ONLY, TEXT_FILE)) { + call sprintf (Memc[lbuf], SZ_LINE, "Cannot open file `%s'") + call pargstr (fname) + cmd = pg_getcmd (tty, Memc[lbuf], 0, 0, 0, fileno, nfiles) + call sfree (sp) + return (cmd) + } + + # Open the line offset save/fetch database. + lp = lno_open (LNO_MAXLINES) + + # Advance to the first page of the file to be displayed. Pages are + # marked by FF chararacters in the text. If the first page is number + # one, do nothing. If the first character in the file is FF, do not + # count it. This is necessary to count pages correctly whether or not + # the first page is preceeded by a FF. + + pageno = 1 + lineno = 1 + pgoff[1] = BOF + pgnch[1] = nchars + pglno[1] = lineno + + if (first_page > 1) { + junk = getci (fd, ch) + nchars = nchars + 1 + + while (pageno < first_page) { + while (getci (fd, ch) != '\f') { + nchars = nchars + 1 + if (ch == '\n') + lineno = lineno + 1 + if (ch == EOF) { + call close (fd) + call lno_close (lp) + call sfree (sp) + return + } + } + pageno = pageno + 1 + nchars = nchars + 1 + pgoff[pageno] = note (fd) + pgnch[pageno] = nchars + pglno[pageno] = lineno + } + } + + # Always clear the screen between files; the "clear_screen" param + # applies only to the pages of a single file. + + if (!redirout) { + call ttyclear (STDERR, tty) + call flush (STDERR) + } + + # Output lines, mapping control characters if enabled. Pause at the + # end of every screen, or when FF is encountered in the text. + + pushback= false + ateof = false + nleft = maxlines # nlines left to display before prompt + lnout = 0 + + repeat { + # Fetch and display the next line of the file. + + if (pushback) + pushback = false + else + loffset = note (fd) + + if (pg_getline (fd, Memc[lbuf]) == EOF) { + if ((nfiles==1 && lineno <= maxlines) || redirin || redirout) { + # Simply quit if a single small file or the standard input + # is being paged. + + call close (fd) + call lno_close (lp) + call sfree (sp) + return (QUIT) + + } else { + nchars = totchars + SZ_LINE + ateof = true + nleft = 0 + } + + } else if (Memc[lbuf] == '\f') { + # Formfeed encountered; pause for the prompt and print the + # remainder of the line on the next screen. If we have not + # yet written anything on the screen (nleft=maxlines) don't + # bother to prompt again. + + pageno = pageno + 1 + pgoff[pageno] = loffset + pglno[pageno] = lineno + pgnch[pageno] = nchars + call ungetline (fd, Memc[lbuf+1]) + pushback = true + + if (nleft == maxlines) + next + else + nleft = 0 + + } else { + # Output line, processing all escapes as req'd by the device. + # Keep track of position in file for %done message in prompt, + # and of position on screen so that we know when to prompt. + + call lno_save (lp, lineno, loffset, nchars) + linelen = strlen (Memc[lbuf]) + nchars = nchars + linelen + lineno = lineno + 1 + + # Count the number of printed columns in the output text. + n = 1 + do i = 1, linelen + if (ch >= ' ') + n = n + 1 + else if (ch == '\t') { + n = n + 1 + while (mod (n-1, 8) != 0) + n = n + 1 + } + + # Decrement lines left on screen. + nleft = nleft - max (1, ((n + maxcols-1) / maxcols)) + + if (spoolfd != NULL) + call putline (spoolfd, Memc[lbuf]) + + # Cancel upline if line is too long. + if (upline && lnout <= 0 && linelen >= maxcols) { + call ttyclear (STDERR, tty) + call flush (STDERR) + upline = false + lnout = 0 + } + + if (!(upline && lnout > 0)) + call ttyputline (STDOUT, tty, Memc[lbuf], map_cc) + lnout = min (maxlines, lnout + 1) + } + + if (nleft <= 0) { + # Move cursor to query line at end of line insert sequence. + if (upline) { + # Don't bother if the next command is another insert. + if (pg_peekcmd() != PREV_LINE) { + call ttygoto (STDOUT, tty, 1, lnout + 1) + call ttyclearln (STDOUT, tty) + } + upline = false + } + + # Pause and get next keystroke from the user. + cmd = pg_getcmd (tty, Memc[prompt], nchars, totchars, lineno, + fileno, nfiles) + + # Allow use of the space bar to advance to the next file, + # when at the end of the current file. + + if (ateof && nfiles > 1 && (cmd == BLANK || cmd == FWD_SCREEN)) + cmd = NEXT_FILE + + repeat { + switch (cmd) { + case NEXT_FILE: + # This really means the next file if multiple files. + if (nfiles > 1) + goto quit_ + else if (pushback) { + cmd = FWD_SCREEN + next + } + + # Otherwise we want the next page (formfeed). + o_loffset = note (fd) + o_nchars = nchars + o_lineno = lineno + + repeat { + loffset = note (fd) + n = pg_getline (fd, Memc[lbuf]) + if (n == EOF) { + if (!redirin) { + call seek (fd, o_loffset) + pushback = false + nchars = o_nchars + lineno = o_lineno + ateof = false + } + cmd = pg_getcmd (tty, "No more pages", + nchars,totchars, lineno, fileno,nfiles) + Memc[lbuf] = EOS + break + } + + call lno_save (lp, lineno, loffset, nchars) + + if (Memc[lbuf] == '\f') { + pageno = min (MAX_PAGE, pageno + 1) + pgoff[pageno] = loffset + pgnch[pageno] = nchars + pglno[pageno] = lineno + if (!redirout) { + call ttyclear (STDERR, tty) + call flush (STDERR) + lnout = 0 + } + call ungetline (fd, Memc[lbuf+1]) + pushback = true + nleft = maxlines + break + } + + nchars = nchars + n + lineno = lineno + 1 + } + + if (n == EOF) + next + else + break + + case PREV_FILE: + # If there are multiple files go to previous file, + # otherwise, go to previous page (formfeed). + + if (nfiles > 1) + goto quit_ + if (redirin) + goto err_ + + # Special case - just reached beginning of next + # page, but still displaying previous page. + + if (pglno[pageno] == lineno) + pageno = max (1, pageno - 1) + + # If the beginning of the current page is not on + # the screen, go back to the beginning of the page. + + if (lineno <= pglno[pageno]+maxlines) + pageno = max (1, pageno - 1) + + # Go there. + call seek (fd, pgoff[pageno]) + nchars = pgnch[pageno] + lineno = pglno[pageno] + pushback = false + + if (!redirout) { + call ttyclear (STDERR, tty) + call flush (STDERR) + lnout = 0 + } + if (getci (fd, ch) != '\f') + call ungetci (fd, ch) + nleft = maxlines + break + + case QUIT: +quit_ call close (fd) + call lno_close (lp) + call sfree (sp) + return (cmd) + + case TO_BOF: + if (redirin) + goto err_ + + call pg_setprompt (Memc[prompt], u_prompt, fname) + call seek (fd, BOFL) + pushback = false + Memc[lbuf] = EOS + ateof = false + lineno = 1 + nchars = 0 + nleft = maxlines + pageno = 1 + + if (!redirout) { + call ttyclear (STDERR, tty) + call flush (STDERR) + lnout = 0 + } + break + + case FWD_SCREEN, BLANK: + if (!ateof && clear_screen == YES && !redirout) { + call ttyclear (STDERR, tty) + call flush (STDERR) + lnout = 0 + } + nleft = maxlines + break + + case TO_EOF, TO_EOF_ALT: + destline = MAX_INT + goto destline_ + case SCROLL_DOWN: + nleft = (maxlines + 1) / 2 + break + case SCROLL_UP: + if (redirin) + goto err_ + if (upline_ok) { + destline = lineno - 2 + do i = 1, ((maxlines + 1) / 2 - 1) + if (lineno - lnout - i > 1) + call pg_pushcmd (PREV_LINE) + } else + destline = lineno - ((maxlines + 1) / 2) - 1 + goto destline_ + case BACK_SCREEN: + if (redirin) + goto err_ + destline = lineno - maxlines - 1 + goto destline_ + case PREV_LINE: + if (redirin) + goto err_ + destline = lineno - 2 + goto destline_ + case REDRAW: + if (redirin) + goto err_ + destline = lineno + goto destline_ + case NEXT_LINE, CR, LF: + nleft = 1 + break + case SEARCH: + # Stop at next line containing current pattern. + goto search_ + + case HELP: + cmd = pg_getcmd (tty, HELPTXT, 0, 0, 0, 0, 0) + # get another command + + case EDIT: + # Edit the file being paged. + if (redirin) + goto err_ + + # Close file and LNO database. + call close (fd) + call lno_close (lp) + call flush (STDOUT) + call flush (STDERR) + + # Command the CL to edit the file. + call sprintf (Memc[lbuf], SZ_LINE, "edit (\"%s\")") + call pargstr (fname) + iferr (call clcmdw (Memc[lbuf])) + call erract (EA_WARN) + + # Reopen the file and LNO database. + iferr (fd = open (fname, READ_ONLY, TEXT_FILE)) { + call sfree (sp) + return (NEXT_FILE) + } else + lp = lno_open (LNO_MAXLINES) + + # Redisplay the file at the BOF. + if (!redirout) { + call ttyclear (STDERR, tty) + call flush (STDERR) + lnout = 0 + } + Memc[lbuf] = EOS + nchars = 0 + lineno = 1 + nleft = maxlines + break + + case LCMD: + # Colon escape. + call pg_getstr (Memc[cmdbuf], SZ_LINE) + for (ip=cmdbuf; IS_WHITE (Memc[ip]); ip=ip+1) + ; + + if (Memc[ip] == '!') { + # Send a command to the CL. + + iferr (call clcmdw (Memc[cmdbuf+1])) + call erract (EA_WARN) + cmd = pg_getcmd (tty, Memc[prompt], + nchars, totchars, lineno, fileno, nfiles) + Memc[lbuf] = EOS + next + + } else if (Memc[ip] == '/') { + # Search for a line containing the given pattern. + + if (patmake (Memc[ip+1], patbuf, SZ_LINE) == ERR) + goto err_ +search_ + if (patbuf[1] == EOS) { + cmd = pg_getcmd (tty, "No current pattern", + 0, 0, 0, fileno, nfiles) + Memc[lbuf] = EOS + next + } + + o_loffset = note (fd) + o_nchars = nchars + o_lineno = lineno + o_pageno = pageno + + repeat { + loffset = note (fd) + n = pg_getline (fd, Memc[lbuf]) + if (n == EOF) { + if (!redirin) { + call seek (fd, o_loffset) + pushback = false + nchars = o_nchars + lineno = o_lineno + pageno = o_pageno + ateof = false + } + cmd = pg_getcmd (tty, "Pattern not found", + nchars,totchars,lineno,fileno,nfiles) + Memc[lbuf] = EOS + break + } + + call lno_save (lp, lineno, loffset, nchars) + if (Memc[lbuf] == '\f') { + pageno = pageno + 1 + pgoff[pageno] = loffset + pgnch[pageno] = nchars + pglno[pageno] = lineno + } + + if (patmatch (Memc[lbuf], patbuf) > 0) { + if (redirin) { + call ungetline (fd, Memc[lbuf]) + pushback = true + nleft = maxlines + break + } else { + destline = lineno + nchars = nchars + n + lineno = lineno + 1 + goto destline_ + } + } + + nchars = nchars + n + lineno = lineno + 1 + } + + if (n == EOF) + next + else + break + } + + # Case ":cmd arg". + for (op=token; IS_ALPHA (Memc[ip]); ip=ip+1) { + Memc[op] = Memc[ip] + op = op + 1 + } + for (; IS_WHITE (Memc[ip]); ip=ip+1) + ; + Memc[op] = EOS + toklen = op - token + + # Print help if no : string given. + if (toklen <= 0) { + call strcpy ("help", Memc[token], SZ_FNAME) + toklen = 4 + } + + if (strncmp (Memc[token], "line", toklen) == 0) { + # Move to the destination line, expressed as + # ":line N" for an absolute line, or ":line +/-N" + # for a relative move. + + destline = lineno + if (Memc[ip] == '+') { + ip = ip + 1 + if (ctoi (Memc, ip, n) > 0) + destline = lineno + n + } else if (Memc[ip] == '-') { + ip = ip + 1 + if (ctoi (Memc, ip, n) > 0) + destline = lineno - n + } else if (ctoi (Memc, ip, n) > 0) + destline = n +destline_ + # Upscroll one line? + if (upline_ok && destline == lineno-2) + upline = true + + # Determine line at top of new screen. + nleft = maxlines + if (destline < lineno && destline >= lineno-lnout-1) + destline = destline - lnout + 1 + else + destline = destline - nleft + 1 + + # Don't upscroll off the top of the screen. + if (destline < 1) { + destline = 1 + upline = false + } + + # Look up the desired line offset in the database + # and go directly there if found, otherwise either + # advance forward or rewind the file and advance + # forward to the indicated line. + + if (lno_fetch(lp,destline,loffset,nchars)==ERR) { + if (!redirin && destline < lineno) { + call seek (fd, BOFL) + pushback = false + lineno = 1 + pageno = 1 + nchars = 0 + ateof = false + call pg_setprompt (Memc[prompt], + u_prompt, fname) + } + + while (lineno < destline) { + loffset = note (fd) + n = pg_getline (fd, Memc[lbuf]) + if (n == EOF) { + destline = lineno - 1 # goto EOF + goto destline_ + } + call lno_save (lp, lineno, loffset, nchars) + if (Memc[lbuf] == '\f') { + pageno = pageno + 1 + pgoff[pageno] = loffset + pgnch[pageno] = nchars + pglno[pageno] = lineno + } + nchars = nchars + n + lineno = lineno + 1 + } + } else if (!redirin) { + call seek (fd, loffset) + pushback = false + lineno = destline + ateof = false + + # Determine which page we are in. + do i = 2, MAX_PAGE + if (pglno[i] <= 0) { + pageno = i - 1 + break + } else if (pglno[i] >= lineno) { + pageno = i + break + } + + call pg_setprompt (Memc[prompt],u_prompt,fname) + } + + # Prepare to draw the screen. Upline mode means + # we want to insert a line at the top of the screen + # and then skip to the page prompt; otherwise we + # clear the screen and output a full page of text. + + if (!redirout) { + if (upline) { + # Clear screen if backing up over a page. + if (destline+1 == pglno[pageno]) + call ttyclear (STDERR, tty) + call ttygoto (STDOUT, tty, 1, 1) + junk = ttyctrl (STDOUT, tty, "al", maxlines) + lnout = 0 + } else { + call ttyclear (STDERR, tty) + upline = false + lnout = 0 + } + call flush (STDERR) + } + Memc[lbuf] = EOS + break + + } else if (strncmp (Memc[token], "file", toklen) == 0) { + # Position to the named file (must be in file list). + + call strcpy (Memc[ip], newfname, SZ_FNAME) + call close (fd) + call lno_close (lp) + call sfree (sp) + return (TO_FILE) + + } else if (strncmp (Memc[token],"spool",toklen) == 0) { + # Begin spooling output in a file. + + if (spoolfd != NULL) { + call close (spoolfd) + spoolfd = NULL + } + + if (Memc[ip] == EOS) { + ; + } else iferr { + spoolfd = open (Memc[ip], APPEND, TEXT_FILE) + } then { + spoolfd = NULL + call erract (EA_WARN) + } + + # Get next keystroke from the user. + cmd = pg_getcmd (tty, Memc[prompt], + nchars, totchars, lineno, fileno, nfiles) + + } else { + cmd = pg_getcmd (tty, + "colon cmds: :!cmd :/pat :line L :file F :spool F", + 0, 0, 0, 0, 0) + } + + default: +err_ call eprintf ("\07") + call flush (STDERR) + cmd = pg_getcmd (tty, Memc[prompt], nchars, totchars, + lineno, fileno, nfiles) + } + } + } + } +end + + +# PG_SETPROMPT -- Set the prompt string for the ukey end-of-page query. +# The name of the file currently being paged is used unless a prompt string +# is given. + +procedure pg_setprompt (prompt, u_prompt, fname) + +char prompt[SZ_FNAME] # receives prompt string +char u_prompt[ARB] # user prompt string +char fname[ARB] # file being paged + +int gstrcpy() + +begin + if (gstrcpy (u_prompt, prompt, SZ_FNAME) <= 0) + call strcpy (fname, prompt, SZ_FNAME) +end + + +# PG_GETLINE -- Get a line from the input file. Accumulates very long lines +# (requiring several getline calls to read) into a single string. + +int procedure pg_getline (fd, lbuf) + +int fd # input file +char lbuf[SZ_LONGLINE] # output buffer + +int nchars, op +int getline() +errchk getline + +begin + for (op=1; op + SZ_LINE < SZ_LONGLINE; op=op+nchars) { + nchars = getline (fd, lbuf[op]) + if (nchars == EOF) { + if (op == 1) + return (EOF) + else + return (op - 1) + } else if (lbuf[op+nchars-1] == '\n') + break + } + + return (op + nchars - 1) +end + + +# PG_GETCMD -- Query the user for a single character command keystroke. +# A prompt naming the current file and our position in it is printed, +# we read the single character command keystroke in raw mode, and then +# the prompt line is cleared and we return. + +int procedure pg_getcmd (tty, fname, nchars, totchars, lineno, fileno, nfiles) + +pointer tty # tty descriptor +char fname[ARB] # prefix string +long nchars # position in file +long totchars # size of file +int lineno # current line number +int fileno # current file number +int nfiles # nfiles being paged through + +char keystr[SZ_KEYSTR] +int key, pb, pbcmd[MAX_PBCMD] +common /pgucom/ key, pb, pbcmd, keystr +int clgkey(), fstati() + +begin + # If any commands have been pushed, return the next pushed command + # without generating a query. + + if (pb > 0) { + key = pbcmd[pb] + pb = pb - 1 + return (key) + } + + # If the standard output is redirected, skip the query and just go on + # to the next page. + + if (fstati (STDOUT, F_REDIR) == YES) + return (FWD_SCREEN) + + # Ensure synchronization with the standard output. + call flush (STDOUT) + + # Print query in standout mode, preceded by %done info. + call ttyso (STDERR, tty, YES) + call eprintf ("%s") + call pargstr (fname) + if (totchars > 0) { + if (nchars >= totchars + SZ_LINE) + call eprintf ("-(EOF)") + else { + call eprintf ("-(%02d%%)") + call pargi (max(0, min(99, nchars * 100 / totchars))) + } + } + if (lineno > 0) { + call eprintf ("-line %d") + call pargi (lineno - 1) + } + if (fileno > 0 && nfiles > 0) { + call eprintf ("-file %d of %d") + call pargi (fileno) + call pargi (nfiles) + } + call ttyso (STDERR, tty, NO) + call flush (STDERR) + + call fseti (STDIN, F_SETREDRAW, REDRAW) + + # Read the user's response, normally a single keystroke. + if (clgkey (UKEYS, key, keystr, SZ_KEYSTR) == EOF) + key = INTCHAR + + call fseti (STDIN, F_SETREDRAW, 0) + + if (key == INTCHAR) + key = QUIT + else if (key == NEXT_FILE_ALT) + key = NEXT_FILE + else if (key == PREV_FILE_ALT) + key = PREV_FILE + + # Erase the prompt and return. + call eprintf ("\r") + call ttyclearln (STDERR, tty) + call flush (STDERR) + + return (key) +end + + +# PG_GETSTR -- Called after receipt of a : key to get the string value. + +procedure pg_getstr (strval, maxch) + +char strval[maxch] # receives string +int maxch + +char keystr[SZ_KEYSTR] +int key, pb, pbcmd[MAX_PBCMD] +common /pgucom/ key, pb, pbcmd, keystr + +begin + call strcpy (keystr, strval, maxch) +end + + +# PG_PUSHCMD -- Push back a command keystroke. + +procedure pg_pushcmd (cmd) + +int cmd #I command to be pushed + +char keystr[SZ_KEYSTR] +int key, pb, pbcmd[MAX_PBCMD] +common /pgucom/ key, pb, pbcmd, keystr + +begin + if (cmd <= 0) + pb = 0 + else { + pb = min (MAX_PBCMD, pb + 1) + pbcmd[pb] = cmd + } +end + + +# PG_PEEKCMD -- Peek at any pushed back command keystroke. + +int procedure pg_peekcmd() + +char keystr[SZ_KEYSTR] +int key, pb, pbcmd[MAX_PBCMD] +common /pgucom/ key, pb, pbcmd, keystr + +begin + if (pb <= 0) + return (ERR) + else + return (pbcmd[pb]) +end diff --git a/sys/etc/prc.com b/sys/etc/prc.com new file mode 100644 index 00000000..5893ef10 --- /dev/null +++ b/sys/etc/prc.com @@ -0,0 +1,27 @@ +define MAX_PS 10 # maximum pseudofiles + +# Process table common. + +int pr_pid[MAX_CHILDPROCS] # process id +int pr_status[MAX_CHILDPROCS] # process status +int pr_inchan[MAX_CHILDPROCS] # input IPC channel from child +int pr_infd[MAX_CHILDPROCS] # fd of input IPC +int pr_outchan[MAX_CHILDPROCS] # output IPC channel to child +int pr_outfd[MAX_CHILDPROCS] # fd of output IPC +int pr_nopen[MAX_CHILDPROCS] # number of open channels +int pr_pstofd[MAX_CHILDPROCS,MAX_PS] # pseudofile -> FD +int pr_last_exit_code # exit code of last process closed +int pr_lastio # index of last active process +int pr_index # index of current process +int pr_oldipc # old X_IPC handler +int epa_giotr # gio.cursor driver entry points +int epa_control # " " +int epa_gflush # " " +int epa_writep # " " +int epa_readtty # " " +int epa_writetty # " " + +common /prccom/ pr_pid, pr_status, pr_inchan, pr_infd, pr_outchan, pr_outfd, + pr_nopen, pr_pstofd, pr_lastio, pr_last_exit_code, pr_index, pr_oldipc, + epa_giotr, epa_control, epa_gflush, epa_writep, epa_readtty, + epa_writetty diff --git a/sys/etc/prchdir.x b/sys/etc/prchdir.x new file mode 100644 index 00000000..d11c903a --- /dev/null +++ b/sys/etc/prchdir.x @@ -0,0 +1,21 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# PRCHDIR -- Change the current working directory of a connected child +# process, or of all connected subprocesses if pid=0. + +procedure prchdir (pid, newdir) + +int pid # process id of child, or 0 for all subprocesses +char newdir[ARB] # new directory +pointer sp, cmd + +begin + call smark (sp) + call salloc (cmd, SZ_COMMAND, TY_CHAR) + + call strcpy ("chdir ", Memc[cmd], SZ_COMMAND) + call strcat (newdir, Memc[cmd], SZ_COMMAND) + + call prupdate (pid, Memc[cmd], YES) + call sfree (sp) +end diff --git a/sys/etc/prclcpr.x b/sys/etc/prclcpr.x new file mode 100644 index 00000000..e5dd397c --- /dev/null +++ b/sys/etc/prclcpr.x @@ -0,0 +1,33 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> +include <syserr.h> + +# PRCLCPR -- Close a connected subprocess. Given the PID of the child process +# we get the input and output file descriptors from the process table and +# close both files. When the second file is closed the process is disconnected +# by the PR_ZCLSPR procedure, which leaves the exit status in the process table +# common. + +int procedure prclcpr (pid) + +int pid # process id of child process + +int child +int pr_findproc() +include "prc.com" +errchk syserr + +begin + # Search process table for the PID of the child process and close it + # if found. Return process termination code to parent. + + child = pr_findproc (pid) + if (child == ERR) + call syserr (SYS_PRNOTFOUND) + + call close (pr_infd[child]) + call close (pr_outfd[child]) + + return (pr_last_exit_code) +end diff --git a/sys/etc/prcldpr.x b/sys/etc/prcldpr.x new file mode 100644 index 00000000..479fffb9 --- /dev/null +++ b/sys/etc/prcldpr.x @@ -0,0 +1,47 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <knet.h> +include <config.h> +include <syserr.h> + +define NOKILL NO +define KILL YES + +# PRCLDPR -- Close a detached process. Called following process termination +# to obtain the exit status and free up any system resources still allocated +# to the job. If called prior to job termination execution of the current +# process will be suspended until the bkg job terminates. PRDONE should be +# called to determine if the job is still running if waiting is not desired. + +int procedure prcldpr (job) + +int job # slot number of job in prd.com table +int exit_status +include "prd.com" + +begin + # Wait for process to terminate if it is still active. If we are + # interrupted the process table is left unmodified. If the process + # has been killed the exit status will have been left in the table + # and ZCLDPR should not be called again. + + if (pr_jobcode[job] == NULL) + call syserr (SYS_PRBKGNF) + else if (pr_active[job] == YES) + call zcldpr (pr_jobcode[job], NOKILL, exit_status) + else + exit_status = pr_exit_status[job] + + # Free all remaining resources allocated to job. The bkgfile should + # already have been deleted by the process but if not, e.g., in the + # event of abnormal process termination, we delete it ourselves. The + # buffer for the bkgfile filename is freed as is the slot in the + # process table. + + iferr (call delete (Memc[pr_bkgfile[job]])) + ; + call mfree (pr_bkgfile[job], TY_CHAR) + pr_jobcode[job] = NULL + + return (exit_status) +end diff --git a/sys/etc/prclose.x b/sys/etc/prclose.x new file mode 100644 index 00000000..26e2702c --- /dev/null +++ b/sys/etc/prclose.x @@ -0,0 +1,32 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> +include <syserr.h> +include <prstat.h> + +# PRCLOSE -- Close a connected subprocess. Send the command "bye" to the +# child to initiate process shutdown, then close the IPC channels and +# wait for the child to terminate, returning the termination status to +# our caller. Note that process shutdown may take an arbitrarily long +# time, depending on the number and nature of ONEXIT procedures posted by +# tasks in the the child process. + +int procedure prclose (pid) + +int pid # process-id of child process + +int child +int pr_findproc(), prclcpr() +include "prc.com" +errchk syserr + +begin + child = pr_findproc (pid) + if (child == ERR) + call syserr (SYS_PRNOTFOUND) + + if (pr_status[child] != P_DONE && pr_status[child] != P_DEAD) + call putline (pr_outfd[child], "bye\n") + + return (prclcpr (pid)) +end diff --git a/sys/etc/prd.com b/sys/etc/prd.com new file mode 100644 index 00000000..599dc6b6 --- /dev/null +++ b/sys/etc/prd.com @@ -0,0 +1,8 @@ +# Job table for detached processes. + +int pr_jobcode[MAX_BKGJOBS] # job code assigned by host system +int pr_active[MAX_BKGJOBS] # set to NO if job is killed +int pr_exit_status[MAX_BKGJOBS] # exit status of process +pointer pr_bkgfile[MAX_BKGJOBS] # bkgfile filename (signals job term) + +common /prdcom/ pr_jobcode, pr_active, pr_exit_status, pr_bkgfile diff --git a/sys/etc/prdone.x b/sys/etc/prdone.x new file mode 100644 index 00000000..2df2dccc --- /dev/null +++ b/sys/etc/prdone.x @@ -0,0 +1,26 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> +include <syserr.h> + +# PRDONE -- Determine if a detached process (background job) has completed. +# This is a difficult process to perform portably at the system call level, +# hence the deletion of the bkgfile is used to signal the completion of a +# detached process. If the detached process fails to delete its bkgfile +# for some reason, PRCLDPR will do so if the process has indeed terminated. + +int procedure prdone (job) + +int job # job number (slot number in job table) +int access() +include "prd.com" + +begin + if (pr_jobcode[job] == NULL) + call syserr (SYS_PRBKGNF) + + if (access (Memc[pr_bkgfile[job]], 0, 0) == YES) + return (NO) + else + return (YES) +end diff --git a/sys/etc/prenvfree.x b/sys/etc/prenvfree.x new file mode 100644 index 00000000..90908789 --- /dev/null +++ b/sys/etc/prenvfree.x @@ -0,0 +1,36 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# PRENVFREE -- Free any recently defined or redefined environment variables, +# updating the values of any redefined variables uncovered by the free +# operation in the specified connected subprocesses. + +int procedure prenvfree (pid, marker) + +int pid # pid of process to be updated, or 0 for all subprocs +int marker # stack pointer returned by ENVMARK + +int ev_pid +common /prvcom/ ev_pid +int locpr(), envfree() +extern prv_reset() + +begin + ev_pid = pid + return (envfree (marker, locpr (prv_reset))) +end + + +# PRV_RESET -- Reset the value of an environment variable in the specified +# connected subprocesses. + +procedure prv_reset (name, value) + +char name[ARB] # name of variable to be reset +char value[ARB] # new value + +int ev_pid +common /prvcom/ ev_pid + +begin + call prenvset (ev_pid, name, value) +end diff --git a/sys/etc/prenvset.x b/sys/etc/prenvset.x new file mode 100644 index 00000000..6c21133d --- /dev/null +++ b/sys/etc/prenvset.x @@ -0,0 +1,24 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# PRENVSET -- Change the value of an environment variable in a connected child +# process, or in all connected subprocesses if pid=0. + +procedure prenvset (pid, envvar, valuestr) + +int pid # process id of child, or 0 for all subprocesses +char envvar[ARB] # name of environment variable +char valuestr[ARB] # value of environment variable +pointer sp, cmd + +begin + call smark (sp) + call salloc (cmd, SZ_COMMAND, TY_CHAR) + + call strcpy ("set ", Memc[cmd], SZ_COMMAND) + call strcat (envvar, Memc[cmd], SZ_COMMAND) + call strcat ("=", Memc[cmd], SZ_COMMAND) + call strcat (valuestr, Memc[cmd], SZ_COMMAND) + + call prupdate (pid, Memc[cmd], NO) + call sfree (sp) +end diff --git a/sys/etc/prfilbuf.x b/sys/etc/prfilbuf.x new file mode 100644 index 00000000..4ec09907 --- /dev/null +++ b/sys/etc/prfilbuf.x @@ -0,0 +1,38 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> +include <fio.h> + +# PRFILBUF -- Fill the FIO buffer from a process. The function is equivalent +# to the ordinary FIO filbuf with the exception that pseudofile read and +# write directives are intercepted and processed. Hence, the reader sees a +# stream of application specific commands need not know about pseudofile i/o. + +int procedure prfilbuf (fd) + +int fd # parent's input IPC from child process + +int pr +int filbuf(), prpsio() +include "prc.com" + +begin + # Determine which process has the given file as its CLIN stream. + # If FD not associated with a process call ordinary FILBUF, otherwise + # call PR_PSIO. To minimize searches of the process table we keep + # track of the slot number of the last active pid. + + if (pr_infd[pr_lastio] == fd && pr_pid[pr_lastio] != NULL) + pr = pr_lastio + else { + for (pr=1; pr <= MAX_CHILDPROCS; pr=pr+1) + if (pr_pid[pr] != NULL) + if (pr_infd[pr] == fd) + break + if (pr > MAX_CHILDPROCS) + return (filbuf (fd)) # normal file + pr_lastio = pr + } + + return (prpsio (pr_pid[pr], CLIN, FF_READ)) +end diff --git a/sys/etc/prfindpr.x b/sys/etc/prfindpr.x new file mode 100644 index 00000000..3df73ed2 --- /dev/null +++ b/sys/etc/prfindpr.x @@ -0,0 +1,20 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> + +# PR_FINDPROC -- Search the process table for the given PID of a child process, +# returning the index of the process if found. + +int procedure pr_findproc (pid) + +int pid # process id of child process +int pr +include "prc.com" + +begin + for (pr=1; pr <= MAX_CHILDPROCS; pr=pr+1) + if (pr_pid[pr] == pid) + return (pr) + + return (ERR) +end diff --git a/sys/etc/prgline.x b/sys/etc/prgline.x new file mode 100644 index 00000000..21ec1780 --- /dev/null +++ b/sys/etc/prgline.x @@ -0,0 +1,204 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> +include <syserr.h> +include <ctype.h> +include <fset.h> + +define XMIT 0 +define XFER 1 + +# PRGETLINE -- Get a line of text from a process. The function is equivalent +# to the ordinary FIO getline with the exception that pseudofile read and +# write directives are intercepted and processed. Hence, the reader sees a +# stream of application specific commands need not know about pseudofile i/o. +# The function of PRGETLINE is such that it can be used in place of GETLINE +# on any file; pseudofile directives are recognized and process only if the +# FD is associated with a connected subprocess. + +int procedure prgetline (fd, lbuf) + +int fd # parent's input IPC from child process +char lbuf[SZ_LINE] # output line buffer + +char ch +int nchars, maxchars, nchars_read, raw_mode_set, ndigits +int bufsize, outfd, destfd, pr, pseudofile, line_type, offset +pointer sp, buf, ip + +char getc() +int getline(), read(), fstati(), ctoi(), itoc() +errchk syserr, getline, fstati, read, write, pr_decodeargs, putc, getc +include "prc.com" + +begin + call smark (sp) + + pr = 0 + buf = NULL + raw_mode_set = 0 + + repeat { + nchars = getline (fd, lbuf) + + # Return immediately if not XMIT or XFER directive. This code is + # exercised heavily when performing raw mode i/o, hence some + # clarity is sacrificed for the sake of efficiency. + # + # Syntax: "xmit(P,NNN)" or "xfer(P,NNN)" + # 12345678 12345678 + # + # where P is the pseudofile code (0<P<10) and NNN is the size of + # the data block in chars. In the following code all explicit + # integer constants refer to the character offsets shown above. + + if (lbuf[1] != 'x' || nchars == EOF) { + break + } else if (lbuf[2] == 'm') { + if (lbuf[3] == 'i' && lbuf[4] == 't' && lbuf[5] == '(') { + line_type = XMIT + pseudofile = TO_INTEG (lbuf[6]) + } else + break + } else if (lbuf[2] == 'f') { + if (lbuf[3] == 'e' && lbuf[4] == 'r' && lbuf[5] == '(') { + line_type = XFER + pseudofile = TO_INTEG (lbuf[6]) + } else + break + } else + break + + # Ignore directive if FD not associated with a process. To minimize + # searches of the process table we keep track of the slot number + # of the last active pid. + + if (pr == 0) { + if (pr_infd[pr_lastio] == fd && pr_pid[pr_lastio] != NULL) + pr = pr_lastio + else { + for (pr=1; pr <= MAX_CHILDPROCS; pr=pr+1) + if (pr_pid[pr] != NULL) + if (pr_infd[pr] == fd) + break + if (pr > MAX_CHILDPROCS) + break + pr_lastio = pr + } + outfd = pr_outfd[pr] + } + + # Map pseudofile code to a file descriptor in the local process. + + destfd = pr_pstofd[pr,pseudofile] + + + # RAW mode transfers are handled as a special case to minimize the + # per-character overhead. + + if (lbuf[8] == '1' && lbuf[9] == ')') { + if (line_type == XMIT) { + # XMIT + if (getc (fd, ch) == EOF) + call syserr (SYS_PRIPCSYNTAX) + + # Clear RAW input mode if newline is encountered in output. + # Only works for STDIN/STDOUT, but that is all raw mode is + # used for with pseudofiles. + + if (ch == '\n') + if (destfd == STDOUT) { + call fseti (STDIN, F_RAW, NO) + if (raw_mode_set == STDIN) + raw_mode_set = 0 + } + + call putc (destfd, ch) + call flush (destfd) + + } else { + # XFER + if (raw_mode_set != destfd) { + call fseti (destfd, F_RAW, YES) + raw_mode_set = destfd + } + + if (getc (destfd, ch) == EOF) + call putline (outfd, "0\n") + else { + call putline (outfd, "1\n") + call flush (outfd) + call putc (outfd, ch) + } + call flush (outfd) + } + next + } + + + # GENERAL XMIT or XFER directive. Read a block of data from one + # stream and transmit it to the other stream. + + if (buf == NULL) { + bufsize = fstati (fd, F_BUFSIZE) + call salloc (buf, bufsize, TY_CHAR) + } + + offset = 8 + if (ctoi (lbuf, offset, nchars) <= 0) + call syserr (SYS_PRIPCSYNTAX) + + if (line_type == XMIT) { + # XMIT -- Copy the block of data from the IPC channel to the + # destination file. + + nchars_read = read (fd, Memc[buf], nchars) + if (nchars_read != nchars) + call syserr (SYS_PRIPCSYNTAX) + else { + # Clear RAW input mode if set and newline is encountered + # in the output stream. + + if (destfd == STDOUT) + if (fstati (STDIN, F_RAW) == YES) + for (ip=buf+nchars-1; ip >= buf; ip=ip-1) + if (Memc[ip] == '\n') { + call fseti (STDIN, F_RAW, NO) + if (raw_mode_set == STDIN) + raw_mode_set = 0 + break + } + + call write (destfd, Memc[buf], nchars) + call flush (destfd) + } + next + + } else { + # XFER -- Read up to maxchars chars from the input file and + # pass them on to the output IPC channel. + + maxchars = min (nchars, bufsize) + nchars = read (destfd, Memc[buf], maxchars) + if (nchars == EOF) + nchars = 0 + + # Write the byte count record followed by the data record. + # These must be written as two separate records or deadlock + # will occur (with the reader waiting for the second record). + + ndigits = itoc (nchars, lbuf, SZ_LINE) + lbuf[ndigits+1] = '\n' + call write (outfd, lbuf, ndigits + 1) + call flush (outfd) + + call write (outfd, Memc[buf], nchars) + call flush (outfd) + + next + } + } + + call sfree (sp) + return (nchars) +end diff --git a/sys/etc/prgredir.x b/sys/etc/prgredir.x new file mode 100644 index 00000000..c5ffceee --- /dev/null +++ b/sys/etc/prgredir.x @@ -0,0 +1,19 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> + +# PR_GETREDIR -- Get the pseudofile redirection code for a process. + +int procedure pr_getredir (pid, stream) + +int pid # process id +int stream # stream for which redirection info is needed + +int pr +int pr_findproc() +include "prc.com" + +begin + pr = pr_findproc (pid) + return (pr_pstofd[pr,stream]) +end diff --git a/sys/etc/prkill.x b/sys/etc/prkill.x new file mode 100644 index 00000000..f6938923 --- /dev/null +++ b/sys/etc/prkill.x @@ -0,0 +1,42 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <knet.h> +include <config.h> +include <syserr.h> + +define NOKILL NO +define KILL YES + +# PRKILL -- Kill a detached process. Control does not return until the process +# has terminated, unless the kill fails for some reason. If the process exists +# and is terminated by the kill directive, the exit status is left in the +# process table for return by PRCLDPR. + +procedure prkill (job) + +int job # slot number of job in prd.com table +include "prd.com" +errchk syserr + +begin + # Kill the process if there is such a process and it is still active. + # It is an error to try to kill a nonexistent process or a process + # which has already been killed. + + if (pr_jobcode[job] == NULL) + call syserr (SYS_PRBKGNF) + else if (pr_active[job] == NO) + call syserr (SYS_PRBKGNOKILL) + else { + call zcldpr (pr_jobcode[job], KILL, pr_exit_status[job]) + if (pr_exit_status[job] == ERR) + call syserr (SYS_PRBKGNOKILL) + else + pr_active[job] = NO + } + + # Delete the bkgfile if the process has not already done so during + # shutdown. + iferr (call delete (Memc[pr_bkgfile[job]])) + ; +end diff --git a/sys/etc/propcpr.x b/sys/etc/propcpr.x new file mode 100644 index 00000000..b7b394a1 --- /dev/null +++ b/sys/etc/propcpr.x @@ -0,0 +1,201 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <knet.h> +include <config.h> +include <syserr.h> +include <fset.h> +include <xwhen.h> +include <prstat.h> + +# PROPCPR -- Open a connected subprocess, i.e., spawn the subprocess and +# connect the two IPC channels to FIO file descriptors. No i/o is done on +# the IPC channels, hence this relatively low level command is independent +# of the IPC protocol used. PROPEN should be used if the standard IPC +# protocol is followed, so that the environment and current working directory +# may be passed to the subprocess. + +int procedure propcpr (process, in, out) + +char process[ARB] # filename of executable process file +int in # fd of IPC input from child (output) +int out # fd of IPC output to child (output) + +bool first_time +int pr, loc_onipc +pointer sp, fname +int fopnbf() +extern pr_onipc(), pr_dummy_open(), pr_zclspr() +extern zardpr(), zawrpr(), zawtpr(), zsttpr() +errchk xwhen, fmapfn, syserr +include "prc.com" + +define cleanup1_ 91 +define cleanup2_ 92 +define cleanup3_ 93 +data first_time /true/ + +begin + call smark (sp) + call salloc (fname, SZ_PATHNAME, TY_CHAR) + + # Initialize the process table. Post exception handler to recover + # from write to IPC with no reader. + + if (first_time) { + do pr = 1, MAX_CHILDPROCS + pr_pid[pr] = NULL + pr_lastio = 1 # any legal slot number will do + pr_last_exit_code = OK + call zlocpr (pr_onipc, loc_onipc) + call xwhen (X_IPC, loc_onipc, pr_oldipc) + first_time = false + } + + # Find empty process slot. + for (pr=1; pr <= MAX_CHILDPROCS; pr=pr+1) + if (pr_pid[pr] == NULL) + break + if (pr > MAX_CHILDPROCS) + call syserr (SYS_PROVFL) + pr_index = pr + + # Initialize the mapping of pseudofile codes to file descriptor numbers. + # PS codes begin at 1, corresponding to STDIN. + + pr_pstofd[pr,STDIN] = STDIN + pr_pstofd[pr,STDOUT] = STDOUT + pr_pstofd[pr,STDERR] = STDERR + pr_pstofd[pr,STDGRAPH] = STDGRAPH + pr_pstofd[pr,STDIMAGE] = STDIMAGE + pr_pstofd[pr,STDPLOT] = STDPLOT + + # Spawn process and open IPC channels. + call fmapfn (process, Memc[fname], SZ_PATHNAME) + call zopcpr (Memc[fname], pr_inchan[pr], pr_outchan[pr], pr_pid[pr]) + if (pr_pid[pr] == ERR) + goto cleanup3_ + pr_nopen[pr] = 2 + + # Set up file descriptors for the two IPC channels. + + call strcpy (process, Memc[fname], SZ_PATHNAME) + call strcat (".in", Memc[fname], SZ_PATHNAME) + iferr (in = fopnbf (Memc[fname], READ_ONLY, + pr_dummy_open, zardpr, zawrpr, zawtpr, zsttpr, pr_zclspr)) + goto cleanup2_ + pr_infd[pr] = in + + call strcpy (process, Memc[fname], SZ_PATHNAME) + call strcat (".out", Memc[fname], SZ_PATHNAME) + iferr (out = fopnbf (Memc[fname], WRITE_ONLY, + pr_dummy_open, zardpr, zawrpr, zawtpr, zsttpr, pr_zclspr)) + goto cleanup1_ + pr_outfd[pr] = out + + pr_status[pr] = P_RUNNING + call sfree (sp) + return (pr_pid[pr]) + +cleanup1_ + iferr (call close (out)) + ; +cleanup2_ + iferr (call close (in)) + ; +cleanup3_ + call sfree (sp) + pr_pid[pr] = NULL + call syserrs (SYS_PROPEN, process) +end + + +# PR_DUMMY_OPEN -- Dummy ZOPNPR procedure called by FIO to "open" the IPC +# channel to a subprocess. Our only function is to return the appropriate +# channel code to FIO, since the channel has already been opened by ZOPCPR. + +procedure pr_dummy_open (osfn, mode, chan) + +char osfn[ARB] # not used +int mode # used to select read or write IPC channel +int chan # returned to FIO +include "prc.com" + +begin + if (mode == READ_ONLY) + chan = pr_inchan[pr_index] + else + chan = pr_outchan[pr_index] +end + + +# PR_ZCLSPR -- Dummy "zclspr" routine called by FIO to close an IPC channel +# when CLOSE is called on the corresponding FIO file descriptor. A subprocess +# opened with PROPCPR is normally closed with PRCLCPR, but if error recovery +# takes place CLOSE will automatically be called by the system to close both +# file descriptors. We decrement the count of open channels and close the +# process and both IPC channels when the count reaches zero. Hence, a +# connected subprocess may be closed either by calling PRCLCPR or by closing +# the IN and OUT file descriptors. + +procedure pr_zclspr (chan, status) + +int chan # either inchan or outchan of process +int status # OK or ERR on output +int pr +include "prc.com" + +begin + do pr = 1, MAX_CHILDPROCS + if (pr_pid[pr] != NULL) + if (pr_inchan[pr] == chan || pr_outchan[pr] == chan) { + pr_nopen[pr] = pr_nopen[pr] - 1 + if (pr_nopen[pr] == 0) { + call zclcpr (pr_pid[pr], pr_last_exit_code) + pr_pid[pr] = NULL + } + status = OK + return + } + + status = ERR +end + + +# PR_ONIPC -- Exception handler for the X_IPC (write to IPC with no reader) +# exception. This exception occurs when the child process dies unexpectedly. +# Determine what process was being written to, cancel any output (to prevent +# a cascade of onipcs trying to flush the output buffer), and cause FIO to +# return a file write error. We cannot do any more than that w/o reentrancy +# problems. + +procedure pr_onipc (vex, next_handler) + +int vex # virtual exception +int next_handler # next handler in chain +int pr, fd +int fstati() +include "prc.com" + +begin + # Chain to next exception handler, if any. + next_handler = pr_oldipc + + # Get the FD of the file being written to at the time that the + # exception occurred. We assume that the write operation is still + # in progress when the exception takes place. + + fd = fstati (0, F_LASTREFFILE) + for (pr=1; pr <= MAX_CHILDPROCS; pr=pr+1) + if (pr_pid[pr] != NULL) + if (pr_outfd[pr] == fd) + break + if (pr > MAX_CHILDPROCS) + return + + # Cancel any buffered output and remove write permission to ensure + # that we will not get a cascade of X_IPC exceptions. + + call fseti (fd, F_CANCEL, ERR) + call fseti (fd, F_MODE, READ_ONLY) + pr_status[pr] = P_DEAD +end diff --git a/sys/etc/propdpr.x b/sys/etc/propdpr.x new file mode 100644 index 00000000..79690a60 --- /dev/null +++ b/sys/etc/propdpr.x @@ -0,0 +1,68 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <knet.h> +include <config.h> +include <syserr.h> + +# PROPDPR -- Open a detached process. A detached process runs independently of +# and asynchronous with the parent, with no direct communications (i.e., like +# the IPC channels of connected subprocesses). The bkgfile is prepared by the +# parent and read by the detached process, telling the detached process what +# to do. There are no restrictions on the format or contents of the bkgfile +# other than those placed by the implementor of the two processes (either a +# text or binary file may be used). Deletion of the bkgfile is however assumed +# to signify that the bkg process has terminated. + +int procedure propdpr (process, bkgfile, bkgmsg) + +char process[ARB] # vfn of executable process file +char bkgfile[ARB] # vfn of background file +char bkgmsg[ARB] # control string for kernel + +bool first_time +int jobcode, pr +pointer sp, process_osfn, bkgfile_osfn, pk_bkgmsg +data first_time /true/ +errchk fmapfn, syserrs, malloc +include "prd.com" + +begin + call smark (sp) + call salloc (process_osfn, SZ_PATHNAME, TY_CHAR) + call salloc (bkgfile_osfn, SZ_PATHNAME, TY_CHAR) + call salloc (pk_bkgmsg, SZ_LINE, TY_CHAR) + + # First time initialization of the job table. + if (first_time) { + do pr = 1, MAX_BKGJOBS + pr_jobcode[pr] = NULL + first_time = false + } + + # Get job slot. + for (pr=1; pr <= MAX_BKGJOBS; pr=pr+1) + if (pr_jobcode[pr] == NULL) + break + if (pr > MAX_BKGJOBS) + call syserrs (SYS_PRBKGOVFL, process) + + # Map file names. + call fmapfn (process, Memc[process_osfn], SZ_PATHNAME) + call fmapfn (bkgfile, Memc[bkgfile_osfn], SZ_PATHNAME) + call strpak (bkgmsg, Memc[pk_bkgmsg], SZ_LINE) + + # Spawn or enqueue detached process. + call zopdpr (Memc[process_osfn], Memc[bkgfile_osfn], Memc[pk_bkgmsg], + jobcode) + if (jobcode == ERR) + call syserrs (SYS_PRBKGOPEN, process) + + # Set up bkg job descriptor. + pr_jobcode[pr] = jobcode + pr_active[pr] = YES + call malloc (pr_bkgfile[pr], SZ_FNAME, TY_CHAR) + call strcpy (bkgfile, Memc[pr_bkgfile[pr]], SZ_FNAME) + + call sfree (sp) + return (pr) +end diff --git a/sys/etc/propen.x b/sys/etc/propen.x new file mode 100644 index 00000000..21bdf334 --- /dev/null +++ b/sys/etc/propen.x @@ -0,0 +1,67 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <knet.h> + +# PROPEN -- Open a connected subprocess. Call PROPCPR to spawn the child +# process and connect the input and output IPC channels to FIO file +# descriptors, then pass the environment list and current working directory +# to the child. The child is left waiting for the next command from the +# parent, which is eventually written to the OUT channel by the parent. +# +# N.B.: If the child cannot process a SET or CHDIR command it is will take +# a panic exit, raising the X_IPC exception in the parent. This is necessary +# to avoid filling the IN (childs out) IPC channel, which would cause deadlock +# if the parent were to fill the other channel with SET commands. Output of +# SET commands w/o handshaking is desirable to minimize context switches and +# IPC records and hence speed up process startup. + +int procedure propen (process, in, out) + +char process[ARB] # filename of executable file +int in, out # input, output file descriptors to child + +int pid, print_redefined_variables, status +pointer sp, cwd +int propcpr() +data print_redefined_variables /NO/ +errchk propcpr, envlist, putline, putci + +begin + call smark (sp) + call salloc (cwd, SZ_PATHNAME, TY_CHAR) + + # Connect the subprocess with read and write IPC channels. + + pid = propcpr (process, in, out) + + # Pass the environment list to the child, omitting all but the most + # recent definitions of each variable. The list is passed in the + # opposite order from which it was redefined, but it does not matter + # since there is only one entry for each variable. + + call envlist (out, "set ", print_redefined_variables) + + # Set the current working directory in the child, in case the OS does + # not do so, and to save the child the need to ask the kernel for the + # cwd name, an expensive operation on some systems. + + call zfgcwd (Memc[cwd], SZ_PATHNAME, status) + call strupk (Memc[cwd], Memc[cwd], SZ_PATHNAME) + call putline (out, "chdir ") + call putline (out, Memc[cwd]) + call putci (out, '\n') + + # The command "_go_" must be sent to the child to signal that process + # startup is completed. The process STDOUT and STDERR are redirected + # into the nullfile during startup, hence we will see no output if + # this command is not sent. + + call putline (out, "_go_\n") + + # Flush the output so the child can munch on this while we go off and + # do something else. + call flush (out) + + call sfree (sp) + return (pid) +end diff --git a/sys/etc/proscmd.x b/sys/etc/proscmd.x new file mode 100644 index 00000000..cf1e5bb3 --- /dev/null +++ b/sys/etc/proscmd.x @@ -0,0 +1,32 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> + +# PROSCMD -- Process an OS escape command from a subprocess. Execute the +# command and return the exit status to the subprocess via IPC. + +procedure proscmd (pr, cmd) + +int pr # subprocess process slot number +char cmd[ARB] # host command to be executed + +char statbuf[5] +int fd, status, op +int itoc(), oscmd() +include "prc.com" + +begin + fd = pr_outfd[pr] + + # Execute the command (waits for completion). + status = oscmd (cmd, "", "", "") + + # Encode the return status. + op = itoc (status, statbuf, 5) + 1 + statbuf[op] = '\n' + statbuf[op+1] = EOS + + # Return the status to the subprocess. + call write (fd, statbuf, op) + call flush (fd) +end diff --git a/sys/etc/prpsio.x b/sys/etc/prpsio.x new file mode 100644 index 00000000..99050481 --- /dev/null +++ b/sys/etc/prpsio.x @@ -0,0 +1,484 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <gio.h> +include <fio.h> +include <fset.h> +include <chars.h> +include <error.h> +include <config.h> +include <syserr.h> + +define LEN_STACK 5 # depth one level, four fields +define LEN_STACKFRAME 5 # size of one pushed stack frame + +define S_PR stack[$1] +define S_IN stack[$1+1] +define S_DESTFD stack[$1+2] +define S_STREAM stack[$1+3] +define S_REQUEST stack[$1+4] + +define push {stkp=stkp+1;stack[stkp]=($1)} +define pop {$1=stack[stkp];stkp=stkp-1} + + +# PR_PSIO -- Pseudofile i/o for a process. Process an i/o request for the +# specified pseudofile stream of the specified process. Called either to read +# command input from the CLIN of a process, or to process a read or write +# request to a pseudofile of a process. I/O to STDIN, STDOUT, and STDERR +# consists of simple binary copies of records. Output to the graphics streams +# STDGRAPH, STDIMAGE, or STDPLOT consists of GKI metacode and is optionally +# spooled and filtered with GIOTR (to apply the workstation transformation) +# before be passed to a graphics kernel. Process to process i/o is tricky +# since we must wait for a process to read or write (send us an XMIT or XFER) +# before transferring a data record. A process may read or write to streams +# of its own choosing before satisfying our request. A graphics kernel +# connected as a subprocess reads and writes metacode on a graphics stream +# and is free to read and write STDIN, STDOUT, etc. during execution as if +# the kernel were being run as a CL task. +# +# Note: This code is far more subtle than it appears. I was unable to express +# the subtleties in comments, eventually concluding that the code was easier +# to understand than the explanation (see Notes.psio for the attempts). Beware +# that the code is not completely general and assumes certain restrictions on +# process configurations. + +int procedure pr_psio (pid, fd, rwflag) + +int pid # process id number +int fd # file for which request is desired +int rwflag # type of transfer to wait for + +pointer ip, op +int stack[LEN_STACK], stkp, nchars, nleft +int stream, pr, in, record_type, rq, iotype +int pseudofile, destfd, destpr, destination, ps, flags +bool filter_gki, graphics_stream, xmit_pending, ioctrl + +int filbuf(), read(), strncmp(), fstati() +int pr_findproc(), psio_isxmit(), zfunc2(), zfunc3() +errchk epa_writep, epa_giotr, epa_writetty, epa_readtty, epa_gflush +errchk pr_findproc, psio_xfer, filbuf, read, write, flush, syserr +include <fio.com> +include "prc.com" + +begin + stream = fd + pr = pr_findproc (pid) + in = pr_infd[pr] + stkp = 0 + + if (rwflag == FF_WRITE) { + # We have been called to write to a subprocess. Simulate a + # pending XMIT request by pushing an XMIT on the stack. This + # causes XFER requests to be processed from the subprocess + # until the FIO buffer for destfd is exhausted. + + push (pr) + push (in) + push (fd) + push (stream) + push (XMIT) + } + +# call putline (STDERR, "----------------------------------------------\n") +# call eprintf ("PSIO (pid=%d, pr=%d, stream=%d)\n") +# call pargi(pid); call pargi(pr); call pargi(stream) + + # Process i/o requests from the subprocess until a request is received + # for the stream FD. Unsolicited requests from the process do not + # satisfy the request we were called for, e.g., a process may read from + # STDIN or write to STDERR before reading from fd=STDGRAPH. + + repeat { + repeat { +# call eprintf ("\n.....fill buffer: in=%d, pr=%d, stream=%d, stkp=%d\n") +# call pargi(in); call pargi(pr); call pargi(stream); call pargi(stkp) + nleft = itop[in] - iop[in] + if (nleft <= 0) + nleft = filbuf (in) + +# for(ip=iop[in];ip<itop[in];ip=ip+1)call putc(STDERR, Memc[ip]) + if (nleft == EOF) { + stkp = 0 + nchars = 0 + break + } else + ip = iop[in] + + # Determine the type of directive, e.g., OS escape, xmit/xfer, + # or data (anything other than a pseudofile directive). + + if (Memc[ip] == '!') + record_type = OSCMD + else if (Memc[ip] != 'x') + record_type = DATA + else + record_type = psio_isxmit (Memc[ip], pseudofile, nchars) + +# call eprintf ("record_type=%d, ps=%d, nchars=%d\n") +# call pargi(record_type); call pargi(pseudofile); call pargi(nchars) + + if (record_type == OSCMD) { + itop[in] = ip + nchars = nleft + + } else if (record_type == DATA) { + pseudofile = CLIN + nchars = nleft + + } else if (pseudofile < PSIOCTRL) { + # Decode the destination code into the destination FD, + # process slot number, and GKI filter flag. + + destination = pr_pstofd[pr,pseudofile] +# call eprintf ("redir code = %d\n"); call pargi (destination) + if (destination <= 0) { + destination = -destination + filter_gki = true + } else + filter_gki = false + + if (destination > KSHIFT) { + destfd = mod (destination, KSHIFT) + destpr = destination / KSHIFT + } else { + destfd = destination + destpr = 0 + } + + graphics_stream = (destfd >= STDGRAPH && destfd <= STDPLOT) + + # Discard the xmit or xfer directive. We will reuse the + # buffer at Memc[ip] later for temporary storage. + + itop[in] = ip +# call eprintf ("filter=%b, destfd=%d, destpr=%d\n") +# call pargb(filter_gki); call pargi (destfd); call pargi (destpr) + + } else { + # Pseudofile control directive. + record_type = PSIO + itop[in] = ip + } + + # Process the record (data or PSIO directive). + switch (record_type) { + case DATA: + # Ordinary data record. If the requested fd is not CLIN + # we have an unsolicited command input error. If this + # occurs on a graphics stream, reset the stream (close the + # kernel and free all storage) to avoid leaving the graphics + # system in a funny state. + + iotype = FF_READ + destfd = CLIN + + if (stream != destfd) { + # Reset graphics stream. + if (graphics_stream) + call zcall1 (epa_gflush, stream) + + # Take error action. + Memc[ip+nchars] = EOS + call putline (STDERR, Memc[ip]) + call syserr (SYS_PRPSIOUCI) + } + + case XMIT: + # Write to a process pseudofile. + iotype = FF_READ + + # If pseudofile output is not connected to a stream read + # and discard the data block. This situation occurs + # whenever a task in interrupted. + + if (destfd == 0) { + if (read (in, Memc[ip], nchars) < nchars) + call syserr (SYS_PRIPCSYNTAX) + next + } + + if (filter_gki) { + # Process a block of GKI metacode. Append the block + # to the frame buffer for the stream and call GIOTR + # to process the metacode. + + op = zfunc2 (epa_writep, destfd, nchars) + if (read (in, Memc[op], nchars) < nchars) + call syserr (SYS_PRIPCSYNTAX) +# call eprintf ("___giotr, %d chars\n") +# call pargi (nchars) + + # Call GIOTR to process the graphics data. Any data + # to be returned to the client is spooled in the + # graphics stream to be read by a subsequent XFER. + + call fseti (destfd, F_CANCEL, OK) + call zcall1 (epa_giotr, destfd) + call seek (destfd, BOFL) + + } else { + # Binary transfer. + + if (read (in, Memc[ip], nchars) < nchars) + call syserr (SYS_PRIPCSYNTAX) + + # If writing to a standard stream and a raw mode i/o + # control sequence is seen, do a fseti on STDIN in + # this process to set up raw mode at the FIO level + # on the stream. If we don't do this, raw mode will + # be set in the driver but will be disabled in the + # first i/o operation by a nchars>1 read request from + # FIO. + + if (destfd >= STDIN && destfd <= STDERR) { + ioctrl = (Memc[ip] == ESC && + (nchars==LEN_RAWCMD || nchars==LEN_RAWCMD+1)) + if (ioctrl) { + if (strncmp(Memc[ip],RAWOFF,LEN_RAWCMD) == 0) { + flags = IO_NORMAL + } else if (strncmp (Memc[ip], + RAWON, LEN_RAWCMD) == 0) { + flags = IO_RAW + if (Memc[ip+LEN_RAWCMD] == 'N') + flags = flags + IO_NDELAY + } else + ioctrl = false + } + + if (ioctrl) + call fseti (STDIN, F_IOMODE, flags) + else { + call zcall3 (epa_writetty, destfd, Memc[ip], + nchars) + } + } else { + call write (destfd, Memc[ip], nchars) + if (!graphics_stream) + call flush (destfd) + } + } + + # If writing to another process, push the current request + # and transfer command input to the destination process. + # Rewind the destfd file buffer so that it may be read by + # the process in a subsequent XFER call on the stream. + + if (destpr != 0) { + if (graphics_stream) + call seek (destfd, BOFL) + + push (pr) + push (in) + push (destfd) + push (stream) + push (XMIT) + + pr = destpr + in = pr_infd[pr] + stream = destfd +# call eprintf ("push XMIT, new in = %d, new pr = %d\n") +# call pargi (in); call pargi(pr) + + } else if (stkp > 0) { + # If the XMIT just completed satisfies a pending XFER + # request, complete the XFER request and pop it from + # the stack. + + rq = stkp - LEN_STACKFRAME + 1 + if (S_REQUEST(rq) == XFER && + S_DESTFD(rq) == destfd) { + + pop (record_type) + pop (stream) + pop (destfd) + pop (in) + pop (pr) + + call seek (stream, BOFL) + nchars = itop[stream] - iop[stream] + if (nchars <= 0) + nchars = 0 + else + nchars = read (stream, Memc[ip], nchars) +# call eprintf ("XFER completed from fd=%d to pr=%d, %d chars\n") +# call pargi(stream); call pargi(pr); call pargi(nchars) + call psio_xfer (pr_outfd[pr], Memc[ip], nchars) + + # The stream buffer should now be empty as only + # one IPC record at a time is buffered for an + # XFER request. Mark the buffer empty. + + call fseti (stream, F_CANCEL, OK) + } + } + + case XFER: + # Read from a pseudofile. + iotype = FF_WRITE + + if (destpr != 0 && iop[destfd] >= itop[destfd]) { + # Read from another process. Pseudofile FIO buffer + # is empty. Push the current request and transfer + # command input to the second process to give it an + # opportunity to write data into the buffer so that + # we can complete the XFER request. + + push (pr) + push (in) + push (destfd) + push (stream) + push (XFER) + + pr = destpr + in = pr_infd[pr] + stream = destfd +# call eprintf ("push XFER, new in = %d, new pr = %d\n") +# call pargi (in); call pargi(pr) + + } else { + # Binary transfer. If reading from the stream + # associated with a pushed XMIT and the stream + # buffer is empty, the XMIT has been completed + # and must be popped. + + xmit_pending = false + if (stkp > 0) { + rq = stkp - LEN_STACKFRAME + 1 + if (S_REQUEST(rq) == XMIT && S_DESTFD(rq) == destfd) + xmit_pending = true + } + +# call eprintf ("in XFER: req=%d, str=%d, xmp=%b, iop=%d, itop=%d\n") +# call pargi(S_REQUEST(rq)); call pargi(S_STREAM(rq)) +# call pargb(xmit_pending); call pargi(iop[destfd]); call pargi(itop[destfd]) + + if (xmit_pending && iop[destfd] >= itop[destfd]) { + # The pending XMIT has been completed (the stream + # buffer has been emptied by the reading process). + # Push the current XFER request back into the + # process input stream since we are not prepared + # to deal with it now. + + itop[in] = iop[in] + nleft + + # Pop the XMIT request. + pop (record_type) + pop (stream) + pop (destfd) + pop (in) + pop (pr) + ip = iop[in] + + # Empty the fully read stream buffer. + call fseti (destfd, F_CANCEL, OK) +# call eprintf ("XFER pops XMIT; push back XFER for later\n") + + } else { + # Satisfy XFER by reading a data record and + # returning it to the requesting process. + # A request to read a single char enables raw + # mode, just as it does for ZGETTX. + +# This should not be necessary since the raw mode control sequence is +# intercepted above. Also it is incorrect since F_NDELAY is not supported. +# if (nchars == 1) +# call fseti (destfd, F_RAW, YES) + + if (destfd == STDIN) { + nchars = zfunc3 (epa_readtty, + destfd, Memc[ip], nchars) + } else + nchars = read (destfd, Memc[ip], nchars) + if (nchars == EOF) + nchars = 0 +# call eprintf ("XFER completed from fd=%d to pr=%d, %d chars\n") +# call pargi(destfd); call pargi(pr); call pargi(nchars) + call psio_xfer (pr_outfd[pr], Memc[ip], nchars) + } + } + + + case PSIO: + # Pseudofile i/o control directive. These directives are + # used to connect graphics kernels to streams, to set and + # get WCS, set cursor mode parameters, etc. An XMIT to the + # pseudofile PSIOCTRL is use to pass control instructions + # via us to GTR_CONTROL, below. Note that the PSIOCTRL + # pseudofile is used to control all the graphics pseudofile + # streams. The number of the graphics pseudofile stream + # to be operated upon by gtr_control is passed as the first + # integer word of the data block. + + # Read pseudofile number. + iotype = 0 + if (read (in, ps, SZ_INT32) < SZ_INT32) + call syserr (SYS_PRIPCSYNTAX) + + # Read data block. + nchars = nchars - SZ_INT32 + if (read (in, Memc[ip], nchars) < nchars) + call syserr (SYS_PRIPCSYNTAX) + + # Call gtr_control to process the control directives. + iferr (call zcall3 (epa_control,ps,Memc[ip],pr_pid[pr])) + call erract (EA_WARN) + + # When writing to a graphics subkernel gtr_control may + # leave graphics metacode spooled in the graphics stream + # which we need to pass on to the subkernel. This is + # done by pushing an XMIT on the psio control stack to + # cause the subkernel process to be polled to see if it + # wants the spooled data. + + nchars = fstati (ps, F_FILESIZE) + if (nchars > 0) { + destination = abs(pr_pstofd[pr,ps]) + if (destination > KSHIFT) { + destfd = mod (destination, KSHIFT) + destpr = destination / KSHIFT + } else { + destfd = destination + destpr = 0 + } + + if (destpr != 0) { + call seek (destfd, BOFL) + + push (pr) + push (in) + push (destfd) + push (stream) + push (XMIT) + + pr = destpr + in = pr_infd[pr] + stream = destfd + } + } + + case OSCMD: + # OS escape directive. There are portability problems + # with issuing ZOSCMD os escapes from subprocesses, so + # subprocesses send OS escapes to us (the parent process) + # as !cmd commands on CLOUT. + + Memc[ip+nchars] = EOS + call proscmd (pr, Memc[ip+1]) + } + + } until (stkp <= 0 && record_type != OSCMD) + +# call eprintf ("termination ps(%d)=st(%d), io(%d)=rw(%d)\n") +# call pargi(pseudofile); call pargi(stream) +# call pargi(iotype); call pargi(rwflag) + } until (pseudofile == stream && iotype == rwflag) + +# call putline (STDERR, "----------------------------------------------\n") +# call eprintf ("EXIT PSIO\n") + + if (nchars == 0) + return (EOF) + else + return (nchars) +end diff --git a/sys/etc/prpsload.x b/sys/etc/prpsload.x new file mode 100644 index 00000000..c44eea03 --- /dev/null +++ b/sys/etc/prpsload.x @@ -0,0 +1,30 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> + +# PRPSLOAD -- Must be called at process startup time to initialize pseudofile +# i/o for the graphics streams, if any i/o to the graphics pseudofiles is +# expected. The arguments are the LOCPR entry point addresses of the graphics +# driver (gio.cursor) procedures to be called to process i/o requests on the +# graphics streams. + +procedure prpsload (giotr, control, gflush, writep, readtty, writetty) + +extern giotr() #I gio.cursor driver procedures +extern control() #I " " +extern gflush() #I " " +extern writep() #I " " +extern readtty() #I " " +extern writetty() #I " " + +int locpr() +include "prc.com" + +begin + epa_giotr = locpr (giotr) + epa_control = locpr (control) + epa_gflush = locpr (gflush) + epa_writep = locpr (writep) + epa_readtty = locpr (readtty) + epa_writetty = locpr (writetty) +end diff --git a/sys/etc/prredir.x b/sys/etc/prredir.x new file mode 100644 index 00000000..baf68b48 --- /dev/null +++ b/sys/etc/prredir.x @@ -0,0 +1,32 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> +include <syserr.h> + +# PRREDIR -- Redirect the pseudofile stream of a connected subprocess. A newly +# connected subprocess inherits the pseudofile streams of the parent, i.e., +# a write to STDOUT by the child will be directed to the STDOUT of the parent. +# Note that unlike FREDIR, the destination stream must already be open and +# is unaffected by the redirection of the pseudofile (the pseudofile stream is +# redirected into the existing stream). The destination file need not be of +# the same type (binary) as the pseudofile, unless the pseudofile stream +# contains binary data. + +procedure prredir (pid, stream, new_fd) + +int pid # process-id of child +int stream # stream to be redirected (STDIN, STDOUT, etc) +int new_fd # destination FD (already opened) + +int pr +int pr_findproc() +include "prc.com" +errchk syserr + +begin + pr = pr_findproc (pid) + if (pr == ERR) + call syserr (SYS_PRNOTFOUND) + + pr_pstofd[pr,stream] = new_fd +end diff --git a/sys/etc/prseti.x b/sys/etc/prseti.x new file mode 100644 index 00000000..ad798d42 --- /dev/null +++ b/sys/etc/prseti.x @@ -0,0 +1,51 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <config.h> +include <prstat.h> + +# PRSETI -- Set the value of a parameter for a connected subprocess. + +procedure prseti (pid, param, value) + +int pid #I process id of connected subprocess +int param #I parameter to be set +int value #I new parameter value + +int pr +int pr_findproc() +include "prc.com" +errchk syserr + +begin + pr = pr_findproc (pid) + if (pr == ERR) + call syserr (SYS_PRNOTFOUND) + + switch (param) { + case PR_STATUS: + pr_status[pr] = value + case PR_INCHAN: + pr_inchan[pr] = value + case PR_INFD: + pr_infd[pr] = value + case PR_OUTCHAN: + pr_outchan[pr] = value + case PR_OUTFD: + pr_outfd[pr] = value + case PR_STDIN: + pr_pstofd[pr,STDIN] = value + case PR_STDERR: + pr_pstofd[pr,STDERR] = value + case PR_STDOUT: + pr_pstofd[pr,STDOUT] = value + case PR_STDGRAPH: + pr_pstofd[pr,STDGRAPH] = value + case PR_STDIMAGE: + pr_pstofd[pr,STDIMAGE] = value + case PR_STDPLOT: + pr_pstofd[pr,STDPLOT] = value + default: + call syserr (SYS_PRSTAT) + } +end diff --git a/sys/etc/prsignal.x b/sys/etc/prsignal.x new file mode 100644 index 00000000..0ec647a0 --- /dev/null +++ b/sys/etc/prsignal.x @@ -0,0 +1,27 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> +include <syserr.h> +include <knet.h> + +# PRSIGNAL -- Send a signal (interrupt) to a child process. It is an error +# if the pid given is not found in the process table. + +procedure prsignal (pid, signal) + +int pid # process-id of child process +int signal # code of signal to be sent (e.g. X_INT) + +int child +int pr_findproc() +include "prc.com" +errchk syserr + +begin + child = pr_findproc (pid) + if (child != ERR) + call zintpr (pid, signal, child) + + if (child == ERR) + call syserr (SYS_PRSIGNAL) +end diff --git a/sys/etc/prstati.x b/sys/etc/prstati.x new file mode 100644 index 00000000..bd3eb221 --- /dev/null +++ b/sys/etc/prstati.x @@ -0,0 +1,49 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <config.h> +include <prstat.h> + +# PRSTATI -- Get the value of a parameter for a connected subprocess. + +int procedure prstati (pid, param) + +int pid # process id of connected subprocess +int param # parameter for which status is desired +int pr +int pr_findproc() +include "prc.com" +errchk syserr + +begin + pr = pr_findproc (pid) + if (pr == ERR) + call syserr (SYS_PRNOTFOUND) + + switch (param) { + case PR_STATUS: + return (pr_status[pr]) + case PR_INCHAN: + return (pr_inchan[pr]) + case PR_INFD: + return (pr_infd[pr]) + case PR_OUTCHAN: + return (pr_outchan[pr]) + case PR_OUTFD: + return (pr_outfd[pr]) + case PR_STDIN: + return (pr_pstofd[pr,STDIN]) + case PR_STDERR: + return (pr_pstofd[pr,STDERR]) + case PR_STDOUT: + return (pr_pstofd[pr,STDOUT]) + case PR_STDGRAPH: + return (pr_pstofd[pr,STDGRAPH]) + case PR_STDIMAGE: + return (pr_pstofd[pr,STDIMAGE]) + case PR_STDPLOT: + return (pr_pstofd[pr,STDPLOT]) + default: + call syserr (SYS_PRSTAT) + } +end diff --git a/sys/etc/prupdate.x b/sys/etc/prupdate.x new file mode 100644 index 00000000..49aa7e56 --- /dev/null +++ b/sys/etc/prupdate.x @@ -0,0 +1,61 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <error.h> +include <config.h> +include <prstat.h> + +# PRUPDATE -- Broadcast a message to a process, or if pid=0, to all connected +# subprocesses. Used primarily to incrementally pass SET and CHDIR commands to +# subprocesses, eliminating the need to reconnect each process. Note that the +# child process does not return "bye" in response to one of the builtin +# functions SET and CHDIR. NOTE: if a child process is marked "busy" the +# message is not sent to that process; only idle processes receive the message. + +procedure prupdate (pid, message, flushout) + +int pid #I process to be updated, or 0 for all procs +char message[ARB] #I message to be broadcast to each child +int flushout #I flush output + +int pr, status +pointer sp, cmd, op +int gstrcpy(), prstati() +include "prc.com" + +begin + call smark (sp) + call salloc (cmd, SZ_COMMAND, TY_CHAR) + + # Make sure that the message string is non-null and is newline + # delimited. + + op = cmd + gstrcpy (message, Memc[cmd], SZ_COMMAND) + if (op == cmd) { + call sfree (sp) + return + } else if (Memc[op-1] != '\n') { + Memc[op] = '\n' + Memc[op+1] = EOS + } + + # Broadcast the message. If the child fails to process the command + # and returns the ERROR statement, the error will not be detected until + # the next user command is sent to the process (and indeed may corrupt + # the protocol). The parent should execute the SET or CHDIR prior + # to sending it to the child to make sure it is valid. + + for (pr=1; pr <= MAX_CHILDPROCS; pr=pr+1) + if ((pid != NULL && pr_pid[pr] == pid) || + (pid == NULL && pr_pid[pr] != NULL)) { + + status = prstati (pr_pid[pr], PR_STATUS) + if (status == P_RUNNING) { + iferr (call putline (pr_outfd[pr], Memc[cmd])) + call erract (EA_WARN) + else if (flushout == YES) + call flush (pr_outfd[pr]) + } + } + + call sfree (sp) +end diff --git a/sys/etc/psioisxt.x b/sys/etc/psioisxt.x new file mode 100644 index 00000000..ddebd7df --- /dev/null +++ b/sys/etc/psioisxt.x @@ -0,0 +1,58 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <ctype.h> +include <gio.h> + + +# PSIO_ISXMIT -- Test for a pseudofile directive. Return XMIT, XFER, or DATA +# as the function value, and if we do have a pseudofile, decode the pseudofile +# number and char count. +# +# Syntax: "xmit(P,NNN)" or "xfer(P,NNN)" +# 12345678 12345678 +# +# where P is the pseudofile code (0<P<10) and NNN is the size of the data block +# in chars. In the following code all explicit integer constants refer to the +# character offsets shown above. + +int procedure psio_isxmit (lbuf, pseudofile, nchars) + +char lbuf[ARB] # text +int pseudofile # pseudofile code (output) +int nchars # block size (output) +int line_type, ip +int ctoi() +errchk syserr + +begin + # Decode line type. If we are called we have already determined that + # lbuf[1] is 'x'. + + if (lbuf[2] == 'm') { + if (lbuf[3] == 'i' && lbuf[4] == 't' && lbuf[5] == '(') + line_type = XMIT + else + return (DATA) + } else if (lbuf[2] == 'f') { + if (lbuf[3] == 'e' && lbuf[4] == 'r' && lbuf[5] == '(') + line_type = XFER + else + return (DATA) + } else + return (DATA) + + # Get pseudofile code. + ip = 6 + if (ctoi (lbuf, ip, pseudofile) <= 0) + call syserr (SYS_PRIPCSYNTAX) + + while (lbuf[ip] == ',' || IS_WHITE(lbuf[ip])) + ip = ip + 1 + + # Get char size of data block. + if (ctoi (lbuf, ip, nchars) <= 0) + call syserr (SYS_PRIPCSYNTAX) + + return (line_type) +end diff --git a/sys/etc/psioxfer.x b/sys/etc/psioxfer.x new file mode 100644 index 00000000..ca286512 --- /dev/null +++ b/sys/etc/psioxfer.x @@ -0,0 +1,33 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +define SZ_NUMBUF 8 # encoded count for an XFER + + +# PSIO_XFER -- Transfer a data record to a process to complete an XFER +# request. Write the byte count record followed by the data record. +# These must be written as two separate records or deadlock +# will occur (with the reader waiting for the second record). + +procedure psio_xfer (fd, buf, nchars) + +int fd # output file +char buf[ARB] # buffer containing record to be written +int nchars # length of record + +int ndigits +char numbuf[SZ_NUMBUF] +int itoc() + +begin + if (nchars >= 0) { + ndigits = itoc (nchars, numbuf, SZ_NUMBUF) + numbuf[ndigits+1] = '\n' + call write (fd, numbuf, ndigits + 1) + call flush (fd) + + if (nchars > 0) { + call write (fd, buf, nchars) + call flush (fd) + } + } +end diff --git a/sys/etc/qsort.x b/sys/etc/qsort.x new file mode 100644 index 00000000..f7efc4d3 --- /dev/null +++ b/sys/etc/qsort.x @@ -0,0 +1,81 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +define LOGPTR 32 # log2(maxpts) (4e9) + +# QSORT -- General quicksort for arbitrary objects. X is an integer array +# indexing the array to be sorted. The user supplied COMPARE function is used +# to compare objects indexed by X: +# +# -1,0,1 = compare (x1, x2) +# +# where the value returned by COMPARE has the following significance: +# +# -1 obj[x1] < obj[x2] +# 0 obj[x1] == obj[x2] +# 1 obj[x1] > obj[x2] +# +# QSORT reorders the elements of the X array, which must be of type integer. +# **NOTE** - See also gqsort.x, a more recent version of this routine. + +procedure qsort (x, nelem, compare) + +int x[ARB] # array to be sorted +int nelem # number of elements in array +extern compare() # function to be called to compare elements + +int i, j, k, lv[LOGPTR], p, pivot, uv[LOGPTR], temp +define swap {temp=$1;$1=$2;$2=temp} +int compare() + +begin + lv[1] = 1 + uv[1] = nelem + 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 the optimizer. + do p = p, ARB { + i = lv[p] - 1 + j = uv[p] + + # Select as the pivot the element at the center of the + # subfile, to avoid quadratic behavior on an already + # sorted list. + + k = (lv[p] + uv[p]) / 2 + swap (x[j], x[k]) + pivot = x[j] # pivot line + + while (i < j) { + for (i=i+1; compare (x[i], pivot) < 0; i=i+1) + ; + for (j=j-1; j > i; j=j-1) + if (compare (x[j], pivot) <= 0) + break + if (i < j) # out of order pair + swap (x[i], x[j]) # interchange elements + } + + j = uv[p] # move pivot to position i + swap (x[i], x[j]) # interchange elements + + 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 diff --git a/sys/etc/sttyco.x b/sys/etc/sttyco.x new file mode 100644 index 00000000..54f2c5ce --- /dev/null +++ b/sys/etc/sttyco.x @@ -0,0 +1,519 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <error.h> +include <syserr.h> +include <ctype.h> +include <ttyset.h> +include <ttset.h> + +.help sttyco +.nf --------------------------------------------------------------------------- +STTYCO -- Set/stat VOS terminal driver options via command string. This is a +high level front-end to the ttset/ttstat procedures, used to set or query the +individual terminal driver parameters. Since STTYCO is driven by a command +string it may be called either as a task or as a subroutine. When called as +a task, e.g, as the STTY task in the CL, the argument list is simply +concatenated into a long string and passed to STTYCO for processing. + +The argument list consists of zero or more argument strings, as follows: + + reset Reset default terminal settings + init Send initialization sequence to the terminal + show Show terminal settings + all Show all parameters, even if not in use + <nullarglist> Show terminal settings + <unknown> Assumed to be the termcap name of a terminal. + Set envvars `terminal', `ttyncols', and + `ttynlines' for the named terminal. + baud=N Set envvar `ttybaud=N'. + ncols=N Set envvar `ttyncols=N'. + nlines=N Set envvar `ttynlines=N'. + resize Reset the screen size parameters. + + clear Disable named driver functions. + + ucasein Map input to lower case. + ucaseout Map output to upper case. + + logio [=logiofile] Log all i/o to the terminal in a file. + login [=loginfile] Log input from terminal in a file. + logout [=logoutfile] Log output to terminal in a file. + + playback [=pbfile] Read terminal input from a logfile. + verify Pause at newline when in playback mode. + delay=N Msec delay in playback mode, verify disabled. + +Simply naming a parameter like ucasein, logio, etc., causes that function to +be enabled, or disabled if preceeded by the keyword `clear'. Any of the +sequences +, -, =yes, =no may also be appended to turn the function on or off. +The logging functions may also take a filename argument, e.g., logio=file +enables i/o logging into the named file. The default filenames are as follows: + + logio home$ttyio.log + login home$ttin.log + logout home$ttout.log + playback home$ttin.log + +If verify is disabled a delay will precede each record returned from the +input file; the default delay is quite short. Pause mode is terminated by +typing a space or carriage return to continue execution, or `q' to terminate +playback mode. +.endhelp ---------------------------------------------------------------------- + +define STTY_KEYWORDS "|reset|init|all|show|baud|ncols|nlines|resize|clear|\ + |ucasein|ucaseout|logio|login|logout|playback|verify|delay|" + +define RESET 1 # reset default terminal settings +define INIT 2 # send initialization sequence to the terminal +define ALL 3 # show all parameters +define SHOW 4 # show parameters +define BAUD 5 # set envvar `ttybaud' +define NCOLS 6 # set envvar `ttyncols' +define NLINES 7 # set envvar `ttynlines' +define RESIZE 8 # reset the screen size parameters +define CLEAR 9 # set default action to NO rather than YES +# newline 10 +define UCASEIN 11 # map input to lower case +define UCASEOUT 12 # map output to upper case +define LOGIO 13 # log all i/o in a file +define LOGIN 14 # log input in a file +define LOGOUT 15 # log output in a file +define PLAYBACK 16 # take input from a file +define VERIFY 17 # wait for user to type a key after each record +define DELAY 18 # msec delay after each record in playback mode + + +# STTYCO -- Main entry point. Input consists of an argument list of arbitrary +# length. Output is to the given file descriptor. + +procedure sttyco (args, ttin, ttout, outfd) + +char args[ARB] # argument list +int ttin, ttout # tty file descriptors +int outfd # write task output here + +pointer sp, keyw, value, tty +int startcol, ival, nargs, yesno, defact, show, all, ip +int stty_getarg(), strdic(), ctoi() +pointer ttyodes() + +string keywords STTY_KEYWORDS +errchk ttseti, ttsets, stty_ttyinit +define argerr_ 91 + +begin + call smark (sp) + call salloc (keyw, SZ_FNAME, TY_CHAR) + call salloc (value, SZ_FNAME, TY_CHAR) + + defact = YES + show = NO + all = NO + ip = 1 + + # Process successive keyword=value arguments. + + for (nargs=0; stty_getarg (args, ip, Memc[keyw], SZ_FNAME, Memc[value], + SZ_FNAME, defact, yesno) != EOF; nargs = nargs + 1) { + + switch (strdic (Memc[keyw], Memc[keyw], SZ_FNAME, keywords)) { + case RESET: + call ttseti (ttin, TT_INITIALIZE, yesno) + case INIT: + call stty_ttyinit (ttin, ttout, "terminal") + + case ALL: + all = yesno + show = YES + case SHOW: + show = yesno + case BAUD: + if (IS_DIGIT (Memc[value])) + call stty_envreset ("ttybaud", Memc[value]) + else + goto argerr_ + case NCOLS: + if (IS_DIGIT (Memc[value])) + call stty_envreset ("ttyncols", Memc[value]) + else + goto argerr_ + case NLINES: + if (IS_DIGIT (Memc[value])) + call stty_envreset ("ttynlines", Memc[value]) + else + goto argerr_ + + case RESIZE: + tty = ttyodes ("terminal") + call stty_setsize (ttin, ttout, tty) + call ttycdes (tty) + + case CLEAR: + defact = NO + + case UCASEIN: + call ttseti (ttin, TT_UCASEIN, yesno) + case UCASEOUT: + call ttseti (ttin, TT_UCASEOUT, yesno) + + case LOGIO: + if (yesno == YES && Memc[value] != EOS) + call ttsets (ttin, TT_IOFILE, Memc[value]) + call ttseti (ttin, TT_LOGIO, yesno) + case LOGIN: + if (yesno == YES && Memc[value] != EOS) + call ttsets (ttin, TT_INFILE, Memc[value]) + call ttseti (ttin, TT_LOGIN, yesno) + case LOGOUT: + if (yesno == YES && Memc[value] != EOS) + call ttsets (ttin, TT_OUTFILE, Memc[value]) + call ttseti (ttin, TT_LOGOUT, yesno) + case PLAYBACK: + if (yesno == YES && Memc[value] != EOS) + call ttsets (ttin, TT_PBFILE, Memc[value]) + call ttseti (ttin, TT_PLAYBACK, yesno) + + case VERIFY: + call ttseti (ttin, TT_PBVERIFY, yesno) + case DELAY: + startcol = 1 + if (ctoi (Memc[value], startcol, ival) > 0) + call ttseti (ttin, TT_PBDELAY, ival) + else + goto argerr_ + + default: + # If not keyword, must be a terminal name. + iferr (call stty_newterm (ttin, ttout, Memc[keyw])) + call erract (EA_WARN) + } + } + + # If the argument list was null or the SHOW flag was set, show + # the current terminal settings. + + if (nargs == 0 || show == YES) + call stty_showterm (ttin, ttout, outfd, all) + + call sfree (sp) + return + +argerr_ + call syserrs (SYS_STTYNUMARG, Memc[keyw]) + call sfree (sp) +end + + +# STTY_NEWTERM -- Configure the environment for a new type of terminal. + +procedure stty_newterm (ttin, ttout, terminal) + +int ttin, ttout # tty file descriptors +char terminal[ARB] # termcap name of new terminal + +pointer sp, vp, tty +pointer ttyodes() + +bool ttygetb() +int ttygets() +errchk ttyodes, stty_envreset, ttygsize + +begin + call smark (sp) + call salloc (vp, SZ_FNAME, TY_CHAR) + + tty = ttyodes (terminal) + + # Set the terminal parameters. + call stty_envreset ("terminal", terminal) + call stty_setsize (ttin, ttout, tty) + + # Set the stdgraph device name for this terminal, if given. + if (ttygetb (tty, "gd")) { + if (ttygets (tty, "gd", Memc[vp], SZ_FNAME) <= 0) + call strcpy (terminal, Memc[vp], SZ_FNAME) + } else + call strcpy ("none", Memc[vp], SZ_FNAME) + call stty_envreset ("stdgraph", Memc[vp]) + + call ttycdes (tty) + call sfree (sp) +end + + +# STTY_SETSIZE -- Determine the terminal screen size in characters, and set +# up the environment appropriately. + +procedure stty_setsize (ttin, ttout, tty) + +int ttin, ttout # tty file descriptors +pointer tty + +char num[4] +int ncols, nlines, n +int itoc() + +begin + call ttygsize (ttin, ttout, tty, ncols, nlines) + + n = itoc (ncols, num, 4) + call stty_envreset ("ttyncols", num) + call ttyseti (tty, TTY_NCOLS, ncols) + + n = itoc (nlines, num, 4) + call stty_envreset ("ttynlines", num) + call ttyseti (tty, TTY_NLINES, nlines) +end + + +# STTY_TTYINIT -- Output the initialization string and the contents of +# the initialization file to the terminal, if either is specified in the +# termcap entry for the device. + +procedure stty_ttyinit (ttin, ttout, terminal) + +int ttin, ttout # tty file descriptors +char terminal[ARB] # termcap name of new terminal + +pointer tty +pointer ttyodes() + +begin + tty = ttyodes (terminal) + call ttyinit (ttout, tty) + call flush (ttout) + call ttycdes (tty) +end + + +# STTY_ENVRESET -- Set the value of an environment variable in the current +# process and in all connected subprocesses. + +procedure stty_envreset (envvar, value) + +char envvar[ARB] # environment variable to be set +char value[ARB] # new value + +errchk envreset + +begin + call envreset (envvar, value) + call prenvset (0, envvar, value) +end + + +# STTY_SHOWTERM -- Show the current terminal driver status. + +procedure stty_showterm (ttin, ttout, fd, all) + +int ttin, ttout # tty file descriptors +int fd # where the output goes +int all # show all params, even if not in use + +int junk +pointer sp, val +bool ucasein, ucaseout, shift, logio, login, logout, playback, showall +int ttstati(), ttstats(), envfind() + +string unknown "[unknown]" +string on "on" +string off "off" + +begin + call smark (sp) + call salloc (val, SZ_FNAME, TY_CHAR) + + ucasein = (ttstati (ttin, TT_UCASEIN) == YES) + ucaseout = (ttstati (ttin, TT_UCASEOUT) == YES) + shift = (ttstati (ttin, TT_SHIFTLOCK) == YES) + logio = (ttstati (ttin, TT_LOGIO) == YES) + login = (ttstati (ttin, TT_LOGIN) == YES) + logout = (ttstati (ttin, TT_LOGOUT) == YES) + playback = (ttstati (ttin, TT_PLAYBACK) == YES) + showall = (all == YES) + + # Show tty environment variables. + + if (envfind ("terminal", Memc[val], SZ_FNAME) <= 0) + call strcpy ("?", Memc[val], SZ_FNAME) + call fprintf (fd, "%s ") + call pargstr (Memc[val]) + + if (envfind ("ttyncols", Memc[val], SZ_FNAME) <= 0) + call strcpy ("?", Memc[val], SZ_FNAME) + call fprintf (fd, "ncols=%s ") + call pargstr (Memc[val]) + + if (envfind ("ttynlines", Memc[val], SZ_FNAME) <= 0) + call strcpy ("?", Memc[val], SZ_FNAME) + call fprintf (fd, "nlines=%s ") + call pargstr (Memc[val]) + + if (showall || ucasein || ucaseout) { + if (envfind ("ttybaud", Memc[val], SZ_FNAME) <= 0) + call strcpy ("?", Memc[val], SZ_FNAME) + call fprintf (fd, "baudrate=%s ") + call pargstr (Memc[val]) + + call fprintf (fd, "ucasein=%b ") + call pargb (ucasein) + call fprintf (fd, "ucaseout=%b ") + call pargb (ucaseout) + call fprintf (fd, "shift=%b\n") + call pargb (shift) + } else + call fprintf (fd, "\n") + + # Show internal driver state variables in `show all' mode. + + if (showall) { + call fprintf (fd, + "kichan=%d kochan=%d lichan=%d lochan=%d pbchan=%d ") + call pargi (ttstati (ttin, TT_KINCHAN)) + call pargi (ttstati (ttin, TT_KOUTCHAN)) + call pargi (ttstati (ttin, TT_LOGINCHAN)) + call pargi (ttstati (ttin, TT_LOGOUTCHAN)) + call pargi (ttstati (ttin, TT_PBINCHAN)) + + call fprintf (fd, "raw=%b passthru=%b\n") + call pargb (ttstati (ttin, TT_RAWMODE) == YES) + call pargb (ttstati (ttin, TT_PASSTHRU) == YES) + } + + # Show the status of the logging options. + + if (logio || showall) { + junk = ttstats (ttin, TT_IOFILE, Memc[val], SZ_FNAME) + call fprintf (fd, "logio=%s [%s]\n") + call pargstr (Memc[val]) + if (logio) + call pargstr (on) + else + call pargstr (off) + } + + if (!logio || showall) { + if (login || showall) { + junk = ttstats (ttin, TT_INFILE, Memc[val], SZ_FNAME) + call fprintf (fd, "login=%s [%s]\n") + call pargstr (Memc[val]) + if (login) + call pargstr (on) + else + call pargstr (off) + } + if (logout || showall) { + junk = ttstats (ttin, TT_OUTFILE, Memc[val], SZ_FNAME) + call fprintf (fd, "logout=%s [%s]\n") + call pargstr (Memc[val]) + if (logout) + call pargstr (on) + else + call pargstr (off) + } + } + + if (playback || showall) { + junk = ttstats (ttin, TT_PBFILE, Memc[val], SZ_FNAME) + call fprintf (fd, "playback=%s [%s] ") + call pargstr (Memc[val]) + if (playback) + call pargstr (on) + else + call pargstr (off) + + call fprintf (fd, "verify=%b ") + call pargb (ttstati (ttin, TT_PBVERIFY) == YES) + call fprintf (fd, "delay=%d (msec)") + call pargi (ttstati (ttin, TT_PBDELAY)) + call fprintf (fd, "\n") + } + + if (playback) { + call fprintf (fd, "script recorded with terminal=%s, stdgraph=%s\n") + if (ttstats (ttin, TT_TDEVICE, Memc[val], SZ_FNAME) <= 0) + call pargstr (unknown) + else + call pargstr (Memc[val]) + if (ttstats (ttin, TT_GDEVICE, Memc[val], SZ_FNAME) <= 0) + call pargstr (unknown) + else + call pargstr (Memc[val]) + } + + call sfree (sp) +end + + +# STTY_GETARG -- Get the next argument from an argument list. Arguments are of +# the form keyw, keyw+, keyw-, keyw=(yes|y), keyw=(no|n), or keyw=value. +# All forms are reduced to a flag YESNO and a value string VALUE. The forms +# keyw=yes, key=no, etc., cause YESNO to be set but not VALUE. If only the +# keyword name is given YESNO is set to YES and VALUE to the null string. +# The number of characters in the keyword=value argument string is returned +# as the function value, or EOF when the argument list is exhausted. + +int procedure stty_getarg (args, ip, keyw, maxkc, value, maxvc, defact, yesno) + +char args[ARB] # argument string +int ip # index into argument string [RW] +char keyw[ARB] # receives keyword name +int maxkc # max chars in keyw string +char value[ARB] # receives value string or EOS +int maxvc # max chars in value string +int defact # default action (yes/no) if only keyword given +int yesno # boolean value of parameter + +int op +int ip_save +bool streq() + +begin + while (IS_WHITE (args[ip])) + ip = ip + 1 + + ip_save = ip + + # Get keyword name. + for (op=1; IS_ALNUM (args[ip]); ip=ip+1) { + keyw[op] = args[ip] + op = min (maxkc, op + 1) + } + keyw[op] = EOS + + while (IS_WHITE (args[ip])) + ip = ip + 1 + + value[1] = EOS + yesno = defact + + if (args[ip] == '=') { + # Extract value string. + op = 1 + for (ip=ip+1; args[ip] > ' '; ip=ip+1) { + value[op] = args[ip] + op = min (maxvc, op + 1) + } + value[op] = EOS + + # Check for keyw=[yes|no]. + if (streq (value, "yes") || streq (value, "y")) { + yesno = YES + value[1] = EOS + } else if (streq (value, "no") || streq (value, "n")) { + yesno = NO + value[1] = EOS + } + } else if (args[ip] == '+') { + yesno = YES + ip = ip + 1 + } else if (args[ip] == '-') { + yesno = NO + ip = ip + 1 + } + + if (ip <= ip_save) + return (EOF) + else + return (ip - ip_save) +end diff --git a/sys/etc/syserr.x b/sys/etc/syserr.x new file mode 100644 index 00000000..a14d516d --- /dev/null +++ b/sys/etc/syserr.x @@ -0,0 +1,49 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +define SZ_ERRMSG SZ_LINE + +# SYSERR -- Process a system error. No arguments; print only the error +# message from the system error message file. + +procedure syserr (errcode) + +int errcode + +begin + call syserrs (errcode, "") +end + + +# SYSERRS -- System error, with a user supplied string argument. We do not +# want to search the system error message file until ERRACT is called to +# output the error message and initiate error recovery, because if an IFERR +# error handler is posted the message will never be used. Hence we encode +# an error message of the form "123 user_string", where "123" is the encoded +# system error message number. If a message is ever actually output the +# 123 will be expanded into a readable error message. + +procedure syserrs (errcode, user_string) + +int errcode +char user_string[ARB] + +char buf[SZ_ERRMSG] +int ip, op +int itoc() + +begin + # Encode error code, to be used to search error message file. + op = itoc (errcode, buf, SZ_ERRMSG) + 1 + + if (user_string[1] != EOS) { + buf[op] = ' ' + op = op + 1 + for (ip=1; op <= SZ_ERRMSG && user_string[ip] != EOS; ip=ip+1) { + buf[op] = user_string[ip] + op = op + 1 + } + } + buf[op] = EOS + + call error (errcode, buf) +end diff --git a/sys/etc/sysid.x b/sys/etc/sysid.x new file mode 100644 index 00000000..94bd77bc --- /dev/null +++ b/sys/etc/sysid.x @@ -0,0 +1,57 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# SYSID -- Return a line of text identifying the current user, machine, and +# version of IRAF, and containing the current date and time. The format is +# as follows: +# +# NOAO/IRAF V1.3 username@lyra Tue 09:47:50 27-Aug-85 +# +# The string "NOAO/IRAF V1.3" is given by the value of the environment variable +# "version", defined in lib$clpackage.cl (unless redefined by the user). The +# string "username" is the value of the environment variable "userid", defined +# by the user in the login.cl file. The output string is not terminated by a +# newline. + +procedure sysid (outstr, maxch) + +char outstr[maxch] # receives id string +int maxch + +pointer sp, buf +int op, nchars +int envfind(), gstrcpy() +long clktime() + +begin + call smark (sp) + call salloc (buf, SZ_LINE, TY_CHAR) + + nchars = envfind ("version", outstr, maxch) + if (nchars <= 0) + nchars = gstrcpy ("NOAO/IRAF", outstr, maxch) + + op = nchars + 1 + outstr[op] = ' ' + op = op + 1 + + # The variable "userid" is defined in the user's login.cl file. This + # gives the user the opportunity to set the value of this string to + # something other than their host system login name. + + nchars = envfind ("userid", Memc[buf], SZ_LINE) + + op = op + gstrcpy (Memc[buf], outstr[op], maxch-op+1) + outstr[op] = '@' + op = op + 1 + + call gethost (Memc[buf], SZ_LINE) + op = op + gstrcpy (Memc[buf], outstr[op], maxch-op+1) + outstr[op] = ' ' + op = op + 1 + + call cnvtime (clktime(long(0)), Memc[buf], SZ_LINE) + op = op + gstrcpy (Memc[buf], outstr[op], maxch-op+1) + outstr[op] = EOS + + call sfree (sp) +end diff --git a/sys/etc/syspanic.x b/sys/etc/syspanic.x new file mode 100644 index 00000000..8ddfdb81 --- /dev/null +++ b/sys/etc/syspanic.x @@ -0,0 +1,17 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# SYS_PANIC -- Unconditionally abort process execution. Called when an error +# condition occurs so serious that process execution cannot continue reliably. + +procedure sys_panic (errcode, errmsg) + +int errcode # error code +char errmsg[ARB] # error message + +begin + # Since process termination is imminent we may as well overwrite the + # error message string by packing it in place. + + call strpak (errmsg, errmsg, ARB) + call zpanic (errcode, errmsg) +end diff --git a/sys/etc/sysptime.x b/sys/etc/sysptime.x new file mode 100644 index 00000000..3a2657c2 --- /dev/null +++ b/sys/etc/sysptime.x @@ -0,0 +1,84 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <ctype.h> + +define SZ_OBUF 8 +define CPU 1 +define CLK 2 + + +# SYS_MTIME -- Mark the time, i.e., save the current clock and cpu times in +# the save buffer. + +procedure sys_mtime (save_time) + +long save_time[2] # mark time buffer + +begin + call zgtime (save_time[CLK], save_time[CPU]) +end + + +# SYS_PTIME -- Print the cpu and clock time consumed since the last call to +# SYS_MTIME. + +procedure sys_ptime (fd, opstr, save_time) + +int fd # output file +char opstr[ARB] # optional operand name string +long save_time[2] # mark time buffer + +int op, junk +char obuf[SZ_OBUF] +long new_clk, new_cpu +int d_clk, d_cpu, msec, sec, percent +int itoc() + +begin + call zgtime (new_clk, new_cpu) + d_clk = (new_clk - save_time[CLK]) # clk seconds + d_cpu = (new_cpu - save_time[CPU]) # cpu msec + + call putline (fd, "Time ") + if (opstr[1] != EOS) { + call putci (fd, '(') + call putline (fd, opstr) + call putline (fd, ") ") + } + + # Output the cpu time in seconds. + op = itoc (d_cpu / 1000, obuf, SZ_OBUF) + 1 + obuf[op] = '.'; op = op + 1 + msec = mod (d_cpu, 1000) + if (msec < 100) { + obuf[op] = '0'; op = op + 1 + } + if (msec < 10) { + obuf[op] = '0'; op = op + 1 + } + if (msec > 0) + op = op + itoc (msec, obuf[op], SZ_OBUF-op+1) + call putline (fd, obuf) + + # Output the clock time in minutes and seconds. + call putci (fd, ' ') + op = itoc (d_clk / 60, obuf, SZ_OBUF) + 1 + obuf[op] = ':'; op = op + 1 + sec = mod (d_clk, 60) + obuf[op] = TO_DIGIT(sec/10); op = op + 1 + obuf[op] = TO_DIGIT(mod(sec,10)); op = op + 1 + obuf[op] = EOS + call putline (fd, obuf) + + # Output the percent cpu utilization. + call putci (fd, ' ') + if (d_clk < 1) + call strcpy ("99", obuf, SZ_OBUF) + else { + percent = min (99, d_cpu / d_clk / 10) + junk = itoc (percent, obuf, SZ_OBUF) + } + + call putline (fd, obuf) + call putline (fd, "%\n") +end diff --git a/sys/etc/tsleep.x b/sys/etc/tsleep.x new file mode 100644 index 00000000..d1dbccb1 --- /dev/null +++ b/sys/etc/tsleep.x @@ -0,0 +1,13 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# TSLEEP -- Suspend execution of the calling task for the specified number +# of seconds. + +procedure tsleep (seconds) + +int seconds + +begin + if (seconds > 0) + call zwmsec (seconds * 1000) +end diff --git a/sys/etc/ttopen.x b/sys/etc/ttopen.x new file mode 100644 index 00000000..979d6f67 --- /dev/null +++ b/sys/etc/ttopen.x @@ -0,0 +1,96 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <fset.h> + +# TTOPEN -- Open a terminal for direct i/o. The logical device "dev$tty" +# denotes the user terminal. Note that this string is passed on to the +# kernel without modification, despite the apparent use of a logical directory. +# (See also fio$zfiott.x, the logical terminal driver). + +int procedure ttopen (terminal, mode) + +char terminal[ARB] # device to be opened +int mode + +int fopntx() +extern zopntt(), zgettt(), zputtt(), zflstt(), zstttt(), zclstt(), + zsektt(), znottt() + +begin + return (fopntx (terminal, mode, zopntt, zgettt, zputtt, zflstt, + zstttt, zclstt, zsektt, znottt)) +end + + +# TTSETI -- Set special terminal driver options. The regular FIO options +# are set using FSETI. + +procedure ttseti (fd, param, value) + +int fd # file descriptor +int param # parameter to be set +int value # new value + +int channel +int fstati() + +begin + channel = fstati (fd, F_CHANNEL) + call zsettt (channel, param, value) +end + + +# TTSTATI -- Stat special terminal driver options. + +int procedure ttstati (fd, param) + +int fd # file descriptor +int param # parameter to be set + +long lvalue +int channel +int fstati() + +begin + channel = fstati (fd, F_CHANNEL) + call zstttt (channel, param, lvalue) + return (lvalue) +end + + +# TTSETS -- Set special terminal driver option, type string. The regular FIO +# options are set using FSETI. + +procedure ttsets (fd, param, svalue) + +int fd # file descriptor +int param # parameter to be set +char svalue[ARB] # new string value + +int channel +int fstati() + +begin + channel = fstati (fd, F_CHANNEL) + call zsestt (channel, param, svalue) +end + + +# TTSTATS -- Stat special terminal driver options, type string. + +int procedure ttstats (fd, param, outstr, maxch) + +int fd # file descriptor +int param # parameter to be set +char outstr[maxch] # receives parameter value +int maxch + +int nchars +int channel +int fstati() + +begin + channel = fstati (fd, F_CHANNEL) + call zststt (channel, param, outstr, maxch, nchars) + return (nchars) +end diff --git a/sys/etc/urlget.x b/sys/etc/urlget.x new file mode 100644 index 00000000..23270fed --- /dev/null +++ b/sys/etc/urlget.x @@ -0,0 +1,384 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <ctype.h> +include <mach.h> +include <fset.h> + + +# HTTP error codes we care about + +define HTTP_OK 200 # Success +define HTTP_CREATED 201 # Created +define HTTP_ACCEPTED 202 # Accepted +define HTTP_PARTIAL 203 # Partial Information +define HTTP_NORESP 204 # No Response + +define HTTP_MOVED 301 # Moved +define HTTP_FOUND 302 # Found +define HTTP_SEEOTHER 303 # Method +define HTTP_NOTMOD 304 # Not Modified + +define HTTP_BADREQ 400 # Bad Request +define HTTP_UNAUTH 401 # Unauthorized +define HTTP_PAYMENT 402 # Payment Required +define HTTP_FORBIDDEN 403 # Forbidden +define HTTP_NOTFOUND 404 # Not Found + +define HTTP_INTERR 500 # Internal Error +define HTTP_NOTIMP 501 # Not Implemented +define HTTP_OVERLOAD 502 # Service Temporarily Overloaded +define HTTP_GWTIMEOUT 503 # Gateway Timeout + +define SZ_BUF 8192 # download buffer + +define DBG_HDRS FALSE + + + +# URL_GET -- Do an HTTP GET on the given URL, save the results to the named +# file. If a 'reply' pointer is given, return the request reply string (must +# be allocated at least SZ_PATHNAME). + +int procedure url_get (url, fname, reply) + +char url[ARB] #i URL to access +char fname[ARB] #i local filename +pointer reply #u pointer to reply string + +char protocol[SZ_FNAME], host[SZ_FNAME], path[SZ_BUF], emsg[SZ_PATHNAME] +char inurl[SZ_PATHNAME], outname[SZ_PATHNAME] +int port, stat +pointer buf + +int url_access(), strcmp() +bool url_redirect() + +define redirect_ 99 + +begin + # Breakup the URL into usable pieces. + call strcpy (url, inurl, SZ_PATHNAME) +redirect_ + call url_break (inurl, protocol, host, port, path) + + # Check for a supported protocol. + if (strcmp (protocol, "http") != 0) { + call aclrc (emsg, SZ_PATHNAME) + call sprintf (emsg, SZ_PATHNAME, "Unsupported URI protocol (%s)") + call pargstr (protocol) + call error (0, emsg) + } + + # Download the file to the given name + call strcpy (fname, outname, SZ_PATHNAME) + + if (reply == NULL) { + call calloc (buf, SZ_LINE, TY_CHAR) + stat = url_access (host, port, path, outname, buf) + if (url_redirect (stat, buf, inurl)) { # check for a redirection + call mfree (buf, TY_CHAR) + goto redirect_ + } + call mfree (buf, TY_CHAR) + + } else { + stat = url_access (host, port, path, outname, reply) + if (url_redirect (stat, reply, inurl)) # check for a redirection + goto redirect_ + } + + # URL Error Codes are returned as negative values, positive values + # are the number of bytes read. We let the caller decode the return + # value, if desired, using the url_errcode() procedure. + + return (stat) +end + + +# URL_REDIRECT -- Check for a redirection reply code and modify the URL so +# we can try again. + +bool procedure url_redirect (stat, reply, url) + +int stat #i status code +pointer reply #i pointer to reply string +char url[ARB] #u access url + +int code, loc +pointer ip, op +char inurl[SZ_LINE] + +int strsearch() +bool streq() + +begin + code = - stat + + if (code == HTTP_MOVED || code == HTTP_FOUND || code == HTTP_SEEOTHER) { + loc = strsearch (Memc[reply], "Location:") + if (loc > 0) { + call aclrc (inurl, SZ_LINE) + call strcpy (url, inurl, SZ_LINE) + for (ip=reply+loc; IS_WHITE(Memc[ip]); ip=ip+1) + ; + for (op=1; Memc[ip] != '\n'; op=op+1) { + url[op] = Memc[ip] + ip = ip + 1 + } + url[op-1] = EOS + + if (streq (inurl, url)) + return (FALSE) + + return (TRUE) + } + } + + return (FALSE) +end + + +# URL_BREAK -- Break the URL into components needed to make the netpath. + +procedure url_break (url, protocol, host, port, path) + +char url[SZ_BUF] #i url to parse +char protocol[ARB] #o URL protocol (only HTTP, for now) +char host[ARB] #o host name +int port #o server port (if specified, or 80) +char path[ARB] #o path part of URL, including args + +int i, nch, ip +int ctoi() + +begin + port = 80 # set default port number + + # Pull out the protocol part of the URL. + for (ip=1; url[ip] != ':'; ip = ip + 1) + protocol[ip] = url[ip] + protocol[ip] = '\0' + + # Skip the "://" separator. + while (url[ip] == ':' || url[ip] == '/') + ip = ip + 1 + + # Get the host name. + for (i=1; url[ip] != ':' && url[ip] != '/' && url[ip] != EOS; i=i+1) { + host[i] = url[ip] + ip = ip + 1 + } + host[i] = '\0' + + if (url[ip] == EOS) { + call strcpy ("/", path, 2) + return + } + + # Extract a port number of specified + if (url[ip] == ':') { + ip = ip + 1 + nch = ctoi (url, ip, port) + } + + # Get the remaining path. + for (i=1; url[ip] != EOS; i = i + 1) { + path[i] = url[ip] + ip = ip + 1 + } + path[i] = '\0' +end + + +# URL_ACCESS -- Do an HTTP GET of a resource to the named file. + +int procedure url_access (host, port, path, fname, reply) + +char host[ARB] #i host name +int port #i server port number +char path[ARB] #i resource path +char fname[ARB] #i saved file path +pointer reply #i reply buffer + +pointer rep +int in, out, nchars, totchars, retcode, clen, ip +char buf[SZ_BUF], netpath[SZ_PATHNAME], request[SZ_BUF], hd[SZ_PATHNAME] +bool done + +int open(), access(), ndopen(), getline(), read(), strlen(), ctoi() +int strncmp(), url_retcode() + +begin + # Connect to server on the given host. + call sprintf (netpath, SZ_PATHNAME, "inet:%d:%s:%s") + call pargi (port) + call pargstr (host) + call pargstr ("text") + + iferr (in = ndopen (netpath, READ_WRITE)) { + call eprintf ("cannot access host '%s:%d'\n") + call pargstr (host) + call pargi (port) + return (- HTTP_NOTFOUND) + } + + # Format the request header. + call aclrc (request, SZ_BUF) + call sprintf (request, SZ_BUF, "GET %s HTTP/1.0\n") + call pargstr (path) + call strcat ("Accept: */*\n", request, SZ_BUF) + call strcat ("User-Agent: IRAF/urlget\n", request, SZ_BUF) + call strcat ("Host: ", request, SZ_BUF) + call strcat ( host, request, SZ_BUF) + call strcat ("\n", request, SZ_BUF) + call strcat ("Connection: keep-alive\n\n", request, SZ_BUF) + + # Send the GET-url request to the server. + nchars = strlen (request) + call write (in, request, nchars) + call flush (in) + call fseti (in, F_CANCEL, OK) + + if (DBG_HDRS) { + call eprintf ("request [%d]:\n%s\n") + call pargi (nchars) + call pargstr (request) + } + + # Read the reply. Read the HTTP header assuming it ends with a \n or + # a \r\n. and then validate it will return the request correctly. + done = false + clen = -1 + call calloc (rep, SZ_PATHNAME, TY_CHAR) + repeat { + call aclrc (hd, SZ_PATHNAME) + nchars = getline (in, hd) + if (nchars <= 0) + break + call strcat (hd, Memc[rep], SZ_PATHNAME) + if (strncmp (hd, "Content-Length:", 15) == 0) { + ip = 16 + nchars = ctoi (hd, ip, clen) + } + } until ((hd[1] == '\r' && hd[2] == '\n') || (hd[1] == '\n')) + + if (DBG_HDRS) { + call eprintf ("reply: %s\nclen = %d\n") + call pargstr (Memc[rep]) + call pargi(clen) + } + + # Make sure we have a valid file. + retcode = url_retcode (Memc[rep]) + + if (reply != NULL) + call strcpy (Memc[rep], Memc[reply], SZ_PATHNAME) + call mfree (rep, TY_CHAR) + if (retcode != HTTP_OK) + return (- retcode) + + + # Open the named output file. + if (access (fname, 0, 0) == YES) + call syserrs (SYS_FCLOBBER, fname) + iferr (out = open (fname, NEW_FILE, TEXT_FILE)) + call syserrs (SYS_FOPEN, fname) + + # Now read the resource and save it to the named file. + totchars = 0 + done = false + repeat { + call aclrc (buf, SZ_BUF) + nchars = read (in, buf, SZ_BUF) + if (nchars > 0) { + call write (out, buf, nchars) + call flush (out) + totchars = totchars + nchars + done = false + } else + done = true + + if (clen > 0 && totchars >= clen) + break + } until (done) + + call close (in) # clean up + call close (out) + + return (totchars) # return number of chars read +end + + +# URL_RETCODE -- Get the return code from the HTTP header reply. + +int procedure url_retcode (reply) + +char reply[ARB] #i reply string + +int ip, len, code, ctoi() + +begin + for (ip=1; !IS_WHITE(reply[ip]); ip=ip+1) + ; + len = ctoi (reply, ip, code) + + return (code) +end + + +# URL_ERRCODE - Convert between an HTTP return code and the equivalent +# syserr() code value. + +int procedure url_errcode (code) + +int code #i http return code + +begin + # Note: Not all error codes are implemented in syserr. In this + # case we just return the input code. + + switch (code) { + case HTTP_OK: # Success + ; + case HTTP_CREATED: # Created + ; + case HTTP_ACCEPTED: # Accepted + ; + case HTTP_PARTIAL: # Partial Information + ; + case HTTP_NORESP: # No Response + ; + + case HTTP_MOVED: # Moved + return (SYS_URLREDIRECT); + case HTTP_FOUND: # Found + return (SYS_URLREDIRECT); + case HTTP_SEEOTHER: # See Other + return (SYS_URLREDIRECT); + case HTTP_NOTMOD: # Not Modified + ; + + case HTTP_BADREQ: # Bad Request + return (SYS_URLBADREQUEST) + case HTTP_UNAUTH: # Unauthorized + ; + case HTTP_PAYMENT: # Payment Required + ; + case HTTP_FORBIDDEN: # Forbidden + return (SYS_URLFORBIDDEN) + case HTTP_NOTFOUND: # Not Found + return (SYS_URLNOTFOUND) + + case HTTP_INTERR: # Internal Error + return (SYS_URLINTERROR) + case HTTP_NOTIMP: # Not Implemented + ; + case HTTP_OVERLOAD: # Service Temporarily Overloaded + ; + case HTTP_GWTIMEOUT: # Gateway Timeout + ; + } + + return (code) +end diff --git a/sys/etc/votable.x b/sys/etc/votable.x new file mode 100644 index 00000000..ec931030 --- /dev/null +++ b/sys/etc/votable.x @@ -0,0 +1,304 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <fio.h> +include <votParse_spp.h> + + +# VOTABLE.X -- Utility procedures for dealing with VOTables. + + +# VOTINIT -- Initialize the VOT struct, parse the document and save the +# summary. We return the VOT struct pointer itself, the caller is +# responsible for accessing the VOT_ROOT to get the raw root handle + +pointer procedure votinit (votable) + +char votable[ARB] #i VOTable file name + +pointer vot, vot_handle + +# Declare the libVOTable functions we'll be using. +int vx_openVOTABLE(), vx_getRESOURCE(), vx_getTABLE(), vx_getDATA() +int vx_getTABLEDATA(), vx_getFIELD(), vx_getINFO(), vx_getPARAM() +int vx_getNCols(), vx_getNRows(), vx_getLength() + +begin + # Allocate the structure. + call calloc (vot, SZ_VOT_STRUCT, TY_STRUCT) + + # Open and parse the votable. + vot_handle = vx_openVOTABLE (votable) + if (vot_handle <= 0) { + call eprintf ("Cannot open file: '%s'\n") + call pargstr (votable) + return (NULL) + } + VOT_ROOT(vot) = vot_handle + + # Now get various handles from the table. + VOT_RES(vot) = vx_getRESOURCE (vot_handle) + VOT_TAB(vot) = vx_getTABLE (VOT_RES(vot)) + VOT_DATA(vot) = vx_getDATA (VOT_TAB(vot)) + VOT_TDATA(vot) = vx_getTABLEDATA (VOT_DATA(vot)) + + VOT_INFO(vot) = vx_getINFO (VOT_RES(vot)) + VOT_PARAM(vot) = vx_getPARAM (VOT_RES(vot)) + VOT_FIELD(vot) = vx_getFIELD (VOT_TAB(vot)) + + VOT_NRES(vot) = vx_getLength (VOT_RES(vot)) + VOT_NCOLS(vot) = vx_getNCols (VOT_TDATA(vot)) + VOT_NROWS(vot) = vx_getNRows (VOT_TDATA(vot)) + + return (vot) # return the struct pointer +end + + +# VOTCLOSE -- Close the VOT struct and free any resources. + +procedure votclose (vot) + +pointer vot #i VOT struct pointer + +begin + call vx_closeVOTABLE (VOT_ROOT(vot)) + call mfree (vot, TY_STRUCT) +end + +# IS_VOTABLE -- Utility routine to determine if the named file is a VOTable +# XML document. + +define VOT_MAXLINES 10 + +bool procedure is_votable (fname) + +char fname[ARB] #i local filename + +int i, fd, nchars +bool stat +char buf[SZ_LINE] + +int open (), access (), getline (), strsearch () + +begin + stat = FALSE + + if (access (fname, 0, 0) == NO) + return (stat) + + iferr { + fd = open (fname, READ_ONLY, TEXT_FILE) + + # Look for a "<VOTABLE>" element in the first 10 lines of the file. + for (i=0; i < VOT_MAXLINES; i = i + 1) { + call aclrc (buf, SZ_LINE) + nchars = getline (fd, buf) + if (nchars == EOF) + break + + call strupr (buf) + if (strsearch (buf, "<VOTABLE") > 0) + stat = TRUE + } + call close (fd) + } then + stat = FALSE + + return (stat) +end + + +# VOT_CONVERT -- Convert a VOTable to some other format. + +define VOT_FMTS "|ascii|asv|bsv|csv|tsv|html|shtml|fits|xml|raw|votable" + +define ASCII 1 # ascii separated values +define ASV 2 # ascii separated values +define BSV 3 # bar separated values +define CSV 4 # comma separated values +define TSV 5 # tab separated values +define HTML 6 # standalone HTML document +define SHTML 7 # single HTML <table> element +define FITS 8 # FITS binary table +define XML 9 # VOTable alias +define RAW 10 # " " +define VOTBL 11 # " " + +int procedure vot_convert (in, out, fmt) + +char in[ARB] #i VOTable file name +char out[ARB] #i FITS bintable file name +char fmt[ARB] #i format name + +pointer sp, nodename, buf +char osfn[SZ_PATHNAME], cnvname[SZ_PATHNAME], format[SZ_LINE] +int vfd, status, ip, opt, delim, infile, outfile + +int vfnopen(), vfnmapu(), access(), ki_gnode(), strdic(), strncmp() +int open(), getline() +bool streq() + +begin + call smark (sp) + call salloc (nodename, SZ_FNAME, TY_CHAR) + call salloc (buf, SZ_LINE, TY_CHAR) + + + # Map input VFN to OSFN. + ip = 1 + if (strncmp (in, "http://", 7) == 0) { + call strcpy (in, osfn, SZ_PATHNAME) + } else { + vfd = vfnopen (in, READ_ONLY) + status = vfnmapu (vfd, osfn, SZ_PATHNAME) + call vfnclose (vfd, VFN_NOUPDATE) + + # If the file resides on the local node strip the node name, + # returning a legal host system filename as the result. + if (ki_gnode (osfn, Memc[nodename], delim) == 0) + ip = delim + 1 + } + + # Create a tempfile name for the converted output file. + call mktemp ("/tmp/vo", cnvname, SZ_PATHNAME) + call strcat (".", cnvname, SZ_PATHNAME) + call strcat (fmt, cnvname, SZ_PATHNAME) + + + # Validate the format. + opt = strdic (fmt, format, SZ_LINE, VOT_FMTS) + if (opt == 0) { + call eprintf ("Invalid output format '%s'\n") + call pargstr (fmt) + call sfree (sp) + return (ERR) + } + if (opt == VOTBL || opt == XML || opt == RAW) + call strcpy ("vot", format, SZ_FNAME) + if (opt == ASCII) + call strcpy ("asv", format, SZ_FNAME) + + + # Convert the file from VOTable to FITS bintable. + call vx_vocopy (5, "-f", format, "-o", cnvname, osfn[ip]) + + if (access (cnvname,0,0) == NO) { + call eprintf ("Cannot convert %s to '%s'\n") + call pargstr (osfn[ip]) + call pargstr (fmt) + return (ERR) + } + + # Delete the downloaded XML file, copy the bintable into its + # place and delete the converted output filename. + if (streq (in, out)) + call delete (in) + + + # Copy converted file to output file. Works for STDOUT/STDERR as + # well. + infile = open (cnvname, READ_ONLY, TEXT_FILE) + outfile = open (out, NEW_FILE, TEXT_FILE) + + while (getline (infile, Memc[buf]) != EOF) + call putline (outfile, Memc[buf]) + + call close (infile) + call close (outfile) + + call delete (cnvname) # delete the temporary converted file + call sfree (sp) + return (OK) +end + + +# VOT_TO_FITS -- Convert a VOTable to a FITS bintable. + +int procedure vot_to_fits (in, out) + +char in[ARB] #i VOTable file name +char out[ARB] #i FITS bintable file name + +pointer sp, nodename +char osfn[SZ_PATHNAME], cnvname[SZ_PATHNAME] +int vfd, status, ip, delim + +int vfnopen(), vfnmapu(), access(), ki_gnode() +bool streq() + +begin + call smark (sp) + call salloc (nodename, SZ_FNAME, TY_CHAR) + + # Map input VFN to OSFN. + vfd = vfnopen (in, READ_ONLY) + status = vfnmapu (vfd, osfn, SZ_PATHNAME) + call vfnclose (vfd, VFN_NOUPDATE) + + # If the file resides on the local node strip the node name, + # returning a legal host system filename as the result. + if (ki_gnode (osfn, Memc[nodename], delim) == 0) + ip = delim + 1 + else + ip = 1 + + + # Create a tempfile name for the converted output file. + call mktemp ("/tmp/vo", cnvname, SZ_PATHNAME) + call strcat (".fits", cnvname, SZ_PATHNAME) + + # Convert the file from VOTable to FITS bintable. + call vx_vocopy (5, "-f", "fits", "-o", cnvname, osfn[ip]) + + if (access (cnvname,0,0) == NO) + return (ERR) + + # Delete the downloaded XML file, copy the bintable into its + # place and delete the converted output filename. + if (streq (in, out)) + call delete (in) + + call fcopy (cnvname, out) # copy converted file to output file + call delete (cnvname) # delete the temporary converted file + + call sfree (sp) + + return (OK) +end + + +# VOT_FROM_FITS -- Convert from a FITS bintable to a VOTable. + +int procedure vot_from_fits (in, out) + +char in[ARB] #i FITS bintable file name +char out[ARB] #i VOTable file name + +char osfn[SZ_PATHNAME], cnvname[SZ_PATHNAME] +int vfd, status + +int vfnopen(), vfnmapu() +bool streq() + +begin + # Map input VFN to OSFN. + vfd = vfnopen (in, READ_ONLY) + status = vfnmapu (vfd, osfn, SZ_PATHNAME) + call vfnclose (vfd, VFN_NOUPDATE) + + # Create a tempfile name for the converted output file. + call mktemp ("/tmp/vo", cnvname, SZ_PATHNAME) + call strcat (".xml", cnvname, SZ_PATHNAME) + + # Convert the file from VOTable to FITS bintable. + call vx_vocopy (5, "-f", "votable", "-o", cnvname, osfn) + + # Delete the downloaded XML file, copy the bintable into its + # place and delete the converted output filename. + if (streq (in, out)) + call delete (in) + + call fcopy (cnvname, out) # copy converted file to output file + call delete (cnvname) # delete the temporary converted file + + return (OK) +end diff --git a/sys/etc/xalloc.x b/sys/etc/xalloc.x new file mode 100644 index 00000000..63be577a --- /dev/null +++ b/sys/etc/xalloc.x @@ -0,0 +1,197 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <xalloc.h> +include <syserr.h> +include <ctype.h> +include <knet.h> + +.helpsys xalloc +.nf _________________________________________________________________________ +XALLOC -- Device allocation package. + + xallocate (device) + xdeallocate (device, rewind) + xdevowner (device, owner, maxch) + xdevstatus (device, out) + xgdevlist (device, devlist, maxch, onedev) + +status: + + DV_DEVFREE device is free and can be allocated + DV_DEVALLOC device is already allocated + DV_DEVINUSE device is in use by someone else + DV_DEVNOTFOUND device is not in device table + +The allocatable devices are defined in the text file dev$tapecap. +.endhelp ____________________________________________________________________ + +define SZ_DEVLIST 256 +define ALLOCATE 1 +define DEALLOCATE 0 + + +# XALLOCATE -- Attempt to allocate the named device, i.e., allocate the device +# for exclusive i/o, and ready it for i/o following some sort of OPEN call. +# Allocate performs the function called "mount" on some systems, as well as +# allocating the device. + +int procedure xallocate (device) + +char device[ARB] #I device to be allocated + +pointer sp, devlist +int status, onedev +int xgdevlist(), mtfile() +errchk xgdevlist, mtallocate +define done_ 91 + +begin + call smark (sp) + call salloc (devlist, SZ_DEVLIST, TY_CHAR) + + # Fetch the device list for the named device. + onedev = NO + status = xgdevlist (device, Memc[devlist], SZ_DEVLIST, onedev) + if (status != OK) + goto done_ + + # Attempt to allocate the device at the host system level. + call strpak (Memc[devlist], Memc[devlist], SZ_DEVLIST) + call zdvall (Memc[devlist], ALLOCATE, status) + + # If that worked and the device is a magtape, call MTIO to complete + # the allocation process. + + if (status == OK && mtfile (device) == YES) + call mtallocate (device) +done_ + call sfree (sp) + return (status) +end + + +# XDEALLOCATE -- Deallocate the named device. + +int procedure xdeallocate (device, rewind) + +char device[ARB] #I device to be deallocated +int rewind #I rewind if magtape? + +int status, onedev +pointer sp, devlist, osdev, owner +int xgdevlist(), mtfile() +errchk xgdevlist, syserrs +define done_ 91 + +begin + call smark (sp) + call salloc (devlist, SZ_DEVLIST, TY_CHAR) + call salloc (osdev, SZ_FNAME, TY_CHAR) + call salloc (owner, SZ_FNAME, TY_CHAR) + + # Get the i/o device name. + onedev = YES + status = xgdevlist (device, Memc[osdev], SZ_FNAME, onedev) + if (status != OK) + goto done_ + + # Verify that the device is actually allocated. If the device is a + # magtape, call MTIO to conditionally rewind the drive and deallocate + # the drive in MTIO. + + call strpak (Memc[osdev], Memc[osdev], SZ_FNAME) + call zdvown (Memc[osdev], Memc[owner], SZ_FNAME, status) + if (status != DV_DEVALLOC) + call syserrs (SYS_MTNOTALLOC, device) + else if (mtfile (device) == YES) + call mtdeallocate (device, rewind) + + # Fetch the device list for the named device. + onedev = NO + status = xgdevlist (device, Memc[devlist], SZ_DEVLIST, onedev) + if (status != OK) + goto done_ + + # Physically deallocate the device. + call strpak (Memc[devlist], Memc[devlist], SZ_DEVLIST) + call zdvall (Memc[devlist], DEALLOCATE, status) +done_ + call sfree (sp) + return (status) +end + + +# XDEVSTATUS -- Print the status of the named device on the output file. + +procedure xdevstatus (device, out) + +char device[ARB] #I device +int out #I output file + +int status +char owner[SZ_FNAME] +int xdevowner(), mtfile() +errchk xdevowner, mtfile + +begin + status = xdevowner (device, owner, SZ_FNAME) + + switch (status) { + case DV_DEVFREE: + call fprintf (out, "device %s is not currently allocated\n") + call pargstr (device) + if (mtfile (device) == YES) + iferr (call mtstatus (out, device)) + ; + case DV_DEVINUSE: + call fprintf (out, "device %s is currently allocated to %s\n") + call pargstr (device) + call pargstr (owner) + case DV_DEVALLOC: + if (mtfile (device) == YES) + call mtstatus (out, device) + else { + call fprintf (out, "device %s is allocated\n") + call pargstr (device) + } + default: + call fprintf (out, "cannot get device status for `%s'\n") + call pargstr (device) + } +end + + +# XDEVOWNER -- Determine whether or not the named device is already +# allocated, and if the device is currently allocated to someone else, +# return the owner name. + +int procedure xdevowner (device, owner, maxch) + +char device[ARB] #I device to be deallocated +char owner[maxch] #O receives owner name +int maxch #I max chars out + +pointer sp, devlist +int status, onedev +int xgdevlist() +errchk xgdevlist +define done_ 91 + +begin + call smark (sp) + call salloc (devlist, SZ_DEVLIST, TY_CHAR) + + # Fetch the device list for the named device. + onedev = YES + status = xgdevlist (device, Memc[devlist], SZ_DEVLIST, onedev) + if (status != OK) + goto done_ + + # Query device allocation. + call strpak (Memc[devlist], Memc[devlist], SZ_DEVLIST) + call zdvown (Memc[devlist], owner, maxch, status) + call strupk (owner, owner, maxch) +done_ + call sfree (sp) + return (status) +end diff --git a/sys/etc/xerfmt.x b/sys/etc/xerfmt.x new file mode 100644 index 00000000..596e6ce5 --- /dev/null +++ b/sys/etc/xerfmt.x @@ -0,0 +1,96 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <ctype.h> + +# XER_FMTERRMSG -- Expand error message encoded as "123 user_string" into +# a full error message by looking the error message string up in lib$syserrmsg. +# If the first character of ERRMSG is nonnumeric no processing is done. +# The conversion may be performed in place, i.e., errmsg and outstr may be +# the same array. + +procedure xer_fmterrmsg (errmsg, outstr, maxch) + +char errmsg[ARB] # encoded error message. +char outstr[maxch] # output string +int maxch + +char buf[SZ_LINE], user_string[SZ_FNAME] +int codelen, nchars, chan, ip, op, junk +int strncmp(), envfind(), gstrcpy() +define nofile_ 91 + +begin + # Determine ndigits in error code. + for (ip=1; IS_DIGIT (errmsg[ip]); ip=ip+1) + ; + codelen = ip - 1 + + # Output message as is if no error code. Copy into local buf first + # in case errmsg and outstr overlap. + + if (codelen == 0) { + call strcpy (errmsg, buf, SZ_LINE) + call strcpy (buf, outstr, maxch) + return + } + + # Extract the user string into a local buffer. + while (IS_WHITE (errmsg[ip])) + ip = ip + 1 + for (op=1; errmsg[ip] != EOS && errmsg[ip] != '\n'; ip=ip+1) { + user_string[op] = errmsg[ip] + op = op + 1 + } + user_string[op] = EOS + + # Generate the OS pathname of the "lib$syserrmsg" file. + if (envfind ("iraf", buf, SZ_LINE) > 0) { + call zfsubd (buf, SZ_LINE, "lib", nchars) + call strcat ("syserrmsg", buf, SZ_LINE) + call strpak (buf, buf, SZ_LINE) + } else + goto nofile_ + + # Open and search the system error message file. + call zopntx (buf, READ_ONLY, chan) + if (chan == ERR) + goto nofile_ + + repeat { + call zgettx (chan, buf, SZ_LINE, nchars) + if (nchars == 0 || nchars == ERR) { + call zclstx (chan, junk) + goto nofile_ + } else if (strncmp (buf, errmsg, codelen) == 0) { + call zclstx (chan, junk) + break + } + } + + # Skip the error code prefix and the blank which follows. + for (ip=codelen+1; IS_WHITE(buf[ip]); ip=ip+1) + ; + + # Output system error message. + for (op=1; buf[ip] != '\n' && buf[ip] != EOS; ip=ip+1) { + outstr[op] = buf[ip] + op = op + 1 + } + + # Add user operand, if supplied, enclosed in parens. + if (user_string[1] != EOS) { + outstr[op] = ' ' + outstr[op+1] = '(' + op = op + 2 + op = op + gstrcpy (user_string, outstr[op], maxch-op+1) + outstr[op] = ')' + op = op + 1 + } + + outstr[op] = EOS + return + +nofile_ + call strcpy (errmsg, buf, SZ_LINE) + call strcpy (buf, outstr, maxch) +end diff --git a/sys/etc/xerpop.x b/sys/etc/xerpop.x new file mode 100644 index 00000000..a4723508 --- /dev/null +++ b/sys/etc/xerpop.x @@ -0,0 +1,55 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <error.h> + +# XERPSH -- Push an error handler on the error "stack". All we really need +# do is keep track of the number of nested handlers. If an error condition +# already exists when we are called, an error has occurred which was not +# caught, probably because of a missing errchk declaration. + +procedure xerpsh() + +include "error.com" + +begin + if (xerflg) # error not caught + call erract (EA_FATAL) + nhandlers = nhandlers + 1 + xercod = OK +end + + +# XERPOP -- Pop an error handler, and return the error status flag (true if +# an error occurred). + +bool procedure xerpop() + +bool error_status +include "error.com" + +begin + nhandlers = nhandlers - 1 + error_status = xerflg + xerflg = false + + return (error_status) +end + + +# XERPOPI -- Integer version of XERPOP. + +int procedure xerpopi() + +bool error_status +include "error.com" + +begin + nhandlers = nhandlers - 1 + error_status = xerflg + xerflg = false + + if (error_status) + return (1) + else + return (0) +end diff --git a/sys/etc/xerpue.x b/sys/etc/xerpue.x new file mode 100644 index 00000000..9cc995ee --- /dev/null +++ b/sys/etc/xerpue.x @@ -0,0 +1,32 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> +include <mach.h> +include <fio.h> + +# XER_PUTLINE -- Put a line to the output file (STDERR), using only low level +# routines. It is important to use run time indirection through the device +# table here, to avoid linking the entire IPC and KI into non-IRAF programs +# that use error handlers, e.g., HSI or IMFORT programs. + +procedure xer_putline (fd, text) + +int fd +char text[ARB] + +long offset +int nchars, junk +int strlen() +include <fio.com> + +begin + nchars = strlen (text) + fp = fiodes[fd] + + if (FTYPE(fp) == BINARY_FILE) { + offset = 0 + call zcall4 (ZAWRBF(fp), FCHAN(fp), text, nchars * SZB_CHAR, offset) + call zcall2 (ZAWTBF(fp), FCHAN(fp), junk) + } else + call zcall4 (ZPUTTX(fp), FCHAN(fp), text, nchars, junk) +end diff --git a/sys/etc/xerreset.x b/sys/etc/xerreset.x new file mode 100644 index 00000000..773e38f9 --- /dev/null +++ b/sys/etc/xerreset.x @@ -0,0 +1,19 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <error.h> + +# XER_RESET -- Called to initialize error handling. Used during startup and +# during error recovery (e.g. in an interrupt handler) to reset the state of +# the error handling code. + +procedure xer_reset() + +include "error.com" + +begin + xerflg = false + xercod = OK + err_restart = NO + nhandlers = 0 + xermsg[1] = EOS +end diff --git a/sys/etc/xerstmt.x b/sys/etc/xerstmt.x new file mode 100644 index 00000000..0a28167b --- /dev/null +++ b/sys/etc/xerstmt.x @@ -0,0 +1,66 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <error.h> +include <ctype.h> + +define SZ_NUMBUF 6 + +# XERSTMT -- Format and issue an error statement to the CL. Note that this is +# a command issued to the CL, not a line written to STDERR. The error code and +# error message string output were posted in the last call to ERROR or FATAL. +# +# Example: ERROR (501, "Access Violation") +# +# The actual concatentation and transmission of the error message is carried +# out by the primitive XERPUTC, rather than by PUTLINE and PUTC calls to CLOUT, +# to avoid recursion in the FIO routines, probably leading to error recursion. + +procedure xer_send_error_statement_to_cl (errcode) + +int errcode +char numbuf[SZ_NUMBUF] +int ip, junk, itoc() +include "error.com" + +begin + # The error code is passed as an argument rather than taken from the + # xercom common because XERPOP clears the error code before we are + # called by the IRAF Main. + + junk = itoc (errcode, numbuf, SZ_NUMBUF) + + # Format the ERROR statement and sent it to the CL. + + call xerpstr ("ERROR (") + call xerpstr (numbuf) + call xerpstr (", \"") + + # Output error message string, omitting characters like newline or + # quote which could cause syntax problems. + + for (ip=1; xermsg[ip] != EOS; ip=ip+1) + if (IS_PRINT (xermsg[ip]) && xermsg[ip] != '"') + call xerputc (xermsg[ip]) + + # Ring terminal bell if unexpected error (anything other than + # a keyboard interrupt). + + if (xercod != SYS_XINT) + call xerpstr ("\7") + call xerpstr ("\")\n") +end + + +# XERPSTR -- Put a string to the CL (special routine, to avoid recursion). +# Use PUTLINE in normal code. + +procedure xerpstr (str) + +char str[ARB] +int ip + +begin + for (ip=1; str[ip] != EOS; ip=ip+1) + call xerputc (str[ip]) +end diff --git a/sys/etc/xerverify.x b/sys/etc/xerverify.x new file mode 100644 index 00000000..dfb4e88a --- /dev/null +++ b/sys/etc/xerverify.x @@ -0,0 +1,21 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <error.h> + +# XER_VERIFY -- The following procedure is called by the iraf main after +# a task completes, to verify that NHANDLERS is zero, indicating that an XERPOP +# was executed for each XERPSH. Note that a transfer out of an IFERR block +# (a programming error) could prevent XERPOP from being called. + +procedure xer_verify() + +include "error.com" + +begin + if (xerflg) + call erract (EA_FATAL) + if (nhandlers != 0) { + nhandlers = 0 + call putline (STDERR, "Warning: Transfer out of IFERR block\n") + } +end diff --git a/sys/etc/xgdevlist.x b/sys/etc/xgdevlist.x new file mode 100644 index 00000000..d20b68a9 --- /dev/null +++ b/sys/etc/xgdevlist.x @@ -0,0 +1,49 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <syserr.h> +include <xalloc.h> + +# XGDEVLIST -- Fetch the allocation string for the named logical device from +# the device table (tapecap file). DV_DEVNOTFOUND is returned there is no +# entry in the device table for the device. An error action is taken if there +# is any problem reading the device entry. +# +# This routine is a bit of an anachronism in the days of tapecap, but is +# left pretty much as it was originally to minimize code modifications. +# In principle the allocation code can be used to allocate any device, not +# just tape drives. This is still the case, given an entry for the device +# in the tapecap file. + +int procedure xgdevlist (device, outstr, maxch, onedev) + +char device[ARB] #I logical device name +char outstr[maxch] #O receives device list +int maxch #I max chars out +int onedev #I return i/o device instead? + +pointer gty +int nchars +pointer mtcap() +int gtygets(), strlen() +errchk syserrs + +begin + # Fetch the tapecap entry for the named device. Do not close the GTY + # descriptor. mtcap always keeps the last one in an internal cache. + + iferr (gty = mtcap (device)) + return (DV_DEVNOTFOUND) + + if (onedev == YES) + nchars = gtygets (gty, "dv", outstr, maxch) + else + nchars = gtygets (gty, "al", outstr, maxch) + + call ki_xnode (device, outstr, maxch) + nchars = strlen (outstr) + + if (nchars <= 0) + call syserrs (SYS_MTTAPECAP, device) + + return (OK) +end diff --git a/sys/etc/xisatty.x b/sys/etc/xisatty.x new file mode 100644 index 00000000..177bec67 --- /dev/null +++ b/sys/etc/xisatty.x @@ -0,0 +1,38 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <clset.h> +include <fset.h> + +# XISATTY -- Test if the given file is a terminal. + +int procedure xisatty (fd) + +int fd # file descriptor of candidate device +int epa, epa_tt, epa_ty +extern zgettt(), zgetty() +int fstati(), clstati() + +begin + # If we are a connected subprocess, the referenced file is a standard + # stream, and i/o has not been redirected, assume that the file behaves + # as a terminal. + + if (clstati(CL_PRTYPE) == PR_CONNECTED) + if (fd == STDIN || fd == STDOUT || fd == STDERR) + if (fstati (fd, F_REDIR) == NO) + return (YES) + else + return (NO) + + # Otherwise, the use of the terminal driver tells us if the file is + # open on a terminal device. + + epa = fstati (fd, F_DEVICE) + call zlocpr (zgettt, epa_tt) + call zlocpr (zgetty, epa_ty) + + if (epa == epa_tt || epa == epa_ty) + return (YES) + else + return (NO) +end diff --git a/sys/etc/xmjbuf.x b/sys/etc/xmjbuf.x new file mode 100644 index 00000000..45585060 --- /dev/null +++ b/sys/etc/xmjbuf.x @@ -0,0 +1,20 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <config.h> + +# XMJBUF -- Return a char pointer to the IRAF main interpreter context restart +# buffer (for ZDOJMP restarts). + +procedure xmjbuf (bp) + +pointer bp #O pointer to jumpbuf + +int a_jb, a_mem +int jumpbuf[LEN_JUMPBUF] +common /JUMPCOM/ jumpbuf + +begin + call zlocva (jumpbuf[1], a_jb) + call zlocva (Memc, a_mem) + bp = a_jb - a_mem + 1 +end diff --git a/sys/etc/xttysize.x b/sys/etc/xttysize.x new file mode 100644 index 00000000..4c95056e --- /dev/null +++ b/sys/etc/xttysize.x @@ -0,0 +1,51 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <clset.h> + +# XTTYSIZE -- Query the size of the terminal screen in characters. This is +# different than simply reading the screen size from the environment or from +# termcap, because the screen size will be queried at runtime if the terminal +# has a screen which can change size at runtime. Note that when this routine +# is called, the variables ttyncols and ttynlines are updated in the IRAF +# environment, allowing ordinary envgeti calls to be used thereafter to query +# the screen size. The XTTYSIZE routine should not be called all over the +# place, because it may involve i/o to the terminal. + +procedure xttysize (width, height) + +int width # width of screen (out) +int height # height of screen (out) + +int junk, i +pointer sp, buf, tty +pointer ttyodes() +int clstati(), getline(), envgeti(), envscan() +errchk clcmd, getline, envgeti, ttyodes + +begin + call smark (sp) + call salloc (buf, SZ_LINE, TY_CHAR) + + # If we are a connected subprocess it is difficult to write directly + # to the terminal, since the terminal is opened by the CL. Hence we + # have the CL run the STTY task instead to reset the screen size + # parameters in the environment. If we are not a connected subprocess + # we query the terminal size directly, assuming that the terminal is + # opened on the process standard input and output. + + if (clstati (CL_PRTYPE) == PR_CONNECTED) { + call clcmd ("stty resize") + do i = 1, 2 + if (getline (CLIN, Memc[buf]) != EOF) + junk = envscan (Memc[buf]) + width = envgeti ("ttyncols") + height = envgeti ("ttynlines") + + } else { + tty = ttyodes ("terminal") + call ttygsize (STDIN, STDOUT, tty, width, height) + call ttycdes (tty) + } + + call sfree (sp) +end diff --git a/sys/etc/xwhen.x b/sys/etc/xwhen.x new file mode 100644 index 00000000..948eca8f --- /dev/null +++ b/sys/etc/xwhen.x @@ -0,0 +1,13 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +# XWHEN -- Post an exception handler. + +procedure xwhen (signal, handler, old_handler) + +int signal # signal to be caught +int handler # epa of user supplied exception handler +int old_handler # epa of old handler, if any + +begin + call zxwhen (signal, handler, old_handler) +end diff --git a/sys/etc/zzdebug.x b/sys/etc/zzdebug.x new file mode 100644 index 00000000..05324872 --- /dev/null +++ b/sys/etc/zzdebug.x @@ -0,0 +1,404 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <fset.h> +include <chars.h> + +# Debug the ENVIRON environment list package. The following definitions are +# from the header of "environ.x" and are used by envdebug to examine the +# environment list data structures; these should be compared to the defs in +# environ.x to make sure they agree. Use of a header file is not warranted +# since we really do not want the environ.x data structures known outside +# the package. + +task get = t_get, + put = t_put, + list = t_list, + mark = t_mark, + free = t_free, + debug = t_debug, + spawn = t_spawn, + edit = t_edit, + tty = t_tty, + urlget = t_urlget + + +# Strings may optionally be quoted in SET stmts with either ' or ". +define IS_QUOTE ($1 == '\'' || $1 == '"') + +# Size limiting definitions. + +define NTHREADS 100 # number of hash threads +define HASH_FACTOR 1637 # divisor for hash function +define NHASHCHARS 6 # no. chars used for hashing +define LEN_ENVBUF 1500 # storage for environment list +define INC_ENVBUF 500 # increment if overflow occurs +define MAX_SZKEY 32 # max chars in a key +define MAX_SZVALUE 80 # max chars in value string +define MAX_LENLISTELEM (3+(MAX_SZKEY+1+MAX_SZVALUE+1+SZ_SHORT-1)/SZ_SHORT) + +# List element structure, stored in ENVBUF, which is allocated as an array of +# type SHORT integer. Each list element is aligned on a short integer boundary +# within the array. E_NEXT points to the next element in a thread, whereas +# E_LASTELEM points to the last element in the envbuf (which is a stack). + +define E_NEXT Mems[$1] # next element in thread (list) +define E_LASTELEM Mems[$1+1] # next element in envbuf +define E_REDEF Mems[$1+2] # set if element is redefined +define E_SETP P2C($1+3) # char pointer to name field +define E_SET Memc[E_SETP($1)] # "name=value" string +define E_SETOFFSET 3 + + +# GET -- Lookup the definition of an environment variable. + +procedure t_get() + +char name[SZ_FNAME] +char value[SZ_LINE] +int envgets() + +begin + call clgstr ("name", name, SZ_FNAME) + if (envgets (name, value, SZ_LINE) <= 0) { + call printf ("%s not found\n") + call pargstr (name) + } else { + call printf ("%s = %s\n") + call pargstr (name) + call pargstr (value) + } +end + + +# PUT -- Enter a new environment variable or list of variables into the +# environment list. Enter "stmt: set name=value" to enter a single variable, +# or "stmt: set @filename" to process set statements from a file. + +procedure t_put() + +char stmt[SZ_LINE] +int envscan() + +begin + call clgstr ("statement", stmt, SZ_LINE) + call printf ("%d set statements processed\n") + call pargi (envscan (stmt)) +end + + +# LIST -- Print the environment list. + +procedure t_list() + +bool clgetb() +int btoi() + +begin + call envlist (STDOUT, " ", btoi (clgetb ("show_redefs"))) +end + + +# MARK -- Mark the end of the environment list for later restoration by +# the FREE task. + +procedure t_mark() + +int top +common /xxx/ top + +begin + call envmark (top) + call printf ("top = %d\n") + call pargi (top) +end + + +# FREE -- Free the environment list back to the last position marked. + +procedure t_free() + +int top +int envfree() +common /xxx/ top + +begin + call printf ("free uncovers %d redefs\n") + call pargi (envfree (top, 0)) +end + + +# DEBUG -- Print the internal data structures (the hash table) of the +# environment list package. + +procedure t_debug() + +begin + call envdebug (STDOUT) +end + + +# ENVDEBUG -- Print the contents of the environment list data structures for +# debugging the code. + +procedure envdebug (fd) + +int fd # output file +int i, t, head +pointer el, ep +include "environ.com" + +begin + call fprintf (fd, "envbuf at %d, len %d, last=%d, top=%d, %d%% full\n") + call pargi (envbuf) + call pargi (len_envbuf) + call pargi (last) + call pargi (top) + call pargr (real(top) / real(len_envbuf) * 100.0) + + for (t=1; t <= NTHREADS; t=t+1) { + call fprintf (fd, "%6d"); call pargi (t) + head = threads[t] + if (head != NULL) + for (i=head; i != NULL; i=E_NEXT(el)) { + el = envbuf + i + call putci (fd, ' ') + for (ep=E_SETP(el); Memc[ep] != '='; ep=ep+1) + call putc (fd, Memc[ep]) + } + call putci (fd, '\n') + } +end + + +# SPAWN -- Spawn a connected subprocess. Used to test process control and +# interprocess communication. + +procedure t_spawn() + +char process[SZ_FNAME] +char lbuf[SZ_LINE] +int in, out, pid +int prgetline(), propen(), prclose(), strmatch() +define done_ 91 + +begin + call clgstr ("process", process, SZ_FNAME) + pid = propen (process, in, out) + + call putline (STDERR, "-> ") + call flush (STDERR) + + while (prgetline (STDIN, lbuf) != EOF) { + if (strmatch (lbuf, "^bye") > 0) + break + else { + call putline (out, lbuf) + call flush (out) + } + + while (prgetline (in, lbuf) != EOF) { + call putline (STDERR, lbuf) + + if (strmatch (lbuf, "^bye") > 0) + break + else { + call putline (STDERR, ">> ") + call flush (STDERR) + if (prgetline (STDIN, lbuf) == EOF) + goto done_ + call putline (out, lbuf) + } + + call flush (STDERR) + call flush (out) + } + + call putline (STDERR, "------------\n") + call putline (STDERR, "-> ") + call flush (STDERR) + } + +done_ + call putline (STDERR, "\n") + call eprintf ("termination code %d\n") + call pargi (prclose (pid)) +end + + +# EDIT -- Test raw mode to a terminal. + +procedure t_edit() + +char lbuf[SZ_LINE], temp[SZ_LINE], ch +int i, stdline + +char getchar() +int envgets(), ttygeti() +pointer tty, ttyodes() +define accum_ 91 +define done_ 92 + +begin + # Set terminal to raw mode. + call fseti (STDIN, F_RAW, YES) + + # Open termcap for terminal. + if (envgets ("terminal", lbuf, SZ_LINE) <= 0) + call strcpy ("vt100", lbuf, SZ_LINE) + tty = ttyodes (lbuf) + stdline = ttygeti (tty, "li") + + # Edit loop. The variable I is the character position within the + # line. Start out in insert mode, with line displayed at bottom + # of terminal screen. + + lbuf[1] = EOS + i = 1 + call ttygoto (STDOUT, tty, 1, stdline) + call flush (STDOUT) + goto accum_ + + while (getchar (ch) != EOF) { + switch (ch) { + + case 'h': + # Move left one column. + if (i <= 1) + call putci (STDOUT, BEL) + else { + call putci (STDOUT, BS) + i = i - 1 + } + + case 'l': + # Move right one column. + if (lbuf[i+1] == EOS) + call putci (STDOUT, BEL) + else { + call putc (STDOUT, lbuf[i]) + i = i + 1 + } + + case 'x': + # Delete a character. + call strcpy (lbuf[i+1], lbuf[i], SZ_LINE-i+1) + call putline (STDOUT, lbuf[i]) + call putci (STDOUT, BLANK) + call ttygoto (STDOUT, tty, i, STDLINE) + + if (i > 1 && lbuf[i] == EOS) { + call putci (STDOUT, BS) + i = i - 1 + } + + case 'i': + # Insert a character. +accum_ + while (getchar (ch) != ESC) { + call putc (STDOUT, ch) + if (ch == '\r') + goto done_ + + # Insert char in line buffer. + call strcpy (lbuf[i], temp, SZ_LINE) + lbuf[i] = ch + i = i + 1 + call strcpy (temp, lbuf[i], SZ_LINE-i+1) + + # Redraw right portion of line. + call putline (STDOUT, lbuf[i]) + call ttygoto (STDOUT, tty, i, STDLINE) + call flush (STDOUT) + } + + if (i > 1) { + call putci (STDOUT, BS) + i = i - 1 + } + + case '\f': + # Redraw line. + call printf ("\r%s") + call pargstr (lbuf) + call ttygoto (STDOUT, tty, i, STDLINE) + + case '\r': + break + + default: + call putci (STDOUT, BEL) + } + + call flush (STDOUT) + } + +done_ + call fseti (STDIN, F_RAW, NO) + call putci (STDOUT, '\n') + call ttycdes (tty) +end + + +# TTY -- Test direct terminal i/o. + +procedure t_tty() + +int in, out, ch +int ttopen(), getci() +bool clgetb() + +begin + if (clgetb ("dualstreams")) { + in = ttopen ("dev$tty", READ_ONLY) + out = ttopen ("dev$tty", WRITE_ONLY) + } else { + in = ttopen ("dev$tty", READ_WRITE) # NOT SUPPORTED + out = in + } + + call fseti (in, F_RAW, YES) + while (getci (in, ch) > 0) { + call fprintf (out, "%c\r\n") + call pargi (ch) + call flush (out) + if (ch == EOFCHAR) + break + } + + if (in == out) + call close (in) + else { + call close (out) + call close (in) + } +end + + +# URL_GET -- Do an HTTP GET of a URL + +procedure t_urlget () + +pointer reply +char url[SZ_LINE], fname[SZ_FNAME] +bool hdr +int nread + +int url_get() + +begin + call clgstr ("url", url, SZ_LINE) # get the parameters + call clgstr ("fname", fname, SZ_FNAME) + hdr = clgetb ("hdr") + + call calloc (reply, SZ_LINE, TY_CHAR) + + nread = url_get (url, fname, reply) + + call eprintf ("File '%s', downloaded %d bytes.\n") + call pargstr (fname) + call pargi (nread) + + if (hdr) + call eprintf (Memc[reply]) + call mfree (reply, TY_CHAR) +end |