(* Date: 02-05-95 From: DON PAULSEN This unit provides routines to manipulate individual bits in memory, including test, set, clear, and toggle. You may also count the number of bits set with NumFlagsSet, and get a "picture" of them with the function FlagString. All the routines are in the interface section to provide complete low-level control of your own data space used for flags. Usually the oFlags object will be most convenient. Just initialize the object with the number of flags required, and it will allocate sufficient memory on the heap and clear them to zero. *) UNIT DpFlags; {$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,R-,S-,V-,X-} {$IFDEF VER70} {$P-,Q-,T-,Y-} {$ENDIF} (* File(s) DPFLAGS.PAS Unit(s) None Compiler Turbo Pascal v6.0+ Author Don Paulsen v1.00 Date 7-01-92 Last Change 11-12-93 Version 1.11 *) { Flags are numbered from left to right (low memory to high memory), starting with 0, to a maximum of 65520. If the flags object isn't used, use the System.FillChar routine to set or clear all the flags at once. The memory for storing the flags can be allocated in the data segment or on the heap. Here are two methods for declaring an array for the flags (not needed if the oFlags object is used): CONST cMaxFlagNumber = 50; cNumberOfFlags = 51; VAR flags_A : array [0..(cMaxFlagNumber div 8)] of byte; flags_B : array [0..(cNumberOfFlags - 1) div 8] of byte; Note that since the first flag is flag 0, cNumberOfFlags is always 1 greater than cMaxFlagNumber. } INTERFACE PROCEDURE SetFlag (var flags; flagNum : word); PROCEDURE ClearFlag (var flags; flagNum : word); PROCEDURE ToggleFlag (var flags; flagNum : word); FUNCTION FlagIsSet (var flags; flagNum : word): boolean; FUNCTION NumFlagsSet (var flags; numFlags: word): word; FUNCTION FlagString (var flags; numFlags: word): string; TYPE tFlags = ^oFlags; oFlags = OBJECT CONSTRUCTOR Init (numberOfFlags: word); PROCEDURE ClearAllFlags; PROCEDURE SetAllFlags; PROCEDURE SetFlag (flagNum: word); PROCEDURE ClearFlag (flagNum: word); PROCEDURE ToggleFlag (flagNum: word); FUNCTION FlagIsSet (flagNum: word): boolean; FUNCTION NumFlagsSet : word; FUNCTION FlagString : string; DESTRUCTOR Done; PRIVATE flags : pointer; numFlags : word; END; IMPLEMENTATION {=======================================================} PROCEDURE SetFlag (var flags; flagNum: word); assembler; ASM les di, flags mov cx, flagNum mov bx, cx shr bx, 1 shr bx, 1 shr bx, 1 and cl, 7 mov al, 80h shr al, cl or es:[di][bx], al END; {=========================================================} PROCEDURE ClearFlag (var flags; flagNum: word); assembler; ASM les di, flags mov cx, flagNum mov bx, cx shr bx, 1 shr bx, 1 shr bx, 1 and cl, 7 mov al, 7Fh ror al, cl and es:[di][bx], al END; {==========================================================} PROCEDURE ToggleFlag (var flags; flagNum: word); assembler; ASM les di, flags mov cx, flagNum mov bx, cx shr bx, 1 shr bx, 1 shr bx, 1 and cl, 7 mov al, 80h shr al, cl xor es:[di][bx], al END; {=================================================================} FUNCTION FlagIsSet (var flags; flagNum: word): boolean; assembler; ASM les di, flags mov cx, flagNum mov bx, cx shr bx, 1 shr bx, 1 shr bx, 1 and cl, 7 inc cx mov al, es:[di][bx] rol al, cl and al, 1 @done: END; {=================================================================} FUNCTION NumFlagsSet (var flags; numFlags: word): word; assembler; ASM push ds cld lds si, flags xor bx, bx mov cx, numFlags mov dx, cx xor di, di shr cx, 1 shr cx, 1 shr cx, 1 jcxz @remainder @byte8: lodsb shl al, 1; adc bx, di shl al, 1; adc bx, di shl al, 1; adc bx, di shl al, 1; adc bx, di shl al, 1; adc bx, di shl al, 1; adc bx, di shl al, 1; adc bx, di shl al, 1; adc bx, di loop @byte8 @remainder: mov cx, dx and cx, 7 jz @done lodsb @bit: shl al, 1 adc bx, di loop @bit @done: mov ax, bx pop ds END; {==================================================================} FUNCTION FlagString (var flags; numFlags: word): string; assembler; { Returns a string of 0's & 1's showing the flags. Note that at most 255 flags can shown in a string. Returns nul if numFlags is 0 or greater than 255. } ASM push ds cld lds si, flags les di, @result mov cx, numflags or ch, ch jz @ok xor cx, cx @ok: mov al, cl stosb { length of string } jcxz @done mov dx, cx push dx { save number of flags } mov ah, '0' shr dl, 1 shr dl, 1 shr dl, 1 jz @remainder @byte8: { do 8 bits at a time } lodsb mov bl, al mov cl, 8 @bit8: mov al, ah { ah = '0' } shl bl, 1 adc al, dh { dh = 0 } stosb loop @bit8 dec dl jnz @byte8 @remainder: { do remaining (numFlags mod 8) bits } pop dx mov cx, dx and cl, 7 { 0 <= cx <= 7 (number of flags in partial byte) } jz @done lodsb { last byte containing flags } mov bl, al @bit: mov al, ah { ah = '0' } shl bl, 1 adc al, dh { dh = 0 } stosb loop @bit @done: pop ds END; {=============================================} CONSTRUCTOR oFlags.Init (numberOfFlags: word); BEGIN if numberOfFlags > 65520 then FAIL; numFlags:= numberOfFlags; GetMem (flags, (numFlags + 7) div 8); if flags = nil then FAIL; END; {==============================} PROCEDURE oFlags.ClearAllFlags; BEGIN FillChar (flags^, (numFlags + 7) div 8, #0); END; {============================} PROCEDURE oFlags.SetAllFlags; BEGIN FillChar (flags^, (numFlags + 7) div 8, #1); END; {========================================} PROCEDURE oFlags.SetFlag (flagNum: word); BEGIN DpFlags.SetFlag (flags^, flagNum); END; {==========================================} PROCEDURE oFlags.ClearFlag (flagNum: word); BEGIN DpFlags.ClearFlag (flags^, flagNum); END; {===========================================} PROCEDURE oFlags.ToggleFlag (flagNum: word); BEGIN DpFlags.ToggleFlag (flags^, flagNum); END; {==================================================} FUNCTION oFlags.FlagIsSet (flagNum: word): boolean; BEGIN FlagIsSet:= DpFlags.FlagIsSet (flags^, flagNum); END; {=================================} FUNCTION oFlags.NumFlagsSet: word; BEGIN NumFlagsSet:= DpFlags.NumFlagsSet (flags^, numFlags); END; {==================================} FUNCTION oFlags.FlagString: string; VAR w : word; BEGIN w:= numFlags; if w > 255 then w:= 255; FlagString:= DpFlags.FlagString (flags^, w); END; {======================} DESTRUCTOR oFlags.Done; BEGIN if flags <> nil then FreeMem (flags, (numFlags + 7) div 8); END; END. { Unit DpFlags }