Classic Computer Magazine Archive COMPUTE! ISSUE 30 / NOVEMBER 1982 / PAGE 168

Easy File Input:
The String Thing

Jim Butterfield
Associate Editor

For Upgrade and 4.0 BASIC PET/CBM, String Thing solves the problems created by INPUT # and is faster.

Files are easy to handle, but sometimes the INPUT# statement is too clever. It looks so carefully at the material coming in from the file that it can overprocess your information. The INPUT # statement:

  • —trims spaces from the front of the data;
  • —trims quotation marks from front and back;
  • —gives trouble if you want to input over 80 characters;
  • —drops commas and following information; and
  • —drops colons and following information.

You often don't want such things to happen when you are reading a file. But the alternative is to use GET# statements, and they are slow.

Some years ago, Bill McLean, of B.M.B. Compuscience, wrote a String Thing to get around these problems and speed up input. It worked well on Upgrade ROMs, but the transition to 4.0 systems was uncomfortable; strings are stored in a different way in the newer BASIC, and the code needed major surgery. Extra code is needed in order to avoid falling prey to a berserk garbage collection routine. This made the job rather complex and called for two different versions for the two different ROM sets.

New And Improved?

It seems to be time to unearth a new String Thing, one that will work without change on both Upgrade and 4.0 BASIC PETs and CBMs. This way, your program can still move between machines without difficulty. But there's a problem: since different BASIC versions store strings in different ways, how can we make one program compatible with all?

The trick is this: instead of trying to build a new string, we'll re-use an old one. We must be careful: if the string we are recycling is only ten characters long, we must be sure we don't try to put 11 new characters into it.

How To Use It

The program listing comes in two parts: setting up the String Thing and using it. There are two things we need to do in order to set up: define the program's first variable as a string (in the example, A$), making sure that it's long enough to hold any input that we might want to catch (in this case, up to 255 bytes); and then POKEing the String Thing program into place. This setup takes place in lines 70 to 260.

Now that we have String Thing in place, we need to use it. That's the easy part: we just give SYS 896, and the program performs the equivalent of INPUT# 1,A$ without the problems of INPUT. You may remember that we set A$ to a very long string; it will keep its length, but we can find out how many characters have been read by checking PEEK(139). String Thing uses location 139 to record how many characters it has received. If the first thing to come from the file is a RETURN character, this value will be zero, indicating no data characters received. On the other hand, if we fill the string space completely and still have not seen a RETURN, we'll stop at that point. The next call to String Thing will get more of the same sequence.

Some usage hints: Try to leave a string that is at least one character longer than the data you expect. If PEEK(139) ends up equal to the string length, we haven't seen the RETURN character yet-better to leave extra room. Remember that all the things that happen with an INPUT# will happen with String Thing, such as ST signalling end of file. Don't try to change your string variable (in this case, A$) as the program runs; copy the information out to another variable if you need it, e.g., X$=LEFT$(A$,PEEK(139)). String Thing isn't location sensitive; you can move it to some other location with little trouble.

String Thing will work correctly in reading files from cassette tape or disk. Just change the OPEN statement to suit. You won't notice the speed advantage on tape, of course, but you may still benefit from the improved logic handling. String Thing works splendidly with Relative disk files. Position to the record you want in the usual way, with RECORD#1, and then substitute the SYS statement for the INPUT#1.

Try the following demonstration program. You can change the file name in line 400 to any sequential file of your own, or you can write a demonstration file using the following direct statements:

OPEN 1,8,3, "file,s,w"
PRINT#1, "line 1, with comma"
PRINT#1, "mission: impossible"
PRINT#1, CHR$(34); "quotes";CHR$(34)
FOR j = 1 to 40 : PRINT#1,j; : NEXT j : PRINT#1
PRINT#1,"spaced out"
CLOSE 1

If you like, try getting this DATA back using INPUT # statements.

Now for String Thing:

70 REM ** STRING THING (PET/CBM) **
75 REM ** UPGRADE AND 4.0 BASIC **
80 REM ** JIM BUTTERFIELD **
90 REMARK: STRING MUST BE FIRST VARIABLE
100 A$ = "ABCDEFGHIJKLMNOPQ"
110 A$ = A$+A$+A$+A$+A$
120 A$ = A$+A$+A$
130 REM ABOVE SETS STRING FOR MAX (255)
200 DATA 160, 2, 177, 42, 153, 134, 0, 200, 192, 6
210 DATA 208, 246, 162, 1, 32, 198, 255
220 DATA 32, 228, 255, 201, 13, 240, 11, 164, 139, 145
230 DATA 137, 200, 132, 139, 196, 136, 208, 238, 76, 204, 255
250 FOR J = 896 To 933 : READ X : POKE J, X : T = T + X : NEXT J
260 IF T <>5517 THEN STOP
400 OPEN 1, 8, 2, "FILE" (OR DOPEN#1, "FILE")
410 REM: NEXT SYS SAME AS ‘INPUT#1, A$’
420 SYS 896
425 REM: 1 = SIZE OF INPUT (COULD BE 0)
430 L = PEEK (139)
440 PRINT LEFT$ (A$, 1)
450 IF ST = 0 GOTO 420
460 CLOSE 1		(OR DCLOSE)

Alternate Versions

For VIC and Commodore 64 machines, we may once again choose between cassette tape and disk. I've written the disk version below; to get a cassette version, you'll need to do a little juggling. That's because the String Thing program sits in the cassette buffer; it will need to be moved elsewhere if you need to use tape.

Now for the String Thing program:

70 REM ** STRING THING **
75 REM ** VIC AND COMMODORE 64 **
80 REM ** JIM BUTTERFIELD **
90 REM STRING MUST BE FIRST VARIABLE
100 A$ = "ABCDEFGHIJKLMNOPQ"
110 A$ = A$ + A$ + A$ + A$ + A$
120 A$ = A$ + A$ + A$
130 REM ABOVE SETS STRING FOR MAX (255)
200 DATA 160,2,177,45,153,137,0,200,192,6
210 DATA 208,246,162,1,32,198,255
220 DATA 32,228,255,201,13,240,11,164,142,145
230 DATA 140,200,132,142,196,139,208,238,76,204,255
250 FOR J = 896 TO 933 : READ X : POKE J,X:T=T + X : NEXT J
260 IF T<> 5535 THEN STOP
400 OPEN 1,8,3, "FILE"
420 SYS 896
425 REM: 1 = SIZE OF INPUT (COULD BE 0)
430 L = PEEK (142)
440 PRINT LEFTS (A$, 1)
450 IF ST = 0 GOTO 420
460 CLOSE 1

If you have an Original ROM machine, you can't handle disk. Even tape files have certain problems. If you plan to write and read files, you will be much better off if you upgrade your machine to Upgrade ROM. This can be done with a chip change. Even so, let's show that String Thing can be made to work here: we'll read a tape on an Original ROM system.

You may write a demonstration file TO tape in exactly the same way as before, except that you must change the OPEN statement TO:

OPEN 1, 1, 1, "file"
70 REM ** STRING THING **
75 REM ** ORIGINAL ROM BASIC **
80 REM ** JIM BUTTERFIELD **
90 REM STRING MUST BE FIRST VARIABLE
100 A$ = "ABCDEFGHIJKLMNOPQ"
110 A$ = A$ + A$ + A$ + A$ + A$
120 A$ = A$ + A$ + A$
130 REM ABOVE SETS STRING FOR MAXIMUM (255)
200 DATA 160,2,177,124,153,216,0,200,192,6
210 DATA 208,246,162,1,32,198,255
220 DATA 32,228,255,201,13,240,11,164,221,145
230 DATA 219,200,132,221,196,218,208,238,76,204,255
250 FOR J = 896 TO 933 : READ X : POKE J,X : T + X : NEXT J
260 IF T <>6009 THEN STOP
400 OPEN 1,1,0, "FILE"
410 REM: NEXT SYS SAME AS ‘INPUT#1, A$’
420 SYS 896
422 REM: ST LOGIC CHANGE
423 IF ST = 0 GOTO 460
425 REM : 1 = SIZE OF INPUT (COULD BE 0)
430 L = PEEK (221)
440 PRINT LEFTS (A$, 1)
450 GOTO 420
460 CLOSE 1

Assembly Listing

For those who would like to track the machine language, here's the assembly version of the program. The version is Upgrade/4.0 ROMs (the first BASIC program).

0380 A0 02            LDY #2         Copy string…
0382 B1 2A    LOOP1   LDA (VARTAB),Y info TO work
0384 99 86 00         STA WORK,Y     area
0387 C8               INY            ..Four bytes
0388 C0 06            CPY #6
038A D0 F6            BNE LOOP1
038C A2 01            LDX #1         Connect file #1
038E 20 C6 FF         JSR CHKIN      ..as input.
0391 20 E4 FF LOOP2   JSR GETIN      Get character
0394 C9 0D            CMP #$0D       Return?
0396 F0 0B            BEQ QUIT       Yes, quit
0398 A4 8B            LDY COUNT      No, get pointer
039A 91 89            STA (STRING),Y ..and stash char
039C C8               INY            Count it
039D 84 8B            STA COUNT      Save count
039F C4 88            CPY LENGTH     Full string?
3A1  D0 EE            BNE LOOP2      Nope, do more
03A3 4C CC FF         JMP CLRCHN     Disconnect&quit

String Thing solves many file input problems: in particular, long data blocks and special characters become very simple. It's as fast as INPUT, but for most purposes it's better.

Copyright © 1982 Jim Butterfield