home *** CD-ROM | disk | FTP | other *** search
/ The Developer Connection…ice Driver Kit for OS/2 3 / DEV3-D1.ISO / docs / rexxbase.inf (.txt) < prev    next >
Encoding:
OS/2 Help File  |  1994-03-07  |  340.5 KB  |  10,889 lines

  1.  
  2. ΓòÉΓòÉΓòÉ 1. (C) Copyright IBM Corp. 1992 ΓòÉΓòÉΓòÉ
  3.  
  4. (C) Copyright International Business Machines Corporation 1992. All rights 
  5. reserved. 
  6.  
  7. Note to U.S. Government Users - Documentation related to restricted rights - 
  8. Use, duplication or disclosure is subject to restrictions set forth in GSA ADP 
  9. Schedule Contract with IBM Corp. 
  10.  
  11.  
  12. ΓòÉΓòÉΓòÉ 2. Cover ΓòÉΓòÉΓòÉ
  13.  
  14.  
  15. ΓòÉΓòÉΓòÉ <hidden> Title Page ΓòÉΓòÉΓòÉ
  16.  
  17.                                     OS/2 2.0
  18.                                 Technical Library
  19.  
  20.                              Procedures Language 2/
  21.                                 REXX User's Guide
  22.  
  23.                                   Version 2.00
  24.  
  25.                                Programming Family
  26.  
  27.  
  28. ΓòÉΓòÉΓòÉ 3. Version Notice ΓòÉΓòÉΓòÉ
  29.  
  30. Important:  This document was originally created in BookMaster.  The 
  31.             translation to the Information Presentation Facility was done 
  32.             specifically for this project. Although the information in this 
  33.             document relates to a product that is currently available, the 
  34.             document itself should be treated as a beta product. 
  35.  
  36. Note:  Before using this information and the product it supports, be sure to 
  37.        read the general information under Notices. 
  38.  
  39. First Edition (December 1991) 
  40.  
  41. The following paragraph does not apply to the United Kingdom or any country 
  42. where such provisions are inconsistent with local law: INTERNATIONAL BUSINESS 
  43. MACHINES CORPORATION PROVIDES THIS PUBLICATION "AS IS" WITHOUT WARRANTY OF ANY 
  44. KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
  45. WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some states 
  46. do not allow disclaimer of express or implied warranties in certain 
  47. transactions, therefore, this statement may not apply to you. 
  48.  
  49. This publication could include technical inaccuracies or typographical errors. 
  50. Changes are periodically made to the information herein; these changes will be 
  51. incorporated in new editions of the publication. IBM may make improvements 
  52. and/or changes in the product(s) and/or the program(s) described in this 
  53. publication at any time. 
  54.  
  55. It is possible that this publication may contain reference to, or information 
  56. about, IBM products (machines and programs), programming, or services that are 
  57. not announced in your country.  Such references or information must not be 
  58. construed to mean that IBM intends to announce such IBM products, programming, 
  59. or services in your country. 
  60.  
  61. Requests for technical information about IBM products should be made to your 
  62. IBM Authorized Dealer or your IBM Marketing Representative. 
  63.  
  64. IBM may have patents or pending patent applications covering subject matter in 
  65. this document. The furnishing of this document does not give you any license to 
  66. these patents. You can send license inquiries, in writing, to the IBM Director 
  67. of Commercial Relations, IBM Corporation, Purchase, NY 10577. 
  68.  
  69. COPYRIGHT LICENSE: This publication contains printed sample application 
  70. programs in source language, which illustrate OS/2 programming techniques. You 
  71. may copy and distribute these sample programs in any form without payment to 
  72. IBM, for the purposes of developing, using, marketing or distributing 
  73. application programs conforming to the OS/2 application programming interface. 
  74.  
  75. Each copy of any portion of these sample programs or any derivative work, which 
  76. is distributed to others, must include a copyright notice as follows: "(C) 
  77. (your company name) (year) All Rights Reserved." 
  78.  
  79. MAK - Revision 1.0
  80.  
  81.  
  82. ΓòÉΓòÉΓòÉ 4. Notices ΓòÉΓòÉΓòÉ
  83.  
  84. References in this publication to IBM products, programs, or services do not 
  85. imply that IBM intends to make these available in all countries in which IBM 
  86. operates. Any reference to an IBM product, program, or service is not intended 
  87. to state or imply that only IBM's product, program, or service may be used. Any 
  88. functionally equivalent product, program, or service that does not infringe any 
  89. of IBM's intellectual property rights or other legally protectible rights may 
  90. be used instead of the IBM product, program, or service. Evaluation and 
  91. verification of operation in conjunction with other products, programs, or 
  92. services, except those expressly designated by IBM, are the user's 
  93. responsibility. 
  94.  
  95. IBM may have patents or pending patent applications covering subject matter in 
  96. this document. The furnishing of this document does not give you any license to 
  97. these patents. You can send license inquiries, in writing, to the IBM Director 
  98. of Commercial Relations, IBM Corporation, Purchase, NY 10577. 
  99.  
  100.  
  101. ΓòÉΓòÉΓòÉ 4.1. Trademarks ΓòÉΓòÉΓòÉ
  102.  
  103. The following terms, denoted by an asterisk (*) in this publication, are 
  104. trademarks of the IBM Corporation in the United States and/or other countries: 
  105.  
  106. OS/2             Operating System/2
  107. SAA              Systems Application Architecture
  108. CUA              Common User Access
  109.  
  110.  
  111. ΓòÉΓòÉΓòÉ 4.2. Double-Byte Character Set (DBCS) ΓòÉΓòÉΓòÉ
  112.  
  113. Throughout this publication, you will see references to specific values for 
  114. character strings.  The values are for single-byte character set (SBCS).  If 
  115. you use the double-byte character set (DBCS), note that one DBCS character 
  116. equals two SBCS characters. 
  117.  
  118.  
  119. ΓòÉΓòÉΓòÉ 5. About This Book ΓòÉΓòÉΓòÉ
  120.  
  121. The IBM Operating System/2 Procedures Language 2/REXX User's Guide (referred to 
  122. as User's Guide in the rest of this book) describes the programming language 
  123. known as REXX.  REXX is an integral part of IBM  OS/2 2.0. This guide describes 
  124. how to write programs using REXX. 
  125.  
  126.  
  127. ΓòÉΓòÉΓòÉ 5.1. Before You Begin ΓòÉΓòÉΓòÉ
  128.  
  129. Before reading this book, it is important that you consider the following 
  130. items: 
  131.  
  132.  
  133. ΓòÉΓòÉΓòÉ 5.1.1. What You Need ΓòÉΓòÉΓòÉ
  134.  
  135. This is what you need to get started: 
  136.  
  137. o Your computer with the OS/2 program installed. 
  138.  
  139. o A text-editing or word-processing program such as the system editor supplied 
  140.   with the OS/2 program.  Whatever editor you use must be able to create 
  141.   straight-ASCII files (nearly all such programs can). 
  142.  
  143. o OS/2 2.0 Procedures Language 2/REXX Reference. 
  144.  
  145. It is also useful, though not essential, to have a printer so you can print 
  146. your programs. 
  147.  
  148.  
  149. ΓòÉΓòÉΓòÉ 5.1.2. What You Need to Know ΓòÉΓòÉΓòÉ
  150.  
  151. To use this book, you should know: 
  152.  
  153. o What a file is and how to create a text file 
  154.  
  155. o How to use an editor or word processor 
  156.  
  157. o The basic OS/2 commands for manipulating files, such as COPY, DELETE, DIR, 
  158.   and so on. 
  159.  
  160. If you have little or no experience with the OS/2 program or with personal 
  161. computers, you may want to read the following publications: c. 
  162.  
  163. o OS/2 2.0 Overview 
  164.  
  165. o OS/2 2.0 Installation Guide 
  166.  
  167.  
  168. ΓòÉΓòÉΓòÉ 5.2. Who Should Read This Guide ΓòÉΓòÉΓòÉ
  169.  
  170. Both inexperienced and experienced computer users should read this guide to 
  171. learn about REXX.  The guide shows how REXX is a useful programming language 
  172. for both the experienced programmer and the user new to programming. 
  173.  
  174.  
  175. ΓòÉΓòÉΓòÉ 5.3. How This Guide Is Structured ΓòÉΓòÉΓòÉ
  176.  
  177. Each chapter, except chapter 1, is divided into two parts: 
  178.  
  179. o The first part of each chapter, Basics, is a tutorial guide to the most 
  180.   frequently used features of REXX.  "Basics" in each chapter builds on the 
  181.   preceding chapters and prepares you for those that follow. 
  182.  
  183. o The second part of each chapter, Advanced Topics, discusses more advanced 
  184.   information about REXX and includes descriptions and examples of the more 
  185.   specialized features of REXX. 
  186.  
  187. Each chapter of this Guide concentrates on a single topic. 
  188.  
  189. o Introduction to REXX, is a brief introduction to programming and REXX. 
  190.  
  191. o How REXX Works, describes how the program works. 
  192.  
  193. o Variables, tells about handling data in terms of symbols. 
  194.  
  195. o Expressions, shows how REXX computes information. 
  196.  
  197. o Commands, describes using REXX with OS/2 and other programs. 
  198.  
  199. o Program Control, tells about refining and automating programs. 
  200.  
  201. o Program Structure, tells about running programs within programs. 
  202.  
  203. o Parsing, tells about reading and analyzing data. 
  204.  
  205. o Arithmetic, shows how REXX calculates numbers. 
  206.  
  207. o Input and Output, describes using REXX with outside data. 
  208.  
  209. o Program Style, describes how to plan and correct programs. 
  210.  
  211. o Using REXX with Applications, describes how to use certain REXX features to 
  212.   get the most from the operating system. 
  213.  
  214.  
  215. ΓòÉΓòÉΓòÉ 6. Introduction to REXX ΓòÉΓòÉΓòÉ
  216.  
  217. The REstructured eXtended eXecutor language, or REXX, is a versatile, easy to 
  218. use structured programming language that is an integral part of the  OS/2 
  219. program. Its simplicity makes it a good first language for beginners.  For more 
  220. experienced users and computer professionals, REXX offers powerful functions, 
  221. extensive mathematical capabilities, and the ability to issue commands to 
  222. multiple environments. 
  223.  
  224.  
  225. ΓòÉΓòÉΓòÉ 6.1. Features of REXX ΓòÉΓòÉΓòÉ
  226.  
  227. The following REXX features contribute to its versatility and function. 
  228.  
  229.  
  230. ΓòÉΓòÉΓòÉ 6.1.1. Ease of Use ΓòÉΓòÉΓòÉ
  231.  
  232. REXX is easy to learn and use because many instructions are meaningful English 
  233. words.  Unlike some programming languages that use abbreviations, REXX 
  234. instructions are common words such as SAY, PULL, IF...THEN...ELSE, DO...END, 
  235. and EXIT. 
  236.  
  237.  
  238. ΓòÉΓòÉΓòÉ 6.1.2. Free Format ΓòÉΓòÉΓòÉ
  239.  
  240. REXX has few rules about format.  A single instruction can span many lines or 
  241. multiple instructions can be entered on a single line.  Instructions do not 
  242. have to begin in a particular column and can be typed in uppercase, lowercase, 
  243. or mixed case.  Spaces can be skipped in a line or entire lines can be skipped. 
  244. There is no line numbering. 
  245.  
  246.  
  247. ΓòÉΓòÉΓòÉ 6.1.3. Interpreted ΓòÉΓòÉΓòÉ
  248.  
  249. REXX is an interpreted language.  When a REXX program runs, its language 
  250. processor reads each statement from the source file and runs it, one statement 
  251. at a time.  Languages that are not interpreted must be compiled into machine 
  252. language (in separate files) before they can be run. 
  253.  
  254.  
  255. ΓòÉΓòÉΓòÉ 6.1.4. Built-in Functions ΓòÉΓòÉΓòÉ
  256.  
  257. REXX has built-in functions that perform various processing, searching, and 
  258. comparison operations for both text and numbers.  Other built-in functions 
  259. provide formatting capabilities and arithmetic calculations. 
  260.  
  261.  
  262. ΓòÉΓòÉΓòÉ 6.1.5. Typeless Variables ΓòÉΓòÉΓòÉ
  263.  
  264. REXX regards all data as character strings.  This means that there is no need 
  265. to predefine variables or variable arrays as strings or as numbers. REXX 
  266. performs arithmetic operations on any string that represents a valid number, 
  267. including those in exponential formats. 
  268.  
  269.  
  270. ΓòÉΓòÉΓòÉ 6.1.6. Parsing Capabilities ΓòÉΓòÉΓòÉ
  271.  
  272. REXX includes capabilities for manipulating character strings.  This allows 
  273. programs to read and separate characters, numbers, and mixed input. 
  274.  
  275.  
  276. ΓòÉΓòÉΓòÉ 6.1.7. Debugging ΓòÉΓòÉΓòÉ
  277.  
  278. REXX displays messages with meaningful explanations when a REXX program 
  279. encounters an error.  In addition, the TRACE instruction provides a powerful 
  280. debugging tool. 
  281.  
  282.  
  283. ΓòÉΓòÉΓòÉ 6.2. REXX and the OS/2 Program ΓòÉΓòÉΓòÉ
  284.  
  285. The most vital role REXX plays is as a procedural language for the OS/2 
  286. program.  A REXX program can serve as a script for the OS/2 program to follow. 
  287. By using REXX, long, complex, or repetitious tasks can be reduced to a single 
  288. command or program that can be run from Presentation Manager. 
  289.  
  290. REXX is a built-in feature of the OS/2 program, so programs are run directly 
  291. from an windowed or full-screen command prompt. There is no installation 
  292. process or separate environment. Anywhere that an OS/2 command or batch file 
  293. can be used, a REXX program can be run.  Any REXX program can call OS/2 
  294. commands. 
  295.  
  296.  
  297. ΓòÉΓòÉΓòÉ 6.3. About REXX and SAA ΓòÉΓòÉΓòÉ
  298.  
  299. REXX is one of the programming languages included in the IBM Systems 
  300. Application Architecture* (SAA*). SAA is a framework of standards and 
  301. definitions intended to promote consistency among different IBM products. 
  302. Programs written in REXX according to SAA specifications are portable to all 
  303. other SAA environments.  For example, a REXX program written for OS/2 
  304. environment can be run in a CMS or TSO/E environment, if the program does not 
  305. use OS/2-specific features. 
  306.  
  307. To learn more about using REXX in SAA environments, see the Common Programming 
  308. Interface Procedures Language Reference, SC24-5549. 
  309.  
  310.  
  311. ΓòÉΓòÉΓòÉ 6.4. About Programming ΓòÉΓòÉΓòÉ
  312.  
  313. A program is a list of instructions that have a basic sequence.  Some 
  314. instructions indicate actions and some instructions specify the number and 
  315. sequence of these actions.  There are also instructions to tell you how to 
  316. execute other instructions. Those that specify repetitious actions are 
  317. iterative. Those that indicate when an action should begin or end are 
  318. conditional. 
  319.  
  320. You may think of programming as a skill practiced only by computer experts, but 
  321. that is not true.  You do not need to know how a computer works to write a 
  322. program.  Anyone can write a program, and almost everyone who uses a computer 
  323. eventually needs to do so.  With a little programming knowledge, you can reduce 
  324. a long or repetitious series of commands into a single command.  You can also 
  325. customize OS/2 programs and other programs to work in a way that will best suit 
  326. your needs.  Programming helps you make the computer work faster or better. 
  327. That is what REXX was meant for, and this book should make REXX easier to 
  328. understand. 
  329.  
  330.  
  331. ΓòÉΓòÉΓòÉ 6.4.1. If You Have Never Written a Computer Program ΓòÉΓòÉΓòÉ
  332.  
  333. If you are inexperienced at programming, you will find it fairly easy to learn 
  334. and write programs in REXX.  Start by reading "Basics" in each chapter.  After 
  335. you have read "Basics," go back and read "Advanced Topics" in each chapter to 
  336. learn more about specific topics. 
  337.  
  338.  
  339. ΓòÉΓòÉΓòÉ 6.4.2. If You Are Already Familiar With Another Language ΓòÉΓòÉΓòÉ
  340.  
  341. If you are an experienced programmer, reading "Basics" in each chapter gives 
  342. you an overview of the REXX language.  Or, you may prefer to read about 
  343. individual topics, one at a time.  Here are some areas you may want to 
  344. investigate: 
  345.  
  346. o If you now use OS/2 CMD files to automate your work, you will find that REXX 
  347.   gives you more flexibility in controlling program flow and in handling 
  348.   parameters.  Refer to Commands, which discusses how REXX works with OS/2 
  349.   commands. 
  350.  
  351. o If you are skilled in BASIC, you may want to note these ways that REXX 
  352.   differs from BASIC: 
  353.  
  354.    - There is no line numbering. 
  355.    - There are no GOSUB or GOTO statements.  Use CALL and SIGNAL instead (see 
  356.      Subroutines). 
  357.    - REXX variables have no data type. 
  358.    - There are no DIM arrays.  Use compound variables instead (see Using 
  359.      Compound Symbols). 
  360.  
  361. o If you are familiar with development languages, such as C and Pascal, you 
  362.   will find REXX somewhat similar.  Again, the main difference is that a REXX 
  363.   program is interpreted; that is, the source code of the program is processed 
  364.   line by line.  There is no compiling process. 
  365.  
  366.   Refer to Commands, for examples of command-passing and Input and Output, for 
  367.   examples of file and queue processing. 
  368.  
  369.  
  370. ΓòÉΓòÉΓòÉ 6.4.3. Exercises and Examples ΓòÉΓòÉΓòÉ
  371.  
  372. As with other programming languages, you do not learn REXX by reading about it. 
  373. Exercises and examples are included to help you learn REXX by using it.  To get 
  374. the most out of this book: 
  375.  
  376. o Test yourself with the exercises as you read. 
  377.  
  378. o Examine the examples and sample programs in the text.  Type them exactly as 
  379.   they are shown. 
  380.  
  381. o Try your own variations of each program.  See if you can find a different or 
  382.   better way to do what the sample program does. 
  383.  
  384. Note:  When your REXX program issues an OS/2 command, REXX passes the command 
  385. to the OS/2 command handler for processing.  This processing includes 
  386. displaying the command on the screen (echoing). 
  387.  
  388. For the sake of simplification, the examples in this book do not include 
  389. echoing of the commands. :enote. 
  390.  
  391.  
  392. ΓòÉΓòÉΓòÉ 6.4.4. The REXX Reference ΓòÉΓòÉΓòÉ
  393.  
  394. The REXX Reference contains a more complete description of how to use the REXX 
  395. language.  You should have a copy of this book, so you can look up any 
  396. instruction or function not completely defined here. Think of the REXX 
  397. Reference as a dictionary for REXX and this User's Guide as a book of 
  398. directions and ideas. 
  399.  
  400. The Procedures Language/2REXX is available online. It contains information on 
  401. REXX features, functions, and instructions. 
  402.  
  403.  
  404. ΓòÉΓòÉΓòÉ 7. How REXX Works ΓòÉΓòÉΓòÉ
  405.  
  406. A REXX program is a list of instructions for your computer.  The program is 
  407. simply a text file that you create with a text-editing or word-processing 
  408. program.  Sometimes a computer runs a program with no guidance.  Other times it 
  409. may need additional information from the user to do its work.  One way that a 
  410. computer communicates with the user is to ask questions and then compute 
  411. results based on the responses.  The programmer (you) can include instructions 
  412. that let the computer converse with the user. 
  413.  
  414.  
  415. ΓòÉΓòÉΓòÉ 7.1. Basics ΓòÉΓòÉΓòÉ
  416.  
  417.      In this chapter: Basics 
  418.  
  419.      o A computer conversation-creating and running your first REXX program and 
  420.        how REXX interprets it 
  421.      o What goes into a program-elements in the grammar of REXX. 
  422.      o Syntax errors-how to read REXX messages. 
  423.  
  424.  
  425. ΓòÉΓòÉΓòÉ 7.1.1. A Computer Conversation ΓòÉΓòÉΓòÉ
  426.  
  427. Figure "HELLO.CMD" shows a sample REXX program.  It asks users to type their 
  428. names.  Then the program greets the user by that name.  For example, if the 
  429. user types Jean, the program displays Hello JEAN on the screen.  If the user 
  430. does not type anything, the program displays Hello stranger! on the screen. 
  431.  
  432.  
  433. HELLO.CMD
  434.  
  435. /* A conversation */
  436. say "Hello! What is your name?"
  437. pull who
  438. if who = "" then say "Hello stranger!"
  439. else say "Hello" who
  440.  
  441. This sample program consists of five statements called clauses.  The various 
  442. pieces of this program are: 
  443.  
  444.  /* ... */               The first clause is a comment explaining what the 
  445.                          program is about.  All REXX programs must start with a 
  446.                          comment beginning in column 1. Except for this, all 
  447.                          other comments are ignored. 
  448.  
  449.  say                     The second clause is the keyword instruction say, 
  450.                          which displays text on the screen. 
  451.  
  452.  "Hello!..."             Anything in quotes after say is displayed on the 
  453.                          screen exactly as it was typed.  This is called a 
  454.                          literal string. 
  455.  
  456.  pull                    The third clause is the keyword instruction pull, 
  457.                          which reads and stores the response typed by the user 
  458.                          of the program. 
  459.  
  460.  who                     This is a variable: a name given to the place in 
  461.                          memory where the user's response is stored. 
  462.  
  463.  if                      The fourth clause is the keyword instruction if, which 
  464.                          tests for a given condition. 
  465.  
  466.  who = ""                The condition to be tested: whether the variable who 
  467.                          is empty. 
  468.  
  469.  then                    Tells the program to process the instruction that 
  470.                          follows, if the tested condition is true. 
  471.  
  472.  say "Hello stranger!"   Displays Hello stranger! on the screen if the 
  473.                          condition is true. 
  474.  
  475.  else                    This final clause gives an alternative direction: 
  476.                          process the instruction that follows, if the tested 
  477.                          condition is not true. 
  478.  
  479.  say "Hello" who         Displays Hello, followed by whatever data is stored in 
  480.                          who, if the tested condition is not true. 
  481.  
  482.  
  483. ΓòÉΓòÉΓòÉ 7.1.1.1. Creating Your First Program ΓòÉΓòÉΓòÉ
  484.  
  485. Follow these steps to create your first program by: 
  486.  
  487.   1. Using a word processor or editor to create a text file named HELLO.CMD. 
  488.      Be sure to make it a straight-ASCII or nondocument file, without special 
  489.      formatting characters. 
  490.  
  491.   2. Typing the HELLO.CMD program exactly as shown in Figure "HELLO.CMD". Be 
  492.      sure that the first line begins with /* and ends with */. 
  493.  
  494.   3. Saving the file and then returning to Presentation Manager. 
  495.  
  496.  
  497. ΓòÉΓòÉΓòÉ 7.1.1.2. Running the Program ΓòÉΓòÉΓòÉ
  498.  
  499. Follow these steps to run the sample program from the OS/2 command prompt by: 
  500.  
  501.   1. Typing the file name of the program.  In this example, type hello at the 
  502.      OS/2 prompt and press the Enter key. 
  503.  
  504.   2. Typing your name and pressing the Enter key.  If your name is Fred, Hello 
  505.      FRED is displayed on the screen. 
  506.  
  507.           [C:\] hello
  508.           Hello! What is your name?
  509.           fred
  510.           Hello FRED
  511.           [C:\]
  512.  
  513.  When you run this program: 
  514.  
  515.   1. The SAY instruction displays Hello! What is your name? on the screen. 
  516.  
  517.   2. You type fred on the command line and press the Enter key. 
  518.  
  519.   3. The PULL instruction puts FRED into the variable (the place in memory) 
  520.      called who. 
  521.  
  522.   4. The IF instruction tests, is who equal to nothing? 
  523.  
  524.           who = ""
  525.  
  526.      To find out, REXX substitutes the stored value for the variable name.  Now 
  527.      the question is, is FRED equal to nothing? 
  528.  
  529.           "FRED" = ""
  530.  
  531.   5. Not true. The SAY instruction after then is not processed. Instead, REXX 
  532.      processes the SAY instruction after else. 
  533.  
  534.   6. The SAY instruction displays "Hello" who, which is evaluated as Hello FRED 
  535.      on the screen. 
  536.  
  537.  The following is displayed on the screen, if you press the Enter key without 
  538.  typing a response. 
  539.  
  540.   [C:\] hello
  541.   Hello! What is your name?
  542.  
  543.   Hello stranger
  544.   [C:\]
  545.  
  546.  When you run this program: 
  547.  
  548.   1. The PULL instruction puts nothing ("") into the variable (the place in 
  549.      memory) called who. 
  550.  
  551.   2. The IF instruction tests is who equal to nothing? 
  552.  
  553.           who = ""
  554.  
  555.      When the stored value of who is substituted, this is: 
  556.  
  557.           "" = ""
  558.  
  559.   3. This time, it is true.  The SAY instruction after then is processed, and 
  560.      the SAY instruction after else is not. 
  561.  
  562.  
  563. ΓòÉΓòÉΓòÉ 7.1.1.3. Problems ΓòÉΓòÉΓòÉ
  564.  
  565. Did you get your version of HELLO.CMD to run?  If not, check that you have 
  566. correctly typed it in.  Also, be sure that you used the nondocument mode of 
  567. your text editor to create the program file. 
  568.  
  569. The most common error is forgetting the comment on the first line.  Be sure 
  570. that the first line begins with the /* and ends with the */ characters.  If you 
  571. mistype or omit these characters, you get a message on the screen from REXX 
  572. that looks something like this. 
  573.  
  574. [C:\] hello
  575.      0 +++;
  576. REX0006: Error 6 running C:\HELLO.CMD, line 0: Unmatched "/*" or quote
  577.  
  578. This means that REXX found the beginning /* but not the ending */ of the 
  579. comment.  Edit your HELLO.CMD program file to match the sample in Figure 
  580. "HELLO.CMD". 
  581.  
  582. If you do not start the first line with /*, you get a message like this. 
  583.  
  584. SYS1041: The name specified is not recognized as an
  585. internal or external command, operable program or batch file.
  586.  
  587. This means that the operating system did not recognize HELLO.CMD as a REXX 
  588. program. (See First-line Comments in the following text.) 
  589.  
  590. If you get another error, refer to Fixing Syntax Errors. 
  591.  
  592.  
  593. ΓòÉΓòÉΓòÉ 7.1.1.4. Stopping a Program ΓòÉΓòÉΓòÉ
  594.  
  595. If you need to stop a program, press the Control (Ctrl)+Break keys. That is, 
  596. press and hold down the Ctrl key and then press the Break key once. REXX stops 
  597. running the program and returns to the OS/2 command prompt. 
  598.  
  599.  
  600. ΓòÉΓòÉΓòÉ 7.1.2. What Goes into a Program ΓòÉΓòÉΓòÉ
  601.  
  602. To explain what happens when you run a REXX program, a number of terms have 
  603. been introduced.  There will be more; so before continuing, here are 
  604. definitions of the terms used so far. 
  605.  
  606.  
  607. ΓòÉΓòÉΓòÉ 7.1.2.1. Comments ΓòÉΓòÉΓòÉ
  608.  
  609. When you write a program, you will want to read it later (for example, before 
  610. improving it).  Other users of your program will also want to read it to know 
  611. what the program is for, what kind of input it can handle, what kind of output 
  612. it produces, and so forth.  You may also want to write remarks about individual 
  613. instructions.  All these things, words that are to be read by people but not 
  614. interpreted by REXX, are called comments. 
  615.  
  616. To indicate comments, use /* to mark the start of a comment and */ to mark the 
  617. end of a comment. 
  618.  
  619. The /* causes REXX to stop interpreting the program. Interpreting starts again 
  620. only after a */ is found, which may be a few words or several lines later.  For 
  621. example: 
  622.  
  623. /* This is a comment. */
  624.  
  625. say ...  /* This is a comment on the same line as the instruction */
  626.  
  627. /* Comments may
  628.    occupy more
  629.    than one line. */
  630.  
  631.  
  632. ΓòÉΓòÉΓòÉ 7.1.2.1.1. First-line Comments ΓòÉΓòÉΓòÉ
  633.  
  634. The first line of a REXX program must start with a comment.  The OS/2 program 
  635. can be programmed with its built-in Batch Facility and in REXX.  Both Batch 
  636. Facility and REXX programs can use the file name extension CMD.  Each type 
  637. requires its own special processing, so the OS/2 program checks the first line 
  638. of the program. If it finds a REXX-style comment, the program is processed as 
  639. REXX. Therefore, to recognize that your program is written in REXX, the first 
  640. line of the file must be or begin a comment. For example: 
  641.  
  642. /* this is a REXX program.  */
  643. Also, the first-line comment must begin in column 1.  It is sufficient to use 
  644. /* */, but a better use for the space is to give a brief description of your 
  645. program.  You can also do it this way. 
  646.  
  647. /*************************************
  648. *  HELLO.CMD written by J. Smith     *
  649. *       June 30, 1989                *
  650. * A program to greet a user by name. *
  651. *************************************/
  652.  
  653.  
  654. ΓòÉΓòÉΓòÉ 7.1.2.2. Keyword Instructions ΓòÉΓòÉΓòÉ
  655.  
  656. Words such as SAY, PULL, and IF are part of the REXX language called 
  657. instructions.  The words themselves are referred to as keywords.  You will 
  658. notice that they are usually verbs.  They are the directions that tell REXX 
  659. what to do with information at a certain point in the program. 
  660.  
  661.  SAY (display on screen) hello. 
  662.  PULL (accept and store) information from the user. 
  663.  IF (test) this situation is true, then perform this action. 
  664.  
  665.  When you list these instructions in the order you want REXX to execute them, 
  666.  you have created a program. 
  667.  
  668.  
  669. ΓòÉΓòÉΓòÉ 7.1.2.2.1. Clauses ΓòÉΓòÉΓòÉ
  670.  
  671. A REXX program is made up of clauses; that is, complete instructions, including 
  672. the information it works on and any options that may be used.  REXX reads each 
  673. clause and processes it before going on to the next. That is why REXX is an 
  674. interpreted language. 
  675.  
  676. In the previous sample program, each line of text corresponds to a single 
  677. clause.  REXX allows exceptions to this (see More about Clauses). The examples 
  678. and sample programs in this book follow the convention of one clause to a line, 
  679. except where noted. 
  680.  
  681.  
  682. ΓòÉΓòÉΓòÉ 7.1.2.3. Literal Strings ΓòÉΓòÉΓòÉ
  683.  
  684. When REXX finds a quote (either " or '), it stops processing and looks ahead 
  685. for the matching quote.  The string of characters inside the matching quotes is 
  686. used as it is and is called a literal string. Examples of literal strings are: 
  687.  
  688. 'Hello'
  689. "Final result:"
  690.  
  691. If you need to use quotation marks within a literal string, use quotation marks 
  692. of the other type to delimit the string.  For example: 
  693.  
  694. "Don't panic"
  695. 'He said, "Bother"'
  696.  
  697. There is another way.  Within a literal string, a pair of quotes (the same type 
  698. that delimits the string) is interpreted as one of that type.  For example: 
  699.  
  700. 'Don''t panic'                   (same as "Don't panic")
  701. "He said, ""Bother"""          (same as 'He said, "Bother"')
  702.  
  703.  
  704. ΓòÉΓòÉΓòÉ 7.1.2.3.1. Uppercase Translation ΓòÉΓòÉΓòÉ
  705.  
  706. When a clause is processed, any letters that are not in quotes are translated 
  707. to uppercase.  For example, the letters a, b, c, ... z are changed to A, B, C, 
  708. ... Z. This translation applies only to clauses written in English. 
  709.  
  710. REXX also ignores some of the spaces that you may have written into your 
  711. program, keeping only one space between words.  Figure "HELLO2.CMD" shows an 
  712. example using quotes to get more than one space between words. 
  713.  
  714.  
  715. HELLO2.CMD
  716.  
  717. /* Example: cases and spaces */
  718. say  Hello!     What     is     your     name?
  719.  
  720. say "Hello!     What     is     your     name?"
  721.  
  722. say Hello!"    "stranger!
  723.  
  724. The following is displayed on the screen, when you run the HELLO2 program. 
  725.  
  726. [C:\] hello2
  727. HELLO! WHAT IS YOUR NAME?
  728. Hello!     What     is     your     name?"
  729. HELLO!    STRANGER!
  730. [C:\]
  731.  
  732. Note:  In the HELLO.CMD sample program, the user's input fred was changed to 
  733. FRED.  That translation is not the process described here, but is a feature of 
  734. the PULL instruction.  The PULL instruction always converts the input to 
  735. uppercase, which allows the user to type any combination of uppercase and 
  736. lowercase letters. :enote. 
  737.  
  738.  
  739. ΓòÉΓòÉΓòÉ 7.1.2.4. Variables ΓòÉΓòÉΓòÉ
  740.  
  741. When you need to work with changeable information (such as the user's name in 
  742. HELLO.CMD), you can reserve a place in memory to store it.  That place is 
  743. called a variable. 
  744.  
  745. When REXX processes a clause containing a variable, it substitutes the stored 
  746. data for the variable.  That is how the stored entry FRED took the place of the 
  747. variable name who in the HELLO.CMD program. 
  748.  
  749. Refer to Variables, for more information on variables. 
  750.  
  751.  
  752. ΓòÉΓòÉΓòÉ 7.1.3. Fixing Syntax Errors ΓòÉΓòÉΓòÉ
  753.  
  754. The rules governing the arrangement of words and punctuation marks in a 
  755. language are called syntax.  The actions described are part of the syntax for 
  756. the REXX language.  If REXX encounters something that does not make sense 
  757. according to its syntax, it stops running your program, displays the incorrect 
  758. instruction line and an error message saying what is wrong, and returns to the 
  759. OS/2 program. 
  760.  
  761. Figure "HELLO.CMD with a syntax error" shows the HELLO.CMD program with a 
  762. syntax error. The */ is missing at the end of the second comment. 
  763.  
  764.  
  765. HELLO.CMD with a syntax error
  766.  
  767. /* A conversation */
  768. say "Hello! What is your name?"
  769. pull who                                  /* Get the answer!
  770. if who = "" then say "Hello stranger!"
  771. else say "Hello" who
  772.  
  773. The following is displayed on the screen, when you run the program and enter 
  774. fred. 
  775.  
  776. [C:\] hello
  777. Hello! What is your name?
  778.  
  779. fred
  780.  
  781. REX0006: Error 6 running C:\HELLO.CMD,line 3: Unmatched "/*" or quote
  782.  
  783. [C:\]
  784.  
  785. This error message means: 
  786.  
  787.  o REX0006: is the REXX error number.  If you need more information, type help 
  788.    followed by the error number (REX0006) at the command prompt and press the 
  789.    Enter key.  More information about the error is displayed.  You can also 
  790.    find error message help in the REXX Reference. 
  791.  
  792.  o The phrase in line 3 means REXX was processing the clause that started on 
  793.    line 3 when the error occurred. 
  794.  
  795.  Leaving out a final quotation mark at the end of a literal string causes REXX 
  796.  to issue a similar error message. 
  797.  
  798.  
  799. ΓòÉΓòÉΓòÉ 7.1.3.1. Test Yourself ΓòÉΓòÉΓòÉ
  800.  
  801.   1. Read the following program and write down what each clause is and what 
  802.      REXX will do with it, depending on how the user responds. 
  803.  
  804.  
  805.           WHOAMI.CMD
  806.  
  807.           /* Who Am I? game */
  808.           say "What is my name?"
  809.           pull guess
  810.           if guess = "REXX" then say "You win!"
  811.           else say no but guess "is a good guess."
  812.  
  813.      Create a file called WHOAMI.CMD, type the program shown in Figure 
  814.      "WHOAMI.CMD", and run it. 
  815.  
  816.      Did everything happen as you expected?  If not, read this chapter again 
  817.      and then study the explanation below. 
  818.  
  819.   2. Figure "TROUBLE.CMD" shows a program with an error in it.  Create a file 
  820.      called TROUBLE.CMD, type the program, and run it. 
  821.  
  822.  
  823.           TROUBLE.CMD
  824.  
  825.           /* Example: a syntax error */
  826.           say Unfortunately, there is an error here
  827.  
  828.      Using the error number, find the cause of the error in the REXX Reference. 
  829.      Correct the error and run the program again. 
  830.  
  831.  
  832. ΓòÉΓòÉΓòÉ 7.1.3.1.1. Answers: ΓòÉΓòÉΓòÉ
  833.  
  834.   1. The syntax of the WHOAMI.CMD program shown in Figure "WHOAMI.CMD" is: 
  835.  
  836.     o /* Who Am I? game */  is a comment describing the program.  (The first 
  837.       line of a REXX program must start with a comment.) 
  838.  
  839.     o say is an instruction that displays,  What is my name? 
  840.  
  841.     o pull is an instruction that stores the user response in the variable 
  842.       guess 
  843.  
  844.     o if is an instruction that tests to see if the user typed REXX. 
  845.  
  846.       Note:  Because pull translates the entry to uppercase, you can type it in 
  847.       any combination of uppercase and lowercase letters (rexx, Rexx, rExX, and 
  848.       so on). :enote. 
  849.  
  850.     o If guess = REXX, then say displays You win!. 
  851.  
  852.     o If the user types something other than REXX, then the clause beginning 
  853.       with else is interpreted and say displays the result as follows: 
  854.  
  855.        - no but is a string, but it is not in quotes. Therefore, it is changed 
  856.          to uppercase and is displayed as NO BUT. 
  857.  
  858.        - guess is the name of a variable.  The user's response, translated to 
  859.          uppercase, is substituted. 
  860.  
  861.        - "is a good guess." is a literal string.  It is displayed as is, even 
  862.          though guess is also the name of a variable. 
  863.  
  864.      The following is displayed on the screen, if the user guesses correctly. 
  865.  
  866.           [C:\] whoami
  867.           What is my name?
  868.           rexx
  869.           You win!
  870.  
  871.      The following is displayed on the screen, if the user guesses incorrectly. 
  872.  
  873.           [C:\] whoami
  874.           What is my name?
  875.           spot
  876.           NO BUT SPOT is a good guess.
  877.  
  878.      The following is displayed on the screen, if the user presses the Enter 
  879.      key without typing a response. 
  880.  
  881.           [C:\] whoami
  882.           What is my name?
  883.  
  884.           NO BUT  is a good guess.
  885.  
  886.      The variable guess was empty, so the say instruction displayed nothing. 
  887.      Only the blank before and after the variable in the program remain. 
  888.  
  889.      That last response does not make much sense.  See if you can think of a 
  890.      way to fix WHOAMI.CMD so that it does. (Hint: Take another look at 
  891.      HELLO.CMD.) 
  892.  
  893.   2. The error number for the program TROUBLE.CMD is 37.  The error message 
  894.      displays Unexpected "," or ")". 
  895.  
  896.      REXX found a comma where it did not belong.  It may not be obvious what to 
  897.      do about it.  When you get a message like this, refer to the REXX 
  898.      Reference for a list of error messages and explanation of their causes. 
  899.  
  900.      The comma has a special meaning when it is used outside of a literal 
  901.      string (see More about Clauses).  Figure "TROUBLE2.CMD" shows that to use 
  902.      a comma as it is intended, it must be enclosed in matching quotes. 
  903.  
  904.  
  905.           TROUBLE2.CMD
  906.  
  907.           /* Example: a syntax error fixed */
  908.           say Unfortunately"," there is an error here
  909.  
  910.  
  911. ΓòÉΓòÉΓòÉ 7.1.4. Summary ΓòÉΓòÉΓòÉ
  912.  
  913. This completes "Basics" in this chapter.  You have learned that REXX reads a 
  914. literal string.  In addition, you have learned how to: 
  915.  
  916.  o Write a program 
  917.  o Run a program 
  918.  o Use the SAY and PULL instructions. 
  919.  
  920.  "Advanced Topics" in this chapter discusses more about the structure of REXX 
  921.  programs. 
  922.  
  923.  To continue with "Basics," go to page 3-1. 
  924.  
  925.  
  926. ΓòÉΓòÉΓòÉ 7.2. Advanced Topics ΓòÉΓòÉΓòÉ
  927.  
  928.      In this chapter: Advanced Topics 
  929.  
  930.      o Kinds of clauses-more about REXX syntax. 
  931.  
  932.  
  933. ΓòÉΓòÉΓòÉ 7.2.1. More about Clauses ΓòÉΓòÉΓòÉ
  934.  
  935. Your REXX program is made up of a number of clauses.  REXX processes clauses, 
  936. one at a time, reading from left to right. 
  937.  
  938. Usually, each clause occupies one line of the program, but that is only a 
  939. convention.  It is sometimes useful to be able to write more than one clause on 
  940. a line or to extend a clause over many lines.  The rules for writing clauses 
  941. are: 
  942.  
  943.  o If you want to put more than one clause on a line, you must use a semicolon 
  944.    (;) to tell REXX where one clause ends and the next begins. 
  945.  
  946.  o If you have a long quoted string that you would like to span several lines, 
  947.    write it as several separate strings and concatenate them. Quoted strings 
  948.    cannot span more than one line. 
  949.  
  950.  o If you want a clause to span more than one line, you must put a comma (,) at 
  951.    the end of the line to tell REXX that the clause continues on the next line. 
  952.  
  953.  o If you use a comma in the middle of a string, REXX interprets the comma as 
  954.    part of the string. A comma inside a comment is ignored. 
  955.  
  956.  What is displayed on the screen, when the program shown in Figure "RAH.CMD" is 
  957.  run? 
  958.  
  959.  
  960.   RAH.CMD
  961.  
  962.   /* Example: there are six clauses in this program */
  963.   say "Everybody cheer!"
  964.   say "2"; say "4"; say "6"; say "8";
  965.   say "Who do we",
  966.   "appreciate?"
  967.  
  968.  If you are not sure, create a file called RAH.CMD, type the program, and run 
  969.  it. 
  970.  
  971.  
  972. ΓòÉΓòÉΓòÉ 7.2.2. Types of Clauses ΓòÉΓòÉΓòÉ
  973.  
  974. The three types of clauses are: 
  975.  
  976.  o Null clauses 
  977.  o Labels 
  978.  o Instructions. 
  979.  
  980.  
  981. ΓòÉΓòÉΓòÉ 7.2.2.1. Null Clauses ΓòÉΓòÉΓòÉ
  982.  
  983. A clause that is empty (a blank line) or consists only of blanks or comments is 
  984. called a null clause.  REXX ignores all null clauses, except to check for a 
  985. comment in the first line of a program.  This means you can use spaces and 
  986. blank lines to make your program more readable without affecting its 
  987. performance. 
  988.  
  989.  
  990. ΓòÉΓòÉΓòÉ 7.2.2.2. Labels ΓòÉΓòÉΓòÉ
  991.  
  992. Labels are symbols that mark positions or portions of a program, internal 
  993. subroutines, condition traps, and so forth.  They are distinguished by a 
  994. trailing colon (for example, ERROR:). Except for their use with the CALL and 
  995. SIGNAL instructions and for internal function calls, labels are regarded as 
  996. null clauses. 
  997.  
  998. Unlike null and instruction clauses, labels are self-delimiting.  They do not 
  999. require semicolons or carriage returns to separate them from other clauses. 
  1000.  
  1001.  
  1002. ΓòÉΓòÉΓòÉ 7.2.2.3. Instructions ΓòÉΓòÉΓòÉ
  1003.  
  1004. The three types of instruction clauses are: 
  1005.  
  1006.  Keywords       Clauses that begin with words, such as PULL and SAY, that REXX 
  1007.                 recognizes as instructions.  Keywords are not reserved words, 
  1008.                 but the language processor recognizes them by their context 
  1009.                 (see Variables as Symbols).  Certain keyword instructions may 
  1010.                 comprise one or more clauses, such as the IF instruction. 
  1011.  
  1012.                 The keyword instructions are listed alphabetically in the REXX 
  1013.                 Reference. 
  1014.  
  1015.  Assignments    Clauses that assign values to variables.  An assignment 
  1016.                 normally takes the form symbol = expression.  The PARSE 
  1017.                 instruction and its variants PULL and ARG also assign values to 
  1018.                 variables.  Refer to Variables, for a description of variable 
  1019.                 assignments. 
  1020.  
  1021.  Commands       Clauses that are processed by other programs.  A clause that is 
  1022.                 an expression by itself is interpreted as a command to be 
  1023.                 passed to the current environment (the application that 
  1024.                 initially called REXX). You can also use the ADDRESS 
  1025.                 instruction to pass commands to other environments.  Refer to 
  1026.                 Commands, for a description of more commands. 
  1027.  
  1028.  
  1029. ΓòÉΓòÉΓòÉ 7.2.3. For More Information ΓòÉΓòÉΓòÉ
  1030.  
  1031. For a more complete discussion of REXX syntax, refer to "General Concepts" in 
  1032. the REXX Reference. 
  1033.  
  1034.  
  1035. ΓòÉΓòÉΓòÉ 8. Variables ΓòÉΓòÉΓòÉ
  1036.  
  1037. Variables are a means of handling changeable information by representing it in 
  1038. terms of symbols.  This chapter explains why variables are important when 
  1039. writing programs and describes the basic rules for using them. 
  1040.  
  1041.  
  1042. ΓòÉΓòÉΓòÉ 8.1. Basics ΓòÉΓòÉΓòÉ
  1043.  
  1044.      In this chapter: Basics 
  1045.  
  1046.      o Handling data with symbols 
  1047.      o Assignments 
  1048.      o Naming variables 
  1049.      o Other assignments. 
  1050.  
  1051.  
  1052. ΓòÉΓòÉΓòÉ 8.1.1. Handling Data with Symbols ΓòÉΓòÉΓòÉ
  1053.  
  1054. One basic requirement of any program is that it must work with information that 
  1055. is unknown when the program is written. 
  1056.  
  1057. You could write a program that totals a fixed list of numbers. For example: 
  1058.  
  1059. say "2 + 3 equals" 2 + 3
  1060.  
  1061. This example displays the result 5 each time you run it, but that is all you 
  1062. would get.  This is a reliable program but not a very useful one.  A program 
  1063. that is more useful can process different information each time it is run.  You 
  1064. can do this by using variables to stand in for values to be processed.  A 
  1065. variable is a symbol (one or more characters) that represents a value. 
  1066.  
  1067. Figure "ADD2NUM.CMD" shows a program that contains a simple calculation. 
  1068.  
  1069.  
  1070. ADD2NUM.CMD
  1071.  
  1072. /* the sum of two numbers */
  1073. say "Type a number:"
  1074. pull first                        /* waits for entry */
  1075. say "Type another number:"
  1076. pull second                       /* waits for entry */
  1077. say "The sum is" first + second
  1078.  
  1079. The following is displayed on the screen, when you run the program. 
  1080.  
  1081. [C:\]add2num
  1082. Type a number:
  1083. ?
  1084. 25
  1085. Type another number:
  1086. ?
  1087. 32
  1088. The sum is 57
  1089. [C:\]
  1090.  
  1091. Two PULL instructions are used, allowing the user to type the two numbers to be 
  1092. added and then assign (store) them in the variables first and second.  The SAY 
  1093. instruction displays the sum of the two. 
  1094.  
  1095.  
  1096. ΓòÉΓòÉΓòÉ 8.1.1.1. Names and Values ΓòÉΓòÉΓòÉ
  1097.  
  1098. The information stored in a variable is called its value. The value can be one 
  1099. or more words of text, numbers, or nothing.  The value of a variable can change 
  1100. any time you want it to.  It can be different each time the program is run, or 
  1101. it can change many times in a single run. If the value of a variable changes, 
  1102. the name of the variable stays the same.  It will be easier to remember 
  1103. variables if you choose names that are meaningful to you. 
  1104.  
  1105. You can think of a variable as a name for the type of values you want it to 
  1106. hold. 
  1107.  
  1108.  
  1109. ΓòÉΓòÉΓòÉ 8.1.2. Assignments ΓòÉΓòÉΓòÉ
  1110.  
  1111. An instruction that stores a value in a variable or changes its value is called 
  1112. an assignment.  The simplest form of assignment is the equal sign, a REXX 
  1113. clause in the form name = value where: 
  1114.  
  1115.  name      is the name you give the variable 
  1116.  
  1117.  value     is the value it will hold. 
  1118.  
  1119.  In more formal terms, the syntax of an assignment is in the form symbol = 
  1120.  expression where: 
  1121.  
  1122.  symbol    is a valid variable name 
  1123.  
  1124.  expression is the information to be stored, such as a number, a string, or 
  1125.            some calculation that you want REXX to perform. 
  1126.  
  1127.  REXX evaluates (computes) the expression and then puts the result of that 
  1128.  evaluation into the variable called symbol.  The assignment instruction means 
  1129.  "Evaluate the expression and store the result as symbol." 
  1130.  
  1131.  In an assignment, you name a variable and give it a value. For example: 
  1132.  
  1133.  o To give a variable called total the value 0, use the assignment total = 0. 
  1134.  
  1135.  o To give another variable, called price, the same value as total, use the 
  1136.    assignment price = total. 
  1137.  
  1138.  o To give the variable called total a new value, the old value of total plus 
  1139.    the value of something, use the assignment total = total + something. 
  1140.  
  1141.  In a different type of assignment, pull something, the PULL instruction gives 
  1142.  the variable something a value that the user types while the program is 
  1143.  running. 
  1144.  
  1145.  
  1146. ΓòÉΓòÉΓòÉ 8.1.2.1. Displaying the Value of a Variable ΓòÉΓòÉΓòÉ
  1147.  
  1148. To display the value of a variable while a program is running, use the SAY 
  1149. instruction, as shown in Figure "ASSIGN.CMD". 
  1150.  
  1151.  
  1152. ASSIGN.CMD
  1153.  
  1154. /* some assignments */
  1155. amount = 100                       /* assigns 100 to AMOUNT      */
  1156. money = "dollars"                  /* assigns "dollars" to MONEY */
  1157. say amount money                   /* displays "100 dollars"     */
  1158. amount = amount + 25               /* adds 25 to AMOUNT          */
  1159. say amount money                   /* displays "125 dollars"     */
  1160.  
  1161. /* Now get some input from the user */
  1162.  
  1163. say "Type a line, then press the Enter key" /* prompts the user to type  */
  1164. pull anything                    /* waits for user to press the Enter key*/
  1165. say "You typed:" anything          /* displays the input on screen  */
  1166.  
  1167. If you use a SAY instruction with a variable that has not been assigned a 
  1168. value, some languages would generate an error.  In REXX, the default value of a 
  1169. variable is its own name, converted to uppercase letters, as shown in Figure 
  1170. "NOASSIGN.CMD". 
  1171.  
  1172.  
  1173. NOASSIGN.CMD
  1174.  
  1175. /* display unassigned variables */
  1176. say amount          /* displays AMOUNT */
  1177. say first           /* displays FIRST  */
  1178. say price           /* displays PRICE  */
  1179. say who             /* displays WHO    */
  1180.  
  1181. Note:  Another way to display the value of a variable while a program is 
  1182. running is with the TRACE instruction, used for correcting programs. Refer to 
  1183. Tracing Evaluation. :enote. 
  1184.  
  1185.  
  1186. ΓòÉΓòÉΓòÉ 8.1.3. Naming Variables ΓòÉΓòÉΓòÉ
  1187.  
  1188. You can name variables almost anything you want.  There are a few rules that 
  1189. REXX imposes and a few conventions that should be observed. A variable name can 
  1190. be any symbol (group of characters), containing up to 250 characters, with the 
  1191. following restrictions: 
  1192.  
  1193.  o The first character must be A-Z, a-z, !, ?, or _. REXX translates lowercase 
  1194.    letters to uppercase before using them. 
  1195.  
  1196.  o The rest of the characters may be A-Z, a-z, !, ?, _, ., or 0-9. 
  1197.  
  1198.  o The period (.) has a special meaning for REXX variables.  Do not use it in a 
  1199.    variable name until you understand the rules for forming compound symbols. 
  1200.    See Using Compound Symbols. 
  1201.  
  1202.  Here are some tips for good programming practice: 
  1203.  
  1204.  o Give variables names that describe the data they represent. 
  1205.  
  1206.  o Give variables names that are different from REXX keywords or OS/2 commands. 
  1207.  
  1208.  o Give variables names that will not be confused with each other. 
  1209.  
  1210.  o Do not abbreviate unnecessarily.  It is better that the name is long rather 
  1211.    than obscure. 
  1212.  
  1213.  o Use each variable for only one purpose.  Do not use the same variable for a 
  1214.    user entry that you used elsewhere to accumulate a total. 
  1215.  
  1216.  
  1217. ΓòÉΓòÉΓòÉ 8.1.3.1. Test Yourself ΓòÉΓòÉΓòÉ
  1218.  
  1219. Which of the following could be used as the name of a REXX variable? 
  1220.  
  1221.   1. DOG 
  1222.   2. K9 
  1223.   3. 9T 
  1224.   4. nine_to_five 
  1225.   5. ?7 
  1226.  
  1227.  
  1228. ΓòÉΓòÉΓòÉ 8.1.3.1.1. Answers: ΓòÉΓòÉΓòÉ
  1229.  
  1230.   1. OK 
  1231.   2. OK 
  1232.   3. Invalid, because the first character is a numeric digit. 
  1233.   4. OK, same as NINE_TO_FIVE 
  1234.   5. OK 
  1235.  
  1236.  
  1237. ΓòÉΓòÉΓòÉ 8.1.4. Other Assignments ΓòÉΓòÉΓòÉ
  1238.  
  1239. You can also use variables to store information that is unknown when you are 
  1240. writing the program. 
  1241.  
  1242.  
  1243. ΓòÉΓòÉΓòÉ 8.1.4.1. Assigning User Input ΓòÉΓòÉΓòÉ
  1244.  
  1245. One use for variables that has already been discussed is as a holding place for 
  1246. information typed by the user.  The PULL and ARG keyword instructions are 
  1247. commonly used for this purpose. 
  1248.  
  1249. The PULL instruction pauses the running of a program to let you type one or 
  1250. more items of data, which are then assigned to variables.  For example, the 
  1251. PULL instruction was used in the program shown in Figure "ADD2NUM.CMD" to get 
  1252. two numbers to add. 
  1253.  
  1254. say "Type a number:"
  1255. pull first                    /* waits for entry */
  1256. say "Type another number:"
  1257. pull second                   /* waits for entry */
  1258.  
  1259. Each PULL instruction pauses the program and displays a ? to prompt you to type 
  1260. a number and press the Enter key.  It then assigns the entry to the variable 
  1261. named in the instruction. 
  1262.  
  1263. You can also use the PULL instruction to collect more than one item in an entry 
  1264. as long as the items are separated by spaces.  The four lines in the preceding 
  1265. example could be replaced with: 
  1266.  
  1267. say "Type two numbers (leave a space between) and press the Enter key"
  1268. pull first second
  1269.  
  1270. The PULL instruction pauses the program so you can type the two numbers to be 
  1271. added.  When you press the Enter key, PULL reads the two numbers and assigns 
  1272. them, in the order they were typed, to the list of variables (first and 
  1273. second). This process of reading and separating information is called parsing. 
  1274.  
  1275. The ARG instruction is another way to assign data from the user.  ARG works 
  1276. similar to PULL, except that items are typed at the command prompt with the 
  1277. program name.  The calculation in the program shown in Figure "ADD2NUM.CMD" 
  1278. could also be done by the program shown in Figure "ADD.CMD", which follows. 
  1279.  
  1280.  
  1281. ADD.CMD
  1282.  
  1283. /* the sum of two numbers, this time    */
  1284. /* typed at the command prompt          */
  1285. arg first second     /*collects entries */
  1286. say "The sum is" first + second
  1287.  
  1288. The following is displayed on the screen, when you run ADD.CMD. 
  1289.  
  1290. [C:\]add 25 32
  1291. The sum is 57
  1292.  
  1293. Notice that with the ARG instruction the program does not pause. The numbers to 
  1294. be added are typed with the ADD command that starts the program. 
  1295.  
  1296.  
  1297. ΓòÉΓòÉΓòÉ 8.1.4.2. Assigning an Expression Result ΓòÉΓòÉΓòÉ
  1298.  
  1299. The instruction amount = amount + 25 in the program shown in Figure 
  1300. "ASSIGN.CMD" shows how variables can represent another type of unknown 
  1301. information-data that must be calculated or otherwise manipulated.  You can 
  1302. assign to a variable the result of a calculation or expression, as shown in 
  1303. Figure "AREAS.CMD". 
  1304.  
  1305.  
  1306. AREAS.CMD
  1307.  
  1308. /* area of a 3 by 5 in. rectangle */
  1309. area = 3 * 5
  1310. say area "sq. in."                  /* displays "15 sq. in." */
  1311.  
  1312. /* area of a 5 in. circle */
  1313. diameter = 5
  1314. radius = diameter/2
  1315. area = 3.14 * radius * radius
  1316. say area "sq. in."             /* displays "19.6250 sq. in." */
  1317.  
  1318. REXX expressions can have very complex forms and they can work with all kinds 
  1319. of information. 
  1320.  
  1321.  
  1322. ΓòÉΓòÉΓòÉ 8.1.5. Summary ΓòÉΓòÉΓòÉ
  1323.  
  1324. This completes "Basics" in this chapter.  You have learned how to: 
  1325.  
  1326.  o Assign a value to a variable using the equal sign 
  1327.  o Display the value of a variable 
  1328.  o Name variables 
  1329.  o Assign user input to a variable. 
  1330.  
  1331.  "Advanced Topics" in this chapter discusses: 
  1332.  
  1333.  o How REXX recognizes and processes variables 
  1334.  o Using variables in ordered groups called arrays 
  1335.  o Using variables in complex programs. 
  1336.  
  1337.  To continue with "Basics," go to page 4-1. 
  1338.  
  1339.  
  1340. ΓòÉΓòÉΓòÉ 8.2. Advanced Topics ΓòÉΓòÉΓòÉ
  1341.  
  1342.      In this chapter: Advanced Topics 
  1343.  
  1344.      o Variables as symbols 
  1345.      o Using compound symbols 
  1346.      o Variables in programs and subroutines 
  1347.      o Other types of data storage. 
  1348.  
  1349.  
  1350. ΓòÉΓòÉΓòÉ 8.3. Variables as Symbols ΓòÉΓòÉΓòÉ
  1351.  
  1352. Variables are part of a class of REXX language elements called symbols. These 
  1353. include: 
  1354.  
  1355.  o REXX keywords and instructions 
  1356.  
  1357.  o Labels used to call internal subroutines (see CALL Instruction) 
  1358.  
  1359.  o Constants 
  1360.  
  1361.  o Variables. 
  1362.  
  1363.  REXX uses the context of a symbol to determine if it is a keyword, a label, or 
  1364.  a variable.  For each symbol it encounters, REXX takes the following steps to 
  1365.  determine how it will be handled: 
  1366.  
  1367.   1. If the first token is a symbol and is followed by: 
  1368.  
  1369.      a. An equal sign (=), the clause is an assignment instruction.  The symbol 
  1370.         is a variable and is assigned the expression that follows the equal 
  1371.         sign. 
  1372.  
  1373.      b. A colon (:), the clause is a label, signalling the beginning of a 
  1374.         subroutine. 
  1375.  
  1376.   2. If the symbol is in the list of REXX keyword instructions or is a keyword 
  1377.      used in a control structure, such as while or then, REXX interprets the 
  1378.      keyword accordingly.  (See Program Control.) 
  1379.  
  1380.   3. If the symbol begins with a number, it is a constant (an unchangeable 
  1381.      value). 
  1382.  
  1383.  If none of these steps determine how the symbol is to be handled, REXX 
  1384.  evaluates the symbol as a variable and replaces the variable name with the 
  1385.  stored value of the symbol. 
  1386.  
  1387.  
  1388. ΓòÉΓòÉΓòÉ 8.3.1. Constants and Variables ΓòÉΓòÉΓòÉ
  1389.  
  1390. Symbols that begin with a digit (0-9), a period, or a sign (+ or -) are 
  1391. constants.  They cannot be assigned new values and, therefore, cannot be used 
  1392. as variables.  Some examples of constants are: 
  1393.  
  1394.  77        a valid number 
  1395.  .0004     begins with a period (decimal point) 
  1396.  1.2e6     Scientific notation (equal to 1 200 000) 
  1397.  42nd      Not a valid number; its value is always 42ND. 
  1398.  
  1399.  All valid numbers are constants, but not all constants are valid numbers.  The 
  1400.  symbol 3girls is not a valid number; it cannot be used as a variable name. 
  1401.  Its value is always 3GIRLS. 
  1402.  
  1403.  The default value for a symbol is its own name, translated into uppercase 
  1404.  letters.  A variable that has not been assigned a value contains this default 
  1405.  value. 
  1406.  
  1407.  
  1408. ΓòÉΓòÉΓòÉ 8.3.2. Using Compound Symbols ΓòÉΓòÉΓòÉ
  1409.  
  1410. There is a special class of symbols, called compound symbols, in which 
  1411. variables and constants are combined to create groups of variables for easy 
  1412. processing.  A variable containing a period is treated as a compound symbol. 
  1413. Some examples of compound symbols are: 
  1414.  
  1415. fred.3
  1416. row.column
  1417. array.I.J.
  1418. gift.day
  1419.  
  1420. You can use compound symbols to create a collection of variables that can be 
  1421. processed by their derived names.  An example of a collection is: 
  1422.  
  1423. gift.1 = 'A partridge in a pear tree'
  1424. gift.2 = 'Two turtle doves'
  1425. gift.3 = 'Three French hens'
  1426. gift.4 = 'Four calling birds'
  1427. .
  1428. .
  1429. .
  1430.  
  1431. If you know what day it is, you know what gift will be given.  Assign a 
  1432. variable called DAY a value of 3. 
  1433.  
  1434. day = 3
  1435.  
  1436. Then the instruction say gift.day, in the program shown in Figure 
  1437. "TWELVDAY.CMD", displays Three French hens on the screen.  When the program is 
  1438. run: 
  1439.  
  1440.   1. REXX recognizes the symbol gift.day as compound because it contains a 
  1441.      period. 
  1442.  
  1443.   2. REXX checks if the characters following the period form the name of a 
  1444.      variable.  In this example, it is the variable name day. 
  1445.  
  1446.   3. The value of day is substituted for its name, producing a derived name of 
  1447.      gift.3. 
  1448.  
  1449.   4. The value of the variable gift.3 is the literal string 'Three French 
  1450.      hens'. 
  1451.  
  1452.  If day had never been given a value, its value would have been its own name; 
  1453.  day and the derived name of the compound symbol gift.day would have been 
  1454.  GIFT.DAY. 
  1455.  
  1456.  Figure "TWELVDAY.CMD" is a collection of consecutively numbered variables, 
  1457.  sometimes called an array. 
  1458.  
  1459.  
  1460.   TWELVDAY.CMD
  1461.  
  1462.   /* What my true love sent ... */
  1463.  
  1464.   /* First, assign the gifts to the days   */
  1465.   gift.1  = 'A partridge in a pear tree'
  1466.   gift.2  = 'Two turtle doves'
  1467.   gift.3  = 'Three French hens'
  1468.   gift.4  = 'Four calling birds'
  1469.   gift.5  = 'Five golden rings'
  1470.   gift.6  = 'Six geese a-laying'
  1471.   gift.7  = 'Seven swans a-swimming'
  1472.   gift.8  = 'Eight maids a-milking'
  1473.   gift.9  = 'Nine ladies dancing'
  1474.   gift.10 = 'Ten lords a-leaping'
  1475.   gift.11 = 'Eleven pipers piping'
  1476.   gift.12 = 'Twelve drummers drumming'
  1477.  
  1478.   /* list all gifts from the 12th day to   */
  1479.   /* the 1st day; refer to the discussion  */
  1480.   /* of loops on page Repetitive Tasks.                */
  1481.   do day=12 to 1
  1482.    say gift.day
  1483.   end
  1484.  
  1485.   /* now display the gift for a chosen day */
  1486.   say "Type a number from 1 to 12."
  1487.   pull day
  1488.  
  1489.   /* check for proper input */
  1490.   /* see page Checking Input Numbers           */
  1491.   if  \ datatype(day,n) then      /* if the entry is not a number */
  1492.     exit                          /* then exit the program        */
  1493.  
  1494.   if day < 1 | day > 12 then     /* same if it is out of range    */
  1495.    exit
  1496.  
  1497.   say gift.day
  1498.  
  1499.  
  1500. ΓòÉΓòÉΓòÉ 8.3.2.1. Test Yourself ΓòÉΓòÉΓòÉ
  1501.  
  1502.   1. Write a program to display the days of the week repeatedly, as: 
  1503.  
  1504.           Sunday
  1505.           Monday
  1506.           Tuesday
  1507.           Wednesday
  1508.           Thursday
  1509.           Friday
  1510.           Saturday
  1511.           Sunday
  1512.           Monday
  1513.           .
  1514.           .
  1515.           .
  1516.  
  1517.      You will need to create an endless loop, using the DO instruction.  (See 
  1518.      Repetitive Tasks for information about loops.) 
  1519.  
  1520.      Note:  To stop this program, press the Control (Ctrl)+Break keys if you 
  1521.      are running the program in an OS/2 command prompt session. Select 
  1522.      Interactive trace on from the Options menu if you are running it in 
  1523.      PMREXX. This stops any REXX program. :enote. 
  1524.  
  1525.   2. Extend this program to display the days of the month, as: 
  1526.  
  1527.           Sunday 1st January
  1528.           Monday 2nd January
  1529.           .
  1530.           .
  1531.           .
  1532.  
  1533.  
  1534. ΓòÉΓòÉΓòÉ 8.3.2.1.1. Answers: ΓòÉΓòÉΓòÉ
  1535.  
  1536.   1. Figure "DAYS1.CMD" shows one solution. 
  1537.  
  1538.  
  1539.           DAYS1.CMD
  1540.  
  1541.           /* To display the days of the week indefinitely */
  1542.           do forever
  1543.              say "Sunday"
  1544.              say "Monday"
  1545.              say "Tuesday"
  1546.              say "Wednesday"
  1547.              say "Thursday"
  1548.              say "Friday"
  1549.              say "Saturday"
  1550.           end
  1551.  
  1552.      In view of the preceding discussion, Figure "DAYS2.CMD" shows a solution 
  1553.      that uses compound variables. 
  1554.  
  1555.  
  1556.           DAYS2.CMD
  1557.  
  1558.           /* to display the days of the week indefinitely */
  1559.           day.1 = "Sunday"
  1560.           day.2 = "Monday"
  1561.           day.3 = "Tuesday"
  1562.           day.4 = "Wednesday"
  1563.           day.5 = "Thursday"
  1564.           day.6 = "Friday"
  1565.           day.7 = "Saturday"
  1566.  
  1567.           do j = 1
  1568.              say day.j
  1569.              if j = 7 then j = 0
  1570.           end
  1571.  
  1572.   2. Figure "MONTH1.CMD" shows how to extend the idea using the SELECT 
  1573.      instruction. 
  1574.  
  1575.  
  1576.           MONTH1.CMD
  1577.  
  1578.           /* to display the days of the month for January */
  1579.           day.1 = "Sunday"
  1580.           day.2 = "Monday"
  1581.           day.3 = "Tuesday"
  1582.           day.4 = "Wednesday"
  1583.           day.5 = "Thursday"
  1584.           day.6 = "Friday"
  1585.           day.7 = "Saturday"
  1586.  
  1587.           do dayofmonth = 1 to 31
  1588.              dayofweek = (dayofmonth+6)//7 + 1
  1589.  
  1590.              select
  1591.                 when dayofmonth = 1 then th = "st"
  1592.                 when dayofmonth = 2 then th = "nd"
  1593.                 when dayofmonth = 3 then th = "rd"
  1594.                 when dayofmonth = 21 then th = "st"
  1595.                 when dayofmonth = 22 then th = "nd"
  1596.                 when dayofmonth = 23 then th = "rd"
  1597.                 when dayofmonth = 31 then th = "st"
  1598.                 otherwise th = "th"
  1599.              end
  1600.  
  1601.              say day.dayofweek dayofmonth||th "January"
  1602.           end
  1603.  
  1604.  
  1605. ΓòÉΓòÉΓòÉ 8.3.2.2. A Scoreboard Array ΓòÉΓòÉΓòÉ
  1606.  
  1607. Figure "GAME.CMD" shows how you can use compound symbols to collect and process 
  1608. data.  In the first part of the program, the first player's score is entered 
  1609. into SCORE.1, the second player's into SCORE.2, and so on.  By using compound 
  1610. symbols, the SCORE array is processed to give the result in the required form. 
  1611.  
  1612.  
  1613. GAME.CMD
  1614.  
  1615. /* This is a scoreboard for a game.  Any number of      */
  1616. /* players can play.  The rules for scoring are these:  */
  1617. /*                                                      */
  1618. /* Each player has one turn and can score any number of */
  1619. /* points;  fractions of a point are not allowed.  The  */
  1620. /* scores are entered into the computer and the program */
  1621. /* replies with                                         */
  1622. /*                                                      */
  1623. /*      the average score (to the nearest hundredth of  */
  1624. /*                           a point)                   */
  1625. /*      the highest score                               */
  1626. /*      the winner        (or, in the case of a tie,    */
  1627. /*                           the winners)               */
  1628.  
  1629. /*------------------------------------------------------*/
  1630. /* Obtain scores from players                           */
  1631. /*------------------------------------------------------*/
  1632. say "Type the score for each player in turn.  When all"
  1633. say "have been typed, enter a blank line!"
  1634. say
  1635. n=1
  1636. do forever
  1637.   say "Please type the score for player "n
  1638.   pull score.n
  1639.   select
  1640.     when datatype(score.n,whole) then n=n+1
  1641.     when score.n="" then leave
  1642.     otherwise  say "The score must be a whole number."
  1643.   end
  1644. end
  1645.  
  1646. n = n - 1                  /* now n = number of players */
  1647. if n = 0 then exit
  1648. /*------------------------------------------------------*/
  1649. /* compute average score                                */
  1650. /*------------------------------------------------------*/
  1651. total = 0
  1652. do player = 1 to n
  1653.    total = total + score.player
  1654. end
  1655.  
  1656. say "Average score is",
  1657.     format(total/n,,2,0) /* format "total/n" with       */
  1658.                          /*   no leading blanks,        */
  1659.                          /*   round to 2 decimal places,*/
  1660.                          /*   do not use exponential    */
  1661.                          /*     notation                */
  1662.  
  1663.                                      /* continued ...   */
  1664.  
  1665. /*------------------------------------------------------*/
  1666. /* compute highest score                                */
  1667. /*------------------------------------------------------*/
  1668. highest = 0
  1669. do player = 1 to n
  1670.    highest = max(highest,score.player)
  1671. end
  1672. say "Highest score is" highest
  1673.  
  1674. /*------------------------------------------------------*/
  1675. /* Now compute:                                         */
  1676. /*  * W, the total number of players that have a score  */
  1677. /*    equal to HIGHEST                                  */
  1678. /*  * WINNER.1, WINNER.2 ... WINNER.W, the id-numbers   */
  1679. /*    of these players                                  */
  1680. /*------------------------------------------------------*/
  1681. w = 0                      /* number of winners         */
  1682. do player = 1 to n
  1683.    if score.player = highest then do
  1684.       w = w + 1
  1685.       winner.w = player
  1686.    end
  1687. end
  1688.  
  1689. /*------------------------------------------------------*/
  1690. /* announce winners                                     */
  1691. /*------------------------------------------------------*/
  1692. if w = 1
  1693.    then say "The winner is Player #"winner.1
  1694. else do
  1695.    say "There is a draw for top place.  The winners are"
  1696.    do p = 1 to w
  1697.       say "     Player #"winner.p
  1698.    end
  1699. end
  1700. say
  1701.  
  1702.  
  1703. ΓòÉΓòÉΓòÉ 8.3.2.3. Stems and Tails ΓòÉΓòÉΓòÉ
  1704.  
  1705. The stem of a compound symbol is the portion up to and including the first 
  1706. period.  That is, it is a valid variable name that ends with a period. 
  1707.  
  1708. The stem is followed by a tail, comprised of one or more valid symbols 
  1709. (constants or variables) separated by periods. You can refer to all the 
  1710. variables in an array by using the stem of the array. For example: 
  1711.  
  1712. player. = 0
  1713. say player.1 player.2 player.golf      /* displays '0 0 0'  */
  1714. It is often convenient to set all variables in an array to 0 in this way. 
  1715.  
  1716.  
  1717. ΓòÉΓòÉΓòÉ 8.3.3. Filling a Two-Dimensional Array ΓòÉΓòÉΓòÉ
  1718.  
  1719. You can have more than one period in a compound symbol.  For example, here is 
  1720. the beginning of a program for playing checkers.  BOARD is a 2-dimensional 
  1721. array, 8 squares by 8 squares.  The squares on the board are called 
  1722. BOARD.ROW.COL and there are 64 of them.  Figure "Checker Board" shows how the 
  1723. men are set at the start of the game. 
  1724.  
  1725.  
  1726. Checker Board
  1727.  
  1728. Figure "CHECKERS.CMD" shows a program that sets the men on the checker board. 
  1729.  
  1730.  
  1731. CHECKERS.CMD
  1732.  
  1733. /* This program simulates a board on which the game of  */
  1734. /* checkers can be played.                              */
  1735.  
  1736. /* In the internal representation, Red's "men" are      */
  1737. /* represented by the character "r" and Red's "kings"   */
  1738. /* by the character "R".  Similarly, Black's "men" and  */
  1739. /* "kings" are represented by "b" and "B".              */
  1740. /*------------------------------------------------------*/
  1741. /* Clear the board                                      */
  1742. /*------------------------------------------------------*/
  1743. board. = " "
  1744.  
  1745. /*------------------------------------------------------*/
  1746. /* Set out the men                                      */
  1747. /*------------------------------------------------------*/
  1748. do col = 1 by 2 to 7
  1749.    board.1.col = "r"
  1750. end
  1751. do col = 2 by 2 to 8
  1752.    board.2.col = "r"
  1753. end
  1754. do col = 1 by 2 to 7
  1755.    board.3.col = "r"
  1756. end
  1757. do col = 2 by 2 to 8
  1758.    board.6.col = "b"
  1759. end
  1760. do col = 1 by 2 to 7
  1761.    board.7.col = "b"
  1762. end
  1763. do col = 2 by 2 to 8
  1764.    board.8.col = "b"
  1765. end
  1766.  
  1767.  
  1768. ΓòÉΓòÉΓòÉ 8.3.4. Variables in Programs and Subroutines ΓòÉΓòÉΓòÉ
  1769.  
  1770. Here are some considerations for using variables in REXX programs.  For more 
  1771. information about variables, including how programs written in other languages 
  1772. can use REXX variables, see the REXX Reference. 
  1773.  
  1774.  
  1775. ΓòÉΓòÉΓòÉ 8.3.4.1. Special Variables ΓòÉΓòÉΓòÉ
  1776.  
  1777. REXX has three special variables that are assigned values automatically as 
  1778. needed: 
  1779.  
  1780.  RESULT    holds the value set by a RETURN instruction in a subroutine. (See 
  1781.            RETURN Instruction.) 
  1782.  
  1783.  SIGL      holds the line number of the last call to a label. (See CALL 
  1784.            Instructionand SIGNAL Instruction.) 
  1785.  
  1786.  RC        holds the return code from the last OS/2 command issued. (See 
  1787.            Reading Return Codes.) 
  1788.  
  1789.  
  1790. ΓòÉΓòÉΓòÉ 8.3.5. SYMBOL()Function ΓòÉΓòÉΓòÉ
  1791.  
  1792. It is sometimes useful to check whether a symbol has already been used as a 
  1793. name of a variable.  To do this, use the SYMBOL() function, SYMBOL(name), where 
  1794. name is the name of the symbol that you want to test.  The SYMBOL() function 
  1795. returns: 
  1796.  
  1797.  BAD    if name is not a valid symbol 
  1798.  
  1799.  VAR    if name has been used as a variable in the program 
  1800.  
  1801.  LIT    if the symbol name is a valid variable that has not yet been assigned a 
  1802.         value, or if it is a constant symbol (such as a number). 
  1803.  
  1804.  One use of SYMBOL() is to ensure initialization of a variable; that is, making 
  1805.  certain that the variable is set to a proper starting value before it is used 
  1806.  in an operation.  For example, you can use SYMBOL() to make sure REXX does not 
  1807.  try to add a variable called payment to one named cash until cash has been set 
  1808.  to a numeric value. 
  1809.  
  1810.   if symbol("CASH") = "LIT" then  cash = 0
  1811.  
  1812.   cash = cash + payment
  1813.  
  1814.  Put CASH in quotes to test the symbol rather than its value. Notice what 
  1815.  happens if the argument of SYMBOL() is not in quotes. 
  1816.  
  1817.   cash = 100
  1818.  
  1819.   say symbol(CASH)        /* displays 'LIT', because the value */
  1820.                           /* of CASH is 100 - a constant       */
  1821.  
  1822.   say symbol("CASH")      /* displays 'VAR', because CASH is   */
  1823.                           /* the name of a variable            */
  1824.  
  1825.  Without the enclosing quotes, CASH is treated as a variable and its value is 
  1826.  substituted before the function is performed. 
  1827.  
  1828.  
  1829. ΓòÉΓòÉΓòÉ 8.3.5.1. PROCEDURE Instruction ΓòÉΓòÉΓòÉ
  1830.  
  1831. When you are writing a subroutine, you may not know the names of all the 
  1832. variables in the main program.  You could check by reading the entire program 
  1833. every time you wanted to create a new name, but this is tedious and prone to 
  1834. error.  To delete all variables, for the sake of the subroutine, use the REXX 
  1835. PROCEDURE instruction. 
  1836.  
  1837. Once this instruction has been processed, new variables can be created that are 
  1838. regarded as different, even if some of them have the same names as variables 
  1839. that existed before the PROCEDURE instruction was processed. 
  1840.  
  1841. When a RETURN instruction is processed, the new variables are deleted and the 
  1842. original variables are restored. 
  1843.  
  1844. A PROCEDURE instruction can only be used within an internal routine.  It can be 
  1845. used only once and must be the first instruction in the routine.  For further 
  1846. details on the PROCEDURE instruction, see the REXX Reference. 
  1847.  
  1848. Figure "PROCEDURE.CMD" shows count being used for two separate purposes. 
  1849.  
  1850.  
  1851. PROCEDURE.CMD
  1852.  
  1853.  
  1854.           count = 999
  1855.           list = 3 4 5 6 7
  1856.  
  1857.           CALL average list ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  1858.                   ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ   Γöé
  1859.     ΓöîΓöÇΓöÇΓöÇ ....                                    Γöé   Γöé
  1860.     Γöé     /* At this point:    COUNT = 999   */   Γöé   Γöé
  1861.     Γöé     /*                   RESULT = 5    */   Γöé   Γöé
  1862.     Γöé     ...                                     Γöé   Γöé
  1863.     Γöé     ...                                     Γöé   Γöé
  1864.     Γöé     EXIT                                    Γöé   Γöé
  1865.     Γöé                                             Γöé   Γöé
  1866.     Γöé     ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ   Γöé
  1867.     Γöé                                                Γöé
  1868.     Γöé     AVERAGE:                                    Γöé
  1869.     Γöé     /* The argument must be a list     */       Γöé
  1870.     Γöé     /* of numbers, delimited by blanks.*/       Γöé
  1871.     Γöé     /* The average is returned.        */       Γöé
  1872.     Γöé                                                 Γöé
  1873.     Γöé     PROCEDURE                                   Γöé
  1874.     Γöé                                                 Γöé
  1875.     Γöé     /* At this point the value of LIST */       Γöé
  1876.     Γöé     /* would be LIST                   */       Γöé
  1877.     Γöé     /* and COUNT would be COUNT.       */       Γöé
  1878.     Γöé     ...                                         Γöé
  1879.     Γöé     ...     ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  1880.     Γöé     ...     
  1881.     Γöé     ARG inputlist
  1882.     Γöé     sum = 0
  1883.     Γöé     do count = 1 to words(inputlist)
  1884.     Γöé        sum = sum + word(inputlist,count)
  1885.     Γöé     end
  1886.     Γöé     ...
  1887.     Γöé     ...
  1888.     Γöé     RETURN     sum/words(inputlist)
  1889.     ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  1890.  
  1891.  
  1892. ΓòÉΓòÉΓòÉ 8.3.5.2. PROCEDURE EXPOSE Instruction ΓòÉΓòÉΓòÉ
  1893.  
  1894. To share a limited set of variables between the main routine and the subroutine 
  1895. (leaving all the other variables protected), use PROCEDURE EXPOSE name [name] 
  1896. [name]..., where name is the name of a variable to be shared. 
  1897.  
  1898. You can also name a list of variables to be shared.  By specifying the stem of 
  1899. an array (PROCEDURE EXPOSE player.), you can share all of the variables 
  1900. therein. 
  1901.  
  1902. For further details, see the discussion of the PROCEDURE instruction in the 
  1903. REXX Reference. 
  1904.  
  1905.  
  1906. ΓòÉΓòÉΓòÉ 8.3.6. Other Types of Data Storage ΓòÉΓòÉΓòÉ
  1907.  
  1908. Variables are the principal means of manipulating data within a REXX program. 
  1909. REXX features other ways to work with data outside the program and to share 
  1910. data with other programs, such as: 
  1911.  
  1912.  Queues     store sequential data in memory. 
  1913.  
  1914.  Files      provide more permanent storage on disk. 
  1915.  
  1916.  Refer to Input and Output, for the REXX instructions and functions that work 
  1917.  with external data. 
  1918.  
  1919.  
  1920. ΓòÉΓòÉΓòÉ 9. Expressions ΓòÉΓòÉΓòÉ
  1921.  
  1922. An expression is a description of information that you want REXX to compute. 
  1923. It can be as simple as adding two numbers or as complex as you want to make it. 
  1924.  
  1925.  
  1926. ΓòÉΓòÉΓòÉ 9.1. Basics ΓòÉΓòÉΓòÉ
  1927.  
  1928.      In this chapter: Basics 
  1929.  
  1930.      o Transforming data 
  1931.      o Operator precedence 
  1932.      o Using functions 
  1933.      o Comparing data 
  1934.      o Using comparisons for program control 
  1935.      o Using expressions in instructions 
  1936.      o Tracing evaluation. 
  1937.  
  1938.  
  1939. ΓòÉΓòÉΓòÉ 9.1.1. Transforming Data ΓòÉΓòÉΓòÉ
  1940.  
  1941. The process of REXX reading an expression and producing a result is called 
  1942. evaluating the expression.  REXX has many rules for evaluating expressions. 
  1943.  
  1944. Expressions are made up of terms, the data that is computed, and operators, the 
  1945. computations that are performed. 
  1946.  
  1947. Some examples of REXX expressions are: 
  1948.  
  1949. /*      some arithmetic                 */
  1950. say 3 + 2         /* displays "5"       */
  1951. say 3 * 2         /* displays "6"       */
  1952. say 3 2           /* displays "3 2"     */
  1953. say 3||2          /* displays "32"      */
  1954.  
  1955.  
  1956. /*      some literal strings            */
  1957. say "box" "car"   /* displays "box car" */
  1958. say "box""car"    /* displays "box"car" */
  1959. say "box"||"car"  /* displays "boxcar"  */
  1960.  
  1961.  
  1962. /*      some variables                  */
  1963. x = 6
  1964. y = 7
  1965. say x + y         /* displays "13"      */
  1966. x = x + y
  1967. say x             /* displays "13"      */
  1968.  
  1969.  
  1970. ΓòÉΓòÉΓòÉ 9.1.1.1. Terms ΓòÉΓòÉΓòÉ
  1971.  
  1972. The terms of an expression are the individual pieces of information that you 
  1973. want REXX to work on.  The types of terms that make up expressions are: 
  1974.  
  1975.  Numbers           Strings that REXX can calculate.  REXX recognizes them as 
  1976.                    constant values.  For example: 
  1977.  
  1978.                                       25   3.14159   -6   1989
  1979.  
  1980.  Literal strings   Anything within matched quotes REXX accepts as is.  For 
  1981.                    example: 
  1982.  
  1983.                                       "Wednesday"   'C:\PROGRAMS\'  "09 June 89"
  1984.  
  1985.  Variables         Symbols that stand for changeable data.  When you use a 
  1986.                    variable in an expression, REXX evaluates it and uses its 
  1987.                    value as the expression.  For example: 
  1988.  
  1989.                                       date = 30            /* stores the number 30          */
  1990.                                                            /* in the variable DATE          */
  1991.  
  1992.                                       month = "March"      /* stores the literal string     */
  1993.                                                            /* "March" in the variable MONTH */
  1994.  
  1995.                                       say month date       /* displays "March 30" on screen */
  1996.  
  1997.  Function calls    These are special computations, some built into REXX, others 
  1998.                    that you can create.  When you use a function call in an 
  1999.                    expression, REXX performs the function's calculation first, 
  2000.                    then uses its result as the expression term.  For example: 
  2001.  
  2002.                                       say time()             /* displays the current time   */
  2003.  
  2004.                                       say substr("REXX",2,1) /* displays "E" on screen;     */
  2005.                                                              /* i.e., 1 character from the  */
  2006.                                                              /* string "REXX" beginning     */
  2007.                                                              /* with the 2nd character      */
  2008.  
  2009.  
  2010. ΓòÉΓòÉΓòÉ 9.1.1.2. Basic Operators ΓòÉΓòÉΓòÉ
  2011.  
  2012. The most commonly used operators are those used for arithmetic and 
  2013. concatenation. Arithmetic performs adding, subtracting, multiplying, and 
  2014. dividing.  Some examples of arithmetic operators are: 
  2015.  
  2016. /* add, subtract, multiply ...        */
  2017. say 14 + 5     /* displays "19"       */
  2018. say 14 - 5     /* displays "9"        */
  2019. say 14 * 5     /* displays "70"       */
  2020.  
  2021.  
  2022. /* ... and three ways to divide       */
  2023. say 14 / 5     /* displays "2.8" -    */
  2024.                /* normal division     */
  2025.  
  2026.  
  2027. say 14 % 5     /* displays "2" - the  */
  2028.                /* integer result only */
  2029.  
  2030.  
  2031. say 14 // 5    /* displays "4" -the   */
  2032.                /* remainder only      */
  2033.  
  2034. For more information about using numbers in REXX, see Arithmetic. 
  2035.  
  2036. Concatenation joins strings together with: 
  2037.  
  2038.  o A single blank, if you leave one or more blanks between the terms of an 
  2039.    expression 
  2040.  
  2041.  o No intervening blanks, if you put the terms together.  This is called 
  2042.    abuttal.  For abuttal to work, REXX  must be able to recognize the terms as 
  2043.    separate. 
  2044.  
  2045.  o No intervening blanks, if you use the concatenation operator vbar.| (two 
  2046.    vertical bars). Use this operator where abuttal does not work (such as with 
  2047.    two variables) or to state exactly how you want the strings joined. 
  2048.  
  2049.    Note:  On the OS/2 operating system, REXX uses ASCII character 124 as the 
  2050.           concatenation operator and as the logical OR operator.  This 
  2051.           character may appear as a solid vertical bar (|) or as a split 
  2052.           vertical bar (|). The character on the screen may not match the 
  2053.           character engraved on the key.  If you receive error 13, invalid 
  2054.           character in program on an instruction including a vertical bar 
  2055.           character, make sure this character is ASCII 124. 
  2056.  
  2057.  
  2058.  Some examples of concatenation are: 
  2059.  
  2060.   say "slow"    "coach"  /* displays 'slow coach' */
  2061.  
  2062.   adjective = "slow"
  2063.   say adjective  "coach" /* displays 'slow coach'           */
  2064.  
  2065.   say adjective"coach"   /* displays 'slowcoach'            */
  2066.                          /* (using abuttal)                 */
  2067.  
  2068.   say "slow"||"coach"    /* displays 'slowcoach'                     */
  2069.  
  2070.  
  2071.   say 4 5                /* displays '4 5'                 */
  2072.   say 4||5               /* displays '45'                            */
  2073.  
  2074.   tens = 4
  2075.   units = 5
  2076.   say tensunits          /* displays 'TENSUNITS' (abuttal     */
  2077.                          /*  produces a new symbol)           */
  2078.  
  2079.   say tens||units        /* says '45'                           */
  2080.   say (4||5) / 3         /* displays '15'                            */
  2081.  
  2082.  Concatenation works with numeric as well as non-numeric strings.  In the 
  2083.  previous example, parentheses are used to force REXX to concatenate the 4 and 
  2084.  the 5 before dividing the result by 3. 
  2085.  
  2086.  
  2087. ΓòÉΓòÉΓòÉ 9.1.2. Operator Precedence ΓòÉΓòÉΓòÉ
  2088.  
  2089. Without parentheses in the previous example, REXX would have performed the 
  2090. division first, then the concatenation.  It would divide 5 by 3 (result 
  2091. 1.6666667) and then join the 4 in front.  For example: 
  2092.  
  2093. say 4||5 / 3           /* displays '41.6666667' */
  2094.  
  2095. REXX gives precedence, or priority, to division over concatenation.  This means 
  2096. that REXX has a set of built-in rules for the order in which operations are 
  2097. performed. 
  2098.  
  2099. Basically, REXX evaluates an expression by reading it from left to right. 
  2100. Before it does, it takes into account: 
  2101.  
  2102.  o Any parentheses you have used. 
  2103.  
  2104.  o The built-in operator precedence of REXX, which means some operations get 
  2105.    higher priority than others, no matter where they are in the expression. 
  2106.    Multiplication and division come before addition and subtraction; addition 
  2107.    and subtraction before concatenation. See page Precedence for a listing of 
  2108.    REXX operator precedence. 
  2109.  
  2110.  You can always use parentheses to override the precedence rules of REXX. It is 
  2111.  a good practice to use parentheses because they help make your program more 
  2112.  readable. 
  2113.  
  2114.  
  2115. ΓòÉΓòÉΓòÉ 9.1.3. Using Functions ΓòÉΓòÉΓòÉ
  2116.  
  2117. For more extensive computations, REXX has built-in functions. A function always 
  2118. returns (produces) a value.  This value is represented in an expression by a 
  2119. symbol referred to as a function call.  All function calls consist of a name, 
  2120. followed by parentheses.  There is no space between the name and the first 
  2121. parenthesis. For example: 
  2122.  
  2123. length("Madison")
  2124.  
  2125.  o The value you want the function to work on is called the function's 
  2126.    argument.  In this example, the argument is the literal string "Madison". 
  2127.  
  2128.  o The value a function call produces is its return value.  The return value 
  2129.    depends on what you put inside the parentheses.  In this example, the 
  2130.    LENGTH() function returns the value 7, the number of characters in Madison. 
  2131.  The instruction, say length("Madison Avenue") displays the return value 14. 
  2132.  
  2133.  The argument of a function can itself be an expression.  For example, the 
  2134.  function ABS() returns the absolute (positive) value of a given number. Given 
  2135.  an arithmetic expression as an argument, ABS() first evaluates the expression 
  2136.  and gets the result.  In the following example, the ABS() function calculates 
  2137.  the result -98and returns the absolute value of that result, which is 98. 
  2138.  
  2139.   say abs(2 - (50 * 2))      /* displays '98' */
  2140.  
  2141.  If a function allows for or requires more than one argument, the arguments are 
  2142.  separated by commas.  For example: 
  2143.  
  2144.   say copies("=",80)  /* displays 80 "=" characters */
  2145.  
  2146.  Some functions need no arguments.  For example, the DATE() function gets the 
  2147.  date from your system clock.  It has several optional arguments. 
  2148.  
  2149.   say date()          /* displays '15 Mar 89'   */
  2150.   say date(w)         /* displays 'Wednesday'   */
  2151.   say date(s)         /* displays '19890315'    */
  2152.  
  2153.  The DATATYPE() function reports the type of data an expression evaluates as: 
  2154.  
  2155.   str1 = "ABC"        /* a character string     */
  2156.   str2 = "12"         /* a numeric string       */
  2157.   say datatype(str1)  /* displays 'CHAR'        */
  2158.   say datatype(str2)  /* displays 'NUM'         */
  2159.  
  2160.  You can include a function call anywhere within an expression.  REXX performs 
  2161.  the function's computation and then substitutes the return value for the 
  2162.  function call before it evaluates the entire expression. 
  2163.  
  2164.  For more information about functions, see Program Structure. 
  2165.  
  2166.  Refer to the REXX Reference for descriptions of the REXX built-in functions. 
  2167.  
  2168.  
  2169. ΓòÉΓòÉΓòÉ 9.1.4. Comparing Data ΓòÉΓòÉΓòÉ
  2170.  
  2171. Comparisons test data rather than manipulate it.  The following is an example 
  2172. of a comparison in a program (see Figure "HELLO.CMD"). 
  2173.  
  2174. if who = "" then say...
  2175.  
  2176. What happened next in the program depended on the test:  was the variable who 
  2177. empty? 
  2178.  
  2179. Comparisons are performed using the following operators: 
  2180.  
  2181. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  2182. Γöé OPERATOR   Γöé MEANING              Γöé
  2183. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2184. Γöé "="        Γöé Equal                Γöé
  2185. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2186. Γöé "\="       Γöé Not equal            Γöé
  2187. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2188. Γöé "<>" or    Γöé Not equal            Γöé
  2189. Γöé "><"       Γöé                      Γöé
  2190. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2191. Γöé ">"        Γöé Greater than         Γöé
  2192. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2193. Γöé "\>"       Γöé Not greater than     Γöé
  2194. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2195. Γöé "<"        Γöé Less than            Γöé
  2196. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  2197. Γöé "\<"       Γöé Not less than        Γöé
  2198. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  2199.  
  2200. The comparison operators can be combined so that >= stands for greater than or 
  2201. equal and \>= means not greater than or equal (same as <). 
  2202.  
  2203. The backslash character (\) negates a comparison operator, turning equalto not 
  2204. equal and so on.  This character is also used for not in expressions generally. 
  2205. (See NOT Operator (\) on page Boolean Operators.) 
  2206.  
  2207. The equal sign (=) can have different meanings in REXX depending on its 
  2208. position in a clause.  For example: 
  2209.  
  2210. amount = 5      /* The variable AMOUNT gets the value 5     */
  2211.  
  2212. say amount = 5  /* Compare the value of AMOUNT with 5       */
  2213.                 /* If they are the same, displays '1'       */
  2214.                 /* Otherwise, displays '0'                  */
  2215. The rule is that a clause beginning with symbol = ... is an assignment.  An 
  2216. equal sign anywhere else in a clause usually stands as a comparison operator. 
  2217. There are exceptions.  The equal sign has a special use in the PARSE 
  2218. instruction, and it is a character, not an operator, in a comment or literal 
  2219. string. 
  2220.  
  2221.  
  2222. ΓòÉΓòÉΓòÉ 9.1.4.1. Testing for True or False ΓòÉΓòÉΓòÉ
  2223.  
  2224. The result of a comparison expression is either true (1) or false (0).  For 
  2225. example: 
  2226.  
  2227. /* some comparisons */
  2228. say 5 = 5                   /* displays '1'       */
  2229. say 5 <> 5                  /* displays '0'       */
  2230. say 5 = 4                   /* displays '0'       */
  2231. say 2 + 2 = 4               /* displays '1'       */
  2232. say 2 + 2 = 5               /* displays '0'       */
  2233.  
  2234. howmuch = 2 + 3             /* assigns the sum    */
  2235.                             /* of 2 and 3 to the  */
  2236.                             /* variable HOWMUCH   */
  2237.  
  2238. say "apples" = "oranges"    /* displays '0' */
  2239.  
  2240. fruit = "oranges"           /* assigns the string */
  2241.                             /* "oranges" to the   */
  2242.                             /* variable FRUIT     */
  2243.  
  2244. say fruit = "apples"        /* displays '0'       */
  2245.  
  2246. say fruit = "oranges"       /* displays '1'       */
  2247.  
  2248. say howmuch fruit         /* displays "5 oranges" */
  2249.  
  2250. say howmuch fruit = "4 oranges"  /* displays '0'  */
  2251. say howmuch fruit = "5 plums"    /* displays '0'  */
  2252. say howmuch fruit = "5 oranges"  /* displays '1'  */
  2253.  
  2254.  
  2255. ΓòÉΓòÉΓòÉ 9.1.4.2. Combining Expressions ΓòÉΓòÉΓòÉ
  2256.  
  2257. It is often useful to combine two or more comparisons to find a single 
  2258. true-or-false value.  You can have REXX evaluate a set of comparisons and 
  2259. compute an overall value of 1 or 0 for the set.  You can combine comparisons so 
  2260. that REXX evaluates them as: 
  2261.  
  2262.  o True (1) only if all of the comparisons in the set evaluate as 1, but false 
  2263.    (0) if any one or more  of them evaluates as 0. This is called an AND 
  2264.    condition.  To combine comparisons this way, use the AND (&) operator.  For 
  2265.    example: 
  2266.  
  2267.       fruit = "grapes"
  2268.       howmuch = 10
  2269.       say fruit = "apples" & howmuch = 10   /* displays '0'   */
  2270.       say fruit = "grapes" & howmuch = 5    /* displays '0'   */
  2271.       say fruit = "grapes" & howmuch = 10   /* displays '1'   */
  2272.  
  2273.    Only in the third example are both of the comparisons true, so only, then, 
  2274.    is the combined result evaluated as 1. 
  2275.  
  2276.  o True (1) if any one or more of the comparisons in the set evaluate as 1, and 
  2277.    false (0) only if all the comparisons evaluate as 0. This is called an OR 
  2278.    condition.  To combine comparisons this way, use the OR (|) operator.  For 
  2279.    example: 
  2280.  
  2281.       fruit = "grapes"
  2282.       howmuch = 10
  2283.       say fruit = "apples" | howmuch = 10   /* displays '1'   */
  2284.       say fruit = "grapes" | howmuch = 5    /* displays '1'   */
  2285.       say fruit = "grapes" | howmuch = 10   /* displays '1'   */
  2286.       say fruit = "apples" | howmuch = 5    /* displays '0'   */
  2287.  
  2288.    Both comparisons, individually, had to evaluate as 0 in order for their 
  2289.    combined value to be 0. 
  2290.  
  2291.  
  2292. ΓòÉΓòÉΓòÉ 9.1.5. Using Comparisons for Program Control ΓòÉΓòÉΓòÉ
  2293.  
  2294. REXX has a set of instructions that control the program and choose the action a 
  2295. program is to take in a given situation.  That situation is determined by 
  2296. comparisons. 
  2297.  
  2298. Instructions, such as IF expression THEN ..., must be given an expression that 
  2299. computes to 0 or 1. In the example of IF...THEN..., a result of 1 means the 
  2300. clause following THEN is processed; a result of 0 means that it is not 
  2301. processed. 
  2302.  
  2303. The following two examples give the same result. 
  2304.  
  2305. ready = "YES"
  2306. .
  2307. .
  2308. .
  2309. if ready = "YES" then ...
  2310. .
  2311. .
  2312. .
  2313. or 
  2314.  
  2315. ready = 1
  2316. .
  2317. .
  2318. .
  2319. if ready then ...
  2320. .
  2321. .
  2322. .
  2323.  
  2324. You can use whichever form you prefer. 
  2325.  
  2326. For more information about how comparisons can control a program's processing, 
  2327. see Program Control. 
  2328.  
  2329.  
  2330. ΓòÉΓòÉΓòÉ 9.1.6. Using Expressions in Instructions ΓòÉΓòÉΓòÉ
  2331.  
  2332. The REXX Reference and the online OS/2 Procedures Language/2 REXX provide an 
  2333. alphabetical listing of all REXX instructions and their syntax. Where the 
  2334. syntax of an instruction calls for or allows an expression, you can use any of 
  2335. the rules described here. 
  2336.  
  2337.  
  2338. ΓòÉΓòÉΓòÉ 9.1.7. Tracing Evaluation ΓòÉΓòÉΓòÉ
  2339.  
  2340. If your program produces unexpected results, the problem may be that an 
  2341. expression was mis-stated.  When your program will not run, use the TRACE 
  2342. instruction.  TRACE displays how REXX evaluates expressions while the program 
  2343. is actually running.  The options most often used are: 
  2344.  
  2345.  TRACE Intermediates    Displays the immediate result of each operation. 
  2346.  
  2347.  TRACE Results          Displays only the final result of each expression, 
  2348.                         after it has been evaluated. 
  2349.  
  2350.  When a TRACE instruction is being interpreted, the first letter of the option 
  2351.  determines the type of tracing that is switched on; the rest of the word is 
  2352.  ignored. 
  2353.  
  2354.  For example, to TRACE intermediate results for an expression, you could write: 
  2355.  
  2356.   TRACE I
  2357.   ... expression
  2358.  Figure "TTRACE.CMD" shows a program that uses the TRACE I instruction. 
  2359.  
  2360.  
  2361.   TTRACE.CMD
  2362.  
  2363.   /* Example: to show how an expression       */
  2364.   /* is evaluated, operation by operation     */
  2365.   x = 9
  2366.   y = 2
  2367.   trace I                  /* Switch on tracing. */
  2368.   if x + 1 > 5 * y then    /* If the comparison  */
  2369.                            /* evaluates as '1'   */
  2370.   say "x is big enough."   /* ...display this.   */
  2371.  
  2372.  The following is displayed on the screen when you run the program. 
  2373.  
  2374.   [C:\] ttrace
  2375.        6 *-* If x + 1 > 5 * y
  2376.          >V>   "9"
  2377.          >L>   "1"
  2378.          >O>   "10"
  2379.          >L>   "5"
  2380.          >V>   "2"
  2381.          >O>   "10"
  2382.          >>>   "0"
  2383.   [C:\]
  2384.  
  2385.  The symbols mean: 
  2386.  
  2387.  *-*    An instruction is being traced.  The number on the left is the line 
  2388.         number in your program. 
  2389.  
  2390.  >V>    Value of a Variable. 
  2391.  
  2392.  >L>    Value of a Literal. 
  2393.  
  2394.  >O>    Result of an Operation. 
  2395.  
  2396.  >>>    The final result of the evaluation. 
  2397.  
  2398.  The output information below Figure "TTRACE.CMD" shows that the final result 
  2399.  is false (0). Because the IF expression is false, the THEN clause is not 
  2400.  processed. 
  2401.  
  2402.  You may not need a trace of every intermediate result.  For example, to 
  2403.  display only the final evaluation results, use TRACE results. 
  2404.  
  2405.   TRACE R
  2406.   ... expression
  2407.  
  2408.  Figure "RTRACE.CMD" shows a program that uses the TRACE R instruction. 
  2409.  
  2410.  
  2411.   RTRACE.CMD
  2412.  
  2413.   /* Example: to show how an expression is evaluated,     */
  2414.   /* operation by operation using TRACE R                 */
  2415.   x = 9
  2416.   y = 2
  2417.   trace R                  /* Switch on tracing. */
  2418.   if x + 1 > 5 * y then    /* If the comparison  */
  2419.                            /* evaluates as '1'   */
  2420.   say "x is big enough."   /* ...display this.   */
  2421.  
  2422.  The following is displayed on the screen when you run the program. 
  2423.  
  2424.   [C:\] rtrace
  2425.        6 *-* if x + 1 > 5 * y
  2426.          >>>   "0"
  2427.   [C:\]
  2428.  
  2429.  Here too, the symbol >>> indicates the final result.  Again, the final result 
  2430.  is false (0).  Because the IF expression is false, the THEN clause is not 
  2431.  processed. 
  2432.  
  2433.  
  2434. ΓòÉΓòÉΓòÉ 9.1.8. Summary ΓòÉΓòÉΓòÉ
  2435.  
  2436. This completes "Basics" in this chapter.  You have learned how to: 
  2437.  
  2438.  o Use basic REXX arithmetic 
  2439.  o Join strings by concatenation 
  2440.  o Test data using comparison operators 
  2441.  o Use trace evaluation while a program runs. 
  2442.  
  2443.  "Advanced Topics" in this chapter discusses: 
  2444.  
  2445.  o Operator precedence 
  2446.  o Using parentheses 
  2447.  o Manipulating strings with functions 
  2448.  o More about comparisons. 
  2449.  
  2450.  To continue with "Basics," go to page 5-1. 
  2451.  
  2452.  
  2453. ΓòÉΓòÉΓòÉ 9.2. Advanced Topics ΓòÉΓòÉΓòÉ
  2454.  
  2455.      In this chapter: Advanced Topics 
  2456.  
  2457.      o Precedence 
  2458.      o Using parentheses 
  2459.      o More about numbers 
  2460.      o Concatenation 
  2461.      o Substring functions 
  2462.      o Comparisons 
  2463.      o Translating and converting data. 
  2464.  
  2465.  
  2466. ΓòÉΓòÉΓòÉ 9.3. Precedence ΓòÉΓòÉΓòÉ
  2467.  
  2468.  
  2469.  
  2470.  
  2471.  
  2472.  
  2473.  
  2474. When evaluating an expression, REXX reads the operations from left to right. 
  2475. But some operators are given a higher precedence (priority) than others and are 
  2476. processed first regardless of their position.  The complete order of precedence 
  2477. of the operators by group (highest priority at the top) is: 
  2478.  
  2479.  Prefix operators        \  -  + 
  2480.  
  2481.  Power                   ** 
  2482.  
  2483.  Multiply and divide     * / % // 
  2484.  
  2485.  Add and subtract        +  - 
  2486.  
  2487.  Concatenation           " "  ||  abuttal 
  2488.  with/without blank 
  2489.  
  2490.  Comparison operators    ==  =  \== 
  2491.                          \= 
  2492.                          >  <  >>  <<  >< 
  2493.                          <>  >=  \< 
  2494.                          >>=  \<< 
  2495.                          <=  \>  <<= 
  2496.                          \>> 
  2497.  
  2498.  Logical and             & 
  2499.  
  2500.  Logical or              | && 
  2501.  (inclusive/exclusive) 
  2502.  
  2503.  Note:  For the OS/2 operating system, || can also be used as the concatenation 
  2504.         operator and as the logical OR operator. See Basic Operators for 
  2505.         additional information. 
  2506.  
  2507.  From this list, you can determine the sequence of operations for any 
  2508.  expression.  For example: 
  2509.  
  2510.   Say 3 + 2 * 5         /*    displays '13'  */
  2511.  
  2512.  Because multiply (*) has a higher priority than add (+), the multiply 
  2513.  operation is done before the operation on its left. Similarly, because add (+) 
  2514.  has a higher priority than concatenate (blank), the add operation is done 
  2515.  before the concatenate operation.  For example: 
  2516.  
  2517.   Say 3 2+2 5           /* displays '3 4 5' */
  2518.  
  2519.  
  2520. ΓòÉΓòÉΓòÉ 9.3.1. Using Parentheses ΓòÉΓòÉΓòÉ
  2521.  
  2522. You can use parentheses to force evaluation in a different order since 
  2523. expressions inside parentheses are evaluated first.  For example the value of: 
  2524.  
  2525.  6 - 4 + 1    is  3. 
  2526.  6 -(4 + 1)   is  1. 
  2527.  3 + 2||2 + 3  is  55. 
  2528.  3 +(2||2)+ 3  is  28. 
  2529.  
  2530.  
  2531. ΓòÉΓòÉΓòÉ 9.3.1.1. Test Yourself ΓòÉΓòÉΓòÉ
  2532.  
  2533. What is the value of: 
  2534.  
  2535.   1. 4 + 20 "tailors" 
  2536.   2. 24 = 4 + 20 
  2537.   3. "eggs" = "eggs"  &  2*2 = 4 
  2538.   4. 3 / 2*5 
  2539.   5. 3 || 7+7 
  2540.   6. 3(2+2) 
  2541.   7. (2+2)3. 
  2542.  
  2543.  
  2544. ΓòÉΓòÉΓòÉ 9.3.1.1.1. Answers: ΓòÉΓòÉΓòÉ
  2545.  
  2546.   1. 24 tailors (add before concatenate) 
  2547.   2. 1 (add before comparison) 
  2548.   3. 1 (comparison before AND, multiply before AND, comparison before AND) 
  2549.   4. 7.5 (operators that have the same priority are processed left to right) 
  2550.   5. 314 (add before concatenate) 
  2551.   6. calls the function 3 with the argument 4 (or gives a syntax error if a 
  2552.      function or subroutine named 3 does not exist) 
  2553.   7. 43 (evaluate expression in parentheses first; then do the abuttal). 
  2554.  
  2555.  
  2556. ΓòÉΓòÉΓòÉ 9.3.2. More about Numbers ΓòÉΓòÉΓòÉ
  2557.  
  2558. REXX regards everything in a program as a string to be evaluated. REXX treats 
  2559. certain strings as numbers that can be calculated, such as: 
  2560.  
  2561.  o A number begins with a digit, decimal point, or sign (+ or -). 
  2562.  
  2563.  o Powers of 10 are indicated by E. These are called floating point numbers. 
  2564.  
  2565.  o Numbers may be in quotes, and spaces are allowed around the plus or minus 
  2566.    sign. 
  2567.  
  2568.  For more information about valid numbers, see About REXX Numbers. 
  2569.  
  2570.  
  2571. ΓòÉΓòÉΓòÉ 9.3.3. Concatenation ΓòÉΓòÉΓòÉ
  2572.  
  2573. The three concatenation operations are: 
  2574.  
  2575.  o Leave one or more spaces between the terms.  REXX joins the terms with a 
  2576.    single blank. 
  2577.  
  2578.  o Put the terms together with no space.  You can do this so long as REXX can 
  2579.    recognize the terms as separate 
  2580.  
  2581.  o Use the || operator to join the terms without a blank. 
  2582.  
  2583.    For the OS/2 operating system, || can also be used as the concatenation 
  2584.    operator.  See Basic Operators for further information. 
  2585.  
  2586.  
  2587. ΓòÉΓòÉΓòÉ 9.3.4. Substring Functions ΓòÉΓòÉΓòÉ
  2588.  
  2589. The following two substring functions are useful when working with strings. 
  2590.  
  2591.  
  2592. ΓòÉΓòÉΓòÉ 9.3.4.1. Getting Pieces of Strings ΓòÉΓòÉΓòÉ
  2593.  
  2594. To select a part of a string (a substring), use the SUBSTR() function.  For 
  2595. example: 
  2596.  
  2597. substr(string,n)
  2598. substr(string,n,length)
  2599. where: 
  2600.  
  2601.  string is the string from which the substring is taken. 
  2602.  
  2603.  n      is the position of the character in string that is the first character 
  2604.         of the substring.  (Characters in a string are numbered 1,2,3,...) 
  2605.  
  2606.  length (optional); is the number of characters in the substring.  If you omit 
  2607.         it, the rest of string (from the nth position to the end) is returned. 
  2608.  
  2609.  An example using the SUBSTR() function is: 
  2610.  
  2611.   say substr('revealing',1,6)    /* displays 'reveal'   */
  2612.   verb = substr('revealing',1,6) /* stores 'reveal' */
  2613.                                  /* in  a variable  */
  2614.  
  2615.   say substr(verb,2)      /* displays 'eveal' */
  2616.   say substr(verb,2,3)    /* displays 'eve'   */
  2617.   say substr(verb,3,4)    /* displays 'veal'  */
  2618.  
  2619.  
  2620. ΓòÉΓòÉΓòÉ 9.3.4.2. Finding Lengths of Strings ΓòÉΓòÉΓòÉ
  2621.  
  2622. To find out the length of the result of any string or string expression, use 
  2623. the LENGTH() function, length(n), where n is the number of characters in the 
  2624. string.  For example: 
  2625.  
  2626. verb = "reveal"
  2627. say length(verb)      /* displays '6'    */
  2628.  
  2629. Figure "CHKFNAME.CMD" shows a program that uses these two functions.  The 
  2630. program checks a file name typed by a user. 
  2631.  
  2632.  
  2633. CHKFNAME.CMD
  2634.  
  2635. /* Checking a file name */
  2636. say "Type a file name"
  2637. pull fname"."ext          /* Pull reads the file name   */
  2638.                            /* up to the period (if an   */
  2639.                            /* extension is entered)     */
  2640. if length(fname) > 8
  2641. then
  2642.    do
  2643.       fname = substr(fname,1,8)
  2644.       say "The file name you typed was too long. ",
  2645.           fname "will be used."
  2646.    end
  2647.  
  2648. For more information about substrings, see String Functions. 
  2649.  
  2650.  
  2651. ΓòÉΓòÉΓòÉ 9.3.5. Parsing ΓòÉΓòÉΓòÉ
  2652.  
  2653. Another way to manipulate and analyze string expressions is by parsing.  See 
  2654. Parsing. 
  2655.  
  2656.  
  2657. ΓòÉΓòÉΓòÉ 9.3.6. Comparisons ΓòÉΓòÉΓòÉ
  2658.  
  2659. Comparisons are performed using these operators: 
  2660.  
  2661.  =                   (equal) 
  2662.  
  2663.  \= or <> or ><      (not equal) 
  2664.  
  2665.  >                   (greater than) 
  2666.  
  2667.  \>                  (not greater than) 
  2668.  
  2669.  <                   (less than) 
  2670.  
  2671.  \<                  (not less than). 
  2672.  
  2673.  
  2674. ΓòÉΓòÉΓòÉ 9.3.7. Comparing Numbers ΓòÉΓòÉΓòÉ
  2675.  
  2676. Use comparison operators in an expression to compare the terms.  The result is 
  2677. 1 if the comparison is true; 0 if the comparison is false. 
  2678.  
  2679. For strings that are numbers, on which REXX can perform arithmetic, comparisons 
  2680. work differently.  If both the terms being compared are numbers, comparison is 
  2681. numeric, rather than character-by-character.  For example the value of: 
  2682.  
  2683.  5 > 3 is 1     (true) 
  2684.  2.0 = 002 is 1 (true) 
  2685.  3E2 < 299 is 0 (false). 
  2686.  
  2687.  
  2688. ΓòÉΓòÉΓòÉ 9.3.8. Comparing Characters ΓòÉΓòÉΓòÉ
  2689.  
  2690. Comparing characters is performed by using one of two methods, normal 
  2691. comparison or strict comparison.  Normal comparison ignores leading and 
  2692. trailing blanks and compares character-by-character.  Strict comparison 
  2693. compares character-by-character including any blanks. 
  2694.  
  2695. The value of a character is less than another character according to this 
  2696. sequence of lowest to highest value. 
  2697.  
  2698.  Lowest ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ Highest
  2699.  
  2700.  Γöé                blank
  2701.  Γöé       .../     special characters
  2702.  Γöé      0...9     numbers
  2703.  Γöé      A...Z     uppercase letters
  2704.  Γöé      [...`     special characters
  2705.  Γöé      a...z     lowercase letters
  2706.  Γöé      {...Γûá     special characters
  2707.  Γöé
  2708.  
  2709.  
  2710.  Highest
  2711.  
  2712. Note:  Special characters are mixed between the previously listed categories of 
  2713. numbers and letters as shown.  Only unaccented characters and numbers are in 
  2714. numerical order in any of the code pages supported by the OS/2 program. All 
  2715. characters are compared through pure binary sorting according to their order in 
  2716. the code page you are using.  For more information on the special characters 
  2717. for the primary code page you are using, see Keyboards and Code Pages. :enote. 
  2718.  
  2719.  
  2720. ΓòÉΓòÉΓòÉ 9.3.8.1. Normal Comparison ΓòÉΓòÉΓòÉ
  2721.  
  2722. If either of the terms is not a number, leading and trailing blanks are 
  2723. ignored.  The shorter string is padded on the right with blanks and then the 
  2724. strings are compared from left to right, character-by-character.  If the 
  2725. strings are not equal, the first pair of characters that do not match determine 
  2726. the result. 
  2727.  
  2728. For example, if "  Cheese" is compared with "Chalk ": 
  2729.  
  2730. leading blanks
  2731. ignored
  2732.       ΓöîΓöÇΓöÉ
  2733.        
  2734.      ΓöîΓöÇΓö¼ΓöÇΓö¼ΓöÇΓö¼ΓöÇΓö¼ΓöÇΓö¼ΓöÇΓö¼ΓöÇΓö¼ΓöÇΓöÉ
  2735.      Γöé Γöé ΓöéCΓöéhΓöéeΓöéeΓöésΓöéeΓöé
  2736.      ΓööΓöÇΓö┤ΓöÇΓö┤ΓöÇΓö┤ΓöÇΓö┤ΓöÇΓö┤ΓöÇΓö┤ΓöÇΓö┤ΓöÇΓöÿ
  2737.           Γöé Γöé Γöé
  2738.           = = * ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ 'a' < 'e', so 'Chalk' << '  Cheese'
  2739.           Γöé Γöé Γöé
  2740.          ΓöîΓöÇΓö¼ΓöÇΓö¼ΓöÇΓö¼ΓöÇΓö¼ΓöÇΓö¼ΓöÇΓöÉ  shorter string
  2741.          ΓöéCΓöéhΓöéaΓöélΓöékΓöé Γöé  padded with blanks
  2742.          ΓööΓöÇΓö┤ΓöÇΓö┤ΓöÇΓö┤ΓöÇΓö┤ΓöÇΓö┤ΓöÇΓöÿ
  2743.  
  2744.  
  2745. ΓòÉΓòÉΓòÉ 9.3.8.2. Test Yourself ΓòÉΓòÉΓòÉ
  2746.  
  2747.   1. What is the value of each of the following expressions? 
  2748.  
  2749.      a. "3" < "five" 
  2750.      b. "Kilogram" < "kilogram" 
  2751.      c. "a" > "#" 
  2752.      d. "q" > "?" 
  2753.      e. "9a" > "9" 
  2754.      f. "?" > " " 
  2755.  
  2756.   2. What is displayed on the screen when the program shown in Figure 
  2757.      "FAIR.CMD" is run? 
  2758.  
  2759.  
  2760.           FAIR.CMD
  2761.  
  2762.           /* A fair comparison */
  2763.           say "Apples" = "Apples"
  2764.  
  2765.  
  2766. ΓòÉΓòÉΓòÉ 9.3.8.2.1. Answers: ΓòÉΓòÉΓòÉ
  2767.  
  2768.   1. All are 1 (true). 
  2769.  
  2770.   2. The following is displayed on the screen; because "Apples" is equal to 
  2771.      "Apples", the result is 1 (true). 
  2772.  
  2773.           [C:\] fair
  2774.           1
  2775.           [C:\]
  2776.  
  2777.  
  2778. ΓòÉΓòÉΓòÉ 9.3.8.3. Strict Comparisons ΓòÉΓòÉΓòÉ
  2779.  
  2780. By using strict-comparison operators, we can specify character-by-character 
  2781. comparisons, with no padding of either of the strings. They do not try to 
  2782. perform numeric comparisons because they test for an exact match between the 
  2783. two strings. 
  2784.  
  2785. To find out whether two strings are exactly equal, use the double-equal sign 
  2786. (==) operator.  For example: 
  2787.  
  2788.  The value of "cookies" =  "  cookies" is 1 (true) 
  2789.  
  2790.  The value of "cookies" \=  "  cookies" is 0 (false) 
  2791.  
  2792.  The value of "cookies" ==  "  cookies" is 0 (false) 
  2793.  
  2794.  The value of "cookies" \==  "  cookies" is 1 (true) 
  2795.  
  2796.  Blanks are lower in the ASCII sequence than letters. Strict comparison 
  2797.  compares the leading blanks in its evaluation. 
  2798.  
  2799.  To find out whether two strings are exactly greater than or exactly less than, 
  2800.  use the double-greater-than (>>) and double-less-than (<<) operators.  A 
  2801.  character is less than another character if it comes earlier in the sequence, 
  2802.  see Comparing Characters.  For example the value of: 
  2803.  
  2804.  "cookies" >> "carrots" is 1 (true) 
  2805.  
  2806.  "$10" >> "nine" is 0 (false) 
  2807.  
  2808.  "steak" << "fish" is 0 (false) 
  2809.  
  2810.  " steak" << "steak" is 1 (true). 
  2811.  
  2812.  Since the blank is lower in the sequence of characters, " steak" is strictly 
  2813.  less than "steak". 
  2814.  
  2815.  See the difference now when we strictly compare "  Cheese" and "Chalk": 
  2816.  
  2817.   leading blanks
  2818.   counted
  2819.         ΓöîΓöÇΓöÉ
  2820.          
  2821.        ΓöîΓöÇΓö¼ΓöÇΓö¼ΓöÇΓö¼ΓöÇΓö¼ΓöÇΓö¼ΓöÇΓö¼ΓöÇΓö¼ΓöÇΓöÉ
  2822.        Γöé Γöé ΓöéCΓöéhΓöéeΓöéeΓöésΓöéeΓöé
  2823.        ΓööΓöÇΓö┤ΓöÇΓö┤ΓöÇΓö┤ΓöÇΓö┤ΓöÇΓö┤ΓöÇΓö┤ΓöÇΓö┤ΓöÇΓöÿ
  2824.         Γöé
  2825.         * ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ a blank < 'C' so '  Cheese' << 'Chalk'
  2826.         Γöé
  2827.  
  2828.        ΓöîΓöÇΓö¼ΓöÇΓö¼ΓöÇΓö¼ΓöÇΓö¼ΓöÇΓöÉ
  2829.        ΓöéCΓöéhΓöéaΓöélΓöékΓöé   no padding of the
  2830.        ΓööΓöÇΓö┤ΓöÇΓö┤ΓöÇΓö┤ΓöÇΓö┤ΓöÇΓöÿ   shorter string
  2831.  
  2832.  Strict-comparison operators are especially useful when you want to compare 
  2833.  strings for leading and trailing blanks. 
  2834.  
  2835.  Strict comparison is not usually applied to numeric strings, because the 
  2836.  reason for such a comparison is generally to compare values rather than 
  2837.  characters.  Given that x = "2" and y = "+2", the value of: 
  2838.  
  2839.  x = y is 1 (true) 
  2840.  
  2841.  x \= y is 0 (false) 
  2842.  
  2843.  x == y is 0 (false) 
  2844.  
  2845.  x \== y is 1 (true). 
  2846.  
  2847.  Strict comparison is also useful if you want to check for nonsignificant 
  2848.  zeroes or exponential notation.  For example, the value of: 
  2849.  
  2850.  32.000 = 32  is 1 (true) 
  2851.  
  2852.  32.000 == 32  is 0 (false) 
  2853.  
  2854.  000000 = 0E0000  is 1 (true) 
  2855.  
  2856.  000000 == 0E0000 is 0 (false). 
  2857.  
  2858.  
  2859. ΓòÉΓòÉΓòÉ 9.3.8.4. Boolean Operators ΓòÉΓòÉΓòÉ
  2860.  
  2861. The logical or Boolean operators modify and combine expressions. The Boolean 
  2862. operators are: 
  2863.  
  2864.  o NOT Operator (\)-A not operator (\) placed in front of a term changes its 
  2865.    value from true to false or from false to true. 
  2866.  
  2867.    A NOT operator (\) reverses the result of any comparison it precedes.  An 
  2868.    expression that REXX otherwise evaluates as 1 is changed to 0 when you put 
  2869.    the NOT operator in front of it.  Similarly, an expression that REXX would 
  2870.    otherwise evaluate as 0 is evaluated as 1 when preceded by a NOT operator. 
  2871.    For example: 
  2872.  
  2873.       say \ 0                     /* displays '1'             */
  2874.       say \ 1                     /* displays '0'             */
  2875.       say \ 2                     /* returns a syntax error   */
  2876.  
  2877.       say \ (3 = 3)               /* displays '0'             */
  2878.  
  2879.  
  2880.       fruit = "oranges"           /* assigns "oranges" to      */
  2881.                                   /* the variable FRUIT       */
  2882.       say fruit = "oranges"       /* displays '1'             */
  2883.       say fruit = "apples"        /* displays '0'             */
  2884.       say \(fruit = "apples")     /* displays '1'             */
  2885.       say \(fruit = "oranges")    /* displays '0'             */
  2886.  
  2887.    To combine comparisons, to get the overall true-or-false value of more than 
  2888.    one condition, use the logical operators AND and OR. 
  2889.  
  2890.  o AND Operator (&)-To write an expression that is only true when every one of 
  2891.    a set of comparisons is true, use the AND (&) operator. For example: 
  2892.  
  2893.       If ready = "YES" & steady = "RIGHT"
  2894.       then say "GO"
  2895.  
  2896.    This means that if ready has a value of YES and steady has a value of RIGHT, 
  2897.    then say GO. Otherwise, do nothing. 
  2898.  
  2899.  o Inclusive OR Operator (|)-The single vertical bar (|) is an inclusive OR. 
  2900.    It combines comparisons so that the whole expression evaluates as 1 (true) 
  2901.    if any of the comparisons are true. 
  2902.  
  2903.    To write an expression that is true when at least one of a set of 
  2904.    comparisons is true, use the inclusive OR (|) operator. For the OS/2 
  2905.    operating system, || can also be used as the concatenation operator and as 
  2906.    the logical OR operator. See Basic Operators for additional information. 
  2907.  
  2908.    For example: 
  2909.  
  2910.       If ready = "YES" | steady = "RIGHT"
  2911.       then say "GO"
  2912.  
  2913.    This means that if either ready has a value of YES or steady has a value of 
  2914.    RIGHT, or both, then say GO.  Otherwise, do nothing. 
  2915.  
  2916.  o Exclusive OR Operator (&&)-The double ampersand (&&) is an exclusive OR.  It 
  2917.    combines comparisons so that the expression evaluates as 1 (true) when one 
  2918.    and only one of the comparisons is true. 
  2919.  
  2920.       city = 'NEW YORK'
  2921.       state = 'NJ'
  2922.       local = 'NO'
  2923.       if city = 'NEW YORK' && state = 'NJ' then
  2924.       local = 'YES'
  2925.       say local                          /* displays 'NO' */
  2926.  
  2927.  
  2928. ΓòÉΓòÉΓòÉ 9.3.8.5. Test Yourself ΓòÉΓòÉΓòÉ
  2929.  
  2930. What is displayed on the screen, when the program shown in Figure 
  2931. "MEASURES.CMD" is run? 
  2932.  
  2933.  
  2934. MEASURES.CMD
  2935.  
  2936. /* Example: comparing numbers */
  2937. dozen = 12
  2938. score = 20
  2939. say score = dozen + 8
  2940.  
  2941. /* Using the AND operator */
  2942. say dozen = 12 & score = 21
  2943.  
  2944. /* Using the OR operator */
  2945. say dozen = 12 | score = 21
  2946.  
  2947.  
  2948. ΓòÉΓòÉΓòÉ 9.3.8.5.1. Answer ΓòÉΓòÉΓòÉ
  2949.  
  2950. The following is displayed on the screen when you run the program. 
  2951.  
  2952. [C:\] measures
  2953. 1
  2954. 0
  2955. 1
  2956. [C:\]
  2957.  
  2958. For the expression using the AND operator: 
  2959.  
  2960.  o The first comparison (dozen = 12) produces the result 1 (true). 
  2961.  
  2962.  o The second comparison (score = 21) produces the result 0 (false). 
  2963.  
  2964.  The result of the AND operation is 0 (false).  The AND operation evaluates as 
  2965.  1 (true) only when both comparisons evaluate as 1. 
  2966.  
  2967.  For the expression using the OR operator: 
  2968.  
  2969.  o The first comparison (dozen = 12) produces the result 1 (true). 
  2970.  
  2971.  o The second comparison (score = 21) produces the result 0 (false). 
  2972.  
  2973.  The result of the OR operation is 1 (true).  The OR operation evaluates as 1 
  2974.  (true) when at least one of the comparisons evaluate as 1. 
  2975.  
  2976.  
  2977. ΓòÉΓòÉΓòÉ 9.3.9. Translating and Converting Data ΓòÉΓòÉΓòÉ
  2978.  
  2979. REXX functions can translate data from one character set to another. 
  2980. Translation is especially useful when a REXX program must process output that 
  2981. is in binary or hexadecimal form. If you are a beginning programmer, you may 
  2982. not need these functions. However, you may want to read this discussion if you 
  2983. want to use REXX with your printer or with other programs. 
  2984.  
  2985. For more information on how REXX works with external data in files and queues, 
  2986. refer to Input and Output. 
  2987.  
  2988. For more information about the following functions, refer to "Functions" in the 
  2989. REXX Reference. 
  2990.  
  2991.  
  2992. ΓòÉΓòÉΓòÉ 9.3.9.1. Number Systems ΓòÉΓòÉΓòÉ
  2993.  
  2994. The OS/2 program uses a standard character set, called the ASCII (American 
  2995. Standard Code for Information Interchange) set, to represent information.  In 
  2996. ASCII, each character has a unique number that may be represented in different 
  2997. ways.  For example, the character ? has the value 63. 
  2998.  
  2999. Computers operate in binary terms such as on and off, yes and no, true and 
  3000. false.  They regard numbers in the same way.  The decimal number 63 in a binary 
  3001. numbering system is 00111111. Each digit stands for a power of two.  In this 
  3002. example the binary number stands for 32+16+8+4+2+1, or 63.  That is how a 
  3003. computer sees a question mark. Every character is rendered as a byte: a set of 
  3004. eight binary digits, each having a value of 0 or 1. Binary numbers are 
  3005. difficult for people to read. 
  3006.  
  3007. Programmers use another numbering system, based on 16 digits, called 
  3008. hexadecimal or hex, for short.  Each digit of a hex number represents four 
  3009. binary digits.  Therefore, a byte can be represented by just two digits.  The 
  3010. 16 possible hex digits are: 
  3011.  
  3012. 0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F (hex)
  3013. 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 (decimal)
  3014.  
  3015. The hexadecimal equivalent of decimal 63 is 3F. That is 3*16 plus 15*1, or 63, 
  3016. which translates to the question-mark (?) character. 
  3017.  
  3018. Note:  For some decimal or hexadecimal numbers, the ASCII character is 
  3019. different, depending on the code page that you are using (see Keyboard 
  3020. Layouts). :enote. 
  3021.  
  3022. In addition to ASCII and decimal numbers, REXX also accepts strings expressed 
  3023. in these forms: 
  3024.  
  3025.  Binary       If a string is to be expressed as one or more binary numbers, 
  3026.               enclose it in matching quotes and put the letter B (uppercase or 
  3027.               lowercase) immediately following the closing quote.  Spaces 
  3028.               within the string are allowed only to separate digits into groups 
  3029.               of four or eight. 
  3030.  
  3031.  Hexadecimal  If a string is expressed in hex, place the letter X (uppercase or 
  3032.               lowercase) immediately following the closing quote.  Spaces 
  3033.               within the string are allowed only to separate the digits into 
  3034.               pairs.  For example: 
  3035.  
  3036.   say 37             /* displays '37' (decimal number)           */
  3037.   say "%"            /* displays '%' (ASCII character 37)        */
  3038.   say '25'x          /* '37' in hex; says '%' (ASCII 37)     */
  3039.   say '0010 0101'b   /* '37' in  binary; says '%' (ASCII 37) */
  3040.  
  3041.  Note:  If you use x or b as variables, REXX gives precedence to their use as 
  3042.  number-base indicators.  For example: 
  3043.  
  3044.   x = 'mno'       /* assign a string to variable X */
  3045.   say '3F'x       /* displays the character '?'    */
  3046.                   /* ... not '3Fmno'               */
  3047.  :enote. 
  3048.  
  3049.  
  3050. ΓòÉΓòÉΓòÉ 9.3.9.2. Using Functions to Convert Data ΓòÉΓòÉΓòÉ
  3051.  
  3052. The following REXX built-in functions convert numbers from one form to another 
  3053. or convert character data to its numeric form. 
  3054.  
  3055.  B2X()     Binary to hexadecimal 
  3056.  C2X()     ASCII to hexadecimal 
  3057.  C2D()     ASCII to decimal 
  3058.  X2B()     Hexadecimal to binary 
  3059.  X2C()     Hexadecimal to ASCII 
  3060.  X2D()     Hexadecimal to decimal 
  3061.  D2C()     Decimal to ASCII 
  3062.  D2X()     Decimal to hexadecimal. 
  3063.  
  3064.  The following function calls represent the conversions they perform. 
  3065.  
  3066.  2 means translate to 
  3067.  B means binary 
  3068.  C means characters (that is, ASCII) 
  3069.  X means hexadecimal. 
  3070.  D means decimal. 
  3071.  
  3072.  Thus the value of: 
  3073.  
  3074.  B2X(0011 1111) is 3F 
  3075.  X2B(3F) is 00111111 
  3076.  C2X(?) is 3F 
  3077.  X2C(3F) is ? 
  3078.  C2D(?) is 63 
  3079.  D2C(63) is ? 
  3080.  D2X(63) is 3F 
  3081.  X2D(3F) is 63. 
  3082.  
  3083.  All these functions accept strings more than 1 byte long. 
  3084.  
  3085.  Note:  For some decimal or hexadecimal numbers, the ASCII character is 
  3086.  different, depending on the code page that you are using (see Keyboard 
  3087.  Layouts). :enote. 
  3088.  
  3089.  Binary numbers can only be translated to and from hexadecimal numbers. To 
  3090.  translate binary into other forms, use nesting.  For example, the value of: 
  3091.  
  3092.  X2C(B2X(0011 1111)) is ? 
  3093.  X2B(D2X(63)) is 00111111. 
  3094.  
  3095.  Figure "Conversion Table" shows a table of conversion functions. 
  3096.  
  3097.  
  3098.   Conversion Table
  3099.  
  3100.   ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3101.   Γöé TO      Γöé    TO BINARY    Γöé     TO ASCII    Γöé      TO HEX     Γöé   TO DECIMAL   Γöé
  3102.   Γöé CHANGE  Γöé                 Γöé                 Γöé                 Γöé                Γöé
  3103.   Γöé n FROM  Γöé                 Γöé                 Γöé                 Γöé                Γöé
  3104.   Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3105.   Γöé BINARY  Γöé                 Γöé   X2C(B2X(n))   Γöé      B2X(n)     Γöé   X2D(B2X(n))  Γöé
  3106.   Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3107.   Γöé ASCII   Γöé   X2B(C2X(n))   Γöé                 Γöé      C2X(n)     Γöé     C2D(n)     Γöé
  3108.   Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3109.   Γöé HEX     Γöé      X2B(n)     Γöé      X2C(n)     Γöé                 Γöé     X2D(n)     Γöé
  3110.   Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  3111.   Γöé DECIMAL Γöé   X2B(D2X(n))   Γöé      D2C(n)     Γöé      D2X(n)     Γöé                Γöé
  3112.   ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3113.  
  3114.  For complete descriptions of these functions, refer to the REXX Reference. 
  3115.  
  3116.  
  3117. ΓòÉΓòÉΓòÉ 10. Commands ΓòÉΓòÉΓòÉ
  3118.  
  3119. Commands are instructions that REXX passes to another environment.  You can use 
  3120. a program written in REXX to control other programs, including the operating 
  3121. system (OS/2 program) for your computer. 
  3122.  
  3123. If you use an application program, such as a word processor, that is controlled 
  3124. by subcommands (the application commands, typed at a user prompt), you can use 
  3125. REXX to create macros, programs that issue a series of subcommands to an 
  3126. application.  You can, in effect, create your own commands. 
  3127.  
  3128. You may now be using the OS/2 Batch Facility to automate the OS/2 tasks. Using 
  3129. a REXX program instead, with its variables, its control structures, and its 
  3130. math and parsing capabilities, can make these procedures much more powerful. 
  3131.  
  3132.  
  3133. ΓòÉΓòÉΓòÉ 10.1. Basics ΓòÉΓòÉΓòÉ
  3134.  
  3135.      In this chapter: Basics 
  3136.  
  3137.      o Environment 
  3138.      o From REXX to the OS/2 Program 
  3139.      o From the OS/2 Program to REXX 
  3140.      o Trying out REXX Instructions. 
  3141.  
  3142.  
  3143. ΓòÉΓòÉΓòÉ 10.1.1. Environment ΓòÉΓòÉΓòÉ
  3144.  
  3145. Environment is a term used to describe the workspace that the OS/2 program and 
  3146. certain applications create for themselves.  You may already be familiar with 
  3147. the idea of an environment with respect to the OS/2 command set, which defines 
  3148. (or displays) various settings such as default paths and files. 
  3149.  
  3150. Using REXX, the term environment refers not so much to individual features of 
  3151. the OS/2 program or other applications, but rather to the way they operate 
  3152. generally.  REXX does not impose an environment of its own.  Instead, it 
  3153. operates entirely within the environment (default environment) from which it is 
  3154. called.  This could be the environment of the OS/2 program or of any 
  3155. application program that can use REXX as a macro or scripting language. 
  3156.  
  3157. The basic rule is that whatever REXX cannot process, it evaluates and then 
  3158. passes the result to the default environment. 
  3159.  
  3160. The concept of environment becomes important when you use a REXX program to 
  3161. issue commands to other programs.  Fortunately, the REXX language makes this 
  3162. easy.  Starting your REXX programs from the OS/2 command line makes the OS/2 
  3163. program the default environment for REXX commands. 
  3164.  
  3165.  
  3166. ΓòÉΓòÉΓòÉ 10.1.2. From REXX to the OS/2 Program ΓòÉΓòÉΓòÉ
  3167.  
  3168. There are three ways to issue a command to the OS/2 program.  You can: 
  3169.  
  3170.  o Let REXX evaluate part or all of a clause as an expression.  The resulting 
  3171.    string is automatically passed to the OS/2 program. 
  3172.  
  3173.  o Enclose the entire clause in quotes.  That renders it a literal string to be 
  3174.    passed to the OS/2 program. 
  3175.  
  3176.  o Send a command explicitly to the OS/2 program by using the ADDRESS 
  3177.    instruction. 
  3178.  
  3179.  
  3180. ΓòÉΓòÉΓòÉ 10.1.2.1. Issuing a Command Expression ΓòÉΓòÉΓòÉ
  3181.  
  3182. REXX processes your program one clause at a time.  It examines each clause to 
  3183. determine if it is: 
  3184.  
  3185.  o A keyword instruction, such as: 
  3186.  
  3187.       say "Type total number"
  3188.    or 
  3189.  
  3190.       pull input
  3191.  
  3192.  o A variable assignment (any valid symbol followed by an equal sign), such as: 
  3193.  
  3194.       price = cost * 1.2
  3195.  
  3196.  o A label for calling other routines (see Subroutines) 
  3197.  
  3198.  o A null (empty) clause. 
  3199.  
  3200.  If the clause is none of the above, REXX evaluates the entire clause as an 
  3201.  expression and passes the resulting string to the OS/2 program. 
  3202.  
  3203.  If the string is a valid OS/2 command, then the OS/2 program processes it as 
  3204.  though you had typed the string at the command prompt and pressed the Enter 
  3205.  key. 
  3206.  
  3207.  Figure "DIRREX.CMD" shows a REXX clause that uses the DIR command in the OS/2 
  3208.  program to display a list of files in the current directory. 
  3209.  
  3210.  
  3211.   DIRREX.CMD
  3212.  
  3213.   /* display current directory */
  3214.   say "DIR command via REXX"
  3215.   dir
  3216.  
  3217.  The clause dir is not a REXX instruction or a label, so REXX evaluates it and 
  3218.  passes the resulting string to the OS/2 program.  The OS/2 program recognizes 
  3219.  the string DIR as one of its commands and processes it.  This is also true if 
  3220.  the PATH command is used to display the current search path for processible 
  3221.  files (see Figure "PATHREX.CMD"). 
  3222.  
  3223.  
  3224.   PATHREX.CMD
  3225.  
  3226.   /* display current path      */
  3227.   say "PATH command via REXX"
  3228.   path
  3229.  
  3230.  REXX evaluates the clause path and passes the string PATH to the OS/2 program 
  3231.  as a command. 
  3232.  
  3233.  Figure "DP.CMD" shows a program using the DIR and PATH commands. The PAUSE 
  3234.  command is added to wait for the user to press a key before issuing the next 
  3235.  instruction or command.  Also, borders were added. 
  3236.  
  3237.  
  3238.   DP.CMD
  3239.  
  3240.   /*    Issue DIR and PATH commands to OS/2      */
  3241.  
  3242.   say copies('=',40)    /* display line of "="'s */
  3243.                         /* for a border          */
  3244.  
  3245.   dir                   /* display listing of    */
  3246.                         /* the current directory */
  3247.  
  3248.   pause                 /* pauses processing and */
  3249.                         /* tells user to "Press  */
  3250.                         /* any key to continue." */
  3251.  
  3252.   say copies('=',40)    /* display line of '='   */
  3253.   path                  /* display the current   */
  3254.                         /* PATH setting          */
  3255.  
  3256.  The following is displayed on the screen when you run the program. 
  3257.  
  3258.   [C:\]dp
  3259.   ========================================
  3260.  
  3261.    The volume label in drive C is OS2.
  3262.    Directory of C:\EXAMPLES
  3263.  
  3264.   .            <DIR>     10-16-88  12:43p
  3265.   ..           <DIR>     10-16-88  12:43p
  3266.   EX4_1    CMD     nnnn  10-16-88   1:08p
  3267.   DEMO     TXT      117  10-16-88   1:10p
  3268.        4 File(s)   12163072 bytes free
  3269.   Press any key when ready . . .
  3270.  
  3271.   ========================================
  3272.   PATH=C:\OS2;C:\OS2\UTIL;C:\OS2\INSTALL
  3273.   [C:\]
  3274.  
  3275.  
  3276. ΓòÉΓòÉΓòÉ 10.1.2.2. Echoing of OS/2 Commands: ΓòÉΓòÉΓòÉ
  3277.  
  3278. When your REXX program issues an OS/2 command, REXX passes the command to the 
  3279. OS/2 command handler for processing.  This processing includes displaying the 
  3280. command on the screen (echoing).  Commands are also echoed in old-style 
  3281. (non-REXX) .CMD files. 
  3282.  
  3283. This echo can be distracting.  To suppress it, issue the ECHO OFF command from 
  3284. your REXX program.  This tells the OS/2 program to suppress all echoing for the 
  3285. remainder of your REXX program.  To suppress echoing for one command, put an at 
  3286. sign (@) in front of the command. 
  3287.  
  3288. Note:  For simplification, the examples in this book do not echo commands. 
  3289. :enote. 
  3290.  
  3291.  
  3292. ΓòÉΓòÉΓòÉ 10.1.2.3. Issuing a Command to Call a .CMD File ΓòÉΓòÉΓòÉ
  3293.  
  3294. If you are issuing a command to have the OS/2 program run one of its built-in 
  3295. commands or other programs, you can call it by name as previously shown. 
  3296. However, to have the OS/2 program run another .CMD program from your REXX 
  3297. program, you must call it using a CALL instruction instead of calling it by 
  3298. name.  There are two kinds of calls you can use: 
  3299.  
  3300.  o The REXX CALL instruction 
  3301.  
  3302.  o The OS/2 CALL command. 
  3303.  
  3304.  The REXX CALL instruction calls other REXX programs.  To call a REXX program 
  3305.  named mysub1, you could write the CALL instruction, call mysub1.  REXX 
  3306.  recognizes the CALL instruction, handles the call, and processes mysub1 as a 
  3307.  REXX program. 
  3308.  
  3309.  The REXX CALL instruction does not work to call a non-REXX .CMD file. Instead, 
  3310.  you would use the OS/2 CALL command.  To call a non-REXX .CMD program named 
  3311.  mysub2, you could write the CALL instruction, "call mysub2".  REXX evaluates 
  3312.  the expression and passes it to the OS/2 command handler for processing.  The 
  3313.  command handler recognizes the CALL command and processes mysub2 as a .CMD 
  3314.  program. 
  3315.  
  3316.  The quotation marks around call mysub2 indicate that this is the OS/2 CALL 
  3317.  command instead of a REXX CALL instruction. 
  3318.  
  3319.  
  3320. ΓòÉΓòÉΓòÉ 10.1.2.4. Using Variables ΓòÉΓòÉΓòÉ
  3321.  
  3322. Figure "SHOFIL.CMD" shows a program that builds a command string using a 
  3323. variable for user input.  It prompts the user to type a file name and then 
  3324. builds a variable to hold the TYPE command and the input file name. 
  3325.  
  3326. To have REXX issue the command to the operating system, put the command string 
  3327. on a line by itself.  REXX evaluates the string and tries to issue it as a 
  3328. command, which is passed to the OS/2 program. 
  3329.  
  3330.  
  3331. SHOFIL.CMD
  3332.  
  3333. /* Issue TYPE command with an input file name  */
  3334.  
  3335. /* prompt the user for a file name          */
  3336. say "Type a file name:"
  3337.  
  3338. /* assign the response to variable FILENAME */
  3339. pull filename
  3340.  
  3341. /* build a command string by concatenation  */
  3342. commandstr = "TYPE" filename
  3343.  
  3344. /* If the user typed "demo.txt":            */
  3345. /* Now the variable COMMANDSTR contains     */
  3346. /* the string "TYPE DEMO.TXT" and so...     */
  3347.  
  3348. commandstr           /* ...REXX passes the  */
  3349.                      /* string on to OS/2   */
  3350.  
  3351. The following is displayed on the screen when you run the program. 
  3352.  
  3353. [C:\]shofil
  3354. Type a file name:
  3355. demo.txt
  3356.  
  3357. This is a sample text file. Its sole
  3358. purpose is to demonstrate how OS/2
  3359. commands can be issued from REXX
  3360. programs.
  3361.  
  3362. [C:\]
  3363.  
  3364.  
  3365. ΓòÉΓòÉΓòÉ 10.1.2.5. Using Quotes ΓòÉΓòÉΓòÉ
  3366.  
  3367. The rules for forming a command from an expression are exactly the same as 
  3368. those for forming expressions.  Be careful of symbols that have meanings for 
  3369. both REXX and OS/2 programs. To determine how REXX evaluates a command when the 
  3370. command name and a variable name are the same, use the program DIRREX.CMD (see 
  3371. Figure "DIRREX.CMD") and assign a value to the symbol DIR as shown in Figure 
  3372. "DIRREX2.CMD". 
  3373.  
  3374.  
  3375. DIRREX2.CMD
  3376.  
  3377. /* assign a value to the symbol DIR */
  3378. say "DIR command via REXX"
  3379. dir = "echo This is not a directory!"
  3380.  
  3381. /* pass the evaluated variable to OS/2 */
  3382. dir
  3383.  
  3384. Now dir is a variable with the string, "echo This is not a directory!", as the 
  3385. assigned value. 
  3386.  
  3387. The following is displayed on the screen when you run the program. 
  3388.  
  3389. [C:\]dirrex2
  3390. DIR command via REXX:
  3391. This is not a directory!
  3392. [C:\]
  3393.  
  3394. REXX evaluates a literal string, a string enclosed in matching quotes, exactly 
  3395. as it is found.  To ensure that a symbol in a command is not evaluated as a 
  3396. variable, enclose it in matching quotes as shown in Figure "DIRREX3.CMD". 
  3397.  
  3398.  
  3399. DIRREX3.CMD
  3400.  
  3401. /* assign a value to the symbol DIR */
  3402. say "DIR command via REXX"
  3403. dir = "echo This is another string now!"
  3404.  
  3405. /* pass the literal string "dir" to OS/2 * /
  3406. "dir"
  3407.  
  3408. The result displayed on the screen is now a directory listing. 
  3409.  
  3410. The best way to ensure that REXX passes a string to the OS/2 program as a 
  3411. command is to enclose the entire clause in quotes.  This is especially 
  3412. important when you use OS/2 symbols that REXX uses as operators. 
  3413.  
  3414. If you were trying to erase a set of files by wildcard pattern, the clause, 
  3415. delete *.bak, would result in a syntax error.  REXX would read the * as its 
  3416. multiplication operator, and REXX would try to multiple the value of "delete" 
  3417. by the value of ".bak". Those values are not numbers; therefore, the 
  3418. multiplication would fail. 
  3419.  
  3420. The same thing happens with the character /.  It denotes command options in the 
  3421. OS/2 program, but to REXX, it is the division operator: 
  3422.  
  3423. w  = "anything"
  3424. dir/w
  3425.  
  3426. This would also result in a syntax error, because you can only divide with 
  3427. numbers.  The correct way would be: 
  3428.  
  3429. delete "*.bak"
  3430. dir"/w"
  3431. or 
  3432.  
  3433. "delete *.bak"
  3434. "dir/w"
  3435.  
  3436. If you want to use a variable in the command string (see Figure "SHOFIL.CMD"), 
  3437. leave the variable outside the quotes.  For example: 
  3438.  
  3439. extension = "BAK"
  3440. "delete *."||extension
  3441.  
  3442. option = "/w"
  3443. "dir"||option
  3444.  
  3445.  
  3446. ΓòÉΓòÉΓòÉ 10.1.2.6. To Summarize ΓòÉΓòÉΓòÉ
  3447.  
  3448. The basic points of using commands are: 
  3449.  
  3450.  o REXX always examines each clause for REXX syntax. 
  3451.  
  3452.  o If REXX finds no valid instruction or label and the clause is not empty, 
  3453.    then it evaluates the clause as an expression. 
  3454.  
  3455.  o The result of the expression, a string, is then passed on to the environment 
  3456.    from which REXX was originally called-the default environment. 
  3457.  
  3458.  
  3459. ΓòÉΓòÉΓòÉ 10.1.2.7. ADDRESS Instruction ΓòÉΓòÉΓòÉ
  3460.  
  3461. A more explicit way to send a command to the environment is by using the 
  3462. ADDRESS instruction, ADDRESS environment expression, where: 
  3463.  
  3464.  environment is the destination of the string.  To address the OS/2 program, 
  3465.              use the symbol CMD. 
  3466.  
  3467.  expression  is evaluated by REXX as a string to be passed to the environment. 
  3468.  
  3469.  The ADDRESS instruction works like this: 
  3470.  
  3471.   address CMD "dir"     /* pass the literal string   */
  3472.                         /* "dir" to the OS/2 program */
  3473.  
  3474.   cmdstr = 'dir *.txt'  /* assign a string          */
  3475.                         /* to a variable            */
  3476.  
  3477.   address CMD cmdstr    /* REXX passes the string          */
  3478.                         /* "dir *.txt" to the OS/2 program */
  3479.  
  3480.  When you use the ADDRESS instruction this way, REXX first evaluates the string 
  3481.  expression that follows the CMD.  Then, it sends the resulting string to the 
  3482.  OS/2 program. 
  3483.  
  3484.  The ADDRESS instruction in this example works exactly the same way as in the 
  3485.  methods already described.  If you want to send a literal string to the OS/2 
  3486.  program, you must enclose it in quotes.  Otherwise, REXX evaluates the terms 
  3487.  and operators and passes the resulting string to the OS/2 program. 
  3488.  
  3489.  The ADDRESS instruction lets a single REXX program issue commands to two or 
  3490.  more environments.  This can be used when using REXX as a macro language. 
  3491.  
  3492.  
  3493. ΓòÉΓòÉΓòÉ 10.1.2.8. Test Yourself ΓòÉΓòÉΓòÉ
  3494.  
  3495. Figure "FILFRAG.CMD" shows a program that passes the DIR command and SORT 
  3496. filter to the OS/2 program. 
  3497.  
  3498.  
  3499. FILFRAG.CMD
  3500.  
  3501. /*                  */
  3502. say 'Type fragment'
  3503. pull frag
  3504. if frag = '' then
  3505.    say 'You asked for it!'
  3506. 'DIR' frag ||'*.*  | SORT'
  3507.  
  3508.   1. What does each line of the program do? 
  3509.  
  3510.   2. What happens if the user types who at the prompt message? 
  3511.  
  3512.   3. What happens if the user presses the Enter key without typing anything? 
  3513.  
  3514.   4. What happens if no files fit the pattern? 
  3515.  
  3516.  
  3517. ΓòÉΓòÉΓòÉ 10.1.2.8.1. Answers: ΓòÉΓòÉΓòÉ
  3518.  
  3519.   1. Here is what the program does: 
  3520.  
  3521.     o The first line is a comment. 
  3522.  
  3523.     o The second line displays the prompt message, Type fragment:, on the 
  3524.       screen. 
  3525.  
  3526.     o The third line reads the user's entry and stores it in the variable frag. 
  3527.  
  3528.     o The fourth line tests if frag is empty, as in HELLO.CMD, see Figure 
  3529.       "HELLO.CMD". 
  3530.  
  3531.     o If frag is empty, then the fifth line displays the message, You asked for 
  3532.       it!, on the screen. 
  3533.  
  3534.     o The sixth line is evaluated as a string expression and concatenates the 
  3535.       contents of frag into a DIR command with a wildcard file-pattern. The 
  3536.       directory is sorted and displayed on screen. 
  3537.  
  3538.   2. The OS/2 program displays a directory for the command 
  3539.  
  3540.           DIR WHO*.* | SORT
  3541.  
  3542.   3. The program displays the message You asked for it! and then a listing of 
  3543.      all files in the current directory, as if the command DIR *.* | SORT had 
  3544.      been typed. 
  3545.  
  3546.   4. The OS/2 program displays the message, The system cannot find the file 
  3547.      specified., on the screen. 
  3548.  
  3549.  The following is displayed on screen when you run the program. 
  3550.  
  3551.   [C:\]filfrag
  3552.   Type fragment
  3553.   who
  3554.   <sorted directory display>
  3555.   [C:\]
  3556.  
  3557.  The following is displayed on the screen if you make no entry and press the 
  3558.  Enter key. 
  3559.  
  3560.   [C:\]filfrag
  3561.   Type fragment
  3562.  
  3563.   You asked for it!
  3564.   < full directory listing >
  3565.   [C:\]
  3566.  
  3567.  The following is displayed on the screen if no files in the current directory 
  3568.  match the given pattern. 
  3569.  
  3570.   [C:\]filfrag
  3571.   Type fragment
  3572.   who
  3573.  
  3574.   SYS0002 The system cannot find the file specified.
  3575.  
  3576.  
  3577. ΓòÉΓòÉΓòÉ 10.1.3. From the OS/2 Program to REXX ΓòÉΓòÉΓòÉ
  3578.  
  3579. Information between REXX and OS/2 programs is passed both ways; this is an 
  3580. essential part of using REXX with other environments.  If a command fails to 
  3581. operate the way you intended, such as if you try to copy a file that does not 
  3582. exist, you get a message that tells you that file cannot be found and you can 
  3583. respond accordingly. 
  3584.  
  3585. The same thing happens when a REXX program tries to copy a nonexistent file, 
  3586. except that for REXX to respond, it must be apparent that a system error has 
  3587. occurred.  Otherwise, the program continues running, unaware that neither the 
  3588. source file nor the copy of it exists. 
  3589.  
  3590. A system error alone does not stop the running of a REXX program.  Without some 
  3591. provision to stop the program, called a trap, REXX continues running.  You may 
  3592. have to press the Control (Ctrl)+Break keys to stop processing. 
  3593.  
  3594. With each command it processes, the OS/2 program produces a number called a 
  3595. return code. When a REXX program is running, this return code is automatically 
  3596. assigned to a special built-in REXX variable named RC. 
  3597.  
  3598. If the command was processed with no problems, the return code is nearly always 
  3599. 0.  If something goes wrong, the return code issued is another nonzero number, 
  3600. depending on the command itself and the error encountered. 
  3601.  
  3602. In the previous example, the file not found error occurred at the end of the 
  3603. program, so there was no great problem.  But a system error that occurs in the 
  3604. middle of a program can indeed cause trouble. 
  3605.  
  3606.  
  3607. ΓòÉΓòÉΓòÉ 10.1.3.1. Reading Return Codes ΓòÉΓòÉΓòÉ
  3608.  
  3609. Figure "GETRC.CMD" shows a program that can read a return code. 
  3610.  
  3611.  
  3612. GETRC.CMD
  3613.  
  3614. /* RC report */
  3615. "TYPE nosuch.fil"
  3616. say "the return code is" RC
  3617.  
  3618. Figure "REPORTRC.CMD" shows a program that displays a response to the return 
  3619. code. 
  3620.  
  3621.  
  3622. REPORTRC.CMD
  3623.  
  3624. /* Simple if/then error-handler. */
  3625. say "Type a file name:"
  3626. pull filename
  3627. "TYPE" filename
  3628. if RC \= 0
  3629. then say "Could not find" filename
  3630.  
  3631. This program tells you only that the OS/2 program could not copy a nonexistent 
  3632. file.  This program does not do much more than the OS/2 program does, but you 
  3633. have the basic idea of how to capture a return code. 
  3634.  
  3635. Programs need to respond more effectively to whatever situation occurs. This 
  3636. applies not only to OS/2 errors, but also to the choices of a program user and 
  3637. even the data that the program processes.  For that kind of response, REXX has 
  3638. instructions, such as IF, that control the processing of the program itself, 
  3639. sometimes called its flow.  For more information about program flow, refer to 
  3640. Program Control. 
  3641.  
  3642.  
  3643. ΓòÉΓòÉΓòÉ 10.1.3.2. More and Better Traps ΓòÉΓòÉΓòÉ
  3644.  
  3645. When you have completed "Basics" in this guide, you may want to explore other 
  3646. methods of controlling system errors, particularly the instructions: 
  3647.  
  3648.  o CALL ON ERROR 
  3649.  o CALL ON FAILURE 
  3650.  o SIGNAL ON ERROR 
  3651.  o SIGNAL ON FAILURE. 
  3652.  
  3653.  These instructions are discussed in "Advanced Topics" in this chapter (see 
  3654.  Trapping Command Errors) and "Instructions" in the REXX Reference. 
  3655.  
  3656.  
  3657. ΓòÉΓòÉΓòÉ 10.1.4. The REXXTRY Program ΓòÉΓòÉΓòÉ
  3658.  
  3659.  REXXTRY is a REXX command that lets you run different REXX instructions and 
  3660. observe the results. REXXTRY is also useful when you want to do a REXX 
  3661. operation only once, since it is easier than creating, running, and erasing a 
  3662. .CMD file. REXXTRY can be used as a learning tool. It allows you to experiment 
  3663. with different REXX instructions and observe the results. As with other REXX 
  3664. programs, REXXTRY may be run in full screen or in a window. 
  3665.  
  3666. Beginning and ending a REXXTRY session is easy.  To start a REXXTRY session, 
  3667. type the following: c. 
  3668.  
  3669.  REXXTRY 
  3670.  To end a REXXTRY session, type: c. 
  3671.  
  3672.  EXIT or RETURN 
  3673.  
  3674.   Here are some examples of how to use the REXXTRY command: 
  3675.  
  3676.  
  3677.   REXXTRY Example
  3678.  
  3679.   REXXTRY say 1+2                                  /* Displays 3        */
  3680.  
  3681.   REXXTRY say 2+3; say 3+4                         /* Displays 3        */
  3682.                                                    /* Displays 4        */
  3683.  
  3684.   REXXTRY sum = 1+2+3+4; say 'average is' sum/4    /* Displays 2.5      */
  3685.  
  3686.  Note that when you run REXXTRY from a command line and provide some REXX 
  3687.  instructions on that command line, the OS/2 command interpreter processes the 
  3688.  command line in its usual way.  That means it may treat part of your input in 
  3689.  a way you do not expect. For instance, if you type: c. 
  3690.  
  3691.   REXXTRY Say AB>CD 
  3692.  the REXXTRY program is not run with the argument "Say AB>CD." Instead, it is 
  3693.  run with the argument "Say AB," and the output of the program will be 
  3694.  redirected to the file CD. This is because the OS/2 command interpreter 
  3695.  recognizes the > character as a redirection operator. 
  3696.  
  3697.  However, when you start REXXTRY without a parameter and then enter an 
  3698.  instruction, for example, Say AB>CD, REXX processes the instruction directly. 
  3699.  REXXTRY performs the comparison between AB and CD and writes the result, "0." 
  3700.  
  3701.  Figure "REXXTRY Interactive Example" shows how to run REXXTRY interactively. 
  3702.  
  3703.  
  3704.   REXXTRY Interactive Example
  3705.  
  3706.   C:\]rexxtry
  3707.     REXXTRY.CMD lets you interactively try REXX statements.
  3708.     Each string is executed when you hit Enter.
  3709.     Enter 'call tell' for a description of the features.
  3710.     Go on - try a few...             Enter 'exit' to end.
  3711.  
  3712.   say AB > CD
  3713.  
  3714.   0
  3715.     ................................................ REXXTRY.CMD on OS/2
  3716.  
  3717.   sum = 1 + 2 + 3 + 4
  3718.  
  3719.     ................................................ REXXTRY.CMD on OS/2
  3720.  
  3721.   say 'average is' sum / 4
  3722.  
  3723.   average is 2.5
  3724.     ................................................ REXXTRY.CMD on OS/2
  3725.  
  3726.   exit
  3727.  
  3728.  
  3729.   C:\]
  3730.  
  3731.  
  3732. ΓòÉΓòÉΓòÉ 10.1.5. Summary ΓòÉΓòÉΓòÉ
  3733.  
  3734. This completes "Basics" in this chapter.  You have learned how to: 
  3735.  
  3736.  o Pass commands from REXX programs to the OS/2 program: 
  3737.  
  3738.     - Using expressions 
  3739.     - Using the ADDRESS instruction. 
  3740.  
  3741.  o Read the RC variable that the OS/2 program returns to REXX 
  3742.  o Run REXX instructions by using the REXXTRY command. 
  3743.  
  3744.  "Advanced Topics" in this chapter discusses: 
  3745.  
  3746.  o Using REXX as a substitute for batch files 
  3747.  o Using REXX as a macro language 
  3748.  o Using SIGNAL and CALL to trap errors and failures 
  3749.  o Using PMREXX to run programs. 
  3750.  
  3751.  To continue with "Basics," go to page 6-1. 
  3752.  
  3753.  
  3754. ΓòÉΓòÉΓòÉ 10.2. Advanced Topics ΓòÉΓòÉΓòÉ
  3755.  
  3756.      In this chapter: Advanced Topics 
  3757.  
  3758.      o REXX and Batch Files 
  3759.      o Subcommand processing 
  3760.      o Trapping command errors 
  3761.      o Running REXX programs in a window. 
  3762.  
  3763.  
  3764. ΓòÉΓòÉΓòÉ 10.2.1. REXX and Batch Files ΓòÉΓòÉΓòÉ
  3765.  
  3766. You can use a REXX program anywhere you now use OS/2 batch files. Figure 
  3767. "HELP.CMD (OS/2-batch version)" shows an example of an OS/2 batch file that 
  3768. processes user input to display a help message. 
  3769.  
  3770.  
  3771. HELP.CMD (OS/2-batch version)
  3772.  
  3773. @echo off
  3774. if %1.==. goto msg
  3775. if %1 == on goto yes
  3776. if %1 == off goto no
  3777. if %1 == ON goto yes
  3778. if %1 == OFF goto no
  3779. if %1 == On goto yes
  3780. if %1 == oN goto yes
  3781. if %1 == OFf goto no
  3782. if %1 == OfF goto no
  3783. if %1 == Off goto no
  3784. if %1 == oFF goto no
  3785. if %1 == oFf goto no
  3786. if %1 == ofF goto no
  3787. helpmsg %1
  3788. goto exit
  3789. :msg
  3790. helpmsg
  3791. goto exit
  3792. :yes
  3793. prompt $i[$p]
  3794. goto exit
  3795. :no
  3796. cls
  3797. prompt
  3798. :exit
  3799.  
  3800. Figure "HELP.CMD (REXX version)" shows an example of an equivalent program in 
  3801. REXX. 
  3802.  
  3803.  
  3804. HELP.CMD (REXX version)
  3805.  
  3806. /* HELP.CMD - Get help for a system message */
  3807. arg action .
  3808. select
  3809.   when action=''    then     'helpmsg'
  3810.   when action='ON'  then     'prompt $i[$p]'
  3811.   when action='OFF' then do
  3812.                            'cls'
  3813.                            'prompt'
  3814.                            end
  3815.   otherwise 'helpmsg' action
  3816.   end
  3817. exit
  3818.  
  3819.  
  3820. ΓòÉΓòÉΓòÉ 10.2.2. Subcommand Processing ΓòÉΓòÉΓòÉ
  3821.  
  3822. REXX programs can issue commands or subcommands to programs other than the OS/2 
  3823. program.  The specifics about other application environments are beyond the 
  3824. scope of this book.  However: 
  3825.  
  3826.  o If your application permits access to the OS/2 system prompt, you can call 
  3827.    REXX programs that way. 
  3828.  
  3829.  o To use REXX as a macro or scripting language in applications such as word 
  3830.    processors, the application must be registered with the language processor. 
  3831.    This is done by the producer of the program. 
  3832.  
  3833.  o If you have programs of your own that you want to register with the language 
  3834.    processor, refer to "Applications Programming Interfaces" in the REXX 
  3835.    Reference. 
  3836.  
  3837.  
  3838. ΓòÉΓòÉΓòÉ 10.2.3. Trapping Command Errors ΓòÉΓòÉΓòÉ
  3839.  
  3840. The most efficient way to detect errors from commands is by creating condition 
  3841. traps, using the SIGNAL ON and CALL ON instructions, with either the ERROR or 
  3842. the FAILURE condition.  When used in a program, these instructions enable 
  3843. (switch on) a detector in REXX that tests the result of every command.  Then, 
  3844. if a command signals an error, REXX stops normal program processing, searches 
  3845. the program for the appropriate label (ERROR: or FAILURE:) or a label that you 
  3846. created, and resumes processing there. 
  3847.  
  3848. The SIGNAL ON and CALL ON instructions also tell REXX to store the line number 
  3849. (in the REXX program) of the command instruction that triggered the condition. 
  3850. That line number is assigned to the special variable SIGL. Your program can get 
  3851. even more information about what caused the command error through the built-in 
  3852. function CONDITION(). 
  3853.  
  3854. Using the SIGNAL and CALL instructions to handle errors has several advantages. 
  3855. Programs: 
  3856.  
  3857.  o Are easier to read, because you can confine error-trapping to a single, 
  3858.    common routine 
  3859.  
  3860.  o Are more flexible, because they can respond to errors by clause (SIGL), by 
  3861.    return code (RC), or by other information (CONDITION()) 
  3862.  
  3863.  o Can catch problems and react to them before the environment issues an error 
  3864.    message 
  3865.  
  3866.  o Are easier to correct, because you can turn the traps on and off (SIGNAL OFF 
  3867.    and CALL OFF). 
  3868.  
  3869.  For other conditions that may be detected using SIGNAL ON and CALL ON, see 
  3870.  Condition Traps. 
  3871.  
  3872.  
  3873. ΓòÉΓòÉΓòÉ 10.2.3.1. Instructions and Conditions ΓòÉΓòÉΓòÉ
  3874.  
  3875. The instructions to set a trap for errors are: 
  3876.  
  3877. SIGNAL ON condition [NAME trapname]
  3878. CALL   ON condition [NAME trapname]
  3879.  
  3880.  SIGNAL ON      Initiates an exit subroutine that ends the program 
  3881.  
  3882.  CALL ON        Initiates a return subroutine that returns processing to the 
  3883.                 clause immediately following the CALL ON instruction. Use this 
  3884.                 instruction to recover from a command error or failure. 
  3885.  
  3886.  The two command conditions that can be trapped are: 
  3887.  
  3888.  ERROR          Detects any nonzero error code issued by the default 
  3889.                 environment as the result of a REXX command 
  3890.  
  3891.  FAILURE        Detects a severe error preventing the system from processing 
  3892.                 the command. 
  3893.  
  3894.  A failure, in this sense, is a particular category of error.  If you use 
  3895.  SIGNAL ON or CALL ON to set a trap only for ERROR conditions, then it traps 
  3896.  failures as well as other errors.  If you also specify a FAILURE condition, 
  3897.  then the ERROR trap ignores failures. 
  3898.  
  3899.  As an option, you can also use the NAME keyword to specify a particular 
  3900.  subroutine, trapname, to be run. When an ERROR or FAILURE condition occurs 
  3901.  and: 
  3902.  
  3903.  o If a trap is specified by name, REXX jumps to the clause following the 
  3904.    appropriate label (the trapname followed by colon). 
  3905.  
  3906.  o If you do not specify a trapname in the SIGNAL ON or CALL ON instruction, 
  3907.    REXX searches for a label matching the appropriate condition.  It looks for 
  3908.    the label ERROR: or FAILURE:). 
  3909.  
  3910.  For more information about other conditions that can be trapped, see Condition 
  3911.  Traps.  For more information about how labels are used to call subroutines, 
  3912.  refer to Program Structure. 
  3913.  
  3914.  
  3915. ΓòÉΓòÉΓòÉ 10.2.3.2. Disabling Traps ΓòÉΓòÉΓòÉ
  3916.  
  3917. To turn off a trap for any part of a program, use the same instruction with the 
  3918. OFF keyword, such as: 
  3919.  
  3920. SIGNAL OFF ERROR
  3921. SIGNAL OFF FAILURE
  3922. CALL OFF ERROR
  3923. CALL OFF FAILURE
  3924.  
  3925.  
  3926. ΓòÉΓòÉΓòÉ 10.2.3.3. Using SIGNAL ON ERROR ΓòÉΓòÉΓòÉ
  3927.  
  3928. Figure "SIGNAL ON Trap" shows an example of how a program might use SIGNAL ON 
  3929. to trap a command error in a program that copies a file.  In this example, an 
  3930. error occurs because a nonexistent file name is stored in the variable FILE1. 
  3931. Processing jumps to the clause following the label error:. 
  3932.  
  3933.  
  3934. SIGNAL ON Trap
  3935.  
  3936.            /* example of error trap */
  3937.            signal on error                 /* Set the trap */
  3938.                 .
  3939.                 .
  3940.                 .
  3941.       ΓöÇΓöÇΓöÇ"COPY"  file1 file2             /* When an error occurs... */
  3942.       Γöé         .
  3943.       Γöé         .
  3944.       Γöé    exit .
  3945.       ΓöÇΓöÇΓöÇerror:                           /* ...REXX jumps to here  */
  3946.            say "Error" rc "at line" sigl
  3947.            say "Program can not continue."
  3948.            exit                             /* and ends the program.  */
  3949.  
  3950.  
  3951. ΓòÉΓòÉΓòÉ 10.2.3.4. Using CALL ON ERROR ΓòÉΓòÉΓòÉ
  3952.  
  3953. If there were a way to recover, such as by typing another file name, you could 
  3954. use CALL ON as shown in Figure "CALL ON Trap" to recover and resume processing. 
  3955.  
  3956.  
  3957. CALL ON Trap
  3958.  
  3959.            /* example of error recovery */
  3960.            call on error
  3961.                 .
  3962.                 .
  3963.                 .
  3964.      ΓöîΓöÇΓöÇΓöÇΓöÇ "COPY"  file1 file2
  3965.      Γöé     say "Using" file2 ΓöéΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  3966.      Γöé          .                              Γöé
  3967.      Γöé          .                              Γöé
  3968.      Γöé           exit                          Γöé
  3969.      ΓööΓöÇΓöÇΓöÇ error:                              Γöé
  3970.            say "Can not find" file1            Γöé
  3971.            say "Type Y to continue anyway."    Γöé
  3972.            pull ans                            Γöé
  3973.            if ans = "Y" then                   Γöé
  3974.               do                               Γöé
  3975.                  /* create dummy file */       Γöé
  3976.                       .                        Γöé
  3977.                       .                        Γöé
  3978.                       .                        Γöé
  3979.                  file2 = "dummy.fil"           Γöé
  3980.                  RETURN ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  3981.                  end
  3982.            else exit
  3983.  
  3984.  
  3985. ΓòÉΓòÉΓòÉ 10.2.3.5. A Common Error-handling Routine ΓòÉΓòÉΓòÉ
  3986.  
  3987. Figure "SIGERR.CMD" shows an example of a simple error trap that can be used in 
  3988. many programs. 
  3989.  
  3990.  
  3991. SIGERR.CMD
  3992.  
  3993. /* Here is a sample "main program"           */
  3994. signal on error        /* enable error handling             */
  3995. 'ersae myfiles.*'      /* mis-typed 'erase' instruction     */
  3996. exit
  3997.  
  3998. /* And here is a fairly generic error-handler for this */
  3999. /* program (and many others...)                        */
  4000. error:
  4001.   say 'error' rc 'in system call.'
  4002.   say
  4003.   say 'line number =' sigl
  4004.   say 'instruction = '  || sourceline(sigl)
  4005.   exit
  4006.  
  4007.  
  4008. ΓòÉΓòÉΓòÉ 10.2.4. Using PMREXX ΓòÉΓòÉΓòÉ
  4009.  
  4010. Earlier you learned to run REXX programs from the OS/2 command line. You can 
  4011. also run REXX programs with the PMREXX command. The PMREXX command runs a REXX 
  4012. program in a Presentation Manager window. The Presentation Manager window gives 
  4013. you: 
  4014.  
  4015.  o A window for REXX output from: 
  4016.  
  4017.     - The SAY instruction 
  4018.     - Output and error messages from OS/2 commands 
  4019.     - REXX TRACE output. 
  4020.  
  4021.  o An input window for: 
  4022.  
  4023.     - The PULL and PARSE PULL instructions 
  4024.     - Input to OS/2 programs and commands 
  4025.  
  4026.  o REXX output browsing, scrolling, and clipboard capability 
  4027.  o A selection of fonts for the output window 
  4028.  o Menu options to trace or end a REXX program. 
  4029.  
  4030.  
  4031. ΓòÉΓòÉΓòÉ 10.2.4.1. Starting the PMREXX Program ΓòÉΓòÉΓòÉ
  4032.  
  4033. Using PMREXX to run a REXX program is easy.  Just add the command "PMREXX" to 
  4034. the front of your command line: 
  4035.  
  4036.     PMREXX rexxtry say "Hello Stranger!"
  4037.  
  4038. PMREXX displays "Hello Stranger!" in a Presentation Manager window, then 
  4039. displays a Presentation Manager message box to inform you that the REXX program 
  4040. has ended. 
  4041.  
  4042. Figure Figure "FILES.CMD" shows a simple REXX program for displaying OS/2 
  4043. files. 
  4044.  
  4045.  
  4046. FILES.CMD
  4047.  
  4048. /**/
  4049. '@echo off'
  4050. Do Forever
  4051.   Say 'Please enter a file or directory name'
  4052.   Parse Pull filename
  4053.   If filename = ''
  4054.     Then Leave
  4055.   'dir' filename
  4056. End
  4057.  
  4058. Run the program FILES.CMD and type the following response when the program 
  4059. pauses: 
  4060.  
  4061.     C:\OS2
  4062.  
  4063. There are very many files in the C:\OS2 directory, more lines that will fit in 
  4064. an OS/2 command window.  The first files in the list will scroll off the top of 
  4065. the screen before FILES.CMD pauses again. Press enter one more to end the 
  4066. program, then type in the command: 
  4067.  
  4068.     pmrexx files
  4069.  
  4070. PMREXX will display the prompt from FILES.CMD in the PMREXX window and pause 
  4071. until you type in a file name. You must type the file name in the input box at 
  4072. the top of the PMREXX window. Again, type the response 
  4073.  
  4074.     C:\OS2
  4075.  
  4076. When the FILES.CMD pauses again, you can use the PMREXX window scroll bars to 
  4077. see the first lines the DIR command displayed. You can move or size the 
  4078. PMREXX.EXE window or select PMREXX menu-bar choices: 
  4079.  
  4080.  Menu-Bar Choice          Description 
  4081.  
  4082.  File                     Save the PMREXX output or exit PMREXX 
  4083.  
  4084.  Edit                     Copy to the clipboard, paste the clipboard to the 
  4085.                           input box, clear the PMREXX output window, and select 
  4086.                           all lines in the PMREXX output window. 
  4087.  
  4088.  Options                  Restart the REXX program, turn on REXX interactive 
  4089.                           Trace, and change the PMREXX output window font. 
  4090.  
  4091.  Actions                  Halt the REXX program, trace next REXX instruction, 
  4092.                           redo the last REXX instruction, and turn off REXX 
  4093.                           tracing. 
  4094.  
  4095.  Help                     PMREXX help. 
  4096.  
  4097.  
  4098. ΓòÉΓòÉΓòÉ 10.2.4.2. The RxMessageBox Function ΓòÉΓòÉΓòÉ
  4099.  
  4100. When you run your REXX programs with PMREXX, you can also use the RxMessageBox 
  4101. function to display messages. For example, you can use RxMessageBox to display 
  4102. an error message: 
  4103.  
  4104.  
  4105. ERROR.CMD
  4106.  
  4107. /* Check the input parameter */
  4108. arg count
  4109. if datatype(count, 'Whole') <> 0 then do
  4110.   RxMessageBox("Argument" count "is not a whole number")
  4111.   exit
  4112. end
  4113.  
  4114. RxMessageBox displays a Presentation Manager message box with a title of 
  4115. "Error!" and an "OK" button. The REXX program will wait until you press the 
  4116. "OK" button. 
  4117.  
  4118. You can change message box title and buttons. You can also add a colorful icon 
  4119. to the message box: 
  4120.  
  4121.  
  4122. FILECHK.CMD
  4123.  
  4124. /* Does the file exist? */
  4125. if stream(file, 'Command', "Query Exists") <> ''
  4126.   then do
  4127.     reply = RxMessageBox("Do you want to replace file" file"",,
  4128.         "Replace File?", "YesNo", "Question")
  4129.     if reply = 7 then exit         /* user pressed 'No' */
  4130.   end
  4131.  
  4132. FILECHK.CMD displays a question in a message box with a question mark icon and 
  4133. two buttons;  one labeled "Yes", the other labeled "No". When you press the Yes 
  4134. or No button, gives your program the number of the button you chose. The Yes 
  4135. button is number 6 and the No button is number 7. 
  4136.  
  4137.  
  4138. ΓòÉΓòÉΓòÉ 10.2.4.3. The PMREXX Trace Option ΓòÉΓòÉΓòÉ
  4139.  
  4140. The PMREXX /T option turns on interactive tracing for the REXX program. You 
  4141. must place the /T option before the name of the REXX program name: 
  4142.  
  4143.     PMREXX /T files
  4144.  
  4145. You can use the PMREXX menu to control how REXX traces the program. 
  4146.  
  4147. With PMREXX you can also turn tracing on while a program is running. Select 
  4148. Interactive trace from the Options menu to do this. 
  4149.  
  4150.  
  4151. ΓòÉΓòÉΓòÉ 11. Program Control ΓòÉΓòÉΓòÉ
  4152.  
  4153. So far, the sample programs have been fairly straightforward lists of clauses. 
  4154. Various instructions have been used to input, store, display, and manipulate 
  4155. information. 
  4156.  
  4157. In this chapter, another class of instructions, keywords that manipulate the 
  4158. program itself, are discussed.  One of these, IF... THEN... ELSE, was already 
  4159. used to choose between two possible directions a program might take. 
  4160.  
  4161.  
  4162. ΓòÉΓòÉΓòÉ 11.1. Basics ΓòÉΓòÉΓòÉ
  4163.  
  4164.      In this chapter: Basics 
  4165.  
  4166.      o Changing the flow of a program 
  4167.      o Repetitive tasks 
  4168.      o Conditional loops 
  4169.      o Using counters to exit loops 
  4170.      o Exiting a program. 
  4171.  
  4172.  
  4173. ΓòÉΓòÉΓòÉ 11.1.1. Changing the Flow of a Program ΓòÉΓòÉΓòÉ
  4174.  
  4175. A program can be: 
  4176.  
  4177.  o A single list of instructions 
  4178.  
  4179.  o A number of short lists connected by instructions that determine which list 
  4180.    to process and how many times to process it. 
  4181.  
  4182.  Instructions that direct the processing of the program are called control 
  4183.  instructions.  The maneuvers they perform include: 
  4184.  
  4185.  Branching      Selecting one of several lists of instructions to process.  The 
  4186.                 branching instructions are IF and SELECT. 
  4187.  
  4188.  Looping        Repeating a list of instructions, either for a specified number 
  4189.                 of times or as long as some condition is satisfied.  The DO 
  4190.                 instruction (when used with keywords like UNTIL and WHILE) does 
  4191.                 the looping in REXX. 
  4192.  
  4193.  Exiting        A program that is a single list ends when it reaches the last 
  4194.                 instruction. To explicitly end a program, use the instructions 
  4195.                 EXIT and RETURN. 
  4196.  
  4197.  
  4198. ΓòÉΓòÉΓòÉ 11.1.1.1. Grouping Instructions ΓòÉΓòÉΓòÉ
  4199.  
  4200. What most control instructions have in common is that they often use groups of 
  4201. clauses that act as a single clause.  The simplest way to group clauses is with 
  4202. the keyword DO.  For example: 
  4203.  
  4204. DO
  4205.    clause1
  4206.    clause2
  4207.    clause3
  4208.    ...
  4209. END
  4210.  
  4211. If the keyword DO is in a clause by itself, the list of clauses that follows 
  4212. (up to the END keyword) is processed once (no loop is implied).  This form of 
  4213. the DO instruction and the END keyword associated with it tell REXX to treat 
  4214. the enclosed instructions as a single instruction. 
  4215.  
  4216. The enclosed instructions may be indented to the right.  The indentation does 
  4217. not affect how REXX processes the list.  It does, however, make the program 
  4218. easier for people to read.  It shows that these instructions belong together. 
  4219.  
  4220.  
  4221. ΓòÉΓòÉΓòÉ 11.1.1.2. Testing Conditions ΓòÉΓòÉΓòÉ
  4222.  
  4223. In Expressions, a class of expressions called comparisons, which test whether a 
  4224. given condition is true or false, was introduced.  In a comparison, two terms 
  4225. are joined by operators such as  = (equal to), > (greater than), or < (less 
  4226. than) in order to pose a test of the terms.  The expression itself evaluates 
  4227. as, 1 if the comparison is true or 0 if the comparison is false.  For example: 
  4228.  
  4229. /* some comparisons */
  4230. say 5 = 5                   /* displays '1' - true    */
  4231. say 5 < 4                   /* displays '0' - false   */
  4232. say 5 = 4                   /* displays '0' - false   */
  4233. say 5 > 4                   /* displays '1' - true    */
  4234.  
  4235. reply = "YES"               /* assigns the string "YES"
  4236.                               to the variable REPLY   */
  4237.  
  4238. say reply                   /* displays "YES"         */
  4239. say reply = "MAYBE"         /* displays '0' - false   */
  4240. say reply = "YES"           /* displays '1' - true    */
  4241.  
  4242. For more complex ways to combine terms and operators to form comparisons, see 
  4243. Comparisons. 
  4244.  
  4245.  
  4246. ΓòÉΓòÉΓòÉ 11.1.1.3. Simple Branching ΓòÉΓòÉΓòÉ
  4247.  
  4248. To tell REXX how to make a decision about a single instruction, use: 
  4249.  
  4250. IF expression
  4251. THEN instruction
  4252.  
  4253. REXX processes instruction only if expression is true, see Figure 
  4254. "CONFIRM.CMD". 
  4255.  
  4256.  
  4257. CONFIRM.CMD
  4258.  
  4259. /* Asking confirmation */
  4260. say "Type YES to continue"
  4261. pull reply
  4262. if reply = "YES" then say "OK!"
  4263. /* program continues from here...*/
  4264.  
  4265. The instruction say "OK!" is processed only if the variable reply has the value 
  4266. YES. 
  4267.  
  4268. The IF instruction introduces a new branch of instructions to process when the 
  4269. IF expression is true.  Programmers often visualize the action of a 
  4270. decision-making instruction by using a diagram like this, called a flowchart. 
  4271.  
  4272. The decision-making expression is represented by a diamond.  If the expression 
  4273. (here REPLY="YES") evaluates as true, then the program branches, or takes a 
  4274. detour, through one additional instruction before resuming on the next line. 
  4275.  
  4276.  
  4277. ΓòÉΓòÉΓòÉ 11.1.1.4. Using DO...END for Multiple Clauses ΓòÉΓòÉΓòÉ
  4278.  
  4279. To put a list of instructions after the THEN, use the DO instruction and the 
  4280. END keyword.  That turns the whole group into a single instruction.  For 
  4281. example: 
  4282.  
  4283. IF expression THEN
  4284. DO
  4285.    instruction1
  4286.    instruction2
  4287.    instruction3
  4288.    <...and so on>
  4289. END
  4290.  
  4291. With the DO and END keywords bracketing the list, REXX knows to treat the 
  4292. listed instructions as a unit to: 
  4293.  
  4294.  o Process all of them if expression is true 
  4295.  o Ignore them all if expression is false. 
  4296.  
  4297.  Figure "WAKEUP.CMD" shows an example using DO and END. 
  4298.  
  4299.  
  4300.   WAKEUP.CMD
  4301.  
  4302.   /* Wake-up call */
  4303.   if sun = "shining"
  4304.   then
  4305.      do
  4306.        say "Get up!"
  4307.        say "Get out!"
  4308.        say "Meet the sun half way!"
  4309.      end
  4310.  
  4311.  The flowchart diagram would look like this. 
  4312.  
  4313.  In the previous example, if sun = "shining" evaluates as 1 (true), then all 
  4314.  three SAY instructions are processed.  But if sun = "shining" evaluates as 0 
  4315.  (false), then none of the SAY instructions are processed. 
  4316.  
  4317.  The THEN and DO keywords are each on a separate line.  This is optional.  You 
  4318.  could also write the program as: 
  4319.  
  4320.   /* ...this way... */                /* ...or this way */
  4321.   if sun = "shining" then            If sun = "shining" then do
  4322.   do                                    say "Get up!"
  4323.     say "Get up!"                       (etc.)
  4324.     (etc.)                              end
  4325.     end
  4326.  
  4327.  
  4328. ΓòÉΓòÉΓòÉ 11.1.1.5. Test Yourself ΓòÉΓòÉΓòÉ
  4329.  
  4330. Refer to Figure "WAKEUP.CMD".  What would happen if you left out DO and END 
  4331. keywords? 
  4332.  
  4333.  
  4334. ΓòÉΓòÉΓòÉ 11.1.1.5.1. Answer ΓòÉΓòÉΓòÉ
  4335.  
  4336. Without DO and END to mark the list as a unit, REXX assumes that only the first 
  4337. instruction following THEN is processed on condition. 
  4338.  
  4339. The instruction, say "Get up!", would be processed only if the comparison 
  4340. expression, sun = "shining", is true.  The rest of the instructions in the list 
  4341. would always be processed, regardless of the true\or-false condition of 
  4342. expression. 
  4343.  
  4344.  
  4345. ΓòÉΓòÉΓòÉ 11.1.1.6. Two Paths: ELSE ΓòÉΓòÉΓòÉ
  4346.  
  4347. Used alone, IF...THEN adds a branch of instructions to process when the 
  4348. controlling expression is true.  You can also add a second branch of 
  4349. instructions to process when the expression is false.  The keyword ELSE 
  4350. introduces this alternate list.  For example: 
  4351.  
  4352. IF expression
  4353. THEN instruction1
  4354. ELSE instruction2
  4355.  
  4356. When IF is used this way, REXX processes only one of these instructions, not 
  4357. the other.  It will process: 
  4358.  
  4359.  o Instruction1 only if expression is true 
  4360.  
  4361.  o Instruction2 only if expression is false. 
  4362.  
  4363.  IF, THEN, and ELSE were used to control the processing of the first program in 
  4364.  this book, HELLO.CMD, as shown in Figure "HELLO.CMD". 
  4365.  
  4366.  
  4367.   HELLO.CMD
  4368.  
  4369.   /* A conversation */
  4370.   say "Hello! What is your name?"
  4371.   pull who
  4372.   if who = "" then say "Hello stranger"
  4373.   else say "Hello" who
  4374.  
  4375.  The flowchart diagram would look like this. 
  4376.  
  4377.  The same idea, with a command, is used to create a more practical program. 
  4378.  Figure "BACKITUP.CMD" shows a program that takes a file name and creates a 
  4379.  backup copy.  You may want to compare the program shown in Figure 
  4380.  "BACKITUP.CMD" to the REPORTRC.CMD program shown in Figure "REPORTRC.CMD". 
  4381.  
  4382.  
  4383.   BACKITUP.CMD
  4384.  
  4385.   /* backup a REXX program */
  4386.   arg fname"."ext                  /* This is a technique called    */
  4387.                                    /* "parsing a literal pattern".  */
  4388.                                    /* Use it just as you see it     */
  4389.                                    /* here for now; more about it   */
  4390.                                    /* on page Parsing with Patterns.                  */
  4391.  
  4392.   if fname = "" then do            /* If no file name typed, then   */
  4393.      Say "Type a file name:"       /* prompt user to type a name    */
  4394.      pull fname"."ext
  4395.      end
  4396.  
  4397.   if ext = "" then ext = "CMD"     /* IF no extension given, then   */
  4398.                                    /* give it the extension '.CMD'  */
  4399.  
  4400.   "dir" fname"."ext                /* displays directory entry for  */
  4401.                                    /* the input file name, thereby  */
  4402.                                    /* making sure it exists....     */
  4403.  
  4404.   if rc <> 0 then do               /* IF no such file exists, then  */
  4405.      say "No backup performed."    /* EXIT the program. (More about */
  4406.      say "Program ended."          /* the EXIT instruction on       */
  4407.      exit                          /* on page Exiting a Program.)                  */
  4408.      end
  4409.  
  4410.   else do                                /* ELSE, copy the file to  */
  4411.      say "Backing up" fname"."ext        /* one with the extension  */
  4412.      "copy" fname"."ext  fname".BKP"     /* '.BKP'; then confirm    */
  4413.      "dir" fname".BKP"                   /* it with a "DIR" command */
  4414.      say "Program ended"
  4415.      exit
  4416.      end
  4417.  
  4418.  The ELSE clause must also use DO and END to bracket a list of instructions. 
  4419.  
  4420.  Note:  REXX features in this program that have not been introduced yet are: 
  4421.  
  4422.  o The EXIT instruction, which tells REXX explicitly to end the program. 
  4423.  
  4424.  o The period in quotes in the ARG and PULL instructions called a literal 
  4425.    parsing pattern, which tells REXX to remove that quoted string (if it 
  4426.    occurs) in the user's file name entry. What is left is broken into two 
  4427.    parts, which in turn are assigned to the variable FNAME and EXT.  This is 
  4428.    the only example of a literal pattern used in "Basics".  For more 
  4429.    information, refer to Parsing with Patterns. 
  4430.  :enote. 
  4431.  
  4432.  
  4433. ΓòÉΓòÉΓòÉ 11.1.1.7. The SELECT Instruction ΓòÉΓòÉΓòÉ
  4434.  
  4435. You are not limited to two choices.  You can use the SELECT instruction to have 
  4436. a REXX program select one of any number of branches. For example: 
  4437.  
  4438. SELECT
  4439.    WHEN expression1 THEN instruction1
  4440.    WHEN expression2 THEN instruction2
  4441.    WHEN expression3 THEN instruction3
  4442.    ...
  4443.  
  4444.     OTHERWISE
  4445.        instruction
  4446.        instruction
  4447.        instruction
  4448.        ...
  4449.  
  4450. END
  4451.  
  4452.  o If expression1 is true, instruction1 is processed. After this, processing 
  4453.    continues with the instruction following the END. 
  4454.  
  4455.  o If expression1 is false, then expression2 is tested. If it is true, then 
  4456.    instruction2 is processed and processing continues with the instruction 
  4457.    following the END. 
  4458.  
  4459.  o If expression1, expression2, and so on, are all false, then processing 
  4460.    continues with the instruction following the OTHERWISE. 
  4461.  
  4462.  OTHERWISE is essentially the SELECT-equivalent of ELSE.  If there is any 
  4463.  possibility that all the WHEN expressions could be false, there must be an 
  4464.  OTHERWISE clause. 
  4465.  
  4466.  The following is how SELECT is diagramed in a flowchart. 
  4467.  
  4468.  To process a list of instructions following the THEN keyword, use: 
  4469.  
  4470.   DO
  4471.      instruction1
  4472.      instruction2
  4473.      instruction3
  4474.   .
  4475.   .
  4476.   .
  4477.   END
  4478.  
  4479.  A DO; ... END group is not required after the OTHERWISE keyword. 
  4480.  
  4481.  
  4482. ΓòÉΓòÉΓòÉ 11.1.1.8. Multiple Choice ΓòÉΓòÉΓòÉ
  4483.  
  4484. Figure "Q.CMD" shows a short program that uses SELECT. 
  4485.  
  4486.  
  4487. Q.CMD
  4488.  
  4489. /* displays date/time information */
  4490.  
  4491. arg request      /* get argument; convert to uppercase */
  4492.  
  4493. select
  4494.    when request = "DATE"  then say date()
  4495.    when request = "TIME"  then say time()
  4496.    when request = "DAY"   then say date(w)
  4497.    when request = "MONTH" then say date(m)
  4498.    when request = "SOFAR" then do
  4499.                                  say time(h) "hours"
  4500.                                  say time(m) "minutes"
  4501.                                  say time(s) "seconds"
  4502.                                end
  4503.  
  4504.    /* if no valid argument given, display help information */
  4505.  
  4506.    otherwise say "Valid arguments are:"
  4507.              say " date   -  calendar date"
  4508.              say " time   -  military time"
  4509.              say " day    -  day of the week"
  4510.              say " month  -  month"
  4511.              say " sofar  -  hrs/min/sec since midnight"
  4512. end
  4513.  
  4514. Remember that SELECT must have a corresponding END.  As with DO, it makes your 
  4515. program easier for people to read if you indent everything between the SELECT 
  4516. and the END three spaces to the right.  SELECT is a specialized form of the IF 
  4517. instruction. 
  4518.  
  4519.  
  4520. ΓòÉΓòÉΓòÉ 11.1.1.9. Test Yourself ΓòÉΓòÉΓòÉ
  4521.  
  4522. Write a program that asks the user to type two words on the same line and 
  4523. computes if: 
  4524.  
  4525.  o The values of the words are the same (or numerically equal). 
  4526.  o The value of the first word is higher. 
  4527.  o The value of the second word is higher. 
  4528.  
  4529.  The comparison must ignore differences in case.  For example, A should 
  4530.  evaluate as equal to a. 
  4531.  
  4532.  
  4533. ΓòÉΓòÉΓòÉ 11.1.1.9.1. Answers ΓòÉΓòÉΓòÉ
  4534.  
  4535. Figure "COMPARE1.CMD" shows one possible program. 
  4536.  
  4537.  
  4538. COMPARE1.CMD
  4539.  
  4540.  
  4541. /* This program requests the user to supply two     */
  4542. /* words and says which is higher.                  */
  4543.  
  4544. say "Type two words"
  4545. pull word1 word2 .
  4546. select
  4547.    when word1 = word2 then
  4548.       say "The words are the same",
  4549.                "or numerically equal"
  4550.    when word1 > word2 then
  4551.       say "The first word is higher"
  4552.    otherwise
  4553.       say "The second word is higher"
  4554.    end
  4555.  
  4556. Notice that a period appears after the PULL instruction in Figure 
  4557. "COMPARE1.CMD". You've already learned about using a period in compound 
  4558. symbols. (See Using Compound Symbols.)  You can use a period as a placeholder 
  4559. with the PULL instruction.  Refer to Using a Placeholder for additional 
  4560. information. 
  4561.  
  4562. Figure "COMPARE2.CMD" shows an alternative program using IF. 
  4563.  
  4564.  
  4565. COMPARE2.CMD
  4566.  
  4567.  
  4568. /* This program requests the user to supply two     */
  4569. /* words and says which is higher.                  */
  4570.  
  4571. say "Type two words"
  4572. pull word1 word2 .
  4573. if word1 = word2
  4574. then say "The words are the same",
  4575.             "or numerically equal"
  4576. else do
  4577.    if word1 > word2
  4578.    then say "The first word is higher"
  4579.    else say "The second word is higher"
  4580. end
  4581.  
  4582. Some people may consider the first solution better because it is slightly 
  4583. easier to understand. 
  4584.  
  4585. For other considerations about when to use IF and SELECT, see Nested IF and 
  4586. SELECT. 
  4587.  
  4588.  
  4589. ΓòÉΓòÉΓòÉ 11.1.2. Repetitive Tasks ΓòÉΓòÉΓòÉ
  4590.  
  4591. Computers excel at repetitive tasks.  An essential part of any computer 
  4592. language is a loop instruction, which is a way to make a program repeat a list 
  4593. of instructions: 
  4594.  
  4595.  o A specific number of times 
  4596.  o As long as some condition is true 
  4597.  o Until some condition is satisfied 
  4598.  o Forever (until the user wants to stop). 
  4599.  
  4600.  To repeat a loop a number of times, use: 
  4601.  
  4602.   DO exprr
  4603.      instruction1
  4604.      instruction2
  4605.      instruction3
  4606.   .
  4607.   .
  4608.   .
  4609.   END
  4610.  where: 
  4611.  
  4612.  exprr    (the expression for repetitor) gives a whole number, which is the 
  4613.           number of times the loop is processed. 
  4614.  
  4615.  To make your program easier for people to read, you should indent the 
  4616.  instructions between the DO and the END three spaces to the right. 
  4617.  
  4618.  Figure "HANDOUTS.CMD" is an example of a repetitive loop that prints three 
  4619.  documents five times. 
  4620.  
  4621.  
  4622.   HANDOUTS.CMD
  4623.  
  4624.   /* To print documents for a meeting:  for each person,  */
  4625.   /* the agenda, minutes and accounts are printed once    */
  4626.  
  4627.   do 5
  4628.      "PRINT AGENDA.DOC"
  4629.      "PRINT MINUTES.DOC"
  4630.      "PRINT ACCOUNTS.DOC"
  4631.   end
  4632.  
  4633.  Consider how you would write a program that would ask for the number of copies 
  4634.  needed and one that would ask for the names of the documents. 
  4635.  
  4636.  Figure "RECTANGL.CMD" is an example of a repetitive loop that processes the 
  4637.  instruction between the DO and the END, height times. 
  4638.  
  4639.  
  4640.   RECTANGL.CMD
  4641.  
  4642.   /* The user is asked to specify the height of a         */
  4643.   /* rectangle (within certain limits).  The rectangle    */
  4644.   /* is then displayed on the screen.                     */
  4645.  
  4646.   say "Type the height of the rectangle",
  4647.       " (a whole number between 3 and 15)."
  4648.   pull height
  4649.   select
  4650.      when  \datatype(height,WHOLE) then say "Rubbish!"
  4651.      when  height < 3 then say "Too small!"
  4652.      when  height > 15 then say "Too big!"
  4653.      otherwise
  4654.  
  4655.                                   /* draw rectangle       */
  4656.      do height
  4657.         say copies("*",2*height)
  4658.      end
  4659.  
  4660.      say "What a pretty box!"
  4661.   end
  4662.  
  4663.  
  4664. ΓòÉΓòÉΓòÉ 11.1.3. Conditional Loops ΓòÉΓòÉΓòÉ
  4665.  
  4666. A conditional expression is tested to determine how many times the loop is 
  4667. processed.  Conditional loops continue running as long as some condition is 
  4668. satisfied.  The three main ways to do this, depending on when the test takes 
  4669. place are: 
  4670.  
  4671.  o DO FOREVER (with LEAVE) 
  4672.  o DO WHILE (a condition is true) 
  4673.  o DO UNTIL (a condition is true). 
  4674.  
  4675.  Note:  When you are experimenting with conditional loops, you may run into a 
  4676.  situation where your program does not stop.  This is called an endless loop, 
  4677.  which means that the condition that controls the loop is never false.  If this 
  4678.  happens, you can stop the program by pressing the Control (Ctrl)+Break keys. 
  4679.  :enote. 
  4680.  
  4681.  
  4682. ΓòÉΓòÉΓòÉ 11.1.3.1. DO FOREVER with the LEAVE Instruction ΓòÉΓòÉΓòÉ
  4683.  
  4684. The simplest way to create a conditional loop is to use the instructions DO 
  4685. FOREVER and LEAVE.  The LEAVE instruction causes processing to continue with 
  4686. the instruction following the END keyword. 
  4687.  
  4688. The mini-calculator program, ADD2NUM.CMD, shown in Figure "ADD2NUM.CMD", adds 
  4689. only two numbers.  Figure "SUM.CMD" shows a program that continues running as 
  4690. long as you type a number.  If you do not type a number, the LEAVE instruction 
  4691. is processed and processing continues with the SAY instruction after the END of 
  4692. the loop. 
  4693.  
  4694.  
  4695. SUM.CMD
  4696.  
  4697. /* This program adds up the numbers that the user is    */
  4698. /* invited to type.  When the user types something      */
  4699. /* that is not a number, a message is displayed and     */
  4700. /* the program ends.                                    */
  4701. total = 0
  4702. do forever
  4703.    say "Type a number"
  4704.    pull entry
  4705.    if \datatype(entry,n)  /*if the entry is not a valid number */
  4706.    then leave                   /* leave the loop */
  4707.    total = total + entry
  4708.    say "Total = " total
  4709. end
  4710. say "'"entry"' is not a number.  Returning to OS/2."
  4711.  
  4712. The other two forms of DO loops, where the conditional test (the if) is built 
  4713. into the control instruction, are: 
  4714.  
  4715.  o DO WHILE 
  4716.  o DO UNTIL. 
  4717.  
  4718.  
  4719. ΓòÉΓòÉΓòÉ 11.1.3.2. DO WHILE Instruction ΓòÉΓòÉΓòÉ
  4720.  
  4721. To create a loop that repeats the list of instructions as long as a given 
  4722. condition is true, use the DO WHILE instruction.  For example: 
  4723.  
  4724. DO WHILE exprw
  4725.    instruction1
  4726.    instruction2
  4727.    instruction3
  4728. END
  4729. where: 
  4730.  
  4731.  exprw    (expression for while) is an expression that, when evaluated, must 
  4732.           give a result of 0 or 1. 
  4733.  
  4734.  The following is a flowchart of a DO WHILE loop.  The condition is tested at 
  4735.  the top of the loop, before the instruction list is processed.  This means 
  4736.  that if the given condition is false at the start, the list of instructions 
  4737.  are not be processed at all.  Compare this instruction with the flowchart 
  4738.  showing the DO UNTIL instruction on page DO UNTIL Instruction. 
  4739.  
  4740.  Two fragments that produce the same results are: 
  4741.  
  4742.   DO WHILE \ finished
  4743.      instruction1
  4744.      instruction2
  4745.      instruction3
  4746.   END
  4747.  or 
  4748.  
  4749.   DO FOREVER
  4750.      if finished then LEAVE
  4751.      instruction1
  4752.      instruction2
  4753.      instruction3
  4754.   END
  4755.  
  4756.  You could use DO WHILE to prompt users for data only if they forget to type an 
  4757.  argument at the command prompt.  For example: 
  4758.  
  4759.   /* get the argument */
  4760.   arg filename
  4761.   do while filename = ""    /* if no argument given, then do... */
  4762.     say "Type a file name (or a * to quit):"
  4763.     pull filename
  4764.     if filename = "*" then exit
  4765.     end
  4766.   .
  4767.   .
  4768.   .
  4769.  
  4770.  In the previous example, if the user types a file name as a command argument, 
  4771.  then the instructions within the DO WHILE loop are ignored.  If no argument 
  4772.  has been given, the loop is processed as long as the variable filename holds 
  4773.  an empty string. 
  4774.  
  4775.  
  4776. ΓòÉΓòÉΓòÉ 11.1.3.3. DO UNTIL Instruction ΓòÉΓòÉΓòÉ
  4777.  
  4778. To repeat one or more instructions until a given condition is true, you can 
  4779. create a loop with the test at the bottom. For example: 
  4780.  
  4781. DO UNTIL expru
  4782.    instruction1
  4783.    instruction2
  4784.    instruction3
  4785. .
  4786. .
  4787. .
  4788. END
  4789. where: 
  4790.  
  4791.  expru    (expression for until) is an expression that, when evaluated, must 
  4792.           give a result of 0 or 1. 
  4793.  
  4794.  Putting the test at the bottom of the loop means that the enclosed instruction 
  4795.  list is always processed at least once, even if the given condition is false 
  4796.  at the start.  Compare the following flowchart with the previous one for the 
  4797.  DO WHILE instruction on page DO WHILE Instruction. 
  4798.  
  4799.  Two fragments that produce the same results are: 
  4800.  
  4801.   DO UNTIL finished
  4802.      instruction1
  4803.      instruction2
  4804.      instruction3
  4805.   END
  4806.  or 
  4807.  
  4808.   DO FOREVER
  4809.      instruction1
  4810.      instruction2
  4811.      instruction3
  4812.      if finished then LEAVE
  4813.   END
  4814.  
  4815.  The DO UNTIL instruction also provides a convenient way to check input.  This 
  4816.  loop uses the DATATYPE() function to ensure that the user types only a number: 
  4817.  
  4818.   /* numbers only */
  4819.   do until datatype(entry,num)
  4820.     say "type a number"
  4821.     say "(or press the Enter key alone to quit):"
  4822.     pull entry
  4823.     if entry = "" then exit
  4824.     end
  4825.  
  4826.  This loop is always processed at least once, even if the variable entry is 
  4827.  already a number.  It continues until the user either types a number or enters 
  4828.  an empty string by pressing the Enter key. 
  4829.  
  4830.  By typing an asterisk in the first example or a null string in the second, the 
  4831.  user has a way out of the loop.  It is important to include these escape 
  4832.  clauses.  Endless loops are frustrating to the program user. 
  4833.  
  4834.  
  4835. ΓòÉΓòÉΓòÉ 11.1.3.4. To Summarize ΓòÉΓòÉΓòÉ
  4836.  
  4837. In the three kinds of conditional loops, the decision is made: 
  4838.  
  4839.  o Before processing starts.  The following example of this program fills bath 
  4840.    by repeatedly adding the value of bucket to it.  If bath is already full 
  4841.    (equal to or greater than the value of full), the body of the loop is not 
  4842.    processed and nothing is added to bath. 
  4843.  
  4844.       DO WHILE bath < full
  4845.          bath = bath + bucket
  4846.       end
  4847.  
  4848.  o After the first pass through the loop and again after every subsequent pass. 
  4849.    An example is requesting valid data from a user. 
  4850.  
  4851.       DO UNTIL datatype(input,NUMBER)
  4852.          say "Type a number"
  4853.          pull input
  4854.       end
  4855.  
  4856.  o During each pass.  For example, the decision to leave may depend on 
  4857.    information obtained during the loop. 
  4858.  
  4859.       DO FOREVER
  4860.          say "Type an item of data.  When there is",
  4861.              " no more data, type QUIT"
  4862.          pull answer
  4863.          if answer = "QUIT" then leave
  4864.             ...   /* process the data */
  4865.       end
  4866.  
  4867.  Be careful about the condition for repeating the loop.  For DO WHILE, the 
  4868.  condition must be true; for DO UNTIL, the condition must be false. 
  4869.  
  4870.  
  4871. ΓòÉΓòÉΓòÉ 11.1.3.5. Test Yourself ΓòÉΓòÉΓòÉ
  4872.  
  4873.   1. What type of DO instruction would you use to code the following sequence? 
  4874.  
  4875.     Is job done? 
  4876.  
  4877.        instruction1 
  4878.        instruction2 
  4879.        instruction3 
  4880.  
  4881.     Is job done? 
  4882.  
  4883.        instruction1 
  4884.        instruction2 
  4885.        instruction3 
  4886.  
  4887.     Is job done? 
  4888.  
  4889.     . 
  4890.     . 
  4891.     . 
  4892.  
  4893.     Is job done? 
  4894.  
  4895.   2. What type of DO instruction would you use to code the following sequence? 
  4896.  
  4897.        instruction1 
  4898.        instruction2 
  4899.        instruction3 
  4900.  
  4901.     Is job done? 
  4902.  
  4903.        instruction1 
  4904.        instruction2 
  4905.        instruction3 
  4906.  
  4907.     Is job done? 
  4908.  
  4909.     . 
  4910.     . 
  4911.     . 
  4912.  
  4913.     Is job done? 
  4914.  
  4915.   3. "Thirty days hath September, April, June, and November; all the rest have 
  4916.      thirty-one, excepting February alone ..." 
  4917.  
  4918.      Write a program that asks the user to specify the month as a number 
  4919.      between 1 and 12 and gives the number of days in the month in response. 
  4920.      For month 2, the response can be 28 or 29. 
  4921.  
  4922.  
  4923. ΓòÉΓòÉΓòÉ 11.1.3.5.1. Answers: ΓòÉΓòÉΓòÉ
  4924.  
  4925.   1. DO WHILE job \= done  (The first operation is to test "Is job done?"). 
  4926.  
  4927.   2. DO UNTIL job = done  (The first operation is to process the list of 
  4928.      instructions.) 
  4929.  
  4930.   3. Figure "CALENDAR.CMD" shows a program that displays the number of days in 
  4931.      the month. 
  4932.  
  4933.  
  4934.           CALENDAR.CMD
  4935.  
  4936.  
  4937.           /* This program requests the user to type a whole   */
  4938.           /* number from 1 through 12 and displays the        */
  4939.           /* number of days in that month.                    */
  4940.  
  4941.           /*--------------------------------------------------*/
  4942.           /* Get input from user                              */
  4943.           /*--------------------------------------------------*/
  4944.           do until datatype(month,WHOLE),
  4945.                 & month >= 1 & month <= 12
  4946.              say "Type the month as a number from 1 through 12"
  4947.              pull month
  4948.           end
  4949.           /*--------------------------------------------------*/
  4950.           /* Compute days in month                            */
  4951.           /*--------------------------------------------------*/
  4952.           select
  4953.              when month =  9 then days = 30
  4954.              when month =  4 then days = 30
  4955.              when month =  6 then days = 30
  4956.              when month = 11 then days = 30
  4957.              when month =  2 then days = "28 or 29"
  4958.              otherwise
  4959.              days = 31
  4960.           end
  4961.  
  4962.           say "There are" days "days in Month" month
  4963.  
  4964.  
  4965. ΓòÉΓòÉΓòÉ 11.1.3.6. Using IF, SELECT, and DO ΓòÉΓòÉΓòÉ
  4966.  
  4967. Figure "CENSUS.CMD" shows a program that combines three different control 
  4968. instructions.  It asks the user to provide a person's age and sex and, in 
  4969. reply, it displays a person's status. 
  4970.  
  4971. Note: 
  4972.  
  4973.  A person under the age of 5 is a BABY. 
  4974.  A person aged 5 through 12 is a BOY or a GIRL. 
  4975.  A person aged 13 through 19 is a TEENAGER. 
  4976.  A person over the age of 19 a MAN or a WOMAN. 
  4977.  :enote. 
  4978.  
  4979.  The program uses DO UNTIL to make certain that the proper input has been 
  4980.  typed.  It then uses SELECT to choose one of four age groups and IF, as 
  4981.  needed, to determine the sex.  Try the program. 
  4982.  
  4983.  
  4984.   CENSUS.CMD
  4985.  
  4986.  
  4987.   /*------------------------------------------------------*/
  4988.   /* Get input from user                                  */
  4989.   /*------------------------------------------------------*/
  4990.   do until datatype(age,NUMBER) & age >= 0
  4991.      say "What is the person's age?"
  4992.      pull age
  4993.   end
  4994.  
  4995.   do until sex = "M" | sex = "F"
  4996.      say "What is the person's sex (M or F)?"
  4997.      pull sex
  4998.   end
  4999.   /*------------------------------------------------------*/
  5000.   /* COMPUTE STATUS                                       */
  5001.   /*                                                      */
  5002.   /* Input:                                               */
  5003.   /* AGE     Assumed to be 0 or a positive number.        */
  5004.   /* SEX     "M" is taken to be male;                     */
  5005.   /*         anything else is taken to be female.         */
  5006.   /*                                                      */
  5007.   /* Result:                                              */
  5008.   /* STATUS  Possible values: BABY, BOY, GIRL, TEENAGER   */
  5009.   /*         MAN, WOMAN.                                  */
  5010.   /*------------------------------------------------------*/
  5011.   Select
  5012.      when age < 5 then status = "BABY"
  5013.      when age < 13 then do
  5014.         if sex = "M"
  5015.         then status = "BOY"
  5016.         else status = "GIRL"
  5017.         end
  5018.      when age < 20 then status = "TEENAGER"
  5019.      otherwise
  5020.         if sex = "M"
  5021.         then status = "MAN"
  5022.         else status = "WOMAN"
  5023.   end
  5024.  
  5025.   say "This person should be counted as a" status
  5026.  
  5027.  
  5028. ΓòÉΓòÉΓòÉ 11.1.4. Using Counters to Exit Loops ΓòÉΓòÉΓòÉ
  5029.  
  5030. Number each pass through the loop in such a way that you can use that number as 
  5031. a variable in your program.  For example: 
  5032.  
  5033. DO name = expri
  5034.    instruction1
  5035.    instruction2
  5036.    instruction3
  5037. .
  5038. .
  5039. .
  5040. END
  5041. or 
  5042.  
  5043. DO name = expri TO exprt
  5044.    instruction1
  5045.    instruction2
  5046.    instruction3
  5047. .
  5048. .
  5049. .
  5050. END
  5051. where: 
  5052.  
  5053.  name       is the control variable, sometimes called a counter. You can use it 
  5054.             in the body of the loop.  Its value is changed (in this example, 
  5055.             increased by 1) each time through the loop. 
  5056.  
  5057.  expri      (the expression for the initial value) is the value you want the 
  5058.             counter to have the first time through the loop. 
  5059.  
  5060.  exprt      (the expression for the TO value) is the value you want the counter 
  5061.             to have the last time through the loop.  That is, the loop ends if 
  5062.             the next time through, it puts the counter above the exprt value. 
  5063.  
  5064.  The following flowchart shows how the counter is changed and how the decision 
  5065.  to leave the loop is made. 
  5066.  
  5067.  You can use the counter to compute something different each time through the 
  5068.  loop.  Figure "TRIANGLE.CMD" shows a program in which the counter is called 
  5069.  count, and it computes the width of each row of asterisks. 
  5070.  
  5071.  
  5072.   TRIANGLE.CMD
  5073.  
  5074.   /* This program displays a triangle on the screen.      */
  5075.   /* The user is asked to specify the height of the       */
  5076.   /* triangle.                                            */
  5077.  
  5078.   say "Type the height of the triangle",
  5079.       " (a whole number between 3 and 15)."
  5080.   pull height
  5081.   select
  5082.      when  \datatype(height,WHOLE) then say "Rubbish!"
  5083.      when  height < 3 then say "Too small!"
  5084.      when  height > 15 then say "Too big!"
  5085.      otherwise
  5086.  
  5087.                                   /* draw triangle        */
  5088.      do count = 1 to height
  5089.         say copies("*",2*count - 1)
  5090.      end
  5091.  
  5092.      say "What an ugly triangle!"
  5093.   end
  5094.  
  5095.  After you have left the loop, you can still refer to the counter. It always 
  5096.  exceeds the value of the TO expression (exprt). 
  5097.  
  5098.  
  5099. ΓòÉΓòÉΓòÉ 11.1.4.1. Bigger Steps ΓòÉΓòÉΓòÉ
  5100.  
  5101. So far, the counter has been incremented by 1 each time through the loop. This 
  5102. is the default.  To specify some other value, write: 
  5103.  
  5104. DO name = expri BY exprb [TO exprt]
  5105. .
  5106. .
  5107. .
  5108. .
  5109. .
  5110. .
  5111. END
  5112. where: 
  5113.  
  5114.  exprb    (the expression for BY) is the number that is to be added to name at 
  5115.           the bottom of the loop. 
  5116.  
  5117.  
  5118. ΓòÉΓòÉΓòÉ 11.1.4.2. Different Steps ΓòÉΓòÉΓòÉ
  5119.  
  5120. All of the expressions described for controlling loops (the TO and BY 
  5121. expressions and the counter) need not be positive whole numbers.  You can use 
  5122. expressions that evaluate as decimal fractions and negative values as well. 
  5123. See the REXX Reference for examples. 
  5124.  
  5125.  
  5126. ΓòÉΓòÉΓòÉ 11.1.4.3. Test Yourself ΓòÉΓòÉΓòÉ
  5127.  
  5128.   1. Refer to the flowchart on page Using Counters to Exit Loops and predict 
  5129.      what the program in Figure "MORE.CMD" will display. 
  5130.  
  5131.  
  5132.           MORE.CMD
  5133.  
  5134.           /* Example: use of a counter */
  5135.           do digit = 1 to 3
  5136.              say digit
  5137.           end
  5138.           say "Now you have reached" digit
  5139.  
  5140.   2. What will the program in Figure "2LESS.CMD" display? 
  5141.  
  5142.  
  5143.           2LESS.CMD
  5144.  
  5145.           /* Example: use of a counter */
  5146.           do count = 10 by -2 to 6
  5147.              say count
  5148.           end
  5149.           say "Now you have reached" count
  5150.  
  5151.   3. How many lines will the program in Figure "3HUP.CMD" display? 
  5152.  
  5153.  
  5154.           3HUP.CMD
  5155.  
  5156.           /* Example: use of a counter */
  5157.           do j = 10 to 8
  5158.              say "Hup! Hup! Hup!"
  5159.           end
  5160.  
  5161.   4. How many lines will the program in Figure "4NOW.CMD" display? 
  5162.  
  5163.  
  5164.           4NOW.CMD
  5165.  
  5166.           /* Example: use of a counter */
  5167.           do NOW = 1
  5168.              if NOW = 9 then exit
  5169.              say NOW
  5170.           end
  5171.  
  5172.  
  5173. ΓòÉΓòÉΓòÉ 11.1.4.3.1. Answers: ΓòÉΓòÉΓòÉ
  5174.  
  5175.   1. The counter is updated at the bottom of the loop.  The test for leaving is 
  5176.      made after this.  So the counter is beyond the limit value. 
  5177.  
  5178.     1 
  5179.     2 
  5180.     3 
  5181.     Now you have reached 4 
  5182.  
  5183.   2. If exprb is negative, count down: 
  5184.  
  5185.     10 
  5186.     8 
  5187.     6 
  5188.     Now you have reached 4 
  5189.  
  5190.   3. None  (10 already exceeds 8). 
  5191.  
  5192.   4. Eight, (on the ninth pass, the EXIT instruction ends the program before 
  5193.      the SAY instruction is reached). 
  5194.  
  5195.  
  5196. ΓòÉΓòÉΓòÉ 11.1.5. Exiting a Program ΓòÉΓòÉΓòÉ
  5197.  
  5198. Use EXIT [expression], to tell REXX to leave your program.  If you started the 
  5199. program by typing its name at the OS/2 command prompt: 
  5200.  
  5201.  o EXIT takes you back to the OS/2 program. 
  5202.  
  5203.  o The result of expression must be a whole number, which is returned to (but 
  5204.    not displayed by) the OS/2 program. 
  5205.  Figure "FADE.CMD" shows an example using EXIT. 
  5206.  
  5207.  
  5208.   FADE.CMD
  5209.  
  5210.   /* Example: using EXIT with a return code */
  5211.   say "Returning to the OS/2 program"
  5212.   exit 22
  5213.  
  5214.  The following is displayed on the screen, when you run this program. 
  5215.  
  5216.   [C:\]fade
  5217.   Returning to OS/2
  5218.   [C:\]
  5219.  
  5220.  
  5221. ΓòÉΓòÉΓòÉ 11.1.6. Summary ΓòÉΓòÉΓòÉ
  5222.  
  5223. This completes "Basics" in this chapter.  You have learned how to: 
  5224.  
  5225.  o Create branches in a program with IF and SELECT 
  5226.  o Group instructions with DO 
  5227.  o Create loops with DO FOREVER, DO UNTIL, and DO WHILE. 
  5228.  
  5229.  "Advanced Topics" in this chapter discusses complex controls, including: 
  5230.  
  5231.  o Nesting IF instructions 
  5232.  o Using the NOP instruction 
  5233.  o Using DO with LEAVE and ITERATE 
  5234.  o Nesting DO instructions. 
  5235.  
  5236.  To continue with "Basics," go to page 7-1. 
  5237.  
  5238.  
  5239. ΓòÉΓòÉΓòÉ 11.2. Advanced Topics ΓòÉΓòÉΓòÉ
  5240.  
  5241.      In this chapter: Advanced Topics 
  5242.  
  5243.      o Nesting IF instructions 
  5244.      o The ITERATE instruction 
  5245.      o Compound DO instructions 
  5246.      o Nested loops. 
  5247.  
  5248.  
  5249. ΓòÉΓòÉΓòÉ 11.2.1. Nesting IF Instructions ΓòÉΓòÉΓòÉ
  5250.  
  5251. You can manage more complicated situations by using IF instructions in the 
  5252. lists controlled by other IFs.  This flowchart shows two successive decisions 
  5253. that lead to one of four possible outcomes. 
  5254.  
  5255. The best way to write this as a program is: 
  5256.  
  5257. if weather = "fine"
  5258. then do
  5259.    if tenniscourt = "free"
  5260.    then say "Shall we play tennis?"
  5261.    else say "Shall we take a stroll?"
  5262. end
  5263. else do
  5264.    if players = 2
  5265.    then say "Shall we play chess?"
  5266.    else say "Shall we play poker?"
  5267. end
  5268.  
  5269. Indenting the secondary decisions to the right three spaces does not change how 
  5270. REXX processes the program.  It makes it easier for someone reading the program 
  5271. to see the control structure. 
  5272.  
  5273.  
  5274. ΓòÉΓòÉΓòÉ 11.2.1.1. Nested IF and SELECT ΓòÉΓòÉΓòÉ
  5275.  
  5276. The previous example tests each condition and moves on to the next level.  It 
  5277. does not consider whether the tennis court is free until it has determined that 
  5278. the weather is fine. 
  5279.  
  5280. Compare this nested-IF example to one using the SELECT instruction.  There 
  5281. still are four possible outcomes, but this time they are tested in parallel. 
  5282.  
  5283. select
  5284.   when weather = "fine" & tenniscourt = "free"
  5285.      then say "Shall we play tennis?"
  5286.   when weather = "fine" & tenniscourt \= "free"
  5287.      then say "Shall we take a stroll?"
  5288.   when weather \= "fine" & players = 2
  5289.      then say "Shall we play chess?"
  5290.   otherwise say "Shall we play poker?"
  5291. end
  5292.  
  5293. The distinction to make here is not which version works better. Rather, it is 
  5294. which of the two programs is more readable to the user who corrects and 
  5295. improves them.  The results of these two programs would be the same. 
  5296.  
  5297. For this application, the nested-IF version shows more clearly how the decision 
  5298. whether to play tennis depends on the weather.  The only priority of 
  5299. decision-making available to SELECT is the order given the WHEN keywords. 
  5300. Therefore use: 
  5301.  
  5302.  o SELECT when your program must make more or less parallel decisions, choosing 
  5303.    one option to the exclusion of the rest. 
  5304.  
  5305.  o Nested IF when your program must make a series of decisions, each decision 
  5306.    dependent on the ones that precede it. 
  5307.  
  5308.  
  5309. ΓòÉΓòÉΓòÉ 11.2.1.2. Dangling ELSE ΓòÉΓòÉΓòÉ
  5310.  
  5311. DO and END help REXX keep the ELSEs tied to the right IFs.  Look at the 
  5312. following example.  Avoid writing code like this, because it is too 
  5313. error-prone. 
  5314.  
  5315. /* The dangling ELSE */
  5316.  
  5317. if weather = fine
  5318. then
  5319.     if tenniscourt = free
  5320.     then say "Shall we play tennis?"
  5321.  
  5322.   else say "Shall we take our raincoats?"
  5323.  
  5324.   /* REXX will take this ELSE to belong               */
  5325.   /* to the nearest preceding IF, but a person        */
  5326.   /* reading the program might easily assume that it  */
  5327.   /* belonged to the first IF.                        */
  5328.  
  5329. Programs that have IFs within IFs should use DO ... END. The following example 
  5330. pairs THEN DO with END and THEN with ELSE. 
  5331.  
  5332. if ...
  5333.    then do
  5334.       if ...
  5335.          then do
  5336.             ...
  5337.             ...
  5338.          end
  5339.          else do
  5340.             ...
  5341.             ...
  5342.          end
  5343.    end
  5344.    else ...
  5345.  
  5346. Remember, using indentation does not affect how the program is interpreted. It 
  5347. is simply a convention to make the program more readable. Readability is 
  5348. discussed in Making Programs Easy to Read. 
  5349.  
  5350.  
  5351. ΓòÉΓòÉΓòÉ 11.2.1.3. Test Yourself ΓòÉΓòÉΓòÉ
  5352.  
  5353. What will the program in Figure "WHATTODO.CMD" do? 
  5354.  
  5355.  
  5356. WHATTODO.CMD
  5357.  
  5358. /* An example of a program that does not use "DO...END"  */
  5359. /* input data */
  5360. trace r
  5361. weather = "RAIN"
  5362. tenniscourt = "FREE"
  5363. players = 2
  5364.  
  5365. if weather = fine
  5366. then
  5367.    if tenniscourt = free
  5368.    then say "Shall we play tennis?"
  5369.    /* else say "Shall we take a stroll?" (DELETED)     */
  5370. else
  5371.    if players = 2
  5372.    then say "Shall we play chess?"
  5373.    else say "Shall we play poker?"
  5374.  
  5375. Try it!  The TRACE R (results) instruction at the beginning will help you see 
  5376. what is happening. 
  5377.  
  5378.  
  5379. ΓòÉΓòÉΓòÉ 11.2.1.3.1. Answer ΓòÉΓòÉΓòÉ
  5380.  
  5381. Remember the ELSE keyword is associated with the nearest preceding IF. The 
  5382. following flowchart shows what happens when these values are given for weather, 
  5383. tenniscourt, and players. 
  5384.  
  5385. If the weather is anything but fine, the program displays nothing.  It never 
  5386. considers how many players are available. The trace of WHATTODO.CMD program 
  5387. displays: 
  5388.  
  5389. [C:\]whattodo
  5390.      3 *-*      weather = 'RAIN';
  5391.      3 >>>        "RAIN"
  5392.      4 *-*      tenniscourt = 'FREE';
  5393.      4 >>>        "FREE'
  5394.      5 *-*      players = 2;
  5395.      5 >>>        "2"
  5396.      7 *-*      If weather = 'FINE';
  5397.      7 +++        "0"
  5398.  
  5399. [C:\]
  5400.  
  5401.  
  5402. ΓòÉΓòÉΓòÉ 11.2.1.4. NOP Instruction ΓòÉΓòÉΓòÉ
  5403.  
  5404. A THEN or ELSE keyword must be followed by an instruction. A semicolon is not 
  5405. sufficient.  In cases where you intend that nothing should be done, use a NOP 
  5406. (no operation) instruction.  You could use the NOP instruction to add an ELSE 
  5407. keyword in WHATTODO.CMD in Figure "WHATTODO.CMD". For example: 
  5408.  
  5409. .
  5410. .
  5411. .
  5412. if weather = fine
  5413. then
  5414.    if tenniscourt = free
  5415.    then say "Shall we play tennis?"
  5416.    /* else say "Shall we take a stroll?" (DELETED)     */
  5417.    else NOP
  5418. else
  5419.    if players = 2
  5420.    then say "Shall we play chess?"
  5421.    else say "Shall we play poker?"
  5422.  
  5423. The following flowchart shows how the program flow is changed to. 
  5424.  
  5425. Figure "PILOT.CMD" and Figure "TRUCKER.CMD" show examples using the NOP 
  5426. instruction. 
  5427.  
  5428.  
  5429. PILOT.CMD
  5430.  
  5431. /* Example: steering a course                           */
  5432.  
  5433. Say "Where is the harbor?"
  5434. pull where
  5435. select
  5436.    when where = "AHEAD" then nop
  5437.    when where = "PORT BOW" then say "Turn left"
  5438.    when where = "STARBOARD BOW" then say "Turn right"
  5439.    otherwise say "Not understood"
  5440. end
  5441.  
  5442.  
  5443. TRUCKER . CMD
  5444.  
  5445. /* Example: using NOP to simplify the presentation of   */
  5446. /* a set of conditions.                                 */
  5447.  
  5448. If gas = "FULL" & oil = "SAFE" & window = "CLEAN"
  5449. then nop
  5450. else say "Find a gas station!"
  5451.  
  5452.  
  5453. ΓòÉΓòÉΓòÉ 11.2.2. ITERATE Instruction ΓòÉΓòÉΓòÉ
  5454.  
  5455. To bypass all remaining instructions in the loop and test the ending 
  5456. conditions, use the ITERATE instruction.  Similar to LEAVE, ITERATE can be 
  5457. introduced by a THEN or ELSE keyword.  Instead of leaving the loop altogether, 
  5458. REXX proceeds with the operations usually done at the bottom of the loop.  If 
  5459. an UNTIL condition is specified, it is tested; if a counter is specified, it is 
  5460. incremented and tested; and if a WHILE condition is specified, it is tested. 
  5461.  
  5462. If tests indicate that the loop is still active, then normal processing 
  5463. continues from the top of the loop.  For example: 
  5464.  
  5465. DO j = 1 to limit by delta
  5466.    instruction1
  5467.    instruction2
  5468.    if condition
  5469.    then do
  5470.       instruction3
  5471.       instruction4
  5472.       ITERATE j
  5473.    end
  5474.    instruction5
  5475.    instruction6
  5476. END
  5477.  
  5478. The following flowchart shows the program flow. 
  5479.  
  5480.  
  5481. ΓòÉΓòÉΓòÉ 11.2.3. Compound DO Instructions ΓòÉΓòÉΓòÉ
  5482.  
  5483. You can combine one repetitive phrase and one conditional phrase in a single DO 
  5484. instruction.  You should know where in the loop the counters are updated and 
  5485. where the tests for leaving the loop are made (see Conditional Loops). 
  5486.  
  5487. Compound DO instructions can do a lot of useful work.  Figure "POSN.CMD" shows 
  5488. an example of how a simplified version of the POS() function may be implemented 
  5489. as a REXX function. 
  5490.  
  5491.  
  5492. POSN.CMD
  5493.  
  5494. /* Example: the POSN() function is similar to the       */
  5495. /* POS(), except that the third argument ("start")      */
  5496. /* is not allowed                                       */
  5497.  
  5498. if arg() \= 2
  5499. then return               /* wrong number of arguments  */
  5500.  
  5501. if arg(1,omitted)
  5502. then return               /* argument was omitted       */
  5503.  
  5504. parse arg needle,haystack
  5505.  
  5506. last = length(haystack),  /* compute the rightmost      */
  5507.        -length(needle)+1  /* position that needle could */
  5508.                           /* be found in                */
  5509.  
  5510. do result = 1 to last,    /* Search for needle          */
  5511.    until substr(haystack,result,length(needle)) = needle
  5512. end
  5513. if result > last then result = 0
  5514. return result
  5515.  
  5516.  
  5517. ΓòÉΓòÉΓòÉ 11.2.4. Nested Loops ΓòÉΓòÉΓòÉ
  5518.  
  5519. Sometimes a program is constructed of loops within loops.  When you leave a 
  5520. loop, you may need to specify which loop you want to leave.  To do this, give a 
  5521. DO loop a name (specify a counter in the DO instruction).  If the loop does not 
  5522. contain a counter already, create one.  For example: 
  5523.  
  5524. DO outer = 1
  5525. .
  5526. .
  5527. .
  5528. END
  5529.  
  5530. This is the same, for all practical purposes, as DO FOREVER. In the previous 
  5531. example, outer is the counter for the loop. To leave a specific loop, put the 
  5532. name of its counter after the keyword LEAVE.  For example: 
  5533.  
  5534. DO outer = 1
  5535. .
  5536. .
  5537. .
  5538.    do until datatype(answer,WHOLE)
  5539.       say "Type a number. ",
  5540.           "When you have no more data, enter a blank line"
  5541.       pull answer
  5542.       if answer = "" then leave outer
  5543.    end
  5544. .
  5545. .
  5546. .
  5547.    /* process answer */
  5548. end
  5549. /* come here when there is no more data */
  5550.  
  5551.  
  5552. ΓòÉΓòÉΓòÉ 12. Program Structure ΓòÉΓòÉΓòÉ
  5553.  
  5554. This chapter discusses a different type of program-control-using instructions 
  5555. that run one program from within another.  Using these subsidiary programs or 
  5556. subroutines can actually make programming easier. 
  5557.  
  5558.  
  5559. ΓòÉΓòÉΓòÉ 12.1. Basics ΓòÉΓòÉΓòÉ
  5560.  
  5561.      In this chapter: Basics 
  5562.  
  5563.      o Subroutines 
  5564.      o External subroutines 
  5565.      o Using arguments 
  5566.      o Subroutines and data. 
  5567.  
  5568.  
  5569. ΓòÉΓòÉΓòÉ 12.1.1. Subroutines ΓòÉΓòÉΓòÉ
  5570.  
  5571. A subroutine is a segment of program code that can be called from more than one 
  5572. place in your main program.  Subroutines can reside in the same file as the 
  5573. main program or they can reside in a separate REXX program file.  The following 
  5574. diagram shows a subroutine that is in the same file as the main program. 
  5575.  
  5576. A CALL instruction tells REXX to look through the program until it finds a 
  5577. corresponding label, a clause that marks the start of the subroutine. 
  5578.  
  5579. REXX processes the instructions following the label until it encounters a 
  5580. RETURN instruction.  RETURN tells REXX to resume processing in the main 
  5581. program, beginning with the instruction immediately after the CALL. 
  5582.  
  5583. A subroutine can be called from more than one place in a program. That is, 
  5584. several CALL instructions can use the same subroutine. The subroutine always 
  5585. returns processing to the clause following the last CALL instruction. 
  5586.  
  5587. Each CALL instruction can supply data, called arguments, which the subroutine 
  5588. can use when called.  In the subroutine, you can determine the data supplied by 
  5589. using the ARG() function or the ARG instruction. 
  5590.  
  5591.  
  5592. ΓòÉΓòÉΓòÉ 12.1.1.1. CALL Instruction ΓòÉΓòÉΓòÉ
  5593.  
  5594. Figure "SQUARIT.CMD" shows an example of how to have REXX run a subroutine at a 
  5595. particular point in a program: 
  5596.  
  5597. CALL subname [argument1, argument2 ...]
  5598. where: 
  5599.  
  5600.  subname            is the name of the subroutine.  REXX searches first for the 
  5601.                     corresponding label in your program.  A label consists of a 
  5602.                     symbol followed by a colon (:). For example: 
  5603.  
  5604.                                         subname:
  5605.  
  5606.                     If no such label is found, REXX looks for a built-in 
  5607.                     function or program file named subname.  (See the search 
  5608.                     order in Comparing Subroutines and Functions.) 
  5609.  
  5610.  argument           is any data that you want passed to the subroutine.  The 
  5611.                     subroutine can collect the arguments with the ARG 
  5612.                     instruction or the ARG() function. 
  5613.  
  5614.  Figure "SQUARIT.CMD" shows a program that displays the squares of numbers from 
  5615.  1 to 5.  The calculation is performed in a subroutine. 
  5616.  
  5617.  
  5618.   SQUARIT.CMD
  5619.  
  5620.   /* Simple example of using CALL instruction */
  5621.   trace r                            /* we turn on tracing    */
  5622.                                      /* so you can see the    */
  5623.                                      /* subroutine in action  */
  5624.  
  5625.   say "This is the main program"       /* remark 1            */
  5626.   do num = 1 to 5
  5627.      call square                       /* calls subroutine    */
  5628.      say "Back in the main program."   /* remark 3            */
  5629.      say num "squared is" num2         /* display result      */
  5630.   end
  5631.   exit                                 /* end the program     */
  5632.  
  5633.   square:                        /* subroutine begins   */
  5634.   say "This is the subroutine."        /* remark 2            */
  5635.   num2 = num * num                     /* calculate square    */
  5636.   return                               /* resume main program */
  5637.  
  5638.  Try this program without the TRACE instruction and extra remarks. 
  5639.  
  5640.  
  5641. ΓòÉΓòÉΓòÉ 12.1.1.2. RETURN Instruction ΓòÉΓòÉΓòÉ
  5642.  
  5643. The RETURN instruction takes processing back to the main routine. Processing 
  5644. continues with the instruction following the last CALL. The full form of the 
  5645. instruction is: 
  5646.  
  5647. RETURN [expression]
  5648.  
  5649. where, if expression is specified, it is assigned to the REXX special variable, 
  5650. RESULT, which can then be used by the main program. But, if expression is 
  5651. omitted, RESULT is dropped and not assigned a value.  Its value is its own 
  5652. name-RESULT. 
  5653.  
  5654.  
  5655. ΓòÉΓòÉΓòÉ 12.1.1.3. Test Yourself ΓòÉΓòÉΓòÉ
  5656.  
  5657. Figure "RACEGAME.CMD" shows a program that simulates a children's race game 
  5658. that used to be played with dice.  Write the subroutine TELL to tell who is 
  5659. winning. 
  5660.  
  5661.  
  5662. RACEGAME.CMD
  5663.  
  5664. /* Example of a subroutine: a child's race game     */
  5665. a = 0                    /* Arthur starts from zero */
  5666. b = 3                /* Barry gets a headstart of 3 */
  5667. do 15
  5668.    a = a + random(1,6)   /* Arthur gets first turn  */
  5669.    call tell             /* Who's ahead now         */
  5670.    b = b + random(1,6)  /* Now it is Barry's turn   */
  5671.    call tell             /* Who's ahead now         */
  5672. end
  5673. exit                     /* End of main program     */
  5674.  
  5675. Copy the main program and your subroutine into another file and test your 
  5676. program. 
  5677.  
  5678.  
  5679. ΓòÉΓòÉΓòÉ 12.1.1.3.1. Answer ΓòÉΓòÉΓòÉ
  5680.  
  5681. Figure "RACEGAME.CMD Subroutine" is an example of a possible solution. 
  5682.  
  5683.  
  5684. RACEGAME.CMD Subroutine
  5685.  
  5686. /*--------------------------------------------------*/
  5687. /* Subroutine to display the position               */
  5688. /* ==================================               */
  5689. /* INPUT: a (Arthur's score)                        */
  5690. /*        b (Barry's score)                         */
  5691. /* RESULT: displayed on user's screen               */
  5692. /*--------------------------------------------------*/
  5693. TELL:
  5694. values = "Arthur =" a ";  Barry =" b "; "
  5695. select
  5696.    when a > b then say values "Arthur is ahead"
  5697.    when b > a then say values "Barry is ahead"
  5698.    otherwise say values "Neck and neck!"
  5699. end
  5700. return
  5701.  
  5702. In this sample solution, there are no arguments on the CALL instruction. 
  5703. Nevertheless, a person reading the program needs to know what data the 
  5704. subroutine is using. 
  5705.  
  5706. A well-designed subroutine operates on a clearly defined set of data.  To make 
  5707. your program more readable, you should define this data in comments at the 
  5708. beginning of the subroutine. 
  5709.  
  5710.  
  5711. ΓòÉΓòÉΓòÉ 12.1.2. External Subroutines ΓòÉΓòÉΓòÉ
  5712.  
  5713. The subroutines that have been discussed are internal routines. Subroutines can 
  5714. also exist as a separate REXX program file. The following diagram shows a 
  5715. subroutine that is a separate REXX program file. 
  5716.  
  5717. In an external routine, the variables belonging to the calling routine are not 
  5718. available to the subroutine.  Therefore, data: 
  5719.  
  5720.  o Must be formally passed to the subroutine as arguments to the CALL 
  5721.    instruction. 
  5722.  
  5723.  o Can only be returned to the caller by assigning a value to the variable 
  5724.    RESULT, using the RETURN instruction.  If necessary, the calling routine can 
  5725.    then parse the RESULT value into a number of variables. 
  5726.  
  5727.  Note:  The variables of the CALL are available to an internal subroutine 
  5728.  unless you use the PROCEDURE instruction (see PROCEDURE Instruction). :enote. 
  5729.  
  5730.  
  5731. ΓòÉΓòÉΓòÉ 12.1.3. Using Arguments ΓòÉΓòÉΓòÉ
  5732.  
  5733. In the example shown in Figure "ADD.CMD", type the program name, add, followed 
  5734. by the two numbers to be added.  The numbers are assigned to variables first 
  5735. and second by the ARG instruction.  Information given to a program in this 
  5736. manner is called an argument.  That is, the numbers given ADD.CMD to add 
  5737. together are arguments to the startup command, ADD. 
  5738.  
  5739.  
  5740. ADD.CMD
  5741.  
  5742. /* the sum of two numbers, this time    */
  5743. /* typed at the command prompt          */
  5744. arg first second     /*collects entries */
  5745. say "The sum is" first + second
  5746.  
  5747. In much the same way, you can provide a subroutine with the needed information 
  5748. by arguments passed by the CALL instruction that starts the subroutine.  To 
  5749. assign the arguments to variables, you can use the ARG instruction or the PARSE 
  5750. ARG instruction. 
  5751.  
  5752. The difference is: 
  5753.  
  5754.  ARG            assigns argument data to variables, translating lowercase 
  5755.                 letters into uppercase. In this way, ARG is similar to PULL. 
  5756.                 ARG is the short form of the instruction PARSE UPPER ARG. 
  5757.  
  5758.  PARSE ARG      assigns the information to variables exactly as it is entered, 
  5759.                 with no translation to uppercase. 
  5760.  
  5761.  For example, here is a CALL instruction: 
  5762.  
  5763.   CALL BAKE "white", "fresh", "sweet", "dessert"
  5764.  
  5765.  If you want the results of these four expressions assigned to flour, butter, 
  5766.  sugar, and cookies, you would write: 
  5767.  
  5768.   PARSE ARG flour, butter, sugar, cookies
  5769.  
  5770.  But, if you wanted the four arguments to be translated to uppercase, you would 
  5771.  write: 
  5772.  
  5773.   ARG flour, butter, sugar, cookies
  5774.  
  5775.  As there are commas between the expressions in the CALL instruction, there are 
  5776.  likewise commas between the symbols in the PARSE ARG or ARG instruction when 
  5777.  it is used in this way.  For example, the instruction: 
  5778.  
  5779.   CALL words "a string of words",5
  5780.  might be parsed using: 
  5781.  
  5782.   WORDS:
  5783.   PARSE ARG first second third fourth rest, number
  5784.  
  5785.  The result would be that: 
  5786.  
  5787.       first        gets a
  5788.       second       gets string
  5789.       third        gets of
  5790.       fourth       gets words
  5791.       rest         gets (blank)
  5792.       number       gets 5
  5793.  
  5794.  Figure "MAKEBOX.CMD" is an example of the main program, that shows how: 
  5795.  
  5796.  o CALL passes arguments to a subroutine. 
  5797.  o ARG assigns the argument values to variables. 
  5798.  o RETURN assigns a value to the RESULT variable. 
  5799.  o RESULT is used by the main program. 
  5800.  
  5801.  
  5802.   MAKEBOX . CMD
  5803.  
  5804.   /* Main program to gather input and display result     */
  5805.   Say "To calculate the material you need to make a box,"
  5806.  
  5807.   /* Input the dimensions of the desired box (meters)    */
  5808.  
  5809.   say "type the desired length of the box:"
  5810.   pull length
  5811.  
  5812.   say "type the desired width:"
  5813.   pull width
  5814.  
  5815.   say "type the height:"
  5816.   pull height
  5817.  
  5818.   /* call the subroutine program BOX.CMD  with arguments */
  5819.  
  5820.   CALL box length, width, height
  5821.  
  5822.   /* report the returned value from the RESULT variable   */
  5823.   SAY 'Material required =' RESULT 'square meters'
  5824.   exit
  5825.  
  5826.  Figure "BOX.CMD" is the subroutine program called by MAKEBOX.CMD. 
  5827.  
  5828.  
  5829.   BOX.CMD
  5830.  
  5831.   /* computes area of a box */
  5832.   /* including a lid        */
  5833.  
  5834.   ARG long, wide, high
  5835.  
  5836.   /* total area is base and top plus  */
  5837.   /* short sides plus long sides      */
  5838.  
  5839.   area = 2*(long*wide) + 2*(wide*high) + 2*(long*high)
  5840.  
  5841.   RETURN area
  5842.  
  5843.  When you run MAKEBOX, the data you enter is gathered by the PULL instructions 
  5844.  and then passed, as arguments of CALL, to BOX.CMD.  The calculation of the 
  5845.  area of the box is then passed back to MAKEBOX.CMD by the RETURN instruction 
  5846.  to the variable RESULT. Processing of MAKEBOX then resumes with the next 
  5847.  clause following the CALL. 
  5848.  
  5849.  The following diagram shows the flow of data between the two programs. 
  5850.  
  5851.         MAKEBOX.CMD
  5852.         ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ╤Ç
  5853.         Γöé                                                            Γöé
  5854.         Γöé /* Main program to gather input and display result     */  Γöé
  5855.         Γöé say "To calculate the material you need to make a box,"    Γöé
  5856.         Γöé                                                            Γöé
  5857.         Γöé say "type the desired length of the box:"                  Γöé
  5858.         Γöé pull length                                                Γöé
  5859.         Γöé .                                                          Γöé
  5860.         Γöé .                                                          Γöé
  5861.         Γöé .                                                          Γöé
  5862.         Γöé                                                            Γöé
  5863.         Γöé CALL box length, width, height                             Γöé
  5864.         Γöé             Γöé      Γöé       Γöé                               Γöé
  5865.         Γöé             ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ╤Ç       Γöé
  5866.     ΓöÇΓöÇΓöÇ╨ÆΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ╤Ç                      Γöé       Γöé
  5867.     Γöé   Γöé                             ╤è                      Γöé       Γöé
  5868.     Γöé  ╨Æ SAY 'Material required =' RESULT 'square meters'  Γöé       Γöé
  5869.     Γöé  ΓöéΓöé                                                    Γöé       Γöé
  5870.     Γöé  ΓöéΓöé  exit                                              Γöé       Γöé
  5871.     Γöé  ΓöéΓöé                                                    Γöé       Γöé
  5872.     Γöé  ΓöéΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ╨ÆΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  5873.     Γöé  Γöé                                                     Γöé
  5874.     Γöé  Γöé                                                     Γöé
  5875.     Γöé  Γöé                                                     Γöé
  5876.     Γöé  Γöé     ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ╨ÆΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ╤Ç
  5877.     Γöé  Γöé     Γöé /* Computes area of a box, including a lid */ Γöé       Γöé
  5878.     Γöé  Γöé     Γöé                                               Γöé       Γöé
  5879.     Γöé  Γöé     Γöé       ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ       Γöé
  5880.     Γöé  Γöé     Γöé       ╤è     ╤è     ╤è                                   Γöé
  5881.     Γöé  Γöé     Γöé ARG long, wide, high                                  Γöé
  5882.     Γöé  Γöé     Γöé                                                       Γöé
  5883.     Γöé  Γöé     Γöé area = 2*(long*wide) + 2*(wide*high) + 2*(long*high)  Γöé
  5884.     Γöé  Γöé     Γöé                                                       Γöé
  5885.     Γöé  ΓöÇΓöÇΓöÇΓöÇΓöÇ╨ÆΓöÇRETURN area                                           Γöé
  5886.     Γöé        Γöé         Γöé                                             Γöé
  5887.     ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ╨ÆΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ                                             Γöé
  5888.              ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  5889.  
  5890.                                                                BOX.CMD
  5891.  
  5892.  If program variables are referred to by the same names both outside and inside 
  5893.  an internal routine (a routine that exists in the same file as the CALL 
  5894.  instruction), then it is not necessary to include them as arguments on the 
  5895.  CALL or ARG instructions. However, not including them could make it more 
  5896.  difficult for a user reading your program to understand what your subroutine 
  5897.  does.  So it is a good idea to give a list of the arguments in the comments 
  5898.  that introduce the subroutine. 
  5899.  
  5900.  
  5901. ΓòÉΓòÉΓòÉ 12.1.3.1. ARG() Function ΓòÉΓòÉΓòÉ
  5902.  
  5903. Another way to pass arguments to a subroutine is to use the ARG function. For 
  5904. example: 
  5905.  
  5906. CALL subname [argument1, argument2 ...]
  5907. where: 
  5908.  
  5909.  subname                  is the name of the subroutine. 
  5910.  
  5911.  argument1, argument2,... are expressions.  The value of each is computed and 
  5912.                           can be obtained in the subroutine by using the ARG() 
  5913.                           function. 
  5914.  
  5915.     ARG(1) returns the first argument 
  5916.     ARG(2) returns the second argument 
  5917.     and so on... 
  5918.  
  5919.  You can have up to 20 arguments on a CALL instruction. 
  5920.  
  5921.  Figure "CHEER.CMD" shows an example that calls a subroutine using arguments. 
  5922.  
  5923.  
  5924.   CHEER.CMD
  5925.  
  5926.   /* Example: calling a subroutine with arguments */
  5927.   do 3
  5928.     call triple "R"
  5929.     call triple "E"
  5930.     call triple "X"
  5931.     call triple "X"
  5932.     say
  5933.   end
  5934.   say "R...!"
  5935.   say "E...!"
  5936.   say "X...!"
  5937.   say "X...!"
  5938.   say
  5939.   say "REXX!"
  5940.   exit                             /* end of main program */
  5941.   /*------------------------------------------------------*/
  5942.   /* Subroutine to repeat a shout three times             */
  5943.   /* ========================================             */
  5944.   /* The first argument is displayed on the screen, three */
  5945.   /* times on one line, with suitable punctuation.        */
  5946.   /*------------------------------------------------------*/
  5947.   TRIPLE:
  5948.   say arg(1)",  "arg(1)",  "arg(1)"!"
  5949.   return
  5950.  
  5951.  The following is displayed on the screen when you run the program. 
  5952.  
  5953.   cheer
  5954.   R,  R,  R!
  5955.   E,  E,  E!
  5956.   X,  X,  X!
  5957.   X,  X,  X!
  5958.  
  5959.   R,  R,  R!
  5960.   E,  E,  E!
  5961.   X,  X,  X!
  5962.   X,  X,  X!
  5963.  
  5964.   R,  R,  R!
  5965.   E,  E,  E!
  5966.   X,  X,  X!
  5967.   X,  X,  X!
  5968.  
  5969.   R...!
  5970.   E...!
  5971.   X...!
  5972.   X...!
  5973.  
  5974.   REXX!
  5975.  
  5976.  The EXIT instruction in Figure "CHEER.CMD" stops the main program from running 
  5977.  on into the subroutine. 
  5978.  
  5979.  
  5980. ΓòÉΓòÉΓòÉ 12.1.4. Subroutines and Data ΓòÉΓòÉΓòÉ
  5981.  
  5982. Passing arguments to a subroutine is one form of parsing input information. 
  5983. This is a particularly important concept in REXX. 
  5984.  
  5985. The best starting point for a large program is to study the information that 
  5986. you want REXX to work with.  The next few chapters concentrate on how to 
  5987. analyze and calculate data and how REXX shares information with other programs 
  5988. and devices. 
  5989.  
  5990.  
  5991. ΓòÉΓòÉΓòÉ 12.1.5. Summary ΓòÉΓòÉΓòÉ
  5992.  
  5993. This completes "Basics" in this chapter.  You have learned how to: 
  5994.  
  5995.  o Use subroutines with the CALL and RETURN instructions 
  5996.  o Use subroutines in the same program file as the main program or in a 
  5997.    separate file 
  5998.  o Pass data to a subroutine, using the ARG instruction and the ARG function. 
  5999.  
  6000.  "Advanced Topics" in this chapter discusses advanced elements of program 
  6001.  structure, including: 
  6002.  
  6003.  o Modular programming 
  6004.  o Creating your own functions 
  6005.  o Jumps and condition traps. 
  6006.  
  6007.  To continue with "Basics," go to page 8-1. 
  6008.  
  6009.  
  6010. ΓòÉΓòÉΓòÉ 12.2. Advanced Topics ΓòÉΓòÉΓòÉ
  6011.  
  6012.      In this chapter: Advanced Topics 
  6013.  
  6014.      o Structured programming 
  6015.      o Function calls 
  6016.      o Comparing subroutines and functions 
  6017.      o Jumps 
  6018.      o Condition traps. 
  6019.  
  6020.  
  6021. ΓòÉΓòÉΓòÉ 12.3. Structured Programming ΓòÉΓòÉΓòÉ
  6022.  
  6023. Using the CALL instruction to call a subroutine is part of an approach to 
  6024. programming called structured programming. 
  6025.  
  6026. Experienced programmers rarely write complex programs as a single list of 
  6027. instructions.  Rather, they separate a large job into smaller units called 
  6028. modules.  Then, they create a single main module that calls all the others, 
  6029. either in a specific listed order or by means of control instructions such as 
  6030. IF, SELECT, and DO.  For example: 
  6031.  
  6032.             Main program module              Subroutine modules
  6033.  
  6034.          ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ╤Ç         ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ╤Ç
  6035.          Γöé CALL a ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ a  Γöé                    Γöé
  6036.          Γöé  .                     Γöé         ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  6037.          Γöé  .                     Γöé         ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ╤Ç
  6038.          Γöé CALL b ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ b  Γöé                    Γöé
  6039.          Γöé                        Γöé         ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  6040.          Γöé                        Γöé         ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ╤Ç
  6041.          Γöé                        Γöé ΓöÇΓöÇ c  Γöé                    Γöé
  6042.          Γöé SELECT                 Γöé Γöé       ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  6043.          Γöé    WHEN...THEN CALL c ΓöÇΓöÇΓöÇΓöÿ       ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  6044.          Γöé    WHEN...THEN CALL d ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ d  Γöé                    Γöé
  6045.          Γöé    WHEN...THEN CALL e ΓöÇΓöÇΓöÇΓöÉ       ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  6046.       ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ OTHERWISE SIGNAL q  Γöé Γöé       ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  6047.       Γöé  Γöé END                    Γöé ΓööΓöÇΓöÇ e  Γöé                    Γöé
  6048.       Γöé  Γöé  .                     Γöé         ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  6049.       Γöé  Γöé  .                     Γöé
  6050.       Γöé  Γöé  .                     Γöé
  6051.       Γöé  Γöé DO UNTIL done          Γöé         ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  6052.       Γöé  Γöé   CALL f ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ f  Γöé                    Γöé
  6053.       Γöé  Γöé END                    Γöé         ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  6054.       Γöé  Γöé                        Γöé
  6055.       Γöé  Γöé                        Γöé
  6056.       ΓööΓöÇΓöÇΓöÇq:                     Γöé
  6057.          Γöé EXIT                   Γöé
  6058.          ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  6059.  
  6060. Structured programming helps programmers in the following ways: 
  6061.  
  6062.  o It makes planning a program easier because large projects can be separated 
  6063.    into smaller tasks that are easier to understand. 
  6064.  
  6065.  o It makes the finished program more readable by users.  This is a definite 
  6066.    help when correcting and improving the program.  You can fix and enhance one 
  6067.    module at a time.  Errors are easier to trace, and the overall structure is 
  6068.    clearer. 
  6069.  
  6070.  o As you become more fluent in the REXX language, you become more adept at 
  6071.    defining the work a program can do.  You can define clearly what a module 
  6072.    should do before you write a line of program code.  For example, the program 
  6073.    code you write will have applications beyond the task it was written for.  A 
  6074.    clever routine for sorting a directory might prove useful in another 
  6075.    file-management program. 
  6076.  
  6077.  For more information about structured programming, refer to Program Style. 
  6078.  
  6079.  
  6080. ΓòÉΓòÉΓòÉ 12.3.1. Function Calls ΓòÉΓòÉΓòÉ
  6081.  
  6082. A subroutine can produce a computed result, or return value, that the calling 
  6083. procedure can use.  The RETURN instruction does this (see RETURN Instruction). 
  6084. You have the following options: 
  6085.  
  6086.  o Use CALL to call the subroutine and then get the return value from the 
  6087.    built-in variable RESULT. 
  6088.  
  6089.  o Call the subroutine as a function call, the same way that you call the REXX 
  6090.    built-in functions. 
  6091.  
  6092.  
  6093. ΓòÉΓòÉΓòÉ 12.3.1.1. Creating a Function ΓòÉΓòÉΓòÉ
  6094.  
  6095. A subroutine called by a function call is essentially no different than any 
  6096. other subroutine that returns a value.  That is an important distinction, 
  6097. because the very definition of a function is that it always returns a value, 
  6098. even if that value is a null string. 
  6099.  
  6100. Arguments of the function (the input that goes between the parentheses in the 
  6101. function call), can be read with the ARG instruction or with the ARG function. 
  6102.  
  6103. Since functions always return a value, they are normally used in expressions, 
  6104. such as in a SAY instruction. If you write a function call on a line by itself, 
  6105. the value returned by the function is passed to the system as a command. For 
  6106. example, if you write Word('Now is the time',3), REXX passes 'the' to the 
  6107. system as a command. If you are calling a function but do not need the value 
  6108. returned, call the function as a subroutine. 
  6109.  
  6110. Figure "WORDAVG.CMD" shows a subroutine that calculates and returns the average 
  6111. number of letters per word. 
  6112.  
  6113.  
  6114. WORDAVG.CMD
  6115.  
  6116. /* Returns the average letters per word in an input line */
  6117. arg line                        /* get the line; set TOTAL to 0 */
  6118. total = 0
  6119.  
  6120. do num = 1 until line = ""      /* repeat until LINE is empty,  */
  6121.                                 /* adding 1 to NUM with each    */
  6122.                                 /* iteration                    */
  6123.  
  6124.    parse var line word line     /* take out just the first word */
  6125.                                 /* remaining in LINE            */
  6126.  
  6127.    total = total + length(word) /* add its length to TOTAL      */
  6128.  
  6129.    end                          /* see if LINE is empty yet...  */
  6130.                                 /* if so, the loop ends.
  6131.  
  6132. avg = format(total/num,,0)      /* now, divide TOTAL (letters)  */
  6133.                                 /* by NUM(ber of words) to get  */
  6134.                                 /* the average per word         */
  6135.  
  6136. return avg                      /* return the number AVG        */
  6137.  
  6138. You can also create functions that return non-numeric values, as shown in 
  6139. Figure "DATESTMP.CMD". 
  6140.  
  6141.  
  6142. DATESTMP.CMD
  6143.  
  6144. /* Returns today's date in 'natural language' format */
  6145.  
  6146. /* First, use DATE() function and its options to...        */
  6147. month = date(m)                      /* ...get the month   */
  6148. day = date(w)                        /* ...get the weekday */
  6149. parse value date() with cdate . .    /* ...get the date    */
  6150.  
  6151. /* The RIGHT() function returns the last digit of the date */
  6152. /* so we can add on the proper suffix (similar to the way  */
  6153. /* we used for Figure "MONTH1.CMD".*/
  6154. select
  6155.    when right(cdate,1) = 1 then th = "st"
  6156.    when right(cdate,1) = 2 then th = "nd"
  6157.    when right(cdate,1) = 3 then th = "rd"
  6158.    otherwise th = "th"
  6159. end
  6160.  
  6161. return day"," month cdate||th           /* return the date */
  6162.  
  6163.  
  6164. ΓòÉΓòÉΓòÉ 12.3.2. Comparing Subroutines and Functions ΓòÉΓòÉΓòÉ
  6165.  
  6166. There are differences and similarities between subroutines and functions. 
  6167.  
  6168. The differences are: 
  6169.  
  6170.  o To call a subroutine, you use a CALL instruction: 
  6171.  
  6172.       CALL routine [argument1, ... ]
  6173.  
  6174.    To call a function, you use a function call: 
  6175.  
  6176.       routine([argument1, ... ])
  6177.  
  6178.  o A subroutine need not return a result, but a function must return a result. 
  6179.  
  6180.    In a subroutine, you can write: 
  6181.  
  6182.       RETURN
  6183.  
  6184.    In a function you must at least write: 
  6185.  
  6186.       RETURN ""   /* This returns a null string */
  6187.  
  6188.  o A subroutine sets the value of the special variable RESULT. The result 
  6189.    returned by a function is used in the expression where the function call 
  6190.    appeared. 
  6191.  
  6192.  The similarities are that both: 
  6193.  
  6194.  o Use the ARG and PARSE ARG instructions and the ARG() function for obtaining 
  6195.    the values of their arguments. 
  6196.  
  6197.  o Can be internal (starting with a label in the same file as the CALL 
  6198.    instruction or the function call) or external (located in a different file). 
  6199.  
  6200.  o Have the same search order.  When a call to routine is recognized: 
  6201.  
  6202.      1. REXX first looks for the label routine: in the same file. 
  6203.      2. If no label by that name is found, REXX looks for a built-in function 
  6204.         called routine(). 
  6205.      3. If none of its own functions have that name, REXX looks for an external 
  6206.         routine; that is, a program in a file named routine. 
  6207.  
  6208.  There are many kinds of external routines that REXX can use, including those 
  6209.  written in other languages.  These are made available to REXX through function 
  6210.  packages, which are described in the REXX Reference. 
  6211.  
  6212.  
  6213. ΓòÉΓòÉΓòÉ 12.3.2.1. Using a Call of the Other Kind ΓòÉΓòÉΓòÉ
  6214.  
  6215. There is another similarity between functions and subroutines. Where 
  6216. convenient, programs designed as functions can be called as subroutines.  If 
  6217. they always return a result, programs designed as subroutines can be called as 
  6218. functions. Both, when they are internal, can use the PROCEDURE instruction. 
  6219.  
  6220. You could eliminate the CALL instruction in MAKEBOX.CMD (see Figure 
  6221. "MAKEBOX.CMD") and simply call the subroutine BOX.CMD (see Figure "BOX.CMD") as 
  6222. a function in the final SAY instruction.  For example: 
  6223.  
  6224. say "Material required ="  box(length,width,height) "sq. meters"
  6225.  
  6226. In the following example, the POS() function returns the character position of 
  6227. a substring (needle) within a larger string (haystack). 
  6228.  
  6229. POS(needle,haystack)
  6230.  
  6231. Figure "NEEDLE.CMD" shows an example that is called as a subroutine. 
  6232.  
  6233.  
  6234. NEEDLE.CMD
  6235.  
  6236. /* to remove NEEDLEs from haystack */
  6237. do forever
  6238.    call pos needle,haystack
  6239.    if result = 0
  6240.    then leave
  6241.    else haystack = delstr(haystack,result,length(needle))
  6242. end
  6243.  
  6244. This routine removes every instance of one string within another.  It uses the 
  6245. DELSTR() and LENGTH() functions, which are also built into REXX, and are called 
  6246. here as functions.  In this example: 
  6247.  
  6248.   1. POS(), called as a subroutine, searches in the string stored in haystack 
  6249.      for the first occurrence of the string in needle. 
  6250.  
  6251.   2. That character position (a number) is then assigned to the RESULT 
  6252.      variable.  If no occurrence if found, the loop ends. 
  6253.  
  6254.   3. DELSTR() then removes the needle substring from haystack, deleting from 
  6255.      the RESULT starting position, for the length of needle (determined by the 
  6256.      LENGTH() function). 
  6257.  
  6258.  
  6259. ΓòÉΓòÉΓòÉ 12.3.3. Jumps ΓòÉΓòÉΓòÉ
  6260.  
  6261. A jump shifts REXX processing to a different point in the program.  After the 
  6262. jump, the program does not automatically return to the calling instruction. 
  6263.  
  6264.  
  6265. ΓòÉΓòÉΓòÉ 12.3.3.1. SIGNAL Instruction ΓòÉΓòÉΓòÉ
  6266.  
  6267. The SIGNAL instruction can jump (transfer control) to another part of your 
  6268. program.  SIGNAL is a one-way path.  When REXX encounters a SIGNAL instruction 
  6269. in the middle of a program, any SELECT constructs or DO loops it has been 
  6270. processing are abandoned. SIGNAL cannot be used to jump back into or jump 
  6271. around within a DO loop.  This means that you should use SIGNAL only to bring 
  6272. your program to an exit.  For other purposes, it is better to manipulate 
  6273. program control using IF, SELECT, or DO. 
  6274.  
  6275. To tell REXX to go to another part of the same file, use the instruction: 
  6276.  
  6277. SIGNAL symbol
  6278.  
  6279. This causes a jump to the specified label, the symbol followed by a colon (:). 
  6280. REXX searches from the top of the file for the clause symbol: and processing 
  6281. continues from there. 
  6282.  
  6283. The SIGNAL instruction always stores its line number in the REXX special 
  6284. variable SIGL. 
  6285.  
  6286. This is an example of an abnormal end to a program using SIGNAL. 
  6287.  
  6288. SIGNAL abend
  6289. .
  6290. .
  6291. .
  6292. EXIT                            /* end of ordinary code */
  6293. /*------------------------------------------------------*/
  6294. /* This code handles abnormal ends                      */
  6295. /*------------------------------------------------------*/
  6296. ABEND:
  6297. say "Abnormal end signalled at line" sigl,
  6298.  ||".  Cannot continue."
  6299. exit
  6300.  
  6301. The first EXIT instruction is there to stop the normal program from running on 
  6302. into the abend: (abnormal end) routine. 
  6303.  
  6304. SIGNAL is not a go to statement similar to the BASIC instruction GOTO, because 
  6305. SIGNAL causes the logic of other control structures to be abandoned. The 
  6306. concept of go to does not really apply to a structured language such as REXX. 
  6307. Most tasks or routines that are to be performed according to some condition are 
  6308. better handled as subroutines.  They are easier to read that way, and they are 
  6309. easier to correct. 
  6310.  
  6311. The exception is when you use SIGNAL to call an exit routine.  This is a 
  6312. specific application of SIGNAL, to act as a detector to bring a program to an 
  6313. end whenever a specific condition occurs.  In other words, you can set a trap. 
  6314.  
  6315.  
  6316. ΓòÉΓòÉΓòÉ 12.3.4. Condition Traps ΓòÉΓòÉΓòÉ
  6317.  
  6318. The SIGNAL instruction by itself initiates a jump from one particular point in 
  6319. a program (the SIGNAL clause) to another, indicated by a label. 
  6320.  
  6321. Another way to use SIGNAL is with the keyword ON and the name of a specific 
  6322. condition that you want REXX to test for.  Whenever the specified condition is 
  6323. detected, processing immediately jumps to the corresponding label.  For 
  6324. example: 
  6325.  
  6326. SIGNAL ON condition [NAME trapname]
  6327.  
  6328. When a SIGNAL ON instruction is in effect (enabled) and the given condition 
  6329. occurs, REXX jumps to a label that can be either: 
  6330.  
  6331.  o The name of the condition itself (the default) 
  6332.  
  6333.  o An optional trapname, specified by the NAME keyword. 
  6334.  
  6335.  This trap remains enabled for the rest of the program or until issued the 
  6336.  instruction: 
  6337.  
  6338.   SIGNAL OFF condition
  6339.  
  6340.  These are the conditions that can be trapped by SIGNAL ON instruction: 
  6341.  
  6342.  ERROR              Sets a trap to a subroutine with the label ERROR:. An ERROR 
  6343.                     condition occurs whenever a REXX program issues a command 
  6344.                     (a string expression passed to the environment) that 
  6345.                     results in an error in the default environment. This 
  6346.                     includes commands that produce nonzero return codes and 
  6347.                     commands that are unknown to the system. (This includes 
  6348.                     failures only when a FAILURE condition trap is not set.) 
  6349.  
  6350.  FAILURE            Sets a trap to a subroutine with the label FAILURE:. A 
  6351.                     FAILURE condition occurs whenever a REXX program issues a 
  6352.                     command to the default environment and the system 
  6353.                     encounters a severe error preventing it from processing the 
  6354.                     command. 
  6355.  
  6356.                     Refer to Trapping Command Errors for more information. 
  6357.  
  6358.  NOTREADY           Sets a trap to a subroutine with the label NOTREADY:. A 
  6359.                     NOTREADY condition occurs whenever an error occurs during 
  6360.                     an input or output operation. (Refer to Input and Output, 
  6361.                     for more information.) 
  6362.  
  6363.  NOVALUE            Sets a trap to a subroutine with the label NOVALUE:. A 
  6364.                     NOVALUE condition occurs whenever a symbol that could be 
  6365.                     the name of a variable is encountered and the variable does 
  6366.                     not exist. This can be especially useful for finding 
  6367.                     misspelled variable names. 
  6368.  
  6369.  SYNTAX             Sets a trap to a subroutine with the label SYNTAX:. A 
  6370.                     SYNTAX condition occurs whenever a REXX syntax error is 
  6371.                     detected. This is especially useful for debugging programs 
  6372.                     in which syntax errors occur, but the user is unable to 
  6373.                     provide an accurate description of the problem. 
  6374.  
  6375.  If the trap you have set with SIGNAL ON detects one of the previous 
  6376.  conditions: 
  6377.  
  6378.   1. REXX stops whatever instruction it is processing. 
  6379.  
  6380.   2. The line number of that instruction is assigned to the special variable 
  6381.      SIGL. 
  6382.  
  6383.   3. The condition is disabled; it is set to SIGNAL OFF. 
  6384.  
  6385.   4. Processing then jumps (as in a normal SIGNAL) to the appropriate label (to 
  6386.      trapname:, if given; otherwise, to condition:). 
  6387.  
  6388.  
  6389. ΓòÉΓòÉΓòÉ 12.3.5. Using CALL ON ΓòÉΓòÉΓòÉ
  6390.  
  6391. In certain instances, it is possible to resume program processing after a 
  6392. condition is trapped.  In such an instance, use the instruction: 
  6393.  
  6394. CALL ON condition [NAME trapname]
  6395.  
  6396. See Trapping Command Errors for an example comparing the CALL ON and SIGNAL ON 
  6397. instructions. 
  6398.  
  6399.  
  6400. ΓòÉΓòÉΓòÉ 12.3.5.1. Useful Functions ΓòÉΓòÉΓòÉ
  6401.  
  6402. The following two functions you may find useful: 
  6403.  
  6404.  CONDITION()    Returns the keyword (CALL or SIGNAL) used to trap the 
  6405.                 condition. Used with its options, CONDITION() can also supply 
  6406.                 the name of the trapped condition (for example, ERROR), its 
  6407.                 status (ON, OFF, or DELAY), or an associated description. 
  6408.  
  6409.  VALUE()        Returns or sets the value of a variable whose name may be a 
  6410.                 string expression. VALUE() does not trigger a NOVALUE 
  6411.                 condition. 
  6412.  
  6413.  For more information about these instructions and functions, refer to 
  6414.  "Conditions and Condition Traps" in the REXX Reference. 
  6415.  
  6416.  
  6417. ΓòÉΓòÉΓòÉ 13. Parsing ΓòÉΓòÉΓòÉ
  6418.  
  6419. Parsing is a way of analyzing information for your program to use. It is one of 
  6420. the most powerful and practical features of the REXX language. You may have 
  6421. noticed that it has already been used in many examples. This chapter discusses 
  6422. these ideas and examines the parsing options one by one. 
  6423.  
  6424. Parsing is separating input data and assigning it to one or more variables. 
  6425. Some examples of sources of the input data are: 
  6426.  
  6427.  o The keyboard-more specifically, any data a user types in while a program is 
  6428.    running 
  6429.  
  6430.  o An input parameter-an option typed after the command that starts a program 
  6431.  
  6432.  o An external data source-such as a queue or a disk file. 
  6433.  
  6434.  
  6435. ΓòÉΓòÉΓòÉ 13.1. Basics ΓòÉΓòÉΓòÉ
  6436.  
  6437.      In this chapter: Basics 
  6438.  
  6439.      o Conversations 
  6440.      o Parsing variables and expressions 
  6441.      o Specialties. 
  6442.  
  6443.  
  6444. ΓòÉΓòÉΓòÉ 13.1.1. Conversations ΓòÉΓòÉΓòÉ
  6445.  
  6446. The most common source of input data is the person using the program. The 
  6447. following is a review of the instructions you use to converse with the user of 
  6448. your program-that is, to allow that person to direct the program's processing. 
  6449.  
  6450.  
  6451. ΓòÉΓòÉΓòÉ 13.1.1.1. Prompting the User for Input ΓòÉΓòÉΓòÉ
  6452.  
  6453. To display information on the screen, use SAY expression. The expression is 
  6454. evaluated and the result is displayed as a new line on the screen.  For 
  6455. example, say 3 * 4 "= twelve" causes the following to be displayed on the 
  6456. screen. 
  6457.  
  6458. 12 = twelve
  6459.  
  6460. If you want to display a clause that occupies more than one line in your 
  6461. program, use a comma at the end of a line to indicate that the expression 
  6462. continues on the next line.  For example, the instruction: 
  6463.  
  6464. say "What can not be done today, will have to be put off",
  6465.     "until tomorrow."
  6466. causes the following to be displayed on the screen: 
  6467.  
  6468. What can not be done today, will have to be put off until tomorrow.
  6469.  
  6470. The continuation comma is replaced by a blank when the expression is displayed. 
  6471. Remember that the continuation comma cannot be enclosed in quotes or REXX will 
  6472. consider it part of the string. 
  6473.  
  6474. Having asked the user a question using SAY, you can collect the answer using 
  6475. PULL.  When pull symbol is processed, the program pauses for the user to type 
  6476. data on the command line and press the Enter key. Whatever the user types is 
  6477. translated to uppercase and then assigned to the variable symbol. 
  6478.  
  6479. The PULL instruction is a short version of the instruction PARSE UPPER PULL, 
  6480. which converts lowercase letters in the user input to uppercase.  The program 
  6481. recognizes a user's response whether it is in uppercase, lowercase, or mixed 
  6482. case.  To get the data as it is, without this conversion, use the form: 
  6483.  
  6484. PARSE PULL symbol
  6485.  
  6486. Figure "CHITCHAT.CMD" shows an example that uses both PULL and PARSE PULL. 
  6487.  
  6488.  
  6489. CHITCHAT.CMD
  6490.  
  6491. /* Another conversation */
  6492. say "Hello!  What is your name?"
  6493. parse pull name
  6494. say "Say," name", are you going to the party?"
  6495. pull answer
  6496. if answer = "YES"
  6497. then say "Good.  See you there!"
  6498.  
  6499. The user's name is displayed exactly as it was typed, but answer is translated 
  6500. to uppercase.  This simplifies the program by ensuring that the same action is 
  6501. taken regardless of the way the user types the word yes. 
  6502.  
  6503.  
  6504. ΓòÉΓòÉΓòÉ 13.1.1.2. Test Yourself ΓòÉΓòÉΓòÉ
  6505.  
  6506.   1. Figure "RIDDLE.CMD" shows a program that asks a question. 
  6507.  
  6508.  
  6509.           RIDDLE.CMD
  6510.  
  6511.           /* Simple question (?) */
  6512.           say "Mary, Mary, quite contrary"
  6513.           say "How many letters in that?"
  6514.           pull ans
  6515.           if ans = length(that)
  6516.           then say "Quite right!"
  6517.           else say "Oh!"
  6518.  
  6519.      What is displayed on the screen, if the user responds: 
  6520.  
  6521.     o 21 
  6522.     o 4 
  6523.     o Four. 
  6524.  
  6525.   2. What is displayed on the screen when you run the program shown in Figure 
  6526.      "NOAH.CMD"? 
  6527.  
  6528.  
  6529.           NOAH.CMD
  6530.  
  6531.           /* Example: expressions that continue for more      */
  6532.           /* than one line.                                   */
  6533.           x = 3
  6534.           say "x =" x
  6535.           say
  6536.           say "Ham,",
  6537.               "Shem",
  6538.               "and Japheth"
  6539.           say "Silly"
  6540.               "Billy"
  6541.  
  6542.   3. Create a file called PULLIN.CMD, type the program shown in Figure 
  6543.      "PULLIN.CMD", and try to run the program. 
  6544.  
  6545.  
  6546.           PULLIN.CMD
  6547.  
  6548.           /* Example: appending input, using PULL,            */
  6549.           /* to a REXX variable                               */
  6550.           text = ""
  6551.           do until input = "QUIT"
  6552.              say "Text so far is:"
  6553.              say text
  6554.              say "Would you like to add to that?",
  6555.                  " If so, type your message.",
  6556.                  " If not, type QUIT."
  6557.              pull input
  6558.              text = text||input
  6559.           end
  6560.  
  6561.      Did the program run correctly?  If not, study the error messages and make 
  6562.      sure you copied everything correctly.  Notice that: 
  6563.  
  6564.     o When you run the program, everything you type is changed to uppercase 
  6565.       letters. 
  6566.  
  6567.     o There are not any blanks between the old text and the new input. 
  6568.  
  6569.   4. Change  pull input to parse pull input. Change the concatenation operator 
  6570.      "||" to a single blank, then try the program again. On the OS/2 operating 
  6571.      system, | can also be used as the concatenation operator.  See Basic 
  6572.      Operators for additional information. 
  6573.  
  6574.      Notice that: 
  6575.  
  6576.     o Your input does not get changed to uppercase. 
  6577.  
  6578.     o There is always one blank between the old text and the new input. 
  6579.  
  6580.     o You cannot exit the program by typing quit, but you can exit by typing 
  6581.       QUIT. 
  6582.  
  6583.  
  6584. ΓòÉΓòÉΓòÉ 13.1.1.2.1. Answers: ΓòÉΓòÉΓòÉ
  6585.  
  6586.   1. This is displayed on the screen: 
  6587.  
  6588.     o Oh! 
  6589.     o Quite right! 
  6590.     o Oh! 
  6591.  
  6592.   2. This is displayed on the screen: 
  6593.  
  6594.           [C:\]noah
  6595.           x = 3
  6596.  
  6597.           Ham, Shem and Japheth
  6598.           Silly
  6599.  
  6600.           [C:\]BILLY
  6601.           SYS1041: The name specified is not recognized as an
  6602.           internal or external command, operable program or batch file.
  6603.           [C:\]
  6604.  
  6605.      Because there is no comma after Silly, Billy is treated as a command. If 
  6606.      no such command exists, then the OS/2 program issues an error message. 
  6607.  
  6608.  
  6609. ΓòÉΓòÉΓòÉ 13.1.1.3. Getting Data When the Program Starts ΓòÉΓòÉΓòÉ
  6610.  
  6611. When you want to run your program, type its file name at the command prompt. 
  6612. This can be followed by information for the program to use in the form of 
  6613. arguments.  To use these arguments in the program, use the ARG instruction. 
  6614. ARG parses command arguments in the same way that PULL parses data from the 
  6615. keyboard, except that the first word typed (the name of the program) is 
  6616. ignored. 
  6617.  
  6618. Figure "PHONE.CMD" shows an example of how a parsed argument can be used in a 
  6619. SELECT instruction. 
  6620.  
  6621.  
  6622. PHONE.CMD
  6623.  
  6624. /* telephone tickler: displays the phone number */
  6625. /* of a person whose NAME is given as the       */
  6626. /* argument; e.g., the command "phone anne"     */
  6627. /* displays "ANNE'S NUMBER IS 555-3434"         */
  6628.  
  6629. arg name                        /* get the name */
  6630.  
  6631. select
  6632.    when name = "WILLIAM"  then
  6633.       number = "555-1212"
  6634.    when name = "ANNE"     then
  6635.       number = "555-3434"
  6636.    when name = "LOUISE"   then
  6637.       number = "555-5656"
  6638.    when name = "STEVE"    then
  6639.       number = "555-7878"
  6640.    when name = "HELEN"    then
  6641.       number = "555-9090"
  6642.  
  6643.    otherwise
  6644.       say "I do not have that number."
  6645.       exit
  6646. end
  6647.  
  6648. say name||"'S NUMBER IS" number||"."
  6649. exit
  6650.  
  6651. The ARG instruction is the short form of the PARSE UPPER ARG instruction. To 
  6652. obtain arguments without the uppercase translation of letters, use the PARSE 
  6653. ARG instruction instead. 
  6654.  
  6655.  
  6656. ΓòÉΓòÉΓòÉ 13.1.1.4. Multiple-Variable Assignment ΓòÉΓòÉΓòÉ
  6657.  
  6658. PULL and ARG can also fetch each word into a different variable. In the 
  6659. following example, first, second, third, and leftover have been chosen as the 
  6660. names of variables. 
  6661.  
  6662. say "Please enter three or more words:"
  6663. pull first second third leftover
  6664. .
  6665. .
  6666. .
  6667. say first second third leftover
  6668.  
  6669. The following is displayed on the screen. 
  6670.  
  6671.  
  6672.    ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ╤Ç
  6673.    Γöé  Please type three or more words         Γöé
  6674.    Γöé                                          Γöé
  6675.    Γöé  three wise men on camels                ╤ÄΓöÇΓöÇΓöÇΓöÇΓöÇ the user types
  6676.    Γöé                                          Γöé
  6677.    Γöé  THREE WISE MEN ON CAMELS                ╤ÄΓöÇΓöÇΓöÇΓöÇΓöÇ the program displays
  6678.    Γöé    Γöé    Γöé    Γöé  Γöé       Γöé                Γöé
  6679.    Γöé    Γöé    Γöé    Γöé  ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ                Γöé
  6680.    Γöé    Γöé    Γöé    Γöé      Γöé                    Γöé
  6681.    Γöé    Γöé    Γöé    Γöé      Γöé                    Γöé
  6682.    Γöé    Γöé    Γöé    Γöé      Γöé                    Γöé
  6683.    ΓöÇΓöÇΓöÇΓöÇ╨ÆΓöÇΓöÇΓöÇΓöÇ╨ÆΓöÇΓöÇΓöÇΓöÇ╨ÆΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ╨ÆΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  6684.         Γöé    Γöé    Γöé      Γöé
  6685.         Γöé    Γöé    Γöé      Γöé
  6686.       first  Γöé    Γöé      Γöé
  6687.              Γöé    Γöé      Γöé
  6688.           second  Γöé      Γöé
  6689.                   Γöé      Γöé
  6690.                 third    Γöé
  6691.                          Γöé
  6692.                         leftover
  6693.  
  6694. The program pauses and the user can type something on the command line. When 
  6695. the user presses the Enter key, the program continues and the variable: 
  6696.  
  6697.  first is given the value THREE. 
  6698.  second is given the value WISE. 
  6699.  third is given the value MEN. 
  6700.  leftover is given the value ON CAMELS. 
  6701.  
  6702.  In general, each variable gets a word (without blanks) and the last variable 
  6703.  gets the rest of the input, if any (with blanks). If there are more variables 
  6704.  than words, the extra variables are assigned the null value. 
  6705.  
  6706.  The same thing can be done with ARG. Figure "MIX.CMD" shows a program that 
  6707.  accepts user input and then displays it in a different order. 
  6708.  
  6709.  
  6710.   MIX.CMD
  6711.  
  6712.   /* Example: this program starts by assigning the words     */
  6713.   /* from the command line to REXX variables and then        */
  6714.   /* displays them, swapping the first and third arguments. */
  6715.  
  6716.   arg first second third rest
  6717.   say third second first rest
  6718.  
  6719.  The following is displayed on the screen. 
  6720.  
  6721.   [C:\] mix james joe jack and jeff
  6722.   JACK JOE JAMES AND JEFF
  6723.  
  6724.  When the ARG instruction is processed, the variable: 
  6725.  
  6726.  first is given the value JAMES. 
  6727.  second is given the value JOE. 
  6728.  third is given the value JACK. 
  6729.  rest is given the value AND JEFF. 
  6730.  
  6731.  You can then use the SAY instruction to display the variables in any order you 
  6732.  choose. 
  6733.  
  6734.  
  6735. ΓòÉΓòÉΓòÉ 13.1.1.5. Checking for Input Errors ΓòÉΓòÉΓòÉ
  6736.  
  6737. To ensure that the user types in the right number of words, provide one extra 
  6738. variable and test that it is empty.  Also, test the variable that holds the 
  6739. last word that the user is expected to type.  By testing both variables for a 
  6740. null value, you can be sure that each of your variables contains exactly one 
  6741. word. 
  6742.  
  6743. Figure "FUSSY.CMD" shows an example that ensures that the user has typed the 
  6744. correct number of words. 
  6745.  
  6746.  
  6747. FUSSY.CMD
  6748.  
  6749. /* Example: getting the number of words that you want   */
  6750.  
  6751. good = 0
  6752. do until good
  6753.    say "Please type exactly three words"
  6754.    pull first second third rest
  6755.    select
  6756.       when third = "" then say "Not enough words"
  6757.       when rest \= "" then say "Too many words"
  6758.       otherwise good = 1
  6759.    end
  6760. end
  6761.  
  6762.  
  6763. ΓòÉΓòÉΓòÉ 13.1.1.6. Using a Placeholder ΓòÉΓòÉΓòÉ
  6764.  
  6765. The period symbol (.) by itself may not be used as a name, but it may be used 
  6766. as a place-holder with the PULL instruction. For example, pull  . .  lastname 
  6767. ., would discard the first two words, assign the third word into lastname, and 
  6768. discard the remainder of the input. 
  6769.  
  6770.  
  6771. ΓòÉΓòÉΓòÉ 13.1.1.7. Test Yourself ΓòÉΓòÉΓòÉ
  6772.  
  6773.   1. What is displayed on the screen when you run the program shown in Figure 
  6774.      "PULLING.CMD"? 
  6775.  
  6776.  
  6777.           PULLING.CMD
  6778.  
  6779.  
  6780.  
  6781.           /* Example: the PULL instruction */
  6782.           Say "Where did Jack and Jill go?"
  6783.           parse pull one two three four five six .
  6784.  
  6785.                   /* User replies 'To fetch a pail of water' */
  6786.  
  6787.           say one two six
  6788.           say
  6789.           Say "Will you buy me a diamond ring?"
  6790.           pull reply .
  6791.  
  6792.                    /* User replies 'Yes, if I can afford it' */
  6793.  
  6794.           say reply
  6795.  
  6796.   2. Write a program that asks users for their name and then greets them by 
  6797.      first name only.  Your program should ignore any other names. 
  6798.  
  6799.  
  6800. ΓòÉΓòÉΓòÉ 13.1.1.7.1. Answers: ΓòÉΓòÉΓòÉ
  6801.  
  6802.   1. The following is displayed on the screen. 
  6803.  
  6804.           Where did Jack and Jill go?
  6805.           To fetch a pail of water
  6806.           To fetch water
  6807.  
  6808.           Will you buy me a diamond ring?
  6809.           Yes, if I can afford it
  6810.           YES,
  6811.  
  6812.  
  6813.   2. Figure "HOWDY.CMD" shows an example of a possible answer. 
  6814.  
  6815.  
  6816.           HOWDY.CMD
  6817.  
  6818.           /* Example: selecting a single word */
  6819.           say "Howdy!  Say, what is your name?"
  6820.  
  6821.           pull reply .             /* The period causes second */
  6822.                                    /* and subsequent words to  */
  6823.                                    /* be ignored               */
  6824.  
  6825.           say "Pleased to meet you," reply
  6826.  
  6827.  
  6828. ΓòÉΓòÉΓòÉ 13.1.2. Parsing Variables and Expressions ΓòÉΓòÉΓòÉ
  6829.  
  6830. PULL and ARG are the short versions of options of the PARSE instruction. As 
  6831. well as parsing replies from the user and the data from the command line, you 
  6832. can also parse: 
  6833.  
  6834.  o The values of variables by using PARSE VAR symbol v1 v2 v3 ... 
  6835.  
  6836.  o The results of expressions by using PARSE VALUE expression WITH v1 v2 v3 ... 
  6837.  
  6838.  Figure "PARSING.CMD" shows an example of parsing variables and expressions. 
  6839.  
  6840.  
  6841.   PARSING.CMD
  6842.  
  6843.   /* Examples of parsing variables and expressions   */
  6844.   phrase = "Three blind mice"
  6845.   PARSE VAR phrase number adjective noun
  6846.   say number                   /* says 'Three'       */
  6847.   say adjective                /* says 'blind'       */
  6848.   say noun                     /* says 'mice'        */
  6849.   PARSE VALUE copies(phrase,2) WITH . a . b . c
  6850.   say b a c               /* says 'Three blind mice' */
  6851.  
  6852.   /* Here is a very useful trick for taking */
  6853.   /* the first word away from a sentence    */
  6854.   PARSE VAR phrase first phrase
  6855.   say first                    /* says 'Three'       */
  6856.   say phrase                   /* says 'blind mice'  */
  6857.  
  6858.  You can use parsing to analyze data from sources other than user input, such 
  6859.  as from files, queues, or hardware devices. For more information, see Input 
  6860.  and Output. 
  6861.  
  6862.  
  6863. ΓòÉΓòÉΓòÉ 13.1.2.1. Parsing Numeric Data ΓòÉΓòÉΓòÉ
  6864.  
  6865. Only parsing text data has been discussed, but all of the parsing options that 
  6866. have been described work equally well with numeric data. 
  6867.  
  6868. The way REXX handles numbers is another measure of its flexibility. Most 
  6869. computer languages have many rules about the differences between text data and 
  6870. number data.  In REXX, a number is simply a string that can be calculated. 
  6871.  
  6872.  
  6873. ΓòÉΓòÉΓòÉ 13.1.3. Summary ΓòÉΓòÉΓòÉ
  6874.  
  6875. This completes "Basics" in this chapter.  You have learned how to: 
  6876.  
  6877.  o Prompt, receive, and check user input 
  6878.  o Manipulate variable templates 
  6879.  o Use the period as a placeholder 
  6880.  o Parse variables and expressions. 
  6881.  
  6882.  "Advanced Topics" in this chapter discusses parsing using: 
  6883.  
  6884.  o Literal-string patterns 
  6885.  o Character positions 
  6886.  o Variables in patterns 
  6887.  o String functions. 
  6888.  
  6889.  To continue with "Basics," go to page 9-1. 
  6890.  
  6891.  
  6892. ΓòÉΓòÉΓòÉ 13.2. Advanced Topics ΓòÉΓòÉΓòÉ
  6893.  
  6894.      In this chapter: Advanced Topics 
  6895.  
  6896.      o Parsing with patterns 
  6897.      o Literal string patterns 
  6898.      o Character position 
  6899.      o Variables in patterns 
  6900.      o String functions. 
  6901.  
  6902.  
  6903. ΓòÉΓòÉΓòÉ 13.2.1. Parsing with Patterns ΓòÉΓòÉΓòÉ
  6904.  
  6905. By using patterns in a parsing template, you can have your programs analyze all 
  6906. types of information. In this chapter, several kinds of parsing patterns are 
  6907. discussed. 
  6908.  
  6909. For more information about the use of patterns refer to "Parsing" in the REXX 
  6910. Reference. 
  6911.  
  6912.  
  6913. ΓòÉΓòÉΓòÉ 13.2.2. Literal String Patterns ΓòÉΓòÉΓòÉ
  6914.  
  6915. One way to parse data is by literal pattern. If your PARSE instruction template 
  6916. specifies a literal string (one or more characters enclosed in quotes), the 
  6917. data being parsed is split at the point where the string is found. 
  6918.  
  6919. Figure "TAKE.CMD" shows an example where the ARG instruction parses the data 
  6920. given with the command TAKE.  The first literal pattern is the first / and the 
  6921. second literal pattern is the second /. 
  6922.  
  6923.  
  6924. TAKE.CMD
  6925.  
  6926. /* Example: recognizing options */
  6927.  
  6928. arg drink form shelf  "/"  typ1 typ2 typ3 "/" rest
  6929. say drink form shelf":" typ1 typ2 typ3 "("rest")"
  6930. .
  6931. .
  6932. .
  6933.  
  6934. The following is displayed on the screen. 
  6935.  
  6936. [C:\] take coffee beans /kenya decaf/in bags
  6937. COFFEE BEANS : KENYA DECAF  (IN BAGS)
  6938.  
  6939. When the ARG instruction is processed: 
  6940.  
  6941.  o The words in front of the first pattern are parsed in the usual way into 
  6942.    drink, form, and shelf.  In this example, shelf is set to null; that is, an 
  6943.    empty string or "".  The SAY instruction keeps the space following the 
  6944.    variable name.  That is why there is a space before the colon. 
  6945.  
  6946.  o The words between the first pattern and the second pattern (if there is one) 
  6947.    are parsed into typ1, typ2, and typ3. Here, typ3 is set to null, but SAY 
  6948.    still displays the extra space before the parenthesis. 
  6949.  
  6950.  o If there is a second pattern, the words that follow it are assigned to the 
  6951.    variable rest.  In this example, rest is assigned the two-word string IN 
  6952.    BAGS. 
  6953.  
  6954.  This technique of parsing using literal patterns can be used with any of the 
  6955.  parsing instructions. 
  6956.  
  6957.  
  6958. ΓòÉΓòÉΓòÉ 13.2.3. Character Position ΓòÉΓòÉΓòÉ
  6959.  
  6960. Another way to parse a string is by the position of the individual characters. 
  6961. There are two types of positions, absolute and relative. 
  6962.  
  6963.  
  6964. ΓòÉΓòÉΓòÉ 13.2.3.1. Absolute Position ΓòÉΓòÉΓòÉ
  6965.  
  6966. Usually, the breaks in a parsed string occur at the spaces. For example: 
  6967.  
  6968. PARSE VALUE "Five golden rings" WITH var1 var2 var3
  6969.  
  6970. This instruction assigns: 
  6971.  
  6972.  var1 the string "Five". 
  6973.  var2 the string "golden". 
  6974.  var3 the string "rings". 
  6975.  
  6976.  If you want to refer to the specific character position in the input string 
  6977.  where you want the parsing to break, specify the number of characters from the 
  6978.  beginning of the string.  That is, the first character is 1, the second is 2, 
  6979.  and so forth. 
  6980.  
  6981.   PARSE VALUE "Five golden rings" WITH var1 10 var2 15 var3
  6982.  
  6983.  This template assigns: 
  6984.  
  6985.  var1 the string "Five gold" (up to the 9th position) 
  6986.  var2 the string "en ri"   (positions 10 to 14) 
  6987.  var3 the string "ngs"    (position 15 to the end) 
  6988.  
  6989.  Figure "ABSPTRN.CMD" shows an example that uses PARSE VALUE to parse the 
  6990.  string returned by REXX's built-in TIME() function.  The TIME() string has two 
  6991.  digits each for hours, minutes, and seconds that are separated by colons. For 
  6992.  example, 12:34:55. 
  6993.  
  6994.  
  6995.   ABSPTRN.CMD
  6996.  
  6997.   /* parsing TIME() by absolute character position */
  6998.   PARSE VALUE time() WITH hr 3 . 4 mn 6 . 7 sc .
  6999.   say 'Hours   :' hr
  7000.   say 'Minutes :' mn
  7001.   say 'Seconds :' sc
  7002.  
  7003.  
  7004. ΓòÉΓòÉΓòÉ 13.2.3.2. Relative Position ΓòÉΓòÉΓòÉ
  7005.  
  7006. You can also specify breaks by relative position;  that is, by a given number 
  7007. of characters from the last break.  To parse this way, use signed numbers, 
  7008. which are numbers preceded by plus or minus signs to indicate the direction to 
  7009. move the break.  For example: 
  7010.  
  7011.   PARSE VALUE "Five golden rings" WITH var1 10 -5 var2 +8 var3 17
  7012.  
  7013. This instruction assigns: 
  7014.  
  7015.   var1 the string "Five gold"  (up to the 10th position)
  7016.   var2 the string 'golden'     (back 5, forward 8; note the leading space)
  7017.   var3 the string 'ring'       (stopped at position 16)
  7018.  
  7019. Figure "RELPTRN.CMD" shows an example that uses PARSE VALUE as applied to the 
  7020. TIME() string. 
  7021.  
  7022.  
  7023. RELPTRN.CMD
  7024.  
  7025. /* parsing TIME() by relative character position */
  7026. PARSE VALUE time() WITH hr 3 +1 mn 6 +1 sc .
  7027. say 'Hours   :' hr
  7028. say 'Minutes :' mn
  7029. say 'Seconds :' sc
  7030.  
  7031. Though PARSE VALUE was used for these examples, you can use positional patterns 
  7032. with any PARSE instruction. 
  7033.  
  7034.  
  7035. ΓòÉΓòÉΓòÉ 13.2.4. Variables in Patterns ΓòÉΓòÉΓòÉ
  7036.  
  7037. In place of a literal string or a position, you can use a variable containing 
  7038. the string, the absolute position, or the relative position.  To do this, 
  7039. enclose the variable name in parentheses, as in Figure "VARPTRN1.CMD". 
  7040.  
  7041.  
  7042. VARPTRN1.CMD
  7043.  
  7044. char = ':'
  7045. parse value time() with hr (char) mn (char) sc .
  7046. say 'Hours   :' hr
  7047. say 'Minutes :' mn
  7048. say 'Seconds :' sc
  7049.  
  7050. In fact, you can use a variable assigned in the same template, as in Figure 
  7051. "VARPTRN2.CMD". 
  7052.  
  7053.  
  7054. VARPTRN2.CMD
  7055.  
  7056. parse value time() with hr 3 char +1 mn (char) sc .
  7057. say 'Hours   :' hr
  7058. say 'Minutes :' mn
  7059. say 'Seconds :' sc
  7060.  
  7061.  
  7062. ΓòÉΓòÉΓòÉ 13.2.4.1. To Summarize ΓòÉΓòÉΓòÉ
  7063.  
  7064. Any data can be parsed using patterns in the template of a PULL, ARG, or PARSE 
  7065. instruction. A token within a template is recognized as a pattern where there 
  7066. is: 
  7067.  
  7068.  o A literal string, such as / in the example TAKE.CMD (see Figure "TAKE.CMD") 
  7069.  
  7070.  o A symbol in parentheses, which means that it is the name of a variable 
  7071.  
  7072.  o An unsigned number, which means that parsing continues at the specified 
  7073.    character position 
  7074.  
  7075.  o A signed number, which means that parsing continues at the specified 
  7076.    character position, relative to the first character of the last match. 
  7077.  
  7078.  
  7079. ΓòÉΓòÉΓòÉ 13.2.5. String Functions ΓòÉΓòÉΓòÉ
  7080.  
  7081. Another kind of parsing can be performed using REXX's built-in string 
  7082. functions.  They are grouped here by the tasks they perform.  For more 
  7083. information, refer to "Functions" in the REXX Reference. 
  7084.  
  7085. You can use the following functions to separate and change input strings. 
  7086.  
  7087.  
  7088. ΓòÉΓòÉΓòÉ 13.2.5.1. Getting Pieces ΓòÉΓòÉΓòÉ
  7089.  
  7090. Substring functions that get (return a piece of a larger string) are: 
  7091.  
  7092.  SUBSTR()       Gets a piece of a string by numbered position 
  7093.  
  7094.  LEFT()         Gets the leftmost substring; can add trailing spaces 
  7095.  
  7096.  RIGHT()        Gets the rightmost substring; can add leading spaces 
  7097.  
  7098.  WORD()         Gets a word from a string (by number) 
  7099.  
  7100.  SUBWORD()      Gets a substring beginning with a given word. 
  7101.  
  7102.  
  7103. ΓòÉΓòÉΓòÉ 13.2.5.2. Editing ΓòÉΓòÉΓòÉ
  7104.  
  7105. Functions that change a string are: 
  7106.  
  7107.  INSERT()       Inserts a substring into a string 
  7108.  
  7109.  OVERLAY()      Overlays part of one string with another 
  7110.  
  7111.  REVERSE()      Swaps the characters in a string, end for end 
  7112.  
  7113.  COPIES()       Replicates a string a given number of times. 
  7114.  
  7115.  
  7116. ΓòÉΓòÉΓòÉ 13.2.5.3. Deleting ΓòÉΓòÉΓòÉ
  7117.  
  7118. Functions that delete substrings are: 
  7119.  
  7120.  DELSTR()       Deletes a substring from the input string 
  7121.  
  7122.  DELWORD()      Deletes a substring from the input string, beginning with a 
  7123.                 given word. 
  7124.  
  7125.  
  7126. ΓòÉΓòÉΓòÉ 13.2.5.4. Formatting ΓòÉΓòÉΓòÉ
  7127.  
  7128. Functions that change a string by adding or removing spaces or other characters 
  7129. are: 
  7130.  
  7131.  SPACE()        Adds or deletes intervening spaces (or other delimiting 
  7132.                 characters) between words 
  7133.  
  7134.  CENTER()       Centers the input string within a larger string of a given 
  7135.                 length; adds spaces (or other characters) 
  7136.  
  7137.  STRIP()        Removes leading or trailing spaces (or both) from a string. 
  7138.  
  7139.  Note:  The previously described LEFT and RIGHT functions can also add spaces. 
  7140.  :enote. 
  7141.  
  7142.  
  7143. ΓòÉΓòÉΓòÉ 13.2.5.5. Counting ΓòÉΓòÉΓòÉ
  7144.  
  7145. Functions that get the lengths of strings, compare strings, or locate a 
  7146. particular character position within a string are: 
  7147.  
  7148.  LENGTH()            Counts the characters in a string 
  7149.  
  7150.  WORDS()             Counts the words in a string 
  7151.  
  7152.  WORDLENGTH()        Returns the length of a word (specified by number). 
  7153.  
  7154.  
  7155. ΓòÉΓòÉΓòÉ 13.2.5.6. Comparing ΓòÉΓòÉΓòÉ
  7156.  
  7157. Functions that return a number, based on a comparison of two strings are: 
  7158.  
  7159.  VERIFY()       Determines whether one string is made up of characters in 
  7160.                 another.  It can return the position of either the first 
  7161.                 matching character or the first nonmatching character (the 
  7162.                 default). 
  7163.  
  7164.  ABBREV()       Returns 1 (true) if one string matches the leading characters 
  7165.                 of another. 
  7166.  
  7167.  COMPARE()      Determines if two strings are identical. 
  7168.  
  7169.  
  7170. ΓòÉΓòÉΓòÉ 13.2.5.7. Finding Positions ΓòÉΓòÉΓòÉ
  7171.  
  7172. Functions that return a number that is a sought-after character position are: 
  7173.  
  7174.  POS()               Searches one string, from the beginning, for the presence 
  7175.                      of a given substring and returns the substring's position 
  7176.  
  7177.  LASTPOS()           Searches one string, from the end, backward, for the 
  7178.                      presence of a given substring and returns the substring's 
  7179.                      position 
  7180.  
  7181.  WORDINDEX()         Searches for a word by number and returns the initial 
  7182.                      character position 
  7183.  
  7184.  WORDPOS()           Seaches for a word by the word itself and returns the 
  7185.                      initial character position. 
  7186.  
  7187.  
  7188. ΓòÉΓòÉΓòÉ 13.2.5.8. Examples ΓòÉΓòÉΓòÉ
  7189.  
  7190. Figure "DOLLAR.CMD" shows an example of a REXX program that may be called as a 
  7191. string function.  It changes an input number into a string in currency format. 
  7192. It uses PARSE VAR with a literal pattern and PARSE VALUE with a 
  7193. character-position pattern. 
  7194.  
  7195.  
  7196. DOLLAR.CMD
  7197.  
  7198. /* Takes a number and returns a string in comma-delimited          */
  7199. /* dollar format; e.g., DOLLAR(1234.5555)  returns '$1,234.56'     */
  7200.  
  7201. arg number                             /* get the argument NUMBER  */
  7202.  
  7203. /* Round off the argument to the nearest cent, then      */
  7204. /* parse the result into the integer (DOLLARS), the      */
  7205. /* decimal point and the decimal fraction (CENTS)        */
  7206. /* (NOTE: More about the FORMAT() function on page Formatting Output.) */
  7207.  
  7208. PARSE VALUE format(number,,2,0) WITH dollars "." cents
  7209.  
  7210. dollars = abs(dollars)                 /* make DOLLARS positive    */
  7211.  
  7212. backin = reverse(dollars)              /* reverse the digits in    */
  7213.                                        /* DOLLARS so we can parse  */
  7214.                                        /* them into groups of 3    */
  7215.                                        /* (see REVERSE(), above)   */
  7216.  
  7217. backout = ""                           /* initialize a variable    */
  7218.                                        /* for re-concatenation     */
  7219.  
  7220. do while length(backin) > 3            /* while three digits or    */
  7221.                                        /* more remain in BACKIN,   */
  7222.    PARSE VAR backin group 4 backin    /* take each group of three */
  7223.                                        /* remaining digits, and    */
  7224.    backout = backout||group||","       /* then join it to the end  */
  7225.                                        /* of the BACKOUT variable  */
  7226.                                        /* and add a comma          */
  7227.    end
  7228.  
  7229. backout = backout||backin||"$"         /* concatenate the digits   */
  7230.                                        /* that remain; add '$'     */
  7231.  
  7232. if number < 0 then                     /* if the argument was      */
  7233.    backout = backout||"-"              /* negative, restore the    */
  7234.                                        /* minus sign               */
  7235.  
  7236. bucks = reverse(backout)||"."||cents   /* restore the proper order */
  7237.                                        /* of the digits; add the   */
  7238.                                        /* decimal point and cents  */
  7239.  
  7240. return bucks                           /* return the string        */
  7241.  
  7242. Figure "SUMCASH.CMD" shows an example of how DOLLAR.CMD could be used as a 
  7243. function in the program SUM.CMD (see Figure "SUM.CMD"). 
  7244.  
  7245.  
  7246. SUMCASH.CMD
  7247.  
  7248. /* using the function DOLLAR() in a program */
  7249. total = 0
  7250. do forever
  7251.    say "Type amount:"
  7252.    pull entry
  7253.    if \datatype(entry,n)            /*if entry is not a valid number  */
  7254.    then leave                        /* leave the loop                 */
  7255.    total = total + entry
  7256.    say "Total = " DOLLAR(total)      /* display TOTAL in dollar format */
  7257. end
  7258. say entry "is not a number.  Returning to OS/2."
  7259.  
  7260. Figure "CHANGE.CMD" shows an example of a useful search-and-replace string 
  7261. function. Notice how the second PARSE instruction uses a variable as a pattern. 
  7262.  
  7263.  
  7264. CHANGE.CMD
  7265.  
  7266. /* Function:  CHANGE(string,old,new)                    */
  7267. /* Changes all occurrences of "old" in "string"         */
  7268. /* to "new".  If "old" == "", then "new" is prefixed    */
  7269. /* to "string".                                         */
  7270.  
  7271. parse arg string, old, new
  7272. if old=="" then return new||string
  7273.  
  7274. out=""
  7275. do while pos(old,string)\= 0
  7276.    PARSE VAR string prepart (old) string
  7277.    out=out||prepart||new
  7278. end
  7279. return out||string
  7280.  
  7281. Figure "CHNGDEMO.CMD" shows an example using the CHANGE() function. 
  7282.  
  7283.  
  7284. CHNGDEMO.CMD
  7285.  
  7286. /* using the CHANGE() function  */
  7287. direction = "north by northwest"
  7288. wrong = "north"
  7289. right = "south"
  7290. say direction
  7291. say change(direction,wrong,right)   /* displays "south by southwest" */
  7292.  
  7293.  
  7294. ΓòÉΓòÉΓòÉ 14. Arithmetic ΓòÉΓòÉΓòÉ
  7295.  
  7296. This chapter discusses using REXX for calculating and displaying numbers. For 
  7297. more detailed information, refer to the REXX Reference. 
  7298.  
  7299.  
  7300. ΓòÉΓòÉΓòÉ 14.1. Basics ΓòÉΓòÉΓòÉ
  7301.  
  7302.      In this chapter: Basics 
  7303.  
  7304.      o About REXX numbers 
  7305.      o Checking input numbers 
  7306.      o Calculating 
  7307.      o Formatting output. 
  7308.  
  7309.  
  7310. ΓòÉΓòÉΓòÉ 14.1.1. About REXX Numbers ΓòÉΓòÉΓòÉ
  7311.  
  7312. Character strings on which REXX can perform arithmetic operations are referred 
  7313. to as numbers. 
  7314.  
  7315. In REXX, a number is a string of digits (0 through 9).  A number must begin 
  7316. with a digit, a plus sign (+), or a minus sign (-).  A single decimal point is 
  7317. permitted.  The letter E (or e) can be used to denote powers of 10. 
  7318.  
  7319. The NUMERIC DIGITS instruction controls the number of decimal places allowed. 
  7320. The default is nine places. 
  7321.  
  7322. REXX ignores leading and trailing spaces in number strings.  It does not allow 
  7323. spaces or commas within a number. 
  7324.  
  7325. These are some examples of valid REXX numbers: 
  7326.  
  7327.  12       This is a whole number or integer. 
  7328.  
  7329.  -5       This is a signed number (minus five). 
  7330.  
  7331.  0.5      This is a decimal fraction or decimal (one half). 
  7332.  
  7333.  3.5E6    This is a floating point number (three and one-half million). It uses 
  7334.           exponential notation.  This notation is useful when dealing with very 
  7335.           large or very small numbers.  The portion that follows the E is the 
  7336.           number of places the decimal point must be moved to the right to make 
  7337.           it into an ordinary number. 
  7338.  
  7339.  
  7340. ΓòÉΓòÉΓòÉ 14.1.2. Checking Input Numbers ΓòÉΓòÉΓòÉ
  7341.  
  7342. Before a program tries to do arithmetic on data typed from the keyboard, the 
  7343. data should be checked to verify that it has valid numbers to work with. You 
  7344. can do this by using the DATATYPE() function.  For example: 
  7345.  
  7346. datatype(expression,[type])
  7347. where 
  7348.  
  7349.  expression  is the value to be tested. 
  7350.  
  7351.  type        is an optional argument, the kind of data you are testing for. 
  7352.  
  7353.  In its simplest form, DATATYPE() returns the string NUM if the argument (the 
  7354.  expression inside the parentheses) is accepted by REXX as a number that could 
  7355.  be used in arithmetical operations.  Otherwise, it returns the string CHAR. 
  7356.  
  7357.  The value of             is the string 
  7358.  datatype(49)             "NUM" 
  7359.  datatype(5.5)            "NUM" 
  7360.  datatype(5.5.5)          "CHAR" 
  7361.  datatype("5,000")        "CHAR" 
  7362.  datatype(5 4 3 2)        "CHAR" 
  7363.  
  7364.  Figure "VALNUM.CMD" shows an example that requires the user to keep trying 
  7365.  until a valid number is typed. 
  7366.  
  7367.  
  7368.   VALNUM.CMD
  7369.  
  7370.   /* Example requiring numeric input */
  7371.   do until datatype(howmuch) = "NUM"
  7372.      say "Type a number"
  7373.      pull howmuch
  7374.      if datatype(howmuch) = "CHAR" then
  7375.        say "That was not a number.  Try again!"
  7376.   end
  7377.  
  7378.   say "The number you typed was" howmuch
  7379.  
  7380.  To test for a particular type of data, such as whole numbers, use the 
  7381.  alternative form of the DATATYPE() function.  This form requires two 
  7382.  arguments: 
  7383.  
  7384.  o The expression to be tested 
  7385.  
  7386.  o The type of data to be tested; for example, whole for a whole number. 
  7387.  
  7388.    Only the first character of type is inspected.  To test for whole numbers, 
  7389.    it would be sufficient to write W or w. In this book, whole is used to 
  7390.    remind you of the meaning of this argument. 
  7391.  
  7392.  This form of the function, DATATYPE(number,whole), returns 1 (true) if number 
  7393.  is a whole number, 0 (false) if otherwise.  For example: 
  7394.  
  7395.   do until datatype(howmany,whole)
  7396.   .
  7397.   .
  7398.   .
  7399.      pull howmany
  7400.   .
  7401.   .
  7402.   .
  7403.   end
  7404.  
  7405.  If you also want to restrict the input to numbers greater than 0, you could 
  7406.  write: 
  7407.  
  7408.   do until datatype(howmany,whole) & howmany > 0
  7409.   .
  7410.   .
  7411.   .
  7412.      pull howmany
  7413.   .
  7414.   .
  7415.   .
  7416.   end
  7417.  
  7418.  The ampersand (&) is an operator that combines conditions (see Combining 
  7419.  Expressions).  In this example, both datatype (howmany,whole) and howmany > 0 
  7420.  must be true for the loop to end. 
  7421.  
  7422.  The DATATYPE() function can test for other types of data, as well. For 
  7423.  examples, see the REXX Reference. 
  7424.  
  7425.  
  7426. ΓòÉΓòÉΓòÉ 14.1.3. Calculating ΓòÉΓòÉΓòÉ
  7427.  
  7428.  
  7429. ΓòÉΓòÉΓòÉ 14.1.3.1. Addition and Subtraction ΓòÉΓòÉΓòÉ
  7430.  
  7431. These operations are performed in the usual way.  You can use both whole 
  7432. numbers and decimal fractions. 
  7433.  
  7434. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  7435. Γöé OPERATOR     Γöé OPERATION    Γöé EXAMPLE                                          Γöé
  7436. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7437. Γöé + (plus      Γöé Add          Γöé "say 7 + 2   /* displays '9'  */"                Γöé
  7438. Γöé sign)        Γöé              Γöé                                                  Γöé
  7439. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7440. Γöé - (minus     Γöé Subtract     Γöé "say 7 - 2   /* displays '5'  */"                Γöé
  7441. Γöé sign)        Γöé              Γöé                                                  Γöé
  7442. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  7443.  
  7444.  
  7445. ΓòÉΓòÉΓòÉ 14.1.3.2. Multiplication and Powers ΓòÉΓòÉΓòÉ
  7446.  
  7447. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  7448. Γöé OPERATOR     Γöé OPERATION    Γöé EXAMPLE                                          Γöé
  7449. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7450. Γöé * (asterisk) Γöé Multiply     Γöé "say 7 * 2   /* displays '14' */"                Γöé
  7451. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  7452. Γöé ** (double   Γöé Raise to a   Γöé "say 7**2   /* displays '49' */"                 Γöé
  7453. Γöé asterisk)    Γöé whole number Γöé                                                  Γöé
  7454. Γöé              Γöé power        Γöé                                                  Γöé
  7455. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  7456.  
  7457.  
  7458. ΓòÉΓòÉΓòÉ 14.1.3.3. Division ΓòÉΓòÉΓòÉ
  7459.  
  7460. When you divide, you determine whether or not you want the answer expressed as 
  7461. a whole number (integer).  The operators you can use are: 
  7462.  
  7463.  / (one slash)       Divide.  For example: 
  7464.  
  7465.                                           say 7 / 2   /* displays '3.5' */
  7466.  
  7467.  % (percent sign)    Integer divide.  The result is a whole number. Any 
  7468.                      remainder is ignored.  For example: 
  7469.  
  7470.                                           say 7 % 2   /* displays '3'   */
  7471.  
  7472.  // (two slashes)    Remainder after integer division.  For example: 
  7473.  
  7474.                                           say 7 // 2  /* displays '1'   */
  7475.  
  7476.  Notice which of these operators is used in the example shown in Figure 
  7477.  "SHARE.CMD". 
  7478.  
  7479.  
  7480.   SHARE.CMD
  7481.  
  7482.   /* This program works out how to share zero or more     */
  7483.   /* sweets between one or more children, assuming that   */
  7484.   /* a single sweet cannot be split.                      */
  7485.  
  7486.   /*------------------------------------------------------*/
  7487.   /* Get input from user                                  */
  7488.   /*------------------------------------------------------*/
  7489.   do until datatype(sweets,whole) & sweets >= 0
  7490.      say "How many sweets?"
  7491.      pull sweets
  7492.   end
  7493.  
  7494.   do until datatype(children,whole) & children > 0
  7495.      say "How many children?"
  7496.      pull children
  7497.   end
  7498.  
  7499.   /*------------------------------------------------------*/
  7500.   /* Compute result                                       */
  7501.   /*------------------------------------------------------*/
  7502.   say "Each child will get" sweets%children  "sweets",
  7503.       "and there will be"   sweets//children  "left over."
  7504.  
  7505.  Do not to try to divide by 0.  If you do, a syntax error results. That is why, 
  7506.  in Figure "SHARE.CMD", the user was not allowed to answer 0 to the question 
  7507.  "How many children?". 
  7508.  
  7509.  Because apples and oranges can be cut into pieces, you can use the / division 
  7510.  operator.  For example: 
  7511.  
  7512.   children = 5;  apples = 7;
  7513.   say "Each child gets" apples/children "apples."
  7514.  
  7515.   /* displays 'Each child gets 1.4 apples.' */
  7516.  
  7517.  Fractions are usually computed with an accuracy of nine significant digits. 
  7518.  For example: 
  7519.  
  7520.   children = 3;  oranges = 7;
  7521.   say "Each child gets" oranges/children "oranges."
  7522.  
  7523.   /* displays 'Each child gets 2.33333333 oranges.' */
  7524.  
  7525.  To summarize: 
  7526.  
  7527.  o The result of a % operation is always a whole number, the quotient only. 
  7528.  
  7529.  o There may be a remainder.  To compute the remainder, write the expression 
  7530.    using the // operator. 
  7531.  
  7532.  o The result of a / operation can be a decimal. 
  7533.  
  7534.  
  7535. ΓòÉΓòÉΓòÉ 14.1.3.4. Range and Precision ΓòÉΓòÉΓòÉ
  7536.  
  7537. REXX calculates the result correct to nine digits if necessary.  This means 
  7538. nine significant digits, not counting the zeros that come immediately after the 
  7539. decimal point in very small decimal fractions.  For example: 
  7540.  
  7541. say 1*2*3*4*5*6*7*8*9*10*11*12      /* displays '479001600' */
  7542.  
  7543. say 7/30000000000       /* displays '0.000000000233333333' */
  7544.  
  7545. The accuracy of computed results can be changed using the NUMERIC DIGITS 
  7546. instruction.  See Changing Precision. 
  7547.  
  7548.  
  7549. ΓòÉΓòÉΓòÉ 14.1.3.5. Exponential Notation ΓòÉΓòÉΓòÉ
  7550.  
  7551. Numbers much larger or smaller than those previously discussed are difficult to 
  7552. read and write, because it is easy to make a mistake counting the zeros.  It is 
  7553. simpler to use exponential notation.  Very large numbers can be written as an 
  7554. ordinary number, followed by a letter E, followed by a whole number, called the 
  7555. exponent.  The exponent is how many places to the right (positive exponent) or 
  7556. left (negative exponent) that the decimal point of the fixed-point number would 
  7557. have to be moved to obtain the same value as an ordinary number.  For example: 
  7558.  
  7559.  4.5E6 is the same as 4 500 000 (four and one-half million) 
  7560.  23E6 is the same as 23 000 000 (twenty-three million) 
  7561.  1E12 is the same as 1 000 000 000 000 (a million million) 
  7562.  4.5E-3 is the same as 0.004 5 (four and one-half thousandths) 
  7563.  1E-6 is the same as 0.000 001 (one millionth). 
  7564.  
  7565.  Write numbers this way in expressions and also when entering numeric data 
  7566.  requested by REXX programs.  REXX uses this notation when displaying results 
  7567.  that are too large or too small to be expressed conveniently as ordinary 
  7568.  numbers or decimals.  When REXX uses this notation, the part of the number 
  7569.  that comes before the E (the mantissa) is usually a number between 1 and 9.999 
  7570.  999 99. For example: 
  7571.  
  7572.   j = 1
  7573.   do until j > 1e12
  7574.      say j                   /* displays '1'                */
  7575.      j = j * 11              /*          '11'               */
  7576.   end                        /*          '121'              */
  7577.                              /*          '1331'             */
  7578.                              /*          '14641'            */
  7579.                              /*          '161051'           */
  7580.                              /*          '1771561'          */
  7581.                              /*          '19487171'         */
  7582.                              /*          '214358881'        */
  7583.                              /*          '2.35794769E+9'    */
  7584.                              /*          '2.59374246E+10'   */
  7585.                              /*          '2.85311671E+11'   */
  7586.  
  7587.  Numbers written in exponential notation, such as 1.5E9, are sometimes called 
  7588.  floating-point numbers.  Conversely, ordinary numbers, such as 3.14, are 
  7589.  sometimes called fixed-point numbers. 
  7590.  
  7591.  
  7592. ΓòÉΓòÉΓòÉ 14.1.3.6. Test Yourself ΓòÉΓòÉΓòÉ
  7593.  
  7594. What is displayed on the screen when you run the program shown in Figure 
  7595. "ARITHOPS.CMD"? 
  7596.  
  7597.  
  7598. ARITHOPS.CMD
  7599.  
  7600. /* Example: arithmetical operations */
  7601. quarter = 25
  7602. deuce = 2
  7603. say quarter + deuce
  7604. say quarter - deuce
  7605. say quarter * deuce
  7606. say quarter / deuce
  7607. say quarter % deuce
  7608. say quarter // deuce
  7609. x = quarter"E"deuce
  7610. say x + 0
  7611.  
  7612.  
  7613. ΓòÉΓòÉΓòÉ 14.1.3.6.1. Answer ΓòÉΓòÉΓòÉ
  7614.  
  7615. The following is displayed on the screen. 
  7616.  
  7617. [C:\] arithops
  7618. 27
  7619. 23
  7620. 50
  7621. 12.5
  7622. 12
  7623. 1
  7624. 2500
  7625. C:\[]
  7626.  
  7627. The last two lines of the program require some explanation.  First, x gets the 
  7628. value 25E2.  This is the same as 25.00 with the decimal point moved two places 
  7629. to the right (in other words, 2500).  When x is used in the arithmetical 
  7630. expression, the number 25E2 is added to 0, giving a result of 2500. 
  7631.  
  7632.  
  7633. ΓòÉΓòÉΓòÉ 14.1.4. Formatting Output ΓòÉΓòÉΓòÉ
  7634.  
  7635. Your program has accepted numbers from its user and made calculations. Now it 
  7636. must display the results. 
  7637.  
  7638. When formatting output, REXX: 
  7639.  
  7640.  o Rounds numbers automatically before every operation, if necessary. Rounding 
  7641.    is to the current precision value set by a NUMERIC DIGITS instruction (see 
  7642.    page Changing Precision) or to the default value of nine decimal digits. 
  7643.  
  7644.  o Removes all leading zeros from the integer part of number, but leaves in the 
  7645.    trailing zeros in the decimal portion. 
  7646.  
  7647.  You may want to keep the precision of the calculations to the ninth place, but 
  7648.  you do not need to display all those extra zeros. That is what the following 
  7649.  two functions are for: 
  7650.  
  7651.   TRUNC(number,places)
  7652.  
  7653.  TRUNC() returns just the integer part of number and the number of decimal 
  7654.  places you specify.  The only remaining decimals are truncated or cut off. 
  7655.  That is, TRUNC rounds down. For example: 
  7656.  
  7657.   say trunc(321.765,2)  /* displays 321.76. */
  7658.  
  7659.  Likewise, FORMAT() function leaves a specified number of decimals, but it does 
  7660.  conventional rounding.  The last decimal remaining is increased by one if the 
  7661.  next (truncated) decimal is 5 or greater. For example: 
  7662.  
  7663.   FORMAT(number,before,after)
  7664.  
  7665.  The first three arguments of the FORMAT() function are: 
  7666.  
  7667.  The number to be formatted 
  7668.  How many digits to be shown before the decimal point 
  7669.  How many digits to be shown after the decimal point. 
  7670.  
  7671.  For example: 
  7672.  
  7673.   say format (321.765,3,2)   /* displays 321.77 */
  7674.  
  7675.  Note:  321.7649 rounded to two places is 321.76, because FORMAT() only uses 
  7676.  the first truncated digit to determine rounding. :enote. 
  7677.  
  7678.  Figure "ROUNDING.CMD" shows an extended example to compare FORMAT() and 
  7679.  TRUNC(). 
  7680.  
  7681.  
  7682.   ROUNDING.CMD
  7683.  
  7684.   /*  An example of rounding and displaying numbers */
  7685.   say
  7686.   say "       At full         Round w/   Round w/ "
  7687.   say "       precision       FORMAT()   TRUNC()"
  7688.   say copies("-",45)
  7689.  
  7690.   do num = 1 to 9
  7691.      quotient = 23 / num
  7692.  
  7693.      norm = FORMAT(quotient,3,3) /* rounding normally to 3 decimal places */
  7694.      down = TRUNC(quotient,3)    /* rounding down to 3 decimal places     */
  7695.  
  7696.      /* Now, we will use FORMAT() to put the numbers into columns */
  7697.  
  7698.      say "23/"num "=" FORMAT(quotient,2,8) FORMAT(norm,6,3) FORMAT(down,6,3)
  7699.  
  7700.   end
  7701.  
  7702.  The following is displayed on the screen, when you run ROUNDIT.CMD. 
  7703.  
  7704.   [C:\]roundit
  7705.  
  7706.           At full        Round w/   Round w/
  7707.           precision      FORMAT()   TRUNC()
  7708.   ---------------------------------------------
  7709.   23/1 = 23.00000000     23.000     23.000
  7710.   23/2 = 11.50000000     11.500     11.500
  7711.   23/3 =  7.66666667      7.667      7.666
  7712.   23/4 =  5.75000000      5.750      5.750
  7713.   23/5 =  4.60000000      4.600      4.600
  7714.   23/6 =  3.83333333      3.833      3.833
  7715.   23/7 =  3.28571429      3.286      3.285
  7716.   23/8 =  2.87500000      2.875      2.875
  7717.   23/9 =  2.55555556      2.556      2.555
  7718.   [C:\]
  7719.  
  7720.  
  7721. ΓòÉΓòÉΓòÉ 14.1.5. Summary ΓòÉΓòÉΓòÉ
  7722.  
  7723. This completes "Basics" in this chapter.  You have learned how to: 
  7724.  
  7725.  o Check user input 
  7726.  o Make REXX do the calculating 
  7727.  o Display the results on the screen. 
  7728.  
  7729.  "Advanced Topics" in this chapter discusses: 
  7730.  
  7731.  o Additional formatting techniques 
  7732.  o How to control the precision of REXX arithmetic 
  7733.  o Comparing number strings 
  7734.  o Scientific notation and exponentiation. 
  7735.  
  7736.  To continue with "Basics," go to page 10-1. 
  7737.  
  7738.  
  7739. ΓòÉΓòÉΓòÉ 14.2. Advanced Topics ΓòÉΓòÉΓòÉ
  7740.  
  7741.      In this chapter: Advanced Topics 
  7742.  
  7743.      o Putting numbers into columns 
  7744.      o Formatting errors 
  7745.      o Rounding errors 
  7746.      o Conventional and scientific notation 
  7747.      o Changing precision 
  7748.      o Comparing numbers 
  7749.      o Powers (** operator) 
  7750.      o A square-root function. 
  7751.  
  7752.  
  7753. ΓòÉΓòÉΓòÉ 14.2.1. Putting Numbers into Columns ΓòÉΓòÉΓòÉ
  7754.  
  7755. Columns of figures are easier to read if the numbers are aligned with the units 
  7756. in the same column.  The FORMAT() function helps you to do this (see Figure 
  7757. "INVOICE.CMD"). 
  7758.  
  7759.  
  7760. INVOICE.CMD
  7761.  
  7762. /* Example showing how columns of figures are formatted */
  7763.  
  7764. qty.1 = 101;     unitprice.1 = 0.73;     remark.1 = OK
  7765. qty.2 = 500;     unitprice.2 = 1995;     remark.2 = OK
  7766. qty.3 = 60000;   unitprice.3 = 70000;    remark.3 = OK
  7767. qty.4 = 500;     unitprice.4 = 400/12;   remark.4 = OK
  7768.  
  7769. say "Quantity    Unit Price    Total Price   Observations"
  7770.  
  7771. do item = 1 to 4
  7772.    say format(qty.item, 5,0),
  7773.        format(unitprice.item, 11,2),
  7774.        format(qty.item * unitprice.item, 12,2),
  7775.        "  " remark.item
  7776. end
  7777.  
  7778. The following formatted data is displayed on the screen. 
  7779.  
  7780. Quantity    Unit Price    Total Price   Observations
  7781.   101           0.73           73.73    OK
  7782.   500        1995.00       997500.00    OK
  7783. 60000       70000.00            4.20E+9    OK
  7784.   500          33.33        16666.67    OK
  7785.  
  7786.  
  7787. ΓòÉΓòÉΓòÉ 14.2.2. Formatting Errors ΓòÉΓòÉΓòÉ
  7788.  
  7789. The numbers to be formatted should always be small enough to fit into the space 
  7790. you have reserved for them with FORMAT. 
  7791.  
  7792. A simple rule is to always specify at least nine spaces for the before the 
  7793. decimal point argument.  To ensure that numbers with more than nine digits are 
  7794. displayed in exponential notation.  The extra characters required causes fields 
  7795. to the right of the number to shift to the right, thus drawing attention to the 
  7796. exception. 
  7797.  
  7798. Look at item 3 in the previous example.  The quantity times the unit price (60 
  7799. 000 times 70 000) gives a total price of 4 200 000 000, which is too large for 
  7800. the nine-digit field that was specified.  The result has therefore been 
  7801. displayed in exponential notation.  This in turn has caused OK to be shifted 
  7802. right. 
  7803.  
  7804. If we add qty.5 = 880 000, unitprice.5 = 1, and remark.5 = "Big deal" and 
  7805. change the 4 to a 5 in the DO instruction, then the following is displayed on 
  7806. the screen. 
  7807.  
  7808. [C:\]invoice
  7809. Quantity    Unit Price    Total Price   Observations
  7810.     101           0.73           73.73    OK
  7811.     500        1995.00       997500.00    OK
  7812.   60000       70000.00            4.20E+9    OK
  7813.     500          33.33        16666.67    OK
  7814.      12 +++  say format(qty.item, 5,0),       format(unitprice.item, 11, 2),
  7815.  format(qty.item * unitprice.item, 12,2),       "  " remark.item
  7816. REX0040: Error 40 running C:\INVOICE.CMD, line 12: Incorrect call to
  7817. routine
  7818.  
  7819. [C:\]
  7820.  
  7821. The error could have been avoided by: 
  7822.  
  7823.  o Testing the input values for a maximum number of 99 999 
  7824.  
  7825.    or 
  7826.  
  7827.  o Allowing space enough for at least nine digits for the integer part. For 
  7828.    example: 
  7829.  
  7830.       say format(qty.item, 9,0),
  7831.           format(unitprice.item, 9,2),
  7832.           format(qty.item * unitprice.item, 11,2),
  7833.           "  " remark.item
  7834.  
  7835.    The following formatted data is displayed on the screen. 
  7836.  
  7837.       Quantity    Unit Price    Total Price   Observations
  7838.             101         0.73          73.73    OK
  7839.             500      1995.00      997500.00    OK
  7840.           60000     70000.00           4.20E+9    OK
  7841.             500        33.33       16666.67    OK
  7842.          880000         1.00      880000.00    Big deal
  7843.       [C:\]
  7844.  
  7845.  
  7846. ΓòÉΓòÉΓòÉ 14.2.3. Rounding Errors ΓòÉΓòÉΓòÉ
  7847.  
  7848. When your program performs a series of arithmetical operations, additional 
  7849. errors can be inadvertently introduced.  Look at the fourth item in the 
  7850. INVOICE.CMD program shown in Figure "INVOICE.CMD".  The customer seems to have 
  7851. been overcharged by $1.67.  The price was $400 a dozen.  FORMAT() has rounded 
  7852. this to 33.33 each.  But Total Price was not rounded until after it had been 
  7853. multiplied by 500. 
  7854.  
  7855. For rounding numbers, use FORMAT() at the point in your calculations where you 
  7856. want rounding to occur.  For rounding down, use TRUNC(). 
  7857.  
  7858.  
  7859. ΓòÉΓòÉΓòÉ 14.2.3.1. Test Yourself ΓòÉΓòÉΓòÉ
  7860.  
  7861. Write a program that accepts input liquid quantities and unit prices and 
  7862. displays the price per gallon and per liter. 
  7863.  
  7864.  
  7865. ΓòÉΓòÉΓòÉ 14.2.3.1.1. Answer ΓòÉΓòÉΓòÉ
  7866.  
  7867. Figure "LIQUID.CMD" shows an example, divided into six parts, of one way to do 
  7868. this. 
  7869.  
  7870.  
  7871. LIQUID.CMD
  7872.  
  7873. /* Calculate a conversion table for input liquid quantities           */
  7874.  
  7875. /*   Simple variables (input and program control):                    */
  7876. /*   INPUTQTY  : Quantity                                             */
  7877. /*   INPUTUPR  : Unit price                                           */
  7878. /*   UNIT      : Unit of measure (G or L)                             */
  7879. /*   RPTUPR    : Unit price of previous entry                         */
  7880. /*   RPTUNIT   : Unit of measurement of previous entry                */
  7881. /*   ITEM      : Item number (each purchase)                          */
  7882.  
  7883. /*   Compound symbols (for each item of output):                      */
  7884. /*   QTYINGAL.ITEM  : Quantity in gallons                             */
  7885. /*   UPPGAL.ITEM    : Unit price per gallon                           */
  7886. /*   QTYINLIT.ITEM  : Quantity in liters                              */
  7887. /*   UPPLIT.ITEM    : Unit price per liter                            */
  7888. /*   TTLPRC.ITEM    : Total price of purchase                         */
  7889.  
  7890. /* MAIN PROGRAM: Calls input subroutines GETQTY, GETUPR, and GETUNIT  */
  7891. /* and CALCULATE subroutine ; results are then displayed in table.    */
  7892.  
  7893. inputqty = ""             /* Initialize variable for quantity input   */
  7894.                           /* (also controls end of input).            */
  7895.  
  7896. do item = 1               /* For each item...                         */
  7897.  
  7898.    call getqty            /* - get input for quantity                 */
  7899.    if inputqty = "" then  /*   if none entered, then quit the loop    */
  7900.       leave               /*   and display results                    */
  7901.  
  7902.    call getupr            /* - get input for unit price               */
  7903.    call getunit           /* - get unit of measurement for input      */
  7904.    call calculate         /* - do the calculations                    */
  7905.    inputqty = ""          /* re-initialize input variable             */
  7906.  
  7907. end                       /* and repeat the loop                      */
  7908.  
  7909. /* When all data have been input, display a header ....               */
  7910. say
  7911. say "    |    IN LITERS      |    IN GALLONS     |     TOTAL"
  7912. say "    | quantity    unit  | quantity    unit  |     PRICE"
  7913. say "    |            price  |            price  |          "
  7914. say copies("=",56)
  7915. /* ... then display the calculated values in columns using FORMAT().  */
  7916. last = item -1
  7917. do item = 1 to last
  7918.    say,
  7919.         format(item,3,0)" |",                     /* Item number      */
  7920.         format(qtyinlit.item,5,2),                /* Qty. in liters   */
  7921.         format(upplit.item,3,3)"  |",             /* Price per liter  */
  7922.         format(qtyingal.item,5,2),                /* Qty. in gallons  */
  7923.         format(uppgal.item,3,3)"  |",             /* Price per gallon */
  7924.         format(ttlprc.item,7,2)                   /* Total purchase   */
  7925. end
  7926. exit
  7927.  
  7928. /*     Following are the subroutines for data input                   */
  7929.  
  7930. getqty:           /* Accept input quantity for each item.             */
  7931. /* The DO loop allows the user to type only a number or (by           */
  7932. /* pressing the Enter key alone) a null string, ending the input loop.*/
  7933.  
  7934. do until datatype(inputqty,n) | inputqty = ""
  7935.    say
  7936.    say "Type quantity for item number" item
  7937.    say "  or press the Enter key alone to end the program."
  7938.    pull inputqty
  7939. end
  7940. return
  7941.  
  7942. getupr:           /* Accept input for each item's unit price.         */
  7943. /* The SYMBOL() function tests whether previous input exists          */
  7944. /* (i.e., if the variable REPTUPR has been assigned a value).         */
  7945. /* If so, the user can 'carry over' that previous input by            */
  7946. /* simply pressing the Enter key.                                     */
  7947.  
  7948. say
  7949. say "Type unit price"
  7950. if symbol("reptupr") <> "LIT" then
  7951.    say "  (or press the Enter key for" reptupr")"
  7952.  
  7953. /* Again, the DO loop allows only numeric input.                      */
  7954.  
  7955. do until datatype(inputupr,n)
  7956.    pull inputupr              /* Entering a null string (i.e.,        */
  7957.    if inputupr = "" then      /* pressing the Enter key only)         */
  7958.       inputupr = reptupr      /* 'carries over' the previous item's   */
  7959.    else reptupr  = inputupr   /* unit price; otherwise this input is  */
  7960. end                           /* stored for later 'carry-over.'       */
  7961. return
  7962. getunit:          /* Accept input for measure (liters or gallons);    */
  7963. /* again, the SYMBOL function checks for prior use of repeat variable */
  7964.  
  7965. say "Type G for gallons or L for liters"
  7966. if symbol("reptunit") <> "LIT" then
  7967.    say "  (or press the Enter key for" reptunit")"
  7968.  
  7969. /* The DO loop allows only a "G" or "L" as input                      */
  7970.  
  7971. do until unit = "G" | unit = "L"
  7972.    pull unit
  7973.    if unit = "" then       /* A null string is changed to             */
  7974.       unit = reptunit      /* the previous input; otherwise           */
  7975.    else reptunit = unit    /* this entry is stored for next time.     */
  7976. end
  7977. return
  7978.  
  7979. calculate:       /* Calculate the output values according to unit     */
  7980.  
  7981. select
  7982.    when unit ="G" then do               /* if input is in gallons...  */
  7983.      qtyingal.item = inputqty           /* store the input quantity   */
  7984.      qtyinlit.item = inputqty*3.7853    /* convert to liters          */
  7985.      uppgal.item  = inputupr            /* store the unit price       */
  7986.      upplit.item  = inputupr/3.7853     /* compute 'per liter' price  */
  7987.      end
  7988.    when unit ="L" then do               /* if input is in liters...   */
  7989.      qtyinlit.item = inputqty           /* store the input quantity   */
  7990.      qtyingal.item = inputqty/3.7853    /* convert to gallons         */
  7991.      upplit.item  = inputupr            /* store the unit price       */
  7992.      uppgal.item  = inputupr*3.7853     /* compute 'per gallon' price */
  7993.      end
  7994. end
  7995.  
  7996. ttlprc.item = inputqty * inputupr       /* compute total price of item */
  7997. return
  7998.  
  7999.  
  8000. ΓòÉΓòÉΓòÉ 14.2.4. Conventional and Scientific Notation ΓòÉΓòÉΓòÉ
  8001.  
  8002. You can control whether numbers are expressed in conventional or scientific 
  8003. notation with the FORMAT() function. 
  8004.  
  8005.  
  8006. ΓòÉΓòÉΓòÉ 14.2.4.1. Fixed-point (Conventional) Notation ΓòÉΓòÉΓòÉ
  8007.  
  8008. To stop FORMAT() from returning floating-point numbers (when results would 
  8009. usually be expressed in floating-point numbers), use the fourth argument of 
  8010. FORMAT.  This argument specifies the number of character positions reserved for 
  8011. the exponent.  Exponential notation is not used if you write: 
  8012.  
  8013. FORMAT(number,before,after,0)
  8014.  
  8015. Be sure that the amount of space you have allowed for before and after is 
  8016. sufficient. 
  8017.  
  8018.  
  8019. ΓòÉΓòÉΓòÉ 14.2.4.2. Floating-point (Scientific) Notation ΓòÉΓòÉΓòÉ
  8020.  
  8021. To make FORMAT() return floating-point numbers (called exponential or 
  8022. scientific notation) when the results would usually be expressed in fixed-point 
  8023. numbers, use the fifth argument of FORMAT().  This argument specifies the 
  8024. threshold for expressing the result in exponential notation.  Exponential 
  8025. notation is used if you write: 
  8026.  
  8027. FORMAT(number,before,after,,0)
  8028.  
  8029. Note:  When a floating-point number has an absolute value between 1 and 9.999 
  8030. 99999 (that is, when the exponent is 0) the characters E+0 are always omitted, 
  8031. even when floating-point has been specified. :enote. 
  8032.  
  8033. For other uses of the FORMAT() function, see the REXX Reference. 
  8034.  
  8035.  
  8036. ΓòÉΓòÉΓòÉ 14.2.4.3. Test Yourself ΓòÉΓòÉΓòÉ
  8037.  
  8038.   1. Write a program called REFORMAT that expresses numbers typed by the user 
  8039.      in both fixed-point and exponential notation. 
  8040.  
  8041.   2. Test your program with the numbers: 
  8042.  
  8043.     123 456 789 
  8044.     0.000 000 000 001 234 5 
  8045.     999 999 999 999e-6 
  8046.     1.2e10 
  8047.     1.2 
  8048.     1.2e+0 
  8049.  
  8050.  
  8051. ΓòÉΓòÉΓòÉ 14.2.4.3.1. Answers: ΓòÉΓòÉΓòÉ
  8052.  
  8053.   1. Figure "REFORMAT.CMD" shows an example of a possible answer. 
  8054.  
  8055.  
  8056.           REFORMAT.CMD
  8057.  
  8058.  
  8059.  
  8060.           /* Example: to change the format of a number */
  8061.           do forever
  8062.              say "Type a number"
  8063.              pull answer
  8064.              if \ datatype(answer,number) then exit
  8065.              say "Fixed-point equivalent:" format(answer,,,0)
  8066.              say "Exponential equivalent:" format(answer,,,,0)
  8067.           end
  8068.  
  8069.   2. Figure "REFORMAT.CMD Results" shows a table that lists the results you 
  8070.      should get when using the test numbers with the REFORMAT.CMD. 
  8071.  
  8072.  
  8073.   REFORMAT . CMDResults
  8074.  
  8075.   ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  8076.   Γöé Number typed             Γöé Fixed point equivalent   Γöé Exponential equivalent   Γöé
  8077.   Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8078.   Γöé 123 456 789              Γöé 123 456 789              Γöé 1.234 567 89EΓö╝8          Γöé
  8079.   Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8080.   Γöé 0.000 000 000 001 234 5  Γöé 0.000 000 000 001 234 5  Γöé 1.2345E-12               Γöé
  8081.   Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8082.   Γöé 999 999 999 999e-6       Γöé 1 000 000.00             Γöé 1.000 000 00EΓö╝6          Γöé
  8083.   Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8084.   Γöé 1.2e10                   Γöé 1 200 000 000 000        Γöé 1.2EΓö╝10                  Γöé
  8085.   Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8086.   Γöé 1.2                      Γöé 1.2                      Γöé 1.2                      Γöé
  8087.   Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8088.   Γöé 1.2eΓö╝0                   Γöé 1.2                      Γöé 1.2                      Γöé
  8089.   ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  8090.  
  8091.  
  8092. ΓòÉΓòÉΓòÉ 14.2.5. Changing Precision ΓòÉΓòÉΓòÉ
  8093.  
  8094. If you want to avoid using exponential notation, or if you want to control the 
  8095. precision of your calculations, use the NUMERIC DIGITS instruction to change 
  8096. the number of significant digits  (see Figure "ACCURATE.CMD").  (The default 
  8097. setting for NUMERIC DIGITS is 9.) 
  8098.  
  8099.  
  8100. ACCURATE.CMD
  8101.  
  8102. /* examples of numbers with unusually high precision */
  8103.  
  8104. numeric digits 10
  8105. say "The largest signed number that can be held"
  8106. say "in a C long integer is" 2**31 - 1 "exactly."
  8107. say
  8108.  
  8109. numeric digits 48
  8110. say "1/7 =" 1/7
  8111.  
  8112. The following is displayed on the screen when you run the program. 
  8113.  
  8114. [C:\] accurate
  8115. The largest signed number that can be held
  8116. in a C long integer is 2147483647 exactly.
  8117.  
  8118. 1/7 = 0.142857142857142857142857142857142857142857142857
  8119. [C:\]
  8120.  
  8121. To check the current setting of the NUMERIC DIGITS instruction, use the 
  8122. DIGITS() function, digits().  If you have not used the NUMERIC DIGITS 
  8123. instruction to change precision, then the DIGITS() function returns 9 (the 
  8124. default setting). 
  8125.  
  8126.  
  8127. ΓòÉΓòÉΓòÉ 14.2.5.1. Rounding and Precision ΓòÉΓòÉΓòÉ
  8128.  
  8129. The NUMERIC DIGITS instruction specifies the maximum number of significant 
  8130. digits in the result of a REXX calculation.  Whatever the setting you give for 
  8131. NUMERIC DIGITS, REXX carries out its calculations to an even higher precision. 
  8132. Extra guard digits are provided for each input number. Multiplication and 
  8133. division are calculated out to twice the NUMERIC DIGITS setting. 
  8134.  
  8135. This means that the only arithmetic errors that can occur are in the final 
  8136. rounding.  For example: 
  8137.  
  8138. numeric digits 3
  8139. say 100.3 + 100.3           /* displays 201                  */
  8140.                             /* 200.6 is rounded to '201'     */
  8141.  
  8142. Unless you have a specific need for high-precision calculations, leave NUMERIC 
  8143. DIGITS at the default setting of 9.  Higher settings can slow your programs 
  8144. down needlessly.  Lower settings can affect calculations in a way you do not 
  8145. intend (for example, how DO loop counters are incremented). When you need to 
  8146. round final results for printouts or displays, use the FORMAT() function. 
  8147.  
  8148. For more information about rounding, see "Numerics and Arithmetic" in the REXX 
  8149. Reference. 
  8150.  
  8151.  
  8152. ΓòÉΓòÉΓòÉ 14.2.6. Comparing Numbers ΓòÉΓòÉΓòÉ
  8153.  
  8154. There are times when an accurate comparison is inconvenient (see Figure 
  8155. "NOFUZZ.CMD"). 
  8156.  
  8157.  
  8158. NOFUZZ.CMD
  8159.  
  8160. /* Example: no approximation here */
  8161.  
  8162. say 1 + 1/3                     /* displays '1.33333333'   */
  8163. say 1 + 1/3 + 1/3 + 1/3         /* displays '1.99999999'   */
  8164. say 1 + 1/3 + 1/3 + 1/3 = 2     /* displays '0'  (false)   */
  8165.  
  8166. To make REXX comparisons allow for approximate values (make them less accurate 
  8167. than ordinary REXX arithmetic), use the instruction, NUMERIC FUZZ n, where n is 
  8168. the number of digits (at full precision) that REXX should ignore when comparing 
  8169. numbers. The number n must be a whole positive number (or any expression that 
  8170. is so evaluated), and it must be less than the current NUMERIC DIGITS setting 
  8171. (see Figure "FUZZ.CMD"). 
  8172.  
  8173.  
  8174. FUZZ.CMD
  8175.  
  8176. /* Example: allowing approximation */
  8177. say 1 + 1/3 + 1/3 + 1/3 = 2     /* displays '0'  (false)  */
  8178. numeric fuzz 1
  8179. say 1 + 1/3 + 1/3 + 1/3 = 2     /* displays '1'  (true)   */
  8180.  
  8181. To check the current setting of the NUMERIC FUZZ instruction, use the function, 
  8182. FUZZ().  If no NUMERIC FUZZ setting has been given, FUZZ() returns 0 by 
  8183. default.  This means that the 0 digits are ignored during a comparison 
  8184. operation. 
  8185.  
  8186.  
  8187. ΓòÉΓòÉΓòÉ 14.2.7. Powers (** Operator) ΓòÉΓòÉΓòÉ
  8188.  
  8189. The operator ** means raised to the whole-number power of. For example: 
  8190.  
  8191.  2**1 = 2       =  2  (2 to the power of 1) 
  8192.  2**2 = 2*2     =  4  (2 to the power of 2, or 2 squared) 
  8193.  2**3 = 2*2*2    =  8  (2 to the power of 3, or 2 cubed) 
  8194.  2**4 = 2*2*2*2  = 16  (2 to the power of 4). 
  8195.  
  8196.  As in ordinary algebra: 
  8197.  
  8198.  2**0   = 1 
  8199.  2**-1 = 1/(2**1) = 0.5  (2 to the power of minus 1) 
  8200.  2**-2 = 1/(2**2) = 0.25 (2 to the power of minus 2). 
  8201.  
  8202.  Note:  The number on the right of the ** must be a whole number. :enote. 
  8203.  
  8204.  In the order of precedence built into REXX, the powers (**) operator comes 
  8205.  below the prefix operators and above the multiply and divide operators.  For 
  8206.  example: 
  8207.  
  8208.   say -5**2        /* displays '25'.  Same as (-5)**2         */
  8209.   say 10**3/2**2   /* displays '250'.  Same as (10**3)/(2**2) */
  8210.  
  8211.  
  8212. ΓòÉΓòÉΓòÉ 14.2.7.1. Test Yourself ΓòÉΓòÉΓòÉ
  8213.  
  8214.   1. Examine the program shown in Figure "EXPONENT.CMD". 
  8215.  
  8216.  
  8217.           EXPONENT.CMD
  8218.  
  8219.           /* Example of a negative exponent */
  8220.           if 2 ** -3 = 1/(2**3) then say "True"
  8221.           else say "False"
  8222.  
  8223.      a. What is displayed on the screen when you run this program? 
  8224.      b. Are the parentheses in this expression really necessary? 
  8225.  
  8226.   2. What value is computed for the expression: 
  8227.  
  8228.           say      9 ** (1/2)
  8229.  
  8230.  
  8231. ΓòÉΓòÉΓòÉ 14.2.7.1.1. Answers ΓòÉΓòÉΓòÉ
  8232.  
  8233.   1. In EXPONENT.CMD 
  8234.  
  8235.      a. The word True is displayed on the screen. 
  8236.      b. No.  The ** operator has a higher priority than the / operator, so REXX 
  8237.         evaluates the expression in the same way if the parentheses were 
  8238.         removed. 
  8239.  
  8240.   2. The result is a syntax error.  The decimal form (9 ** 0.5) does not work 
  8241.      either.  True, in mathematics, x to the power of 1/2 means the square root 
  8242.      of x.  But in REXX, the ** operator must be followed by a whole number or 
  8243.      by an expression that, when evaluated, gives a whole number. 
  8244.  
  8245.  
  8246. ΓòÉΓòÉΓòÉ 14.2.8. A Square-Root Function ΓòÉΓòÉΓòÉ
  8247.  
  8248. Figure "SQRT.CMD" shows an example of a SQRT() function written as a REXX 
  8249. program. 
  8250.  
  8251.  
  8252. SQRT.CMD
  8253.  
  8254. /* The SQUARE ROOT function                             */
  8255. /*                                                      */
  8256. /*                SQRT(number)                          */
  8257. /*                                                      */
  8258. /* where "number" is a non-negative REXX number,        */
  8259. /* returns the square root of "number".  Precision is   */
  8260. /* nine significant figures, independent of the setting */
  8261. /* of NUMERIC DIGITS (explained on page Changing Precision).          */
  8262. /*                                                      */
  8263. /* Implementation details:  "number" is normalized to   */
  8264. /* give an even exponent (so that the exponent can be   */
  8265. /* dealt with separately later) and a mantissa between  */
  8266. /* 1 and 100.  The most significant digit of the result */
  8267. /* is found.                                            */
  8268. /*                                                      */
  8269. /* The mantissa is multiplied by 100, the exponent is   */
  8270. /* reduced by 2 to compensate, the partial result       */
  8271. /* (ROOT) is multiplied by 10 (leaving a 0 in the       */
  8272. /* units position) and the units digit of this partial  */
  8273. /* result is then found, and so on.                     */
  8274. /*                                                      */
  8275. /* Finally, the result is adjusted using the computed   */
  8276. /* exponent.                                            */
  8277.  
  8278. /*------------------------------------------------------*/
  8279. /* Set precision                                        */
  8280. /*------------------------------------------------------*/
  8281. numeric digits 10             /* for partial results    */
  8282.                               /* use one digit more     */
  8283.                               /* than final precision   */
  8284. /*------------------------------------------------------*/
  8285. /* Check arguments                                      */
  8286. /*------------------------------------------------------*/
  8287. if arg() \= 1
  8288.    then return                /* wrong number arguments */
  8289. arg x
  8290. if \ datatype(x,number)
  8291.    then return                /* argument not a number  */
  8292. if x < 0
  8293.    then return                /* argument is negative   */
  8294.  
  8295.                                      /* continued ...   */
  8296.  
  8297. /*------------------------------------------------------*/
  8298. /* Normalize:                                           */
  8299. /* FROM                                                 */
  8300. /*    x      the argument                               */
  8301. /* COMPUTE                                              */
  8302. /*    mant   the mantissa, where 0 < mant < 100         */
  8303. /*    exp    the exponent, where exp is even            */
  8304. /*------------------------------------------------------*/
  8305.                         /* Format so that 0 < mant < 10 */
  8306. parse value format(x,,,,0) with  mant "E" exp
  8307.  
  8308.                         /* Modify so that exp is even   */
  8309. if exp = "" then exp = 0
  8310. if exp//2 \= 0 then do
  8311.    mant = mant * 10
  8312.    exp = exp - 1
  8313. end
  8314.  
  8315. /*------------------------------------------------------*/
  8316. /* Find root by successive approximation                */
  8317. /*------------------------------------------------------*/
  8318. root = 0
  8319. do 10
  8320.   do digit = 9 by -1 to 0,      /* find largest digit,  */
  8321.      while,                     /* such that            */
  8322.        (root + digit)**2 > mant /* (root+digit)squared  */
  8323.   end                           /*          is \>  mant*/
  8324.   root = root + digit
  8325.   if root**2 = mant then leave
  8326.   root = root * 10
  8327.   mant = mant * 100
  8328.   exp = exp - 2
  8329. end
  8330.  
  8331. /*------------------------------------------------------*/
  8332. /* Adjust for computed exponent                         */
  8333. /*------------------------------------------------------*/
  8334. numeric digits 9
  8335. return root * 10**(exp/2)
  8336.  
  8337.  
  8338. ΓòÉΓòÉΓòÉ 15. Input and Output ΓòÉΓòÉΓòÉ
  8339.  
  8340. REXX can do more than manipulate the information that the user has typed at the 
  8341. keyboard and then process it for display on the screen. REXX can store, access, 
  8342. print, and organize data outside the program. 
  8343.  
  8344.  
  8345. ΓòÉΓòÉΓòÉ 15.1. Basics ΓòÉΓòÉΓòÉ
  8346.  
  8347.      In this chapter: Basics 
  8348.  
  8349.      o A stream of information 
  8350.      o Text file processing 
  8351.      o Writing data to a file 
  8352.      o Reading data from a file 
  8353.      o Printing a text file. 
  8354.  
  8355.  
  8356. ΓòÉΓòÉΓòÉ 15.1.1. A Stream of Information ΓòÉΓòÉΓòÉ
  8357.  
  8358. In computing, the form in which information comes is often as important as its 
  8359. content.  A spreadsheet file, for example, contains not only the numbers and 
  8360. formulas put into it, but a good deal of other information that you never see, 
  8361. such as information about the structure of the file.  This additional data 
  8362. describes how the file is organized and how it is stored and displayed. 
  8363.  
  8364. The structure of a spreadsheet file is very different from that of a document 
  8365. formatted by a word processor.  Information takes on other forms when it moves 
  8366. among the various devices in a system: the keyboard, the display, the printer, 
  8367. and so on. 
  8368.  
  8369. The goal of the REXX language is to keep things as simple as possible. 
  8370. Therefore, REXX takes the simplest possible view of the information it 
  8371. receives.  The simplest way to look at information is one character at a time. 
  8372. REXX sees external information as a stream, a long, single-file row of 
  8373. characters. 
  8374.  
  8375. For example, in a REXX program that reads from a text file and then sends the 
  8376. text to a printer, both the file and the device to which the printer is 
  8377. connected are character streams: 
  8378.  
  8379.                                Input stream JAB.TXT
  8380.  
  8381.                                ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ╤Ç
  8382.                                Γöétext fileΓöé
  8383.                                Γöé(JAB.TXT)╤ÄΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ╤Ç
  8384.                                ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ                                Γöé
  8385.                                ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ╤Ç                                Γöé
  8386.                                Γöé a REXX  Γöé                                Γöé
  8387.                                Γöé         Γöé                                Γöé
  8388.                                Γöé program ΓöéΓöÇΓöÇΓöÇslithyΓöÇtovesΓöÇdidΓöÇgyreΓöÇand...ΓöÇ
  8389.      ΓöÇΓöÇTwasΓöÇbrilligΓöÇandΓöÇtheΓöÇΓöÇΓöÇ╨ö         Γöé
  8390.      Γöé                         ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  8391.      Γöé                         ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ╤Ç
  8392.      ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöé printer Γöé
  8393.                                Γöé  (PRT)  Γöé
  8394.                                ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  8395.  
  8396.       Output stream PRT
  8397.  
  8398. In the preceding diagram: 
  8399.  
  8400.  o The text file being read (JAB.TXT) is the input stream. 
  8401.  o The printer device written to (PRT) is the output stream. 
  8402.  
  8403.  In this discussion, a stream means any source or destination of external 
  8404.  information used by a REXX program.  A stream can be a disk file, the input 
  8405.  from the keyboard or a data port, or the output to a printer or display. 
  8406.  
  8407.  In certain instances, as with text files, REXX can work with a stream in 
  8408.  entire lines of data; that is, as strings of characters separated by carriage 
  8409.  returns.  For example: 
  8410.  
  8411.                             lines
  8412.  
  8413.  
  8414.   line 1ΓöÇΓöÇΓöÇ
  8415.   ΓöÇΓöÇΓöÇΓöÇline2ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  8416.   ΓöÇΓöÇΓöÇΓöÇline3ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  8417.   line4ΓöÇΓöÇΓöÇ
  8418.   Twas brilligoAnd the slithy tovesodid gyre and gimbleoin the wabeoall mi
  8419.                                                                 
  8420.               ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  8421.  
  8422.                        carriage returns
  8423.  
  8424.  REXX can arrange these lines into ordered lists, called queues. 
  8425.  
  8426.  The input and output operations of REXX fall into these broad categories: 
  8427.  
  8428.  o Streams of characters 
  8429.  o Lines, or segments of a stream, separated by carriage returns 
  8430.  o Queues, which are ordered lists of lines. 
  8431.  
  8432.  The way you use data streams in a program depends upon the kind of information 
  8433.  you are working with and what you want to do with it. 
  8434.  
  8435.  
  8436. ΓòÉΓòÉΓòÉ 15.1.2. Text File Processing ΓòÉΓòÉΓòÉ
  8437.  
  8438. You begin text file processing by putting line data into more or less permanent 
  8439. form, such as in simple text files on disk.  You already know some ways to 
  8440. create, read, and write disk files, either through application programs, such 
  8441. as your text editor, or through the OS/2 program. 
  8442.  
  8443. In REXX, file processing is performed with a set of stream functions that read 
  8444. and write data a single character at a time or line-by-line.  Because text 
  8445. files are usually organized into lines, the first function you try is one that 
  8446. writes in lines. 
  8447.  
  8448.  
  8449. ΓòÉΓòÉΓòÉ 15.1.2.1. LINEOUT() Function ΓòÉΓòÉΓòÉ
  8450.  
  8451. To write a line of text to a file, use the LINEOUT() function. For example: 
  8452.  
  8453. lineout(stream,linedata)
  8454. where: 
  8455.  
  8456.  stream    is name of the file (that REXX regards as a stream) to which the 
  8457.            text is written. 
  8458.  
  8459.  linedata  is a line of text (or any data) to be written. 
  8460.  
  8461.  The first time a program uses LINEOUT() in this way, the named stream is 
  8462.  opened for writing and the line linedata is written to the end of the stream. 
  8463.  
  8464.  The stream remains open, and each subsequent LINEOUT() call writes a new line 
  8465.  to the end of stream. 
  8466.  
  8467.  When the program ends, REXX automatically closes stream. Or, you can close 
  8468.  stream explicitly at any time by omitting the linedata argument.  For example: 
  8469.  
  8470.   lineout(stream)
  8471.  
  8472.  
  8473. ΓòÉΓòÉΓòÉ 15.1.2.2. Calling LINEOUT() ΓòÉΓòÉΓòÉ
  8474.  
  8475. LINEOUT() is a function call rather than a keyword instruction. That means that 
  8476. it not only performs a given task (writing data to a file, in this example), 
  8477. but that it also returns a value of: 
  8478.  
  8479.  o 0 if linedata was successfully written to stream. 
  8480.  
  8481.  o 1 if for any reason linedata could not be written. For example, if you try 
  8482.    to write to a read-only file. 
  8483.  
  8484.  The return value can be used by your program to detect whether something has 
  8485.  gone wrong in the course of writing to a stream. 
  8486.  
  8487.  Note:  If you use LINEOUT() without the linedata argument, the return value 
  8488.  tells you if stream was successfully closed. :enote. 
  8489.  
  8490.  LINEOUT() is a function call; therefore, you have a choice about how you can 
  8491.  use it.  You can call LINEOUT: 
  8492.  
  8493.  o As part of a REXX instruction.  For example, with the keyword SAY: 
  8494.  
  8495.       say lineout("mybook.txt","Chapter 1.")  /* displays "0" if successful */
  8496.  
  8497.    or as a variable assignment: 
  8498.  
  8499.       ready = lineout("mybook.txt","Chapter 1.") /* assigns "0" to READY   */
  8500.                                 /* if successful          */
  8501.  
  8502.  o As a subroutine with arguments (this is true of all function calls). For 
  8503.    example: 
  8504.  
  8505.       call lineout "mybook.txt", "Chapter 1."
  8506.  
  8507.  When you use LINEOUT() (or any function call) in this way, the return value of 
  8508.  the function is automatically assigned to the REXX variable RESULT.  For more 
  8509.  information about calling functions in this way, see Using a Call of the Other 
  8510.  Kind. 
  8511.  
  8512.  
  8513. ΓòÉΓòÉΓòÉ 15.1.3. Writing Data to a File ΓòÉΓòÉΓòÉ
  8514.  
  8515. Figure "EDDY.CMD" shows an example of a simple text editor.  It only writes new 
  8516. text to a file.  Look closely at how the LINEOUT() function is used. 
  8517.  
  8518.  
  8519. EDDY.CMD
  8520.  
  8521. /* World's smallest editor */
  8522. say "Type file name"
  8523. pull filename
  8524. say "Type as many lines as you like.",
  8525.     "To finish, press the Enter key only."
  8526. do forever
  8527.    parse pull line
  8528.  
  8529.  
  8530.    if line = "" then           /* empty line?           */
  8531.       do
  8532.          call lineout filename /* if so, close the file */
  8533.          exit                   /* and end the program   */
  8534.          end
  8535.  
  8536.  
  8537.    /* otherwise, write LINE to the end of the file */
  8538.    call lineout filename, line
  8539.    if result = 1 then leave
  8540. end
  8541. say "Error, return code" result
  8542. exit
  8543.  
  8544. The user types a file name, which is then parsed by the PULL instructions and 
  8545. stored in the variable filename. As each line is typed: 
  8546.  
  8547.  o The PARSE PULL instruction stores it as a string in the variable line. 
  8548.  
  8549.  o The LINEOUT() function (called as a subroutine) writes the string contained 
  8550.    in line to the file name stored in the variable filename. 
  8551.  
  8552.  o The DO loop continues until the user presses the Enter key twice, thereby 
  8553.    entering a null string. 
  8554.  
  8555.  o The program then calls LINEOUT() with only the filename (closing the file), 
  8556.    and then exits. 
  8557.  
  8558.  
  8559. ΓòÉΓòÉΓòÉ 15.1.4. Reading Data from a File ΓòÉΓòÉΓòÉ
  8560.  
  8561. To read the file and display the data on the screen, you could use the OS/2 
  8562. command TYPE.  Use a REXX program to add some extra features. 
  8563.  
  8564.  
  8565. ΓòÉΓòÉΓòÉ 15.1.4.1. LINEIN() Function ΓòÉΓòÉΓòÉ
  8566.  
  8567. To read a line from a stream into a REXX program, use the LINEIN() function. 
  8568. For example: 
  8569.  
  8570. linein(stream)
  8571. where: 
  8572.  
  8573.  stream    is name of the data stream (such as a file) from which the line is 
  8574.            read. 
  8575.  
  8576.  The first time LINEIN() is called in a program, it opens the named stream and 
  8577.  returns the first line of data.  The second time it is called, it reads the 
  8578.  second line and returns the second line of data, and so on until the program 
  8579.  ends (or you close the stream with LINEOUT()).  In other words, LINEIN() keeps 
  8580.  track of its place in the stream with a kind of bookmark, called the read 
  8581.  position.  LINEOUT() uses a similar marker, called the write position.  For 
  8582.  more information, see Accessing Data within a Stream. 
  8583.  
  8584.  LINEIN() has no way of knowing when there are no more lines to read in a 
  8585.  stream, such as when it gets to the end of a text file.  To know when the read 
  8586.  position has reached the end of the file, use the LINES() function. 
  8587.  
  8588.  
  8589. ΓòÉΓòÉΓòÉ 15.1.4.2. LINES() Function ΓòÉΓòÉΓòÉ
  8590.  
  8591. To find out if any lines remain between the read position and the end of a 
  8592. stream, the function, lines(stream), returns: 
  8593.  
  8594.  0         if no complete lines remain to be read 
  8595.  
  8596.  1         if any lines remain. 
  8597.  
  8598.  Figure "SHOLIN1.CMD" shows an example, where stream is a text file , so 
  8599.  LINES() would return 0 when the end of the file has been reached. 
  8600.  
  8601.  
  8602.   SHOLIN1.CMD
  8603.  
  8604.   /* Program to display an entire file */
  8605.   /* exits when end-of-file is reached */
  8606.  
  8607.   say "Type a file name"         /* get the name of the file           */
  8608.   pull filename                   /* from the user                     */
  8609.  
  8610.   lineno = 1                      /* initialize a counter to display   */
  8611.                                   /* the line number
  8612.  
  8613.   do until lines(filename) = 0    /* repeat this loop until no lines   */
  8614.                                   /* remain in the selected file...    */
  8615.  
  8616.      say lineno linein(filename)  /* display the line number, and then */
  8617.                                   /* read and display a line of text,  */
  8618.                                   /* advancing the read position       */
  8619.                                   /* with each pass though the loop    */
  8620.  
  8621.      lineno = lineno + 1          /* increment the line-number counter */
  8622.  
  8623.      end
  8624.   exit                            /* end the program                   */
  8625.  
  8626.  
  8627. ΓòÉΓòÉΓòÉ 15.1.4.3. Resetting the Read Position ΓòÉΓòÉΓòÉ
  8628.  
  8629. Have the user select how many lines are displayed.  If a number larger then the 
  8630. number of lines in the file is typed, the program cycles back to the beginning. 
  8631. To do this, use LINEIN() with its second and third arguments.  For example: 
  8632.  
  8633. linein(stream,position,count)
  8634. where: 
  8635.  
  8636.  stream    is the name of the stream from which the line is read. 
  8637.  
  8638.  position  is the new position for the read position.  The options are: 
  8639.  
  8640.     o no argument (the default)-to leave the read position where it is. 
  8641.     o 1-to set the read position to the beginning of the stream (line 1). 
  8642.  
  8643.  count     is whether or not to actually read a line.  The options are: 
  8644.  
  8645.     o 1 (the default)-to read one line and advance the read position. 
  8646.     o 0-to read no lines and not advance the read position. 
  8647.  
  8648.  So far, LINEIN() has been used with the default values for the second and 
  8649.  third arguments to simply read the next line.  By setting 1 for the position 
  8650.  and 0for the count, LINEIN() can be used to reset the read position to the 
  8651.  beginning of the stream without reading a line (or advancing the read 
  8652.  position).  For example: 
  8653.  
  8654.   linein(filename,1,0)
  8655.  
  8656.  Since you are not interested in the return value (which would be empty 
  8657.  anyway), you can call LINEIN() as a subroutine: 
  8658.  
  8659.   call linein filename,1,0
  8660.  
  8661.  Figure "SHOLIN2.CMD" shows an example calling LINEIN() as a subroutine to 
  8662.  reset the read position. 
  8663.  
  8664.  
  8665.   SHOLIN2.CMD
  8666.  
  8667.   /* Displays a given number of lines in a text file   */
  8668.   /* If the given number exceeds the number of lines   */
  8669.   /* in the file then the read position is reset back  */
  8670.   /* to the beginning of the file                      */
  8671.  
  8672.   say "Type a file name"
  8673.   pull filename
  8674.  
  8675.   say "Type number of lines to display"
  8676.   pull howmany
  8677.  
  8678.   lineno = 1
  8679.   do howmany
  8680.      say lineno linein(filename)
  8681.      lineno = lineno + 1
  8682.  
  8683.      if lines(filename) = 0 then     /* if the end of file is reached */
  8684.        do
  8685.           call linein filename,1,0   /* reset the read position       */
  8686.           say ">>> End of File <<<"  /* display end-of-file marker    */
  8687.           lineno = 1                 /* reset line counter            */
  8688.           end
  8689.      end
  8690.   exit
  8691.  
  8692.  
  8693. ΓòÉΓòÉΓòÉ 15.1.5. Printing a Text File ΓòÉΓòÉΓòÉ
  8694.  
  8695. Using REXX to send data to a printer is very similar to writing to a file. 
  8696. There are some things you need to know: 
  8697.  
  8698.  o The name of the device that your computer is connected. Use this device name 
  8699.    in place of a file name. In Figure "PRINTIT.CMD", the printer device is 
  8700.    named PRN. 
  8701.  
  8702.  o The control characters and escape sequences that your printer uses for 
  8703.    various formatting operations.  Generally, these are listed in the manual 
  8704.    for the printer.  The example uses the standard character for a form feed, 
  8705.    which directs the printer to start a new page. 
  8706.  
  8707.  
  8708. ΓòÉΓòÉΓòÉ 15.1.5.1. Sending Special Characters ΓòÉΓòÉΓòÉ
  8709.  
  8710. Printers often use certain characters as controls, such as ESC (escape) and FF 
  8711. (form feed) that you cannot type from the keyboard. To use these characters, 
  8712. you need to look up the ASCII number of the character.  Then, you can use the 
  8713. built-in REXX function D2C() (decimal-to-character) to translate the ASCII code 
  8714. number into the character you need. 
  8715.  
  8716. For example, the character that tells the printer to start a new page is ASCII 
  8717. number 12.  To translate that code number 12 into a character for the printer 
  8718. use, you would write, d2c(12). 
  8719.  
  8720. For more information about functions such as D2C(), see Using Functions to 
  8721. Convert Data. 
  8722.  
  8723.  
  8724. ΓòÉΓòÉΓòÉ 15.1.5.2. CHAROUT() Function ΓòÉΓòÉΓòÉ
  8725.  
  8726. Generally, the CHAROUT() function is most useful for issuing printer controls. 
  8727.  
  8728. CHAROUT(stream,string)
  8729. where: 
  8730.  
  8731.  stream    is the name of the stream to which the character is written. Figure 
  8732.            "PRINTIT.CMD" shows an example where stream is the name of the 
  8733.            device connected to a printer. 
  8734.  
  8735.  string    is a string-the characters to be written. 
  8736.  
  8737.  Like the LINEOUT function, CHAROUT() returns 0 if all the characters in string 
  8738.  are successfully written to stream. Unlike LINEOUT(), if for any reason 
  8739.  CHAROUT() cannot write to the named stream, it returns the number of 
  8740.  characters that remain unwritten. 
  8741.  
  8742.  CHAROUT() is also similar to LINEOUT() in that it is more convenient to call 
  8743.  it as a subroutine.  For example, to tell the printer to start a new page, you 
  8744.  could use call charout "PRN",d2c(12). 
  8745.  
  8746.  
  8747. ΓòÉΓòÉΓòÉ 15.1.5.3. A Printout Program ΓòÉΓòÉΓòÉ
  8748.  
  8749. Figure "PRINTIT.CMD" shows an example of a program for printing a file. 
  8750.  
  8751.  
  8752. PRINTIT.CMD
  8753.  
  8754. /* Prints a text file */
  8755. say 'Type file name: '           /* prompt for a file name             */
  8756. pull filename                     /* ...and get it from the user       */
  8757.  
  8758. printer = 'PRN:'                  /* save name of printer device       */
  8759. newpage = d2c(12)                 /* save page-eject character         */
  8760.  
  8761. /* Repeat this loop until no lines remain in the file */
  8762. /* and keep track of the line count with COUNT        */
  8763.  
  8764. do count = 1 until lines(filename) = 0
  8765.  
  8766. /* Read a line from the file ...  */
  8767.  
  8768.    output =  linein(filename)
  8769.  
  8770. /* ... and send it to the printer */
  8771.  
  8772.    call lineout printer, output
  8773.  
  8774.    if result <> 0 then                             /* if there is a  */
  8775.       do                                           /* write error,   */
  8776.          say 'Error: unable to write to printer'   /* display it, and*/
  8777.          leave                                     /* exit the loop  */
  8778.          end
  8779.  
  8780.    if count // 50 = 0 then                 /* if the line count is a */
  8781.       call charout printer, newpage        /* multiple of 50, then   */
  8782.                                            /* start a new page by    */
  8783.                                            /* sending the form feed  */
  8784.  
  8785.    end                            /* go back to the start of loop    */
  8786.                                   /* until no lines remain           */
  8787.  
  8788. call lineout filename             /* close the file                  */
  8789. exit                              /* end the program normally        */
  8790.  
  8791.  
  8792. ΓòÉΓòÉΓòÉ 15.1.5.4. To Summarize ΓòÉΓòÉΓòÉ
  8793.  
  8794. Here is a review the input and output functions that have been used so far. 
  8795.  
  8796. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  8797. Γöé USE THIS FUNCTION                      Γöé TO DO THIS                            Γöé
  8798. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8799. Γöé "LINEOUT(STREAM,LINEDATA)"             Γöé To open "stream" and append           Γöé
  8800. Γöé                                        Γöé "linedata" (write it to the end of    Γöé
  8801. Γöé                                        Γöé "stream").  Returns "1" if suc-       Γöé
  8802. Γöé                                        Γöé cessful; "0" if otherwise.            Γöé
  8803. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8804. Γöé                                        Γöé                                       Γöé
  8805. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8806. Γöé "LINEOUT(STREAM)"                      Γöé To close "stream" when writing is     Γöé
  8807. Γöé                                        Γöé completed.  Returns "1" if suc-       Γöé
  8808. Γöé                                        Γöé cessful; "0" if otherwise.  (REXX     Γöé
  8809. Γöé                                        Γöé automatically closes any open streams Γöé
  8810. Γöé                                        Γöé at the end of a program.)             Γöé
  8811. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8812. Γöé                                        Γöé                                       Γöé
  8813. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8814. Γöé "LINEIN(STREAM)" or"                   Γöé To open "stream", read the first line Γöé
  8815. Γöé LINEIN(STREAM,,1)"                     Γöé and advance the read position to the  Γöé
  8816. Γöé                                        Γöé second line.                          Γöé
  8817. Γöé                                        Γöé                                       Γöé
  8818. Γöé                                        Γöé If "stream" is already open, then     Γöé
  8819. Γöé                                        Γöé LINEIN() reads the current line and   Γöé
  8820. Γöé                                        Γöé advances the read position one line   Γöé
  8821. Γöé                                        Γöé ahead.                                Γöé
  8822. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8823. Γöé                                        Γöé                                       Γöé
  8824. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8825. Γöé "LINEIN(STREAM,1,0)"                   Γöé To put the write position at the      Γöé
  8826. Γöé                                        Γöé beginning of the "stream" without     Γöé
  8827. Γöé                                        Γöé reading a line or advancing the read  Γöé
  8828. Γöé                                        Γöé position.                             Γöé
  8829. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8830. Γöé                                        Γöé                                       Γöé
  8831. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  8832.  
  8833. Although not discussed in this chapter, you can also: 
  8834.  
  8835. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  8836. Γöé USE THIS FUNCTION                      Γöé TO DO THIS                            Γöé
  8837. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8838. Γöé "LINEIN(STREAM,1,1)"                   Γöé To put the write position at the      Γöé
  8839. Γöé                                        Γöé beginning of the "stream" and specif- Γöé
  8840. Γöé                                        Γöé ically read the first line (advancing Γöé
  8841. Γöé                                        Γöé the read position to the second       Γöé
  8842. Γöé                                        Γöé line). The action is the same whether Γöé
  8843. Γöé                                        Γöé or not "stream" is already open.      Γöé
  8844. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8845. Γöé                                        Γöé                                       Γöé
  8846. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8847. Γöé "LINEIN(STREAM,,0)"                    Γöé To open "stream" without reading the  Γöé
  8848. Γöé                                        Γöé first line or advancing the read      Γöé
  8849. Γöé                                        Γöé position.  No action is taken if      Γöé
  8850. Γöé                                        Γöé "stream" is already open.             Γöé
  8851. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  8852.  
  8853. Figure "Read and Write Functions" is a table showing the REXX functions that 
  8854. read from and write to a data stream. 
  8855.  
  8856.  
  8857. Read and Write Functions
  8858.  
  8859. ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
  8860. Γöé                   Γöé READ               Γöé WRITE             Γöé CHECK FOR         Γöé
  8861. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8862. Γöé CHARACTERS        Γöé CHARIN()           Γöé CHAROUT()         Γöé CHARS()           Γöé
  8863. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8864. Γöé LINES             Γöé LINEIN()           Γöé LINEOUT()         Γöé LINES()           Γöé
  8865. Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
  8866. ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
  8867.  
  8868.  
  8869. ΓòÉΓòÉΓòÉ 15.1.5.5. STREAM() Function ΓòÉΓòÉΓòÉ
  8870.  
  8871. You can use the STREAM() function to get the following information about a 
  8872. stream: 
  8873.  
  8874.  o To determine if a stream exists 
  8875.  o To determine if a stream is ready for input or output 
  8876.  o To get the size or last edit date of a file. 
  8877.  
  8878.  You can also use STREAM() for more complex input and output tasks, as when 
  8879.  your program must read from or write to: 
  8880.  
  8881.  o Files other than text files 
  8882.  o Streams other than files and printers 
  8883.  o A specific position in a stream. 
  8884.  
  8885.  See STREAM() Function for examples of STREAM(). 
  8886.  
  8887.  
  8888. ΓòÉΓòÉΓòÉ 15.1.6. Queues ΓòÉΓòÉΓòÉ
  8889.  
  8890. A queue is a means of holding a list of lines in a specific order. 
  8891.  
  8892. A queue in REXX combines the functions of a stack (in which the last item added 
  8893. is the first read) and a queue (in which the first item added is the first 
  8894. read).  That is, it can be either last in, first out (LIFO) or first in, first 
  8895. out (FIFO). 
  8896.  
  8897. The REXX concept of a queue is different from that generally used. Throughout 
  8898. this book, the REXX definition a of queue is used. 
  8899.  
  8900. One particular advantage of using a queue is that it lets your REXX programs 
  8901. share data with other programs when those programs are written in REXX or any 
  8902. other language. 
  8903.  
  8904. Data in a queue is held as a series of lines.  Thus, data can only be put on or 
  8905. taken off a queue one line at a time.  A line of data can be added to the back 
  8906. or to the front of a queue, but a line of data can only be taken off from the 
  8907. front. 
  8908.  
  8909. The queue is external to REXX.  Unlike variables, a queue remains even after 
  8910. your REXX program ends.  Once created, it is retained for the duration of the 
  8911. current OS/2 session or until you delete it.  This means that other programs 
  8912. can add or remove data from the queue whenever your REXX program allows. 
  8913.  
  8914.  
  8915. ΓòÉΓòÉΓòÉ 15.1.6.1. Lists of Data ΓòÉΓòÉΓòÉ
  8916.  
  8917. The difference between LIFO and FIFO is significant.  Think of a queue as a 
  8918. list that you can add to from either end.  You can add items on the back of the 
  8919. queue using the QUEUE instruction, or you can add items on the front of the 
  8920. queue, using the PUSH instruction. 
  8921.  
  8922. You could picture it like this: 
  8923.  
  8924.       back                    front
  8925.          ΓöîΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÉ
  8926.          Γöé  Γöé        Γöé  Γöé  Γöé  Γöé
  8927. QUEUEΓöÇΓöÇΓöÇΓöé  Γöé  . . . Γöé  Γöé  Γöé  Γöé
  8928.          Γöé  Γöé        Γöé  Γöé  Γöé  ΓöéΓöéΓöÇΓöÇΓöÇΓöÇPUSH
  8929.          Γöé  Γöé        Γöé  Γöé  Γöé  Γöé
  8930.          ΓööΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÿ
  8931.  
  8932. The concept of a queue having a front and a back is important, because you can 
  8933. only read items from the front of the queue.  The command that reads data from 
  8934. a queue is the PULL instruction. 
  8935.  
  8936. Now you could picture it like this: 
  8937.  
  8938.       back                    front
  8939.          ΓöîΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÉ
  8940.          Γöé  Γöé        Γöé  Γöé  Γöé  Γöé
  8941.          Γöé  Γöé        Γöé  Γöé  Γöé  ΓöéΓöéΓöÇΓöÇΓöÇΓöÇPUSH
  8942. QUEUEΓöÇΓöÇΓöÇΓöé  Γöé  . . . Γöé  Γöé  Γöé  Γöé
  8943.          Γöé  Γöé        Γöé  Γöé  Γöé  ΓöéΓöÇΓöÇΓöÇΓöÇPULL
  8944.          ΓööΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÿ
  8945.  
  8946.  
  8947. ΓòÉΓòÉΓòÉ 15.1.6.2. Putting Data on a Queue ΓòÉΓòÉΓòÉ
  8948.  
  8949. The QUEUE instruction puts an item of data on the queue in FIFO order: 
  8950.  
  8951.       back                    front
  8952.          ΓöîΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÉ
  8953.          Γöé  Γöé  Γöé  Γöé  Γöé  Γöé  Γöé  Γöé
  8954. QUEUEΓöÇΓöÇΓöÇΓöé7 Γöé6 Γöé5 Γöé4 Γöé3 Γöé2 Γöé1 Γöé
  8955.          Γöé  Γöé  Γöé  Γöé  Γöé  Γöé  Γöé  ΓöéΓöéΓöÇΓöÇΓöÇΓöÇnext item
  8956.          Γöé  Γöé  Γöé  Γöé  Γöé  Γöé  Γöé  Γöé     to be read
  8957.          ΓööΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÿ
  8958.            Γöé                 Γöé
  8959. last itemΓöÇΓöÇΓöÿ     first itemΓöÇΓöÇΓöÿ
  8960.   added            added
  8961.  
  8962. The PUSH instruction puts an item of data on the queue in LIFO order: 
  8963.  
  8964.       back                    front
  8965.          ΓöîΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÉ
  8966.          Γöé  Γöé  Γöé  Γöé  Γöé  Γöé  Γöé  Γöé
  8967.          Γöé1 Γöé2 Γöé3 Γöé4 Γöé5 Γöé6 Γöé7 ΓöéΓöéΓöÇΓöÇΓöÇΓöÇPUSH
  8968.          Γöé  Γöé  Γöé  Γöé  Γöé  Γöé  Γöé  Γöé
  8969.          Γöé  Γöé  Γöé  Γöé  Γöé  Γöé  Γöé  ΓöéΓöéΓöÇΓöÇΓöÇΓöÇnext item
  8970.          ΓööΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÇΓö┤ΓöÇΓöÿ     to be read
  8971.            Γöé                 Γöé
  8972. first itemΓöÇΓöÿ       last itemΓöÇΓöÿ
  8973.   added              added
  8974.  
  8975.  
  8976. ΓòÉΓòÉΓòÉ 15.1.6.3. Reading the Queue ΓòÉΓòÉΓòÉ
  8977.  
  8978. Up to now, the PULL instruction has been used to collect user input, such as 
  8979. data typed at the keyboard, to store it into variables. 
  8980.  
  8981. What the PULL instruction actually parses is the next available line of data 
  8982. from the queue.  It is only when the queue is empty (as it has been so far) 
  8983. that PULL parses input from the keyboard. 
  8984.  
  8985. Try the program shown in Figure "QUEUING.CMD". 
  8986.  
  8987.  
  8988. QUEUING.CMD
  8989.  
  8990. /* Using QUEUE and PULL */
  8991. QUEUE time()         /* add the current time to the queue  */
  8992. QUEUE date()         /* add the current date to the queue  */
  8993.  
  8994. PULL data1           /* get a string from the queue front  */
  8995. PULL data2           /* get a string from the queue front  */
  8996.  
  8997. say 'The first  element on the queue was:' data1
  8998. say 'The second element on the queue was:' data2
  8999.  
  9000. exit                 /* end the program normally           */
  9001.  
  9002. Change the program by substituting PUSH for QUEUE, see Figure "PUSHING.CMD". 
  9003.  
  9004.  
  9005. PUSHING.CMD
  9006.  
  9007. /* Using PUSH and PULL */
  9008. push time()            /* add the current time to the queue  */
  9009. push date()            /* add the current date to the queue  */
  9010.  
  9011. pull Data1             /* get a string from the queue front  */
  9012. pull Data2             /* get a string from the queue front  */
  9013.  
  9014. say 'The first  element on the queue was:' Data1
  9015. say 'The second element on the queue was:' Data2
  9016.  
  9017. exit                   /* end the program normally           */
  9018.  
  9019.  
  9020. ΓòÉΓòÉΓòÉ 15.1.6.4. QUEUED Function ΓòÉΓòÉΓòÉ
  9021.  
  9022. It would be useful to be able to determine how many items are on the queue at 
  9023. any given time.  That is the purpose of the REXX function QUEUED, see Figure 
  9024. "QCOUNT.CMD". 
  9025.  
  9026.  
  9027. QCOUNT.CMD
  9028.  
  9029. /* counting the queue */
  9030. push "manny"
  9031. push "moe"
  9032. push "mac"
  9033. count = queued()
  9034. say count "names in queue." /* displays '3 names in queue.' */
  9035.  
  9036. You will find that QUEUED is particularly useful for controlling a DO loop that 
  9037. pulls data from the queue, see Figure "DOQUEUE.CMD". 
  9038.  
  9039.  
  9040. DOQUEUE.CMD
  9041.  
  9042.   /* Find all DEVICE= lines in C:\CONFIG.SYS, put them in */
  9043.   /* the queue, and process them later                    */
  9044.   file = "C:\CONFIG.SYS"
  9045.   Do While Lines(file) > 0
  9046.   line = Linein(file)
  9047.   If Translate(Left(line,7)) = 'DEVICE=' Then Push line
  9048.   End
  9049.  
  9050.   Say 'There are' queued() 'DEVICE= lines in' file'.  Here they are
  9051.   Do queued()
  9052.   Parse Pull line
  9053.   Say line
  9054.   End
  9055.  
  9056.  
  9057. ΓòÉΓòÉΓòÉ 15.1.7. Summary ΓòÉΓòÉΓòÉ
  9058.  
  9059. This completes "Basics" in this chapter.  You have learned how to: 
  9060.  
  9061.  o Read and write disk files 
  9062.  o Send data to the printer 
  9063.  o Use the REXX data queue. 
  9064.  
  9065.  To make best use of the topics discussed in this chapter, see "Data Streams" 
  9066.  in the REXX Reference. 
  9067.  
  9068.  "Advanced Topics" in this chapter discusses more about input and output. 
  9069.  
  9070.  To continue with "Basics," go to page 11-1. 
  9071.  
  9072.  
  9073. ΓòÉΓòÉΓòÉ 15.2. Advanced Topics ΓòÉΓòÉΓòÉ
  9074.  
  9075.      In this chapter: Advanced Topics 
  9076.  
  9077.      o More about data streams 
  9078.      o Default streams 
  9079.      o STREAM() function 
  9080.      o Accessing data within a stream 
  9081.      o More about queues. 
  9082.  
  9083.  
  9084. ΓòÉΓòÉΓòÉ 15.2.1. More about Data Streams ΓòÉΓòÉΓòÉ
  9085.  
  9086. REXX regards all information from any file or device as a continuous stream of 
  9087. single characters.  Data read into a REXX program (whether from a disk file, 
  9088. the keyboard, a device, or another program) is processed equally as a character 
  9089. stream.  The same is true for output data that a REXX program writes to a file 
  9090. or other device. All of these are streams. 
  9091.  
  9092. Your program can work with the information in a stream as it is, 1 character at 
  9093. a time.  Or, if the data is in line form (as in a text file), you can 
  9094. manipulate the information from the stream (or put information into it) 
  9095. line-by-line. 
  9096.  
  9097. As shown in "Basics" in this chapter, your REXX programs can access and 
  9098. manipulate text files by using: 
  9099.  
  9100.  LINEIN()          to read a line 
  9101.  
  9102.  LINEOUT()         to write a line 
  9103.  
  9104.  LINES()           to check for the end of the stream 
  9105.  
  9106.  CHARIN()          to read 1 or more characters 
  9107.  
  9108.  CHAROUT()         to write 1 or more characters 
  9109.  
  9110.  CHARS()           to count the characters remaining in the stream. 
  9111.  
  9112.  
  9113. ΓòÉΓòÉΓòÉ 15.2.2. Default Streams ΓòÉΓòÉΓòÉ
  9114.  
  9115. Each of the I/O functions listed here has as its first argument the name of a 
  9116. stream that is read or written to.  Each of these functions also has a default 
  9117. stream that is used if you omit the name of a specific stream. STDIN is  the 
  9118. default input stream (for LINEIN() and CHARIN() functions).  STDIN is any data 
  9119. that is typed at the keyboard. 
  9120.  
  9121. This means that you can use the LINEIN() function to pause processing and read 
  9122. a line typed at the keyboard, as you can with the PARSE PULL instruction. But 
  9123. note these differences: 
  9124.  
  9125.  o Unlike PARSE PULL, the LINEIN() function reads only keyboard entries, 
  9126.    regardless of whether there are outstanding items on the default data queue. 
  9127.  
  9128.  o LINEIN() does not prompt the user with a question mark. 
  9129.  
  9130.  To understand how this works, use the first file-reading program, SHOLIN1.CMD 
  9131.  (see Figure "SHOLIN1.CMD") and add an instruction as shown in Figure 
  9132.  "SHOLIN3.CMD". 
  9133.  
  9134.  
  9135.   SHOLIN3.CMD
  9136.  
  9137.   /* Displays a file one line at a time           */
  9138.   /* as the user presses the Enter key; program   */
  9139.   /* ends when the end-of-file is reached         */
  9140.   /* OR if user types any character.              */
  9141.  
  9142.   say "Type a file name"
  9143.   pull filename
  9144.   lineno= 1
  9145.  
  9146.   do until lines(filename) = 0
  9147.      say lineno linein(filename)
  9148.      if linein() \= "" then leave   /* waits for user to press the Enter*/
  9149.                                      /* key; if anything else is typed */
  9150.                                      /* (if LINEIN() does not return  */
  9151.                                      /* an empty string), then the   */
  9152.                                      /* loop (and the program) ends   */
  9153.      lineno = lineno + 1
  9154.      end
  9155.   exit
  9156.  
  9157.  Or, you could modify the cycling version of this program, SHOLIN2.CMD (see 
  9158.  Figure "SHOLIN2.CMD") to let the user choose the number of lines to display. 
  9159.  To do this, put the display routine inside a DO FOREVER loop, as shown in 
  9160.  Figure "SHOLIN4.CMD". 
  9161.  
  9162.  
  9163.   SHOLIN4.CMD
  9164.  
  9165.   /* Displays a file one line at a time   */
  9166.   /* as the user presses the Enter key, or*/
  9167.   /* displays a given number of lines.    */
  9168.   /* Cycles back to the beginning of the  */
  9169.   /* file when the end-of-file is reached */
  9170.   /* Program ends only when user types    */
  9171.   /* any non-numeric character.           */
  9172.  
  9173.   say "Type a file name"
  9174.   pull filename
  9175.  
  9176.   say "Type a number of lines to display"
  9177.   say "or press the Enter key alone to advance one line"
  9178.   say "Type any other character to end."
  9179.   lineno = 1
  9180.  
  9181.   do forever
  9182.      howmany = linein()                 /* pause for user entry and store */
  9183.                                         /* it in the variable HOWMANY     */
  9184.  
  9185.      if howmany = "" then howmany = 1   /* pressing the Enter key alone   */
  9186.                                         /* is the same as typing '1'      */
  9187.  
  9188.      if \datatype(howmany,n) then leave/* typing any non-numeric         */
  9189.                                         /* character ends the program    */
  9190.  
  9191.      do howmany
  9192.         say lineno linein(filename)
  9193.         lineno = lineno + 1
  9194.  
  9195.         if lines(filename) = 0 then
  9196.           do
  9197.              call linein filename,1,0
  9198.              say ">>> End of File <<<"
  9199.              lineno = 1
  9200.              end
  9201.         end
  9202.  
  9203.      end
  9204.   exit
  9205.  
  9206.  
  9207. ΓòÉΓòÉΓòÉ 15.2.2.1. Parsing Default Input ΓòÉΓòÉΓòÉ
  9208.  
  9209. You can parse the input for individual words, either by using the instruction: 
  9210.  
  9211. PARSE VALUE linein() WITH var1 var2 ...
  9212. or with the shorter form built into the PARSE instruction: 
  9213.  
  9214. PARSE LINEIN var1 var2 ...
  9215.  
  9216. For more information about the PARSE instruction and its options, see Parsing. 
  9217. Also, see "Parsing" in the REXX Reference. 
  9218.  
  9219.  
  9220. ΓòÉΓòÉΓòÉ 15.2.3. STREAM() Function ΓòÉΓòÉΓòÉ
  9221.  
  9222. For more intricate and specialized input and output tasks, REXX provides 
  9223. another function called STREAM().  For example: 
  9224.  
  9225. STREAM(name,operation,command)
  9226. where: 
  9227.  
  9228.  name           is the stream you want to work on 
  9229.  
  9230.  operation      is one of these: 
  9231.  
  9232.     C  for a command or action to be taken 
  9233.     S  for the state of the stream 
  9234.     D  for a more detailed description. 
  9235.  
  9236.  command        is an action to perform.  This argument must be used when and 
  9237.                 only when you specify C as the operation. 
  9238.  
  9239.  The syntax may look a bit complicated at first, because STREAM() has a wide 
  9240.  variety of applications such as: 
  9241.  
  9242.  o The C (command) operation lets your program select and gain access to a 
  9243.    named stream. 
  9244.  
  9245.  o The operations S and D (state and description) report the current status of 
  9246.    a stream; that is, whether: 
  9247.  
  9248.     - the stream is READY or NOTREADY for input/output 
  9249.     - it is UNKNOWN (not yet identified) 
  9250.     - an input or output ERROR has occurred. 
  9251.  
  9252.  For the full syntax of STREAM() and the other REXX input and output functions, 
  9253.  see the REXX Reference. 
  9254.  
  9255.  
  9256. ΓòÉΓòÉΓòÉ 15.2.3.1. Getting Information about a Stream ΓòÉΓòÉΓòÉ
  9257.  
  9258. To determine if a particular stream exists, use the stream command QUERY EXIST 
  9259. with the STREAM() function call.  For example: 
  9260.  
  9261. stream(name,C,'query exists')
  9262.  
  9263. Note that the stream command is enclosed in matching quotes. 
  9264.  
  9265. If the stream name exists, then this function call returns the full-path 
  9266. specification of the stream.  For example: 
  9267.  
  9268. C:\WORK\MYFILE.TXT
  9269.  
  9270. If the stream name does not exist, then the result is a null string. 
  9271.  
  9272. Figure "QRYFILE1.CMD" shows an example of a program that reads a file. 
  9273.  
  9274.  
  9275. QRYFILE1.CMD
  9276.  
  9277. /* For a program that reads a file       */
  9278. say "Type a file name (or press the Enter key alone to exit): "
  9279. pull fname
  9280. if fname = "" then exit
  9281.  
  9282. /* Check that the file exists:           */
  9283. /* if STREAM() returns a null string,    */
  9284. /* then report the stream not found      */
  9285. /* and exit....                          */
  9286.  
  9287. call stream fname, C, 'query exists'
  9288. if result = "" then
  9289.    do
  9290.      say "Can not find" fname"."
  9291.      say "Check for proper path specification."
  9292.      exit
  9293.    end
  9294.  
  9295. /* ...else store the full pathname       */
  9296. /* (in RESULT) to the variable FNAME,    */
  9297. /* in case the user has typed a          */
  9298. /* relative path (e.g., "..\docs\my.txt" */
  9299.  
  9300. else fname = result
  9301. say "Full path specification is" fname
  9302.  
  9303. You can also query for information about the size of a stream and the date and 
  9304. time of the last edit, see Figure "QRYFILE2.CMD". 
  9305.  
  9306.  
  9307. QRYFILE2.CMD
  9308.  
  9309. /* How big and when last changed? */
  9310. say "Type a file name (or press the Enter key alone to exit): "
  9311. pull fname
  9312. .
  9313. .
  9314. .
  9315. bytes = stream(fname,c,'query size')
  9316. ledit = stream(fname,c,'query datetime')
  9317. say fname "is" bytes "bytes."
  9318. say "Last edit of" fname "was" ledit"."
  9319.  
  9320.  
  9321. ΓòÉΓòÉΓòÉ 15.2.3.2. Opening and Closing Streams ΓòÉΓòÉΓòÉ
  9322.  
  9323. The functions LINEOUT(), LINEIN(), CHARIN() and CHAROUT() do much of their own 
  9324. housekeeping.  They automatically open the streams they work on and leave REXX 
  9325. to close the stream at the end of a program. 
  9326.  
  9327. However, there are cases where it is necessary (or at least more prudent) to 
  9328. explicitly open and close a stream, such as in a program that reads from more 
  9329. than one device or one that writes to the middle of a file. 
  9330.  
  9331. This is done with the STREAM() function: 
  9332.  
  9333. stream(name,c,"open")
  9334.  
  9335. This default form opens a stream name for both reading and writing text.  To 
  9336. open a stream for: 
  9337.  
  9338.  o Writing only, add the word write.  For example: 
  9339.  
  9340.         stream(name,c,"open write")
  9341.  
  9342.  o Reading only, add the word read.  For example: 
  9343.  
  9344.         stream(name,c,"open read")
  9345.  
  9346.  When you open a stream in this way, STREAM() returns the string READY: if the 
  9347.  stream has been successfully opened.  An error message is returned if for any 
  9348.  reason it was unable to open the stream. 
  9349.  
  9350.  To explicitly close a stream, use: 
  9351.  
  9352.   stream(name,c,"close")
  9353.  
  9354.  In this form, STREAM() returns the string READY if the operation is 
  9355.  successful, the string ERROR if the operation fails. 
  9356.  
  9357.  
  9358. ΓòÉΓòÉΓòÉ 15.2.4. Accessing Data within a Stream ΓòÉΓòÉΓòÉ
  9359.  
  9360. REXX regards all external data as streams of information.  Nonetheless, these 
  9361. streams can take different forms.  A disk file, for example, differs from the 
  9362. output to a printer in that it has a static, physical form. A disk file is one 
  9363. example of a persistent stream.  This means a disk file can not only be read 
  9364. from its beginning or written to its end, it can be read from and written to 
  9365. any place between. 
  9366.  
  9367. As a program reads a file, REXX keeps a place marker, called the read position, 
  9368. that points to the next character (or line) to be read. 
  9369.  
  9370. The same is true when writing.  REXX maintains a write position that marks the 
  9371. next place it is to write. 
  9372.  
  9373. When both reading and writing a file, the read position and the write position 
  9374. are the same. The read position and the write position are always the same. 
  9375. When one moves, the other also moves. 
  9376.  
  9377. If you do not specify a position for these markers, REXX advances them, by 
  9378. default, the number of characters read or written. 
  9379.  
  9380. You can specify another position for the read or write positions by giving 
  9381. additional arguments to the stream functions, LINEIN(), LINEOUT(), CHARIN(), 
  9382. CHAROUT(), or by using the position option of the STREAM() function. For more 
  9383. information, refer to "Functions" in the REXX Reference. 
  9384.  
  9385.  
  9386. ΓòÉΓòÉΓòÉ 15.2.5. More about Queues ΓòÉΓòÉΓòÉ
  9387.  
  9388. In certain applications, your REXX programs can organize information for use by 
  9389. other programs by putting it in an external data queue. A queue is an ordered 
  9390. list that can be read or written at either end, top or bottom, so that each 
  9391. item of the queue constitutes a line of data. 
  9392.  
  9393. There are two kinds of queues in REXX: 
  9394.  
  9395.  o One default queue, SESSION, is automatically provided for each active OS/2 
  9396.    session.  SESSION is created by REXX the first time a REXX program issues a 
  9397.    PUSH or QUEUE instruction to a line of data.  Any program, REXX or 
  9398.    otherwise, in a given session can access the SESSION queue, but only the 
  9399.    SESSION queue defined for its own session can be accessed. 
  9400.  
  9401.  o A REXX program can also create private queues for itself.  A private queue 
  9402.    must be accessed by a unique name.  You can name the queue or leave the 
  9403.    naming to REXX. 
  9404.  
  9405.  Private data queues are created and manipulated by the RXQUEUE function, 
  9406.  described in "Applications Programming Interfaces" in the REXX Reference. 
  9407.  
  9408.  For more information about file and device input and output, refer to 
  9409.  "Functions" and "Data Streams" in the REXX Reference. 
  9410.  
  9411.  
  9412. ΓòÉΓòÉΓòÉ 15.2.6. Examples ΓòÉΓòÉΓòÉ
  9413.  
  9414.  
  9415. SDIR.CMD
  9416.  
  9417. /* SDIR.CMD - Program to print a sorted directory.         */
  9418. /*   Program will read in the current directory, and       */
  9419. /*     then sort it using a quick-sort routine.            */
  9420. list. = 0
  9421. 'dir | rxqueue /fifo'
  9422. j=0
  9423. do queued()
  9424.   j=j+1
  9425.   parse pull list.j
  9426.   end
  9427. call quicksort 4, j-1
  9428. do i = 1 to j
  9429.    say list.i
  9430. end
  9431. exit 0
  9432. /* The quick-sort procedure */
  9433. Quicksort:
  9434. PROCEDURE EXPOSE list.
  9435. ARG bot, top
  9436. center = Qsort(bot, top)
  9437. IF center - 1 > bot THEN CALL Quicksort bot, center - 1
  9438. IF center + 1 < top THEN CALL Quicksort center + 1, top
  9439. RETURN
  9440. qsort: PROCEDURE EXPOSE list.
  9441. ARG b , t
  9442. choose = list.b
  9443. small = b
  9444. large = t + 1
  9445. DO WHILE (small + 1 < large)
  9446.    next = small + 1
  9447.    IF list.next <= choose THEN
  9448.       DO
  9449.       list.small = list.next
  9450.       small = small + 1
  9451.       list.next = choose
  9452.       END
  9453.    ELSE
  9454.       DO
  9455.       large = large - 1
  9456.       temp = list.large
  9457.       list.large = list.next
  9458.       list.next = temp
  9459.       END
  9460.    END
  9461. RETURN small
  9462.  
  9463.  
  9464. LINLEN.CMD
  9465.  
  9466. /* Program printing exec - program will determine which records  */
  9467. /*   in a file exceed the specified length.                      */
  9468.  
  9469. say 'Please type the name of the file to examine {filename.ext}: '
  9470. parse pull file
  9471. say 'Please type the length to scan for: '
  9472. parse pull col
  9473. "type" file "| rxqueue /fifo"
  9474. if rc <> 0 then exit rc
  9475. lines = queued()
  9476. do currline = 1 to lines
  9477.    parse pull line
  9478.    if length(line) > col then
  9479.      say 'Line #' currline '  length =' length(line)
  9480.    end
  9481. exit 0
  9482.  
  9483.  
  9484. ΓòÉΓòÉΓòÉ 16. Program Style ΓòÉΓòÉΓòÉ
  9485.  
  9486. The focus in this chapter is more on method than on individual features, which 
  9487. are better learned by practicing and experimenting. 
  9488.  
  9489.  
  9490. ΓòÉΓòÉΓòÉ 16.1. Basics ΓòÉΓòÉΓòÉ
  9491.  
  9492.      In this chapter: Basics 
  9493.  
  9494.      o Consider the data 
  9495.      o Define the tasks 
  9496.      o Create modules 
  9497.      o Planning the program 
  9498.      o Putting it all together 
  9499.      o Testing and debugging. 
  9500.  
  9501.  As you learn more about the syntax of REXX, you can get better at deciding 
  9502.  which computing tasks are appropriate to a program.  Translating an idea for a 
  9503.  program into actual code is less a matter of expert programming than of good 
  9504.  planning.  If you plan your program thoroughly, the coding will be that much 
  9505.  easier. 
  9506.  
  9507.  
  9508. ΓòÉΓòÉΓòÉ 16.1.1. Consider the Data ΓòÉΓòÉΓòÉ
  9509.  
  9510. When you are faced with the task of writing a program, the first thing to 
  9511. consider is the data you are required to process. 
  9512.  
  9513.   1. Make a list of the input data.  What are the items and the possible values 
  9514.      of each? 
  9515.  
  9516.   2. If the input data items have a type of structure or pattern, draw a 
  9517.      diagram to illustrate it. 
  9518.  
  9519.   3. Do the same for the output data.  What data and in what form does the user 
  9520.      expect as output? 
  9521.  
  9522.   4. Study your two diagrams to see if they fit together.  If they do, you are 
  9523.      well on the way to designing your program. 
  9524.  
  9525.   5. Write a specification of input for the user.  This may be a written 
  9526.      specification, a HELP file, or both. 
  9527.  
  9528.  
  9529. ΓòÉΓòÉΓòÉ 16.1.1.1. Test Yourself ΓòÉΓòÉΓòÉ
  9530.  
  9531. You are required to write an interactive program that invites the user to play 
  9532. heads or tails.  The game can be played as long as the user likes.  To end the 
  9533. game, the user types Quit in answer to the question Heads or Tails?. The 
  9534. program is arranged so that the computer always wins. 
  9535.  
  9536. Think about how you would write this program. 
  9537.  
  9538. The computer starts with: 
  9539.  
  9540. Let us play a game!  Type "Heads", "Tails", or "Quit"
  9541. and press the Enter key.
  9542. This means that there are four possible inputs: 
  9543.  
  9544.  o Heads 
  9545.  o Tails 
  9546.  o Quit 
  9547.  o None of these three. 
  9548.  And so the corresponding outputs should be: 
  9549.  
  9550.  o Sorry.  It was TAILS.  Hard luck! 
  9551.  o Sorry.  It was HEADS.  Hard luck! 
  9552.  o (no output) 
  9553.  o That is not a valid answer.  Try again! 
  9554.  
  9555.  This sequence must be repeated indefinitely, ending with the return to the 
  9556.  OS/2 program. 
  9557.  
  9558.  Now that you understand the specification, the input data, and the output 
  9559.  data, you are ready to write the program. 
  9560.  
  9561.  Write the program.  If you are careful, it should run the first time. 
  9562.  
  9563.  
  9564. ΓòÉΓòÉΓòÉ 16.1.1.1.1. Answer ΓòÉΓòÉΓòÉ
  9565.  
  9566. Figure "CON.CMD" is an example of a possible solution. 
  9567.  
  9568.  
  9569. CON.CMD
  9570.  
  9571. /* Tossing a coin.  The machine is lucky, not the user */
  9572.  
  9573. do forever
  9574.    say "Let us play a game!  Type 'Heads', 'Tails'",
  9575.        "or 'Quit' and press the Enter key."
  9576.    pull answer
  9577.  
  9578.    select
  9579.       when answer = "HEADS"
  9580.          then say "Sorry!  It was TAILS.  Hard luck!"
  9581.       when answer = "TAILS"
  9582.          then say "Sorry!  It was HEADS.  Hard luck!"
  9583.       when answer = "QUIT"
  9584.          then exit
  9585.       otherwise
  9586.          say "That is not a valid answer.  Try again!"
  9587.    end
  9588.    say
  9589. end
  9590.  
  9591.  
  9592. ΓòÉΓòÉΓòÉ 16.1.2. Define the Tasks ΓòÉΓòÉΓòÉ
  9593.  
  9594. You are going to knit a warm, woolen, pullover sweater to wear when you go 
  9595. sailing.  You may: 
  9596.  
  9597.   1. Knit the front 
  9598.   2. Knit the back 
  9599.   3. Knit the left arm 
  9600.   4. Knit the right arm 
  9601.   5. Sew the pieces together. 
  9602.  
  9603.  Each of these jobs is simpler to describe than the the job of knitting. In 
  9604.  computer jargon, separating a job into simpler jobs is called stepwise 
  9605.  refinement. 
  9606.  
  9607.  Look at the specification again.  You may need to put on the pullover in the 
  9608.  dark quickly, without worrying about the front or back.  Therefore, the front 
  9609.  should be the same as the back, and the two sleeves should also be the same. 
  9610.  Figure "PULLOVER.CMD" shows a way that this could be coded. 
  9611.  
  9612.  
  9613.   PULLOVER.CMD
  9614.  
  9615.   do 2
  9616.      CALL Knit_body_panel
  9617.   end
  9618.  
  9619.   do 2
  9620.      CALL Knit_sleeve
  9621.   end
  9622.  
  9623.   CALL sew_pieces_together
  9624.  
  9625.  
  9626. ΓòÉΓòÉΓòÉ 16.1.2.1. Reconsider the Data ΓòÉΓòÉΓòÉ
  9627.  
  9628. When you are refining your program, your objective is to make each piece 
  9629. simpler.  This means simpler: 
  9630.  
  9631.  o Input data for each segment or routine 
  9632.  o Output data for each segment or routine 
  9633.  o Processing 
  9634.  o Code. 
  9635.  
  9636.  In the preceding example, if your pieces really are simpler, they probably 
  9637.  have simpler names, too.  For example: 
  9638.  
  9639.  o Knit cuff. 
  9640.  
  9641.    rather than 
  9642.  
  9643.  o Make ribbing for cuffs and waistband. 
  9644.  
  9645.  
  9646. ΓòÉΓòÉΓòÉ 16.1.3. Create Modules ΓòÉΓòÉΓòÉ
  9647.  
  9648. Using the stepwise refinement method discussed previously, you start with a 
  9649. specification (which may be incomplete).  Then, you separate the proposed 
  9650. program into routines, so that each routine is easier to code than the entire 
  9651. program.  You repeat the process for each of these routines until you reach 
  9652. routines that you are sure you can code correctly the first time. 
  9653.  
  9654. While you are doing this, keep asking yourself two questions: 
  9655.  
  9656.  o What data does this routine handle? 
  9657.  
  9658.  o Is the specification complete? 
  9659.  
  9660.  Still thinking about method, which is as important as language, look at a 
  9661.  simple arcade-type game program called CATMOUSE.CMD, as shown in Figure 
  9662.  "CATMOUSE.CMD". You may want to take a moment to type it in and play it. 
  9663.  
  9664.  
  9665.   CATMOUSE.CMD
  9666.  
  9667.   /* The user says where the mouse is to go.  But where   */
  9668.   /* will the cat jump?                                   */
  9669.  
  9670.   say "This is the mouse ---------->   @"
  9671.   say "These are the cat's paws --->  ( )"
  9672.   say "This is the mousehole ------>   O"
  9673.   say "This is a wall ------------->   |"
  9674.   say
  9675.   say "You are the mouse.  You win if you reach",
  9676.       "the mousehole.  You cannot go past"
  9677.   say "the cat.  Wait for him to jump over you.",
  9678.       "If you bump into him you are caught!"
  9679.   say
  9680.   say "The cat always jumps towards you, but he's not",
  9681.       "very good at judging distances."
  9682.   say "If either player hits the wall he misses a turn"
  9683.   say
  9684.   say "Type a number between 0 and 2 to say how far to",
  9685.       "the right you want to run."
  9686.   say "Be careful, if you type a number greater than 2 then",
  9687.       "the mouse will freeze and the cat will move!"
  9688.   say
  9689.  
  9690.   /*------------------------------------------------------*/
  9691.   /* Parameters that can be changed to make a different   */
  9692.   /* game                                                 */
  9693.   /*------------------------------------------------------*/
  9694.   len = 14               /* length of corridor            */
  9695.   hole = 14              /* position of hole              */
  9696.   spring = 5             /* maximum distance cat can jump */
  9697.   mouse = 1              /* mouse starts on left          */
  9698.   cat = len              /* cat starts on right           */
  9699.   /*------------------------------------------------------*/
  9700.   /* Main program                                         */
  9701.   /*------------------------------------------------------*/
  9702.   do forever
  9703.      call display
  9704.      /*---------------------------------------------------*/
  9705.      /* Mouse's turn                                      */
  9706.      /*---------------------------------------------------*/
  9707.      pull move
  9708.      if datatype(move,whole) & move >= 0 & move <= 2
  9709.      then select
  9710.         when mouse + move > len then nop     /* hits wall */
  9711.         when cat > mouse,
  9712.            & mouse + move >= cat             /* hits cat  */
  9713.                                          /* continued ... */
  9714.         then mouse = cat
  9715.         otherwise                            /* moves     */
  9716.         mouse = mouse + move
  9717.      end
  9718.      if mouse = hole then leave           /* reaches hole */
  9719.      if mouse = cat then leave            /* hits cat     */
  9720.      /*---------------------------------------------------*/
  9721.      /* Cat's turn                                        */
  9722.      /*---------------------------------------------------*/
  9723.      jump = random(1,spring)
  9724.      if cat > mouse then do     /* cat tries to jump left */
  9725.         if cat - jump < 1 then nop          /* hits wall  */
  9726.         else cat = cat - jump
  9727.      end
  9728.      else do                   /* cat tries to jump right */
  9729.         if cat + jump > len then nop        /* hits wall  */
  9730.         else cat = cat + jump
  9731.      end
  9732.      if cat = mouse then leave
  9733.   end
  9734.   /*------------------------------------------------------*/
  9735.   /* Conclusion                                           */
  9736.   /*------------------------------------------------------*/
  9737.   call display
  9738.   if cat = mouse then say "Cat wins"
  9739.   else say "Mouse wins"
  9740.   exit
  9741.   /*------------------------------------------------------*/
  9742.   /* Subroutine to display the state of play              */
  9743.   /*                                                      */
  9744.   /* Input: CAT and MOUSE                                 */
  9745.   /*                                                      */
  9746.   /* Design note:  each position in the corridor occupies */
  9747.   /* three character positions on the screen.             */
  9748.   /*------------------------------------------------------*/
  9749.   display:
  9750.   corridor = copies(" ",3*len)               /* corridor  */
  9751.   corridor = overlay("O",corridor,3*hole-1)  /* hole      */
  9752.  
  9753.   if mouse \= len                      /* mouse in hole? */
  9754.   then corridor = overlay("@",corridor,3*mouse-1)/* mouse */
  9755.  
  9756.   corridor = overlay("(",corridor,3*cat-2)       /* cat   */
  9757.   corridor = overlay(")",corridor,3*cat)
  9758.   say "   |"corridor"|"
  9759.   return
  9760.  
  9761.  
  9762. ΓòÉΓòÉΓòÉ 16.1.4. Planning the Program ΓòÉΓòÉΓòÉ
  9763.  
  9764. The program is about a cat and a mouse and their positions in a corridor. 
  9765.  
  9766.   1. The program begins with some initial settings, such as the length of the 
  9767.      corridor and the positions of the cat and the mouse. 
  9768.  
  9769.   2. The player types the moves of the mouse.  The cat's jumps are generated 
  9770.      using a random number.  The resulting positions are calculated at some 
  9771.      point. 
  9772.  
  9773.   3. At some other point, these positions are displayed on the screen. 
  9774.  
  9775.  Obviously, the whole program is too complicated to think about all at once. 
  9776.  The first step is to separate it into tasks such as: 
  9777.  
  9778.  o Setup-establish the initial positions. 
  9779.  
  9780.  o Main program-accept and calculate the result of each move. 
  9781.  
  9782.  o Display subroutine-display the new positions. 
  9783.  
  9784.  Now look at the main program.  The user (who plays the mouse) will want to see 
  9785.  where everybody is before making a move.  The cat will not.  The next step is 
  9786.  to separate the main program into: 
  9787.  
  9788.   Do forever
  9789.      call Display
  9790.      Mouse's move
  9791.      Cat's move
  9792.   End
  9793.   Conclusion
  9794.  
  9795.  
  9796. ΓòÉΓòÉΓòÉ 16.1.4.1. Designing Loops ΓòÉΓòÉΓòÉ
  9797.  
  9798. The method for designing loops is to ask two questions: 
  9799.  
  9800.  o Will it always terminate? 
  9801.  o Whenever it terminates, will the data meet the conditions required? 
  9802.  
  9803.  The loop terminates (and the game ends) when: 
  9804.  
  9805.  o The mouse runs to the hole. 
  9806.  o The mouse runs into the cat. 
  9807.  o The cat catches the mouse. 
  9808.  
  9809.  
  9810. ΓòÉΓòÉΓòÉ 16.1.4.2. Conclusion ΓòÉΓòÉΓòÉ
  9811.  
  9812. At the end of the program, the user must be told what happened by issuing the 
  9813. following: 
  9814.  
  9815. call display
  9816. say who won
  9817.  
  9818.  
  9819. ΓòÉΓòÉΓòÉ 16.1.5. Putting It All Together ΓòÉΓòÉΓòÉ
  9820.  
  9821. Figure "CATMOUSE2.CMD"shows how to put the modules together: 
  9822.  
  9823.  
  9824. CATMOUSE2.CMD
  9825.  
  9826. /*------------------------------------------------------*/
  9827. /* Main program                                         */
  9828. /*------------------------------------------------------*/
  9829. do forever
  9830.    call display
  9831.    /*---------------------------------------------------*/
  9832.    /* Mouse's turn                                      */
  9833.    /*---------------------------------------------------*/
  9834.     ...
  9835.  
  9836.    if mouse = hole then leave           /* reaches hole */
  9837.    if mouse = cat then leave            /* hits cat     */
  9838.    /*---------------------------------------------------*/
  9839.    /* Cat's turn                                        */
  9840.    /*---------------------------------------------------*/
  9841.     ...
  9842.  
  9843.    if cat = mouse then leave
  9844. end
  9845.  
  9846. /*------------------------------------------------------*/
  9847. /* Conclusion                                           */
  9848. /*------------------------------------------------------*/
  9849. call display
  9850. if cat = mouse then say "Cat wins"
  9851. else say "Mouse wins"
  9852. exit
  9853.  
  9854. /*------------------------------------------------------*/
  9855. /* Subroutine to display the state of play              */
  9856. /* Input: CAT and MOUSE                                 */
  9857. /*------------------------------------------------------*/
  9858. display:
  9859.  ...
  9860.  
  9861.  
  9862. ΓòÉΓòÉΓòÉ 16.1.6. Testing and Debugging ΓòÉΓòÉΓòÉ
  9863.  
  9864. If you cannot understand why your program is giving wrong results, you can: 
  9865.  
  9866.  o Modify your program so that it tells you what it is doing 
  9867.  
  9868.  o Put extra instructions into your program, such as: 
  9869.  
  9870.       .
  9871.       .
  9872.       .
  9873.       say "Checkpoint A.  x =" x
  9874.       .
  9875.       .
  9876.       .
  9877.       say "End of first routine"
  9878.       .
  9879.       .
  9880.       .
  9881.  
  9882.  o Use some of the REXX interactive trace facilities. 
  9883.  
  9884.  You will gradually learn which of these techniques is best for you. 
  9885.  
  9886.  
  9887. ΓòÉΓòÉΓòÉ 16.1.6.1. Using TRACE ΓòÉΓòÉΓòÉ
  9888.  
  9889. The TRACE instruction is a facility that you can use to perform the following 
  9890. tasks. 
  9891.  
  9892.  o To find out where your program is going, use TRACE L (labels). Figure 
  9893.    "ROTATE.CMD"shows an example and the trace it displays on the screen. 
  9894.  
  9895.  
  9896.       ROTATE.CMD
  9897.  
  9898.       /* Example: two iterations of wheel, six iterations */
  9899.       /* of cog.  On the first three iterations,  "x < 2" */
  9900.       /* is true. On the next three, it is false.         */
  9901.       trace L
  9902.       do x = 1 to 2
  9903.       wheel:
  9904.          do 3
  9905.       cog:
  9906.             if x < 2 then do
  9907.       true:
  9908.             end
  9909.             else do
  9910.       false:
  9911.             end
  9912.          end
  9913.       end
  9914.       done:
  9915.  
  9916.    The following trace is displayed on the screen. 
  9917.  
  9918.       [C:\]rotate
  9919.            6 *-*  wheel:
  9920.            8 *-*   cog:
  9921.           10 *-*     true:
  9922.            8 *-*   cog:
  9923.           10 *-*     true:
  9924.            8 *-*   cog:
  9925.           10 *-*     true:
  9926.            6 *-*  wheel:
  9927.            8 *-*   cog:
  9928.           13 *-*     false:
  9929.            8 *-*   cog:
  9930.           13 *-*     false:
  9931.            8 *-*   cog:
  9932.           13 *-*     false:
  9933.           17 *-* done:
  9934.       [C:\]
  9935.  
  9936.  o To see how the interpreter is computing expressions, use TRACE I 
  9937.    (intermediates). 
  9938.  
  9939.  o To find out whether you are passing the right data to a command or 
  9940.    subroutine, use TRACE R (results). 
  9941.  
  9942.  o To make sure that you get to see nonzero return codes from commands, use 
  9943.    TRACE E (errors). 
  9944.  
  9945.  
  9946. ΓòÉΓòÉΓòÉ 16.1.6.2. TRACE Symbols ΓòÉΓòÉΓòÉ
  9947.  
  9948. The trace symbols mean: 
  9949.  
  9950.  *-*    Identifies the source of a single clause, that is, the data actually in 
  9951.         the program. 
  9952.  
  9953.  ++&plusend. Identifies a trace message.  This may be the nonzero return code 
  9954.         from a command, the prompt message when interactive debug is entered, 
  9955.         an indication of a syntax error when in interactive debug, or the 
  9956.         traceback clauses after a syntax error in the program. 
  9957.  
  9958.  >>>    Identifies the result of an expression (for TRACE R), the value 
  9959.         assigned to a variable during parsing, or the value returned from a 
  9960.         subroutine call. 
  9961.  
  9962.  >.>    Identifies the value assigned to a placeholder during parsing (see 
  9963.         Using a Placeholder). 
  9964.  
  9965.  If you are using TRACE I (intermediates), these symbols are also used: 
  9966.  
  9967.  >C>    The data traced is the name of a compound variable, traced after 
  9968.         substitution and before use, provided that the name had the value of a 
  9969.         variable substituted into it. 
  9970.  
  9971.  >F>    The data traced is the result of a function call. 
  9972.  
  9973.  >L>    The data traced is a literal (string, uninitialized variable, or 
  9974.         constant symbol). 
  9975.  
  9976.  >O>    The data traced is the result of an operation on two terms. 
  9977.  
  9978.  >P>    The data traced is the result of a prefix operation. 
  9979.  
  9980.  >V>    The data traced is the contents of a variable. 
  9981.  
  9982.  
  9983. ΓòÉΓòÉΓòÉ 16.1.6.3. Interactive Debugging ΓòÉΓòÉΓòÉ
  9984.  
  9985. By putting a question mark in front of the TRACE option, TRACE ?R, you can turn 
  9986. on the REXX interactive debugging tool.  That means the program pauses after it 
  9987. processes most instructions (exceptions include SIGNAL, CALL, and reiterations 
  9988. of DO loops).  You can examine each clause, one at a time, and advance 
  9989. processing by pressing the Enter key. 
  9990.  
  9991. For more information about interactive debug, refer to "Debug Aids" in the REXX 
  9992. Reference. 
  9993.  
  9994.  
  9995. ΓòÉΓòÉΓòÉ 16.1.7. Summary ΓòÉΓòÉΓòÉ
  9996.  
  9997. This completes "Basics" in this chapter.  You have learned how to: 
  9998.  
  9999.  o Define tasks and create program modules 
  10000.  o Plan and develop a program 
  10001.  o Test and debug a program. 
  10002.  
  10003.  "Advanced Topics" in this chapter discusses refining programs to make them 
  10004.  easier to read. 
  10005.  
  10006.  
  10007. ΓòÉΓòÉΓòÉ 16.2. Advanced Topics ΓòÉΓòÉΓòÉ
  10008.  
  10009.      In this chapter: Advanced Topics 
  10010.  
  10011.      o Making programs easy to read. 
  10012.  
  10013.  
  10014. ΓòÉΓòÉΓòÉ 16.2.1. Making Programs Easy to Read ΓòÉΓòÉΓòÉ
  10015.  
  10016. The only sure way to determine if a program is correct is to read it. 
  10017. Therefore, programs must be easy-to-read.  Easy to read means different things 
  10018. to different programmers.  Here are examples of different styles.  You can 
  10019. choose the style you prefer. 
  10020.  
  10021. A very good way to check your program is to ask someone to read it. Be sure to 
  10022. choose a coding style that they find easy to read. 
  10023.  
  10024. Most people would find the program fragment shown in Figure "CATMOUSE3.CMD" 
  10025. difficult to read. 
  10026.  
  10027.  
  10028. CATMOUSE3.CMD
  10029.  
  10030. /**************************************************************/
  10031. /* SAMPLE #1:  A portion of CATMOUSE.CMD (Page Create Modules),         */
  10032. /* not divided into segments and written with no indentation  */
  10033. /* and no comments.  This style is not recommended.           */
  10034. /**************************************************************/
  10035. do forever
  10036. call display
  10037. pull move
  10038. if datatype(move,whole) & move >= 0 & move <=2
  10039. then select
  10040. when mouse+move > len then nop
  10041. when cat > mouse,
  10042. & mouse+move >= cat,
  10043. then mouse = cat
  10044. otherwise
  10045. mouse = mouse + move
  10046. end
  10047. if mouse = hole then leave
  10048. if mouse = cat  then leave
  10049. jump = random(1,spring)
  10050. if cat > mouse then do
  10051. if cat-jump < 1 then nop
  10052. else cat = cat-jump
  10053. end
  10054. else do
  10055. if cat+jump > len then nop
  10056. else cat = cat+jump
  10057. end
  10058. if cat = mouse then leave
  10059. end
  10060. call display
  10061. if cat = mouse then say "Cat wins"
  10062. else say "Mouse wins"
  10063. exit
  10064.  
  10065. Figure "CATMOUSE4.CMD" shows an example that is easier to read.  It is 
  10066. separated into segments, each with its own heading.  The comments on the right 
  10067. are sometimes called remarks.  They can help the reader get a general idea of 
  10068. what the program is doing. 
  10069.  
  10070.  
  10071. CATMOUSE4.CMD
  10072.  
  10073. /********************************************************/
  10074. /* SAMPLE #2:  A portion of CATMOUSE.CMD (Page Create Modules),   */
  10075. /* divided into segments and written with 'some'        */
  10076. /* indentation and 'some' comments.                     */
  10077. /********************************************************/
  10078.  
  10079. /********************************************************/
  10080. /* Main program                                         */
  10081. /********************************************************/
  10082. do forever
  10083.    call display
  10084.    /*****************************************************/
  10085.    /* Mouse's turn                                      */
  10086.    /*****************************************************/
  10087.    pull move
  10088.    if datatype(move,whole) & move >= 0 & move <=2
  10089.    then select
  10090.       when mouse+move > len then nop       /* hits wall */
  10091.       when cat > mouse,
  10092.          & mouse + move >= cat,            /* hits cat  */
  10093.       then mouse = cat
  10094.       otherwise                            /* moves     */
  10095.       mouse = mouse + move
  10096.   end
  10097.   if mouse = hole then leave            /* reaches hole */
  10098.   if mouse = cat then leave             /* hits cat     */
  10099.   /******************************************************/
  10100.   /* Cat's turn                                         */
  10101.   /******************************************************/
  10102.   jump = random(1,spring)
  10103.   if cat > mouse then do      /* cat tries to jump left */
  10104.      if cat - jump < 1 then nop           /* hits wall  */
  10105.      else cat = cat - jump
  10106.   end
  10107.   else do                    /* cat tries to jump right */
  10108.      if cat + jump > len then nop         /* hits wall  */
  10109.      else cat = cat + jump
  10110.   end
  10111.   if cat = mouse then leave
  10112. end
  10113. /********************************************************/
  10114. /* Conclusion                                           */
  10115. /********************************************************/
  10116. call display
  10117. if cat = mouse then say "Cat wins"
  10118. else say "Mouse wins"
  10119. exit
  10120.  
  10121. Figure "CATMOUSE5.CMD" shows an example with additional features that are 
  10122. popular with some programmers.  Keywords written in uppercase and a different 
  10123. indentation style highlight the structure of the code.  The abundant comments 
  10124. recall the detail of the specification. 
  10125.  
  10126.  
  10127. CATMOUSE5.CMD
  10128.  
  10129. /********************************************************/
  10130. /* SAMPLE #3:  A portion of CATMOUSE.CMD (Page Create Modules),   */
  10131. /* divided into segments and written with 'more'        */
  10132. /* indentation and 'more' comments.                     */
  10133. /* Note commands in uppercase (to highlight logic)      */
  10134. /********************************************************/
  10135.  
  10136. /********************************************************/
  10137. /* Main program                                         */
  10138. /********************************************************/
  10139. DO FOREVER
  10140.   CALL display
  10141.   /**********************************/
  10142.   /* Mouse's turn                   */
  10143.   /**********************************/
  10144.   PULL move
  10145.   IF datatype(move,whole) & move >= 0 & move <=2
  10146.     THEN SELECT
  10147.            WHEN mouse+move > len     /* mouse hits wall */
  10148.              THEN nop                /* and loses turn  */
  10149.            WHEN cat > mouse,
  10150.                 & mouse+move >= cat, /* mouse hits cat  */
  10151.              THEN mouse = cat        /* and loses game  */
  10152.            OTHERWISE mouse = mouse + move /* mouse ...  */
  10153.          END                   /* moves to new location */
  10154.   IF mouse = hole THEN LEAVE   /* mouse is home safely  */
  10155.   IF mouse = cat  THEN LEAVE   /* mouse hits cat (ouch) */
  10156.   /**********************************/
  10157.   /* Cat's turn                     */
  10158.   /**********************************/
  10159.   jump = RANDOM(1,spring)      /* determine cat's move  */
  10160.   IF cat > mouse               /* cat must jump left    */
  10161.     THEN DO
  10162.            IF cat-jump < 1          /* cat hits wall    */
  10163.              THEN nop               /* misses turn      */
  10164.              ELSE cat = cat-jump    /* cat jumps left   */
  10165.          END
  10166.     ELSE DO                    /* cat must jump right   */
  10167.            IF cat+jump > len        /* cat hits wall    */
  10168.              THEN nop               /* misses turn      */
  10169.              ELSE cat = cat+jump    /* cat jumps right  */
  10170.          END
  10171.   IF cat = mouse THEN LEAVE    /* cat catches mouse     */
  10172. END
  10173.  
  10174.                                /*continued*/
  10175.  
  10176. /********************************************************/
  10177. /* Conclusion                                           */
  10178. /********************************************************/
  10179. CALL display                        /* on final display */
  10180.   IF cat = mouse                    /* who won?         */
  10181.     THEN say "Cat wins"             /* ... the cat      */
  10182.     ELSE say "Mouse wins"           /* ... the mouse    */
  10183. EXIT
  10184.  
  10185.  
  10186. ΓòÉΓòÉΓòÉ 17. Using REXX with Applications ΓòÉΓòÉΓòÉ
  10187.  
  10188. The early chapters in this book familiarized you with the REXX language and 
  10189. showed you how to create and run REXX programs. This chapter builds on that 
  10190. knowledge with some REXX features designed to get the most out of your OS/2 
  10191. system. These features enable you to customize your system and write more 
  10192. powerful programs. 
  10193.  
  10194.  
  10195. ΓòÉΓòÉΓòÉ 17.1. Basics ΓòÉΓòÉΓòÉ
  10196.  
  10197.      In this chapter: 
  10198.  
  10199.      o Customizing OS/2 programs 
  10200.      o Getting the most from OS/2 
  10201.      o REXX utility functions. 
  10202.  
  10203.  
  10204. ΓòÉΓòÉΓòÉ 17.1.1. Customizing OS/2 Programs ΓòÉΓòÉΓòÉ
  10205.  
  10206. Your REXX programs can customize the way OS/2 programs work. If you always 
  10207. start an application with the same set of parameters, you can write a REXX 
  10208. program to call the application. This saves typing each time you use an 
  10209. application. You also do not need to remember the application parameters and 
  10210. options; REXX remembers them for you. 
  10211.  
  10212.  
  10213. ΓòÉΓòÉΓòÉ 17.1.2. Accessing Command Environments ΓòÉΓòÉΓòÉ
  10214.  
  10215. When you place the DIR command in a REXX program, REXX gives the command to the 
  10216. CMD.EXE program. CMD.EXE processes the command and gives a return code back to 
  10217. REXX. CMD.EXE is not the only program REXX can send commands. Any application 
  10218. can create a command environment for REXX programs to use. The application 
  10219. command environments create new sets of commands that you can use. 
  10220.  
  10221. For example, the IBM Extended Services/2 product provides communications 
  10222. support command environment. To use the communications command environment, you 
  10223. must use the REXX ADDRESS instruction. The ADDRESS instruction tells REXX to 
  10224. send commands to the communications program instead of the CMD.EXE program. The 
  10225. communications environment is called CPICOMM. Figure "CPICOMM" shows a REXX 
  10226. program that uses the CPICOMM command environment. 
  10227.  
  10228.  
  10229. CPICOMM
  10230.  
  10231. /* Start of a program that uses SAA communications support */
  10232. Address CPICOMM
  10233. destination = "SYSTEMA"              /* prepare input for CMINIT command */
  10234. "CMINIT conv_id destination cm_rc"   /* Issue CMINIT command to CPICOMM. */
  10235.                                      /* The meaning of CMINIT and what   */
  10236.                                      /* its parameters are defined by    */
  10237.                                      /* the SAA communication program,   */
  10238.                                      /* not by REXX.                     */
  10239.  
  10240. You must run the CPICREXX command before you can use the CPICOMM command 
  10241. environment. More commonly, you must use the RXSUBCOM command to create a 
  10242. command environment. The RXSUBCOM command tells REXX which program it should 
  10243. pass REXX program commands. For example, REXX Dialog Manager programs use 
  10244. RXSUBCOM to create the ISPCIR subcommand handler: 
  10245.  
  10246.   'RXSUBCOM REGISTER ISPCIR ISPCIR ISPCIR'
  10247.   Address ispcir
  10248.  
  10249. The Dialog Manager ISPCIR subcommand environment is a routine named ISPCIR in 
  10250. the ISPCIR.DLL dynamic link library. You must issue the instruction ADDRESS 
  10251. ISPCIR to send commands to the Dialog Manager. 
  10252.  
  10253.  
  10254. ΓòÉΓòÉΓòÉ 17.1.3. Using External Functions ΓòÉΓòÉΓòÉ
  10255.  
  10256. In addition to the REXX built-in functions, you can use functions external to 
  10257. REXX in your REXX programs. An external function may be simply another REXX 
  10258. program, or it may be a function written in a compiled language. Before you can 
  10259. use a function in a compiled language, you must tell REXX where the function is 
  10260. located with the RxFuncAdd function. 
  10261.  
  10262. For example, the IBM Extended Services/2 product provides a REXX function for 
  10263. the Emulator High Level Language Application Programming Interface (EHLLAPI). 
  10264. The EHLLAPI function is in an OS/2 dynamic link library module named 
  10265. SAAHLAPI.DLL. The function routine within SAAHLAPI.DLL is HllApiSrv. To use the 
  10266. EHLLAPI function, you must first tell REXX where the function is found: 
  10267.  
  10268.   call RxFuncAdd 'hllapi', 'saahlapi', 'hllapisrv'
  10269.  
  10270. You can now use the function HLLAPI in your REXX programs: 
  10271.  
  10272.  rc = hllapi("Set_session_parms","CONPHYS")
  10273.  rc = hllapi("Connect",session)
  10274.  if (rc <> 0) then return rc
  10275.  rc = hllapi("Start_keystroke_intercept",session,"L")
  10276.  
  10277. You only need to register HLLAPI with RxFuncAdd one time. Once registered, a 
  10278. function is available from anywhere on your OS/2 system. 
  10279.  
  10280.  
  10281. ΓòÉΓòÉΓòÉ 17.1.4. Summary ΓòÉΓòÉΓòÉ
  10282.  
  10283. This completes "Basics" in this chapter. You know how to: 
  10284.  
  10285.  o Start an application efficiently 
  10286.  o Send commands to applications 
  10287.  o Use external functions. 
  10288.  
  10289.  "Advanced Topics" in this chapter discusses REXX utilities. 
  10290.  
  10291.  
  10292. ΓòÉΓòÉΓòÉ 17.2. Advanced Topics ΓòÉΓòÉΓòÉ
  10293.  
  10294.      In this chapter: 
  10295.  
  10296.      o REXX Utility Functions 
  10297.  
  10298.  
  10299. ΓòÉΓòÉΓòÉ 17.2.1. The REXXUTIL external function package ΓòÉΓòÉΓòÉ
  10300.  
  10301. RexxUtil is a Dynamic Link Library (DLL) package of OS/2 operating system REXX 
  10302. functions. These operating system functions: 
  10303.  
  10304.  o Manipulate OS/2 operating system files and directories 
  10305.  
  10306.  o Manipulate OS/2 operating system classes and objects 
  10307.  
  10308.  o Perform text screen input and output. 
  10309.  
  10310.  To use a RexxUtil function, you must first register the function with the REXX 
  10311.  RxFuncAdd function: 
  10312.  
  10313.      Add RexxUtil Function 
  10314.  
  10315.           call RxFuncAdd 'SysCls', 'RexxUtil', 'SysCls'
  10316.  
  10317.  The RxFuncAdd function can register functions in other dynamic link libraries 
  10318.  as well. 
  10319.  
  10320.  The example above registers the SysCls function. You can now use the SysCls 
  10321.  function in your REXX programs. 
  10322.  
  10323.  The SysLoadFuncs RexxUtil function automatically loads the other RexxUtil 
  10324.  functions. The following instructions in a REXX program will register all of 
  10325.  the RexxUtil functions. 
  10326.  
  10327.      Load RexxUtil Function 
  10328.  
  10329.           call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
  10330.           call SysLoadFuncs
  10331.  
  10332.  Once registered, the RexxUtil functions are available from all OS/2 operating 
  10333.  system sessions. If you use the RexxUtil functions frequently, you should 
  10334.  place a call to SysLoadFuncs in your STARTUP.CMD file. 
  10335.  
  10336.  
  10337. ΓòÉΓòÉΓòÉ 17.2.1.1. Functions that Replace Commands ΓòÉΓòÉΓòÉ
  10338.  
  10339. Several RexxUtil functions duplicate OS/2 operating system command functions. 
  10340. The command functions are: 
  10341.  
  10342.  SysMkDir 
  10343.       Creates a directory 
  10344.  
  10345.  SysRmDir 
  10346.       Deletes a directory 
  10347.  
  10348.  SysFileDelete 
  10349.       Deletes (erases) a file 
  10350.  
  10351.  SysCls 
  10352.       Clears the screen. 
  10353.  
  10354.  The RexxUtil command functions have several advantages over the equivalent 
  10355.  operating system commands: 
  10356.  
  10357.  o The RexxUtil functions do not issue error messages. For example, for a file 
  10358.    that does not exist, the DELETE command issues the message: 
  10359.  
  10360.         SYS0002: The system cannot find the file specified.
  10361.  
  10362.    if you wish to unconditionally erase the file, you would need to redirect 
  10363.    the error message: 
  10364.  
  10365.         'del' file '>NUL'
  10366.  
  10367.    The RexxUtil SysFileDelete function can do this easily, without an error 
  10368.    message: 
  10369.  
  10370.         call SysFileDelete file
  10371.  
  10372.  o The RexxUtil functions calls are not echoed to the screen. When using the 
  10373.    RexxUtil functions, you do not need to use "ECHO OFF" prevent the command 
  10374.    echo. 
  10375.  
  10376.  o The RexxUtil functions can be faster than the OS/2 operating system command. 
  10377.  
  10378.  Figure "INSTALL.CMD" shows a program called INSTALL.CMD. That program uses the 
  10379.  RexxUtil SysMkDir and SysFileDelete functions to install an application. 
  10380.  
  10381.  
  10382.   INSTALL.CMD
  10383.  
  10384.   /* Application install program - Install information */
  10385.   /* comes from an application control file            */
  10386.   parse arg product            /* get product name     */
  10387.  
  10388.   call setup                   /* read control info    */
  10389.   rc = SysMkDir directory      /* create main directory*/
  10390.   if rc <> 0 then do           /* already installed    */
  10391.     say product 'is already installed.  Do you wish to'
  10392.     say product 'continue? (Yes/No)'
  10393.     pull answer
  10394.     if answer <> 'YES' then exit 100
  10395.                                /* delete old files     */
  10396.     do i = 1 to files.0
  10397.       call SysDeleteFile 'C:'files.i
  10398.     end
  10399.   end
  10400.                                /* get free space       */
  10401.   parse value SysDriveInfo('C:') with . free .
  10402.                                /* not enough room      */
  10403.   if free < required_space then do
  10404.     say 'Product' product 'requires' required_space
  10405.     say 'bytes of storage.  You only have' free 'bytes'
  10406.     say 'available.  Please make more space available on'
  10407.     say 'the drive and try again.'
  10408.     exit 100
  10409.   end
  10410.  
  10411.   do i = 1 to directories      /* make subdirectories  */
  10412.     call SysMkDir directories.i
  10413.   end
  10414.  
  10415.   do i = 1 to files            /* copy the files       */
  10416.     say 'Copying C:'files.i
  10417.     '@copy A:'files.i 'C:'files.i '> NUL'
  10418.   end
  10419.   Setup:                         /* read control file          */
  10420.     file = product||'.CTL'       /* read control information   */
  10421.     files = 0                    /* no files to read           */
  10422.     directories = 0              /* no subdirectories          */
  10423.     call on notready             /* set up end-of-file handler */
  10424.     eof = 0                      /* not at end yet             */
  10425.  
  10426.     line = linein(file)          /* get first line             */
  10427.     do while \eof                /* read entire file           */
  10428.       parse var line type value  /* get the first word         */
  10429.       select                     /* process the record type    */
  10430.                                  /* product root directory     */
  10431.         when type = 'DIRECTORY' then
  10432.           directory = value
  10433.                                  /* product subdirectories     */
  10434.         when type = 'SUBDIRECTORY' then do
  10435.           directories = directories + 1
  10436.           directories.directories = value
  10437.         end
  10438.                                  /* product files (with the    */
  10439.                                  /* target directories         */
  10440.         when type = 'FILE' then do
  10441.           files = files + 1
  10442.           files.files = value
  10443.         end
  10444.         otherwise nop
  10445.       end
  10446.       line = linein(file)        /* get next line              */
  10447.     end
  10448.     return
  10449.  
  10450.  
  10451. ΓòÉΓòÉΓòÉ 17.2.1.2. Functions for Saving Information ΓòÉΓòÉΓòÉ
  10452.  
  10453. You can use use the RexxUtil SysPutEA, SysGetEA, and SysIni functions to save 
  10454. information outside of your REXX programs: 
  10455.  
  10456.  SysPutEA 
  10457.       Saves information in a file's extended attributes. SysPutEA stores the 
  10458.       information as a named attribute. The SysGetEA retrieves the saved 
  10459.       information using the name you used with SysPutEA. The extended 
  10460.       attributes remain with the file until the file is erased. 
  10461.  
  10462.  SysGetEA 
  10463.       Retrieves information from a file's extended attributes. The extended 
  10464.       attribute may have been stored by the SysPutEA function or another 
  10465.       program. 
  10466.  
  10467.  SysIni 
  10468.       Saves and retrieves information from a system profile file. Profile 
  10469.       information is stored as Application Names with associated Key Names. You 
  10470.       can store information in the system profile (OS2SYS.INI), the user 
  10471.       profile (OS2.INI), or any profile file you designate. 
  10472.  
  10473.  Information you save with SysPutEA remains with the named file as hidden 
  10474.  information. It not visible when you edit or type the file, but you can 
  10475.  retrieve it using the SysGetEA function. Information you save with the SysIni 
  10476.  function is written to an OS/2 operating system profile file. You save the 
  10477.  information under an application name and a key name. For example, a text 
  10478.  editor might store profile information using an "Editor" application name with 
  10479.  application keys of "TempFile", "Dictionary", and "DefaultOptions". 
  10480.  
  10481.  Figure "SETCOMP.CMD" and Figure "SETPROJ.CMD" show how compiler option 
  10482.  information is saved in a file's extended attributes and in a PROJECT.INI 
  10483.  profile file. The DOCOMP.CMD program uses the information stored in the 
  10484.  extended attributes and the PROJECT.INI file to compile a source file. 
  10485.  
  10486.  
  10487.   SETCOMP.CMD
  10488.  
  10489.   /* Store file compilation options in extended attributes        */
  10490.   parse arg file options         /* get the file name and options */
  10491.                                  /* set the compile options       */
  10492.   call SysPutEA file, 'Compile_options', options
  10493.  
  10494.  
  10495.   SETPROJ.CMD
  10496.  
  10497.   /* Store project file compilation options in profile            */
  10498.   parse arg options              /* get the options               */
  10499.                                  /* find the profile              */
  10500.   profile = SysSearchPath('DPATH', 'PROFILE.INI')
  10501.   if profile = '' then           /* find it?                      */
  10502.     profile = 'PROFILE.INI'      /* place in current directory    */
  10503.                                  /* set the compile options       */
  10504.   call SysIni profile, 'Compiler', 'Options', options
  10505.  
  10506.  
  10507.   DOCOMP . CMD
  10508.  
  10509.   /* Compile a program using the options stored in the program    */
  10510.   /* source extended attributes                                   */
  10511.   parse arg file                 /* get the file name             */
  10512.                                  /* retrieve the file options     */
  10513.   rc = SysGetEA file, 'Compile_options', 'options'
  10514.  
  10515.   if rc <> 0 then do             /* no options for file?          */
  10516.                                  /* find the profile              */
  10517.     profile = SysSearchPath('DPATH', 'PROFILE.INI')
  10518.     if profile <> '' then        /* find it?                      */
  10519.                                  /* retrieve default options      */
  10520.       options = SysIni(project, 'Compiler', 'Options')
  10521.   end
  10522.  
  10523.   'CC' options file              /* compile it                    */
  10524.  
  10525.  
  10526. ΓòÉΓòÉΓòÉ 17.2.1.3. Using the Screen ΓòÉΓòÉΓòÉ
  10527.  
  10528. When you run a REXX program in an OS/2 windowed session or an OS/2 full screen 
  10529. session, you can control the screen with the RexxUtil text screen functions. 
  10530. The text screen functions are: 
  10531.  
  10532.  SysCurPos 
  10533.       Places the cursor at a screen row and column position. You can also use 
  10534.       SysCurPos to obtain the current cursor position. 
  10535.  
  10536.  SysCurState 
  10537.       Hides the cursor or makes the cursor visible. 
  10538.  
  10539.  SysGetKey 
  10540.       Reads the next key from the keyboard buffer. If the keyboard buffer is 
  10541.       empty, SysGetKey will wait until a key is pressed. 
  10542.  
  10543.  SysTextScreenRead 
  10544.       Reads characters from the screen. 
  10545.  
  10546.  SysTextScreenSize 
  10547.       Returns the screen size. 
  10548.  
  10549.  You cannot use the text screen functions in REXX programs running under PMREXX 
  10550.  or called from a Presentation Manager application. 
  10551.  
  10552.  You can use the text screen functions for screen input and output functions 
  10553.  not possible with the REXX input and output built-in functions. For example, 
  10554.  Figure "GETPASS.CMD" contains a REXX program that reads a password from the 
  10555.  screen without revealing the characters typed. 
  10556.  
  10557.  
  10558.   GETPASS.CMD
  10559.  
  10560.   /* Read a password from the screen */
  10561.   Valid = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890#$@'
  10562.   Passwd = ''
  10563.   MaxLength = 8
  10564.  
  10565.   ETK = d2c(13)             /* Enter key                */
  10566.   BS = d2c(8)               /* Backspace                */
  10567.   X1 = d2c(0)               /* Extended key             */
  10568.   X2 = d2c(224)             /* Extended key             */
  10569.  
  10570.   do forever                /* Loop until complete      */
  10571.     Ch = translate(SysGetKey('NOECHO'))
  10572.     select
  10573.       when Ch = ETK         /* Enter key pressed        */
  10574.         then do
  10575.           say ''            /* Give a carriage return   */
  10576.           leave
  10577.         end
  10578.       when Ch = BS          /* Backspace                */
  10579.         then if PassWd = ''
  10580.           then call Beep 262, 200
  10581.  
  10582.           else do           /* Overstrike a blank       */
  10583.             call charout ,BS BS
  10584.             PassWd = left(PassWd, length(PassWd)-1)
  10585.           end
  10586.                             /* All other characters     */
  10587.       when pos(Ch, Valid) > 0
  10588.         then if length(PassWd) = MaxLength
  10589.           then call Beep 262, 200
  10590.           else do
  10591.             call charout ,'*'
  10592.             Passwd = PassWd||Ch
  10593.           end
  10594.       otherwise do          /* Swallow next for extended*/
  10595.         if Ch = X1 | Ch = X2
  10596.           then call SysGetKey('NOECHO')
  10597.         call beep 262, 200
  10598.       end
  10599.     end
  10600.   end
  10601.   return PassWd
  10602.  
  10603.  GETPASS.CMD uses the SysGetKey function to read characters from the keyboard. 
  10604.  SysGetKey reads each character as you type it and does not echo the character 
  10605.  to the screen. 
  10606.  
  10607.  When SysGetKey is combined with the other RexxUtil text screen functions, you 
  10608.  can create text based menu systems. Figure "TEXTMENU.CMD" contains an example 
  10609.  of a simple menu program. 
  10610.  
  10611.  
  10612.   TEXTMENU.CMD
  10613.  
  10614.   /* Place a simple menu on the screen                                */
  10615.   ** These functions are used to create the following subroutines:
  10616.   **
  10617.   **   MakeWindow  - Reserves part of a window as a sub-window.
  10618.   **                 Draws a border and returns a window handle.
  10619.   **   WriteWindow - Writes a line into a sub-window
  10620.   **   WriteMenu   - Write a menu-line into a window, where accelerator
  10621.   **                 keys are underlined
  10622.   **   WaitMenu    - Waits until one of the menu entries are selected,
  10623.   **                 and returns the choice.
  10624.   */
  10625.   handles = 0
  10626.   Call SysCls
  10627.  
  10628.   handle = Makewindow(5,5,10,50)
  10629.   call writewindow handle, 5 ,10, 'This is a demo.'
  10630.   call writewindow handle, 7 ,10, 'Choose an item from the Menu above.'
  10631.   call writemenu handle, '~Quit ~Exit Lea~ve'
  10632.   call Waitmenu handle
  10633.   Call writeWindow handle, 9, 5, 'You entered' result
  10634.   call syscurpos 23,0
  10635.   exit
  10636.  
  10637.   /********************************************************************/
  10638.   /* This routine reserves a portion of the text window as a          */
  10639.   /* sub-window.  The window is defined by giving the position of its */
  10640.   /* upper left hand corner (based on 0,0 being the upper left hand   */
  10641.   /* corner of the text window), and the size in rows and columns.    */
  10642.   /*                                                                  */
  10643.   /* The sub-window is blanked out and a border is drawn around it.   */
  10644.   /* This routine assigns a window handle to the window.  That handle */
  10645.   /* is passed to the other routines to identify which window they    */
  10646.   /* should act on.                                                   */
  10647.   /*                                                                  */
  10648.   /* Return values:  negative number if there is an error.            */
  10649.   /*   a positive number is a valid window handle.                    */
  10650.   /********************************************************************/
  10651.   MakeWindow:  Procedure expose handles Windowdata.
  10652.   Arg orgrow, orgcol, rows, cols
  10653.  
  10654.   /* First make sure the requested sub-window will fit                */
  10655.   Parse Value SysTextScreenSize() With ssrows sscols
  10656.   Select
  10657.     When  orgrow < 0 Then Return -1
  10658.     When  orgcol < 0 Then Return -2
  10659.     When  rows   < 0 Then Return -3
  10660.     When  cols   < 0 Then Return -4
  10661.     When  orgrow + rows > ssrows Then Return -5
  10662.     When  orgrow + rows > ssrows Then Return -6
  10663.     Otherwise Nop   /* No error on input */
  10664.   End
  10665.   /* Record data about window for future use.                         */
  10666.   handles = handles + 1
  10667.   WindowData.handles._orgrow = orgrow
  10668.   WindowData.handles._orgcol = orgcol
  10669.   WindowData.handles._rows = rows
  10670.   WindowData.handles._cols = cols
  10671.  
  10672.   /* Now draw the window                                              */
  10673.   FillerLine = copies('ΓöÇ',cols -2)
  10674.   BlankLine  = copies(' ',cols -2)
  10675.  
  10676.   Call WriteLineAbsolute orgrow, orgcol, 'Γöî'fillerline'ΓöÉ'
  10677.   Do ii = orgrow + 1 for rows -1
  10678.     Call WriteLineAbsolute ii, orgcol, 'Γöé'blankline'Γöé'
  10679.   End
  10680.   Call WriteLineAbsolute ii, orgcol, 'Γöö'fillerline'Γöÿ'
  10681.  
  10682.   Return handles
  10683.  
  10684.  
  10685.   /********************************************************************/
  10686.   /* This routine will write one line of text into a sub-window.      */
  10687.   /* The caller specifies the row and column number to place the text.*/
  10688.   /* This location is based on the upper left hand corner of the      */
  10689.   /* sub-window, which is defined as 1,1.                             */
  10690.   /* Text is not allowed to overlay the window border.                */
  10691.   /********************************************************************/
  10692.   WriteWindow: Procedure expose handles Windowdata.
  10693.   Parse Arg Handle, row, col, text
  10694.  
  10695.   /* Make sure the window handle is OK, and the text will fit in the  */
  10696.   /* window.                                                          */
  10697.   Select
  10698.     When handle < 0 Then Return -1
  10699.     When handle > handles Then Return -2
  10700.     When row <=1 Then Return -3
  10701.     When col <=1 Then Return -4
  10702.     When row >= Windowdata.handle._rows Then return -5
  10703.     When length(text) + col > Windowdata.handle._cols Then return -6
  10704.     Otherwise Nop
  10705.   End
  10706.  
  10707.   /* Calculate the location and write the text                        */
  10708.   AbsoluteRow = Windowdata.handle._orgrow + row
  10709.   AbsoluteCol = Windowdata.handle._orgcol + col
  10710.   Call WriteLineAbsolute AbsoluteRow, AbsoluteCol, text
  10711.   Return 0
  10712.   /********************************************************************/
  10713.   /* This routine takes a string of words and writes it on the top of */
  10714.   /* a window as a menu.  Each word should have a ~ character in      */
  10715.   /* front of the character which will be used to select it.          */
  10716.   /* Each of these characters will be underlined and written as a     */
  10717.   /* capital letter.  The caller must ensure that no duplicate        */
  10718.   /* selection characters are included in the word list.              */
  10719.   /********************************************************************/
  10720.   WriteMenu: Procedure expose handles Windowdata.
  10721.   Parse Arg handle, orgtext
  10722.  
  10723.   /* We make the input text all lower case, the uppercase the         */
  10724.   /* selection characters later.                                      */
  10725.   orgtext = Translate(orgtext, xrange('a','z'), xrange('A', 'Z'))
  10726.  
  10727.   MenuText = ''                     /* output word list               */
  10728.   UnderlineText = ''                /* output underline characters    */
  10729.   MenuCount = 0                     /* how many selections so far     */
  10730.   JustDidUnderline = 0              /* did we just find a ~ character?*/
  10731.  
  10732.   Do OrgCounter = 1 to length(orgtext)
  10733.     OrgChar = substr(OrgText, OrgCounter, 1)
  10734.  
  10735.     if Orgchar <> '~' Then Do
  10736.       If JustDidUnderline Then Do   /* put in uppercase letter        */
  10737.         MenuText = MenuText || translate(OrgChar)
  10738.         JustDidUnderline = 0
  10739.         MenuCount = MenuCount + 1
  10740.  
  10741.         /* remember the accelerator keys for use by WaitMenu routine  */
  10742.         WindowData.handle._Accelkey.MenuCount = Translate(OrgChar)
  10743.         End
  10744.       Else Do                       /* put in lower case letter       */
  10745.         UnderlineText = UnderlineText || ' '
  10746.         MenuText = MenuText || OrgChar
  10747.         End
  10748.     End
  10749.     Else Do                         /* found a ~ character            */
  10750.       UnderlineText = UnderlineText || 'ΓöÇ'
  10751.       JustDidUnderline = 1
  10752.     End
  10753.   End Orgcounter
  10754.  
  10755.   Windowdata.handle._MenuCount = MenuCount
  10756.  
  10757.   /* Now we have the menu text.  Write to the top of the window,      */
  10758.   /* center, with the underline row below it.                         */
  10759.   width = Windowdata.handle._cols - 3
  10760.   Call WriteWindow handle, 2, 2, center(MenuText, width)
  10761.   if result < 0 then Return result
  10762.   Call WriteWindow handle, 3, 2, center(UnderlineText, width)
  10763.   Return result
  10764.   /********************************************************************/
  10765.   /* This is a simple routine that writes a line of text to a location*/
  10766.   /* defined in relation to the main text window.                     */
  10767.   /********************************************************************/
  10768.   WriteLineAbsolute: Procedure
  10769.   Parse Arg row, col, text
  10770.   Call SysCurPos row, col
  10771.   call charout , text
  10772.   Return
  10773.  
  10774.   /********************************************************************/
  10775.   /* This routine waits for the user to select a menu choice by       */
  10776.   /* pressing a key that corresponds to one of the selection          */
  10777.   /* characters defined for a given window.                           */
  10778.   /* Any other keys are ignored.                                      */
  10779.   /********************************************************************/
  10780.   WaitMenu: Procedure expose handles Windowdata.
  10781.   arg handle
  10782.  
  10783.   /* Make sure the window handle is OK.                               */
  10784.   Select
  10785.     When Handle < 0 Then Return -1
  10786.     When handle > handles Then Return -2
  10787.     Otherwise Nop
  10788.   End
  10789.  
  10790.   /* Turn off cursor and wait for an expected character               */
  10791.   Call syscurstate 'OFF'
  10792.   Do outerloop = 0
  10793.     char = translate(SysGetKey('NOECHO'))
  10794.     do ii = 1 to Windowdata.handle._MenuCount
  10795.       if char = Windowdata.handle._accelkey.ii Then Leave outerloop
  10796.     End
  10797.   End outerloop
  10798.  
  10799.   /* Turn cursor back on and return uppercase of the selection char.  */
  10800.   Call syscurstate 'OFF'
  10801.   return char
  10802.  
  10803.  When you run TEXTMENU.CMD, a small menu box appears on the screen. 
  10804.  
  10805.  
  10806.   TEXTMENU.CMD Display
  10807.  Continue on the next page of this chapter. 
  10808.  
  10809.  
  10810. ΓòÉΓòÉΓòÉ 17.2.1.4. Using the Screen (continued) ΓòÉΓòÉΓòÉ
  10811.  
  10812.  
  10813.             Quit Exit leaVe
  10814.             -   -    -
  10815.  
  10816.         This is a demo.
  10817.  
  10818.         Choose an item from the Menu above.
  10819.  
  10820.  
  10821. When you press a Q, E, or V key, the menu displays your selection and the 
  10822. program ends. 
  10823.  
  10824.  
  10825. ΓòÉΓòÉΓòÉ 17.2.1.5. Seaching Functions ΓòÉΓòÉΓòÉ
  10826.  
  10827. RexxUtil also includes some functions for searching files and directories. The 
  10828. program FINDFILE.CMD in Figure "FINDFILE.CMD" creates a list of files that 
  10829. matches a file specification containing a given character string. FINDFILE.CMD 
  10830. uses the RexxUtil SysFileTree, SysFileSearch, and SysDriveMap functions. 
  10831.  
  10832.  
  10833. FINDFILE.CMD
  10834.  
  10835. /* Search all drives for files with a given string */
  10836. parse arg filespec '"' string '"'
  10837.  
  10838. drivelist = SysDriveMap()     /* get list of drives      */
  10839.  
  10840. do while drivelist <> ''      /* check each drive        */
  10841.   parse var drivelist drive drivelist
  10842.                               /* get the list of matching*/
  10843.                               /* files on this drive     */
  10844.  
  10845.  
  10846.   do i = 1 to files.0         /* seach each file         */
  10847.     call SysFileSearch string, files.i, 'Lines.', 'NC'
  10848.  
  10849.     if lines.0 > 0 then do    /* found something,        */
  10850.       say '===> "'string'"' found in file' files.i'
  10851.       do j = 1 to lines.0
  10852.         say '  ' lines.j
  10853.       end
  10854.     end
  10855.   end
  10856. end
  10857.  
  10858. The SysFileTree and SysFileSearch functions are different from the functions 
  10859. you've already tried. SysFileTree and SysFileSearch return lists of information 
  10860. by placing them directly into an array of REXX compound variables. The compound 
  10861. variables begin with a stem name that you provide to the SysFileTree or 
  10862. SysFileSearch functions. For example, the following SysFileTree calls returns a 
  10863. list of file names using the FILES. stem variable: 
  10864.  
  10865.      call SysFileTree drive'\', 'Files.', 'sf'
  10866.  
  10867. SysFileTree returns the list size in compound variable FILES.0.  Variables 
  10868. FILES.1, FILES.2, up to the size contained in FILES.0 contains the members of 
  10869. the list. 
  10870.  
  10871.  
  10872. ΓòÉΓòÉΓòÉ 17.2.1.6. Additional RexxUtil Functions ΓòÉΓòÉΓòÉ
  10873.  
  10874. RexxUtil contains many more functions than are covered here. There are 
  10875. functions for creating objects and object classes, functions for obtaining 
  10876. system values, and even a function to put your REXX program to sleep. 
  10877.  
  10878. For a more complete discussion of REXX utilities, refer to "Rexx Utilities" in 
  10879. the REXX Reference. 
  10880.  
  10881.  
  10882. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  10883.  
  10884. Trademark of IBM Corporation 
  10885.  
  10886.  
  10887. ΓòÉΓòÉΓòÉ <hidden>  ΓòÉΓòÉΓòÉ
  10888.  
  10889. Trademark of IBM Corporation