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

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

Issue 2590803003: Revert "third_party/protobuf: Update to HEAD (83d681ee2c)" (Closed)
Patch Set: 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/io/coded_stream.h>
48 #include <google/protobuf/io/zero_copy_stream_impl.h>
47 #include <google/protobuf/descriptor.pb.h> 49 #include <google/protobuf/descriptor.pb.h>
48 #include <google/protobuf/io/coded_stream.h>
49 #include <google/protobuf/io/printer.h>
50 #include <google/protobuf/io/zero_copy_stream_impl.h>
51 #include <google/protobuf/stubs/common.h> 50 #include <google/protobuf/stubs/common.h>
52 #include <google/protobuf/stubs/strutil.h> 51 #include <google/protobuf/stubs/strutil.h>
53 52
54 // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some 53 // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
55 // error cases, so it seems to be ok to use as a back door for errors. 54 // error cases, so it seems to be ok to use as a back door for errors.
56 55
57 namespace google { 56 namespace google {
58 namespace protobuf { 57 namespace protobuf {
59 namespace compiler { 58 namespace compiler {
60 namespace objectivec { 59 namespace objectivec {
(...skipping 14 matching lines...) Expand all
75 result.insert(words[i]); 74 result.insert(words[i]);
76 } 75 }
77 return result; 76 return result;
78 } 77 }
79 78
80 const char* const kUpperSegmentsList[] = {"url", "http", "https"}; 79 const char* const kUpperSegmentsList[] = {"url", "http", "https"};
81 80
82 hash_set<string> kUpperSegments = 81 hash_set<string> kUpperSegments =
83 MakeWordsMap(kUpperSegmentsList, GOOGLE_ARRAYSIZE(kUpperSegmentsList)); 82 MakeWordsMap(kUpperSegmentsList, GOOGLE_ARRAYSIZE(kUpperSegmentsList));
84 83
85 bool ascii_isnewline(char c) {
86 return c == '\n' || c == '\r';
87 }
88
89 // Internal helper for name handing. 84 // Internal helper for name handing.
90 // Do not expose this outside of helpers, stick to having functions for specific 85 // Do not expose this outside of helpers, stick to having functions for specific
91 // cases (ClassName(), FieldName()), so there is always consistent suffix rules. 86 // cases (ClassName(), FieldName()), so there is always consistent suffix rules.
92 string UnderscoresToCamelCase(const string& input, bool first_capitalized) { 87 string UnderscoresToCamelCase(const string& input, bool first_capitalized) {
93 vector<string> values; 88 vector<string> values;
94 string current; 89 string current;
95 90
96 bool last_char_was_number = false; 91 bool last_char_was_number = false;
97 bool last_char_was_lower = false; 92 bool last_char_was_lower = false;
98 bool last_char_was_upper = false; 93 bool last_char_was_upper = false;
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 "Fixed", "Fract", "Size", "LogicalAddress", "PhysicalAddress", "ByteCount", 198 "Fixed", "Fract", "Size", "LogicalAddress", "PhysicalAddress", "ByteCount",
204 "ByteOffset", "Duration", "AbsoluteTime", "OptionBits", "ItemCount", 199 "ByteOffset", "Duration", "AbsoluteTime", "OptionBits", "ItemCount",
205 "PBVersion", "ScriptCode", "LangCode", "RegionCode", "OSType", 200 "PBVersion", "ScriptCode", "LangCode", "RegionCode", "OSType",
206 "ProcessSerialNumber", "Point", "Rect", "FixedPoint", "FixedRect", "Style", 201 "ProcessSerialNumber", "Point", "Rect", "FixedPoint", "FixedRect", "Style",
207 "StyleParameter", "StyleField", "TimeScale", "TimeBase", "TimeRecord", 202 "StyleParameter", "StyleField", "TimeScale", "TimeBase", "TimeRecord",
208 }; 203 };
209 204
210 hash_set<string> kReservedWords = 205 hash_set<string> kReservedWords =
211 MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList)); 206 MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList));
212 207
213 string SanitizeNameForObjC(const string& input, 208 string SanitizeNameForObjC(const string& input, const string& extension) {
214 const string& extension,
215 string* out_suffix_added) {
216 if (kReservedWords.count(input) > 0) { 209 if (kReservedWords.count(input) > 0) {
217 if (out_suffix_added) *out_suffix_added = extension;
218 return input + extension; 210 return input + extension;
219 } 211 }
220 if (out_suffix_added) out_suffix_added->clear();
221 return input; 212 return input;
222 } 213 }
223 214
224 string NameFromFieldDescriptor(const FieldDescriptor* field) { 215 string NameFromFieldDescriptor(const FieldDescriptor* field) {
225 if (field->type() == FieldDescriptor::TYPE_GROUP) { 216 if (field->type() == FieldDescriptor::TYPE_GROUP) {
226 return field->message_type()->name(); 217 return field->message_type()->name();
227 } else { 218 } else {
228 return field->name(); 219 return field->name();
229 } 220 }
230 } 221 }
(...skipping 28 matching lines...) Expand all
259 // new_ton). 250 // new_ton).
260 return !ascii_islower(name[length]); 251 return !ascii_islower(name[length]);
261 } else { 252 } else {
262 return true; 253 return true;
263 } 254 }
264 } 255 }
265 } 256 }
266 return false; 257 return false;
267 } 258 }
268 259
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
297 } // namespace 260 } // namespace
298 261
299 // Escape C++ trigraphs by escaping question marks to \? 262 // Escape C++ trigraphs by escaping question marks to \?
300 string EscapeTrigraphs(const string& to_escape) { 263 string EscapeTrigraphs(const string& to_escape) {
301 return StringReplace(to_escape, "?", "\\?", true); 264 return StringReplace(to_escape, "?", "\\?", true);
302 } 265 }
303 266
304 string StripProto(const string& filename) { 267 string StripProto(const string& filename) {
305 if (HasSuffixString(filename, ".protodevel")) { 268 if (HasSuffixString(filename, ".protodevel")) {
306 return StripSuffixString(filename, ".protodevel"); 269 return StripSuffixString(filename, ".protodevel");
307 } else { 270 } else {
308 return StripSuffixString(filename, ".proto"); 271 return StripSuffixString(filename, ".proto");
309 } 272 }
310 } 273 }
311 274
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
322 bool IsRetainedName(const string& name) { 275 bool IsRetainedName(const string& name) {
323 // List of prefixes from 276 // List of prefixes from
324 // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Memo ryMgmt/Articles/mmRules.html 277 // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Memo ryMgmt/Articles/mmRules.html
325 static const string retained_names[] = {"new", "alloc", "copy", 278 static const string retained_names[] = {"new", "alloc", "copy",
326 "mutableCopy"}; 279 "mutableCopy"};
327 return IsSpecialName(name, retained_names, 280 return IsSpecialName(name, retained_names,
328 sizeof(retained_names) / sizeof(retained_names[0])); 281 sizeof(retained_names) / sizeof(retained_names[0]));
329 } 282 }
330 283
331 bool IsInitName(const string& name) { 284 bool IsInitName(const string& name) {
332 static const string init_names[] = {"init"}; 285 static const string init_names[] = {"init"};
333 return IsSpecialName(name, init_names, 286 return IsSpecialName(name, init_names,
334 sizeof(init_names) / sizeof(init_names[0])); 287 sizeof(init_names) / sizeof(init_names[0]));
335 } 288 }
336 289
337 string BaseFileName(const FileDescriptor* file) { 290 string BaseFileName(const FileDescriptor* file) {
338 string basename; 291 string basename;
339 PathSplit(file->name(), NULL, &basename); 292 PathSplit(file->name(), NULL, &basename);
340 return basename; 293 return basename;
341 } 294 }
342 295
343 string FileClassPrefix(const FileDescriptor* file) { 296 string FileName(const FileDescriptor* file) {
344 // Default is empty string, no need to check has_objc_class_prefix. 297 string path = FilePath(file);
345 string result = file->options().objc_class_prefix(); 298 string basename;
346 return result; 299 PathSplit(path, NULL, &basename);
300 return basename;
347 } 301 }
348 302
349 string FilePath(const FileDescriptor* file) { 303 string FilePath(const FileDescriptor* file) {
350 string output; 304 string output;
351 string basename; 305 string basename;
352 string directory; 306 string directory;
353 PathSplit(file->name(), &directory, &basename); 307 PathSplit(file->name(), &directory, &basename);
354 if (directory.length() > 0) { 308 if (directory.length() > 0) {
355 output = directory + "/"; 309 output = directory + "/";
356 } 310 }
357 basename = StripProto(basename); 311 basename = StripProto(basename);
358 312
359 // CamelCase to be more ObjC friendly. 313 // CamelCase to be more ObjC friendly.
360 basename = UnderscoresToCamelCase(basename, true); 314 basename = UnderscoresToCamelCase(basename, true);
361 315
362 output += basename; 316 output += basename;
363 return output; 317 return output;
364 } 318 }
365 319
366 string FilePathBasename(const FileDescriptor* file) { 320 string FileClassPrefix(const FileDescriptor* file) {
367 string output; 321 // Default is empty string, no need to check has_objc_class_prefix.
368 string basename; 322 string result = file->options().objc_class_prefix();
369 string directory; 323 return result;
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;
377 } 324 }
378 325
379 string FileClassName(const FileDescriptor* file) { 326 string FileClassName(const FileDescriptor* file) {
380 string name = FileClassPrefix(file); 327 string name = FileClassPrefix(file);
381 name += UnderscoresToCamelCase(StripProto(BaseFileName(file)), true); 328 name += UnderscoresToCamelCase(StripProto(BaseFileName(file)), true);
382 name += "Root"; 329 name += "Root";
383 // There aren't really any reserved words that end in "Root", but playing 330 // There aren't really any reserved words that end in "Root", but playing
384 // it safe and checking. 331 // it safe and checking.
385 return SanitizeNameForObjC(name, "_RootClass", NULL); 332 return SanitizeNameForObjC(name, "_RootClass");
386 } 333 }
387 334
388 string ClassNameWorker(const Descriptor* descriptor) { 335 string ClassNameWorker(const Descriptor* descriptor) {
389 string name; 336 string name;
390 if (descriptor->containing_type() != NULL) { 337 if (descriptor->containing_type() != NULL) {
391 name = ClassNameWorker(descriptor->containing_type()); 338 name = ClassNameWorker(descriptor->containing_type());
392 name += "_"; 339 name += "_";
393 } 340 }
394 return name + descriptor->name(); 341 return name + descriptor->name();
395 } 342 }
396 343
397 string ClassNameWorker(const EnumDescriptor* descriptor) { 344 string ClassNameWorker(const EnumDescriptor* descriptor) {
398 string name; 345 string name;
399 if (descriptor->containing_type() != NULL) { 346 if (descriptor->containing_type() != NULL) {
400 name = ClassNameWorker(descriptor->containing_type()); 347 name = ClassNameWorker(descriptor->containing_type());
401 name += "_"; 348 name += "_";
402 } 349 }
403 return name + descriptor->name(); 350 return name + descriptor->name();
404 } 351 }
405 352
406 string ClassName(const Descriptor* descriptor) { 353 string ClassName(const Descriptor* descriptor) {
407 return ClassName(descriptor, NULL);
408 }
409
410 string ClassName(const Descriptor* descriptor, string* out_suffix_added) {
411 // 1. Message names are used as is (style calls for CamelCase, trust it). 354 // 1. Message names are used as is (style calls for CamelCase, trust it).
412 // 2. Check for reserved word at the very end and then suffix things. 355 // 2. Check for reserved word at the very end and then suffix things.
413 string prefix = FileClassPrefix(descriptor->file()); 356 string prefix = FileClassPrefix(descriptor->file());
414 string name = ClassNameWorker(descriptor); 357 string name = ClassNameWorker(descriptor);
415 return SanitizeNameForObjC(prefix + name, "_Class", out_suffix_added); 358 return SanitizeNameForObjC(prefix + name, "_Class");
416 } 359 }
417 360
418 string EnumName(const EnumDescriptor* descriptor) { 361 string EnumName(const EnumDescriptor* descriptor) {
419 // 1. Enum names are used as is (style calls for CamelCase, trust it). 362 // 1. Enum names are used as is (style calls for CamelCase, trust it).
420 // 2. Check for reserved word at the every end and then suffix things. 363 // 2. Check for reserved word at the every end and then suffix things.
421 // message Fixed { 364 // message Fixed {
422 // message Size {...} 365 // message Size {...}
423 // enum Mumble {...} 366 // enum Mumble {...}
424 // ... 367 // ...
425 // } 368 // }
426 // yields Fixed_Class, Fixed_Size. 369 // yields Fixed_Class, Fixed_Size.
427 string name = FileClassPrefix(descriptor->file()); 370 string name = FileClassPrefix(descriptor->file());
428 name += ClassNameWorker(descriptor); 371 name += ClassNameWorker(descriptor);
429 return SanitizeNameForObjC(name, "_Enum", NULL); 372 return SanitizeNameForObjC(name, "_Enum");
430 } 373 }
431 374
432 string EnumValueName(const EnumValueDescriptor* descriptor) { 375 string EnumValueName(const EnumValueDescriptor* descriptor) {
433 // Because of the Switch enum compatibility, the name on the enum has to have 376 // Because of the Switch enum compatibility, the name on the enum has to have
434 // the suffix handing, so it slightly diverges from how nested classes work. 377 // the suffix handing, so it slightly diverges from how nested classes work.
435 // enum Fixed { 378 // enum Fixed {
436 // FOO = 1 379 // FOO = 1
437 // } 380 // }
438 // yields Fixed_Enum and Fixed_Enum_Foo (not Fixed_Foo). 381 // yields Fixed_Enum and Fixed_Enum_Foo (not Fixed_Foo).
439 const string& class_name = EnumName(descriptor->type()); 382 const string& class_name = EnumName(descriptor->type());
440 const string& value_str = UnderscoresToCamelCase(descriptor->name(), true); 383 const string& value_str = UnderscoresToCamelCase(descriptor->name(), true);
441 const string& name = class_name + "_" + value_str; 384 const string& name = class_name + "_" + value_str;
442 // There aren't really any reserved words with an underscore and a leading 385 // There aren't really any reserved words with an underscore and a leading
443 // capital letter, but playing it safe and checking. 386 // capital letter, but playing it safe and checking.
444 return SanitizeNameForObjC(name, "_Value", NULL); 387 return SanitizeNameForObjC(name, "_Value");
445 } 388 }
446 389
447 string EnumValueShortName(const EnumValueDescriptor* descriptor) { 390 string EnumValueShortName(const EnumValueDescriptor* descriptor) {
448 // Enum value names (EnumValueName above) are the enum name turned into 391 // Enum value names (EnumValueName above) are the enum name turned into
449 // a class name and then the value name is CamelCased and concatenated; the 392 // a class name and then the value name is CamelCased and concatenated; the
450 // whole thing then gets sanitized for reserved words. 393 // whole thing then gets sanitized for reserved words.
451 // The "short name" is intended to be the final leaf, the value name; but 394 // The "short name" is intended to be the final leaf, the value name; but
452 // you can't simply send that off to sanitize as that could result in it 395 // you can't simply send that off to sanitize as that could result in it
453 // getting modified when the full name didn't. For example enum 396 // getting modified when the full name didn't. For example enum
454 // "StorageModes" has a value "retain". So the full name is 397 // "StorageModes" has a value "retain". So the full name is
(...skipping 16 matching lines...) Expand all
471 result += '_'; 414 result += '_';
472 } 415 }
473 result += ascii_toupper(c); 416 result += ascii_toupper(c);
474 } 417 }
475 return result; 418 return result;
476 } 419 }
477 420
478 string ExtensionMethodName(const FieldDescriptor* descriptor) { 421 string ExtensionMethodName(const FieldDescriptor* descriptor) {
479 const string& name = NameFromFieldDescriptor(descriptor); 422 const string& name = NameFromFieldDescriptor(descriptor);
480 const string& result = UnderscoresToCamelCase(name, false); 423 const string& result = UnderscoresToCamelCase(name, false);
481 return SanitizeNameForObjC(result, "_Extension", NULL); 424 return SanitizeNameForObjC(result, "_Extension");
482 } 425 }
483 426
484 string FieldName(const FieldDescriptor* field) { 427 string FieldName(const FieldDescriptor* field) {
485 const string& name = NameFromFieldDescriptor(field); 428 const string& name = NameFromFieldDescriptor(field);
486 string result = UnderscoresToCamelCase(name, false); 429 string result = UnderscoresToCamelCase(name, false);
487 if (field->is_repeated() && !field->is_map()) { 430 if (field->is_repeated() && !field->is_map()) {
488 // Add "Array" before do check for reserved worlds. 431 // Add "Array" before do check for reserved worlds.
489 result += "Array"; 432 result += "Array";
490 } else { 433 } else {
491 // If it wasn't repeated, but ends in "Array", force on the _p suffix. 434 // If it wasn't repeated, but ends in "Array", force on the _p suffix.
492 if (HasSuffixString(result, "Array")) { 435 if (HasSuffixString(result, "Array")) {
493 result += "_p"; 436 result += "_p";
494 } 437 }
495 } 438 }
496 return SanitizeNameForObjC(result, "_p", NULL); 439 return SanitizeNameForObjC(result, "_p");
497 } 440 }
498 441
499 string FieldNameCapitalized(const FieldDescriptor* field) { 442 string FieldNameCapitalized(const FieldDescriptor* field) {
500 // Want the same suffix handling, so upcase the first letter of the other 443 // Want the same suffix handling, so upcase the first letter of the other
501 // name. 444 // name.
502 string result = FieldName(field); 445 string result = FieldName(field);
503 if (result.length() > 0) { 446 if (result.length() > 0) {
504 result[0] = ascii_toupper(result[0]); 447 result[0] = ascii_toupper(result[0]);
505 } 448 }
506 return result; 449 return result;
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after
846 case FieldDescriptor::CPPTYPE_MESSAGE: 789 case FieldDescriptor::CPPTYPE_MESSAGE:
847 return false; 790 return false;
848 } 791 }
849 792
850 // Some compilers report reaching end of function even though all cases of 793 // Some compilers report reaching end of function even though all cases of
851 // the enum are handed in the switch. 794 // the enum are handed in the switch.
852 GOOGLE_LOG(FATAL) << "Can't get here."; 795 GOOGLE_LOG(FATAL) << "Can't get here.";
853 return false; 796 return false;
854 } 797 }
855 798
856 string BuildFlagsString(const FlagType flag_type, 799 string BuildFlagsString(const vector<string>& strings) {
857 const vector<string>& strings) {
858 if (strings.size() == 0) { 800 if (strings.size() == 0) {
859 return GetZeroEnumNameForFlagType(flag_type); 801 return "0";
860 } else if (strings.size() == 1) {
861 return strings[0];
862 } 802 }
863 string string("(" + GetEnumNameForFlagType(flag_type) + ")("); 803 string string;
864 for (size_t i = 0; i != strings.size(); ++i) { 804 for (size_t i = 0; i != strings.size(); ++i) {
865 if (i > 0) { 805 if (i > 0) {
866 string.append(" | "); 806 string.append(" | ");
867 } 807 }
868 string.append(strings[i]); 808 string.append(strings[i]);
869 } 809 }
870 string.append(")");
871 return string; 810 return string;
872 } 811 }
873 812
874 string BuildCommentsString(const SourceLocation& location, 813 string BuildCommentsString(const SourceLocation& location) {
875 bool prefer_single_line) {
876 const string& comments = location.leading_comments.empty() 814 const string& comments = location.leading_comments.empty()
877 ? location.trailing_comments 815 ? location.trailing_comments
878 : location.leading_comments; 816 : location.leading_comments;
879 vector<string> lines; 817 vector<string> lines;
880 SplitStringAllowEmpty(comments, "\n", &lines); 818 SplitStringAllowEmpty(comments, "\n", &lines);
881 while (!lines.empty() && lines.back().empty()) { 819 while (!lines.empty() && lines.back().empty()) {
882 lines.pop_back(); 820 lines.pop_back();
883 } 821 }
884 // If there are no comments, just return an empty string. 822 string prefix("///");
885 if (lines.size() == 0) { 823 string suffix("\n");
886 return ""; 824 string final_comments;
825 for (int i = 0; i < lines.size(); i++) {
826 // HeaderDoc uses '\' and '@' for markers; escape them.
827 const string line = StringReplace(lines[i], "\\", "\\\\", true);
828 final_comments +=
829 prefix + StringReplace(line, "@", "\\@", true) + suffix;
887 } 830 }
888
889 string prefix;
890 string suffix;
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
907 for (int i = 0; i < lines.size(); i++) {
908 string line = StripPrefixString(lines[i], " ");
909 // HeaderDoc and appledoc use '\' and '@' for markers; escape them.
910 line = StringReplace(line, "\\", "\\\\", true);
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;
921 }
922 final_comments += epilogue;
923 return final_comments; 831 return final_comments;
924 } 832 }
925 833
926 // Making these a generator option for folks that don't use CocoaPods, but do 834 namespace {
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";
931 835
932 string ProtobufFrameworkImportSymbol(const string& framework_name) { 836 // Internal helper class that parses the expected package to prefix mappings
933 // GPB_USE_[framework_name]_FRAMEWORK_IMPORTS 837 // file.
934 string result = string("GPB_USE_"); 838 class Parser {
935 result += ToUpper(framework_name); 839 public:
936 result += "_FRAMEWORK_IMPORTS"; 840 Parser(map<string, string>* inout_package_to_prefix_map)
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 }
937 return result; 876 return result;
938 } 877 }
939 878
940 bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file) { 879 bool Parser::Finish() {
941 // We don't check the name prefix or proto package because some files 880 if (leftover_.empty()) {
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") {
955 return true; 881 return true;
956 } 882 }
957 return false; 883 // Force a newline onto the end to finish parsing.
884 p_ = StringPiece(leftover_ + "\n");
885 if (!ParseLoop()) {
886 return false;
887 }
888 return p_.empty(); // Everything used?
958 } 889 }
959 890
891 static bool ascii_isnewline(char c) { return c == '\n' || c == '\r'; }
892
960 bool ReadLine(StringPiece* input, StringPiece* line) { 893 bool ReadLine(StringPiece* input, StringPiece* line) {
961 for (int len = 0; len < input->size(); ++len) { 894 for (int len = 0; len < input->size(); ++len) {
962 if (ascii_isnewline((*input)[len])) { 895 if (ascii_isnewline((*input)[len])) {
963 *line = StringPiece(input->data(), len); 896 *line = StringPiece(input->data(), len);
964 ++len; // advance over the newline 897 ++len; // advance over the newline
965 *input = StringPiece(input->data() + len, input->size() - len); 898 *input = StringPiece(input->data() + len, input->size() - len);
966 return true; 899 return true;
967 } 900 }
968 } 901 }
969 return false; // Ran out of input with no newline. 902 return false; // Ran out of input with no newline.
970 } 903 }
971 904
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
972 void RemoveComment(StringPiece* input) { 914 void RemoveComment(StringPiece* input) {
973 int offset = input->find('#'); 915 int offset = input->find('#');
974 if (offset != StringPiece::npos) { 916 if (offset != StringPiece::npos) {
975 input->remove_suffix(input->length() - offset); 917 input->remove_suffix(input->length() - offset);
976 } 918 }
977 } 919 }
978 920
979 namespace { 921 bool Parser::ParseLoop() {
980 922 StringPiece line;
981 class ExpectedPrefixesCollector : public LineConsumer { 923 while (ReadLine(&p_, &line)) {
982 public: 924 ++line_;
983 ExpectedPrefixesCollector(map<string, string>* inout_package_to_prefix_map) 925 RemoveComment(&line);
984 : prefix_map_(inout_package_to_prefix_map) {} 926 TrimWhitespace(&line);
985 927 if (line.size() == 0) {
986 virtual bool ConsumeLine(const StringPiece& line, string* out_error); 928 continue; // Blank line.
987 929 }
988 private: 930 int offset = line.find('=');
989 map<string, string>* prefix_map_; 931 if (offset == StringPiece::npos) {
990 }; 932 error_str_ =
991 933 string("Line without equal sign: '") + line.ToString() + "'.";
992 bool ExpectedPrefixesCollector::ConsumeLine( 934 return false;
993 const StringPiece& line, string* out_error) { 935 }
994 int offset = line.find('='); 936 StringPiece package(line, 0, offset);
995 if (offset == StringPiece::npos) { 937 StringPiece prefix(line, offset + 1, line.length() - offset - 1);
996 *out_error = 938 TrimWhitespace(&package);
997 string("Expected prefixes file line without equal sign: '") + 939 TrimWhitespace(&prefix);
998 line.ToString() + "'."; 940 // Don't really worry about error checking the package/prefix for
999 return false; 941 // being valid. Assume the file is validated when it is created/edited.
942 (*prefix_map_)[package.ToString()] = prefix.ToString();
1000 } 943 }
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();
1008 return true; 944 return true;
1009 } 945 }
1010 946
1011 bool LoadExpectedPackagePrefixes(const Options &generation_options, 947 bool LoadExpectedPackagePrefixes(const Options &generation_options,
1012 map<string, string>* prefix_map, 948 map<string, string>* prefix_map,
1013 string* out_error) { 949 string* out_error) {
1014 if (generation_options.expected_prefixes_path.empty()) { 950 if (generation_options.expected_prefixes_path.empty()) {
1015 return true; 951 return true;
1016 } 952 }
1017 953
1018 ExpectedPrefixesCollector collector(prefix_map); 954 int fd;
1019 return ParseSimpleFile( 955 do {
1020 generation_options.expected_prefixes_path, &collector, out_error); 956 fd = open(generation_options.expected_prefixes_path.c_str(), O_RDONLY);
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();
1021 } 984 }
1022 985
1023 bool ValidateObjCClassPrefix( 986 } // namespace
1024 const FileDescriptor* file, 987
1025 const string& expected_prefixes_path, 988 bool ValidateObjCClassPrefix(const FileDescriptor* file,
1026 const map<string, string>& expected_package_prefixes, 989 const Options& generation_options,
1027 string* out_error) { 990 string* out_error) {
1028 const string prefix = file->options().objc_class_prefix(); 991 const string prefix = file->options().objc_class_prefix();
1029 const string package = file->package(); 992 const string package = file->package();
1030 993
1031 // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some 994 // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
1032 // error cases, so it seems to be ok to use as a back door for warnings. 995 // error cases, so it seems to be ok to use as a back door for warnings.
1033 996
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
1034 // Check: Error - See if there was an expected prefix for the package and 1005 // Check: Error - See if there was an expected prefix for the package and
1035 // report if it doesn't match (wrong or missing). 1006 // report if it doesn't match (wrong or missing).
1036 map<string, string>::const_iterator package_match = 1007 map<string, string>::iterator package_match =
1037 expected_package_prefixes.find(package); 1008 expected_package_prefixes.find(package);
1038 if (package_match != expected_package_prefixes.end()) { 1009 if (package_match != expected_package_prefixes.end()) {
1039 // There was an entry, and... 1010 // There was an entry, and...
1040 if (package_match->second == prefix) { 1011 if (package_match->second == prefix) {
1041 // ...it matches. All good, out of here! 1012 // ...it matches. All good, out of here!
1042 return true; 1013 return true;
1043 } else { 1014 } else {
1044 // ...it didn't match! 1015 // ...it didn't match!
1045 *out_error = "error: Expected 'option objc_class_prefix = \"" + 1016 *out_error = "error: Expected 'option objc_class_prefix = \"" +
1046 package_match->second + "\";' for package '" + package + 1017 package_match->second + "\";' for package '" + package +
1047 "' in '" + file->name() + "'"; 1018 "' in '" + file->name() + "'";
1048 if (prefix.length()) { 1019 if (prefix.length()) {
1049 *out_error += "; but found '" + prefix + "' instead"; 1020 *out_error += "; but found '" + prefix + "' instead";
1050 } 1021 }
1051 *out_error += "."; 1022 *out_error += ".";
1052 return false; 1023 return false;
1053 } 1024 }
1054 } 1025 }
1055 1026
1056 // If there was no prefix option, we're done at this point. 1027 // If there was no prefix option, we're done at this point.
1057 if (prefix.empty()) { 1028 if (prefix.length() == 0) {
1058 // No prefix, nothing left to check. 1029 // No prefix, nothing left to check.
1059 return true; 1030 return true;
1060 } 1031 }
1061 1032
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
1062 // Check: Warning - Make sure the prefix is is a reasonable value according 1049 // Check: Warning - Make sure the prefix is is a reasonable value according
1063 // to Apple's rules (the checks above implicitly whitelist anything that 1050 // to Apple's rules (the checks above implicitly whitelist anything that
1064 // doesn't meet these rules). 1051 // doesn't meet these rules).
1065 if (!ascii_isupper(prefix[0])) { 1052 if (!ascii_isupper(prefix[0])) {
1066 cerr << endl 1053 cerr << endl
1067 << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" 1054 << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
1068 << prefix << "\";' in '" << file->name() << "';" 1055 << prefix << "\";' in '" << file->name() << "';"
1069 << " it should start with a capital letter." << endl; 1056 << " it should start with a capital letter." << endl;
1070 cerr.flush(); 1057 cerr.flush();
1071 } 1058 }
1072 if (prefix.length() < 3) { 1059 if (prefix.length() < 3) {
1073 // Apple reserves 2 character prefixes for themselves. They do use some 1060 // Apple reserves 2 character prefixes for themselves. They do use some
1074 // 3 character prefixes, but they haven't updated the rules/docs. 1061 // 3 character prefixes, but they haven't updated the rules/docs.
1075 cerr << endl 1062 cerr << endl
1076 << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" 1063 << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
1077 << prefix << "\";' in '" << file->name() << "';" 1064 << prefix << "\";' in '" << file->name() << "';"
1078 << " Apple recommends they should be at least 3 characters long." 1065 << " Apple recommends they should be at least 3 characters long."
1079 << endl; 1066 << endl;
1080 cerr.flush(); 1067 cerr.flush();
1081 } 1068 }
1082 1069
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
1133 // Check: Warning - If the given package/prefix pair wasn't expected, issue a 1070 // Check: Warning - If the given package/prefix pair wasn't expected, issue a
1134 // warning issue a warning suggesting it gets added to the file. 1071 // warning issue a warning suggesting it gets added to the file.
1135 if (!expected_package_prefixes.empty()) { 1072 if (!expected_package_prefixes.empty()) {
1136 cerr << endl 1073 cerr << endl
1137 << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \"" 1074 << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \""
1138 << prefix << "\";' in '" << file->name() << "';" 1075 << prefix << "\";' in '" << file->name() << "';"
1139 << " consider adding it to the expected prefixes file (" 1076 << " consider adding it to the expected prefixes file ("
1140 << expected_prefixes_path << ")." << endl; 1077 << generation_options.expected_prefixes_path << ")." << endl;
1141 cerr.flush(); 1078 cerr.flush();
1142 } 1079 }
1143 1080
1144 return true; 1081 return true;
1145 } 1082 }
1146 1083
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
1177 void TextFormatDecodeData::AddString(int32 key, 1084 void TextFormatDecodeData::AddString(int32 key,
1178 const string& input_for_decode, 1085 const string& input_for_decode,
1179 const string& desired_output) { 1086 const string& desired_output) {
1180 for (vector<DataEntry>::const_iterator i = entries_.begin(); 1087 for (vector<DataEntry>::const_iterator i = entries_.begin();
1181 i != entries_.end(); ++i) { 1088 i != entries_.end(); ++i) {
1182 if (i->first == key) { 1089 if (i->first == key) {
1183 cerr << "error: duplicate key (" << key 1090 cerr << "error: duplicate key (" << key
1184 << ") making TextFormat data, input: \"" << input_for_decode 1091 << ") making TextFormat data, input: \"" << input_for_decode
1185 << "\", desired: \"" << desired_output << "\"." << endl; 1092 << "\", desired: \"" << desired_output << "\"." << endl;
1186 cerr.flush(); 1093 cerr.flush();
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
1375 1282
1376 if (x != input_for_decode.size()) { 1283 if (x != input_for_decode.size()) {
1377 // Extra input (suffix from name sanitizing?), just return a full decode. 1284 // Extra input (suffix from name sanitizing?), just return a full decode.
1378 return DirectDecodeString(desired_output); 1285 return DirectDecodeString(desired_output);
1379 } 1286 }
1380 1287
1381 // Add the end marker. 1288 // Add the end marker.
1382 return builder.Finish() + (char)'\0'; 1289 return builder.Finish() + (char)'\0';
1383 } 1290 }
1384 1291
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
1668 } // namespace objectivec 1292 } // namespace objectivec
1669 } // namespace compiler 1293 } // namespace compiler
1670 } // namespace protobuf 1294 } // namespace protobuf
1671 } // namespace google 1295 } // namespace google
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698