Learn Macro Assembler in a Day
February 07, 2012 Tuesday

Section 6 - CODE EXAMPLE: PRINT FILE PROGRAM

INTRODUCTION

The following example is a simple program to read a file and print the contents to a standard printer. It gets the filename of the file to print from the DOS command prompt input line. The prompt input information is passed to the program in a buffer area of the Program Segment Prefix (PSP). The address of the Program Segment Prefix is passed to the program in the ES and DS registers when the program execution starts. This program checks the keyboard between every character printed for an escape key code to terminate execution of the program.

;This program prints a file defined on the command line
.MODEL small
;************* Stack Section *********************
.STACK 500
;************* Data Section **********************
.DATA
psp_seg             dw   0
no_cl_mess          db   "This routine requires that a "
                    db   "filename be on the command line for printing."
                    db   0dh,0ah,"Please try with a filename.",0dh,0ah,"$"
file_bad_open       db   "Bad file open",0dh,0ah,"$"
file_bad_read       db   "Bad file read",0dh,0ah,"$"
printer_bad_mess    db   "!! Printer Error !!!!",0dh,0ah,"$"
printing_mess       db   "A file is being printed,",0dh,0ah
                    db   "To stop printing, Press ESC key",0dh,0ah,"$"
filename            db   128 dup(0)
file_handle         dw   0
file_count          dw   0
file_pointer        dw   offset file_buffer
file_buffer         db   1024 dup(0)

.CODE
start     proc near

 ;DS and ES are indexing PSP area

    mov  al,[DS:80h]     ;load AL with size of data line
    mov  dx,@data        ;get segment address of data area
    mov  ds,dx           ;point DS to data area
    mov  psp_seg,ES      ;save PSP address
    cmp  al,1         ;?? data in DOS command line ??
    ja   get_PSP_filename  ;branch if data found

 ;if here, there is no data on command line
 ;display error message to user and terminate

    lea  dx,no_cl_mess

terminate_display:

 ;display message indexed by DX then terminate

    mov  ah,09
    int  21h     ;DOS Call

terminate_program:

 ;terminating the program
    mov  ah,4Ch    ;set AH for terminating function
    mov  al,00     ;set terminating code variable
    int  21h        ;call DOS to terminate

get_PSP_filename:

 ;move PSP filename to filename buffer in our data area
    mov  ax,ds
    mov  es,ax              ;point ES to data segment
    mov  ds,psp_seg
    mov  si,82h             ;SI source is PSP data area
    lea  di,filename
    cld                     ;make strings go forward
    get_PSP_data_1:
    lodsb                   ;load string data byte
                            ;check for end of filename
    cmp  al,21h
                            ;branch if end of string
    jb  got_PSP_filename
    stosb                   ;store string data byte
    jmp  get_PSP_data_1


got_PSP_filename:
    mov  al,0
    stosb                   ;make ASCIIZ string with zero end
    push es
    pop  ds                 ;reset data segment pointer

;try to open file
    mov  ah,3Dh
    lea  dx,filename
    mov  al,0               ;read access code
    int  21h                ;DOS Call
    jnc  file_open_ok
    lea  dx,file_bad_open
    jmp  terminate_display

file_open_ok:
 ;save file handle
    mov  file_handle,ax
    lea  dx,printing_mess   ;display start message
    mov  ah,09
    int  21h                ;DOS Call

file_read:
 ;read in block of file data
    mov  ah,3fh
    lea  dx,file_buffer
    mov  cx,1024
    mov  bx,file_handle
    int  21h                ;DOS Call
    jnc  file_read_ok       ;branch if good read
    
 ;else read file error occurred
 ;close file
    mov  ah,3eh
    mov  bx,file_handle
    int  21h
                            ;index exit error message
    lea  dx,file_bad_read
    jmp  terminate_display

file_read_ok:
 ;check to see if no more file data
    cmp  ax,0
    je   close_file         ;branch if no data left
                            ;else reset data block 
                            ;size and pointer
    mov  file_count,ax
    lea  bx,file_buffer
    mov  file_pointer,bx

print_data_block:
 ;main loop to print block of file data
 ;scan keyboard to check for any keys
    mov  ah,1
    int  16h
    jz   print_data_block_1   ;branch if no key
 ;get key code out of buffer 
    mov  ah,0
    int  16h                ;call BIOS keyboard
    cmp  al,01Bh            ;check key code
    je   close_file         ;branch if ESC

print_data_block_1:
    mov  si,file_pointer
    mov  al,[si]
    mov  ah,0
    mov  dx,0               ;select LPT1
    int  17h                ;BIOS Call
    test ah,25h
    jnz  printer_error
    inc  si
    mov  file_pointer,si
    dec  file_count
    jnz  print_data_block   ;loop if more data
                            ;else go read in next 
                            ;block of file data
    jmp  file_read

close_file:
    mov  ah,3eh
    mov  bx,file_handle
    int  21h    ;DOS Call
    jmp  terminate_program

printer_error:
 ;index exit error message
    lea  dx,printer_bad_mess
    jmp  terminate_display

start    endp                    ;end of start procedure
end      start                   ;define start as 
                                 ;beginning of program