From 009e409276cbfe678d13189d717003a6a05062ba Mon Sep 17 00:00:00 2001 From: eccles Date: Sun, 14 Dec 2003 00:31:25 +0000 Subject: [PATCH] 2.4: - Added Switch..Case*/Default..EndSwitch: similar to Select but behaves just like the C version (thanks to kichik). - Added unsigned integer comparisons. - Added 64-bit integer comparisons. - Added case-sensitive string tests. - Added other string relational comparisons. - Added section flag tests. git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@3279 212acab6-be3b-0410-9dea-997c60f758d6 --- Examples/LogicLib.nsi | 174 +++++++++++++++++++++++++++++++----- Include/LogicLib.nsh | 201 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 350 insertions(+), 25 deletions(-) diff --git a/Examples/LogicLib.nsi b/Examples/LogicLib.nsi index 0f21c5fc..fb0c29a7 100644 --- a/Examples/LogicLib.nsi +++ b/Examples/LogicLib.nsi @@ -2,10 +2,39 @@ Name "NSIS LogicLib Example" OutFile "example.exe" ShowInstDetails show -;!define LOGICLIB_VERBOSITY 4 +!include "sections.nsh" !include "logiclib.nsh" -Section +;!undef LOGICLIB_VERBOSITY +;!define LOGICLIB_VERBOSITY 4 ; For debugging - watch what logiclib does with your code! + +Page components "" "" ComponentsLeave +Page instfiles + +Section /o "Run tests" TESTS + + ; kinds of if other than "value1 comparison value2" + ClearErrors + FindFirst $R1 $R2 "$PROGRAMFILES\*" + ${Unless} ${Errors} + ${Do} + ${Select} $R2 + ${Case2} "." ".." + ; Do nothing + ${CaseElse} + DetailPrint "Found $PROGRAMFILES\$R2" + ${EndSelect} + FindNext $R1 $R2 + ${LoopUntil} ${Errors} + FindClose $R1 + ${EndUnless} + + StrCpy $R1 "example.xxx" + ${If} ${FileExists} "${__FILE__}" + DetailPrint 'Source file "${__FILE__}" still exists' + ${Else} + DetailPrint 'Source file "${__FILE__}" has gone' + ${EndIf} ; if..endif StrCpy $R1 1 @@ -167,6 +196,56 @@ Section DetailPrint "FAILED Select..Case*..EndSelect test" ${EndIf} + ; switch..case..caseelse..endswitch + StrCpy $R2 "" + ${For} $R1 1 10 + ${Switch} $R1 + ${Case} 3 + StrCpy $R2 $R2A + ${Case} 4 + StrCpy $R2 $R2B + ${Break} + ${Case} 5 + StrCpy $R2 $R2C + ${EndSwitch} + ${Switch} $R1 + ${Case} 1 + StrCpy $R2 $R2D + ${Default} + StrCpy $R2 $R2E + ${Break} + ${Case} 2 + StrCpy $R2 $R2F + ${EndSwitch} + ${Switch} $R1 + ${Case} 6 + ${Case} 7 + StrCpy $R2 $R2G + ${If} $R1 = 6 + ${Case} 8 + StrCpy $R2 $R2H + ${Switch} $R1 + ${Case} 6 + StrCpy $R2 $R2I + ${Break} + ${Case} 8 + StrCpy $R2 $R2J + ${EndSwitch} + ${EndIf} + StrCpy $R2 $R2K + ${Break} + ${Default} + StrCpy $R2 $R2L + ${Case} 9 + StrCpy $R2 $R2M + ${EndSwitch} + ${Next} + ${If} $R2 == "DELMFLMABELMBELMCELMEGHIKEGKEHJKEMELM" + DetailPrint "PASSED Switch..Case*..EndSwitch test" + ${Else} + DetailPrint "FAILED Switch..Case*..EndSwitch test" + ${EndIf} + ; for[each]..exitfor..next StrCpy $R2 "" ${For} $R1 1 5 @@ -264,27 +343,78 @@ Section DetailPrint "FAILED While..ExitWhile..EndWhile test" ${EndIf} - ; kinds of if other than "value1 comparison value2" - ClearErrors - FindFirst $R1 $R2 "$PROGRAMFILES\*" - ${Unless} ${Errors} - ${Do} - ${Select} $R2 - ${Case2} "." ".." - ; Do nothing - ${CaseElse} - DetailPrint "Found $PROGRAMFILES\$R2" - ${EndSelect} - FindNext $R1 $R2 - ${LoopUntil} ${Errors} - FindClose $R1 - ${EndUnless} - - StrCpy $R1 "example.xxx" - ${If} ${FileExists} "${__FILE__}" - DetailPrint 'Source file "${__FILE__}" still exists' + ; Unsigned integer tests + StrCpy $R2 "" + ${If} -1 < 1 + StrCpy $R2 $R2A + ${EndIf} + ${If} -1 U< 1 + StrCpy $R2 $R2B + ${EndIf} + ${If} 0xFFFFFFFF > 1 + StrCpy $R2 $R2C + ${EndIf} + ${If} 0xFFFFFFFF U> 1 + StrCpy $R2 $R2D + ${EndIf} + ${If} $R2 == "AD" + DetailPrint "PASSED unsigned integer test" ${Else} - DetailPrint 'Source file "${__FILE__}" has gone' + DetailPrint "FAILED unsigned integer test" + ${EndIf} + + ; 64-bit integer tests (uses System.dll) + StrCpy $R2 "" + ${If} 0x100000000 L= 4294967296 + StrCpy $R2 $R2A + ${EndIf} + ${If} 0x100000000 L< 0x200000000 + StrCpy $R2 $R2B + ${EndIf} + ${If} 0x500000000 L>= 0x500000000 + StrCpy $R2 $R2C + ${EndIf} + ${If} $R2 == "ABC" + DetailPrint "PASSED 64-bit integer test" + ${Else} + DetailPrint "FAILED 64-bit integer test" + ${EndIf} + + ; Extra string tests (uses System.dll) + StrCpy $R2 "" + ${If} "A" S< "B" + StrCpy $R2 $R2A + ${EndIf} + ${If} "b" S> "A" + StrCpy $R2 $R2B + ${EndIf} + ${If} "a" S<= "B" + StrCpy $R2 $R2C + ${EndIf} + ${If} "B" S< "B" + StrCpy $R2 $R2D + ${EndIf} + ${If} "A" S== "A" + StrCpy $R2 $R2E + ${EndIf} + ${If} "A" S== "a" + StrCpy $R2 $R2F + ${EndIf} + ${If} "A" S!= "a" + StrCpy $R2 $R2G + ${EndIf} + ${If} $R2 == "ABCEG" + DetailPrint "PASSED extra string test" + ${Else} + DetailPrint "FAILED extra string test" ${EndIf} SectionEnd + +Function ComponentsLeave + ; Section flags tests (requires sections.nsh be included) + ${Unless} ${SectionIsSelected} ${TESTS} + MessageBox MB_OK "Please select the component" + Abort + ${EndIf} +FunctionEnd diff --git a/Include/LogicLib.nsh b/Include/LogicLib.nsh index fcd3db5d..c5660530 100644 --- a/Include/LogicLib.nsh +++ b/Include/LogicLib.nsh @@ -1,5 +1,5 @@ ; NSIS LOGIC LIBRARY - logiclib.nsh -; Version 2.3 - 12/06/2003 +; Version 2.4 - 12/13/2003 ; By dselkirk@hotmail.com ; and eccles@users.sf.net ; @@ -22,6 +22,8 @@ ; - Conditionally executes an inline statement, depending on a True value of the provided NSIS function. ; select..case..case2..case3..case4..case5..caseelse..endselect ; - Executes one of several groups of statements, depending on the value of an expression. +; switch..case..default..endswitch +; - As above but with C-like features and behaviour. ; for..exitfor..continue..break..next ; - Repeats a group of statements a specified number of times. ; foreach..exitfor..continue..break..next @@ -82,6 +84,25 @@ ; 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). +; 2.4 - 12/13/2003 - 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). !verbose push !verbose 3 @@ -97,6 +118,8 @@ !define | "'" !define || "' '" + Var _LOGICLIB_TEMP ; Temporary variable to aid the more elaborate logic tests + !macro _PushLogic !insertmacro _PushScope Logic _${__LINE__} !macroend @@ -141,6 +164,44 @@ !insertmacro _== `${_a}` `${_b}` `${_f}` `${_t}` !macroend + ; Case-sensitive string tests + !macro _StrCmp _a _b _e _l _m + System::Call `kernel32::lstrcmpA(ts, ts) i.s` `${_a}` `${_b}` + Pop $_LOGICLIB_TEMP + IntCmp $_LOGICLIB_TEMP 0 `${_e}` `${_l}` `${_m}` + !macroend + + !macro _S== _a _b _t _f + !insertmacro _StrCmp `${_a}` `${_b}` `${_t}` `${_f}` `${_f}` + !macroend + + !macro _S!= _a _b _t _f + !insertmacro _S== `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + ; Extra string tests (cannot do these case-sensitively - I tried and lstrcmp still ignored the case) + !macro _StrCmpI _a _b _e _l _m + System::Call `kernel32::lstrcmpiA(ts, ts) i.s` `${_a}` `${_b}` + Pop $_LOGICLIB_TEMP + IntCmp $_LOGICLIB_TEMP 0 `${_e}` `${_l}` `${_m}` + !macroend + + !macro _S< _a _b _t _f + !insertmacro _StrCmpI `${_a}` `${_b}` `${_f}` `${_t}` `${_f}` + !macroend + + !macro _S>= _a _b _t _f + !insertmacro _S< `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + !macro _S> _a _b _t _f + !insertmacro _StrCmpI `${_a}` `${_b}` `${_f}` `${_f}` `${_t}` + !macroend + + !macro _S<= _a _b _t _f + !insertmacro _S> `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + ; Integer tests !macro _= _a _b _t _f IntCmp `${_a}` `${_b}` `${_t}` `${_f}` `${_f}` @@ -166,6 +227,54 @@ !insertmacro _> `${_a}` `${_b}` `${_f}` `${_t}` !macroend + ; Unsigned integer tests (NB: no need for extra equality tests) + !macro _U< _a _b _t _f + IntCmpU `${_a}` `${_b}` `${_f}` `${_t}` `${_f}` + !macroend + + !macro _U>= _a _b _t _f + !insertmacro _U< `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + !macro _U> _a _b _t _f + IntCmpU `${_a}` `${_b}` `${_f}` `${_f}` `${_t}` + !macroend + + !macro _U<= _a _b _t _f + !insertmacro _U> `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + ; Int64 tests + !macro _Int64Cmp _a _o _b _t _f + System::Int64Op `${_a}` `${_o}` `${_b}` + Pop $_LOGICLIB_TEMP + !insertmacro _= $_LOGICLIB_TEMP 0 `${_f}` `${_t}` + !macroend + + !macro _L= _a _b _t _f + !insertmacro _Int64Cmp `${_a}` = `${_b}` `${_t}` `${_f}` + !macroend + + !macro _L<> _a _b _t _f + !insertmacro _L= `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + !macro _L< _a _b _t _f + !insertmacro _Int64Cmp `${_a}` < `${_b}` `${_t}` `${_f}` + !macroend + + !macro _L>= _a _b _t _f + !insertmacro _L< `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + + !macro _L> _a _b _t _f + !insertmacro _Int64Cmp `${_a}` > `${_b}` `${_t}` `${_f}` + !macroend + + !macro _L<= _a _b _t _f + !insertmacro _L> `${_a}` `${_b}` `${_f}` `${_t}` + !macroend + ; Flag tests !macro _Abort _a _b _t _f IfAbort `${_t}` `${_f}` @@ -207,6 +316,20 @@ !macroend !define Cmd `"" Cmd` + ; Section flag test + !macro _SectionFlagIsSet _a _b _t _f + SectionGetFlags `${_b}` $_LOGICLIB_TEMP + IntOp $_LOGICLIB_TEMP $_LOGICLIB_TEMP & `${_a}` + !insertmacro _= $_LOGICLIB_TEMP `${_a}` `${_t}` `${_f}` + !macroend + !define SectionIsSelected `${SF_SELECTED} SectionFlagIsSet` + !define SectionIsSubSection `${SF_SUBSEC} SectionFlagIsSet` + !define SectionIsSubSectionEnd `${SF_SUBSECEND} SectionFlagIsSet` + !define SectionIsBold `${SF_BOLD} SectionFlagIsSet` + !define SectionIsReadOnly `${SF_RO} SectionFlagIsSet` + !define SectionIsExpanded `${SF_EXPAND} SectionFlagIsSet` + !define SectionIsPartiallySelected `${SF_PSELECTED} SectionFlagIsSet` + !define IfCmd `!insertmacro _IfThen "" Cmd ${|}` !macro _If _c _a _o _b @@ -421,7 +544,7 @@ !macroend !define Select `!insertmacro _Select` - !macro _CaseElse + !macro _Select_CaseElse !verbose push !verbose ${LOGICLIB_VERBOSITY} !ifndef _Logic | ${_Logic}Select @@ -443,7 +566,7 @@ !define Case_Else `!insertmacro _CaseElse` ; Compatibility with 2.2 and earlier !define Default `!insertmacro _CaseElse` ; For the C-minded - !macro _Case _a + !macro _Select_Case _a !verbose push !verbose ${LOGICLIB_VERBOSITY} ${CaseElse} ; Perform the CaseElse @@ -523,6 +646,78 @@ !macroend !define EndSelect `!insertmacro _EndSelect` + !macro _Switch _a + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !insertmacro _PushLogic + !insertmacro _PushScope Switch ${_Logic} ; Keep a separate stack for switch data + !insertmacro _PushScope Break _${__LINE__} ; Get a lable for beyond the end of the switch + !define ${_Switch}Var `${_a}` ; Remember the left hand side of the comparison + !define ${_Switch}Tmp "$%TMP%\${__LINE__}.tmp" ; Get a name for a temporary file + !system `@echo # logiclib temp file > "${${_Switch}Tmp}"` ; and create it + !define ${_Logic}Switch _${__LINE__} ; Get a label for the end of the switch + Goto ${${_Logic}Switch} ; and go there + !verbose pop + !macroend + !define Switch `!insertmacro _Switch` + + !macro _Case _a + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !ifdef _Logic & ${_Logic}Select ; Check for an active Select + !insertmacro _Select_Case `${_a}` + !else ifndef _Switch ; If not then check for an active Switch + !error "Cannot use Case without a preceding Select or Switch" + !else + !define _label _${__LINE__} ; Get a label for this case, + ${_label}: ; place it and add it's check to the temp file + !system `@echo !insertmacro _== $\`${${_Switch}Var}$\` $\`${_a}$\` ${_label} "" >> "${${_Switch}Tmp}"` + !undef _label + !endif + !verbose pop + !macroend + + !macro _CaseElse + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !ifdef _Logic & ${_Logic}Select ; Check for an active Select + !insertmacro _Select_CaseElse + !else ifndef _Switch ; If not then check for an active Switch + !error "Cannot use Case without a preceding Select or Switch" + !else ifdef ${_Switch}Else ; Already had a default case? + !error "Cannot use CaseElse following a CaseElse" + !else + !define ${_Switch}Else _${__LINE__} ; Get a label for the default case, + ${${_Switch}Else}: ; and place it + !endif + !verbose pop + !macroend + + !macro _EndSwitch + !verbose push + !verbose ${LOGICLIB_VERBOSITY} + !ifndef _Logic | ${_Logic}Switch + !error "Cannot use EndSwitch without a preceding Switch" + !endif + Goto ${_Break} ; Skip the jump table + ${${_Logic}Switch}: ; Place the end of the switch + !undef ${_Logic}Switch + !include "${${_Switch}Tmp}" ; Include the jump table + !system `@del /q "${${_Switch}Tmp}"` ; and clear it up + !ifdef ${_Switch}Else ; Was there a default case? + Goto ${${_Switch}Else} ; then go there if all else fails + !undef ${_Switch}Else + !endif + !undef ${_Switch}Tmp + !undef ${_Switch}Var + ${_Break}: ; Place the break label + !insertmacro _PopScope Break + !insertmacro _PopScope Switch + !insertmacro _PopLogic + !verbose pop + !macroend + !define EndSwitch `!insertmacro _EndSwitch` + !endif ; LOGICLIB !verbose 3 !define LOGICLIB_VERBOSITY ${_LOGICLIB_VERBOSITY}