home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 March / CMCD0304.ISO / Software / Freeware / Programare / nullsoft / nsis20.exe / Contrib / Math / Source / Math.c next >
C/C++ Source or Header  |  2003-09-22  |  59KB  |  1,542 lines

  1. #include <windows.h>
  2. #include "mathcrt.h"
  3. #include "MyMath.h"
  4. #include "Math.h"
  5.  
  6. extern "C" int _fltused;
  7. int _fltused;
  8. ExpressionItem *stack;
  9.  
  10. int UserVarsCount, UserFuncsCount;
  11. UserVar UserVars[MAX_USER_VARS];
  12. UserFunc UserFuncs[MAX_USER_FUNCS];
  13.  
  14. void PrintTree(ExpressionItem *root, char *str);
  15. void ParseString(char *&sp, ExpressionItem* &itemplace);
  16. void CleanupItems(ExpressionItem* &itemplace);
  17. void PlaceVariable(char *&vb, ParseInfo *pi);
  18.  
  19. void PlaceNewItem(char *&vb, ParseInfo *pi, int precedence)
  20. {
  21.     ExpressionItem *newroot;
  22.     PlaceVariable(vb, pi);
  23.     if (pi->item == NULL) return;
  24.  
  25.     while ((pi->OpsStack) && ((((int) pi->OpsStack->param2) < precedence)
  26.         || ((((int)pi->OpsStack->param2) == precedence) 
  27.             && (precedence != OPERATOR_SET_PRECEDENCE))))
  28.     {
  29.         // second operand for our operator        
  30.         newroot = pi->OpsStack;
  31.         *((ExpressionItem **)&(newroot->param2)) = pi->item;
  32.         pi->OpsStack = newroot->next;
  33.         newroot->next = NULL;
  34.         pi->item = newroot;
  35.     }
  36.     // finally we have got new root 
  37.     newroot = pi->item;
  38.  
  39.     if (pi->SetupNewRoot)
  40.     {
  41.         (*pi->root)->next = newroot;
  42.         pi->root = &((*pi->root)->next);
  43.         pi->SetupNewRoot = 0;
  44.     }
  45.     if (pi->place == *pi->root) pi->place = *pi->root = newroot;
  46.     else *pi->root = newroot;    
  47.     // no item at our pockets
  48.     pi->item = NULL;
  49. }
  50.  
  51. #define NSIS_VARS_COUNT 27
  52. #define NSIS_VARS_STACK 25
  53. #define NSIS_VARS_NSTACK 26
  54.  
  55. typedef char smallstr[2];
  56. const smallstr NSISVariablesNames[NSIS_VARS_COUNT] = {{'r','0'}, {'r','1'}, {'r','2'}, {'r','3'}, {'r','4'}, {'r','5'}, {'r','6'}, {'r','7'}, {'r','8'}, {'r','9'}, 
  57. {'R','0'}, {'R','1'}, {'R','2'}, {'R','3'}, {'R','4'}, {'R','5'}, {'R','6'}, {'R','7'}, {'R','8'}, {'R','9'}, 
  58. {'C','L'}, {'I','D'}, {'O','D'}, {'E','D'}, {'L','G'}, {'S',0}, {'N','S'}};
  59.  
  60. ExpressionItem *FindVariable(char *varname)
  61. {
  62.     ExpressionItem *item = AllocItem();
  63.     // check NSIS variables
  64.     for (int i = 0; i < NSIS_VARS_COUNT; i++)
  65.     {
  66.         if (lstrcmpn(varname, NSISVariablesNames[i],2) == 0)
  67.         {
  68.             if (i == NSIS_VARS_STACK) item->type = IT_VARIABLE | ITV_STACK;
  69.             else if (i == NSIS_VARS_NSTACK) item->type = IT_VARIABLE | ITV_NSTACK;
  70.             else
  71.                 item->type = (IT_VARIABLE | ITV_NSIS) + i;
  72.             return item;
  73.         }
  74.     }
  75.     // no.. that's user variable
  76.     for (int i = 0; i < UserVarsCount; i++)
  77.     {
  78.         if (lstrcmp(varname, UserVars[i].name) == 0)
  79.         {
  80.             // ok. we found user var expression needed
  81.             break;
  82.         }
  83.     }
  84.     if (i == UserVarsCount)
  85.     {
  86.         // new variable
  87.         UserVarsCount++;
  88.         lstrcpy(UserVars[i].name, varname);
  89.         UserVars[i].item = NULL;
  90.     }
  91.     item->type = (IT_VARIABLE | ITV_USER) + i;
  92.     return item;
  93. }
  94.  
  95. void PlaceVariable(char *&vb, ParseInfo *pi)
  96. {
  97.     if (vb <= pi->valbuf) return;
  98.     *vb = 0;
  99.     pi->item = FindVariable(pi->valbuf);
  100.     vb = pi->valbuf;
  101. }
  102.  
  103. #define MATHFUNCNUM 29
  104. const MathFunction MathFunctions[MATHFUNCNUM] = {
  105.     {{'s','i','n'}, ITF_MATH1 >> 8, _fsin},
  106.     {{'s','n','h'}, ITF_MATH1 >> 8, _fsinh},
  107.     {{'a','s','n'}, ITF_MATH1 >> 8, _fasin},
  108.     {{'c','o','s'}, ITF_MATH1 >> 8, _fcos},
  109.     {{'c','s','h'}, ITF_MATH1 >> 8, _fcosh},
  110.     {{'a','c','s'}, ITF_MATH1 >> 8, _facos},
  111.     {{'t','a','n'}, ITF_MATH1 >> 8, _ftan},
  112.     {{'t','n','h'}, ITF_MATH1 >> 8, _ftanh},
  113.     {{'a','t','n'}, ITF_MATH1 >> 8, _fatan},
  114.     {{'a','b','s'}, ITF_MATH1 >> 8, _fabs},
  115.     {{'l','n',0}, ITF_MATH1 >> 8, _flog},
  116.     {{'l','o','g'}, ITF_MATH1 >> 8, _flog10},
  117.     {{'e','x','p'}, ITF_MATH1 >> 8, _fexp},
  118.     {{'s','q','t'}, ITF_MATH1 >> 8, _fsqrt},
  119.     {{'c','e','l'}, ITF_MATH1 >> 8, _fceil},
  120.     {{'f','l','r'}, ITF_MATH1 >> 8, _floor},
  121.  
  122.     {{'a','t','2'}, ITF_MATH2 >> 8, (Math1FuncPtr)_fatan2},
  123.     {{'p','o','w'}, ITF_MATH2 >> 8, (Math1FuncPtr)_fpow},
  124.     {{'f','m','d'}, ITF_MATH2 >> 8, (Math1FuncPtr)_fmod},
  125.  
  126.     // type conversions
  127.     {{'i',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)ITC_INT},
  128.     {{'s',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)ITC_STRING},
  129.     {{'f',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)ITC_FLOAT},
  130.     {{'a',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)ITC_ARRAY},
  131. #define ITFT_CARRAY_ID    23
  132.     {{'c','a',0}, ITF_TYPE >> 8, (Math1FuncPtr)ITC_ARRAY},
  133.     {{'f','f',0}, ITF_TYPE >> 8, (Math1FuncPtr)FTT_FLOATF},
  134.     {{'l',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)FTT_LEN},
  135.     {{'c',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)FTT_CHAR},
  136.  
  137.     {{'f','e','x'}, ITF_MATH2 >> 8, (Math1FuncPtr)_frexp},
  138.     {{'m','d','f'}, ITF_MATH2 >> 8, (Math1FuncPtr)_fmodf},
  139. };
  140.  
  141. void PlaceFunction(char *&vb, char *&sp, ParseInfo *pi, int redefine)
  142. {
  143.     ExpressionItem *item = pi->item = AllocItem();
  144.     *vb = 0;
  145.     
  146.     // check BUILTIN functions
  147.     for (int i = 0; i < MATHFUNCNUM; i++)
  148.     {
  149.         if (lstrcmpn(pi->valbuf, MathFunctions[i].name, 3) == 0)
  150.         {
  151.             item->type = IT_FUNCTION | (MathFunctions[i].type << 8) | i;
  152.             // get first argument
  153.             sp++;
  154.             ParseString(sp, *((ExpressionItem **)(&item->param1)));
  155.             if (*sp == ',')
  156.             {
  157.                 // get second argument
  158.                 sp++;
  159.                 ParseString(sp, *((ExpressionItem **)(&item->param2)));
  160.             }
  161.             sp++; vb = pi->valbuf;            
  162.             return;
  163.         }
  164.     }
  165.  
  166.     // heh, may be it user function
  167.     for (int i = 0; i < UserFuncsCount; i++)
  168.     {
  169.         if (lstrcmp(pi->valbuf, UserFuncs[i].name) == 0)
  170.         {
  171.             // Function found? Redefine option specified?
  172.             if (redefine) break;
  173.  
  174.             item->type = IT_FUNCTION | ITF_USER | i;
  175.             // get arguments list
  176.             ExpressionItem **newplace = ((ExpressionItem **)(&pi->item->param1));
  177.             while (*sp != ')')
  178.             {
  179.                 *newplace = AllocItem();
  180.                 (*newplace)->type = IT_EXPRESSION;
  181.                 sp++;
  182.                 ParseString(sp, *((ExpressionItem **)(&(*newplace)->param1)));
  183.                 newplace = &((*newplace)->next);
  184.             }
  185.             sp++; vb = pi->valbuf;            
  186.             return;
  187.         }
  188.     }
  189.  
  190.     // oops, we need no item for function defenition
  191.     CleanupItems(item); pi->item = NULL;    
  192.  
  193.     // it's user function define
  194.     int flags = 0;
  195.     char buffer[128], *buf = buffer;
  196.  
  197.     // workaround for redefine flag - if the function already present,
  198.     // it will be cleared and redefined
  199.     UserFunc *f = &UserFuncs[i];
  200.     if (i == UserFuncsCount) UserFuncsCount++;
  201.     else CleanupItems(f->root);
  202.  
  203.     lstrcpy(f->name, pi->valbuf);
  204.     f->varflags = 0;
  205.     f->varsnum = 0;    
  206.     do
  207.     {
  208.         sp++;
  209.         switch (*sp)
  210.         {
  211.         case ' ':
  212.             break;
  213.         case ',':
  214.         case ')':            
  215.             if (buf > buffer)
  216.             {
  217.                 *buf = 0;
  218.                 // it should be user variable
  219.                 ExpressionItem *it = FindVariable(buffer);
  220.                 f->vars[f->varsnum++] = (it->type) & ITEMOPTIONS;
  221.                 CleanupItems(it);
  222.                 buf = buffer;
  223.                 flags <<= 1;
  224.             }            
  225.             break;
  226.         case '&':
  227.             flags |= 1;
  228.             break;
  229.         default:
  230.             *(buf++) = *sp;
  231.             break;
  232.         }
  233.     }
  234.     while (*sp != ')');
  235.  
  236.     // prepare flag for fast analisys
  237.     for (int i = 0; i < f->varsnum; i++)
  238.     {
  239.         f->varflags <<= 1;
  240.         flags >>= 1;
  241.         f->varflags |= flags&1;
  242.     }
  243.  
  244.     // find nearest round bracket - function body
  245.     while (*sp != '(') sp++;
  246.     sp++;    
  247.  
  248.     // now we are ready to parse function body
  249.     ParseString(sp, f->root);
  250.     sp++; // closing bracket
  251.     vb = pi->valbuf;
  252.  
  253. #ifdef _DEBUG
  254.   // dump function (in debug mode)
  255.   char place[1024];
  256.   wsprintf(place, "function %s(", f->name);
  257.   flags = f->varflags;
  258.   for (int i = 0; i < f->varsnum; i++)
  259.   {
  260.     if (flags&1) lstrcat(place, "&");
  261.     lstrcat(place, UserVars[f->vars[i]].name);
  262.     if (i < f->varsnum-1) lstrcat(place, ", ");
  263.     flags >>= 1;
  264.   }
  265.   lstrcat(place, ")");                
  266.   PrintTree(f->root, place);
  267. #endif
  268. }
  269.  
  270. // operator options
  271. #define PO_UNARYPRE    0x1 // this operator can be uniary pre (--a) for ex
  272. #define PO_UNARYPOST   0x2 // this op can be uniary post (a++) (couldn't be binary)
  273. #define PO_PRENONCONST  0x4 // pre argument (a = b) -> a is non const
  274. #define PO_POSTNONCONST 0x8 // post argument (b--) is non const
  275. #define PO_LASTOP      0x10 // op should be the last item at expression (=, -=, etc)
  276. #define PO_SET         0x20 // op will set new value to one of args
  277. #define PO_USESPRE     0x40 // operator will use pre operand
  278. #define PO_USESPOST    0x80 // operator will use post operan
  279.  
  280. void PlaceOp(char *&vb, int type, int precedence, ParseInfo *pi)
  281. {
  282.     PlaceVariable(vb, pi);
  283.     if ((type & PO_UNARYPRE) && (!pi->item))
  284.     {
  285.         // uniary pre op
  286.         ExpressionItem *item = AllocItem();
  287.         item->type = type;
  288.         item->param2 = (EIPARAM) precedence;
  289.         item->next = pi->OpsStack;        
  290.         pi->OpsStack = item;
  291.     }
  292.     else 
  293.     {
  294.         // get previous tree as items and operators of lower precedence
  295.         PlaceNewItem(vb, pi, precedence);
  296.         // post operators
  297.         ExpressionItem *item = AllocItem();
  298.         item->type = type;
  299.         item->param1 = (EIPARAM) (*pi->root);
  300.  
  301.         if (pi->place == *pi->root) pi->place = *pi->root = NULL;
  302.         else *pi->root = NULL;    
  303.  
  304.         if (type & PO_UNARYPOST)
  305.         {
  306.             // uniary post op
  307.             pi->item = item;
  308.         } else
  309.         {
  310.             // binary operator
  311.             item->param2 = (EIPARAM) precedence;
  312.             item->next = pi->OpsStack;
  313.             pi->OpsStack = item;
  314.         }
  315.     }
  316. }
  317.  
  318. #define OPSNUM  35
  319. const OpStruct Operators[OPSNUM] =
  320. {
  321. // three byte ops
  322. {{'>','>','='}, 14, ITO_SHR | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
  323. {{'<','<','='}, 14, ITO_SHL | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
  324.  
  325. // two byte ops
  326. // !!! don't forget to change Set Operator Precedence !!!
  327. {"-=", 14, ITO_MINUS | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
  328. {"+=", 14, ITO_PLUS | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
  329. {"/=", 14, ITO_DIV | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
  330. {"*=", 14, ITO_MUL | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
  331. {"|=", 14, ITO_OR | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
  332. {"&=", 14, ITO_AND | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
  333. {"^=", 14, ITO_XOR | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
  334. {"%=", 14, ITO_MOD | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
  335. {"--", 2, ITO_DEC | PO_POSTNONCONST | PO_PRENONCONST | PO_UNARYPRE | PO_UNARYPOST | PO_SET | PO_USESPRE | PO_USESPOST},
  336. {"++", 2, ITO_INC | PO_POSTNONCONST | PO_PRENONCONST | PO_UNARYPRE | PO_UNARYPOST | PO_SET | PO_USESPRE | PO_USESPOST},
  337. {">>", 6, ITO_SHR | PO_USESPRE | PO_USESPOST},
  338. {"<<", 6, ITO_SHL | PO_USESPRE | PO_USESPOST},
  339.  
  340. // logical
  341. {"&&", 12, ITO_LAND | PO_USESPRE | PO_USESPOST},
  342. {"||", 13, ITO_LOR | PO_USESPRE | PO_USESPOST},
  343.  
  344. // comparisons
  345. {"<=", 7, ITO_LE | PO_USESPRE | PO_USESPOST},
  346. {"=<", 7, ITO_LE | PO_USESPRE | PO_USESPOST},
  347. {">=", 7, ITO_GE | PO_USESPRE | PO_USESPOST},
  348. {"=>", 7, ITO_GE | PO_USESPRE | PO_USESPOST},
  349. {"!=", 8, ITO_NE | PO_USESPRE | PO_USESPOST},
  350. {"==", 8, ITO_EQ | PO_USESPRE | PO_USESPOST},
  351.  
  352. // single byte ops
  353. // !!! don't forget to change Set Operator Precedence !!!
  354. {"=", 14, ITO_SET | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPOST}, 
  355. {"+", 5, ITO_PLUS | PO_USESPRE | PO_USESPOST},
  356. {"-", 5, ITO_MINUS | PO_USESPRE | PO_USESPOST | PO_UNARYPRE},
  357. {"*", 4, ITO_MUL | PO_USESPRE | PO_USESPOST | PO_UNARYPRE},
  358. {"/", 4, ITO_DIV | PO_USESPRE | PO_USESPOST},
  359. {"%", 4, ITO_MOD | PO_USESPRE | PO_USESPOST},
  360. {"<", 7, ITO_LS | PO_USESPRE | PO_USESPOST},
  361. {">", 7, ITO_GR | PO_USESPRE | PO_USESPOST},
  362. {"&", 9, ITO_AND | PO_USESPRE | PO_USESPOST | PO_UNARYPRE},
  363. {"|", 11, ITO_OR | PO_USESPRE | PO_USESPOST},
  364. {"^", 10, ITO_XOR | PO_USESPRE | PO_USESPOST},
  365. {"~", 3, ITO_NOT | PO_USESPOST | PO_UNARYPRE},
  366. {"!", 3, ITO_LNOT |PO_USESPOST | PO_UNARYPRE}
  367. };
  368.  
  369. void CheckForOperator(char *&sp, char *&vb, ParseInfo *pi)
  370. {
  371.     for (int op = 0; op < OPSNUM; op++)
  372.     {        
  373.         int c = lstrlen(Operators[op].name);
  374.         if (c > 3) c = 3; // real operator length
  375.         if (lstrcmpn(sp, Operators[op].name, c))
  376.         {
  377.             // wrong - different op
  378.             continue;
  379.         }
  380.         // that is our op
  381.         sp += c;
  382.         PlaceOp(vb, ((int) Operators[op].type) | IT_OPERATOR, Operators[op].precedence, pi);
  383.         break;
  384.     }
  385. }
  386.  
  387. void ParseString(char *&sp, ExpressionItem* &itemplace)
  388. {
  389.     ParseInfo pi = {0, NULL, NULL, itemplace, &itemplace};
  390.  
  391.     int redefine = 0;
  392.     char *vb = pi.valbuf;
  393.     // cycle until current expression end
  394.     while ((*sp != 0) && (*sp != ')') && (*sp != '}') &&
  395.         (*sp != ']') && (*sp != ','))
  396.     {
  397.         int processed = 1;
  398.         switch (*sp)
  399.         {
  400.         case ' ':
  401.         case '\t':
  402.             sp++;
  403.             break;
  404.         case ';':
  405.             // expression delimeter
  406.             PlaceNewItem(vb, &pi, 255);
  407.             if (*pi.root) pi.SetupNewRoot = 1;
  408.             sp++;
  409.             break;
  410.         case '0': case '1': case '2': case '3': case '4': 
  411.         case '5': case '6': case '7': case '8': case '9':
  412.             // variable & function names could contain numbers as non first chars
  413.             if (vb > pi.valbuf) 
  414.             {
  415.                 processed = FALSE;
  416.                 break;
  417.             }
  418.         case '\'': case '\"': case '`':
  419.             // constant meet
  420.             pi.item = AllocItem();
  421.             StringToItem(sp, pi.item, STI_STRING | STI_FLOAT | STI_INT);
  422.             break;
  423.  
  424.         case '(': // start of function or expression
  425.             if (vb > pi.valbuf)
  426.             {
  427.                 // thats function
  428.                 PlaceFunction(vb, sp, &pi, redefine);                
  429.             } else
  430.             {
  431.                 // expression
  432.                 sp++;
  433.                 ParseString(sp, pi.item);
  434.                 if (*sp == ')') sp++;
  435.             }
  436.             redefine = 0;
  437.             break;
  438.  
  439.         case '#':   // start of one of logical expresions
  440.             sp++;            
  441.             if ((*sp != '[') && (*sp != '{'))
  442.             {
  443.                 // function redefine flag
  444.                 redefine = 1;
  445.                 break;
  446.             }
  447.             {
  448.                 pi.item = AllocItem();
  449.                 // IF or WHILE
  450.                 pi.item->type = ((*sp == '[')?(IT_LOGIC | ITL_IF):(IT_LOGIC | ITL_WHILE));
  451.                 // first expr - logic statement
  452.                 sp++;
  453.             
  454.                 ParseString(sp, *((ExpressionItem **)(&pi.item->param1)));
  455.                 // ok, second expr - then, third - else statement.. others???
  456.                 ExpressionItem **newplace = ((ExpressionItem **)(&pi.item->param2));
  457.                 while (*sp == ',')
  458.                 {
  459.                     *newplace = AllocItem();
  460.                     (*newplace)->type = IT_EXPRESSION;
  461.                     sp++;
  462.                     ParseString(sp, *((ExpressionItem **)(&(*newplace)->param1)));
  463.                     newplace = &((*newplace)->next);
  464.                 }
  465.             }
  466.             sp++;
  467.             break;
  468.  
  469.         case '[':
  470.             {
  471.             // thats array access 
  472.             PlaceOp(vb, IT_ARRAY | ITA_ACCESS | PO_UNARYPOST, 1, &pi);
  473.             sp++;
  474.             // item index
  475.             ParseString(sp, *(ExpressionItem **)&(pi.item->param2));
  476.             if (*sp == ',')
  477.             {
  478.                 // two indexes - string access
  479.                 ExpressionItem *it = AllocItem();
  480.                 it->type = IT_EXPRESSION;
  481.                 it->param1 = (EIPARAM)  *(ExpressionItem **)&(pi.item->param2);
  482.                 *(ExpressionItem **)&(pi.item->param2) = it;
  483.                 it = it->next = AllocItem();
  484.                 it->type = IT_EXPRESSION;
  485.                 sp++;
  486.                 ParseString(sp, *((ExpressionItem **)(&it->param1)));
  487.             }
  488.             sp++;
  489.             }
  490.             break;
  491.  
  492.         case '{':   // start of array define
  493.             {            
  494.                 // array define - constists of array copy operator and array define itself
  495.  
  496.                 // type conversion item (to create a copy of array)
  497.                 pi.item = AllocItem();
  498.                 pi.item->type = IT_FUNCTION | ITF_TYPE | ITFT_CARRAY_ID | ITFA_COPY;
  499.  
  500.                 // during first create our array descriptor and array pointers 
  501.                 ExpressionItem *ai = AllocArray(DEFAULT_ARRAY_SIZE);
  502.                 pi.item->param1 = (EIPARAM)  ai;
  503.                 ArrayDesc *ad = *((ArrayDesc**)&(ai->param1));
  504.  
  505.                 // parse array initializers
  506.                 while (*sp != '}')
  507.                 {
  508.                     sp++;
  509.                     ParseString(sp, ad->array[ad->count++]); 
  510.                 }
  511.  
  512.                 sp++;
  513.             }
  514.             break;
  515.         case '-': case '+': case '<': case '=': case '>':
  516.         case '/': case '*': case '~': case '^': case '!':
  517.         case '&': case '|': case '%': 
  518.             CheckForOperator(sp, vb, &pi);
  519.             break;
  520.  
  521.         // non expression? ok, then it should be common char, like function or var name
  522.         default:
  523.             processed = FALSE;
  524.             break;
  525.         }
  526.         if (!processed) *(vb++) = *(sp++);
  527.     }
  528.     PlaceNewItem(vb, &pi, 255);
  529. }
  530.  
  531. void CleanupArray(ArrayDesc *ad)
  532. {
  533.     if (!(--(ad->references)))
  534.     {
  535.         // last array reference, we could kill it
  536.         // cleanup array items
  537.         for (int i = 0; i < ad->count; i++)
  538.         {
  539.             ExpressionItem *aritem = ad->array[i];
  540.             if (aritem)
  541.                 CleanupItems(aritem);
  542.         }
  543.         // cleanup ptrs and descriptor
  544.         dbgGlobalFree(ad->array);
  545.         dbgGlobalFree(ad);
  546.     }
  547.  }
  548.  
  549. void CleanupItems(ExpressionItem* &itemplace)
  550. {
  551.     if (itemplace == NULL) return;
  552.     ExpressionItem *item = itemplace, *itemnext;
  553.     do
  554.     {
  555.         if (((item->type & (ITEMTYPE|ITEMSUBTYPE)) == (IT_VARIABLE|ITV_ARRITEM))
  556.             ||
  557.             ((item->type & (ITEMTYPE|ITEMSUBTYPE)) == (IT_CONST|ITC_ARRAY)))
  558.         {
  559.             CleanupArray((ArrayDesc *)item->param1);
  560.         }
  561.         else
  562.         if ((item->type & ITEMTYPE) == IT_CONST)
  563.         {
  564.             if ((item->type & ITEMSUBTYPE) == ITC_STRING)
  565.                 dbgGlobalFree((HGLOBAL) item->param1);
  566.         } else 
  567.         {
  568.             CleanupItems(*((ExpressionItem**) &item->param1));
  569.             CleanupItems(*((ExpressionItem**) &item->param2));
  570.         }
  571.         // free the item itself
  572.         itemnext = item->next;
  573.         dbgGlobalFree((HGLOBAL) item);
  574.         item = itemnext;
  575.     } while (item != NULL);    
  576.     itemplace = NULL;
  577. }
  578.  
  579. #ifdef _DEBUG
  580. HANDLE myfile;
  581.  
  582. char *opsnames[] = {"", "-", "+", "<<", ">>", "*", "/", "=", "&&", "||", "++", "--",
  583. "=<", ">=", "!=", "==", "<", ">", "&", "%", "|", "^", "~", "!"};
  584.  
  585. void PrintNode(int index, int spaces, ExpressionItem* itemplace)
  586. {
  587.     if (itemplace == NULL) return;
  588.     
  589.     ExpressionItem *item = itemplace;
  590.     do
  591.     {
  592.         DWORD wrote;
  593.         char buffer[1024], *place = buffer;
  594.         for (int k = 0; k < spaces; k++)
  595.             *(place++) = 32;
  596.         *place = 0;
  597.  
  598.         switch (item->type & ITEMTYPE)
  599.         {
  600.         case  IT_EXPRESSION:
  601.             wsprintf(place, "Expression Place-Holder   ");
  602.             break;
  603.         case  IT_CONST:
  604.             switch (item->type & ITEMSUBTYPE)
  605.             {
  606.             case ITC_STRING:                
  607.                 wsprintf(place, "String: \"%s\"", (char *) item->param1);
  608.                 break;
  609.             case ITC_INT:
  610.                 wsprintf(place, "Int: ");
  611.                 itoa64(*((__int64*)&(item->param1)), place+5);
  612.                 break;
  613.             case ITC_FLOAT:                
  614.                 wsprintf(place, "Float: ");
  615.                 FloatFormat(place+7, *((double*)&(item->param1)), 6);
  616.                 break;
  617.             case ITC_ARRAY:
  618.                 ArrayDesc *ad = (ArrayDesc*) item->param1;
  619.                 wsprintf(place, "Array, ptr %08X, size %d, count %d, references %d", 
  620.                     ad->array, ad->size, ad->count, ad->references);                
  621.                 break;
  622.             }
  623.             strcat(place, "    ");
  624.             break;
  625.         case IT_OPERATOR:
  626.             wsprintf(place, "Op: %s%s    ", opsnames[(item->type & ITEMSUBTYPE) >> 8], (item->type & PO_SET)?("(=)"):(""));
  627.             break;
  628.         case IT_VARIABLE:
  629.             switch (item->type & ITEMSUBTYPE)
  630.             {
  631.             case ITV_NSIS:
  632.                 {
  633.                 char buffer[128];
  634.                 buffer[0] = NSISVariablesNames[item->type & ITEMOPTIONS][0];
  635.                 buffer[1] = NSISVariablesNames[item->type & ITEMOPTIONS][1];
  636.                 buffer[2] = 0;
  637.                 wsprintf(place, "Var: %s (%d)   ", 
  638.                     buffer,
  639.                     item->type & ITEMOPTIONS);
  640.                 }
  641.                 break;
  642.             case ITV_USER:
  643.                 wsprintf(place, "Var: %s (%d)   ", UserVars[item->type & ITEMOPTIONS].name, item->type & ITEMOPTIONS);
  644.                 break;
  645.             case ITV_STACK:
  646.                 wsprintf(place, "Plugin Stack   ");
  647.                 break;
  648.             case ITV_NSTACK:
  649.                 wsprintf(place, "NSIS Stack   ");
  650.                 break;
  651.             }
  652.             break;
  653.         case IT_LOGIC:
  654.             if ((item->type & ITEMSUBTYPE) == ITL_IF)
  655.                 wsprintf(place, "IF ");
  656.             else
  657.                 wsprintf(place, "WHILE ");
  658.             break;
  659.         case IT_FUNCTION:
  660.             if (((item->type & ITEMSUBTYPE) == ITF_MATH1) ||
  661.                 ((item->type & ITEMSUBTYPE) == ITF_MATH2) ||
  662.                 ((item->type & ITEMSUBTYPE) == ITF_TYPE))
  663.             {
  664.                 char buffer[128];
  665.                 buffer[0] = (MathFunctions[item->type &ITEMOPTIONS].name)[0];
  666.                 buffer[1] = (MathFunctions[item->type &ITEMOPTIONS].name)[1];
  667.                 buffer[2] = (MathFunctions[item->type &ITEMOPTIONS].name)[2];
  668.                 buffer[3] = 0;
  669.                 wsprintf(place, "Built-In Function %s() [%d] ", 
  670.                     buffer,
  671.                     item->type &ITEMOPTIONS);
  672.             }
  673.             else
  674.             {
  675.                 UserFunc *f = &(UserFuncs[item->type & ITEMOPTIONS]);
  676.                 wsprintf(place, "User Function: %s(", f->name);
  677.                 int flags = f->varflags;
  678.                 for (int i = 0; i < f->varsnum; i++)
  679.                 {
  680.                     if (flags&1) lstrcat(place, "&");
  681.                     lstrcat(place, UserVars[f->vars[i]].name);
  682.                     if (i < f->varsnum-1) lstrcat(place, ", ");
  683.                     flags >>= 1;
  684.                 }
  685.                 lstrcat(place, ")   ");
  686.             }
  687.             break;
  688.         case IT_ARRAY:
  689.             wsprintf(place, "Array access []   ");
  690.             break;
  691.         } 
  692.         place += lstrlen(place);
  693.         wsprintf(place, "Addr: %08X Type: %08X   Next: %08X  Param1: %08X  Param2: %08X", item, item->type, item->next, item->param1, item->param2);
  694.         lstrcat(place, "\n");
  695.         WriteFile(myfile, buffer, lstrlen(buffer), &wrote, NULL);
  696.         if (((item->type & ITEMTYPE) != IT_CONST) && ((item->type & (ITEMTYPE|ITEMSUBTYPE)) != (IT_VARIABLE|ITV_ARRITEM)))
  697.         {
  698.             place = buffer;
  699.             for (int k = 0; k < spaces+2; k++)
  700.                 *(place++) = 32;
  701.             int show = 0;
  702.             if (((item->param1 != NULL) && ((*((ExpressionItem**) &item->param1))->next != NULL)) ||
  703.                 ((item->param2 != NULL) && ((*((ExpressionItem**) &item->param2))->next != NULL)))
  704.                 show = 1;
  705.             if (show)
  706.             {
  707.                 wsprintf(place, "Sub1:\n"); 
  708.                 WriteFile(myfile, buffer, lstrlen(buffer), &wrote, NULL);
  709.             }
  710.             PrintNode(1, spaces + 4, *((ExpressionItem**) &item->param1));
  711.             if (show)
  712.             {
  713.                 wsprintf(place, "Sub2:\n"); 
  714.                 WriteFile(myfile, buffer, lstrlen(buffer), &wrote, NULL);
  715.             }
  716.             PrintNode(2, spaces + 4, *((ExpressionItem**) &item->param2));
  717.         } else if ((item->type & (ITEMSUBTYPE|ITEMTYPE)) == (ITC_ARRAY|IT_CONST))
  718.         {
  719.             ArrayDesc *ad = (ArrayDesc *) item->param1;
  720.             for (int i = 0; i < ad->count; i++)
  721.             {
  722.                 ExpressionItem *aritem = ad->array[i];
  723.                 if (aritem)
  724.                     PrintNode(2, spaces + 4, aritem);
  725.             }
  726.         }
  727.         item = item->next;
  728.     } while (item != NULL);    
  729. }
  730.  
  731. void PrintTree(ExpressionItem *root, char *str)
  732. {
  733.     myfile = CreateFile("d:\\math.debug", GENERIC_ALL, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, 0);
  734.     SetFilePointer(myfile, 0, NULL, FILE_END);
  735.     char buffer[1024]; DWORD wrote;
  736.     wsprintf(buffer, "New tree for \'%s\'\n", str);
  737.     WriteFile(myfile, buffer, lstrlen(buffer), &wrote, NULL);
  738.  
  739.     PrintNode(0, 4, root);
  740.     CloseHandle(myfile);
  741.     myfile = NULL;
  742. }
  743. #endif
  744.  
  745. void CopyArray(ExpressionItem *&item)
  746. {
  747.     if (item == NULL) return;
  748.     // especial case - array to array conversion is requested array copy
  749.     ExpressionItem *olditem = item;
  750.     ArrayDesc *oad = (ArrayDesc *) (olditem->param1);
  751.     // Initialize the array of the same size
  752.     item = AllocArray(oad->size);
  753.     ArrayDesc *nad = (ArrayDesc *) (item->param1);
  754.     nad->count = oad->count;
  755.     // copy items
  756.     for (int i = 0; i < oad->count; i++)
  757.        nad->array[i] = CopyItem(oad->array[i], TRUE);
  758.     // cleanup old array pointer (may be array itself)
  759.     CleanupItems(olditem);
  760. }
  761.  
  762. void ItemToType(ExpressionItem* &item, int type)
  763. {
  764.     char *buffer;
  765.     if (item == NULL) return;
  766.     int itemt = item->type & ITEMTYPE, oldtype = item->type & ITEMSUBTYPE;
  767.  
  768.     if (((itemt == IT_CONST) && (oldtype == type)) 
  769.         || (itemt != IT_CONST)) return;
  770.  
  771.     switch (type)
  772.     {
  773.     case ITC_STRING:
  774.         buffer = AllocString();
  775.         ItemToString(buffer, item);
  776.         item->param1 = (EIPARAM)  buffer;
  777.         item->param2 = 0;
  778.         break;
  779.     case ITC_FLOAT:
  780.         if (oldtype == ITC_INT) 
  781.             *((double *)&(item->param1)) = (double) *((__int64 *)&(item->param1));
  782.         else
  783.         {
  784.             buffer = (char*) item->param1;
  785.             StringToItem(buffer, item, STI_FLOAT);
  786.             dbgGlobalFree(buffer);
  787.         }
  788.         break;
  789.     case ITC_INT:
  790.         if (oldtype == ITC_FLOAT) 
  791.             *((__int64 *)&(item->param1)) = (__int64) *((double *)&(item->param1));
  792.         else
  793.         {
  794.             buffer = (char*) item->param1;
  795.             StringToItem(buffer, item, STI_INT);
  796.             dbgGlobalFree(buffer);
  797.         }
  798.         break;
  799.     case ITC_ARRAY:
  800.         if (oldtype == ITC_STRING)
  801.         {
  802.             char *buf = (char*) item->param1;
  803.             int len = lstrlen(buf)+1;            
  804.             ExpressionItem *ni = AllocArray(lstrlen(buf)+1);
  805.             ArrayDesc *ad = (ArrayDesc*) ni->param1;
  806.             for (int i = 0; i < len; i++)
  807.             {
  808.                 ad->array[i] = AllocItem();
  809.                 *((__int64 *) &(ad->array[i]->param1)) = (__int64) buf[i];
  810.             }
  811.             ad->count = len;
  812.             CleanupItems(item);
  813.             item = ni;
  814.         }
  815.         break;
  816.     }
  817.     item->type = IT_CONST | type;
  818. }
  819.  
  820. void SaveResult(ExpressionItem *var, ExpressionItem *result)
  821. {
  822.     if ((var->type & ITEMTYPE) != IT_VARIABLE) return;
  823.  
  824.     // result should be stored at variable to
  825.     int varindex = var->type & ITEMOPTIONS;
  826.     switch (var->type & ITEMSUBTYPE)
  827.     {
  828.     case ITV_NSIS:
  829.         {
  830.             // store string result direct to NSIS variable
  831.             char *ptr = g_variables + varindex*g_stringsize;
  832.             ItemToString(ptr, result);
  833.         }
  834.         break;
  835.     case ITV_USER:
  836.         {
  837.             CleanupItems(UserVars[varindex].item);
  838.             UserVars[varindex].item = CopyItem(result);
  839.         }
  840.         break;
  841.     case ITV_ARRITEM:
  842.         {
  843.             ExpressionItem *&ei = ((ArrayDesc*)(var->param1))->array[(int)var->param2];
  844.             CleanupItems(ei);
  845.             ei = CopyItem(result);
  846.         }
  847.         break;
  848.     case ITV_STACK:
  849.         {
  850.             ExpressionItem *newitem = CopyItem(result);
  851.             newitem->next = stack;
  852.             stack = newitem;
  853.         }
  854.         break;
  855.     case ITV_NSTACK:
  856.         {
  857.             char *buf = AllocString();
  858.             ItemToString(buf, result);
  859.             pushstring(buf);
  860.             dbgGlobalFree(buf);
  861.         }
  862.         break;
  863.     }
  864. }
  865.  
  866. void RunAndGetConst(int from, ExpressionItem* &result, int type)
  867. {
  868.     RunTree(*((ExpressionItem**)&(from)), result, type | RTO_NEEDCONST);
  869.     ItemToType(result, type);
  870. }
  871.  
  872. void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
  873. {
  874.     ExpressionItem *item = from;
  875.     result = NULL;
  876.     while (item != NULL)
  877.     {
  878.         CleanupItems(result);
  879.         int type = item->type & ITEMTYPE, 
  880.             subtype = item->type & ITEMSUBTYPE,
  881.             ioptions = item->type & ITEMOPTIONS;
  882.         switch (type)
  883.         {
  884.         case IT_EXPRESSION:
  885.             RunTree(*((ExpressionItem**)&(item->param1)), result, options);
  886.             break;
  887.         case IT_CONST:
  888.             result = CopyItem(item);
  889.             break;
  890.         case IT_VARIABLE:
  891.             if (options & RTO_NEEDCONST)
  892.             {
  893.                 // we need const result - :) is it nsis or common variable
  894.                 switch (subtype)
  895.                 {
  896.                 case ITV_NSIS:
  897.                     {
  898.                         // nsis                  
  899.                         result = AllocItem();
  900.                         char *variable = getuservariable(ioptions);
  901.                         StringToItem(variable, result, options); 
  902.                     }
  903.                     break;
  904.                 case ITV_USER:
  905.                     {
  906.                         // usual variable
  907.                         if (UserVars[ioptions].item)
  908.                             result = CopyItem(UserVars[ioptions].item);
  909.                         else
  910.                             result = AllocItem();
  911.                     }
  912.                     break;
  913.                 case ITV_ARRITEM:
  914.                     {
  915.                         // array item
  916.                         ExpressionItem *ei = ((ArrayDesc*)(item->param1))->array[(int)item->param2];
  917.                         if (ei)
  918.                             result = CopyItem(ei);
  919.                         else
  920.                             result = AllocItem();
  921.                     }
  922.                     break;
  923.                 case ITV_STACK:
  924.                     {  
  925.                         // pop from plugin stack
  926.                         result = stack;
  927.                         if (result == NULL) result = AllocItem();
  928.                         stack = result->next;
  929.                         result->next = NULL;
  930.                     }
  931.                     break;
  932.                 case ITV_NSTACK:
  933.                     {
  934.                         // NSIS stack
  935.                         char buffer[1024], *buf = buffer;
  936.                         result = AllocItem();
  937.                         popstring(buffer);
  938.                         StringToItem(buf, result, options);
  939.                     }
  940.                     break;
  941.                 }
  942.             }
  943.             else
  944.                 // if we don't need const - we will just pass variable record
  945.                 result = CopyItem(item);
  946.             break;
  947.         case IT_OPERATOR:
  948.             {
  949.                 ExpressionItem *var = NULL, *item1 = NULL, *item2 = NULL;
  950.                 // prepare arguments in case of SET operator
  951.                 if (ioptions & PO_SET)
  952.                 {
  953.                     if ((item->param1) && (ioptions & PO_PRENONCONST))
  954.                     {
  955.                         RunTree(*((ExpressionItem**)&(item->param1)), var, 0);
  956.                         if (ioptions & PO_USESPRE)
  957.                             RunTree(var, item1, RTO_NEEDCONST | STI_INT | STI_FLOAT | STI_STRING);
  958.                     } else
  959.                     if ((item->param2) && (ioptions & PO_POSTNONCONST))
  960.                     {
  961.                         RunTree(*((ExpressionItem**)&(item->param2)), var, 0);
  962.                         if (ioptions & PO_USESPOST)
  963.                             RunTree(var, item2, RTO_NEEDCONST | STI_INT | STI_FLOAT | STI_STRING);
  964.                     }
  965.                 }
  966.  
  967.                 // prepare arguments in case of any operator
  968.                 int needmore = 1;
  969.                 if ((!item1) && (item->param1) && (ioptions & PO_USESPRE))
  970.                 {
  971.                     RunTree(*((ExpressionItem**)&(item->param1)), item1, RTO_NEEDCONST | STI_INT | STI_FLOAT | STI_STRING);
  972.                     // logical expressions && and || can make decision on first arg basis
  973.                     if ((subtype == ITO_LAND) || (subtype == ITO_LOR) )
  974.                     {
  975.                         ItemToType(item1, ITC_INT);
  976.                         int res = (int) *((__int64*) &(item1->param1));
  977.                         if (((res)&&(subtype==ITO_LOR)) || ((!res)&&(subtype==ITO_LAND)))
  978.                             needmore = 0;
  979.                     }
  980.                 }
  981.  
  982.                 // get-reference operator
  983.                 if ((!item1) && (subtype == ITO_AND) && (!item2) && (item->param2))
  984.                 {
  985.                     RunTree(*((ExpressionItem**)&(item->param2)), result, 0);
  986.                     break;
  987.                 }
  988.  
  989.                 if ((needmore) && (!item2) && (item->param2) && (ioptions & PO_USESPOST))
  990.                     RunTree(*((ExpressionItem**)&(item->param2)), item2, RTO_NEEDCONST | STI_INT | STI_FLOAT | STI_STRING);
  991.  
  992.                 // reference operator
  993.                 if ((!item1) && (subtype == ITO_MUL) && ((item2->type & ITEMTYPE) == (IT_VARIABLE)))
  994.                 {
  995.                     // ok, that's the result we need                    
  996.                     if (options & RTO_NEEDCONST)
  997.                     {
  998.                         RunTree(item2, result, options);
  999.                         CleanupItems(item2);
  1000.                     } else
  1001.                         result = item2;                        
  1002.                     break;
  1003.                 }                
  1004.  
  1005.                 __int64 i1, i2, i3, i4;
  1006.                 if (((!item1)||((item1->type & ITEMTYPE)==IT_CONST)) &&
  1007.                     ((!item2)||((item2->type & ITEMTYPE)==IT_CONST)))
  1008.                 {
  1009.  
  1010.                 // find the best type match for operation
  1011.                 int it1 = (item1 && (ioptions & PO_USESPRE))?(item1->type & ITEMSUBTYPE):(ITC_UNKNOWN),
  1012.                     it2 = (item2 && (ioptions & PO_USESPOST))?(item2->type & ITEMSUBTYPE):(ITC_UNKNOWN),
  1013.                     type = (it1 < it2)?(it1):(it2);
  1014.  
  1015.                 // convert operands to desired type
  1016.                 ItemToType(item1, type);
  1017.                 ItemToType(item2, type);
  1018.                 
  1019.                 switch (type)
  1020.                 {
  1021.                 case ITC_INT:
  1022.                     {
  1023.                         i1 = (item1)?(*((__int64*)&item1->param1)):(0);
  1024.                         i2 = (item2)?(*((__int64*)&item2->param1)):(0);
  1025.               
  1026.                     switch (subtype)
  1027.                     {
  1028.                     case ITO_MINUS: i1 -= i2; break;    // unary minus auto handled with NULL
  1029.                     case ITO_PLUS:  i1 += i2; break;
  1030.                     case ITO_SHL:   i1 <<= i2; break;
  1031.                     case ITO_SHR:   i1 >>= i2; break;
  1032.                     case ITO_MUL:   i1 *= i2; break;
  1033.                     case ITO_MOD:
  1034.                     case ITO_DIV:   
  1035.                                     if (i2 == 0) { i3 = 0; i4 = i1;  }
  1036.                                     else { i3 = i1 / i2; i4 = i1 % i2; }
  1037.                                     if (subtype == ITO_DIV) i1 = i3; else i1 = i4;
  1038.                                     break;
  1039.                     case ITO_SET:   i1 = i2; break;
  1040.                     case ITO_LE:    i1 = (i1 <= i2); break;
  1041.                     case ITO_GE:    i1 = (i1 >= i2); break;
  1042.                     case ITO_NE:    i1 = (i1 != i2); break;
  1043.                     case ITO_EQ:    i1 = (i1 == i2); break;
  1044.                     case ITO_LS:    i1 = (i1 < i2); break;
  1045.                     case ITO_GR:    i1 = (i1 > i2); break;
  1046.                     case ITO_AND:   i1 = (i1 & i2); break;
  1047.                     case ITO_OR:    i1 = (i1 | i2); break;
  1048.                     case ITO_XOR:   i1 = (i1 ^ i2); break;
  1049.                     case ITO_NOT:   i1 = ~i2; break;
  1050.                     case ITO_LNOT:  i1 = !i2; break;
  1051.                     case ITO_LAND:  i1 = i1 && i2; break;
  1052.                     case ITO_LOR:   i1 = i1 || i2; break;
  1053.                     case ITO_INC:
  1054.                             if (item1) i2 = i1++;
  1055.                             else i1 = ++i2;
  1056.                             break;
  1057.                     case ITO_DEC:
  1058.                             if (item1) i2 = i1--;
  1059.                             else i1 = --i2;
  1060.                             break;
  1061.                     }
  1062.                     result = AllocItem();
  1063.                     *((__int64*)&result->param1) = i1;
  1064.                     }
  1065.                     break;
  1066.                 case ITC_FLOAT:
  1067.                     {
  1068.                         int ir = -666;
  1069.                         double i1 = (item1)?(*((double*)&item1->param1)):(0.0);
  1070.                         double i2 = (item2)?(*((double*)&item2->param1)):(0.0);
  1071.                     
  1072.                     switch (subtype)
  1073.                     {
  1074.                     case ITO_MINUS: i1 -= i2; break;    // unary minus auto handled with NULL
  1075.                     case ITO_PLUS:  i1 += i2; break;
  1076.                     case ITO_MUL:   i1 *= i2; break;
  1077.                     case ITO_DIV:   i1 /= i2; break;
  1078.                     case ITO_SET:   i1 = i2; break;
  1079.                     case ITO_LE:    ir = (i1 <= i2); break;
  1080.                     case ITO_GE:    ir = (i1 >= i2); break;
  1081.                     case ITO_NE:    ir = (i1 != i2); break;
  1082.                     case ITO_EQ:    ir = (i1 == i2); break;
  1083.                     case ITO_LS:    ir = (i1 < i2); break;
  1084.                     case ITO_GR:    ir = (i1 > i2); break;
  1085.                     }
  1086.                     result = AllocItem();
  1087.                     if (ir == -666)
  1088.                     {
  1089.                         // if ir value left intact - result is double
  1090.                         result->type = IT_CONST | ITC_FLOAT;
  1091.                         *((double*)&result->param1) = i1;            
  1092.                     } else
  1093.                         *((__int64*)&result->param1) = (__int64) ir;            
  1094.                     }
  1095.                     break;
  1096.                 case ITC_STRING:
  1097.                     {
  1098.                         int ir = -666;
  1099.                         char *i1 = (item1)?((char*)item1->param1):(NULL);
  1100.                         char *i2 = (item2)?((char*)item2->param1):(NULL);
  1101.                         int sc = lstrcmp(i1, i2);
  1102.                     
  1103.                     switch (subtype)
  1104.                     {
  1105.                     case ITO_PLUS:  lstrcat(i1, i2); break;
  1106.                     case ITO_SET:   i1 = i2; break;
  1107.                     case ITO_LE:    ir = (sc <= 0); break;
  1108.                     case ITO_GE:    ir = (sc >= 0); break;
  1109.                     case ITO_NE:    ir = (sc != 0); break;
  1110.                     case ITO_EQ:    ir = (sc == 0); break;
  1111.                     case ITO_LS:    ir = (sc < 0); break;
  1112.                     case ITO_GR:    ir = (sc > 0); break;
  1113.                     }                    
  1114.                     if (ir == -666)
  1115.                     {
  1116.                         result = CopyItem((item1)?(item1):(item2));
  1117.                     } else
  1118.                     {
  1119.                         result = AllocItem();
  1120.                         *((__int64*)&result->param1) = (__int64) ir;            
  1121.                     }
  1122.                     }
  1123.                     break;
  1124.                 case ITC_ARRAY:
  1125.                     result = CopyItem(item2);
  1126.                     break;
  1127.                 }
  1128.  
  1129.                 } // check for both items constant
  1130.                 // the other case - usually UniaryPre operators working with non constants
  1131.                 else result = CopyItem(item2);
  1132.  
  1133.                 if (ioptions & PO_SET)
  1134.                 {
  1135.                     // Save our result in output variable
  1136.                     SaveResult(var, result);
  1137.                 }
  1138.  
  1139.                 // Actual value to be returned as result is at i2 for ++ and -- ops
  1140.                 if ((subtype == ITO_DEC) || (subtype == ITO_INC))
  1141.                     *((__int64*)&result->param1) = i2;
  1142.  
  1143.                 CleanupItems(item1); CleanupItems(item2); CleanupItems(var);
  1144.             }
  1145.             break;
  1146.         case IT_LOGIC:
  1147.             {
  1148.                 int ifmode = (subtype == ITL_IF);
  1149.                 ExpressionItem *ifbr = *((ExpressionItem**)&(item->param1)),
  1150.                     *dobr = *((ExpressionItem**)&(item->param2)),
  1151.                     *thbr = NULL, *elbr = NULL;
  1152.                 // check do branche for existance
  1153.                 if (dobr && ifmode)
  1154.                 {
  1155.                     // then...
  1156.                     thbr = *((ExpressionItem**)&(dobr->param1));
  1157.                     // ... and else branches
  1158.                     if (dobr->next) elbr = *((ExpressionItem**)&(dobr->next->param1));
  1159.                 }
  1160.                 while (true)
  1161.                 {
  1162.                     RunAndGetConst((int) ifbr, result, ITC_INT);
  1163.                     if (ifmode)
  1164.                     {
  1165.                         // we need then or else branch?
  1166.                         if ((*((__int64*)&result->param1))) dobr = thbr;
  1167.                         else dobr = elbr;
  1168.                     } else
  1169.                     {
  1170.                         // while mode
  1171.                         if (!(*((__int64*)&result->param1))) break;
  1172.                     }
  1173.                     // ok, run the approtiate branch of if statement (if available)
  1174.                     if (dobr)
  1175.                     {                    
  1176.                         CleanupItems(result);
  1177.                         RunTree(dobr, result, options);
  1178.                     }
  1179.                     if (ifmode) break;
  1180.                     CleanupItems(result);
  1181.                 }
  1182.             }
  1183.             break;
  1184.         case IT_FUNCTION:
  1185.             if (subtype == ITF_USER)
  1186.             {
  1187.                 UserFunc *f = &(UserFuncs[ioptions]);
  1188.                 int flags = f->varflags;
  1189.                 ExpressionItem *ip = *((ExpressionItem**)&(item->param1));
  1190.                 ExpressionItem *si = AllocItem(), *var = AllocItem();
  1191.                 ExpressionItem *vals[32];
  1192.                 si->type = IT_VARIABLE | ITV_STACK; 
  1193.                 for (int i = 0; i < f->varsnum; i++)
  1194.                 {
  1195.                     // push every variable
  1196.                     ExpressionItem *val;
  1197.                     var->type = (IT_VARIABLE | ITV_USER) + f->vars[i];
  1198.                     RunTree(var, val, RTO_NEEDCONST | ITC_STRING | ITC_INT | ITC_FLOAT | ITC_ARRAY);                    
  1199.                     SaveResult(si, val);
  1200.                     CleanupItems(val);
  1201.                     // calculate argument value and for future
  1202.                     if (ip)
  1203.                     {
  1204.                         if (flags&1)
  1205.                         {
  1206.                             // var ptr required
  1207.                             RunTree(*((ExpressionItem**)&(ip->param1)), vals[i], 0);
  1208.                         } else
  1209.                         {
  1210.                             RunTree(*((ExpressionItem**)&(ip->param1)), vals[i], RTO_NEEDCONST | ITC_STRING | ITC_INT | ITC_FLOAT | ITC_ARRAY);
  1211.                         }
  1212.                         ip = ip->next;
  1213.                     } else vals[i] = AllocItem();
  1214.  
  1215.                     flags >>= 1; 
  1216.                 }
  1217.  
  1218.                 // now when all values got we could save them to variables
  1219.                 for (int i = 0; i < f->varsnum; i++)
  1220.                 {
  1221.                         var->type = (IT_VARIABLE | ITV_USER) + f->vars[i];
  1222.                         SaveResult(var, vals[i]);
  1223.                         CleanupItems(vals[i]);
  1224.                 }
  1225.  
  1226.  
  1227.                 // ok, call the func
  1228.                 RunTree(f->root, result, RTO_NEEDCONST | ITC_STRING | ITC_INT | ITC_FLOAT | ITC_ARRAY);
  1229.  
  1230.                 // pop original params
  1231.                 for (int i = f->varsnum-1; i >= 0; i--)
  1232.                 {
  1233.                     // pop every variable
  1234.                     ExpressionItem *val;
  1235.                     var->type = (IT_VARIABLE | ITV_USER) + f->vars[i];
  1236.                     RunTree(si, val, RTO_NEEDCONST | ITC_STRING | ITC_INT | ITC_FLOAT | ITC_ARRAY);                    
  1237.                     SaveResult(var, val);
  1238.                     CleanupItems(val);
  1239.                 }
  1240.  
  1241.                 // free used items
  1242.                 CleanupItems(si); CleanupItems(var); 
  1243.             } else if (subtype == ITF_TYPE)
  1244.             {
  1245.                 int newtype = (int) MathFunctions[ioptions].fptr;
  1246.                 if (newtype < ITC_UNKNOWN)
  1247.                 {
  1248.                     // get as possibly close to ready expression                                        
  1249.                     RunAndGetConst((int)item->param1, result, newtype);
  1250.                     if (ioptions == ITFT_CARRAY_ID) 
  1251.                         CopyArray(result);
  1252.                 } else if (newtype == FTT_FLOATF)
  1253.                 {
  1254.                     // float format function
  1255.                     ExpressionItem *arg1, *arg2;
  1256.                     RunAndGetConst((int)item->param1, arg1, ITC_FLOAT);
  1257.                     double value = *((double*)&(arg1->param1));                
  1258.                     RunAndGetConst((int)item->param2, arg2, ITC_INT);
  1259.                     int format = (int) *((__int64*)&(arg2->param1));
  1260.                     
  1261.                     result = AllocItem();
  1262.                     result->type = IT_CONST | ITC_STRING;
  1263.                     result->param1 = (EIPARAM)  AllocString();
  1264.                     FloatFormat((char*) result->param1, value, format);
  1265.                     CleanupItems(arg1); CleanupItems(arg2);
  1266.                 } else if (newtype == FTT_LEN)
  1267.                 {
  1268.                     // length function
  1269.                     RunTree(*((ExpressionItem **) &(item->param1)), result, RTO_NEEDCONST | ITC_STRING | ITC_ARRAY);
  1270.                     if ((result->type & (ITEMTYPE|ITEMSUBTYPE)) == (IT_CONST|ITC_ARRAY))
  1271.                     {
  1272.                         int len = ((ArrayDesc*)(result->param1))->count;
  1273.                         CleanupItems(result);
  1274.                         result = AllocItem();
  1275.                         *((__int64*)&(result->param1)) = (__int64) len;
  1276.                         break;
  1277.                     } else
  1278.                         if ((result->type & (ITEMTYPE|ITEMSUBTYPE)) != (IT_CONST|ITC_STRING))
  1279.                             ItemToType(result, ITC_STRING);
  1280.  
  1281.                     if ((result->type & (ITEMTYPE|ITEMSUBTYPE)) == (IT_CONST|ITC_STRING))
  1282.                     {
  1283.                         // ok, that's string
  1284.                         int len = lstrlen((char*)result->param1);
  1285.                         dbgGlobalFree((HGLOBAL) result->param1);
  1286.                         *((__int64*)&(result->param1)) = (__int64) len;
  1287.                         result->type = IT_CONST | ITC_INT;
  1288.                     } else CleanupItems(result);
  1289.                 } else
  1290.                 {
  1291.                     // only one left - c() - char/int/char conversion
  1292.                     RunTree(*((ExpressionItem **) &(item->param1)), result, RTO_NEEDCONST | ITC_STRING | ITC_INT);
  1293.                     if ((result->type & (ITEMTYPE|ITEMSUBTYPE)) == (IT_CONST|ITC_STRING))
  1294.                     {
  1295.                         // ok, that's string - convert first char to int
  1296.                         int chr = (*((char*)result->param1)) & 0xFF;
  1297.                         dbgGlobalFree((HGLOBAL) result->param1);
  1298.                         *((__int64*)&(result->param1)) = (__int64) chr;
  1299.                         result->type = IT_CONST | ITC_INT;
  1300.                         break;
  1301.                     } 
  1302.                     if ((result->type & (ITEMTYPE|ITEMSUBTYPE)) == (IT_CONST|ITC_INT))
  1303.                     {
  1304.                         // ok, that's int - convert to new string (char+0)
  1305.                         int chr = (int) (*((__int64*)&(result->param1))) & 0xFF;
  1306.                         result->param1 = (EIPARAM)  AllocString();
  1307.                         *((char*)result->param1) = (char) chr;
  1308.                         *((char*)(result->param1+1)) = (char) 0;
  1309.                         result->type = IT_CONST | ITC_STRING;
  1310.                         break;
  1311.                     } else CleanupItems(result);
  1312.                 }
  1313.             } else
  1314.             {
  1315.                 // oops :-o function call :)
  1316.                 RunAndGetConst((int)item->param1, result, ITC_FLOAT);
  1317.                 double &value = *((double*)&(result->param1));
  1318.                 if (subtype == ITF_MATH1)
  1319.                 {
  1320.                     // Built-In math function with 1 arg
  1321.                     value = MathFunctions[ioptions].fptr(value);
  1322.                 } else
  1323.                 if (subtype == ITF_MATH2)
  1324.                 {
  1325.                     // Built-In math function with 2 args
  1326.                     if (ioptions >= MATHFUNCNUM-2)  
  1327.                     {
  1328.                         // specific function - we need second arg as out
  1329.                         ExpressionItem *arg2, *res2 = AllocItem();
  1330.                         RunTree(*((ExpressionItem**)&(item->param2)), arg2, 0);
  1331.                         if (ioptions == MATHFUNCNUM-1)
  1332.                         {
  1333.                             // fmodf function - second arg is ptr to double
  1334.                             res2->type = IT_CONST | ITC_FLOAT;
  1335.                             double &v = *((double*)&(res2->param1));
  1336.                             value = ((Math2dFuncPtr)(MathFunctions[ioptions].fptr))(value, &v);
  1337.                         } else
  1338.                         {
  1339.                             // frexp function - second arg is ptr to int
  1340.                             int v = 0;
  1341.                             value = ((Math2iFuncPtr)(MathFunctions[ioptions].fptr))(value, &v);
  1342.                             *((__int64 *)&(res2->param1)) = (__int64) v;
  1343.                         }
  1344.                         SaveResult(arg2, res2);
  1345.                         CleanupItems(arg2); CleanupItems(res2);
  1346.                     } else
  1347.                     {
  1348.                         // normal 2-arg math function
  1349.                         ExpressionItem *arg2;
  1350.                         RunAndGetConst((int)item->param2, arg2, ITC_FLOAT);
  1351.                         double value2 = *((double*)&(arg2->param1));
  1352.                         value = ((Math2FuncPtr)(MathFunctions[ioptions].fptr))(value, value2);
  1353.                         CleanupItems(arg2);
  1354.                     }
  1355.                 } 
  1356.             }
  1357.             break;
  1358.         case IT_ARRAY:
  1359.             {
  1360.                 // currently only array access is used
  1361.                 ExpressionItem *index, *aritem;
  1362.                 RunTree(*((ExpressionItem **) &(item->param1)), aritem, RTO_NEEDCONST | ITC_STRING | ITC_ARRAY);
  1363.  
  1364.                 if ((aritem->type & (ITEMTYPE|ITEMSUBTYPE)) == (IT_CONST | ITC_STRING))
  1365.                 {
  1366.                     // argument is string
  1367.                     char *str = (char*)(aritem->param1);
  1368.                     int len = lstrlen(str);
  1369.                     // have we two indexes or one?
  1370.                     if ((*((ExpressionItem **) &(item->param2)))->type != IT_EXPRESSION)
  1371.                     {
  1372.                         // one index - user need a char
  1373.                         RunAndGetConst((int)item->param2, index, ITC_INT);
  1374.                         
  1375.                         int pos = (int) *((__int64*)&(index->param1));
  1376.                         if (pos < 0) pos += len; // -index - means from end
  1377.                         if ((pos > len) || (pos < 0))
  1378.                             *str = 0; // index is accross string boundaries
  1379.                         else
  1380.                         {
  1381.                             // new string - just a single char
  1382.                             *str = *(str+pos);
  1383.                             *(str+1) = 0;
  1384.                         }
  1385.                     } else
  1386.                     {
  1387.                         // two indexes
  1388.                         ExpressionItem *index2;
  1389.                         // if first index is skipped -> 0 (from first char)
  1390.                         if ((*((ExpressionItem **) &(item->param2)))->param1 == 0)
  1391.                             index = AllocItem();
  1392.                         else
  1393.                             RunAndGetConst((int)(*((ExpressionItem **) &(item->param2)))->param1, index, ITC_INT);
  1394.                         if ((*((ExpressionItem **) &(item->param2)))->next->param1 == 0)
  1395.                         {
  1396.                             // if second index is skipped -> -1 (till last char)
  1397.                             index2 = AllocItem();
  1398.                             *((__int64*)&(index2->param1)) = -1;
  1399.                         }
  1400.                         else
  1401.                             RunAndGetConst((int)(*((ExpressionItem **) &(item->param2)))->next->param1, index2, ITC_INT);
  1402.  
  1403.                         // ok, we've got two indexes
  1404.                         int pos1 = (int) *((__int64*)&(index->param1));
  1405.                         int pos2 = (int) *((__int64*)&(index2->param1));
  1406.                         if (pos1 < 0) pos1 += len; // -index - means from end
  1407.                         if (pos2 < 0) pos2 += len; // -index - means from end
  1408.                         // limit start/stop positions
  1409.                         if (pos1 < 0) pos1 = 0;
  1410.                         if (pos2 < 0) pos2 = 0;
  1411.                         if (pos1 > len) pos1 = len;
  1412.                         if (pos2 >= len) pos2 = len-1;
  1413.  
  1414.                         // copy string part
  1415.                         char* lpos = str + (pos2-pos1);
  1416.                         while (str <= lpos) 
  1417.                         {
  1418.                             *str = *(str + pos1);
  1419.                             str++;
  1420.                         }
  1421.                         // null-termiante
  1422.                         *str = 0;
  1423.  
  1424.                         CleanupItems(index2);
  1425.                     }
  1426.                     
  1427.                 } else
  1428.                 {
  1429.                     // argument is array
  1430.                     RunAndGetConst((int)item->param2, index, ITC_INT);
  1431.  
  1432.                     // convert array pointer to array item pointer
  1433.                     aritem->type = IT_VARIABLE | ITV_ARRITEM;
  1434.                     aritem->param2 = (EIPARAM) *((__int64*)&(index->param1));
  1435.  
  1436.                     ArrayDesc *ad = (ArrayDesc*)aritem->param1;
  1437.                     if (((int)aritem->param2) > ad->count) 
  1438.                     {
  1439.                         ad->count = ((int)aritem->param2)+1;
  1440.                         while (ad->count > ad->size)
  1441.                         {
  1442.                             // resize array
  1443.                             ExpressionItem **oldei = ad->array;                        
  1444.                             ad->array = (ExpressionItem**) dbgGlobalAlloc(GPTR, 2*ad->size*sizeof(ExpressionItem*));
  1445.                             for (int i = 0; i < ad->size; i++)
  1446.                                 ad->array[i] = oldei[i];                        
  1447.                             ad->size*=2;
  1448.                             dbgGlobalFree(oldei);
  1449.                         }
  1450.                     }
  1451.                 }
  1452.                                 
  1453.                 CleanupItems(index);
  1454.  
  1455.                 // we need constant result?
  1456.                 if (options & RTO_NEEDCONST)
  1457.                 {
  1458.                     RunTree(aritem, result, options);
  1459.                     CleanupItems(aritem);
  1460.                 } else result = aritem;
  1461.             }
  1462.             break;
  1463.         }
  1464.         item = item->next;
  1465.     }
  1466. }
  1467.  
  1468. extern "C"
  1469. void __declspec(dllexport) Script(HWND hwndParent, int string_size, 
  1470.                                       char *variables, stack_t **stacktop)
  1471. {
  1472.   Math_INIT();
  1473.   char *buffer = AllocString(), *buf = buffer;
  1474.   ExpressionItem *root = NULL; // root of current tree    
  1475.  
  1476.   // pop script string
  1477.   popstring(buffer);
  1478.  
  1479.   // parse it
  1480.   ParseString(buf, root);
  1481.  
  1482. #ifdef _DEBUG
  1483.   // dump
  1484.   PrintTree(root, buffer);
  1485. #endif
  1486.  
  1487.   ExpressionItem *result;
  1488.   RunTree(root, result, 0);
  1489.   CleanupItems(result);
  1490.  
  1491.   CleanupItems(root);
  1492.   dbgGlobalFree((HGLOBAL) buffer);
  1493. }
  1494.  
  1495. double _infinity;
  1496.  
  1497. void CleanAll(int init)
  1498. {
  1499.   if (init)
  1500.   {
  1501.     unsigned char _infinity_base[8] = {0, 0, 0, 0, 0, 0, 0xf0, 0x7f};
  1502.     _fltused = 0;
  1503.     _infinity = *((double*)(_infinity_base));
  1504.     _fpreset();
  1505.  
  1506.     stack = NULL;
  1507.     UserVarsCount = 0;
  1508.     UserFuncsCount = 0;
  1509.   } else
  1510.   {
  1511.     // cleanup stack
  1512.     CleanupItems(stack); stack = NULL;
  1513.     // cleanup user vars
  1514.     for (int i = 0; i < UserVarsCount; i++)
  1515.         CleanupItems(UserVars[i].item);
  1516.     // cleanup user funcs
  1517.     for (int i = 0; i < UserFuncsCount; i++)
  1518.         CleanupItems(UserFuncs[i].root);
  1519.     UserVarsCount = 0;
  1520.     UserFuncsCount = 0;
  1521.  
  1522.     dbgGlobalCheck();
  1523.   }
  1524. }
  1525.  
  1526. BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
  1527. {
  1528.     CleanAll(ul_reason_for_call == DLL_PROCESS_ATTACH);
  1529.     return TRUE;
  1530. }
  1531.  
  1532. #ifdef _DEBUG
  1533. BOOL WINAPI DllMain(
  1534.         HANDLE  hDllHandle,
  1535.         DWORD   dwReason,
  1536.         LPVOID  lpreserved
  1537.         )
  1538. {
  1539.     CleanAll(dwReason == DLL_PROCESS_ATTACH);
  1540.     return TRUE;
  1541. }
  1542. #endif