COOPY » Guide
version 0.6.5
|
00001 00002 00003 /* 00004 Changes in 0.4: 00005 Version number change. 00006 The special "*" character goes away. 00007 A "row transform" operation is added. 00008 Context distinguished from index 00009 00010 Changes in 0.5: 00011 sheet command 00012 00013 */ 00014 00015 #include <coopy/MergeOutputCsvDiff.h> 00016 #include <coopy/SheetStyle.h> 00017 #include <coopy/DataSheet.h> 00018 00019 #include <stdio.h> 00020 #include <stdlib.h> 00021 00022 #define WANT_MAP2STRING 00023 #define WANT_VECTOR2STRING 00024 #include <coopy/Stringer.h> 00025 00026 using namespace std; 00027 using namespace coopy::store; 00028 using namespace coopy::cmp; 00029 00030 #define OP_MATCH "*" 00031 #define OP_ASSIGN "=" 00032 #define OP_MATCH_ASSIGN "*=" 00033 #define OP_CONTEXT "#" 00034 #define OP_NONE "" 00035 00036 MergeOutputCsvDiff::MergeOutputCsvDiff() { 00037 } 00038 00039 bool MergeOutputCsvDiff::mergeStart() { 00040 00041 currentSheetName = ""; 00042 pendingSheetName = ""; 00043 result.setStrict(0); 00044 mergeClear(); 00045 result.addField("dtbl",false); 00046 result.addField("csv",false); 00047 result.addField("version",false); 00048 result.addField("0.5",false); 00049 result.addRecord(); 00050 00051 return true; 00052 } 00053 00054 bool MergeOutputCsvDiff::mergeClear() { 00055 ops.clear(); 00056 nops.clear(); 00057 activeColumn.clear(); 00058 showForSelect.clear(); 00059 showForDescribe.clear(); 00060 prevSelect.clear(); 00061 prevDescribe.clear(); 00062 constantColumns = true; 00063 columns.clear(); 00064 showedColumns = false; 00065 return true; 00066 } 00067 00068 00069 bool MergeOutputCsvDiff::mergeDone() { 00070 mergeClear(); 00071 return true; 00072 } 00073 00074 bool MergeOutputCsvDiff::mergeAllDone() { 00075 SheetStyle style; 00076 //SheetCell c = result.cellSummary(0,0); 00077 fprintf(out,"%s",result.encode(style).c_str()); 00078 return true; 00079 } 00080 00081 00082 bool MergeOutputCsvDiff::changeColumn(const OrderChange& change) { 00083 constantColumns = false; 00084 switch (change.mode) { 00085 case ORDER_CHANGE_DELETE: 00086 clearThroat(); 00087 result.addField("column",false); 00088 result.addField("delete",false); 00089 //result.addField(ROW_COL,false); 00090 for (int i=0; i<(int)change.namesAfter.size(); i++) { 00091 result.addField(change.namesAfter[i].c_str(),false); 00092 } 00093 result.addRecord(); 00094 break; 00095 case ORDER_CHANGE_INSERT: 00096 clearThroat(); 00097 result.addField("column",false); 00098 result.addField("insert",false); 00099 //result.addField(ROW_COL,false); 00100 for (int i=0; i<(int)change.namesAfter.size(); i++) { 00101 result.addField(change.namesAfter[i].c_str(),false); 00102 } 00103 result.addRecord(); 00104 break; 00105 case ORDER_CHANGE_MOVE: 00106 clearThroat(); 00107 result.addField("column",false); 00108 result.addField("move",false); 00109 //result.addField(ROW_COL,false); 00110 for (int i=0; i<(int)change.namesAfter.size(); i++) { 00111 result.addField(change.namesAfter[i].c_str(),false); 00112 } 00113 result.addRecord(); 00114 break; 00115 case ORDER_CHANGE_RENAME: 00116 clearThroat(); 00117 result.addField("column",false); 00118 result.addField("rename",false); 00119 for (int i=0; i<(int)change.namesAfter.size(); i++) { 00120 result.addField(change.namesAfter[i].c_str(),false); 00121 } 00122 result.addRecord(); 00123 break; 00124 default: 00125 fprintf(stderr," Unknown column operation\n\n"); 00126 exit(1); 00127 break; 00128 } 00129 activeColumn.clear(); 00130 for (int i=0; i<(int)change.namesAfter.size(); i++) { 00131 activeColumn[change.namesAfter[i]] = true; 00132 } 00133 nops = change.namesAfter; 00134 return true; 00135 } 00136 00137 bool MergeOutputCsvDiff::operateRow(const RowChange& change, const char *tag) { 00138 vector<string> lnops; 00139 for (int i=0; i<(int)change.names.size(); i++) { 00140 if (activeColumn[change.names[i]]) { 00141 lnops.push_back(change.names[i]); 00142 } 00143 } 00144 if (lnops!=nops) { 00145 if (!showedColumns) { 00146 clearThroat(); 00147 result.addField("column",false); 00148 result.addField("name",false); 00149 for (int i=0; i<(int)columns.size(); i++) { 00150 result.addField(columns[i].c_str(),false); 00151 } 00152 result.addRecord(); 00153 showedColumns = true; 00154 } 00155 if (columns!=lnops) { 00156 clearThroat(); 00157 result.addField("link",false); 00158 result.addField("name",false); 00159 for (int i=0; i<(int)change.names.size(); i++) { 00160 if (activeColumn[change.names[i]]) { 00161 result.addField(change.names[i].c_str(),false); 00162 } 00163 } 00164 result.addRecord(); 00165 columns = lnops; 00166 } 00167 nops = lnops; 00168 } 00169 00170 if (prevSelect!=showForSelect || prevDescribe!=showForDescribe) { 00171 clearThroat(); 00172 result.addField((string(tag)=="act")?"link":"row",false); 00173 result.addField(tag,false); 00174 for (int i=0; i<(int)change.names.size(); i++) { 00175 if (activeColumn[change.names[i]]) { 00176 result.addField(ops[i].c_str(),false); 00177 } 00178 } 00179 result.addRecord(); 00180 } 00181 return true; 00182 } 00183 00184 bool MergeOutputCsvDiff::updateRow(const RowChange& change, const char *tag, 00185 bool select, bool update, bool practice) { 00186 bool ok = true; 00187 00188 if (!practice) { 00189 clearThroat(); 00190 result.addField("row",false); 00191 result.addField(tag,false); 00192 } 00193 for (int i=0; i<(int)change.names.size(); i++) { 00194 string name = change.names[i]; 00195 if (activeColumn[name]) { 00196 bool shown = false; 00197 if (change.cond.find(name)!=change.cond.end() && 00198 showForSelect[name] && select) { 00199 if (!practice) { 00200 clearThroat(); 00201 result.addField(change.cond.find(name)->second); 00202 } 00203 shown = true; 00204 } 00205 if (change.val.find(name)!=change.val.end() && 00206 showForDescribe[name] && update) { 00207 if (!practice) { 00208 clearThroat(); 00209 result.addField(change.val.find(name)->second); 00210 } 00211 if (shown) ok = false; // collision 00212 shown = true; 00213 } 00214 if (!shown) { 00215 if (!practice) { 00216 clearThroat(); 00217 result.addField("",false); 00218 } 00219 } 00220 } 00221 } 00222 if (!practice) { 00223 result.addRecord(); 00224 } 00225 return ok; 00226 } 00227 00228 bool MergeOutputCsvDiff::changeRow(const RowChange& change) { 00229 vector<string> lops; 00230 activeColumn.clear(); 00231 prevSelect = showForSelect; 00232 prevDescribe = showForDescribe; 00233 showForSelect.clear(); 00234 showForDescribe.clear(); 00235 for (int i=0; i<(int)change.names.size(); i++) { 00236 string name = change.names[i]; 00237 bool condActive = false; 00238 bool valueActive = false; 00239 if (change.cond.find(name)!=change.cond.end()) { 00240 condActive = true; 00241 } 00242 if (change.val.find(name)!=change.val.end()) { 00243 valueActive = true; 00244 } 00245 bool shouldMatch = condActive && change.indexes.find(name)->second; 00246 bool shouldAssign = valueActive; 00247 if (shouldAssign) { 00248 // conservative choice, should be optional 00249 if (change.cond.find(name)!=change.cond.end()) { 00250 shouldMatch = true; 00251 } 00252 } 00253 //printf("==> %s %d %d %d %d\n", name.c_str(), condActive, valueActive, 00254 //shouldMatch, shouldAssign); 00255 //bool shouldShow = shouldMatch || shouldAssign; 00256 00257 if (change.mode==ROW_CHANGE_INSERT) { 00258 // we do not care about matching 00259 shouldMatch = prevSelect[name]; 00260 shouldAssign = true; 00261 } 00262 if (change.mode==ROW_CHANGE_DELETE) { 00263 // we do not care about assigning 00264 shouldAssign = prevDescribe[name]; 00265 shouldMatch = true; 00266 } 00267 00268 // ignoring shouldShow for now. 00269 int opidx = (shouldMatch?2:0) + (shouldAssign?1:0); 00270 string opi[4] = { 00271 OP_NONE, // !match !assign 00272 OP_ASSIGN, // !match assign 00273 OP_MATCH, // match !assign 00274 OP_MATCH_ASSIGN, // match assign 00275 }; 00276 string op = opi[opidx]; 00277 00278 if (opidx!=0) { 00279 activeColumn[name] = true; 00280 } 00281 00282 // no way yet to communicate CONTEXT request 00283 lops.push_back(op); 00284 //showForSelect.push_back(shouldMatch); 00285 //showForDescribe.push_back(shouldAssign); 00286 showForSelect[name] = shouldMatch; 00287 showForDescribe[name] = shouldAssign; 00288 } 00289 00290 if (lops!=ops) { 00291 ops = lops; 00292 operateRow(change,"act"); 00293 } 00294 switch (change.mode) { 00295 case ROW_CHANGE_INSERT: 00296 updateRow(change,"insert",false,true,false); 00297 break; 00298 case ROW_CHANGE_DELETE: 00299 updateRow(change,"delete",true,false,false); 00300 break; 00301 case ROW_CHANGE_MOVE: 00302 { 00303 bool terse = updateRow(change,"practice",true,true,true); 00304 if (terse) { 00305 updateRow(change,"move",true,true,false); 00306 } else { 00307 updateRow(change,"select",true,false,false); 00308 updateRow(change,"move",false,true,false); 00309 } 00310 } 00311 break; 00312 case ROW_CHANGE_CONTEXT: 00313 updateRow(change,(change.cond.size()>0)?"after":"start",true,false,false); 00314 break; 00315 case ROW_CHANGE_UPDATE: 00316 { 00317 bool terse = updateRow(change,"practice",true,true,true); 00318 if (terse) { 00319 updateRow(change,"update",true,true,false); 00320 } else { 00321 updateRow(change,"select",true,false,false); 00322 updateRow(change,"update",false,true,false); 00323 } 00324 } 00325 break; 00326 default: 00327 fprintf(stderr," Unknown row operation\n\n"); 00328 exit(1); 00329 break; 00330 } 00331 return true; 00332 } 00333 00334 00335 bool MergeOutputCsvDiff::changeName(const NameChange& change) { 00336 const vector<string>& names = change.names; 00337 bool final = change.final; 00338 bool constant = change.constant; 00339 if (!final) { 00340 activeColumn.clear(); 00341 for (int i=0; i<(int)names.size(); i++) { 00342 activeColumn[names[i]] = true; 00343 showForSelect[names[i]] = true; 00344 showForDescribe[names[i]] = true; 00345 } 00346 if (!constant) { 00347 clearThroat(); 00348 result.addField("column",false); 00349 result.addField("name",false); 00350 //result.addField(ROW_COL,false); 00351 for (int i=0; i<(int)names.size(); i++) { 00352 result.addField(names[i].c_str(),false); 00353 } 00354 result.addRecord(); 00355 showedColumns = true; 00356 } 00357 } 00358 columns = names; 00359 return true; 00360 } 00361 00362 bool MergeOutputCsvDiff::setSheet(const char *name) { 00363 pendingSheetName = name; 00364 return true; 00365 } 00366 00367 bool MergeOutputCsvDiff::clearThroat() { 00368 if (currentSheetName!=pendingSheetName) { 00369 result.addField("table",false); 00370 result.addField("name",false); 00371 result.addField(pendingSheetName.c_str(),false); 00372 result.addRecord(); 00373 currentSheetName = pendingSheetName; 00374 } 00375 return true; 00376 }