Added preprocess only mode (/[SAFE]PPO switch)
git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6495 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
parent
d91176ba49
commit
0bffaecea3
9 changed files with 99 additions and 38 deletions
|
@ -8,6 +8,8 @@ Released on ?, 2014
|
|||
|
||||
\S2{} Major Changes
|
||||
|
||||
\b Added PPO and SafePPO preprocess-only compiler switches
|
||||
|
||||
\b MakeNSIS WM_COPYDATA messages now use the QH_OUTPUTCHARSET encoding with CP_ACP as the default for compatibility with old IDEs.
|
||||
|
||||
\S2{} Minor Changes
|
||||
|
|
|
@ -33,6 +33,8 @@ If you want to use MakeNSIS on the command line, the syntax of the makensis comm
|
|||
|
||||
\b /OUTPUTCHARSET allows you to specify the codepage used by stdout when the output is redirected. (\NsisOutputCharset)
|
||||
|
||||
\b /PPO or /SAFEPPO will only run the preprocessor and print the result to stdout. The safe version will not execute instructions like !appendfile or !system. !packhdr and !finalize are never executed.
|
||||
|
||||
\b Using the /D switch one or more times will add to symbols to the globally defined list (See !define).
|
||||
|
||||
\b Using the /X switch one or more times will execute the code you specify following it. Example: "/XAutoCloseWindow false"
|
||||
|
|
|
@ -105,15 +105,15 @@ CEXEBuild::~CEXEBuild()
|
|||
}
|
||||
}
|
||||
|
||||
CEXEBuild::CEXEBuild() :
|
||||
m_exehead(0),
|
||||
m_exehead_size(0)
|
||||
CEXEBuild::CEXEBuild(signed char pponly) :
|
||||
m_exehead(0),
|
||||
m_exehead_size(0),
|
||||
preprocessonly(pponly)
|
||||
{
|
||||
set_verbosity(3);
|
||||
|
||||
curlinereader=0;
|
||||
curfilename=0;
|
||||
linecnt=0;
|
||||
curfilename=0, linecnt=0;
|
||||
cur_ifblock=NULL;
|
||||
last_line_had_slash=0;
|
||||
inside_comment=false;
|
||||
|
@ -3366,6 +3366,7 @@ int CEXEBuild::get_verbosity() const
|
|||
|
||||
void CEXEBuild::set_verbosity(int lvl)
|
||||
{
|
||||
if (preprocessonly) lvl = STD_MIN(lvl, 1);
|
||||
display_errors = lvl > 0;
|
||||
display_warnings = lvl > 1;
|
||||
display_info = lvl > 2;
|
||||
|
|
|
@ -102,7 +102,7 @@ namespace MakensisAPI {
|
|||
|
||||
class CEXEBuild {
|
||||
public:
|
||||
CEXEBuild();
|
||||
CEXEBuild(signed char pponly);
|
||||
void initialize(const TCHAR *makensis_path);
|
||||
~CEXEBuild();
|
||||
|
||||
|
@ -135,7 +135,7 @@ class CEXEBuild {
|
|||
// process a script (you can process as many scripts as you want,
|
||||
// it is as if they are concatenated)
|
||||
int process_script(NIStream&Strm, const TCHAR *filename);
|
||||
int process_oneline(TCHAR *line, const TCHAR *curfilename, int lineptr);
|
||||
int process_oneline(const TCHAR *line, const TCHAR *curfilename, int lineptr);
|
||||
|
||||
// you only get to call write_output once, so use it wisely.
|
||||
int write_output(void);
|
||||
|
@ -145,6 +145,7 @@ class CEXEBuild {
|
|||
DefineList definedlist; // List of identifiers marked as "defined" like
|
||||
// C++ macro definitions such as _UNICODE.
|
||||
void define(const TCHAR *p, const TCHAR *v=_T("")); // to add a defined thing.
|
||||
signed char preprocessonly; // > 0 = safe, < 0 = unsafe
|
||||
|
||||
int get_verbosity() const;
|
||||
void set_verbosity(int lvl);
|
||||
|
@ -173,6 +174,8 @@ class CEXEBuild {
|
|||
|
||||
// tokens.cpp
|
||||
bool is_ppbranch_token(TCHAR *s);
|
||||
bool is_pp_token(int tkid);
|
||||
bool is_unsafe_pp_token(int tkid);
|
||||
int get_commandtoken(TCHAR *s, int *np, int *op, int *pos);
|
||||
const TCHAR* get_commandtoken_name(int tok);
|
||||
|
||||
|
|
|
@ -98,3 +98,12 @@ void GrowBuf::resize(int newlen)
|
|||
|
||||
int GrowBuf::getlen() const { return m_used; }
|
||||
void *GrowBuf::get() const { return m_s; }
|
||||
|
||||
void GrowBuf::swap(GrowBuf&other)
|
||||
{
|
||||
std::swap(m_s, other.m_s);
|
||||
std::swap(m_alloc, other.m_alloc);
|
||||
std::swap(m_used, other.m_used);
|
||||
std::swap(m_zero, other.m_zero);
|
||||
std::swap(m_bs, other.m_bs);
|
||||
}
|
||||
|
|
|
@ -103,6 +103,8 @@ class GrowBuf : public IGrowBuf
|
|||
*/
|
||||
void *get() const;
|
||||
|
||||
void swap(GrowBuf&other);
|
||||
|
||||
private:
|
||||
void *m_s; /* the storage buffer */
|
||||
int m_alloc; /* allocated bytes */
|
||||
|
|
|
@ -176,6 +176,7 @@ static void print_usage()
|
|||
#ifdef _WIN32
|
||||
_T(" ") OPT_STR _T("OUTPUTCHARSET <") TSTR_OUTPUTCHARSET _T(">\n")
|
||||
#endif
|
||||
_T(" ") OPT_STR _T("[SAFE]PPO preprocess to stdout/file\n")
|
||||
_T(" ") OPT_STR _T("Ddefine[=value] defines the symbol \"define\" for the script [to value]\n")
|
||||
_T(" ") OPT_STR _T("Xscriptcmd executes scriptcmd in script (i.e. \"") OPT_STR _T("XOutFile inst.exe\")\n")
|
||||
_T(" ") _T(" parameters are processed by order (") OPT_STR _T("Ddef ins.nsi != ins.nsi ") OPT_STR _T("Ddef)\n")
|
||||
|
@ -298,6 +299,7 @@ static inline int makensismain(int argc, TCHAR **argv)
|
|||
bool no_logo=true;
|
||||
bool initialparsefail=false;
|
||||
bool noconfig=false;
|
||||
signed char pponly=0;
|
||||
#ifdef _WIN32
|
||||
signed char outputbom=1;
|
||||
|
||||
|
@ -352,6 +354,10 @@ static inline int makensismain(int argc, TCHAR **argv)
|
|||
outputenc.SetCodepage(NStreamEncoding::UTF16LE);
|
||||
}
|
||||
#endif
|
||||
else if (!_tcsicmp(swname,_T("PPO")) || !_tcsicmp(swname,_T("SafePPO")))
|
||||
{
|
||||
pponly = S7IsChEqualI('s',swname[0]) ? 1 : -1;
|
||||
}
|
||||
else if (S7IsChEqualI('v',swname[0]) && swname[1] && !swname[2])
|
||||
{
|
||||
no_logo=swname[1] >= _T('0') && swname[1] <= _T('2');
|
||||
|
@ -394,7 +400,7 @@ static inline int makensismain(int argc, TCHAR **argv)
|
|||
unsigned int files_processed=0;
|
||||
unsigned int cmds_processed=0;
|
||||
|
||||
CEXEBuild build;
|
||||
CEXEBuild build(pponly);
|
||||
try
|
||||
{
|
||||
build.initialize(argv[0]);
|
||||
|
@ -421,7 +427,7 @@ static inline int makensismain(int argc, TCHAR **argv)
|
|||
fflush(g_output);
|
||||
return 0;
|
||||
}
|
||||
if (!no_logo) print_logo();
|
||||
if (!no_logo && !pponly) print_logo();
|
||||
|
||||
|
||||
argpos=initialparsefail ? argc : 1;
|
||||
|
@ -431,15 +437,17 @@ static inline int makensismain(int argc, TCHAR **argv)
|
|||
in_files=1;
|
||||
else if (IS_OPT(argv[argpos]) && _tcscmp(argv[argpos], _T("-")) && !in_files)
|
||||
{
|
||||
if (!_tcsicmp(&argv[argpos][1],_T("NOCD"))) do_cd=false;
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("NOCONFIG"))) noconfig=true;
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("PAUSE"))) g_dopause=true;
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("LICENSE")))
|
||||
const TCHAR* const swname = &argv[argpos][1];
|
||||
if (!_tcsicmp(swname,_T("PPO")) || !_tcsicmp(swname,_T("SafePPO"))) {} // Already parsed
|
||||
else if (!_tcsicmp(swname,_T("NOCD"))) do_cd=false;
|
||||
else if (!_tcsicmp(swname,_T("NOCONFIG"))) noconfig=true;
|
||||
else if (!_tcsicmp(swname,_T("PAUSE"))) g_dopause=true;
|
||||
else if (!_tcsicmp(swname,_T("LICENSE")))
|
||||
{
|
||||
if (build.display_info) print_license();
|
||||
nousage++;
|
||||
}
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("CMDHELP")))
|
||||
else if (!_tcsicmp(swname,_T("CMDHELP")))
|
||||
{
|
||||
if (argpos < argc-1)
|
||||
build.print_help(argv[++argpos]);
|
||||
|
@ -447,12 +455,12 @@ static inline int makensismain(int argc, TCHAR **argv)
|
|||
build.print_help(NULL);
|
||||
nousage++;
|
||||
}
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("HDRINFO")))
|
||||
else if (!_tcsicmp(swname,_T("HDRINFO")))
|
||||
{
|
||||
print_stub_info(build);
|
||||
nousage++;
|
||||
}
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("INPUTCHARSET")) || !_tcsicmp(&argv[argpos][1],_T("ICS")))
|
||||
else if (!_tcsicmp(swname,_T("INPUTCHARSET")) || !_tcsicmp(swname,_T("ICS")))
|
||||
{
|
||||
if (!HasReqParam(argv, ++argpos, argc)) break;
|
||||
WORD cp = GetEncodingFromString(argv[argpos]);
|
||||
|
@ -464,13 +472,13 @@ static inline int makensismain(int argc, TCHAR **argv)
|
|||
}
|
||||
inputenc.SafeSetCodepage(cp);
|
||||
}
|
||||
else if (S7IsChEqualI('v',argv[argpos][1]) &&
|
||||
else if (S7IsChEqualI('v',*swname) &&
|
||||
argv[argpos][2] >= _T('0') && argv[argpos][2] <= _T('4') && !argv[argpos][3])
|
||||
{
|
||||
int v=argv[argpos][2]-_T('0');
|
||||
build.set_verbosity(v);
|
||||
}
|
||||
else if (S7IsChEqualI('p',argv[argpos][1]) &&
|
||||
else if (S7IsChEqualI('p',*swname) &&
|
||||
argv[argpos][2] >= _T('0') && argv[argpos][2] <= _T('5') && !argv[argpos][3])
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
@ -496,10 +504,10 @@ static inline int makensismain(int argc, TCHAR **argv)
|
|||
#endif
|
||||
}
|
||||
// Already parsed these (must adjust argpos)
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("NOTIFYHWND"))) ++argpos;
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("OUTPUTCHARSET")) || !_tcsicmp(&argv[argpos][1],_T("OCS"))) ++argpos;
|
||||
else if (!_tcsicmp(swname,_T("NOTIFYHWND"))) ++argpos;
|
||||
else if (!_tcsicmp(swname,_T("OUTPUTCHARSET")) || !_tcsicmp(swname,_T("OCS"))) ++argpos;
|
||||
// These must be parsed last because they will eat other switches
|
||||
else if (S7IsChEqualI('d',argv[argpos][1]) && argv[argpos][2])
|
||||
else if (S7IsChEqualI('d',swname[0]) && swname[1])
|
||||
{
|
||||
TCHAR *p=argv[argpos]+2;
|
||||
TCHAR *s=_tcsdup(p),*v;
|
||||
|
@ -509,9 +517,9 @@ static inline int makensismain(int argc, TCHAR **argv)
|
|||
build.define(s,v?v:_T(""));
|
||||
free(s);
|
||||
}
|
||||
else if (S7IsChEqualI('x',argv[argpos][1]) && argv[argpos][2])
|
||||
else if (S7IsChEqualI('x',swname[0]) && swname[1])
|
||||
{
|
||||
if (build.process_oneline(argv[argpos]+2,_T("<command line>"),argpos+1) != PS_OK)
|
||||
if (build.process_oneline(swname+1,_T("<command line>"),argpos+1) != PS_OK)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
@ -519,9 +527,9 @@ static inline int makensismain(int argc, TCHAR **argv)
|
|||
}
|
||||
// Already parsed these ("VERSION" never gets this far)
|
||||
#ifdef _WIN32
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("RAW"))) {}
|
||||
else if (!_tcsicmp(swname,_T("RAW"))) {}
|
||||
#endif
|
||||
else if (S7IsChEqualI('o',argv[argpos][1]) && argv[argpos][2]) {}
|
||||
else if (S7IsChEqualI('o',swname[0]) && swname[1]) {}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
@ -615,6 +623,8 @@ static inline int makensismain(int argc, TCHAR **argv)
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (build.preprocessonly) return 0;
|
||||
|
||||
if (build.display_info)
|
||||
{
|
||||
_ftprintf(g_output,_T("\nProcessed "));
|
||||
|
|
|
@ -286,6 +286,8 @@ int CEXEBuild::process_script(NIStream&Strm, const TCHAR *filename)
|
|||
}
|
||||
|
||||
#define PRINTHELP() { print_help(line.gettoken_str(0)); return PS_ERROR; }
|
||||
static void PREPROCESSONLY_BEGINCOMMENT() { extern FILE *g_output; _ftprintf(g_output,_T("!if 0 /*\n")); }
|
||||
static void PREPROCESSONLY_ENDCOMMENT() { extern FILE *g_output; _ftprintf(g_output,_T("*/\n!endif\n")); }
|
||||
|
||||
void CEXEBuild::start_ifblock()
|
||||
{
|
||||
|
@ -369,6 +371,8 @@ int CEXEBuild::doParse(const TCHAR *str)
|
|||
}
|
||||
}
|
||||
|
||||
GrowBuf ppoline;
|
||||
if (preprocessonly) m_linebuild.swap(ppoline); // LineParser strips quotes and we need to display them
|
||||
m_linebuild.resize(0);
|
||||
|
||||
if (res)
|
||||
|
@ -393,7 +397,11 @@ parse_again:
|
|||
ERROR_MSG(_T("Invalid label: %") NPRIs _T(" (labels cannot begin with !, $, -, +, or 0-9)\n"),line.gettoken_str(0));
|
||||
return PS_ERROR;
|
||||
}
|
||||
if (add_label(line.gettoken_str(0))) return PS_ERROR;
|
||||
extern FILE *g_output;
|
||||
if (preprocessonly)
|
||||
_ftprintf(g_output,_T("%") NPRIs _T("\n"),line.gettoken_str(0));
|
||||
else
|
||||
if (add_label(line.gettoken_str(0))) return PS_ERROR;
|
||||
line.eattoken();
|
||||
goto parse_again;
|
||||
}
|
||||
|
@ -616,6 +624,16 @@ parse_again:
|
|||
}
|
||||
if (!cur_ifblock || (!cur_ifblock->ignore && !cur_ifblock->inherited_ignore))
|
||||
{
|
||||
if (preprocessonly)
|
||||
{
|
||||
extern FILE *g_output;
|
||||
bool pptok = is_pp_token(tkid), docmd = pptok;
|
||||
bool both = TOK_P_VERBOSE == tkid || TOK_P_WARNING == tkid || TOK_P_ECHO == tkid;
|
||||
if (TOK_P_FINALIZE == tkid || TOK_P_PACKEXEHEADER == tkid) docmd = false;
|
||||
if (docmd && is_unsafe_pp_token(tkid) && preprocessonly > 0) docmd = false;
|
||||
if (!docmd || both) _ftprintf(g_output,(_T("%") NPRIs _T("\n")),ppoline.get());
|
||||
if (!docmd && !both) return PS_OK;
|
||||
}
|
||||
return doCommand(tkid,line);
|
||||
}
|
||||
|
||||
|
@ -1006,7 +1024,7 @@ l_errwcconv:
|
|||
return PS_OK;
|
||||
}
|
||||
|
||||
int CEXEBuild::process_oneline(TCHAR *line, const TCHAR *filename, int linenum)
|
||||
int CEXEBuild::process_oneline(const TCHAR *line, const TCHAR *filename, int linenum)
|
||||
{
|
||||
const TCHAR *last_filename = curfilename;
|
||||
int last_linecnt = linecnt;
|
||||
|
@ -3129,6 +3147,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
|
|||
}
|
||||
if (!validparams || comp == -1) PRINTHELP()
|
||||
SCRIPT_MSG(_T("%") NPRIs _T(": \"%") NPRIs _T("\"\n"),cmdname,exec);
|
||||
PREPROCESSONLY_BEGINCOMMENT();
|
||||
#ifdef _WIN32
|
||||
if (TOK_P_EXECUTE == which_token)
|
||||
{
|
||||
|
@ -3164,6 +3183,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
|
|||
ERROR_MSG(_T("%") NPRIs _T(": returned %d, aborting\n"),cmdname,ret);
|
||||
return PS_ERROR;
|
||||
}
|
||||
PREPROCESSONLY_ENDCOMMENT();
|
||||
SCRIPT_MSG(_T("%") NPRIs _T(": returned %d\n"),cmdname,ret);
|
||||
}
|
||||
return PS_OK;
|
||||
|
|
|
@ -335,10 +335,29 @@ bool CEXEBuild::is_ppbranch_token(TCHAR *s)
|
|||
case TOK_P_IFDEF: case TOK_P_IFNDEF:
|
||||
case TOK_P_IFMACRODEF: case TOK_P_IFMACRONDEF:
|
||||
return true;
|
||||
default: return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CEXEBuild::is_pp_token(int tkid)
|
||||
{
|
||||
// NOTE: This assumes that all TOK_P_* in tokens.h are grouped together.
|
||||
return (tkid >= TOK_P_IF && tkid <= TOK_P_SEARCHREPLACESTRING);
|
||||
}
|
||||
|
||||
bool CEXEBuild::is_unsafe_pp_token(int tkid)
|
||||
{
|
||||
switch(tkid)
|
||||
{
|
||||
case TOK_P_TEMPFILE: case TOK_P_APPENDFILE: case TOK_P_DELFILE:
|
||||
case TOK_P_SYSTEMEXEC: case TOK_P_EXECUTE: case TOK_P_FINALIZE:
|
||||
case TOK_P_PACKEXEHEADER:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int CEXEBuild::get_commandtoken(TCHAR *s, int *np, int *op, int *pos)
|
||||
{
|
||||
for (int x = 0; x < TOK__LAST; x ++)
|
||||
|
@ -355,16 +374,7 @@ int CEXEBuild::get_commandtoken(TCHAR *s, int *np, int *op, int *pos)
|
|||
int CEXEBuild::GetCurrentTokenPlace()
|
||||
{
|
||||
if (build_cursection)
|
||||
{
|
||||
if (build_cursection_isfunc)
|
||||
{
|
||||
return TP_FUNC;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TP_SEC;
|
||||
}
|
||||
}
|
||||
return build_cursection_isfunc ? TP_FUNC : TP_SEC;
|
||||
|
||||
if (cur_page)
|
||||
return TP_PAGEEX;
|
||||
|
@ -374,6 +384,8 @@ int CEXEBuild::GetCurrentTokenPlace()
|
|||
|
||||
int CEXEBuild::IsTokenPlacedRight(int pos, TCHAR *tok)
|
||||
{
|
||||
if (preprocessonly)
|
||||
return PS_OK;
|
||||
if ((unsigned int) pos > (sizeof(tokenlist) / sizeof(tokenType)))
|
||||
return PS_OK;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue