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

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

Issue 2495533002: third_party/protobuf: Update to HEAD (83d681ee2c) (Closed)
Patch Set: Make chrome settings proto generated file a component Created 4 years 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 // https://developers.google.com/protocol-buffers/ 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.
(...skipping 26 matching lines...) Expand all
37 #include <errno.h> 37 #include <errno.h>
38 #include <fcntl.h> 38 #include <fcntl.h>
39 #include <fstream> 39 #include <fstream>
40 #include <iostream> 40 #include <iostream>
41 #include <sstream> 41 #include <sstream>
42 #include <stdlib.h> 42 #include <stdlib.h>
43 #include <vector> 43 #include <vector>
44 44
45 #include <google/protobuf/stubs/hash.h> 45 #include <google/protobuf/stubs/hash.h>
46 #include <google/protobuf/compiler/objectivec/objectivec_helpers.h> 46 #include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
47 #include <google/protobuf/descriptor.pb.h>
47 #include <google/protobuf/io/coded_stream.h> 48 #include <google/protobuf/io/coded_stream.h>
49 #include <google/protobuf/io/printer.h>
48 #include <google/protobuf/io/zero_copy_stream_impl.h> 50 #include <google/protobuf/io/zero_copy_stream_impl.h>
49 #include <google/protobuf/descriptor.pb.h>
50 #include <google/protobuf/stubs/common.h> 51 #include <google/protobuf/stubs/common.h>
51 #include <google/protobuf/stubs/strutil.h> 52 #include <google/protobuf/stubs/strutil.h>
52 53
53 // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some 54 // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
54 // error cases, so it seems to be ok to use as a back door for errors. 55 // error cases, so it seems to be ok to use as a back door for errors.
55 56
56 namespace google { 57 namespace google {
57 namespace protobuf { 58 namespace protobuf {
58 namespace compiler { 59 namespace compiler {
59 namespace objectivec { 60 namespace objectivec {
(...skipping 14 matching lines...) Expand all
74 result.insert(words[i]); 75 result.insert(words[i]);
75 } 76 }
76 return result; 77 return result;
77 } 78 }
78 79
79 const char* const kUpperSegmentsList[] = {"url", "http", "https"}; 80 const char* const kUpperSegmentsList[] = {"url", "http", "https"};
80 81
81 hash_set<string> kUpperSegments = 82 hash_set<string> kUpperSegments =
82 MakeWordsMap(kUpperSegmentsList, GOOGLE_ARRAYSIZE(kUpperSegmentsList)); 83 MakeWordsMap(kUpperSegmentsList, GOOGLE_ARRAYSIZE(kUpperSegmentsList));
83 84
85 bool ascii_isnewline(char c) {
86 return c == '\n' || c == '\r';
87 }
88
84 // Internal helper for name handing. 89 // Internal helper for name handing.
85 // Do not expose this outside of helpers, stick to having functions for specific 90 // Do not expose this outside of helpers, stick to having functions for specific
86 // cases (ClassName(), FieldName()), so there is always consistent suffix rules. 91 // cases (ClassName(), FieldName()), so there is always consistent suffix rules.
87 string UnderscoresToCamelCase(const string& input, bool first_capitalized) { 92 string UnderscoresToCamelCase(const string& input, bool first_capitalized) {
88 vector<string> values; 93 vector<string> values;
89 string current; 94 string current;
90 95
91 bool last_char_was_number = false; 96 bool last_char_was_number = false;
92 bool last_char_was_lower = false; 97 bool last_char_was_lower = false;
93 bool last_char_was_upper = false; 98 bool last_char_was_upper = false;
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
198 "Fixed", "Fract", "Size", "LogicalAddress", "PhysicalAddress", "ByteCount", 203 "Fixed", "Fract", "Size", "LogicalAddress", "PhysicalAddress", "ByteCount",
199 "ByteOffset", "Duration", "AbsoluteTime", "OptionBits", "ItemCount", 204 "ByteOffset", "Duration", "AbsoluteTime", "OptionBits", "ItemCount",
200 "PBVersion", "ScriptCode", "LangCode", "RegionCode", "OSType", 205 "PBVersion", "ScriptCode", "LangCode", "RegionCode", "OSType",
201 "ProcessSerialNumber", "Point", "Rect", "FixedPoint", "FixedRect", "Style", 206 "ProcessSerialNumber", "Point", "Rect", "FixedPoint", "FixedRect", "Style",
202 "StyleParameter", "StyleField", "TimeScale", "TimeBase", "TimeRecord", 207 "StyleParameter", "StyleField", "TimeScale", "TimeBase", "TimeRecord",
203 }; 208 };
204 209
205 hash_set<string> kReservedWords = 210 hash_set<string> kReservedWords =
206 MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList)); 211 MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList));
207 212
208 string SanitizeNameForObjC(const string& input, const string& extension) { 213 string SanitizeNameForObjC(const string& input,
214 const string& extension,
215 string* out_suffix_added) {
209 if (kReservedWords.count(input) > 0) { 216 if (kReservedWords.count(input) > 0) {
217 if (out_suffix_added) *out_suffix_added = extension;
210 return input + extension; 218 return input + extension;
211 } 219 }
220 if (out_suffix_added) out_suffix_added->clear();
212 return input; 221 return input;
213 } 222 }
214 223
215 string NameFromFieldDescriptor(const FieldDescriptor* field) { 224 string NameFromFieldDescriptor(const FieldDescriptor* field) {
216 if (field->type() == FieldDescriptor::TYPE_GROUP) { 225 if (field->type() == FieldDescriptor::TYPE_GROUP) {
217 return field->message_type()->name(); 226 return field->message_type()->name();
218 } else { 227 } else {
219 return field->name(); 228 return field->name();
220 } 229 }
221 } 230 }
(...skipping 28 matching lines...) Expand all
250 // new_ton). 259 // new_ton).
251 return !ascii_islower(name[length]); 260 return !ascii_islower(name[length]);
252 } else { 261 } else {
253 return true; 262 return true;
254 } 263 }
255 } 264 }
256 } 265 }
257 return false; 266 return false;
258 } 267 }
259 268
269 string GetZeroEnumNameForFlagType(const FlagType flag_type) {
270 switch(flag_type) {
271 case FLAGTYPE_DESCRIPTOR_INITIALIZATION:
272 return "GPBDescriptorInitializationFlag_None";
273 case FLAGTYPE_EXTENSION:
274 return "GPBExtensionNone";
275 case FLAGTYPE_FIELD:
276 return "GPBFieldNone";
277 default:
278 GOOGLE_LOG(FATAL) << "Can't get here.";
279 return "0";
280 }
281 }
282
283 string GetEnumNameForFlagType(const FlagType flag_type) {
284 switch(flag_type) {
285 case FLAGTYPE_DESCRIPTOR_INITIALIZATION:
286 return "GPBDescriptorInitializationFlags";
287 case FLAGTYPE_EXTENSION:
288 return "GPBExtensionOptions";
289 case FLAGTYPE_FIELD:
290 return "GPBFieldFlags";
291 default:
292 GOOGLE_LOG(FATAL) << "Can't get here.";
293 return string();
294 }
295 }
296
260 } // namespace 297 } // namespace
261 298
262 // Escape C++ trigraphs by escaping question marks to \? 299 // Escape C++ trigraphs by escaping question marks to \?
263 string EscapeTrigraphs(const string& to_escape) { 300 string EscapeTrigraphs(const string& to_escape) {
264 return StringReplace(to_escape, "?", "\\?", true); 301 return StringReplace(to_escape, "?", "\\?", true);
265 } 302 }
266 303
267 string StripProto(const string& filename) { 304 string StripProto(const string& filename) {
268 if (HasSuffixString(filename, ".protodevel")) { 305 if (HasSuffixString(filename, ".protodevel")) {
269 return StripSuffixString(filename, ".protodevel"); 306 return StripSuffixString(filename, ".protodevel");
270 } else { 307 } else {
271 return StripSuffixString(filename, ".proto"); 308 return StripSuffixString(filename, ".proto");
272 } 309 }
273 } 310 }
274 311
312 void StringPieceTrimWhitespace(StringPiece* input) {
313 while (!input->empty() && ascii_isspace(*input->data())) {
314 input->remove_prefix(1);
315 }
316 while (!input->empty() && ascii_isspace((*input)[input->length() - 1])) {
317 input->remove_suffix(1);
318 }
319 }
320
321
275 bool IsRetainedName(const string& name) { 322 bool IsRetainedName(const string& name) {
276 // List of prefixes from 323 // List of prefixes from
277 // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Memo ryMgmt/Articles/mmRules.html 324 // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Memo ryMgmt/Articles/mmRules.html
278 static const string retained_names[] = {"new", "alloc", "copy", 325 static const string retained_names[] = {"new", "alloc", "copy",
279 "mutableCopy"}; 326 "mutableCopy"};
280 return IsSpecialName(name, retained_names, 327 return IsSpecialName(name, retained_names,
281 sizeof(retained_names) / sizeof(retained_names[0])); 328 sizeof(retained_names) / sizeof(retained_names[0]));
282 } 329 }
283 330
284 bool IsInitName(const string& name) { 331 bool IsInitName(const string& name) {
285 static const string init_names[] = {"init"}; 332 static const string init_names[] = {"init"};
286 return IsSpecialName(name, init_names, 333 return IsSpecialName(name, init_names,
287 sizeof(init_names) / sizeof(init_names[0])); 334 sizeof(init_names) / sizeof(init_names[0]));
288 } 335 }
289 336
290 string BaseFileName(const FileDescriptor* file) { 337 string BaseFileName(const FileDescriptor* file) {
291 string basename; 338 string basename;
292 PathSplit(file->name(), NULL, &basename); 339 PathSplit(file->name(), NULL, &basename);
293 return basename; 340 return basename;
294 } 341 }
295 342
296 string FileName(const FileDescriptor* file) { 343 string FileClassPrefix(const FileDescriptor* file) {
297 string path = FilePath(file); 344 // Default is empty string, no need to check has_objc_class_prefix.
298 string basename; 345 string result = file->options().objc_class_prefix();
299 PathSplit(path, NULL, &basename); 346 return result;
300 return basename;
301 } 347 }
302 348
303 string FilePath(const FileDescriptor* file) { 349 string FilePath(const FileDescriptor* file) {
304 string output; 350 string output;
305 string basename; 351 string basename;
306 string directory; 352 string directory;
307 PathSplit(file->name(), &directory, &basename); 353 PathSplit(file->name(), &directory, &basename);
308 if (directory.length() > 0) { 354 if (directory.length() > 0) {
309 output = directory + "/"; 355 output = directory + "/";
310 } 356 }
311 basename = StripProto(basename); 357 basename = StripProto(basename);
312 358
313 // CamelCase to be more ObjC friendly. 359 // CamelCase to be more ObjC friendly.
314 basename = UnderscoresToCamelCase(basename, true); 360 basename = UnderscoresToCamelCase(basename, true);
315 361
316 output += basename; 362 output += basename;
317 return output; 363 return output;
318 } 364 }
319 365
320 string FileClassPrefix(const FileDescriptor* file) { 366 string FilePathBasename(const FileDescriptor* file) {
321 // Default is empty string, no need to check has_objc_class_prefix. 367 string output;
322 string result = file->options().objc_class_prefix(); 368 string basename;
323 return result; 369 string directory;
370 PathSplit(file->name(), &directory, &basename);
371 basename = StripProto(basename);
372
373 // CamelCase to be more ObjC friendly.
374 output = UnderscoresToCamelCase(basename, true);
375
376 return output;
324 } 377 }
325 378
326 string FileClassName(const FileDescriptor* file) { 379 string FileClassName(const FileDescriptor* file) {
327 string name = FileClassPrefix(file); 380 string name = FileClassPrefix(file);
328 name += UnderscoresToCamelCase(StripProto(BaseFileName(file)), true); 381 name += UnderscoresToCamelCase(StripProto(BaseFileName(file)), true);
329 name += "Root"; 382 name += "Root";
330 // There aren't really any reserved words that end in "Root", but playing 383 // There aren't really any reserved words that end in "Root", but playing
331 // it safe and checking. 384 // it safe and checking.
332 return SanitizeNameForObjC(name, "_RootClass"); 385 return SanitizeNameForObjC(name, "_RootClass", NULL);
333 } 386 }
334 387
335 string ClassNameWorker(const Descriptor* descriptor) { 388 string ClassNameWorker(const Descriptor* descriptor) {
336 string name; 389 string name;
337 if (descriptor->containing_type() != NULL) { 390 if (descriptor->containing_type() != NULL) {
338 name = ClassNameWorker(descriptor->containing_type()); 391 name = ClassNameWorker(descriptor->containing_type());
339 name += "_"; 392 name += "_";
340 } 393 }
341 return name + descriptor->name(); 394 return name + descriptor->name();
342 } 395 }
343 396
344 string ClassNameWorker(const EnumDescriptor* descriptor) { 397 string ClassNameWorker(const EnumDescriptor* descriptor) {
345 string name; 398 string name;
346 if (descriptor->containing_type() != NULL) { 399 if (descriptor->containing_type() != NULL) {
347 name = ClassNameWorker(descriptor->containing_type()); 400 name = ClassNameWorker(descriptor->containing_type());
348 name += "_"; 401 name += "_";
349 } 402 }
350 return name + descriptor->name(); 403 return name + descriptor->name();
351 } 404 }
352 405
353 string ClassName(const Descriptor* descriptor) { 406 string ClassName(const Descriptor* descriptor) {
407 return ClassName(descriptor, NULL);
408 }
409
410 string ClassName(const Descriptor* descriptor, string* out_suffix_added) {
354 // 1. Message names are used as is (style calls for CamelCase, trust it). 411 // 1. Message names are used as is (style calls for CamelCase, trust it).
355 // 2. Check for reserved word at the very end and then suffix things. 412 // 2. Check for reserved word at the very end and then suffix things.
356 string prefix = FileClassPrefix(descriptor->file()); 413 string prefix = FileClassPrefix(descriptor->file());
357 string name = ClassNameWorker(descriptor); 414 string name = ClassNameWorker(descriptor);
358 return SanitizeNameForObjC(prefix + name, "_Class"); 415 return SanitizeNameForObjC(prefix + name, "_Class", out_suffix_added);
359 } 416 }
360 417
361 string EnumName(const EnumDescriptor* descriptor) { 418 string EnumName(const EnumDescriptor* descriptor) {
362 // 1. Enum names are used as is (style calls for CamelCase, trust it). 419 // 1. Enum names are used as is (style calls for CamelCase, trust it).
363 // 2. Check for reserved word at the every end and then suffix things. 420 // 2. Check for reserved word at the every end and then suffix things.
364 // message Fixed { 421 // message Fixed {
365 // message Size {...} 422 // message Size {...}
366 // enum Mumble {...} 423 // enum Mumble {...}
367 // ... 424 // ...
368 // } 425 // }
369 // yields Fixed_Class, Fixed_Size. 426 // yields Fixed_Class, Fixed_Size.
370 string name = FileClassPrefix(descriptor->file()); 427 string name = FileClassPrefix(descriptor->file());
371 name += ClassNameWorker(descriptor); 428 name += ClassNameWorker(descriptor);
372 return SanitizeNameForObjC(name, "_Enum"); 429 return SanitizeNameForObjC(name, "_Enum", NULL);
373 } 430 }
374 431
375 string EnumValueName(const EnumValueDescriptor* descriptor) { 432 string EnumValueName(const EnumValueDescriptor* descriptor) {
376 // Because of the Switch enum compatibility, the name on the enum has to have 433 // Because of the Switch enum compatibility, the name on the enum has to have
377 // the suffix handing, so it slightly diverges from how nested classes work. 434 // the suffix handing, so it slightly diverges from how nested classes work.
378 // enum Fixed { 435 // enum Fixed {
379 // FOO = 1 436 // FOO = 1
380 // } 437 // }
381 // yields Fixed_Enum and Fixed_Enum_Foo (not Fixed_Foo). 438 // yields Fixed_Enum and Fixed_Enum_Foo (not Fixed_Foo).
382 const string& class_name = EnumName(descriptor->type()); 439 const string& class_name = EnumName(descriptor->type());
383 const string& value_str = UnderscoresToCamelCase(descriptor->name(), true); 440 const string& value_str = UnderscoresToCamelCase(descriptor->name(), true);
384 const string& name = class_name + "_" + value_str; 441 const string& name = class_name + "_" + value_str;
385 // There aren't really any reserved words with an underscore and a leading 442 // There aren't really any reserved words with an underscore and a leading
386 // capital letter, but playing it safe and checking. 443 // capital letter, but playing it safe and checking.
387 return SanitizeNameForObjC(name, "_Value"); 444 return SanitizeNameForObjC(name, "_Value", NULL);
388 } 445 }
389 446
390 string EnumValueShortName(const EnumValueDescriptor* descriptor) { 447 string EnumValueShortName(const EnumValueDescriptor* descriptor) {
391 // Enum value names (EnumValueName above) are the enum name turned into 448 // Enum value names (EnumValueName above) are the enum name turned into
392 // a class name and then the value name is CamelCased and concatenated; the 449 // a class name and then the value name is CamelCased and concatenated; the
393 // whole thing then gets sanitized for reserved words. 450 // whole thing then gets sanitized for reserved words.
394 // The "short name" is intended to be the final leaf, the value name; but 451 // The "short name" is intended to be the final leaf, the value name; but
395 // you can't simply send that off to sanitize as that could result in it 452 // you can't simply send that off to sanitize as that could result in it
396 // getting modified when the full name didn't. For example enum 453 // getting modified when the full name didn't. For example enum
397 // "StorageModes" has a value "retain". So the full name is 454 // "StorageModes" has a value "retain". So the full name is
(...skipping 16 matching lines...) Expand all
414 result += '_'; 471 result += '_';
415 } 472 }
416 result += ascii_toupper(c); 473 result += ascii_toupper(c);
417 } 474 }
418 return result; 475 return result;
419 } 476 }
420 477
421 string ExtensionMethodName(const FieldDescriptor* descriptor) { 478 string ExtensionMethodName(const FieldDescriptor* descriptor) {
422 const string& name = NameFromFieldDescriptor(descriptor); 479 const string& name = NameFromFieldDescriptor(descriptor);
423 const string& result = UnderscoresToCamelCase(name, false); 480 const string& result = UnderscoresToCamelCase(name, false);
424 return SanitizeNameForObjC(result, "_Extension"); 481 return SanitizeNameForObjC(result, "_Extension", NULL);
425 } 482 }
426 483
427 string FieldName(const FieldDescriptor* field) { 484 string FieldName(const FieldDescriptor* field) {
428 const string& name = NameFromFieldDescriptor(field); 485 const string& name = NameFromFieldDescriptor(field);
429 string result = UnderscoresToCamelCase(name, false); 486 string result = UnderscoresToCamelCase(name, false);
430 if (field->is_repeated() && !field->is_map()) { 487 if (field->is_repeated() && !field->is_map()) {
431 // Add "Array" before do check for reserved worlds. 488 // Add "Array" before do check for reserved worlds.
432 result += "Array"; 489 result += "Array";
433 } else { 490 } else {
434 // If it wasn't repeated, but ends in "Array", force on the _p suffix. 491 // If it wasn't repeated, but ends in "Array", force on the _p suffix.
435 if (HasSuffixString(result, "Array")) { 492 if (HasSuffixString(result, "Array")) {
436 result += "_p"; 493 result += "_p";
437 } 494 }
438 } 495 }
439 return SanitizeNameForObjC(result, "_p"); 496 return SanitizeNameForObjC(result, "_p", NULL);
440 } 497 }
441 498
442 string FieldNameCapitalized(const FieldDescriptor* field) { 499 string FieldNameCapitalized(const FieldDescriptor* field) {
443 // Want the same suffix handling, so upcase the first letter of the other 500 // Want the same suffix handling, so upcase the first letter of the other
444 // name. 501 // name.
445 string result = FieldName(field); 502 string result = FieldName(field);
446 if (result.length() > 0) { 503 if (result.length() > 0) {
447 result[0] = ascii_toupper(result[0]); 504 result[0] = ascii_toupper(result[0]);
448 } 505 }
449 return result; 506 return result;
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after
789 case FieldDescriptor::CPPTYPE_MESSAGE: 846 case FieldDescriptor::CPPTYPE_MESSAGE:
790 return false; 847 return false;
791 } 848 }
792 849
793 // Some compilers report reaching end of function even though all cases of 850 // Some compilers report reaching end of function even though all cases of
794 // the enum are handed in the switch. 851 // the enum are handed in the switch.
795 GOOGLE_LOG(FATAL) << "Can't get here."; 852 GOOGLE_LOG(FATAL) << "Can't get here.";
796 return false; 853 return false;
797 } 854 }
798 855
799 string BuildFlagsString(const vector<string>& strings) { 856 string BuildFlagsString(const FlagType flag_type,
857 const vector<string>& strings) {
800 if (strings.size() == 0) { 858 if (strings.size() == 0) {
801 return "0"; 859 return GetZeroEnumNameForFlagType(flag_type);
860 } else if (strings.size() == 1) {
861 return strings[0];
802 } 862 }
803 string string; 863 string string("(" + GetEnumNameForFlagType(flag_type) + ")(");
804 for (size_t i = 0; i != strings.size(); ++i) { 864 for (size_t i = 0; i != strings.size(); ++i) {
805 if (i > 0) { 865 if (i > 0) {
806 string.append(" | "); 866 string.append(" | ");
807 } 867 }
808 string.append(strings[i]); 868 string.append(strings[i]);
809 } 869 }
870 string.append(")");
810 return string; 871 return string;
811 } 872 }
812 873
813 string BuildCommentsString(const SourceLocation& location) { 874 string BuildCommentsString(const SourceLocation& location,
875 bool prefer_single_line) {
814 const string& comments = location.leading_comments.empty() 876 const string& comments = location.leading_comments.empty()
815 ? location.trailing_comments 877 ? location.trailing_comments
816 : location.leading_comments; 878 : location.leading_comments;
817 vector<string> lines; 879 vector<string> lines;
818 SplitStringAllowEmpty(comments, "\n", &lines); 880 SplitStringAllowEmpty(comments, "\n", &lines);
819 while (!lines.empty() && lines.back().empty()) { 881 while (!lines.empty() && lines.back().empty()) {
820 lines.pop_back(); 882 lines.pop_back();
821 } 883 }
822 string prefix("///"); 884 // If there are no comments, just return an empty string.
823 string suffix("\n"); 885 if (lines.size() == 0) {
886 return "";
887 }
888
889 string prefix;
890 string suffix;
824 string final_comments; 891 string final_comments;
892 string epilogue;
893
894 bool add_leading_space = false;
895
896 if (prefer_single_line && lines.size() == 1) {
897 prefix = "/** ";
898 suffix = " */\n";
899 } else {
900 prefix = "* ";
901 suffix = "\n";
902 final_comments += "/**\n";
903 epilogue = " **/\n";
904 add_leading_space = true;
905 }
906
825 for (int i = 0; i < lines.size(); i++) { 907 for (int i = 0; i < lines.size(); i++) {
826 // HeaderDoc uses '\' and '@' for markers; escape them. 908 string line = StripPrefixString(lines[i], " ");
827 const string line = StringReplace(lines[i], "\\", "\\\\", true); 909 // HeaderDoc and appledoc use '\' and '@' for markers; escape them.
828 final_comments += 910 line = StringReplace(line, "\\", "\\\\", true);
829 prefix + StringReplace(line, "@", "\\@", true) + suffix; 911 line = StringReplace(line, "@", "\\@", true);
912 // Decouple / from * to not have inline comments inside comments.
913 line = StringReplace(line, "/*", "/\\*", true);
914 line = StringReplace(line, "*/", "*\\/", true);
915 line = prefix + line;
916 StripWhitespace(&line);
917 // If not a one line, need to add the first space before *, as
918 // StripWhitespace would have removed it.
919 line = (add_leading_space ? " " : "") + line;
920 final_comments += line + suffix;
830 } 921 }
922 final_comments += epilogue;
831 return final_comments; 923 return final_comments;
832 } 924 }
833 925
834 namespace { 926 // Making these a generator option for folks that don't use CocoaPods, but do
927 // want to put the library in a framework is an interesting question. The
928 // problem is it means changing sources shipped with the library to actually
929 // use a different value; so it isn't as simple as a option.
930 const char* const ProtobufLibraryFrameworkName = "Protobuf";
835 931
836 // Internal helper class that parses the expected package to prefix mappings 932 string ProtobufFrameworkImportSymbol(const string& framework_name) {
837 // file. 933 // GPB_USE_[framework_name]_FRAMEWORK_IMPORTS
838 class Parser { 934 string result = string("GPB_USE_");
839 public: 935 result += ToUpper(framework_name);
840 Parser(map<string, string>* inout_package_to_prefix_map) 936 result += "_FRAMEWORK_IMPORTS";
841 : prefix_map_(inout_package_to_prefix_map), line_(0) {}
842
843 // Parses a check of input, returning success/failure.
844 bool ParseChunk(StringPiece chunk);
845
846 // Should be called to finish parsing (after all input has been provided via
847 // ParseChunk()). Returns success/failure.
848 bool Finish();
849
850 int last_line() const { return line_; }
851 string error_str() const { return error_str_; }
852
853 private:
854 bool ParseLoop();
855
856 map<string, string>* prefix_map_;
857 int line_;
858 string error_str_;
859 StringPiece p_;
860 string leftover_;
861 };
862
863 bool Parser::ParseChunk(StringPiece chunk) {
864 if (!leftover_.empty()) {
865 chunk.AppendToString(&leftover_);
866 p_ = StringPiece(leftover_);
867 } else {
868 p_ = chunk;
869 }
870 bool result = ParseLoop();
871 if (p_.empty()) {
872 leftover_.clear();
873 } else {
874 leftover_ = p_.ToString();
875 }
876 return result; 937 return result;
877 } 938 }
878 939
879 bool Parser::Finish() { 940 bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file) {
880 if (leftover_.empty()) { 941 // We don't check the name prefix or proto package because some files
942 // (descriptor.proto), aren't shipped generated by the library, so this
943 // seems to be the safest way to only catch the ones shipped.
944 const string name = file->name();
945 if (name == "google/protobuf/any.proto" ||
946 name == "google/protobuf/api.proto" ||
947 name == "google/protobuf/duration.proto" ||
948 name == "google/protobuf/empty.proto" ||
949 name == "google/protobuf/field_mask.proto" ||
950 name == "google/protobuf/source_context.proto" ||
951 name == "google/protobuf/struct.proto" ||
952 name == "google/protobuf/timestamp.proto" ||
953 name == "google/protobuf/type.proto" ||
954 name == "google/protobuf/wrappers.proto") {
881 return true; 955 return true;
882 } 956 }
883 // Force a newline onto the end to finish parsing. 957 return false;
884 p_ = StringPiece(leftover_ + "\n");
885 if (!ParseLoop()) {
886 return false;
887 }
888 return p_.empty(); // Everything used?
889 } 958 }
890 959
891 static bool ascii_isnewline(char c) { return c == '\n' || c == '\r'; }
892
893 bool ReadLine(StringPiece* input, StringPiece* line) { 960 bool ReadLine(StringPiece* input, StringPiece* line) {
894 for (int len = 0; len < input->size(); ++len) { 961 for (int len = 0; len < input->size(); ++len) {
895 if (ascii_isnewline((*input)[len])) { 962 if (ascii_isnewline((*input)[len])) {
896 *line = StringPiece(input->data(), len); 963 *line = StringPiece(input->data(), len);
897 ++len; // advance over the newline 964 ++len; // advance over the newline
898 *input = StringPiece(input->data() + len, input->size() - len); 965 *input = StringPiece(input->data() + len, input->size() - len);
899 return true; 966 return true;
900 } 967 }
901 } 968 }
902 return false; // Ran out of input with no newline. 969 return false; // Ran out of input with no newline.
903 } 970 }
904 971
905 void TrimWhitespace(StringPiece* input) {
906 while (!input->empty() && ascii_isspace(*input->data())) {
907 input->remove_prefix(1);
908 }
909 while (!input->empty() && ascii_isspace((*input)[input->length() - 1])) {
910 input->remove_suffix(1);
911 }
912 }
913
914 void RemoveComment(StringPiece* input) { 972 void RemoveComment(StringPiece* input) {
915 int offset = input->find('#'); 973 int offset = input->find('#');
916 if (offset != StringPiece::npos) { 974 if (offset != StringPiece::npos) {
917 input->remove_suffix(input->length() - offset); 975 input->remove_suffix(input->length() - offset);
918 } 976 }
919 } 977 }
920 978
921 bool Parser::ParseLoop() { 979 namespace {
922 StringPiece line; 980
923 while (ReadLine(&p_, &line)) { 981 class ExpectedPrefixesCollector : public LineConsumer {
924 ++line_; 982 public:
925 RemoveComment(&line); 983 ExpectedPrefixesCollector(map<string, string>* inout_package_to_prefix_map)
926 TrimWhitespace(&line); 984 : prefix_map_(inout_package_to_prefix_map) {}
927 if (line.size() == 0) { 985
928 continue; // Blank line. 986 virtual bool ConsumeLine(const StringPiece& line, string* out_error);
929 } 987
930 int offset = line.find('='); 988 private:
931 if (offset == StringPiece::npos) { 989 map<string, string>* prefix_map_;
932 error_str_ = 990 };
933 string("Line without equal sign: '") + line.ToString() + "'."; 991
934 return false; 992 bool ExpectedPrefixesCollector::ConsumeLine(
935 } 993 const StringPiece& line, string* out_error) {
936 StringPiece package(line, 0, offset); 994 int offset = line.find('=');
937 StringPiece prefix(line, offset + 1, line.length() - offset - 1); 995 if (offset == StringPiece::npos) {
938 TrimWhitespace(&package); 996 *out_error =
939 TrimWhitespace(&prefix); 997 string("Expected prefixes file line without equal sign: '") +
940 // Don't really worry about error checking the package/prefix for 998 line.ToString() + "'.";
941 // being valid. Assume the file is validated when it is created/edited. 999 return false;
942 (*prefix_map_)[package.ToString()] = prefix.ToString();
943 } 1000 }
1001 StringPiece package(line, 0, offset);
1002 StringPiece prefix(line, offset + 1, line.length() - offset - 1);
1003 StringPieceTrimWhitespace(&package);
1004 StringPieceTrimWhitespace(&prefix);
1005 // Don't really worry about error checking the package/prefix for
1006 // being valid. Assume the file is validated when it is created/edited.
1007 (*prefix_map_)[package.ToString()] = prefix.ToString();
944 return true; 1008 return true;
945 } 1009 }
946 1010
947 bool LoadExpectedPackagePrefixes(const Options &generation_options, 1011 bool LoadExpectedPackagePrefixes(const Options &generation_options,
948 map<string, string>* prefix_map, 1012 map<string, string>* prefix_map,
949 string* out_error) { 1013 string* out_error) {
950 if (generation_options.expected_prefixes_path.empty()) { 1014 if (generation_options.expected_prefixes_path.empty()) {
951 return true; 1015 return true;
952 } 1016 }
953 1017
954 int fd; 1018 ExpectedPrefixesCollector collector(prefix_map);
955 do { 1019 return ParseSimpleFile(
956 fd = open(generation_options.expected_prefixes_path.c_str(), O_RDONLY); 1020 generation_options.expected_prefixes_path, &collector, out_error);
957 } while (fd < 0 && errno == EINTR);
958 if (fd < 0) {
959 *out_error =
960 string("error: Unable to open \"") +
961 generation_options.expected_prefixes_path +
962 "\", " + strerror(errno);
963 return false;
964 }
965 io::FileInputStream file_stream(fd);
966 file_stream.SetCloseOnDelete(true);
967
968 Parser parser(prefix_map);
969 const void* buf;
970 int buf_len;
971 while (file_stream.Next(&buf, &buf_len)) {
972 if (buf_len == 0) {
973 continue;
974 }
975
976 if (!parser.ParseChunk(StringPiece(static_cast<const char*>(buf), buf_len))) {
977 *out_error =
978 string("error: ") + generation_options.expected_prefixes_path +
979 " Line " + SimpleItoa(parser.last_line()) + ", " + parser.error_str();
980 return false;
981 }
982 }
983 return parser.Finish();
984 } 1021 }
985 1022
986 } // namespace 1023 bool ValidateObjCClassPrefix(
987 1024 const FileDescriptor* file,
988 bool ValidateObjCClassPrefix(const FileDescriptor* file, 1025 const string& expected_prefixes_path,
989 const Options& generation_options, 1026 const map<string, string>& expected_package_prefixes,
990 string* out_error) { 1027 string* out_error) {
991 const string prefix = file->options().objc_class_prefix(); 1028 const string prefix = file->options().objc_class_prefix();
992 const string package = file->package(); 1029 const string package = file->package();
993 1030
994 // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some 1031 // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
995 // error cases, so it seems to be ok to use as a back door for warnings. 1032 // error cases, so it seems to be ok to use as a back door for warnings.
996 1033
997 // Load any expected package prefixes to validate against those.
998 map<string, string> expected_package_prefixes;
999 if (!LoadExpectedPackagePrefixes(generation_options,
1000 &expected_package_prefixes,
1001 out_error)) {
1002 return false;
1003 }
1004
1005 // Check: Error - See if there was an expected prefix for the package and 1034 // Check: Error - See if there was an expected prefix for the package and
1006 // report if it doesn't match (wrong or missing). 1035 // report if it doesn't match (wrong or missing).
1007 map<string, string>::iterator package_match = 1036 map<string, string>::const_iterator package_match =
1008 expected_package_prefixes.find(package); 1037 expected_package_prefixes.find(package);
1009 if (package_match != expected_package_prefixes.end()) { 1038 if (package_match != expected_package_prefixes.end()) {
1010 // There was an entry, and... 1039 // There was an entry, and...
1011 if (package_match->second == prefix) { 1040 if (package_match->second == prefix) {
1012 // ...it matches. All good, out of here! 1041 // ...it matches. All good, out of here!
1013 return true; 1042 return true;
1014 } else { 1043 } else {
1015 // ...it didn't match! 1044 // ...it didn't match!
1016 *out_error = "error: Expected 'option objc_class_prefix = \"" + 1045 *out_error = "error: Expected 'option objc_class_prefix = \"" +
1017 package_match->second + "\";' for package '" + package + 1046 package_match->second + "\";' for package '" + package +
1018 "' in '" + file->name() + "'"; 1047 "' in '" + file->name() + "'";
1019 if (prefix.length()) { 1048 if (prefix.length()) {
1020 *out_error += "; but found '" + prefix + "' instead"; 1049 *out_error += "; but found '" + prefix + "' instead";
1021 } 1050 }
1022 *out_error += "."; 1051 *out_error += ".";
1023 return false; 1052 return false;
1024 } 1053 }
1025 } 1054 }
1026 1055
1027 // If there was no prefix option, we're done at this point. 1056 // If there was no prefix option, we're done at this point.
1028 if (prefix.length() == 0) { 1057 if (prefix.empty()) {
1029 // No prefix, nothing left to check. 1058 // No prefix, nothing left to check.
1030 return true; 1059 return true;
1031 } 1060 }
1032 1061
1033 // Check: Error - Make sure the prefix wasn't expected for a different
1034 // package (overlap is allowed, but it has to be listed as an expected
1035 // overlap).
1036 for (map<string, string>::iterator i = expected_package_prefixes.begin();
1037 i != expected_package_prefixes.end(); ++i) {
1038 if (i->second == prefix) {
1039 *out_error =
1040 "error: Found 'option objc_class_prefix = \"" + prefix +
1041 "\";' in '" + file->name() +
1042 "'; that prefix is already used for 'package " + i->first +
1043 ";'. It can only be reused by listing it in the expected file (" +
1044 generation_options.expected_prefixes_path + ").";
1045 return false; // Only report first usage of the prefix.
1046 }
1047 }
1048
1049 // Check: Warning - Make sure the prefix is is a reasonable value according 1062 // Check: Warning - Make sure the prefix is is a reasonable value according
1050 // to Apple's rules (the checks above implicitly whitelist anything that 1063 // to Apple's rules (the checks above implicitly whitelist anything that
1051 // doesn't meet these rules). 1064 // doesn't meet these rules).
1052 if (!ascii_isupper(prefix[0])) { 1065 if (!ascii_isupper(prefix[0])) {
1053 cerr << endl 1066 cerr << endl
1054 << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" 1067 << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
1055 << prefix << "\";' in '" << file->name() << "';" 1068 << prefix << "\";' in '" << file->name() << "';"
1056 << " it should start with a capital letter." << endl; 1069 << " it should start with a capital letter." << endl;
1057 cerr.flush(); 1070 cerr.flush();
1058 } 1071 }
1059 if (prefix.length() < 3) { 1072 if (prefix.length() < 3) {
1060 // Apple reserves 2 character prefixes for themselves. They do use some 1073 // Apple reserves 2 character prefixes for themselves. They do use some
1061 // 3 character prefixes, but they haven't updated the rules/docs. 1074 // 3 character prefixes, but they haven't updated the rules/docs.
1062 cerr << endl 1075 cerr << endl
1063 << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" 1076 << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
1064 << prefix << "\";' in '" << file->name() << "';" 1077 << prefix << "\";' in '" << file->name() << "';"
1065 << " Apple recommends they should be at least 3 characters long." 1078 << " Apple recommends they should be at least 3 characters long."
1066 << endl; 1079 << endl;
1067 cerr.flush(); 1080 cerr.flush();
1068 } 1081 }
1069 1082
1083 // Look for any other package that uses the same prefix.
1084 string other_package_for_prefix;
1085 for (map<string, string>::const_iterator i = expected_package_prefixes.begin() ;
1086 i != expected_package_prefixes.end(); ++i) {
1087 if (i->second == prefix) {
1088 other_package_for_prefix = i->first;
1089 break;
1090 }
1091 }
1092
1093 // Check: Warning - If the file does not have a package, check whether
1094 // the prefix declared is being used by another package or not.
1095 if (package.empty()) {
1096 // The file does not have a package and ...
1097 if (other_package_for_prefix.empty()) {
1098 // ... no other package has declared that prefix.
1099 cerr << endl
1100 << "protoc:0: warning: File '" << file->name() << "' has no "
1101 << "package. Consider adding a new package to the proto and adding '"
1102 << "new.package = " << prefix << "' to the expected prefixes file ("
1103 << expected_prefixes_path << ")." << endl;
1104 cerr.flush();
1105 } else {
1106 // ... another package has declared the same prefix.
1107 cerr << endl
1108 << "protoc:0: warning: File '" << file->name() << "' has no package "
1109 << "and package '" << other_package_for_prefix << "' already uses '"
1110 << prefix << "' as its prefix. Consider either adding a new package "
1111 << "to the proto, or reusing one of the packages already using this "
1112 << "prefix in the expected prefixes file ("
1113 << expected_prefixes_path << ")." << endl;
1114 cerr.flush();
1115 }
1116 return true;
1117 }
1118
1119 // Check: Error - Make sure the prefix wasn't expected for a different
1120 // package (overlap is allowed, but it has to be listed as an expected
1121 // overlap).
1122 if (!other_package_for_prefix.empty()) {
1123 *out_error =
1124 "error: Found 'option objc_class_prefix = \"" + prefix +
1125 "\";' in '" + file->name() +
1126 "'; that prefix is already used for 'package " +
1127 other_package_for_prefix + ";'. It can only be reused by listing " +
1128 "it in the expected file (" +
1129 expected_prefixes_path + ").";
1130 return false; // Only report first usage of the prefix.
1131 }
1132
1070 // Check: Warning - If the given package/prefix pair wasn't expected, issue a 1133 // Check: Warning - If the given package/prefix pair wasn't expected, issue a
1071 // warning issue a warning suggesting it gets added to the file. 1134 // warning issue a warning suggesting it gets added to the file.
1072 if (!expected_package_prefixes.empty()) { 1135 if (!expected_package_prefixes.empty()) {
1073 cerr << endl 1136 cerr << endl
1074 << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \"" 1137 << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \""
1075 << prefix << "\";' in '" << file->name() << "';" 1138 << prefix << "\";' in '" << file->name() << "';"
1076 << " consider adding it to the expected prefixes file (" 1139 << " consider adding it to the expected prefixes file ("
1077 << generation_options.expected_prefixes_path << ")." << endl; 1140 << expected_prefixes_path << ")." << endl;
1078 cerr.flush(); 1141 cerr.flush();
1079 } 1142 }
1080 1143
1081 return true; 1144 return true;
1082 } 1145 }
1083 1146
1147 } // namespace
1148
1149 bool ValidateObjCClassPrefixes(const vector<const FileDescriptor*>& files,
1150 const Options& generation_options,
1151 string* out_error) {
1152 // Load the expected package prefixes, if available, to validate against.
1153 map<string, string> expected_package_prefixes;
1154 if (!LoadExpectedPackagePrefixes(generation_options,
1155 &expected_package_prefixes,
1156 out_error)) {
1157 return false;
1158 }
1159
1160 for (int i = 0; i < files.size(); i++) {
1161 bool is_valid =
1162 ValidateObjCClassPrefix(files[i],
1163 generation_options.expected_prefixes_path,
1164 expected_package_prefixes,
1165 out_error);
1166 if (!is_valid) {
1167 return false;
1168 }
1169 }
1170 return true;
1171 }
1172
1173 TextFormatDecodeData::TextFormatDecodeData() { }
1174
1175 TextFormatDecodeData::~TextFormatDecodeData() { }
1176
1084 void TextFormatDecodeData::AddString(int32 key, 1177 void TextFormatDecodeData::AddString(int32 key,
1085 const string& input_for_decode, 1178 const string& input_for_decode,
1086 const string& desired_output) { 1179 const string& desired_output) {
1087 for (vector<DataEntry>::const_iterator i = entries_.begin(); 1180 for (vector<DataEntry>::const_iterator i = entries_.begin();
1088 i != entries_.end(); ++i) { 1181 i != entries_.end(); ++i) {
1089 if (i->first == key) { 1182 if (i->first == key) {
1090 cerr << "error: duplicate key (" << key 1183 cerr << "error: duplicate key (" << key
1091 << ") making TextFormat data, input: \"" << input_for_decode 1184 << ") making TextFormat data, input: \"" << input_for_decode
1092 << "\", desired: \"" << desired_output << "\"." << endl; 1185 << "\", desired: \"" << desired_output << "\"." << endl;
1093 cerr.flush(); 1186 cerr.flush();
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
1282 1375
1283 if (x != input_for_decode.size()) { 1376 if (x != input_for_decode.size()) {
1284 // Extra input (suffix from name sanitizing?), just return a full decode. 1377 // Extra input (suffix from name sanitizing?), just return a full decode.
1285 return DirectDecodeString(desired_output); 1378 return DirectDecodeString(desired_output);
1286 } 1379 }
1287 1380
1288 // Add the end marker. 1381 // Add the end marker.
1289 return builder.Finish() + (char)'\0'; 1382 return builder.Finish() + (char)'\0';
1290 } 1383 }
1291 1384
1385 namespace {
1386
1387 class Parser {
1388 public:
1389 Parser(LineConsumer* line_consumer)
1390 : line_consumer_(line_consumer), line_(0) {}
1391
1392 // Parses a check of input, returning success/failure.
1393 bool ParseChunk(StringPiece chunk);
1394
1395 // Should be called to finish parsing (after all input has been provided via
1396 // ParseChunk()). Returns success/failure.
1397 bool Finish();
1398
1399 int last_line() const { return line_; }
1400 string error_str() const { return error_str_; }
1401
1402 private:
1403 bool ParseLoop();
1404
1405 LineConsumer* line_consumer_;
1406 int line_;
1407 string error_str_;
1408 StringPiece p_;
1409 string leftover_;
1410 };
1411
1412 bool Parser::ParseChunk(StringPiece chunk) {
1413 if (!leftover_.empty()) {
1414 chunk.AppendToString(&leftover_);
1415 p_ = StringPiece(leftover_);
1416 } else {
1417 p_ = chunk;
1418 }
1419 bool result = ParseLoop();
1420 if (p_.empty()) {
1421 leftover_.clear();
1422 } else {
1423 leftover_ = p_.ToString();
1424 }
1425 return result;
1426 }
1427
1428 bool Parser::Finish() {
1429 if (leftover_.empty()) {
1430 return true;
1431 }
1432 // Force a newline onto the end to finish parsing.
1433 leftover_ += "\n";
1434 p_ = StringPiece(leftover_);
1435 if (!ParseLoop()) {
1436 return false;
1437 }
1438 return p_.empty(); // Everything used?
1439 }
1440
1441 bool Parser::ParseLoop() {
1442 StringPiece line;
1443 while (ReadLine(&p_, &line)) {
1444 ++line_;
1445 RemoveComment(&line);
1446 StringPieceTrimWhitespace(&line);
1447 if (line.size() == 0) {
1448 continue; // Blank line.
1449 }
1450 if (!line_consumer_->ConsumeLine(line, &error_str_)) {
1451 return false;
1452 }
1453 }
1454 return true;
1455 }
1456
1457 } // namespace
1458
1459 LineConsumer::LineConsumer() {}
1460
1461 LineConsumer::~LineConsumer() {}
1462
1463 bool ParseSimpleFile(
1464 const string& path, LineConsumer* line_consumer, string* out_error) {
1465 int fd;
1466 do {
1467 fd = open(path.c_str(), O_RDONLY);
1468 } while (fd < 0 && errno == EINTR);
1469 if (fd < 0) {
1470 *out_error =
1471 string("error: Unable to open \"") + path + "\", " + strerror(errno);
1472 return false;
1473 }
1474 io::FileInputStream file_stream(fd);
1475 file_stream.SetCloseOnDelete(true);
1476
1477 Parser parser(line_consumer);
1478 const void* buf;
1479 int buf_len;
1480 while (file_stream.Next(&buf, &buf_len)) {
1481 if (buf_len == 0) {
1482 continue;
1483 }
1484
1485 if (!parser.ParseChunk(StringPiece(static_cast<const char*>(buf), buf_len))) {
1486 *out_error =
1487 string("error: ") + path +
1488 " Line " + SimpleItoa(parser.last_line()) + ", " + parser.error_str();
1489 return false;
1490 }
1491 }
1492 return parser.Finish();
1493 }
1494
1495 ImportWriter::ImportWriter(
1496 const string& generate_for_named_framework,
1497 const string& named_framework_to_proto_path_mappings_path)
1498 : generate_for_named_framework_(generate_for_named_framework),
1499 named_framework_to_proto_path_mappings_path_(
1500 named_framework_to_proto_path_mappings_path),
1501 need_to_parse_mapping_file_(true) {
1502 }
1503
1504 ImportWriter::~ImportWriter() {}
1505
1506 void ImportWriter::AddFile(const FileDescriptor* file,
1507 const string& header_extension) {
1508 const string file_path(FilePath(file));
1509
1510 if (IsProtobufLibraryBundledProtoFile(file)) {
1511 protobuf_framework_imports_.push_back(
1512 FilePathBasename(file) + header_extension);
1513 protobuf_non_framework_imports_.push_back(file_path + header_extension);
1514 return;
1515 }
1516
1517 // Lazy parse any mappings.
1518 if (need_to_parse_mapping_file_) {
1519 ParseFrameworkMappings();
1520 }
1521
1522 map<string, string>::iterator proto_lookup =
1523 proto_file_to_framework_name_.find(file->name());
1524 if (proto_lookup != proto_file_to_framework_name_.end()) {
1525 other_framework_imports_.push_back(
1526 proto_lookup->second + "/" +
1527 FilePathBasename(file) + header_extension);
1528 return;
1529 }
1530
1531 if (!generate_for_named_framework_.empty()) {
1532 other_framework_imports_.push_back(
1533 generate_for_named_framework_ + "/" +
1534 FilePathBasename(file) + header_extension);
1535 return;
1536 }
1537
1538 other_imports_.push_back(file_path + header_extension);
1539 }
1540
1541 void ImportWriter::Print(io::Printer* printer) const {
1542 assert(protobuf_non_framework_imports_.size() ==
1543 protobuf_framework_imports_.size());
1544
1545 bool add_blank_line = false;
1546
1547 if (protobuf_framework_imports_.size() > 0) {
1548 const string framework_name(ProtobufLibraryFrameworkName);
1549 const string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name));
1550
1551 printer->Print(
1552 "#if $cpp_symbol$\n",
1553 "cpp_symbol", cpp_symbol);
1554 for (vector<string>::const_iterator iter = protobuf_framework_imports_.begin ();
1555 iter != protobuf_framework_imports_.end(); ++iter) {
1556 printer->Print(
1557 " #import <$framework_name$/$header$>\n",
1558 "framework_name", framework_name,
1559 "header", *iter);
1560 }
1561 printer->Print(
1562 "#else\n");
1563 for (vector<string>::const_iterator iter = protobuf_non_framework_imports_.b egin();
1564 iter != protobuf_non_framework_imports_.end(); ++iter) {
1565 printer->Print(
1566 " #import \"$header$\"\n",
1567 "header", *iter);
1568 }
1569 printer->Print(
1570 "#endif\n");
1571
1572 add_blank_line = true;
1573 }
1574
1575 if (other_framework_imports_.size() > 0) {
1576 if (add_blank_line) {
1577 printer->Print("\n");
1578 }
1579
1580 for (vector<string>::const_iterator iter = other_framework_imports_.begin();
1581 iter != other_framework_imports_.end(); ++iter) {
1582 printer->Print(
1583 " #import <$header$>\n",
1584 "header", *iter);
1585 }
1586
1587 add_blank_line = true;
1588 }
1589
1590 if (other_imports_.size() > 0) {
1591 if (add_blank_line) {
1592 printer->Print("\n");
1593 }
1594
1595 for (vector<string>::const_iterator iter = other_imports_.begin();
1596 iter != other_imports_.end(); ++iter) {
1597 printer->Print(
1598 " #import \"$header$\"\n",
1599 "header", *iter);
1600 }
1601 }
1602 }
1603
1604 void ImportWriter::ParseFrameworkMappings() {
1605 need_to_parse_mapping_file_ = false;
1606 if (named_framework_to_proto_path_mappings_path_.empty()) {
1607 return; // Nothing to do.
1608 }
1609
1610 ProtoFrameworkCollector collector(&proto_file_to_framework_name_);
1611 string parse_error;
1612 if (!ParseSimpleFile(named_framework_to_proto_path_mappings_path_,
1613 &collector, &parse_error)) {
1614 cerr << "error parsing " << named_framework_to_proto_path_mappings_path_
1615 << " : " << parse_error << endl;
1616 cerr.flush();
1617 }
1618 }
1619
1620 bool ImportWriter::ProtoFrameworkCollector::ConsumeLine(
1621 const StringPiece& line, string* out_error) {
1622 int offset = line.find(':');
1623 if (offset == StringPiece::npos) {
1624 *out_error =
1625 string("Framework/proto file mapping line without colon sign: '") +
1626 line.ToString() + "'.";
1627 return false;
1628 }
1629 StringPiece framework_name(line, 0, offset);
1630 StringPiece proto_file_list(line, offset + 1, line.length() - offset - 1);
1631 StringPieceTrimWhitespace(&framework_name);
1632
1633 int start = 0;
1634 while (start < proto_file_list.length()) {
1635 offset = proto_file_list.find(',', start);
1636 if (offset == StringPiece::npos) {
1637 offset = proto_file_list.length();
1638 }
1639
1640 StringPiece proto_file(proto_file_list, start, offset - start);
1641 StringPieceTrimWhitespace(&proto_file);
1642 if (proto_file.size() != 0) {
1643 map<string, string>::iterator existing_entry =
1644 map_->find(proto_file.ToString());
1645 if (existing_entry != map_->end()) {
1646 cerr << "warning: duplicate proto file reference, replacing framework en try for '"
1647 << proto_file.ToString() << "' with '" << framework_name.ToString()
1648 << "' (was '" << existing_entry->second << "')." << endl;
1649 cerr.flush();
1650 }
1651
1652 if (proto_file.find(' ') != StringPiece::npos) {
1653 cerr << "note: framework mapping file had a proto file with a space in, hopefully that isn't a missing comma: '"
1654 << proto_file.ToString() << "'" << endl;
1655 cerr.flush();
1656 }
1657
1658 (*map_)[proto_file.ToString()] = framework_name.ToString();
1659 }
1660
1661 start = offset + 1;
1662 }
1663
1664 return true;
1665 }
1666
1667
1292 } // namespace objectivec 1668 } // namespace objectivec
1293 } // namespace compiler 1669 } // namespace compiler
1294 } // namespace protobuf 1670 } // namespace protobuf
1295 } // namespace google 1671 } // namespace google
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698