AppleIIAsm-Collection/documentation/AppleIIAsm Library Collection Technical Manual/0.6.1/35.0 Detailed_Reference_D6_DOS.md

4457 lines
164 KiB
Markdown
Raw Normal View History

# Disk 6: Apple DOS
- [Part I: The DOS Collection](#part-i-the-dos-collection)
- [DOS Components](#dos-components)
- [DOS Header File](#dos-collection-header-file)
- [_SETRWTS](#the-_setrwts-subroutine)
- [_FMGETPARM](#the-_fmgetparm-subroutine)
- [_FMBUFSCAN](#the-_fmbufscan-subroutine)
- [_SETPBUFFS](#the-_setpbuffs-subroutine)
- [_NAMESTR](#the-_namestr-subroutine)
- [_NAMESTR2](#the-_namestr2-subroutine)
- [_FN2BUFF](#the-_fn2buff-subroutine)
- [_FMNM2](#the-_fmnm2-subroutine)
- [_BUFFCLEAR](#the-_buffclear-subroutine)
- [_FMPSET](#the-_fmpset-subroutine)
- [_FMPSETA](#the-_fmpseta-subroutine)
- [_FMPGET](#the-_fmpget-subroutine)
- [_FMPGETA](#the-_fmpgeta-subroutine)
- [Required DOS Macros](#required-dos-macros)
- [FMFIL](#the-fmfil-macro)
- [FMNAM](#the-fmnam-macro)
- [FRWB](#the-frwb-macro)
- [FWRTB](#the-fwrtb-macro)
- [FRDB](#the-frdb-macro)
- [FRWR](#the-frwr-macro)
- [FRDR](#the-frdr-macro)
- [FWRTR](#the-fwrtr-macro)
- [DOS File Manager Macros and Subroutines](#dos-file-manager-macros)
- [FCAT](#the-fcat-macro)
- [FULCK](#the-fulck-macro)
- [FLOCK](#the-flock-macro)
- [FDEL](#the-fdel-macro)
- [FVFY](#the-fvfy-macro)
- [FCLOS](#the-fclos-macro)
- [FRENM](#the-frenm-macro)
- [FOPEN](#the-fopen-macros)
- [BLOAD](#the-bload-macro)
- [FBLOAD](#the-fbload-subroutine)
- [BSAVE](#the-bsave-macro)
- [FBSAVE](#the-fbsave-subroutine)
- [Miscellaneous DOS Macros and Subroutines](#miscellaneous-dos-macros)
- [DVER](#the-dver-macro)
- [DOSIN](#the-dosin-macro)
- [ABAS](#the-abas-macro)
- [IBEX](#the-ibex-macro)
- [ABEX](#the-abex-macro)
- [Part II: DOS Collection Demos](#part-ii-dos-collection-demos)
- File Manager Demo
- Miscellaneous DOS Macros Demo
---
## Part I: The DOS Collection
The sixth disk of the AppleIIAsm library is dedicated to DOS operations. For the most part, the macros and subroutines here act as an abstraction layer between the lower level functions of DOS and the programmer. Unfortunately, this does carry with it some substantial overhead in terms of bytes used, but the ease of functionality is usually worth it unless memory is an extreme concerned. In such a case, the DOS collection can be narrowed to only the functions that are needed.
There are a number of macros and subroutines that are likely to go unused by most programmers, as they are mostly meant for internal use by the collection. These are covered as part of this documentation, but are not the primary focus of functionality. Those macros and subroutines that are the primary focus includes functions for the following:
- Disk Catalog
- File Locking and Unlocking
- File Deletion
- File Verification
- File Renaming
- File Opening and Closing
- Binary File Loading and Saving
- DOS Version Checking
- Integer and Applesoft Runtime Checking
- RWTS Access
---
## DOS Components
The DOS Collection contains the following components:
- A head file that includes a number of hooks, vectors and subroutines that are necessary for the operation of the whole collection.
- A macro library that is required to be included for using the rest of the collection.
- Two further sets of macro files, MAC.DOSFM.ASM and MAC.DOSMORE.ASM. The former contains macros used for managing files while the latter contains miscellaneous macros related to DOS.
- Two demo files that illustrate how all of the major macros are used. Note that this does not include macros that are meant for internal use.
---
## DOS Collection Header File
| Condition | Value |
| ------------- | ------------------------------------------------------------ |
| Name | File: HEAD.DOS.ASM |
| Type | Header File |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin 8 Pro |
| OS | Apple DOS 3.3 |
| Purpose | Provide appropriate hooks and routines for the DOS collection |
| Dependencies | none |
| Bytes | 584 |
| Notes | none |
| See Also | none |
---
*DETAILS*
The DOS Header file includes a number of required subroutines that are detailed later in this section.
`LISTING 6.00: HEAD.DOS.ASM Hooks & Vectors Source`
```assembly
*
*``````````````````````````````*
* HEAD.DOS.ASM *
* *
* THIS HEADER FILE IS USED BY *
* THE DOS COLLECTION AS A *
* REPOSITORY FOR VARIABLE *
* SPACE, HOOKS, SUBROUTINES *
* NECESSARY FOR THE REST OF *
* THE COLLECTION AND OTHER *
* MISCELLANEOUS TASKS. *
* *
* CURRENTLY, THIS COLLECTION *
* HAS QUITE A BIT OF OVERHEAD *
* IN TERMS OF BYTES. THIS WILL *
* HOPEFULLY BE REDUCED IN *
* FUTURE REVISIONS. *
* *
* NOTE THAT THE METHOD USED *
* FOR FINDING AN EMPTY FILE *
* BUFFER IS ADAPTED FROM A *
* LISTING IN DON WORTH'S AND *
* PETER LECHNER'S /BENEATH *
* APPLE DOS AND BENEAT APPLE *
* PRODOS 2020/. AS SUCH, THE *
* LICENSE MAY VARY. *
* *
* AUTHOR: NATHAN RIGGS *
* CONTACT: NATHAN.RIGGS@ *
* OUTLOOK.COM *
* *
* DATE: 07-MAY-2021 *
* ASSEMBLER: MERLIN PRO 8 *
* OS: DOS 3.3 *
* *
* SIZE: 584 BYTES (OVERHEAD) *
* *
* SUBROUTINES: *
* *
* _SETRWTS *
* _FMGETPARM *
* _FMBUFSCAN *
* _SETPBUFFS *
* _NAMESTR *
* _NAMESTR2 *
* _FN2BUFF *
* _FMNM2 *
* _BUFFCLEAR *
* _FMPSET *
* _FMPSETA *
* _FMPGET *
* _FMPGETA *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
*``````````````````````````````*
* RWTS EQUATES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]RWTSPTR EQU ADDR4 ; WORK POINTER FOR RWTS ROUTINES
]RWTSRD EQU 1 ; READ CODE FOR RWTS
]RWTSWR EQU 1 ; WRITE CODE FOR RWTS
]LOCRPL EQU $3E3 ; LOCATE RWTS PARAMLIST
]RWTS EQU $3D9 ; RWTS ROUTINE
*
]RPLIOB EQU $0 ; IOB TYPE, ALWAYS $01
]RPLSLT EQU $1 ; IOB SLOT * 16
]RPLDRV EQU $2 ; IOB DRIVE
]RPLVOL EQU $3 ; IOB VOLUME (#0 FOR ANY)
]RPLTRK EQU $4 ; IOB TRACK
]RPLSEC EQU $5 ; IOB SECTOR
]RPLDCT EQU $6 ; IOB ADDR TO DCT ($6,$7)
]RPLBUF EQU $8 ; IOB ADDR TO BUFFER ($8,$9)
]RPLSIZ EQU $A ; IOB SIZE ($A,$B)
]RPLCMD EQU $C ; IOB COMMAND
]RPLCNL EQU $00 ; NULL COMMAND
]RPLCRD EQU $01 ; READ COMMAND
]RPLCWR EQU $02 ; WRITE COMMAND
]RPLCFM EQU $04 ; FORMAT COMMAND
]RPLRCD EQU $D ; IOB RETURN CODE
]RPLRWP EQU $10 ; WRITED PROTECTED ERROR
]RPLRVM EQU $20 ; VOLUME MISMATCH ERROR
]RPLRDE EQU $40 ; DRIVE ERROR
]RPLRRE EQU $80 ; READ ERROR
]RPLTVL EQU $E ; IOB TRUE VOLUME
]RPLPSL EQU $F ; IOB PREVIOUS SLOT
]RPLPDR EQU $10 ; IOB PREVIOUS DRIVE
*
*``````````````````````````````*
* FILE PARAMETER LIST EQUATES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]FMPADDR EQU $3DC ; FILE MGR PARAM ADDR GET
]FMRUN EQU $3D6 ; RUN FILE MAMAGER ROUTINE
]DOSWARM EQU $3D0 ; DOS WARM START
*
]TYP_TXT EQU $00 ; FILE TYPE TEXT VALUE
]TYP_INT EQU $01 ; FILE TYPE INT VALUE
]TYP_APP EQU $02 ; FILE TYPE APPLESOFT VALUE
]TYP_BIN EQU $04 ; FILE TYPE BINARY VALUE
]TYP_REL EQU $08 ; FILE TYPE REL VALUE
]TYP_S EQU $10 ; FILE TYPE S VALUE
]TYP_A EQU $20 ; FILE TYPE A VALUE
]TYP_B EQU $40 ; FILE TYPE B VALUE
*
]SC_NON EQU $00 ; SUBCODE NOTHING VALUE
]SC_RWB EQU $01 ; SUBCODE READ OR WRITE A BYTE VALUE
]SC_RWR EQU $02 ; SUBCODE READ OR WRITE RANGE VALUE
]SC_PRWB EQU $03 ; SUBCODE POSITION THEN RW 1 BYTE VAL
]SC_PRWR EQU $04 ; SUBCODE POSITION THEN RW RANGE VAL
*
]FC_OPEN EQU $01 ; COMMAND CODE FOR OPEN
]FC_CLOS EQU $02 ; COMMAND CODE FOR CLOSE
]FC_READ EQU $03 ; COMMAND CODE FOR READ
]FC_WRIT EQU $04 ; COMMAND CODE FOR WRITE
]FC_DEL EQU $05 ; COMMAND CODE FOR DELETE
]FC_CAT EQU $06 ; COMMAND CODE FOR CATALOG
]FC_LOCK EQU $07 ; COMMAND CODE FOR LOCK
]FC_UNLK EQU $08 ; COMMAND CODE FOR UNLOCK
]FC_REN EQU $09 ; COMMAND CODE FOR RENAME
]FC_POS EQU $0A ; COMMAND CODE FOR POSITION
]FC_INIT EQU $0B ; COMMAND CODE FOR INIT
]FC_VFY EQU $0C ; COMMAND CODE FOR VERIFY
*
]P_CMD EQU $00 ; PARAM COMMAND OFFSET
]P_REC EQU $02 ; PARAM RECORD OFFSET
]P_VOL EQU $04 ; PARAM VOLUME OFFSET
]P_DRV EQU $05 ; PARAM DRIVE OFFSET
]P_SLOT EQU $06 ; PARAM SLOT OFFSET
]P_TYPE EQU $07 ; PARAM TYPE OFFSET
]P_NAMAD EQU $08 ; PARAM NAME BUFFER ADDRESS OFFSET
]P_WORK EQU $0C ; PARAM WORKAREA BUFFER ADDRESS OFFSET
]P_TSLS EQU $0E ; PARAM TSLS BUFFER ADDRESS OFFSET
]P_DATA EQU $10 ; PARAM DATA BUFFER ADDRESS OFFSET
]P_RETC EQU $0A ; PARAM RETURN CODE OFFSET
]P_RDWR EQU $00 ; READ OR WRITE OFFSET
]P_SUBC EQU $01 ; PARAM SUBCODE OFFSET
]P_BOFF EQU $04 ; PARAM BYTE OFFSET OFFSET
]P_RLEN EQU $06 ; PARAM RANGE LENGTH OFFSET
]P_RADDR EQU $08 ; PARAM RANGE ADDRESS OFFSET
]P_BYTE EQU $08 ; PARAM SINGLE WRITE BYTE OFFSET
]P_DPAGE EQU $01 ; PARAM 1ST DOS PAGE ADDR OFFSET
*
JMP __DHEXIT ; {6C3B} PASS OVER ROUTINES
*
MSLOT DFB $60 ; {0C1B} MASTER SLOT
MDRIVE DFB $2 ; {0C1B} MASTER DRIVE
MTRACK DFB $11 ; {0C1B} MASTER TRACK FOR RWTS
MSECTOR DFB $0 ; {0C1B} MASTER SECTOR FOR RWTS
MBUFFER DFB $9000 ; {0C1B} MASTER BUFFER ADDRESS FOR RWTS
DFB $9000/$100 ; {0C1B}
MCMD DFB $1 ; {0C1B} MASTER COMMAND FOR RWTS
MVOL DFB $0 ; {0C1B} MASTER VOLUME FOR RWTS
*
]TEMP HEX 0000 ; {0C2B}
]TEMP2 HEX 0000 ; {0C2B}
]FPARM HEX 0000 ; {0C2B} FILE MGR PARAM ADDRESS
]FNBUF HEX 0000 ; {0C2B} FILE NAME BUFFER
]FWORK HEX 0000 ; {0C2B} FILE WORKAREA BUFFER
]FDATA HEX 0000 ; {0C2B} FILE DATA BUFFER
]FTSLS HEX 0000 ; {0C2B} FILE TRACK/SECTOR LIST BUFFER
]FNAME DS 30 ; {0C30B} FILENAME TEMP STORAGE
]FNAME2 DS 30 ; {0C30B} SECOND FILENAME BUFFER
```
---
### THE _SETRWTS SUBROUTINE
_SUMMARY_
| Condition | Value |
| --------------- | -------------------------- |
| Name | `_SETRWTS` |
| Type | Subroutine |
| File | `HEAD.DOS.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Set common RWTS parameters |
| Input | none |
| Output | none |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 142+ |
| Bytes | 78 |
| Notes | none |
| See Also | none |
---
*DETAILS*
The `_SETRWTS` routine sets the parameters for the **Input/Output Control Block** **(IOB)** before calling the **Read/Write Track/Sector** **(RWTS)** Routine. For the most part, this is used internally, and is not meant to be used by the end programmer. The following parameters are set in the **IOB** via the values given in global variables, which are set via another routine:
- Slot
- Drive
- Volume
- Track
- Sector
- Buffer
- Command
While the DOS collection makes knowing the format of the **Input/Output Control Block** unnecessary, there may be cases where one needs to access DOS at a lower level. Thus, the format of the **IOB** is listed here:
**INPUT / OUTPUT CONTROL BLOCK**
| Byte | Description |
|------------------|------------------------|
|00| Table type, must always be #00 |
|01| Slot number * 16 ($10, $20, $30, $40, $50, $60, $70) |
|02| Drive number |
|03| Volume number (#00 for any) |
|04| Track number |
|05| Sector number |
|06-07| Address of the Device Characteristics Table (DCT) |
|08-09| Address of the 256 byte buffer for READ/WRITE |
|0A| Unused |
|0B| Byte count for partial sector |
|0C| Command Code:<br />#$00 = SEEK<br />#$01 = READ<br />#$02 = WRITE<br />#$04 = FORMAT |
|0D| Return Code. The CARRY flag is set upon returning from RWTS to indicate that an error has occurred. The following values are passed here to communicate the type of error:<br />#$00 = No error<br />#$08 = Initialization error<br />#$10 = Write protect error<br />#$20 = Volume mismatch<br />#$40 = Drive error<br />#$80 = Read error |
|0E| Volume number last accessed |
|0F| Slot number last accessed * 16 |
|10| Drive number last accessed |
While the **Device Characteristics Table (DCT)** is almost always the same and should remain unchanged (for a Disk II drive), its format is also listed here for reference:
**DEVICE CHARACTERISTICS TABLE**
| Byte | Description |
|--------|-------------------|
|00| Device Type (should be #$00) |
|01| Phases per track (should be #$01) |
|02-03| Motor on time count (should be #$EFD8) |
`LISTING 6.01: HEAD.DOS.ASM _SETRWTS Routine Source`
```assembly
*
*``````````````````````````````*
* _SETRWTS *
* *
* SET THE RWTS IOB PARAMETERS *
* *
* INPUT *
* *
* NONE. *
* *
* DESTROY: NZCIDV *
* ^^^ ^ *
* *
* CYCLES: 142+ *
* SIZE: 78 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
_SETRWTS
JSR ]LOCRPL ; {6C3B} LOCATE RWTS PARAMETER LIST
STY ]RWTSPTR ; {4C3B} SAVE POINTER LOW AND HIGH
STA ]RWTSPTR+1 ; {4C3B}
LDA MSLOT ; {4C3B} GET DEFAULT SLOT
ASL ; {2C1B} MULTIPLY BY 16
ASL ; {2C1B} TO GET APPROPRIATE VALUE
ASL ; {2C1B}
ASL ; {2C1B}
LDY #]RPLSLT ; {3C2B} LOAD IOB SLOT OFFSET
STA (]RWTSPTR),Y ; {6C2B} STORE SLOT VAL AT OFFSET
LDA MDRIVE ; {4C3B} LOAD DEFAULT DRIVE
LDY #]RPLDRV ; {3C2B} GET IOB DRIVE OFFSET
STA (]RWTSPTR),Y ; {6C2B} STORE DRIVE IN IOB
LDA MTRACK ; {4C3B} GET MASTER TRACK
LDY #]RPLTRK ; {3C2B} OFFSET IN PARAM LIST
STA (]RWTSPTR),Y ; {6C2B} STORE TRACK IN IOB
LDA MSECTOR ; {4C3B} GET MASTER SECTOR
CMP #16 ; {3C2B} BIGGER THAN 16?
BCC :SOK ; {3C2B} NOPE, IT'S OKAY
LDA #0 ; {3C2B} ELSE YES, SO CLEAR
STA MSECTOR ; {4C3B} MASTER SECTOR
:SOK LDY #]RPLSEC ; {3C2B} OFFSET IN PARMLIST
STA (]RWTSPTR),Y ; {6C2B} STORE SECTOR IN IOB
LDY #]RPLBUF ; {3C2B} OFFSET IN PARAMLIST
LDA MBUFFER ; {4C3B} GET LOW BYTE OF BUFFER ADDR
STA (]RWTSPTR),Y ; {6C2B} STORE LOW BYTE OF BUFF IN IOB
INY ; {2C1B} INCREASE OFFSET
LDA MBUFFER+1 ; {4C3B} GET HIGH BYTE
STA (]RWTSPTR),Y ; {6C2B} STORE HIGH BYTE IN IOB
LDA MCMD ; {4C3B} GET RWTS MASTER COMMAND
LDY #]RPLCMD ; {3C2B} OFFSET OF PARMLIST
STA (]RWTSPTR),Y ; {6C2B} STORE COMMAND IN IOB
LDA MVOL ; {4C3B} GET RWTS MASTER VOLUME
LDY #]RPLVOL ; {3C2B} OFFSET
STA (]RWTSPTR),Y ; {6C2B} STORE VOLUME IN IOB
RTS ; {6C1B}
```
---
### THE _FMGETPARM SUBROUTINE
_SUMMARY_
| Condition | Value |
| --------------- | ------------------- |
| Name | `_FMGETPARM` |
| Type | Subroutine |
| File | `HEAD.DOS.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Get the FPL Address |
| Input | none |
| Output | none |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 20+ |
| Bytes | 10 |
| Notes | none |
| See Also | `_SETPBUFFS` |
---
*DETAILS*
The `_FMGETPARM` subroutine gets the address of the **File Manager Parameter List (FPL)** and returns it in **.Y** (low byte) and **.A** (high byte), with the addition of storing it in the ]FPARM variable space. This is different from the usual passing of addresses in **.A** and **.X** due to the nature of how DOS was programmed; since this is used internally, however, this should not present a problem.
If the format of the **File Manager Parameter List (FPL)** is needed, it is available under the `SETPBUFFS` entry.
`LISTING 6.02: HEAD.DOS.ASM _FMGETPARM Routine Source`
```assembly
*
*``````````````````````````````*
* _FMGETPARM (NATHAN RIGGS) *
* *
* GET THE ADDRESS OF THE FILE *
* PARAMETER LIST. *
* *
* INPUT *
* *
* NONE. *
* *
* DESTROY: NZCIDV *
* ^^^ ^ *
* *
* CYCLES: 20+ *
* SIZE: 10 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
_FMGETPARM
*
JSR ]FMPADDR ; {6C3B} GET PARAM ADDRESS
STA ]FPARM+1 ; {4C3B} STORE HIGH BYTE
STY ]FPARM ; {4C3B} STORE LOW BYTE
RTS ; {6C1B}
*
```
---
### THE _FMBUFSCAN SUBROUTINE
_SUMMARY_
| Condition | Value |
| --------------- | ----------------------- |
| Name | `_FMBUFSCAN` |
| Type | Subroutine |
| File | `HEAD.DOS.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Find a free file buffer |
| Input | none |
| Output | none |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 211+ |
| Bytes | 117 |
| Notes | none |
| See Also | `_BUFFCLEAR` |
---
*DETAILS*
The `_FMBUFSCAN` subroutine finds an open file buffer and stores the addresses to various necessary sections in the appropriate memory locations. Primarily, this includes the **File Workarea**, the **Filename Buffer**, the **Data Sector Buffer**, and the **T/S List Sector (TSLS) Buffer**. If no file buffers are available then the carry is set to indicate an error, and the memory locations are all cleared to zero. A file buffer is considered clear if the first byte of the filename buffer carries a value of **#0**.
While the DOS collection makes it unnecessary to know the inner workings of DOS, it may be useful for the programmer to know the format of each file buffer. The format is as follows:
|BYTE | DESCRIPTION|
|--------------|--------------------|
|000-0FF | Data Sector Buffer (256 bytes)|
|100-1FF | T/S List Sector Buffer (256 bytes)|
|200-22C | File Manager Workarea Buffer (45 bytes)|
|22D-24A | File Name Buffer (30 bytes)|
|24B-24C | Address of File Manager Work Area Buffer|
|24D-24E | Address of T/S List Sector Buffer|
|24F-250 | Address of Data Sector Buffer|
|251-252 | Address of the File Name Buffer in the next File Buffer. If this is the last buffer available, then the value is #0000.|
`LISTING 6.03: HEAD.DOS.ASM _FMBUFSCAN Routine Source`
```assembly
*
*``````````````````````````````*
* _FMBUFSCAN (NATHAN RIGGS) *
* *
* FIND A FREE FILE BUFFER. IF *
* NONE EXISTS, RETURN #0. *
* *
* INPUT *
* *
* NONE. *
* *
* DESTROY: NZCIDV *
* ^^^ ^ *
* *
* CYCLES: 211+ *
* SIZE: 117 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
_FMBUFFSCAN
*
LDA $3D2 ; {4C3B} LOCATE DOS LOAD POINT
STA ADDR1+1 ; {3C2B} STORE THIS AS FIRST FNAME BUFF
LDY #0 ; {3C2B} LOW BYTE SHOULD START AT 0
STY ADDR1 ; {3C2B}
:GBUF0
LDA (ADDR1),Y ; {6C2B} LOCATE NEXT DOS BUFFER
PHA ; {3C1B} TEMPORARILY HOLD
INY ; {2C1B} INCREASE .Y INDEX
LDA (ADDR1),Y ; {6C2B} LOAD HIGH BYTE OF ADDRESS
STA ADDR1+1 ; {3C2B} STORE HIGH BYTE IN ZERO PAGE
PLA ; {3C1B} PULL BACK EARLIER VALUE
STA ADDR1 ; {3C2B} STORE AS LOW BYTE ON ZERO
BNE :GBUF ; {4C3B} FOUND A BUFFER
LDA ADDR1+1 ; {3C2B} ELSE LOAD HIGH BYTE
BEQ :NBUF ; {4C3B} IF ZERO, NO BUFFER
:GBUF
LDY #0 ; {3C2B} GET FILENAME FIRST CHAR
LDA (ADDR1),Y ; {6C2B} FROM THE BUFFER
BEQ :GOTBUF ; {3C2B} IF 0, THEN BUFFER IS UNUSED
LDY #36 ; {3C2B} IF NOT, SKIP TO NEXT LINK
BNE :GBUF0 ; {3C2B} AND RERUN THE SEARCH LOOP
:GOTBUF
LDA ADDR1 ; {3C2B} LOAD FNAME BUFFER LOW BYTE
STA ]FNBUF ; {4C3B} STORE FILENAME BUFFER ADDRESS
LDA ADDR1+1 ; {3C2B} READ THE HIGH BYTE
STA ]FNBUF+1 ; {4C3B} AND STORE AS POINTER ADDRESS
LDY #30 ; {3C2B} INDEX TO FILE MANAGER WORKAREA
LDA (ADDR1),Y ; {6C2B} FOR CONVENIENT STORAGE
STA ]FWORK ; {4C3B} STORE WORKAREA POINTER
INY ; {2C1B} INCREASE .Y INDEX
LDA (ADDR1),Y ; {6C2B} LOAD THE HIGH BYTE
STA ]FWORK+1 ; {4C3B} AND HOLD IT IN ]FWORK
INY ; {2C1B} POINTER TO T/S LIST SECTOR BUFF
LDA (ADDR1),Y ; {6C2B} LOAD LOW BYTE OF TS BUFFER
STA ]FTSLS ; {4C3B} HOLD POINTER IN MEMORY
INY ; {2C1B} INCREASE .Y INDEX
LDA (ADDR1),Y ; {6C2B} LOAD HIGH BYTE
STA ]FTSLS+1 ; {4C3B} AND HOLD
INY ; {6C2B} INC POINTER TO DATA BUFFER
LDA (ADDR1),Y ; {6C2B} LOAD LOW BYTE OF ADDRESS
STA ]FDATA ; {4C3B} STORE IN MEMORY
INY ; {2C1B} INCREASE .Y INDEX
LDA (ADDR1),Y ; {6C2B} LOAD THE HIGH BYTE
STA ]FDATA+1 ; {4C3B} AND STORE AS WELL
CLC ; {2C1B} CLR CARRY TO INDICATE NO ERR
RTS ; {6C1B}
:NBUF
LDA #0 ; {4C3B} LOAD #0 AND CLEAR OUT
STA ]FNBUF ; {4C3B} ALL OF THE ADDRESS POINTERS
STA ]FNBUF+1 ; {4C3B}
STA ]FWORK ; {4C3B}
STA ]FWORK+1 ; {4C3B}
STA ]FTSLS ; {4C3B}
STA ]FTSLS+1 ; {4C3B}
STA ]FDATA ; {4C3B}
STA ]FDATA+1 ; {4C3B}
SEC ; {2C1B} SET CARRY TO INDICATE ERR
RTS ; {6C1B}
*
```
---
### THE _SETPBUFFS SUBROUTINE
_SUMMARY_
| Condition | Value |
| --------------- | -------------------------------------------------------- |
| Name | `_SETPBUFFS` |
| Type | Subroutine |
| File | `HEAD.DOS.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Set the buffers in the File Manager Parameter List (FPL) |
| Input | none |
| Output | none |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 119+ |
| Bytes | 64 |
| Notes | none |
| See Also | `_FMBUFSCAN` |
---
*DETAILS*
The `_SETPBUFFS` subroutine sets the buffer addresses in the **File Manager Parameter List (FPL)** to the appropriate addresses in an open file buffer, as set by `_FMBUFSCAN`. The buffers set include the **Filename Buffer**, the **TS/LS Buffer**, **Data Sector Buffer** and the **File Workarea Buffer**.
The format of the **FPL** slightly changes depending on the command being called, and the number of minor differences are too many to list here for any useful purposes. For a detailed list of how the **FPL** is formatted according to call type, see Don Worth's and Pieter Lechner's *Beneath Apple DOS*. However, there is a general format to the **FPL**, as follows:
**File Manager Parameter List (FPL)**
| Byte | Description |
|--------|-------------------|
|00| Command/Call Type:<br />$01 = OPEN<br />$02 = CLOSE<br />$03 = READ<br />$04 = WRITE<br />$05 = DELETE<br />$06 = CATALOG<br />$07 = LOCK<br />$08 = UNLOCK<br />$09 = RENAME<br />$0A = POSITION<br />$0B = INIT<br />$0C = VERIFY |
|01| Sub-command/Sub-Call Type for READ or WRITE<br />$00 = No operation<br />$01 = READ or WRITE a byte<br />$02 = READ or WRITE a range of bytes<br />$03 = POSITION then READ or WRITE a byte<br />$04 = POSITION then READ or WRITE a range of bytes |
|02-09| Parameters change based on call type. |
|0A| Return Code. Upon returning from the file manager, the CARRY flag is set to indicate a non-zero return code is present. The number here can then be accessed to further understand the return status.<br />$00 = No errors<br />$01 = Language Not Available<br />$02 = Bad call type<br />$03 = Bad sub-call type<br />$04 = Write protected<br />$05 = End of Data<br />$06 = File not found<br />$07 = Volume mismatch<br />$08 = Disk I/O error<br />$09 = Disk full<br />$0A = File locked |
|0B| Unused |
|0C-0D| Address of File Manager Workarea Buffer |
|0E-0F| Address of the TS/LS Buffer |
|10-11| Address of the Data Sector Buffer |
`LISTING 6.04: HEAD.DOS.ASM _SETPBUFFS Routine Source`
```assembly
*
*``````````````````````````````*
* _SETPBUFFS (NATHAN RIGGS) *
* *
* SET THE FILENAME BUFFER, *
* TS/LS BUFFER, DATA BUFFER *
* AND THE FILE WORKAREA *
* BUFFER. *
* *
* INPUT *
* *
* NONE. *
* *
* DESTROY: NZCIDV *
* ^^^ ^ *
* *
* CYCLES: 119+ *
* SIZE: 64 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
_SETPBUFFS
*
LDA ]FPARM ; {4C3B} GET PARAMATER ADDRESS LOW BYTE
STA ADDR1 ; {3C2B} AND HOLD IN ZERO PAGE
LDA ]FPARM+1 ; {4C3B} LOAD HIGH BYTE
STA ADDR1+1 ; {3C2B} INTO ZERO PAGE TOO
LDY #$10 ; {3C2B} POINT TO DATA BUFFER POINTER
LDA ]FDATA ; {4C3B} LOAD DATA BUFFER ADDRESS LOW
STA (ADDR1),Y ; {6C2B} COPY POINTER TO PARAM LOCATION
INY ; {2C1B} INCREASE .Y INDEX
LDA ]FDATA+1 ; {4C3B} LOAD DATA BUFFER ADDR HIGH BYTE
STA (ADDR1),Y ; {6C2B} COPY TO PARAM LOCATION
LDY #$08 ; {3C2B} POINT TO FILENAME BUFFER
LDA ]FNBUF ; {4C3B} LOAD FILENAME BUFFER POINTER ADDR
STA (ADDR1),Y ; {6C2B} AND COPY TO PARAM LOCATION
INY ; {2C1B} INCREASE .Y POINTER
LDA ]FNBUF+1 ; {4C3B} LOAD THE HIGH BYTE
STA (ADDR1),Y ; {6C2B} AND COPY AS WELL
LDY #$0E ; {3C2B} T/S LIST SECTOR BUFFER POINTER
LDA ]FTSLS ; {4C3B} LOAD CURRENT POINTER LOW BYTE
STA (ADDR1),Y ; {6C2B} AND COPY TO PARAM LOCATION
INY ; {2C1B} INCREASE .Y INDEX
LDA ]FTSLS+1 ; {3C2B} LOAD THE HIGH BYTE
STA (ADDR1),Y ; {6C2B} AND COPY TO PARAM LOCATION
LDY #$0C ; {3C2B} WORKAREA BUFFER OFFSET IN PARAM
LDA ]FWORK ; {4C3B} LOAD CURRENT WORKAREA POINTER
STA (ADDR1),Y ; {6C2B} COPY TO PARAMETER LIST
INY ; {2C1B} INCREASE .Y INDEX
LDA ]FWORK+1 ; {4C3B} LOAD HIGH BYTE
STA (ADDR1),Y ; {6C2B} AND COPY AS WELL
*
RTS ; {6C3B}
*
```
---
### THE _NAMESTR SUBROUTINE
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `_NAMESTR` |
| Type | Subroutine |
| File | `HEAD.DOS.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Copy filename from standard string format to the 30-byte string expected by DOS |
| Input | none |
| Output | none |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 64+ |
| Bytes | 42 |
| Notes | none |
| See Also | `_NAMESTR2` `_FN2BUFF` `_FMNM2` |
---
*DETAILS*
The `_NAMESTR` subroutine is an internal procedure for transferring a standard preceding length-byte string to a temporary fixed 30-byte memory address that fills the empty bytes with spaces (this is determined by subtracting the string length from 30, which equals the number of trailing spaces needed). This subroutine should be called prior to calling the File Manager, given that the filename is not the same as the previous call.
`LISTING 6.05: HEAD.DOS.ASM _NAMESTR Routine Source`
```assembly
*
*``````````````````````````````*
* _NAMESTR (NATHAN RIGGS) *
* *
* COPY FILENAME FROM STANDARD *
* STRING TO THE 30-BYTE STRING *
* EXPECTED BY DOS IN A TEMP *
* MEMORY AREA. *
* *
* INPUT *
* *
* .A = FILENAME STR ADDR LOW *
* .X = HIGH BYTE *
* *
* DESTROY: NZCIDV *
* ^^^ ^ *
* *
* CYCLES: 64+ *
* SIZE: 42 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
_NAMESTR
*
LDY #0 ; {3C2B}
STA ADDR1 ; {3C2B} CLEAR OUT ZERO LOCATION
STX ADDR1+1 ; {3C2B}
LDA (ADDR1),Y ; {6C2B} GET STRING LENGTH
STA BPAR1 ; {3C2B} HOLD TEMP IN ZERO PAGE
LDY #0 ; {3C2B} RESET .Y INDEX
LDX #255 ; {3C2B} SET .X INDEX TO -1
:_NSLP1
INX ; {2C1B} INCREASE .X INDEX
INY ; {2C1B} INCREASE .Y INDEX
LDA (ADDR1),Y ; {6C2B} GET CHARACTER
STA ]FNAME,X ; {5C3B} STORE AT Y-1 LOC IN HOLD AREA
CPX #29 ; {3C2B} COMPARE TO MAX STRING LENGTH
BEQ :_NSEXIT ; {3C2B} IF MAX IS REACHED, EXIT
CPY BPAR1 ; {3C2B} OTHERWISE COMPARE TO STRING LENGTH
BNE :_NSLP1 ; {3C2B} IF NOT EQUAL, RELOOP TO NEXT CHAR
:_NSLP2
INX ; {2C1B} STILL INCREASE .X INDEX
LDA #" " ; {4C3B} NEXT CHAR IS SPACE
STA ]FNAME,X ; {5C3B} STORE IN NAME AREA AT .X
CPX #29 ; {3C2B} CHECK NEW STRING LENGTH
BNE :_NSLP2 ; {3C2B} IF < 30, KEEP LOOPING
:_NSEXIT
RTS ; {6C1B}
*
```
---
### THE _NAMESTR2 SUBROUTINE
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `_NAMESTR2` |
| Type | Subroutine |
| File | `HEAD.DOS.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Copy second filename from standard string <br />format to the 30-byte string expected by DOS |
| Input | none |
| Output | none |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 64+ |
| Bytes | 42 |
| Notes | none |
| See Also | `_NAMESTR` `_FN2BUFF` `_FMNM2` |
---
*DETAILS*
The `_NAMESTR2` subroutine accomplishes the same task as `_NAMESTR`, but does so for a second filename that is needed for procedures like renaming a file. This subroutine will likely be merged with the `_NAMESTR` subroutine in future revisions.
`LISTING 6.06: HEAD.DOS.ASM _NAMESTR2 Routine Source`
```assembly
*
*``````````````````````````````*
* _NAMESTR2 (NATHAN RIGGS) *
* *
* FULFILLS THE SAME FUNCTION *
* AS _NAMESTR, EXCEPT FOR A *
* SECOND STRING USED BY CMDS *
* LIKE RENAME. *
* *
* .A = STRING ADDR LOW BYTE *
* .X = STRING ADDR HIGH BYTE *
* *
* DESTROY: NZCIDV *
* ^^^ ^ *
* *
* CYCLES: 64+ *
* SIZE: 42 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
_NAMESTR2
*
LDY #0 ; {3C2B}
STA ADDR1 ; {3C2B} CLEAR OUT ZERO LOCATION
STX ADDR1+1 ; {3C2B}
LDA (ADDR1),Y ; {6C3B} GET STRING LENGTH
STA BPAR1 ; {3C2B} HOLD TEMP IN ZERO PAGE
LDY #0 ; {3C2B} RESET .Y INDEX
LDX #255 ; {3C2B} SET .X INDEX TO -1
:_NSLP1
INX ; {2C1B} INCREASE .X INDEX
INY ; {2C1B} INCREASE .Y INDEX
LDA (ADDR1),Y ; {6C2B} GET CHARACTER
STA ]FNAME2,X ; {5C2B} STORE AT Y-1 LOC IN HOLD AREA
CPX #29 ; {3C2B} COMPARE TO MAX STRING LENGTH
BEQ :_NSEXIT ; {3C2B} IF MAX IS REACHED, EXIT
CPY BPAR1 ; {3C2B} OTHERWISE COMPARE TO STRING LENGTH
BNE :_NSLP1 ; {3C2B} IF NOT EQUAL, RELOOP TO NEXT CHAR
:_NSLP2
INX ; {2C1B} STILL INCREASE .X INDEX
LDA #" " ; {4C3B} NEXT CHAR IS SPACE
STA ]FNAME2,X ; {5C2B} STORE IN NAME AREA AT .X
CPX #29 ; {2C2B} CHECK NEW STRING LENGTH
BNE :_NSLP2 ; {3C2B} IF < 30, KEEP LOOPING
:_NSEXIT
RTS ; {6C1B}
*
```
---
### THE _FN2BUFF SUBROUTINE
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------- |
| Name | `_FN2BUFF` |
| Type | Subroutine |
| File | `HEAD.DOS.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Copy temporary 30-byte filename to the filename buffer. |
| Input | none |
| Output | none |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 41+ |
| Bytes | 22 |
| Notes | none |
| See Also | `_NAMESTR` `_NAMESTR2` `_FMNM2` |
---
*DETAILS*
The `_FN2BUFF` subroutine simply copies the 30-byte filename created by `_NAMESTR` to the filename buffer for use by the File Manager.
`LISTING 6.07: HEAD.DOS.ASM _FN2BUFF Routine Source`
```assembly
*
*``````````````````````````````*
* _FN2BUFF (NATHAN RIGGS) *
* *
* MOVE THE TEMPORARY 30-BYTE *
* FILENAME STRING INTO THE *
* FILENAME BUFFER OF THE FILE *
* BUFFER IN USE. *
* *
* INPUT *
* *
* NONE. *
* *
* DESTROY: NZCIDV *
* ^^^ ^ *
* CYCLES: 41+ *
* SIZE: 22 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
_FN2BUFF
*
LDA ]FNBUF ; {4C3B} LOAD FILENAME BUFFER ADDR
STA ADDR2 ; {3C2B} STORE LOW IN ZERO
LDA ]FNBUF+1 ; {4C3B}
STA ADDR2+1 ; {3C2B} STORE HIGH IN ZERO
LDY #255 ; {3C2B} SET .Y INDEX TO -1
:_LPC1
INY ; {2C1B} INCREASE .Y INDEX
LDA ]FNAME,Y ; {5C2B} GET CHAR STORED IN NAME AREA
STA (ADDR2),Y ; {6C2B} STORE IN FILENAME BUFFER
CPY #29 ; {2C2B} IS THE END OF STRING REACHED?
BNE :_LPC1 ; {3C2B} IF NO, KEEP LOOPING
RTS ; {6C1B}
*
```
---
### THE _FMNM2 SUBROUTINE
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `_FMNM2` |
| Type | Subroutine |
| File | `HEAD.DOS.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Register the address of the second filename<br /> to be used by the File Manager. |
| Input | none |
| Output | none |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 55+ |
| Bytes | 30 |
| Notes | none |
| See Also | `_NAMESTR` `_NAMESTR2` `_FN2BUFF` |
---
*DETAILS*
The `_FMNM2` subroutine is functionally equivalent to the `_FN2BUFF` subroutine except for a second filename, which is usually a destination filename. Although equivalent, the process for `_FMNM2` is different than `_FN2BUFF` and therefore cannot be merged into a single subroutine.
`LISTING 6.08: HEAD.DOS.ASM _FMNM2 Routine Source`
```assembly
*
*``````````````````````````````*
* _FMNM2 (NATHAN RIGGS) *
* *
* REGISTER THE ADDRESS OF THE *
* SECOND FILENAME IN THE FILE *
* PARAMETER LIST. *
* *
* INPUT *
* *
* NONE. *
* *
* DESTROY: NZCIDV *
* ^^^ ^ *
* CYCLES: 55+ *
* SIZE: 30 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
_FMNM2
LDA #]FNAME2 ; {3C2B}
LDX #>]FNAME2 ; {3C2B}
STA ADDR2 ; {3C2B} LOW BYTE OF REC ADDRESS IN .A
STX ADDR2+1 ; {3C2B} HIGH BYTE IN .X
LDA ]FPARM ; {4C3B} LOAD PARAM ADDRESS
STA ADDR1 ; {3C2B} AND HOLD IN ZERO PAGE
LDA ]FPARM+1 ; {4C3B} ALSO DO FOR HIGH BYTE
STA ADDR1+1 ; {3C2B}
LDY #$02 ; {3C2B} OFFSET TO THE RECORD VARIABLE
LDA ADDR2 ; {3C2B} LOAD LOW BYTE
STA (ADDR1),Y ; {6C2B} AND STORE IN PARAM LIST
INY ; {2C1B} INCREASE .Y INDEX
LDA ADDR2+1 ; {3C2B} LOAD HIGH BYTE
STA (ADDR1),Y ; {6C2B} AND STORE IN PARAM LIST
RTS ; {6C1B}
*
```
---
### THE _BUFFCLEAR SUBROUTINE
_SUMMARY_
| Condition | Value |
| --------------- | -------------------------------------------- |
| Name | `_BUFFCLEAR` |
| Type | Subroutine |
| File | `HEAD.DOS.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Clear the current file buffer for use again. |
| Input | none |
| Output | none |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 31+ |
| Bytes | 17 |
| Notes | none |
| See Also | `_FMBUFFSCAN` |
---
*DETAILS*
The `_BUFFCLEAR` subroutine clears out the last used file buffer for use again in the future. It does this by replacing the first byte in the filename buffer with the value **#$00**, which indicates to DOS that the buffer is free. This subroutine should be called whenever a program is finished using a file and closes it; otherwise, the file buffer will not be cleared, and multiple uses of the file buffers will eventually result in error.
`LISTING 6.09: HEAD.DOS.ASM _BUFFCLEAR Routine Source`
```assembly
*
*``````````````````````````````*
* _BUFFCLEAR (NATHAN RIGGS) *
* *
* CLEAR THE FILE BUFFER THAT *
* IS CURRENTLY IN USE SO THAT *
* THE BUFFER MAY BE REUSED. *
* *
* INPUT *
* *
* NONE. *
* *
* CYCLES: 31+ *
* SIZE: 17 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
_BUFFCLEAR
*
LDA ]FNBUF ; {4C3B} GET FILENAME BUFFER ADDR
STA ADDR2 ; {3C2B} STORE IN ZERO
LDA ]FNBUF+1 ; {4C3B} DO SAME FOR HIGH BYTE
STA ADDR2+1 ; {3C2B}
LDA #0 ; {3C2B} RESET .A
TAY ; {2C1B} AND .Y
STA (ADDR2),Y ; {6C3B} STORE #00 IN FIRST SPOT
RTS ; {6C1B} TO INDICATE EMPTY BUFFER
*
```
---
### THE _FMPSET SUBROUTINE
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------ |
| Name | `_FMPSET` |
| Type | Subroutine |
| File | `HEAD.DOS.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Set a file parameter. |
| Input | .A = Value<br />.Y = File Parameter Offset |
| Output | none |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 30+ |
| Bytes | 16 |
| Notes | none |
| See Also | `_FMPSETA` `_FMPGET` `_FMPGETA` |
---
*DETAILS*
The `_FMPSET` subroutine sets a file parameter in the **FPL** indicated by the offset held in the **.Y** register to the value held in the **.A** register. This only sets a single byte.
`LISTING 6.10: HEAD.DOS.ASM _FMPSET Routine Source`
```assembly
*
*``````````````````````````````*
* _FMPSET (NATHAN RIGGS) *
* *
* SET A FILE PARAMTER TO THE *
* VALUE HELD IN .A AT THE *
* OFFSET INDICATED BY .Y. *
* *
* INPUT *
* *
* .A = VALUE *
* .Y = FILE PARAMETER OFFSET *
* *
* DESTROY: NZCIDV *
* ^^^ ^ *
* *
* CYCLES: 30+ *
* SIZE: 16 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
_FMPSET
; .Y HOLDS THE OFFSET
TAX ; {2C1B} .A HOLDS THE VALUE
LDA ]FPARM ; {4C3B} LOAD FILE MGR PARAMETER LOW
STA ADDR1 ; {3C2B} HOLD ON ZERO PAGE
LDA ]FPARM+1 ; {4C3B} LOAD HIGH BYTE
STA ADDR1+1 ; {3C2B} ONTO ZERO PAGE
TXA ; {2C1B} RETURN VALUE BACK TO .A
STA (ADDR1),Y ; {6C3B} STORE VALUE AT OFFSET IN PARAMS
RTS ; {6C1B}
*
```
---
### THE _FMPSETA SUBROUTINE
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `_FMPSETA` |
| Type | Subroutine |
| File | `HEAD.DOS.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Set a file parameter. |
| Input | .A = Value Low Byte<br />.X = Value High Byte<br />.Y = File Parameter Offset |
| Output | none |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 46+ |
| Bytes | 26 |
| Notes | none |
| See Also | `_FMPSET` `_FMPGET` `_FMPGETA` |
---
*DETAILS*
The `_FMPSETA` subroutine sets a file parameter address in the **FPL** indicated by the offset held in the **.Y** register to the value held in the **.A** register (low byte) and the **.X** register (high byte), setting a two consecutive bytes.
`LISTING 6.11: HEAD.DOS.ASM _FMPSETA Routine Source`
```assembly
*
*``````````````````````````````*
* _FMPSETA (NATHAN RIGGS) *
* *
* SET A TWO-BYTE VALUE, SUCH *
* AS AN ADDRESS, IN THE FILE *
* PARAMETER LIST. *
* *
* INPUT *
* *
* .A = LOWEST BYTE *
* .X = HIGHEST BYTE *
* .Y = OFFSET VALUE *
* *
* DESTROY: NZCIDV *
* ^^^ ^ *
* *
* CYCLES: 46+ *
* SIZE: 26 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
_FMPSETA
; .Y HOLDS THE OFFSET
STA ADDR2 ; {3C2B} .A HOLDS LOW BYTE OF ADDR
STX ADDR2+1 ; {3C2B} .X HOLDS ADDR HIGH BYTE
LDA ]FPARM ; {4C3B} LOAD FILE MGR PARAMETER LOW
STA ADDR1 ; {3C2B} HOLD ON ZERO PAGE
LDA ]FPARM+1 ; {4C3B} LOAD HIGH BYTE
STA ADDR1+1 ; {3C2B} ONTO ZERO PAGE
LDA ADDR2 ; {3C2B}
STA (ADDR1),Y ; {6C3B} STORE VAL AT OFFSET IN PARAMS
LDA ADDR2+1 ; {3C2B}
INY ; {2C1B}
STA (ADDR1),Y ; {6C3B}
RTS ; {6C1B}
*
```
---
### THE _FMPGET SUBROUTINE
_SUMMARY_
| Condition | Value |
| --------------- | --------------------------------------- |
| Name | `_FMPGET` |
| Type | Subroutine |
| File | `HEAD.DOS.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Retrieve a file parameter from the FPL. |
| Input | .Y = File Parameter Offset |
| Output | none |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 26+ |
| Bytes | 14 |
| Notes | none |
| See Also | `_FMPGETA` `_FMPSET` `_FMPSETA` |
---
*DETAILS*
The `_FMPGET` subroutine retrieves a single byte from a given parameter in the **FPL**, as indicated by the offset held in **.Y**.
`LISTING 6.12: HEAD.DOS.ASM _FMPGET Routine Source`
```assembly
*
*``````````````````````````````*
* _FMPGET (NATHAN RIGGS) *
* *
* GET A VALUE RETURNED FROM *
* THE FILE MANAGER AFTER IT *
* RUNS. THIS VALUE IS HELD AT *
* AN OFFSET IN THE FILE PARAM *
* LIST. *
* *
* INPUT: *
* *
* .Y = OFFSET TO READ *
* *
* DESTROY: NZCIDV *
* ^^^ ^ *
* *
* CYCLES: 26+ *
* SIZE: 14 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
_FMPGET
; OFFSET IS PASSED IN .Y
LDA ]FPARM ; {4C3B}
STA ADDR1 ; {3C2B}
LDA ]FPARM+1 ; {4C3B}
STA ADDR1+1 ; {3C2B}
LDA (ADDR1),Y ; {6C3B} VALUE RETURNED IN .A
RTS ; {6C1B}
*
```
---
### THE _FMPGETA SUBROUTINE
_SUMMARY_
| Condition | Value |
| --------------- | -------------------------------------------------------- |
| Name | `_FMPGETA` |
| Type | Subroutine |
| File | `HEAD.DOS.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Retrieve a two-byte address file parameter from the FPL. |
| Input | .Y = File Parameter Offset |
| Output | none |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 42+ |
| Bytes | 21 |
| Notes | none |
| See Also | `_FMPGET` `_FMPSET` `_FMPSETA` |
---
*DETAILS*
The `_FMPGETA` subroutine retrieves two consecutive bytes from the offset held in **.Y** in the **FPL**. This is usually an address; the low byte is returned in **.A** and the high byte is returned in **.X**.
`LISTING 6.13: HEAD.DOS.ASM _FMPGETA Routine Source`
```assembly
*
*``````````````````````````````*
* _FMPGETA (NATHAN RIGGS) *
* *
* RETRIEVE A 2-BYTE VALUE LIKE *
* AN ADDRESS FROM THE FILE *
* PARAMETER LIST AT THE GIVEN *
* OFFSET. *
* *
* INPUT *
* *
* .Y = OFFSET INDEX *
* *
* DESTROY: NZCIDV *
* ^^^ ^ *
* *
* CYCLES: 42+ *
* SIZE: 21 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
_FMPGETA
; OFFSET PASSED IN .Y
LDA ]FPARM ; {4C3B}
STA ADDR1 ; {3C2B}
LDA ]FPARM+1 ; {4C3B}
STA ADDR1+1 ; {3C2B}
LDA (ADDR1),Y ; {6C3B} GET LOW BYTE
PHA ; {3C1B} HOLD ON STACK
INY ; {2C1B} INCREASE INDEX
LDA (ADDR1),Y ; {6C3B} GET HIGH BYTE
TAX ; {2C1B} PASS BACK IN .X
PLA ; {3C1B} PASS LOW IN .A
RTS ; {6C1B}
*
```
---
## Required DOS Macros
The MAC.DOSREQ.ASM file contains various macros that are required to be included (USE) in order for the entire DOS collection to function. This is unlike other collections, which usually do not require a separate macro file that the other macros and subroutines depend upon. While these macros could be replaced in each macro and subroutine with the appropriate code, the Merlin 8 Pro compiler would quickly run into memory management issues due to limitations on file size.
Most of these macros call a combination of the subroutines found in the HEAD.DOS.ASM file, and should be used in place of calling the subroutines directly.
`LISTING 6.20: MAC.DOSREQ.ASM Heading Source`
```assembly
*
*``````````````````````````````*
* MAC.DOSREQ.ASM *
* *
* THESE MACROS ARE REQUIRED *
* FOR USING THE DOS MACROS AND *
* SUBROUTINES. GENERALLY, THIS *
* INCLUDES LOW LEVEL ROUTINES *
* AND MACRO SHORTCUTS TO SAVE *
* MEMORY DURING ASSEMBLY. *
* *
* AUTHOR: NATHAN RIGGS *
* CONTACT: NATHAN.RIGGS@ *
* OUTLOOK.COM *
* *
* DATE: 06-MAY-2021 *
* ASSEMBLER: MERLIN 8 PRO *
* OS: DOS 3.3 *
* *
* SUBROUTINE FILES USED *
* *
* *
* LIST OF MACROS *
* *
* SRWTS : SET RWTS PARAMETERS *
* GRWTS : RUN RWTS ROUTINE *
* FMFIL : FILL FILE MGR PARAMS *
* FMNAM : STRING TO PARAM AREA *
* FRWB : BYTE READ/WRITE MAC *
* FWRTB : WRITE A BYTE TO FILE *
* FRDB : READ BYTE FROM FILE *
* FRWR : RANGE READ/WRITE MAC *
* FRDR : READ RANGE FROM FILE *
* FWRTR : WRITE RANGE TO FILE *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
```
---
### THE SRWTS MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `SRWTS` |
| Type | Macro |
| File | `MAC.DOSREQ.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Set common RWTS parameters. |
| Input | ]1 = Slot<br />]2 = Drive<br />]3 = Volume<br />]4 = Track<br />]5 = Sector<br />]6 = Buffer Address<br />]7 = Command |
| Output | none |
| Dependencies | `_SETRWTS` |
| Flags Destroyed | NZCV |
| Cycles | 228+ |
| Bytes | 141 |
| Notes | none |
| See Also | `_SETRWTS` |
---
*DETAILS*
The `SRWTS` macro sets the most common parameters used in the **IOB** before calling the **RWTS** routine. This includes the slot, drive, volume, track, sector, buffer address and **RWTS** command. If the volume is set to **#0**, then any volume will be acceptable for **RWTS**.
`LISTING 6.21: MAC.DOSREQ.ASM SRWTS Macro Source`
```assembly
*
*``````````````````````````````*
* SETRWTS *
* *
* SET THE PARAMETERS FOR RWTS. *
* *
* PARAMETERS *
* *
* ]1 = RWTS SLOT *
* ]2 = RWTS DRIVE *
* ]3 = RWTS VOLUME *
* ]4 = RWTS TRACK *
* ]5 = RWTS SECTOR *
* ]6 = RWTS BUFFER *
* ]7 = RWTS COMMAND *
* *
* CYCLES: 228+ *
* SIZE: 141 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
SRWTS MAC
LDA ]1 ; {4C3B} RWTS SLOT
STA MSLOT ; {4C3B}
LDA ]2 ; {4C3B} RWTS DRIVE
STA MDRIVE ; {4C3B}
LDA ]3 ; {4C3B} RWTS VOLUME
STA MVOL ; {4C3B}
LDA ]4 ; {4C3B} RWTS TRACK
STA MTRACK ; {4C3B}
LDA ]5 ; {4C3B} RWTS SECTOR
STA MSECTOR ; {4C3B}
IF #=]6 ; IF VALUE IS A LITERAL
LDA ]6 ; {4C3B} THEN STORE LITERAL
STA MBUFFER ; {4C3B} LOW AND HIGH BYTES
LDA ]6/$100 ; {4C3B}
STA MBUFFER+1 ; {4C3B}
ELSE ; OTHERWISE,
LDA ]6 ; {4C3B} LOAD VALUE FROM ADDRESS
STA MBUFFER ; {4C3B} AND STORE IN BUFFER
LDA ]6+1 ; {4C3B} ADDRESS POINTER
STA MBUFFER+1 ; {4C3B}
FIN
LDA ]7 ; {4C3B} RWTS COMMAND
STA MCMD ; {4C3B}
JSR _SETRWTS ; {148C81B} SET THE PARAMETERS
<<<
*
```
---
### THE GRWTS MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------- |
| Name | `GRWTS` |
| Type | Macro |
| File | `MAC.DOSREQ.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Run the DOS RWTS Routine. |
| Input | none |
| Output | none |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 19+ |
| Bytes | 11 |
| Notes | none |
| See Also | `SRWTS` |
---
*DETAILS*
The `GRWTS` macro simply runs the **RWTS** routine found in DOS. At the very least, the `SRWTS` macro should be called beforehand to set the various parameters used by **RWTS**.
`LISTING 6.22: MAC.DOSREQ.ASM GRWTS Macro Source`
```assembly
*
*``````````````````````````````*
* GRWTS *
* *
* RUN THE RWTS ROUTINE. *
* *
* PARAMETERS *
* *
* NONE. *
* *
* CYCLES: 19+ *
* SIZE: 11 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
GRWTS MAC
JSR ]LOCRPL ; {6C3B} (GET ]LOCRPL CYCLES/SIZE)
JSR ]RWTS ; {6C3B} (GET CYCLES/SIZE)
LDA #0 ; {3C2B}
STA $48 ; {4C3B} FIX P REG FOR DOS
<<<
*
```
---
### THE FMFIL MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `FMFIL` |
| Type | Macro |
| File | `MAC.DOSREQ.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Fill the most common parameters in the FPL. |
| Input | ]1 = Command<br />]2 = Slot<br />]3 = Drive<br />]4 = Volume<br />]5 = Record Number |
| Output | none |
| Dependencies | `_FMGETPARM` `_FMBUFFSCAN` `_SETPBUFFS` `_FMPSET` `_FMPSETA` |
| Flags Destroyed | NZCV |
| Cycles | 603+ |
| Bytes | 303 |
| Notes | none |
| See Also | `SRWTS` `FMNAM` |
---
*DETAILS*
The `FMFIL` macro fills out the most common parameters used in the **File Parameter List (FPL)**. This includes the file command, slot, drive, volume, and record number. Note that not all of these are applicable to every use. Like with `SRWTS`, the volume can be set to **#0** to indicate that any volume is acceptable.
`LISTING 6.23: MAC.DOSREQ.ASM FMFIL Macro Source`
```assembly
*
*``````````````````````````````*
* FMFIL (NATHAN RIGGS) *
* *
* FILLS THE MOST COMMON AREAS *
* IN THE FILE PARAMETERS. THIS *
* INCLUDES THE COMMAND, SLOT, *
* DISK, VOLUME AND RECORD. *
* *
* PARAMETERS *
* *
* ]1 = COMMAND *
* ]2 = SLOT *
* ]3 = DRIVE *
* ]4 = VOLUME (0 FOR ANY) *
* ]5 = RECORD NUMBER *
* *
* CYCLES: 603+ *
* SIZE: 303 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
FMFIL MAC
JSR _FMGETPARM ; {26C13B} GET FILE PARAMS ADDRESS
JSR _FMBUFFSCAN ; {217C120B} SCAN FOR FREE FILE BUFF
JSR _SETPBUFFS ; {125C67B} SET PARAMETER BUFFERS
LDA ]1 ; {4C3B} COMMAND TO PARAMETERS
LDY #]P_CMD ; {3C2B} SET INDEX TO COMMAND OFFSET
JSR _FMPSET ; {36C19B} SET COMMAND
LDA ]2 ; {4C3B} SLOT TO PARAMETERS
LDY #]P_SLOT ; {3C2B} SET INDEX TO SLOT OFFSET
JSR _FMPSET ; {36C19B} SET SLOT
; VOLUME AND RECORD NUMBER
LDA ]3 ; {4C3B} DRIVE TO PARAMETERS
LDY #]P_DRV ; {3C2B} SET INDEX TO DRIVE OFFSET
JSR _FMPSET ; {36C19B} SET DRIVE
LDA ]4 ; {4C3B} VOLUME TO PARAMS, 0 FOR ANY
LDY #]P_VOL ; {3C2B} SET INDEX TO VOLUME OFFSET
JSR _FMPSET ; {36C19B} SET VOLUME
_AXLIT ]5 ; {8C6B}
LDY #]P_REC ; {3C2B} SET INDEX TO RECORD OFFSET
JSR _FMPSETA ; {52C29B} SET RECORD LOW AND HIGH
<<<
*
```
---
### THE FMNAM MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `FMNAM` |
| Type | Macro |
| File | `MAC.DOSREQ.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Copy a string with a preceding length-byte to the filename buffer. |
| Input | ]1 = Source string address |
| Output | none |
| Dependencies | `_NAMESTR` `_FN2BUFF` |
| Flags Destroyed | NZCV |
| Cycles | 117+ |
| Bytes | 70 |
| Notes | none |
| See Also | `FMFIL` |
---
*DETAILS*
The `FMNAM` macro copies a string with a preceding length-byte into a 30-byte memory location, filling the unused bytes in the destination with spaces. This is then copied to the **Filename Buffer** in a currently used file buffer. This filename is used for commands such as deletion, verification, opening and closing, and so on. This is also used with the renaming command, with the addition of a destination filename.
`LISTING 6.24: MAC.DOSREQ.ASM FMNAM Macro Source`
```assembly
*
*``````````````````````````````*
* FMNAM (NATHAN RIGGS) *
* *
* COPY A STRING HOLDING THE *
* NAME OF A FILE BEING HANDLED *
* TO A 30-BYTE LOCATION FILLED *
* WITH SPACES, THEN COPY THAT *
* TO THE FILE PARAMETER LIST. *
* *
* PARAMETERS *
* *
* ]1 = ADDRESS OF STRING *
* *
* CYCLES: 117+ *
* SIZE: 70 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
FMNAM MAC
_AXLIT ]1
JSR _NAMESTR ; {70C45B} COPY STRING TO TEMP BUFF
JSR _FN2BUFF ; {47C25B} COPY TEMP BUFF TO FNAME BUFF
<<<
*
```
---
### THE FRWB MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `FRWB` |
| Type | Macro |
| File | `MAC.DOSREQ.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Read or write a byte in a file. |
| Input | ]1 = Read/Write flag<br />]2 = Command<br />]3 = Slot<br />]4 = Drive<br />]5 = Volume<br />]6 = Record Number<br />]7 = Byte offset<br />]8 = Byte to write, if writing |
| Output | none |
| Dependencies | `FMFIL` `_FMPSET` `_FMPSETA` |
| Flags Destroyed | NZCV |
| Cycles | 779+ |
| Bytes | 404 |
| Notes | none |
| See Also | `FWRTB` `FRDB` `FRWR` `FRDR` `FWRTR` |
---
*DETAILS*
The `FRWB` Macro either reads or writes a single byte in an open file, depending on which flag is provided the macro in the first parameter. Usually, this macro is used internally, rather than by the end user; the `FWRTB` macro and the `FRDB` macro are used instead to write and read a byte in a file. If writing, the eighth parameter is set to the byte to write; if not, this parameter is ignored. It should also be noted that this macro does not return a value when reading a byte; instead, this is handled by the `FRDB` macro, as the byte is returned by the file manager in the **File Parameter List (FPL)**.
As usual, a **#0** value can be passed to the volume parameter to indicate that any volume is acceptable.
`LISTING 6.25: MAC.DOSREQ.ASM FRWB Macro Source`
```assembly
*
*``````````````````````````````*
* FRWB (NATHAN RIGGS) *
* *
* EITHER READ OR WRITE A BYTE. *
* THIS USUALLY ISN'T CALLED *
* DIRECTLY, BUT THROUGH *
* ANOTHER MACRO. *
* *
* PARAMETERS *
* *
* ]1 = READ/WRITE FLAG (#3/4) *
* ]2 = COMMAND *
* ]3 = SLOT *
* ]4 = DRIVE *
* ]5 = VOLUME (0 FOR ANY) *
* ]6 = RECORD NUMBER *
* ]7 = BYTE OFFSET *
* ]8 = BYTE TO WRITE (0 READ) *
* *
* CYCLES: 779+ *
* SIZE: 404 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
FRWB MAC
*
FMFIL ]2;]3;]4;]5;]6 ; {603C303B}
*
LDA ]1 ; {4C3B} READ OR WRITE FLAG
LDY #]P_RDWR ; {3C2B} INDEX TO READ/WRITE FLAG
JSR _FMPSET ; {30C16B} SET THE READ/WRITE FLAG
LDA #]SC_PRWB ; {3C2B} SET POS THEN READ OR WRITE
LDY #]P_SUBC ; {3C2B} SET INDEX TO SUBCODE OFFSET
JSR _FMPSET ; {30C16B} SET THE SUBCODE
_AXLIT ]7 ; {8C6B}
LDY #]P_BOFF ; {3C2B} INDEX TO BYTE OFFSET
JSR _FMPSETA ; {46C26B} SET TWO BYTE OFFSET VALUE
LDA ]8 ; {4C3B} BYTE TO WRITE, IF WRITING
LDY #]P_BYTE ; {3C2B} WRITE BYTE
JSR _FMPSET ; {30C16B} SET BYTE
LDX #1 ; {3C2B} DON'T CREATE NEW FILE
JSR ]FMRUN ; {6C3B} RUN FILE MANAGER
<<<
*
```
---
### THE FWRTB MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `FWRTB` |
| Type | Macro |
| File | `MAC.DOSREQ.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Write a byte to a file. |
| Input | ]1 = Slot<br />]2 = Drive<br />]3 = Volume<br />]4 = Record number<br />]5 = Byte offset<br />]6 = Byte to write |
| Output | none |
| Dependencies | `_FMPGET` `_BUFFCLEAR` |
| Flags Destroyed | NZCV |
| Cycles | 665+ |
| Bytes | 337 |
| Notes | none |
| See Also | `FRWB` `FRDB` `FRWR` `FRDR` `FWRTR` `FOPEN` `FCLOS` |
---
*DETAILS*
The `FWRTB` macro is used for writing a single byte at a time to an open file. Like with most File Manager operations, a value of **#0** placed in the volume parameter indicates that any volume is acceptable.
Records in files work much the same way as they do in Applesoft BASIC: each record in a file is separated by a carriage return (**#$8D**), with the zeroth record being the first string of text prior to the first carriage return. These are usually used with text files, which are only marginally supported by the DOS collection: binary files make much more sense to use in Assembly, even when the data itself represents text characters. This is not to say that text files cannot be used--the `FOPEN` macro allows you to read and write text files--but that it is better for the end programmer to devise his or her own system for dealing with text files, as there is no standard method for recognizing an End-of-File (EOF) marker. Both binary files and text files can be fully read into memory before being parsed by a given routine.
The byte offset is particularly useful with `FWRTB`, as without it only the first byte of the file could be written. A byte counter can be used to read or write each consecutive byte at a time, passing the counter value via the offset.
The `FOPEN` macro should be called before `FWRTB`, and the `FCLOS` macro should be called when all operations on the file are finished.
`LISTING 6.26: MAC.DOSREQ.ASM FWRTB Macro Source`
```assembly
*
*``````````````````````````````*
* FWRTB (NATHAN RIGGS) *
* *
* WRITE A BYTE TO A FILE. *
* *
* PARAMETERS *
* *
* ]1 = SLOT *
* ]2 = DRIVE *
* ]3 = VOLUME *
* ]4 = RECORD NUMBER *
* ]5 = BYTE OFFSET *
* ]6 = BYTE TO WRITE (0 READ) *
* *
* CYCLES: 665+ *
* SIZE: 337 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
FWRTB MAC
*
** FRWB ARGUMENTS
**
** ]1 = READ OR WRITE CODE (3 = READ, 4 = WRITE)
** ]2 = READ OR WRITE COMMAND
** ]3 = SLOT
** ]4 = DRIVE
** ]5 = VOLUME (0 FOR ANY)
** ]6 = RECORD NUMBER
** ]7 = BYTE OFFSET
** ]8 = BYTE TO WRITE, IF WRITING
*
FRWB #4;#]FC_WRIT;]1;]2;]3;]4;]5;]6 ; {603C303B}
*
LDY #]P_RETC ; {3C2B} INDEX TO RETURN CODE OFFSET
JSR _FMPGET ; {26C14B} GET THE RETURN CODE
TAX ; {2C1B} PASS BACK IN .X
JSR _BUFFCLEAR ; {31C17B} CLEAR FILE BUFFER FOR USE
<<<
*
```
---
### THE FRDB MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `FRDB` |
| Type | Macro |
| File | `MAC.DOSREQ.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Read a byte from a file. |
| Input | ]1 = Slot<br />]2 = Drive<br />]3 = Volume<br />]4 = Record number<br />]5 = Byte offset<br />]6 = Byte to write (always 0) |
| Output | none |
| Dependencies | `_FMPGET` `_BUFFCLEAR` |
| Flags Destroyed | NZCV |
| Cycles | 700+ |
| Bytes | 357 |
| Notes | none |
| See Also | `FRWB` `FWRTB` `FRWR` `FRDR` `FWRTR` |
---
*DETAILS*
The `FRDB` macro reads a byte from an open file and returns the byte in the **.A** register. If the volume is set to **#0**, any volume will be accepted.
Records in files work much the same way as they do in Applesoft BASIC: each record in a file is separated by a carriage return (**#$8D**), with the zeroth record being the first string of text prior to the first carriage return. These are usually used with text files, which are only marginally supported by the DOS collection: binary files make much more sense to use in Assembly, even when the data itself represents text characters. This is not to say that text files cannot be used--the `FOPEN` macro allows you to read and write text files--but that it is better for the end programmer to devise his or her own system for dealing with text files, as there is no standard method for recognizing an End-of-File (EOF) marker. Both binary files and text files can be fully read into memory before being parsed by a given routine.
The byte offset is particularly useful with `FRDB`, as without it only the first byte of the file could be read. A byte counter can be used to read or write each consecutive byte at a time, passing the counter value via the offset.
The `FOPEN` macro should be called before `FWRTB`, and the `FCLOS` macro should be called when all operations on the file are finished.
`LISTING 6.27: MAC.DOSREQ.ASM FRDB Macro Source`
```assembly
*
*``````````````````````````````*
* FRDB (NATHAN RIGGS) *
* *
* READ A BYTE FROM A FILE. *
* *
* PARAMETERS *
* *
* ]1 = SLOT *
* ]2 = DRIVE *
* ]3 = VOLUME *
* ]4 = RECORD NUMBER *
* ]5 = BYTE OFFSET *
* ]6 = BYTE TO WRITE (0 READ) *
* *
* CYCLES: 700+ *
* SIZE: 357 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
FRDB MAC
*
** FWRB ARGUMENTS
**
** ]1 = READ OR WRITE CODE (3 = READ, 4 = WRITE)
** ]2 = READ OR WRITE COMMAND
** ]3 = SLOT
** ]4 = DRIVE
** ]5 = VOLUME (0 FOR ANY)
** ]6 = RECORD NUMBER
** ]7 = BYTE OFFSET
** ]8 = BYTE TO WRITE, IF WRITING
*
FRWB #3;#]FC_READ;]1;]2;]3;]4;]5;]6 ; {603C303B}
*
LDY #]P_BYTE ; {3C2B} INDEX TO BYTE TO READ
JSR _FMPGET ; {26C14B} GET BYTE IN THE PARAMETERS
STA BPAR1 ; {3C2B} HOLD IN ZERO PAGE
LDY #]P_RETC ; {3C2B} INDEX TO THE RETURN CODE OFFSET
JSR _FMPGET ; {26C14B} GET THE RETURN CODE
TAX ; {2C1B} PASS BACK IN .X
JSR _BUFFCLEAR ; {31C17B} CLEAR FILE BUFFER FOR USE
LDA BPAR1 ; {3C2B} PASS READ BYTE IN .A
<<<
*
```
---
### THE FRWR MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `FRWR` |
| Type | Macro |
| File | `MAC.DOSREQ.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Read or write a range of bytes in a file. |
| Input | ]1 = READ/WRITE flag<br />]2 = Command<br />]3 = Slot<br />]4 = Drive<br />]5 = Volume<br />]6 = Record number<br />]7 = Byte offset<br />]8 = Range Address<br />]TEMP = Range length |
| Output | none |
| Dependencies | `_FMPSET` `_FMPSETA` |
| Flags Destroyed | NZCV |
| Cycles | 846+ |
| Bytes | 451 |
| Notes | none |
| See Also | `FRWB` `FWRTB` `FRDB` `FRDR` `FWRTR` |
---
*DETAILS*
The `FRWR` macro reads or writes a range of bytes from or to an open file, with the Range Address either containing the bytes to be written up to the specified length or the memory area to store the bytes read from the file at the given length. It is notable that because **Merlin 8 Pro** can only handle eight built-in variables (]1 - ]8), the ]TEMP variable is used to pass the range length. Additionally, and like usual, a value of **#0** in the volume parameter indicates that any volume number is valid.
For the most part, this macro is meant to be used internally. The end user should use the `FRDR` macro for reading a range of bytes and the `FWRTR` macro for writing a range of bytes.
`LISTING 6.28: MAC.DOSREQ.ASM FRWR Macro Source`
```assembly
*
*``````````````````````````````*
* FRWR (NATHAN RIGGS) *
* *
* READ OR WRITE A RANGE. *
* *
* PARAMETERS *
* *
* ]1 = READ/WRITE FLAG *
* ]2 = COMMAND *
* ]3 = SLOT *
* ]4 = DRIVE *
* ]5 = VOLUME *
* ]6 = RECORD NUMBER *
* ]7 = BYTE OFFSET *
* ]8 = RANGE ADDRESS *
* ]TEMP = RANGE LENGTH *
* *
* CYCLES: 846+ *
* SIZE: 451 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
FRWR MAC
*
** SET THE COMMAND, SLOT, DRIVE, VOLUME AND RECORD NUMBER
*
FMFIL ]2;]3;]4;]5;]6 ; {603C303B}
*
LDA ]1 ; {4C3B} LOAD READ OR WRITE FLAG
LDY #]P_RDWR ; {3C2B} INDEX TO RD/WRT FLAG OFFSET
JSR _FMPSET ; {30C16B} SET READ OR WRITE FLAG
LDA #]SC_PRWR ; {3C2B} SUBCODE FOR POS AND READ/WRITE
LDY #]P_SUBC ; {3C2B} INDEX TO SUBCODE OFFSET
JSR _FMPSET ; {30C16B} SET SUBCODE
_AXLIT ]7 ; {8C6B}
LDY #]P_BOFF ; {3C2B} INDEX TO BYTE OFFSET
JSR _FMPSETA ; {46C26B} SET BYTE OFFSET
_AXLIT ]8 ; {8C6B}
LDY #]P_RADDR ; {3C2B} INDEX TO RANGE ADDR OFFSET
JSR _FMPSETA ; {46C26B} SET RANGE ADDRESS
LDA ]TEMP ; {4C3B} GET RANGE LENGTH
LDX ]TEMP+1 ; {4C3B} LOW BYTE AND HIGH BYTE
LDY #]P_RLEN ; {3C2B} INDEX TO RANGE LENGTH OFFSET
JSR _FMPSETA ; {46C26B} SET RANGE LENGTH
LDX #1 ; {3C2B} DON'T CREATE NEW FILE
JSR ]FMRUN ; {6C3B} RUN FILE MANAGER
<<<
*
```
---
### THE FRDR MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `FRDR` |
| Type | Macro |
| File | `MAC.DOSREQ.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Read a range of bytes from a file. |
| Input | ]1 = Slot<br />]2 = Drive<br />]3 = Volume<br />]4 = Record number<br />]5 = Byte offset<br />]6 = Range address<br />]7 = Range length |
| Output | none |
| Dependencies | `_FMPGET` `FRWR` `_BUFFCLEAR` |
| Flags Destroyed | NZCV |
| Cycles | 697+ |
| Bytes | 361 |
| Notes | none |
| See Also | `FRWB` `FWRTB` `FRDB` `FRWR` `FWRTR` |
---
*DETAILS*
The `FRDR` macro reads a range of bytes from an open file, storing the range starting at the given range address through to the given range length (two bytes). As per the collection standard, a value of **#0** in the volume parameter indicates that any volume number is valid.
Records in files work much the same way as they do in Applesoft BASIC: each record in a file is separated by a carriage return (**#$8D**), with the zeroth record being the first string of text prior to the first carriage return. These are usually used with text files, which are only marginally supported by the DOS collection: binary files make much more sense to use in Assembly, even when the data itself represents text characters. This is not to say that text files cannot be used--the `FOPEN` macro allows you to read and write text files--but that it is better for the end programmer to devise his or her own system for dealing with text files, as there is no standard method for recognizing an End-of-File (EOF) marker. Both binary files and text files can be fully read into memory before being parsed by a given routine.
The byte offset is used to start reading or writing the range at a particular location in the file.
The `FOPEN` macro should be called before `FRDR`, and the `FCLOS` macro should be called when all operations on the file are finished.
`LISTING 6.29: MAC.DOSREQ.ASM FRDR Macro Source`
```assembly
*
*``````````````````````````````*
* FRDR (NATHAN RIGGS) *
* *
* READ A RANGE FROM A FILE. *
* *
* PARAMETERS *
* *
* ]1 = SLOT *
* ]2 = DRIVE *
* ]3 = VOLUME *
* ]4 = RECORD NUMBER *
* ]5 = BYTE OFFSET *
* ]6 = RANGE ADDRESS *
* ]7 = RANGE LENGTH *
* *
* CYCLES: 697+ *
* SIZE: 361 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
FRDR MAC
IF #=]7 ; IF RANGE ADDR IS A LITERAL
LDA ]7/$100 ; {4C3B} THEN LOAD HIGH BYTE
STA ]TEMP+1 ; {4C3B} AND STORE
LDA ]7 ; {4C3B} AND LOAD LOW BYTE
STA ]TEMP ; {4C3B} AND STORE IN TEMP
ELSE
LDA ]7+1 ; {4C3B} LOAD HIGH BYTE
STA ]TEMP+1 ; {4C3B} STORE HIGH BYTE
LDA ]7 ; {4C3B} LOAD LOW BYTE
STA ]TEMP ; {4C3B} STORE LOW BYTE
FIN
*
FRWR #3;#]FC_READ;]1;]2;]3;]4;]5;]6 ; {603C303B}
*
LDY #]P_RETC ; {3C2B} INDEX TO RETURN CODE
JSR _FMPGET ; {26C14B} GET RETURN CODE
TAX ; {2C1B} HOLD IN .X
JSR _BUFFCLEAR ; {31C17B} CLEAR FILE BUFFER FOR USE
<<<
*
```
---
### THE FWRTR MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `FWRTR` |
| Type | Macro |
| File | `MAC.DOSREQ.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Write a range of bytes to a file. |
| Input | ]1 = Slot<br />]2 = Drive<br />]3 = Volume<br />]4 = Record number<br />]5 = Byte offset<br />]6 = Range address<br />]7 = Range length |
| Output | none |
| Dependencies | `_FMPGET` `FRWR` `_BUFFCLEAR` |
| Flags Destroyed | NZCV |
| Cycles | 940+ |
| Bytes | 509 |
| Notes | none |
| See Also | `FRWB` `FWRTB` `FRDB` `FRWR` `FRDR` |
---
*DETAILS*
The `FWRTR` macro writes to an open file a range of bytes found at a given starting range address through a given range length. As per the collection standard, a value of #0 in the volume parameter indicates that any volume number is valid.
Records in files work much the same way as they do in Applesoft BASIC: each record in a file is separated by a carriage return (**#$8D**), with the zeroth record being the first string of text prior to the first carriage return. These are usually used with text files, which are only marginally supported by the DOS collection: binary files make much more sense to use in Assembly, even when the data itself represents text characters. This is not to say that text files cannot be used--the `FOPEN` macro allows you to read and write text files--but that it is better for the end programmer to devise his or her own system for dealing with text files, as there is no standard method for recognizing an End-of-File (EOF) marker. Both binary files and text files can be fully read into memory before being parsed by a given routine.
The byte offset is used to start reading or writing the range at a particular location in the file.
The `FOPEN` macro should be called before `FWRTR`, and the `FCLOS` macro should be called when all operations on the file are finished.
`LISTING 6.30: MAC.DOSREQ.ASM FWRTR Macro Source`
```assembly
*
*``````````````````````````````*
* FWRTR (NATHAN RIGGS) *
* *
* WRITE A RANGE TO A FILE. *
* *
* PARAMETERS *
* *
* ]1 = SLOT *
* ]2 = DRIVE *
* ]3 = VOLUME *
* ]4 = RECORD NUMBER *
* ]5 = BYTE OFFSET *
* ]6 = RANGE ADDRESS *
* ]7 = RANGE LENGTH *
* *
* CYCLES: 940+ *
* SIZE: 509 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
FWRTR MAC
IF #=]7 ; IF RANGE LENGTH IS A LITERAL THEN
LDA ]7/$100 ; {4C3B} LOAD HIGH BYTE
STA ]TEMP+1 ; {4C3B} AND STORE IN TEMP
LDA ]7 ; {4C3B} LOAD LOW BYTE
STA ]TEMP ; {4C3B} AND STORE IN TEMP
ELSE ; OTHERWISE
LDA ]7+1 ; {4C3B} LOAD HIGH BYTE
STA ]TEMP+1 ; {4C3B} AND STORE IN TEMP
LDA ]7 ; {4C3B} LOAD LOW BYTE
STA ]TEMP ; {4C3B} AND STORE IN TEMP
FIN
*
FRWR #4;#]FC_WRIT;]1;]2;]3;]4;]5;]6 ; {846C451B}
*
LDY #]P_RETC ; {3C2B} INDEX TO RETURN CODE
JSR _FMPGET ; {26C14B} GET RETURN CODE
TAX ; {2C1B} PASS BACK IN .X
JSR _BUFFCLEAR ; {31C17B} CLEAR FILE BUFFER FOR USE
<<<
*
```
---
## DOS File Manager Macros
The MAC.DOSFM.ASM file contains various macros that are used for most file operations. Currently, this includes disk cataloging, locking and unlocking files, deleting files, verifying files, opening and closing files, reading and writing files (both text and binary), renaming files, and bloading and bsaving binary files. Additionally, subroutines are provided for using DOS's **RWTS** routine for low-level access to a disk, though this is mostly limited to reading and writing bytes in a given track and sector.
It should be noted that all of these macros need to have both the HEAD.DOS.ASM file and the MAC.DOSREQ.ASM file included (PUT and USE, respectively) in order to function properly (or, rather, at all).
`LISTING 6.40: MAC.DOSFM.ASM Heading Source`
```assembly
*
*``````````````````````````````*
* MAC.DOSFM.ASM *
* *
* THIS FILE CONTAINS MACROS *
* USED TO INTERFACE TO THE DOS *
* FILE MANAGER. NOTE THE *
* FOLLOWING: *
* *
* 1) THIS COLLECTION CURRENTLY *
* HAS A LOT OF OVERHEAD DUE TO *
* THE TIGHTLY INTEGRATED *
* NATURE OF THE FILE MANAGER. *
* *
* 2) THIS COLLECTION IS THE *
* ONLY ONE IN THE LIBRARY THAT *
* ALLOWS FOR USING THE MACROS *
* WITHIN THE SUBROUTINES, SAVE *
* FOR THE REQUIRED COLLECTION. *
* THIS IS TO MAKE EACH OF THE *
* SUBROUTINES MORE LEGIBLE, AS *
* JUST THE ACT OF PASSING *
* VARIABLES TO OTHER ROUTINES *
* CAN TAKE UP A SIGNIFICANT *
* NUMBER OF BYTES. *
* *
* AUTHOR: NATHAN RIGGS *
* CONTACT: NATHAN.RIGGS@ *
* OUTLOOK.COM *
* *
* DATE: 20-APR-2021 *
* ASSEMBLER: MERLIN 8 PRO *
* OS: DOS 3.3 *
* *
* SUBROUTINE FILES USED *
* *
* *
* LIST OF MACROS *
* *
* FCAT : CATALOG *
* FULCK : UNLOCK FILE *
* FLOCK : LOCK FILE *
* FDEL : DELETE FILE *
* FVFY : VERIFY FILE *
* FCLOS : CLOSE FILE *
* FRENM : RENAME FILE *
* FOPEN : OPEN FILE *
* BLOAD : LOAD BINARY FILE *
* BSAVE : SAVE BINARY FILE *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
```
---
### THE FCAT MACRO
_SUMMARY_
| Condition | Value |
| --------------- | -------------------------------- |
| Name | `FCAT` |
| Type | Macro |
| File | `MAC.DOSFM.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Catalog the disk. |
| Input | ]1 = Slot<br />]2 = Drive |
| Output | A disk catalog to the screen. |
| Dependencies | `_FMFIL` `_FMPGET` `_BUFFCLEAR` |
| Flags Destroyed | NZCV |
| Cycles | 657+ |
| Bytes | 348 |
| Notes | none |
| See Also | none |
---
*DETAILS*
The `FCAT` macro simply requests a disk catalog to be printed to the text screen. This macro does not provide any way to manipulate the data present in the **Volume Table of Contents (VTOC)**; this feature will be added as a separate macro in later revisions of the collection.
`LISTING 6.41: MAC.DOSFM.ASM FCAT Macro Source`
```assembly
*
*``````````````````````````````*
* FCAT (NATHAN RIGGS) *
* *
* SIMPLY LIST THE DISK CATALOG *
* TO THE SCREEN. *
* *
* PARAMETERS *
* *
* ]1 = SLOT *
* ]2 = DRIVE *
* *
* CYCLES: 657+ *
* SIZE: 348 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
FCAT MAC
*
FMFIL #]FC_CAT;]1;]2;#0;#0 ; {603C303B} SET CMD SLOT DRIVE
*
LDX #1 ; {3C2B} DON'T CREATE NEW FILE
JSR ]FMRUN ; {6C3B} RUN THE FILE MANAGER
LDY #]P_RETC ; {3C2B} SET INDEX TO RETURN CODE
JSR _FMPGET ; {32C17B} GET RETURN CODE FROM PARAMS
TAX ; {2C1B} HOLD CODE IN .X
JSR _BUFFCLEAR ; {37C20B} CLEAR THE FILE BUFF FOR USE
<<<
*
```
---
### THE FULCK MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ---------------------------------------------------- |
| Name | `FULCK` |
| Type | Macro |
| File | `MAC.DOSFM.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Unlock a file. |
| Input | ]1 = Filename address<br />]2 = Slot<br />]3 = Drive |
| Output | none. |
| Dependencies | `_FMFIL` `FMNAM` `_FMPGET` `_BUFFCLEAR` |
| Flags Destroyed | NZCV |
| Cycles | 629+ |
| Bytes | 353 |
| Notes | none |
| See Also | `FLOCK` |
---
*DETAILS*
The `FULCK` macro unlocks a file with the specified filename.
`LISTING 6.42: MAC.DOSFM.ASM FULCK Macro Source`
```assembly
*
*``````````````````````````````*
* FULCK (NATHAN RIGGS) *
* *
* UNLOCK A FILE. *
* *
* PARAMETERS *
* *
* ]1 = FILENAME STR ADDRESS *
* ]2 = SLOT *
* ]3 = DRIVE *
* *
* CYCLES: 629+ *
* SIZE: 353 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
FULCK MAC
*
FMFIL #]FC_UNLK;]2;]3;#0;#0 ; {603C303B}
*
FMNAM ]1 ; {4C3B} SET FILENAME
LDX #1 ; {4C3B} DON'T CREATE A NEW FILE
JSR ]FMRUN ; {6C3B} RUN FILE MANAGER
LDY #]P_RETC ; {4C3B} SET INDEX TO RETURN CODE
JSR _FMPGET ; {32C17B} GET RETURN CODE FROM PARAMS
TAX ; {2C1B} HOLD IN .X
JSR _BUFFCLEAR ; {37C20B} CLEAR FILE BUFF FOR USE
<<<
*
```
---
### THE FLOCK MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ---------------------------------------------------- |
| Name | `FLOCK` |
| Type | Macro |
| File | `MAC.DOSFM.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Lock a file. |
| Input | ]1 = Filename address<br />]2 = Slot<br />]3 = Drive |
| Output | none. |
| Dependencies | `_FMFIL` `FMNAM` `_FMPGET` `_BUFFCLEAR` |
| Flags Destroyed | NZCV |
| Cycles | 172+ |
| Bytes | 116 |
| Notes | none |
| See Also | `FULCK` |
---
*DETAILS*
The `FLOCK` macro locks a file with the specified filename.
`LISTING 6.43: MAC.DOSFM.ASM FLOCK Macro Source`
```assembly
*
*``````````````````````````````*
* FLOCK (NATHAN RIGGS) *
* *
* LOCK A FILE. *
* *
* PARAMETERS *
* *
* ]1 = FILENAME STR ADDRESS *
* ]2 = SLOT *
* ]3 = DRIVE *
* *
* CYCLES: 172+ *
* SIZE: 116 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
FLOCK MAC
*
*
FMFIL #]FC_LOCK;]2;]3;#0;#0 ; {603C303B}
*
FMNAM ]1 ; {117C70B} SET FILENAME
LDX #1 ; {4C3B} DON'T CREATE A NEW FILE
JSR ]FMRUN ; {6C3B} RUN FILE MANAGER
LDY #]P_RETC ; {3C2B} SET INDEX TO RETURN CODE
JSR _FMPGET ; {32C17B} GET RETURN CODE FROM PARAMS
TAX ; {2C1B} HOLD IN .X
JSR _BUFFCLEAR ; {37C20B} CLEAR FILE BUFF FOR USE
<<<
*
```
---
### THE FDEL MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ---------------------------------------------------- |
| Name | `FDEL` |
| Type | Macro |
| File | `MAC.DOSFM.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Delete a file. |
| Input | ]1 = Filename address<br />]2 = Slot<br />]3 = Drive |
| Output | none. |
| Dependencies | `_FMFIL` `FMNAM` `_FMPGET` `_BUFFCLEAR` |
| Flags Destroyed | NZCV |
| Cycles | 791+ |
| Bytes | 412 |
| Notes | none |
| See Also | none |
---
*DETAILS*
The `FDEL` macro deletes a file with the specified filename.
`LISTING 6.44: MAC.DOSFM.ASM FDEL Macro Source`
```assembly
*
*``````````````````````````````*
* FDEL (NATHAN RIGGS) *
* *
* DELETE A FILE. *
* *
* PARAMETERS *
* *
* ]1 = FILENAME STR ADDRESS *
* ]2 = SLOT *
* ]3 = DRIVE *
* *
* CYCLES: 791+ *
* SIZE: 412 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
FDEL MAC
*
FMFIL #]FC_DEL;]2;]3;#0;#0 ; {603C303B}
*
FMNAM ]1 ; {117C70B} SET FILE NAME
LDX #1 ; {3C2B} DON'T CREATE NEW FILE
JSR ]FMRUN ; {6C3B} RUN FILE MANAGER
LDY #]P_RETC ; {3C2B} SET INDEX TO RETURN CODE
JSR _FMPGET ; {26C14B} GET CODE FROM PARAMS
TAX ; {2C1B} HOLD IN .X
JSR _BUFFCLEAR ; {31C17B} CLEAR FILE BUFF FOR USE
<<<
*
```
---
### THE FVFY MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ---------------------------------------------------- |
| Name | `FVFY` |
| Type | Macro |
| File | `MAC.DOSFM.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Verify a file. |
| Input | ]1 = Filename address<br />]2 = Slot<br />]3 = Drive |
| Output | none. |
| Dependencies | `_FMFIL` `FMNAM` `_FMPGET` `_BUFFCLEAR` |
| Flags Destroyed | NZCV |
| Cycles | 791+ |
| Bytes | 411 |
| Notes | none |
| See Also | none |
---
*DETAILS*
The `FVFY` macro verifies a file with the specified filename.
`LISTING 6.45: MAC.DOSFM.ASM FVFY Macro Source`
```assembly
*
*``````````````````````````````*
* FVFY (NATHAN RIGGS) *
* *
* VERIFY A FILE. *
* *
* PARAMETERS *
* *
* ]1 = FILENAME STR ADDRESS *
* ]2 = SLOT *
* ]3 = DRIVE *
* *
* CYCLES: 791+ *
* SIZE: 411 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
FVFY MAC
*
FMFIL #]FC_VFY;]2;]3;#0;#0 ; {603C303B}
*
FMNAM ]1 ; {117C70B} SET FILE NAME
LDX #1 ; {3C2B} DON'T CREATE A NEW FILE
JSR ]FMRUN ; {6C3B} RUN THE FILE MANAGER
LDY #]P_RETC ; {3C2B} SET INDEX TO RETURN CODE
JSR _FMPGET ; {26C14B} GET CODE FROM PARAMETERS
TAX ; {2C1B} HOLD IN .X
JSR _BUFFCLEAR ; {31C17B} CLEAR FILE BUFF FOR USE
<<<
*
```
---
### THE FCLOS MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ---------------------------------------------------- |
| Name | `FCLOS` |
| Type | Macro |
| File | `MAC.DOSFM.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Close a file. |
| Input | ]1 = Filename address<br />]2 = Slot<br />]3 = Drive |
| Output | none. |
| Dependencies | `_FMFIL` `FMNAM` `_FMPGET` `_BUFFCLEAR` |
| Flags Destroyed | NZCV |
| Cycles | 797+ |
| Bytes | 415 |
| Notes | none |
| See Also | none |
---
*DETAILS*
The `FCLOS` macro closes a file with the specified filename.
`LISTING 6.46: MAC.DOSFM.ASM FCLOS Macro Source`
```assembly
*
*``````````````````````````````*
* FCLOS (NATHAN RIGGS) *
* *
* CLOSE A FILE. *
* *
* PARAMETERS *
* *
* ]1 = FILENAME STR ADDRESS *
* ]2 = SLOT *
* ]3 = DRIVE *
* *
* CYCLES: 797+ *
* SIZE: 415 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
FCLOS MAC
*
FMFIL #]FC_CLOS;]2;]3;#0;#0 ; {603C303B}
*
FMNAM ]1 ; {117C70B} SET FILENAME
LDX #1 ; {3C2B} DON'T CREATE NEW FILE
JSR ]FMRUN ; {6C3B} RUN FILE MANAGER
LDY #]P_RETC ; {3C2B} SET INDEX TO RETURN CODE
JSR _FMPGET ; {32C17B} GET RETURN CODE
TAX ; {2C1B} AND HOLD IN .X
JSR _BUFFCLEAR ; {31C17B} CLEAR FILE BUFF FOR USE
<<<
*
```
---
### THE FRENM MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `FRENM` |
| Type | Macro |
| File | `MAC.DOSFM.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Rename a file. |
| Input | ]1 = Filename address<br />]2 = New filename address<br />]3 = Slot<br />]4 = Drive |
| Output | none. |
| Dependencies | `_FMFIL` `FMNAM` `_FMPGET` `_BUFFCLEAR` `_FMNM2` |
| Flags Destroyed | NZCV |
| Cycles | 927+ |
| Bytes | 578 |
| Notes | none |
| See Also | none |
---
*DETAILS*
The `FRENM` macro renames a file with the filename given in the first parameter to the filename given in the second parameter.
`LISTING 6.47: MAC.DOSFM.ASM FRENM Macro Source`
```assembly
*
*``````````````````````````````*
* FRENM (NATHAN RIGGS) *
* *
* RENAME A FILE. *
* *
* PARAMETER *
* *
* ]1 = FILENAME STR ADDRESS *
* ]2 = NEW NAME STR ADDRESS *
* ]3 = SLOT *
* ]4 = DRIVE *
* *
* CYCLES: 927+ *
* SIZE: 578 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
FRENM MAC
*
FMFIL #]FC_REN;]3;]4;#0;#0 ; {603C303B}
*
FMNAM ]1 ; {117C70B} SET FILENAME
_AXLIT ]2 ; {8C6B}
JSR _NAMESTR2 ; {64C42B} COPY TO 2ND FILENAME BUFF
JSR _FMNM2 ; {64C42B} SET ADDRESS IN PARAMS
LDX #1 ; {3C2B} DON'T CREATE NEW FILE
JSR ]FMRUN ; {6C3B} RUN FILE MANAGER
LDY #]P_RETC ; {3C2B} SET INDEX TO RETURN CODE
JSR _FMPGET ; {26C14B} GET RETURN CODE
TAX ; {2C1B} AND HOLD IN .X
JSR _BUFFCLEAR ; {31C17B} CLEAR FILE BUFFER FOR USE
<<<
*
```
---
### THE FOPEN MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `FOPEN` |
| Type | Macro |
| File | `MAC.DOSFM.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Open a file. |
| Input | ]1 = Filename address<br />]2 = Slot<br />]3 = Drive<br />]4 = Volume<br />]5 = Record<br />]6 = File type |
| Output | none. |
| Dependencies | `_FMFIL` `FMNAM` `_FMPGET` `_BUFFCLEAR` `_FMPSET` |
| Flags Destroyed | NZCV |
| Cycles | 828+ |
| Bytes | 433 |
| Notes | none |
| See Also | `FCLOS` |
---
*DETAILS*
The `FOPEN` macro opens a file for reading or writing, which is determined by the `FRDB`, `FWRTB`, `FRDR` and `FWRTR` macros. Beyond opening the file for use, `FOPEN` determines the type of file that will be read or written to. The following table describes which type of file corresponds to the value passed in parameter number six, along with a variable name to be used in place of a number for ease of use:
| Value | Variable Name | File Type |
|----------|-----------------------|--------------|
|$00| TYP_TXT | Text File |
|$01| TYP_INT | Integer BASIC File |
|$02| TYP_APP | Applesoft BASIC File |
|$04| TYP_BIN | Binary File |
|$08| TYP_REL | Relocatable File |
|$10| TYP_S | S Type File |
|$20| TYP_A | A Type File |
|$40| TYP_B | B Type File |
`LISTING 6.48: MAC.DOSFM.ASM FOPEN Macro Source`
```assembly
*
*``````````````````````````````*
* FOPEN (NATHAN RIGGS) *
* *
* OPEN FILE FOR READ OR WRITE. *
* *
* PARAMETERS *
* *
* ]1 = FILENAME STR ADDRESS *
* ]2 = SLOT *
* ]3 = DRIVE *
* ]4 = VOLUME (0 FOR ANY) *
* ]5 = RECORD NUMBER *
* ]6 = FILE TYPE *
* *
* CYCLES: 828+ *
* SIZE: 433 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
FOPEN MAC
*
FMFIL #]FC_OPEN;]2;]3;]4;]5 ; {603C303B}
*
LDA ]6 ; {4C3B} FILE TYPE IF NEW FILE
LDY #]P_TYPE ; {3C2B} SET TYPE FOR WRITING
JSR _FMPSET ; {30C16B}
FMNAM ]1 ; {117C70B} SET THE FILENAME
LDX #0 ; {3C2B} NEW FILE ON OPEN
JSR ]FMRUN ; {6C3B} RUN FILE MANAGER
LDY #]P_RETC ; {3C2B} SET INDEX TO RETURN CODE OFFSET
JSR _FMPGET ; {26C14B} GET RETURN CODE
TAX ; {2C1B} HOLD IT IN .X
JSR _BUFFCLEAR ; {31C17B} CLEAR FILE BUFFER FOR USE
<<<
*
```
---
### THE BLOAD MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `BLOAD` |
| Type | Macro |
| File | `MAC.DOSFM.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Binary-load a file. |
| Input | ]1 = Filename address<br />]2 = Loading address<br />]3 = Slot<br />]4 = Drive<br />]5 = Volume |
| Output | none. |
| Dependencies | `FBLOAD` |
| Flags Destroyed | NZCV |
| Cycles | 3768+ |
| Bytes | 2735 |
| Notes | none |
| See Also | `BSAVE` `FBSAVE` `FBLOAD` |
---
*DETAILS*
The `BLOAD` macro loads the contents of a binary file into memory either at a specified address or, if the address passed is **#$0000**, at the address stored in the start of the file. Like with all properly saved binary file, both the default address and the file byte-length is stored in the first four bytes of the file; these are not copied to the specified location. The length is passed back to the calling program via the **.A** register (low) and **.X** register (high).
`LISTING 6.49: MAC.DOSFM.ASM BLOAD Macro Source`
```assembly
*
*``````````````````````````````*
* BLOAD (NATHAN RIGGS) *
* *
* LOAD A MACHINE LANGUAGE FILE *
* INTO MEMORY AT A SPECIFIED *
* ADDRESS. IF THE ADDRESS IS *
* #0000, THEN USE THE DEFAULT *
* ADDRESS PROVIDED AT THE *
* START OF THE FILE. THE FILE *
* LENGTH IS ALSO HELD AT THE *
* BEGINNING OF THE FILE, SO *
* THERE IS NO NEED TO PASS IT *
* HERE. THIS LENGTH IS PASSED *
* BACK TO THE USER VIA THE *
* .A (LOW) AND .X (HIGH) *
* REGISTERS. *
* *
* PARAMETERS *
* *
* ]1 = FILENAME STRING ADDR *
* ]2 = LOADING ADDRESS *
* ]3 = SLOT *
* ]4 = DRIVE *
* ]5 = VOLUME *
* *
* DESTROYS: NZCIDV *
* ^^^ ^ *
* *
* CYCLES: 3768+ *
* SIZE: 2735 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
BLOAD MAC
_MLIT ]1;WPAR1 ; {16C12B} PARSE STRING ADDRESS
_MLIT ]2;WPAR2 ; {16C12B} PARSE LOAD ADDRESS
LDA ]3 ; {4C3B} LOAD SLOT
STA BPAR1 ; {3C2B} AND STORE ON ZERO
LDA ]4 ; {4C3B} LOAD DRIVE
STA BPAR2 ; {3C2B} AND STORE ON ZERO
LDA ]5 ; {4C3B} LOAD VOLUME
STA BPAR3 ; {3C2B} AND STORE ON ZERO
JSR FBLOAD ; {3715C2696B} RUN FBLOAD SUBROUTINE
<<<
*
```
---
### THE FBLOAD SUBROUTINE
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `FBLOAD` |
| Type | Subroutine |
| File | `SUB.FBLOAD.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Binary-load a file. |
| Input | WPAR1 = Filename string address<br />WPAR2 = Loading Address<br />BPAR1 = Slot<br />BPAR2 = Drive<br />BPAR3 = Volume |
| Output | none. |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 3715+ |
| Bytes | 2696 |
| Notes | none |
| See Also | `BSAVE` `FBSAVE` `BLOAD` |
---
*DETAILS*
The `FBLOAD` subroutine loads a binary file into the designated memory address, with the length being determined by a preceding length-byte in the file. If the memory address passed is **#$0000**, then the default address found in the first two bytes of the file is used in place of the address passed. These first four bytes of the file, signifying the default memory address and the length of the range in bytes, are not copied along with the rest of the file.
The length of the data is store in **.A** (low byte) and **.X** (high byte), as well as in `RETURN`. `RETLEN` carries **#$02**.
`LISTING 6.50: SUB.FBLOAD.ASM Source`
```assembly
*
*``````````````````````````````*
* FBLOAD (NATHAN RIGGS) *
* *
* BLOAD A FILE'S MACHINE *
* LANGUAGE CONTENTS TO A GIVEN *
* MEMORY RANGE. NOTE THAT THE *
* FIRST FOUR BYTES OF A BIN *
* FILE CONTAINS THE LOADING *
* ADDRESS (TWO BYTES) AND THE *
* LENGTH OF THE CODE (TWO *
* BYTES). IF THE ADDRESS *
* EQUALS #0000, THEN THESE *
* VALUES WILL BE USED INSTEAD. *
* *
* INPUT *
* *
* WPAR1 = FILENAME STR ADDR *
* WPAR2 = LOAD ADDRESS *
* BPAR1 = SLOT *
* BPAR2 = DRIVE *
* BPAR3 = VOLUME *
* *
* DESTROY: NZCIDV *
* ^^^ ^ *
* *
* CYCLES: 3715+ *
* SIZE: 2696 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]FNSTR EQU WPAR1 ; FILENAME STRING
]LDADDR EQU WPAR2 ; LOADING ADDRESS
]FLEN EQU WPAR3 ; FILE LENGTH
]SLOT EQU BPAR1
]DRIVE EQU BPAR2
]VOL EQU BPAR3
]FLDADDR EQU ADDR4 ; ADDRESS STORED IN FILE
*
FBLOAD
*
** FIRST, READ FIRST TWO BYTES TO GET THE
** DEFAULT ADDRESS. IF THE ADDRESS PASSED IS
** #0000, THEN THE DEFAULT ADDRESS IS USED INSTEAD.
*
FOPEN ]FNSTR;]SLOT;]DRIVE;]VOL;#0;#]TYP_BIN ; {828C433B}
FRDB ]SLOT;]DRIVE;#0;#0;#0;#0 ; {700C357B}
STA ]FLDADDR ; {4C3B}
FRDB ]SLOT;]DRIVE;#0;#0;#1;#0 ; {700C357B}
STA ]FLDADDR+1 ; {4C3B}
*
** NOW GET THE LENGTH OF THE FILE. THEORETICALLY,
** THIS SHOULDN'T INCLUDE THE FIRST 4 BYTES?
*
FRDB ]SLOT;]DRIVE;#0;#0;#2;#0 ; {700C357B}
STA ]FLEN ; {4C3B}
FRDB ]SLOT;]DRIVE;#0;#0;#3;#0 ; {700C357B}
STA ]FLEN+1 ; {4C3B}
*
** IF PASSED ADDRESS IS ZERO, THEN USE THE
** DEFAULT ADDRESS. OTHERWISE, COPY THE PASSED
** ADDRESS INTO THE DEFAULT ADDRESS VARIABLE.
*
LDA ]LDADDR ; {4C3B}
CMP #0 ; {3C2B}
BNE :SET ; {3C2B}
LDA ]LDADDR+1 ; {4C3B}
CMP #0 ; {3C2B}
BNE :SET ; {3C2B}
JMP :SKIP ; {633B}
:SET
LDA ]LDADDR ; {4C3B}
STA ]FLDADDR ; {4C3B}
LDA ]LDADDR+1 ; {4C3B}
STA ]FLDADDR+1 ; {4C3B}
*
** NOW READ THE RANGE OF THE ENTIRE FILE AND
** STORE IT IN MEMORY AT THE APPROPRIATE LOCATION.
*
:SKIP
FRDR ]SLOT;]DRIVE;#0;#0;#4;]FLDADDR;]FLEN ; {697C361B}
FCLOS ]FNSTR;]SLOT;]DRIVE ; {797C415B}
*
LDA ]FLEN ; {4C3B} LOAD LENGTH LOW BYTE
STA RETURN ; {4C3B} AND HOLD IN .A AND RETURN
LDX ]FLEN+1 ; {4C3B} LOAD LENGTH HIGH BYTE
STA RETURN+1 ; {4C3B} AND HOLD IN .X AND RETURN+1
LDY #2 ; {3C2B} LOAD BYTE LENGTH OF RETURN
STY RETLEN ; {4C3B} AND STORE IN RETLEN
RTS ; {6C1B}
*
```
---
### THE BSAVE MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `BSAVE` |
| Type | Macro |
| File | `MAC.DOSFM.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Binary-save a range of memory. |
| Input | ]1 = Filename address<br />]2 = Loading address<br />]3 = Range length<br />]4 = Slot<br />]5 = Drive<br />]6 = Volume |
| Output | none. |
| Dependencies | `FBSAVE` |
| Flags Destroyed | NZCV |
| Cycles | 5300+ |
| Bytes | 2758 |
| Notes | none |
| See Also | `BLOAD` `FBSAVE` `FBLOAD` |
---
*DETAILS*
The `BSAVE` macro stores a range of memory from a starting address to a given byte-length in a binary file, holding the starting address in the first two bytes of the file and the range length in the third and fourth bytes. This is how all binary files are stored in DOS, or should be stored.
`LISTING 6.51: MAC.DOSFM.ASM BSAVE Macro Source`
```assembly
*
*``````````````````````````````*
* BSAVE (NATHAN RIGGS) *
* *
* STORES A MEMORY RANGE IN A *
* FILE STARTING AT THE LOADING *
* ADDRESS AND CONTINUING FOR *
* THE GIVEN RANGE LENGTH. THE *
* FIRST TWO BYTES OF THE FILE *
* HOLD THE LOADING ADDRESS, *
* AND THE 3RD AND 4TH BYTES *
* HOLD THE RANGE LENGTH. *
* *
* PARAMETERS *
* *
* ]1 = FILENAME STRING ADDR *
* ]2 = LOADING ADDRESS *
* ]3 = RANGE LENGTH *
* ]4 = SLOT *
* ]5 = DRIVE *
* ]6 = VOLUME *
* *
* DESTROYS: NZCIDV *
* ^^^ ^ *
* *
* CYCLES: 5300+ *
* SIZE: 2758 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
BSAVE MAC
_MLIT ]1;WPAR1 ; {16C12B} PARSE STRING ADDRESS
_MLIT ]2;WPAR2 ; {16C12B} PARSE LOAD ADDRESS
_MLIT ]3;WPAR3 ; {16C12B}
LDA ]4 ; {4C3B} LOAD SLOT
STA BPAR1 ; {3C2B} AND STORE ON ZERO
LDA ]5 ; {4C3B} LOAD DRIVE
STA BPAR2 ; {3C2B} AND STORE ON ZERO
LDA ]6 ; {4C3B} LOAD VOLUME
STA BPAR3 ; {3C2B} AND STORE ON ZERO
JSR FBSAVE ; {5231C2707B} RUN FBLOAD SUBROUTINE
<<<
*
```
---
### THE FBSAVE SUBROUTINE
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------------------------------ |
| Name | `FBSAVE` |
| Type | Subroutine |
| File | `SUB.FBSAVE.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Binary-save a file. |
| Input | WPAR1 = Filename string address<br />WPAR2 = Loading Address<br />WPAR3 = Range length<br />BPAR1 = Slot<br />BPAR2 = Drive<br />BPAR3 = Volume |
| Output | none. |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 3715+ |
| Bytes | 2696 |
| Notes | none |
| See Also | `BSAVE` `FBLOAD` `BLOAD` |
---
*DETAILS*
The `FBSAVE` subroutine saves a memory range to a binary file that starts at a given address. The first two bytes of the file holds the starting address, while the next two bytes hold the range length.
`LISTING 6.52: SUB.FBSAVE.ASM Source`
```assembly
*
*``````````````````````````````*
* FBSAVE (NATHAN RIGGS) *
* *
* THIS SUBROUTINE TAKES AN *
* ADDRESS AND A BYTE LENGTH, *
* THEN SAVES THAT MEMORY RANGE *
* TO A FILE. THE FIRST TWO *
* BYTES HOLD THE ADDRESS WHERE *
* THE MEMORY WAS STORED, AND *
* THE THIRD AND FOURTH BYTES *
* OF THE FILE HOLD THE LENGTH *
* OF THE FILE (NOT INCLUDING *
* THE FOUR PRECEDING BYTES). *
* *
* INPUT *
* *
* WPAR1 = FILENAME STR ADDR *
* WPAR2 = LOAD ADDRESS *
* WPAR3 = RANGE LENGTH *
* BPAR1 = SLOT *
* BPAR2 = DRIVE *
* BPAR3 = VOLUME *
* *
* DESTROY: NZCIDV *
* ^^^ ^ *
* *
* CYCLES: 5231+ *
* SIZE: 2707 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]FNSTR EQU WPAR1
]LDADDR EQU WPAR2
]FLEN EQU WPAR3
]SLOT EQU BPAR1
]DRIVE EQU BPAR2
]VOL EQU BPAR3
*
FBSAVE
*
** FIRST, OPEN THE FILE FOR BINARY WRITING
*
FOPEN ]FNSTR;]SLOT;]DRIVE;]VOL;#0;#]TYP_BIN ; {828C433B}
*
** NEXT, STORE THE STARTING ADDRESS OF THE
** MEMORY RANGE AT THE FIRST TWO BYTES OF THE FILE.
*
FWRTB ]SLOT;]DRIVE;]VOL;#0;#0;]LDADDR ; {665C337B}
FWRTB ]SLOT;]DRIVE;]VOL;#0;#1;]LDADDR+1 ; {665C337B}
*
** NOW STORE THE LENGTH IN THE THIRD AND FOURTH
** BYTES OF THE FILE.
*
FWRTB ]SLOT;]DRIVE;]VOL;#0;#2;]FLEN ; {665C337B}
FWRTB ]SLOT;]DRIVE;]VOL;#0;#3;]FLEN+1 ; {665C337B}
*
** THEN STORE THE MEMORY RANGE IN THE FILE, OFFSETTING
** BY FOUR TO ACCOUNT FOR THE PRECEDING ADDRESS AND
** LENGTH BYTES.
*
FWRTR ]SLOT;]DRIVE;]VOL;#0;#4;]LDADDR;]FLEN ; {940C509B}
*
** CLOSE FILE, RETURN TO CALLER
*
FCLOS ]FNSTR;]SLOT;]DRIVE {797C416B}
RTS ; {6C1B}
```
---
## Miscellaneous DOS Macros
The MAC.DOSMORE.ASM file contains macros that are primarily concerned with DOS functions but are not required and do not fit neatly in with file management. This includes macros for checking the DOS version, verifying if DOS or Applesoft is loaded, and macros for telling if an Applesoft or Integer BASIC program is running.
`LISTING 6.60: MAC.DOSMORE.ASM Heading`
```assembly
*
*``````````````````````````````*
* MAC.DOSMORE.ASM *
* *
* *
* AUTHOR: NATHAN RIGGS *
* CONTACT: NATHAN.RIGGS@ *
* OUTLOOK.COM *
* *
* DATE: 20-APR-2021 *
* ASSEMBLER: MERLIN 8 PRO *
* OS: DOS 3.3 *
* *
* SUBROUTINE FILES USED *
* *
* NONE *
* *
* LIST OF MACROS *
* *
* DVER : CHECK DOS VERSION *
* DOSIN : CHECK IF DOS LOADED *
* ABAS : IS APPLESOFT LOADED *
* IBEX : IS INTEGER BASIC *
* PROGRAM RUNNING *
* ABEX : IS APPLESOFT BASIC *
* PROGRAM RUNNING *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
```
---
### THE DVER MACRO
_SUMMARY_
| Condition | Value |
| --------------- | --------------------- |
| Name | `DVER` |
| Type | Macro |
| File | `MAC.DOSMORE.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Check the DOS version |
| Input | none |
| Output | none. |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 28+ |
| Bytes | 18 |
| Notes | none |
| See Also | none |
---
*DETAILS*
The `DVER` macro checks the current version of DOS in memory and returns the version number in the **.A** register.
`LISTING 6.61: MAC.DOSMORE.ASM DVER Macro Source`
```assembly
*
*``````````````````````````````*
* DVER (NATHAN RIGGS) *
* *
* RETURN THE DOS VERSION. THIS *
* IS ADAPTED FROM DON WORTH'S *
* AND PIETER LECHNER'S *
* /BENEATH APPLE DOS/. THE *
* LICENSE MAY ACCORDINGLY *
* VARY. *
* *
* PARAMETERS *
* *
* NONE *
* *
* CYCLES: 28 *
* SIZE: 18 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
DVER MAC
CLC ; {2C1B} CLEAR CARRY FLAG
LDA #0 ; {3C2B} CLEAR ACCUMULATOR
ADC #$BE ; {2C2B} ADD #$16BE TO DOS LOAD POINT
STA ADDR1 ; {3C2B} STORE LOW BYTE
LDA $3D2 ; {4C3B} LOAD DOS LOADING POINT
ADC #$16 ; {2C2B} ADD OFFSET
STA ADDR1+1 ; {3C2B} STORE HIGH BYTE
LDY #0 ; {3C2B} SET INDEX TO 0
LDA (ADDR1),Y ; {6C2B} RETURNS #2 OR #3 FOR
; THE DOS VERSION IN .A
<<<
*
```
---
### THE DOSIN MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ---------------------- |
| Name | `DOSIN` |
| Type | Macro |
| File | `MAC.DOSMORE.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Check if DOS is loaded |
| Input | none |
| Output | none. |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 17+ |
| Bytes | 12 |
| Notes | none |
| See Also | none |
---
*DETAILS*
The `DOSIN` macro checks if DOS is currently loaded into memory. The **CARRY** flag is set if DOS is loaded, and it is cleared if DOS is not loaded.
`LISTING 6.62: MAC.DOSMORE.ASM DOSIN Macro Source`
```assembly
*
*``````````````````````````````*
* DOSIN *
* *
* CHECKS IF DOS IS LOADED. *
* THIS SHOULD BE CALLED BEFORE *
* RUNNING RWTS OR THE FILE *
* MANAGER. *
* *
* THIS IS ADAPTED FROM DON *
* WORTH'S AND PIETER LECHNER'S *
* /BENEATH APPLE DOS/, SO THE *
* LICENSE MAY VARY ACCORDINGLY *
* *
* PARAMETERS *
* *
* NONE *
* *
* CYCLES: 17 *
* SIZE: 12 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
DOSIN MAC
LDA $3D0 ; {4C3B} GET VECTOR JUMP
CMP #$4C ; {3C2B} IS IT A JUMP?
BNE ]NODOS ; {3C2B} NOPE, JUMP TO NONE
SEC ; {2C1B} CARRY SET, MEANING DOS LOADED
JMP ]EXIT ; {3C3B}
]NODOS
CLC ; {2C1B} CARRY CLEAR, MEANING NO DOS
]EXIT
<<<
*
```
---
### THE ABAS MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ------------------------------------- |
| Name | `ABAS` |
| Type | Macro |
| File | `MAC.DOSMORE.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Find out which BASIC system is loaded |
| Input | none |
| Output | none. |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 40+ |
| Bytes | 29 |
| Notes | none |
| See Also | none |
---
*DETAILS*
The `ABAS` macro determines whether it is Applesoft BASIC or Integer BASIC that is currently loaded. If Applesoft BASIC is loaded, then the **CARRY** is set; if it is Integer BASIC loaded, then the **CARRY** is cleared.
`LISTING 6.63: MAC.DOSMORE.ASM ABAS Macro Source`
```assembly
*
*``````````````````````````````*
* ABAS *
* *
* DETERMINE WHICH BASIC IS *
* LOADED. IF CARRY IS CLEAR, *
* THEN INTEGER BASIC IS *
* LOADED--ELSE, APPLESOFT IS. *
* *
* THIS IS ADAPTED FROM DON *
* WORTH'S AND PIETER LECHNER'S *
* /BENEATH APPLE DOS/, SO THE *
* LICENSE MAY VARY ACCORDINGLY *
* *
* PARAMETERS *
* *
* NONE *
* *
* CYCLES: 40 *
* SIZE: 29 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
ABAS MAC
LDA #$4C ; {4C3B} CODE FOR APPLESOFT
; #$20 IS FOR INTEGER BASIC
CMP $E000 ; {4C3B} CORRECT BASIC ALREADY THERE?
BEQ ]APPLES ; {3C2B} YES, GOTO RETURN CARRY
STA $C080 ; {4C3B} NOW IS IT THERE?
CMP $E000 ; {4C3B} NOW IS IT THERE?
BEQ ]APPLES ; {3C2B} YEP, GOTO RETURN CARRY
STA $C081 ; {4C3B} STILL NO, TRY ROM CARD
CMP $E000 ; {4C3B} THERE NOW?
BEQ ]APPLES ; {3C2B} YEP, GOTO RETURN CARRY
; NOPE, DON'T RETURN CARRY
CLC ; {2C1B}
JMP ]EXIT ; {3C3B}
]APPLES
SEC ; {2C1B}
]EXIT
<<<
*
```
---
### THE IBEX MACRO
_SUMMARY_
| Condition | Value |
| --------------- | -------------------------------------------- |
| Name | `IBEX` |
| Type | Macro |
| File | `MAC.DOSMORE.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Check if an Integer BASIC program is running |
| Input | none |
| Output | none. |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 17+ |
| Bytes | 12 |
| Notes | none |
| See Also | none |
---
*DETAILS*
The `IBEX` macro sets the **CARRY** flag if an Integer BASIC program is currently running; otherwise, the **CARRY** is cleared.
`LISTING 6.64: MAC.DOSMORE.ASM IBEX Macro Source`
```assembly
*
*``````````````````````````````*
* IBEX *
* *
* CHECK IF AN INTEGER BASIC *
* PROGRAM IS RUNNING. *
* *
* THIS IS ADAPTED FROM DON *
* WORTH'S AND PIETER LECHNER'S *
* /BENEATH APPLE DOS/, SO THE *
* LICENSE MAY VARY ACCORDINGLY *
* *
* PARAMETERS *
* *
* NONE *
* *
* CYCLES: 17 *
* SIZE: 12 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
IBEX MAC
LDA $D9 ; {4C3B} CHECK BASIC
BMI ]YES ; {3C2B} IF NEG, THEN INT BASIC RUNNING
BPL ]NO ; {3C2B} IF POSITIVE, THEN NOT
]YES
SEC ; {2C1B} INT BASIC RUNNING, SET CARRY
JMP ]EXIT ; {3C3B} AND EXIT
]NO
CLC ; {2C1B} NOT RUNNING, SO CLEAR CARRY
]EXIT ; AND EXIT
<<<
*
```
---
### THE ABEX MACRO
_SUMMARY_
| Condition | Value |
| --------------- | ---------------------------------------------- |
| Name | `ABEX` |
| Type | Macro |
| File | `MAC.DOSMORE.ASM` |
| Author | Nathan Riggs |
| Last Revision | 07-MAY-2021 |
| Assembler | Merlin Pro 8 |
| OS | Apple DOS 3.3 |
| Purpose | Check if an Applesoft BASIC program is running |
| Input | none |
| Output | none. |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 26+ |
| Bytes | 18 |
| Notes | none |
| See Also | none |
---
*DETAILS*
The `ABEX` macro sets the **CARRY** flag if an Applesoft BASIC program is currently running; otherwise, the **CARRY** is cleared.
`LISTING 6.65: MAC.DOSMORE.ASM ABEX Macro Source`
```assembly
*
*``````````````````````````````*
* ABEX *
* *
* CHECK IF AN APPLESOFT BASIC *
* PROGRAM IS RUNNING. *
* *
* THIS IS ADAPTED FROM DON *
* WORTH'S AND PIETER LECHNER'S *
* /BENEATH APPLE DOS/, SO THE *
* LICENSE MAY VARY ACCORDINGLY *
* *
* PARAMETERS *
* *
* NONE *
* *
* CYCLES: 26 *
* SIZE: 18 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
ABEX MAC
LDX $76 ; {4C3B} GET LINE NUMBER
INX ; {2C1B}
BEQ ]NO ; {3C2B}
LDX $33 ; {4C3B} GET PROMPT CHARACTER
CPX #$DD ; {3C2B} IS PROMPT A "]" ?
BEQ ]NO ; {3C2B} YES, SO NOT EXECUTING
SEC ; {2C1B} ELSE, IS EXECUTING--SET CARRY
JMP ]EXIT ; {3C3B}
]NO
CLC ; {2C1B}
]EXIT
<<<
*
```
---
## Part II: DOS Collection Demos
This section lists two demo files, DEMO.DOSFM.ASM and DEMO.DOSMORE.ASM, that illustrate how to use the various macros in the DOS collection. This only concerns the macros found in the MAC.DOSFM.ASM file and the MAC.DOSMORE.ASM file, as the macros in DOS.DOSREQ.ASM are meant for internal use only.
`Listing 6.70: DEMO.DOSFM.ASM Source`
```assembly
*
*``````````````````````````````*
* DEMO.DOSFM.ASM *
* *
* A DEMO FILE FOR THE DOS *
* FILE MANAGER MACROS. *
* *
* AUTHOR: NATHAN RIGGS *
* CONTACT: NATHAN.RIGGS@ *
* OUTLOOK.COM *
* *
* DATE: 21-APR-2021 *
* ASSEMBLER: MERLIN 8 PRO *
* OS: DOS 3.3 *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** ASSEMBLER DIRECTIVES
*
CYC AVE
EXP OFF
TR ON
DSK DEMO.DOSFM
OBJ $BFE0
ORG $6000
*
*``````````````````````````````*
* TOP INCLUDES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
PUT MIN.HEAD.REQUIRED.ASM
USE MIN.MAC.REQUIRED.ASM
USE MIN.MAC.DOSREQ.ASM
USE MIN.MAC.DOSFM.ASM
PUT MIN.HEAD.DOS.ASM
*
]HOME EQU $FC58
]ZSLOT EQU $6
]ZDRIVE EQU $2
*
*``````````````````````````````*
* PROGRAM MAIN BODY *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
*``````````````````````````````*
* DOS FILE MANAGER MACROS *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE FOLLOWING MACROS BEING USED ARE EXAMPLES
** OF HOW TO USE EACH MACRO IN THE FILE MANAGER
** MACRO SELECTION OF THE DOS COLLECTION OF THE
** APPLEIIASM LIBRARY. NOTE THAT OTHER DEMO FILES
** EXIST FOR OTHER DOS FUNCTIONS, SUCH AS THE
** DEMO.DOSRWTS.ASM FILE FOR RWTS USAGE AND THE
** DEMO.DOSMORE.ASM FILE FOR MISCELLANEOUS MACROS
** THAT CAN BE OF USE WHILE USING APPLE DOS.
*
*``````````````````````````````*
* THE FCAT MACRO *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE FCAT MACRO SIMPLY RUNS THE CATALOG
** DOS COMMAND, WHICH LISTS THE FILES IN A
** DISK IN THE GIVEN SLOT AND DRIVE. A MORE
** ROBUST CATALOGING MACRO IS PLANNED AS PART
** OF THE DEMO.DOSMORE.ASM SELECTION.
*
JSR ]HOME
_PRN "THE FCAT MACRO",8D
_PRN "==============",8D8D
_WAIT
FCAT #]ZSLOT;#]ZDRIVE
_WAIT
*
*``````````````````````````````*
* THE FLOCK MACRO *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE FLOCK MACRO LOCKS A GIVEN FILE AT THE
** PROVIDED SLOT AND DRIVE NUMBERS.
*
JSR ]HOME
_PRN "THE FLOCK MACRO",8D
_PRN "===============",8D8D
_PRN "FIRST, CATALOG BEFORE LOCKING:",8D8D
_WAIT
FCAT #]ZSLOT;#]ZDRIVE
_WAIT
_PRN " ",8D
_PRN "NOW LOCK A FILE AND DO ANOTHER CAT:",8D8D
FLOCK #FN5;#]ZSLOT;#]ZDRIVE
_WAIT
FCAT #]ZSLOT;#]ZDRIVE
_WAIT
*
*``````````````````````````````*
* THE FULCK MACRO *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE FULCK MACRO SIMPLY UNLOCKS A FILE IN
** THE GIVEN SLOT AND DRIVE.
*
JSR ]HOME
_PRN "THE FULCK MACRO",8D
_PRN "===============",8D8D
_PRN "FIRST, SHOW CATALOG WITH LOCKED FILE:",8D8D
_WAIT
FCAT #]ZSLOT;#]ZDRIVE
_WAIT
_PRN " ",8D
_PRN "NOW SHOW CATALOG WITH UNLOCKED FILE:",8D8D
FULCK #FN5;#]ZSLOT;#]ZDRIVE
_WAIT
FCAT #]ZSLOT;#]ZDRIVE
_WAIT
*
*``````````````````````````````*
* THE FRENM MACRO *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE FRENM MACRO RENAMES A FILE FROM A SOURCE
** FILENAME TO A DESTINATION FILENAME, BOTH IN
** THE SAME SLOT AND DRIVE.
*
JSR ]HOME
_PRN "THE FRENM MACRO",8D
_PRN "===============",8D8D
_PRN "CATALOG WITH RENAMED FILE:",8D8D
FRENM #FN5;#FN3;#]ZSLOT;#]ZDRIVE
_WAIT
FCAT #]ZSLOT;#]ZDRIVE
_PRN " ",8D
_WAIT
_PRN "CATALOG WITH FILE RENAMED BACK:",8D8D
_WAIT
FRENM #FN3;#FN5;#]ZSLOT;]ZDRIVE
FCAT #]ZSLOT;#]ZDRIVE
_WAIT
*
*``````````````````````````````*
* THE FWRTB MACRO *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE FWRTB MACRO, WHICH STANDS FOR
** (F)ILE (WR)I(T)E (B)YTE, WRITES A SINGLE BYTE
** TO A FILE ON A DISK AT A GIVEN SLOT, DRIVE AND
** VOLUME. NOTE THAT THIS CAN BE ANY FILE TYPE.
*
** OTHER THAN THE RETURN CODE, THERE IS NO OUTPUT
** BEYOND THE "A" BEING PUT INTO THE FILE. WE CANNOT
** TEST THIS UNTIL WE ALSO USE A BYTE READING FUNCTION,
** WHICH WE WILL COVER NEXT.
*
** ALSO NOTE THAT THIS MAKES USE OF THE FOPEN AND FCLOS
** MACROS. THESE WILL BE EXHIBITED AGAIN TOWARD THE END
** OF THE DEMO.
*
FOPEN #FN5;#]ZSLOT;#]ZDRIVE;#0;#0;#]TYP_TXT
FWRTB #]ZSLOT;#]ZDRIVE;#0;#0;#0;#"A"
FCLOS #FN5;#]ZSLOT;#]ZDRIVE
*
*``````````````````````````````*
* THE FRDB MACRO *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE FRDB MACRO, WHICH STANDS FOR
** (F)ILE (R)EA(D) (B)YTE, READS A BYTE FROM
** A FILE ON A DISK IN THE GIVEN SLOT, DRIVE AND
** VOLUME.
*
JSR ]HOME
_PRN "THE FRDB AND FWRTB MACROS",8D
_PRN "=========================",8D8D
_PRN "THE FIRST BYTE OF THE FILE IS: "
FOPEN #FN5;#]ZSLOT;#]ZDRIVE;#0;#0;#]TYP_TXT
FRDB #]ZSLOT;#]ZDRIVE;#0;#0;#0;#0
JSR $FDF0
FCLOS #FN5;#]ZSLOT;#]ZDRIVE
_WAIT
*
*``````````````````````````````*
* THE FWRTR MACRO *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE FWRTR MACRO, WHICH STANDS FOR (F)ILE
** (WR)I(T)E RANGE, WRITES A RANGE OF BYTES IN
** MEMORY TO A FILE (THE TYPE IS UP TO THE USER).
** THIS IS USED IN CONJUNCTION WITH THE FRDR MACRO
** TO READ AND WRITE MULTIPLE BYTES FROM AND TO FILES.
*
** THIS MACRO ONLY OUTPUTS TO A FILE, SAVE FOR THE
** RETURN CODE STORED IN THE .X REGISTER. THE NEXT
** MACRO'S EXPLANATION WILL INCLUDE PRINTING THE TEXT
** SAVED TO A FILE HERE.
*
** NOTE THAT WHEN WRITING A RANGE OF BYTES, THE LENGTH
** OF THE BYTES TO BE WRITTEN SHOULD BE REDUCED BY ONE.
** THIS IS DUE TO AN INCONSISTENCY IN DOS.
*
FOPEN #FN5;#]ZSLOT;#]ZDRIVE;#0;#0;#]TYP_TXT
FWRTR #]ZSLOT;#]ZDRIVE;#0;#0;#0;#RANGE+1;#24
FCLOS #FN5;#]ZSLOT;#]ZDRIVE
*
*``````````````````````````````*
* THE FRDR MACRO *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE FRDR MACRO, WHICH STANDS FOR (F)ILE
** (R)EA(D) (R)ANGE, READS A RANGE OF BYTES
** FROM A FILE ON A DISK AT A GIVEN SLOT AND DISK,
** STORING THE DATA AT A PROVIDED ADDRESS. IT
** IS IMPORTANT TO KNOW THE SIZE OF THE FILE
** PRIOR TO READING IT, SINCE READING PAST THE
** END OF THE FILE CAN HAVE UNPREDICTABLE
** CONSEQUENCES.
*
JSR ]HOME
_PRN "THE FRDR AND FWRTR MACROS",8D
_PRN "=========================",8D8D
_PRN "THE FILE CONTAINS:",8D8D
FOPEN #FN5;#]ZSLOT;#]ZDRIVE;#0;#0;#0
FRDR #]ZSLOT;#]ZDRIVE;#0;#0;#0;#RDRANGE;#25
FCLOS #FN5;#]ZSLOT;#]ZDRIVE
LDY #255
LOOP1
INY
LDA RDRANGE,Y
JSR $FDF0
CPY #24
BNE LOOP1
_WAIT
*
*``````````````````````````````*
* THE BLOAD MACRO *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE BLOAD MACRO WORKS MUCH LIKE THE BLOAD
** COMMAND IN DOS, BUT THERE IS NO BLOAD COMMAND
** FOR THE FILE MANAGER; IT HAS TO BE BUILT FROM
** THE ALREADY AVAILABLE COMMANDS.
*
** WHEN USED, THE BLOAD MACRO LOADS A BINARY FILE'S
** CONTENTS AND STORES THEM IN THE PROVIDED ADDRESS ON
** THE DISK IN THE GIVEN SLOT AND DRIVE. IF THE ADDRESS
** PASSED IS #0000, THEN THE MACRO/SUBROUTINE ASSUMES
** THAT THE DEFAULT ADDRESS WILL BE USED, WHICH IS
** STORED IN THE FIRST TWO BYTES OF THE FILE. THE LENGTH
** IS ALSO STORED AT THE BEGINNING OF THE FILE IN BYTES
** THREE AND FOUR, FOLLOWED BY THE ACTUAL DATA REQUESTED.
*
** IT SHOULD BE NOTED THAT THERE IS NO TEXT FILE
** EQUIVALENT TO BLOAD BECAUSE ANYONE WITH ANY SENSE
** WILL USE BINARY FILES TO STORE AND RETRIEVE DATA ON
** THE DISK, AS IT IS BOTH FASTER AND EASIER--TEXT
** FILES, FOR INSTANCE, DO NOT EASILY PROVIDE THE
** LENGTH OF THE FILE. IF A TEXT ROUTINE AS SUCH IS
** NEEDED, IT IS BEST TO BUILD YOUR OWN USING FWRTR,
** FRDR, FWRTB AND FRDB, AS YOU WILL LIKELY CREATE YOUR
** OWN STRUCTURE TO THE FILE.
*
JSR ]HOME
_PRN "THE BLOAD MACRO",8D
_PRN "===============",8D8D
_PRN "$300 NOW HOLDS:",8D8D
BLOAD #FN6;#$0000;#]ZSLOT;#]ZDRIVE;#0
DUMP #$300;#$40
_WAIT
*
*``````````````````````````````*
* THE BSAVE MACRO *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE BSAVE MACRO IS FUNCTIONALLY EQUIVALENT TO
** THE BSAVE COMMAND FROM THE DOS PROMPT. FIRST,
** THE PROVIDED ADDRESS IS STORED IN THE FIRST TWO
** BYTES OF THE FILE TO SUPPLY THE DEAULT LOADING
** ADDRESS. FOLLOWING THAT, THE LENGTH OF THE DATA
** IS STORED IN THE THIRD AND FOURTH BYTES. THE
** DATA IS THEN STORED FOLLOWING THESE BYTES. THIS
** IS HOW DOS ITSELF HANDLES BINARY FILES, AND
** YOUR BINARY FILES SHOULD ALSO FOLLOW THIS SCHEME
** TO AVOID ANGERING THE GODS.
*
** WE WON'T BE GOING THROUGH THE OUTPUT HERE, BUT IF
** YOU EXAMINE THE FILE WITH A TOOL LIKE CIDERPRESS,
** YOU WILL SEE THAT THE FILE SIMPLY CONTAINS THE
** VALUES #$01 TO #$40. BE FOREWARNED THAT YOU WILL
** NOT SEE THE FIRST FOUR BYTES, AS CIDERPRESS HIDES
** THESE TO PREVENT CONFUSION. YOU CAN VIEW THE FIRST
** FOUR BYTES BY LOOKING AT THE SECTOR THE FILE STARTS
** AT.
*
** NOTE AGAIN THAT AN EQUIVALENT MACRO OR SUBROUTINE
** IS NOT PROVIDED IN THIS COLLECTION.
*
JSR ]HOME
_PRN "THE BSAVE MACRO",8D
_PRN "===============",8D8D
_PRN "SAVING BINARY DATA..."
BSAVE #FN7;#MEM40;#$39;#6;#2;#0
_PRN "DONE!!!",8D8D
_WAIT
*
*``````````````````````````````*
* THE FOPEN AND FCLOS MACROS *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE FOPEN MACRO MUST BE RUN BEFORE READING
** OR WRITING A FILE, AND THE FCLOS MACRO MUST
** BE USED AFTERWARDS. IF FOPEN IS NEGLECTED, THE
** FILE WILL NOT BE CREATED; IF FCLOS IS NEGLECTED,
** THEN THAT FILE BUFFER WILL REMAIN IN USE. SINCE
** WE GENERALLY LIKE TO ACTUALLY USE OUR FILES, IT'S
** GOOD PRACTICE TO USE FOPEN AND FCLOS BECAUSE
** UM.. FILE INPUT AND OUTPUT WOULD NOT HAPPEN OTHERWISE.
*
** IF A FILE DOES NOT ALREADY EXIST, FOPEN AUTOMATICALLY
** CREATES A NEW ONE WITH THE PROVIDED FILENAME. HERE,
** WE WILL CREATE A FILE CALLED "TODELETE" THAT WILL BE
** DELETED IN THE NEXT MACRO'S EXPLANATION.
*
JSR ]HOME
_PRN "FOPEN AND FCLOS",8D
_PRN "===============",8D8D
_PRN "CATALOG BEFORE FILE CREATION:",8D8D
_WAIT
FCAT #]ZSLOT;#]ZDRIVE
_WAIT
_PRN " ",8D
_PRN "CATALOG AFTER FILE CREATION:",8D8D
FOPEN #FN8;#]ZSLOT;#]ZDRIVE;#0;#0;#]TYP_TXT
FCLOS #FN8;#]ZSLOT;#]ZDRIVE
_WAIT
FCAT #]ZSLOT;#]ZDRIVE
_WAIT
*
*``````````````````````````````*
* THE FDEL MACRO *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** LASTLY (FOR GOOD REASON), THE FDEL MACRO
** DELETES A FILE WITH THE GIVEN NAME IN THE
** NOTED SLOT AND DISK DRIVE. HERE, LET US
** DELETE THE LAST FILE WE CREATED, "TODELETE".
*
JSR ]HOME
_PRN "THE FDEL MACRO",8D
_PRN "==============",8D8D
_PRN "LOOK MA, NO TODELETE FILE!",8D8D
FDEL #FN8;#]ZSLOT;#]ZDRIVE
_WAIT
FCAT #]ZSLOT;#]ZDRIVE
_WAIT
*
*``````````````````````````````*
* RWTS MACROS *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** WHILE THE RWTS ROUTINE HAS NOT BEEN ABSTRACTED
** TOO MUCH, THIS IS FOR GOOD REASON: OUR HEADER
** FILE IS GETTING TOO BIG FOR ITS BRITCHES!
*
** THE RWTS ROUTINE LETS YOU READ AND WRITE DIRECTLY
** TO A DISK, BYPASSING CONVENTIONS USED BY DOS.
** IT GOES WITHOUT SAYING THAT THIS IS DANGEROUS: THE
** SMALLEST ACCIDENT CAN DESTROY A DISK FOR GOOD, SO
** USE THIS AT YOUR OWN DISCRETION.
*
** THERE ARE TWO MAIN MACROS FOR USING RWTS: THE SRWTS
** MACRO ( (S)ET RWTS ) AND THE GRWTS MACRO. THE SRWTS
** MACRO MUST ALWAYS BE RUN BEFORE GRWTS, AS IT SETS
** THE VARIABLES NEEDED FOR RWTS TO WORK. SINCE THERE
** IS SUCH A THREAT OF DISK CORRUPTION, WE ARE ONLY
** SHOWING HOW TO USE RWTS TO READ THE DISK, NOT WRITE
** IT; HOWEVER, THE PROCESS IS THE SAME FOR BOTH.
*
JSR ]HOME
_PRN "THE RWTS MACROS",8D
_PRN "===============",8D8D
JSR ]LOCRPL
STY ]RWTSPTR
STA ]RWTSPTR+1
*
SRWTS #]ZSLOT;#]ZDRIVE;#0;#$11;#0;#$9000;#1
GRWTS
_PRN "HERE'S THE DISK VTOC:",8D8D
DUMP #$9000;#$F
DUMP #$9010;#$F
DUMP #$9020;#$F
DUMP #$9030;#$F
DUMP #$9040;#$F
DUMP #$9050;#$F
DUMP #$9060;#$F
DUMP #$9070;#$F
_PRN " ",8D
_PRN ".....",8D
_WAIT
*
JSR ]HOME
_PRN "FIN!",8D8D
*
EXIT
JMP $3D0
*
PUT MIN.SUB.FBLOAD.ASM
PUT SUB.FBSAVE.ASM
PUT MIN.LIB.REQUIRED.ASM
*
FN3 STR "RENAMED"
FN5 STR "WRITERANGE"
FN6 STR "BINLOAD"
FN7 STR "BINSAVE"
FN8 STR "TODELETE"
MEM40 HEX 000102030405060708091A1B1C1D1E1F
HEX 101112131415161718191A1B1C1D1E1F
HEX 202122232425262728292A2B2C2D2E2F
HEX 303132333435363738393A3B3C3D3E3F
RANGE STR "ONE RING TO RULE THEM ALL"
RDRANGE DS 25
*
```
`Listing 6.71: DEMO.DOSMORE.ASM Source`
```assembly
*
*``````````````````````````````*
* DEMO.DOSMORE.ASM *
* *
* A DEMO FILE FOR VARIOUS DOS *
* MACROS AND SUBROUTINES. *
* *
* AUTHOR: NATHAN RIGGS *
* CONTACT: NATHAN.RIGGS@ *
* OUTLOOK.COM *
* *
* DATE: 07-MAY-2021 *
* ASSEMBLER: MERLIN 8 PRO *
* OS: DOS 3.3 *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** ASSEMBLER DIRECTIVES
*
CYC AVE
EXP OFF
TR ON
DSK DEMO.DOSMORE
OBJ $BFE0
ORG $6000
*
*``````````````````````````````*
* TOP INCLUDES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
PUT MIN.HEAD.REQUIRED.ASM
USE MIN.MAC.REQUIRED.ASM
USE MIN.MAC.DOSREQ.ASM
USE MIN.MAC.DOSMORE.ASM
PUT MIN.HEAD.DOS.ASM
]HOME EQU $FC58
*
*``````````````````````````````*
* PROGRAM MAIN BODY *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
*``````````````````````````````*
* MISC. DOS MACROS *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
*``````````````````````````````*
* DVER *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE DVER MACRO TESTS WHICH DOS VERSION IS
** BEING USED. IT RETURNS #2 FOR DOS 3.2 AND #3
** FOR DOS 3.X.
*
JSR ]HOME
_PRN "DOS VERSION MACRO (DVER)",8D
_PRN "========================",8D8D
DVER
CMP #3
BEQ THREE
_PRN "USING DOS 2.X",8D
JMP NEXT1
THREE _PRN "USING DOS 3.X",8D
NEXT1
_WAIT
*
*``````````````````````````````*
* THE DOSIN MACRO *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE DOSIN MACRO CHECK WHETHER DOS IS LOADED.
** THIS IS NECESSARY TO CHECK BEFORE TRYING TO
** USE THE DOS FILE MANAGER OR THE RWTS ROUTINES.
*
JSR ]HOME
_PRN "THE DOSIN MACRO",8D
_PRN "===============",8D8D
DOSIN
BCC NODOS
_PRN "DOS IS CURRENTLY LOADED."
JMP NEXT2
NODOS _PRN "DOS IS NOT LOADED."
NEXT2
_WAIT
*
*``````````````````````````````*
* THE ABAS MACRO *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE ABAS MACRO TESTS WHICH VERSION OF
** BASIC IS LOADED: INTEGER OR APPLESOFT.
** IF APPLESOFT IS LOADED, THEN THE CARRY IS
** RETURNED AS TRUE; IF INTEGER BASIC IS LOADED,
** THEN THE CARRY IS RETURNED CLEAR.
*
JSR ]HOME
_PRN "THE ABAS MACRO",8D
_PRN "==============",8D8D
ABAS
BCC INTBAS
_PRN "APPLESOFT IS LOADED."
JMP NEXT3
INTBAS _PRN "INTEGER BASIC IS LOADED."
NEXT3 _WAIT
*
*``````````````````````````````*
* THE IBEX MACRO *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE IBEX MACRO TESTS WHETHER INTEGER BASIC
** IS RUNNING. THE CARRY IS RETURNED AS TRUE IF SO,
** AND CLEAR IF NOT. NOTE THAT YOU SHOULD TEST IF
** INTEGER BASIC IS LOADED BEFOREHAND; OTHERWISE,
** A FALSE POSITIVE MAY RESULT.
*
JSR ]HOME
_PRN "THE IBEX MACRO",8D
_PRN "==============",8D8D
IBEX
BCC INTNORUN
_PRN "INTEGER BASIC IS RUNNING."
JMP NEXT4
INTNORUN _PRN "INTEGER BASIC IS NOT RUNNING."
NEXT4 _WAIT
*
*``````````````````````````````*
* THE ABEX MACRO *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THE ABEX MACRO TESTS WHETHER AN APPLESOFT
** PROGRAM IS CURRENTLY RUNNING.
*
JSR ]HOME
_PRN "THE ABEX MACRO",8D
_PRN "==============",8D8D
ABEX
BCC NOAPP
_PRN "APPLESOFT PROGRAM IS RUNNING."
JMP NEXT5
NOAPP _PRN "APPLESOFT PROGRAM IS NOT RUNNING."
NEXT5 _WAIT
*
JSR ]HOME
_PRN "FIN!",8D8D
*
EXIT
JMP $3D0
*
PUT MIN.LIB.REQUIRED.ASM
*
```