Squashed 'third_party/ctemplate/' content from commit 6742f62

Change-Id: I828e4e4c906f13ba19944d78a8a78652b62949af
git-subtree-dir: third_party/ctemplate
git-subtree-split: 6742f6233db12f545e90baa8f34f5c29c4eb396a
diff --git a/src/diff_tpl_auto_escape.cc b/src/diff_tpl_auto_escape.cc
new file mode 100644
index 0000000..5a833f8
--- /dev/null
+++ b/src/diff_tpl_auto_escape.cc
@@ -0,0 +1,337 @@
+// 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.
+
+// ---
+// Heavily inspired from make_tpl_varnames_h.cc
+//
+// A utility for evaluating the changes in escaping modifiers
+// applied to variables between two versions of a template file.
+// This may come in handy when converting a template to Auto-Escape:
+// If the template previously had escaping modifiers, this tool will show
+// the variables for which Auto-Escaped determined a different escaping.
+//
+// How it works:
+//   . You provide two template files, assumed to be identical in content
+//     (same variables in the same order) except for escaping modifiers
+//     and possibly the AUTOESCAPE pragma. You also provide the Strip mode
+//     or a default of STRIP_WHITESPACE is assumed.
+//
+//   . The tool loads both files and invokes DumpToString on both. It then
+//     compares the escaping modifiers for each variable and when they do
+//     not match, it prints a line with the variable name as well as
+//     the differing modifiers.
+//
+//   . We accept some command-line flags, the most notable are:
+//       --template_dir to set a template root directory other than cwd
+//       --strip to set the Strip mode to other than STRIP_WHITESPACE.
+//         For correct operation of Auto-Escape, ensure this matches
+//         the Strip mode you normally use on these templates.
+//
+//
+// Exit code is zero if there were no differences. It is non-zero
+// if we failed to load the templates or we found one or more
+// differences.
+//
+// TODO(jad): Add flag to optionally report differences when a variable
+//            does not have modifiers in either template.
+
+// This is for opensource ctemplate on windows.  Even though we
+// #include config.h, just like the files used to compile the dll, we
+// are actually a *client* of the dll, so we don't get to decl anything.
+#include <config.h>
+#undef CTEMPLATE_DLL_DECL
+
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <stdarg.h>
+#ifdef HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+#include <string.h>
+#include <string>
+#include <ctemplate/template.h>
+#include <ctemplate/template_pathops.h>
+using std::string;
+using std::vector;
+using GOOGLE_NAMESPACE::Template;
+using GOOGLE_NAMESPACE::TemplateContext;
+using GOOGLE_NAMESPACE::Strip;
+using GOOGLE_NAMESPACE::STRIP_WHITESPACE;
+using GOOGLE_NAMESPACE::STRIP_BLANK_LINES;
+using GOOGLE_NAMESPACE::DO_NOT_STRIP;
+
+enum {LOG_VERBOSE, LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_FATAL};
+
+// A variable name and optional modifiers.
+// For example: in {{NAME:j:x-bla}}
+// variable_name is "NAME" and modifiers is "j:x-bla".
+struct VariableAndMod {
+  VariableAndMod(string name, string mods)
+      : variable_name(name), modifiers(mods) { }
+  string variable_name;
+  string modifiers;
+};
+typedef vector<VariableAndMod> VariableAndMods;
+
+static string FLAG_template_dir(GOOGLE_NAMESPACE::kCWD);   // "./"
+static string FLAG_strip = "";      // cmd-line arg -s
+static bool FLAG_verbose = false;   // cmd-line arg -v
+
+static void LogPrintf(int severity, const char* pat, ...) {
+  if (severity == LOG_VERBOSE && !FLAG_verbose)
+    return;
+  if (severity == LOG_FATAL)
+    fprintf(stderr, "FATAL ERROR: ");
+  if (severity == LOG_VERBOSE)
+    fprintf(stdout, "[VERBOSE] ");
+  va_list ap;
+  va_start(ap, pat);
+  vfprintf(severity == LOG_INFO || severity == LOG_VERBOSE ? stdout: stderr,
+           pat, ap);
+  va_end(ap);
+  if (severity == LOG_FATAL)
+    exit(1);
+}
+
+// Prints to outfile -- usually stdout or stderr -- and then exits
+static int Usage(const char* argv0, FILE* outfile) {
+  fprintf(outfile, "USAGE: %s [-t<dir>] [-v] [-b] [-s<n>] <file1> <file2>\n",
+          argv0);
+
+  fprintf(outfile,
+          "       -t --template_dir=<dir>  Root directory of templates\n"
+          "       -s --strip=<strip>       STRIP_WHITESPACE [default],\n"
+          "                                STRIP_BLANK_LINES, DO_NOT_STRIP\n"
+          "       -h --help                This help\n"
+          "       -v --verbose             For a bit more output\n"
+          "       -V --version             Version information\n");
+  fprintf(outfile, "\n"
+          "This program reports changes to modifiers between two template\n"
+          "files assumed to be identical except for modifiers applied\n"
+          "to variables. One use case is converting a template to\n"
+          "Auto-Escape and using this program to obtain the resulting\n"
+          "changes in escaping modifiers.\n"
+          "The Strip value should match what you provide in\n"
+          "Template::GetTemplate.\n"
+          "NOTE: Variables that do not have escaping modifiers in one of\n"
+          "two templates are ignored and do not count in the differences.\n");
+  exit(0);
+}
+
+static int Version(FILE* outfile) {
+  fprintf(outfile,
+          "diff_tpl_auto_escape (part of google-template 0.9x)\n"
+          "\n"
+          "Copyright 2008 Google Inc.\n"
+          "\n"
+          "This is BSD licensed software; see the source for copying conditions\n"
+          "and license information.\n"
+          "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"
+          "PARTICULAR PURPOSE.\n"
+          );
+  exit(0);
+}
+
+// Populates the vector of VariableAndMods from the DumpToString
+// representation of the template file.
+//
+// Each VariableAndMod represents a variable node found in the template
+// along with the optional modifiers attached to it (or empty string).
+// The parsing is very simple. It looks for lines of the form:
+//    "Variable Node: <VAR_NAME>[:<VAR_MODS>]\n"
+// as outputted by DumpToString() and extracts from each such line the
+// variable name and modifiers when present.
+// Because DumpToString also outputs text nodes, it is possible
+// to trip this function. Probably ok since this is just a helper tool.
+bool LoadVariables(const char* filename, Strip strip,
+                   VariableAndMods& vars_and_mods) {
+  const string kVariablePreambleText = "Variable Node: ";
+  Template *tpl;
+  tpl = Template::GetTemplate(filename, strip);
+  if (tpl == NULL) {
+    LogPrintf(LOG_FATAL, "Could not load file: %s\n", filename);
+    return false;
+  }
+
+  string output;
+  tpl->DumpToString(filename, &output);
+
+  string::size_type index = 0;
+  string::size_type delim, end;
+  // TODO(jad): Switch to using regular expressions.
+  while((index = output.find(kVariablePreambleText, index)) != string::npos) {
+    index += kVariablePreambleText.length();
+    end = output.find('\n', index);
+    if (end == string::npos) {
+      // Should never happen but no need to LOG_FATAL.
+      LogPrintf(LOG_ERROR, "%s: Did not find terminating newline...\n",
+                filename);
+      end = output.length();
+    }
+    string name_and_mods = output.substr(index, end - index);
+    delim = name_and_mods.find(":");
+    if (delim == string::npos)          // no modifiers.
+      delim = name_and_mods.length();
+    VariableAndMod var_mod(name_and_mods.substr(0, delim),
+                           name_and_mods.substr(delim));
+    vars_and_mods.push_back(var_mod);
+  }
+  return true;
+}
+
+// Returns true if the difference in the modifier strings
+// is non-significant and can be safely omitted. This is the
+// case when one is ":j:h" and the other is ":j" since
+// the :h is a no-op after a :j.
+bool SuppressLameDiff(string modifiers_a, string modifiers_b) {
+  if ((modifiers_a == ":j:h" && modifiers_b == ":j") ||
+      (modifiers_a == ":j" && modifiers_b == ":j:h"))
+    return true;
+  return false;
+}
+
+// Main function to analyze differences in escaping modifiers between
+// two template files. These files are assumed to be identical in
+// content [strictly speaking: same number of variables in the same order].
+// If that is not the case, we fail.
+// We return true if there were no differences, false if we failed
+// or we found one or more differences.
+bool DiffTemplates(const char* filename_a, const char* filename_b,
+                   Strip strip) {
+  vector<VariableAndMod> vars_and_mods_a, vars_and_mods_b;
+
+  if (!LoadVariables(filename_a, strip, vars_and_mods_a) ||
+      !LoadVariables(filename_b, strip, vars_and_mods_b))
+    return false;
+
+  if (vars_and_mods_a.size() != vars_and_mods_b.size())
+    LogPrintf(LOG_FATAL, "Templates differ: %s [%d vars] vs. %s [%d vars].\n",
+              filename_a, vars_and_mods_a.size(),
+              filename_b, vars_and_mods_b.size());
+
+  int mismatch_count = 0;      // How many differences there were.
+  int no_modifiers_count = 0;  // How many variables without modifiers.
+  VariableAndMods::const_iterator iter_a, iter_b;
+  for (iter_a = vars_and_mods_a.begin(), iter_b = vars_and_mods_b.begin();
+       iter_a != vars_and_mods_a.end() && iter_b != vars_and_mods_b.end();
+       ++iter_a, ++iter_b) {
+    // The templates have different variables, we fail!
+    if (iter_a->variable_name != iter_b->variable_name)
+      LogPrintf(LOG_FATAL, "Variable name mismatch: %s vs. %s\n",
+                iter_a->variable_name.c_str(),
+                iter_b->variable_name.c_str());
+    // Variables without modifiers are ignored from the diff. They simply
+    // get counted and the count is shown in verbose logging/
+    if (iter_a->modifiers == "" || iter_b->modifiers == "") {
+      no_modifiers_count++;
+    } else {
+      if (iter_a->modifiers != iter_b->modifiers &&
+          !SuppressLameDiff(iter_a->modifiers, iter_b->modifiers)) {
+        mismatch_count++;
+        LogPrintf(LOG_INFO, "Difference for variable %s -- %s vs. %s\n",
+                  iter_a->variable_name.c_str(),
+                  iter_a->modifiers.c_str(), iter_b->modifiers.c_str());
+      }
+    }
+  }
+
+  LogPrintf(LOG_VERBOSE, "Variables Found: Total=%d; Diffs=%d; NoMods=%d\n",
+            vars_and_mods_a.size(), mismatch_count, no_modifiers_count);
+
+  return (mismatch_count == 0);
+}
+
+int main(int argc, char **argv) {
+#if defined(HAVE_GETOPT_LONG)
+  static struct option longopts[] = {
+    {"help", 0, NULL, 'h'},
+    {"strip", 1, NULL, 's'},
+    {"template_dir", 1, NULL, 't'},
+    {"verbose", 0, NULL, 'v'},
+    {"version", 0, NULL, 'V'},
+    {0, 0, 0, 0}
+  };
+  int option_index;
+# define GETOPT(argc, argv)  getopt_long(argc, argv, "t:s:hvV", \
+                                         longopts, &option_index)
+#elif defined(HAVE_GETOPT_H)
+# define GETOPT(argc, argv)  getopt(argc, argv, "t:s:hvV")
+#else
+  // TODO(csilvers): implement something reasonable for windows/etc
+# define GETOPT(argc, argv)  -1
+  int optind = 1;    // first non-opt argument
+  const char* optarg = "";   // not used
+#endif
+
+  int r = 0;
+  while (r != -1) {   // getopt()/getopt_long() return -1 upon no-more-input
+    r = GETOPT(argc, argv);
+    switch (r) {
+      case 's': FLAG_strip.assign(optarg); break;
+      case 't': FLAG_template_dir.assign(optarg); break;
+      case 'v': FLAG_verbose = true; break;
+      case 'V': Version(stdout); break;
+      case -1: break;   // means 'no more input'
+      default: Usage(argv[0], stderr);
+    }
+  }
+
+  Template::SetTemplateRootDirectory(FLAG_template_dir);
+
+
+  if (argc != (optind + 2))
+    LogPrintf(LOG_FATAL,
+              "Must specify exactly two template files on the command line.\n");
+
+  // Validate the Strip value. Default is STRIP_WHITESPACE.
+  Strip strip = STRIP_WHITESPACE;   // To avoid compiler warnings.
+  if (FLAG_strip == "STRIP_WHITESPACE" || FLAG_strip == "")
+    strip = STRIP_WHITESPACE;
+  else if (FLAG_strip == "STRIP_BLANK_LINES")
+    strip = STRIP_BLANK_LINES;
+  else if (FLAG_strip == "DO_NOT_STRIP")
+    strip = DO_NOT_STRIP;
+  else
+    LogPrintf(LOG_FATAL, "Unrecognized Strip: %s. Must be one of: "
+              "STRIP_WHITESPACE, STRIP_BLANK_LINES or DO_NOT_STRIP\n",
+              FLAG_strip.c_str());
+
+  const char* filename_a = argv[optind];
+  const char* filename_b = argv[optind + 1];
+  LogPrintf(LOG_VERBOSE, "------ Diff of [%s, %s] ------\n",
+            filename_a, filename_b);
+
+  if (DiffTemplates(filename_a, filename_b, strip))
+    return 0;
+  else
+    return 1;
+}