 ; Program Name: READFILE.S

 ; Get file name with the file selector.
 ; Search for the file.
 ; If file can't be found, terminate the program.
 ; Else if file is found.
 ;         1. Open the file.
 ;         2. Read the file.
 ;         3. Close the file.

calculate_program_size:
 lea        -$102(pc), a1        ; Fetch basepage start address.
 lea        stack(pc), a7        ; Fetch program end address.
 movea.l    a7, a0
 suba.l     a1, a0               ; Program size.
return_memory:
 pea        (a0)                 ; Push program length.
 pea        (a1)                 ; Push basepage address.
 move.l     #$4A0000, -(sp)      ; Function = m_shrink = GEMDOS $4A.
 trap       #1                   ; Invoke GEMDOS exception.
 lea        $C(a7), sp           ; Reset stack pointer to top of stack.

initialize_application:
 move.l     #appl_init, aes_pb   ; apid returned in int_out[0] and global[2].
 bsr        aes                

get_graf_handle:
 move.l     #graf_handle, aes_pb
 bsr        aes
 lea        open_workscreen, a3  ; Store handle in pre-defined structure.
 move.w     int_out, 12(a3)

open_virtual_workscreen:
 move.l     a3, vdi_pb           ; Address of pre-defined structure to VDI
 lea        int_in, a0           ; parameter block.
 moveq      #9, d0
int_in_loop:                     ; The first 10 elements of the int_in
 move.w     #1, (a0)+            ; array must be set to 1.  The 11th element
 dbra       d0, int_in_loop      ; must be set to 2.
 move.w     #2, 20(a0)           ; Element 11 of array int_in.
 bsr        vdi
 move.w     12(a3), d0           ; Fetch handle.
 lea        clear_workscreen, a0 ; Store handle in pre-defined structures.
 move.w     d0, 12(a0)
 lea        close_workscreen, a0
 move.w     d0, 12(a0)
 bsr        clear_work_screen
 lea        message_1, a0
 bsr        print_line
 
get_current_drive:               ; Current drive = active desktop window.
 move.w     #$19, -(sp)          ; Function = c_getdrv.
 trap       #1                   ; Current drive number returned in D0.
 addq.l     #2, sp
 add.w      #$41, d0             ; Convert drive number to drive letter.
 lea        input_path, a6       ; Fetch address of array 'input_path'.
 move.b     d0, (a6)+            ; Store drive letter in 'input_path' array.
 move.b     #$3A, (a6)+          ; Store a colon in 'input_path' array.

get_sub_directories:             ; The drive is the main directory.
 move.w     #0, -(sp)            ; See Internals page 135 for other values.
 pea        (a6)                 ; Push address of next 'input_path' element.
 move.w     #$47, -(sp)          ; Function = d_getpath = get subdirectories.
 trap       #1                   ; Subdirectories of the active desktop window
 addq.l     #8, sp               ; are returned in the array 'input_path'.

find_path_end:                   ; Find Null at end of returned string.
 tst.b      (a6)+
 bne        find_path_end        ; Branch back till NULL is found.
add_extension:
 subq.l     #1, a6               ; Back up to overwrite the NULL.
 move.b     #$5C, (a6)+          ; Add '\'.
 move.b     #$2A, (a6)+          ; Add '*'.
 move.b     #$2E, (a6)+          ; Add '.'.
 move.b     #$2A, (a6)+          ; Add '*'.
 move.b     #0, (a6)             ; Add NULL.

display_file_selector:           ; COMPUTE!'s AES book page 282.
 lea        input_file, a3
 move.b     #0, (a3)             ; NULL for file selector line.
 lea        input_path, a4
 move.l     #file_select, aes_pb ; Pre-defined AES structure. 
 lea        addr_in, a1          ; Fetch address of array 'addr_in'.
 movea.l    a4, a6               ; Fetch address of array 'input_path'.
 move.l     a6, (a1)             ; Store address of 'input_path' in 'addr_in'.
 move.l     a3, 4(a1)            ; Store address of 'input_file' in 'addr_in'.
 bsr        aes

analyze_returns:                 ; Look at returns for File Selector box.
 tst.w      int_out + 2          ; CANCEL button => 0.
 beq        end_session          ; Go there if CANCEL was selected.
 tst.b      (a3)                 ; NO FILE CHOSEN => 0.
 beq        end_session          ; Go there if no file was chosen.

find_selected_path_end:          ; Search for first asterisk.
 cmp.b      #$2A, (a6)+         
 bne        find_selected_path_end
 subq.l     #1, a6               ; Back up to overwrite the asterisk.
add_filename_to_path:
 move.b     (a3)+, (a6)+
 bne.s      add_filename_to_path ; Now we have a true path.

set_dta:
 pea        dta                  ; dta = address of 44 byte buffer.
 move.w     #$1A, -(sp)          ; GEMDOS function = set dta.
 trap       #1
 addq.l     #6, sp

search_for_file: 
 move.w     #0, -(sp)            ; Attribute = normal access.
 pea        (a4)                 ; Push address of path.
 move.w     #$4E, -(sp)          ; GEMDOS function = search first.
 trap       #1
 addq.l     #8, sp
 tst        d0
 bne        file_not_found

open_file:                       ; Function returns file handle in D0.
 move.w     #0, -(a7)            ; Open as read only.
 pea        (a4)                 ; Push address of path.
 move.w     #$3D, -(a7)          ; See Internals page 127.
 trap       #1
 addq.l     #8, a7
 move.w     d0, d5               ; Store file handle in D5.

read_the_file:
 lea        input_file_addr, a3  
 move.l     #0, (a3)             ; Store NULL for malloc test.
get_file_size:
 lea        dta, a0
 move.l     $1A(a0), d7          ; Fetch file size.
 move.l     d7, d0
 addq.l     #1, d0               ; Add one to store a null at end of file.
get_input_buffer_space:          ; Get space from the system.
 move.l     d0, -(sp)            ; Push buffer size.
 move.w     #$48, -(sp)          ; Function = GEMDOS malloc.
 trap       #1
 addq       #6, sp
 tst.l      d0
 beq        input_malloc_failed
 move.l     d0, (a3)             ; Store input file address.
 move.l     d0, a3

read_file:
 move.l     d0, -(sp)            ; Push file's buffer address
 move.l     d7, -(sp)            ; Number of bytes to read.
 move.w     d5, -(sp)            ; File's handle number.
 move.w     #$3F, -(sp)          ; GEMDOS function = read.
 trap       #1
 lea        $C(sp), sp           ; Reposition stack pointer.

close_file:                      ; Actually, close the path.
 move.w     d5, -(sp)            ; Push file (path) handle.
 move.w     #$3E, -(sp)          ; See Internals page 128.
 trap       #1
 addq       #4, sp


 ; OTHER STUFF.


end_session:
 bsr        return_allocated_memory
 dc.w       $A009
 move.l     #close_workscreen, vdi_pb
 bsr        vdi
 move.l     #appl_exit, aes_pb
 bsr        aes

terminate:
 move.w     #0, -(sp)
 trap       #1

file_not_found:
 move.l     #file_not_found_text, addr_in
 bsr        alert
 bra.s      button_test

 ; MAJOR NOTE:

 ;     The mouse arrow will not appear when the "malloc failed" alert is
 ; displayed; therefore, only the "CANCEL" button can be used with the
 ; alert.

input_malloc_failed:
 move.l     #malloc_failed_text_1, addr_in
 bsr        alert             
 bra.s      end_session
 
button_test:
 cmp.w      #1, int_out          ; Button test.
 bne        end_session
 bra        display_file_selector
 
aes:
 move.l     #aes_pb, d1
 move.w     #$C8, d0
 trap       #2
 rts

vdi:
 move.l     #vdi_pb, d1
 move.w     #$73, d0
 trap       #2
 rts

clear_work_screen:
 dc.w       $A00A
 move.l     #clear_workscreen, vdi_pb
 bsr        vdi
home_cursor:                     ; Print ESC H.
 lea        esc_h, a0
 bsr        print_line
 dc.w       $A009
 rts

alert:
 bsr        clear_work_screen
 move.l     #form_alert, aes_pb
 move.w     #1, int_in           ; Default exit button to int_in[0].
 bsr        aes
 rts

return_allocated_memory:
 lea         input_file_addr, a3
 cmp.l       #0, (a3)
 beq.s       input_memory_block_not_allocated
return_input_memory_block:
 move.l      (a3), -(sp)         ; Push address of memory block.
 move.w      #$49, -(sp)         ; Function = GEMDOS m_free.
 trap        #1
 addq.l      #6, sp
 move.l      #0, (a3)            ; Store a NULL at input_file_addr.
input_memory_block_not_allocated:
 rts 

 data

file_not_found_text:
 dc.b '[2][ | |ERROR: File Not Found.][CONTINUE|CANCEL]',00

malloc_failed_text_1:
 dc.b '[1][ | |ERROR: Insufficient memory|       for input file.][CANCEL]',00

esc_h:           dc.b $1B,$48,0
message_1:       dc.b 'Select Input File.',$D,$A,0

 align

aes_pb:          dc.l  control,global,int_in,int_out,addr_in,addr_out
vdi_pb:          dc.l  control,int_in,pts_in,int_out,pts_out

 ; PREDEFINED 'CONTROL' STRUCTURES

appl_init:
 dc.w  10
 dc.w   0
 dc.w   1
 dc.w   0
 dc.w   0

appl_exit:
 dc.w  19
 dc.w   0
 dc.w   1
 dc.w   0
 dc.w   0

graf_handle:
 dc.w  77
 dc.w   0
 dc.w   5
 dc.w   0
 dc.w   0

open_workscreen:
 dc.w 100
 dc.w   0
 dc.w   0
 dc.w  11
 dc.w   0
 dc.w   0
 dc.w   0

clear_workscreen:
 dc.w   3
 dc.w   0
 dc.w   0
 dc.w   0
 dc.w   0
 dc.w   0
 dc.w   0

close_workscreen:
 dc.w 101
 dc.w   0
 dc.w   0
 dc.w   0
 dc.w   0
 dc.w   0
 dc.w   0

file_select:
 dc.w  90
 dc.w   0
 dc.w   2
 dc.w   2
 dc.w   0

form_alert:
 dc.w  52
 dc.w   1
 dc.w   1
 dc.w   1
 dc.w   0

evnt_multi:
 dc.w  25
 dc.w  16
 dc.w   7
 dc.w   1
 dc.w   0

 bss

 ;
 ; AES AND VDI ARRAYS
 ;

control:          ds.w    12     ; Control parameters.
global:           ds.w    15     ; Global parameters.
int_in:           ds.w   128     ; Input parameters.
int_out:          ds.w   128     ; Output parameters.
addr_in:          ds.w   128     ; Input addresses.
addr_out:         ds.w   128     ; Output addresses.
pts_in:           ds.w   128     ; Input points.
pts_out:          ds.w   128     ; Output points.

 ;
 ; FSEL_INPUT ARRAYS
 ;

input_file:       ds.b    14     ; Array for selected input file.
input_path:       ds.b   120     ; Array for drive name and subdirectories.
 
 ;
 ; APPLICATION VARIABLES
 ;

dta:              ds.l    11     ; 44 byte array.
input_file_addr:  ds.l     1
                  ds.l   300     ; Program stack.
stack:            ds.l     1     ; Address of program stack.
 end
