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