New editions incorporate any updates issued since the previous edition.
A plus sign (+) after a release ID indicates that this manual describes function added to the base release,
either by an interim product modification (IPM) or by a new product version on a .99 site update tape (SUT).
Ordering InformationFor manual ordering information: domestic U.S. customers, call 1-800-243-6886; international customers, contact your
local sales representative.
Document DisclaimerInformation contained in a manual is subject to change without notice. Please check with your authorized Tandem
representative to make sure you have the most recent information.
Export StatementExport of the information contained in this manual may require authorization from the U.S. Department of Commerce.
ExamplesExamples and sample programs are for illustration only and may not be suited for your particular purpose. Tandem does
not warrant, guarantee, or make any representations regarding the use or the results of the use of any examples or sample
programs in any documentation. You should verify the applicability of any example or sample program before placing the
software into productive use.
U.S. Government
Customers
FOR U.S. GOVERNMENT CUSTOMERS REGARDING THIS DOCUMENTATION AND THE ASSOCIATED SOFTWARE:
These notices shall be marked on any reproduction of this data, in whole or in part.
NOTICE: Notwithstanding any other lease or license that may pertain to, or accompany the delivery of, this computer
software, the rights of the Government regarding its use, reproduction and disclosure are as set forth in Section 52.227-19
of the FARS Computer Software-Restricted Rights clause.
RESTRICTED RIGHTS NOTICE: Use, duplication, or disclosure by the Government is subject to the restrictions as set
forth in subparagraph (c)(1)(ii) of the Rights in Technical Data and Computer Software clause at DFARS 52.227-7013.
RESTRICTED RIGHTS LEGEND: Use, duplication or disclosure by the Government is subject to restrictions as set forth
in paragraph (b)(3)(B) of the rights in Technical Data and Computer Software clause in DAR 7-104.9(a). This computer
software is submitted with “restricted rights.” Use, duplication or disclosure is subject to the restrictions as set forth in
NASA FAR SUP 18-52 227-79 (April 1985) “Commercial Computer Software — Restricted Rights (April 1985).” If the
contract contains the Clause at 18-52 227-74 “Rights in Data General” then the “Alternate III” clause applies.
U.S. Government Users Restricted Rights — Use, duplication or disclosure restricted by GSA ADP Schedule Contract.
Unpublished — All rights reserved under the Copyright Laws of the United States.
New and Changed Information
This is the second edition of the TACL Programming Guide . This edition documents
the following new TACL features:
A new built-in function, #SETCONFIGURATION, sets the TACL flags that can
change the behavior of TACL for a specified TACL image or configure the
currently running TACL process.
A new built-in function, #XLOGON, implements the LOGON command.
The LOGON command, #CHANGEUSER built-in function, and #XLOGON built-
in function support the Safeguard authentication dialog.
The STATUS command and #XSTATUS built-in function display new process
type information.
CLASS DEFAULT DEFINEs have eight new optional attributes for
internationalization support.
105919 Tandem Computers Incorporatediii
New and Changed Information
(This page left intentionally blank)
iv105919 Tandem Computers Incorporated
Contents
About This Manual xi
Notation Conventions xv
Section 1An Overview of TACL
Running the Examples in This Manual 1-1
Style Conventions 1-2
Exceptions to the Style Conventions 1-3
Conventions Specific to This Manual 1-3
Section 2Developing TACL Programs
Choosing a Type of Variable 2-1
Defining Program Structure 2-2
Using Flow Control Functions 2-2
Nesting TACL Code 2-7
Saving Levels of Variables 2-8
Exiting From Programs 2-9
Processing Character Data 2-9
Line and Character 2-10
Global Editing Commands 2-13
Additional Data Manipulation Capabilities 2-16
Data Types 2-17
Accessing Time Data 2-17
Timestamp Formats 2-17
Retrieving a Timestamp 2-18
Converting a Timestamp 2-19
Accessing Terminals 2-24
Defining Function Keys 2-24
Sending Escape Sequences to a Terminal 2-25
Changing the TACL Prompt 2-29
Implementing Menus 2-30
Debugging TACL Programs 2-32
Enabling the TACL Debugger 2-32
Debugger Commands 2-32
A Sample Debugging Session 2-33
107365 Tandem Computers Incorporatedv
Contents
Section 3Developing TACL Routines
Processing Arguments 3-1
How #ARGUMENT Works 3-3
Using #ARGUMENT 3-4
Examining the Contents of Arguments 3-9
Parsing Arguments for a Caller 3-11
Returning Results 3-15
Calling a Routine Recursively 3-16
Exiting From a Routine 3-17
Writing an Exception Handler 3-18
Section 5Initiating and Communicating With Processes
Initiating a Process 5-2
Using RUN and #NEWPROCESS Options 5-2
Sending Information at Initiation Time 5-3
Communicating With a Process 5-4
Using the INLINE Facility 5-6
Using INV and OUTV 5-14
Using $RECEIVE 5-21
Using #SERVER 5-29
Using Define Process 5-31
vi107365 Tandem Computers Incorporated
Processing Completion Information 5-32
Processing NetBatch Jobs and Completion Codes 5-32
Monitoring Job Status
ENQUIRY 5-35
Section 6Running TACL as a Server
Running a TACL Process as a Server 6-1
Starting TACL as a Server Process 6-1
Sending Requests to a TACL Server 6-2
Directing Output From TACL 6-4
Running TACL Code as a Server 6-5
Constructing a TACL Server 6-5
Contents
Using TACL as a Pathway Server 6-6
Section 7Using Programmatic Interfaces
Overview of SPI and EMS 7-1
Using SPI 7-4
Defining an SPI Buffer 7-5
Using SPI Functions 7-9
Using EMS 7-12
Communicating With EMS 7-12
Generating an EMS Event 7-13
Section 8Example of a System Management Program
Monitoring System Operation 8-1
Section 9Syntax Summary
TACL Commands and Functions 9-1
Built-In Functions and Variables 9-6
STRUCT Declarations 9-14
#SET Summary 9-15
#DELTA Command Summary 9-16
Appendix ASupplemental Information for D-Series Systems
GlossaryGlossary–1
107365 Tandem Computers Incorporatedvii
Contents
IndexIndex–1
FiguresFigure 2-1.Performing Tasks Within a Loop 2-2
Figure 2-2.Performing a Bubble Sort With Nested #LOOP Statements 2-3
Figure 2-3.Deleting Files in a Subvolume 2-5
Figure 2-4.Processing Macro Arguments 2-8
Figure 2-5.Extracting a Volume Name from a Variable 2-12
Figure 2-6.Retrieving Disk Names From DSAP 2-15
Figure 2-7.Relationships Between System Timestamps and TACL
Functions 2-20
Figure 2-8.Relationships Between #FILEINFO Timestamps and TACL
Functions 2-21
Figure 2-9.Computing the Current Day 2-22
Figure 2-10.Converting Timestamps 2-23
Figure 2-11.Sending Special Characters to a Screen 2-25
Figure 2-12.Displaying a Screen of Text 2-27
Figure 2-13.Locking a Terminal 2-28
Figure 2-14.Displaying a Menu 2-30
Figure 2-15.Starting TEDIT From TACL 2-34
Figure 3-1.Processing Arguments 3-5
Figure 3-2.Returning Characters From a Routine 3-9
Figure 3-3.Returning a Set of Characters From a Variable 3-10
Figure 3-4.Searching for Text 3-10
Figure 3-5.Counting Characters in a Variable 3-11
Figure 3-6.Moving Text Between Variables 3-11
Figure 3-7.Assigning Values to Arguments 3-12
Figure 3-8.Sending Arguments to a Parsing Program 3-14
Figure 3-9.Converting Timestamps 3-15
Figure 3-10.Processing Arguments 3-16
Figure 3-11.Processing File Name Arguments 3-17
Figure 3-12.Sample Release Handler Template 3-20
Figure 3-13.Sample Release Handler 3-21
Figure 3-14.Returning Information From a Release Handler 3-22
Figure 3-15.Sample Keep Exception Handler 3-25
viii107365 Tandem Computers Incorporated
Figure 3-16.Sample Command Shell 3-27
Figure 3-17.Using Nested Keep and Release Handlers (Page 1 of 2) 3-31
Figure 4-1Performing a Waited Read 4-3
Figure 4-2Performing a Nowaited Read 4-5
Figure 4-3Reading From a Terminal and Performing a Waited Write 4-7
Figure 4-4Reading From a Terminal and Performing a Nowaited
Write 4-9
Figure 4-5Copying Records From One File to Another File 4-10
Figure 4-6Comparing Two Files 4-13
Figure 4-7Listing a File 4-16
Figure 4-8TACLLIST Output 4-20
Contents
Figure 5-1Communicating With FUP 5-8
Figure 5-2Building a Script 5-8
Figure 5-3Retrieving Output from FUP 5-10
Figure 5-4Omitting Terminal Output 5-11
Figure 5-5Deleting PERUSE Jobs 5-12
Figure 5-6Retrieving the TACL IN File Name 5-15
Figure 5-7Communicating With FUP Using INV and OUTV 5-17
Figure 5-8Directing FUP Output to a Log File 5-18
Figure 5-9Displaying PERUSE Jobs 5-19
Figure 5-10Sending Messages to a Terminal 5-22
Figure 5-11Creating CMON Messages 5-25
Figure 5-12Communicating With FUP Using #SERVER 5-30
Figure 5-13Checking Completion Codes 5-33
Figure 5-14Retrieving TACL Output 5-36
Figure 6-1Starting and Sending Requests to a TACL Server 6-2
Figure 6-2Running a TACL Program as a Server 6-7
Figure 6-3Screen COBOL Code That Accesses a TACL Server 6-9
Figure 6-4Configuring the Pathway Environment 6-11
Figure 7-1Comparing Two Subsystem IDs 7-9
Figure 7-2Displaying the EMS Log 7-10
Figure 7-3Generating an EMS Event 7-13
Figure 8-1Monitoring System Status 8-2
107365 Tandem Computers Incorporatedix
Contents
TablesTable 2-1.Built-In Functions That Edit Variables by Line 2-10
Table 2-2.Global Editing Commands 2-13
Table 2-3.Data Manipulation Functions 2-16
Table 2-4.Timestamp Conversion Functions 2-19
Table 2-5._DEBUGGER Command Syntax 2-32
Table 3-1.Functions That Support Arguments 3-3
Table 3-2.Functions That Support Exception Handlers 3-19
Table 3-3.Differences Between Keep and Release Exception
Handlers 3-20
Table 4-1Functions Used With #REQUESTER 4-2
Table 5-1RUN and #NEWPROCESS Communication Options 5-2
Table 5-2INLINE Commands and Variables 5-6
Table 5-3Variables and Commands for INLINE Display 5-9
Table 5-4Functions and Options Used With INV and OUTV 5-15
Table 5-5Functions to Use With $RECEIVE 5-21
Table 6-1Functions That Support Interprocess Communication 6-2
Table 7-1TACL Functions That Support SPI 7-4
Table 7-2SPI Token Data Types 7-6
Table 7-3Functions That Support EMS 7-12
x107365 Tandem Computers Incorporated
About This Manual
This manual describes the Tandem Advanced Command Language (TACL) and
provides information and examples for creating TACL programs.
AudienceThis manual is intended for users of TACL who are familiar with TACL commands
and built-in functions and who want to create TACL programs.
OrganizationThis manual contains the following sections:
Section 1, “An Overview of TACL,” contains an overview of TACL features and a
description of the programming conventions used in examples.
Section 2, “Developing TACL Programs,” describes topics that are common to
many TACL programs, whether they are structured as TEXT, MACRO, or
ROUTINE variables. Topics include data editing, flow of control, using time data,
accessing terminals, handling errors, and debugging TACL programs.
Section 3, “Developing TACL Routines,” describes how to use TACL constructs
that are available only for routines, including the use of #ARGUMENT,
#RETURN, and #ROUTINENAME.
Section 4, “Accessing Files,” provides information and examples that show how
to access files from TACL programs.
Section 5, “Initiating and Communicating With Processes,” provides information
and examples that show how to start and communicate with processes from TACL
programs.
Section 6, “Running TACL as a Server,” describes how to create a TACL program
that acts as a server to other processes.
Section 7, “Using Programmatic Interfaces,” provides information and examples
for sending SPI and EMS messages.
Section 8, “Example of a System Management Program,” contains a sample
program that monitors system status.
Section 9, “Syntax Summary,” provides a syntax summary of all TACL functions.
Appendix A, “Supplemental Information for D-Series Systems,” provides
information on D-series features.
Related ReadingThe following paragraphs list manuals that are related to the development of TACL
programs.
PrerequisitesIntroductory material describing the steps involved in using TACL as a command
interpreter, as well as using it for defining function keys, writing simple macros, and
other basic purposes, is presented in the Guardian User’s Guide (contains no
descriptions of TACL built-in functions and variables). You should read and
understand the first four sections of that manual before using this programming
guide.
107365 Tandem Computers Incorporatedxi
About This Manual
Related Reading
CorequisitesAdditional sources of information you might want to have available for reference are:
To use this manual, you should be familiar with the syntax and structure of procedural
variables (TEXT, MACRO, and ROUTINE), including basic programming concepts
and terminology such as “pushing” and “popping” (creating and deleting) variables,
the use of arguments, and so on. Elements of the TACL language are described in the
TACL Reference Manual.
Debug Manual
Event Management Service (EMS) Manual
Enscribe Programmer’s Guide
Expand Network Management Guide
File Utility Program (FUP) Reference Manual
Guardian Programmer’s Guide
Introduction to Distributed Systems Management (DSM)
Distributed Systems Management (DSM) Programming Manual
Inspect Manual
NetBatch Manual
Security Management Guide
System Procedure Errors and Messages Manual
NonStop II and TXP System Operator’s Guide
System Procedure Calls Reference Manual, Volume 1 and 2
Introduction to NonStop Transaction Manager/MP (TM/MP)
ViewPoint Manual
xii107365 Tandem Computers Incorporated
About This Manual
Related Reading
Figure 1 lists the recommended sequence for reading TACL related manuals.
Figure 1. Documentation Road Map
Prerequisite Manuals
TACL
Reference
Manual
TACL
Programming
Guide
Related Manuals
NetBatch
Manual
Guardian
User's Guide
Guardian
Programmer's
Guide
107365 Tandem Computers Incorporatedxiii
Introduction to
Distributed
Systems
Management
(DSM)
Event
Management
Service (EMS)
Manual
001
About This Manual
Related Reading
(This page left intentionally blank)
xiv107365 Tandem Computers Incorporated
Notation Conventions
General Syntax
Notation
UPPERCASE LETTERSUppercase letters indicate keywords and reserved words; enter these items exactly as
lowercase italic lettersLowercase italic letters indicate variable items that you supply. Items not enclosed in
Brackets [ ]Brackets enclose optional syntax items. For example:
The following list summarizes the notation conventions for syntax presentation in this
manual.
shown. Items not enclosed in brackets are required. For example:
STATUS
brackets are required. For example:
file-name
TERM [\
A group of items enclosed in brackets is a list from which you can choose one item or
none. The items in the list may be arranged either vertically, with aligned brackets on
each side of the list, or horizontally, enclosed in a pair of brackets and separated by
vertical lines. For example:
LIGHTS [ ON ]
[ OFF ]
[ SMOOTH [
Note also that TACL uses brackets in commands and functions.
node-name
.]$
terminal-name
num
] ]
Braces { }A group of items enclosed in braces is a list from which you are required to choose one
item. The items in the list may be arranged either vertically, with aligned braces on
each side of the list, or horizontally, enclosed in a pair of braces and separated by
vertical lines. For example:
#BUILTINS [ / { FUNCTIONS | VARIABLES } / ]
Note also that TACL uses braces in comments.
Vertical Line |A vertical line separates alternatives in a horizontal list that is enclosed in brackets or
braces. For example:
INSPECT { OFF | ON | SAVEABEND }
Note also that TACL uses vertical lines to surround labels in enclosures.
107365 Tandem Computers Incorporatedxv
Notation Conventions
General Syntax Notation
Ellipsis ...An ellipsis immediately following a pair of brackets or braces indicates that you can
repeat the enclosed sequence of syntax items any number of times. For example:
#PUSH
variable
[ [,]
variable ] ...
[ + | - ] {0|1|2|3|4|5|6|7|8|9}...
An ellipsis immediately following a single syntax item indicates that you can repeat
that syntax item any number of times.
PunctuationParentheses, commas, semicolons, and other symbols not previously described must
be entered as shown. For example:
#CHARACTERRULES
Quotation marks around a symbol such as a bracket or brace indicate the symbol is a
required character that you must enter as shown.
Item SpacingSpaces shown between items are required unless one of the items is a punctuation
symbol such as a parenthesis or a comma. For example:
PURGE
file-name
If there is no space between two items, spaces are not permitted. In the following
example, there are no spaces permitted between the period and any other items:
$
subvol.file-name
Line SpacingIf the syntax of a command is too long to fit on a single line, each continuation line is
indented three spaces and is separated from the preceding line by a blank line. This
spacing distinguishes items in a continuation line from items in a vertical list of
selections. For example:
#POP
[ [,]
xvi107365 Tandem Computers Incorporated
variable
variable
]...
1An Overview of TACL
The Tandem Advanced Command Language (TACL) is the standard command
interface to the Tandem NonStop kernel. In addition to providing full command
interpreter facilities, TACL is a high-level programming language.
As a programming language, the TACL product is most often used for managing
systems and processes. You can, for example, use TACL to:
Automate system startup and shutdown procedures.
Automate subsystem startup and shutdown procedures; for example, you can use
TACL statements to initialize Pathway, the TMF subsystem, Transfer, and other
subsystems.
Run utilities and issue commands−either with a fixed set of commands or a
flexible set that you can tailor at run time.
Create a customized environment that simplifies commonly performed tasks for
users.
Control subsystem operation using the Subsystem Programmatic Interface (SPI).
Communicate with the Event Management Service (EMS) and generate EMS
messages.
The TACL language consists of commands, built-in functions, and built-in variables.
Commands are typically used for interactive work. Built-in functions are typically
used for programmatic work. Built-in variables store environmental information; you
can set and retrieve their values.
Running the Examples
in This Manual
Procedural constructs such as flow control statements are provided as part of the set of
built-in functions. In addition, TACL provides powerful text manipulation functions
that process output and results from processes.
TACL is extensible; all of the commands supplied by Tandem are implemented as
TACL programs. You can add functions as necessary.
In addition, NetBatch requires the use of TACL.
The following paragraphs describe programming style and the use of examples in this
manual.
Before running the examples in this manual, set the built-in variable #INFORMAT to
TACL, which enables recognition and processing of the TACL special characters ([ and
], for example); without this step, TACL does not recognize metacharacters as special
characters. The function call is:
11> #SET #INFORMAT TACL
In addition, set the built-in variable #PMSEARCHLIST to include (at least)
$SYSTEM.SYSTEM and the keyword #DEFAULTS, which enable the use of implied
RUN commands. An example is:
12> #SET #PMSEARCHLIST [#DEFAULTS] $SYSTEM.SYSTEM
107365 Tandem Computers Incorporated1–1
An Overview of TACL
Style Conventions
You can add these statements to your TACLCSTM file if you use them frequently.
In cases where TACL provides a built-in function that is similar to a command (such
as PUSH and #PUSH), the examples in this manual use the built-in function. Built-in
functions are the most basic unit of TACL, and they return results and provide easier
programmatic access to error information.
Error checking is as important in TACL programs as it is in programs written in other
languages. Possible sources for errors include terminal input and file system
operations.
Examples and sample programs are for illustration only and might not be suited for
your particular purpose. Tandem does not warrant, guarantee, or make any
representations regarding the use or the results of the use of any examples or sample
programs in any documentation. You should verify the applicability of any example
or sample program before placing the software into productive use.
NoteFor additional examples, you can view the code for TACL commands by displaying the contents
(#OUTVAR
command
).
Style ConventionsThe examples in this manual adhere to the following conventions for clarity and
maintainability of programs:
Built-in functions, commands, variables, and other keywords appear in uppercase:
#SET
TIME
User-defined functions, commands, and variables appear in lowercase:
var1
get_info
STRUCT definitions are indented two columns for each level of nesting.
Similar levels of nested text in #IF, #CASE, and #LOOP statements are indented to
the same column. Indentations are in two-space increments. Matching square
brackets are in the same column; labels within square brackets start at the same
column.
Square brackets and labels for #IF and #LOOP statements start at the same
column. Conditional text is indented two more spaces. For example:
1–2107365 Tandem Computers Incorporated
[#IF [timenow] > 12 |THEN|
#OUTPUT Good afternoon
|ELSE|
#OUTPUT Good morning
]
Square brackets for #CASE statements start at the same column. Because
#CASE statements can include include several user defined labels; labels are
An Overview of TACL
Style Conventions
indented two spaces within the square brackets. Conditional text is indented
two spaces past the labels. For example:
[#CASE [errornumber]
|0|
#OUTPUT [filename] was purged
|OTHERWISE|
#OUTPUT [filename] could not be purged
#OUTPUT Error [errornumber]
]
Exceptions to the Style
Conventions
Conventions Specific to
This Manual
In a few situations, the preceding style conventions do not produce optimal results.
For example, an #OUTPUT call that continues on a second line includes leading spaces
in the display. Therefore, text that continues an #OUTPUT call should be left-justified.
For example:
[#IF [x] > 0 |THEN|
#OUTPUT This is a test; the text for this #OUTPUT call &
is longer than a single line.
]
The second line of the #OUTPUT call is not indented two spaces.
In such cases, the examples in this manual note the exception and do not follow the
style conventions.
The following additional conventions are used for consistency:
The COMPUTE command and the #COMPUTE, #IF, and #LOOP built-in
functions accept expressions as arguments. When you supply a variable name as
all or part of an expression, you can enclose the variable name in square brackets
or omit the square brackets. Either way, TACL retrieves the contents of the
variable.
The examples in this manual include the square brackets, to show that the
statement uses the contents of the variable. This approach, however, requires
slightly more processing by TACL.
The examples in this manual are restricted to a line length of 62 characters (as
opposed to 80 characters for an edit file). There are several function calls in this
manual that are longer than 62 characters; these calls are enclosed in square
brackets or are joined by an ampersand character:
Lines that have 80 characters or less can fit on one edit file line; if you join these
lines in your program, you can omit the surrounding square brackets or the
ampersand character.
For more information about expressions, see the TACL Reference Manual.
This section describes topics that are common to all types of procedural variables.
Topics include:
Defining program structure
Processing character data
Accessing time information
Accessing terminals
Debugging TACL programs
The TACL Reference Manual contains information about TACL statements, programs,
and the TACL environment. This information is prerequisite to the topics in this and
later sections.
Choosing a Type of
Variable
The choice of a type of procedural variable depends on the type of work you plan to
do. The variable types can be summarized as follows:
A macro is typically used for programs that have limited need for validation of
arguments and no need for conditional exits. Within a macro, you can:
Define and access data structures such as text and STRUCT variables.
Compare, move, and manipulate the contents of variables.
Process arguments.
Use TACL built-in functions and commands, including built-in functions that
provide conditional execution of code.
Use TACL built-in variables to specify or obtain information about the TACL
environment.
A routine is the most general and fully functioned type of procedural variable, and
is required for programs that handle exceptions (unusual events) or perform
complex flow of control operations. If you plan to perform complex argument
processing, a routine is recommended.
Routines provide all of the capabilities that are available from macros, plus they
support built-in functions such as #ARGUMENT and #RETURN that are not
available to macros. While routines can provide more functionality than macros,
they also require more knowledge.
This section contains examples that illustrate the use of macros; except where noted,
these techniques also apply to routines.
Section 3, “Developing TACL Routines,” discusses additional features that apply only
to TACL routines.
107365 Tandem Computers Incorporated2–1
Developing TACL Programs
Defining Program Structure
Defining Program
Structure
Using Flow Control
Functions
The following paragraphs describe topics that are related to the structure of TACL
programs:
Using flow control functions: #LOOP, #IF, and #CASE
Nesting programs within other TACL programs
Saving and restoring levels of variables
Exiting from TACL programs
The following examples show how #LOOP, #CASE, and #IF statements work.
The macro in Figure 2-1, copier, demonstrates two ways to perform an activity in a
loop. Copier makes six copies of a file named TYPE. (The file TYPE must exist
before you run copier.) For the first three duplications, copier starts a new FUP
process during each pass through a loop. For the second three duplications, copier
loops to prepare a sequence of commands and then passes the commands to FUP. The
second method requires one additional variable and one more function call but starts
only one FUP process, and is therefore more efficient.
When you run copier, your TACL process must be named (using the NAME option
with the TACL command). To run copier, load the file that contains the macro and
then type:
copier
Figure 2-1. Performing Tasks Within a Loop
?SECTION copier MACRO
#FRAME
#PUSH listvar == List of files to be duplicated
#PUSH sn == Serial number
== Less efficient method; multiple processes started
#SET sn 0
[#LOOP |DO|
FUP DUP type, tmpa[sn] == Start FUP for each
#SET sn [#COMPUTE sn + 1] == command in the loop
|UNTIL| (sn = 3)
]
== More efficient method; one process started
#SET sn 0
[#LOOP |DO|
#APPEND listvar DUP type, tmpb[sn]
#SET sn [#COMPUTE sn + 1]
|UNTIL| (sn = 3)
]
FUP/INV listvar/ == Execute FUP only once
#UNFRAME
2–2107365 Tandem Computers Incorporated
Developing TACL Programs
Defining Program Structure
You can define a macro that increments a loop variable (passed as the argument); for
example:
Use the macro in Figure 2-2, bubble, with its nested #LOOP statements, to perform a
bubble sort. A bubble sort compares numbers and switches their places until the
numbers are stored in ascending order.
To run bubble, load its file and supply the number of sort elements as an argument:
bubble
num
Figure 2-2. Performing a Bubble Sort With Nested #LOOP Statements (Page 1 of 2)
?SECTION bubble MACRO
#FRAME
#PUSH i j max ocount element prompt temp
#SETMANY i j max ocount element, 0 0 0 0 0
#SET prompt Enter Next Number to be Sorted...
== Request the number of elements specified in argument 1 and
== store them in levels of STACK
[#LOOP |WHILE| (element < %1%) |DO|
#PUSH stack
#INPUTV stack prompt
#SET element [#COMPUTE element + 1]
] {end of INPUT loop}
== Loop once for each element
#SET ocount 1
[#LOOP |WHILE| (ocount < %1%) |DO|
#SET i 1
#SET max [#COMPUTE %1% - ocount + 1]
== Compare each element to its adjacent number; switch places
== if we encounter a smaller number.
[#LOOP |WHILE| (i < max) |DO|
#SET j [#COMPUTE i + 1]
[#IF ([stack.i] > [stack.j]) |THEN|
#SET temp [stack.i]
#SET stack.i stack.j
#SET stack.j temp
]
#SET i [#COMPUTE i + 1]
] {end of inner loop}
#SET ocount [#COMPUTE ocount + 1]
] == end of outer loop
107365 Tandem Computers Incorporated2–3
Developing TACL Programs
Defining Program Structure
Figure 2-2. Performing a Bubble Sort With Nested #LOOP Statements (Page 2 of 2)
== Loop through all variable levels and display contents
#SET element 1
[#LOOP |DO|
#OUTPUT [stack.[element]]
#SET element [#COMPUTE element + 1]
|UNTIL| (element > %1%)
]
#UNFRAME
Bubble requests the specified number of elements and displays the results:
29> bubble 3
Enter Next Number to be Sorted...1
Enter Next Number to be Sorted...43
Enter Next Number to be Sorted...5
1
5
43
30>
The bubble macro does not check the data type of the argument. Therefore, bubble
abc causes an error:
29> bubble abc
[#IF ( ( 0 < abc) )
Expecting a constant
Or NOT
Or a string
(variable does not exist)
Or a number
Or (
30>
Use the routine in Figure 2-3, checkfiles, with its #IF statements and nested #CASE
statements, to perform file maintenance on a subvolume. The routine asks for an
alphanumeric starting point in the subvolume. It starts at the next file name, loops
through your current subvolume, and displays information about each file in the
subvolume.
NoteWhen you run checkfiles, you must access your local system and your node name must not be
included in your current #DEFAULTS. To remove a node name, if present, enter SYSTEM at the TACL
prompt before running checkfiles.
2–4107365 Tandem Computers Incorporated
Developing TACL Programs
Defining Program Structure
When you run checkfiles, the routine displays the following:
Where do you want to start (default = beginning of subvol)?
To start checking files in the middle of the subvolume, enter a text constant with the
desired starting characters. Checkfiles then performs the following steps for each
file past the specified starting point in the subvolume:
1.Checkfiles displays the file name and date of last alteration.
2.For an Edit file, checkfiles displays the first ten lines of the file; otherwise, it
displays “Not an Edit file; nothing to show you.”
3.Checkfiles asks if you want to purge the file (Y or N). For files that are not Edit
files, checkfiles also asks if you want to empty the file (E).
Checkfiles stops at the end of the subvolume; to stop earlier, press BREAK.
Figure 2-3. Deleting Files in a Subvolume (Page 1 of 2)
#SET prompt &
Enter the start file (default = beginning of subvol)?
== Read text from the terminal
#INPUTV filenm prompt
#SET filenm [#NEXTFILENAME [#SHIFTSTRING/UP/[filenm]] ]
[#SET volsubvol
[#FILEINFO/VOLUME/[filenm]].[#FILEINFO/SUBVOL/[filenm]]
]
== Loop within the same subvolume
[#LOOP |WHILE| ([_COMPAREV volsubvol thisone]) |DO|
== Display last-altered information
#SET temp [#CONTIME [#FILEINFO/MODIFICATION/ [filenm]]]
#OUTPUT
#OUTPUT [filenm] last altered [_CONTIME_TO_TEXT [temp]]
== Get the file code
[#CASE [#FILEINFO/CODE/ [filenm] ]
== If an edit file, list the first ten lines, then
== determine whether the user wants to purge the file
|101|
FUP COPY [filenm] , , COUNT 10
#SET prompt Do you want to purge [filenm] (y/n)?
#INPUTV reply prompt
107365 Tandem Computers Incorporated2–5
Developing TACL Programs
Defining Program Structure
Figure 2-3. Deleting Files in a Subvolume (Page 2 of 2)
|OTHERWISE|
== Not an edit file; determine whether to purge it
#OUTPUT Not an Edit file; nothing to show you.
#SET prompt Do you want to purge/empty [filenm] &
(y/n/e)?
#INPUTV reply prompt
[#IF [#MATCH Y* [#SHIFTSTRING/UP/[reply]]] |THEN|
#SET resp [#PURGE [filenm]]
[#CASE [resp]
|0|
#OUTPUT [filenm] purged
|OTHERWISE|
#OUTPUT [filenm] could not be purged
#OUTPUT Error [resp]
] == end #CASE
] == end #IF
[#IF [#MATCH E* [reply]] |THEN| == empty the file
FUP PURGEDATA [filenm]
]
] == end #CASE
== Get the next file
#SET filenm [#NEXTFILENAME [filenm] ]
[#SET volsubvol
[#FILEINFO/VOLUME/[filenm]].[#FILEINFO/SUBVOL/[filenm]]
] == end #SET
] == end #LOOP
#UNFRAME
NoteThe previous example starts FUP several times; a more efficient way is to start FUP once and send it a
series of commands. For information about starting a process and sending it commands, see Section 5,
“Initiating and Communicating with Processes.”
2–6107365 Tandem Computers Incorporated
Developing TACL Programs
Defining Program Structure
Nesting TACL CodeTo run another TACL program from within a TACL program, invoke the file name or
variable name, as appropriate.
Certain built-in functions can be used only within one type of program (macro or
routine). To determine the use of such functions in a nested program, see individual
function descriptions in the TACL Reference Manual. For example, #ARGUMENT must
be used within a routine, but can be used in a macro if the macro is nested within a
routine.
To call a program recursively, use %0% (for a macro) or #ROUTINENAME (for a
routine) to specify the name of the program. You cannot call a text variable
recursively.
The following macro calls itself to display each of its arguments on a separate line:
?TACL MACRO
#OUTPUT %1%== Display current argument
[#IF NOT [#EMPTY %2%] |THEN|
== Test for additional arguments
%0% %2 TO *%== Call self without current
]== argument.
To run this macro, type the file name from the TACL prompt and supply one or more
arguments. The macro displays the arguments you supply. In the following example,
the file name that contains the macro is called ARGS:
12> args a b c d
a
b
c
d
13>
Section 3, “Developing TACL Routines,” contains a macro that calls a nested routine.
107365 Tandem Computers Incorporated2–7
Developing TACL Programs
Defining Program Structure
Use the macro in Figure 2-4, defaultvars, to assign data to a set of empty variables.
The macro accepts a space-separated list of variables and nonempty values and calls
itself repeatedly until all arguments are processed. To run this macro, load the file that
contains the macro definition and then type:
12> defaultvars [
variable constant [variable constant
Figure 2-4. Processing Macro Arguments
?SECTION defaultvars MACRO
== Any more pairs?
[#IF NOT [#EMPTY %1%] |THEN|
== Is this variable empty?
[#IF [#EMPTYV %1%] |THEN|
== The variable is empty; install default value
#SET %1% %2%
]
== Call self again, omitting the current pair.
%0% %3 TO *%
]
The following session shows how defaultvars works:
15> #PUSH a b c
16> defaultvars a 3 b 4 c 5
...] ]
17> #OUTPUTV a
3
18> #OUTPUTV b
4
19> #OUTPUTV c
5
Saving Levels of VariablesThe #PUSH built-in function creates a new level for a user-defined or built-in variable.
If you push a variable twice, TACL creates two levels of the variable. A new level
remains in existence until you request a #POP, #UNFRAME, or #RESET FRAMES
operation.
The following code redefines the TACL OUT file, retrieves information from the
history buffer, saves the history information in a file named HISTFILE in the current
subvolume, and then restores the OUT file to its previous setting:
?SECTION historysave MACRO
#PUSH #OUT== Create a new level for #OUT
#SET #OUT histfile== Set OUT to HISTFILE
#HISTORY== Retrieve history information
#POP #OUT== Restore #OUT to its previous value
2–8107365 Tandem Computers Incorporated
Developing TACL Programs
Processing Character Data
The #FRAME built-in function creates a local environment for variables. The
#UNFRAME command restores variables to the state they were in at the time of the
last #FRAME operation. For more information about frames, see the TACL Reference
Manual.
Exiting From ProgramsTACL exits from a macro or text variable as soon as it encounters either of the
following conditions:
Successful completion of the code; TACL executes each line and exits when
finished.
Detection of an error condition, in which case TACL restores all variables to the
state they were in when the variable was invoked and then exits the variable.
If you use routine variables, you can use the #RETURN built-in function to return
conditionally from one or more locations in your code. For more information, see
“Returning Results” in Section 3, “Developing TACL Routines.”
Processing Character
Data
When writing a TACL program, you might need to examine or modify the contents of
variables. Such tasks include:
Constructing text strings for input to processes, files, or devices
Analyzing process output
Analyzing results of functions
For example, whenever you use RUN or #NEWPROCESS to initiate a process from
TACL, you can direct output from the process to a variable:
The OUT option directs program output to a file.
The OUTV option stores program output into a variable for later use.
Section 5, “Initiating and Communicating With Processes,” describes process
initiation.
TACL supports several commands and functions that manipulate characters and lines
of characters within variables:
Commands, typically used for interactive work, perform editing operations on one
or more lines in a variable.
Built-in functions perform a single operation, referencing text by character
position or line number.
#DELTA, the low-level character editor, provides text editing capabilities similar to
those provided by the character and line oriented built-in functions. #DELTA is
complex; the newer #CHARxxx and #LINExxx built-in functions are easier to use.
STRUCT variables, or structures, allow you to define a set of elements and access the
elements by name. STRUCT variables support a range of data types. Structures are
helpful when communicating with processes such as $CMON, and are required when
communicating with the Subsystem Programmatic Interface (SPI) and the Event
Management Service (EMS).
107365 Tandem Computers Incorporated2–9
Developing TACL Programs
Processing Character Data
NoteVariable levels that contain TACL code contain special internal multicharacter representations of [, |,
For additional information about #DELTA and STRUCT variables, see the TACL
Reference Manual. For examples showing the use of STRUCT variables with SPI and
EMS, see Section 7, “Using Programmatic Interfaces.”
The following paragraphs describe how to use string manipulation functions and
commands.
and ]. When you use character oriented functions, be aware that these representations are counted as
multiple characters; they contain unprintable characters that are subject to change from one release of
TACL to another.
Line and Character
Built-In Functions
The functions in Table 2-1 operate on the contents of variables; each of these functions
performs an action and/or returns a result. There are two types of functions—one
accepts a character address; the other accepts a line address. Table 2-1 lists both types
of built-in functions; a dash indicates that there is no equivalent function or command.
Table 2-1. Built-In Functions That Edit Variables by Line
Character Address
Function
Line Address
FunctionDescription
#CHARADDR#LINEADDRConverts between a character address and a line
address.
#CHARBREAK#LINEBREAKInserts a line break at the specified character or
line address.
#CHARCOUNT#LINECOUNTCounts characters or lines.
#CHARDEL#LINEDELDeletes consecutive characters or lines.
#CHARFIND#LINEFINDFinds the address of specified text, searching
forward.
#CHARFINDV#LINEFINDVFinds the address of a specified string, searching
forward.
#CHARFINDR#LINEFINDRFinds the address of specified text, searching
backward.
#CHARFINDRV#LINEFINDRVFinds the address a specified string, searching
backward.
#CHARGET#LINEGETReturns a copy of consecutive characters or lines.
#CHARGETV#LINEGETVPlaces a copy of consecutive characters or lines
in the variable.
#CHARINS#LINEINSInserts lines of text at a specified address in the
variable.
#CHARINSV#LINEINSVInserts a string at a specified address in the
variable.
—#LINEJOINJoins two lines.
2–10107365 Tandem Computers Incorporated
Developing TACL Programs
Processing Character Data
A character address specifies a particular character within a variable, counting from
the first character, whose character address is 1. Each end-of-line character (except the
last one in the variable) counts as one character. If a specified character address is
greater than the number of characters in the variable, that address is considered to be
equivalent to the address of the character that appears after the last character in the
variable.
A line address specifies a particular line within a variable, counting from the first line,
whose line address is 1. If a specified line address is greater than the number of lines
in the variable, that address is considered to be equivalent to the address of the line
that appears after the last line in the variable. If the variable changes, the assumed line
numbers will be different on the next operation. Unlike line numbers in an edit-format
file, these assumed line numbers are not saved.
For example, a variable called sample contains three lines of text:
10> #PUSH sample
11> #APPEND sample This variable is called "sample."
12> #APPEND sample It contains three lines of text.
13> #APPEND sample The contents will be edited by built-in
functions.
14> #OUTPUTV sample
This variable is called "sample."
It contains three lines of text.
The contents will be edited by built-in functions.
15>
To retrieve the number of lines, enter:
11> #LINECOUNT sample
#LINECOUNT sample expanded to:
3
12>
To retrieve the number of characters, enter:
12> #CHARCOUNT sample
#CHARCOUNT sample expanded to:
117
13>
To find the line address of the first line that contains “text,” starting at line 1, enter:
13> #LINEFINDV sample 1 "text"
#LINEFINDV sample 1 "text" expanded to:
2
14>
107365 Tandem Computers Incorporated2–11
Developing TACL Programs
Processing Character Data
To find the character position of the first occurrence of the string “text,” starting at
character position 1, enter:
14> #CHARFINDV sample 1 "text"
#CHARFINDV sample 1 "text" expanded to:
62
15>
Use the macro in Figure 2-5, volname, to extract a volume name from a variable
named mylist. To use this macro, load the file that contains the macro definition and
enter:
volname
When you invoke this macro, it displays the following:
15> volname
The volume name is $DATA
16>
Figure 2-5. Extracting a Volume Name from a Variable
?SECTION volname MACRO
#FRAME
#PUSH mylist begin end vol
== Specify the contents of mylist:
#SET mylist The disk file name is \SYS1.$DATA.SVOL.NAME1.
== Search for a dollar sign:
#SET begin [#CHARFINDV mylist 1 "$"]
== Search for the first period following the dollar sign:
#SET end [#CHARFINDV mylist [begin] "."]
== Retrieve the characters between "$" and ".":
#SET vol [#CHARGET mylist begin TO [#COMPUTE end - 1]]
#OUTPUT The volume name is vol
#UNFRAME
For examples showing the use of these functions for argument processing in routines,
see “Processing Arguments” in Section 3, “Developing TACL Routines.”
2–12107365 Tandem Computers Incorporated
Developing TACL Programs
Processing Character Data
Global Editing CommandsUse the commands in Table 2-2 to perform editing operations on the entire contents of
a variable or a range of lines within the variable.
Table 2-2. Global Editing Commands
CommandDescription
VCHANGEChanges all occurrences of one string to another string in a range of consecutive
lines in a variable. VCHANGE is not case-sensitive.
VCOPYCopies a range of lines from one variable and inserts them at a given line position
in another variable.
VDELETEDeletes a range of consecutive lines in a variable.
VFINDFinds all lines containing occurrences of a specified string in a range of lines in a
variable. VFIND is not case-sensitive.
VINSERTInserts lines from the TACL IN file at a given line position in a variable.
VLISTLists a range of consecutive lines in a variable.
VMOVEDeletes a range of lines from one variable and inserts them at a given line position
in another variable.
Unlike the built-in functions, the commands in Table 2-2 do not return a result.
Instead, each of these commands (except VINSERT) lists the lines it operates on, with
sequence numbers, to either the TACL OUT file or another user-specified file. You can
append copies of the lines to an existing variable.
To use these commands, specify a range of line numbers or all of the lines in the
variable (the default). If you use these commands to search for text or change text, the
process is not case-sensitive; TACL performs the operation on all instances of the text.
To specify a case-sensitive text change, use a line-editing or character-editing function,
listed in Table 2-1.
The following code reserves the name of a variable called sample2:
12> #PUSH sample2
(The variable is initialized as soon as you store data in it.)
To insert several lines into the variable, starting at line 1, enter:
13> VINSERT sample2 1
1 The name of this variable is "sample2."
2 There are 37 characters in this line.
3 This is the last line in the variable.
To terminate input, type CTRL/Y (or a line that contains two slashes—//).
107365 Tandem Computers Incorporated2–13
Developing TACL Programs
Processing Character Data
To display the contents of sample2, enter:
14> VLIST sample2
1 The name of this variable is "sample2."
2 There are 37 characters in this line.
3 This is the last line in the variable.
To find all occurrences of the word “line” in sample2, enter:
15> VFIND sample2 "line"
2 There are 37 characters in this line.
3 This is the last line in the variable.
To change all occurrences of “line” to “sentence,” enter:
16> VCHANGE sample2 "line" "sentence"
2 There are 37 characters in this sentence.
3 This is the last sentence in the variable.
You can also use a variable for the comparison string:
2 There are 37 characters in this line.
3 This is the last line in the variable.
2–14107365 Tandem Computers Incorporated
Developing TACL Programs
Processing Character Data
Use the macro in Figure 2-6, volnames, to display the volume names on your system,
using the VFIND global editing command. To run this macro, load the file and type
volnames:
12> volnames
The volume names are:
$SYSTEM
$DATA
$DATA2
$DATA3
13>
This macro uses the OUTV construct to retrieve process output. For more information
about OUTV, see “Using INV and OUTV” in Section 5, “Initiating and Communicating
With Processes.”
Figure 2-6. Retrieving Disk Names From DSAP
?SECTION volnames MACRO
#FRAME
[#PUSH
dsapoutput == an output stack for DSAP
diskpaths == a stack of disk names
diskinfo == a single line from DSAP
volname == a volume name
displayinfo == a stack of volume names to display
count == a stack counter
begin == beginning of the volume name
end == end of the volume name
]
== Run DSAP and capture the output:
DSAP /OUTV dsapoutput/ *, SHORT
VFIND /QUIET, TO diskpaths/ dsapoutput "$"
== Set a stack counter for diskpaths
#SET count [#LINECOUNT diskpaths]
== Loop through the contents of diskpaths
[#LOOP |WHILE| [count] <> 0 |DO|
== Extract a line and put it in diskinfo
#SET diskinfo [#EXTRACT diskpaths]
== Get values for the positions of the "$" and "-"
== characters
#SETMANY volname, [diskinfo]
#APPENDV displayinfo volname
#SET count [#COMPUTE [count] - 1]
]
#OUTPUT The volume names are:
#OUTPUTV displayinfo
#UNFRAME
107365 Tandem Computers Incorporated2–15
Developing TACL Programs
Processing Character Data
Additional Data
Manipulation Capabilities
Use the built-in functions and commands in Table 2-3 to perform other data
manipulation tasks. A dash indicates that there is no equivalent function or command.
Table 2-3. Data Manipulation Functions
FunctionCommandDescription
#APPEND—Adds a line of text to a variable level.
#APPENDV—Appends a string or the contents of a variable level to the
end of another variable level.
#COMPAREV_COMPAREVCompares one string or variable level with another.
—COPYVARCopies the contents of one variable level to another.
#EMPTY—Determines whether specified text is empty.
#EMPTYV—Determines whether a variable level or quoted text is
empty.
#EXTRACT—Obtains the first line of a variable level.
#EXTRACTV—Moves the first line of a variable level to another variable
level.
—FILETOVARCopies data from a file to the end of a variable level.
—JOINConverts a multiple-line variable level into a single-line
variable level with spaces in place of end-of-line indicators.
—_LONGESTReturns the longest element in a variable containing a
space-separated list.
#SETSET VARIABLEChanges the entire contents of a variable level.
#SETMANY—Distributes the members of a space-separated list into
individual variable levels.
#SETV—Copies a string or variable level into another variable level.
—VARTOFILECopies data from a variable level to a file.
To read data into a variable from a sequential file, you can use either FILETOVAR or
#SET. The following statements move the contents of
FILETOVAR
or
#SET /IN
The #SET command is much faster and is easier to debug: FILETOVAR is
implemented as a looping macro; #SET uses TAL code. The maximum record length
for records in files copied by FILETOVAR is 239 characters. When using #SET, make
sure #INFORMAT is set to PLAIN.
2–16107365 Tandem Computers Incorporated
filename variable
filename/ variable
filename
into
variable
:
Developing TACL Programs
Accessing Time Data
To obtain input from a terminal, you can use #INPUTV, #SET, VINSERT, or
#APPEND. The following function calls wait for input and store the input into
variable
:
#INPUTV
#SET
#APPEND
variable prompt
variable
[#INPUT
variable
[#INPUT
prompt-text
prompt-text
]
]
In addition, you can use #REQUESTER to read from a terminal. For additional
information about these built-in functions and commands, see the TACL ReferenceManual.
Data TypesTACL does not support explicit data type definitions except in STRUCT variables. If
you need to determine the data type of variable contents, such as whether the first
constant in a variable is a number or a text constant, you can check to see if the type
matches one of the alternatives supported by the #ARGUMENT built-in function. You
can access a routine that contains an #ARGUMENT call from any type of procedural
variable. For more information, see “Processing Arguments” in Section 3,
“Developing TACL Routines.”
Accessing Time DataThe system clock keeps track of time as a numeric value known as a timestamp. TACL
supports timestamps in four formats for arithmetic operations, comparisons, and
display purposes.
Timestamp FormatsThe four timestamp formats differ in content and form:
Julian timestamp, a four-word timestamp based on the Julian calendar. This
timestamp represents the number of microseconds since 12:00 January 1, 4713 B.C,
using Greenwich mean time (GMT). A GMT timestamp is stored as a four-word
timestamp; for example:
The Julian date includes a Julian day number—the integral number of days since
January 1, 4713 B.C. The operating system assumes that the Julian day number
starts at midnight local or Greenwich mean time, depending on the base of the
timestamp.
107365 Tandem Computers Incorporated2–17
211479971400000000
Developing TACL Programs
Accessing Time Data
Local timestamp, a three-word timestamp. This timestamp represents the number
of centiseconds (.01 second) since 00:00 December 31, 1974. An example is:
45553140000
A local timestamp can represent one of the following three time zones:
Local civil time (LCT): The time of day locally. This is in either standard time
or daylight-saving time, depending on the area and the time of year.
Local standard time (LST): The time of day expressed in standard time.
Local daylight time (LDT): The time of day expressed in daylight-saving time.
The daylight-saving time system extends the amount of daylight in the
evenings by advancing the civil time. Usually, but not always, this is done in
hour increments.
Numeric date, a space-separated list in Gregorian date form—year, month, day,
hour, minute, second, and fraction of a second. If obtained for a Julian timestamp,
the list starts with the Julian day number. Examples include:
1992 4 28 22 59 17 88—converted from a three-word timestamp
2447635 1992 4 28 22 59 17 88—converted from a four-word timestamp
Textual date, in Gregorian form, such as:
May 7, 1992 08:30:00
Retrieving a TimestampUse the following built-in functions to retrieve date and time information from the
system:
#JULIANTIMESTAMP obtains the current timestamp, in Julian (four-word)
format.
#TIMESTAMP obtains the current timestamp, in local (three-word) format.
For example:
14> #TIMESTAMP
#TIMESTAMP expanded to:
54861863444
15> #JULIANTIMESTAMP
#JULIANTIMESTAMP expanded to:
211573083848182841
2–18107365 Tandem Computers Incorporated
Developing TACL Programs
Accessing Time Data
Converting a TimestampAs noted previously, you can retrieve timestamps from the system in a three-word or
four-word format. In addition, the #FILEINFO function returns timestamps in a threeword or four-word format, depending on the option you select. After you obtain the
timestamp, you can include it in a function call, use it for calculations, or display it.
Use the functions and commands in Table 2-4 to convert between time and date
representations. CONTIME is an abbreviation for converted time.
Table 2-4. Timestamp Conversion Functions
Starting TimestampEnding TimestampFunction
Four-word (Julian)Numeric date, including Julian day#INTERPRETTIMESTAMP
Three-wordNumeric date#CONTIME
Numeric dateFour-word#COMPUTETIMESTAMP
Numeric dateJulian day number#COMPUTEJULIANDAYNO
Three-wordFour-word#CONVERTTIMESTAMP
Four-wordThree-word#CONVERTTIMESTAMP
Julian day numberNumeric date#INTERPRETJULIANDAYNO
Numeric dateTextual date_CONTIME_TO_TEXT
Numeric dateTextual date without time_CONTIME_TO_TEXT_DATE
Numeric dateTextual time_CONTIME_TO_TEXT_TIME
In addition, the _MONTH3 function translates a two-digit month number to a threeletter month abbreviation.
Figure 2-7 shows the TACL functions that transform system timestamps from fourword and three-word formats to display format. Figure 2-8 shows how to convert
timestamps returned by #FILEINFO into different formats.
107365 Tandem Computers Incorporated2–19
Developing TACL Programs
Accessing Time Data
Figure 2-7. Relationships Between System Timestamps and TACL Functions
== There are 8640000 hundredths of a second in a day.
== Determine how many days have elapsed since
== midnight, December 31st, 1974 (starting timestamp).
#SET elapsed^days [#COMPUTE [#TIMESTAMP]/8640000]
== Determine how many whole weeks have elapsed.
#SET elapsed^weeks [#COMPUTE [elapsed^days]/7]
== The day of the week is the total elapsed days minus the
== number of days in the elapsed whole weeks.
#SET day^of^week [#COMPUTE [elapsed^days] ([elapsed^weeks]*7)]
== Output the day
[#CASE [day^of^week]
|0| #OUTPUT Tuesday
|1| #OUTPUT Wednesday
|2| #OUTPUT Thursday
|3| #OUTPUT Friday
|4| #OUTPUT Saturday
|5| #OUTPUT Sunday
|6| #OUTPUT Monday
|OTHERWISE|
#OUTPUT Error: Day of week must be 0-6 inclusive
]
#UNFRAME
2–22107365 Tandem Computers Incorporated
Developing TACL Programs
Accessing Time Data
Converting Timestamps Into Different Formats
The macro in Figure 2-10, getdates, converts the current date from a three-word
timestamp to SQL format (yyyy-mm-dd), for use by report generators or other
programs. This type of macro could be used to generate SQL reports.
Figure 3-9 in Section 3, “Developing TACL Routines,” contains a modification of this
example that shows how a nested routine can return dates as results.
Figure 2-10. Converting Timestamps
?SECTION getdates MACRO
#FRAME
== Save the current setting of #OUTFORMAT,
== so that it can be restored later:
#PUSH #OUTFORMAT #INFORMAT
[#PUSH
date == starting date (30 days ago)
yyyy == year
mm == month
dd == day
]
#SET #OUTFORMAT PRETTY
== Get the date and convert to yyyy mm dd calendar format:
#SETMANY yyyy mm dd, [#CONTIME [#TIMESTAMP]]
== Store as yyyy-mm-dd format (SQL date format):
#SET date [yyyy]-[mm]-[dd]
== Display the results to the user
#OUTPUT The reports will use a date of [date]
{ place report-generation code here}
#UNFRAME
107365 Tandem Computers Incorporated2–23
Developing TACL Programs
Accessing Terminals
Accessing TerminalsYou can use TACL to read and write from a terminal. Sample operations include:
Defining function keys
Sending escape sequences to a terminal
Changing the TACL prompt
Implementing menus
In addition, you can write programs that execute one or more commands that you use
frequently. The Guardian User's Guide describes how to create command definitions;
these definitions are typically alias or macro variables.
Defining Function KeysTACL recognizes 16 function keys. In the unshifted position they are named F1
through F15 (TACL predefines F16 as its help key). In the shifted position the function
keys are named SF1 through SF16. You can define each function key to perform a
sequence of operations that are useful in your environment. For example, you could
specify F1 as TIME and F2 as FILES.
To define function keys, create an edit-format file that contains definitions for each
function key you want to define. You then load the file (or refer to it from your
TACLCSTM file so that it is loaded when you log on).
Function key definitions are typically ALIAS variables (if you are providing an alias
for a single command or built-in function) or MACRO variables (for more complex
operations). For example, you can redefine #LOGOFF with an alias, but for
#LOGOFF/SEGRELEASE/ you must use a macro variable. The following code
defines two alias variables:
?SECTION f1 ALIAS
TIME
?SECTION f2 ALIAS
FILES
You can, additionally, define characters or sequences of characters that perform a
sequence of operations. For example, the following macro performs a FILENAMES
operation on the specified subvolume (or on the current subvolume, if the user does
not specify a subvolume):
?SECTION fn MACRO
FILENAMES %*%
To perform the FILENAMES operation, type FN.
The following macro prints a file to $S.#LP:
?SECTION pr MACRO
FUP COPY %*%, $S.#LP
To print a file, type PR
For more information about defining function keys, see the Guardian User's Guide.
2–24107365 Tandem Computers Incorporated
filename
.
Developing TACL Programs
Accessing Terminals
Sending Escape
Sequences to a Terminal
The 6530 terminal and devices that emulate the 6530 terminal recognize a set of escape
characters that allow you to control cursor position, set the size and video attributes of
characters displayed on the screen, and perform other operations. Most escape
sequences have the following format:
escape-character number [number]
The escape character is the 27th character in the ASCII character set. To specify an
escape sequence, store binary values as their decimal equivalents in a STRUCT or
DELTA variable. The easiest way to send these values to your terminal is to use
#OUTPUT.
The following examples use STRUCT variables to store escape sequences. To specify
an escape sequence in a STRUCT variable, set a BYTE value to the decimal value of the
escape character and the numbers that perform the desired operation.
To define an escape sequence using #DELTA, specify a decimal number followed by
the I command; for information about #DELTA, see the TACL Reference Manual.
Use the macro in Figure 2-11, display, to define several escape sequences and send
them to the home terminal. To run this macro, load the file and type display. The
macro displays a series of lines with different display attributes.
Figure 2-11. Sending Special Characters to a Screen (Page 1 of 2)
?SECTION display MACRO
#FRAME
== Define escape sequences
[#DEF ascii STRUCT
BEGIN
BYTE byt0 VALUE 7;
CHAR bell REDEFINES byt0;
BYTE byt1 VALUE 27;
CHAR esc REDEFINES byt1;
BYTE byt2a VALUE 36;
CHAR dollar REDEFINES byt2a;
BYTE byt2 VALUE 37;
CHAR perc REDEFINES byt2;
BYTE byt3 VALUE 38;
CHAR amp REDEFINES byt3;
BYTE byt4 VALUE 64;
CHAR at REDEFINES byt4;
BYTE byt5 (0:1) VALUE 27 73; == clear screen
CHAR clr (0:1) REDEFINES byt5; == escape sequence
END;
] == End ascii
107365 Tandem Computers Incorporated2–25
Developing TACL Programs
Accessing Terminals
Figure 2-11. Sending Special Characters to a Screen (Page 2 of 2)
== Clear the screen
#OUTPUT [ascii:clr(0:1)]
#OUTPUT The screen was just cleared.
== Display text with special video attributes
#OUTPUT Blinking text: [ascii:esc]6b These words are &
blinking[ascii:esc]6[ascii:at]
#OUTPUT Inverted text: [ascii:esc]6[ascii:dollar]These words&
are inverted [ascii:esc]6[ascii:at]
#OUTPUT Inverted text: [ascii:esc]6[ascii:perc]These words &
are inverted and dim [ascii:esc]6[ascii:at]
#OUTPUT [ascii:esc]o[ascii:esc]6[ascii:amp]These words are &
inverted blinking in line 25[ascii:esc]6[ascii:at]
#OUTPUT Here is the bell...[ascii:bell]
#OUTPUT And this is normal text.
#UNFRAME
Figure 5-10, in Section 5, “Initiating and Communicating With Processes,” contains a
sample routine that writes to line 25 of a specified terminal.
2–26107365 Tandem Computers Incorporated
Developing TACL Programs
Accessing Terminals
Use the routine in Figure 2-12, displayinfo, to list a screen full of lines and prompt
the user to continue. To use this routine, load the associated file and enter:
displayinfo
This routine does not display an entire screen of text, but shows how the prompt
works.
Figure 2-12. Displaying a Screen of Text
?SECTION displayinfo ROUTINE
#FRAME
#PUSH help_input help_prompt
[#DEF ascii STRUCT
BEGIN
BYTE byt0 (0:1) VALUE 27;
CHAR esc (0:1) REDEFINES byt0;
BYTE byt1 (0:1) VALUE 84;
CHAR rdf1 (0:1) REDEFINES byt1; == roll down
BYTE byt2 (0:1) VALUE 75;
CHAR rdf2 (0:1) REDEFINES byt2; == erase to end of line
END;
]
#SET help_prompt PRESS CTRL/Y to exit or any other key to &
continue:~
#OUTPUT Sample list text...
#OUTPUT Line 2...
#OUTPUT Line 3...
#INPUTV help_input help_prompt
== The following code erases the prompt
== and resumes output on the line where the prompt was.
[#IF [#INPUTEOF] |THEN|
#OUTPUT [ascii:esc][ascii:rdf1][ascii:esc][ascii:rdf2]&
[ascii:esc][ascii:rdf1]
|ELSE|
#OUTPUT Display more text...
#OUTPUT Line 2...
#OUTPUT Line 3...
]
#UNFRAME
107365 Tandem Computers Incorporated2–27
Developing TACL Programs
Accessing Terminals
Use the macro in Figure 2-13, lock, to lock a terminal until the user types the
password.
Figure 2-13. Locking a Terminal
?SECTION lock MACRO
#FRAME
#PUSH pw == password
#PUSH prompt == prompt variable
#PUSH rslt == result of #CHANGEUSER call
#PUSH userinfo == result of USERS call
#PUSH line
#SET rslt 0
== Define the clear screen escape sequence
[#DEF ascii STRUCT == Clear the screen
BEGIN
BYTE byt0 (0:1) VALUE 27 73; == decimal escape-I
CHAR clear (0:1) REDEFINES byt0;
END;
]
#OUTPUT [ascii:clear(0:1)]
== Disable break mode
#SET #BREAKMODE DISABLE
== Obtain information about the current user
USERS /OUTV userinfo/
#EXTRACTV userinfo line
#EXTRACTV userinfo line
[#SET prompt Password for [#USERNAME
[#CHARGET userinfo 22 FOR 8]]: ]
== Read a password (no echo) and attempt to log on:
[#LOOP |DO|
#INPUTV /NOECHO/ pw prompt
#SET rslt [#CHANGEUSER [#USERNAME [#CHARGET userinfo &
22 FOR 8]] [pw]]
[#IF NOT [rslt] |THEN| == An error occurred
#OUTPUT Invalid password!
]
|UNTIL| rslt
]
== After a successful logon, enable break mode and exit the
== macro:
#SET #BREAKMODE ENABLE
#UNFRAME
2–28107365 Tandem Computers Incorporated
Developing TACL Programs
Accessing Terminals
Changing the TACL PromptThe SETPROMPT command allows you to change the standard TACL prompt so that
it includes the current volume or subvolume name.
To make additional modifications, define a variable called _PROMPTER that contains
the definition of the prompt. Within the _PROMPTER variable, set the #PROMPT
built-in variable to the desired prompt text. To cause TACL to invoke _PROMPTER
prior to displaying a prompt, set the #PREFIX built-in variable to -1.
To save the previous prompt, push the #PREFIX built-in variable before you set
#PREFIX to the new prompt text.
The following code displays the node name, volume, and subvolume in the TACL
prompt:
#SET #PROMPT -1
[#DEF _PROMPTER TEXT |BODY| #SET #PREFIX [#DEFAULTS]]
When you are working on your local system, the prompt looks like this:
$DATA.SVOL 10>
When you have used the SYSTEM command or #SYSTEM built-in function to access
another node, the prompt looks like this:
\RSYS.$DATA.SVOL 10>
To install the prompt whenever a user logs on, add a section to the user's macro
definition file:
?SECTION _PROMPTER MACRO
#SET #PREFIX [#DEFAULTS]
Add the following line to the TACLCSTM file:
#SET #PROMPT -1
Alternatively, you could use the FILEINFO command to obtain the node name,
volume, and subvolume.
For more information about #PROMPT and #PREFIX, see the TACL Reference Manual.
107365 Tandem Computers Incorporated2–29
Developing TACL Programs
Accessing Terminals
Implementing MenusYou can use TACL to define menus. A menu displays a screen and allows users to
press function keys to access information and utilities.
Use the text variable in Figure 2-14, menu, to generate a menu. The user can press
function keys to start applications and utilities. Note that the menu text could be
displayed by individual #OUTPUT calls within the #LOOP function; setting
displayvar to the display text avoids multiple #OUTPUT calls. To run this code,
load the file that contains the code and type menu.
Figure 2-14. Displaying a Menu (Page 1 of 2)
?SECTION menu TEXT
#FRAME
[#PUSH prompt prompt1 prompt2 fkey temp temp2
displayvar done
]
#PUSH #OUTFORMAT == Save the current value
#SET #OUTFORMAT PRETTY
#SET done 0
#SET prompt Please select a function key:~_~_
#SET prompt1 Type file name, followed by <return> :~_~_
#SET prompt2 Type printer name ($S.#AD is the default) :~_~_
[#APPENDV displayvar
"**************************************************
~_
~_
~_
TANDEM APPLICATION MENU
~_
F1 PSMail
F2 TEDIT
F3 TGAL Document Processor
F4 Peruse
F5 TFORM Document Processor
~_
~_
~_
~_
~_
~_
~_
SF1 Exit to TACL
SF16 Log off
~_
Version III 6/92
**************************************************"
]
Debugger CommandsWhen tracing is on, the TACL trace facility invokes the _DEBUGGER function prior to
The TACL debugger shows how TACL interprets code. It provides step-by-step
execution, examination of control flow, and examination and modification of variables.
The debugger is a separate function, invoked by TACL upon request.
For information about how to debug #DELTA code, see “#DELTA Built-In Function”
in the TACL Reference Manual.
You can enable the debugger interactively or from within a macro or routine:
At a TACL prompt, after loading a macro or routine variable, but before invoking
it, type:
10> BREAK
From within a macro or routine, type the following to enable the debugger:
#SET #TRACE -1
When you enable the debugger, TACL waits for an instruction before it performs its
first expansion. At this point, you can set breakpoints and either resume execution or
step through the code.
invoking a variable. The debugger displays the current history number:
-
nnn
-
At this point, you can enter a command. If you enter a TACL command, the debugger
passes the command to TACL for execution. If you enter a _DEBUGGER command,
_DEBUGGER executes the command. Table 2-5 lists _DEBUGGER commands.
variable
Table 2-5. _DEBUGGER Command Syntax
CommandDescription
B[REAK] [variable]Sets a breakpoint on the specified variable or variable level. If you omit
variable, TACL lists all breakpoints. Whenever you invoke variable,
TACL stops executing the code and waits for input from your debugging
terminal.
C[LEAR] [variable | *]Clears the breakpoint for the specified variable or variable level. If you
specify an asterisk (*), TACL clears all breakpoints.
D[ISPLAY] variableDisplays the contents of the specified variable or variable level.
M[ODIFY] variableAllows you to enter new contents for the specified variable or variable
level.
R[ESUME]Resumes execution until the next breakpoint or until TACL finishes
executing code.
ST[EP]Performs one expansion. To step through the function, press the
RETURN key after each subsequent prompt.
2–32107365 Tandem Computers Incorporated
Developing TACL Programs
Debugging TACL Programs
To reenter the debugger after using STEP, set a breakpoint on a variable that will be
invoked later in your program. Next, type RESUME to run your program until TACL
encounters the breakpoint or finishes the program. Note that setting a variable (such
as #SET x 123) is not an invocation of the variable; [x] is an invocation of the
variable.
To end a debugging session, clear all breakpoints and type RESUME.
The following considerations apply to use of the debugger:
The debugger is itself a TACL variable. Any inputs that are not debugger
commands are assumed to be TACL commands, variables, or built-in functions.
Commands such as #UNFRAME can influence the routine that is being debugged.
Debug commands must reference declared variables. The TACL debugger
displays each line before it is evaluated; therefore, a declaration (#PUSH) is in
effect when the debugger is displaying a line that follows the #PUSH function.
To set a breakpoint, specify a variable that will be invoked at a later point in the
debugging session. The variable may be used by the function you will debug or
by a later invocation from within the program, but it must be defined when you
set the breakpoint.
NoteYou cannot set a breakpoint on a variable that is located in a read-only segment file such as TACLSEGF.
A Sample Debugging
Session
Use the routine in Figure 2-15, tedsave, as sample code for the interactive debugging
session described following Figure 2-15.
The routine in Figure 2-15 invokes TEDIT for a file supplied as the argument. The
syntax for this routine is:
tedsave
file-name
The example in Figure 2-15 includes the use of #ARGUMENT, which is described in
Section 3, “Developing TACL Routines.” To perform the same work from a macro,
107365 Tandem Computers Incorporated2–33
Developing TACL Programs
Debugging TACL Programs
without accessibility to the #ARGUMENT built-in function, you would need to check
that the argument is a valid file name.
Figure 2-15. Starting TEDIT From TACL
?SECTION tedsave ROUTINE
#FRAME
#PUSH editfile
== Retrieve the first argument and place it into editfile:
[#CASE [#ARGUMENT /VALUE editfile/ FILENAME /SYNTAX/
OTHERWISE]
|1|
TEDIT [editfile]
#OUTPUT DONE WITH [#FILEINFO /FULLNAME/ [editfile]]
|2|
#OUTPUT *** Error: invalid filename ***
] == end #CASE
#UNFRAME
When you run tedsave , it displays output similar to the following:
>2 tedsave sect08
Control passes to TEDIT. After the user exits from TEDIT, the routine displays:
DONE WITH $VOL.SUBVOL.SECT08
The following paragraphs describe a sample debugging session. The tedsave routine
is already loaded into memory:
3> BREAK tedsave
4> tedsave sect08
tedsave sect08
^
-BREAK-
On line 5, the user issues a STEP command and _DEBUGGER displays the next line of
the routine. The user then presses RETURN to continue stepping through the routine;
when the user steps through the routine in this way, the line number does not advance
(lines that show nothing but a line number are terminated by RETURN):
The user issues a DISPLAY command to see the contents of the variable EDITFILE and
sets a breakpoint on that variable:
-6-DISPLAY editfile
sect08
-7-BREAK editfile
The RESUME command terminates the debug mode, and processing continues until
the routine is ready to invoke EDITFILE, at which point the set breakpoint invokes
_DEBUGGER again, which displays the word -BREAK- to show why it was invoked:
-8-RESUME
TEDIT editfile
-BREAK-
The user displays the contents of EDITFILE again, clears the breakpoint, and resumes
normal processing:
-9-DISPLAY editfile
sect08
-10-CLEAR editfile
-11-RESUME
Control passes to TEDIT. After you exit,
the routine displays:
DONE WITH $VOL.SUBVOL.SECT08
To modify a variable during a debugging session, use the MODIFY command. After
entering the new value, press RETURN, then enter CTRL/Y to signify that there is no
more input. At prompt 10, in the previous example, you could type the following to
change the name of the edit file:
-10-MODIFY editfile
Input new contents of :EDITFILE.1; end with eof
-:EDITFILE.1-sect09
-:EDITFILE.1-EOF!
-11-D editfile
sect09
-12-
By using the MODIFY command, you can determine how a change affects the
program. You can also force choices based on variable values without having to
change the function and rerun it. For example, you can alter the contents of the text in
a #CASE function to force TACL to take a path that you want to test.
107365 Tandem Computers Incorporated2–35
Developing TACL Programs
Debugging TACL Programs
(This page left intentionally blank)
2–36107365 Tandem Computers Incorporated
3Developing TACL Routines
TACL routines provide features that you cannot obtain from any other type of TACL
variable. In a routine, you can:
Use #ARGUMENT to check the syntax and validity of several types of arguments
or to parse data within your program
Use #RESULT to return a specific result (instead of an expansion of text)
Use #ROUTINENAME to obtain the name of the active routine, for issuing
recursive calls
Use #RETURN to exit from any location in the routine
Create an exception handler that processes events or errors
The following subsections describe how to use these features.
Processing ArgumentsWhen you invoke a routine, you can include a list of arguments after the routine name.
A routine does not, however, access these arguments in the same manner as macro
arguments (%n%). Instead, in your routine, you specify an #ARGUMENT function
with a list of argument alternatives. The #ARGUMENT function steps through the list
and checks to see if the current argument matches a specified alternative. If the
argument matches, #ARGUMENT returns an index to the alternative and optionally
stores the argument in a variable for use within the routine.
The following statement checks to see if the next argument is a valid subvolume name
(SUBVOL alternative) or system name (SYSTEMNAME alternative):
#SET num [#ARGUMENT /VALUE name/ SUBVOL SYSTEMNAME]
If the argument is a valid subvolume name, #ARGUMENT assigns 1 to num, indicating
that the argument is a subvolume name, and stores the qualified argument in name.
(The VALUE option affects how the #ARGUMENT built-in function stores the
argument. For more information, see the TACL Reference Manual.)
The following examples show differences between argument processing in macros and
routines. The programs support the following syntax:
process_argm
process_argr
file-name
file-name
107365 Tandem Computers Incorporated3–1
Developing TACL Routines
Processing Arguments
To process the f
ile-name
argument from a macro:
?SECTION process_argm MACRO
== This macro does not check argument type or validity.
== Separate coding is required to validate the argument.
#FRAME
#PUSH fname
== Store the first argument in fname.
#SET fname %1%
#OUTPUT File name is [fname]
#UNFRAME
To process the
file-name
argument from a routine:
?SECTION process_argr ROUTINE
== This routine checks for correct file name syntax and
== existence of the named file.
#FRAME
#PUSH fname rslt
== Check to see if the first argument is a valid file name
== for an existing file. If so, store it in fname.
#SET rslt [#ARGUMENT /VALUE fname/ FILENAME OTHERWISE]
[#IF rslt = 1 |THEN| == valid filename
#OUTPUT File name is [fname]
|ELSE|
#OUTPUT *** Invalid filename ***
]
#UNFRAME
NoteThe OTHERWISE alternative allows you to handle invalid arguments within your program.
#The routine performs more error checking. If, the user does not supply an argument,
or if the file does not exist, the routine returns an error. In contrast, the macro
continues with an invalid file name.
The resulting argument text may be different between macros and routines. In the
previous example, the macro outputs exactly what it was given:
39> process_argm thisfile
File name is thisfile
The routine, because of the VALUE option in the #ARGUMENT call, returns the fully
qualified file name. For example:
40> process_argr thatfile
File name is \NODE.$VOL.SUBVOL.THATFILE
3–2107365 Tandem Computers Incorporated
Developing TACL Routines
Processing Arguments
Table 3-1 lists the built-in functions that support arguments to routines.
Table 3-1. Functions That Support Arguments
FunctionDescription
#ARGUMENTAllows you to define a list of argument types. Compares each argument
against these types. If an argument matches a specified type,
#ARGUMENT returns a number that indicates the position of the argument
type in your list of types. You can optionally specify a variable that will
contain the contents of the argument.
#GETSCANReturns the number of characters that #ARGUMENT has processed, not
including the routine name and the first character after the name.
#MOREDetermines whether an entire argument set has been processed.
#RESETSets the argument pointer to the beginning of the argument list.
#RESTReturns the number of unprocessed arguments.
#SETSCANSpecifies the position at which the next #ARGUMENT function will resume
processing arguments.
How #ARGUMENT WorksUse the #ARGUMENT built-in function to specify data types and, in some cases,
entities as arguments. When invoked, #ARGUMENT steps through the list of
supplied arguments.
#ARGUMENT Options
The #ARGUMENT built-in function supports the following options:
PEEK processes an argument but keeps the internal argument pointer at the
current argument.
TEXT specifies a variable to contain an exact copy of the argument.
VALUE specifies a variable to contain the TACL interpretation of the argument
sequence. For example, FILENAME returns a fully-qualified file name, using
defaults if the user did not specify all components of the file name.
You specify options within slashes (/) after #ARGUMENT.
#ARGUMENT Alternatives
Argument types are called alternatives. You specify alternatives after options and
their associated slashes. Alternatives include:
Contiguous characters (CHARACTERS), a string (STRING), or a number
(NUMBER)
Special characters, including “/” (SLASH), “(“ (OPENPAREN), “)”
(CLOSEPAREN), and “,” (COMMA)
Keywords defined in the routine (KEYWORD), such as TYPE or AGE
107365 Tandem Computers Incorporated3–3
Developing TACL Routines
Processing Arguments
Using #ARGUMENTTo define a fixed order for arguments, use a sequence of #ARGUMENT statements.
File names (FILENAME), DEFINE names and attribute names (DEFINENAME
and ATTRIBUTENAME), process names (PROCESSNAME), system names
(SYSTEMNAME), and user names (USER)
Subsystem IDs (SUBSYSTEM) and text for SPI and EMS tokens (TOKEN)
Some alternatives allow you to limit processing to syntax checking. For example, the
FILENAME alternative looks for the name of an existing file. If, however, you specify
FILENAME /SYNTAX/, the #ARGUMENT built-in function searches for a file name
that is formatted correctly; it does not check for the existence of the file.
If an argument does not match any of the listed alternatives, a TACL error occurs
unless you specify the OTHERWISE alternative. If you use OTHERWISE, an invalid
argument does not produce a TACL error; your routine must retrieve and examine the
invalid argument and determine an appropriate action.
The following statements search for a file name, followed by a slash, followed by a
variable name of type text:
The VALUE options cause the #ARGUMENT built-in functions to store the actual
argument in the specified variable. If there is an error, the program ends with an
error; otherwise, the SINK calls suppress the results of the #ARGUMENT calls. (Each
#ARGUMENT statement processes one type of argument, so the result is always 1
unless an error occurs.)
3–4107365 Tandem Computers Incorporated
Developing TACL Routines
Processing Arguments
To process several types of arguments entered in any order, use a #CASE statement.
Use the routine in Figure 3-1 to process zero or more of the following:
File attribute names (defined in ALL)
Numbers
Figure 3-1. Processing Arguments
?SECTION mult_args ROUTINE
#FRAME
#PUSH stat count end
#SET count 0
#SET end 0
[#DEF attributes TEXT |BODY|
Type Size Age Owner Security
]
#OUTPUT Entered arguments were: [#REST]
[#LOOP |DO|
#SET count [#COMPUTE [count] + 1]
[#CASE [#ARGUMENT/VALUE stat/
KEYWORD/WORDLIST [attributes]/ NUMBER END OTHERWISE]
|1|
#OUTPUT Argument [count] is the keyword [stat].
|2|
#OUTPUT Argument [count] is the number [stat].
|3|
#SET end 1
|4|
#OUTPUT *** Invalid argument ***
#SET end 1
]
|UNTIL| (NOT [#MORE]) OR end
]
#UNFRAME
Using #ARGUMENT for Data Within a Program
TACL itself does not provide data type declarations and functions, but you can write a
function that uses #ARGUMENT to determine the type and return the information.
The following routine returns TRUE (not zero) if you pass it a number; otherwise, it
returns FALSE:
?SECTION anumber ROUTINE
#RESULT [#COMPUTE NOT ([#ARGUMENT NUMBER OTHERWISE] - 1)]
Variations on this routine could return TRUE for text or special characters, a number
that reflects a group of argument types, or an index into the entire set of
#ARGUMENT alternatives.
107365 Tandem Computers Incorporated3–5
Developing TACL Routines
Processing Arguments
The following examples illustrate two ways to retrieve a number from a position
within a line of text (as returned by FUP or other processes). First, you can use the
#CHARGET function:
#PUSH pfree line
#SET line This is a test number: 53
#SET pfree [#CHARGET line 24 FOR 2]
#OUTPUT [pfree]
The preceding code retrieves two characters from line, but does not check that the
two characters are numbers. The number at position 24 must be two characters long;
the code returns two digits even if the number has a single digit or three digits.
As an alternative, you can define a routine that uses #ARGUMENT.
?SECTION getnumber ROUTINE
#FRAME
#PUSH rslt arg position
== First, get the requested character position
#SET rslt [#ARGUMENT /TEXT position/ NUMBER OTHERWISE]
[#CASE [rslt]
|1|
== position is OK
|2|
== Caller did not supply a number for position arg.
#RESULT -1
#RETURN
]
== Skip [position] characters
SINK [#ARGUMENT CHARACTERS /WIDTH [position]/ ]
#SET rslt [#ARGUMENT /TEXT arg/ NUMBER OTHERWISE]
[#CASE [rslt]
|1|
#RESULT 0 [arg]
|2|
== Invalid argument; text at specified position is
== not a number
#RESULT -2
]
#UNFRAME
If getnumber finds a number, it returns a zero followed by the requested number. If
position is invalid, it returns -1; otherwise, it returns -2.
3–6107365 Tandem Computers Incorporated
Developing TACL Routines
Processing Arguments
You could call this routine from your program:
?SECTION caller ROUTINE
#FRAME
== call getnumber with the starting position
== and the line of text
#PUSH pfree position line
#SET line This is a test number: 53
#SET position 23
The routine performs more checking than #CHARGET and is more flexible with the
length of a space-separated number. The routine, however, takes longer to write,
making it most useful if you plan to perform this action many times in your program.
Processing File Name Arguments
The following routine parses an OUT option enclosed in slashes. The routine first
checks for a slash (/). If present, the routine checks for the word OUT, followed by a
file name and an ending slash. The routine then sets the TACL OUT file to the file
specified in the argument list. If the user does not specify an OUT option, this routine
displays the current setting of the OUT file. To run the routine, type the name of the
file that contains the code:
?TACL ROUTINE
#FRAME
#PUSH out outfile
[#CASE [#ARGUMENT SLASH END OTHERWISE]
|1| == Found the first slash character
SINK [#ARGUMENT KEYWORD /WORDLIST out/]
SINK [#ARGUMENT /VALUE outfile/ FILENAME /SYNTAX/]
#OUTPUT [outfile]
SINK [#ARGUMENT SLASH]
SINK [#ARGUMENT END]
#PUSH #OUT
#SET #OUT [outfile]
|2| == No arguments; display the current OUT file
#OUTPUT The current OUT file is [#OUT]
|OTHERWISE| == Unknown argument
#OUTPUT Invalid argument
]
#OUTPUT [outfile]
#UNFRAME
107365 Tandem Computers Incorporated3–7
Developing TACL Routines
Processing Arguments
The following routine expects both a file name and a properly formatted variable
name, but accepts them in either sequence. To run this routine, type the name of the
file that contains this code:
If you run wordlist interactively, load the file that defines wordlist and use
#OUTPUT(V) to display the result:
15> #OUTPUT [wordlist a b c]
a, b, c
16>
For information about #RESULT, see “Returning Results,” later in this section.
3–8107365 Tandem Computers Incorporated
Developing TACL Routines
Processing Arguments
Processing Arguments Recursively
You can use the #ROUTINENAME built-in function to process arguments recursively.
For more information, see “Calling a Routine Recursively,” later in this section.
Examining the Contents of
Arguments
The following routines examine the contents of arguments. These routines return
results; if you use the routines interactively, use #OUTPUT(V) to display results.
Use the routine in Figure 3-2, first, to retrieve a specified number of characters in a
variable. The syntax is:
== Enclose the following in brackets, in case the result
== contains more than one line
[#RESULT [#CHARGET [var] 1 FOR [num]]]
#UNFRAME
To obtain the contents of a multiple-line variable, enclose your statement in square
brackets. If, for example, x contains the following:
abcde
fgh
you can display the contents of x (including the line break character at the end of the
first line) with the following statement:
15> [#OUTPUT [first x 9]]
abcde
fgh
16>
The result includes an end-of-line character. For information about #RESULT, see
“Returning Results,” later in this section.
Use the routine in Figure 3-3, substring, to retrieve characters from position
number1
to position
substring
number2
of a variable. The syntax is:
variable number1 number2
In this and the following three examples, the #RESULT function call is enclosed in
brackets in case the #CHARGET built-in function returns more than one line.
107365 Tandem Computers Incorporated3–9
Developing TACL Routines
Processing Arguments
Figure 3-3. Returning a Set of Characters From a Variable
?SECTION substring ROUTINE
#FRAME
#PUSH bgn end var
[#RESULT [#CHARGET [var] [bgn] TO [end]]]
#UNFRAME
NoteThis routine does not check to make sure that
more thorough argument validation, include that check.
Use the routine in Figure 3-4, scan, to scan for text and retrieve the first position,
starting at a specified position, where the text occurs in the variable. The syntax is:
scan
variable number text
Do not enclose
text
in double quotes unless the quotes are part of the text.
You can use the #ARGUMENT built-in function to provide a general parser for other
TACL programs. Figure 3-7 contains two sample programs:
getargs, a macro that parses arguments for a routine that calls it and returns the
value in a variable (the calling program supplies a name)
call_getargs, a routine that calls getargs
NoteGetargs is defined as a macro, and can be used only when called by a routine. Otherwise, the
#ARGUMENT call inside the macro is not valid.
107365 Tandem Computers Incorporated3–11
Developing TACL Routines
Processing Arguments
The syntax for getargs is:
getargs
where
triplet
{}
REQUIRED or OPTIONAL specifies whether the corresponding argument is
required or optional.
Type
must not permit spaces. The KEYWORD alternative, for example, cannot be used
because it requires the WORDLIST alternative, which allows spaces in its syntax.
Variable
variable with this name. Getargs pushes
argument is found; otherwise,
The following statement asks getargs to search for two arguments—one required
number and one optional text constant:
getargs REQUIRED NUMBER numvar OPTIONAL TEXT datavar
If getargs finds a numeric argument, it pushes num and stores the argument into
num . If getargs finds a text argument, it pushes data and stores the argument in
data .
Figure 3-7. Assigning Values to Arguments (Page 1 of 2)
triplet
contains three parts:
REQUIRED
OPTIONAL
is an #ARGUMENT alternative such as FILENAME. The specified type
is a name for the argument. Getargs stores the argument value in a
[
triplet
type variable
]...
variable
variable
is empty.
and sets it if a matching
?SECTION getargs MACRO
== Loop through all triplets
[#IF [#EMPTY %1%] |THEN|
== No more triplets; routine must have no more arguments
SINK [#ARGUMENT END] == Only valid if called by a routine
|ELSE|
#PUSH %3% == Push the variable
== Check first word of triplet for REQUIRED or OPTIONAL
[#CASE %1%
|optional|
[#IF [#EMPTY %4%] |THEN| == Check for more triplets
== No more triplets; argument cannot be followed by
== a comma
[#CASE [#ARGUMENT/TEXT %3%/ %2% END]
|1|
SINK [#ARGUMENT END]
|2|
#SET %3%
|3|
]
3–12107365 Tandem Computers Incorporated
Developing TACL Routines
Processing Arguments
Figure 3-7. Assigning Values to Arguments (Page 2 of 2)
|ELSE|
== More triplets; argument can be followed by a comma
[#CASE [#ARGUMENT/TEXT %3%/ %2% COMMA END]
|1|
SINK [#ARGUMENT COMMA END]
|2|
#SET %3%
|3|
]
] == end #IF
|required|
SINK [#ARGUMENT/TEXT %3%/ %2%] == Get required argument
[#IF [#EMPTY %4%] |THEN| == Check for more triplets
== No more triplets; argument cannot be followed by
== a comma
SINK [#ARGUMENT END]
|ELSE|
== More triplets; argument can be followed by a comma
SINK [#ARGUMENT COMMA END]
] == end #IF
] == end #CASE
== Call self again, without the current triplet.
%0% %4 TO *%
] == end #IF
Call_getargs supports the following syntax:
call_getargs
filename, filename [, number, number
]
107365 Tandem Computers Incorporated3–13
Developing TACL Routines
Processing Arguments
The following shows a sample invocation of call_getargs:
Returning ResultsFunction results come from one or more #RESULT built-in functions within the
routine. This is an important distinction between macros and routines: a macro
invocation returns the expansion of the text of the macro; a routine returns only what
the #RESULT function provides.
Use the macro in Figure 3-9, report_shell, to calculate today’s date and the date
thirty days ago and convert the dates to SQL format (yyyy-mm-dd). This example is
similar to Figure 2-10, but returns results. To run this macro, load the associated file
and enter:
report_shell
Figure 3-9. Converting Timestamps
?SECTION report_shell MACRO
#FRAME
#PUSH #OUTFORMAT #INFORMAT today
#SET #OUTFORMAT PRETTY
#SET #INFORMAT TACL
== Calling part of Macro
#OUTPUT This macro displays a start and end date.
#SETMANY today, [get_dates]
#OUTPUT
#OUTPUT The date is [today]
#UNFRAME
?SECTION get_dates ROUTINE
#FRAME
== Save the current setting of #OUTFORMAT,
== so that it can be restored later:
#PUSH #OUTFORMAT #INFORMAT
[#PUSH
date == starting date (30 days ago)
yyyy == year
mm == month
dd == day
]
#SET #OUTFORMAT PRETTY
== Get the date and convert to yyyy mm dd calendar format:
#SETMANY yyyy mm dd, [#CONTIME [#TIMESTAMP]]
== Store as yyyy-mm-dd format (SQL date format):
#SET date [yyyy]-[mm]-[dd]
== Return the result to the caller.
#RESULT [date]
#UNFRAME
107365 Tandem Computers Incorporated3–15
Developing TACL Routines
Calling a Routine Recursively
Calling a Routine
Recursively
#The #ROUTINENAME built-in function returns the name of the currently active
routine, which allows you to invoke a routine from within the routine. The function is
similar to accessing %0% from a macro, but you cannot use #ROUTINENAME in a
macro or %0% in a routine.
If you call #ROUTINENAME for a routine defined with a ?TACL ROUTINE directive,
#ROUTINENAME returns the name of the variable TACL uses to hold the active copy
of the routine.
Use the macro in Figure 3-10, caller, to process one or more arguments. To use this
macro, load the associated file and enter:
caller {
Caller calls proc_arg to process each argument. Proc_arg calls itself additional
[#CASE [rslt]
|1| == File name
FILEINFO [var1]
|2| == Keyword
#OUTPUT [#SHIFTSTRING /UP / [var1]] is a keyword
|3| == System name
#OUTPUT /HOLD/ The system number for [var1] is :
#OUTPUT [#SYSTEMNUMBER [var1]]
|4| == Word
#OUTPUT Expecting a file name, the word TACL, TAL,
#OUTPUT or PASCAL, or a system name.
#RETURN
]
[#IF [#MORE] |THEN|
#OUTPUT == blank line
[#ROUTINENAME] [#REST]
]
3–16107365 Tandem Computers Incorporated
Developing TACL Routines
Exiting From a Routine
Use the routine in Figure 3-11, argrec, to process one or more file names, checking
for syntax but not for file existence. File names can be separated by spaces or commas.
After processing each file name, the routine scans ahead and skips over commas. It
calls itself to process each additional file name.
Figure 3-11. Processing File Name Arguments
?SECTION argrec ROUTINE
#FRAME
#PUSH fn nextfn rslt
#SET rslt [#ARGUMENT /TEXT fn/ FILENAME /SYNTAX/ OTHERWISE]
[#IF [rslt] = 2 |THEN|
#OUTPUT *** Invalid filename ***
#RETURN
]
== Process the first argument
#OUTPUT current argument = [fn]
== Check for another file name
#SET rslt [#ARGUMENT /TEXT nextfn/ FILENAME /SYNTAX/ &
COMMA END OTHERWISE]
[#CASE [rslt]
|1|
|2 3|
== Next argument is a comma or end; ignore it
#SET nextfn
|OTHERWISE|
#OUTPUT *** Invalid argument ***
#RETURN
]
== If nextfn contains a file name or there are additional
== unprocessed arguments, call self, appending the results.
[#IF NOT [#EMPTY [nextfn] [#REST]] |THEN|
#RESULT [#ROUTINENAME] [nextfn] [#REST]
]
#UNFRAME
Exiting From a RoutineTo exit from a routine, use the #RETURN built-in function. #RETURN exits
immediately and does not reset any frames unless you specify #UNFRAME or
#RESET FRAMES prior to #RETURN.
You can use #RETURN to define several exit points within a routine. For examples of
the use of #RETURN, see the next subsection, “Writing an Exception Handler.”
107365 Tandem Computers Incorporated3–17
Developing TACL Routines
Writing an Exception Handler
Writing an Exception
Handler
An exception is an event or condition that requires special handling. If, for example, a
user presses the BREAK key or enters alphabetic data when a number is expected, an
exception occurs. TACL cannot detect a modem disconnect, but can detect and
process other exceptions, including ones you define. TACL recognizes three types of
exceptions:
Pressing the BREAK key
A TACL error, as defined in Section 2, “Developing TACL Programs.”
A user-defined exception, such as an end-of-file, for which special handling may
be necessary.
Any one of these exceptions causes TACL to search for an exception handler. An
exception handler is a portion of code that performs actions after an exception. For
example, if a TACL routine opens one or more files and then purges them when
finished, the user could press the BREAK key while the files are still open. TACL
would then close any open files, but would not purge them. If the routine contained
an exception handler, TACL could close the files before exiting. Activities of exception
handlers can include:
Issuing error messages
Resetting data defaults
Terminating open INLINE processes
Resetting frames or accumulated results
Purging scratch files
Performing INITTERM operations
Passing information to the calling routine
Returning control to the calling routine
If you declare local variables within the body of your routine, determine whether or
not to delete these variables within the exception handler.
If an exception occurs and the current routine has no exception handler, TACL exits
from the routine and returns control to the calling routine. TACL continues to
backtrack through the chain of calling routines, exiting routines as it goes, until it finds
a routine that can process the type of exception that occurred. TACL then reinvokes
that routine to process the exception. If TACL finds no such routine, it performs its
own exception handling—it resets frames and results and, if the exception is of type
_ERROR, displays an error message. Similarly, you can nest routines that contain
exception handlers. TACL uses the first exception handler that can process the type of
exception that occurred.
Exception handlers provide a way to release control and deallocate resources. In
addition, you can write an exception handler that does not permit a user to exit the
routine. In this manner, you can write command shells that define a set of commands
available to users.
3–18107365 Tandem Computers Incorporated
Developing TACL Routines
Writing an Exception Handler
Types of Exception
Handlers
Constructing an Exception
Handler
Exception handlers can be divided into two types, depending on how they return
control:
Release handlers that relinquish control to the calling procedure
Keep handlers that retain control regardless of exceptions (usually for security
purposes)
A routine can contain both types of exception handlers.
Use the built-in functions in Table 3-2 to construct exception handlers.
Table 3-2. Functions That Support Exception Handlers
FunctionDescription
#ERRORNUMBERSReturns the most recent TACL error.
#ERRORTEXTIntercepts error text that would have been written to the OUT file if there
had been no exception handler.
#EXCEPTIONReturns the type of exception that invoked the exception handler:
_CALL if the routine containing #EXCEPTION was invoked normally.
The name of the exception if the routine was invoked in response to an
exception that was listed in a #FILTER function.
#FILTERSpecifies the types of exceptions a routine can handle.
#RAISECauses an exception to occur.
#RETURNReturns immediately from the routine.
As shown in Figure 3-12, a routine that contains an exception handler has the
following structure:
It begins with a #CASE statement immediately after the ?SECTION directive. This
#CASE statement uses the #EXCEPTION built-in function to determine which
exception occurred. The #CASE statement includes the following:
The first label in the #CASE is _CALL. This exception occurs as part of normal
processing when a calling program invokes the routine.
Remaining labels identify the exceptions for which the handler can be
invoked. Each case contains statements that handle the associated type of
exception.
Do not place a #FRAME call before the #CASE statement.
The body of code for the routine follows the #CASE statement. This code includes
a #FILTER call that lists the exceptions for which this code is protected—and
which are defined as labels in the #CASE statement. You can change the setting of
#FILTER as necessary during processing to enable or disable processing of specific
exceptions.
The routine ends with an #UNFRAME function.
107365 Tandem Computers Incorporated3–19
Developing TACL Routines
Writing an Exception Handler
Figure 3-12. Sample Release Handler Template
?SECTION name ROUTINE
== Exception handler ==
[#CASE [#EXCEPTION]
|_CALL |
== No action required when first called
|_BREAK|
== Code to handle BREAK goes here
|_ERROR|
== Code to handle errors goes here
] == End CASE
== Beginning of body of routine ==
Creating a Release
Exception Handler
== Filter these exceptions:
#FILTER _BREAK _ERROR
== Body of executable code goes here
#UNFRAME
Keep and release handlers have slightly different structures, as shown in Table 3-3.
Table 3-3. Differences Between Keep and Release Exception Handlers
Keep Handler ContentsRelease Handler Contents
The #CASE statement:
The #CASE statement:
Contains a #FRAME and variable
declarations in the _CALL portion
Pushes global variables
Does not invoke #RESET
Does not contain a #FRAME
Does not push global variables
Invokes #RESET and #RETURN
The body of code ends with #UNFRAMEThe body of code starts with #FRAME and
ends with #UNFRAME
A release exception handler processes exceptions and returns to the calling procedure.
The _CALL path, taken when the routine is invoked by a calling program, typically
requires no action.
Use the routine in Figure 3-13, command_processor, as a sample release handler.
The routine requests commands from the user and allows the user to enter an ADD or
SUB command. The routine then displays the command.
The body of the routine begins with a #FRAME function call and #PUSH (or PUSH)
and #DEF entries to define variables, followed by a #FILTER function call that
declares the exceptions against which the code that follows is to be protected.
3–20107365 Tandem Computers Incorporated
Developing TACL Routines
Writing an Exception Handler
If the user presses the BREAK key while the processing loop is running, TACL raises
the _BREAK exception and reinvokes the routine. The #CASE function executes the
_BREAK case, displays a message, and exits. If the user enters anything other than
ADD or SUB, the #CASE in the loop raises _ERROR, and TACL reinvokes the routine;
in this situation, the #CASE function takes the _ERROR path, displays a message, and
exits. To invoke this routine, load the associated file and enter:
command_processor
Figure 3-13. Sample Release Handler
?SECTION command_processor ROUTINE
== Exception handler ==
[#CASE [#EXCEPTION]
|_CALL |
== No action required when first called
|_BREAK|
#OUTPUT BREAK key pressed.
#RESET RESULTS FRAMES
#RETURN
|_ERROR|
#OUTPUT Input error occurred.
#RESET RESULTS FRAMES
#RETURN
] == End CASE
== Beginning of body of routine ==
#FRAME
#PUSH cmd
== Filter predefined exceptions only
#FILTER _BREAK _ERROR
== Processing loop: runs until invalid command or BREAK key
[#LOOP |DO|
#SET cmd [#INPUT Enter cmd: ] == Get value from terminal
[#CASE [cmd]
|ADD|
#OUTPUT ADD
|SUB|
#OUTPUT SUB
|OTHERWISE|
#OUTPUT Invalid command
#RAISE _ERROR
] == End CASE
|UNTIL| 0 = 1 == (do forever)
] == End LOOP
#UNFRAME
107365 Tandem Computers Incorporated3–21
Developing TACL Routines
Writing an Exception Handler
When you invoke command_processor, the output looks like this:
16> command_processor
Enter cmd: add
ADD
Enter cmd: clr
Invalid command
TACL error occurred.
17> command_processor
Enter cmd: <BREAK>
BREAK key pressed.
18>
Use the routine in Figure 3-14, purgefiles, to purge files based on file name
templates. Purgefiles illustrates the use of #FILTER, #FILENAMES, and the
TEMPLATES alternative for the #ARGUMENT built-in function. To use this routine,
load the associated file and enter:
purgefiles [ ! ]
file-template
[ ,
file-template
] ...
The ! specifies purge without confirmation; without it, the routine prompts for each
file. If the routine encounters a _BREAK exception, it displays a message with the
number of files purged and the number not purged, and then exits.
Figure 3-14. Returning Information From a Release Handler (Page 1 of 3)
?SECTION purgefiles ROUTINE
[#CASE [#EXCEPTION]
|_CALL|
|_BREAK _ERROR|
#PUSH errtext
#ERRORTEXT /CAPTURE errtext/
#OUTPUT Break or error terminated function.
#OUTPUT
[#IF NOT [#EMPTYV /BLANK/ errtext] |THEN|
#OUTPUTV errtext
#OUTPUT
]
#OUTPUT Number of files purged = [filespurged]
#OUTPUT Number of files not purged = [filesnotpurged]
#UNFRAME
#RETURN
]
#FRAME
[#LOOP |WHILE| 1 |DO|
handletemplate
[#CASE [#ARGUMENT /VALUE filetemplate/ COMMA TEMPLATE
END]
|1|
#IF [#ARGUMENT /VALUE filetemplate/ TEMPLATE]
|2|
|3|
#OUTPUT == blank line
#OUTPUT Number of files purged =[filespurged]
#OUTPUT Number of files not purged=[filesnotpurged]
#UNFRAME
#RETURN
]
] == end of #LOOP
Creating a Keep Exception
Handler
A keep exception handler processes exceptions but does not return to the calling
process. If, for example, you want to provide a restrictive command shell with five
commands, a keep handler allows you to process the five commands and any errors or
break conditions without exiting the routine. The user could not, then, gain access to a
standard TACL prompt.
The _CALL path is the entry point for the routine and, because control is to remain in
the routine, it is not likely to be executed repeatedly. Therefore, the _CALL path
contains the #FRAME and variable declarations that typically begin a routine.
Use the routine in Figure 3-15, restricted_cmd_processor, as a sample keep
exception handler. If the BREAK key is pressed while the processing loop is running,
TACL raises the _BREAK exception and reinvokes the routine; the #CASE function
takes the _BREAK path and then reenters the loop.
If the user enters anything other than ADD or SUB, the #CASE statement in the loop
raises _ERROR, and TACL reinvokes the routine; in this situation, the exceptionprocessing #CASE takes the _ERROR path before resuming the loop.
3–24107365 Tandem Computers Incorporated
Developing TACL Routines
Writing an Exception Handler
NoteThe examples in this subsection include an EXIT case for testing purposes, which allows you to exit the
routines. To prohibit exits, delete the EXIT case from the #FILTER statement and from the exception
handler and main loop.
To invoke restricted_cmd_processor, load the file and enter:
== Filters predefined exceptions only
#FILTER _BREAK _ERROR EXIT
== After you enter this loop, control stays here unless the
== routine is processing an exception.
[#LOOP |DO|
#SET cmd [#INPUT Enter cmd: ] == Get value from terminal
[#CASE [cmd]
|ADD|
#OUTPUT ADD
|SUB|
#OUTPUT SUB
|EXIT|
#RAISE EXIT == For demo only
|OTHERWISE|
#OUTPUT Invalid command
#RAISE _ERROR
] == End CASE
|UNTIL| 0 == Always false
] == End LOOP
#UNFRAME
107365 Tandem Computers Incorporated3–25
Developing TACL Routines
Writing an Exception Handler
When you invoke restricted_cmd_processor, the output looks like this:
16> restricted_cmd_processor
Enter cmd: add
ADD
Enter cmd: clr
Invalid command
TACL error occurred.
Enter cmd: <BREAK>
BREAK key pressed.
Enter cmd: exit
17>
By using the definitions in Figure 3-16, a user can start and stop an application. (In the
example, there is no code to start an application; the code performs a delay sequence
to simulate application activity.)
The definitions in Figure 3-16 use the following global variables:
Condition is an error flag; if 0, there is no error; if 1, there is an error, and
recovery might be necessary.
Recovery indicates the need to run a routine to clear local variables. If OFF,
recovery is not necessary; if ON, recovery is necessary.
The shell supports the following commands:
Coldstart —Pops old variables if necessary, pushes new variables, sets the
condition and recovery variables, and then starts the application. If the user
presses BREAK during this time, the exception handler sets the condition and
recovery flags.
When finished, coldstart resets the condition and recovery flags.
Warmstart—Attempts to purge a file with an invalid file name; this attempt
forces a TACL error to show exception handler operation.
Shutdown —Performs a cleanup operation and sets condition to 0.
Exit—Tests the condition variable and does not allow the user to exit until the
error is resolved. If condition is 0, exit raises the user-defined EXIT exception
and exits the shell.
Variables a, b, c, d, e, f, g, and h are created but are not used in this example; they are
deleted during the cleanup phase before exiting.
If an error occurs during coldstart or warmstart, the user cannot exit the shell
until a successful coldstart or shutdown occurs.
For this example, the keep handler returns if you enter an exit command. Usually, a
keep handler would not provide an exit mechanism.
?SECTION display_initial_message TEXT
#OUTPUT This interface is used to:
#OUTPUT COLDSTART, WARMSTART, or SHUTDOWN the application.
#OUTPUT
#OUTPUT EXIT is disabled if an error exists.
#OUTPUT The BREAK key and CTRL/Y do not cause an EXIT.
?SECTION warmstart MACRO == WARMSTART the application
[#IF condition = 1 |THEN|
#OUTPUT An error condition exists.
#OUTPUT Must COLDSTART or SHUTDOWN.
#OUTPUT
|ELSE|
[#CASE [recovery]
|REQUIRED|
cleanup
| OTHERWISE |
]
#SET name [#VARIABLEINFO /VARIABLE/ %0%]
#SET step 1
#PUSH a b
#DELAY 200
#OUTPUT WARMSTARTing application $X
3–28107365 Tandem Computers Incorporated
Developing TACL Routines
Writing an Exception Handler
Figure 3-16. Sample Command Shell (Page 3 of 4)
#SET step 2
#PUSH c d
#DELAY 200
#PURGE filewithlongname
#OUTPUT
] == end #IF
#SET name [#VARIABLEINFO /VARIABLE/ %0%]
#SET step 1
#PUSH e f
== If an error occurs during this step, force recovery
#OUTPUT COLDSTARTing application $X
#OUTPUT (Press BREAK now to force a recovery)
#DELAY 300
#SETMANY condition recovery , 0 OFF
#OUTPUT COLDSTART Successful
#OUTPUT
?SECTION shutdown MACRO == SHUTDOWN the application
#OUTPUT SHUTDOWN of application $X
[#CASE [recovery]
|REQUIRED|
cleanup
|OTHERWISE|
]
#SET name [#VARIABLEINFO /VARIABLE/ %0%]
#SET step 1
#PUSH g h
#DELAY 300
#SET condition 0
#OUTPUT SHUTDOWN Successful
#OUTPUT
107365 Tandem Computers Incorporated3–29
Developing TACL Routines
Writing an Exception Handler
Figure 3-16. Sample Command Shell (Page 4 of 4)
?SECTION exit MACRO == EXIT the exception handler
[#IF condition = 1 |THEN|
#OUTPUT Can not EXIT without resolving the error.
#OUTPUT Must WARMSTART, COLDSTART, or SHUTDOWN.
#OUTPUT
|ELSE|
#OUTPUT Exiting restrictive command shell.
#RAISE EXIT
]
?SECTION cleanup MACRO == delete variables from prev. errors
#SET #BREAKMODE DISABLE
#OUTPUT Performing cleanup procedure
#OUTPUT The Break Key is disabled until cleanup is complete.
[#CASE [name][step]
| WARMSTART1 |
#POP a b
| WARMSTART2 |
#POP a b c d
| COLDSTART1 |
#POP e f
| SHUTDOWN1 |
#POP g h
]
The routines in Figure 3-17 show one way to combine a keep handler
(restricted_caller) and a release handler (protected_code).
Restricted_caller starts first; therefore, if an exception occurs, control returns to
the processing loop after the exception is processed.
When the user enters a valid command, restricted_caller calls
protected_code to execute the command; that routine, in turn, calls either do_add
or do_sub. If the user presses the BREAK key or an unknown exception is raised
during execution of either of the latter routines, TACL pops the routine and reinvokes
protected_code. The #CASE function takes the OTHERWISE path, which
performs an orderly deallocation of resources and then raises the same exception.
TACL then pops that routine (the #FILTER function has not yet been executed in the
reinvocation) and returns to restricted_caller. The #CASE function in that
routine takes the appropriate path to deal with the exception and restarts the
processing loop.
3–30107365 Tandem Computers Incorporated
Developing TACL Routines
Writing an Exception Handler
For this example, the keep handler terminates if you enter an EXIT command.
Usually, a keep handler does not provide an exit mechanism.
Figure 3-17. Using Nested Keep and Release Handlers (Page 1 of 2)
== Filter for predefined exceptions only
#FILTER [exceptionlist]
[#LOOP |DO|
#SET cmd [#INPUT Enter cmd: ] == Get value from terminal
[#CASE [cmd]
|ADD|
protected_code do_add
|SUB|
protected_code do_sub
|EXIT| == For demonstration purposes
#RAISE EXIT
|OTHERWISE|
#OUTPUT Invalid command
#RAISE _ERROR
] == End CASE
|UNTIL| 0 = 1 == (do forever)
] == End LOOP
#UNFRAME
107365 Tandem Computers Incorporated3–31
Developing TACL Routines
Writing an Exception Handler
Figure 3-17. Using Nested Keep and Release Handlers (Page 2 of 2)
?SECTION protected_code ROUTINE
[#CASE [#EXCEPTION]
|_CALL |
== No action required when first called
|OTHERWISE|
#RESET FRAMES RESULTS == Deallocate resources
#RAISE [#EXCEPTION] == Return to caller with
== exception raised, so that
== the caller executes its
== exception handler
] == End CASE
#FILTER [exceptionlist]
[#REST] == Invoke rest of arguments (call macro)
?SECTION do_add ROUTINE
#OUTPUT Adding
?SECTION do_sub ROUTINE
#OUTPUT Subtracting
3–32107365 Tandem Computers Incorporated
4Accessing Files
The #REQUESTER built-in function allows you to open a file, process, or device so
that you can send messages or records to it or read messages or records from it.
This section describes how to use #REQUESTER to access files. For information about
the use of #REQUESTER with processes, see “Using $RECEIVE” in Section 5,
“Initiating and Communicating With Processes.”
#REQUESTER
Operation
To open a file, call the #REQUESTER function and include the file name and a set of
variables that are used to transmit data. If you plan to set up more than one
#REQUESTER operation, you can identify variables by including file identification
information in each variable name. To list a variable and its association with the
#REQUESTER operation, use the VARINFO command.
The call to #REQUESTER does not perform input or output; it opens the specified file
and initializes the associated variables. If a file system error occurs during this step,
#REQUESTER returns the error.
The #REQUESTER function opens a file for waited or nowaited I/O. After you invoke
the #REQUESTER function, TACL continues to execute code. For waited I/O
operations, TACL stops at the next I/O request and ensures that each read or write is
complete before processing the next request. For nowaited operations, call #WAIT to
determine whether your request has been completed. If you plan to read or write
records larger than 239 bytes, you must use waited I/O.
To initiate a read or write operation, you append data to the appropriate variable, as
described in the following subsections. When your TACL process first detects data in
the variable, TACL initiates the operation and transfers a record of data.
To read and write from the same file, call #REQUESTER twice to establish two
communication paths to the file. Use a separate set of variables for each
communication path.
When you use #REQUESTER, your TACL process does not create a separate process,
but manages the I/O from within your TACL process. The #REQUESTER function
uses sequential I/O to access files, devices, and processes.
NoteThe way in which you order the variables in the #REQUESTER call is very important; the file name must
be first, followed by the error variable and the read or write variable. For a read operation, the prompt
variable must be specified last.
To close a file, call #REQUESTER with the CLOSE option.
107365 Tandem Computers Incorporated4–1
Accessing Files
Requesting Waited Reads
Table 4-1 lists functions related to #REQUESTER operation.
Table 4-1. Functions Used With #REQUESTER
FunctionDescription
#APPEND, #APPENDVAdds lines to a variable.
#EXTRACT, #EXTRACTVRetrieves lines from a variable.
Requesting Waited
Reads
NoteIt is very important to check the results of the open operation; otherwise, you will not know if the open
To open a file for waited read operations, issue a #REQUESTER call and include the
WAIT option; for example, the following statement opens FILE1 and initializes
You can also use the WAIT option to specify the size of the text buffer. To specify
shared, protected, or exclusive access to the file, use the EXCLUSION option; the
default for a read operation is shared. For example:
To initiate a read operation, append data to the prompt variable:
#APPEND prompt_var *start read*
When reading a disk file, TACL discards the data in prompt_var; you can specify any
non-null data. TACL reads a record from FILE1 and places it into read_var. You can
use #EXTRACT(V) to retrieve data from read_var; as you #EXTRACT records,
TACL deletes them from read_var.
Each time you append a line to prompt_var, the TACL process reads a record from
the disk file FILE1 and appends it to read_var. TACL then performs a READ
operation. TACL continues executing code until it encounters an #APPEND(V) or
#EXTRACT(V) call that refers to one of the #REQUESTER variables. TACL then waits
until the current read operation is complete before initiating the next read operation.
When you are finished reading from the file, issue a CLOSE request and supply one of
the variable levels associated with the file; for example:
#REQUESTER CLOSE read_var
This operation closes FILE1 (associated with read_var) and terminates the
#REQUESTER function.
4–2107365 Tandem Computers Incorporated
Accessing Files
Requesting Waited Reads
Use the routine in Figure 4-1, waited_read, to perform waited reads from the file
specified in the first argument in the invocation and display the records on the
terminal. To invoke this routine, load the file and type:
waited_read
filename
The routine stops when it detects an error or end-of-file.
[#IF read_error = 1 |THEN|
#OUTPUT *** End of file ***
|ELSE|
#OUTPUT *** Error reading [read_file]: [read_error]
]
SINK [#REQUESTER/WAIT/CLOSE read_data]
#UNFRAME
107365 Tandem Computers Incorporated4–3
Accessing Files
Requesting Nowaited Reads
Requesting Nowaited
Reads
NoteIt is very important to check the results of the open operation; otherwise, you will not know if the open
To open a file for nowaited read operations, issue a #REQUESTER call and omit the
WAIT option; for example, the following statement opens FILE1 and initializes
To initiate a read operation, append data to the prompt variable:
#APPEND prompt_var *start read*
To read a disk file, TACL discards the data in prompt_var, reads a record from
FILE1, and places it into read_var. You can use #EXTRACT(V) to retrieve data from
read_var; as you #EXTRACT records, TACL deletes them from read_var.
Each time you append a line to prompt_var, the TACL process reads a record from
disk file FILE1 and appends it to read_var. TACL then performs a READ operation.
TACL continues executing code; when you are ready to wait for completion of the
read operation, use the #WAIT built-in function to wait until read_var contains
data. To avoid writing over data that has not yet been transmitted, use #WAIT to
make sure the previous operation has finished.
When you are finished reading from the file, issue a CLOSE request and supply one of
the variables associated with the file; for example:
#REQUESTER CLOSE error_var
This operation closes FILE1 (associated with error_var) and terminates the
#REQUESTER function.
Use the routine in Figure 4-2, nowaited_read, to perform nowaited reads from the
file specified in the first argument in the invocation and display the records on the
terminal. To invoke this routine, load the file and type:
nowaited_read
4–4107365 Tandem Computers Incorporated
filename
Accessing Files
Requesting Nowaited Reads
This routine uses #VARIABLEINFO/VARIABLE/ to return a variable name to the
#CASE statement. #VARIABLEINFO/VARIABLE/ returns the name of a variable
without the level number so that it will match one of the labels. The #WAIT built-in
function, when used alone, returns the variable name with the level number.
[#IF [open_error] |THEN|
#OUTPUT *** Error opening [read_file]: [open_error]
#RETURN
]
#SET read_error 0
[#LOOP |WHILE| NOT [read_error] |DO|
#APPEND read_prompt *start*
[#CASE [#VARIABLEINFO/VARIABLE/
[#WAIT read_data read_error]] |THEN|
|read_data |
#EXTRACTV read_data line
#OUTPUTV line
|read_error|
== exit loop
] == end case
] == end loop
|OTHERWISE|
#OUTPUT *** Error: Invalid file ***
#RETURN
] == end #CASE
[#IF read_error = 1 |THEN|
#OUTPUT *** End of file ***
|ELSE|
#OUTPUT *** Error reading [read_file]: [read_error]
]
SINK [#REQUESTER/WAIT/CLOSE read_data]
#UNFRAME
107365 Tandem Computers Incorporated4–5
Accessing Files
Requesting Waited Writes
Requesting Waited
Writes
NoteIt is very important to check the results of the open operation. Otherwise, you will not know if the open
To open a file for waited write operations, issue a #REQUESTER call and include the
WAIT option. The following statement opens FILE1 and initializes error_var and
write_var. If FILE1 does not exist, TACL creates an Edit file:
You can also use the WAIT option to specify the size of the text buffer. To specify
shared, protected, or exclusive access to the file, use the EXCLUSION option; the
default for a write operation is shared. For example:
To initiate the write operation, append data to the write variable:
#APPEND write_var This is a test
When TACL detects data in write_var, it writes the data to FILE1.
You can add a record to a structured file but cannot replace a record. If you attempt to
write a record that already exists, TACL returns an error.
Each time you append a line to write_var, the TACL process writes the record to
FILE1. TACL continues executing code until it encounters an #APPEND(V) call that
refers to one of the #REQUESTER variables, signifying that you have more data to
write. TACL then waits until the current operation is complete before initiating the
next write operation.
When you are finished writing to the file, issue a CLOSE request and supply one of the
variable levels associated with the file; for example:
#REQUESTER CLOSE error_var
This operation closes FILE1 (associated with error_var) and terminates the
#REQUESTER function.
4–6107365 Tandem Computers Incorporated
Accessing Files
Requesting Waited Writes
Use the routine in Figure 4-3, waited_write, to perform waited writes to the file
specified as the first argument in the invocation. If the file already contains data, this
routine appends the new data to the end of the file. To invoke this routine , load the
file and type:
waited_write
filename
The #INPUT call in Figure 4-3 reads a line from the TACL IN file.
Figure 4-3. Reading From a Terminal and Performing a Waited Write
NoteIt is very important to check the results of the open operation. Otherwise, you will not know if the open
To open a file for nowaited write operations, issue a #REQUESTER call and omit the
WAIT option. The following statement opens FILE1 and initializes error_var and
write_var. If FILE1 does not exist, TACL creates an Edit file:
To initiate the write operation, append data to the write variable:
#APPEND write_var This is a test
When TACL detects data in write_var, it writes the record to FILE1.
You can add a record to a structured file but you cannot replace a record. If you
attempt to write a record that already exists, TACL returns an error.
Each time you append a line to write_var, the TACL process writes a record to
FILE1. TACL continues executing code. When you are ready to wait for completion of
the read operation, use the #WAIT built-in function to wait until the write_var
contains data. To avoid writing over data that has not yet been transmitted, use
#WAIT to make sure the previous operation has finished.
When you are finished writing to the file, call the #WAIT function to make sure that
the last write has finished. Next, issue a CLOSE request and supply one of the variable
levels associated with the file; for example:
#REQUESTER CLOSE write_var
This operation closes FILE1 (associated with write_var) and terminates the
#REQUESTER function.
4–8107365 Tandem Computers Incorporated
Accessing Files
Requesting Nowaited Writes
Use the routine in Figure 4-4, nowaited_write, to perform nowaited writes to the
file specified in the first argument in the invocation. If the file already contains data,
this routine appends the new data to the end of the file. To invoke this routine, load
the file and type:
nowaited_write
filename
Figure 4-4. Reading From a Terminal and Performing a Nowaited Write
Use the routine in Figure 4-5, copy, to read records from one file and write them to
another file. The source file is specified as the first argument; the destination file is
specified as the second argument; both files must exist. In this example:
read_err is the error variable for the read operation
read_var contains the data obtained from the read operation
prompt_var is the prompt variable to start the read operation
write_err is the error variable for the write operation
write_var contains the record to be written
To invoke this routine, load the file that contains copy and then type:
copy
file1 file2
Copy appends data to the end of FILE2. Copy could be changed to modify records
before copying them; for example, you could search for a string and, if it is present,
modify the string before writing the record to the destination file.
Figure 4-5. Copying Records From One File to Another File (Page 1 of 2)
== Check for existence of the first argument. If empty,
== display a message and exit.
#SET rslt [#ARGUMENT /VALUE source/ FILENAME OTHERWISE]
[#CASE [rslt]
|1|
== Check for the second file.
#SET rslt2 [#ARGUMENT /VALUE dest/ FILENAME OTHERWISE]
[#CASE [rslt2]
|1|
== Open the source and destination files and
== associate variables with them.
#SET open_err [#REQUESTER READ [source] read_err
read_var prompt_var]
[#IF open_err = 0 |THEN|
#OUTPUT [source] opened successfully
|ELSE|
#OUTPUT [source] not open; error [read_err]
#RETURN
]
#SET open_err [#REQUESTER WRITE [dest] write_err
write_var]
4–10107365 Tandem Computers Incorporated
Accessing Files
Copying Records Between Files
Figure 4-5. Copying Records From One File to Another File (Page 2 of 2)
[#IF open_err = 0 |THEN|
#OUTPUT [dest] opened successfully
|ELSE|
#OUTPUT [dest] not open; error [write_err]
SINK [#REQUESTER CLOSE read_var] == close source
#RETURN
]
== Initiate read and write operations.
#SET read_err 0 == initialize read_err
[#LOOP |DO|
== Start the read.
#APPEND prompt_var READIT
== Wait for read_var or read_err to change.
#SET ready [#WAIT read_var read_err]
== If read_var changed, the read was successful.
[#IF [#MATCH read_var.* [Ready]] |THEN|
== Wait for the last write to complete
SINK [#WAIT write_var]
== Move the record into write_var to initiate the
== write operation.
#EXTRACTV read_var write_var
]
|UNTIL| ([read_err])
] == end of #loop
== Wait for the last write operation to finish.
SINK [#WAIT write_var]
== Close both files and terminate the #REQUESTER
== functions.
SINK [#REQUESTER CLOSE read_var]
SINK [#REQUESTER CLOSE write_var]
|2|
#OUTPUT *** Error: Invalid destination filename ***
]
|2|
#OUTPUT *** Error: Invalid source filename ***
]
#UNFRAME
The #EXTRACTV call that performs the write operation clears the contents of
read_var and write_var. TACL moves a record out of read_var and into
write_var. After TACL writes the data, TACL deletes the record from
write_var.
107365 Tandem Computers Incorporated4–11
Accessing Files
Comparing Files
Comparing FilesUse the routine in Figure 4-6, fcomp, to perform a line-for-line comparison of two
files. A mismatch does not resynchronize the two files.
Fcomp reads a record from each of the two files and then calls #COMPAREV to
compare the records. The maximum line length for an edit file is 239 bytes; fcomp
uses this value as a maximum line length for the input records.
Fcomp supports two options: you can limit the comparison to a range of columns
within the files, and you can write the results to a file.
Fcomp calls the getargs macro (from Section 3, “Developing TACL Routines”) and
the defaultvars macro (from Section 2, “Developing TACL Programs”):
Getargs parses the arguments of a calling routine; it accepts sets of three
arguments:
REQUIRED or OPTIONAL specify whether an argument must be present or
can be omitted from the list of arguments.
Type specifies an #ARGUMENT alternative, such as FILENAME or
KEYWORD.
Variable is pushed and set by the TEXT option of #ARGUMENT if the
argument is supplied; otherwise, the variable remains empty.
defaultvars accepts a space-separated list of space-separated pairs (variable
levels and values) and sets each empty variable level to its corresponding value.
For each pair of arguments:
Variable-level
Value
specifies the corresponding value, or can be empty. Value cannot
specifies the name of a variable level.
contain any spaces.
To call fcomp , load the associated file and enter:
fcomp
file1, file2
[, [f1] [, [f2] [, [
result
]]]]
where
file1
is the name of one of the comparison files.
file2
is the name of the other comparison file.
f1
is a starting field range (optional).
4–12107365 Tandem Computers Incorporated
Loading...
+ hidden pages
You need points to download manuals.
1 point = 1 manual.
You can buy points or you can get point for every manual you upload.