📄 compare.asm
字号:
;/*
; * Microsoft Confidential
; * Copyright (C) Microsoft Corporation 1991
; * All Rights Reserved.
; */
; ZZZZZZ Are there bugs with offset calculations?? Is DGROUP the right
; assume for DS? I am unable to access variable DoQuickCompare from 'C'
; The offset is off by 64 bytes!!
?WIN = 0 ;Not windows;
?PLM = 1 ;DO use pl/m
include cmacros.inc
USA_CODE EQU 001
sBegin data
EXTRN gDescendingOrder: WORD
CollStruc struc
CollInfoId db ?
CollInfoPtr dd ?
CollStruc ends
CountryBuffer struc
Date_Format db 2 dup(?)
Currency_Symbol db 5 dup(?)
Thousands_Sep db 2 dup(?)
Decimal_Sep db 2 dup(?)
Date_Sep db 2 dup(?)
Time_Sep db 2 dup(?)
Currency_Pos db ?
Num_Decimals db ?
Time_Format db ?
Case_Mapping dd ?
Data_Sep db 2 dup(2)
Reserved db 10 dup(?)
;;;;size of structure must be at least 34 bytes!!
CountryBuffer ends
CollInfo CollStruc <>
EXTRN NationData: BYTE
DoQuickCompare db 0 ; Will be set to 1, if USA or
; no collating table avail.
PUBLIC DoQuickCompare
sEnd data
sBegin code
assumes cs, code
assumes ds, DGROUP
;;;; This function gets the International data into global NationData
;;;; Effects:
;;;; Fills in NationData global
;;;; DoQuickCompare set to 1, if country is USA, else unchanged.
;
; BOOL GetInternationalData(void)
;
cProc GetInternationalData, PUBLIC, <si,di,ds,es>
cBegin GetInternationalData
lea dx, NationData ; DS:DX points to NationBuffer
mov ax,3800h ; Get Current Country info
int 21h ; If success, Carry clear and BX = country code
mov ax,0 ;
cmc ;
rcl ax,1 ; value return to C-caller (1 on success, else 0)
;; Now set the DoQuickCompare field
cmp bx, USA_CODE ; Is current country USA?
jne GIDNotQuick
GIDQuick:
mov DoQuickCompare, 1 ; QuickCompare is possible
;;; DoQuickCompare remains 0 if country is not USA.
GIDNotQuick:
cEnd GetInternationalData
;;;; This function sets up the character collating table for sorting
;;;; Effects:
;;;; CollInfoId set to 6 if collating table is found, else 0.
;;;; CollInfoPtr points to collating table found.
;;;; DoQuickCompare set to 1, if no collating table avail, else unchanged.
;
; void SetCollatingTable(void)
;
cProc SetCollatingTable, PUBLIC, <si,di,ds,es>
cBegin SetCollatingTable
assumes ds, DGROUP
lea di, CollInfo
push ds
pop es ; ES:DI points to CollInfo buffer
mov ax, 6506h ; DOS function get extended country Info
; subfunc get pointer to collating sequence table
mov bx, -1 ; BX = code page of interest (active CON = -1)
mov cx, 5 ; CX = length of buffer to receive info
mov dx, bx ; DX = country ID (default = -1)
int 21h
jnc SCTRet ; Success, CollInfoId = 6 is set by DOS.
; The call failed. Set CollInfoInd = 0 to signal no collating table.
mov CollInfo.CollInfoId, 0
mov DoQuickCompare, 1 ; QuickCompare can be done as no coll table avail
SCTRet:
cEnd SetCollatingTable
; Invoked from a c-routine. Returns TRUE, if we can use a non-collating compare
; That is whether a straight ASCII compare can be done.
cProc FDoQuickCompare, PUBLIC, <si,di,ds,es>
cBegin FDoQuickCompare
assumes ds, DGROUP
xor ah, ah
mov al, DoQuickCompare
cEnd FDoQuickCompare
;;;; This function compares two strings using the collating table if avail.
;;;; ENTRY DS:SI = ptr to string1
;;;; ES:DI = ptr to string2
;;;; CX = length of string to be compared
;;;;
;;;; EXIT Depending on >, <, ==, the processor flags are set.
;;;; direction flag cleared.
;;;; destroys AX, BX, CX, DX, DI, SI
str_cmp proc
cld ; for lodsb, repe instructions to inc addresses
push bp ; preserve BP
mov bp, ds ; save string1's seg as we need DS for collating stuff
mov ax, DGROUP
mov ds, ax
assumes ds,DGROUP
lds bx, CollInfo.CollInfoPtr ; DS:BX = ptr to collating table
assumes ds,nothing
mov dx, ds:[bx] ; DX = collating table length
add bx, 2 ; DS:BX = ptr to collating values
dec dx ; dl holds length of table - 1
SC_nextchar:
mov al, es:[di] ; AL = AX = char from string2
inc di ; ES:DI = ptr to next char in string2
;;; BUGBUG -- maybe I should avoid these collating length compares in the loop?
cmp al,dl
ja @F ; in the table?
SC_xlat1:
xlat
@@:
mov ah, al ; store char in ah
push ds ; save DS
mov ds, bp ; DS = seg address of string1
lodsb ; AL = DS:[SI++] = char from string1
pop ds ; restore DS = seg of collating table
cmp al, dl ; compare char to length of collating table
ja @F
SC_xlat2:
xlat
@@:
cmp al, ah ; compare char from string1 with that from string2
ifdef DBCS
loope @f
jmp short SC_not_same ; if not same
@@:
mov al,es:[di-1]
call IsDBCSLeadByte
jnz SC_nextchar ; if this is not lead byte
mov ah,es:[di] ; get tail byte
inc di
push ds
mov ds,bp
lodsb
pop ds
cmp al,ah ; compare tail byte
loope SC_nextchar ; loop until unequal or no more left
SC_not_same:
else
loope SC_nextchar ; loop until unequal or no more left
endif
mov ds, bp ; DS = value on entry to this routine
pop bp ; restore BP
ret
str_cmp endp
;;;; This function compares the names of files for sorting using collating table
;;;; The extension is always at offset 8.
;;;; The short names/extensions are assumed to be padded by NULL/same chars.
;;;; If the names are the same, compare extensions also.
;;;; Returns -1 if one < two
;;;; 0 if equal
;;;; 1 if one > two
;
; int pascal name_cmp(char far* string_one,char far* string_two)
;
cProc name_cmp, PUBLIC, <si,di,ds,es>
parmW string_one_segment
parmW string_one_offset
parmW string_two_segment
parmW string_two_offset
cBegin name_cmp
mov di,string_two_offset
mov es,string_two_segment
mov si,string_one_offset
mov ds,string_one_segment
assumes ds,nothing
mov cx,8
call str_cmp ; sets the >, <, == flags
ja short nc_1_is_bigger
jne short nc_1_is_lesser; if we get here, one is <= two
;;; here we compare the extensions as names match
mov di,string_two_offset
add di,8 ; add 8 to get to extension
mov si,string_one_offset
add si,8 ; add 8 to get to extension
mov cx,3
call str_cmp ; sets the >, <, == flags
mov ax, 0 ; set ret status to mean equal strings
ja short nc_1_is_bigger
je short NameC_end
nc_1_is_lesser:
mov ax,-1
jmp short NameC_Toggle
nc_1_is_bigger:
mov ax,1
NameC_Toggle:
; Based on the sort order exchange the values -1 and 1. Note that the
; flag "gDescendingOrder" will have a value of FFFE or 0!
mov bx, DGROUP
mov ds, bx
assumes ds, DGROUP
xor ax, gDescendingOrder
NameC_end:
cEnd name_cmp
;;;; This function compares the names of files for sorting, with bias
;;;; on the extension name using collating table!!
;;;; The extension is always at offset 8.
;;;; Short names/extensions are assumed to be padded by NULL/same chars.
;;;; If the extensions are the same, compare names also.
;;;; The name is either null terminated or 8 characters long and begins
;;;; at offset 0.
;;;; Returns -1 if one < two
;;;; 0 if equal
;;;; 1 if one > two
;
; int pascal ext_cmp(char far* string_one,char far* string_two)
;
cProc ext_cmp, PUBLIC, <si,di,ds,es>
parmW string_one_segment
parmW string_one_offset
parmW string_two_segment
parmW string_two_offset
cBegin ext_cmp
mov di,string_two_offset
mov es,string_two_segment
add di,8 ; add 8 to get to extension
mov si,string_one_offset
mov ds,string_one_segment
assumes ds,nothing
add si,8 ; add 8 to get to extension
mov cx,3
call str_cmp ; sets the >, <, == flags
;;; ax is zero now
ja short ec_1_is_bigger
jne short ec_1_is_lesser
;;; extensions are the same -- so compare names.
mov di,string_two_offset
mov si,string_one_offset
mov cx,8
call str_cmp ; sets the >, <, == flags
mov ax, 0 ; set ret status to mean equal strings
ja short ec_1_is_bigger
;;; if we get here, one is <= two
je short ExtC_end
ec_1_is_lesser:
mov ax,-1
jmp short ExtC_Toggle
ec_1_is_bigger:
mov ax,1
ExtC_Toggle:
; Based on the sort order exchange the values -1 and 1. Note that the
; flag "gDescendingOrder" will have a value of FFFE or 0!
mov bx, DGROUP
mov ds, bx
assumes ds, DGROUP
xor ax, gDescendingOrder
ExtC_end:
cEnd ext_cmp
;;;; function similar to name_cmp but with direct ASCII values!!
cProc quick_name_cmp, PUBLIC, <si,di,ds,es>
parmW string_one_segment
parmW string_one_offset
parmW string_two_segment
parmW string_two_offset
cBegin quick_name_cmp
assumes ds, DGROUP
mov bx, gDescendingOrder ; store the ascending/descending order flag
; in 'bx'
cld
mov di,string_two_offset
mov es,string_two_segment
mov si,string_one_offset
mov ds,string_one_segment
assumes ds,nothing
mov cx, 11 ; size of name+extension
xor ax, ax ; mark return value as 0 - will be used later
repe cmpsb
;;; ax is zero now
je short QNameC_end
;;; if we get here, one is <> two!
ja short qnc_1_is_bigger
qnc_1_is_lesser:
dec ax ; ax = -1
dec ax ; ax = -2
; Flow thru now makes ax = -1 for return value
qnc_1_is_bigger:
inc ax
;;; Based on the Sort Order -- whether we want to sort by ascending
;;; order or descending order we want to return 1, 0, -1 instead of
;;; the respective values of -1, 0, 1 for less, equal and greater resp.
xor ax, bx ; xor with sort order flag to xchg -1 and 1.
QNameC_end:
cEnd quick_name_cmp
;;;; function similar to ext_cmp but with direct ASCII values!!
cProc quick_ext_cmp, PUBLIC, <si,di,ds,es>
parmW string_one_segment
parmW string_one_offset
parmW string_two_segment
parmW string_two_offset
cBegin quick_ext_cmp
assumes ds, DGROUP
mov bx, gDescendingOrder ; store the ascending/descending order flag
; in 'bx'
cld
mov di, string_two_offset
mov es, string_two_segment
;;; add 8 to get to extension
add di, 8
mov si, string_one_offset
mov ds, string_one_segment
assumes ds, nothing
;;; add 8 to get to extension
add si, 8
mov cx, 3
xor ax, ax ; mark return value as 0 - will be used later
repe cmpsb
ja short qec_1_is_bigger
jne short qec_1_is_lesser
;;; extensions are the same -- so compare names.
mov di, string_two_offset
mov si, string_one_offset
mov cx, 8
repe cmpsb
;;; ax is zero now
je short QExtC_end
;;; if we get here, string one is <> string two
ja short qec_1_is_bigger
qec_1_is_lesser:
dec ax ; ax = -1
dec ax ; ax = -2
; Flow thru now makes ax = -1 for return value
qec_1_is_bigger:
inc ax
;;; Based on the Sort Order -- whether we want to sort by ascending
;;; order or descending order we want to return 1, 0, -1 instead of
;;; the respective values of -1, 0, 1 for less, equal and greater resp.
xor ax, bx ; xor with sort order flag to xchg -1 and 1.
QExtC_end:
cEnd quick_ext_cmp
; THIS FUNCTION IS NOT USED
; int pascal strnzcmp(char far* string_one,char far* string_two, word)
;
;cProc strnzcmp, PUBLIC , <si,di,ds,es>
;parmW string_one_segment
;parmW string_one_offset
;parmW string_two_segment
;parmW string_two_offset
;parmW len
;cBegin strnzcmp
; mov es,string_two_segment
; mov di,string_two_offset
; cld
; xor ax,ax
; mov bx,len
; mov cx,bx
; repne scasb ;;; find length of string 2 but don't look for EOS beyond len
;
; sub bx,cx
; mov cx,bx
; sub di,bx
; mov ds,string_one_segment
; mov si,string_one_offset
; repe cmpsb
;
; ;;; ax is zero now
; ja short str_one_is_bigger
; ;;; if we get here, one is <= two
; je StrC_end
;
;str_one_is_lesser:
; mov ax,-1
; jmp short StrC_end
;
;str_one_is_bigger:
; mov ax,1
;
;StrC_end:
;cEnd strnzcmp
ifdef DBCS
;
; Test if the character is DBCS Lead Byte
;
; input: AL = character to check
; outpit: ZF = 1 if DBCS Lead Byte
;
DBCSLeadByteTable dd 0
IsDBCSLeadByte proc near
push ax
push si
push ds
lds si,cs:DBCSLeadByteTable
cmp word ptr cs:DBCSLeadByteTable+2,0
jnz idlb_check ; if table is already set
push ax
mov ax,6300h
int 21h ; get DBCS lead byte table
pop ax
mov word ptr cs:DBCSLeadByteTable,si
mov word ptr cs:DBCSLeadByteTable+2,ds
idlb_check:
cmp word ptr [si],0
jz idlb_not ; if end of table
cmp al,[si]
jb idlb_next ; if below low value
cmp al,[si+1]
jbe idlb_yes ; if below high value
idlb_next:
add si,2 ; do next
jmp short idlb_check
idlb_not:
or al,1 ; reset ZF
jmp short idlb_end
idlb_yes:
and al,0 ; set ZF
idlb_end:
pop ds
pop si
pop ax
ret
IsDBCSLeadByte endp
endif
sEnd code
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -