%TITLE          "XFD2ATR  - Convert .XFD to .ATR Files - CHiPS bv 1995"
;**********************************************************************
;**                                                                  **
;**  Program   : XFD2ATR                                             **
;**  Purpose   : Converts .XFD Atari files to .ATR Atari files.      **
;**              Assume a maximum of 500 conversions at once.        **
;**                                                                  **
;**  Author    : B.F. Schreurs - CHiPS bv                            **
;**  Date      : September 28, 1995                                  **
;**                                                                  **
;**  Calls     : [None]                                              **
;**                                                                  **
;**  Stack     :  64 Bytes                                           **
;**                                                                  **
;**  Syntax    :                                                     **
;**              Input     : C:> XFD2ATR C:\CONVERT\*.XFD            **
;**              in general: C:> XFD2ATR filemask.XFD                **
;**              Ouput     : C:>         C:\CONVERT\*.ATR            **
;**              in general: C:>         filemask.ATR                **
;**                                                                  **
;**********************************************************************
        IDEAL
        JUMPS

;**********************************************************************
;**  Equates                                                         **
;**********************************************************************
DOS_FUNCTION            EQU    021h
DOS_WRITE_CHARACTER     EQU    002h
DOS_TERMINATE_EXE       EQU    04Ch
DOS_FIND_FILES_ONLY     EQU    000h
DOS_FIND_FILES_AND_DIRS EQU    010h
DOS_FIND_FIRST_FILE     EQU    04Eh
DOS_FIND_NEXT_FILE      EQU    04Fh
DOS_SET_DTA             EQU    01Ah
DOS_GET_DTA             EQU    02Fh
DOS_OPEN_FILE           EQU    03Dh
DOS_CREATE_FILE         EQU    03Ch
DOS_READ_FROM_HANDLE    EQU    03Fh
DOS_WRITE_TO_HANDLE     EQU    040h
DOS_CLOSE_FILE          EQU    03Eh

KEYBOARD_SERVICE        EQU    016h     ; BIOS Keyboard interrupt
INT16_READ_CHAR         EQU    000h     ; Read the next character
INT16_KBD_STATUS        EQU    001h     ; Returns the keyboard status

KEY_ESC                 EQU    01Bh
FILE_READ_ONLY          EQU    000h

FILE_TABLE_SIZE         EQU    6500     ; Reserve space for 500 files + indicator
FILE_SIZE               EQU    13       ; Filename + "." + Extension + FileSize indicator
DISK_DENSITY_090KB      EQU    "S"
DISK_DENSITY_130KB      EQU    "M"
DISK_DENSITY_140KB      EQU    "E"
DISK_DENSITY_180KB      EQU    "X"
DISK_DENSITY_UNKNOWN    EQU    "U"
MAX_FILE_SPEC_SIZE      EQU    256 
NULL                    EQU    00h
LF                      EQU    0Ah
CR                      EQU    0Dh

PROGRAM_NAME            EQU   <CR, LF, "XFD2ATR ">
PROGRAM_VERSION         EQU   <" Version 01.00.00, ">
PROGRAM_COPYRIGHT       EQU   <"Public Domain 1995 by B.F. Schreurs, CHiPS bv", CR, LF>
PROGRAM_SYNTAX          EQU   <"Syntax:  XFD2ATR [d:][path]filename", CR, LF>
PROGRAM_TEXT2           EQU   <"         filename must be an Atari 8-bit XFormer .XFD file", CR, LF>
PROGRAM_TEXT3           EQU   <"         Wild characters are allowed, i.e. POK*.XFD", CR, LF>
PROGRAM_TEXT4           EQU   <"         The converted files will have the same filename, but", CR, LF>
PROGRAM_TEXT5           EQU   <"         the file(s) will have the SIO2PC format now.", CR, LF>
PROGRAM_TEXT6           EQU   <"         SIO2PC files have the .ATR extension.", CR, LF>


;**********************************************************************
SEGMENT SSeg Para Stack 'STACK'
;**********************************************************************

        db        64 dup (0)            ; Stack

ENDS    SSeg

;**********************************************************************
SEGMENT DSeg Word Public 'DATA'
;**********************************************************************

;----------------------------------------------------------------------
;--  Structures                                                      --
;----------------------------------------------------------------------
struc   Psp                             ; Structure representing DOS's
                                        ; Program Segment Prefix (Psp)
  Int20h                DW      ?       ; Int 20h
  EndOfAllocation       DW      ?       ; Segment, end of allocation block
  Reserved1             DB      ?       ; Reserved by DOS
  MsDosDispatcher       DB   5h dup (?) ; Long call to MS-DOS function
                                        ; dispatcher
  OldTermination        DD      ?       ; Previous contents of termination
                                        ; handler interrupt vector (Int22h)
  OldCtrlCHandler       DD      ?       ; Previous contents of CTRL-C
                                        ; interrupt vector (Int23h)
  OldCriticalError      DD      ?       ; Previous contents of critical-error
                                        ; interrupt vector (Int24h)
  Reserved2             DB  16h dup (?) ; Reserved by DOS
  EnvironmentBlock      DW      ?       ; Segment address of environment block
  Reserved3             DB  2Eh dup (?) ; Reserved by DOS
  Fcb1                  DB  10h dup (?) ; Default File Control Block(FCB) #1
  Fcb2                  DB  14h dup (?) ; Default File Control Block(FCB) #2
  LengthByte            DB      ?       ; Leading length byte(<= 255)
  CommandTail           DB  255 dup (?) ; Contents of the string
ends                                    ; Psp


Struc   Dta                             ; Structure representing DOS's
                                        ; Disk Transfer Area (Dta)
  Filler1               DB   26 dup (?) ; Filler
  FileSizeLowLow        DB      ?       ; File Size Low Low
  FileSizeLowHigh       DB      ?       ; File Size Low High
  FileSizeHighLow       DB      ?       ; File Size High Low
  FileSizeHighHigh      DB      ?       ; File Size High High
  Filename              DB   13 dup (0) ; Filename
ends                                    ; Dta



;----------------------------------------------------------------------
;--  Working Storage                                                 --
;----------------------------------------------------------------------
Syntax                  DB      PROGRAM_NAME,      PROGRAM_VERSION
                        DB      PROGRAM_COPYRIGHT, PROGRAM_SYNTAX
                        DB      PROGRAM_TEXT2,     PROGRAM_TEXT3
                        DB      PROGRAM_TEXT4,     PROGRAM_TEXT5
                        DB      PROGRAM_TEXT6,     0

File_Table              DB  FILE_TABLE_SIZE dup (0)
                                        ; Max. number of found files + indicator
File_Spec               DB  256 dup (0) ; File Specification for search
Path_Spec               DB  256 dup (0) ; Path Specification for processing
ATR_File_Spec           DB  256 dup (0) ; Input  .ATR File
XFD_File_Spec           DB  256 dup (0) ; Output .XFD File
Old_Dta_Seg             DW      ?       ; Old Dta Segment Address
Old_Dta_Ofs             DW      ?       ; Old Dta Segment Offset
Own_Dta                 Dta     <>
Atr                     DB      ".ATR"  ; .ATR extension
Add_Characters_090KB    DB   96h,02h,80h,16h,80h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
Add_Characters_130KB    DB   96h,02h,80h,20h,80h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
Add_Characters_140KB    DB   96h,02h,00h,23h,80h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
Add_Characters_180KB    DB   96h,02h,00h,2Dh,00h,01h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
I_O_Buffer              DB 2048 dup (0) ;   Used by input/output file
Check_Abort_Counter     DB      0
Disk_Density            DB      DISK_DENSITY_090KB
Return_Code             DB      0

; Messages
Msg_No_Files_Found      DB      CR, LF, "Sorry, No Files Found To Convert..."
                        DB      CR, LF, ".XFD conversion terminated"
                        DB      CR, LF, NULL
Msg_Start_Conversion    DB      CR, LF, "Conversion will start, press ESC to abort program"
                        DB      CR, LF, NULL
Msg_Conversion_Aborted  DB      CR, LF
                        DB      CR, LF, ".XFD Conversion ABORTED!"
                        DB      CR, LF, NULL
Msg_Thank_You           DB      CR, LF
                        DB      CR, LF, ".XFD conversion completed"
                        DB      CR, LF, "Thank you for using XFD2ATR!"
                        DB      CR, LF, NULL
Msg_Converting          DB      CR, LF, "Now converting "
Msg_Converting_File     DB      "            ", NULL
Msg_File_Skipped        DB      ", File Skipped, unrecognized density", NULL


;----------------------------------------------------------------------
;--  Pointers                                                        --
;----------------------------------------------------------------------
Syntax_Ptr                      DD      Syntax
File_Table_Ptr                  DD      File_Table
File_Spec_Ptr                   DD      File_Spec
Path_Spec_Ptr                   DD      Path_Spec
ATR_File_Spec_Ptr               DD      ATR_File_Spec
XFD_File_Spec_Ptr               DD      XFD_File_Spec
Msg_No_Files_Found_Ptr          DD      Msg_No_Files_Found
Msg_Start_Conversion_Ptr        DD      Msg_Start_Conversion
Msg_Conversion_Aborted_Ptr      DD      Msg_Conversion_Aborted
Msg_Thank_You_Ptr               DD      Msg_Thank_You
Msg_Converting_Ptr              DD      Msg_Converting
Msg_Converting_File_Ptr         DD      Msg_Converting_File
Msg_File_Skipped_Ptr            DD      Msg_File_Skipped
Psp_Ptr                         DW      ?
Dta_Ptr                         DW      ?
Input_File                      DW      0
Output_File                     DW      0

;----------------------------------------------------------------------
;--  External Variables                                              --
;----------------------------------------------------------------------


ENDS    DSeg

;**********************************************************************
SEGMENT CSeg Word Public 'CODE'
;**********************************************************************



;**********************************************************************
Main:   
;**********************************************************************
        ASSUME  cs:CSeg
        ASSUME  ds:DSeg
        mov     ax, DSeg                ; Initialize DS to address
        mov     ds, ax                  ; of data segment

        call    Initialize
        call    Check_Abort
        call    Check_Command_Line_Syntax
        call    Check_Abort
        call    Build_File_Table
        call    Check_Abort
        call    Sort_File_Table
        call    Check_Abort
        call    Process_File_Table
        call    Stop_Run



;**********************************************************************
PROC    Initialize
;**********************************************************************
        ;**                                                          **
        ;**  Purpose   : Initialize program variables                **
        ;**  Input     : [None]                                      **
        ;**  Output    : [None]                                      **
        ;**  Calls     : [None]                                      **
        ;**  Registers : ax, flags                                   **
        ;**                                                          **
        ;**************************************************************

        mov     [Psp_Ptr], es           ; Store the PSP address by storing
                                        ; es in the variable Psp_Ptr
                                        ; Note that we do it this way
                                        ; instead of using DOS function 62h
                                        ; because the function is only
                                        ; available on DOS 3.0 or later
        ret

ENDP    Initialize



;**********************************************************************
PROC    Check_Command_Line_Syntax
;**********************************************************************
        ;**                                                          **
        ;**  Purpose   : Check Command Line Input Syntax             **
        ;**  Input     : [None]                                      **
        ;**  Output    : [None]                                      **
        ;**  Calls     : [None]                                      **
        ;**  Registers : cx, es:di, ds:si                            **
        ;**                                                          **
        ;**************************************************************

; Check Command Line
        xor     cx, cx                  ; Clear cx
        mov     cl, [es:Psp.LengthByte] ; Check if command line is empty
        cmp     cl, 0                   ; Parameter specified?
        jne     @@10                    ; Yes
        les     di, [Syntax_Ptr]        ; No, show correct syntax
        call    Display_String
        jmp     Stop_Run                ; Stop the program

; Copy Command Line To File Specification Buffer
@@10:
        push    ds es es
        mov     bx, cx                  ; Save Length
        mov     si, Offset (es:Psp).CommandTail  ; Position to command line
        inc     si                      ; but skip space character
        les     di, [File_Spec_Ptr]     ; File Spec Mask
        pop     ds
        cld
        rep     movsb                   ; Copy Command_Tail
        pop     es ds

        mov     di, offset File_Spec    ; File Spec Mask
        mov     al, CR                  ; Search for Carriage Return
        mov     cx, bx                  ; Search size
        cld                             ; Search direction is up
        repne   scasb                   ; Search equal CR, uses es:di
        dec     di                      ; Adjust start position after scan
        xor     cx,cx
        mov     [ds:di], cx             ; Remove return character

; Copy Path Spec from File Spec
        les     di, [Path_Spec_Ptr]     ; Path Spec Mask
        mov     si, offset File_Spec    ; File Spec Mask
        mov     cx, MAX_FILE_SPEC_SIZE  ; Max size of command line
        cld                             ; Copy from left to right
        rep     movsb                   ; Copy File Spec to Path Spec

; Determine Path only, remove file search mask
        les     di, [Path_Spec_Ptr]     ; Path Spec Mask
        mov     al, "\"                 ; Search backslash
        mov     cx, MAX_FILE_SPEC_SIZE  ; Search size equal max size of cl
        add     di, cx                  ; Move to end of Path Spec Mask
        std                             ; Search direction is down
        repne   scasb                   ; Search equal "\", uses es:di

; Remove file search mask here
@@20:
        xor     cx, cx                  ; Reset cx
        mov     cl, [byte es:di]        ; Load byte of Path Spec File Mask
        cmp     cx, 0                   ; End of path reached?
        jz      @@99                    ; Yes
                                        ; No, so...
        mov     [byte es:di], NULL      ; Replace file mask byte with 00h
        inc     di
        jmp     @@20

@@99:
        ret

ENDP    Check_Command_Line_Syntax



;**********************************************************************
PROC    Build_File_Table
;**********************************************************************
        ;**                                                          **
        ;**  Purpose   : Build a Filename table with passed Syntax   **
        ;**  Input     : [None]                                      **
        ;**  Output    : [None]                                      **
        ;**  Calls     : [None]                                      **
        ;**  Registers : ax, bx, cx, ds                              **
        ;**                                                          **
        ;**************************************************************

; Save Current Dta
        mov     ah, DOS_GET_DTA         ; Get Disk Transfer Area address
        int     DOS_FUNCTION
        mov     [Old_Dta_Seg], es       ; Save old Dta Segment Address
        mov     [Old_Dta_Ofs], bx       ; Save old Dta Segment Offset

; Specify Own Dta
        mov     di, offset File_Table   ; Address of File Table
        mov     dx, offset Own_Dta      ; Address of Own Dta
        mov     [Dta_Ptr], dx           ; Store the Dta address
        mov     ah, DOS_SET_DTA
        int     DOS_FUNCTION

; Reset pointer to our own file table
        les     di, [File_Table_Ptr]
        xor     cx,cx                   ; Reset cx
        mov     [byte ds:di], cl        ; Set end of Table;

; Use bx as file counter
        xor     bx, bx                  ; Reset file counter

; Only Search For Files
        mov     cx, DOS_FIND_FILES_ONLY
        lds     dx, [File_Spec_Ptr]     ; Use File Spec Mask
        mov     ah, DOS_FIND_FIRST_FILE ; Find First File
        jmp     @@20

@@10:
        mov     ah, DOS_FIND_NEXT_FILE  ; Find Next File

; Read VTOC
@@20:
        int     DOS_FUNCTION            ; Find First/Next File
        jc      @@50                    ; No more files?

; Move File To File Table
@@030:
        inc     bx                      ; First increase file counter
        push    di                      ; Determine File length
        mov     di, offset Own_Dta.Filename
                                        ; Load address of filename
        mov     al, NULL                ; Search for Null terminator
        mov     cx, 13                  ; Search size euqal file length + 1
        cld                             ; Search direction is up
        repne   scasb                   ; Search equal NULL, uses es:di
        mov     ax, cx                  ; ax is used to adjust File Table
        mov     cx, 13                  ; Determine
        sub     cx, ax                  ;   Copy Length
        dec     cx                      ; Adjust Copy Length
        pop     di

                                        ; Now copy File to File Table
        mov     si, offset Own_Dta.Filename
                                        ; Load address of filename
        cld                             ; Copy from left to right
        rep     movsb                   ; Copy string now
        add     di, ax
        xor     cx,cx                   ; Reset cx
        mov     [byte ds:di], cl        ; Set end of Table
        inc     di                      ; And move to File Type

        mov     ax, DISK_DENSITY_090KB
        mov     cl, [offset Own_Dta.FileSizeLowHigh]
        cmp     cx, 104                 ; Single Density Disk?
        je      @@40                    ; Yes
                                        ; No, so
        mov     ax, DISK_DENSITY_130KB
        cmp     cx, 8                   ; Medium Density Disk?
        je      @@40                    ; Yes
                                        ; No, so
        mov     ax, DISK_DENSITY_140KB
        cmp     cx, 48                  ; Enhanced Density Disk?
        je      @@40                    ; Yes
                                        ; No, so
        mov     ax, DISK_DENSITY_180KB
        cmp     cx, 208                 ; XF551 Density Disk?
        je      @@40                    ; Yes
                                        ; No, so
        mov     ax, DISK_DENSITY_UNKNOWN

@@40:
        mov     [byte ds:di], al        ; Set File Type
        inc     di                      ; Point to Next File

        jmp     @@10                    ; Process Next File

; Restore Old Dta
@@50:
        mov     es, [Old_Dta_Seg]       ; Restore old Dta Address
        mov     dx, [Old_Dta_Ofs]
        mov     ah, DOS_SET_DTA
        int     DOS_FUNCTION

        cmp     bx, 0                   ; Any file found?
        jnz     @@99                    ; Yes
                                        ; No, show error
        les     di, [Msg_No_Files_Found_Ptr]
        call    Display_String
        jmp     Stop_Run                ; Stop the program

@@99:        
        les     di, [Msg_Start_Conversion_Ptr]
        call    Display_String
        ret

ENDP    Build_File_Table



;**********************************************************************
PROC    Sort_File_Table
;**********************************************************************
        ;**                                                          **
        ;**  Purpose   : Sort File Table                             **
        ;**  Input     : Unsorted File Table                         **
        ;**  Output    : Sorted File Table                           **
        ;**  Calls     : [None]                                      **
        ;**  Registers : es:di, ds:si                                **
        ;**                                                          **
        ;**************************************************************

        ret

ENDP    Sort_File_Table



;**********************************************************************
PROC    Process_File_Table
;**********************************************************************
        ;**                                                          **
        ;**  Purpose   : Process File Table                          **
        ;**  Input     : File Table, .XFD files                      **
        ;**  Output    : .ATR Files                                  **
        ;**  Calls     : [None]                                      **
        ;**  Registers :                                             **
        ;**                                                          **
        ;**************************************************************

        mov     si, offset File_Table

; Move file from file table to convert file text message
@@10:
        xor     cx, cx                  ; Reset cx
        mov     cl, [byte ds:si]        ; Load first byte of File from table
        cmp     cx, 0                   ; End of table reached?
        jz      @@99                    ; Yes
                                        ; No, so...
        push    si                      ; Save pointer to file for later use
        les     di, [Msg_Converting_File_Ptr]
        mov     cx, 12                  ; Copy length
        cld                             ; Copy from left to right
        rep     movsb                   ; Copy string now

; Show conversion message for file...
        les     di, [Msg_Converting_Ptr]
        call    Display_String          ; Now converting...

; Open XFD file to be converted
; Fist copy path spec mask
        les     di, [XFD_File_Spec_Ptr] ; Copy XFD file spec mask from
        mov     si, offset Path_Spec    ; Path Spec Mask
        mov     cx, MAX_FILE_SPEC_SIZE  ; Max size of command line
        cld                             ; Copy from left to right
        rep     movsb                   ; Copy File Spec to Path Spec

; Search end of path
        les     di, [XFD_File_Spec_Ptr] ; First search end of path
        mov     al, NULL                ; Search for Null terminator
        mov     cx, MAX_FILE_SPEC_SIZE  ; Max size of command line
        cld                             ; Search direction is up
        repne   scasb                   ; Search equal NULL, uses es:di
        dec     di                      ; Adjust pointer after search

; Now copy the File Spec Mask
        pop     si                      ; Pointer to file
        mov     cx, 12                  ; Copy length
        cld                             ; Copy from left to right
        rep     movsb                   ; Copy string now        
        inc     si                      ; Increment table pointer by 1
        mov     cl, [byte ds:si]        ; Load Disk Density
        mov     [Disk_Density], cl      ; Save it
        inc     si                      ; Move pointer to next file
        push    si                      ; Points to next file now,
                                        ;   so save pointer

; Unknown Density Disk?
        cmp     [Disk_Density], DISK_DENSITY_UNKNOWN
        jne     @@15                    ; No
                                        ; Yes, so

; Show conversion message for file...
        les     di, [Msg_File_Skipped_Ptr]
        call    Display_String          ; Unknown Density...
        jmp     @@70                    ; Jmp to next file

@@15:
; Copy File Input Mask to File Output Mask
        les     di, [ATR_File_Spec_Ptr] ; Copy ATR File Spec Mask from
        mov     si, offset XFD_File_Spec
                                        ; XFD File Spec Mask
        mov     cx, MAX_FILE_SPEC_SIZE  ; Max size of command line
        cld                             ; Copy from left to right
        rep     movsb                   ; Copy File Spec to Path Spec

; Search for dot, if any (i.e. MYFILE.XFD)
        les     di, [ATR_File_Spec_Ptr] ; File to be inspected
        mov     al, "."                 ; Search for dot
        mov     cx, MAX_FILE_SPEC_SIZE  ; Max size of command line
        cld                             ; Search direction is up
        repne   scasb                   ; Search equal ".", uses es:di
        dec     di                      ; Adjust pointer at the dot
        cmp     cx, 0                   ; Dot found?
        jne     @@20                    ; Yes
                                        ; No, so
        les     di, [ATR_File_Spec_Ptr] ; File to be inspected
        mov     al, NULL                ; Search for NULL terminator
        mov     cx, MAX_FILE_SPEC_SIZE  ; Max size of command line
        cld                             ; Search direction is up
        repne   scasb                   ; Search equal 00h, uses es:di
        dec     di                      ; Adjust pointer after last char

; Copy .ATR extension
@@20:
        mov     si, offset Atr
        mov     cx, 4                   ; .ATR is 4 characters
        cld                             ; Copy from left to right
        rep     movsb                   ; Copy File Spec to Path Spec

; Open input file to be processed
        mov     dx, offset XFD_File_Spec
        mov     ah, DOS_OPEN_FILE
        mov     al, FILE_READ_ONLY
        int     DOS_FUNCTION
        jc      @@50                    ; Skip processing on error
        mov     [Input_File], ax        ; Store handle

; Open output file
        mov     dx, offset ATR_File_Spec
        xor     cx, cx                  ; Normal attributes
        mov     ah, DOS_CREATE_FILE
        int     DOS_FUNCTION
        jc      @@40                    ; Skip processing on error
        mov     [Output_File], ax       ; Store handle

; First determine Disk Density
        mov     dx, offset Add_Characters_090KB
        cmp     [Disk_Density], DISK_DENSITY_090KB
        je      @@25                    ; Yes,
                                        ; No, so
        mov     dx, offset Add_Characters_130KB
        cmp     [Disk_Density], DISK_DENSITY_130KB
        je      @@25                    ; Yes,
                                        ; No, so
        mov     dx, offset Add_Characters_140KB

        cmp     [Disk_Density], DISK_DENSITY_140KB
        je      @@25                    ; Yes,
                                        ; No, so
        mov     dx, offset Add_Characters_180KB

@@25:
; Then add 16 Header bytes to output file
        mov     ah, DOS_WRITE_TO_HANDLE
        mov     bx, [Output_File]
        mov     cx, 16
        int     DOS_FUNCTION            ; Write 16 characters
        jc      @@40                    ; Close files on error
        or      ax, ax                  ; Disk full?
        jz      @@40                    ; Yes
                                        ; No, so

; Now process files
        mov     [Check_Abort_Counter], 0 ; Reset Counter

@@30:
        cmp     [Check_Abort_Counter], 255
        jne     @@35
        call    Check_Abort
        mov     [Check_Abort_Counter], 0 ; Reset Counter

@@35:
        inc     [Check_Abort_Counter]
        mov     ah, DOS_READ_FROM_HANDLE
        mov     bx, [Input_File]
        mov     cx, 2048
        mov     dx, offset I_O_Buffer
        int     DOS_FUNCTION            ; Read 1 character
        jc      @@40                    ; Close files on error
        or      ax, ax                  ; End of input file?
        jz      @@40                    ; Yes
                                        ; No, so
        mov     ah, DOS_WRITE_TO_HANDLE
        mov     bx, [Output_File]
        mov     cx, 2048
        mov     dx, offset I_O_Buffer
        int     DOS_FUNCTION            ; Write 1 character
        jc      @@40                    ; Close files on error
        or      ax, ax                  ; Disk full?
        jnz     @@30                    ; No
                                        ; Yes, so
; Close Output file
@@40:
        mov     bx, [Output_File]
        mov     ah, DOS_CLOSE_FILE
        int     DOS_FUNCTION

; Close Input file
@@50:
        mov     bx, [Input_File]
        mov     ah, DOS_CLOSE_FILE
        int     DOS_FUNCTION

; Process next file
@@70:
        pop     si                      ; Restore pointer to next file
        jmp     @@10                    ; Convert next file

@@99:
        les     di, [Msg_Thank_You_Ptr]
        call    Display_String

        ret

ENDP    Process_File_Table



;**********************************************************************
PROC    Show_File_Table
;**********************************************************************
        ;**                                                          **
        ;**  Purpose   : Show File Table                             **
        ;**  Input     : File Table Pointer                          **
        ;**  Output    : [None]                                      **
        ;**  Calls     : Display_String                              **
        ;**  Registers : es:di                                       **
        ;**                                                          **
        ;**************************************************************

        les     di, [File_Table_Ptr]    ; Get the address of the string
        call    Display_String
        jmp     Stop_Run                ; Stop the program

ENDP    Show_File_Table



;**********************************************************************
PROC    Display_String
;**********************************************************************
        ;**                                                          **
        ;**  Purpose   : Display NULL terminated ASCII string        **
        ;**  Input     : es:di                                       **
        ;**  Output    : Character to Screen                         **
        ;**  Calls     : [None]                                      **
        ;**  Registers : es:di, ax, dx                               **
        ;**                                                          **
        ;**************************************************************

@@00:
        cmp     [byte es:di], NULL      ; Check for the NULL character
        je      @@99
        mov     dl, [byte es:di]
        mov     ah,DOS_WRITE_CHARACTER
        int     DOS_FUNCTION
        inc     di                      ; Point to the next character
        jmp     @@00

@@99:
        ret

ENDP    Display_String



;**********************************************************************
PROC    Check_Abort
;**********************************************************************
        ;**                                                          **
        ;**  Purpose   : Check Abort of Program                      **
        ;**  Input     : [None]                                      **
        ;**  Output    : [None]                                      **
        ;**  Calls     : [None]                                      **
        ;**  Registers : ax                                          **
        ;**                                                          **
        ;**************************************************************

        xor     ax, ax                  ; Reset ax
        mov     ah, INT16_KBD_STATUS    ; BIOS check buffer function
        int     KEYBOARD_SERVICE        ; Call BIOS keyboard service
                                        ; Key waiting?
        jz      @@99                    ; No
                                        ; Yes, so
        mov     ah, INT16_READ_CHAR     ; BIOS read-key function
        int     KEYBOARD_SERVICE        ; Call BIOS keyboard service

        or      al, al                  ; Special Key pressed?
        jnz     @@10                    ; No
                                        ; Yes, so
        xchg    ah, al                  ; set ah<-0, al<-scan code
        add     al, 32                  ; Adjust scan code to >= 32
        jmp     @@20

@@10:
        xor     ah, ah                  ; Reset ah
        cmp     al, 32                  ; Control Key pressed?
        jb      @@20                    ; Yes
                                        ; No, so
        inc     ah                      ; set ah = 1 (al=ASCII char)

@@20:
        or      ah, ah                  ; Set or clear zf result flag
                                        ; Ascii key pressed?
        jnz     @@99                    ; No
                                        ; Yes, so
        cmp     al, KEY_ESC             ; ESCape key pressed?
        jne     @@99                    ; No
                                        ; Yes, so
        les     di, [Msg_Conversion_Aborted_Ptr]
        call    Display_String          ; Abort Conversion
        jmp     Stop_Run
        
@@99:
        ret

ENDP    Check_Abort



;**********************************************************************
PROC    Stop_Run
;**********************************************************************
        ;**                                                          **
        ;**  Purpose   : Stops the program                           **
        ;**  Input     : [None]                                      **
        ;**  Output    : [None]                                      **
        ;**  Calls     : [None]                                      **
        ;**  Registers : [None]                                      **
        ;**                                                          **
        ;**************************************************************

        mov     ah, DOS_TERMINATE_EXE
        mov     al, [Return_Code]       ; Return code value
        int     DOS_FUNCTION

ENDP    Stop_Run



ENDS    CSeg                    ; End of Code segment

END     Main                    ; End of XFD2ATR
