474 lines
13 KiB
NASM
474 lines
13 KiB
NASM
TITLE lib - various C library routines
|
||
|
||
; Windows Write, Copyright 1985-1992 Microsoft Corporation
|
||
;=============================================================================
|
||
; This file contains various C library functions (and a few other
|
||
; functions) with the PL/M calling conventions. These routines
|
||
; may some day make their way into a real library of some kind, but
|
||
; until then, you'll just have to link this file in with the rest
|
||
; of your code.
|
||
;=============================================================================
|
||
|
||
?PLM = 1
|
||
?WIN = 1
|
||
|
||
;*** See note about cmacros2.inc in DOSLIB.ASM
|
||
include cmacros3.inc
|
||
|
||
;
|
||
;createSeg _MMP2, code, byte, public, CODE
|
||
;
|
||
|
||
sBegin CODE
|
||
; assumes CS,_MMP2
|
||
assumes CS,CODE
|
||
|
||
;------------------------------------------------------------------------------
|
||
; bltbyte (pbFrom, pbTo, cb) - a block transfer of bytes from pbFrom to
|
||
; pbTo. The size of the block is cb bytes. This bltbyte() handles the
|
||
; case of overlapping source and destination. bltbyte() returns a pointer
|
||
; to the end of the destination buffer (pbTo + cb). NOTE - use this
|
||
; bltbyte to transfer within the current DS only--use the bltbx for
|
||
; FAR blts.
|
||
;-----------------------------------------------------------------------------
|
||
|
||
cProc bltbyte, <FAR, PUBLIC>, <SI, DI>
|
||
parmDP <pbFrom, pbTo>
|
||
parmW <cb>
|
||
cBegin bltbyte
|
||
mov si,pbFrom ; get pointers and length of blt
|
||
mov di,pbTo
|
||
mov cx,cb
|
||
mov ax,di ; calculate return value
|
||
add ax,cx
|
||
push ds ; set up segment registers
|
||
pop es
|
||
cmp si,di ; reverse direction of the blt if
|
||
jae bltb1 ; necessary
|
||
add si,cx
|
||
add di,cx
|
||
dec si
|
||
dec di
|
||
std
|
||
bltb1:
|
||
rep movsb
|
||
cld
|
||
cEnd bltbyte
|
||
|
||
;-----------------------------------------------------------------------------
|
||
; bltbx (qbFrom, qbTo, cb) - same as bltbyte above except everything is
|
||
; handled as FAR pointers.
|
||
;-----------------------------------------------------------------------------
|
||
|
||
cProc bltbx, <FAR, PUBLIC>, <SI, DI, DS>
|
||
parmD <qbFrom, qbTo>
|
||
parmW <cb>
|
||
cBegin bltbx
|
||
les di,qbTo
|
||
lds si,qbFrom
|
||
mov cx,cb
|
||
mov ax,di
|
||
add ax,cx
|
||
cmp si,di
|
||
jae bltbx1
|
||
add si,cx
|
||
add di,cx
|
||
dec si
|
||
dec di
|
||
std
|
||
bltbx1:
|
||
rep movsb
|
||
cld
|
||
mov dx,es
|
||
cEnd bltbx
|
||
|
||
|
||
;------------------------------------------------------------------------------
|
||
; blt (pFrom, pTo, cw) - a block transfer of wFills from pFrom to pTo;
|
||
; The size of the block is cw wFills. This blt() handles the case of
|
||
; overlapping source and destination. blt() returns a pointer to the
|
||
; end of the destination buffer (pTo + cw). NOTE - use this blt() to
|
||
; to transfer within the current DS only--use the bltx for FAR blts.
|
||
;-----------------------------------------------------------------------------
|
||
|
||
cProc blt, <FAR, PUBLIC>, <SI, DI>
|
||
parmDP <pFrom, pTo>
|
||
parmW <cw>
|
||
cBegin blt
|
||
mov si,pFrom ; get pointers and length of blt
|
||
mov di,pTo
|
||
mov cx,cw
|
||
mov ax,di ; calculate return value
|
||
mov bx,cx
|
||
shl bx,1
|
||
add ax,bx
|
||
push ds ; set up segment registers
|
||
pop es
|
||
cmp si,di ; reverse direction of the blt if
|
||
jae blt1 ; necessary
|
||
dec bx
|
||
dec bx
|
||
add si,bx
|
||
add di,bx
|
||
std
|
||
blt1:
|
||
rep movsw
|
||
cld
|
||
cEnd blt
|
||
|
||
;-----------------------------------------------------------------------------
|
||
; bltx (qFrom, qTo, cw) - same as blt() above except everything is
|
||
; handled as FAR pointers.
|
||
;-----------------------------------------------------------------------------
|
||
|
||
cProc bltx, <FAR, PUBLIC>, <si, di, ds>
|
||
parmD <qFrom, qTo>
|
||
parmW <cw>
|
||
cBegin bltx
|
||
les di,qTo
|
||
lds si,qFrom
|
||
mov cx,cw
|
||
mov ax,di
|
||
mov bx,cx
|
||
shl bx,1
|
||
add ax,bx
|
||
cmp si,di
|
||
jae bltx1
|
||
dec bx
|
||
dec bx
|
||
add si,bx
|
||
add di,bx
|
||
std
|
||
bltx1:
|
||
rep movsw
|
||
cld
|
||
mov dx,es
|
||
cEnd bltx
|
||
|
||
;-----------------------------------------------------------------------------
|
||
; bltc (pTo, wFill, cw) - fills cw words of memory starting at pTo with wFill.
|
||
;-----------------------------------------------------------------------------
|
||
|
||
cProc bltc, <FAR, PUBLIC>, <DI>
|
||
parmDP <pTo>
|
||
parmW <wFill, cw>
|
||
cBegin bltc
|
||
mov ax,ds ; we are filling in the data segment
|
||
mov es,ax
|
||
mov di,pTo ; get the destination, constant, and count
|
||
mov ax,wFill
|
||
mov cx,cw
|
||
cld ; the operation is forward
|
||
rep stosw ; fill memory
|
||
cEnd bltc
|
||
|
||
;-----------------------------------------------------------------------------
|
||
; bltcx (qTo, wFill, cw) - fills cw words of memory starting at FAR location
|
||
; qTo with wFill.
|
||
;-----------------------------------------------------------------------------
|
||
|
||
cProc bltcx, <FAR, PUBLIC>, <DI>
|
||
parmD <qTo>
|
||
parmW <wFill, cw>
|
||
cBegin bltcx
|
||
les di,qTo ; get the destination, constant, and count
|
||
mov ax,wFill
|
||
mov cx,cw
|
||
cld ; the operation is forward
|
||
rep stosw ; fill memory
|
||
cEnd bltcx
|
||
|
||
;-----------------------------------------------------------------------------
|
||
; bltbc (pTo, bFill, cb) - fills cb bytes of memory starting at pTo with
|
||
; bFill.
|
||
;-----------------------------------------------------------------------------
|
||
|
||
cProc bltbc, <FAR, PUBLIC>, <DI>
|
||
parmDP <pTo>
|
||
parmB <bFill>
|
||
parmW <cb>
|
||
cBegin bltbc
|
||
mov ax,ds ; we are filling in the data segment
|
||
mov es,ax
|
||
mov di,pTo ; get the destination, constant, and count
|
||
mov al,bFill
|
||
mov cx,cb
|
||
cld ; the operation is forward
|
||
rep stosb ; fill memory
|
||
cEnd bltbc
|
||
|
||
;-----------------------------------------------------------------------------
|
||
; bltbcx (qTo, bFill, cb) - fills cb bytes of memory starting at FAR location
|
||
; qTo with bFill.
|
||
;-----------------------------------------------------------------------------
|
||
|
||
cProc bltbcx, <FAR, PUBLIC>, <DI>
|
||
parmD <qTo>
|
||
parmB <bFill>
|
||
parmW <cb>
|
||
cBegin bltbcx
|
||
les di,qTo ; get the destination, constant, and count
|
||
mov al,bFill
|
||
mov cx,cb
|
||
cld ; the operation is forward
|
||
rep stosb ; fill memory
|
||
cEnd bltbcx
|
||
|
||
|
||
|
||
;-----------------------------------------------------------------------------
|
||
; MultDiv(w, Numer, Denom) returns (w * Numer) / Denom rounded to the nearest
|
||
; integer. A check is made so that division by zero is not attempted.
|
||
;-----------------------------------------------------------------------------
|
||
|
||
cProc MultDiv, <FAR, PUBLIC>
|
||
parmW <w, Numer, Denom>
|
||
cBegin MultDiv
|
||
mov bx,Denom ; get the demoninator
|
||
mov cx,bx ; cx holds the final sign
|
||
or bx,bx ; ensure the denominator is positive
|
||
jns md1
|
||
neg bx
|
||
md1:
|
||
mov ax,w ; get the word we are multiplying
|
||
xor cx,ax ; make cx reflect any sign change
|
||
or ax,ax ; ensure this word is positive
|
||
jns md2
|
||
neg ax
|
||
md2:
|
||
mov dx,Numer ; get the numerator
|
||
xor cx,dx ; make cx reflect any sign change
|
||
or dx,dx ; ensure the numerator is positive
|
||
jns md3
|
||
neg dx
|
||
md3:
|
||
mul dx ; multiply
|
||
mov cl,bl ; get half of the demoninator to adjust for rounding
|
||
sar bx,1
|
||
add ax,bx ; adjust for possible rounding error
|
||
adc dx,0 ; this is really a long addition
|
||
sal bx,1 ; restore the demoninator
|
||
or bl,cl
|
||
cmp dx,bx ; check for overflow
|
||
jae md5
|
||
div bx ; divide
|
||
or ax,ax ; if sign is set, then overflow occured
|
||
js md5
|
||
or cx,cx ; put the sign on the result
|
||
jns md4
|
||
neg ax
|
||
md4:
|
||
|
||
cEnd MultDiv
|
||
|
||
md5:
|
||
mov ax,7FFFh ; return the largest integer
|
||
or cx,cx ; with the correct sign
|
||
jns md4
|
||
neg ax
|
||
jmp md4
|
||
|
||
;-----------------------------------------------------------------------------
|
||
; FSzSame (szOne, szTwo) - Compare strings, return 1=Same, 0=different
|
||
; Both strings in DS
|
||
;-----------------------------------------------------------------------------
|
||
|
||
cProc FSzSame, <FAR, PUBLIC>, <SI>
|
||
parmDP <szOne>
|
||
parmDP <szTwo>
|
||
cBegin FszSame
|
||
|
||
mov bx,szOne
|
||
mov si,szTwo
|
||
|
||
fszloop:
|
||
mov al,[bx]
|
||
cmp al,[si]
|
||
jnz notequal ; found inequality - return FALSE
|
||
inc bx
|
||
inc si
|
||
test al,al
|
||
jnz fszloop ; didn't reach a zero-terminator compare next char
|
||
|
||
mov ax,1
|
||
jmp fszend
|
||
notequal:
|
||
xor ax,ax
|
||
fszend:
|
||
|
||
cEnd FszSame
|
||
|
||
|
||
;-----------------------------------------------------------------------------
|
||
; CchDiffer (rgch1,rgch2,cch) - compare 2 strings, returning cch of
|
||
; shortest prefix leaving a common remainder
|
||
; implementation of the following C code
|
||
; note rather odd return values: 0 if =, # of unmatched chars +1 otherwise.
|
||
; note comparison is from end of string
|
||
;** int CchDiffer(rgch1, rgch2, cch)
|
||
;** register CHAR *rgch1, *rgch2;
|
||
;** int cch;
|
||
;** {{ /* Return cch of shortest prefix leaving a common remainder */
|
||
;** int ich;
|
||
|
||
;** for (ich = cch - 1; ich >= 0; ich--)
|
||
;** if (rgch1[ich] != rgch2[ich])
|
||
;** break;
|
||
;** return ich + 1;
|
||
;** }}
|
||
;-----------------------------------------------------------------------------
|
||
|
||
cProc CchDiffer, <FAR, PUBLIC>, <SI,DI>
|
||
parmDP <rgch1>
|
||
parmDP <rgch2>
|
||
parmW <cch>
|
||
cBegin CchDiffer
|
||
mov ax,ds ; set es=ds for string ops
|
||
mov es,ax
|
||
|
||
mov si,rgch1
|
||
mov di,rgch2
|
||
mov cx,cch ; loop count in cx
|
||
mov ax,cx ; compare from end of string down
|
||
dec ax
|
||
add si,ax
|
||
add di,ax
|
||
std
|
||
repz cmpsb ; compare strings
|
||
jz DiffRet ; return 0 if strings =
|
||
inc cx ; else increment return value
|
||
DiffRet:
|
||
mov ax,cx ; return # of unmatched chars
|
||
cld ; restore to be nice
|
||
cEnd CchDiffer
|
||
|
||
|
||
ifdef DEBUG
|
||
|
||
;-----------------------------------------------------------------------------
|
||
; toggleProf () - toggles winprof (windows profiler) profiling on or off.
|
||
; this calls to hard coded locations that both symdeb and winprof know
|
||
; about - see Lyle Kline for an actual explanation.
|
||
;-----------------------------------------------------------------------------
|
||
|
||
cProc toggleProf, <FAR, PUBLIC>
|
||
cBegin toggleProf
|
||
|
||
; ** the following strings are stored by the profiler starting at
|
||
; ** 100h of the loaded segment. This routine checks that the 1st
|
||
; ** 3 letters of each string are in the proper location to determine
|
||
; ** whether the profiler is already loaded.
|
||
|
||
; **** segname db "SEGDEBUG",0
|
||
; **** db "PROFILER",0
|
||
|
||
push es
|
||
push di
|
||
push si
|
||
xor ax,ax
|
||
mov es,ax
|
||
mov ax,es:[14] ;Get segment down there.
|
||
mov es,ax
|
||
mov di,0100h ;See if Profiler in memory.
|
||
|
||
cmp Byte Ptr es:[di],'S'
|
||
jnz $0001
|
||
|
||
cmp Byte Ptr es:[di+1],'E'
|
||
jnz $0001
|
||
|
||
cmp Byte Ptr es:[di+2],'G'
|
||
jnz $0001
|
||
|
||
cmp Byte Ptr es:[di+9],'P'
|
||
jnz $0001
|
||
|
||
cmp Byte Ptr es:[di+10],'R'
|
||
jnz $0001
|
||
|
||
mov ax,30 ;Type of call.
|
||
push ax
|
||
|
||
mov di,00FCh
|
||
call Dword Ptr es:[di] ; call to profiler toggle routine.
|
||
add sp,2 ; winprof uses normal c conventions
|
||
|
||
$0001:
|
||
pop si
|
||
pop di
|
||
pop es
|
||
|
||
cEnd toggleProf
|
||
|
||
endif
|
||
|
||
;-----------------------------------------------------------------------------
|
||
; void OsTime( pTime )
|
||
;
|
||
; pTime is a pointer to a structure of the form:
|
||
; struct {
|
||
; char min; Minutes (0-59)
|
||
; char hour; Hours (0-23)
|
||
; char hsec; Hundredths of seconds (0-99)
|
||
; char sec; Seconds (0-59)
|
||
;
|
||
; Get current time into structure
|
||
; DOS-specific
|
||
;-----------------------------------------------------------------------------
|
||
|
||
cProc OsTime, <FAR, PUBLIC>
|
||
parmDP <pTime>
|
||
cBegin OsTime
|
||
|
||
mov ah,2ch
|
||
int 21h
|
||
|
||
mov bx,pTime
|
||
mov WORD PTR [bx], cx
|
||
mov WORD PTR [bx+2], dx
|
||
|
||
cEnd OsTime
|
||
|
||
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
; Added by PaulT 3/23/89, borrowed from PC Word 5:
|
||
;
|
||
; IchIndexLp(lpsz, ch)
|
||
; char far *lpsz;
|
||
; int ch;
|
||
; Searches for ch in lpsz and returns the index (-1 if not found)
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
cProc IchIndexLp,<FAR, PUBLIC>
|
||
parmD lpsz
|
||
parmB chT
|
||
cBegin
|
||
mov dx, di ; Save di
|
||
les di, lpsz
|
||
mov ah, chT
|
||
xor al,al
|
||
mov bx, di ; Save initial pointer
|
||
; **** Can't access parms anymore
|
||
|
||
mov cx,-1
|
||
repnz scasb ; Must have '\0'
|
||
or ax, ax
|
||
jz LDoneILI
|
||
mov al, ah ; al = chT
|
||
not cx
|
||
dec cx
|
||
mov di, bx
|
||
repnz scasb
|
||
jz LDoneILI
|
||
mov di, bx
|
||
LDoneILI:
|
||
mov ax, di
|
||
sub ax, bx
|
||
dec ax ; ax = return value
|
||
mov di, dx ; Restore di
|
||
cEnd IchIndexLp
|
||
|
||
|
||
sEnd CODE
|
||
|
||
END
|
||
|