thrift: Add -cpp_use_include_prefix flag to compiler

Summary: Adds a new flag to allow for a mode where #include statements in generated c++ will include path context information.  For example, if my .thrift file includes "foo/bar/baz.thrift", the generated source files will contain #include statements like:

         #include "foo/bar/gen-cpp/baz_types.h"

         instead of just:

         #include "baz_types.h"

         -cpp_use_include_prefix is OFF by default.

Reviewed By: dreiss

Test Plan: Tested against multiple thrift input files both with and without the new flag.

Revert: OK

DiffCamp Revision: 5522


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665431 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/parse/t_program.h b/compiler/cpp/src/parse/t_program.h
index 62528e6..7b369d6 100644
--- a/compiler/cpp/src/parse/t_program.h
+++ b/compiler/cpp/src/parse/t_program.h
@@ -70,6 +70,9 @@
   // Namespace
   const std::string& get_namespace() const { return namespace_; }
 
+  // Include prefix accessor
+  const std::string& get_include_prefix() const { return include_prefix_; }
+
   // Accessors for program elements
   const std::vector<t_typedef*>& get_typedefs()  const { return typedefs_;  }
   const std::vector<t_enum*>&    get_enums()     const { return enums_;     }
@@ -113,14 +116,35 @@
 
   // Includes
 
-  void add_include(std::string path) {
-    includes_.push_back(new t_program(path));
+  void add_include(std::string path, std::string include_site) {
+    t_program* program = new t_program(path);
+
+    // include prefix for this program is the site at which it was included
+    // (minus the filename)
+    std::string include_prefix;
+    std::string::size_type last_slash = std::string::npos;
+    if ((last_slash = include_site.rfind("/")) != std::string::npos) {
+      include_prefix = include_site.substr(0, last_slash);
+    }
+
+    program->set_include_prefix(include_prefix);
+    includes_.push_back(program);
   }
 
   std::vector<t_program*>& get_includes() {
     return includes_;
   }
 
+  void set_include_prefix(std::string include_prefix) {
+    include_prefix_ = include_prefix;
+
+    // this is intended to be a directory; add a trailing slash if necessary
+    int len = include_prefix_.size();
+    if (len > 0 && include_prefix_[len - 1] != '/') {
+      include_prefix_ += '/';
+    }
+  }
+
   // Language specific namespace / packaging
 
   void set_cpp_namespace(std::string cpp_namespace) {
@@ -236,6 +260,9 @@
   // Included programs
   std::vector<t_program*> includes_;
 
+  // Include prefix for this program, if any
+  std::string include_prefix_;
+
   // Identifier lookup scope
   t_scope* scope_;