Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

expandlib-expandable.h

Go to the documentation of this file.
00001 
00002 /* This file is part of Expandlib.
00003 
00004   Copyright (C) 2002 Jasper van de Gronde
00005 
00006   This software is provided 'as-is', without any express or implied
00007   warranty.  In no event will the authors be held liable for any damages
00008   arising from the use of this software.
00009 
00010   Permission is granted to anyone to use this software for any purpose,
00011   including commercial applications, and to alter it and redistribute it
00012   freely, subject to the following restrictions:
00013 
00014   1. The origin of this software must not be misrepresented; you must not
00015      claim that you wrote the original software. If you use this software
00016      in a product, an acknowledgment in the product documentation would be
00017      appreciated but is not required.
00018   2. Altered source versions must be plainly marked as such, and must not be
00019      misrepresented as being the original software.
00020   3. This notice may not be removed or altered from any source distribution.
00021 
00022   Jasper van de Gronde th.v.d.gronde@hccnet.nl
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 // This is done because all the commands need to know expandable exists (they all hold a pointer to an expandable class)
00073 namespace expander {
00074     template <
00075         class StringType = ::std::string            // Used for the expandable string (and the expanded string)
00076         > class expandable;
00077 }
00078 
00079 #include "expandlib-cmd.h"
00080 #include "expandlib-vartype.h"
00081 #include "expandlib-exceptions.h"
00082 
00083 // Commands that will be supported
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 // Disables "'this' : used in base member initializer list"
00100 #pragma warning(disable: 4355)
00101 
00103 
00107 namespace expander { // *** Start of namespace
00108 
00110 
00120     template <
00121         class StringType = ::std::string            // Used for the expandable string (and the expanded 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') ) {         // a-f
00195                 ch=(h[0] - _T('a') + 10)*16;
00196             } else if ( h[0] > _T('9') ) {  // A-F
00197                 ch=(h[0] - _T('A') + 10)*16;
00198             } else {                    // 0-9
00199                 ch=(h[0] - _T('0'))*16;
00200             }
00201 
00202             if ( h[1] > _T('F') ) {         // a-f
00203                 ch+=h[1] - _T('a') + 10;
00204             } else if ( h[1] > _T('9') ) {  // A-F
00205                 ch+=h[1] - _T('A') + 10;
00206             } else {                    // 0-9
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         // NOTE: expand (and any functions called by it) are NOT allowed to delete from rvars (and/or free) elements of rvars they did not create themselves
00324 
00325         // *** All kinds of variable declarations
00326         enum {
00327             searching,
00328             twocharvar,
00329             realvar,
00330 //          command, // Only commandchk is used
00331             twocharvarchk,
00332             realvarchk,
00333             commandchk,
00334             commandparams,
00335             realvarparams,
00336             realvarafterparams
00337         } mode=searching;               // Used to keep track of the current "mode"
00338         enum {
00339             none,
00340             backslash
00341         };                              // Used for quotemode, I couldn't use a named enum as template argument, so I chose this solution
00342 
00343         int level=0;                    // Used for commandparams, to keep track of how deep we are in nested commands (command)
00344         StringType::const_iterator s_it;// Used for going through the src string
00345 
00346         bool pendingparams;             // Used for variable params, because they can't be escaped immediately
00347 
00348         StringType varname;             // Used for the name of rvars and for hex numbers (twocharvar, realvar)
00349         StringType cmdname;             // Used to store the name of the command now processing/reading (command)
00350         StringType param;               // Used to store the value of the param now reading (command)
00351 
00352         FParamVectorType params;        // Used to store read parameters (command)
00353         //::std::deque<int> quotemode;
00354         int quotemode=none;             // Used to keep track of the current quote status, originally it was designed to be much more flexible, that is why a deque is (was) used
00355 
00356         StringType * curstring=&dest;   // Used to keep track of the current string to write to, in case something is quoted
00357 
00358         // *** Start of the mainloop (, after some initing)
00359         //quotemode.push_front(none);
00360 
00361         for(s_it=src.begin(); s_it!=src.end(); ++s_it) {
00362 //          if ( quotemode[0] == backslash ) {
00363             if ( quotemode == backslash ) {
00364                 // Quoted by a backslash
00365                 //quotemode.pop_front();
00366                 quotemode=none;
00367                 if ( curstring != NULL ) (*curstring)+=*s_it;
00368             } else if ( *s_it == _T('\\') ) {
00369                 // Encountering a backslash
00370                 //quotemode.push_front(backslash);
00371                 quotemode=backslash;
00372                 if ( curstring != NULL && level>0 ) (*curstring)+=_T('\\'); // This has to do with not removing backslashes from nested #if's (and similar stuff)
00373             } else {
00374                 // Not quoted
00375                 switch(mode) {
00376 
00377 
00378                 // Searching mode (inbetween commands, twocharvars and realvars)
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                 // Twochar mode
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                 // Realvar mode
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=&param;
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 ) { // Apparantly there were no parameters with this var
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 ) { // Apparantly there were no parameters with this var
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                 // Command mode
00599 
00600                 case commandchk:
00601                     {
00602                         if ( *s_it == ParamsOpenChar ) {
00603                             mode=commandparams;
00604                             param=_T("");
00605                             params.clear();
00606                             pendingparams=false;
00607                             curstring=&param;
00608                         } else {
00609                             cmdname+=*s_it;
00610                         }
00611                     }
00612                     break;
00613 /*              case command:
00614                     {
00615                         if ( *s_it == ParamsOpenChar ) {
00616                             mode=commandparams;
00617                             param="";
00618                             params.clear();
00619                             pendingparams=false;
00620                             curstring=&param;
00621                         } else {
00622                             cmdname+=*s_it;
00623                         }
00624                     }
00625                     break;*/
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 ) { // Apparantly there were no parameters with this var
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;    // Should also be pendingparams=true, but it doesn't need to be, so why bother
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 ) { // Apparantly there were no parameters with this var
00688                                 pendingparams=false;
00689                             }
00690                         } else {
00691                             param+=*s_it;
00692                         }
00693                     }
00694                     break;
00695                 } // End of switch(mode)
00696             } // End of else (from the quotemode if)
00697         } // End of main for loop
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 } // *** End of namespace
00710 
00711 #endif //EXPANDLIB_EXPANDABLE_H_INCLUDED

Generated on Tue Feb 4 17:24:13 2003 for ExpandLib by doxygen1.3-rc2