|
Boost : |
From: Eric Boutin (eric_at_[hidden])
Date: 2003-12-03 21:37:30
here's the code :
////////////////////////////////////////////////////////////////////////////
///////////////////////
caller-side code :
////////////////////////////////////////////////////////////////////////////
///////////////////////
/****
* loadlib.hpp : the declaration/definition or the dynamicfunction class
*
* this class calls a run-time librairy using system( ) with a 2 arguments
plus the librairy names (3 arg total)
*
* "librairyfilename" "inputfilename" "outputfilename"
*
* it creates a input and a output file
* the input files is the fallowing format :
* thenameofthefunctiontocall
* firstarg
* secondarg
* thirdarg
*
* to parse it, it's quite easy to do.. getline(file, buffer), function to
call = buffer; vector<string> argv; then while(getline( ))
* you can push_back the value at the end of the vector..
*
* the output file is the output generated by the function.. thoses are
programmers/functions-specifics
*
* for more info about librairy-side parsing, see dynamiclib.hpp
*
****/
//Copyleft - Eric Boutin - december 2003
//this class loads a function from a dynamic librairy and runs it
//sorry if it's messy.. I want this to fit in an include file so no linking
needed..
//sorry
#include <string>
#include <fstream>
#include <vector>
#include <cstdlib>
#include <sstream>
class dynamicfunction {
protected:
std::string outfilename; //the program will output everything in this file
std::string argfilename; //this file will be passed to the program, first
line : function to be called, second line and on arguments, to be reputed on
a vector
std::string libpath; //this contains the path to the librairy
std::string functiontocall; //the name of the function to call
//internal state for genfilename( );
std::vector<std::string> argv; //thoses arguments will be passed to the
program.. to simplify the implementation
//this function generates file names and make shure they are unused
void genfilename(std::string beg, std::string& buff, std::string end) {
static unsigned int genfilenamefeed=0; /* keeps internal state */
genfilenamefeed++;
//first, create a string that have what we want;
std::ostringstream ss;
ss <<"./" << beg << genfilenamefeed << end;
std::string filename = ss.str();
//check if the file exist
std::ifstream file;
file.open(filename.c_str());
if(!file) {
//file doesn't exist;
buff = filename;
return;
}
//file exist, loop back;
genfilename(beg, buff, end); }
public:
void pushargv(std::string in) {argv.push_back(in); return; } //Some
accessors -> this one pushes an argument
void cleanup() { remove(argfilename.c_str());
remove(outfilename.c_str()); } // " " -> this one cleanup the tmp
files.. called by the destructor or when your done with the function.. but
be carefull !
dynamicfunction(std::string libpathb, std::string functiontocallb) {
libpath = libpathb;
functiontocall = functiontocallb;
genfilename("tmplibcall_input", argfilename, ".tmp");
genfilename("tmplibcall_output", outfilename, ".tmp");
}//ok we know where everything is.. now let the user pushargv( ) some
times..
//ok now call the lib, so it'll call and execute the function eventually
int go(std::istream& progoutput) {
//1) put argv in a file (argfilename)
//2) call the lib
//3) fill the istream reference with the file corresponding to the
outputfile and returns the function return value
std::ofstream file;
file.open(argfilename.c_str());
file << functiontocall << std::endl;
std::vector<std::string>::iterator iter;
for(iter = argv.begin(); iter != argv.end(); iter++) { file << *iter <<
std::endl;}
file.close();
//on windows, when presence of whitespace in the filenames, we have to
double quote, else cmd is all messed up
//we want to achieve this command : "pathtolib" "inputfilename"
"outputfilename"
std::ostringstream ss;
ss << "\"\"" << libpath << "\" \"" << argfilename << "\" \"" <<
outfilename << "\"\"";
std::string callstring = ss.str();
int err = system(callstring.c_str());
//if( err < 0) { return std::istringstream("");} //TODO, better error
handling
progoutput = std::ifstream(outfilename.c_str());
return err;
}
~dynamicfunction() {cleanup();}
};
#endif
////////////////////////////////////////////////////////////////////////////
////////////////////////////////
this is the librairy-side doc
////////////////////////////////////////////////////////////////////////////
/////////////////////////////
/*******
* Eric Boutin, Copyleft, december 2003
* dynamiclib.hpp : the class that takes care of exporting functions and
calling the called functions.. kind of a link after main and before
* the exported functions
* HOW TO USE IT:
* first, at the beggining of ONE file, put the word USEDYNAMICLIB, it
define some static variables and functions, and main( )
* second, export functions
*
* Exporting functions:
* to begin, you put a BEGIN_EXPORTLIST statement at the top
* the you put some statement like this : EXPORT("functionname",
functionname);
* then you finish with a END_EXPORTLIST statement at the end
*
* Example:
int functiona(ostream& out, vector<string> argv);
int functionb(ostream& out, vector<string> argv);
BEGIN_EXPORTLIST
EXPORT("functiona", functiona);
EXPORT("functionb", functionb);
END_EXPORTLIST
* Once your done with exporting functions, you can define the functions..
that's always a good idea..
*
* the functions should returns an int, and must accept -> std::ostream&, you
can use this ostream to output all data there..
* -> vector<string>, all arguments are there
*
* Note that the input file is so easy to parse that any langage can parse
it.. you are not limited to this implementation of the librairy..
* write your own one in another programming langage !! e-mail me if you
wrote a perl of sed or awk or java one.. I'll use it !
*
*******/
//at the top of the main file in the dynamic librairy, put USEDYNAMICLIB to
define some static variables and functions
#define DYNAMICLIB_MISUAGE -80000 //wrong argc
#define DYNAMICLIB_BADFILES -80001 //!file failed
#define DYNAMICLIB_NOTEXPORTED -80002 //the function was not exported
#define BEGIN_EXPORTLIST void EXPORT() {
#define END_EXPORTLIST }
#include <map>
#include <string>
#include <fstream>
#include <vector>
//the maker of the librairy must implement this one
extern "C" void EXPORT(); //global C export function; so easy interface with
C
class dynamiclib{
protected:
std::ofstream out; //output everything here please
std::ifstream in;
static std::map<std::string, int (*)(std::ostream&,
std::vector<std::string>)> functionarray;
static std::map<std::string, bool> definedfunction;
std::vector<std::string> arg;
static dynamiclib* lib;
std::string functiontocall;
public:
dynamiclib() {dynamiclib::lib = this;}
static void export(std::string functioname, int (*funct)(std::ostream&,
std::vector<std::string>)) {
functionarray[functioname] = funct; definedfunction[functioname] = true;}
static void EXPORT() {::EXPORT(); }
int go(int argc, char* argv[]) {
EXPORT(); //first step, export the functions
//ok real job begins
//1) check argc and open streams
if(argc != 3) {return DYNAMICLIB_MISUAGE;}
//ok argv is ok.. at least we think...
in.open(argv[1]);
out.open(argv[2]);
if(!(in && out)) { return DYNAMICLIB_BADFILES;}
//2) parse in
//firstline is the function to call, every other lines are arguments
std::string buff;
std::getline(in, functiontocall);
while(std::getline(in, buff)) { arg.push_back(buff);}
//3) call the function
if(definedfunction[functiontocall]) {
return functionarray[functiontocall](out, arg);} else {
//the function wasn't exported
return DYNAMICLIB_NOTEXPORTED;}
}
};
#define USEDYNAMICLIB std::map<std::string, int
(*)(std::ostream&,std::vector<std::string>)> dynamiclib::functionarray;\
std::map<std::string, bool> dynamiclib::definedfunction; \
dynamiclib* dynamiclib::lib; \
int main(int argc, char* argv[]) { dynamiclib lib; return lib.go(argc,
argv); } \
void EXPORT(std::string functionname, int (*funct)(std::ostream&,
std::vector<std::string>)){ dynamiclib::export(functionname, funct);}
//end of the INITDYNAMICLIB macro
#endif
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk