Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
991 lines (950 sloc) 24.8 KB
/* Copyright (C) 2005-2010 Valeriy Argunov (nporep AT mail DOT ru) */
/*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "variables.h"
#include "coding.h"
#include "errors.h"
#include "locations.h"
#include "mathops.h"
#include "regexp.h"
#include "text.h"
QSPVar qspVars[QSP_VARSCOUNT];
QSPVarsGroup *qspSavedVarsGroups = 0;
int qspSavedVarsGroupsCount = 0;
unsigned char qspRand8[256] =
{
0x0C, 0x6B, 0x35, 0x24, 0x85, 0x05, 0x2B, 0xAC, 0x32, 0x26, 0xF3, 0x4C, 0x8F, 0xF4, 0x8E, 0xBC,
0xEC, 0x69, 0x4D, 0x95, 0x77, 0x68, 0xC3, 0xDB, 0xC2, 0x71, 0x1F, 0xD1, 0x14, 0xAA, 0x0A, 0x09,
0x0D, 0x06, 0xD3, 0x51, 0xE9, 0x31, 0x36, 0x9E, 0x9D, 0x80, 0x25, 0xEF, 0xE2, 0x55, 0xEE, 0x90,
0x5A, 0xB4, 0xE7, 0x29, 0x04, 0xC1, 0x67, 0x00, 0xD4, 0xD2, 0x75, 0xD0, 0xF8, 0x74, 0x84, 0x46,
0xC8, 0x44, 0xE6, 0x63, 0x3D, 0xD8, 0x9C, 0xDA, 0x07, 0xB5, 0x39, 0x6A, 0xA7, 0xDE, 0x50, 0xF9,
0x66, 0xA8, 0xBD, 0xC9, 0x19, 0xCE, 0x7D, 0xEB, 0xE4, 0xCD, 0xFD, 0xA5, 0x21, 0x83, 0xA3, 0xD9,
0x97, 0x10, 0xBF, 0x8B, 0xD5, 0x81, 0x41, 0x1E, 0x6E, 0x11, 0x4E, 0xAE, 0x57, 0x92, 0xC4, 0xA1,
0x3F, 0x7C, 0x4A, 0x18, 0x23, 0x6D, 0x3B, 0x96, 0xAF, 0xE0, 0x4F, 0xF5, 0x7E, 0x22, 0xB7, 0x30,
0x59, 0x15, 0x47, 0xDC, 0xE1, 0x65, 0xA6, 0x20, 0x1B, 0x42, 0xCC, 0x1D, 0x94, 0xCF, 0xCA, 0x53,
0x9A, 0x28, 0x87, 0x3C, 0x8C, 0x78, 0x2D, 0x93, 0x8D, 0x38, 0x03, 0xA2, 0xDD, 0x49, 0x62, 0xF0,
0xDF, 0xA0, 0xF2, 0x48, 0x72, 0x6F, 0x7F, 0xC6, 0x73, 0x1A, 0x76, 0xAD, 0x0B, 0xFE, 0x82, 0x6C,
0xBA, 0x0F, 0x3A, 0x60, 0x12, 0x7B, 0x33, 0xBE, 0x9F, 0x5D, 0x01, 0x64, 0xB6, 0x17, 0xD7, 0x98,
0x02, 0xB9, 0x4B, 0xFF, 0xAB, 0xB0, 0x5B, 0xB3, 0x16, 0xF7, 0xCB, 0xFC, 0xC5, 0x0E, 0x52, 0x5C,
0xE8, 0x2A, 0x86, 0x61, 0xC7, 0x2E, 0xE5, 0xA4, 0xFA, 0x79, 0x27, 0xFB, 0xC0, 0x7A, 0x8A, 0x37,
0xB2, 0xED, 0xA9, 0x5F, 0xBB, 0x3E, 0x45, 0x2F, 0x54, 0x58, 0x2C, 0x70, 0x40, 0xE3, 0x56, 0xB8,
0xEA, 0x91, 0x34, 0xF6, 0x88, 0x43, 0x99, 0xD6, 0x89, 0x9B, 0x08, 0xF1, 0x5E, 0x1C, 0xB1, 0x13
};
static int qspIndStringCompare(const void *, const void *);
static void qspRemoveArray(QSPString name);
static void qspRemoveArrayItem(QSPString name, int index);
static void qspInitVarData(QSPVar *);
static int qspGetVarTextIndex(QSPVar *, QSPString, QSP_BOOL);
static QSPVar *qspGetVarData(QSPString s, QSP_BOOL isSet, int *index);
static void qspSetVar(QSPString name, QSPVariant *val, QSP_CHAR op);
static void qspCopyVar(QSPVar *, QSPVar *, int, int);
static void qspSetVarValue(QSPString name, QSPVariant *v, QSP_CHAR op);
static QSPString qspGetVarNameOnly(QSPString s);
static int qspIndStringCompare(const void *name, const void *compareTo)
{
return qspStrsComp(*(QSPString *)name, ((QSPVarIndex *)compareTo)->Str);
}
void qspClearVars(QSP_BOOL isFirst)
{
int i;
QSPVar *var = qspVars;
for (i = 0; i < QSP_VARSCOUNT; ++i)
{
if (isFirst)
qspInitVarData(var);
else
{
qspFreeString(var->Name);
qspEmptyVar(var);
}
var->Name = qspNullString;
++var;
}
}
void qspEmptyVar(QSPVar *var)
{
int count;
if (var->Values)
{
count = var->ValsCount;
while (--count >= 0)
qspFreeString(var->Values[count].Str);
free(var->Values);
}
if (var->Indices)
{
count = var->IndsCount;
while (--count >= 0)
qspFreeString(var->Indices[count].Str);
free(var->Indices);
}
qspInitVarData(var);
}
static void qspRemoveArray(QSPString name)
{
QSPVar *var;
if (!(var = qspVarReferenceWithType(name, QSP_FALSE, 0))) return;
qspEmptyVar(var);
}
static void qspRemoveArrayItem(QSPString name, int index)
{
QSPVar *var;
QSP_BOOL isRemoving;
QSPVarIndex *ind;
int origIndex;
if (!(var = qspVarReferenceWithType(name, QSP_FALSE, 0))) return;
if (index < 0 || index >= var->ValsCount) return;
origIndex = index;
qspFreeString(var->Values[index].Str);
var->ValsCount--;
while (index < var->ValsCount)
{
var->Values[index] = var->Values[index + 1];
++index;
}
isRemoving = QSP_FALSE;
for (index = 0; index < var->IndsCount; ++index)
{
ind = var->Indices + index;
if (ind->Index == origIndex)
{
qspFreeString(ind->Str);
var->IndsCount--;
if (index == var->IndsCount) break;
isRemoving = QSP_TRUE;
}
if (isRemoving) *ind = var->Indices[index + 1];
if (ind->Index > origIndex) ind->Index--;
}
}
static void qspInitVarData(QSPVar *var)
{
var->Values = 0;
var->ValsCount = 0;
var->Indices = 0;
var->IndsCount = 0;
var->IndsBufSize = 0;
}
QSPVar *qspVarReference(QSPString name, QSP_BOOL isCreate)
{
int i;
QSPVar *var;
QSPString uName;
QSP_CHAR *pos;
unsigned char bCode;
if (qspIsEmpty(name))
{
qspSetError(QSP_ERR_NOTCORRECTNAME);
return 0;
}
if (*name.Str == QSP_STRCHAR[0]) ++name.Str;
if (qspIsEmpty(name) || qspIsDigit(*name.Str) || qspStrPBrk(name, QSP_DELIMS))
{
qspSetError(QSP_ERR_NOTCORRECTNAME);
return 0;
}
uName = qspGetNewText(name);
qspUpperStr(&uName);
bCode = 0;
for (pos = uName.Str; pos < uName.End; ++pos)
bCode = qspRand8[bCode ^ (unsigned char)*pos];
var = qspVars + QSP_VARSSEEK * bCode;
for (i = 0; i < QSP_VARSSEEK; ++i)
{
if (!var->Name.Str)
{
if (isCreate)
var->Name = uName;
else
qspFreeString(uName);
return var;
}
if (!qspStrsComp(var->Name, uName))
{
qspFreeString(uName);
return var;
}
++var;
}
qspFreeString(uName);
qspSetError(QSP_ERR_TOOMANYVARS);
return 0;
}
QSPVar *qspVarReferenceWithType(QSPString name, QSP_BOOL isCreate, QSP_BOOL *isString)
{
name = qspDelSpc(name);
if (isString) *isString = (!qspIsEmpty(name) && *name.Str == QSP_STRCHAR[0]);
return qspVarReference(name, isCreate);
}
static int qspGetVarTextIndex(QSPVar *var, QSPString str, QSP_BOOL isCreate)
{
QSPVarIndex *ind;
int i, n = var->IndsCount;
QSPString uStr = qspGetNewText(str);
qspUpperStr(&uStr);
if (n > 0)
{
ind = (QSPVarIndex *)bsearch(&uStr, var->Indices, n, sizeof(QSPVarIndex), qspIndStringCompare);
if (ind)
{
qspFreeString(uStr);
return ind->Index;
}
}
if (isCreate)
{
var->IndsCount++;
if (n >= var->IndsBufSize)
{
var->IndsBufSize = n + 8;
var->Indices = (QSPVarIndex *)realloc(var->Indices, var->IndsBufSize * sizeof(QSPVarIndex));
}
i = n - 1;
while (i >= 0 && qspStrsComp(var->Indices[i].Str, uStr) > 0)
{
var->Indices[i + 1] = var->Indices[i];
--i;
}
++i;
n = var->ValsCount;
var->Indices[i].Str = uStr;
var->Indices[i].Index = n;
return n;
}
qspFreeString(uStr);
return -1;
}
static QSPVar *qspGetVarData(QSPString s, QSP_BOOL isSet, int *index)
{
QSPVar *var;
QSPVariant ind;
int oldRefreshCount;
QSP_CHAR *startPos, *rPos, *lPos = qspStrChar(s, QSP_LSBRACK[0]);
if (lPos)
{
startPos = s.Str;
s.Str = lPos;
rPos = qspStrPos(s, QSP_STATIC_STR(QSP_RSBRACK), QSP_FALSE);
if (!rPos)
{
qspSetError(QSP_ERR_BRACKNOTFOUND);
return 0;
}
var = qspVarReference(qspStringFromPair(startPos, lPos), isSet);
if (!var) return 0;
s.Str = lPos + QSP_STATIC_LEN(QSP_LSBRACK);
qspSkipSpaces(&s);
if (s.Str == rPos)
{
if (isSet)
*index = var->ValsCount;
else
*index = (var->ValsCount ? var->ValsCount - 1 : 0);
}
else
{
oldRefreshCount = qspRefreshCount;
ind = qspExprValue(qspStringFromPair(s.Str, rPos));
if (qspRefreshCount != oldRefreshCount || qspErrorNum) return 0;
if (ind.IsStr)
{
*index = qspGetVarTextIndex(var, QSP_STR(ind), isSet);
qspFreeString(QSP_STR(ind));
}
else
*index = QSP_NUM(ind);
}
return var;
}
*index = 0;
return qspVarReference(s, isSet);
}
void qspSetVarValueByReference(QSPVar *var, int ind, QSPVariant *val)
{
int count, oldCount = var->ValsCount;
if (ind >= oldCount)
{
count = var->ValsCount = ind + 1;
var->Values = (QSPVarValue *)realloc(var->Values, count * sizeof(QSPVarValue));
while (oldCount < count)
{
var->Values[oldCount].Num = 0;
var->Values[oldCount].Str = qspNullString;
++oldCount;
}
}
if (ind >= 0)
{
if (val->IsStr)
qspUpdateText(&var->Values[ind].Str, QSP_PSTR(val));
else
var->Values[ind].Num = QSP_PNUM(val);
}
}
static void qspSetVar(QSPString name, QSPVariant *val, QSP_CHAR op)
{
QSPVariant oldVal;
QSPVar *var;
int index;
if (!(var = qspGetVarData(name, QSP_TRUE, &index))) return;
if (op == QSP_EQUAL[0])
{
if (qspConvertVariantTo(val, *name.Str == QSP_STRCHAR[0]))
{
qspSetError(QSP_ERR_TYPEMISMATCH);
return;
}
qspSetVarValueByReference(var, index, val);
}
else if (op == QSP_ADD[0])
{
oldVal = qspGetVarValueByReference(var, index, *name.Str == QSP_STRCHAR[0]);
if (oldVal.IsStr && val->IsStr)
qspAddText(&QSP_STR(oldVal), QSP_PSTR(val), QSP_FALSE);
else if (qspIsCanConvertToNum(&oldVal) && qspIsCanConvertToNum(val))
{
qspConvertVariantTo(&oldVal, QSP_FALSE);
qspConvertVariantTo(val, QSP_FALSE);
QSP_NUM(oldVal) += QSP_PNUM(val);
qspConvertVariantTo(&oldVal, *name.Str == QSP_STRCHAR[0]);
}
else
{
if (!oldVal.IsStr)
{
qspSetError(QSP_ERR_TYPEMISMATCH);
return;
}
qspConvertVariantTo(val, QSP_TRUE);
qspAddText(&QSP_STR(oldVal), QSP_PSTR(val), QSP_FALSE);
}
qspSetVarValueByReference(var, index, &oldVal);
if (oldVal.IsStr) qspFreeString(QSP_STR(oldVal));
}
else if (qspIsInList(QSP_SUB QSP_DIV QSP_MUL, op))
{
if (qspConvertVariantTo(val, QSP_FALSE))
{
qspSetError(QSP_ERR_TYPEMISMATCH);
return;
}
oldVal = qspGetVarValueByReference(var, index, *name.Str == QSP_STRCHAR[0]);
if (qspConvertVariantTo(&oldVal, QSP_FALSE))
{
qspSetError(QSP_ERR_TYPEMISMATCH);
qspFreeString(QSP_STR(oldVal));
return;
}
if (op == QSP_SUB[0])
QSP_NUM(oldVal) -= QSP_PNUM(val);
else if (op == QSP_DIV[0])
{
if (!QSP_PNUM(val))
{
qspSetError(QSP_ERR_DIVBYZERO);
return;
}
QSP_NUM(oldVal) /= QSP_PNUM(val);
}
else
QSP_NUM(oldVal) *= QSP_PNUM(val);
qspConvertVariantTo(&oldVal, *name.Str == QSP_STRCHAR[0]);
qspSetVarValueByReference(var, index, &oldVal);
if (oldVal.IsStr) qspFreeString(QSP_STR(oldVal));
}
}
QSPVariant qspGetVarValueByReference(QSPVar *var, int ind, QSP_BOOL isStringType)
{
QSPVariant ret;
QSPString text;
if (ind >= 0 && ind < var->ValsCount)
{
if (ret.IsStr = isStringType)
{
text = var->Values[ind].Str;
QSP_STR(ret) = (text.Str ? qspGetNewText(text) : qspNewEmptyString());
}
else
QSP_NUM(ret) = var->Values[ind].Num;
return ret;
}
return qspGetEmptyVariant(isStringType);
}
QSPString qspGetVarStrValue(QSPString name)
{
QSPString text;
QSPVar *var;
if (var = qspVarReference(name, QSP_FALSE))
{
if (var->ValsCount)
{
text = var->Values->Str;
if (text.Str) return text;
}
}
else
qspResetError();
return qspEmptyString;
}
int qspGetVarNumValue(QSPString name)
{
QSPVar *var;
if (var = qspVarReference(name, QSP_FALSE))
{
if (var->ValsCount) return var->Values->Num;
}
else
qspResetError();
return 0;
}
QSPVariant qspGetVar(QSPString name)
{
QSPVar *var;
int index;
if (!(var = qspGetVarData(name, QSP_FALSE, &index))) return qspGetEmptyVariant(QSP_FALSE);
return qspGetVarValueByReference(var, index, *name.Str == QSP_STRCHAR[0]);
}
void qspPrepareGlobalVars()
{
int i, j;
QSPVar *var;
for (i = qspSavedVarsGroupsCount - 1; i >= 0; --i)
{
for (j = qspSavedVarsGroups[i].VarsCount - 1; j >= 0; --j)
{
if (!(var = qspVarReference(qspSavedVarsGroups[i].Vars[j].Name, QSP_TRUE))) return;
qspEmptyVar(var);
qspMoveVar(var, &qspSavedVarsGroups[i].Vars[j]);
}
}
}
int qspPrepareLocalVars(QSPVar **vars)
{
QSPVar *var, *savedVars;
int i, j, ind, varsCount = 0;
for (i = qspSavedVarsGroupsCount - 1; i >= 0; --i)
varsCount += qspSavedVarsGroups[i].VarsCount;
if (!varsCount)
{
*vars = 0;
return 0;
}
savedVars = (QSPVar *)malloc(varsCount * sizeof(QSPVar));
ind = 0;
for (i = qspSavedVarsGroupsCount - 1; i >= 0; --i)
{
for (j = qspSavedVarsGroups[i].VarsCount - 1; j >= 0; --j)
{
if (!(var = qspVarReference(qspSavedVarsGroups[i].Vars[j].Name, QSP_TRUE)))
{
while (--ind >= 0)
qspEmptyVar(savedVars + ind);
free(savedVars);
return 0;
}
qspMoveVar(savedVars + ind, var);
qspMoveVar(var, &qspSavedVarsGroups[i].Vars[j]);
++ind;
}
}
*vars = savedVars;
return varsCount;
}
void qspRestoreLocalVars(QSPVar *savedVars, int varsCount, QSPVarsGroup *savedGroups, int groupsCount)
{
QSPVar *var;
int i, j, ind;
if (savedVars)
{
ind = 0;
for (i = groupsCount - 1; i >= 0; --i)
{
for (j = savedGroups[i].VarsCount - 1; j >= 0; --j)
{
if (!(var = qspVarReference(savedGroups[i].Vars[j].Name, QSP_TRUE)))
{
while (ind < varsCount)
{
qspEmptyVar(savedVars + ind);
++ind;
}
free(savedVars);
return;
}
qspMoveVar(&savedGroups[i].Vars[j], var);
qspMoveVar(var, savedVars + ind);
++ind;
}
}
free(savedVars);
}
}
void qspClearLocalVars(QSPVar *savedVars, int varsCount)
{
int i;
if (savedVars)
{
for (i = 0; i < varsCount; ++i)
qspEmptyVar(savedVars + i);
free(savedVars);
}
}
void qspRestoreVarsList(QSPVar *vars, int varsCount)
{
int i;
QSPVar *var;
if (vars)
{
for (i = 0; i < varsCount; ++i)
{
if (!(var = qspVarReference(vars[i].Name, QSP_TRUE)))
{
while (i < varsCount)
{
qspFreeString(vars[i].Name);
qspEmptyVar(vars + i);
++i;
}
free(vars);
return;
}
qspFreeString(vars[i].Name);
qspEmptyVar(var);
qspMoveVar(var, vars + i);
}
free(vars);
}
}
void qspClearVarsList(QSPVar *vars, int varsCount)
{
int i;
if (vars)
{
for (i = 0; i < varsCount; ++i)
{
qspFreeString(vars[i].Name);
qspEmptyVar(vars + i);
}
free(vars);
}
}
static void qspCopyVar(QSPVar *dest, QSPVar *src, int start, int count)
{
QSPString str;
int i, maxCount, newInd;
if (start < 0) start = 0;
maxCount = src->ValsCount - start;
if (count <= 0 || maxCount <= 0)
{
qspInitVarData(dest);
return;
}
if (count < maxCount) maxCount = count;
dest->ValsCount = maxCount;
dest->Values = (QSPVarValue *)malloc(maxCount * sizeof(QSPVarValue));
for (i = 0; i < maxCount; ++i)
{
dest->Values[i].Num = src->Values[i + start].Num;
str = src->Values[i + start].Str;
dest->Values[i].Str = (str.Str ? qspGetNewText(str) : qspNullString);
}
dest->IndsBufSize = 0;
dest->Indices = 0;
count = 0;
for (i = 0; i < src->IndsCount; ++i)
{
newInd = src->Indices[i].Index - start;
if (newInd >= 0 && newInd < maxCount)
{
if (count >= dest->IndsBufSize)
{
dest->IndsBufSize = count + 16;
dest->Indices = (QSPVarIndex *)realloc(dest->Indices, dest->IndsBufSize * sizeof(QSPVarIndex));
}
dest->Indices[count].Index = newInd;
dest->Indices[count].Str = qspGetNewText(src->Indices[i].Str);
++count;
}
}
dest->IndsCount = count;
}
int qspArraySize(QSPString name)
{
QSPVar *var;
if (!(var = qspVarReferenceWithType(name, QSP_FALSE, 0))) return 0;
return var->ValsCount;
}
int qspArrayPos(QSPString varName, QSPVariant *val, int ind, QSP_BOOL isRegExp)
{
int num, count;
QSPVar *var;
QSPString str, emptyStr;
regex_t *regExp;
QSP_BOOL isString;
if (!(var = qspVarReferenceWithType(varName, QSP_FALSE, &isString))) return -1;
if (qspConvertVariantTo(val, isRegExp || isString))
{
qspSetError(QSP_ERR_TYPEMISMATCH);
return -1;
}
if (isRegExp)
{
regExp = qspRegExpGetCompiled(QSP_PSTR(val));
if (!regExp) return -1;
}
count = var->ValsCount;
if (ind < 0)
ind = 0;
else if (ind > count)
ind = count;
emptyStr = qspEmptyString;
while (ind <= count)
{
if (val->IsStr)
{
if (ind >= count)
str = emptyStr;
else
{
str = var->Values[ind].Str;
if (!str.Str) str = emptyStr;
}
if (isRegExp)
{
if (qspRegExpStrMatch(regExp, str)) return ind;
}
else if (!qspStrsComp(str, QSP_PSTR(val)))
return ind;
}
else
{
num = (ind < count ? var->Values[ind].Num : 0);
if (num == QSP_PNUM(val)) return ind;
}
++ind;
}
return -1;
}
QSPVariant qspArrayMinMaxItem(QSPString name, QSP_BOOL isMin)
{
QSPVar *var;
QSPString str;
QSP_BOOL isString;
int curInd, count;
QSPVariant res;
if (!(var = qspVarReferenceWithType(name, QSP_FALSE, &isString)))
return qspGetEmptyVariant(QSP_FALSE);
curInd = -1;
count = var->ValsCount;
while (--count >= 0)
{
if (isString)
{
str = var->Values[count].Str;
if (!qspIsEmpty(str))
{
if (curInd >= 0)
{
if (isMin)
{
if (QSP_STRCOLL(str, var->Values[curInd].Str) < 0)
curInd = count;
}
else if (QSP_STRCOLL(str, var->Values[curInd].Str) > 0)
curInd = count;
}
else
curInd = count;
}
}
else if (curInd >= 0)
{
if (isMin)
{
if (var->Values[count].Num < var->Values[curInd].Num)
curInd = count;
}
else if (var->Values[count].Num > var->Values[curInd].Num)
curInd = count;
}
else
curInd = count;
}
if (curInd < 0) return qspGetEmptyVariant(isString);
if (res.IsStr = isString)
QSP_STR(res) = qspGetNewText(var->Values[curInd].Str);
else
QSP_NUM(res) = var->Values[curInd].Num;
return res;
}
int qspGetVarsCount()
{
int i, count = 0;
for (i = 0; i < QSP_VARSCOUNT; ++i)
if (qspVars[i].Name.Str) ++count;
return count;
}
void qspSetArgs(QSPVar *var, QSPVariant *args, int count)
{
while (--count >= 0)
qspSetVarValueByReference(var, count, args + count);
}
void qspApplyResult(QSPVar *varRes, QSPVariant *res)
{
QSPString text;
if (varRes->ValsCount)
{
text = varRes->Values[0].Str;
if (text.Str)
{
res->IsStr = QSP_TRUE;
QSP_PSTR(res) = qspGetNewText(text);
}
else
{
res->IsStr = QSP_FALSE;
QSP_PNUM(res) = varRes->Values[0].Num;
}
}
else
{
res->IsStr = QSP_TRUE;
QSP_PSTR(res) = qspNewEmptyString();
}
}
void qspMoveVar(QSPVar *dest, QSPVar *src)
{
dest->Values = src->Values;
dest->ValsCount = src->ValsCount;
dest->Indices = src->Indices;
dest->IndsCount = src->IndsCount;
dest->IndsBufSize = src->IndsBufSize;
qspInitVarData(src);
}
static void qspSetVarValue(QSPString name, QSPVariant *v, QSP_CHAR op)
{
QSPVariant v2;
QSPString strVal;
QSP_BOOL isSingleValue, notFirstValue = QSP_FALSE;
QSP_CHAR *newValPos, *newCommaPos;
int oldRefreshCount = qspRefreshCount;
if (v->IsStr)
{
strVal = QSP_PSTR(v);
isSingleValue = QSP_FALSE; /* Multiple values by default */
}
else
isSingleValue = QSP_TRUE;
while (1)
{
newCommaPos = qspStrPos(name, QSP_STATIC_STR(QSP_COMMA), QSP_FALSE);
if (newCommaPos)
{
if (isSingleValue)
{
if (notFirstValue)
qspSetVar(qspStringFromPair(name.Str, newCommaPos), &v2, op);
else
qspSetVar(qspStringFromPair(name.Str, newCommaPos), v, op);
if (qspRefreshCount != oldRefreshCount || qspErrorNum)
break;
}
else
{
newValPos = qspStrStr(strVal, QSP_STATIC_STR(QSP_VALSDELIM));
if (newValPos)
{
notFirstValue = QSP_TRUE;
v2.IsStr = QSP_TRUE;
QSP_STR(v2) = qspGetNewText(qspStringFromPair(strVal.Str, newValPos));
qspSetVar(qspStringFromPair(name.Str, newCommaPos), &v2, op);
if (qspRefreshCount != oldRefreshCount || qspErrorNum)
break;
if (v2.IsStr) qspFreeString(QSP_STR(v2));
strVal.Str = newValPos + QSP_STATIC_LEN(QSP_VALSDELIM);
}
else /* The last value */
{
isSingleValue = QSP_TRUE;
if (notFirstValue)
{
v2.IsStr = QSP_TRUE;
QSP_STR(v2) = qspGetNewText(strVal);
qspSetVar(qspStringFromPair(name.Str, newCommaPos), &v2, op);
}
else
qspSetVar(qspStringFromPair(name.Str, newCommaPos), v, op);
if (qspRefreshCount != oldRefreshCount || qspErrorNum)
break;
}
}
name.Str = newCommaPos + QSP_STATIC_LEN(QSP_COMMA);
}
else /* The last variable */
{
if (notFirstValue) /* Not a first value */
{
if (!isSingleValue)
{
v2.IsStr = QSP_TRUE;
QSP_STR(v2) = qspGetNewText(strVal);
}
qspSetVar(name, &v2, op);
}
else
qspSetVar(name, v, op);
break;
}
}
if (notFirstValue && v2.IsStr) qspFreeString(QSP_STR(v2));
}
void qspStatementSetVarValue(QSPString s)
{
QSPVariant v;
int oldRefreshCount;
QSPString name;
QSP_CHAR *pos = qspStrPos(s, QSP_STATIC_STR(QSP_EQUAL), QSP_FALSE);
if (!pos)
{
qspSetError(QSP_ERR_EQNOTFOUND);
return;
}
oldRefreshCount = qspRefreshCount;
v = qspExprValue(qspStringFromPair(pos + QSP_STATIC_LEN(QSP_EQUAL), s.End));
if (qspRefreshCount != oldRefreshCount || qspErrorNum) return;
if (pos != s.Str && qspIsInList(QSP_ADD QSP_SUB QSP_DIV QSP_MUL, *(pos - 1))) --pos;
name = qspDelSpc(qspStringFromPair(s.Str, pos));
qspSetVarValue(name, &v, *pos);
if (v.IsStr) qspFreeString(QSP_STR(v));
}
static QSPString qspGetVarNameOnly(QSPString s)
{
QSP_CHAR *brackPos = qspStrChar(s, QSP_LSBRACK[0]);
if (brackPos) s.End = brackPos;
return qspDelSpc(s);
}
void qspStatementLocal(QSPString s)
{
QSPVariant v;
QSPVar *var;
QSP_BOOL isVarFound;
QSPString curPos, varName;
QSP_CHAR *commaPos, *eqPos;
int i, groupInd, count, bufSize, oldRefreshCount;
qspSkipSpaces(&s);
eqPos = qspStrPos(s, QSP_STATIC_STR(QSP_EQUAL), QSP_FALSE);
if (eqPos)
curPos = qspStringFromPair(s.Str, eqPos);
else
curPos = s;
if (qspIsEmpty(curPos))
{
qspSetError(QSP_ERR_SYNTAX);
return;
}
groupInd = qspSavedVarsGroupsCount - 1;
count = bufSize = qspSavedVarsGroups[groupInd].VarsCount;
isVarFound = QSP_FALSE;
while (1)
{
/* Skip type char */
if (*curPos.Str == QSP_STRCHAR[0]) ++curPos.Str;
/* Get variable's name */
commaPos = qspStrPos(curPos, QSP_STATIC_STR(QSP_COMMA), QSP_FALSE);
if (commaPos)
varName = qspStringFromPair(curPos.Str, commaPos);
else
varName = curPos;
varName = qspGetNewText(qspGetVarNameOnly(varName));
qspUpperStr(&varName);
/* Check for the existence */
for (i = 0; i < count; ++i)
{
if (!qspStrsComp(varName, qspSavedVarsGroups[groupInd].Vars[i].Name))
{
isVarFound = QSP_TRUE;
break;
}
}
/* Get variable's data */
if (isVarFound)
{
/* Already exists */
isVarFound = QSP_FALSE;
qspFreeString(varName);
}
else
{
/* Add variable to the local group */
if (!(var = qspVarReference(varName, QSP_FALSE)))
{
qspFreeString(varName);
return;
}
if (count >= bufSize)
{
bufSize = count + 4;
qspSavedVarsGroups[groupInd].Vars = (QSPVar *)realloc(qspSavedVarsGroups[groupInd].Vars, bufSize * sizeof(QSPVar));
}
qspMoveVar(qspSavedVarsGroups[groupInd].Vars + count, var);
qspSavedVarsGroups[groupInd].Vars[count].Name = varName;
qspSavedVarsGroups[groupInd].VarsCount = ++count;
}
if (!commaPos) break;
curPos.Str = commaPos + QSP_STATIC_LEN(QSP_COMMA);
qspSkipSpaces(&curPos);
if (qspIsEmpty(curPos))
{
qspSetError(QSP_ERR_SYNTAX);
return;
}
}
if (eqPos)
{
oldRefreshCount = qspRefreshCount;
v = qspExprValue(qspStringFromPair(eqPos + QSP_STATIC_LEN(QSP_EQUAL), s.End));
if (qspRefreshCount != oldRefreshCount || qspErrorNum)
return;
varName = qspDelSpc(qspStringFromPair(s.Str, eqPos));
qspSetVarValue(varName, &v, QSP_EQUAL[0]);
if (v.IsStr) qspFreeString(QSP_STR(v));
}
}
QSP_BOOL qspStatementCopyArr(QSPVariant *args, int count, QSPString *jumpTo, int extArg)
{
int start, num;
QSPVar *dest, *src;
if (!(dest = qspVarReferenceWithType(QSP_STR(args[0]), QSP_TRUE, 0))) return QSP_FALSE;
if (!(src = qspVarReferenceWithType(QSP_STR(args[1]), QSP_FALSE, 0))) return QSP_FALSE;
if (dest != src)
{
start = (count >= 3 ? QSP_NUM(args[2]) : 0);
num = (count == 4 ? QSP_NUM(args[3]) : src->ValsCount);
qspEmptyVar(dest);
qspCopyVar(dest, src, start, num);
}
return QSP_FALSE;
}
QSP_BOOL qspStatementKillVar(QSPVariant *args, int count, QSPString *jumpTo, int extArg)
{
if (count == 1)
qspRemoveArray(QSP_STR(args[0]));
else if (count == 2)
qspRemoveArrayItem(QSP_STR(args[0]), QSP_NUM(args[1]));
else
qspClearVars(QSP_FALSE);
return QSP_FALSE;
}
Something went wrong with that request. Please try again.