SYS SYSTEM FUNCTION CALLS SAN FRANCISCO STATE UNIVERSITY WINTER 1976 SYS SYSTEM FUNCTION CALLS 7.1 GENERAL SYS SYSTEM FUNCTION CALLS SYS system function calls allow a user program to perform special I/O functions, to establish special characterstics for a job, to set terminal characteristics, and to cause the monitor to execute special operations. The specified SYS format is employed for two reasons. One, the calls are unique to the BASIC-PLUS implementation of the BASIC language. As such, the calls are system dependent and have calling format different from any BASIC language call. Second, the SYS format allows the usage of a variable number of parameters. SYS calls are separated into two classes: privileged and non-privilieged. The privilieged calls can be used only by a privileged user or by a privileged program. The non-privileged calls can be used by anyone and are completely safe in the sense that their misuse can do no damage to other programs. 7.1.1 SYS System Function Formats And Codes The general format of the SYS call is as follows: V$ = SYS (CHR$ (F) + O$) where: V$ is the target string returned by the call F is the SYS system function code O$ is the optional (by function code) parameter string passed by the call Function codes denoted by F in the general format are from zero through nine, inclusive. SYS calls which specify a code outside of these numbers or which pass a zero length string generate the ILLEGAL SYS() USAGE error(ERR = 18). The following list summarizes the codes and their usages. The subsequent pages describe the usage, calling format, and purpose of the calls. Function Code(F) Usage 0 Cancel ^O effect on console terminal 1 Enter tapemode on console terminal 2 Enable echoing on console terminal 3 Disable echoing on console terminal 4 Enable single character input mode (ODT submode) on console terminal 5 Exit to editor with no READY message 6 SYS call to the file processor 7 GET core common string 8 PUT core common string 9 Exit to editor and set up NONAME program 7.1.2 General SYS System Function Calls 7.1.2.1 Cancel ^O Effect On Console Terminal - Not Privileged (F=0) Data Passed: Byte(s) 1 CHR(0%), the cancel ^O effect code 2 Optional. If specified, CHR$ (N% is the number of the channel on which the system executes the call. Data Returned: The target string is equivalent to the passed string. Discussion: This call cancels the effect of the user typing a CTRL/O COMBINATION AT the program's console terminal. If the call is in the form SYS (CHR$ (0%)), the system performs the action on the terminal open on channel N%. See Section 3.7 of the RSTS-11 System User's Guide for a description of the CTRL/O combination. 7.1.2.2 Enter Tape Mode On Console Terminal - Not Privileged (F=1) Data Passed: Byte(s) Meaning 1 CHR$(1%), THE ENTER TAPE MODE CODE 2 Optional. If specified, CHR$(N%) where N% is the number of the channel in which the system executes the call. Data Returned: The target string is equivalent to the passed string. Discussion: The action of this call is the same as that of the TAPE command described in the RSTS-11 System User's Guide. If the call is in the form SYS(CHR$(1%) + CHR$(N%)), the system performs the action on the terminal open on channel N%. 7.1.2.3 Enable Echoing On Console Terminal - Not Privileged (F=2) Data Passed: Byte(s) Meaning 1 CHR$ (2%), the enable echoing code 2 Optional. If specified, CHR$(N%) where N% is the number of the channel on which the system executes the call. Data Returned: The target string is equivalent to the returned string. Discussion: This code cancels the effect of SYS call with codes 1 and 3. If the form of the call is SYS (CHR$(2%) + CHR$(N%)), the action is performed on the terminal open on channel N%. 7.1.2.4 Disable Echoing On Console Terminal - Not Privileged (F=3) Data Passed: 1 CHR$(3%), the disable echoing code 2 Optional. If specified, CHR$(N%) where N% is the number of the channel on which the system executes the call. Data Returned: The target string is equivslent to the passed string. Discussion: This call prevents the system from echoing information typed at the console terminal. As a result, information such as a password is kept secret but accepted as valid input by the system. If the form of the call is SYS (CHR$(N%)), the action is performed at the terminal open on channel N%. 7.1.2.5 Enable Single Character Input Mode (ODT Submode) On Console - Terminal - Not Privileged (F=4) Data Passed: Byte(s) Meaning 1 CHR$(4%), the enable single character input mode code 2 Optional. If specified, CHR$(N%) where N% is the number of the channel on which the system executes the call. Data Returned: The target string is equivalent to the passed string. Discussion: Allows a single character to be accepted as input from the terminal. Normally, the system waits until a line terminated by a RETURN, LINE FEED, FORM FEED or ESCAPE character has been typed before accepting input. In single character mode, a character typed at the terminal is passed immediately to the program by the next keyboard input request statement without waiting forthe delimiting character. This function must be enabled prior to every input request statement that passes a single character to the program. A GET statement is used as the inputrequest statement. (INPUT or INPUT LINE statements cause repeated generation of the input request until a line terminator is detected and, therefore, must not be used.) If a program performs other lengthy operations before it executes it executes either another SYS call and GET statement or other input/output operation at the terminal, it allows time for the user to type more than one character. To provide for such a possibility, the program should examine the system variable RECOUNT after executing each GET statement. This procedure determines how many characters the user typed between keyboard input operations and enables the program to process all the characters without losing any. Since this function is used in the system program ODT.BAS, it is sometimes referred to as "ODT submode". If the form of the call is SYS (CHR$(4%) + CHR(N%)), the action is performed on the terminal open on channel N%. 7.1.2.6 Exit To Editor With No READY Message - Not Privileged (F=5) Data Passed: Byte(s) Meaning 1 CHR$ (5%), the exit with no READY code Data Returned: No data is returned. Discussion: This call causes the same effect as the END statement, execpt that it can appear anywhere in the program and does not cause a ready message to be printed. 7.1.2.7. FIP Function Call - Both Privileged and Not Privileged (F=6) See Section 7.2 for a description of SYS calls to the file processor. 7.1.2.8 Get Core Common String - Not Privileged (F=7) Data Passed: Byte(s) 1 CHR$(7%), the get core common string code Data Returned: The target string is the contents of the core common area. Discussion: Allows a program to extract a single string from a data area loaded by another program previously run by the same job. The data area is called the core common and is from 0 to 127 8-bit bytes long. Refer to SYS function code 8. 7.1.2.9 Put Core Common String - Not Privileged (F=8) Data Passed: Bytes(s) Meaning 1 CHR$ (8%), the put core common string code 2-128 The string to put in the core common area Data Returned: The target string is the passed string. Discussion: Allows a program to load a single string in a common data area called core common. This string can be extracted later by another program, running under the same job and called via the CHAIN statement. The string is from 0 to 127 8-bit bytes long. If the string to be put into the core common area is longer than 127 bytes, the system sets the length of the core common string to 0. Refer to SYS function code 7. This function provides a means for passing a limited amount of information when a CHAIN statement is executed. If a larger amount of information is to be passed, it must be written to a disk file and read back by the later program. 7.1.2.10 Exit To Editor And Set Up NONAME Program - Not Privileged (F=9) Data Passed: Byte(s) Meaning 1 CHR$(9%), the exit and set up NONAME string. Discussion: This function causes the same actions as the END statement placed in the code, and, in addition, clears the program out of memory. This is the proper method of stopping a program that is not to be rerun. Also, the same action is performed by the command NEW NONAME. 7.2 SYS SYSTEM FUNCTION CALLS TO FIP (FUNCTION CODE 6) The SYS function call whose code is 6 is a more specialized case of the general system function call. It is specialized by a subfunction code called the FIP code causes a dispatch call to be made to special resident or non-resident code that performs File Processing. O$ is the optional (by function) parameter string The general format of the target variable (V$) is: Byte(s) Meaning 1 Job number times 2 2 Value of Internal Function called (meaningless to general user) 3-30 Data returned NOTE Thirty bytes are always passed back. Unused bytes are either internal data or 0. The proper use of the FIP system function call requires that the user program build a parameter string to pass and that the program later extract the data from the returned string, called the target string. Each call returns a string of 30 bytes, each byte (or character) of which may or may not contain useful information. The descriptions of the FIP codes specify the contents of each useful byte in the string, from which the user determines whether the information contained is of interest. 7.2.1 Building a Parameter String Some FIP calls require no parameters except the function and subfunction codes; other FIP calls require either variable length parameter strings or very simple parameter strings. For such FIP calls, it is usually easiest to set up and execute the function call in a single statement. The following sample statements show the procedure. A$ = SYS (CHR$(6%) + CHR$(-7%)) !ENABLE CTRL/C TRAP ! (NO PARAMETER STRING) A$ = SYS(CHR$(6%) + "DK0:FILE.EXT") !File NAME STRING SCAN ! (VARIABLE LENGTH ! PARAMETER STRING) A$ = SYS (CHR$(6%) + CHR$((-8%) + CHR$(1%)) ! FCB/DDB INFORMATION ! FOR FILE OPEN ON ! CHANNEL 1 ! STRING 7.2.4 General Utility SYS Calls To Fip The SYS calls to the file processor described in this section are available to both privileged and non-privileged users. 7.2.4.1 File Name String Scan - Not Privileged (F0=10) (F0=-23) Data Passed: Byte(s) Meaning 1 CHR$ (6%) , the SYS CALL TO FIP 2 CHR$ (-10), the filename string scan code. CHR$ (-23), is the same as CHR$(-10) except that the scan terminates on certain characters. See discussion. 3-? Character string to scan; can be any length. Data Returned: Sets the STATUS variable and returns the following. Byte(s) Meaning 1-4 Internal coding 5-6 Project-programmer number (0 means the current account) 7-10 File name in Radix-50 format 11-12 Filename extension in Radix-50 format 13-20 Not used 21 If no protection code is found, this byte is 0. Otherwies, this byte is 255 and byte 22 contains 26 If this byte is 0, no explicit unit number was found for the device. If this byte is 255, the value in byte 25 is the explicitly specified device unit number. The 255 value here indicates that a zero in byte 25 is explicitly unit 0 of the device. Byte(s) Meaning 27-28 First flag word. See discussion. 29-30 Second flag word. See discussion. Possible Errors: Meaning ERR Value ILLEGAL FILE NAME 2 The character string scanned contains unacceptable charcters. See section 9.1 of the BASIC- PLUS Language Manual for a Description of a file specification. Discussion: The file name string scan function determines specific file syntax information (for example, whether a given file name is valid) and returns information in the format required for all other file and device related SYS calls. In addition, it provides a means of packing a string in Radix-50 format. The STATUS variable (see Section 12.3.5 of the BASIC-PLUS Language Manual) is set for the device type found in the string scanned. The following example demonstrates how a string can be converted to Radix-50 format by a user defined function and the file name string scan SYS call. 10 DEF FNP0$(A$) = MID (SYS(CHR$(6%) + CHR$(-10%)+A$),7%,4%) ! PACK 6 CHARACTERS TO RADIX-50 The function FNP0$ returns a 4-character string which is the Radix-50 representation of the first six characters of A$. (Note that no error handling is included and that errors can occur.) The file name string scan call is the only function in BASIC-PLUS which packs a string in Radix-50 format. To pack strings longer than six characters, the user user must make multiple calls to the SYS function. The two words in bytes 27 and 28 and in bytes and in bytes 29 and 30 hold easily accessible flags indicating exactly what fields in the source string were found and what kind of information they contained. For the purposes of discussion, it is assumed that the returned string was converted by a change statement to an integer array, M%(30%). The flag words are then created by doing the proper arithmetic operations on the bytes, as shown: flag word 1: S0% = M%(27%)+SWAP%(M%(28%)) flag word 2: S1% = M%(29%)+SWAP%(M%(30%)) Once these two words are created, the data coded into them is accessible by means of an AND operation between the word and the bit relating to a particular piece of information (see Section 2.8.7 for information about the AND operation). Each bit of the PDP-11 word can be used to hold a YES or NO answer. In the case of S0%, only the high-order 8 bits are used. In the case of S1%, all 16 bits are used. Flag work 1 is redundant; that is, all information returned in flag word 1 is also in flag word 2. Flag word 2 holds much more information than flag word 1. In the following discussion, it is assumed that bytes 27 and 28 have been put into S0% and bytes 29 and 30 have been put into S1% as described above. Flag word 1: where S0% = M%(27%)+SWAP%(M%(28%)) Bit Comparison Meaning 8 S0 AND 256%<>0% Filename was found in the source string (and is returned in Radix-50 format in bytes 7 through 10) 9 S0% AND 256% = 0% No filename found S0% AND 512% <>0% A dot was found in source string S0% AND 512% = 0% No dot was found in source string implying that no extenson could have been specified either 10 S0% AND 1024%<>0% A project-programmer number was found in source string S0% AND 1024% = 0% No project-programmer number was found 11 S0% AND 2048%<>0% A left angle bracket (<) was found in source string implying that a protection code was found S0% AND 2048%=0 No left angle bracket (<) was found (no protection was specified) 12 S0% AND 4096%<>0% A colon (but not necessarily a device name) was found S0%AND 4096% = 0% No colon was found implying that no device could hve been specified 13 S0% AND 8192%<>0% Device name was specified and specified device name was a logical device name S0% AND 8192%<>0% Device name (if specified) was an absolute (non-logical) device name (if device name was not specified, this will 0) 15 S0%<0% Source string contained wild card characters (either ? or * or both) in filename, extension or project programmer number fields. In addition, the device name specified, though a valid logical device name, possibly does not correspond to any of the logical device assignments currently in effect. The user program must extract the device name and attempt to access the unit. (See Section 7.2.16.4 for a description of wild card file specifications.) Flag Word 2: where S1% = M%(29%) + swap%(M%(30%)) Bit Comparison Meaning 0 S1% AND 1%<>0% File name was found in the source string S1% AND 1% = 0% No file name was found (and the following two comparisons return 0) 1 S1% AND 2%<>0% File name was an * character and is returned in bytes 7 through 10 as the Radix-50 representation of the string "???????". S1% AND 2%=0% File name was not an * character 2 S1% AND 4%<>0% Filename contained at least one ? character S1% AND 4% = 0% Filename did not contain any ? characters 3 S1% AND 8%<>0% A dot (.) was found S1% AND 8%=0% No dot was found implying that no extension was specified (and the following three comparisons return 0) 4 S1% AND 16%<>0% An extention was found (that is, the field after the dot was not null) S1% AND 16% = 0% No extension was found (the field after the dot was null - the following two comparisons return 0) 5 S1% AND 32%<>0% Extension was an * character and is returned in bytes 11 and 12 as the Radix-50 Representation of the string "???" S1% AND 32% =0% Extension was not an * character 6 S1% AND 64%<>0% Extension contained at least one ? character S1% AND 64% = 0% Extension did not contain any ? Characters 7 S1% AND L@*%<>0% A Project-programmer number was found S1% AND 128% = 0% No project-programmer number was found (the following two comparisons return 0) 8 S1% AND 256%<>0% Project number was an * character (that is the projelct-programmer number was of the form [*PROG]) amd os returned in byte 6 as 255 S1% AND 256% = 0% Project number was not an * character 9 S1% AND 512%<>0%(1) Programmer number was an * character (that is, the project-programmer number was of the form [PROJ,*] and is returned in byte 5 as 255 S1% AND 512% = 0% Programmer number was not an * character 10 S1% AND 1024%<>0% A protection code was found S1% AND 1024% = 0% No protection code was found 11 S1% AND 2048%<>0% The protection code currently set as default by the current job was used S1% AND 2048% = 0% The assignable protection code was not used (protection code given is either the system default, 60, or that found in the source string) 12 S1% AND 4096%<>0% A colon (:), but not necessarily a device name, was found in the source string S1% AND 4096% = 0% No colon was found (no device could have been specified); the following three comparisons return 0 13 S1% AND 8192%<>0% A device name was found S1% AND 8192% = 0% No device name was found ; the following two comparisons return 0 14 S1% AND 16384%<>0% Device name specified was a logical device name S1% AND 16384% = 0% Device name specified was an actual device name 15 S1% <0% The device name specified was logical and is not assigned to some actual device; the logical name is returned in bytes 23 through 26 as a Radix-50 string ------------- (1) Note that if the project-programmer number was of the form [*,*], then both bit 8 and bit 9 of the data byte returned are non-zero values. S1%>=0 The device name specified, if any, was logical device name to which a value has been assigned; the physical device name is returned in bytes 23 through 26 as described above. Since flag word 2 contains all the information returned in flag word 1 plus more information, it is the more useful of the two words. The following program uses this word. It prints out a list of all the bits returned in the word. 5 DIM M%(30%) ! SET UP AN ARRAY TO RETURN TO 10 PRINT "STRING TO SCAN" 20 INPUT LINE S$ 30 S$=CVT$$(S$,-1%) ! GET RID 0F GARBAGE BYTES 40 CHANGE SYS(CHR$(6%)+CHR$(-10%)S$) TO M% 50 S1%=M%(29%)+SWAP%(M%(30%)) 100 IF S1% AND 1% THEN PRINT "FILENAME FOUND" l10 IF S1% AND 2% THEN PRINT "FILENAME WAS AN *" l10 IF S1 AND 4% THEN PRINT "FILENAME HAD '?' S" 130 IF S1 AND 8% THEN PRINT "DOT () FOUND" 140 IF S1 AND 16% THEN PRINT "NON-NULL EXTENSION FOUND" 150 IF S1 AND 32% THEN PRINT "EXTENSION WAS '*'" 160 IF S1 AND 64% THEN PRINT "EXTENSION HAD '?'S" 170 IF S1 AND 128% THEN PRINT "PPN FOUND" 180%IF S1 AND 256% THEN PRINT "PROJECT NUMBERS WAS '*'" 190 IF S1 AND 512% THEN PRINT "PROGRAMMER WAS '*'" 200 IF S1% AND 1024% THEN PRINT "PROTECTION CODE FOUND" 210 IF S1% AND 2048% THEN PRINT "ASSIGN'D PROTECTION USED" 220 IF S1% AND 4096% THEN PRINT "COLON (:) FOUND" 230 IF S1% AND 8192% THEN PRINT "DEVICE NAME FOUND" 240 IF S1% AND 16384% THEN PRINT "DEVICE NAME WAS LOGICAL" 250 IF S1%(0% THEN PRINT "DEVICE NAME WAS NOT ASSIGN'D" 260 IF S1% AND 4096% THEN IF S1>0% THEN PRINT "'STATUS' HAS BEEN SET" 490 PRINT FOR I%=1% TO 2% 500 GO TO 10 32767 END The following examples show some of the above messages: STRING TO SCAN? ABCDEF. EXT FILENAME FOUND DOT ( ) FOUND NON-NULL EXTENSION FOUND STRING TO SCAN? SY:FILENM. DEX FILENAME FOUND DOT ( ) FOUND NON-NULL EXTENSION FOUND COLON (: ) FOUND DEVICE NME FOUND 'STATUS' HAS BEEN SET STRING TO SCAN? SY:FILENM. EXT[1,203] FILENAME F0UND DOT (. ) FOUND NON-NULL EXTENSION FOUND PPN FOUND COLON (:) FOUND DEVICE NAME FOUND 'STATUS' HAS BEEN SET STRING TO SCAN? SY:FILENM> EXT[2,103]<52> FILENAME F0UND DOT (. ) FOUND NON-NULL EXTENSION FOUND PPN FOUND PROTECTION CODE FOUND COLON (: ) FOUND DEVICE NAME FOUND 'STATUS' HAS BEEN SET STRING TO SCAN? SY:FILENNM. EXT[*,20l] FILENAME FOUND D0T (. ) FOUND NON-NULL EXTENSION FOUND PPN FOUND PROJECT NUMBER WAS '*' COLON (:) FOUND DEVICE NAME FOUND 'STATUS' HAS BEEN SET STRING TO SCAN? SY:A.* FILENAME FOUND DOT (.) FOUND NON-NULL EXTENSION FOUND EXTENSION WAS '*' COLON (:) FOUND DEVICE NAME FOUND 'STATUS' HAS BEEN SET STRING TO SCAN? STRING TO SCAN?SY:FILE??. EXT FILENAME FOUND FILENAME HAD '?'S DOT (.) FOUND NON-NULL EXTENSION FOUND COLON (:) FOUND DEVICE NAME FOUND} 'STATUS' HAS BEEN SET STRING TO SCAN? :A FILENAME FOUND COLON (:) FOUND 'STATUS'HAS BEEN SET The STATUS variable is set or not set depending on the presence or absence of a device in the string scanned. The following three conditions pertain. a. When no device name is found in the string (no colon is found), the STATUS is random. This condition pertains when bit 12 of flagword 2 tests as equal to 0. b. When the device name is logical and untranslatable (an actual device is not assigned), STATUS is random. This condition pertains when bits 12, 13, and 14 of flag word 2 test as not equal to 0 and bit 13 tests as on (S1%<0%). c. When the device name is either an actual device name or is logical and translatable (an actual device is assigned), STATUS is set for the device. This condition pertains when bit 12 tests as not equal to 0 and bit 15 tests as equal to 0 (S1%>=0%). Line 260 of the sample program shows the test to determine when STATUS is set by the call. The file name string scan using CHR$(-23%) in place of CHR$(-10%) terminates without error on the following characters. = (equality sign) / (slant) ; (semi-colon) , (comma) end of string The number of unscanned characters is returned in the BASIC-PLUS variable RECOUNT. FOR EXAMPLE, S$=SYS(CHR$(6%) + CHR$(-23%) + "SY:[1,4]ABC<40>") returns the data as described above for CHR$(-10%) and RECOUNT equals 0. The followin call S$ = SYS(CHR$(6%) + CHR$ (-23%) + "SY:[1,4]ABC<40>,DT:DEF") returns the data described above for the string "SY:[1,4]ABC<40>" with RECOUNT equals 7. (The scan terminates on the comma between file names. Any other characters, including the angle bracket character (<), generate an error and none of the data is returned. Thus, the call with CHR$(-23%) simplifies the task of decoding command strings with multiple file names. 7.2.4.2 Return Error Message - Not Privileged (F0=9) Data Passed: Byte(s) Meaning 1 CHR$ (6%), the SYS call to FIP 2 CHR$ (9%), the return error message code 3 CHR$ (E%), where E% is the RSTS ERR variable number and is between 0 and 127 4-30 Not used Data Returned: Bytes(s) 1 The current job number times 2 2 The keyboard number times 2 3-30 Error message padded to length 28 with CHR$(0%) characters. Possible Errors: No errors are possible. Discussion: file ERR.SYS stored under account [0,1] or in the RSTS.CIL file if This SYS system function call extracts error message text from the ERR.SYS does not exist. The text is associated with the value of the ERR variable passed as byte 3 of the call. The number in byte 2 of the returned string is two times the number of the keyboard involved in generating the error. This is an exception to the conventional contents of byte 2 which usually contains the job number times 2. A sample usage of the call is to print the system header line containing the system name and the local installation name. To do this, the character representation of the ERR value of 0% is used in the call. 10 INPUT "ERR0R NUMBER"; E% 20 S$=SYS(CHR$(6%)+CHR$(9%)+CHR$(E%)) 30 S1$=MID(S$,3%,INSTR(3%,S$,CHR$(0%))-3%) 40 PRINT S1$ 50 PRINT FOR I%=1% TO 2% 60 GOTO 10 32767 END To extract the message text from the data returned by the SYS call, the program executes an INSTR function based on the NUL byte (FILL character) indicating the end of the text. The MID substring of the returned data string, starting at byte number 3, extracts the number of bytes according to the value returned by the INSTR function. Error numbers used in the call can include those associated with recoverable and non-recoverable errors. RUNNH ERROR NUMBER? 0 RSTS V06A-0l SYSTEM #880 7.2.4.7 CTRL/C Trap Enable - Not Privileged (F0=-7) Data Passed: Byte(s) Meaning l CHR$(6%), the SYS call to FIP 2 CHR$(-7%),the CTRL/C trap enable code 3-30 Not used. Data Returned: No meaningful data is returned. Possible Errors: No errors are possible. Discussion: After this FIP function is executed in the user program, the Run Time System treats the first CTRL/C subsequently typed on any terminal belonging to the job as a trappable error (ERR=28). Upon execution of the trap, control is immediately passed to the numbered program statement which has been designated as the error-handling routine by the last execution of an ON ERROR GOTO statement. After the trap, CTRL/C trapping is disabled. If it is desired that CTRL/C trapping remain in effect, the SYS call must be executed again. Such trapping of CTRL/C, however, guarantees only that a defined set of statements is executed when CTRL/C is typed. It is not possible to resume execution at the exact point where the CTRL/C Occurred. 8.4 PROGRAMMING HINTS These sections describe suggested programming methods in two categories: reducing overhead storage spce in programs and decreasing required access time for certain operations. Normally these are mutually exclusive goals. Space is most often saved at the expense of time, and vice versa. In the sections that follow, a discussion of either commodity ignores the other, so it is up to the user to decide when each of these methods can best be used for a particular application. Of course, when both space and time are optimized, as is the case with some of these methods, the entire RSTS/E system as well as the individual program benefits. 8.4.1 Storage Space Overhead Certain steps can be taken to reduce overhead significantly. This section describes some of the most efficient methods to optimize the storage space available on a RSTS/E system. Combining statements on a line with the use of colons or backslashes saves statement header space. When using multiple statement lines, remember the maximum line length is 256 characters. Verbs that always require a statement header, regardless of where they occur, are : DATA, DEF, DIM, FNEND, FOR and NEXT. Whenever possible these statements should be first on a lie to reduce statement header overhead. Statements such as INPUT, which may generate errors, should always be first on a line because a RESUME statement, when executed from an error handling routine, resumes program execution at the nearest preceding statement header. Similarly, since a GOTO statement begins execution only at the first statement of the specified line, the beginning of each routine in a program should be the first statement on a line. Use the exclamation point (!) within statement lines to indicate remarks. The REM statement or an exclamation point with its own line number requires a 12-byte statement header. variable, separate space is required to store the value. This space is required for constants every time they are referenced. 0nce a variable is defined, however, further references generate no more space. For this reason, frequently used constants should be declared as variables. For example: 10 A% = 278%: B% = 278% requires more storage space 10 A% = 278%: B% = A% PROGRAMMING CONVENTIONS AND HINTS And the following statement, accomplishing the same thing, uses the least storage space: 10 A%,B% = 278% In some cases assigning a temporary variable saves vector addressing space. For example, consider this program segment: 10 FOR I% = 1% TO N%: S = S + T: S2 = S2 + X(I%) * X(I%) 20 NEXT I% Assigning a new variable (T), equal to an indexed variable (X(I%)) decreases the number of bytes of storage area as follows: 10 FOR I% = 1% TO N% : T = X(I%) : S = S + T : S2 = S2 + T * T 20 NEXT I% In addition, the example shown above executes quickly since recalculation of vector addresses is eliminated. Similarly, previously calculated items should be re-used. For example: 10 D = SQR(B^2 - 4*A*C)/2%*A: PRINT -B/2%*A + SQR(B^2 - 4*A*C)/2%*A; -B/2%*A - SQR(B^2 - 4*A*C)/2%*A obviously should be written: 10 D = SQR(B^2 - 4*A*C)/2%*A: PRINT -B/2%*A + D; -B/2%*A - D example: 20 A = B + C: D = A + E: F = D + G should be condensed to: 20 F = B + C + E + G unless the variables A and D are to be used independently later in the program. Use integer variables when possible, and always denote them with the percent sign (%). The subscripts in arrays should always be integers, specified with % signs. Use integers in FOR/NEXT loops unless the STEP function value is not an integer. Every constant should include a % or a period (.) each time it is used. Variables with the same first character should be used when possible. For example: A, A%, A$, A(...), A%(...), A$(...) each have the same first character, but A and B do not, and because of the way BASIC-PLUS stores variables, they use more space. So if the variable R is used in the program, using R% is preferable to using another integer variable. Always use as few variables as possilbe; re-use these variables for even more space savings, since no additional overhead is needed. Variables do not have to be compared to zero explicitly. For example: 30 IF M%< > 0% THEN 80 Space can be saved by using subroutines instead of user-defined functions, but be sure to exit with RETURN (not GOTO) statements. Individual variable names are often more economical than arrays, since they require less overhead. But if arrays are used, always dimension them first and limit the use of MAT statements. Use implied FOR loops, which require less core and execute faster, than FOR/NEXT loops. For example: 10 FOR I% = 1% TO 10%: R% = R%^2% 120 IF X% = K% THEN 500 130 IF X% = L% THEN 600 can be rewritten as follows: 100 IF X% = W% THEN 250 ELSE IF X% = A% THEN 300 ELSE IF X% = K% THEN 500 ELSE IF X% = L% THEN 600 This compound IF format, above, saves 35% more core than the single IF format. When a variable is to be compared to some continuous range of values, replace the IF statements with an ON-GOTO statement. For example: 100 IF X% = 4% THEN 250 ELSE IF X% = 5% THEN 300 ELSE IF X% = 6% THEN 500 ELSE IF X% = 7% THEN 600 should be replaced with: 100 ON X%-3% GOTO 250,300,500,600 A similar technique can be used with strings. The following example: 80 IF A$ = "A" THEN GOTO 100 ELSE IF A$ = "B" THEN GOTO 200 ELSE IF A$ = "C" THEN GOTO 300 ELSE IF A$ = "D" THEN GOTO 400 can be rewritten: 80 X% = ASCII(A$)-64% : ON X% GOTO 100,200,300,400 Random string responses can be tested also. For example, to compare A$ with the letters X,K,B and Y, use the following statement: 80 ON INSTR(1%,'XKBY',A$) GOTO 100,200,300,400 8.4.2 Decreasing Access Time There are a number of ways access time can be saved once data or programs are stored on disks. The BASIC-PLUS Language Manual describes some of these methods (for example, see Section 11.5 in that manual). Methods of setting up files are equally important and are discussed in this section. Most of these methods can be employed by users, but some of them may require the assistance of the system manager. Open files at the beginning of a program and pre-extend them to their maximum size. Also, pre-allocate scratch data files and, when through using them, simply close them instead of killing them. In this way, they can be re-used without wasting disk space and, ultimately, access time. These techniques tend to reduce directory fragmentation, decreasing access time. Keep large, frequently used files on separate disks. When two files are often opened at the same time, they too should reside on separate disks. Also, production files and accounts should be kept separate from development and scratch files when possible. If they cannot be kept on separate disks, they should at least be maintained on in separate accounts. File and pack clustersizes should be optimized, as mentioned in the BASIC-PLUS Language Manual and the RSTS/E System Manager's Guide, respectively. 8.4.3 String Manipulation Pre-extend all strings to their maximum length at the beginning of a program, as follows: X% = SPACES$(L%) where L% is the maximum length of the string. Then use LSET and RSET statements (don't re-use LET) to move data into the string. The difference between LET and LSET can be seen with the diagrams shown below. Consider the following statements: 10 LET A$ = "ABCD" 20 LET C$ = "EFG" 50 LET C$ = A$ + "" A$ =======> "ABCD" C$ =======> "ABCD" LSET and RSET statements move data; LET statements move pointers. Proper use of LSET and RSET prevents generation of wasted space, and execute faster than LET statements. The following three algorithms truncate trailing blanks from a data record (for example, a card image). The first two user-defined functions input a string and return the same string without trailing blanks and CR/LF The slowest algorithm successively reassigns the argument until it ends with a non-blank: 1000 DEF FNT$(X$): S$ = LEFT(X$,LEN(X)-1%) WHILE RIGHT(X$,LEN(X$)) <= " " AND LEN(X$) > 0% 1010 FNT$ = S$ 1020 FNEND The following algorithm is much more efficient. It scans backwards until a non-blank character is found. Only one assignment is made. 200 DEF FNW$ (X$): GOTO 2010 IF MID(X$,X%,1%) > " " FOR X% = LEN(X$) TO 0% STEP -1% 2010 FNW$ = LEFT(X$,X%) 2020 FNEND The most efficient algoritm uses the data buffer directly, avoiding the assignment caused by the user-defined function. L% is the record length. 3000 FOR K% = L% TO 1% STEP -1%: FIELD #2%, K%-1% AS L$, A% AS L$: IF L$ > " " THEN FIELD #2%, K% AS L$: GOTO 3020 3010 NEXT K%: LSET L$ = " " 3020 ! DONE The more efficient algorithms are more cpu-bound because they do less swapping. This was typed by Michael Breskin and Amy Lynn Palmer. Michael Breskin made numerous typos, all of which Amy Lynn Palmer was unable to correct. Please send any errors that you find to: Stan Osborne c/o Jack H Rhine Jr San Francisco State University Educational Technology Center 1600 Holloway Ave. San Francisco, CA 94132 Phone: (415) 469-2357