Home | History | Annotate | Download | only in compiler
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // https://developers.google.com/protocol-buffers/
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 // Author: kenton (at) google.com (Kenton Varda)
     32 //  Based on original Protocol Buffers design by
     33 //  Sanjay Ghemawat, Jeff Dean, and others.
     34 
     35 #include <google/protobuf/compiler/command_line_interface.h>
     36 
     37 #include <stdio.h>
     38 #include <sys/types.h>
     39 #include <sys/stat.h>
     40 #include <fcntl.h>
     41 #ifdef _MSC_VER
     42 #include <io.h>
     43 #include <direct.h>
     44 #else
     45 #include <unistd.h>
     46 #endif
     47 #include <errno.h>
     48 #include <iostream>
     49 #include <ctype.h>
     50 
     51 #include <google/protobuf/stubs/hash.h>
     52 #include <memory>
     53 
     54 #include <google/protobuf/stubs/common.h>
     55 #include <google/protobuf/stubs/stringprintf.h>
     56 #include <google/protobuf/compiler/importer.h>
     57 #include <google/protobuf/compiler/code_generator.h>
     58 #include <google/protobuf/compiler/plugin.pb.h>
     59 #include <google/protobuf/compiler/subprocess.h>
     60 #include <google/protobuf/compiler/zip_writer.h>
     61 #include <google/protobuf/descriptor.h>
     62 #include <google/protobuf/text_format.h>
     63 #include <google/protobuf/dynamic_message.h>
     64 #include <google/protobuf/io/coded_stream.h>
     65 #include <google/protobuf/io/zero_copy_stream_impl.h>
     66 #include <google/protobuf/io/printer.h>
     67 #include <google/protobuf/stubs/strutil.h>
     68 #include <google/protobuf/stubs/substitute.h>
     69 #include <google/protobuf/stubs/map_util.h>
     70 #include <google/protobuf/stubs/stl_util.h>
     71 
     72 
     73 namespace google {
     74 namespace protobuf {
     75 namespace compiler {
     76 
     77 #if defined(_WIN32)
     78 #define mkdir(name, mode) mkdir(name)
     79 #ifndef W_OK
     80 #define W_OK 02  // not defined by MSVC for whatever reason
     81 #endif
     82 #ifndef F_OK
     83 #define F_OK 00  // not defined by MSVC for whatever reason
     84 #endif
     85 #ifndef STDIN_FILENO
     86 #define STDIN_FILENO 0
     87 #endif
     88 #ifndef STDOUT_FILENO
     89 #define STDOUT_FILENO 1
     90 #endif
     91 #endif
     92 
     93 #ifndef O_BINARY
     94 #ifdef _O_BINARY
     95 #define O_BINARY _O_BINARY
     96 #else
     97 #define O_BINARY 0     // If this isn't defined, the platform doesn't need it.
     98 #endif
     99 #endif
    100 
    101 namespace {
    102 #if defined(_WIN32) && !defined(__CYGWIN__)
    103 static const char* kPathSeparator = ";";
    104 #else
    105 static const char* kPathSeparator = ":";
    106 #endif
    107 
    108 // Returns true if the text looks like a Windows-style absolute path, starting
    109 // with a drive letter.  Example:  "C:\foo".  TODO(kenton):  Share this with
    110 // copy in importer.cc?
    111 static bool IsWindowsAbsolutePath(const string& text) {
    112 #if defined(_WIN32) || defined(__CYGWIN__)
    113   return text.size() >= 3 && text[1] == ':' &&
    114          isalpha(text[0]) &&
    115          (text[2] == '/' || text[2] == '\\') &&
    116          text.find_last_of(':') == 1;
    117 #else
    118   return false;
    119 #endif
    120 }
    121 
    122 void SetFdToTextMode(int fd) {
    123 #ifdef _WIN32
    124   if (_setmode(fd, _O_TEXT) == -1) {
    125     // This should never happen, I think.
    126     GOOGLE_LOG(WARNING) << "_setmode(" << fd << ", _O_TEXT): " << strerror(errno);
    127   }
    128 #endif
    129   // (Text and binary are the same on non-Windows platforms.)
    130 }
    131 
    132 void SetFdToBinaryMode(int fd) {
    133 #ifdef _WIN32
    134   if (_setmode(fd, _O_BINARY) == -1) {
    135     // This should never happen, I think.
    136     GOOGLE_LOG(WARNING) << "_setmode(" << fd << ", _O_BINARY): " << strerror(errno);
    137   }
    138 #endif
    139   // (Text and binary are the same on non-Windows platforms.)
    140 }
    141 
    142 void AddTrailingSlash(string* path) {
    143   if (!path->empty() && path->at(path->size() - 1) != '/') {
    144     path->push_back('/');
    145   }
    146 }
    147 
    148 bool VerifyDirectoryExists(const string& path) {
    149   if (path.empty()) return true;
    150 
    151   if (access(path.c_str(), F_OK) == -1) {
    152     cerr << path << ": " << strerror(errno) << endl;
    153     return false;
    154   } else {
    155     return true;
    156   }
    157 }
    158 
    159 // Try to create the parent directory of the given file, creating the parent's
    160 // parent if necessary, and so on.  The full file name is actually
    161 // (prefix + filename), but we assume |prefix| already exists and only create
    162 // directories listed in |filename|.
    163 bool TryCreateParentDirectory(const string& prefix, const string& filename) {
    164   // Recursively create parent directories to the output file.
    165   vector<string> parts = Split(filename, "/", true);
    166   string path_so_far = prefix;
    167   for (int i = 0; i < parts.size() - 1; i++) {
    168     path_so_far += parts[i];
    169     if (mkdir(path_so_far.c_str(), 0777) != 0) {
    170       if (errno != EEXIST) {
    171         cerr << filename << ": while trying to create directory "
    172              << path_so_far << ": " << strerror(errno) << endl;
    173         return false;
    174       }
    175     }
    176     path_so_far += '/';
    177   }
    178 
    179   return true;
    180 }
    181 
    182 }  // namespace
    183 
    184 // A MultiFileErrorCollector that prints errors to stderr.
    185 class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector,
    186                                            public io::ErrorCollector {
    187  public:
    188   ErrorPrinter(ErrorFormat format, DiskSourceTree *tree = NULL)
    189     : format_(format), tree_(tree) {}
    190   ~ErrorPrinter() {}
    191 
    192   // implements MultiFileErrorCollector ------------------------------
    193   void AddError(const string& filename, int line, int column,
    194                 const string& message) {
    195 
    196     // Print full path when running under MSVS
    197     string dfile;
    198     if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS &&
    199         tree_ != NULL &&
    200         tree_->VirtualFileToDiskFile(filename, &dfile)) {
    201       cerr << dfile;
    202     } else {
    203       cerr << filename;
    204     }
    205 
    206     // Users typically expect 1-based line/column numbers, so we add 1
    207     // to each here.
    208     if (line != -1) {
    209       // Allow for both GCC- and Visual-Studio-compatible output.
    210       switch (format_) {
    211         case CommandLineInterface::ERROR_FORMAT_GCC:
    212           cerr << ":" << (line + 1) << ":" << (column + 1);
    213           break;
    214         case CommandLineInterface::ERROR_FORMAT_MSVS:
    215           cerr << "(" << (line + 1) << ") : error in column=" << (column + 1);
    216           break;
    217       }
    218     }
    219 
    220     cerr << ": " << message << endl;
    221   }
    222 
    223   // implements io::ErrorCollector -----------------------------------
    224   void AddError(int line, int column, const string& message) {
    225     AddError("input", line, column, message);
    226   }
    227 
    228  private:
    229   const ErrorFormat format_;
    230   DiskSourceTree *tree_;
    231 };
    232 
    233 // -------------------------------------------------------------------
    234 
    235 // A GeneratorContext implementation that buffers files in memory, then dumps
    236 // them all to disk on demand.
    237 class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
    238  public:
    239   GeneratorContextImpl(const vector<const FileDescriptor*>& parsed_files);
    240   ~GeneratorContextImpl();
    241 
    242   // Write all files in the directory to disk at the given output location,
    243   // which must end in a '/'.
    244   bool WriteAllToDisk(const string& prefix);
    245 
    246   // Write the contents of this directory to a ZIP-format archive with the
    247   // given name.
    248   bool WriteAllToZip(const string& filename);
    249 
    250   // Add a boilerplate META-INF/MANIFEST.MF file as required by the Java JAR
    251   // format, unless one has already been written.
    252   void AddJarManifest();
    253 
    254   // implements GeneratorContext --------------------------------------
    255   io::ZeroCopyOutputStream* Open(const string& filename);
    256   io::ZeroCopyOutputStream* OpenForAppend(const string& filename);
    257   io::ZeroCopyOutputStream* OpenForInsert(
    258       const string& filename, const string& insertion_point);
    259   void ListParsedFiles(vector<const FileDescriptor*>* output) {
    260     *output = parsed_files_;
    261   }
    262 
    263  private:
    264   friend class MemoryOutputStream;
    265 
    266   // map instead of hash_map so that files are written in order (good when
    267   // writing zips).
    268   map<string, string*> files_;
    269   const vector<const FileDescriptor*>& parsed_files_;
    270   bool had_error_;
    271 };
    272 
    273 class CommandLineInterface::MemoryOutputStream
    274     : public io::ZeroCopyOutputStream {
    275  public:
    276   MemoryOutputStream(GeneratorContextImpl* directory, const string& filename,
    277                      bool append_mode);
    278   MemoryOutputStream(GeneratorContextImpl* directory, const string& filename,
    279                      const string& insertion_point);
    280   virtual ~MemoryOutputStream();
    281 
    282   // implements ZeroCopyOutputStream ---------------------------------
    283   virtual bool Next(void** data, int* size) { return inner_->Next(data, size); }
    284   virtual void BackUp(int count)            {        inner_->BackUp(count);    }
    285   virtual int64 ByteCount() const           { return inner_->ByteCount();      }
    286 
    287  private:
    288   // Where to insert the string when it's done.
    289   GeneratorContextImpl* directory_;
    290   string filename_;
    291   string insertion_point_;
    292 
    293   // The string we're building.
    294   string data_;
    295 
    296   // Whether we should append the output stream to the existing file.
    297   bool append_mode_;
    298 
    299   // StringOutputStream writing to data_.
    300   scoped_ptr<io::StringOutputStream> inner_;
    301 };
    302 
    303 // -------------------------------------------------------------------
    304 
    305 CommandLineInterface::GeneratorContextImpl::GeneratorContextImpl(
    306     const vector<const FileDescriptor*>& parsed_files)
    307     : parsed_files_(parsed_files),
    308       had_error_(false) {
    309 }
    310 
    311 CommandLineInterface::GeneratorContextImpl::~GeneratorContextImpl() {
    312   STLDeleteValues(&files_);
    313 }
    314 
    315 bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk(
    316     const string& prefix) {
    317   if (had_error_) {
    318     return false;
    319   }
    320 
    321   if (!VerifyDirectoryExists(prefix)) {
    322     return false;
    323   }
    324 
    325   for (map<string, string*>::const_iterator iter = files_.begin();
    326        iter != files_.end(); ++iter) {
    327     const string& relative_filename = iter->first;
    328     const char* data = iter->second->data();
    329     int size = iter->second->size();
    330 
    331     if (!TryCreateParentDirectory(prefix, relative_filename)) {
    332       return false;
    333     }
    334     string filename = prefix + relative_filename;
    335 
    336     // Create the output file.
    337     int file_descriptor;
    338     do {
    339       file_descriptor =
    340         open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
    341     } while (file_descriptor < 0 && errno == EINTR);
    342 
    343     if (file_descriptor < 0) {
    344       int error = errno;
    345       cerr << filename << ": " << strerror(error);
    346       return false;
    347     }
    348 
    349     // Write the file.
    350     while (size > 0) {
    351       int write_result;
    352       do {
    353         write_result = write(file_descriptor, data, size);
    354       } while (write_result < 0 && errno == EINTR);
    355 
    356       if (write_result <= 0) {
    357         // Write error.
    358 
    359         // FIXME(kenton):  According to the man page, if write() returns zero,
    360         //   there was no error; write() simply did not write anything.  It's
    361         //   unclear under what circumstances this might happen, but presumably
    362         //   errno won't be set in this case.  I am confused as to how such an
    363         //   event should be handled.  For now I'm treating it as an error,
    364         //   since retrying seems like it could lead to an infinite loop.  I
    365         //   suspect this never actually happens anyway.
    366 
    367         if (write_result < 0) {
    368           int error = errno;
    369           cerr << filename << ": write: " << strerror(error);
    370         } else {
    371           cerr << filename << ": write() returned zero?" << endl;
    372         }
    373         return false;
    374       }
    375 
    376       data += write_result;
    377       size -= write_result;
    378     }
    379 
    380     if (close(file_descriptor) != 0) {
    381       int error = errno;
    382       cerr << filename << ": close: " << strerror(error);
    383       return false;
    384     }
    385   }
    386 
    387   return true;
    388 }
    389 
    390 bool CommandLineInterface::GeneratorContextImpl::WriteAllToZip(
    391     const string& filename) {
    392   if (had_error_) {
    393     return false;
    394   }
    395 
    396   // Create the output file.
    397   int file_descriptor;
    398   do {
    399     file_descriptor =
    400       open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
    401   } while (file_descriptor < 0 && errno == EINTR);
    402 
    403   if (file_descriptor < 0) {
    404     int error = errno;
    405     cerr << filename << ": " << strerror(error);
    406     return false;
    407   }
    408 
    409   // Create the ZipWriter
    410   io::FileOutputStream stream(file_descriptor);
    411   ZipWriter zip_writer(&stream);
    412 
    413   for (map<string, string*>::const_iterator iter = files_.begin();
    414        iter != files_.end(); ++iter) {
    415     zip_writer.Write(iter->first, *iter->second);
    416   }
    417 
    418   zip_writer.WriteDirectory();
    419 
    420   if (stream.GetErrno() != 0) {
    421     cerr << filename << ": " << strerror(stream.GetErrno()) << endl;
    422   }
    423 
    424   if (!stream.Close()) {
    425     cerr << filename << ": " << strerror(stream.GetErrno()) << endl;
    426   }
    427 
    428   return true;
    429 }
    430 
    431 void CommandLineInterface::GeneratorContextImpl::AddJarManifest() {
    432   string** map_slot = &files_["META-INF/MANIFEST.MF"];
    433   if (*map_slot == NULL) {
    434     *map_slot = new string(
    435         "Manifest-Version: 1.0\n"
    436         "Created-By: 1.6.0 (protoc)\n"
    437         "\n");
    438   }
    439 }
    440 
    441 io::ZeroCopyOutputStream* CommandLineInterface::GeneratorContextImpl::Open(
    442     const string& filename) {
    443   return new MemoryOutputStream(this, filename, false);
    444 }
    445 
    446 io::ZeroCopyOutputStream*
    447 CommandLineInterface::GeneratorContextImpl::OpenForAppend(
    448     const string& filename) {
    449   return new MemoryOutputStream(this, filename, true);
    450 }
    451 
    452 io::ZeroCopyOutputStream*
    453 CommandLineInterface::GeneratorContextImpl::OpenForInsert(
    454     const string& filename, const string& insertion_point) {
    455   return new MemoryOutputStream(this, filename, insertion_point);
    456 }
    457 
    458 // -------------------------------------------------------------------
    459 
    460 CommandLineInterface::MemoryOutputStream::MemoryOutputStream(
    461     GeneratorContextImpl* directory, const string& filename, bool append_mode)
    462     : directory_(directory),
    463       filename_(filename),
    464       append_mode_(append_mode),
    465       inner_(new io::StringOutputStream(&data_)) {
    466 }
    467 
    468 CommandLineInterface::MemoryOutputStream::MemoryOutputStream(
    469     GeneratorContextImpl* directory, const string& filename,
    470     const string& insertion_point)
    471     : directory_(directory),
    472       filename_(filename),
    473       insertion_point_(insertion_point),
    474       inner_(new io::StringOutputStream(&data_)) {
    475 }
    476 
    477 CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
    478   // Make sure all data has been written.
    479   inner_.reset();
    480 
    481   // Insert into the directory.
    482   string** map_slot = &directory_->files_[filename_];
    483 
    484   if (insertion_point_.empty()) {
    485     // This was just a regular Open().
    486     if (*map_slot != NULL) {
    487       if (append_mode_) {
    488         (*map_slot)->append(data_);
    489       } else {
    490         cerr << filename_ << ": Tried to write the same file twice." << endl;
    491         directory_->had_error_ = true;
    492       }
    493       return;
    494     }
    495 
    496     *map_slot = new string;
    497     (*map_slot)->swap(data_);
    498   } else {
    499     // This was an OpenForInsert().
    500 
    501     // If the data doens't end with a clean line break, add one.
    502     if (!data_.empty() && data_[data_.size() - 1] != '\n') {
    503       data_.push_back('\n');
    504     }
    505 
    506     // Find the file we are going to insert into.
    507     if (*map_slot == NULL) {
    508       cerr << filename_ << ": Tried to insert into file that doesn't exist."
    509            << endl;
    510       directory_->had_error_ = true;
    511       return;
    512     }
    513     string* target = *map_slot;
    514 
    515     // Find the insertion point.
    516     string magic_string = strings::Substitute(
    517         "@@protoc_insertion_point($0)", insertion_point_);
    518     string::size_type pos = target->find(magic_string);
    519 
    520     if (pos == string::npos) {
    521       cerr << filename_ << ": insertion point \"" << insertion_point_
    522            << "\" not found." << endl;
    523       directory_->had_error_ = true;
    524       return;
    525     }
    526 
    527     // Seek backwards to the beginning of the line, which is where we will
    528     // insert the data.  Note that this has the effect of pushing the insertion
    529     // point down, so the data is inserted before it.  This is intentional
    530     // because it means that multiple insertions at the same point will end
    531     // up in the expected order in the final output.
    532     pos = target->find_last_of('\n', pos);
    533     if (pos == string::npos) {
    534       // Insertion point is on the first line.
    535       pos = 0;
    536     } else {
    537       // Advance to character after '\n'.
    538       ++pos;
    539     }
    540 
    541     // Extract indent.
    542     string indent_(*target, pos, target->find_first_not_of(" \t", pos) - pos);
    543 
    544     if (indent_.empty()) {
    545       // No indent.  This makes things easier.
    546       target->insert(pos, data_);
    547     } else {
    548       // Calculate how much space we need.
    549       int indent_size = 0;
    550       for (int i = 0; i < data_.size(); i++) {
    551         if (data_[i] == '\n') indent_size += indent_.size();
    552       }
    553 
    554       // Make a hole for it.
    555       target->insert(pos, data_.size() + indent_size, '\0');
    556 
    557       // Now copy in the data.
    558       string::size_type data_pos = 0;
    559       char* target_ptr = string_as_array(target) + pos;
    560       while (data_pos < data_.size()) {
    561         // Copy indent.
    562         memcpy(target_ptr, indent_.data(), indent_.size());
    563         target_ptr += indent_.size();
    564 
    565         // Copy line from data_.
    566         // We already guaranteed that data_ ends with a newline (above), so this
    567         // search can't fail.
    568         string::size_type line_length =
    569             data_.find_first_of('\n', data_pos) + 1 - data_pos;
    570         memcpy(target_ptr, data_.data() + data_pos, line_length);
    571         target_ptr += line_length;
    572         data_pos += line_length;
    573       }
    574 
    575       GOOGLE_CHECK_EQ(target_ptr,
    576           string_as_array(target) + pos + data_.size() + indent_size);
    577     }
    578   }
    579 }
    580 
    581 // ===================================================================
    582 
    583 CommandLineInterface::CommandLineInterface()
    584   : mode_(MODE_COMPILE),
    585     print_mode_(PRINT_NONE),
    586     error_format_(ERROR_FORMAT_GCC),
    587     imports_in_descriptor_set_(false),
    588     source_info_in_descriptor_set_(false),
    589     disallow_services_(false),
    590     inputs_are_proto_path_relative_(false) {}
    591 CommandLineInterface::~CommandLineInterface() {}
    592 
    593 void CommandLineInterface::RegisterGenerator(const string& flag_name,
    594                                              CodeGenerator* generator,
    595                                              const string& help_text) {
    596   GeneratorInfo info;
    597   info.flag_name = flag_name;
    598   info.generator = generator;
    599   info.help_text = help_text;
    600   generators_by_flag_name_[flag_name] = info;
    601 }
    602 
    603 void CommandLineInterface::RegisterGenerator(const string& flag_name,
    604                                              const string& option_flag_name,
    605                                              CodeGenerator* generator,
    606                                              const string& help_text) {
    607   GeneratorInfo info;
    608   info.flag_name = flag_name;
    609   info.option_flag_name = option_flag_name;
    610   info.generator = generator;
    611   info.help_text = help_text;
    612   generators_by_flag_name_[flag_name] = info;
    613   generators_by_option_name_[option_flag_name] = info;
    614 }
    615 
    616 void CommandLineInterface::AllowPlugins(const string& exe_name_prefix) {
    617   plugin_prefix_ = exe_name_prefix;
    618 }
    619 
    620 int CommandLineInterface::Run(int argc, const char* const argv[]) {
    621   Clear();
    622   switch (ParseArguments(argc, argv)) {
    623     case PARSE_ARGUMENT_DONE_AND_EXIT:
    624       return 0;
    625     case PARSE_ARGUMENT_FAIL:
    626       return 1;
    627     case PARSE_ARGUMENT_DONE_AND_CONTINUE:
    628       break;
    629   }
    630 
    631   // Set up the source tree.
    632   DiskSourceTree source_tree;
    633   for (int i = 0; i < proto_path_.size(); i++) {
    634     source_tree.MapPath(proto_path_[i].first, proto_path_[i].second);
    635   }
    636 
    637   // Map input files to virtual paths if necessary.
    638   if (!inputs_are_proto_path_relative_) {
    639     if (!MakeInputsBeProtoPathRelative(&source_tree)) {
    640       return 1;
    641     }
    642   }
    643 
    644   // Allocate the Importer.
    645   ErrorPrinter error_collector(error_format_, &source_tree);
    646   Importer importer(&source_tree, &error_collector);
    647 
    648   vector<const FileDescriptor*> parsed_files;
    649 
    650   // Parse each file.
    651   for (int i = 0; i < input_files_.size(); i++) {
    652     // Import the file.
    653     importer.AddUnusedImportTrackFile(input_files_[i]);
    654     const FileDescriptor* parsed_file = importer.Import(input_files_[i]);
    655     importer.ClearUnusedImportTrackFiles();
    656     if (parsed_file == NULL) return 1;
    657     parsed_files.push_back(parsed_file);
    658 
    659     // Enforce --disallow_services.
    660     if (disallow_services_ && parsed_file->service_count() > 0) {
    661       cerr << parsed_file->name() << ": This file contains services, but "
    662               "--disallow_services was used." << endl;
    663       return 1;
    664     }
    665   }
    666 
    667   // We construct a separate GeneratorContext for each output location.  Note
    668   // that two code generators may output to the same location, in which case
    669   // they should share a single GeneratorContext so that OpenForInsert() works.
    670   typedef hash_map<string, GeneratorContextImpl*> GeneratorContextMap;
    671   GeneratorContextMap output_directories;
    672 
    673   // Generate output.
    674   if (mode_ == MODE_COMPILE) {
    675     for (int i = 0; i < output_directives_.size(); i++) {
    676       string output_location = output_directives_[i].output_location;
    677       if (!HasSuffixString(output_location, ".zip") &&
    678           !HasSuffixString(output_location, ".jar")) {
    679         AddTrailingSlash(&output_location);
    680       }
    681       GeneratorContextImpl** map_slot = &output_directories[output_location];
    682 
    683       if (*map_slot == NULL) {
    684         // First time we've seen this output location.
    685         *map_slot = new GeneratorContextImpl(parsed_files);
    686       }
    687 
    688       if (!GenerateOutput(parsed_files, output_directives_[i], *map_slot)) {
    689         STLDeleteValues(&output_directories);
    690         return 1;
    691       }
    692     }
    693   }
    694 
    695   // Write all output to disk.
    696   for (GeneratorContextMap::iterator iter = output_directories.begin();
    697        iter != output_directories.end(); ++iter) {
    698     const string& location = iter->first;
    699     GeneratorContextImpl* directory = iter->second;
    700     if (HasSuffixString(location, "/")) {
    701       if (!directory->WriteAllToDisk(location)) {
    702         STLDeleteValues(&output_directories);
    703         return 1;
    704       }
    705     } else {
    706       if (HasSuffixString(location, ".jar")) {
    707         directory->AddJarManifest();
    708       }
    709 
    710       if (!directory->WriteAllToZip(location)) {
    711         STLDeleteValues(&output_directories);
    712         return 1;
    713       }
    714     }
    715   }
    716 
    717   STLDeleteValues(&output_directories);
    718 
    719   if (!descriptor_set_name_.empty()) {
    720     if (!WriteDescriptorSet(parsed_files)) {
    721       return 1;
    722     }
    723   }
    724 
    725   if (mode_ == MODE_ENCODE || mode_ == MODE_DECODE) {
    726     if (codec_type_.empty()) {
    727       // HACK:  Define an EmptyMessage type to use for decoding.
    728       DescriptorPool pool;
    729       FileDescriptorProto file;
    730       file.set_name("empty_message.proto");
    731       file.add_message_type()->set_name("EmptyMessage");
    732       GOOGLE_CHECK(pool.BuildFile(file) != NULL);
    733       codec_type_ = "EmptyMessage";
    734       if (!EncodeOrDecode(&pool)) {
    735         return 1;
    736       }
    737     } else {
    738       if (!EncodeOrDecode(importer.pool())) {
    739         return 1;
    740       }
    741     }
    742   }
    743 
    744   if (mode_ == MODE_PRINT) {
    745     switch (print_mode_) {
    746       case PRINT_FREE_FIELDS:
    747         for (int i = 0; i < parsed_files.size(); ++i) {
    748           const FileDescriptor* fd = parsed_files[i];
    749           for (int j = 0; j < fd->message_type_count(); ++j) {
    750             PrintFreeFieldNumbers(fd->message_type(j));
    751           }
    752         }
    753         break;
    754       case PRINT_NONE:
    755         GOOGLE_LOG(ERROR) << "If the code reaches here, it usually means a bug of "
    756                      "flag parsing in the CommonadLineInterface.";
    757         return 1;
    758 
    759       // Do not add a default case.
    760     }
    761   }
    762 
    763   return 0;
    764 }
    765 
    766 void CommandLineInterface::Clear() {
    767   // Clear all members that are set by Run().  Note that we must not clear
    768   // members which are set by other methods before Run() is called.
    769   executable_name_.clear();
    770   proto_path_.clear();
    771   input_files_.clear();
    772   output_directives_.clear();
    773   codec_type_.clear();
    774   descriptor_set_name_.clear();
    775 
    776   mode_ = MODE_COMPILE;
    777   print_mode_ = PRINT_NONE;
    778   imports_in_descriptor_set_ = false;
    779   source_info_in_descriptor_set_ = false;
    780   disallow_services_ = false;
    781 }
    782 
    783 bool CommandLineInterface::MakeInputsBeProtoPathRelative(
    784     DiskSourceTree* source_tree) {
    785   for (int i = 0; i < input_files_.size(); i++) {
    786     string virtual_file, shadowing_disk_file;
    787     switch (source_tree->DiskFileToVirtualFile(
    788         input_files_[i], &virtual_file, &shadowing_disk_file)) {
    789       case DiskSourceTree::SUCCESS:
    790         input_files_[i] = virtual_file;
    791         break;
    792       case DiskSourceTree::SHADOWED:
    793         cerr << input_files_[i] << ": Input is shadowed in the --proto_path "
    794                 "by \"" << shadowing_disk_file << "\".  Either use the latter "
    795                 "file as your input or reorder the --proto_path so that the "
    796                 "former file's location comes first." << endl;
    797         return false;
    798       case DiskSourceTree::CANNOT_OPEN:
    799         cerr << input_files_[i] << ": " << strerror(errno) << endl;
    800         return false;
    801       case DiskSourceTree::NO_MAPPING:
    802         // First check if the file exists at all.
    803         if (access(input_files_[i].c_str(), F_OK) < 0) {
    804           // File does not even exist.
    805           cerr << input_files_[i] << ": " << strerror(ENOENT) << endl;
    806         } else {
    807           cerr << input_files_[i] << ": File does not reside within any path "
    808                   "specified using --proto_path (or -I).  You must specify a "
    809                   "--proto_path which encompasses this file.  Note that the "
    810                   "proto_path must be an exact prefix of the .proto file "
    811                   "names -- protoc is too dumb to figure out when two paths "
    812                   "(e.g. absolute and relative) are equivalent (it's harder "
    813                   "than you think)." << endl;
    814         }
    815         return false;
    816     }
    817   }
    818 
    819   return true;
    820 }
    821 
    822 CommandLineInterface::ParseArgumentStatus
    823 CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
    824   executable_name_ = argv[0];
    825 
    826   // Iterate through all arguments and parse them.
    827   for (int i = 1; i < argc; i++) {
    828     string name, value;
    829 
    830     if (ParseArgument(argv[i], &name, &value)) {
    831       // Returned true => Use the next argument as the flag value.
    832       if (i + 1 == argc || argv[i+1][0] == '-') {
    833         cerr << "Missing value for flag: " << name << endl;
    834         if (name == "--decode") {
    835           cerr << "To decode an unknown message, use --decode_raw." << endl;
    836         }
    837         return PARSE_ARGUMENT_FAIL;
    838       } else {
    839         ++i;
    840         value = argv[i];
    841       }
    842     }
    843 
    844     ParseArgumentStatus status = InterpretArgument(name, value);
    845     if (status != PARSE_ARGUMENT_DONE_AND_CONTINUE)
    846       return status;
    847   }
    848 
    849   // If no --proto_path was given, use the current working directory.
    850   if (proto_path_.empty()) {
    851     // Don't use make_pair as the old/default standard library on Solaris
    852     // doesn't support it without explicit template parameters, which are
    853     // incompatible with C++0x's make_pair.
    854     proto_path_.push_back(pair<string, string>("", "."));
    855   }
    856 
    857   // Check some errror cases.
    858   bool decoding_raw = (mode_ == MODE_DECODE) && codec_type_.empty();
    859   if (decoding_raw && !input_files_.empty()) {
    860     cerr << "When using --decode_raw, no input files should be given." << endl;
    861     return PARSE_ARGUMENT_FAIL;
    862   } else if (!decoding_raw && input_files_.empty()) {
    863     cerr << "Missing input file." << endl;
    864     return PARSE_ARGUMENT_FAIL;
    865   }
    866   if (mode_ == MODE_COMPILE && output_directives_.empty() &&
    867       descriptor_set_name_.empty()) {
    868     cerr << "Missing output directives." << endl;
    869     return PARSE_ARGUMENT_FAIL;
    870   }
    871   if (imports_in_descriptor_set_ && descriptor_set_name_.empty()) {
    872     cerr << "--include_imports only makes sense when combined with "
    873             "--descriptor_set_out." << endl;
    874   }
    875   if (source_info_in_descriptor_set_ && descriptor_set_name_.empty()) {
    876     cerr << "--include_source_info only makes sense when combined with "
    877             "--descriptor_set_out." << endl;
    878   }
    879 
    880   return PARSE_ARGUMENT_DONE_AND_CONTINUE;
    881 }
    882 
    883 bool CommandLineInterface::ParseArgument(const char* arg,
    884                                          string* name, string* value) {
    885   bool parsed_value = false;
    886 
    887   if (arg[0] != '-') {
    888     // Not a flag.
    889     name->clear();
    890     parsed_value = true;
    891     *value = arg;
    892   } else if (arg[1] == '-') {
    893     // Two dashes:  Multi-character name, with '=' separating name and
    894     //   value.
    895     const char* equals_pos = strchr(arg, '=');
    896     if (equals_pos != NULL) {
    897       *name = string(arg, equals_pos - arg);
    898       *value = equals_pos + 1;
    899       parsed_value = true;
    900     } else {
    901       *name = arg;
    902     }
    903   } else {
    904     // One dash:  One-character name, all subsequent characters are the
    905     //   value.
    906     if (arg[1] == '\0') {
    907       // arg is just "-".  We treat this as an input file, except that at
    908       // present this will just lead to a "file not found" error.
    909       name->clear();
    910       *value = arg;
    911       parsed_value = true;
    912     } else {
    913       *name = string(arg, 2);
    914       *value = arg + 2;
    915       parsed_value = !value->empty();
    916     }
    917   }
    918 
    919   // Need to return true iff the next arg should be used as the value for this
    920   // one, false otherwise.
    921 
    922   if (parsed_value) {
    923     // We already parsed a value for this flag.
    924     return false;
    925   }
    926 
    927   if (*name == "-h" || *name == "--help" ||
    928       *name == "--disallow_services" ||
    929       *name == "--include_imports" ||
    930       *name == "--include_source_info" ||
    931       *name == "--version" ||
    932       *name == "--decode_raw" ||
    933       *name == "--print_free_field_numbers") {
    934     // HACK:  These are the only flags that don't take a value.
    935     //   They probably should not be hard-coded like this but for now it's
    936     //   not worth doing better.
    937     return false;
    938   }
    939 
    940   // Next argument is the flag value.
    941   return true;
    942 }
    943 
    944 CommandLineInterface::ParseArgumentStatus
    945 CommandLineInterface::InterpretArgument(const string& name,
    946                                         const string& value) {
    947   if (name.empty()) {
    948     // Not a flag.  Just a filename.
    949     if (value.empty()) {
    950       cerr << "You seem to have passed an empty string as one of the "
    951               "arguments to " << executable_name_ << ".  This is actually "
    952               "sort of hard to do.  Congrats.  Unfortunately it is not valid "
    953               "input so the program is going to die now." << endl;
    954       return PARSE_ARGUMENT_FAIL;
    955     }
    956 
    957     input_files_.push_back(value);
    958 
    959   } else if (name == "-I" || name == "--proto_path") {
    960     // Java's -classpath (and some other languages) delimits path components
    961     // with colons.  Let's accept that syntax too just to make things more
    962     // intuitive.
    963     vector<string> parts = Split(
    964         value, kPathSeparator, true);
    965 
    966     for (int i = 0; i < parts.size(); i++) {
    967       string virtual_path;
    968       string disk_path;
    969 
    970       string::size_type equals_pos = parts[i].find_first_of('=');
    971       if (equals_pos == string::npos) {
    972         virtual_path = "";
    973         disk_path = parts[i];
    974       } else {
    975         virtual_path = parts[i].substr(0, equals_pos);
    976         disk_path = parts[i].substr(equals_pos + 1);
    977       }
    978 
    979       if (disk_path.empty()) {
    980         cerr << "--proto_path passed empty directory name.  (Use \".\" for "
    981                 "current directory.)" << endl;
    982         return PARSE_ARGUMENT_FAIL;
    983       }
    984 
    985       // Make sure disk path exists, warn otherwise.
    986       if (access(disk_path.c_str(), F_OK) < 0) {
    987         cerr << disk_path << ": warning: directory does not exist." << endl;
    988       }
    989 
    990       // Don't use make_pair as the old/default standard library on Solaris
    991       // doesn't support it without explicit template parameters, which are
    992       // incompatible with C++0x's make_pair.
    993       proto_path_.push_back(pair<string, string>(virtual_path, disk_path));
    994     }
    995 
    996   } else if (name == "-o" || name == "--descriptor_set_out") {
    997     if (!descriptor_set_name_.empty()) {
    998       cerr << name << " may only be passed once." << endl;
    999       return PARSE_ARGUMENT_FAIL;
   1000     }
   1001     if (value.empty()) {
   1002       cerr << name << " requires a non-empty value." << endl;
   1003       return PARSE_ARGUMENT_FAIL;
   1004     }
   1005     if (mode_ != MODE_COMPILE) {
   1006       cerr << "Cannot use --encode or --decode and generate descriptors at the "
   1007               "same time." << endl;
   1008       return PARSE_ARGUMENT_FAIL;
   1009     }
   1010     descriptor_set_name_ = value;
   1011 
   1012   } else if (name == "--include_imports") {
   1013     if (imports_in_descriptor_set_) {
   1014       cerr << name << " may only be passed once." << endl;
   1015       return PARSE_ARGUMENT_FAIL;
   1016     }
   1017     imports_in_descriptor_set_ = true;
   1018 
   1019   } else if (name == "--include_source_info") {
   1020     if (source_info_in_descriptor_set_) {
   1021       cerr << name << " may only be passed once." << endl;
   1022       return PARSE_ARGUMENT_FAIL;
   1023     }
   1024     source_info_in_descriptor_set_ = true;
   1025 
   1026   } else if (name == "-h" || name == "--help") {
   1027     PrintHelpText();
   1028     return PARSE_ARGUMENT_DONE_AND_EXIT;  // Exit without running compiler.
   1029 
   1030   } else if (name == "--version") {
   1031     if (!version_info_.empty()) {
   1032       cout << version_info_ << endl;
   1033     }
   1034     cout << "libprotoc "
   1035          << protobuf::internal::VersionString(GOOGLE_PROTOBUF_VERSION)
   1036          << endl;
   1037     return PARSE_ARGUMENT_DONE_AND_EXIT;  // Exit without running compiler.
   1038 
   1039   } else if (name == "--disallow_services") {
   1040     disallow_services_ = true;
   1041 
   1042   } else if (name == "--encode" || name == "--decode" ||
   1043              name == "--decode_raw") {
   1044     if (mode_ != MODE_COMPILE) {
   1045       cerr << "Only one of --encode and --decode can be specified." << endl;
   1046       return PARSE_ARGUMENT_FAIL;
   1047     }
   1048     if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
   1049       cerr << "Cannot use " << name
   1050            << " and generate code or descriptors at the same time." << endl;
   1051       return PARSE_ARGUMENT_FAIL;
   1052     }
   1053 
   1054     mode_ = (name == "--encode") ? MODE_ENCODE : MODE_DECODE;
   1055 
   1056     if (value.empty() && name != "--decode_raw") {
   1057       cerr << "Type name for " << name << " cannot be blank." << endl;
   1058       if (name == "--decode") {
   1059         cerr << "To decode an unknown message, use --decode_raw." << endl;
   1060       }
   1061       return PARSE_ARGUMENT_FAIL;
   1062     } else if (!value.empty() && name == "--decode_raw") {
   1063       cerr << "--decode_raw does not take a parameter." << endl;
   1064       return PARSE_ARGUMENT_FAIL;
   1065     }
   1066 
   1067     codec_type_ = value;
   1068 
   1069   } else if (name == "--error_format") {
   1070     if (value == "gcc") {
   1071       error_format_ = ERROR_FORMAT_GCC;
   1072     } else if (value == "msvs") {
   1073       error_format_ = ERROR_FORMAT_MSVS;
   1074     } else {
   1075       cerr << "Unknown error format: " << value << endl;
   1076       return PARSE_ARGUMENT_FAIL;
   1077     }
   1078 
   1079   } else if (name == "--plugin") {
   1080     if (plugin_prefix_.empty()) {
   1081       cerr << "This compiler does not support plugins." << endl;
   1082       return PARSE_ARGUMENT_FAIL;
   1083     }
   1084 
   1085     string plugin_name;
   1086     string path;
   1087 
   1088     string::size_type equals_pos = value.find_first_of('=');
   1089     if (equals_pos == string::npos) {
   1090       // Use the basename of the file.
   1091       string::size_type slash_pos = value.find_last_of('/');
   1092       if (slash_pos == string::npos) {
   1093         plugin_name = value;
   1094       } else {
   1095         plugin_name = value.substr(slash_pos + 1);
   1096       }
   1097       path = value;
   1098     } else {
   1099       plugin_name = value.substr(0, equals_pos);
   1100       path = value.substr(equals_pos + 1);
   1101     }
   1102 
   1103     plugins_[plugin_name] = path;
   1104 
   1105   } else if (name == "--print_free_field_numbers") {
   1106     if (mode_ != MODE_COMPILE) {
   1107       cerr << "Cannot use " << name << " and use --encode, --decode or print "
   1108            << "other info at the same time." << endl;
   1109       return PARSE_ARGUMENT_FAIL;
   1110     }
   1111     if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
   1112       cerr << "Cannot use " << name
   1113            << " and generate code or descriptors at the same time." << endl;
   1114       return PARSE_ARGUMENT_FAIL;
   1115     }
   1116     mode_ = MODE_PRINT;
   1117     print_mode_ = PRINT_FREE_FIELDS;
   1118   } else {
   1119     // Some other flag.  Look it up in the generators list.
   1120     const GeneratorInfo* generator_info =
   1121         FindOrNull(generators_by_flag_name_, name);
   1122     if (generator_info == NULL &&
   1123         (plugin_prefix_.empty() || !HasSuffixString(name, "_out"))) {
   1124       // Check if it's a generator option flag.
   1125       generator_info = FindOrNull(generators_by_option_name_, name);
   1126       if (generator_info == NULL) {
   1127         cerr << "Unknown flag: " << name << endl;
   1128         return PARSE_ARGUMENT_FAIL;
   1129       } else {
   1130         string* parameters = &generator_parameters_[generator_info->flag_name];
   1131         if (!parameters->empty()) {
   1132           parameters->append(",");
   1133         }
   1134         parameters->append(value);
   1135       }
   1136     } else {
   1137       // It's an output flag.  Add it to the output directives.
   1138       if (mode_ != MODE_COMPILE) {
   1139         cerr << "Cannot use --encode, --decode or print .proto info and "
   1140                 "generate code at the same time." << endl;
   1141         return PARSE_ARGUMENT_FAIL;
   1142       }
   1143 
   1144       OutputDirective directive;
   1145       directive.name = name;
   1146       if (generator_info == NULL) {
   1147         directive.generator = NULL;
   1148       } else {
   1149         directive.generator = generator_info->generator;
   1150       }
   1151 
   1152       // Split value at ':' to separate the generator parameter from the
   1153       // filename.  However, avoid doing this if the colon is part of a valid
   1154       // Windows-style absolute path.
   1155       string::size_type colon_pos = value.find_first_of(':');
   1156       if (colon_pos == string::npos || IsWindowsAbsolutePath(value)) {
   1157         directive.output_location = value;
   1158       } else {
   1159         directive.parameter = value.substr(0, colon_pos);
   1160         directive.output_location = value.substr(colon_pos + 1);
   1161       }
   1162 
   1163       output_directives_.push_back(directive);
   1164     }
   1165   }
   1166 
   1167   return PARSE_ARGUMENT_DONE_AND_CONTINUE;
   1168 }
   1169 
   1170 void CommandLineInterface::PrintHelpText() {
   1171   // Sorry for indentation here; line wrapping would be uglier.
   1172   cerr <<
   1173 "Usage: " << executable_name_ << " [OPTION] PROTO_FILES\n"
   1174 "Parse PROTO_FILES and generate output based on the options given:\n"
   1175 "  -IPATH, --proto_path=PATH   Specify the directory in which to search for\n"
   1176 "                              imports.  May be specified multiple times;\n"
   1177 "                              directories will be searched in order.  If not\n"
   1178 "                              given, the current working directory is used.\n"
   1179 "  --version                   Show version info and exit.\n"
   1180 "  -h, --help                  Show this text and exit.\n"
   1181 "  --encode=MESSAGE_TYPE       Read a text-format message of the given type\n"
   1182 "                              from standard input and write it in binary\n"
   1183 "                              to standard output.  The message type must\n"
   1184 "                              be defined in PROTO_FILES or their imports.\n"
   1185 "  --decode=MESSAGE_TYPE       Read a binary message of the given type from\n"
   1186 "                              standard input and write it in text format\n"
   1187 "                              to standard output.  The message type must\n"
   1188 "                              be defined in PROTO_FILES or their imports.\n"
   1189 "  --decode_raw                Read an arbitrary protocol message from\n"
   1190 "                              standard input and write the raw tag/value\n"
   1191 "                              pairs in text format to standard output.  No\n"
   1192 "                              PROTO_FILES should be given when using this\n"
   1193 "                              flag.\n"
   1194 "  -oFILE,                     Writes a FileDescriptorSet (a protocol buffer,\n"
   1195 "    --descriptor_set_out=FILE defined in descriptor.proto) containing all of\n"
   1196 "                              the input files to FILE.\n"
   1197 "  --include_imports           When using --descriptor_set_out, also include\n"
   1198 "                              all dependencies of the input files in the\n"
   1199 "                              set, so that the set is self-contained.\n"
   1200 "  --include_source_info       When using --descriptor_set_out, do not strip\n"
   1201 "                              SourceCodeInfo from the FileDescriptorProto.\n"
   1202 "                              This results in vastly larger descriptors that\n"
   1203 "                              include information about the original\n"
   1204 "                              location of each decl in the source file as\n"
   1205 "                              well as surrounding comments.\n"
   1206 "  --error_format=FORMAT       Set the format in which to print errors.\n"
   1207 "                              FORMAT may be 'gcc' (the default) or 'msvs'\n"
   1208 "                              (Microsoft Visual Studio format).\n"
   1209 "  --print_free_field_numbers  Print the free field numbers of the messages\n"
   1210 "                              defined in the given proto files. Groups share\n"
   1211 "                              the same field number space with the parent \n"
   1212 "                              message. Extension ranges are counted as \n"
   1213 "                              occupied fields numbers."  << endl;
   1214   if (!plugin_prefix_.empty()) {
   1215     cerr <<
   1216 "  --plugin=EXECUTABLE         Specifies a plugin executable to use.\n"
   1217 "                              Normally, protoc searches the PATH for\n"
   1218 "                              plugins, but you may specify additional\n"
   1219 "                              executables not in the path using this flag.\n"
   1220 "                              Additionally, EXECUTABLE may be of the form\n"
   1221 "                              NAME=PATH, in which case the given plugin name\n"
   1222 "                              is mapped to the given executable even if\n"
   1223 "                              the executable's own name differs." << endl;
   1224   }
   1225 
   1226   for (GeneratorMap::iterator iter = generators_by_flag_name_.begin();
   1227        iter != generators_by_flag_name_.end(); ++iter) {
   1228     // FIXME(kenton):  If the text is long enough it will wrap, which is ugly,
   1229     //   but fixing this nicely (e.g. splitting on spaces) is probably more
   1230     //   trouble than it's worth.
   1231     cerr << "  " << iter->first << "=OUT_DIR "
   1232          << string(19 - iter->first.size(), ' ')  // Spaces for alignment.
   1233          << iter->second.help_text << endl;
   1234   }
   1235 }
   1236 
   1237 bool CommandLineInterface::GenerateOutput(
   1238     const vector<const FileDescriptor*>& parsed_files,
   1239     const OutputDirective& output_directive,
   1240     GeneratorContext* generator_context) {
   1241   // Call the generator.
   1242   string error;
   1243   if (output_directive.generator == NULL) {
   1244     // This is a plugin.
   1245     GOOGLE_CHECK(HasPrefixString(output_directive.name, "--") &&
   1246           HasSuffixString(output_directive.name, "_out"))
   1247         << "Bad name for plugin generator: " << output_directive.name;
   1248 
   1249     // Strip the "--" and "_out" and add the plugin prefix.
   1250     string plugin_name = plugin_prefix_ + "gen-" +
   1251         output_directive.name.substr(2, output_directive.name.size() - 6);
   1252 
   1253     if (!GeneratePluginOutput(parsed_files, plugin_name,
   1254                               output_directive.parameter,
   1255                               generator_context, &error)) {
   1256       cerr << output_directive.name << ": " << error << endl;
   1257       return false;
   1258     }
   1259   } else {
   1260     // Regular generator.
   1261     string parameters = output_directive.parameter;
   1262     if (!generator_parameters_[output_directive.name].empty()) {
   1263       if (!parameters.empty()) {
   1264         parameters.append(",");
   1265       }
   1266       parameters.append(generator_parameters_[output_directive.name]);
   1267     }
   1268     for (int i = 0; i < parsed_files.size(); i++) {
   1269       if (!output_directive.generator->Generate(parsed_files[i], parameters,
   1270                                                 generator_context, &error)) {
   1271         // Generator returned an error.
   1272         cerr << output_directive.name << ": " << parsed_files[i]->name() << ": "
   1273              << error << endl;
   1274         return false;
   1275       }
   1276     }
   1277   }
   1278 
   1279   return true;
   1280 }
   1281 
   1282 bool CommandLineInterface::GeneratePluginOutput(
   1283     const vector<const FileDescriptor*>& parsed_files,
   1284     const string& plugin_name,
   1285     const string& parameter,
   1286     GeneratorContext* generator_context,
   1287     string* error) {
   1288   CodeGeneratorRequest request;
   1289   CodeGeneratorResponse response;
   1290 
   1291   // Build the request.
   1292   if (!parameter.empty()) {
   1293     request.set_parameter(parameter);
   1294   }
   1295 
   1296   set<const FileDescriptor*> already_seen;
   1297   for (int i = 0; i < parsed_files.size(); i++) {
   1298     request.add_file_to_generate(parsed_files[i]->name());
   1299     GetTransitiveDependencies(parsed_files[i],
   1300                               true,  // Include source code info.
   1301                               &already_seen, request.mutable_proto_file());
   1302   }
   1303 
   1304   // Invoke the plugin.
   1305   Subprocess subprocess;
   1306 
   1307   if (plugins_.count(plugin_name) > 0) {
   1308     subprocess.Start(plugins_[plugin_name], Subprocess::EXACT_NAME);
   1309   } else {
   1310     subprocess.Start(plugin_name, Subprocess::SEARCH_PATH);
   1311   }
   1312 
   1313   string communicate_error;
   1314   if (!subprocess.Communicate(request, &response, &communicate_error)) {
   1315     *error = strings::Substitute("$0: $1", plugin_name, communicate_error);
   1316     return false;
   1317   }
   1318 
   1319   // Write the files.  We do this even if there was a generator error in order
   1320   // to match the behavior of a compiled-in generator.
   1321   scoped_ptr<io::ZeroCopyOutputStream> current_output;
   1322   for (int i = 0; i < response.file_size(); i++) {
   1323     const CodeGeneratorResponse::File& output_file = response.file(i);
   1324 
   1325     if (!output_file.insertion_point().empty()) {
   1326       // Open a file for insert.
   1327       // We reset current_output to NULL first so that the old file is closed
   1328       // before the new one is opened.
   1329       current_output.reset();
   1330       current_output.reset(generator_context->OpenForInsert(
   1331           output_file.name(), output_file.insertion_point()));
   1332     } else if (!output_file.name().empty()) {
   1333       // Starting a new file.  Open it.
   1334       // We reset current_output to NULL first so that the old file is closed
   1335       // before the new one is opened.
   1336       current_output.reset();
   1337       current_output.reset(generator_context->Open(output_file.name()));
   1338     } else if (current_output == NULL) {
   1339       *error = strings::Substitute(
   1340         "$0: First file chunk returned by plugin did not specify a file name.",
   1341         plugin_name);
   1342       return false;
   1343     }
   1344 
   1345     // Use CodedOutputStream for convenience; otherwise we'd need to provide
   1346     // our own buffer-copying loop.
   1347     io::CodedOutputStream writer(current_output.get());
   1348     writer.WriteString(output_file.content());
   1349   }
   1350 
   1351   // Check for errors.
   1352   if (!response.error().empty()) {
   1353     // Generator returned an error.
   1354     *error = response.error();
   1355     return false;
   1356   }
   1357 
   1358   return true;
   1359 }
   1360 
   1361 bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) {
   1362   // Look up the type.
   1363   const Descriptor* type = pool->FindMessageTypeByName(codec_type_);
   1364   if (type == NULL) {
   1365     cerr << "Type not defined: " << codec_type_ << endl;
   1366     return false;
   1367   }
   1368 
   1369   DynamicMessageFactory dynamic_factory(pool);
   1370   scoped_ptr<Message> message(dynamic_factory.GetPrototype(type)->New());
   1371 
   1372   if (mode_ == MODE_ENCODE) {
   1373     SetFdToTextMode(STDIN_FILENO);
   1374     SetFdToBinaryMode(STDOUT_FILENO);
   1375   } else {
   1376     SetFdToBinaryMode(STDIN_FILENO);
   1377     SetFdToTextMode(STDOUT_FILENO);
   1378   }
   1379 
   1380   io::FileInputStream in(STDIN_FILENO);
   1381   io::FileOutputStream out(STDOUT_FILENO);
   1382 
   1383   if (mode_ == MODE_ENCODE) {
   1384     // Input is text.
   1385     ErrorPrinter error_collector(error_format_);
   1386     TextFormat::Parser parser;
   1387     parser.RecordErrorsTo(&error_collector);
   1388     parser.AllowPartialMessage(true);
   1389 
   1390     if (!parser.Parse(&in, message.get())) {
   1391       cerr << "Failed to parse input." << endl;
   1392       return false;
   1393     }
   1394   } else {
   1395     // Input is binary.
   1396     if (!message->ParsePartialFromZeroCopyStream(&in)) {
   1397       cerr << "Failed to parse input." << endl;
   1398       return false;
   1399     }
   1400   }
   1401 
   1402   if (!message->IsInitialized()) {
   1403     cerr << "warning:  Input message is missing required fields:  "
   1404          << message->InitializationErrorString() << endl;
   1405   }
   1406 
   1407   if (mode_ == MODE_ENCODE) {
   1408     // Output is binary.
   1409     if (!message->SerializePartialToZeroCopyStream(&out)) {
   1410       cerr << "output: I/O error." << endl;
   1411       return false;
   1412     }
   1413   } else {
   1414     // Output is text.
   1415     if (!TextFormat::Print(*message, &out)) {
   1416       cerr << "output: I/O error." << endl;
   1417       return false;
   1418     }
   1419   }
   1420 
   1421   return true;
   1422 }
   1423 
   1424 bool CommandLineInterface::WriteDescriptorSet(
   1425     const vector<const FileDescriptor*> parsed_files) {
   1426   FileDescriptorSet file_set;
   1427 
   1428   if (imports_in_descriptor_set_) {
   1429     set<const FileDescriptor*> already_seen;
   1430     for (int i = 0; i < parsed_files.size(); i++) {
   1431       GetTransitiveDependencies(parsed_files[i],
   1432                                 source_info_in_descriptor_set_,
   1433                                 &already_seen, file_set.mutable_file());
   1434     }
   1435   } else {
   1436     for (int i = 0; i < parsed_files.size(); i++) {
   1437       FileDescriptorProto* file_proto = file_set.add_file();
   1438       parsed_files[i]->CopyTo(file_proto);
   1439       if (source_info_in_descriptor_set_) {
   1440         parsed_files[i]->CopySourceCodeInfoTo(file_proto);
   1441       }
   1442     }
   1443   }
   1444 
   1445   int fd;
   1446   do {
   1447     fd = open(descriptor_set_name_.c_str(),
   1448               O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
   1449   } while (fd < 0 && errno == EINTR);
   1450 
   1451   if (fd < 0) {
   1452     perror(descriptor_set_name_.c_str());
   1453     return false;
   1454   }
   1455 
   1456   io::FileOutputStream out(fd);
   1457   if (!file_set.SerializeToZeroCopyStream(&out)) {
   1458     cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno()) << endl;
   1459     out.Close();
   1460     return false;
   1461   }
   1462   if (!out.Close()) {
   1463     cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno()) << endl;
   1464     return false;
   1465   }
   1466 
   1467   return true;
   1468 }
   1469 
   1470 void CommandLineInterface::GetTransitiveDependencies(
   1471     const FileDescriptor* file, bool include_source_code_info,
   1472     set<const FileDescriptor*>* already_seen,
   1473     RepeatedPtrField<FileDescriptorProto>* output) {
   1474   if (!already_seen->insert(file).second) {
   1475     // Already saw this file.  Skip.
   1476     return;
   1477   }
   1478 
   1479   // Add all dependencies.
   1480   for (int i = 0; i < file->dependency_count(); i++) {
   1481     GetTransitiveDependencies(file->dependency(i), include_source_code_info,
   1482                               already_seen, output);
   1483   }
   1484 
   1485   // Add this file.
   1486   FileDescriptorProto* new_descriptor = output->Add();
   1487   file->CopyTo(new_descriptor);
   1488   if (include_source_code_info) {
   1489     file->CopySourceCodeInfoTo(new_descriptor);
   1490   }
   1491 }
   1492 
   1493 namespace {
   1494 
   1495 // Utility function for PrintFreeFieldNumbers.
   1496 // Stores occupied ranges into the ranges parameter, and next level of sub
   1497 // message types into the nested_messages parameter.  The FieldRange is left
   1498 // inclusive, right exclusive. i.e. [a, b).
   1499 //
   1500 // Nested Messages:
   1501 // Note that it only stores the nested message type, iff the nested type is
   1502 // either a direct child of the given descriptor, or the nested type is a
   1503 // decendent of the given descriptor and all the nodes between the
   1504 // nested type and the given descriptor are group types. e.g.
   1505 //
   1506 // message Foo {
   1507 //   message Bar {
   1508 //     message NestedBar {}
   1509 //   }
   1510 //   group Baz = 1 {
   1511 //     group NestedBazGroup = 2 {
   1512 //       message Quz {
   1513 //         message NestedQuz {}
   1514 //       }
   1515 //     }
   1516 //     message NestedBaz {}
   1517 //   }
   1518 // }
   1519 //
   1520 // In this case, Bar, Quz and NestedBaz will be added into the nested types.
   1521 // Since free field numbers of group types will not be printed, this makes sure
   1522 // the nested message types in groups will not be dropped. The nested_messages
   1523 // parameter will contain the direct children (when groups are ignored in the
   1524 // tree) of the given descriptor for the caller to traverse. The declaration
   1525 // order of the nested messages is also preserved.
   1526 typedef pair<int, int> FieldRange;
   1527 void GatherOccupiedFieldRanges(const Descriptor* descriptor,
   1528                                set<FieldRange>* ranges,
   1529                                vector<const Descriptor*>* nested_messages) {
   1530   set<const Descriptor*> groups;
   1531   for (int i = 0; i < descriptor->field_count(); ++i) {
   1532     const FieldDescriptor* fd = descriptor->field(i);
   1533     ranges->insert(FieldRange(fd->number(), fd->number() + 1));
   1534     if (fd->type() == FieldDescriptor::TYPE_GROUP) {
   1535       groups.insert(fd->message_type());
   1536     }
   1537   }
   1538   for (int i = 0; i < descriptor->extension_range_count(); ++i) {
   1539     ranges->insert(FieldRange(descriptor->extension_range(i)->start,
   1540                               descriptor->extension_range(i)->end));
   1541   }
   1542   // Handle the nested messages/groups in declaration order to make it
   1543   // post-order strict.
   1544   for (int i = 0; i < descriptor->nested_type_count(); ++i) {
   1545     const Descriptor* nested_desc = descriptor->nested_type(i);
   1546     if (groups.find(nested_desc) != groups.end()) {
   1547       GatherOccupiedFieldRanges(nested_desc, ranges, nested_messages);
   1548     } else {
   1549       nested_messages->push_back(nested_desc);
   1550     }
   1551   }
   1552 }
   1553 
   1554 // Utility function for PrintFreeFieldNumbers.
   1555 // Actually prints the formatted free field numbers for given message name and
   1556 // occupied ranges.
   1557 void FormatFreeFieldNumbers(const string& name,
   1558                             const set<FieldRange>& ranges) {
   1559   string output;
   1560   StringAppendF(&output, "%-35s free:", name.c_str());
   1561   int next_free_number = 1;
   1562   for (set<FieldRange>::const_iterator i = ranges.begin();
   1563        i != ranges.end(); ++i) {
   1564     // This happens when groups re-use parent field numbers, in which
   1565     // case we skip the FieldRange entirely.
   1566     if (next_free_number >= i->second) continue;
   1567 
   1568     if (next_free_number < i->first) {
   1569       if (next_free_number + 1 == i->first) {
   1570         // Singleton
   1571         StringAppendF(&output, " %d", next_free_number);
   1572       } else {
   1573         // Range
   1574         StringAppendF(&output, " %d-%d", next_free_number, i->first - 1);
   1575       }
   1576     }
   1577     next_free_number = i->second;
   1578   }
   1579   if (next_free_number <= FieldDescriptor::kMaxNumber) {
   1580     StringAppendF(&output, " %d-INF", next_free_number);
   1581   }
   1582   cout << output << endl;
   1583 }
   1584 
   1585 }  // namespace
   1586 
   1587 void CommandLineInterface::PrintFreeFieldNumbers(
   1588     const Descriptor* descriptor) {
   1589   set<FieldRange> ranges;
   1590   vector<const Descriptor*> nested_messages;
   1591   GatherOccupiedFieldRanges(descriptor, &ranges, &nested_messages);
   1592 
   1593   for (int i = 0; i < nested_messages.size(); ++i) {
   1594     PrintFreeFieldNumbers(nested_messages[i]);
   1595   }
   1596   FormatFreeFieldNumbers(descriptor->full_name(), ranges);
   1597 }
   1598 
   1599 
   1600 
   1601 }  // namespace compiler
   1602 }  // namespace protobuf
   1603 }  // namespace google
   1604