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:
anders_k 2014-06-19 19:06:49 +00:00
parent d91176ba49
commit 0bffaecea3
9 changed files with 99 additions and 38 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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);
}

View file

@ -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 */

View file

@ -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 "));

View file

@ -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;

View file

@ -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;