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