                                                                     COMMENT ~
FILES.ASM -- File manipulation Procedures

   From `BLUEBOOK of ASSEMBLY ROUTINES for the IBM PC & XT'
         by Christopher L. Morgan
         Copyright (C) 1984 by The Waite Group, Inc.

   Contents:
   ---------
   CBUF_CLR     --  Clear the circular buffer
   CBUF_IN      --  Input to circular buffer
   CBUF_INIT    --  Initialize a circular buffer
   CBUF_OUT     --  Output to a circular buffer
   CBUF_PUT     --  Put a byte into a circular buffer
   CLOS_FIL     --  Close a file
   EMSG_OUT     --  Exception message output
   FILT_CR*     --  Filter for carriage return/linefeed
   MAKE_FIL     --  Create a file
   READ_FIL     --  Read bytes from a file
   SAVE         --  Save a file from communications line to disk
   WRIT_FIL     --  Write bytes to a file

    >>>>>  See FILES.DOC for complete descriptions of these routines. <<<<<
 ------------------------------------------------------------------------------
  It is better to put this data in the source code calling these routines, and
    then comment out this section.                                            ~
DATAS   SEGMENT PUBLIC
        CR      EQU     0DH                     ;ASCII code for carriage return
        LF      EQU     0AH                     ;ASCII code for linefeed
        CTRL_Z  EQU     1AH                     ;ASCII code for ^Z
        BLK_SIZ   =     0                       ;K=block size
        CBUF_SIZ        DW      256             ;K=CBUF max capacity
        CBUF            DB      1               ;K=base address of CBUF
        LBUF            DB      256 DUP('LBUF')
        NAME_BUF        DB      64 DUP('NAME')
;
;Following table used by EMSG_OUT
        EMSG    DW      EMSG1
                DW      EMSG2
                DW      EMSG3
                DW      EMSG4
                DW      EMSG5
                DW      EMSG6
                DW      EMSG7
                DW      EMSG8
                DW      EMSG9
                DW      EMSG10
                DW      EMSG11
                DW      EMSG12
                DW      EMSG13
                DW      EMSG14
                DW      EMSG15
                DW      EMSG16
                DW      EMSG17
                DW      EMSG18
        EMSG1   DB      CR,LF,'Invalid function number',CR,LF,0
        EMSG2   DB      CR,LF,'File not found',CR,LF,0
        EMSG3   DB      CR,LF,'Path not found',CR,LF,0
        EMSG4   DB      CR,LF,'Too many open files',CR,LF,0
        EMSG5   DB      CR,LF,'Access denied',CR,LF,0
        EMSG6   DB      CR,LF,'Invalid handle',CR,LF,0
        EMSG7   DB      CR,LF,'Memory control blocks destroyed',CR,LF,0
        EMSG8   DB      CR,LF,'Insufficient memory',CR,LF,0
        EMSG9   DB      CR,LF,'Invalid memory block address',CR,LF,0
        EMSG10  DB      CR,LF,'Invalid environment',CR,LF,0
        EMSG11  DB      CR,LF,'Invalid format',CR,LF,0
        EMSG12  DB      CR,LF,'Invalid access code',CR,LF,0
        EMSG13  DB      CR,LF,'Invalid data',CR,LF,0
        EMSG14  DB      CR,LF,'Message not in use',CR,LF,0
        EMSG15  DB      CR,LF,'Invalid drive was specified',CR,LF,0
        EMSG16  DB      CR,LF,'Attempted to remove the current directory',CR,LF,0
        EMSG17  DB      CR,LF,'Not same device',CR,LF,0
        EMSG18  DB      CR,LF,'No more files',CR,LF,0
DATAS   ENDS
;------------------------------------------------------------------------------
;It is better to include this data in the source code calling these routines,
;  and then comment out this section.
STACKS  SEGMENT STACK
        DB      20 DUP(' STACKS ')
STACKS  ENDS
;------------------------------------------------------------------------------
CODES   SEGMENT
;The following variables/constants must be defined in the source code calling
;  these routines. See FILES.DOC.

        EXTRN   COM_INCK:FAR,COM_INIT:FAR,COM_ON:FAR,COM_OFF:FAR,MSG_OUT:FAR
        EXTRN   DTA:DWORD,LAST:BYTE,GAUGE:WORD,NEARFULL:WORD,NEAREMPTY:BYTE

        PUBLIC  EMSG_OUT,GET_SPEC,MAKE_FIL,CLOS_FIL,WRIT_FIL,READ_FIL
        PUBLIC  CBUF_INIT,CBUF_PUT,CBUF_IN,CBUF_CLR,CBUF_OUT,SAVE

ASSUME CS:CODES,DS:DATAS
;----------------------------I/O ROUTINES--------------------------------------
;Routine to send out exception messages
EMSG_OUT        PROC    FAR
        PUSH    SI                              ;Save registers
        PUSH    AX
        ADD     AX,AX                           ;Double to index through table
        MOV     SI,AX                           ;SI points into table
        MOV     SI,EMSG[SI]                     ;Look up address of message
        CALL    MSG_OUT                         ;Send the message
        POP     AX                              ;Restore registers
        POP     SI
        RET
EMSG_OUT        ENDP
;------------------------------------------------------------------------------
;Routine to get a file specifier
;
GET_SPEC        PROC    FAR
        PUSH    DS                              ;Save registers
        PUSH    ES
        PUSH    SI
        PUSH    DI
        PUSH    CX
;
;Set up pointer to DTA  to get parameters
        LDS     SI,DTA                          ;Point to DTA for parameters
        MOV     CL,[SI]                         ;Get length of string
        MOV     CH,0                            ;Make 16-bit
        INC     SI                              ;Skip the length byte
        MOV     AL,' '                          ;Scan past the spaces
GET_SPEC1:
        CMP     [SI],AL                         ;Check for space
        JNE     GET_SPEC2                       ;Exit loop if nonspace
        INC     SI                              ;Else point to next byte
        LOOP    GET_SPEC1                       ;Loop back for more
        JCXZ    GET_SPEC3                       ;No file specifier?
;
;Move the rest into place
GET_SPEC2:
        MOV     DI,DX                           ;Index points to destination
        CLD                                     ;Forward direction
        REP     MOVSB                           ;Make the transfer
        CLC                                     ;No error, so no carry
        JMP     GET_SPEC_XIT                    ; and return
GET_SPEC3:
        MOV     AX,20                           ;No file specified
        STC                                     ;Set carry for error
        JMP     GET_SPEC_XIT                    ; and exit
GET_SPEC_XIT:
        POP     CX                              ;Restore registers
        POP     DI
        POP     SI
        POP     ES
        POP     DS
        RET
GET_SPEC        ENDP
;------------------------------------------------------------------------------
;Routine to create a file
;
MAKE_FIL        PROC    FAR
        PUSH    CX                              ;Save register
        MOV     CX,0                            ;Attribute 0
        INT     21H                             ;DOS call
        POP     CX                              ;Restore register
        RET
MAKE_FIL        ENDP
;------------------------------------------------------------------------------
;Routine to close a file
;
CLOS_FIL        PROC    FAR
        MOV     AH,3EH                          ;Close a file
        INT     21H                             ;DOS call
        RET
CLOS_FIL        ENDP
;------------------------------------------------------------------------------
;Routine to write bytes to a file
;
WRIT_FIL        PROC    FAR
        MOV     AH,40H                          ;Write to a file
        INT     21H                             ;DOS call
        CMP     AX,CX                           ;Was it all written?
        JE      WRIT_FIL_XIT                    ;Skip if yes
        MOV     AX,21                           ;Not all bytes were transferred
        STC                                     ;Set carry for error
WRIT_FIL_XIT:
        RET
WRIT_FIL        ENDP
;------------------------------------------------------------------------------
;Routine to read bytes from a file
;
READ_FIL        PROC    FAR
        MOV     AH,3FH                          ;Read from a file
        INT     21H                             ;DOS call
        CMP     AX,CX                           ;Everything back?
        JE      READFIL_XIT                     ;Skip if yes
        MOV     AX,22                           ;Not all read
        STC                                     ;Set carry for error
READFIL_XIT:
        RET
READ_FIL        ENDP
;------------------------------------------------------------------------------
;Routine to handle input for a circular buffer
;
CBUF_INIT       PROC    FAR
        MOV     SI,0                            ;Initialize SI
        MOV     DI,0                            ;Initialize DI
        MOV     GAUGE,0                         ; and # of bytes in buffer
        MOV     LAST,0                          ; and last byte buffer
        RET
CBUF_INIT       ENDP
;------------------------------------------------------------------------------
;Routine to one byte into a circular buffer
;
CBUF_PUT        PROC    FAR
        PUSH    DX                              ;Save register
        MOV     DX,GAUGE                        ;Put V Guage in DX
        MOV     CBUF[DI],AL                     ;Put the byte into the buffer
        INC     DI                              ;Adjust pointer to next char
        CMP     DI,CBUF_SIZ                     ;Wrap it around?
        JNE     CBUF_PUT1                       ;Skip if no wrap
        MOV     DI,0                            ;Wraps back to zero
CBUF_PUT1:
        INC     DX                              ;Count the character
        CMP     DX,NEARFULL                     ;Too many characters?
        JNE     CBUF_PUT_XIT                    ;Skip if not
        CALL    COM_OFF                         ;Request to stop flow
CBUF_PUT_XIT:
        POP     DX                              ;Restore register
        RET
CBUF_PUT        ENDP
;------------------------------------------------------------------------------
;Routine to handle input to a circular buffer
;
CBUF_IN PROC    FAR
        CALL    COM_INCK                        ;Check for a character
        JZ      CBUF_IN_XIT                     ;Good exit if none
        AND     AL,7FH                          ;Strip off parity bit
        CMP     AL,10                           ;Check for <LF> (ASCII 10)
        JNE     CBUF_IN1                        ;Skip if not <LF>
        CMP     LAST,13                         ;Check for <CR> (ASCI 13)
        JE      CBUF_IN2                        ;Skip if CR/LF
CBUF_IN1:
        CALL    CBUF_PUT                        ;Put byte into buffer
        MOV     LAST,AL                         ;Update last byte
CBUF_IN2:
        CMP     AL,13                           ;Check for <CR>
        JNE     CBUF_IN3                        ;Skip if not
;
;Insert LF if character was <CR>
        PUSH    AX                              ;Save the current character
        MOV     AL,10                           ;<LF>
        CALL    CBUF_PUT                        ; goes into buffer
        POP     AX                              ;Restore current character
;
;Check for end of file
CBUF_IN3:
        CMP     AL,CTRL_Z                       ;Check for ^-Z (1AH)
        JE      CBUF_IN5                        ;EOF is an exception
;
;Check for overflow
        PUSH    DX                              ;Save register
        MOV     DX,GAUGE
        CMP     DX,NEARFULL                     ;Overflow of characters?
        JL      CBUF_IN4                        ;Skip if not
        CALL    COM_OFF                         ;Stop flow request
        JMP     CBUF_IN_XIT                     ;Good exit
CBUF_IN4:                                       ;No overflow
        CALL    COM_ON                          ;Make sure flow is on
        JMP     CBUF_IN_XIT                     ;Good exit
CBUF_IN5:                                       ;EOF exception handling
        MOV     AX,19                           ;EOF exception code
        STC                                     ;Set carry for exception
        JMP     CBUF_IN_RET                     ;Return with exception
CBUF_IN_XIT:
        POP     DX
        CLC                                     ;Clear carry -- no exception
CBUF_IN_RET:
        RET
CBUF_IN ENDP
;------------------------------------------------------------------------------
;Routine to flush a circular buffer
;
CBUF_CLR        PROC    FAR
        PUSH    DI                              ;Save registers
        PUSH    DX
        PUSH    CX
;
;Get the bytes from the buffer
        MOV     CX,GAUGE                        ;Get the count
        JCXZ    CBUF_CLR_XIT                    ;Check for empty
        MOV     DI,0                            ;Initialize destination
;
;Loop to get all the bytes
CBUF_CLR1:
        MOV     AL,CBUF[SI]                     ;Get the character
        INC     SI                              ;Increment the pointer
        CMP     SI,CBUF_SIZ                     ;Wrap it?
        JNE     CBUF_CLR2                       ;Skip if no wrap
        MOV     SI,0                            ;Wrap the buffer pointer
CBUF_CLR2:
        MOV     LBUF[DI],AL                     ;Put the byte in linear buffer
        INC     DI
        LOOP    CBUF_CLR1                       ;Loop until all bytes in LBUF
;
;Send the linear buffer to the disk
        MOV     CX,GAUGE                        ;This is the number of bytes
        LEA     DX,LBUF                         ;Here is where they are
        CALL    WRIT_FIL                        ;Send them out
        MOV     GAUGE,0                         ;Set circular buffer empty
CBUF_CLR_XIT:
        POP     CX                              ;Restore registers
        POP     DX
        POP     DI
        RET
CBUF_CLR        ENDP
;------------------------------------------------------------------------------
;Routine to handle output from a circular buffer
;
CBUF_OUT        PROC    FAR
        CMP     GAUGE,BLK_SIZ                   ;Any characters?
        JL      CBUF_OUT_XIT                    ;If no, go
;
;Empty the buffer
        CALL    COM_OFF                         ;Hold the com line
        CALL    CBUF_CLR                        ;Clear the buffer
        JC      CBUF_OUT_RET                    ;Error?
CBUF_OUT_XIT:
        CLC                                     ;Clear carry -- no exception
CBUF_OUT_RET:
        RET
CBUF_OUT        ENDP
;------------------------------------------------------------------------------
;Routine to save a file from a communications line to disk
;
SAVE    PROC    FAR
;
;Set up return
        PUSH    DS                              ;Save for proper return
        MOV     AX,0                            ;Point to beginning of segment
        PUSH    AX                              ; for the offset
;
;Set up segments
        MOV     DX,DS                           ;PSP was data segment
        MOV     AX,DATAS                        ;New data segment
        MOV     DS,AX                           ;Put in DS
        MOV     ES,AX                           ; and in ES
        MOV     WORD PTR DTA+2,DX               ;Set the segment of the data
;
;Set up the file
        LEA     DX,NAME_BUF                     ;Point to the ASCIIZ buffer
        CALL    GET_SPEC                        ;Get file specifications
        JC      EXCEPTION                       ;Error?
        LEA     DX,NAME_BUF                     ;ASCIIZ buff had file specs
        CALL    MAKE_FIL                        ;Set up the file
        JC      EXCEPTION                       ;Error?
        MOV     BX,AX                           ;Get the file handle
;
;Set up the communications line
        MOV     DX,1                            ;For COM1:
        MOV     AL,0BBH                         ;2400,E,8,1
        CALL    COM_INIT                        ;Initialize it
        CALL    COM_ON                          ; & turn it on
        CALL    CBUF_INIT                       ;Initialize the circular buffer
        MOV     DX,1                            ;COM_2:
;
;Main loop for pulling in bytes
SAV_LOOP:
        CALL    CBUF_IN                         ;Check for input
        JC      EXCEPTION                       ;Error or EOF?
        CALL    CBUF_OUT                        ;Check to send it out
        JC      EXCEPTION                       ;Error?
        JMP     SAV_LOOP
EXCEPTION:                                      ;Error/Exception handler
        CMP     AX,19                           ;EOF?
        JE      SAV_1                           ;If so, close it up & return
        CALL    EMSG_OUT                        ;Else report exception
        JMP     SAV_XIT                         ; and return
SAV_1:                                          ;Normal return
        CALL    COM_OFF                         ;Com line off
        CALL    CBUF_CLR                        ;Clear the circular buffer
        JC      EXCEPTION                       ;Error?
        CALL    CLOS_FIL                        ;Close the file
        JC      EXCEPTION                       ;Error?
        JMP     SAV_XIT                         ;Exit
SAV_XIT:
        CALL    COM_ON                          ;Turn on com line
        RET
SAVE    ENDP
;------------------------------------------------------------------------------
CODES   ENDS
;
        END
;_____________________________________________________________________________
;>>>>> Physical EOF FILES.ASM <<<<<
