COOPY » Guide
version 0.6.5
|
00001 00002 #include <coopy/PatchParser.h> 00003 #include <coopy/CsvFile.h> 00004 #include <coopy/Format.h> 00005 #include <coopy/Dbg.h> 00006 #include <coopy/PolyBook.h> 00007 #include <coopy/Mover.h> 00008 00009 #include <stdio.h> 00010 #include <string.h> 00011 00012 #include <string> 00013 #include <vector> 00014 #include <algorithm> 00015 00016 #define WANT_VECTOR2STRING 00017 #include <coopy/Stringer.h> 00018 00019 using namespace coopy::cmp; 00020 using namespace coopy::format; 00021 using namespace coopy::store; 00022 using namespace std; 00023 00024 class PatchColumnNames { 00025 public: 00026 vector<string> lst; 00027 vector<SheetCell> data; 00028 vector<int> indices; 00029 00030 void read(const vector<string>& vals, int offset) { 00031 for (int i=0; i<(int)vals.size(); i++) { 00032 lst.push_back(vals[i]); 00033 indices.push_back(i); 00034 } 00035 } 00036 00037 void read(const DataSheet& sheet, int x, int y, int len = -1) { 00038 lst.clear(); 00039 indices.clear(); 00040 int last = sheet.width()-1; 00041 if (len>=0) { 00042 last = x+len-1; 00043 } 00044 for (int i=x; i<=last; i++) { 00045 string v = sheet.cellString(i,y); 00046 if (v==""&&len==-1) break; 00047 lst.push_back(v); 00048 indices.push_back(i-x); 00049 } 00050 } 00051 00052 void readData(const DataSheet& sheet, int x, int y, int len) { 00053 data.clear(); 00054 for (int i=x; i<x+len; i++) { 00055 SheetCell v = sheet.cellSummary(i,y); 00056 data.push_back(v); 00057 } 00058 } 00059 00060 string toString() { 00061 return vector2string(lst); 00062 } 00063 00064 string dataString() { 00065 return vector2string(data); 00066 } 00067 00068 void autoStart(PatchColumnNames& prior, 00069 const char *name, 00070 bool add, 00071 bool mv) { 00072 if (name!=NULL && prior.lst.size()==0) { 00073 int idx = 0; 00074 for (int i=0; i<(int)lst.size(); i++) { 00075 if (lst[i]!=name||mv) { 00076 prior.lst.push_back(lst[i]); 00077 prior.indices.push_back(idx); 00078 idx++; 00079 } 00080 } 00081 if (!add && !mv) { 00082 prior.lst.push_back(name); 00083 prior.indices.push_back(idx); 00084 } 00085 } 00086 } 00087 00088 string inferRename(PatchColumnNames& prior, 00089 int *dest, 00090 const char *name = NULL) { 00091 COOPY_ASSERT(lst.size()==prior.lst.size()); 00092 int i; 00093 for (i=0; i<(int)lst.size(); i++) { 00094 if (lst[i]!=prior.lst[i]) { 00095 break; 00096 } 00097 } 00098 // the deleted element is named by prior.lst[i] 00099 string mover = prior.lst[i]; 00100 indices = prior.indices; 00101 int subject = i; 00102 if (dest!=NULL) *dest = indices[subject]; 00103 return mover; 00104 } 00105 00106 00107 string inferInsert(PatchColumnNames& prior, 00108 int *dest, 00109 const char *name = NULL) { 00110 autoStart(prior,name,true,false); 00111 if (lst.size()!=prior.lst.size()+1) { 00112 fprintf(stderr, "Error in insertion, final length is %d, original length is %d\n", 00113 lst.size(), prior.lst.size()); 00114 } 00115 COOPY_ASSERT(lst.size()==prior.lst.size()+1); 00116 int i; 00117 for (i=0; i<(int)prior.lst.size(); i++) { 00118 if (lst[i]!=prior.lst[i]) { 00119 break; 00120 } 00121 } 00122 // the inserted element is named by lst[i] 00123 string mover = lst[i]; 00124 indices = prior.indices; 00125 int subject = i; 00126 if (subject>=prior.lst.size()) { 00127 subject = -1; 00128 } 00129 int neg = 0; 00130 for (int j=0; j<(int)indices.size(); j++) { 00131 if (indices[j]<neg) { 00132 neg = indices[j]; 00133 } 00134 } 00135 neg--; 00136 if (subject>=0) { 00137 indices.insert(indices.begin()+subject,neg); 00138 } else { 00139 indices.push_back(neg); 00140 } 00141 if (dest!=NULL) *dest = neg; 00142 //if (dest!=NULL) *dest = subject; 00143 return mover; 00144 } 00145 00146 string inferDelete(PatchColumnNames& prior, 00147 int *src, 00148 const char *name = NULL) { 00149 autoStart(prior,name,false,false); 00150 COOPY_ASSERT(lst.size()==prior.lst.size()-1); 00151 int i; 00152 for (i=0; i<(int)lst.size(); i++) { 00153 if (lst[i]!=prior.lst[i]) { 00154 break; 00155 } 00156 } 00157 // the deleted element is named by prior.lst[i] 00158 string mover = prior.lst[i]; 00159 indices = prior.indices; 00160 int subject = i; 00161 if (src!=NULL) *src = indices[subject]; 00162 indices.erase(indices.begin()+subject); 00163 return mover; 00164 } 00165 00166 string inferMove(PatchColumnNames& prior, 00167 int *src, 00168 int *dest, 00169 const char *name = NULL) { 00170 autoStart(prior,name,false,true); 00171 COOPY_ASSERT(lst.size()==prior.lst.size()); 00172 int i; 00173 bool useName = false; 00174 for (i=0; i<(int)lst.size(); i++) { 00175 if (lst[i]!=prior.lst[i]) { 00176 break; 00177 } 00178 } 00179 if (i==lst.size()) { 00180 if (name!=NULL) { 00181 for (i=0; i<(int)lst.size(); i++) { 00182 if (lst[i]==name) { 00183 useName = true; 00184 break; 00185 } 00186 } 00187 } 00188 } 00189 00190 if (i==lst.size()) { 00191 printf("A move was proposed, but does not make sense\n"); 00192 exit(1); 00193 } 00194 00195 // The moved element is named by either lst[i] or prior.lst[i] 00196 // We are guaranteed at least one element after this one. 00197 string mover; 00198 if (!useName) { 00199 if (prior.lst[i+1]==lst[i]) { 00200 mover = prior.lst[i]; 00201 } else { 00202 mover = lst[i]; 00203 } 00204 } else { 00205 mover = name; 00206 } 00207 00208 int isrc = -1; 00209 int idest = -1; 00210 vector<string>::const_iterator it = 00211 find(prior.lst.begin(),prior.lst.end(),mover); 00212 int rem = it-prior.lst.begin(); 00213 isrc = rem; 00214 vector<string>::const_iterator it2 = 00215 find(lst.begin(),lst.end(),mover); 00216 int add = it2-lst.begin(); 00217 bool append = false; 00218 if (add==((int)lst.size())-1) { 00219 idest = -1; 00220 append = true; 00221 } else { 00222 vector<string>::const_iterator it_post = it2; 00223 it_post++; 00224 vector<string>::const_iterator it_post_org = 00225 find(prior.lst.begin(),prior.lst.end(),*it_post); 00226 idest = it_post_org-prior.lst.begin(); 00227 } 00228 indices = prior.indices; 00229 int v = indices[rem]; 00230 if (src!=NULL) *src = v; 00231 if (dest!=NULL) *dest = v; 00232 indices.erase(indices.begin()+rem); 00233 //printf("removing at %d, inserting at %d\n", rem, add); 00234 if (add>rem) add--; 00235 if (append) { 00236 indices.push_back(v); 00237 } else { 00238 indices.insert(indices.begin()+add,v); 00239 } 00240 00241 //if (dest!=NULL) *dest = v; 00242 00243 //if (src!=NULL) *src = isrc; 00244 //if (dest!=NULL) *dest = idest; 00245 00246 return mover; 00247 } 00248 }; 00249 00250 00251 static SheetCell nully(string x) { 00252 if (x=="NULL") { 00253 return SheetCell("NULL",true); 00254 } 00255 int score = 0; 00256 for (score=0; score<(int)x.length(); score++) { 00257 if (x[score]!='_') { 00258 break; 00259 } 00260 } 00261 if (score>0) { 00262 string token = "NULL"; 00263 if (memcmp(((char*)x.c_str())+score,token.c_str(),x.length()-score)==0) { 00264 return SheetCell(x.substr(1,x.length()),false); 00265 } 00266 } 00267 // does nothing for now 00268 return SheetCell(x,false); 00269 } 00270 00271 bool PatchParser::apply() { 00272 if (patcher==NULL) return false; 00273 00274 if (preread_book!=NULL) { 00275 return applyHiliteBook(*preread_book); 00276 } 00277 00278 if (fname!="") { 00279 sniffer.open(fname.c_str()); 00280 } else { 00281 string txt = ""; 00282 for (int i=0; i<(int)oneliners.size(); i++) { 00283 txt += oneliners[i]; 00284 txt += "\n"; 00285 } 00286 if (txt=="") return true; 00287 sniffer.setString(txt.c_str()); 00288 } 00289 00290 Format format = sniffer.getFormat(); 00291 if (use_oneliners) { 00292 return applyTdiff(); 00293 } 00294 00295 if (format.id==FORMAT_PATCH_CSV) { 00296 dbg_printf("Looks like DTBL\n"); 00297 return applyCsv(); 00298 } 00299 if (format.id==FORMAT_PATCH_TDIFF) { 00300 dbg_printf("Looks like TDIFF\n"); 00301 return applyTdiff(); 00302 } 00303 //fprintf(stderr,"Unsupported format\n"); 00304 dbg_printf("Try color\n"); 00305 return applyColor(); 00306 } 00307 00308 bool PatchParser::applyCsv() { 00309 00310 CsvSheet patch; 00311 if (CsvFile::read(sniffer,patch)!=0) { 00312 fprintf(stderr,"Failed to read patch\n"); 00313 return false; 00314 } 00315 00316 patcher->mergeStart(); 00317 00318 PatchColumnNames names; 00319 vector<string> allNames; 00320 00321 map<string,bool> match_column; 00322 map<string,bool> assign_column; 00323 00324 vector<SheetCell> selector; 00325 bool needSelector = true; 00326 int len = 0; 00327 int row_index = -1; 00328 bool ok = true; 00329 bool sequential = true; 00330 00331 bool configSent = false; 00332 bool configSet = false; 00333 ConfigChange cc; 00334 bool support_name_ROW = false; 00335 bool support_name_star = false; 00336 int name_start = 2; 00337 for (int i=0; i<patch.height(); i++) { 00338 dbg_printf("[%d] ", i); 00339 string cmd0 = patch.cell(0,i); 00340 string cmd1 = patch.cell(1,i); 00341 bool fail = false; 00342 if (cmd0!="config" && configSet && !configSent) { 00343 patcher->changeConfig(cc); 00344 } 00345 if (cmd0=="dtbl") { 00346 string ver = patch.cell(3,i); 00347 dbg_printf("Processed header version %s\n", ver.c_str()); 00348 if (ver == "0.2") { 00349 support_name_ROW = true; 00350 support_name_star = true; 00351 } 00352 } else if (cmd0=="config") { 00353 string key = patch.cell(1,i); 00354 string val = patch.cell(2,i); 00355 config.put(key.c_str(),val.c_str()); 00356 dbg_printf("Set config variable %s -> %s\n", key.c_str(), val.c_str()); 00357 if (key=="order") { 00358 if (val=="named") { 00359 cc.ordered = false; 00360 cc.complete = false; 00361 cc.trustNames = true; 00362 } else if (val=="map") { 00363 cc.ordered = true; 00364 cc.complete = true; 00365 cc.trustNames = false; 00366 } else { 00367 fprintf(stderr,"key configuration unrecognized\n"); 00368 exit(1); 00369 } 00370 configSet = true; 00371 } 00372 } else if ((cmd0=="sheet"||cmd0=="table")&&cmd1=="name") { 00373 patcher->setSheet(patch.cell(2,i).c_str()); 00374 } else if (cmd0=="column") { 00375 OrderChange change; 00376 PatchColumnNames names2; 00377 names2.read(patch,name_start,i); 00378 len = (int)names2.lst.size(); 00379 if (names2.lst.size()>=1) { 00380 if (names2.lst[0]=="ROW" && support_name_ROW && name_start == 2) { 00381 name_start = 3; 00382 names2.read(patch,name_start,i); 00383 len = (int)names2.lst.size(); 00384 } 00385 } 00386 change.indicesBefore = names.indices; 00387 change.namesBefore = names.lst; 00388 change.namesAfter = names2.lst; 00389 allNames = names2.lst; 00390 match_column.clear(); 00391 assign_column.clear(); 00392 for (int i=0; i<len; i++) { 00393 match_column[names2.lst[i]] = true; 00394 assign_column[names2.lst[i]] = true; 00395 } 00396 if (cmd1=="name") { 00397 dbg_printf("Set column names to %s\n", names2.toString().c_str()); 00398 NameChange nc; 00399 nc.mode = NAME_CHANGE_DECLARE; 00400 nc.final = false; 00401 nc.names = names2.lst; 00402 allNames = nc.names; 00403 patcher->changeName(nc); 00404 //patcher->declareNames(names2.lst,false); 00405 } else if (cmd1=="move") { 00406 string mover = names2.inferMove(names,&change.subject,&change.object); 00407 dbg_printf("Moving columns to %s (%s moves // subj %d obj %d)\n", 00408 names2.toString().c_str(), 00409 mover.c_str(), 00410 change.subject, 00411 change.object); 00412 change.indicesAfter = names2.indices; 00413 change.mode = ORDER_CHANGE_MOVE; 00414 patcher->changeColumn(change); 00415 } else if (cmd1=="rename") { 00416 string mover = names2.inferRename(names,&change.subject); 00417 dbg_printf("Rename columns to %s (%s active // subj %d)\n", 00418 names2.toString().c_str(), 00419 mover.c_str(), 00420 change.subject); 00421 change.indicesAfter = names2.indices; 00422 change.mode = ORDER_CHANGE_RENAME; 00423 patcher->changeColumn(change); 00424 } else if (cmd1=="insert") { 00425 string mover = names2.inferInsert(names,&change.subject); 00426 dbg_printf("Inserting columns to %s (%s insert // subj %d)\n", 00427 names2.toString().c_str(), 00428 mover.c_str(), 00429 change.subject); 00430 change.indicesAfter = names2.indices; 00431 change.mode = ORDER_CHANGE_INSERT; 00432 patcher->changeColumn(change); 00433 } else if (cmd1=="delete") { 00434 string mover = names2.inferDelete(names,&change.subject); 00435 dbg_printf("Deleting columns from %s (%s delete // subj %d)\n", 00436 names2.toString().c_str(), 00437 mover.c_str(), 00438 change.subject); 00439 change.indicesAfter = names2.indices; 00440 change.mode = ORDER_CHANGE_DELETE; 00441 patcher->changeColumn(change); 00442 } else { 00443 fail = true; 00444 } 00445 if (!fail) { 00446 names = names2; 00447 } 00448 } else if (cmd0=="row"||cmd0=="link") { 00449 RowChange change; 00450 change.sequential = sequential; 00451 change.names = names.lst; 00452 change.allNames = allNames; 00453 for (int k=0; k<(int)change.names.size(); k++) { 00454 change.indexes[names.lst[k]] = true; 00455 } 00456 PatchColumnNames names2; 00457 if (cmd1=="columns"||cmd1=="name") { 00458 names2.read(patch,name_start,i); 00459 } else { 00460 names2.readData(patch,name_start,i,len); 00461 } 00462 if (cmd1=="columns"||cmd1=="name") { 00463 dbg_printf("Active columns %s\n", names2.toString().c_str()); 00464 names.lst = names2.lst; 00465 len = (int)names2.lst.size(); 00466 match_column.clear(); 00467 assign_column.clear(); 00468 for (int i=0; i<len; i++) { 00469 match_column[names.lst[i]] = true; 00470 assign_column[names.lst[i]] = true; 00471 } 00472 } else if (cmd1=="operate"||cmd1=="act") { 00473 dbg_printf("Operate columns %s: ", names2.dataString().c_str()); 00474 for (int i=0; i<len; i++) { 00475 string name = names.lst[i]; 00476 string code = names2.data[i].text; 00477 match_column[name] = code.find('*')!=string::npos; 00478 assign_column[name] = code.find('=')!=string::npos; 00479 dbg_printf("%d:%d ", match_column[name], 00480 assign_column[name]); 00481 } 00482 dbg_printf("\n"); 00483 } else if (cmd1=="select"||cmd1=="*") { 00484 sequential = true; 00485 dbg_printf("Selecting %s\n", names2.dataString().c_str()); 00486 selector = names2.data; 00487 needSelector = false; 00488 } else if (cmd1=="start") { 00489 sequential = true; 00490 RowChange change2; 00491 change2.mode = ROW_CHANGE_CONTEXT; 00492 ok = patcher->changeRow(change2); 00493 } else if (cmd1=="after") { 00494 sequential = true; 00495 dbg_printf("%s %s\n", cmd1.c_str(), names2.dataString().c_str()); 00496 change.mode = ROW_CHANGE_CONTEXT; 00497 for (int i=0; i<len; i++) { 00498 string name = names.lst[i]; 00499 const SheetCell& val = names2.data[i]; 00500 bool ok = match_column[name]; 00501 if (support_name_star && val.text=="*") ok = false; 00502 if (ok) { 00503 change.cond[change.names[i]] = val; 00504 } 00505 } 00506 ok = patcher->changeRow(change); 00507 } else if (cmd1=="move") { 00508 sequential = true; 00509 if (needSelector) { 00510 selector = names2.data; 00511 } 00512 dbg_printf("Moving to %s\n", names2.dataString().c_str()); 00513 change.mode = ROW_CHANGE_MOVE; 00514 for (int i=0; i<len; i++) { 00515 const SheetCell& sel = selector[i]; 00516 string name = names.lst[i]; 00517 bool ok = match_column[name]; 00518 if (support_name_star && sel.text=="*") ok = false; 00519 if (ok) { 00520 change.cond[change.names[i]] = sel; 00521 } 00522 const SheetCell& val = names2.data[i]; 00523 ok = assign_column[name]; 00524 if (support_name_star && val.text=="*") ok = false; 00525 if (ok) { 00526 change.val[change.names[i]] = val; 00527 //printf("assign %s %s\n", change.names[i].c_str(), val.toString().c_str()); 00528 } 00529 } 00530 ok = patcher->changeRow(change); 00531 needSelector = true; 00532 } else if (cmd1=="etc") { 00533 sequential = false; 00534 } else if (cmd1=="update"||cmd1=="=") { 00535 sequential = true; 00536 if (needSelector) { 00537 selector = names2.data; 00538 } 00539 dbg_printf("Updating to %s\n", names2.dataString().c_str()); 00540 change.mode = ROW_CHANGE_UPDATE; 00541 for (int i=0; i<len; i++) { 00542 const SheetCell& sel = selector[i]; 00543 string name = names.lst[i]; 00544 bool ok = match_column[name]; 00545 if (support_name_star && sel.text=="*") ok = false; 00546 if (ok) { 00547 change.cond[change.names[i]] = sel; 00548 } 00549 const SheetCell& val = names2.data[i]; 00550 ok = assign_column[name]; 00551 if (support_name_star && val.text=="*") ok = false; 00552 if (ok) { 00553 change.val[change.names[i]] = val; 00554 //printf("assign %s %s\n", change.names[i].c_str(), val.toString().c_str()); 00555 } 00556 } 00557 if (flags.canUpdate()) { 00558 ok = patcher->changeRow(change); 00559 } 00560 needSelector = true; 00561 } else if (cmd1=="insert") { 00562 sequential = true; 00563 if (needSelector) { 00564 selector = names2.data; 00565 } 00566 dbg_printf("Inserting %s\n", names2.dataString().c_str()); 00567 change.mode = ROW_CHANGE_INSERT; 00568 for (int i=0; i<len; i++) { 00569 string name = names.lst[i]; 00570 const SheetCell& val = names2.data[i]; 00571 bool ok = assign_column[name]; 00572 if (support_name_star && val.text=="*") ok = false; 00573 if (ok) { 00574 change.val[change.names[i]] = val; 00575 } 00576 } 00577 if (flags.canInsert()) { 00578 patcher->changeRow(change); 00579 } 00580 needSelector = true; 00581 } else if (cmd1=="delete") { 00582 sequential = true; 00583 if (needSelector) { 00584 selector = names2.data; 00585 } 00586 dbg_printf("Deleting %s\n", names2.dataString().c_str()); 00587 change.mode = ROW_CHANGE_DELETE; 00588 for (int i=0; i<len; i++) { 00589 string name = names.lst[i]; 00590 const SheetCell& val = names2.data[i]; 00591 bool ok = match_column[name]; 00592 if (support_name_star && val.text=="*") ok = false; 00593 if (ok) { 00594 change.cond[change.names[i]] = val; 00595 } 00596 } 00597 if (flags.canDelete()) { 00598 ok = patcher->changeRow(change); 00599 } 00600 needSelector = true; 00601 } else { 00602 fail = true; 00603 } 00604 } else { 00605 fail = true; 00606 } 00607 if (fail) { 00608 dbg_printf("%s %s ?\n", cmd0.c_str(), cmd1.c_str()); 00609 if (!coopy_is_verbose()) { 00610 fprintf(stderr,"%s %s ?\n", cmd0.c_str(), cmd1.c_str()); 00611 } 00612 fail = false; 00613 } else if (!ok) { 00614 dbg_printf("*** %s %s failed\n", cmd0.c_str(), cmd1.c_str()); 00615 if (!coopy_is_verbose()) { 00616 fprintf(stderr,"*** %s %s failed\n", cmd0.c_str(), cmd1.c_str()); 00617 } 00618 fail = false; 00619 } 00620 } 00621 00622 patcher->mergeDone(); 00623 patcher->mergeAllDone(); 00624 00625 return true; 00626 } 00627 00628 vector<string> normalizedMessage(const string& line) { 00629 vector<string> all; 00630 string result; 00631 bool white = true; 00632 bool quote = false; 00633 bool pending = false; 00634 bool commit = false; 00635 bool haveBars = false; 00636 for (int i=0; i<(int)line.length(); i++) { 00637 char ch = line[i]; 00638 if (ch=='\'') { 00639 quote = !quote; 00640 result += ch; 00641 pending = true; 00642 } else if (quote) { 00643 result += ch; 00644 pending = true; 00645 } else if (((ch==' '||ch=='\r'||ch=='\t')&&!commit)||ch=='|') { 00646 if (pending) { 00647 all.push_back(result); 00648 pending = false; 00649 } 00650 result = ""; 00651 white = true; 00652 if (ch=='|') { 00653 pending = true; 00654 commit = true; 00655 haveBars = true; 00656 } 00657 } else { 00658 white = false; 00659 result += ch; 00660 pending = true; 00661 } 00662 } 00663 if (pending&&result!=""&&!haveBars) { 00664 all.push_back(result); 00665 pending = false; 00666 } 00667 00668 for (int i=0; i<(int)all.size(); i++) { 00669 string& result = all[i]; 00670 Stringer::replace(result,"\\n","\n"); 00671 Stringer::replace(result,"\\r","\r"); 00672 Stringer::replace(result,"\\\\","\\"); 00673 00674 //if (result[0]=='\'') { 00675 //result = result.substr(1,result.length()-2); 00676 //} 00677 } 00678 00679 00680 return all; 00681 } 00682 00683 class TDiffPart { 00684 public: 00685 string orig; 00686 00687 string key; 00688 SheetCell val; 00689 SheetCell nval; 00690 SheetCell cval; 00691 SheetCell pval; 00692 bool hasKey; 00693 bool hasVal; 00694 bool hasNval; 00695 bool hasCval; 00696 bool hasPval; 00697 00698 bool conflict; 00699 00700 bool isId; 00701 bool isFresh; 00702 00703 TDiffPart() { 00704 isId = false; 00705 isFresh = false; 00706 hasKey = false; 00707 hasVal = false; 00708 hasNval = false; 00709 hasCval = false; 00710 hasPval = false; 00711 conflict = false; 00712 } 00713 00714 TDiffPart(const string& s, bool columnLike) { 00715 apply(s, columnLike); 00716 } 00717 00718 00719 string peel(const string& s, string& sep, string& rem, bool& hasQuote) { 00720 hasQuote = false; 00721 char quoter = '\0'; 00722 bool acceptSingle = true; 00723 bool acceptDouble = true; 00724 bool allowDouble = false; 00725 bool quote = false; 00726 int cc = -1; 00727 int state = 0; 00728 int pre = -2; 00729 sep = ""; 00730 bool first = true; 00731 for (int i=0; i<(int)s.length(); i++) { 00732 char ch = s[i]; 00733 bool was_first = first; 00734 first = false; 00735 if ((allowDouble&&ch=='\"'&&acceptDouble)||(ch=='\''&&acceptSingle)) { 00736 if (was_first) { 00737 hasQuote = true; 00738 quoter = ch; 00739 } 00740 state = 0; 00741 quote = !quote; 00742 if (ch=='\"'&"e) { 00743 acceptSingle = false; 00744 } 00745 if (ch=='\''&"e) { 00746 acceptDouble = false; 00747 } 00748 if (!quote) { 00749 acceptSingle = acceptDouble = true; 00750 } 00751 } else if (quote) { 00752 state = 0; 00753 } else if (ch==':'&&state==0&&pre==-2) { 00754 pre = i-1; 00755 sep = ":"; 00756 break; 00757 } else if (ch=='='&&state==0&&pre==-2) { 00758 pre = i-1; 00759 sep = "="; 00760 break; 00761 } else if (ch=='-'&&state==0&&pre==-2) { 00762 state = 1; 00763 } else if (ch=='>'&&state==1) { 00764 pre = i-2; 00765 sep = "->"; 00766 break; 00767 } else if (ch=='!') { 00768 conflict = true; 00769 if (cc==-1) { 00770 cc = i; 00771 if (i==0) { 00772 first = true; 00773 } 00774 } else { 00775 sep = "!"; 00776 pre = i-1; 00777 break; 00778 } 00779 } else { 00780 state = 0; 00781 } 00782 } 00783 string result = s; 00784 rem = ""; 00785 if (pre!=-2) { 00786 result = s.substr(0,pre+1); 00787 if (result[0]=='!') result = result.substr(1,result.length()-1); 00788 rem = s.substr(pre+sep.length()+1,s.length()); 00789 //if (rem[0]=='!') rem = rem.substr(1,rem.length()-1); 00790 } 00791 if (hasQuote) { 00792 result = result.substr(1,result.length()-2); 00793 if (quoter=='\'') { 00794 Stringer::replace(result,"''","'"); 00795 } else { 00796 Stringer::replace(result,"\"\"","\""); 00797 } 00798 } 00799 return result; 00800 } 00801 00802 SheetCell getCell(const string& txt, bool quoted) { 00803 SheetCell result; 00804 if (quoted) { 00805 result.text = txt; 00806 result.escaped = false; 00807 //printf("Made cell %s from %s\n", result.toString().c_str(), txt.c_str()); 00808 return result; 00809 } 00810 if (txt=="NULL") { 00811 result.escaped = true; 00812 result.text = txt; 00813 return result; 00814 } 00815 result.text = txt; 00816 result.escaped = false; 00817 return result; 00818 } 00819 00820 bool checkCell(const string& txt, bool quoted) { 00821 if (quoted) return true; 00822 return (txt!="*"); 00823 } 00824 00825 void applyElement(const string& txt, 00826 const string& pre, 00827 string& post, 00828 bool quoted, 00829 bool columnLike) { 00830 /* 00831 printf("applyElement [%s] [%s] [%s], %s, %s\n", 00832 pre.c_str(), txt.c_str(), post.c_str(), 00833 quoted?"quoted":"unquoted", 00834 columnLike?"column":"value"); 00835 */ 00836 00837 if (post=="!") { 00838 if (checkCell(txt,quoted)) { 00839 pval = getCell(txt,quoted); 00840 hasPval = true; 00841 } 00842 post = pre; 00843 return; 00844 } 00845 00846 if (pre=="") { 00847 if ((!columnLike)&&(post!="="&&post!=":")) { 00848 if (checkCell(txt,quoted)) { 00849 val = getCell(txt,quoted); 00850 hasVal = true; 00851 } 00852 } else { 00853 key = txt; 00854 hasKey = true; 00855 } 00856 } else if (pre=="->") { 00857 if (!columnLike) { 00858 if (checkCell(txt,quoted)) { 00859 nval = getCell(txt,quoted); 00860 hasNval = true; 00861 } 00862 if (!hasVal) { 00863 isFresh = true; 00864 } 00865 } else { 00866 isFresh = true; 00867 } 00868 } else if (pre=="="||pre==":") { 00869 isId = (pre=="="); 00870 if (!columnLike) { 00871 if (checkCell(txt,quoted)) { 00872 val = getCell(txt,quoted); 00873 hasVal = true; 00874 } 00875 } 00876 } 00877 } 00878 00879 void apply(const string& s, bool columnLike) { 00880 orig = s; 00881 hasKey = false; 00882 hasVal = false; 00883 hasNval = false; 00884 hasCval = false; 00885 conflict = false; 00886 00887 isId = false; 00888 isFresh = false; 00889 00890 string sep1, r1, rem1; 00891 string sep2, r2, rem2; 00892 string sep3, r3, rem3; 00893 string sep4, r4, rem4; 00894 bool q1, q2, q3, q4; 00895 bool set1, set2, set3, set4; 00896 set1 = set2 = set3 = set4 = false; 00897 00898 r1 = peel(s,sep1,rem1, q1); 00899 set1 = true; 00900 if (sep1!="") { 00901 r2 = peel(rem1,sep2,rem2, q2); 00902 set2 = true; 00903 if (sep2!="") { 00904 r3 = peel(rem2,sep3,rem3, q3); 00905 set3 = true; 00906 if (sep3!="") { 00907 r4 = peel(rem3,sep4,rem4, q4); 00908 set4 = true; 00909 } 00910 } 00911 } 00912 00913 //printf("Input %s\n", s.c_str()); 00914 //printf(" %s %s %s\n", r1.c_str(), sep1.c_str(), rem1.c_str()); 00915 //printf(" %s %s %s\n", r2.c_str(), sep2.c_str(), rem2.c_str()); 00916 //printf(" %s %s %s\n", r3.c_str(), sep3.c_str(), rem3.c_str()); 00917 00918 if (set1) applyElement(r1,"",sep1,q1,columnLike); 00919 if (set2) applyElement(r2,sep1,sep2,q2,columnLike); 00920 if (set3) applyElement(r3,sep2,sep3,q3,columnLike); 00921 if (set4) applyElement(r4,sep3,sep4,q4,columnLike); 00922 00923 if (conflict) { 00924 if (hasNval) { 00925 hasCval = true; 00926 cval = nval; 00927 if (hasVal) { 00928 nval = val; 00929 } 00930 } 00931 } 00932 } 00933 00934 string toString() const { 00935 SheetCell b; 00936 return string("(") + (hasKey?key:b.text) + "," + 00937 (hasVal?val:b).text + "," + 00938 (hasNval?nval:b).text + "," + 00939 (hasNval?cval:b).text + ")"; 00940 } 00941 00942 }; 00943 00944 string stringer_encoder(const TDiffPart& part) { 00945 return string("[") + part.orig + (part.isId?";id":"") + (part.isFresh?";fresh":"") + "]"; 00946 } 00947 00948 00949 bool PatchParser::applyTdiff() { 00950 vector<string> allNames; 00951 00952 patcher->mergeStart(); 00953 00954 bool eof = false; 00955 vector<TDiffPart> cols; 00956 bool inComment = false; 00957 while (!eof) { 00958 string line = sniffer.readLine(eof); 00959 if (inComment) { 00960 if (line.find("*/")!=string::npos) { 00961 inComment = false; 00962 } else { 00963 dbg_printf("Ignoring comment [%s]\n", line.c_str()); 00964 } 00965 continue; 00966 } 00967 vector<string> msg = normalizedMessage(line); 00968 if (msg.size()==0) { 00969 //dbg_printf("Empty line\n"); 00970 continue; 00971 } 00972 string first = msg[0]; 00973 bool conflict = false; 00974 if (first[0]=='#') { 00975 dbg_printf("Ignoring comment [%s]\n", line.c_str()); 00976 continue; 00977 } 00978 if (first[0]=='!') { 00979 dbg_printf("Conflict line [%s]\n", line.c_str()); 00980 conflict = true; 00981 first = first.substr(1,first.length()-1); 00982 } 00983 if (first.length()>=2) { 00984 if (first[0]=='/') { 00985 if (first[1]=='*') { 00986 dbg_printf("Ignoring comment [%s]\n", line.c_str()); 00987 inComment = true; 00988 continue; 00989 } 00990 } 00991 } 00992 if (coopy_is_verbose()) { 00993 dbg_printf("Got: "); 00994 for (int i=0; i<(int)msg.size(); i++) { 00995 dbg_printf("[%s] ", msg[i].c_str()); 00996 } 00997 dbg_printf("\n"); 00998 } 00999 if (first=="@@@") { 01000 table_name = msg[1]; 01001 patcher->setSheet(table_name.c_str()); 01002 allNames.clear(); 01003 } else if (first=="x") { 01004 PoolChange pc; 01005 if (msg.size()>=2) { 01006 string poolName = msg[1]; 01007 for (int i=2; i<(int)msg.size(); i++) { 01008 TDiffPart part(msg[i],true); 01009 if (part.hasKey) { 01010 TableField f; 01011 string f2 = part.key; 01012 string f1 = ""; 01013 if (f2.find(".")!=string::npos) { 01014 f1 = f2.substr(0,f2.find(".")); 01015 f2 = f2.substr(f2.find(".")+1,f2.length()); 01016 } 01017 f.tableName = f1; 01018 f.fieldName = f2; 01019 f.invented = part.isId; 01020 pc.pool.push_back(f); 01021 } 01022 } 01023 pc.poolName = poolName; 01024 pc.tableName = table_name; 01025 if (pc.pool.size()>0) { 01026 patcher->changePool(pc); 01027 } 01028 } 01029 } else if (first=="@"||first=="@@"||first=="@@=") { 01030 vector<string> names; 01031 cols.clear(); 01032 for (int i=1; i<(int)msg.size(); i++) { 01033 cols.push_back(TDiffPart(msg[i],true)); 01034 names.push_back(cols[i-1].key); 01035 } 01036 if (first=="@@"||first=="@@=") { 01037 needTable(); 01038 NameChange nc; 01039 nc.mode = NAME_CHANGE_DECLARE; 01040 nc.final = false; 01041 nc.strong = (first=="@@="); 01042 nc.names = names; 01043 patcher->changeName(nc); 01044 } 01045 /* 01046 printf("Columns set to: "); 01047 for (int i=0; i<(int)cols.size(); i++) { 01048 printf("\"%s\" ", cols[i].base.c_str()); 01049 } 01050 printf("\n"); 01051 */ 01052 } else if (first=="@:"||first=="@+"||first=="@-"||first=="@=") { 01053 needTable(); 01054 vector<string> ocols; 01055 vector<string> ncols; 01056 for (int i=0; i<(int)cols.size(); i++) { 01057 ocols.push_back(cols[i].key); 01058 } 01059 for (int i=2; i<(int)msg.size(); i++) { 01060 ncols.push_back(TDiffPart(msg[i],true).key); 01061 } 01062 if (first=="@+" && ncols.size()==0) { 01063 ncols.push_back(msg[1].c_str()); 01064 } 01065 01066 OrderChange change; 01067 PatchColumnNames names; 01068 PatchColumnNames names2; 01069 names.read(ocols,0); 01070 names2.read(ncols,0); 01071 if (first=="@:") { 01072 string mover = names2.inferMove(names,&change.subject,&change.object, 01073 msg[1].c_str()); 01074 dbg_printf("Moving columns to %s (%s moves // subj %d obj %d)\n", 01075 names2.toString().c_str(), 01076 mover.c_str(), 01077 change.subject, 01078 change.object); 01079 change.mode = ORDER_CHANGE_MOVE; 01080 } else if (first=="@+") { 01081 string mover = names2.inferInsert(names,&change.subject,msg[1].c_str()); 01082 dbg_printf("Inserting columns to %s (%s insert // subj %d)\n", 01083 names2.toString().c_str(), 01084 mover.c_str(), 01085 change.subject); 01086 change.mode = ORDER_CHANGE_INSERT; 01087 } else if (first=="@-") { 01088 string mover = names2.inferDelete(names,&change.subject,msg[1].c_str()); 01089 dbg_printf("Deleting columns from %s (%s delete // subj %d)\n", 01090 names2.toString().c_str(), 01091 mover.c_str(), 01092 change.subject); 01093 change.mode = ORDER_CHANGE_DELETE; 01094 } else if (first=="@=") { 01095 string mover = names2.inferRename(names,&change.subject,msg[1].c_str()); 01096 dbg_printf("Renaming columns to %s (%s insert // subj %d)\n", 01097 names2.toString().c_str(), 01098 mover.c_str(), 01099 change.subject); 01100 change.mode = ORDER_CHANGE_RENAME; 01101 } 01102 change.indicesBefore = names.indices; 01103 change.indicesAfter = names2.indices; 01104 change.namesBefore = names.lst; 01105 change.namesAfter = names2.lst; 01106 allNames = change.namesAfter; 01107 patcher->changeColumn(change); 01108 01109 cols.clear(); 01110 for (int i=2; i<(int)msg.size(); i++) { 01111 cols.push_back(TDiffPart(msg[i],true)); 01112 } 01113 01114 } else if (first=="="||first=="-"||first=="+"||first=="*"||first==":") { 01115 needTable(); 01116 vector<TDiffPart> assign; 01117 bool mod = false; 01118 for (int i=1; i<(int)msg.size(); i++) { 01119 TDiffPart part; 01120 part.apply(msg[i],false); 01121 dbg_printf("key %d [%s] / val %d [%s] / nval %d [%s]\n", 01122 (int)part.hasKey, part.key.c_str(), 01123 (int)part.hasVal, part.val.toString().c_str(), 01124 (int)part.hasNval, part.nval.toString().c_str()); 01125 01126 assign.push_back(part); 01127 if (part.hasKey) { mod = true; } 01128 } 01129 if (mod) { 01130 cols.clear(); 01131 for (int i=1; i<(int)msg.size(); i++) { 01132 TDiffPart& a = assign[i-1]; 01133 TDiffPart context = a; 01134 context.hasVal = false; 01135 context.hasNval = false; 01136 context.hasCval = false; 01137 a.hasKey = false; 01138 cols.push_back(context); 01139 } 01140 } 01141 dbg_printf(" assign %s\n", vector2string(assign).c_str()); 01142 dbg_printf(" cols %s\n", vector2string(cols).c_str()); 01143 while (assign.size()<cols.size()) { 01144 cols.erase(cols.begin()+assign.size()); 01145 } 01146 if (cols.size()<assign.size()) { 01147 if (cols.size()==0) { 01148 for (int i=0; i<(int)assign.size(); i++) { 01149 //cols.push_back(TDiffPart(Stringer::getSpreadsheetColumnName(i),true)); 01150 cols.push_back(TDiffPart(string("[")+stringer_encoder(i)+"]",true)); 01151 } 01152 } 01153 } 01154 COOPY_ASSERT(assign.size()==cols.size()); 01155 01156 RowChange change; 01157 change.conflicted = conflict; 01158 bool allIndex = false; 01159 bool skip = false; 01160 if (first=="=") { 01161 change.mode = ROW_CHANGE_UPDATE; 01162 skip = !flags.canUpdate(); 01163 } else if (first=="-") { 01164 change.mode = ROW_CHANGE_DELETE; 01165 skip = !flags.canDelete(); 01166 } else if (first=="+") { 01167 change.mode = ROW_CHANGE_INSERT; 01168 skip = !flags.canInsert(); 01169 } else if (first=="*") { 01170 change.mode = ROW_CHANGE_CONTEXT; 01171 if (!flags.use_order) skip = true; 01172 } else if (first==":") { 01173 change.mode = ROW_CHANGE_MOVE; 01174 skip = !flags.canUpdate(); 01175 if (!flags.use_order) skip = true; 01176 } 01177 change.indexes.clear(); 01178 for (int i=0; i<(int)assign.size(); i++) { 01179 TDiffPart& context = cols[i]; 01180 TDiffPart& part = assign[i]; 01181 dbg_printf(" Looking at {{%s // %s // %s // %s}} and {{%s // %s // %s // %s}}\n", 01182 context.orig.c_str(), context.key.c_str(), context.val.text.c_str(), context.nval.text.c_str(), 01183 part.orig.c_str(), part.key.c_str(), part.val.text.c_str(), part.nval.text.c_str() 01184 ); 01185 bool conded = false; 01186 if (part.hasVal) { 01187 if (context.hasKey&&change.mode!=ROW_CHANGE_INSERT) { 01188 if (!context.isFresh) { 01189 change.cond[context.key.c_str()] = part.val; 01190 conded = true; 01191 } 01192 } 01193 } 01194 if (context.isId||allIndex) { 01195 if (part.hasVal) { 01196 change.indexes[context.key.c_str()] = true; 01197 } 01198 } 01199 if (part.hasNval||change.mode==ROW_CHANGE_INSERT) { 01200 if (part.hasNval) { 01201 change.val[context.key.c_str()] = part.nval; 01202 if (part.hasCval) { 01203 change.conflictingVal[context.key.c_str()] = part.cval; 01204 } 01205 if (part.hasPval) { 01206 change.conflictingParentVal[context.key.c_str()] = part.pval; 01207 } 01208 } else { 01209 if (!conded) { 01210 change.val[context.key.c_str()] = part.val; 01211 } 01212 } 01213 } 01214 if (context.isFresh) { 01215 if (part.hasVal) { 01216 if (!conded) { 01217 change.val[context.key.c_str()] = part.val; 01218 } 01219 } 01220 } 01221 // Testing: change all cells to "zig" 01222 // if (change.val.find(context.key.c_str())!=change.val.end()) { 01223 // change.val[context.key.c_str()] = SheetCell("zig",false); 01224 // } 01225 change.names.push_back(context.key.c_str()); 01226 } 01227 if (change.names.size()>allNames.size()) { 01228 allNames = change.names; 01229 } 01230 change.allNames = allNames; 01231 dbg_printf(" ... change row ...\n"); 01232 if (!skip) { 01233 patcher->changeRow(change); 01234 } 01235 } 01236 } 01237 01238 dbg_printf(" ... patching complete! ...\n"); 01239 01240 patcher->mergeDone(); 01241 patcher->mergeAllDone(); 01242 01243 dbg_printf(" ... PatchParser finished ...\n"); 01244 01245 return true; 01246 } 01247 01248 01249 static bool checkAllowed(DataSheet& sheet, int i, bool allowed) { 01250 if (sheet.height()<=i) return false; 01251 SheetCell cell = sheet.cellSummary(0,i); 01252 string c = cell.text; 01253 if (cell.escaped) c = ""; 01254 if (c[0]=='N'||c[0]=='n'||c[0]=='0') { 01255 allowed = false; 01256 } 01257 if (c[0]=='Y'||c[0]=='y'||c[0]=='1') { 01258 allowed = true; 01259 } 01260 return allowed; 01261 } 01262 01263 01264 bool PatchParser::applyColor() { 01265 sniffer.close(); 01266 PolyBook book; 01267 if (!book.read(fname.c_str())) { 01268 fprintf(stderr, "Don't know what to do with %s\n", fname.c_str()); 01269 return false; 01270 } 01271 return applyHiliteBook(book); 01272 } 01273 01274 static string remap(map<string,string>& m, const string& s) { 01275 map<string,string>::const_iterator it = m.find(s); 01276 if (it!=m.end()) return it->second; 01277 return s; 01278 } 01279 01280 static int remap(map<int,int>& m, int s) { 01281 map<int,int>::const_iterator it = m.find(s); 01282 if (it!=m.end()) return it->second; 01283 return s; 01284 } 01285 01286 static int remap(vector<int>& m, int s) { 01287 return m[s]; 01288 } 01289 01290 static void shuffle(vector<int>& indexMap, int j, int jj, bool undo) { 01291 // What is at j came from offset jj 01292 dbg_printf(">>> Move to %d, offset %d\n", j, jj); 01293 vector<int> indexMap2; 01294 int at = 0; 01295 for (int i=0; i<(int)indexMap.size()+1; i++) { 01296 if (at==j) { 01297 indexMap2.push_back(indexMap[j+jj]); 01298 at++; 01299 } 01300 if (i!=j+jj&&i<(int)indexMap.size()) { 01301 indexMap2.push_back(indexMap[i]); 01302 at++; 01303 } 01304 dbg_printf(" %s / %s\n", 01305 vector2string(indexMap2).c_str(), 01306 vector2string(indexMap).c_str()); 01307 } 01308 indexMap = indexMap2; 01309 } 01310 01311 bool PatchParser::applyHiliteBook(coopy::store::TextBook& book) { 01312 01313 patcher->mergeStart(); 01314 01315 vector<string> names = book.getNames(); 01316 bool needDeclare = false; 01317 for (int s=0; s<(int)names.size(); s++) { 01318 string name = names[s]; 01319 patcher->setSheet(name.c_str()); 01320 PolySheet sheet = book.readSheet(name); 01321 if (sheet.width()<2) { 01322 fprintf(stderr, "Not a diff: %s\n", fname.c_str()); 01323 return false; 01324 } 01325 vector<string> cols; 01326 vector<string> activeCol; 01327 vector<string> statusCol; 01328 vector<string> nameCol; 01329 vector<string> origCol; 01330 vector<int> offsetCol; 01331 vector<int> rootCol; 01332 RowChange::txt2bool indexes; 01333 int xoff = 1; 01334 int yoff = 0; 01335 bool needYes = false; 01336 for (int i=0; i<sheet.height(); i++) { 01337 string c = sheet.cellString(0,i); 01338 if (c[0]=='@'||c[0]=='-'||c[0]=='+') { 01339 xoff = 0; 01340 break; 01341 } 01342 if (c=="yes"||c=="YES"||c=="Yes") { 01343 needYes = true; 01344 } 01345 } 01346 01347 for (int i=0; i<sheet.height(); i++) { 01348 bool allowed = true; 01349 bool willBeAllowed = true; 01350 if (xoff==1) { 01351 if (needYes) { 01352 allowed = false; 01353 willBeAllowed = false; 01354 } 01355 allowed = checkAllowed(sheet,i,allowed); 01356 willBeAllowed = checkAllowed(sheet,i+1,willBeAllowed); 01357 } 01358 01359 RowChange change; 01360 change.names = activeCol; 01361 //change.allNames = cols; 01362 change.allNames = activeCol; 01363 dbg_printf("Columns are %s\n",vector2string(cols).c_str()); 01364 change.indexes = indexes; 01365 string code = sheet.cellString(xoff,i); 01366 string tail2 = ""; 01367 if (code.length()>=2) { 01368 tail2 = code.substr(code.length()-2,2); 01369 } 01370 dbg_printf("Code is %s, allowed is %d, needYes is %d\n", code.c_str(), 01371 allowed, needYes); 01372 if (code[0] == '@') { 01373 cols.clear(); 01374 bool acts = false; 01375 if (i>0) { 01376 if (sheet.cellString(xoff,i-1)=="!") { 01377 acts = true; 01378 } 01379 } 01380 for (int j=1+xoff; j<sheet.width(); j++) { 01381 TDiffPart p(sheet.cellString(j,i),false); 01382 dbg_printf(" COLUMN %s\n", p.toString().c_str()); 01383 string txt = p.hasNval?p.nval.text:p.val.text; 01384 cols.push_back(txt); 01385 activeCol.push_back(txt); 01386 statusCol.push_back(""); 01387 offsetCol.push_back(0); 01388 rootCol.push_back(-1); 01389 nameCol.push_back(""); 01390 indexes[txt] = true; 01391 } 01392 if (acts) { 01393 activeCol.clear(); 01394 int org_ct = 0; 01395 for (int j=1+xoff; j<sheet.width(); j++) { 01396 string act = sheet.cellString(j,i-1); 01397 string col = cols[j-1-xoff]; 01398 //printf("[%s] [%s]\n", act.c_str(), col.c_str()); 01399 01400 bool haveName = act.find("(")!=string::npos; 01401 if (act=="+++") { 01402 statusCol[j-1-xoff] = act; 01403 indexes[col] = false; 01404 } else { 01405 if (!haveName) { 01406 origCol.push_back(col); 01407 } 01408 } 01409 if (act=="---") { 01410 statusCol[j-1-xoff] = act; 01411 indexes[col] = false; 01412 } else { 01413 activeCol.push_back(col); 01414 } 01415 string rem = act; 01416 if (haveName) { 01417 int at = 0; 01418 while (rem[at]=='<'||rem[at]=='>') { 01419 at++; 01420 } 01421 act = rem.substr(0,at); 01422 rem = rem.substr(at,rem.length()-at); 01423 COOPY_ASSERT(rem[0]=='('); 01424 //statusCol[j-1-xoff] = "="; 01425 nameCol[j-1-xoff] = rem.substr(1,rem.length()-2); 01426 origCol.push_back(nameCol[j-1-xoff]); 01427 } 01428 if (act[0]=='<'||act[0]=='>') { 01429 statusCol[j-1-xoff] = "<>"; 01430 offsetCol[j-1-xoff] = act.length()*((act[0]=='>')?-1:1); 01431 } 01432 if (act!="+++") { 01433 rootCol[j-1-xoff] = org_ct; 01434 org_ct++; 01435 } 01436 } 01437 01438 vector<int> indexMap; 01439 vector<int> indexMapBase; 01440 indexMap.clear(); 01441 for (int j=0; j<(int)origCol.size(); j++) { 01442 indexMap.push_back(j); 01443 } 01444 indexMapBase = indexMap; 01445 01446 int at = 0; 01447 //printf("MAP %s\n", vector2string(indexMap).c_str()); 01448 for (int j=0; j<(int)rootCol.size(); j++) { 01449 string act = statusCol[j]; 01450 if (act!="<>") continue; 01451 int rr = rootCol[j]; 01452 int jj = offsetCol[j]; 01453 //printf(":: %d %d\n", rr, jj); 01454 int tmp = indexMap[rr+jj]; 01455 indexMap[rr+jj] = rr; 01456 if (indexMap[rr] == rr) { 01457 indexMap[rr] = tmp; 01458 } 01459 //printf("%d vs %d\n", j, jj); 01460 //shuffle(indexMap,j+jj,-jj,true); 01461 //indexMap[j] = jj; 01462 //indexMap[jj] = j; 01463 } 01464 //printf("MAP %s\n", vector2string(indexMap).c_str()); 01465 Mover mover; 01466 vector<int> move_order; 01467 mover.move(indexMapBase,indexMap,move_order); 01468 //printf("MOVES %s\n", vector2string(move_order).c_str()); 01469 01470 NameChange nc; 01471 nc.mode = NAME_CHANGE_DECLARE; 01472 nc.final = false; 01473 vector<int> local_cols; 01474 vector<int> shuffled_cols; 01475 vector<string> local_col_names; 01476 for (int j=0; j<(int)origCol.size(); j++) { 01477 nc.names.push_back(origCol[remap(indexMap,j)]); 01478 local_cols.push_back(remap(indexMap,j)); 01479 shuffled_cols.push_back(j); 01480 local_col_names.push_back(origCol[remap(indexMap,j)]); 01481 } 01482 origCol = nc.names; 01483 patcher->changeName(nc); 01484 01485 indexMap = indexMapBase; 01486 01487 for (int m=0; m<(int)move_order.size(); m++) { 01488 int a = move_order[m]; 01489 dbg_printf("Move %d\n", a); 01490 01491 OrderChange change; 01492 change.indicesBefore = local_cols; 01493 change.namesBefore = local_col_names; 01494 vector<int>::iterator it = std::find(local_cols.begin(), 01495 local_cols.end(), 01496 a); 01497 if (it==local_cols.end()) { 01498 fprintf(stderr,"Merge logic failure\n"); 01499 exit(1); 01500 } 01501 vector<int>::iterator it2 = std::find(shuffled_cols.begin(), 01502 shuffled_cols.end(), 01503 a); 01504 if (it2==shuffled_cols.end()) { 01505 fprintf(stderr,"Merge logic failure\n"); 01506 exit(1); 01507 } 01508 change.subject = *it; 01509 change.object = *it2; 01510 int idx = it-local_cols.begin(); 01511 int idx2 = it2-shuffled_cols.begin(); 01512 change.mode = ORDER_CHANGE_MOVE; 01513 local_cols.erase(it); 01514 string name = local_col_names[idx]; 01515 change.object = *it2; 01516 local_col_names.erase(local_col_names.begin()+idx); 01517 local_cols.insert(local_cols.begin()+idx2,a); 01518 local_col_names.insert(local_col_names.begin()+idx2,name); 01519 change.indicesAfter = local_cols; 01520 change.namesAfter = local_col_names; 01521 if (change.namesBefore!=change.namesAfter) { 01522 patcher->changeColumn(change); 01523 } 01524 } 01525 01526 /* 01527 for (int j=0; j<(int)origCol.size(); j++) { 01528 string act = statusCol[j]; 01529 if (act!="<>") continue; 01530 01531 OrderChange order; 01532 order.mode = ORDER_CHANGE_MOVE; 01533 01534 for (int k=0; k<(int)origCol.size(); k++) { 01535 order.namesBefore.push_back(origCol[remap(indexMap,k)]); 01536 order.indicesBefore.push_back(remap(indexMap,k)); 01537 } 01538 01539 int jj = offsetCol[j]; 01540 shuffle(indexMap,j,jj,false); 01541 01542 for (int k=0; k<(int)origCol.size(); k++) { 01543 order.namesAfter.push_back(origCol[remap(indexMap,k)]); 01544 order.indicesAfter.push_back(remap(indexMap,k)); 01545 } 01546 01547 order.subject = j+jj; 01548 patcher->changeColumn(order); 01549 } 01550 */ 01551 01552 for (int j=0; j<(int)cols.size(); j++) { 01553 string nact = nameCol[j]; 01554 if (nact!="") { statusCol[j] = "="; } 01555 } 01556 for (int j=0; j<(int)cols.size(); j++) { 01557 string act = statusCol[j]; 01558 if (act=="") continue; 01559 if (act=="<>") continue; 01560 OrderChange order; 01561 if (act=="+++") { 01562 order.mode = ORDER_CHANGE_INSERT; 01563 } else if (act=="---") { 01564 order.mode = ORDER_CHANGE_DELETE; 01565 } else if (act=="=") { 01566 order.mode = ORDER_CHANGE_RENAME; 01567 } 01568 for (int k=0; k<(int)cols.size(); k++) { 01569 string actk = statusCol[k]; 01570 if (actk=="" || actk=="=" || actk=="<>" || 01571 (k>=j&&actk=="---") || (k<j&&actk=="+++")) { 01572 if (actk=="="&&k>=j) { 01573 order.namesBefore.push_back(nameCol[k]); 01574 } else { 01575 order.namesBefore.push_back(cols[k]); 01576 } 01577 order.indicesBefore.push_back((actk=="+++")?-(k+1):k); 01578 } 01579 } 01580 for (int k=0; k<(int)cols.size(); k++) { 01581 string actk = statusCol[k]; 01582 if (actk=="" || actk=="=" || actk=="<>" || 01583 (k>j&&actk=="---") || (k<=j&&actk=="+++")) { 01584 if (actk=="="&&k>j) { 01585 order.namesAfter.push_back(nameCol[k]); 01586 } else { 01587 order.namesAfter.push_back(cols[k]); 01588 } 01589 order.indicesAfter.push_back((actk=="+++")?-(k+1):k); 01590 } 01591 } 01592 order.subject = (act=="+++")?-(j+1):j; 01593 patcher->changeColumn(order); 01594 } 01595 } 01596 code = code.substr(1,code.length()); 01597 01598 NameChange nc; 01599 nc.mode = NAME_CHANGE_DECLARE; 01600 nc.final = true; 01601 nc.names = activeCol; 01602 patcher->changeName(nc); 01603 } 01604 if (code == "+++") { 01605 change.mode = ROW_CHANGE_INSERT; 01606 for (int j=1+xoff; j<sheet.width(); j++) { 01607 SheetCell c = sheet.cellSummary(j,i); 01608 change.val[cols[j-1-xoff]] = c; 01609 } 01610 if (flags.canInsert()) { 01611 if (allowed) patcher->changeRow(change); 01612 } 01613 } else if (code == "---") { 01614 change.mode = ROW_CHANGE_DELETE; 01615 for (int j=1+xoff; j<sheet.width(); j++) { 01616 SheetCell c = sheet.cellSummary(j,i); 01617 if (!c.escaped) { 01618 change.cond[cols[j-1-xoff]] = c; 01619 } 01620 } 01621 if (flags.canDelete()) { 01622 if (allowed) patcher->changeRow(change); 01623 } 01624 } else if ((tail2 == "->"||code=="+")) { // && code.find("!")==string::npos) { 01625 change.mode = ROW_CHANGE_UPDATE; 01626 int minuses = 0; 01627 string separator, conflict_separator, full_separator; 01628 if (code!="+") { 01629 separator = code; //code.substr(code.find("-"),code.length()); 01630 if (separator[0]=='@') separator = separator.substr(1,separator.length()); 01631 if (separator[0]=='@') separator = separator.substr(1,separator.length()); 01632 full_separator = separator; 01633 if (separator.find("!")!=string::npos) { 01634 conflict_separator = full_separator; 01635 separator = full_separator.substr(separator.find("!")+1,separator.length()); 01636 } 01637 } 01638 for (int j=1+xoff; j<sheet.width(); j++) { 01639 SheetCell c = sheet.cellSummary(j,i); 01640 bool done = false; 01641 string col = cols[j-1-xoff]; 01642 bool added = statusCol[j-1-xoff]=="+++"; 01643 if (!c.escaped) { 01644 //printf("Looking at [%s], separator [%s]\n", 01645 //c.toString().c_str(), separator.c_str()); 01646 if (code=="+") { 01647 change.val[col] = c; 01648 } else { 01649 string::size_type offset = c.text.find(separator); 01650 if (offset!=string::npos) { 01651 // check for conflict 01652 bool conflict = false; 01653 if (conflict_separator!="") { 01654 string::size_type coffset = c.text.find(conflict_separator); 01655 if (coffset!=string::npos) { 01656 conflict = true; 01657 string s1 = c.text.substr(0,coffset); 01658 string s2 = c.text.substr(coffset+conflict_separator.length(), 01659 c.text.length()); 01660 string::size_type coffset2 = s2.find(conflict_separator); 01661 if (coffset2!=string::npos) { 01662 string s3 = s2.substr(coffset2+conflict_separator.length(), 01663 s2.length()); 01664 s2 = s2.substr(0,coffset2); 01665 change.val[col] = nully(s2); 01666 change.cond[col] = nully(s2); 01667 change.conflictingVal[col] = nully(s3); 01668 change.conflictingParentVal[col] = nully(s1); 01669 } else { 01670 change.val[col] = nully(s1); 01671 change.cond[col] = nully(s1); 01672 change.conflictingVal[col] = nully(s2); 01673 } 01674 change.conflicted = true; 01675 done = true; 01676 } 01677 } 01678 if (!conflict) { 01679 if (!added) { 01680 SheetCell tmp = nully(c.text.substr(0,offset)); 01681 change.cond[col] = tmp; 01682 done = true; 01683 } 01684 SheetCell tmp = nully(c.text.substr(offset+separator.length(), 01685 c.text.length())); 01686 change.val[col] = tmp; 01687 } 01688 } else if (added) { 01689 change.val[col] = c; 01690 } 01691 } 01692 /* 01693 TDiffPart p(c.text,false,minuses); 01694 if (p.hasNval) { 01695 change.val[col] = p.nval; 01696 if (!added) { 01697 change.cond[col] = p.val; 01698 } 01699 done = true; 01700 } 01701 */ 01702 } 01703 if (!done) { 01704 if (!added) { 01705 if (!c.escaped) { 01706 change.cond[col] = c; 01707 } 01708 } 01709 } 01710 } 01711 if (flags.canUpdate()) { 01712 if (allowed) patcher->changeRow(change); 01713 } 01714 } else { 01715 if (i<sheet.height()-1) { 01716 if (sheet.cellString(xoff,i+1)=="+++") { 01717 change.mode = ROW_CHANGE_CONTEXT; 01718 for (int j=1+xoff; j<sheet.width(); j++) { 01719 SheetCell c = sheet.cellSummary(j,i); 01720 // printf("? %d %d %d\n", xoff, j-1-xoff, cols.size()); 01721 change.cond[cols[j-1-xoff]] = c; 01722 } 01723 if (willBeAllowed) patcher->changeRow(change); 01724 } 01725 } 01726 } 01727 } 01728 } 01729 01730 patcher->mergeDone(); 01731 patcher->mergeAllDone(); 01732 01733 return true; 01734 } 01735 01736 01737 void PatchParser::needTable() { 01738 if (table_name=="") { 01739 if (flags.ordered_tables.size()>0) { 01740 table_name = flags.ordered_tables[0]; 01741 patcher->setSheet(table_name.c_str()); 01742 } 01743 } 01744 } 01745 01746 01747