Beyond the Basics


Input/Output on the Atari

Larry Isaacs

Here is much that you will want to know about dealing with files. There is also an explanation of the XIO commands.

In this article, I will try to explain how to use the various BASIC commands at your disposal to communicate with the peripheral devices in your system. These peripheral devices include the Screen Editor (E:), keyboard (K:), and TV Monitor (S:), all of which are part of your machine. External devices which are currently available include disk drives (D1: through D4:), printer (P:), and cassette (C:). The I/O (Input/Output) commands we will be discussing are the PUT, GET, PRINT, INPUT, XIO5, XIO7, XIO9, and XIO11 commands. Also, the discussion will be limited to the use of these commands as it relates to logical files.

Before we get into details, there are two important facts to remember. The first one is that these I/O commands result in the transfer of one or more bytes of data, and that, often, these bytes will be ATASCII characters. The second fact is that the byte or bytes which get transferred will be the same regardless of the device with which you are communicating.

Open And Close

Before you can communicate with a peripheral device, it must first be "opened," and, in the case of the disk, a file name provided. The syntax of the open command is as follows:

OPEN #iocb,mode,0,"device:name.ext"

iocb - I/O Control Block through which BASIC will send its requests to the I/O software.

mode - This should be an arithmetic expression which evaluates to 4, 6, 8, 9, or 12. For now we will just be using 4, 8, and 12. Their meaning is as follows:

4 = open for reading
8 = open for writing
12 = open for reading and writing

device - This should be a letter which identifies which device to associate with the I/O Control Block specified previously.

name - This should be a name of up to eight alphanumeric characters, the first of which must be a letter.

ext - This is an extension to the name which is usually used to indicate the type of file, BASIC program, data, etc. It may include up to three alphanumeric characters. The name plus extension form the file name which is needed when communicating with the disk. Once you have opened a device, you communicate with that device using the "iocb" number. To close a device or file, you use the CLOSE command. The syntax for this command is as follows:

CLOSE #iocb

Only one device can be associated with an IOCB at a time. If you wish to associate a new drive with an IOCB that is currently in use, you must close the old device first. In the case of the disk, cassette, and the printer, a CLOSE command may be required for proper operation. For example, the disk can only write groups of 128 bytes, called sectors, which are written once enough data has been received to fill the sector. The CLOSE command is required to cause the last sector of a file, which is only partially filled with data, to be written to the disk. The cassette also needs a CLOSE command to write the last group of bytes. And since the printer doesn't print a line until an EOL (End of Line) character is received, a CLOSE may be needed to print out the last line.

If a program terminates without error, or via an END statement, all open devices and files will be closed automatically. If the program terminates because of an error, a STOP statement, or the BREAK key being struck, the devices and files will he left open. If you aren't able to continue the program, you may close the devices and files by entering the necessary CLOSE commands directly, i.e. without line numbers. Also, executing the RUN command will close any open devices or files.

Now we will begin our discussion of the I/O commands. Many of the examples make use of the disk. If you wish to use cassette instead, simply change the file specification in the OPEN commands to the cassette device. Just place a blank cassette in the cassette player. Then whenever you hear two beeps, rewind the tape, press PLAY and RECORD on the player, then hit RETURN on the ATARI. Whenever you hear one beep, rewind the tape, press PLAY on the player, then hit RETURN on the ATARI.

Put And Get

Let's look first at the PUT and GET commands, which are the most basic of the I/O commands. These two commands result in the transfer of a single byte, with the PUT command sending a byte, and the GET command receiving a byte. Here is the syntax for the commands:

GET #fn, variable where "fn" is a file number, and "variable" is a simple variable, not an array or string variable

PUT #fn, expression where "expression" is an arithmetic expression

Listing 1 provides an example for using the GET and PUT commands. In this program the Screen device is opened for reading and writing. This open command will also cause the screen to be cleared. The letters from "A" to "Z" are sent to the Screen using the PUT command and, after the cursor is repositioned, the letters are fetched hack from the Screen using the GET command.

Program 1: Example of using GET and PUT

Download (Saved BASIC)
Download / View (Listed BASIC)

Listing 2 provides a similar example which communicates with a disk. Note, if you run this program a second time, opening the file for writing will cause the old file to be deleted. Also, if you try to get more bytes than were written to the file, an ERROR 136 (End of File encountered) will he given. Changing the 26 to 27 in line 60 will illustrate this.

Program 2: Read and write from disk file

Download (Saved BASIC)
Download / View (Listed BASIC)

The advantage of using GET and PUT is that you are controlling the transfer of individual bytes. If this isn't necessary, you will likely find it simpler and faster to use one of the following I/O commands. Each of these commands involves the transfer of a string of bytes.

Print And Input

The PRINT and INPUT commands are used to transfer a string of characters. The syntax of these commands is as follows:

PRINT #iocb; list where the "list" is a list of expressions separated by commas or semicolons. The expressions may be numbers, strings, simple variables or string variables. If a semicolon is used prior to an expression, the characters for this expression will be sent immediately following any previous characters. If a comma is used instead of a semicolon, including the one shown in the syntax, tabbing will occur before characters from the expression are sent. If the list doesn't end with a comma or semicolon, an EOL character will be sent at the end of the list. If you wish, the list need not contain any expressions.

INPUT #iocb, list where the "list" is a list of expressions separated by commas. The expressions may be simple variables or string variables.

When printing strings, naturally the characters in the string are sent. However, when you print a number, the number is converted to a string of digits and sent as ATASCII characters. When you input a string, characters will be fetched until an EOL character is received. These characters will be stored in the string's reserved memory until that is filled or the EOL character is received. When you input a number, characters will be fetched until an EOL character or a comma is received. At this point, assuming all the characters were valid digits, the string is converted back to a number.

Listing 3 provides an example of using PRINT and INPUT with the Editor device. Like the Screen device, the Editor will print and fetch characters from the screen memory. However, when printing to the Editor, control characters will perform the associated function instead of printing a character. When you input from the Editor, RETURN must be hit before the Editor will begin sending characters. Also, the Editor remembers the line and column of the cursor when the input request is made. As long as you don't hit a cursor-up or cursor-down, the fetching of characters will begin with the first character of the new line which the cursor occupies. The fetching of characters will continue until the last nonblank character of the line occupied by the cursor when RETURN was hit. You can explore the operation of the Editor further by making changes to Listing 3, and finding out what happens.

Program 3: Example of using E:

Download (Saved BASIC)
Download / View (Listed BASIC)

Listing 4 gives an example of using PRINT with the disk. The program reads back the characters using the GET command so you can see what was sent to the disk by the PRINT command. Again, you can experiment with changes to this program to improve your understanding of how these commands operate.

Program 4: Example of using PRINT to write to disk

Download (Saved BASIC)
Download / View (Listed BASIC)

XIO9 And XIO5

The XIO9 and XIO5 commands, like the PRINT and INPUT commands, send and receive a string of characters. The syntax for these commands is as follows:

XIO cmdn,#icob,mode,0,exp
"cmdn" is the XIO command number.
9 = PUT RECORD
5 = GET RECORD
"iocb" and "mode" have the same function as in the OPEN statement.
"exp" may be a string or string variable when writing, or a string variable when reading.

The XIO9, or PUT RECORD command will write characters from the specified string until an EOL character is written. If the string contains an EOL character, the XIO9 terminates at this point, and the rest of the string isn't written. If the string does not contain an EOL character, one is appended. This differs from the PRINT command where the entire string is written regardless of content. The program in Listing 5 illustrates this difference.

Program 5: XIO9 example

Download (Saved BASIC)
Download / View (Listed BASIC)

The XIO5 command, like the INPUT command, will fetch one string and store it in memory. But where the INPUT command stops (when the memory reserved for the string variable is filled), the XIO5 command keeps going. This means that the XIO5 command can load more than one string variable. A second difference is that the INPUT command doesn't store the EOL character, where the XIO5 command does. And one last difference, the INPUT command will change the length of the string variable to the number of characters stored, where the XIO5 command doesn't change the length of any string variable. Before you can make productive use of the XIO5 command, there is one more necessary fact. Once the XIO5 command fills the first string variable to its current length, the next character fetched is apparently discarded and the next memory location is left unchanged. This applies only to the string variable specified in the command statement. The program in Listing 6 illustrates the preceding discussion.

Program 6: XIO5 example

Download (Saved BASIC)
Download / View (Listed BASIC)

XIO11 And XIO7

The XIO11 and XIO7 commands are used to write and read blocks of 255 bytes, respectively. The syntax for these commands is the same as for XIO9 and XIO5 except for the command number. The commands transfer bytes beginning with the reserved memory of the string variable specified in the command. Since you are transferring bytes, their content has no effect on the operation of the command. As with the XIO5 command, once the XIO7 command fills the current length of the first string variable, the next byte fetched isn't stored in memory.

Naturally the XIO11 and XIO7 commands could he used for handling strings of characters. However, if we knew where the address of a string's reserved memory was kept, we could make changes to it, and use these commands to save and restore any portion of memory we want. Fortunately this isn't too difficult. Each string variable will have an entry in the variable storage area, which contains 8 bytes of parameters for the variable. The third and fourth bytes of the parameters contain the displacement from the beginning of the array storage area to the reserved memory for that string. If we dimension a string variable in the first statement of a program, then this displacement can be found by PEEK(134) + (PEEK(135)*256) +2. Also, the address of the reserved memory for this string will be at the beginning of the array storage area. For more detail about this, see INSIDE ATARI BASIC and ATARI TAPE DATA FILES in COMPUTE #4.

Listing 7 shows how to save an array to disk and then read the data from disk into a different array. In this program we direct the XIO11 command to save the desired portion of memory by POKEing the required displacement into the parameters of D$. We then read the data into a different array, which could have been in a different program, by again POKEing the necessary displacement into the parameters of D$. Note the use of the MARK strings and the ADR function to find where the arrays are in memory. Another application might be to add some machine language routines to a program by reading them from disk or cassette and storing them in the required location in memory.

Program 7: Save and read an array to/from disk with XIO11

Download (Saved BASIC)
Download / View (Listed BASIC)

This concludes the explanations of the various I/O commands. I hope I have explained them well enough for you to put them to productive use. Some of the explanations are fairly brief, so to find out more, or to better understand their operation, I highly recommend that you do some experimenting of your own. This is the best way to find out what the commands will do in specific situations.


Return to Table of Contents | Previous Section | Next Section