;-----------------------------------------------------------------------;
; FARREAD.ASM                                                           ;
;                                                                       ;
; This module contains functions that duplicate the library functions   ;
; _read() and _write(), except that these expect far pointers to the    ;
; file buffer.  Thus, when used with farmalloc(), the calling program   ;
; can set up large file buffers using the far heap, regardless of the   ;
; memory model being used.                                              ;
;                                                                       ;
; The len variable, indicating the buffer size, can be any int sized    ;
; value up to (but not including) 65,535.  65,535 is also used to       ;
; represent -1, which is used as the return value in case of error.     ;
; It is recommended that the buffer be a multiple of the sector size    ;
; (512 bytes in the current version of DOS), since reads and writes     ;
; are more efficient if they involve whole sectors.  A good value to    ;
; use is 65024 (decimal), since this is 1 sector (512 bytes) short      ;
; of a complete segment (64k).                                          ;
;-----------------------------------------------------------------------;
; Usage:                                                                ;
;                                                                       ;
; #include "fcopy.h"                                                    ;
;                                                                       ;
; Function prototypes:                                                  ;
;                                                                       ;
; int _farread (int handle, void far *buf, unsigned len)                ;
;                                                                       ;
;          Returns the number of bytes read;                            ;
;          on end-of-file, returns 0;                                   ;
;          on error returns -1 and sets both errno and _doserrno.       ;
;                                                                       ;
; int _farwrite (int handle, void far *buf, unsigned len)               ;
;                                                                       ;
;          Returns the number of bytes written;                         ;
;          on error returns -1 and sets both errno and _doserrno.       ;
;-----------------------------------------------------------------------;
; Revision history:                                                     ;
;                                                                       ;
;       1.0      5 JAN 92       Original.                               ;
;                                                                       ;
;                               Uses conditional assembly for all       ;
;                               memory models by defining _model.       ;
;                               Defaults to the small model if          ;
;                               _model is not defined.                  ;
;                                                                       ;
;                               Uses TASM 2.0 extensions, so this       ;
;                               source file will need modifications     ;
;                               to assemble under MASM 5.1 or 6.0.      ;
;-----------------------------------------------------------------------;
;   Copyright (c) 1992 Ray Waters                                       ;
;   All Rights Reserved                                                 ;
;-----------------------------------------------------------------------;

IFNDEF  _model                          ; if a _model directive was
	.MODEL	LARGE, C		; not defined, default to the
ELSE                                    ; SMALL model
%        .MODEL   _model, C             ; else, use the model indicated
ENDIF

        EXTRN   C errno:WORD            ; global error variable
        EXTRN   C _doserrno:WORD        ; global DOS error variable

        .CODE                           ; open code segment

        PUBLIC  _farread                ; make visible to Linker
;-----------------------------------------------------------------------;
; int _farread (int handle, void far *buf, unsigned len)                ;
;                                                                       ;
; Reads a file into a far buffer.                                       ;
;                                                                       ;
; Returns:  If successful, returns number of bytes read.  On            ;
;           end-of-file, returns 0.                                     ;
;                                                                       ;
;           If read failed, returns -1 and sets errno and _doserrno     ;
;           to one of the following:                                    ;
;                                                                       ;
;               EACCES  Permission denied                               ;
;               EBADF   Bad file number                                 ;
;-----------------------------------------------------------------------;
_farread        PROC    C

        ARG     handle:WORD, buf:FAR PTR BYTE, len:WORD

        push    ds                      ; save data segment
        mov     ah,3Fh                  ; DOS read file function
        mov     bx,[handle]             ; file handle
        mov     cx,[len]                ; number bytes to read
        lds     dx,[buf]                ; far pointer to buffer
        int     21h
        pop     ds                      ; restore data segment

        jc      @@read_error            ; jump on error, else...
        ret                             ; return to caller

@@read_error:

IF @DataSize EQ 2                       ; if HUGE memory model,
        push    ds                      ; save DS
        mov     bx,SEG errno            ; get segment address
        mov     ds,bx                   ;  of errno into DS
ENDIF
        mov     [errno],ax              ; set errno
        mov     [_doserrno],ax          ; set _doserrno
        mov     ax,-1                   ; return int value of -1

IF @DataSize EQ 2                       ; if HUGE memory model,
        pop     ds                      ; restore DS
ENDIF
        ret                             ; return to caller

_farread        ENDP

        PUBLIC  _farwrite               ; make visible to Linker
;-----------------------------------------------------------------------;
; int _farwrite (int handle, void far *buf, unsigned len)               ;
;                                                                       ;
; Writes to a file from a far buffer.                                   ;
;                                                                       ;
; Returns:  If successful, returns number of bytes written.             ;
;                                                                       ;
;           If write failed, returns -1 and sets errno amd _doserrno    ;
;           to one of the following:                                    ;
;                                                                       ;
;               EACCES  Permission denied                               ;
;               EBADF   Bad file number                                 ;
;                   -1  Target disk full                                ;
;-----------------------------------------------------------------------;
_farwrite       PROC    C

        ARG     handle:WORD, buf:FAR PTR BYTE, len:WORD

        push    ds                      ; save data segment
        mov     ah,40h                  ; DOS write file function
        mov     bx,[handle]             ; file handle
        mov     cx,[len]                ; number bytes to write
        lds     dx,[buf]                ; far pointer to buffer
        int     21h
        pop     ds                      ; restore data segment

        jc      @@write_error           ; jump on error

        cmp     ax,cx                   ; were all bytes written?
        jne     @@partial_write_error   ; if not, partial write error

        ret                             ; return to caller

@@partial_write_error:

IF @DataSize EQ 2                       ; if HUGE memory model,
        push    ds                      ; save DS
        mov     bx,SEG errno            ; get segment address
        mov     ds,bx                   ;  of errno into DS
ENDIF
        mov     ax,-1                   ; return int value of -1
        mov     [errno],ax              ; set errno to -1
        mov     [_doserrno],ax          ; set _doserrno to -1

IF @DataSize EQ 2                       ; if HUGE memory model,
        pop     ds                      ; restore DS
ENDIF
        ret                             ; return to caller

@@write_error:                          ; if write error,

IF @DataSize EQ 2                       ; if HUGE memory model,
        push    ds                      ; save DS
        mov     bx,SEG errno            ; get segment address
        mov     ds,bx                   ;  of errno into DS
ENDIF
        mov     [errno],ax              ; set errno
        mov     [_doserrno],ax          ; set _doserrno
        mov     ax,-1                   ; return int value of -1

IF @DataSize EQ 2                       ; if HUGE memory model,
        pop     ds                      ; restore DS
ENDIF
        ret                             ; return to caller

_farwrite       ENDP

        END
