NSIS split enviromental variable - environment-variables

I can read and use the env var with NSIS:
!define var "$%envvar%"
For example envvar contains some string "word anotherword thirdword" so I need to split it by this words and use it while compiling.
!if $"var1" == "word"
...some code
!else if $"var2" == "anotherword"
...some code
!endif
Can I do it with NSIS?

String handling in the pre-compiler is somewhat limited but this works:
!define var "word anotherword thirdword"
!searchparse /noerrors "IGNORED ${var}" ' ' var1 ' ' var2 ' ' var3
!warning "Debug: 1=${var1}"
!warning "Debug: 2=${var2}"
!warning "Debug: 3=${var3}"
!if "${var1}" == "word"
!else if "${var2}" == "anotherword"
!endif
Anything more advanced might require calling batch for with !system and outputting to a .nsh you can include.

Related

Checking if a String container any of a set of Symbols in Dart

I would like to check if a string contains any of the following symbols ^ $ * . [ ] { } ( ) ? - " ! # # % & / \ , > < ' : ; | _ ~ ` + =
I tried using the following
string.contains(RegExp(r'[^$*.[]{}()?-"!##%&/\,><:;_~`+=]'))
But that does not seem to do anything. I am also not able to add the ' symbol.
Questions:
How do I check if a string contains any one of a set of symbols?
How do I add the ' symbol in my regex collection?
When writing such a RegExp pattern, you should escape the special symbols (if you want to search specifically by them).
Also, to add the ' to the RegExp, there is no straightforward way, but you could use String concatenation to work around this.
This is what the final result could look like:
void main() {
final regExp = RegExp(
r'[\^$*.\[\]{}()?\-"!##%&/\,><:;_~`+=' // <-- Notice the escaped symbols
"'" // <-- ' is added to the expression
']'
);
final string1 = 'abc';
final string2 = 'abc[';
final string3 = "'";
print(string1.contains(regExp)); // false
print(string2.contains(regExp)); // true
print(string3.contains(regExp)); // true
}
To ad both ' an " to the same string literal, you can use a multiline (triple-quoted) string.
string.contains(RegExp(r'''[^$*.[\]{}()?\-"'!##%&/\\,><:;_~`+=]'''))
You also need to escape characters which have meaning inside a RegExp character class (], - and \ in particular).
Another approach is to create a set of character codes, and check if the string's characters are in that set:
var chars = r'''^$*.[]{}()?-"'!##%&/\,><:;_~`+=''';
var charSet = {...chars.codeUnits};
var containsSpecialChar = string.codeUnits.any(charSet.contains);

Lua: "attempt to concatenate global" Error in MPV

I am trying to write a little script to output filetags in mpv. My script looks like this:
require 'os'
require 'string'
function displayTrack()
currentTrack = mp.get_property("metadata/by-key/Title")
currentArtist = mp.get_property("metadata/by-key/Artist")
currentAlbum = mp.get_property("metadata/by-key/Album")
print(currentArtist)
print(currentAlbum)
print(currentTrack)
if currentTrack == nil then
os.execute("terminal-notifier -title '" .. currentArtist .. "' -message 'Unknown Title'")
else
os.execute("terminal-notifier -title '" .. currentArtist .. "' -message '" .. currentAlbum .. " - " .. currentTrack .. "'")
end
end
mp.observe_property("eof-reached", "bool", displayTrack)
Catching the tags and printing them works with every tested title. But if i want to uncomment the 5 lines starting with "if currentTrack == nil ..." so it also dislpays a native notification i get the LUA error:
/Users/marcel/.config/mpv/scripts/notification.lua:15: attempt to concatenate global 'currentArtist' (a nil value)
Can somebody tell me why i can print the string but not forward it to the os.execute?
It is not os.execute, it is concatenation - .. - that can't work with nil. And yes, you can print standalone nil just fine. In your case not only currentTrack is nil, but currentArtist too, so you can't build a string with it. Consider if you even need those entries where you don't have value for currentArtist and either skip them, provide alternative if branch to do something else or provide some default in concatenation. Usual idiom is (currentArtist or '') - here your default will be empty string.
if currentTrack == nil then
os.execute("terminal-notifier -title '" .. currentArtist .. "' -message 'Unknown Title'")
If this branch gets executed, currentTrack is nil, thus the concatenation fails as stated by the error message.
Just get rid of the concatenation all together:
if currentTrack == nil then
os.execute("terminal-notifier -title -message 'Unknown Title'")

Lua - util_server.lua:440 attempt to index local 'self' (a nil value)

Good evening
Will you help me solve this problem?
ERROR: race/util_server.lua:440: attempt to index local 'self' (a nil value)
function string:split(separator)
if separator == '.' then
separator = '%.'
end
local result = {}
for part in self:gmatch('(.-)' .. separator) do
result[#result+1] = part
end
result[#result+1] = self:match('.*' .. separator .. '(.*)$') or self
return result
end
You're probably calling it wrong.
function string:split(separator)
Is short hand for:
function string.split(self, separator)
Given a string and separator:
s = 'This is a test'
separator = ' '
You need to call it like this:
string.split(s, separator)
Or:
s:split(separator)
If you call it like this:
s.split(separator)
You're failing to provide a value for the self argument.
Side note, you can write split more simply like this:
function string:split(separators)
local result = {}
for part in self:gmatch('[^'..separators..']+') do
result[#result + 1] = part
end
return result
end
This has the disadvantage that you can't used multi-character strings as delimiters, but the advantage that you can specify more than one delimiter. For instance, you could strip all the punctuation from a sentence and grab just the words:
s = 'This is an example: homemade, freshly-baked pies are delicious!'
for _,word in pairs(s:split(' :.,!-')) do
print(word)
end
Output:
This
is
an
example
homemade
freshly
baked
pies
are
delicious

How do I parse a string at compile time in Nimrod?

Going through the second part of Nimrod's tutorial I've reached the part were macros are explained. The documentation says they run at compile time, so I thought I could do some parsing of strings to create myself a domain specific language. However, there are no examples of how to do this, the debug macro example doesn't display how one deals with a string parameter.
I want to convert code like:
instantiate("""
height,f,132.4
weight,f,75.0
age,i,25
""")
…into something which by hand I would write like:
var height: float = 132.4
var weight: float = 75.0
var age: int = 25
Obviously this example is not very useful, but I want to look at something simple (multiline/comma splitting, then transformation) which could help me implement something more complex.
My issue here is how does the macro obtain the input string, parse it (at compile time!), and what kind of code can run at compile time (is it just a subset of a languaje? can I use macros/code from other imported modules)?
EDIT: Based on the answer here's a possible code solution to the question:
import macros, strutils
# Helper proc, macro inline lambdas don't seem to compile.
proc cleaner(x: var string) = x = x.strip()
macro declare(s: string): stmt =
# First split all the input into separate lines.
var
rawLines = split(s.strVal, {char(0x0A), char(0x0D)})
buf = ""
for rawLine in rawLines:
# Split the input line into three columns, stripped, and parse.
var chunks = split(rawLine, ',')
map(chunks, cleaner)
if chunks.len != 3:
error("Declare macro syntax is 3 comma separated values:\n" &
"Got: '" & rawLine & "'")
# Add the statement, preppending a block if the buffer is empty.
if buf.len < 1: buf = "var\n"
buf &= " " & chunks[0] & ": "
# Parse the input type, which is an abbreviation.
case chunks[1]
of "i": buf &= "int = "
of "f": buf &= "float = "
else: error("Unexpected type '" & chunks[1] & "'")
buf &= chunks[2] & "\n"
# Finally, check if we did add any variable!
if buf.len > 0:
result = parseStmt(buf)
else:
error("Didn't find any input values!")
declare("""
x, i, 314
y, f, 3.14
""")
echo x
echo y
Macros can, by and large, utilize all pure Nimrod code that a procedure in the same place could see, too. E.g., you can import strutils or peg to parse your string, then construct output from that. Example:
import macros, strutils
macro declare(s: string): stmt =
var parts = split(s.strVal, {' ', ','})
if len(parts) != 3:
error("declare macro requires three parts")
result = parseStmt("var $1: $2 = $3" % parts)
declare("x, int, 314")
echo x
"Calling" a macro will basically evaluate it at compile time as though it were a procedure (with the caveat that the macro arguments will actually be ASTs, hence the need to use s.strVal above instead of s), then insert the AST that it returns at the position of the macro call.
The macro code is evaluated by the compiler's internal virtual machine.

Why will Powershell write to the console, but not to a file?

I have a PowerShell script that sets flags based on various conditions of the file. I'll abbreviate for brevity.
$path = "c:\path"
$srcfiles = Get-ChildItem $path -filter *.htm*
ForEach ($doc in $srcfiles) {
$s = $doc.Fullname
Write-Host "Processing :" $doc.FullName
if (stuff) {flag 1 = 1} else {flag 1 = 0}
if (stuff) {flag 1 = 1} else {flag 1 = 0}
if (stuff) {flag 1 = 1} else {flag 1 = 0}
$t = "$s;$flag1;$flag2;$flag2"
Write-Host "Output: " $t
This all works great. My file processes, the flags are set properly, and a neat semicolon delimited line is generated as $t. However, if I slap these two lines at the end of the function,
$stream = [System.IO.StreamWriter] "flags.txt"
$stream.WriteLine $t
I get this error.
Unexpected token 't' in expression or statement.
At C:\CGC003a.ps1:53 char:25
+ $stream.WriteLine $t <<<<
+ CategoryInfo : ParserError: (t:String) [], ParseException
+ FullyQualifiedErrorId : UnexpectedToken
If I'm reading this write, it appears that write-host flushed my variable $t before it got to the WriteLine. Before I try out-file, though, I want to understand what's happening to $t after Write-Host that prevents Write Line from seeing it as valid. Or is there something else I'm missing?
try:
$stream.WriteLine($t)
writeline is a method of streamwriter .net object. To pass in value you need to enclose it in ( )
-if you need to append to a streamwriter you need to create it like this:
$a = new-object 'System.IO.StreamWriter' -ArgumentList "c:\path\to\flags.txt",$true
Where the boolean arguments can be true to append data to the file orfalse to overwrite the file.
I suggest to pass full path for:
$stream = [System.IO.StreamWriter] "c:\path\to\flags.txt"
otherwise you create the file in .net current folder ( probably c:\windows\system32 if run as administrator your current powershell console, to know it type [System.IO.Directory]::GetCurrentDirectory())
you could try
$t > c:\path\to\flags.txt

Resources