Archive: NSIS Logic Library


NSIS Logic Library
  Hey, Here is another library to simplify the creation of your installs. This is the result of the previous post entitled "Select Statements". Thanks to eccles I have been able to completely rewrite it with improved functionality and speed.

Here is a list of the available statements:

if..elseif..else..endif
ifthen..|..|
ifcmd..||..|
select..case..case2..case3..case4..case5..case_else..endselect
for..exitfor..next
foreach..exitfor..next
do..exitdo..loop
dountil..exitdo..loop
do..exitdo..loopuntil
while..exitwhile..endwhile

Have a look at the provided example.nsi for working examples of the library. Once I get some feed back on possible changes or improvements then I will post it in the archive.

Don


Hey Don, check your private messages...!

Dave.


Version 2.1 adds break and continue labels to repeat type statements. Useful for functions like MessageBox, here is an example:


${do}
MessageBox MB_YESNO "Stop loop?" IDYES ${_break} ID_NO ${_continue}
${loop}


Thanks to eccles for the idea.

Damn, that's so cool! :)


Don, I've made a couple of changes for your perusal.

You've added some code to the If {ElseIf} [Else] EndIf code (ElseIf labels) that I don't understand - I'm not sure that they are needed?

Anyway, looking good! Should help newcommers to NSIS no end :)

--
Dave.

Good work on the consolidation and fixes. I especially love your solution for the operation comparison in the foreach statement. Very nice. What were the issues with the break and continue labels? For the if..then statments I had to add some extra lines to handle just an if..else..endif statements. When I had something like the foloowing:


${if} 1 = 5
MessageBox MB_OK "test1"
${else}
MessageBox MB_OK "test2"
${endif}

Both messages would appear. It wasn't moving to the end. Here it is again with the updated file header.

Originally posted by dselkirk
I especially love your solution for the operation comparison in the foreach statement.
Heh, you have to jump through some hoops sometimes to get NSIS to do what you want, but it's not often impossible.
What were the issues with the break and continue labels?
Either For or ForEach was not setting them (I forget which) and a couple of places were pushing them instead of popping them (IIRC...).

${if} 1 = 5
MessageBox MB_OK "test1"
${else}
MessageBox MB_OK "test2"
${endif}

Both messages would appear.
Ah, OK fair enough. :)

--
Dave.

Hi eccles & dselkirk!

You are amazing - very nice job done !
This is going to save quite some lines of script...


NSIS LogicLib Version 2.3

More changes are in the pipeline and LogicLib should be included in the standard NSIS distribution by the next NSIS release.

Enjoy!

--
Dave.

NSIS LogicLib Version 2.4

All of the new features can be seen in action in the example script.

--
Dave.

I love it! :D :up:


Great stuff! Truly amazing! What dou you come up with next? A NSIS compiler written in NSIS? :D

There's only one thing which should be improved:
Get rid of the ${} around the commands.
For example by adding a DeclareCommand function to NSIS or something similar. DeclareCommand ${If} If would make the If command available which then works like any of the built-in commands.
Or another way: Add support for function parameters and get rid of call.

And last but not least: Implicit inclusion of LogicLib.nsh to every script ;)

Keep up the good work!


These things will become possible when NSIS supports compiler plug-ins.


Compiler plugins? Whoah, any ETA?


NSIS 2.1 :)

NSIS 2.0 has to be finished first.


Thanks all for the thanks :D Thanks must also go out to Don (dselkirk) for planting the seed (and the code up to version 2.1 ;)).

LogicLib has now been added to CVS and is included in the nightly snapshots and forthcoming NSIS releases.

I am open to ideas for other improvements and logic tests to encapsulate (such as the section flag tests added in the latest version).

And last but not least: Implicit inclusion of LogicLib.nsh to every script ;)
nsisconf.nsh :p

--
Dave.

New in CVS: LogicLib v2.5


eccles this logic library is amazing. I've converted some of my scripts to use it and have been able to eliminate huge chunks of script because of it. Thanks alot man!


small question... can you not use LogicLib inside of macros with passed variables ?
e.g.

!macro someMacro someVar

${If} ${someVar} == 0
# do something
${EndIf}
!macroend
>
Tells me: !insertmacro: macro "_If" requires 4 parameter(s), passed 3!

nevermind... it's fine..

The problem is that I'm passing the macro an empty string:


"" 

And that throws the error. Apparently because once inside the macro, "" becomes <null>. Weird.

Work-arounds?
!macro someMacro someVar

>${If} "${someVar}" == "0"
# do something
>${ElseIf} "${someVar}" == ""
# do something else
>${EndIf}
!macroend
>
That would kill any integer checks, though.


"''" 

Seems to work - is that the proper way to go about this ?

I'm a bit confused as to why an empty string becomes null if passed to a macro, though. In the latter bit, my string consisting of two quotation marks essentially becomes an empty string? :)

Quoting in the ${If} line is the correct way to get around this. Why would it kill any integer checks?


because I'm making the gross assumption that you can't compare a string to an int :x

Thanks for the pointer :)


But an integer is a string in NSIS. Commands that require integers automatically convert the string to an integer.


Hi,
i have a question how to use If in the new Logiclib.
${If} ${SectionIsSelected} ${CSEC}
!insertmacro UnSelectSection ${ESEC}
${EndIf}

i get an error: "macro "If" requires 3 parameter(s), passed 2!"
I don't understand


Hi mamilo!

Did you write this code below the
Section Sec01 CSEC
declaration?

Cheers

Bruno


Shouldn't it be this?


${If} ${CSEC} = ${SectionIsSelected}
!insertmacro UnSelectSection ${ESEC}
${EndIf}

I think the code is correct.

http://nsis.sourceforge.net/LogicLib#Expressions

But I believe the define has not yet been created by the compiler and therefore the constant is empty. Put the code below the section declaration.


How do I use the OrUnless Statement correctly? I want to do something when one of two sections is selected. Here is my code that doesn't work:

SectionGetFlags ${SEC02} $R0
Intop $R1 $R0 | 1
SectionGetFlags ${SEC03} $R2
Intop $R3 $R2 | 1
${Unless} $R0 <> $R1 ${OrUnless} $R2 <> $R3
Do Something
${EndUnless}

only one "if" statement per line


Is this correct?

SectionGetFlags ${SEC02} $R0
Intop $R1 $R0 | 1
SectionGetFlags ${SEC03} $R2
Intop $R3 $R2 | 1
${Unless} $R0 <> $R1
${OrUnless} $R2 <> $R3
Do Something
${EndUnless}

You can just use the ${If} ${SectionIsSelected} ... ${OrIf} ${SectionIsSelected} ...

Stu


besides what Afrow said - yes, that'd be correct :)
'd still go with what Afrow said, though :D


Originally posted by Afrow UK
You can just use the ${If} ${SectionIsSelected} ... ${OrIf} ${SectionIsSelected} ...

Stu
That is not a good idea. Because with your code I have to copy my "Do Something" code twice.

${Unless} $R0 <> $R1
${OrUnless} $R2 <> $R3
Do Something
${EndUnless}

This seems to work and is very short.

Why?

${If} ${SectionIsSelected} ${SEC02}
${OrIf} ${SectionIsSelected} ${SEC03}
...
${EndIf}

Stu


That's right I didn't see that. But my code is also ok?


It may work but the proper logic is to check if ${SF_SELECTED} (1) is set:

SectionGetFlags ${SEC02} $R0
IntOp $R0 $R0 & ${SF_SELECTED}
${If} $R0 != 0
...

This is what ${If} ${SectionIsSelected} ${SEC02} would be doing internally.

Stu


What does this line?

IntOp $R0 $R0 & ${SF_SELECTED}


There's a replacement macro for ${FileExists} in the Wiki, but it doesn't work with ${IfNot} or ${Unless}.

http://nsis.sourceforge.net/LogicLib

FileExists

The ${FileExists} condition included in LogicLib will evaluate to true if what exists is actually a directory. I suggest you add the following macros to your script (right after including LogicLib.nsh):
!macro _FileExists2 _a _b _t _f
StrCmp `${_b}` `` `${_f}` 0
IfFileExists `${_b}` `0` `${_f}` ;returns true if this is a directory
IfFileExists `${_b}\*.*` `${_f}` `${_t}` ;so if it is a directory, jump to false
!macroend
!undef FileExists
!define FileExists `"" FileExists2`
!macro _DirExists _a _b _t _f
StrCmp `${_b}` `` `${_f}` 0
IfFileExists `${_b}\*.*` `${_t}` `${_f}`
!macroend
!define DirExists `"" DirExists`

Then you can use ${If} ${FileExists} and ${If} ${DirExists}.
In my script if I use:

${If} ${FileExists} <path> and it exists, it will perform.

However, if I use:

${IfNot} ${FileExists} <path> and the file doesn't exist, it won't perform.

I deleted the FileExists2 macro code from my script and returned to the one included in LogicLib.nsh and it works correctly again.

There's no need for a new macro. You can simply use ${If} ${FileExists} $YourFile ${AndIfNot} ${FileExists} "$YourFile\*.*" .


I know that but the code in the LogicLib Wiki (which is the official entry for LogicLib and makes the recommendation, actually - and links to this thread) doesn't work. It's weird that it doesn't work actually, FileExists2 is nearly identical to the old one, it looks like it should work the same except for returning false on directories.

Original:

!macro _FileExists _a _b _t _f

IfFileExists`${_b}` `${_t}` `${_f}`
!macroend
>!define FileExists `"" FileExists`
FileExists2 (slightly edited version)
!macro _FileExists2 _a _b _t _f

IfFileExists`${_b}` `0` `${_f}` ;continues if something exists, returns false if not
IfFileExists`${_b}\*.*` `${_f}` `${_t}` ;so if it is a directory, jump to false - else return true
>!macroend
>!define FileExists2 `"" FileExists2`

Wonder why it doesn't work?