You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
474 lines
14 KiB
474 lines
14 KiB
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
|
|
|