#IF 0 ---------------------------- PowerBASIC ---| DASoft |------------------------------------------ ---------------------------- Code DATE: 2002-04-12 | FILE NAME Bit_Scan.bas | by ---------------------------- Don Schullian, Jr. This code is released into the Public Domain ---------------------------------------------------------- No guarantee as to the viability, accuracy, or safety of use of this code is implied, warranted, or guaranteed ---------------------------------------------------------- Use at your own risk! ---------------------------------------------------------- CONTACT AUTHOR AT d83@DASoftVSS.com ------------------------------------------------------------------------- NOTE: As fBitScan compliments the BIT functions in PowerBASIC it would be advisable if you were to follow the same rules. PARAMETERS: Aptr = pointer/address to the array to be scanned Bytes = number of bytes to be scanned StartBit = bit to start scan TestVal = value to be tested for (1 or 0) RETURNS: -1 if no match was found The bit number of the next requested value USAGE: I used this function, among other things, to keep track of empty records in a file. If the record is used/active then the bit for that record number is ON (1) else it is off. When I add a record I scann the array to see which record number is empty. #ENDIF ' ' ' FUNCTION fBITscan ALIAS "fBITscan" ( BYVAL Aptr AS LONG, _ BYVAL Bytes AS LONG, _ BYVAL StartBit AS LONG, _ BYVAL TestVal AS LONG ) EXPORT AS LONG #REGISTER NONE ! push esi ; popped in Exet ! mov esi, Aptr ; array into ESI ! mov ecx, Bytes ; # of bytes into ECX ! mov eax, StartBit ; starting bit number ! mov ebx, TestVal ; load test value into ebx ! ; BL = SCAN MASK FOR BIT SEARCH ! cmp ebx, 0 ; if testing for OFF bit..... ! je L1 ; goto ! mov bl, 0 ; BL = 0 if testing for ON bit ! jmp L2 ; L1: ' ! mov bl, &hFF ; BL = 255 if testing for OFF bit L2: ' COMPUTE START BIT OFFSET & MASK ! cmp eax, 0 ; if start bit = 0 ..... ! je L6 ; goto ! ; COMPUTE FULL BYTES TO BE SKIPPED ! mov dl, al ; DL = will test odd bits ! shr eax, 3 ; EAX = full bytes from offset ! cmp eax, ecx ; if past end of array..... ! jge L8 ; goto ! sub ecx, eax ; reduce Bytes counter ! add esi, eax ; move pointer ! and dl, &b00000111 ; EDX = odd bits ! cmp dl, 0 ; if no odd bits..... ! je L6 ; goto ! lodsb ; load next byte ! cmp al, bl ; if byte has a winner.... ! jne L3 ; goto ! dec ecx ; lope off one more byte counter ! jecxz L8 ; if past end of array goto ! jmp L6 ; scan remaining bytes L3: ' ! push ecx ; >-------------------------------| ! mov cl, dl ; CL holds bit count to mask | ! mov dl, &b11111111 ; DL will become mask | ! cmp bl, 0 ; if search for ON bit | ! je L4 ; goto | ! mov ch, 8 ; | ! sub ch, cl ; | ! mov cl, ch ; CL = ( 8 - CL ) | ! shl dl, cl ; shift off left most bits | ! shr dl, cl ; move mask back into position | ! or al, dl ; set odd bits to ON for OFF test | ! jmp L5 ; send to pop & test | L4: ' | ! shr dl, cl ; shift off right most bits | ! shl dl, cl ; move mask back into position | ! and al, dl ; set odd bits to OFF for ON test | L5: ' | ! pop ecx ; <-------------------------------| ! jmp L7 ; goto ! ;;;;;;;;;;;;;;;;;;;;;;;;; L6: ' WHILE ECX > 0 ! lodsb ; load byte into AL L7: ' ! cmp al, bl ; if byte <> test mask .... ! jne L9 ; goto ! loop L6 ; WEND ! ;;;;;;;;;;;;;;;;;;;;;;;;; L8: ' BIT NOT FOUND ..... ! mov edx, -1 ; load negative return value ! jmp Exet ; goto ! ;;;;;;;;;;;;;;;;;;;;;;;;; L9: ' FINAL TEST ! mov edx, Bytes ; reload total bytes to be tested ! sub edx, ecx ; compute number of bytes tested ! shl edx, 3 ; multiply by 8 (bits) ! cmp bl, 0 ; if testing for ON bits ! je LB ; goto ! ;;;;;;;;;;;;;;;;;;;;;;;;; LA: ' TEST FOR OFF BIT WITHIN THE BYTE ! shr al, 1 ; shift off right most bit ! jnc Exet ; if the bit was ZERO goto ! inc edx ; bump bit position by one ! jmp LA ; loop ! ;;;;;;;;;;;;;;;;;;;;;;;;; LB: ' TEST FOR ON BIT WITHIN THE BYTE ! shr al, 1 ; shift off right most bit ! jc Exet ; if bit was ONE goto ! inc edx ; bump bit position by one ! jmp LB ; loop Exet: ' ! pop esi ; popped from 1sl line of code ! mov FUNCTION, edx ; RETURN value END FUNCTION ' '-------------------------------------------------------------------------- 'This function is thrown in to demonstrate how one can write more friendly 'functions that use fBitScan. '-------------------------------------------------------------------------- ' FUNCTION fBitScan_Long ( Arr() AS LONG, _ BYVAL StartBit AS LONG, _ BYVAL TestVal AS LONG ) AS LONG DIM L AS LOCAL LONG DIM Bytes AS LOCAL LONG L = LBOUND(Arr(1)) Bytes = 4 * (1 + UBOUND(Arr(1)) - L) FUNCTION = fBitScan(BYREF Arr(L), Bytes, StartBit, TestVal) END FUNCTION ' '-------------------------------------------------------------------------- 'Test Code for PBcc '-------------------------------------------------------------------------- ' FUNCTION WINMAIN( BYVAL hInstance AS LONG, _ BYVAL hPrevInst AS LONG, _ BYVAL lpszCmdLine AS ASCIIZ PTR, _ BYVAL nCmdShow AS LONG ) EXPORT AS LONG DIM bArr(19) AS LOCAL BYTE DIM iArr(19) AS LOCAL INTEGER DIM lArr(19) AS LOCAL LONG DIM xArr(19) AS LOCAL WORD DIM X AS LOCAL LONG RANDOMIZE TIMER ' ' BIT SET bArr(0), 30 ' X = fBitScan(BYREF bArr(0), 20, 0, 1) ' the answer will be 30 PRINT X ' ' BIT SET iArr(0), 50 ' X = fBitScan(BYREF iArr(0), 40, 10, 1) ' returns 50 but started PRINT X ' search at 10 ' BIT SET lArr(0), 100 ' X = fBitScan_Long(lArr(), 0, 1) ' returns 100 PRINT X ' ' X = fBitScan(BYREF xArr(0), 40, 0, 1) ' no bits set: returns -1 PRINT X ' PRINT ' ' FOR X = 1 TO 10 ' here we'll set 10 bits BIT SET xArr(0), RND(0,319) ' at random in the array NEXT ' ' X = -1 ' start with bit 0 DO ' find ON bits INCR X ' skip last found bit X = fBitScan(BYREF xArr(0), 40, X, 1) ' get next ON bit IF X = -1 THEN EXIT LOOP ' all done! PRINT FORMAT$(X, "000 "); ' print found bit number LOOP ' PRINT ' WAITKEY$ END FUNCTION