~ubuntu-branches/debian/stretch/protobuf/stretch

« back to all changes in this revision

Viewing changes to src/google/protobuf/compiler/command_line_interface.cc

  • Committer: Package Import Robot
  • Author(s): Robert S. Edmonds
  • Date: 2014-09-11 22:50:10 UTC
  • mfrom: (10.1.9 experimental)
  • Revision ID: package-import@ubuntu.com-20140911225010-wt4yo9dpc1fzuq5g
Tags: 2.6.0-3
Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
49
49
#include <ctype.h>
50
50
 
51
51
#include <google/protobuf/stubs/hash.h>
 
52
#include <memory>
52
53
 
53
54
#include <google/protobuf/stubs/common.h>
 
55
#include <google/protobuf/stubs/stringprintf.h>
54
56
#include <google/protobuf/compiler/importer.h>
55
57
#include <google/protobuf/compiler/code_generator.h>
56
58
#include <google/protobuf/compiler/plugin.pb.h>
64
66
#include <google/protobuf/io/printer.h>
65
67
#include <google/protobuf/stubs/strutil.h>
66
68
#include <google/protobuf/stubs/substitute.h>
67
 
#include <google/protobuf/stubs/map-util.h>
 
69
#include <google/protobuf/stubs/map_util.h>
68
70
#include <google/protobuf/stubs/stl_util.h>
69
71
 
70
72
 
160
162
// directories listed in |filename|.
161
163
bool TryCreateParentDirectory(const string& prefix, const string& filename) {
162
164
  // Recursively create parent directories to the output file.
163
 
  vector<string> parts;
164
 
  SplitStringUsing(filename, "/", &parts);
 
165
  vector<string> parts = Split(filename, "/", true);
165
166
  string path_so_far = prefix;
166
167
  for (int i = 0; i < parts.size() - 1; i++) {
167
168
    path_so_far += parts[i];
252
253
 
253
254
  // implements GeneratorContext --------------------------------------
254
255
  io::ZeroCopyOutputStream* Open(const string& filename);
 
256
  io::ZeroCopyOutputStream* OpenForAppend(const string& filename);
255
257
  io::ZeroCopyOutputStream* OpenForInsert(
256
258
      const string& filename, const string& insertion_point);
257
259
  void ListParsedFiles(vector<const FileDescriptor*>* output) {
271
273
class CommandLineInterface::MemoryOutputStream
272
274
    : public io::ZeroCopyOutputStream {
273
275
 public:
274
 
  MemoryOutputStream(GeneratorContextImpl* directory, const string& filename);
 
276
  MemoryOutputStream(GeneratorContextImpl* directory, const string& filename,
 
277
                     bool append_mode);
275
278
  MemoryOutputStream(GeneratorContextImpl* directory, const string& filename,
276
279
                     const string& insertion_point);
277
280
  virtual ~MemoryOutputStream();
290
293
  // The string we're building.
291
294
  string data_;
292
295
 
 
296
  // Whether we should append the output stream to the existing file.
 
297
  bool append_mode_;
 
298
 
293
299
  // StringOutputStream writing to data_.
294
300
  scoped_ptr<io::StringOutputStream> inner_;
295
301
};
434
440
 
435
441
io::ZeroCopyOutputStream* CommandLineInterface::GeneratorContextImpl::Open(
436
442
    const string& filename) {
437
 
  return new MemoryOutputStream(this, filename);
 
443
  return new MemoryOutputStream(this, filename, false);
 
444
}
 
445
 
 
446
io::ZeroCopyOutputStream*
 
447
CommandLineInterface::GeneratorContextImpl::OpenForAppend(
 
448
    const string& filename) {
 
449
  return new MemoryOutputStream(this, filename, true);
438
450
}
439
451
 
440
452
io::ZeroCopyOutputStream*
446
458
// -------------------------------------------------------------------
447
459
 
448
460
CommandLineInterface::MemoryOutputStream::MemoryOutputStream(
449
 
    GeneratorContextImpl* directory, const string& filename)
 
461
    GeneratorContextImpl* directory, const string& filename, bool append_mode)
450
462
    : directory_(directory),
451
463
      filename_(filename),
 
464
      append_mode_(append_mode),
452
465
      inner_(new io::StringOutputStream(&data_)) {
453
466
}
454
467
 
471
484
  if (insertion_point_.empty()) {
472
485
    // This was just a regular Open().
473
486
    if (*map_slot != NULL) {
474
 
      cerr << filename_ << ": Tried to write the same file twice." << endl;
475
 
      directory_->had_error_ = true;
 
487
      if (append_mode_) {
 
488
        (*map_slot)->append(data_);
 
489
      } else {
 
490
        cerr << filename_ << ": Tried to write the same file twice." << endl;
 
491
        directory_->had_error_ = true;
 
492
      }
476
493
      return;
477
494
    }
478
495
 
565
582
 
566
583
CommandLineInterface::CommandLineInterface()
567
584
  : mode_(MODE_COMPILE),
 
585
    print_mode_(PRINT_NONE),
568
586
    error_format_(ERROR_FORMAT_GCC),
569
587
    imports_in_descriptor_set_(false),
570
588
    source_info_in_descriptor_set_(false),
632
650
  // Parse each file.
633
651
  for (int i = 0; i < input_files_.size(); i++) {
634
652
    // Import the file.
 
653
    importer.AddUnusedImportTrackFile(input_files_[i]);
635
654
    const FileDescriptor* parsed_file = importer.Import(input_files_[i]);
 
655
    importer.ClearUnusedImportTrackFiles();
636
656
    if (parsed_file == NULL) return 1;
637
657
    parsed_files.push_back(parsed_file);
638
658
 
721
741
    }
722
742
  }
723
743
 
 
744
  if (mode_ == MODE_PRINT) {
 
745
    switch (print_mode_) {
 
746
      case PRINT_FREE_FIELDS:
 
747
        for (int i = 0; i < parsed_files.size(); ++i) {
 
748
          const FileDescriptor* fd = parsed_files[i];
 
749
          for (int j = 0; j < fd->message_type_count(); ++j) {
 
750
            PrintFreeFieldNumbers(fd->message_type(j));
 
751
          }
 
752
        }
 
753
        break;
 
754
      case PRINT_NONE:
 
755
        GOOGLE_LOG(ERROR) << "If the code reaches here, it usually means a bug of "
 
756
                     "flag parsing in the CommonadLineInterface.";
 
757
        return 1;
 
758
 
 
759
      // Do not add a default case.
 
760
    }
 
761
  }
 
762
 
724
763
  return 0;
725
764
}
726
765
 
735
774
  descriptor_set_name_.clear();
736
775
 
737
776
  mode_ = MODE_COMPILE;
 
777
  print_mode_ = PRINT_NONE;
738
778
  imports_in_descriptor_set_ = false;
739
779
  source_info_in_descriptor_set_ = false;
740
780
  disallow_services_ = false;
889
929
      *name == "--include_imports" ||
890
930
      *name == "--include_source_info" ||
891
931
      *name == "--version" ||
892
 
      *name == "--decode_raw") {
 
932
      *name == "--decode_raw" ||
 
933
      *name == "--print_free_field_numbers") {
893
934
    // HACK:  These are the only flags that don't take a value.
894
935
    //   They probably should not be hard-coded like this but for now it's
895
936
    //   not worth doing better.
919
960
    // Java's -classpath (and some other languages) delimits path components
920
961
    // with colons.  Let's accept that syntax too just to make things more
921
962
    // intuitive.
922
 
    vector<string> parts;
923
 
    SplitStringUsing(value, kPathSeparator, &parts);
 
963
    vector<string> parts = Split(
 
964
        value, kPathSeparator, true);
924
965
 
925
966
    for (int i = 0; i < parts.size(); i++) {
926
967
      string virtual_path;
1061
1102
 
1062
1103
    plugins_[plugin_name] = path;
1063
1104
 
 
1105
  } else if (name == "--print_free_field_numbers") {
 
1106
    if (mode_ != MODE_COMPILE) {
 
1107
      cerr << "Cannot use " << name << " and use --encode, --decode or print "
 
1108
           << "other info at the same time." << endl;
 
1109
      return PARSE_ARGUMENT_FAIL;
 
1110
    }
 
1111
    if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
 
1112
      cerr << "Cannot use " << name
 
1113
           << " and generate code or descriptors at the same time." << endl;
 
1114
      return PARSE_ARGUMENT_FAIL;
 
1115
    }
 
1116
    mode_ = MODE_PRINT;
 
1117
    print_mode_ = PRINT_FREE_FIELDS;
1064
1118
  } else {
1065
1119
    // Some other flag.  Look it up in the generators list.
1066
1120
    const GeneratorInfo* generator_info =
1082
1136
    } else {
1083
1137
      // It's an output flag.  Add it to the output directives.
1084
1138
      if (mode_ != MODE_COMPILE) {
1085
 
        cerr << "Cannot use --encode or --decode and generate code at the "
1086
 
                "same time." << endl;
 
1139
        cerr << "Cannot use --encode, --decode or print .proto info and "
 
1140
                "generate code at the same time." << endl;
1087
1141
        return PARSE_ARGUMENT_FAIL;
1088
1142
      }
1089
1143
 
1151
1205
"                              well as surrounding comments.\n"
1152
1206
"  --error_format=FORMAT       Set the format in which to print errors.\n"
1153
1207
"                              FORMAT may be 'gcc' (the default) or 'msvs'\n"
1154
 
"                              (Microsoft Visual Studio format)." << endl;
 
1208
"                              (Microsoft Visual Studio format).\n"
 
1209
"  --print_free_field_numbers  Print the free field numbers of the messages\n"
 
1210
"                              defined in the given proto files. Groups share\n"
 
1211
"                              the same field number space with the parent \n"
 
1212
"                              message. Extension ranges are counted as \n"
 
1213
"                              occupied fields numbers."  << endl;
1155
1214
  if (!plugin_prefix_.empty()) {
1156
1215
    cerr <<
1157
1216
"  --plugin=EXECUTABLE         Specifies a plugin executable to use.\n"
1431
1490
  }
1432
1491
}
1433
1492
 
 
1493
namespace {
 
1494
 
 
1495
// Utility function for PrintFreeFieldNumbers.
 
1496
// Stores occupied ranges into the ranges parameter, and next level of sub
 
1497
// message types into the nested_messages parameter.  The FieldRange is left
 
1498
// inclusive, right exclusive. i.e. [a, b).
 
1499
//
 
1500
// Nested Messages:
 
1501
// Note that it only stores the nested message type, iff the nested type is
 
1502
// either a direct child of the given descriptor, or the nested type is a
 
1503
// decendent of the given descriptor and all the nodes between the
 
1504
// nested type and the given descriptor are group types. e.g.
 
1505
//
 
1506
// message Foo {
 
1507
//   message Bar {
 
1508
//     message NestedBar {}
 
1509
//   }
 
1510
//   group Baz = 1 {
 
1511
//     group NestedBazGroup = 2 {
 
1512
//       message Quz {
 
1513
//         message NestedQuz {}
 
1514
//       }
 
1515
//     }
 
1516
//     message NestedBaz {}
 
1517
//   }
 
1518
// }
 
1519
//
 
1520
// In this case, Bar, Quz and NestedBaz will be added into the nested types.
 
1521
// Since free field numbers of group types will not be printed, this makes sure
 
1522
// the nested message types in groups will not be dropped. The nested_messages
 
1523
// parameter will contain the direct children (when groups are ignored in the
 
1524
// tree) of the given descriptor for the caller to traverse. The declaration
 
1525
// order of the nested messages is also preserved.
 
1526
typedef pair<int, int> FieldRange;
 
1527
void GatherOccupiedFieldRanges(const Descriptor* descriptor,
 
1528
                               set<FieldRange>* ranges,
 
1529
                               vector<const Descriptor*>* nested_messages) {
 
1530
  set<const Descriptor*> groups;
 
1531
  for (int i = 0; i < descriptor->field_count(); ++i) {
 
1532
    const FieldDescriptor* fd = descriptor->field(i);
 
1533
    ranges->insert(FieldRange(fd->number(), fd->number() + 1));
 
1534
    if (fd->type() == FieldDescriptor::TYPE_GROUP) {
 
1535
      groups.insert(fd->message_type());
 
1536
    }
 
1537
  }
 
1538
  for (int i = 0; i < descriptor->extension_range_count(); ++i) {
 
1539
    ranges->insert(FieldRange(descriptor->extension_range(i)->start,
 
1540
                              descriptor->extension_range(i)->end));
 
1541
  }
 
1542
  // Handle the nested messages/groups in declaration order to make it
 
1543
  // post-order strict.
 
1544
  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
 
1545
    const Descriptor* nested_desc = descriptor->nested_type(i);
 
1546
    if (groups.find(nested_desc) != groups.end()) {
 
1547
      GatherOccupiedFieldRanges(nested_desc, ranges, nested_messages);
 
1548
    } else {
 
1549
      nested_messages->push_back(nested_desc);
 
1550
    }
 
1551
  }
 
1552
}
 
1553
 
 
1554
// Utility function for PrintFreeFieldNumbers.
 
1555
// Actually prints the formatted free field numbers for given message name and
 
1556
// occupied ranges.
 
1557
void FormatFreeFieldNumbers(const string& name,
 
1558
                            const set<FieldRange>& ranges) {
 
1559
  string output;
 
1560
  StringAppendF(&output, "%-35s free:", name.c_str());
 
1561
  int next_free_number = 1;
 
1562
  for (set<FieldRange>::iterator i = ranges.begin();
 
1563
       i != ranges.end(); ++i) {
 
1564
    // This happens when groups re-use parent field numbers, in which
 
1565
    // case we skip the FieldRange entirely.
 
1566
    if (next_free_number >= i->second) continue;
 
1567
 
 
1568
    if (next_free_number < i->first) {
 
1569
      if (next_free_number + 1 == i->first) {
 
1570
        // Singleton
 
1571
        StringAppendF(&output, " %d", next_free_number);
 
1572
      } else {
 
1573
        // Range
 
1574
        StringAppendF(&output, " %d-%d", next_free_number, i->first - 1);
 
1575
      }
 
1576
    }
 
1577
    next_free_number = i->second;
 
1578
  }
 
1579
  if (next_free_number <= FieldDescriptor::kMaxNumber) {
 
1580
    StringAppendF(&output, " %d-INF", next_free_number);
 
1581
  }
 
1582
  cout << output << endl;
 
1583
}
 
1584
 
 
1585
}  // namespace
 
1586
 
 
1587
void CommandLineInterface::PrintFreeFieldNumbers(
 
1588
    const Descriptor* descriptor) {
 
1589
  set<FieldRange> ranges;
 
1590
  vector<const Descriptor*> nested_messages;
 
1591
  GatherOccupiedFieldRanges(descriptor, &ranges, &nested_messages);
 
1592
 
 
1593
  for (int i = 0; i < nested_messages.size(); ++i) {
 
1594
    PrintFreeFieldNumbers(nested_messages[i]);
 
1595
  }
 
1596
  FormatFreeFieldNumbers(descriptor->full_name(), ranges);
 
1597
}
 
1598
 
 
1599
 
1434
1600
 
1435
1601
}  // namespace compiler
1436
1602
}  // namespace protobuf