command_line_interface.cc 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // https://developers.google.com/protocol-buffers/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. // Author: kenton@google.com (Kenton Varda)
  31. // Based on original Protocol Buffers design by
  32. // Sanjay Ghemawat, Jeff Dean, and others.
  33. #include <google/protobuf/compiler/command_line_interface.h>
  34. #include <stdio.h>
  35. #include <sys/types.h>
  36. #include <sys/stat.h>
  37. #include <fcntl.h>
  38. #ifdef _MSC_VER
  39. #include <io.h>
  40. #include <direct.h>
  41. #else
  42. #include <unistd.h>
  43. #endif
  44. #include <errno.h>
  45. #include <iostream>
  46. #include <sstream>
  47. #include <ctype.h>
  48. #include <google/protobuf/stubs/hash.h>
  49. #include <memory>
  50. #ifndef _SHARED_PTR_H
  51. #include <google/protobuf/stubs/shared_ptr.h>
  52. #endif
  53. #include <google/protobuf/stubs/common.h>
  54. #include <google/protobuf/stubs/stringprintf.h>
  55. #include <google/protobuf/compiler/importer.h>
  56. #include <google/protobuf/compiler/code_generator.h>
  57. #include <google/protobuf/compiler/plugin.pb.h>
  58. #include <google/protobuf/compiler/subprocess.h>
  59. #include <google/protobuf/compiler/zip_writer.h>
  60. #include <google/protobuf/descriptor.h>
  61. #include <google/protobuf/text_format.h>
  62. #include <google/protobuf/dynamic_message.h>
  63. #include <google/protobuf/io/coded_stream.h>
  64. #include <google/protobuf/io/zero_copy_stream_impl.h>
  65. #include <google/protobuf/io/printer.h>
  66. #include <google/protobuf/stubs/strutil.h>
  67. #include <google/protobuf/stubs/substitute.h>
  68. #include <google/protobuf/stubs/map_util.h>
  69. #include <google/protobuf/stubs/stl_util.h>
  70. namespace google {
  71. namespace protobuf {
  72. namespace compiler {
  73. #if defined(_WIN32)
  74. #define mkdir(name, mode) mkdir(name)
  75. #ifndef W_OK
  76. #define W_OK 02 // not defined by MSVC for whatever reason
  77. #endif
  78. #ifndef F_OK
  79. #define F_OK 00 // not defined by MSVC for whatever reason
  80. #endif
  81. #ifndef STDIN_FILENO
  82. #define STDIN_FILENO 0
  83. #endif
  84. #ifndef STDOUT_FILENO
  85. #define STDOUT_FILENO 1
  86. #endif
  87. #endif
  88. #ifndef O_BINARY
  89. #ifdef _O_BINARY
  90. #define O_BINARY _O_BINARY
  91. #else
  92. #define O_BINARY 0 // If this isn't defined, the platform doesn't need it.
  93. #endif
  94. #endif
  95. namespace {
  96. #if defined(_WIN32) && !defined(__CYGWIN__)
  97. static const char* kPathSeparator = ";";
  98. #else
  99. static const char* kPathSeparator = ":";
  100. #endif
  101. // Returns true if the text looks like a Windows-style absolute path, starting
  102. // with a drive letter. Example: "C:\foo". TODO(kenton): Share this with
  103. // copy in importer.cc?
  104. static bool IsWindowsAbsolutePath(const string& text) {
  105. #if defined(_WIN32) || defined(__CYGWIN__)
  106. return text.size() >= 3 && text[1] == ':' &&
  107. isalpha(text[0]) &&
  108. (text[2] == '/' || text[2] == '\\') &&
  109. text.find_last_of(':') == 1;
  110. #else
  111. return false;
  112. #endif
  113. }
  114. void SetFdToTextMode(int fd) {
  115. #ifdef _WIN32
  116. if (_setmode(fd, _O_TEXT) == -1) {
  117. // This should never happen, I think.
  118. GOOGLE_LOG(WARNING) << "_setmode(" << fd << ", _O_TEXT): " << strerror(errno);
  119. }
  120. #endif
  121. // (Text and binary are the same on non-Windows platforms.)
  122. }
  123. void SetFdToBinaryMode(int fd) {
  124. #ifdef _WIN32
  125. if (_setmode(fd, _O_BINARY) == -1) {
  126. // This should never happen, I think.
  127. GOOGLE_LOG(WARNING) << "_setmode(" << fd << ", _O_BINARY): " << strerror(errno);
  128. }
  129. #endif
  130. // (Text and binary are the same on non-Windows platforms.)
  131. }
  132. void AddTrailingSlash(string* path) {
  133. if (!path->empty() && path->at(path->size() - 1) != '/') {
  134. path->push_back('/');
  135. }
  136. }
  137. bool VerifyDirectoryExists(const string& path) {
  138. if (path.empty()) return true;
  139. if (access(path.c_str(), F_OK) == -1) {
  140. cerr << path << ": " << strerror(errno) << endl;
  141. return false;
  142. } else {
  143. return true;
  144. }
  145. }
  146. // Try to create the parent directory of the given file, creating the parent's
  147. // parent if necessary, and so on. The full file name is actually
  148. // (prefix + filename), but we assume |prefix| already exists and only create
  149. // directories listed in |filename|.
  150. bool TryCreateParentDirectory(const string& prefix, const string& filename) {
  151. // Recursively create parent directories to the output file.
  152. vector<string> parts = Split(filename, "/", true);
  153. string path_so_far = prefix;
  154. for (int i = 0; i < parts.size() - 1; i++) {
  155. path_so_far += parts[i];
  156. if (mkdir(path_so_far.c_str(), 0777) != 0) {
  157. if (errno != EEXIST) {
  158. cerr << filename << ": while trying to create directory "
  159. << path_so_far << ": " << strerror(errno) << endl;
  160. return false;
  161. }
  162. }
  163. path_so_far += '/';
  164. }
  165. return true;
  166. }
  167. } // namespace
  168. // A MultiFileErrorCollector that prints errors to stderr.
  169. class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector,
  170. public io::ErrorCollector {
  171. public:
  172. ErrorPrinter(ErrorFormat format, DiskSourceTree *tree = NULL)
  173. : format_(format), tree_(tree) {}
  174. ~ErrorPrinter() {}
  175. // implements MultiFileErrorCollector ------------------------------
  176. void AddError(const string& filename, int line, int column,
  177. const string& message) {
  178. // Print full path when running under MSVS
  179. string dfile;
  180. if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS &&
  181. tree_ != NULL &&
  182. tree_->VirtualFileToDiskFile(filename, &dfile)) {
  183. cerr << dfile;
  184. } else {
  185. cerr << filename;
  186. }
  187. // Users typically expect 1-based line/column numbers, so we add 1
  188. // to each here.
  189. if (line != -1) {
  190. // Allow for both GCC- and Visual-Studio-compatible output.
  191. switch (format_) {
  192. case CommandLineInterface::ERROR_FORMAT_GCC:
  193. cerr << ":" << (line + 1) << ":" << (column + 1);
  194. break;
  195. case CommandLineInterface::ERROR_FORMAT_MSVS:
  196. cerr << "(" << (line + 1) << ") : error in column=" << (column + 1);
  197. break;
  198. }
  199. }
  200. cerr << ": " << message << endl;
  201. }
  202. // implements io::ErrorCollector -----------------------------------
  203. void AddError(int line, int column, const string& message) {
  204. AddError("input", line, column, message);
  205. }
  206. private:
  207. const ErrorFormat format_;
  208. DiskSourceTree *tree_;
  209. };
  210. // -------------------------------------------------------------------
  211. // A GeneratorContext implementation that buffers files in memory, then dumps
  212. // them all to disk on demand.
  213. class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
  214. public:
  215. GeneratorContextImpl(const vector<const FileDescriptor*>& parsed_files);
  216. ~GeneratorContextImpl();
  217. // Write all files in the directory to disk at the given output location,
  218. // which must end in a '/'.
  219. bool WriteAllToDisk(const string& prefix);
  220. // Write the contents of this directory to a ZIP-format archive with the
  221. // given name.
  222. bool WriteAllToZip(const string& filename);
  223. // Add a boilerplate META-INF/MANIFEST.MF file as required by the Java JAR
  224. // format, unless one has already been written.
  225. void AddJarManifest();
  226. // implements GeneratorContext --------------------------------------
  227. io::ZeroCopyOutputStream* Open(const string& filename);
  228. io::ZeroCopyOutputStream* OpenForAppend(const string& filename);
  229. io::ZeroCopyOutputStream* OpenForInsert(
  230. const string& filename, const string& insertion_point);
  231. void ListParsedFiles(vector<const FileDescriptor*>* output) {
  232. *output = parsed_files_;
  233. }
  234. private:
  235. friend class MemoryOutputStream;
  236. // map instead of hash_map so that files are written in order (good when
  237. // writing zips).
  238. map<string, string*> files_;
  239. const vector<const FileDescriptor*>& parsed_files_;
  240. bool had_error_;
  241. };
  242. class CommandLineInterface::MemoryOutputStream
  243. : public io::ZeroCopyOutputStream {
  244. public:
  245. MemoryOutputStream(GeneratorContextImpl* directory, const string& filename,
  246. bool append_mode);
  247. MemoryOutputStream(GeneratorContextImpl* directory, const string& filename,
  248. const string& insertion_point);
  249. virtual ~MemoryOutputStream();
  250. // implements ZeroCopyOutputStream ---------------------------------
  251. virtual bool Next(void** data, int* size) { return inner_->Next(data, size); }
  252. virtual void BackUp(int count) { inner_->BackUp(count); }
  253. virtual int64 ByteCount() const { return inner_->ByteCount(); }
  254. private:
  255. // Where to insert the string when it's done.
  256. GeneratorContextImpl* directory_;
  257. string filename_;
  258. string insertion_point_;
  259. // The string we're building.
  260. string data_;
  261. // Whether we should append the output stream to the existing file.
  262. bool append_mode_;
  263. // StringOutputStream writing to data_.
  264. google::protobuf::scoped_ptr<io::StringOutputStream> inner_;
  265. };
  266. // -------------------------------------------------------------------
  267. CommandLineInterface::GeneratorContextImpl::GeneratorContextImpl(
  268. const vector<const FileDescriptor*>& parsed_files)
  269. : parsed_files_(parsed_files),
  270. had_error_(false) {
  271. }
  272. CommandLineInterface::GeneratorContextImpl::~GeneratorContextImpl() {
  273. STLDeleteValues(&files_);
  274. }
  275. bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk(
  276. const string& prefix) {
  277. if (had_error_) {
  278. return false;
  279. }
  280. if (!VerifyDirectoryExists(prefix)) {
  281. return false;
  282. }
  283. for (map<string, string*>::const_iterator iter = files_.begin();
  284. iter != files_.end(); ++iter) {
  285. const string& relative_filename = iter->first;
  286. const char* data = iter->second->data();
  287. int size = iter->second->size();
  288. if (!TryCreateParentDirectory(prefix, relative_filename)) {
  289. return false;
  290. }
  291. string filename = prefix + relative_filename;
  292. // Create the output file.
  293. int file_descriptor;
  294. do {
  295. file_descriptor =
  296. open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
  297. } while (file_descriptor < 0 && errno == EINTR);
  298. if (file_descriptor < 0) {
  299. int error = errno;
  300. cerr << filename << ": " << strerror(error);
  301. return false;
  302. }
  303. // Write the file.
  304. while (size > 0) {
  305. int write_result;
  306. do {
  307. write_result = write(file_descriptor, data, size);
  308. } while (write_result < 0 && errno == EINTR);
  309. if (write_result <= 0) {
  310. // Write error.
  311. // FIXME(kenton): According to the man page, if write() returns zero,
  312. // there was no error; write() simply did not write anything. It's
  313. // unclear under what circumstances this might happen, but presumably
  314. // errno won't be set in this case. I am confused as to how such an
  315. // event should be handled. For now I'm treating it as an error,
  316. // since retrying seems like it could lead to an infinite loop. I
  317. // suspect this never actually happens anyway.
  318. if (write_result < 0) {
  319. int error = errno;
  320. cerr << filename << ": write: " << strerror(error);
  321. } else {
  322. cerr << filename << ": write() returned zero?" << endl;
  323. }
  324. return false;
  325. }
  326. data += write_result;
  327. size -= write_result;
  328. }
  329. if (close(file_descriptor) != 0) {
  330. int error = errno;
  331. cerr << filename << ": close: " << strerror(error);
  332. return false;
  333. }
  334. }
  335. return true;
  336. }
  337. bool CommandLineInterface::GeneratorContextImpl::WriteAllToZip(
  338. const string& filename) {
  339. if (had_error_) {
  340. return false;
  341. }
  342. // Create the output file.
  343. int file_descriptor;
  344. do {
  345. file_descriptor =
  346. open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
  347. } while (file_descriptor < 0 && errno == EINTR);
  348. if (file_descriptor < 0) {
  349. int error = errno;
  350. cerr << filename << ": " << strerror(error);
  351. return false;
  352. }
  353. // Create the ZipWriter
  354. io::FileOutputStream stream(file_descriptor);
  355. ZipWriter zip_writer(&stream);
  356. for (map<string, string*>::const_iterator iter = files_.begin();
  357. iter != files_.end(); ++iter) {
  358. zip_writer.Write(iter->first, *iter->second);
  359. }
  360. zip_writer.WriteDirectory();
  361. if (stream.GetErrno() != 0) {
  362. cerr << filename << ": " << strerror(stream.GetErrno()) << endl;
  363. }
  364. if (!stream.Close()) {
  365. cerr << filename << ": " << strerror(stream.GetErrno()) << endl;
  366. }
  367. return true;
  368. }
  369. void CommandLineInterface::GeneratorContextImpl::AddJarManifest() {
  370. string** map_slot = &files_["META-INF/MANIFEST.MF"];
  371. if (*map_slot == NULL) {
  372. *map_slot = new string(
  373. "Manifest-Version: 1.0\n"
  374. "Created-By: 1.6.0 (protoc)\n"
  375. "\n");
  376. }
  377. }
  378. io::ZeroCopyOutputStream* CommandLineInterface::GeneratorContextImpl::Open(
  379. const string& filename) {
  380. return new MemoryOutputStream(this, filename, false);
  381. }
  382. io::ZeroCopyOutputStream*
  383. CommandLineInterface::GeneratorContextImpl::OpenForAppend(
  384. const string& filename) {
  385. return new MemoryOutputStream(this, filename, true);
  386. }
  387. io::ZeroCopyOutputStream*
  388. CommandLineInterface::GeneratorContextImpl::OpenForInsert(
  389. const string& filename, const string& insertion_point) {
  390. return new MemoryOutputStream(this, filename, insertion_point);
  391. }
  392. // -------------------------------------------------------------------
  393. CommandLineInterface::MemoryOutputStream::MemoryOutputStream(
  394. GeneratorContextImpl* directory, const string& filename, bool append_mode)
  395. : directory_(directory),
  396. filename_(filename),
  397. append_mode_(append_mode),
  398. inner_(new io::StringOutputStream(&data_)) {
  399. }
  400. CommandLineInterface::MemoryOutputStream::MemoryOutputStream(
  401. GeneratorContextImpl* directory, const string& filename,
  402. const string& insertion_point)
  403. : directory_(directory),
  404. filename_(filename),
  405. insertion_point_(insertion_point),
  406. inner_(new io::StringOutputStream(&data_)) {
  407. }
  408. CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() {
  409. // Make sure all data has been written.
  410. inner_.reset();
  411. // Insert into the directory.
  412. string** map_slot = &directory_->files_[filename_];
  413. if (insertion_point_.empty()) {
  414. // This was just a regular Open().
  415. if (*map_slot != NULL) {
  416. if (append_mode_) {
  417. (*map_slot)->append(data_);
  418. } else {
  419. cerr << filename_ << ": Tried to write the same file twice." << endl;
  420. directory_->had_error_ = true;
  421. }
  422. return;
  423. }
  424. *map_slot = new string;
  425. (*map_slot)->swap(data_);
  426. } else {
  427. // This was an OpenForInsert().
  428. // If the data doens't end with a clean line break, add one.
  429. if (!data_.empty() && data_[data_.size() - 1] != '\n') {
  430. data_.push_back('\n');
  431. }
  432. // Find the file we are going to insert into.
  433. if (*map_slot == NULL) {
  434. cerr << filename_ << ": Tried to insert into file that doesn't exist."
  435. << endl;
  436. directory_->had_error_ = true;
  437. return;
  438. }
  439. string* target = *map_slot;
  440. // Find the insertion point.
  441. string magic_string = strings::Substitute(
  442. "@@protoc_insertion_point($0)", insertion_point_);
  443. string::size_type pos = target->find(magic_string);
  444. if (pos == string::npos) {
  445. cerr << filename_ << ": insertion point \"" << insertion_point_
  446. << "\" not found." << endl;
  447. directory_->had_error_ = true;
  448. return;
  449. }
  450. // Seek backwards to the beginning of the line, which is where we will
  451. // insert the data. Note that this has the effect of pushing the insertion
  452. // point down, so the data is inserted before it. This is intentional
  453. // because it means that multiple insertions at the same point will end
  454. // up in the expected order in the final output.
  455. pos = target->find_last_of('\n', pos);
  456. if (pos == string::npos) {
  457. // Insertion point is on the first line.
  458. pos = 0;
  459. } else {
  460. // Advance to character after '\n'.
  461. ++pos;
  462. }
  463. // Extract indent.
  464. string indent_(*target, pos, target->find_first_not_of(" \t", pos) - pos);
  465. if (indent_.empty()) {
  466. // No indent. This makes things easier.
  467. target->insert(pos, data_);
  468. } else {
  469. // Calculate how much space we need.
  470. int indent_size = 0;
  471. for (int i = 0; i < data_.size(); i++) {
  472. if (data_[i] == '\n') indent_size += indent_.size();
  473. }
  474. // Make a hole for it.
  475. target->insert(pos, data_.size() + indent_size, '\0');
  476. // Now copy in the data.
  477. string::size_type data_pos = 0;
  478. char* target_ptr = string_as_array(target) + pos;
  479. while (data_pos < data_.size()) {
  480. // Copy indent.
  481. memcpy(target_ptr, indent_.data(), indent_.size());
  482. target_ptr += indent_.size();
  483. // Copy line from data_.
  484. // We already guaranteed that data_ ends with a newline (above), so this
  485. // search can't fail.
  486. string::size_type line_length =
  487. data_.find_first_of('\n', data_pos) + 1 - data_pos;
  488. memcpy(target_ptr, data_.data() + data_pos, line_length);
  489. target_ptr += line_length;
  490. data_pos += line_length;
  491. }
  492. GOOGLE_CHECK_EQ(target_ptr,
  493. string_as_array(target) + pos + data_.size() + indent_size);
  494. }
  495. }
  496. }
  497. // ===================================================================
  498. CommandLineInterface::CommandLineInterface()
  499. : mode_(MODE_COMPILE),
  500. print_mode_(PRINT_NONE),
  501. error_format_(ERROR_FORMAT_GCC),
  502. imports_in_descriptor_set_(false),
  503. source_info_in_descriptor_set_(false),
  504. disallow_services_(false),
  505. inputs_are_proto_path_relative_(false) {}
  506. CommandLineInterface::~CommandLineInterface() {}
  507. void CommandLineInterface::RegisterGenerator(const string& flag_name,
  508. CodeGenerator* generator,
  509. const string& help_text) {
  510. GeneratorInfo info;
  511. info.flag_name = flag_name;
  512. info.generator = generator;
  513. info.help_text = help_text;
  514. generators_by_flag_name_[flag_name] = info;
  515. }
  516. void CommandLineInterface::RegisterGenerator(const string& flag_name,
  517. const string& option_flag_name,
  518. CodeGenerator* generator,
  519. const string& help_text) {
  520. GeneratorInfo info;
  521. info.flag_name = flag_name;
  522. info.option_flag_name = option_flag_name;
  523. info.generator = generator;
  524. info.help_text = help_text;
  525. generators_by_flag_name_[flag_name] = info;
  526. generators_by_option_name_[option_flag_name] = info;
  527. }
  528. void CommandLineInterface::AllowPlugins(const string& exe_name_prefix) {
  529. plugin_prefix_ = exe_name_prefix;
  530. }
  531. int CommandLineInterface::Run(int argc, const char* const argv[]) {
  532. Clear();
  533. switch (ParseArguments(argc, argv)) {
  534. case PARSE_ARGUMENT_DONE_AND_EXIT:
  535. return 0;
  536. case PARSE_ARGUMENT_FAIL:
  537. return 1;
  538. case PARSE_ARGUMENT_DONE_AND_CONTINUE:
  539. break;
  540. }
  541. // Set up the source tree.
  542. DiskSourceTree source_tree;
  543. for (int i = 0; i < proto_path_.size(); i++) {
  544. source_tree.MapPath(proto_path_[i].first, proto_path_[i].second);
  545. }
  546. // Map input files to virtual paths if necessary.
  547. if (!inputs_are_proto_path_relative_) {
  548. if (!MakeInputsBeProtoPathRelative(&source_tree)) {
  549. return 1;
  550. }
  551. }
  552. // Allocate the Importer.
  553. ErrorPrinter error_collector(error_format_, &source_tree);
  554. Importer importer(&source_tree, &error_collector);
  555. vector<const FileDescriptor*> parsed_files;
  556. // Parse each file.
  557. for (int i = 0; i < input_files_.size(); i++) {
  558. // Import the file.
  559. importer.AddUnusedImportTrackFile(input_files_[i]);
  560. const FileDescriptor* parsed_file = importer.Import(input_files_[i]);
  561. importer.ClearUnusedImportTrackFiles();
  562. if (parsed_file == NULL) return 1;
  563. parsed_files.push_back(parsed_file);
  564. // Enforce --disallow_services.
  565. if (disallow_services_ && parsed_file->service_count() > 0) {
  566. cerr << parsed_file->name() << ": This file contains services, but "
  567. "--disallow_services was used." << endl;
  568. return 1;
  569. }
  570. }
  571. // We construct a separate GeneratorContext for each output location. Note
  572. // that two code generators may output to the same location, in which case
  573. // they should share a single GeneratorContext so that OpenForInsert() works.
  574. typedef hash_map<string, GeneratorContextImpl*> GeneratorContextMap;
  575. GeneratorContextMap output_directories;
  576. // Generate output.
  577. if (mode_ == MODE_COMPILE) {
  578. for (int i = 0; i < output_directives_.size(); i++) {
  579. string output_location = output_directives_[i].output_location;
  580. if (!HasSuffixString(output_location, ".zip") &&
  581. !HasSuffixString(output_location, ".jar")) {
  582. AddTrailingSlash(&output_location);
  583. }
  584. GeneratorContextImpl** map_slot = &output_directories[output_location];
  585. if (*map_slot == NULL) {
  586. // First time we've seen this output location.
  587. *map_slot = new GeneratorContextImpl(parsed_files);
  588. }
  589. if (!GenerateOutput(parsed_files, output_directives_[i], *map_slot)) {
  590. STLDeleteValues(&output_directories);
  591. return 1;
  592. }
  593. }
  594. }
  595. // Write all output to disk.
  596. for (GeneratorContextMap::iterator iter = output_directories.begin();
  597. iter != output_directories.end(); ++iter) {
  598. const string& location = iter->first;
  599. GeneratorContextImpl* directory = iter->second;
  600. if (HasSuffixString(location, "/")) {
  601. if (!directory->WriteAllToDisk(location)) {
  602. STLDeleteValues(&output_directories);
  603. return 1;
  604. }
  605. } else {
  606. if (HasSuffixString(location, ".jar")) {
  607. directory->AddJarManifest();
  608. }
  609. if (!directory->WriteAllToZip(location)) {
  610. STLDeleteValues(&output_directories);
  611. return 1;
  612. }
  613. }
  614. }
  615. STLDeleteValues(&output_directories);
  616. if (!descriptor_set_name_.empty()) {
  617. if (!WriteDescriptorSet(parsed_files)) {
  618. return 1;
  619. }
  620. }
  621. if (!manifest_name_.empty()) {
  622. if (!GenerateDependencyManifestFile(parsed_files, &source_tree)) {
  623. return 1;
  624. }
  625. }
  626. if (mode_ == MODE_ENCODE || mode_ == MODE_DECODE) {
  627. if (codec_type_.empty()) {
  628. // HACK: Define an EmptyMessage type to use for decoding.
  629. DescriptorPool pool;
  630. FileDescriptorProto file;
  631. file.set_name("empty_message.proto");
  632. file.add_message_type()->set_name("EmptyMessage");
  633. GOOGLE_CHECK(pool.BuildFile(file) != NULL);
  634. codec_type_ = "EmptyMessage";
  635. if (!EncodeOrDecode(&pool)) {
  636. return 1;
  637. }
  638. } else {
  639. if (!EncodeOrDecode(importer.pool())) {
  640. return 1;
  641. }
  642. }
  643. }
  644. if (mode_ == MODE_PRINT) {
  645. switch (print_mode_) {
  646. case PRINT_FREE_FIELDS:
  647. for (int i = 0; i < parsed_files.size(); ++i) {
  648. const FileDescriptor* fd = parsed_files[i];
  649. for (int j = 0; j < fd->message_type_count(); ++j) {
  650. PrintFreeFieldNumbers(fd->message_type(j));
  651. }
  652. }
  653. break;
  654. case PRINT_NONE:
  655. GOOGLE_LOG(ERROR) << "If the code reaches here, it usually means a bug of "
  656. "flag parsing in the CommonadLineInterface.";
  657. return 1;
  658. // Do not add a default case.
  659. }
  660. }
  661. return 0;
  662. }
  663. void CommandLineInterface::Clear() {
  664. // Clear all members that are set by Run(). Note that we must not clear
  665. // members which are set by other methods before Run() is called.
  666. executable_name_.clear();
  667. proto_path_.clear();
  668. input_files_.clear();
  669. output_directives_.clear();
  670. codec_type_.clear();
  671. descriptor_set_name_.clear();
  672. manifest_name_.clear();
  673. mode_ = MODE_COMPILE;
  674. print_mode_ = PRINT_NONE;
  675. imports_in_descriptor_set_ = false;
  676. source_info_in_descriptor_set_ = false;
  677. disallow_services_ = false;
  678. }
  679. bool CommandLineInterface::MakeInputsBeProtoPathRelative(
  680. DiskSourceTree* source_tree) {
  681. for (int i = 0; i < input_files_.size(); i++) {
  682. string virtual_file, shadowing_disk_file;
  683. switch (source_tree->DiskFileToVirtualFile(
  684. input_files_[i], &virtual_file, &shadowing_disk_file)) {
  685. case DiskSourceTree::SUCCESS:
  686. input_files_[i] = virtual_file;
  687. break;
  688. case DiskSourceTree::SHADOWED:
  689. cerr << input_files_[i] << ": Input is shadowed in the --proto_path "
  690. "by \"" << shadowing_disk_file << "\". Either use the latter "
  691. "file as your input or reorder the --proto_path so that the "
  692. "former file's location comes first." << endl;
  693. return false;
  694. case DiskSourceTree::CANNOT_OPEN:
  695. cerr << input_files_[i] << ": " << strerror(errno) << endl;
  696. return false;
  697. case DiskSourceTree::NO_MAPPING:
  698. // First check if the file exists at all.
  699. if (access(input_files_[i].c_str(), F_OK) < 0) {
  700. // File does not even exist.
  701. cerr << input_files_[i] << ": " << strerror(ENOENT) << endl;
  702. } else {
  703. cerr << input_files_[i] << ": File does not reside within any path "
  704. "specified using --proto_path (or -I). You must specify a "
  705. "--proto_path which encompasses this file. Note that the "
  706. "proto_path must be an exact prefix of the .proto file "
  707. "names -- protoc is too dumb to figure out when two paths "
  708. "(e.g. absolute and relative) are equivalent (it's harder "
  709. "than you think)." << endl;
  710. }
  711. return false;
  712. }
  713. }
  714. return true;
  715. }
  716. CommandLineInterface::ParseArgumentStatus
  717. CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
  718. executable_name_ = argv[0];
  719. // Iterate through all arguments and parse them.
  720. for (int i = 1; i < argc; i++) {
  721. string name, value;
  722. if (ParseArgument(argv[i], &name, &value)) {
  723. // Returned true => Use the next argument as the flag value.
  724. if (i + 1 == argc || argv[i+1][0] == '-') {
  725. cerr << "Missing value for flag: " << name << endl;
  726. if (name == "--decode") {
  727. cerr << "To decode an unknown message, use --decode_raw." << endl;
  728. }
  729. return PARSE_ARGUMENT_FAIL;
  730. } else {
  731. ++i;
  732. value = argv[i];
  733. }
  734. }
  735. ParseArgumentStatus status = InterpretArgument(name, value);
  736. if (status != PARSE_ARGUMENT_DONE_AND_CONTINUE)
  737. return status;
  738. }
  739. // If no --proto_path was given, use the current working directory.
  740. if (proto_path_.empty()) {
  741. // Don't use make_pair as the old/default standard library on Solaris
  742. // doesn't support it without explicit template parameters, which are
  743. // incompatible with C++0x's make_pair.
  744. proto_path_.push_back(pair<string, string>("", "."));
  745. }
  746. // Check some errror cases.
  747. bool decoding_raw = (mode_ == MODE_DECODE) && codec_type_.empty();
  748. if (decoding_raw && !input_files_.empty()) {
  749. cerr << "When using --decode_raw, no input files should be given." << endl;
  750. return PARSE_ARGUMENT_FAIL;
  751. } else if (!decoding_raw && input_files_.empty()) {
  752. cerr << "Missing input file." << endl;
  753. return PARSE_ARGUMENT_FAIL;
  754. }
  755. if (mode_ == MODE_COMPILE && output_directives_.empty() &&
  756. descriptor_set_name_.empty()) {
  757. cerr << "Missing output directives." << endl;
  758. return PARSE_ARGUMENT_FAIL;
  759. }
  760. if (imports_in_descriptor_set_ && descriptor_set_name_.empty()) {
  761. cerr << "--include_imports only makes sense when combined with "
  762. "--descriptor_set_out." << endl;
  763. }
  764. if (source_info_in_descriptor_set_ && descriptor_set_name_.empty()) {
  765. cerr << "--include_source_info only makes sense when combined with "
  766. "--descriptor_set_out." << endl;
  767. }
  768. return PARSE_ARGUMENT_DONE_AND_CONTINUE;
  769. }
  770. bool CommandLineInterface::ParseArgument(const char* arg,
  771. string* name, string* value) {
  772. bool parsed_value = false;
  773. if (arg[0] != '-') {
  774. // Not a flag.
  775. name->clear();
  776. parsed_value = true;
  777. *value = arg;
  778. } else if (arg[1] == '-') {
  779. // Two dashes: Multi-character name, with '=' separating name and
  780. // value.
  781. const char* equals_pos = strchr(arg, '=');
  782. if (equals_pos != NULL) {
  783. *name = string(arg, equals_pos - arg);
  784. *value = equals_pos + 1;
  785. parsed_value = true;
  786. } else {
  787. *name = arg;
  788. }
  789. } else {
  790. // One dash: One-character name, all subsequent characters are the
  791. // value.
  792. if (arg[1] == '\0') {
  793. // arg is just "-". We treat this as an input file, except that at
  794. // present this will just lead to a "file not found" error.
  795. name->clear();
  796. *value = arg;
  797. parsed_value = true;
  798. } else {
  799. *name = string(arg, 2);
  800. *value = arg + 2;
  801. parsed_value = !value->empty();
  802. }
  803. }
  804. // Need to return true iff the next arg should be used as the value for this
  805. // one, false otherwise.
  806. if (parsed_value) {
  807. // We already parsed a value for this flag.
  808. return false;
  809. }
  810. if (*name == "-h" || *name == "--help" ||
  811. *name == "--disallow_services" ||
  812. *name == "--include_imports" ||
  813. *name == "--include_source_info" ||
  814. *name == "--version" ||
  815. *name == "--decode_raw" ||
  816. *name == "--print_free_field_numbers") {
  817. // HACK: These are the only flags that don't take a value.
  818. // They probably should not be hard-coded like this but for now it's
  819. // not worth doing better.
  820. return false;
  821. }
  822. // Next argument is the flag value.
  823. return true;
  824. }
  825. CommandLineInterface::ParseArgumentStatus
  826. CommandLineInterface::InterpretArgument(const string& name,
  827. const string& value) {
  828. if (name.empty()) {
  829. // Not a flag. Just a filename.
  830. if (value.empty()) {
  831. cerr << "You seem to have passed an empty string as one of the "
  832. "arguments to " << executable_name_ << ". This is actually "
  833. "sort of hard to do. Congrats. Unfortunately it is not valid "
  834. "input so the program is going to die now." << endl;
  835. return PARSE_ARGUMENT_FAIL;
  836. }
  837. input_files_.push_back(value);
  838. } else if (name == "-I" || name == "--proto_path") {
  839. // Java's -classpath (and some other languages) delimits path components
  840. // with colons. Let's accept that syntax too just to make things more
  841. // intuitive.
  842. vector<string> parts = Split(
  843. value, kPathSeparator, true);
  844. for (int i = 0; i < parts.size(); i++) {
  845. string virtual_path;
  846. string disk_path;
  847. string::size_type equals_pos = parts[i].find_first_of('=');
  848. if (equals_pos == string::npos) {
  849. virtual_path = "";
  850. disk_path = parts[i];
  851. } else {
  852. virtual_path = parts[i].substr(0, equals_pos);
  853. disk_path = parts[i].substr(equals_pos + 1);
  854. }
  855. if (disk_path.empty()) {
  856. cerr << "--proto_path passed empty directory name. (Use \".\" for "
  857. "current directory.)" << endl;
  858. return PARSE_ARGUMENT_FAIL;
  859. }
  860. // Make sure disk path exists, warn otherwise.
  861. if (access(disk_path.c_str(), F_OK) < 0) {
  862. cerr << disk_path << ": warning: directory does not exist." << endl;
  863. }
  864. // Don't use make_pair as the old/default standard library on Solaris
  865. // doesn't support it without explicit template parameters, which are
  866. // incompatible with C++0x's make_pair.
  867. proto_path_.push_back(pair<string, string>(virtual_path, disk_path));
  868. }
  869. } else if (name == "-o" || name == "--descriptor_set_out") {
  870. if (!descriptor_set_name_.empty()) {
  871. cerr << name << " may only be passed once." << endl;
  872. return PARSE_ARGUMENT_FAIL;
  873. }
  874. if (value.empty()) {
  875. cerr << name << " requires a non-empty value." << endl;
  876. return PARSE_ARGUMENT_FAIL;
  877. }
  878. if (mode_ != MODE_COMPILE) {
  879. cerr << "Cannot use --encode or --decode and generate descriptors at the "
  880. "same time." << endl;
  881. return PARSE_ARGUMENT_FAIL;
  882. }
  883. descriptor_set_name_ = value;
  884. } else if (name == "--manifest-file") {
  885. if (!manifest_name_.empty()) {
  886. cerr << name << " may only be passed once." << endl;
  887. return PARSE_ARGUMENT_FAIL;
  888. }
  889. if (value.empty()) {
  890. cerr << name << " requires a non-empty value." << endl;
  891. return PARSE_ARGUMENT_FAIL;
  892. }
  893. if (mode_ != MODE_COMPILE) {
  894. cerr << "Cannot use --encode or --decode and generate a manifest at the "
  895. "same time." << endl;
  896. return PARSE_ARGUMENT_FAIL;
  897. }
  898. manifest_name_ = value;
  899. } else if (name == "--include_imports") {
  900. if (imports_in_descriptor_set_) {
  901. cerr << name << " may only be passed once." << endl;
  902. return PARSE_ARGUMENT_FAIL;
  903. }
  904. imports_in_descriptor_set_ = true;
  905. } else if (name == "--include_source_info") {
  906. if (source_info_in_descriptor_set_) {
  907. cerr << name << " may only be passed once." << endl;
  908. return PARSE_ARGUMENT_FAIL;
  909. }
  910. source_info_in_descriptor_set_ = true;
  911. } else if (name == "-h" || name == "--help") {
  912. PrintHelpText();
  913. return PARSE_ARGUMENT_DONE_AND_EXIT; // Exit without running compiler.
  914. } else if (name == "--version") {
  915. if (!version_info_.empty()) {
  916. cout << version_info_ << endl;
  917. }
  918. cout << "libprotoc "
  919. << protobuf::internal::VersionString(GOOGLE_PROTOBUF_VERSION)
  920. << endl;
  921. return PARSE_ARGUMENT_DONE_AND_EXIT; // Exit without running compiler.
  922. } else if (name == "--disallow_services") {
  923. disallow_services_ = true;
  924. } else if (name == "--encode" || name == "--decode" ||
  925. name == "--decode_raw") {
  926. if (mode_ != MODE_COMPILE) {
  927. cerr << "Only one of --encode and --decode can be specified." << endl;
  928. return PARSE_ARGUMENT_FAIL;
  929. }
  930. if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
  931. cerr << "Cannot use " << name
  932. << " and generate code or descriptors at the same time." << endl;
  933. return PARSE_ARGUMENT_FAIL;
  934. }
  935. mode_ = (name == "--encode") ? MODE_ENCODE : MODE_DECODE;
  936. if (value.empty() && name != "--decode_raw") {
  937. cerr << "Type name for " << name << " cannot be blank." << endl;
  938. if (name == "--decode") {
  939. cerr << "To decode an unknown message, use --decode_raw." << endl;
  940. }
  941. return PARSE_ARGUMENT_FAIL;
  942. } else if (!value.empty() && name == "--decode_raw") {
  943. cerr << "--decode_raw does not take a parameter." << endl;
  944. return PARSE_ARGUMENT_FAIL;
  945. }
  946. codec_type_ = value;
  947. } else if (name == "--error_format") {
  948. if (value == "gcc") {
  949. error_format_ = ERROR_FORMAT_GCC;
  950. } else if (value == "msvs") {
  951. error_format_ = ERROR_FORMAT_MSVS;
  952. } else {
  953. cerr << "Unknown error format: " << value << endl;
  954. return PARSE_ARGUMENT_FAIL;
  955. }
  956. } else if (name == "--plugin") {
  957. if (plugin_prefix_.empty()) {
  958. cerr << "This compiler does not support plugins." << endl;
  959. return PARSE_ARGUMENT_FAIL;
  960. }
  961. string plugin_name;
  962. string path;
  963. string::size_type equals_pos = value.find_first_of('=');
  964. if (equals_pos == string::npos) {
  965. // Use the basename of the file.
  966. string::size_type slash_pos = value.find_last_of('/');
  967. if (slash_pos == string::npos) {
  968. plugin_name = value;
  969. } else {
  970. plugin_name = value.substr(slash_pos + 1);
  971. }
  972. path = value;
  973. } else {
  974. plugin_name = value.substr(0, equals_pos);
  975. path = value.substr(equals_pos + 1);
  976. }
  977. plugins_[plugin_name] = path;
  978. } else if (name == "--print_free_field_numbers") {
  979. if (mode_ != MODE_COMPILE) {
  980. cerr << "Cannot use " << name << " and use --encode, --decode or print "
  981. << "other info at the same time." << endl;
  982. return PARSE_ARGUMENT_FAIL;
  983. }
  984. if (!output_directives_.empty() || !descriptor_set_name_.empty()) {
  985. cerr << "Cannot use " << name
  986. << " and generate code or descriptors at the same time." << endl;
  987. return PARSE_ARGUMENT_FAIL;
  988. }
  989. mode_ = MODE_PRINT;
  990. print_mode_ = PRINT_FREE_FIELDS;
  991. } else {
  992. // Some other flag. Look it up in the generators list.
  993. const GeneratorInfo* generator_info =
  994. FindOrNull(generators_by_flag_name_, name);
  995. if (generator_info == NULL &&
  996. (plugin_prefix_.empty() || !HasSuffixString(name, "_out"))) {
  997. // Check if it's a generator option flag.
  998. generator_info = FindOrNull(generators_by_option_name_, name);
  999. if (generator_info == NULL) {
  1000. cerr << "Unknown flag: " << name << endl;
  1001. return PARSE_ARGUMENT_FAIL;
  1002. } else {
  1003. string* parameters = &generator_parameters_[generator_info->flag_name];
  1004. if (!parameters->empty()) {
  1005. parameters->append(",");
  1006. }
  1007. parameters->append(value);
  1008. }
  1009. } else {
  1010. // It's an output flag. Add it to the output directives.
  1011. if (mode_ != MODE_COMPILE) {
  1012. cerr << "Cannot use --encode, --decode or print .proto info and "
  1013. "generate code at the same time." << endl;
  1014. return PARSE_ARGUMENT_FAIL;
  1015. }
  1016. OutputDirective directive;
  1017. directive.name = name;
  1018. if (generator_info == NULL) {
  1019. directive.generator = NULL;
  1020. } else {
  1021. directive.generator = generator_info->generator;
  1022. }
  1023. // Split value at ':' to separate the generator parameter from the
  1024. // filename. However, avoid doing this if the colon is part of a valid
  1025. // Windows-style absolute path.
  1026. string::size_type colon_pos = value.find_first_of(':');
  1027. if (colon_pos == string::npos || IsWindowsAbsolutePath(value)) {
  1028. directive.output_location = value;
  1029. } else {
  1030. directive.parameter = value.substr(0, colon_pos);
  1031. directive.output_location = value.substr(colon_pos + 1);
  1032. }
  1033. output_directives_.push_back(directive);
  1034. }
  1035. }
  1036. return PARSE_ARGUMENT_DONE_AND_CONTINUE;
  1037. }
  1038. void CommandLineInterface::PrintHelpText() {
  1039. // Sorry for indentation here; line wrapping would be uglier.
  1040. cerr <<
  1041. "Usage: " << executable_name_ << " [OPTION] PROTO_FILES\n"
  1042. "Parse PROTO_FILES and generate output based on the options given:\n"
  1043. " -IPATH, --proto_path=PATH Specify the directory in which to search for\n"
  1044. " imports. May be specified multiple times;\n"
  1045. " directories will be searched in order. If not\n"
  1046. " given, the current working directory is used.\n"
  1047. " --version Show version info and exit.\n"
  1048. " -h, --help Show this text and exit.\n"
  1049. " --encode=MESSAGE_TYPE Read a text-format message of the given type\n"
  1050. " from standard input and write it in binary\n"
  1051. " to standard output. The message type must\n"
  1052. " be defined in PROTO_FILES or their imports.\n"
  1053. " --decode=MESSAGE_TYPE Read a binary message of the given type from\n"
  1054. " standard input and write it in text format\n"
  1055. " to standard output. The message type must\n"
  1056. " be defined in PROTO_FILES or their imports.\n"
  1057. " --decode_raw Read an arbitrary protocol message from\n"
  1058. " standard input and write the raw tag/value\n"
  1059. " pairs in text format to standard output. No\n"
  1060. " PROTO_FILES should be given when using this\n"
  1061. " flag.\n"
  1062. " -oFILE, Writes a FileDescriptorSet (a protocol buffer,\n"
  1063. " --descriptor_set_out=FILE defined in descriptor.proto) containing all of\n"
  1064. " the input files to FILE.\n"
  1065. " --include_imports When using --descriptor_set_out, also include\n"
  1066. " all dependencies of the input files in the\n"
  1067. " set, so that the set is self-contained.\n"
  1068. " --include_source_info When using --descriptor_set_out, do not strip\n"
  1069. " SourceCodeInfo from the FileDescriptorProto.\n"
  1070. " This results in vastly larger descriptors that\n"
  1071. " include information about the original\n"
  1072. " location of each decl in the source file as\n"
  1073. " well as surrounding comments.\n"
  1074. " --manifest_file=FILE Write a dependency output file in the format\n"
  1075. " expected by make. This writes the transitive\n"
  1076. " set of input file paths to FILE\n"
  1077. " --error_format=FORMAT Set the format in which to print errors.\n"
  1078. " FORMAT may be 'gcc' (the default) or 'msvs'\n"
  1079. " (Microsoft Visual Studio format).\n"
  1080. " --print_free_field_numbers Print the free field numbers of the messages\n"
  1081. " defined in the given proto files. Groups share\n"
  1082. " the same field number space with the parent \n"
  1083. " message. Extension ranges are counted as \n"
  1084. " occupied fields numbers." << endl;
  1085. if (!plugin_prefix_.empty()) {
  1086. cerr <<
  1087. " --plugin=EXECUTABLE Specifies a plugin executable to use.\n"
  1088. " Normally, protoc searches the PATH for\n"
  1089. " plugins, but you may specify additional\n"
  1090. " executables not in the path using this flag.\n"
  1091. " Additionally, EXECUTABLE may be of the form\n"
  1092. " NAME=PATH, in which case the given plugin name\n"
  1093. " is mapped to the given executable even if\n"
  1094. " the executable's own name differs." << endl;
  1095. }
  1096. for (GeneratorMap::iterator iter = generators_by_flag_name_.begin();
  1097. iter != generators_by_flag_name_.end(); ++iter) {
  1098. // FIXME(kenton): If the text is long enough it will wrap, which is ugly,
  1099. // but fixing this nicely (e.g. splitting on spaces) is probably more
  1100. // trouble than it's worth.
  1101. cerr << " " << iter->first << "=OUT_DIR "
  1102. << string(19 - iter->first.size(), ' ') // Spaces for alignment.
  1103. << iter->second.help_text << endl;
  1104. }
  1105. }
  1106. bool CommandLineInterface::GenerateOutput(
  1107. const vector<const FileDescriptor*>& parsed_files,
  1108. const OutputDirective& output_directive,
  1109. GeneratorContext* generator_context) {
  1110. // Call the generator.
  1111. string error;
  1112. if (output_directive.generator == NULL) {
  1113. // This is a plugin.
  1114. GOOGLE_CHECK(HasPrefixString(output_directive.name, "--") &&
  1115. HasSuffixString(output_directive.name, "_out"))
  1116. << "Bad name for plugin generator: " << output_directive.name;
  1117. // Strip the "--" and "_out" and add the plugin prefix.
  1118. string plugin_name = plugin_prefix_ + "gen-" +
  1119. output_directive.name.substr(2, output_directive.name.size() - 6);
  1120. if (!GeneratePluginOutput(parsed_files, plugin_name,
  1121. output_directive.parameter,
  1122. generator_context, &error)) {
  1123. cerr << output_directive.name << ": " << error << endl;
  1124. return false;
  1125. }
  1126. } else {
  1127. // Regular generator.
  1128. string parameters = output_directive.parameter;
  1129. if (!generator_parameters_[output_directive.name].empty()) {
  1130. if (!parameters.empty()) {
  1131. parameters.append(",");
  1132. }
  1133. parameters.append(generator_parameters_[output_directive.name]);
  1134. }
  1135. for (int i = 0; i < parsed_files.size(); i++) {
  1136. if (!output_directive.generator->Generate(parsed_files[i], parameters,
  1137. generator_context, &error)) {
  1138. // Generator returned an error.
  1139. cerr << output_directive.name << ": " << parsed_files[i]->name() << ": "
  1140. << error << endl;
  1141. return false;
  1142. }
  1143. }
  1144. }
  1145. return true;
  1146. }
  1147. bool CommandLineInterface::GenerateDependencyManifestFile(
  1148. const vector<const FileDescriptor*> parsed_files,
  1149. DiskSourceTree * source_tree) {
  1150. FileDescriptorSet file_set;
  1151. set<const FileDescriptor*> already_seen;
  1152. for (int i = 0; i < parsed_files.size(); i++) {
  1153. GetTransitiveDependencies(parsed_files[i],
  1154. false,
  1155. &already_seen, file_set.mutable_file());
  1156. }
  1157. int fd;
  1158. do {
  1159. fd = open(manifest_name_.c_str(),
  1160. O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
  1161. } while (fd < 0 && errno == EINTR);
  1162. if (fd < 0) {
  1163. perror(manifest_name_.c_str());
  1164. return false;
  1165. }
  1166. stringstream ss;
  1167. string output_filename = manifest_name_;
  1168. if (output_filename.compare(0, 2, "./") == 0) {
  1169. output_filename = output_filename.substr(2);
  1170. }
  1171. ss << output_filename << ": ";
  1172. for (set<const FileDescriptor*>::const_iterator it = already_seen.begin(); it != already_seen.end(); ++it ) {
  1173. string virtual_file = (*it)->name();
  1174. string disk_file;
  1175. if (source_tree && source_tree->VirtualFileToDiskFile(virtual_file, &disk_file) ) {
  1176. ss << " " << disk_file << " \\" << endl;
  1177. } else {
  1178. cerr << "Unable to identify path for file " << virtual_file << endl;
  1179. return false;
  1180. }
  1181. }
  1182. string manifest_contents = ss.str();
  1183. if ( write(fd, manifest_contents.c_str(), manifest_contents.size()) != manifest_contents.size() ) {
  1184. cerr << "Error when writing to " << manifest_name_ << endl;
  1185. return false;
  1186. }
  1187. int rv = ::close(fd);
  1188. if ( rv != 0 ) {
  1189. cerr << manifest_name_ << ": " << strerror(rv) << endl;
  1190. return false;
  1191. }
  1192. return true;
  1193. }
  1194. bool CommandLineInterface::GeneratePluginOutput(
  1195. const vector<const FileDescriptor*>& parsed_files,
  1196. const string& plugin_name,
  1197. const string& parameter,
  1198. GeneratorContext* generator_context,
  1199. string* error) {
  1200. CodeGeneratorRequest request;
  1201. CodeGeneratorResponse response;
  1202. // Build the request.
  1203. if (!parameter.empty()) {
  1204. request.set_parameter(parameter);
  1205. }
  1206. set<const FileDescriptor*> already_seen;
  1207. for (int i = 0; i < parsed_files.size(); i++) {
  1208. request.add_file_to_generate(parsed_files[i]->name());
  1209. GetTransitiveDependencies(parsed_files[i],
  1210. true, // Include source code info.
  1211. &already_seen, request.mutable_proto_file());
  1212. }
  1213. // Invoke the plugin.
  1214. Subprocess subprocess;
  1215. if (plugins_.count(plugin_name) > 0) {
  1216. subprocess.Start(plugins_[plugin_name], Subprocess::EXACT_NAME);
  1217. } else {
  1218. subprocess.Start(plugin_name, Subprocess::SEARCH_PATH);
  1219. }
  1220. string communicate_error;
  1221. if (!subprocess.Communicate(request, &response, &communicate_error)) {
  1222. *error = strings::Substitute("$0: $1", plugin_name, communicate_error);
  1223. return false;
  1224. }
  1225. // Write the files. We do this even if there was a generator error in order
  1226. // to match the behavior of a compiled-in generator.
  1227. google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> current_output;
  1228. for (int i = 0; i < response.file_size(); i++) {
  1229. const CodeGeneratorResponse::File& output_file = response.file(i);
  1230. if (!output_file.insertion_point().empty()) {
  1231. // Open a file for insert.
  1232. // We reset current_output to NULL first so that the old file is closed
  1233. // before the new one is opened.
  1234. current_output.reset();
  1235. current_output.reset(generator_context->OpenForInsert(
  1236. output_file.name(), output_file.insertion_point()));
  1237. } else if (!output_file.name().empty()) {
  1238. // Starting a new file. Open it.
  1239. // We reset current_output to NULL first so that the old file is closed
  1240. // before the new one is opened.
  1241. current_output.reset();
  1242. current_output.reset(generator_context->Open(output_file.name()));
  1243. } else if (current_output == NULL) {
  1244. *error = strings::Substitute(
  1245. "$0: First file chunk returned by plugin did not specify a file name.",
  1246. plugin_name);
  1247. return false;
  1248. }
  1249. // Use CodedOutputStream for convenience; otherwise we'd need to provide
  1250. // our own buffer-copying loop.
  1251. io::CodedOutputStream writer(current_output.get());
  1252. writer.WriteString(output_file.content());
  1253. }
  1254. // Check for errors.
  1255. if (!response.error().empty()) {
  1256. // Generator returned an error.
  1257. *error = response.error();
  1258. return false;
  1259. }
  1260. return true;
  1261. }
  1262. bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) {
  1263. // Look up the type.
  1264. const Descriptor* type = pool->FindMessageTypeByName(codec_type_);
  1265. if (type == NULL) {
  1266. cerr << "Type not defined: " << codec_type_ << endl;
  1267. return false;
  1268. }
  1269. DynamicMessageFactory dynamic_factory(pool);
  1270. google::protobuf::scoped_ptr<Message> message(dynamic_factory.GetPrototype(type)->New());
  1271. if (mode_ == MODE_ENCODE) {
  1272. SetFdToTextMode(STDIN_FILENO);
  1273. SetFdToBinaryMode(STDOUT_FILENO);
  1274. } else {
  1275. SetFdToBinaryMode(STDIN_FILENO);
  1276. SetFdToTextMode(STDOUT_FILENO);
  1277. }
  1278. io::FileInputStream in(STDIN_FILENO);
  1279. io::FileOutputStream out(STDOUT_FILENO);
  1280. if (mode_ == MODE_ENCODE) {
  1281. // Input is text.
  1282. ErrorPrinter error_collector(error_format_);
  1283. TextFormat::Parser parser;
  1284. parser.RecordErrorsTo(&error_collector);
  1285. parser.AllowPartialMessage(true);
  1286. if (!parser.Parse(&in, message.get())) {
  1287. cerr << "Failed to parse input." << endl;
  1288. return false;
  1289. }
  1290. } else {
  1291. // Input is binary.
  1292. if (!message->ParsePartialFromZeroCopyStream(&in)) {
  1293. cerr << "Failed to parse input." << endl;
  1294. return false;
  1295. }
  1296. }
  1297. if (!message->IsInitialized()) {
  1298. cerr << "warning: Input message is missing required fields: "
  1299. << message->InitializationErrorString() << endl;
  1300. }
  1301. if (mode_ == MODE_ENCODE) {
  1302. // Output is binary.
  1303. if (!message->SerializePartialToZeroCopyStream(&out)) {
  1304. cerr << "output: I/O error." << endl;
  1305. return false;
  1306. }
  1307. } else {
  1308. // Output is text.
  1309. if (!TextFormat::Print(*message, &out)) {
  1310. cerr << "output: I/O error." << endl;
  1311. return false;
  1312. }
  1313. }
  1314. return true;
  1315. }
  1316. bool CommandLineInterface::WriteDescriptorSet(
  1317. const vector<const FileDescriptor*> parsed_files) {
  1318. FileDescriptorSet file_set;
  1319. if (imports_in_descriptor_set_) {
  1320. set<const FileDescriptor*> already_seen;
  1321. for (int i = 0; i < parsed_files.size(); i++) {
  1322. GetTransitiveDependencies(parsed_files[i],
  1323. source_info_in_descriptor_set_,
  1324. &already_seen, file_set.mutable_file());
  1325. }
  1326. } else {
  1327. for (int i = 0; i < parsed_files.size(); i++) {
  1328. FileDescriptorProto* file_proto = file_set.add_file();
  1329. parsed_files[i]->CopyTo(file_proto);
  1330. if (source_info_in_descriptor_set_) {
  1331. parsed_files[i]->CopySourceCodeInfoTo(file_proto);
  1332. }
  1333. }
  1334. }
  1335. int fd;
  1336. do {
  1337. fd = open(descriptor_set_name_.c_str(),
  1338. O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
  1339. } while (fd < 0 && errno == EINTR);
  1340. if (fd < 0) {
  1341. perror(descriptor_set_name_.c_str());
  1342. return false;
  1343. }
  1344. io::FileOutputStream out(fd);
  1345. if (!file_set.SerializeToZeroCopyStream(&out)) {
  1346. cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno()) << endl;
  1347. out.Close();
  1348. return false;
  1349. }
  1350. if (!out.Close()) {
  1351. cerr << descriptor_set_name_ << ": " << strerror(out.GetErrno()) << endl;
  1352. return false;
  1353. }
  1354. return true;
  1355. }
  1356. void CommandLineInterface::GetTransitiveDependencies(
  1357. const FileDescriptor* file, bool include_source_code_info,
  1358. set<const FileDescriptor*>* already_seen,
  1359. RepeatedPtrField<FileDescriptorProto>* output) {
  1360. if (!already_seen->insert(file).second) {
  1361. // Already saw this file. Skip.
  1362. return;
  1363. }
  1364. // Add all dependencies.
  1365. for (int i = 0; i < file->dependency_count(); i++) {
  1366. GetTransitiveDependencies(file->dependency(i), include_source_code_info,
  1367. already_seen, output);
  1368. }
  1369. // Add this file.
  1370. FileDescriptorProto* new_descriptor = output->Add();
  1371. file->CopyTo(new_descriptor);
  1372. if (include_source_code_info) {
  1373. file->CopySourceCodeInfoTo(new_descriptor);
  1374. }
  1375. }
  1376. namespace {
  1377. // Utility function for PrintFreeFieldNumbers.
  1378. // Stores occupied ranges into the ranges parameter, and next level of sub
  1379. // message types into the nested_messages parameter. The FieldRange is left
  1380. // inclusive, right exclusive. i.e. [a, b).
  1381. //
  1382. // Nested Messages:
  1383. // Note that it only stores the nested message type, iff the nested type is
  1384. // either a direct child of the given descriptor, or the nested type is a
  1385. // decendent of the given descriptor and all the nodes between the
  1386. // nested type and the given descriptor are group types. e.g.
  1387. //
  1388. // message Foo {
  1389. // message Bar {
  1390. // message NestedBar {}
  1391. // }
  1392. // group Baz = 1 {
  1393. // group NestedBazGroup = 2 {
  1394. // message Quz {
  1395. // message NestedQuz {}
  1396. // }
  1397. // }
  1398. // message NestedBaz {}
  1399. // }
  1400. // }
  1401. //
  1402. // In this case, Bar, Quz and NestedBaz will be added into the nested types.
  1403. // Since free field numbers of group types will not be printed, this makes sure
  1404. // the nested message types in groups will not be dropped. The nested_messages
  1405. // parameter will contain the direct children (when groups are ignored in the
  1406. // tree) of the given descriptor for the caller to traverse. The declaration
  1407. // order of the nested messages is also preserved.
  1408. typedef pair<int, int> FieldRange;
  1409. void GatherOccupiedFieldRanges(const Descriptor* descriptor,
  1410. set<FieldRange>* ranges,
  1411. vector<const Descriptor*>* nested_messages) {
  1412. set<const Descriptor*> groups;
  1413. for (int i = 0; i < descriptor->field_count(); ++i) {
  1414. const FieldDescriptor* fd = descriptor->field(i);
  1415. ranges->insert(FieldRange(fd->number(), fd->number() + 1));
  1416. if (fd->type() == FieldDescriptor::TYPE_GROUP) {
  1417. groups.insert(fd->message_type());
  1418. }
  1419. }
  1420. for (int i = 0; i < descriptor->extension_range_count(); ++i) {
  1421. ranges->insert(FieldRange(descriptor->extension_range(i)->start,
  1422. descriptor->extension_range(i)->end));
  1423. }
  1424. // Handle the nested messages/groups in declaration order to make it
  1425. // post-order strict.
  1426. for (int i = 0; i < descriptor->nested_type_count(); ++i) {
  1427. const Descriptor* nested_desc = descriptor->nested_type(i);
  1428. if (groups.find(nested_desc) != groups.end()) {
  1429. GatherOccupiedFieldRanges(nested_desc, ranges, nested_messages);
  1430. } else {
  1431. nested_messages->push_back(nested_desc);
  1432. }
  1433. }
  1434. }
  1435. // Utility function for PrintFreeFieldNumbers.
  1436. // Actually prints the formatted free field numbers for given message name and
  1437. // occupied ranges.
  1438. void FormatFreeFieldNumbers(const string& name,
  1439. const set<FieldRange>& ranges) {
  1440. string output;
  1441. StringAppendF(&output, "%-35s free:", name.c_str());
  1442. int next_free_number = 1;
  1443. for (set<FieldRange>::const_iterator i = ranges.begin();
  1444. i != ranges.end(); ++i) {
  1445. // This happens when groups re-use parent field numbers, in which
  1446. // case we skip the FieldRange entirely.
  1447. if (next_free_number >= i->second) continue;
  1448. if (next_free_number < i->first) {
  1449. if (next_free_number + 1 == i->first) {
  1450. // Singleton
  1451. StringAppendF(&output, " %d", next_free_number);
  1452. } else {
  1453. // Range
  1454. StringAppendF(&output, " %d-%d", next_free_number, i->first - 1);
  1455. }
  1456. }
  1457. next_free_number = i->second;
  1458. }
  1459. if (next_free_number <= FieldDescriptor::kMaxNumber) {
  1460. StringAppendF(&output, " %d-INF", next_free_number);
  1461. }
  1462. cout << output << endl;
  1463. }
  1464. } // namespace
  1465. void CommandLineInterface::PrintFreeFieldNumbers(
  1466. const Descriptor* descriptor) {
  1467. set<FieldRange> ranges;
  1468. vector<const Descriptor*> nested_messages;
  1469. GatherOccupiedFieldRanges(descriptor, &ranges, &nested_messages);
  1470. for (int i = 0; i < nested_messages.size(); ++i) {
  1471. PrintFreeFieldNumbers(nested_messages[i]);
  1472. }
  1473. FormatFreeFieldNumbers(descriptor->full_name(), ranges);
  1474. }
  1475. } // namespace compiler
  1476. } // namespace protobuf
  1477. } // namespace google