COOPY » Guide  version 0.6.5
/home/paulfitz/cvs/coopy_scm/coopy/src/libcoopy_full/PatchParser.cpp
Go to the documentation of this file.
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=='\"'&&quote) {
00743           acceptSingle = false;
00744         }
00745         if (ch=='\''&&quote) {
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 
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines