- NSIS Discussion
- NSIS Logic Library
Archive: NSIS Logic Library
dselkirk
3rd October 2003 15:34 UTC
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
eccles
3rd October 2003 19:37 UTC
Hey Don, check your private messages...!
Dave.
dselkirk
5th October 2003 23:06 UTC
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.
kichik
7th October 2003 01:02 UTC
Damn, that's so cool! :)
eccles
7th October 2003 13:56 UTC
Don, I've made a couple of changes for your perusal.
- Simplified IfThen by utilising If and EndIf
- Maybe something similar could be done with IfCmd but I've not investigated this yet
- Simplified For by utilising ForEach
- Fixed ForEach missing the final iteration
- Fixed a couple of Break/Continue bugs
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.
dselkirk
7th October 2003 14:55 UTC
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.
eccles
7th October 2003 16:04 UTC
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.
fraefel
7th October 2003 21:15 UTC
Hi eccles & dselkirk!
You are amazing - very nice job done !
This is going to save quite some lines of script...
eccles
11th December 2003 00:18 UTC
NSIS LogicLib Version 2.3
- Much reworking and refactoring of things to help reduce duplication, etc. E.g. all loop varieties now go through a common set of macros.
- Added built-in support for the rest of NSIS's built-in conditional tests (Abort, Errors, FileExists, RebootFlag, Silent).
- Added ability to use any NSIS conditional command in a normal If type statement (no longer restricted to the specialised IfCmd statement).
- Optimised the code produced by If (fewer Goto's).
- Added statement similar to If that works in reverse: "Unless" executes the code in the contained block if the condition is false. If, Unless, ElseIf, ElseUnless, EndIf and EndUnless can be used freely in any combination.
- Fixed bug where using Continue in a Do..LoopUntil loop went to the top of the loop and not the loop condition.
- Added DoWhile..Loop and Do..LoopWhile loop varieties (the existing While..EndWhile loop is still available and is identical to DoWhile..Loop).
- Optimised the code produced by Select (fewer Goto's).
- Renamed Case_Else to CaseElse (nothing else has an underscore so why should that one). The old name is still available too though (if you must).
- CaseElse can also be called Default (for the C-minded).
More changes are in the pipeline and LogicLib should be included in the standard NSIS distribution by the next NSIS release.
Enjoy!
--
Dave.
eccles
13th December 2003 16:53 UTC
NSIS LogicLib Version 2.4
- Added Switch..Case*/Default..EndSwitch: similar to Select but behaves just like the C version. I.e.:
- Each Case is more like a label than a block so execution "falls through" unless you use Break.
- CaseElse (or Default) does not have to be the final case.
- Case*/Default can appear anywhere inside the Switch (e.g. inside an If inside the Switch).
(With thanks to kichik for the idea and proof-of-concept model).
- Added unsigned integer comparisons U<, U>=, U> and U<=.
- Added 64-bit integer comparisons L=, L<>, L<, L>=, L> and L<= (these use System.dll).
- Added case-sensitive string tests S== and S!= (these use System.dll).
- Added string comparisons (not case sensitive) S<, S>=, S> and S<= (these use System.dll).
- Added section flag tests (SectionIsSelected, etc.) (to use these your script must include sections.nsh).
All of the new features can be seen in action in the example script.
--
Dave.
kichik
13th December 2003 17:04 UTC
I love it! :D :up:
CodeSquid
14th December 2003 11:28 UTC
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!
Joost Verburg
14th December 2003 13:14 UTC
These things will become possible when NSIS supports compiler plug-ins.
CodeSquid
14th December 2003 13:54 UTC
Compiler plugins? Whoah, any ETA?
Joost Verburg
14th December 2003 15:33 UTC
NSIS 2.1 :)
NSIS 2.0 has to be finished first.
eccles
14th December 2003 16:10 UTC
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.
eccles
23rd August 2004 14:49 UTC
New in CVS: LogicLib v2.5
- AndIf, AndUnless, OrIf, OrUnless added. These can be placed after If, Unless, ElseIf and ElseUnless to add any number of extra conditions. Order of precedence is strictly left-to-right though (or rather, top to bottom).
- Warnings of "unused variable _LOGICLIB_TEMP" are now avoided. When using the features that make use of this variable you will need to add a !define above !include LogicLib.nsh to let LogicLib know in advance. If you forget, a compiler error message will explain what is needed.
rsegal
24th August 2004 03:54 UTC
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!
Animaether
24th November 2005 01:33 UTC
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!
Animaether
24th November 2005 04:19 UTC
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? :)
kichik
24th November 2005 13:24 UTC
Quoting in the ${If} line is the correct way to get around this. Why would it kill any integer checks?
Animaether
24th November 2005 15:55 UTC
because I'm making the gross assumption that you can't compare a string to an int :x
Thanks for the pointer :)
kichik
24th November 2005 16:00 UTC
But an integer is a string in NSIS. Commands that require integers automatically convert the string to an integer.
mamilo
29th November 2006 11:59 UTC
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
bholliger
29th November 2006 21:00 UTC
Hi mamilo!
Did you write this code below the
Section Sec01 CSEC
declaration?
Cheers
Bruno
Comperio
1st December 2006 15:28 UTC
Shouldn't it be this?
${If} ${CSEC} = ${SectionIsSelected}
!insertmacro UnSelectSection ${ESEC}
${EndIf}
bholliger
1st December 2006 22:31 UTC
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.
phunkydizco
20th November 2008 14:40 UTC
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}
Anders
20th November 2008 14:46 UTC
only one "if" statement per line
phunkydizco
20th November 2008 14:50 UTC
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}
Afrow UK
20th November 2008 17:40 UTC
You can just use the ${If} ${SectionIsSelected} ... ${OrIf} ${SectionIsSelected} ...
Stu
Animaether
20th November 2008 18:31 UTC
besides what Afrow said - yes, that'd be correct :)
'd still go with what Afrow said, though :D
phunkydizco
20th November 2008 18:49 UTC
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.
Afrow UK
20th November 2008 19:01 UTC
Why?
${If} ${SectionIsSelected} ${SEC02}
${OrIf} ${SectionIsSelected} ${SEC03}
...
${EndIf}
Stu
phunkydizco
20th November 2008 19:47 UTC
That's right I didn't see that. But my code is also ok?
Afrow UK
20th November 2008 23:42 UTC
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
phunkydizco
21st November 2008 07:49 UTC
What does this line?
IntOp $R0 $R0 & ${SF_SELECTED}
o___O
8th March 2011 08:06 UTC
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.
MSG
8th March 2011 08:10 UTC
There's no need for a new macro. You can simply use ${If} ${FileExists} $YourFile ${AndIfNot} ${FileExists} "$YourFile\*.*" .
o___O
8th March 2011 11:16 UTC
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?