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;
905