title   MSDOS V2.0  FIND

;--------------------------------------------------------------------;
; Revision History:                                                  ;
;                                                                    ;
;       V1.1    8/23/82         M.A.Ulloa                            ;
;                                                                    ;
;       V1.2    9/22/82         M.A.Ulloa                            ;
;                 Added the -c and -n options                        ;
;                                                                    ;
;               9/23/82         M.A.Ulloa                            ;
;                 Added DOS version number control                   ;
;                                                                    ;
;               10/07/82  Rev.2         M.A.Ulloa                    ;
;                 Changed quote for double quotes, and added         ;
;               file name printing                                   ;
;                                                                    ;
;               10/20/82  Rev.3         M.A.Ulloa                    ;
;                 Modified IBM name to FIND, and changed the text    ;
;               of some messages.                                    ;
;                                                                    ;
;               10/25/82  Rev.4         M.A.Ulloa                    ;
;                 Changed name to FIND and all messages to the       ;
;               IBM form.                                            ;
;                                                                    ;
;               10/27/82  Rev.5         M.A.Ulloa                    ;
;                 Made the correct exit on version check in case     ;
;               of a 1.x DOS.                                        ;
;                                                                    ;
;               11/4/82 Rev. 5          A.R. Reynolds                ;
;                  Messages moved to external module                 ;
;                                                                    ;
;               11/10/82  Rev. 6        M.A. Ulloa                   ;
;                 Corrected problem with line numbers, and a problem ;
;               with seeking for 0 chars.                            ;
;                                                                    ;
;               03/30/83  Rev. 7        M.A. Ulloa                   ;
;                 Added patch area for bug fixing.                   ;
;                                                                    ;
;               04/14/83  Rev. 8        M.A. Ulloa                   ;
;                 Made changes for Kanji characters. (uhg!)          ;
;                                                                    ;
;--------------------------------------------------------------------;

FALSE   equ     0
TRUE    equ     NOT FALSE

KANJI   equ     FALSE                   ;set to true is kanji vers.

;--------------------------------------------------------------------;
;       FIND program following the standart UNIX operation.          ;
;                                                                    ;
; FORMAT:                                                            ;
;       find {option} string {filename {filename} {...}}             ;
;                                                                    ;
; NOTES:                                                             ;
;       1) String arguments HAVE to be enclosed                      ;
;       in double quotes. (Two double quotes if a                    ;
;       doble quote is to be included). Only ONE                     ;
;       string argument is presently allowed.                        ;
;                                                                    ;
;       2) Options are available:                                    ;
;               v       All lines but those matching are considered  ;
;               c       Only print a count of matching lines         ;
;               n       Each line is preceded by its relative        ;
;                         line number in the file.                   ;
;                                                                    ;
;       - Options can be Upper or lower case.                        ;
;       - Format: The switch character followed by an options        ;
;       character. I.e.: In the IBM PC: /v                           ;
;                                                                    ;
;       3) The program returns:                                      ;
;               0 - OK, and some matches                             ;
;               2 - Some Error                                       ;
;                                                                    ;
;       4) The maximum line size is determined by                    ;
;       buffer size. Bigger lines will bomb the program.             ;
;                                                                    ;
;       5) If no file name is given then it will asssume             ;
;       the input is comming from the Standart Input. NO             ;
;       errors are reported when reading from Standart Input.        ;
;--------------------------------------------------------------------;

code    segment public
assume  cs:code,ss:code,ds:nothing,es:nothing


CR      equ     0dh                     ;A Carriage Return
LF      equ     0ah                     ;A Line Feed
quote_char equ  22h                     ;A double quote character


buffer_size equ 4096                    ;file buffer size
st_buf_size equ 128                     ;string arg. buffer size
fname_buf_size equ 64                   ;file name buffer size


;----- DOS EQUATES --------------------------------------------------;
std_in  equ     0                       ;STD input handle
std_out equ     1                       ;STD output handle
std_err equ     2                       ;STD error handle
dos_ent equ     21h                     ;DOS entry point

std_con_string_output equ 9
get_version equ 48
char_oper equ   55                      ;get configuration parameters
open    equ     61                      ;DOS std open code
close   equ     62                      ;DOS std close code
read    equ     63                      ;DOS std read code
write   equ     64                      ;DOS std write code
lseek   equ     66                      ;DOS file seek
exit    equ     76                      ;DOS process exit code


;----- Misc  Data -----------------------------------------------;
make    db      "***MAUlloa/Microsoft/V12***"
rev     db      "8"


colon   db      ": "
n1_buf  db      "["
n2_buf  db      8 dup(0)                ;buffer for number conversion



;----- OPTION FLAGS -------------------------------------------------;
; If a flag is set (0ffh) then the option has been selected, if
;reset (0) then it has been not. All options are reset initially.
; NOTE: the order of this table has to remain consistent with the
;options dispatch code. If any changes are made they have to
;correspond with the code.

opt_tbl:

v_flg   db      0
c_flg   db      0
n_flg   db      0
x_flg   db      0               ;not used
l_flg   db      0               ;not used


;----- LINE COUNTERS ------------------------------------------------;
mtch_cntr dw    0                       ;matched lines counter
line_cntr dw    0                       ;line counter


;----- MAIN ROUTINE -------------------------------------------------;
start:

;----- CHECK VERSION NUMBER -----------------------------------------;

        mov     ah,get_version
        int     21h
        cmp     al,2
        jge     vers_ok
        push    cs
        pop     ds
        mov     dx,offset bad_vers
        mov     ah,std_con_string_output
        int     21h
        push    es              ;bad vers, exit a la 1.x
        xor     ax,ax
        push    ax

badfart proc    far             ;(what a hack!!)
        ret
badfart endp

vers_ok:

        push    cs                      ;load ES to the right area,
        pop     es                      ; for use with DI register

assume  es:code

;--------------------------------------------------------------------;

        mov     si,81h                  ;Start addrss. of commad line buf.

        call    kill_bl                 ;Get rid of blanks
        or      bx,bx                   ;A CR found?
        jz      find_opt                ;no, first find the options
args_missing:
        mov     dx,offset errmsg1       ;empty command line, no args: error.
        mov     cl,cs:errlen1
        call    prt_err
        mov     al,2                    ;error code for exit
        jmp     done


;----- FIND THE OPTION IF ANY ---------------------------------------;
find_opt:
        mov     ah,char_oper            ;get the dos switch char.
        mov     al,0
        int     dos_ent                 ;switch char in DL
        push    dx
another_opt:
        lodsb                           ;get the first char of command line
        cmp     al,' '                  ;a blank?
        je      cont_scan
        cmp     al,CR                   ;a Carriage Return
        je      args_missing
        pop     dx                      ;get switch character
        cmp     al,dl                   ;is it the switch char?
        jne     find_str                ;no, no options: get the string
        push    dx                      ;save for another round

        lodsb                           ;get the option character
        cmp     al,' '                  ;a blank?
        je      cont_scan               ;yes, ignore and continue
        cmp     al,CR                   ;a CR?
        je      args_missing            ;yes, error...
        call    make_caps               ;Capitalize the character
        mov     bx,offset opt_tbl       ;pointer to option flag table

        cmp     al,'V'                  ;the v option?
        je      opt_v
        cmp     al,'C'                  ;the c option?
        je      opt_c
        cmp     al,'N'                  ;the n option?
        je      opt_n

        mov     cs:errmsg5_opt,al       ;save the option
        mov     dx,offset errmsg5       ;unknown option: error
        mov     cl,cs:errlen5
        call    prt_err
        mov     dx,offset crlf          ;print a CRLF
        mov     cx,2
        call    prt_err
        jmp     another_opt             ;process next option

opt_v:
        mov     di,0
        jmp     short opt_dispatch

opt_c:
        mov     di,1
        jmp     short opt_dispatch

opt_n:
        mov     di,2

opt_dispatch:
        mov     es:byte ptr[bx+di],0ffh ;set the corresponding flag
        jmp     another_opt             ;process the rest of the options

cont_scan:
        dec     si                      ;adjust SI
        call    kill_bl                 ;get rid of blanks
        or      bx,bx                   ;A CR found?
        jz      another_opt             ;no, test for other options
        jmp     args_missing            ;yes, error...


;----- FIND STRING ARGUMENT -----------------------------------------;
find_str:
        cmp     al,quote_char           ;string should start with a
        jnz     bad_str_err             ; quote character, if not: error.
        mov     di,offset st_buffer     ;String argument buffer addrss.
        xor     cx,cx                   ;Clear to keep string length.

move_str:
        lodsb
        cmp     al,CR                   ;if a CR is found in the string
        jnz     str_ok                  ; then it's a bad string
bad_str_err:
        mov     dx,offset errmsg2       ;bad string error message
        mov     cl,cs:errlen2
        call    prt_err                 ;print the error.
        mov     al,2
        jmp     done

str_ok:
        cmp     al,quote_char           ;look for a quote character
        jnz     move_char               ;not an apost., move to buffer
        lodsb                           ;an apost., check next char.
        cmp     al,quote_char           ;another quote character?
        je      move_char               ;yes, move it to the buffer
        dec     si                      ;no, adjust the pointer
        mov     es:st_length,cx         ;store the string length
        or      cx,cx                   ;Is the string empty?
        jnz     other_args              ;no: get the rest of the args.
        mov     al,1                    ;empty: no matches(!?)
        jmp     done
move_char:
        stosb                           ;put in buffer
        inc     cx                      ;increment string length
        jmp     move_str


;----- FIND THE FILE ARGUMENTS --------------------------------------;
other_args:                             ;Process the rest of the command
                                        ; line arguments.
        call    kill_bl                 ;get rid of leading blanks
        or      bx,bx                   ;At least one argument necessary,
        jz      further_args            ; if a CR not found: ok.

;----- USE STD IN FOR INPUT -----------------------------------------;
        push    cs
        pop     ds
        mov     ax,std_in               ;handle
        jmp     fill

further_args:
        call    clr_cntrs               ;set all counters to zero
        mov     di,offset file_name_buf ;Set pointer to the name buffer
        xor     cx,cx                   ;zero file name length
move_fname:
        lodsb
        cmp     al,' '                  ;A blank: end of file name,
        je      done_move
        cmp     al,CR                   ;A CR: idem.
        je      done_move
        stosb                           ;store in name buffer
        inc     cx                      ;increment file name length
        jmp     move_fname
done_move:
        dec     si                      ;Adjust pointer for next round.
        mov     es:byte ptr[di],00h     ;File names are null terminated
        push    si                      ;Save SI to continue com. line scan.
        push    ds                      ;Save DS register contents for
                                        ; later because it points to the
                                        ; rest of the arguments.
        mov     es:file_name_len,cx     ;save the name length

;----- OPEN FILE FOR READING ----------------------------------------;
        push    cs                      ;Load new DS with CS
        pop     ds
        mov     dx,offset file_name_buf ;addrss. of the file name
        mov     ah,open
        mov     al,0                    ;file open for reading
        int     dos_ent                 ;call the DOS
        jnc     say_name                ;if no carry then no errors
        jmp     open_error

;----- PRINT FILE NAME ----------------------------------------------;
say_name:
        push    ax                      ;save file handle
        mov     dx,offset heading
        mov     cl,cs:heading_len
        xor     ch,ch
        call    prout

        mov     dx,offset file_name_buf
        mov     cx,ds:file_name_len
        call    prout

        cmp     ds:c_flg,0ffh           ;count only flag set?
        je      xx1

        mov     dx,offset crlf
        mov     cx,2
        call    prout

xx1:
        pop     ax

;----- Fill Buffer for Matching -------------------------------------;
fill:
        mov     bx,ax                   ;retrieve handle
refill:
        mov     dx,offset buffer        ;data buffer addrss.
        mov     cx,buffer_size
        mov     ah,read
        int     dos_ent
        jnc     no_read_error           ;if carry then read error
        jmp     read_error
no_read_error:
        or      ax,ax                   ;if ax=0 then all done
        jnz     go_match
        cmp     ds:c_flg,0ffh           ;count only flag set?
        jne     sj2
        call    print_count
sj2:
        cmp     bx,std_in               ;Using STD IN?
        jnz     regular
        jmp     foo                     ;if so: all done, exit
regular:
        mov     ah,close                ;otherwise close the file
        int     dos_ent
        jmp     scan_rest               ;get another file

;----- MATCH ROUTINE ------------------------------------------------;
;Note: If input is being taken from a file the stack contains
; (from top to bottom):
;       - Pointer to the next command in the command line
;       - Pointer to the program segment prefix (to be loaded into
;         DS to access the command line.
; if the imput is from the standart input then NONE of it will be
; in the stack.

go_match:
        push    bx                      ;save the file handle
        mov     bp,offset buffer        ;ptr to first line of file
        mov     di,ax                   ;dispalcement from beg of buffer

        cmp     ax,buffer_size-1        ;last line of the file?
        jg      no_last_line            ;if yes, add a CRLF just in case
        mov     bx,bp
        cmp     byte ptr[bx+di-1],LF    ;finished with a LF?
        je      no_last_line            ;yes, it's an OK line.
        mov     byte ptr[bx+di],CR      ;put a CR at the end of the data
        inc     di
        mov     byte ptr[bx+di],LF      ;put a LF ...
        inc     di

no_last_line:
        push    di                      ;save the # of chars. in the buffer
        push    bp
        mov     dx,ds:st_length         ;length of the string arg.
        dec     dx                      ;adjust for later use
        jmp     short try_again


more_stuff_o:
        jmp     more_stuff



;----- SCAN LINES IN THE BUFFER FOR A MATCH -------------------------;
;Note: at this point the stack contains (from top to bottom):
;       - Stuff mentioned before
;       - File Handle
;       - Number of chars. left in the buffer from the next line.
;       - Addrs. of the next line in the buffer.
;
; plus, DX has the adjusted length of the string argument.

try_again:
        inc     ds:line_cntr            ;increment line counter
        pop     bp                      ;addrs. of next line in the buffer
        mov     di,bp                   ;points to beg. of a line
        pop     cx                      ;get # of chars left in the buffer
        mov     bx,cx                   ;save in case a non-complete line
        mov     al,LF                   ;search for a Line Feed
        jcxz    more_stuff_o            ;no chars left in buffer
        repnz   scasb
        jnz     more_stuff_o            ;no full line left in buffer

        push    cx                      ;save chars left in buffer
        push    di                      ;points to beg. of next line
        mov     cx,di
        sub     cx,bp                   ;length of the current line
        mov     bx,cx                   ;save in case it has a match
        dec     cx
        dec     cx                      ;CRLF characters discounted
        jcxz    try_again_opt           ;if line empty go to next line
        mov     di,bp                   ;pointer to the beg. of current line
another_char:
;
; On entry:
;       BX      line length
;       CX      adjusted line length
;       DX      adjusted string argument length
;       DI      points to beg. of line
;

IF      KANJI

        push    dx                      ;save for next line
lop:
        pop     dx
        push    dx
        inc     dx                      ;different algorithm!
        mov     si,offset st_buffer     ;pointer to beg. of string argument

comp_next_char:
        push    di
        mov     di,si
        call    is_prefix               ;check for a prefix char
        pop     di
        jnc     nopre
        lodsw
        cmp     cx,1                    ; Can not compare a two byte char
        jz      try_again_opt1          ; if there is only one available
        cmp     ax,word ptr [di]
        jz      kmatch1
        call    next_kchar              ;no match, advance di to next kanji
        jc      try_again_opt1          ;not enough chars left in line
        jmp     short lop               ;try another char in line

nopre:
        lodsb
        cmp     al,byte ptr [di]
        jz      kmatch
        call    next_kchar              ;no match, advance di to next kanji
        jc      try_again_opt1          ;not enough chars left in line
        jmp     short lop               ;try another char in line

try_again_opt1:
        pop     dx
        jmp     try_again_opt


kmatch1:
        dec     dx                      ;last char had prefix so it was
                                        ; long.
kmatch:
        dec     dx
        jz      a_matchk                ; no chars left: a match!
        call    next_kchar
        jc      try_again_opt1
        jmp     comp_next_char          ; loop if chars left in arg.

a_matchk:
        pop     dx

ELSE

        mov     si,offset st_buffer     ;pointer to beg. of string argument
        lodsb                           ;get first character of the str. arg.
        repnz   scasb                   ;search for a match in current line
        jnz     try_again_opt           ;no match, try the next line
        cmp     cx,dx                   ;compare lengths, a full match is not
        jb      try_again_opt           ; possible if CX < DX.
        push    di                      ;save addrs. of next char. in the line
        push    cx                      ;save the # of chars. left in the line
        mov     cx,dx                   ;get the adjusted string arg. length
        jcxz    a_match                 ;if a single char string, then match!
        repz    cmpsb                   ;compare string with line
        jz      a_match                 ;a match found, hurrah!
        pop     cx                      ;no match, get # of chars remaining
                                        ; in the line.
        pop     di                      ;position of the next char. in the line
        jmp     another_char


;----- A MATCH: CHECK FOR THE v OPTION ------------------------------;
a_match:
        pop     ax                      ;adjust stack
        pop     ax
ENDIF

        cmp     ds:v_flg,0ffh           ;is flag set?
        jne     prt_line                ;no, print the line
        jmp     try_again

;----- NO MATCH: CHECK FOR THE v OPTION -----------------------------;
try_again_opt:
        cmp     ds:v_flg,0ffh           ;is flag set?
        jne     try_again               ;no goto next line

;----- PRINT THE LINE WITH THE MATCH --------------------------------;
;Note: at this point the stack contains (top to bottom)
;       - Stuff mentioned before
;
; plus, BP points to begginig of the current line, BX has the length
;of the current line including the CRLF, and DX the adjusted length of
;the string argument.

prt_line:
        cmp     ds:c_flg,0ffh           ;is count only flag set?
        jne     no_c_flg
        inc     ds:mtch_cntr            ;yes, increment counter
        jmp     try_again

no_c_flg:
        push    dx                      ;save the adjusted string arg. length
        cmp     ds:n_flg,0ffh           ;is line number flag set?
        jne     no_n_flg
        call    prt_lcntr
no_n_flg:
        mov     dx,bp
        mov     cx,bx
        call    prout
        pop     dx                      ;restore
        jmp     try_again

;----- READ MORE TEXT LINES INTO THE BUFFER -------------------------;
; The scanning routines have detected that the buffer does not
;contain a full line any more. More lines have to be read into the
;buffer. But first perform a seek on the file in order to re-read
;the non-complete line into the begining of the buffer.
; Uppon entry BP contains points to the begining of the non-complete
;line, and BX has the number of characters left in the buffer.
; The Stack contains (top to bottom):
;       - Pointer to the next command in the command line
;       - Pointer to the program segment prefix (to be loaded into
;         DS to access the command line).
;       - File handle.

more_stuff:
        mov     dx,bx                   ;get chars left in buffer
        pop     bx                      ;get the handle
        or      dx,dx                   ;are there 0 left?
        jz      no_seek                 ;yes, do not seek
        neg     dx                      ;form two's complement
        mov     cx,-1
        mov     al,1                    ;seek from the current position
        mov     ah,lseek                ;seek on file
        int     dos_ent
        jc      read_error
no_seek:
        jmp     refill                  ;no errors: refill the buffer
read_error:
        cmp     bx,std_in               ;Using STD IN?
        je      foo                     ;if so: all done, exit
        mov     ah,close                ;close the file
        int     dos_ent
        mov     dx,offset errmsg4_pre   ;read error
        mov     cl,cs:errlen4_pre
        call    prt_file_name           ;print the file name in error
        mov     dx,offset errmsg4_post  ;read error
        mov     cl,cs:errlen4_post
        jmp     r_error

;----- PRINT ERRORS -------------------------------------------------;
open_error:
        mov     dx,offset errmsg3_pre    ;error in open operation
        mov     cl,cs:errlen3_pre
        call    prt_err_2               ;print error message
        call    prt_file_name           ;print the file name in error
        mov     dx,offset errmsg3_post  ;error in open operation
        mov     cl,cs:errlen3_post
r_error:
        call    prt_err_2               ;print error message

;----- SCAN THE REST OF THE COMMAND LINE ----------------------------;
scan_rest:
        pop     ds                      ;restore pointer to comm. line
        pop     si                      ;restore pointer to next comm.
        call    kill_bl                 ;look for further args.
        or      bx,bx                   ;test for a CR
        jnz     foo
        jmp     further_args
foo:
        mov     al,0                    ;Proper code
done:
        mov     ah,exit                 ;All done, exit with proper code.
        int     dos_ent


;--------------------------------------------------------------------;
;            Get rid of blanks in command line.                      ;
;    Advances the SI reg till the next non-blank character, if the   ;
; character is a CR (0dh) then returns with BX non-zero, otherwise   ;
; BX is zero.                                                        ;
;                                                                    ;
; entry:                                                             ;
;       SI      points to the first character on the line to scan.   ;
;                                                                    ;
; exit:                                                              ;
;       SI      points to the first non-blank character found.       ;
;       BX      contains 0D hex if the first non-blank found is      ;
;                a Carriage Return, otherwise it is 0.               ;
;                                                                    ;
; modifies:                                                          ;
;       BX, SI, and AX                                               ;
;                                                                    ;
;--------------------------------------------------------------------;
kill_bl:
        cld                             ;increment
        xor     bx,bx                   ;zero bx to start: no CR found
no_bl:
        lodsb                           ;get rid of blanks
        cmp     al,' '
        je      no_bl
        cmp     al,CR
        jnz     no_cr
        mov     bx,ax                   ;make bx non-zero (actually 0dh)
no_cr:
        dec     si                      ;adjust pointer
        ret


;--------------------------------------------------------------------;
;               Clear Counters                                       ;
;--------------------------------------------------------------------;
clr_cntrs:
        mov     byte ptr es:mtch_cntr,0
        mov     byte ptr es:line_cntr,0
        ret

;--------------------------------------------------------------------;
;               Print Count of Matched lines                         ;
;                                                                    ;
;               Modifies: AX,CX,DX and DI                            ;
;--------------------------------------------------------------------;
print_count:
        push    bx                      ;save handle
        cmp     bx,std_in               ;using std_in?
        jz      sj3                     ;if so do not print file name

        mov     dx,offset colon
        mov     cx,2
        call    prout                   ;print colon
sj3:
        mov     ax,ds:mtch_cntr
        mov     di,offset n2_buf        ;buffer for characters
        call    bin2asc                 ;convert to ascii
        mov     dx,offset n2_buf
        call    prout                   ;print the number
        mov     dx,offset crlf
        mov     cx,2
        call    prout                   ;print an end of line
        pop     bx
        ret


;--------------------------------------------------------------------;
;               Print relative line number                           ;
;                                                                    ;
;               Modifies: AX,CX and DI                               ;
;--------------------------------------------------------------------;
prt_lcntr:
        push    bx
        push    dx
        mov     ax,ds:line_cntr
        mov     di,offset n2_buf
        call    bin2asc
        mov     byte ptr[di],"]"
        inc     cx
        inc     cx
        mov     dx,offset n1_buf
        call    prout
        pop     dx
        pop     bx
        ret

;--------------------------------------------------------------------;
;               Print string to STD_OUT                              ;
;--------------------------------------------------------------------;
prout:
        mov     bx,std_out
        mov     ah,write
        int     dos_ent
        ret


;--------------------------------------------------------------------;
;       Binary to Ascii conversion routine                           ;
;                                                                    ;
; Entry:                                                             ;
;       AX      Binary number                                        ;
;       DI      Points to one past the last char in the              ;
;             result buffer.                                         ;
;                                                                    ;
; Exit:                                                              ;
;       Result in the buffer MSD first                               ;
;       CX      Digit count                                          ;
;                                                                    ;
; Modifies:                                                          ;
;       AX,BX,CX,DX and DI                                           ;
;                                                                    ;
;--------------------------------------------------------------------;
bin2asc:
        mov     bx,0ah
        xor     cx,cx
go_div:
        inc     cx
        cmp     ax,bx
        jb      div_done
        xor     dx,dx
        div     bx
        add     dl,'0'          ;convert to ASCII
        push    dx
        jmp     short go_div

div_done:
        add     al,'0'
        push    ax
        mov     bx,cx
deposit:
        pop     ax
        stosb
        loop    deposit
        mov     cx,bx
        ret


;--------------------------------------------------------------------;
;       Print the current file name                                  ;
;                                                                    ;
; modifies:                                                          ;
;       DX, CX, BX and AX                                            ;
;--------------------------------------------------------------------;
prt_file_name:
        mov     dx,offset file_name_buf ;print the file name
        mov     cx,ds:file_name_len     ;retrive file name length
        jmp     short prt_err_2


;--------------------------------------------------------------------;
;       Print an error message to the Standart error                 ;
;                                                                    ;
; entry:                                                             ;
;       DX      has the pointer to the message                       ;
;       CX      has the length of the message                        ;
;                                                                    ;
; modifies:                                                          ;
;        BX and AX                                                   ;
;--------------------------------------------------------------------;
prt_err:
        push    ds                      ;Save the current DS
        push    cs                      ;Make DS point to the right
        pop     ds                      ; place, for DOS use.
        call    prt_err_2
        pop     ds
        ret

prt_err_2:
        xor     ch,ch
        mov     bx,std_err
        mov     ah,write
        int     dos_ent                 ;write error message
        ret


;--------------------------------------------------------------------;
;       CAPIALIZES THE CHARACTER IN AL                               ;
;                                                                    ;
;       entry:                                                       ;
;               AL      has the character to Capitalize              ;
;                                                                    ;
;       exit:                                                        ;
;               AL      has the capitalized character                ;
;                                                                    ;
;       modifies:                                                    ;
;               AL                                                   ;
;--------------------------------------------------------------------;
make_caps:
        cmp     al,'a'
        jb      no_cap
        cmp     al,'z'
        jg      no_cap
        and     al,0dfh
no_cap:
        ret



IF      KANJI

;--------------------------------------------------------------------;
;       ADVANCE POINTER TO NEXT KANJI CHARACTER                      ;
;                                                                    ;
; entry:        DI  points to a Kanji string                         ;
;               CX  length in bytes of the string                    ;
;                                                                    ;
; exit:         DI  points to next Kanji char                        ;
;               CX  has number of bytes left                         ;
;                                                                    ;
; modifies:     AX                                                   ;
;                                                                    ;
;--------------------------------------------------------------------;
next_kchar:
        jcxz    no_kleft
        call    is_prefix
        jnc     no_p
        inc     di
        dec     cx
        jcxz    no_kleft                ; for insurance
no_p:
        inc     di
        dec     cx
        clc
        ret

no_kleft:
        stc
        ret


;--------------------------------------------------------------------;
;       FIND OUT IS THE BYTE IS A KANJI PREFIX                       ;
;                                                                    ;
; entry:  DI    points to a kanji string                             ;
;                                                                    ;
; exit:   Carry set if it is a kanji prefix                          ;
;                                                                    ;
; modifies:     AX                                                   ;
;                                                                    ;
;--------------------------------------------------------------------;
is_prefix:
        mov     al,byte ptr [di]
        cmp     al,81h
        jb      nok
        cmp     al,0a0h
        jb      isk
        cmp     al,0e0h
        jb      nok
        cmp     al,0fdh
        jb      isk
nok:
        clc
        ret
isk:
        stc
        ret

ENDIF


;----- PATCH AREA ---------------------------------------------------;

patch_area      dw      100h dup(?)



;----- BUFFER AREA --------------------------------------------------;
st_length dw    0                       ;String argumnet length
st_buffer db    st_buf_size dup(?)      ;String argument buffer

file_name_len dw 0                      ;File name length
file_name_buf db fname_buf_size+1 dup(?)  ;File name buffer,(allow for
                                        ; null at the end).

buffer  db      buffer_size+1 dup(?)    ;file buffer, the last byte is
                                        ;a guard in case of forced insertion
                                        ;of a CRLF pair.

;----- ERROR MESSAGES -----------------------------------------------;
        EXTRN   bad_vers:byte,crlf:byte,errmsg1:byte,errlen1:byte,errmsg2:byte
        EXTRN   errmsg3_pre:byte,errlen3_pre:byte
        EXTRN   errmsg3_post:byte,errlen3_post:byte
        EXTRN   errmsg4_pre:byte,errlen4_pre:byte
        EXTRN   errmsg4_post:byte,errlen4_post:byte
        EXTRN   heading:byte,heading_len:byte,errlen2:byte
        EXTRN   errmsg5:byte,errmsg5_opt:byte,errlen5:byte
code    ends


;----- STACK AREA ---------------------------------------------------;
stack   segment stack

        dw      64 dup(?,?)
stack_top equ   $

stack   ends

        end     start
�������������������������������������������������������������������������