How to implement Bit Flags in VBScript - vbscript

Ok, two disclaimers,
I do not work in Vbscript but need to use it a little for an HMI project
I am looking at doing this because this application limits total "tags" or variables
So basically what I am trying to achieve is the following;
a unit8, foo, has the value 5 which is b00000101 now I would like to view this as 8 binary values a pseudocode way of doing this would be
IF foo AND b00000001 <> 0 THEN 'sudo read
.....
foo = foo OR b00000010 'sudo write 1
foo = foo AND b11111101 'sudo write 0
...ect
I think it will be something like
&foo AND &b00000001 <> 0
is this practical in VBScript again I am well aware this is not standard practice but in between tag limitations and HMI input limitations it might actually make the most sense in this application.

You could give something like this a try which uses Bitwise Operators to read and write the bitwise flags.
Function GetFlag(value, bit_num)
Dim bit_mask
If bit_num < 32 Then bit_mask = 2 ^ (bit_num - 1) Else bit_mask = "&H80000000"
GetFlag = CBool(value AND bit_mask)
End Function
Function SetFlag(value, bit_num, new_value)
Dim bit_mask
If bit_num < 32 Then bit_mask = 2 ^ (bit_num - 1) Else bit_mask = "&H80000000"
If new_value Then
SetFlag = value OR bit_mask
Else
bit_mask = NOT bit_mask
SetFlag = value AND bit_mask
End If
End Function
'Define constants to store the flags (maximum of 32)
Const FLAG_SUDOREAD = 1
Const FLAG_SUDOWRITEONE = 2
Const FLAG_SUDOWRITETWO = 3
'Set the flags
Dim options
options = SetFlag(options, FLAG_SUDOREAD, True)
options = SetFlag(options, FLAG_SUDOWRITEONE, False)
options = SetFlag(options, FLAG_SUDOWRITETWO, True)
'Read the flags
WScript.Echo "FLAG_SUDOREAD = " & GetFlag(options, FLAG_SUDOREAD)
WScript.Echo "FLAG_SUDOWRITEONE = " & GetFlag(options, FLAG_SUDOWRITEONE)
Output:
FLAG_SUDOREAD = True
FLAG_SUDOWRITEONE = False
Useful Links
Using Bitwise Operators In VB (Excellent resource for learning Bitwise operators and how to use them)

Related

Checking if a random number already exists VBscript

I have written code which generates a random number between 1-9.
I now want to add to this and generate a random number but generate a new number if that number has already been used before.
Sub main()
Dim max,min
max=9
min=1
Randomize
MsgBox(Int((max-min+1)*Rnd+min))
// Random number between 1-9 is generated
I had tried to implement a loop but i'm unsure of how it would work as i would need to keep the number generated in memory
If Int = random
Msgbox("Already in use")
End If
If Int = not random Then
Msgbox("Can be used")
End If
End Sub
Sounds like you just want to keep track of which random numbers have already been chosen. You could handle this any number of different ways (eg, with an array, hash-table/dictionary, numeric bit mask, etc.)
The solution I present below is similar to a numeric bit mask, but uses a string. Starting at all zeros (eg, "0000"), each indexable position in the string gets populated with a one (1) until the string becomes all ones (eg, "1111"). While potentially oversimplified -- since it assumes your min will always be one (1) -- it should get you started.
Dim min : min=1
Dim max : max=9
Dim result : result = ""
Dim r, s: s = String(max, "0")
Randomize
Do
r = Int((max-min+1)*Rnd+min)
If "0" = Mid(s, r, 1) Then
WScript.Echo "Can be used: " & r
result = result & ":" & r
s = Left(s, r-1) & "1" & Right(s, max-r)
Else
WScript.Echo "Already in use: " & r
End If
Loop Until String(max, "1") = s
WScript.Echo "Result" & result
Sample output:
Can be used: 4
Can be used: 5
Can be used: 9
Can be used: 3
Already in use: 3
Can be used: 1
Can be used: 8
Can be used: 6
Already in use: 6
Can be used: 7
Already in use: 8
Already in use: 4
Already in use: 3
Already in use: 1
Already in use: 6
Can be used: 2
Result:4:5:9:3:1:8:6:7:2
Hope this helps.

How do I extract numbers from a string in VB6?

I have a string that looks something like 'NS-BATHROOMS 04288'
I only want the numbers.
I hve searched for answers, but none so far even get pst the compiler.
How can I do this?
without regex you can do it with: (altough VB6/VBA Code really isn`t nice to look at)
Public Function ReturnNonAlpha(ByVal sString As String) As String
Dim i As Integer
For i = 1 To Len(sString)
If Mid(sString, i, 1) Like "[0-9]" Then
ReturnNonAlpha = ReturnNonAlpha + Mid(sString, i, 1)
End If
Next i
End Function
I'd personally use regex. You can match given regex patterns to achieve what you need. This function matches only digits.
For VB6 you'd do something like:
Dim myRegExp, ResultString
Set myRegExp = New RegExp
myRegExp.Global = True
myRegExp.Pattern = "[\d]"
Then you'd go against your String.
https://support.microsoft.com/en-us/kb/818802
You can use this function for extract numerical chr as string value:
Public Function Str_To_Int(MyString As Variant) As Long
Dim i As Integer
Dim X As Variant
If IsNull(MyString) Or MyString = "" Then
Str_To_Int = 0
Exit Function
End If
For i = 1 To Len(MyString)
If IsNumeric(Mid(MyString, i, 1)) = True Then
X = Nz(X, "") & Mid(MyString, i, 1)
End If
Next i
Str_To_Int = Nz(X, 0)
End Function

How to make a function with two strings as arguments

I'm not entirely sure what I'm doing wrong here. I have tested the code by input and output and it functions as desired no pun intended. :'P
I'm just not setting up this function correctly and I believe it's because my arguments happen to be desirably a string. Where if done correctly "CD" will be inserted into the middle of "ABEF". So, how do I go about doing this?
Thanks!
insertstr(ABEF, CD)
Function insertstr(string1, string2)
nostrmsg = "No string"
fullng = len(string1)
half = len(string1)/2
if half>0 then hfstr1 = mid(string1, 1, half)
str2lng = len(string2)
if str2lng>0 then paste = hfstr1+string2
lshalf = mid(string1, half+1, fullng)
if str2lng+half=str2lng+half then insert = paste+lshalf
End Function
Start with the knowledge that a functions returns a value, a tentative specification of what the function should do, and a basic testing skeleton:
Option Explicit
' returns the string build by inserting m(iddle) into f(ull) at half position
Function insertInto(f, m)
insertInto = "?"
End Function
Dim t, r
For Each t In Array( _
Array("ABEF", "CD", "ABCDEF") _
)
r = insertInto(t(0), t(1))
WScript.Echo t(0), t(1), r, CStr(r = t(2))
Next
output:
cscript 26873276.vbs
ABEF CD ? False
Then learn about Left, Mid, Len, and \ (integer division).
At last, re-write insertInto() so that the result starts with
cscript 26873276.vbs
ABEF CD ABCDEF True

Checking for TPM readiness with WMI and VBSCRIPT

If I am using this WMI method '.IsEnabled' should I be concerned with how I am handling the results in my if statement. If a method returns a bool value can I still use a Not or should I do something like
if myStatus <> 0 OR isTPMEnabled <> True then
Here is my code
function isTPMReadyToBeOwned(myTPMService)
dim myStatus, isTPMEnabled, isTPMActivated, isTPMOwnershipAllowed
myStatus = myTPMService.IsEnabled(isTPMEnabled)
if myStatus <> 0 or not(isTPMEnabled) then
oLogging.CreateEntry "TPM isn't enable and must be enabled and activated manually, errorcode " & Hex(myStatus), LogTypeWarning
isTPMReadyToBeOwned = False
exit Function
end If
myStatus = myTPMService.IsActivated(isTPMActivated)
If myStatus <> 0 or not(isTPMActivated) then
oLogging.CreateEntry "TPM isn't active and must be activated manually, errorcode " & Hex(myStatus), LogTypeWarning
isTPMReadyToBeOwned = False
exit Function
end If
myStatus = myTPMService.isOwnershipAllowed(isTPMOwnershipAllowed)
if myStatus <> 0 or not(isTPMOwnershipAllowed) then
oLogging.CreateEntry "TPM ownership is not allowed, errorcode " & Hex(myStatus), LogTypeWarning
isTPMReadyToBeOwned = False
exit Function
end If
isTPMReadyToBeOwned = True
end Function
Boolean expressions/variables shouldn't be compared to boolean literal, because it adds an extra level of complexity (operator and operand). So use Not isTPMEnabled. As Not is neither a function nor an array, don't use param list/index (); reserve () for cases of precedence override.
Update wrt comment:
() have (too) many functions in VBScript
parameter list () in function calls: x = f(y, z)
index (): a = SomeArray(4711)
precedence override: 2 + 3 * 4 = 14, (2 + 3) * 5 = 25
() in boolean expression should be of type 3 only.

Bracket finding algorithm lua?

I'm making a JSON parser and I am looking for an algorithm that can find all of the matching brackets ([]) and braces ({}) and put them into a table with the positions of the pair.
Examples of returned values:
table[x][firstPos][secondPos] = type
table[x] = {firstPos, secondPos, bracketType}
EDIT: Let parse() be the function that returns the bracket pairs. Let table be the value returned by the parse() function. Let codeString be the string containing the brackets that I want to detect. Let firstPos be the position of the first bracket in the Nth pair of brackets. Let secondPos be the position of the second bracket in the Nth pair of brackets. Let bracketType be the type of the bracket pair ("bracket" or "brace").
Example:
If you called:
table = parse(codeString)
table[N][firstPos][secondPos] would be equal to type.
Well, In plain Lua, you could do something like this, also taking into account nested brackets:
function bm(s)
local res ={}
if not s:match('%[') then
return s
end
for k in s:gmatch('%b[]') do
res[#res+1] = bm(k:sub(2,-2))
end
return res
end
Of course you can generalize this easy enough to braces, parentheses, whatever (do keep in mind the necessary escaping of [] in patterns , except behind the %b pattern).
If you're not restricted to plain Lua, you could use LPeg for more flexibility
If you are not looking for the contents of the brackets, but the locations, the recursive approach is harder to implement, since you should keep track of where you are. Easier is just walking through the string and match them while going:
function bm(s,i)
local res={}
res.par=res -- Root
local lev = 0
for loc=1,#s do
if s:sub(loc,loc) == '[' then
lev = lev+1
local t={par=res,start=loc,lev=lev} -- keep track of the parent
res[#res+1] = t -- Add to the parent
res = t -- make this the current working table
print('[',lev,loc)
elseif s:sub(loc,loc) == ']' then
lev = lev-1
if lev<0 then error('too many ]') end -- more closing than opening.
print(']',lev,loc)
res.stop=loc -- save bracket closing position
res = res.par -- revert to the parent.
end
end
return res
end
Now that you have all matched brackets, you can loop through the table, extracting all locations.
I figured out my own algorithm.
function string:findAll(query)
local firstSub = 1
local lastSub = #query
local result = {}
while lastSub <= #self do
if self:sub(firstSub, lastSub) == query then
result[#result + 1] = firstSub
end
firstSub = firstSub + 1
lastSub = lastSub + 1
end
return result
end
function string:findPair(openPos, openChar, closeChar)
local counter = 1
local closePos = openPos
while closePos <= #self do
closePos = closePos + 1
if self:sub(closePos, closePos) == openChar then
counter = counter + 1
elseif self:sub(closePos, closePos) == closeChar then
counter = counter - 1
end
if counter == 0 then
return closePos
end
end
return -1
end
function string:findBrackets(bracketType)
local openBracket = ""
local closeBracket = ""
local openBrackets = {}
local result = {}
if bracketType == "[]" then
openBracket = "["
closeBracket = "]"
elseif bracketType == "{}" then
openBracket = "{"
closeBracket = "}"
elseif bracketType == "()" then
openBracket = "("
closeBracket = ")"
elseif bracketType == "<>" then
openBracket = "<"
closeBracket = ">"
else
error("IllegalArgumentException: Invalid or unrecognized bracket type "..bracketType.."\nFunction: findBrackets()")
end
local openBrackets = self:findAll(openBracket)
if not openBrackets[1] then
return {}
end
for i, j in pairs(openBrackets) do
result[#result + 1] = {j, self:findPair(j, openBracket, closeBracket)}
end
return result
end
Will output:
5 14
6 13
7 12
8 11
9 10

Resources