Serial Files
Introduction
The section on serial files is split into three parts. The first deals with character data files. These are the simplest type of files to use and the examples are correspondingly short. The second part looks at mixed numeric/character data files. The final part describes conversion between BBC BASIC (Z80) format files and the file formats required/produced by other systems.
Character Data Files
The first three examples are programs to write data in character format to a serial file and to read the data back. All the data is in character format and, since the files will not be read by other versions of BASIC, no extra control characters have been added.
You may notice that we have cheated a little in that a procedure is called to close the files and end the program without returning. This saves using a GOTO, but leaves the return address on the stack. However, ending a program clears the stack and no harm is done. You should not use this sort of trick anywhere else in a program. If you do you will quickly use up memory.
Ex 1 - Writing Serial Character Data
10 REM F-WSER1
20 :
30 REM WRITING TO A SERIAL CHARACTER DATA FILE
40 :
50 REM This program opens a data file and writes
60 REM serial character data to it. The use of
70 REM OPENOUT ensures that, even if the file
80 REM existed before, it is cleared before
90 REM being written to.
100 :
110 phonenos=OPENOUT "PHONENOS"
120 PRINT "File Name PHONENOS Opened as Handle ";phonenos
130 PRINT
140 REPEAT
150 INPUT "Name ? " name$
160 IF name$="" THEN PROC_end
170 INPUT "Phone Number ? " phone$
180 PRINT
190 PRINT#phonenos,name$,phone$
200 UNTIL FALSE
210 :
220 DEF PROC_end
230 CLOSE#phonenos
240 END
Ex 2 - Reading Serial Character Data
10 REM F-RSER1
20 :
30 REM EXAMPLE OF READING A SERIAL CHARACTER FILE
40 :
50 REM This program opens a previously written
60 REM serial file and reads it.
70 :
80 :
90 phonenos=OPENIN "PHONENOS"
100 PRINT "File Name PHONENOS Opened as Handle ";phonenos
110 PRINT
120 REPEAT
130 INPUT#phonenos,name$,phone$
140 PRINT name$,phone$
150 UNTIL EOF#phonenos
160 :
170 CLOSE#phonenos
180 END
Ex 3 - Writing 'AT END' of Character Files
The next example extends the write program from Example 1. This new program opens the file, sets PTR# to the end (line 380) and then adds data to it. A procedure is used to open the file. This has the advantage of making the program more understandable by putting the detailed 'open at end' coding out of the main flow of the program.
10 REM F-WESER1
20 :
30 REM EXAMPLE OF WRITING TO THE END OF A SERIAL DATA FILE
40 :
50 REM The program opens a file and sets PTR
60 REM to the end before writing data to it.
70 :
80 REM A function is used to open the file.
90 :
100 :
110 phonenos=FN_openend("PHONENOS")
120 PRINT "File Name PHONENOS Opened as Handle ";phonenos
130 PRINT
140 REPEAT
150 INPUT "Name ? " name$
160 IF name$="" THEN PROC_end
170 INPUT "Phone Number ? " phone$
180 PRINT
190 PRINT#phonenos,name$,phone$
200 UNTIL FALSE
210 :
220 DEF PROC_end
230 CLOSE#phonenos
240 END
250 :
260 :
270 REM Open the file 'AT END'.
280 :
290 REM If the file does not already exist, it
300 REM is created with OPENOUT. PTR# is left
310 REM at zero and the handle is returned. If
320 REM the file exists, PTR# is set to the end
330 REM and the file handle returned.
340 DEF FN_openend(name$)
350 LOCAL fnum
360 fnum=OPENUP(name$)
370 IF fnum=0 THEN fnum=OPENOUT(name$): =fnum
380 PTR#fnum=EXT#fnum
390 =fnum
Mixed Numeric/Character Data Files
The second three examples are also programs which write data to a file and read it back, but this time the data is mixed. They are simply extensions of the previous examples which illustrate the handling of mixed data.
Ex 4 - Writing a Mixed Data File
10 REM F-WSER2
20 :
30 REM EXAMPLE OF WRITING TO A MIXED NUMERIC/CHAR DATA FILE
40 :
50 REM This program opens a file and writes
60 REM numeric and char data to it. The use
70 REM of OPENOUT ensures that, even if the
80 REM file exists, it is cleared before
90 REM being written to. Functions
100 REM are used to accept and validate
110 REM the data before writing it to the file.
120 :
130 :
140 stats=OPENOUT("STATS")
150 PRINT "File Name STATS Opened as Handle ";stats
160 PRINT
170 REPEAT
180 name$=FN_name
190 IF name$="" THEN PROC_end
200 age=FN_age
210 height=FN_height
220 sex$=FN_sex
230 PRINT
240 PRINT#stats,name$,age,height,sex$
250 UNTIL FALSE
260 :
270 DEF PROC_end
280 PRINT "The file is ";EXT#stats;" bytes long"
290 CLOSE#stats
300 END
310 :
320 :
330 REM Accept a name from the keyboard and make
340 REM sure it consists only of spaces and
350 REM upper or lower case characters. Leading
360 REM spaces are ignored on input.
370 :
380 DEF FN_name
390 LOCAL name$,FLAG,n
400 REPEAT
410 FLAG=TRUE
420 INPUT "Name ? " name$
430 IF name$="" THEN 490
440 FOR I=1 TO LEN(name$)
450 n=ASC(MID$(name$,I,1))
460 IF NOT(n=32 OR n>64 AND n<91 OR n>96 AND n<123) THEN FLAG=FALSE
470 NEXT
480 IF NOT FLAG THEN PRINT "No funny characters please !!!"
490 UNTIL FLAG
500 =name$
510 :
520 :
530 REM Accept the age from the keyboard and
540 REM round to one place of decimals. Ages
550 REM of 0 or less, or 150 or more are
560 REM considere dto be in error.
570 DEF FN_age
580 LOCAL age
590 REPEAT
600 INPUT "What age ? " age
610 IF age<=0 OR age >=150 THEN PRINT "No impossible ages please !!!"
620 UNTIL age>0 AND age<150
630 =INT(age*10+.5)/10
640 :
650 :
660 REM Accept the height in centimetres from
670 REM the keyboard and round to an integer.
680 REM Heights of 50 or less and 230 or more
690 REM are considered to be in error.
700 DEF FN_height
710 LOCAL height
720 REPEAT
730 INPUT "Height in centimetres ? " height
740 IF height<=50 OR height>=230 THEN PRINT "Very funny !!!"
750 UNTIL height>50 AND height<230
760 =INT(height+.5)
770 :
780 :
790 REM Accept the sex from the keyboard. Only
800 REM words beginning with upper or lower case
810 REM M or F are OK. The returned string is
820 REM truncated to 1 character.
830 DEF FN_sex
840 LOCAL sex$,FLAG
850 REPEAT
860 FLAG=TRUE
870 INPUT "Male or Female - M or F ? " sex$
880 IF sex$<>"" THEN sex$=CHR$(ASC(MID$(sex$,1,1)) AND 95)
890 IF sex$<>"M" AND sex$<>"F" THEN FLAG=FALSE
900 IF NOT FLAG THEN PRINT "No more sex(es) please !!!"
910 UNTIL FLAG
920 =sex$
Ex 5 - Reading a Mixed Data File
10 REM F-RSER2
20 :
30 REM EXAMPLE OF READING FROM A MIXED NUMERIC/CHAR DATA FILE
40 :
50 REM This program opens a file and reads
60 REM numeric and character data from it.
70 :
80 :
90 stats=OPENIN("STATS")
100 PRINT "File Name STATS Opened as Handle ";stats
110 PRINT
120 REPEAT
130 INPUT#stats,name$,age,height,sex$
140 PRINT "Name ";name$
150 PRINT "Age ";age
160 PRINT "Height in centimetres ";height
170 IF sex$="M" THEN PRINT "Male" ELSE PRINT "Female"
180 PRINT
190 UNTIL EOF#stats
200 :
210 CLOSE#stats
220 END
Ex 6 - Writing 'AT END' of Mixed Files
This example is similar to Example 3, but for a mixed data file.
10 REM F-WESER2
20 :
30 REM EXAMPLE OF WRITING AT THE END OF A
40 REM MIXED NUMERIC/CHAR DATA FILE
50 :
60 REM This program opens a file, sets PTR
70 REM to its end and then writes numeric and
80 REM character data to it.
90 :
100 REM Functions are used to accept and
110 REM validate the data before writing it to
120 REM the file.
130 :
140 stats=FN_open("STATS")
150 PRINT "File Name STATS Opened as Handle ";stats
160 PRINT
170 REPEAT
180 name$=FN_name
190 IF name$="" THEN PROC_end
200 age=FN_age
210 height=FN_height
220 sex$=FN_sex
230 PRINT
240 PRINT#stats,name$,age,height,sex$
250 UNTIL FALSE
260 :
270 DEF PROC_end
280 PRINT "The file is ";EXT#stats;" bytes long"
290 CLOSE#stats
300 END
310 :
320 :
330 REM Open the file. If it exists, set PTR#
340 REM to vthe end and return the handle. If
350 REM it does not exist, open it, leave PTR#
360 REM as it is and return the file handle.
370 DEF FN_open(name$)
380 LOCAL fnum
390 fnum=OPENUP(name$)
400 IF fnum=0 THEN fnum=OPENOUT(name$): =fnum
410 PTR#fnum=EXT#fnum
420 =fnum
430 :
440 :
450 REM Accept a name from the keyboard and make
460 REM sure it consists of spaces and upper or
470 REM lower case characters. Leading spaces
480 REM are automatically ignored on input.
490 DEF FN_name
500 LOCAL name$,FLAG,n
510 REPEAT
520 FLAG=TRUE
530 INPUT "Name ? " name$
540 IF name$="" THEN 600
550 FOR I=1 TO LEN(name$)
560 n=ASC(MID$(name$,I,1))
570 IF NOT(n=32 OR n>64 AND n<91 OR n>96 AND n<123) THEN FLAG=FALSE
580 NEXT
590 IF NOT FLAG THEN PRINT "No funny characters please !!!"
600 UNTIL FLAG
610 =name$
620 :
630 :
640 REM Accept the age from the keyboard and
650 REM round to one place of decimals. Ages of
660 REM 0 or less or 150 or more are in error.
670 :
680 DEF FN_age
690 LOCAL age
700 REPEAT
710 INPUT "What age ? " age
720 IF age<=0 OR age >=150 THEN PRINT "No impossible ages please !!!"
730 UNTIL age>0 AND age<150
740 =INT(age*10+.5)/10
750 :
760 :
770 REM Accept the height in centimetres from
780 REM the keyboard and round to an integer.
790 REM Heights of 50 or less or 230 or more
800 REM are in error.
810 DEF FN_height
820 LOCAL height
830 REPEAT
840 INPUT "Height in centimetres ? " height
850 IF height<=50 OR height>=230 THEN PRINT "Very funny !!!"
860 UNTIL height>50 AND height<230
870 =INT(height+.5)
880 :
890 :
900 REM Accept the sex from the keyboard. Only
910 REM words beginning with upper or lower
920 REM case M or F are valid. The returned
930 REM string is truncated to 1 character.
940 DEF FN_sex
950 LOCAL sex$,FLAG
960 REPEAT
970 FLAG=TRUE
980 INPUT "Male or Female - M or F ? " sex$
990 IF sex$<>"" THEN sex$=CHR$(ASC(MID$(sex$,1,1)) AND 95)
1000 IF sex$<>"M" AND sex$<>"F" THEN FLAG=FALSE
1010 IF NOT FLAG THEN PRINT "No more sex(es) please !!!"
1020 UNTIL FLAG
1030 =sex$
Compatible Data Files
The next example tackles the problem of writing files which will be compatible with other versions of BASIC. The most common format for serial files is as follows:
-
Data is written to the file as ASCII characters.
-
Data items are separated by commas.
-
Records are terminated by the two characters CR and LF.
-
The file is terminated by a Control Z (&1A).
The example program accepts data from the keyboard and writes it to a file in the above format.
Ex 7 - Writing a Compatible Data File
10 REM F-WSTD
20 :
30 REM EXAMPLE OF WRITING A COMPATIBLE FILE
40 :
50 REM This program opens a file and writes
60 REM numeric and character data to it in a
70 REM compatible format. Numerics are changed
80 REM to strings before they are written and
90 REM the data items are separated by commas.
100 REM Each record is terminated by CR LF and
110 REM the file is terminated by a Control Z.
120 :
130 REM Functions are used to accept and
140 REM validate the data before writing it to
150 REM the file.
160 :
170 record$=STRING$(100," "): REM Reserve room for the longest
180 name$=STRING$(20," "): REM record necessary.
190 : REM It saves on string space.
200 compat=OPENOUT("COMPAT")
210 PRINT "File Name COMPAT Opened as Handle ";compat
220 PRINT
230 REPEAT
240 name$=FN_name
250 IF name$="" THEN PROC_end
260 age=FN_age
270 height=FN_height
280 sex$=FN_sex
290 PRINT
300 record$=name$+","+STR$(age)+","+STR$(height)+","+sex$
310 PRINT#compat,record$
320 BPUT#compat,&0A
330 UNTIL FALSE
340 :
350 DEF PROC_end
360 BPUT#compat,&1A
370 CLOSE#compat
380 END
390 :
400 :
410 REM Accept a name from the keyboard and make
420 REM sure it consists only of spaces and
430 REM upper or lower case characters. Leading
440 REM spaces are ignored on input.
450 :
460 DEF FN_name
470 LOCAL name$,FLAG,n
480 REPEAT
490 FLAG=TRUE
500 INPUT "Name ? " name$
510 IF name$="" THEN 570
520 FOR I=1 TO LEN(name$)
530 n=ASC(MID$(name$,I,1))
540 IF NOT(n=32 OR n>64 AND n<91 OR n>96 AND n<123) THEN FLAG=TRUE
550 NEXT
560 IF NOT FLAG THEN PRINT "No funny characters please !!!"
570 UNTIL FLAG
580 =name$
590 :
600 :
610 REM Accept the age from the keyboard and
620 REM round to one place of decimals. Ages
630 REM of 0 or less or 150 or more are
640 REM considered to be in error.
650 DEF FN_age
660 LOCAL age
670 REPEAT
680 INPUT "What age ? " age
690 IF age<=0 OR age >=150 THEN PRINT "No impossible ages please !!!"
700 UNTIL age>0 AND age<150
710 =INT(age*10+.5)/10
720 :
730 :
740 REM Accept the height in centimetres from
750 REM the keyboard and round to an integer.
760 REM Heights of 50 or less and 230 or more
770 REM are considered to be in error.
780 DEF FN_height
790 LOCAL height
800 REPEAT
810 INPUT "Height in centimetres ? " height
820 IF height<=50 OR height>=230 THEN PRINT "Very funny !!!"
830 UNTIL height>50 AND height<230
840 =INT(height+.5)
850 :
860 :
870 REM Accept the sex from the keyboard. Only
880 REM words beginning with upper or lower
890 REM case M or F are valid. The returned
900 REM string is truncated to 1 character.
910 DEF FN_sex
920 LOCAL sex$,FLAG
930 REPEAT
940 FLAG=TRUE
950 INPUT "Male or Female - M or F ? " sex$
960 IF sex$<>"" THEN sex$=CHR$(ASC(MID$(sex$,1,1)) AND 95)
970 IF sex$<>"M" AND sex$<>"F" THEN FLAG=FALSE
980 IF NOT FLAG THEN PRINT "No more sex(es) please !!!"
990 UNTIL FLAG
1000 =sex$
Ex 8 - Reading a Compatible Data File
The last example in this section reads a file written in the above format and strips off the extraneous characters. The file is read character by character and the appropriate action taken. This is a simple example of how BBC BASIC (Z80) can be used to manipulate any CP/M-80 file by processing it on a character by character basis.
10 REM F-RSTD
20 :
30 REM EXAMPLE OF READING A COMPATIBLE FILE
40 :
50 REM This program opens a data file and reads
60 REM numeric and character data from it. The
70 REM data is read a byte at a time and the
80 REM appropriate action taken depending on
90 REM whether it is a character, a comma, or
100 REM a control char.
110 compat=OPENUP("COMPAT")
120 PRINT "File Name COMPAT Opened as Handle ";compat
130 PRINT
140 REPEAT
150 name$=FN_read
160 PRINT "Name ";name$
170 age=VAL(FN_read)
180 PRINT "Age ";age
190 height=VAL(FN_read)
200 PRINT "Height in centimetres ";height
210 sex$=FN_read
220 IF sex$="M" THEN PRINT "Male" ELSE PRINT "Female"
230 PRINT
240 UNTIL FALSE
250 :
260 :
270 REM Read a data item from the file. Treat
280 REM commas and CRs as data item terminators
290 REM and Control Z as the file terminator.
300 REM Since we are not interested in reading a
310 REM record at a time, the record terminator
320 REM CR LF is of no special interest to us.
330 REM We use the CR, along with commas, as a
332 REM data item separator and discard the LF.
334 :
340 DEF FN_read
350 LOCAL data$,byte$,byte
360 data$=""
370 REPEAT
380 byte=BGET#compat
390 IF byte=&1A OR EOF#compat THEN CLOSE#compat: END
400 IF NOT(byte=&0A OR byte=&0D OR byte=&2C) THEN data$=data$+CHR$(byte)
410 UNTIL byte=&0D OR byte=&2C
420 =data$