pelib
2.0.0
|
00001 /* 00002 Copyright 2015 Nicolas Melot 00003 00004 This file is part of Pelib. 00005 00006 Pelib is free software: you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation, either version 3 of the License, or 00009 (at your option) any later version. 00010 00011 Pelib is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with Pelib. If not, see <http://www.gnu.org/licenses/>. 00018 */ 00019 00020 00021 #include <iostream> 00022 #include <cstdlib> 00023 #include <vector> 00024 #include <map> 00025 00026 #include <pelib/Record.hpp> 00027 00028 #include <pelib/argument_parsing.hpp> 00029 #include <pelib/dl.h> 00030 00031 #ifdef debug 00032 #undef debug 00033 #endif 00034 00035 #define debug(expr) cerr << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << #expr << " = \"" << expr << "\"." << endl; 00036 00037 using namespace std; 00038 using namespace pelib; 00039 00040 struct conversion 00041 { 00042 vector<pelib_argument_stream_t> inputs; 00043 vector<pelib_argument_stream_t> process; 00044 vector<pelib_argument_stream_t> outputs; 00045 }; 00046 typedef struct conversion conversion_t; 00047 00048 static conversion_t 00049 parse_args(char** argv) 00050 { 00051 conversion_t conversion; 00052 string self(argv[0]); 00053 //conversion.process.library = NULL; 00054 00055 for(argv++; *argv != NULL; argv++) 00056 { 00057 if(string(*argv).compare("--input") == 0) 00058 { 00059 pelib_argument_stream_t input; 00060 pelib_argument_stream_init(&input); 00061 argv++; 00062 size_t num = pelib_argument_stream_parse(argv, &input); 00063 argv = argv + num - 1; 00064 conversion.inputs.push_back(input); 00065 continue; 00066 } 00067 00068 if(string(*argv).compare("--process") == 0) 00069 { 00070 pelib_argument_stream_t process; 00071 pelib_argument_stream_init(&process); 00072 argv++; 00073 size_t num = pelib_argument_stream_parse(argv, &process); 00074 argv = argv + num - 1; 00075 conversion.process.push_back(process); 00076 continue; 00077 } 00078 00079 if(string(*argv).compare("--output") == 0) 00080 { 00081 pelib_argument_stream_t output; 00082 pelib_argument_stream_init(&output); 00083 argv++; 00084 size_t num = pelib_argument_stream_parse(argv, &output); 00085 argv = argv + num - 1; 00086 conversion.outputs.push_back(output); 00087 continue; 00088 } 00089 00090 if(string(*argv).compare("--sources") == 0) 00091 { 00092 string cmd = string("ls $(dirname $(realpath $(which ").append(self).append(")))/../share/pelib/pelib-*.tar.gz | sort -rV | head -1 | xargs realpath"); 00093 exit(system(cmd.c_str())); 00094 } 00095 00096 if(string(*argv).compare("--seed") == 0) 00097 { 00098 argv++; 00099 size_t seed; 00100 if(string(*argv).compare("--random") == 0) 00101 { 00102 seed = (size_t)time(NULL); 00103 } 00104 else 00105 { 00106 stringstream str(argv[0]); 00107 str >> seed; 00108 } 00109 srand(seed); 00110 } 00111 00112 } 00113 00114 return conversion; 00115 } 00116 00117 int 00118 main(int argc, char **argv) 00119 { 00120 vector<void*> process; 00121 map<const char*, Record*> inputs; 00122 map<const char*, void (*)(Record*)> freelist; 00123 map<const char*, void*> parserList; 00124 00125 conversion_t conversion = parse_args(argv); 00126 00127 size_t counter = 1; 00128 for(vector<pelib_argument_stream_t>::const_iterator i = conversion.inputs.begin(); i != conversion.inputs.end(); i++, counter++) 00129 { 00130 /* Load functions from shared libraries */ 00131 void *libParser; 00132 if(i->library != NULL) 00133 { 00134 libParser = load_lib(i->library); 00135 } 00136 else 00137 { 00138 cerr << "[WARNING] No parser library specified for input #" << counter << ". Skipping." << endl; 00139 continue; 00140 } 00141 00142 /* Link function handles to function pointers */ 00143 Record* (*parse)(istream&, size_t, char**) = (Record* (*)(istream&, size_t, char**))load_function(libParser, "pelib_parse"); 00144 void (*del)(Record*) = (void (*)(Record*))load_function(libParser, "pelib_delete"); 00145 00146 switch(i->stream) 00147 { 00148 case STREAM_STDIN: 00149 { 00150 Record* rec = parse(cin, i->argc, i->argv); 00151 if(rec != NULL) 00152 { 00153 if(i->name != NULL) 00154 { 00155 inputs.insert(pair<const char*, Record*>(i->name, rec)); 00156 freelist.insert(pair<const char*, void (*)(Record*)>(i->name, del)); 00157 parserList.insert(pair<const char*, void*>(pair<const char*, void*>(i->name, libParser))); 00158 } 00159 else 00160 { 00161 inputs.insert(pair<const char*, Record*>(typeid(*rec).name(), rec)); 00162 freelist.insert(pair<const char*, void (*)(Record*)>(typeid(*rec).name(), del)); 00163 parserList.insert(pair<const char*, void*>(pair<const char*, void*>(typeid(*rec).name(), libParser))); 00164 } 00165 } 00166 else 00167 { 00168 cerr << "[WARNING] Parser \"" << i->library << "\" failed to parse input on stdin for input #" << counter << ". Skipping." << endl; 00169 } 00170 } 00171 break; 00172 case STREAM_STDOUT: 00173 case STREAM_STDERR: 00174 cerr << "[WARNING] Cannot read data from an output stream for input #" << counter << ". Skipping." << endl; 00175 break; 00176 case STREAM_FILE: 00177 { 00178 ifstream myfile(i->filename); 00179 Record *rec = parse(myfile, i->argc, i->argv); 00180 00181 if(rec != NULL) 00182 { 00183 if(i->name != NULL) 00184 { 00185 inputs.insert(pair<const char*, Record*>(i->name, rec)); 00186 freelist.insert(pair<const char*, void (*)(Record*)>(i->name, del)); 00187 } 00188 else 00189 { 00190 inputs.insert(pair<const char*, Record*>(typeid(*rec).name(), rec)); 00191 freelist.insert(pair<const char*, void (*)(Record*)>(typeid(*rec).name(), del)); 00192 } 00193 myfile.close(); 00194 } 00195 else 00196 { 00197 cerr << "[WARNING] Parser \"" << i->library << "\" failed to parse input on stdin for input #" << counter << ". Skipping." << endl; 00198 } 00199 } 00200 break; 00201 case STREAM_NOTHING: 00202 default: 00203 cerr << "[WARNING] No input stream specified for input #" << counter << ". Skipping." << endl; 00204 break; 00205 } 00206 00207 // Don't destroy the libparser yet, as we need to destroy data elements parsed 00208 // Don't destroy the pelib_argument_stream descriptor yet as we still need input names 00209 } 00210 00211 for(vector<pelib_argument_stream_t>::const_iterator i = conversion.process.begin(); i != conversion.process.end(); i++) 00212 { 00213 void *libProcess = load_lib(i->library); 00214 process.push_back(libProcess); 00215 00216 /* Link function handles to function pointers */ 00217 std::map<const char*, Record*> (*process)(std::map<const char*, Record*> records, size_t, char**) = (std::map<const char*, Record*> (*)(std::map<const char*, Record*> records, size_t, char**))load_function(libProcess, "pelib_process"); 00218 std::map<const char*, Record*> transform = process(inputs, i->argc, i->argv); 00219 00220 // Free data structure parsed 00221 for(map<const char*, void (*)(Record*)>::iterator i = freelist.begin(); i != freelist.end(); i++) 00222 { 00223 void (*del)(Record*) = i->second; 00224 del(inputs.find(i->first)->second); 00225 } 00226 00227 // Replace inputs with transformation outcome 00228 inputs = transform; 00229 00230 // Replace function pointers 00231 freelist.clear(); 00232 void (*del)(Record*) = (void (*)(Record*))load_function(libProcess, "pelib_delete"); 00233 for(map<const char*, Record*>::iterator i = inputs.begin(); i != inputs.end(); i++) 00234 { 00235 freelist.insert(pair<const char*, void (*)(Record*)>(i->first, del)); 00236 } 00237 } 00238 00239 counter = 1; 00240 for(vector<pelib_argument_stream_t>::const_iterator i = conversion.outputs.begin(); i != conversion.outputs.end() && inputs.size() > 0; i++, counter++) 00241 { 00242 /* Load functions from shared libraries */ 00243 void *libOutput; 00244 if(i->library != NULL) 00245 { 00246 libOutput = load_lib(i->library); 00247 } 00248 else 00249 { 00250 cerr << "[WARNING] No output library specified for output #" << counter << ". Skipping." << endl; 00251 continue; 00252 } 00253 00254 /* Link function handles to function pointers */ 00255 void (*dump)(ostream&, std::map<const char*, Record*> records, size_t, char**) = (void (*)(ostream&, std::map<const char*, Record*> records, size_t, char**))load_function(libOutput, "pelib_dump"); 00256 00257 switch(i->stream) 00258 { 00259 case STREAM_STDIN: 00260 cerr << "[WARNING] Cannot dump data to an input stream for output #" << counter << ". Skipping." << endl; 00261 case STREAM_STDOUT: 00262 dump(cout, inputs, i->argc, i->argv); 00263 break; 00264 case STREAM_STDERR: 00265 dump(cerr, inputs, i->argc, i->argv); 00266 break; 00267 case STREAM_FILE: 00268 { 00269 ofstream myfile(i->filename, ios::out | ios::trunc | ios::binary); 00270 dump(myfile, inputs, i->argc, i->argv); 00271 myfile.close(); 00272 } 00273 break; 00274 case STREAM_NOTHING: 00275 default: 00276 cerr << "[WARNING] No output stream specified for output #" << counter << ". Skipping." << endl; 00277 break; 00278 } 00279 00280 // Destroy dynamic libraries 00281 destroy_lib(libOutput); 00282 00283 // Destroy the stream descriptor 00284 pelib_argument_stream_destroy(*i); 00285 } 00286 00287 // Destroy input structures 00288 for(map<const char*, Record*>::iterator i = inputs.begin(); i != inputs.end(); i++) 00289 { 00290 void (*del)(Record*) = freelist.find(i->first)->second; 00291 del(i->second); 00292 } 00293 00294 // Destroy input library handlers 00295 for(map<const char*, void*>::iterator i = parserList.begin(); i != parserList.end(); i++) 00296 { 00297 destroy_lib(i->second); 00298 } 00299 00300 // Delete processing dynamic library 00301 for(vector<void*>::const_iterator i = process.begin(); i != process.end(); i++) 00302 { 00303 destroy_lib(*i); 00304 } 00305 00306 // Destroy input arguments 00307 for(vector<pelib_argument_stream_t>::const_iterator i = conversion.inputs.begin(); i != conversion.inputs.end(); i++) 00308 { 00309 pelib_argument_stream_destroy(*i); 00310 } 00311 } 00312