; WARLIB.ASM Library routines by Warren A. Ring OpenDOSLibrary ;This routine opens the DOS liibrary MOVEM.L D0/A1/A5-A6,-(A7) ;(Push registers) MOVE.L A0,ScanPointer ;Set the ScanPointer and ScanCounter to scan MOVE.L D0,ScanCounter ; the CLI line MOVE.L _AbsExecBase,A6 ;Open the dos library LEA.L DosName,A1 MOVEQ #0,D0 ;(Specify "any version") JSR _LVOOpenLibrary(A6) MOVE.L D0,DosLibraryHandle MOVE.L DosLibraryHandle,A5 ;Save the console JSR _LVOInput(A5) ; input handle MOVE.L D0,ConIn ; locally MOVE.L DosLibraryHandle,A5 ;Save the console JSR _LVOOutput(A5) ; output handle MOVE.L D0,ConOut ; locally MOVEM.L (A7)+,D0/A1/A5-A6 ;(Pop registers) RTS ;Return DosName DC.B 'dos.library',0 CNOP 0,2 CloseDOSLibrary ;This routine closes the DOS library MOVEM.L A1/A6,-(A7) ;(Push registers) MOVE.L _AbsExecBase,A6 ;Close the dos MOVE.L DosLibraryHandle,A1 ; library JSR _LVOCloseLibrary(A6) MOVEM.L (A7)+,A1/A6 ;(Pop registers) RTS ;Return OpenFile ;This routine opens an already-existing file ;In: A0 => a string buffer containing the filename ;Out: A1 => the file handle (0 = file doesn't exist) ; Zero Flag = Clear if the file exists, ; Set if the file doesn't exist MOVEM.L D0-D3/A0/A6,-(A7) ;(Push registers) ;First, we must convert the filename from string buffer form to "C" form ADDQ.L #4,A0 ;(Make A0 point to the current useage of ; the filename string buffer) MOVE.L (A0)+,D1 ;Set the byte counter (D1) to the current ; useage of the string buffer ;(Make A0 point to the first data byte of ; the filename) MOVE.L D1,D2 ;Create a temporary buffer on the stack ADDQ.L #3,D2 ; of the length of the filename, +1, rounded ANDI.L #$FFFE,D2 ; up to the next word boundary SUB.L D2,A7 ;(D2 = the size of the temporary buffer on ; the stack) MOVE.L A7,A2 ;(Make A2 point to the temporary buffer) MOVE.L A7,A3 ;(Make A3 point to the temporary buffer) SUBQ.L #1,D1 OpenFile2 MOVE.B (A0)+,(A2)+ ;Copy the filename from the filename string DBRA D1,OpenFile2 MOVE.B #0,(A2) MOVE.L A3,D1 ;Open the file MOVEM.L A1/D2,-(A7) MOVE.L #MODE_OLDFILE,D2 MOVE.L DosLibraryHandle,A6 JSR _LVOOpen(A6) MOVEM.L (A7)+,A1/D2 ADD.L D2,A7 ;Delete the temporary buffer MOVE.L D0,(A1) ;(Set the caller's file handle value) MOVEM.L (A7)+,D0-D3/A0/A6 ;(Pop registers) RTS ;Return CreateFile ;This routine creates a new file ;In: A0 => a string buffer containing the filename ;Out: A1 => the file handle (0 = file could not be created) ; Zero Flag = Clear if the file was created, ; Set if the file wasn't created ;Notes: This routine deletes any already-existing file of the same name ; ; A create operation may fail because an already-existing file under ; the same name has its protection attribute set, or there is ; insufficient disk space to create the new file. MOVEM.L D0-D3/A0/A6,-(A7) ;(Push registers) ;First, we must convert the filename from string buffer form to "C" form ADDQ.L #4,A0 ;(Make A0 point to the current useage of ; the filename string buffer) MOVE.L (A0)+,D1 ;Set the byte counter (D1) to the current ; useage of the string buffer ;(Make A0 point to the first data byte of ; the filename) MOVE.L D1,D2 ;Create a temporary buffer on the stack ADDQ.L #3,D2 ; of the length of the filename, +1, rounded ANDI.L #$FFFE,D2 ; up to the next word boundary SUB.L D2,A7 ;(D2 = the size of the temporary buffer on ; the stack) MOVE.L A7,A2 ;(Make A2 point to the temporary buffer) MOVE.L A7,A3 ;(Make A3 point to the temporary buffer) SUBQ.L #1,D1 CreateFile2 MOVE.B (A0)+,(A2)+ ;Copy the filename from the filename string DBRA D1,CreateFile2 MOVE.B #0,(A2) MOVE.L A3,D1 ;Create the file MOVEM.L A1/D2,-(A7) MOVE.L #MODE_NEWFILE,D2 MOVE.L DosLibraryHandle,A6 JSR _LVOOpen(A6) MOVEM.L (A7)+,A1/D2 ADD.L D2,A7 ;Delete the temporary buffer MOVE.L D0,(A1) ;(Set the caller's file handle value) MOVEM.L (A7)+,D0-D3/A0/A6 ;(Pop registers) RTS ;Return DeleteFile ;This routine deletes a file ;In: A0 => a string buffer containing the filename ;Out: D0 = the status (0 = file could not be deleted) ;Note: A delete operation may fail because the existing file has its ; protection attribute set. MOVEM.L D0-D3/A0/A2/A3/A6,-(A7) ;(Push registers) ;First, we must convert the filename from string buffer form to "C" form ADDQ.L #4,A0 ;(Make A0 point to the current useage of ; the filename string buffer) MOVE.L (A0)+,D1 ;Set the byte counter (D1) to the current ; useage of the string buffer ;(Make A0 point to the first data byte of ; the filename) MOVE.L D1,D2 ;Create a temporary buffer on the stack ADDQ.L #3,D2 ; of the length of the filename, +1, rounded ANDI.L #$FFFE,D2 ; up to the next word boundary SUB.L D2,A7 ;(D2 = the size of the temporary buffer on ; the stack) MOVE.L A7,A2 ;(Make A2 point to the temporary buffer) MOVE.L A7,A3 ;(Make A3 point to the temporary buffer) SUBQ.L #1,D1 DeleteFile2 MOVE.B (A0)+,(A2)+ ;Copy the filename from the filename string DBRA D1,DeleteFile2 MOVE.B #0,(A2) MOVE.L A3,D1 ;Delete the file MOVEM.L A1,-(A7) MOVE.L DosLibraryHandle,A6 JSR _LVODeleteFile(A6) MOVEM.L (A7)+,A1 ADD.L D2,A7 ;Delete the temporary buffer TST.L D0 ;(Set/clear the Zero Flag) MOVEM.L (A7)+,D0-D3/A0/A2/A3/A6 ;(Pop registers) RTS ;Return ReadFile ;This routine reads a record from a file ;In: A0 => the file handle ; A1 => a string buffer to receive the data from the file ;Out: D0 = the number of characters read from the file ; ;Note: This routine overwrites any data already in the string buffer MOVEM.L D1-D3/A0-A1/A5,-(A7) ;(Push registers) MOVE.L A0,D1 ;(File specifier) MOVE.L A1,D2 ;(Buffer location) ADDQ.L #8,D2 MOVE.L (A1),D3 ;(# of bytes to get) MOVEM.L A1,-(A7) MOVE.L DosLibraryHandle,A5 JSR _LVORead(A5) MOVEM.L (A7)+,A1 ADDQ.L #4,A1 ;Set the current useage to the number of MOVE.L D0,(A1) ; bytes read MOVEM.L (A7)+,D1-D3/A0-A1/A5 ;(Pop registers) RTS ;Return WriteFile ;This routine writes a record to a file ;In: A0 => the file handle ; A1 => a string buffer containing the data for the file ;Out: D0 = the number of characters written to the file ; (-1 = write error, possibly disk full) MOVEM.L D1-D3/A0-A1/A5,-(A7) ;(Push registers) MOVE.L A0,D1 ;(File specifier) MOVE.L A1,D2 ;(Buffer location) ADDQ.L #8,D2 ADDQ.L #4,A1 MOVE.L (A1),D3 ;(# of bytes to write) MOVE.L DosLibraryHandle,A5 JSR _LVOWrite(A5) MOVEM.L (A7)+,D1-D3/A0-A1/A5 ;(Pop registers) RTS ;Return SeekFile ;This routine moves the position in a file at which the next read or write ; is to take place. ;In: A0 => the file handle ; D0 = the offset ; D1 = the mode: ; -1 = the offset is from the beginning of the file ; 0 = the offset is from the current position in the file ; 1 = the offset is from the end of file ;Out: D0 = the previous position ; (-1 = seek error) ; ;Notes: When a file is opened, the position at which the next read or write ; is to take place is the beginning of file. This position advances ; to the byte just beyond the end of each record as that record is ; read, so that if you read a file sequentially, you need never use the ; Seek system call. ; ; If you wish to append data to the end of a file, you seek with an ; offset of zero, and a mode of 1. MOVEM.L D1-D3/A0-A1/A5,-(A7) ;(Push registers) MOVE.L D1,D3 ;(mode) MOVE.L D0,D2 ;(offset) MOVE.L A0,D1 ;(file handle) MOVE.L DosLibraryHandle,A5 JSR _LVOSeek(A5) MOVEM.L (A7)+,D1-D3/A0-A1/A5 ;(Pop registers) RTS ;Return CloseFile ;This routine closes a previously-opened file. ;In: A0 => the file handle MOVEM.L D1/A0/A5,-(A7) ;(Push registers) MOVE.L A0,D1 MOVE.L DosLibraryHandle,A5 JSR _LVOClose(A5) MOVEM.L (A7)+,D1/A0/A5 ;(Pop registers) RTS ;Return RenameFile ;This routine renames a file ;In: A0 => a string buffer containing the current filename ; A1 => a string buffer containing the new filename ;Out: D0 = the status (0 = file could not be renamed) ;Notes: Directory names may be included in the filenames. Thus, this ; function can serve as a move function within a volume. ; ; A delete operation may fail because the destination file already ; exists, or because a named directory doesn't exist. MOVEM.L D1-D3/D7/A0-A4/A6,-(A7);(Push registers) MOVE.L A7,D7 ;(Save the stack pointer in D7) ;First, we must convert the source filename from SB form to "C" form ADDQ.L #4,A0 ;(Make A0 point to the current useage of ; the filename string buffer) MOVE.L (A0)+,D1 ;Set the byte counter (D1) to the current ; useage of the string buffer ;(Make A0 point to the first data byte of ; the filename) MOVE.L D1,D2 ;Create a temporary buffer on the stack ADDQ.L #3,D2 ; of the length of the filename, +1, rounded ANDI.L #$FFFE,D2 ; up to the next word boundary SUB.L D2,A7 ;(D2 = the size of the temporary buffer on ; the stack) MOVE.L A7,A2 ;(Make A2 point to the temporary buffer) MOVE.L A7,A3 ;(Make A3 point to the temporary buffer) SUBQ.L #1,D1 RenameFile1 MOVE.B (A0)+,(A2)+ ;Copy the filename from the filename string DBRA D1,RenameFile1 MOVE.B #0,(A2) ;Next, we must convert the destination filename from SB form to "C" form ADDQ.L #4,A1 ;(Make A1 point to the current useage of ; the filename string buffer) MOVE.L (A1)+,D1 ;Set the byte counter (D1) to the current ; useage of the string buffer ;(Make A1 point to the first data byte of ; the filename) MOVE.L D1,D2 ;Create a temporary buffer on the stack ADDQ.L #3,D2 ; of the length of the filename, +1, rounded ANDI.L #$FFFE,D2 ; up to the next word boundary SUB.L D2,A7 ;(D2 = the size of the temporary buffer on ; the stack) MOVE.L A7,A2 ;(Make A2 point to the temporary buffer) MOVE.L A7,A4 ;(Make A4 point to the temporary buffer) SUBQ.L #1,D1 RenameFile2 MOVE.B (A1)+,(A2)+ ;Copy the filename from the filename string DBRA D1,RenameFile2 MOVE.B #0,(A2) ;Now we rename the file MOVE.L A3,D1 ;Rename the file MOVE.L A4,D2 MOVE.L DosLibraryHandle,A6 JSR _LVORename(A6) MOVE.L D7,A7 ;(Restore the stack pointer) TST.L D0 ;(Set/clear the Zero Flag) MOVEM.L (A7)+,D1-D3/D7/A0-A4/A6;(Pop registers) RTS ;Return DisplayCrlf WritCon #DisplayCrlf_7 RTS DisplayCrlf_7 DC.L 1,1 DC.B 10 CNOP 0,2 DisplaySpace WritCon #DisplaySpace_7 RTS DisplaySpace_7 DC.L 1,1 DC.B ' ' CNOP 0,2 Left_ ;BASIC Fn: B$ = Left$(A$, I) ; D0 ;In: A0 => source buffer ; A1 => dest buffer ; D0 = Number of bytes to copy MOVEM.L D0-D2/A0-A1,-(A7) ;(Push registers) MOVE.L (A1),D2 ;(Set D2 to the max length of B$) ADDQ.L #4,A1 ;(Make A1 point to the current useage of B$) MOVE.L #0,(A1) ;Set the current useage of B$ to zero ADDQ.L #4,A0 ;(Make A0 point to the current useage of A$) MOVE.L D0,D1 ;Set the byte counter (D1) to the minimum of: (1) I, CMP.L (A0),D1 ; (2) the current useage of A$, (3) and the maximum BLE Left_1 ; length of B$ MOVE.L (A0),D1 Left_1 CMP.L D2,D1 BLE Left_2 MOVE.L D2,D1 Left_2 TST.L D1 ;If the byte counter is 0 or negative, BLE Left_9 ; then jump to Left_9 MOVE.L D1,(A1) ;Set the current useage of B$ to the byte counter ADDQ.L #4,A0 ;(Make A0 point to the first data byte of A$) ADDQ.L #4,A1 ;(Make A1 point to the first data byte of B$) SUBI.L #1,D1 ;Copy the data bytes from A$ to B$ Left_3 MOVE.B (A0)+,(A1)+ DBRA D1,Left_3 Left_9 MOVEM.L (A7)+,D0-D2/A0-A1 ;(Pop registers) RTS ;Return Mid_ ;BASIC Fn: B$ = Mid$(A$, I, J) ; D0 D1 ;In: A0 => source buffer ; A1 => dest buffer ; D0 = The position in A$ to start copying ; D1 = Number of bytes to copy MOVEM.L D0-D3/A0-A1,-(A7) ;(Push registers) MOVE.L (A1),D2 ;(Set D2 to the max length of B$) ADDQ.L #4,A1 ;(Make A1 point to the current useage of B$) MOVE.L #0,(A1) ;Set the current useage of B$ to zero TST.L D0 ;If I is 0 or negative, then jump to Mid_9 BLE Mid_9 ADDQ.L #4,A0 ;(Make A0 point to the current useage of A$) MOVE.L (A0),D3 ;Set the byte counter (D3) to the minimum of: (1) J, SUB.L D0,D3 ; (2) the current useage of A$ - I + 1, and (3) the ADDQ.L #1,D3 ; maximum length of B$ CMP.L D1,D3 BLE Mid_1 MOVE.L D1,D3 Mid_1 CMP.L D2,D3 BLE Mid_2 MOVE.L D2,D3 Mid_2 TST.L D3 ;If the byte counter is 0 or negative, BLE Mid_9 ; then jump to Mid_9 MOVE.L D3,(A1) ;Set the current useage of B$ to the byte counter ADDQ.L #4,A0 ;(Make A0 point to the first data byte of A$) ADDQ.L #4,A1 ;(Make A1 point to the first data byte of B$) ADDA.L D0,A0 ;(Make A0 point to byte I in A$) SUBQ.L #1,A0 SUBI.L #1,D3 ;Copy the data bytes from A$ to B$ Mid_3 MOVE.B (A0)+,(A1)+ DBRA D3,Mid_3 Mid_9 MOVEM.L (A7)+,D0-D3/A0-A1 ;(Pop registers) RTS ;Return Right_ ;BASIC Fn: B$ = Right$(A$, I) ; D0 ;In: A0 => source buffer ; A1 => dest buffer ; D0 = The number of bytes in A$, from the right end, ; to start copying MOVEM.L D0-D2/A0-A1,-(A7) ;(Push registers) MOVE.L (A1),D2 ;(Set D2 to the max length of B$) ADDQ.L #4,A1 ;(Make A1 point to the current useage of B$) MOVE.L #0,(A1) ;Set the current useage of B$ to zero ADDQ.L #4,A0 ;(Make A0 point to the current useage of A$) MOVE.L D0,D1 ;Set the byte counter (D1) to the minimum of: (1) I, CMP.L (A0),D1 ; (2) the current useage of A$, (3) the max length of B$ BLE Right_1 MOVE.L (A0),D1 Right_1 CMP.L D2,D1 BLE Right_2 MOVE.L D2,D1 Right_2 TST.L D1 ;If the byte counter is 0 or negative, BLE Right_9 ; then jump to Right_9 MOVE.L D1,(A1) ;Set the current useage of B$ to the byte counter) MOVE.L (A0),D2 ;(Set D2 to the current length of A$) ADDQ.L #4,A0 ;(Make A0 point to the first data byte of A$) ADDQ.L #4,A1 ;(Make A1 point to the first data byte of B$) SUB.L D1,D2 ;(Make A0 point to the last byte in A$, minus the ADDA.L D2,A0 ; byte counter) SUBQ.L #1,D1 ;Copy the data bytes from A$ to B$ Right_3 MOVE.B (A0)+,(A1)+ DBRA D1,Right_3 Right_9 MOVEM.L (A7)+,D0-D2/A0-A1 ;(Push registers) RTS ;Return StrCpy_ ;BASIC Fn: B$ = A$ ; ;In: A0 => source buffer (A$) ; A1 => dest buffer (B$) MOVEM.L D0,-(A7);(Push registers) MOVE.L (A0),D0 ;Set the number of bytes to copy to the max length of A$ JSR Left_ ;Copy the data bytes from A$ to B$ MOVE.L (A7)+,D0;(Pop registers) RTS ;Return StrCat_ ;BASIC Fn: B$ = B$ + A$ ;In: A0 => source buffer (A$) ; A1 => dest buffer (B$) MOVEM.L D0-D2/A0-A1,-(A7) ;(Push registers) MOVE.L (A1),D0 ;(Set D0 to the max length of B$) ADDQ.L #4,A1 ;(Make A1 point to the current useage of B$) ADDQ.L #4,A0 ;(Make A0 point to the current useage of A$) MOVE.L (A1),D2 ;(Set D2 to the current useage of B$) MOVE.L (A0),D1 ;Set the byte counter (D1) to the current useage of A$ ADD.L (A1),D1 ; plus the current useage of B$ CMP.L D0,D1 ;If the byte counter > the max length of B$, BLE StrCat_1; then set the byte counter to the max useage of B$ MOVE.L D0,D1 StrCat_1 MOVE.L D1,(A1) ;Set the current useage of B$ to the byte counter SUB.L D2,D1 ;Subtract the current useage of B$ from the byte counter TST.L D1 ;If the byte counter is now zero, BEQ StrCat_9; then jump to StrCat_9 ADDQ.L #4,A0 ;(Make A0 point to the first data byte of A$) ADDQ.L #4,A1 ;(Make A1 point to the byte after the last byte currently ADD.L D2,A1 ; used by B$) SUBQ.L #1,D1 ;Copy the bytes from A$ to B$ StrCat_2 MOVE.B (A0)+,(A1)+ DBRA D1,StrCat_2 StrCat_9 MOVEM.L (A7)+,D0-D2/A0-A1 ;(Pop registers) RTS ;Return StrCmp_ ;C fn: I = (A$==B$); ;This routine indicates whether or not A$ = B$ ;In: A0 => source buffer (A$) ; A1 => dest buffer (B$) ;Out: = Set if the strings are equal, ; = Clear if the strings are unequal MOVEM.L D0/A0-A1,-(A7) ;(Push registers) ADDQ.L #4,A0 ;(Make A0 point to the current useage of A$) ADDQ.L #4,A1 ;(Make A1 point to the current useage of B$) MOVE.L (A0),D0 ;Set the byte counter (D0) to the current useage of A$ CMPM.L (A0)+,(A1)+;If the current useage of A$ <> the current useage BNE StrCmp_9; of B$, then jump to StrCmp_9 SUBQ.L #1,D0 ;If the A$ data bytes <> the B$ data bytes, StrCmp_5 ; then jump to StrCmp_9 CMPM.B (A0)+,(A1)+ BNE StrCmp_9 DBRA D0,StrCmp_5 ORI #$4,CCR ;Set the zero flag StrCmp_9 MOVEM.L (A7)+,D0/A0-A1 ;(Pop registers) RTS ;Return StrLen_ ;BASIC Fn: I = LEN(A$) ;This routine indicates the current length of a string ;In: A0 => the buffer (A$) ;Out: D0 = the current useage of A$ MOVEM.L A0,-(A7) ;(Push registers) ADDQ.L #4,A0 ;(Make A0 point to the current useage of A$) MOVE.L (A0),D0 ;Set D0 to the current useage of A$ MOVEM.L (A7)+,A0 ;(Pop registers) RTS ;Return Scanw_ ;This routine scans a string for the next visible word ;In: ScanPointer => the next byte in the string to be scanned ; ScanCounter = the number of bytes in the string remaining ; to be scanned ; A0 => the dest buffer ;Out: ScanPointer, ScanCounter are updated ; ;Note: This routine skips over spaces, tabs, and other invisible characters MOVEM.L D0-D2/A0-A2,-(A7) ;(Push registers) MOVE.L (A0)+,D1;(Set D1 to the max length of A$) MOVE.L A0,A1 ;(Make A1 point to the current length of A$) MOVE.L #0,(A1) ;Set the current useage of A$ to 0 ADDQ.L #4,A0 ;Advance the dest buffer pointer (A0) to the first data ; byte of A$ MOVE.L ScanPointer,A2;(Set A1 to the scan pointer) MOVE.L ScanCounter,D2;If the scan counter (D2) is zero, BEQ Scanw_9 ; then jump to Scanw_9 Scanw_1 MOVE.B (A2)+,D0;Fetch the character at which the scan pointer points, ; and advance the scan pointer SUBQ.L #1,D2 ;Decrement the scan counter CMPI.B #'!',D0 ;If the character is visible, then jump to Scanw_2 BLT Scanw_3 CMPI.B #$7F,D0 BLT Scanw_2 Scanw_3 TST.L D2 ;If the scan counter is zero, then jump to Scanw_9 BEQ Scanw_9 BRA Scanw_1 ;Jump to Scanw_1 Scanw_2 MOVE.B D0,(A0)+;Place the character into A$, ; and advance the dest buffer pointer ADD.L #1,(A1) ;Increment the current useage of A$ CMP.L (A1),D1 ;If the current useage of A$ = the max length of A$, BEQ Scanw_9 ; then jump to Scanw_9 TST.L D2 ;If the scan counter is zero, then jump to Scanw_9 BEQ Scanw_9 MOVE.B (A2)+,D0;Fetch the character at which the scan pointer points, ; and advance the scan pointer SUBQ.L #1,D2 ;Decrement the scan counter CMPI.B #'!',D0 ; If the character is visible, then jump to Scanw_2 BCC Scanw_2 Scanw_9 MOVE.L A2,ScanPointer;(Update the scan pointer) MOVE.L D2,ScanCounter;(Update the scan counter) MOVEM.L (A7)+,D0-D2/A0-A2 ;(Pop registers) RTS ;Return Scana_ ;This routine scans a string for the next alphanumeric word ;In: ScanPointer => the next byte in the string to be scanned ; ScanCounter = the number of bytes in the string remaining ; to be scanned ; A0 => the dest buffer ;Out: ScanPointer, ScanCounter are updated ; ;Note: This routine skips over spaces, tabs, and invisible characters ; including non-alphanumeric characters MOVEM.L D0-D2/A0-A2,-(A7) ;(Push registers) MOVE.L (A0)+,D1;(Set D1 to the max length of A$) MOVE.L A0,A1 ;(Make A1 point to the current length of A$) MOVE.L #0,(A1) ;Set the current useage of A$ to 0 ADDQ.L #4,A0 ;Advance the dest buffer pointer (A0) to the first data ; byte of A$ MOVE.L ScanPointer,A2;(Set A1 to the scan pointer) MOVE.L ScanCounter,D2;If the scan counter (D2) is zero, BEQ Scana_9 ; then jump to Scana_9 Scana_1 MOVE.B (A2)+,D0;Fetch the character at which the scan pointer points, ; and advance the scan pointer SUBQ.L #1,D2 ;Decrement the scan counter CMPI.B #$30,D0 ;If the character is alphanumeric, then jump to Scana_2 BLT Scana_3 CMPI.B #$3A,D0 BLT Scana_2 CMPI.B #$41,D0 BLT Scana_3 CMPI.B #$5B,D0 BLT Scana_2 CMPI.B #$61,D0 BLT Scana_3 CMPI.B #$7B,D0 BLT Scana_2 Scana_3 TST.L D2 ;If the scan counter is zero, then jump to Scana_9 BEQ Scana_9 BRA Scana_1 ;Jump to Scana_1 Scana_2 MOVE.B D0,(A0)+;Place the character into A$, ; and advance the dest buffer pointer ADD.L #1,(A1) ;Increment the current useage of A$ CMP.L (A1),D1 ;If the current useage of A$ = the max length of A$, BEQ Scana_9 ; then jump to Scana_9 TST.L D2 ;If the scan counter is zero, then jump to Scana_9 BEQ Scana_9 MOVE.B (A2)+,D0;Fetch the character at which the scan pointer points, ; and advance the scan pointer SUBQ.L #1,D2 ;Decrement the scan counter CMPI.B #$30,D0 ; If the character is alphanumeric, then jump to Scana_2 BLT Scana_4 CMPI.B #$3A,D0 BLT Scana_2 CMPI.B #$41,D0 BLT Scana_4 CMPI.B #$5B,D0 BLT Scana_2 CMPI.B #$61,D0 BLT Scana_4 CMPI.B #$7B,D0 BLT Scana_2 Scana_4 Scana_9 MOVE.L A2,ScanPointer;(Update the scan pointer) MOVE.L D2,ScanCounter;(Update the scan counter) MOVEM.L (A7)+,D0-D2/A0-A2 ;(Pop registers) RTS ;Return Scanc_ ;This routine scans a string for the next character ;In: ScanPointer => the next byte in the string to be scanned ; ScanCounter = the number of bytes in the string remaining ; to be scanned ; A0 => the dest buffer ;Out: ScanPointer, ScanCounter are updated ; MOVEM.L D0-D2/A0-A2,-(A7) ;(Push registers) MOVEQ.L #0,D0 ;Set the byte counter to 0 ADDQ.L #4,A0 ;(Make A0 point to the current useage of A$) MOVEA.L ScanPointer,A1;(Set A1 to the scan pointer) MOVE.L ScanCounter,D1;(Set D1 to the scan counter) BEQ Scanc_9 ;If the scan counter is 0, then jump to Scanc_9 MOVE.B (A1)+,D2;Fetch the character at which the scan pointer points, ; and advance the scan pointer SUBQ.L #1,D1 ;Decrement the scan counter ADDQ.L #4,A0 ;(Make A0 point to the first data byte in A$) MOVE.B D2,(A0) ;Place the character in the buffer SUBQ.L #4,A0 ;(Make A0 point to the current useage of A$) MOVEQ.L #1,D0 ;Set the byte counter to 1 Scanc_9 MOVE.L D0,(A0) ;Set the current useage in A$ to the byte counter MOVE.L A1,ScanPointer;(Update the scan pointer) MOVE.L D1,ScanCounter;(Update the scan counter) MOVEM.L (A7)+,D0-D2/A0-A2 ;(Pop registers) RTS ;Return ItoA_ ;BASIC Fn: A$ = STR$(I) ; (A0) (D0) ;This routine converts a signed integer from binary to a decimal ASCII ; string MOVEM.L D0-D4/A0-A4,-(A7) ;(Push registers) MOVE.L #ItoA_values,A1;Set the table pointer (A1) to the beginning of ; the table MOVEQ.L #10,D1 ;Set the table counter (D1) to the length of the table MOVEQ.L #0,D4 ;Set the character counter (D4) to 0 MOVE.L (A0)+,D2;Set the limit value (D2) to the max length of A$ MOVE.L A0,A2 ;(Make A2 point to the current useage of A$) ADDQ.L #4,A0 ;(Make A0 and A4 point to the first data byte in A$) MOVE.L A0,A4 TST.L D0 ;If I >= 0, then jump to ItoA_1 BPL ItoA_1 MOVE.B #'-',(A0)+;Place a '-' in A$, and advance the A$ pointer ADDQ.L #1,D4 ;Increment the character counter CMP.L D2,D4 ;If the character counter equals the limit value, BEQ ItoA_5 ; then jump to ItoA_5 NEG.L D0 ;Complement I ItoA_1 CMP.L (A1),D0 ;If I >= the table value, BCC ItoA_2 ; then jump to ItoA_2 ADDQ.L #4,A1 ;Advance the table pointer SUBQ.L #1,D1 ;Decrement the table counter CMPI.L #1,D1 ;If the table counter is not yet 1, BNE ItoA_1 ; then jump to ItoA_1 ItoA_2 MOVE.B #'0',(A0);Set the character to '0' ADDQ.L #1,D4 ;Increment the character counter ItoA_3 SUB.L (A1),D0 ;Subtract the table value from I BCS ItoA_4 ;If I is negative, then jump to ItoA_4 ADDQ.B #1,(A0) ;Increment the data byte in A$ BRA ItoA_3 ;Jump to ItoA_3 ItoA_4 ADD.L (A1),D0 ;Add the table value to I, making I positive again ADDQ.L #4,A1 ;Advance the table pointer to the next value SUBQ.L #1,D1 ;Decrement the table counter BEQ ItoA_7 ;If the table counter is zero, then jump to ItoA_7 ADDQ.L #1,A0 ;Advance the A$ pointer CMP.L D4,D2 ;If the character counter <= the limit value, BGT ItoA_2 ; then jump to ItoA_2 ItoA_5 MOVE.L D2,(A2) ;Set the current useage of A$ to the max length of A$ SUBQ.L #1,D4 ;Fill the buffer with astericks ItoA_6 MOVE.B #'*',(A4)+ DBRA D4,ItoA_6 BRA ItoA_8 ;Jump to Itoa_8 ItoA_7 MOVE.L D4,(A2) ;Set the current useage of A$ to the character count ItoA_8 MOVEM.L (A7)+,D0-D4/A0-A4 ;(Pop registers) RTS ;Return ItoA_values DC.L 1000000000 DC.L 100000000 DC.L 10000000 DC.L 1000000 DC.L 100000 DC.L 10000 DC.L 1000 DC.L 100 DC.L 10 DC.L 1 AtoI_ ;BASIC Fn: I = VAL(A$) ; (D0) (A0) ;This routine converts a decimal ASCII string to a signed binary integer MOVEM.L D1-D4/A0-A1,-(A7) ;(Push registers) MOVEQ.L #0,D0 ;Set the character field to zero MOVEQ.L #0,D2 ;Set the result (D2) to 0 MOVEQ.L #0,D3 ;Clear the negative flag (D3) ADDQ.L #4,A0 ;(Make A1 point to the current useage of A$) MOVE.L A0,A1 MOVE.L (A0)+,D1;Set the byte counter (D1) to the current useage of A$ ;(Make A0 point to the first data byte in A$) BEQ AtoI_9 ;If the byte counter is zero, then jump to AtoI_9 MOVE.B (A0)+,D0;Fetch the first data byte in A$ ;(Make A0 point to the second data byte in A$) CMPI.B #'-',D0 ;If the byte is not a '-', then jump to AtoI_1 BNE AtoI_1 MOVEQ.L #1,D3 ;Set the negative flag BRA AtoI_4 ;Jump to AtoI_4 AtoI_1 CMPI.B #'0',D0 ;If the byte is not numeric, then jump to AtoI_9 BLT AtoI_9 CMPI.B #'9',D0 BGT AtoI_9 LSL.L #1,D2 ;Multiply the result by 10 MOVE.L D2,D4 LSL.L #2,D2 ADD.L D4,D2 SUBI.B #'0',D0 ;Convert the byte to binary ADD.L D0,D2 ;Add the byte to the result AtoI_4 SUBQ.L #1,D1 ;Decrement the byte counter BEQ AtoI_9 ;If the byte counter is zero, then jump to AtoI_9 MOVE.B (A0)+,D0;Fetch the next data byte in A$ ;(Make A0 point to the next data byte in A$) BRA AtoI_1 ;Jump to AtoI_1 AtoI_9 TST.L D3 ;If the negative flag is clear, then jump to AtoI_A BEQ AtoI_A NEG.L D2 ;Negate the result AtoI_A MOVE.L D2,D0 ;Set D0 to the result MOVEM.L (A7)+,D1-D4/A0-A1 ;(Pop registers) RTS ;Return HAtoI_ ;BASIC Fn: I = HEX(A$) ; (D0) (A0) ;This routine converts a hex-ASCII string to a binary integer ; ;Note: Conversion stops if a non-hex-ASCII character is encountered in ; the string MOVEM.L D1-D2,-(A7) ;(Push registers) MOVEQ.L #0,D2 ;Set the result (D2) to 0 ADDQ.L #4,A0 ;Set the limit value (D1) to the current length of A$ MOVE.L (A0)+,D1;(Make A0 point to the current useage of A$) HAtoI_1 MOVE.B (A0)+,D0;If the first (next) character in A$ is not a hex-ASCII JSR IsHexASCII; character, then jump to HAtoI_7 BEQ HAtoI_7 CMPI.B #'9'+1,D0;Convert the hex-ASCII character to a binary value BCS HAtoI_2 ANDI.B #$0F,D0 ADD.L #9,D0 BRA HAtoI_3 HAtoI_2 SUB.L #'0',D0 HAtoI_3 LSL.L #4,D2 ;Shift the result left 4 bits OR.L D0,D2 ;'Or' the binary value into the result SUBQ.L #1,D1 ;Decrement the limit value BNE HAtoI_1 ;If the limit value is not yet zero, ; then jump to HAtoI_1 HAtoI_7 MOVE.L D2,D0 ;(Set D0 to the result) MOVEM.L (A7)+,D1-D2 ;(Pop registers) RTS ;Return ItoHA8_ ;BASIC Fn: A$ = STR8HEX$(I) ; (A0) (D0) MOVEM.L D1,-(A7);(Push registers) MOVEQ.L #8,D1 ;Set the field width to 8 JSR ItoHA_ ;Convert the field MOVEM.L (A7)+,D1;(Pop registers) RTS ;Return ItoHA4_ ;BASIC Fn: A$ = STR4HEX$(I) ; (A0) (D0) MOVEM.L D1,-(A7);(Push registers) MOVEQ.L #4,D1 ;Set the field width to 4 JSR ItoHA_ ;Convert the field MOVEM.L (A7)+,D1;(Pop registers) RTS ;Return ItoHA2_ ;BASIC Fn: A$ = STR2HEX$(I) ; (A0) (D0) MOVEM.L D1,-(A7);(Push registers) MOVEQ.L #2,D1 ;Set the field width to 2 JSR ItoHA_ ;Convert the field MOVEM.L (A7)+,D1;(Pop registers) RTS ;Return ItoHA1_ ;BASIC Fn: A$ = STR1HEX$(I) ; (A0) (D0) MOVEM.L D1,-(A7);(Push registers) MOVEQ.L #1,D1 ;Set the field width to 1 JSR ItoHA_ ;Convert the field MOVEM.L (A7)+,D1;(Pop registers) RTS ;Return ItoHA_ ;BASIC Fn: A$ = STRHEX$(I) ; (A0) (D0) ;In: D1 = the number of hex-ASCII characters to convert MOVEM.L D0-D5,-(A7) ;(Push registers) MOVE.L D1,D2 ;(Set D2 to the field width -1) SUBQ.L #1,D2 MOVE.L (A0)+,D3;If the max length of A$ < the field width, CMP.L D1,D3 ; (Make A0 point to the current useage of A$) BLT ItoHA_7 ; then jump to ItoHA_7 ; (Set D3 to the max length of A$) MOVE.L D1,(A0)+;Set the current useage of A$ to the field width ;(Make A0 point to the first data byte of A$) CMPI.L #1,D1 ;If the field width is 1, BEQ ItoHA_2 ; then jump to ItoHA_2 MOVE.L D2,D4 ;Rotate I right by the field width -1 times 4 bits SUBQ.L #1,D4 ItoHA_1 ROR.L #4,D0 DBRA D4,ItoHA_1 ItoHA_2 MOVE.L D2,D4 ;Set the counter to the field width -1 ItoHA_3 MOVE.B D0,D5 ;Convert I bits 3-0 to a hex-ASCII character AND.L #$0F,D5 ADD.L #'0',D5 CMP.L #'9'+1,D5 BLT ItoHA_4 ADDQ.L #7,D5 ItoHA_4 MOVE.B D5,(A0)+;Place the character in A$ ;(Make A0 point to the next data byte in A$) ROL.L #4,D0 ;Rotate I left by 4 bits DBRA D4,ItoHA_3;Decrement the counter ;If the counter is not yet -1, then jump to ItoHA_2 BRA ItoHA_9 ;Jump to ItoHA_9 ItoHA_7 MOVE.L D3,(A0)+;Set the current useage of A$ to the max length of A$ SUBQ.L #1,D3 ;Fill A$ with astericks ItoHA_8 MOVE.B #'*',(A0)+ DBRA D3,ItoHA_8 ItoHA_9 MOVEM.L (A7)+,D0-D5 ;(Pop registers) RTS ;Return IsHexASCII ;Is hex-ASCII routine ;This routine determines whether or not a character ; is a valid hex-ASCII character ;In: = the character ;Out: = Clear if the character is a hex-ASCII ; character, ; = Set if the character is not a hex- ; ASCII character MOVE.L D0,-(A7) ;Push registers ANDI.L #$FF,D0 ;Strip off all but bits 7-0 CMPI.B #'0',D0 ;If the character is not a hex-ASCII character, BMI IsHex8 ; then jump to IsHex8 CMPI.B #'9'+1,D0 ;If in the range "0" - "9", then jump to IsHex4 BMI IsHex4 CMPI.B #'A',D0 BMI IsHex8 CMPI.B #'F'+1,D0 ;If in the range "A" - "F", then jump to IF#4 BMI IsHex4 CMPI.B #'a',D0 BMI IsHex8 CMPI.B #'f'+1,D0 ;If in the range "0" - "f", then jump to IsHex4 BMI IsHex4 BRA IsHex8 ;Jump to IsHex8 IsHex4 MOVE.L (A7)+,D0 ;Pop registers ANDI #$FB,CCR ;Clear the zero flag BRA IsHex9 IsHex8 MOVE.L (A7)+,D0 ;Pop registers ORI #$04,CCR ;Set the zero flag IsHex9 RTS ;Return IFND ScanPointer ScanPointer DS.L 1 ENDC IFND ScanCounter ScanCounter DS.L 1 ENDC IFND ConIn ConIn DS.L 1 ENDC IFND ConOut ConOut DS.L 1 ENDC IFND DosLibraryHandle DosLibraryHandle DS.L 1 ENDC IFND SystemSP SystemSP DS.L 1 ENDC IFND MODE_OLDFILE MODE_OLDFILE EQU 1005 ENDC IFND MODE_NEWFILE MODE_NEWFILE EQU 1006 ENDC