        PAGE    DESCRIPTIONS        TITLE   BINARY ACCESS ROUTINES*       THE FOLLOWING ROUTINES MAKE UP THIS PACKAGE:**       *       INIT:*               THIS ROUTINE IS USED TO INFORM THE PACKAGE THAT*               A NEW BINARY FILE HAS BEEN OPENED ON A CHANNEL.*               THE CALLING SEQUENCE FROM BASIC IS:**               CALL INIT(CHANNEL,BUFFER$,ARRAY$)**               CHANNEL, WHICH MUST BE <256 AND >-1 AND AN INTEGER,*               IS THE CHANNEL ON WHICH THE BINARY FILE IS ALREADY OPEN.*               THIS PACKAGE IS WILLING TO HANDLE ANY BINARY OBJECT*               FOR 6800, 6801 AND/OR 6809, SO THE CALLER MUST VERIFY*               THE TYPE OF OBJECT FILE.**               BUFFER$ IS USED BY THE ACCESS PACKAGE AS AN I/O*               BUFFER; THUS, THE PROGRAM WILL ONLY DO SINGLE*               BYTE I/O WHEN MAXLEN(BUFFER$)=1.*               THE OPTIMUM SIZE IS*               DETERMINED BY ALL SORTS OF THINGS TOO COMPLICATED*               TO THINK ABOUT; BUT A GOOD RULE OF THUMB IS:*               MAKE MAXLEN(BUFFER$) >= THE AVERAGE SIZE OF DATA*               YOU PLAN TO ACCESS SEQUENTIALLY.  SO IF YOU PLAN*               TO DO SECTOR SIZE ACCESSES, MAKE IT A SECTOR SIZE.*               IF YOU PLAN TO BE CHASING 2 BYTE POINTERS, MAKE*               LEN(BUFFER$)>=2. THIS SHOULD BE TEMPERED BY THE REALIZATION*               THAT SDOS TAKES ABOUT THE SAME AMOUNT OF TIME TO ACCESS*               1 BYTE FROM A FILE AS IT DOES TO ACCESS 50,*               SO A BUFFER SIZE OF 50 CANNOT HURT MUCH AND IT*               COULD BE VERY HELPFUL.**               ARRAY$ IS USED BY THE PACKAGE TO KEEP TRACK OF*               THE STRUCTURE OF THE BINARY FILE.  ITS SIZE*               (IN BYTES) NEEDS TO BE AT LEAST 8*(# OF LOAD DATA RECORDS)*               THE STRUCTURE OF ENTRIES IN THE ARRAY IS:**               LOWER BOUND     2 BYTES  \*               UPPER BOUND     2 BYTES   )  REPEATED ONCE PER RECORD*               FILE POSITION   4 BYTES  /**               THERE IS ONE ENTRY PER LOAD RECORD. SKIP AND START RECORDS*               ARE NOT RECORDED IN THE ARRAY.**               LOWER BOUND CONTAINS THE ADDRESS OF THE LOWEST ADDRESS BYTE*               IN THE BINARY RECORD REPRESENTED BY THIS DESCRIPTOR, WHILE*               UPPER BOUND HAS THE ADDRESS OF THE HIGHEST BYTE ACTUALLY*               CONTAINED IN THE RECORD (THIS HANDLES CASE OF RECORD*               WHOSE LAST BYTE IS AT :FFFF).*               THE FILE POSITION POINTS TO THE BYTE THAT WOULD BE LOADED*               INTO THE MEMORY ADDRESS SPECIFIED BY LOWER BOUND.        PAGE*       RELEASE:*               THIS SUBROUTINE MUST BE INVOKED BEFORE THE PROGRAM*               CLOSES THE BINARY FILE; RELEASE FLUSHES ANY*               BUFFERED DATA IT KEEPS BACK OUT TO THE DISK.*               FAILURE TO INVOKE RELEASE BEFORE CLOSING THE CHANNEL*               WILL PROBABLY RESULT IN DAMAGE TO THE BINARY FILE.*               THE CALL FORMAT FROM BASIC IS:**               CALL RELEASE(CHANNEL)*        PAGE*       PUTBYTE AND GETBYTE:**               THESE TWO SUBROUTINES ARE USED TO DO THE ACTUAL*               ACCESSING OF THE BINARY FILE.  THE CALL FORMAT IS:**               CALL GETBYTE(CHANNEL,ADDRESS,BYTE$)*                            AND*               CALL PUTBYTE(CHANNEL,ADDRESS,BYTE$)**               CHANNEL IS, OF COURSE, THE CHANNEL NUMBER*               THE ON WHICH THE BINARY FILE IS OPEN.  THE CHANNEL*               MUST HAVE PREVIOUSLY BEEN INITed.**               ADDRESS IS A AN EXPRESSION WHICH CONTAINS*               A SIXTEEN BIT INTEGER WHICH IS THE LOAD ADDRESS*               DESIRED FOR THE FIRST BYTE OF BYTE$.**               BYTE$ IS EITHER THE SOURCE (IN PUT) OR THE*               DESTINATION (IN GET) OF THE BYTE FOR I/O.*               IF THE LEN(BYTE$)>1, THEN THE PROGRAM*               WILL SEQUENTIALLY PUT OR GET BYTES FOR ALL*               BYTES IN BYTE$**               IF GETBYTE CANNOT FIND A LOAD RECORD WHICH LOADS*               INTO THE ADDRESS SPECIFIED, IT WILL SIMPLY*               RETURN A ZERO, WITH NO ERRORS AND NO FLAGS;*               THUS, A BINARY FILE CAN BE THOUGHT TO HAVE*               64K BYTES IN IT AND LOAD RECORDS ARE A FORM*               OF SPARSENESS.**               IF PUTBYTE CANNOT FIND A LOAD RECORD WHICH LOADS*               INTO THE ADDRESS SPECIFIED, IT WILL DO ONE*               OF TWO THINGS:**               1)  IF THE LAST LOAD RECORD (THE TYPE 3 RECORD)*                   HAPPENS TO STOP ONE BYTE SHORT OF ADDRESS,*                   PUTBYTE WILL EXTEND THE RECORD TO INCLUDE*                   THE NEW BYTE.**               2)  OTHERWISE, PUTBYTE WILL FIRST CHANGE THE*                   TYPE 3 RECORD INTO A TYPE 2 RECORD, AND THEN*                   CREATE A NEW, ONE BYTE TYPE 3 RECORD WHICH*                   CONTAINS THE BYTE WRITTEN OUT AND LOADS TO THE*                   SPECIFIED ADDRESS. 1) WILL TAKE CARE OF THE CASES*                   IN WHICH BYTE$ HAS A LENGTH OF 2 OR MORE.**               THUS, PUTBYTE WILL ALWAYS WORK, EVEN IF THERE ARE*               NO LOAD RECORDS TO PUT THE BYTE IN.  THE ONLY*               TIME PUTBYTE WILL FAIL IS IF THE ARRAY$ BECOMES*               FULL, OR IF AN SDOS I/O ERROR OCCURS.        PAGE*       KNOWN PROBLEMS:*               <EOF> WHILE 'INIT'ING A CHANNEL IS TREATED LIKE*               AN ENDLESS STREAM OF SKIP RECORDS. THIS IS VERY TACKY.**               IF NO LOAD RECORD EXISTS IN FILE, THIS PROCEDURE RETURNS*               A "ZERO" INSTEAD OF A "NO SUCH RECORD" (OR SOME OTHER)*               ERROR. THIS COULD BE USEFUL.        PAGE    DEFINITIONS        IFUND   M6800M6800   EQU     1M6801   EQU     0M6809   EQU     0        FIN:X:     SET     ****       D E F I N I T I O N S**        ORG     0**       C H A N N E L   T A B L E**       E N T R Y   D I S P L A C E M E N T S*ENTRY:ARRAYADDRESS RMB  2              ADDRESS OF ARRAY$ STORAGEENTRY:ARRAYSIZE    RMB  2              SIZE OF ARRAY, IN BYTESENTRY:STARTADDRESS RMB  2              START ADDRESS OF FILEENTRY:LASTRECORDPTR RMB 2              -> LAST RECORD DESCRIPTOR IN ARRAYENTRY:LASTRECORDHEADERDIRTY RMB 1      HEADER OF LAST RECORD NEEDS TO BE UPDATEDENTRY:BUFFERPTR RMB     2              POINTER TO WORK BUFFERENTRY:BUFFERLEN RMB     2              CURRENT LENGTH OF WORK BUFFERENTRY:BUFFERMAX RMB     2              TOTAL SPACE AVAILABLE TO WORK BUFFERENTRY:BUFFERFILEPOS RMB 4              WHERE BUFFER GOES IN OBJECT FILEENTRY:BUFFERDIRTY RMB   1              BUFFER CONTENTS HAVE BEEN CHANGEDENTRY:SIZE      EQU     *        PAGE**       A R R A Y   D I S P L A C E M E N T S*        ORG     0ARRAY:LOWER     RMB     2          ADDRESS OF LOWEST BYTE IN LOAD RECORDARRAY:UPPER     RMB     2          ADDRESS OF HIGHEST BYTE IN LOAD RECORD, +1?ARRAY:POSITION  RMB     4          WHERE LOAD RECORD IS IN OBJECT FILEARRAY:SIZE      EQU     *          NEXT DESCRIPTOR RECORD STARTS HERE******************************************************************************        LIST    0SYSTEMDEFS EQU 1                       I WANT SYSTEM DEFS (LOAD:XXX DEFS)        INCLUDE    SDOSUSERDEFS.ASM        LIST    1******************************************************************************        ORG     :X:        IFUND   DEBUG        ELSE        ORG     $5800              FOR DEBUGGING PURPOSES ONLY!        FIN        PAGE    I N I T I A L I Z E**       INITIALIZE CALL*INIT    STS     ERRORRECOVERYSTACK     IN CASE OF DISASTER        JSR     GETSTRING              GET ARRAY$        PSHD                           SAVE ARRAY LENGTH        PSHX                           SAVE ARRAY ADDRESS        LDX     ARGLIST        LEAX    6,X                    NEXT ARG, PLEEZ...        JSR     GETSTRING              GET BUFFER$        PSHD                           SAVE BUFFER MAX LENGTH        PSHX                           AND ADDRESS OF BUFFER        LDX     ARGLIST        LEAX    6,X                    GET POINTER TO NEXT PARAMETER        JSR     GETINT                 GET CHANNEL NUMBER INTO (A,B)        TFR     B,A        JSR     COMPUTEENTRY           SET UP ENTRYPTR INTO CHANNEL TABLE        PULD                           = ADDRESS OF BUFFER        STD     ENTRY:BUFFERPTR,X      SAVE BUFFER ADDRESS AND MAX SIZE        PULD        STD     ENTRY:BUFFERMAX,X        CLR     ENTRY:BUFFERLEN,X      MAKE BUFFER EMPTY        CLR     ENTRY:BUFFERLEN+1,X    SO IT IS PURGED ON 1ST USE        CLR     ENTRY:BUFFERDIRTY,X    AND MARK IT AS "CLEAN"        PULD                           SAVE ARRAY ADDRESS AND LENGTH        STD     ENTRY:ARRAYADDRESS,X        SUBD    #ARRAY:SIZE            = ADDRESS OF "LAST" RECORD IN LOAD FILE        STD     ENTRY:LASTRECORDPTR,X  INITIALIZE ARRAY TO EMPTY        PULD        STD     ENTRY:ARRAYSIZE,X        PAGE                           PROCESS START RECORD        CLR     CURPOS        CLR     CURPOS+1        CLR     CURPOS+2        CLR     CURPOS+3               "RESTORE #CHANNEL, 0"        JSR     READBYTE               PROCESS THE START RECORD        TSTA                           CHECK FOR STARTS WITH 0...        BEQ     ERRNOTLOADFILE         B/ NOT A LOAD FILE        CMPA    #3                     START LIKE 6800, 6801 OR 6809 FILE ?        BHI     ERRNOTLOADFILE         B/ NO, GIVE UP NOW!        JSR     READDOUBLEBYTE        LDX     ENTRYPTR               SAVE START ADDRESS        STD     ENTRY:STARTADDRESS,X        JSR     READDOUBLEBYTE        LDX     ENTRYPTR        EORA    ENTRY:STARTADDRESS,X        EORB    ENTRY:STARTADDRESS+1,X        CMPD    #$FFFF                 START ADDRESS PROPERLY COMPLEMENTED ?        BNE     ERRBADLOADRECORD       B/ NO, NOT A LOAD FILE        PAGE    SCAN LOAD RECORDSGETBINARYRECS ; PROCESS THE FILE TO GET LOAD RECORD ADDRESSES        JSR     READBYTE        CMPA    #LOAD:TYPE2        BEQ     PROCESSLOADRECORD        CMPA    #LOAD:TYPE3        BEQ     PROCESSGORECORD        CMPA    #LOAD:TYPE0        BEQ     PROCESSSKIPRECORDERRBADLOADRECORD ; ILLEGAL LOAD RECORD ENCOUNTERED        LDX     #ERR:BADLOADRECORD        JMP     ERRORERRNOTLOADFILE        LDX     #ERR:NOTALOADFILE        JMP     ERRORPROCESSSKIPRECORD ; SKIP RECORD ENCOUNTERED        JSR     READDOUBLEBYTE         GET SKIP COUNT        JSR     ADDTOCURPOS            HOW'S THAT FOR EASY!        BRA     GETBINARYRECSPROCESSLOADRECORD ; LOAD RECORD, BUT NOT LAST ONE...        BSR     PROCESSLOADRECORD1        BRA     GETBINARYRECSPROCESSGORECORD ; LAST LOAD RECORD        BSR     PROCESSLOADRECORD1        OKRTS                          DONE!ERRNOTENOUGHROOM ; TOO MANY LOAD RECORDS TO HANDLE WITH ALLOCATION GIVEN ARRAY$        LDX     #ERR:NOTENOUGHROOM        JMP     ERROR        PAGEPROCESSLOADRECORD1 ; (HEART OF) PROCESS LOAD RECORD        LDX     ENTRYPTR               ENOUGH ROOM FOR ANOTHER LOAD RECORD ?        LDD     ENTRY:LASTRECORDPTR,X        ADDD    #2*ARRAY:SIZE          = ADDRESS OF 1ST BYTE NOT NEEDED        SUBD    ENTRY:ARRAYADDRESS,X   = AMOUNT OF SPACE DESIRED FOR USE        CMPD    ENTRY:ARRAYSIZE,X      = AMOUNT OF SPACE AVAILABLE        BHI     ERRNOTENOUGHROOM B/ OUT OF ROOM        LDD     ENTRY:LASTRECORDPTR,X  GET POINTER TO LAST RECORD, AGAIN        ADDD    #ARRAY:SIZE            MAKE POINTER TO NEW LAST RECORD        STD     ENTRY:LASTRECORDPTR,X        JSR     READDOUBLEBYTE         READ VIRTUAL ADDRESS OF 1ST DATA BYTE        LDX     ENTRYPTR               IN RECORD        LDX     ENTRY:LASTRECORDPTR,X        STD     ARRAY:LOWER,X        JSR     READDOUBLEBYTE         READ NUMBER OF BYTES IN RECORD        PSHD                           AND SAVE        LDX     ENTRYPTR        LDX     ENTRY:LASTRECORDPTR,X        ADDD    ARRAY:LOWER,X          COMPUTE VIRTUAL ADDRESS OF LAST BYTE...        SUBD    #1                     IN LOAD RECORD        STD     ARRAY:UPPER,X        LDD     CURPOS                 SAVE FILE POSITION OF 1ST DATA BYTE...        STD     ARRAY:POSITION,X       IN RECORD        LDD     CURPOS+2        STD     ARRAY:POSITION+2,X        PULD                           = NUMBER OF DATA BYTES IN RECORD        JMP     ADDTOCURPOS            SKIP PAST DATA PART OF LOAD RECORD        PAGE*       GETBYTE(ADDRESS$,BYTE$,CHANNEL)*GETBYTE STS     ERRORRECOVERYSTACK     SAVE ERRORY RECOVER STACK POINTER        JSR     GETPARAMS              GET PARAMETERS OF CALLGETBYTEL BSR    GET1BYTE               GET ONE BYTE OF DESIRED DATA        LDX     BINARYADDRESS          ADVANCE POINTERS        INX        STX     BINARYADDRESS        LDX     BYTEADDRESS        INX        STX     BYTEADDRESS        LDX     BYTECOUNT              DECREMENT COUNT        DEX        STX     BYTECOUNT        BNE     GETBYTEL               B/ MORE BYTES TO GET        RTSGET1BYTE ; GET ONE BYTE (SUBROUTINE FOR GETBYTE)        JSR     CONVERTTOPHYSICAL        CLRA                           ASSUME BYTE DOESN'T EXIST        LDX     CURPOS                 DOES BYTE EXIST ?        CPX     #$FFFF        BEQ     GET1BYTEZ              B/ BYTE DOESN'T EXIST, RETURN ZERO        JSR     READBYTEGET1BYTEZ        STA     [BYTEADDRESS]        RTS        PAGE    PUTBYTE*       PUTBYTE(ADDRESS$,BYTE$,CHANNEL)*PUTBYTE STS     ERRORRECOVERYSTACK     SAVE SP IN CASE OF DISASTER        JSR     GETPARAMS              GET PARAMETERSPUTBYTEL BSR    PUT1BYTE        LDX     BYTEADDRESS            ADVANCE POINTERS        INX        STX     BYTEADDRESS        LDX     BINARYADDRESS        INX        STX     BINARYADDRESS        LDX     BYTECOUNT        DEX        STX     BYTECOUNT        BNE     PUTBYTEL               B/ MORE BYTES TO PUT        RTSPUT1BYTE ; PUT ONE BYTE TO OBJECT FILE (SUBROUTINE FOR PUTBYTE)        JSR     CONVERTTOPHYSICAL        LDX     CURPOS                 DOES BYTE EXIST IN OBJECT FILE ?        CPX     #$FFFF        BNE     PUT1BYTE.STORE         B/ YES, GO STORE THE BYTEEXTENDFILE ; EXTEND BINARY FILE SO IT HAS ROOM FOR DATA BYTE        LDX     ENTRYPTR               SEE IF POSSIBLE TO EXTEND...        LDX     ENTRY:LASTRECORDPTR,X  LAST LOAD RECORD OF FILE        LDD     ARRAY:UPPER,X          LAST BYTE OF RECORD + 1 = NEW ADDRESS ?        ADDD    #1        CMPD    BINARYADDRESS          ...?        BNE     CREATENEWRECORD        B/ NO, MUST CREATE A NEW LOAD RECORD        STD     ARRAY:UPPER,X          YES, EXTEND THIS RECORD BY ONE BYTE        JSR     FOUNDRECORD            SET CURPOS TO CORRECT VALUE FOR WRITEBYTE        LDX     ENTRYPTR               MARK LAST RECORD HEADER AS "UPDATE REQD"        LDA     #1                     THIS PATH IS INTENDED TO BE FAST!        STAA    ENTRY:LASTRECORDHEADERDIRTY,XPUT1BYTE.STORE ; LOAD RECORD EXISTS, STORE INTO IT        LDA     [BYTEADDRESS]        JMP     WRITEBYTE        PAGECREATENEWRECORD ; MUST CREATE A NEW LOAD RECORD        JSR     UPDATELASTLOADRECORDHEADER TO MAKE SURE IT IS CLEAN        LDX     ENTRYPTR        LDD     ENTRY:ARRAYADDRESS,X   DETERMINE END OF DESCRIPTOR ARRAY        ADDD    ENTRY:ARRAYSIZE,X    = ARRAY ADDRESS + LENGTH IN BYTES        SUBD    #2*ARRAY:SIZE          = HIGHEST ADDRESS ALLOWED FOR...*                                      OLD LAST DESCRIPTOR, IF THERE IS...*                                      ENOUGH ROOM FOR NEW DESCRIPTOR        CMPD    ENTRY:LASTRECORDPTR,X  AVAILABLE ARRAY SPACE EXCEEDED ?        LBLO    ERRNOTENOUGHROOM       B/ NOT ENOUGH ROOM        LDX     ENTRY:LASTRECORDPTR,X        LDD     ARRAY:POSITION+2,X     CONVERT OLD LAST RECORD...        SUBD    #5                     FROM "GO" RECORD TO "LOAD" RECORD        STD     CURPOS+2               COMPUTE RECORD TYPE BYTE FILE POSITION        LDD     ARRAY:POSITION,X        SBCB    #0        SBCA    #0        STD     CURPOS                 (CURPOS NOW POINTS TO RECORD TYPE BYTE)        LDD     ARRAY:UPPER,X          COMPUTE SIZE OF BODY OF OLD LAST RECORD        SUBD    ARRAY:LOWER,X          = UPPER-LOWER+1        ADDD    #1+5                   ADD 5 TO HANDLE RECORD HEADER        ADDD    ARRAY:POSITION+2,X     COMPUTE FILE POSITION FOR NEW RECORD        STD     ARRAY:POSITION+2+ARRAY:SIZE,X AND SAVE        LDD     ARRAY:POSITION,X        ADCB    #0        ADCA    #0        STD     ARRAY:POSITION+ARRAY:SIZE,X        LDD     BINARYADDRESS          FILL IN THE RECORD DESCRIPTOR INFO        STD     ARRAY:LOWER+ARRAY:SIZE,X SAVE ADDRESS BOUNDS ON NEW RECORD        STD     ARRAY:UPPER+ARRAY:SIZE,X        LDAA    #LOAD:TYPE2            = RECORD TYPE TO CHANGE LAST RECORD TO        JSR     WRITEBYTE        LDX     ENTRYPTR               RECORD NEW RECORD DESCRIPTOR EXISTENCE        LDD     ENTRY:LASTRECORDPTR,X        ADDD    #ARRAY:SIZE        STD     ENTRY:LASTRECORDPTR,X        LDA     #1                     MARK LAST RECORD HEADER AS "UPDATE REQD"        STAA    ENTRY:LASTRECORDHEADERDIRTY,X        JMP     PUT1BYTE               NOW START THE PUTBYTE PROCESS AGAIN        PAGE    UPDATE LAST LOAD RECORD HEADERUPDATELASTLOADRECORDHEADER ; REWRITES HEADER OF LAST LOAD RECORD IF CHANGED        LDX     ENTRYPTR               LAST LOAD RECORD HEADER NEED UPDATE ?        TST     ENTRY:LASTRECORDHEADERDIRTY,X ...?        BEQ     UPDATELASTLOADRECORDHEADERRTS B/ NO        CLR     ENTRY:LASTRECORDHEADERDIRTY,X CLEAR THE FLAG        LDX     ENTRY:LASTRECORDPTR,X  GET POINTER TO LAST RECORD DESCRIPTOR        LDD     ARRAY:POSITION+2,X     COMPUTE RECORD TYPE BYTE FILE POSITION        SUBD    #5        STD     CURPOS+2        LDD     ARRAY:POSITION,X        SBCB    #0        SBCA    #0        STD     CURPOS        LDAA    #LOAD:TYPE3            WRITE LOAD RECORD TYPE TO DISK FILE        JSR     WRITEBYTE        LDX     ENTRYPTR               FETCH BASE ADDRESS OF RECORD        LDX     ENTRY:LASTRECORDPTR,X        LDD     ARRAY:LOWER,X        PSHB                           AND WRITE BASE ADDRESS TO FILE        JSR     WRITEBYTE        PULA        JSR     WRITEBYTE        LDX     ENTRYPTR               COMPUTE NUMBER OF BYTES IN RECORD        LDX     ENTRY:LASTRECORDPTR,X        LDD     ARRAY:UPPER,X          = UPPER-LOWER+1        SUBD    ARRAY:LOWER,X        ADDD    #1        PSHB                           AND WRITE COUNT TO FILE        JSR     WRITEBYTE        PULA        JSR     WRITEBYTEUPDATELASTLOADRECORDHEADERRTS ; UPDATE OF LOAD RECORD HEADER IS COMPLETE        RTS        PAGE    READ/WRITE BYTE**       READ BYTE: ADDRESS IS IN CURPOS**READBYTE ; READ BYTE FROM FILE @ CURPOS        JSR     LOCATEBYTE        LDAA    0,X        PSHA        JSR     BUMPCURPOS             GO ADD 1 TO CURPOS        PULA        RTS**       READ DOUBLE BYTE*READDOUBLEBYTE ; READ BYTE PAIR, RETURN RESULT IN (D)        BSR     READBYTE        PSHA        BSR     READBYTE        TFR     A,B        PULA        RTS**       WRITE BYTE*WRITEBYTE ; WRITE BYTE IN (A) TO DISK FILE AT "CURBYTE" FILE POSITION        PSHA        JSR     LOCATEBYTE        PULA        STAA    0,X        LDX     ENTRYPTR        LDD     #1                     MARK "BUFFER IS DIRTY"        STB     ENTRY:BUFFERDIRTY,X        JMP     BUMPCURPOS             ADVANCE CURPOS BY 1        PAGE    LOCATE BYTE**       L O C A T E   B Y T E*       LOCATES BYTE IN "CURPOS" IN FILE.*       READS INTO BUFFER SO BYTE IS ACCESSIBLE.*       RETURNS POINTER TO BYTE IN BUFFER IN (X)*LOCATEBYTE ; LOCATE BYTE WITHIN BUFFER        LDX     ENTRYPTR               DOES CURRENT BUFFER CONTAIN BYTE ?*       I.E., IS ENTRY:BUFFERFILEPOS<=CURPOS AND*       CURPOS<ENTRY:BUFFERPOS+ENTRY:BUFFERLEN ?        LDD     CURPOS+2               IS CURPOS>=ENTRY:BUFFERFILEPOS ?        SUBD    ENTRY:BUFFERFILEPOS+2,X        BLO     LOCATEBYTED            B/ CURPOS<ENTRY:BUFFERFILEPOS        LDD     CURPOS        SBCB    ENTRY:BUFFERFILEPOS+1,X        BNE     LOCATEBYTED            B/ CURPOS>=2^16 BYTES PAST BUFFERFILEPOS        SBCA    ENTRY:BUFFERFILEPOS,X        BNE     LOCATEBYTED            B/ CURPOS>=2^24 BYTES PAST BUFFERFILEPOS        BCS     LOCATEBYTED            B/ CURPOS<ENTRY:BUFFERFILEPOS        LDD     CURPOS+2               CURPOS>=ENTRY:BUFFERPOS, BY HOW MUCH ?        SUBD    ENTRY:BUFFERFILEPOS+2,X ( (D) NOW HAS DISTANCE )        CMPD    ENTRY:BUFFERLEN,X      IS CURPOS-ENTRY:BUFFERFILEPOS>BUFFERLEN?        BLO     LOCATEBYTEFOUND        B/ BYTE DESIRED IS IN BUFFER !LOCATEBYTED ; MUST DUMP CURRENT BUFFER AND FETCH A NEW ONE        BSR     PURGEBUFFER            GET RID OF OLD BUFFER CONTENTS        LDX     ENTRYPTR               NOW FETCH BUFFER OF STUFF        LDD     CURPOS                 REMEMBER WHERE BUFFER WILL COME FROM...        STD     ENTRY:BUFFERFILEPOS,X     IN THE FILE        LDD     CURPOS+2        STD     ENTRY:BUFFERFILEPOS+2,X        JSR     DOPOSITION             POSITION THE FILE        LDX     ENTRYPTR               NOW READ A BUFFERFUL FROM THE FILE        LDD     ENTRY:BUFFERMAX,X        LDX     ENTRY:BUFFERPTR,X        STX     READBLOCK+SCBLK:RDBUF        STD     READBLOCK+SCBLK:RDLEN        LDX     #READBLOCK        JSR     SYSCALL$        BCC     LOCATEBYTE1            B/ NO ERROR ON READ        CPX     #ERR:EOFHIT        LBNE    ERROR                  B/ NOT EOF, I CAN'T HANDLE IT!LOCATEBYTE1        LDX     ENTRYPTR               UPDATE BUFFER SIZE INFO        LDD     READBLOCK+SCBLK:RPLEN        STD     ENTRY:BUFFERLEN,X        BNED    LOCATEBYTEFOUND        B/ # BYTES READ > 0        INC     ENTRY:BUFFERLEN+1,X    TREAT AS THOUGH 1 ZERO BYTE WERE READ        CLR     [READBLOCK+SCBLK:RDBUF] THIS CASE OCCURS WHEN READING AT EOFLOCATEBYTEFOUND ; BYTE IS FOUND WITHIN BUFFER        LDX     ENTRYPTR        LDD     CURPOS+2        SUBD    ENTRY:BUFFERFILEPOS+2,X        ADDD    ENTRY:BUFFERPTR,X        TDX                            COPY POINTER TO BYTE TO (X)        RTS        PAGE    RELEASE**       RELEASE(CHANNEL)*RELEASE STS     ERRORRECOVERYSTACK     IN CASE OF DISASTER        JSR     GETINT                 GET INTEGER ARGUMENT        TFR     B,A        JSR     COMPUTEENTRY           DETERMINE WHICH BINARY FILE IS DESIRED        JSR     UPDATELASTLOADRECORDHEADER UPDATE LAST RECORD HEADER IF NEEDED*       JSR     PURGEBUFFER            FORCE LAST BUFFERFUL BACK TO DISK*       RTS        PAGE    PURGEBUFFERPURGEBUFFER ; IF BUFFER IS DIRTY, WRITE IT BACK TO DISK        LDX     ENTRYPTR               GET POINTER TO DESCRIPTOR INFO BLOCK        TST     ENTRY:BUFFERDIRTY,X    NEED TO WRITE BINARY BUFFER TO DISK ?        BEQ     PURGEBUFFERRTS         B/ NO        CLR     ENTRY:BUFFERDIRTY,X    YES, RESET "MUST WRITE" FLAG        BSR     DOPOSITION             POSITION FILE TO LOGICAL BUFFER POSITION        LDX     ENTRYPTR               NOW ISSUE A WRITE TO GET RID OF BLOCK        LDD     ENTRY:BUFFERLEN,X        LDX     ENTRY:BUFFERPTR,X        STX     WRITEBLOCK+SCBLK:WRBUF        STD     WRITEBLOCK+SCBLK:WRLEN        LDX     #WRITEBLOCK        JSR     SYSCALL$        LBCS    ERRORPURGEBUFFERRTS        RTSDOPOSITION ; POSITION TO ENTRY:BUFFERPOS ON DESIRED CHANNEL        LDAA    CHANNEL        STAA    POSITIONBLOCK+SCBLK:PARAMS        STAA    READBLOCK+SCBLK:PARAMS FOR CONVENIENCE, SINCE I'M HERE...        STAA    WRITEBLOCK+SCBLK:PARAMS        LDD     ENTRYPTR        ADDD    #ENTRY:BUFFERFILEPOS        STD     POSITIONBLOCK+SCBLK:WRBUF        LDX     #POSITIONBLOCK        JSR     SYSCALL$        BCC     DOPOSITIONRTS          B/ NO ERROR, JUST LEAVE        CPX     #ERR:EOFHIT        LBNE    ERRORDOPOSITIONRTS        OKRTS        PAGE    GET STRING*       GET STRING: X POINTS TO A STRING DESCRIPTOR**       RETURNS: X POINTS TO FIRST BYTE OF STRING BODY*                (A,B) = CURRENT LENGTH OF STRING*GETSTRING ; CONVERT STRING DESCRIPTOR INTO ADDRESS AND COUNT        STX     ARGLIST                SAVE POINTER TO THIS ARGUMENT        LDD     4,X                    GET STRING SIZE        LDX     2,X                    GET STRING ADDRESS        CMPD    #$FFFF                 "THE WHOLE STRING..." ?        BNE     GETSTRING1             B/ NO        LDD     2,X                    USE CURLEN OF STRING AS SIZEGETSTRING1        LEAX    4,X                    = ADDRESS OF 1ST DATA BYTE IN STRING        RTS*       GETINT -- GETS THE 16 BIT INTEGER POINTED TO BY BASIC ARGUMENT AT (X)*GETINT ; GET INTEGER ARGUMENT VALUE        STX     ARGLIST                SAVE POINTER TO THIS ARGUMENT        LDX     4,X                    GET ADDRESS OF VALUE FROM ARGUMENT        LDD     4,X                    FETCH INTEGER PART OF 6 BYTE VALUE        RTS        PAGE    GET PARAMETERS FROM BASIC PROGRAM*       GET PARAMETERS**       ENTRY PARAMETERS**       X=> (CHANNEL,ADDRESS,BYTE$) FROM BASIC**       EXIT:**       BINARYADDRESS= VALUE OF ADDRESS ARGUMENT*       BYTECOUNT= LEN(BYTE$)*       BYTEADDRESS= ADDRESS OF DATA IN BYTE$*GETPARAMS ; GET PARAMETERS FOR "GETBYTE" OR "PUTBYTE"        JSR     GETSTRING              GET INFO ABOUT THE BUFFER TO FILL/EMPTY        STD     BYTECOUNT        STX     BYTEADDRESS        LDX     ARGLIST        LEAX    6,X        JSR     GETINT                 GET ADDRESS DESIRED        STD     BINARYADDRESS        LDX     ARGLIST        LEAX    6,X        JSR     GETINT  GET THE CHANNEL #        STAB    CHANNEL        TFR     B,ACOMPUTEENTRY ; (A) = CHANNEL NUMBER        ; (X) AND ENTRYPTR ON EXIT POINT TO ENTRY: SLOT        STAA    CHANNEL        ASLA            *2        LDAB    #CHANNELTABLE/256        STAB    TEMPX                  LOOK CAREFULLY BEFORE YOU TRY TO...        STAA    TEMPX+1                OPTIMIZE THIS FOR THE '09!!!        LDX     TEMPX        LDX     CHANNELTABLE&$FF,X        STX     ENTRYPTR        RTS        PAGE    CONVERT BINARY ADDRESS TO CURPOS***       CONVERT TO PHYSICAL:**       CONVERTS BINARYADDRESS TO CURPOS**       SEARCHES RECORD LIST BACKWARDS...*       SO THAT THE "LATEST" LOAD RECORD CONTAINING THE ADDRESS IS FOUND*       THIS HANDLES PATCHED FILES PROPERLY**       IF THERE IS NO LOAD RECORD FOR BINARYADDRESS,*       RETURNS $FFFFFFFF IN CURPOS*CONVERTTOPHYSICAL        LDX     ENTRYPTR        LDD     ENTRY:ARRAYADDRESS,X   SAVE ADDRESS OF FIRST RECORD        STD     TEMPX                  (USED TO LIMIT LOOP SEARCH)        LDX     ENTRY:LASTRECORDPTR,X  GET POINTER TO LAST RECORD DESCRIPTOR        LDD     BINARYADDRESS          GET ADDRESS TO SEARCH FORFINDRECORDLOOP ; SEE IF DESIRED ADDRESS IS COVERED BY DESCRIPTOR AT (X)        CMPD    ARRAY:LOWER,X          ADDRESS>LOWER?        BLO     TRYNEXTRECORD          B/ ADDRESS NOT COVERED BY THIS LOAD RECORD        CMPD    ARRAY:UPPER,X        BLS     FOUNDRECORD            B/ ADDRESS IS COVERED BY THIS RECORDTRYNEXTRECORD ; BECAUSE THIS ONE ISN'T THE RIGHT ONE        CPX     TEMPX                  SEARCHED THE COMPLETE LIST ?        BEQ     RECORDNOTFOUND         B/ YES, NO RECORD EXISTS        LEAX    -ARRAY:SIZE,X          NO, BACK UP TO PREVIOUS ONE        BRA     FINDRECORDLOOPFOUNDRECORD ; WE FOUND THE CORRECT RECORD        SUBD    ARRAY:LOWER,X        ADDD    ARRAY:POSITION+2,X        STD     CURPOS+2        LDD     ARRAY:POSITION,X        ADCB    #0        ADCA    #0        STD     CURPOS        RTSRECORDNOTFOUND ; NO RECORD CONTAINS "BINARYADDRESS"        LDX     #$FFFF                 SIGNAL "NOT FOUND"...        STX     CURPOS        STX     CURPOS+2        RTS        PAGE    MISC ROUTINESERROR   LDS     ERRORRECOVERYSTACK     CLEAN GARBAGE FROM STACK        SEC                            SIGNAL AN ERROR        RTS                            AND EXIT!BUMPCURPOS ; ADD 1 TO CURPOS        LDD     #1                     = AMOUNT TO ADDADDTOCURPOS ; ADD (D) TO CURPOS        ADDD    CURPOS+2        STD     CURPOS+2        LDD     CURPOS        ADCB    #0        ADCA    #0        STD     CURPOS        RTS        PAGE    DATAERRORRECOVERYSTACK  RMB  2             SAVED STACK POINTER IN CASE OF DISASTERCURPOS  RMB     4                      CURRENT FILE POSITIONENTRYPTR RMB    2                      POINTER TO ENTRY: BLOCKCHANNEL RMB     1ARGLIST RMB     2BINARYADDRESS   RMB     2BYTEADDRESS     RMB     2BYTECOUNT       RMB     2CHANNELTABLE    EQU     *        RPT     10        FDB     ((*-CHANNELTABLE)/2)*ENTRY:SIZE+ENTRIESENTRIES RMB     10*ENTRY:SIZEPOSITIONBLOCK   FCB     SYSCALL:CONTROL        FCB     8        FCB     CHANGED        FCB     CC:POSITION        FDB     CHANGED,4WRITEBLOCK      FCB     SYSCALL:WRITEB        FCB     WRITEB:SCLEN        FCB     CHANGED,IGNORED        CHANNEL #, IGNORED        FDB     CHANGED,CHANGED        WRBUF,WRLENREADBLOCK       FCB     SYSCALL:READB        FCB     READB:SCLEN        FCB     CHANGED,IGNORED        CHANNEL #, IGNORED        FDB     IGNORED,IGNORED        WRBUF,WRLEN        FDB     CHANGED                RPLEN        FDB     CHANGED,CHANGED        RDBUF,RDLEN        END     .PROGSTART      ;AT LAST!