I am defining a custom std::streambuf class for use in file I/O. In this class, I am overloading the functions open, close, is_open, xsgetn, xsputn, overflow, underflow, and uflow. I then insert this buffer into an std::ifstream as follows (the same scenario holds for std::ofstream):
std::ifstream temp;
Filebuffer *buffer = new Filebuffer();
buffer->open(fileName.c_str(), std::ios_base::in | std::ios_base::binary);
temp.basic_ios<char>::rdbuf(buffer);
The implementation for Filebuffer (my custom class) is as follows:
std::streamsize
Filebuffer::xsputn(const char *s, std::streamsize n)
{
std::streamsize result = 0;
if(file && n)
{
for(;;)
{
size_t buffer_use = this->epptr() - this->pptr();
if(buffer_use > 0)
{
if(static_cast<int>(buffer_use) > n)
{
buffer_use = n;
}
std::char_traits<char>::copy(this->pptr(), s, buffer_use);
this->pbump(buffer_use);
result += buffer_use;
n -= buffer_use;
if(n == 0)
{
break;
}
s += buffer_use;
}
this->overflow(static_cast<int>(*s));
}
}
return result;
}
std::streamsize
Filebuffer::xsgetn(char *s, std::streamsize n)
{
std::streamsize result = 0;
if(file && n)
{
int ch; do
{
size_t buffer_use = this->egptr() - this->gptr();
if(buffer_use > 0)
{
if(static_cast<int>(buffer_use) > n)
{
buffer_use = n;
}
std::char_traits<char>::copy(s, this->gptr(), buffer_use);
this->gbump(buffer_use);
result += buffer_use;
n -= buffer_use;
if(n == 0)
{
break;
}
s += buffer_use;
}
ch = this->underflow();
} while(!(ch == std::char_traits<char>::eof()));
}
return result;
}
int
Filebuffer::underflow()
{
if(file)
{
nullify_put_area(); //clears write buffer
if(!buffer) //allocated in open()
{
int value = ungetc(fgetc(file), file);
if(value == EOF)
{
return std::char_traits<char>::eof();
}
return value;
}
char *begin = buffer;
char *end = buffer + bufferSize - 1; //bufferSize set to 4 KB
char *next = end;
if(this->gptr() < this->egptr())
{
size_t buffer_use = this->egptr() - this->gptr();
memmove(begin, next, buffer_use);
begin += buffer_use;
}
setg(begin, begin, begin);
size_t m = (bufferSize - 1 - (begin - this->eback()));
if(m > 0)
{
size_t status = fread(begin, 1, m, file);
if(status == 0)
{
return std::char_traits<char>::eof();
}
setg(this->eback(), this->gptr(), begin + status);
}
return static_cast<int>(*this->gptr());
}
return std::char_traits<char>::eof();
}
int
Filebuffer::uflow()
{
if(!file)
{
return std::char_traits<char>::eof();
}
int ch = underflow();
if(ch != std::char_traits<char>::eof())
{
if(buffer)
{
this->gbump(1);
}
else
{
fgetc(file);
}
}
return ch;
}
int
Filebuffer::overflow(int c)
{
if(!file)
{
return std::char_traits<char>::eof();
}
const char *begin = this->pbase();
char *next = this->pptr();
if(buffer)
{
setp(buffer, buffer + bufferSize - 1);
}
nullify_get_area(); //clears read buffer
char temp;
if(c == std::char_traits<char>::eof())
{
c = std::char_traits<char>::not_eof(std::char_traits<char>::eof());
}
else
{
if(!next)
{
begin = next = &temp;
}
assert(next == &temp || buffer <= next);
assert(next == &temp || next < buffer + bufferSize);
*next++ = static_cast<char>(c);
}
if(begin != next)
{
if(begin == &temp)
{
fputc(temp, file);
return c;
}
size_t n = next - begin;
size_t status = fwrite(begin, 1, n, file);
if(status != n)
{
return std::char_traits<char>::eof();
}
return c;
}
return std::char_traits<char>::eof();
}
Unfortunately, whenever I use (e.g.) temp >> readVar;, it does not use any of my overloaded functions - the call stack shows that the STL original implementations were called - and instead, simply reads in garbage. Per this question, I need to define overflow for ofstream (and presumably, underflow for ifstream), which I have done. Am I defining xsputn and xsgetn correctly? Why are my overloaded functions not being called?
It appears that trying to do this with std::ifstream will not work, and I need to change it std::istream. Once I make this change, the overloaded functions are called and everything works properly.
Here's the code :
The place where it crashed is marked with a comment(//////crash).
I don't know what results in the problem.
After I print the size of data got from file,It shows '1' means that the array should only contains 1 element. So it seems that there's no 'bad_allocate error' ...
Could you guys help me ? I would appreciate your kindly help very much. :)
#include<stdio.h>
#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<algorithm>
#include<string.h>
#include<type_traits>
using namespace std;
bool read_int(int& val,FILE*& fp)
{
if(fp == nullptr)
return false;
fread(&val,sizeof(int),1,fp);
return true;
}
bool write_int(int val,FILE*& fp)
{
if(fp == nullptr)
{
return false;
}
fwrite(&val,sizeof(int),1,fp);
return true;
}
struct SANOBJ
{
char path[128];
char nickname[40];
SANOBJ(const char* _p = nullptr,const char* _n = nullptr)
{
if(_p == nullptr || _n == nullptr)
*this = {};
int m = strlen(_p),n = strlen(_n);
if(m < 128) strcpy(path,_p);
if(n < 40) strcpy(nickname,_n);
}
~SANOBJ(){}
SANOBJ(const SANOBJ& other)
{
memcpy(path,other.path,sizeof(char) * 128);
memcpy(nickname,other.nickname,sizeof(char) * 40);
}
bool operator < (const SANOBJ& other) const
{
return string(path) < string(other.path);
}
bool operator == (const SANOBJ& other) const
{
return (strcmp(other.path,path) == 0);
}
};
template <typename source_type> //the 'source_type' type need to have the member 'int m_index'
class FrameQueue
{
public:
FrameQueue() //fill the 1st frame automatically
{
source_type new_node;
new_node.m_index = 0;
m_data.push_back(new_node);
}
FrameQueue(const FrameQueue& other)
{
m_data = other.m_data;
}
bool AddFrame(const source_type& other) // keeps an ascending order
{
int index = _binary_search(other);
if(index != -1)
{
return false;
}
m_data.insert(std::upper_bound(m_data.begin(),m_data.end(),other,
[](const source_type& a,const source_type& b)->bool const{return a.m_index < b.m_index;}
),other);
return true;
}
bool DeleteFrameByElemIndex(int elemIndex) //delete frame according to the index of frame in the queue
{
if(elemIndex < 0)
return false;
if(elemIndex >= m_data.size())
return false;
typename std::vector<source_type>::iterator it ;
it = m_data.begin() + elemIndex;
it = m_data.erase(it);
return true;
}
bool DeleteFrameByFrameIndex(int frameIndex)
{
source_type node = {};
node.m_index = frameIndex;
int index = _binary_search(node);
if(index == -1)
{
return false;
}
typename std::vector<source_type>::iterator it;
it = m_data.begin() + index;
it = m_data.erase(it);
return true;
}
bool Clear() // There would always be a single frame
{
source_type new_node = {};
new_node.m_index = 0;
m_data.clear();
m_data.push_back(new_node);
return true;
}
bool WriteFile(FILE*& fp)
{
if(fp == nullptr)
return false;
bool result = write_int(m_data.size(),fp);
if(result == false)
return false;
fwrite(&(m_data[0]),sizeof(source_type),m_data.size(),fp);
return true;
}
bool ReadFile(FILE*& fp)
{
if(fp == nullptr)
return false;
int data_size;
bool result = read_int(data_size,fp);
if(result == false)
return false;
if(data_size > 0)
{
m_data.resize(data_size);
fread(&(m_data[0]),sizeof(source_type),data_size,fp);
}
return true;
}
private:
int _binary_search(source_type target)
{
int l = 0,r = (int)m_data.size() - 1,mid;
while(l<=r)
{
mid = (l + r) / 2;
if(m_data[l].m_index == target.m_index)
{
return l;
}
if(m_data[r].m_index == target.m_index)
{
return r;
}
if(m_data[mid].m_index == target.m_index)
{
return mid;
}
if(m_data[mid].m_index > target.m_index)
{
r = mid - 1;
}
else
{
l = mid + 1;
}
}
return -1;
}
public:
vector<source_type> m_data;
};
template<typename source_type>
class UniqueSource
{
public:
UniqueSource(){}
~UniqueSource(){}
bool Add(const source_type& other)//return false when insert failed,otherwise return true
{
if(m_map_source_to_index.find(other) == m_map_source_to_index.end())
{
int map_size = m_map_source_to_index.size();
m_data.push_back(other);
m_map_source_to_index.insert(pair<source_type,int>(other,map_size));
m_result.push_back(map_size);
return true;
}
else
{
m_result.push_back(m_map_source_to_index[other]);
return true;
}
return false;
}
bool Delete(int elemIndex) // delete the elem by elem Index,If succeed ,return true,otherwise return false
{
if(elemIndex < 0)
return false;
if(elemIndex >= m_data.size())
return false;
typename std::map<source_type,int>::iterator mit;
typename std::vector<source_type>::iterator vit;
for(mit = m_map_source_to_index.begin();mit!=m_map_source_to_index.end();++mit)
{
m_map_source_to_index.erase(mit);
}
vit = m_data.begin() + elemIndex;
m_data.erase(vit);
return true;
}
bool Clear()
{
m_map_source_to_index.clear();
m_data.clear();
m_result.clear();
return true;
}
bool WriteFile(FILE*& fp)
{
if(fp == nullptr)
return false;
bool result = write_int(m_data.size(),fp);
if(result == false)
return false;
if(m_data.size() > 0)
fwrite(&(m_data[0]),sizeof(source_type),m_data.size(),fp);
result = write_int(m_result.size(),fp);
if(result == false)
return false;
if(m_result.size() > 0)
fwrite(&(m_result[0]),sizeof(int),m_result.size(),fp);
return true;
}
bool ReadFile(FILE*& fp)
{
if(fp == nullptr)
return false;
Clear();
int data_size;
read_int(data_size,fp);
if(data_size > 0)
{
printf("[%d]",data_size);
m_data.resize(data_size); /////////////////Crash!!!!!!!!!!!!
printf("Resize Ok\r\n");
fread(&(m_data[0]),sizeof(source_type),data_size,fp);
}
read_int(data_size,fp);
printf("[%d]",data_size);
if(data_size > 0)
{
m_result.resize(data_size);
fread(&(m_result[0]),sizeof(int),data_size,fp);
}
return true;
}
//private:
map<source_type,int> m_map_source_to_index;
vector<source_type> m_data;
vector<int> m_result; //the index I want
};
int main()
{
UniqueSource<SANOBJ> m;
SANOBJ t = {"123","456"};
m.Add(t);
printf("Added\r\n");
FILE* fp = nullptr;
fp = fopen("test.b","wb");
if(fp == nullptr)
{
printf("Failed...\r\n");
}
bool ret = false;
ret = m.WriteFile(fp);
if(ret)
{
printf("Writed!\r\n");
fclose(fp);
}
fp = fopen("test.b","rb");
if(fp == nullptr)
{
printf("Failed...\r\n");
}
ret = m.ReadFile(fp);
fclose(fp);
printf("Readed\r\n");
for(int i=0;i<m.m_data.size();i++)
printf("%s %s\r\n",m.m_data[i].path,m.m_data[i].nickname);
return 0;
}
*this = {} default-constructs a new SANOBJ instance and then assigns it to *this. This would normally be OK, but here you are calling it from the SANOBJ default constructor (making the logic being something like "to default-construct a SANOBJ, default-construct a SANOBJ and then assign its value to myself"), leading to infinite recursion and eventually a stack overflow.
Sidenote: The copy constructor is not needed.
Yes. The problem is is with *this = {}
If I were you, I'd rewrite SANOBJ constructor like this (this is a rough code and you may need to slightly modify it if you wish)
SANOBJ(const char* _p = nullptr,const char* _n = nullptr)
{
if (( _p != nullptr ) && ((strlen(_p) < 128)))
strcpy(path,_p);
if (( _n != nullptr ) && ((strlen(_n) < 40)))
strcpy(nickname,_n);
}
It'll resolve the problem.
Naturally, I don't play with *this (not this).
If you want to be sure that the member variables are empty (char path[128] and char nickname[40])
set at the beginning of the constructor something like:
path[0] = '\0';
nickname[0] = '\0';
Or use something like on constructor:
SANOBJ(const char* _p = nullptr,const char* _n = nullptr)
: path(), nickname()
{
}
But don't use *this= {}
I have gone through the guides given out here & http://cpptcl.sourceforge.net/doc/compiling.html Hence I have pretty much done the basic stuffs.
Here's the code for Hello.cc given in the guide present in C++/Tcl:
#include "cpptcl.h"
#include <iostream>
using namespace std;
void hello()
{
cout << "Hello C++/Tcl!" << endl;
}
CPPTCL_MODULE(Mymodule, i)
{
i.def("hello", hello);
}
According to the guide, we need cpptcl.h & cpptcl.cc & few other files in details/ directory which I have included.
While building the code, it's giving me the following error:
1>Compiling...
1>cpptcl.cc
cpptcl.cc(35) : warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)
cpptcl.cc(325) : error C2039: 'what' : is not a member of 'boost::exception'
1> c:\program files\boost\boost_1_44_0\boost\exception\exception.hpp(194) : see declaration of 'boost::exception'
1>cpptcl.cc(366) : error C2872: 'exception' : ambiguous symbol
1> could be 'c:\program files\boost\boost_1_44_0\boost\exception\exception.hpp(194) : boost::exception'
1> or 'c:\program files\microsoft visual studio 8\vc\include\exception(88) : std::exception'
1>cpptcl.cc(368) : error C2039: 'what' : is not a member of 'boost::exception'
1>c:\program files\boost\boost_1_44_0\boost\exception\exception.hpp(194) : see declaration of 'boost::exception'
1>3 error(s), 2 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
It's not able to resolve exception symbol. I am not sure whether the exception.hpp or the std::exception.
Below is the code for cpptcl.cc
//
// Copyright (C) 2004-2005, Maciej Sobczak
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
#include "cpptcl.h"
#include
#include
#include
#include
using namespace Tcl;
using namespace Tcl::details;
using namespace std;
using namespace boost;
result::result(Tcl_Interp *interp) : interp_(interp) {}
result::operator bool() const
{
Tcl_Obj *obj = Tcl_GetObjResult(interp_);
int val, cc;
cc = Tcl_GetBooleanFromObj(interp_, obj, &val);
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
return static_cast(val);
}
result::operator double() const
{
Tcl_Obj *obj = Tcl_GetObjResult(interp_);
double val;
int cc = Tcl_GetDoubleFromObj(interp_, obj, &val);
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
return val;
}
result::operator int() const
{
Tcl_Obj *obj = Tcl_GetObjResult(interp_);
int val, cc;
cc = Tcl_GetIntFromObj(interp_, obj, &val);
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
return val;
}
result::operator long() const
{
Tcl_Obj *obj = Tcl_GetObjResult(interp_);
long val;
int cc;
cc = Tcl_GetLongFromObj(interp_, obj, &val);
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
return val;
}
result::operator string() const
{
Tcl_Obj *obj = Tcl_GetObjResult(interp_);
return Tcl_GetString(obj);
}
result::operator object() const
{
return object(Tcl_GetObjResult(interp_));
}
void details::set_result(Tcl_Interp *interp, bool b)
{
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(b));
}
void details::set_result(Tcl_Interp *interp, int i)
{
Tcl_SetObjResult(interp, Tcl_NewIntObj(i));
}
void details::set_result(Tcl_Interp *interp, long i)
{
Tcl_SetObjResult(interp, Tcl_NewLongObj(i));
}
void details::set_result(Tcl_Interp *interp, double d)
{
Tcl_SetObjResult(interp, Tcl_NewDoubleObj(d));
}
void details::set_result(Tcl_Interp *interp, string const &s)
{
Tcl_SetObjResult(interp,
Tcl_NewStringObj(s.data(), static_cast(s.size())));
}
void details::set_result(Tcl_Interp *interp, void *p)
{
ostringstream ss;
ss (s.size())));
}
void details::set_result(Tcl_Interp *interp, object const &o)
{
Tcl_SetObjResult(interp, o.get_object());
}
void details::check_params_no(int objc, int required)
{
if (objc > callback_interp_map;
typedef map callback_map;
callback_map callbacks;
callback_map constructors;
// map of call policies
typedef map policies_interp_map;
typedef map policies_map;
policies_map call_policies;
// map of object handlers
typedef map > class_interp_map;
typedef map class_handlers_map;
class_handlers_map class_handlers;
// helper for finding call policies - returns true when found
bool find_policies(Tcl_Interp *interp, string const &cmdName,
policies_interp_map::iterator &piti)
{
policies_map::iterator pit = call_policies.find(interp);
if (pit == call_policies.end())
{
return false;
}
piti = pit->second.find(cmdName);
return piti != pit->second.end();
}
extern "C"
int object_handler(ClientData cd, Tcl_Interp *interp,
int objc, Tcl_Obj * CONST objv[]);
// helper function for post-processing call policies
// for both free functions (isMethod == false)
// and class methods (isMethod == true)
void post_process_policies(Tcl_Interp *interp, policies &pol,
Tcl_Obj * CONST objv[], bool isMethod)
{
// check if it is a factory
if (!pol.factory_.empty())
{
class_handlers_map::iterator it = class_handlers.find(interp);
if (it == class_handlers.end())
{
throw tcl_error(
"Factory was registered for unknown class.");
}
class_interp_map::iterator oit = it->second.find(pol.factory_);
if (oit == it->second.end())
{
throw tcl_error(
"Factory was registered for unknown class.");
}
class_handler_base *chb = oit->second.get();
// register a new command for the object returned
// by this factory function
// if everything went OK, the result is the address of the
// new object in the 'pXXX' form
// - the new command will be created with this name
Tcl_CreateObjCommand(interp,
Tcl_GetString(Tcl_GetObjResult(interp)),
object_handler, static_cast(chb), 0);
}
// process all declared sinks
// - unregister all object commands that envelopes the pointers
for (vector::iterator s = pol.sinks_.begin();
s != pol.sinks_.end(); ++s)
{
if (isMethod == false)
{
// example: if there is a declared sink at parameter 3,
// and the Tcl command was:
// % fun par1 par2 PAR3 par4
// then the index 3 correctly points into the objv array
int index = *s;
Tcl_DeleteCommand(interp, Tcl_GetString(objv[index]));
}
else
{
// example: if there is a declared sink at parameter 3,
// and the Tcl command was:
// % $p method par1 par2 PAR3 par4
// then the index 3 needs to be incremented
// in order correctly point into the 4th index of objv array
int index = *s + 1;
Tcl_DeleteCommand(interp, Tcl_GetString(objv[index]));
}
}
}
// actual functions handling various callbacks
// generic callback handler
extern "C"
int callback_handler(ClientData cd, Tcl_Interp *interp,
int objc, Tcl_Obj * CONST objv[])
{
callback_map::iterator it = callbacks.find(interp);
if (it == callbacks.end())
{
Tcl_SetResult(interp,
"Trying to invoke non-existent callback (wrong interpreter?)",
TCL_STATIC);
return TCL_ERROR;
}
string cmdName(Tcl_GetString(objv[0]));
callback_interp_map::iterator iti = it->second.find(cmdName);
if (iti == it->second.end())
{
Tcl_SetResult(interp,
"Trying to invoke non-existent callback (wrong cmd name?)",
TCL_STATIC);
return TCL_ERROR;
}
policies_map::iterator pit = call_policies.find(interp);
if (pit == call_policies.end())
{
Tcl_SetResult(interp,
"Trying to invoke callback with no known policies",
TCL_STATIC);
return TCL_ERROR;
}
policies_interp_map::iterator piti;
if (find_policies(interp, cmdName, piti) == false)
{
Tcl_SetResult(interp,
"Trying to invoke callback with no known policies",
TCL_STATIC);
return TCL_ERROR;
}
policies &pol = piti->second;
try
{
iti->second->invoke(interp, objc, objv, pol);
post_process_policies(interp, pol, objv, false);
}
catch (boost::exception const &e)
{
Tcl_SetResult(interp, const_cast(e.what()), TCL_VOLATILE);
return TCL_ERROR;
}
catch (...)
{
Tcl_SetResult(interp, "Unknown error.", TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
}
// generic "object" command handler
extern "C"
int object_handler(ClientData cd, Tcl_Interp *interp,
int objc, Tcl_Obj * CONST objv[])
{
// here, client data points to the singleton object
// which is responsible for managing commands for
// objects of a given type
class_handler_base *chb = reinterpret_cast(cd);
// the command name has the form 'pXXX' where XXX is the address
// of the "this" object
string const str(Tcl_GetString(objv[0]));
istringstream ss(str);
char dummy;
void *p;
ss >> dummy >> p;
try
{
string methodName(Tcl_GetString(objv[1]));
policies &pol = chb->get_policies(methodName);
chb->invoke(p, interp, objc, objv, pol);
post_process_policies(interp, pol, objv, true);
}
catch (exception const &e)
{
Tcl_SetResult(interp, const_cast(e.what()), TCL_VOLATILE);
return TCL_ERROR;
}
catch (...)
{
Tcl_SetResult(interp, "Unknown error.", TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
}
// generic "constructor" command
extern "C"
int constructor_handler(ClientData cd, Tcl_Interp *interp,
int objc, Tcl_Obj * CONST objv[])
{
// here, client data points to the singleton object
// which is responsible for managing commands for
// objects of a given type
class_handler_base *chb = reinterpret_cast(cd);
callback_map::iterator it = constructors.find(interp);
if (it == constructors.end())
{
Tcl_SetResult(interp,
"Trying to invoke non-existent callback (wrong interpreter?)",
TCL_STATIC);
return TCL_ERROR;
}
string className(Tcl_GetString(objv[0]));
callback_interp_map::iterator iti = it->second.find(className);
if (iti == it->second.end())
{
Tcl_SetResult(interp,
"Trying to invoke non-existent callback (wrong class name?)",
TCL_STATIC);
return TCL_ERROR;
}
policies_interp_map::iterator piti;
if (find_policies(interp, className, piti) == false)
{
Tcl_SetResult(interp,
"Trying to invoke callback with no known policies",
TCL_STATIC);
return TCL_ERROR;
}
policies &pol = piti->second;
try
{
iti->second->invoke(interp, objc, objv, pol);
// if everything went OK, the result is the address of the
// new object in the 'pXXX' form
// - we can create a new command with this name
Tcl_CreateObjCommand(interp,
Tcl_GetString(Tcl_GetObjResult(interp)),
object_handler, static_cast(chb), 0);
}
catch (std::exception const &e)
{
Tcl_SetResult(interp, const_cast(e.what()), TCL_VOLATILE);
return TCL_ERROR;
}
catch (...)
{
Tcl_SetResult(interp, "Unknown error.", TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
}
} // namespace anonymous
Tcl::details::no_init_type Tcl::no_init;
policies & policies::factory(string const &name)
{
factory_ = name;
return *this;
}
policies & policies::sink(int index)
{
sinks_.push_back(index);
return *this;
}
policies & policies::variadic()
{
variadic_ = true;
return *this;
}
policies Tcl::factory(string const &name)
{
return policies().factory(name);
}
policies Tcl::sink(int index)
{
return policies().sink(index);
}
policies Tcl::variadic()
{
return policies().variadic();
}
class_handler_base::class_handler_base()
{
// default policies for the -delete command
policies_["-delete"] = policies();
}
void class_handler_base::register_method(string const &name,
shared_ptr ocb, policies const &p)
{
methods_[name] = ocb;
policies_[name] = p;
}
policies & class_handler_base::get_policies(string const &name)
{
policies_map_type::iterator it = policies_.find(name);
if (it == policies_.end())
{
throw tcl_error("Trying to use non-existent policy: " + name);
}
return it->second;
}
object::object()
: interp_(0)
{
obj_ = Tcl_NewObj();
Tcl_IncrRefCount(obj_);
}
object::object(bool b)
: interp_(0)
{
obj_ = Tcl_NewBooleanObj(b);
Tcl_IncrRefCount(obj_);
}
object::object(char const *buf, size_t size)
: interp_(0)
{
obj_ = Tcl_NewByteArrayObj(
reinterpret_cast(buf),
static_cast(size));
Tcl_IncrRefCount(obj_);
}
object::object(double d)
: interp_(0)
{
obj_ = Tcl_NewDoubleObj(d);
Tcl_IncrRefCount(obj_);
}
object::object(int i)
: interp_(0)
{
obj_ = Tcl_NewIntObj(i);
Tcl_IncrRefCount(obj_);
}
object::object(long l)
: interp_(0)
{
obj_ = Tcl_NewLongObj(l);
Tcl_IncrRefCount(obj_);
}
object::object(char const *s)
: interp_(0)
{
obj_ = Tcl_NewStringObj(s, -1);
Tcl_IncrRefCount(obj_);
}
object::object(string const &s)
: interp_(0)
{
obj_ = Tcl_NewStringObj(s.data(), static_cast(s.size()));
Tcl_IncrRefCount(obj_);
}
object::object(Tcl_Obj *o, bool shared)
: interp_(0)
{
init(o, shared);
}
object::object(object const &other, bool shared)
: interp_(other.get_interp())
{
init(other.obj_, shared);
}
void object::init(Tcl_Obj *o, bool shared)
{
if (shared)
{
obj_ = o;
}
else
{
obj_ = Tcl_DuplicateObj(o);
}
Tcl_IncrRefCount(obj_);
}
object::~object()
{
Tcl_DecrRefCount(obj_);
}
object & object::assign(bool b)
{
Tcl_SetBooleanObj(obj_, b);
return *this;
}
object & object::resize(size_t size)
{
Tcl_SetByteArrayLength(obj_, static_cast(size));
return *this;
}
object & object::assign(char const *buf, size_t size)
{
Tcl_SetByteArrayObj(obj_,
reinterpret_cast(buf),
static_cast(size));
return *this;
}
object & object::assign(double d)
{
Tcl_SetDoubleObj(obj_, d);
return *this;
}
object & object::assign(int i)
{
Tcl_SetIntObj(obj_, i);
return *this;
}
object & object::assign(long l)
{
Tcl_SetLongObj(obj_, l);
return *this;
}
object & object::assign(char const *s)
{
Tcl_SetStringObj(obj_, s, -1);
return *this;
}
object & object::assign(string const &s)
{
Tcl_SetStringObj(obj_, s.data(), static_cast(s.size()));
return *this;
}
object & object::assign(object const &other)
{
object(other).swap(*this);
return *this;
}
object & object::assign(Tcl_Obj *o)
{
object(o).swap(*this);
return *this;
}
object & object::swap(object &other)
{
std::swap(obj_, other.obj_);
std::swap(interp_, other.interp_);
return *this;
}
template
bool object::get(interpreter &i) const
{
int retVal;
int res = Tcl_GetBooleanFromObj(i.get(), obj_, &retVal);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return static_cast(retVal);
}
template
vector object::get >(interpreter &) const
{
size_t size;
char const *buf = get(size);
return vector(buf, buf + size);
}
template
double object::get(interpreter &i) const
{
double retVal;
int res = Tcl_GetDoubleFromObj(i.get(), obj_, &retVal);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return retVal;
}
template
int object::get(interpreter &i) const
{
int retVal;
int res = Tcl_GetIntFromObj(i.get(), obj_, &retVal);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return retVal;
}
template
long object::get(interpreter &i) const
{
long retVal;
int res = Tcl_GetLongFromObj(i.get(), obj_, &retVal);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return retVal;
}
template
char const * object::get(interpreter &) const
{
return get();
}
template
string object::get(interpreter &) const
{
int len;
char const *buf = Tcl_GetStringFromObj(obj_, &len);
return string(buf, buf + len);
}
char const * object::get() const
{
return Tcl_GetString(obj_);
}
char const * object::get(size_t &size) const
{
int len;
unsigned char *buf = Tcl_GetByteArrayFromObj(obj_, &len);
size = len;
return const_cast(reinterpret_cast(buf));
}
size_t object::length(interpreter &i) const
{
int len;
int res = Tcl_ListObjLength(i.get(), obj_, &len);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return static_cast(len);
}
object object::at(interpreter &i, size_t index) const
{
Tcl_Obj *o;
int res = Tcl_ListObjIndex(i.get(), obj_, static_cast(index), &o);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
if (o == NULL)
{
throw tcl_error("Index out of range.");
}
return object(o);
}
object & object::append(interpreter &i, object const &o)
{
int res = Tcl_ListObjAppendElement(i.get(), obj_, o.obj_);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return *this;
}
object & object::append_list(interpreter &i, object const &o)
{
int res = Tcl_ListObjAppendList(i.get(), obj_, o.obj_);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return *this;
}
object & object::replace(interpreter &i, size_t index, size_t count,
object const &o)
{
int res = Tcl_ListObjReplace(i.get(), obj_,
static_cast(index), static_cast(count),
1, &(o.obj_));
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return *this;
}
object & object::replace_list(interpreter &i, size_t index, size_t count,
object const &o)
{
int objc;
Tcl_Obj **objv;
int res = Tcl_ListObjGetElements(i.get(), obj_, &objc, &objv);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
res = Tcl_ListObjReplace(i.get(), obj_,
static_cast(index), static_cast(count),
objc, objv);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return *this;
}
void object::set_interp(Tcl_Interp *interp)
{
interp_ = interp;
}
Tcl_Interp * object::get_interp() const
{
return interp_;
}
interpreter::interpreter()
{
interp_ = Tcl_CreateInterp();
}
interpreter::interpreter(Tcl_Interp *interp, bool owner)
{
interp_ = interp;
owner_ = owner;
}
interpreter::~interpreter()
{
if (owner_)
{
// clear all callback info belonging to this interpreter
clear_definitions(interp_);
Tcl_DeleteInterp(interp_);
}
}
void interpreter::make_safe()
{
int cc = Tcl_MakeSafe(interp_);
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
}
result interpreter::eval(string const &script)
{
int cc = Tcl_Eval(interp_, script.c_str());
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
return result(interp_);
}
result interpreter::eval(istream &s)
{
string str(
istreambuf_iterator(s.rdbuf()),
istreambuf_iterator()
);
return eval(str);
}
result interpreter::eval(object const &o)
{
int cc = Tcl_EvalObjEx(interp_, o.get_object(), 0);
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
return result(interp_);
}
void interpreter::pkg_provide(string const &name, string const &version)
{
int cc = Tcl_PkgProvide(interp_, name.c_str(), version.c_str());
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
}
void interpreter::create_alias(string const &cmd,
interpreter &targetInterp, string const &targetCmd)
{
int cc = Tcl_CreateAlias(interp_, cmd.c_str(),
targetInterp.interp_, targetCmd.c_str(), 0, 0);
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
}
void interpreter::clear_definitions(Tcl_Interp *interp)
{
// delete all callbacks that were registered for given interpreter
{
callback_map::iterator it = callbacks.find(interp);
if (it == callbacks.end())
{
// no callbacks defined for this interpreter
return;
}
callback_interp_map &imap = it->second;
for (callback_interp_map::iterator it2 = imap.begin();
it2 != imap.end(); ++it2)
{
Tcl_DeleteCommand(interp, it2->first.c_str());
}
callbacks.erase(interp);
}
// delete all constructors
{
callback_map::iterator it = constructors.find(interp);
if (it == constructors.end())
{
// no callbacks defined for this interpreter
return;
}
callback_interp_map &imap = it->second;
for (callback_interp_map::iterator it2 = imap.begin();
it2 != imap.end(); ++it2)
{
Tcl_DeleteCommand(interp, it2->first.c_str());
}
callbacks.erase(interp);
}
// delete all call policies
call_policies.erase(interp);
// delete all object handlers
// (we have to assume that all living objects were destroyed,
// otherwise Bad Things will happen)
class_handlers.erase(interp);
}
void interpreter::add_function(string const &name,
shared_ptr cb, policies const &p)
{
Tcl_CreateObjCommand(interp_, name.c_str(),
callback_handler, 0, 0);
callbacks[interp_][name] = cb;
call_policies[interp_][name] = p;
}
void interpreter::add_class(string const &name,
shared_ptr chb)
{
class_handlers[interp_][name] = chb;
}
void interpreter::add_constructor(string const &name,
shared_ptr chb, shared_ptr cb,
policies const &p)
{
Tcl_CreateObjCommand(interp_, name.c_str(),
constructor_handler, static_cast(chb.get()), 0);
constructors[interp_][name] = cb;
call_policies[interp_][name] = p;
}
int tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj)
{
int res;
int cc = Tcl_GetIntFromObj(interp, obj, &res);
if (cc != TCL_OK)
{
throw tcl_error(interp);
}
return res;
}
long tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj)
{
long res;
int cc = Tcl_GetLongFromObj(interp, obj, &res);
if (cc != TCL_OK)
{
throw tcl_error(interp);
}
return res;
}
bool tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj)
{
int res;
int cc = Tcl_GetBooleanFromObj(interp, obj, &res);
if (cc != TCL_OK)
{
throw tcl_error(interp);
}
return res != 0;
}
double tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj)
{
double res;
int cc = Tcl_GetDoubleFromObj(interp, obj, &res);
if (cc != TCL_OK)
{
throw tcl_error(interp);
}
return res;
}
string tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj)
{
return Tcl_GetString(obj);
}
char const * tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj)
{
return Tcl_GetString(obj);
}
object tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj)
{
object o(obj);
o.set_interp(interp);
return o;
}
How do I resolve this?
Thanks
The code seems to refer to the regular std::exception, but the symbol gets mixed because of using both the boost and std namespaces. Maybe it's some difference between VC and gcc headers.
In any case, adding the following lines to the file solves this compiler error and another similar conflict with shared_ptr in VC2010 (at least for me):
#define shared_ptr boost::shared_ptr
#define exception std::exception
Regards,
Miguel
A project has been started to fix the problems in this library here: https://github.com/wsong83/cpptcl
I notice cpptcl.cc has the following:
try
{
iti->second->invoke(interp, objc, objv, pol);
post_process_policies(interp, pol, objv, false);
}
catch (boost::exception const &e)
{
Tcl_SetResult(interp, const_cast(e.what()), TCL_VOLATILE);
return TCL_ERROR;
}
The compiler complains that boost::exceptiondoesn't have what() (which indeed it doesn't since that's in std::exception). So you have to change this to use get_error_info().
Also, I notice that the const_cast isn't taking a template argument. This is going to be problematic.