home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 March / CMCD0304.ISO / Software / Freeware / Programare / nullsoft / nsis20.exe / Source / script.cpp < prev    next >
C/C++ Source or Header  |  2004-02-06  |  189KB  |  5,583 lines

  1. #include "Platform.h"
  2. #include <stdio.h>
  3. #include <shlobj.h>
  4. #define _RICHEDIT_VER 0x0200
  5. #include <RichEdit.h>
  6. #undef _RICHEDIT_VER
  7. #include "tokens.h"
  8. #include "build.h"
  9. #include "util.h"
  10. #include "exedata.h"
  11. #include "ResourceEditor.h"
  12. #include "DialogTemplate.h"
  13. #include "lang.h"
  14. #include "exehead/resource.h"
  15.  
  16. #define MAX_INCLUDEDEPTH 10
  17. #define MAX_LINELENGTH 4096
  18.  
  19. #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES
  20. // Added by Sunil Kamath 11 June 2003
  21. char *CEXEBuild::set_file_predefine(char *filename)
  22. {
  23.   char *oldfilename = definedlist.find("__FILE__");
  24.   if(oldfilename)
  25.   {
  26.     oldfilename = strdup(oldfilename);
  27.     definedlist.del("__FILE__");
  28.   }
  29.   char *p = strrchr(filename,'\\');
  30.   if(p) {
  31.     p++;
  32.   }
  33.   else {
  34.     p = curfilename;
  35.   }
  36.   definedlist.add("__FILE__",p);
  37.  
  38.   return oldfilename;
  39. }
  40.  
  41. void CEXEBuild::restore_file_predefine(char *oldfilename)
  42. {
  43.   definedlist.del("__FILE__");
  44.   if(oldfilename) {
  45.       definedlist.add("__FILE__",oldfilename);
  46.       free(oldfilename);
  47.   }
  48. }
  49.  
  50. char *CEXEBuild::set_timestamp_predefine(char *filename)
  51. {
  52.   char *oldtimestamp = definedlist.find("__TIMESTAMP__");
  53.   if(oldtimestamp) {
  54.     oldtimestamp = strdup(oldtimestamp);
  55.     definedlist.del("__TIMESTAMP__");
  56.   }
  57.  
  58.   char timestampbuf[256] = "";
  59.   char datebuf[128] = "";
  60.   char timebuf[128] = "";
  61.   WIN32_FIND_DATA fd;
  62.   FILETIME floctime;
  63.   SYSTEMTIME stime;
  64.  
  65.   HANDLE hSearch = FindFirstFile(filename, &fd);
  66.   if (hSearch != INVALID_HANDLE_VALUE)
  67.   {
  68.     FindClose(hSearch);
  69.  
  70.     FileTimeToLocalFileTime(&fd.ftLastWriteTime, &floctime);
  71.     FileTimeToSystemTime(&floctime, &stime);
  72.  
  73.     GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &stime, NULL, datebuf, sizeof(datebuf)); 
  74.     GetTimeFormat(LOCALE_USER_DEFAULT, 0, &stime, NULL, timebuf, sizeof(timebuf)); 
  75.     wsprintf(timestampbuf,"%s %s",datebuf,timebuf);
  76.  
  77.     definedlist.add("__TIMESTAMP__",timestampbuf);
  78.   }
  79.  
  80.   return oldtimestamp;
  81. }
  82.  
  83. void CEXEBuild::restore_timestamp_predefine(char *oldtimestamp)
  84. {
  85.   definedlist.del("__TIMESTAMP__");
  86.   if(oldtimestamp) {
  87.       definedlist.add("__TIMESTAMP__",oldtimestamp);
  88.       free(oldtimestamp);
  89.   }
  90. }
  91.  
  92. char *CEXEBuild::set_line_predefine(int linecnt, BOOL is_macro)
  93. {
  94.   char* linebuf = NULL;
  95.   char temp[8] = "";
  96.   wsprintf(temp,"%d",linecnt);
  97.  
  98.   char *oldline = definedlist.find("__LINE__");
  99.   if(oldline) {
  100.     oldline = strdup(oldline);
  101.     definedlist.del("__LINE__");
  102.   }
  103.   if(is_macro && oldline) {
  104.     linebuf = (char *)malloc(strlen(oldline)+strlen(temp)+2);
  105.     wsprintf(linebuf,"%s.%s",oldline,temp);
  106.   }
  107.   else {
  108.     linebuf = strdup(temp);
  109.   }
  110.   definedlist.add("__LINE__",linebuf);
  111.   free(linebuf);
  112.  
  113.   return oldline;
  114. }
  115.  
  116. void CEXEBuild::restore_line_predefine(char *oldline)
  117. {
  118.   definedlist.del("__LINE__");
  119.   if(oldline) {
  120.       definedlist.add("__LINE__",oldline);
  121.       free(oldline);
  122.   }
  123. }
  124.  
  125. void CEXEBuild::set_date_time_predefines()
  126. {
  127.   time_t etime;
  128.   struct tm * ltime;
  129.   SYSTEMTIME stime;
  130.   char datebuf[32];
  131.   char timebuf[32];
  132.  
  133.   time(&etime);
  134.   ltime = localtime(&etime);
  135.   stime.wYear = ltime->tm_year+1900;
  136.   stime.wMonth = ltime->tm_mon + 1;
  137.   stime.wDay = ltime->tm_mday;
  138.   stime.wHour= ltime->tm_hour; 
  139.   stime.wMinute= ltime->tm_min; 
  140.   stime.wSecond= ltime->tm_sec; 
  141.   stime.wMilliseconds= 0; 
  142.   GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &stime, NULL, datebuf, sizeof(datebuf)); 
  143.   definedlist.add("__DATE__",(char *)datebuf);
  144.   GetTimeFormat(LOCALE_USER_DEFAULT, 0, &stime, NULL, timebuf, sizeof(timebuf)); 
  145.   definedlist.add("__TIME__",(char *)timebuf);
  146. }
  147.  
  148. void CEXEBuild::del_date_time_predefines()
  149. {
  150.   definedlist.del("__DATE__");
  151.   definedlist.del("__TIME__");
  152. }
  153. #endif
  154.  
  155. int CEXEBuild::process_script(FILE *filepointer, char *filename)
  156. {
  157.   linecnt = 0;
  158.   fp = filepointer;
  159.   curfilename = filename;
  160.  
  161.   if (has_called_write_output)
  162.   {
  163.     ERROR_MSG("Error (process_script): write_output already called, can't continue\n");
  164.     return PS_ERROR;
  165.   }
  166.  
  167. #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES
  168.   // Added by Sunil Kamath 11 June 2003
  169.   set_date_time_predefines();
  170.   char *oldfilename = set_file_predefine(curfilename);
  171.   char *oldtimestamp = set_timestamp_predefine(curfilename);
  172. #endif
  173.  
  174.   int ret=parseScript();
  175.  
  176. #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES
  177.   // Added by Sunil Kamath 11 June 2003
  178.   restore_file_predefine(oldfilename);
  179.   restore_timestamp_predefine(oldtimestamp);
  180.   del_date_time_predefines();
  181. #endif
  182.  
  183.   fp = 0;
  184.   curfilename = 0;
  185.  
  186.   if (m_linebuild.getlen())
  187.   {
  188.     ERROR_MSG("Error: invalid script: last line ended with \\\n");
  189.     return PS_ERROR;
  190.   }
  191.  
  192.   if (ret == PS_EOF && num_ifblock())
  193.   {
  194.     ERROR_MSG("!if[macro][n]def: open at EOF - need !endif\n");
  195.     return PS_ERROR;
  196.   }
  197.  
  198.   return ret;
  199. }
  200.  
  201. #define PRINTHELP() { print_help(line.gettoken_str(0)); return PS_ERROR; }
  202.  
  203. void CEXEBuild::start_ifblock()
  204. {
  205.   ifblock ib = {0, };
  206.   if (cur_ifblock)
  207.     ib.inherited_ignore = cur_ifblock->ignore || cur_ifblock->inherited_ignore;
  208.   int num = build_preprocessor_data.getlen() / sizeof(ifblock);
  209.   build_preprocessor_data.add(&ib, sizeof(ifblock));
  210.   cur_ifblock = (ifblock *) build_preprocessor_data.get() + num;
  211. }
  212.  
  213. void CEXEBuild::end_ifblock()
  214. {
  215.   if (build_preprocessor_data.getlen())
  216.   {
  217.     cur_ifblock--;
  218.     build_preprocessor_data.resize(build_preprocessor_data.getlen() - sizeof(ifblock));
  219.     if (!build_preprocessor_data.getlen())
  220.       cur_ifblock = 0;
  221.   }
  222. }
  223.  
  224. int CEXEBuild::num_ifblock()
  225. {
  226.   return build_preprocessor_data.getlen() / sizeof(ifblock);
  227. }
  228.  
  229. int CEXEBuild::doParse(const char *str)
  230. {
  231.   LineParser line(inside_comment);
  232.   int res;
  233.  
  234.   while (*str == ' ' || *str == '\t') str++;
  235.  
  236.   // if ignoring, ignore all lines that don't begin with !.
  237.   if (cur_ifblock && (cur_ifblock->ignore || cur_ifblock->inherited_ignore) && *str!='!' && !last_line_had_slash) return PS_OK;
  238.  
  239.   if (m_linebuild.getlen()>1) m_linebuild.resize(m_linebuild.getlen()-2);
  240.  
  241.   m_linebuild.add(str,strlen(str)+1);
  242.  
  243.   // remove trailing slash and null
  244.   if (str[0] && CharPrev(str,str+strlen(str))[0] == '\\') {
  245.     last_line_had_slash = 1;
  246.     return PS_OK;
  247.   }
  248.   else last_line_had_slash = 0;
  249.  
  250.   res=line.parse((char*)m_linebuild.get(),!strnicmp((char*)m_linebuild.get(),"!define",7));
  251.  
  252.   inside_comment = line.InCommentBlock();
  253.  
  254.   m_linebuild.resize(0);
  255.  
  256.   if (res)
  257.   {
  258.     if (res==-2) ERROR_MSG("Error: unterminated string parsing line at %s:%d\n",curfilename,linecnt);
  259.     else ERROR_MSG("Error: error parsing line (%s:%d)\n",curfilename,linecnt);
  260.     return PS_ERROR;
  261.   }
  262.  
  263. parse_again:
  264.   if (line.getnumtokens() < 1) return PS_OK;
  265.  
  266.   int np,op,pos;
  267.   int tkid=get_commandtoken(line.gettoken_str(0),&np,&op,&pos);
  268.   if (tkid == -1)
  269.   {
  270.     char *p=line.gettoken_str(0);
  271.     if (p[0] && p[strlen(p)-1]==':')
  272.     {
  273.       if (p[0] == '!' || (p[0] >= '0' && p[0] <= '9') || p[0] == '$' || p[0] == '-' || p[0] == '+')
  274.       {
  275.         ERROR_MSG("Invalid label: %s (labels cannot begin with !, $, -, +, or 0-9)\n",line.gettoken_str(0));
  276.         return PS_ERROR;
  277.       }
  278.       if (add_label(line.gettoken_str(0))) return PS_ERROR;
  279.       line.eattoken();
  280.       goto parse_again;
  281.     }
  282.  
  283. #ifdef NSIS_CONFIG_PLUGIN_SUPPORT
  284.     // Added by Ximon Eighteen 5th August 2002
  285.     // We didn't recognise this command, could it be the name of a
  286.     // function exported from a dll?
  287.     if (m_plugins.IsPluginCommand(line.gettoken_str(0)))
  288.     {
  289.       np   = 0;   // parameters are optional
  290.       op   = -1;  // unlimited number of optional parameters
  291.       pos  = -1;  // placement will tested later
  292.       tkid = TOK__PLUGINCOMMAND;
  293.     }
  294.     else
  295. #endif
  296.     {
  297.       ERROR_MSG("Invalid command: %s\n",line.gettoken_str(0));
  298.       return PS_ERROR;
  299.     }
  300.   }
  301.  
  302.   if (IsTokenPlacedRight(pos, line.gettoken_str(0)) != PS_OK)
  303.     return PS_ERROR;
  304.  
  305.   int v=line.getnumtokens()-(np+1);
  306.   if (v < 0 || (op >= 0 && v > op)) // opt_parms is -1 for unlimited
  307.   {
  308.     ERROR_MSG("%s expects %d",line.gettoken_str(0),np);
  309.     if (op < 0) ERROR_MSG("+");
  310.     if (op > 0) ERROR_MSG("-%d",op+np);
  311.     ERROR_MSG(" parameters, got %d.\n",line.getnumtokens()-1);
  312.     PRINTHELP()
  313.   }
  314.  
  315.   int if_from_else = 0;
  316.  
  317.   if (tkid == TOK_P_ELSE)
  318.   {
  319.     if (cur_ifblock && cur_ifblock->inherited_ignore)
  320.       return PS_OK;
  321.  
  322.     if (!num_ifblock() || cur_ifblock->elseused)
  323.     {
  324.       ERROR_MSG("!else: stray !else\n");
  325.       return PS_ERROR;
  326.     }
  327.  
  328.     if (cur_ifblock->hasexeced)
  329.     {
  330.       cur_ifblock->ignore++;
  331.       return PS_OK;
  332.     }
  333.  
  334.     if (line.getnumtokens() == 1)
  335.     {
  336.       cur_ifblock->ignore = !cur_ifblock->ignore;
  337.       // if not executed up until now, it will now
  338.       cur_ifblock->hasexeced++;
  339.       cur_ifblock->elseused++;
  340.       return PS_OK;
  341.     }
  342.  
  343.     line.eattoken();
  344.  
  345.     int v=line.gettoken_enum(0,"ifdef\0ifndef\0ifmacrodef\0ifmacrondef\0");
  346.     if (v < 0) PRINTHELP()
  347.     if (line.getnumtokens() == 1) PRINTHELP()
  348.     int cmds[] = {TOK_P_IFDEF, TOK_P_IFNDEF, TOK_P_IFMACRODEF, TOK_P_IFMACRONDEF};
  349.     tkid = cmds[v];
  350.     if_from_else++;
  351.   }
  352.  
  353.   if (tkid == TOK_P_IFNDEF || tkid == TOK_P_IFDEF ||
  354.       tkid == TOK_P_IFMACRODEF || tkid == TOK_P_IFMACRONDEF)
  355.   {
  356.     if (!if_from_else)
  357.       start_ifblock();
  358.  
  359.     if (cur_ifblock && cur_ifblock->inherited_ignore)
  360.     {
  361.       return PS_OK;
  362.     }
  363.  
  364.     int istrue=0;
  365.     
  366.     int mod=0;
  367.     int p;
  368.  
  369.     // pure left to right precedence. Not too powerful, but useful.
  370.     for (p = 1; p < line.getnumtokens(); p ++)
  371.     {
  372.       if (p & 1)
  373.       {
  374.         int new_s;
  375.         if (tkid == TOK_P_IFNDEF || tkid == TOK_P_IFDEF)
  376.           new_s=!!definedlist.find(line.gettoken_str(p));
  377.         else
  378.           new_s=MacroExists(line.gettoken_str(p));
  379.         if (tkid == TOK_P_IFNDEF || tkid == TOK_P_IFMACRONDEF)
  380.           new_s=!new_s;
  381.  
  382.         if (mod == 0) istrue = istrue || new_s;
  383.         else istrue = istrue && new_s;
  384.       }
  385.       else
  386.       {
  387.         mod=line.gettoken_enum(p,"|\0&\0||\0&&\0");
  388.         if (mod == -1) PRINTHELP()
  389.         mod &= 1;
  390.       }
  391.     }
  392.  
  393.     if (istrue)
  394.     {
  395.       cur_ifblock->hasexeced++;
  396.       cur_ifblock->ignore = 0;
  397.     }
  398.     else
  399.       cur_ifblock->ignore++;
  400.  
  401.     return PS_OK;
  402.   }
  403.   if (tkid == TOK_P_ENDIF) {
  404.     if (!num_ifblock())
  405.     {
  406.       ERROR_MSG("!endif: no !ifdef open\n");
  407.       return PS_ERROR;
  408.     }
  409.     end_ifblock();
  410.     return PS_OK;
  411.   }
  412.   if (!cur_ifblock || (!cur_ifblock->ignore && !cur_ifblock->inherited_ignore))
  413.   {
  414.     return doCommand(tkid,line);
  415.   }
  416.  
  417.   return PS_OK;
  418. }
  419.  
  420. #ifdef NSIS_FIX_DEFINES_IN_STRINGS
  421. void CEXEBuild::ps_addtoline(const char *str, GrowBuf &linedata, StringList &hist, bool bIgnoreDefines /*= false*/)
  422. #else
  423. void CEXEBuild::ps_addtoline(const char *str, GrowBuf &linedata, StringList &hist)
  424. #endif
  425. {
  426.   // convert $\r, $\n to their literals
  427.   // preprocessor replace ${VAR} and $%VAR% with whatever value
  428.   // note that if VAR does not exist, ${VAR} or $%VAR% will go through unmodified
  429.   const char *in=str;
  430.   while (*in)
  431.   {
  432.     int add=1;
  433.     char *t;
  434.     char c=*in;
  435.     t=CharNext(in);
  436.  
  437.     if (t-in > 1) // handle multibyte chars (no escape)
  438.     {
  439.       linedata.add((void*)in,t-in);
  440.       in=t;
  441.       continue;
  442.     }
  443.     in=t;
  444.  
  445.     if (c == '$')
  446.     {
  447.       if (in[0] == '\\')
  448.       {
  449.         if (in[1] == 'r')
  450.         {
  451.           in+=2;
  452.           c='\r';
  453.         }
  454.         else if (in[1] == 'n')
  455.         {
  456.           in+=2;
  457.           c='\n';
  458.         }
  459.         else if (in[1] == 't')
  460.         {
  461.           in+=2;
  462.           c='\t';
  463.         }
  464.       }
  465.       else if (in[0] == '{')
  466.       {
  467.         char *s=strdup(in+1);
  468.         char *t=s;
  469.         unsigned int bn = 0;
  470.         while (*t)
  471.         {
  472.           if (*t == '{') bn++;
  473.           if (*t == '}' && bn-- == 0) break;
  474.           t=CharNext(t);
  475.         }
  476.         if (*t && t!=s 
  477. #ifdef NSIS_FIX_DEFINES_IN_STRINGS
  478.           && !bIgnoreDefines 
  479. #endif
  480.           )
  481.         {
  482.           *t=0;
  483.           // check for defines inside the define name - ${bla${blo}}
  484.           GrowBuf defname;
  485.           ps_addtoline(s,defname,hist);
  486.           defname.add("",1);
  487.           t=definedlist.find((char*)defname.get());
  488.           if (t && hist.find((char*)defname.get(),0)<0)
  489.           {
  490.             in+=strlen(s)+2;
  491.             add=0;
  492.             hist.add((char*)defname.get(),0);
  493. #ifdef NSIS_FIX_DEFINES_IN_STRINGS
  494.             ps_addtoline(t,linedata,hist,true);
  495. #else
  496.             ps_addtoline(t,linedata,hist);
  497. #endif
  498.             hist.delbypos(hist.find((char*)defname.get(),0));
  499.           }
  500.         }
  501.         free(s);
  502.       }
  503.       else if (in[0] == '%')
  504.       {
  505.         char *s=strdup(in+1);
  506.         char *t=s;
  507.         while (*t)
  508.         {
  509.           if (*t == '%') break;
  510.           t=CharNext(t);
  511.         }
  512.         if (*t && t!=s)
  513.         {
  514.           *t=0;
  515.           // check for defines inside the define name - ${bla${blo}}
  516.           GrowBuf defname;
  517.           ps_addtoline(s,defname,hist);
  518.           defname.add("",1);
  519.           t=getenv((char*)defname.get());
  520.           if (t && hist.find((char*)defname.get(),0)<0)
  521.           {
  522.             in+=strlen(s)+2;
  523.             add=0;
  524.             hist.add((char*)defname.get(),0);
  525. #ifdef NSIS_FIX_DEFINES_IN_STRINGS
  526.             ps_addtoline(t,linedata,hist,true);
  527. #else
  528.             ps_addtoline(t,linedata,hist);
  529. #endif
  530.             hist.delbypos(hist.find((char*)defname.get(),0));
  531.           }
  532.         }
  533.         free(s);
  534.       }
  535. #ifdef NSIS_FIX_DEFINES_IN_STRINGS
  536.       else if (in[0] == '$')
  537.       {
  538.         if (in[1] == '{') // Found $$ before - Don't replace this define
  539.         {
  540.           char *s=strdup(in+2);
  541.           char *t=s;
  542.           unsigned int bn = 0;
  543.           while (*t)
  544.           {
  545.             if (*t == '{') bn++;
  546.             if (*t == '}' && bn-- == 0) break;
  547.             t=CharNext(t);
  548.           }
  549.           if (*t && t!=s)
  550.           {
  551.             *t=0;
  552.             // add text unchanged
  553.             GrowBuf defname;
  554.             ps_addtoline(s,defname,hist);
  555.             in++;
  556.           }
  557.           free(s);
  558.         }
  559.         else
  560.         {
  561.           linedata.add((void*)&c,1);
  562.           in++;
  563.         }
  564.       }
  565. #endif
  566.     }
  567.     if (add) linedata.add((void*)&c,1);
  568.   }
  569. }
  570.  
  571. int CEXEBuild::parseScript()
  572. {
  573.   char str[MAX_LINELENGTH];
  574.  
  575.   for (;;)
  576.   {
  577.     char *p=str;
  578.     *p=0;
  579.     fgets(str,MAX_LINELENGTH,fp);
  580.     linecnt++;
  581.     if (feof(fp)&&!str[0]) break;
  582.  
  583.     // remove trailing whitespace
  584.     while (*p) p++;
  585.     if (p > str) p--;
  586.     while (p >= str && (*p == '\r' || *p == '\n' || *p == ' ' || *p == '\t')) p--;
  587.     *++p=0;
  588.  
  589.     StringList hist;
  590.     GrowBuf linedata;
  591.  
  592. #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES
  593.   // Added by Sunil Kamath 11 June 2003
  594.     char *oldline = set_line_predefine(linecnt, FALSE);
  595. #endif
  596.  
  597.     ps_addtoline(str,linedata,hist);
  598.     linedata.add((void*)"",1);
  599.     int ret=doParse((char*)linedata.get());
  600.  
  601. #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES
  602.     // Added by Sunil Kamath 11 June 2003
  603.     restore_line_predefine(oldline);
  604. #endif
  605.     
  606.     if (ret != PS_OK) return ret;
  607.   }
  608.  
  609.   return PS_EOF;
  610. }
  611.  
  612. int CEXEBuild::includeScript(char *f)
  613. {
  614.   SCRIPT_MSG("!include: \"%s\"\n",f);
  615.   FILE *incfp=fopen(f,"rt");
  616.   if (!incfp)
  617.   {
  618.     ERROR_MSG("!include: could not open file: \"%s\"\n",f);
  619.     return PS_ERROR;
  620.   }
  621.   if (build_include_depth >= MAX_INCLUDEDEPTH)
  622.   {
  623.     ERROR_MSG("parseScript: too many levels of includes (%d max).\n",MAX_INCLUDEDEPTH);
  624.     return PS_ERROR;
  625.   }
  626.   build_include_depth++;
  627.  
  628.   int last_linecnt=linecnt;
  629.   linecnt=0;
  630.   char *last_filename=curfilename;
  631.   curfilename=f;
  632.   FILE *last_fp=fp;
  633.   fp=incfp;
  634.  
  635. #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES
  636.   // Added by Sunil Kamath 11 June 2003
  637.   char *oldfilename = set_file_predefine(curfilename);
  638.   char *oldtimestamp = set_timestamp_predefine(curfilename);
  639. #endif
  640.  
  641.   int r=parseScript();
  642.  
  643. #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES
  644.   // Added by Sunil Kamath 11 June 2003
  645.   restore_file_predefine(oldfilename);
  646.   restore_timestamp_predefine(oldtimestamp);
  647. #endif
  648.  
  649.   int errlinecnt=linecnt;
  650.  
  651.   linecnt=last_linecnt;
  652.   curfilename=last_filename;
  653.   fp=last_fp;
  654.  
  655.   build_include_depth--;
  656.   fclose(incfp);
  657.   if (r != PS_EOF && r != PS_OK)
  658.   {
  659.     ERROR_MSG("!include: error in script: \"%s\" on line %d\n",f,errlinecnt);
  660.     return PS_ERROR;
  661.   }
  662.   SCRIPT_MSG("!include: closed: \"%s\"\n",f);
  663.   return PS_OK;
  664. }
  665.  
  666. // !ifmacro[n]def based on Anders Kjersem's code
  667. int CEXEBuild::MacroExists(const char *macroname)
  668. {
  669.   char *m = (char *) m_macros.get();
  670.  
  671.   while (m && *m)
  672.   {
  673.     // check if macroname matches
  674.     if (!stricmp(m, macroname))
  675.       return 1;
  676.  
  677.     // skip macro name
  678.     m += strlen(m) + 1;
  679.  
  680.     // skip params
  681.     while (*m) m += strlen(m) + 1;
  682.     m++;
  683.  
  684.     // skip data
  685.     while (*m) m += strlen(m) + 1;
  686.     if (m - (char *) m_macros.get() >= m_macros.getlen() - 1) break;
  687.     m++;
  688.   }
  689.   return 0;
  690. }
  691.  
  692. int CEXEBuild::process_oneline(char *line, char *filename, int linenum)
  693. {
  694.   char *last_filename=curfilename;
  695.   curfilename=filename;
  696.   int last_linecnt=linecnt;
  697.   linecnt=linenum;
  698.  
  699.   StringList hist;
  700.   GrowBuf linedata;
  701.   
  702. #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES
  703.   // Added by Sunil Kamath 11 June 2003
  704.   char *oldfilename = NULL;
  705.   char *oldtimestamp = NULL;
  706.   char *oldline = NULL;
  707.   BOOL is_commandline = !strcmp(filename,"command line");
  708.   BOOL is_macro = !strncmp(filename,"macro:",strlen("macro:"));
  709.  
  710.   if(!is_commandline) { // Don't set the predefines for command line /X option
  711.     if(!is_macro) {
  712.       oldfilename = set_file_predefine(curfilename);
  713.       oldtimestamp = set_timestamp_predefine(curfilename);
  714.     }
  715.     oldline = set_line_predefine(linecnt, is_macro);
  716.   }
  717. #endif
  718.  
  719.   ps_addtoline(line,linedata,hist);
  720.   linedata.add((void*)"",1);
  721.   int ret=doParse((char*)linedata.get());
  722.  
  723. #ifdef NSIS_SUPPORT_STANDARD_PREDEFINES
  724.   // Added by Sunil Kamath 11 June 2003
  725.   if(!is_commandline) { // Don't set the predefines for command line /X option
  726.     if(!is_macro) {
  727.       restore_file_predefine(oldfilename);
  728.       restore_timestamp_predefine(oldtimestamp);
  729.     }
  730.     restore_line_predefine(oldline);
  731.   }
  732. #endif
  733.  
  734.   linecnt=last_linecnt;
  735.   curfilename=last_filename;
  736.  
  737.   return ret;
  738. }
  739.  
  740. int CEXEBuild::process_jump(LineParser &line, int wt, int *offs)
  741. {
  742.   const char *s=line.gettoken_str(wt);
  743.   int v;
  744.  
  745.   if (!stricmp(s,"0") || !stricmp(s,"")) *offs=0;
  746.   else if ((v=GetUserVarIndex(line, wt))>=0)
  747.   {
  748.     *offs=-v-1; // to jump to a user variable target, -variable_index-1 is stored.
  749.   }
  750.   else
  751.   {
  752.     if ((s[0] == '-' || s[0] == '+') && !atoi(s+1))
  753.     {
  754.       ERROR_MSG("Error: Goto targets beginning with '+' or '-' must be followed by nonzero integer (relative jump)\n");
  755.       return 1;
  756.     }
  757.     if ((s[0] >= '0' && s[0] <= '9') || s[0] == '$' || s[0] == '!')
  758.     {
  759.       ERROR_MSG("Error: Goto targets cannot begin with 0-9, $, !\n");
  760.       return 1;
  761.     }
  762.     *offs=ns_label.add(s,0);
  763.   }
  764.   return 0;
  765. }
  766.  
  767. #define FLAG_OFFSET(flag) (FIELD_OFFSET(exec_flags, flag)/sizeof(int))
  768. #define SECTION_FIELD_GET(field) (FIELD_OFFSET(section, field)/sizeof(int))
  769. #define SECTION_FIELD_SET(field) (-1 - (int)(FIELD_OFFSET(section, field)/sizeof(int)))
  770.  
  771. int CEXEBuild::doCommand(int which_token, LineParser &line)
  772. {
  773.   static const char *rootkeys[2] = {
  774.     "HKCR\0HKLM\0HKCU\0HKU\0HKCC\0HKDD\0HKPD\0",
  775.     "HKEY_CLASSES_ROOT\0HKEY_LOCAL_MACHINE\0HKEY_CURRENT_USER\0HKEY_USERS\0HKEY_CURRENT_CONFIG\0HKEY_DYN_DATA\0HKEY_PERFORMANCE_DATA\0"
  776.   };
  777.   static HKEY rootkey_tab[] = {
  778.     HKEY_CLASSES_ROOT,HKEY_LOCAL_MACHINE,HKEY_CURRENT_USER,HKEY_USERS,HKEY_CURRENT_CONFIG,HKEY_DYN_DATA,HKEY_PERFORMANCE_DATA
  779.   };
  780.  
  781. #ifdef NSIS_CONFIG_PLUGIN_SUPPORT
  782.   build_plugin_table();
  783. #endif
  784.  
  785.   entry ent={0,};
  786.   switch (which_token)
  787.   {
  788.     // macro shit
  789.     ///////////////////////////////////////////////////////////////////////////////
  790.     case TOK_P_MACRO:
  791.       {
  792.         if (!line.gettoken_str(1)[0]) PRINTHELP()
  793.         char *t=(char *)m_macros.get();
  794.         while (t && *t)
  795.         {
  796.           if (!stricmp(t,line.gettoken_str(1))) break;
  797.           t+=strlen(t)+1;
  798.  
  799.           // advance over parameters
  800.           while (*t) t+=strlen(t)+1;
  801.           t++;
  802.  
  803.           // advance over data
  804.           while (*t) t+=strlen(t)+1;
  805.           if (t-(char *)m_macros.get() >= m_macros.getlen()-1)
  806.             break;
  807.           t++;
  808.         }
  809.         if (t && *t)
  810.         {
  811.           ERROR_MSG("!macro: macro named \"%s\" already found!\n",line.gettoken_str(1));
  812.           return PS_ERROR;
  813.         }
  814.         m_macros.add(line.gettoken_str(1),strlen(line.gettoken_str(1))+1);
  815.  
  816.         int pc;
  817.         for (pc=2; pc < line.getnumtokens(); pc ++)
  818.         {
  819.           if (!line.gettoken_str(pc)[0])
  820.           {
  821.             ERROR_MSG("!macro: macro parameter %d is empty, not valid!\n",pc-1);
  822.             return PS_ERROR;
  823.           }
  824.           int a;
  825.           for (a=2; a < pc; a ++)
  826.           {
  827.             if (!stricmp(line.gettoken_str(pc),line.gettoken_str(a)))
  828.             {
  829.               ERROR_MSG("!macro: macro parameter named %s is used multiple times!\n",
  830.                 line.gettoken_str(pc));
  831.               return PS_ERROR;
  832.             }
  833.           }
  834.           m_macros.add(line.gettoken_str(pc),strlen(line.gettoken_str(pc))+1);
  835.         }
  836.         m_macros.add("",1);
  837.  
  838.         for (;;)
  839.         {
  840.           char str[MAX_LINELENGTH];
  841.           char *p=str;
  842.           str[0]=0;
  843.           fgets(str,MAX_LINELENGTH,fp);
  844.           //SCRIPT_MSG("%s%s", str, str[lstrlen(str)-1]=='\n'?"":"\n");
  845.           if (feof(fp) && !str[0])
  846.           {
  847.             ERROR_MSG("!macro \"%s\": unterminated (no !macroend found in file)!\n",line.gettoken_str(1));
  848.             return PS_ERROR;
  849.           }
  850.           // remove trailing whitespace
  851.           while (*p) p++;
  852.           if (p > str) p--;
  853.           while (p >= str && (*p == '\r' || *p == '\n' || *p == ' ' || *p == '\t')) p--;
  854.           *++p=0;
  855.           LineParser l2(false);
  856.           if (!l2.parse(str))
  857.           {
  858.             if (!stricmp(l2.gettoken_str(0),"!macroend"))
  859.             {
  860.               linecnt++;
  861.               break;
  862.             }
  863.             if (!stricmp(l2.gettoken_str(0),"!macro"))
  864.             {
  865.               ERROR_MSG("Error: can't define a macro inside a macro!\n");
  866.               return PS_ERROR;
  867.             }
  868.           }
  869.           if (str[0]) m_macros.add(str,strlen(str)+1);
  870.           else m_macros.add(" ",2);
  871.           linecnt++;
  872.         }
  873.         m_macros.add("",1);
  874.       }
  875.     return PS_OK;
  876.     case TOK_P_MACROEND:
  877.       ERROR_MSG("!macroend: no macro currently open.\n");
  878.     return PS_ERROR;
  879.     case TOK_P_INSERTMACRO:
  880.       {
  881.         if (!line.gettoken_str(1)[0]) PRINTHELP()
  882.         char *t=(char *)m_macros.get();
  883.         while (t && *t)
  884.         {
  885.           if (!stricmp(t,line.gettoken_str(1))) break;
  886.           t+=strlen(t)+1;
  887.  
  888.           // advance over parms
  889.           while (*t) t+=strlen(t)+1;
  890.           t++;
  891.  
  892.           // advance over data
  893.           while (*t) t+=strlen(t)+1;
  894.           if (t-(char *)m_macros.get() >= m_macros.getlen()-1)
  895.             break;
  896.           t++;
  897.         }
  898.         SCRIPT_MSG("!insertmacro: %s\n",line.gettoken_str(1));
  899.         if (!t || !*t)
  900.         {
  901.           ERROR_MSG("!insertmacro: macro named \"%s\" not found!\n",line.gettoken_str(1));
  902.           return PS_ERROR;
  903.         }
  904.         t+=strlen(t)+1;
  905.  
  906.  
  907.         GrowBuf l_define_names;
  908.         DefineList l_define_saves;
  909.         int npr=0;
  910.         // advance over parms
  911.         while (*t)
  912.         {
  913.           char *v;
  914.           if (v=definedlist.find(t))
  915.           {
  916.             l_define_saves.add(t,v);
  917.             definedlist.del(t);
  918.           }
  919.           l_define_names.add(t,strlen(t)+1);
  920.           definedlist.add(t,line.gettoken_str(npr+2));
  921.  
  922.           npr++;
  923.           t+=strlen(t)+1;
  924.         }
  925.         l_define_names.add("",1);
  926.         t++;
  927.         if (npr != line.getnumtokens()-2)
  928.         {
  929.           ERROR_MSG("!insertmacro: macro \"%s\" requires %d parameter(s), passed %d!\n",
  930.             line.gettoken_str(1),npr,line.getnumtokens()-2);
  931.           return PS_ERROR;
  932.         }
  933.  
  934.         int lp=0;
  935.         char str[1024];
  936.         if (m_macro_entry.find(line.gettoken_str(1),0)>=0)
  937.         {
  938.           ERROR_MSG("!insertmacro: macro \"%s\" already being inserted!\n",line.gettoken_str(1));
  939.           return PS_ERROR;
  940.         }
  941.         int npos=m_macro_entry.add(line.gettoken_str(1),0);
  942.  
  943.         wsprintf(str,"macro:%s",line.gettoken_str(1));
  944.         while (*t)
  945.         {
  946.           lp++;
  947.           if (strcmp(t," "))
  948.           {
  949.             int ret=process_oneline(t,str,lp);
  950.             if (ret != PS_OK)
  951.             {
  952.               ERROR_MSG("Error in macro %s on macroline %d\n",line.gettoken_str(1),lp);
  953.               return ret;
  954.             }
  955.           }
  956.           t+=strlen(t)+1;
  957.         }
  958.         m_macro_entry.delbypos(npos);
  959.         {
  960.           char *p=(char*)l_define_names.get();
  961.           while (*p)
  962.           {
  963.             definedlist.del(p);
  964.             char *v;
  965.             if ((v=l_define_saves.find(p))) definedlist.add(p,v);
  966.             p+=strlen(p)+1;
  967.           }
  968.         }
  969.         SCRIPT_MSG("!insertmacro: end of %s\n",line.gettoken_str(1));
  970.       }
  971.  
  972.     return PS_OK;
  973.     // page ordering shit
  974.     ///////////////////////////////////////////////////////////////////////////////
  975. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  976.     case TOK_UNINSTPAGE:
  977.       set_uninstall_mode(1);
  978.     case TOK_PAGE:
  979.       {
  980.         if (!uninstall_mode) {
  981.           enable_last_page_cancel = 0;
  982.           if (!stricmp(line.gettoken_str(line.getnumtokens()-1),"/ENABLECANCEL"))
  983.             enable_last_page_cancel = 1;
  984.         }
  985.         else {
  986.           uenable_last_page_cancel = 0;
  987.           if (!stricmp(line.gettoken_str(line.getnumtokens()-1),"/ENABLECANCEL"))
  988.             uenable_last_page_cancel = 1;
  989.         }
  990.  
  991.         int k = line.gettoken_enum(1,"custom\0license\0components\0directory\0instfiles\0uninstConfirm");
  992.  
  993.         if (k < 0) PRINTHELP();
  994.  
  995.         if (add_page(k) != PS_OK)
  996.           return PS_ERROR;
  997.  
  998. #ifndef NSIS_SUPPORT_CODECALLBACKS
  999.         if (!k) {
  1000.           ERROR_MSG("Error: custom page specified, NSIS_SUPPORT_CODECALLBACKS not defined.\n");
  1001.           return PS_ERROR;
  1002.         }
  1003. #endif//!NSIS_SUPPORT_CODECALLBACKS
  1004.  
  1005.         if (k) {
  1006.           // not custom
  1007. #ifdef NSIS_SUPPORT_CODECALLBACKS
  1008.           switch (line.getnumtokens() - enable_last_page_cancel) {
  1009.             case 6:
  1010.               PRINTHELP();
  1011.             case 5:
  1012.               if (*line.gettoken_str(4))
  1013.                 cur_page->leavefunc = ns_func.add(line.gettoken_str(4),0);
  1014.             case 4:
  1015.               if (*line.gettoken_str(3))
  1016.                 cur_page->showfunc = ns_func.add(line.gettoken_str(3),0);
  1017.             case 3:
  1018.               if (*line.gettoken_str(2))
  1019.                 cur_page->prefunc = ns_func.add(line.gettoken_str(2),0);
  1020.           }
  1021. #endif//NSIS_SUPPORT_CODECALLBACKS
  1022.         }
  1023. #ifdef NSIS_SUPPORT_CODECALLBACKS
  1024.         else {
  1025.           // a custom page
  1026.           switch (line.getnumtokens() - enable_last_page_cancel) {
  1027.             case 6:
  1028.               PRINTHELP();
  1029.             case 5:
  1030.               cur_page->caption = add_string(line.gettoken_str(4));
  1031.             case 4:
  1032.               if (*line.gettoken_str(3))
  1033.                 cur_page->leavefunc = ns_func.add(line.gettoken_str(3),0);
  1034.             case 3:
  1035.               if (*line.gettoken_str(2))
  1036.                 cur_page->prefunc = ns_func.add(line.gettoken_str(2),0);
  1037.               break;
  1038.             case 2:
  1039.               ERROR_MSG("Error: custom page must have a creator function!\n");
  1040.               PRINTHELP();
  1041.           }
  1042.         }
  1043. #endif//NSIS_SUPPORT_CODECALLBACKS
  1044.  
  1045.         SCRIPT_MSG("%sPage: %s", uninstall_mode?"Uninst":"", line.gettoken_str(1));
  1046.  
  1047. #ifdef NSIS_SUPPORT_CODECALLBACKS
  1048.         if (cur_page->prefunc>=0)
  1049.           SCRIPT_MSG(" (%s:%s)", k?"pre":"creator", line.gettoken_str(2));
  1050.         if (cur_page->showfunc>=0 && k)
  1051.           SCRIPT_MSG(" (show:%s)", line.gettoken_str(3));
  1052.         if (cur_page->leavefunc>=0)
  1053.           SCRIPT_MSG(" (leave:%s)", line.gettoken_str(4-!k));
  1054.         else if (cur_page->caption && !k)
  1055.           SCRIPT_MSG(" (caption:%s)", line.gettoken_str(3));
  1056. #endif
  1057.         SCRIPT_MSG("\n");
  1058.  
  1059.         page_end();
  1060.  
  1061.         if (k == PAGE_INSTFILES) {
  1062.           add_page(PAGE_COMPLETED);
  1063.           page_end();
  1064.         }
  1065.  
  1066.         set_uninstall_mode(0);
  1067.       }
  1068.     return PS_OK;
  1069.  
  1070.     // extended page setting
  1071.     case TOK_PAGEEX:
  1072.     {
  1073.       int k = line.gettoken_enum(1,"custom\0license\0components\0directory\0instfiles\0uninstConfirm\0");
  1074.       if (k < 0) {
  1075.         k = line.gettoken_enum(1,"un.custom\0un.license\0un.components\0un.directory\0un.instfiles\0un.uninstConfirm\0");
  1076.         if (k < 0) PRINTHELP();
  1077.         set_uninstall_mode(1);
  1078.       }
  1079.  
  1080.       SCRIPT_MSG("PageEx: %s\n", line.gettoken_str(1));
  1081.  
  1082.       if (add_page(k) != PS_OK)
  1083.         return PS_ERROR;
  1084.  
  1085.       cur_page->flags |= PF_PAGE_EX;
  1086.     }
  1087.     return PS_OK;
  1088.  
  1089.     case TOK_PAGEEXEND:
  1090.     {
  1091.       SCRIPT_MSG("PageExEnd\n");
  1092.  
  1093. #ifdef NSIS_SUPPORT_CODECALLBACKS
  1094.       if (cur_page_type == PAGE_CUSTOM && !cur_page->prefunc) {
  1095.         ERROR_MSG("Error: custom pages must have a creator function.\n");
  1096.         return PS_ERROR;
  1097.       }
  1098. #endif
  1099.  
  1100.       page_end();
  1101.  
  1102.       if (cur_page_type == PAGE_INSTFILES) {
  1103.         add_page(PAGE_COMPLETED);
  1104.         page_end();
  1105.       }
  1106.  
  1107.       set_uninstall_mode(0);
  1108.     }
  1109.     return PS_OK;
  1110.     case TOK_PAGECALLBACKS:
  1111. #ifdef NSIS_SUPPORT_CODECALLBACKS
  1112.     {
  1113.       SCRIPT_MSG("PageCallbacks:");
  1114.  
  1115.       if (cur_page_type == PAGE_CUSTOM)
  1116.       {
  1117.         switch (line.getnumtokens())
  1118.         {
  1119.           case 4:
  1120.           {
  1121.             PRINTHELP();
  1122.           }
  1123.           case 3:
  1124.           {
  1125.             if (*line.gettoken_str(2))
  1126.             {
  1127.               if (strnicmp(line.gettoken_str(2), "un.", 3))
  1128.               {
  1129.                 if (uninstall_mode)
  1130.                 {
  1131.                   ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n");
  1132.                   return PS_ERROR;
  1133.                 }
  1134.               }
  1135.               else
  1136.               {
  1137.                 if (!uninstall_mode)
  1138.                 {
  1139.                   ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n");
  1140.                   return PS_ERROR;
  1141.                 }
  1142.               }
  1143.               cur_page->leavefunc = ns_func.add(line.gettoken_str(2),0);
  1144.             }
  1145.           }
  1146.           case 2:
  1147.           {
  1148.             if (*line.gettoken_str(1))
  1149.             {
  1150.               if (strnicmp(line.gettoken_str(1), "un.", 3))
  1151.               {
  1152.                 if (uninstall_mode)
  1153.                 {
  1154.                   ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n");
  1155.                   return PS_ERROR;
  1156.                 }
  1157.               }
  1158.               else
  1159.               {
  1160.                 if (!uninstall_mode)
  1161.                 {
  1162.                   ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n");
  1163.                   return PS_ERROR;
  1164.                 }
  1165.               }
  1166.               cur_page->prefunc = ns_func.add(line.gettoken_str(1),0);
  1167.             }
  1168.           }
  1169.         }
  1170.       }
  1171.       else
  1172.       {
  1173.         switch (line.getnumtokens())
  1174.         {
  1175.           case 4:
  1176.           {
  1177.             if (*line.gettoken_str(3))
  1178.             {
  1179.               if (strnicmp(line.gettoken_str(3), "un.", 3))
  1180.               {
  1181.                 if (uninstall_mode)
  1182.                 {
  1183.                   ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n");
  1184.                   return PS_ERROR;
  1185.                 }
  1186.               }
  1187.               else
  1188.               {
  1189.                 if (!uninstall_mode)
  1190.                 {
  1191.                   ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n");
  1192.                   return PS_ERROR;
  1193.                 }
  1194.               }
  1195.               cur_page->leavefunc = ns_func.add(line.gettoken_str(3),0);
  1196.             }
  1197.           }
  1198.           case 3:
  1199.           {
  1200.             if (*line.gettoken_str(2))
  1201.             {
  1202.               if (strnicmp(line.gettoken_str(2), "un.", 3))
  1203.               {
  1204.                 if (uninstall_mode)
  1205.                 {
  1206.                   ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n");
  1207.                   return PS_ERROR;
  1208.                 }
  1209.               }
  1210.               else
  1211.               {
  1212.                 if (!uninstall_mode)
  1213.                 {
  1214.                   ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n");
  1215.                   return PS_ERROR;
  1216.                 }
  1217.               }
  1218.               cur_page->showfunc = ns_func.add(line.gettoken_str(2),0);
  1219.             }
  1220.           }
  1221.           case 2:
  1222.           {
  1223.             if (*line.gettoken_str(1))
  1224.             {
  1225.               if (strnicmp(line.gettoken_str(1), "un.", 3))
  1226.               {
  1227.                 if (uninstall_mode)
  1228.                 {
  1229.                   ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n");
  1230.                   return PS_ERROR;
  1231.                 }
  1232.               }
  1233.               else
  1234.               {
  1235.                 if (!uninstall_mode)
  1236.                 {
  1237.                   ERROR_MSG("\nError: function names must start with \"un.\" in an uninstall page.\n");
  1238.                   return PS_ERROR;
  1239.                 }
  1240.               }
  1241.               cur_page->prefunc = ns_func.add(line.gettoken_str(1),0);
  1242.             }
  1243.           }
  1244.         }
  1245.       }
  1246.       
  1247.       int custom = cur_page_type == PAGE_CUSTOM ? 1 : 0;
  1248.  
  1249.       if (cur_page->prefunc>=0)
  1250.         SCRIPT_MSG(" %s:%s", !custom?"pre":"creator", line.gettoken_str(1));
  1251.       if (cur_page->showfunc>=0 && !custom)
  1252.         SCRIPT_MSG(" show:%s", line.gettoken_str(2));
  1253.       if (cur_page->leavefunc>=0)
  1254.         SCRIPT_MSG(" leave:%s", line.gettoken_str(3-custom));
  1255.  
  1256.       SCRIPT_MSG("\n");
  1257.     }
  1258.     return PS_OK;
  1259. #else
  1260.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_CODECALLBACKS not defined.\n",  line.gettoken_str(0));
  1261.     return PS_ERROR;
  1262. #endif//NSIS_SUPPORT_CODECALLBACKS
  1263. #else
  1264.     case TOK_PAGE:
  1265.     case TOK_UNINSTPAGE:
  1266.     case TOK_PAGEEX:
  1267.     case TOK_PAGEEXEND:
  1268.     case TOK_PAGECALLBACKS:
  1269.       ERROR_MSG("Error: %s specified, NSIS_CONFIG_VISIBLE_SUPPORT not defined.\n",  line.gettoken_str(0));
  1270.     return PS_ERROR;
  1271. #endif//NSIS_CONFIG_VISIBLE_SUPPORT
  1272.     // header flags
  1273.     ///////////////////////////////////////////////////////////////////////////////
  1274.     case TOK_LANGSTRING:
  1275.     {
  1276.       char *name = line.gettoken_str(1);
  1277.       LANGID lang = line.gettoken_int(2);
  1278.       char *str = line.gettoken_str(3);
  1279.       int ret = SetLangString(name, lang, str);
  1280.       if (ret == PS_WARNING)
  1281.         warning_fl("LangString \"%s\" set multiple times for %d, wasting space", name, lang);
  1282.       else if (ret == PS_ERROR) {
  1283.         ERROR_MSG("Error: can't set LangString \"%s\"!\n", name);
  1284.         return PS_ERROR;
  1285.       }
  1286.       SCRIPT_MSG("LangString: \"%s\" %d \"%s\"\n", name, lang, str);
  1287.     }
  1288.     return PS_OK;
  1289.     case TOK_LANGSTRINGUP:
  1290.       SCRIPT_MSG("Error: LangStringUP is obsolete, there are no more unprocessed strings. Use LangString.\n");
  1291.     return PS_ERROR;
  1292.     case TOK_LICENSELANGSTRING:
  1293.     {
  1294. #ifdef NSIS_CONFIG_SILENT_SUPPORT
  1295.       if (build_header.flags&(CH_FLAGS_SILENT|CH_FLAGS_SILENT_LOG))
  1296.       {
  1297.         warning_fl("LicenseLangString: SilentInstall enabled, wasting space");
  1298.       }
  1299. #endif
  1300.       char *name = line.gettoken_str(1);
  1301.       LANGID lang = line.gettoken_int(2);
  1302.       char *file = line.gettoken_str(3);
  1303.  
  1304.       FILE *fp;
  1305.       int datalen;
  1306.       fp=fopen(file,"rb");
  1307.       if (!fp)
  1308.       {
  1309.         ERROR_MSG("LicenseLangString: open failed \"%s\"\n",file);
  1310.         PRINTHELP()
  1311.       }
  1312.       fseek(fp,0,SEEK_END);
  1313.       datalen=ftell(fp);
  1314.       if (!datalen)
  1315.       {
  1316.         ERROR_MSG("LicenseLangString: empty license file \"%s\"\n",file);
  1317.         fclose(fp);
  1318.         return PS_ERROR;
  1319.       }
  1320.       rewind(fp);
  1321.       char *data=(char*)malloc(datalen+2);
  1322.       if (!data)
  1323.       {
  1324.         ERROR_MSG("Internal compiler error #12345: LicenseData malloc(%d) failed.\n", datalen+2);
  1325.         return PS_ERROR;
  1326.       }
  1327.       char *ldata=data+1;
  1328.       if (fread(ldata,1,datalen,fp) != datalen)
  1329.       {
  1330.         ERROR_MSG("LicenseLangString: can't read file.\n");
  1331.         fclose(fp);
  1332.         return PS_ERROR;
  1333.       }
  1334.       fclose(fp);
  1335.       ldata[datalen]=0;
  1336.       if (!strncmp(ldata,"{\\rtf",sizeof("{\\rtf")-1))
  1337.         *data = SF_RTF;
  1338.       else
  1339.         *data = SF_TEXT;
  1340.  
  1341.       int ret = SetLangString(name, lang, data);
  1342.       free(data);
  1343.       if (ret == PS_WARNING)
  1344.         warning_fl("LicenseLangString \"%s\" set multiple times for %d, wasting space", name, lang);
  1345.       else if (ret == PS_ERROR)
  1346.       {
  1347.         ERROR_MSG("Error: can't set LicenseLangString \"%s\"!\n", name);
  1348.         return PS_ERROR;
  1349.       }
  1350.  
  1351.       SCRIPT_MSG("LicenseLangString: \"%s\" %d \"%s\"\n", name, lang, file);
  1352.     }
  1353.     return PS_OK;
  1354.     case TOK_NAME:
  1355.       {
  1356.         if (SetInnerString(NLF_NAME,line.gettoken_str(1)) == PS_WARNING)
  1357.           warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0));
  1358.         SetInnerString(NLF_NAME_DA,line.gettoken_str(2));
  1359.         SCRIPT_MSG("Name: \"%s\"",line.gettoken_str(1));
  1360.         if (*line.gettoken_str(2))
  1361.           SCRIPT_MSG(" \"%s\"",line.gettoken_str(2));
  1362.         SCRIPT_MSG("\n");
  1363.       }
  1364.     return PS_OK;
  1365.     case TOK_CAPTION:
  1366.       {
  1367.         if (!cur_page)
  1368.         {
  1369.           if (SetInnerString(NLF_CAPTION,line.gettoken_str(1)) == PS_WARNING)
  1370.             warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0));
  1371.         }
  1372.         else
  1373.         {
  1374.           cur_page->caption = add_string(line.gettoken_str(1));
  1375.         }
  1376.         SCRIPT_MSG("Caption: \"%s\"\n",line.gettoken_str(1));
  1377.       }
  1378.     return PS_OK;
  1379.     case TOK_ICON:
  1380.       SCRIPT_MSG("Icon: \"%s\"\n",line.gettoken_str(1));
  1381.       try {
  1382.         init_res_editor();
  1383.         if (replace_icon(res_editor, IDI_ICON2, line.gettoken_str(1))) {
  1384.           ERROR_MSG("Error: File doesn't exist or is an invalid icon file\n");
  1385.           return PS_ERROR;
  1386.         }
  1387.       }
  1388.       catch (exception& err) {
  1389.         ERROR_MSG("Error while replacing icon: %s\n", err.what());
  1390.         return PS_ERROR;
  1391.       }
  1392.     return PS_OK;
  1393. #ifdef NSIS_CONFIG_COMPONENTPAGE
  1394.     case TOK_CHECKBITMAP:
  1395.       SCRIPT_MSG("CheckBitmap: \"%s\"\n",line.gettoken_str(1));
  1396.       try {
  1397.         init_res_editor();
  1398.         int err = update_bitmap(res_editor, IDB_BITMAP1, line.gettoken_str(1), 96, 16, 8);
  1399.         if (err) {
  1400.           switch (err) {
  1401.             case -1:
  1402.               ERROR_MSG("Error: can't find bitmap\n");
  1403.               break;
  1404.             case -2:
  1405.               ERROR_MSG("Error: invalid bitmap file - corrupted or not a bitmap\n");
  1406.               break;
  1407.             case -3:
  1408.               ERROR_MSG("Error: bitmap isn't 96x16 in size\n");
  1409.               break;
  1410.             case -4:
  1411.               ERROR_MSG("Error: bitmap has more than 8bpp\n");
  1412.               break;
  1413.           }
  1414.           return PS_ERROR;
  1415.         }
  1416.       }
  1417.       catch (exception& err) {
  1418.         ERROR_MSG("Error while replacing bitmap: %s\n", err.what());
  1419.         return PS_ERROR;
  1420.       }
  1421.     return PS_OK;
  1422. #else//NSIS_CONFIG_COMPONENTPAGE
  1423.     case TOK_CHECKBITMAP:
  1424.       ERROR_MSG("Error: %s specified, NSIS_CONFIG_COMPONENTPAGE not defined.\n",  line.gettoken_str(0));
  1425.     return PS_ERROR;
  1426. #endif//!NSIS_CONFIG_COMPONENTPAGE
  1427.     case TOK_DIRTEXT:
  1428. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  1429.       {
  1430.         if (!cur_page) {
  1431.           if (SetInnerString(NLF_DIR_TEXT, line.gettoken_str(1)) == PS_WARNING)
  1432.             warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0));
  1433.           if (line.getnumtokens() > 2)
  1434.             SetInnerString(NLF_DIR_SUBTEXT, line.gettoken_str(2));
  1435.           if (line.getnumtokens() > 3)
  1436.             SetInnerString(NLF_BTN_BROWSE, line.gettoken_str(3));
  1437.           if (line.getnumtokens() > 4)
  1438.             SetInnerString(NLF_DIR_BROWSETEXT, line.gettoken_str(4));
  1439.         }
  1440.         else {
  1441.           if (cur_page_type != PAGE_DIRECTORY) {
  1442.             ERROR_MSG("Error: DirText can only be used inside PageEx directory.\n");
  1443.             return PS_ERROR;
  1444.           }
  1445.           cur_page->parms[0] = add_string(line.gettoken_str(1));
  1446.           if (line.getnumtokens() > 2)
  1447.             cur_page->parms[1] = add_string(line.gettoken_str(2));
  1448.           if (line.getnumtokens() > 3)
  1449.             cur_page->parms[2] = add_string(line.gettoken_str(3));
  1450.           if (line.getnumtokens() > 4)
  1451.             cur_page->parms[3] = add_string(line.gettoken_str(4));
  1452.         }
  1453.         SCRIPT_MSG("DirText: \"%s\" \"%s\" \"%s\" \"%s\"\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4));
  1454.       }
  1455.     return PS_OK;
  1456. #else//NSIS_CONFIG_VISIBLE_SUPPORT
  1457.       ERROR_MSG("Error: %s specified, NSIS_CONFIG_VISIBLE_SUPPORT not defined.\n",  line.gettoken_str(0));
  1458.     return PS_ERROR;
  1459. #endif//!NSIS_CONFIG_VISIBLE_SUPPORT
  1460.     case TOK_DIRVAR:
  1461.     {
  1462.       if (cur_page_type != PAGE_DIRECTORY && cur_page_type != PAGE_UNINSTCONFIRM) {
  1463.         ERROR_MSG("Error: can't use DirVar outside of PageEx directory|uninstConfirm.\n");
  1464.         return PS_ERROR;
  1465.       }
  1466.       cur_page->parms[4] = GetUserVarIndex(line, 1) + 1;
  1467.       if (cur_page->parms[4] <= 0) PRINTHELP();
  1468.       SCRIPT_MSG("DirVar: %s\n", line.gettoken_str(1));
  1469.     }
  1470.     return PS_OK;
  1471.     case TOK_DIRVERIFY:
  1472.     {
  1473.       if (cur_page_type != PAGE_DIRECTORY) {
  1474.         ERROR_MSG("Error: can't use DirVerify outside of PageEx directory.\n");
  1475.         return PS_ERROR;
  1476.       }
  1477.       cur_page->flags &= ~PF_DIR_NO_BTN_DISABLE;
  1478.       int k = line.gettoken_enum(1,"auto\0leave\0");
  1479.       if (k == -1)
  1480.         PRINTHELP();
  1481.       if (k)
  1482.         cur_page->flags |= PF_DIR_NO_BTN_DISABLE;
  1483.       SCRIPT_MSG("DirVerify: %s\n", line.gettoken_str(1));
  1484.     }
  1485.     return PS_OK;
  1486.     case TOK_GETINSTDIRERROR:
  1487.       ent.which = EW_GETFLAG;
  1488.       ent.offsets[0] = GetUserVarIndex(line, 1);
  1489.       ent.offsets[1] = FLAG_OFFSET(instdir_error);
  1490.     return add_entry(&ent);
  1491. #ifdef NSIS_CONFIG_COMPONENTPAGE
  1492.     case TOK_COMPTEXT:
  1493.       {
  1494.         if (!cur_page) {
  1495.           if (SetInnerString(NLF_COMP_TEXT, line.gettoken_str(1)) == PS_WARNING)
  1496.             warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0));
  1497.           if (line.getnumtokens() > 2)
  1498.             SetInnerString(NLF_COMP_SUBTEXT1, line.gettoken_str(2));
  1499.           if (line.getnumtokens() > 3)
  1500.             SetInnerString(NLF_COMP_SUBTEXT2, line.gettoken_str(3));
  1501.         }
  1502.         else {
  1503.           if (cur_page_type != PAGE_COMPONENTS) {
  1504.             ERROR_MSG("Error: ComponentText can only be used inside PageEx components.\n");
  1505.             return PS_ERROR;
  1506.           }
  1507.           cur_page->parms[0] = add_string(line.gettoken_str(1));
  1508.           cur_page->parms[1] = add_string(line.gettoken_str(2));
  1509.           cur_page->parms[2] = add_string(line.gettoken_str(3));
  1510.           cur_page->parms[3] = cur_page->parms[1];
  1511.           cur_page->parms[4] = cur_page->parms[2];
  1512.         }
  1513.         SCRIPT_MSG("ComponentText: \"%s\" \"%s\" \"%s\"\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3));
  1514.       }
  1515.     return PS_OK;
  1516.     case TOK_INSTTYPE:
  1517.       {
  1518.         int x;
  1519.  
  1520.         if (!stricmp(line.gettoken_str(1),"/NOCUSTOM"))
  1521.         {
  1522.           build_header.flags|=CH_FLAGS_NO_CUSTOM;
  1523.           SCRIPT_MSG("InstType: disabling custom install type\n");
  1524.         }
  1525.         else if (!stricmp(line.gettoken_str(1),"/COMPONENTSONLYONCUSTOM"))
  1526.         {
  1527.           build_header.flags|=CH_FLAGS_COMP_ONLY_ON_CUSTOM;
  1528.           SCRIPT_MSG("InstType: making components viewable only on custom install type\n");
  1529.         }
  1530.         else if (!strnicmp(line.gettoken_str(1),"/CUSTOMSTRING=",14))
  1531.         {
  1532.           SCRIPT_MSG("InstType: setting custom text to: \"%s\"\n",line.gettoken_str(1)+14);
  1533.           if (SetInnerString(NLF_COMP_CUSTOM,line.gettoken_str(1)+14) == PS_WARNING)
  1534.             warning_fl("%s: specified multiple times, wasting space","InstType /CUSTOMSTRING");
  1535.         }
  1536.         else if (line.gettoken_str(1)[0]=='/')
  1537.         {
  1538.           PRINTHELP()
  1539.         }
  1540.         else
  1541.         {
  1542.           char *itname = line.gettoken_str(1);
  1543.  
  1544.           if (!strnicmp(itname, "un.", 3)) {
  1545.             set_uninstall_mode(1);
  1546.             itname += 3;
  1547.           }
  1548.  
  1549.           for (x = 0; x < NSIS_MAX_INST_TYPES && cur_header->install_types[x]; x ++);
  1550.           if (x == NSIS_MAX_INST_TYPES)
  1551.           {
  1552.             ERROR_MSG("InstType: no more than %d install types allowed. %d specified\n", NSIS_MAX_INST_TYPES, NSIS_MAX_INST_TYPES + 1);
  1553.             return PS_ERROR;
  1554.           }
  1555.           else
  1556.           {
  1557.             cur_header->install_types[x] = add_string(itname);
  1558.             SCRIPT_MSG("InstType: %s%d=\"%s\"\n", uninstall_mode ? "(uninstall) " : "", x+1, itname);
  1559.           }
  1560.  
  1561.           set_uninstall_mode(0);
  1562.         }
  1563.       }
  1564.     return PS_OK;
  1565. #else//NSIS_CONFIG_COMPONENTPAGE
  1566.     case TOK_COMPTEXT:
  1567.     case TOK_INSTTYPE:
  1568.       ERROR_MSG("Error: %s specified but NSIS_CONFIG_COMPONENTPAGE not defined\n",line.gettoken_str(0));
  1569.     return PS_ERROR;
  1570. #endif//!NSIS_CONFIG_COMPONENTPAGE
  1571. #ifdef NSIS_CONFIG_LICENSEPAGE
  1572.     case TOK_LICENSETEXT:
  1573.       {
  1574.         if (!cur_page) {
  1575.           if (SetInnerString(NLF_LICENSE_TEXT, line.gettoken_str(1)) == PS_WARNING)
  1576.             warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0));
  1577.           SetInnerString(NLF_LICENSE_TEXT_FSRB, line.gettoken_str(1));
  1578.           SetInnerString(NLF_LICENSE_TEXT_FSCB, line.gettoken_str(1));
  1579.           if (line.getnumtokens() > 2)
  1580.             SetInnerString(NLF_BTN_LICENSE, line.gettoken_str(2));
  1581.         }
  1582.         else {
  1583.           if (cur_page_type != PAGE_LICENSE) {
  1584.             ERROR_MSG("Error: LicenseText can only be used inside PageEx license.\n");
  1585.             return PS_ERROR;
  1586.           }
  1587.           cur_page->parms[0] = add_string(line.gettoken_str(1));
  1588.           cur_page->next = add_string(line.gettoken_str(2));
  1589.         }
  1590.         SCRIPT_MSG("LicenseText: \"%s\" \"%s\"\n",line.gettoken_str(1),line.gettoken_str(2));
  1591.       }
  1592.     return PS_OK;
  1593.     case TOK_LICENSEDATA:
  1594.       {
  1595.         int idx = 0;
  1596.         char *file = line.gettoken_str(1);
  1597.         char *data;
  1598.  
  1599.         if (file[0] == '$' && file[1] == '(')
  1600.         {
  1601.           char *cp = strdup(file+2);
  1602.           char *p = strchr(cp, ')');
  1603.           if (p && p[1] == 0) { // if string is only a language str identifier
  1604.             *p = 0;
  1605.             idx = DefineLangString(cp, 0);
  1606.           }
  1607.           free(cp);
  1608.           data = file;
  1609.         }
  1610.  
  1611.         if (!idx)
  1612.         {
  1613.           int datalen;
  1614.           FILE *fp=fopen(file,"rb");
  1615.           if (!fp)
  1616.           {
  1617.             ERROR_MSG("LicenseData: open failed \"%s\"\n",file);
  1618.             PRINTHELP()
  1619.           }
  1620.           fseek(fp,0,SEEK_END);
  1621.           datalen=ftell(fp);
  1622.           if (!datalen)
  1623.           {
  1624.             ERROR_MSG("LicenseData: empty license file \"%s\"\n",file);
  1625.             fclose(fp);
  1626.             return PS_ERROR;
  1627.           }
  1628.           rewind(fp);
  1629.           data=(char*)malloc(datalen+2);
  1630.           if (!data)
  1631.           {
  1632.             ERROR_MSG("Internal compiler error #12345: LicenseData malloc(%d) failed.\n", datalen+2);
  1633.             return PS_ERROR;
  1634.           }
  1635.           char *ldata=data+1;
  1636.           if (fread(ldata,1,datalen,fp) != datalen) {
  1637.             ERROR_MSG("LicenseData: can't read file.\n");
  1638.             fclose(fp);
  1639.             free(data);
  1640.             return PS_ERROR;
  1641.           }
  1642.           fclose(fp);
  1643.           ldata[datalen]=0;
  1644.           if (!strncmp(ldata,"{\\rtf",sizeof("{\\rtf")-1))
  1645.             *data = SF_RTF;
  1646.           else
  1647.             *data = SF_TEXT;
  1648.         }
  1649.  
  1650.         if (!cur_page) {
  1651.           if (SetInnerString(NLF_LICENSE_DATA,data) == PS_WARNING)
  1652.             warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0));
  1653.         }
  1654.         else {
  1655.           if (cur_page_type != PAGE_LICENSE) {
  1656.             ERROR_MSG("Error: LicenseData can only be used inside PageEx license.\n");
  1657.             return PS_ERROR;
  1658.           }
  1659.  
  1660.           cur_page->parms[1] = add_string(data, 0);
  1661.         }
  1662.  
  1663.         if (!idx)
  1664.           free(data);
  1665.  
  1666.         SCRIPT_MSG("LicenseData: \"%s\"\n",file);
  1667.       }
  1668.     return PS_OK;
  1669.     case TOK_LICENSEFORCESELECTION:
  1670.     {
  1671.       int k=line.gettoken_enum(1,"off\0checkbox\0radiobuttons\0");
  1672.       if (k == -1) PRINTHELP()
  1673.       if (k < line.getnumtokens() - 2) PRINTHELP()
  1674.  
  1675.       if (!cur_page) {
  1676.         switch (line.getnumtokens()) {
  1677.           case 4:
  1678.             SetInnerString(NLF_BTN_LICENSE_DISAGREE, line.gettoken_str(3));
  1679.           case 3:
  1680.             SetInnerString(NLF_BTN_LICENSE_AGREE, line.gettoken_str(2));
  1681.             break;
  1682.         }
  1683.  
  1684.         switch (k) {
  1685.           case 0:
  1686.             license_res_id = IDD_LICENSE;
  1687.             break;
  1688.           case 1:
  1689.             license_res_id = IDD_LICENSE_FSCB;
  1690.             break;
  1691.           case 2:
  1692.             license_res_id = IDD_LICENSE_FSRB;
  1693.             break;
  1694.         }
  1695.       }
  1696.       else {
  1697.         if (cur_page_type != PAGE_LICENSE) {
  1698.           ERROR_MSG("Error: LicenseForceSelection can only be used inside PageEx license.\n");
  1699.           return PS_ERROR;
  1700.         }
  1701.         switch (line.getnumtokens()) {
  1702.           case 4:
  1703.             cur_page->parms[3] = add_string(line.gettoken_str(3));
  1704.           case 3:
  1705.             cur_page->parms[2] = add_string(line.gettoken_str(2));
  1706.             break;
  1707.         }
  1708.  
  1709.         cur_page->flags &= ~(PF_LICENSE_FORCE_SELECTION | PF_LICENSE_NO_FORCE_SELECTION);
  1710.  
  1711.         switch (k) {
  1712.           case 0:
  1713.             cur_page->dlg_id = IDD_LICENSE;
  1714.             cur_page->flags |= PF_LICENSE_NO_FORCE_SELECTION;
  1715.             break;
  1716.           case 1:
  1717.             cur_page->dlg_id = IDD_LICENSE_FSCB;
  1718.             cur_page->flags |= PF_LICENSE_FORCE_SELECTION;
  1719.             break;
  1720.           case 2:
  1721.             cur_page->dlg_id = IDD_LICENSE_FSRB;
  1722.             cur_page->flags |= PF_LICENSE_FORCE_SELECTION;
  1723.             break;
  1724.         }
  1725.       }
  1726.  
  1727.       SCRIPT_MSG("LicenseForceSelection: %s \"%s\" \"%s\"\n", line.gettoken_str(1), line.gettoken_str(2), line.gettoken_str(3));
  1728.     }
  1729.     return PS_OK;
  1730.     case TOK_LICENSEBKCOLOR:
  1731.       {
  1732.         char *p = line.gettoken_str(1);
  1733.         if (!strcmpi(p,"/windows"))
  1734.         {
  1735.           build_header.license_bg=-COLOR_WINDOW;
  1736.           SCRIPT_MSG("LicenseBkColor: /windows\n");
  1737.         }
  1738.         else if (!strcmpi(p,"/grey") || !strcmpi(p,"/gray"))
  1739.         {
  1740.           build_header.license_bg=-COLOR_BTNFACE;
  1741.           SCRIPT_MSG("LicenseBkColor: /grey\n");
  1742.         }
  1743.         else
  1744.         {
  1745.         int v=strtoul(p,&p,16);
  1746.         build_header.license_bg=((v&0xff)<<16)|(v&0xff00)|((v&0xff0000)>>16);
  1747.         build_uninst.license_bg=build_header.license_bg;
  1748.         SCRIPT_MSG("LicenseBkColor: %06X\n",v);
  1749.       }
  1750.       }
  1751.     return PS_OK;
  1752. #else//!NSIS_CONFIG_LICENSEPAGE
  1753.     case TOK_LICENSETEXT:
  1754.     case TOK_LICENSEDATA:
  1755.     case TOK_LICENSEBKCOLOR:
  1756.       ERROR_MSG("Error: %s specified, NSIS_CONFIG_LICENSEPAGE not defined.\n",  line.gettoken_str(0));
  1757.     return PS_ERROR;
  1758. #endif//!NSIS_CONFIG_LICENSEPAGE
  1759. #ifdef NSIS_CONFIG_SILENT_SUPPORT
  1760.     case TOK_SILENTINST:
  1761.     {
  1762.       int k=line.gettoken_enum(1,"normal\0silent\0silentlog\0");
  1763.       if (k<0) PRINTHELP()
  1764. #ifndef NSIS_CONFIG_LOG
  1765.       if (k == 2)
  1766.       {
  1767.         ERROR_MSG("SilentInstall: silentlog specified, no log support compiled in (use NSIS_CONFIG_LOG)\n");
  1768.         return PS_ERROR;
  1769.       }
  1770. #endif//NSIS_CONFIG_LOG
  1771.       SCRIPT_MSG("SilentInstall: %s\n",line.gettoken_str(1));
  1772. #ifdef NSIS_CONFIG_LICENSEPAGE
  1773.       if (k && HasUserDefined(NLF_LICENSE_DATA))
  1774.       {
  1775.         warning_fl("SilentInstall: LicenseData already specified. wasting space");
  1776.       }
  1777.       if (k) {
  1778.         build_header.flags|=CH_FLAGS_SILENT;
  1779.         if (k == 2)
  1780.           build_header.flags|=CH_FLAGS_SILENT_LOG;
  1781.       }
  1782.       else {
  1783.         build_header.flags&=~CH_FLAGS_SILENT;
  1784.         build_header.flags&=~CH_FLAGS_SILENT_LOG;
  1785.       }
  1786. #endif//NSIS_CONFIG_LICENSEPAGE
  1787.     }
  1788.     return PS_OK;
  1789.     case TOK_SILENTUNINST:
  1790. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  1791.     {
  1792.       int k=line.gettoken_enum(1,"normal\0silent\0");
  1793.       if (k<0) PRINTHELP()
  1794.       if (k)
  1795.         build_uninst.flags|=CH_FLAGS_SILENT;
  1796.       else
  1797.         build_uninst.flags&=~CH_FLAGS_SILENT;
  1798.       SCRIPT_MSG("SilentUnInstall: %s\n",line.gettoken_str(1));
  1799.     }
  1800.     return PS_OK;
  1801. #else
  1802.       ERROR_MSG("Error: %s specified, NSIS_CONFIG_UNINSTALL_SUPPORT not defined.\n",  line.gettoken_str(0));
  1803.     return PS_ERROR;
  1804. #endif
  1805.     case TOK_IFSILENT:
  1806.       ent.which=EW_IFFLAG;
  1807.       if (process_jump(line,1,&ent.offsets[0]) ||
  1808.           process_jump(line,2,&ent.offsets[1])) PRINTHELP()
  1809.       ent.offsets[2]=FLAG_OFFSET(silent);
  1810.       ent.offsets[3]=~0;//new value mask - keep flag
  1811.       SCRIPT_MSG("IfSilent ?%s:%s\n",line.gettoken_str(1),line.gettoken_str(2));
  1812.     return add_entry(&ent);
  1813.     case TOK_SETSILENT:
  1814.     {
  1815.       ent.which=EW_SETFLAG;
  1816.       ent.offsets[0]=FLAG_OFFSET(silent);
  1817.       int k=line.gettoken_enum(1,"normal\0silent\0");
  1818.       if (k<0) PRINTHELP()
  1819.       ent.offsets[1]=add_intstring(k);
  1820.       SCRIPT_MSG("SetSilent: %s\n",line.gettoken_str(1));
  1821.     }
  1822.     return add_entry(&ent);
  1823. #else//!NSIS_CONFIG_SILENT_SUPPORT
  1824.     case TOK_SILENTINST:
  1825.     case TOK_SILENTUNINST:
  1826.     case TOK_IFSILENT:
  1827.     case TOK_SETSILENT:
  1828.       ERROR_MSG("Error: %s specified, NSIS_CONFIG_SILENT_SUPPORT not defined.\n",  line.gettoken_str(0));
  1829.     return PS_ERROR;
  1830. #endif//NSIS_CONFIG_SILENT_SUPPORT
  1831.     case TOK_OUTFILE:
  1832.       strncpy(build_output_filename,line.gettoken_str(1),1024-1);
  1833.       SCRIPT_MSG("OutFile: \"%s\"\n",build_output_filename);
  1834.     return PS_OK;
  1835.     case TOK_INSTDIR:
  1836.     {
  1837.       char *p = line.gettoken_str(1);
  1838.       if (build_header.install_directory_ptr)
  1839.       {
  1840.         warning_fl("%s: specified multiple times. wasting space",line.gettoken_str(0));
  1841.       }
  1842.       build_header.install_directory_ptr = add_string(p);
  1843.       build_header.install_directory_auto_append = 0;
  1844.       if (*p && *CharPrev(p, p + strlen(p)) != '\\')
  1845.       {
  1846.         p = build_strlist.get() + build_header.install_directory_ptr;
  1847.         char *p2 = p + strlen(p);
  1848.         while (p2 >= p && *CharPrev(p, p2) != '\\') p2--;;
  1849.         if (p2)
  1850.         {
  1851.           build_header.install_directory_auto_append = build_header.install_directory_ptr + (p2 - p);
  1852.         }
  1853.       }
  1854.       SCRIPT_MSG("InstallDir: \"%s\"\n",line.gettoken_str(1));
  1855.     }
  1856.     return PS_OK;
  1857.     case TOK_INSTALLDIRREGKEY: // InstallDirRegKey
  1858.       {
  1859.         if (build_header.install_reg_key_ptr)
  1860.         {
  1861.           warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0));
  1862.         }
  1863.         int k=line.gettoken_enum(1,rootkeys[0]);
  1864.         if (k == -1) k=line.gettoken_enum(1,rootkeys[1]);
  1865.         if (k == -1) PRINTHELP()
  1866.         build_header.install_reg_rootkey=(int)rootkey_tab[k];
  1867.         build_header.install_reg_key_ptr = add_string(line.gettoken_str(2),0);
  1868.         if (line.gettoken_str(2)[0] == '\\')
  1869.           warning_fl("%s: registry path name begins with \'\\\', may cause problems",line.gettoken_str(0));
  1870.         build_header.install_reg_value_ptr = add_string(line.gettoken_str(3),0);
  1871.         SCRIPT_MSG("InstallRegKey: \"%s\\%s\\%s\"\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3));
  1872.       }
  1873.     return PS_OK;
  1874.     case TOK_CRCCHECK:
  1875.       build_crcchk=line.gettoken_enum(1,"off\0on\0force\0");
  1876.       if (build_crcchk==-1) PRINTHELP()
  1877.       SCRIPT_MSG("CRCCheck: %s\n",line.gettoken_str(1));
  1878.     return PS_OK;
  1879.     case TOK_INSTPROGRESSFLAGS:
  1880.       {
  1881.         int x;
  1882.         int smooth=0;
  1883.         build_header.flags&=~CH_FLAGS_PROGRESS_COLORED;
  1884.         for (x = 1; x < line.getnumtokens(); x ++)
  1885.         {
  1886.           if (!stricmp(line.gettoken_str(x),"smooth")) smooth=1;
  1887.           else if (!stricmp(line.gettoken_str(x),"colored")) build_header.flags|=CH_FLAGS_PROGRESS_COLORED;
  1888.           else PRINTHELP()
  1889.         }
  1890.         try {
  1891.           init_res_editor();
  1892.  
  1893.           BYTE* dlg = res_editor->GetResource(RT_DIALOG, MAKEINTRESOURCE(IDD_INSTFILES), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
  1894.           if (!dlg) throw runtime_error("IDD_INSTFILES doesn't exist!");
  1895.           CDialogTemplate dt(dlg,uDefCodePage);
  1896.           free(dlg);
  1897.           DialogItemTemplate* progress = dt.GetItem(IDC_PROGRESS);
  1898.           if (!progress) {
  1899.             throw runtime_error("IDC_PROGRESS doesn't exist!");
  1900.           }
  1901.  
  1902.           if (smooth)
  1903.             progress->dwStyle |= PBS_SMOOTH;
  1904.           else
  1905.             progress->dwStyle &= ~PBS_SMOOTH;
  1906.  
  1907.           DWORD dwSize;
  1908.           dlg = dt.Save(dwSize);
  1909.           res_editor->UpdateResource(RT_DIALOG, MAKEINTRESOURCE(IDD_INSTFILES), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), dlg, dwSize);
  1910.           res_editor->FreeResource(dlg);
  1911.         }
  1912.         catch (exception& err) {
  1913.           ERROR_MSG("Error setting smooth progress bar: %s\n", err.what());
  1914.           return PS_ERROR;
  1915.         }
  1916.         SCRIPT_MSG("InstProgressFlags: smooth=%d, colored=%d\n",smooth,
  1917.           !!(build_header.flags&CH_FLAGS_PROGRESS_COLORED));
  1918.       }
  1919.     return PS_OK;
  1920.     case TOK_AUTOCLOSE:
  1921.       {
  1922.         int k=line.gettoken_enum(1,"false\0true\0");
  1923.         if (k == -1) PRINTHELP();
  1924.         if (k)
  1925.           build_header.flags|=CH_FLAGS_AUTO_CLOSE;
  1926.         else
  1927.           build_header.flags&=~CH_FLAGS_AUTO_CLOSE;
  1928.         SCRIPT_MSG("AutoCloseWindow: %s\n",k?"true":"false");
  1929.       }
  1930.     return PS_OK;
  1931.     case TOK_WINDOWICON:
  1932. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  1933.       disable_window_icon=line.gettoken_enum(1,"on\0off\0");
  1934.       if (disable_window_icon == -1) PRINTHELP();
  1935.       SCRIPT_MSG("WindowIcon: %s\n",line.gettoken_str(1));
  1936.     return PS_OK;
  1937. #else
  1938.     ERROR_MSG("Error: %s specified, NSIS_CONFIG_VISIBLE_SUPPORT not defined.\n",line.gettoken_str(0));
  1939.     return PS_ERROR;
  1940. #endif // NSIS_CONFIG_VISIBLE_SUPPORT
  1941.     case TOK_SHOWDETAILSUNINST:
  1942. #ifndef NSIS_CONFIG_UNINSTALL_SUPPORT
  1943.       ERROR_MSG("Error: ShowUninstDetails specified but NSIS_CONFIG_UNINSTALL_SUPPORT not defined\n");
  1944.       return PS_ERROR;
  1945. #endif
  1946.     case TOK_SHOWDETAILS:
  1947.       {
  1948.         int k=line.gettoken_enum(1,"hide\0show\0nevershow\0");
  1949.         if (k == -1) PRINTHELP()
  1950. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  1951.         if (which_token == TOK_SHOWDETAILSUNINST)
  1952.         {
  1953.           build_uninst.flags&=~(CH_FLAGS_DETAILS_NEVERSHOW|CH_FLAGS_DETAILS_SHOWDETAILS);
  1954.           if (k==1)
  1955.             build_uninst.flags|=CH_FLAGS_DETAILS_SHOWDETAILS;
  1956.           else if (k==2)
  1957.             build_uninst.flags|=CH_FLAGS_DETAILS_NEVERSHOW;
  1958.         }
  1959.         else
  1960. #endif
  1961.         {
  1962.           build_header.flags&=~(CH_FLAGS_DETAILS_NEVERSHOW|CH_FLAGS_DETAILS_SHOWDETAILS);
  1963.           if (k==1)
  1964.             build_header.flags|=CH_FLAGS_DETAILS_SHOWDETAILS;
  1965.           else if (k==2)
  1966.             build_header.flags|=CH_FLAGS_DETAILS_NEVERSHOW;
  1967.         }
  1968.         SCRIPT_MSG("%s: %s\n",line.gettoken_str(0),line.gettoken_str(1));
  1969.       }
  1970.     return PS_OK;
  1971.     case TOK_DIRSHOW:
  1972.       /*{
  1973.         int k=line.gettoken_enum(1,"show\0hide\0");
  1974.         if (k == -1) PRINTHELP();
  1975.         if (k)
  1976.           build_header.flags|=CH_FLAGS_DIR_NO_SHOW;
  1977.         else
  1978.           build_header.flags&=~CH_FLAGS_DIR_NO_SHOW;
  1979.         SCRIPT_MSG("DirShow: %s\n",k?"hide":"show");
  1980.       }*/
  1981.       ERROR_MSG("Error: DirShow doesn't currently work\n");
  1982.     return PS_ERROR;
  1983.     case TOK_ROOTDIRINST:
  1984.       {
  1985.         int k=line.gettoken_enum(1,"true\0false\0");
  1986.         if (k == -1) PRINTHELP();
  1987.         if (k)
  1988.           build_header.flags|=CH_FLAGS_NO_ROOT_DIR;
  1989.         else
  1990.           build_header.flags&=~CH_FLAGS_NO_ROOT_DIR;
  1991.         SCRIPT_MSG("AllowRootDirInstall: %s\n",k?"false":"true");
  1992.       }
  1993.     return PS_OK;
  1994.     case TOK_BGGRADIENT:
  1995. #ifndef NSIS_SUPPORT_BGBG
  1996.       ERROR_MSG("Error: BGGradient specified but NSIS_SUPPORT_BGBG not defined\n");
  1997.       return PS_ERROR;
  1998. #else//NSIS_SUPPORT_BGBG
  1999.       if (line.getnumtokens()==1)
  2000.       {
  2001.         SCRIPT_MSG("BGGradient: default colors\n");
  2002.         build_header.bg_color1=0;
  2003.         build_header.bg_color2=RGB(0,0,255);
  2004.       }
  2005.       else if (!stricmp(line.gettoken_str(1),"off"))
  2006.       {
  2007.         build_header.bg_color1=build_header.bg_color2=-1;
  2008.         SCRIPT_MSG("BGGradient: off\n");
  2009.         if (line.getnumtokens()>2) PRINTHELP()
  2010.       }
  2011.       else
  2012.       {
  2013.         char *p = line.gettoken_str(1);
  2014.         int v1,v2,v3=-1;
  2015.         v1=strtoul(p,&p,16);
  2016.         build_header.bg_color1=((v1&0xff)<<16)|(v1&0xff00)|((v1&0xff0000)>>16);
  2017.         p=line.gettoken_str(2);
  2018.         v2=strtoul(p,&p,16);
  2019.         build_header.bg_color2=((v2&0xff)<<16)|(v2&0xff00)|((v2&0xff0000)>>16);
  2020.  
  2021.         p=line.gettoken_str(3);
  2022.         if (*p)
  2023.         {
  2024.           if (!stricmp(p,"notext")) build_header.bg_textcolor=-1;
  2025.           else
  2026.           {
  2027.             v3=strtoul(p,&p,16);
  2028.             build_header.bg_textcolor=((v3&0xff)<<16)|(v3&0xff00)|((v3&0xff0000)>>16);
  2029.           }
  2030.         }
  2031.  
  2032.         SCRIPT_MSG("BGGradient: 0x%06X->0x%06X (text=0x%06X)\n",v1,v2,v3);
  2033.       }
  2034.  
  2035. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  2036.       build_uninst.bg_color1=build_header.bg_color1;
  2037.       build_uninst.bg_color2=build_header.bg_color2;
  2038.       build_uninst.bg_textcolor=build_header.bg_textcolor;
  2039. #endif//NSIS_CONFIG_UNINSTALL_SUPPORT
  2040. #endif//NSIS_SUPPORT_BGBG
  2041.     return PS_OK;
  2042. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  2043.     case TOK_INSTCOLORS:
  2044.     {
  2045.       char *p = line.gettoken_str(1);
  2046.       if (p[0]=='/')
  2047.       {
  2048.         if (stricmp(p,"/windows") || line.getnumtokens()!=2) PRINTHELP()
  2049.         build_header.lb_fg=build_header.lb_bg=-1;
  2050.         SCRIPT_MSG("InstallColors: windows default colors\n");
  2051.       }
  2052.       else
  2053.       {
  2054.         int v1,v2;
  2055.         if (line.getnumtokens()!=3) PRINTHELP()
  2056.         v1=strtoul(p,&p,16);
  2057.         build_header.lb_fg=((v1&0xff)<<16)|(v1&0xff00)|((v1&0xff0000)>>16);
  2058.         p=line.gettoken_str(2);
  2059.         v2=strtoul(p,&p,16);
  2060.         build_header.lb_bg=((v2&0xff)<<16)|(v2&0xff00)|((v2&0xff0000)>>16);
  2061.         SCRIPT_MSG("InstallColors: fg=%06X bg=%06X\n",v1,v2);
  2062.       }
  2063.  
  2064. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  2065.       build_uninst.lb_fg=build_header.lb_fg;
  2066.       build_uninst.lb_bg=build_header.lb_bg;
  2067. #endif
  2068.     }
  2069.     return PS_OK;
  2070.     case TOK_XPSTYLE:
  2071.       try {
  2072.         int k=line.gettoken_enum(1,"on\0off\0");
  2073.         if (k == -1) PRINTHELP()
  2074.         SCRIPT_MSG("XPStyle: %s\n", line.gettoken_str(1));
  2075.         init_res_editor();
  2076.         char* szXPManifest = k ? 0 : "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\"><assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"X86\" name=\"Nullsoft.NSIS.exehead\" type=\"win32\"/><description>Nullsoft Install System v2.0</description><dependency><dependentAssembly><assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"X86\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\" /></dependentAssembly></dependency></assembly>";
  2077.         res_editor->UpdateResource(MAKEINTRESOURCE(24), MAKEINTRESOURCE(1), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (unsigned char*)szXPManifest, k ? 0 : lstrlen(szXPManifest));
  2078.       }
  2079.       catch (exception& err) {
  2080.         ERROR_MSG("Error while adding XP style: %s\n", err.what());
  2081.         return PS_ERROR;
  2082.       }
  2083.     return PS_OK;
  2084.     case TOK_CHANGEUI:
  2085.       try {
  2086.         DWORD dwSize;
  2087.         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");
  2088.         if (k<0) PRINTHELP();
  2089.  
  2090.         HINSTANCE hUIFile = LoadLibraryEx(line.gettoken_str(2), 0, LOAD_LIBRARY_AS_DATAFILE);
  2091.         if (!hUIFile) {
  2092.           ERROR_MSG("Error: Can't find \"%s\" in \"%s\"!\n", line.gettoken_str(1), line.gettoken_str(2));
  2093.           return PS_ERROR;
  2094.         }
  2095.  
  2096.         init_res_editor();
  2097.  
  2098.         // Search for required items
  2099.         #define SEARCH(x) if (!UIDlg.GetItem(x)) {ERROR_MSG("Error: Can't find %s (%u) in the custom UI!\n", #x, x);return PS_ERROR;}
  2100.         #define SAVE(x) dwSize = UIDlg.GetSize(); res_editor->UpdateResource(RT_DIALOG, x, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), dlg, dwSize);
  2101.  
  2102.         BYTE* dlg = 0;
  2103.  
  2104.         if (k == 0 || k == 1) {
  2105.           dlg = get_dlg(hUIFile, IDD_LICENSE, line.gettoken_str(2));
  2106.           if (!dlg) return PS_ERROR;
  2107.           CDialogTemplate UIDlg(dlg,uDefCodePage);
  2108.           SEARCH(IDC_EDIT1);
  2109.           SAVE(IDD_LICENSE);
  2110.         }
  2111.  
  2112.         if (k == 0 || k == 2) {
  2113.           dlg = get_dlg(hUIFile, IDD_DIR, line.gettoken_str(2));
  2114.           if (!dlg) return PS_ERROR;
  2115.           CDialogTemplate UIDlg(dlg,uDefCodePage);
  2116.           SEARCH(IDC_DIR);
  2117.           SEARCH(IDC_BROWSE);
  2118. #ifdef NSIS_CONFIG_LOG
  2119.           SEARCH(IDC_CHECK1);
  2120. #endif
  2121.           SAVE(IDD_DIR);
  2122.         }
  2123.  
  2124.         if (k == 0 || k == 3) {
  2125.           dlg = get_dlg(hUIFile, IDD_SELCOM, line.gettoken_str(2));
  2126.           if (!dlg) return PS_ERROR;
  2127.           CDialogTemplate UIDlg(dlg,uDefCodePage);
  2128.           SEARCH(IDC_TREE1);
  2129.           SEARCH(IDC_COMBO1);
  2130.           SAVE(IDD_SELCOM);
  2131.         }
  2132.  
  2133.         if (k == 0 || k == 4) {
  2134.           dlg = get_dlg(hUIFile, IDD_INST, line.gettoken_str(2));
  2135.           if (!dlg) return PS_ERROR;
  2136.           CDialogTemplate UIDlg(dlg,uDefCodePage);
  2137.           SEARCH(IDC_BACK);
  2138.           SEARCH(IDC_CHILDRECT);
  2139.           SEARCH(IDC_VERSTR);
  2140.           SEARCH(IDOK);
  2141.           SEARCH(IDCANCEL);
  2142.  
  2143.           // Search for bitmap holder (default for SetBrandingImage)
  2144.           branding_image_found = false;
  2145.           DialogItemTemplate* dlgItem = 0;
  2146.           for (int i = 0; dlgItem = UIDlg.GetItemByIdx(i); i++) {
  2147.             if (IS_INTRESOURCE(dlgItem->szClass)) {
  2148.               if (dlgItem->szClass == MAKEINTRESOURCE(0x0082)) {
  2149.                 if ((dlgItem->dwStyle & SS_BITMAP) == SS_BITMAP) {
  2150.                   branding_image_found = true;
  2151.                   branding_image_id = dlgItem->wId;
  2152.                   break;
  2153.                 }
  2154.               }
  2155.             }
  2156.           }
  2157.  
  2158.           SAVE(IDD_INST);
  2159.         }
  2160.  
  2161.         if (k == 0 || k == 5) {
  2162.           dlg = get_dlg(hUIFile, IDD_INSTFILES, line.gettoken_str(2));
  2163.           if (!dlg) return PS_ERROR;
  2164.           CDialogTemplate UIDlg(dlg,uDefCodePage);
  2165.           SEARCH(IDC_LIST1);
  2166.           SEARCH(IDC_PROGRESS);
  2167.           SEARCH(IDC_SHOWDETAILS);
  2168.           SAVE(IDD_INSTFILES);
  2169.         }
  2170.  
  2171.         if (k == 0 || k == 6) {
  2172.           dlg = get_dlg(hUIFile, IDD_UNINST, line.gettoken_str(2));
  2173.           if (!dlg) return PS_ERROR;
  2174.           CDialogTemplate UIDlg(dlg,uDefCodePage);
  2175.           SEARCH(IDC_EDIT1);
  2176.           SAVE(IDD_UNINST);
  2177.         }
  2178.  
  2179.         if (k == 0 || k == 7) {
  2180.           dlg = get_dlg(hUIFile, IDD_VERIFY, line.gettoken_str(2));
  2181.           if (!dlg) return PS_ERROR;
  2182.           CDialogTemplate UIDlg(dlg,uDefCodePage);
  2183.           SEARCH(IDC_STR);
  2184.           // No RTL here, pure English goes here.
  2185.           //SAVE(IDD_VERIFY);
  2186.           res_editor->UpdateResource(RT_DIALOG, IDD_VERIFY, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), dlg, UIDlg.GetSize());
  2187.         }
  2188.  
  2189.         if (k == 0 || k == 8) {
  2190.           dlg = get_dlg(hUIFile, IDD_LICENSE_FSRB, line.gettoken_str(2));
  2191.           if (!dlg) return PS_ERROR;
  2192.           CDialogTemplate UIDlg(dlg,uDefCodePage);
  2193.           SEARCH(IDC_EDIT1);
  2194.           SEARCH(IDC_LICENSEAGREE);
  2195.           SEARCH(IDC_LICENSEDISAGREE);
  2196.           SAVE(IDD_LICENSE_FSRB);
  2197.         }
  2198.  
  2199.         if (k == 0 || k == 9) {
  2200.           dlg = get_dlg(hUIFile, IDD_LICENSE_FSCB, line.gettoken_str(2));
  2201.           if (!dlg) return PS_ERROR;
  2202.           CDialogTemplate UIDlg(dlg,uDefCodePage);
  2203.           SEARCH(IDC_EDIT1);
  2204.           SEARCH(IDC_LICENSEAGREE);
  2205.           SAVE(IDD_LICENSE_FSCB);
  2206.         }
  2207.  
  2208.         if (!FreeLibrary(hUIFile)) {
  2209.           ERROR_MSG("can't free library!\n");
  2210.         }
  2211.  
  2212.         SCRIPT_MSG("ChangeUI: %s %s%s\n", line.gettoken_str(1), line.gettoken_str(2), branding_image_found?" (branding image holder found)":"");
  2213.       }
  2214.       catch (exception& err) {
  2215.         ERROR_MSG("Error while changing UI: %s\n", err.what());
  2216.         return PS_ERROR;
  2217.       }
  2218.     return PS_OK;
  2219.     case TOK_ADDBRANDINGIMAGE:
  2220.       try {
  2221.         int k=line.gettoken_enum(1,"top\0left\0bottom\0right\0");
  2222.         int wh=line.gettoken_int(2);
  2223.         if (k == -1) PRINTHELP();
  2224.         int padding = 2;
  2225.         if (line.getnumtokens() == 4)
  2226.           padding = line.gettoken_int(3);
  2227.  
  2228.         init_res_editor();
  2229.         BYTE* dlg = res_editor->GetResource(RT_DIALOG, MAKEINTRESOURCE(IDD_INST), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
  2230.  
  2231.         CDialogTemplate dt(dlg,uDefCodePage);
  2232.         delete [] dlg;
  2233.  
  2234.         DialogItemTemplate *childRect = dt.GetItem(IDC_CHILDRECT);
  2235.         DialogItemTemplate brandingCtl = {0,};
  2236.  
  2237.         brandingCtl.dwStyle = SS_BITMAP | WS_CHILD | WS_VISIBLE;
  2238.         brandingCtl.sX = padding;
  2239.         brandingCtl.sY = padding;
  2240.         brandingCtl.szClass = MAKEINTRESOURCE(0x0082);
  2241.         brandingCtl.szTitle = "";
  2242.         brandingCtl.wId = IDC_BRANDIMAGE;
  2243.  
  2244.         brandingCtl.sHeight = wh;
  2245.         brandingCtl.sWidth = wh;
  2246.         dt.PixelsToDlgUnits(brandingCtl.sWidth, brandingCtl.sHeight);
  2247.         if (k%2) {
  2248.           // left (1) / right (3)
  2249.  
  2250.           if (k & 2) // right
  2251.             brandingCtl.sX += dt.GetWidth();
  2252.           else // left
  2253.             dt.MoveAll(brandingCtl.sWidth + (padding * 2), 0);
  2254.           
  2255.           dt.Resize(brandingCtl.sWidth + (padding * 2), 0);
  2256.  
  2257.           brandingCtl.sHeight = dt.GetHeight() - (padding * 2);
  2258.         }
  2259.         else {
  2260.           // top (0) / bottom (2)
  2261.  
  2262.           if (k & 2) // bottom
  2263.             brandingCtl.sY += dt.GetHeight();
  2264.           else // top
  2265.             dt.MoveAll(0, brandingCtl.sHeight + (padding * 2));
  2266.  
  2267.           dt.Resize(0, brandingCtl.sHeight + (padding * 2));
  2268.  
  2269.           brandingCtl.sWidth = dt.GetWidth() - (padding * 2);
  2270.         }
  2271.  
  2272.         dt.AddItem(brandingCtl);
  2273.  
  2274.         DWORD dwDlgSize;
  2275.         dlg = dt.Save(dwDlgSize);
  2276.  
  2277.         res_editor->UpdateResource(RT_DIALOG, IDD_INST, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), dlg, dwDlgSize);
  2278.  
  2279.         res_editor->FreeResource(dlg);
  2280.  
  2281.         dt.DlgUnitsToPixels(brandingCtl.sWidth, brandingCtl.sHeight);
  2282.         SCRIPT_MSG("AddBrandingImage: %s %ux%u\n", line.gettoken_str(1), brandingCtl.sWidth, brandingCtl.sHeight);
  2283.  
  2284.         branding_image_found = true;
  2285.         branding_image_id = IDC_BRANDIMAGE;
  2286.       }
  2287.       catch (exception& err) {
  2288.         ERROR_MSG("Error while adding image branding support: %s\n", err.what());
  2289.         return PS_ERROR;
  2290.       }
  2291.     return PS_OK;
  2292.     case TOK_SETFONT:
  2293.     {
  2294.       if (!strnicmp(line.gettoken_str(1), "/LANG=", 6))
  2295.       {
  2296.         LANGID lang_id = atoi(line.gettoken_str(1) + 6);
  2297.         LanguageTable *table = GetLangTable(lang_id);
  2298.         table->nlf.m_szFont = (char*)malloc(strlen(line.gettoken_str(2))+1);
  2299.         strcpy(table->nlf.m_szFont, line.gettoken_str(2));
  2300.         table->nlf.m_iFontSize = line.gettoken_int(3);
  2301.  
  2302.         SCRIPT_MSG("SetFont: lang=%d \"%s\" %s\n", lang_id, line.gettoken_str(2), line.gettoken_str(3));
  2303.       }
  2304.       else
  2305.       {
  2306.         strncpy(build_font, line.gettoken_str(1), sizeof(build_font));
  2307.         build_font_size = line.gettoken_int(2);
  2308.  
  2309.         SCRIPT_MSG("SetFont: \"%s\" %s\n", line.gettoken_str(1), line.gettoken_str(2));
  2310.       }
  2311.     }
  2312.     return PS_OK;
  2313. #else
  2314.   case TOK_INSTCOLORS:
  2315.   case TOK_XPSTYLE:
  2316.   case TOK_CHANGEUI:
  2317.   case TOK_ADDBRANDINGIMAGE:
  2318.   case TOK_SETFONT:
  2319.     ERROR_MSG("Error: %s specified, NSIS_CONFIG_VISIBLE_SUPPORT not defined.\n",line.gettoken_str(0));
  2320.   return PS_ERROR;
  2321. #endif// NSIS_CONFIG_VISIBLE_SUPPORT
  2322.     // Ability to change compression methods from within the script
  2323.     case TOK_SETCOMPRESSOR:
  2324. #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
  2325.     {
  2326.       if (build_compressor_set) {
  2327.         ERROR_MSG("Error: can't change compressor after data already got compressed or header already changed!\n");
  2328.         return PS_ERROR;
  2329.       }
  2330.       if (!build_compressor_final)
  2331.       {
  2332.         int a = 1;
  2333.         if (!strcmpi(line.gettoken_str(1),"/FINAL"))
  2334.         {
  2335.           build_compressor_final = true;
  2336.           a++;
  2337.         }
  2338.         else if (line.getnumtokens() == 3)
  2339.         {
  2340.           ERROR_MSG("%s expects 2 parameters, got 3.\n",line.gettoken_str(0));
  2341.           PRINTHELP();
  2342.         }
  2343.         int k=line.gettoken_enum(a,"zlib\0bzip2\0lzma\0");
  2344.         switch (k) {
  2345.           case 0: // JF> should handle the state of going from bzip2 back to zlib:
  2346.             compressor = &zlib_compressor;
  2347.             free(header_data_new);
  2348.             header_data_new=(unsigned char*)malloc(zlib_exeheader_size);
  2349.             exeheader_size_new=zlib_exeheader_size;
  2350.             exeheader_size=zlib_exeheader_size;
  2351.  
  2352.             if (!header_data_new)
  2353.             {
  2354.               ERROR_MSG("Internal compiler error #12345: malloc(%d) failed\n",exeheader_size_new);
  2355.               extern void quit(); quit();
  2356.             }
  2357.  
  2358.             memcpy(header_data_new,zlib_header_data,zlib_exeheader_size);
  2359. #ifdef NSIS_ZLIB_COMPRESS_WHOLE
  2360.             build_compress_whole=true;
  2361. #else
  2362.             build_compress_whole=false;
  2363. #endif
  2364.           break;
  2365.           case 1:
  2366.             compressor=&bzip2_compressor;
  2367.             free(header_data_new);
  2368.             header_data_new=(unsigned char*)malloc(bzip2_exeheader_size);
  2369.             exeheader_size_new=bzip2_exeheader_size;
  2370.             exeheader_size=bzip2_exeheader_size;
  2371.  
  2372.             if (!header_data_new)
  2373.             {
  2374.               ERROR_MSG("Internal compiler error #12345: malloc(%d) failed\n",exeheader_size_new);
  2375.               extern void quit(); quit();
  2376.             }
  2377.  
  2378.             memcpy(header_data_new,bzip2_header_data,bzip2_exeheader_size);
  2379. #ifdef NSIS_BZIP2_COMPRESS_WHOLE
  2380.             build_compress_whole=true;
  2381. #else
  2382.             build_compress_whole=false;
  2383. #endif
  2384.             break;
  2385.           case 2:
  2386.             compressor = &lzma_compressor;
  2387.             free(header_data_new);
  2388.             header_data_new=(unsigned char*)malloc(lzma_exeheader_size);
  2389.             exeheader_size_new=lzma_exeheader_size;
  2390.             exeheader_size=lzma_exeheader_size;
  2391.  
  2392.             if (!header_data_new)
  2393.             {
  2394.               ERROR_MSG("Internal compiler error #12345: malloc(%d) failed\n",exeheader_size_new);
  2395.               extern void quit(); quit();
  2396.             }
  2397.  
  2398.             memcpy(header_data_new, lzma_header_data, lzma_exeheader_size);
  2399. #ifdef NSIS_LZMA_COMPRESS_WHOLE
  2400.             build_compress_whole=true;
  2401. #else
  2402.             build_compress_whole=false;
  2403. #endif
  2404.           break;
  2405.           default:
  2406.             PRINTHELP();
  2407.         }
  2408.         SCRIPT_MSG("SetCompressor: %s%s\n", build_compressor_final? "/FINAL " : "", line.gettoken_str(a));
  2409.       }
  2410.       else
  2411.       {
  2412.         warning_fl("SetCompressor ignored due to previous call with the /FINAL switch");
  2413.       }
  2414.     }
  2415.     return PS_OK;
  2416. #else//NSIS_CONFIG_COMPRESSION_SUPPORT
  2417.       ERROR_MSG("Error: %s specified, NSIS_CONFIG_COMPRESSION_SUPPORT not defined.\n",  line.gettoken_str(0));
  2418.     return PS_ERROR;
  2419. #endif//NSIS_CONFIG_COMPRESSION_SUPPORT
  2420.     case TOK_LOADNLF:
  2421.     {
  2422.       SCRIPT_MSG("LoadLanguageFile: %s\n", line.gettoken_str(1));
  2423.  
  2424.       LanguageTable *table = LoadLangFile(line.gettoken_str(1));
  2425.  
  2426.       if (!table)
  2427.         return PS_ERROR;
  2428.  
  2429.       if (!defcodepage_set)
  2430.       {
  2431.         uDefCodePage = table->nlf.m_uCodePage;
  2432.         defcodepage_set = true;
  2433.       }
  2434.  
  2435.       last_used_lang = table->lang_id;
  2436.       // define LANG_LangName as "####" (lang id)
  2437.       // for example ${LANG_ENGLISH} = 1033
  2438.       char lang_id[16];
  2439.       char lang_name[1024];
  2440.       wsprintf(lang_name, "LANG_%s", table->nlf.m_szName);
  2441.       wsprintf(lang_id, "%u", table->lang_id);
  2442.       definedlist.add(lang_name, lang_id);
  2443.     }
  2444.     return PS_OK;
  2445.  
  2446.     // preprocessor-ish (ifdef/ifndef/else/endif are handled one step out from here)
  2447.     ///////////////////////////////////////////////////////////////////////////////
  2448.     case TOK_P_DEFINE:
  2449.       if (definedlist.add(line.gettoken_str(1),line.gettoken_str(2)))
  2450.       {
  2451.         ERROR_MSG("!define: \"%s\" already defined!\n",line.gettoken_str(1));
  2452.         return PS_ERROR;
  2453.       }
  2454.       SCRIPT_MSG("!define: \"%s\"=\"%s\"\n",line.gettoken_str(1),line.gettoken_str(2));
  2455.     return PS_OK;
  2456.     case TOK_P_UNDEF:
  2457.       if (definedlist.del(line.gettoken_str(1)))
  2458.       {
  2459.         ERROR_MSG("!undef: \"%s\" not defined!\n",line.gettoken_str(1));
  2460.         return PS_ERROR;
  2461.       }
  2462.       SCRIPT_MSG("!undef: \"%s\"\n",line.gettoken_str(1));
  2463.     return PS_OK;
  2464.     case TOK_P_PACKEXEHEADER:
  2465.       strncpy(build_packname,line.gettoken_str(1),sizeof(build_packname)-1);
  2466.       strncpy(build_packcmd,line.gettoken_str(2),sizeof(build_packcmd)-1);
  2467.       SCRIPT_MSG("!packhdr: filename=\"%s\", command=\"%s\"\n",
  2468.         build_packname, build_packcmd);
  2469.     return PS_OK;
  2470.     case TOK_P_SYSTEMEXEC:
  2471.       {
  2472.         char *exec=line.gettoken_str(1);
  2473.         int comp=line.gettoken_enum(2,"<\0>\0<>\0=\0ignore\0");
  2474.         if (line.getnumtokens() == 2) comp = 4;
  2475.         if (comp == -1 && line.getnumtokens() == 3) comp=4;
  2476.         if (comp == -1) PRINTHELP()
  2477.         int success=0;
  2478.         int cmpv=line.gettoken_int(3,&success);
  2479.         if (!success && comp != 4) PRINTHELP()
  2480.         SCRIPT_MSG("!system: \"%s\"\n",exec);
  2481.         int ret=system(exec);
  2482.         if (comp == 0 && ret < cmpv);
  2483.         else if (comp == 1 && ret > cmpv);
  2484.         else if (comp == 2 && ret != cmpv);
  2485.         else if (comp == 3 && ret == cmpv);
  2486.         else if (comp == 4);
  2487.         else
  2488.         {
  2489.           ERROR_MSG("!system: returned %d, aborting\n",ret);
  2490.           return PS_ERROR;
  2491.         }
  2492.         SCRIPT_MSG("!system: returned %d\n",ret);
  2493.       }
  2494.     return PS_OK;
  2495.     case TOK_P_ADDINCLUDEDIR:
  2496.       include_dirs.add(line.gettoken_str(1),0);
  2497.     return PS_OK;
  2498.     case TOK_P_INCLUDE:
  2499.       {
  2500.         WIN32_FIND_DATA fd;
  2501.         char *f = line.gettoken_str(1);
  2502.         unsigned int malloced = sizeof(fd.cFileName) + strlen(f) + 1;
  2503.         char *incfile = (char *) malloc(malloced);
  2504.  
  2505.         int included = 0;
  2506.  
  2507.         strcpy(incfile, f);
  2508.         char *slash = strrchr(incfile, '\\');
  2509.  
  2510.         HANDLE search = FindFirstFile(f, &fd);
  2511.         if (search != INVALID_HANDLE_VALUE)
  2512.         {
  2513.           do
  2514.           {
  2515.             if (slash)
  2516.               slash[1] = 0;
  2517.             else
  2518.               incfile[0] = 0;
  2519.             strcat(incfile, fd.cFileName);
  2520.             if (includeScript(incfile) != PS_OK)
  2521.               return PS_ERROR;
  2522.             included++;
  2523.           }
  2524.           while (FindNextFile(search, &fd));
  2525.           FindClose(search);
  2526.         }
  2527.         else
  2528.         {
  2529.           char *dir = include_dirs.get();
  2530.           int dirs = include_dirs.getnum();
  2531.  
  2532.           for (int i = 0; i < dirs; i++) {
  2533.             if (malloced < strlen(f) + strlen(dir) + 1)
  2534.             {
  2535.               free(incfile);
  2536.               malloced += strlen(dir);
  2537.               incfile = (char *) malloc(malloced);
  2538.             }
  2539.             strcpy(incfile, dir);
  2540.             if (*f != '\\')
  2541.               strcat(incfile, "\\");
  2542.             strcat(incfile, f);
  2543.             slash = strrchr(incfile, '\\');
  2544.             
  2545.             search = FindFirstFile(incfile, &fd);
  2546.             if (search != INVALID_HANDLE_VALUE)
  2547.             {
  2548.               do
  2549.               {
  2550.                 if (slash)
  2551.                   slash[1] = 0;
  2552.                 else
  2553.                   incfile[0] = 0;
  2554.                 strcat(incfile, fd.cFileName);
  2555.                 if (includeScript(incfile) != PS_OK)
  2556.                   return PS_ERROR;
  2557.                 included++;
  2558.               }
  2559.               while (FindNextFile(search, &fd));
  2560.               FindClose(search);
  2561.               break;
  2562.             }
  2563.             else
  2564.             {
  2565.               dir += strlen(dir) + 1;
  2566.             }
  2567.           }
  2568.         }
  2569.  
  2570.         free(incfile);
  2571.  
  2572.         if (!included)
  2573.         {
  2574.           ERROR_MSG("!include: could not find: \"%s\"\n",f);
  2575.           return PS_ERROR;
  2576.         }
  2577.       }
  2578.     return PS_OK;
  2579.     case TOK_P_CD:
  2580.       if (!line.gettoken_str(1)[0] || !SetCurrentDirectory(line.gettoken_str(1)))
  2581.       {
  2582.         ERROR_MSG("!cd: error changing to: \"%s\"\n",line.gettoken_str(1));
  2583.         return PS_ERROR;
  2584.       }
  2585.     return PS_OK;
  2586.     case TOK_P_ERROR:
  2587.       ERROR_MSG("!error: %s\n",line.gettoken_str(1));
  2588.     return PS_ERROR;
  2589.     case TOK_P_WARNING:
  2590.       warning_fl("!warning: %s\n",line.gettoken_str(1));
  2591.     return PS_OK;
  2592.     case TOK_P_ECHO:
  2593.       SCRIPT_MSG("%s (%s:%d)\n", line.gettoken_str(1),curfilename,linecnt);
  2594.     return PS_OK;
  2595.  
  2596.     case TOK_P_VERBOSE:
  2597.     {
  2598.       extern int g_display_errors;
  2599.       int k=line.gettoken_enum(1,"push\0pop\0");
  2600.       int v;
  2601.       if (k < 0)
  2602.         // just set
  2603.         v=line.gettoken_int(1);
  2604.       else
  2605.       {
  2606.         if (k)
  2607.         {
  2608.           // pop
  2609.           int l=verbose_stack.getlen();
  2610.           if (l)
  2611.           {
  2612.             v=((int*)verbose_stack.get())[(l/sizeof(int))-1];
  2613.             verbose_stack.resize(l-sizeof(int));
  2614.           }
  2615.           else
  2616.             return PS_OK;
  2617.         }
  2618.         else
  2619.         {
  2620.           // push
  2621.           v=0;
  2622.           if (display_errors)
  2623.           {
  2624.             v++;
  2625.             if (display_warnings)
  2626.             {
  2627.               v++;
  2628.               if (display_info)
  2629.               {
  2630.                 v++;
  2631.                 if (display_script)
  2632.                 {
  2633.                   v++;
  2634.                 }
  2635.               }
  2636.             }
  2637.           }
  2638.           verbose_stack.add(&v,sizeof(int));
  2639.           return PS_OK;
  2640.         }
  2641.       }
  2642.       display_script=v>3;
  2643.       display_info=v>2;
  2644.       display_warnings=v>1;
  2645.       display_errors=v>0;
  2646.       g_display_errors=display_errors;
  2647.     }
  2648.     return PS_OK;
  2649.  
  2650.     case TOK_UNINSTALLEXENAME: PRINTHELP()
  2651.  
  2652.  
  2653. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  2654.     case TOK_UNINSTCAPTION:
  2655.       {
  2656.         if (SetInnerString(NLF_UCAPTION,line.gettoken_str(1)) == PS_WARNING)
  2657.           warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0));
  2658.         SCRIPT_MSG("UninstCaption: \"%s\"\n",line.gettoken_str(1));
  2659.       }
  2660.     return PS_OK;
  2661.     case TOK_UNINSTICON:
  2662.       SCRIPT_MSG("UninstallIcon: \"%s\"\n",line.gettoken_str(1));
  2663.       try {
  2664.         free(m_unicon_data);
  2665.         m_unicon_data = generate_uninstall_icon_data(line.gettoken_str(1));
  2666.         if (!m_unicon_data) {
  2667.           ERROR_MSG("Error: File doesn't exist or is an invalid icon file\n");
  2668.           return PS_ERROR;
  2669.         }
  2670.       }
  2671.       catch (exception& err) {
  2672.         ERROR_MSG("Error while replacing icon: %s\n", err.what());
  2673.         return PS_ERROR;
  2674.       }
  2675.     return PS_OK;
  2676.     case TOK_UNINSTTEXT:
  2677.       {
  2678.         if (!cur_page) {
  2679.           if (SetInnerString(NLF_UNINST_TEXT, line.gettoken_str(1)) == PS_WARNING)
  2680.             warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0));
  2681.           SetInnerString(NLF_UNINST_SUBTEXT, line.gettoken_str(2));
  2682.         }
  2683.         else {
  2684.           if (cur_page_type != PAGE_UNINSTCONFIRM) {
  2685.             ERROR_MSG("Error: UninstallText can only be used inside PageEx uninstConfirm.\n");
  2686.             return PS_ERROR;
  2687.           }
  2688.           cur_page->parms[0] = add_string(line.gettoken_str(1));
  2689.           cur_page->parms[1] = add_string(line.gettoken_str(2));
  2690.         }
  2691.         SCRIPT_MSG("UninstallText: \"%s\" \"%s\"\n",line.gettoken_str(1),line.gettoken_str(2));
  2692.       }
  2693.     return PS_OK;
  2694.     case TOK_UNINSTSUBCAPTION:
  2695.       {
  2696.         int s;
  2697.         int w=line.gettoken_int(1,&s);
  2698.         if (!s || w < 0 || w > 2) PRINTHELP()
  2699.         SetInnerString(NLF_USUBCAPTION_CONFIRM+w,line.gettoken_str(2));
  2700.         SCRIPT_MSG("UninstSubCaption: page:%d, text=%s\n",w,line.gettoken_str(2));
  2701.       }
  2702.     return PS_OK;
  2703.     case TOK_WRITEUNINSTALLER:
  2704.       if (uninstall_mode)
  2705.       {
  2706.         ERROR_MSG("WriteUninstaller only valid from install, not from uninstall.\n");
  2707.         PRINTHELP()
  2708.       }
  2709.       uninstaller_writes_used++;
  2710.       ent.which=EW_WRITEUNINSTALLER;
  2711.       ent.offsets[0]=add_string(line.gettoken_str(1));
  2712.       if (!ent.offsets[0]) PRINTHELP()
  2713.       SCRIPT_MSG("WriteUninstaller: \"%s\"\n",line.gettoken_str(1));
  2714.  
  2715.       DefineInnerLangString(NLF_ERR_CREATING);
  2716.       DefineInnerLangString(NLF_CREATED_UNINST);
  2717.     return add_entry(&ent);
  2718. #else//!NSIS_CONFIG_UNINSTALL_SUPPORT
  2719.     case TOK_WRITEUNINSTALLER:
  2720.     case TOK_UNINSTCAPTION:
  2721.     case TOK_UNINSTICON:
  2722.     case TOK_UNINSTTEXT:
  2723.     case TOK_UNINSTSUBCAPTION:
  2724.       ERROR_MSG("Error: %s specified, NSIS_CONFIG_UNINSTALL_SUPPORT not defined.\n", line.gettoken_str(0));
  2725.     return PS_ERROR;
  2726. #endif
  2727.  
  2728.  
  2729.  
  2730.     // section/function shit
  2731.     ///////////////////////////////////////////////////////////////////////////////
  2732.  
  2733.     case TOK_SECTION:
  2734.     {
  2735.       int a=1,unselected = 0;
  2736.       if (!strcmpi(line.gettoken_str(1),"/o"))
  2737.       {
  2738.         unselected = 1;
  2739.         a++;
  2740.       }
  2741.       else if (line.getnumtokens() > 3)
  2742.         PRINTHELP();
  2743.       SCRIPT_MSG("Section: \"%s\"",line.gettoken_str(a));
  2744.       if (line.gettoken_str(a+1)[0]) SCRIPT_MSG(" ->(%s)",line.gettoken_str(a+1));
  2745.       SCRIPT_MSG("\n");
  2746. #ifndef NSIS_CONFIG_UNINSTALL_SUPPORT
  2747.       if (!stricmp(line.gettoken_str(a),"uninstall"))
  2748.       {
  2749.         ERROR_MSG("Error: Uninstall section declared, no NSIS_CONFIG_UNINSTALL_SUPPORT\n");
  2750.         return PS_ERROR;
  2751.       }
  2752. #endif
  2753.  
  2754.       int ret;
  2755.  
  2756.       if (line.gettoken_str(a)[0]=='-')
  2757.       {
  2758.         if (!strnicmp(line.gettoken_str(a)+1,"un.",3))
  2759.           ret=add_section("un.",line.gettoken_str(a+1));
  2760.         else
  2761.           ret=add_section("",line.gettoken_str(a+1));
  2762.       }
  2763.       else ret=add_section(line.gettoken_str(a),line.gettoken_str(a+1));
  2764.       if (ret != PS_OK) return ret;
  2765.       
  2766.       if (unselected)
  2767.         build_cursection->flags &= ~SF_SELECTED;
  2768.  
  2769.       return PS_OK;
  2770.     }
  2771.     case TOK_SECTIONEND:
  2772.       SCRIPT_MSG("SectionEnd\n");
  2773.     return section_end();
  2774.     case TOK_SECTIONIN:
  2775.       {
  2776.         SCRIPT_MSG("SectionIn: ");
  2777.         int wt;
  2778.         for (wt = 1; wt < line.getnumtokens(); wt ++)
  2779.         {
  2780.           char *p=line.gettoken_str(wt);
  2781.           if (p[0]=='R' && p[1]=='O')
  2782.           {
  2783.             if (section_add_flags(SF_RO) != PS_OK) return PS_ERROR;
  2784.             SCRIPT_MSG("[RO] ");
  2785.           }
  2786.           else
  2787.           {
  2788.             int x=atoi(p)-1;
  2789.             if (x >= 0 && x < NSIS_MAX_INST_TYPES)
  2790.             {
  2791.               if (section_add_install_type(1<<x) != PS_OK) return PS_ERROR;
  2792.               SCRIPT_MSG("[%d] ",x);
  2793.             }
  2794.             else if (x < 0)
  2795.             {
  2796.               PRINTHELP()
  2797.             }
  2798.             else
  2799.             {
  2800.               ERROR_MSG("Error: SectionIn section %d out of range 1-%d\n",x+1,NSIS_MAX_INST_TYPES);
  2801.               return PS_ERROR;
  2802.             }
  2803.             p++;
  2804.           }
  2805.         }
  2806.         SCRIPT_MSG("\n");
  2807.       }
  2808.     return PS_OK;
  2809.     case TOK_SUBSECTIONEND:
  2810.     case TOK_SUBSECTION:
  2811.     {
  2812.       char buf[1024];
  2813.       int a=1,ex = 0;
  2814.       if (!strcmpi(line.gettoken_str(1),"/e"))
  2815.       {
  2816.         ex = 1;
  2817.         a++;
  2818.       }
  2819.       wsprintf(buf,"-%s",line.gettoken_str(a));
  2820.       if (which_token == TOK_SUBSECTION)
  2821.       {
  2822.         char *s = line.gettoken_str(a);
  2823.         if (!s[0] || (!strcmpi(s, "un.") && !s[3]))
  2824.           PRINTHELP();
  2825.       }
  2826.  
  2827.       SCRIPT_MSG("%s %s",line.gettoken_str(0),line.gettoken_str(a));
  2828.       if (line.gettoken_str(a+1)[0]) SCRIPT_MSG(" ->(%s)",line.gettoken_str(a+1));
  2829.       SCRIPT_MSG("\n");
  2830.       return add_section(buf,line.gettoken_str(a+1),ex);
  2831.     }
  2832.     case TOK_FUNCTION:
  2833.       if (!line.gettoken_str(1)[0]) PRINTHELP()
  2834.       if (line.gettoken_str(1)[0]==':' || line.gettoken_str(1)[0]=='/')
  2835.       {
  2836.         ERROR_MSG("Function: function name cannot begin with : or /.\n");
  2837.         PRINTHELP()
  2838.       }
  2839.       SCRIPT_MSG("Function: \"%s\"\n",line.gettoken_str(1));
  2840. #ifndef NSIS_CONFIG_UNINSTALL_SUPPORT
  2841.       if (!strnicmp(line.gettoken_str(1),"un.",3))
  2842.       {
  2843.         ERROR_MSG("Error: Uninstall function declared, no NSIS_CONFIG_UNINSTALL_SUPPORT\n");
  2844.         return PS_ERROR;
  2845.       }
  2846. #endif
  2847.       return add_function(line.gettoken_str(1));
  2848.     case TOK_FUNCTIONEND:
  2849.       SCRIPT_MSG("FunctionEnd\n");
  2850.     return function_end();
  2851.  
  2852.     // flag setters
  2853.     ///////////////////////////////////////////////////////////////////////////////
  2854.  
  2855.     // BEGIN - Added by ramon 23 May 2003
  2856.     case TOK_ALLOWSKIPFILES:
  2857.       build_allowskipfiles=line.gettoken_enum(1,"off\0on\0");
  2858.       if (build_allowskipfiles==-1) PRINTHELP()
  2859.       SCRIPT_MSG("AllowSkipFiles: %s\n",line.gettoken_str(1));
  2860.     return PS_OK;
  2861.     // END - Added by ramon 23 May 2003
  2862.     case TOK_SETDATESAVE:
  2863.       build_datesave=line.gettoken_enum(1,"off\0on\0");
  2864.       if (build_datesave==-1) PRINTHELP()
  2865.       SCRIPT_MSG("SetDateSave: %s\n",line.gettoken_str(1));
  2866.     return PS_OK;
  2867.     case TOK_SETOVERWRITE:
  2868.     {
  2869.       int k=line.gettoken_enum(1,"on\0off\0try\0ifnewer\0ifdiff\0lastused\0");
  2870.       if (k==-1) PRINTHELP()
  2871.       if (k==5)
  2872.       {
  2873.         k=build_overwrite;
  2874.         build_overwrite=build_last_overwrite;
  2875.         build_last_overwrite=k;
  2876.       }
  2877.       else
  2878.       {
  2879.         build_last_overwrite=build_overwrite;
  2880.         build_overwrite=k;
  2881.       }
  2882.       SCRIPT_MSG("overwrite = %d, last_overwrite = %d\n", build_overwrite, build_last_overwrite);
  2883.       SCRIPT_MSG("SetOverwrite: %s\n",line.gettoken_str(1));
  2884.     }
  2885.     return PS_OK;
  2886. #ifdef NSIS_CONFIG_PLUGIN_SUPPORT
  2887.     case TOK_SETPLUGINUNLOAD:
  2888.       build_plugin_unload=line.gettoken_enum(1,"manual\0alwaysoff\0");
  2889.       if (build_plugin_unload==-1) PRINTHELP()
  2890.       SCRIPT_MSG("SetPluginUnload: %s\n",line.gettoken_str(1));
  2891.     return PS_OK;
  2892. #endif //NSIS_CONFIG_PLUGIN_SUPPORT
  2893.     case TOK_SETCOMPRESS:
  2894.       build_compress=line.gettoken_enum(1,"off\0auto\0force\0");
  2895.       if (build_compress==-1) PRINTHELP()
  2896.       if (build_compress==0 && build_compress_whole)
  2897.       {
  2898.         warning_fl("'SetCompress off' encountered, and in whole compression mode. Effectively ignored.");
  2899.       }
  2900.       SCRIPT_MSG("SetCompress: %s\n",line.gettoken_str(1));
  2901.     return PS_OK;
  2902.     case TOK_DBOPTIMIZE:
  2903.       build_optimize_datablock=line.gettoken_enum(1,"off\0on\0");
  2904.       if (build_optimize_datablock==-1) PRINTHELP()
  2905.       SCRIPT_MSG("SetDatablockOptimize: %s\n",line.gettoken_str(1));
  2906.     return PS_OK;
  2907.     case TOK_FILEBUFSIZE:
  2908.       build_filebuflen=line.gettoken_int(1);
  2909.       build_filebuflen<<=20;
  2910.       if (build_filebuflen<=0)
  2911.       {
  2912.         ERROR_MSG("Error: FileBufSize: invalid buffer size -- %d\n",build_filebuflen);
  2913.         return PS_ERROR;
  2914.       }
  2915.       SCRIPT_MSG("FileBufSize: %smb (%d bytes)\n",line.gettoken_str(1),build_filebuflen);
  2916.     return PS_OK;
  2917. #ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
  2918.     case TOK_SETCOMPRESSIONLEVEL:
  2919.     {
  2920.       if (compressor == &lzma_compressor)
  2921.         warning_fl("SetCompressionLevel: compressor is set to LZMA. Effectively ignored.");
  2922.       if (build_compressor_set && build_compress_whole)
  2923.         warning_fl("SetCompressionLevel: data already compressed in compress whole mode. Effectively ignored.");
  2924.  
  2925.       int s;
  2926.       build_compress_level=line.gettoken_int(1,&s);
  2927.       if (!s || build_compress_level < 0 || build_compress_level > 9) PRINTHELP();
  2928.       SCRIPT_MSG("SetCompressionLevel: %u\n", build_compress_level);
  2929.     }
  2930.     return PS_OK;
  2931.     case TOK_SETCOMPRESSORDICTSIZE:
  2932.     {
  2933.       if (compressor != &lzma_compressor)
  2934.         warning_fl("SetCompressorDictSize: compressor is not set to LZMA. Effectively ignored.");
  2935.       if (build_compressor_set && build_compress_whole)
  2936.         warning_fl("SetCompressorDictSize: data already compressed in compress whole mode. Effectively ignored.");
  2937.  
  2938.       int s;
  2939.       build_compress_dict_size=line.gettoken_int(1,&s);
  2940.       if (!s) PRINTHELP();
  2941.       SCRIPT_MSG("SetCompressorDictSize: %u mb\n", build_compress_dict_size);
  2942.       build_compress_dict_size <<= 20;
  2943.     }
  2944.     return PS_OK;
  2945. #else
  2946.     case TOK_SETCOMPRESSIONLEVEL:
  2947.     case TOK_SETCOMPRESSORDICTSIZE:
  2948.       ERROR_MSG("Error: %s specified, NSIS_CONFIG_COMPRESSION_SUPPORT not defined.\n",  line.gettoken_str(0));
  2949.     return PS_ERROR;
  2950. #endif//NSIS_CONFIG_COMPRESSION_SUPPORT
  2951.     case TOK_ADDSIZE:
  2952.       {
  2953.         int s;
  2954.         int size_kb=line.gettoken_int(1,&s);
  2955.         if (!s) PRINTHELP()
  2956.         SCRIPT_MSG("AddSize: %d kb\n",size_kb);
  2957.         section_add_size_kb(size_kb);
  2958.       }
  2959.     return PS_OK;
  2960.     case TOK_SUBCAPTION:
  2961.       {
  2962.         int s;
  2963.         int w=line.gettoken_int(1,&s);
  2964.         if (!s || w < 0 || w > 4) PRINTHELP()
  2965.         SetInnerString(NLF_SUBCAPTION_LICENSE+w,line.gettoken_str(2));
  2966.         SCRIPT_MSG("SubCaption: page:%d, text=%s\n",w,line.gettoken_str(2));
  2967.       }
  2968.     return PS_OK;
  2969.     case TOK_FILEERRORTEXT:
  2970. #ifdef NSIS_SUPPORT_FILE
  2971.       {
  2972.         SetInnerString(NLF_FILE_ERROR,line.gettoken_str(1));
  2973.         SetInnerString(NLF_FILE_ERROR_NOIGNORE,line.gettoken_str(2));
  2974.         SCRIPT_MSG("FileErrorText: \"%s\" \"%s\"\n",line.gettoken_str(1),line.gettoken_str(2));
  2975.       }
  2976.     return PS_OK;
  2977. #else
  2978.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_FILE not defined.\n",  line.gettoken_str(0));
  2979.     return PS_ERROR;
  2980. #endif
  2981.     case TOK_BRANDINGTEXT:
  2982.       {
  2983.         int a = 1;
  2984.         int trim = 0;
  2985.         while (line.gettoken_str(a)[0] == '/') {
  2986.           if (!strnicmp(line.gettoken_str(a),"/TRIM",5)) {
  2987.             if (!stricmp(line.gettoken_str(a)+5,"LEFT")) trim = 1;
  2988.             else if (!stricmp(line.gettoken_str(a)+5,"RIGHT")) trim = 2;
  2989.             else if (!stricmp(line.gettoken_str(a)+5,"CENTER")) trim = 3;
  2990.             else PRINTHELP();
  2991.             a++;
  2992.           }
  2993.           else break;
  2994.         }
  2995.         if (line.getnumtokens()!=a+1 && !trim) PRINTHELP();
  2996.         if (line.getnumtokens()==a+1)
  2997.           SetInnerString(NLF_BRANDING,line.gettoken_str(a));
  2998.         if (trim) try {
  2999.           init_res_editor();
  3000.  
  3001.           BYTE* dlg = res_editor->GetResource(RT_DIALOG, MAKEINTRESOURCE(IDD_INST), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
  3002.           CDialogTemplate td(dlg,uDefCodePage);
  3003.           free(dlg);
  3004.  
  3005.           if (trim) {
  3006.             char str[512];
  3007.             extern const char *NSIS_VERSION;
  3008.             if (line.getnumtokens()==a+1 && line.gettoken_str(a)[0])
  3009.               lstrcpy(str, line.gettoken_str(a));
  3010.             else
  3011.               wsprintf(str, "Nullsoft Install System %s", NSIS_VERSION);
  3012.  
  3013.             switch (trim) {
  3014.               case 1: td.LTrimToString(IDC_VERSTR, str, 4); break;
  3015.               case 2: td.RTrimToString(IDC_VERSTR, str, 4); break;
  3016.               case 3: td.CTrimToString(IDC_VERSTR, str, 4); break;
  3017.             }
  3018.           }
  3019.  
  3020.           DWORD dwSize;
  3021.           dlg = td.Save(dwSize);
  3022.           res_editor->UpdateResource(RT_DIALOG, MAKEINTRESOURCE(IDD_INST), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), dlg, dwSize);
  3023.           res_editor->FreeResource(dlg);
  3024.         }
  3025.         catch (exception& err) {
  3026.           ERROR_MSG("Error while triming branding text control: %s\n", err.what());
  3027.           return PS_ERROR;
  3028.         }
  3029.         SCRIPT_MSG("BrandingText: \"%s\"\n",line.gettoken_str(a));
  3030.       }
  3031.     return PS_OK;
  3032.     case TOK_MISCBUTTONTEXT:
  3033.       {
  3034.         SetInnerString(NLF_BTN_BACK,line.gettoken_str(1));
  3035.         SetInnerString(NLF_BTN_NEXT,line.gettoken_str(2));
  3036.         SetInnerString(NLF_BTN_CANCEL,line.gettoken_str(3));
  3037.         SetInnerString(NLF_BTN_CLOSE,line.gettoken_str(4));
  3038.         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));
  3039.       }
  3040.     return PS_OK;
  3041.     case TOK_SPACETEXTS:
  3042.       {
  3043.         if (!lstrcmpi(line.gettoken_str(1), "none")) {
  3044.           no_space_texts=true;
  3045.           SCRIPT_MSG("SpaceTexts: none\n");
  3046.         }
  3047.         else {
  3048.           no_space_texts=false;
  3049.           SetInnerString(NLF_SPACE_REQ,line.gettoken_str(1));
  3050.           SetInnerString(NLF_SPACE_AVAIL,line.gettoken_str(2));
  3051.           SCRIPT_MSG("SpaceTexts: required=\"%s\" available=\"%s\"\n",line.gettoken_str(1),line.gettoken_str(2));
  3052.         }
  3053.       }
  3054.     return PS_OK;
  3055.     case TOK_INSTBUTTONTEXT:
  3056.       {
  3057.         SetInnerString(NLF_BTN_INSTALL,line.gettoken_str(1));
  3058.         SCRIPT_MSG("InstallButtonText: \"%s\"\n",line.gettoken_str(1));
  3059.       }
  3060.     return PS_OK;
  3061.     case TOK_DETAILSBUTTONTEXT:
  3062.       {
  3063.         if (!cur_page) {
  3064.           if (SetInnerString(NLF_BTN_DETAILS,line.gettoken_str(1)) == PS_WARNING)
  3065.             warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0));
  3066.         }
  3067.         else {
  3068.           if (cur_page_type != PAGE_INSTFILES) {
  3069.             ERROR_MSG("Error: DetailsButtonText can only be used inside PageEx instfiles.\n");
  3070.             return PS_ERROR;
  3071.           }
  3072.           cur_page->parms[1] = add_string(line.gettoken_str(1));
  3073.         }
  3074.         SCRIPT_MSG("DetailsButtonText: \"%s\"\n",line.gettoken_str(1));
  3075.       }
  3076.     return PS_OK;
  3077.     case TOK_COMPLETEDTEXT:
  3078.       {
  3079.         if (!cur_page) {
  3080.           if (SetInnerString(NLF_COMPLETED,line.gettoken_str(1)) == PS_WARNING)
  3081.             warning_fl("%s: specified multiple times, wasting space",line.gettoken_str(0));
  3082.         }
  3083.         else {
  3084.           if (cur_page_type != PAGE_INSTFILES) {
  3085.             ERROR_MSG("Error: CompletedText can only be used inside PageEx instfiles.\n");
  3086.             return PS_ERROR;
  3087.           }
  3088.           cur_page->parms[2] = add_string(line.gettoken_str(1));
  3089.         }
  3090.         SCRIPT_MSG("CompletedText: \"%s\"\n",line.gettoken_str(1));
  3091.       }
  3092.     return PS_OK;
  3093.     case TOK_UNINSTBUTTONTEXT:
  3094. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  3095.       {
  3096.         SetInnerString(NLF_BTN_UNINSTALL,line.gettoken_str(1));
  3097.         SCRIPT_MSG("UninstButtonText: \"%s\"\n",line.gettoken_str(1));
  3098.       }
  3099.     return PS_OK;
  3100. #else
  3101.       ERROR_MSG("Error: %s specified, NSIS_CONFIG_UNINSTALL_SUPPORT not defined.\n",  line.gettoken_str(0));
  3102.     return PS_ERROR;
  3103. #endif
  3104.  
  3105.     // instructions
  3106.     ///////////////////////////////////////////////////////////////////////////////
  3107.     case TOK_NOP:
  3108.       SCRIPT_MSG("Nop\n");
  3109.       ent.which=EW_NOP;
  3110.     return add_entry(&ent);
  3111.     case TOK_GOTO:
  3112.       ent.which=EW_NOP;
  3113.       if (process_jump(line,1,&ent.offsets[0])) PRINTHELP()
  3114.       SCRIPT_MSG("Goto: %s\n",line.gettoken_str(1));
  3115.     return add_entry(&ent);
  3116.     case TOK_SETSHELLVARCONTEXT:
  3117.     {
  3118.       ent.which=EW_SETFLAG;
  3119.       ent.offsets[0]=FLAG_OFFSET(all_user_var);
  3120.       int k=line.gettoken_enum(1,"current\0all\0");
  3121.       if (k<0) PRINTHELP()
  3122.       ent.offsets[1]=add_intstring(k);
  3123.       SCRIPT_MSG("SetShellVarContext: %s\n",line.gettoken_str(1));
  3124.     }
  3125.     return add_entry(&ent);
  3126.     case TOK_RET:
  3127.       SCRIPT_MSG("Return\n");
  3128.       ent.which=EW_RET;
  3129.     return add_entry(&ent);
  3130.     case TOK_CALL:
  3131.       if (!line.gettoken_str(1)[0] || (line.gettoken_str(1)[0]==':' && !line.gettoken_str(1)[1] )) PRINTHELP()
  3132. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  3133.       if (uninstall_mode && strnicmp(line.gettoken_str(1),"un.",3) && (GetUserVarIndex(line,1) < 0))
  3134.       {
  3135.         ERROR_MSG("Call must be used with function names starting with \"un.\" in the uninstall section.\n");
  3136.         PRINTHELP()
  3137.       }
  3138.       if (!uninstall_mode && !strnicmp(line.gettoken_str(1),"un.",3))
  3139.       {
  3140.         ERROR_MSG("Call must not be used with functions starting with \"un.\" in the non-uninstall sections.\n");
  3141.         PRINTHELP()
  3142.       }
  3143. #endif
  3144.       ent.which=EW_CALL;
  3145.       ent.offsets[1]=0;
  3146.       {
  3147.         int v;
  3148.         if ((v=GetUserVarIndex(line, 1))>=0)
  3149.         {
  3150.           ent.offsets[0]=-v-2;
  3151.         }
  3152.         else
  3153.         {
  3154.           if (line.gettoken_str(1)[0] == ':')
  3155.           {
  3156.             ent.offsets[1]=1;
  3157.             ent.offsets[0]=ns_label.add(line.gettoken_str(1)+1,0);
  3158.           }
  3159.           else ent.offsets[0]=ns_func.add(line.gettoken_str(1),0);
  3160.         }
  3161.       }
  3162.       SCRIPT_MSG("Call \"%s\"\n",line.gettoken_str(1));
  3163.     return add_entry(&ent);
  3164.     case TOK_SETOUTPATH:
  3165.       {
  3166.         SCRIPT_MSG("SetOutPath: \"%s\"\n",line.gettoken_str(1));
  3167.         ent.which=EW_CREATEDIR;
  3168.         ent.offsets[0]=add_string(line.gettoken_str(1));
  3169.         ent.offsets[1]=1;
  3170.  
  3171.         DefineInnerLangString(NLF_OUTPUT_DIR);
  3172.       }
  3173.     return add_entry(&ent);
  3174.     case TOK_CREATEDIR:
  3175.       {
  3176.         char out_path[1024];
  3177.         char *p=line.gettoken_str(1);
  3178.         if (*p == '-') out_path[0]=0;
  3179.         else
  3180.         {
  3181.           if (p[0] == '\\' && p[1] != '\\') p++;
  3182.           strncpy(out_path,p,1024-1);
  3183.           if (*CharPrev(out_path,out_path+strlen(out_path))=='\\')
  3184.             *CharPrev(out_path,out_path+strlen(out_path))=0; // remove trailing slash
  3185.         }
  3186.         if (!*out_path) PRINTHELP()
  3187.         SCRIPT_MSG("CreateDirectory: \"%s\"\n",out_path);
  3188.         ent.which=EW_CREATEDIR;
  3189.         ent.offsets[0]=add_string(out_path);
  3190.  
  3191.         DefineInnerLangString(NLF_CREATE_DIR);
  3192.       }
  3193.     return add_entry(&ent);
  3194.     case TOK_EXEC:
  3195.     case TOK_EXECWAIT:
  3196. #ifdef NSIS_SUPPORT_EXECUTE
  3197.       ent.which=EW_EXECUTE;
  3198.       ent.offsets[0]=add_string(line.gettoken_str(1));
  3199.       ent.offsets[2]=0;
  3200.       if (which_token == TOK_EXECWAIT)
  3201.       {
  3202.         ent.offsets[2]=1;
  3203.         ent.offsets[1]=GetUserVarIndex(line, 2);
  3204.         if (line.gettoken_str(2)[0] && ent.offsets[1]<0) PRINTHELP()
  3205.       }
  3206.       SCRIPT_MSG("%s: \"%s\" (->%s)\n",ent.offsets[2]?"ExecWait":"Exec",line.gettoken_str(1),line.gettoken_str(2));
  3207.  
  3208.       DefineInnerLangString(NLF_EXEC);
  3209.     return add_entry(&ent);
  3210. #else//!NSIS_SUPPORT_EXECUTE
  3211.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_EXECUTE not defined.\n",  line.gettoken_str(0));
  3212.     return PS_ERROR;
  3213. #endif//!NSIS_SUPPORT_EXECUTE
  3214.     case TOK_EXECSHELL: // this uses improvements of Andras Varga
  3215. #ifdef NSIS_SUPPORT_SHELLEXECUTE
  3216.       ent.which=EW_SHELLEXEC;
  3217.       ent.offsets[0]=add_string(line.gettoken_str(1));
  3218.       ent.offsets[1]=add_string(line.gettoken_str(2));
  3219.       ent.offsets[2]=add_string(line.gettoken_str(3));
  3220.       ent.offsets[3]=SW_SHOWNORMAL;
  3221.       if (line.getnumtokens() > 4)
  3222.       {
  3223.         int tab[3]={SW_SHOWNORMAL,SW_SHOWMAXIMIZED,SW_SHOWMINIMIZED};
  3224.         int a=line.gettoken_enum(4,"SW_SHOWNORMAL\0SW_SHOWMAXIMIZED\0SW_SHOWMINIMIZED\0");
  3225.         if (a < 0) PRINTHELP()
  3226.         ent.offsets[3]=tab[a];
  3227.       }
  3228.       SCRIPT_MSG("ExecShell: %s: \"%s\" \"%s\" %s\n",line.gettoken_str(1),line.gettoken_str(2),
  3229.                                                  line.gettoken_str(3),line.gettoken_str(4));
  3230.  
  3231.       DefineInnerLangString(NLF_EXEC_SHELL);
  3232.     return add_entry(&ent);
  3233. #else//!NSIS_SUPPORT_SHELLEXECUTE
  3234.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_SHELLEXECUTE not defined.\n",  line.gettoken_str(0));
  3235.     return PS_ERROR;
  3236. #endif//!NSIS_SUPPORT_SHELLEXECUTE
  3237.     case TOK_CALLINSTDLL:
  3238.     case TOK_REGDLL:
  3239.     case TOK_UNREGDLL:
  3240. #ifndef NSIS_SUPPORT_ACTIVEXREG
  3241.       ERROR_MSG("%s: support not compiled in (NSIS_SUPPORT_ACTIVEXREG)\n",line.gettoken_str(0));
  3242.       return PS_ERROR;
  3243. #else//NSIS_SUPPORT_ACTIVEXREG
  3244.       ent.which=EW_REGISTERDLL;
  3245.       ent.offsets[0]=add_string(line.gettoken_str(1));
  3246.       if (which_token == TOK_UNREGDLL)
  3247.       {
  3248.         ent.offsets[1]=add_string("DllUnregisterServer");
  3249.         ent.offsets[2]=DefineInnerLangString(NLF_UNREGISTERING);
  3250.       }
  3251.       else if (which_token == TOK_CALLINSTDLL)
  3252.       {
  3253.         int a = 2;
  3254.         if (!stricmp(line.gettoken_str(a), "/NOUNLOAD")) {
  3255.           ent.offsets[3]=1;
  3256.           a++;
  3257.         }
  3258.         if (a+1 != line.getnumtokens()) PRINTHELP();
  3259.         ent.offsets[1]=add_string(line.gettoken_str(a));
  3260.         if (!ent.offsets[1]) PRINTHELP()
  3261.         ent.offsets[2]=0;
  3262.       }
  3263.       else // register
  3264.       {
  3265.         ent.offsets[1] = add_string(line.gettoken_str(2));
  3266.         if (!ent.offsets[1]) ent.offsets[1]=add_string("DllRegisterServer");
  3267.         ent.offsets[2]=DefineInnerLangString(NLF_REGISTERING);
  3268.       }
  3269.  
  3270.       SCRIPT_MSG("%s: \"%s\" %s\n",line.gettoken_str(0),line.gettoken_str(1), line.gettoken_str(ent.offsets[3]?3:2));
  3271.  
  3272.       DefineInnerLangString(NLF_SYMBOL_NOT_FOUND);
  3273.       DefineInnerLangString(NLF_COULD_NOT_LOAD);
  3274.       DefineInnerLangString(NLF_NO_OLE);
  3275.       DefineInnerLangString(NLF_ERR_REG_DLL);
  3276.     return add_entry(&ent);
  3277. #endif//NSIS_SUPPORT_ACTIVEXREG
  3278.     case TOK_RENAME:
  3279. #ifdef NSIS_SUPPORT_RENAME
  3280.       {
  3281.         int a=1;
  3282.         ent.which=EW_RENAME;
  3283.         if (!stricmp(line.gettoken_str(1),"/REBOOTOK"))
  3284.         {
  3285.           ent.offsets[2]=1;
  3286.           a++;
  3287. #ifndef NSIS_SUPPORT_MOVEONREBOOT
  3288.           ERROR_MSG("Error: /REBOOTOK specified, NSIS_SUPPORT_MOVEONREBOOT not defined\n");
  3289.           PRINTHELP()
  3290. #endif
  3291.         }
  3292.         else if (line.gettoken_str(1)[0]=='/')
  3293.         {
  3294.           a=line.getnumtokens(); // cause usage to go here:
  3295.         }
  3296.         if (line.getnumtokens()!=a+2) PRINTHELP()
  3297.         ent.offsets[0]=add_string(line.gettoken_str(a));
  3298.         ent.offsets[1]=add_string(line.gettoken_str(a+1));
  3299.         SCRIPT_MSG("Rename: %s%s->%s\n",ent.offsets[2]?"/REBOOTOK ":"",line.gettoken_str(a),line.gettoken_str(a+1));
  3300.  
  3301.         DefineInnerLangString(NLF_RENAME);
  3302. #ifdef NSIS_SUPPORT_MOVEONREBOOT
  3303.         DefineInnerLangString(NLF_RENAME_ON_REBOOT);
  3304. #endif
  3305.       }
  3306.     return add_entry(&ent);
  3307. #else//!NSIS_SUPPORT_RENAME
  3308.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_RENAME not defined.\n",  line.gettoken_str(0));
  3309.     return PS_ERROR;
  3310. #endif//!NSIS_SUPPORT_RENAME
  3311.     case TOK_MESSAGEBOX:
  3312. #ifdef NSIS_SUPPORT_MESSAGEBOX
  3313.       {
  3314.         #define MBD(x) {x,#x},
  3315.         struct
  3316.         {
  3317.           int id;
  3318.           char *str;
  3319.         } list[]=
  3320.         {
  3321.           MBD(MB_ABORTRETRYIGNORE)
  3322.           MBD(MB_OK)
  3323.           MBD(MB_OKCANCEL)
  3324.           MBD(MB_RETRYCANCEL)
  3325.           MBD(MB_YESNO)
  3326.           MBD(MB_YESNOCANCEL)
  3327.           MBD(MB_ICONEXCLAMATION)
  3328.           MBD(MB_ICONINFORMATION)
  3329.           MBD(MB_ICONQUESTION)
  3330.           MBD(MB_ICONSTOP)
  3331.           MBD(MB_TOPMOST)
  3332.           MBD(MB_SETFOREGROUND)
  3333.           MBD(MB_RIGHT)
  3334.           MBD(MB_DEFBUTTON1)
  3335.           MBD(MB_DEFBUTTON2)
  3336.           MBD(MB_DEFBUTTON3)
  3337.           MBD(MB_DEFBUTTON4)
  3338.         };
  3339.         #undef MBD
  3340.         int r=0;
  3341.         int x;
  3342.         char *p=line.gettoken_str(1);
  3343.  
  3344.         while (*p)
  3345.         {
  3346.           char *np=p;
  3347.           while (*np && *np != '|') np++;
  3348.           if (*np) *np++=0;
  3349.           for (x  =0 ; x < sizeof(list)/sizeof(list[0]) && strcmpi(list[x].str,p); x ++);
  3350.           if (x < sizeof(list)/sizeof(list[0]))
  3351.           {
  3352.             r|=list[x].id;
  3353.           }
  3354.           else PRINTHELP()
  3355.           p=np;
  3356.         }
  3357.         ent.which=EW_MESSAGEBOX;
  3358.         ent.offsets[0]=r;
  3359.         ent.offsets[1]=add_string(line.gettoken_str(2));
  3360.         int rettab[] =
  3361.         {
  3362.           0,IDABORT,IDCANCEL,IDIGNORE,IDNO,IDOK,IDRETRY,IDYES
  3363.         };
  3364.         const char *retstr="0\0IDABORT\0IDCANCEL\0IDIGNORE\0IDNO\0IDOK\0IDRETRY\0IDYES\0";
  3365.         int a=3;
  3366.         if (line.getnumtokens() > 3)
  3367.         {
  3368.           if (!strcmpi(line.gettoken_str(3),"/SD"))
  3369.           {
  3370.             int k=line.gettoken_enum(4,retstr);
  3371.             if (k <= 0) PRINTHELP();
  3372.             ent.offsets[0]|=rettab[k]<<20;
  3373.             a=5;
  3374.           }
  3375.           else if (line.getnumtokens() > 7)
  3376.             PRINTHELP();
  3377.  
  3378.           if (line.getnumtokens() > a)
  3379.           {
  3380.             ent.offsets[2]=line.gettoken_enum(a,retstr);
  3381.             if (ent.offsets[2] < 0)
  3382.               PRINTHELP();
  3383.             ent.offsets[2] = rettab[ent.offsets[2]];
  3384.             if (process_jump(line,a+1,&ent.offsets[3]))
  3385.               PRINTHELP();
  3386.             if (line.getnumtokens() > a+2)
  3387.             {
  3388.               int v=line.gettoken_enum(a+2,retstr);
  3389.               if (v < 0)
  3390.                 PRINTHELP();
  3391.               ent.offsets[4] = rettab[v];
  3392.               if (process_jump(line,a+3,&ent.offsets[5]))
  3393.                 PRINTHELP();
  3394.             }
  3395.           }
  3396.         }
  3397.         SCRIPT_MSG("MessageBox: %d: \"%s\"",r,line.gettoken_str(2));
  3398.         if (line.getnumtokens()>a+1) SCRIPT_MSG(" (on %s goto %s)",line.gettoken_str(a),line.gettoken_str(a+1));
  3399.         SCRIPT_MSG("\n");
  3400.       }
  3401.     return add_entry(&ent);
  3402. #else//!NSIS_SUPPORT_MESSAGEBOX
  3403.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_MESSAGEBOX not defined.\n",  line.gettoken_str(0));
  3404.     return PS_ERROR;
  3405. #endif//!NSIS_SUPPORT_MESSAGEBOX
  3406.     case TOK_CREATESHORTCUT:
  3407. #ifdef NSIS_SUPPORT_CREATESHORTCUT
  3408.       ent.which=EW_CREATESHORTCUT;
  3409.       ent.offsets[0]=add_string(line.gettoken_str(1));
  3410.       ent.offsets[1]=add_string(line.gettoken_str(2));
  3411.       ent.offsets[2]=add_string(line.gettoken_str(3));
  3412.       ent.offsets[3]=add_string(line.gettoken_str(4));
  3413.       ent.offsets[5]=add_string(line.gettoken_str(8));
  3414.       int s;
  3415.       ent.offsets[4]=line.gettoken_int(5,&s)&0xff;
  3416.       if (!s)
  3417.       {
  3418.         if (line.getnumtokens() > 5 && *line.gettoken_str(5))
  3419.         {
  3420.           ERROR_MSG("CreateShortCut: cannot interpret icon index\n");
  3421.           PRINTHELP()
  3422.         }
  3423.         ent.offsets[4]=0;
  3424.       }
  3425.       if (line.getnumtokens() > 6 && *line.gettoken_str(6))
  3426.       {
  3427.         int tab[3]={SW_SHOWNORMAL,SW_SHOWMAXIMIZED,SW_SHOWMINNOACTIVE/*SW_SHOWMINIMIZED doesn't work*/};
  3428.         int a=line.gettoken_enum(6,"SW_SHOWNORMAL\0SW_SHOWMAXIMIZED\0SW_SHOWMINIMIZED\0");
  3429.         if (a < 0)
  3430.         {
  3431.           ERROR_MSG("CreateShortCut: unknown show mode \"%s\"\n",line.gettoken_str(6));
  3432.           PRINTHELP()
  3433.         }
  3434.         ent.offsets[4]|=tab[a]<<8;
  3435.       }
  3436.       if (line.getnumtokens() > 7)
  3437.       {
  3438.         char *s=(line.gettoken_str(7));
  3439.  
  3440.         char b[255];
  3441.         for (unsigned int spos=0; (spos <= strlen(s)) && (spos <= 255); spos++)
  3442.           b[spos]=toupper(*(s+spos));
  3443.         strcpy(s,b);
  3444.         
  3445.         if (*s)
  3446.         {
  3447.           int c=0;
  3448.           if (strstr(s,"ALT|")) ent.offsets[4]|=HOTKEYF_ALT << 24;
  3449.           if (strstr(s,"CONTROL|")) ent.offsets[4]|=HOTKEYF_CONTROL << 24;
  3450.           if (strstr(s,"EXT|")) ent.offsets[4]|=HOTKEYF_EXT << 24;
  3451.           if (strstr(s,"SHIFT|")) ent.offsets[4]|=HOTKEYF_SHIFT << 24;
  3452.           while (strstr(s,"|"))
  3453.           {
  3454.             s=strstr(s,"|")+1;
  3455.           }
  3456.           if ((s[0] == 'F') && (s[1] >= '1' && s[1] <= '9'))
  3457.           {
  3458.             c=VK_F1-1+atoi(s+1);
  3459.             if (atoi(s+1) < 1 || atoi(s+1) > 24)
  3460.             {
  3461.               warning_fl("CreateShortCut: F-key \"%s\" out of range",s);
  3462.             }
  3463.           }
  3464.           else if (((s[0] >= 'A' && s[0] <= 'Z') || (s[0] >= '0' && s[0] <= '9')) && !s[1])
  3465.             c=s[0];
  3466.           else
  3467.           {
  3468.             c=s[0];
  3469.             warning_fl("CreateShortCut: unrecognized hotkey \"%s\"",s);
  3470.           }
  3471.           ent.offsets[4] |= (c) << 16;
  3472.         }
  3473.       }
  3474.       SCRIPT_MSG("CreateShortCut: \"%s\"->\"%s\" %s icon:%s,%d, showmode=0x%X, hotkey=0x%X, comment=%s\n",
  3475.         line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),
  3476.         line.gettoken_str(4),ent.offsets[4]&0xff,(ent.offsets[4]>>8)&0xff,ent.offsets[4]>>16,line.gettoken_str(8));
  3477.  
  3478.       DefineInnerLangString(NLF_CREATE_SHORTCUT);
  3479.       DefineInnerLangString(NLF_ERR_CREATING_SHORTCUT);
  3480.     return add_entry(&ent);
  3481. #else//!NSIS_SUPPORT_CREATESHORTCUT
  3482.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_CREATESHORTCUT not defined.\n",  line.gettoken_str(0));
  3483.     return PS_ERROR;
  3484. #endif//NSIS_SUPPORT_CREATESHORTCUT
  3485. #ifdef NSIS_SUPPORT_HWNDS
  3486.     case TOK_FINDWINDOW:
  3487.       ent.which=EW_FINDWINDOW;
  3488.       ent.offsets[0]=GetUserVarIndex(line, 1);
  3489.       if (ent.offsets[0] < 0) PRINTHELP()
  3490.       ent.offsets[1]=add_string(line.gettoken_str(2));
  3491.       ent.offsets[2]=add_string(line.gettoken_str(3));
  3492.       ent.offsets[3]=add_string(line.gettoken_str(4));
  3493.       ent.offsets[4]=add_string(line.gettoken_str(5));
  3494.       SCRIPT_MSG("FindWindow: output=%s, class=\"%s\", text=\"%s\" hwndparent=\"%s\" hwndafter=\"%s\"\n",
  3495.         line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4),line.gettoken_str(5));
  3496.     return add_entry(&ent);
  3497.     case TOK_SENDMESSAGE:
  3498.       ent.which=EW_SENDMESSAGE;
  3499.  
  3500.       if (line.gettoken_str(1)[0] == '/' || line.gettoken_str(2)[0] == '/' ||
  3501.           line.gettoken_str(3)[0] == '/' || line.gettoken_str(4)[0] == '/')
  3502.       {
  3503.         PRINTHELP()
  3504.       }
  3505.  
  3506.       SCRIPT_MSG("SendMessage:");
  3507.       {
  3508.         int a=5;
  3509.         ent.offsets[0]=GetUserVarIndex(line, 5);
  3510.         if (ent.offsets[0]>=0)
  3511.         {
  3512.           SCRIPT_MSG("(->%s)",line.gettoken_str(5));
  3513.           a++;
  3514.         }
  3515.  
  3516.         if (!strncmp(line.gettoken_str(a),"/TIMEOUT=",9))
  3517.         {
  3518.           ent.offsets[5]|=atoi(line.gettoken_str(a)+9)<<2;
  3519.           SCRIPT_MSG(" (timeout=%d)",ent.offsets[5]>>2);
  3520.           a++;
  3521.         }
  3522.  
  3523.         if (line.getnumtokens()>a)
  3524.         {
  3525.           PRINTHELP()
  3526.         }
  3527.       }
  3528.  
  3529.       if (!strncmp(line.gettoken_str(3),"STR:",4))
  3530.       {
  3531.         ent.offsets[5]|=1;
  3532.         ent.offsets[3]=add_string(line.gettoken_str(3)+4);
  3533.       }
  3534.       else ent.offsets[3]=add_string(line.gettoken_str(3));
  3535.       if (!strncmp(line.gettoken_str(4),"STR:",4))
  3536.       {
  3537.         ent.offsets[5]|=2;
  3538.         ent.offsets[4]=add_string(line.gettoken_str(4)+4);
  3539.       }
  3540.       else ent.offsets[4]=add_string(line.gettoken_str(4));
  3541.  
  3542.       ent.offsets[1]=add_string(line.gettoken_str(1));
  3543.       ent.offsets[2]=add_string(line.gettoken_str(2));
  3544.  
  3545.       SCRIPT_MSG("(%s,%s,%s,%s)\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4));
  3546.     return add_entry(&ent);
  3547.     case TOK_ISWINDOW:
  3548.       ent.which=EW_ISWINDOW;
  3549.       ent.offsets[0]=add_string(line.gettoken_str(1));
  3550.       if (process_jump(line,2,&ent.offsets[1])||
  3551.           process_jump(line,3,&ent.offsets[2])) PRINTHELP()
  3552.       SCRIPT_MSG("IsWindow(%s): %s:%s\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3));
  3553.     return add_entry(&ent);
  3554. #ifdef NSIS_CONFIG_ENHANCEDUI_SUPPORT
  3555.     case TOK_GETDLGITEM:
  3556.       ent.which=EW_GETDLGITEM;
  3557.       ent.offsets[0]=GetUserVarIndex(line, 1);
  3558.       if (ent.offsets[0]<0) PRINTHELP();
  3559.       ent.offsets[1]=add_string(line.gettoken_str(2));
  3560.       ent.offsets[2]=add_string(line.gettoken_str(3));
  3561.       SCRIPT_MSG("GetDlgItem: output=%s dialog=%s item=%s\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3));
  3562.     return add_entry(&ent);
  3563.     case TOK_SETCTLCOLORS:
  3564.     {
  3565.       ctlcolors c={0, };
  3566.  
  3567.       ent.which=EW_SETCTLCOLORS;
  3568.       ent.offsets[0]=add_string(line.gettoken_str(1));
  3569.  
  3570.       int a = 2;
  3571.  
  3572.       if (!strcmpi(line.gettoken_str(2),"/BRANDING"))
  3573.         a++;
  3574.       
  3575.       {
  3576.         char *p;
  3577.  
  3578.         if (a == 2 && line.getnumtokens() == 5) {
  3579.           ERROR_MSG("Error: SetCtlColors expected 3 parameters, got 4\n");
  3580.           return PS_ERROR;
  3581.         }
  3582.  
  3583.         if (!strcmpi(line.gettoken_str(a+1),"transparent")) {
  3584.           c.flags|=CC_BKB;
  3585.           c.lbStyle=BS_NULL;
  3586.           c.bkmode=TRANSPARENT;
  3587.         }
  3588.         else {
  3589.           p=line.gettoken_str(a+1);
  3590.           if (*p) {
  3591.             int v=strtoul(p,&p,16);
  3592.             c.bkc=((v&0xff)<<16)|(v&0xff00)|((v&0xff0000)>>16);
  3593.             c.flags|=CC_BK|CC_BKB;
  3594.           }
  3595.  
  3596.           c.lbStyle=BS_SOLID;
  3597.           c.bkmode=OPAQUE;
  3598.         }
  3599.  
  3600.         p=line.gettoken_str(a);
  3601.         if (*p) {
  3602.           int v=strtoul(p,&p,16);
  3603.           c.text=((v&0xff)<<16)|(v&0xff00)|((v&0xff0000)>>16);
  3604.           c.flags|=CC_TEXT;
  3605.         }
  3606.       }
  3607.  
  3608.       if (a == 3)
  3609.       {
  3610.         c.flags|=CC_BK|CC_BKB;
  3611.         c.lbStyle=BS_NULL;
  3612.         if (!*line.gettoken_str(a))
  3613.         {
  3614.           c.bkc=COLOR_BTNFACE;
  3615.           c.flags|=CC_BK_SYS;
  3616.         }
  3617.         c.flags|=CC_TEXT;
  3618.         if (!*line.gettoken_str(a+1))
  3619.         {
  3620.           c.text=COLOR_BTNFACE;
  3621.           c.flags|=CC_TEXT_SYS;
  3622.         }
  3623.         c.bkmode=OPAQUE;
  3624.       }
  3625.  
  3626.       int i;
  3627.       int l=cur_ctlcolors->getlen()/sizeof(ctlcolors);
  3628.       for (i=0; i<l; i++) {
  3629.         if (!memcmp((ctlcolors*)cur_ctlcolors->get()+i,&c,sizeof(ctlcolors))) {
  3630.           ent.offsets[1]=i*sizeof(ctlcolors);
  3631.           break;
  3632.         }
  3633.       }
  3634.       if (i>=l) {
  3635.         ent.offsets[1]=cur_ctlcolors->add(&c,sizeof(ctlcolors));
  3636.       }
  3637.  
  3638.       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));
  3639.     }
  3640.     return add_entry(&ent);
  3641.     case TOK_CREATEFONT:
  3642.       ent.which=EW_CREATEFONT;
  3643.       ent.offsets[0]=GetUserVarIndex(line, 1);
  3644.       ent.offsets[1]=add_string(line.gettoken_str(2));
  3645.       SCRIPT_MSG("CreateFont: output=%s \"%s\"",line.gettoken_str(1),line.gettoken_str(2));
  3646.       {
  3647.         int height=0;
  3648.         int weight=0;
  3649.         int flags=0;
  3650.         for (int i = 3; i < line.getnumtokens(); i++) {
  3651.           char *tok=line.gettoken_str(i);
  3652.           if (tok[0]=='/') {
  3653.             if (!lstrcmpi(tok,"/ITALIC")) {
  3654.               SCRIPT_MSG(" /ITALIC");
  3655.               flags|=1;
  3656.             }
  3657.             else if (!lstrcmpi(tok,"/UNDERLINE")) {
  3658.               SCRIPT_MSG(" /UNDERLINE");
  3659.               flags|=2;
  3660.             }
  3661.             else if (!lstrcmpi(tok,"/STRIKE")) {
  3662.               SCRIPT_MSG(" /STRIKE");
  3663.               flags|=4;
  3664.             }
  3665.             else {
  3666.               SCRIPT_MSG("\n");
  3667.               PRINTHELP();
  3668.             }
  3669.           }
  3670.           else {
  3671.             if (!height) {
  3672.               SCRIPT_MSG(" height=%s",tok);
  3673.               height=add_string(tok);
  3674.             }
  3675.             else if (!weight) {
  3676.               SCRIPT_MSG(" weight=%s",tok);
  3677.               weight=add_string(tok);
  3678.             }
  3679.             else {
  3680.               SCRIPT_MSG("\n");
  3681.               PRINTHELP();
  3682.             }
  3683.           }
  3684.         }
  3685.         ent.offsets[2]=height;
  3686.         ent.offsets[3]=weight;
  3687.         ent.offsets[4]=flags;
  3688.       }
  3689.       SCRIPT_MSG("\n");
  3690.     return add_entry(&ent);
  3691.     case TOK_ENABLEWINDOW:
  3692.       ent.which=EW_SHOWWINDOW;
  3693.       ent.offsets[0]=add_string(line.gettoken_str(1));
  3694.       ent.offsets[1]=add_string(line.gettoken_str(2));
  3695.       ent.offsets[3]=1;
  3696.       SCRIPT_MSG("EnableWindow: handle=%s enable=%s\n",line.gettoken_str(1),line.gettoken_str(2));
  3697.     return add_entry(&ent);
  3698.     case TOK_SHOWWINDOW:
  3699.       ent.which=EW_SHOWWINDOW;
  3700.       ent.offsets[0]=add_string(line.gettoken_str(1));
  3701.       ent.offsets[1]=add_string(line.gettoken_str(2));
  3702.       SCRIPT_MSG("ShowWindow: handle=%s show state=%s\n",line.gettoken_str(1),line.gettoken_str(2));
  3703.     return add_entry(&ent);
  3704.     case TOK_HIDEWINDOW:
  3705.       ent.which=EW_SHOWWINDOW;
  3706.       ent.offsets[0]=add_string("$HWNDPARENT");
  3707.       ent.offsets[1]=add_string("0"/*SW_HIDE*/);
  3708.       ent.offsets[2]=1;
  3709.       SCRIPT_MSG("HideWindow\n");
  3710.     return add_entry(&ent);
  3711.     case TOK_BRINGTOFRONT:
  3712.     {
  3713.       int ret;
  3714.       ent.which=EW_SHOWWINDOW;
  3715.       ent.offsets[0]=add_string("$HWNDPARENT");
  3716.       ent.offsets[1]=add_string("5"/*SW_SHOW*/);
  3717.       ret = add_entry(&ent);
  3718.       if (ret != PS_OK) return ret;
  3719.       ent.which=EW_BRINGTOFRONT;
  3720.       ent.offsets[0]=0;
  3721.       ent.offsets[1]=0;
  3722.       SCRIPT_MSG("BringToFront\n");
  3723.     }
  3724.     return add_entry(&ent);
  3725. #else//NSIS_CONFIG_ENHANCEDUI_SUPPORT
  3726.     case TOK_GETDLGITEM:
  3727.     case TOK_SETCTLCOLORS:
  3728.     case TOK_SHOWWINDOW:
  3729.     case TOK_BRINGTOFRONT:
  3730.     case TOK_CREATEFONT:
  3731.     case TOK_HIDEWINDOW:
  3732.     case TOK_ENABLEWINDOW:
  3733.       ERROR_MSG("Error: %s specified, NSIS_CONFIG_ENHANCEDUI_SUPPORT not defined.\n",  line.gettoken_str(0));
  3734.     return PS_ERROR;
  3735. #endif//NSIS_CONFIG_ENHANCEDUI_SUPPORT
  3736. #else//!NSIS_SUPPORT_HWNDS
  3737.     case TOK_ISWINDOW:
  3738.     case TOK_SENDMESSAGE:
  3739.     case TOK_FINDWINDOW:
  3740.     case TOK_GETDLGITEM:
  3741.     case TOK_SETCTLCOLORS:
  3742.     case TOK_SHOWWINDOW:
  3743.     case TOK_ENABLEWINDOW:
  3744.     case TOK_CREATEFONT:
  3745.     case TOK_HIDEWINDOW:
  3746.     case TOK_BRINGTOFRONT:
  3747.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_HWNDS not defined.\n",  line.gettoken_str(0));
  3748.     return PS_ERROR;
  3749. #endif//!NSIS_SUPPORT_HWNDS
  3750.     case TOK_DELETE:
  3751. #ifdef NSIS_SUPPORT_DELETE
  3752.       {
  3753.         int a=1;
  3754.         ent.which=EW_DELETEFILE;
  3755.         if (!stricmp(line.gettoken_str(a),"/REBOOTOK"))
  3756.         {
  3757.           a++;
  3758.           ent.offsets[1]=1;
  3759. #ifndef NSIS_SUPPORT_MOVEONREBOOT
  3760.           ERROR_MSG("Error: /REBOOTOK specified, NSIS_SUPPORT_MOVEONREBOOT not defined\n");
  3761.           PRINTHELP()
  3762. #endif
  3763.         }
  3764.         else if (line.gettoken_str(1)[0]=='/')
  3765.         {
  3766.           a=line.getnumtokens();
  3767.         }
  3768.         if (line.getnumtokens() != a+1) PRINTHELP()
  3769.         ent.offsets[0]=add_string(line.gettoken_str(a));
  3770.         SCRIPT_MSG("Delete: %s\"%s\"\n",ent.offsets[1]?"/REBOOTOK ":"",line.gettoken_str(a));
  3771.  
  3772.         DefineInnerLangString(NLF_DEL_FILE);
  3773. #ifdef NSIS_SUPPORT_MOVEONREBOOT
  3774.         DefineInnerLangString(NLF_DEL_ON_REBOOT);
  3775. #endif
  3776.       }
  3777.     return add_entry(&ent);
  3778. #else//!NSIS_SUPPORT_DELETE
  3779.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_DELETE not defined.\n",  line.gettoken_str(0));
  3780.     return PS_ERROR;
  3781. #endif//!NSIS_SUPPORT_DELETE
  3782.     case TOK_RMDIR:
  3783. #ifdef NSIS_SUPPORT_RMDIR
  3784.       {
  3785.         int a=1;
  3786.         ent.which=EW_RMDIR;
  3787.         if (!stricmp(line.gettoken_str(1),"/r"))
  3788.         {
  3789.           if (line.getnumtokens() < 3) PRINTHELP()
  3790.           a++;
  3791.           ent.offsets[1]=1;
  3792.         }
  3793.         else if (!stricmp(line.gettoken_str(1),"/REBOOTOK"))
  3794.         {
  3795.           if (line.getnumtokens() < 3) PRINTHELP()
  3796.           a++;
  3797.           ent.offsets[1]=2;
  3798.         }          
  3799.         else if (line.gettoken_str(1)[0]=='/') PRINTHELP()
  3800.         ent.offsets[0]=add_string(line.gettoken_str(a));
  3801.         SCRIPT_MSG("RMDir: %s%s\"%s\"\n",a==1?"":line.gettoken_str(1),ent.offsets[1]?" ":"",line.gettoken_str(a));
  3802.  
  3803.         DefineInnerLangString(NLF_REMOVE_DIR);
  3804.       }
  3805.     return add_entry(&ent);
  3806. #else//!NSIS_SUPPORT_RMDIR
  3807.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_RMDIR not defined.\n",  line.gettoken_str(0));
  3808.     return PS_ERROR;
  3809. #endif//!NSIS_SUPPORT_RMDIR
  3810.     case TOK_RESERVEFILE:
  3811.     case TOK_FILE:
  3812. #ifdef NSIS_SUPPORT_FILE
  3813.       {
  3814.         int a=1,attrib=0,rec=0,fatal=1;
  3815.         if (!stricmp(line.gettoken_str(a),"/nonfatal")) {
  3816.           fatal=0;
  3817.           a++;
  3818.         }
  3819.         if (which_token == TOK_FILE && !stricmp(line.gettoken_str(a),"/a"))
  3820.         {
  3821.           attrib=1;
  3822.           a++;
  3823.         }
  3824.         if (!stricmp(line.gettoken_str(a),"/r"))
  3825.         {
  3826.           rec=1;
  3827.           a++;
  3828.         }
  3829.         else if (which_token == TOK_FILE && !strnicmp(line.gettoken_str(a),"/oname=",7))
  3830.         {
  3831.           char *on=line.gettoken_str(a)+7;
  3832.           a++;
  3833.           if (!*on||line.getnumtokens()!=a+1||strstr(on,"*") || strstr(on,"?")) PRINTHELP()
  3834.  
  3835.           int tf=0;
  3836.           int v=do_add_file(line.gettoken_str(a), attrib, 0, linecnt,&tf,on);
  3837.           if (v != PS_OK) return v;
  3838.           if (tf > 1) PRINTHELP()
  3839.           if (!tf)
  3840.           {
  3841.             if (fatal)
  3842.             {
  3843.               ERROR_MSG("%sFile: \"%s\" -> no files found.\n",(which_token == TOK_FILE)?"":"Reserve",line.gettoken_str(a));
  3844.               PRINTHELP()
  3845.             }
  3846.             else
  3847.             {
  3848.               warning_fl("%sFile: \"%s\" -> no files found",(which_token == TOK_FILE)?"":"Reserve",line.gettoken_str(a));
  3849.             }
  3850.           }
  3851.  
  3852.           return PS_OK;
  3853.         }
  3854.         else if (line.gettoken_str(a)[0] == '/') PRINTHELP()
  3855.         if (line.getnumtokens()<a+1) PRINTHELP()
  3856.         while (a < line.getnumtokens())
  3857.         {
  3858.           if (line.gettoken_str(a)[0]=='/') PRINTHELP()
  3859.           char buf[32];
  3860.           char *t=line.gettoken_str(a++);
  3861.           if (t[0] && CharNext(t)[0] == ':' && CharNext(t)[1] == '\\' && !CharNext(t)[2])
  3862.           {
  3863.             strcpy(buf,"X:\\*.*");
  3864.             buf[0]=t[0];
  3865.             t=buf;
  3866.           }
  3867.           int tf=0;
  3868.           int v=do_add_file(t, attrib, rec, linecnt,&tf,NULL,which_token == TOK_FILE);
  3869.           if (v != PS_OK) return v;
  3870.           if (!tf)
  3871.           {
  3872.             ERROR_MSG("%sFile: \"%s\" -> no files found.\n",(which_token == TOK_FILE)?"":"Reserve",t);
  3873.             if (fatal) PRINTHELP()
  3874.           }
  3875.         }
  3876.       }
  3877.     return PS_OK;
  3878. #else//!NSIS_SUPPORT_FILE
  3879.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_FILE not defined.\n",  line.gettoken_str(0));
  3880.     return PS_ERROR;
  3881. #endif//!NSIS_SUPPORT_FILE
  3882. #ifdef NSIS_SUPPORT_COPYFILES
  3883.     case TOK_COPYFILES:
  3884.       {
  3885.         ent.which=EW_COPYFILES;
  3886.         ent.offsets[2]=FOF_NOCONFIRMATION|FOF_NOCONFIRMMKDIR|FOF_NOERRORUI|FOF_SIMPLEPROGRESS;
  3887.  
  3888.         int a=1;
  3889.         int x;
  3890.         for (x = 0; x < 2; x ++)
  3891.         {
  3892.           if (!stricmp(line.gettoken_str(a),"/SILENT"))
  3893.           {
  3894.             a++;
  3895.             ent.offsets[2]&=~FOF_SIMPLEPROGRESS;
  3896.             ent.offsets[2]|=FOF_SILENT;
  3897.           }
  3898.           else if (!stricmp(line.gettoken_str(a),"/FILESONLY"))
  3899.           {
  3900.             a++;
  3901.             ent.offsets[2]|=FOF_FILESONLY;
  3902.           }
  3903.           else if (line.gettoken_str(a)[0]=='/') PRINTHELP()
  3904.           else break;
  3905.         }
  3906.         ent.offsets[0]=add_string(line.gettoken_str(a));
  3907.         ent.offsets[1]=add_string(line.gettoken_str(a+1));
  3908.         int s;
  3909.         int size_kb=line.gettoken_int(a+2,&s);
  3910.         if (!s && line.gettoken_str(a+2)[0]) PRINTHELP()
  3911.         section_add_size_kb(size_kb);
  3912.         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);
  3913.  
  3914.         DefineInnerLangString(NLF_COPY_FAILED);
  3915.         DefineInnerLangString(NLF_COPY_TO);
  3916.       }
  3917.     return add_entry(&ent);
  3918. #else//!NSIS_SUPPORT_COPYFILES
  3919.     case TOK_COPYFILES:
  3920.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_COPYFILES not defined.\n",  line.gettoken_str(0));
  3921.     return PS_ERROR;
  3922. #endif//!NSIS_SUPPORT_COPYFILES
  3923.  
  3924.     case TOK_SETFILEATTRIBUTES:
  3925.       {
  3926.         #define MBD(x) {x,#x},
  3927.         struct
  3928.         {
  3929.           int id;
  3930.           char *str;
  3931.         } list[]=
  3932.         {
  3933.           MBD(FILE_ATTRIBUTE_NORMAL)
  3934.           MBD(FILE_ATTRIBUTE_ARCHIVE)
  3935.           MBD(FILE_ATTRIBUTE_HIDDEN)
  3936.           MBD(FILE_ATTRIBUTE_OFFLINE)
  3937.           MBD(FILE_ATTRIBUTE_READONLY)
  3938.           MBD(FILE_ATTRIBUTE_SYSTEM)
  3939.           MBD(FILE_ATTRIBUTE_TEMPORARY)
  3940.           {FILE_ATTRIBUTE_NORMAL,"NORMAL"},
  3941.           {FILE_ATTRIBUTE_ARCHIVE,"ARCHIVE"},
  3942.           {FILE_ATTRIBUTE_HIDDEN,"HIDDEN"},
  3943.           {FILE_ATTRIBUTE_OFFLINE,"OFFLINE"},
  3944.           {FILE_ATTRIBUTE_READONLY,"READONLY"},
  3945.           {FILE_ATTRIBUTE_SYSTEM,"SYSTEM"},
  3946.           {FILE_ATTRIBUTE_TEMPORARY,"TEMPORARY"},
  3947.           {FILE_ATTRIBUTE_NORMAL,"0"},
  3948.         };
  3949.         #undef MBD
  3950.         int r=0;
  3951.         int x;
  3952.         char *p=line.gettoken_str(2);
  3953.  
  3954.         while (*p)
  3955.         {
  3956.           char *np=p;
  3957.           while (*np && *np != '|') np++;
  3958.           if (*np) *np++=0;
  3959.           for (x  =0 ; x < sizeof(list)/sizeof(list[0]) && stricmp(list[x].str,p); x ++);
  3960.  
  3961.           if (x < sizeof(list)/sizeof(list[0]))
  3962.           {
  3963.             r|=list[x].id;
  3964.           }
  3965.           else PRINTHELP()
  3966.           p=np;
  3967.         }
  3968.         ent.which=EW_SETFILEATTRIBUTES;
  3969.         ent.offsets[0]=add_string(line.gettoken_str(1));
  3970.         ent.offsets[1]=r;
  3971.       }
  3972.     return add_entry(&ent);
  3973.     case TOK_SLEEP:
  3974.       {
  3975.         ent.which=EW_SLEEP;
  3976.         ent.offsets[0]=add_string(line.gettoken_str(1));
  3977.         SCRIPT_MSG("Sleep: %s ms\n",line.gettoken_str(1));
  3978.       }
  3979.     return add_entry(&ent);
  3980.     case TOK_IFFILEEXISTS:
  3981.       ent.which=EW_IFFILEEXISTS;
  3982.       ent.offsets[0] = add_string(line.gettoken_str(1));
  3983.       if (process_jump(line,2,&ent.offsets[1]) ||
  3984.           process_jump(line,3,&ent.offsets[2])) PRINTHELP()
  3985.       SCRIPT_MSG("IfFileExists: \"%s\" ? %s : %s\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3));
  3986.     return add_entry(&ent);
  3987.     case TOK_QUIT:
  3988.       ent.which=EW_QUIT;
  3989.       SCRIPT_MSG("Quit\n");
  3990.     return add_entry(&ent);
  3991.     case TOK_ABORT:
  3992.       ent.which=EW_ABORT;
  3993.       ent.offsets[0] = add_string(line.gettoken_str(1));
  3994.       SCRIPT_MSG("Abort: \"%s\"\n",line.gettoken_str(1));
  3995.     return add_entry(&ent);
  3996.     case TOK_SETDETAILSVIEW:
  3997.       {
  3998.         int v=line.gettoken_enum(1,"hide\0show\0");
  3999.         ent.which=EW_CHDETAILSVIEW;
  4000.         if (v < 0) PRINTHELP()
  4001.         ent.offsets[0] = v?SW_SHOWNA:SW_HIDE;
  4002.         ent.offsets[1] = v?SW_HIDE:SW_SHOWNA;
  4003.         SCRIPT_MSG("SetDetailsView: %s\n",line.gettoken_str(1));
  4004.       }
  4005.     return add_entry(&ent);
  4006.     case TOK_SETDETAILSPRINT:
  4007.       ent.which=EW_UPDATETEXT;
  4008.       ent.offsets[0] = 0;
  4009.       ent.offsets[1] = line.gettoken_enum(1,"lastused\0listonly\0textonly\0both\0none\0");
  4010.       if (ent.offsets[1] < 0) PRINTHELP();
  4011.       switch (ent.offsets[1]) {
  4012.         case 0:
  4013.           ent.offsets[1]=8;
  4014.         break;
  4015.         case 1:
  4016.         case 2:
  4017.         case 3:
  4018.           ent.offsets[1]<<=1;
  4019.         break;
  4020.         case 4:
  4021.           ent.offsets[1]=16;
  4022.         break;
  4023.       }
  4024.       SCRIPT_MSG("SetDetailsPrint: %s\n",line.gettoken_str(1));
  4025.     return add_entry(&ent);
  4026.     case TOK_SETAUTOCLOSE:
  4027.     {
  4028.       ent.which=EW_SETFLAG;
  4029.       ent.offsets[0]=FLAG_OFFSET(autoclose);
  4030.       int k=line.gettoken_enum(1,"false\0true\0");
  4031.       if (k < 0) PRINTHELP()
  4032.       ent.offsets[1]=add_intstring(k);
  4033.       SCRIPT_MSG("SetAutoClose: %s\n",line.gettoken_str(1));
  4034.     }
  4035.     return add_entry(&ent);
  4036.     case TOK_IFERRORS:
  4037.       ent.which=EW_IFFLAG;
  4038.       if (process_jump(line,1,&ent.offsets[0]) ||
  4039.           process_jump(line,2,&ent.offsets[1])) PRINTHELP()
  4040.       ent.offsets[2]=FLAG_OFFSET(exec_error);
  4041.       ent.offsets[3]=0;//new value mask - clean error
  4042.       SCRIPT_MSG("IfErrors ?%s:%s\n",line.gettoken_str(1),line.gettoken_str(2));
  4043.     return add_entry(&ent);
  4044.     case TOK_IFABORT:
  4045.       ent.which=EW_IFFLAG;
  4046.       if (process_jump(line,1,&ent.offsets[0]) ||
  4047.           process_jump(line,2,&ent.offsets[1])) PRINTHELP()
  4048.       ent.offsets[2]=FLAG_OFFSET(abort);
  4049.       ent.offsets[3]=~0;//new value mask - keep flag
  4050.       SCRIPT_MSG("IfAbort ?%s:%s\n",line.gettoken_str(1),line.gettoken_str(2));
  4051.     return add_entry(&ent);
  4052.     case TOK_CLEARERRORS:
  4053.       ent.which=EW_SETFLAG;
  4054.       ent.offsets[0]=FLAG_OFFSET(exec_error);
  4055.       ent.offsets[1]=add_intstring(0);
  4056.       SCRIPT_MSG("ClearErrors\n");
  4057.     return add_entry(&ent);
  4058.     case TOK_SETERRORS:
  4059.       ent.which=EW_SETFLAG;
  4060.       ent.offsets[0]=FLAG_OFFSET(exec_error);
  4061.       ent.offsets[1]=add_intstring(1);
  4062.       SCRIPT_MSG("SetErrors\n");
  4063.     return add_entry(&ent);
  4064. #ifdef NSIS_SUPPORT_STROPTS
  4065.     case TOK_STRLEN:
  4066.       ent.which=EW_STRLEN;
  4067.       ent.offsets[0]=GetUserVarIndex(line, 1);
  4068.       ent.offsets[1]=add_string(line.gettoken_str(2));
  4069.       if (ent.offsets[0] < 0) PRINTHELP()
  4070.       SCRIPT_MSG("StrLen %s \"%s\"\n",line.gettoken_str(1),line.gettoken_str(2));
  4071.     return add_entry(&ent);
  4072.     case TOK_STRCPY:
  4073.       ent.which=EW_ASSIGNVAR;
  4074.       ent.offsets[0]=GetUserVarIndex(line, 1);
  4075.       ent.offsets[1]=add_string(line.gettoken_str(2));
  4076.       ent.offsets[2]=add_string(line.gettoken_str(3));
  4077.       ent.offsets[3]=add_string(line.gettoken_str(4));
  4078.  
  4079.       if (ent.offsets[0] < 0) PRINTHELP()
  4080.       SCRIPT_MSG("StrCpy %s \"%s\" (%s) (%s)\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4));
  4081.     return add_entry(&ent);
  4082.     case TOK_GETFUNCTIONADDR:
  4083.       ent.which=EW_GETFUNCTIONADDR;
  4084.       ent.offsets[0]=GetUserVarIndex(line, 1);
  4085.       ent.offsets[1]=ns_func.add(line.gettoken_str(2),0);
  4086.       ent.offsets[2]=0;
  4087.       ent.offsets[3]=0;
  4088.       if (ent.offsets[0] < 0) PRINTHELP()
  4089.       SCRIPT_MSG("GetFunctionAddress: %s %s",line.gettoken_str(1),line.gettoken_str(2));
  4090.     return add_entry(&ent);
  4091.     case TOK_GETLABELADDR:
  4092.       ent.which=EW_GETLABELADDR;
  4093.       ent.offsets[0]=GetUserVarIndex(line, 1);
  4094.       if (ent.offsets[0] < 0 || process_jump(line,2,&ent.offsets[1])) PRINTHELP()
  4095.       ent.offsets[2]=0;
  4096.       ent.offsets[3]=0;
  4097.       SCRIPT_MSG("GetLabelAddress: %s %s",line.gettoken_str(1),line.gettoken_str(2));
  4098.     return add_entry(&ent);
  4099.     case TOK_GETCURRENTADDR:
  4100.       ent.which=EW_ASSIGNVAR;
  4101.       ent.offsets[0]=GetUserVarIndex(line, 1);
  4102.       {
  4103.         char buf[32];
  4104.         wsprintf(buf,"%d",1+(cur_header->blocks[NB_ENTRIES].num));
  4105.         ent.offsets[1]=add_string(buf);
  4106.       }
  4107.       if (ent.offsets[0] < 0) PRINTHELP()
  4108.       ent.offsets[2]=0;
  4109.       ent.offsets[3]=0;
  4110.       SCRIPT_MSG("GetCurrentAddress: %s %s",line.gettoken_str(1));
  4111.     return add_entry(&ent);
  4112.     case TOK_STRCMP:
  4113.       ent.which=EW_STRCMP;
  4114.       ent.offsets[0]=add_string(line.gettoken_str(1));
  4115.       ent.offsets[1]=add_string(line.gettoken_str(2));
  4116.       if (process_jump(line,3,&ent.offsets[2]) ||
  4117.           process_jump(line,4,&ent.offsets[3])) PRINTHELP()
  4118.       SCRIPT_MSG("StrCmp \"%s\" \"%s\" equal=%s, nonequal=%s\n",line.gettoken_str(1),line.gettoken_str(2), line.gettoken_str(3),line.gettoken_str(4));
  4119.     return add_entry(&ent);
  4120.     case TOK_GETDLLVERSIONLOCAL:
  4121.       {
  4122.         char buf[128];
  4123.         DWORD low, high;
  4124.         DWORD s,d;
  4125.         int flag=0;
  4126.         int alloced=0;
  4127.         char *path=line.gettoken_str(1);
  4128.         if (!((*path == '\\' && path[1] == '\\') || (*path && path[1] == ':'))) {
  4129.           size_t pathlen=lstrlen(path)+GetCurrentDirectory(0, buf)+2;
  4130.           char *nrpath=(char *)malloc(pathlen);
  4131.           alloced=1;
  4132.           GetCurrentDirectory(pathlen, nrpath);
  4133.           if (path[0] != '\\')
  4134.             strcat(nrpath,"\\");
  4135.           else if (nrpath[1] == ':') {
  4136.             nrpath[2]=0;
  4137.           }
  4138.           else {
  4139.             char *p=nrpath+2;
  4140.             while (*p!='\\') p++;
  4141.             *p=0;
  4142.           }
  4143.           strcat(nrpath,path);
  4144.           FILE *f=fopen(nrpath, "r");
  4145.           if (f) {
  4146.             path=nrpath;
  4147.             fclose(f);
  4148.           }
  4149.           else {
  4150.             free(nrpath);
  4151.             alloced=0;
  4152.           }
  4153.         }
  4154.         s=GetFileVersionInfoSize(path,&d);
  4155.         if (s)
  4156.         {
  4157.           void *buf;
  4158.           buf=(void *)GlobalAlloc(GPTR,s);
  4159.           if (buf)
  4160.           {
  4161.             UINT uLen;
  4162.             VS_FIXEDFILEINFO *pvsf;
  4163.             if (GetFileVersionInfo(path,0,s,buf) && VerQueryValue(buf,"\\",(void**)&pvsf,&uLen))
  4164.             {
  4165.               low=pvsf->dwFileVersionLS;
  4166.               high=pvsf->dwFileVersionMS;
  4167.               flag=1;
  4168.             }
  4169.             GlobalFree(buf);
  4170.           }
  4171.         }
  4172.         if (alloced) free(path);
  4173.         if (!flag)
  4174.         {
  4175.           ERROR_MSG("GetDLLVersionLocal: error reading version info from \"%s\"\n",line.gettoken_str(1));
  4176.           return PS_ERROR;
  4177.         }
  4178.         ent.which=EW_ASSIGNVAR;
  4179.         ent.offsets[0]=GetUserVarIndex(line, 2);
  4180.         wsprintf(buf,"%u",high);
  4181.         ent.offsets[1]=add_string(buf);
  4182.         ent.offsets[2]=0;
  4183.         ent.offsets[3]=0;
  4184.         if (ent.offsets[0]<0) PRINTHELP()
  4185.         add_entry(&ent);
  4186.  
  4187.         ent.offsets[0]=GetUserVarIndex(line, 3);
  4188.         wsprintf(buf,"%u",low);
  4189.         ent.offsets[1]=add_string(buf);
  4190.         ent.offsets[2]=0;
  4191.         ent.offsets[3]=0;
  4192.         if (ent.offsets[0]<0) PRINTHELP()
  4193.         SCRIPT_MSG("GetDLLVersionLocal: %s (%u,%u)->(%s,%s)\n",
  4194.           line.gettoken_str(1),high,low,line.gettoken_str(2),line.gettoken_str(3));
  4195.       }
  4196.     return add_entry(&ent);
  4197.     case TOK_GETFILETIMELOCAL:
  4198.       {
  4199.         char buf[129];
  4200.         DWORD high,low;
  4201.         int flag=0;
  4202.         HANDLE hFile=CreateFile(line.gettoken_str(1),0,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
  4203.         if (hFile != INVALID_HANDLE_VALUE)
  4204.         {
  4205.           FILETIME ft;
  4206.           if (GetFileTime(hFile,NULL,NULL,&ft))
  4207.           {
  4208.             high=ft.dwHighDateTime;
  4209.             low=ft.dwLowDateTime;
  4210.             flag=1;
  4211.           }
  4212.           CloseHandle(hFile);
  4213.         }
  4214.         if (!flag)
  4215.         {
  4216.           ERROR_MSG("GetFileTimeLocal: error reading date from \"%s\"\n",line.gettoken_str(1));
  4217.           return PS_ERROR;
  4218.         }
  4219.  
  4220.         ent.which=EW_ASSIGNVAR;
  4221.         ent.offsets[0]=GetUserVarIndex(line, 2);
  4222.         wsprintf(buf,"%u",high);
  4223.         ent.offsets[1]=add_string(buf);
  4224.         ent.offsets[2]=0;
  4225.         ent.offsets[3]=0;
  4226.         if (ent.offsets[0]<0) PRINTHELP()
  4227.         add_entry(&ent);
  4228.  
  4229.         ent.offsets[0]=GetUserVarIndex(line, 3);
  4230.         wsprintf(buf,"%u",low);
  4231.         ent.offsets[1]=add_string(buf);
  4232.         ent.offsets[2]=0;
  4233.         ent.offsets[3]=0;
  4234.         if (ent.offsets[0]<0) PRINTHELP()
  4235.         SCRIPT_MSG("GetFileTimeLocal: %s (%u,%u)->(%s,%s)\n",
  4236.           line.gettoken_str(1),high,low,line.gettoken_str(2),line.gettoken_str(3));
  4237.       }
  4238.     return add_entry(&ent);
  4239.  
  4240. #else//!NSIS_SUPPORT_STROPTS
  4241.     case TOK_GETDLLVERSIONLOCAL:
  4242.     case TOK_GETFILETIMELOCAL:
  4243.     case TOK_GETFUNCTIONADDR:
  4244.     case TOK_GETLABELADDR:
  4245.     case TOK_GETCURRENTADDR:
  4246.     case TOK_STRLEN:
  4247.     case TOK_STRCPY:
  4248.     case TOK_STRCMP:
  4249.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_STROPTS not defined.\n",  line.gettoken_str(0));
  4250.     return PS_ERROR;
  4251. #endif//!NSIS_SUPPORT_STROPTS
  4252. #ifdef NSIS_SUPPORT_INIFILES
  4253.     case TOK_DELETEINISEC:
  4254.     case TOK_DELETEINISTR:
  4255.       {
  4256.         char *vname="";
  4257.         char *space="";
  4258.         ent.which=EW_WRITEINI;
  4259.         ent.offsets[0]=add_string(line.gettoken_str(2)); // section name
  4260.         if (line.getnumtokens() > 3)
  4261.         {
  4262.           vname=line.gettoken_str(3);
  4263.           ent.offsets[1]=add_string(vname); // value name
  4264.           space=" ";
  4265.         }
  4266.         else ent.offsets[1]=0;
  4267.         ent.offsets[2]=0;
  4268.         ent.offsets[3]=add_string(line.gettoken_str(1));
  4269.         SCRIPT_MSG("DeleteINI%s: [%s] %s%sin %s\n",*vname?"Str":"Sec",
  4270.           line.gettoken_str(2),vname,space,line.gettoken_str(1));
  4271.       }
  4272.     return add_entry(&ent);
  4273.     case TOK_FLUSHINI:
  4274.       ent.which=EW_WRITEINI;
  4275.       ent.offsets[3]=add_string(line.gettoken_str(1));
  4276.       SCRIPT_MSG("FlushINI: %s\n",line.gettoken_str(1));
  4277.     return add_entry(&ent);
  4278.     case TOK_WRITEINISTR:
  4279.       ent.which=EW_WRITEINI;
  4280.       ent.offsets[0]=add_string(line.gettoken_str(2));
  4281.       ent.offsets[1]=add_string(line.gettoken_str(3));
  4282.       ent.offsets[2]=add_string(line.gettoken_str(4));
  4283.       ent.offsets[3]=add_string(line.gettoken_str(1));
  4284.       ent.offsets[4]=1; // write
  4285.       SCRIPT_MSG("WriteINIStr: [%s] %s=%s in %s\n",
  4286.         line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4),line.gettoken_str(1));
  4287.     return add_entry(&ent);
  4288.     case TOK_READINISTR:
  4289.       ent.which=EW_READINISTR;
  4290.       ent.offsets[0]=GetUserVarIndex(line, 1);
  4291.       if (ent.offsets[0] < 0) PRINTHELP()
  4292.       ent.offsets[1]=add_string(line.gettoken_str(3));
  4293.       ent.offsets[2]=add_string(line.gettoken_str(4));
  4294.       ent.offsets[3]=add_string(line.gettoken_str(2));
  4295.       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));
  4296.     return add_entry(&ent);
  4297. #else//!NSIS_SUPPORT_INIFILES
  4298.     case TOK_DELETEINISEC:
  4299.     case TOK_DELETEINISTR:
  4300.     case TOK_FLUSHINI:
  4301.     case TOK_WRITEINISTR:
  4302.     case TOK_READINISTR:
  4303.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_INIFILES not defined.\n",  line.gettoken_str(0));
  4304.     return PS_ERROR;
  4305. #endif//!NSIS_SUPPORT_INIFILES
  4306.     case TOK_DETAILPRINT:
  4307.       ent.which=EW_UPDATETEXT;
  4308.       ent.offsets[0]=add_string(line.gettoken_str(1));
  4309.       ent.offsets[1]=0;
  4310.       SCRIPT_MSG("DetailPrint: \"%s\"\n",line.gettoken_str(1));
  4311.     return add_entry(&ent);
  4312. #ifdef NSIS_SUPPORT_FNUTIL
  4313.     case TOK_GETTEMPFILENAME:
  4314.       ent.which=EW_GETTEMPFILENAME;
  4315.       ent.offsets[0]=GetUserVarIndex(line, 1);
  4316.       if (line.getnumtokens() == 3)
  4317.         ent.offsets[1]=add_string(line.gettoken_str(2));
  4318.       else
  4319.         ent.offsets[1]=add_string("$TEMP");
  4320.       if (ent.offsets[0]<0) PRINTHELP()
  4321.       SCRIPT_MSG("GetTempFileName -> %s\n",line.gettoken_str(1));
  4322.     return add_entry(&ent);
  4323.     case TOK_GETFULLPATHNAME:
  4324.       {
  4325.         int a=0;
  4326.         ent.which=EW_GETFULLPATHNAME;
  4327.         if (line.getnumtokens()==4 && !stricmp(line.gettoken_str(1),"/SHORT")) a++;
  4328.         else if (line.getnumtokens()==4 || *line.gettoken_str(1)=='/') PRINTHELP()
  4329.         ent.offsets[0]=add_string(line.gettoken_str(2+a));
  4330.         ent.offsets[1]=GetUserVarIndex(line, 1+a);
  4331.         ent.offsets[2]=!a;
  4332.         if (ent.offsets[0]<0) PRINTHELP()
  4333.         SCRIPT_MSG("GetFullPathName: %s->%s (%d)\n",
  4334.           line.gettoken_str(2+a),line.gettoken_str(1+a),a?"sfn":"lfn");
  4335.       }
  4336.     return add_entry(&ent);
  4337.     case TOK_SEARCHPATH:
  4338.       ent.which=EW_SEARCHPATH;
  4339.       ent.offsets[0]=GetUserVarIndex(line, 1);
  4340.       if (ent.offsets[0] < 0) PRINTHELP()
  4341.       ent.offsets[1]=add_string(line.gettoken_str(2));
  4342.       SCRIPT_MSG("SearchPath %s %s\n",line.gettoken_str(1),line.gettoken_str(2));
  4343.     return add_entry(&ent);
  4344. #else
  4345.     case TOK_SEARCHPATH:
  4346.     case TOK_GETTEMPFILENAME:
  4347.     case TOK_GETFULLPATHNAME:
  4348.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_FNUTIL not defined.\n",  line.gettoken_str(0));
  4349.       return PS_ERROR;
  4350. #endif
  4351.     case TOK_GETDLLVERSION:
  4352. #ifdef NSIS_SUPPORT_GETDLLVERSION
  4353.       ent.which=EW_GETDLLVERSION;
  4354.       ent.offsets[0]=GetUserVarIndex(line, 2);
  4355.       ent.offsets[1]=GetUserVarIndex(line, 3);
  4356.       ent.offsets[2]=add_string(line.gettoken_str(1));
  4357.       if (ent.offsets[0]<0 || ent.offsets[1]<0) PRINTHELP()
  4358.       SCRIPT_MSG("GetDLLVersion: %s->%s,%s\n",
  4359.         line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3));
  4360.     return add_entry(&ent);
  4361. #else//!NSIS_SUPPORT_GETDLLVERSION
  4362.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_GETDLLVERSION not defined.\n",  line.gettoken_str(0));
  4363.       return PS_ERROR;
  4364. #endif//!NSIS_SUPPORT_GETDLLVERSION
  4365.     case TOK_GETFILETIME:
  4366. #ifdef NSIS_SUPPORT_GETFILETIME
  4367.       ent.which=EW_GETFILETIME;
  4368.       ent.offsets[0]=GetUserVarIndex(line, 2);
  4369.       ent.offsets[1]=GetUserVarIndex(line, 3);
  4370.       ent.offsets[2]=add_string(line.gettoken_str(1));
  4371.       if (ent.offsets[0]<0 || ent.offsets[1]<0) PRINTHELP()
  4372.       SCRIPT_MSG("GetFileTime: %s->%s,%s\n",
  4373.         line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3));
  4374.     return add_entry(&ent);
  4375. #else//!NSIS_SUPPORT_GETFILETIME
  4376.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_GETFILETIME not defined.\n",  line.gettoken_str(0));
  4377.       return PS_ERROR;
  4378. #endif//!NSIS_SUPPORT_GETFILETIME
  4379. #ifdef NSIS_SUPPORT_INTOPTS
  4380.     case TOK_INTOP:
  4381.       ent.which=EW_INTOP;
  4382.       ent.offsets[0]=GetUserVarIndex(line, 1);
  4383.       ent.offsets[3]=line.gettoken_enum(3,"+\0-\0*\0/\0|\0&\0^\0!\0||\0&&\0%\0~\0");
  4384.       if (ent.offsets[0] < 0 || ent.offsets[3]<0 || ((ent.offsets[3] == 7 || ent.offsets[3]==11) && line.getnumtokens()>4)) PRINTHELP()
  4385.       ent.offsets[1]=add_string(line.gettoken_str(2));
  4386.       if (ent.offsets[3] != 7 && ent.offsets[3] != 11) ent.offsets[2]=add_string(line.gettoken_str(4));
  4387.       if (ent.offsets[3] == 11) {
  4388.         ent.offsets[3]=6;
  4389.         ent.offsets[2]=add_string("0xFFFFFFFF");
  4390.       }
  4391.       SCRIPT_MSG("IntOp: %s=%s%s%s\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4));
  4392.     return add_entry(&ent);
  4393.     case TOK_INTFMT:
  4394.       ent.which=EW_INTFMT;
  4395.       ent.offsets[0]=GetUserVarIndex(line, 1);
  4396.       if (ent.offsets[0]<0) PRINTHELP()
  4397.       ent.offsets[1]=add_string(line.gettoken_str(2));
  4398.       ent.offsets[2]=add_string(line.gettoken_str(3));
  4399.       SCRIPT_MSG("IntFmt: %s->%s (fmt:%s)\n",line.gettoken_str(3),line.gettoken_str(1),line.gettoken_str(2));
  4400.     return add_entry(&ent);
  4401.     case TOK_INTCMP:
  4402.     case TOK_INTCMPU:
  4403.       ent.which=EW_INTCMP;
  4404.       ent.offsets[0]=add_string(line.gettoken_str(1));
  4405.       ent.offsets[1]=add_string(line.gettoken_str(2));
  4406.       ent.offsets[5]=which_token == TOK_INTCMPU;
  4407.       if (process_jump(line,3,&ent.offsets[2]) ||
  4408.           process_jump(line,4,&ent.offsets[3]) ||
  4409.           process_jump(line,5,&ent.offsets[4]))  PRINTHELP()
  4410.       SCRIPT_MSG("%s %s:%s equal=%s, < %s, > %s\n",line.gettoken_str(0),
  4411.         line.gettoken_str(1),line.gettoken_str(2), line.gettoken_str(3),line.gettoken_str(4),line.gettoken_str(5));
  4412.     return add_entry(&ent);
  4413. #else//!NSIS_SUPPORT_INTOPTS
  4414.     case TOK_INTOP:
  4415.     case TOK_INTCMP:
  4416.     case TOK_INTFMT:
  4417.     case TOK_INTCMPU:
  4418.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_INTOPTS not defined.\n",  line.gettoken_str(0));
  4419.       return PS_ERROR;
  4420. #endif//!NSIS_SUPPORT_INTOPTS
  4421. #ifdef NSIS_SUPPORT_REGISTRYFUNCTIONS
  4422.     case TOK_READREGSTR:
  4423.     case TOK_READREGDWORD:
  4424.       {
  4425.         ent.which=EW_READREGSTR;
  4426.         ent.offsets[0]=GetUserVarIndex(line, 1);
  4427.         int k=line.gettoken_enum(2,rootkeys[0]);
  4428.         if (k == -1) k=line.gettoken_enum(2,rootkeys[1]);
  4429.         if (ent.offsets[0] == -1 || k == -1) PRINTHELP()
  4430.         ent.offsets[1]=(int)rootkey_tab[k];
  4431.         ent.offsets[2]=add_string(line.gettoken_str(3));
  4432.         ent.offsets[3]=add_string(line.gettoken_str(4));
  4433.         if (which_token == TOK_READREGDWORD) ent.offsets[4]=1;
  4434.         else ent.offsets[4]=0;
  4435.         if (line.gettoken_str(3)[0] == '\\')
  4436.           warning_fl("%s: registry path name begins with \'\\\', may cause problems",line.gettoken_str(0));
  4437.  
  4438.         SCRIPT_MSG("%s %s %s\\%s\\%s\n",line.gettoken_str(0),
  4439.           line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4));
  4440.       }
  4441.     return add_entry(&ent);
  4442.     case TOK_DELETEREGVALUE:
  4443.     case TOK_DELETEREGKEY:
  4444.       {
  4445.         int a=1;
  4446.         if (which_token==TOK_DELETEREGKEY)
  4447.         {
  4448.           ent.offsets[3]=1;
  4449.           char *s=line.gettoken_str(a);
  4450.           if (s[0] == '/')
  4451.           {
  4452.             if (stricmp(s,"/ifempty")) PRINTHELP()
  4453.             a++;
  4454.             ent.offsets[3]=3;
  4455.           }
  4456.           if (line.gettoken_str(a+2)[0]) PRINTHELP()
  4457.         }
  4458.         int k=line.gettoken_enum(a,rootkeys[0]);
  4459.         if (k == -1) k=line.gettoken_enum(a,rootkeys[1]);
  4460.         if (k == -1) PRINTHELP()
  4461.         ent.which=EW_DELREG;
  4462.         ent.offsets[0]=(int)rootkey_tab[k];
  4463.         ent.offsets[1]=add_string(line.gettoken_str(a+1));
  4464.         ent.offsets[2]=(which_token==TOK_DELETEREGKEY)?0:add_string(line.gettoken_str(a+2));
  4465.         if (line.gettoken_str(a+1)[0] == '\\')
  4466.           warning_fl("%s: registry path name begins with \'\\\', may cause problems",line.gettoken_str(0));
  4467.         if (which_token==TOK_DELETEREGKEY)
  4468.           SCRIPT_MSG("DeleteRegKey: %s\\%s\n",line.gettoken_str(a),line.gettoken_str(a+1));
  4469.         else
  4470.           SCRIPT_MSG("DeleteRegValue: %s\\%s\\%s\n",line.gettoken_str(a),line.gettoken_str(a+1),line.gettoken_str(a+2));
  4471.       }
  4472.     return add_entry(&ent);
  4473.     case TOK_WRITEREGSTR:
  4474.     case TOK_WRITEREGEXPANDSTR:
  4475.     case TOK_WRITEREGBIN:
  4476.     case TOK_WRITEREGDWORD:
  4477.       {
  4478.         int k=line.gettoken_enum(1,rootkeys[0]);
  4479.         if (k == -1) k=line.gettoken_enum(1,rootkeys[1]);
  4480.         if (k == -1) PRINTHELP()
  4481.         ent.which=EW_WRITEREG;
  4482.         ent.offsets[0]=(int)rootkey_tab[k];
  4483.         ent.offsets[1]=add_string(line.gettoken_str(2));
  4484.         if (line.gettoken_str(2)[0] == '\\')
  4485.           warning_fl("%s: registry path name begins with \'\\\', may cause problems",line.gettoken_str(0));
  4486.         ent.offsets[2]=add_string(line.gettoken_str(3));
  4487.         if (which_token == TOK_WRITEREGSTR || which_token == TOK_WRITEREGEXPANDSTR)
  4488.         {
  4489.           SCRIPT_MSG("%s: %s\\%s\\%s=%s\n",
  4490.             line.gettoken_str(0),line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4));
  4491.           ent.offsets[3]=add_string(line.gettoken_str(4));
  4492.           ent.offsets[4]=ent.offsets[5]=REG_SZ;
  4493.           if (which_token == TOK_WRITEREGEXPANDSTR)
  4494.           {
  4495.             ent.offsets[5]=REG_EXPAND_SZ;
  4496.           }
  4497.         }
  4498.         if (which_token == TOK_WRITEREGBIN)
  4499.         {
  4500.           char data[NSIS_MAX_STRLEN];
  4501.           char *p=line.gettoken_str(4);
  4502.           int data_len=0;
  4503.           while (*p)
  4504.           {
  4505.             int c;
  4506.             int a,b;
  4507.             a=*p;
  4508.             if (a >= '0' && a <= '9') a-='0';
  4509.             else if (a >= 'a' && a <= 'f') a-='a'-10;
  4510.             else if (a >= 'A' && a <= 'F') a-='A'-10;
  4511.             else break;
  4512.             b=*++p;
  4513.             if (b >= '0' && b <= '9') b-='0';
  4514.             else if (b >= 'a' && b <= 'f') b-='a'-10;
  4515.             else if (b >= 'A' && b <= 'F') b-='A'-10;
  4516.             else break;
  4517.             p++;
  4518.             c=(a<<4)|b;
  4519.             if (data_len >= NSIS_MAX_STRLEN)
  4520.             {
  4521.               ERROR_MSG("WriteRegBin: %d bytes of data exceeded\n",NSIS_MAX_STRLEN);
  4522.               return PS_ERROR;
  4523.             }
  4524.             data[data_len++]=c;
  4525.           }
  4526.           if (*p) PRINTHELP()
  4527.           SCRIPT_MSG("WriteRegBin: %s\\%s\\%s=%s\n",
  4528.             line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4));
  4529.           ent.offsets[3]=add_db_data(data,data_len);
  4530.           if (ent.offsets[3] < 0) return PS_ERROR;
  4531.           ent.offsets[4]=ent.offsets[5]=REG_BINARY;
  4532.         }
  4533.         if (which_token == TOK_WRITEREGDWORD)
  4534.         {
  4535.           ent.offsets[3]=add_string(line.gettoken_str(4));
  4536.           ent.offsets[4]=ent.offsets[5]=REG_DWORD;
  4537.  
  4538.           SCRIPT_MSG("WriteRegDWORD: %s\\%s\\%s=%s\n",
  4539.             line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4));
  4540.         }
  4541.       }
  4542.     return add_entry(&ent);
  4543.     case TOK_ENUMREGKEY:
  4544.     case TOK_ENUMREGVAL:
  4545.       {
  4546.         ent.which=EW_REGENUM;
  4547.         ent.offsets[0]=GetUserVarIndex(line, 1);
  4548.         int k=line.gettoken_enum(2,rootkeys[0]);
  4549.         if (k == -1) k=line.gettoken_enum(2,rootkeys[1]);
  4550.         if (ent.offsets[0] == -1 || k == -1) PRINTHELP()
  4551.         ent.offsets[1]=(int)rootkey_tab[k];
  4552.         ent.offsets[2]=add_string(line.gettoken_str(3));
  4553.         ent.offsets[3]=add_string(line.gettoken_str(4));
  4554.         ent.offsets[4]=which_token == TOK_ENUMREGKEY;
  4555.         if (line.gettoken_str(3)[0] == '\\') warning_fl("%s: registry path name begins with \'\\\', may cause problems",line.gettoken_str(0));
  4556.         SCRIPT_MSG("%s %s %s\\%s\\%s\n",which_token == TOK_ENUMREGKEY ? "EnumRegKey" : "EnumRegValue",
  4557.           line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4));
  4558.       }
  4559.     return add_entry(&ent);
  4560. #else//!NSIS_SUPPORT_REGISTRYFUNCTIONS
  4561.     case TOK_READREGSTR:
  4562.     case TOK_READREGDWORD:
  4563.     case TOK_DELETEREGVALUE:
  4564.     case TOK_DELETEREGKEY:
  4565.     case TOK_WRITEREGSTR:
  4566.     case TOK_WRITEREGEXPANDSTR:
  4567.     case TOK_WRITEREGBIN:
  4568.     case TOK_WRITEREGDWORD:
  4569.     case TOK_ENUMREGKEY:
  4570.     case TOK_ENUMREGVAL:
  4571.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_REGISTRYFUNCTIONS not defined.\n",  line.gettoken_str(0));
  4572.       return PS_ERROR;
  4573. #endif//!NSIS_SUPPORT_REGISTRYFUNCTIONS
  4574. #ifdef NSIS_SUPPORT_STACK
  4575.     case TOK_EXCH:
  4576.       {
  4577.         int swapitem=1;
  4578.         int save=GetUserVarIndex(line, 1);
  4579.         ent.which=EW_PUSHPOP;
  4580.         if (line.gettoken_str(1)[0] && save<0)
  4581.         {
  4582.           int s=0;
  4583.           swapitem=line.gettoken_int(1,&s);
  4584.           if (!s || swapitem <= 0) PRINTHELP()
  4585.         }
  4586.         if (save>=0)
  4587.         {
  4588.           SCRIPT_MSG("Exch(%s,0)\n",line.gettoken_str(1));
  4589.           ent.offsets[0]=add_string(line.gettoken_str(1));
  4590.           ent.offsets[1]=0;
  4591.           ent.offsets[2]=0;
  4592.           add_entry(&ent);
  4593.         }
  4594.         else SCRIPT_MSG("Exch(st(%d),0)\n",swapitem);
  4595.  
  4596.         ent.offsets[0]=0;
  4597.         ent.offsets[1]=0;
  4598.         ent.offsets[2]=swapitem;
  4599.  
  4600.         if (save>=0)
  4601.         {
  4602.           add_entry(&ent);
  4603.           ent.offsets[0]=save;
  4604.           ent.offsets[1]=1;
  4605.           ent.offsets[2]=0;
  4606.         }
  4607.  
  4608.         DefineInnerLangString(NLF_INST_CORRUPTED);
  4609.       }
  4610.     return add_entry(&ent);
  4611.     case TOK_PUSH:
  4612.       ent.which=EW_PUSHPOP;
  4613.       ent.offsets[0]=add_string(line.gettoken_str(1));
  4614.       ent.offsets[1]=0;
  4615.       SCRIPT_MSG("Push: %s\n",line.gettoken_str(1));
  4616.     return add_entry(&ent);
  4617.     case TOK_POP:
  4618.       ent.which=EW_PUSHPOP;
  4619.       ent.offsets[0]=GetUserVarIndex(line, 1);
  4620.       ent.offsets[1]=1;
  4621.       if (ent.offsets[0] < 0) PRINTHELP()
  4622.       SCRIPT_MSG("Pop: %s\n",line.gettoken_str(1));
  4623.     return add_entry(&ent);
  4624. #else//!NSIS_SUPPORT_STACK
  4625.     case TOK_POP:
  4626.     case TOK_PUSH:
  4627.     case TOK_EXCH:
  4628.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_STACK not defined.\n",  line.gettoken_str(0));
  4629.     return PS_ERROR;
  4630. #endif//!NSIS_SUPPORT_STACK
  4631. #ifdef NSIS_SUPPORT_ENVIRONMENT
  4632.     case TOK_READENVSTR:
  4633.       ent.which=EW_READENVSTR;
  4634.       ent.offsets[0]=GetUserVarIndex(line, 1);
  4635.       {
  4636.         ent.offsets[1]=add_string(line.gettoken_str(2));
  4637.         if (ent.offsets[0] < 0 || strlen(line.gettoken_str(2))<1) PRINTHELP()
  4638.       }
  4639.       ent.offsets[2]=1;
  4640.       SCRIPT_MSG("ReadEnvStr: %s->%s\n",line.gettoken_str(2),line.gettoken_str(1));
  4641.     return add_entry(&ent);
  4642.     case TOK_EXPANDENVSTRS:
  4643.       ent.which=EW_READENVSTR;
  4644.       ent.offsets[0]=GetUserVarIndex(line, 1);
  4645.       ent.offsets[1]=add_string(line.gettoken_str(2));
  4646.       ent.offsets[2]=0;
  4647.       if (ent.offsets[0] < 0) PRINTHELP()
  4648.       SCRIPT_MSG("ExpandEnvStrings: %s->%s\n",line.gettoken_str(2),line.gettoken_str(1));
  4649.     return add_entry(&ent);
  4650. #else//!NSIS_SUPPORT_ENVIRONMENT
  4651.     case TOK_EXPANDENVSTRS:
  4652.     case TOK_READENVSTR:
  4653.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_ENVIRONMENT not defined.\n",  line.gettoken_str(0));
  4654.     return PS_ERROR;
  4655. #endif//!NSIS_SUPPORT_ENVIRONMENT
  4656. #ifdef NSIS_SUPPORT_FINDFIRST
  4657.     case TOK_FINDFIRST:
  4658.       ent.which=EW_FINDFIRST;
  4659.       ent.offsets[0]=GetUserVarIndex(line, 2); // out
  4660.       ent.offsets[1]=GetUserVarIndex(line, 1); // handleout
  4661.       ent.offsets[2]=add_string(line.gettoken_str(3)); // filespec
  4662.       if (ent.offsets[0] < 0 || ent.offsets[1] < 0) PRINTHELP()
  4663.       SCRIPT_MSG("FindFirst: spec=\"%s\" handle=%s output=%s\n",line.gettoken_str(3),line.gettoken_str(1),line.gettoken_str(2));
  4664.     return add_entry(&ent);
  4665.     case TOK_FINDNEXT:
  4666.       ent.which=EW_FINDNEXT;
  4667.       ent.offsets[0]=GetUserVarIndex(line, 2);
  4668.       ent.offsets[1]=GetUserVarIndex(line, 1);
  4669.       if (ent.offsets[0] < 0 || ent.offsets[1] < 0) PRINTHELP()
  4670.       SCRIPT_MSG("FindNext: handle=%s output=%s\n",line.gettoken_str(1),line.gettoken_str(2));
  4671.     return add_entry(&ent);
  4672.     case TOK_FINDCLOSE:
  4673.       ent.which=EW_FINDCLOSE;
  4674.       ent.offsets[0]=GetUserVarIndex(line, 1);
  4675.       if (ent.offsets[0] < 0) PRINTHELP()
  4676.       SCRIPT_MSG("FindClose: %s\n",line.gettoken_str(1));
  4677.     return add_entry(&ent);
  4678. #else//!NSIS_SUPPORT_FINDFIRST
  4679.     case TOK_FINDCLOSE:
  4680.     case TOK_FINDNEXT:
  4681.     case TOK_FINDFIRST:
  4682.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_FINDFIRST not defined.\n",  line.gettoken_str(0));
  4683.     return PS_ERROR;
  4684.  
  4685. #endif//!NSIS_SUPPORT_FINDFIRST
  4686.  
  4687.  
  4688. #ifdef NSIS_SUPPORT_FILEFUNCTIONS
  4689.     case TOK_FILEOPEN:
  4690.       {
  4691.         ent.which=EW_FOPEN;
  4692.         ent.offsets[0]=GetUserVarIndex(line, 1); // file handle
  4693.         ent.offsets[3]=add_string(line.gettoken_str(2));
  4694.         ent.offsets[1]=0; //openmode
  4695.         if (!stricmp(line.gettoken_str(3),"r"))
  4696.         {
  4697.           ent.offsets[1]=GENERIC_READ;
  4698.           ent.offsets[2]=OPEN_EXISTING;
  4699.         }
  4700.         else if (!stricmp(line.gettoken_str(3),"w"))
  4701.         {
  4702.           ent.offsets[1]=GENERIC_WRITE;
  4703.           ent.offsets[2]=CREATE_ALWAYS;
  4704.         }
  4705.         else if (!stricmp(line.gettoken_str(3),"a"))
  4706.         {
  4707.           ent.offsets[1]=GENERIC_WRITE|GENERIC_READ;
  4708.           ent.offsets[2]=OPEN_ALWAYS;
  4709.         }
  4710.  
  4711.         if (ent.offsets[3] < 0 || !ent.offsets[1]) PRINTHELP()
  4712.       }
  4713.       SCRIPT_MSG("FileOpen: %s as %s -> %s\n",line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(1));
  4714.     return add_entry(&ent);
  4715.     case TOK_FILECLOSE:
  4716.       ent.which=EW_FCLOSE;
  4717.       ent.offsets[0]=GetUserVarIndex(line, 1); // file handle
  4718.       if (ent.offsets[0] < 0) PRINTHELP()
  4719.       SCRIPT_MSG("FileClose: %s\n",line.gettoken_str(1));
  4720.     return add_entry(&ent);
  4721.     case TOK_FILEREAD:
  4722.       ent.which=EW_FGETS;
  4723.       ent.offsets[0]=GetUserVarIndex(line, 1); // file handle
  4724.       ent.offsets[1]=GetUserVarIndex(line, 2); // output string
  4725.       ent.offsets[2]=add_string(line.gettoken_str(3)[0]?line.gettoken_str(3):"1023");
  4726.       if (ent.offsets[0]<0 || ent.offsets[1]<0) PRINTHELP()
  4727.       SCRIPT_MSG("FileRead: %s->%s (max:%s)\n",line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3));
  4728.     return add_entry(&ent);
  4729.     case TOK_FILEWRITE:
  4730.       ent.which=EW_FPUTS;
  4731.       ent.offsets[0]=GetUserVarIndex(line, 1); // file handle
  4732.       ent.offsets[1]=add_string(line.gettoken_str(2));
  4733.       if (ent.offsets[0]<0) PRINTHELP()
  4734.       SCRIPT_MSG("FileWrite: %s->%s\n",line.gettoken_str(2),line.gettoken_str(1));
  4735.     return add_entry(&ent);
  4736.     case TOK_FILEREADBYTE:
  4737.       ent.which=EW_FGETS;
  4738.       ent.offsets[0]=GetUserVarIndex(line, 1); // file handle
  4739.       ent.offsets[1]=GetUserVarIndex(line, 2); // output string
  4740.       ent.offsets[2]=add_string("1");
  4741.       ent.offsets[3]=1;
  4742.       if (ent.offsets[0]<0 || ent.offsets[1]<0) PRINTHELP()
  4743.       SCRIPT_MSG("FileReadByte: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2));
  4744.     return add_entry(&ent);
  4745.     case TOK_FILEWRITEBYTE:
  4746.       ent.which=EW_FPUTS;
  4747.       ent.offsets[0]=GetUserVarIndex(line, 1); // file handle
  4748.       ent.offsets[1]=add_string(line.gettoken_str(2));
  4749.       ent.offsets[2]=1;
  4750.       if (ent.offsets[0]<0) PRINTHELP()
  4751.       SCRIPT_MSG("FileWriteByte: %s->%s\n",line.gettoken_str(2),line.gettoken_str(1));
  4752.     return add_entry(&ent);
  4753.     case TOK_FILESEEK:
  4754.       {
  4755.         char *modestr;
  4756.         int tab[3]={FILE_BEGIN,FILE_CURRENT,FILE_END};
  4757.         int mode=line.gettoken_enum(3,"SET\0CUR\0END\0");
  4758.         ent.which=EW_FSEEK;
  4759.         ent.offsets[0]=GetUserVarIndex(line, 1);
  4760.         ent.offsets[1]=GetUserVarIndex(line, 4);
  4761.         ent.offsets[2]=add_string(line.gettoken_str(2));
  4762.  
  4763.         if (mode<0 && !line.gettoken_str(3)[0])
  4764.         {
  4765.           mode=0;
  4766.           modestr="SET";
  4767.         }
  4768.         else modestr=line.gettoken_str(3);
  4769.  
  4770.         if (mode<0 || ent.offsets[0] < 0 || (ent.offsets[1]<0 && line.gettoken_str(4)[0])) PRINTHELP()
  4771.         ent.offsets[3]=tab[mode];
  4772.         SCRIPT_MSG("FileSeek: fp=%s, ofs=%s, mode=%s, output=%s\n",
  4773.           line.gettoken_str(1),
  4774.           line.gettoken_str(2),
  4775.           modestr,
  4776.           line.gettoken_str(4));
  4777.       }
  4778.  
  4779.     return add_entry(&ent);
  4780. #else//!NSIS_SUPPORT_FILEFUNCTIONS
  4781.     case TOK_FILEOPEN:
  4782.     case TOK_FILECLOSE:
  4783.     case TOK_FILESEEK:
  4784.     case TOK_FILEREAD:
  4785.     case TOK_FILEWRITE:
  4786.     case TOK_FILEREADBYTE:
  4787.     case TOK_FILEWRITEBYTE:
  4788.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_FILEFUNCTIONS not defined.\n",  line.gettoken_str(0));
  4789.     return PS_ERROR;
  4790.  
  4791. #endif//!NSIS_SUPPORT_FILEFUNCTIONS
  4792. #ifdef NSIS_SUPPORT_REBOOT
  4793.     case TOK_REBOOT:
  4794.       ent.which=EW_REBOOT;
  4795.       ent.offsets[0]=0xbadf00d;
  4796.       SCRIPT_MSG("Reboot! (WOW)\n");
  4797.  
  4798.       DefineInnerLangString(NLF_INST_CORRUPTED);
  4799.     return add_entry(&ent);
  4800.     case TOK_IFREBOOTFLAG:
  4801.       ent.which=EW_IFFLAG;
  4802.       if (process_jump(line,1,&ent.offsets[0]) ||
  4803.           process_jump(line,2,&ent.offsets[1])) PRINTHELP()
  4804.       ent.offsets[2]=FLAG_OFFSET(exec_reboot);
  4805.       ent.offsets[3]=~0;//new value mask - keep flag
  4806.       SCRIPT_MSG("IfRebootFlag ?%s:%s\n",line.gettoken_str(1),line.gettoken_str(2));
  4807.     return add_entry(&ent);
  4808.     case TOK_SETREBOOTFLAG:
  4809.     {
  4810.       ent.which=EW_SETFLAG;
  4811.       ent.offsets[0]=FLAG_OFFSET(exec_reboot);
  4812.       int k=line.gettoken_enum(1,"false\0true\0");
  4813.       if (k < 0) PRINTHELP()
  4814.       ent.offsets[1]=add_intstring(k);
  4815.     }
  4816.     return add_entry(&ent);
  4817. #else//!NSIS_SUPPORT_REBOOT
  4818.     case TOK_REBOOT:
  4819.     case TOK_IFREBOOTFLAG:
  4820.     case TOK_SETREBOOTFLAG:
  4821.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_REBOOT not defined.\n",  line.gettoken_str(0));
  4822.     return PS_ERROR;
  4823. #endif//!NSIS_SUPPORT_REBOOT
  4824. #ifdef NSIS_CONFIG_LOG
  4825.     case TOK_LOGSET:
  4826.       ent.which=EW_LOG;
  4827.       ent.offsets[0]=1;
  4828.       ent.offsets[1]=line.gettoken_enum(1,"off\0on\0");
  4829.       if (ent.offsets[1]<0) PRINTHELP()
  4830.  
  4831.       SCRIPT_MSG("LogSet: %s\n",line.gettoken_str(1));
  4832.     return add_entry(&ent);
  4833.     case TOK_LOGTEXT:
  4834.       ent.which=EW_LOG;
  4835.       ent.offsets[0]=0;
  4836.       ent.offsets[1]=add_string(line.gettoken_str(1));
  4837.       SCRIPT_MSG("LogText \"%s\"\n",line.gettoken_str(1));
  4838.     return add_entry(&ent);
  4839. #else//!NSIS_CONFIG_LOG
  4840.  
  4841.     case TOK_LOGSET:
  4842.     case TOK_LOGTEXT:
  4843.       ERROR_MSG("Error: %s specified, NSIS_CONFIG_LOG not defined.\n",  line.gettoken_str(0));
  4844.     return PS_ERROR;
  4845. #endif//!NSIS_CONFIG_LOG
  4846. #ifdef NSIS_CONFIG_COMPONENTPAGE
  4847.     case TOK_SECTIONSETTEXT:
  4848.       ent.which=EW_SECTIONSET;
  4849.       ent.offsets[0]=add_string(line.gettoken_str(1));
  4850.       ent.offsets[1]=add_string(line.gettoken_str(2));
  4851.       ent.offsets[2]=SECTION_FIELD_SET(name_ptr);
  4852.       SCRIPT_MSG("SectionSetText: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2));
  4853.     return add_entry(&ent);
  4854.     case TOK_SECTIONGETTEXT:
  4855.       ent.which=EW_SECTIONSET;
  4856.       ent.offsets[0]=add_string(line.gettoken_str(1));
  4857.       ent.offsets[1]=GetUserVarIndex(line, 2);
  4858.       ent.offsets[2]=SECTION_FIELD_GET(name_ptr);
  4859.       if (line.gettoken_str(2)[0] && ent.offsets[1]<0) PRINTHELP()
  4860.       SCRIPT_MSG("SectionGetText: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2));
  4861.     return add_entry(&ent);
  4862.     case TOK_SECTIONSETFLAGS:
  4863.       ent.which=EW_SECTIONSET;
  4864.       ent.offsets[0]=add_string(line.gettoken_str(1));
  4865.       ent.offsets[1]=add_string(line.gettoken_str(2));
  4866.       ent.offsets[2]=SECTION_FIELD_SET(flags);
  4867.       SCRIPT_MSG("SectionSetFlags: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2));
  4868.     return add_entry(&ent);
  4869.     case TOK_SECTIONGETFLAGS:
  4870.       ent.which=EW_SECTIONSET;
  4871.       ent.offsets[0]=add_string(line.gettoken_str(1));
  4872.       ent.offsets[1]=GetUserVarIndex(line, 2);
  4873.       ent.offsets[2]=SECTION_FIELD_GET(flags);
  4874.       if (line.gettoken_str(2)[0] && ent.offsets[1]<0) PRINTHELP()
  4875.       SCRIPT_MSG("SectionGetFlags: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2));
  4876.     return add_entry(&ent);
  4877.     case TOK_INSTTYPESETTEXT:
  4878.       ent.which=EW_INSTTYPESET;
  4879.       ent.offsets[0]=add_string(line.gettoken_str(1));
  4880.       ent.offsets[1]=add_string(line.gettoken_str(2));
  4881.       ent.offsets[2]=1;
  4882.       SCRIPT_MSG("InstTypeSetText: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2));
  4883.     return add_entry(&ent);
  4884.     case TOK_INSTTYPEGETTEXT:
  4885.       ent.which=EW_INSTTYPESET;
  4886.       ent.offsets[0]=add_string(line.gettoken_str(1));
  4887.       ent.offsets[1]=GetUserVarIndex(line, 2);
  4888.       ent.offsets[2]=0;
  4889.       if (line.gettoken_str(1)[0] && ent.offsets[1]<0) PRINTHELP()
  4890.       SCRIPT_MSG("InstTypeGetText: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2));
  4891.     return add_entry(&ent);
  4892.     case TOK_SECTIONSETINSTTYPES:
  4893.       ent.which=EW_SECTIONSET;
  4894.       ent.offsets[0]=add_string(line.gettoken_str(1));
  4895.       ent.offsets[1]=add_string(line.gettoken_str(2));
  4896.       ent.offsets[2]=SECTION_FIELD_SET(install_types);
  4897.       SCRIPT_MSG("SectionSetInstTypes: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2));
  4898.     return add_entry(&ent);
  4899.     case TOK_SECTIONGETINSTTYPES:
  4900.       ent.which=EW_SECTIONSET;
  4901.       ent.offsets[0]=add_string(line.gettoken_str(1));
  4902.       ent.offsets[1]=GetUserVarIndex(line, 2);
  4903.       ent.offsets[2]=SECTION_FIELD_GET(install_types);
  4904.       if (line.gettoken_str(2)[0] && ent.offsets[1]<0) PRINTHELP()
  4905.       SCRIPT_MSG("SectionGetInstTypes: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2));
  4906.     return add_entry(&ent);
  4907.     case TOK_SECTIONSETSIZE:
  4908.       ent.which=EW_SECTIONSET;
  4909.       ent.offsets[0]=add_string(line.gettoken_str(1));
  4910.       ent.offsets[1]=add_string(line.gettoken_str(2));
  4911.       ent.offsets[2]=SECTION_FIELD_SET(size_kb);
  4912.       SCRIPT_MSG("SectionSetSize: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2));
  4913.     return add_entry(&ent);
  4914.     case TOK_SECTIONGETSIZE:
  4915.       ent.which=EW_SECTIONSET;
  4916.       ent.offsets[0]=add_string(line.gettoken_str(1));
  4917.       ent.offsets[1]=GetUserVarIndex(line, 2);
  4918.       ent.offsets[2]=SECTION_FIELD_GET(size_kb);
  4919.       if (line.gettoken_str(2)[0] && ent.offsets[1]<0) PRINTHELP()
  4920.       SCRIPT_MSG("SectionGetSize: %s->%s\n",line.gettoken_str(1),line.gettoken_str(2));
  4921.     return add_entry(&ent);
  4922.     case TOK_SETCURINSTTYPE:
  4923.     {
  4924.       int ret;
  4925.       SCRIPT_MSG("SetCurInstType: %s\n",line.gettoken_str(1));
  4926.       ret = add_entry_direct(EW_SETFLAG, FLAG_OFFSET(cur_insttype), add_string(line.gettoken_str(1)));
  4927.       if (ret != PS_OK) return ret;
  4928.       ret = add_entry_direct(EW_INSTTYPESET, 0, 0, 0, 1);
  4929.       if (ret != PS_OK) return ret;
  4930.     }
  4931.     return PS_OK;
  4932.     case TOK_GETCURINSTTYPE:
  4933.       ent.which=EW_GETFLAG;
  4934.       ent.offsets[0]=GetUserVarIndex(line, 1);
  4935.       ent.offsets[1]=FLAG_OFFSET(cur_insttype);
  4936.       if (line.gettoken_str(1)[0] && ent.offsets[0]<0) PRINTHELP()
  4937.       SCRIPT_MSG("GetCurInstType: %s\n",line.gettoken_str(1));
  4938.     return add_entry(&ent);
  4939. #else//!NSIS_CONFIG_COMPONENTPAGE
  4940.     case TOK_SECTIONSETTEXT:
  4941.     case TOK_SECTIONGETTEXT:
  4942.     case TOK_SECTIONSETFLAGS:
  4943.     case TOK_SECTIONGETFLAGS:
  4944.     case TOK_SECTIONSETSIZE:
  4945.     case TOK_SECTIONGETSIZE:
  4946.     case TOK_SECTIONSETINSTTYPES:
  4947.     case TOK_SECTIONGETINSTTYPES:
  4948.     case TOK_SETCURINSTTYPE:
  4949.     case TOK_GETCURINSTTYPE:
  4950.       ERROR_MSG("Error: %s specified, NSIS_CONFIG_COMPONENTPAGE not defined.\n",  line.gettoken_str(0));
  4951.     return PS_ERROR;
  4952. #endif//!NSIS_CONFIG_COMPONENTPAGE
  4953.     // Added by Amir Szekely 29th July 2002
  4954. #ifdef NSIS_CONFIG_ENHANCEDUI_SUPPORT
  4955.     case TOK_SETBRANDINGIMAGE:
  4956.     {
  4957.       SCRIPT_MSG("SetBrandingImage: ");
  4958.       if (!branding_image_found) {
  4959.         ERROR_MSG("\nError: no branding image found in chosen UI!\n");
  4960.         return PS_ERROR;
  4961.       }
  4962.       ent.which=EW_SETBRANDINGIMAGE;
  4963.       for (int i = 1; i < line.getnumtokens(); i++)
  4964.         if (!strnicmp(line.gettoken_str(i),"/IMGID=",7)) {
  4965.           ent.offsets[1]=atoi(line.gettoken_str(i)+7);
  4966.           SCRIPT_MSG("/IMGID=%d ",ent.offsets[1]);
  4967.         }
  4968.         else if (!stricmp(line.gettoken_str(i),"/RESIZETOFIT")) {
  4969.           ent.offsets[2]=1; // must be 1 or 0
  4970.           SCRIPT_MSG("/RESIZETOFIT ");
  4971.         }
  4972.         else if (!ent.offsets[0]) {
  4973.           ent.offsets[0]=add_string(line.gettoken_str(i));
  4974.           SCRIPT_MSG("\"%s\" ", line.gettoken_str(i));
  4975.         }
  4976.         else {
  4977.           SCRIPT_MSG("\n");
  4978.           PRINTHELP();
  4979.         }
  4980.  
  4981.       if (!ent.offsets[1])
  4982.         ent.offsets[1]=branding_image_id;
  4983.       SCRIPT_MSG("\n");
  4984.     }
  4985.     return add_entry(&ent);
  4986. #else//NSIS_CONFIG_ENHANCEDUI_SUPPORT
  4987.     case TOK_SETBRANDINGIMAGE:
  4988.       ERROR_MSG("Error: %s specified, NSIS_CONFIG_ENHANCEDUI_SUPPORT not defined.\n",line.gettoken_str(0));
  4989.       return PS_ERROR;
  4990. #endif//!NSIS_SUPPORT_CREATEFONT
  4991.  
  4992.     // Added by ramon 3 jun 2003
  4993.     case TOK_DEFVAR:
  4994.     {
  4995.         SCRIPT_MSG("VAR \"%s\"\n",line.gettoken_str(1));
  4996.         int res = DeclaredUserVar(line.gettoken_str(1));
  4997.         if (res != PS_OK)
  4998.           return res;        
  4999.     }
  5000.     return PS_OK;
  5001.  
  5002.     // Added by ramon 6 jun 2003
  5003. #ifdef NSIS_SUPPORT_VERSION_INFO
  5004.     case TOK_VI_ADDKEY:
  5005.     {
  5006.         LANGID LangID=0;
  5007.         int a = 1;
  5008.         if (!strnicmp(line.gettoken_str(a),"/LANG=",6))
  5009.           LangID=atoi(line.gettoken_str(a++)+6);
  5010.         if (line.getnumtokens()!=a+2) PRINTHELP();
  5011.         char *pKey = line.gettoken_str(a);
  5012.         char *pValue = line.gettoken_str(a+1);
  5013.         if ( !(*pKey) )
  5014.         {
  5015.            ERROR_MSG("Error: empty name for version info key!\n");
  5016.            return PS_ERROR;
  5017.         }
  5018.         else
  5019.         {
  5020.            SCRIPT_MSG("%s: \"%s\" \"%s\"\n", line.gettoken_str(0), line.gettoken_str(a), line.gettoken_str(a+1));
  5021.            LANGID lReaded = LangID;
  5022.            LanguageTable *table = GetLangTable(LangID);
  5023.            if ( a > 1 && lReaded == 0 )
  5024.              warning_fl("%s: %s language not loaded, using default \"1033-English\"", line.gettoken_str(0), line.gettoken_str(1));
  5025.            if ( rVersionInfo.SetKeyValue(LangID, table->nlf.m_bLoaded ? table->nlf.m_uCodePage : 1252 /*English US*/, pKey, pValue) )
  5026.            {
  5027.              ERROR_MSG("%s: \"%s\" \"%04d-%s\" already defined!\n",line.gettoken_str(0), line.gettoken_str(2), LangID, table->nlf.m_bLoaded ? table->nlf.m_szName : LangID == 1033 ? "English" : "???");
  5028.              return PS_ERROR;
  5029.            }
  5030.  
  5031.            return PS_OK;
  5032.         }
  5033.     }
  5034.     case TOK_VI_SETPRODUCTVERSION:
  5035.       if ( version_product_v[0] )
  5036.       {
  5037.            ERROR_MSG("Error: %s already defined!\n", line.gettoken_str(0));
  5038.            return PS_ERROR;
  5039.       }
  5040.       strcpy(version_product_v, line.gettoken_str(1));
  5041.       return PS_OK;
  5042.  
  5043. #else
  5044.     case TOK_VI_ADDKEY:
  5045.     case TOK_VI_SETPRODUCTVERSION:
  5046.       ERROR_MSG("Error: %s specified, NSIS_SUPPORT_VERSION_INFO not defined.\n",line.gettoken_str(0));
  5047.       return PS_ERROR;
  5048. #endif
  5049.  
  5050.     // end of instructions
  5051.     ///////////////////////////////////////////////////////////////////////////////
  5052.  
  5053.     // Added by Ximon Eighteen 5th August 2002
  5054. #ifdef NSIS_CONFIG_PLUGIN_SUPPORT
  5055.     case TOK_PLUGINDIR:
  5056.     {
  5057.       if (line.getnumtokens() == 2)
  5058.       {
  5059.         SCRIPT_MSG("PluginDir: \"%s\"\n",line.gettoken_str(1));
  5060.         m_plugins.FindCommands(line.gettoken_str(1),display_info?true:false);
  5061.         return PS_OK;
  5062.       }
  5063.     }
  5064.     return PS_ERROR;
  5065.     case TOK__PLUGINCOMMAND:
  5066.     {
  5067.       int ret, data_handle;
  5068.       char* command = strdup(line.gettoken_str(0));
  5069.  
  5070.       char* dllPath = m_plugins.GetPluginDll(uninstall_mode, &command, &data_handle);
  5071.       if (dllPath)
  5072.       {
  5073.         if (uninstall_mode) uninst_plugin_used = true;
  5074.         else plugin_used = true;
  5075.  
  5076.         // Initialize $PLUGINSDIR
  5077.         ent.which=EW_CALL;
  5078.         ent.offsets[0]=ns_func.add(uninstall_mode?"un.Initialize_____Plugins":"Initialize_____Plugins",0);
  5079.         ret=add_entry(&ent);
  5080.         if (ret != PS_OK) {
  5081.           free(command);
  5082.           return ret;
  5083.         }
  5084.  
  5085.         // DLL name on the user machine
  5086.         char tempDLL[NSIS_MAX_STRLEN];
  5087.         wsprintf(tempDLL, "$PLUGINSDIR%s", strrchr(dllPath,'\\'));
  5088.  
  5089.         // Add the DLL to the installer
  5090.         if (data_handle == -1)
  5091.         {
  5092.           int files_added;
  5093.           // BEGIN - Added by ramon 23 May 2003
  5094.           int old_build_allowskipfiles=build_allowskipfiles;
  5095.           build_allowskipfiles=1; // on
  5096.           // END - Added by ramon 23 May 2003
  5097.           int old_build_overwrite=build_overwrite;
  5098.           build_overwrite=1; // off
  5099.           int old_build_datesave=build_datesave;
  5100.           build_datesave=0; // off
  5101.           ret=do_add_file(dllPath,0,0,linecnt,&files_added,tempDLL,2,&data_handle); // 2 means no size add
  5102.           if (ret != PS_OK) {
  5103.             free(command);
  5104.             return ret;
  5105.           }
  5106.           m_plugins.SetDllDataHandle(uninstall_mode, line.gettoken_str(0),data_handle);
  5107.           build_overwrite=old_build_overwrite;
  5108.           build_datesave=old_build_datesave;
  5109.           // Added by ramon 23 May 2003
  5110.           build_allowskipfiles=old_build_allowskipfiles;
  5111.         }
  5112.         else
  5113.         {
  5114.           ent.which=EW_EXTRACTFILE;
  5115.           
  5116.           DefineInnerLangString(NLF_SKIPPED);
  5117.           DefineInnerLangString(NLF_ERR_DECOMPRESSING);
  5118.           DefineInnerLangString(NLF_ERR_WRITING);
  5119.           DefineInnerLangString(NLF_EXTRACT);
  5120.           DefineInnerLangString(NLF_CANT_WRITE);
  5121.  
  5122.           ent.offsets[0]=1; // overwrite off
  5123.           ent.offsets[0]|=(MB_RETRYCANCEL|MB_ICONSTOP|(IDCANCEL<<20))<<3;
  5124.           ent.offsets[1]=add_string(tempDLL);
  5125.           ent.offsets[2]=data_handle;
  5126.           ent.offsets[3]=0xffffffff;
  5127.           ent.offsets[4]=0xffffffff;
  5128.           ent.offsets[5]=DefineInnerLangString(NLF_FILE_ERROR);
  5129.           ret=add_entry(&ent);
  5130.           if (ret != PS_OK) {
  5131.             free(command);
  5132.             return ret;
  5133.           }
  5134.         }
  5135.  
  5136.         // SetDetailsPrint lastused
  5137.         ent.which=EW_UPDATETEXT;
  5138.         ent.offsets[0]=0;
  5139.         ent.offsets[1]=8; // lastused
  5140.         ent.offsets[2]=0;
  5141.         ret=add_entry(&ent);
  5142.         if (ret != PS_OK) {
  5143.           free(command);
  5144.           return ret;
  5145.         }
  5146.  
  5147.         // Call the DLL
  5148.         char* funcname = strstr(command,"::");
  5149.         if (funcname) funcname += 2;
  5150.         else          funcname  = command;
  5151.         SCRIPT_MSG("Plugin Command: %s",funcname);
  5152.  
  5153.         int i = 1;
  5154.         int nounload = 0;
  5155.         if (!lstrcmpi(line.gettoken_str(i), "/NOUNLOAD")) {
  5156.           i++;
  5157.           nounload++;
  5158.         }
  5159.  
  5160.         // First push dll args
  5161.  
  5162.         int parmst=i; // we push  em in reverse order
  5163.         int nounloadmisused=0;
  5164.         for (; i < line.getnumtokens(); i++) {
  5165.           int w=parmst + (line.getnumtokens()-i - 1);
  5166.           ent.which=EW_PUSHPOP;
  5167.           ent.offsets[0]=add_string(line.gettoken_str(w));
  5168.           if (!lstrcmpi(line.gettoken_str(w), "/NOUNLOAD")) nounloadmisused=1;
  5169.           ent.offsets[1]=0;
  5170.           ret=add_entry(&ent);
  5171.           if (ret != PS_OK) {
  5172.             free(command);
  5173.             return ret;
  5174.           }
  5175.           SCRIPT_MSG(" %s",line.gettoken_str(i));
  5176.         }
  5177.         SCRIPT_MSG("\n");
  5178.         if (nounloadmisused)
  5179.           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");
  5180.  
  5181.         // next, call it
  5182.         ent.which=EW_REGISTERDLL;
  5183.         ent.offsets[0]=add_string(tempDLL);;
  5184.         ent.offsets[1]=add_string(funcname);
  5185.         ent.offsets[2]=0;
  5186.         ent.offsets[3]=nounload|build_plugin_unload;
  5187.         ret=add_entry(&ent);
  5188.         if (ret != PS_OK) {
  5189.           free(command);
  5190.           return ret;
  5191.         }
  5192.  
  5193.         free(command);
  5194.  
  5195.         return PS_OK;
  5196.       }
  5197.       else
  5198.         ERROR_MSG("Error: Plugin dll for command \"%s\" not found.\n",line.gettoken_str(0));
  5199.       free(command);
  5200.     }
  5201.     return PS_ERROR;
  5202.     case TOK_INITPLUGINSDIR:
  5203.     {
  5204.       int ret;
  5205.       SCRIPT_MSG("%s\n",line.gettoken_str(0));
  5206.       if (uninstall_mode) uninst_plugin_used = true;
  5207.       else plugin_used = true;
  5208.       // Call [un.]Initialize_____Plugins
  5209.       ent.which=EW_CALL;
  5210.       ent.offsets[0]=ns_func.add(uninstall_mode?"un.Initialize_____Plugins":"Initialize_____Plugins",0);
  5211.       ret=add_entry(&ent);
  5212.       if (ret != PS_OK) return ret;
  5213.       // SetDetailsPrint lastused
  5214.       ent.which=EW_UPDATETEXT;
  5215.       ent.offsets[0]=0;
  5216.       ent.offsets[1]=8; // lastused
  5217.       ret=add_entry(&ent);
  5218.       if (ret != PS_OK) return ret;
  5219.     }
  5220.     return PS_OK;
  5221. #else
  5222.     case TOK_PLUGINDIR:
  5223.     case TOK__PLUGINCOMMAND:
  5224.     case TOK_INITPLUGINSDIR:
  5225.     {
  5226.       ERROR_MSG("Error: %s specified, NSIS_CONFIG_PLUGIN_SUPPORT not defined.\n",line.gettoken_str(0));
  5227.     }
  5228.     return PS_ERROR;
  5229. #endif// NSIS_CONFIG_PLUGIN_SUPPORT
  5230.  
  5231. #ifdef NSIS_LOCKWINDOW_SUPPORT
  5232.     case TOK_LOCKWINDOW:
  5233.       SCRIPT_MSG("LockWindow: lock state=%d\n",line.gettoken_str(1));
  5234.       ent.which=EW_LOCKWINDOW;
  5235.       ent.offsets[0]=line.gettoken_enum(1,"on\0off\0");
  5236.       if (ent.offsets[0] == -1)
  5237.         PRINTHELP();
  5238.     return add_entry(&ent);
  5239. #else
  5240.     case TOK_LOCKWINDOW:
  5241.     {
  5242.       ERROR_MSG("Error: %s specified, NSIS_LOCKWINDOW_SUPPORT not defined.\n",line.gettoken_str(0));
  5243.     }
  5244.     return PS_ERROR;
  5245. #endif // NSIS_LOCKWINDOW_SUPPORT
  5246.  
  5247.     default: break;
  5248.  
  5249.   }
  5250.   ERROR_MSG("Error: doCommand: Invalid token \"%s\".\n",line.gettoken_str(0));
  5251.   return PS_ERROR;
  5252. }
  5253.  
  5254. #ifdef NSIS_SUPPORT_FILE
  5255. int CEXEBuild::do_add_file(const char *lgss, int attrib, int recurse, int linecnt, int *total_files, const char *name_override, int generatecode, int *data_handle, int rec_depth)
  5256. {
  5257.   char dir[1024];
  5258.   char newfn[1024];
  5259.   HANDLE h;
  5260.   WIN32_FIND_DATA d;
  5261.   strcpy(dir,lgss);
  5262.   {
  5263.     char *s=dir+strlen(dir);
  5264.     while (s > dir && *s != '\\') s=CharPrev(dir,s);
  5265.     *s=0;
  5266.   }
  5267.  
  5268.   h = FindFirstFile(lgss,&d);
  5269.   if (h != INVALID_HANDLE_VALUE)
  5270.   {
  5271.     do
  5272.     {
  5273.       if ((d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  5274.       {
  5275.         MMapFile mmap;
  5276.         HANDLE hFile;
  5277.         DWORD len;
  5278.         (*total_files)++;
  5279.         sprintf(newfn,"%s%s%s",dir,dir[0]?"\\":"",d.cFileName);
  5280.         hFile=CreateFile(
  5281.           newfn,
  5282.           GENERIC_READ,
  5283.           FILE_SHARE_READ,
  5284.           NULL,
  5285.           OPEN_EXISTING,
  5286.           FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  5287.           NULL
  5288.         );
  5289.         if (hFile == INVALID_HANDLE_VALUE)
  5290.         {
  5291.           ERROR_MSG("%sFile: failed opening file \"%s\"\n",generatecode?"":"Reserve",newfn);
  5292.           return PS_ERROR;
  5293.         }
  5294.         len = GetFileSize(hFile, NULL);
  5295.         if (len && !mmap.setfile(hFile, len))
  5296.         {
  5297.           CloseHandle(hFile);
  5298.           ERROR_MSG("%sFile: failed creating mmap of \"%s\"\n",generatecode?"":"Reserve",newfn);
  5299.           return PS_ERROR;
  5300.         }
  5301.  
  5302.         if (generatecode&1)
  5303.           section_add_size_kb((len+1023)/1024);
  5304.         if (name_override) SCRIPT_MSG("%sFile: \"%s\"->\"%s\"",generatecode?"":"Reserve",d.cFileName,name_override);
  5305.         else SCRIPT_MSG("%sFile: \"%s\"",generatecode?"":"Reserve",d.cFileName);
  5306.         if (!build_compress_whole)
  5307.           if (build_compress) SCRIPT_MSG(" [compress]");
  5308.         fflush(stdout);
  5309.         char buf[1024];
  5310.         int last_build_datablock_used=getcurdbsize();
  5311.         entry ent={0,};
  5312.         if (generatecode)
  5313.         {
  5314.           ent.which=EW_EXTRACTFILE;
  5315.  
  5316.           DefineInnerLangString(NLF_SKIPPED);
  5317.           DefineInnerLangString(NLF_ERR_DECOMPRESSING);
  5318.           DefineInnerLangString(NLF_ERR_WRITING);
  5319.           DefineInnerLangString(NLF_EXTRACT);
  5320.           DefineInnerLangString(NLF_CANT_WRITE);
  5321.  
  5322.           ent.offsets[0]=build_overwrite;
  5323.           if (name_override)
  5324.           {
  5325.             ent.offsets[1]=add_string(name_override);
  5326.           }
  5327.           else
  5328.           {
  5329.             char *i=d.cFileName,*o=buf;
  5330.             while (*i)
  5331.             {
  5332.               char c=*i++;
  5333.               *o++=c;
  5334.               if (c == '$') *o++='$';
  5335.             }
  5336.             *o=0;
  5337.             ent.offsets[1]=add_string(buf);
  5338.           }
  5339.         }
  5340.         ent.offsets[2]=add_db_data(&mmap);
  5341.  
  5342.         mmap.clear();
  5343.  
  5344.         if (ent.offsets[2] < 0)
  5345.         {
  5346.           CloseHandle(hFile);
  5347.           return PS_ERROR;
  5348.         }
  5349.  
  5350.         if (data_handle)
  5351.         {
  5352.           *data_handle=ent.offsets[2];
  5353.         }
  5354.  
  5355.         {
  5356.           DWORD s=getcurdbsize()-last_build_datablock_used;
  5357.           if (s) s-=4;
  5358.           if (s != len) SCRIPT_MSG(" %d/%d bytes\n",s,len);
  5359.           else SCRIPT_MSG(" %d bytes\n",len);
  5360.         }
  5361.  
  5362.         if (generatecode)
  5363.         {
  5364.           if (build_datesave || build_overwrite>=0x3 /*ifnewer or ifdiff*/)
  5365.           {
  5366.             FILETIME ft;
  5367.             if (GetFileTime(hFile,NULL,NULL,&ft))
  5368.             {
  5369.               ent.offsets[3]=ft.dwLowDateTime;
  5370.               ent.offsets[4]=ft.dwHighDateTime;
  5371.             }
  5372.             else
  5373.             {
  5374.               CloseHandle(hFile);
  5375.               ERROR_MSG("%sFile: failed getting file date from \"%s\"\n",generatecode?"":"Reserve",newfn);
  5376.               return PS_ERROR;
  5377.             }
  5378.           }
  5379.           else
  5380.           {
  5381.             ent.offsets[3]=0xffffffff;
  5382.             ent.offsets[4]=0xffffffff;
  5383.           }
  5384.  
  5385.           // overwrite flag can be 0, 1, 2 or 3. in all cases, 2 bits
  5386.           int mb = 0;
  5387.           if (build_allowskipfiles)
  5388.           {
  5389.             mb = MB_ABORTRETRYIGNORE | MB_ICONSTOP;
  5390.             // default for silent installers
  5391.             mb |= IDIGNORE << 20;
  5392.           }
  5393.           else
  5394.           {
  5395.             mb = MB_RETRYCANCEL | MB_ICONSTOP;
  5396.             // default for silent installers
  5397.             mb |= IDCANCEL << 20;
  5398.           }
  5399.           ent.offsets[0] |= mb << 3;
  5400.  
  5401.           ent.offsets[5] = DefineInnerLangString(build_allowskipfiles ? NLF_FILE_ERROR : NLF_FILE_ERROR_NOIGNORE);
  5402.         }
  5403.  
  5404.         CloseHandle(hFile);
  5405.  
  5406.         if (generatecode)
  5407.         {
  5408.           int a=add_entry(&ent);
  5409.           if (a != PS_OK)
  5410.           {
  5411.             FindClose(h);
  5412.             return a;
  5413.           }
  5414.           if (attrib)
  5415.           {
  5416.             ent.which=EW_SETFILEATTRIBUTES;
  5417.             // $OUTDIR is the working directory
  5418.             ent.offsets[0]=add_string(name_override?name_override:buf);
  5419.             ent.offsets[1]=d.dwFileAttributes;
  5420.             ent.offsets[2]=0;
  5421.             ent.offsets[3]=0;
  5422.             ent.offsets[4]=0;
  5423.             ent.offsets[5]=0;
  5424.  
  5425.             a=add_entry(&ent);
  5426.             if (a != PS_OK)
  5427.             {
  5428.               FindClose(h);
  5429.               return a;
  5430.             }
  5431.           }
  5432.         }
  5433.       }
  5434.     } while (FindNextFile(h,&d));
  5435.     FindClose(h);
  5436.   }
  5437.  
  5438.   if (recurse)
  5439.   {
  5440. #ifdef NSIS_SUPPORT_STACK
  5441.     WIN32_FIND_DATA temp;
  5442.  
  5443.     int a=GetFileAttributes(lgss);
  5444.     const char *fspec=lgss+strlen(dir)+!!dir[0];
  5445.     strcpy(newfn,lgss);
  5446.     if (a==INVALID_FILE_ATTRIBUTES)
  5447.     {
  5448.       a=GetFileAttributes(dir);
  5449.       sprintf(newfn,"%s%s*.*",dir,dir[0]?"\\":"");
  5450.     }
  5451.     else
  5452.     {
  5453.       // we don't want to include a whole directory if it's not the first call
  5454.       if (rec_depth) return PS_OK;
  5455.       fspec="*.*";
  5456.     }
  5457.     if (a&FILE_ATTRIBUTE_DIRECTORY)
  5458.     {
  5459.       h=FindFirstFile(newfn,&d);
  5460.       if (h != INVALID_HANDLE_VALUE)
  5461.       {
  5462.         do
  5463.         {
  5464.           if (d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  5465.           {
  5466.             if (strcmp(d.cFileName,"..") && strcmp(d.cFileName,"."))
  5467.             {
  5468.               entry ent={0,};
  5469.               int a;
  5470.               char out_path[1024] = "$OUTDIR\\";
  5471.  
  5472.               {
  5473.                 char *i = d.cFileName, *o=out_path+strlen(out_path);
  5474.  
  5475.                 while (*i)
  5476.                 {
  5477.                   char *ni=CharNext(i);
  5478.                   if (ni-i > 1)
  5479.                   {
  5480.                     int l=ni-i;
  5481.                     while (l--)
  5482.                     {
  5483.                       *o++=*i++;
  5484.                     }
  5485.                   }
  5486.                   else
  5487.                   {
  5488.                     char c=*i++;
  5489.                     *o++=c;
  5490.                     if (c == '$') *o++='$';
  5491.                   }
  5492.                 }
  5493.                 *o=0;
  5494.               }
  5495.  
  5496.               char spec[1024];
  5497.               sprintf(spec,"%s%s%s",dir,dir[0]?"\\":"",d.cFileName);
  5498.               SCRIPT_MSG("%sFile: Descending to: \"%s\"\n",generatecode?"":"Reserve",spec);
  5499.               strcat(spec,"\\");
  5500.               strcat(spec,fspec);
  5501.               if (generatecode)
  5502.               {
  5503.                 a=add_entry_direct(EW_PUSHPOP, add_string("$OUTDIR"));
  5504.                 if (a != PS_OK)
  5505.                 {
  5506.                   FindClose(h);
  5507.                   return a;
  5508.                 }
  5509.  
  5510.                 a=add_entry_direct(EW_ASSIGNVAR, m_UserVarNames.get("OUTDIR"), add_string(out_path));
  5511.                 if (a != PS_OK)
  5512.                 {
  5513.                   FindClose(h);
  5514.                   return a;
  5515.                 }
  5516.  
  5517.                 HANDLE htemp = FindFirstFile(spec,&temp);
  5518.                 if (htemp != INVALID_HANDLE_VALUE)
  5519.                 {
  5520.                   FindClose(htemp);
  5521.  
  5522.                   a=add_entry_direct(EW_CREATEDIR, add_string("$OUTDIR"), 1);
  5523.                   if (a != PS_OK)
  5524.                   {
  5525.                     FindClose(h);
  5526.                     return a;
  5527.                   }
  5528.                 }
  5529.               }
  5530.               a=do_add_file(spec,attrib,recurse,linecnt,total_files,NULL,generatecode,data_handle,rec_depth+1);
  5531.               if (a != PS_OK)
  5532.               {
  5533.                 FindClose(h);
  5534.                 return a;
  5535.               }
  5536.  
  5537.               if (generatecode)
  5538.               {
  5539.                 a=add_entry_direct(EW_PUSHPOP, m_UserVarNames.get("OUTDIR"), 1);
  5540.                 if (a != PS_OK)
  5541.                 {
  5542.                   FindClose(h);
  5543.                   return a;
  5544.                 }
  5545.  
  5546.                 if (attrib)
  5547.                 {
  5548.                   a=add_entry_direct(EW_SETFILEATTRIBUTES, add_string(out_path), d.dwFileAttributes);
  5549.                   if (a != PS_OK)
  5550.                   {
  5551.                     FindClose(h);
  5552.                     return a;
  5553.                   }
  5554.                 }
  5555.               }
  5556.               SCRIPT_MSG("%sFile: Returning to: \"%s\"\n",generatecode?"":"Reserve",dir);
  5557.             }
  5558.           }
  5559.         } while (FindNextFile(h,&d));
  5560.         FindClose(h);
  5561.  
  5562.         if (!rec_depth)
  5563.         {
  5564.           // return to the original $OUTDIR
  5565.           a=add_entry_direct(EW_CREATEDIR, add_string("$OUTDIR"), 1);
  5566.           if (a != PS_OK)
  5567.           {
  5568.             FindClose(h);
  5569.             return a;
  5570.           }
  5571.         }
  5572.       }
  5573.     }
  5574. #else
  5575.     ERROR_MSG("Error: recursive [Reserve]File requires NSIS_SUPPORT_STACK\n");
  5576.     return PS_ERROR;
  5577. #endif
  5578.   }
  5579.  
  5580.   return PS_OK;
  5581. }
  5582. #endif
  5583.