Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: third_party/protobuf/src/google/protobuf/compiler/command_line_interface.cc

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

Powered by Google App Engine
This is Rietveld 408576698