PAGE ,132
TITLE Cluster Owner Program, Version 1.61, 21-Apr-1987

;
; Written By Steven Georgiades
;
;
;       If you have any questions or comments about this or any other
;       SMG program, call or write:
;
;               Steven M. Georgiades
;               SMG Software
;               701-H South Hayward Street
;               Anaheim, CA 92804
;

CODE      SEGMENT BYTE PUBLIC 'CODE'

          ASSUME  CS:CODE,DS:CODE,ES:CODE,SS:CODE

          ORG     5CH

FCB       LABEL   BYTE

          ORG     80H

PARAM     LABEL   BYTE

          ORG     100H

OWNER:    JMP     BEGIN

DIGIT     DB      "0123456789ABCDEF"
PARM_ERR  DB      "Illegal Parameter!",7
CRLF      DB      13,10,"$"
READERR   DB      "Error Reading Drive X:",7,13,10,"$"
SIGNON    DB      "Cluster Owner Program, Version 1.61",13,10
          DB      "SMG Software",13,10
          DB      "(C) Copyright 1986,1987 Steven Georgiades",13,10,10,"$"
USAGE     DB      "Usage:",13,10,10
          DB      "  OWNER [d:] n [[d:] n [...]]",13,10,10
          DB      "    d: = Optional Drive Letter",13,10
          DB      "    n  = Cluster Number to Check",13,10,10,"$"
CLUSTMSG  DB      "Cluster XXXXX $"
OWNERMSG  DB      "is Owned by $"
BADMSG    DB      "is Marked as Bad",13,10,"$"
FREEMSG   DB      "is not is Use by any File",13,10,"$"
INVALID   DB      "does not Exist!",7,13,10,"$"
LOSTMSG   DB      "Appears to be Lost!",7,13,10,"$"
RESVMSG   DB      "is Reserved",13,10,"$"

CLSTSEC   DW      ?
CLSTTOT   DW      ?
CLUST     DW      ?
DIR_LEN   DW      ?
DIRBUF    DW      ?
DIRSEC    DW      ?
DRIVE     DB      ?
EOF       DW      0FF8H
FATSEC    DW      ?
FATSIZE   DB      3
LASTDRV   DB      -1
RDIR_LEN  DW      ?
SECSIZE   DW      ?
STARTSEC  DW      ?

DIRNAME   DB      14 DUP(?)
FILESPEC  DB      "X:\"
PATH      DB      "$",79 DUP(?)
FILENAME  DB      14 DUP(?)

BEGIN:    MOV     AH,9                          ; Output Sign-On Message
          MOV     DX,OFFSET SIGNON
          INT     21H
          MOV     AH,19H                        ; Get Default Drive Number
          INT     21H
          MOV     DRIVE,AL                      ;   and Save
          MOV     SI,OFFSET PARAM               ; Set up Pointer to Parameter
          LODSB                                 ; Read Parameter Length
          CMP     AL,2
          JNB     GET_PARM
          MOV     DX,OFFSET USAGE
          JMP     SHORT GET_OW03
GET_PARM: CBW
          MOV     BX,AX
          MOV     BYTE PTR [SI][BX],0           ; Terminate Parameter String
STRIP:    LODSB                                 ; Strip Off Leading Whitespace
          CMP     AL,' '
          JE      STRIP
          CMP     AL,9
          JE      STRIP
          OR      AL,AL                         ; If End-of-Parameter,
          JZ      EXIT                          ;   Continue Proccessing
          CMP     BYTE PTR [SI],':'             ; If Drive Letter,
          JNE     NOTDRIVE
          AND     AL,0DFH                       ;   Convert to Drive Number
          SUB     AL,'A'
          MOV     DRIVE,AL                      ;   and Save
          LODSB                                 ;   Skip Colon
          JMP     SHORT STRIP                   ;   Continue
NOTDRIVE: DEC     SI                            ; ReUse Last Character
          CALL    GET_WORD                      ; Read Cluster Number (Hex)
          JNE     PARM_OK                       ; If Error,
PARMERR:  MOV     DX,OFFSET PARM_ERR            ;   Output Parameter Error
          MOV     AH,9
          INT     21H
          MOV     AX,4C01H                      ;   Exit to DOS
          INT     21H
PARM_OK:  MOV     CLUST,DX                      ; Save Cluster Number
          CALL    GET_OWNR                      ; Find Cluster Owner
          JMP     SHORT STRIP                   ; Get Next Parameter
EXIT:     MOV     AX,4C00H                      ; Exit to DOS
          INT     21H

GET_OWNR: PUSH    AX                            ; Save Registers
          PUSH    BX
          PUSH    CX
          PUSH    DX
          PUSH    DI
          PUSH    SI
          MOV     PATH,'$'                      ; Initialize Path
          MOV     AL,DRIVE                      ; If drive has changed,
          CMP     AL,LASTDRV
          JNE     GET_OW01
          JMP     GET_OW07
GET_OW01: MOV     LASTDRV,AL                    ;   Last Drive = This Drive
          MOV     CX,1                          ;   Read Boot Record
          MOV     DX,0
          MOV     BX,OFFSET FATBUF
          INT     25H
          JNC     GET_OW04                      ;   If Error,
GET_OW02: POPF
          MOV     AL,DRIVE                      ;     Convert Drive Number
          ADD     AL,'A'
          MOV     READERR[20],AL
          MOV     DX,OFFSET READERR             ;     Point to Read Error
GET_OW03: MOV     AH,9                          ;     Output Error Message
          INT     21H
          MOV     AX,4C01H                      ;     Exit to DOS
          INT     21H
GET_OW04: POPF
          MOV     AX,FATBUF[11]                 ;   Read Sector Size
          MOV     SECSIZE,AX                    ;     and Save
          MOV     AL,BYTE PTR FATBUF[13]        ;   Read Sectors per Cluster
          XOR     AH,AH
          MOV     CLSTSEC,AX                    ;     and Save
          MOV     CX,FATBUF[14]                 ;   Read # of Reserved Sectors
          MOV     AL,BYTE PTR FATBUF[16]        ;   Read # of FAT's
          XOR     AH,AH                         ;   Convert to Word
          MOV     BX,FATBUF[22]                 ;   Read Sectors per FAT
          MOV     FATSEC,BX
          MUL     BX                            ;   Calculate Total FAT Sectors
          ADD     CX,AX                         ;   Add to Reserved Sectors
          MOV     AX,FATBUF[17]                 ;   Read Number of DIR Entries
          MOV     RDIR_LEN,AX
          PUSH    CX                            ;   Calculate DIR Sectors
          MOV     CL,5
          SHL     AX,CL
          POP     CX
          MOV     BX,SECSIZE
          XOR     DX,DX
          DIV     BX
          OR      DX,DX                         ;   Adjust for Partial Sector
          JZ      GET_OW05
          INC     AX
GET_OW05: MOV     DIRSEC,AX                     ;   Save DIR Sectors
          ADD     CX,AX                         ;   Add DIR Sectors to Reserved
          MOV     STARTSEC,CX                   ;   Save in STARTSEC
          MOV     AX,FATSEC                     ;   Determine FAT Buffer Size
          MOV     BX,SECSIZE
          MUL     BX
          ADD     AX,OFFSET FATBUF
          MOV     DIRBUF,AX                     ;   Save DIRBUF Pointer
          MOV     AX,FATBUF[19]                 ;   Read Total Sectors on Media
          SUB     AX,CX                         ;   Calc. Total Data Clusters
          MOV     BX,CLSTSEC
          XOR     DX,DX
          DIV     BX
          ADD     AX,2
          MOV     CLSTTOT,AX                    ;     and Save
          CMP     AX,4081                       ;   Adjust FAT Size
          JLE     GET_OW06
          MOV     FATSIZE,4
          MOV     EOF,0FFF8H
          JMP     SHORT GET_OW07
GET_OW06: MOV     FATSIZE,3
          MOV     EOF,0FF8H                      
GET_OW07: MOV     AL,DRIVE                      ; Read FAT
          MOV     CX,FATSEC
          MOV     DX,1
          MOV     BX,OFFSET FATBUF
          INT     25H
          JNC     GET_OW08
          JMP     GET_OW02                      ; If Error, Say So
GET_OW08: POPF
          MOV     BX,CLUST                      ; Get Cluster Number
          MOV     AX,BX                         ; Convert Cluster # to Decimal
          MOV     DI,OFFSET CLUSTMSG[13]
          CALL    DEC5OUT
          CALL    STRIP0                        ; Strip Off Leading Zeroes
          MOV     AH,9
          MOV     DX,OFFSET CLUSTMSG            ; Output Cluster Message
          INT     21H
          CMP     BX,CLSTTOT                    ; Test Cluster Number
          JNB     GET_OW09
          CMP     BX,2
          JNB     GET_OW10
GET_OW09: MOV     DX,OFFSET INVALID             ; If Invalid, Say So
          JMP     SHORT GET_OW17
GET_OW10: CALL    NEXTCLST                      ; Determine Next Cluster
          OR      BX,BX                         ; If Not in Use, Say So
          JNZ     GET_OW11
          MOV     DX,OFFSET FREEMSG
          JMP     SHORT GET_OW17
GET_OW11: MOV     AX,EOF                        ; If In Use, Continue
          CMP     BX,AX
          JAE     GET_OW13
          DEC     AX                            ; If Bad, Say So
          CMP     BX,AX
          JNE     GET_OW12
          MOV     DX,OFFSET BADMSG
          JMP     SHORT GET_OW17
GET_OW12: SUB     AX,7                          ; If Reserved, Say So
          CMP     BX,AX
          JB      GET_OW13
          MOV     DX,OFFSET RESVMSG
          JMP     SHORT GET_OW17
GET_OW13: MOV     AX,CLUST                      ; Get Cluster Number
GET_OW14: MOV     BX,AX                         ; Get Previous Cluster in Chain
          CALL    PREVCLST
          OR      AX,AX                         ; If Not First, Repeat
          JNZ     GET_OW14
          MOV     CLUST,BX                      ; Save First Cluster in Chain
GET_OW15: CALL    GETDIR                        ; Load the Current Directory
          CALL    SRCHCLST                      ; Search Directory for Cluster
          JNC     GET_OW16                      ; If Found, Exit Search Loop
          CALL    SRCHDIR                       ; Search Dir for Sub-Directory
          JNC     GET_OW15                      ; If Found, Continue Search Loop
          CALL    DIRNEXT                       ; Use Next Sub-Directory
          JNC     GET_OW15                      ; If Found, Continue Search Loop
          MOV     DX,OFFSET LOSTMSG             ; Else Couldn't find Cluster
          JMP     SHORT GET_OW17
GET_OW16: MOV     AL,DRIVE                      ; Convert Drive Number to Letter
          ADD     AL,'A'
          MOV     FILESPEC,AL
          MOV     AH,9                          ; Output Owner Message
          MOV     DX,OFFSET OWNERMSG
          INT     21H
          MOV     DX,OFFSET FILESPEC            ; Output FileSpec
          INT     21H
          MOV     DX,OFFSET FILENAME            ; Output FileName
          INT     21H
          MOV     DX,OFFSET CRLF
GET_OW17: MOV     AH,9
          INT     21H
          POP     SI                            ; Restore Registers
          POP     DI
          POP     DX
          POP     CX
          POP     BX
          POP     AX
          RET                                   ; Done

GETDIR:   PUSH    AX                            ; Save Registers
          PUSH    BX
          PUSH    CX
          PUSH    DX
          PUSH    DI
          PUSH    SI
          MOV     AL,DRIVE                      ; Read Root Directory
          MOV     CX,DIRSEC
          MOV     DX,STARTSEC
          SUB     DX,CX
          MOV     BX,DIRBUF
          INT     25H
          POPF
          MOV     AX,RDIR_LEN                   ; DIR Length = Root DIR Length
          MOV     DIR_LEN,AX
          MOV     SI,OFFSET PATH                ; Point to First Element of Path
GETDIR1:  MOV     DI,OFFSET DIRNAME             ; Point to FileName Buffer
GETDIR2:  LODSB                                 ; Copy Path Element to FileName
          CMP     AL,'\'                        ;   until '\' or '$'
          JE      GETDIR3
          CMP     AL,'$'
          JE      GETDIR4
          STOSB
          JMP     SHORT GETDIR2
GETDIR3:  MOV     AL,0                          ; Read Subdirectory
          STOSB
          CALL    READDIR
          JC      GETDIR5                       ; If Error, Say So
          JMP     SHORT GETDIR1                 ; Get Next Element
GETDIR4:  CLC                                   ; Clear Error Flag
GETDIR5:  POP     SI                            ; Restore Registers
          POP     DI
          POP     DX
          POP     CX
          POP     BX
          POP     AX
          RET                                   ; Done

READDIR:  PUSH    CX                            ; Save Registers
          PUSH    DI
          PUSH    SI
          CALL    SRCHFILE                      ; Search for DIR
          JC      READDIR2                      ; If Not Found, Error
          MOV     BX,[BX+26]                    ; Get Starting Cluster Number
          MOV     DIR_LEN,0                     ; DIR Length = 0
          OR      BX,BX                         ; If Start Cluster = 0, Error
          JZ      READDIR2
          MOV     AX,SECSIZE                    ; Calculate DIR Entries/Cluster
          MOV     CX,CLSTSEC
          MUL     CX
          MOV     CL,5
          SHR     AX,CL
          MOV     CX,AX
          MOV     DI,DIRBUF                     ; Point to DIR Buffer
READDIR1: CALL    READCLST                      ; Read Cluster
          ADD     DIR_LEN,CX                    ; Increment DIR Length
          CMP     BX,EOF                        ; If Not Last Cluster,
          JB      READDIR1                      ;   Get Next Cluster
          JMP     SHORT READDIR3                ; Done Reading DIR
READDIR2: STC                                   ; Set Error Flag
READDIR3: POP     SI                            ; Restore Registers
          POP     DI
          POP     CX
          RET                                   ; Done

DIRNEXT:  PUSH    AX                            ; Save Registers
          PUSH    BX
          PUSH    CX
          PUSH    DI
          PUSH    SI
DIRNEXT1: MOV     DI,OFFSET PATH                ; Scan to End of Path
          MOV     CX,80
          MOV     AL,'$'
          REPNE   SCASB
          JNE     DIRNEXT3                      ; If No End, Error
          CMP     CX,79                         ; If Null Path, Error
          JE      DIRNEXT3
          STD                                   ; Auto-Decrement
          MOV     AX,78                         ; Determine Path Length
          SUB     AX,CX
          MOV     CX,AX
          SUB     DI,2                          ; Point to End of DirName
          MOV     AL,0                          ; Set End of DirName
          STOSB
          MOV     AL,'\'                        ; Scan to Previous DirName
          REPNE   SCASB
          JE      DIRNEXT2                      ; If Not Found,
          MOV     DI,OFFSET PATH[-2]            ;   Point to Start of Path
DIRNEXT2: CLD                                   ; Auto-Increment
          ADD     DI,2                          ; Copy Last SubDir to FileName
          PUSH    DI
          MOV     SI,DI
          MOV     DI,OFFSET FILENAME
          CALL    MOVSTR
          POP     DI
          MOV     AL,'$'                        ; Terminate Path String
          STOSB
          CALL    GETDIR                        ; Read Directory
          JC      DIRNEXT4                      ; If Error, Say So
          MOV     SI,OFFSET FILENAME
          MOV     DI,OFFSET DIRNAME
          CALL    MOVSTR
          CALL    SRCHFILE                      ; Search for FileName
          JC      DIRNEXT4                      ; If Error, Say So
          MOV     SI,BX                         ; Save Pointer
          ADD     SI,32                         ; Point to Next Dir Entry
          MOV     AX,SI                         ; Determine Dir Entry Count
          SUB     AX,DIRBUF
          MOV     CL,5
          SHR     AX,CL
          MOV     CX,DIR_LEN
          SUB     CX,AX
          CALL    FINDDIR                       ; Find Next SubDirectory
          JC      DIRNEXT1
          JMP     SHORT DIRNEXT4
DIRNEXT3: STC                                   ; Set Error Return Flag
DIRNEXT4: POP     SI                            ; Restore Registers
          POP     DI
          POP     CX
          POP     BX
          POP     AX
          RET                                   ; Done

SRCHDIR:  PUSH    CX                            ; Save Registers
          PUSH    SI
          MOV     SI,DIRBUF                     ; Point to First DIR Entry
          MOV     CX,DIR_LEN                    ; Load DIR Length
          CALL    FINDDIR                       ; Find SubDirectory
          POP     SI                            ; Restore Registers
          POP     CX
          RET                                   ; Done

FINDDIR:  PUSH    AX                            ; Save Registers
          PUSH    DI
FINDDIR1: JCXZ    FINDDIR4                      ; If Zero, Not Found
FINDDIR2: CMP     BYTE PTR [SI],0               ; If Null, End of Search
          JE      FINDDIR4
          CMP     BYTE PTR [SI],'.'             ; If '.' or '..', Skip
          JE      FINDDIR3
          CMP     BYTE PTR [SI],0E5H            ; If Deleted, Skip
          JE      FINDDIR3
          TEST    BYTE PTR [SI+11],10H          ; Test File Attribute
          JNZ     FINDDIR5                      ; If Match, Found
FINDDIR3: ADD     SI,32                         ; Else Next DIR Entry
          LOOP    FINDDIR2                      ; and Repeat
FINDDIR4: STC                                   ; Set Error Flag
          JMP     SHORT FINDDIR6                ; Done
FINDDIR5: MOV     DI,OFFSET DIRNAME
          CALL    UNPARSE                       ; UnParse Directory Name
          MOV     DI,OFFSET PATH                ; Search for End of Path
          MOV     AL,'$'
          MOV     CX,80
          REPNE   SCASB
          JNE     FINDDIR4                      ; If Not Found, Error
          DEC     DI
          MOV     BX,SI                         ; Set Pointer to DIR Entry
          MOV     SI,OFFSET DIRNAME             ; Copy Directory Name to Path
          CALL    MOVSTR
          DEC     DI
          MOV     AX,'$\'                       ; Terminate Path
          STOSW
          CLC                                   ; Clear Error Flag
FINDDIR6: POP     DI                            ; Restore Registers
          POP     AX
          RET                                   ; Done

SRCHFILE: PUSH    AX                            ; Save Register
          PUSH    CX
          PUSH    DI
          PUSH    SI
          MOV     AX,2900H                      ; Parse Filename
          MOV     SI,OFFSET DIRNAME
          MOV     DI,OFFSET FCB
          INT     21H
          INC     DI                            ; Point to Filename in FCB
          MOV     SI,DIRBUF                     ; Point to Start of DIRBUF
          MOV     CX,DIR_LEN                    ; Load DIR Length
          JCXZ    SRCHFIL2                      ; If Zero, Not Found
SRCHFIL1: PUSH    CX                            ; Save Registers
          PUSH    DI
          PUSH    SI
          MOV     CX,11                         ; Compare Filename
          REPE    CMPSB
          POP     SI                            ; Restore Registers
          POP     DI
          POP     CX
          JE      SRCHFIL3                      ; If Match, Found
          ADD     SI,32                         ; Else Next DIR Entry
          LOOP    SRCHFIL1                      ; and Repeat
SRCHFIL2: STC                                   ; Set Error Flag
          JMP     SHORT SRCHFIL4                ; Done
SRCHFIL3: MOV     BX,SI                         ; Set Pointer to DIR Entry
          CLC                                   ; Clear Error Flag
SRCHFIL4: POP     SI                            ; Restore Registers
          POP     DI
          POP     CX
          POP     AX
          RET                                   ; Done

SRCHCLST: PUSH    AX                            ; Save Register
          PUSH    CX
          PUSH    DI
          PUSH    SI
          MOV     SI,DIRBUF                     ; Point to First DIR Entry
          MOV     CX,DIR_LEN                    ; Load DIR Length
          JCXZ    SRCHCLS3                      ; If Zero, Not Found
          MOV     BX,CLUST
SRCHCLS1: CMP     BYTE PTR [SI],0               ; If Null, End of Search
          JE      SRCHCLS3
          CMP     BYTE PTR [SI],'.'             ; If '.' or '..', Skip
          JE      SRCHCLS2
          CMP     BYTE PTR [SI],0E5H            ; If Deleted, Skip
          JE      SRCHCLS2
          CMP     BX,[SI+26]                    ; Compare Start Cluster Number
          JE      SRCHCLS4                      ; If Match, Found
SRCHCLS2: ADD     SI,32                         ; Else Next DIR Entry
          LOOP    SRCHCLS1                      ; and Repeat
SRCHCLS3: STC                                   ; Set Error Flag
          JMP     SHORT SRCHCLS5                ; Done
SRCHCLS4: MOV     DI,OFFSET FILENAME            ; UnParse File Name
          CALL    UNPARSE
          CLC                                   ; Clear Error Flag
SRCHCLS5: POP     SI                            ; Restore Registers
          POP     DI
          POP     CX
          POP     AX
          RET                                   ; Done

READCLST: PUSH    AX                            ; Save Registers
          PUSH    CX
          PUSH    DX
          MOV     AX,BX                         ; Calculate Absolute Sector #
          SUB     AX,2
          MOV     CX,CLSTSEC
          MUL     CX
          ADD     AX,STARTSEC
          MOV     DX,AX
          MOV     AL,DRIVE
          PUSH    BX                            ; Save Registers
          PUSH    DI
          MOV     BX,DI                         ; Read Cluster
          INT     25H
          POPF
          POP     DI                            ; Restore Registers
          POP     BX
          CALL    NEXTCLST                      ; Get Next Cluster Number
          MOV     AX,CLSTSEC                    ; Increment Buffer Pointer
          MOV     CX,SECSIZE
          MUL     CX
          ADD     DI,AX
          POP     DX                            ; Restore Registers
          POP     CX
          POP     AX
          RET                                   ; Done

PREVCLST: PUSH    BX                            ; Save Registers
          PUSH    CX
          PUSH    DX
          MOV     DX,BX                         ; Reserve Cluster Number
          MOV     CX,CLSTTOT                    ; Start Looking at Last Cluster
PREVCLS1: MOV     BX,CX                         ; Check Cluster
          INC     BX
          CALL    NEXTCLST
          CMP     BX,DX                         ; If Match, Use It
          LOOPNE  PREVCLS1                      ; Else Repeat
          JNE     PREVCLS2                      ; If No Match, Return Zero
          ADD     CX,2                          ; Adjust for Cluster Number
PREVCLS2: MOV     AX,CX                         ; AX = Cluster Number
          POP     DX                            ; Restore Registers
          POP     CX
          POP     BX
          RET                                   ; Done

NEXTCLST: CMP     FATSIZE,3                     ; If FAT Size = 16 Bits,
          JE      NEXTCLS1
          SHL     BX,1                          ;   Simply Read Next Cluster #
          MOV     BX,FATBUF[BX]
          RET                                   ;   Done
NEXTCLS1: PUSH    AX                            ; Save Registers
          PUSH    CX
          MOV     AX,BX                         ; Word # = Cluster # * 1.5
          SHL     AX,1
          ADD     BX,AX
          SHR     BX,1
          MOV     BX,FATBUF[BX]
          JNC     NEXTCLS2                      ; If Odd, Use 12 MSB's
          MOV     CL,4
          SHR     BX,CL
NEXTCLS2: AND     BX,0FFFH                      ; Else Use 12 LSB's
          POP     CX                            ; Restore Registers
          POP     AX
          RET                                   ; Done

UNPARSE:  PUSH    CX                            ; Save Registers
          PUSH    DI
          PUSH    SI
          MOV     CX,8                          ; FileName Length = 8 Max
UNPARSE1: LODSB                                 ; Read Character
          CMP     AL,' '                        ; If Space, Exit Loop
          JE      UNPARSE2
          STOSB                                 ; Move Character
          LOOP    UNPARSE1                      ; Repeat
UNPARSE2: MOV     AL,'.'                        ; Put a Dot in the String
          STOSB
          POP     SI                            ; Point to Extension
          PUSH    SI
          ADD     SI,8
          MOV     CX,3                          ; Extension Length = 3 Max
UNPARSE3: LODSB                                 ; Read Character
          CMP     AL,' '                        ; If Space, Exit Loop
          JE      UNPARSE4
          STOSB                                 ; Move Character
          LOOP    UNPARSE3                      ; Repeat
UNPARSE4: CMP     CX,3                          ; If No Extension, Remove Dot
          JNE     UNPARSE5
          DEC     DI
UNPARSE5: MOV     AL,0                          ; Terminate FileName
          STOSB
          MOV     AL,'$'
          STOSB
          POP     SI                            ; Restore Registers
          POP     DI
          POP     CX
          RET                                   ; Done

MOVSTR:   LODSB                                 ; Read Source
          STOSB                                 ; Write Destination
          OR      AL,AL                         ; If Not EOS, Repeat
          JNZ     MOVSTR
          RET                                   ; Done

GET_WORD: PUSH    BX                            ; Save Registers
          PUSH    DI
          PUSH    SI                            ; Save Pointer
          XOR     DX,DX                         ; Value = 0
GET_WRD1: LODSB                                 ; Read Character
          CMP     AL,'0'                        ; If Not Numeric, Done
          JB      GET_WRD2
          CMP     AL,'9'
          JA      GET_WRD2
          SUB     AL,'0'                        ; Convert to BCD
          CBW
          MOV     BX,AX                         ; Value = Value*10+BCD
          MOV     AX,10
          MUL     DX
          ADD     AX,BX
          MOV     DX,AX
          JMP     GET_WRD1                      ; Repeat
GET_WRD2: DEC     SI
          POP     DI                            ; Restore Pointer
          CMP     DI,SI                         ; Compare Pointer
          POP     DI                            ; Restore Registers
          POP     BX
          RET                                   ; Done

STRIP0:   CMP     BYTE PTR [DI],'0'             ; If Character != '0', Done
          JNE     STRIP1
          CMP     BYTE PTR [DI+1],'0'           ; If Next Character != Digit,
          JL      STRIP1                        ;   Done
          CMP     BYTE PTR [DI+1],'9'
          JG      STRIP1
          MOV     BYTE PTR [DI],' '             ; Change '0' to ' '
          INC     DI                            ; Point to Next Character
          JMP     SHORT STRIP0                  ; Repeat
STRIP1:   RET                                   ; Done

DEC2OUT:  PUSH    AX                            ; Save Registers
          PUSH    BX
          XOR     AH,AH                         ; Clear AH
          MOV     BL,10                         ; AH=AX%10,AL=AX/10
          DIV     BL
          ADD     AX,'00'                       ; Convert to ASCII
          SUB     DI,2
          MOV     [DI],AX                       ; Store in String
          POP     BX                            ; Restore Registers
          POP     AX
          RET                                   ; Done

DEC4OUT:  PUSH    AX                            ; Save Registers
          PUSH    BX
          MOV     BL,100                        ; AH=AX%100,AL=AX/100
          DIV     BL
          XCHG    AH,AL                         ; Convert 2 LSD's
          CALL    DEC2OUT
          XCHG    AH,AL                         ; Convert 2 MSD's
          CALL    DEC2OUT
          POP     BX                            ; Restore Registers
          POP     AX
          RET                                   ; Done

DEC5OUT:  PUSH    AX                            ; Save Registers
          PUSH    BX
          PUSH    DX                            ; DX=AX%10000,AX=AX/10000
          MOV     BX,10000
          XOR     DX,DX
          DIV     BX
          XCHG    DX,AX                         ; Convert 4 LSD's
          CALL    DEC4OUT
          XCHG    DX,AX                         ; Convert MSD
          ADD     AL,'0'
          SUB     DI,1
          MOV     [DI],AL
          POP     DX                            ; Restore Registers
          POP     BX
          POP     AX
          RET                                   ; Done

FATBUF    LABEL   WORD

CODE      ENDS

          END     OWNER
