00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "stdgeorges.h"
00028
00029 #include "nel/misc/i_xml.h"
00030 #include "nel/misc/eval_num_expr.h"
00031 #include "nel/misc/path.h"
00032 #include "nel/georges/u_type.h"
00033
00034 #include "georges/form.h"
00035 #include "georges/form_elm.h"
00036
00037 #include "type.h"
00038
00039 using namespace NLMISC;
00040 using namespace std;
00041
00042 namespace NLGEORGES
00043 {
00044
00045
00046
00047 void warning (bool exception, const char *format, ... );
00048
00049
00050
00051 CType::CType ()
00052 {
00053 Type = UnsignedInt;
00054 UIType = Edit;
00055 }
00056
00057
00058
00059 CType::~CType ()
00060 {
00061 int toto = 0;
00062 }
00063
00064
00065
00066 void CType::write (xmlDocPtr doc, bool georges4CVS) const
00067 {
00068
00069 xmlNodePtr node = xmlNewDocNode (doc, NULL, (const xmlChar*)"TYPE", NULL);
00070 xmlDocSetRootElement (doc, node);
00071
00072
00073 xmlSetProp (node, (const xmlChar*)"Type", (const xmlChar*)TypeNames[Type]);
00074 xmlSetProp (node, (const xmlChar*)"UI", (const xmlChar*)UITypeNames[UIType]);
00075
00076
00077 if (!Default.empty())
00078 {
00079 xmlSetProp (node, (const xmlChar*)"Default", (const xmlChar*)Default.c_str());
00080 }
00081
00082
00083 if (!Min.empty())
00084 {
00085 xmlSetProp (node, (const xmlChar*)"Min", (const xmlChar*)Min.c_str());
00086 }
00087
00088
00089 if (!Max.empty())
00090 {
00091 xmlSetProp (node, (const xmlChar*)"Max", (const xmlChar*)Max.c_str());
00092 }
00093
00094
00095 if (!Increment.empty())
00096 {
00097 xmlSetProp (node, (const xmlChar*)"Increment", (const xmlChar*)Increment.c_str());
00098 }
00099
00100
00101 uint def = 0;
00102 for (def = 0; def<Definitions.size(); def++)
00103 {
00104 xmlNodePtr defNode = xmlNewChild ( node, NULL, (const xmlChar*)"DEFINITION", NULL);
00105 xmlSetProp (defNode, (const xmlChar*)"Label", (const xmlChar*)Definitions[def].Label.c_str());
00106 xmlSetProp (defNode, (const xmlChar*)"Value", (const xmlChar*)Definitions[def].Value.c_str());
00107 }
00108
00109
00110 Header.write (node, georges4CVS);
00111 }
00112
00113
00114
00115 void CType::read (xmlNodePtr root)
00116 {
00117
00118 if ( ((const char*)root->name == NULL) || (strcmp ((const char*)root->name, "TYPE") != 0) )
00119 {
00120
00121 warning2 (true, "read", "XML Syntax error in block line %d, node (%s) should be TYPE.",
00122 (int)root->content, root->name);
00123 }
00124
00125
00126 const char *value = (const char*)xmlGetProp (root, (xmlChar*)"Type");
00127 if (value)
00128 {
00129
00130 uint type;
00131 for (type=0; type<TypeCount; type++)
00132 {
00133 if (strcmp (value, TypeNames[type]) == 0)
00134 break;
00135 }
00136
00137
00138 if (type!=TypeCount)
00139 Type = (TType)type;
00140 else
00141 {
00142
00143 string valueStr = value;
00144
00145
00146 xmlFree ((void*)value);
00147
00148
00149 warning2 (true, "read", "XML Syntax error in TYPE block line %d, the Type value is unknown (%s).",
00150 (int)root->content, valueStr.c_str ());
00151 }
00152
00153
00154 xmlFree ((void*)value);
00155 }
00156 else
00157 {
00158
00159 warning2 (true, "read", "XML Syntax error in TYPE block line %d, the Type argument was not found.",
00160 (int)root->content);
00161 }
00162
00163
00164 value = (const char*)xmlGetProp (root, (xmlChar*)"UI");
00165 if (value)
00166 {
00167
00168 uint type;
00169 for (type=0; type<UITypeCount; type++)
00170 {
00171 if (strcmp (value, UITypeNames[type]) == 0)
00172 break;
00173 }
00174
00175
00176 if (type!=UITypeCount)
00177 UIType = (TUI)type;
00178 else
00179 UIType = Edit;
00180
00181
00182 xmlFree ((void*)value);
00183 }
00184 else
00185 UIType = Edit;
00186
00187
00188 value = (const char*)xmlGetProp (root, (xmlChar*)"Default");
00189 if (value)
00190 {
00191 Default = value;
00192
00193
00194 xmlFree ((void*)value);
00195 }
00196 else
00197 Default = "";
00198
00199
00200 value = (const char*)xmlGetProp (root, (xmlChar*)"Min");
00201 if (value)
00202 {
00203 Min = value;
00204
00205
00206 xmlFree ((void*)value);
00207 }
00208 else
00209 Min = "";
00210
00211
00212 value = (const char*)xmlGetProp (root, (xmlChar*)"Max");
00213 if (value)
00214 {
00215 Max = value;
00216
00217
00218 xmlFree ((void*)value);
00219 }
00220 else
00221 Max = "";
00222
00223
00224 value = (const char*)xmlGetProp (root, (xmlChar*)"Increment");
00225 if (value)
00226 {
00227 Increment = value;
00228
00229
00230 xmlFree ((void*)value);
00231 }
00232 else
00233 Increment = "";
00234
00235
00236 uint childrenCount = CIXml::countChildren (root, "DEFINITION");
00237
00238
00239 Definitions.resize (childrenCount);
00240 uint child=0;
00241 xmlNodePtr childPtr = CIXml::getFirstChildNode (root, "DEFINITION");
00242 while (child < childrenCount)
00243 {
00244
00245 nlassert (childPtr);
00246
00247
00248 const char *label = (const char*)xmlGetProp (childPtr, (xmlChar*)"Label");
00249 if (label)
00250 {
00251
00252 value = (const char*)xmlGetProp (childPtr, (xmlChar*)"Value");
00253 if (value)
00254 {
00255 Definitions[child].Label = label;
00256 Definitions[child].Value = value;
00257
00258
00259 xmlFree ((void*)value);
00260 }
00261 else
00262 {
00263
00264 xmlFree ((void*)label);
00265
00266
00267 warning2 (true, "read", "XML Syntax error in DEFINITION block line %d, the Value argument was not found.",
00268 (int)childPtr->content);
00269 }
00270
00271
00272 xmlFree ((void*)label);
00273 }
00274 else
00275 {
00276
00277 warning2 (true, "read", "XML Syntax error in DEFINITION block line %d, the Label argument was not found.",
00278 (int)childPtr->content);
00279 }
00280
00281
00282 child++;
00283
00284 childPtr = CIXml::getNextChildNode (childPtr, "DEFINITION");;
00285 }
00286
00287
00288 Header.read (root);
00289 }
00290
00291
00292
00293 const char *CType::TypeNames[TypeCount]=
00294 {
00295 "UnsignedInt",
00296 "SignedInt",
00297 "Double",
00298 "String",
00299 "Color",
00300 };
00301
00302
00303
00304 const char *CType::UITypeNames[UITypeCount]=
00305 {
00306 "Edit",
00307 "EditSpin",
00308 "NonEditableCombo",
00309 "FileBrowser",
00310 "BigEdit",
00311 "ColorEdit",
00312 };
00313
00314
00315
00316 const char *CType::getTypeName (TType type)
00317 {
00318 return TypeNames[type];
00319 }
00320
00321
00322
00323 const char *CType::getUIName (TUI type)
00324 {
00325 return UITypeNames[type];
00326 }
00327
00328
00329
00330 class CMyEvalNumExpr : public CEvalNumExpr
00331 {
00332 public:
00333 CMyEvalNumExpr (const CForm *form)
00334 {
00335 Form = form;
00336 }
00337 virtual CEvalNumExpr::TReturnState evalValue (const char *value, double &result, uint32 round)
00338 {
00339
00340 if (Form)
00341 {
00342
00343 if (strcmp (value, "$filename") == 0)
00344 {
00345
00346 const string filename = CFile::getFilenameWithoutExtension (Form->getFilename ());
00347
00348
00349 sint i;
00350 for (i=filename.size ()-1; i>=0; i--)
00351 {
00352 if ((filename[i]<'0') || (filename[i]>'9'))
00353 break;
00354 }
00355
00356
00357 if ((i >= 0) && (i<((sint)filename.size ()-1)))
00358 {
00359 i++;
00360
00361 result = atof (filename.c_str () + i);
00362 }
00363 else
00364 {
00365
00366 result = 0;
00367 }
00368 return CEvalNumExpr::NoError;
00369 }
00370 else
00371 {
00372
00373
00374
00375 const CFormDfn *parentDfn;
00376 const CFormDfn *nodeDfn;
00377 const CType *nodeType;
00378 CFormElm *node;
00379 uint parentIndex;
00380 bool array;
00381 bool parentVDfnArray;
00382 UFormDfn::TEntryType type;
00383
00384
00385 if (((const CFormElm&)Form->getRootNode ()).getNodeByName (value, &parentDfn, parentIndex, &nodeDfn, &nodeType, &node, type, array, parentVDfnArray, false, round))
00386 {
00387
00388 if (type == UFormDfn::EntryType)
00389 {
00390
00391 const CFormElmAtom *atom = node ? safe_cast<const CFormElmAtom*> (node) : NULL;
00392
00393
00394 nlassert (nodeType);
00395 string res;
00396 if (nodeType->getValue (res, Form, atom, *parentDfn, parentIndex, UFormElm::Eval, NULL, round, value))
00397 {
00398 if (((const CFormElm&)Form->getRootNode ()).convertValue (result, res.c_str ()))
00399 {
00400 return CEvalNumExpr::NoError;
00401 }
00402 }
00403 }
00404 }
00405 }
00406 }
00407 return CEvalNumExpr::evalValue (value, result, round);
00408 }
00409
00410
00411 const CForm *Form;
00412 };
00413
00414
00415
00416 #define NL_TOKEN_STRING 0
00417 #define NL_TOKEN_DOUBLE_QUOTE 1
00418 #define NL_TOKEN_OPEN_BRACKET 2
00419 #define NL_TOKEN_NAME 3
00420 #define NL_TOKEN_END 4
00421
00422 uint getNextToken (const char *startString, string &token, uint &offset)
00423 {
00424 if (startString[offset] == 0)
00425 return NL_TOKEN_END;
00426 if (startString[offset] == '"')
00427 {
00428 offset++;
00429 return NL_TOKEN_DOUBLE_QUOTE;
00430 }
00431 if (startString[offset] == '{')
00432 {
00433 offset++;
00434 return NL_TOKEN_OPEN_BRACKET;
00435 }
00436 if ( (startString[offset] == '$') && (strncmp (startString+offset+1, "filename", 8) == 0) )
00437 {
00438 offset += 9;
00439 return NL_TOKEN_NAME;
00440 }
00441 token = "";
00442 while (startString[offset])
00443 {
00444 if (startString[offset] == '\\')
00445 {
00446 if (startString[offset+1])
00447 {
00448 token += startString[offset+1];
00449 offset++;
00450 }
00451 else
00452 {
00453 offset++;
00454 break;
00455 }
00456 }
00457 else if (startString[offset] == '"')
00458 break;
00459 else if (startString[offset] == '{')
00460 break;
00461 else if ( (startString[offset] == '$') && (strncmp (startString+offset+1, "filename", 8) == 0) )
00462 break;
00463 else
00464 token += startString[offset];
00465 offset++;
00466 }
00467 return NL_TOKEN_STRING;
00468 }
00469
00470
00471
00472 uint findSpecialCharacter (const char *special, char c, uint startOffset)
00473 {
00474 uint offset = startOffset;
00475 while (special[offset])
00476 {
00477 if (special[offset] == '\\')
00478 {
00479 if (special[offset+1])
00480 offset++;
00481 else
00482 break;
00483 }
00484 else
00485 {
00486 if (special[offset] == c)
00487 return offset;
00488 }
00489 offset++;
00490 }
00491 return 0xffffffff;
00492 }
00493
00494
00495
00496 void buildError (char *msg, uint offset)
00497 {
00498 msg[0] = 0;
00499 if (offset<512)
00500 {
00501 uint i;
00502 for (i=0; i<offset; i++)
00503 msg[i] = '-';
00504 msg[i] = '^';
00505 msg[i+1] = 0;
00506 }
00507 }
00508
00509
00510
00511 bool CType::getValue (string &result, const CForm *form, const CFormElmAtom *node, const CFormDfn &parentDfn, uint parentIndex, UFormElm::TEval evaluate, uint32 *where, uint32 round, const char *formName) const
00512 {
00513
00514 if (node && !node->Value.empty())
00515 {
00516 if (where)
00517 *where = (node->Form == form) ? CFormElm::ValueForm : CFormElm::ValueParentForm;
00518 result = node->Value;
00519 }
00520
00521 else
00522 {
00523 const string &defDfn = parentDfn.Entries[parentIndex].Default;
00524 if (!defDfn.empty ())
00525 {
00526 if (where)
00527 *where = CFormElm::ValueDefaultDfn;
00528 result = defDfn;
00529 }
00530 else
00531 {
00532 if (where)
00533 *where = CFormElm::ValueDefaultType;
00534 result = Default;
00535 }
00536 }
00537
00538
00539 if (evaluate == UFormElm::Formula)
00540 {
00541
00542 uint i;
00543 uint predefCount = Definitions.size ();
00544 for (i=0; i<predefCount; i++)
00545 {
00546
00547 const CType::CDefinition &def = Definitions[i];
00548
00549
00550 if (def.Label == result)
00551 {
00552 result = def.Value;
00553 break;
00554 }
00555 }
00556 }
00557 else if (evaluate == UFormElm::Eval)
00558 {
00559
00560 if ((Type == Double) || (Type == SignedInt) || (Type == UnsignedInt) || (Type == UnsignedInt))
00561 {
00562
00563 uint i;
00564 uint predefCount = Definitions.size ();
00565 for (i=0; i<predefCount; i++)
00566 {
00567
00568 const CType::CDefinition &def = Definitions[i];
00569
00570
00571 if (def.Label == result)
00572 {
00573 result = def.Value;
00574 break;
00575 }
00576 }
00577
00578 double value;
00579 CMyEvalNumExpr expr (form);
00580 int offset;
00581 CEvalNumExpr::TReturnState error = expr.evalExpression (result.c_str (), value, &offset, round);
00582 if (error == CEvalNumExpr::NoError)
00583 {
00584
00585 result = toString (value);
00586 }
00587 else
00588 {
00589
00590 char msg[512];
00591 buildError (msg, offset);
00592 warning (false, formName, form->getFilename ().c_str (), "getValue", "Syntax error in expression: %s\n%s\n%s", expr.getErrorString (error), result.c_str (), msg);
00593 return false;
00594 }
00595 }
00596 else
00597 {
00598
00599 uint offset = 0;
00600 string dest;
00601 while (offset < result.size ())
00602 {
00603 string token;
00604 uint tokenType = getNextToken (result.c_str (), token, offset);
00605
00606
00607 if (tokenType == NL_TOKEN_OPEN_BRACKET)
00608 {
00609
00610 uint nextEnd = findSpecialCharacter (result.c_str (), '}', offset);
00611 if (nextEnd == 0xffffffff)
00612 {
00613
00614 char msg[512];
00615 buildError (msg, result.size ());
00616 warning (false, formName, form->getFilename ().c_str (), "getValue", "Missing closing quote\n%s\n%s", result.c_str (), msg);
00617 return false;
00618 }
00619 else
00620 {
00621
00622 char zeroPadding = 0;
00623
00624
00625 if ( ( (nextEnd - offset) >= 3 ) && ( result[offset] == '$' ) && ( result[offset+1] == 'z' )
00626 && ( result[offset+2] <= '9' ) && ( result[offset+2] >= '0' ) )
00627 {
00628
00629 zeroPadding = result[offset+2] - '0';
00630 offset += 3;
00631 }
00632
00633
00634 string valueName = result.substr ( offset, nextEnd-offset );
00635
00636 double value;
00637 CMyEvalNumExpr expr (form);
00638 int offsetExpr;
00639 CEvalNumExpr::TReturnState error = expr.evalExpression (valueName.c_str (), value, &offsetExpr, round);
00640 if (error == CEvalNumExpr::NoError)
00641 {
00642
00643 char format[200];
00644 char result[200];
00645 smprintf (format, 200, "%%0%cg", zeroPadding+'0');
00646 smprintf (result, 200, format, value);
00647 dest += result;
00648 }
00649 else
00650 {
00651
00652 char msg[512];
00653 buildError (msg, offset+offsetExpr);
00654 warning (false, formName, form->getFilename ().c_str (), "getValue", "Syntax error in expression: %s\n%s\n%s", expr.getErrorString (error), result.c_str (), msg);
00655 return false;
00656 }
00657
00658
00659 offset = nextEnd + 1;
00660 }
00661 }
00662 else if (tokenType == NL_TOKEN_DOUBLE_QUOTE)
00663 {
00664
00665 uint nextEnd = findSpecialCharacter (result.c_str (), '"', offset);
00666 if (nextEnd == 0xffffffff)
00667 {
00668
00669 char msg[512];
00670 buildError (msg, result.size ());
00671 warning (false, formName, form->getFilename ().c_str (), "getValue", "Missing double quote\n%s\n%s", result.c_str (), msg);
00672 return false;
00673 }
00674 else
00675 {
00676
00677 string valueName = result.substr ( offset, nextEnd-offset );
00678
00679
00680 const CFormDfn *parentDfn;
00681 const CFormDfn *nodeDfn;
00682 const CType *nodeType;
00683 CFormElm *node;
00684 uint parentIndex;
00685 bool array;
00686 bool parentVDfnArray;
00687 UFormDfn::TEntryType type;
00688
00689
00690 if (((const CFormElm&)form->getRootNode ()).getNodeByName (valueName.c_str (), &parentDfn, parentIndex, &nodeDfn, &nodeType, &node, type, array, parentVDfnArray, false, round))
00691 {
00692
00693 if (type == UFormDfn::EntryType)
00694 {
00695
00696 const CFormElmAtom *atom = node ? safe_cast<const CFormElmAtom*> (node) : NULL;
00697
00698
00699 nlassert (nodeType);
00700 string result2;
00701 if (nodeType->getValue (result2, form, atom, *parentDfn, parentIndex, UFormElm::Eval, NULL, round, valueName.c_str ()))
00702 {
00703 dest += result2;
00704 }
00705 }
00706 else
00707 {
00708 char msg[512];
00709 buildError (msg, offset);
00710 warning (false, formName, form->getFilename ().c_str (), "getValue", "Node is not an atom (%s)\n%s\n%s", valueName.c_str (), result.c_str (), msg);
00711 return false;
00712 }
00713 }
00714 else
00715 return false;
00716 }
00717
00718
00719 offset = nextEnd + 1;
00720 }
00721 else if (tokenType == NL_TOKEN_STRING)
00722 {
00723
00724 uint i;
00725 uint predefCount = Definitions.size ();
00726 for (i=0; i<predefCount; i++)
00727 {
00728
00729 const CType::CDefinition &def = Definitions[i];
00730
00731
00732 if (def.Label == token)
00733 {
00734 token = def.Value;
00735 break;
00736 }
00737 }
00738
00739
00740 dest += token;
00741 }
00742 else if (tokenType == NL_TOKEN_NAME)
00743 {
00744 dest += form->getFilename ();
00745 }
00746 }
00747
00748
00749 result = dest;
00750 }
00751 }
00752
00753
00754 return true;
00755 }
00756
00757
00758
00759 bool CType::uiCompatible (TType type, TUI ui)
00760 {
00761 switch (type)
00762 {
00763 case UnsignedInt:
00764 case SignedInt:
00765 case Double:
00766 return (ui == Edit) || (ui == EditSpin) || (ui == NonEditableCombo);
00767 case String:
00768 return (ui == Edit) || (ui == NonEditableCombo) || (ui == FileBrowser) || (ui == BigEdit);
00769 case Color:
00770 return (ui == ColorEdit);
00771 }
00772 return false;
00773 }
00774
00775
00776
00777 void CType::warning (bool exception, const char *formName, const char *formFilename, const char *function, const char *format, ... ) const
00778 {
00779
00780 va_list args;
00781 va_start( args, format );
00782 char buffer[1024];
00783 sint ret = vsnprintf( buffer, 1024, format, args );
00784 va_end( args );
00785
00786
00787 NLGEORGES::warning (exception, "(CType::%s) In form (%s) in node (%s) : %s", function, formFilename, formName, buffer);
00788 }
00789
00790
00791
00792 void CType::warning2 (bool exception, const char *function, const char *format, ... ) const
00793 {
00794
00795 va_list args;
00796 va_start( args, format );
00797 char buffer[1024];
00798 sint ret = vsnprintf( buffer, 1024, format, args );
00799 va_end( args );
00800
00801
00802 NLGEORGES::warning (exception, "(CType::%s) : %s", function, buffer);
00803 }
00804
00805
00806
00807 UType::TType CType::getType () const
00808 {
00809 return Type;
00810 }
00811
00812
00813
00814 const string &CType::getDefault () const
00815 {
00816 return Default;
00817 }
00818
00819
00820
00821 const string &CType::getMin () const
00822 {
00823 return Min;
00824 }
00825
00826
00827
00828 const string &CType::getMax () const
00829 {
00830 return Max;
00831 }
00832
00833
00834
00835 const string &CType::getIncrement () const
00836 {
00837 return Increment;
00838 }
00839
00840
00841
00842 uint CType::getNumDefinition () const
00843 {
00844 return Definitions.size ();
00845 }
00846
00847
00848
00849 bool CType::getDefinition (uint index, std::string &label, std::string &value) const
00850 {
00851 if (index < Definitions.size ())
00852 {
00853 label = Definitions[index].Label;
00854 value = Definitions[index].Value;
00855 return true;
00856 }
00857 warning2 (false, "getDefinition", "Index out of bounds (%d >= %d)", index, Definitions.size ());
00858 return false;
00859 }
00860
00861
00862
00863 const string &CType::getComment () const
00864 {
00865 return Header.Comments;
00866 }
00867
00868
00869
00870 }