home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2004 March
/
CMCD0304.ISO
/
Software
/
Freeware
/
Programare
/
nullsoft
/
nsis20.exe
/
Contrib
/
Math
/
Source
/
Math.c
next >
Wrap
C/C++ Source or Header
|
2003-09-22
|
59KB
|
1,542 lines
#include <windows.h>
#include "mathcrt.h"
#include "MyMath.h"
#include "Math.h"
extern "C" int _fltused;
int _fltused;
ExpressionItem *stack;
int UserVarsCount, UserFuncsCount;
UserVar UserVars[MAX_USER_VARS];
UserFunc UserFuncs[MAX_USER_FUNCS];
void PrintTree(ExpressionItem *root, char *str);
void ParseString(char *&sp, ExpressionItem* &itemplace);
void CleanupItems(ExpressionItem* &itemplace);
void PlaceVariable(char *&vb, ParseInfo *pi);
void PlaceNewItem(char *&vb, ParseInfo *pi, int precedence)
{
ExpressionItem *newroot;
PlaceVariable(vb, pi);
if (pi->item == NULL) return;
while ((pi->OpsStack) && ((((int) pi->OpsStack->param2) < precedence)
|| ((((int)pi->OpsStack->param2) == precedence)
&& (precedence != OPERATOR_SET_PRECEDENCE))))
{
// second operand for our operator
newroot = pi->OpsStack;
*((ExpressionItem **)&(newroot->param2)) = pi->item;
pi->OpsStack = newroot->next;
newroot->next = NULL;
pi->item = newroot;
}
// finally we have got new root
newroot = pi->item;
if (pi->SetupNewRoot)
{
(*pi->root)->next = newroot;
pi->root = &((*pi->root)->next);
pi->SetupNewRoot = 0;
}
if (pi->place == *pi->root) pi->place = *pi->root = newroot;
else *pi->root = newroot;
// no item at our pockets
pi->item = NULL;
}
#define NSIS_VARS_COUNT 27
#define NSIS_VARS_STACK 25
#define NSIS_VARS_NSTACK 26
typedef char smallstr[2];
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'},
{'R','0'}, {'R','1'}, {'R','2'}, {'R','3'}, {'R','4'}, {'R','5'}, {'R','6'}, {'R','7'}, {'R','8'}, {'R','9'},
{'C','L'}, {'I','D'}, {'O','D'}, {'E','D'}, {'L','G'}, {'S',0}, {'N','S'}};
ExpressionItem *FindVariable(char *varname)
{
ExpressionItem *item = AllocItem();
// check NSIS variables
for (int i = 0; i < NSIS_VARS_COUNT; i++)
{
if (lstrcmpn(varname, NSISVariablesNames[i],2) == 0)
{
if (i == NSIS_VARS_STACK) item->type = IT_VARIABLE | ITV_STACK;
else if (i == NSIS_VARS_NSTACK) item->type = IT_VARIABLE | ITV_NSTACK;
else
item->type = (IT_VARIABLE | ITV_NSIS) + i;
return item;
}
}
// no.. that's user variable
for (int i = 0; i < UserVarsCount; i++)
{
if (lstrcmp(varname, UserVars[i].name) == 0)
{
// ok. we found user var expression needed
break;
}
}
if (i == UserVarsCount)
{
// new variable
UserVarsCount++;
lstrcpy(UserVars[i].name, varname);
UserVars[i].item = NULL;
}
item->type = (IT_VARIABLE | ITV_USER) + i;
return item;
}
void PlaceVariable(char *&vb, ParseInfo *pi)
{
if (vb <= pi->valbuf) return;
*vb = 0;
pi->item = FindVariable(pi->valbuf);
vb = pi->valbuf;
}
#define MATHFUNCNUM 29
const MathFunction MathFunctions[MATHFUNCNUM] = {
{{'s','i','n'}, ITF_MATH1 >> 8, _fsin},
{{'s','n','h'}, ITF_MATH1 >> 8, _fsinh},
{{'a','s','n'}, ITF_MATH1 >> 8, _fasin},
{{'c','o','s'}, ITF_MATH1 >> 8, _fcos},
{{'c','s','h'}, ITF_MATH1 >> 8, _fcosh},
{{'a','c','s'}, ITF_MATH1 >> 8, _facos},
{{'t','a','n'}, ITF_MATH1 >> 8, _ftan},
{{'t','n','h'}, ITF_MATH1 >> 8, _ftanh},
{{'a','t','n'}, ITF_MATH1 >> 8, _fatan},
{{'a','b','s'}, ITF_MATH1 >> 8, _fabs},
{{'l','n',0}, ITF_MATH1 >> 8, _flog},
{{'l','o','g'}, ITF_MATH1 >> 8, _flog10},
{{'e','x','p'}, ITF_MATH1 >> 8, _fexp},
{{'s','q','t'}, ITF_MATH1 >> 8, _fsqrt},
{{'c','e','l'}, ITF_MATH1 >> 8, _fceil},
{{'f','l','r'}, ITF_MATH1 >> 8, _floor},
{{'a','t','2'}, ITF_MATH2 >> 8, (Math1FuncPtr)_fatan2},
{{'p','o','w'}, ITF_MATH2 >> 8, (Math1FuncPtr)_fpow},
{{'f','m','d'}, ITF_MATH2 >> 8, (Math1FuncPtr)_fmod},
// type conversions
{{'i',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)ITC_INT},
{{'s',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)ITC_STRING},
{{'f',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)ITC_FLOAT},
{{'a',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)ITC_ARRAY},
#define ITFT_CARRAY_ID 23
{{'c','a',0}, ITF_TYPE >> 8, (Math1FuncPtr)ITC_ARRAY},
{{'f','f',0}, ITF_TYPE >> 8, (Math1FuncPtr)FTT_FLOATF},
{{'l',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)FTT_LEN},
{{'c',0,0}, ITF_TYPE >> 8, (Math1FuncPtr)FTT_CHAR},
{{'f','e','x'}, ITF_MATH2 >> 8, (Math1FuncPtr)_frexp},
{{'m','d','f'}, ITF_MATH2 >> 8, (Math1FuncPtr)_fmodf},
};
void PlaceFunction(char *&vb, char *&sp, ParseInfo *pi, int redefine)
{
ExpressionItem *item = pi->item = AllocItem();
*vb = 0;
// check BUILTIN functions
for (int i = 0; i < MATHFUNCNUM; i++)
{
if (lstrcmpn(pi->valbuf, MathFunctions[i].name, 3) == 0)
{
item->type = IT_FUNCTION | (MathFunctions[i].type << 8) | i;
// get first argument
sp++;
ParseString(sp, *((ExpressionItem **)(&item->param1)));
if (*sp == ',')
{
// get second argument
sp++;
ParseString(sp, *((ExpressionItem **)(&item->param2)));
}
sp++; vb = pi->valbuf;
return;
}
}
// heh, may be it user function
for (int i = 0; i < UserFuncsCount; i++)
{
if (lstrcmp(pi->valbuf, UserFuncs[i].name) == 0)
{
// Function found? Redefine option specified?
if (redefine) break;
item->type = IT_FUNCTION | ITF_USER | i;
// get arguments list
ExpressionItem **newplace = ((ExpressionItem **)(&pi->item->param1));
while (*sp != ')')
{
*newplace = AllocItem();
(*newplace)->type = IT_EXPRESSION;
sp++;
ParseString(sp, *((ExpressionItem **)(&(*newplace)->param1)));
newplace = &((*newplace)->next);
}
sp++; vb = pi->valbuf;
return;
}
}
// oops, we need no item for function defenition
CleanupItems(item); pi->item = NULL;
// it's user function define
int flags = 0;
char buffer[128], *buf = buffer;
// workaround for redefine flag - if the function already present,
// it will be cleared and redefined
UserFunc *f = &UserFuncs[i];
if (i == UserFuncsCount) UserFuncsCount++;
else CleanupItems(f->root);
lstrcpy(f->name, pi->valbuf);
f->varflags = 0;
f->varsnum = 0;
do
{
sp++;
switch (*sp)
{
case ' ':
break;
case ',':
case ')':
if (buf > buffer)
{
*buf = 0;
// it should be user variable
ExpressionItem *it = FindVariable(buffer);
f->vars[f->varsnum++] = (it->type) & ITEMOPTIONS;
CleanupItems(it);
buf = buffer;
flags <<= 1;
}
break;
case '&':
flags |= 1;
break;
default:
*(buf++) = *sp;
break;
}
}
while (*sp != ')');
// prepare flag for fast analisys
for (int i = 0; i < f->varsnum; i++)
{
f->varflags <<= 1;
flags >>= 1;
f->varflags |= flags&1;
}
// find nearest round bracket - function body
while (*sp != '(') sp++;
sp++;
// now we are ready to parse function body
ParseString(sp, f->root);
sp++; // closing bracket
vb = pi->valbuf;
#ifdef _DEBUG
// dump function (in debug mode)
char place[1024];
wsprintf(place, "function %s(", f->name);
flags = f->varflags;
for (int i = 0; i < f->varsnum; i++)
{
if (flags&1) lstrcat(place, "&");
lstrcat(place, UserVars[f->vars[i]].name);
if (i < f->varsnum-1) lstrcat(place, ", ");
flags >>= 1;
}
lstrcat(place, ")");
PrintTree(f->root, place);
#endif
}
// operator options
#define PO_UNARYPRE 0x1 // this operator can be uniary pre (--a) for ex
#define PO_UNARYPOST 0x2 // this op can be uniary post (a++) (couldn't be binary)
#define PO_PRENONCONST 0x4 // pre argument (a = b) -> a is non const
#define PO_POSTNONCONST 0x8 // post argument (b--) is non const
#define PO_LASTOP 0x10 // op should be the last item at expression (=, -=, etc)
#define PO_SET 0x20 // op will set new value to one of args
#define PO_USESPRE 0x40 // operator will use pre operand
#define PO_USESPOST 0x80 // operator will use post operan
void PlaceOp(char *&vb, int type, int precedence, ParseInfo *pi)
{
PlaceVariable(vb, pi);
if ((type & PO_UNARYPRE) && (!pi->item))
{
// uniary pre op
ExpressionItem *item = AllocItem();
item->type = type;
item->param2 = (EIPARAM) precedence;
item->next = pi->OpsStack;
pi->OpsStack = item;
}
else
{
// get previous tree as items and operators of lower precedence
PlaceNewItem(vb, pi, precedence);
// post operators
ExpressionItem *item = AllocItem();
item->type = type;
item->param1 = (EIPARAM) (*pi->root);
if (pi->place == *pi->root) pi->place = *pi->root = NULL;
else *pi->root = NULL;
if (type & PO_UNARYPOST)
{
// uniary post op
pi->item = item;
} else
{
// binary operator
item->param2 = (EIPARAM) precedence;
item->next = pi->OpsStack;
pi->OpsStack = item;
}
}
}
#define OPSNUM 35
const OpStruct Operators[OPSNUM] =
{
// three byte ops
{{'>','>','='}, 14, ITO_SHR | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{{'<','<','='}, 14, ITO_SHL | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
// two byte ops
// !!! don't forget to change Set Operator Precedence !!!
{"-=", 14, ITO_MINUS | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"+=", 14, ITO_PLUS | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"/=", 14, ITO_DIV | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"*=", 14, ITO_MUL | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"|=", 14, ITO_OR | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"&=", 14, ITO_AND | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"^=", 14, ITO_XOR | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"%=", 14, ITO_MOD | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPRE | PO_USESPOST},
{"--", 2, ITO_DEC | PO_POSTNONCONST | PO_PRENONCONST | PO_UNARYPRE | PO_UNARYPOST | PO_SET | PO_USESPRE | PO_USESPOST},
{"++", 2, ITO_INC | PO_POSTNONCONST | PO_PRENONCONST | PO_UNARYPRE | PO_UNARYPOST | PO_SET | PO_USESPRE | PO_USESPOST},
{">>", 6, ITO_SHR | PO_USESPRE | PO_USESPOST},
{"<<", 6, ITO_SHL | PO_USESPRE | PO_USESPOST},
// logical
{"&&", 12, ITO_LAND | PO_USESPRE | PO_USESPOST},
{"||", 13, ITO_LOR | PO_USESPRE | PO_USESPOST},
// comparisons
{"<=", 7, ITO_LE | PO_USESPRE | PO_USESPOST},
{"=<", 7, ITO_LE | PO_USESPRE | PO_USESPOST},
{">=", 7, ITO_GE | PO_USESPRE | PO_USESPOST},
{"=>", 7, ITO_GE | PO_USESPRE | PO_USESPOST},
{"!=", 8, ITO_NE | PO_USESPRE | PO_USESPOST},
{"==", 8, ITO_EQ | PO_USESPRE | PO_USESPOST},
// single byte ops
// !!! don't forget to change Set Operator Precedence !!!
{"=", 14, ITO_SET | PO_PRENONCONST | PO_LASTOP | PO_SET | PO_USESPOST},
{"+", 5, ITO_PLUS | PO_USESPRE | PO_USESPOST},
{"-", 5, ITO_MINUS | PO_USESPRE | PO_USESPOST | PO_UNARYPRE},
{"*", 4, ITO_MUL | PO_USESPRE | PO_USESPOST | PO_UNARYPRE},
{"/", 4, ITO_DIV | PO_USESPRE | PO_USESPOST},
{"%", 4, ITO_MOD | PO_USESPRE | PO_USESPOST},
{"<", 7, ITO_LS | PO_USESPRE | PO_USESPOST},
{">", 7, ITO_GR | PO_USESPRE | PO_USESPOST},
{"&", 9, ITO_AND | PO_USESPRE | PO_USESPOST | PO_UNARYPRE},
{"|", 11, ITO_OR | PO_USESPRE | PO_USESPOST},
{"^", 10, ITO_XOR | PO_USESPRE | PO_USESPOST},
{"~", 3, ITO_NOT | PO_USESPOST | PO_UNARYPRE},
{"!", 3, ITO_LNOT |PO_USESPOST | PO_UNARYPRE}
};
void CheckForOperator(char *&sp, char *&vb, ParseInfo *pi)
{
for (int op = 0; op < OPSNUM; op++)
{
int c = lstrlen(Operators[op].name);
if (c > 3) c = 3; // real operator length
if (lstrcmpn(sp, Operators[op].name, c))
{
// wrong - different op
continue;
}
// that is our op
sp += c;
PlaceOp(vb, ((int) Operators[op].type) | IT_OPERATOR, Operators[op].precedence, pi);
break;
}
}
void ParseString(char *&sp, ExpressionItem* &itemplace)
{
ParseInfo pi = {0, NULL, NULL, itemplace, &itemplace};
int redefine = 0;
char *vb = pi.valbuf;
// cycle until current expression end
while ((*sp != 0) && (*sp != ')') && (*sp != '}') &&
(*sp != ']') && (*sp != ','))
{
int processed = 1;
switch (*sp)
{
case ' ':
case '\t':
sp++;
break;
case ';':
// expression delimeter
PlaceNewItem(vb, &pi, 255);
if (*pi.root) pi.SetupNewRoot = 1;
sp++;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
// variable & function names could contain numbers as non first chars
if (vb > pi.valbuf)
{
processed = FALSE;
break;
}
case '\'': case '\"': case '`':
// constant meet
pi.item = AllocItem();
StringToItem(sp, pi.item, STI_STRING | STI_FLOAT | STI_INT);
break;
case '(': // start of function or expression
if (vb > pi.valbuf)
{
// thats function
PlaceFunction(vb, sp, &pi, redefine);
} else
{
// expression
sp++;
ParseString(sp, pi.item);
if (*sp == ')') sp++;
}
redefine = 0;
break;
case '#': // start of one of logical expresions
sp++;
if ((*sp != '[') && (*sp != '{'))
{
// function redefine flag
redefine = 1;
break;
}
{
pi.item = AllocItem();
// IF or WHILE
pi.item->type = ((*sp == '[')?(IT_LOGIC | ITL_IF):(IT_LOGIC | ITL_WHILE));
// first expr - logic statement
sp++;
ParseString(sp, *((ExpressionItem **)(&pi.item->param1)));
// ok, second expr - then, third - else statement.. others???
ExpressionItem **newplace = ((ExpressionItem **)(&pi.item->param2));
while (*sp == ',')
{
*newplace = AllocItem();
(*newplace)->type = IT_EXPRESSION;
sp++;
ParseString(sp, *((ExpressionItem **)(&(*newplace)->param1)));
newplace = &((*newplace)->next);
}
}
sp++;
break;
case '[':
{
// thats array access
PlaceOp(vb, IT_ARRAY | ITA_ACCESS | PO_UNARYPOST, 1, &pi);
sp++;
// item index
ParseString(sp, *(ExpressionItem **)&(pi.item->param2));
if (*sp == ',')
{
// two indexes - string access
ExpressionItem *it = AllocItem();
it->type = IT_EXPRESSION;
it->param1 = (EIPARAM) *(ExpressionItem **)&(pi.item->param2);
*(ExpressionItem **)&(pi.item->param2) = it;
it = it->next = AllocItem();
it->type = IT_EXPRESSION;
sp++;
ParseString(sp, *((ExpressionItem **)(&it->param1)));
}
sp++;
}
break;
case '{': // start of array define
{
// array define - constists of array copy operator and array define itself
// type conversion item (to create a copy of array)
pi.item = AllocItem();
pi.item->type = IT_FUNCTION | ITF_TYPE | ITFT_CARRAY_ID | ITFA_COPY;
// during first create our array descriptor and array pointers
ExpressionItem *ai = AllocArray(DEFAULT_ARRAY_SIZE);
pi.item->param1 = (EIPARAM) ai;
ArrayDesc *ad = *((ArrayDesc**)&(ai->param1));
// parse array initializers
while (*sp != '}')
{
sp++;
ParseString(sp, ad->array[ad->count++]);
}
sp++;
}
break;
case '-': case '+': case '<': case '=': case '>':
case '/': case '*': case '~': case '^': case '!':
case '&': case '|': case '%':
CheckForOperator(sp, vb, &pi);
break;
// non expression? ok, then it should be common char, like function or var name
default:
processed = FALSE;
break;
}
if (!processed) *(vb++) = *(sp++);
}
PlaceNewItem(vb, &pi, 255);
}
void CleanupArray(ArrayDesc *ad)
{
if (!(--(ad->references)))
{
// last array reference, we could kill it
// cleanup array items
for (int i = 0; i < ad->count; i++)
{
ExpressionItem *aritem = ad->array[i];
if (aritem)
CleanupItems(aritem);
}
// cleanup ptrs and descriptor
dbgGlobalFree(ad->array);
dbgGlobalFree(ad);
}
}
void CleanupItems(ExpressionItem* &itemplace)
{
if (itemplace == NULL) return;
ExpressionItem *item = itemplace, *itemnext;
do
{
if (((item->type & (ITEMTYPE|ITEMSUBTYPE)) == (IT_VARIABLE|ITV_ARRITEM))
||
((item->type & (ITEMTYPE|ITEMSUBTYPE)) == (IT_CONST|ITC_ARRAY)))
{
CleanupArray((ArrayDesc *)item->param1);
}
else
if ((item->type & ITEMTYPE) == IT_CONST)
{
if ((item->type & ITEMSUBTYPE) == ITC_STRING)
dbgGlobalFree((HGLOBAL) item->param1);
} else
{
CleanupItems(*((ExpressionItem**) &item->param1));
CleanupItems(*((ExpressionItem**) &item->param2));
}
// free the item itself
itemnext = item->next;
dbgGlobalFree((HGLOBAL) item);
item = itemnext;
} while (item != NULL);
itemplace = NULL;
}
#ifdef _DEBUG
HANDLE myfile;
char *opsnames[] = {"", "-", "+", "<<", ">>", "*", "/", "=", "&&", "||", "++", "--",
"=<", ">=", "!=", "==", "<", ">", "&", "%", "|", "^", "~", "!"};
void PrintNode(int index, int spaces, ExpressionItem* itemplace)
{
if (itemplace == NULL) return;
ExpressionItem *item = itemplace;
do
{
DWORD wrote;
char buffer[1024], *place = buffer;
for (int k = 0; k < spaces; k++)
*(place++) = 32;
*place = 0;
switch (item->type & ITEMTYPE)
{
case IT_EXPRESSION:
wsprintf(place, "Expression Place-Holder ");
break;
case IT_CONST:
switch (item->type & ITEMSUBTYPE)
{
case ITC_STRING:
wsprintf(place, "String: \"%s\"", (char *) item->param1);
break;
case ITC_INT:
wsprintf(place, "Int: ");
itoa64(*((__int64*)&(item->param1)), place+5);
break;
case ITC_FLOAT:
wsprintf(place, "Float: ");
FloatFormat(place+7, *((double*)&(item->param1)), 6);
break;
case ITC_ARRAY:
ArrayDesc *ad = (ArrayDesc*) item->param1;
wsprintf(place, "Array, ptr %08X, size %d, count %d, references %d",
ad->array, ad->size, ad->count, ad->references);
break;
}
strcat(place, " ");
break;
case IT_OPERATOR:
wsprintf(place, "Op: %s%s ", opsnames[(item->type & ITEMSUBTYPE) >> 8], (item->type & PO_SET)?("(=)"):(""));
break;
case IT_VARIABLE:
switch (item->type & ITEMSUBTYPE)
{
case ITV_NSIS:
{
char buffer[128];
buffer[0] = NSISVariablesNames[item->type & ITEMOPTIONS][0];
buffer[1] = NSISVariablesNames[item->type & ITEMOPTIONS][1];
buffer[2] = 0;
wsprintf(place, "Var: %s (%d) ",
buffer,
item->type & ITEMOPTIONS);
}
break;
case ITV_USER:
wsprintf(place, "Var: %s (%d) ", UserVars[item->type & ITEMOPTIONS].name, item->type & ITEMOPTIONS);
break;
case ITV_STACK:
wsprintf(place, "Plugin Stack ");
break;
case ITV_NSTACK:
wsprintf(place, "NSIS Stack ");
break;
}
break;
case IT_LOGIC:
if ((item->type & ITEMSUBTYPE) == ITL_IF)
wsprintf(place, "IF ");
else
wsprintf(place, "WHILE ");
break;
case IT_FUNCTION:
if (((item->type & ITEMSUBTYPE) == ITF_MATH1) ||
((item->type & ITEMSUBTYPE) == ITF_MATH2) ||
((item->type & ITEMSUBTYPE) == ITF_TYPE))
{
char buffer[128];
buffer[0] = (MathFunctions[item->type &ITEMOPTIONS].name)[0];
buffer[1] = (MathFunctions[item->type &ITEMOPTIONS].name)[1];
buffer[2] = (MathFunctions[item->type &ITEMOPTIONS].name)[2];
buffer[3] = 0;
wsprintf(place, "Built-In Function %s() [%d] ",
buffer,
item->type &ITEMOPTIONS);
}
else
{
UserFunc *f = &(UserFuncs[item->type & ITEMOPTIONS]);
wsprintf(place, "User Function: %s(", f->name);
int flags = f->varflags;
for (int i = 0; i < f->varsnum; i++)
{
if (flags&1) lstrcat(place, "&");
lstrcat(place, UserVars[f->vars[i]].name);
if (i < f->varsnum-1) lstrcat(place, ", ");
flags >>= 1;
}
lstrcat(place, ") ");
}
break;
case IT_ARRAY:
wsprintf(place, "Array access [] ");
break;
}
place += lstrlen(place);
wsprintf(place, "Addr: %08X Type: %08X Next: %08X Param1: %08X Param2: %08X", item, item->type, item->next, item->param1, item->param2);
lstrcat(place, "\n");
WriteFile(myfile, buffer, lstrlen(buffer), &wrote, NULL);
if (((item->type & ITEMTYPE) != IT_CONST) && ((item->type & (ITEMTYPE|ITEMSUBTYPE)) != (IT_VARIABLE|ITV_ARRITEM)))
{
place = buffer;
for (int k = 0; k < spaces+2; k++)
*(place++) = 32;
int show = 0;
if (((item->param1 != NULL) && ((*((ExpressionItem**) &item->param1))->next != NULL)) ||
((item->param2 != NULL) && ((*((ExpressionItem**) &item->param2))->next != NULL)))
show = 1;
if (show)
{
wsprintf(place, "Sub1:\n");
WriteFile(myfile, buffer, lstrlen(buffer), &wrote, NULL);
}
PrintNode(1, spaces + 4, *((ExpressionItem**) &item->param1));
if (show)
{
wsprintf(place, "Sub2:\n");
WriteFile(myfile, buffer, lstrlen(buffer), &wrote, NULL);
}
PrintNode(2, spaces + 4, *((ExpressionItem**) &item->param2));
} else if ((item->type & (ITEMSUBTYPE|ITEMTYPE)) == (ITC_ARRAY|IT_CONST))
{
ArrayDesc *ad = (ArrayDesc *) item->param1;
for (int i = 0; i < ad->count; i++)
{
ExpressionItem *aritem = ad->array[i];
if (aritem)
PrintNode(2, spaces + 4, aritem);
}
}
item = item->next;
} while (item != NULL);
}
void PrintTree(ExpressionItem *root, char *str)
{
myfile = CreateFile("d:\\math.debug", GENERIC_ALL, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, 0);
SetFilePointer(myfile, 0, NULL, FILE_END);
char buffer[1024]; DWORD wrote;
wsprintf(buffer, "New tree for \'%s\'\n", str);
WriteFile(myfile, buffer, lstrlen(buffer), &wrote, NULL);
PrintNode(0, 4, root);
CloseHandle(myfile);
myfile = NULL;
}
#endif
void CopyArray(ExpressionItem *&item)
{
if (item == NULL) return;
// especial case - array to array conversion is requested array copy
ExpressionItem *olditem = item;
ArrayDesc *oad = (ArrayDesc *) (olditem->param1);
// Initialize the array of the same size
item = AllocArray(oad->size);
ArrayDesc *nad = (ArrayDesc *) (item->param1);
nad->count = oad->count;
// copy items
for (int i = 0; i < oad->count; i++)
nad->array[i] = CopyItem(oad->array[i], TRUE);
// cleanup old array pointer (may be array itself)
CleanupItems(olditem);
}
void ItemToType(ExpressionItem* &item, int type)
{
char *buffer;
if (item == NULL) return;
int itemt = item->type & ITEMTYPE, oldtype = item->type & ITEMSUBTYPE;
if (((itemt == IT_CONST) && (oldtype == type))
|| (itemt != IT_CONST)) return;
switch (type)
{
case ITC_STRING:
buffer = AllocString();
ItemToString(buffer, item);
item->param1 = (EIPARAM) buffer;
item->param2 = 0;
break;
case ITC_FLOAT:
if (oldtype == ITC_INT)
*((double *)&(item->param1)) = (double) *((__int64 *)&(item->param1));
else
{
buffer = (char*) item->param1;
StringToItem(buffer, item, STI_FLOAT);
dbgGlobalFree(buffer);
}
break;
case ITC_INT:
if (oldtype == ITC_FLOAT)
*((__int64 *)&(item->param1)) = (__int64) *((double *)&(item->param1));
else
{
buffer = (char*) item->param1;
StringToItem(buffer, item, STI_INT);
dbgGlobalFree(buffer);
}
break;
case ITC_ARRAY:
if (oldtype == ITC_STRING)
{
char *buf = (char*) item->param1;
int len = lstrlen(buf)+1;
ExpressionItem *ni = AllocArray(lstrlen(buf)+1);
ArrayDesc *ad = (ArrayDesc*) ni->param1;
for (int i = 0; i < len; i++)
{
ad->array[i] = AllocItem();
*((__int64 *) &(ad->array[i]->param1)) = (__int64) buf[i];
}
ad->count = len;
CleanupItems(item);
item = ni;
}
break;
}
item->type = IT_CONST | type;
}
void SaveResult(ExpressionItem *var, ExpressionItem *result)
{
if ((var->type & ITEMTYPE) != IT_VARIABLE) return;
// result should be stored at variable to
int varindex = var->type & ITEMOPTIONS;
switch (var->type & ITEMSUBTYPE)
{
case ITV_NSIS:
{
// store string result direct to NSIS variable
char *ptr = g_variables + varindex*g_stringsize;
ItemToString(ptr, result);
}
break;
case ITV_USER:
{
CleanupItems(UserVars[varindex].item);
UserVars[varindex].item = CopyItem(result);
}
break;
case ITV_ARRITEM:
{
ExpressionItem *&ei = ((ArrayDesc*)(var->param1))->array[(int)var->param2];
CleanupItems(ei);
ei = CopyItem(result);
}
break;
case ITV_STACK:
{
ExpressionItem *newitem = CopyItem(result);
newitem->next = stack;
stack = newitem;
}
break;
case ITV_NSTACK:
{
char *buf = AllocString();
ItemToString(buf, result);
pushstring(buf);
dbgGlobalFree(buf);
}
break;
}
}
void RunAndGetConst(int from, ExpressionItem* &result, int type)
{
RunTree(*((ExpressionItem**)&(from)), result, type | RTO_NEEDCONST);
ItemToType(result, type);
}
void RunTree(ExpressionItem *from, ExpressionItem* &result, int options)
{
ExpressionItem *item = from;
result = NULL;
while (item != NULL)
{
CleanupItems(result);
int type = item->type & ITEMTYPE,
subtype = item->type & ITEMSUBTYPE,
ioptions = item->type & ITEMOPTIONS;
switch (type)
{
case IT_EXPRESSION:
RunTree(*((ExpressionItem**)&(item->param1)), result, options);
break;
case IT_CONST:
result = CopyItem(item);
break;
case IT_VARIABLE:
if (options & RTO_NEEDCONST)
{
// we need const result - :) is it nsis or common variable
switch (subtype)
{
case ITV_NSIS:
{
// nsis
result = AllocItem();
char *variable = getuservariable(ioptions);
StringToItem(variable, result, options);
}
break;
case ITV_USER:
{
// usual variable
if (UserVars[ioptions].item)
result = CopyItem(UserVars[ioptions].item);
else
result = AllocItem();
}
break;
case ITV_ARRITEM:
{
// array item
ExpressionItem *ei = ((ArrayDesc*)(item->param1))->array[(int)item->param2];
if (ei)
result = CopyItem(ei);
else
result = AllocItem();
}
break;
case ITV_STACK:
{
// pop from plugin stack
result = stack;
if (result == NULL) result = AllocItem();
stack = result->next;
result->next = NULL;
}
break;
case ITV_NSTACK:
{
// NSIS stack
char buffer[1024], *buf = buffer;
result = AllocItem();
popstring(buffer);
StringToItem(buf, result, options);
}
break;
}
}
else
// if we don't need const - we will just pass variable record
result = CopyItem(item);
break;
case IT_OPERATOR:
{
ExpressionItem *var = NULL, *item1 = NULL, *item2 = NULL;
// prepare arguments in case of SET operator
if (ioptions & PO_SET)
{
if ((item->param1) && (ioptions & PO_PRENONCONST))
{
RunTree(*((ExpressionItem**)&(item->param1)), var, 0);
if (ioptions & PO_USESPRE)
RunTree(var, item1, RTO_NEEDCONST | STI_INT | STI_FLOAT | STI_STRING);
} else
if ((item->param2) && (ioptions & PO_POSTNONCONST))
{
RunTree(*((ExpressionItem**)&(item->param2)), var, 0);
if (ioptions & PO_USESPOST)
RunTree(var, item2, RTO_NEEDCONST | STI_INT | STI_FLOAT | STI_STRING);
}
}
// prepare arguments in case of any operator
int needmore = 1;
if ((!item1) && (item->param1) && (ioptions & PO_USESPRE))
{
RunTree(*((ExpressionItem**)&(item->param1)), item1, RTO_NEEDCONST | STI_INT | STI_FLOAT | STI_STRING);
// logical expressions && and || can make decision on first arg basis
if ((subtype == ITO_LAND) || (subtype == ITO_LOR) )
{
ItemToType(item1, ITC_INT);
int res = (int) *((__int64*) &(item1->param1));
if (((res)&&(subtype==ITO_LOR)) || ((!res)&&(subtype==ITO_LAND)))
needmore = 0;
}
}
// get-reference operator
if ((!item1) && (subtype == ITO_AND) && (!item2) && (item->param2))
{
RunTree(*((ExpressionItem**)&(item->param2)), result, 0);
break;
}
if ((needmore) && (!item2) && (item->param2) && (ioptions & PO_USESPOST))
RunTree(*((ExpressionItem**)&(item->param2)), item2, RTO_NEEDCONST | STI_INT | STI_FLOAT | STI_STRING);
// reference operator
if ((!item1) && (subtype == ITO_MUL) && ((item2->type & ITEMTYPE) == (IT_VARIABLE)))
{
// ok, that's the result we need
if (options & RTO_NEEDCONST)
{
RunTree(item2, result, options);
CleanupItems(item2);
} else
result = item2;
break;
}
__int64 i1, i2, i3, i4;
if (((!item1)||((item1->type & ITEMTYPE)==IT_CONST)) &&
((!item2)||((item2->type & ITEMTYPE)==IT_CONST)))
{
// find the best type match for operation
int it1 = (item1 && (ioptions & PO_USESPRE))?(item1->type & ITEMSUBTYPE):(ITC_UNKNOWN),
it2 = (item2 && (ioptions & PO_USESPOST))?(item2->type & ITEMSUBTYPE):(ITC_UNKNOWN),
type = (it1 < it2)?(it1):(it2);
// convert operands to desired type
ItemToType(item1, type);
ItemToType(item2, type);
switch (type)
{
case ITC_INT:
{
i1 = (item1)?(*((__int64*)&item1->param1)):(0);
i2 = (item2)?(*((__int64*)&item2->param1)):(0);
switch (subtype)
{
case ITO_MINUS: i1 -= i2; break; // unary minus auto handled with NULL
case ITO_PLUS: i1 += i2; break;
case ITO_SHL: i1 <<= i2; break;
case ITO_SHR: i1 >>= i2; break;
case ITO_MUL: i1 *= i2; break;
case ITO_MOD:
case ITO_DIV:
if (i2 == 0) { i3 = 0; i4 = i1; }
else { i3 = i1 / i2; i4 = i1 % i2; }
if (subtype == ITO_DIV) i1 = i3; else i1 = i4;
break;
case ITO_SET: i1 = i2; break;
case ITO_LE: i1 = (i1 <= i2); break;
case ITO_GE: i1 = (i1 >= i2); break;
case ITO_NE: i1 = (i1 != i2); break;
case ITO_EQ: i1 = (i1 == i2); break;
case ITO_LS: i1 = (i1 < i2); break;
case ITO_GR: i1 = (i1 > i2); break;
case ITO_AND: i1 = (i1 & i2); break;
case ITO_OR: i1 = (i1 | i2); break;
case ITO_XOR: i1 = (i1 ^ i2); break;
case ITO_NOT: i1 = ~i2; break;
case ITO_LNOT: i1 = !i2; break;
case ITO_LAND: i1 = i1 && i2; break;
case ITO_LOR: i1 = i1 || i2; break;
case ITO_INC:
if (item1) i2 = i1++;
else i1 = ++i2;
break;
case ITO_DEC:
if (item1) i2 = i1--;
else i1 = --i2;
break;
}
result = AllocItem();
*((__int64*)&result->param1) = i1;
}
break;
case ITC_FLOAT:
{
int ir = -666;
double i1 = (item1)?(*((double*)&item1->param1)):(0.0);
double i2 = (item2)?(*((double*)&item2->param1)):(0.0);
switch (subtype)
{
case ITO_MINUS: i1 -= i2; break; // unary minus auto handled with NULL
case ITO_PLUS: i1 += i2; break;
case ITO_MUL: i1 *= i2; break;
case ITO_DIV: i1 /= i2; break;
case ITO_SET: i1 = i2; break;
case ITO_LE: ir = (i1 <= i2); break;
case ITO_GE: ir = (i1 >= i2); break;
case ITO_NE: ir = (i1 != i2); break;
case ITO_EQ: ir = (i1 == i2); break;
case ITO_LS: ir = (i1 < i2); break;
case ITO_GR: ir = (i1 > i2); break;
}
result = AllocItem();
if (ir == -666)
{
// if ir value left intact - result is double
result->type = IT_CONST | ITC_FLOAT;
*((double*)&result->param1) = i1;
} else
*((__int64*)&result->param1) = (__int64) ir;
}
break;
case ITC_STRING:
{
int ir = -666;
char *i1 = (item1)?((char*)item1->param1):(NULL);
char *i2 = (item2)?((char*)item2->param1):(NULL);
int sc = lstrcmp(i1, i2);
switch (subtype)
{
case ITO_PLUS: lstrcat(i1, i2); break;
case ITO_SET: i1 = i2; break;
case ITO_LE: ir = (sc <= 0); break;
case ITO_GE: ir = (sc >= 0); break;
case ITO_NE: ir = (sc != 0); break;
case ITO_EQ: ir = (sc == 0); break;
case ITO_LS: ir = (sc < 0); break;
case ITO_GR: ir = (sc > 0); break;
}
if (ir == -666)
{
result = CopyItem((item1)?(item1):(item2));
} else
{
result = AllocItem();
*((__int64*)&result->param1) = (__int64) ir;
}
}
break;
case ITC_ARRAY:
result = CopyItem(item2);
break;
}
} // check for both items constant
// the other case - usually UniaryPre operators working with non constants
else result = CopyItem(item2);
if (ioptions & PO_SET)
{
// Save our result in output variable
SaveResult(var, result);
}
// Actual value to be returned as result is at i2 for ++ and -- ops
if ((subtype == ITO_DEC) || (subtype == ITO_INC))
*((__int64*)&result->param1) = i2;
CleanupItems(item1); CleanupItems(item2); CleanupItems(var);
}
break;
case IT_LOGIC:
{
int ifmode = (subtype == ITL_IF);
ExpressionItem *ifbr = *((ExpressionItem**)&(item->param1)),
*dobr = *((ExpressionItem**)&(item->param2)),
*thbr = NULL, *elbr = NULL;
// check do branche for existance
if (dobr && ifmode)
{
// then...
thbr = *((ExpressionItem**)&(dobr->param1));
// ... and else branches
if (dobr->next) elbr = *((ExpressionItem**)&(dobr->next->param1));
}
while (true)
{
RunAndGetConst((int) ifbr, result, ITC_INT);
if (ifmode)
{
// we need then or else branch?
if ((*((__int64*)&result->param1))) dobr = thbr;
else dobr = elbr;
} else
{
// while mode
if (!(*((__int64*)&result->param1))) break;
}
// ok, run the approtiate branch of if statement (if available)
if (dobr)
{
CleanupItems(result);
RunTree(dobr, result, options);
}
if (ifmode) break;
CleanupItems(result);
}
}
break;
case IT_FUNCTION:
if (subtype == ITF_USER)
{
UserFunc *f = &(UserFuncs[ioptions]);
int flags = f->varflags;
ExpressionItem *ip = *((ExpressionItem**)&(item->param1));
ExpressionItem *si = AllocItem(), *var = AllocItem();
ExpressionItem *vals[32];
si->type = IT_VARIABLE | ITV_STACK;
for (int i = 0; i < f->varsnum; i++)
{
// push every variable
ExpressionItem *val;
var->type = (IT_VARIABLE | ITV_USER) + f->vars[i];
RunTree(var, val, RTO_NEEDCONST | ITC_STRING | ITC_INT | ITC_FLOAT | ITC_ARRAY);
SaveResult(si, val);
CleanupItems(val);
// calculate argument value and for future
if (ip)
{
if (flags&1)
{
// var ptr required
RunTree(*((ExpressionItem**)&(ip->param1)), vals[i], 0);
} else
{
RunTree(*((ExpressionItem**)&(ip->param1)), vals[i], RTO_NEEDCONST | ITC_STRING | ITC_INT | ITC_FLOAT | ITC_ARRAY);
}
ip = ip->next;
} else vals[i] = AllocItem();
flags >>= 1;
}
// now when all values got we could save them to variables
for (int i = 0; i < f->varsnum; i++)
{
var->type = (IT_VARIABLE | ITV_USER) + f->vars[i];
SaveResult(var, vals[i]);
CleanupItems(vals[i]);
}
// ok, call the func
RunTree(f->root, result, RTO_NEEDCONST | ITC_STRING | ITC_INT | ITC_FLOAT | ITC_ARRAY);
// pop original params
for (int i = f->varsnum-1; i >= 0; i--)
{
// pop every variable
ExpressionItem *val;
var->type = (IT_VARIABLE | ITV_USER) + f->vars[i];
RunTree(si, val, RTO_NEEDCONST | ITC_STRING | ITC_INT | ITC_FLOAT | ITC_ARRAY);
SaveResult(var, val);
CleanupItems(val);
}
// free used items
CleanupItems(si); CleanupItems(var);
} else if (subtype == ITF_TYPE)
{
int newtype = (int) MathFunctions[ioptions].fptr;
if (newtype < ITC_UNKNOWN)
{
// get as possibly close to ready expression
RunAndGetConst((int)item->param1, result, newtype);
if (ioptions == ITFT_CARRAY_ID)
CopyArray(result);
} else if (newtype == FTT_FLOATF)
{
// float format function
ExpressionItem *arg1, *arg2;
RunAndGetConst((int)item->param1, arg1, ITC_FLOAT);
double value = *((double*)&(arg1->param1));
RunAndGetConst((int)item->param2, arg2, ITC_INT);
int format = (int) *((__int64*)&(arg2->param1));
result = AllocItem();
result->type = IT_CONST | ITC_STRING;
result->param1 = (EIPARAM) AllocString();
FloatFormat((char*) result->param1, value, format);
CleanupItems(arg1); CleanupItems(arg2);
} else if (newtype == FTT_LEN)
{
// length function
RunTree(*((ExpressionItem **) &(item->param1)), result, RTO_NEEDCONST | ITC_STRING | ITC_ARRAY);
if ((result->type & (ITEMTYPE|ITEMSUBTYPE)) == (IT_CONST|ITC_ARRAY))
{
int len = ((ArrayDesc*)(result->param1))->count;
CleanupItems(result);
result = AllocItem();
*((__int64*)&(result->param1)) = (__int64) len;
break;
} else
if ((result->type & (ITEMTYPE|ITEMSUBTYPE)) != (IT_CONST|ITC_STRING))
ItemToType(result, ITC_STRING);
if ((result->type & (ITEMTYPE|ITEMSUBTYPE)) == (IT_CONST|ITC_STRING))
{
// ok, that's string
int len = lstrlen((char*)result->param1);
dbgGlobalFree((HGLOBAL) result->param1);
*((__int64*)&(result->param1)) = (__int64) len;
result->type = IT_CONST | ITC_INT;
} else CleanupItems(result);
} else
{
// only one left - c() - char/int/char conversion
RunTree(*((ExpressionItem **) &(item->param1)), result, RTO_NEEDCONST | ITC_STRING | ITC_INT);
if ((result->type & (ITEMTYPE|ITEMSUBTYPE)) == (IT_CONST|ITC_STRING))
{
// ok, that's string - convert first char to int
int chr = (*((char*)result->param1)) & 0xFF;
dbgGlobalFree((HGLOBAL) result->param1);
*((__int64*)&(result->param1)) = (__int64) chr;
result->type = IT_CONST | ITC_INT;
break;
}
if ((result->type & (ITEMTYPE|ITEMSUBTYPE)) == (IT_CONST|ITC_INT))
{
// ok, that's int - convert to new string (char+0)
int chr = (int) (*((__int64*)&(result->param1))) & 0xFF;
result->param1 = (EIPARAM) AllocString();
*((char*)result->param1) = (char) chr;
*((char*)(result->param1+1)) = (char) 0;
result->type = IT_CONST | ITC_STRING;
break;
} else CleanupItems(result);
}
} else
{
// oops :-o function call :)
RunAndGetConst((int)item->param1, result, ITC_FLOAT);
double &value = *((double*)&(result->param1));
if (subtype == ITF_MATH1)
{
// Built-In math function with 1 arg
value = MathFunctions[ioptions].fptr(value);
} else
if (subtype == ITF_MATH2)
{
// Built-In math function with 2 args
if (ioptions >= MATHFUNCNUM-2)
{
// specific function - we need second arg as out
ExpressionItem *arg2, *res2 = AllocItem();
RunTree(*((ExpressionItem**)&(item->param2)), arg2, 0);
if (ioptions == MATHFUNCNUM-1)
{
// fmodf function - second arg is ptr to double
res2->type = IT_CONST | ITC_FLOAT;
double &v = *((double*)&(res2->param1));
value = ((Math2dFuncPtr)(MathFunctions[ioptions].fptr))(value, &v);
} else
{
// frexp function - second arg is ptr to int
int v = 0;
value = ((Math2iFuncPtr)(MathFunctions[ioptions].fptr))(value, &v);
*((__int64 *)&(res2->param1)) = (__int64) v;
}
SaveResult(arg2, res2);
CleanupItems(arg2); CleanupItems(res2);
} else
{
// normal 2-arg math function
ExpressionItem *arg2;
RunAndGetConst((int)item->param2, arg2, ITC_FLOAT);
double value2 = *((double*)&(arg2->param1));
value = ((Math2FuncPtr)(MathFunctions[ioptions].fptr))(value, value2);
CleanupItems(arg2);
}
}
}
break;
case IT_ARRAY:
{
// currently only array access is used
ExpressionItem *index, *aritem;
RunTree(*((ExpressionItem **) &(item->param1)), aritem, RTO_NEEDCONST | ITC_STRING | ITC_ARRAY);
if ((aritem->type & (ITEMTYPE|ITEMSUBTYPE)) == (IT_CONST | ITC_STRING))
{
// argument is string
char *str = (char*)(aritem->param1);
int len = lstrlen(str);
// have we two indexes or one?
if ((*((ExpressionItem **) &(item->param2)))->type != IT_EXPRESSION)
{
// one index - user need a char
RunAndGetConst((int)item->param2, index, ITC_INT);
int pos = (int) *((__int64*)&(index->param1));
if (pos < 0) pos += len; // -index - means from end
if ((pos > len) || (pos < 0))
*str = 0; // index is accross string boundaries
else
{
// new string - just a single char
*str = *(str+pos);
*(str+1) = 0;
}
} else
{
// two indexes
ExpressionItem *index2;
// if first index is skipped -> 0 (from first char)
if ((*((ExpressionItem **) &(item->param2)))->param1 == 0)
index = AllocItem();
else
RunAndGetConst((int)(*((ExpressionItem **) &(item->param2)))->param1, index, ITC_INT);
if ((*((ExpressionItem **) &(item->param2)))->next->param1 == 0)
{
// if second index is skipped -> -1 (till last char)
index2 = AllocItem();
*((__int64*)&(index2->param1)) = -1;
}
else
RunAndGetConst((int)(*((ExpressionItem **) &(item->param2)))->next->param1, index2, ITC_INT);
// ok, we've got two indexes
int pos1 = (int) *((__int64*)&(index->param1));
int pos2 = (int) *((__int64*)&(index2->param1));
if (pos1 < 0) pos1 += len; // -index - means from end
if (pos2 < 0) pos2 += len; // -index - means from end
// limit start/stop positions
if (pos1 < 0) pos1 = 0;
if (pos2 < 0) pos2 = 0;
if (pos1 > len) pos1 = len;
if (pos2 >= len) pos2 = len-1;
// copy string part
char* lpos = str + (pos2-pos1);
while (str <= lpos)
{
*str = *(str + pos1);
str++;
}
// null-termiante
*str = 0;
CleanupItems(index2);
}
} else
{
// argument is array
RunAndGetConst((int)item->param2, index, ITC_INT);
// convert array pointer to array item pointer
aritem->type = IT_VARIABLE | ITV_ARRITEM;
aritem->param2 = (EIPARAM) *((__int64*)&(index->param1));
ArrayDesc *ad = (ArrayDesc*)aritem->param1;
if (((int)aritem->param2) > ad->count)
{
ad->count = ((int)aritem->param2)+1;
while (ad->count > ad->size)
{
// resize array
ExpressionItem **oldei = ad->array;
ad->array = (ExpressionItem**) dbgGlobalAlloc(GPTR, 2*ad->size*sizeof(ExpressionItem*));
for (int i = 0; i < ad->size; i++)
ad->array[i] = oldei[i];
ad->size*=2;
dbgGlobalFree(oldei);
}
}
}
CleanupItems(index);
// we need constant result?
if (options & RTO_NEEDCONST)
{
RunTree(aritem, result, options);
CleanupItems(aritem);
} else result = aritem;
}
break;
}
item = item->next;
}
}
extern "C"
void __declspec(dllexport) Script(HWND hwndParent, int string_size,
char *variables, stack_t **stacktop)
{
Math_INIT();
char *buffer = AllocString(), *buf = buffer;
ExpressionItem *root = NULL; // root of current tree
// pop script string
popstring(buffer);
// parse it
ParseString(buf, root);
#ifdef _DEBUG
// dump
PrintTree(root, buffer);
#endif
ExpressionItem *result;
RunTree(root, result, 0);
CleanupItems(result);
CleanupItems(root);
dbgGlobalFree((HGLOBAL) buffer);
}
double _infinity;
void CleanAll(int init)
{
if (init)
{
unsigned char _infinity_base[8] = {0, 0, 0, 0, 0, 0, 0xf0, 0x7f};
_fltused = 0;
_infinity = *((double*)(_infinity_base));
_fpreset();
stack = NULL;
UserVarsCount = 0;
UserFuncsCount = 0;
} else
{
// cleanup stack
CleanupItems(stack); stack = NULL;
// cleanup user vars
for (int i = 0; i < UserVarsCount; i++)
CleanupItems(UserVars[i].item);
// cleanup user funcs
for (int i = 0; i < UserFuncsCount; i++)
CleanupItems(UserFuncs[i].root);
UserVarsCount = 0;
UserFuncsCount = 0;
dbgGlobalCheck();
}
}
BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
{
CleanAll(ul_reason_for_call == DLL_PROCESS_ATTACH);
return TRUE;
}
#ifdef _DEBUG
BOOL WINAPI DllMain(
HANDLE hDllHandle,
DWORD dwReason,
LPVOID lpreserved
)
{
CleanAll(dwReason == DLL_PROCESS_ATTACH);
return TRUE;
}
#endif