.nf ECL: Enhanced CL Release Notes and User's Guide ================================================ Michael Fitzpatrick NOAO/IRAF Group 12/12/04 Revised: 5/28/05 ******************************************************************************** Release History: 02/10/05 ** Alpha Release for testing 05/06/05 ** 2nd Alpha Release for testing 06/07/05 ** 1st Beta Release for testing ******************************************************************************** Table of Contents ----------------- Introduction Installation and Use To Install the CL Determine CL Version Type Error Handling Introduction and Cautions Example Descriptions Reporting Errors Traceback Trapping Errors The 'iferr' Syntax The 'erract' Environment Variable Error Handling: Then and Now New CL parameters What Errors Are NOT Trapped Command-line History and BackSpace Revisions Input Command Summary New Builtin Functions and Variables Error Functions String Functions Trig Functions Utility Functions Bitwise Operations Defined Constants Post-Release Notes ******************************************************************************** ============ Introduction ============ The primary goals of the ECL project were to o add an error-handling capability to the existing IRAF CL, o include other functionality which could improve the scripting environment (e.g. pre-defined language constants such as 'PI') and add any other features we found lacking (e.g. missing trig functions and string utilities), and o add commonly requested features. Where possible, small enhancements such as a new utility builtin function will be implemented in the "old" CL as well, however as scripts begin to use the more advanced features scripts will naturally become less backward compatible. Future work will build on the version presented here with the hope that users will migrate to the new system over a short time. This is a work in progress. Users are encouraged to experiment with features, request future enhancements, and to please report any errors or problems to iraf@noao.edu New releases will be announced on the IRAF website (http://iraf.noao.edu) following the addition of any new features or when critical bugs have been fixed. ==================== Installation and Use ==================== The ECL is being distributed in a self-extracting script file rather than the traditional IRAF external package since it is meant to overlay an existing IRAF system until the time when it becomes part of the core distribution. Since the script creates a new command link in the unix system "local bin directory" and adds files to the IRAF source tree, it MUST be run as the root user (the script will terminate or ask if you wish to proceed with a no-op installation otherwise). The installation script does the following to your system: 1) Replaces the existing hlib$cl.csh script with a modified version after creating a hlib$cl.csh.ORIG backup file 2) Creates an "ecl" command link in the same directory as the current "cl" IRAF command link. Both links point to the same hlib$cl.csh script which checks for how it was called an invokes the proper binary. 3) Moves the "ecl.e" binary to the proper iraf$bin. directory, changing the ownership to the 'iraf' user and setting the execute permissions on the file. 4) Creates a iraf$pkg/ecl directory and moves all ECL sources there. The install script may be run from any directory on the system, it is unpacked in /tmp and cleans up temp files when complete. A "personal installation" option is not implemented at this time but could be considered later for users who don't have write permission on their IRAF tree. Please contact iraf@noao.edu for instructions on how to manually setup such a system for personal use. To Install the ECL ------------------ Step 1) Download the distribution file appropriate for your system. For example, % ftp iraf.noao.edu (140.252.1.1) login: anonymous password: [your email address] ftp> cd pub ftp> binary ftp> get ecl_install_redhat.csh ftp> quit Step 2) Execute the script AS ROOT: % su # become the root user # ./ecl_install_redhat.csh The script will prompt you for the local bin directory or any iraf paths needed, simply accept the default values determined for your system or override them with others. Once executed, the ECL source and binaries will be installed in the system as described above. The file you are reading right now is available as iraf$pkg/ecl/Notes.ecl and will be updated with post-release notes at the end of the file with each new release. Step 3) Start the ECL from your normal IRAF login directory as either % ecl or % cl -ecl The second form of the command is needed on systems which mount IRAF from another machine since the CL command links are created at IRAF install time. One reason for replacing the hlib$cl.csh script is to allow for the "-ecl" argument to override the binary to be used on systems where only the 'cl' command is available and so that the installation isn't required on all machines mounting a common IRAF. The default ECL prompt is now "ecl>" in the new version as a visual clue that the new system is being used. Additionally, package prompts default to using the complete package name rather than the familiar 2-character prefix as another clue. This behavior can be changed by adding the string "nolongprompt" to the CL 'ehinit' parameter, e.g. cl> cl.ehinit = cl.ehinit // " nolongprompt" Except as described below, use of the ECL should be identical to the traditional CL for most users. Determining CL Version ---------------------- As users begin to make regular use of features found only in the ECL, the first error to be checked is that the script is running using the proper version of the CL. This needs to be done using features found in both the ECL and traditional CL languages. The simplest test, for either package loading scripts or within tasks, is something like if (defpar ("$errno")) { print ("You are using the ECL") } else { print ("You are using the old CL") } ============== Error Handling ============== Introduction and Cautions ========================= The error-handling enhancements are composed of two elements: o the reporting of errors within scripts, and o the ability to trap and recover those errors. The first case addresses the long-standing problem in which an error message returned by a script gives a line number that has no basis in reality, and which gives no useful information about the underlying task that created it. In the second case, one often wants scripts to be able to trap errors from compiled tasks so that some sort of cleanup can be done in order to allow the script to continue, or so that an error status code can be examined and some specific action taken (which may simply be to ignore the error). In the ECL, messages are now printed with the correct line number and with a detailed traceback to the user's command-line showing more precisely what was called at the time of the error. New language constructs are available which allow scripts to conditionally check for errors from tasks they call and branch to code to deal with those errors. Finally, new ECL environment variables and builtin functions allow for limited error-handling control over scripts already in the system which have not been retrofitted to specifically trap errors. Details of each of these capabilities and examples of how they may be used by developers and users are given below. It is also worth discussing the types of errors which can occur in a script task before getting into details about how they might be handled by the user or script programmer. Error conditions in the CL break down into roughly the following types: Error Type Examples ---------- -------- Compiled Task Errors 1) A call to a compiled task in the system dies unexpectedly with an exception (e.g. FPE, segmentation violation, etc) 2) A task aborts due to an error condition the task has trapped and cannot recover (e.g. invalid parameters, out of memory, etc). CL Internal Errors 1) Script code performs an illegal operation causing an exception (e.g. "i = j / k" where 'k' is zero. 2) Script code triggers a runtime error within the CL itself (e.g. "log (string_value)") CL Error Assertions 1) Script programmer forces the task to exit with a call to the CL error() builtin. 2) Script programmer simply prints and error message indicating a problem and returns without further processing. All of these errors can be detected at some level, however not all of them can be handled in a way which allows a calling script to recover and continue executing, nor would it always make sense to do so. Errors such as a floating-point-exception (FPE) may be data-dependent, a segmentation violation may indicate a coding error in a compiled task or a platform-specific bug, or an error in another script task may be beyond the control of the scripter to fix. Error assertions by a script programmer are not meant to be recoverable, and in the second example an arbitrary problem message cannot be trapped by the system. An error-handling capability in the ECL (or any language) is not a panacea for all error conditions one might encounter, the best a script programmer can hope to do is to trap an error and take some reasonable action at the time. The ECL offers a way for a script to print a more meaningful error message, or at least abort gracefully after cleaning itself up. However, depending on the type of error, *your* script may still never run to completion until somebody else fixes *their* code. Lastly, it is also important to note that trapping an error means the script finds itself in an unnatural state. Proper recovery requires that the script programmer understand the error condition as well as the state of the script at that point of execution. The error-handling code must restore the script to a state where it can continue running (if possible) and avoid potential side-effects caused by e.g. forgetting to clean up intermediate files or reset counter variables. New language features mean new types of bugs can be introduced into a script, even if the irony is that these new features are meant to trap bugs! Example Descriptions -------------------- In the examples to follow we will make use of an ERRTEST package distributed with the ECL source and containing the following tasks used in the examples to follow: nested -- Test various error conditions from layered scripts nest0 -- Dummy layer for nested testing errtype -- Low-level script to test compiled and CL error conditions fpe -- Compiled task producing an arithmetic exception segvio -- Compiled task producing a segmentation violation spperr -- Compiled task invoking the SPP error() function Reporting of Errors =================== Traceback --------- The most obvious change to users will be in the traceback of errors reported by the ECL. As an example, suppose we have a test script called NESTED that calls several layers of other scripts until it gets to a compiled task called FPE which simply triggers a divide-by-zero arithmetic exception. The calling sequence we use is NESTED (type) # toplevel test task NEST0 (type) # hidden script task ERRTYPE (type) # script task FPE () # compiled task giving the error (The 'type' argument here is a code used to test various types of system errors but its value isn't important to the current discussion.) In the traditional CL, executing this script results in the following and familiar message: cl> nested 1 ERROR on line 72: floating point divide by zero errtype (type=1) nested (type=1) There are a number of issues with the error report here we wish to correct: 1) The error is reported to be on line 72, but none of the scripts called invoke any task on that line, or even have that many lines, and so it is clearly wrong. 2) Was it the ERRTYPE script that caused an error or something else? 3) There is no mention of the FPE task we know to be the culprit. These problems are resolved in the ECL where the error report now looks like: cl> nested 1 ERROR: floating point divide by zero "fpe ()" line 15: errtest$errtype.cl called as: `errtype (type=1)' "errtype (type)" line 13: errtest$nest0.cl (hidden task) called as: `nest0 (type=1)' "nest0 (type)" line 11: errtest$nested.cl called as: `nested (type=1)' The traceback is more complete and begins with the task which actually throws the error. Checking the line numbers of the ERRTEST package scripts we find that indeed FPE is called on line 15 of 'errtype.cl', ERRTYPE is called from line 13 of 'nest0.cl', and so on. For each task in the calling sequence the format of the traceback is