applied patch #1412982 - "!if" - enhanced compile time flow control
git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@4526 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
parent
0bcee34186
commit
b1dc917843
5 changed files with 138 additions and 34 deletions
|
@ -31,7 +31,7 @@ Removes an item from the global define list. Note that $\{SYMBOL\} where SYMBOL
|
|||
|
||||
\S1{ifdef} !ifdef
|
||||
|
||||
\c gflag [bcheck [gflag [...]]]
|
||||
\c gflag [bcheck gflag [...]]]
|
||||
|
||||
This command, when paired with an !endif command, will tell the compiler whether or not to compile the lines in between the two lines. If gflag is globally defined (using !define or the /D switch), then the contained lines will be compiled. Otherwise, they will be skipped. 'bcheck' can be specified as & (boolean and) or | (boolean or) along with more gflags -- precedence is simple, left to right.
|
||||
|
||||
|
@ -46,13 +46,29 @@ This command, when paired with an !endif command, will tell the compiler whether
|
|||
|
||||
\S1{ifndef} !ifndef
|
||||
|
||||
\c gflag [bcheck [gflag [...]]]
|
||||
\c gflag [bcheck gflag [...]]]
|
||||
|
||||
The opposite of !ifdef. The lines will be compiled when the gflag has not been defined.
|
||||
|
||||
\S1{if} !if
|
||||
|
||||
\c [!] value [op value2]
|
||||
|
||||
This command, when paired with an !endif command, will tell the compiler whether or not to compile the lines in between the two lines. If value is non-zero, or the comparison of value and value2 depending on the operator results in true, the contained lines will be compiled. Otherwise, they will be skipped.
|
||||
op can be either == or != (string comparison), <=, < > or >= (float comparison), && or || (boolean comparison).
|
||||
If [!] is set, return value will be switched from true to false and vice versa.
|
||||
|
||||
\c !if 1 < 2
|
||||
\c !echo "1 is smaller than 2!!"
|
||||
\c !else if ! 3.1 > 1.99
|
||||
\c !error "this line should never appear"
|
||||
\c !else
|
||||
\c !error "neither should this"
|
||||
\c !endif
|
||||
|
||||
\S1{ifmacrodef} !ifmacrodef
|
||||
|
||||
\c gflag [bcheck [gflag [...]]]
|
||||
\c gflag [bcheck gflag [...]]]
|
||||
|
||||
This command, when paired with an !endif command, will tell the compiler whether or not to compile the lines in between the two lines. If the macro gflag exists, then the contained lines will be compiled. Otherwise, they will be skipped. 'bcheck' can be specified as & (boolean and) or | (boolean or) along with more gflags -- precedence is simple, left to right.
|
||||
|
||||
|
@ -64,13 +80,13 @@ This command, when paired with an !endif command, will tell the compiler whether
|
|||
|
||||
\S1{ifmacrondef} !ifmacrondef
|
||||
|
||||
\c gflag [bcheck [gflag [...]]]
|
||||
\c gflag [bcheck gflag [...]]]
|
||||
|
||||
The opposite of !ifmacrodef. The lines will be compiled when the macro gflag does not exist.
|
||||
|
||||
\S1{else} !else
|
||||
|
||||
\c [ifdef|ifndef|ifmacrodef|ifmacrondef [...]]
|
||||
\c [if|ifdef|ifndef|ifmacrodef|ifmacrondef [...]]
|
||||
|
||||
This command allows to easily insert different code when different defines or macros are set. You can create blocks like !ifdef/!else/!endif, !ifdef/!else ifdef/!else/!endif etc.
|
||||
|
||||
|
@ -82,7 +98,7 @@ This command allows to easily insert different code when different defines or ma
|
|||
|
||||
\S1{endif} !endif
|
||||
|
||||
This command closes a block started with !ifdef, !ifndef, !ifmacrodef or !ifmacrondef.
|
||||
This command closes a block started with !if, !ifdef, !ifndef, !ifmacrodef or !ifmacrondef.
|
||||
|
||||
\S1{insertmacro} !insertmacro
|
||||
|
||||
|
|
|
@ -51,6 +51,40 @@ d\
|
|||
i\
|
||||
f
|
||||
|
||||
# tests for !if statement
|
||||
!if 'test' == 'test'
|
||||
!if 1 <= 2
|
||||
!if ! 100 < 99.99
|
||||
!if 2.2 > 1.12
|
||||
!if ! 23 >= 37
|
||||
!if 1 && 1
|
||||
!if ! 0 || 0
|
||||
|
||||
# this should be compiled
|
||||
|
||||
!else
|
||||
!error "!if ! 0 || 0 is true!"
|
||||
!endif
|
||||
!else
|
||||
!error "!if 1 && 1 is true!"
|
||||
!endif
|
||||
!else
|
||||
!error "!if ! 23 >= 37 is true!"
|
||||
!endif
|
||||
!else
|
||||
!error "!if 2.2 > 1.12 is true!"
|
||||
!endif
|
||||
!else
|
||||
!error "!if ! 100 < 99.99 is true!"
|
||||
!endif
|
||||
!else
|
||||
!error "!if 1 <= 2 is true!"
|
||||
!endif
|
||||
!else
|
||||
!error "!if 'test' == 'test' is true!"
|
||||
!endif
|
||||
|
||||
|
||||
# this should just give a warning, not an error
|
||||
!include /NONFATAL file_that_doesnt_exist.nsh
|
||||
|
||||
|
|
|
@ -353,9 +353,15 @@ parse_again:
|
|||
if (cur_ifblock && cur_ifblock->inherited_ignore)
|
||||
return PS_OK;
|
||||
|
||||
if (!num_ifblock() || cur_ifblock->elseused)
|
||||
if (!num_ifblock())
|
||||
{
|
||||
ERROR_MSG("!else: stray !else\n");
|
||||
ERROR_MSG("!else: no if block open (!if[macro][n][def])\n");
|
||||
return PS_ERROR;
|
||||
}
|
||||
|
||||
if (cur_ifblock->elseused)
|
||||
{
|
||||
ERROR_MSG("!else: else already used in current if block\n");
|
||||
return PS_ERROR;
|
||||
}
|
||||
|
||||
|
@ -376,16 +382,17 @@ parse_again:
|
|||
|
||||
line.eattoken();
|
||||
|
||||
int v=line.gettoken_enum(0,"ifdef\0ifndef\0ifmacrodef\0ifmacrondef\0");
|
||||
int v=line.gettoken_enum(0,"if\0ifdef\0ifndef\0ifmacrodef\0ifmacrondef\0");
|
||||
if (v < 0) PRINTHELP()
|
||||
if (line.getnumtokens() == 1) PRINTHELP()
|
||||
int cmds[] = {TOK_P_IFDEF, TOK_P_IFNDEF, TOK_P_IFMACRODEF, TOK_P_IFMACRONDEF};
|
||||
int cmds[] = {TOK_P_IF, TOK_P_IFDEF, TOK_P_IFNDEF, TOK_P_IFMACRODEF, TOK_P_IFMACRONDEF};
|
||||
tkid = cmds[v];
|
||||
if_from_else++;
|
||||
}
|
||||
|
||||
if (tkid == TOK_P_IFNDEF || tkid == TOK_P_IFDEF ||
|
||||
tkid == TOK_P_IFMACRODEF || tkid == TOK_P_IFMACRONDEF)
|
||||
tkid == TOK_P_IFMACRODEF || tkid == TOK_P_IFMACRONDEF ||
|
||||
tkid == TOK_P_IF)
|
||||
{
|
||||
if (!if_from_else)
|
||||
start_ifblock();
|
||||
|
@ -398,29 +405,74 @@ parse_again:
|
|||
int istrue=0;
|
||||
|
||||
int mod=0;
|
||||
int p;
|
||||
|
||||
// pure left to right precedence. Not too powerful, but useful.
|
||||
for (p = 1; p < line.getnumtokens(); p ++)
|
||||
{
|
||||
if (p & 1)
|
||||
{
|
||||
int new_s;
|
||||
if (tkid == TOK_P_IFNDEF || tkid == TOK_P_IFDEF)
|
||||
new_s=!!definedlist.find(line.gettoken_str(p));
|
||||
else
|
||||
new_s=MacroExists(line.gettoken_str(p));
|
||||
if (tkid == TOK_P_IFNDEF || tkid == TOK_P_IFMACRONDEF)
|
||||
new_s=!new_s;
|
||||
|
||||
if (mod == 0) istrue = istrue || new_s;
|
||||
else istrue = istrue && new_s;
|
||||
|
||||
int p=0;
|
||||
|
||||
if (tkid == TOK_P_IF) {
|
||||
if(!strcmp(line.gettoken_str(1),"!")) {
|
||||
p = 1;
|
||||
line.eattoken();
|
||||
}
|
||||
else
|
||||
|
||||
if(line.getnumtokens() == 2)
|
||||
istrue = line.gettoken_int(1);
|
||||
|
||||
else if (line.getnumtokens() == 4) {
|
||||
mod = line.gettoken_enum(2,"=\0==\0!=\0<=\0<\0>\0>=\0&\0&&\0|\0||\0");
|
||||
|
||||
switch(mod) {
|
||||
case 0:
|
||||
case 1:
|
||||
istrue = strcmp(line.gettoken_str(1),line.gettoken_str(3)) == 0; break;
|
||||
case 2:
|
||||
istrue = strcmp(line.gettoken_str(1),line.gettoken_str(3)) != 0; break;
|
||||
case 3:
|
||||
istrue = line.gettoken_float(1) <= line.gettoken_float(3); break;
|
||||
case 4:
|
||||
istrue = line.gettoken_float(1) < line.gettoken_float(3); break;
|
||||
case 5:
|
||||
istrue = line.gettoken_float(1) > line.gettoken_float(3); break;
|
||||
case 6:
|
||||
istrue = line.gettoken_float(1) >= line.gettoken_float(3); break;
|
||||
case 7:
|
||||
case 8:
|
||||
istrue = line.gettoken_int(1) && line.gettoken_int(3); break;
|
||||
case 9:
|
||||
case 10:
|
||||
istrue = line.gettoken_int(1) || line.gettoken_int(3); break;
|
||||
default:
|
||||
PRINTHELP()
|
||||
}
|
||||
}
|
||||
else PRINTHELP()
|
||||
|
||||
if(p) istrue = !istrue;
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
// pure left to right precedence. Not too powerful, but useful.
|
||||
for (p = 1; p < line.getnumtokens(); p ++)
|
||||
{
|
||||
mod=line.gettoken_enum(p,"|\0&\0||\0&&\0");
|
||||
if (mod == -1) PRINTHELP()
|
||||
mod &= 1;
|
||||
if (p & 1)
|
||||
{
|
||||
int new_s;
|
||||
if (tkid == TOK_P_IFNDEF || tkid == TOK_P_IFDEF)
|
||||
new_s=!!definedlist.find(line.gettoken_str(p));
|
||||
else
|
||||
new_s=MacroExists(line.gettoken_str(p));
|
||||
if (tkid == TOK_P_IFNDEF || tkid == TOK_P_IFMACRONDEF)
|
||||
new_s=!new_s;
|
||||
|
||||
if (mod == 0) istrue = istrue || new_s;
|
||||
else istrue = istrue && new_s;
|
||||
}
|
||||
else
|
||||
{
|
||||
mod=line.gettoken_enum(p,"|\0&\0||\0&&\0");
|
||||
if (mod == -1) PRINTHELP()
|
||||
mod &= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -437,7 +489,7 @@ parse_again:
|
|||
if (tkid == TOK_P_ENDIF) {
|
||||
if (!num_ifblock())
|
||||
{
|
||||
ERROR_MSG("!endif: no !ifdef open\n");
|
||||
ERROR_MSG("!endif: no if block open (!if[macro][n][def])\n");
|
||||
return PS_ERROR;
|
||||
}
|
||||
end_ifblock();
|
||||
|
|
|
@ -225,12 +225,13 @@ static tokenType tokenlist[TOK__LAST] =
|
|||
{TOK_P_ADDINCLUDEDIR,"!AddIncludeDir",1,0,"dir",TP_ALL},
|
||||
{TOK_P_INCLUDE,"!include",1,1,"[/NONFATAL] filename.nsh",TP_ALL},
|
||||
{TOK_P_CD,"!cd",1,0,"absolute_or_relative_new_directory",TP_ALL},
|
||||
{TOK_P_IF,"!if",1,3,"[!] value [(==,!=,<=,<,>,>=,&&,||) value2] [...]",TP_ALL},
|
||||
{TOK_P_IFDEF,"!ifdef",1,-1,"symbol [| symbol2 [& symbol3 [...]]]",TP_ALL},
|
||||
{TOK_P_IFNDEF,"!ifndef",1,-1,"symbol [| symbol2 [& symbol3 [...]]]",TP_ALL},
|
||||
{TOK_P_ENDIF,"!endif",0,0,"",TP_ALL},
|
||||
{TOK_P_DEFINE,"!define",1,2,"[/date] symbol [value]",TP_ALL},
|
||||
{TOK_P_UNDEF,"!undef",1,1,"symbol [value]",TP_ALL},
|
||||
{TOK_P_ELSE,"!else",0,-1,"[ifdef|ifndef symbol [|symbol2 [& symbol3 [...]]]]",TP_ALL},
|
||||
{TOK_P_ELSE,"!else",0,-1,"[if[macro][n][def] ...]",TP_ALL},
|
||||
{TOK_P_ECHO,"!echo",1,0,"message",TP_ALL},
|
||||
{TOK_P_WARNING,"!warning",0,1,"[warning_message]",TP_ALL},
|
||||
{TOK_P_ERROR,"!error",0,1,"[error_message]",TP_ALL},
|
||||
|
|
|
@ -71,6 +71,7 @@ enum
|
|||
TOK_FILEBUFSIZE,
|
||||
|
||||
// system "preprocessor"ish tokens
|
||||
TOK_P_IF,
|
||||
TOK_P_IFDEF,
|
||||
TOK_P_IFNDEF,
|
||||
TOK_P_ELSE,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue