ODDS & ENDS
ON PET/CBM files
Jim Butterfield
Writing data to a file is quite straightforward: OPEN the file, PRINT# to the file as many times as you like, and then CLOSE the file. Reading is pretty easy, too: OPEN the file, INPUT# until the file has given you all its data, and CLOSE the file.
You can also read a file by using GET# instead of INPUT#. The GET# command is especially useful for checking out a file and seeing what's on there. Here's why: INPUT reads everything to the end-of-line; trims the line it has received by taking off leading and trailing spaces and quotation marks, and then scans the line, converting numbers to internal representation, etc. All very handy; but if something goes wrong, you'll want to use GET to look at the characters one at a time.
When you're reading a data file, keep watching variable ST. It will normally be zero; at the time you read the last value it will change to a value of 64. Any other value means you have a read error.
The ST indicator works slightly differently on the original PET ROMs. It does not go to 64 at the time you read the last value; instead, it switches to 64 only when you try for the following value — the one that isn't there. You can handle this with careful coding. But you'll be better off to upgrade your ROM set so that your programs will be compatible with newer machines.
End-of-file on a disk read is shown in ST, but errors are not. On upgrade (2.0) ROMs, use the command channel (Secondary Address 15) to ask the disk unit how it's doing. Newer ROMs give you disk status variables called DS and DS$ to make it easy to check errors.
PRINT# sends to a file in almost exactly the same way that PRINT sends to the screen: as a group of ASCII type characters. INPUT# receives from a file the same way that INPUT receives from the keyboard/screen. Make sure that what you send to a file will be seen as a good input when it comes back.
Let's pick up more detail on the previous item. If X is five and Y is two, and you say PRINT#3,X;Y the file will be written as:
(space) 3 (space) (space) 2 (space) (return)
Think about it. What would happen if you typed the above sequence in response to an INPUT? Answer: PET would see a single number — not two — whose value is 32. That's exactly what would happen if you later tried to read with an INPUT#. Solution: say PRINT#3,X : PRINT#3,Y and the two numbers will be neatly separated with a RETURN character.
For exactly the same reasons. You shouldn't say PRINT#3,X,Y ... you'll put more spaces on the file, but you won't solve the problem.
Best practice: Use a separate PRINT# statement for each variable.
Early PETs — everything before ROM 4.0 — write both RETURN and LINEFEED at the end of a line. The RETURN is handy — in fact, it's vital — but the LINEFEED can give trouble and should be taken out. You do this by coding something like:
PRINT#3,X;CHR$(13);
The CHR$(13) is the RETURN character. Don't forget the semicolon at the end, or PET will stick another RETURN and LINEFEED behind the whole thing and you'll have a mess.
On 4.0 and subsequent ROMs, the LINEFEED will normally be supressed, and you can go back to PRINT#3,X. Cassette tape files have a special feature which avoids writing the LINEFEED character.
Programs using cassette tape files are quite easy to convert to disk. To open a file for writing change, for example, OPEN 1,1,1, "INVENTORY" to OPEN 1,8,3, "0: INVENTORY,S,W". The 8 means device 8, usually disk; the 3 is an internal disk channel number (pick anything from 3 to 14); 0: means drive zero, and ,S,W means we plan to Write a Sequential file. Everything else for writing the file can remain as before (PRINT# and CLOSE), so long as you watch to make sure you don't write LINEFEEDS with your PRINT#.
Switching over to disk for reading a file is even easier. Change OPEN 1,1,0, "FILENAME" to OPEN 1,8,3, "FILENAME" and you're in business.
In cutting over from tape to disk files, it doesn't hurt to add error checking, of course — secondary address 15 or variables DS and DS$, depending on your system.
Never use the TAB function in writing to a file — or to the printer, for that matter. PET will try to calculate the proper place on the screen for the information — and then sends that type of information to the file. It almost invariably botches the job.
Make sure that any file you write is always closed properly. It's all too easy to write a program that stops or goes into a special routine in certain cases — leaving a file open forever.
Get into the habit of protective CLOSE statements. It's perfectly allowable to say CLOSE 1 even if you're not sure that file number 1 was ever opened. And it doesn't hurt.
Don't forget that you can use a variable to indicate the logical address you want to use. You can say, PRINT#J ... and if J is one, you'll send to logical device number one, etc. This is a very effective way to split a file into several smaller files.
Remember, too, that you can open the screen as a file (it's device 3), so that you could send some things to the screen and others to disk.