GWBasic Variables Pointer


VARPTR Statement


Remember the call statement? In order to pass variables to machine language routines, it was necessary to know where these variables are in memory so that the routine can use the value in the GWBasic variable and return information to GWBasic by changing the value of the variable.

The VARPTR function can also be used to examine the File Control Block of a disk file as well as the disk content on a track / sector level. Here is an example that demonstrates using VARPTR to directly examine a disk file's content by PEEKing into the File Control Block directly.




Read a sequential file


GWBasic has a number of statements that open a file control block for input and output of data. A file can be opened and displayed by executing an input and displaying the contents with a print statement. This is a tiny routine that will open a file for input and display the output, byte at a time until the first Control Z is detected. The Control Z byte with a value of 1A hexidecimal defines the end of file. The read function terminates when an End of File is detected.

Create a text file named  scrap.txt   and display it in ascii with the following program, one byte at a time. The program terminates when it sees the End Of File byte, the control Z or binary 1A.

10 OPEN "scrap.txt" FOR INPUT AS #1
20 PRINT INPUT$(1, #1);
30 IF INKEY$="" THEN 30
40 GOTO 20


Replace line 20 with the following line of code and read the file as binary one byte  at a time.

20   PRINT HEX$(ASC(INPUT$(1, #1)));

This works great for an ascii file. But a binary file just might contain a 1A byte. This will cause the program to terminate when it detects it.




The BASIC program demonstrating the VARPTR statement

This program permits opening a file and gaining access to the File Control Block that contains information needed to extract data from a file on the disk. VARPTR provides the location of these data, including the data buffer that contains the file data. These bytes can be read directly using the PEEK function, including any number of Control Zs. A file is opened, VARPTR provides the address of the File Control Block and these data are displayed. The data in the data buffer is dumped in the usual Dump format.

10 '                   prog   Varptr.bas
20 '
30 '
40 ' This program displays the File Control Block for a selected
50 '           Sequential Text file for analysis
60 '
70 '
80 '
90 '
100 '        program start
110 KEY OFF: COLOR 0,7: CLS
120 BASE=0: N=0: N%=0: N$="": A=0: A%=0: A$=""
130 INPUT " Enter Sequential Text File to OPEN FOR INPUT AS #1  >",FILE$
140 IF FILE$="" THEN FILE$="Scrap.txt": PRINT
150 '
160 OPEN FILE$ FOR INPUT AS #1
170 BASE= VARPTR(#1)
180 '
190 COLOR 0 : PRINT "                      File-Control Block"
200 COLOR 0 : PRINT "Base         Address ";
210 COLOR 14: PRINT BASE;"   "; RIGHT$("00"+HEX$(BASE),4)
220 '
230 COLOR 0 : PRINT "Base+ 0      Mode   Sequential Input only ";
240 COLOR 14: FOR N=0  TO  0 : PRINT PEEK(BASE+N): NEXT
250 '
260 N%= 0
270 COLOR 0:  PRINT "Base+ 01     FCB    Discette File Control Block data"
280 COLOR 14: FOR N=1  TO  38: PRINT RIGHT$("0"+HEX$(PEEK(BASE+N)),2);" ";
290    IF (N- N%) MOD(16)=0 THEN PRINT
300       NEXT
310         PRINT
320 '
330 COLOR 0:  PRINT "Base+ 39     CURLOC Number of Sectors ";
340 COLOR 14: FOR N=39 TO  40:PRINT RIGHT$("0"+HEX$(PEEK(BASE+N)),2);" ";:NEXT
350 PRINT
360 '
370 COLOR 0:  PRINT "Base+ 41     ORNOFS Number of bytes in Sectors ";
380 COLOR 14: FOR N=41 TO  41:PRINT RIGHT$("0"+HEX$(PEEK(BASE+N)),2);" ";:NEXT
390 PRINT
400 '
410 COLOR 0:  PRINT "Base+ 42     NMLOFS Number of bytes remaining in buffer ";
420 COLOR 14: FOR N=42 TO  42:PRINT RIGHT$("0"+HEX$(PEEK(BASE+N)),2);" ";:NEXT
430 PRINT
440 '
450 COLOR 0:  PRINT "Base+ 43     ***    reserved for future expansion ";
460 COLOR 14: FOR N=43 TO  45:PRINT RIGHT$("0"+HEX$(PEEK(BASE+N)),2);" ";:NEXT
470 PRINT
480 '
490 COLOR 0:  PRINT "Base+ 46     DEVICE Device number disk 0 through 9 ";
500 COLOR 14: FOR N=46 TO  46:PRINT RIGHT$("0"+HEX$(PEEK(BASE+N)),2);" ";:NEXT
510 PRINT
520 '
530 COLOR 0:  PRINT "Base+ 47     WIDTH  Device width ";
540 COLOR 14: FOR N=47 TO  47:PRINT RIGHT$("0"+HEX$(PEEK(BASE+N)),2);" ";:NEXT
550 PRINT
560 '
570 COLOR 0:  PRINT "Base+ 48     POS    Position in Buffer (print) ";
580 COLOR 14: FOR N=48 TO  48:PRINT RIGHT$("0"+HEX$(PEEK(BASE+N)),2);" ";:NEXT
590 PRINT
600 '
610 COLOR 0:  PRINT "Base+ 49     FLAGS  BLOAD-BSAVE internal use ";
620 COLOR 14: FOR N=49 TO  49:PRINT RIGHT$("0"+HEX$(PEEK(BASE+N)),2);" ";:NEXT
630 PRINT
640 '
650 COLOR 0:  PRINT "Base+ 50     OUTPOS Output Position during tab expansion ";
660 COLOR 14: FOR N=50 TO  50:PRINT RIGHT$("0"+HEX$(PEEK(BASE+N)),2);" ";:NEXT
670 PRINT
680 '
690   COLOR 0: PRINT " any keystroke to continue with file dump"
700       N$= INKEY$: IF N$= "" THEN 700  ' Wait here for any keystroke
710          CLS
720 '________________________ Dump a Record __________________________________
730 N%= 0: A$="": N$=""
740 COLOR 0:  PRINT "Base+ 51     BUFFER Physical data binary dump "
750 COLOR 14: FOR N=51 TO 178: A%= PEEK(BASE+N)
760 A$=A$+RIGHT$("0"+HEX$(A%),2)+" ": IF A%<32 OR A%>127 THEN A%=32
770 N$=N$+ CHR$(A%): N%=N%+1: IF N%=16 THEN PRINT A$" "N$: N%=0: A$="": N$=""
780       NEXT
790         PRINT
800 '
810 COLOR 0:  PRINT "Base+179     VRECL  Variable length record size ";
820 COLOR 14: FOR N=179 TO 180:PRINT RIGHT$("0"+HEX$(PEEK(BASE+N)),2);" ";:NEXT
830 PRINT
840 '
850 COLOR 0:  PRINT "Base+181     PHYREC  Current physical Record number ";
860 COLOR 14: FOR N=181 TO 182:PRINT RIGHT$("0"+HEX$(PEEK(BASE+N)),2);" ";:NEXT
870 PRINT
880 '
890 COLOR 0:  PRINT "Base+183     LOGREC  Current logical  Record number ";
900 COLOR 14: FOR N=183 TO 184:PRINT RIGHT$("0"+HEX$(PEEK(BASE+N)),2);" ";:NEXT
910 PRINT
920 '
930 COLOR 0:  PRINT "Base+185     ***     Future use ";
940 COLOR 14: FOR N=185 TO 185:PRINT RIGHT$("0"+HEX$(PEEK(BASE+N)),2);" ";:NEXT
950 PRINT
960 '
970 COLOR 0:  PRINT "Base+186     OUTPOS  Position for PRINT,INPUT, WRITE ";
980 COLOR 14: FOR N=186 TO 187:PRINT RIGHT$("0"+HEX$(PEEK(BASE+N)),2);" ";:NEXT
990 PRINT
1000 '
1010 COLOR 0:  PRINT "Base+188     FIELD   Actual Field Data Buffer ";
1020 COLOR 14: FOR N=188 TO 196:PRINT RIGHT$("0"+HEX$(PEEK(BASE+N)),2);" ";:NEXT
1030 PRINT
1040 '
1050 COLOR 0
1060 PRINT: END
1070 '
1080 '
1090 STOP: END   ' development handy backup statement
1100 SAVE"Varptr",A



All variables are assigned a value before the File is opened because assigning a variable changes all the variable locations. We don't want to change the locations in the File Control Block once we have called it.

The input file name is selectable and INPUT into variable FILE$. The default file name ( carriage return selected ) selects a file named SCRAP.TXT. The selected file is OPENed for Input as File  #1. This is followed by using VARPTR to return the location in memory for that File Control Block. This Base address is stored in variable BASE. This address is the offset from the GWBasic default segment and displayed.

The first data, one byte at FCB base plus zero is the mode the file was opened in. In this case it is sequential read only.
The next 38 bytes provide FCB information needed to locate the file on the disk.
Other data is displayed through offset 50 and the program is halted, awaiting any keystroke.

When the program resumes, 128 bytes of the FCB data buffer is output to the monitor in binary and ascii. PEEKing at the data bytes in this buffer space can display the data bytes in a binary (or ascii) file, including any Control Z bytes.

To verify this ability to read and display past the normal ascii End of File mark, a binary file can be made that contains as least one 1A byte. The Windows DEBUG program may easily be used to make such a file.



Create a Binary File

Its possible to output a binary file using the VARPTR statement, but there is no room for an error in the process. A typo or a program hick-up could very easily corrupt the disk. I prefer to use the old, tried and true, DEBUG.EXE program to do it. Its easy enough to do using COMMAND.COM with a Batch file. Simply copy this BAT stream into a file named SCRAP.BAT and double click on it. It will create a file named SCRAP.BIN. Then its only necessary to run the program named VARPTR.BAS and name SCRAP.BIN as the target file to dump.

The only big consideration is where will the new file be created. I do all my work in a single directory (folder) so that I don't have to go searching around the disk to find the file that I create. If I have a copy of COMMAND.COM, DEBUG.EXE, VARPTR.BAS and SCRAP.BAT, all in my working directory, then there is no such consideration because the output file will be created in the local working directory. To be more careful yet, use the A: drive as the working directory and edit all the file names in the programs to begin with the A: prefix. This degree of care is a matter of your discretion; however.

The disk file created with this BAT stream creates a 128 bit binary file whose byte value is located at its own location in the file. These data are all the ascii characters from 00 to 7F. Notice that the 26th byte is 1A, or Control Z. If this file were opened for input with GWBasic's OPEN statement then it would be treated as an ascii file and terminate at this byte's location because it would be recognized as the End Of File mark. Not only that, the only ascii characters recognized would be the internal bell (Control G), the line feed  0A, and the carriage return 0D. The form feed character would be recognized if the printer was selected as the output device .

debug < scrap.bat
e 0100 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
e 0110 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
e 0120 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
e 0130 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
e 0140 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
e 0150 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
e 0160 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f
e 0170 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f
n scrap.bin
rcx
0080

w
q




Summary


Link to the program and copy-paste it into a text file so you can run it with the GWBasic Interpreter.

Isn't it nice that all these programs are available in the set of programs that have been provided with the Window's system? It isn't even necessary to go out and purchase a bunch of applications to write programs using the Windows system.
Its all here. Its just a matter of becoming familiar with their operation.

In short.... play around and have fun.........  Happy Hacking......