How to Store Multiple "Flags" in One LONG

Hello Everyone,

For some reason I am drawing a blank on this. It’s something I haven’t had to deal with for a long time.

Scenario:

Say I have multiple possible “flags” stored as Equates. For example:

FlagOne			Equate(1)
FlagTwo			Equate(2)
FlagThree		Equate(3)
FlagFour		Equate(4)
FlagFive		Equate(5)
FlagSix			Equate(6)

I have a TPS table that has a LONG to store flag options. Value could be one or more of the flag equates. For example:

Record One
TpsLong = FlagOne

Record Two
TpsLong = FlagFour + FlagFive + FlagSix

Record Three
TpsLong = FlagTwo + FlagFour

Question:

When performing a loop through the records; How can I check if a record has one or more flags set?

I’ve tried several variations of Band(TpsLong,FlagOne) but I don’t think I’m doing that correctly.

Thank you!!!

Don

It’s easiest to think in hex for these bits.
Each individual bit is either 1, 2, 4, or 8.

MyBit0  EQUATE(01h)
MyBit1  EQUATE(02h)
MyBit2  EQUATE(04h)
MyBit3  EQUATE(08h)

then it moves to the next hex digit (nybble)

MyBit4 EQUATE(10h)
MyBit5 EQUATE(20h)
MyBit6 EQUATE(40h)
MyBit7 EQUATE(80h)

Then continue all the way to (80000000h)

Once you use the correct flags, this should work OK.
Your existing flags are not correct. e.g. Flag3 is the same as combining Flag1 and Flag2.

You might find my bit pairs class to be useful in seeing how to set/read bits.

1 Like

An interesting example of this in the Clarion language are the Font Style attributes are a bitmap stored in LONG that is used by FONT(), GETFONT(), SETFONT()

These are in Equates.CLW

FONT:Thin      EQUATE (100)
FONT:Regular   EQUATE (400)
! Semi Bold    EQUATE(600)  !From Win API
FONT:Bold      EQUATE (700)
! Extra Bold   EQUATE(800)  !From Win API
! Black        EQUATE(900)  !From Win API

FONT:Weight    EQUATE (07FFH)

FONT:Fixed     EQUATE (0800H)
FONT:Italic    EQUATE (01000H)
FONT:Underline EQUATE (02000H)
FONT:Strikeout EQUATE (04000H)

The tricky part here is the LONG is divided into 2 parts:

  1. Upper half Style a USHORT Bitmap
  2. Lower half Weight a USHORT Value

The Weight is Not a Bitmap it is a value from 100 to 999.
To get just the Weight use BAND(Style, FONT:Weight)

The Style Flags (Italic, Underline, etc) Are a Bitmap.
To get just those flags BAND(Style, BXOR(-1,FONT:Weight))
You can just check one flag easily e.g.
IF BAND(Style, FONT:Italic)FONT:Italic THEN DO Its _Italic.

To get into all the ways to work with bits there are plenty of websites. Clarion works the same as all other languages.

That works as long as the bitmask have no overlap. When working with Bits the proper and safe way is to BOR() them. Clarion BOR() is limited to 2 operands where most languages allow many. You can make your own BORmany(LONG,LONG,<LONG>,<LONG>,<LONG>,<LONG>...,<LONG>)

As other have pointed out, your flags cannot overlap. So this could instead be:

FlagOne			Equate(1)
FlagTwo			Equate(2)
FlagThree		Equate(4)
FlagFour		Equate(8)
FlagFive		Equate(16)
FlagSix			Equate(32)

or you could represent them in binary or hex.

now say you want to set on FlagFour:

TpsLong = bor(TpsLong, FlagFour)

and if you want to check if FlagFour is on:

if band(TpsLong, FlagFour) then do something.

hth

you can set on more than one flag at once, so instead of doing it in two statements like:

TpsLong = bor(TpsLong, FlagTwo)
TpsLong = bor(TpsLong, FlagFour)

you could simply say:

TpsLong = bor(TpsLong, FlagTwo+FlagFour)

The difference in doing that compared to

TpsLong = FlagTwo + FlagFour

is that using bor() will not upset/clear other existing flags that have already been set. I think this is probably why Carl said:

When working with Bits the proper and safe way is to BOR() them

(unless Carl doesn’t like adding them within the bor() ?)

1 Like

The most correct code is to not use Addition or Subtraction when doing Boolean.

Instead:
TpsLong = bor( bor(TpsLong, FlagTwo), FlagFour)

Or:
TpsLong = bor(TpsLong,FlagTwo)
TpsLong = bor(TpsLong,FlagFour)

2 Likes

I agree completely, but sometimes it’s just easier to add the stuff up.

Like with FILEDIALOG(), for example. Nobody ever BOR’s those switches (FILE:Save+FILE:KeepDir+FILE:LongName, etc).

3 Likes

Stumbled across an interesting video explaining bitwise operators:

I use the BitList control template from ClarionMag… It has great features
image

1 Like

Maybe you would find this useful for visualizing how bits are laid out in a hex digit. I guess I should have made it go right-to-left, but I kind of like it like this.

Counting in Hex

1 Like

I agree. Another good example of Bit Maps is the Message Button Equates. They also can be added:

BUTTON:OK               EQUATE (01H)
BUTTON:YES              EQUATE (02H)
BUTTON:NO               EQUATE (04H)
BUTTON:ABORT            EQUATE (08H)
BUTTON:RETRY            EQUATE (10H)
BUTTON:IGNORE           EQUATE (20H)
BUTTON:CANCEL           EQUATE (40H)
BUTTON:HELP             EQUATE (80H)

SVAPI.INC has many API examples.

1 Like

Basically, I think a good rule of thumb could be this:

  1. If you are modifying existing values, you should ONLY use the appropriate bitwise functions.
  2. If you trust that your bits won’t clash, and you are starting with no value (e.g., you are creating the mask value from scratch), and you don’t add the same equate twice, then it is OK (and even visually preferable) to add the values.

There could be more circumstances that might cause you to decide one way or the other.

IF we could use a “|” instead of “BOR()”, like in javascript, then BOR would be a lot more sexy than adding, but all of those parens get BORing.

e.g. Here is a link to a javascript example

Agree.

CW Utils should have a functions for And/Or/Xor that take more than 2. This should work…

BOrMany PROCEDURE(LONG pValue, LONG pMask, |
                  <LONG p3>,  <LONG p4>,  <LONG p5>,  <LONG p6>,  <LONG p7>,  <LONG p8>,  <LONG p9>,  |
                  <LONG p10>, <LONG p11>, <LONG p12>, <LONG p13>, <LONG p14>, <LONG p15>, <LONG p16>) !,LONG 
RV LONG,AUTO
    CODE
    RV=BOR(pValue,pMask)
    IF ~Omitted(p3) THEN RV=BOR(RV, p3).
    IF ~Omitted(p4) THEN RV=BOR(RV, p4).
    IF ~Omitted(p5) THEN RV=BOR(RV, p5).
    IF ~Omitted(p6) THEN RV=BOR(RV, p6).
    ...
    IF ~Omitted(p16) THEN RV=BOR(RV, p16).
    RETURN RV

:+1: I’ve also used BitList multiple times, it’s a simple but effective little class.

1 Like

that was thanks to Jeff Slarve - see this earlier message:

1 Like

Not sure, but maybe this helps:

GetBitInLong  PROCEDURE  (plBit,plLong)   ! plBit = 0 ... 31. RETURN: 0, 1, 2, 4, ... 256
slMask LONG
  CODE
  slMask = 1
  slMask = BSHIFT(slMask,plBit)
  RETURN BAND(slMask,plLong)
! ---
SetBitInLong   PROCEDURE  (plBit,plLong)   ! plBit = 0 ... 31
slMask LONG
  CODE
  slMask = 1
  slMask = BSHIFT(slMask,plBit)
  RETURN BOR(slMask,plLong)

ClarionMag was always an invaluable source of information!

1 Like

Looking at my ~20 year old code is pretty difficult . It could definitely use some re-working. I didn’t have iWindowComponent on my radar at that time, and there are numerous other things I would have done differently if written today.

1 Like

Hello Joei,

Thank you for sharing your code. Using the same concept, how would you clear a previously set BIT?

I have found an old suggestion from Bruce Johnson to use to “turn off” a BIT:

x = BAND(x,255-SomeBit)

GetBitInLong  PROCEDURE  (plBit,plLong)   ! plBit = 0 ... 31. RETURN: 0, 1, 2, 4, ... 256
slMask LONG
  CODE
  slMask = 1
  slMask = BSHIFT(slMask,plBit)
  RETURN BAND(slMask,plLong)

SetBitInLong   PROCEDURE  (plBit,plLong)   ! plBit = 0 ... 31
slMask LONG
  CODE
  slMask = 1
  slMask = BSHIFT(slMask,plBit)
  RETURN BOR(slMask,plLong)