#-h- ed 43879 asc 02-apr-82 17:01:24 v1.1 (sw-tools v1.1) Ed (4) 28-Oct-80 Ed (4) NAME Ed - text editor A Tutorial Introduction to the Software Tools TEXT EDITOR B. Kernighan Bell Laboratories and M.J. Gralia Johns Hopkins University - Applied Physics Laboratory INTRODUCTION EEEddd is a "text editor", that is, an interactive program for creating and modifying "text", using directions provided by a user at a terminal. The text is often a document like this one, or a program or perhaps data for a program. This introduction is meant to simplify learning eeeddd... The recommended way to learn eeeddd is to read this document, simultaneously using eeeddd to follow the examples, then to read the description in section I of the Software Tools manual, all the while experimenting with eeeddd... (Solicitation of advice from experienced users is also useful.) Do the exercises! They cover material not completely discussed in the actual text. An appendix summarizes the commands. DISCLAIMER This is an introduction and a tutorial. For this reason, no attempt is made to cover more than a part of the facilities that eeeddd offers (although this fraction includes the most useful and frequently used parts). Also, there is not enough space to explain basic Software Tools procedures. We will assume that you know how to log on and access the Software Tools, and that you have at least a vague understanding of what a file is. You must also know what character to type as the end-of-line on your particular terminal. It is almost always a "return". Throughout, we will refer to this character, whatever it is, as "newline". CASES And about case: it is traditional to use both upper and lower -1- Ed (4) 28-Oct-80 Ed (4) case characters when using the Software Tools, but it is not required. In describing eeeddd,,, we will follow that convention, but eeeddd will work with either. But a caution: eeeddd differentiates cases. If your files contain both and your terminal is in upper case, you can get into a "deadly embrace" situation in which you can see a character but can't delete it. The solution is simple - always use both upper and lower case with Software Tools. GETTING STARTED We'll assume that you have logged in. The easiest way to get eeeddd is to type ed (followed by a newline) You are now ready to go - eeeddd is waiting for you to tell it what to do. CREATING TEXT - the Append command ``a'' As our first problem, suppose we want to create some text starting from scratch. Perhaps we are typing the very first draft of a paper; clearly it will have to start somewhere, and undergo modifications later. This section will show how to get some text in, just to get started. Later we'll talk about how to change it. When eeeddd is first started, it is rather like working with a blank piece of paper - there is no text or information present. This must be supplied by the person using eeeddd;;; it is usually done by typing in the text, or by reading it into eeeddd from a file. We will start by typing in some text, and return shortly to how to read files. First a bit of terminology. In eeeddd jargon, the text being marked on is said to be "kept in a buffer." Think of the buffer as a work space, if you like, or simply as the information that you are going to be editing. In effect the buffer is like the piece of paper on which we will write things, then change some of them, and finally file the whole thing away for another day. The user tells eeeddd what to do to his text by typing instructions called "commands". Most commands consist of a single letter. Each command is typed on a separate line. (Sometimes the command is preceded by information about what line or lines of text are to be affected - we will discuss these shortly.) The first command is aaappppppeeennnddd,,, written as the letter a -2- Ed (4) 28-Oct-80 Ed (4) all by itself. It means """aaappppppeeennnddd (or add) text lines to the buffer, as I type them in." Appending is rather like writing fresh material on a piece of paper. So to enter lines of text into the buffer, we just type an "a" followed by a newline, followed by the lines of text we want, like this: a Now is the time for all good men to come to the aid of their party. . The only way to stop appending is to type a line that contains only a period. The "." is used to tell eeeddd that we have finished appending. (Even experienced users forget that terminating "." sometimes. If eeeddd seems to be ignoring you, type an extra line with just "." on it. You may then find you've added some garbage lines to your text, which you'll have to take out later.) After the append command has been done, the buffer will contain the three lines Now is the time for all good men to come to the aid of their party. The "a" and "." aren't there, because they are not text. To add more text to what we already have, just issue another "a" command, and continue typing. (Try it now - it won't always work right until we explain about line numbers.) ERROR MESSAGES - ``?'' If at any time you make an error in the commands you type to eeeddd,,, it will tell you by typing ? This is about as cryptic as it can be, but with practice, you can usually figure out how you goofed. WRITING TEXT OUT AS A FILE - the Write command ``w'' It's likely that we'll want to save our text for later use. To write out the contents of the buffer onto a file, we use the wwwrrriiittteee command w -3- Ed (4) 28-Oct-80 Ed (4) followed by the filename we want to write on. This will copy the buffer's contents onto the specified file (destroying any previous information on the file). To save the text on a file named "junk", for example, type w junk Leave a space between "w" and the file name. EEEddd will respond by printing the number of lines it wrote out. In our case, eeeddd would respond with 3 Writing a file just makes a copy of the text - the buffer's contents are not disturbed, so we can go on adding lines to it. This is an important point. EEEddd at all times works on a copy of a file, not the file itself. No change in the contents of a file takes place until you give a "w" command. (Writing out the text onto a file from time to time as it is being created is a good idea, since if the system crashes or if you make some horrible mistake, you will lose all the text in the buffer, but any text that was written onto a file is relatively safe.) LEAVING ED - the Quit command ``q'' To terminate a session with eeeddd,,, save the text you're working on by writing it onto a file using the "w" command, and then type the command q which stands for qqquuuiiittt... At this point your buffer vanishes, with all its text, which is why you want to write it out before quitting. EXERCISE 1: Enter eeeddd and create some text using a ...text... . Write it out using "w". Then leave eeeddd with the "q" command, and print the file, to see that everything worked. (To print a file, say cat filename Also try crt filename -4- Ed (4) 28-Oct-80 Ed (4) Here, you need to enter a newline (to see the next page) or "q" (to quit displaying the text). READING TEXT FROM A FILE - the Edit command ``e'' A common way to get text into the buffer is to read it from a file in the file system. This is what you do to edit text that you saved with the "w" command in a previous session. The eeedddiiittt command "e" fetches the entire contents of a file into the buffer. So if we had saved the three lines "Now is the time", etc., with a "w" command in an earlier session, the eeeddd command e junk would fetch the entire contents of the file "junk" into the buffer, and respond 3 which is the number of lines in "junk". If anything was already in the buffer, it is deleted first. If we use the "e" command to read a file into the buffer, then we need not use a file name after a subsequent "w" command; eeeddd remembers the last file name used in an "e" command, and "w" will write on this file. Thus a common way to operate is ed e file [editing session] w q You can find out at any time what file named eeeddd is remembering by typing the fffiiillleee command "f". In our case, if we typed f eeeddd would reply junk READING TEXT FROM A FILE - the Read command ``r'' Sometimes we want to read a file into the buffer without destroying anything that is already there. This is done by the rrreeeaaaddd command "r". The command r junk will read the file "junk" into the buffer; it adds it to the buffer (after the current line). So if we do a read after an -5- Ed (4) 28-Oct-80 Ed (4) edit: e junk r junk the buffer will contain tttwwwooo copies of the text (six lines). Now is the time for all good men to come to the aid of their party. Now is the time for all good men to come to the aid of their party. Like the "w" and "e" commands, "r" prints the number of newlines read in, after the reading operation is complete. Generally speaking, "r" is much less used than "e". EXERCISE 2: Experiment with the "e" command - try reading and printing various files. You may get an error "?.", typically because you spelled the file name wrong. Try alternately reading and appending to see that they work similarly. Verify that ed filename is exactly equivalent to ed e filename What does f filename do? PRINTING THE CONTENTS OF THE BUFFER - the Print command ``p'' To ppprrriiinnnttt or list the contents of the buffer (or parts of it) on the terminal, we use the print command p The way this is done is as follows. We specify the lines where we want printing to begin and where we want it to end, separated by a comma, and followed by the letter "p". Thus to print the first two lines of the buffer, for example, (that is, lines 1 through 2) we say -6- Ed (4) 28-Oct-80 Ed (4) 1,2p (starting line=1, ending line=2) EEEddd will respond with Now is the time for all good men Suppose we want to print aaallllll the lines in the buffer. We could use "1,3p" as above if we knew there were exactly 3 lines in the buffer. But in general, we don't know how many there are so what do we use for the ending line number? EEEddd provides a shorthand symbol for "line number of last line in buffer" - the dollar sign "$". Use it this way: 1,$p This will print aaallllll the lines in the buffer (line 1 to the last line.) To print the lllaaasssttt line of the buffer, we could use $,$p but eeeddd lets us abbreviate this to $p We can print any single line by typing the line number followed by a "p". Thus 1p produces the response Now is the time which is the first line of the buffer. In fact, eeeddd lets us abbreviate even further: we can print any single line by typing jjjuuusssttt the line number - no need to type the letter "p". So if we say $ eeeddd will print the last line of the buffer for us. We can also use "$" in combinations like $-1,$p -7- Ed (4) 28-Oct-80 Ed (4) which prints the last two lines of the buffer. This helps when we want to see how far we got in typing. EXERCISE 3: As before, create some text using the append command and experiment with the "p" command. You will find, for example, that you can't print line 0 or a line beyond the end of the buffer, and that attempts to print a buffer in reverse order by saying 3,1p don't work. THE CURRENT LINE - 'Dot' or '.' Suppose our buffer still contains the six lines as above, that we have just typed 1,3p and eeeddd has printed the three lines for us. Try typing just p (no line numbers). This will print to come to the aid of their party. which is the third line of the buffer. In fact it is the last (most recent) line that we have done anything with. (We just printed it!) We can repeat this "p" command without line numbers, and it will continue to print line 3. The reason is that eeeddd maintains a record of the last line that we did anything to (in this case, line 3, which we just printed) so that it can be used instead of an explicit line number. This most recent line is referred to by the shorthand symbol . (pronounced "dot"). Dot is a line number in the same way that "$" is; it means exactly "the current line", or loosely, "the line we most recently did something to." We can use it in several ways - one possibility is to say .,$p This will print all the lines from (including) the current line to the end of the buffer. In our case these are lines 3 through 6. -8- Ed (4) 28-Oct-80 Ed (4) Some commands change the value of dot, while others do not. The print command sets dot to the number of the last line printed; by our last command, we would have "." = "$" = 6. Dot is most useful when used in combinations like this one: .+1 (or equivalently, .+1p) This means "print the next line" and gives us a handy way to step slowly through a buffer. We can also say .-1 (or .-1p) which means "print the line bbbeeefffooorrreee the current line." This enables us to go backwards if we wish. Another useful one is something like .-3,.-1p which prints the previous three lines. Don't forget that all of these change the value of dot. You can find out what dot is at any time by typing .= EEEddd will respond by printing the value of dot. Let's summarize some things about the "p" command and dot. Essentially "p" can be preceded by 0, 1, or 2 line numbers. If there is no line number given, it prints the "current line", the line that dot refers to. If there is one line number given (with or without the letter "p"), it prints that line (and dot is set there); and if there are two line numbers, it prints all the lines in that range (and sets dot to the last line printed.) If two line numbers are specified the first can't be bigger than the second (see Exercise 3.) Typing a single newline will cause printing of the next line - it's equivalent to ".+1p". Try it. DELETING LINES: the ``d'' command Suppose we want to get rid of the three extra lines in the buffer. This is done by the dddeeellleeettteee command d Except that "d" deletes lines instead of printing them, its action is similar to that of "p". The lines to be deleted are specified for "d" exactly as they are for "p": -9- Ed (4) 28-Oct-80 Ed (4) starting-line, ending-line d Thus the command 4,$d deletes lines 4 through the end. There are now three lines left, as we can check by using 1,$p And notice that "$" now is line 3! Dot is set to the next line after the last line deleted, unless the last line deleted is the last line in the buffer. In that case, dot is set to "$". EXERCISE 4: Experiment with "a", "e", "r", "w", "p", and "d" until you are sure that you know what they do, and until you understand how dot, "$", and line numbers are used. If you are adventurous, try using line numbers with "a", "r", and "w" as well. You will find that "a" will append lines aaafffttteeerrr the line number that you specify (rather than after dot); that "r" reads a file in aaafffttteeerrr the line number you specify (not necessarily at the end of the buffer); and that "w" will write out exactly the lines you specify, not necessarily the whole buffer. These variations are sometimes handy. For instance you can insert a file at the beginning of a buffer by saying 0r filename and you can enter lines at the beginning of the buffer by saying 0a ...text... . Notice that ".w" is vvveeerrryyy different from . w MODIFYING TEXT: the Substitute command ``s'' We are now ready to try one of the most important of all commands - the substitute command s This is the command that is used to change individual words or -10- Ed (4) 28-Oct-80 Ed (4) letters within a line or group of lines. It is what we use, for example, for correcting spelling mistakes and typing errors. Suppose that by a typing error, line 1 says Now is th time - the "e" has been left off "the". We can use "s" to fix this up as follows: 1s/th/the/ This says: "in line 1, substitute for the characters `th' the characters `the'. To verify that it works ( eeeddd will not print the result automatically) we say p and get Now is the time which is what we wanted. Notice that dot must have been set to the line where the substitution took place, since the "p" command printed that line. Dot is always set this way with the "s" command. The general way to use the substitute command is starting-line, ending-line s/change this/to this/ Whatever string of characters is between the first pair of slashes is replaced by whatever is between the second pair, in aaallllll the lines between starting line and ending line. Only the first occurrence on each line is changed, however. If you want to change eeevvveeerrryyy occurrence, see Exercise 5. The rules for line numbers are the same as those for "p", except that dot is set to the last line changed. (But there is a trap for the unwary: if no substitution took place, dot is nnnooottt changed. This causes an error "?" as a warning.) Thus we can say 1,$s/speling/spelling/ and correct the first spelling mistake on each line in the text. (This is useful for people who are consistent misspellers!) If no line numbers are given, the "s" command assumes we mean -11- Ed (4) 28-Oct-80 Ed (4) "make the substitution on line dot", so it changes things only on the current line. This leads to the very common sequence s/something/something else/p which makes some correction on the current line, and then prints it, to make sure it worked out right. If it didn't, we can try again. (Notice that we put a print command on the same line as the substitute. With few exceptions, "p" can follow any command; no other multi-command lines are legal.) It's also legal to say s/something// which means "change 'something' to nnnooottthhhiiinnnggg,,,""" i.e., remove it. This is useful for deleting extra words in a line or removing extra letters from words. For instance, if we had Nowxx is the time we can say s/xx//p to get Now is the time Notice that "//" here means "no characters", not a blank. There iiisss a difference! (See below for another meaning of "//".) EXERCISE 5: Experiment with the substitute command. See what happens if you substitute for some word on a line with several occurrences of that word. For example, do this: a the other side of the coin . s/the/on the/p You will get on the other side of the coin A substitute command changes only the first occurrence of the first string. You can change all occurrences by adding a "g" (for "global") to the "s" command, like this: -12- Ed (4) 28-Oct-80 Ed (4) s/.../.../gp Try other characters instead of slashes to delimit the two sets of characters in the "s" command - anything should work except blanks or tabs. (If you get funny results using any of the characters % ? $ [ * read the section on "Special Characters".) CONTEXT SEARCHING - ``/.../'' With the substitute command mastered, we can move on to another highly important idea of eeeddd - context searching. Suppose we have our original three line text in the buffer: Now is the time for all good men to come to the aid of their party. Suppose we want to find the line that contains "their" so we can change it to "the". Now with only three lines in the buffer, it's pretty easy to keep track of what line the word "their" is on. But if the buffer contained several hundred lines, and we'd been making changes, deleting and rearranging lines, and so on, we would no longer really know what this line number would be. Context searching is simply a method of specifying the desired line, regardless of what its number is, by specifying some context on it. The way we say "search for a line that contains this particular string of characters" is to type /string of characters we want to find/ For example, the eeeddd line /their/ is a context search which is sufficient to find the desired line - it will locate the next occurrence of the characters between slashes ("their"). It also sets dot to that line and prints the line for verification: to come to the aid of their party. "Next occurrence" means that eeeddd starts looking for the string at line ".+1", searches to the end of the buffer, then continues at -13- Ed (4) 28-Oct-80 Ed (4) line 1 and searches to line dot. (That is, the search "wraps around" from "$" to 1.) It scans all the lines in the buffer until it either finds the desired line or gets back to dot again. If the given string of characters can't be found in any line, eeeddd types the error message ? Otherwise it prints the line it found. We can do both the search for the desired line aaannnddd a substitution all at once, like this: /their/s/their/the/p which will yield to come to the aid of the party. There were three parts to that last command: context search for the desired line, make the substitution, print the line. The expression "/their/" is a context search expression. In their simplest form, all context search expressions are like this - a string of characters surrounded by slashes. Context searches are interchangeable with line numbers, so they can be used by themselves to find and print a desired line, or as line numbers for some other command, like "s". We used them both ways in the examples above. Suppose the buffer contains the three familiar lines Now is the time for all good men to come to the aid of their party. Then the eeeddd line numbers /Now/+1 /good/ /party/-1 are all context search expressions, and they all refer to the same line (line 2). To make a change in line 2, we could say /Now/+1s/good/bad/ or /good/s/good/bad/ -14- Ed (4) 28-Oct-80 Ed (4) or /party/-1s/good/bad/ The choice is dictated only by convenience. We could print all three lines by, for instance /Now/,/party/p or /Now/,/Now/+2p or by any number of similar combinations. The first one of these might be better if we don't know how many lines are involved. (Of course, if there were only three lines in the buffer, we could use 1,$p but not if there were several hundred.) The basic rule is: a context search expression is ttthhheee same as a line number, so it can be used wherever a line number is needed. EXERCISE 6: Experiment with context searching. Try a body of text with several occurrences of the same string of characters, and scan through it using the same context search. Try using context searches as line numbers for the substitute, print and delete commands. (They can also be used with "r", "w", and "a".) Try context searching using "\text\" instead of "/text/". This scans lines in the buffer in reverse order rather than normal. This is sometimes useful if you go too far while looking for some string of characters - it's an easy way to back up. (If you get funny results with any of the characters % ? $ [ * read the section on "Special Characters".) EEEddd provides a shorthand for repeating a context search for the same string. For example, the eeeddd line number /string/ -15- Ed (4) 28-Oct-80 Ed (4) will find the next occurrence of "string". It often happens that this is not the desired line, so the search must be repeated. This can be done by typing merely // This shorthand stands for "the most recently used context search expression." It can also be used as the first string of the substitute command, as in /string1/s//string2/ which will find the next occurrence of "string1" and replace it by "string2". This can save a lot of typing. Similarly \\ means "scan backwards for the same expression." CHANGE and INSERT - ``c'' and ``i'' This section discusses the ccchhhaaannngggeee command c which is used to change or replace a group of one or more lines, and the iiinnnssseeerrrttt command i which is used for inserting a group of one or more lines. "Change", written as c is used to replace a number of lines with different lines, which are typed in at the terminal. For example, to change lines ".+1" through "$" to something else, type .+1,$c ...type the lines of text you want here... . The lines you type between the "c" command and the "." will take the place of the original lines between start line and end line. This is most useful in replacing a line or several lines which have errors in them. If only one line is specified in the "c" command, then just that line is replaced. (You can type in as many replacement lines as -16- Ed (4) 28-Oct-80 Ed (4) you like.) Notice the use of "." to end the input - this works just like the "." in the append command and must appear by itself on a new line. If no line number is given, line dot is replaced. The value of dot is set to the last line you typed in. "Insert" is similar to append - for instance /string/i ...type the lines to be inserted here... . will insert the given text bbbeeefffooorrreee the next line that contains "string". The text between "i" and "." is iiinnnssseeerrrttteeeddd before the specified line. If no line number is specified dot is used. Dot is set to the last line inserted. EXERCISE 7: "Change" is rather like a combination of delete followed by insert. Experiment to verify that start, end d i ...text... . is almost the same as start, end c ...text... . These are not ppprrreeeccciiissseeelllyyy the same if line "$" gets deleted. Check this out. What is dot? Experiment with "a" and "i", to see that they are similar, but not the same. You will observe that line-number a ...text.. . appends aaafffttteeerrr the given line, while line-number i ...text... . inserts bbbeeefffooorrreee it. Observe that if no line number is given, "i" inserts before line dot, while "a" appends after line dot. -17- Ed (4) 28-Oct-80 Ed (4) BROWSING: the ``b'' command Many times you want to look at several lines of a large file while you're using a video terminal. If you said 1,$p the whole buffer would flash on the screen, usually too fast to read. A better way is the browse command "b". It prints just enough lines (23) to fill the CRT screen. Browse has three major forms which control what lines are displayed. "b" or "b+" prints the current line and the screen after it. "b." prints the screen centered on the current line and including it. "b-" prints the screenful before the current line. MOVING TEXT AROUND: the ``m'' command The move command "m" is used for cutting and pasting - it lets you move a group of lines from one place to another on the buffer. Suppose we want to put the first three lines of the buffer at the end instead. We could do it by saying: 1,3w temp $r temp 1,3d (Do you see why?) but we can do it a lot easier with the "m" command: 1,3m$ The general case is start-line, end-line m after-this-line Notice that there is a third line to be specified - the place where the moved stuff gets put. Of course the lines to be moved can be specified by context searches; if we had First paragraph ... end of first paragraph. Second paragraph ... end of second paragraph. we could reverse the two paragraphs like this: /Second/,/second/m/First/-1 Notice the "-1" - the moved text goes aaafffttteeerrr the line mentioned. -18- Ed (4) 28-Oct-80 Ed (4) Dot gets set to the last line moved. THE GLOBAL COMMAND ``g'' The ggglllooobbbaaalll command "g" is used to execute an eeeddd command on all those lines in the buffer that match some specified string. For example g/peling/p prints all lines that contain "peling". More usefully, g/peling/s//pelling/gp makes the substitution everywhere on the line, then prints each corrected line. Compare this to 1,$s/peling/pelling/gp which only prints the last line substituted. Another subtle difference is that the "g" command does not give a "?" if "peling" is not found where the "s" command will. SPECIAL CHARACTERS You may have noticed that things just don't work right when you used some characters like "?", "*", "$", and others in context searches and the substitute command. The reason is rather complex, although the cure is simple. Basically, eeeddd treats these characters as special, with special meanings. For instance, iiinnn a context search or the first string of the substitute command only, /x?y/ means "a line with an x, aaannnyyy character, and a y," nnnooottt just "a line with an x, a question mark, and a y." A complete list of the special characters that can cause trouble is the following: % . $ [ ] * @ # ! + { } WWWaaarrrnnniiinnnggg::: The character @ is special to eeeddd... For safety's sake, avoid it where possible. If you have to use one of the special characters in a substitute command, you can turn off its magic meaning temporarily by preceding it with the "at" sign. Thus s/@@?@*/at quest star/ will change "@?*" into "at quest star". Here is a hurried synopsis of the other special characters. First, the percent "%" signifies the beginning of a line. Thus -19- Ed (4) 28-Oct-80 Ed (4) /%string/ finds "string" only if it is at the beginning of a line: it will find string but not the string... The dollar-sign "$" is just the opposite of the percent sign; it means the end of a line: /string$/ will only find an occurrence of "string" that is at the end of some line. This implies, of course, that /%string$/ will find only a line that contains just "string", and /%?$/ finds a line containing exactly one character. The character "?", as we mentioned above, matches anything; /x?y/ matches any of xay x1y x+y x-y x y x.y This is useful in conjunction with "*", which is a repetition character; "a*" is shorthand for "any number of a's", so "?*" matches any number of anythings. This is used like this: s/?*/stuff/ which changes an entire line, or s/?*,// -20- Ed (4) 28-Oct-80 Ed (4) which deletes all characters in the line up to and including the last comma. (Since "?*" finds the longest possible match, this goes up to the last comma.) "[" is used with "]" to form "character classes"; for example, /[1234567890]/ matches any single digit - any one of the characters inside the braces will cause a match. Finally, the "&" is another shorthand character - it is used only on the right-hand part of a substitute command where it means "whatever was matched on the left-hand side". It is used to save typing. Suppose the current line contained Now is the time and we wanted to put parentheses around it. We could just retype the line, but this is tedious. Or we could say s/%/(/ s/$/)/ using our knowledge of "%" and "$". But the easiest way uses the "&": s/?*/(&)/ This says "match the whole line, and replace it by itself surrounded by parens." The "&" can be used several times in a line; consider using s/?*/&. &!!/ to produce Now is the time. Now is the time!! We don't have to match the whole line, of course: if the buffer contains the end of the world we could type /world/s//& is at hand/ to produce -21- Ed (4) 28-Oct-80 Ed (4) the end of the world is at hand Observe this expression carefully, for it illustrates how to take advantage of eeeddd to save typing. The string "/world/" found the desired line; the shorthand "//" found the same word in the line; and the "&" saved us from typing it again. The "&" is a special character only within the replacement text of a substitute command, and has no special meaning elsewhere. We can turn off the special meaning of "&" by preceding it with a "@": s/ampersand/@&/ will convert the word "ampersand" into the literal symbol "&" in the current line. ACKNOWLEDGEMENT The majority of this document has been taken, with the author's permission, from "A Tutorial Introduction to the UNIX Text Editor" by B. W. Kernighan. It has been changed only to reflect the differences between this editor and the UNIX version. SUMMARY OF COMMANDS AND LINE NUMBERS The general form of eeeddd commands is the command name, perhaps preceded by one or two line numbers, and, in the case of eee,,, rrr and www,,, followed by a file name. Only one command is allowed per line, but a ppp command may follow any other command (except for eee,,, rrr,,, www and qqq)))... aaa (append) Add lines to the buffer (at line dot, unless a different line is specified). Appending continues until "." is typed on a new line. Dot is set to the last line appended. bbb (browse) Display 23 lines of text, beginning at the current line. The current line will be centered if you use b. ("b dot"). Using b- will cause the previous 23 lines to be printed. ccc (change) Change the specified lines to the new text which follows. The new lines are terminated by a ".". If no lines are specified, replace line dot. Dot is set to last line changed. ddd (delete) Delete the lines specified. If none are specified, delete line dot. Dot is set to the first undeleted line, unless "$" is deleted, in which case dot is set to "$". eee (edit) Edit new file. Any previous contents of the buffer are -22- Ed (4) 28-Oct-80 Ed (4) thrown away, so issue a www beforehand if you want to save them. fff (file) Print remembered filename. If a name follows fff the remembered name will be set to it. ggg (global) g/---/command will execute the command on those lines that contain "---", which can be any context search expression. iii (insert) Insert lines before specified line (or dot) until a "." is typed on a new line. Dot is set to last line inserted. mmm (move) Move lines specified to after the line named after mmm... Dot is set to the last line moved. ppp (print) Print specified lines. If none specified, print line dot. A single line number is equivalent to "line-number p". A single newline prints ".+1", the next line. qqq (quit) Exit from ed. Wipes out all text in buffer!! rrr (read) Read a file into buffer (at end unless specified elsewhere.) Dot set to last line read. sss (substitute) s/string1/string2/ will substitute the characters of `string2' for `string1' in specified lines. If no line is specified, make substitution in line dot. Dot is set to last line in which a substitution took place, which means that if no substitution took place, dot is not changed. sss changes only the first occurrence of string1 on a line; to change all of them, type a "g" after the final slash. www (write) Write out buffer onto a file. Dot is not changed. ...=== (dot value) Print value of dot. ("=" by itself prints the value of "$".) ///---------/// Context search. Search for next line which contains this string of characters. Print it. Dot is set to line where string found. Search starts at ".+1", wraps around from "$" to 1, and continues to dot, if necessary. \---\ Context search in reverse direction. Start search at ".-1", scan to 1, wrap around to "$". -23- #-h- msg 32822 asc 02-apr-82 17:01:40 v1.1 (sw-tools v1.1) Msg (4) 17-Mar-82 Msg (4) NAME Msg - message editor MSG Primer Joseph Sventek Computer Science & Mathematics Department Lawrence Berkeley Laboratory Berkeley, CA 94720 msg is basically a message editor. It may be used to read, write and modify files which have the message file format. There are two default files of this type in your home directory: mymail - messages sent to you by others are deposited here. mbox - the messages in mymail are saved here, by default. msg gives the user the power to create and manage other files for conveniently sorting and categorizing messages received. All commands to msg consist of a single character. msg then types out the rest of the command name and, if necessary, prompts for additional information needed to complete the request. msg is entered via the following command line to the command interpreter on your machine: msg [-p[n]] [filename] If no filename is specified, msg defaults to the file mymail in the home directory. msg first prints out a banner identifying itself; then it reads the file specified (or mymail). If there are any messages in the file, the headers for that file are automatically displayed. Completing this, msg then prompts the user for a command character with the string <- The following symbols are used in the command descriptions below: the character generated by hitting the RETURN or CR key the character generated by hitting the space bar the character generated by hitting the ESC key ^C the character generated by holding down the CTRL key and hitting the key `C' -1- Msg (4) 17-Mar-82 Msg (4) There are only five types of input expected by msg: 1. an msg command character 2. a message sequence specification 3. a filename 4. a confirmation character () 5. an output continuation character () Whenever msg prompts for input, typing causes the current command to be aborted, and the user is returned to command level. The following conventions are used in the command descriptions below: This stands for any valid file specification on your system. If the tools on your system support pathname to local-name translation, any valid pathname may also be used. This input is prompted for by the string "(message sequence)". Valid responses to this prompt are: 1. Any single message number, as listed in the headers. 2. Any two message numbers separated by ":" or "-". This specification describes a range of message numbers (e.g. 2-5 means messages 2 and 3 and 4 and 5 in that order). If the first number is larger than the second, then the range is traversed in decreasing order. 3. Any sequence of the previous two types separated by commas. For example, 1,3,5-7,10 means messages 1 and 3 and 5 through 7 and 10. of the types described above are terminated by . 4. Special types of message sequences, which are determined by the first character typed in response to the (message sequence) prompt. character typed action --------- --------------------------------------------- The relevant process is performed on the current message a The string "all messages" is displayed and the relevant action is taken on all messages d The string "deleted messages" is displayed and the appropriate action is taken on those messages -2- Msg (4) 17-Mar-82 Msg (4) currently marked as deleted f The string "from string: " is displayed, prompting the user to supply a string to be used in a pattern match with the from fields of the headers. The characteristics of these strings are described below. s The string "subject string: " is displayed, prompting the user to supply a string to be used in a pattern match with the subject fields of the headers. See below for more information on the characteristics of these strings. u The string "undeleted messages" is displayed and the relevant action is taken on those messages currently not deleted The strings required for the from and subject search are the same regular expressions used by the editor, find and change. Those manual entries may be consulted for more information. The string must be terminated by a . If a bare is typed, no searching is done and the command is terminated. Whenever msg prompts for a string which must be terminated by a (message sequences, from or subject search strings or a filename), character editing may be performed as follows: 1. DEL(RUB) or BACKSPACE(^H) will delete the last character. 2. ^U will delete the entire string typed so far. 3. ^R will cause the current string to be retyped on the next line of the terminal. This is handy for users with hardcopy terminals, as character deletions and replacements will result in overprinted paper, and ^R can be used to see exactly what has been typed. Since msg is a tool, both its standard input and standard output may be redirected to disk files. In particular, that is how the writeups for each individual command below was obtained, through the use of the online help facility, as well as the example dialogue described below. It should be noted that if the standard output is redirected to a file but standard input is not, none of the prompts or output of the commands typed will be seen by the user. When operating in interactive mode, all output to the user's terminal is paged - i.e. after a screenful is displayed, the user is prompted to see if more output is desired. Positive responses to this prompt ("[type SPACE to continue]") is a . Any other response results in the following actions: -3- Msg (4) 17-Mar-82 Msg (4) 1. If msg was typing a large message, it will stop displaying the current message. If there are more messages to be typed in the current command, msg will then ask if the next message is desired. A negative response to this prompt ("[type SPACE for next message]") results in the discontinuation of the current command and a return to command level ("<-"). 2. If the ? or h[eaders] command generates more than a screenful of lines, the user will be prompted. A negative response will result in the discontinuation of the current command. The default page size is 22 lines. This may be modified by using the `-p[n]' switch in the arguments to msg. If n is specified, then the page size is reset to that value. Simply typing -p with no trailing number turns paging off. !!!BEWARE!!! If you turn off paging altogether, and give a command which generates a lot of output (i.e. t[ype] a[ll messages]), there is no way to stop msg until it is done. A better approach is to set n very large (say 1000 or so), so that header listings and entire messages will not be paged, but msg will stop after each message when typing multiple message sequences. -4- Msg (4) 17-Mar-82 Msg (4) The banner that msg greets the user with is: Software Tools MSG System type ? for help type # for news Typing ? to the prompt results in the following information: <- ? MSG Help The following commands are recognized by msg: a[nswer] message b[ackup] to previous message and type it c[urrent] message number and file d[elete] message(s) e[xit] and update old file f[orward] message g[o to] message specified and print it h[eaders] print headers of message(s) i[nformation] on command displayed j[ump] into shell - return by typing logout to shell k[ey] encryption-key *** UNIMPLEMENTED *** l[ist] message(s) in print format on file m[ove] message(s) to another mail file and mark them deleted n[ext] message is typed o[verwrite] current file and re-read p[ut] copies of message(s) in another mail file q[uit] leave MSG without updating current file r[ead] in another mail file s[ndmsg] invoke SNDMSG to send a message (and return to MSG) t[ype] message(s) on standard output u[ndelete] message(s) w[rite] current file, sorted by date field *** UNIMPLEMENTED *** #[news] print MSG news ?[help] print this list %[intro] type an introduction to MSG (for first-time users) For more information, use the i[nformation] command. Listed are the valid commands to msg. Those which are defined but unimplemented are noted as such. Expanded information for each command may be had through the use of the i[nformation] command. -5- Msg (4) 17-Mar-82 Msg (4) Typing # results in the following display: <- # MSG News No news is good news! As modifications are made to the system, entries will be placed in msg's database such that the news command will inform the user of recent changes. Typing % results in the following display: <- % Introduction to MSG If you are a new MSG user, you probably need ONLY the following commands: t type message(s) on terminal; common options are `a' for all messages or `' (where is an integer) for message . d delete a message after reading it; common options as above. e exit MSG and move messages which have not been deleted to your mail file (`mbox' in your home directory). q quit MSG without updating your mail file; if there are any messages left, you will be notified when you next login (or the next time you run `postmn'). NOTE: These command characters should NOT be followed by a RETURN. When you type one of them, MSG will immediately prompt you for more input. To print a copy of the MSG primer on the lineprinter, type sh -c "msgprim | lpr" This synopsis is meant for first time users, to help them in their efforts to use msg. -6- Msg (4) 17-Mar-82 Msg (4) The following is a list of the online documentation available for each of the supported commands. The general format of the output of the i[nformation] command is: 1. A line which shows how the terminal will look when the command is used. 2. A full description of what the command does, what inputs it expects, and references to other commands with similar functionality. <- information - type command character: a Answer message number: This command causes sndmsg to be spawned as a sub-process, with the To field being the sender of the indicated message, and the subject field consisting of the string "Re: ", where is replaced by the subject of the indicated message. In addition, the message header of the answering message will contain the line "In-reply-to: Your message of " where is replaced by the date of the indicated message. The user will be prompted for Cc addresses and the message to be sent. <- information - type command character: b Backing up - previous message is: This command displays the previous message (i.e. current message - 1). It is the inverse of the Next command. The current message number is decremented. If the current message number is 1 when Backup is invoked, an error message is displayed. <- information - type command character: c Current message is nn of mm messages in file This command displays: 1. the number of the current message 2. the total number of messages in the message file 3. the file name of the currently active message file -7- Msg (4) 17-Mar-82 Msg (4) <- information - type command character: d Delete (message sequence) This command marks the messages specified in MSG-SEQUENCE as deleted, as indicated by an asterisk following the message number in the headers of the affected messages. The actual messages in the message file are not affected unless an Overwrite, Exit or Write command is executed before leaving MSG. <- information - type command character: e Exit and update old file [type SPACE to confirm] This command overwrites the current message file, but permits the user to leave MSG rather than re-reading the message file as Overwrite does. <- information - type command character: f Forward message number: This command causes sndmsg to be spawned as a sub-process, with the message consisting of the header and message body of the indicated message. The user will be prompted for To, Cc and Subject fields upon entry into sndmsg. <- information - type command character: g Go to message number: This command permits explicit changing of the current message number. If is not in the range of acceptable values (i.e. it is less than 1 or greater than the number of messages in the file), an error message is displayed and the current message number will remain unchanged. Legal inputs for are: 1. a number in the range 1 <= n <= NMSGS 2. f for the first message (message number 1) 3. l for the last message 4. for the current message number (a noop) <- information - type command character: h Headers (message sequence) This command displays the headers for the messages defined by the specified message sequence. Headers corresponding to deleted -8- Msg (4) 17-Mar-82 Msg (4) messages have an asterisk printed after the message number for that particular message. The format for the headers is: The headers are displayed a screenful at a time. After a screenful has been output, if there are more headers remaining to be displayed, the user is prompted with the string "[type SPACE to continue]". A response of SPACE will cause the next screenful to be displayed. Any other response terminates the listing of the headers. <- information - type command character: i Information - type command character: This command displays full help information for those commands listed by the ? command. <- information - type command character: j Jump into shell [type SPACE to confirm] This command drops the user into the Software Tools shell. All normal commands may be executed while in the shell. Control returns to MSG by typing logout to the shell. <- information - type command character: l List (message sequence) on file name: This command lists all the specified messages on the file specified (overwriting the current contents of . A preface page, consisting of a FORMFEED character and the headers of the selected messages is output first, followed by each message preceded by a FORMFEED character. The file output by List can be disposed to a printer using the lpr shell command, resulting in a message on each page of the output. <- information - type command character: m Move (message sequence) into file name: This command is a convenient combination of the Put and Delete commands. It will first put the selected messages into the file specified and then -9- Msg (4) 17-Mar-82 Msg (4) mark the messages as deleted in the header information. <- information - type command character: n Next message is: This command displays the next message (current message number + 1) and increments the current message number. If the current message is already the last one, an error message is displayed and the current message number remains unchanged. <- information - type command character: o Overwrite old file [type SPACE to confirm] This command will overwrite the current file (specified by ), eliminating any deleted messages. It then re-reads the file, re-numbering the messages. <- information - type command character: p Put (message sequence) into file name: This command will put the messages specified by into the file specified by . If the file does not exist, it will create the file and write the messages into it. If the file already exists, the messages are appended to those already in the file. <- information - type command character: q Quit [type SPACE to confirm] This command allows the user to leave MSG without modifying the current message file. <- information - type command character: r Read file name: This command allows the user to use MSG on files created by previous Move or Put invocations. The current message file is closed with no modification, and the file specified is read, displaying the headers before prompting for the next command. -10- Msg (4) 17-Mar-82 Msg (4) <- information - type command character: s Sndmsg [type SPACE to confirm] This command causes SNDMSG to be spawned as a sub-process, allowing the user to send a message without leaving MSG; when SNDMSG exits, MSG regains control with no changed to files, etc. <- information - type command character: t Type (message sequence) This command displays the messages specified. If more than one message is specified, the user is prompted with "[type SPACE for next message]" after each message. In addition, if a particular message is larger than one screenful, the user is prompted after each screenful. A negative response to this latter prompt results in the termination of the display of the particular message, while a negative response to the former results in termination of the Type command. <- information - type command character: u Undelete (message sequence) This command undoes the actions of the Delete command. -11- Msg (4) 17-Mar-82 Msg (4) The following is a sample dialogue using many of the msg commands. The characters typed by the user are underlined, with the token standing for typing . % _m_s_g_t_e_s_t _>_t_e_s_t_._m_s_g_; _m_s_g _t_e_s_t_._m_s_g_<_C_R_> Software Tools MSG System type ? for help type # for news 1 114 25-MAR-80 Tools another test of mail 2 323 27-MAR-80 Tools still more tests 3 289 27-MAR-80 Tools testing 4 114 01-APR-80 Tools test of the mail system 5 330 03-APR-80 System A TEST OF THE MAIL SYSTEM 6 116 09-APR-80 Tools a test of the mail system 7 308 09-APR-80 Tools more testing 8 99 09-APR-80 Tools another test 9 145 09-APR-80 Tools why doesn't mail work? 10 129 10-APR-80 Tools more testing 11 298 10-APR-80 Tools more testing 12 326 10-APR-80 Tools Yet another test 13 129 10-APR-80 Sventek sventek's test 14 314 10-APR-80 Tools testing again <- _headers (message sequence) _1_,_2_,_4_-_6_<_C_R_> 1 114 25-MAR-80 Tools another test of mail 2 323 27-MAR-80 Tools still more tests 4 114 01-APR-80 Tools test of the mail system 5 330 03-APR-80 System A TEST OF THE MAIL SYSTEM 6 116 09-APR-80 Tools a test of the mail system <- _type (message sequence) _subject string: _s_v_e_n_t_e_k_<_C_R_> (message 13, 129 characters) Date: 10-APR-80 10:43:02 - PST From: Sventek Subject: sventek's test To: sventek, tools, system sure hope this works <- _put (message sequence) _subject string: _m_a_i_l_<_C_R_> into file name: _n_t_e_s_t_._m_s_g_<_C_R_> <- _delete (message sequence) _from string: _s_y_s_t_e_m_<_C_R_> <- _type (message sequence) _deleted messages -12- Msg (4) 17-Mar-82 Msg (4) (message 5, 330 characters) Date: 03-APR-80 11:35:09 - PST From: System Subject: A TEST OF THE MAIL SYSTEM To: allen, austin, bargmeyer, benson, gey, guest, heckman, helena, hogan, holmes, kreps, merrill, oracle, robinson, rtsg, scherrer, shoshani, sventek, sventekv, system, tabata, tape, tools THIS IS ANOTHER TEST. SORRY FOR THE INCONVENIENCE. <- _overwrite old file 'test.msg' [type SPACE to confirm] _<_S_P_A_C_E_> updating... 1 114 25-MAR-80 Tools another test of mail 2 323 27-MAR-80 Tools still more tests 3 289 27-MAR-80 Tools testing 4 114 01-APR-80 Tools test of the mail system 5 116 09-APR-80 Tools a test of the mail system 6 308 09-APR-80 Tools more testing 7 99 09-APR-80 Tools another test 8 145 09-APR-80 Tools why doesn't mail work? 9 129 10-APR-80 Tools more testing 10 298 10-APR-80 Tools more testing 11 326 10-APR-80 Tools Yet another test 12 129 10-APR-80 Sventek sventek's test 13 314 10-APR-80 Tools testing again <- _move (message sequence) _1_-_5_<_C_R_> into file name: _o_l_d_._m_s_g_<_C_R_> <- _go to message number: _first (message 1, 114 characters) Date: 25-MAR-80 12:46:23 - PST From: Tools Subject: another test of mail To: tools sure hope this works again. <- _current message is 1 of 13 messages in file 'test.msg' <- _next message is: (message 2, 323 characters) Date: 27-MAR-80 15:08:32 - PST From: Tools Subject: still more tests To: allen, austin, bargmeyer, benson, gey, guest, heckman, helena, hogan, holmes, kreps, merrill, oracle, robinson, rtsg, scherrer, shoshani, sventek, sventekv, system, tabata, tape, tools -13- Msg (4) 17-Mar-82 Msg (4) another test message <- _go to message number: _last (message 13, 314 characters) Date: 10-APR-80 14:53:19 - PST From: Tools Subject: testing again To: allen, austin, bargmeyer, benson, gey, guest, heckman, helena, hogan, holmes, kreps, merrill, oracle, robinson, rtsg, scherrer, shoshani, sventek, sventekv, system, tabata, tape, tools will it never stop? <- _current message is 13 of 13 messages in file 'test.msg' <- _backing up - previous message is: (message 12, 129 characters) Date: 10-APR-80 10:43:02 - PST From: Sventek Subject: sventek's test To: sventek, tools, system sure hope this works <- _jump into shell [type SPACE to confirm] _<_S_P_A_C_E_> % _l_o_g_o_u_t_<_C_R_> <- _? MSG Help The following commands are recognized by msg: a[nswer] message b[ackup] to previous message and type it c[urrent] message number and file d[elete] message(s) e[xit] and update old file f[orward] message g[o to] message specified and print it h[eaders] print headers of message(s) i[nformation] on command displayed j[ump] into shell - return by typing logout to shell k[ey] encryption-key *** UNIMPLEMENTED *** l[ist] message(s) in print format on file m[ove] message(s) to another mail file and mark them deleted n[ext] message is typed o[verwrite] current file and re-read p[ut] copies of message(s) in another mail file q[uit] leave MSG without updating current file r[ead] in another mail file -14- Msg (4) 17-Mar-82 Msg (4) s[ndmsg] invoke SNDMSG to send a message (and return to MSG) t[ype] message(s) on standard output u[ndelete] message(s) w[rite] current file, sorted by date field *** UNIMPLEMENTED *** #[news] print MSG news ?[help] print this list %[intro] type an introduction to MSG (for first-time users) For more information, use the i[nformation] command. <- _# MSG News No news is good news! <- _information - type command character: _r Read file name: This command allows the user to use MSG on files created by previous Move or Put invocations. The current message file is closed with no modification, and the file specified is read, displaying the headers before prompting for the next command. <- _headers (message sequence) _all messages 1* 114 25-MAR-80 Tools another test of mail 2* 323 27-MAR-80 Tools still more tests 3* 289 27-MAR-80 Tools testing 4* 114 01-APR-80 Tools test of the mail system 5* 116 09-APR-80 Tools a test of the mail system 6 308 09-APR-80 Tools more testing 7 99 09-APR-80 Tools another test 8 145 09-APR-80 Tools why doesn't mail work? 9 129 10-APR-80 Tools more testing 10 298 10-APR-80 Tools more testing 11 326 10-APR-80 Tools Yet another test 12 129 10-APR-80 Sventek sventek's test 13 314 10-APR-80 Tools testing again <- _list (message sequence) _from string: _t_o_o_l_s_<_C_R_> on file name: _t_o_o_l_s_._l_s_t_<_C_R_> <- _undelete (message sequence) _deleted messages <- _move (message sequence) _from string: _s_v_e_n_t_e_k_<_C_R_> into file name: _s_v_e_n_t_e_k_._m_s_g_<_C_R_> <- _current message is 12 of 13 messages in file 'test.msg' <- _headers (message sequence) _undeleted messages 1 114 25-MAR-80 Tools another test of mail 2 323 27-MAR-80 Tools still more tests 3 289 27-MAR-80 Tools testing 4 114 01-APR-80 Tools test of the mail system 5 116 09-APR-80 Tools a test of the mail system 6 308 09-APR-80 Tools more testing -15- Msg (4) 17-Mar-82 Msg (4) 7 99 09-APR-80 Tools another test 8 145 09-APR-80 Tools why doesn't mail work? 9 129 10-APR-80 Tools more testing 10 298 10-APR-80 Tools more testing 11 326 10-APR-80 Tools Yet another test 13 314 10-APR-80 Tools testing again <- _overwrite old file 'test.msg' [type SPACE to confirm] _<_S_P_A_C_E_> updating... 1 114 25-MAR-80 Tools another test of mail 2 323 27-MAR-80 Tools still more tests 3 289 27-MAR-80 Tools testing 4 114 01-APR-80 Tools test of the mail system 5 116 09-APR-80 Tools a test of the mail system 6 308 09-APR-80 Tools more testing 7 99 09-APR-80 Tools another test 8 145 09-APR-80 Tools why doesn't mail work? 9 129 10-APR-80 Tools more testing 10 298 10-APR-80 Tools more testing 11 326 10-APR-80 Tools Yet another test 12 314 10-APR-80 Tools testing again <- _read file name: _n_t_e_s_t_._m_s_g_<_C_R_> reading... 1 114 25-MAR-80 Tools another test of mail 2 114 01-APR-80 Tools test of the mail system 3 330 03-APR-80 System A TEST OF THE MAIL SYSTEM 4 116 09-APR-80 Tools a test of the mail system 5 145 09-APR-80 Tools why doesn't mail work? <- _quit [type SPACE to confirm] _<_S_P_A_C_E_> -16- #-h- ratfor 25882 asc 02-apr-82 17:01:52 v1.1 (sw-tools v1.1) Ratfor (4) 4-Apr-78 Ratfor (4) NAME Ratfor - rational FORTRAN pre-processor RATFOR PRIMER Ratfor 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, and by improving the "cosmetics" of the language. Ratfor allows for all the features of normal Fortran, plus makes available these control structures: "if"-"else" "while", "for", and "repeat"-"until" for looping "select" for multi-way branching "break" and "next" for controlling loop exits statement grouping with braces The cosmetic aspects of Ratfor have been designed to make it concise and reasonably pleasing to the eye: free form input unobtrusive comment convention translation of >, <=, etc. into .GT., .LE., etc. string data type quoted character strings character constants "define" statement for symbolic constants conditional preprocessing "include" statement for including source files Ratfor is implemented as a preprocessor which translates the above features into Fortran, which can then be fed into almost any Fortran compiler. Each of the Ratfor features will now be discussed in more detail. In the following, a "statement" is any legal statement in Fortran: assignment, declaration, subroutine call, I/O, etc., or any of the Ratfor statements themselves. Any Fortran or Ratfor 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- Ratfor (4) 4-Apr-78 Ratfor (4) IF-ELSE Ratfor 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 Ratfor statements may be one or more valid Ratfor 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- Ratfor (4) 4-Apr-78 Ratfor (4) WHILE Ratfor 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 Ratfor statements, so if the condition is not met, the loop will be executed zero times. Also, as with the IF, the Ratfor statements can be any valid Ratfor 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) } -3- Ratfor (4) 4-Apr-78 Ratfor (4) 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 backward loops, 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.) Groups of Fortran statements may be used in the "init" and "increment" clauses by using the usual grouping characters ({...} or [...]) and separating the statements with semicolons (;). For example: for ([i=1; j=1]; buf(i) != EOS; [i=i+2; j=j+1]) out(j) = buf(i) copies every other character in buf into consecutive locations in out. -4- Ratfor (4) 4-Apr-78 Ratfor (4) 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 Ratfor 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 (' ') col = col + 1 } until (tabpos(col,tabs) == YES) -5- Ratfor (4) 4-Apr-78 Ratfor (4) SELECT The "select" statement permits the execution of multi-way branches. The syntax is: select (expression) { case constant[,constant]*: statement(s) case constant[,constant]*: statement(s) . . . case constant[,constant]*: statement(s) default: statement(s) } `expression' must result in an integer or character value, which is then compared with the `constant's enumerated in the statement block. Unlike the `switch' statement in the C programming language, there is an implied break after each case. If more than one Ratfor statement is desired for each case, the statements must be enclosed in brackets. It is possible to exit from a group of statements in the scope of a case label through the use of a break statement (see below). An example of the use of select is: select (ngetch(c, fd)) { case 'a','q': x = 5 case 'b','c': x = 10 case EOF: { call remark("Error in input.") call putbak(EOF) } default: x = 0 } -6- Ratfor (4) 4-Apr-78 Ratfor (4) BREAK and NEXT Ratfor provides statements for leaving a loop early and for beginning the next iteration. "Break" causes an immediate exit from whatever loop it is contained in (which may be a "while", "for", "repeat" or "select"). Control resumes with the next statement after the loop. Only one loop is terminated by a "break", even if the "break" is contained inside several nested loops. For example: repeat { if (getc(c) == EOF) break ... } "Next" is a branch to the bottom of the 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, and to the reinitialize part of a "for". For example: for (i=1; i<10; i=i+1) { if (array(i) == ' ') next ... } Breaking out of multiple loops can be achieved by specifying the number of levels to break out of after the break statement, as in: repeat { repeat { if (condition) break 2 line 2 } line 1 } line 0 Upon execution of the "break 2" statement, execution resumes at "line 0". It is probably better to use a "goto" statement when breaking out of multiple loops, since that should be a little -7- Ratfor (4) 4-Apr-78 Ratfor (4) easier to maintain and understand. -8- Ratfor (4) 4-Apr-78 Ratfor (4) STATEMENT GROUPING AND NULL STATEMENTS Ratfor 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 Ratfor 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, the characters "[" and "]" may be used instead of "{" and "}" respectively. Ratfor 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) == ' '; i=i+1) ; positions after leading blanks in a line. -9- Ratfor (4) 4-Apr-78 Ratfor (4) 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 Ratfor assumes there is one statement per line unless told otherwise. Ratfor will, however, continue lines when it seems obvious that they are not yet done. 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. Statements may be passed through the Ratfor compiler unaltered by inserting a percent sign (%) as the first character on the line. The percent will be removed, the rest of the line shifted one position to the left, and the line sent out without any changes. This is a convenient way to pass regular Fortran or assembly code through the ratfor compiler. -10- Ratfor (4) 4-Apr-78 Ratfor (4) 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 -11- Ratfor (4) 4-Apr-78 Ratfor (4) CHARACTER TRANSLATION Sometimes the characters >, <=, etc. are easier to read in Fortran condition statements than the standard Fortran .EQ., .LT., etc.. Ratfor allows either convention. If the special characters are used, they are translated in the following manner: == .EQ. != ^= ~= .NE. < .LT. > .GT. <= .LE. >= .GE. | .OR. & .AND. ! .NOT. For example, for (i=1; i<= 5; i=i+1) ... if (j != 100) ... -12- Ratfor (4) 4-Apr-78 Ratfor (4) STRING DATA TYPE All character arrays in Ratfor are sequences of ASCII characters, stored right-adjusted, one per array element, with the string terminated with an EOS marker. An automatic way to initialize string characters arrays is provided. The syntax is: string name "characters" or string name(n) "characters" Ratfor will define name to be a character (or, more likely, integer) array long enough to accomodate the ASCII codes for the given character string, one per element. The last word of name is initialized to EOS. If a size is given, name is declared to be an integer array of size 'n'. If several string statements appear consecutively, the generated declarations for the array will precede the data statements that initialize them. For example, the declarations: string errmsg "error" string done "bye" would be converted by ratfor into the Fortran: integer error(6) integer done(4) data error(1), error(2), error(3), error(4), error(5), error(6) /'e', 'r', 'r', 'o', 'r', EOS/ data done(1), done(2), done(3), done(4) /'d', 'o', 'n', 'e', EOS/ The standard escape characters used in the text processing utilities (find, ch, ed, etc.) can be used inside of a string. In particular, to embed an atsign ('@') of a double quote ('"') into the string, they must be escaped, as in: string escape "Embed quote (@")" -13- Ratfor (4) 4-Apr-78 Ratfor (4) QUOTED CHARACTER STRINGS Text enclosed in matching double quotes is converted to nH... format, but is otherwise unaltered. For instance, call remark ("Error detected") would translate to call remark (14hError detected) and data string /"Can't find answer"/ would become data string /17hCan't find answer/ If the local operating system does not support both upper and lower case hollerith strings, an escape mechanism is generally provided to allow the user to indicate case. Some operating systems are not capable of finding the end of a fortran hollerith string. In this case it may be necessary for the user to mark the end of her quoted string with a specific character, such as a period. The only escape sequence interpreted inside of hollerith strings is to permit embedding of a double quote into the string, as in call error("Bad quote character (@").") becomes call error(24hBad quote character (").) -14- Ratfor (4) 4-Apr-78 Ratfor (4) CHARACTER LITERALS Character constants of the form 'c' are converted to the decimal integer representation of that character in the ASCII character set. For example: call putc('!') becomes call putc(33) The standard escape sequences for characters (as used in find, ch and ed) are interpreted within the apostrophes. In particular, '@n' is NEWLINE, '@t' is TAB and '@@' is ATSIGN. Consult the writeup on the find utility for the complete set of escaped characters. -15- Ratfor (4) 4-Apr-78 Ratfor (4) DEFINE Any string of alphanumeric characters can be defined as a name: thereafter, whenever that name occurs in the input (delimited by non-alphanumerics) it is replaced by the rest of the definition line. The syntax is: define(name, replacement string) which define "name" as a macro which will be replaced with "replacement string" when encountered in the source files. As a simple example: define(ROW,10) define(COLUMN,25) dimension array (ROW, COLUMN) and define(EOF,-1) if (getlin(line, fd) == EOF) ... Definitions may be included anywhere in the code, as long as they appear before the defined name occurs. The names of macro may contain letters, digits, and underline characters, but must start with a letter. Upper and lower cases ARE significant (thus EOF is not the same as eof). Any occurrences of the strings '$n' in the replacement text, where 1 <= n <= 9, will be replaced with the nth argument when the macro is actually invoked. For example: define(bump, $1 = $1 + 1) will cause the source line bump(i) to be expanded into i = i + 1 In addition to define, four other built-in macros are provided: arith(x,op,y) performs the "integer" arithmetic specified by -16- Ratfor (4) 4-Apr-78 Ratfor (4) op (+,-,*,/) on the two numeric operands and returns the result as its replacement. incr(x) converts the string x to a number, adds one to it, and returns the value as its replacement (as a character string). ifelse(a,b,c,d) compares a and b as character strings; if they are the same, c is pushed back onto the input, else d is pushed back. substr(s,m,n) produces the substring of s which starts at position m (with origin one), of length n. If n is omitted or too big, the rest of the string is used, while if m is out of range the result is a null string. -17- Ratfor (4) 4-Apr-78 Ratfor (4) CONDITIONAL PREPROCESSING Ratfor source code may be conditionally preprocessed, dependent upon the definition (or lack thereof) of a symbol. The syntax is ifdef(symbols) ifnotdef(symbol) . . . . . . elsedef elsedef . . . . . . enddef enddef Conditionals may be nested to some maximum level (usually 10). An example of their use might be an output routine which forces the output of a characters from a string to uppercase, depending upon the definition of a symbol DO_UPPER: for (i = 1; buf(i) != EOS; i = i + 1) { ifdef (DO_UPPER) call putc(cupper(buf(i)) elsedef call putc(buf(i)) enddef } -18- Ratfor (4) 4-Apr-78 Ratfor (4) INCLUDE Files may be inserted into the input stream via the "include" command. The statement include filename or include "filename" inserts the file found on input file "filename" into the Ratfor 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 -19- Ratfor (4) 4-Apr-78 Ratfor (4) IMPLEMENTATION Ratfor was originally written in C, a high-level language, on the Unix operating system. Our version is written in Ratfor itself, originally brought up by a bootstrap written in Fortran. Ratfor generates code by reading input files and translating any Ratfor keywords into standard Fortran. Thus, if the first token (word) on a source line is not a keyword (like "for", "while", etc.) the entire statement is simply copied to the output with appropriate character translation and formatting. Ratfor knows very little Fortran and thus does not handle any Fortran error detection. Errors in Ratfor keyword syntax are generally noted by a message to the user's terminal along with an indication of the source line number which caused the problem. CONCLUSIONS Ratfor 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. -20- Ratfor (4) 4-Apr-78 Ratfor (4) EXAMPLE The following is a sample Ratfor tool designed to show some of the commonly-used Ratfor commands. The routine reads through a list of files, counting the lines as it goes. # This is an example of a routine written in Ratfor # Symbols such as EOF, ERR, MAXLINE, character and filedes are # automatically defined (i.e. a file containing them is included) # by the preprocessor ## count - counts lines in files DRIVER(count) include comblk # this file contains a common block which # contains a variable "linect" character file(FILENAMESIZE), line(MAXLINE) integer i filedes fd integer getarg, open, getlin string total "total lines: " call query ("usage: count file.") linect = 0 #loop through the list of files for (i=1; getarg(i, file, FILENAMESIZE) != EOF; i=i+1) { fd = open (file, READ) # open (attach) the file if (fd == ERR) # file could not be located call cant (file) while (getlin(line, fd) != EOF) # read and count lines linect = linect + 1 call close (fd) # close (unattach) the file } call putlin(total, STDOUT) call putint (linect, 5, STDOUT) call putch ('@n', STDOUT) DRETURN end -21- Ratfor (4) 4-Apr-78 Ratfor (4) SEE ALSO 1) Kernighan, Brian W., "Ratfor--a Preprocessor for a Rational Fortran". Software - Practice and Experience, Vol. 5, 4 (Oct-Dec 75), pp. 395-406. 2) Kernighan, Brian W. and P. J. Plauger, "Software Tools". Addison-Wesley Publishing Company, Reading, Mass., 1976. 3) The ratfor user document 4) The Unix command "rc" in the Unix Manual (RC(I)) -22-