PageRenderTime 21ms CodeModel.GetById 47ms RepoModel.GetById 0ms app.codeStats 0ms

/src/google/protobuf/compiler/c/c_helpers.cc

http://protobuf-c.googlecode.com/
C++ | 502 lines | 389 code | 50 blank | 63 comment | 87 complexity | 2aa0feda826d1af97eeabd9e0489052f MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc.
  3. // http://code.google.com/p/protobuf/
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. // Author: kenton@google.com (Kenton Varda)
  17. // Based on original Protocol Buffers design by
  18. // Sanjay Ghemawat, Jeff Dean, and others.
  19. // Modified to implement C code by Dave Benson.
  20. #include <vector>
  21. #include <set>
  22. #include <stdio.h> // for snprintf
  23. #include <float.h>
  24. #include <google/protobuf/compiler/c/c_helpers.h>
  25. #include <google/protobuf/stubs/common.h>
  26. namespace google {
  27. namespace protobuf {
  28. namespace compiler {
  29. namespace c {
  30. #if defined(_MSC_VER)
  31. // FIXME: In the case where the generated string is longer than the buffer,
  32. // _snprint() returns a negative value, where snprintf() returns the number
  33. // of characters that *would* have been stored, had there been room.
  34. // That is fundamental, as it allows snprintf() to be used to find the size
  35. // necessary for the buffer, simply by calling it with the size of the buffer
  36. // passed in as zero.
  37. // Note: at the present moment return value isn't used in the code.
  38. #define snprintf _snprintf
  39. #pragma warning(disable:4800)
  40. #pragma warning(disable:4996)
  41. #endif
  42. string DotsToUnderscores(const string& name) {
  43. return StringReplace(name, ".", "_", true);
  44. }
  45. string DotsToColons(const string& name) {
  46. return StringReplace(name, ".", "::", true);
  47. }
  48. string SimpleFtoa(float f) {
  49. char buf[100];
  50. snprintf(buf,sizeof(buf),"%.*g", FLT_DIG, f);
  51. buf[sizeof(buf)-1] = 0; /* should NOT be necessary */
  52. return buf;
  53. }
  54. string SimpleDtoa(double d) {
  55. char buf[100];
  56. snprintf(buf,sizeof(buf),"%.*g", DBL_DIG, d);
  57. buf[sizeof(buf)-1] = 0; /* should NOT be necessary */
  58. return buf;
  59. }
  60. string CamelToUpper(const string &name) {
  61. bool was_upper = true; // suppress initial _
  62. string rv = "";
  63. int len = name.length();
  64. for (int i = 0; i < len; i++) {
  65. bool is_upper = isupper(name[i]);
  66. if (is_upper) {
  67. if (!was_upper)
  68. rv += '_';
  69. rv += name[i];
  70. } else {
  71. rv += toupper(name[i]);
  72. }
  73. was_upper = is_upper;
  74. }
  75. return rv;
  76. }
  77. string CamelToLower(const string &name) {
  78. bool was_upper = true; // suppress initial _
  79. string rv = "";
  80. int len = name.length();
  81. for (int i = 0; i < len; i++) {
  82. bool is_upper = isupper(name[i]);
  83. if (is_upper) {
  84. if (!was_upper)
  85. rv += '_';
  86. rv += tolower(name[i]);
  87. } else {
  88. rv += name[i];
  89. }
  90. was_upper = is_upper;
  91. }
  92. return rv;
  93. }
  94. string ToUpper(const string &name) {
  95. string rv = "";
  96. int len = name.length();
  97. for (int i = 0; i < len; i++) {
  98. rv += toupper(name[i]);
  99. }
  100. return rv;
  101. }
  102. string ToLower(const string &name) {
  103. string rv = "";
  104. int len = name.length();
  105. for (int i = 0; i < len; i++) {
  106. rv += tolower(name[i]);
  107. }
  108. return rv;
  109. }
  110. string ToCamel(const string &name) {
  111. string rv = "";
  112. int len = name.length();
  113. bool next_is_upper = true;
  114. for (int i = 0; i < len; i++) {
  115. if (name[i] == '_') {
  116. next_is_upper = true;
  117. } else if (next_is_upper) {
  118. rv += toupper (name[i]);
  119. next_is_upper = false;
  120. } else {
  121. rv += name[i];
  122. }
  123. }
  124. return rv;
  125. }
  126. string FullNameToLower(const string &full_name) {
  127. vector<string> pieces;
  128. SplitStringUsing(full_name, ".", &pieces);
  129. string rv = "";
  130. for (unsigned i = 0; i < pieces.size(); i++) {
  131. if (pieces[i] == "") continue;
  132. if (rv != "") rv += "__";
  133. rv += CamelToLower(pieces[i]);
  134. }
  135. return rv;
  136. }
  137. string FullNameToUpper(const string &full_name) {
  138. vector<string> pieces;
  139. SplitStringUsing(full_name, ".", &pieces);
  140. string rv = "";
  141. for (unsigned i = 0; i < pieces.size(); i++) {
  142. if (pieces[i] == "") continue;
  143. if (rv != "") rv += "__";
  144. rv += CamelToUpper(pieces[i]);
  145. }
  146. return rv;
  147. }
  148. string FullNameToC(const string &full_name) {
  149. vector<string> pieces;
  150. SplitStringUsing(full_name, ".", &pieces);
  151. string rv = "";
  152. for (unsigned i = 0; i < pieces.size(); i++) {
  153. if (pieces[i] == "") continue;
  154. if (rv != "") rv += "__";
  155. rv += ToCamel(pieces[i]);
  156. }
  157. return rv;
  158. }
  159. string ConvertToSpaces(const string &input) {
  160. return string(input.size(), ' ');
  161. }
  162. int compare_name_indices_by_name(const void *a, const void *b)
  163. {
  164. const NameIndex *ni_a = (const NameIndex *) a;
  165. const NameIndex *ni_b = (const NameIndex *) b;
  166. return strcmp (ni_a->name, ni_b->name);
  167. }
  168. string CEscape(const string& src);
  169. const char* const kKeywordList[] = {
  170. "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case",
  171. "catch", "char", "class", "compl", "const", "const_cast", "continue",
  172. "default", "delete", "do", "double", "dynamic_cast", "else", "enum",
  173. "explicit", "extern", "false", "float", "for", "friend", "goto", "if",
  174. "inline", "int", "long", "mutable", "namespace", "new", "not", "not_eq",
  175. "operator", "or", "or_eq", "private", "protected", "public", "register",
  176. "reinterpret_cast", "return", "short", "signed", "sizeof", "static",
  177. "static_cast", "struct", "switch", "template", "this", "throw", "true", "try",
  178. "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual",
  179. "void", "volatile", "wchar_t", "while", "xor", "xor_eq"
  180. };
  181. std::set<string> MakeKeywordsMap() {
  182. set<string> result;
  183. for (int i = 0; i < GOOGLE_ARRAYSIZE(kKeywordList); i++) {
  184. result.insert(kKeywordList[i]);
  185. }
  186. return result;
  187. }
  188. std::set<string> kKeywords = MakeKeywordsMap();
  189. string ClassName(const Descriptor* descriptor, bool qualified) {
  190. // Find "outer", the descriptor of the top-level message in which
  191. // "descriptor" is embedded.
  192. const Descriptor* outer = descriptor;
  193. while (outer->containing_type() != NULL) outer = outer->containing_type();
  194. const string& outer_name = outer->full_name();
  195. string inner_name = descriptor->full_name().substr(outer_name.size());
  196. if (qualified) {
  197. return "::" + DotsToColons(outer_name) + DotsToUnderscores(inner_name);
  198. } else {
  199. return outer->name() + DotsToUnderscores(inner_name);
  200. }
  201. }
  202. string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) {
  203. if (enum_descriptor->containing_type() == NULL) {
  204. if (qualified) {
  205. return DotsToColons(enum_descriptor->full_name());
  206. } else {
  207. return enum_descriptor->name();
  208. }
  209. } else {
  210. string result = ClassName(enum_descriptor->containing_type(), qualified);
  211. result += '_';
  212. result += enum_descriptor->name();
  213. return result;
  214. }
  215. }
  216. string FieldName(const FieldDescriptor* field) {
  217. string result = ToLower(field->name());
  218. if (kKeywords.count(result) > 0) {
  219. result.append("_");
  220. }
  221. return result;
  222. }
  223. string FieldDeprecated(const FieldDescriptor* field) {
  224. if (field->options().deprecated()) {
  225. return " PROTOBUF_C_DEPRECATED";
  226. }
  227. return "";
  228. }
  229. string StripProto(const string& filename) {
  230. if (HasSuffixString(filename, ".protodevel")) {
  231. return StripSuffixString(filename, ".protodevel");
  232. } else {
  233. return StripSuffixString(filename, ".proto");
  234. }
  235. }
  236. // Convert a file name into a valid identifier.
  237. string FilenameIdentifier(const string& filename) {
  238. string result;
  239. for (unsigned i = 0; i < filename.size(); i++) {
  240. if (isalnum(filename[i])) {
  241. result.push_back(filename[i]);
  242. } else {
  243. // Not alphanumeric. To avoid any possibility of name conflicts we
  244. // use the hex code for the character.
  245. result.push_back('_');
  246. char buffer[32];
  247. result.append(FastHexToBuffer(static_cast<uint8>(filename[i]), buffer));
  248. }
  249. }
  250. return result;
  251. }
  252. // Return the name of the BuildDescriptors() function for a given file.
  253. string GlobalBuildDescriptorsName(const string& filename) {
  254. return "proto_BuildDescriptors_" + FilenameIdentifier(filename);
  255. }
  256. string GetLabelName(FieldDescriptor::Label label) {
  257. switch (label) {
  258. case FieldDescriptor::LABEL_OPTIONAL: return "optional";
  259. case FieldDescriptor::LABEL_REQUIRED: return "required";
  260. case FieldDescriptor::LABEL_REPEATED: return "repeated";
  261. }
  262. return "bad-label";
  263. }
  264. unsigned
  265. WriteIntRanges(io::Printer* printer, int n_values, const int *values, const string &name)
  266. {
  267. map<string, string> vars;
  268. vars["name"] = name;
  269. if (n_values > 0) {
  270. int n_ranges = 1;
  271. for (int i = 1; i < n_values; i++) {
  272. if (values[i-1] + 1 != values[i])
  273. n_ranges++;
  274. }
  275. vars["n_ranges"] = SimpleItoa(n_ranges);
  276. printer->Print(vars, "static const ProtobufCIntRange $name$[$n_ranges$ + 1] =\n"
  277. "{\n");
  278. int last_range_start = 0;
  279. for (int i = 1; i < n_values; i++) {
  280. if (values[i-1] + 1 != values[i]) {
  281. int count = i - last_range_start;
  282. int expected = values[i-1] + 1;
  283. vars["start_value"] = SimpleItoa(expected - count);
  284. vars["orig_offset"] = SimpleItoa(last_range_start);
  285. printer->Print (vars, " { $start_value$, $orig_offset$ },\n");
  286. last_range_start = i;
  287. }
  288. }
  289. // write last real entry
  290. {
  291. int i = n_values;
  292. int count = i - last_range_start;
  293. int expected = values[i-1] + 1;
  294. vars["start_value"] = SimpleItoa(expected - count);
  295. vars["orig_offset"] = SimpleItoa(last_range_start);
  296. printer->Print (vars, " { $start_value$, $orig_offset$ },\n");
  297. }
  298. // write sentinel entry
  299. vars["n_entries"] = SimpleItoa(n_values);
  300. printer->Print (vars, " { 0, $n_entries$ }\n");
  301. printer->Print (vars, "};\n");
  302. return n_ranges;
  303. } else {
  304. printer->Print (vars, "#define $name$ NULL\n");
  305. return 0;
  306. }
  307. }
  308. // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
  309. // XXXXXXXXX this stuff is copied from strutils.cc !!!! XXXXXXXXXXXXXXXXXXXXXXXXXXXXx
  310. // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
  311. // ----------------------------------------------------------------------
  312. // StringReplace()
  313. // Replace the "old" pattern with the "new" pattern in a string,
  314. // and append the result to "res". If replace_all is false,
  315. // it only replaces the first instance of "old."
  316. // ----------------------------------------------------------------------
  317. void StringReplace(const string& s, const string& oldsub,
  318. const string& newsub, bool replace_all,
  319. string* res) {
  320. if (oldsub.empty()) {
  321. res->append(s); // if empty, append the given string.
  322. return;
  323. }
  324. string::size_type start_pos = 0;
  325. string::size_type pos;
  326. do {
  327. pos = s.find(oldsub, start_pos);
  328. if (pos == string::npos) {
  329. break;
  330. }
  331. res->append(s, start_pos, pos - start_pos);
  332. res->append(newsub);
  333. start_pos = pos + oldsub.size(); // start searching again after the "old"
  334. } while (replace_all);
  335. res->append(s, start_pos, s.length() - start_pos);
  336. }
  337. // ----------------------------------------------------------------------
  338. // StringReplace()
  339. // Give me a string and two patterns "old" and "new", and I replace
  340. // the first instance of "old" in the string with "new", if it
  341. // exists. If "global" is true; call this repeatedly until it
  342. // fails. RETURN a new string, regardless of whether the replacement
  343. // happened or not.
  344. // ----------------------------------------------------------------------
  345. string StringReplace(const string& s, const string& oldsub,
  346. const string& newsub, bool replace_all) {
  347. string ret;
  348. StringReplace(s, oldsub, newsub, replace_all, &ret);
  349. return ret;
  350. }
  351. // ----------------------------------------------------------------------
  352. // SplitStringUsing()
  353. // Split a string using a character delimiter. Append the components
  354. // to 'result'.
  355. //
  356. // Note: For multi-character delimiters, this routine will split on *ANY* of
  357. // the characters in the string, not the entire string as a single delimiter.
  358. // ----------------------------------------------------------------------
  359. template <typename ITR>
  360. static inline
  361. void SplitStringToIteratorUsing(const string& full,
  362. const char* delim,
  363. ITR& result) {
  364. // Optimize the common case where delim is a single character.
  365. if (delim[0] != '\0' && delim[1] == '\0') {
  366. char c = delim[0];
  367. const char* p = full.data();
  368. const char* end = p + full.size();
  369. while (p != end) {
  370. if (*p == c) {
  371. ++p;
  372. } else {
  373. const char* start = p;
  374. while (++p != end && *p != c);
  375. *result++ = string(start, p - start);
  376. }
  377. }
  378. return;
  379. }
  380. string::size_type begin_index, end_index;
  381. begin_index = full.find_first_not_of(delim);
  382. while (begin_index != string::npos) {
  383. end_index = full.find_first_of(delim, begin_index);
  384. if (end_index == string::npos) {
  385. *result++ = full.substr(begin_index);
  386. return;
  387. }
  388. *result++ = full.substr(begin_index, (end_index - begin_index));
  389. begin_index = full.find_first_not_of(delim, end_index);
  390. }
  391. }
  392. void SplitStringUsing(const string& full,
  393. const char* delim,
  394. vector<string>* result) {
  395. back_insert_iterator< vector<string> > it(*result);
  396. SplitStringToIteratorUsing(full, delim, it);
  397. }
  398. char* FastHexToBuffer(int i, char* buffer)
  399. {
  400. snprintf(buffer, 16, "%x", i);
  401. return buffer;
  402. }
  403. static int CEscapeInternal(const char* src, int src_len, char* dest,
  404. int dest_len, bool use_hex) {
  405. const char* src_end = src + src_len;
  406. int used = 0;
  407. bool last_hex_escape = false; // true if last output char was \xNN
  408. for (; src < src_end; src++) {
  409. if (dest_len - used < 2) // Need space for two letter escape
  410. return -1;
  411. bool is_hex_escape = false;
  412. switch (*src) {
  413. case '\n': dest[used++] = '\\'; dest[used++] = 'n'; break;
  414. case '\r': dest[used++] = '\\'; dest[used++] = 'r'; break;
  415. case '\t': dest[used++] = '\\'; dest[used++] = 't'; break;
  416. case '\"': dest[used++] = '\\'; dest[used++] = '\"'; break;
  417. case '\'': dest[used++] = '\\'; dest[used++] = '\''; break;
  418. case '\\': dest[used++] = '\\'; dest[used++] = '\\'; break;
  419. default:
  420. // Note that if we emit \xNN and the src character after that is a hex
  421. // digit then that digit must be escaped too to prevent it being
  422. // interpreted as part of the character code by C.
  423. if (!isprint(*src) || (last_hex_escape && isxdigit(*src))) {
  424. if (dest_len - used < 4) // need space for 4 letter escape
  425. return -1;
  426. sprintf(dest + used, (use_hex ? "\\x%02x" : "\\%03o"),
  427. static_cast<uint8>(*src));
  428. is_hex_escape = use_hex;
  429. used += 4;
  430. } else {
  431. dest[used++] = *src; break;
  432. }
  433. }
  434. last_hex_escape = is_hex_escape;
  435. }
  436. if (dest_len - used < 1) // make sure that there is room for \0
  437. return -1;
  438. dest[used] = '\0'; // doesn't count towards return value though
  439. return used;
  440. }
  441. string CEscape(const string& src) {
  442. const int dest_length = src.size() * 4 + 1; // Maximum possible expansion
  443. scoped_array<char> dest(new char[dest_length]);
  444. const int len = CEscapeInternal(src.data(), src.size(),
  445. dest.get(), dest_length, false);
  446. GOOGLE_DCHECK_GE(len, 0);
  447. return string(dest.get(), len);
  448. }
  449. } // namespace c
  450. } // namespace compiler
  451. } // namespace protobuf
  452. } // namespace google