/* * script.cpp * * This file is a part of NSIS. * * Copyright (C) 1999-2009 Nullsoft and Contributors * * Licensed under the zlib/libpng license (the "License"); * you may not use this file except in compliance with the License. * * Licence details can be found in the file COPYING. * * This software is provided 'as-is', without any express or implied * warranty. */ #include "Platform.h" #include #include #include "tokens.h" #include "build.h" #include "util.h" #include "winchar.h" #include "ResourceEditor.h" #include "DialogTemplate.h" #include "lang.h" #include "dirreader.h" #include "version.h" #include "icon.h" #include "exehead/api.h" #include "exehead/resource.h" #include // for assert(3) #include #include #include #include "boost/scoped_ptr.hpp" using namespace std; #ifdef _WIN32 # include // for chdir #else # include // for stat and umask # include // for mode_t # include // for O_RDONLY # include # include // for mkstemp #endif #define MAX_INCLUDEDEPTH 10 #define MAX_LINELENGTH 16384 #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES // Added by Sunil Kamath 11 June 2003 char *CEXEBuild::set_file_predefine(char *filename) { char *oldfilename = definedlist.find("__FILE__"); if(oldfilename) { oldfilename = strdup(oldfilename); definedlist.del("__FILE__"); } char *p = strrchr(filename,'\\'); if(p) { p++; } else { p = curfilename; } definedlist.add("__FILE__",p); return oldfilename; } void CEXEBuild::restore_file_predefine(char *oldfilename) { definedlist.del("__FILE__"); if(oldfilename) { definedlist.add("__FILE__",oldfilename); free(oldfilename); } } char *CEXEBuild::set_timestamp_predefine(char *filename) { char *oldtimestamp = definedlist.find("__TIMESTAMP__"); if(oldtimestamp) { oldtimestamp = strdup(oldtimestamp); definedlist.del("__TIMESTAMP__"); } #ifdef _WIN32 char timestampbuf[256] = ""; char datebuf[128] = ""; char timebuf[128] = ""; WIN32_FIND_DATA fd; FILETIME floctime; SYSTEMTIME stime; HANDLE hSearch = FindFirstFile(filename, &fd); if (hSearch != INVALID_HANDLE_VALUE) { FindClose(hSearch); FileTimeToLocalFileTime(&fd.ftLastWriteTime, &floctime); FileTimeToSystemTime(&floctime, &stime); GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &stime, NULL, datebuf, sizeof(datebuf)); GetTimeFormat(LOCALE_USER_DEFAULT, 0, &stime, NULL, timebuf, sizeof(timebuf)); wsprintf(timestampbuf,"%s %s",datebuf,timebuf); definedlist.add("__TIMESTAMP__",timestampbuf); } #else struct stat st; if (!stat(filename, &st)) definedlist.add("__TIMESTAMP__",ctime(&st.st_mtime)); #endif return oldtimestamp; } void CEXEBuild::restore_timestamp_predefine(char *oldtimestamp) { definedlist.del("__TIMESTAMP__"); if(oldtimestamp) { definedlist.add("__TIMESTAMP__",oldtimestamp); free(oldtimestamp); } } char *CEXEBuild::set_line_predefine(int linecnt, BOOL is_macro) { char* linebuf = NULL; MANAGE_WITH(linebuf, free); char temp[128] = ""; sprintf(temp,"%d",linecnt); char *oldline = definedlist.find("__LINE__"); if(oldline) { oldline = strdup(oldline); definedlist.del("__LINE__"); } if(is_macro && oldline) { linebuf = (char *)malloc(strlen(oldline)+strlen(temp)+2); sprintf(linebuf,"%s.%s",oldline,temp); } else { linebuf = strdup(temp); } definedlist.add("__LINE__",linebuf); return oldline; } void CEXEBuild::restore_line_predefine(char *oldline) { definedlist.del("__LINE__"); if(oldline) { definedlist.add("__LINE__",oldline); free(oldline); } } void CEXEBuild::set_date_time_predefines() { time_t etime; struct tm * ltime; char datebuf[128]; char timebuf[128]; time(&etime); ltime = localtime(&etime); #ifdef _WIN32 SYSTEMTIME stime; stime.wYear = ltime->tm_year+1900; stime.wMonth = ltime->tm_mon + 1; stime.wDay = ltime->tm_mday; stime.wHour= ltime->tm_hour; stime.wMinute= ltime->tm_min; stime.wSecond= ltime->tm_sec; stime.wMilliseconds= 0; GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &stime, NULL, datebuf, sizeof(datebuf)); definedlist.add("__DATE__",(char *)datebuf); GetTimeFormat(LOCALE_USER_DEFAULT, 0, &stime, NULL, timebuf, sizeof(timebuf)); definedlist.add("__TIME__",(char *)timebuf); #else my_strftime(datebuf, sizeof(datebuf), "%x", ltime); definedlist.add("__DATE__",(char *)datebuf); my_strftime(timebuf, sizeof(timebuf), "%X", ltime); definedlist.add("__TIME__",(char *)timebuf); #endif } void CEXEBuild::del_date_time_predefines() { definedlist.del("__DATE__"); definedlist.del("__TIME__"); } #endif int CEXEBuild::process_script(FILE *filepointer, char *filename) { linecnt = 0; fp = filepointer; curfilename = filename; if (has_called_write_output) { ERROR_MSG("Error (process_script): write_output already called, can't continue\n"); return PS_ERROR; } #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES // Added by Sunil Kamath 11 June 2003 set_date_time_predefines(); char *oldfilename = set_file_predefine(curfilename); char *oldtimestamp = set_timestamp_predefine(curfilename); #endif int ret=parseScript(); #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES // Added by Sunil Kamath 11 June 2003 restore_file_predefine(oldfilename); restore_timestamp_predefine(oldtimestamp); del_date_time_predefines(); #endif fp = 0; curfilename = 0; if (m_linebuild.getlen()) { ERROR_MSG("Error: invalid script: last line ended with \\\n"); return PS_ERROR; } if (ret == PS_EOF && num_ifblock()) { ERROR_MSG("!if[macro][n]def: open at EOF - need !endif\n"); return PS_ERROR; } return ret; } #define PRINTHELP() { print_help(line.gettoken_str(0)); return PS_ERROR; } void CEXEBuild::start_ifblock() { ifblock ib = {0, }; if (cur_ifblock) ib.inherited_ignore = cur_ifblock->ignore || cur_ifblock->inherited_ignore; int num = build_preprocessor_data.getlen() / sizeof(ifblock); build_preprocessor_data.add(&ib, sizeof(ifblock)); cur_ifblock = (ifblock *) build_preprocessor_data.get() + num; } void CEXEBuild::end_ifblock() { if (build_preprocessor_data.getlen()) { cur_ifblock--; build_preprocessor_data.resize(build_preprocessor_data.getlen() - sizeof(ifblock)); if (!build_preprocessor_data.getlen()) cur_ifblock = 0; } } int CEXEBuild::num_ifblock() { return build_preprocessor_data.getlen() / sizeof(ifblock); } // Func size: just under 200 lines (orip) int CEXEBuild::doParse(const char *str) { LineParser line(inside_comment); int res; while (*str == ' ' || *str == '\t') str++; // remove trailing slash and null, if there's a previous line if (m_linebuild.getlen()>1) m_linebuild.resize(m_linebuild.getlen()-2); // warn of comment with line-continuation if (m_linebuild.getlen()) { LineParser prevline(inside_comment); prevline.parse((char*)m_linebuild.get()); LineParser thisline(inside_comment); thisline.parse((char*)str); if (prevline.inComment() && !thisline.inComment()) { warning_fl("comment contains line-continuation character, following line will be ignored"); } } // add new line to line buffer m_linebuild.add(str,strlen(str)+1); // keep waiting for more lines, if this line ends with a backslash if (str[0] && CharPrev(str,str+strlen(str))[0] == '\\') { return PS_OK; } // parse before checking if the line should be ignored, so block comments won't be missed // escaped quotes should be ignored for compile time commands that set defines // because defines can be inserted in commands at a later stage bool ignore_escaping = (!strnicmp((char*)m_linebuild.get(),"!define",7) || !strnicmp((char*)m_linebuild.get(),"!insertmacro",12)); res=line.parse((char*)m_linebuild.get(), ignore_escaping); inside_comment = line.inCommentBlock(); // if ignoring, ignore all lines that don't begin with an exclamation mark { bool ignore_line = cur_ifblock && (cur_ifblock->ignore || cur_ifblock->inherited_ignore); char first_char = *(char *) m_linebuild.get(); if (ignore_line && (first_char!='!' || !is_valid_token(line.gettoken_str(0)))) { m_linebuild.resize(0); return PS_OK; } } m_linebuild.resize(0); if (res) { if (res==-2) ERROR_MSG("Error: unterminated string parsing line at %s:%d\n",curfilename,linecnt); else ERROR_MSG("Error: error parsing line (%s:%d)\n",curfilename,linecnt); return PS_ERROR; } parse_again: if (line.getnumtokens() < 1) return PS_OK; int np,op,pos; int tkid=get_commandtoken(line.gettoken_str(0),&np,&op,&pos); if (tkid == -1) { char *p=line.gettoken_str(0); if (p[0] && p[strlen(p)-1]==':') { if (p[0] == '!' || (p[0] >= '0' && p[0] <= '9') || p[0] == '$' || p[0] == '-' || p[0] == '+') { ERROR_MSG("Invalid label: %s (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; line.eattoken(); goto parse_again; } #ifdef NSIS_CONFIG_PLUGIN_SUPPORT // Added by Ximon Eighteen 5th August 2002 // We didn't recognise this command, could it be the name of a // function exported from a dll? if (m_plugins.IsPluginCommand(line.gettoken_str(0))) { np = 0; // parameters are optional op = -1; // unlimited number of optional parameters pos = -1; // placement will tested later tkid = TOK__PLUGINCOMMAND; } else #endif { ERROR_MSG("Invalid command: %s\n",line.gettoken_str(0)); return PS_ERROR; } } if (IsTokenPlacedRight(pos, line.gettoken_str(0)) != PS_OK) return PS_ERROR; int v=line.getnumtokens()-(np+1); if (v < 0 || (op >= 0 && v > op)) // opt_parms is -1 for unlimited { ERROR_MSG("%s expects %d",line.gettoken_str(0),np); if (op < 0) ERROR_MSG("+"); if (op > 0) ERROR_MSG("-%d",op+np); ERROR_MSG(" parameters, got %d.\n",line.getnumtokens()-1); PRINTHELP() } int if_from_else = 0; if (tkid == TOK_P_ELSE) { if (cur_ifblock && cur_ifblock->inherited_ignore) return PS_OK; if (!num_ifblock()) { 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; } if (cur_ifblock->hasexeced) { cur_ifblock->ignore++; return PS_OK; } if (line.getnumtokens() == 1) { cur_ifblock->ignore = !cur_ifblock->ignore; // if not executed up until now, it will now cur_ifblock->hasexeced++; cur_ifblock->elseused++; return PS_OK; } line.eattoken(); 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_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_IF) { if (!if_from_else) start_ifblock(); if (cur_ifblock && cur_ifblock->inherited_ignore) { return PS_OK; } int istrue=0; int mod=0; int p=0; if (tkid == TOK_P_IF) { if(!strcmp(line.gettoken_str(1),"!")) { p = 1; line.eattoken(); } 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 = stricmp(line.gettoken_str(1),line.gettoken_str(3)) == 0; break; case 2: istrue = stricmp(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 ++) { 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; } } } if (istrue) { cur_ifblock->hasexeced++; cur_ifblock->ignore = 0; } else cur_ifblock->ignore++; return PS_OK; } if (tkid == TOK_P_ENDIF) { if (!num_ifblock()) { ERROR_MSG("!endif: no if block open (!if[macro][n][def])\n"); return PS_ERROR; } end_ifblock(); return PS_OK; } if (!cur_ifblock || (!cur_ifblock->ignore && !cur_ifblock->inherited_ignore)) { return doCommand(tkid,line); } return PS_OK; } // Func size: about 140 lines (orip) #ifdef NSIS_FIX_DEFINES_IN_STRINGS void CEXEBuild::ps_addtoline(const char *str, GrowBuf &linedata, StringList &hist, bool bIgnoreDefines /*= false*/) #else void CEXEBuild::ps_addtoline(const char *str, GrowBuf &linedata, StringList &hist) #endif { // convert $\r, $\n to their literals // preprocessor replace ${VAR} and $%VAR% with whatever value // note that if VAR does not exist, ${VAR} or $%VAR% will go through unmodified const char *in=str; while (*in) { int add=1; char *t; char c=*in; t=CharNext(in); if (t-in > 1) // handle multibyte chars (no escape) { linedata.add((void*)in,t-in); in=t; continue; } in=t; if (c == '$') { if (in[0] == '\\') { if (in[1] == 'r') { in+=2; c='\r'; } else if (in[1] == 'n') { in+=2; c='\n'; } else if (in[1] == 't') { in+=2; c='\t'; } } else if (in[0] == '{') { char *s=strdup(in+1); MANAGE_WITH(s, free); char *t=s; unsigned int bn = 0; while (*t) { if (*t == '{') bn++; if (*t == '}' && bn-- == 0) break; t=CharNext(t); } if (*t && t!=s #ifdef NSIS_FIX_DEFINES_IN_STRINGS && !bIgnoreDefines #endif ) { *t=0; // check for defines inside the define name - ${bla${blo}} GrowBuf defname; ps_addtoline(s,defname,hist); defname.add("",1); t=definedlist.find((char*)defname.get()); if (t && hist.find((char*)defname.get(),0)<0) { in+=strlen(s)+2; add=0; hist.add((char*)defname.get(),0); #ifdef NSIS_FIX_DEFINES_IN_STRINGS ps_addtoline(t,linedata,hist,true); #else ps_addtoline(t,linedata,hist); #endif hist.delbypos(hist.find((char*)defname.get(),0)); } } } else if (in[0] == '%') { char *s=strdup(in+1); MANAGE_WITH(s, free); char *t=s; while (*t) { if (*t == '%') break; t=CharNext(t); } if (*t && t!=s) { *t=0; // check for defines inside the define name - ${bla${blo}} GrowBuf defname; ps_addtoline(s,defname,hist); defname.add("",1); t=getenv((char*)defname.get()); if (t && hist.find((char*)defname.get(),0)<0) { in+=strlen(s)+2; add=0; hist.add((char*)defname.get(),0); #ifdef NSIS_FIX_DEFINES_IN_STRINGS ps_addtoline(t,linedata,hist,true); #else ps_addtoline(t,linedata,hist); #endif hist.delbypos(hist.find((char*)defname.get(),0)); } } } #ifdef NSIS_FIX_DEFINES_IN_STRINGS else if (in[0] == '$') { if (in[1] == '{') // Found $$ before - Don't replace this define { char *s=strdup(in+2); MANAGE_WITH(s, free); char *t=s; unsigned int bn = 0; while (*t) { if (*t == '{') bn++; if (*t == '}' && bn-- == 0) break; t=CharNext(t); } if (*t && t!=s) { *t=0; // add text unchanged GrowBuf defname; ps_addtoline(s,defname,hist); in++; } } else { linedata.add((void*)&c,1); in++; } } #endif } if (add) linedata.add((void*)&c,1); } } int CEXEBuild::parseScript() { char str[MAX_LINELENGTH]; for (;;) { char *p=str; *p=0; fgets(str,MAX_LINELENGTH,fp); linecnt++; if (feof(fp)&&!str[0]) break; // remove trailing whitespace while (*p) p++; if (p > str) p--; while (p >= str && (*p == '\r' || *p == '\n' || *p == ' ' || *p == '\t')) p--; *++p=0; StringList hist; GrowBuf linedata; #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES // Added by Sunil Kamath 11 June 2003 char *oldline = set_line_predefine(linecnt, FALSE); #endif ps_addtoline(str,linedata,hist); linedata.add((void*)"",1); int ret=doParse((char*)linedata.get()); #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES // Added by Sunil Kamath 11 June 2003 restore_line_predefine(oldline); #endif if (ret != PS_OK) return ret; } return PS_EOF; } int CEXEBuild::includeScript(char *f) { SCRIPT_MSG("!include: \"%s\"\n",f); FILE *incfp=FOPEN(f,"rt"); if (!incfp) { ERROR_MSG("!include: could not open file: \"%s\"\n",f); return PS_ERROR; } // auto-fclose(3) incfp MANAGE_WITH(incfp, fclose); if (build_include_depth >= MAX_INCLUDEDEPTH) { ERROR_MSG("parseScript: too many levels of includes (%d max).\n",MAX_INCLUDEDEPTH); return PS_ERROR; } build_include_depth++; int last_linecnt=linecnt; linecnt=0; char *last_filename=curfilename; curfilename=f; FILE *last_fp=fp; fp=incfp; #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES // Added by Sunil Kamath 11 June 2003 char *oldfilename = set_file_predefine(curfilename); char *oldtimestamp = set_timestamp_predefine(curfilename); #endif int r=parseScript(); #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES // Added by Sunil Kamath 11 June 2003 restore_file_predefine(oldfilename); restore_timestamp_predefine(oldtimestamp); #endif int errlinecnt=linecnt; linecnt=last_linecnt; curfilename=last_filename; fp=last_fp; build_include_depth--; if (r != PS_EOF && r != PS_OK) { ERROR_MSG("!include: error in script: \"%s\" on line %d\n",f,errlinecnt); return PS_ERROR; } SCRIPT_MSG("!include: closed: \"%s\"\n",f); return PS_OK; } // !ifmacro[n]def based on Anders Kjersem's code int CEXEBuild::MacroExists(const char *macroname) { char *m = (char *) m_macros.get(); while (m && *m) { // check if macroname matches if (!stricmp(m, macroname)) return 1; // skip macro name m += strlen(m) + 1; // skip params while (*m) m += strlen(m) + 1; m++; // skip data while (*m) m += strlen(m) + 1; if (m - (char *) m_macros.get() >= m_macros.getlen() - 1) break; m++; } return 0; } int CEXEBuild::process_oneline(char *line, char *filename, int linenum) { char *last_filename=curfilename; curfilename=filename; int last_linecnt=linecnt; linecnt=linenum; StringList hist; GrowBuf linedata; #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES // Added by Sunil Kamath 11 June 2003 char *oldfilename = NULL; char *oldtimestamp = NULL; char *oldline = NULL; BOOL is_commandline = !strcmp(filename,"command line"); BOOL is_macro = !strncmp(filename,"macro:",strlen("macro:")); if(!is_commandline) { // Don't set the predefines for command line /X option if(!is_macro) { oldfilename = set_file_predefine(curfilename); oldtimestamp = set_timestamp_predefine(curfilename); } oldline = set_line_predefine(linecnt, is_macro); } #endif ps_addtoline(line,linedata,hist); linedata.add((void*)"",1); int ret=doParse((char*)linedata.get()); #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES // Added by Sunil Kamath 11 June 2003 if(!is_commandline) { // Don't set the predefines for command line /X option if(!is_macro) { restore_file_predefine(oldfilename); restore_timestamp_predefine(oldtimestamp); } restore_line_predefine(oldline); } #endif linecnt=last_linecnt; curfilename=last_filename; return ret; } int CEXEBuild::process_jump(LineParser &line, int wt, int *offs) { const char *s=line.gettoken_str(wt); int v; if (!stricmp(s,"0") || !stricmp(s,"")) *offs=0; else if ((v=GetUserVarIndex(line, wt))>=0) { *offs=-v-1; // to jump to a user variable target, -variable_index-1 is stored. } else { if ((s[0] == '-' || s[0] == '+') && !atoi(s+1)) { ERROR_MSG("Error: Goto targets beginning with '+' or '-' must be followed by nonzero integer (relative jump)\n"); return 1; } if ((s[0] >= '0' && s[0] <= '9') || s[0] == '$' || s[0] == '!') { ERROR_MSG("Error: Goto targets cannot begin with 0-9, $, !\n"); return 1; } *offs=ns_label.add(s,0); } return 0; } #define FLAG_OFFSET(flag) (FIELD_OFFSET(exec_flags_t, flag)/sizeof(int)) #define SECTION_FIELD_GET(field) (FIELD_OFFSET(section, field)/sizeof(int)) #define SECTION_FIELD_SET(field) (-1 - (int)(FIELD_OFFSET(section, field)/sizeof(int))) // Func size: about 5000 lines (orip) int CEXEBuild::doCommand(int which_token, LineParser &line) { static const char *rootkeys[2] = { "HKCR\0HKLM\0HKCU\0HKU\0HKCC\0HKDD\0HKPD\0SHCTX\0", "HKEY_CLASSES_ROOT\0HKEY_LOCAL_MACHINE\0HKEY_CURRENT_USER\0HKEY_USERS\0HKEY_CURRENT_CONFIG\0HKEY_DYN_DATA\0HKEY_PERFORMANCE_DATA\0SHELL_CONTEXT\0" }; static HKEY rootkey_tab[] = { HKEY_CLASSES_ROOT,HKEY_LOCAL_MACHINE,HKEY_CURRENT_USER,HKEY_USERS,HKEY_CURRENT_CONFIG,HKEY_DYN_DATA,HKEY_PERFORMANCE_DATA,0 }; #ifdef NSIS_CONFIG_PLUGIN_SUPPORT build_plugin_table(); #endif multiple_entries_instruction=0; entry ent={0,}; switch (which_token) { // macro shit /////////////////////////////////////////////////////////////////////////////// case TOK_P_MACRO: { if (!line.gettoken_str(1)[0]) PRINTHELP() char *t=(char *)m_macros.get(); while (t && *t) { if (!stricmp(t,line.gettoken_str(1))) break; t+=strlen(t)+1; // advance over parameters while (*t) t+=strlen(t)+1; t++; // advance over data while (*t) t+=strlen(t)+1; if (t-(char *)m_macros.get() >= m_macros.getlen()-1) break; t++; } if (t && *t) { ERROR_MSG("!macro: macro named \"%s\" already found!\n",line.gettoken_str(1)); return PS_ERROR; } m_macros.add(line.gettoken_str(1),strlen(line.gettoken_str(1))+1); int pc; for (pc=2; pc < line.getnumtokens(); pc ++) { if (!line.gettoken_str(pc)[0]) { ERROR_MSG("!macro: macro parameter %d is empty, not valid!\n",pc-1); return PS_ERROR; } int a; for (a=2; a < pc; a ++) { if (!stricmp(line.gettoken_str(pc),line.gettoken_str(a))) { ERROR_MSG("!macro: macro parameter named %s is used multiple times!\n", line.gettoken_str(pc)); return PS_ERROR; } } m_macros.add(line.gettoken_str(pc),strlen(line.gettoken_str(pc))+1); } m_macros.add("",1); for (;;) { char str[MAX_LINELENGTH]; char *p=str; str[0]=0; fgets(str,MAX_LINELENGTH,fp); //SCRIPT_MSG("%s%s", str, str[strlen(str)-1]=='\n'?"":"\n"); if (feof(fp) && !str[0]) { ERROR_MSG("!macro \"%s\": unterminated (no !macroend found in file)!\n",line.gettoken_str(1)); return PS_ERROR; } // remove trailing whitespace while (*p) p++; if (p > str) p--; while (p >= str && (*p == '\r' || *p == '\n' || *p == ' ' || *p == '\t')) p--; *++p=0; LineParser l2(false); if (!l2.parse(str)) { if (!stricmp(l2.gettoken_str(0),"!macroend")) { linecnt++; break; } if (!stricmp(l2.gettoken_str(0),"!macro")) { ERROR_MSG("Error: can't define a macro inside a macro!\n"); return PS_ERROR; } } if (str[0]) m_macros.add(str,strlen(str)+1); else m_macros.add(" ",2); linecnt++; } m_macros.add("",1); } return PS_OK; case TOK_P_MACROEND: ERROR_MSG("!macroend: no macro currently open.\n"); return PS_ERROR; case TOK_P_INSERTMACRO: { if (!line.gettoken_str(1)[0]) PRINTHELP() char *t=(char *)m_macros.get(); char *m=t; while (t && *t) { if (!stricmp(t,line.gettoken_str(1))) break; t+=strlen(t)+1; // advance over parms while (*t) t+=strlen(t)+1; t++; // advance over data while (*t) t+=strlen(t)+1; if (t-(char *)m_macros.get() >= m_macros.getlen()-1) break; t++; } SCRIPT_MSG("!insertmacro: %s\n",line.gettoken_str(1)); if (!t || !*t) { ERROR_MSG("!insertmacro: macro named \"%s\" not found!\n",line.gettoken_str(1)); return PS_ERROR; } t+=strlen(t)+1; GrowBuf l_define_names; DefineList l_define_saves; int npr=0; // advance over parms while (*t) { char *v=definedlist.find(t); if (v) { l_define_saves.add(t,v); definedlist.del(t); } l_define_names.add(t,strlen(t)+1); definedlist.add(t,line.gettoken_str(npr+2)); npr++; t+=strlen(t)+1; } l_define_names.add("",1); t++; if (npr != line.getnumtokens()-2) { ERROR_MSG("!insertmacro: macro \"%s\" requires %d parameter(s), passed %d!\n", line.gettoken_str(1),npr,line.getnumtokens()-2); return PS_ERROR; } int lp=0; char str[1024]; if (m_macro_entry.find(line.gettoken_str(1),0)>=0) { ERROR_MSG("!insertmacro: macro \"%s\" already being inserted!\n",line.gettoken_str(1)); return PS_ERROR; } int npos=m_macro_entry.add(line.gettoken_str(1),0); wsprintf(str,"macro:%s",line.gettoken_str(1)); while (*t) { lp++; if (strcmp(t," ")) { int ret=process_oneline(t,str,lp); if (ret != PS_OK) { ERROR_MSG("Error in macro %s on macroline %d\n",line.gettoken_str(1),lp); return ret; } } { // fix t if process_oneline changed m_macros char *nm=(char *)m_macros.get(); if (nm != m) { t += nm - m; m = nm; } } t+=strlen(t)+1; } m_macro_entry.delbypos(npos); { char *p=(char*)l_define_names.get(); while (*p) { definedlist.del(p); char *v; if ((v=l_define_saves.find(p))) definedlist.add(p,v); p+=strlen(p)+1; } } SCRIPT_MSG("!insertmacro: end of %s\n",line.gettoken_str(1)); } return PS_OK; // preprocessor files fun /////////////////////////////////////////////////////////////////////////////// case TOK_P_TEMPFILE: { char *symbol = line.gettoken_str(1); char *fpath; #ifdef _WIN32 char buf[MAX_PATH], buf2[MAX_PATH]; GetTempPath(MAX_PATH, buf); if (!GetTempFileName(buf, "nst", 0, buf2)) { ERROR_MSG("!tempfile: unable to create temporary file.\n"); return PS_ERROR; } fpath = buf2; #else char t[] = "/tmp/makensisXXXXXX"; mode_t old_umask = umask(0077); int fd = mkstemp(t); if (fd == -1) { ERROR_MSG("!tempfile: unable to create temporary file.\n"); return PS_ERROR; } close(fd); umask(old_umask); fpath = t; #endif if (definedlist.add(symbol, fpath)) { ERROR_MSG("!tempfile: \"%s\" already defined!\n", symbol); return PS_ERROR; } SCRIPT_MSG("!tempfile: \"%s\"=\"%s\"\n", symbol, fpath); } return PS_OK; case TOK_P_DELFILE: { char *file = line.gettoken_str(1); #ifndef _WIN32 file = my_convert(file); #endif int result = unlink(file); #ifndef _WIN32 my_convert_free(file); #endif if (result == -1) { ERROR_MSG("!delfile: \"%s\" couldn't be deleted.\n", line.gettoken_str(1)); return PS_ERROR; } SCRIPT_MSG("!delfile: \"%s\"\n", line.gettoken_str(1)); } return PS_OK; case TOK_P_APPENDFILE: { char *file = line.gettoken_str(1); char *text = line.gettoken_str(2); FILE *fp = FOPEN(file, "a"); if (!fp) { ERROR_MSG("!appendfile: \"%s\" couldn't be opened.\n", file); return PS_ERROR; } if (fputs(text, fp) < 0) { ERROR_MSG("!appendfile: error writing to \"%s\".\n", file); return PS_ERROR; } fclose(fp); SCRIPT_MSG("!appendfile: \"%s\" \"%s\"\n", file, text); } return PS_OK; // page ordering shit /////////////////////////////////////////////////////////////////////////////// #ifdef NSIS_CONFIG_VISIBLE_SUPPORT case TOK_UNINSTPAGE: set_uninstall_mode(1); case TOK_PAGE: { if (!uninstall_mode) { enable_last_page_cancel = 0; if (!stricmp(line.gettoken_str(line.getnumtokens()-1),"/ENABLECANCEL")) enable_last_page_cancel = 1; } else { uenable_last_page_cancel = 0; if (!stricmp(line.gettoken_str(line.getnumtokens()-1),"/ENABLECANCEL")) uenable_last_page_cancel = 1; } int k = line.gettoken_enum(1,"custom\0license\0components\0directory\0instfiles\0uninstConfirm\0"); if (k < 0) PRINTHELP(); if (add_page(k) != PS_OK) return PS_ERROR; #ifndef NSIS_SUPPORT_CODECALLBACKS if (!k) { ERROR_MSG("Error: custom page specified, NSIS_SUPPORT_CODECALLBACKS not defined.\n"); return PS_ERROR; } #endif//!NSIS_SUPPORT_CODECALLBACKS if (k) { // not custom #ifdef NSIS_SUPPORT_CODECALLBACKS switch (line.getnumtokens() - enable_last_page_cancel) { case 6: PRINTHELP(); case 5: if (*line.gettoken_str(4)) cur_page->leavefunc = ns_func.add(line.gettoken_str(4),0); case 4: if (*line.gettoken_str(3)) cur_page->showfunc = ns_func.add(line.gettoken_str(3),0); case 3: if (*line.gettoken_str(2)) cur_page->prefunc = ns_func.add(line.gettoken_str(2),0); } #endif//NSIS_SUPPORT_CODECALLBACKS } #ifdef NSIS_SUPPORT_CODECALLBACKS else { // a custom page switch (line.getnumtokens() - enable_last_page_cancel) { case 6: PRINTHELP(); case 5: cur_page->caption = add_string(line.gettoken_str(4)); case 4: if (*line.gettoken_str(3)) cur_page->leavefunc = ns_func.add(line.gettoken_str(3),0); case 3: if (*line.gettoken_str(2)) cur_page->prefunc = ns_func.add(line.gettoken_str(2),0); break; case 2: ERROR_MSG("Error: custom page must have a creator function!\n"); PRINTHELP(); } } #endif//NSIS_SUPPORT_CODECALLBACKS SCRIPT_MSG("%sPage: %s", uninstall_mode?"Uninst":"", line.gettoken_str(1)); #ifdef NSIS_SUPPORT_CODECALLBACKS if (cur_page->prefunc>=0) SCRIPT_MSG(" (%s:%s)", k?"pre":"creator", line.gettoken_str(2)); if (cur_page->showfunc>=0 && k) SCRIPT_MSG(" (show:%s)", line.gettoken_str(3)); if (cur_page->leavefunc>=0) SCRIPT_MSG(" (leave:%s)", line.gettoken_str(4-!k)); else if (cur_page->caption && !k) SCRIPT_MSG(" (caption:%s)", line.gettoken_str(3)); #endif SCRIPT_MSG("\n"); page_end(); if (k == PAGE_INSTFILES) { add_page(PAGE_COMPLETED); page_end(); } set_uninstall_mode(0); } return PS_OK; // extended page setting case TOK_PAGEEX: { int k = line.gettoken_enum(1,"custom\0license\0components\0directory\0instfiles\0uninstConfirm\0"); if (k < 0) { k = line.gettoken_enum(1,"un.custom\0un.license\0un.components\0un.directory\0un.instfiles\0un.uninstConfirm\0"); if (k < 0) PRINTHELP(); set_uninstall_mode(1); } SCRIPT_MSG("PageEx: %s\n", line.gettoken_str(1)); if (add_page(k) != PS_OK) return PS_ERROR; cur_page->flags |= PF_PAGE_EX; } return PS_OK; case TOK_PAGEEXEND: { SCRIPT_MSG("PageExEnd\n"); #ifdef NSIS_SUPPORT_CODECALLBACKS if (cur_page_type == PAGE_CUSTOM && !cur_page->prefunc) { ERROR_MSG("Error: custom pages must have a creator function.\n"); return PS_ERROR; } #endif page_end(); if (cur_page_type == PAGE_INSTFILES) { add_page(PAGE_COMPLETED); page_end(); } set_uninstall_mode(0); } return PS_OK; case TOK_PAGECALLBACKS: #ifdef NSIS_SUPPORT_CODECALLBACKS { SCRIPT_MSG("PageCallbacks:"); if (cur_page_type == PAGE_CUSTOM) { switch (line.getnumtokens()) { case 4: { PRINTHELP(); } case 3: { if (*line.gettoken_str(2)) { if (strnicmp(line.gettoken_str(2), "un.", 3)) { if (uninstall_mode) { ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n"); return PS_ERROR; } } else { if (!uninstall_mode) { ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n"); return PS_ERROR; } } cur_page->leavefunc = ns_func.add(line.gettoken_str(2),0); } } case 2: { if (*line.gettoken_str(1)) { if (strnicmp(line.gettoken_str(1), "un.", 3)) { if (uninstall_mode) { ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n"); return PS_ERROR; } } else { if (!uninstall_mode) { ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n"); return PS_ERROR; } } cur_page->prefunc = ns_func.add(line.gettoken_str(1),0); } } } } else { switch (line.getnumtokens()) { case 4: { if (*line.gettoken_str(3)) { if (strnicmp(line.gettoken_str(3), "un.", 3)) { if (uninstall_mode) { ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n"); return PS_ERROR; } } else { if (!uninstall_mode) { ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n"); return PS_ERROR; } } cur_page->leavefunc = ns_func.add(line.gettoken_str(3),0); } } case 3: { if (*line.gettoken_str(2)) { if (strnicmp(line.gettoken_str(2), "un.", 3)) { if (uninstall_mode) { ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n"); return PS_ERROR; } } else { if (!uninstall_mode) { ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n"); return PS_ERROR; } } cur_page->showfunc = ns_func.add(line.gettoken_str(2),0); } } case 2: { if (*line.gettoken_str(1)) { if (strnicmp(line.gettoken_str(1), "un.", 3)) { if (uninstall_mode) { ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n"); return PS_ERROR; } } else { if (!uninstall_mode) { ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n"); return PS_ERROR; } } cur_page->prefunc = ns_func.add(line.gettoken_str(1),0); } } } } int custom = cur_page_type == PAGE_CUSTOM ? 1 : 0; if (cur_page->prefunc>=0) SCRIPT_MSG(" %s:%s", !custom?"pre":"creator", line.gettoken_str(1)); if (cur_page->showfunc>=0 && !custom) SCRIPT_MSG(" show:%s", line.gettoken_str(2)); if (cur_page->leavefunc>=0) SCRIPT_MSG(" leave:%s", line.gettoken_str(3-custom)); SCRIPT_MSG("\n"); } return PS_OK; #else ERROR_MSG("Error: %s specified, NSIS_SUPPORT_CODECALLBACKS not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//NSIS_SUPPORT_CODECALLBACKS #else case TOK_PAGE: case TOK_UNINSTPAGE: case TOK_PAGEEX: case TOK_PAGEEXEND: case TOK_PAGECALLBACKS: ERROR_MSG("Error: %s specified, NSIS_CONFIG_VISIBLE_SUPPORT not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//NSIS_CONFIG_VISIBLE_SUPPORT // header flags /////////////////////////////////////////////////////////////////////////////// case TOK_LANGSTRING: { char *name = line.gettoken_str(1); LANGID lang = line.gettoken_int(2); char *str = line.gettoken_str(3); int ret = SetLangString(name, lang, str); if (ret == PS_WARNING) warning_fl("LangString \"%s\" set multiple times for %d, wasting space", name, lang); else if (ret == PS_ERROR) { ERROR_MSG("Error: can't set LangString \"%s\"!\n", name); return PS_ERROR; } SCRIPT_MSG("LangString: \"%s\" %d \"%s\"\n", name, lang, str); } return PS_OK; case TOK_LANGSTRINGUP: SCRIPT_MSG("Error: LangStringUP is obsolete, there are no more unprocessed strings. Use LangString.\n"); return PS_ERROR; case TOK_LICENSELANGSTRING: { #ifdef NSIS_CONFIG_SILENT_SUPPORT if (build_header.flags&(CH_FLAGS_SILENT|CH_FLAGS_SILENT_LOG)) { warning_fl("LicenseLangString: SilentInstall enabled, wasting space"); } #endif char *name = line.gettoken_str(1); LANGID lang = line.gettoken_int(2); char *file = line.gettoken_str(3); FILE *fp; unsigned int datalen; fp=FOPEN(file,"rb"); if (!fp) { ERROR_MSG("LicenseLangString: open failed \"%s\"\n",file); PRINTHELP() } MANAGE_WITH(fp, fclose); fseek(fp,0,SEEK_END); datalen=ftell(fp); if (!datalen) { ERROR_MSG("LicenseLangString: empty license file \"%s\"\n",file); return PS_ERROR; } rewind(fp); char *data=(char*)malloc(datalen+2); if (!data) { ERROR_MSG("Internal compiler error #12345: LicenseData malloc(%d) failed.\n", datalen+2); return PS_ERROR; } MANAGE_WITH(data, free); char *ldata=data+1; if (fread(ldata,1,datalen,fp) != datalen) { ERROR_MSG("LicenseLangString: can't read file.\n"); return PS_ERROR; } ldata[datalen]=0; if (!strncmp(ldata,"{\\rtf",sizeof("{\\rtf")-1)) *data = SF_RTF; else *data = SF_TEXT; int ret = SetLangString(name, lang, data); if (ret == PS_WARNING) warning_fl("LicenseLangString \"%s\" set multiple times for %d, wasting space", name, lang); else if (ret == PS_ERROR) { ERROR_MSG("Error: can't set LicenseLangString \"%s\"!\n", name); return PS_ERROR; } SCRIPT_MSG("LicenseLangString: \"%s\" %d \"%s\"\n", name, lang, file); } return PS_OK; case TOK_NAME: { if (SetInnerString(NLF_NAME,line.gettoken_str(1)) == PS_WARNING) warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0)); SetInnerString(NLF_NAME_DA,line.gettoken_str(2)); SCRIPT_MSG("Name: \"%s\"",line.gettoken_str(1)); if (*line.gettoken_str(2)) SCRIPT_MSG(" \"%s\"",line.gettoken_str(2)); SCRIPT_MSG("\n"); } return PS_OK; case TOK_CAPTION: { if (!cur_page) { if (SetInnerString(NLF_CAPTION,line.gettoken_str(1)) == PS_WARNING) warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0)); } else { cur_page->caption = add_string(line.gettoken_str(1)); } SCRIPT_MSG("Caption: \"%s\"\n",line.gettoken_str(1)); } return PS_OK; case TOK_ICON: SCRIPT_MSG("Icon: \"%s\"\n",line.gettoken_str(1)); try { free_loaded_icon(installer_icon); installer_icon = load_icon_file(line.gettoken_str(1)); } catch (exception& err) { ERROR_MSG("Error while loading icon from \"%s\": %s\n", line.gettoken_str(1), err.what()); return PS_ERROR; } return PS_OK; #ifdef NSIS_CONFIG_COMPONENTPAGE case TOK_CHECKBITMAP: SCRIPT_MSG("CheckBitmap: \"%s\"\n",line.gettoken_str(1)); try { init_res_editor(); int err = update_bitmap(res_editor, IDB_BITMAP1, line.gettoken_str(1), 96, 16, 8); if (err) { switch (err) { case -1: ERROR_MSG("Error: can't find bitmap\n"); break; case -2: ERROR_MSG("Error: invalid bitmap file - corrupted or not a bitmap\n"); break; case -3: ERROR_MSG("Error: bitmap isn't 96x16 in size\n"); break; case -4: ERROR_MSG("Error: bitmap has more than 8bpp\n"); break; } return PS_ERROR; } } catch (exception& err) { ERROR_MSG("Error while replacing bitmap: %s\n", err.what()); return PS_ERROR; } return PS_OK; #else//NSIS_CONFIG_COMPONENTPAGE case TOK_CHECKBITMAP: ERROR_MSG("Error: %s specified, NSIS_CONFIG_COMPONENTPAGE not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_CONFIG_COMPONENTPAGE case TOK_DIRTEXT: #ifdef NSIS_CONFIG_VISIBLE_SUPPORT { if (!cur_page) { if (SetInnerString(NLF_DIR_TEXT, line.gettoken_str(1)) == PS_WARNING) warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0)); if (line.getnumtokens() > 2) SetInnerString(NLF_DIR_SUBTEXT, line.gettoken_str(2)); if (line.getnumtokens() > 3) SetInnerString(NLF_BTN_BROWSE, line.gettoken_str(3)); if (line.getnumtokens() > 4) SetInnerString(NLF_DIR_BROWSETEXT, line.gettoken_str(4)); } else { if (cur_page_type != PAGE_DIRECTORY) { ERROR_MSG("Error: DirText can only be used inside PageEx directory.\n"); return PS_ERROR; } cur_page->parms[0] = add_string(line.gettoken_str(1)); if (line.getnumtokens() > 2) cur_page->parms[1] = add_string(line.gettoken_str(2)); if (line.getnumtokens() > 3) cur_page->parms[2] = add_string(line.gettoken_str(3)); if (line.getnumtokens() > 4) cur_page->parms[3] = add_string(line.gettoken_str(4)); } SCRIPT_MSG("DirText: \"%s\" \"%s\" \"%s\" \"%s\"\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4)); } return PS_OK; #else//NSIS_CONFIG_VISIBLE_SUPPORT ERROR_MSG("Error: %s specified, NSIS_CONFIG_VISIBLE_SUPPORT not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_CONFIG_VISIBLE_SUPPORT case TOK_DIRVAR: { if (cur_page_type != PAGE_DIRECTORY && cur_page_type != PAGE_UNINSTCONFIRM) { ERROR_MSG("Error: can't use DirVar outside of PageEx directory|uninstConfirm.\n"); return PS_ERROR; } cur_page->parms[4] = GetUserVarIndex(line, 1) + 1; if (cur_page->parms[4] <= 0) PRINTHELP(); SCRIPT_MSG("DirVar: %s\n", line.gettoken_str(1)); } return PS_OK; case TOK_DIRVERIFY: { if (cur_page_type != PAGE_DIRECTORY) { ERROR_MSG("Error: can't use DirVerify outside of PageEx directory.\n"); return PS_ERROR; } cur_page->flags &= ~PF_DIR_NO_BTN_DISABLE; int k = line.gettoken_enum(1,"auto\0leave\0"); if (k == -1) PRINTHELP(); if (k) cur_page->flags |= PF_DIR_NO_BTN_DISABLE; SCRIPT_MSG("DirVerify: %s\n", line.gettoken_str(1)); } return PS_OK; case TOK_GETINSTDIRERROR: ent.which = EW_GETFLAG; ent.offsets[0] = GetUserVarIndex(line, 1); ent.offsets[1] = FLAG_OFFSET(instdir_error); return add_entry(&ent); #ifdef NSIS_CONFIG_COMPONENTPAGE case TOK_COMPTEXT: { if (!cur_page) { if (SetInnerString(NLF_COMP_TEXT, line.gettoken_str(1)) == PS_WARNING) warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0)); if (line.getnumtokens() > 2) SetInnerString(NLF_COMP_SUBTEXT1, line.gettoken_str(2)); if (line.getnumtokens() > 3) SetInnerString(NLF_COMP_SUBTEXT2, line.gettoken_str(3)); } else { if (cur_page_type != PAGE_COMPONENTS) { ERROR_MSG("Error: ComponentText can only be used inside PageEx components.\n"); return PS_ERROR; } cur_page->parms[0] = add_string(line.gettoken_str(1)); cur_page->parms[1] = add_string(line.gettoken_str(2)); cur_page->parms[2] = add_string(line.gettoken_str(3)); cur_page->parms[3] = cur_page->parms[1]; cur_page->parms[4] = cur_page->parms[2]; } SCRIPT_MSG("ComponentText: \"%s\" \"%s\" \"%s\"\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3)); } return PS_OK; case TOK_INSTTYPE: { int x; if (!stricmp(line.gettoken_str(1),"/NOCUSTOM")) { build_header.flags|=CH_FLAGS_NO_CUSTOM; SCRIPT_MSG("InstType: disabling custom install type\n"); } else if (!stricmp(line.gettoken_str(1),"/COMPONENTSONLYONCUSTOM")) { build_header.flags|=CH_FLAGS_COMP_ONLY_ON_CUSTOM; SCRIPT_MSG("InstType: making components viewable only on custom install type\n"); } else if (!strnicmp(line.gettoken_str(1),"/CUSTOMSTRING=",14)) { SCRIPT_MSG("InstType: setting custom text to: \"%s\"\n",line.gettoken_str(1)+14); if (SetInnerString(NLF_COMP_CUSTOM,line.gettoken_str(1)+14) == PS_WARNING) warning_fl("%s: specified multiple times, wasting space","InstType /CUSTOMSTRING"); } else if (line.gettoken_str(1)[0]=='/') { PRINTHELP() } else { char *itname = line.gettoken_str(1); if (!strnicmp(itname, "un.", 3)) { set_uninstall_mode(1); itname += 3; } for (x = 0; x < NSIS_MAX_INST_TYPES && cur_header->install_types[x]; x ++); if (x == NSIS_MAX_INST_TYPES) { ERROR_MSG("InstType: no more than %d install types allowed. %d specified\n", NSIS_MAX_INST_TYPES, NSIS_MAX_INST_TYPES + 1); return PS_ERROR; } else { cur_header->install_types[x] = add_string(itname); SCRIPT_MSG("InstType: %s%d=\"%s\"\n", uninstall_mode ? "(uninstall) " : "", x+1, itname); } set_uninstall_mode(0); } } return PS_OK; #else//NSIS_CONFIG_COMPONENTPAGE case TOK_COMPTEXT: case TOK_INSTTYPE: ERROR_MSG("Error: %s specified but NSIS_CONFIG_COMPONENTPAGE not defined\n",line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_CONFIG_COMPONENTPAGE #ifdef NSIS_CONFIG_LICENSEPAGE case TOK_LICENSETEXT: { if (!cur_page) { if (SetInnerString(NLF_LICENSE_TEXT, line.gettoken_str(1)) == PS_WARNING) warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0)); SetInnerString(NLF_LICENSE_TEXT_FSRB, line.gettoken_str(1)); SetInnerString(NLF_LICENSE_TEXT_FSCB, line.gettoken_str(1)); if (line.getnumtokens() > 2) SetInnerString(NLF_BTN_LICENSE, line.gettoken_str(2)); } else { if (cur_page_type != PAGE_LICENSE) { ERROR_MSG("Error: LicenseText can only be used inside PageEx license.\n"); return PS_ERROR; } cur_page->parms[0] = add_string(line.gettoken_str(1)); cur_page->next = add_string(line.gettoken_str(2)); } SCRIPT_MSG("LicenseText: \"%s\" \"%s\"\n",line.gettoken_str(1),line.gettoken_str(2)); } return PS_OK; case TOK_LICENSEDATA: { int idx = 0; char *file = line.gettoken_str(1); char *data = NULL; if (file[0] == '$' && file[1] == '(') { char *cp = strdup(file+2); MANAGE_WITH(cp, free); char *p = strchr(cp, ')'); if (p && p[1] == 0) { // if string is only a language str identifier *p = 0; idx = DefineLangString(cp, 0); } data = file; } if (!idx) { unsigned int datalen; FILE *fp=FOPEN(file,"rb"); if (!fp) { ERROR_MSG("LicenseData: open failed \"%s\"\n",file); PRINTHELP() } MANAGE_WITH(fp, fclose); fseek(fp,0,SEEK_END); datalen=ftell(fp); if (!datalen) { ERROR_MSG("LicenseData: empty license file \"%s\"\n",file); return PS_ERROR; } rewind(fp); data=(char*)malloc(datalen+2); if (!data) { ERROR_MSG("Internal compiler error #12345: LicenseData malloc(%d) failed.\n", datalen+2); return PS_ERROR; } //MANAGE_WITH(data, free); char *ldata=data+1; if (fread(ldata,1,datalen,fp) != datalen) { ERROR_MSG("LicenseData: can't read file.\n"); free(data); // TODO: fix later (orip) return PS_ERROR; } ldata[datalen]=0; if (!strncmp(ldata,"{\\rtf",sizeof("{\\rtf")-1)) *data = SF_RTF; else *data = SF_TEXT; } if (!cur_page) { if (SetInnerString(NLF_LICENSE_DATA,data) == PS_WARNING) warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0)); } else { if (cur_page_type != PAGE_LICENSE) { ERROR_MSG("Error: LicenseData can only be used inside PageEx license.\n"); return PS_ERROR; } cur_page->parms[1] = add_string(data, 0); } if (!idx) free(data); // TODO: fix later (orip) SCRIPT_MSG("LicenseData: \"%s\"\n",file); } return PS_OK; case TOK_LICENSEFORCESELECTION: { int k=line.gettoken_enum(1,"off\0checkbox\0radiobuttons\0"); if (k == -1) PRINTHELP() if (k < line.getnumtokens() - 2) PRINTHELP() if (!cur_page) { switch (line.getnumtokens()) { case 4: SetInnerString(NLF_BTN_LICENSE_DISAGREE, line.gettoken_str(3)); case 3: SetInnerString(NLF_BTN_LICENSE_AGREE, line.gettoken_str(2)); break; } switch (k) { case 0: license_res_id = IDD_LICENSE; break; case 1: license_res_id = IDD_LICENSE_FSCB; break; case 2: license_res_id = IDD_LICENSE_FSRB; break; } } else { if (cur_page_type != PAGE_LICENSE) { ERROR_MSG("Error: LicenseForceSelection can only be used inside PageEx license.\n"); return PS_ERROR; } switch (line.getnumtokens()) { case 4: cur_page->parms[3] = add_string(line.gettoken_str(3)); case 3: cur_page->parms[2] = add_string(line.gettoken_str(2)); break; } cur_page->flags &= ~(PF_LICENSE_FORCE_SELECTION | PF_LICENSE_NO_FORCE_SELECTION); switch (k) { case 0: cur_page->dlg_id = IDD_LICENSE; cur_page->flags |= PF_LICENSE_NO_FORCE_SELECTION; break; case 1: cur_page->dlg_id = IDD_LICENSE_FSCB; cur_page->flags |= PF_LICENSE_FORCE_SELECTION; break; case 2: cur_page->dlg_id = IDD_LICENSE_FSRB; cur_page->flags |= PF_LICENSE_FORCE_SELECTION; break; } } SCRIPT_MSG("LicenseForceSelection: %s \"%s\" \"%s\"\n", line.gettoken_str(1), line.gettoken_str(2), line.gettoken_str(3)); } return PS_OK; case TOK_LICENSEBKCOLOR: { char *p = line.gettoken_str(1); if (!strcmpi(p,"/windows")) { build_header.license_bg=-COLOR_WINDOW; SCRIPT_MSG("LicenseBkColor: /windows\n"); } else if (!strcmpi(p,"/grey") || !strcmpi(p,"/gray")) { build_header.license_bg=-COLOR_BTNFACE; SCRIPT_MSG("LicenseBkColor: /grey\n"); } else { int v=strtoul(p,&p,16); build_header.license_bg=((v&0xff)<<16)|(v&0xff00)|((v&0xff0000)>>16); build_uninst.license_bg=build_header.license_bg; SCRIPT_MSG("LicenseBkColor: %06X\n",v); } } return PS_OK; #else//!NSIS_CONFIG_LICENSEPAGE case TOK_LICENSETEXT: case TOK_LICENSEDATA: case TOK_LICENSEBKCOLOR: ERROR_MSG("Error: %s specified, NSIS_CONFIG_LICENSEPAGE not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_CONFIG_LICENSEPAGE #ifdef NSIS_CONFIG_SILENT_SUPPORT case TOK_SILENTINST: { int k=line.gettoken_enum(1,"normal\0silent\0silentlog\0"); if (k<0) PRINTHELP() #ifndef NSIS_CONFIG_LOG if (k == 2) { ERROR_MSG("SilentInstall: silentlog specified, no log support compiled in (use NSIS_CONFIG_LOG)\n"); return PS_ERROR; } #endif//NSIS_CONFIG_LOG SCRIPT_MSG("SilentInstall: %s\n",line.gettoken_str(1)); #ifdef NSIS_CONFIG_LICENSEPAGE if (k && HasUserDefined(NLF_LICENSE_DATA)) { warning_fl("SilentInstall: LicenseData already specified. wasting space"); } if (k) { build_header.flags|=CH_FLAGS_SILENT; if (k == 2) build_header.flags|=CH_FLAGS_SILENT_LOG; } else { build_header.flags&=~CH_FLAGS_SILENT; build_header.flags&=~CH_FLAGS_SILENT_LOG; } #endif//NSIS_CONFIG_LICENSEPAGE } return PS_OK; case TOK_SILENTUNINST: #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT { int k=line.gettoken_enum(1,"normal\0silent\0"); if (k<0) PRINTHELP() if (k) build_uninst.flags|=CH_FLAGS_SILENT; else build_uninst.flags&=~CH_FLAGS_SILENT; SCRIPT_MSG("SilentUnInstall: %s\n",line.gettoken_str(1)); } return PS_OK; #else ERROR_MSG("Error: %s specified, NSIS_CONFIG_UNINSTALL_SUPPORT not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif case TOK_IFSILENT: ent.which=EW_IFFLAG; if (process_jump(line,1,&ent.offsets[0]) || process_jump(line,2,&ent.offsets[1])) PRINTHELP() ent.offsets[2]=FLAG_OFFSET(silent); ent.offsets[3]=~0;//new value mask - keep flag SCRIPT_MSG("IfSilent ?%s:%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_SETSILENT: { ent.which=EW_SETFLAG; ent.offsets[0]=FLAG_OFFSET(silent); int k=line.gettoken_enum(1,"normal\0silent\0"); if (k<0) PRINTHELP() ent.offsets[1]=add_intstring(k); SCRIPT_MSG("SetSilent: %s\n",line.gettoken_str(1)); } return add_entry(&ent); #else//!NSIS_CONFIG_SILENT_SUPPORT case TOK_SILENTINST: case TOK_SILENTUNINST: case TOK_IFSILENT: case TOK_SETSILENT: ERROR_MSG("Error: %s specified, NSIS_CONFIG_SILENT_SUPPORT not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//NSIS_CONFIG_SILENT_SUPPORT case TOK_OUTFILE: strncpy(build_output_filename,line.gettoken_str(1),1024-1); SCRIPT_MSG("OutFile: \"%s\"\n",build_output_filename); return PS_OK; case TOK_INSTDIR: { char *p = line.gettoken_str(1); if (build_header.install_directory_ptr) { warning_fl("%s: specified multiple times. wasting space",line.gettoken_str(0)); } build_header.install_directory_ptr = add_string(p); build_header.install_directory_auto_append = 0; char *p2 = p + strlen(p); if (*p && *CharPrev(p, p2) != '\\') { // we risk hitting $\r or something like $(bla\ad) or ${bla\ad} here, but it's better // than hitting backslashes in processed strings while (p2 > p && *p2 != '\\') p2 = CharPrev(p, p2); if (*p2 == '\\') { build_header.install_directory_auto_append = add_string(p2 + 1); } } SCRIPT_MSG("InstallDir: \"%s\"\n",line.gettoken_str(1)); } return PS_OK; case TOK_INSTALLDIRREGKEY: // InstallDirRegKey { if (build_header.install_reg_key_ptr) { warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0)); } int k=line.gettoken_enum(1,rootkeys[0]); if (k == -1) k=line.gettoken_enum(1,rootkeys[1]); if (k == -1) PRINTHELP() build_header.install_reg_rootkey=(int)rootkey_tab[k]; if (!build_header.install_reg_rootkey) PRINTHELP() // SHCTX is invalid here build_header.install_reg_key_ptr = add_string(line.gettoken_str(2),0); if (line.gettoken_str(2)[0] == '\\') warning_fl("%s: registry path name begins with \'\\\', may cause problems",line.gettoken_str(0)); build_header.install_reg_value_ptr = add_string(line.gettoken_str(3),0); SCRIPT_MSG("InstallRegKey: \"%s\\%s\\%s\"\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3)); } return PS_OK; case TOK_CRCCHECK: build_crcchk=line.gettoken_enum(1,"off\0on\0force\0"); if (build_crcchk==-1) PRINTHELP() SCRIPT_MSG("CRCCheck: %s\n",line.gettoken_str(1)); return PS_OK; case TOK_INSTPROGRESSFLAGS: { int x; int smooth=0; build_header.flags&=~CH_FLAGS_PROGRESS_COLORED; for (x = 1; x < line.getnumtokens(); x ++) { if (!stricmp(line.gettoken_str(x),"smooth")) smooth=1; else if (!stricmp(line.gettoken_str(x),"colored")) build_header.flags|=CH_FLAGS_PROGRESS_COLORED; else PRINTHELP() } try { init_res_editor(); BYTE* dlg = res_editor->GetResourceA(RT_DIALOG, MAKEINTRESOURCE(IDD_INSTFILES), NSIS_DEFAULT_LANG); if (!dlg) throw runtime_error("IDD_INSTFILES doesn't exist!"); CDialogTemplate dt(dlg,uDefCodePage); free(dlg); DialogItemTemplate* progress = dt.GetItem(IDC_PROGRESS); if (!progress) { throw runtime_error("IDC_PROGRESS doesn't exist!"); } if (smooth) progress->dwStyle |= PBS_SMOOTH; else progress->dwStyle &= ~PBS_SMOOTH; DWORD dwSize; dlg = dt.Save(dwSize); res_editor->UpdateResourceA(RT_DIALOG, MAKEINTRESOURCE(IDD_INSTFILES), NSIS_DEFAULT_LANG, dlg, dwSize); delete [] dlg; } catch (exception& err) { ERROR_MSG("Error setting smooth progress bar: %s\n", err.what()); return PS_ERROR; } SCRIPT_MSG("InstProgressFlags: smooth=%d, colored=%d\n",smooth, !!(build_header.flags&CH_FLAGS_PROGRESS_COLORED)); } return PS_OK; case TOK_AUTOCLOSE: { int k=line.gettoken_enum(1,"false\0true\0"); if (k == -1) PRINTHELP(); if (k) build_header.flags|=CH_FLAGS_AUTO_CLOSE; else build_header.flags&=~CH_FLAGS_AUTO_CLOSE; SCRIPT_MSG("AutoCloseWindow: %s\n",k?"true":"false"); } return PS_OK; case TOK_WINDOWICON: #ifdef NSIS_CONFIG_VISIBLE_SUPPORT disable_window_icon=line.gettoken_enum(1,"on\0off\0"); if (disable_window_icon == -1) PRINTHELP(); SCRIPT_MSG("WindowIcon: %s\n",line.gettoken_str(1)); return PS_OK; #else ERROR_MSG("Error: %s specified, NSIS_CONFIG_VISIBLE_SUPPORT not defined.\n",line.gettoken_str(0)); return PS_ERROR; #endif // NSIS_CONFIG_VISIBLE_SUPPORT case TOK_SHOWDETAILSUNINST: #ifndef NSIS_CONFIG_UNINSTALL_SUPPORT ERROR_MSG("Error: ShowUninstDetails specified but NSIS_CONFIG_UNINSTALL_SUPPORT not defined\n"); return PS_ERROR; #endif case TOK_SHOWDETAILS: { int k=line.gettoken_enum(1,"hide\0show\0nevershow\0"); if (k == -1) PRINTHELP() #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT if (which_token == TOK_SHOWDETAILSUNINST) { build_uninst.flags&=~(CH_FLAGS_DETAILS_NEVERSHOW|CH_FLAGS_DETAILS_SHOWDETAILS); if (k==1) build_uninst.flags|=CH_FLAGS_DETAILS_SHOWDETAILS; else if (k==2) build_uninst.flags|=CH_FLAGS_DETAILS_NEVERSHOW; } else #endif { build_header.flags&=~(CH_FLAGS_DETAILS_NEVERSHOW|CH_FLAGS_DETAILS_SHOWDETAILS); if (k==1) build_header.flags|=CH_FLAGS_DETAILS_SHOWDETAILS; else if (k==2) build_header.flags|=CH_FLAGS_DETAILS_NEVERSHOW; } SCRIPT_MSG("%s: %s\n",line.gettoken_str(0),line.gettoken_str(1)); } return PS_OK; case TOK_DIRSHOW: /*{ int k=line.gettoken_enum(1,"show\0hide\0"); if (k == -1) PRINTHELP(); if (k) build_header.flags|=CH_FLAGS_DIR_NO_SHOW; else build_header.flags&=~CH_FLAGS_DIR_NO_SHOW; SCRIPT_MSG("DirShow: %s\n",k?"hide":"show"); }*/ ERROR_MSG("Error: DirShow doesn't currently work\n"); return PS_ERROR; case TOK_ROOTDIRINST: { int k=line.gettoken_enum(1,"true\0false\0"); if (k == -1) PRINTHELP(); if (k) build_header.flags|=CH_FLAGS_NO_ROOT_DIR; else build_header.flags&=~CH_FLAGS_NO_ROOT_DIR; SCRIPT_MSG("AllowRootDirInstall: %s\n",k?"false":"true"); } return PS_OK; case TOK_BGFONT: #ifndef NSIS_SUPPORT_BGBG ERROR_MSG("Error: BGFont specified but NSIS_SUPPORT_BGBG not defined\n"); return PS_ERROR; #else//NSIS_SUPPORT_BGBG if (line.getnumtokens()==1) { memcpy(&bg_font,&bg_default_font,sizeof(LOGFONT)); SCRIPT_MSG("BGFont: default font\n"); return PS_OK; } LOGFONT newfont; newfont.lfHeight=40; newfont.lfWidth=0; newfont.lfEscapement=0; newfont.lfOrientation=0; newfont.lfWeight=FW_NORMAL; newfont.lfItalic=FALSE; newfont.lfUnderline=FALSE; newfont.lfStrikeOut=FALSE; newfont.lfCharSet=DEFAULT_CHARSET; newfont.lfOutPrecision=OUT_DEFAULT_PRECIS; newfont.lfClipPrecision=CLIP_DEFAULT_PRECIS; newfont.lfQuality=DEFAULT_QUALITY; newfont.lfPitchAndFamily=DEFAULT_PITCH; strncpy(newfont.lfFaceName,line.gettoken_str(1),LF_FACESIZE); SCRIPT_MSG("BGFont: \"%s\"",line.gettoken_str(1)); { bool height=false; bool weight=false; for (int i = 2; i < line.getnumtokens(); i++) { char *tok=line.gettoken_str(i); if (tok[0]=='/') { if (!strcmpi(tok,"/ITALIC")) { SCRIPT_MSG(" /ITALIC"); newfont.lfItalic=TRUE; } else if (!strcmpi(tok,"/UNDERLINE")) { SCRIPT_MSG(" /UNDERLINE"); newfont.lfUnderline=TRUE; } else if (!strcmpi(tok,"/STRIKE")) { SCRIPT_MSG(" /STRIKE"); newfont.lfStrikeOut=TRUE; } else { SCRIPT_MSG("\n"); PRINTHELP(); } } else { if (!height) { SCRIPT_MSG(" height=%s",tok); newfont.lfHeight=line.gettoken_int(i); height=true; } else if (!weight) { SCRIPT_MSG(" weight=%s",tok); newfont.lfWeight=line.gettoken_int(i); weight=true; } else { SCRIPT_MSG("\n"); PRINTHELP(); } } } } SCRIPT_MSG("\n"); memcpy(&bg_font, &newfont, sizeof(LOGFONT)); return PS_OK; #endif//NSIS_SUPPORT_BGBG case TOK_BGGRADIENT: #ifndef NSIS_SUPPORT_BGBG ERROR_MSG("Error: BGGradient specified but NSIS_SUPPORT_BGBG not defined\n"); return PS_ERROR; #else//NSIS_SUPPORT_BGBG if (line.getnumtokens()==1) { SCRIPT_MSG("BGGradient: default colors\n"); build_header.bg_color1=0; build_header.bg_color2=RGB(0,0,255); } else if (!stricmp(line.gettoken_str(1),"off")) { build_header.bg_color1=build_header.bg_color2=build_header.bg_textcolor=-1; SCRIPT_MSG("BGGradient: off\n"); if (line.getnumtokens()>2) PRINTHELP() } else { char *p = line.gettoken_str(1); int v1,v2,v3=-1; v1=strtoul(p,&p,16); build_header.bg_color1=((v1&0xff)<<16)|(v1&0xff00)|((v1&0xff0000)>>16); p=line.gettoken_str(2); v2=strtoul(p,&p,16); build_header.bg_color2=((v2&0xff)<<16)|(v2&0xff00)|((v2&0xff0000)>>16); p=line.gettoken_str(3); if (*p) { if (!stricmp(p,"notext")) build_header.bg_textcolor=-1; else { v3=strtoul(p,&p,16); build_header.bg_textcolor=((v3&0xff)<<16)|(v3&0xff00)|((v3&0xff0000)>>16); } } SCRIPT_MSG("BGGradient: 0x%06X->0x%06X (text=0x%06X)\n",v1,v2,v3); } #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT build_uninst.bg_color1=build_header.bg_color1; build_uninst.bg_color2=build_header.bg_color2; build_uninst.bg_textcolor=build_header.bg_textcolor; #endif//NSIS_CONFIG_UNINSTALL_SUPPORT #endif//NSIS_SUPPORT_BGBG return PS_OK; #ifdef NSIS_CONFIG_VISIBLE_SUPPORT case TOK_INSTCOLORS: { char *p = line.gettoken_str(1); if (p[0]=='/') { if (stricmp(p,"/windows") || line.getnumtokens()!=2) PRINTHELP() build_header.lb_fg=build_header.lb_bg=-1; SCRIPT_MSG("InstallColors: windows default colors\n"); } else { int v1,v2; if (line.getnumtokens()!=3) PRINTHELP() v1=strtoul(p,&p,16); build_header.lb_fg=((v1&0xff)<<16)|(v1&0xff00)|((v1&0xff0000)>>16); p=line.gettoken_str(2); v2=strtoul(p,&p,16); build_header.lb_bg=((v2&0xff)<<16)|(v2&0xff00)|((v2&0xff0000)>>16); SCRIPT_MSG("InstallColors: fg=%06X bg=%06X\n",v1,v2); } #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT build_uninst.lb_fg=build_header.lb_fg; build_uninst.lb_bg=build_header.lb_bg; #endif } return PS_OK; case TOK_XPSTYLE: { int k=line.gettoken_enum(1,"on\0off\0"); if (k == -1) PRINTHELP() SCRIPT_MSG("XPStyle: %s\n", line.gettoken_str(1)); if (!k) manifest_comctl = manifest::comctl_xp; else manifest_comctl = manifest::comctl_old; } return PS_OK; case TOK_CHANGEUI: try { DWORD dwSize; int k=line.gettoken_enum(1, "all\0IDD_LICENSE\0IDD_DIR\0IDD_SELCOM\0IDD_INST\0IDD_INSTFILES\0IDD_UNINST\0IDD_VERIFY\0IDD_LICENSE_FSRB\0IDD_LICENSE_FSCB\0"); if (k<0) PRINTHELP(); FILE *fui = FOPEN(line.gettoken_str(2), "rb"); if (!fui) { ERROR_MSG("Error: Can't open \"%s\"!\n", line.gettoken_str(2)); return PS_ERROR; } MANAGE_WITH(fui, fclose); fseek(fui, 0, SEEK_END); unsigned int len = ftell(fui); fseek(fui, 0, SEEK_SET); LPBYTE ui = (LPBYTE) malloc(len); if (!ui) { ERROR_MSG("Internal compiler error #12345: malloc(%d) failed\n", len); extern void quit(); quit(); } MANAGE_WITH(ui, free); if (fread(ui, 1, len, fui) != len) { ERROR_MSG("Error: Can't read \"%s\"!\n", line.gettoken_str(2)); return PS_ERROR; } CResourceEditor *uire = new CResourceEditor(ui, len); init_res_editor(); // Search for required items #define GET(x) dlg = uire->GetResourceA(RT_DIALOG, MAKEINTRESOURCE(x), 0); if (!dlg) return PS_ERROR; CDialogTemplate UIDlg(dlg, uDefCodePage); #define SEARCH(x) if (!UIDlg.GetItem(x)) {ERROR_MSG("Error: Can't find %s (%u) in the custom UI!\n", #x, x);delete [] dlg;delete uire;return PS_ERROR;} #define SAVE(x) dwSize = UIDlg.GetSize(); res_editor->UpdateResourceA(RT_DIALOG, x, NSIS_DEFAULT_LANG, dlg, dwSize); delete [] dlg; LPBYTE dlg = NULL; if (k == 0 || k == 1) { GET(IDD_LICENSE); SEARCH(IDC_EDIT1); SAVE(IDD_LICENSE); } if (k == 0 || k == 2) { GET(IDD_DIR); SEARCH(IDC_DIR); SEARCH(IDC_BROWSE); #ifdef NSIS_CONFIG_LOG SEARCH(IDC_CHECK1); #endif SAVE(IDD_DIR); } if (k == 0 || k == 3) { GET(IDD_SELCOM); SEARCH(IDC_TREE1); SEARCH(IDC_COMBO1); SAVE(IDD_SELCOM); } if (k == 0 || k == 4) { GET(IDD_INST); SEARCH(IDC_BACK); SEARCH(IDC_CHILDRECT); SEARCH(IDC_VERSTR); SEARCH(IDOK); SEARCH(IDCANCEL); // Search for bitmap holder (default for SetBrandingImage) branding_image_found = false; DialogItemTemplate* dlgItem = 0; for (int i = 0; (dlgItem = UIDlg.GetItemByIdx(i)); i++) { bool check = false; if (IS_INTRESOURCE(dlgItem->szClass)) { if (dlgItem->szClass == MAKEINTRESOURCEW(0x0082)) { check = true; } } else { char *szClass = winchar_toansi(dlgItem->szClass); check = stricmp(szClass, "Static") == 0; delete [] szClass; } if (check) { if ((dlgItem->dwStyle & SS_BITMAP) == SS_BITMAP) { branding_image_found = true; branding_image_id = dlgItem->wId; break; } } } SAVE(IDD_INST); } if (k == 0 || k == 5) { GET(IDD_INSTFILES); SEARCH(IDC_LIST1); SEARCH(IDC_PROGRESS); SEARCH(IDC_SHOWDETAILS); SAVE(IDD_INSTFILES); } if (k == 0 || k == 6) { GET(IDD_UNINST); SEARCH(IDC_EDIT1); SAVE(IDD_UNINST); } if (k == 0 || k == 7) { GET(IDD_VERIFY); SEARCH(IDC_STR); SAVE(IDD_VERIFY); } if (k == 0 || k == 8) { GET(IDD_LICENSE_FSRB); SEARCH(IDC_EDIT1); SEARCH(IDC_LICENSEAGREE); SEARCH(IDC_LICENSEDISAGREE); SAVE(IDD_LICENSE_FSRB); } if (k == 0 || k == 9) { GET(IDD_LICENSE_FSCB); SEARCH(IDC_EDIT1); SEARCH(IDC_LICENSEAGREE); SAVE(IDD_LICENSE_FSCB); } delete uire; SCRIPT_MSG("ChangeUI: %s %s%s\n", line.gettoken_str(1), line.gettoken_str(2), branding_image_found?" (branding image holder found)":""); } catch (exception& err) { ERROR_MSG("Error while changing UI: %s\n", err.what()); return PS_ERROR; } return PS_OK; case TOK_ADDBRANDINGIMAGE: #ifdef _WIN32 try { int k=line.gettoken_enum(1,"top\0left\0bottom\0right\0"); int wh=line.gettoken_int(2); if (k == -1) PRINTHELP(); int padding = 2; if (line.getnumtokens() == 4) padding = line.gettoken_int(3); init_res_editor(); BYTE* dlg = res_editor->GetResourceA(RT_DIALOG, MAKEINTRESOURCE(IDD_INST), NSIS_DEFAULT_LANG); CDialogTemplate dt(dlg, uDefCodePage); res_editor->FreeResource(dlg); DialogItemTemplate brandingCtl = {0,}; brandingCtl.dwStyle = SS_BITMAP | WS_CHILD | WS_VISIBLE; brandingCtl.sX = padding; brandingCtl.sY = padding; brandingCtl.szClass = MAKEINTRESOURCEW(0x0082); brandingCtl.szTitle = NULL; brandingCtl.wId = IDC_BRANDIMAGE; brandingCtl.sHeight = wh; brandingCtl.sWidth = wh; dt.PixelsToDlgUnits(brandingCtl.sWidth, brandingCtl.sHeight); if (k%2) { // left (1) / right (3) if (k & 2) // right brandingCtl.sX += dt.GetWidth(); else // left dt.MoveAll(brandingCtl.sWidth + (padding * 2), 0); dt.Resize(brandingCtl.sWidth + (padding * 2), 0); brandingCtl.sHeight = dt.GetHeight() - (padding * 2); } else { // top (0) / bottom (2) if (k & 2) // bottom brandingCtl.sY += dt.GetHeight(); else // top dt.MoveAll(0, brandingCtl.sHeight + (padding * 2)); dt.Resize(0, brandingCtl.sHeight + (padding * 2)); brandingCtl.sWidth = dt.GetWidth() - (padding * 2); } dt.AddItem(brandingCtl); DWORD dwDlgSize; dlg = dt.Save(dwDlgSize); res_editor->UpdateResourceA(RT_DIALOG, IDD_INST, NSIS_DEFAULT_LANG, dlg, dwDlgSize); delete [] dlg; dt.DlgUnitsToPixels(brandingCtl.sWidth, brandingCtl.sHeight); SCRIPT_MSG("AddBrandingImage: %s %ux%u\n", line.gettoken_str(1), brandingCtl.sWidth, brandingCtl.sHeight); branding_image_found = true; branding_image_id = IDC_BRANDIMAGE; } catch (exception& err) { ERROR_MSG("Error while adding image branding support: %s\n", err.what()); return PS_ERROR; } return PS_OK; #else ERROR_MSG("Error: AddBrandingImage is disabled for non Win32 platforms.\n"); return PS_ERROR; #endif case TOK_SETFONT: { if (!strnicmp(line.gettoken_str(1), "/LANG=", 6)) { LANGID lang_id = atoi(line.gettoken_str(1) + 6); LanguageTable *table = GetLangTable(lang_id); table->nlf.m_szFont = (char*)malloc(strlen(line.gettoken_str(2))+1); strcpy(table->nlf.m_szFont, line.gettoken_str(2)); table->nlf.m_iFontSize = line.gettoken_int(3); SCRIPT_MSG("SetFont: lang=%d \"%s\" %s\n", lang_id, line.gettoken_str(2), line.gettoken_str(3)); } else { strncpy(build_font, line.gettoken_str(1), sizeof(build_font)); build_font_size = line.gettoken_int(2); SCRIPT_MSG("SetFont: \"%s\" %s\n", line.gettoken_str(1), line.gettoken_str(2)); } } return PS_OK; #else case TOK_INSTCOLORS: case TOK_XPSTYLE: case TOK_CHANGEUI: case TOK_ADDBRANDINGIMAGE: case TOK_SETFONT: ERROR_MSG("Error: %s specified, NSIS_CONFIG_VISIBLE_SUPPORT not defined.\n",line.gettoken_str(0)); return PS_ERROR; #endif// NSIS_CONFIG_VISIBLE_SUPPORT case TOK_REQEXECLEVEL: { int k=line.gettoken_enum(1,"none\0user\0highest\0admin\0"); switch (k) { case 0: manifest_exec_level = manifest::exec_level_none; break; case 1: manifest_exec_level = manifest::exec_level_user; break; case 2: manifest_exec_level = manifest::exec_level_highest; break; case 3: manifest_exec_level = manifest::exec_level_admin; break; default: PRINTHELP(); } } return PS_OK; // Ability to change compression methods from within the script case TOK_SETCOMPRESSOR: #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT { if (build_compressor_set) { ERROR_MSG("Error: can't change compressor after data already got compressed or header already changed!\n"); return PS_ERROR; } if (build_compressor_final) { warning_fl("SetCompressor ignored due to previous call with the /FINAL switch"); return PS_OK; } int a = 1; build_compress_whole = false; while (line.gettoken_str(a)[0] == '/') { if (!strcmpi(line.gettoken_str(a),"/FINAL")) { build_compressor_final = true; a++; } else if (!strcmpi(line.gettoken_str(a),"/SOLID")) { build_compress_whole = true; a++; } else PRINTHELP(); } if (a != line.getnumtokens() - 1) { ERROR_MSG("%s expects %d parameters, got %d.\n", line.gettoken_str(0), a + 1, line.getnumtokens()); PRINTHELP(); } int k=line.gettoken_enum(a, "zlib\0bzip2\0lzma\0"); switch (k) { case 0: compressor = &zlib_compressor; break; case 1: compressor = &bzip2_compressor; break; case 2: compressor = &lzma_compressor; break; default: PRINTHELP(); } string compressor_name = line.gettoken_str(a); compressor_name = lowercase(compressor_name); if (set_compressor(compressor_name, build_compress_whole) != PS_OK) { SCRIPT_MSG("SetCompressor: error loading stub for \"%s\" compressor.\n", compressor_name.c_str()); return PS_ERROR; } SCRIPT_MSG("SetCompressor: %s%s%s\n", build_compressor_final ? "/FINAL " : "", build_compress_whole ? "/SOLID " : "", line.gettoken_str(a)); } return PS_OK; #else//NSIS_CONFIG_COMPRESSION_SUPPORT ERROR_MSG("Error: %s specified, NSIS_CONFIG_COMPRESSION_SUPPORT not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//NSIS_CONFIG_COMPRESSION_SUPPORT case TOK_LOADNLF: { SCRIPT_MSG("LoadLanguageFile: %s\n", line.gettoken_str(1)); LanguageTable *table = LoadLangFile(line.gettoken_str(1)); if (!table) return PS_ERROR; if (!defcodepage_set) { uDefCodePage = table->nlf.m_uCodePage; defcodepage_set = true; } last_used_lang = table->lang_id; // define LANG_LangName as "####" (lang id) // for example ${LANG_ENGLISH} = 1033 char lang_id[16]; char lang_cp[16]; char lang_name[1024]; wsprintf(lang_name, "LANG_%s", table->nlf.m_szName); wsprintf(lang_id, "%u", table->lang_id); wsprintf(lang_cp, "%u", table->nlf.m_uCodePage); definedlist.add(lang_name, lang_id); wsprintf(lang_name, "LANG_%s_CP", table->nlf.m_szName); definedlist.add(lang_name, lang_cp); } return PS_OK; // preprocessor-ish (ifdef/ifndef/else/endif are handled one step out from here) /////////////////////////////////////////////////////////////////////////////// case TOK_P_DEFINE: { char *define=line.gettoken_str(1); char *value; GrowBuf file_buf; char datebuf[256]; char mathbuf[256]; if (!stricmp(define,"/date") || !stricmp(define,"/utcdate")) { if (line.getnumtokens()!=4) PRINTHELP() char *date_type = define; define=line.gettoken_str(2); value=line.gettoken_str(3); time_t rawtime; time(&rawtime); if (!stricmp(date_type,"/utcdate")) rawtime = mktime(gmtime(&rawtime)); datebuf[0]=0; size_t s=strftime(datebuf,sizeof(datebuf),value,localtime(&rawtime)); if (s == 0) datebuf[0]=0; else datebuf[max(s,sizeof(datebuf)-1)]=0; value=datebuf; } else if (!stricmp(define,"/file") || !stricmp(define,"/file_noerr")) { if (line.getnumtokens()!=4) PRINTHELP() define=line.gettoken_str(2); const char *filename=line.gettoken_str(3); FILE *fp=fopen(filename,"r"); if (!fp && stricmp(define,"/file_noerr")) { ERROR_MSG("!define /file: file not found (\"%s\")\n",filename); return PS_ERROR; } if (fp) { char str[MAX_LINELENGTH]; for (;;) { char *p=str; *p=0; fgets(str,MAX_LINELENGTH,fp); linecnt++; if (feof(fp)&&!str[0]) break; while (*p) p++; if (p > str) p--; while (p >= str && (*p == '\r' || *p == '\n')) p--; *++p=0; if (file_buf.getlen()) file_buf.add("\n",1); file_buf.add(str,strlen(str)); } fclose(fp); } file_buf.add("\0",1); value = (char *)file_buf.get(); } else if (!stricmp(define,"/math")) { int value1; int value2; char *mathop; if (line.getnumtokens()!=6) PRINTHELP() define = line.gettoken_str(2); value1 = line.gettoken_int(3); mathop = line.gettoken_str(4); value2 = line.gettoken_int(5); value = mathbuf; if (!strcmp(mathop,"+")) { sprintf(value,"%d",value1+value2); } else if (!strcmp(mathop,"-")) { sprintf(value,"%d",value1-value2); } else if (!strcmp(mathop,"*")) { sprintf(value,"%d",value1*value2); } else if (!strcmp(mathop,"&")) { sprintf(value,"%d",value1&value2); } else if (!strcmp(mathop,"|")) { sprintf(value,"%d",value1|value2); } else if (!strcmp(mathop,"^")) { sprintf(value,"%d",value1^value2); } else if (!strcmp(mathop,"/")) { if (value2==0) { ERROR_MSG("!define /math: division by zero! (\"%i / %i\")\n",value1,value2); return PS_ERROR; } sprintf(value,"%d",value1/value2); } else if (!strcmp(mathop,"%")) { if (value2==0) { ERROR_MSG("!define /math: division by zero! (\"%i %% %i\")\n",value1,value2); return PS_ERROR; } sprintf(value,"%d",value1%value2); } else PRINTHELP() } else { if (line.getnumtokens()==4) PRINTHELP() value=line.gettoken_str(2); } if (definedlist.add(define,value)) { ERROR_MSG("!define: \"%s\" already defined!\n",define); return PS_ERROR; } SCRIPT_MSG("!define: \"%s\"=\"%s\"\n",define,value); } return PS_OK; case TOK_P_UNDEF: if (definedlist.del(line.gettoken_str(1))) { ERROR_MSG("!undef: \"%s\" not defined!\n",line.gettoken_str(1)); return PS_ERROR; } SCRIPT_MSG("!undef: \"%s\"\n",line.gettoken_str(1)); return PS_OK; case TOK_P_PACKEXEHEADER: strncpy(build_packname,line.gettoken_str(1),sizeof(build_packname)-1); strncpy(build_packcmd,line.gettoken_str(2),sizeof(build_packcmd)-1); SCRIPT_MSG("!packhdr: filename=\"%s\", command=\"%s\"\n", build_packname, build_packcmd); return PS_OK; case TOK_P_SYSTEMEXEC: { char *exec=line.gettoken_str(1); int comp=line.gettoken_enum(2,"<\0>\0<>\0=\0ignore\0"); if (line.getnumtokens() == 2) comp = 4; if (comp == -1 && line.getnumtokens() == 3) comp=4; if (comp == -1) PRINTHELP() int success=0; int cmpv=line.gettoken_int(3,&success); if (!success && comp != 4) PRINTHELP() SCRIPT_MSG("!system: \"%s\"\n",exec); #ifdef _WIN32 int ret=sane_system(exec); #else char *execfixed = my_convert(exec); int ret=system(execfixed); my_convert_free(execfixed); #endif if (comp == 0 && ret < cmpv); else if (comp == 1 && ret > cmpv); else if (comp == 2 && ret != cmpv); else if (comp == 3 && ret == cmpv); else if (comp == 4); else { ERROR_MSG("!system: returned %d, aborting\n",ret); return PS_ERROR; } SCRIPT_MSG("!system: returned %d\n",ret); } return PS_OK; case TOK_P_EXECUTE: { char *exec=line.gettoken_str(1); #ifdef _WIN32 PROCESS_INFORMATION pi; STARTUPINFO si={sizeof(STARTUPINFO),}; if (CreateProcess(NULL,exec,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)) { WaitForSingleObject(pi.hProcess,INFINITE); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } #else char *execfixed = my_convert(exec); system(execfixed); my_convert_free(execfixed); #endif SCRIPT_MSG("!execute: \"%s\"\n",exec); } case TOK_P_ADDINCLUDEDIR: #ifdef _WIN32 include_dirs.add(line.gettoken_str(1),0); #else { char *f = line.gettoken_str(1); char *fc = my_convert(f); include_dirs.add(fc,0); my_convert_free(fc); } #endif return PS_OK; case TOK_P_INCLUDE: { bool required = true; char *f = line.gettoken_str(1); if(!stricmp(f,"/nonfatal")) { if (line.getnumtokens()!=3) PRINTHELP(); f = line.gettoken_str(2); required = false; } else if (line.getnumtokens()!=2) { PRINTHELP(); } #ifdef _WIN32 char *fc = f; #else char *fc = my_convert(f); #endif int included = 0; string dir = get_dir_name(fc); string spec = get_file_name(fc); string basedir = dir + PLATFORM_PATH_SEPARATOR_STR; if (dir == spec) { // no path, just file name dir = "."; basedir = ""; } #ifndef _WIN32 my_convert_free(fc); #endif // search working directory boost::scoped_ptr dr( new_dir_reader() ); dr->read(dir); for (dir_reader::iterator files_itr = dr->files().begin(); files_itr != dr->files().end(); files_itr++) { if (!dir_reader::matches(*files_itr, spec)) continue; string incfile = basedir + *files_itr; if (includeScript((char *) incfile.c_str()) != PS_OK) { return PS_ERROR; } included++; } if (included) return PS_OK; // search include dirs char *incdir = include_dirs.get(); int incdirs = include_dirs.getnum(); for (int i = 0; i < incdirs; i++, incdir += strlen(incdir) + 1) { string curincdir = string(incdir) + PLATFORM_PATH_SEPARATOR_STR + dir; boost::scoped_ptr dr( new_dir_reader() ); dr->read(curincdir); for (dir_reader::iterator incdir_itr = dr->files().begin(); incdir_itr != dr->files().end(); incdir_itr++) { if (!dir_reader::matches(*incdir_itr, spec)) continue; string incfile = string(incdir) + PLATFORM_PATH_SEPARATOR_STR + basedir + *incdir_itr; if (includeScript((char *) incfile.c_str()) != PS_OK) { return PS_ERROR; } included++; } if (included) return PS_OK; } // nothing found if (!included) { if(required) { ERROR_MSG("!include: could not find: \"%s\"\n",f); return PS_ERROR; } else { warning_fl("!include: could not find: \"%s\"",f); } } } return PS_OK; case TOK_P_CD: if (!line.gettoken_str(1)[0] || chdir(line.gettoken_str(1))) { ERROR_MSG("!cd: error changing to: \"%s\"\n",line.gettoken_str(1)); return PS_ERROR; } return PS_OK; case TOK_P_ERROR: ERROR_MSG("!error: %s\n",line.gettoken_str(1)); return PS_ERROR; case TOK_P_WARNING: warning_fl("!warning: %s",line.gettoken_str(1)); return PS_OK; case TOK_P_ECHO: SCRIPT_MSG("%s (%s:%d)\n", line.gettoken_str(1),curfilename,linecnt); return PS_OK; case TOK_P_SEARCHPARSESTRING: { bool ignCase=false; bool noErrors=false; bool isFile=false; int parmOffs=1; while (parmOffs < line.getnumtokens()) { if (!stricmp(line.gettoken_str(parmOffs),"/ignorecase")) { ignCase=true; parmOffs++; } else if (!stricmp(line.gettoken_str(parmOffs),"/noerrors")) { noErrors=true; parmOffs++; } else if (!stricmp(line.gettoken_str(parmOffs),"/file")) { isFile=true; parmOffs++; } else break; } if (parmOffs+3 > line.getnumtokens()) { ERROR_MSG("!searchparse: not enough parameters\n"); return PS_ERROR; } const char *source_string = line.gettoken_str(parmOffs++); DefineList *list=NULL; if (isFile) { FILE *fp=fopen(source_string,"r"); if (!fp) { ERROR_MSG("!searchparse /file: error opening \"%s\"\n",source_string); return PS_ERROR; } int req_parm = (line.getnumtokens() - parmOffs)/2; GrowBuf tmpstr; char str[MAX_LINELENGTH]; for (;;) { for (;;) { str[0]=0; fgets(str,sizeof(str),fp); if (!str[0]) break; char *p=str; while (*p) p++; if (p > str) p--; while (p >= str && (*p == '\r' || *p == '\n')) p--; *++p=0; bool endSlash = (str[0] && str[strlen(str)-1] == '\\'); if (tmpstr.getlen() || endSlash) tmpstr.add(str,strlen(str)); if (!endSlash) break; } char *thisline=str; if (tmpstr.getlen()) { tmpstr.add("\0",1); thisline=(char *)tmpstr.get(); } DefineList *tlist = searchParseString(thisline,&line,parmOffs,ignCase,true); if (tlist && tlist->getnum()) { if (!list || tlist->getnum() > list->getnum()) { delete list; list=tlist; if (tlist->getnum() >= req_parm) break; // success! } else delete list; } // parse line tmpstr.resize(0); } fclose(fp); if (!noErrors) { if (!list) { ERROR_MSG("!searchparse: starting string \"%s\" not found in file!\n",line.gettoken_str(parmOffs)); return PS_ERROR; } else if (list->getnum() < req_parm) { char *p=line.gettoken_str(parmOffs + list->getnum()*2); ERROR_MSG("!searchparse: failed search at string \"%s\" not found in file!\n",p?p:"(null)"); return PS_ERROR; } } } else { list=searchParseString(source_string,&line,parmOffs,ignCase,noErrors); if (!list && !noErrors) return PS_ERROR; } if (list) // if we got our list, merge them defines in { int i; for (i=0;igetnum(); i ++) { char *def=list->getname(i); char *val=list->getvalue(i); if (def && val) { if (definedlist.find(def)) definedlist.del(def); definedlist.add(def,val); } } } delete list; } return PS_OK; case TOK_P_SEARCHREPLACESTRING: { int ignoreCase=!stricmp(line.gettoken_str(1),"/ignorecase"); if (line.getnumtokens()!=5+ignoreCase) PRINTHELP() char *define=line.gettoken_str(1+ignoreCase); char *src = line.gettoken_str(2+ignoreCase); char *search = line.gettoken_str(3+ignoreCase); char *replace = line.gettoken_str(4+ignoreCase); int searchlen=strlen(search); int replacelen=strlen(replace); if (!searchlen) { ERROR_MSG("!searchreplace: search string must not be empty for search/replace!\n"); return PS_ERROR; } GrowBuf valout; while (*src) { if (ignoreCase ? strnicmp(src,search,searchlen) : strncmp(src,search,searchlen)) valout.add(src++,1); else { valout.add(replace,replacelen); src+=searchlen; } } valout.add("",1); definedlist.del(define); // allow changing variables since we'll often use this in series if (definedlist.add(define,(char*)valout.get())) { ERROR_MSG("!searchreplace: error defining \"%s\"!\n",define); return PS_ERROR; } SCRIPT_MSG("!searchreplace: \"%s\"=\"%s\"\n",define,(char*)valout.get()); } return PS_OK; case TOK_P_VERBOSE: { extern int g_display_errors; int k=line.gettoken_enum(1,"push\0pop\0"); int v; if (k < 0) // just set v=line.gettoken_int(1); else { if (k) { // pop int l=verbose_stack.getlen(); if (l) { v=((int*)verbose_stack.get())[(l/sizeof(int))-1]; verbose_stack.resize(l-sizeof(int)); } else return PS_OK; } else { // push v=0; if (display_errors) { v++; if (display_warnings) { v++; if (display_info) { v++; if (display_script) { v++; } } } } verbose_stack.add(&v,sizeof(int)); return PS_OK; } } display_script=v>3; display_info=v>2; display_warnings=v>1; display_errors=v>0; g_display_errors=display_errors; } return PS_OK; case TOK_UNINSTALLEXENAME: PRINTHELP() #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT case TOK_UNINSTCAPTION: { if (SetInnerString(NLF_UCAPTION,line.gettoken_str(1)) == PS_WARNING) warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0)); SCRIPT_MSG("UninstCaption: \"%s\"\n",line.gettoken_str(1)); } return PS_OK; case TOK_UNINSTICON: SCRIPT_MSG("UninstallIcon: \"%s\"\n",line.gettoken_str(1)); try { free_loaded_icon(uninstaller_icon); uninstaller_icon = load_icon_file(line.gettoken_str(1)); } catch (exception& err) { ERROR_MSG("Error while loading icon from \"%s\": %s\n", line.gettoken_str(1), err.what()); return PS_ERROR; } return PS_OK; case TOK_UNINSTTEXT: { if (!cur_page) { if (SetInnerString(NLF_UNINST_TEXT, line.gettoken_str(1)) == PS_WARNING) warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0)); SetInnerString(NLF_UNINST_SUBTEXT, line.gettoken_str(2)); } else { if (cur_page_type != PAGE_UNINSTCONFIRM) { ERROR_MSG("Error: UninstallText can only be used inside PageEx uninstConfirm.\n"); return PS_ERROR; } cur_page->parms[0] = add_string(line.gettoken_str(1)); cur_page->parms[1] = add_string(line.gettoken_str(2)); } SCRIPT_MSG("UninstallText: \"%s\" \"%s\"\n",line.gettoken_str(1),line.gettoken_str(2)); } return PS_OK; case TOK_UNINSTSUBCAPTION: { int s; int w=line.gettoken_int(1,&s); if (!s || w < 0 || w > 2) PRINTHELP() SetInnerString(NLF_USUBCAPTION_CONFIRM+w,line.gettoken_str(2)); SCRIPT_MSG("UninstSubCaption: page:%d, text=%s\n",w,line.gettoken_str(2)); } return PS_OK; case TOK_WRITEUNINSTALLER: { if (uninstall_mode) { ERROR_MSG("WriteUninstaller only valid from install, not from uninstall.\n"); PRINTHELP() } uninstaller_writes_used++; ent.which=EW_WRITEUNINSTALLER; ent.offsets[0]=add_string(line.gettoken_str(1)); string full = string("$INSTDIR\\") + string(line.gettoken_str(1)); ent.offsets[3]=add_string(full.c_str()); // ent.offsets[1] and ent.offsets[2] are set in CEXEBuild::uninstall_generate() if (!ent.offsets[0]) PRINTHELP() SCRIPT_MSG("WriteUninstaller: \"%s\"\n",line.gettoken_str(1)); DefineInnerLangString(NLF_ERR_CREATING); DefineInnerLangString(NLF_CREATED_UNINST); } return add_entry(&ent); #else//!NSIS_CONFIG_UNINSTALL_SUPPORT case TOK_WRITEUNINSTALLER: case TOK_UNINSTCAPTION: case TOK_UNINSTICON: case TOK_UNINSTTEXT: case TOK_UNINSTSUBCAPTION: ERROR_MSG("Error: %s specified, NSIS_CONFIG_UNINSTALL_SUPPORT not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif // section/function shit /////////////////////////////////////////////////////////////////////////////// case TOK_SECTION: { int a=1,unselected = 0; if (!strcmpi(line.gettoken_str(1),"/o")) { unselected = 1; a++; } else if (line.getnumtokens() > 3) PRINTHELP(); SCRIPT_MSG("Section: \"%s\"",line.gettoken_str(a)); if (line.gettoken_str(a+1)[0]) SCRIPT_MSG(" ->(%s)",line.gettoken_str(a+1)); SCRIPT_MSG("\n"); #ifndef NSIS_CONFIG_UNINSTALL_SUPPORT if (!stricmp(line.gettoken_str(a),"uninstall")) { ERROR_MSG("Error: Uninstall section declared, no NSIS_CONFIG_UNINSTALL_SUPPORT\n"); return PS_ERROR; } #endif int ret; if (line.gettoken_str(a)[0]=='-') { if (!strnicmp(line.gettoken_str(a)+1,"un.",3)) ret=add_section("un.",line.gettoken_str(a+1)); else ret=add_section("",line.gettoken_str(a+1)); } else ret=add_section(line.gettoken_str(a),line.gettoken_str(a+1)); if (ret != PS_OK) return ret; if (unselected) build_cursection->flags &= ~SF_SELECTED; return PS_OK; } case TOK_SECTIONEND: SCRIPT_MSG("SectionEnd\n"); return section_end(); case TOK_SECTIONIN: { SCRIPT_MSG("SectionIn: "); int wt; for (wt = 1; wt < line.getnumtokens(); wt ++) { char *p=line.gettoken_str(wt); if (!stricmp(p, "RO")) { if (section_add_flags(SF_RO) != PS_OK) return PS_ERROR; SCRIPT_MSG("[RO] "); } else { int x=atoi(p)-1; if (x >= 0 && x < NSIS_MAX_INST_TYPES) { if (section_add_install_type(1<(%s)",line.gettoken_str(a+1)); SCRIPT_MSG("\n"); return add_section(buf,line.gettoken_str(a+1),ex); } case TOK_FUNCTION: if (!line.gettoken_str(1)[0]) PRINTHELP() if (line.gettoken_str(1)[0]==':' || line.gettoken_str(1)[0]=='/') { ERROR_MSG("Function: function name cannot begin with : or /.\n"); PRINTHELP() } SCRIPT_MSG("Function: \"%s\"\n",line.gettoken_str(1)); #ifndef NSIS_CONFIG_UNINSTALL_SUPPORT if (!strnicmp(line.gettoken_str(1),"un.",3)) { ERROR_MSG("Error: Uninstall function declared, no NSIS_CONFIG_UNINSTALL_SUPPORT\n"); return PS_ERROR; } #endif return add_function(line.gettoken_str(1)); case TOK_FUNCTIONEND: SCRIPT_MSG("FunctionEnd\n"); return function_end(); // flag setters /////////////////////////////////////////////////////////////////////////////// // BEGIN - Added by ramon 23 May 2003 case TOK_ALLOWSKIPFILES: build_allowskipfiles=line.gettoken_enum(1,"off\0on\0"); if (build_allowskipfiles==-1) PRINTHELP() SCRIPT_MSG("AllowSkipFiles: %s\n",line.gettoken_str(1)); return PS_OK; // END - Added by ramon 23 May 2003 case TOK_SETDATESAVE: build_datesave=line.gettoken_enum(1,"off\0on\0"); if (build_datesave==-1) PRINTHELP() SCRIPT_MSG("SetDateSave: %s\n",line.gettoken_str(1)); return PS_OK; case TOK_SETOVERWRITE: { int k=line.gettoken_enum(1,"on\0off\0try\0ifnewer\0ifdiff\0lastused\0"); if (k==-1) PRINTHELP() if (k==5) { k=build_overwrite; build_overwrite=build_last_overwrite; build_last_overwrite=k; } else { build_last_overwrite=build_overwrite; build_overwrite=k; } SCRIPT_MSG("SetOverwrite: %s\n",line.gettoken_str(1)); } return PS_OK; #ifdef NSIS_CONFIG_PLUGIN_SUPPORT case TOK_SETPLUGINUNLOAD: build_plugin_unload=line.gettoken_enum(1,"manual\0alwaysoff\0"); if (build_plugin_unload==-1) PRINTHELP() SCRIPT_MSG("SetPluginUnload: %s\n",line.gettoken_str(1)); return PS_OK; #endif //NSIS_CONFIG_PLUGIN_SUPPORT case TOK_SETCOMPRESS: build_compress=line.gettoken_enum(1,"off\0auto\0force\0"); if (build_compress==-1) PRINTHELP() if (build_compress==0 && build_compress_whole) { warning_fl("'SetCompress off' encountered, and in whole compression mode. Effectively ignored."); } SCRIPT_MSG("SetCompress: %s\n",line.gettoken_str(1)); return PS_OK; case TOK_DBOPTIMIZE: build_optimize_datablock=line.gettoken_enum(1,"off\0on\0"); if (build_optimize_datablock==-1) PRINTHELP() SCRIPT_MSG("SetDatablockOptimize: %s\n",line.gettoken_str(1)); return PS_OK; case TOK_FILEBUFSIZE: build_filebuflen=line.gettoken_int(1); build_filebuflen<<=20; if (build_filebuflen<=0) { ERROR_MSG("Error: FileBufSize: invalid buffer size -- %d\n",build_filebuflen); return PS_ERROR; } SCRIPT_MSG("FileBufSize: %smb (%d bytes)\n",line.gettoken_str(1),build_filebuflen); return PS_OK; #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT case TOK_SETCOMPRESSIONLEVEL: { if (compressor == &lzma_compressor) warning_fl("SetCompressionLevel: compressor is set to LZMA. Effectively ignored."); if (build_compressor_set && build_compress_whole) warning_fl("SetCompressionLevel: data already compressed in compress whole mode. Effectively ignored."); int s; build_compress_level=line.gettoken_int(1,&s); if (!s || build_compress_level < 0 || build_compress_level > 9) PRINTHELP(); SCRIPT_MSG("SetCompressionLevel: %u\n", build_compress_level); } return PS_OK; case TOK_SETCOMPRESSORDICTSIZE: { if (compressor != &lzma_compressor) warning_fl("SetCompressorDictSize: compressor is not set to LZMA. Effectively ignored."); if (build_compressor_set && build_compress_whole) warning_fl("SetCompressorDictSize: data already compressed in compress whole mode. Effectively ignored."); int s; build_compress_dict_size=line.gettoken_int(1,&s); if (!s) PRINTHELP(); SCRIPT_MSG("SetCompressorDictSize: %u mb\n", build_compress_dict_size); build_compress_dict_size <<= 20; } return PS_OK; #else case TOK_SETCOMPRESSIONLEVEL: case TOK_SETCOMPRESSORDICTSIZE: ERROR_MSG("Error: %s specified, NSIS_CONFIG_COMPRESSION_SUPPORT not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//NSIS_CONFIG_COMPRESSION_SUPPORT case TOK_ADDSIZE: { int s; int size_kb=line.gettoken_int(1,&s); if (!s) PRINTHELP() SCRIPT_MSG("AddSize: %d kb\n",size_kb); section_add_size_kb(size_kb); } return PS_OK; case TOK_SUBCAPTION: { int s; int w=line.gettoken_int(1,&s); if (!s || w < 0 || w > 4) PRINTHELP() SetInnerString(NLF_SUBCAPTION_LICENSE+w,line.gettoken_str(2)); SCRIPT_MSG("SubCaption: page:%d, text=%s\n",w,line.gettoken_str(2)); } return PS_OK; case TOK_FILEERRORTEXT: #ifdef NSIS_SUPPORT_FILE { SetInnerString(NLF_FILE_ERROR,line.gettoken_str(1)); SetInnerString(NLF_FILE_ERROR_NOIGNORE,line.gettoken_str(2)); SCRIPT_MSG("FileErrorText: \"%s\" \"%s\"\n",line.gettoken_str(1),line.gettoken_str(2)); } return PS_OK; #else ERROR_MSG("Error: %s specified, NSIS_SUPPORT_FILE not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif case TOK_BRANDINGTEXT: { int a = 1; int trim = 0; while (line.gettoken_str(a)[0] == '/') { if (!strnicmp(line.gettoken_str(a),"/TRIM",5)) { if (!stricmp(line.gettoken_str(a)+5,"LEFT")) trim = 1; else if (!stricmp(line.gettoken_str(a)+5,"RIGHT")) trim = 2; else if (!stricmp(line.gettoken_str(a)+5,"CENTER")) trim = 3; else PRINTHELP(); a++; } else break; } if (line.getnumtokens()!=a+1 && !trim) PRINTHELP(); if (line.getnumtokens()==a+1) SetInnerString(NLF_BRANDING,line.gettoken_str(a)); #ifdef _WIN32 if (trim) try { init_res_editor(); BYTE* dlg = res_editor->GetResourceA(RT_DIALOG, MAKEINTRESOURCE(IDD_INST), NSIS_DEFAULT_LANG); CDialogTemplate td(dlg,uDefCodePage); free(dlg); if (trim) { char str[512]; if (line.getnumtokens()==a+1 && line.gettoken_str(a)[0]) strcpy(str, line.gettoken_str(a)); else wsprintf(str, "Nullsoft Install System %s", NSIS_VERSION); short old_width = td.GetItem(IDC_VERSTR)->sWidth; switch (trim) { case 1: td.LTrimToString(IDC_VERSTR, str, 4); break; case 2: td.RTrimToString(IDC_VERSTR, str, 4); break; case 3: td.CTrimToString(IDC_VERSTR, str, 4); break; } if (td.GetItem(IDC_VERSTR)->sWidth > old_width) { warning_fl("BrandingText: \"%s\" is too long, trimming has expanded the label", str); } } DWORD dwSize; dlg = td.Save(dwSize); res_editor->UpdateResourceA(RT_DIALOG, MAKEINTRESOURCE(IDD_INST), NSIS_DEFAULT_LANG, dlg, dwSize); res_editor->FreeResource(dlg); } catch (exception& err) { ERROR_MSG("Error while triming branding text control: %s\n", err.what()); return PS_ERROR; } #else if (trim) { ERROR_MSG("Error: BrandingText /TRIM* is disabled for non Win32 platforms.\n"); return PS_ERROR; } #endif SCRIPT_MSG("BrandingText: \"%s\"\n",line.gettoken_str(a)); } return PS_OK; case TOK_MISCBUTTONTEXT: { SetInnerString(NLF_BTN_BACK,line.gettoken_str(1)); SetInnerString(NLF_BTN_NEXT,line.gettoken_str(2)); SetInnerString(NLF_BTN_CANCEL,line.gettoken_str(3)); SetInnerString(NLF_BTN_CLOSE,line.gettoken_str(4)); SCRIPT_MSG("MiscButtonText: back=\"%s\" next=\"%s\" cancel=\"%s\" close=\"%s\"\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4)); } return PS_OK; case TOK_SPACETEXTS: { if (!strcmpi(line.gettoken_str(1), "none")) { no_space_texts=true; SCRIPT_MSG("SpaceTexts: none\n"); } else { no_space_texts=false; SetInnerString(NLF_SPACE_REQ,line.gettoken_str(1)); SetInnerString(NLF_SPACE_AVAIL,line.gettoken_str(2)); SCRIPT_MSG("SpaceTexts: required=\"%s\" available=\"%s\"\n",line.gettoken_str(1),line.gettoken_str(2)); } } return PS_OK; case TOK_INSTBUTTONTEXT: { SetInnerString(NLF_BTN_INSTALL,line.gettoken_str(1)); SCRIPT_MSG("InstallButtonText: \"%s\"\n",line.gettoken_str(1)); } return PS_OK; case TOK_DETAILSBUTTONTEXT: { if (!cur_page) { if (SetInnerString(NLF_BTN_DETAILS,line.gettoken_str(1)) == PS_WARNING) warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0)); } else { if (cur_page_type != PAGE_INSTFILES) { ERROR_MSG("Error: DetailsButtonText can only be used inside PageEx instfiles.\n"); return PS_ERROR; } cur_page->parms[1] = add_string(line.gettoken_str(1)); } SCRIPT_MSG("DetailsButtonText: \"%s\"\n",line.gettoken_str(1)); } return PS_OK; case TOK_COMPLETEDTEXT: { if (!cur_page) { if (SetInnerString(NLF_COMPLETED,line.gettoken_str(1)) == PS_WARNING) warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0)); } else { if (cur_page_type != PAGE_INSTFILES) { ERROR_MSG("Error: CompletedText can only be used inside PageEx instfiles.\n"); return PS_ERROR; } cur_page->parms[2] = add_string(line.gettoken_str(1)); } SCRIPT_MSG("CompletedText: \"%s\"\n",line.gettoken_str(1)); } return PS_OK; case TOK_UNINSTBUTTONTEXT: #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT { SetInnerString(NLF_BTN_UNINSTALL,line.gettoken_str(1)); SCRIPT_MSG("UninstButtonText: \"%s\"\n",line.gettoken_str(1)); } return PS_OK; #else ERROR_MSG("Error: %s specified, NSIS_CONFIG_UNINSTALL_SUPPORT not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif // instructions /////////////////////////////////////////////////////////////////////////////// case TOK_NOP: SCRIPT_MSG("Nop\n"); ent.which=EW_NOP; return add_entry(&ent); case TOK_GOTO: ent.which=EW_NOP; if (process_jump(line,1,&ent.offsets[0])) PRINTHELP() SCRIPT_MSG("Goto: %s\n",line.gettoken_str(1)); return add_entry(&ent); case TOK_SETREGVIEW: { ent.which=EW_SETFLAG; ent.offsets[0]=FLAG_OFFSET(alter_reg_view); // "64" results in setting the flag to 1 which alters the view int k=line.gettoken_enum(1,"32\0" "64\0lastused\0"); if (k<0) PRINTHELP() if (k == 0) // 32 ent.offsets[1]=add_intstring(0); else if (k == 1) // 64 ent.offsets[1]=add_intstring(KEY_WOW64_64KEY); else if (k == 2) // last used ent.offsets[2]=1; SCRIPT_MSG("SetRegView: %s\n",line.gettoken_str(1)); } return add_entry(&ent); case TOK_SETSHELLVARCONTEXT: { ent.which=EW_SETFLAG; ent.offsets[0]=FLAG_OFFSET(all_user_var); int k=line.gettoken_enum(1,"current\0all\0"); if (k<0) PRINTHELP() ent.offsets[1]=add_intstring(k); SCRIPT_MSG("SetShellVarContext: %s\n",line.gettoken_str(1)); } return add_entry(&ent); case TOK_RET: SCRIPT_MSG("Return\n"); ent.which=EW_RET; return add_entry(&ent); case TOK_CALL: if (!line.gettoken_str(1)[0] || (line.gettoken_str(1)[0]==':' && !line.gettoken_str(1)[1] )) PRINTHELP() #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT if (uninstall_mode && strnicmp(line.gettoken_str(1),"un.",3) && (GetUserVarIndex(line,1) < 0) && line.gettoken_str(1)[0]!=':') { ERROR_MSG("Call must be used with function names starting with \"un.\" in the uninstall section.\n"); PRINTHELP() } if (!uninstall_mode && !strnicmp(line.gettoken_str(1),"un.",3)) { ERROR_MSG("Call must not be used with functions starting with \"un.\" in the non-uninstall sections.\n"); PRINTHELP() } #endif ent.which=EW_CALL; ent.offsets[1]=0; { int v; if ((v=GetUserVarIndex(line, 1))>=0) { ent.offsets[0]=-v-2; } else { if (line.gettoken_str(1)[0] == ':') { ent.offsets[1]=1; ent.offsets[0]=ns_label.add(line.gettoken_str(1)+1,0); } else ent.offsets[0]=ns_func.add(line.gettoken_str(1),0); } } SCRIPT_MSG("Call \"%s\"\n",line.gettoken_str(1)); return add_entry(&ent); case TOK_SETOUTPATH: { char *op=line.gettoken_str(1); if (!strcmp(op,"-")) { op="$INSTDIR"; } SCRIPT_MSG("SetOutPath: \"%s\"\n",op); ent.which=EW_CREATEDIR; ent.offsets[0]=add_string(op); ent.offsets[1]=1; DefineInnerLangString(NLF_OUTPUT_DIR); } return add_entry(&ent); case TOK_CREATEDIR: { char out_path[1024]; char *p=line.gettoken_str(1); if (*p == '-') out_path[0]=0; else { if (p[0] == '\\' && p[1] != '\\') p++; strncpy(out_path,p,1024-1); if (*CharPrev(out_path,out_path+strlen(out_path))=='\\') *CharPrev(out_path,out_path+strlen(out_path))=0; // remove trailing slash } if (!*out_path) PRINTHELP() SCRIPT_MSG("CreateDirectory: \"%s\"\n",out_path); ent.which=EW_CREATEDIR; ent.offsets[0]=add_string(out_path); DefineInnerLangString(NLF_CREATE_DIR); } return add_entry(&ent); case TOK_EXEC: case TOK_EXECWAIT: #ifdef NSIS_SUPPORT_EXECUTE ent.which=EW_EXECUTE; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[2]=0; if (which_token == TOK_EXECWAIT) { ent.offsets[2]=1; ent.offsets[1]=GetUserVarIndex(line, 2); if (line.gettoken_str(2)[0] && ent.offsets[1]<0) PRINTHELP() } SCRIPT_MSG("%s: \"%s\" (->%s)\n",ent.offsets[2]?"ExecWait":"Exec",line.gettoken_str(1),line.gettoken_str(2)); DefineInnerLangString(NLF_EXEC); return add_entry(&ent); #else//!NSIS_SUPPORT_EXECUTE ERROR_MSG("Error: %s specified, NSIS_SUPPORT_EXECUTE not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_EXECUTE case TOK_EXECSHELL: // this uses improvements of Andras Varga #ifdef NSIS_SUPPORT_SHELLEXECUTE { ent.which=EW_SHELLEXEC; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=add_string(line.gettoken_str(2)); ent.offsets[2]=add_string(line.gettoken_str(3)); ent.offsets[3]=SW_SHOWNORMAL; if (line.getnumtokens() > 4) { int tab[4]={SW_SHOWNORMAL,SW_SHOWMAXIMIZED,SW_SHOWMINIMIZED,SW_HIDE}; int a=line.gettoken_enum(4,"SW_SHOWNORMAL\0SW_SHOWMAXIMIZED\0SW_SHOWMINIMIZED\0SW_HIDE\0"); if (a < 0) PRINTHELP() ent.offsets[3]=tab[a]; } string detail=string(line.gettoken_str(1))+" "+string(line.gettoken_str(2)); ent.offsets[5]=add_string(detail.c_str()); SCRIPT_MSG("ExecShell: %s: \"%s\" \"%s\" %s\n",line.gettoken_str(1),line.gettoken_str(2), line.gettoken_str(3),line.gettoken_str(4)); DefineInnerLangString(NLF_EXEC_SHELL); } return add_entry(&ent); #else//!NSIS_SUPPORT_SHELLEXECUTE ERROR_MSG("Error: %s specified, NSIS_SUPPORT_SHELLEXECUTE not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_SHELLEXECUTE case TOK_CALLINSTDLL: case TOK_REGDLL: case TOK_UNREGDLL: #ifndef NSIS_SUPPORT_ACTIVEXREG ERROR_MSG("%s: support not compiled in (NSIS_SUPPORT_ACTIVEXREG)\n",line.gettoken_str(0)); return PS_ERROR; #else//NSIS_SUPPORT_ACTIVEXREG ent.which=EW_REGISTERDLL; ent.offsets[0]=add_string(line.gettoken_str(1)); if (which_token == TOK_UNREGDLL) { ent.offsets[1]=add_string("DllUnregisterServer"); ent.offsets[2]=DefineInnerLangString(NLF_UNREGISTERING); } else if (which_token == TOK_CALLINSTDLL) { int a = 2; if (!stricmp(line.gettoken_str(a), "/NOUNLOAD")) { ent.offsets[3]=1; a++; } if (a+1 != line.getnumtokens()) PRINTHELP(); ent.offsets[1]=add_string(line.gettoken_str(a)); if (!ent.offsets[1]) PRINTHELP() ent.offsets[2]=0; } else // register { ent.offsets[1] = add_string(line.gettoken_str(2)); if (!ent.offsets[1]) ent.offsets[1]=add_string("DllRegisterServer"); ent.offsets[2]=DefineInnerLangString(NLF_REGISTERING); } SCRIPT_MSG("%s: \"%s\" %s\n",line.gettoken_str(0),line.gettoken_str(1), line.gettoken_str(ent.offsets[3]?3:2)); DefineInnerLangString(NLF_SYMBOL_NOT_FOUND); DefineInnerLangString(NLF_COULD_NOT_LOAD); DefineInnerLangString(NLF_NO_OLE); // not used anywhere - DefineInnerLangString(NLF_ERR_REG_DLL); return add_entry(&ent); #endif//NSIS_SUPPORT_ACTIVEXREG case TOK_RENAME: #ifdef NSIS_SUPPORT_RENAME { int a=1; ent.which=EW_RENAME; if (!stricmp(line.gettoken_str(1),"/REBOOTOK")) { ent.offsets[2]=1; a++; #ifndef NSIS_SUPPORT_MOVEONREBOOT ERROR_MSG("Error: /REBOOTOK specified, NSIS_SUPPORT_MOVEONREBOOT not defined\n"); PRINTHELP() #endif } else if (line.gettoken_str(1)[0]=='/') { a=line.getnumtokens(); // cause usage to go here: } if (line.getnumtokens()!=a+2) PRINTHELP() ent.offsets[0]=add_string(line.gettoken_str(a)); ent.offsets[1]=add_string(line.gettoken_str(a+1)); string print = string(line.gettoken_str(a)) + "->" + string(line.gettoken_str(a+1)); ent.offsets[3]=add_string(print.c_str()); SCRIPT_MSG("Rename: %s%s->%s\n",ent.offsets[2]?"/REBOOTOK ":"",line.gettoken_str(a),line.gettoken_str(a+1)); DefineInnerLangString(NLF_RENAME); #ifdef NSIS_SUPPORT_MOVEONREBOOT DefineInnerLangString(NLF_RENAME_ON_REBOOT); #endif } return add_entry(&ent); #else//!NSIS_SUPPORT_RENAME ERROR_MSG("Error: %s specified, NSIS_SUPPORT_RENAME not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_RENAME case TOK_MESSAGEBOX: #ifdef NSIS_SUPPORT_MESSAGEBOX { #define MBD(x) {x,#x}, struct { int id; char *str; } list[]= { MBD(MB_ABORTRETRYIGNORE) MBD(MB_OK) MBD(MB_OKCANCEL) MBD(MB_RETRYCANCEL) MBD(MB_YESNO) MBD(MB_YESNOCANCEL) MBD(MB_ICONEXCLAMATION) MBD(MB_ICONINFORMATION) MBD(MB_ICONQUESTION) MBD(MB_ICONSTOP) MBD(MB_USERICON) MBD(MB_TOPMOST) MBD(MB_SETFOREGROUND) MBD(MB_RIGHT) MBD(MB_RTLREADING) MBD(MB_DEFBUTTON1) MBD(MB_DEFBUTTON2) MBD(MB_DEFBUTTON3) MBD(MB_DEFBUTTON4) }; #undef MBD int r=0; int x; char *p=line.gettoken_str(1); while (*p) { char *np=p; while (*np && *np != '|') np++; if (*np) *np++=0; for (x = 0 ; (unsigned) x < sizeof(list) / sizeof(list[0]) && strcmpi(list[x].str, p); x++); if ((unsigned) x < sizeof(list) / sizeof(list[0])) { r|=list[x].id; } else PRINTHELP() p=np; } ent.which=EW_MESSAGEBOX; ent.offsets[0]=r; ent.offsets[1]=add_string(line.gettoken_str(2)); int rettab[] = { 0,IDABORT,IDCANCEL,IDIGNORE,IDNO,IDOK,IDRETRY,IDYES }; const char *retstr="0\0IDABORT\0IDCANCEL\0IDIGNORE\0IDNO\0IDOK\0IDRETRY\0IDYES\0"; int a=3; if (line.getnumtokens() > 3) { if (!strcmpi(line.gettoken_str(3),"/SD")) { int k=line.gettoken_enum(4,retstr); if (k <= 0) PRINTHELP(); ent.offsets[0]|=rettab[k]<<21; a=5; } else if (line.getnumtokens() > 7) PRINTHELP(); if (line.getnumtokens() > a) { ent.offsets[2]=line.gettoken_enum(a,retstr); if (ent.offsets[2] < 0) PRINTHELP(); ent.offsets[2] = rettab[ent.offsets[2]]; if (process_jump(line,a+1,&ent.offsets[3])) PRINTHELP(); if (line.getnumtokens() > a+2) { int v=line.gettoken_enum(a+2,retstr); if (v < 0) PRINTHELP(); ent.offsets[4] = rettab[v]; if (process_jump(line,a+3,&ent.offsets[5])) PRINTHELP(); } } } SCRIPT_MSG("MessageBox: %d: \"%s\"",r,line.gettoken_str(2)); if (line.getnumtokens()>a+1) SCRIPT_MSG(" (on %s goto %s)",line.gettoken_str(a),line.gettoken_str(a+1)); SCRIPT_MSG("\n"); } return add_entry(&ent); #else//!NSIS_SUPPORT_MESSAGEBOX ERROR_MSG("Error: %s specified, NSIS_SUPPORT_MESSAGEBOX not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_MESSAGEBOX case TOK_CREATESHORTCUT: #ifdef NSIS_SUPPORT_CREATESHORTCUT ent.which=EW_CREATESHORTCUT; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=add_string(line.gettoken_str(2)); ent.offsets[2]=add_string(line.gettoken_str(3)); ent.offsets[3]=add_string(line.gettoken_str(4)); ent.offsets[5]=add_string(line.gettoken_str(8)); int s; ent.offsets[4]=line.gettoken_int(5,&s)&0xff; if (!s) { if (line.getnumtokens() > 5 && *line.gettoken_str(5)) { ERROR_MSG("CreateShortCut: cannot interpret icon index\n"); PRINTHELP() } ent.offsets[4]=0; } if (line.getnumtokens() > 6 && *line.gettoken_str(6)) { int tab[3]={SW_SHOWNORMAL,SW_SHOWMAXIMIZED,SW_SHOWMINNOACTIVE/*SW_SHOWMINIMIZED doesn't work*/}; int a=line.gettoken_enum(6,"SW_SHOWNORMAL\0SW_SHOWMAXIMIZED\0SW_SHOWMINIMIZED\0"); if (a < 0) { ERROR_MSG("CreateShortCut: unknown show mode \"%s\"\n",line.gettoken_str(6)); PRINTHELP() } ent.offsets[4]|=tab[a]<<8; } if (line.getnumtokens() > 7) { char *s=(line.gettoken_str(7)); char b[255]; for (unsigned int spos=0; (spos <= strlen(s)) && (spos <= 255); spos++) b[spos]=toupper(*(s+spos)); strcpy(s,b); if (*s) { int c=0; if (strstr(s,"ALT|")) ent.offsets[4]|=HOTKEYF_ALT << 24; if (strstr(s,"CONTROL|")) ent.offsets[4]|=HOTKEYF_CONTROL << 24; if (strstr(s,"EXT|")) ent.offsets[4]|=HOTKEYF_EXT << 24; if (strstr(s,"SHIFT|")) ent.offsets[4]|=HOTKEYF_SHIFT << 24; while (strstr(s,"|")) { s=strstr(s,"|")+1; } if ((s[0] == 'F') && (s[1] >= '1' && s[1] <= '9')) { c=VK_F1-1+atoi(s+1); if (atoi(s+1) < 1 || atoi(s+1) > 24) { warning_fl("CreateShortCut: F-key \"%s\" out of range",s); } } else if (((s[0] >= 'A' && s[0] <= 'Z') || (s[0] >= '0' && s[0] <= '9')) && !s[1]) c=s[0]; else { c=s[0]; warning_fl("CreateShortCut: unrecognized hotkey \"%s\"",s); } ent.offsets[4] |= (c) << 16; } } SCRIPT_MSG("CreateShortCut: \"%s\"->\"%s\" %s icon:%s,%d, showmode=0x%X, hotkey=0x%X, comment=%s\n", line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3), line.gettoken_str(4),ent.offsets[4]&0xff,(ent.offsets[4]>>8)&0xff,ent.offsets[4]>>16,line.gettoken_str(8)); DefineInnerLangString(NLF_CREATE_SHORTCUT); DefineInnerLangString(NLF_ERR_CREATING_SHORTCUT); return add_entry(&ent); #else//!NSIS_SUPPORT_CREATESHORTCUT ERROR_MSG("Error: %s specified, NSIS_SUPPORT_CREATESHORTCUT not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//NSIS_SUPPORT_CREATESHORTCUT #ifdef NSIS_SUPPORT_HWNDS case TOK_FINDWINDOW: ent.which=EW_FINDWINDOW; ent.offsets[0]=GetUserVarIndex(line, 1); if (ent.offsets[0] < 0) PRINTHELP() ent.offsets[1]=add_string(line.gettoken_str(2)); ent.offsets[2]=add_string(line.gettoken_str(3)); ent.offsets[3]=add_string(line.gettoken_str(4)); ent.offsets[4]=add_string(line.gettoken_str(5)); SCRIPT_MSG("FindWindow: output=%s, class=\"%s\", text=\"%s\" hwndparent=\"%s\" hwndafter=\"%s\"\n", line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4),line.gettoken_str(5)); return add_entry(&ent); case TOK_SENDMESSAGE: ent.which=EW_SENDMESSAGE; if (line.gettoken_str(1)[0] == '/' || line.gettoken_str(2)[0] == '/' || line.gettoken_str(3)[0] == '/' || line.gettoken_str(4)[0] == '/') { PRINTHELP() } SCRIPT_MSG("SendMessage:"); { int a=5; ent.offsets[0]=GetUserVarIndex(line, 5); if (ent.offsets[0]>=0) { SCRIPT_MSG("(->%s)",line.gettoken_str(5)); a++; } if (!strncmp(line.gettoken_str(a),"/TIMEOUT=",9)) { ent.offsets[5]|=atoi(line.gettoken_str(a)+9)<<2; SCRIPT_MSG(" (timeout=%d)",ent.offsets[5]>>2); a++; } if (line.getnumtokens()>a) { PRINTHELP() } } if (!strncmp(line.gettoken_str(3),"STR:",4)) { ent.offsets[5]|=1; ent.offsets[3]=add_string(line.gettoken_str(3)+4); } else ent.offsets[3]=add_string(line.gettoken_str(3)); if (!strncmp(line.gettoken_str(4),"STR:",4)) { ent.offsets[5]|=2; ent.offsets[4]=add_string(line.gettoken_str(4)+4); } else ent.offsets[4]=add_string(line.gettoken_str(4)); ent.offsets[1]=add_string(line.gettoken_str(1)); ent.offsets[2]=add_string(line.gettoken_str(2)); SCRIPT_MSG("(%s,%s,%s,%s)\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4)); return add_entry(&ent); case TOK_ISWINDOW: ent.which=EW_ISWINDOW; ent.offsets[0]=add_string(line.gettoken_str(1)); if (process_jump(line,2,&ent.offsets[1])|| process_jump(line,3,&ent.offsets[2])) PRINTHELP() SCRIPT_MSG("IsWindow(%s): %s:%s\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3)); return add_entry(&ent); #ifdef NSIS_CONFIG_ENHANCEDUI_SUPPORT case TOK_GETDLGITEM: ent.which=EW_GETDLGITEM; ent.offsets[0]=GetUserVarIndex(line, 1); if (ent.offsets[0]<0) PRINTHELP(); ent.offsets[1]=add_string(line.gettoken_str(2)); ent.offsets[2]=add_string(line.gettoken_str(3)); SCRIPT_MSG("GetDlgItem: output=%s dialog=%s item=%s\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3)); return add_entry(&ent); case TOK_SETCTLCOLORS: { ctlcolors c={0, }; ent.which=EW_SETCTLCOLORS; ent.offsets[0]=add_string(line.gettoken_str(1)); int a = 2; if (!strcmpi(line.gettoken_str(2),"/BRANDING")) a++; { char *p; if (a == 2 && line.getnumtokens() == 5) { ERROR_MSG("Error: SetCtlColors expected 3 parameters, got 4\n"); return PS_ERROR; } if (!strcmpi(line.gettoken_str(a+1),"transparent")) { c.flags|=CC_BKB; c.lbStyle=BS_NULL; c.bkmode=TRANSPARENT; } else { p=line.gettoken_str(a+1); if (*p) { int v=strtoul(p,&p,16); c.bkc=((v&0xff)<<16)|(v&0xff00)|((v&0xff0000)>>16); c.flags|=CC_BK|CC_BKB; } c.lbStyle=BS_SOLID; c.bkmode=OPAQUE; } p=line.gettoken_str(a); if (*p) { int v=strtoul(p,&p,16); c.text=((v&0xff)<<16)|(v&0xff00)|((v&0xff0000)>>16); c.flags|=CC_TEXT; } } if (a == 3) { c.flags|=CC_BK|CC_BKB; c.lbStyle=BS_NULL; if (!*line.gettoken_str(a+1)) { c.bkc=COLOR_BTNFACE; c.flags|=CC_BK_SYS; } c.flags|=CC_TEXT; if (!*line.gettoken_str(a)) { c.text=COLOR_BTNFACE; c.flags|=CC_TEXT_SYS; } c.bkmode=OPAQUE; } int i; int l=cur_ctlcolors->getlen()/sizeof(ctlcolors); for (i=0; iget()+i,&c,sizeof(ctlcolors))) { ent.offsets[1]=i*sizeof(ctlcolors); break; } } if (i>=l) { ent.offsets[1]=cur_ctlcolors->add(&c,sizeof(ctlcolors)); } SCRIPT_MSG("SetCtlColors: hwnd=%s %stext=%s background=%s\n",line.gettoken_str(1),a==2?"":"/BRANDING ",line.gettoken_str(a),line.gettoken_str(a+1)); } return add_entry(&ent); case TOK_CREATEFONT: ent.which=EW_CREATEFONT; ent.offsets[0]=GetUserVarIndex(line, 1); ent.offsets[1]=add_string(line.gettoken_str(2)); SCRIPT_MSG("CreateFont: output=%s \"%s\"",line.gettoken_str(1),line.gettoken_str(2)); { int height=0; int weight=0; int flags=0; for (int i = 3; i < line.getnumtokens(); i++) { char *tok=line.gettoken_str(i); if (tok[0]=='/') { if (!strcmpi(tok,"/ITALIC")) { SCRIPT_MSG(" /ITALIC"); flags|=1; } else if (!strcmpi(tok,"/UNDERLINE")) { SCRIPT_MSG(" /UNDERLINE"); flags|=2; } else if (!strcmpi(tok,"/STRIKE")) { SCRIPT_MSG(" /STRIKE"); flags|=4; } else { SCRIPT_MSG("\n"); PRINTHELP(); } } else { if (!height) { SCRIPT_MSG(" height=%s",tok); height=add_string(tok); } else if (!weight) { SCRIPT_MSG(" weight=%s",tok); weight=add_string(tok); } else { SCRIPT_MSG("\n"); PRINTHELP(); } } } ent.offsets[2]=height; ent.offsets[3]=weight; ent.offsets[4]=flags; } SCRIPT_MSG("\n"); return add_entry(&ent); case TOK_ENABLEWINDOW: ent.which=EW_SHOWWINDOW; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=add_string(line.gettoken_str(2)); ent.offsets[3]=1; SCRIPT_MSG("EnableWindow: handle=%s enable=%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_SHOWWINDOW: ent.which=EW_SHOWWINDOW; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=add_string(line.gettoken_str(2)); SCRIPT_MSG("ShowWindow: handle=%s show state=%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_HIDEWINDOW: ent.which=EW_SHOWWINDOW; ent.offsets[0]=add_string("$HWNDPARENT"); ent.offsets[1]=add_string("0"/*SW_HIDE*/); ent.offsets[2]=1; SCRIPT_MSG("HideWindow\n"); return add_entry(&ent); case TOK_BRINGTOFRONT: { int ret; ent.which=EW_SHOWWINDOW; ent.offsets[0]=add_string("$HWNDPARENT"); ent.offsets[1]=add_string("5"/*SW_SHOW*/); ret = add_entry(&ent); if (ret != PS_OK) return ret; ent.which=EW_BRINGTOFRONT; ent.offsets[0]=0; ent.offsets[1]=0; SCRIPT_MSG("BringToFront\n"); } return add_entry(&ent); #else//NSIS_CONFIG_ENHANCEDUI_SUPPORT case TOK_GETDLGITEM: case TOK_SETCTLCOLORS: case TOK_SHOWWINDOW: case TOK_BRINGTOFRONT: case TOK_CREATEFONT: case TOK_HIDEWINDOW: case TOK_ENABLEWINDOW: ERROR_MSG("Error: %s specified, NSIS_CONFIG_ENHANCEDUI_SUPPORT not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//NSIS_CONFIG_ENHANCEDUI_SUPPORT #else//!NSIS_SUPPORT_HWNDS case TOK_ISWINDOW: case TOK_SENDMESSAGE: case TOK_FINDWINDOW: case TOK_GETDLGITEM: case TOK_SETCTLCOLORS: case TOK_SHOWWINDOW: case TOK_ENABLEWINDOW: case TOK_CREATEFONT: case TOK_HIDEWINDOW: case TOK_BRINGTOFRONT: ERROR_MSG("Error: %s specified, NSIS_SUPPORT_HWNDS not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_HWNDS case TOK_DELETE: #ifdef NSIS_SUPPORT_DELETE { int a=1; ent.which=EW_DELETEFILE; if (!stricmp(line.gettoken_str(a),"/REBOOTOK")) { a++; ent.offsets[1]=DEL_REBOOT; #ifndef NSIS_SUPPORT_MOVEONREBOOT ERROR_MSG("Error: /REBOOTOK specified, NSIS_SUPPORT_MOVEONREBOOT not defined\n"); PRINTHELP() #endif } else if (line.gettoken_str(1)[0]=='/') { a=line.getnumtokens(); } if (line.getnumtokens() != a+1) PRINTHELP() ent.offsets[0]=add_string(line.gettoken_str(a)); SCRIPT_MSG("Delete: %s\"%s\"\n",ent.offsets[1]?"/REBOOTOK ":"",line.gettoken_str(a)); DefineInnerLangString(NLF_DEL_FILE); #ifdef NSIS_SUPPORT_MOVEONREBOOT DefineInnerLangString(NLF_DEL_ON_REBOOT); #endif } return add_entry(&ent); #else//!NSIS_SUPPORT_DELETE ERROR_MSG("Error: %s specified, NSIS_SUPPORT_DELETE not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_DELETE case TOK_RMDIR: #ifdef NSIS_SUPPORT_RMDIR { int a=1; ent.which=EW_RMDIR; ent.offsets[1]=DEL_DIR; while (line.gettoken_str(a)[0]=='/') { if (!stricmp(line.gettoken_str(a),"/r")) { if (a == 3) PRINTHELP(); a++; ent.offsets[1]|=DEL_RECURSE; } else if (!stricmp(line.gettoken_str(a),"/REBOOTOK")) { if (a == 3) PRINTHELP(); a++; ent.offsets[1]|=DEL_REBOOT; } else PRINTHELP(); } if (a < line.getnumtokens() - 1) PRINTHELP(); ent.offsets[0]=add_string(line.gettoken_str(a)); SCRIPT_MSG("RMDir: "); if (a>1) SCRIPT_MSG("%s ",line.gettoken_str(1)); if (a>2) SCRIPT_MSG("%s ",line.gettoken_str(2)); SCRIPT_MSG("\"%s\"\n",line.gettoken_str(a)); DefineInnerLangString(NLF_REMOVE_DIR); DefineInnerLangString(NLF_DEL_FILE); #ifdef NSIS_SUPPORT_MOVEONREBOOT DefineInnerLangString(NLF_DEL_ON_REBOOT); #endif } return add_entry(&ent); #else//!NSIS_SUPPORT_RMDIR ERROR_MSG("Error: %s specified, NSIS_SUPPORT_RMDIR not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_RMDIR case TOK_RESERVEFILE: case TOK_FILE: #ifdef NSIS_SUPPORT_FILE { set excluded; int a=1,attrib=0,rec=0,fatal=1; if (!stricmp(line.gettoken_str(a),"/nonfatal")) { fatal=0; a++; } if (which_token == TOK_FILE && !stricmp(line.gettoken_str(a),"/a")) { #ifdef _WIN32 attrib=1; #else warning_fl("%sFile /a is disabled for non Win32 platforms.",(which_token == TOK_FILE)?"":"Reserve"); #endif a++; } if (!stricmp(line.gettoken_str(a),"/r")) { rec=1; a++; } else if (which_token == TOK_FILE && !strnicmp(line.gettoken_str(a),"/oname=",7)) { char *on=line.gettoken_str(a)+7; a++; if (!*on||line.getnumtokens()!=a+1||strstr(on,"*") || strstr(on,"?")) PRINTHELP() if (on[0]=='"') { ERROR_MSG("%sFile: output name must not begin with a quote, use \"/oname=name with spaces\".\n",(which_token == TOK_FILE)?"":"Reserve",line.gettoken_str(a)); PRINTHELP(); } int tf=0; #ifdef _WIN32 int v=do_add_file(line.gettoken_str(a), attrib, 0, &tf, on); #else char *fn = my_convert(line.gettoken_str(a)); int v=do_add_file(fn, attrib, 0, &tf, on); my_convert_free(fn); #endif if (v != PS_OK) return v; if (tf > 1) PRINTHELP() if (!tf) { if (fatal) { ERROR_MSG("%sFile: \"%s\" -> no files found.\n",(which_token == TOK_FILE)?"":"Reserve",line.gettoken_str(a)); PRINTHELP() } else { warning_fl("%sFile: \"%s\" -> no files found",(which_token == TOK_FILE)?"":"Reserve",line.gettoken_str(a)); // workaround for bug #1299100 // add a nop opcode so relative jumps will work as expected add_entry_direct(EW_NOP); } } return PS_OK; } if (!strnicmp(line.gettoken_str(a),"/x",2)) { while (!strnicmp(line.gettoken_str(a),"/x",2)) { a++; if (line.getnumtokens() < a+1) PRINTHELP() excluded.insert(line.gettoken_str(a)); a++; } } #ifdef _WIN32 if (line.gettoken_str(a)[0] == '/') PRINTHELP() #endif if (line.getnumtokens() no files found.\n",(which_token == TOK_FILE)?"":"Reserve",t); PRINTHELP(); } else { warning_fl("%sFile: \"%s\" -> no files found.",(which_token == TOK_FILE)?"":"Reserve",t); } } } } return PS_OK; #else//!NSIS_SUPPORT_FILE ERROR_MSG("Error: %s specified, NSIS_SUPPORT_FILE not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_FILE #ifdef NSIS_SUPPORT_COPYFILES case TOK_COPYFILES: { ent.which=EW_COPYFILES; ent.offsets[2]=FOF_NOCONFIRMATION|FOF_NOCONFIRMMKDIR|FOF_NOERRORUI|FOF_SIMPLEPROGRESS; int a=1; int x; for (x = 0; x < 2; x ++) { if (!stricmp(line.gettoken_str(a),"/SILENT")) { a++; ent.offsets[2]&=~FOF_SIMPLEPROGRESS; ent.offsets[2]|=FOF_SILENT; } else if (!stricmp(line.gettoken_str(a),"/FILESONLY")) { a++; ent.offsets[2]|=FOF_FILESONLY; } else if (line.gettoken_str(a)[0]=='/') PRINTHELP() else break; } if (line.getnumtokens() < a+2) PRINTHELP() ent.offsets[0]=add_string(line.gettoken_str(a)); ent.offsets[1]=add_string(line.gettoken_str(a+1)); string copy_to = string("$(^CopyTo)") + line.gettoken_str(a+1); ent.offsets[3]=add_string(copy_to.c_str()); int s; int size_kb=line.gettoken_int(a+2,&s); if (!s && line.gettoken_str(a+2)[0]) PRINTHELP() section_add_size_kb(size_kb); SCRIPT_MSG("CopyFiles: %s\"%s\" -> \"%s\", size=%iKB\n",ent.offsets[2]&FOF_SILENT?"(silent) ":"", line.gettoken_str(a),line.gettoken_str(a+1),size_kb); DefineInnerLangString(NLF_COPY_FAILED); DefineInnerLangString(NLF_COPY_TO); } return add_entry(&ent); #else//!NSIS_SUPPORT_COPYFILES case TOK_COPYFILES: ERROR_MSG("Error: %s specified, NSIS_SUPPORT_COPYFILES not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_COPYFILES case TOK_SETFILEATTRIBUTES: { #define MBD(x) {x,#x}, struct { int id; char *str; } list[]= { MBD(FILE_ATTRIBUTE_NORMAL) MBD(FILE_ATTRIBUTE_ARCHIVE) MBD(FILE_ATTRIBUTE_HIDDEN) MBD(FILE_ATTRIBUTE_OFFLINE) MBD(FILE_ATTRIBUTE_READONLY) MBD(FILE_ATTRIBUTE_SYSTEM) MBD(FILE_ATTRIBUTE_TEMPORARY) {FILE_ATTRIBUTE_NORMAL,"NORMAL"}, {FILE_ATTRIBUTE_ARCHIVE,"ARCHIVE"}, {FILE_ATTRIBUTE_HIDDEN,"HIDDEN"}, {FILE_ATTRIBUTE_OFFLINE,"OFFLINE"}, {FILE_ATTRIBUTE_READONLY,"READONLY"}, {FILE_ATTRIBUTE_SYSTEM,"SYSTEM"}, {FILE_ATTRIBUTE_TEMPORARY,"TEMPORARY"}, {FILE_ATTRIBUTE_NORMAL,"0"}, }; #undef MBD int r=0; int x; char *p=line.gettoken_str(2); while (*p) { char *np=p; while (*np && *np != '|') np++; if (*np) *np++=0; for (x = 0 ; (unsigned) x < sizeof(list)/sizeof(list[0]) && stricmp(list[x].str,p); x ++); if ((unsigned) x < sizeof(list)/sizeof(list[0])) { r|=list[x].id; } else PRINTHELP() p=np; } ent.which=EW_SETFILEATTRIBUTES; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=r; } return add_entry(&ent); case TOK_SLEEP: { ent.which=EW_SLEEP; ent.offsets[0]=add_string(line.gettoken_str(1)); SCRIPT_MSG("Sleep: %s ms\n",line.gettoken_str(1)); } return add_entry(&ent); case TOK_IFFILEEXISTS: ent.which=EW_IFFILEEXISTS; ent.offsets[0] = add_string(line.gettoken_str(1)); if (process_jump(line,2,&ent.offsets[1]) || process_jump(line,3,&ent.offsets[2])) PRINTHELP() SCRIPT_MSG("IfFileExists: \"%s\" ? %s : %s\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3)); return add_entry(&ent); case TOK_QUIT: ent.which=EW_QUIT; SCRIPT_MSG("Quit\n"); return add_entry(&ent); case TOK_ABORT: ent.which=EW_ABORT; ent.offsets[0] = add_string(line.gettoken_str(1)); SCRIPT_MSG("Abort: \"%s\"\n",line.gettoken_str(1)); return add_entry(&ent); case TOK_SETDETAILSVIEW: { int v=line.gettoken_enum(1,"hide\0show\0"); ent.which=EW_CHDETAILSVIEW; if (v < 0) PRINTHELP() ent.offsets[0] = v?SW_SHOWNA:SW_HIDE; ent.offsets[1] = v?SW_HIDE:SW_SHOWNA; SCRIPT_MSG("SetDetailsView: %s\n",line.gettoken_str(1)); } return add_entry(&ent); case TOK_SETDETAILSPRINT: { ent.which=EW_SETFLAG; ent.offsets[0]=FLAG_OFFSET(status_update); int k=line.gettoken_enum(1,"both\0textonly\0listonly\0none\0lastused\0"); if (k<0) PRINTHELP() if (k == 4) { ent.offsets[2]=1; } else { // both 0 // textonly 2 // listonly 4 // none 6 ent.offsets[1]=add_intstring(k*2); } SCRIPT_MSG("SetDetailsPrint: %s\n",line.gettoken_str(1)); } return add_entry(&ent); case TOK_SETAUTOCLOSE: { ent.which=EW_SETFLAG; ent.offsets[0]=FLAG_OFFSET(autoclose); int k=line.gettoken_enum(1,"false\0true\0"); if (k < 0) PRINTHELP() ent.offsets[1]=add_intstring(k); SCRIPT_MSG("SetAutoClose: %s\n",line.gettoken_str(1)); } return add_entry(&ent); case TOK_IFERRORS: ent.which=EW_IFFLAG; if (process_jump(line,1,&ent.offsets[0]) || process_jump(line,2,&ent.offsets[1])) PRINTHELP() ent.offsets[2]=FLAG_OFFSET(exec_error); ent.offsets[3]=0;//new value mask - clean error SCRIPT_MSG("IfErrors ?%s:%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_IFABORT: ent.which=EW_IFFLAG; if (process_jump(line,1,&ent.offsets[0]) || process_jump(line,2,&ent.offsets[1])) PRINTHELP() ent.offsets[2]=FLAG_OFFSET(abort); ent.offsets[3]=~0;//new value mask - keep flag SCRIPT_MSG("IfAbort ?%s:%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_CLEARERRORS: ent.which=EW_SETFLAG; ent.offsets[0]=FLAG_OFFSET(exec_error); ent.offsets[1]=add_intstring(0); SCRIPT_MSG("ClearErrors\n"); return add_entry(&ent); case TOK_SETERRORS: ent.which=EW_SETFLAG; ent.offsets[0]=FLAG_OFFSET(exec_error); ent.offsets[1]=add_intstring(1); SCRIPT_MSG("SetErrors\n"); return add_entry(&ent); case TOK_SETERRORLEVEL: ent.which=EW_SETFLAG; ent.offsets[0]=FLAG_OFFSET(errlvl); ent.offsets[1]=add_string(line.gettoken_str(1)); SCRIPT_MSG("SetErrorLevel: %s\n",line.gettoken_str(1)); return add_entry(&ent); case TOK_GETERRORLEVEL: ent.which=EW_GETFLAG; ent.offsets[0]=GetUserVarIndex(line, 1); ent.offsets[1]=FLAG_OFFSET(errlvl); if (line.gettoken_str(1)[0] && ent.offsets[0]<0) PRINTHELP() SCRIPT_MSG("GetErrorLevel: %s\n",line.gettoken_str(1)); return add_entry(&ent); #ifdef NSIS_SUPPORT_STROPTS case TOK_STRLEN: ent.which=EW_STRLEN; ent.offsets[0]=GetUserVarIndex(line, 1); ent.offsets[1]=add_string(line.gettoken_str(2)); if (ent.offsets[0] < 0) PRINTHELP() SCRIPT_MSG("StrLen %s \"%s\"\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_STRCPY: ent.which=EW_ASSIGNVAR; ent.offsets[0]=GetUserVarIndex(line, 1); ent.offsets[1]=add_string(line.gettoken_str(2)); ent.offsets[2]=add_string(line.gettoken_str(3)); ent.offsets[3]=add_string(line.gettoken_str(4)); if (ent.offsets[0] < 0) PRINTHELP() SCRIPT_MSG("StrCpy %s \"%s\" (%s) (%s)\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4)); return add_entry(&ent); case TOK_GETFUNCTIONADDR: ent.which=EW_GETFUNCTIONADDR; ent.offsets[0]=GetUserVarIndex(line, 1); ent.offsets[1]=ns_func.add(line.gettoken_str(2),0); ent.offsets[2]=0; ent.offsets[3]=0; if (ent.offsets[0] < 0) PRINTHELP() SCRIPT_MSG("GetFunctionAddress: %s %s",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_GETLABELADDR: ent.which=EW_GETLABELADDR; ent.offsets[0]=GetUserVarIndex(line, 1); if (ent.offsets[0] < 0 || process_jump(line,2,&ent.offsets[1])) PRINTHELP() ent.offsets[2]=0; ent.offsets[3]=0; SCRIPT_MSG("GetLabelAddress: %s %s",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_GETCURRENTADDR: ent.which=EW_ASSIGNVAR; ent.offsets[0]=GetUserVarIndex(line, 1); { char buf[32]; wsprintf(buf,"%d",1+(cur_header->blocks[NB_ENTRIES].num)); ent.offsets[1]=add_string(buf); } if (ent.offsets[0] < 0) PRINTHELP() ent.offsets[2]=0; ent.offsets[3]=0; SCRIPT_MSG("GetCurrentAddress: %s",line.gettoken_str(1)); return add_entry(&ent); case TOK_STRCMP: case TOK_STRCMPS: ent.which=EW_STRCMP; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=add_string(line.gettoken_str(2)); ent.offsets[4]=which_token == TOK_STRCMPS; if (process_jump(line,3,&ent.offsets[2]) || process_jump(line,4,&ent.offsets[3])) PRINTHELP() SCRIPT_MSG("%s \"%s\" \"%s\" equal=%s, nonequal=%s\n",line.gettoken_str(0),line.gettoken_str(1),line.gettoken_str(2), line.gettoken_str(3),line.gettoken_str(4)); return add_entry(&ent); case TOK_GETDLLVERSIONLOCAL: { DWORD low, high; if (!GetDLLVersion(line.gettoken_str(1),high,low)) { ERROR_MSG("GetDLLVersionLocal: error reading version info from \"%s\"\n",line.gettoken_str(1)); return PS_ERROR; } ent.which=EW_ASSIGNVAR; ent.offsets[0]=GetUserVarIndex(line, 2); ent.offsets[1]=add_intstring(high); ent.offsets[2]=0; ent.offsets[3]=0; if (ent.offsets[0]<0) PRINTHELP() add_entry(&ent); ent.offsets[0]=GetUserVarIndex(line, 3); ent.offsets[1]=add_intstring(low); ent.offsets[2]=0; ent.offsets[3]=0; if (ent.offsets[0]<0) PRINTHELP() SCRIPT_MSG("GetDLLVersionLocal: %s (%u,%u)->(%s,%s)\n", line.gettoken_str(1),high,low,line.gettoken_str(2),line.gettoken_str(3)); } return add_entry(&ent); case TOK_GETFILETIMELOCAL: { char buf[129]; DWORD high=0,low=0; #ifdef _WIN32 int flag=0; HANDLE hFile=CreateFile(line.gettoken_str(1),0,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if (hFile != INVALID_HANDLE_VALUE) { FILETIME ft; if (GetFileTime(hFile,NULL,NULL,&ft)) { high=ft.dwHighDateTime; low=ft.dwLowDateTime; flag=1; } CloseHandle(hFile); } if (!flag) { ERROR_MSG("GetFileTimeLocal: error reading date from \"%s\"\n",line.gettoken_str(1)); return PS_ERROR; } #else struct stat st; if (!stat(line.gettoken_str(1), &st)) { unsigned long long ll = (st.st_mtime * 10000000LL) + 116444736000000000LL; high = (DWORD) (ll >> 32); low = (DWORD) ll; } else { ERROR_MSG("GetFileTimeLocal: error reading date from \"%s\"\n",line.gettoken_str(1)); return PS_ERROR; } #endif ent.which=EW_ASSIGNVAR; ent.offsets[0]=GetUserVarIndex(line, 2); wsprintf(buf,"%u",high); ent.offsets[1]=add_string(buf); ent.offsets[2]=0; ent.offsets[3]=0; if (ent.offsets[0]<0) PRINTHELP() add_entry(&ent); ent.offsets[0]=GetUserVarIndex(line, 3); wsprintf(buf,"%u",low); ent.offsets[1]=add_string(buf); ent.offsets[2]=0; ent.offsets[3]=0; if (ent.offsets[0]<0) PRINTHELP() SCRIPT_MSG("GetFileTimeLocal: %s (%u,%u)->(%s,%s)\n", line.gettoken_str(1),high,low,line.gettoken_str(2),line.gettoken_str(3)); } return add_entry(&ent); #else//!NSIS_SUPPORT_STROPTS case TOK_GETDLLVERSIONLOCAL: case TOK_GETFILETIMELOCAL: case TOK_GETFUNCTIONADDR: case TOK_GETLABELADDR: case TOK_GETCURRENTADDR: case TOK_STRLEN: case TOK_STRCPY: case TOK_STRCMP: case TOK_STRCMPS: ERROR_MSG("Error: %s specified, NSIS_SUPPORT_STROPTS not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_STROPTS #ifdef NSIS_SUPPORT_INIFILES case TOK_DELETEINISEC: case TOK_DELETEINISTR: { char *vname=""; char *space=""; ent.which=EW_WRITEINI; ent.offsets[0]=add_string(line.gettoken_str(2)); // section name if (line.getnumtokens() > 3) { vname=line.gettoken_str(3); ent.offsets[1]=add_string(vname); // value name space=" "; } else ent.offsets[1]=0; ent.offsets[2]=0; ent.offsets[3]=add_string(line.gettoken_str(1)); SCRIPT_MSG("DeleteINI%s: [%s] %s%sin %s\n",*vname?"Str":"Sec", line.gettoken_str(2),vname,space,line.gettoken_str(1)); } return add_entry(&ent); case TOK_FLUSHINI: ent.which=EW_WRITEINI; ent.offsets[3]=add_string(line.gettoken_str(1)); SCRIPT_MSG("FlushINI: %s\n",line.gettoken_str(1)); return add_entry(&ent); case TOK_WRITEINISTR: ent.which=EW_WRITEINI; ent.offsets[0]=add_string(line.gettoken_str(2)); ent.offsets[1]=add_string(line.gettoken_str(3)); ent.offsets[2]=add_string(line.gettoken_str(4)); ent.offsets[3]=add_string(line.gettoken_str(1)); ent.offsets[4]=1; // write SCRIPT_MSG("WriteINIStr: [%s] %s=%s in %s\n", line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4),line.gettoken_str(1)); return add_entry(&ent); case TOK_READINISTR: ent.which=EW_READINISTR; ent.offsets[0]=GetUserVarIndex(line, 1); if (ent.offsets[0] < 0) PRINTHELP() ent.offsets[1]=add_string(line.gettoken_str(3)); ent.offsets[2]=add_string(line.gettoken_str(4)); ent.offsets[3]=add_string(line.gettoken_str(2)); SCRIPT_MSG("ReadINIStr %s [%s]:%s from %s\n",line.gettoken_str(1),line.gettoken_str(3),line.gettoken_str(4),line.gettoken_str(2)); return add_entry(&ent); #else//!NSIS_SUPPORT_INIFILES case TOK_DELETEINISEC: case TOK_DELETEINISTR: case TOK_FLUSHINI: case TOK_WRITEINISTR: case TOK_READINISTR: ERROR_MSG("Error: %s specified, NSIS_SUPPORT_INIFILES not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_INIFILES case TOK_DETAILPRINT: ent.which=EW_UPDATETEXT; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=0; SCRIPT_MSG("DetailPrint: \"%s\"\n",line.gettoken_str(1)); return add_entry(&ent); #ifdef NSIS_SUPPORT_FNUTIL case TOK_GETTEMPFILENAME: ent.which=EW_GETTEMPFILENAME; ent.offsets[0]=GetUserVarIndex(line, 1); if (line.getnumtokens() == 3) ent.offsets[1]=add_string(line.gettoken_str(2)); else ent.offsets[1]=add_string("$TEMP"); if (ent.offsets[0]<0) PRINTHELP() SCRIPT_MSG("GetTempFileName -> %s\n",line.gettoken_str(1)); return add_entry(&ent); case TOK_GETFULLPATHNAME: { int a=0; ent.which=EW_GETFULLPATHNAME; if (line.getnumtokens()==4 && !stricmp(line.gettoken_str(1),"/SHORT")) a++; else if (line.getnumtokens()==4 || *line.gettoken_str(1)=='/') PRINTHELP() ent.offsets[0]=add_string(line.gettoken_str(2+a)); ent.offsets[1]=GetUserVarIndex(line, 1+a); ent.offsets[2]=!a; if (ent.offsets[1]<0) PRINTHELP() SCRIPT_MSG("GetFullPathName: %s->%s (%d)\n", line.gettoken_str(2+a),line.gettoken_str(1+a),a?"sfn":"lfn"); } return add_entry(&ent); case TOK_SEARCHPATH: ent.which=EW_SEARCHPATH; ent.offsets[0]=GetUserVarIndex(line, 1); if (ent.offsets[0] < 0) PRINTHELP() ent.offsets[1]=add_string(line.gettoken_str(2)); SCRIPT_MSG("SearchPath %s %s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); #else case TOK_SEARCHPATH: case TOK_GETTEMPFILENAME: case TOK_GETFULLPATHNAME: ERROR_MSG("Error: %s specified, NSIS_SUPPORT_FNUTIL not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif case TOK_GETDLLVERSION: #ifdef NSIS_SUPPORT_GETDLLVERSION ent.which=EW_GETDLLVERSION; ent.offsets[0]=GetUserVarIndex(line, 2); ent.offsets[1]=GetUserVarIndex(line, 3); ent.offsets[2]=add_string(line.gettoken_str(1)); if (ent.offsets[0]<0 || ent.offsets[1]<0) PRINTHELP() SCRIPT_MSG("GetDLLVersion: %s->%s,%s\n", line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3)); return add_entry(&ent); #else//!NSIS_SUPPORT_GETDLLVERSION ERROR_MSG("Error: %s specified, NSIS_SUPPORT_GETDLLVERSION not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_GETDLLVERSION case TOK_GETFILETIME: #ifdef NSIS_SUPPORT_GETFILETIME ent.which=EW_GETFILETIME; ent.offsets[0]=GetUserVarIndex(line, 2); ent.offsets[1]=GetUserVarIndex(line, 3); ent.offsets[2]=add_string(line.gettoken_str(1)); if (ent.offsets[0]<0 || ent.offsets[1]<0) PRINTHELP() SCRIPT_MSG("GetFileTime: %s->%s,%s\n", line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3)); return add_entry(&ent); #else//!NSIS_SUPPORT_GETFILETIME ERROR_MSG("Error: %s specified, NSIS_SUPPORT_GETFILETIME not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_GETFILETIME #ifdef NSIS_SUPPORT_INTOPTS case TOK_INTOP: ent.which=EW_INTOP; ent.offsets[0]=GetUserVarIndex(line, 1); ent.offsets[3]=line.gettoken_enum(3,"+\0-\0*\0/\0|\0&\0^\0!\0||\0&&\0%\0<<\0>>\0~\0"); if (ent.offsets[0] < 0 || ent.offsets[3] < 0 || ((ent.offsets[3] == 7 || ent.offsets[3] == 13) && line.getnumtokens() > 4)) PRINTHELP() ent.offsets[1]=add_string(line.gettoken_str(2)); if (ent.offsets[3] != 7 && ent.offsets[3] != 13) ent.offsets[2]=add_string(line.gettoken_str(4)); if (ent.offsets[3] == 13) { ent.offsets[3]=6; ent.offsets[2]=add_string("0xFFFFFFFF"); } SCRIPT_MSG("IntOp: %s=%s%s%s\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4)); return add_entry(&ent); case TOK_INTFMT: ent.which=EW_INTFMT; ent.offsets[0]=GetUserVarIndex(line, 1); if (ent.offsets[0]<0) PRINTHELP() ent.offsets[1]=add_string(line.gettoken_str(2)); ent.offsets[2]=add_string(line.gettoken_str(3)); SCRIPT_MSG("IntFmt: %s->%s (fmt:%s)\n",line.gettoken_str(3),line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_INTCMP: case TOK_INTCMPU: ent.which=EW_INTCMP; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=add_string(line.gettoken_str(2)); ent.offsets[5]=which_token == TOK_INTCMPU; if (process_jump(line,3,&ent.offsets[2]) || process_jump(line,4,&ent.offsets[3]) || process_jump(line,5,&ent.offsets[4])) PRINTHELP() SCRIPT_MSG("%s %s:%s equal=%s, < %s, > %s\n",line.gettoken_str(0), line.gettoken_str(1),line.gettoken_str(2), line.gettoken_str(3),line.gettoken_str(4),line.gettoken_str(5)); return add_entry(&ent); #else//!NSIS_SUPPORT_INTOPTS case TOK_INTOP: case TOK_INTCMP: case TOK_INTFMT: case TOK_INTCMPU: ERROR_MSG("Error: %s specified, NSIS_SUPPORT_INTOPTS not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_INTOPTS #ifdef NSIS_SUPPORT_REGISTRYFUNCTIONS case TOK_READREGSTR: case TOK_READREGDWORD: { ent.which=EW_READREGSTR; ent.offsets[0]=GetUserVarIndex(line, 1); int k=line.gettoken_enum(2,rootkeys[0]); if (k == -1) k=line.gettoken_enum(2,rootkeys[1]); if (ent.offsets[0] == -1 || k == -1) PRINTHELP() ent.offsets[1]=(int)rootkey_tab[k]; ent.offsets[2]=add_string(line.gettoken_str(3)); ent.offsets[3]=add_string(line.gettoken_str(4)); if (which_token == TOK_READREGDWORD) ent.offsets[4]=1; else ent.offsets[4]=0; if (line.gettoken_str(3)[0] == '\\') warning_fl("%s: registry path name begins with \'\\\', may cause problems",line.gettoken_str(0)); SCRIPT_MSG("%s %s %s\\%s\\%s\n",line.gettoken_str(0), line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4)); } return add_entry(&ent); case TOK_DELETEREGVALUE: case TOK_DELETEREGKEY: { int a=1; if (which_token==TOK_DELETEREGKEY) { ent.offsets[4]=1; char *s=line.gettoken_str(a); if (s[0] == '/') { if (stricmp(s,"/ifempty")) PRINTHELP() a++; ent.offsets[4]=3; } if (line.gettoken_str(a+2)[0]) PRINTHELP() } int k=line.gettoken_enum(a,rootkeys[0]); if (k == -1) k=line.gettoken_enum(a,rootkeys[1]); if (k == -1) PRINTHELP() ent.which=EW_DELREG; ent.offsets[1]=(int)rootkey_tab[k]; ent.offsets[2]=add_string(line.gettoken_str(a+1)); ent.offsets[3]=(which_token==TOK_DELETEREGKEY)?0:add_string(line.gettoken_str(a+2)); if (line.gettoken_str(a+1)[0] == '\\') warning_fl("%s: registry path name begins with \'\\\', may cause problems",line.gettoken_str(0)); if (which_token==TOK_DELETEREGKEY) SCRIPT_MSG("DeleteRegKey: %s\\%s\n",line.gettoken_str(a),line.gettoken_str(a+1)); else SCRIPT_MSG("DeleteRegValue: %s\\%s\\%s\n",line.gettoken_str(a),line.gettoken_str(a+1),line.gettoken_str(a+2)); } return add_entry(&ent); case TOK_WRITEREGSTR: case TOK_WRITEREGEXPANDSTR: case TOK_WRITEREGBIN: case TOK_WRITEREGDWORD: { int k=line.gettoken_enum(1,rootkeys[0]); if (k == -1) k=line.gettoken_enum(1,rootkeys[1]); if (k == -1) PRINTHELP() ent.which=EW_WRITEREG; ent.offsets[0]=(int)rootkey_tab[k]; ent.offsets[1]=add_string(line.gettoken_str(2)); if (line.gettoken_str(2)[0] == '\\') warning_fl("%s: registry path name begins with \'\\\', may cause problems",line.gettoken_str(0)); ent.offsets[2]=add_string(line.gettoken_str(3)); if (which_token == TOK_WRITEREGSTR || which_token == TOK_WRITEREGEXPANDSTR) { SCRIPT_MSG("%s: %s\\%s\\%s=%s\n", line.gettoken_str(0),line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4)); ent.offsets[3]=add_string(line.gettoken_str(4)); ent.offsets[4]=ent.offsets[5]=REG_SZ; if (which_token == TOK_WRITEREGEXPANDSTR) { ent.offsets[5]=REG_EXPAND_SZ; } } if (which_token == TOK_WRITEREGBIN) { char data[3*NSIS_MAX_STRLEN]; char *p=line.gettoken_str(4); int data_len=0; while (*p) { int c; int a,b; a=*p; if (a >= '0' && a <= '9') a-='0'; else if (a >= 'a' && a <= 'f') a-='a'-10; else if (a >= 'A' && a <= 'F') a-='A'-10; else break; b=*++p; if (b >= '0' && b <= '9') b-='0'; else if (b >= 'a' && b <= 'f') b-='a'-10; else if (b >= 'A' && b <= 'F') b-='A'-10; else break; p++; c=(a<<4)|b; if (data_len >= 3*NSIS_MAX_STRLEN) { ERROR_MSG("WriteRegBin: %d bytes of data exceeded\n",3*NSIS_MAX_STRLEN); return PS_ERROR; } data[data_len++]=c; } if (*p) PRINTHELP() SCRIPT_MSG("WriteRegBin: %s\\%s\\%s=%s\n", line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4)); ent.offsets[3]=add_db_data(data,data_len); if (ent.offsets[3] < 0) return PS_ERROR; ent.offsets[4]=ent.offsets[5]=REG_BINARY; } if (which_token == TOK_WRITEREGDWORD) { ent.offsets[3]=add_string(line.gettoken_str(4)); ent.offsets[4]=ent.offsets[5]=REG_DWORD; SCRIPT_MSG("WriteRegDWORD: %s\\%s\\%s=%s\n", line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4)); } } return add_entry(&ent); case TOK_ENUMREGKEY: case TOK_ENUMREGVAL: { ent.which=EW_REGENUM; ent.offsets[0]=GetUserVarIndex(line, 1); int k=line.gettoken_enum(2,rootkeys[0]); if (k == -1) k=line.gettoken_enum(2,rootkeys[1]); if (ent.offsets[0] == -1 || k == -1) PRINTHELP() ent.offsets[1]=(int)rootkey_tab[k]; ent.offsets[2]=add_string(line.gettoken_str(3)); ent.offsets[3]=add_string(line.gettoken_str(4)); ent.offsets[4]=which_token == TOK_ENUMREGKEY; if (line.gettoken_str(3)[0] == '\\') warning_fl("%s: registry path name begins with \'\\\', may cause problems",line.gettoken_str(0)); SCRIPT_MSG("%s %s %s\\%s\\%s\n",which_token == TOK_ENUMREGKEY ? "EnumRegKey" : "EnumRegValue", line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4)); } return add_entry(&ent); #else//!NSIS_SUPPORT_REGISTRYFUNCTIONS case TOK_READREGSTR: case TOK_READREGDWORD: case TOK_DELETEREGVALUE: case TOK_DELETEREGKEY: case TOK_WRITEREGSTR: case TOK_WRITEREGEXPANDSTR: case TOK_WRITEREGBIN: case TOK_WRITEREGDWORD: case TOK_ENUMREGKEY: case TOK_ENUMREGVAL: ERROR_MSG("Error: %s specified, NSIS_SUPPORT_REGISTRYFUNCTIONS not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_REGISTRYFUNCTIONS #ifdef NSIS_SUPPORT_STACK case TOK_EXCH: { int swapitem=1; int save=GetUserVarIndex(line, 1); ent.which=EW_PUSHPOP; if (line.gettoken_str(1)[0] && save<0) { int s=0; swapitem=line.gettoken_int(1,&s); if (!s || swapitem <= 0) PRINTHELP() } if (save>=0) { SCRIPT_MSG("Exch(%s,0)\n",line.gettoken_str(1)); ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=0; ent.offsets[2]=0; add_entry(&ent); } else SCRIPT_MSG("Exch(st(%d),0)\n",swapitem); ent.offsets[0]=0; ent.offsets[1]=0; ent.offsets[2]=swapitem; if (save>=0) { add_entry(&ent); ent.offsets[0]=save; ent.offsets[1]=1; ent.offsets[2]=0; } DefineInnerLangString(NLF_INST_CORRUPTED); } return add_entry(&ent); case TOK_PUSH: ent.which=EW_PUSHPOP; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=0; SCRIPT_MSG("Push: %s\n",line.gettoken_str(1)); return add_entry(&ent); case TOK_POP: ent.which=EW_PUSHPOP; ent.offsets[0]=GetUserVarIndex(line, 1); ent.offsets[1]=1; if (ent.offsets[0] < 0) PRINTHELP() SCRIPT_MSG("Pop: %s\n",line.gettoken_str(1)); return add_entry(&ent); #else//!NSIS_SUPPORT_STACK case TOK_POP: case TOK_PUSH: case TOK_EXCH: ERROR_MSG("Error: %s specified, NSIS_SUPPORT_STACK not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_STACK #ifdef NSIS_SUPPORT_ENVIRONMENT case TOK_READENVSTR: ent.which=EW_READENVSTR; ent.offsets[0]=GetUserVarIndex(line, 1); { char str[NSIS_MAX_STRLEN]; strcpy(str, "%"); strcat(str, line.gettoken_str(2)); strcat(str, "%"); ent.offsets[1]=add_string(str); if (ent.offsets[0] < 0 || strlen(line.gettoken_str(2))<1) PRINTHELP() } ent.offsets[2]=1; SCRIPT_MSG("ReadEnvStr: %s->%s\n",line.gettoken_str(2),line.gettoken_str(1)); return add_entry(&ent); case TOK_EXPANDENVSTRS: ent.which=EW_READENVSTR; ent.offsets[0]=GetUserVarIndex(line, 1); ent.offsets[1]=add_string(line.gettoken_str(2)); ent.offsets[2]=0; if (ent.offsets[0] < 0) PRINTHELP() SCRIPT_MSG("ExpandEnvStrings: %s->%s\n",line.gettoken_str(2),line.gettoken_str(1)); return add_entry(&ent); #else//!NSIS_SUPPORT_ENVIRONMENT case TOK_EXPANDENVSTRS: case TOK_READENVSTR: ERROR_MSG("Error: %s specified, NSIS_SUPPORT_ENVIRONMENT not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_ENVIRONMENT #ifdef NSIS_SUPPORT_FINDFIRST case TOK_FINDFIRST: ent.which=EW_FINDFIRST; ent.offsets[0]=GetUserVarIndex(line, 2); // out ent.offsets[1]=GetUserVarIndex(line, 1); // handleout ent.offsets[2]=add_string(line.gettoken_str(3)); // filespec if (ent.offsets[0] < 0 || ent.offsets[1] < 0) PRINTHELP() SCRIPT_MSG("FindFirst: spec=\"%s\" handle=%s output=%s\n",line.gettoken_str(3),line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_FINDNEXT: ent.which=EW_FINDNEXT; ent.offsets[0]=GetUserVarIndex(line, 2); ent.offsets[1]=GetUserVarIndex(line, 1); if (ent.offsets[0] < 0 || ent.offsets[1] < 0) PRINTHELP() SCRIPT_MSG("FindNext: handle=%s output=%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_FINDCLOSE: ent.which=EW_FINDCLOSE; ent.offsets[0]=GetUserVarIndex(line, 1); if (ent.offsets[0] < 0) PRINTHELP() SCRIPT_MSG("FindClose: %s\n",line.gettoken_str(1)); return add_entry(&ent); #else//!NSIS_SUPPORT_FINDFIRST case TOK_FINDCLOSE: case TOK_FINDNEXT: case TOK_FINDFIRST: ERROR_MSG("Error: %s specified, NSIS_SUPPORT_FINDFIRST not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_FINDFIRST #ifdef NSIS_SUPPORT_FILEFUNCTIONS case TOK_FILEOPEN: { ent.which=EW_FOPEN; ent.offsets[0]=GetUserVarIndex(line, 1); // file handle ent.offsets[3]=add_string(line.gettoken_str(2)); ent.offsets[1]=0; //openmode if (!stricmp(line.gettoken_str(3),"r")) { ent.offsets[1]=GENERIC_READ; ent.offsets[2]=OPEN_EXISTING; } else if (!stricmp(line.gettoken_str(3),"w")) { ent.offsets[1]=GENERIC_WRITE; ent.offsets[2]=CREATE_ALWAYS; } else if (!stricmp(line.gettoken_str(3),"a")) { ent.offsets[1]=GENERIC_WRITE|GENERIC_READ; ent.offsets[2]=OPEN_ALWAYS; } if (ent.offsets[0] < 0 || !ent.offsets[1]) PRINTHELP() } SCRIPT_MSG("FileOpen: %s as %s -> %s\n",line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(1)); return add_entry(&ent); case TOK_FILECLOSE: ent.which=EW_FCLOSE; ent.offsets[0]=GetUserVarIndex(line, 1); // file handle if (ent.offsets[0] < 0) PRINTHELP() SCRIPT_MSG("FileClose: %s\n",line.gettoken_str(1)); return add_entry(&ent); case TOK_FILEREAD: ent.which=EW_FGETS; ent.offsets[0]=GetUserVarIndex(line, 1); // file handle ent.offsets[1]=GetUserVarIndex(line, 2); // output string if (line.gettoken_str(3)[0]) ent.offsets[2]=add_string(line.gettoken_str(3)); else ent.offsets[2]=add_intstring(NSIS_MAX_STRLEN-1); if (ent.offsets[0]<0 || ent.offsets[1]<0) PRINTHELP() SCRIPT_MSG("FileRead: %s->%s (max:%s)\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3)); return add_entry(&ent); case TOK_FILEWRITE: ent.which=EW_FPUTS; ent.offsets[0]=GetUserVarIndex(line, 1); // file handle ent.offsets[1]=add_string(line.gettoken_str(2)); if (ent.offsets[0]<0) PRINTHELP() SCRIPT_MSG("FileWrite: %s->%s\n",line.gettoken_str(2),line.gettoken_str(1)); return add_entry(&ent); case TOK_FILEREADBYTE: ent.which=EW_FGETS; ent.offsets[0]=GetUserVarIndex(line, 1); // file handle ent.offsets[1]=GetUserVarIndex(line, 2); // output string ent.offsets[2]=add_string("1"); ent.offsets[3]=1; if (ent.offsets[0]<0 || ent.offsets[1]<0) PRINTHELP() SCRIPT_MSG("FileReadByte: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_FILEWRITEBYTE: ent.which=EW_FPUTS; ent.offsets[0]=GetUserVarIndex(line, 1); // file handle ent.offsets[1]=add_string(line.gettoken_str(2)); ent.offsets[2]=1; if (ent.offsets[0]<0) PRINTHELP() SCRIPT_MSG("FileWriteByte: %s->%s\n",line.gettoken_str(2),line.gettoken_str(1)); return add_entry(&ent); case TOK_FILESEEK: { char *modestr; int tab[3]={FILE_BEGIN,FILE_CURRENT,FILE_END}; int mode=line.gettoken_enum(3,"SET\0CUR\0END\0"); ent.which=EW_FSEEK; ent.offsets[0]=GetUserVarIndex(line, 1); ent.offsets[1]=GetUserVarIndex(line, 4); ent.offsets[2]=add_string(line.gettoken_str(2)); if (mode<0 && !line.gettoken_str(3)[0]) { mode=0; modestr="SET"; } else modestr=line.gettoken_str(3); if (mode<0 || ent.offsets[0] < 0 || (ent.offsets[1]<0 && line.gettoken_str(4)[0])) PRINTHELP() ent.offsets[3]=tab[mode]; SCRIPT_MSG("FileSeek: fp=%s, ofs=%s, mode=%s, output=%s\n", line.gettoken_str(1), line.gettoken_str(2), modestr, line.gettoken_str(4)); } return add_entry(&ent); #else//!NSIS_SUPPORT_FILEFUNCTIONS case TOK_FILEOPEN: case TOK_FILECLOSE: case TOK_FILESEEK: case TOK_FILEREAD: case TOK_FILEWRITE: case TOK_FILEREADBYTE: case TOK_FILEWRITEBYTE: ERROR_MSG("Error: %s specified, NSIS_SUPPORT_FILEFUNCTIONS not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_FILEFUNCTIONS #ifdef NSIS_SUPPORT_REBOOT case TOK_REBOOT: { int ret = add_entry_direct(EW_REBOOT, 0xbadf00d); if (ret != PS_OK) return ret; ret = add_entry_direct(EW_QUIT); if (ret != PS_OK) return ret; SCRIPT_MSG("Reboot! (WOW)\n"); DefineInnerLangString(NLF_INST_CORRUPTED); } return PS_OK; case TOK_IFREBOOTFLAG: ent.which=EW_IFFLAG; if (process_jump(line,1,&ent.offsets[0]) || process_jump(line,2,&ent.offsets[1])) PRINTHELP() ent.offsets[2]=FLAG_OFFSET(exec_reboot); ent.offsets[3]=~0;//new value mask - keep flag SCRIPT_MSG("IfRebootFlag ?%s:%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_SETREBOOTFLAG: { ent.which=EW_SETFLAG; ent.offsets[0]=FLAG_OFFSET(exec_reboot); int k=line.gettoken_enum(1,"false\0true\0"); if (k < 0) PRINTHELP() ent.offsets[1]=add_intstring(k); } return add_entry(&ent); #else//!NSIS_SUPPORT_REBOOT case TOK_REBOOT: case TOK_IFREBOOTFLAG: case TOK_SETREBOOTFLAG: ERROR_MSG("Error: %s specified, NSIS_SUPPORT_REBOOT not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_REBOOT #ifdef NSIS_CONFIG_LOG case TOK_LOGSET: ent.which=EW_LOG; ent.offsets[0]=1; ent.offsets[1]=line.gettoken_enum(1,"off\0on\0"); if (ent.offsets[1]<0) PRINTHELP() SCRIPT_MSG("LogSet: %s\n",line.gettoken_str(1)); return add_entry(&ent); case TOK_LOGTEXT: ent.which=EW_LOG; ent.offsets[0]=0; ent.offsets[1]=add_string(line.gettoken_str(1)); SCRIPT_MSG("LogText \"%s\"\n",line.gettoken_str(1)); return add_entry(&ent); #else//!NSIS_CONFIG_LOG case TOK_LOGSET: case TOK_LOGTEXT: ERROR_MSG("Error: %s specified, NSIS_CONFIG_LOG not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_CONFIG_LOG #ifdef NSIS_CONFIG_COMPONENTPAGE case TOK_SECTIONSETTEXT: ent.which=EW_SECTIONSET; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[2]=SECTION_FIELD_SET(name_ptr); ent.offsets[4]=add_string(line.gettoken_str(2)); SCRIPT_MSG("SectionSetText: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_SECTIONGETTEXT: ent.which=EW_SECTIONSET; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=GetUserVarIndex(line, 2); ent.offsets[2]=SECTION_FIELD_GET(name_ptr); if (line.gettoken_str(2)[0] && ent.offsets[1]<0) PRINTHELP() SCRIPT_MSG("SectionGetText: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_SECTIONSETFLAGS: ent.which=EW_SECTIONSET; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=add_string(line.gettoken_str(2)); ent.offsets[2]=SECTION_FIELD_SET(flags); ent.offsets[3]=1; SCRIPT_MSG("SectionSetFlags: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_SECTIONGETFLAGS: ent.which=EW_SECTIONSET; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=GetUserVarIndex(line, 2); ent.offsets[2]=SECTION_FIELD_GET(flags); if (line.gettoken_str(2)[0] && ent.offsets[1]<0) PRINTHELP() SCRIPT_MSG("SectionGetFlags: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_INSTTYPESETTEXT: ent.which=EW_INSTTYPESET; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=add_string(line.gettoken_str(2)); ent.offsets[2]=1; SCRIPT_MSG("InstTypeSetText: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_INSTTYPEGETTEXT: ent.which=EW_INSTTYPESET; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=GetUserVarIndex(line, 2); ent.offsets[2]=0; if (line.gettoken_str(1)[0] && ent.offsets[1]<0) PRINTHELP() SCRIPT_MSG("InstTypeGetText: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_SECTIONSETINSTTYPES: ent.which=EW_SECTIONSET; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=add_string(line.gettoken_str(2)); ent.offsets[2]=SECTION_FIELD_SET(install_types); SCRIPT_MSG("SectionSetInstTypes: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_SECTIONGETINSTTYPES: ent.which=EW_SECTIONSET; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=GetUserVarIndex(line, 2); ent.offsets[2]=SECTION_FIELD_GET(install_types); if (line.gettoken_str(2)[0] && ent.offsets[1]<0) PRINTHELP() SCRIPT_MSG("SectionGetInstTypes: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_SECTIONSETSIZE: ent.which=EW_SECTIONSET; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=add_string(line.gettoken_str(2)); ent.offsets[2]=SECTION_FIELD_SET(size_kb); SCRIPT_MSG("SectionSetSize: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_SECTIONGETSIZE: ent.which=EW_SECTIONSET; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=GetUserVarIndex(line, 2); ent.offsets[2]=SECTION_FIELD_GET(size_kb); if (line.gettoken_str(2)[0] && ent.offsets[1]<0) PRINTHELP() SCRIPT_MSG("SectionGetSize: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2)); return add_entry(&ent); case TOK_SETCURINSTTYPE: ent.which=EW_INSTTYPESET; ent.offsets[0]=add_string(line.gettoken_str(1)); ent.offsets[1]=0; ent.offsets[2]=1; ent.offsets[3]=1; SCRIPT_MSG("SetCurInstType: %s\n",line.gettoken_str(1)); return add_entry(&ent); case TOK_GETCURINSTTYPE: ent.which=EW_INSTTYPESET; ent.offsets[0]=0; ent.offsets[1]=GetUserVarIndex(line,1); ent.offsets[2]=0; ent.offsets[3]=1; if (line.gettoken_str(1)[0] && ent.offsets[1]<0) PRINTHELP() SCRIPT_MSG("GetCurInstType: %s\n",line.gettoken_str(1)); return add_entry(&ent); #else//!NSIS_CONFIG_COMPONENTPAGE case TOK_SECTIONSETTEXT: case TOK_SECTIONGETTEXT: case TOK_SECTIONSETFLAGS: case TOK_SECTIONGETFLAGS: case TOK_SECTIONSETSIZE: case TOK_SECTIONGETSIZE: case TOK_SECTIONSETINSTTYPES: case TOK_SECTIONGETINSTTYPES: case TOK_SETCURINSTTYPE: case TOK_GETCURINSTTYPE: ERROR_MSG("Error: %s specified, NSIS_CONFIG_COMPONENTPAGE not defined.\n", line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_CONFIG_COMPONENTPAGE #ifdef NSIS_CONFIG_ENHANCEDUI_SUPPORT case TOK_SETBRANDINGIMAGE: { SCRIPT_MSG("SetBrandingImage: "); if (!branding_image_found) { ERROR_MSG("\nError: no branding image found in chosen UI!\n"); return PS_ERROR; } ent.which=EW_SETBRANDINGIMAGE; for (int i = 1; i < line.getnumtokens(); i++) if (!strnicmp(line.gettoken_str(i),"/IMGID=",7)) { ent.offsets[1]=atoi(line.gettoken_str(i)+7); SCRIPT_MSG("/IMGID=%d ",ent.offsets[1]); } else if (!stricmp(line.gettoken_str(i),"/RESIZETOFIT")) { ent.offsets[2]=1; // must be 1 or 0 SCRIPT_MSG("/RESIZETOFIT "); } else if (!ent.offsets[0]) { ent.offsets[0]=add_string(line.gettoken_str(i)); SCRIPT_MSG("\"%s\" ", line.gettoken_str(i)); } else { SCRIPT_MSG("\n"); PRINTHELP(); } if (!ent.offsets[1]) ent.offsets[1]=branding_image_id; SCRIPT_MSG("\n"); } return add_entry(&ent); #else//NSIS_CONFIG_ENHANCEDUI_SUPPORT case TOK_SETBRANDINGIMAGE: ERROR_MSG("Error: %s specified, NSIS_CONFIG_ENHANCEDUI_SUPPORT not defined.\n",line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_CREATEFONT // Added by ramon 3 jun 2003 case TOK_DEFVAR: { int a=1; if (!strcmpi(line.gettoken_str(1),"/GLOBAL")) { a++; } else if (line.getnumtokens() == 3) { PRINTHELP(); } if (build_cursection) { if (a==1) { ERROR_MSG("Var: currently, only global variables can be defined.\n"); PRINTHELP(); } } SCRIPT_MSG("Var: \"%s\"\n",line.gettoken_str(a)); int res = DeclaredUserVar(line.gettoken_str(a)); if (res != PS_OK) return res; } return PS_OK; // Added by ramon 6 jun 2003 #ifdef NSIS_SUPPORT_VERSION_INFO case TOK_VI_ADDKEY: { LANGID LangID=0; int a = 1; if (!strnicmp(line.gettoken_str(a),"/LANG=",6)) LangID=atoi(line.gettoken_str(a++)+6); if (line.getnumtokens()!=a+2) PRINTHELP(); char *pKey = line.gettoken_str(a); char *pValue = line.gettoken_str(a+1); if ( !(*pKey) ) { ERROR_MSG("Error: empty name for version info key!\n"); return PS_ERROR; } else { SCRIPT_MSG("%s: \"%s\" \"%s\"\n", line.gettoken_str(0), line.gettoken_str(a), line.gettoken_str(a+1)); LANGID lReaded = LangID; if ( a > 1 && lReaded == 0 ) warning_fl("%s: %s language not loaded, using default \"1033-English\"", line.gettoken_str(0), line.gettoken_str(1)); unsigned int codepage; char *lang_name = GetLangNameAndCP(LangID, &codepage); if ( rVersionInfo.SetKeyValue(LangID, codepage, pKey, pValue) ) { ERROR_MSG("%s: \"%s\" \"%04d-%s\" already defined!\n",line.gettoken_str(0), line.gettoken_str(2), LangID, lang_name); return PS_ERROR; } return PS_OK; } } case TOK_VI_SETPRODUCTVERSION: if ( version_product_v[0] ) { ERROR_MSG("Error: %s already defined!\n", line.gettoken_str(0)); return PS_ERROR; } strcpy(version_product_v, line.gettoken_str(1)); return PS_OK; #else case TOK_VI_ADDKEY: case TOK_VI_SETPRODUCTVERSION: ERROR_MSG("Error: %s specified, NSIS_SUPPORT_VERSION_INFO not defined.\n",line.gettoken_str(0)); return PS_ERROR; #endif // end of instructions /////////////////////////////////////////////////////////////////////////////// // Added by Ximon Eighteen 5th August 2002 #ifdef NSIS_CONFIG_PLUGIN_SUPPORT case TOK_PLUGINDIR: { if (line.getnumtokens() == 2) { SCRIPT_MSG("PluginDir: \"%s\"\n",line.gettoken_str(1)); #ifdef _WIN32 m_plugins.FindCommands(line.gettoken_str(1), display_info?true:false); #else char *converted_path = my_convert(line.gettoken_str(1)); m_plugins.FindCommands(converted_path, display_info?true:false); my_convert_free(converted_path); #endif return PS_OK; } } return PS_ERROR; case TOK__PLUGINCOMMAND: { int ret; const string command = m_plugins.NormalizedCommand(line.gettoken_str(0)); const string dllPath = m_plugins.GetPluginPath(command); int data_handle = m_plugins.GetPluginHandle(uninstall_mode?true:false, command); if (uninstall_mode) uninst_plugin_used = true; else plugin_used = true; // Initialize $PLUGINSDIR ent.which=EW_CALL; ent.offsets[0]=ns_func.add(uninstall_mode?"un.Initialize_____Plugins":"Initialize_____Plugins",0); ret=add_entry(&ent); if (ret != PS_OK) { return ret; } // DLL name on the user machine char tempDLL[NSIS_MAX_STRLEN]; string dllName = get_file_name(dllPath); wsprintf(tempDLL, "$PLUGINSDIR\\%s", dllName.c_str()); // Add the DLL to the installer if (data_handle == -1) { int files_added; int old_build_allowskipfiles=build_allowskipfiles; build_allowskipfiles=1; // on int old_build_overwrite=build_overwrite; build_overwrite=1; // off int old_build_datesave=build_datesave; build_datesave=0; // off ret=do_add_file(dllPath.c_str(),0,0,&files_added,tempDLL,2,&data_handle); // 2 means no size add if (ret != PS_OK) { return ret; } m_plugins.SetDllDataHandle(uninstall_mode?true:false, line.gettoken_str(0), data_handle); build_overwrite=old_build_overwrite; build_datesave=old_build_datesave; // Added by ramon 23 May 2003 build_allowskipfiles=old_build_allowskipfiles; } else { ent.which=EW_EXTRACTFILE; DefineInnerLangString(NLF_SKIPPED); DefineInnerLangString(NLF_ERR_DECOMPRESSING); DefineInnerLangString(NLF_ERR_WRITING); DefineInnerLangString(NLF_EXTRACT); DefineInnerLangString(NLF_CANT_WRITE); ent.offsets[0]=1; // overwrite off ent.offsets[0]|=(MB_RETRYCANCEL|MB_ICONSTOP|(IDCANCEL<<21))<<3; ent.offsets[1]=add_string(tempDLL); ent.offsets[2]=data_handle; ent.offsets[3]=0xffffffff; ent.offsets[4]=0xffffffff; ent.offsets[5]=DefineInnerLangString(NLF_FILE_ERROR); ret=add_entry(&ent); if (ret != PS_OK) { return ret; } } // SetDetailsPrint lastused ret=add_entry_direct(EW_SETFLAG, FLAG_OFFSET(status_update), 0, 1); if (ret != PS_OK) { return ret; } // Call the DLL string funcname = get_string_suffix(command, "::"); SCRIPT_MSG("Plugin Command: %s",funcname.c_str()); int i = 1; int nounload = 0; if (!strcmpi(line.gettoken_str(i), "/NOUNLOAD")) { i++; nounload++; } // First push dll args int parmst=i; // we push em in reverse order int nounloadmisused=0; for (; i < line.getnumtokens(); i++) { int w=parmst + (line.getnumtokens()-i - 1); ent.which=EW_PUSHPOP; ent.offsets[0]=add_string(line.gettoken_str(w)); if (!strcmpi(line.gettoken_str(w), "/NOUNLOAD")) nounloadmisused=1; ent.offsets[1]=0; ent.offsets[2]=0; ret=add_entry(&ent); if (ret != PS_OK) { return ret; } SCRIPT_MSG(" %s",line.gettoken_str(i)); } SCRIPT_MSG("\n"); if (nounloadmisused) warning_fl("/NOUNLOAD must come first before any plugin parameter. Unless the plugin you are trying to use has a parameter /NOUNLOAD, you are doing something wrong"); // next, call it ent.which=EW_REGISTERDLL; ent.offsets[0]=add_string(tempDLL);; ent.offsets[1]=add_string(funcname.c_str()); ent.offsets[2]=0; ent.offsets[3]=nounload|build_plugin_unload; ent.offsets[4]=1; ret=add_entry(&ent); if (ret != PS_OK) { return ret; } DefineInnerLangString(NLF_SYMBOL_NOT_FOUND); DefineInnerLangString(NLF_COULD_NOT_LOAD); DefineInnerLangString(NLF_NO_OLE); // not used anywhere - DefineInnerLangString(NLF_ERR_REG_DLL); return PS_OK; } case TOK_INITPLUGINSDIR: { int ret; SCRIPT_MSG("%s\n",line.gettoken_str(0)); if (uninstall_mode) uninst_plugin_used = true; else plugin_used = true; // Call [un.]Initialize_____Plugins ent.which=EW_CALL; ent.offsets[0]=ns_func.add(uninstall_mode?"un.Initialize_____Plugins":"Initialize_____Plugins",0); ret=add_entry(&ent); if (ret != PS_OK) return ret; // SetDetailsPrint lastused ret=add_entry_direct(EW_SETFLAG, FLAG_OFFSET(status_update), 0, 1); if (ret != PS_OK) return ret; } return PS_OK; #else case TOK_PLUGINDIR: case TOK__PLUGINCOMMAND: case TOK_INITPLUGINSDIR: { ERROR_MSG("Error: %s specified, NSIS_CONFIG_PLUGIN_SUPPORT not defined.\n",line.gettoken_str(0)); } return PS_ERROR; #endif// NSIS_CONFIG_PLUGIN_SUPPORT #ifdef NSIS_LOCKWINDOW_SUPPORT case TOK_LOCKWINDOW: SCRIPT_MSG("LockWindow: lock state=%d\n",line.gettoken_str(1)); ent.which=EW_LOCKWINDOW; ent.offsets[0]=line.gettoken_enum(1,"on\0off\0"); if (ent.offsets[0] == -1) PRINTHELP(); return add_entry(&ent); #else case TOK_LOCKWINDOW: { ERROR_MSG("Error: %s specified, NSIS_LOCKWINDOW_SUPPORT not defined.\n",line.gettoken_str(0)); } return PS_ERROR; #endif // NSIS_LOCKWINDOW_SUPPORT default: break; } ERROR_MSG("Error: doCommand: Invalid token \"%s\".\n",line.gettoken_str(0)); return PS_ERROR; } #ifdef NSIS_SUPPORT_FILE int CEXEBuild::do_add_file(const char *lgss, int attrib, int recurse, int *total_files, const char *name_override, int generatecode, int *data_handle, const set& excluded, const string& basedir, bool dir_created) { assert(!name_override || !recurse); string dir = get_dir_name(lgss); string spec; if (dir == lgss) { dir = "."; spec = lgss; } else { spec = string(lgss).substr(dir.length() + 1, string::npos); } if (spec == "") { spec = "*"; } if (basedir == "") { dir_created = true; if (recurse) { // save $OUTDIR into $_OUTDIR [StrCpy $_OUTDIR $OUTDIR] if (add_entry_direct(EW_ASSIGNVAR, m_UserVarNames.get("_OUTDIR"), add_string("$OUTDIR")) != PS_OK) { return PS_ERROR; } } } boost::scoped_ptr dr( new_dir_reader() ); dr->exclude(excluded); dr->read(dir); // add files in the current directory for (dir_reader::iterator files_itr = dr->files().begin(); files_itr != dr->files().end(); files_itr++) { if (!dir_reader::matches(*files_itr, spec)) continue; if (!dir_created && generatecode) { SCRIPT_MSG("%sFile: Descending to: \"%s\"\n", generatecode ? "" : "Reserve", dir.c_str()); if (do_add_file_create_dir(dir, basedir, attrib) != PS_OK) { return PS_ERROR; } dir_created = true; } if (add_file(dir, *files_itr, attrib, name_override, generatecode, data_handle) != PS_OK) { return PS_ERROR; } (*total_files)++; } if (!recurse) { return PS_OK; } // recurse into directories for (dir_reader::iterator dirs_itr = dr->dirs().begin(); dirs_itr != dr->dirs().end(); dirs_itr++) { string new_dir; bool created = false; if (basedir == "") { new_dir = *dirs_itr; } else { new_dir = basedir + '\\' + *dirs_itr; } string new_spec = dir + PLATFORM_PATH_SEPARATOR_STR + *dirs_itr + PLATFORM_PATH_SEPARATOR_STR; if (!dir_reader::matches(*dirs_itr, spec)) { new_spec += spec; } else if (generatecode) { // always create directories that match SCRIPT_MSG("%sFile: Descending to: \"%s\"\n", generatecode ? "" : "Reserve", new_spec.c_str()); if (do_add_file_create_dir(dir + '\\' + *dirs_itr, new_dir, attrib) != PS_OK) { return PS_ERROR; } created = true; } const char *new_spec_c = new_spec.c_str(); int res = do_add_file(new_spec_c, attrib, 1, total_files, NULL, generatecode, NULL, excluded, new_dir, created); if (res != PS_OK) { return PS_ERROR; } } if (basedir == "") { SCRIPT_MSG("%sFile: Returning to: \"%s\"\n", generatecode ? "" : "Reserve", dir.c_str()); // restore $OUTDIR from $_OUTDIR [SetOutPath $_OUTDIR] if (add_entry_direct(EW_CREATEDIR, add_string("$_OUTDIR"), 1) != PS_OK) { return PS_ERROR; } } return PS_OK; } int CEXEBuild::add_file(const string& dir, const string& file, int attrib, const char *name_override, int generatecode, int *data_handle) { string newfn_s = dir + PLATFORM_PATH_SEPARATOR_C + file; const char *newfn = newfn_s.c_str(); const char *filename = file.c_str(); MMapFile mmap; DWORD len; #ifdef _WIN32 HANDLE hFile = CreateFile( newfn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL ); if (hFile == INVALID_HANDLE_VALUE) { ERROR_MSG("%sFile: failed opening file \"%s\"\n",generatecode?"":"Reserve",newfn); return PS_ERROR; } // Will auto-CloseHandle hFile MANAGE_WITH(hFile, CloseHandle); len = GetFileSize(hFile, NULL); if (len && !mmap.setfile(hFile, len)) { ERROR_MSG("%sFile: failed creating mmap of \"%s\"\n",generatecode?"":"Reserve",newfn); return PS_ERROR; } #else struct stat s; if (stat(newfn, &s)) { ERROR_MSG("%sFile: failed stating file \"%s\"\n",generatecode?"":"Reserve",newfn); return PS_ERROR; } len = (DWORD) s.st_size; int fd = OPEN(newfn, O_RDONLY); if (fd == -1) { ERROR_MSG("%sFile: failed opening file \"%s\"\n",generatecode?"":"Reserve",newfn); return PS_ERROR; } // Will auto-close(2) fd MANAGE_WITH(fd, close); if (len && !mmap.setfile(fd, len)) { ERROR_MSG("%sFile: failed creating mmap of \"%s\"\n",generatecode?"":"Reserve",newfn); return PS_ERROR; } #endif if (generatecode&1) section_add_size_kb((len+1023)/1024); if (name_override) SCRIPT_MSG("%sFile: \"%s\"->\"%s\"",generatecode?"":"Reserve",filename,name_override); else SCRIPT_MSG("%sFile: \"%s\"",generatecode?"":"Reserve",filename); if (!build_compress_whole) if (build_compress) SCRIPT_MSG(" [compress]"); fflush(stdout); char buf[1024]; int last_build_datablock_used=getcurdbsize(); entry ent={0,}; if (generatecode) { ent.which=EW_EXTRACTFILE; DefineInnerLangString(NLF_SKIPPED); DefineInnerLangString(NLF_ERR_DECOMPRESSING); DefineInnerLangString(NLF_ERR_WRITING); DefineInnerLangString(NLF_EXTRACT); DefineInnerLangString(NLF_CANT_WRITE); ent.offsets[0]=build_overwrite; if (name_override) { ent.offsets[1]=add_string(name_override); } else { const char *i=filename; char *o=buf; while (*i) { const char c=*i++; *o++=c; if (c == '$') *o++='$'; } *o=0; ent.offsets[1]=add_string(buf); } } ent.offsets[2]=add_db_data(&mmap); mmap.clear(); if (ent.offsets[2] < 0) { return PS_ERROR; } if (data_handle) { *data_handle=ent.offsets[2]; } { DWORD s=getcurdbsize()-last_build_datablock_used; if (s) s-=4; if (s != len) SCRIPT_MSG(" %d/%d bytes\n",s,len); else SCRIPT_MSG(" %d bytes\n",len); } if (generatecode) { if (build_datesave || build_overwrite>=0x3 /*ifnewer or ifdiff*/) { #ifdef _WIN32 FILETIME ft; if (GetFileTime(hFile,NULL,NULL,&ft)) { // FAT write time has a resolution of 2 seconds PULONGLONG fti = (PULONGLONG) &ft; *fti -= *fti % 20000000; ent.offsets[3]=ft.dwLowDateTime; ent.offsets[4]=ft.dwHighDateTime; } #else struct stat st; if (!fstat(fd, &st)) { unsigned long long ll = (st.st_mtime * 10000000LL) + 116444736000000000LL; // FAT write time has a resolution of 2 seconds ll -= ll % 20000000; ent.offsets[3] = (int) ll; ent.offsets[4] = (int) (ll >> 32); } #endif else { ERROR_MSG("%sFile: failed getting file date from \"%s\"\n",generatecode?"":"Reserve",newfn); return PS_ERROR; } } else { ent.offsets[3]=0xffffffff; ent.offsets[4]=0xffffffff; } // overwrite flag can be 0, 1, 2 or 3. in all cases, 2 bits int mb = 0; if (build_allowskipfiles) { mb = MB_ABORTRETRYIGNORE | MB_ICONSTOP; // default for silent installers mb |= IDIGNORE << 21; } else { mb = MB_RETRYCANCEL | MB_ICONSTOP; // default for silent installers mb |= IDCANCEL << 21; } ent.offsets[0] |= mb << 3; ent.offsets[5] = DefineInnerLangString(build_allowskipfiles ? NLF_FILE_ERROR : NLF_FILE_ERROR_NOIGNORE); } if (generatecode) { int a=add_entry(&ent); if (a != PS_OK) { return a; } if (attrib) { #ifdef _WIN32 ent.which=EW_SETFILEATTRIBUTES; // $OUTDIR is the working directory ent.offsets[0]=add_string(name_override?name_override:buf); ent.offsets[1]=GetFileAttributes(newfn); ent.offsets[2]=0; ent.offsets[3]=0; ent.offsets[4]=0; ent.offsets[5]=0; if (ent.offsets[1] != INVALID_FILE_ATTRIBUTES) { a=add_entry(&ent); if (a != PS_OK) { return a; } } #endif } } return PS_OK; } int CEXEBuild::do_add_file_create_dir(const string& local_dir, const string& dir, int attrib) { string outdir_s = "$_OUTDIR\\" + dir; string::size_type pos = 1; pos = outdir_s.find('$', pos); while (pos != string::npos) { outdir_s = outdir_s.insert(pos, "$"); pos = outdir_s.find('$', pos + 2); } int outdir = add_string(outdir_s.c_str()); if (add_entry_direct(EW_CREATEDIR, outdir, 1) != PS_OK) { return PS_ERROR; } #ifdef _WIN32 if (attrib) { int ndc = add_string("."); DWORD attr = GetFileAttributes(local_dir.c_str()); if (attr != INVALID_FILE_ATTRIBUTES) { if (add_entry_direct(EW_SETFILEATTRIBUTES, ndc, attr) != PS_OK) { return PS_ERROR; } } } #endif return PS_OK; } #endif DefineList *CEXEBuild::searchParseString(const char *source_string, LineParser *line, int parmOffs, bool ignCase, bool noErrors) { const char *tok = line->gettoken_str(parmOffs++); if (tok && *tok) { int toklen = strlen(tok); while (*source_string && (ignCase?strnicmp(source_string,tok,toklen):strncmp(source_string,tok,toklen))) source_string++; if (!*source_string) { if (!noErrors) ERROR_MSG("!searchparse: starting string \"%s\" not found, aborted search!\n",tok); return NULL; } if (*source_string) source_string+=toklen; } DefineList *ret = NULL; while (parmOffs < line->getnumtokens()) { const char *defout = line->gettoken_str(parmOffs++); if (parmOffs < line->getnumtokens()) tok=line->gettoken_str(parmOffs++); else tok=NULL; int maxlen=-1; const char *src_start = source_string; if (tok && *tok) { int toklen = strlen(tok); while (*source_string && (ignCase?strnicmp(source_string,tok,toklen):strncmp(source_string,tok,toklen))) source_string++; maxlen = source_string - src_start; if (*source_string) source_string += toklen; else if (!noErrors) { ERROR_MSG("!searchparse: string \"%s\" not found, aborted search!\n",tok); delete ret; return NULL; } } if (defout && defout[0]) { if (!ret) ret = new DefineList; if (maxlen < 0) ret->add(defout,src_start); else { char *p=strdup(src_start); if (p) { p[maxlen]=0; ret->add(defout,p); free(p); } } } } return ret; }