Table 5-5 Continued 8E28: 00 C4 100 IHVECT4 DA $C400 0E2A: EE 9A 101 INVECT5 DA N0DEVERR BE2C: 00 C6 102 INVECT6 DA $C600 BE2E: EE 9A 103 INVECT7 DA N0DEYERR 104 ;(Assume mouse card) ;(Assume 5.25-inch drive) 105 *********************************************** 106 The BASIC.SYSTEM 1/0 links are stored here. 107 These are the addresses control will pass 108 to if the input or output is not handled 109 internally. 110 *********************************************** 8E30: 07 C3 111 VECT0UT DA C0UT80 ProDOS output link BE32: 05 C3 112 VECTIN DA KEYIN80 ProDOS input link 113 114 Miscellaneous internal BASIC.SYSTEM parameters: 115 BE34: Fl 87 116 VD0SI0 DA D0S0UT ;Character out intercept 8E36: F4 87 117 DA D0SIN ;Character in intercept 118 8E38: 2F 9A 119 VSYSI0 DA SYS0UT Internal output subroutine 8E3A: 8A 9A 120 DA SYSIN ;Internal input subroutine 121 8E3C: 06 122 DEFSLT DF8 6 ;Default slot # 8E3D: 01 123 DEFDRV DF8 1 Default drive # 124 8E3E: 00 125 PREGA DF8 0 ;Temporary storage for A 8E3F: 00 126 PREGX DF8 0 Temporary storage for X 8E40: 00 127 PREGY DF8 0 ;Temporary storage for Y 128 8E41: 00 129 DTRACE DFB 0 ;bit 7=1 ==> Applesoft trace on 130 8E42: 00 131 STATE DF8 0 ;0=direct. ~0=in program 8E43: 00 132 EXACTV DF8 0 ;bit 7=1 ==> EXEC file open 8E44: 00 133 IFILACTV DF8 0 bit 7=1 ==> input file active 8E45: 00 134 0FILACTV DF8 0 ;bit 7=1 ==> output file active 8E46: 00 135 PFXACTV DF8 0 8E47: 00 136 DIRFLG DF8 0 8E48: 00 137 EDIRFLG DF8 0 8E49: 00 138 STRINGS DF8 0 8E4A: 00 139 T8UFPTR DF8 0 8E48: 00 140 INPTR DF8 0 8E4C: 00 141 CHRLAST DF8 0 8E4D: 00 142 0PENCNT DF8 0 8E4E: 00 143 EXFILE DF8 0 8E4F: 00 144 CATFLAG DF8 0 145 ;bit 7=1 ==> prefix input active ;bit 7=1 ==> dir. file active ;bit 7=1 ==> end of directory ;Counter for free space calc. Character count for WRITE ;Char. count for kbd input Last character printed ;Number of open files (not EXEC) ;EXEC file close flag Directory input flag 146 **************************~************************ 147 The following three locations will be used if 148 you are adding user commands to 8ASIC.SYSTEM. The BASIC. SYSTEM Global Page: $BEO~$BEFF 243 Table 5-5 Continued BE50: 00 00 150 XTRNADDR DA 0 ;Address of user command handler BE52: 00 151 XLEN DFB BE53: 00 152 XCNUM DFB 153 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 8E54: 00 OO 184 PBITS DW 0 154 0 ;Length of user command - 1 0 ;Command number in use (O=user) * Notes on PBITS and FBITS: * Once BASIC.SYSTEM has identified a valid command, * it stores a number in PBITS and PBITS*l that * reflects the syntax of the command. It then calls * the command parser, which updates FBITS and * FBITS+l to reflect the parameters actually found. * Meaning of bits in PBITS/FBITS: * bit 7 fetch prefix if pathname not specified * bit 6 slot number required/found * bit 5 command NOT valid in direct mode * bit 4 pathname is optional (no names+parms) * bit 3 create file if it doesn't exist * bit 2 file type optional (T parameter)/found * bit 1 second pathname required (for RENAME)/found * bit 0 filename allowed/found * Meaning of bits in PBITS~l/FBITS+l: * bit 7 A parameter allowed/found * bit 6 8 parameter allowed/found * bit 5 E parameter allowed/found * bit 4 L parameter allowed/found * bit 3 parameter allowed/found * bit 2 S/D parameters allowed/found * bit 1 F parameter allowed/found * bit 0 R parameter allowed/found 0000 185 FBITS DW 0 186 ;Permitted parameter bits BE56: ;Found parameter bits 188 189 190 191 192 8E58: 00 00 193 BE5A: 00 00 00 194 8E5D: 00 00 195 8E5F: 00 00 196 8E61: 00 197 187 *****************~**~*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * The following table is where command parameters * are stored during a parsing operation. The * entries for unspecified parameters are not * changed. APARM DA 0 A (address) parameter BPARM DS 3 8 (byte #) parameter EPARM DA 0 ;E (end addr) parameter LPARM DW 0 ;L (length) parameter SPARM DF8 0 5 (slot) parameter 244 System Programs Table 5-5 Continued BE62: DO 198 DPARM DFB 0 BE63: 00 00 199 FPARM DW 0 BE65: 00 00 200 RPARM DW 0 BE67: 00 201 VPARM DFB 0 BE68: DO 00 202 QPARM DW 0 BE6A: 00 203 TPARM DFB 0 BE6B: 00 204 SLPARM DFB 0 BE6C: BC BC 205 PATHl DA TXBUF-l 8E6E: 80 02 206 PATH2 DA TXBUF2 207 ;D (drive) parameter ;F (field #) parameter ;R (record #) parameter ;V (volume #) parameter (line #) parameter ;T (file type code) parameter ;slot (for IN#, PR#) parameter ;Pointer to first pathname ;Pointer to second pathname 208 ***************************************************** 209 All BASIC.SYSTEM MLI calls are routed to GOSYSTEM 210 * with the command number in the accumulator. 211 Prior to calling GOSYSTEM. BASIC.SYSTEM 212 sets up the appropriate parameter table in the 213 global page as required by the call. GOSYSTEM 214 handles all MLI calls from $CO..$D3 inclusive. If 215 an error occurs. an Applesoft error code is 216 returned in A with the carry flag set. 217 **************~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BE70: 8D 85 BE 218 GOSYSTEM STA SYSCALL Save MLI command number BE73: 8E A8 BC 219 STX CALLX Save X register BE76: 29 IF 220 AND #$lF ;# mod 32 BE78: AA 221 TAX BE79: BD 05 B8 222 LDA SYSCTBL.X ;Get address of parm table BE7C: 8D 86 BE 223 STA SYSPARM (low) and save it BE7F: AE A8 BC 224 LDX CALLX Restore X BE82: 20 00 BF 225 JSR MLI ;Do the MLI call BE85: 00 226 SYSCALL DFB 0 ;MLI command # stored here BE86: 00 227 SYSPARM DFB 0 ;Address of parm table (low) BE87: BE 228 DFB $BE High address always $BE BE88: BO 01 229 BCS BADCALL ;Branch if error BE8A: 60 230 RTS 231 232 *******~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 233 The BADCALL subroutine converts the MLI 234 error code to a corresponding Applesoft 235 error code. 236 *******~~*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BE8B: A2 12 237 BADCALL LDX #$12 BE8D: DD EE B9 238 MLIERRl CMP MLIERTBL,X ;Is it a "known" MLI error? BE90: FO 05 239 BEQ MLIERR2 Yes. so branch BE92: CA 240 DEX ;Check all 19 possibilities BE93: 10 F8 241 BPL MLIERRl BE95: A2 13 242 LDX #$13 ;Not known, so "1/0 error" 243 BE97: BD 01 BA 244 MLIERR2 LDA BIERRTBL,X ;Convert to Applesoft error code BE9A: AE A8 BC 245 BE9D: 38 246 LDX CALLX ;Restore X SEC ;==> error The BASIC. SYSTEM Global Page: $BEO~$BEFF 245 Table 5-5 Continued BE9F: 00 248 DFB $00 ;Unused byte 249 250 *************~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 251 The parameter tables for each of the MLI functions 252 supported by BASIC.SYSTEM follow. These tables 253 * must be filled in before calling GOSYSTEM. 254 ****************~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 255 Parm table for CREATE: BEAD: 07 256 DFB $07 BEAl: BC BC 257 DA TXBUF-l BEA3: C3 258 DFB $C3 BEA4: 00 259 DFB 0 BEA5: 00 00 260 DW $0000 BEA7: 00 261 DFB 0 BEA8: 00 00 262 DW 0 BEAA: 00 00 263 DW 0 264 265 Parm table for DESTROY BEAC: 01 266 DFB $01 BEAD: BC BC 267 DA TXBUF-l 268 269 Parm table for RENAME: BEAF: 02 270 DFB $02 BEB0: BC BC 271 DA TXBUF-1 BEB2: 80 02 272 DA TXBUF2 273 ;Number of parameters ;Pathname pointer Access code ;File type code ;Auxiliary type code Storage type code (usually 1) ;Create date ;Create time SET_PREFIX. GET_PREFIX: ;Number of parameters ;Pathname pointer Number of parameters Old pathname pointer ;New pathname pointer 274 Parm table for SET_FILE_INFO and GET_FILE_INFO: BEB4: 00 275 DFB $00 ;=7 (SFI) or 10 (GFI) BEB5: BC BC 276 0A TXBUF-lz ;Pathname pointer BEB7: 00 277 DFB $00 ;Access code BEB8: 00 278 DFB $00 ;File type code BEB9: 00 00 279 OW $0000 ;Auxiliary type code BEBB: 00 280 DFB $00 Storage type code (GFI only) BEBC: 00 00 281 DW $0000 ;Blocks used (GFI only) BEBE: 00 00 282 DW $0000 ;Modification date BEC0: 00 00 283 DW $0000 Modification time BEC2: 00 00 284 DW $0000 ;Create date (GFI only) BEC4: 00 00 285 DW $0000 ;Create time (GFI only) 286 287 Parm table for ON_LINE, SET_MARK, GET_MARK. 288 SET_E0F,GET_E0F.SET_BUF,GET_BUF: BEC6: 02 289 DFB $02 Number of parameters BEC7: 00 290 DFB $00 ;Unit or reference number BEC8: 00 291 DFB $00 ;2-byte pointer to data buffer BEC9: 00 292 DFB $00 (BUF, ON_LINE), or 3-byte BECA: 00 293 DF8 $00 position (MARK, E0F) 294 295 Parm table for OPEN: 246 System Programs Table 5-5 Continued BECB: 03 296 DFB $03 BECC: BC BC 297 DA TXBUF-l BECE: OO 00 298 DA $0000 BEDO: DO 299 DFB O 300 301 Parm table for NEWLINE BEDl: 03 302 DFB $03 BED2: DO 303 DFB 0 BED3: 7F 304 DFB $7F BED4: OD 305 DFB $OD 306 Number of parameters ;Pathname pointer ;Buffer pointer (lK) ;Reference number Number of parameters ;Reference number ;Ignore state of high bit ;Newline is $OD or $8D 307 Parm table for READ and WRITE: BEDS: 04 308 DFB $04 Number of parameters BED6: 00 309 DFB $00 Reference number BED7: 00 00 310 DA $0000 ;Buffer pointer BED9: 00 00 311 DW $0000 ;Number of bytes to read/write BEDB: 00 00 312 DW $0000 Actual number read/written 313 314 * Parm table for CLOSE and FLUSH: BEDD: 01 315 DFB $01 ;Number of parameters BEDE: 00 316 DFB 0 ;Reference number 317 BEDF: 00 318 DFB 0 ;Unused byte 319 BEEO: C3 CF DD 320 ASC "COPYRIGHT APPLE, 1983" BEE3: D9 D2 C9 C7 C8 D4 AD Cl BEEB: DO DO CC C5 AC AD Bl B9 BEF3: B8 B3 321 322 ***************************************************** 323 * Call GETBUFR to free up "A" pages above HIMEM. If 324 * the carry flag is set upon exit, there was not 325 enough memory to do so; otherwise, "A" will 326 * contain the number of the first page of the 327 buffer. Call FREEBUFR to remove the buffer, and 328 restore HIMEM to its bootup value (that value is 329 * stored at PAGETOP). 330 ***************************************************** BEF5: 4C B5 A2 331 GETBUFR JMP BEF8: 4C 01 A3 332 FREEBUFR JMP BEFB: 96 333 PAGET0P DFB 334 BEFC: 00 DO 00 335 DS BEFF: 00 PAGEGET ;Reserve "A" pages above HIMEM PAGEFREE ;Restore original HIMEM $96 ;HIMEM page on boot 4 ;Unused bytes The BASIC. SYSTEM Global Page: $BEO~$BEFF 247 Important; When using GOSYSTEM, be careful not to disturb the values of parameter table entries that BASIC.SYSTEM sets up as constants. These parar z The pathname pointers in all parameter lists z The time and date entries at ~BEAA-$BEAB and ~BEA8-~BEA9 in CREATE parameter list (they should both be zero) z The "newline character" entry' at ~BED4 in the NEWLINE parameter should always be $OD) If you want to temporarily change any of these parameters, save their values first, restore them after the GOSYSTEM call. In the following section we discuss some of the other important areas of BASIC.SYSTEM global page. BASIC.SYSTEM ERROR HANDLING If a call to GOSYSTEM results in a system error, G0SYSTEM branches to CALL ($BE8B), a subroutine that converts the MLI error code in the into a BASIC.SYSTEM (Applesoft) error code. Table 5-6 shows the - between a given MLI code and a BASIC.SYSTEM code. Note that only 19 MLI error codes are specifically dealt with by BADCALL automatically converts all others to error code 8 ("1/0 Error"). Moreover, four B' SYSTEM error codes do not correspond to any MLI error code at all; these codes are generated by illegal conditions within BASIC.SYSTEM itself- such as - attempt to load a program that is too large. After BASIC.SYSTEM converts the MLI error code, it calls ERR0UT (~BE~ handle the error. This subroutine first stores the error code in ERRC0DE and at $DE (the Applesoft interpreter expects to find an error code at $DE) and checks if the Applesoft 0NERR G0T0 error-trapping feature is active. If it is,: passes to the internal Applesoft error-handling subroutine. If it isn't, BASIC. _ calls PRINTERR ($BEOC) to print the error message corresponding to the error (see Table 5-6). If you are writing an assembly-language program that operates in an - BASIC.SYSTEM environment, you can call ERB0UT or PRINTERR to handle rors. But you must ensure that you call these subroutines with a BASIC.SYST: (Applesoft) error code, rather than an M LI error code, in the accumulator. You execute a JSR BADCALL instruction (with the error code in the accumulator) perform the necessary error code conversion. EXECUTING DISK COMMAND STRINGS FROM ASSEMBLY LANGUAGE An assembly-language program can use the D0SCMD ($BE03) subroutine in BASIC.SYSTEM global page to interpret and execute a standard BASIC.SYSTE~ 248 System Programs Table 5-6 BASIC.SYSTEM error codes and messages BASIC. SYSTEM Error Code MLI Error Code $00 $00 $02 $4D $03 $28 $04 $2B $05 $4C $06 $45,$44 $07 $46 $08 [all others] $09 $48 $0A $4E $0B $53 $0C $56,$42,$41 $0D $4B $0E $0F $10 $40 $11 $49 $12 $43 $13 $47 $14 $50 $15 $16 BASIC. SYSTEM Error Message [no error occurred] RANGE ERROR NO DEVICE CONNECTED WRITE PROTECTED END OF DATA PATH NOT FOUND PATH NOT FOUND 1/0 ERROR DISK FULL FILE LOCKED INVALID PARAMETER NO BUFFERS AVAILABLE FILE '1'YPE MISMATCH PROGRAM TOO LARGE NOT DIRECT COMMAND SYNTAX ERROR DIRECTORY FULL FILE NOT OPEN DUPLICATE FILE NAME FILE BUSY FILE(S) STILL OPEN DIRECT COMMAND disk command stored in the Apple input buffer at $200 as an ASCII string followed by a carriage return code ($8D). DOSCMD is effective only when an Applesoft program is actually running, so an Applesoft program must use the CALL command to access the assembly-language program. Executing Disk Command Strings from Assembly language 249 (Under DOS 3.3, assembly-language programs can execute disk sending code $04 (Control-D) to the standard character output subro'itine, ($FDED), followed by the ASCII codes for the command and a carriage return BASIC.SYSTEM does not support this technic~ue.) DOSCMD can execute most, but not all, BASIC.SYSTEM disk commands it does not handle properly are - (dash), RUN, LOAD, CHAIN, WRITE, APPEND, and EXEC. When you call DOSCMD to execute a can handle, it returns a BASIC.SYSTEM error code in the accumulator. If no occurred, the code is 0, and the carry flag is clear. If an error did occur, the is set. Handle an error condition by calling ERROUT ($BE09) or PRI. ($BE0C) (as described in the previous section) or by passing control to your error-handling code. Important: Just before a program using DOSCMD ends, it must clear the carry' and execute a CLC instruction. If it ends with the carry flag set, the program that called it may not work properly. ADDING COMMANDS TO BASIC.SYSTEM One of the best features of BASIC.SYSTEM is its support of user-defined commands. To see how to extend BASIC.SYSTEM's standard command set, let's '- look at exactly what happens when BASIC. SYSTEM encounters a string of charactert may represent a valid command. Figure 5-2 shows a flowchart of this procedure. The first thing BASIC.SYSTEM does is check if one of its 32 standard has been specified (CATALOG, OPEN, WRITE, and so on). If one has been, handles it internally. But if the command can't be identified, BASIC.SYSTEM does not immediately, an error code; rather, it calls a subroutine in its global page, EXTRNCMD ($BE06), to if a user-installed external command handler will claim the command. (The address is always stored at $BE07 and $BE08.) If no external command handler has installed, EXTRNCMD simply jumps to a "do-nothing" RTS instruction at XRETU ($BE9E). If the external command handler does not claim the command, and if command was issued from within a program, a BASIC.SYSTEM syntax error occurs. If on the other hand, the command was entered in Applesofi command mode, it passed on for consideration by the Applesofi interpreter. Only if the interpreter does recognize it does an Applesofi syntax error occur. Let's assume an external command handler has been installed so that a call EXTRNCMD will pass control to it. Such a handler first executes a CLD instruction, which Apple says it will use as an identification byte in future versions of BASIC.SYS- TEM. The handler then determines whether its command has, in fact, been entered; it can do this by checking if the first few characters in the command line match the expected command string. (The command line is stored in the Apple's standard input 250 System Programs Figure 5-2 A flowchart showing how BASIC. SYSTEM executes external commands XLEN = $BE52 XCNUM = $BE53 PBI'T'S = $BE54 XTRNADDR = $BE5O/$BE51 JMP (x'T'RNADDR) External command syntax No code ok? ~ call e::ternaI command handler Adding Commands to BASIC. SYSTEM 251 buffer beginning at $200 in ASCII form with the high bit of each code set to 1.) If don't match, the subroutine must end with the carry flag set to indicate that it did claim the command. If the handler detects the correct command, the handler can do one of two It can proceed to parse any expected parameters (such as a pathname, one of the BASIC.SYSTEM letter parameters, or special parameters defined by the c~-- itself) from the command line and then actually execute the command. Alt: all the possible parameters are capable of being recognized by BASIC.SYSTEM, handler can ask BASIC.SYSTEM to do the parsing and syntax checking; the' does this by setting certain bits in PBITS ($BE54) and PBITS + 1 ($BE55) to the required command syntax. If BASIC.SYSTEM does the parsing and it detect:: error, BASIC.SYSTEM handles the error itself. Table 5-1 shows the command parameters supported by BASIC.SYSTEM and the range of values that they can take - With three exceptions, each bit in PBITS and PBITS + 1 is a flag indic whether the particular parameter associated with that bit is required or allowed. exceptions are bits that indicate particular characteristics of the command: 'v,'hotko prefix must be fetched for it, whether it is valid in Applesoft command mode, whether a file that is specified should be created if it doesn't already exist. meaning of each bit is as follows: PBITS ($8E54) bit 7 Fetch the current prefix if a pathname is not specified. The command line cannot contain a pathname and a set of parameters unless bit 0 of PBITS is also set to 1. bit 6 A slot number is required (for example, IN#, PR,'). bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 The slot number must be the first parameter after the command name, and no pathnames can appear on the command line (so bit 0 and bit 1 of PBITS must both be 0). The command is not valid in command mode. A pathname is optional. Pathnames and parameters cannot be specified on the same command line. Create a file if the one specified does not exist. The file type parameter is allowed (T parameter). The T parameter can be a number or a three- character file type mnemonic corresponding to a file type code (see Table 2-4 in Chapter 2). For example, ,TDIR selects the file type code for a DIR file ($OF). A second pathname is required (for example, RENAME). Two pathnames must be specified, or the first letter parameter will be incorrectly interpreted as a pathname. A pathname is allowed. Pathnames and parameters can be specified on the same command line. If the S and D bit (bit 2) of PBITS+1 is also set to 1, a pathname is mandatory, and parameters 252 System Programs alone cannot be specified without generating a syntax error. PBITS+1 ($BEss) bit 7 The A parameter is allowed. bit 6 The B parameter is allowed. bit 5 The E parameter is allowed. bit 4 The L parameter is allowed. bit 3 The @ parameter is allowed. bit 2 The S and D parameters are allowed. The S (slot) and D (drive) parameters must correspond to an existing disk drive if preceded by a filename; if preceded by a slot number specification (see bit 6 of PBITS), they do not. If the S and D parameters are allowed, but not specified. their values default to those stored at DEFSLT ($BE3C) and DEFDRV ($BE3D). If this bit is set, and no prefix is active, the name of the volume directory on the slot S, drive D drive is fetched and used to create a full pathname whenever a filename or partial pathname is specified. If a prefix is active, it will be fetched like this only if an S or D parameter is actually specified. bit 1 The F parameter is allowed. bit 0 The R parameter is allowed. (One other parameter is always allowed and always parsed: the V (volume) parameter. BASIC.SYSTEM commands tolerate this parameter but do not use it; it has been included to maintain compatibility with DOS 3.3 commands that do use it.) The descriptions for PBITS and PBITS + 1 apply when the corresponding bit is set to 1. For example, if the command allows a pathname and A and E parameters, the handler would set PBITS to $01 and PBITS + 1 to $A0. If a pathname is actually mandatory, bit 2 of PBITS + 1 (the S and D bit) must be set to 1 as well. As indicated above, this actually serves two purposes: First, it tells BASIC.SYSTEM to automati- cally create a full pathname if one is not specified, and second, it tells BASIC. SYSTEM a pathname must be specified. If BASIC.SYSTEM is not to do any parsing, PBITS must be set to 0. Whether or not the command handler does its own parsing, if the command is found, the subrou- tine must store the length of the command string minus 1 in XLEN ($BE52), store 0 (the code number for an external command) in XCNUM ($BE53), and then store at XTRNADDR ($BE50-$BE51) the address control is to pass to after BASIC.SYSTEM ultimately parses the command line. The latter step must be performed even if the handler has indicated that no parsing need be performed. Lastly, the carry flag must be cleared before executing the RTS to return control to BASIC.SYSTEM. When control returns to BASIC.SYSTEM, the parameters in the command line are parsed according to the instructions stored in PBITS and PBITS + 1 (if applicable). The values of the parameters that are actually parsed from the line are stored in a global page parameter table located from $BE58 to $BE6F (see Table 5-7); if a Adding Commands to BASIC. SYSTEM 253 Table 5-7 BASIC. SYSTEM parameter table= location Symbolic Name Meaning $BE58-$BE59 APARM A (address) parameter $BE5A-$BE5C BPARM B (byte #) parameter $BE5D-$BE5E EPARM E (end addr) parameter $BE5F-$BE60 LPARM L (length) parameter $BE61 SPARM S (slot) parameter $BE62 DPARM D (drive) parameter $BE63-$BE64 FPARM F (field #) parameter $BE65-$BE66 RPARM R (record #) parameter $BE67 VPARM V (volume #) parameter $BE68-$BE69 @PARM @ (line #) parameterb $BE6A TPARM T (file type code) paramet~ $BE6B SLPARM slot (for IN#, PR#) $BE6C-$BE6D PATH 1 Pointer to first pathname $BE6E-$BE6F PATH2 Pointer to second pathname N0TE5: ~e value associated with a parameter is stored in this table as it is parsed by BASIC.SYSTEM. If $ D parameters are allowed, but not specified, the default values stored at DEFSLT ($BE3C) and DEFDRV ($BE3D) are transferred to this table. hA bug in BASIC.SYSTEM (versions I.l and 1.2) causes the V parameter to be stored in @PARM than VPARM (as shown). This means V and @ cannot be used together on the same command line because the value of the first parameter specified will be overwritten by the value of the other. particular parameter is not detected in the parsing operation, its entry in the stays as it was before the external command was executed. The actual parameters were successfully parsed are indicated by setting the appropriate bits in ($BE56) and FBITS + 1 ($BE57). (Table 5-7 describes a BASIC.SYSTEM version 1. and 1.2 bug that hinders the proper parsing of a command line that uses both the and @ parameters.) Note that the first pathname parsed from a command line is stored in a pointed to by VPATH1 ($BE6C) and the second is stored in a buffer pointed to by VPATH2 ($BE6E). These are the same buffers pointed to by the pathname pointers In 254 System Programs the MLI parameter tables used by BASIC.SYSTEM's GOSYSTEM ($BE70) subrou- tine. This means an external command handler can use COSYSTEM to perform MLI commands without first having to modify these pointers. After a successful parse, BASIC.SYSTEM jumps to the subroutine whose address is stored at XTRNADDR ($BE50-$BE51); this is the second half of the external com- mand handler. This subroutine can actually execute the command (if this wasn't done in the first half) and then return with a zero in the accumulator and the carry flag clear if there was no error. If an error is detected, it can be passed to BASIC.SYSTEM for handling by setting the carry flag and placing the appropriate error code in the accumulator (the BASIC. SYSTEM error code, not the MLI error code). Alternatively, the command handler can deal with the error itself if it does, the carry flag must be cleared and the accumulator set to 0 before returning to BASIC.SYSTEM. Note that if BASIC.SYSTEM does the parsing, the second part of the command handler can examine FBITS to determine exactly what parameters were found and then read their values from the table beginning at $BE58. If some parameters (marked as optional in PBITS and PBITS + 1) must be specified, the second part of the command handler can check the appropriate bits of FBITS and FBITS + 1 to ensure that they are 1; if they're not, an error condition can be flagged by loading the accumulator with the BASIC.SYSTEM error code (16 for "syntax error") and setting the carry flag before returning. The ONLINE Command In this section, we see how to design and install the handler for a new BASIC. SYSTEM command called ONLINE. This command displays the names of any, or all, of the disk volumes currently available to the system. ONLINE is useful if you habitually forget the name of a disk microseconds after putting it into a disk drive. The syntax of the ONLINE command is ONLINE [,5,'] [,D#] where the brackets mean the enclosed parameter (slot number or drive number) is optional. If a specific slot or drive number is specified, only the name of the volume for the corresponding disk device is displayed. But if both parameters are omitted, the volume names for all disk devices are displayed. The ONLINE command can be typed in while in Applesoft command mode, or it can be executed within a program using a PRINT CHR$(4);"ONLINE" statement. Table 5-8 shows the ONLINE installation program, which is executed with the BRUN command. The first part of the program installs the image of the ONLINE command handler code that begins at $2100. It first finds a safe spot above HIMEM to store the image, patches it so that it will execute at this new position, and then moves the code to its new home. It also links in the command handler by storing its Adding Commands to BASIC. SYSTEM 255 Table 5-8 Adding the ONLINE command to BASIC.SYSTEM 4 5 * ONLINE [,Sn] [,Dn] 6 7 * Copyright 1985-1988 Gary B. Little 8 9 Last modified: August 26, 1988 10 11 12 SBLOCK EQU $3C Parameters for block move 13 EBLOCK EQU $3E 14 FBLOCK EQU $42 15 HIMEM EQU $73 16 17 IN EQU $200 18 19 EXTRNCMD EQU $BEO6 20 ERROUT EQU $BE09 21 XTRNADDR EQU $BE50 22 XLEN EQU $BE52 23 XCNUM EQU $BE53 24 PBITS EQU $BE54 25 FBITS EQU $BE56 26 VSLOT EQU $BE61 27 VDRIV EQU $BE62 28 GETBUFR EQU $BEF5 29 30 MLI EQU $BFOO 31 32 CROUT EQU $FD8E 33 COUT EQU $FDED 34 MOVE EQU $FE2C 35 36 ORG $2000 37 ;Use this as ON_LINE buffer ;Command input buffer External command JMP opcode Error handler Start of external cmd handler ;External cmd name length (-1) ;Command (0 for external) ;Command parameter bits ;Parameters found in parse Slot parameter specified ;Drive parameter specified ;Get a free space ;Entry point to MLI ;Print a CR Character output subroutine Block move subroutine 38 Calculate # of pages that we need to reserve: 39 2000:38 40 SEC 2001: A9 22 41 LDA #>END 2003: E9 21 42 SBC #>CMDCODE 2005: 8D 74 20 43 STA PAGES 2008: EE 74 20 44 INC PAGES 45 20DB: AD 74 20 46 LDA PAGES ;Reserve the pages for the 200E: 20 F5 BE 47 JSR GETBUFR command handler 2011: 90 05 48 BCC INSTALL ;Carry clear if OK 49 2013: A9 DE 50 LDA #14 ;"PRDGRAM TOO LARGE" error 256 System Programs Table 5-8 Continued 2015: 4C 09 BE 2018: 8D 75 20 201B: AD 07 BE 201E: 8D 26 21 2021: AD 08 BE 2024: 8D 27 21 2027: A9 00 2029: 8D 07 BE 202C: AD 75 20 2O2F: 8D 08 BE 2032: AD 75 20 2035: 8D OF 21 2038: 8D 1A 21 203B: 8D 32 21 2O3E: 8D 49 21 2041: 8D 4E 21 2044: 8D 55 21 2047: 8D 6F 21 204A: 8D 75 21 204D: 8D 8A 21 2050: 8D A4 21 2053: 8D D5 21 2056: A9 00 2058: 85 3C 205A: A9 21 205C: 85 3D 205E: A9 03 2060: 85 3E 2062: A9 22 2064: 85 3F 51 JMP ERROUT 52 53 INSTALL STA PGSTART Save starting page 54 55 * Install the new command handler: 56 57 LDA EXTRNCMD+1 Set up link to 58 STA NEXTCMD+1 existing external command 59 LDA EXTRNCMD+2 60 STA NEXTCMD+2 61 62 **************************************** 63 Install the external command handler 64 by storing its address after the 65 JMP at EXTRNCMD. 66 **************************************** 67 68 LDA #0 69 STA EXTRNCMD+1 70 LDA PGSTART 71 STA EXTRNCMD+2 72 73 * Relocate the code: 74 75 LDA PGSTART ;Get new page 76 STA CMDCODE+$OF 77 STA CMDCODE+$1A 78 STA CMDCODE+$32 79 STA CMDCODE+$49 80 STA CMDCODE+$4E 81 STA CMDCODE+$55 82 STA CMDCODE+$6F 83 STA CMDCODE+$75 84 STA CMDCODE+$8A 85 STA CMDCODE+$A4 86 STA CMDCODE+$D5 87 88 Set up parameters for block move to final location: 89 90 LDA #CMDCODE 93 STA SBLOCK+1 94 95 LDA #END 98 STA EBLOCK+1 99 Adding Commands to BASIC. SYSTEM 257 Table 5-8 Continued 206A: AD 75 20 102 LDA PGSTART 206D: 85 43 103 STA FBL0CK+1 104 206F: AD O0 105 LDY #0 2071: 4C 2C FE 106 JMP MOVE Move it! 107 2074: 00 108 PAGES 05 1 2075:00 109 PG5TART 05 1 110 2076: 00 00 00 111 05 $2100~* 2079: 00 00 00 00 00 00 00 00 2081: 00 00 00 00 00 00 00 00 2089: 00 00 00 00 00 00 00 00 2091: 00 00 00 00 00 00 00 00 2099: 00 00 00 00 00 00 00 00 20A1: 00 00 00 00 00 00 00 00 20A9: 00 00 00 00 00 00 00 00 20B1: 00 00 00 00 00 00 00 00 20B9: 00 00 00 00 00 00 00 00 20C1: 00 00 00 00 00 00 00 00 20C9: 00 00 00 00 00 00 00 00 2001: 00 00 00 00 00 00 00 00 2009: 00 00 00 00 00 00 00 00 20E1: 00 00 00 00 00 00 00 00 20E9: 00 00 00 00 00 00 00 00 20F1: 00 00 00 00 00 00 00 00 20F9: 00 00 00 00 00 00 00 112 113 CMDC00E EQU 114 ;Length of command handler Starting page of cmd handler (Must start on page boundary) 115 ****** * This is the command checker. It * scans the input buffer to see * if the command has been entered. 116 117 118 11 * ******* 2100:08 120 CLD 2101: AD 00 121 L0Y #0 2103: A2 00 122 L0X #0 2105: BD 00 02 123 CHKCM0 LDA IN,X ;Get command character 2108: E8 124 INX 2109: C9 AD 125 CMP #$A0 Is it a blank? 21D~: F0 F8 126 BEQ CHKCM0 ;If it is, ignore it 2100: 09 EE 21 127 CMP CM0NAME,Y Same as our command? 2110: F0 0B 128 BEQ CHKCMD1 ;Yes, so branch 2112: C9 ED 129 CMP #$E0 Lowercase? 2114: 90 DE 130 BCC N0TF0UND No, so branch 2116: 29 OF 131 AND #$0F ;Convert to uppercase 258 Systein Programs Table 5-8 Continued 2118: D9 EE 21 132 CMP 211B: DO 07 133 BNE 211D: C8 134 CHKCMD1 1NY 211E: CO 06 135 CPY 2120: DO E3 136 BNE 2122: F0 04 137 BED 138 2124: 38 13~ N0TF0UND SEC 2125: 4C 00 00 140 NEXTCMD JMP 141 2128: 88 142 SETRULES 0EY 2129: 8C 52 BE 143 STY 144 212C: Ag 51 145 LDA 212E: 8D 50 BE 146 STA 2131: A9 21 147 LDA 2133: 8D 51 BE 148 STA 149 2136: A9 00 150 L0A 2138: 80 53 BE 151 STA 152 CMDNAME,Y OK now? N0TF0UND ;No, so branch #CMDLEN-CMDNAME ;At end? CHKCMD ;No, so branch SETRULES Yes, so branch Set carry to indicate failure $0000 ;(Fill in when installed) XLEN ;Store command length-I #EXECUTE XTRNADDR+1 #0 XCNUM ;External cmd number = 0 153 Set up string parsing rules: 154 213B: A9 10 155 LOA #$10 ;Pathname is optional 2130: 8D 54 BE 156 STA PBITS 2140: A9 04 157 LDA #$04 Slot, drive allowed 2142: 80 55 BE 158 STA PBITS+1 159 2145: AS 73 160 LDA HIMEM ;Set ON_LINE buffer (at least 2147: 80 EC 21 161 STA BUFFER 256 bytes) to free area 214A: AS 74 162 LDA HIMEM+1 beginning at HIMEM 214C: 80 ED 21 163 STA BUFFER+1 164 214F: 18 165 CLC 2150:60 166 RTS 167 ;Clear carry to indicate success 168 * BASIC.SYSTEM comes here after it has 169 successfully parsed the command line: 170 2151: A9 00 171 EXECUTE LDA #0 2153: 8D EB 21 172 STA UNITNUM (Assume all volumes) 2156: AD 57 BE 173 LDA FBITS+1 Examine result of parse 2159: 29 04 174 AND #$04 Slot, drive specified? 215B: FO 13 175 BEQ DOCALL ;No, so check everything 2150: AD 61 BE 176 LDA VSL0T Get slot # specified 2160:0A 177 ASL 2161:0A 178 ASL 2162:0A 179 ASL 2163: 0A 180 ASL Slot 16 Adding Comnjcinds to BASIC. SYSTEM 259 Table 5-8 Continued 2169: DO 02 183 BNE SAVEUN 216B: 09 80 184 0RA #$80 216D: 8D EB 21 185 SAVEUN STA UNITNUM 186 2170: 20 00 BF 187 D0CALL JSR MLI 2173: C5 188 DFB $C5 2174: EA 21 189 DA 0LPARM 190 2176: 20 8E FD 191 JSR CR0UT 2179: A0 00 192 LDY #0 217B: 98 193 SCAN TYA 217C: 48 194 PHA 217D: B1 73 195 LDA (HIMEM),Y 217F: F0 61 196 BEQ SCAN2 2181: 29 OF 197 AND #$0F 2183: F0 4E 198 BEQ NEXTNAME 2185:48 199 PHA 200 2186: A2 00 201 LDX #0 2188: BD F4 21 202 PRTMSG1 LDA SL0TMSG,X 218B: FO 06 203 BEQ PRTNUM1 218D: 20 ED FD 204 JSR C0UT 2190: E8 205 INX 2191: DO F5 206 BNE PRTMSG1 207 2193: B1 73 208 PRTNUM1 LDA (HIMEM),Y 2195: 29 70 209 AND #$70 2197:4A 210 LSR 2198:4A 211 LSR 2199:4A 212 LSR 219A: 4A 213 LSR 219B: 09 BO 214 ORA #$BO 219D: 20 ED FD 215 JSR COUT 216 21A0: A2 00 217 LDX #0 ;Drive 2? ;No, so branch Set "drive 2" bit ;Store slot, drive as unit num ON_LINE call ;Address of parm table ;Get slot, drive + length ;If $00, then all done Isolate length bits ;If 0, then must be error ;Print slot ;Get slot, drive + length Isolate slot bits ;We now have slot ;Convert to ASCII digit 21A2: BD FA 21 218 PRTMSG2 LDA DRIVEMSG,X ;Print drive # 21A5: FO 06 219 BEQ PRTNUM2 21A7: 20 ED FD 220 JSR COUT 21AA: E8 221 INX 21AB: DO F5 222 BNE PRTMSG2 223 21AD: A2 B1 224 PRTNUM2 LDX #$B1 ;Assume drive 1 21AF: B1 73 225 LDA (HIMEM),Y 21B1: 10 02 226 BPL PSKIP Branch if drive 1 21B3: A2 B2 227 LDX #$B2 Must be drive 2 21BS: 8A 228 PSKIP TXA 21B6: 20 ED FD 229 JSR COUT 260 System I'i'ogranrs Table 5-8 Continued 21B9: A9 BA 230 LDA #": 21BB: 20 ED FD 231 JSR C0UT 21BE: A9 A0 232 LDA #$A0 21C0: 20 ED FD 233 JSR C0UT 234 21C3: 68 235 PLA 21C4: AA 236 TAX 21C5: C8 237 PRTNAME INY 21C6: B1 73 238 LDA (HIMEM).Y Get next character in name 21C8: 09 80 239 0RA #$80 ;Set high bit 21CA: 20 ED FD 240 JSR C0UT and display it 21CD: CA 241 DEX 21CE: DO F5 242 BNE PRTNAME ;Branch until done 21D0: 20 8E FD 243 JSR CROUT 244 21D3: AD EB 21 245 NEXTNAME LDA UNITNUM Was only one volume specified? 21D6: DO 0A 246 BNE SCAN2 Yes, so branch 247 21D8: 68 248 PLA 21D9: 18 249 CLC 21DA: 69 10 250 ADC #16 ;Move to next name 21DC: A8 251 TAY 21DD: CO ED 252 CPY #224 At end of table? 21DF: DO 9A 253 BNE SCAN ;No, so branch 21E1: 48 254 PHA 255 21E2: 68 256 SCAN2 PLA 21E3: 20 8E FD 257 JSR CR0UT 21E6: 18 258 CLC ;CLC ==> no error 21E7: A9 00 259 LDA #0 ;Error code = 0 21E9: 60 260 RTS 261 21EA: 02 262 0LPARM DFB 2 ;Two parameters 21EB: 00 263 UNITNUM DFB 0 ;Unit number (05550000) 21EC: 00 00 264 BUFFER DA $0000 ;Device buffer 265 21EE: CF CE CC 266 CMDNAME ASC "ONLINE" External command name 21F1: C9 CE C5 267 CMDLEN EQU 268 21F4: 03 CC CF 269 SLOTMSG ASC "SLOT ".00 21F7: 04 AD DO 21FA: AC AD C4 270 DRIVEMSG ASC ", DRIVE ",00 21FD: 02 C9 D6 C5 AD 00 271 272 END EQU Adding Commands to BASIC. SYSTEM 261 starting address at EXTRNCMD + 1 ($BE07) a"d EhTRNCMD + 2 ($ just in case another user con,n,and handler has already been installed, it address previously stored in EhTRNCMD + 1 and E~TRNCMD + 2 and the target address of a JMP instruction in the body of the ONLINE con,,i,aiid This JMP is executed only if the ONLINE handler doesn't recognize the passed to it. This nieans control always daisy-chains down to a previously external coii,niai'd handler so that it will have a chance to clain, the con,tiiaiid. The GETBUFR ($BEF5) subroutine is used to locate a "safe" buffer large to store the command handler. It is called with the number of pages required accumulator (1). If we run out of room, the carry flag will be set, and a "pr large" error message will be printed by calling ERROUT ($BE09). Othei~ise, memory page is, the block freed up will be returned in the accumulator. A> earlier in the chapter, we can now use this block to store a prograni without later being overwritten by file buffers or string variables. Since the ONLINE command handler is not inherently relocatable, all to internal absolute addresses must be altered to reflect the change in the the code. The relocation procedure is relatively simple in our example bee code fur the command handler was assembled on a page boundary, and it is moved to another page boundary. This means only the high-order part absolute address in the handler need be modified. Although it is possible to complex subroutine to antomatically patch the code, we chose to "manuallv" by inspecting the handler to identify addresses to be changed and then new page number at these positions. If you change the handler in any way, have to recalculate which addresses must be patched and make the necessarv to the installation code. The code is moved into place by using the system Monitor block move MOVE ($FEC2). This subroutine moves the block of memory beginning at address stored in $3C-$3D and ending at the address stored in $3E-$3F to the' beginning at the address stored in $42-$43. MOVE must be called with the Y set to zero. The main part of the ONLINE command handler begins at CMDCODE. The thing it does is check if the ASCII codes for the word "ONLINE" or "onlsne the beginning of the input buffer at $200 (intervening spaces are ignored). If uot, carry flag is set (indicating not handled), and the jutnp at NEXTCMD is explained above, this gives a previously installed command handler a crack at fying the command. If the "ONLINE" command is detected, the length of the command (minus stored at XLEN ($BE52); the external command number (0) is stored at XCN1 ($BE53); and the address of the postparsing subroutine, EXECUTE, is stored XTRNADDR ($BE50) and XTRNADDR + 1 ($BE51). Finally, the parsing rules stored in PBITS ($BE54) and PBITS + 1 ($BE55): pathname optional, slot and allowed. The pathname optional bit must be set because the ONLINE command 262 Systcin I'cogi'ains