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