// Copyright (c) 2006, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Frank H. Jernigan // // This file implements the Template class. For information about // how to use this class, and to write the templates it takes as input, // see doc/howto.html #ifndef _TEMPLATE_H #define _TEMPLATE_H #include // for time_t #include #include // We include this just so folks don't have to include both template.h // and template_dictionary.h, or template_namelist.h etc, to use the // template system; we don't actually use anything in these files ourselves. #if 1 #include #include #else @ac_google_start_namespace@ class TemplateDictionary; @ac_google_end_namespace@ #endif @ac_windows_dllexport_defines@ @ac_google_start_namespace@ // TemplateState of a template is: // - TS_EMPTY before parsing is complete, // - TS_ERROR if a syntax error was found during parsing, and // - TS_READY if parsing has completed successfully // - TS_SHOULD_RELOAD if marked to reload next time it is called for // (TS_UNUSED is not used) enum TemplateState { TS_UNUSED, TS_EMPTY, TS_ERROR, TS_READY, TS_SHOULD_RELOAD }; // Template // The object which reads and parses the template file and then is used to // expand the parsed structure to a string. class @ac_windows_dllexport@ Template { public: // GetTemplate (static Template factory method) // Attempts to retrieve the template object from the cache, stored // under its filename. This will fail only the first time the method // is invoked for a given filename. // Any object retrieved from the cache is then checked to see if // its status is marked for "reload if changed." If so, ReloadIfChanged // is called on the retrieved object. Then the retrieved object is // returned. // When it fails to retrieve one from the cache, it creates a new // template object, passing the filename and 'strip' values to the // constructor. (See constructor below for the meaning of the flags.) // If it succeeds in creating an object, including loading and parsing // the associated template file, the object is stored in the cache // and then returned. // If it fails in loading and parsing the template file, either // because the file was not found or it contained syntax errors, then // the newly created object is deleted and the method returns NULL. // (NOTE: This description is much longer and less precise and probably // harder to understand than the method itself. Read the code.) // // 'Strip' indicates how to handle whitespace when expanding the // template. DO_NOT_STRIP keeps the template exactly as-is. // STRIP_BLANK_LINES elides all blank lines in the template. // STRIP_WHITESPACE elides all blank lines, and also all whitespace // at either the beginning or end of a line. See template constructor // for more details. static Template *GetTemplate(const std::string& filename, Strip strip); // Template destructor virtual ~Template(); // SetTemplateRootDirectory // Sets the root directory for all templates used by the program. // After calling this method, the filename passed to GetTemplate // may be a relative pathname (no leading '/'), in which case // this root-directory is prepended to the filename. static bool SetTemplateRootDirectory(const std::string& directory); // ReloadAllIfChanged // Marks each template object in the cache to check to see if // its template file has changed the next time it is invoked // via GetTemplate. If it finds the file has changed, it // then reloads and parses the file before being returned by // GetTemplate. static void ReloadAllIfChanged(); // ClearCache // Deletes all the template objects in the cache. This should only // be done once, just before exiting the program and after all // template expansions are completed. (If you want to refresh the // cache, the correct method to use is ReloadAllIfChanged, not // this one.) Note: this method is not necessary unless you are // testing for memory leaks. Calling this before exiting the // program will prevent unnecessary reporting in that case. static void ClearCache(); // Expand // Expands the template into a string using the values // in the supplied dictionary. Returns true iff all the template // files load and parse correctly. bool Expand(std::string *output_buffer, const TemplateDictionary *dictionary) const; // Dump // Dumps the parsed structure to stdout for debugging assistance void Dump(const char *filename) const; // state // Retrieves the state of the template (see TemplateState above) TemplateState state() const; // template_file // Returns the name of the template file used to build this template const char *template_file() const; // ReloadIfChanged // Reloads the file from the filesystem iff its mtime is different // now from what it was last time the file was reloaded. Note a // file is always "reloaded" the first time this is called. If // the file is in fact reloaded, then the contents of the file are // parsed into the template node parse tree by calling BuildTree // After this call, the state of the Template will be either // TS_READY or TS_ERROR. Return value is true iff we reloaded // because the content changed and could be parsed with no errors. bool ReloadIfChanged(); // template_root_directory // Returns the stored template root directory name static std::string template_root_directory(); // WriteHeaderEntries void WriteHeaderEntries(std::string *outstring) const; protected: friend class SectionTemplateNode; // for access to set_state(), ParseState friend class TemplateTemplateNode; // for recursive call to Expand() // AssureGlobalsInitialized // Initializes the global (static) variables the first time it is // called. After that it simply checks one of the // initialized pointers and finds it has already been called. static void AssureGlobalsInitialized(); // Template constructor // Reads the template file and parses it into a parse tree of TemplateNodes // by calling the method ReloadIfChanged // The top node is a section node with the arbitrary name "__MAIN__" // 'Strip' indicates how to handle whitespace when expanding the // template. DO_NOT_STRIP keeps the template exactly as-is. // STRIP_BLANK_LINES elides all blank lines in the template. // STRIP_WHITESPACE elides all blank lines, and also all whitespace // at either the beginning or end of a line. It also removes // any linefeed (possibly following whitespace) that follows a closing // '}}' of any kind of template marker EXCEPT a template variable. // This means a linefeed may be removed anywhere by simply placing // a comment marker as the last element on the line. // These two options allow the template to include whitespace for // readability without adding to the expanded output. Template(const std::string& filename, Strip strip); // BuildTree // Parses the contents of the file (retrieved via ReloadIfChanged) // and stores the resulting parse structure in tree_. Returns true // iff the tree-builder encountered no errors. bool BuildTree(const char *input_buffer, const char* input_buffer_end); // Internal version of Expand, used for recursive calls. // force_annotate_dict is a dictionary that can be used to force // annotations: even if dictionary->ShouldAnnotateOutput() is false, // if force_annotate_dict->ShouldAnnotateOutput() is true, we annotate. bool Expand(class ExpandEmitter *expand_emitter, const TemplateDictionary *dictionary, const TemplateDictionary *force_annotate_dict) const; // Internal version of ReloadIfChanged, used when the function already // has a write-lock on mutex_. bool ReloadIfChangedLocked(); // set_state // Sets the state of the template. Used during BuildTree(). void set_state(TemplateState new_state); // InsertLine and InsertFile // Writes each line to buffer, and returns number of bytes written. // A line is a string of characters that ends with a \n (or \0). // (We need to be line-based because Strip works line-by-line). // buffer must be big enough to hold the output. It's guaranteed // that the output size is no bigger than the input size. // Used by ReloadIfChanged() int InsertLine(const char *line, int len, char* buffer); int InsertFile(const char *file, size_t len, char* buffer); // The file we read the template from std::string filename_; // can't be const because of TemplateFromString :-( time_t filename_mtime_; // lastmod time for filename last time we loaded it // What to do with whitespace at template-expand time const Strip strip_; // Keeps track of where we are in reloading, or if there was an error loading TemplateState state_; // The current template-contents, as read from the file const char* template_text_; int template_text_len_; // The current parsed template structure. Has pointers into template_text_. class SectionTemplateNode *tree_; // defined in template.cc // The current parsing state. Used in BuildTree() and subroutines struct ParseState { const char* bufstart; const char* bufend; enum { PS_UNUSED, GETTING_TEXT, GETTING_NAME } phase; ParseState() : bufstart(NULL), bufend(NULL), phase(PS_UNUSED) {} }; ParseState parse_state_; // The mutex object used during ReloadIfChanged to prevent the same // object from reloading the template file in parallel by different // threads. mutable class Mutex* mutex_; // The root directory for all templates. Defaults to "./" until // SetTemplateRootDirectory changes it static std::string *template_root_directory_; private: // Can't invoke copy constructor or assignment operator Template(const Template&); void operator=(const Template &); }; @ac_google_end_namespace@ #endif // _TEMPLATE_H