You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sip-tester/variables.cpp

369 lines
8.1 KiB

/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Authors : Benjamin GAUTHIER - 24 Mar 2004
* Joseph BANINO
* Olivier JACQUES
* Richard GAYRAUD
* From Hewlett Packard Company.
*
*/
#include "sipp.hpp"
/*
__________________________________________________________________________
C L A S S C C a l l V a r i a b l e
__________________________________________________________________________
*/
bool CCallVariable::isSet()
{
if (M_type == E_VT_REGEXP) {
if(M_nbOfMatchingValue >= 1)
return(true);
else
return(false);
} else if (M_type == E_VT_BOOL) {
return M_bool;
} else if (M_type == E_VT_DOUBLE) {
return M_double;
}
return (M_type != E_VT_UNDEFINED);
}
bool CCallVariable::isDouble()
{
return (M_type == E_VT_DOUBLE);
}
bool CCallVariable::isBool()
{
return (M_type == E_VT_BOOL);
}
bool CCallVariable::isRegExp()
{
return (M_type == E_VT_REGEXP);
}
bool CCallVariable::isString()
{
return (M_type == E_VT_STRING);
}
// WARNING : setMatchingValue does't allocate the memory for the matching value
// but the destructor free the memory
void CCallVariable::setMatchingValue(char* P_matchingVal)
{
M_type = E_VT_REGEXP;
if(M_matchingValue != NULL) {
delete [] M_matchingValue;
}
M_matchingValue = P_matchingVal;
M_nbOfMatchingValue++;
}
char* CCallVariable::getMatchingValue()
{
if (M_type != E_VT_REGEXP) {
return NULL;
}
return(M_matchingValue);
}
void CCallVariable::setDouble(double val)
{
M_type = E_VT_DOUBLE;
M_double = val;
}
double CCallVariable::getDouble()
{
if (M_type != E_VT_DOUBLE) {
return 0.0;
}
return(M_double);
}
void CCallVariable::setString(char *P_val)
{
M_type = E_VT_STRING;
free(M_stringValue);
M_stringValue = P_val;
}
char *CCallVariable::getString()
{
if (M_type == E_VT_STRING) {
return(M_stringValue);
} else if (M_type == E_VT_REGEXP && M_matchingValue) {
return(M_matchingValue);
} else {
return "";
}
}
/* Convert this variable to a double. Returns true on success, false on failure. */
bool CCallVariable::toDouble(double *newValue)
{
char *p;
switch(M_type) {
case E_VT_REGEXP:
if(M_nbOfMatchingValue < 1) {
return false;
}
*newValue = strtod(M_matchingValue, &p);
if (*p) {
return false;
}
break;
case E_VT_STRING:
*newValue = strtod(M_stringValue, &p);
if (*p) {
return false;
}
break;
case E_VT_DOUBLE:
*newValue = getDouble();
break;
case E_VT_BOOL:
*newValue = (double)getBool();
break;
default:
return false;
}
return true;
}
void CCallVariable::setBool(bool val)
{
M_type = E_VT_BOOL;
M_bool = val;
}
bool CCallVariable::getBool()
{
if (M_type != E_VT_BOOL) {
return false;
}
return(M_bool);
}
// Constuctor and destructor
CCallVariable::CCallVariable()
{
M_matchingValue = NULL;
M_stringValue = NULL;
M_nbOfMatchingValue = 0;
M_type = E_VT_UNDEFINED;
}
CCallVariable::~CCallVariable()
{
if(M_matchingValue != NULL) {
delete [] M_matchingValue;
}
M_matchingValue = NULL;
free(M_stringValue);
}
#define LEVEL_BITS 8
VariableTable::VariableTable(VariableTable *parent, int size) {
if (parent) {
level = parent->level + 1;
assert(level < (1 << LEVEL_BITS));
this->parent = parent->getTable();
} else {
level = 0;
this->parent = NULL;
}
count = 1;
this->size = size;
if (size == 0) {
variableTable = NULL;
return;
}
variableTable = (CCallVariable **)malloc(size * sizeof(CCallVariable *));
if (!variableTable) {
ERROR("Could not allocate variable table!");
}
for (int i = 0; i < size; i++) {
variableTable[i] = new CCallVariable();
if (variableTable[i] == NULL) {
ERROR ("Call variable allocation failed");
}
}
}
VariableTable::VariableTable(AllocVariableTable *src) {
count = 1;
this->level = src->level;
if (src->parent) {
this->parent = src->parent->getTable();
} else {
this->parent = NULL;
}
if (level > 0) {
assert(this->parent);
}
this->size = src->size;
if (size == 0) {
variableTable = NULL;
return;
}
variableTable = (CCallVariable **)malloc(size * sizeof(CCallVariable *));
if (!variableTable) {
ERROR("Could not allocate variable table!");
}
for (int i = 0; i < size; i++) {
variableTable[i] = new CCallVariable();
if (variableTable[i] == NULL) {
ERROR ("Call variable allocation failed");
}
}
}
void VariableTable::expand(int size) {
assert(size > this->size);
if (size == this->size) {
return;
}
variableTable = (CCallVariable **)realloc(variableTable, size * sizeof(CCallVariable *));
if (!variableTable) {
ERROR("Could not expand variable table!");
}
for (int i = this->size; i < size; i++) {
variableTable[i] = new CCallVariable();
if (variableTable[i] == NULL) {
ERROR ("Call variable allocation failed");
}
}
this->size = size;
}
VariableTable::~VariableTable() {
if (parent) {
parent->putTable();
}
for (int i = 0; i < size; i++) {
delete variableTable[i];
}
free(variableTable);
}
VariableTable *VariableTable::getTable() {
count++;
return this;
}
void VariableTable::putTable() {
if (--count == 0) {
delete this;
}
}
CCallVariable *VariableTable::getVar(int i) {
int thisLevel = i & ((1 << LEVEL_BITS) - 1);
assert(thisLevel <= level);
if (thisLevel == level) {
i = i >> LEVEL_BITS;
assert(i > 0);
assert(i <= size );
return variableTable[i - 1];
}
assert(parent);
return parent->getVar(i);
}
AllocVariableTable::AllocVariableTable(AllocVariableTable *av_parent) : VariableTable((VariableTable *)av_parent, 0) {
this->av_parent = av_parent;
}
AllocVariableTable::~AllocVariableTable() {
clear_str_int(variableMap);
clear_int_str(variableRevMap);
clear_int_int(variableReferences);
}
int AllocVariableTable::find(const char *varName, bool allocate) {
/* If this variable has already been used, then we have nothing to do. */
str_int_map::iterator var_it = variableMap.find(varName);
if (var_it != variableMap.end()) {
variableReferences[var_it->second]++;
return var_it->second;
}
if (av_parent) {
int ret = av_parent->find(varName, false);
if (ret > 0) {
return ret;
}
}
if (allocate) {
int varNum = size + 1;
expand(varNum);
varNum = (varNum << LEVEL_BITS) | level;
variableMap[varName] = varNum;
variableReferences[varNum] = 1;
variableRevMap[varNum] = strdup(varName);
return varNum;
}
return -1;
}
char *AllocVariableTable::getName(int i) {
int thisLevel = i & ((1 << LEVEL_BITS) - 1);
assert(thisLevel <= level);
if (thisLevel == level) {
return variableRevMap[i];
}
assert(av_parent);
return av_parent->getName(i);
}
void AllocVariableTable::dump() {
if (av_parent) {
av_parent->dump();
}
WARNING("%d level %d variables:", variableMap.size(), level);
for (str_int_map::iterator i = variableMap.begin(); i != variableMap.end(); i++) {
WARNING("%s", i->first.c_str());
}
}
void AllocVariableTable::validate() {
for (str_int_map::iterator var_it = variableMap.begin(); var_it != variableMap.end(); var_it++) {
if (variableReferences[var_it->second] < 2) {
const char *varName = var_it->first.c_str();
int varRef = variableReferences[var_it->second];
ERROR("Variable $%s is referenced %d times!\n", varName, varRef);
}
}
if (av_parent) {
av_parent->validate();
}
}