COOPY » Guide
version 0.6.5
|
00001 #include <coopy/PolyBook.h> 00002 #include <coopy/ShortTextBook.h> 00003 #include <coopy/CsvTextBook.h> 00004 #include <coopy/CsvFile.h> 00005 #include <coopy/FormatSniffer.h> 00006 #include <coopy/Dbg.h> 00007 #include <coopy/TextBookFactory.h> 00008 #include <coopy/ShortTextBookFactory.h> 00009 #include <coopy/FormatDesc.h> 00010 00011 #include <stdlib.h> 00012 #include <stdio.h> 00013 00014 #include <map> 00015 #include <fstream> 00016 00017 using namespace std; 00018 using namespace coopy::store; 00019 using namespace coopy::format; 00020 00021 extern TextBook *readHelper(const char *fname, 00022 const char *ext, 00023 const char *data); 00024 00025 extern bool readHelperJson(coopy::store::Property& config, 00026 const char *filename); 00027 00028 extern void getFactories(vector<TextBookFactory *>& lst); 00029 extern void getFactoriesList(vector<FormatDesc>& descs); 00030 00031 class Factories { 00032 public: 00033 vector<TextBookFactory *> all; 00034 00035 Factories() { 00036 all.push_back(new ShortTextBookFactory); 00037 all.push_back(CsvTextBookFactory::makeFactory()); 00038 all.push_back(CsvTextBookFactory::makeCompactFactory()); 00039 getFactories(all); 00040 } 00041 00042 ~Factories() { 00043 for (int i=0; i<(int)all.size(); i++) { 00044 if (all[i]!=NULL) { 00045 delete all[i]; 00046 } 00047 } 00048 } 00049 00050 TextBook *open(AttachConfig& config, AttachReport& report) { 00051 string key = config.options.get("type").asString(); 00052 for (int i=0; i<(int)all.size(); i++) { 00053 if (all[i]==NULL) { 00054 fprintf(stderr,"Failed to allocate a factory\n"); 00055 return NULL; 00056 } 00057 if (all[i]->getName()==key) { 00058 dbg_printf("Factories::open operating on %s (prev book: |%ld|%s)\n", key.c_str(), 00059 (long int)config.prevBook, 00060 (config.prevBook!=NULL)?config.prevBook->desc().c_str():""); 00061 TextBook *result = all[i]->open(config,report); 00062 dbg_printf("success [%s] msg [%s]\n", report.success?"ok":"fail", 00063 report.msg.c_str()); 00064 if (!report.success) { 00065 fprintf(stderr,"* %s%s%s\n", 00066 key.c_str(), 00067 (report.msg!="")?": ":" operation failed.", 00068 report.msg.c_str()); 00069 } 00070 return result; 00071 } 00072 } 00073 fprintf(stderr,"* Book type not known (%s)\n", key.c_str()); 00074 return NULL; 00075 } 00076 }; 00077 00078 class Namer { 00079 public: 00080 map<string,int> existing; 00081 string name(string input) { 00082 string sane = ""; 00083 for (size_t i=0; i<input.length(); i++) { 00084 char ch = input[i]; 00085 if (ch=='"') { 00086 sane += '"'; 00087 } 00088 sane += ch; 00089 } 00090 if (existing.find(sane)!=existing.end()) { 00091 char buf[256]; 00092 int at = 0; 00093 do { 00094 sprintf(buf,"%d",at); 00095 at++; 00096 } while (existing.find(sane+buf)==existing.end()); 00097 sane += buf; 00098 } 00099 existing[sane] = 1; 00100 return sane; 00101 } 00102 }; 00103 00104 class Valuer { 00105 public: 00106 string name(string input) { 00107 string sane = ""; 00108 for (size_t i=0; i<input.length(); i++) { 00109 char ch = input[i]; 00110 if (ch=='\'') { 00111 sane += '\''; 00112 } 00113 sane += ch; 00114 } 00115 return sane; 00116 } 00117 }; 00118 00119 bool PolyBook::expand(Property& config) { 00120 string filename = config.get("file").asString(); 00121 string name = filename; 00122 string ext = config.get("ext").asString(); 00123 if (ext=="") { 00124 size_t eid = name.rfind("."); 00125 if (eid!=string::npos) { 00126 ext = name.substr(eid); 00127 } 00128 } else { 00129 if (ext[0]!='.') { 00130 ext = string(".") + ext; 00131 } 00132 } 00133 for (size_t i=0; i<ext.length(); i++) { 00134 ext[i] = tolower(ext[i]); 00135 } 00136 //dbg_printf("Attach: extension is %s\n", ext.c_str()); 00137 00138 if (filename.substr(0,4)!="dbi:") { 00139 if (ext == ".json") { 00140 dbg_printf("Asked to attach, with json configuration\n"); 00141 if (!readHelperJson(config,filename.c_str())) { 00142 return false; 00143 } 00144 filename = config.get("file",PolyValue::makeString("-")).asString(); 00145 ext = ""; 00146 config.put("ext",""); 00147 } else { 00148 config.put("ext",ext); 00149 } 00150 } 00151 00152 if (filename.substr(0,4)=="dbi:") { 00153 string s = filename + ":"; 00154 int first = 0; 00155 vector<string> words; 00156 char prev = '*'; 00157 bool last = false; 00158 for (int i=0; i<(int)s.length(); i++) { 00159 char ch = s[i]; 00160 if (ch==':'&&(i==s.length()-1||!last)) { 00161 if (prev==ch) { 00162 last = true; 00163 } 00164 string word = s.substr(first,i-first); 00165 size_t div = word.find('='); 00166 if (div==string::npos) { 00167 words.push_back(word); 00168 //dbg_printf("dbi: part %s\n", word.c_str()); 00169 } else { 00170 string key = word.substr(0,div); 00171 string val = word.substr(div+1,word.length()); 00172 //dbg_printf("dbi: %s->%s\n", key.c_str(), val.c_str()); 00173 if (key=="port") { 00174 config.put(key.c_str(),atoi(val.c_str())); 00175 } else { 00176 config.put(key.c_str(),val); 00177 } 00178 } 00179 first = i+1; 00180 } 00181 prev = ch; 00182 } 00183 if (words.size()>1) { 00184 config.put("type",words[1]); 00185 } 00186 if (words.size()>2) { 00187 config.put("database",words[2]); 00188 } 00189 if (words.size()>3) { 00190 config.put("host",words[3]); 00191 } 00192 if (words.size()>4) { 00193 config.put("port",atoi(words[4].c_str())); 00194 } 00195 } 00196 00197 string key = config.get("type",PolyValue::makeString("")).asString(); 00198 00199 if (key=="") { 00200 if (ext==".csv"||ext==".ssv"||ext==".tsv"||ext==".txt") { 00201 key = "csv"; 00202 } 00203 if (ext==".csvs") { 00204 key = "csvs"; 00205 } 00206 if (ext==".xls"||ext==".xlsx"||ext==".gnumeric"||ext==".ods") { 00207 key = "gnumeric"; 00208 } 00209 if (ext==".socialcalc"||ext==".sc") { 00210 key = "socialcalc"; 00211 } 00212 if (ext==".jsonbook") { 00213 key = "jsonbook"; 00214 } 00215 if (ext==".mdb") { 00216 key = "access"; 00217 } 00218 if (ext==".sqlite") { 00219 key = "sqlite"; 00220 } 00221 if (ext==".sqlitext") { 00222 key = "sqlitext"; 00223 } 00224 if (ext==".book") { 00225 key = "book"; 00226 } 00227 } 00228 if (key==""&&filename=="-") { 00229 key = "csvs"; 00230 } 00231 00232 if (key=="") { 00233 //printf("SNIFFING %s\n",filename.c_str()); 00234 FormatSniffer sniffer; 00235 sniffer.open(filename.c_str(),false); 00236 Format f = sniffer.getFormat(); 00237 switch (f.id) { 00238 case FORMAT_BOOK_SQLITE: 00239 key = "sqlite"; 00240 break; 00241 case FORMAT_BOOK_CSVS: 00242 key = "csvs"; 00243 break; 00244 } 00245 } 00246 00247 dbg_printf("FILE: type [%s] file [%s] settings: %s\n", key.c_str(), filename.c_str(), config.toString().c_str()); 00248 00249 if (config.get("file").asString()=="-"&&config.check("only_if_exists")) { 00250 config.put("skip",true); 00251 } 00252 00253 if (key=="") { 00254 fprintf(stderr,"* Extension %s not known, maybe use a .json config file?\n", 00255 ext.c_str()); 00256 return false; 00257 } 00258 config.put("type",key); 00259 config.put("expanded_filename",filename.c_str()); 00260 config.put("expanded_ext",ext.c_str()); 00261 00262 return true; 00263 } 00264 00265 bool PolyBook::attach(Property& config, PolyBook *base) { 00266 dbg_printf("PolyBook::attach %s\n", config.toString().c_str()); 00267 if (config.check("should_clear")) { 00268 if (config.get("should_clear").asBoolean()) { 00269 clear(); 00270 } 00271 } 00272 00273 bool ok = expand(config); 00274 if (!ok) return false; 00275 00276 string filename = config.get("expanded_filename").asString(); 00277 string ext = config.get("expanded_ext").asString(); 00278 00279 Factories f; 00280 AttachConfig ac; 00281 AttachReport ar; 00282 ac.fname = config.get("file").asString(); 00283 if (ac.fname=="") ac.fname = filename; 00284 ac.ext = ext; 00285 ac.data = ""; 00286 ac.options = config; 00287 ac.canCreate = config.get("can_create").asBoolean(); 00288 ac.canOverwrite = true; 00289 ac.shouldRead = config.get("should_read").asBoolean(); 00290 ac.shouldWrite = config.get("should_write").asBoolean(); 00291 if (config.check("skip")) { 00292 ac.shouldRead = false; 00293 ac.shouldWrite = false; 00294 } 00295 ac.prevBook = book; 00296 ac.baseBook = base; 00297 ac.prevOptions = options; 00298 TextBook *nextBook = f.open(ac,ar); 00299 if (nextBook!=NULL) { 00300 if (book!=NULL) { 00301 if (nextBook!=book) { 00302 clear(); 00303 } 00304 } 00305 } 00306 if (nextBook!=NULL && nextBook!=book) { 00307 nextBook->addReference(); 00308 } 00309 book = nextBook; 00310 options = config; 00311 return book!=NULL; 00312 } 00313 00314 bool PolyBook::flush() { 00315 if (!inplace()) { 00316 options.put("can_create",true); 00317 options.put("should_read",false); 00318 options.put("should_write",true); 00319 return attach(options); 00320 } 00321 return true; 00322 } 00323 00324 00325 #define STRVAL PolyValue::makeString 00326 00327 std::vector<FormatDesc> PolyBook::getFormatList() { 00328 00329 vector<FormatDesc> descs; 00330 00331 FormatDesc csv("CSV: plain-text delimiter-separated family of formats"); 00332 csv.addExtension(".csv","Comma-separated values"); 00333 csv.addExtension(".tsv","Tab-separated values"); 00334 csv.addExtension(".ssv","Semicolon-separated values"); 00335 csv.addOption("type",STRVAL("csv"),"CSV family",true); 00336 csv.addOption("file",STRVAL("fname.dsv"),"File name",true); 00337 csv.addOption("delimiter",STRVAL("|"),"Delimiter character",true); 00338 descs.push_back(csv); 00339 00340 getFactoriesList(descs); 00341 00342 return descs; 00343 } 00344 00345 void PolyBook::showFormats() { 00346 vector<FormatDesc> descs = getFormatList(); 00347 00348 printf("Supported formats\n"); 00349 printf("-----------------\n\n"); 00350 for (int i=0; i<(int)descs.size(); i++) { 00351 descs[i].show(); 00352 } 00353 00354 printf("Tips:\n"); 00355 printf("* Most spreadsheet/database formats support a 'table' option to restrict\n"); 00356 printf(" input/output to a named table or tables\n"); 00357 printf("* json options and dbi options are interchangeable\n"); 00358 } 00359 00360 00361 bool PolyBook::copyFile(const char *src, const char *dest) { 00362 PolyBook bsrc; 00363 if (!bsrc.read(src)) { 00364 fprintf(stderr,"Failed to read %s\n", src); 00365 return false; 00366 } 00367 if (!bsrc.write(dest)) { 00368 fprintf(stderr,"Failed to write %s\n", dest); 00369 return false; 00370 } 00371 return true; 00372 } 00373 00374 00375 bool PolyBook::copy(const TextBook& alt, const Property& options) { 00376 if (!book) 00377 book = new CsvTextBook(true); 00378 if (book) 00379 return book->copy(alt,options); 00380 return false; 00381 }