Ratfiv May 14, 1981 RATFIV PRIMER Ratfiv is a preprocessor for Fortran. Its primary purpose is to encourage readable and well-structured code while taking advantage of the universality, portability, and efficiency of Fortran. This is done by providing the control structures not available in bare Fortran, adding a sophisticated macro processor, and by improving the "cosmetics" of the language. Ratfiv allows for all the features of normal Fortran, plus makes available these control structures: "if"-"else" "while", "for", "do", and "repeat"-"until" looping constructs the "switch" case statement "break" and "next" for exiting loops statement grouping with braces The cosmetic aspects of Ratfiv have been designed to make it concise and reasonably pleasing to the eye: "include" statement for including source files "return value " statement in functions formats may be specified in read, write, encode, and decode statements "string" statement for initialization of character arrays specification of numbers in bases 2-36 free form input unobtrusive comment convention translation of >, <=, etc. into .GT., .LE., etc. quoted character strings In addition, Ratfiv provides a sophisticated macro processor for the definition of symbolic constants as well as macros with arguments. Ratfiv is implemented as a preprocessor which translates the above features into Fortran, which can then be fed into almost any Fortran compiler. The section of this document titled "Using Ratfiv" tells how to invoke Ratfiv on your system. Each of the Ratfiv features will now be discussed in more detail. Please note that although the examples are given in lower case, upper case may be used as well for writing Ratfiv. In the following, a "statement" is any legal statement in Fortran: assignment, declaration, subroutine call, I/O, etc., or any of the Ratfiv statements themselves. Any Fortran or Ratfiv statement or group of these can be enclosed in braces-- { } --or brackets-- [ ] --to make it a compound statement, which is then equivalent to a single statement and usable anywhere a single statement can be used. -1- Ratfiv May 14, 1981 IF-ELSE Ratfiv provides an "else" statement to handle the construction "if a condition is true, do this thing, otherwise do that thing". The syntax is if (legal Fortran condition) statement(s) else statement(s) where the else part is optional. The "legal Fortran condition" is anything that can legally go into a Fortran logical IF. The Ratfiv statements may be one or more valid Ratfiv or Fortran statements of any kind. If more than one statement is desired, the statements must be enclosed by braces. For example, if (a > b) { k = 1 call remark (...) } else if (a < b) { k = 2 call remark (...) } else return -2- Ratfiv May 14, 1981 WHILE Ratfiv provides a while statement, which is simply a loop: "while some condition is true, repeat this group of statements". The syntax is while (legal Fortran condition) statement(s) As with the if, "legal Fortran condition" is something that can go into a Fortran logical IF. The condition is tested before execution of any of the Ratfiv statements, so if the condition is not met, the loop will be executed zero times. Also, as with the IF, the Ratfiv statements can be any valid Ratfiv or Fortran constructs. If more than one statement is desired, the statements must be enclosed by braces. For example, WHILE (GETC(C) != EOF) [ C = CNVT(C) CALL PUTC(C) ] Note that upper case is perfectly acceptable to Ratfiv, and that brackets ([]) may be used instead of braces ({}). -3- Ratfiv May 14, 1981 FOR The "for" statement is similar to the "while" except that it allows explicit initialization and increment steps as part of the statement. The syntax is for (init; condition; increment) statement(s) where "init" is any single Fortran statement which gets done once before the loop begins. "Increment" is any single Fortran statement which gets done at the end of each pass through the loop, before the test. "Condition" is again anything that is legal in a logical IF. Any of init, condition, and increment may be omitted, although the semicolons must remain. A non-existent condition is treated as always true, so "for( ; ; ) " is an indefinite repeat. The "for" statement is particularly useful for chaining along lists, loops that might be done zero times, and similar things which are hard to express with a DO statement. Here are two examples of "for" loops: for (i=1; getarg(i, file, MAXLINE) != EOF; i=i+1) { int = open (file, READ) while (getlin (line, int) != EOF) { for (j=80; j>0; j=j-1) call putc (line(j)) } call close (int) } The above code simply reads cards from a list of files, reverses the order of the characters, and writes the cards onto a standard output file. (The "!=" means . NE.) -4- Ratfiv May 14, 1981 DO The "do" statement is like the Fortran do-loop. The syntax is: do Fortran do-part statement(s) The Fortran do-part is whatever Fortran will accept after a do, with the exception of the statement label. If more than one Ratfiv statement is desired, they must be enclosed in brackets. For example: do i = 1,10 { do j = 1,10 x(i,j) = 0.0 x(i,i) = 1.0 } -5- Ratfiv May 14, 1981 REPEAT-UNTIL The "repeat-until" statements allow for repetition of a group of statements until a specified condition is met. The syntax is: repeat statement(s) until condition The "until" is optional. Once again, if more than one Ratfiv statement is desired, the statements must be enclosed by brackets. If the "until" part is omitted, the result is an infinite loop which must be broken with a "break" or "next" statement (see below). An example of a repeat-until loop is: repeat { call putc (BLANK) col = col + 1 } until (tabpos(col,tabs) == YES) -6- Ratfiv May 14, 1981 SWITCH The switch statement is a multi-way decision maker that allows selection of one path of execution from among many based on the value of an expression. It is similar to the computed goto in Fortran, however it is more flexible. The syntax is: switch (legal fortran expression) { case expr: statement(s) ..... default: statement(s) } The legal fortran expression in parentheses is evaluated and then tested in turn against each of the constant expression(s) in each case statement; when a matching value is found, execution is started at that case. Once the statements at the matching case have been executed, execution continues after the "switch" statement. The case labelled "default" is executed if none of the other cases match. The "default" is optional; if ommitted and none of the cases match, no action is taken and execution falls through to the end of the case statement. An "expr" may be a list of constants separated by commas, a single constant, or a range of constant values separated by a "-" (minus) character. Constants must be integers, character constants of the form 'c' or "c", or a define which evaluates to one of the above. Cases and defaults may occur in any order, and must be different. Note that the brackets are neccessary here. Following is an example of the "switch" statement: switch (i-1) { case 1: call docas1 case 2,3: j = 2 write(5, (' executing cases 2,3!')) if (x > y) break y = x case 8-12,'B',"0-9": .... default: write(5, (' error in switch statement!')) } The "break" statement in case 2,3 above causes a jump to the end of the "switch" statement; see below under "break". -7- Ratfiv May 14, 1981 BREAK and NEXT Ratfiv provides statements for leaving a loop or switch statement early and for beginning the next iteration. "Break" causes an immediate exit from whatever loop (which may be a "while", "for", "do", or "repeat") or switch statement it is contained in . Control resumes with the next statement after the loop or switch statement. If "break" is followed by a number, then that many enclosing loops and/or switch statements are exited, otherwise the loop or switch statement in which the "break" appears is exited. For example: repeat { if (getc(c) == EOF) break ... } "Next" is a branch to the bottom of a loop, so it causes the next iteration to be done. "Next" goes to the condition part of a "while" or "until", to the top of an infinite "repeat" loop, to the increment part of a "for", and to the next iteration of a "do". If a number is specified after the "next", then control is given to the condition part of the loop which is that many nested loops out from the "next", otherwise control is given to the condition part of the enclosing loop. For example: for (i=1; i<10; i=i+1) { if (array(i) == BLANK) next ... } -8- Ratfiv May 14, 1981 RETURN The "return" statement may be used as usual in Ratfiv. However, in a function subprogram the function value may be implicitly assigned before returning using the following syntax: return value Here "value" is the value of the function subprogram. For example: integer function index(char,strng) byte strng(80), char for (i = 1; i <= 80; i = i+1) if (strng(i) == char) return i return 0 end -9- Ratfiv May 14, 1981 SPECIFYING FORMATS Format specifications may be included in read, write, encode, and decode statements by including the specfication, surrounded by parentheses, in the same position in the statement as the format statement number would normally appear. For example: write(5, ('$FILE? ')) read(5, (80a1), end=99) file Formats may be specified in the usual way by specifying a normal statement number instead of a parenthesized format specification. For example: read(5, 10, end=99) file 10 format(80a1) -10- Ratfiv May 14, 1981 STRING The "string" statement defines the size and contents of a character array. The syntax is: string name "character string" or string name(size) "character string" The first form of the string statement defines 'name' to be a character (byte on DEC systems) array big enough to accommodate all the characters in the character string plus a terminating end of string character (EOS is 0 on DEC systems). The second form allocates 'size' characters for 'name' and initializes it to the specified character string with the EOS character. 'size' must be large enough to hold the entire string plus the terminator. A tab or newline character may be specified in the character string by @T or @t for tab and @N or @n for newline. @@ inserts an @ character. All string statements must appear together after all normal Fortran declarations and before any DATA statements. Example: string error "Error reading file. Execution terminated." string file(FILENAMESIZE) "SY:" -11- Ratfiv May 14, 1981 INCLUDE Files may be inserted into the input stream via the "include" command. The statement include filename or include "filename" or include 'filename' inserts the file found on input file "filename" into the Ratfiv input in place of the include statement. This is especially useful in inserting common blocks. For example, function exampl (x) include comblk exampl = x + z return end might translate into function exampl (x) common /comblk/ q, r, z exampl = x + z return end -12- Ratfiv May 14, 1981 STATEMENT GROUPING AND NULL STATEMENTS Ratfiv allows a group of statements to be treated as a unit by enclosing them in braces -- { and }. This is true throughout the language: wherever a single Ratfiv statement can be used, there could also be several enclosed in braces. For example: if (x > 100) { call error (...) err = 1 return } If braces are not valid characters in the local operating system, or if you wish to use upper case only, the characters "[" and "]" may be used instead of "{" and "}" respectively. Ratfiv also allows for null statements, most useful after "for" and "while" statements. A semicolon alone indicates a null statement. For instance, while (getlin(line, int) != EOF) ; would read lines from a file until the end-of-file was reached and for (i=1; line(i) == BLANK; i=i+1) ; positions after leading blanks in a line. -13- Ratfiv May 14, 1981 FREE-FORM INPUT Statements may be placed anywhere on a line and several may appear on one line if they are separated by semicolons. No semicolon is needed at the end of each line because Ratfiv assumes there is one statement per line unless told otherwise. Ratfiv will, however, continue lines when it seems obvious that they are not yet done, or if the line explicitly ends with an underline ("_"). Note that the underline is not included in the Fortran output of Ratfiv. Do not attempt to use a continuation character in column 6 to continue a line. Any statement that begins with an all-numeric field is assumed to be a Fortran label and is placed in columns 1-5 upon output. Ratfiv generates labels starting at 2000 and increasing by intervals of 10, so try to use labels under 2000 for your own uses. Statements may be passed through the Ratfiv compiler unaltered in two ways; if the toggle character "%" appears on a line by itself before and after the lines desired to be literal, the lines will be passed through unaltered to Fortran. However if the line on which the "%" character appears has other non-blank characters after the "%" character, those characters will be passed to Fortran and a matching "%" character is not needed. This is a convenient way to pass regular Fortran code through the Ratfiv compiler. Be careful to indent Fortran code passed this way to column seven! -14- Ratfiv May 14, 1981 COMMENTS A sharp character "#" in a line marks the beginning of a comment and the rest of the line is considered to be that comment. Comments and code can co-exist on the same line. For example, function dummy (x) # I made up this function to show some comments dummy = x #I am simply returning the parameter return end -15- Ratfiv May 14, 1981 CHARACTER TRANSLATION Sometimes the characters >, <=, etc. are easier to read in Fortran condition statements than the standard Fortran . EQ., . LT., etc.. Ratfiv allows either convention. If the special characters are used, they are translated in the following manner: == .EQ. != or ^= or ~= .NE. < .LT. > .GT. <= .LE. >= .GE. | or \ .OR. & .AND. ! or ^ or ~ .NOT. For example, for (i=1; i<= 5; i=i+1) ... if (j != 100) ... -16- Ratfiv May 14, 1981 SPECIFYING NUMBERS IN BASES OTHER THAN BASE TEN Numbers may be specified in any of the bases 2-36. Base ten is the default base. Numbers in other bases are specified as n%dddd... where 'n' is a decimal number indicating the base and 'dddd...' are digits in that base. Digits above 9 are specified by the letters a-z (A-Z), where 'a' stands for 10, 'b' for 11, etc. For example, 8%100000 stands for -32768 base 10 16%ff stands for 255 base 10 -17- Ratfiv May 14, 1981 QUOTED CHARACTER STRINGS Character strings may be enclosed in single or double quotes. To specify a quote character inside a string, repeat the character twice, e.g. if you want: he's back then say: 'he''s back' Unfortunately there is currently no way to include a " character within a double quoted string; however the string may be single quoted with no loss of function, since any character may appear inside a single quoted string. Note: Octal constants which are defined by a preceding double quote as in DEC Fortran will be passed successfully through Ratfiv if only one octal constant appears per line; otherwise Ratfiv will assume that a quoted string was desired. It is recommended that Ratfiv's method for specifying bases other than decimal be used, however (see above). -18- Ratfiv May 14, 1981 DEFINE MACRO PROCESSOR The "define" statement allows you to define symbolic constants (macros). The simplest use of "define" allows you to define any string of alphanumeric characters as a symbolic constant; thereafter, whenever that symbolic constant occurs in the input (delimited by non-alphanumerics) it is replaced by the definition of that constant. "Define" could be used to make these symbolic parameters: define(ROW,10) define(COLUMN,25) dimension array (ROW, COLUMN) and define(EOF,-1) if (getlin(line, int) == EOF) .... Definitions may be included anywhere in the code, as long as they appear before the defined name occurs. Defined names may contain letters, digits, and the underscore and dot characters. Uppercase names are different from lower case names. -19- Ratfiv May 14, 1981 Macros with arguments It is also possible to define macros with arguments which are inserted in the replacement text when the macro is expanded. For instance: define(write_buf,if ($3 > 0) write($1,(1x,<$3>a1)) ($2(ii),ii=1,$3)) defines a macro which when "called" by: write_buf(5, buf, n) expands to: if (n > 0) write(5, (1x,a1)) (buf(ii), ii=1,n) The $n's are placeholders for the nth argument, and are replaced by the argument when the macro is called. -20- Ratfiv May 14, 1981 System macros In addition to define, there are a number of other built-in macros: _macro(x,y) equivalent to define(x,y). _undef(x) undoes the most recent definition of x. If x had been defined twice, _undef(x) would pop x back to it's first definition. _incr(x) converts x to a number and adds one to it. _arith(x1,op1,x2[,op2,x3,...]) performs integer arithmetic (-,+,/,*) specified by op on x1, x2, etc. Evaluation is from left to right. _len(x) returns the length of string x. _substr(s,m,n) returns the substring of s which starts at location m and is n long. If n is not specified or is too large, returns the rest of the string starting at m. _index(s,c) returns the index in string s of character c. If _len(c) is > 1, the index of the first character in c is returned. If c doesn't occur in s, 0 is returned. _ifelse(a,b,c,d) evaluates a and b; if a equals b as a character string, c is evaluated and returned, else d is evaluated and returned. Note that d is not evaluated if a = b, and c is not evaluated if a != b. _include(file) equivalent to the include facility described above. -21- Ratfiv May 14, 1981 Evaluation of macro arguments (you might want to skip this section on first reading) There are two ways to pass an argument to a macro when it is being expanded; with and without pre-evaluation of the argument. For instance, the arguments to the "define" system macro are not evaluated before they are passed to it; Thus if X is defined as Y (by define(X,Y) for instance) then the result of define(X,Z) is to redefine X as Z, and leave Y alone. When you write a macro, you can specify whether or not each argument is evaluated before it is passed to your macro. Arguments specified as "$n" are evaluated before being passed to the macro (these are called "eval" arguments), while arguments specified as "%n" are not evaluated before being passed to the macro (these are called "noeval" arguments). For example, define(def2,define($1,%2)) defines a macro, def2, which is equivalent to the "define" system macro except that the first argument, $1, is evaluated before being defined as the second argument. Thus, if X was already defined as Y, then the result of define(X,Z) would be to redefine X as Z (as above), but the result of def2(X,Z) would be to define Y as Z, leaving X defined as Y, since X is expanded to Y before being passed to def2. A given argument (argument 1 for example) may not be both an eval and a noeval type, thus "$1" and "%1" could not both appear in a macro definition. -22- Ratfiv May 14, 1981 Passing literal strings through Ratfiv A string may be passed literally through Ratfiv without being expanded by enclosing it in accent characters (`). To specify a literal accent character, you must place two of them in a row within enclosing accent characters. Thus the string `define(X,Y)``` is passed to the output as define(X,Y)` and is not evaluated. Accented literal strings may appear within macro definitions as well, however occurrences of argument replacement strings ($n or %n) within accents are still replaced by their corresponding arguments. Brackets ([ and ]) also have a special meaning when they appear inside a macro definition only. At evaluation time, an outer pair of brackets are stripped off and the contained string is not evaluated. For example, a macro "isdef" which returns T if it's argument is defined, or F if it isn't, is defined as follows: define(isdef,_ifelse([%1],%1,F,T)) "isdef" compares the unevaluated form of argument 1 to the evaluated form; if they are equal, the argument is not defined and F is returned, otherwise it is defined and T is returned. Since _ifelse evaluates it's first two arguments, brackets are needed to keep the first one from being evaluated before being passed to _ifelse. -23- Ratfiv May 14, 1981 Example macros Here is an example of macros which implement "while" and "endwhile" statements: define(push,define(_stack,$1)_stack) Push pushes a new definition on top of the old definition of a macro named _stack, then returns the new value of _stack. define(pop,_stack _undef(_stack)) Pop returns the current value of _stack, then undefines it back to it's previous value. Now we can define while and endwhile: define(while, push(_incr(_stack)) if (.not.($1)) goto push(_incr(_stack))) define(endwhile, goto _arith(pop,-,1) _incr(pop) continue) With while and endwhile defined, the sequence: while (x < y) y = y/2 endwhile expands to: 1 if (.not. (x < y)) goto 2 y = y/2 goto 1 2 continue Of course the Ratfiv output would look different; the above output is the output of the macro processor before processing by Ratfiv. -24- Ratfiv May 14, 1981 CONDITIONAL CODE EXPANSION Code may be conditionally bypassed depending on whether or not a macro is defined. The statement _ifdef(x) tests if x is defined as a macro (symbolic constant). If so, then processing continues normally until the occurrence of an _elsedef macro. If x is not defined, then all code following the _ifdef is bypassed completely until the occurrence of an _elsedef or _enddef macro. For example: define(PDP11) .... _ifdef(PDP) write(5, (' PDP11 version 1.0 started')) _elsedef write(5, (' VAX version 1.0 started')) _enddef -25- Ratfiv May 14, 1981 USING RATFOR RATFOR expects one or more input files on the command line and one output file preceded by a ">". For example: RAT FILE1.RAT FILE2.RAT >FILE.FTN The above command would cause the files FILE1.RAT and FILE2.RAT to be compiled to FILE.FTN by Ratfiv. If the Ratfiv compiler detects an error in the Ratfiv code, an error message will be printed to the terminal and to the . FTN file at the point where the error occurred. After pre-proccessing by Ratfiv, the F4P compiler should be invoked, producing FILE.OBJ. Many Fortran errors cannot be detected by Ratfiv; when these occur, check the . LST file for the error message. It is usually not too hard to figure out where in the Ratfiv source the error is, once it has been found in the Fortran source. The Ratfiv compiler has one switch, the /SYMBOLS switch, which causes Ratfiv to look on your directory for a file named SYMBOLS; this file is opened and read as a prefix file to the other files on your command line. If SYMBOLS is not on your directory, Ratfiv looks on a system-dependent directory for the SYMBOLS file, which normally would have some standard "defines" on it, such as EOS, EOF, etc. -26- Ratfiv May 14, 1981 DIAGNOSTICS Unfortunately some error messages are not discussed here. can't open symbols file The special symbols file containing general purpose ratfiv definitions could not be opened. Possibly the user did not have access to the particular library the preprocessor expected to read. can't open include File to be included was not found. definition too long The number of characters in the name to be defined exceeded Ratfiv's internal array size (current maximum is 500 characters per definition) for clause too long the reinit clause of a for clause was was too long. This is a fatal error. format too long A format specification in a read, write, encode, or decode statement was too long (current maximum is 500 characters) illegal break Break did not occur inside a valid "while", "for", "do", or "repeat" loop, or inside a "switch" statement. illegal case or default a case or default statement occurred while not inside a switch statement illegal else Else clause probably did not follow an "if" clause illegal next "Next" did not occur inside a valid "for", "while", "do", or "repeat" loop illegal right brace A right brace was found without a matching left brace includes nested too deeply At the present, includes may only be nested 4 files deep, counting the current input file invalid for clause The "for" clause did not contain a valid init, condition, and/or increment section missing left paren A parenthesis was expected, probably in an "if" statement, but not found missing parenthesis in condition A right parenthesis was expected, probably in an "if" statement, but not found missing quote an expected quote was not found missing right paren A right parenthesis was expected in a Fortran (as opposed to Ratfiv) statement but not found non-alphanumeric name Definition keywords may contain only alphanumeric characters or the underscore (_) and dot (.) characters stack overflow in parser -27- Ratfiv May 14, 1981 Statements were nested at too deep a level. Current maximum is 100 statements nested at a time. This is a fatal error. token too long A token (word) in the sourcecode was too long to fit into one of Ratfiv's internal arrays. (Current maximum word size is 200 characters.) too many characters pushed back The source code has illegally specified a Ratfiv command, or has used a keyword or macro in an illegal manner, and the parser has attempted but failed to make sense out of it. This is a fatal error. too many definitions Ratfiv's internal arrays could not hold all the definitions. unbalanced parentheses Unbalanced parentheses detected in a Fortran (as opposed to Ratfiv) statement unexpected EOF An end-of-file was reached before all braces had been accounted for. This is usually caused by unmatched braces somewhere deep in the sourcecode. warning possible label conflict This message is printed when the user has labeled a statement with a label in the 2000 and up range if the label is divisible by 10. Ratfiv statements are assigned in this range and a user-defined one may conflict with a Ratfiv-generated one. "file": can't open Ratfiv could not open an input file specified by the user. -28- Ratfiv May 14, 1981 IMPLEMENTATION Ratfiv generates code by reading input files and translating any Ratfiv keywords into standard Fortran. Ratfiv keywords need not appear at the beginning of a line in order to be recognized. Ratfiv does not know any Fortran and thus does not handle any Fortran error detection. Errors in Ratfiv keyword syntax are generally noted by a message to the user's terminal and to the Fortran output file along with an indication of the source line number which caused the problem. Ratfiv was originally written in C, a high-level language, on the Unix operating system. Our version is written in Ratfiv itself, originally brought up by a bootstrap written in Fortran. This compiler was originally written by B. Kernighan and P. J. Plauger, with rewrites and enhancements by David Hanson and friends (U. of Arizona), Joe Sventek and Debbie Scherrer (Lawrence Berkely Laboratory), and William Wood (Institute For Cancer Research). For information, comments, or bug reports, please contact: William Wood The Institute For Cancer Research 7701 Burholme Ave. Phila., Pa. 19111 CONCLUSIONS Ratfiv demonstrates that with modest effort Fortran-based programmers can increase their productivity by using a language that provides them with the control structures and cosmetic features essential for structured programming design. Debugging and subsequent revision times are much faster than the equivalent efforts in Fortran, mainly because the code can be easily read. Thus it becomes easier to write code that is readable, reliable, and even esthetically pleasing, as well as being portable to other environments. -29- Ratfiv May 14, 1981 EXAMPLE The following is a sample Ratfiv tool designed to show some of the commonly-used Ratfiv commands. The routine reads through a list of files, counting the lines as it goes. The subroutines and functions which are used but not defined here are available in the Ratfiv library, however you will probably have no need for them. # this is an example of a routine written in Ratfiv # symbols such as EOF, ERR, MAXLINE, etc. are automatically # defined (i.e. a file containing them is included) by the # preprocessor if the "/SYMBOLS" switch is specified # at compile time. ## main calling routine call initr4 call count call endr4 end # count - counts lines in files subroutine count include comblk # this file contains a common block which # contains a variable "linect" character file(FILENAMESIZE), line(MAXLINE) integer i, getarg, int, open, getlin linect = 0 #loop through the list of files for (i=1; getarg(i, file, FILENAMESIZE) != EOF; i=i+1) { int = open (file, READ) # open (attach) the file if (int == ERR) { # file could not be located call remark ("can't open file") next } else # read lines from the file while (getlin(line, int) != EOF) linect = linect + 1 call close (int) # close (unattach) the file } return end -30- Ratfiv May 14, 1981 SEE ALSO 1) Kernighan, Brian W., "Ratfiv--a Preprocessor for a Rational Fortran". Bell Laboratories publication. Also available from the UC Berkeley Computer Science library. 2) Kernighan, Brian W. and P. J. Plauger, "Software Tools". Addison-Wesley Publishing Company, Reading, Mass., 1976. 3) The rat4 user and design documents; the rc user document. 4) The Unix command "rc" in the Unix Manual (RC(I)) -31-