/* * Copyright (C) 2007-2014 Xagasoft, All rights reserved. * * This file is part of the libbu++ library and is released under the * terms of the license contained in the file LICENSE. */ #ifndef BU_MINI_MACRO_H #define BU_MINI_MACRO_H #include "bu/hash.h" #include "bu/string.h" namespace Bu { typedef Bu::Hash StrHash; /** * A processor for Libbu++ brand Mini Macros. These are really simple, but * still fairly flexible. It's mainly text replacement, but with a few * extras like filter functions and conditional text segments. So far we * don't support loops or anything, I'm not sure we ever will. * * Anatomy of a mini macro: * - Every macro begins with a two character code, the first character is * always '{', the second character determines the operation to perform. * - If the '{' is followed by a character that is not valid it is not * considered for expansion and the characters are copied to the output. * - Every macro ends with a closing '}' * - Macro types: * - '=': variable replacement. The '=' is immediatley followed by the * name of the variable to replace, then any number of optional filter * segments. * - '?': conditional text. The '?' is immediately followed by the * variable to test. This works two ways, the variable can be alone, in * which case it's existance is tested, or it can be followed by a "=" * and a string to compare to. This is then followed by a text segment * that will be used if the test is true, and an optional text segment * to be used if the test is false. * - ':': command. The ':' is immediately followed by a command string, * of which there's only one right now, but that's ok. These are not * put into the output stream, but instead mark something for the * parser. Currently supported: * - {:end}: end of parsing, stop here, also make note of how many input * characters were used. * - Segments: * - Each segment is seperated by a colon. * - Filter segments give the name of the filter, followed by * parenthesies. Parameters may be provided within the parenthesies. * - Text segments should always be quoted, but may contain any characters * within the quotes, backslash is used as per C/ANSI/ISO standard. * You can also quote any text using [' '] instead of quotes, which * allows for nested strings. The [' token is only recognised within * a macro. * *@verbatim {=name:tolower()} {=name:ccsplit("_"):toupper()} {?name:"name exists and is {=name}"} {?name:"{=name}":"no name!"} {?name="bob":"You're named bob!":"Who are you? I only know bob..."} @endverbatim */ class MiniMacro { public: MiniMacro(); MiniMacro( const StrHash &sVarSrc ); virtual ~MiniMacro(); Bu::String parse( const Bu::String &sIn ); void addVar( const Bu::String &sName, const Bu::String &sValue ); bool hasVar( const Bu::String &sName ); const Bu::String &getVar( const Bu::String &sName ); const StrHash &getVars(); int getPosition(); private: const char *sCur; Bu::String parseRepl(); Bu::String parseCond(); Bu::String parseCmd(); Bu::String callFunc( const Bu::String &sIn, const Bu::String &sFunc ); StrHash hVars; bool bContinue; int iLastPos; public: typedef Bu::List StrList; class Func { public: Func(){} virtual ~Func(){} virtual Bu::String call( const Bu::String &sIn, StrList &lsParam )=0; }; class FuncToUpper : public Func { public: FuncToUpper(){} virtual ~FuncToUpper(){} virtual Bu::String call( const Bu::String &sIn, StrList & ) { return sIn.toUpper(); } }; class FuncToLower : public Func { public: FuncToLower(){} virtual ~FuncToLower(){} virtual Bu::String call( const Bu::String &sIn, StrList & ) { return sIn.toLower(); } }; private: typedef Bu::Hash FuncHash; FuncHash hFuncs; }; }; #endif