;       SCCSID = @(#)kutila.asm	6.2 91/01/23
;       SCCSID = @(#)kutila.asm	6.2 91/01/23

.xlist
include dosseg.inc
include basemaca.inc
include osmaca.inc
include osconst.inc
include ostypes.inc
include mi.inc
.list

CpuMode 386


FARCODE HIGH32
HIGH32CODE segment

;***EP  _AllocBit - Allocate a bit from a dword bitmap
;
;       _AllocBit allocates a bit from a dword bitmap.
;
;       ENTRY   ab_pbm - bitmap pointer
;               ab_cbits - size of bitmap (in BITs)
;       EXIT    (EAX) = -1 on failure
;               (EAX) = 0-based bit number on success
;       USES    EAX, ECX, EDX, ES, Flags

Procedure _AllocBit,near
    assume ds:FLAT, es:FLAT, fs:nothing, gs:nothing, ss:nothing
    ArgVar alb_pbm,DWORD
    ArgVar alb_cbits,DWORD
        EnterProc
        push    edi
        push    esi
        push    ds                      ; (es) = (ds)
        pop     es
        mov     edi,[alb_pbm]           ; (edi) = pointer to bitmap
        mov     ecx,[alb_cbits]         ; (ecx) = size in bits
        add     ecx,31
        shr     ecx,5                   ; round up to size in dwords
        mov     eax,-1                  ; (eax) = pattern to skip
    repe scasd                          ; search for dword with any bit clear
        je      albe                    ; jmp if no bit is clear

        sub     edi,4                   ; point to subject dword
        mov     edx,[edi]               ; (edx) = grab bitmap dword
        mov     eax,1                   ; (eax) = 1-based bit number in dword
        mov     esi,eax                 ; (esi) = bit to test
alb00:  test    edx,esi                 ; test single bit
        jz      alb10                   ; jmp if bit clear
        shl     esi,1                   ; shift bit to test
        inc     eax                     ; inc bit number
        jmp     short alb00

;       Found a clear bit:
;
;       (eax) = 1-based bit number in dword
;       (ecx) = count of unexamined bitmap dwords
;       (edx) = bitmap dword with free bit
;       (esi) = bit mask
;       (edi) = pointer to bitmap dword with free bit

alb10:  or      edx,esi                 ; turn on bit (assume success)
        mov     ecx,edi
        sub     ecx,[alb_pbm]
        shl     ecx,3                   ; convert to bit count
        add     eax,ecx                 ; (eax) += number of bits before dword
        cmp     eax,[alb_cbits]         ; is the found bit valid?
        ja      albe                    ; jmp if out of range
        mov     [edi],edx               ; set the newly allocated bit
        dec     eax                     ; convert to 0-based
        jmp     short albx

albe:   mov     eax,-1                  ; indicate failure
albx:   pop     esi
        pop     edi
        LeaveProc
        RETC
EndProc _AllocBit


;**EP   _AllocBitGroup - Allocate a group of contiguous bits from a bitmap
;
;
;       ENTRY   ab_pbm - bitmap pointer
;               ab_cbits - size of bitmap (in BITs)
;               ab_cgrp  - size of group to find (in BITS)
;       EXIT    (EAX) = -1 on failure
;               (EAX) = 0-based bit number on success
;       USES    EAX, ECX, EDX, Flags


Procedure _AllocBitGroup,near
    assume ds:FLAT, es:FLAT, fs:nothing, gs:nothing, ss:nothing
    ArgVar abg_pbm,DWORD
    ArgVar abg_cbits,DWORD
    ArgVar abg_cgrp,DWORD
        EnterProc

        push    ebx
        push    edi
        push    esi

        mov     edi,[abg_pbm]           ; (edi) = pointer to bitmap
        mov     ecx,[abg_cbits]         ; (ecx) = size in bits
        mov     ebx,[abg_cgrp]          ; get number of bits in group
        add     ecx,31                  ;     do not disturb register ebx !!!
        shr     ecx,5                   ; round up to size in dwords
        mov     eax,-1                  ; (eax) = pattern to skip
abgagain:  jcxz abgy                    ; may have run out of grp bits
           repe scasd                   ; search for dword with any bit clear
        push    ecx                     ; save values if need to try again
        push    eax                     ; save values if need to try again
        push    edi                     ;
        je      abge                    ; jmp if no bit is clear

        sub     edi,4                   ; point to subject dword
        mov     edx,[edi]               ; (edx) = grab bitmap dword
        mov     eax,1                   ; (eax) = 1-based # of bits in group
        mov     ecx,ebx                 ; get number of bits in group
        mov     esi,eax                 ; get number of bits in group
        shl     esi, cl                 ; calculate mask for group
        dec     esi                     ; turn on bits not to match
abg00:  test    edx,esi                 ; test the bits
        jz      abg10                   ; jmp if bits are clear
        shl     esi, cl                 ; shift bits to test (into carry)
        jnc     abg01                   ; look for another double word
        pop     edi                     ; get back to where we left off
        pop     eax
        pop     ecx
        jmp     short abgagain

abg01:  add     eax, ebx                ; inc bit count
        jmp     short abg00

;       Found a clear bit:
;
;       (eax) = 1-based bit number in dword
;       (edx) = bitmap dword with free bit
;       (esi) = bit mask
;       (edi) = pointer to bitmap dword with free bit
;       (ebx) = number of bits in group

abg10:  or      edx,esi                 ; turn on bits (assume success)
        mov     ecx,edi
        sub     ecx,[abg_pbm]
        shl     ecx,3                   ; convert to bit count was 3
        add     eax,ecx                 ; (eax) += number of bits before dword
        add     ebx,eax                 ; ebx = last bit in the group
        cmp     ebx,[abg_cbits]         ; is the last bit valid?
        ja      abge                    ; jmp if out of range
        mov     [edi],edx               ; set the newly allocated bits
        dec     eax                     ; make zero based
        jmp     short abgx

abge:   mov     eax,-1                  ; indicate failure
abgx:   pop     edi                     ; clean up stack from saves
        pop     edi                     ; dont muck with eax
        pop     ecx                     ;

abgz:   pop     esi
        pop     edi
        pop     ebx
        LeaveProc
        RETC

abgy:   mov     eax,-1                  ; indicate failure
        jmp     short abgz              ; but dont clean stack from saves

EndProc _AllocBitGroup


;***EP  _FreeBit - Free a bit in a dword bitmap
;
;       _FreeBit frees a bit in a dword bitmap.
;
;       ENTRY   frb_pbm - bitmap pointer
;               frb_bitno - 0-based bit number
;       EXIT    NONE
;       USES    EAX, ECX, EDX, Flags

Procedure _FreeBit,near
    assume ds:FLAT, es:FLAT, fs:nothing, gs:nothing, ss:nothing
    ArgVar frb_pbm,DWORD
    ArgVar frb_bitno,DWORD
        EnterProc

        mov     ecx,[frb_bitno]         ; (ecx) = bit number
        mov     eax,ecx
        shr     eax,5                   ; (eax) = 0-based dword number
        shl     eax,2                   ; (eax) = 0-based byte offset
        add     eax,[frb_pbm]           ; (eax) += pointer to bitmap
        mov     edx,not 1               ; set all but bit 0
        rol     edx,cl                  ; rotate clear bit into position
        and     [eax],edx               ; clear specified bit

        LeaveProc
        RETC
EndProc _FreeBit


;***EP  _HighestBit - Return number of highest set bit in bitmap
;
;       _HighestBit returns the number of the highest set bit in
;       a bitmap.  Useful for determining how big your bitmap really
;       needs to be.
;
;       ENTRY   hib_pbm - bitmap pointer
;               hib_cbits - size of bitmap (in BITs)
;       EXIT    (EAX) = -1 if no bits set
;               (EAX) = 0-based bit number of highest set bit
;       USES    EAX, ECX, EDX, Flags

Procedure _HighestBit,near
    assume ds:FLAT, es:FLAT, fs:nothing, gs:nothing, ss:nothing
    ArgVar hib_pbm,DWORD
    ArgVar hib_cbits,DWORD
        EnterProc
        push    edi
        push    esi

        mov     edx,[hib_pbm]           ; (edx) = pointer to start of bitmap
        mov     ecx,[hib_cbits]         ; (ecx) = size in bits
        jecxz   hibe                    ; if bm is empty, quit now
        dec     ecx
        mov     edi,ecx
        shr     edi,3
        and     edi,(NOT 3)             ; (edi) = byte offset of dword
                                        ;         containing end of bitmap
        mov     edx,[edx+edi]           ; (edx) = last dword of bitmap
        mov     esi,-1
        shl     esi,cl                  ; cl implicitly masked by 0x1f
        shl     esi,1                   ; account for decrement above
        not     esi
        and     edx,esi                 ; (edx) : bits past end of bitmap
                                        ; have been set to zero
        bsr     esi,edx                 ; (esi) = index of last 1 bit in dword
        jz      hib20                   ; jump if last dword was all zeros
        mov     eax,ecx
        and     eax,(NOT 31)            ; (eax) = 0-index of last dword
        add     eax,esi                 ; (eax) = 1-index of last set bit
        jmp     hibx

;       Last dword in map is entirely clear
;
;       (edi) = byte offset of last dword in map
;       (ecx) = count of bits

hib20:  std                             ; we're going to scan downwards
        add     edi,[hib_pbm]           ; (edi) = addr of last dword
        sub     edi,4                   ; point at next-to-last dword
        shr     ecx,5                   ; (ecx) = # of dwords to scan
        jecxz   hibe                    ; jump if map is now empty
        xor     eax,eax
        repe scasd                      ; scan till we find a non-zero dword
        jz      hibe                    ; jump if we didn't find one
                                        ; rep scasd overshoots by a dword => +4
        bsr     eax,[edi+4]             ; (eax) = 0-index of bit in dword
        shl     ecx,5                   ; (ecx) = 0-index of start of dword
        add     eax,ecx                 ; (eax) = 0-index of bit in map
        jmp     short hibx

hibe:   mov     eax,-1                  ; indicate failure
hibx:   cld
        pop     esi
        pop     edi
        LeaveProc
        RETC
EndProc _HighestBit


;***EP  _strncmp - compare two strings.
;
;       _strncmp emulates the _strncmp C runtime library call.
;
;       See the C runtime library call documentation for _strncmp
;
;       The comparison proceeds up to the first terminating null
;       byte, but no more than cchMax bytes are compared.
;
;       _strncmp (char *pch1, char *pch2, char cchMax);
;
;       ENTRY
;               sz1             : string 1
;               sz1             : string 2
;               cchMax          : maximum number of bytes compared.
;
;       EXIT
;               Return Value < 0 :
;                       string 1 is less than string 2
;
;               Return Value == 0 :
;                       string 1 is equal to string 2, up to
;                       either the terminating null byte, or
;                       cchMax, whichever is reached first.
;
;               Return Value > 0 :
;                       string 1 is greater than string 2
;
;       USES            EAX, ECX, EDX, EFlags
;
;       PRESERVES       EBX, ESI, EDI, EBP, DS, ES, FS, GS

Procedure       _strncmp

        ASSUME  DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:TASKAREA

        ArgVar  sz1,DWORD               ; string 1
        ArgVar  sz2,DWORD               ; string 2
        ArgVar  cchMax,DWORD            ; Max string length

        EnterProc

        push    esi
        xor     eax,eax                 ; flush out EAX.
        mov     ecx,cchMax              ; (ECX) = length
        jcxz    scmp9                   ; return if zero length.

        mov     esi,sz1                 ; (ESI) = sz1
        mov     edx,sz2                 ; (EDX) = sz2

scmp1:  lodsb                           ; (AL) = *sz1;  sz1++;
        mov     ah,[edx]                ; (AH) = *sz2;
        inc     edx                     ; sz2++;

        or      al,al                   ; null terminator?
        jz      scmp8                   ; yes - compare last byte

        cmp     al,ah
        loope   scmp1                   ; repeat while equal strings

;       At this point, we have one of the following situations :
;       1) Reached a null byte in string 1.
;       2) Reached two unequal bytes.
;       3) Reached the maximum comparison length (implies equality)
;
;       The comparison of the strings now rests in (AL) and (AH).
;       We subtract the value of the last character from string 2 (AH)
;       from the value of the last character from string 1 (AL),
;       to get the comparison into (AL).   Sign extension completes
;       the return value in (EAX).

scmp8:  sub     al,ah
        movsx   eax,al
scmp9:  pop     esi
        LeaveProc
        RETC
EndProc _strncmp


;***EP  _xchg - atomic exchange of a dword memory location with a value
;
;       ENTRY:  x_pul - flat pointer to dword
;               x_val - dword value
;       EXIT:   eax = dword pointed to by x_pul
;       USES:   eax,edx
;
Procedure       _xchg,,,,esp
        ASSUME  DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:TASKAREA
        ArgVar  x_pul,dword
        ArgVar  x_val,dword

        mov     eax,[x_val]
        mov     edx,[x_pul]
        xchg    [edx],eax

        RETC
EndProc         _xchg

HIGH32CODE ends
        end
