00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00062 #ifndef EXPANDLIB_EXPANDABLE_H_INCLUDED
00063 #define EXPANDLIB_EXPANDABLE_H_INCLUDED
00064
00065 #include <iostream>
00066 #include <string>
00067 #include <vector>
00068 #include <map>
00069
00070 #include <tchar.h>
00071
00072
00073 namespace expander {
00074 template <
00075 class StringType = ::std::string
00076 > class expandable;
00077 }
00078
00079 #include "expandlib-cmd.h"
00080 #include "expandlib-vartype.h"
00081 #include "expandlib-exceptions.h"
00082
00083
00084 #include "expandlib-cmd-abbr.h"
00085 #include "expandlib-cmd-bpad.h"
00086 #include "expandlib-cmd-btrunc.h"
00087 #include "expandlib-cmd-fpad.h"
00088 #include "expandlib-cmd-ftrunc.h"
00089 #include "expandlib-cmd-if.h"
00090 #include "expandlib-cmd-knownvars.h"
00091 #include "expandlib-cmd-lower.h"
00092 #include "expandlib-cmd-ltrim.h"
00093 #include "expandlib-cmd-numvars.h"
00094 #include "expandlib-cmd-rtrim.h"
00095 #include "expandlib-cmd-trim.h"
00096 #include "expandlib-cmd-unknownvars.h"
00097 #include "expandlib-cmd-upper.h"
00098
00099
00100 #pragma warning(disable: 4355)
00101
00103
00107 namespace expander {
00108
00110
00120 template <
00121 class StringType = ::std::string
00122 >
00123 class expandable {
00124 public:
00125 typedef ::std::vector<StringType> FParamVectorType;
00126 typedef ::std::map<StringType, ::expander::expandvartype<StringType>*> FVarMapType;
00127 typedef ::std::map<StringType, ::expander::expandcmd<StringType>*> FCmdMapType;
00128
00129 protected:
00131 const bool InlineExpandErrors;
00132
00134 const bool InlineGeneralErrors;
00135
00137 StringType expstr;
00138
00140 FCmdMapType cmdmap;
00141
00150 friend class expandcmd<StringType>;
00151 friend class expcmd_abbr<StringType>;
00152 expcmd_abbr<StringType> cmd_abbr;
00153 friend class expcmd_bpad<StringType>;
00154 expcmd_bpad<StringType> cmd_bpad;
00155 friend class expcmd_btrunc<StringType>;
00156 expcmd_btrunc<StringType> cmd_btrunc;
00157 friend class expcmd_fpad<StringType>;
00158 expcmd_fpad<StringType> cmd_fpad;
00159 friend class expcmd_ftrunc<StringType>;
00160 expcmd_ftrunc<StringType> cmd_ftrunc;
00161 friend class expcmd_if<StringType>;
00162 expcmd_if<StringType> cmd_if;
00163 friend class expcmd_knownvars<StringType>;
00164 expcmd_knownvars<StringType> cmd_knownvars;
00165 friend class expcmd_lower<StringType>;
00166 expcmd_lower<StringType> cmd_lower;
00167 friend class expcmd_ltrim<StringType>;
00168 expcmd_ltrim<StringType> cmd_ltrim;
00169 friend class expcmd_numvars<StringType>;
00170 expcmd_numvars<StringType> cmd_numvars;
00171 friend class expcmd_rtrim<StringType>;
00172 expcmd_rtrim<StringType> cmd_rtrim;
00173 friend class expcmd_trim<StringType>;
00174 expcmd_trim<StringType> cmd_trim;
00175 friend class expcmd_unknownvars<StringType>;
00176 expcmd_unknownvars<StringType> cmd_unknownvars;
00177 friend class expcmd_upper<StringType>;
00178 expcmd_upper<StringType> cmd_upper;
00180
00182 bool expand(StringType &dest, const StringType &src, const FVarMapType &vars, ExpandResultsType &results);
00183
00185 inline const StringType::value_type ConvHexToChar(const StringType &h)
00186 {
00187 if ( h.size() != 2 ) throw general_error(_T("ConvHexToChar"),_T("Wrong size!"),h.c_str());
00188
00189 if ( ( h[0] < _T('0') || h[0] > _T('9') ) && ( h[0] < _T('a') || h[0] > _T('f') ) && ( h[0] < _T('A') || h[0] > _T('F') ) ) throw expand_error(_T("ConvHexToChar"),_T("Not a hexadecimal number!"),h.c_str());
00190 if ( ( h[1] < _T('0') || h[1] > _T('9') ) && ( h[1] < _T('a') || h[1] > _T('f') ) && ( h[1] < _T('A') || h[1] > _T('F') ) ) throw expand_error(_T("ConvHexToChar"),_T("Not a hexadecimal number!"),h.c_str());
00191
00192 StringType::value_type ch;
00193
00194 if ( h[0] > _T('F') ) {
00195 ch=(h[0] - _T('a') + 10)*16;
00196 } else if ( h[0] > _T('9') ) {
00197 ch=(h[0] - _T('A') + 10)*16;
00198 } else {
00199 ch=(h[0] - _T('0'))*16;
00200 }
00201
00202 if ( h[1] > _T('F') ) {
00203 ch+=h[1] - _T('a') + 10;
00204 } else if ( h[1] > _T('9') ) {
00205 ch+=h[1] - _T('A') + 10;
00206 } else {
00207 ch+=h[1] - _T('0');
00208 }
00209
00210 return ch;
00211 }
00212
00213 public:
00215 expandable(const StringType & value = StringType(_T("")), const bool iee=true, const bool ige=false) : cmdmap(), InlineExpandErrors(iee), InlineGeneralErrors(ige),
00216 cmd_abbr(this),
00217 cmd_bpad(this),
00218 cmd_btrunc(this),
00219 cmd_fpad(this),
00220 cmd_ftrunc(this),
00221 cmd_if(this),
00222 cmd_knownvars(this),
00223 cmd_lower(this),
00224 cmd_ltrim(this),
00225 cmd_numvars(this),
00226 cmd_rtrim(this),
00227 cmd_trim(this),
00228 cmd_unknownvars(this),
00229 cmd_upper(this),
00230 expstr(value)
00231 {
00232 cmd_abbr.Register();
00233 cmd_bpad.Register();
00234 cmd_btrunc.Register();
00235 cmd_fpad.Register();
00236 cmd_ftrunc.Register();
00237 cmd_if.Register();
00238 cmd_knownvars.Register();
00239 cmd_lower.Register();
00240 cmd_ltrim.Register();
00241 cmd_numvars.Register();
00242 cmd_rtrim.Register();
00243 cmd_trim.Register();
00244 cmd_unknownvars.Register();
00245 cmd_upper.Register();
00246 }
00247
00249 inline bool expandto(StringType &dest, FVarMapType &vars, ExpandResultsType &results) { return expand(dest, expstr, vars, results); }
00250
00252 inline void set_expstr(const StringType &value) { expstr=value; }
00253
00255 inline StringType get_expstr() { return expstr; }
00256 };
00257
00263 const _TCHAR TwoCharVarDelimiter = _T('%');
00264 const _TCHAR RealVarDelimiter = _T('$');
00265 const _TCHAR CommandDelimiter = _T('#');
00266 const _TCHAR VarnameOpenChar = _T('{');
00267 const _TCHAR VarnameCloseChar = _T('}');
00268 const _TCHAR ParamsOpenChar = _T('(');
00269 const _TCHAR ParamsCloseChar = _T(')');
00270 const _TCHAR ParamsSeperator = _T(';');
00271
00272
00321 template <class StringType> bool expandable<StringType>::expand(StringType &dest, const StringType &src, const FVarMapType &vars, ExpandResultsType &results)
00322 {
00323
00324
00325
00326 enum {
00327 searching,
00328 twocharvar,
00329 realvar,
00330
00331 twocharvarchk,
00332 realvarchk,
00333 commandchk,
00334 commandparams,
00335 realvarparams,
00336 realvarafterparams
00337 } mode=searching;
00338 enum {
00339 none,
00340 backslash
00341 };
00342
00343 int level=0;
00344 StringType::const_iterator s_it;
00345
00346 bool pendingparams;
00347
00348 StringType varname;
00349 StringType cmdname;
00350 StringType param;
00351
00352 FParamVectorType params;
00353
00354 int quotemode=none;
00355
00356 StringType * curstring=&dest;
00357
00358
00359
00360
00361 for(s_it=src.begin(); s_it!=src.end(); ++s_it) {
00362
00363 if ( quotemode == backslash ) {
00364
00365
00366 quotemode=none;
00367 if ( curstring != NULL ) (*curstring)+=*s_it;
00368 } else if ( *s_it == _T('\\') ) {
00369
00370
00371 quotemode=backslash;
00372 if ( curstring != NULL && level>0 ) (*curstring)+=_T('\\');
00373 } else {
00374
00375 switch(mode) {
00376
00377
00378
00379
00380 case searching:
00381 {
00382 switch(*s_it) {
00383 case TwoCharVarDelimiter:
00384 {
00385 mode=twocharvarchk;
00386 varname=_T("");
00387 curstring=&varname;
00388 }
00389 break;
00390 case RealVarDelimiter:
00391 {
00392 mode=realvarchk;
00393 curstring=NULL;
00394 }
00395 break;
00396 case CommandDelimiter:
00397 {
00398 mode=commandchk;
00399 cmdname=_T("");
00400 curstring=&cmdname;
00401 }
00402 break;
00403 default:
00404 dest+=*s_it;
00405 }
00406 }
00407 break;
00408
00409
00410
00411
00412 case twocharvarchk:
00413 {
00414 mode=twocharvar;
00415 varname+=*s_it;
00416 }
00417 break;
00418 case twocharvar:
00419 {
00420 varname+=*s_it;
00421 if ( varname.size() >= 2 ) {
00422 mode=searching;
00423 curstring=&dest;
00424
00425 {
00426 try {
00427 dest+=ConvHexToChar(varname);
00428 } catch(general_error e) {
00429 if ( InlineGeneralErrors ) {
00430 dest+=_T('#');
00431 dest+=e.error_message();
00432 dest+=_T('#');
00433 } else {
00434 throw;
00435 }
00436 } catch(expand_error e) {
00437 if ( InlineExpandErrors ) {
00438 dest+=_T('#');
00439 dest+=e.error_message();
00440 dest+=_T('#');
00441 } else {
00442 throw;
00443 }
00444 }
00445 }
00446 }
00447 }
00448 break;
00449
00450
00451
00452
00453 case realvarchk:
00454 {
00455 if ( *s_it == VarnameOpenChar ) {
00456 mode=realvar;
00457 varname=_T("");
00458 curstring=&varname;
00459 } else {
00460 if ( *s_it == RealVarDelimiter ) {
00461 dest+=RealVarDelimiter;
00462 } else if ( InlineExpandErrors ) {
00463 mode=searching;
00464 curstring=&dest;
00465 dest+=_T("#Syntax error#");
00466 } else {
00467 throw expand_error(_T("expandable"),_T("Syntax error!"));
00468 }
00469 }
00470 }
00471 break;
00472 case realvar:
00473 {
00474 if ( *s_it == VarnameCloseChar ) {
00475 mode=searching;
00476 curstring=&dest;
00477
00478 {
00479 const FVarMapType::const_iterator it=vars.find(varname);
00480 if ( it!=vars.end() ) {
00481 try {
00482 (*it).second->AppendValue(dest);
00483 } catch(general_error e) {
00484 if ( InlineGeneralErrors ) {
00485 dest+=_T('#');
00486 dest+=e.error_message();
00487 dest+=_T('#');
00488 } else {
00489 throw;
00490 }
00491 } catch(expand_error e) {
00492 if ( InlineExpandErrors ) {
00493 dest+=_T('#');
00494 dest+=e.error_message();
00495 dest+=_T('#');
00496 } else {
00497 throw;
00498 }
00499 }
00500 ++results.FoundVars;
00501 } else {
00502 ++results.MissedVars;
00503 }
00504 }
00505 } else if ( *s_it == ParamsOpenChar ) {
00506 mode=realvarparams;
00507 param=_T("");
00508 params.clear();
00509 pendingparams=false;
00510 curstring=¶m;
00511 } else {
00512 varname+=*s_it;
00513 }
00514 }
00515 break;
00516 case realvarparams:
00517 {
00518 if ( level > 0 ) {
00519 param+=*s_it;
00520 if ( *s_it == CommandDelimiter ) {
00521 ++level;
00522 } else if ( *s_it == RealVarDelimiter ) {
00523 pendingparams=true;
00524 } else if ( pendingparams ) {
00525 if ( *s_it == ParamsOpenChar ) {
00526 ++level;
00527 pendingparams=false;
00528 } else if ( *s_it == VarnameCloseChar ) {
00529 pendingparams=false;
00530 }
00531 } else if ( *s_it == ParamsCloseChar ) {
00532 --level;
00533 }
00534 } else if ( *s_it == ParamsCloseChar ) {
00535 mode=realvarafterparams;
00536 curstring=NULL;
00537 params.push_back(param);
00538
00539 {
00540 const FVarMapType::const_iterator it=vars.find(varname);
00541 if ( it!=vars.end() ) {
00542 try {
00543 (*it).second->AppendValue(dest, params, vars, results);
00544 } catch(general_error e) {
00545 if ( InlineGeneralErrors ) {
00546 dest+='#';
00547 dest+=e.error_message();
00548 dest+='#';
00549 } else {
00550 throw;
00551 }
00552 } catch(expand_error e) {
00553 if ( InlineExpandErrors ) {
00554 dest+='#';
00555 dest+=e.error_message();
00556 dest+='#';
00557 } else {
00558 throw;
00559 }
00560 }
00561 ++results.FoundVars;
00562 } else {
00563 ++results.MissedVars;
00564 }
00565 }
00566 } else if ( *s_it == ParamsSeperator ) {
00567 params.push_back(param);
00568 param=_T("");
00569 } else if ( *s_it == CommandDelimiter ) {
00570 ++level;
00571 param+=*s_it;
00572 } else if ( *s_it == RealVarDelimiter ) {
00573 pendingparams=true;
00574 param+=*s_it;
00575 } else if ( pendingparams ) {
00576 param+=*s_it;
00577 if ( *s_it == ParamsOpenChar ) {
00578 ++level;
00579 pendingparams=false;
00580 } else if ( *s_it == VarnameCloseChar ) {
00581 pendingparams=false;
00582 }
00583 } else {
00584 param+=*s_it;
00585 }
00586 }
00587 break;
00588 case realvarafterparams:
00589 {
00590 if ( *s_it == VarnameCloseChar ) {
00591 mode=searching;
00592 curstring=&dest;
00593 }
00594 }
00595 break;
00596
00597
00598
00599
00600 case commandchk:
00601 {
00602 if ( *s_it == ParamsOpenChar ) {
00603 mode=commandparams;
00604 param=_T("");
00605 params.clear();
00606 pendingparams=false;
00607 curstring=¶m;
00608 } else {
00609 cmdname+=*s_it;
00610 }
00611 }
00612 break;
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626 case commandparams:
00627 {
00628 if ( level > 0 ) {
00629 param+=*s_it;
00630 if ( *s_it == CommandDelimiter ) {
00631 ++level;
00632 } else if ( *s_it == RealVarDelimiter ) {
00633 pendingparams=true;
00634 } else if ( pendingparams ) {
00635 if ( *s_it == ParamsOpenChar ) {
00636 ++level;
00637 pendingparams=false;
00638 } else if ( *s_it == VarnameCloseChar ) {
00639 pendingparams=false;
00640 }
00641 } else if ( *s_it == ParamsCloseChar ) {
00642 --level;
00643 }
00644 } else if ( *s_it == ParamsCloseChar ) {
00645 mode=searching;
00646 curstring=&dest;
00647 params.push_back(param);
00648
00649 {
00650 const FCmdMapType::const_iterator it=cmdmap.find(cmdname);
00651 if ( it != cmdmap.end() ) {
00652 try {
00653 (*((*it).second))(dest, params, vars, results);
00654 } catch(general_error e) {
00655 if ( InlineGeneralErrors ) {
00656 dest+='#';
00657 dest+=e.error_message();
00658 dest+='#';
00659 } else {
00660 throw;
00661 }
00662 } catch(expand_error e) {
00663 if ( InlineExpandErrors ) {
00664 dest+='#';
00665 dest+=e.error_message();
00666 dest+='#';
00667 } else {
00668 throw;
00669 }
00670 }
00671 }
00672 }
00673 } else if ( *s_it == ParamsSeperator ) {
00674 params.push_back(param);
00675 param=_T("");
00676 } else if ( *s_it == CommandDelimiter ) {
00677 ++level;
00678 param+=*s_it;
00679 } else if ( *s_it == RealVarDelimiter ) {
00680 pendingparams=true;
00681 param+=*s_it;
00682 } else if ( pendingparams ) {
00683 param+=*s_it;
00684 if ( *s_it == ParamsOpenChar ) {
00685 ++level;
00686 pendingparams=false;
00687 } else if ( *s_it == VarnameCloseChar ) {
00688 pendingparams=false;
00689 }
00690 } else {
00691 param+=*s_it;
00692 }
00693 }
00694 break;
00695 }
00696 }
00697 }
00698
00699 if ( mode != searching ) {
00700 if ( InlineExpandErrors ) {
00701 dest+=_T("#Unexpected end of string#");
00702 } else {
00703 throw expand_error(_T("expandable"),_T("Unexpected end of string!"));
00704 }
00705 }
00706
00707 return true;
00708 }
00709 }
00710
00711 #endif //EXPANDLIB_EXPANDABLE_H_INCLUDED