2014-09-14 22:28:23 +08:00
|
|
|
/**
|
|
|
|
@file variable.cpp
|
|
|
|
|
|
|
|
@brief Implements the variable class.
|
|
|
|
*/
|
|
|
|
|
2013-11-15 04:55:18 +08:00
|
|
|
#include "variable.h"
|
2014-12-09 08:29:08 +08:00
|
|
|
#include "threading.h"
|
2013-11-15 04:55:18 +08:00
|
|
|
|
2014-12-26 19:35:19 +08:00
|
|
|
/**
|
|
|
|
\brief The container that stores the variables.
|
|
|
|
*/
|
2014-08-07 00:05:27 +08:00
|
|
|
static VariableMap variables;
|
2013-11-15 04:55:18 +08:00
|
|
|
|
2014-12-26 19:35:19 +08:00
|
|
|
/**
|
|
|
|
\brief Sets a variable with a value.
|
|
|
|
\param [in,out] var The variable to set the value of. The previous value will be freed. Cannot be null.
|
|
|
|
\param [in] value The new value. Cannot be null.
|
|
|
|
*/
|
2014-03-27 05:52:41 +08:00
|
|
|
static void varsetvalue(VAR* var, VAR_VALUE* value)
|
|
|
|
{
|
2015-03-26 10:17:52 +08:00
|
|
|
// VAR_STRING needs to be freed before destroying it
|
|
|
|
if(var->value.type == VAR_STRING)
|
2014-03-27 05:52:41 +08:00
|
|
|
{
|
2014-03-27 06:42:11 +08:00
|
|
|
var->value.u.data->clear();
|
|
|
|
delete var->value.u.data;
|
2014-03-27 05:52:41 +08:00
|
|
|
}
|
2015-03-26 10:17:52 +08:00
|
|
|
|
|
|
|
// Replace all information in the struct
|
2014-03-27 05:52:41 +08:00
|
|
|
memcpy(&var->value, value, sizeof(VAR_VALUE));
|
|
|
|
}
|
|
|
|
|
2014-12-26 19:35:19 +08:00
|
|
|
/**
|
|
|
|
\brief Sets a variable by name.
|
|
|
|
\param name The name of the variable. Cannot be null.
|
|
|
|
\param value The new value. Cannot be null.
|
|
|
|
\param setreadonly true to set read-only variables (like $hProcess etc.).
|
|
|
|
\return true if the variable was set correctly, false otherwise.
|
|
|
|
*/
|
2014-03-27 06:42:11 +08:00
|
|
|
static bool varset(const char* name, VAR_VALUE* value, bool setreadonly)
|
|
|
|
{
|
2015-03-23 09:14:18 +08:00
|
|
|
EXCLUSIVE_ACQUIRE(LockVariables);
|
|
|
|
|
2014-11-15 21:56:16 +08:00
|
|
|
String name_;
|
2014-08-07 00:05:27 +08:00
|
|
|
if(*name != '$')
|
|
|
|
name_ = "$";
|
|
|
|
name_ += name;
|
|
|
|
VariableMap::iterator found = variables.find(name_);
|
2015-03-23 09:14:18 +08:00
|
|
|
if(found == variables.end()) //not found
|
2014-03-27 06:42:11 +08:00
|
|
|
return false;
|
2014-08-07 04:47:19 +08:00
|
|
|
if(found->second.alias.length())
|
2015-03-23 09:14:18 +08:00
|
|
|
{
|
|
|
|
// Release the lock (potential deadlock here)
|
|
|
|
EXCLUSIVE_RELEASE();
|
|
|
|
|
2014-08-07 04:47:19 +08:00
|
|
|
return varset(found->second.alias.c_str(), value, setreadonly);
|
2015-03-23 09:14:18 +08:00
|
|
|
}
|
|
|
|
|
2014-08-07 00:05:27 +08:00
|
|
|
if(!setreadonly && (found->second.type == VAR_READONLY || found->second.type == VAR_HIDDEN))
|
2014-03-27 06:42:11 +08:00
|
|
|
return false;
|
2014-08-07 00:05:27 +08:00
|
|
|
varsetvalue(&found->second, value);
|
2014-03-27 06:42:11 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-12-26 19:35:19 +08:00
|
|
|
/**
|
|
|
|
\brief Initializes various default variables.
|
|
|
|
*/
|
2013-11-15 04:55:18 +08:00
|
|
|
void varinit()
|
|
|
|
{
|
2014-12-09 08:29:08 +08:00
|
|
|
varfree();
|
2015-03-26 10:17:52 +08:00
|
|
|
|
|
|
|
// General variables
|
2014-08-07 04:47:19 +08:00
|
|
|
varnew("$result\1$res", 0, VAR_SYSTEM);
|
|
|
|
varnew("$result1\1$res1", 0, VAR_SYSTEM);
|
|
|
|
varnew("$result2\1$res2", 0, VAR_SYSTEM);
|
|
|
|
varnew("$result3\1$res3", 0, VAR_SYSTEM);
|
|
|
|
varnew("$result4\1$res4", 0, VAR_SYSTEM);
|
2015-03-26 10:17:52 +08:00
|
|
|
|
|
|
|
// InitDebug variables
|
|
|
|
varnew("$hProcess\1$hp", 0, VAR_READONLY); // Process handle
|
|
|
|
varnew("$pid", 0, VAR_READONLY); // Process ID
|
|
|
|
|
|
|
|
// Hidden variables
|
2013-11-15 04:55:18 +08:00
|
|
|
varnew("$ans\1$an", 0, VAR_HIDDEN);
|
2015-03-26 10:17:52 +08:00
|
|
|
|
|
|
|
// Read-only variables
|
|
|
|
varnew("$lastalloc", 0, VAR_READONLY); // Last memory allocation
|
|
|
|
varnew("$_EZ_FLAG", 0, VAR_READONLY); // Equal/zero flag for internal use (1=equal, 0=unequal)
|
|
|
|
varnew("$_BS_FLAG", 0, VAR_READONLY); // Bigger/smaller flag for internal use (1=bigger, 0=smaller)
|
2013-11-15 04:55:18 +08:00
|
|
|
}
|
|
|
|
|
2014-12-26 19:35:19 +08:00
|
|
|
/**
|
|
|
|
\brief Clears all variables.
|
|
|
|
*/
|
2013-11-17 20:10:29 +08:00
|
|
|
void varfree()
|
|
|
|
{
|
2015-04-05 09:49:09 +08:00
|
|
|
EXCLUSIVE_ACQUIRE(LockVariables);
|
2015-03-27 06:58:48 +08:00
|
|
|
|
2015-04-05 09:49:09 +08:00
|
|
|
// Each variable must be deleted manually; strings especially
|
|
|
|
// because there are sub-allocations
|
|
|
|
VAR_VALUE emptyValue;
|
2015-03-27 06:58:48 +08:00
|
|
|
|
2015-04-05 09:49:09 +08:00
|
|
|
for (auto& itr : variables)
|
|
|
|
varsetvalue(&itr.second, &emptyValue);
|
2015-03-27 06:58:48 +08:00
|
|
|
|
2015-04-05 09:49:09 +08:00
|
|
|
// Now clear all vector elements
|
2014-08-07 00:05:27 +08:00
|
|
|
variables.clear();
|
2013-11-17 20:10:29 +08:00
|
|
|
}
|
|
|
|
|
2014-12-26 19:35:19 +08:00
|
|
|
/**
|
|
|
|
\brief Creates a new variable.
|
|
|
|
\param name The name of the variable. You can specify alias names by separating the names by '\1'. Cannot be null.
|
|
|
|
\param value The new variable value.
|
|
|
|
\param type The variable type.
|
|
|
|
\return true if the new variables was created and set successfully, false otherwise.
|
|
|
|
*/
|
2014-08-07 00:05:27 +08:00
|
|
|
bool varnew(const char* name, uint value, VAR_TYPE type)
|
2013-11-15 04:55:18 +08:00
|
|
|
{
|
2014-08-07 00:05:27 +08:00
|
|
|
if(!name)
|
2013-11-15 04:55:18 +08:00
|
|
|
return false;
|
2015-03-23 09:14:18 +08:00
|
|
|
|
|
|
|
CriticalSectionLocker locker(LockVariables);
|
|
|
|
|
2014-11-15 21:56:16 +08:00
|
|
|
std::vector<String> names = StringUtils::Split(name, '\1');
|
|
|
|
String firstName;
|
2014-08-07 04:47:19 +08:00
|
|
|
for(int i = 0; i < (int)names.size(); i++)
|
|
|
|
{
|
2014-11-15 21:56:16 +08:00
|
|
|
String name_;
|
2014-08-07 04:47:19 +08:00
|
|
|
name = names.at(i).c_str();
|
|
|
|
if(*name != '$')
|
|
|
|
name_ = "$";
|
|
|
|
name_ += name;
|
|
|
|
if(!i)
|
|
|
|
firstName = name;
|
|
|
|
if(variables.find(name_) != variables.end()) //found
|
|
|
|
return false;
|
|
|
|
VAR var;
|
|
|
|
var.name = name_;
|
|
|
|
if(i)
|
|
|
|
var.alias = firstName;
|
|
|
|
var.type = type;
|
2014-08-07 05:13:21 +08:00
|
|
|
var.value.size = sizeof(uint);
|
|
|
|
var.value.type = VAR_UINT;
|
|
|
|
var.value.u.value = value;
|
2014-08-07 04:47:19 +08:00
|
|
|
variables.insert(std::make_pair(name_, var));
|
|
|
|
}
|
2013-11-15 04:55:18 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-12-26 19:35:19 +08:00
|
|
|
/**
|
|
|
|
\brief Gets a variable value.
|
|
|
|
\param name The name of the variable.
|
|
|
|
\param [out] value This function can get the variable value. If this value is null, it is ignored.
|
|
|
|
\param [out] size This function can get the variable size. If this value is null, it is ignored.
|
|
|
|
\param [out] type This function can get the variable type. If this value is null, it is ignored.
|
|
|
|
\return true if the variable was found and the optional values were retrieved successfully, false otherwise.
|
|
|
|
*/
|
2014-03-27 06:42:11 +08:00
|
|
|
static bool varget(const char* name, VAR_VALUE* value, int* size, VAR_TYPE* type)
|
2013-11-15 04:55:18 +08:00
|
|
|
{
|
2015-03-26 10:17:52 +08:00
|
|
|
SHARED_ACQUIRE(LockVariables);
|
2015-03-23 09:14:18 +08:00
|
|
|
|
2014-11-15 21:56:16 +08:00
|
|
|
String name_;
|
2014-08-07 00:05:27 +08:00
|
|
|
if(*name != '$')
|
|
|
|
name_ = "$";
|
|
|
|
name_ += name;
|
|
|
|
VariableMap::iterator found = variables.find(name_);
|
|
|
|
if(found == variables.end()) //not found
|
2013-11-15 04:55:18 +08:00
|
|
|
return false;
|
2014-08-07 04:47:19 +08:00
|
|
|
if(found->second.alias.length())
|
2015-03-23 09:14:18 +08:00
|
|
|
{
|
|
|
|
// Release the lock (potential deadlock here)
|
2015-03-26 10:17:52 +08:00
|
|
|
SHARED_RELEASE();
|
2015-03-23 09:14:18 +08:00
|
|
|
|
2014-08-07 04:47:19 +08:00
|
|
|
return varget(found->second.alias.c_str(), value, size, type);
|
2015-03-23 09:14:18 +08:00
|
|
|
}
|
2014-08-07 04:47:19 +08:00
|
|
|
if(type)
|
|
|
|
*type = found->second.type;
|
|
|
|
if(size)
|
|
|
|
*size = found->second.value.size;
|
|
|
|
if(value)
|
|
|
|
*value = found->second.value;
|
2014-03-27 06:42:11 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-12-26 19:35:19 +08:00
|
|
|
/**
|
|
|
|
\brief Gets a variable value.
|
|
|
|
\param name The name of the variable.
|
|
|
|
\param [out] value This function can get the variable value. If this value is null, it is ignored.
|
|
|
|
\param [out] size This function can get the variable size. If this value is null, it is ignored.
|
|
|
|
\param [out] type This function can get the variable type. If this value is null, it is ignored.
|
|
|
|
\return true if the variable was found and the optional values were retrieved successfully, false otherwise.
|
|
|
|
*/
|
2014-03-27 06:42:11 +08:00
|
|
|
bool varget(const char* name, uint* value, int* size, VAR_TYPE* type)
|
|
|
|
{
|
|
|
|
VAR_VALUE varvalue;
|
|
|
|
int varsize;
|
|
|
|
VAR_TYPE vartype;
|
2014-08-05 07:06:59 +08:00
|
|
|
if(!varget(name, &varvalue, &varsize, &vartype) or varvalue.type != VAR_UINT)
|
2014-03-27 05:52:41 +08:00
|
|
|
return false;
|
|
|
|
if(size)
|
2014-08-05 07:06:59 +08:00
|
|
|
*size = varsize;
|
2014-03-27 06:42:11 +08:00
|
|
|
if(!value && size)
|
|
|
|
return true; //variable was valid, just get the size
|
|
|
|
if(type)
|
2014-08-05 07:06:59 +08:00
|
|
|
*type = vartype;
|
2014-09-01 05:21:31 +08:00
|
|
|
if(value)
|
|
|
|
*value = varvalue.u.value;
|
2013-11-15 04:55:18 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-12-26 19:35:19 +08:00
|
|
|
/**
|
|
|
|
\brief Gets a variable value.
|
|
|
|
\param name The name of the variable.
|
|
|
|
\param [out] string This function can get the variable value. If this value is null, it is ignored.
|
|
|
|
\param [out] size This function can get the variable size. If this value is null, it is ignored.
|
|
|
|
\param [out] type This function can get the variable type. If this value is null, it is ignored.
|
|
|
|
\return true if the variable was found and the optional values were retrieved successfully, false otherwise.
|
|
|
|
*/
|
2014-03-27 06:42:11 +08:00
|
|
|
bool varget(const char* name, char* string, int* size, VAR_TYPE* type)
|
2013-11-15 04:55:18 +08:00
|
|
|
{
|
2014-03-27 06:42:11 +08:00
|
|
|
VAR_VALUE varvalue;
|
|
|
|
int varsize;
|
|
|
|
VAR_TYPE vartype;
|
2014-08-05 07:06:59 +08:00
|
|
|
if(!varget(name, &varvalue, &varsize, &vartype) or varvalue.type != VAR_STRING)
|
2013-11-15 04:55:18 +08:00
|
|
|
return false;
|
2014-03-27 06:42:11 +08:00
|
|
|
if(size)
|
2014-08-05 07:06:59 +08:00
|
|
|
*size = varsize;
|
2014-03-27 06:42:11 +08:00
|
|
|
if(!string && size)
|
|
|
|
return true; //variable was valid, just get the size
|
|
|
|
if(type)
|
2014-08-05 07:06:59 +08:00
|
|
|
*type = vartype;
|
2014-09-01 05:21:31 +08:00
|
|
|
if(string)
|
2015-04-03 09:37:04 +08:00
|
|
|
memcpy(string, varvalue.u.data->data(), varsize);
|
2013-11-15 04:55:18 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-12-26 19:35:19 +08:00
|
|
|
/**
|
|
|
|
\brief Sets a variable by name.
|
|
|
|
\param name The name of the variable. Cannot be null.
|
|
|
|
\param value The new value.
|
|
|
|
\param setreadonly true to set read-only variables (like $hProcess etc.).
|
|
|
|
\return true if the variable was set successfully, false otherwise.
|
|
|
|
*/
|
2014-03-27 05:52:41 +08:00
|
|
|
bool varset(const char* name, uint value, bool setreadonly)
|
2013-11-15 04:55:18 +08:00
|
|
|
{
|
2014-03-27 05:52:41 +08:00
|
|
|
VAR_VALUE varvalue;
|
2014-08-05 07:06:59 +08:00
|
|
|
varvalue.size = sizeof(uint);
|
|
|
|
varvalue.type = VAR_UINT;
|
|
|
|
varvalue.u.value = value;
|
2014-08-07 04:47:19 +08:00
|
|
|
return varset(name, &varvalue, setreadonly);
|
2014-03-27 05:52:41 +08:00
|
|
|
}
|
|
|
|
|
2014-12-26 19:35:19 +08:00
|
|
|
/**
|
|
|
|
\brief Sets a variable by name.
|
|
|
|
\param name The name of the variable. Cannot be null.
|
|
|
|
\param string The new value. Cannot be null.
|
|
|
|
\param setreadonly true to set read-only variables (like $hProcess etc.).
|
|
|
|
\return true if the variable was set successfully, false otherwise.
|
|
|
|
*/
|
2014-03-27 06:42:11 +08:00
|
|
|
bool varset(const char* name, const char* string, bool setreadonly)
|
2014-03-27 05:52:41 +08:00
|
|
|
{
|
|
|
|
VAR_VALUE varvalue;
|
2014-08-05 07:06:59 +08:00
|
|
|
int size = (int)strlen(string);
|
|
|
|
varvalue.size = size;
|
|
|
|
varvalue.type = VAR_STRING;
|
|
|
|
varvalue.u.data = new std::vector<unsigned char>;
|
2014-03-27 05:52:41 +08:00
|
|
|
varvalue.u.data->resize(size);
|
2014-03-27 06:42:11 +08:00
|
|
|
memcpy(&varvalue.u.data->front(), string, size);
|
|
|
|
if(!varset(name, &varvalue, setreadonly))
|
|
|
|
{
|
|
|
|
varvalue.u.data->clear();
|
|
|
|
delete varvalue.u.data;
|
|
|
|
return false;
|
|
|
|
}
|
2014-03-27 05:52:41 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-12-26 19:35:19 +08:00
|
|
|
/**
|
|
|
|
\brief Deletes a variable.
|
|
|
|
\param name The name of the variable to delete. Cannot be null.
|
|
|
|
\param delsystem true to allow deleting system variables.
|
|
|
|
\return true if the variable was deleted successfully, false otherwise.
|
|
|
|
*/
|
2014-03-27 05:52:41 +08:00
|
|
|
bool vardel(const char* name, bool delsystem)
|
|
|
|
{
|
2015-03-23 09:14:18 +08:00
|
|
|
EXCLUSIVE_ACQUIRE(LockVariables);
|
|
|
|
|
2014-11-15 21:56:16 +08:00
|
|
|
String name_;
|
2014-08-05 07:06:59 +08:00
|
|
|
if(*name != '$')
|
2014-08-07 00:05:27 +08:00
|
|
|
name_ = "$";
|
|
|
|
name_ += name;
|
|
|
|
VariableMap::iterator found = variables.find(name_);
|
|
|
|
if(found == variables.end()) //not found
|
2013-11-15 04:55:18 +08:00
|
|
|
return false;
|
2014-08-07 04:47:19 +08:00
|
|
|
if(found->second.alias.length())
|
2015-03-23 09:14:18 +08:00
|
|
|
{
|
|
|
|
// Release the lock (potential deadlock here)
|
|
|
|
EXCLUSIVE_RELEASE();
|
|
|
|
|
2014-08-07 04:47:19 +08:00
|
|
|
return vardel(found->second.alias.c_str(), delsystem);
|
2015-03-23 09:14:18 +08:00
|
|
|
}
|
|
|
|
|
2014-08-07 00:05:27 +08:00
|
|
|
if(!delsystem && found->second.type != VAR_USER)
|
2013-11-15 04:55:18 +08:00
|
|
|
return false;
|
2014-08-07 04:47:19 +08:00
|
|
|
found = variables.begin();
|
|
|
|
while(found != variables.end())
|
|
|
|
{
|
|
|
|
VariableMap::iterator del = found;
|
|
|
|
found++;
|
2014-11-15 21:56:16 +08:00
|
|
|
if(found->second.name == String(name))
|
2014-08-07 04:47:19 +08:00
|
|
|
variables.erase(del);
|
|
|
|
}
|
2013-11-15 04:55:18 +08:00
|
|
|
return true;
|
|
|
|
}
|
2014-03-27 06:42:11 +08:00
|
|
|
|
2014-12-26 19:35:19 +08:00
|
|
|
/**
|
|
|
|
\brief Gets a variable type.
|
|
|
|
\param name The name of the variable. Cannot be null.
|
|
|
|
\param [out] type This function can retrieve the variable type. If null it is ignored.
|
|
|
|
\param [out] valtype This function can retrieve the variable value type. If null it is ignored.
|
|
|
|
\return true if getting the type was successful, false otherwise.
|
|
|
|
*/
|
2014-06-30 23:43:59 +08:00
|
|
|
bool vargettype(const char* name, VAR_TYPE* type, VAR_VALUE_TYPE* valtype)
|
2014-03-27 06:42:11 +08:00
|
|
|
{
|
2015-03-26 10:17:52 +08:00
|
|
|
SHARED_ACQUIRE(LockVariables);
|
|
|
|
|
2014-11-15 21:56:16 +08:00
|
|
|
String name_;
|
2014-08-07 00:05:27 +08:00
|
|
|
if(*name != '$')
|
|
|
|
name_ = "$";
|
|
|
|
name_ += name;
|
|
|
|
VariableMap::iterator found = variables.find(name_);
|
|
|
|
if(found == variables.end()) //not found
|
2014-03-27 06:42:11 +08:00
|
|
|
return false;
|
2014-08-07 04:47:19 +08:00
|
|
|
if(found->second.alias.length())
|
|
|
|
return vargettype(found->second.alias.c_str(), type, valtype);
|
2014-06-30 23:43:59 +08:00
|
|
|
if(valtype)
|
2014-08-07 00:05:27 +08:00
|
|
|
*valtype = found->second.value.type;
|
2014-03-27 06:42:11 +08:00
|
|
|
if(type)
|
2014-08-07 00:05:27 +08:00
|
|
|
*type = found->second.type;
|
2014-03-27 06:42:11 +08:00
|
|
|
return true;
|
|
|
|
}
|
2014-08-07 00:05:27 +08:00
|
|
|
|
2014-12-26 19:35:19 +08:00
|
|
|
/**
|
|
|
|
\brief Enumerates all variables.
|
|
|
|
\param [in,out] entries A pointer to place the variables in. If null, \p cbsize will be filled to the number of bytes required.
|
|
|
|
\param [in,out] cbsize This function retrieves the number of bytes required to store all variables. Can be null if \p entries is not null.
|
|
|
|
\return true if it succeeds, false if it fails.
|
|
|
|
*/
|
2015-03-26 10:17:52 +08:00
|
|
|
bool varenum(VAR* List, size_t* Size)
|
2014-08-07 00:05:27 +08:00
|
|
|
{
|
2015-03-26 10:17:52 +08:00
|
|
|
// A list or size must be requested
|
|
|
|
if(!List && !Size)
|
2014-08-07 00:05:27 +08:00
|
|
|
return false;
|
2015-03-26 10:17:52 +08:00
|
|
|
|
|
|
|
SHARED_ACQUIRE(LockVariables);
|
|
|
|
|
|
|
|
if(Size)
|
2014-08-07 00:05:27 +08:00
|
|
|
{
|
2015-03-26 10:17:52 +08:00
|
|
|
// Size requested, so return it
|
|
|
|
*Size = variables.size() * sizeof(VAR);
|
|
|
|
|
|
|
|
if(!List)
|
|
|
|
return true;
|
2014-08-07 00:05:27 +08:00
|
|
|
}
|
2015-03-26 10:17:52 +08:00
|
|
|
|
|
|
|
// Fill out all list entries
|
|
|
|
for(auto & itr : variables)
|
|
|
|
{
|
|
|
|
*List = itr.second;
|
|
|
|
List++;
|
|
|
|
}
|
|
|
|
|
2014-08-07 00:05:27 +08:00
|
|
|
return true;
|
|
|
|
}
|