There are two built-in Functions that you primarily use to write (ie, save) data to a file.
Writing lines of text
The first such Function is named LINEOUT. LINEOUT is used with text (ie, ascii) files, and it writes a complete line of characters to a file. REXX automatically puts a newline character at the end of the line of characters that you write to the file.
Note: Upon some operating systems, REXX may put both a newline character and a linefeed character at the end of the line. This is the case for Windows, since Windows text editors usually expect both characters at the end of each line. Although a text editor won't display these special "end of line" characters, they are nevertheless at the end of each line in the file.
The first argument you pass to LINEOUT is the name of the file. You can include the full path to the file, for example C:\MyDir\MyFileName.txt.
The second argument is the actual line of characters you wish written.
The third argument is the position at which you wish the line to be written. If you pass a 1, then the line is written at the very start of the file (and will overwrite, and by default erase, any previous contents of the file).
If you omit the position argument, then LINEOUT will write the line after any other line you wrote with a previous call to LINEOUT. If you have not yet done any LINEOUT to this file, then the assumed position will be at the end of the file. In other words, the line you write will be appended to any existing lines in the file.
You may wonder "What happens if I tell LINEOUT to write a line to a file that hasn't yet been created?". In that case, REXX will automatically create the new file for you, and then write the line to it.
If LINEOUT successfully writes the line to the file, then it will return a 0. If there is a problem, LINEOUT will return some other number, raise the NOTREADY condition, and put the file in an "error state" such that no further calls to LINEOUT will write data until you clear that error state. (You can use STREAM Function's "D" option to retrieve an error message for why LINEOUT failed).
Here is an example where we write 3 lines to a text file. The text for the three lines will be This is line 1, This is line 2, and This is the last line. That is the order in which we will write them out. So, we need to make 3 calls to LINEOUT since we want to write 3 lines of text. For the name of the file, we'll use mytext.txt.
/* Write the first line to a text file named "mytext.txt". Note * that we specify a position of 1, so if the file already exists * and has some text in it, that original text is erased. */ err = LINEOUT("mytext.txt", "This is line 1", 1) /* Check for an error. */ IF err \== 0 THEN DO Bad: SAY "ERROR:" STREAM("mytext.txt", "D") RETURN END /* Write the second line to the same text file. Note that * we omit the position, so this line gets written immediately * after the line we just wrote above. */ err = LINEOUT("mytext.txt", "This is line 2") /* Check for an error. */ IF err \== 0 THEN SIGNAL Bad /* Write the third line to the same text file. Note that * we omit the position, so this line gets written immediately * after the line we just wrote above. */ err = LINEOUT("mytext.txt", "This is the last line") /* Check for an error. */ IF err \== 0 THEN SIGNAL Bad SAY "Successful! Now use Notepad to view mytext.txt" RETURNIf you run the above script, it should create a text file (named "mytext.txt" in the current directory, which is usually the same directory as where you saved your script). If you view this file in Notepad or Rexx Programmer Center, you'll see that it contains those 3 lines of text we wrote to it.
Of course, we could use variables to pass arguments to LINEOUT, as so:
MyFilename = "mytext.txt" MyLine = "This is line 1" err = LINEOUT(MyFileName, MyLine, 1)
The position arg allows you to determine where you would like to write a line. For example, let's say that we wish to write a script that changes the second line of that text file we created above. We want to change the text to "This is the second line". For LINEOUT, the position arg specifies at what line number you wish LINEOUT to write. So if we want to overwrite the second line in a text file, we specify a position of 2. Run the following script, and then view "mytext.txt" in Notepad:
/* Modify the second line of a text file named "mytext.txt". Note * that we specify a position of 2 to write at the second * line. */ err = LINEOUT("mytext.txt", "This is the second line", 2) /* Check for an error. */ IF err \== 0 THEN DO Bad: SAY "ERROR:" STREAM("mytext.txt", "D") RETURN END SAY "Successful! Now use Notepad to view mytext.txt" RETURNNow when you view "mytext.txt", you should see that the second line is changed. But, you may notice something else too. The third line is now gone. This is because, when LINEOUT writes to a file, it erases all existing lines after the position you specify. Because we chose to write at position 2, that means that the third line (and any subsequent lines, if there were some) are erased. Reginald allows you to change that behavior and preserve the subsequent lines. You must use OPTIONS 'NOLINEOUTTRUNC' once before you call LINEOUT as so:
/* Turn off the LINEOUTTRUNC option. This need be done * once only, usually at the beginning of your script. */ OPTIONS 'NOLINEOUTTRUNC' /* Modify the second line of a text file named "mytext.txt". Note * that we specify a position of 2 to write at the second * line. */ err = LINEOUT("mytext.txt", "This is the second line", 2) /* Check for an error. */ IF err \== 0 THEN DO Bad: SAY "ERROR:" STREAM("mytext.txt", "D") RETURN END SAY "Successful! Now use Notepad to view mytext.txt" RETURNNow rerun the very first script to recreate the 3 line version of "mytext.txt", then run the above script. When you view the file in Notepad, you will notice that line 2 is changed, but you'll notice that line 3 still exists... sort of. We overwrote line 2 with text that was longer than the original text in line 2. So it "spilled over" and actually overwrote the start of line 3. So, one thing you should note is that, although this option allows you to overwrite existing lines without erasing subsequent lines in the file, if your new text isn't exactly as long as the original line (that you're replacing), then you'll either overwrite subseqent lines (if the new text is longer) or leave part of the original line still in the file (if the new text is shorter. Of course you could pad out the new text with trailing spaces to make it the same size as the original to solve this latter dilemma).
If you need to change some of the lines of an existing text file to different lengths, while retaining existing lines, you'll have to read all of the lines into REXX variables, modify the variables' values, and then erase the original contents of the file when you write all those modified lines back to the file. We'll look into that later, after you learn about reading a file.
Writing individual characters
Alternately, the CHAROUT Function can write characters (ie, individual bytes) to a file. Unlike with LINEOUT, REXX will not append any newline or linefeed characters. The arguments are almost exactly the same as with LINEOUT, except that CHAROUT's Position argument is not in terms of lines, but rather, characters. In other words, if you specify a position of 3, then CHAROUT starts writing after the third already existing character (not line) in the file.
If you omit the position argument, then CHAROUT will write the characters after any other characters you wrote with a previous call to CHAROUT. If you have not yet done any CHAROUT to this file, then the assumed position will be at the end of the file. In other words, the characters you write will be appended to any existing characters in the file. In this respect, CHAROUT is very much like LINEOUT.
And just like with LINEOUT, if you write characters to a file that hasn't yet been created, REXX will automatically create the new file for you, and then write the characters to it.
If CHAROUT successfully writes the characters to the file, then it will return a 0. If there is a problem, CHAROUT will return some other number, raise the NOTREADY condition, and put the file in an "error state" such that no further calls to CHAROUT (or LINEOUT) will write data until you clear that error state. (You can use STREAM Function's "D" option to retrieve an error message for why CHAROUT failed). This is also just like LINEOUT.
Here is an example where we write some characters to a text file. For the name of the file, we'll use mytext.txt.
/* Write the characters "1234" to a text file named "mytext.txt". * Note that we specify a position of 1, so if the file already * exists and has some text in it, that original text is erased. */ err = CHAROUT("mytext.txt", "1234", 1) /* Check for an error. */ IF err \== 0 THEN DO Bad: SAY "ERROR:" STREAM("mytext.txt", "D") RETURN END /* Write some more characters to the same text file. * Note that we omit the position, so these characters get * written immediately after the characters we just wrote * above. */ err = CHAROUT("mytext.txt", "567") /* Check for an error. */ IF err \== 0 THEN SIGNAL Bad /* Write one more character to the same text file. * Note that we omit the position. */ err = CHAROUT("mytext.txt", "8") /* Check for an error. */ IF err \== 0 THEN SIGNAL Bad SAY "Successful! Now use Notepad to view mytext.txt" RETURNIf you run the above script, it should create a text file named "mytext.txt" in the current directory. If you view this file in Notepad, you'll see that it contains those 8 characters we wrote to it. They are all on one line because, after all, CHAROUT does not automatically put any newline or linefeed characters in there, unlike LINEOUT.
The position arg allows you to determine where you would like to write characters. For example, let's say that we wish to write a script that changes the third character of that text file we created above. We want to change the character to a plus sign (+). For CHAROUT, the position arg specifies at what character number you wish CHAROUT to write. So if we want to overwrite the third character in a text file, we specify a position of 3. Run the following script, and then view "mytext.txt" in Notepad:
/* Modify the third character of a text file named "mytext.txt". * Note that we specify a position of 3 to write at the third * character. */ err = CHAROUT("mytext.txt", "+", 3) /* Check for an error. */ IF err \== 0 THEN DO Bad: SAY "ERROR:" STREAM("mytext.txt", "D") RETURN END SAY "Successful! Now use Notepad to view mytext.txt" RETURNNow when you view "mytext.txt", you should see that the third character is changed. And unlike with LINEOUT, CHAROUT doesn't automatically erase any subsequent characters.
Intermixing LINEOUT/CHAROUT
It is even acceptable to use CHAROUT to write some characters, and then use LINEIN to write the remainder of the line of text. In other words, you can intermix calls to CHAROUT and LINEOUT on the same file (although LINEOUT makes sense only when dealing with files that have lines of text in them). If you do not pass the position arg, LINEOUT starts writing a line where CHAROUT stopped writing characters (and vice versa).
/* Write the characters "Line 1:" to a text file named "mytext.txt". * Note that we specify a position of 1, just to make sure that * we start at the beginning of the file (in case it already * exists and has some text in it). */ err = CHAROUT("mytext.txt", "Line 1: ", 1) IF err \== 0 THEN DO Bad: SAY "ERROR:" STREAM("mytext.txt", "D") RETURN END /* Write a line to the same text file. Note * that we omit the position, so this line gets written * immediately after the characters we just wrote above. * Also, since we haven't specified NOLINEOUTTRUNC, any * original text after this line is erased. */ err = LINEOUT("mytext.txt", "This is the first line") IF err \== 0 THEN SIGNAL Bad /* Write some more characters to the same text file. * Note that we omit the position, so these characters * get written after the line we just wrote above. */ err = CHAROUT("mytext.txt", "Line 2: ") IF err \== 0 THEN SIGNAL Bad /* Write a line to the same text file. Note * that we omit the position, so this line gets written * immediately after the characters we just wrote above. */ err = LINEOUT("mytext.txt", "This is the second line") IF err \== 0 THEN SIGNAL Bad SAY "Successful! Now use Notepad to view mytext.txt" RETURN