00001 #include "stdafx.h"
00002 #include <afxext.h>
00003
00004 #ifndef _AFX_NO_OLE_SUPPORT
00005 #include <afxole.h>
00006 #include <afxodlgs.h>
00007 #include <afxdisp.h>
00008 #endif // _AFX_NO_OLE_SUPPORT
00009
00010
00011 #ifndef _AFX_NO_DB_SUPPORT
00012 #include <afxdb.h>
00013 #endif // _AFX_NO_DB_SUPPORT
00014
00015 #ifndef _AFX_NO_DAO_SUPPORT
00016 #include <afxdao.h>
00017 #endif // _AFX_NO_DAO_SUPPORT
00018
00019 #include <afxdtctl.h>
00020 #ifndef _AFX_NO_AFXCMN_SUPPORT
00021 #include <afxcmn.h>
00022 #endif // _AFX_NO_AFXCMN_SUPPORT
00023
00024
00025 #include "BONComponent.h"
00026
00027 #define PATLINELENGTH 500
00028
00029
00030
00031 class FileGenerator {
00032 private:
00033 FILE *fo;
00034 CList<CString *, CString *> outstrings;
00035 CMapStringToString vars;
00036 void outchannel_push(CString &buf) {
00037 outstrings.AddHead(&buf);
00038 }
00039 void outchannel_pop() {
00040 outstrings.RemoveHead();
00041 }
00042
00043 void outc(CString str) {
00044 if(!outstrings.IsEmpty()) {
00045 *outstrings.GetHead() += str;
00046 }
00047 else if(fo) fputs(str, fo);
00048 else {
00049 str.TrimLeft();
00050 if(!str.IsEmpty()) throw CString("Nowhere to write generated text");
00051 }
00052 }
00053 void outc(char c) {
00054 if(!outstrings.IsEmpty()) {
00055 *outstrings.GetHead() += c;
00056 }
00057 else if(fo) fputc(c, fo);
00058 else {
00059 if(!isspace(c)) throw CString("Nowhere to write generated text");
00060 }
00061 }
00062 int readarg(const char *pptr, CString &outstr, char term);
00063 void evaluate_line(const char * line, CBuilderObject* context, bool escape);
00064 int evaluate_cmd(const char *ptr, char *cmd, CBuilderObject* context);
00065 public:
00066 void Define(CString name, CString value) {
00067 vars.SetAt(name, value);
00068 }
00069 FileGenerator() {
00070 fo = NULL;
00071 }
00072 int GenFile(const char *patfilename, CBuilderObject* context);
00073 };
00074
00075
00076
00077 void eatss(const char *&ptr, CString &outstr);
00078
00079
00080 void eatdq(const char *&ptr, CString &outstr) {
00081 char c = 0;
00082 if(*ptr != '"') {
00083 while(*ptr != ',' && *ptr != ')') {
00084 if(*ptr == '$' && c != '\\') eatss(ptr, outstr);
00085 else {
00086 c = *ptr++;
00087 if(c == '\0') throw 0;
00088 outstr += c;
00089 }
00090 }
00091 return;
00092 }
00093 else {
00094 ptr++;
00095 while(*ptr != '"' || c == '\\') {
00096 if(*ptr == '$' && c != '\\') eatss(ptr, outstr);
00097 else {
00098 c = *ptr++;
00099 if(c == '\0') throw 0;
00100 outstr += c;
00101 }
00102 }
00103 if(*ptr++ != '"') throw 0;
00104 }
00105 }
00106
00107
00108
00109 void eatss(const char *&ptr, CString &outstr) {
00110 bool cmd = false;
00111 if(*ptr != '$') throw 0;
00112 outstr += *ptr++;
00113 if(*ptr == '(') {
00114 char c;
00115 do {
00116 c = *ptr;
00117 if(c == '\0') throw 0;
00118 if(c == '"') {
00119 outstr += '"';
00120 eatdq(ptr, outstr);
00121 outstr += '"';
00122 }
00123 else if(c == '$') eatss(ptr, outstr);
00124 else outstr += *ptr++;
00125 } while(c != ')');
00126 }
00127 else {
00128 if(*ptr == '!') {
00129 cmd = true;
00130 outstr += *ptr++;
00131 }
00132 while(isalnum(*ptr) || *ptr == '_') {
00133 outstr += *ptr++;
00134 }
00135 }
00136 if(cmd && *ptr == '(') {
00137 char c;
00138 do {
00139 c = *ptr;
00140 if(c == '\0') throw 0;
00141 if(c == '"') {
00142 outstr += '"';
00143 eatdq(ptr, outstr);
00144 outstr += '"';
00145 }
00146 else if(c == '$') eatss(ptr, outstr);
00147 else outstr += *ptr++;
00148 } while(c != ')');
00149 }
00150 }
00151
00152 #define ANY_TERM ((char)0xFF)
00153
00154 int FileGenerator::readarg(const char *pptr, CString &outstr, char term) {
00155 const char *ptr = pptr;
00156 try {
00157 while(isspace(*ptr)) ptr++;
00158 eatdq(ptr, outstr);
00159 while(isspace(*ptr)) ptr++;
00160 if(*ptr++ != term && term != ANY_TERM) throw 0;
00161 }
00162 catch(int) {
00163 throw CString("Error reading argument: ") + pptr;
00164 };
00165 return ptr - pptr;
00166 }
00167
00168
00169 int FileGenerator::evaluate_cmd(const char *pptr, char *cmd, CBuilderObject* context) {
00170 const char *ptr = pptr;
00171 bool single;
00172 if((single = !strcmp(cmd, "EVAL_WITH")) ||
00173 !strcmp(cmd, "EVAL_FORALL")) {
00174 CString arg1; ptr += readarg(ptr, arg1, ',');
00175 CString arg2; ptr += readarg(ptr, arg2, ')');
00176 int k = arg1.Find(':');
00177 if(k++ <= 0) k = arg1.GetLength();
00178 CString mode = arg1.Left(k);
00179 arg1.Delete(0,k);
00180 CBuilderObjectList ll;
00181 if(mode == "R:") {
00182 if(!context->IsKindOf(RUNTIME_CLASS(CBuilderModel))) throw CString("Roles accessed ('R:') on non-model");
00183 CBuilderObjectList const*list = ((CBuilderModel *)context)->GetChildren();
00184 POSITION pos = list->GetHeadPosition();
00185 while(pos) {
00186 CBuilderObject *m = list->GetNext(pos);
00187 if(m->GetPartName() == arg1) ll.AddTail(m);
00188 }
00189 }
00190 else if(mode == "Src:") {
00191 context->GetInConnectedObjects(arg1,ll);
00192 }
00193 else if(mode == "Dst:") {
00194 context->GetOutConnectedObjects(arg1,ll);
00195 }
00196 else if(mode == "Ref") {
00197 const CBuilderObject *p;
00198 if(context->IsKindOf(RUNTIME_CLASS(CBuilderModelReference))) p = ((CBuilderModelReference *)context)->GetReferred();
00199 else if(context->IsKindOf(RUNTIME_CLASS(CBuilderAtomReference))) p = ((CBuilderAtomReference *)context)->GetReferred();
00200 else throw CString("Ref accessed ('Ref:') on non-reference");
00201 if(p != NULL) ll.AddTail(const_cast<CBuilderObject *>(p));
00202 }
00203 else if(mode == "Parent") {
00204 const CBuilderObject *p = context->GetParent();
00205 if(p != NULL) ll.AddTail(const_cast<CBuilderObject *>(p));
00206 }
00207 else if(mode == "Type") {
00208 const CBuilderObject *p = context->GetType();
00209 if(p != NULL) ll.AddTail(const_cast<CBuilderObject *>(p));
00210 }
00211 else throw CString("Unknown EVAL_xxx mode: ") + mode;
00212 if(single && ll.GetCount() != 1) throw CString("EVAL_WITH results not a single object") + arg1;
00213 POSITION pos = ll.GetHeadPosition();
00214 while(pos) {
00215 const CBuilderObject *m = ll.GetNext(pos);
00216 if(m->IsKindOf(RUNTIME_CLASS(CBuilderReferencePort))) m = ((CBuilderReferencePort *)m)->GetAtom();
00217 evaluate_line(arg2, const_cast<CBuilderObject *>(m), true);
00218 }
00219 }
00220 else if(!strcmp(cmd, "DEFINE")) {
00221 CString arg1; ptr += readarg(ptr, arg1, ',');
00222 CString arg2; ptr += readarg(ptr, arg2, ')');
00223 CString b;
00224 outchannel_push(b);
00225 evaluate_line(arg2, context, true);
00226 outchannel_pop();
00227 Define(arg1, b);
00228 }
00229 else if(!strcmp(cmd, "IFDEFAULT")) {
00230 CString arg1; ptr += readarg(ptr, arg1, ',');
00231 CString arg2; ptr += readarg(ptr, arg2, ')');
00232 CString b;
00233 context->GetAttribute(arg1, b);
00234 if(b.IsEmpty()) {
00235 outchannel_push(b);
00236 evaluate_line(arg2, context, true);
00237 outchannel_pop();
00238 }
00239 outc(b);
00240 }
00241 else if(!strcmp(cmd, "IFEMPTY")) {
00242 CString arg1; ptr += readarg(ptr, arg1, ',');
00243 CString arg2; ptr += readarg(ptr, arg2, ')');
00244 CString b;
00245 outchannel_push(b);
00246 evaluate_line(arg1, context, true);
00247 if(b.IsEmpty()) evaluate_line(arg2, context, true);
00248 outchannel_pop();
00249 outc(b);
00250 }
00251 else if(!strcmp(cmd, "TO_FILE")) {
00252 CString b;
00253 outchannel_push(b);
00254 CString arg; ptr += readarg(ptr, arg, ')');
00255 evaluate_line(arg, context, true);
00256 outchannel_pop();
00257 if(fo) fclose(fo);
00258 fo = fopen(b, "wt");
00259 if(fo == NULL) throw CString("Cannot open output file")+b;
00260 }
00261 else if(!strcmp(cmd, "POSTINCR")) {
00262 CString arg; ptr += readarg(ptr, arg, ')');
00263 CString attrval;
00264 if(!vars.Lookup(CString(arg), attrval)) throw CString("POSTINCR: undefined var: ") + arg;
00265 outc(attrval);
00266 int n = atoi(attrval);
00267 attrval.Format("%d",n+1);
00268 Define(arg, attrval);
00269 }
00270 else if(!strcmp(cmd, "SEQ")) {
00271
00272 do {
00273 CString arg1; ptr += readarg(ptr, arg1, ANY_TERM);
00274 evaluate_line(arg1, context, true);
00275 } while(ptr[-1] == ',');
00276 if(ptr[-1] != ')') throw CString("Unbalanced '(' ')' for SEQ");
00277
00278
00279
00280
00281
00282 }
00283 else if(!strcmp(cmd, "GETPRINTFIELD")) {
00284 CString arg; ptr += readarg(ptr, arg, ')');
00285 CString b;
00286 outchannel_push(b);
00287 evaluate_line(arg, context, true);
00288 outchannel_pop();
00289 CString code;
00290 if(!strcmp(b,"int")) code = "%d";
00291 else if(!strcmp(b,"long")) code = "%ld";
00292 else if(!strcmp(b,"float")) code = "%f";
00293 else if(!strcmp(b,"double")) code = "%f";
00294 else throw CString("Cannot generate printf field for ")+b;
00295 outc(code);
00296 }
00297 else if(!strcmp(cmd, "COMMENT")) {
00298 do {
00299 CString arg1; ptr += readarg(ptr, arg1, ANY_TERM);
00300 } while(ptr[-1] == ',');
00301 }
00302 return ptr - pptr;
00303 }
00304
00305
00306 void FileGenerator::evaluate_line(const char * line, CBuilderObject* context, bool escape) {
00307 const char *ptr = line;
00308 bool in_esc = false;
00309 while( *ptr != '\0') {
00310 char c = *ptr++;
00311 if(escape && in_esc) {
00312 in_esc = false;
00313 if(c == 'n') outc('\n');
00314 else outc(c);
00315 }
00316 else if(escape && c == '\\') in_esc = true;
00317 else if(c != '$') {
00318 outc(c);
00319 }
00320 else if(!escape && *ptr == '$') outc(*ptr++);
00321 else {
00322 bool endparen = false;
00323 bool command = false;
00324 if(*ptr == '!') {
00325 command = true;
00326 ptr++;
00327 }
00328 if(*ptr == '(') {
00329 endparen = true;
00330 ptr++;
00331 }
00332 char cmd[56];
00333 int add;
00334 if(sscanf(ptr, "%53[A-Za-z_0-9]%n", cmd, &add) != 1 ||
00335 add > 50 ||
00336 (endparen && ptr[add++] != ')') ||
00337 (command && ptr[add++] != '(')
00338 ) throw CString("Invalid $macro") ;
00339 ptr += add;
00340 if(command) {
00341 ptr += evaluate_cmd(ptr, cmd, context);
00342 }
00343 else {
00344 CString attrval;
00345 if(vars.Lookup(CString(cmd), attrval));
00346 else if(!strcmp(cmd, "Name")) attrval = context->GetName();
00347 else if(!strcmp(cmd, "Kind")) attrval = context->GetKindName();
00348 else if(!context->GetAttribute(cmd, attrval)) throw(CString("Unknown attribute: ")+cmd);
00349 if(attrval == "") throw CString("Attribute is empty: ")+cmd;
00350 outc(attrval);
00351 }
00352 }
00353 }
00354 }
00355
00356 int FileGenerator::GenFile(const char *patfilename, CBuilderObject* context) {
00357 int line = 0;
00358 FILE *fi = fopen(patfilename, "rt");
00359 try {
00360 if(fi == 0) throw CString("File not found: ");
00361 int rounds;
00362 for(line = 1; ; line += rounds) {
00363 char buf[PATLINELENGTH+3];
00364 int pos = 0;
00365 rounds = 0;
00366 while(1) {
00367 fgets(buf+pos, sizeof(buf)-pos, fi);
00368 if(feof(fi)) break;
00369 rounds++;
00370 pos = strlen(buf);
00371 if(pos > PATLINELENGTH + 1) throw(CString("Too long line"));
00372 if(pos >= 2 && buf[pos-2] == '\\') pos -= 2;
00373 else break;
00374 }
00375 if(feof(fi)) break;
00376 evaluate_line(buf, context, false);
00377 }
00378 if(!fo) throw CString("No output is generated");
00379 fclose(fi);
00380 fclose(fo);
00381 }
00382 catch(CString e) {
00383 if(fi) fclose(fi);
00384 if(fo) fclose(fo);
00385 CString linestr;
00386 linestr.Format("%d", line);
00387 AfxMessageBox(CString("Error: ") + e + "\nfile: " + CString(patfilename) + " line: " + linestr);
00388 }
00389 return 0;
00390 }
00391
00392
00393
00394
00395 void CComponent::InvokeEx(CBuilder &builder,CBuilderObject *focus, CBuilderObjectList &selected, long param)
00396 {
00397 if (focus == NULL) {
00398 AfxMessageBox("Please select an element in an opened model!", MB_OK | MB_ICONSTOP);
00399 return;
00400 }
00401
00402 CString script(builder.GetParameter("script"));
00403
00404 if(script.IsEmpty()) {
00405 static char filter[] = "Pattern Files (*.pat)|*.pat|" "All Files (*.*)|*.*||";
00406
00407 CFileDialog cfd(true, "pat", NULL, OFN_EXPLORER | OFN_FILEMUSTEXIST, filter);
00408 if( cfd.DoModal() != IDOK )
00409 return;
00410 script = cfd.GetPathName();
00411 }
00412
00413 FileGenerator gen;
00414 gen.GenFile(script, focus);
00415 }
00416
00417